Merge with ~openstack-charmers/charms/trusty/nova-cloud-controller/next

This commit is contained in:
Subbarayudu Mukkamala 2015-05-27 16:29:46 -07:00
commit 5d4df943ed
29 changed files with 227 additions and 116 deletions

@ -18,8 +18,7 @@ test:
# coreycb note: The -v should only be temporary until Amulet sends
# raise_status() messages to stderr:
# https://bugs.launchpad.net/amulet/+bug/1320357
@juju test -v -p AMULET_HTTP_PROXY --timeout 900 \
00-setup 14-basic-precise-icehouse 15-basic-trusty-icehouse
@juju test -v -p AMULET_HTTP_PROXY,AMULET_OS_VIP --timeout 2700
sync: bin/charm_helpers_sync.py
@$(PYTHON) bin/charm_helpers_sync.py -c charm-helpers-hooks.yaml

@ -84,7 +84,6 @@ options:
nvp|nsx - Nicira Network Virtualization Platform/
VMware NSX Network Virtualization Platform
(renamed for Icehouse)
vsp - Nuage Networks VSP
.
This configuration only has context when used with
network-manager Quantum|Neutron.

@ -247,7 +247,9 @@ class NRPE(object):
service('restart', 'nagios-nrpe-server')
for rid in relation_ids("local-monitors"):
monitor_ids = relation_ids("local-monitors") + \
relation_ids("nrpe-external-master")
for rid in monitor_ids:
relation_set(relation_id=rid, monitors=yaml.dump(monitors))

@ -44,17 +44,24 @@ class OpenStackAmuletDeployment(AmuletDeployment):
Determine if the local branch being tested is derived from its
stable or next (dev) branch, and based on this, use the corresonding
stable or next branches for the other_services."""
base_charms = ['mysql', 'mongodb', 'rabbitmq-server']
base_charms = ['mysql', 'mongodb']
if self.series in ['precise', 'trusty']:
base_series = self.series
else:
base_series = self.current_next
if self.stable:
for svc in other_services:
temp = 'lp:charms/{}'
svc['location'] = temp.format(svc['name'])
temp = 'lp:charms/{}/{}'
svc['location'] = temp.format(base_series,
svc['name'])
else:
for svc in other_services:
if svc['name'] in base_charms:
temp = 'lp:charms/{}'
svc['location'] = temp.format(svc['name'])
temp = 'lp:charms/{}/{}'
svc['location'] = temp.format(base_series,
svc['name'])
else:
temp = 'lp:~openstack-charmers/charms/{}/{}/next'
svc['location'] = temp.format(self.current_next,
@ -99,9 +106,12 @@ class OpenStackAmuletDeployment(AmuletDeployment):
Return an integer representing the enum value of the openstack
release.
"""
# Must be ordered by OpenStack release (not by Ubuntu release):
(self.precise_essex, self.precise_folsom, self.precise_grizzly,
self.precise_havana, self.precise_icehouse,
self.trusty_icehouse, self.trusty_juno, self.trusty_kilo) = range(8)
self.trusty_icehouse, self.trusty_juno, self.utopic_juno,
self.trusty_kilo, self.vivid_kilo) = range(10)
releases = {
('precise', None): self.precise_essex,
('precise', 'cloud:precise-folsom'): self.precise_folsom,
@ -110,7 +120,9 @@ class OpenStackAmuletDeployment(AmuletDeployment):
('precise', 'cloud:precise-icehouse'): self.precise_icehouse,
('trusty', None): self.trusty_icehouse,
('trusty', 'cloud:trusty-juno'): self.trusty_juno,
('trusty', 'cloud:trusty-kilo'): self.trusty_kilo}
('trusty', 'cloud:trusty-kilo'): self.trusty_kilo,
('utopic', None): self.utopic_juno,
('vivid', None): self.vivid_kilo}
return releases[(self.series, self.openstack)]
def _get_openstack_release_string(self):

