[coreycb,r=james-page] Fixup amulet tests.

This commit is contained in:
James Page 2014-10-06 22:43:12 +01:00
commit ea5c67d3c7
11 changed files with 186 additions and 126 deletions

View File

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

View File

@ -57,6 +57,8 @@ def get_address_in_network(network, fallback=None, fatal=False):
else: else:
if fatal: if fatal:
not_found_error_out() not_found_error_out()
else:
return None
_validate_cidr(network) _validate_cidr(network)
network = netaddr.IPNetwork(network) network = netaddr.IPNetwork(network)

View File

@ -1,6 +1,3 @@
from bzrlib.branch import Branch
import os
import re
from charmhelpers.contrib.amulet.deployment import ( from charmhelpers.contrib.amulet.deployment import (
AmuletDeployment AmuletDeployment
) )
@ -13,62 +10,62 @@ class OpenStackAmuletDeployment(AmuletDeployment):
that is specifically for use by OpenStack charms. that is specifically for use by OpenStack charms.
""" """
def __init__(self, series=None, openstack=None, source=None): def __init__(self, series=None, openstack=None, source=None, stable=True):
"""Initialize the deployment environment.""" """Initialize the deployment environment."""
super(OpenStackAmuletDeployment, self).__init__(series) super(OpenStackAmuletDeployment, self).__init__(series)
self.openstack = openstack self.openstack = openstack
self.source = source self.source = source
self.stable = stable
def _is_dev_branch(self): # Note(coreycb): this needs to be changed when new next branches come
"""Determine if branch being tested is a dev (i.e. next) branch.""" # out.
branch = Branch.open(os.getcwd()) self.current_next = "trusty"
parent = branch.get_parent()
pattern = re.compile("^.*/next/$")
if (pattern.match(parent)):
return True
else:
return False
def _determine_branch_locations(self, other_services): def _determine_branch_locations(self, other_services):
"""Determine the branch locations for the other services. """Determine the branch locations for the other services.
If the branch being tested is a dev branch, then determine the Determine if the local branch being tested is derived from its
development branch locations for the other services. Otherwise, stable or next (dev) branch, and based on this, use the corresonding
the default charm store branches will be used.""" stable or next branches for the other_services."""
name = 0 base_charms = ['mysql', 'mongodb', 'rabbitmq-server']
if self._is_dev_branch():
updated_services = [] if self.stable:
for svc in other_services: for svc in other_services:
if svc[name] in ['mysql', 'mongodb', 'rabbitmq-server']: temp = 'lp:charms/{}'
location = 'lp:charms/{}'.format(svc[name]) svc['location'] = temp.format(svc['name'])
else:
for svc in other_services:
if svc['name'] in base_charms:
temp = 'lp:charms/{}'
svc['location'] = temp.format(svc['name'])
else: else:
temp = 'lp:~openstack-charmers/charms/trusty/{}/next' temp = 'lp:~openstack-charmers/charms/{}/{}/next'
location = temp.format(svc[name]) svc['location'] = temp.format(self.current_next,
updated_services.append(svc + (location,)) svc['name'])
other_services = updated_services
return other_services return other_services
def _add_services(self, this_service, other_services): def _add_services(self, this_service, other_services):
"""Add services to the deployment and set openstack-origin/source.""" """Add services to the deployment and set openstack-origin/source."""
name = 0
other_services = self._determine_branch_locations(other_services) other_services = self._determine_branch_locations(other_services)
super(OpenStackAmuletDeployment, self)._add_services(this_service, super(OpenStackAmuletDeployment, self)._add_services(this_service,
other_services) other_services)
services = other_services services = other_services
services.append(this_service) services.append(this_service)
use_source = ['mysql', 'mongodb', 'rabbitmq-server', 'ceph'] use_source = ['mysql', 'mongodb', 'rabbitmq-server', 'ceph',
'ceph-osd', 'ceph-radosgw']
if self.openstack: if self.openstack:
for svc in services: for svc in services:
if svc[name] not in use_source: if svc['name'] not in use_source:
config = {'openstack-origin': self.openstack} config = {'openstack-origin': self.openstack}
self.d.configure(svc[name], config) self.d.configure(svc['name'], config)
if self.source: if self.source:
for svc in services: for svc in services:
if svc[name] in use_source: if svc['name'] in use_source:
config = {'source': self.source} config = {'source': self.source}
self.d.configure(svc[name], config) self.d.configure(svc['name'], config)
def _configure_services(self, configs): def _configure_services(self, configs):
"""Configure all of the services.""" """Configure all of the services."""

