Workload Status

This commit is contained in:
David Ames 2015-09-25 15:12:01 -07:00
parent 0d6ad4872a
commit 783d5ccc85
5 changed files with 125 additions and 3 deletions

View File

@ -18,7 +18,7 @@ import os
import six import six
from charmhelpers.fetch import apt_install from charmhelpers.fetch import apt_install, apt_update
from charmhelpers.core.hookenv import ( from charmhelpers.core.hookenv import (
log, log,
ERROR, ERROR,
@ -29,6 +29,7 @@ from charmhelpers.contrib.openstack.utils import OPENSTACK_CODENAMES
try: try:
from jinja2 import FileSystemLoader, ChoiceLoader, Environment, exceptions from jinja2 import FileSystemLoader, ChoiceLoader, Environment, exceptions
except ImportError: except ImportError:
apt_update(fatal=True)
apt_install('python-jinja2', fatal=True) apt_install('python-jinja2', fatal=True)
from jinja2 import FileSystemLoader, ChoiceLoader, Environment, exceptions from jinja2 import FileSystemLoader, ChoiceLoader, Environment, exceptions

View File

@ -25,6 +25,7 @@ import sys
import re import re
import six import six
import traceback
import yaml import yaml
from charmhelpers.contrib.network import ip from charmhelpers.contrib.network import ip
@ -34,6 +35,8 @@ from charmhelpers.core import (
) )
from charmhelpers.core.hookenv import ( from charmhelpers.core.hookenv import (
action_fail,
action_set,
config, config,
log as juju_log, log as juju_log,
charm_dir, charm_dir,
@ -51,7 +54,8 @@ from charmhelpers.contrib.storage.linux.lvm import (
) )
from charmhelpers.contrib.network.ip import ( from charmhelpers.contrib.network.ip import (
get_ipv6_addr get_ipv6_addr,
is_ipv6,
) )
from charmhelpers.contrib.python.packages import ( from charmhelpers.contrib.python.packages import (
@ -516,6 +520,12 @@ def sync_db_with_multi_ipv6_addresses(database, database_user,
relation_prefix=None): relation_prefix=None):
hosts = get_ipv6_addr(dynamic_only=False) hosts = get_ipv6_addr(dynamic_only=False)
if config('vip'):
vips = config('vip').split()
for vip in vips:
if vip and is_ipv6(vip):
hosts.append(vip)
kwargs = {'database': database, kwargs = {'database': database,
'username': database_user, 'username': database_user,
'hostname': json.dumps(hosts)} 'hostname': json.dumps(hosts)}
@ -921,3 +931,47 @@ def incomplete_relation_data(configs, required_interfaces):
for i in incomplete_relations: for i in incomplete_relations:
incomplete_context_data[i] = configs.get_incomplete_context_data(required_interfaces[i]) incomplete_context_data[i] = configs.get_incomplete_context_data(required_interfaces[i])
return incomplete_context_data return incomplete_context_data
def do_action_openstack_upgrade(package, upgrade_callback, configs):
"""Perform action-managed OpenStack upgrade.
Upgrades packages to the configured openstack-origin version and sets
the corresponding action status as a result.
If the charm was installed from source we cannot upgrade it.
For backwards compatibility a config flag (action-managed-upgrade) must
be set for this code to run, otherwise a full service level upgrade will
fire on config-changed.
@param package: package name for determining if upgrade available
@param upgrade_callback: function callback to charm's upgrade function
@param configs: templating object derived from OSConfigRenderer class
@return: True if upgrade successful; False if upgrade failed or skipped
"""
ret = False
if git_install_requested():
action_set({'outcome': 'installed from source, skipped upgrade.'})
else:
if openstack_upgrade_available(package):
if config('action-managed-upgrade'):
juju_log('Upgrading OpenStack release')
try:
upgrade_callback(configs=configs)
action_set({'outcome': 'success, upgrade completed.'})
ret = True
except:
action_set({'outcome': 'upgrade failed, see traceback.'})
action_set({'traceback': traceback.format_exc()})
action_fail('do_openstack_upgrade resulted in an '
'unexpected error')
else:
action_set({'outcome': 'action-managed-upgrade config is '
'False, skipped upgrade.'})
else:
action_set({'outcome': 'no upgrade available.'})
return ret

View File

@ -13,6 +13,7 @@ from charmhelpers.core.hookenv import (
service_name, service_name,
unit_get, unit_get,
UnregisteredHookError, UnregisteredHookError,
status_set,
) )
from charmhelpers.core.host import ( from charmhelpers.core.host import (
restart_on_change, restart_on_change,
@ -32,6 +33,7 @@ from charmhelpers.contrib.openstack.utils import (
git_install_requested, git_install_requested,
openstack_upgrade_available, openstack_upgrade_available,
os_requires_version, os_requires_version,
os_workload_status,
) )
from charmhelpers.contrib.storage.linux.ceph import ( from charmhelpers.contrib.storage.linux.ceph import (
@ -66,6 +68,8 @@ from nova_compute_utils import (
assert_charm_supports_ipv6, assert_charm_supports_ipv6,
manage_ovs, manage_ovs,
install_hugepages, install_hugepages,
REQUIRED_INTERFACES,
check_optional_relations,
) )
from charmhelpers.contrib.network.ip import ( from charmhelpers.contrib.network.ip import (
@ -86,28 +90,38 @@ CONFIGS = register_configs()
@hooks.hook('install.real') @hooks.hook('install.real')
@os_workload_status(CONFIGS, REQUIRED_INTERFACES,
charm_func=check_optional_relations)
def install(): def install():
status_set('maintenance', 'Executing pre-install')
execd_preinstall() execd_preinstall()
configure_installation_source(config('openstack-origin')) configure_installation_source(config('openstack-origin'))
status_set('maintenance', 'Installing apt packages')
apt_update() apt_update()
apt_install(determine_packages(), fatal=True) apt_install(determine_packages(), fatal=True)
status_set('maintenance', 'Git install')
git_install(config('openstack-origin-git')) git_install(config('openstack-origin-git'))
@hooks.hook('config-changed') @hooks.hook('config-changed')
@os_workload_status(CONFIGS, REQUIRED_INTERFACES,
charm_func=check_optional_relations)
@restart_on_change(restart_map()) @restart_on_change(restart_map())
def config_changed(): def config_changed():
if config('prefer-ipv6'): if config('prefer-ipv6'):
status_set('maintenance', 'configuring ipv6')
assert_charm_supports_ipv6() assert_charm_supports_ipv6()
global CONFIGS global CONFIGS
if git_install_requested(): if git_install_requested():
if config_value_changed('openstack-origin-git'): if config_value_changed('openstack-origin-git'):
status_set('maintenance', 'Running Git install')
git_install(config('openstack-origin-git')) git_install(config('openstack-origin-git'))
else: else:
if openstack_upgrade_available('nova-common'): if openstack_upgrade_available('nova-common'):
status_set('maintenance', 'Running openstack upgrade')
CONFIGS = do_openstack_upgrade() CONFIGS = do_openstack_upgrade()
sysctl_dict = config('sysctl') sysctl_dict = config('sysctl')
@ -117,11 +131,13 @@ def config_changed():
if migration_enabled() and config('migration-auth-type') == 'ssh': if migration_enabled() and config('migration-auth-type') == 'ssh':
# Check-in with nova-c-c and register new ssh key, if it has just been # Check-in with nova-c-c and register new ssh key, if it has just been
# generated. # generated.
status_set('maintenance', 'SSH key exchange')
initialize_ssh_keys() initialize_ssh_keys()
import_authorized_keys() import_authorized_keys()
if config('enable-resize') is True: if config('enable-resize') is True:
enable_shell(user='nova') enable_shell(user='nova')
status_set('maintenance', 'SSH key exchange')
initialize_ssh_keys(user='nova') initialize_ssh_keys(user='nova')
import_authorized_keys(user='nova', prefix='nova') import_authorized_keys(user='nova', prefix='nova')
else: else:
@ -132,6 +148,7 @@ def config_changed():
fix_path_ownership(fp, user='nova') fix_path_ownership(fp, user='nova')
if config('virt-type').lower() == 'lxd': if config('virt-type').lower() == 'lxd':
status_set('maintenance', 'Configure LXD')
configure_lxd(user='nova') configure_lxd(user='nova')
[compute_joined(rid) for rid in relation_ids('cloud-compute')] [compute_joined(rid) for rid in relation_ids('cloud-compute')]
@ -148,6 +165,8 @@ def config_changed():
@hooks.hook('amqp-relation-joined') @hooks.hook('amqp-relation-joined')
@os_workload_status(CONFIGS, REQUIRED_INTERFACES,
charm_func=check_optional_relations)
def amqp_joined(relation_id=None): def amqp_joined(relation_id=None):
relation_set(relation_id=relation_id, relation_set(relation_id=relation_id,
username=config('rabbit-user'), username=config('rabbit-user'),
@ -156,6 +175,8 @@ def amqp_joined(relation_id=None):
@hooks.hook('amqp-relation-changed') @hooks.hook('amqp-relation-changed')
@hooks.hook('amqp-relation-departed') @hooks.hook('amqp-relation-departed')
@os_workload_status(CONFIGS, REQUIRED_INTERFACES,
charm_func=check_optional_relations)
@restart_on_change(restart_map()) @restart_on_change(restart_map())
def amqp_changed(): def amqp_changed():
if 'amqp' not in CONFIGS.complete_contexts(): if 'amqp' not in CONFIGS.complete_contexts():
@ -171,6 +192,8 @@ def amqp_changed():
@hooks.hook('shared-db-relation-joined') @hooks.hook('shared-db-relation-joined')
@os_workload_status(CONFIGS, REQUIRED_INTERFACES,
charm_func=check_optional_relations)
def db_joined(rid=None): def db_joined(rid=None):
if is_relation_made('pgsql-db'): if is_relation_made('pgsql-db'):
# error, postgresql is used # error, postgresql is used
@ -186,6 +209,8 @@ def db_joined(rid=None):
@hooks.hook('pgsql-db-relation-joined') @hooks.hook('pgsql-db-relation-joined')
@os_workload_status(CONFIGS, REQUIRED_INTERFACES,
charm_func=check_optional_relations)
def pgsql_db_joined(): def pgsql_db_joined():
if is_relation_made('shared-db'): if is_relation_made('shared-db'):
# raise error # raise error
@ -198,6 +223,8 @@ def pgsql_db_joined():
@hooks.hook('shared-db-relation-changed') @hooks.hook('shared-db-relation-changed')
@os_workload_status(CONFIGS, REQUIRED_INTERFACES,
charm_func=check_optional_relations)
@restart_on_change(restart_map()) @restart_on_change(restart_map())
def db_changed(): def db_changed():
if 'shared-db' not in CONFIGS.complete_contexts(): if 'shared-db' not in CONFIGS.complete_contexts():
@ -207,6 +234,8 @@ def db_changed():
@hooks.hook('pgsql-db-relation-changed') @hooks.hook('pgsql-db-relation-changed')
@os_workload_status(CONFIGS, REQUIRED_INTERFACES,
charm_func=check_optional_relations)
@restart_on_change(restart_map()) @restart_on_change(restart_map())
def postgresql_db_changed(): def postgresql_db_changed():
if 'pgsql-db' not in CONFIGS.complete_contexts(): if 'pgsql-db' not in CONFIGS.complete_contexts():
@ -216,6 +245,8 @@ def postgresql_db_changed():
@hooks.hook('image-service-relation-changed') @hooks.hook('image-service-relation-changed')
@os_workload_status(CONFIGS, REQUIRED_INTERFACES,
charm_func=check_optional_relations)
@restart_on_change(restart_map()) @restart_on_change(restart_map())
def image_service_changed(): def image_service_changed():
if 'image-service' not in CONFIGS.complete_contexts(): if 'image-service' not in CONFIGS.complete_contexts():
@ -258,7 +289,10 @@ def compute_changed():
@hooks.hook('ceph-relation-joined') @hooks.hook('ceph-relation-joined')
@restart_on_change(restart_map()) @restart_on_change(restart_map())
@os_workload_status(CONFIGS, REQUIRED_INTERFACES,
charm_func=check_optional_relations)
def ceph_joined(): def ceph_joined():
status_set('maintenance', 'Installing apt packages')
apt_install(filter_installed_packages(['ceph-common']), fatal=True) apt_install(filter_installed_packages(['ceph-common']), fatal=True)
# Bug 1427660 # Bug 1427660
service_restart('libvirt-bin') service_restart('libvirt-bin')
@ -273,6 +307,8 @@ def get_ceph_request():
@hooks.hook('ceph-relation-changed') @hooks.hook('ceph-relation-changed')
@restart_on_change(restart_map()) @restart_on_change(restart_map())
@os_workload_status(CONFIGS, REQUIRED_INTERFACES,
charm_func=check_optional_relations)
def ceph_changed(): def ceph_changed():
if 'ceph' not in CONFIGS.complete_contexts(): if 'ceph' not in CONFIGS.complete_contexts():
log('ceph relation incomplete. Peer not ready?') log('ceph relation incomplete. Peer not ready?')
@ -306,6 +342,8 @@ def ceph_changed():
@hooks.hook('ceph-relation-broken') @hooks.hook('ceph-relation-broken')
@os_workload_status(CONFIGS, REQUIRED_INTERFACES,
charm_func=check_optional_relations)
def ceph_broken(): def ceph_broken():
service = service_name() service = service_name()
delete_keyring(service=service) delete_keyring(service=service)
@ -316,6 +354,8 @@ def ceph_broken():
'image-service-relation-broken', 'image-service-relation-broken',
'shared-db-relation-broken', 'shared-db-relation-broken',
'pgsql-db-relation-broken') 'pgsql-db-relation-broken')
@os_workload_status(CONFIGS, REQUIRED_INTERFACES,
charm_func=check_optional_relations)
@restart_on_change(restart_map()) @restart_on_change(restart_map())
def relation_broken(): def relation_broken():
CONFIGS.write_all() CONFIGS.write_all()
@ -324,6 +364,7 @@ def relation_broken():
@hooks.hook('upgrade-charm') @hooks.hook('upgrade-charm')
def upgrade_charm(): def upgrade_charm():
# NOTE: ensure psutil install for hugepages configuration # NOTE: ensure psutil install for hugepages configuration
status_set('maintenance', 'Installing apt packages')
apt_install(filter_installed_packages(['python-psutil'])) apt_install(filter_installed_packages(['python-psutil']))
for r_id in relation_ids('amqp'): for r_id in relation_ids('amqp'):
amqp_joined(relation_id=r_id) amqp_joined(relation_id=r_id)
@ -339,6 +380,8 @@ def nova_ceilometer_relation_changed():
@hooks.hook('zeromq-configuration-relation-joined') @hooks.hook('zeromq-configuration-relation-joined')
@os_workload_status(CONFIGS, REQUIRED_INTERFACES,
charm_func=check_optional_relations)
@os_requires_version('kilo', 'nova-common') @os_requires_version('kilo', 'nova-common')
def zeromq_configuration_relation_joined(relid=None): def zeromq_configuration_relation_joined(relid=None):
relation_set(relation_id=relid, relation_set(relation_id=relid,
@ -347,6 +390,8 @@ def zeromq_configuration_relation_joined(relid=None):
@hooks.hook('zeromq-configuration-relation-changed') @hooks.hook('zeromq-configuration-relation-changed')
@os_workload_status(CONFIGS, REQUIRED_INTERFACES,
charm_func=check_optional_relations)
@restart_on_change(restart_map()) @restart_on_change(restart_map())
def zeromq_configuration_relation_changed(): def zeromq_configuration_relation_changed():
CONFIGS.write(NOVA_CONF) CONFIGS.write(NOVA_CONF)

View File

@ -32,6 +32,7 @@ from charmhelpers.core.hookenv import (
relation_get, relation_get,
DEBUG, DEBUG,
INFO, INFO,
status_get,
) )
from charmhelpers.core.templating import render from charmhelpers.core.templating import render
@ -48,7 +49,8 @@ from charmhelpers.contrib.openstack.utils import (
git_src_dir, git_src_dir,
git_pip_venv_dir, git_pip_venv_dir,
git_yaml_value, git_yaml_value,
os_release os_release,
set_os_workload_status,
) )
from charmhelpers.contrib.python.packages import ( from charmhelpers.contrib.python.packages import (
@ -248,6 +250,14 @@ LIBVIRT_URIS = {
'lxc': 'lxc:///', 'lxc': 'lxc:///',
} }
# The interface is said to be satisfied if anyone of the interfaces in the
# list has a complete context.
REQUIRED_INTERFACES = {
'database': ['shared-db', 'pgsql-db'],
'message': ['amqp', 'zeromq-configuration'],
'image': ['image-service'],
}
def resource_map(): def resource_map():
''' '''
@ -829,3 +839,12 @@ def install_hugepages():
) )
subprocess.check_call('/etc/init.d/qemu-hugefsdir') subprocess.check_call('/etc/init.d/qemu-hugefsdir')
subprocess.check_call(['update-rc.d', 'qemu-hugefsdir', 'defaults']) subprocess.check_call(['update-rc.d', 'qemu-hugefsdir', 'defaults'])
def check_optional_relations(configs):
if relation_ids('ceph'):
required_interfaces = {'image-backend': 'ceph'}
set_os_workload_status(configs, required_interfaces)
return status_get()
else:
return 'unknown', 'No optional relations'

View File

@ -6,6 +6,9 @@ import yaml
from contextlib import contextmanager from contextlib import contextmanager
from mock import patch, MagicMock from mock import patch, MagicMock
patch('charmhelpers.contrib.openstack.utils.set_os_workload_status').start()
patch('charmhelpers.core.hookenv.status_set').start()
def load_config(): def load_config():
''' '''