Merged trunk in + LE charmhelper sync

This commit is contained in:
Liam Young 2015-05-11 08:28:22 +01:00
commit ec24411e0f
38 changed files with 929 additions and 128 deletions

View File

@ -1,2 +1,3 @@
.coverage
bin
tags

View File

@ -3,7 +3,7 @@ PYTHON := /usr/bin/env python
lint:
@echo "Running flake8 tests: "
@flake8 --exclude hooks/charmhelpers hooks unit_tests tests
@flake8 --exclude hooks/charmhelpers actions hooks unit_tests tests
@echo "OK"
@echo "Running charm proof: "
@charm proof
@ -26,8 +26,7 @@ test:
# /!\ 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
publish: lint unit_test
bzr push lp:charms/glance

View File

@ -81,6 +81,92 @@ as the endpoint for Glance).
Note that Glance in this configuration must be used with either Ceph or
Swift providing backing image storage.
Deploying from source
---------------------
The minimum openstack-origin-git config required to deploy from source is:
openstack-origin-git: include-file://glance-juno.yaml
glance-juno.yaml
repositories:
- {name: requirements,
repository: 'git://github.com/openstack/requirements',
branch: stable/juno}
- {name: glance,
repository: 'git://github.com/openstack/glance',
branch: stable/juno}
Note that there are only two 'name' values the charm knows about: 'requirements'
and 'glance'. These repositories must correspond to these 'name' values.
Additionally, the requirements repository must be specified first and the
glance repository must be specified last. All other repostories are installed
in the order in which they are specified.
The following is a full list of current tip repos (may not be up-to-date):
openstack-origin-git: include-file://glance-master.yaml
glance-master.yaml
repositories:
- {name: requirements,
repository: 'git://github.com/openstack/requirements',
branch: master}
- {name: oslo-concurrency,
repository: 'git://github.com/openstack/oslo.concurrency',
branch: master}
- {name: oslo-config,
repository: 'git://github.com/openstack/oslo.config',
branch: master}
- {name: oslo-db,
repository: 'git://github.com/openstack/oslo.db',
branch: master}
- {name: oslo-i18n,
repository: 'git://github.com/openstack/oslo.i18n',
branch: master}
- {name: oslo-messaging,
repository: 'git://github.com/openstack/oslo.messaging',
branch: master}
- {name: oslo-serialization,
repository: 'git://github.com/openstack/oslo.serialization',
branch: master}
- {name: oslo-utils,
repository: 'git://github.com/openstack/oslo.utils',
branch: master}
- {name: oslo-vmware,
repository: 'git://github.com/openstack/oslo.vmware',
branch: master}
- {name: osprofiler,
repository: 'git://github.com/stackforge/osprofiler',
branch: master}
- {name: pbr,
repository: 'git://github.com/openstack-dev/pbr',
branch: master}
- {name: python-keystoneclient,
repository: 'git://github.com/openstack/python-keystoneclient',
branch: master}
- {name: python-swiftclient,
repository: 'git://github.com/openstack/python-swiftclient',
branch: master}
- {name: sqlalchemy-migrate,
repository: 'git://github.com/stackforge/sqlalchemy-migrate',
branch: master}
- {name: stevedore,
repository: 'git://github.com/openstack/stevedore',
branch: master}
- {name: wsme,
repository: 'git://github.com/stackforge/wsme',
branch: master}
- {name: keystonemiddleware,
repository: 'git://github.com/openstack/keystonemiddleware',
branch: master}
- {name: glance-store,
repository: 'git://github.com/openstack/glance_store',
branch: master}
- {name: glance,
repository: 'git://github.com/openstack/glance',
branch: master}
Contact Information
-------------------

2
actions.yaml Normal file
View File

@ -0,0 +1,2 @@
git-reinstall:
description: Reinstall glance from the openstack-origin-git repositories.

1
actions/git-reinstall Symbolic link
View File

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

45
actions/git_reinstall.py Executable file
View File

@ -0,0 +1,45 @@
#!/usr/bin/python
import sys
import traceback
sys.path.append('hooks/')
from charmhelpers.contrib.openstack.utils import (
git_install_requested,
)
from charmhelpers.core.hookenv import (
action_set,
action_fail,
config,
)
from glance_utils import (
git_install,
)
from glance_relations import (
config_changed,
)
def git_reinstall():
"""Reinstall from source and restart services.
If the openstack-origin-git config option was used to install openstack
from source git repositories, then this action can be used to reinstall
from updated git repositories, followed by a restart of services."""
if not git_install_requested():
action_fail('openstack-origin-git is not configured')
return
try:
git_install(config('openstack-origin-git'))
config_changed()
except:
action_set({'traceback': traceback.format_exc()})
action_fail('git-reinstall resulted in an unexpected error')
if __name__ == '__main__':
git_reinstall()

View File

@ -14,6 +14,22 @@ options:
Note that updating this setting to a source that is known to
provide a later version of OpenStack will trigger a software
upgrade.
Note that when openstack-origin-git is specified, openstack
specific packages will be installed from source rather than
from the openstack-origin repository.
openstack-origin-git:
default:
type: string
description: |
Specifies a YAML-formatted dictionary listing the git
repositories and branches from which to install OpenStack and
its dependencies.
Note that the installed config files will be determined based on
the OpenStack release of the openstack-origin option.
For more details see README.md.
database-user:
default: glance
type: string

View File

@ -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))

View File

@ -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):

View File

