Update charm to use Python 3

Updates across the charm and unit tests to switch to
execution under Python 3.

Note that the changes are not backwards compatible
with Python 2.

Refactor use of neutronclient python module to simply
wrap the neutron binary, using the yaml output format
to avoid the requirement for a Python 3 module on
older OpenStack release versions.

Change-Id: Ic26b0dd19a76552481939325963a6c21585dee3c
This commit is contained in:
James Page 2017-11-05 09:04:50 +11:00
parent c6513b0dc1
commit 5f22e621c2
16 changed files with 99 additions and 128 deletions

1
.gitignore vendored
View File

@ -9,3 +9,4 @@ tags
trusty/ trusty/
xenial/ xenial/
.stestr .stestr
__pycache__

View File

@ -1,4 +1,4 @@
#!/usr/bin/python #!/usr/bin/env python3
# #
# Copyright 2016 Canonical Ltd # Copyright 2016 Canonical Ltd
# #

View File

@ -1,4 +1,4 @@
#!/usr/bin/python #!/usr/bin/env python3
# #
# Copyright 2016 Canonical Ltd # Copyright 2016 Canonical Ltd
# #

View File

@ -1,4 +1,4 @@
#!/usr/bin/python #!/usr/bin/env python3
# #
# Copyright 2016 Canonical Ltd # Copyright 2016 Canonical Ltd
# #

View File

@ -1,20 +0,0 @@
#!/bin/bash
# Wrapper to deal with newer Ubuntu versions that don't have py2 installed
# by default.
declare -a DEPS=('apt' 'netaddr' 'netifaces' 'pip' 'yaml')
check_and_install() {
pkg="${1}-${2}"
if ! dpkg -s ${pkg} 2>&1 > /dev/null; then
apt-get -y install ${pkg}
fi
}
PYTHON="python"
for dep in ${DEPS[@]}; do
check_and_install ${PYTHON} ${dep}
done
exec ./hooks/install.real

1
hooks/install Symbolic link
View File

@ -0,0 +1 @@
neutron_api_hooks.py

View File

@ -1 +0,0 @@
neutron_api_hooks.py

View File

@ -349,7 +349,7 @@ class NeutronCCContext(context.NeutronContext):
cmp_release = CompareOpenStackReleases(release) cmp_release = CompareOpenStackReleases(release)
if config('neutron-plugin') in ['vsp']: if config('neutron-plugin') in ['vsp']:
_config = config() _config = config()
for k, v in _config.iteritems(): for k, v in _config.items():
if k.startswith('vsd'): if k.startswith('vsd'):
ctxt[k.replace('-', '_')] = v ctxt[k.replace('-', '_')] = v
for rid in relation_ids('vsd-rest-api'): for rid in relation_ids('vsd-rest-api'):

View File

@ -1,4 +1,4 @@
#!/usr/bin/python #!/usr/bin/env python3
# #
# Copyright 2016 Canonical Ltd # Copyright 2016 Canonical Ltd
# #
@ -186,8 +186,7 @@ def configure_https():
identity_joined(rid=rid) identity_joined(rid=rid)
@hooks.hook('install.real') @hooks.hook('install')
@hooks.hook()
@harden() @harden()
def install(): def install():
status_set('maintenance', 'Executing pre-install') status_set('maintenance', 'Executing pre-install')

View File