View File

@ -52,6 +52,7 @@ from charmhelpers.contrib.openstack.neutron import (
from charmhelpers.contrib.network.ip import ( from charmhelpers.contrib.network.ip import (
get_address_in_network, get_address_in_network,
get_ipv6_addr, get_ipv6_addr,
get_netmask_for_address,
format_ipv6_addr, format_ipv6_addr,
is_address_in_network is_address_in_network
) )
@ -408,6 +409,9 @@ class CephContext(OSContextGenerator):
return ctxt return ctxt
ADDRESS_TYPES = ['admin', 'internal', 'public']
class HAProxyContext(OSContextGenerator): class HAProxyContext(OSContextGenerator):
interfaces = ['cluster'] interfaces = ['cluster']
@ -420,7 +424,6 @@ class HAProxyContext(OSContextGenerator):
if not relation_ids('cluster'): if not relation_ids('cluster'):
return {} return {}
cluster_hosts = {}
l_unit = local_unit().replace('/', '-') l_unit = local_unit().replace('/', '-')
if config('prefer-ipv6'): if config('prefer-ipv6'):
@ -428,17 +431,49 @@ class HAProxyContext(OSContextGenerator):
else: else:
addr = unit_get('private-address') addr = unit_get('private-address')
cluster_hosts[l_unit] = get_address_in_network(config('os-internal-network'), cluster_hosts = {}
addr)
for rid in relation_ids('cluster'): # NOTE(jamespage): build out map of configured network endpoints
for unit in related_units(rid): # and associated backends
_unit = unit.replace('/', '-') for addr_type in ADDRESS_TYPES:
addr = relation_get('private-address', rid=rid, unit=unit) laddr = get_address_in_network(
cluster_hosts[_unit] = addr config('os-{}-network'.format(addr_type)))
if laddr:
cluster_hosts[laddr] = {}
cluster_hosts[laddr]['network'] = "{}/{}".format(
laddr,
get_netmask_for_address(laddr)
)
cluster_hosts[laddr]['backends'] = {}
cluster_hosts[laddr]['backends'][l_unit] = laddr
for rid in relation_ids('cluster'):
for unit in related_units(rid):
_unit = unit.replace('/', '-')
_laddr = relation_get('{}-address'.format(addr_type),
rid=rid, unit=unit)
if _laddr:
cluster_hosts[laddr]['backends'][_unit] = _laddr
# NOTE(jamespage) no split configurations found, just use
# private addresses
if not cluster_hosts:
cluster_hosts[addr] = {}
cluster_hosts[addr]['network'] = "{}/{}".format(
addr,
get_netmask_for_address(addr)
)
cluster_hosts[addr]['backends'] = {}
cluster_hosts[addr]['backends'][l_unit] = addr
for rid in relation_ids('cluster'):
for unit in related_units(rid):
_unit = unit.replace('/', '-')
_laddr = relation_get('private-address',
rid=rid, unit=unit)
if _laddr:
cluster_hosts[addr]['backends'][_unit] = _laddr
ctxt = { ctxt = {
'units': cluster_hosts, 'frontends': cluster_hosts,
} }
if config('haproxy-server-timeout'): if config('haproxy-server-timeout'):
@ -455,12 +490,13 @@ class HAProxyContext(OSContextGenerator):
ctxt['haproxy_host'] = '0.0.0.0' ctxt['haproxy_host'] = '0.0.0.0'
ctxt['stat_port'] = ':8888' ctxt['stat_port'] = ':8888'
if len(cluster_hosts.keys()) > 1: for frontend in cluster_hosts:
# Enable haproxy when we have enough peers. if len(cluster_hosts[frontend]['backends']) > 1:
log('Ensuring haproxy enabled in /etc/default/haproxy.') # Enable haproxy when we have enough peers.
with open('/etc/default/haproxy', 'w') as out: log('Ensuring haproxy enabled in /etc/default/haproxy.')
out.write('ENABLED=1\n') with open('/etc/default/haproxy', 'w') as out:
return ctxt out.write('ENABLED=1\n')
return ctxt
log('HAProxy context is incomplete, this unit has no peers.') log('HAProxy context is incomplete, this unit has no peers.')
return {} return {}
@ -722,22 +758,22 @@ class NeutronContext(OSContextGenerator):
class OSConfigFlagContext(OSContextGenerator): class OSConfigFlagContext(OSContextGenerator):
""" """
Responsible for adding user-defined config-flags in charm config to a Responsible for adding user-defined config-flags in charm config to a
template context. template context.
NOTE: the value of config-flags may be a comma-separated list of NOTE: the value of config-flags may be a comma-separated list of
key=value pairs and some Openstack config files support key=value pairs and some Openstack config files support
comma-separated lists as values. comma-separated lists as values.
""" """
def __call__(self): def __call__(self):
config_flags = config('config-flags') config_flags = config('config-flags')
if not config_flags: if not config_flags:
return {} return {}
flags = config_flags_parser(config_flags) flags = config_flags_parser(config_flags)
return {'user_config_flags': flags} return {'user_config_flags': flags}
class SubordinateConfigContext(OSContextGenerator): class SubordinateConfigContext(OSContextGenerator):

View File

@ -34,17 +34,21 @@ listen stats {{ stat_port }}
stats uri / stats uri /
stats auth admin:password stats auth admin:password
{% if units -%} {% if frontends -%}
{% for service, ports in service_ports.iteritems() -%} {% for service, ports in service_ports.iteritems() -%}
listen {{ service }}_ipv4 0.0.0.0:{{ ports[0] }} frontend tcp-in_{{ service }}
balance roundrobin bind *:{{ ports[0] }}
{% for unit, address in units.iteritems() -%} bind :::{{ ports[0] }}
server {{ unit }} {{ address }}:{{ ports[1] }} check {% for frontend in frontends -%}
acl net_{{ frontend }} dst {{ frontends[frontend]['network'] }}
use_backend {{ service }}_{{ frontend }} if net_{{ frontend }}
{% endfor %} {% endfor %}
listen {{ service }}_ipv6 :::{{ ports[0] }} {% for frontend in frontends -%}
balance roundrobin backend {{ service }}_{{ frontend }}
{% for unit, address in units.iteritems() -%} balance leastconn
{% for unit, address in frontends[frontend]['backends'].iteritems() -%}
server {{ unit }} {{ address }}:{{ ports[1] }} check server {{ unit }} {{ address }}:{{ ports[1] }} check
{% endfor %} {% endfor %}
{% endfor -%} {% endfor -%}
{% endfor -%}
{% endif -%} {% endif -%}

View File

@ -78,6 +78,8 @@ SWIFT_CODENAMES = OrderedDict([
('1.12.0', 'icehouse'), ('1.12.0', 'icehouse'),
('1.11.0', 'icehouse'), ('1.11.0', 'icehouse'),
('2.0.0', 'juno'), ('2.0.0', 'juno'),
('2.1.0', 'juno'),
('2.2.0', 'juno'),
]) ])
DEFAULT_LOOPBACK_SIZE = '5G' DEFAULT_LOOPBACK_SIZE = '5G'