@ -459,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 {}
@ -808,6 +813,19 @@ class NeutronContext(OSContextGenerator):
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):
driver = neutron_plugin_attribute(self.plugin, 'driver',
self.network_manager)
@ -891,6 +909,8 @@ class NeutronContext(OSContextGenerator):
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:

View File

@ -180,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':

View File

@ -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 -%}

View File

@ -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):
"""

View File

@ -20,11 +20,14 @@
# Authors:
# Charm Helpers Developers <juju@lists.ubuntu.com>
from __future__ import print_function
from functools import wraps
import os
import json
import yaml
import subprocess
import sys
import errno
from subprocess import CalledProcessError
import six
@ -56,12 +59,14 @@ def cached(func):
will cache the result of unit_get + 'test' for future calls.
"""
@wraps(func)
def wrapper(*args, **kwargs):
global cache
key = str((func, args, kwargs))
try:
return cache[key]
except KeyError:
pass # Drop out of the exception handler scope.
res = func(*args, **kwargs)
cache[key] = res
return res
@ -87,7 +92,18 @@ def log(message, level=None):
if not isinstance(message, six.string_types):
message = repr(message)
command += [message]
# 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):
@ -165,7 +181,7 @@ def local_unit():
def remote_unit():
"""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():
@ -237,6 +253,12 @@ class Config(dict):
except KeyError:
return (self._prev_dict or {})[key]
def get(self, key, default=None):
try:
return self[key]
except KeyError:
return default
def keys(self):
prev_keys = []
if self._prev_dict is not None:
@ -507,6 +529,11 @@ def unit_get(attribute):
return None
def unit_public_ip():
"""Get this unit's public IP address"""
return unit_get('public-address')
def unit_private_ip():
"""Get this unit's private IP address"""
return unit_get('private-address')
@ -664,3 +691,49 @@ def action_fail(message):
The results set by action_set are preserved."""
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'],
stderr=subprocess.STDOUT).decode('UTF-8')
except subprocess.CalledProcessError as e:
return 'unrecognized service' not in e.output
return b'unrecognized service' not in e.output
else:
return True

View File

@ -17,7 +17,7 @@
import os
import re
import json
from collections import Iterable
from collections import Iterable, OrderedDict
from charmhelpers.core import host
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 = None
self.services = {}
self.services = OrderedDict()
for service in services or []:
service_name = service['service']
self.services[service_name] = service

View File

@ -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)

View File

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

View File

@ -8,12 +8,13 @@ from subprocess import (
from glance_utils import (
do_openstack_upgrade,
git_install,
migrate_database,
register_configs,
restart_map,
services,
CLUSTER_RES,
PACKAGES,
determine_packages,
SERVICES,
CHARM,
GLANCE_REGISTRY_CONF,
@ -43,6 +44,7 @@ from charmhelpers.core.hookenv import (
from charmhelpers.core.host import (
restart_on_change,
service_reload,
service_restart,
service_stop,
)
from charmhelpers.fetch import (
@ -55,11 +57,13 @@ from charmhelpers.contrib.hahelpers.cluster import (
get_hacluster_config
)
from charmhelpers.contrib.openstack.utils import (
config_value_changed,
configure_installation_source,
get_os_codename_package,
openstack_upgrade_available,
git_install_requested,
lsb_release,
sync_db_with_multi_ipv6_addresses
openstack_upgrade_available,
os_release,
sync_db_with_multi_ipv6_addresses,
)
from charmhelpers.contrib.storage.linux.ceph import (
ensure_ceph_keyring,
@ -103,7 +107,9 @@ def install_hook():
configure_installation_source(src)
apt_update(fatal=True)
apt_install(PACKAGES, fatal=True)
apt_install(determine_packages(), fatal=True)
git_install(config('openstack-origin-git'))
for service in SERVICES:
service_stop(service)
@ -143,7 +149,7 @@ def pgsql_db_joined():
@hooks.hook('shared-db-relation-changed')
@restart_on_change(restart_map())
def db_changed():
rel = get_os_codename_package("glance-common")
rel = os_release('glance-common')
if 'shared-db' not in CONFIGS.complete_contexts():
juju_log('shared-db relation incomplete. Peer not ready?')
@ -159,9 +165,7 @@ 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('allowed_units')
if allowed_units and local_unit() not in allowed_units.split():
juju_log('Allowed_units list provided and this unit not present')
return
if allowed_units and local_unit() in allowed_units.split():
if rel == "essex":
status = call(['glance-manage', 'db_version'])
if status != 0:
@ -171,12 +175,15 @@ def db_changed():
juju_log('Cluster leader, performing db sync')
migrate_database()
else:
juju_log('allowed_units either not presented, or local unit '
'not in acl list: %s' % allowed_units)
@hooks.hook('pgsql-db-relation-changed')
@restart_on_change(restart_map())
def pgsql_db_changed():
rel = get_os_codename_package("glance-common")
rel = os_release('glance-common')
if 'pgsql-db' not in CONFIGS.complete_contexts():
juju_log('pgsql-db relation incomplete. Peer not ready?')
@ -259,6 +266,9 @@ def ceph_changed():
(rsp.exit_code, rsp.exit_msg), level=INFO)
CONFIGS.write(GLANCE_API_CONF)
CONFIGS.write(ceph_config_file())
# Ensure that glance-api is restarted since only now can we
# guarantee that ceph resources are ready.
service_restart('glance-api')
else:
rq = CephBrokerRq()
replicas = config('ceph-osd-replication-count')
@ -320,6 +330,10 @@ def config_changed():
sync_db_with_multi_ipv6_addresses(config('database'),
config('database-user'))
if git_install_requested():
if config_value_changed('openstack-origin-git'):
git_install(config('openstack-origin-git'))
else:
if openstack_upgrade_available('glance-common'):
juju_log('Upgrading OpenStack release')
do_openstack_upgrade(CONFIGS)
@ -366,7 +380,7 @@ def cluster_changed():
@hooks.hook('upgrade-charm')
@restart_on_change(restart_map(), stopstart=True)
def upgrade_charm():
apt_install(filter_installed_packages(PACKAGES), fatal=True)
apt_install(filter_installed_packages(determine_packages()), fatal=True)
configure_https()
update_nrpe_config()
CONFIGS.write_all()

View File

@ -1,6 +1,7 @@
#!/usr/bin/python
import os
import shutil
import subprocess
import glance_contexts
@ -14,16 +15,22 @@ from charmhelpers.fetch import (
add_source)
from charmhelpers.core.hookenv import (
charm_dir,
config,
log,
relation_ids,
service_name)
from charmhelpers.core.host import (
adduser,
add_group,
add_user_to_group,
mkdir,
service_stop,
service_start,
lsb_release
service_restart,
lsb_release,
write_file,
)
from charmhelpers.contrib.openstack import (
@ -37,8 +44,14 @@ from charmhelpers.contrib.hahelpers.cluster import (
from charmhelpers.contrib.openstack.alternatives import install_alternative
from charmhelpers.contrib.openstack.utils import (
get_os_codename_install_source,
get_os_codename_package,
configure_installation_source)
git_install_requested,
git_clone_and_install,
git_src_dir,
configure_installation_source,
os_release,
)
from charmhelpers.core.templating import render
from charmhelpers.core.decorators import (
retry_on_exception,
@ -50,8 +63,27 @@ PACKAGES = [
"apache2", "glance", "python-mysqldb", "python-swiftclient",
"python-psycopg2", "python-keystone", "python-six", "uuid", "haproxy", ]
BASE_GIT_PACKAGES = [
'libxml2-dev',
'libxslt1-dev',
'python-dev',
'python-pip',
'python-setuptools',
'zlib1g-dev',
]
SERVICES = [
"glance-api", "glance-registry", ]
"glance-api",
"glance-registry",
]
# ubuntu packages that should not be installed when deploying from git
GIT_PACKAGE_BLACKLIST = [
'glance',
'python-swiftclient',
'python-keystone',
]
CHARM = "glance"
@ -144,7 +176,7 @@ def register_configs():
# Register config files with their respective contexts.
# Regstration of some configs may not be required depending on
# existing of certain relations.
release = get_os_codename_package('glance-common', fatal=False) or 'essex'
release = os_release('glance-common')
configs = templating.OSConfigRenderer(templates_dir=TEMPLATES,
openstack_release=release)
@ -184,6 +216,18 @@ def register_configs():
# NOTE(jamespage): Retry deals with sync issues during one-shot HA deploys.
# mysql might be restarting or suchlike.
@retry_on_exception(5, base_delay=3, exc_type=subprocess.CalledProcessError)
def determine_packages():
packages = [] + PACKAGES
if git_install_requested():
packages.extend(BASE_GIT_PACKAGES)
# don't include packages that will be installed from git
for p in GIT_PACKAGE_BLACKLIST:
packages.remove(p)
return list(set(packages))
def migrate_database():
'''Runs glance-manage to initialize a new database
or migrate existing
@ -212,7 +256,7 @@ def do_openstack_upgrade(configs):
]
apt_update()
apt_upgrade(options=dpkg_opts, fatal=True, dist=True)
apt_install(PACKAGES, fatal=True)
apt_install(determine_packages(), fatal=True)
# set CONFIGS to load templates from new release and regenerate config
configs.set_release(openstack_release=new_os_rel)
@ -263,3 +307,85 @@ def setup_ipv6():
' main')
apt_update()
apt_install('haproxy/trusty-backports', fatal=True)
def git_install(projects_yaml):
"""Perform setup, and install git repos specified in yaml parameter."""
if git_install_requested():
git_pre_install()
git_clone_and_install(projects_yaml, core_project='glance')
git_post_install(projects_yaml)
def git_pre_install():
"""Perform glance pre-install setup."""
dirs = [
'/var/lib/glance',
'/var/lib/glance/images',
'/var/lib/glance/image-cache',
'/var/lib/glance/image-cache/incomplete',
'/var/lib/glance/image-cache/invalid',
'/var/lib/glance/image-cache/queue',
'/var/log/glance',
]
logs = [
'/var/log/glance/glance-api.log',
'/var/log/glance/glance-registry.log',
]
adduser('glance', shell='/bin/bash', system_user=True)
add_group('glance', system_group=True)
add_user_to_group('glance', 'glance')
for d in dirs:
mkdir(d, owner='glance', group='glance', perms=0755, force=False)
for l in logs:
write_file(l, '', owner='glance', group='glance', perms=0600)
def git_post_install(projects_yaml):
"""Perform glance post-install setup."""
src_etc = os.path.join(git_src_dir(projects_yaml, 'glance'), 'etc')
configs = {
'src': src_etc,
'dest': '/etc/glance',
}
if os.path.exists(configs['dest']):
shutil.rmtree(configs['dest'])
shutil.copytree(configs['src'], configs['dest'])
glance_api_context = {
'service_description': 'Glance API server',
'service_name': 'Glance',
'user_name': 'glance',
'start_dir': '/var/lib/glance',
'process_name': 'glance-api',
'executable_name': '/usr/local/bin/glance-api',
'config_files': ['/etc/glance/glance-api.conf'],
'log_file': '/var/log/glance/api.log',
}
glance_registry_context = {
'service_description': 'Glance registry server',
'service_name': 'Glance',
'user_name': 'glance',
'start_dir': '/var/lib/glance',
'process_name': 'glance-registry',
'executable_name': '/usr/local/bin/glance-registry',
'config_files': ['/etc/glance/glance-registry.conf'],
'log_file': '/var/log/glance/registry.log',
}
# NOTE(coreycb): Needs systemd support
templates_dir = 'hooks/charmhelpers/contrib/openstack/templates'
templates_dir = os.path.join(charm_dir(), templates_dir)
render('git.upstart', '/etc/init/glance-api.conf',
glance_api_context, perms=0o644, templates_dir=templates_dir)
render('git.upstart', '/etc/init/glance-registry.conf',
glance_registry_context, perms=0o644, templates_dir=templates_dir)
service_restart('glance-api')
service_restart('glance-registry')

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

@ -0,0 +1,11 @@
#!/usr/bin/python
"""Amulet tests on a basic Glance deployment on trusty-juno."""
from basic_deployment import GlanceBasicDeployment
if __name__ == '__main__':
deployment = GlanceBasicDeployment(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 glance deployment on trusty-kilo."""
from basic_deployment import GlanceBasicDeployment
if __name__ == '__main__':
deployment = GlanceBasicDeployment(series='trusty',
openstack='cloud:trusty-kilo',
source='cloud:trusty-updates/kilo')
deployment.run_tests()

