bugfix: Graceful shutdown of VM - improvement
[vswitchperf.git] / src / ovs / daemon.py
1 # Copyright 2015 Intel Corporation.
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 #   http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14
15 """Class wrapper for controlling an OVS instance.
16
17 Wraps a pair of ``ovs-vswitchd`` and ``ovsdb-server`` processes.
18 """
19
20 import os
21 import logging
22 import pexpect
23
24 from conf import settings
25 from tools import tasks
26
27 _OVS_VAR_DIR = settings.getValue('OVS_VAR_DIR')
28 _OVS_ETC_DIR = settings.getValue('OVS_ETC_DIR')
29
30 _LOG_FILE_VSWITCHD = os.path.join(
31     settings.getValue('LOG_DIR'), settings.getValue('LOG_FILE_VSWITCHD'))
32
33 class VSwitchd(tasks.Process):
34     """Class wrapper for controlling an OVS instance.
35
36     Wraps a pair of ``ovs-vswitchd`` and ``ovsdb-server`` processes.
37     """
38     _ovsdb_pid = None
39     _logfile = _LOG_FILE_VSWITCHD
40     _ovsdb_pidfile_path = os.path.join(settings.getValue('LOG_DIR'), "ovsdb_pidfile.pid")
41     _vswitchd_pidfile_path = os.path.join(settings.getValue('LOG_DIR'), "vswitchd_pidfile.pid")
42     _proc_name = 'ovs-vswitchd'
43
44     def __init__(self, timeout=30, vswitchd_args=None, expected_cmd=None):
45         """Initialise the wrapper with a specific start timeout and extra
46         parameters.
47
48         :param timeout: Timeout to wait for application to start.
49         :param vswitchd_args: Command line parameters for vswitchd.
50
51         :returns: None
52         """
53         self._logger = logging.getLogger(__name__)
54         self._timeout = timeout
55         self._expect = expected_cmd
56         vswitchd_args = vswitchd_args or []
57         ovs_vswitchd_bin = os.path.join(
58             settings.getValue('OVS_DIR'), 'vswitchd', 'ovs-vswitchd')
59         sep = ['--'] if '--dpdk' in vswitchd_args else []
60         self._cmd = ['sudo', '-E', ovs_vswitchd_bin] + vswitchd_args + sep + \
61                     ['--pidfile=' + self._vswitchd_pidfile_path, '--overwrite-pidfile',
62                      '--log-file=' + self._logfile]
63
64     # startup/shutdown
65
66     def start(self):
67         """ Start ``ovsdb-server`` and ``ovs-vswitchd`` instance.
68
69         :returns: None
70         :raises: pexpect.EOF, pexpect.TIMEOUT
71         """
72
73         self._reset_ovsdb()
74         self._start_ovsdb()  # this has to be started first
75
76         try:
77             super(VSwitchd, self).start()
78             self.relinquish()
79         except (pexpect.EOF, pexpect.TIMEOUT) as exc:
80             logging.error("Exception during VSwitch start.")
81             self._kill_ovsdb()
82             raise exc
83
84     def kill(self, signal='-15', sleep=10):
85         """Kill ``ovs-vswitchd`` instance if it is alive.
86
87         :returns: None
88         """
89         self._logger.info('Killing ovs-vswitchd...')
90         with open(self._vswitchd_pidfile_path, "r") as pidfile:
91             vswitchd_pid = pidfile.read().strip()
92             tasks.terminate_task(vswitchd_pid, logger=self._logger)
93
94         self._kill_ovsdb()  # ovsdb must be killed after vswitchd
95
96         # just for case, that sudo envelope has not terminated
97         super(VSwitchd, self).kill(signal, sleep)
98
99     # helper functions
100
101     def _reset_ovsdb(self):
102         """Reset system for 'ovsdb'.
103
104         :returns: None
105         """
106         self._logger.info('Resetting system after last run...')
107
108         tasks.run_task(['sudo', 'rm', '-rf', _OVS_VAR_DIR], self._logger)
109         tasks.run_task(['sudo', 'mkdir', '-p', _OVS_VAR_DIR], self._logger)
110         tasks.run_task(['sudo', 'rm', '-rf', _OVS_ETC_DIR], self._logger)
111         tasks.run_task(['sudo', 'mkdir', '-p', _OVS_ETC_DIR], self._logger)
112
113         tasks.run_task(['sudo', 'rm', '-f',
114                         os.path.join(_OVS_ETC_DIR, 'conf.db')],
115                        self._logger)
116
117         self._logger.info('System reset after last run.')
118
119     def _start_ovsdb(self):
120         """Start ``ovsdb-server`` instance.
121
122         :returns: None
123         """
124         ovsdb_tool_bin = os.path.join(
125             settings.getValue('OVS_DIR'), 'ovsdb', 'ovsdb-tool')
126         tasks.run_task(['sudo', ovsdb_tool_bin, 'create',
127                         os.path.join(_OVS_ETC_DIR, 'conf.db'),
128                         os.path.join(settings.getValue('OVS_DIR'), 'vswitchd',
129                                      'vswitch.ovsschema')],
130                        self._logger,
131                        'Creating ovsdb configuration database...')
132
133         ovsdb_server_bin = os.path.join(
134             settings.getValue('OVS_DIR'), 'ovsdb', 'ovsdb-server')
135
136         tasks.run_background_task(
137             ['sudo', ovsdb_server_bin,
138              '--remote=punix:%s' % os.path.join(_OVS_VAR_DIR, 'db.sock'),
139              '--remote=db:Open_vSwitch,Open_vSwitch,manager_options',
140              '--pidfile=' + self._ovsdb_pidfile_path, '--overwrite-pidfile'],
141             self._logger,
142             'Starting ovsdb-server...')
143
144     def _kill_ovsdb(self):
145         """Kill ``ovsdb-server`` instance.
146
147         :returns: None
148         """
149         with open(self._ovsdb_pidfile_path, "r") as pidfile:
150             ovsdb_pid = pidfile.read().strip()
151
152         self._logger.info("Killing ovsdb with pid: " + ovsdb_pid)
153
154         if ovsdb_pid:
155             tasks.terminate_task(ovsdb_pid, logger=self._logger)
156
157     @staticmethod
158     def get_db_sock_path():
159         """Method returns location of db.sock file
160
161         :returns: path to db.sock file.
162         """
163         return os.path.join(_OVS_VAR_DIR, 'db.sock')