| peusterm | 0019978 | 2017-05-17 08:48:12 +0200 | [diff] [blame] | 1 | from docker import DockerClient, APIClient |
| 2 | import time |
| 3 | import re |
| 4 | |
| 5 | |
| 6 | def docker_container_id(container_name): |
| 7 | """ |
| 8 | Uses the container name to return the container ID. |
| 9 | |
| 10 | :param container_name: The full name of the docker container. |
| 11 | :type container_name: ``str`` |
| 12 | :return: Returns the container ID or None if the container is not running or could not be found. |
| 13 | :rtype: ``dict`` |
| 14 | """ |
| 15 | c = APIClient() |
| 16 | detail = c.inspect_container(container_name) |
| 17 | if bool(detail["State"]["Running"]): |
| 18 | return detail['Id'] |
| 19 | return None |
| 20 | |
| 21 | |
| 22 | def docker_abs_cpu(container_id): |
| 23 | """ |
| 24 | Returns the used CPU time since container startup and the system time in nanoseconds and returns the number |
| 25 | of available CPU cores. |
| 26 | |
| 27 | :param container_id: The full ID of the docker container. |
| 28 | :type container_id: ``str`` |
| 29 | :return: Returns a dict with CPU_used in nanoseconds, the current system time in nanoseconds and the number of |
| 30 | CPU cores available. |
| 31 | :rtype: ``dict`` |
| 32 | """ |
| 33 | with open('/sys/fs/cgroup/cpuacct/docker/' + container_id + '/cpuacct.usage_percpu', 'r') as f: |
| 34 | line = f.readline() |
| 35 | sys_time = int(time.time() * 1000000000) |
| 36 | numbers = [int(x) for x in line.split()] |
| 37 | cpu_usage = 0 |
| 38 | for number in numbers: |
| 39 | cpu_usage += number |
| 40 | return {'CPU_used': cpu_usage, 'CPU_used_systime': sys_time, 'CPU_cores': len(numbers)} |
| 41 | |
| 42 | |
| 43 | def docker_mem_used(container_id): |
| 44 | """ |
| 45 | Bytes of memory used from the docker container. |
| 46 | |
| 47 | Note: If you have problems with this command you have to enable memory control group. |
| 48 | For this you have to add the following kernel parameters: `cgroup_enable=memory swapaccount=1`. |
| 49 | See: https://docs.docker.com/engine/admin/runmetrics/ |
| 50 | |
| 51 | :param container_id: The full ID of the docker container. |
| 52 | :type container_id: ``str`` |
| 53 | :return: Returns the memory utilization in bytes. |
| 54 | :rtype: ``str`` |
| 55 | """ |
| 56 | with open('/sys/fs/cgroup/memory/docker/' + container_id + '/memory.usage_in_bytes', 'r') as f: |
| 57 | return int(f.readline()) |
| 58 | |
| 59 | |
| 60 | def docker_max_mem(container_id): |
| 61 | """ |
| 62 | Bytes of memory the docker container could use. |
| 63 | |
| 64 | :param container_id: The full ID of the docker container. |
| 65 | :type container_id: ``str`` |
| 66 | :return: Returns the bytes of memory the docker container could use. |
| 67 | :rtype: ``str`` |
| 68 | """ |
| 69 | with open('/sys/fs/cgroup/memory/docker/' + container_id + '/memory.limit_in_bytes', 'r') as f: |
| 70 | mem_limit = int(f.readline()) |
| 71 | with open('/proc/meminfo', 'r') as f: |
| 72 | line = f.readline().split() |
| 73 | sys_value = int(line[1]) |
| 74 | unit = line[2] |
| 75 | if unit == 'kB': |
| 76 | sys_value *= 1024 |
| 77 | if unit == 'MB': |
| 78 | sys_value *= 1024 * 1024 |
| 79 | |
| 80 | if sys_value < mem_limit: |
| 81 | return sys_value |
| 82 | else: |
| 83 | return mem_limit |
| 84 | |
| 85 | |
| 86 | def docker_mem(container_id): |
| 87 | """ |
| 88 | Calculates the current, maximal and percentage usage of the specified docker container. |
| 89 | |
| 90 | :param container_id: The full ID of the docker container. |
| 91 | :type container_id: ``str`` |
| 92 | :return: Returns a dictionary with the total memory usage, the maximal available memory and the percentage |
| 93 | memory usage. |
| 94 | :rtype: ``dict`` |
| 95 | """ |
| 96 | out_dict = dict() |
| 97 | out_dict['MEM_used'] = docker_mem_used(container_id) |
| 98 | out_dict['MEM_limit'] = docker_max_mem(container_id) |
| 99 | out_dict['MEM_%'] = float(out_dict['MEM_used']) / float(out_dict['MEM_limit']) |
| 100 | return out_dict |
| 101 | |
| 102 | |
| 103 | def docker_abs_net_io(container_id): |
| 104 | """ |
| 105 | Network traffic of all network interfaces within the controller. |
| 106 | |
| 107 | :param container_id: The full ID of the docker container. |
| 108 | :type container_id: ``str`` |
| 109 | :return: Returns the absolute network I/O till container startup, in bytes. The return dict also contains the |
| 110 | system time. |
| 111 | :rtype: ``dict`` |
| 112 | """ |
| 113 | c = APIClient() |
| 114 | command = c.exec_create(container_id, 'ifconfig') |
| 115 | ifconfig = c.exec_start(command['Id']) |
| 116 | sys_time = int(time.time() * 1000000000) |
| 117 | |
| 118 | in_bytes = 0 |
| 119 | m = re.findall('RX bytes:(\d+)', str(ifconfig)) |
| 120 | if m: |
| 121 | for number in m: |
| 122 | in_bytes += int(number) |
| 123 | else: |
| 124 | in_bytes = None |
| 125 | |
| 126 | out_bytes = 0 |
| 127 | m = re.findall('TX bytes:(\d+)', str(ifconfig)) |
| 128 | if m: |
| 129 | for number in m: |
| 130 | out_bytes += int(number) |
| 131 | else: |
| 132 | out_bytes = None |
| 133 | |
| 134 | return {'NET_in': in_bytes, 'NET_out': out_bytes, 'NET_systime': sys_time} |
| 135 | |
| 136 | |
| 137 | def docker_block_rw(container_id): |
| 138 | """ |
| 139 | Determines the disk read and write access from the controller since startup. |
| 140 | |
| 141 | :param container_id: The full ID of the docker container. |
| 142 | :type container_id: ``str`` |
| 143 | :return: Returns a dictionary with the total disc I/O since container startup, in bytes. |
| 144 | :rtype: ``dict`` |
| 145 | """ |
| 146 | with open('/sys/fs/cgroup/blkio/docker/' + container_id + '/blkio.throttle.io_service_bytes', 'r') as f: |
| 147 | read = f.readline().split() |
| 148 | write = f.readline().split() |
| 149 | rw_dict = dict() |
| 150 | rw_dict['BLOCK_systime'] = int(time.time() * 1000000000) |
| 151 | if len(read) < 3: |
| 152 | rw_dict['BLOCK_read'] = 0 |
| 153 | else: |
| 154 | rw_dict['BLOCK_read'] = read[2] |
| 155 | if len(write) < 3: |
| 156 | rw_dict['BLOCK_write'] = 0 |
| 157 | else: |
| 158 | rw_dict['BLOCK_write'] = write[2] |
| 159 | return rw_dict |
| 160 | |
| 161 | |
| 162 | def docker_PIDS(container_id): |
| 163 | """ |
| 164 | Determines the number of processes within the docker container. |
| 165 | |
| 166 | :param container_id: The full ID of the docker container. |
| 167 | :type container_id: ``str`` |
| 168 | :return: Returns the number of PIDS within a dictionary. |
| 169 | :rtype: ``dict`` |
| 170 | """ |
| 171 | with open('/sys/fs/cgroup/cpuacct/docker/' + container_id + '/tasks', 'r') as f: |
| 172 | return {'PIDS': len(f.read().split('\n')) - 1} |
| 173 | |
| 174 | |
| 175 | def monitoring_over_time(container_id): |
| 176 | """ |
| 177 | Calculates the cpu workload and the network traffic per second. |
| 178 | |
| 179 | :param container_id: The full docker container ID |
| 180 | :type container_id: ``str`` |
| 181 | :return: A dictionary with disk read and write per second, network traffic per second (in and out), |
| 182 | the cpu workload and the number of cpu cores available. |
| 183 | :rtype: ``dict`` |
| 184 | """ |
| 185 | first_cpu_usage = docker_abs_cpu(container_id) |
| 186 | first = docker_abs_net_io(container_id) |
| 187 | first_disk_io = docker_block_rw(container_id) |
| 188 | time.sleep(1) |
| 189 | second_cpu_usage = docker_abs_cpu(container_id) |
| 190 | second = docker_abs_net_io(container_id) |
| 191 | second_disk_io = docker_block_rw(container_id) |
| 192 | |
| 193 | # Disk access |
| 194 | time_div = (int(second_disk_io['BLOCK_systime']) - int(first_disk_io['BLOCK_systime'])) |
| 195 | read_div = int(second_disk_io['BLOCK_read']) - int(first_disk_io['BLOCK_read']) |
| 196 | write_div = int(second_disk_io['BLOCK_write']) - int(first_disk_io['BLOCK_write']) |
| 197 | out_dict = {'BLOCK_read/s': int(read_div * 1000000000 / float(time_div) + 0.5), |
| 198 | 'BLOCK_write/s': int(write_div * 1000000000 / float(time_div) + 0.5)} |
| 199 | |
| 200 | # Network traffic |
| 201 | time_div = (int(second['NET_systime']) - int(first['NET_systime'])) |
| 202 | in_div = int(second['NET_in']) - int(first['NET_in']) |
| 203 | out_div = int(second['NET_out']) - int(first['NET_out']) |
| 204 | out_dict.update({'NET_in/s': int(in_div * 1000000000 / float(time_div) + 0.5), |
| 205 | 'NET_out/s': int(out_div * 1000000000 / float(time_div) + 0.5)}) |
| 206 | |
| 207 | # CPU utilization |
| 208 | time_div = (int(second_cpu_usage['CPU_used_systime']) - int(first_cpu_usage['CPU_used_systime'])) |
| 209 | usage_div = int(second_cpu_usage['CPU_used']) - int(first_cpu_usage['CPU_used']) |
| 210 | out_dict.update({'CPU_%': usage_div / float(time_div), 'CPU_cores': first_cpu_usage['CPU_cores']}) |
| 211 | return out_dict |