JIRA: BOTTLENECKS-29
[bottlenecks.git] / vstf / vstf / agent / env / fsmonitor / FSMonitor.py
1 ##############################################################################
2 # Copyright (c) 2015 Huawei Technologies Co.,Ltd and others.
3 #
4 # All rights reserved. This program and the accompanying materials
5 # are made available under the terms of the Apache License, Version 2.0
6 # which accompanies this distribution, and is available at
7 # http://www.apache.org/licenses/LICENSE-2.0
8 ##############################################################################
9
10
11 import os
12 import time
13 import logging
14 import subprocess
15 import sys
16
17 import constant
18 from utils import IPCommandHelper, umount, check_and_rmmod, check_output, check_call, call
19
20 LOG_FILE = '/tmp/fsmonitor.log'
21 PID_FILE = '/tmp/fsmonitor.pid'
22 LOG = logging.getLogger('__name__')
23
24
25 class VMOperation(object):
26     def __init__(self):
27         self.RTE_SDK = '/home/dpdk-2.0.0'
28         self.RTE_TARGET = 'x86_64-native-linuxapp-gcc'
29         self.nr_hugepages = '512'
30         self.pid = 0
31         self.ip_helper = IPCommandHelper()
32
33     def config_ip(self, mac, ip):
34         device = self.ip_helper.mac_device_map[mac]
35         check_call("ifconfig %s %s up" % (device, ip), shell=True)
36
37     def config_gw(self, ip):
38         call("route del default", shell=True)
39         check_call("route add default gw %s" % ip, shell=True)
40
41     def recover_nic_binding(self, *tap_macs):
42         if self.pid:
43             os.kill(self.pid, 9)
44             self.pid = None
45         bdf_str = ''
46         for mac in tap_macs:
47             bdf = self.ip_helper.mac_bdf_map[mac]
48             bdf_str = bdf_str + ' ' + bdf
49         cmd = 'python %s/tools/dpdk_nic_bind.py --bind=virtio-pci %s' % (self.RTE_SDK, bdf_str)
50         LOG.debug("recover_nic_binding runs cmd = %s", cmd)
51         check_call(cmd, shell=True)
52
53     def set_pktloop_dpdk(self, *tap_macs):
54         RTE_SDK = self.RTE_SDK
55         RTE_TARGET = self.RTE_TARGET
56         umount("/mnt/huge")
57         with open('/sys/kernel/mm/hugepages/hugepages-2048kB/nr_hugepages', 'w') as f:
58             f.write(self.nr_hugepages)
59         check_call("mkdir -p /mnt/huge", shell=True)
60         check_call("mount -t hugetlbfs nodev /mnt/huge", shell=True)
61         check_call("modprobe uio", shell=True)
62         check_and_rmmod('igb_uio')
63         check_call("insmod %s/%s/kmod/igb_uio.ko" % (RTE_SDK, RTE_TARGET), shell=True)
64
65         bdf_str = ''
66         for mac in tap_macs:
67             bdf = self.ip_helper.mac_bdf_map[mac]
68             bdf_str = bdf_str + ' ' + bdf
69
70         check_call('python %s/tools/dpdk_nic_bind.py --bind=igb_uio %s' % (RTE_SDK, bdf_str), shell=True)
71         cpu_num = int(check_output('cat /proc/cpuinfo | grep processor | wc -l', shell=True))
72         cpu_bit_mask = 0
73         i = cpu_num
74         while i:
75             cpu_bit_mask = (cpu_bit_mask << 1) + 1
76             i -= 1
77         cpu_bit_mask = hex(cpu_bit_mask)
78         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" % (
79             RTE_SDK,
80             RTE_TARGET,
81             cpu_bit_mask,
82             cpu_num / 2,
83             cpu_num - 1,
84             (cpu_num - 1) / 2,
85             (cpu_num - 1) / 2
86         )
87         LOG.info("set_pktloop_dpdk runs cmd = %s", cmd)
88         p = subprocess.Popen(cmd.split())
89         if not p.poll():
90             self.pid = p.pid
91             return True
92         else:
93             raise Exception("start testpmd failed")
94
95     def config_amqp(self, file_name):
96         if not os.path.isfile(file_name):
97             raise Exception("file: %s not exists." % file_name)
98         check_call("cp %s /etc/vstf/amqp/amqp.ini" % file_name, shell=True)
99         check_call("vstf-agent restart", shell=True)
100         return True
101
102     def stop_vstf(self):
103         check_call("vstf-agent stop", shell=True)
104         return True
105
106
107 class FSMonitor(object):
108     def __init__(self, pidfile=None, interval=1):
109         if pidfile:
110             self.pidfile = pidfile
111         else:
112             self.pidfile = PID_FILE
113         self.interval = interval
114         self.handlers = []
115         self.kill_old()
116         umount(constant.FS_MOUNT_POINT)
117         check_call("mkdir -p %s" % constant.FS_MOUNT_POINT, shell=True)
118         check_call("mount -t 9p 9pfs %s" % constant.FS_MOUNT_POINT, shell=True)
119         os.chdir(constant.FS_MOUNT_POINT)
120         with open(constant.VM_UP_Flag_FILE, 'w'):
121             pass
122
123     def kill_old(self):
124         out = check_output("ps -ef | grep -v grep | egrep 'python.*%s' | awk '{print $2}'" % sys.argv[0],
125                                       shell=True)
126         if out:
127             for pid in out.split():
128                 if int(pid) != os.getpid():
129                     os.kill(int(pid), 9)
130                     LOG.debug("found daemon:pid=%s and kill.", pid)
131
132     def set_fail(self, failed_reason):
133         with open(constant.VM_CMD_RETURN_CODE_FILE, 'w') as f:
134             f.writelines([constant.VM_CMD_EXCUTE_FAILED_FLAG_CONTENT, '\n', failed_reason])
135         with open(constant.VM_CMD_DONE_FLAG_FILE, 'w') as f:
136             pass
137
138     def set_success(self):
139         with open(constant.VM_CMD_RETURN_CODE_FILE, 'w') as f:
140             f.write(constant.VM_CMD_EXCUTE_SUCCES_FLAG_CONTENT)
141         with open(constant.VM_CMD_DONE_FLAG_FILE, 'w') as f:
142             pass
143
144     def register_handler(self, obj):
145         self.handlers.append(obj)
146
147     def daemonize(self):
148         try:
149             pid = os.fork()
150             if pid > 0:
151                 sys.exit(0)
152         except OSError, e:
153             sys.stderr.write('fork #1 failed:%d,(%s)\n' % (e.errno, e.strerror))
154             sys.exit(1)
155         os.setsid()
156         os.umask(0)
157         try:
158             pid = os.fork()
159             if pid > 0:
160                 sys.exit(0)
161         except OSError, e:
162             sys.stderr.write('fork #2 failed:%d,(%s)\n' % (e.errno, e.strerror))
163             sys.exit(1)
164         LOG.debug("pid:%d,ppid:%d,sid:%d", os.getpid(), os.getppid(), os.getsid(os.getpid()))
165         old = open('/dev/null', 'r')
166         os.dup2(old.fileno(), sys.stdin.fileno())
167         old = open('/dev/null', 'a+')
168         os.dup2(old.fileno(), sys.stdout.fileno())
169         old = open('/dev/null', 'a+', 0)
170         os.dup2(old.fileno(), sys.stderr.fileno())
171         pid = str(os.getpid())
172         file(self.pidfile, 'w+').write('%s\n' % pid)
173
174     def run_forever(self):
175         # todo:resolve handlers name space conflict
176         self.daemonize()
177         while True:
178             time.sleep(self.interval)
179             files = os.listdir(constant.FS_MOUNT_POINT)
180             if constant.VM_CMD_SET_FLAG_FILE in files and constant.VM_CMD_CONTENT_FILE in files:
181                 with open(constant.VM_CMD_CONTENT_FILE, 'r') as f:
182                     out = f.read().strip()
183                 LOG.debug("new command arrived:%s", out)
184                 cmd_param = out.split()
185                 cmd = cmd_param[0]
186                 param = cmd_param[1:]
187                 for obj in self.handlers:
188                     if hasattr(obj, cmd) and callable(getattr(obj, cmd)):
189                         LOG.debug("method:%s found!", cmd)
190                         method = getattr(obj, cmd)
191                         try:
192                             method(*param)
193                             self.set_success()
194                             LOG.debug("cmd sucessfully done")
195                         except Exception, e:
196                             LOG.debug('failed to run:%s %s,reason:%s', cmd, param, str(e))
197                             self.set_fail(str(e))
198                         break
199                 else:
200                     LOG.debug("method:%s not found!", cmd)
201                     self.set_fail(constant.VM_CMD_NOT_FOUND)
202                 os.remove(constant.VM_CMD_SET_FLAG_FILE)
203                 os.remove(constant.VM_CMD_CONTENT_FILE)
204
205
206 if __name__ == '__main__':
207     # echo "set_pktloop_dpdk" > command;touch command_set
208     # echo "recover_nic_binding" > command;touch command_set
209     # echo "config_ip 56:6f:44:a5:3f:a2 192.168.188.200/23" > command;touch command_set
210     # echo "config_gw 192.168.188.1" > command;touch command_set
211     # echo set_pktloop_dpdk 56:6f:44:a5:3f:a2 56:6f:44:a5:3f:a3 > command;touch command_set
212     # echo recover_nic_binding 56:6f:44:a5:3f:a2 56:6f:44:a5:3f:a3 > command;touch command_set
213     import os
214     logging.basicConfig(level=logging.DEBUG, filename=LOG_FILE, filemode='w')
215     os.environ['PATH'] = os.environ["PATH"] + ":/usr/local/bin"
216     LOG.info(os.environ['PATH'])
217     vm_op = VMOperation()
218     agent = FSMonitor()
219     agent.register_handler(vm_op)
220     agent.run_forever()