Merged trunk in + LE charmhelper sync

This commit is contained in:
Liam Young
2015-05-11 09:04:17 +01:00
31 changed files with 294 additions and 89 deletions

View File

@@ -15,8 +15,7 @@ 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 --timeout 1200 \ @juju test -v -p AMULET_HTTP_PROXY,AMULET_OS_VIP --timeout 2700
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

@@ -79,6 +79,12 @@ options:
default: default:
description: | description: |
Base64 encoded SSL key to use with certificate specified as ssl_cert. Base64 encoded SSL key to use with certificate specified as ssl_cert.
ssl_ca:
type: string
default:
description: |
Base64 encoded SSL CA to use with the certificate and key provided - only
required if you are providing a privately signed ssl_cert and ssl_key.
# General Swift Proxy configuration # General Swift Proxy configuration
bind-port: bind-port:
default: 8080 default: 8080
@@ -116,6 +122,15 @@ options:
Timeouts from these requests can be recovered from so setting this to Timeouts from these requests can be recovered from so setting this to
something lower than node-timeout would provide quicker error recovery something lower than node-timeout would provide quicker error recovery
while allowing for a longer timeout for non-recoverable requests (PUTs). while allowing for a longer timeout for non-recoverable requests (PUTs).
# Logging configuration
debug:
default: False
type: boolean
description: Enable debug level logging.
log-headers:
default: False
type: boolean
description: Enable logging of all request headers.
# Manual Keystone configuration. # Manual Keystone configuration.
keystone-auth-host: keystone-auth-host:
type: string type: string

View File

@@ -247,7 +247,9 @@ class NRPE(object):
service('restart', 'nagios-nrpe-server') 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)) relation_set(relation_id=rid, monitors=yaml.dump(monitors))

View File

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

View File

@@ -459,6 +459,11 @@ class AMQPContext(OSContextGenerator):
ctxt['rabbitmq_hosts'] = ','.join(sorted(rabbitmq_hosts)) 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): if not context_complete(ctxt):
return {} return {}
@@ -808,6 +813,19 @@ class NeutronContext(OSContextGenerator):
return ovs_ctxt return ovs_ctxt
def nuage_ctxt(self):
driver = neutron_plugin_attribute(self.plugin, 'driver',
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}
return nuage_ctxt
def nvp_ctxt(self): def nvp_ctxt(self):
driver = neutron_plugin_attribute(self.plugin, 'driver', driver = neutron_plugin_attribute(self.plugin, 'driver',
self.network_manager) self.network_manager)
@@ -891,6 +909,8 @@ class NeutronContext(OSContextGenerator):
ctxt.update(self.n1kv_ctxt()) ctxt.update(self.n1kv_ctxt())
elif self.plugin == 'Calico': elif self.plugin == 'Calico':
ctxt.update(self.calico_ctxt()) ctxt.update(self.calico_ctxt())
elif self.plugin == 'vsp':
ctxt.update(self.nuage_ctxt())
alchemy_flags = config('neutron-alchemy-flags') alchemy_flags = config('neutron-alchemy-flags')
if alchemy_flags: if alchemy_flags:

View File

@@ -180,6 +180,19 @@ def neutron_plugins():
'nova-api-metadata']], 'nova-api-metadata']],
'server_packages': ['neutron-server', 'calico-control'], 'server_packages': ['neutron-server', 'calico-control'],
'server_services': ['neutron-server'] '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': if release >= 'icehouse':

View File

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

View File

