neutron/neutron/tests/functional/resources/process.py

241 lines
9.9 KiB
Python

# Copyright 2016 Red Hat, Inc.
#
# 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.
from distutils import spawn
import os
import fixtures
import psutil
import tenacity
from neutron.agent.linux import utils
class DaemonProcessFixture(fixtures.Fixture):
def __init__(self, temp_dir):
super(DaemonProcessFixture, self).__init__()
self.temp_dir = temp_dir
def _get_pid_from_pidfile(self, pidfile):
with open(os.path.join(self.temp_dir, pidfile), 'r') as pidfile_f:
pid = pidfile_f.read().strip()
try:
return int(pid)
except ValueError:
raise RuntimeError(
"Pidfile %(pidfile)s contains %(pid)s that "
"is not a pid" % {'pidfile': pidfile, 'pid': pid}
)
class OvnNorthd(DaemonProcessFixture):
def __init__(self, temp_dir, ovn_nb_db, ovn_sb_db, protocol='unix',
debug=True):
super(OvnNorthd, self).__init__(temp_dir)
self.ovn_nb_db = ovn_nb_db
self.ovn_sb_db = ovn_sb_db
self.protocol = protocol
self.unixctl_path = os.path.join(self.temp_dir, 'ovn_northd.ctl')
self.log_file_path = os.path.join(self.temp_dir, 'ovn_northd.log')
self.debug = debug
if self.protocol == 'ssl':
self.private_key = os.path.join(self.temp_dir, 'ovn-privkey.pem')
self.certificate = os.path.join(self.temp_dir, 'ovn-cert.pem')
self.ca_cert = os.path.join(self.temp_dir, 'controllerca',
'cacert.pem')
def _setUp(self):
self.addCleanup(self.stop)
self.start()
def start(self):
# start the ovn-northd
ovn_northd_cmd = [
spawn.find_executable('ovn-northd'), '-vconsole:off',
'--detach',
'--ovnnb-db=%s' % self.ovn_nb_db,
'--ovnsb-db=%s' % self.ovn_sb_db,
'--no-chdir',
'--unixctl=%s' % self.unixctl_path,
'--log-file=%s' % (self.log_file_path)]
if self.protocol == 'ssl':
ovn_northd_cmd.append('--private-key=%s' % self.private_key)
ovn_northd_cmd.append('--certificate=%s' % self.certificate)
ovn_northd_cmd.append('--ca-cert=%s' % self.ca_cert)
if self.debug:
ovn_northd_cmd.append('--verbose')
obj, _ = utils.create_process(ovn_northd_cmd)
obj.communicate()
def stop(self):
try:
stop_cmd = ['ovs-appctl', '-t', self.unixctl_path, 'exit']
utils.execute(stop_cmd)
except Exception:
pass
class OvsdbServer(DaemonProcessFixture):
def __init__(self, temp_dir, ovs_dir, ovn_nb_db=True, ovn_sb_db=False,
protocol='unix', debug=True):
super(OvsdbServer, self).__init__(temp_dir)
self.ovs_dir = ovs_dir
self.ovn_nb_db = ovn_nb_db
self.ovn_sb_db = ovn_sb_db
# The value of the protocol must be unix or tcp or ssl
self.protocol = protocol
self.ovsdb_server_processes = []
self.private_key = os.path.join(self.temp_dir, 'ovn-privkey.pem')
self.certificate = os.path.join(self.temp_dir, 'ovn-cert.pem')
self.ca_cert = os.path.join(self.temp_dir, 'controllerca',
'cacert.pem')
self.debug = debug
def _setUp(self):
if self.ovn_nb_db:
self.ovsdb_server_processes.append(
{'db_path': os.path.join(self.temp_dir, 'ovn_nb.db'),
'schema_path': os.path.join(self.ovs_dir, 'ovn-nb.ovsschema'),
'remote_path': os.path.join(self.temp_dir, 'ovnnb_db.sock'),
'protocol': self.protocol,
'remote_ip': '127.0.0.1',
'remote_port': '0',
'pidfile': 'ovn-nb.pid',
'unixctl_path': os.path.join(self.temp_dir, 'ovnnb_db.ctl'),
'log_file_path': os.path.join(self.temp_dir, 'ovn_nb.log'),
'db_type': 'nb',
'connection': 'db:OVN_Northbound,NB_Global,connections',
'ctl_cmd': 'ovn-nbctl'})
if self.ovn_sb_db:
self.ovsdb_server_processes.append(
{'db_path': os.path.join(self.temp_dir, 'ovn_sb.db'),
'schema_path': os.path.join(self.ovs_dir, 'ovn-sb.ovsschema'),
'remote_path': os.path.join(self.temp_dir, 'ovnsb_db.sock'),
'protocol': self.protocol,
'remote_ip': '127.0.0.1',
'remote_port': '0',
'pidfile': 'ovn-sb.pid',
'unixctl_path': os.path.join(self.temp_dir, 'ovnsb_db.ctl'),
'log_file_path': os.path.join(self.temp_dir, 'ovn_sb.log'),
'db_type': 'sb',
'connection': 'db:OVN_Southbound,SB_Global,connections',
'ctl_cmd': 'ovn-sbctl'})
self.addCleanup(self.stop)
self.start()
def _init_ovsdb_pki(self):
os.chdir(self.temp_dir)
pki_init_cmd = [spawn.find_executable('ovs-pki'), 'init',
'-d', self.temp_dir, '-l',
os.path.join(self.temp_dir, 'pki.log'), '--force']
utils.execute(pki_init_cmd)
pki_req_sign = [spawn.find_executable('ovs-pki'), 'req+sign', 'ovn',
'controller', '-d', self.temp_dir, '-l',
os.path.join(self.temp_dir, 'pki.log'), '--force']
utils.execute(pki_req_sign)
def delete_dbs(self):
for ovsdb in self.ovsdb_server_processes:
try:
os.remove(ovsdb['db_path'])
except OSError:
pass
def start(self):
pki_done = False
for ovsdb_process in self.ovsdb_server_processes:
# create the db from the schema using ovsdb-tool
ovsdb_tool_cmd = [spawn.find_executable('ovsdb-tool'),
'create', ovsdb_process['db_path'],
ovsdb_process['schema_path']]
utils.execute(ovsdb_tool_cmd)
# start the ovsdb-server
ovsdb_server_cmd = [
spawn.find_executable('ovsdb-server'), '-vconsole:off',
'--detach',
'--pidfile=%s' % os.path.join(
self.temp_dir, ovsdb_process['pidfile']),
'--log-file=%s' % (ovsdb_process['log_file_path']),
'--remote=punix:%s' % (ovsdb_process['remote_path']),
'--remote=%s' % (ovsdb_process['connection']),
'--unixctl=%s' % (ovsdb_process['unixctl_path']),
'--detach']
if ovsdb_process['protocol'] == 'ssl':
if not pki_done:
pki_done = True
self._init_ovsdb_pki()
ovsdb_server_cmd.append('--private-key=%s' % self.private_key)
ovsdb_server_cmd.append('--certificate=%s' % self.certificate)
ovsdb_server_cmd.append('--ca-cert=%s' % self.ca_cert)
ovsdb_server_cmd.append(ovsdb_process['db_path'])
if self.debug:
ovsdb_server_cmd.append('--verbose')
obj, _ = utils.create_process(ovsdb_server_cmd)
obj.communicate()
conn_cmd = [spawn.find_executable(ovsdb_process['ctl_cmd']),
'--db=unix:%s' % ovsdb_process['remote_path'],
'set-connection',
'p%s:%s:%s' % (ovsdb_process['protocol'],
ovsdb_process['remote_port'],
ovsdb_process['remote_ip']),
'--', 'set', 'connection', '.',
'inactivity_probe=60000']
@tenacity.retry(wait=tenacity.wait_exponential(multiplier=0.1),
stop=tenacity.stop_after_delay(3), reraise=True)
def _set_connection():
utils.execute(conn_cmd)
@tenacity.retry(
wait=tenacity.wait_exponential(multiplier=0.1),
stop=tenacity.stop_after_delay(10),
reraise=True)
def get_ovsdb_remote_port_retry(pid):
process = psutil.Process(pid)
for connect in process.connections():
if connect.status == 'LISTEN':
return connect.laddr[1]
raise Exception(_("Could not find LISTEN port."))
if ovsdb_process['protocol'] != 'unix':
_set_connection()
pid = self._get_pid_from_pidfile(ovsdb_process['pidfile'])
ovsdb_process['remote_port'] = \
get_ovsdb_remote_port_retry(pid)
def stop(self):
for ovsdb_process in self.ovsdb_server_processes:
try:
stop_cmd = ['ovs-appctl', '-t', ovsdb_process['unixctl_path'],
'exit']
utils.execute(stop_cmd)
except Exception:
pass
def get_ovsdb_connection_path(self, db_type='nb'):
for ovsdb_process in self.ovsdb_server_processes:
if ovsdb_process['db_type'] == db_type:
if ovsdb_process['protocol'] == 'unix':
return 'unix:' + ovsdb_process['remote_path']
else:
return '%s:%s:%s' % (ovsdb_process['protocol'],
ovsdb_process['remote_ip'],
ovsdb_process['remote_port'])