@ -20,6 +20,7 @@ import shutil
import subprocess import subprocess
import uuid import uuid
import glob import glob
import yaml
from base64 import b64encode from base64 import b64encode
from charmhelpers.contrib.openstack import context, templating from charmhelpers.contrib.openstack import context, templating
from charmhelpers.contrib.openstack.neutron import ( from charmhelpers.contrib.openstack.neutron import (
@ -511,14 +512,14 @@ def register_configs(release=None):
release = release or os_release('neutron-common') release = release or os_release('neutron-common')
configs = templating.OSConfigRenderer(templates_dir=TEMPLATES, configs = templating.OSConfigRenderer(templates_dir=TEMPLATES,
openstack_release=release) openstack_release=release)
for cfg, rscs in resource_map().iteritems(): for cfg, rscs in resource_map().items():
configs.register(cfg, rscs['contexts']) configs.register(cfg, rscs['contexts'])
return configs return configs
def restart_map(): def restart_map():
return OrderedDict([(cfg, v['services']) return OrderedDict([(cfg, v['services'])
for cfg, v in resource_map().iteritems() for cfg, v in resource_map().items()
if v['services']]) if v['services']])
@ -686,22 +687,43 @@ def setup_ipv6():
apt_install('haproxy/trusty-backports', fatal=True) apt_install('haproxy/trusty-backports', fatal=True)
class FakeNeutronClient(object):
'''Fake wrapper for Neutron Client'''
def __init__(self, username, password, tenant_name,
auth_url, region_name):
self.env = {
'OS_USERNAME': username,
'OS_PASSWORD': password,
'OS_TENANT_NAME': tenant_name,
'OS_AUTH_URL': auth_url,
'OS_REGION': region_name,
}
def list_routers(self):
cmd = ['neutron', 'router-list', '-f', 'yaml']
try:
routers = subprocess.check_output(
cmd, env=self.env).decode('UTF-8')
return {'routers': yaml.load(routers)}
except subprocess.CalledProcessError:
return {'routers': []}
def get_neutron_client(): def get_neutron_client():
''' Return a neutron client if possible ''' ''' Return a neutron client if possible '''
env = neutron_api_context.IdentityServiceContext()() env = neutron_api_context.IdentityServiceContext()()
if not env: if not env:
log('Unable to check resources at this time') log('Unable to check resources at this time')
return return None
auth_url = '%(auth_protocol)s://%(auth_host)s:%(auth_port)s/v2.0' % env auth_url = '{auth_protocol}://{auth_host}:{auth_port}/v2.0'.format(**env)
# Late import to avoid install hook failures when pkg hasnt been installed
from neutronclient.v2_0 import client return FakeNeutronClient(username=env['admin_user'],
neutron_client = client.Client(username=env['admin_user'], password=env['admin_password'],
password=env['admin_password'], tenant_name=env['admin_tenant_name'],
tenant_name=env['admin_tenant_name'], auth_url=auth_url,
auth_url=auth_url, region_name=env['region'])
region_name=env['region'])
return neutron_client
def router_feature_present(feature): def router_feature_present(feature):
@ -758,10 +780,10 @@ def git_pre_install():
add_user_to_group('neutron', 'neutron') add_user_to_group('neutron', 'neutron')
for d in dirs: for d in dirs:
mkdir(d, owner='neutron', group='neutron', perms=0755, force=False) mkdir(d, owner='neutron', group='neutron', perms=0o755, force=False)
for l in logs: for l in logs:
write_file(l, '', owner='neutron', group='neutron', perms=0600) write_file(l, '', owner='neutron', group='neutron', perms=0o600)
def git_post_install(projects_yaml): def git_post_install(projects_yaml):

View File

@ -5,12 +5,12 @@ coverage>=3.6
mock>=1.2 mock>=1.2
flake8>=2.2.4,<=2.4.1 flake8>=2.2.4,<=2.4.1
os-testr>=0.4.1 os-testr>=0.4.1
charm-tools>=2.0.0 charm-tools>=2.0.0;python_version=='2.7'
requests==2.6.0 requests==2.6.0
# BEGIN: Amulet OpenStack Charm Helper Requirements # BEGIN: Amulet OpenStack Charm Helper Requirements
# Liberty client lower constraints # Liberty client lower constraints
amulet>=1.14.3,<2.0 amulet>=1.14.3,<2.0;python_version=='2.7'
bundletester>=0.6.1,<1.0 bundletester>=0.6.1,<1.0;python_version=='2.7'
python-ceilometerclient>=1.5.0 python-ceilometerclient>=1.5.0
python-cinderclient>=1.4.0 python-cinderclient>=1.4.0
python-glanceclient>=1.1.0 python-glanceclient>=1.1.0

View File

@ -2,7 +2,7 @@
# This file is managed centrally by release-tools and should not be modified # This file is managed centrally by release-tools and should not be modified
# within individual charm repos. # within individual charm repos.
[tox] [tox]
envlist = pep8,py27 envlist = pep8,py27,py35
skipsdist = True skipsdist = True
[testenv] [testenv]
@ -20,6 +20,7 @@ passenv = HOME TERM AMULET_* CS_API_*
basepython = python2.7 basepython = python2.7
deps = -r{toxinidir}/requirements.txt deps = -r{toxinidir}/requirements.txt
-r{toxinidir}/test-requirements.txt -r{toxinidir}/test-requirements.txt
commands = /bin/true
[testenv:py35] [testenv:py35]
basepython = python3.5 basepython = python3.5

View File

@ -16,3 +16,4 @@ import sys
sys.path.append('actions/') sys.path.append('actions/')
sys.path.append('hooks/') sys.path.append('hooks/')
sys.path.append('unit_tests')

View File

@ -63,10 +63,8 @@ class GeneralTests(CharmTestCase):
def test_get_tenant_network_types_unsupported(self): def test_get_tenant_network_types_unsupported(self):
self.test_config.set('overlay-network-type', 'tokenring') self.test_config.set('overlay-network-type', 'tokenring')
with self.assertRaises(ValueError) as _exceptctxt: with self.assertRaises(ValueError):
context._get_tenant_network_types() context._get_tenant_network_types()
self.assertEqual(_exceptctxt.exception.message,
'Unsupported overlay-network-type tokenring')
def test_get_tenant_network_types_default(self): def test_get_tenant_network_types_default(self):
self.test_config.set('overlay-network-type', 'gre vxlan') self.test_config.set('overlay-network-type', 'gre vxlan')
@ -92,20 +90,14 @@ class GeneralTests(CharmTestCase):
def test_get_tenant_network_types_unsupported_default(self): def test_get_tenant_network_types_unsupported_default(self):
self.test_config.set('overlay-network-type', '') self.test_config.set('overlay-network-type', '')
self.test_config.set('default-tenant-network-type', 'whizzy') self.test_config.set('default-tenant-network-type', 'whizzy')
with self.assertRaises(ValueError) as _exceptctxt: with self.assertRaises(ValueError):
context._get_tenant_network_types() context._get_tenant_network_types()
self.assertEqual(_exceptctxt.exception.message,
'Unsupported or unconfigured '
'default-tenant-network-type whizzy')
def test_get_tenant_network_types_unconfigured_default(self): def test_get_tenant_network_types_unconfigured_default(self):
self.test_config.set('overlay-network-type', 'gre') self.test_config.set('overlay-network-type', 'gre')
self.test_config.set('default-tenant-network-type', 'vxlan') self.test_config.set('default-tenant-network-type', 'vxlan')
with self.assertRaises(ValueError) as _exceptctxt: with self.assertRaises(ValueError):
context._get_tenant_network_types() context._get_tenant_network_types()
self.assertEqual(_exceptctxt.exception.message,
'Unsupported or unconfigured '
'default-tenant-network-type vxlan')
def test_get_l3ha(self): def test_get_l3ha(self):
self.test_config.set('enable-l3ha', True) self.test_config.set('enable-l3ha', True)
@ -317,7 +309,7 @@ class HAProxyContextTest(CharmTestCase):
def test_context_No_peers(self, _log, _rids, _mkdir): def test_context_No_peers(self, _log, _rids, _mkdir):
_rids.return_value = [] _rids.return_value = []
hap_ctxt = context.HAProxyContext() hap_ctxt = context.HAProxyContext()
with patch('__builtin__.__import__'): with patch('builtins.__import__'):
self.assertTrue('units' not in hap_ctxt()) self.assertTrue('units' not in hap_ctxt())
@patch.object(charmhelpers.contrib.openstack.context, 'mkdir') @patch.object(charmhelpers.contrib.openstack.context, 'mkdir')
@ -333,8 +325,8 @@ class HAProxyContextTest(CharmTestCase):
@patch.object(charmhelpers.contrib.openstack.context, 'relation_ids') @patch.object(charmhelpers.contrib.openstack.context, 'relation_ids')
@patch.object(charmhelpers.contrib.openstack.context, 'log') @patch.object(charmhelpers.contrib.openstack.context, 'log')
@patch.object(charmhelpers.contrib.openstack.context, 'kv') @patch.object(charmhelpers.contrib.openstack.context, 'kv')
@patch('__builtin__.__import__') @patch('builtins.__import__')
@patch('__builtin__.open') @patch('builtins.open')
def test_context_peers(self, _open, _import, _kv, _log, _rids, _runits, def test_context_peers(self, _open, _import, _kv, _log, _rids, _runits,
_rget, _uget, _lunit, _config, _rget, _uget, _lunit, _config,
_get_address_in_network, _get_netmask_for_address, _get_address_in_network, _get_netmask_for_address,
@ -414,7 +406,7 @@ class NeutronCCContextTest(CharmTestCase):
@patch.object(context.NeutronCCContext, 'network_manager') @patch.object(context.NeutronCCContext, 'network_manager')
@patch.object(context.NeutronCCContext, 'plugin') @patch.object(context.NeutronCCContext, 'plugin')
@patch('__builtin__.__import__') @patch('builtins.__import__')
def test_neutroncc_context_no_setting(self, _import, plugin, nm): def test_neutroncc_context_no_setting(self, _import, plugin, nm):
plugin.return_value = None plugin.return_value = None
ctxt_data = { ctxt_data = {
@ -502,7 +494,7 @@ class NeutronCCContextTest(CharmTestCase):
@patch.object(context.NeutronCCContext, 'network_manager') @patch.object(context.NeutronCCContext, 'network_manager')
@patch.object(context.NeutronCCContext, 'plugin') @patch.object(context.NeutronCCContext, 'plugin')
@patch('__builtin__.__import__') @patch('builtins.__import__')
def test_neutroncc_context_vxlan(self, _import, plugin, nm): def test_neutroncc_context_vxlan(self, _import, plugin, nm):
plugin.return_value = None plugin.return_value = None
self.test_config.set('flat-network-providers', 'physnet2 physnet3') self.test_config.set('flat-network-providers', 'physnet2 physnet3')
@ -550,7 +542,7 @@ class NeutronCCContextTest(CharmTestCase):
@patch.object(context.NeutronCCContext, 'network_manager') @patch.object(context.NeutronCCContext, 'network_manager')
@patch.object(context.NeutronCCContext, 'plugin') @patch.object(context.NeutronCCContext, 'plugin')
@patch('__builtin__.__import__') @patch('builtins.__import__')
def test_neutroncc_context_l3ha(self, _import, plugin, nm): def test_neutroncc_context_l3ha(self, _import, plugin, nm):
plugin.return_value = None plugin.return_value = None
self.test_config.set('enable-l3ha', True) self.test_config.set('enable-l3ha', True)
@ -602,7 +594,7 @@ class NeutronCCContextTest(CharmTestCase):
@patch.object(context.NeutronCCContext, 'network_manager') @patch.object(context.NeutronCCContext, 'network_manager')
@patch.object(context.NeutronCCContext, 'plugin') @patch.object(context.NeutronCCContext, 'plugin')
@patch('__builtin__.__import__') @patch('builtins.__import__')
def test_neutroncc_context_l3ha_l3_agents(self, _import, plugin, nm): def test_neutroncc_context_l3ha_l3_agents(self, _import, plugin, nm):
plugin.return_value = None plugin.return_value = None
self.os_release.return_value = 'juno' self.os_release.return_value = 'juno'
@ -616,7 +608,7 @@ class NeutronCCContextTest(CharmTestCase):
@patch.object(context.NeutronCCContext, 'network_manager') @patch.object(context.NeutronCCContext, 'network_manager')
@patch.object(context.NeutronCCContext, 'plugin') @patch.object(context.NeutronCCContext, 'plugin')
@patch('__builtin__.__import__') @patch('builtins.__import__')
def test_neutroncc_context_sriov(self, _import, plugin, nm): def test_neutroncc_context_sriov(self, _import, plugin, nm):
plugin.return_value = None plugin.return_value = None
self.test_config.set('enable-sriov', True) self.test_config.set('enable-sriov', True)
@ -660,7 +652,7 @@ class NeutronCCContextTest(CharmTestCase):
@patch.object(context.NeutronCCContext, 'network_manager') @patch.object(context.NeutronCCContext, 'network_manager')
@patch.object(context.NeutronCCContext, 'plugin') @patch.object(context.NeutronCCContext, 'plugin')
@patch('__builtin__.__import__') @patch('builtins.__import__')
def test_neutroncc_context_unsupported_overlay(self, _import, plugin, nm): def test_neutroncc_context_unsupported_overlay(self, _import, plugin, nm):
plugin.return_value = None plugin.return_value = None
self.test_config.set('overlay-network-type', 'bobswitch') self.test_config.set('overlay-network-type', 'bobswitch')
@ -669,7 +661,7 @@ class NeutronCCContextTest(CharmTestCase):
@patch.object(context.NeutronCCContext, 'network_manager') @patch.object(context.NeutronCCContext, 'network_manager')
@patch.object(context.NeutronCCContext, 'plugin') @patch.object(context.NeutronCCContext, 'plugin')
@patch('__builtin__.__import__') @patch('builtins.__import__')
def test_neutroncc_context_api_rel(self, _import, plugin, nm): def test_neutroncc_context_api_rel(self, _import, plugin, nm):
nova_url = 'http://127.0.0.10' nova_url = 'http://127.0.0.10'
plugin.return_value = None plugin.return_value = None
@ -697,7 +689,7 @@ class NeutronCCContextTest(CharmTestCase):
@patch.object(context.NeutronCCContext, 'network_manager') @patch.object(context.NeutronCCContext, 'network_manager')
@patch.object(context.NeutronCCContext, 'plugin') @patch.object(context.NeutronCCContext, 'plugin')
@patch('__builtin__.__import__') @patch('builtins.__import__')
def test_neutroncc_context_nsx(self, _import, plugin, nm): def test_neutroncc_context_nsx(self, _import, plugin, nm):
plugin.return_value = 'nsx' plugin.return_value = 'nsx'
self.os_release.return_value = 'havana' self.os_release.return_value = 'havana'
@ -712,12 +704,12 @@ class NeutronCCContextTest(CharmTestCase):
'nsx_tz_uuid': 'tzuuid', 'nsx_tz_uuid': 'tzuuid',
'nsx_username': 'bob', 'nsx_username': 'bob',
} }
for key in expect.iterkeys(): for key in expect.keys():
self.assertEqual(napi_ctxt[key], expect[key]) self.assertEqual(napi_ctxt[key], expect[key])
@patch.object(context.NeutronCCContext, 'network_manager') @patch.object(context.NeutronCCContext, 'network_manager')
@patch.object(context.NeutronCCContext, 'plugin') @patch.object(context.NeutronCCContext, 'plugin')
@patch('__builtin__.__import__') @patch('builtins.__import__')
def test_neutroncc_context_nuage(self, _import, plugin, nm): def test_neutroncc_context_nuage(self, _import, plugin, nm):
plugin.return_value = 'vsp' plugin.return_value = 'vsp'
self.os_release.return_value = 'havana' self.os_release.return_value = 'havana'
@ -732,12 +724,12 @@ class NeutronCCContextTest(CharmTestCase):
'vsd_base_uri': '/nuage/api/v1_0', 'vsd_base_uri': '/nuage/api/v1_0',
'vsd_netpart_name': 'foo-enterprise', 'vsd_netpart_name': 'foo-enterprise',
} }
for key in expect.iterkeys(): for key in expect.keys():
self.assertEqual(napi_ctxt[key], expect[key]) self.assertEqual(napi_ctxt[key], expect[key])
@patch.object(context.NeutronCCContext, 'network_manager') @patch.object(context.NeutronCCContext, 'network_manager')
@patch.object(context.NeutronCCContext, 'plugin') @patch.object(context.NeutronCCContext, 'plugin')
@patch('__builtin__.__import__') @patch('builtins.__import__')
def test_neutroncc_context_qos(self, _import, plugin, nm): def test_neutroncc_context_qos(self, _import, plugin, nm):
plugin.return_value = None plugin.return_value = None
self.os_release.return_value = 'mitaka' self.os_release.return_value = 'mitaka'
@ -749,12 +741,12 @@ class NeutronCCContextTest(CharmTestCase):
'extension_drivers': 'qos', 'extension_drivers': 'qos',
'service_plugins': service_plugins, 'service_plugins': service_plugins,
} }
for key in expect.iterkeys(): for key in expect.keys():
self.assertEqual(napi_ctxt[key], expect[key]) self.assertEqual(napi_ctxt[key], expect[key])
@patch.object(context.NeutronCCContext, 'network_manager') @patch.object(context.NeutronCCContext, 'network_manager')
@patch.object(context.NeutronCCContext, 'plugin') @patch.object(context.NeutronCCContext, 'plugin')
@patch('__builtin__.__import__') @patch('builtins.__import__')
def test_neutroncc_context_service_plugins(self, _import, plugin, nm): def test_neutroncc_context_service_plugins(self, _import, plugin, nm):
plugin.return_value = None plugin.return_value = None
self.test_config.set('enable-qos', False) self.test_config.set('enable-qos', False)