View File

@ -1,9 +1,9 @@
#!/usr/bin/python
"""Amulet tests on a basic glance deployment on precise-essex."""
"""Amulet tests on a basic Glance deployment on utopic-juno."""
from basic_deployment import GlanceBasicDeployment
if __name__ == '__main__':
deployment = GlanceBasicDeployment(series='precise')
deployment = GlanceBasicDeployment(series='utopic')
deployment.run_tests()

View File

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

View File

@ -0,0 +1,9 @@
#!/usr/bin/python
"""Amulet tests on a basic Glance git deployment on trusty-icehouse."""
from basic_deployment import GlanceBasicDeployment
if __name__ == '__main__':
deployment = GlanceBasicDeployment(series='trusty', git=True)
deployment.run_tests()

12
tests/051-basic-trusty-juno-git Executable file
View File

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

View File

@ -1,11 +0,0 @@
#!/usr/bin/python
"""Amulet tests on a basic glance deployment on precise-folsom."""
from basic_deployment import GlanceBasicDeployment
if __name__ == '__main__':
deployment = GlanceBasicDeployment(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 glance deployment on precise-grizzly."""
from basic_deployment import GlanceBasicDeployment
if __name__ == '__main__':
deployment = GlanceBasicDeployment(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 glance deployment on precise-havana."""
from basic_deployment import GlanceBasicDeployment
if __name__ == '__main__':
deployment = GlanceBasicDeployment(series='precise',
openstack='cloud:precise-havana',
source='cloud:precise-updates/havana')
deployment.run_tests()

31
tests/basic_deployment.py Executable file → Normal file
View File

@ -1,6 +1,8 @@
#!/usr/bin/python
import amulet
import os
import yaml
from charmhelpers.contrib.openstack.amulet.deployment import (
OpenStackAmuletDeployment
@ -13,7 +15,7 @@ from charmhelpers.contrib.openstack.amulet.utils import (
)
# Use DEBUG to turn on debug logging
u = OpenStackAmuletUtils(ERROR)
u = OpenStackAmuletUtils(DEBUG)
class GlanceBasicDeployment(OpenStackAmuletDeployment):
'''Amulet tests on a basic file-backed glance deployment. Verify relations,
@ -23,9 +25,11 @@ class GlanceBasicDeployment(OpenStackAmuletDeployment):
# * Add tests with different storage back ends
# * Resolve Essex->Havana juju set charm bug
def __init__(self, series=None, openstack=None, source=None, stable=False):
def __init__(self, series=None, openstack=None, source=None, git=False,
stable=False):
'''Deploy the entire test environment.'''
super(GlanceBasicDeployment, self).__init__(series, openstack, source, stable)
self.git = git
self._add_services()
self._add_relations()
self._configure_services()
@ -55,11 +59,30 @@ class GlanceBasicDeployment(OpenStackAmuletDeployment):
def _configure_services(self):
'''Configure all of the services.'''
glance_config = {}
if self.git:
branch = 'stable/' + self._get_openstack_release_string()
amulet_http_proxy = os.environ.get('AMULET_HTTP_PROXY')
openstack_origin_git = {
'repositories': [
{'name': 'requirements',
'repository': 'git://git.openstack.org/openstack/requirements',
'branch': branch},
{'name': 'glance',
'repository': 'git://git.openstack.org/openstack/glance',
'branch': branch},
],
'directory': '/mnt/openstack-git',
'http_proxy': amulet_http_proxy,
'https_proxy': amulet_http_proxy,
}
glance_config['openstack-origin-git'] = yaml.dump(openstack_origin_git)
keystone_config = {'admin-password': 'openstack',
'admin-token': 'ubuntutesting'}
mysql_config = {'dataset-size': '50%'}
configs = {'keystone': keystone_config,
configs = {'glance': glance_config,
'keystone': keystone_config,
'mysql': mysql_config}
super(GlanceBasicDeployment, self)._configure_services(configs)

View File

@ -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):

View File

@ -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):

View File

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

View File

@ -0,0 +1,96 @@
from mock import patch
import os
os.environ['JUJU_UNIT_NAME'] = 'glance'
with patch('glance_utils.register_configs') as register_configs:
import git_reinstall
from test_utils import (
CharmTestCase
)
TO_PATCH = [
'config',
]
openstack_origin_git = \
"""repositories:
- {name: requirements,
repository: 'git://git.openstack.org/openstack/requirements',
branch: stable/juno}
- {name: glance,
repository: 'git://git.openstack.org/openstack/glance',
branch: stable/juno}"""
class TestGlanceActions(CharmTestCase):
def setUp(self):
super(TestGlanceActions, self).setUp(git_reinstall, TO_PATCH)
self.config.side_effect = self.test_config.get
@patch.object(git_reinstall, 'action_set')
@patch.object(git_reinstall, 'action_fail')
@patch.object(git_reinstall, 'git_install')
@patch.object(git_reinstall, 'config_changed')
@patch('charmhelpers.contrib.openstack.utils.config')
def test_git_reinstall(self, _config, config_changed, git_install,
action_fail, action_set):
_config.return_value = openstack_origin_git
self.test_config.set('openstack-origin-git', openstack_origin_git)
git_reinstall.git_reinstall()
git_install.assert_called_with(openstack_origin_git)
self.assertTrue(git_install.called)
self.assertTrue(config_changed.called)
self.assertFalse(action_set.called)
self.assertFalse(action_fail.called)
@patch.object(git_reinstall, 'action_set')
@patch.object(git_reinstall, 'action_fail')
@patch.object(git_reinstall, 'git_install')
@patch.object(git_reinstall, 'config_changed')
@patch('charmhelpers.contrib.openstack.utils.config')
def test_git_reinstall_not_configured(self, _config, config_changed,
git_install, action_fail,
action_set):
_config.return_value = None
git_reinstall.git_reinstall()
msg = 'openstack-origin-git is not configured'
action_fail.assert_called_with(msg)
self.assertFalse(git_install.called)
self.assertFalse(action_set.called)
@patch.object(git_reinstall, 'action_set')
@patch.object(git_reinstall, 'action_fail')
@patch.object(git_reinstall, 'git_install')
@patch.object(git_reinstall, 'config_changed')
@patch('traceback.format_exc')
@patch('charmhelpers.contrib.openstack.utils.config')
def test_git_reinstall_exception(self, _config, format_exc,
config_changed, git_install, action_fail,
action_set):
_config.return_value = openstack_origin_git
e = OSError('something bad happened')
git_install.side_effect = e
traceback = (
"Traceback (most recent call last):\n"
" File \"actions/git_reinstall.py\", line 37, in git_reinstall\n"
" git_install(config(\'openstack-origin-git\'))\n"
" File \"/usr/lib/python2.7/dist-packages/mock.py\", line 964, in __call__\n" # noqa
" return _mock_self._mock_call(*args, **kwargs)\n"
" File \"/usr/lib/python2.7/dist-packages/mock.py\", line 1019, in _mock_call\n" # noqa
" raise effect\n"
"OSError: something bad happened\n")
format_exc.return_value = traceback
git_reinstall.git_reinstall()
msg = 'git-reinstall resulted in an unexpected error'
action_fail.assert_called_with(msg)
action_set.assert_called_with({'traceback': traceback})

View File

@ -1,6 +1,7 @@
from mock import call, patch, MagicMock
import json
import os
import yaml
from test_utils import CharmTestCase
@ -42,7 +43,7 @@ TO_PATCH = [
'service_stop',
# charmhelpers.contrib.openstack.utils
'configure_installation_source',
'get_os_codename_package',
'os_release',
'openstack_upgrade_available',
# charmhelpers.contrib.hahelpers.cluster_utils
'is_elected_leader',
@ -53,6 +54,7 @@ TO_PATCH = [
'migrate_database',
'ensure_ceph_keyring',
'ceph_config_file',
'git_install',
'update_nrpe_config',
# other
'call',
@ -75,23 +77,26 @@ class GlanceRelationTests(CharmTestCase):
super(GlanceRelationTests, self).setUp(relations, TO_PATCH)
self.config.side_effect = self.test_config.get
def test_install_hook(self):
@patch.object(utils, 'git_install_requested')
def test_install_hook(self, git_requested):
git_requested.return_value = False
repo = 'cloud:precise-grizzly'
self.test_config.set('openstack-origin', repo)
self.service_stop.return_value = True
relations.install_hook()
self.configure_installation_source.assert_called_with(repo)
self.apt_update.assert_called_with(fatal=True)
self.apt_install.assert_called_with(['apache2', 'glance',
'python-mysqldb',
'python-swiftclient',
'python-psycopg2',
self.apt_install.assert_called_with(['haproxy', 'python-six', 'uuid',
'python-mysqldb', 'apache2',
'python-psycopg2', 'glance',
'python-keystone',
'python-six',
'uuid', 'haproxy'], fatal=True)
'python-swiftclient'], fatal=True)
self.assertTrue(self.execd_preinstall.called)
self.git_install.assert_called_with(None)
def test_install_hook_precise_distro(self):
@patch.object(utils, 'git_install_requested')
def test_install_hook_precise_distro(self, git_requested):
git_requested.return_value = False
self.test_config.set('openstack-origin', 'distro')
self.lsb_release.return_value = {'DISTRIB_RELEASE': 12.04,
'DISTRIB_CODENAME': 'precise'}
@ -101,6 +106,37 @@ class GlanceRelationTests(CharmTestCase):
"cloud:precise-folsom"
)
@patch.object(utils, 'git_install_requested')
def test_install_hook_git(self, git_requested):
git_requested.return_value = True
repo = 'cloud:trusty-juno'
openstack_origin_git = {
'repositories': [
{'name': 'requirements',
'repository': 'git://git.openstack.org/openstack/requirements', # noqa
'branch': 'stable/juno'},
{'name': 'glance',
'repository': 'git://git.openstack.org/openstack/glance',
'branch': 'stable/juno'}
],
'directory': '/mnt/openstack-git',
}
projects_yaml = yaml.dump(openstack_origin_git)
self.test_config.set('openstack-origin', repo)
self.test_config.set('openstack-origin-git', projects_yaml)
relations.install_hook()
self.assertTrue(self.execd_preinstall.called)
self.configure_installation_source.assert_called_with(repo)
self.apt_update.assert_called_with(fatal=True)
self.apt_install.assert_called_with(['haproxy', 'python-setuptools',
'python-six', 'uuid',
'python-mysqldb', 'python-pip',
'apache2', 'libxslt1-dev',
'python-psycopg2', 'zlib1g-dev',
'python-dev', 'libxml2-dev'],
fatal=True)
self.git_install.assert_called_with(projects_yaml)
def test_db_joined(self):
self.unit_get.return_value = 'glance.foohost.com'
self.is_relation_made.return_value = False
@ -171,8 +207,9 @@ class GlanceRelationTests(CharmTestCase):
'pgsql-db relation incomplete. Peer not ready?'
)
def _shared_db_test(self, configs, unit_name):
self.relation_get.return_value = 'glance/0 glance/3'
def _shared_db_test(self, configs, unit_name,
allowed_units='glance/0 glance/3'):
self.relation_get.return_value = allowed_units
self.local_unit.return_value = unit_name
configs.complete_contexts = MagicMock()
configs.complete_contexts.return_value = ['shared-db']
@ -204,6 +241,14 @@ class GlanceRelationTests(CharmTestCase):
configs.write.call_args_list)
self.assertFalse(self.migrate_database.called)
@patch.object(relations, 'CONFIGS')
def test_db_changed_no_acls(self, configs):
self._shared_db_test(configs, 'glance/2', None)
self.assertEquals([call('/etc/glance/glance-registry.conf'),
call('/etc/glance/glance-api.conf')],
configs.write.call_args_list)
self.assertFalse(self.migrate_database.called)
@patch.object(relations, 'CONFIGS')
def test_postgresql_db_changed_no_essex(self, configs):
self._postgresql_db_test(configs)
@ -217,7 +262,7 @@ class GlanceRelationTests(CharmTestCase):
@patch.object(relations, 'CONFIGS')
def test_db_changed_with_essex_not_setting_version_control(self, configs):
self.get_os_codename_package.return_value = "essex"
self.os_release.return_value = "essex"
self.call.return_value = 0
self._shared_db_test(configs, 'glance/0')
self.assertEquals([call('/etc/glance/glance-registry.conf')],
@ -230,7 +275,7 @@ class GlanceRelationTests(CharmTestCase):
@patch.object(relations, 'CONFIGS')
def test_postgresql_db_changed_with_essex_not_setting_version_control(
self, configs):
self.get_os_codename_package.return_value = "essex"
self.os_release.return_value = "essex"
self.call.return_value = 0
self._postgresql_db_test(configs)
self.assertEquals([call('/etc/glance/glance-registry.conf')],
@ -242,7 +287,7 @@ class GlanceRelationTests(CharmTestCase):
@patch.object(relations, 'CONFIGS')
def test_db_changed_with_essex_setting_version_control(self, configs):
self.get_os_codename_package.return_value = "essex"
self.os_release.return_value = "essex"
self.call.return_value = 1
self._shared_db_test(configs, 'glance/0')
self.assertEquals([call('/etc/glance/glance-registry.conf')],
@ -258,7 +303,7 @@ class GlanceRelationTests(CharmTestCase):
@patch.object(relations, 'CONFIGS')
def test_postgresql_db_changed_with_essex_setting_version_control(
self, configs):
self.get_os_codename_package.return_value = "essex"
self.os_release.return_value = "essex"
self.call.return_value = 1
self._postgresql_db_test(configs)
self.assertEquals([call('/etc/glance/glance-registry.conf')],
@ -442,8 +487,12 @@ class GlanceRelationTests(CharmTestCase):
@patch.object(relations, 'configure_https')
@patch.object(relations, 'object_store_joined')
@patch.object(relations, 'CONFIGS')
def test_keystone_changed_with_object_store_relation(
self, configs, object_store_joined, configure_https):
@patch.object(utils, 'git_install_requested')
def test_keystone_changed_with_object_store_relation(self, git_requested,
configs,
object_store_joined,
configure_https):
git_requested.return_value = False
configs.complete_contexts = MagicMock()
configs.complete_contexts.return_value = ['identity-service']
configs.write = MagicMock()
@ -458,14 +507,20 @@ class GlanceRelationTests(CharmTestCase):
self.assertTrue(configure_https.called)
@patch.object(relations, 'configure_https')
def test_config_changed_no_openstack_upgrade(self, configure_https):
@patch.object(relations, 'git_install_requested')
def test_config_changed_no_openstack_upgrade(self, git_requested,
configure_https):
git_requested.return_value = False
self.openstack_upgrade_available.return_value = False
relations.config_changed()
self.open_port.assert_called_with(9292)
self.assertTrue(configure_https.called)
@patch.object(relations, 'configure_https')
def test_config_changed_with_openstack_upgrade(self, configure_https):
@patch.object(relations, 'git_install_requested')
def test_config_changed_with_openstack_upgrade(self, git_requested,
configure_https):
git_requested.return_value = False
self.openstack_upgrade_available.return_value = True
relations.config_changed()
self.juju_log.assert_called_with(
@ -474,6 +529,32 @@ class GlanceRelationTests(CharmTestCase):
self.assertTrue(self.do_openstack_upgrade.called)
self.assertTrue(configure_https.called)
@patch.object(relations, 'configure_https')
@patch.object(relations, 'git_install_requested')
@patch.object(relations, 'config_value_changed')
def test_config_changed_git_updated(self, config_val_changed,
git_requested, configure_https):
git_requested.return_value = True
repo = 'cloud:trusty-juno'
openstack_origin_git = {
'repositories': [
{'name': 'requirements',
'repository': 'git://git.openstack.org/openstack/requirements', # noqa
'branch': 'stable/juno'},
{'name': 'glance',
'repository': 'git://git.openstack.org/openstack/glance',
'branch': 'stable/juno'}
],
'directory': '/mnt/openstack-git',
}
projects_yaml = yaml.dump(openstack_origin_git)
self.test_config.set('openstack-origin', repo)
self.test_config.set('openstack-origin-git', projects_yaml)
relations.config_changed()
self.git_install.assert_called_with(projects_yaml)
self.assertFalse(self.do_openstack_upgrade.called)
self.assertTrue(configure_https.called)
@patch.object(relations, 'CONFIGS')
def test_cluster_changed(self, configs):
self.test_config.set('prefer-ipv6', False)
@ -500,7 +581,9 @@ class GlanceRelationTests(CharmTestCase):
configs.write.call_args_list)
@patch.object(relations, 'CONFIGS')
def test_upgrade_charm(self, configs):
@patch.object(utils, 'git_install_requested')
def test_upgrade_charm(self, git_requested, configs):
git_requested.return_value = False
self.filter_installed_packages.return_value = ['test']
relations.upgrade_charm()
self.apt_install.assert_called_with(['test'], fatal=True)

View File

@ -14,7 +14,6 @@ TO_PATCH = [
'config',
'log',
'relation_ids',
'get_os_codename_package',
'get_os_codename_install_source',
'configure_installation_source',
'is_elected_leader',
@ -23,6 +22,7 @@ TO_PATCH = [
'apt_upgrade',
'apt_install',
'mkdir',
'os_release',
'service_start',
'service_stop',
'service_name',
@ -34,6 +34,15 @@ DPKG_OPTS = [
'--option', 'Dpkg::Options::=--force-confdef',
]
openstack_origin_git = \
"""repositories:
- {name: requirements,
repository: 'git://git.openstack.org/openstack/requirements',
branch: stable/juno}
- {name: glance,
repository: 'git://git.openstack.org/openstack/glance',
branch: stable/juno}"""
class TestGlanceUtils(CharmTestCase):
@ -50,7 +59,7 @@ class TestGlanceUtils(CharmTestCase):
@patch('os.path.exists')
def test_register_configs_apache(self, exists):
exists.return_value = False
self.get_os_codename_package.return_value = 'grizzly'
self.os_release.return_value = 'grizzly'
self.relation_ids.return_value = False
configs = utils.register_configs()
calls = []
@ -69,7 +78,7 @@ class TestGlanceUtils(CharmTestCase):
@patch('os.path.exists')
def test_register_configs_apache24(self, exists):
exists.return_value = True
self.get_os_codename_package.return_value = 'grizzly'
self.os_release.return_value = 'grizzly'
self.relation_ids.return_value = False
configs = utils.register_configs()
calls = []
@ -88,7 +97,7 @@ class TestGlanceUtils(CharmTestCase):
@patch('os.path.exists')
def test_register_configs_ceph(self, exists):
exists.return_value = True
self.get_os_codename_package.return_value = 'grizzly'
self.os_release.return_value = 'grizzly'
self.relation_ids.return_value = ['ceph:0']
self.service_name.return_value = 'glance'
configs = utils.register_configs()
@ -121,8 +130,26 @@ class TestGlanceUtils(CharmTestCase):
])
self.assertEquals(ex_map, utils.restart_map())
@patch('charmhelpers.contrib.openstack.utils.config')
def test_determine_packages(self, _config):
_config.return_value = None
result = utils.determine_packages()
ex = utils.PACKAGES
self.assertEquals(set(ex), set(result))
@patch('charmhelpers.contrib.openstack.utils.config')
def test_determine_packages_git(self, _config):
_config.return_value = openstack_origin_git
result = utils.determine_packages()
ex = utils.PACKAGES + utils.BASE_GIT_PACKAGES
for p in utils.GIT_PACKAGE_BLACKLIST:
ex.remove(p)
self.assertEquals(set(ex), set(result))
@patch.object(utils, 'migrate_database')
def test_openstack_upgrade_leader(self, migrate):
@patch.object(utils, 'git_install_requested')
def test_openstack_upgrade_leader(self, git_requested, migrate):
git_requested.return_value = True
self.config.side_effect = None
self.config.return_value = 'cloud:precise-havana'
self.is_elected_leader.return_value = True
@ -130,14 +157,17 @@ class TestGlanceUtils(CharmTestCase):
configs = MagicMock()
utils.do_openstack_upgrade(configs)
self.assertTrue(configs.write_all.called)
self.apt_install.assert_called_with(utils.PACKAGES, fatal=True)
self.apt_install.assert_called_with(utils.determine_packages(),
fatal=True)
self.apt_upgrade.assert_called_with(options=DPKG_OPTS,
fatal=True, dist=True)
configs.set_release.assert_called_with(openstack_release='havana')
self.assertTrue(migrate.called)
@patch.object(utils, 'migrate_database')
def test_openstack_upgrade_not_leader(self, migrate):
@patch.object(utils, 'git_install_requested')
def test_openstack_upgrade_not_leader(self, git_requested, migrate):
git_requested.return_value = True
self.config.side_effect = None
self.config.return_value = 'cloud:precise-havana'
self.is_elected_leader.return_value = False
@ -145,8 +175,111 @@ class TestGlanceUtils(CharmTestCase):
configs = MagicMock()
utils.do_openstack_upgrade(configs)
self.assertTrue(configs.write_all.called)
self.apt_install.assert_called_with(utils.PACKAGES, fatal=True)
self.apt_install.assert_called_with(utils.determine_packages(),
fatal=True)
self.apt_upgrade.assert_called_with(options=DPKG_OPTS,
fatal=True, dist=True)
configs.set_release.assert_called_with(openstack_release='havana')
self.assertFalse(migrate.called)
@patch.object(utils, 'git_install_requested')
@patch.object(utils, 'git_clone_and_install')
@patch.object(utils, 'git_post_install')
@patch.object(utils, 'git_pre_install')
def test_git_install(self, git_pre, git_post, git_clone_and_install,
git_requested):
projects_yaml = openstack_origin_git
git_requested.return_value = True
utils.git_install(projects_yaml)
self.assertTrue(git_pre.called)
git_clone_and_install.assert_called_with(openstack_origin_git,
core_project='glance')
self.assertTrue(git_post.called)
@patch.object(utils, 'mkdir')
@patch.object(utils, 'write_file')
@patch.object(utils, 'add_user_to_group')
@patch.object(utils, 'add_group')
@patch.object(utils, 'adduser')
def test_git_pre_install(self, adduser, add_group, add_user_to_group,
write_file, mkdir):
utils.git_pre_install()
adduser.assert_called_with('glance', shell='/bin/bash',
system_user=True)
add_group.assert_called_with('glance', system_group=True)
add_user_to_group.assert_called_with('glance', 'glance')
expected = [
call('/var/lib/glance', owner='glance',
group='glance', perms=0755, force=False),
call('/var/lib/glance/images', owner='glance',
group='glance', perms=0755, force=False),
call('/var/lib/glance/image-cache', owner='glance',
group='glance', perms=0755, force=False),
call('/var/lib/glance/image-cache/incomplete', owner='glance',
group='glance', perms=0755, force=False),
call('/var/lib/glance/image-cache/invalid', owner='glance',
group='glance', perms=0755, force=False),
call('/var/lib/glance/image-cache/queue', owner='glance',
group='glance', perms=0755, force=False),
call('/var/log/glance', owner='glance',
group='glance', perms=0755, force=False),
]
self.assertEquals(mkdir.call_args_list, expected)
expected = [
call('/var/log/glance/glance-api.log', '', owner='glance',
group='glance', perms=0600),
call('/var/log/glance/glance-registry.log', '', owner='glance',
group='glance', perms=0600),
]
self.assertEquals(write_file.call_args_list, expected)
@patch.object(utils, 'git_src_dir')
@patch.object(utils, 'service_restart')
@patch.object(utils, 'render')
@patch('os.path.join')
@patch('os.path.exists')
@patch('shutil.copytree')
@patch('shutil.rmtree')
def test_git_post_install(self, rmtree, copytree, exists, join, render,
service_restart, git_src_dir):
projects_yaml = openstack_origin_git
join.return_value = 'joined-string'
utils.git_post_install(projects_yaml)
expected = [
call('joined-string', '/etc/glance'),
]
copytree.assert_has_calls(expected)
glance_api_context = {
'service_description': 'Glance API server',
'service_name': 'Glance',
'user_name': 'glance',
'start_dir': '/var/lib/glance',
'process_name': 'glance-api',
'executable_name': '/usr/local/bin/glance-api',
'config_files': ['/etc/glance/glance-api.conf'],
'log_file': '/var/log/glance/api.log',
}
glance_registry_context = {
'service_description': 'Glance registry server',
'service_name': 'Glance',
'user_name': 'glance',
'start_dir': '/var/lib/glance',
'process_name': 'glance-registry',
'executable_name': '/usr/local/bin/glance-registry',
'config_files': ['/etc/glance/glance-registry.conf'],
'log_file': '/var/log/glance/registry.log',
}
expected = [
call('git.upstart', '/etc/init/glance-api.conf',
glance_api_context, perms=0o644,
templates_dir='joined-string'),
call('git.upstart', '/etc/init/glance-registry.conf',
glance_registry_context, perms=0o644,
templates_dir='joined-string'),
]
self.assertEquals(render.call_args_list, expected)
expected = [
call('glance-api'),
call('glance-registry'),
]
self.assertEquals(service_restart.call_args_list, expected)