a93e75e3b83d811a0c61e54d3412538f59652094
[osm/vim-emu.git] / src / emuvim / api / openstack / docker_util.py
1 """
2 Copyright (c) 2017 SONATA-NFV and Paderborn University
3 ALL RIGHTS RESERVED.
4
5 Licensed under the Apache License, Version 2.0 (the "License");
6 you may not use this file except in compliance with the License.
7 You may obtain a copy of the License at
8
9 http://www.apache.org/licenses/LICENSE-2.0
10
11 Unless required by applicable law or agreed to in writing, software
12 distributed under the License is distributed on an "AS IS" BASIS,
13 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 See the License for the specific language governing permissions and
15 limitations under the License.
16
17 Neither the name of the SONATA-NFV, Paderborn University
18 nor the names of its contributors may be used to endorse or promote
19 products derived from this software without specific prior written
20 permission.
21
22 This work has been performed in the framework of the SONATA project,
23 funded by the European Commission under Grant number 671517 through
24 the Horizon 2020 and 5G-PPP programmes. The authors would like to
25 acknowledge the contributions of their colleagues of the SONATA
26 partner consortium (www.sonata-nfv.eu).
27 """
28 from docker import DockerClient, APIClient
29 import time
30 import re
31
32
33 def docker_container_id(container_name):
34 """
35 Uses the container name to return the container ID.
36
37 :param container_name: The full name of the docker container.
38 :type container_name: ``str``
39 :return: Returns the container ID or None if the container is not running or could not be found.
40 :rtype: ``dict``
41 """
42 c = APIClient()
43 detail = c.inspect_container(container_name)
44 if bool(detail["State"]["Running"]):
45 return detail['Id']
46 return None
47
48
49 def docker_abs_cpu(container_id):
50 """
51 Returns the used CPU time since container startup and the system time in nanoseconds and returns the number
52 of available CPU cores.
53
54 :param container_id: The full ID of the docker container.
55 :type container_id: ``str``
56 :return: Returns a dict with CPU_used in nanoseconds, the current system time in nanoseconds and the number of
57 CPU cores available.
58 :rtype: ``dict``
59 """
60 with open('/sys/fs/cgroup/cpuacct/docker/' + container_id + '/cpuacct.usage_percpu', 'r') as f:
61 line = f.readline()
62 sys_time = int(time.time() * 1000000000)
63 numbers = [int(x) for x in line.split()]
64 cpu_usage = 0
65 for number in numbers:
66 cpu_usage += number
67 return {'CPU_used': cpu_usage, 'CPU_used_systime': sys_time, 'CPU_cores': len(numbers)}
68
69
70 def docker_mem_used(container_id):
71 """
72 Bytes of memory used from the docker container.
73
74 Note: If you have problems with this command you have to enable memory control group.
75 For this you have to add the following kernel parameters: `cgroup_enable=memory swapaccount=1`.
76 See: https://docs.docker.com/engine/admin/runmetrics/
77
78 :param container_id: The full ID of the docker container.
79 :type container_id: ``str``
80 :return: Returns the memory utilization in bytes.
81 :rtype: ``str``
82 """
83 with open('/sys/fs/cgroup/memory/docker/' + container_id + '/memory.usage_in_bytes', 'r') as f:
84 return int(f.readline())
85
86
87 def docker_max_mem(container_id):
88 """
89 Bytes of memory the docker container could use.
90
91 :param container_id: The full ID of the docker container.
92 :type container_id: ``str``
93 :return: Returns the bytes of memory the docker container could use.
94 :rtype: ``str``
95 """
96 with open('/sys/fs/cgroup/memory/docker/' + container_id + '/memory.limit_in_bytes', 'r') as f:
97 mem_limit = int(f.readline())
98 with open('/proc/meminfo', 'r') as f:
99 line = f.readline().split()
100 sys_value = int(line[1])
101 unit = line[2]
102 if unit == 'kB':
103 sys_value *= 1024
104 if unit == 'MB':
105 sys_value *= 1024 * 1024
106
107 if sys_value < mem_limit:
108 return sys_value
109 else:
110 return mem_limit
111
112
113 def docker_mem(container_id):
114 """
115 Calculates the current, maximal and percentage usage of the specified docker container.
116
117 :param container_id: The full ID of the docker container.
118 :type container_id: ``str``
119 :return: Returns a dictionary with the total memory usage, the maximal available memory and the percentage
120 memory usage.
121 :rtype: ``dict``
122 """
123 out_dict = dict()
124 out_dict['MEM_used'] = docker_mem_used(container_id)
125 out_dict['MEM_limit'] = docker_max_mem(container_id)
126 out_dict['MEM_%'] = float(out_dict['MEM_used']) / float(out_dict['MEM_limit'])
127 return out_dict
128
129
130 def docker_abs_net_io(container_id):
131 """
132 Network traffic of all network interfaces within the controller.
133
134 :param container_id: The full ID of the docker container.
135 :type container_id: ``str``
136 :return: Returns the absolute network I/O till container startup, in bytes. The return dict also contains the
137 system time.
138 :rtype: ``dict``
139 """
140 c = APIClient()
141 command = c.exec_create(container_id, 'ifconfig')
142 ifconfig = c.exec_start(command['Id'])
143 sys_time = int(time.time() * 1000000000)
144
145 in_bytes = 0
146 m = re.findall('RX bytes:(\d+)', str(ifconfig))
147 if m:
148 for number in m:
149 in_bytes += int(number)
150 else:
151 in_bytes = None
152
153 out_bytes = 0
154 m = re.findall('TX bytes:(\d+)', str(ifconfig))
155 if m:
156 for number in m:
157 out_bytes += int(number)
158 else:
159 out_bytes = None
160
161 return {'NET_in': in_bytes, 'NET_out': out_bytes, 'NET_systime': sys_time}
162
163
164 def docker_block_rw(container_id):
165 """
166 Determines the disk read and write access from the controller since startup.
167
168 :param container_id: The full ID of the docker container.
169 :type container_id: ``str``
170 :return: Returns a dictionary with the total disc I/O since container startup, in bytes.
171 :rtype: ``dict``
172 """
173 with open('/sys/fs/cgroup/blkio/docker/' + container_id + '/blkio.throttle.io_service_bytes', 'r') as f:
174 read = f.readline().split()
175 write = f.readline().split()
176 rw_dict = dict()
177 rw_dict['BLOCK_systime'] = int(time.time() * 1000000000)
178 if len(read) < 3:
179 rw_dict['BLOCK_read'] = 0
180 else:
181 rw_dict['BLOCK_read'] = read[2]
182 if len(write) < 3:
183 rw_dict['BLOCK_write'] = 0
184 else:
185 rw_dict['BLOCK_write'] = write[2]
186 return rw_dict
187
188
189 def docker_PIDS(container_id):
190 """
191 Determines the number of processes within the docker container.
192
193 :param container_id: The full ID of the docker container.
194 :type container_id: ``str``
195 :return: Returns the number of PIDS within a dictionary.
196 :rtype: ``dict``
197 """
198 with open('/sys/fs/cgroup/cpuacct/docker/' + container_id + '/tasks', 'r') as f:
199 return {'PIDS': len(f.read().split('\n')) - 1}
200
201
202 def monitoring_over_time(container_id):
203 """
204 Calculates the cpu workload and the network traffic per second.
205
206 :param container_id: The full docker container ID
207 :type container_id: ``str``
208 :return: A dictionary with disk read and write per second, network traffic per second (in and out),
209 the cpu workload and the number of cpu cores available.
210 :rtype: ``dict``
211 """
212 first_cpu_usage = docker_abs_cpu(container_id)
213 first = docker_abs_net_io(container_id)
214 first_disk_io = docker_block_rw(container_id)
215 time.sleep(1)
216 second_cpu_usage = docker_abs_cpu(container_id)
217 second = docker_abs_net_io(container_id)
218 second_disk_io = docker_block_rw(container_id)
219
220 # Disk access
221 time_div = (int(second_disk_io['BLOCK_systime']) - int(first_disk_io['BLOCK_systime']))
222 read_div = int(second_disk_io['BLOCK_read']) - int(first_disk_io['BLOCK_read'])
223 write_div = int(second_disk_io['BLOCK_write']) - int(first_disk_io['BLOCK_write'])
224 out_dict = {'BLOCK_read/s': int(read_div * 1000000000 / float(time_div) + 0.5),
225 'BLOCK_write/s': int(write_div * 1000000000 / float(time_div) + 0.5)}
226
227 # Network traffic
228 time_div = (int(second['NET_systime']) - int(first['NET_systime']))
229 in_div = int(second['NET_in']) - int(first['NET_in'])
230 out_div = int(second['NET_out']) - int(first['NET_out'])
231 out_dict.update({'NET_in/s': int(in_div * 1000000000 / float(time_div) + 0.5),
232 'NET_out/s': int(out_div * 1000000000 / float(time_div) + 0.5)})
233
234 # CPU utilization
235 time_div = (int(second_cpu_usage['CPU_used_systime']) - int(first_cpu_usage['CPU_used_systime']))
236 usage_div = int(second_cpu_usage['CPU_used']) - int(first_cpu_usage['CPU_used'])
237 out_dict.update({'CPU_%': usage_div / float(time_div), 'CPU_cores': first_cpu_usage['CPU_cores']})
238 return out_dict