View File

@ -151,7 +151,7 @@ class NeutronAPIHooksTests(CharmTestCase):
_port_calls = [call(port) for port in _ports] _port_calls = [call(port) for port in _ports]
self.determine_packages.return_value = _pkgs self.determine_packages.return_value = _pkgs
self.determine_ports.return_value = _ports self.determine_ports.return_value = _ports
self._call_hook('install.real') self._call_hook('install')
self.configure_installation_source.assert_called_with( self.configure_installation_source.assert_called_with(
'distro' 'distro'
) )
@ -174,7 +174,7 @@ class NeutronAPIHooksTests(CharmTestCase):
_port_calls = [call(port) for port in _ports] _port_calls = [call(port) for port in _ports]
self.determine_packages.return_value = _pkgs self.determine_packages.return_value = _pkgs
self.determine_ports.return_value = _ports self.determine_ports.return_value = _ports
self._call_hook('install.real') self._call_hook('install')
self.configure_installation_source.assert_called_with( self.configure_installation_source.assert_called_with(
'distro' 'distro'
) )
@ -210,7 +210,7 @@ class NeutronAPIHooksTests(CharmTestCase):
self.test_config.set('openstack-origin', repo) self.test_config.set('openstack-origin', repo)
self.test_config.set('openstack-origin-git', projects_yaml) self.test_config.set('openstack-origin-git', projects_yaml)
codename.return_value = 'juno' codename.return_value = 'juno'
self._call_hook('install.real') self._call_hook('install')
self.assertTrue(self.execd_preinstall.called) self.assertTrue(self.execd_preinstall.called)
self.configure_installation_source.assert_called_with(repo) self.configure_installation_source.assert_called_with(repo)
self.apt_update.assert_called_with(fatal=True) self.apt_update.assert_called_with(fatal=True)
@ -251,22 +251,16 @@ class NeutronAPIHooksTests(CharmTestCase):
self.neutron_ready.return_value = True self.neutron_ready.return_value = True
self.dvr_router_present.return_value = True self.dvr_router_present.return_value = True
self.get_dvr.return_value = False self.get_dvr.return_value = False
with self.assertRaises(Exception) as context: with self.assertRaises(Exception):
self._call_hook('config-changed') self._call_hook('config-changed')
self.assertEqual(context.exception.message,
'Cannot disable dvr while dvr enabled routers exist.'
' Please remove any distributed routers')
def test_config_changed_nol3ha_harouters(self): def test_config_changed_nol3ha_harouters(self):
self.neutron_ready.return_value = True self.neutron_ready.return_value = True
self.dvr_router_present.return_value = False self.dvr_router_present.return_value = False
self.l3ha_router_present.return_value = True self.l3ha_router_present.return_value = True
self.get_l3ha.return_value = False self.get_l3ha.return_value = False
with self.assertRaises(Exception) as context: with self.assertRaises(Exception):
self._call_hook('config-changed') self._call_hook('config-changed')
self.assertEqual(context.exception.message,
'Cannot disable Router HA while ha enabled routers'
' exist. Please remove any ha routers')
@patch.object(utils, 'get_os_codename_install_source') @patch.object(utils, 'get_os_codename_install_source')
@patch.object(hooks, 'configure_https') @patch.object(hooks, 'configure_https')
@ -372,12 +366,8 @@ class NeutronAPIHooksTests(CharmTestCase):
def test_db_joined_with_postgresql(self): def test_db_joined_with_postgresql(self):
self.is_relation_made.return_value = True self.is_relation_made.return_value = True
with self.assertRaises(Exception):
with self.assertRaises(Exception) as context:
hooks.db_joined() hooks.db_joined()
self.assertEqual(context.exception.message,
'Attempting to associate a mysql database when there '
'is already associated a postgresql one')
def test_postgresql_db_joined(self): def test_postgresql_db_joined(self):
self.unit_get.return_value = 'myhostname' self.unit_get.return_value = 'myhostname'
@ -389,12 +379,8 @@ class NeutronAPIHooksTests(CharmTestCase):
def test_postgresql_joined_with_db(self): def test_postgresql_joined_with_db(self):
self.is_relation_made.return_value = True self.is_relation_made.return_value = True
with self.assertRaises(Exception):
with self.assertRaises(Exception) as context:
hooks.pgsql_neutron_db_joined() hooks.pgsql_neutron_db_joined()
self.assertEqual(context.exception.message,
'Attempting to associate a postgresql database when'
' there is already associated a mysql one')
@patch.object(hooks, 'neutron_plugin_api_subordinate_relation_joined') @patch.object(hooks, 'neutron_plugin_api_subordinate_relation_joined')
@patch.object(hooks, 'conditional_neutron_migration') @patch.object(hooks, 'conditional_neutron_migration')