@@ -510,8 +510,10 @@ def git_clone_and_install(projects_yaml, core_project):
repository: 'git://git.openstack.org/openstack/requirements.git', repository: 'git://git.openstack.org/openstack/requirements.git',
branch: 'stable/icehouse'} branch: 'stable/icehouse'}
directory: /mnt/openstack-git 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 global requirements_dir
parent_dir = '/mnt/openstack-git' parent_dir = '/mnt/openstack-git'
@@ -522,6 +524,13 @@ def git_clone_and_install(projects_yaml, core_project):
projects = yaml.load(projects_yaml) projects = yaml.load(projects_yaml)
_git_validate_projects_yaml(projects, core_project) _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(): if 'directory' in projects.keys():
parent_dir = projects['directory'] 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, repo_dir = _git_clone_and_install_single(repo, branch, parent_dir,
update_requirements=True) update_requirements=True)
os.environ = old_environ
def _git_validate_projects_yaml(projects, core_project): def _git_validate_projects_yaml(projects, core_project):
""" """

View File

@@ -175,6 +175,8 @@ def peer_retrieve_by_prefix(prefix, relation_name='cluster', delimiter='_',
exc_list = exc_list if exc_list else [] exc_list = exc_list if exc_list else []
peerdb_settings = peer_retrieve('-', relation_name=relation_name) peerdb_settings = peer_retrieve('-', relation_name=relation_name)
matched = {} matched = {}
if peerdb_settings is None:
return matched
for k, v in peerdb_settings.items(): for k, v in peerdb_settings.items():
full_prefix = prefix + delimiter full_prefix = prefix + delimiter
if k.startswith(full_prefix): if k.startswith(full_prefix):

View File

@@ -20,11 +20,14 @@
# Authors: # Authors:
# Charm Helpers Developers <juju@lists.ubuntu.com> # Charm Helpers Developers <juju@lists.ubuntu.com>
from __future__ import print_function
from functools import wraps
import os import os
import json import json
import yaml import yaml
import subprocess import subprocess
import sys import sys
import errno
from subprocess import CalledProcessError from subprocess import CalledProcessError
import six import six
@@ -56,12 +59,14 @@ def cached(func):
will cache the result of unit_get + 'test' for future calls. will cache the result of unit_get + 'test' for future calls.
""" """
@wraps(func)
def wrapper(*args, **kwargs): def wrapper(*args, **kwargs):
global cache global cache
key = str((func, args, kwargs)) key = str((func, args, kwargs))
try: try:
return cache[key] return cache[key]
except KeyError: except KeyError:
pass # Drop out of the exception handler scope.
res = func(*args, **kwargs) res = func(*args, **kwargs)
cache[key] = res cache[key] = res
return res return res
@@ -87,7 +92,18 @@ def log(message, level=None):
if not isinstance(message, six.string_types): if not isinstance(message, six.string_types):
message = repr(message) message = repr(message)
command += [message] command += [message]
# Missing juju-log should not cause failures in unit tests
# Send log output to stderr
try:
subprocess.call(command) 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): class Serializable(UserDict):
@@ -165,7 +181,7 @@ def local_unit():
def remote_unit(): def remote_unit():
"""The remote unit for the current relation hook""" """The remote unit for the current relation hook"""
return os.environ['JUJU_REMOTE_UNIT'] return os.environ.get('JUJU_REMOTE_UNIT', None)
def service_name(): def service_name():
@@ -237,6 +253,12 @@ class Config(dict):
except KeyError: except KeyError:
return (self._prev_dict or {})[key] return (self._prev_dict or {})[key]
def get(self, key, default=None):
try:
return self[key]
except KeyError:
return default
def keys(self): def keys(self):
prev_keys = [] prev_keys = []
if self._prev_dict is not None: if self._prev_dict is not None:
@@ -507,6 +529,11 @@ def unit_get(attribute):
return None return None
def unit_public_ip():
"""Get this unit's public IP address"""
return unit_get('public-address')
def unit_private_ip(): def unit_private_ip():
"""Get this unit's private IP address""" """Get this unit's private IP address"""
return unit_get('private-address') return unit_get('private-address')
@@ -664,3 +691,49 @@ def action_fail(message):
The results set by action_set are preserved.""" The results set by action_set are preserved."""
subprocess.check_call(['action-fail', message]) subprocess.check_call(['action-fail', message])
def status_set(workload_state, message):
"""Set the workload state with a message
Use status-set to set the workload state with a message which is visible
to the user via juju status. If the status-set command is not found then
assume this is juju < 1.23 and juju-log the message unstead.
workload_state -- valid juju workload state.
message -- status update message
"""
valid_states = ['maintenance', 'blocked', 'waiting', 'active']
if workload_state not in valid_states:
raise ValueError(
'{!r} is not a valid workload state'.format(workload_state)
)
cmd = ['status-set', workload_state, message]
try:
ret = subprocess.call(cmd)
if ret == 0:
return
except OSError as e:
if e.errno != errno.ENOENT:
raise
log_message = 'status-set failed: {} {}'.format(workload_state,
message)
log(log_message, level='INFO')
def status_get():
"""Retrieve the previously set juju workload state
If the status-set command is not found then assume this is juju < 1.23 and
return 'unknown'
"""
cmd = ['status-get']
try:
raw_status = subprocess.check_output(cmd, universal_newlines=True)
status = raw_status.rstrip()
return status
except OSError as e:
if e.errno == errno.ENOENT:
return 'unknown'
else:
raise