View File

@ -4,8 +4,8 @@ set -ex
sudo add-apt-repository --yes ppa:juju/stable sudo add-apt-repository --yes ppa:juju/stable
sudo apt-get update --yes sudo apt-get update --yes
sudo apt-get install --yes python-amulet sudo apt-get install --yes python-amulet \
sudo apt-get install --yes python-swiftclient python-swiftclient \
sudo apt-get install --yes python-glanceclient python-glanceclient \
sudo apt-get install --yes python-keystoneclient python-keystoneclient \
sudo apt-get install --yes python-novaclient python-novaclient

View File

@ -1,6 +1,12 @@
This directory provides Amulet tests that focus on verification of swift-storage This directory provides Amulet tests that focus on verification of swift-storage
deployments. deployments.
In order to run tests, you'll need charm-tools installed (in addition to
juju, of course):
sudo add-apt-repository ppa:juju/stable
sudo apt-get update
sudo apt-get install charm-tools
If you use a web proxy server to access the web, you'll need to set the If you use a web proxy server to access the web, you'll need to set the
AMULET_HTTP_PROXY environment variable to the http URL of the proxy server. AMULET_HTTP_PROXY environment variable to the http URL of the proxy server.

View File

@ -20,10 +20,10 @@ u = OpenStackAmuletUtils(ERROR)
class SwiftStorageBasicDeployment(OpenStackAmuletDeployment): class SwiftStorageBasicDeployment(OpenStackAmuletDeployment):
"""Amulet tests on a basic swift-storage deployment.""" """Amulet tests on a basic swift-storage deployment."""
def __init__(self, series, openstack=None, source=None): def __init__(self, series, openstack=None, source=None, stable=False):
"""Deploy the entire test environment.""" """Deploy the entire test environment."""
super(SwiftStorageBasicDeployment, self).__init__(series, openstack, super(SwiftStorageBasicDeployment, self).__init__(series, openstack,
source) source, stable)
self._add_services() self._add_services()
self._add_relations() self._add_relations()
self._configure_services() self._configure_services()
@ -31,12 +31,15 @@ class SwiftStorageBasicDeployment(OpenStackAmuletDeployment):
self._initialize_tests() self._initialize_tests()
def _add_services(self): def _add_services(self):
"""Add the service that we're testing, including the number of units, """Add services
where swift-storage is local, and the other charms are from
the charm store.""" Add the services that we're testing, where swift-storage is local,
this_service = ('swift-storage', 1) and the rest of the service are from lp branches that are
other_services = [('mysql', 1), compatible with the local charm (e.g. stable or next).
('keystone', 1), ('glance', 1), ('swift-proxy', 1)] """
this_service = {'name': 'swift-storage'}
other_services = [{'name': 'mysql'}, {'name': 'keystone'},
{'name': 'glance'}, {'name': 'swift-proxy'}]
super(SwiftStorageBasicDeployment, self)._add_services(this_service, super(SwiftStorageBasicDeployment, self)._add_services(this_service,
other_services) other_services)
@ -249,9 +252,14 @@ class SwiftStorageBasicDeployment(OpenStackAmuletDeployment):
message = u.relation_error('swift-proxy swift-storage', ret) message = u.relation_error('swift-proxy swift-storage', ret)
amulet.raise_status(amulet.FAIL, msg=message) amulet.raise_status(amulet.FAIL, msg=message)
def test_restart_on_config_change(self): def test_z_restart_on_config_change(self):
"""Verify that the specified services are restarted when the config """Verify that the specified services are restarted when the config
is changed.""" is changed.
Note(coreycb): The method name with the _z_ is a little odd
but it forces the test to run last. It just makes things
easier because restarting services requires re-authorization.
"""
# NOTE(coreycb): Skipping failing test on until resolved. This test # NOTE(coreycb): Skipping failing test on until resolved. This test
# fails because the config file's last mod time is # fails because the config file's last mod time is
# slightly after the process' last mod time. # slightly after the process' last mod time.
@ -282,6 +290,8 @@ class SwiftStorageBasicDeployment(OpenStackAmuletDeployment):
config = '/etc/swift/{}'.format(conf) config = '/etc/swift/{}'.format(conf)
if not u.service_restarted(self.swift_storage_sentry, s, config, if not u.service_restarted(self.swift_storage_sentry, s, config,
pgrep_full=True, sleep_time=time): pgrep_full=True, sleep_time=time):
self.d.configure('swift-storage',
{'object-server-threads-per-disk': '4'})
msg = "service {} didn't restart after config change".format(s) msg = "service {} didn't restart after config change".format(s)
amulet.raise_status(amulet.FAIL, msg=msg) amulet.raise_status(amulet.FAIL, msg=msg)
time = 0 time = 0

