Merge branch 'add-stats-api-support' of https://github.com/nir0s/docker-py into nir0s-add-stats-api-support

This commit is contained in:
Joffrey F 2015-02-12 13:15:59 -08:00
commit 1a7e3a2d6d
7 changed files with 215 additions and 1 deletions

View File

@ -869,11 +869,22 @@ class Client(requests.Session):
res = self._post_json(url, data=start_config)
self._raise_for_status(res)
def stats(self, container):
if utils.compare_version('1.17', self._version) < 0:
raise errors.InvalidVersion(
'Stats retrieval is not supported in API < 1.17!')
if isinstance(container, dict):
container = container.get('Id')
url = self._url("/containers/{0}/stats".format(container))
return self._stream_helper(self._get(url, stream=True))
def stop(self, container, timeout=10):
if isinstance(container, dict):
container = container.get('Id')
params = {'t': timeout}
url = self._url("/containers/{0}/stop".format(container))
res = self._post(url, params=params,
timeout=(timeout + self.timeout))
self._raise_for_status(res)

View File

@ -708,6 +708,27 @@ from. Optionally a single string joining container id's with commas
None
```
## stats
The Docker API parallel to the `docker stats` command.
This will stream statistics for a specific container.
**Params**:
* container (str): The container to start
```python
>>> from docker import Client
>>> cli = Client(base_url='tcp://127.0.0.1:2375')
>>> stats_obj = cli.stats('elasticsearch')
>>> for stat in stats:
>>> print(stat)
{"read":"2015-02-11T21:47:30.49388286+02:00","network":{"rx_bytes":666052,"rx_packets":4409 ...
...
...
...
```
## stop
Stops a container. Similar to the `docker stop` command.

View File

@ -1,6 +1,14 @@
Change Log
==========
0.7.3
-----
### Features
* Added support for `stats` API.
0.7.2
-----

View File

@ -12,6 +12,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
import fake_stat
CURRENT_VERSION = 'v1.17'
FAKE_CONTAINER_ID = '3cc2351ab11b'
@ -337,6 +339,11 @@ def post_fake_tag_image():
return status_code, response
def get_fake_stats():
status_code = 200
response = fake_stat.OBJ
return status_code, response
# Maps real api url to fake response callback
prefix = 'http+unix://var/run/docker.sock'
fake_responses = {
@ -376,6 +383,8 @@ fake_responses = {
post_fake_execute,
'{1}/{0}/exec/3cc2351ab11b/start'.format(CURRENT_VERSION, prefix):
post_fake_execute_start,
'{1}/{0}/containers/3cc2351ab11b/stats'.format(CURRENT_VERSION, prefix):
get_fake_stats,
'{1}/{0}/containers/3cc2351ab11b/stop'.format(CURRENT_VERSION, prefix):
post_fake_stop_container,
'{1}/{0}/containers/3cc2351ab11b/kill'.format(CURRENT_VERSION, prefix):

153
tests/fake_stat.py Normal file
View File

@ -0,0 +1,153 @@
OBJ = {
"read": "2015-02-11T19:20:46.667237763+02:00",
"network": {
"rx_bytes": 567224,
"rx_packets": 3773,
"rx_errors": 0,
"rx_dropped": 0,
"tx_bytes": 1176,
"tx_packets": 13,
"tx_errors": 0,
"tx_dropped": 0
},
"cpu_stats": {
"cpu_usage": {
"total_usage": 157260874053,
"percpu_usage": [
52196306950,
24118413549,
53292684398,
27653469156
],
"usage_in_kernelmode": 37140000000,
"usage_in_usermode": 62140000000
},
"system_cpu_usage": 3.0881377e+14,
"throttling_data": {
"periods": 0,
"throttled_periods": 0,
"throttled_time": 0
}
},
"memory_stats": {
"usage": 179314688,
"max_usage": 258166784,
"stats": {
"active_anon": 90804224,
"active_file": 2195456,
"cache": 3096576,
"hierarchical_memory_limit": 1.844674407371e+19,
"inactive_anon": 85516288,
"inactive_file": 798720,
"mapped_file": 2646016,
"pgfault": 101034,
"pgmajfault": 1207,
"pgpgin": 115814,
"pgpgout": 75613,
"rss": 176218112,
"rss_huge": 12582912,
"total_active_anon": 90804224,
"total_active_file": 2195456,
"total_cache": 3096576,
"total_inactive_anon": 85516288,
"total_inactive_file": 798720,
"total_mapped_file": 2646016,
"total_pgfault": 101034,
"total_pgmajfault": 1207,
"total_pgpgin": 115814,
"total_pgpgout": 75613,
"total_rss": 176218112,
"total_rss_huge": 12582912,
"total_unevictable": 0,
"total_writeback": 0,
"unevictable": 0,
"writeback": 0
},
"failcnt": 0,
"limit": 8039038976
},
"blkio_stats": {
"io_service_bytes_recursive": [
{
"major": 8,
"minor": 0,
"op": "Read",
"value": 72843264
},
{
"major": 8,
"minor": 0,
"op": "Write",
"value": 4096
},
{
"major": 8,
"minor": 0,
"op": "Sync",
"value": 4096
},
{
"major": 8,
"minor": 0,
"op": "Async",
"value": 72843264
},
{
"major": 8,
"minor": 0,
"op": "Total",
"value": 72847360
}
],
"io_serviced_recursive": [
{
"major": 8,
"minor": 0,
"op": "Read",
"value": 10581
},
{
"major": 8,
"minor": 0,
"op": "Write",
"value": 1
},
{
"major": 8,
"minor": 0,
"op": "Sync",
"value": 1
},
{
"major": 8,
"minor": 0,
"op": "Async",
"value": 10581
},
{
"major": 8,
"minor": 0,
"op": "Total",
"value": 10582
}
],
"io_queue_recursive": [
],
"io_service_time_recursive": [
],
"io_wait_time_recursive": [
],
"io_merged_recursive": [
],
"io_time_recursive": [
],
"sectors_recursive": [
]
}
}

View File

@ -29,7 +29,7 @@ import six
from test import Cleanup
# FIXME: missing tests for
# export; history; import_image; insert; port; push; tag; get; load
# export; history; import_image; insert; port; push; tag; get; load; stats;
DEFAULT_BASE_URL = os.environ.get('DOCKER_HOST')

View File

@ -1672,6 +1672,18 @@ class DockerClientTest(Cleanup, unittest.TestCase):
timeout=docker.client.DEFAULT_TIMEOUT_SECONDS
)
def test_container_stats(self):
try:
self.client.stats(fake_api.FAKE_CONTAINER_ID)
except Exception as e:
self.fail('Command should not raise exception: {0}'.format(e))
fake_request.assert_called_with(
url_prefix + 'containers/3cc2351ab11b/stats',
timeout=60,
stream=True
)
##################
# IMAGES TESTS #
##################