@ -320,14 +320,15 @@ def db_ssl(rdata, ctxt, ssl_dir):
class IdentityServiceContext(OSContextGenerator):
interfaces = ['identity-service']
def __init__(self, service=None, service_user=None):
def __init__(self, service=None, service_user=None, rel_name='identity-service'):
self.service = service
self.service_user = service_user
self.rel_name = rel_name
self.interfaces = [self.rel_name]
def __call__(self):
log('Generating template context for identity-service', level=DEBUG)
log('Generating template context for ' + self.rel_name, level=DEBUG)
ctxt = {}
if self.service and self.service_user:
@ -341,7 +342,7 @@ class IdentityServiceContext(OSContextGenerator):
ctxt['signing_dir'] = cachedir
for rid in relation_ids('identity-service'):
for rid in relation_ids(self.rel_name):
for unit in related_units(rid):
rdata = relation_get(rid=rid, unit=unit)
serv_host = rdata.get('service_host')
@ -458,6 +459,11 @@ class AMQPContext(OSContextGenerator):
ctxt['rabbitmq_hosts'] = ','.join(sorted(rabbitmq_hosts))
oslo_messaging_flags = conf.get('oslo-messaging-flags', None)
if oslo_messaging_flags:
ctxt['oslo_messaging_flags'] = config_flags_parser(
oslo_messaging_flags)
if not context_complete(ctxt):
return {}
@ -812,13 +818,12 @@ class NeutronContext(OSContextGenerator):
self.network_manager)
config = neutron_plugin_attribute(self.plugin, 'config',
self.network_manager)
nuage_ctxt = {
'core_plugin': driver,
'neutron_plugin': 'vsp',
'neutron_security_groups': self.neutron_security_groups,
'local_ip': unit_private_ip(),
'config': config
}
nuage_ctxt = {'core_plugin': driver,
'neutron_plugin': 'vsp',
'neutron_security_groups': self.neutron_security_groups,
'local_ip': unit_private_ip(),
'config': config}
return nuage_ctxt
def nvp_ctxt(self):
@ -898,14 +903,14 @@ class NeutronContext(OSContextGenerator):
if self.plugin == 'ovs':
ctxt.update(self.ovs_ctxt())
elif self.plugin == 'vsp':
ctxt.update(self.nuage_ctxt())
elif self.plugin in ['nvp', 'nsx']:
ctxt.update(self.nvp_ctxt())
elif self.plugin == 'n1kv':
ctxt.update(self.n1kv_ctxt())
elif self.plugin == 'Calico':
ctxt.update(self.calico_ctxt())
elif self.plugin == 'vsp':
ctxt.update(self.nuage_ctxt())
alchemy_flags = config('neutron-alchemy-flags')
if alchemy_flags:

@ -161,20 +161,6 @@ def neutron_plugins():
'neutron-plugin-cisco'],
'server_services': ['neutron-server']
},
'vsp': {
'config': '/etc/neutron/plugins/nuage/nuage_plugin.ini',
'driver': 'neutron.plugins.nuage.plugin.NuagePlugin',
'contexts': [
context.SharedDBContext(user=config('neutron-database-user'),
database=config('neutron-database'),
relation_prefix='neutron',
ssl_dir=NEUTRON_CONF_DIR)],
'services': [],
'packages': [],
'server_packages': ['neutron-server',
'neutron-plugin-nuage'],
'server_services': ['neutron-server']
},
'Calico': {
'config': '/etc/neutron/plugins/ml2/ml2_conf.ini',
'driver': 'neutron.plugins.ml2.plugin.Ml2Plugin',
@ -194,6 +180,19 @@ def neutron_plugins():
'nova-api-metadata']],
'server_packages': ['neutron-server', 'calico-control'],
'server_services': ['neutron-server']
},
'vsp': {
'config': '/etc/neutron/plugins/nuage/nuage_plugin.ini',
'driver': 'neutron.plugins.nuage.plugin.NuagePlugin',
'contexts': [
context.SharedDBContext(user=config('neutron-database-user'),
database=config('neutron-database'),
relation_prefix='neutron',
ssl_dir=NEUTRON_CONF_DIR)],
'services': [],
'packages': [],
'server_packages': ['neutron-server', 'neutron-plugin-nuage'],
'server_services': ['neutron-server']
}
}
if release >= 'icehouse':

@ -9,5 +9,9 @@ respawn
exec start-stop-daemon --start --chuid {{ user_name }} \
--chdir {{ start_dir }} --name {{ process_name }} \
--exec {{ executable_name }} -- \
{% for config_file in config_files -%}
--config-file={{ config_file }} \
{% endfor -%}
{% if log_file -%}
--log-file={{ log_file }}
{% endif -%}