View File

@ -25,25 +25,30 @@ class AmuletDeployment(object):
Add services to the deployment where this_service is the local charm Add services to the deployment where this_service is the local charm
that we're testing and other_services are the other services that that we're testing and other_services are the other services that
are being used in the amulet tests. are being used in the local amulet tests.
""" """
name, units, location = range(3) if this_service['name'] != os.path.basename(os.getcwd()):
s = this_service['name']
if this_service[name] != os.path.basename(os.getcwd()):
s = this_service[name]
msg = "The charm's root directory name needs to be {}".format(s) msg = "The charm's root directory name needs to be {}".format(s)
amulet.raise_status(amulet.FAIL, msg=msg) amulet.raise_status(amulet.FAIL, msg=msg)
self.d.add(this_service[name], units=this_service[units]) if 'units' not in this_service:
this_service['units'] = 1
self.d.add(this_service['name'], units=this_service['units'])
for svc in other_services: for svc in other_services:
if len(svc) > 2: if 'location' in svc:
branch_location = svc[location] branch_location = svc['location']
elif self.series: elif self.series:
branch_location = 'cs:{}/{}'.format(self.series, svc[name]), branch_location = 'cs:{}/{}'.format(self.series, svc['name']),
else: else:
branch_location = None branch_location = None
self.d.add(svc[name], charm=branch_location, units=svc[units])
if 'units' not in svc:
svc['units'] = 1
self.d.add(svc['name'], charm=branch_location, units=svc['units'])
def _add_relations(self, relations): def _add_relations(self, relations):
"""Add all of the relations for the services.""" """Add all of the relations for the services."""