View File

@@ -90,7 +90,7 @@ def service_available(service_name):
['service', service_name, 'status'], ['service', service_name, 'status'],
stderr=subprocess.STDOUT).decode('UTF-8') stderr=subprocess.STDOUT).decode('UTF-8')
except subprocess.CalledProcessError as e: except subprocess.CalledProcessError as e:
return 'unrecognized service' not in e.output return b'unrecognized service' not in e.output
else: else:
return True return True

View File

@@ -17,7 +17,7 @@
import os import os
import re import re
import json import json
from collections import Iterable from collections import Iterable, OrderedDict
from charmhelpers.core import host from charmhelpers.core import host
from charmhelpers.core import hookenv from charmhelpers.core import hookenv
@@ -119,7 +119,7 @@ class ServiceManager(object):
""" """
self._ready_file = os.path.join(hookenv.charm_dir(), 'READY-SERVICES.json') self._ready_file = os.path.join(hookenv.charm_dir(), 'READY-SERVICES.json')
self._ready = None self._ready = None
self.services = {} self.services = OrderedDict()
for service in services or []: for service in services or []:
service_name = service['service'] service_name = service['service']
self.services[service_name] = service self.services[service_name] = service

View File

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

View File

@@ -158,7 +158,7 @@ def filter_installed_packages(packages):
def apt_cache(in_memory=True): def apt_cache(in_memory=True):
"""Build and return an apt cache""" """Build and return an apt cache"""
import apt_pkg from apt import apt_pkg
apt_pkg.init() apt_pkg.init()
if in_memory: if in_memory:
apt_pkg.config.set("Dir::Cache::pkgcache", "") apt_pkg.config.set("Dir::Cache::pkgcache", "")

View File

@@ -100,8 +100,14 @@ class SwiftIdentityContext(OSContextGenerator):
'delay_auth_decision': config('delay-auth-decision'), 'delay_auth_decision': config('delay-auth-decision'),
'node_timeout': config('node-timeout'), 'node_timeout': config('node-timeout'),
'recoverable_node_timeout': config('recoverable-node-timeout'), 'recoverable_node_timeout': config('recoverable-node-timeout'),
'log_headers': config('log-headers')
} }
if config('debug'):
ctxt['log_level'] = 'DEBUG'
else:
ctxt['log_level'] = 'INFO'
# Instead of duplicating code lets use charm-helpers to set signing_dir # Instead of duplicating code lets use charm-helpers to set signing_dir
# TODO(hopem): refactor this context handler to use charm-helpers # TODO(hopem): refactor this context handler to use charm-helpers
# code. # code.

View File

