241 lines
9.9 KiB
Python
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'])
|