View File

@ -127,7 +127,7 @@ class TestNeutronAPIUtils(CharmTestCase):
pkg_list = nutils.determine_packages() pkg_list = nutils.determine_packages()
expect = deepcopy(nutils.BASE_PACKAGES) expect = deepcopy(nutils.BASE_PACKAGES)
expect.extend(['neutron-server', 'neutron-plugin-ml2']) expect.extend(['neutron-server', 'neutron-plugin-ml2'])
self.assertItemsEqual(pkg_list, expect) self.assertEqual(sorted(pkg_list), sorted(expect))
@patch.object(nutils, 'git_install_requested') @patch.object(nutils, 'git_install_requested')
def test_determine_vsp_packages(self, git_requested): def test_determine_vsp_packages(self, git_requested):
@ -141,7 +141,7 @@ class TestNeutronAPIUtils(CharmTestCase):
expect = deepcopy(nutils.BASE_PACKAGES) expect = deepcopy(nutils.BASE_PACKAGES)
expect.extend(['neutron-server', 'neutron-plugin-nuage', expect.extend(['neutron-server', 'neutron-plugin-nuage',
'python-nuagenetlib', 'nuage-neutron']) 'python-nuagenetlib', 'nuage-neutron'])
self.assertItemsEqual(pkg_list, expect) self.assertEqual(sorted(pkg_list), sorted(expect))
@patch.object(nutils, 'git_install_requested') @patch.object(nutils, 'git_install_requested')
def test_determine_packages_kilo(self, git_requested): def test_determine_packages_kilo(self, git_requested):
@ -153,7 +153,7 @@ class TestNeutronAPIUtils(CharmTestCase):
expect.extend(['neutron-server', 'neutron-plugin-ml2', expect.extend(['neutron-server', 'neutron-plugin-ml2',
'python-networking-hyperv']) 'python-networking-hyperv'])
expect.extend(nutils.KILO_PACKAGES) expect.extend(nutils.KILO_PACKAGES)
self.assertItemsEqual(pkg_list, expect) self.assertEqual(sorted(pkg_list), sorted(expect))
@patch.object(nutils, 'git_install_requested') @patch.object(nutils, 'git_install_requested')
def test_determine_packages_noplugin(self, git_requested): def test_determine_packages_noplugin(self, git_requested):
@ -164,12 +164,12 @@ class TestNeutronAPIUtils(CharmTestCase):
pkg_list = nutils.determine_packages() pkg_list = nutils.determine_packages()
expect = deepcopy(nutils.BASE_PACKAGES) expect = deepcopy(nutils.BASE_PACKAGES)
expect.extend(['neutron-server']) expect.extend(['neutron-server'])
self.assertItemsEqual(pkg_list, expect) self.assertEqual(sorted(pkg_list), sorted(expect))
def test_determine_ports(self): def test_determine_ports(self):
self.os_release.return_value = 'havana' self.os_release.return_value = 'havana'
port_list = nutils.determine_ports() port_list = nutils.determine_ports()
self.assertItemsEqual(port_list, [9696]) self.assertEqual(port_list, [9696])
@patch.object(nutils, 'manage_plugin') @patch.object(nutils, 'manage_plugin')
@patch('os.path.exists') @patch('os.path.exists')
@ -232,26 +232,14 @@ class TestNeutronAPIUtils(CharmTestCase):
_restart_map = nutils.restart_map() _restart_map = nutils.restart_map()
ML2CONF = "/etc/neutron/plugins/ml2/ml2_conf.ini" ML2CONF = "/etc/neutron/plugins/ml2/ml2_conf.ini"
expect = OrderedDict([ expect = OrderedDict([
(nutils.NEUTRON_CONF, { (nutils.NEUTRON_CONF, ['neutron-server']),
'services': ['neutron-server'], (nutils.NEUTRON_DEFAULT, ['neutron-server']),
}), (nutils.API_PASTE_INI, ['neutron-server']),
(nutils.NEUTRON_DEFAULT, { (nutils.APACHE_CONF, ['apache2']),
'services': ['neutron-server'], (nutils.HAPROXY_CONF, ['haproxy']),
}), (ML2CONF, ['neutron-server']),
(nutils.API_PASTE_INI, {
'services': ['neutron-server'],
}),
(ML2CONF, {
'services': ['neutron-server'],
}),
(nutils.APACHE_CONF, {
'services': ['apache2'],
}),
(nutils.HAPROXY_CONF, {
'services': ['haproxy'],
}),
]) ])
self.assertItemsEqual(_restart_map, expect) self.assertEqual(_restart_map, expect)
@patch('os.path.exists') @patch('os.path.exists')
def test_register_configs(self, mock_path_exists): def test_register_configs(self, mock_path_exists):
@ -275,7 +263,7 @@ class TestNeutronAPIUtils(CharmTestCase):
'/etc/neutron/plugins/ml2/ml2_conf.ini', '/etc/neutron/plugins/ml2/ml2_conf.ini',
'/etc/apache2/sites-available/openstack_https_frontend', '/etc/apache2/sites-available/openstack_https_frontend',
'/etc/haproxy/haproxy.cfg'] '/etc/haproxy/haproxy.cfg']
self.assertItemsEqual(_regconfs.configs, confs) self.assertEqual(sorted(_regconfs.configs), sorted(confs))
@patch('os.path.isfile') @patch('os.path.isfile')
def test_keystone_ca_cert_b64_no_cert_file(self, _isfile): def test_keystone_ca_cert_b64_no_cert_file(self, _isfile):
@ -390,7 +378,7 @@ class TestNeutronAPIUtils(CharmTestCase):
self.assertFalse(migrate_neutron_db.called) self.assertFalse(migrate_neutron_db.called)
@patch.object(ncontext, 'IdentityServiceContext') @patch.object(ncontext, 'IdentityServiceContext')
@patch('neutronclient.v2_0.client.Client') @patch.object(nutils, 'FakeNeutronClient')
def test_get_neutron_client(self, nclient, IdentityServiceContext): def test_get_neutron_client(self, nclient, IdentityServiceContext):
creds = { creds = {
'auth_protocol': 'http', 'auth_protocol': 'http',
@ -533,16 +521,16 @@ class TestNeutronAPIUtils(CharmTestCase):
add_user_to_group.assert_called_with('neutron', 'neutron') add_user_to_group.assert_called_with('neutron', 'neutron')
expected = [ expected = [
call('/var/lib/neutron', owner='neutron', call('/var/lib/neutron', owner='neutron',
group='neutron', perms=0755, force=False), group='neutron', perms=0o755, force=False),
call('/var/lib/neutron/lock', owner='neutron', call('/var/lib/neutron/lock', owner='neutron',
group='neutron', perms=0755, force=False), group='neutron', perms=0o755, force=False),
call('/var/log/neutron', owner='neutron', call('/var/log/neutron', owner='neutron',
group='neutron', perms=0755, force=False), group='neutron', perms=0o755, force=False),
] ]
self.assertEqual(mkdir.call_args_list, expected) self.assertEqual(mkdir.call_args_list, expected)
expected = [ expected = [
call('/var/log/neutron/server.log', '', owner='neutron', call('/var/log/neutron/server.log', '', owner='neutron',
group='neutron', perms=0600), group='neutron', perms=0o600),
] ]
self.assertEqual(write_file.call_args_list, expected) self.assertEqual(write_file.call_args_list, expected)

View File

@ -12,6 +12,7 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
import io
import os import os
import logging import logging
import unittest import unittest
@ -54,7 +55,7 @@ def get_default_config():
''' '''
default_config = {} default_config = {}
config = load_config() config = load_config()
for k, v in config.iteritems(): for k, v in config.items():
if 'default' in v: if 'default' in v:
default_config[k] = v['default'] default_config[k] = v['default']
else: else:
@ -128,12 +129,12 @@ def patch_open():
Yields the mock for "open" and "file", respectively.''' Yields the mock for "open" and "file", respectively.'''
mock_open = MagicMock(spec=open) mock_open = MagicMock(spec=open)
mock_file = MagicMock(spec=file) mock_file = MagicMock(spec=io.FileIO)
@contextmanager @contextmanager
def stub_open(*args, **kwargs): def stub_open(*args, **kwargs):
mock_open(*args, **kwargs) mock_open(*args, **kwargs)
yield mock_file yield mock_file
with patch('__builtin__.open', stub_open): with patch('builtins.open', stub_open):
yield mock_open, mock_file yield mock_open, mock_file