-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Add daemon which periodically pushes process and docker stats to State DB #3525
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
jleveque
merged 21 commits into
sonic-net:master
from
pra-moh:dev/pramoh/procdockdaemon
Nov 27, 2019
Merged
Changes from 4 commits
Commits
Show all changes
21 commits
Select commit
Hold shift + click to select a range
d0f36ee
adding draft for daemon getting process data
pra-moh 58b59dc
resolving PR comments, adding separate method for docker
pra-moh d5cf0f0
adjusting whitespace
pra-moh b085b5b
adding process data output parsing to daemon
pra-moh 9624514
adjusting space
pra-moh f1b2d8a
removing trailing spaces
pra-moh 57da086
adding seperate method for docker data formatting
pra-moh 9119ba9
uncommenting root check
pra-moh cd49b30
resolving comments on constant name, rounded integer
pra-moh a56b356
Resolving comment for converting to integer and uppercase for table n…
pra-moh 8d0ef54
adding restart=always
pra-moh 0c51c28
adding entry in sonic_debian_extension.j2
pra-moh 147719f
added new line at end of file
pra-moh b00378d
uppercase for process and docker_stats
pra-moh 57c33ed
trying to add changes from previous commit
pra-moh e2f147d
correcting return statement
pra-moh f049311
appending BYTES to converted columns
pra-moh cd00617
changing top 5 to 1024 processes
pra-moh 14a1056
adding d to suggest daemon file
pra-moh 4270c30
removing d from classname
pra-moh eedab12
adding database.service as dependency
pra-moh File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,162 @@ | ||
# !/usr/bin/env python | ||
''' | ||
This code is for a specific daemon, process-docker. | ||
Which sends process and docker CPU/memory utilization data to DB every 2 mins. | ||
''' | ||
|
||
import sys | ||
import os | ||
import time | ||
import syslog | ||
import subprocess | ||
import re | ||
import swsssdk | ||
jleveque marked this conversation as resolved.
Show resolved
Hide resolved
|
||
from datetime import datetime | ||
jleveque marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
VERSION = '1.0' | ||
SYSLOG_IDENTIFIER = "procdockerstats" | ||
REDIS_HOSTIP = "127.0.0.1" | ||
|
||
# ========================== Syslog wrappers ========================== | ||
def log_info(msg, also_print_to_console=False): | ||
syslog.openlog(SYSLOG_IDENTIFIER) | ||
syslog.syslog(syslog.LOG_INFO, msg) | ||
syslog.closelog() | ||
|
||
def log_warning(msg, also_print_to_console=False): | ||
syslog.openlog(SYSLOG_IDENTIFIER) | ||
syslog.syslog(syslog.LOG_WARNING, msg) | ||
syslog.closelog() | ||
|
||
def log_error(msg, also_print_to_console=False): | ||
syslog.openlog(SYSLOG_IDENTIFIER) | ||
syslog.syslog(syslog.LOG_ERR, msg) | ||
syslog.closelog() | ||
|
||
# ========================== ProcessDocker class ========================== | ||
class ProcDockerStats: | ||
|
||
def __init__(self): | ||
self.state_db = swsssdk.SonicV2Connector(host=REDIS_HOSTIP) | ||
self.state_db.connect("STATE_DB") | ||
pra-moh marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
jleveque marked this conversation as resolved.
Show resolved
Hide resolved
|
||
def run_command(self, cmd): | ||
proc = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE) | ||
(stdout, stderr) = proc.communicate() | ||
if proc.returncode != 0: | ||
log_error("Error running command '{}'".format(cmd)) | ||
jleveque marked this conversation as resolved.
Show resolved
Hide resolved
|
||
else: | ||
return stdout | ||
|
||
def format_docker_cmd_output(self, cmdout): | ||
lines = re.split("\n", cmdout) | ||
keys = re.split(" +", lines[0]) | ||
dict1 = dict() | ||
jleveque marked this conversation as resolved.
Show resolved
Hide resolved
|
||
dict_list = [] | ||
for item in lines[1:]: | ||
values1 = re.split(" +", item) | ||
dict1 = dict(zip(keys, values1)) | ||
pra-moh marked this conversation as resolved.
Show resolved
Hide resolved
|
||
dict_list.append(dict1) | ||
return dict_list | ||
|
||
def format_process_cmd_output(self, cmdout): | ||
lines = re.split("\n", cmdout) | ||
keys = re.split(" +", lines[0]) | ||
keylist = list(filter(None, keys)) | ||
dict1 = dict() | ||
jleveque marked this conversation as resolved.
Show resolved
Hide resolved
|
||
dict_list = [] | ||
for item in lines[1:]: | ||
values1 = re.split(" +", str(item)) | ||
# To remove extra space before UID | ||
val = list(filter(None, values1)) | ||
# Merging extra columns created due to space in cmd ouput | ||
val[8:] = [''.join(val[8:])] | ||
jleveque marked this conversation as resolved.
Show resolved
Hide resolved
|
||
dict1 = dict(zip(keylist, val)) | ||
dict_list.append(dict1) | ||
return dict_list | ||
|
||
jleveque marked this conversation as resolved.
Show resolved
Hide resolved
|
||
def update_dockerstats_command(self): | ||
pra-moh marked this conversation as resolved.
Show resolved
Hide resolved
|
||
data = self.run_command("docker stats --no-stream -a") | ||
dockerdata = self.format_docker_cmd_output(data) | ||
value = "" | ||
# wipe out all data before updating with new values | ||
self.state_db.delete_all_by_pattern('STATE_DB', 'Docker_Stats|*') | ||
jleveque marked this conversation as resolved.
Show resolved
Hide resolved
|
||
for row in dockerdata[0:]: | ||
cid = row.get('CONTAINER ID') | ||
if cid: | ||
value = 'Docker_Stats|' + str(cid) | ||
name = row.get('NAME') | ||
self.update_state_db(value, 'NAME', name) | ||
cpu = row.get('CPU %') | ||
self.update_state_db(value, 'CPU%', str(cpu)) | ||
splitcol = row.get('MEM USAGE / LIMIT') | ||
memuse = re.split(" / ", str(splitcol)) | ||
self.update_state_db(value, 'MEM', str(memuse[0])) | ||
self.update_state_db(value, 'MEM_LIMIT', str(memuse[1])) | ||
mem = row.get('MEM %') | ||
self.update_state_db(value, 'MEM %', str(mem)) | ||
splitcol = row.get('NET I/O') | ||
netio = re.split(" / ", str(splitcol)) | ||
self.update_state_db(value, 'NET_IN', str(netio[0])) | ||
self.update_state_db(value, 'NET_OUT', str(netio[1])) | ||
splitcol = row.get('BLOCK I/O') | ||
blocio = re.split(" / ", str(splitcol)) | ||
self.update_state_db(value, 'BLOCK_IN', str(blocio[0])) | ||
self.update_state_db(value, 'BLOCK_OUT', str(blocio[1])) | ||
pids = row.get('PIDS') | ||
self.update_state_db(value, 'PIDS', pids) | ||
|
||
jleveque marked this conversation as resolved.
Show resolved
Hide resolved
|
||
def update_processstats_command(self): | ||
|
||
jleveque marked this conversation as resolved.
Show resolved
Hide resolved
jleveque marked this conversation as resolved.
Show resolved
Hide resolved
|
||
data = self.run_command("ps -eo uid,pid,ppid,%mem,%cpu,stime,tty,time,cmd --sort -%cpu | head -1024") | ||
processdata = self.format_process_cmd_output(data) | ||
value = "" | ||
# wipe out all data before updating with new values | ||
self.state_db.delete_all_by_pattern('STATE_DB', 'Process_Stats|*') | ||
for row in processdata[0:]: | ||
cid = row.get('PID') | ||
if cid: | ||
value = 'Process_Stats|' + str(cid) | ||
uid = row.get('UID') | ||
self.update_state_db(value, 'UID', uid) | ||
ppid = row.get('PPID') | ||
self.update_state_db(value, 'PPID', ppid) | ||
cpu = row.get('%CPU') | ||
self.update_state_db(value, '%CPU', str(cpu)) | ||
mem = row.get('%MEM') | ||
self.update_state_db(value, '%MEM', str(mem)) | ||
stime = row.get('STIME') | ||
self.update_state_db(value, 'STIME', stime) | ||
tty = row.get('TT') | ||
self.update_state_db(value, 'TT', tty) | ||
time = row.get('TIME') | ||
self.update_state_db(value, 'TIME', time) | ||
cmd = row.get('CMD') | ||
self.update_state_db(value, 'CMD', cmd) | ||
|
||
jleveque marked this conversation as resolved.
Show resolved
Hide resolved
|
||
def update_state_db(self, key1, key2, value2): | ||
self.state_db.set('STATE_DB', key1, key2, value2) | ||
|
||
def run(self): | ||
self.update_dockerstats_command() | ||
datetimeobj = datetime.now() | ||
# Adding key to store latest update time. | ||
self.update_state_db('Docker_Stats|LastUpdateTime', 'lastupdate', datetimeobj) | ||
jleveque marked this conversation as resolved.
Show resolved
Hide resolved
|
||
self.update_processstats_command() | ||
self.update_state_db('Process_Stats|LastUpdateTime', 'lastupdate', datetimeobj) | ||
jleveque marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
# main start | ||
def main(): | ||
log_info("process-docker stats aemon starting up..") | ||
if not os.getuid() == 0: | ||
log_error("Must be root to run process-docker daemon") | ||
print "Error: Must be root to run process-docker daemon" | ||
sys.exit(1) | ||
jleveque marked this conversation as resolved.
Show resolved
Hide resolved
|
||
pd = ProcDockerStats() | ||
# Data need to be updated every 2 mins. hence adding delay of 120 seconds | ||
time.sleep(120) | ||
pd.run() | ||
log_info("process-docker stats daemon exited") | ||
|
||
if __name__ == '__main__': | ||
main() |
12 changes: 12 additions & 0 deletions
12
files/image_config/procdockerstats/procdockerstats.service
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
[Unit] | ||
Description=Control Plane ACL configuration daemon | ||
Requires=updategraph.service | ||
After=updategraph.service | ||
|
||
[Service] | ||
Type=simple | ||
ExecStart=/usr/bin/procdockerstats | ||
|
||
[Install] | ||
WantedBy=multi-user.target | ||
|
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.