@ -510,8 +510,10 @@ def git_clone_and_install(projects_yaml, core_project):
repository: 'git://git.openstack.org/openstack/requirements.git',
branch: 'stable/icehouse'}
directory: /mnt/openstack-git
http_proxy: http://squid.internal:3128
https_proxy: https://squid.internal:3128
The directory key is optional.
The directory, http_proxy, and https_proxy keys are optional.
"""
global requirements_dir
parent_dir = '/mnt/openstack-git'
@ -522,6 +524,13 @@ def git_clone_and_install(projects_yaml, core_project):
projects = yaml.load(projects_yaml)
_git_validate_projects_yaml(projects, core_project)
old_environ = dict(os.environ)
if 'http_proxy' in projects.keys():
os.environ['http_proxy'] = projects['http_proxy']
if 'https_proxy' in projects.keys():
os.environ['https_proxy'] = projects['https_proxy']
if 'directory' in projects.keys():
parent_dir = projects['directory']
@ -536,6 +545,8 @@ def git_clone_and_install(projects_yaml, core_project):
repo_dir = _git_clone_and_install_single(repo, branch, parent_dir,
update_requirements=True)
os.environ = old_environ
def _git_validate_projects_yaml(projects, core_project):
"""

@ -20,11 +20,13 @@
# Authors:
# Charm Helpers Developers <juju@lists.ubuntu.com>
from __future__ import print_function
import os
import json
import yaml
import subprocess
import sys
import errno
from subprocess import CalledProcessError
import six
@ -87,7 +89,18 @@ def log(message, level=None):
if not isinstance(message, six.string_types):
message = repr(message)
command += [message]
subprocess.call(command)
# Missing juju-log should not cause failures in unit tests
# Send log output to stderr
try:
subprocess.call(command)
except OSError as e:
if e.errno == errno.ENOENT:
if level:
message = "{}: {}".format(level, message)
message = "juju-log: {}".format(message)
print(message, file=sys.stderr)
else:
raise
class Serializable(UserDict):

@ -33,9 +33,9 @@ def bool_from_string(value):
value = value.strip().lower()
if value in ['y', 'yes', 'true', 't']:
if value in ['y', 'yes', 'true', 't', 'on']:
return True
elif value in ['n', 'no', 'false', 'f']:
elif value in ['n', 'no', 'false', 'f', 'off']:
return False
msg = "Unable to interpret string value '%s' as boolean" % (value)