View File

@ -1,6 +1,3 @@
from bzrlib.branch import Branch
import os
import re
from charmhelpers.contrib.amulet.deployment import ( from charmhelpers.contrib.amulet.deployment import (
AmuletDeployment AmuletDeployment
) )
@ -13,62 +10,62 @@ class OpenStackAmuletDeployment(AmuletDeployment):
that is specifically for use by OpenStack charms. that is specifically for use by OpenStack charms.
""" """
def __init__(self, series=None, openstack=None, source=None): def __init__(self, series=None, openstack=None, source=None, stable=True):
"""Initialize the deployment environment.""" """Initialize the deployment environment."""
super(OpenStackAmuletDeployment, self).__init__(series) super(OpenStackAmuletDeployment, self).__init__(series)
self.openstack = openstack self.openstack = openstack
self.source = source self.source = source
self.stable = stable
def _is_dev_branch(self): # Note(coreycb): this needs to be changed when new next branches come
"""Determine if branch being tested is a dev (i.e. next) branch.""" # out.
branch = Branch.open(os.getcwd()) self.current_next = "trusty"
parent = branch.get_parent()
pattern = re.compile("^.*/next/$")
if (pattern.match(parent)):
return True
else:
return False
def _determine_branch_locations(self, other_services): def _determine_branch_locations(self, other_services):
"""Determine the branch locations for the other services. """Determine the branch locations for the other services.
If the branch being tested is a dev branch, then determine the Determine if the local branch being tested is derived from its
development branch locations for the other services. Otherwise, stable or next (dev) branch, and based on this, use the corresonding
the default charm store branches will be used.""" stable or next branches for the other_services."""
name = 0 base_charms = ['mysql', 'mongodb', 'rabbitmq-server']
if self._is_dev_branch():
updated_services = [] if self.stable:
for svc in other_services: for svc in other_services:
if svc[name] in ['mysql', 'mongodb', 'rabbitmq-server']: temp = 'lp:charms/{}'
location = 'lp:charms/{}'.format(svc[name]) svc['location'] = temp.format(svc['name'])
else:
for svc in other_services:
if svc['name'] in base_charms:
temp = 'lp:charms/{}'
svc['location'] = temp.format(svc['name'])
else: else:
temp = 'lp:~openstack-charmers/charms/trusty/{}/next' temp = 'lp:~openstack-charmers/charms/{}/{}/next'
location = temp.format(svc[name]) svc['location'] = temp.format(self.current_next,
updated_services.append(svc + (location,)) svc['name'])
other_services = updated_services
return other_services return other_services
def _add_services(self, this_service, other_services): def _add_services(self, this_service, other_services):
"""Add services to the deployment and set openstack-origin/source.""" """Add services to the deployment and set openstack-origin/source."""
name = 0
other_services = self._determine_branch_locations(other_services) other_services = self._determine_branch_locations(other_services)
super(OpenStackAmuletDeployment, self)._add_services(this_service, super(OpenStackAmuletDeployment, self)._add_services(this_service,
other_services) other_services)
services = other_services services = other_services
services.append(this_service) services.append(this_service)
use_source = ['mysql', 'mongodb', 'rabbitmq-server', 'ceph'] use_source = ['mysql', 'mongodb', 'rabbitmq-server', 'ceph',
'ceph-osd', 'ceph-radosgw']
if self.openstack: if self.openstack:
for svc in services: for svc in services:
if svc[name] not in use_source: if svc['name'] not in use_source:
config = {'openstack-origin': self.openstack} config = {'openstack-origin': self.openstack}
self.d.configure(svc[name], config) self.d.configure(svc['name'], config)
if self.source: if self.source:
for svc in services: for svc in services:
if svc[name] in use_source: if svc['name'] in use_source:
config = {'source': self.source} config = {'source': self.source}
self.d.configure(svc[name], config) self.d.configure(svc['name'], config)
def _configure_services(self, configs): def _configure_services(self, configs):
"""Configure all of the services.""" """Configure all of the services."""