@@ -82,7 +82,6 @@ from charmhelpers.contrib.network.ip import (
format_ipv6_addr, format_ipv6_addr,
) )
from charmhelpers.contrib.openstack.context import ADDRESS_TYPES from charmhelpers.contrib.openstack.context import ADDRESS_TYPES
from charmhelpers.contrib.charmsupport import nrpe from charmhelpers.contrib.charmsupport import nrpe
extra_pkgs = [ extra_pkgs = [
@@ -147,22 +146,18 @@ def config_changed():
@hooks.hook('identity-service-relation-joined') @hooks.hook('identity-service-relation-joined')
def keystone_joined(relid=None): def keystone_joined(relid=None):
if not is_elected_leader(SWIFT_HA_RES):
return
port = config('bind-port') port = config('bind-port')
admin_url = '%s:%s' % (canonical_url(CONFIGS, ADMIN), port) admin_url = '%s:%s' % (canonical_url(CONFIGS, ADMIN), port)
internal_url = '%s:%s/v1/AUTH_$(tenant_id)s' % \ internal_url = ('%s:%s/v1/AUTH_$(tenant_id)s' %
(canonical_url(CONFIGS, INTERNAL), port) (canonical_url(CONFIGS, INTERNAL), port))
public_url = '%s:%s/v1/AUTH_$(tenant_id)s' % \ public_url = ('%s:%s/v1/AUTH_$(tenant_id)s' %
(canonical_url(CONFIGS, PUBLIC), port) (canonical_url(CONFIGS, PUBLIC), port))
relation_set(service='swift', region = config('region')
region=config('region'), roles = config('operator-roles')
public_url=public_url,
internal_url=internal_url, relation_set(service='swift', region=region, public_url=public_url,
admin_url=admin_url, internal_url=internal_url, admin_url=admin_url,
requested_roles=config('operator-roles'), requested_roles=roles, relation_id=relid)
relation_id=relid)
@hooks.hook('identity-service-relation-changed') @hooks.hook('identity-service-relation-changed')

View File

@@ -3,6 +3,12 @@ bind_port = {{ bind_port }}
workers = {{ workers }} workers = {{ workers }}
user = swift user = swift
bind_ip = {{ bind_host }} bind_ip = {{ bind_host }}
log_name = swift
log_facility = LOG_LOCAL0
log_level = {{ log_level }}
log_address = /dev/log
log_headers = {{ log_headers }}
{% if ssl %} {% if ssl %}
cert_file = {{ ssl_cert }} cert_file = {{ ssl_cert }}
key_file = {{ ssl_key }} key_file = {{ ssl_key }}
@@ -10,10 +16,10 @@ key_file = {{ ssl_key }}
{% if auth_type == 'keystone' %} {% if auth_type == 'keystone' %}
[pipeline:main] [pipeline:main]
pipeline = gatekeeper healthcheck cache swift3 s3token container_sync bulk tempurl slo dlo formpost authtoken keystoneauth staticweb container-quotas account-quotas proxy-server pipeline = gatekeeper healthcheck proxy-logging cache swift3 s3token container_sync bulk tempurl slo dlo formpost authtoken keystoneauth staticweb container-quotas account-quotas proxy-logging proxy-server
{% else %} {% else %}
[pipeline:main] [pipeline:main]
pipeline = gatekeeper healthcheck cache container_sync bulk tempurl slo dlo formpost tempauth staticweb container-quotas account-quotas proxy-server pipeline = gatekeeper healthcheck proxy-logging cache container_sync bulk tempurl slo dlo formpost tempauth staticweb container-quotas account-quotas proxy-logging proxy-server
{% endif %} {% endif %}
[app:proxy-server] [app:proxy-server]
@@ -40,6 +46,9 @@ use = egg:swift#account_quotas
[filter:container-quotas] [filter:container-quotas]
use = egg:swift#container_quotas use = egg:swift#container_quotas
[filter:proxy-logging]
use = egg:swift#proxy_logging
[filter:staticweb] [filter:staticweb]
use = egg:swift#staticweb use = egg:swift#staticweb

View File

@@ -3,6 +3,12 @@ bind_port = {{ bind_port }}
workers = {{ workers }} workers = {{ workers }}
user = swift user = swift
bind_ip = {{ bind_host }} bind_ip = {{ bind_host }}
log_name = swift
log_facility = LOG_LOCAL0
log_level = {{ log_level }}
log_address = /dev/log
log_headers = {{ log_headers }}
{% if ssl %} {% if ssl %}
cert_file = {{ ssl_cert }} cert_file = {{ ssl_cert }}
key_file = {{ ssl_key }} key_file = {{ ssl_key }}
@@ -10,10 +16,10 @@ key_file = {{ ssl_key }}
{% if auth_type == 'keystone' %} {% if auth_type == 'keystone' %}
[pipeline:main] [pipeline:main]
pipeline = gatekeeper healthcheck cache swift3 s3token container_sync bulk tempurl slo dlo formpost authtoken keystoneauth staticweb container-quotas account-quotas proxy-server pipeline = gatekeeper healthcheck proxy-logging cache swift3 s3token container_sync bulk tempurl slo dlo formpost authtoken keystoneauth staticweb container-quotas account-quotas proxy-logging proxy-server
{% else %} {% else %}
[pipeline:main] [pipeline:main]
pipeline = gatekeeper healthcheck cache container_sync bulk tempurl slo dlo formpost tempauth staticweb container-quotas account-quotas proxy-server pipeline = gatekeeper healthcheck proxy-logging cache container_sync bulk tempurl slo dlo formpost tempauth staticweb container-quotas account-quotas proxy-logging proxy-server
{% endif %} {% endif %}
[app:proxy-server] [app:proxy-server]
@@ -40,6 +46,9 @@ use = egg:swift#account_quotas
[filter:container-quotas] [filter:container-quotas]
use = egg:swift#container_quotas use = egg:swift#container_quotas
[filter:proxy-logging]
use = egg:swift#proxy_logging
[filter:staticweb] [filter:staticweb]
use = egg:swift#staticweb use = egg:swift#staticweb

11
tests/016-basic-trusty-juno Executable file
View File

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

View File

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

9
tests/018-basic-utopic-juno Executable file
View File

@@ -0,0 +1,9 @@
#!/usr/bin/python
"""Amulet tests on a basic swift-proxy deployment on utopic-juno."""
from basic_deployment import SwiftProxyBasicDeployment
if __name__ == '__main__':
deployment = SwiftProxyBasicDeployment(series='utopic')
deployment.run_tests()

View File

@@ -0,0 +1,9 @@
#!/usr/bin/python
"""Amulet tests on a basic swift-proxy deployment on vivid-kilo."""
from basic_deployment import SwiftProxyBasicDeployment
if __name__ == '__main__':
deployment = SwiftProxyBasicDeployment(series='vivid')
deployment.run_tests()

View File

@@ -1,11 +0,0 @@
#!/usr/bin/python
"""Amulet tests on a basic swift-proxy deployment on precise-folsom."""
from basic_deployment import SwiftProxyBasicDeployment
if __name__ == '__main__':
deployment = SwiftProxyBasicDeployment(series='precise',
openstack='cloud:precise-folsom',
source='cloud:precise-updates/folsom')
deployment.run_tests()

View File

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

View File

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

View File

@@ -14,7 +14,7 @@ from charmhelpers.contrib.openstack.amulet.utils import (
) )
# Use DEBUG to turn on debug logging # Use DEBUG to turn on debug logging
u = OpenStackAmuletUtils(ERROR) u = OpenStackAmuletUtils(DEBUG)
class SwiftProxyBasicDeployment(OpenStackAmuletDeployment): class SwiftProxyBasicDeployment(OpenStackAmuletDeployment):
@@ -368,13 +368,19 @@ class SwiftProxyBasicDeployment(OpenStackAmuletDeployment):
expected = { expected = {
'DEFAULT': { 'DEFAULT': {
'bind_port': '8070', 'bind_port': '8070',
'user': 'swift' 'user': 'swift',
'log_name': 'swift',
'log_facility': 'LOG_LOCAL0',
'log_level': 'INFO',
'log_headers': 'False',
'log_address': '/dev/log'
}, },
'pipeline:main': { 'pipeline:main': {
'pipeline': 'gatekeeper healthcheck cache swift3 s3token ' 'pipeline': 'gatekeeper healthcheck proxy-logging cache swift3 '
'container_sync bulk tempurl slo dlo formpost ' 's3token container_sync bulk tempurl slo dlo '
'authtoken keystoneauth staticweb ' 'formpost authtoken keystoneauth staticweb '
'container-quotas account-quotas proxy-server' 'container-quotas account-quotas proxy-logging '
'proxy-server'
}, },
'app:proxy-server': { 'app:proxy-server': {
'use': 'egg:swift#proxy', 'use': 'egg:swift#proxy',
@@ -395,6 +401,7 @@ class SwiftProxyBasicDeployment(OpenStackAmuletDeployment):
}, },
'filter:account-quotas': {'use': 'egg:swift#account_quotas'}, 'filter:account-quotas': {'use': 'egg:swift#account_quotas'},
'filter:container-quotas': {'use': 'egg:swift#container_quotas'}, 'filter:container-quotas': {'use': 'egg:swift#container_quotas'},
'filter:proxy-logging': {'use': 'egg:swift#proxy_logging'},
'filter:staticweb': {'use': 'egg:swift#staticweb'}, 'filter:staticweb': {'use': 'egg:swift#staticweb'},
'filter:bulk': {'use': 'egg:swift#bulk'}, 'filter:bulk': {'use': 'egg:swift#bulk'},
'filter:slo': {'use': 'egg:swift#slo'}, 'filter:slo': {'use': 'egg:swift#slo'},

View File

@@ -79,6 +79,9 @@ class AmuletUtils(object):
for k, v in six.iteritems(commands): for k, v in six.iteritems(commands):
for cmd in v: for cmd in v:
output, code = k.run(cmd) output, code = k.run(cmd)
self.log.debug('{} `{}` returned '
'{}'.format(k.info['unit_name'],
cmd, code))
if code != 0: if code != 0:
return "command `{}` returned {}".format(cmd, str(code)) return "command `{}` returned {}".format(cmd, str(code))
return None return None
@@ -86,7 +89,11 @@ class AmuletUtils(object):
def _get_config(self, unit, filename): def _get_config(self, unit, filename):
"""Get a ConfigParser object for parsing a unit's config file.""" """Get a ConfigParser object for parsing a unit's config file."""
file_contents = unit.file_contents(filename) 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)) config.readfp(io.StringIO(file_contents))
return config return config
@@ -118,6 +125,9 @@ class AmuletUtils(object):
longs, or can be a function that evaluate a variable and returns a longs, or can be a function that evaluate a variable and returns a
bool. bool.
""" """
self.log.debug('actual: {}'.format(repr(actual)))
self.log.debug('expected: {}'.format(repr(expected)))
for k, v in six.iteritems(expected): for k, v in six.iteritems(expected):
if k in actual: if k in actual:
if (isinstance(v, six.string_types) or if (isinstance(v, six.string_types) or
@@ -134,7 +144,6 @@ class AmuletUtils(object):
def validate_relation_data(self, sentry_unit, relation, expected): def validate_relation_data(self, sentry_unit, relation, expected):
"""Validate actual relation data based on expected relation data.""" """Validate actual relation data based on expected relation data."""
actual = sentry_unit.relation(relation[0], relation[1]) actual = sentry_unit.relation(relation[0], relation[1])
self.log.debug('actual: {}'.format(repr(actual)))
return self._validate_dict_data(expected, actual) return self._validate_dict_data(expected, actual)
def _validate_list_data(self, expected, actual): def _validate_list_data(self, expected, actual):

View File

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