@ -207,8 +207,11 @@ def amqp_changed():
def conditional_neutron_migration():
if os_release('nova-common') <= 'icehouse':
log('Not running neutron database migration as migrations are handled'
log('Not running neutron database migration as migrations are handled '
'by the neutron-server process.')
elif os_release('nova-common') >= 'kilo':
log('Not running neutron database migration as migrations are by '
'the neutron-api charm.')
else:
migrate_neutron_database()
# neutron-api service may have appeared while the migration was
@ -295,17 +298,18 @@ def db_changed():
# acl entry has been added. So, if the db supports passing a list of
# permitted units then check if we're in the list.
allowed_units = relation_get('nova_allowed_units')
if allowed_units and local_unit() not in allowed_units.split():
log('Allowed_units list provided and this unit not present')
return
migrate_nova_database()
log('Triggering remote cloud-compute restarts.')
[compute_joined(rid=rid, remote_restart=True)
for rid in relation_ids('cloud-compute')]
log('Triggering remote cell restarts.')
[nova_cell_relation_joined(rid=rid, remote_restart=True)
for rid in relation_ids('cell')]
conditional_neutron_migration()
if allowed_units and local_unit() in allowed_units.split():
migrate_nova_database()
log('Triggering remote cloud-compute restarts.')
[compute_joined(rid=rid, remote_restart=True)
for rid in relation_ids('cloud-compute')]
log('Triggering remote cell restarts.')
[nova_cell_relation_joined(rid=rid, remote_restart=True)
for rid in relation_ids('cell')]
conditional_neutron_migration()
else:
log('allowed_units either not presented, or local unit '
'not in acl list: %s' % repr(allowed_units))
@hooks.hook('pgsql-nova-db-relation-changed')

@ -530,11 +530,12 @@ def _do_openstack_upgrade(new_src):
configs.write_all()
neutron_db_manage(['upgrade', 'head'])
else:
if new_os_rel < 'kilo':
neutron_db_manage(['stamp', cur_os_rel])
migrate_neutron_database()
# NOTE(jamespage) upgrade with existing config files as the
# havana->icehouse migration enables new service_plugins which
# create issues with db upgrades
neutron_db_manage(['stamp', cur_os_rel])
migrate_neutron_database()
reset_os_release()
configs = register_configs(release=new_os_rel)
configs.write_all()

@ -72,6 +72,10 @@ default_floating_pool = {{ external_network }}
{% endif -%}
{% endif -%}
{% if neutron_plugin and neutron_plugin == 'vsp' -%}
neutron_ovs_bridge = alubr0
{% endif -%}
{% if neutron_plugin and neutron_plugin == 'nvp' -%}
security_group_api = neutron
nova_firewall_driver = nova.virt.firewall.NoopFirewallDriver

@ -65,6 +65,10 @@ default_floating_pool = {{ external_network }}
{% endif -%}
{% endif -%}
{% if neutron_plugin and neutron_plugin == 'vsp' -%}
neutron_ovs_bridge = alubr0
{% endif -%}
{% if neutron_plugin and neutron_plugin == 'nvp' -%}
security_group_api = neutron
nova_firewall_driver = nova.virt.firewall.NoopFirewallDriver

12
tests/016-basic-trusty-juno Executable file

@ -0,0 +1,12 @@
#!/usr/bin/python
"""Amulet tests on a basic nova cloud controller deployment on
trusty-juno."""
from basic_deployment import NovaCCBasicDeployment
if __name__ == '__main__':
deployment = NovaCCBasicDeployment(series='trusty',
openstack='cloud:trusty-juno',
source='cloud:trusty-updates/juno')
deployment.run_tests()

@ -0,0 +1,12 @@
#!/usr/bin/python
"""Amulet tests on a basic nova cloud controller deployment on
trusty-kilo."""
from basic_deployment import NovaCCBasicDeployment
if __name__ == '__main__':
deployment = NovaCCBasicDeployment(series='trusty',
openstack='cloud:trusty-kilo',
source='cloud:trusty-updates/kilo')
deployment.run_tests()

10
tests/018-basic-utopic-juno Executable file

@ -0,0 +1,10 @@
#!/usr/bin/python
"""Amulet tests on a basic nova cloud controller deployment on
utopic-juno."""
from basic_deployment import NovaCCBasicDeployment
if __name__ == '__main__':
deployment = NovaCCBasicDeployment(series='utopic')
deployment.run_tests()

@ -0,0 +1,10 @@
#!/usr/bin/python
"""Amulet tests on a basic nova cloud controller deployment on
vivid-kilo."""
from basic_deployment import NovaCCBasicDeployment
if __name__ == '__main__':
deployment = NovaCCBasicDeployment(series='vivid')
deployment.run_tests()

@ -1,18 +0,0 @@
#!/usr/bin/python
"""Amulet tests on a basic nova cloud controller deployment on
precise-folsom."""
import amulet
from basic_deployment import NovaCCBasicDeployment
if __name__ == '__main__':
# NOTE(coreycb): Skipping failing test until resolved. 'nova-manage db sync'
# fails in shared-db-relation-changed (only fails on folsom)
message = "Skipping failing test until resolved"
amulet.raise_status(amulet.SKIP, msg=message)
deployment = NovaCCBasicDeployment(series='precise',
openstack='cloud:precise-folsom',
source='cloud:precise-updates/folsom')
deployment.run_tests()

@ -1,12 +0,0 @@
#!/usr/bin/python
"""Amulet tests on a basic nova cloud controller deployment on
precise-grizzly."""
from basic_deployment import NovaCCBasicDeployment
if __name__ == '__main__':
deployment = NovaCCBasicDeployment(series='precise',
openstack='cloud:precise-grizzly',
source='cloud:precise-updates/grizzly')
deployment.run_tests()

@ -1,12 +0,0 @@
#!/usr/bin/python
"""Amulet tests on a basic nova cloud controller deployment on
precise-havana."""
from basic_deployment import NovaCCBasicDeployment
if __name__ == '__main__':
deployment = NovaCCBasicDeployment(series='precise',
openstack='cloud:precise-havana',
source='cloud:precise-updates/havana')
deployment.run_tests()

@ -13,13 +13,13 @@ from charmhelpers.contrib.openstack.amulet.utils import (
)
# Use DEBUG to turn on debug logging
u = OpenStackAmuletUtils(ERROR)
u = OpenStackAmuletUtils(DEBUG)
class NovaCCBasicDeployment(OpenStackAmuletDeployment):
"""Amulet tests on a basic nova cloud controller deployment."""
def __init__(self, series=None, openstack=None, source=None, stable=True):
def __init__(self, series=None, openstack=None, source=None, stable=False):
"""Deploy the entire test environment."""
super(NovaCCBasicDeployment, self).__init__(series, openstack, source, stable)
self._add_services()

@ -79,6 +79,9 @@ class AmuletUtils(object):
for k, v in six.iteritems(commands):
for cmd in v:
output, code = k.run(cmd)
self.log.debug('{} `{}` returned '
'{}'.format(k.info['unit_name'],
cmd, code))
if code != 0:
return "command `{}` returned {}".format(cmd, str(code))
return None
@ -86,7 +89,11 @@ class AmuletUtils(object):
def _get_config(self, unit, filename):
"""Get a ConfigParser object for parsing a unit's config file."""
file_contents = unit.file_contents(filename)
config = ConfigParser.ConfigParser()
# NOTE(beisner): by default, ConfigParser does not handle options
# with no value, such as the flags used in the mysql my.cnf file.
# https://bugs.python.org/issue7005
config = ConfigParser.ConfigParser(allow_no_value=True)
config.readfp(io.StringIO(file_contents))
return config
@ -118,6 +125,9 @@ class AmuletUtils(object):
longs, or can be a function that evaluate a variable and returns a
bool.
"""
self.log.debug('actual: {}'.format(repr(actual)))
self.log.debug('expected: {}'.format(repr(expected)))
for k, v in six.iteritems(expected):
if k in actual:
if (isinstance(v, six.string_types) or
@ -134,7 +144,6 @@ class AmuletUtils(object):
def validate_relation_data(self, sentry_unit, relation, expected):
"""Validate actual relation data based on expected relation data."""
actual = sentry_unit.relation(relation[0], relation[1])
self.log.debug('actual: {}'.format(repr(actual)))
return self._validate_dict_data(expected, actual)
def _validate_list_data(self, expected, actual):

@ -44,17 +44,24 @@ class OpenStackAmuletDeployment(AmuletDeployment):
Determine if the local branch being tested is derived from its
stable or next (dev) branch, and based on this, use the corresonding
stable or next branches for the other_services."""
base_charms = ['mysql', 'mongodb', 'rabbitmq-server']
base_charms = ['mysql', 'mongodb']
if self.series in ['precise', 'trusty']:
base_series = self.series
else:
base_series = self.current_next
if self.stable:
for svc in other_services:
temp = 'lp:charms/{}'
svc['location'] = temp.format(svc['name'])
temp = 'lp:charms/{}/{}'
svc['location'] = temp.format(base_series,
svc['name'])
else:
for svc in other_services:
if svc['name'] in base_charms:
temp = 'lp:charms/{}'
svc['location'] = temp.format(svc['name'])
temp = 'lp:charms/{}/{}'
svc['location'] = temp.format(base_series,
svc['name'])
else:
temp = 'lp:~openstack-charmers/charms/{}/{}/next'
svc['location'] = temp.format(self.current_next,
@ -99,9 +106,12 @@ class OpenStackAmuletDeployment(AmuletDeployment):
Return an integer representing the enum value of the openstack
release.
"""
# Must be ordered by OpenStack release (not by Ubuntu release):
(self.precise_essex, self.precise_folsom, self.precise_grizzly,
self.precise_havana, self.precise_icehouse,
self.trusty_icehouse, self.trusty_juno, self.trusty_kilo) = range(8)
self.trusty_icehouse, self.trusty_juno, self.utopic_juno,
self.trusty_kilo, self.vivid_kilo) = range(10)
releases = {
('precise', None): self.precise_essex,
('precise', 'cloud:precise-folsom'): self.precise_folsom,
@ -110,7 +120,9 @@ class OpenStackAmuletDeployment(AmuletDeployment):
('precise', 'cloud:precise-icehouse'): self.precise_icehouse,
('trusty', None): self.trusty_icehouse,
('trusty', 'cloud:trusty-juno'): self.trusty_juno,
('trusty', 'cloud:trusty-kilo'): self.trusty_kilo}
('trusty', 'cloud:trusty-kilo'): self.trusty_kilo,
('utopic', None): self.utopic_juno,
('vivid', None): self.vivid_kilo}
return releases[(self.series, self.openstack)]
def _get_openstack_release_string(self):

@ -348,10 +348,11 @@ class NovaCCHooksTests(CharmTestCase):
@patch.object(hooks, 'conditional_neutron_migration')
@patch.object(hooks, 'CONFIGS')
def test_db_changed(self, configs, cond_neutron_mig):
'No database migration is attempted when ACL list is not present'
self._shared_db_test(configs)
self.assertTrue(configs.write_all.called)
self.migrate_nova_database.assert_called_with()
cond_neutron_mig.assert_called_with()
self.assertFalse(self.migrate_nova_database.called)
self.assertFalse(cond_neutron_mig.called)
@patch.object(hooks, 'CONFIGS')
def test_db_changed_allowed(self, configs):
@ -597,21 +598,28 @@ class NovaCCHooksTests(CharmTestCase):
}
self.assertEqual(_con_sets, console_settings)
def test_conditional_neutron_migration_noapi_rel(self):
def test_conditional_neutron_migration(self):
self.os_release.return_value = 'juno'
self.relation_ids.return_value = []
self.services.return_value = ['neutron-server']
hooks.conditional_neutron_migration()
self.migrate_neutron_database.assert_called_with()
self.service_restart.assert_called_with('neutron-server')
def test_conditional_neutron_migration_noapi_rel_juno(self):
def test_conditional_neutron_migration_juno(self):
self.os_release.return_value = 'icehouse'
self.relation_ids.return_value = []
hooks.conditional_neutron_migration()
self.log.assert_called_with(
'Not running neutron database migration as migrations are handled'
'by the neutron-server process.'
' by the neutron-server process.'
)
def test_conditional_neutron_migration_kilo(self):
self.os_release.return_value = 'kilo'
self.relation_ids.return_value = []
hooks.conditional_neutron_migration()
self.log.assert_called_with(
'Not running neutron database migration as migrations are by the '
'neutron-api charm.'
)
def test_ha_relation_joined_no_bound_ip(self):

@ -687,6 +687,29 @@ class NovaCCUtilsTests(CharmTestCase):
self.assertEquals(self.ml2_migration.call_count, 0)
self.assertTrue(migrate_nova_database.call_count, 1)
@patch.object(utils, 'get_step_upgrade_source')
@patch.object(utils, 'migrate_nova_database')
@patch.object(utils, 'determine_packages')
def test_upgrade_juno_kilo(self, determine_packages,
migrate_nova_database,
get_step_upgrade_source):
"Simulate a call to do_openstack_upgrade() for juno->kilo"
self.test_config.set('openstack-origin', 'cloud:trusty-kilo')
get_step_upgrade_source.return_value = None
self.os_release.return_value = 'juno'
self.get_os_codename_install_source.return_value = 'kilo'
self.eligible_leader.return_value = True
self.relation_ids.return_value = []
utils.do_openstack_upgrade()
self.assertEquals(self.neutron_db_manage.call_count, 0)
self.apt_update.assert_called_with(fatal=True)
self.apt_upgrade.assert_called_with(options=DPKG_OPTS, fatal=True,
dist=True)
self.apt_install.assert_called_with(determine_packages(), fatal=True)
self.register_configs.assert_called_with(release='kilo')
self.assertEquals(self.ml2_migration.call_count, 0)
self.assertTrue(migrate_nova_database.call_count, 1)
@patch.object(utils, '_do_openstack_upgrade')
def test_upgrade_grizzly_icehouse_source(self, _do_openstack_upgrade):
"Verify get_step_upgrade_source() for grizzly->icehouse"