Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
蜕变的菜鸟
glances
提交
eb3cd8fd
G
glances
项目概览
蜕变的菜鸟
/
glances
与 Fork 源项目一致
从无法访问的项目Fork
通知
1
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
G
glances
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
前往新版Gitcode,体验更适合开发者的 AI 搜索 >>
提交
eb3cd8fd
编写于
10月 03, 2017
作者:
N
nicolargo
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Support for Docker API < 2.0 is deprecated (docker plugins)
上级
98716b55
变更
2
隐藏空白更改
内联
并排
Showing
2 changed file
with
57 addition
and
126 deletion
+57
-126
NEWS
NEWS
+4
-0
glances/plugins/glances_docker.py
glances/plugins/glances_docker.py
+53
-126
未找到文件。
NEWS
浏览文件 @
eb3cd8fd
...
...
@@ -13,6 +13,10 @@ Bugs corrected:
* Failed to connect to bus: No such file or directory #1156
Backward-incompatible changes:
* Support for Docker API < 2.0 is deprecated (docker plugins)
==============================================================================
Glances Version 2
==============================================================================
...
...
glances/plugins/glances_docker.py
浏览文件 @
eb3cd8fd
...
...
@@ -20,7 +20,6 @@
"""Docker plugin."""
import
os
import
re
import
threading
import
time
...
...
@@ -29,13 +28,10 @@ from glances.logger import logger
from
glances.timer
import
getTimeSinceLastUpdate
from
glances.plugins.glances_plugin
import
GlancesPlugin
from
glances.globals
import
WINDOWS
# Docker-py library (optional and Linux-only)
# https://github.com/docker/docker-py
try
:
import
docker
import
requests
except
ImportError
as
e
:
logger
.
debug
(
"Docker library not found (%s). Glances cannot grab Docker info."
%
e
)
docker_tag
=
False
...
...
@@ -47,7 +43,7 @@ class Plugin(GlancesPlugin):
"""Glances Docker plugin.
stats is a
list
stats is a
dict: {'version': {...}, 'containers': [{}, {}]}
"""
def
__init__
(
self
,
args
=
None
):
...
...
@@ -61,7 +57,7 @@ class Plugin(GlancesPlugin):
self
.
display_curse
=
True
# Init the Docker API
self
.
docker_client
=
False
self
.
docker_client
=
self
.
connect
()
# Dict of thread (to grab stats asynchroniously, one thread is created by container)
# key: Container Id
...
...
@@ -95,79 +91,13 @@ class Plugin(GlancesPlugin):
logger
.
debug
(
"docker plugin - Docker export error {}"
.
format
(
e
))
return
ret
def
__connect_old
(
self
,
version
):
"""Connect to the Docker server with the 'old school' method"""
# Glances is compatible with both API 2.0 and <2.0
# (thanks to the @bacondropped patch)
if
hasattr
(
docker
,
'APIClient'
):
# Correct issue #1000 for API 2.0
init_docker
=
docker
.
APIClient
elif
hasattr
(
docker
,
'Client'
):
# < API 2.0
init_docker
=
docker
.
Client
else
:
# Can not found init method (new API version ?)
logger
.
error
(
"docker plugin - Can not found any way to init the Docker API"
)
return
None
# Init connection to the Docker API
try
:
if
WINDOWS
:
url
=
'npipe:////./pipe/docker_engine'
else
:
url
=
'unix://var/run/docker.sock'
if
version
is
None
:
ret
=
init_docker
(
base_url
=
url
)
else
:
ret
=
init_docker
(
base_url
=
url
,
version
=
version
)
except
NameError
:
# docker lib not found
return
None
return
ret
def
connect
(
self
,
version
=
None
):
def
connect
(
self
):
"""Connect to the Docker server."""
if
hasattr
(
docker
,
'from_env'
)
and
version
is
not
None
:
# Connect to Docker using the default socket or
# the configuration in your environment
ret
=
docker
.
from_env
()
else
:
ret
=
self
.
__connect_old
(
version
=
version
)
global
docker_tag
# Check the server connection with the version() method
try
:
ret
.
version
()
except
requests
.
exceptions
.
ConnectionError
as
e
:
# Connexion error (Docker not detected)
# Let this message in debug mode
logger
.
debug
(
"docker plugin - Can't connect to the Docker server (%s)"
%
e
)
return
None
except
docker
.
errors
.
APIError
as
e
:
if
version
is
None
:
# API error (Version mismatch ?)
logger
.
debug
(
"docker plugin - Docker API error (%s)"
%
e
)
# Try the connection with the server version
version
=
re
.
search
(
'(?:server API version|server)\:\ (.*)\)
\"
.*\)'
,
str
(
e
))
if
version
:
logger
.
debug
(
"docker plugin - Try connection with Docker API version %s"
%
version
.
group
(
1
))
ret
=
self
.
connect
(
version
=
version
.
group
(
1
))
else
:
logger
.
debug
(
"docker plugin - Can not retreive Docker server version"
)
ret
=
None
else
:
# API error
logger
.
error
(
"docker plugin - Docker API error (%s)"
%
e
)
ret
=
None
except
Exception
as
e
:
# Others exceptions...
# Connexion error (Docker not detected)
logger
.
error
(
"docker plugin - Can't connect to the Docker server (%s)"
%
e
)
ret
=
None
# Log an info if Docker plugin is disabled
if
ret
is
None
:
logger
.
debug
(
"docker plugin - Docker plugin is disable because an error has been detected"
)
ret
=
docker
.
from_env
()
# TODO: manage connection error
return
ret
...
...
@@ -179,22 +109,10 @@ class Plugin(GlancesPlugin):
@
GlancesPlugin
.
_log_result_decorator
def
update
(
self
):
"""Update Docker stats using the input method."""
global
docker_tag
# Reset stats
self
.
reset
()
# Get the current Docker API client
if
not
self
.
docker_client
:
# First time, try to connect to the server
try
:
self
.
docker_client
=
self
.
connect
()
except
Exception
:
docker_tag
=
False
else
:
if
self
.
docker_client
is
None
:
docker_tag
=
False
# The Docker-py lib is mandatory
if
not
docker_tag
:
return
self
.
stats
...
...
@@ -219,35 +137,27 @@ class Plugin(GlancesPlugin):
logger
.
error
(
"{} plugin - Cannot get Docker version ({})"
.
format
(
self
.
plugin_name
,
e
))
return
self
.
stats
# Container globals information
# Example: [{u'Status': u'Up 36 seconds',
# u'Created': 1420378904,
# u'Image': u'nginx:1',
# u'Ports': [{u'Type': u'tcp', u'PrivatePort': 443},
# {u'IP': u'0.0.0.0', u'Type': u'tcp', u'PublicPort': 8080, u'PrivatePort': 80}],
# u'Command': u"nginx -g 'daemon off;'",
# u'Names': [u'/webstack_nginx_1'],
# u'Id': u'b0da859e84eb4019cf1d965b15e9323006e510352c402d2f442ea632d61faaa5'}]
# Update current containers list
try
:
self
.
stats
[
'containers'
]
=
self
.
docker_client
.
containers
()
or
[]
# Issue #1152: Docker module doesn't export details about stopped containers
# It could be done here by setting all=True but the list is too long...
containers
=
self
.
docker_client
.
containers
.
list
(
all
=
False
)
or
[]
except
Exception
as
e
:
logger
.
error
(
"{} plugin - Cannot get containers list ({})"
.
format
(
self
.
plugin_name
,
e
))
return
self
.
stats
# Start new thread for new container
for
container
in
self
.
stats
[
'containers'
]
:
if
container
[
'Id'
]
not
in
self
.
thread_list
:
for
container
in
containers
:
if
container
.
id
not
in
self
.
thread_list
:
# Thread did not exist in the internal dict
# Create it and add it to the internal dict
logger
.
debug
(
"{} plugin - Create thread for container {}"
.
format
(
self
.
plugin_name
,
container
[
'Id'
]
[:
12
]))
t
=
ThreadDockerGrabber
(
self
.
docker_client
,
container
[
'Id'
]
)
self
.
thread_list
[
container
[
'Id'
]
]
=
t
logger
.
debug
(
"{} plugin - Create thread for container {}"
.
format
(
self
.
plugin_name
,
container
.
id
[:
12
]))
t
=
ThreadDockerGrabber
(
container
)
self
.
thread_list
[
container
.
id
]
=
t
t
.
start
()
# Stop threads for non-existing containers
nonexisting_containers
=
set
(
iterkeys
(
self
.
thread_list
))
-
set
([
c
[
'Id'
]
for
c
in
self
.
stats
[
'containers'
]
])
nonexisting_containers
=
set
(
iterkeys
(
self
.
thread_list
))
-
set
([
c
.
id
for
c
in
containers
])
for
container_id
in
nonexisting_containers
:
# Stop the thread
logger
.
debug
(
"{} plugin - Stop thread for old container {}"
.
format
(
self
.
plugin_name
,
container_id
[:
12
]))
...
...
@@ -256,17 +166,30 @@ class Plugin(GlancesPlugin):
del
self
.
thread_list
[
container_id
]
# Get stats for all containers
for
container
in
self
.
stats
[
'containers'
]:
self
.
stats
[
'containers'
]
=
[]
for
container
in
containers
:
# Init the stats for the current container
container_stats
=
{}
# The key is the container name and not the Id
container
[
'key'
]
=
self
.
get_key
()
container_stats
[
'key'
]
=
self
.
get_key
()
# Export name (first name in the list, without the /)
container
[
'name'
]
=
container
[
'Names'
][
0
][
1
:]
container
[
'cpu'
]
=
self
.
get_docker_cpu
(
container
[
'Id'
],
self
.
thread_list
[
container
[
'Id'
]].
stats
)
container
[
'memory'
]
=
self
.
get_docker_memory
(
container
[
'Id'
],
self
.
thread_list
[
container
[
'Id'
]].
stats
)
container
[
'network'
]
=
self
.
get_docker_network
(
container
[
'Id'
],
self
.
thread_list
[
container
[
'Id'
]].
stats
)
container
[
'io'
]
=
self
.
get_docker_io
(
container
[
'Id'
],
self
.
thread_list
[
container
[
'Id'
]].
stats
)
container_stats
[
'name'
]
=
container
.
name
# Global stats (from attrs)
container_stats
[
'Status'
]
=
container
.
attrs
[
'State'
][
'Status'
]
container_stats
[
'Command'
]
=
container
.
attrs
[
'Config'
][
'Entrypoint'
]
# Standards stats
if
container_stats
[
'Status'
]
in
(
'running'
,
'paused'
):
container_stats
[
'cpu'
]
=
self
.
get_docker_cpu
(
container
.
id
,
self
.
thread_list
[
container
.
id
].
stats
)
container_stats
[
'memory'
]
=
self
.
get_docker_memory
(
container
.
id
,
self
.
thread_list
[
container
.
id
].
stats
)
container_stats
[
'network'
]
=
self
.
get_docker_network
(
container
.
id
,
self
.
thread_list
[
container
.
id
].
stats
)
container_stats
[
'io'
]
=
self
.
get_docker_io
(
container
.
id
,
self
.
thread_list
[
container
.
id
].
stats
)
else
:
container_stats
[
'cpu'
]
=
{}
container_stats
[
'memory'
]
=
{}
container_stats
[
'network'
]
=
{}
container_stats
[
'io'
]
=
{}
# Add current container stats to the stats list
self
.
stats
[
'containers'
].
append
(
container_stats
)
elif
self
.
input_method
==
'snmp'
:
# Update stats using SNMP
...
...
@@ -454,7 +377,7 @@ class Plugin(GlancesPlugin):
iow
=
[
i
for
i
in
iocounters
[
'io_service_bytes_recursive'
]
if
i
[
'op'
]
==
'Write'
][
0
][
'value'
]
ior_old
=
[
i
for
i
in
self
.
iocounters_old
[
container_id
][
'io_service_bytes_recursive'
]
if
i
[
'op'
]
==
'Read'
][
0
][
'value'
]
iow_old
=
[
i
for
i
in
self
.
iocounters_old
[
container_id
][
'io_service_bytes_recursive'
]
if
i
[
'op'
]
==
'Write'
][
0
][
'value'
]
except
(
IndexError
,
KeyError
)
as
e
:
except
(
IndexError
,
KeyError
,
TypeError
)
as
e
:
# all_stats do not have io information
logger
.
debug
(
"docker plugin - Cannot grab block IO usage for container {} ({})"
.
format
(
container_id
,
e
))
else
:
...
...
@@ -634,10 +557,14 @@ class Plugin(GlancesPlugin):
def
container_alert
(
self
,
status
):
"""Analyse the container status."""
if
"Paused"
in
status
:
return
'CAREFUL'
else
:
if
status
in
(
'running'
):
return
'OK'
elif
status
in
(
'exited'
):
return
'WARNING'
elif
status
in
(
'dead'
):
return
'CRITICAL'
else
:
return
'CAREFUL'
class
ThreadDockerGrabber
(
threading
.
Thread
):
...
...
@@ -647,19 +574,19 @@ class ThreadDockerGrabber(threading.Thread):
stats is a dict
"""
def
__init__
(
self
,
docker_client
,
container_id
):
def
__init__
(
self
,
container
):
"""Init the class:
docker_client: instance of Docker-py client
container_id: Id of the container"""
logger
.
debug
(
"docker plugin - Create thread for container {}"
.
format
(
container_id
[:
12
]))
container: instance of Docker-py Container
"""
super
(
ThreadDockerGrabber
,
self
).
__init__
()
# Event needed to stop properly the thread
self
.
_stopper
=
threading
.
Event
()
# The docker-py return stats as a stream
self
.
_container
_id
=
container_id
self
.
_stats_stream
=
docker_client
.
stats
(
container_id
,
decode
=
True
)
self
.
_container
=
container
self
.
_stats_stream
=
container
.
stats
(
decode
=
True
)
# The class return the stats as a dict
self
.
_stats
=
{}
logger
.
debug
(
"docker plugin - Create thread for container {}"
.
format
(
self
.
_container
.
name
))
def
run
(
self
):
"""Function called to grab stats.
...
...
@@ -683,7 +610,7 @@ class ThreadDockerGrabber(threading.Thread):
def
stop
(
self
,
timeout
=
None
):
"""Stop the thread"""
logger
.
debug
(
"docker plugin - Close thread for container {}"
.
format
(
self
.
_container
_id
[:
12
]
))
logger
.
debug
(
"docker plugin - Close thread for container {}"
.
format
(
self
.
_container
.
name
))
self
.
_stopper
.
set
()
def
stopped
(
self
):
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录