diff options
Diffstat (limited to 'vstf/vstf/agent/env/fsmonitor')
-rwxr-xr-x | vstf/vstf/agent/env/fsmonitor/FSMonitor.py | 215 | ||||
-rwxr-xr-x | vstf/vstf/agent/env/fsmonitor/Readme | 13 | ||||
-rwxr-xr-x | vstf/vstf/agent/env/fsmonitor/__init__.py | 14 | ||||
-rwxr-xr-x | vstf/vstf/agent/env/fsmonitor/constant.py | 17 | ||||
-rwxr-xr-x | vstf/vstf/agent/env/fsmonitor/utils.py | 110 |
5 files changed, 369 insertions, 0 deletions
diff --git a/vstf/vstf/agent/env/fsmonitor/FSMonitor.py b/vstf/vstf/agent/env/fsmonitor/FSMonitor.py new file mode 100755 index 00000000..71029705 --- /dev/null +++ b/vstf/vstf/agent/env/fsmonitor/FSMonitor.py @@ -0,0 +1,215 @@ +""" +Created on 2015-7-13 + +@author: y00228926 +""" +import os +import time +import logging +import subprocess +import sys + +import constant +from utils import IPCommandHelper, umount, check_and_rmmod, check_output, check_call, call + +LOG_FILE = '/tmp/fsmonitor.log' +PID_FILE = '/tmp/fsmonitor.pid' +LOG = logging.getLogger('__name__') + + +class VMOperation(object): + def __init__(self): + self.RTE_SDK = '/home/dpdk-2.0.0' + self.RTE_TARGET = 'x86_64-native-linuxapp-gcc' + self.nr_hugepages = '512' + self.pid = 0 + self.ip_helper = IPCommandHelper() + + def config_ip(self, mac, ip): + device = self.ip_helper.mac_device_map[mac] + check_call("ifconfig %s %s up" % (device, ip), shell=True) + + def config_gw(self, ip): + call("route del default", shell=True) + check_call("route add default gw %s" % ip, shell=True) + + def recover_nic_binding(self, *tap_macs): + if self.pid: + os.kill(self.pid, 9) + self.pid = None + bdf_str = '' + for mac in tap_macs: + bdf = self.ip_helper.mac_bdf_map[mac] + bdf_str = bdf_str + ' ' + bdf + cmd = 'python %s/tools/dpdk_nic_bind.py --bind=virtio-pci %s' % (self.RTE_SDK, bdf_str) + LOG.debug("recover_nic_binding runs cmd = %s", cmd) + check_call(cmd, shell=True) + + def set_pktloop_dpdk(self, *tap_macs): + RTE_SDK = self.RTE_SDK + RTE_TARGET = self.RTE_TARGET + umount("/mnt/huge") + with open('/sys/kernel/mm/hugepages/hugepages-2048kB/nr_hugepages', 'w') as f: + f.write(self.nr_hugepages) + check_call("mkdir -p /mnt/huge", shell=True) + check_call("mount -t hugetlbfs nodev /mnt/huge", shell=True) + check_call("modprobe uio", shell=True) + check_and_rmmod('igb_uio') + check_call("insmod %s/%s/kmod/igb_uio.ko" % (RTE_SDK, RTE_TARGET), shell=True) + + bdf_str = '' + for mac in tap_macs: + bdf = self.ip_helper.mac_bdf_map[mac] + bdf_str = bdf_str + ' ' + bdf + + check_call('python %s/tools/dpdk_nic_bind.py --bind=igb_uio %s' % (RTE_SDK, bdf_str), shell=True) + cpu_num = int(check_output('cat /proc/cpuinfo | grep processor | wc -l', shell=True)) + cpu_bit_mask = 0 + i = cpu_num + while i: + cpu_bit_mask = (cpu_bit_mask << 1) + 1 + i -= 1 + cpu_bit_mask = hex(cpu_bit_mask) + cmd = "%s/%s/app/testpmd -c %s -n %d -- --disable-hw-vlan --disable-rss --nb-cores=%d --rxq=%d --txq=%d --rxd=4096 --txd=4096" % ( + RTE_SDK, + RTE_TARGET, + cpu_bit_mask, + cpu_num / 2, + cpu_num - 1, + (cpu_num - 1) / 2, + (cpu_num - 1) / 2 + ) + LOG.info("set_pktloop_dpdk runs cmd = %s", cmd) + p = subprocess.Popen(cmd.split()) + if not p.poll(): + self.pid = p.pid + return True + else: + raise Exception("start testpmd failed") + + def config_amqp(self, file_name): + if not os.path.isfile(file_name): + raise Exception("file: %s not exists." % file_name) + check_call("cp %s /etc/vstf/amqp/amqp.ini" % file_name, shell=True) + check_call("vstf-agent restart", shell=True) + return True + + def stop_vstf(self): + check_call("vstf-agent stop", shell=True) + return True + + +class FSMonitor(object): + def __init__(self, pidfile=None, interval=1): + if pidfile: + self.pidfile = pidfile + else: + self.pidfile = PID_FILE + self.interval = interval + self.handlers = [] + self.kill_old() + umount(constant.FS_MOUNT_POINT) + check_call("mkdir -p %s" % constant.FS_MOUNT_POINT, shell=True) + check_call("mount -t 9p 9pfs %s" % constant.FS_MOUNT_POINT, shell=True) + os.chdir(constant.FS_MOUNT_POINT) + with open(constant.VM_UP_Flag_FILE, 'w'): + pass + + def kill_old(self): + out = check_output("ps -ef | grep -v grep | egrep 'python.*%s' | awk '{print $2}'" % sys.argv[0], + shell=True) + if out: + for pid in out.split(): + if int(pid) != os.getpid(): + os.kill(int(pid), 9) + LOG.debug("found daemon:pid=%s and kill.", pid) + + def set_fail(self, failed_reason): + with open(constant.VM_CMD_RETURN_CODE_FILE, 'w') as f: + f.writelines([constant.VM_CMD_EXCUTE_FAILED_FLAG_CONTENT, '\n', failed_reason]) + with open(constant.VM_CMD_DONE_FLAG_FILE, 'w') as f: + pass + + def set_success(self): + with open(constant.VM_CMD_RETURN_CODE_FILE, 'w') as f: + f.write(constant.VM_CMD_EXCUTE_SUCCES_FLAG_CONTENT) + with open(constant.VM_CMD_DONE_FLAG_FILE, 'w') as f: + pass + + def register_handler(self, obj): + self.handlers.append(obj) + + def daemonize(self): + try: + pid = os.fork() + if pid > 0: + sys.exit(0) + except OSError, e: + sys.stderr.write('fork #1 failed:%d,(%s)\n' % (e.errno, e.strerror)) + sys.exit(1) + os.setsid() + os.umask(0) + try: + pid = os.fork() + if pid > 0: + sys.exit(0) + except OSError, e: + sys.stderr.write('fork #2 failed:%d,(%s)\n' % (e.errno, e.strerror)) + sys.exit(1) + LOG.debug("pid:%d,ppid:%d,sid:%d", os.getpid(), os.getppid(), os.getsid(os.getpid())) + old = open('/dev/null', 'r') + os.dup2(old.fileno(), sys.stdin.fileno()) + old = open('/dev/null', 'a+') + os.dup2(old.fileno(), sys.stdout.fileno()) + old = open('/dev/null', 'a+', 0) + os.dup2(old.fileno(), sys.stderr.fileno()) + pid = str(os.getpid()) + file(self.pidfile, 'w+').write('%s\n' % pid) + + def run_forever(self): + # todo:resolve handlers name space conflict + self.daemonize() + while True: + time.sleep(self.interval) + files = os.listdir(constant.FS_MOUNT_POINT) + if constant.VM_CMD_SET_FLAG_FILE in files and constant.VM_CMD_CONTENT_FILE in files: + with open(constant.VM_CMD_CONTENT_FILE, 'r') as f: + out = f.read().strip() + LOG.debug("new command arrived:%s", out) + cmd_param = out.split() + cmd = cmd_param[0] + param = cmd_param[1:] + for obj in self.handlers: + if hasattr(obj, cmd) and callable(getattr(obj, cmd)): + LOG.debug("method:%s found!", cmd) + method = getattr(obj, cmd) + try: + method(*param) + self.set_success() + LOG.debug("cmd sucessfully done") + except Exception, e: + LOG.debug('failed to run:%s %s,reason:%s', cmd, param, str(e)) + self.set_fail(str(e)) + break + else: + LOG.debug("method:%s not found!", cmd) + self.set_fail(constant.VM_CMD_NOT_FOUND) + os.remove(constant.VM_CMD_SET_FLAG_FILE) + os.remove(constant.VM_CMD_CONTENT_FILE) + + +if __name__ == '__main__': + # echo "set_pktloop_dpdk" > command;touch command_set + # echo "recover_nic_binding" > command;touch command_set + # echo "config_ip 56:6f:44:a5:3f:a2 192.168.188.200/23" > command;touch command_set + # echo "config_gw 192.168.188.1" > command;touch command_set + # echo set_pktloop_dpdk 56:6f:44:a5:3f:a2 56:6f:44:a5:3f:a3 > command;touch command_set + # echo recover_nic_binding 56:6f:44:a5:3f:a2 56:6f:44:a5:3f:a3 > command;touch command_set + import os + logging.basicConfig(level=logging.DEBUG, filename=LOG_FILE, filemode='w') + os.environ['PATH'] = os.environ["PATH"] + ":/usr/local/bin" + LOG.info(os.environ['PATH']) + vm_op = VMOperation() + agent = FSMonitor() + agent.register_handler(vm_op) + agent.run_forever() diff --git a/vstf/vstf/agent/env/fsmonitor/Readme b/vstf/vstf/agent/env/fsmonitor/Readme new file mode 100755 index 00000000..f2bf9a8e --- /dev/null +++ b/vstf/vstf/agent/env/fsmonitor/Readme @@ -0,0 +1,13 @@ +FSMonitor is a daemon process which runs in the vm. +FSMonitor receive "commands" from 'VmManager' by libvirt 9pfs. + +Basically the process works like this: + 1.The 'VmManager' writes 'command string' to 'command' file on the libvirt 9pfs used by vm. + 2.The FSMonitor constantly detects file changes on the libvirt 9pfs. + 3.The FSMonitor finds the newly created file, it then reads the file and execute the command. + +All the dependencies of FSMonitor should be satisfied by modules in this directory. + +When deploying FSMonitor, just copy this directory into the vm. + + diff --git a/vstf/vstf/agent/env/fsmonitor/__init__.py b/vstf/vstf/agent/env/fsmonitor/__init__.py new file mode 100755 index 00000000..89dcd4e2 --- /dev/null +++ b/vstf/vstf/agent/env/fsmonitor/__init__.py @@ -0,0 +1,14 @@ +# Copyright Huawei Technologies Co., Ltd. 1998-2015. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the License); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an AS IS BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. diff --git a/vstf/vstf/agent/env/fsmonitor/constant.py b/vstf/vstf/agent/env/fsmonitor/constant.py new file mode 100755 index 00000000..d30bb439 --- /dev/null +++ b/vstf/vstf/agent/env/fsmonitor/constant.py @@ -0,0 +1,17 @@ +""" +Created on 2015-8-27 + +@author: y00228926 +""" +VM_UP_Flag_FILE = 'up' +VM_CMD_DONE_FLAG_FILE = 'command_done' +VM_CMD_RESULT_FILE = 'command_result_data' +VM_CMD_SET_FLAG_FILE = 'command_set' +VM_CMD_CONTENT_FILE = 'command' +VM_CMD_RETURN_CODE_FILE = 'command_result' +VM_CMD_EXCUTE_SUCCES_FLAG_CONTENT = 'success' +VM_CMD_EXCUTE_FAILED_FLAG_CONTENT = 'fail' +VM_CMD_NOT_FOUND = 'comamnd_not_found' +VM_UP_TIME_OUT = 120 +VM_COMMON_CMD_EXCUTE_TIME_OUT = 10 +FS_MOUNT_POINT = '/mnt/9pfs'
\ No newline at end of file diff --git a/vstf/vstf/agent/env/fsmonitor/utils.py b/vstf/vstf/agent/env/fsmonitor/utils.py new file mode 100755 index 00000000..e6eb1536 --- /dev/null +++ b/vstf/vstf/agent/env/fsmonitor/utils.py @@ -0,0 +1,110 @@ +""" +Created on 2015-7-8 + +@author: y00228926 +""" +import subprocess +from StringIO import StringIO +import re +import logging + +LOG = logging.getLogger(__name__) + + +def call(cmd, shell=False): + if shell: + LOG.info(cmd) + else: + LOG.info(' '.join(cmd)) + return subprocess.call(cmd, shell=shell) + + +def check_call(cmd, shell=False): + if shell: + LOG.info(cmd) + else: + LOG.info(' '.join(cmd)) + subprocess.check_call(cmd, shell=shell) + + +def check_output(cmd, shell=False): + if shell: + LOG.info(cmd) + else: + LOG.info(' '.join(cmd)) + return subprocess.check_output(cmd, shell=shell) + + +def check_and_kill(process): + cmd = "ps -ef | grep -v grep | awk '{print $8}' | grep -w %s | wc -l" % process + out = check_output(cmd, shell=True) + if int(out): + check_call(['killall', process]) + + +def check_and_rmmod(mod): + cmd = "lsmod | awk '{print $1}' | grep -w %s | wc -l" % mod + out = check_output(cmd, shell=True) + if int(out): + check_call(['rmmod', mod]) + + +def umount(path): + mount_path_set = set() + out = check_output("cat /proc/mounts", shell=True) + f = StringIO(out) + line = f.readline() + while line: + line = f.readline() + if line: + mpath = line.split()[1] + mount_path_set.add(mpath) + if path in mount_path_set: + ret = call("umount %s" % path, shell=True) + return ret == 0 + return True + + +class IPCommandHelper(object): + def __init__(self): + self.devices = [] + self.macs = [] + self.device_mac_map = {} + self.mac_device_map = {} + self.bdf_device_map = {} + self.device_bdf_map = {} + self.mac_bdf_map = {} + self.bdf_mac_map = {} + buf = check_output("ip link", shell=True) + macs = re.compile("[A-F0-9]{2}(?::[A-F0-9]{2}){5}", re.IGNORECASE | re.MULTILINE) + for mac in macs.findall(buf): + if mac.lower() in ('00:00:00:00:00:00', 'ff:ff:ff:ff:ff:ff'): + continue + self.macs.append(mac) + sio = StringIO(buf) + for line in sio: + m = re.match(r'^\d+:(.*):.*', line) + if m and m.group(1).strip() != 'lo': + self.devices.append(m.group(1).strip()) + for device, mac in zip(self.devices, self.macs): + self.device_mac_map[device] = mac + self.mac_device_map[mac] = device + for device in self.devices: + buf = check_output("ethtool -i %s" % device, shell=True) + bdfs = re.findall(r'^bus-info: \d{4}:(\d{2}:\d{2}\.\d*)$', buf, re.MULTILINE) + if bdfs: + self.bdf_device_map[bdfs[0]] = device + self.device_bdf_map[device] = bdfs[0] + mac = self.device_mac_map[device] + self.mac_bdf_map[mac] = bdfs[0] + self.bdf_mac_map[bdfs[0]] = mac + + +if __name__ == '__main__': + ip_helper = IPCommandHelper() + print ip_helper.device_mac_map + print ip_helper.mac_device_map + print ip_helper.bdf_device_map + print ip_helper.device_bdf_map + print ip_helper.mac_bdf_map + print ip_helper.bdf_mac_map |