From 18b938c693e75ac75c160fe4d10926a3e021cd7d Mon Sep 17 00:00:00 2001 From: Chuck Short Date: Thu, 23 Jul 2015 22:24:48 -0400 Subject: [PATCH 01/27] Refactor LXD and add build from support source. --- hooks/nova_compute_hooks.py | 10 ++++++--- hooks/nova_compute_utils.py | 35 +++++++++++++++++++++++------ metadata.yaml | 3 +++ templates/git/nova-compute-lxd.conf | 2 ++ 4 files changed, 40 insertions(+), 10 deletions(-) create mode 100644 templates/git/nova-compute-lxd.conf diff --git a/hooks/nova_compute_hooks.py b/hooks/nova_compute_hooks.py index 25a9d3f5..375c9a77 100755 --- a/hooks/nova_compute_hooks.py +++ b/hooks/nova_compute_hooks.py @@ -130,9 +130,6 @@ def config_changed(): fp = config('instances-path') fix_path_ownership(fp, user='nova') - if config('virt-type').lower() == 'lxd': - configure_lxd(user='nova') - [compute_joined(rid) for rid in relation_ids('cloud-compute')] for rid in relation_ids('zeromq-configuration'): zeromq_configuration_relation_joined(rid) @@ -379,6 +376,13 @@ def neutron_plugin_changed(): CONFIGS.write(NOVA_CONF) +@hooks.hook('lxd-relation-joined') +@restart_on_change(restart_map()) +def lxd_joined(): + settings = relation_get() + configure_lxd(settings, user='nova') + + def main(): try: hooks.execute(sys.argv) diff --git a/hooks/nova_compute_utils.py b/hooks/nova_compute_utils.py index 0595c7a0..72d113a5 100644 --- a/hooks/nova_compute_utils.py +++ b/hooks/nova_compute_utils.py @@ -4,7 +4,13 @@ import pwd from base64 import b64decode from copy import deepcopy -from subprocess import check_call, check_output, CalledProcessError +from subprocess import ( + PIPE, + Popen, + check_call, + check_output, + CalledProcessError +) from charmhelpers.fetch import ( apt_update, @@ -123,6 +129,7 @@ GIT_PACKAGE_BLACKLIST = [ 'nova-compute', 'nova-compute-kvm', 'nova-compute-lxc', + 'nova-compute-lxd', 'nova-compute-qemu', 'nova-compute-uml', 'nova-compute-xen', @@ -578,19 +585,21 @@ def create_libvirt_secret(secret_file, secret_uuid, key): check_call(cmd) -def configure_lxd(user='nova'): +def configure_lxd(settings, user='nova'): ''' Configure lxd use for nova user ''' - if lsb_release()['DISTRIB_CODENAME'].lower() < "vivid": - raise Exception("LXD is not supported for Ubuntu " - "versions less than 15.04 (vivid)") + if not git_install_requested(): + if lsb_release()['DISTRIB_CODENAME'].lower() < "vivid": + raise Exception("LXD is not supported for Ubuntu " + "versions less than 15.04 (vivid)") configure_subuid(user='nova') - configure_lxd_daemon(user='nova') + configure_lxd_daemon(settings, user='nova') + configure_lxd_host(settings, user='nova') service_restart('nova-compute') -def configure_lxd_daemon(user): +def configure_lxd_daemon(settings, user): add_user_to_group(user, 'lxd') service_restart('lxd') # NOTE(jamespage): Call list function to initialize cert @@ -603,6 +612,18 @@ def lxc_list(user): check_call(cmd) +@retry_on_exception(5, base_delay=2, exc_type=CalledProcessError) +def configure_lxd_host(settings, user): + cmd = ['sudo', '-u', user, 'lxc', 'config', 'set', + 'core.trust_password', settings['lxd_password']] + check_call(cmd) + + p = Popen(['sudo', '-u', user, 'lxc', 'remote', 'add', + settings['lxd_hostname'], '%s:8443' % settings['lxd_address'], + '--accept-certificate'], stdin=PIPE) + p.communicate(input='%s\n' % settings['lxd_password']) + + def configure_subuid(user): cmd = ['usermod', '-v', '100000-200000', '-w', '100000-200000', user] check_call(cmd) diff --git a/metadata.yaml b/metadata.yaml index 8b7f916d..38f89b6d 100644 --- a/metadata.yaml +++ b/metadata.yaml @@ -24,6 +24,9 @@ requires: interface: glance ceph: interface: ceph-client + lxd: + interface: containers + scope: container nova-ceilometer: interface: nova-ceilometer scope: container diff --git a/templates/git/nova-compute-lxd.conf b/templates/git/nova-compute-lxd.conf new file mode 100644 index 00000000..94ce84b7 --- /dev/null +++ b/templates/git/nova-compute-lxd.conf @@ -0,0 +1,2 @@ +[DEFAULT] +compute_driver=nclxd.nova.virt.lxd.LXDDriver From 4e2ab7be804dead965300d95302bd18e0f3e65c2 Mon Sep 17 00:00:00 2001 From: Chuck Short Date: Thu, 23 Jul 2015 22:30:01 -0400 Subject: [PATCH 02/27] Add missing hook --- hooks/lxd-relation-joined | 1 + 1 file changed, 1 insertion(+) create mode 120000 hooks/lxd-relation-joined diff --git a/hooks/lxd-relation-joined b/hooks/lxd-relation-joined new file mode 120000 index 00000000..3ba0bdea --- /dev/null +++ b/hooks/lxd-relation-joined @@ -0,0 +1 @@ +nova_compute_hooks.py \ No newline at end of file From 08e2daa366ec714bc2b04c72b8e6f72abb98fd06 Mon Sep 17 00:00:00 2001 From: Chuck Short Date: Fri, 4 Sep 2015 12:58:56 -0400 Subject: [PATCH 03/27] Case out vivid-kilo --- hooks/nova_compute_hooks.py | 1 - hooks/nova_compute_utils.py | 22 +++++++++++++++------- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/hooks/nova_compute_hooks.py b/hooks/nova_compute_hooks.py index 89e8088b..7b2a5797 100755 --- a/hooks/nova_compute_hooks.py +++ b/hooks/nova_compute_hooks.py @@ -388,7 +388,6 @@ def lxd_joined(): settings = relation_get() configure_lxd(settings, user='nova') - def main(): try: hooks.execute(sys.argv) diff --git a/hooks/nova_compute_utils.py b/hooks/nova_compute_utils.py index 64c081d3..9a2f5223 100644 --- a/hooks/nova_compute_utils.py +++ b/hooks/nova_compute_utils.py @@ -618,14 +618,22 @@ def lxc_list(user): @retry_on_exception(5, base_delay=2, exc_type=CalledProcessError) def configure_lxd_host(settings, user): - cmd = ['sudo', '-u', user, 'lxc', 'config', 'set', - 'core.trust_password', settings['lxd_password']] - check_call(cmd) + if lsb_release()['DISTRIB_CODENAME'].lower() > "vivid": + cmd = ['sudo', '-u', user, 'lxc', 'config', 'set', + 'core.trust_password', settings['lxd_password']] + check_call(cmd) - p = Popen(['sudo', '-u', user, 'lxc', 'remote', 'add', - settings['lxd_hostname'], '%s:8443' % settings['lxd_address'], - '--accept-certificate'], stdin=PIPE) - p.communicate(input='%s\n' % settings['lxd_password']) + cmd = ['sudo', '-u', user, 'lxc', 'config', 'core.https_address option', + settings['lxd_address']] + check_call(cmd) + + if lsb_release()['DISTRIB_CODENAME'].lower() == "vivid"; + log('Loading kernel module', level=INFO) + cmd = ['modprobe', 'overlay'] + check_call(cmd) + with open('/etc/modules', 'r+') as modules: + if module not in modules.read(): + modules.write(module) def configure_subuid(user): From 04065ffff6357102c061aecb53f0a0f81717263b Mon Sep 17 00:00:00 2001 From: "james.page@ubuntu.com" <> Date: Wed, 9 Sep 2015 09:42:34 +0100 Subject: [PATCH 04/27] Fixup casing --- hooks/nova_compute_utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hooks/nova_compute_utils.py b/hooks/nova_compute_utils.py index 9a2f5223..c87ff3fe 100644 --- a/hooks/nova_compute_utils.py +++ b/hooks/nova_compute_utils.py @@ -627,7 +627,7 @@ def configure_lxd_host(settings, user): settings['lxd_address']] check_call(cmd) - if lsb_release()['DISTRIB_CODENAME'].lower() == "vivid"; + if lsb_release()['DISTRIB_CODENAME'].lower() == "vivid": log('Loading kernel module', level=INFO) cmd = ['modprobe', 'overlay'] check_call(cmd) From fd31cc20f2ece01ae533460aa0741dcdd4906eda Mon Sep 17 00:00:00 2001 From: "james.page@ubuntu.com" <> Date: Wed, 9 Sep 2015 09:46:23 +0100 Subject: [PATCH 05/27] Tidy configure_lxd_host --- hooks/nova_compute_utils.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/hooks/nova_compute_utils.py b/hooks/nova_compute_utils.py index c87ff3fe..6c4901d4 100644 --- a/hooks/nova_compute_utils.py +++ b/hooks/nova_compute_utils.py @@ -618,7 +618,10 @@ def lxc_list(user): @retry_on_exception(5, base_delay=2, exc_type=CalledProcessError) def configure_lxd_host(settings, user): - if lsb_release()['DISTRIB_CODENAME'].lower() > "vivid": + ubuntu_release = lsb_release()['DISTRIB_CODENAME'].lower() + if ubuntu_release > "vivid": + log('>= Wily deployment - configuring LXD trust password and address', + level=INFO) cmd = ['sudo', '-u', user, 'lxc', 'config', 'set', 'core.trust_password', settings['lxd_password']] check_call(cmd) @@ -626,14 +629,13 @@ def configure_lxd_host(settings, user): cmd = ['sudo', '-u', user, 'lxc', 'config', 'core.https_address option', settings['lxd_address']] check_call(cmd) - - if lsb_release()['DISTRIB_CODENAME'].lower() == "vivid": - log('Loading kernel module', level=INFO) + elif ubuntu_release == "vivid": + log('Vivid deployment - loading overlay kernel module', level=INFO) cmd = ['modprobe', 'overlay'] check_call(cmd) with open('/etc/modules', 'r+') as modules: - if module not in modules.read(): - modules.write(module) + if 'overlay' not in modules.read(): + modules.write('overlay') def configure_subuid(user): From 06f64699fd17c52d6b1da3c87e7c12849792c28d Mon Sep 17 00:00:00 2001 From: "james.page@ubuntu.com" <> Date: Wed, 9 Sep 2015 12:23:31 +0100 Subject: [PATCH 06/27] Sortout lxd config options --- hooks/nova_compute_utils.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/hooks/nova_compute_utils.py b/hooks/nova_compute_utils.py index 6c4901d4..195517bc 100644 --- a/hooks/nova_compute_utils.py +++ b/hooks/nova_compute_utils.py @@ -622,12 +622,12 @@ def configure_lxd_host(settings, user): if ubuntu_release > "vivid": log('>= Wily deployment - configuring LXD trust password and address', level=INFO) - cmd = ['sudo', '-u', user, 'lxc', 'config', 'set', + cmd = ['lxc', 'config', 'set', 'core.trust_password', settings['lxd_password']] check_call(cmd) - cmd = ['sudo', '-u', user, 'lxc', 'config', 'core.https_address option', - settings['lxd_address']] + cmd = ['lxc', 'config', 'set', + 'core.https_address', settings['lxd_address']] check_call(cmd) elif ubuntu_release == "vivid": log('Vivid deployment - loading overlay kernel module', level=INFO) From 54a1896d6cf36d157e83450a4806acfb0f322dbf Mon Sep 17 00:00:00 2001 From: "james.page@ubuntu.com" <> Date: Wed, 9 Sep 2015 12:39:09 +0100 Subject: [PATCH 07/27] Set lxc configuration for the user --- hooks/nova_compute_utils.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/hooks/nova_compute_utils.py b/hooks/nova_compute_utils.py index 195517bc..8908c17f 100644 --- a/hooks/nova_compute_utils.py +++ b/hooks/nova_compute_utils.py @@ -622,11 +622,10 @@ def configure_lxd_host(settings, user): if ubuntu_release > "vivid": log('>= Wily deployment - configuring LXD trust password and address', level=INFO) - cmd = ['lxc', 'config', 'set', + cmd = ['sudo', '-u', user, 'lxc', 'config', 'set', 'core.trust_password', settings['lxd_password']] check_call(cmd) - - cmd = ['lxc', 'config', 'set', + cmd = ['sudo', '-u', user, 'lxc', 'config', 'set', 'core.https_address', settings['lxd_address']] check_call(cmd) elif ubuntu_release == "vivid": From a3aee3cda3bec7b1ff947f99a54fcb6ba4092a17 Mon Sep 17 00:00:00 2001 From: "james.page@ubuntu.com" <> Date: Wed, 9 Sep 2015 12:59:09 +0100 Subject: [PATCH 08/27] Nope - do it as root --- hooks/nova_compute_utils.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hooks/nova_compute_utils.py b/hooks/nova_compute_utils.py index 8908c17f..2fbe54cd 100644 --- a/hooks/nova_compute_utils.py +++ b/hooks/nova_compute_utils.py @@ -622,10 +622,10 @@ def configure_lxd_host(settings, user): if ubuntu_release > "vivid": log('>= Wily deployment - configuring LXD trust password and address', level=INFO) - cmd = ['sudo', '-u', user, 'lxc', 'config', 'set', + cmd = ['lxc', 'config', 'set', 'core.trust_password', settings['lxd_password']] check_call(cmd) - cmd = ['sudo', '-u', user, 'lxc', 'config', 'set', + cmd = ['lxc', 'config', 'set', 'core.https_address', settings['lxd_address']] check_call(cmd) elif ubuntu_release == "vivid": From 09ae1f009b5b70cf746acf60bece4bca441df6f5 Mon Sep 17 00:00:00 2001 From: "james.page@ubuntu.com" <> Date: Tue, 22 Sep 2015 09:29:20 +0100 Subject: [PATCH 09/27] Add compatibility wrapper for >= wily --- hooks/nova_compute_hooks.py | 2 +- hooks/python2or3 | 21 +++++++++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) create mode 100755 hooks/python2or3 diff --git a/hooks/nova_compute_hooks.py b/hooks/nova_compute_hooks.py index 9454c2cf..adfd3825 100755 --- a/hooks/nova_compute_hooks.py +++ b/hooks/nova_compute_hooks.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!./hooks/python2or3 import sys from charmhelpers.core.hookenv import ( diff --git a/hooks/python2or3 b/hooks/python2or3 new file mode 100755 index 00000000..8e1c8079 --- /dev/null +++ b/hooks/python2or3 @@ -0,0 +1,21 @@ +#!/bin/bash +# Wrapper to deal with newer Ubuntu versions that don't have py2 installed +# by default. +# TODO: make this really do python3 when the charm codebase supports it. + +declare -a DEPS=('apt' 'netaddr' 'netifaces' 'pip' 'yaml') + +check_and_install() { + pkg="${1}-${2}" + if ! dpkg -s ${pkg} 2>&1 > /dev/null; then + apt-get -y install ${pkg} + fi +} + +PYTHON="python" + +for dep in ${DEPS[@]}; do + check_and_install ${PYTHON} ${dep} +done + +exec /usr/bin/python $@ From b3bef7b58ec6e5ea49c542464c287c837c047ed1 Mon Sep 17 00:00:00 2001 From: "james.page@ubuntu.com" <> Date: Tue, 22 Sep 2015 15:19:29 +0100 Subject: [PATCH 10/27] Revert --- hooks/nova_compute_hooks.py | 2 +- hooks/python2or3 | 21 --------------------- 2 files changed, 1 insertion(+), 22 deletions(-) delete mode 100755 hooks/python2or3 diff --git a/hooks/nova_compute_hooks.py b/hooks/nova_compute_hooks.py index c5f3d0d4..e3b4f57f 100755 --- a/hooks/nova_compute_hooks.py +++ b/hooks/nova_compute_hooks.py @@ -1,4 +1,4 @@ -#!./hooks/python2or3 +#!/usr/bin/python import sys from charmhelpers.core.hookenv import ( diff --git a/hooks/python2or3 b/hooks/python2or3 deleted file mode 100755 index 8e1c8079..00000000 --- a/hooks/python2or3 +++ /dev/null @@ -1,21 +0,0 @@ -#!/bin/bash -# Wrapper to deal with newer Ubuntu versions that don't have py2 installed -# by default. -# TODO: make this really do python3 when the charm codebase supports it. - -declare -a DEPS=('apt' 'netaddr' 'netifaces' 'pip' 'yaml') - -check_and_install() { - pkg="${1}-${2}" - if ! dpkg -s ${pkg} 2>&1 > /dev/null; then - apt-get -y install ${pkg} - fi -} - -PYTHON="python" - -for dep in ${DEPS[@]}; do - check_and_install ${PYTHON} ${dep} -done - -exec /usr/bin/python $@ From 965a5f0a8f6fd38e38f0b20c214bdaf902c2fc1c Mon Sep 17 00:00:00 2001 From: "james.page@ubuntu.com" <> Date: Tue, 22 Sep 2015 15:22:50 +0100 Subject: [PATCH 11/27] Ensure all settings provided on lxd relation before configuring --- hooks/lxd-relation-changed | 1 + hooks/nova_compute_hooks.py | 10 +++++++--- 2 files changed, 8 insertions(+), 3 deletions(-) create mode 120000 hooks/lxd-relation-changed diff --git a/hooks/lxd-relation-changed b/hooks/lxd-relation-changed new file mode 120000 index 00000000..3ba0bdea --- /dev/null +++ b/hooks/lxd-relation-changed @@ -0,0 +1 @@ +nova_compute_hooks.py \ No newline at end of file diff --git a/hooks/nova_compute_hooks.py b/hooks/nova_compute_hooks.py index 5ce7390c..3ad58cd4 100755 --- a/hooks/nova_compute_hooks.py +++ b/hooks/nova_compute_hooks.py @@ -373,11 +373,15 @@ def neutron_plugin_changed(): CONFIGS.write(NOVA_CONF) -@hooks.hook('lxd-relation-joined') +@hooks.hook('lxd-relation-changed') @restart_on_change(restart_map()) def lxd_joined(): - settings = relation_get() - configure_lxd(settings, user='nova') + settings = { + 'lxd_password': relation_get('lxd_password'), + 'lxd_address': relation_get('lxd_address'), + } + if all(settings): + configure_lxd(settings, user='nova') def main(): try: From 710b7efd34b20e1db3ee43e6984b7b7dbb7b1c54 Mon Sep 17 00:00:00 2001 From: "james.page@ubuntu.com" <> Date: Wed, 23 Sep 2015 12:48:09 +0100 Subject: [PATCH 12/27] Move lxd core config to lxd charm --- hooks/nova_compute_hooks.py | 2 +- hooks/nova_compute_utils.py | 23 ----------------------- 2 files changed, 1 insertion(+), 24 deletions(-) diff --git a/hooks/nova_compute_hooks.py b/hooks/nova_compute_hooks.py index 3ad58cd4..6e0cba8e 100755 --- a/hooks/nova_compute_hooks.py +++ b/hooks/nova_compute_hooks.py @@ -380,7 +380,7 @@ def lxd_joined(): 'lxd_password': relation_get('lxd_password'), 'lxd_address': relation_get('lxd_address'), } - if all(settings): + if all(settings.values()): configure_lxd(settings, user='nova') def main(): diff --git a/hooks/nova_compute_utils.py b/hooks/nova_compute_utils.py index 841cb9af..3e4477a7 100644 --- a/hooks/nova_compute_utils.py +++ b/hooks/nova_compute_utils.py @@ -598,8 +598,6 @@ def configure_lxd(settings, user='nova'): configure_subuid(user='nova') configure_lxd_daemon(settings, user='nova') - configure_lxd_host(settings, user='nova') - service_restart('nova-compute') @@ -616,27 +614,6 @@ def lxc_list(user): check_call(cmd) -@retry_on_exception(5, base_delay=2, exc_type=CalledProcessError) -def configure_lxd_host(settings, user): - ubuntu_release = lsb_release()['DISTRIB_CODENAME'].lower() - if ubuntu_release > "vivid": - log('>= Wily deployment - configuring LXD trust password and address', - level=INFO) - cmd = ['lxc', 'config', 'set', - 'core.trust_password', settings['lxd_password']] - check_call(cmd) - cmd = ['lxc', 'config', 'set', - 'core.https_address', settings['lxd_address']] - check_call(cmd) - elif ubuntu_release == "vivid": - log('Vivid deployment - loading overlay kernel module', level=INFO) - cmd = ['modprobe', 'overlay'] - check_call(cmd) - with open('/etc/modules', 'r+') as modules: - if 'overlay' not in modules.read(): - modules.write('overlay') - - def configure_subuid(user): cmd = ['usermod', '-v', '100000-200000', '-w', '100000-200000', user] check_call(cmd) From 24c9b7bbead65e778773b2aec5572dff859c938f Mon Sep 17 00:00:00 2001 From: "james.page@ubuntu.com" <> Date: Wed, 23 Sep 2015 13:11:45 +0100 Subject: [PATCH 13/27] Move to sub configured access, and triggered restart --- hooks/nova_compute_hooks.py | 24 ++++++++++++++++-------- hooks/nova_compute_utils.py | 12 ++---------- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/hooks/nova_compute_hooks.py b/hooks/nova_compute_hooks.py index 6e0cba8e..0532503c 100755 --- a/hooks/nova_compute_hooks.py +++ b/hooks/nova_compute_hooks.py @@ -72,6 +72,8 @@ from charmhelpers.contrib.network.ip import ( get_ipv6_addr ) +from charmhelpers.core.unitdata import kv + from nova_compute_context import ( CEPH_SECRET_UUID, assert_libvirt_imagebackend_allowed @@ -373,15 +375,21 @@ def neutron_plugin_changed(): CONFIGS.write(NOVA_CONF) +@hooks.hook('lxd-relation-joined') +def lxd_joined(relid=None): + relation_set(relation_id=relid, + user='nova') + + @hooks.hook('lxd-relation-changed') -@restart_on_change(restart_map()) -def lxd_joined(): - settings = { - 'lxd_password': relation_get('lxd_password'), - 'lxd_address': relation_get('lxd_address'), - } - if all(settings.values()): - configure_lxd(settings, user='nova') +def lxc_changed(): + nonce = relation_get('nonce') + db = kv() + if nonce and db.get('lxd-nonce') != nonce: + db.set('lxd-nonce', nonce) + configure_lxd(user='nova') + service_restart('nova-compute') + def main(): try: diff --git a/hooks/nova_compute_utils.py b/hooks/nova_compute_utils.py index 3e4477a7..db7eb22d 100644 --- a/hooks/nova_compute_utils.py +++ b/hooks/nova_compute_utils.py @@ -589,22 +589,14 @@ def create_libvirt_secret(secret_file, secret_uuid, key): check_call(cmd) -def configure_lxd(settings, user='nova'): +def configure_lxd(user='nova'): ''' Configure lxd use for nova user ''' if not git_install_requested(): if lsb_release()['DISTRIB_CODENAME'].lower() < "vivid": raise Exception("LXD is not supported for Ubuntu " "versions less than 15.04 (vivid)") - configure_subuid(user='nova') - configure_lxd_daemon(settings, user='nova') - service_restart('nova-compute') - - -def configure_lxd_daemon(settings, user): - add_user_to_group(user, 'lxd') - service_restart('lxd') - # NOTE(jamespage): Call list function to initialize cert + configure_subuid(user) lxc_list(user) From f4c6aba8b22f3cd63309b918dffd9dfb32280167 Mon Sep 17 00:00:00 2001 From: David Ames Date: Fri, 25 Sep 2015 15:12:01 -0700 Subject: [PATCH 14/27] Workload Status --- .../contrib/openstack/templating.py | 3 +- hooks/charmhelpers/contrib/openstack/utils.py | 56 ++++++++++++++++++- hooks/nova_compute_hooks.py | 45 +++++++++++++++ hooks/nova_compute_utils.py | 21 ++++++- unit_tests/test_utils.py | 3 + 5 files changed, 125 insertions(+), 3 deletions(-) diff --git a/hooks/charmhelpers/contrib/openstack/templating.py b/hooks/charmhelpers/contrib/openstack/templating.py index 0813719a..e5e3cb1b 100644 --- a/hooks/charmhelpers/contrib/openstack/templating.py +++ b/hooks/charmhelpers/contrib/openstack/templating.py @@ -18,7 +18,7 @@ import os import six -from charmhelpers.fetch import apt_install +from charmhelpers.fetch import apt_install, apt_update from charmhelpers.core.hookenv import ( log, ERROR, @@ -29,6 +29,7 @@ from charmhelpers.contrib.openstack.utils import OPENSTACK_CODENAMES try: from jinja2 import FileSystemLoader, ChoiceLoader, Environment, exceptions except ImportError: + apt_update(fatal=True) apt_install('python-jinja2', fatal=True) from jinja2 import FileSystemLoader, ChoiceLoader, Environment, exceptions diff --git a/hooks/charmhelpers/contrib/openstack/utils.py b/hooks/charmhelpers/contrib/openstack/utils.py index 47a4c22f..eefcf08b 100644 --- a/hooks/charmhelpers/contrib/openstack/utils.py +++ b/hooks/charmhelpers/contrib/openstack/utils.py @@ -25,6 +25,7 @@ import sys import re import six +import traceback import yaml from charmhelpers.contrib.network import ip @@ -34,6 +35,8 @@ from charmhelpers.core import ( ) from charmhelpers.core.hookenv import ( + action_fail, + action_set, config, log as juju_log, charm_dir, @@ -51,7 +54,8 @@ from charmhelpers.contrib.storage.linux.lvm import ( ) from charmhelpers.contrib.network.ip import ( - get_ipv6_addr + get_ipv6_addr, + is_ipv6, ) from charmhelpers.contrib.python.packages import ( @@ -516,6 +520,12 @@ def sync_db_with_multi_ipv6_addresses(database, database_user, relation_prefix=None): 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, 'username': database_user, 'hostname': json.dumps(hosts)} @@ -921,3 +931,47 @@ def incomplete_relation_data(configs, required_interfaces): for i in incomplete_relations: incomplete_context_data[i] = configs.get_incomplete_context_data(required_interfaces[i]) 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 diff --git a/hooks/nova_compute_hooks.py b/hooks/nova_compute_hooks.py index df58bb10..50c9dd77 100755 --- a/hooks/nova_compute_hooks.py +++ b/hooks/nova_compute_hooks.py @@ -13,6 +13,7 @@ from charmhelpers.core.hookenv import ( service_name, unit_get, UnregisteredHookError, + status_set, ) from charmhelpers.core.host import ( restart_on_change, @@ -32,6 +33,7 @@ from charmhelpers.contrib.openstack.utils import ( git_install_requested, openstack_upgrade_available, os_requires_version, + os_workload_status, ) from charmhelpers.contrib.storage.linux.ceph import ( @@ -66,6 +68,8 @@ from nova_compute_utils import ( assert_charm_supports_ipv6, manage_ovs, install_hugepages, + REQUIRED_INTERFACES, + check_optional_relations, ) from charmhelpers.contrib.network.ip import ( @@ -86,28 +90,38 @@ CONFIGS = register_configs() @hooks.hook('install.real') +@os_workload_status(CONFIGS, REQUIRED_INTERFACES, + charm_func=check_optional_relations) def install(): + status_set('maintenance', 'Executing pre-install') execd_preinstall() configure_installation_source(config('openstack-origin')) + status_set('maintenance', 'Installing apt packages') apt_update() apt_install(determine_packages(), fatal=True) + status_set('maintenance', 'Git install') git_install(config('openstack-origin-git')) @hooks.hook('config-changed') +@os_workload_status(CONFIGS, REQUIRED_INTERFACES, + charm_func=check_optional_relations) @restart_on_change(restart_map()) def config_changed(): if config('prefer-ipv6'): + status_set('maintenance', 'configuring ipv6') assert_charm_supports_ipv6() global CONFIGS if git_install_requested(): if config_value_changed('openstack-origin-git'): + status_set('maintenance', 'Running Git install') git_install(config('openstack-origin-git')) else: if openstack_upgrade_available('nova-common'): + status_set('maintenance', 'Running openstack upgrade') CONFIGS = do_openstack_upgrade() sysctl_dict = config('sysctl') @@ -117,11 +131,13 @@ def config_changed(): 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 # generated. + status_set('maintenance', 'SSH key exchange') initialize_ssh_keys() import_authorized_keys() if config('enable-resize') is True: enable_shell(user='nova') + status_set('maintenance', 'SSH key exchange') initialize_ssh_keys(user='nova') import_authorized_keys(user='nova', prefix='nova') else: @@ -132,6 +148,7 @@ def config_changed(): fix_path_ownership(fp, user='nova') if config('virt-type').lower() == 'lxd': + status_set('maintenance', 'Configure LXD') configure_lxd(user='nova') [compute_joined(rid) for rid in relation_ids('cloud-compute')] @@ -148,6 +165,8 @@ def config_changed(): @hooks.hook('amqp-relation-joined') +@os_workload_status(CONFIGS, REQUIRED_INTERFACES, + charm_func=check_optional_relations) def amqp_joined(relation_id=None): relation_set(relation_id=relation_id, username=config('rabbit-user'), @@ -156,6 +175,8 @@ def amqp_joined(relation_id=None): @hooks.hook('amqp-relation-changed') @hooks.hook('amqp-relation-departed') +@os_workload_status(CONFIGS, REQUIRED_INTERFACES, + charm_func=check_optional_relations) @restart_on_change(restart_map()) def amqp_changed(): if 'amqp' not in CONFIGS.complete_contexts(): @@ -171,6 +192,8 @@ def amqp_changed(): @hooks.hook('shared-db-relation-joined') +@os_workload_status(CONFIGS, REQUIRED_INTERFACES, + charm_func=check_optional_relations) def db_joined(rid=None): if is_relation_made('pgsql-db'): # error, postgresql is used @@ -186,6 +209,8 @@ def db_joined(rid=None): @hooks.hook('pgsql-db-relation-joined') +@os_workload_status(CONFIGS, REQUIRED_INTERFACES, + charm_func=check_optional_relations) def pgsql_db_joined(): if is_relation_made('shared-db'): # raise error @@ -198,6 +223,8 @@ def pgsql_db_joined(): @hooks.hook('shared-db-relation-changed') +@os_workload_status(CONFIGS, REQUIRED_INTERFACES, + charm_func=check_optional_relations) @restart_on_change(restart_map()) def db_changed(): if 'shared-db' not in CONFIGS.complete_contexts(): @@ -207,6 +234,8 @@ def db_changed(): @hooks.hook('pgsql-db-relation-changed') +@os_workload_status(CONFIGS, REQUIRED_INTERFACES, + charm_func=check_optional_relations) @restart_on_change(restart_map()) def postgresql_db_changed(): if 'pgsql-db' not in CONFIGS.complete_contexts(): @@ -216,6 +245,8 @@ def postgresql_db_changed(): @hooks.hook('image-service-relation-changed') +@os_workload_status(CONFIGS, REQUIRED_INTERFACES, + charm_func=check_optional_relations) @restart_on_change(restart_map()) def image_service_changed(): if 'image-service' not in CONFIGS.complete_contexts(): @@ -258,7 +289,10 @@ def compute_changed(): @hooks.hook('ceph-relation-joined') @restart_on_change(restart_map()) +@os_workload_status(CONFIGS, REQUIRED_INTERFACES, + charm_func=check_optional_relations) def ceph_joined(): + status_set('maintenance', 'Installing apt packages') apt_install(filter_installed_packages(['ceph-common']), fatal=True) # Bug 1427660 service_restart('libvirt-bin') @@ -273,6 +307,8 @@ def get_ceph_request(): @hooks.hook('ceph-relation-changed') @restart_on_change(restart_map()) +@os_workload_status(CONFIGS, REQUIRED_INTERFACES, + charm_func=check_optional_relations) def ceph_changed(): if 'ceph' not in CONFIGS.complete_contexts(): log('ceph relation incomplete. Peer not ready?') @@ -306,6 +342,8 @@ def ceph_changed(): @hooks.hook('ceph-relation-broken') +@os_workload_status(CONFIGS, REQUIRED_INTERFACES, + charm_func=check_optional_relations) def ceph_broken(): service = service_name() delete_keyring(service=service) @@ -316,6 +354,8 @@ def ceph_broken(): 'image-service-relation-broken', 'shared-db-relation-broken', 'pgsql-db-relation-broken') +@os_workload_status(CONFIGS, REQUIRED_INTERFACES, + charm_func=check_optional_relations) @restart_on_change(restart_map()) def relation_broken(): CONFIGS.write_all() @@ -324,6 +364,7 @@ def relation_broken(): @hooks.hook('upgrade-charm') def upgrade_charm(): # NOTE: ensure psutil install for hugepages configuration + status_set('maintenance', 'Installing apt packages') apt_install(filter_installed_packages(['python-psutil'])) for r_id in relation_ids('amqp'): amqp_joined(relation_id=r_id) @@ -339,6 +380,8 @@ def nova_ceilometer_relation_changed(): @hooks.hook('zeromq-configuration-relation-joined') +@os_workload_status(CONFIGS, REQUIRED_INTERFACES, + charm_func=check_optional_relations) @os_requires_version('kilo', 'nova-common') def zeromq_configuration_relation_joined(relid=None): relation_set(relation_id=relid, @@ -347,6 +390,8 @@ def zeromq_configuration_relation_joined(relid=None): @hooks.hook('zeromq-configuration-relation-changed') +@os_workload_status(CONFIGS, REQUIRED_INTERFACES, + charm_func=check_optional_relations) @restart_on_change(restart_map()) def zeromq_configuration_relation_changed(): CONFIGS.write(NOVA_CONF) diff --git a/hooks/nova_compute_utils.py b/hooks/nova_compute_utils.py index 15e7a535..87126dd2 100644 --- a/hooks/nova_compute_utils.py +++ b/hooks/nova_compute_utils.py @@ -32,6 +32,7 @@ from charmhelpers.core.hookenv import ( relation_get, DEBUG, INFO, + status_get, ) from charmhelpers.core.templating import render @@ -48,7 +49,8 @@ from charmhelpers.contrib.openstack.utils import ( git_src_dir, git_pip_venv_dir, git_yaml_value, - os_release + os_release, + set_os_workload_status, ) from charmhelpers.contrib.python.packages import ( @@ -248,6 +250,14 @@ LIBVIRT_URIS = { '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(): ''' @@ -829,3 +839,12 @@ def install_hugepages(): ) subprocess.check_call('/etc/init.d/qemu-hugefsdir') 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' diff --git a/unit_tests/test_utils.py b/unit_tests/test_utils.py index c9c7bace..cc80b485 100644 --- a/unit_tests/test_utils.py +++ b/unit_tests/test_utils.py @@ -6,6 +6,9 @@ import yaml from contextlib import contextmanager 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(): ''' From 561b3ef126f10b0dd8e9930f012cf85784d6e934 Mon Sep 17 00:00:00 2001 From: David Ames Date: Fri, 25 Sep 2015 15:50:56 -0700 Subject: [PATCH 15/27] List value in dictionary --- hooks/nova_compute_utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hooks/nova_compute_utils.py b/hooks/nova_compute_utils.py index 87126dd2..b4ffef59 100644 --- a/hooks/nova_compute_utils.py +++ b/hooks/nova_compute_utils.py @@ -843,7 +843,7 @@ def install_hugepages(): def check_optional_relations(configs): if relation_ids('ceph'): - required_interfaces = {'image-backend': 'ceph'} + required_interfaces = {'image-backend': ['ceph']} set_os_workload_status(configs, required_interfaces) return status_get() else: From 335b6bf2a3a04ad8a75458ac237dc844e848be68 Mon Sep 17 00:00:00 2001 From: David Ames Date: Mon, 28 Sep 2015 14:40:59 -0700 Subject: [PATCH 16/27] Check for neutron plugin relation --- hooks/nova_compute_hooks.py | 2 ++ hooks/nova_compute_utils.py | 8 +++++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/hooks/nova_compute_hooks.py b/hooks/nova_compute_hooks.py index 50c9dd77..7845f42c 100755 --- a/hooks/nova_compute_hooks.py +++ b/hooks/nova_compute_hooks.py @@ -410,6 +410,8 @@ def update_nrpe_config(): @hooks.hook('neutron-plugin-relation-changed') +@os_workload_status(CONFIGS, REQUIRED_INTERFACES, + charm_func=check_optional_relations) @restart_on_change(restart_map()) def neutron_plugin_changed(): settings = relation_get() diff --git a/hooks/nova_compute_utils.py b/hooks/nova_compute_utils.py index b4ffef59..3d5ec788 100644 --- a/hooks/nova_compute_utils.py +++ b/hooks/nova_compute_utils.py @@ -842,8 +842,14 @@ def install_hugepages(): def check_optional_relations(configs): + required_interfaces = {} if relation_ids('ceph'): - required_interfaces = {'image-backend': ['ceph']} + required_interfaces['storage-backend'] = ['ceph'] + + if relation_ids('neutron-plugin'): + required_interfaces['neutron-plugin'] = ['neutron-plugin'] + + if required_interfaces: set_os_workload_status(configs, required_interfaces) return status_get() else: From b90126233bc89223cf04e55ba2eb26b8189a6c58 Mon Sep 17 00:00:00 2001 From: "james.page@ubuntu.com" <> Date: Tue, 29 Sep 2015 16:14:00 +0100 Subject: [PATCH 17/27] Drop vif driver config --- templates/kilo/nova.conf | 3 --- 1 file changed, 3 deletions(-) diff --git a/templates/kilo/nova.conf b/templates/kilo/nova.conf index a8f92d18..db395656 100644 --- a/templates/kilo/nova.conf +++ b/templates/kilo/nova.conf @@ -46,7 +46,6 @@ novnc_enabled = False {% endif -%} {% if neutron_plugin and neutron_plugin == 'ovs' -%} -libvirt_vif_driver = nova.virt.libvirt.vif.LibvirtGenericVIFDriver {% if neutron_security_groups -%} security_group_api = neutron firewall_driver = nova.virt.firewall.NoopFirewallDriver @@ -55,14 +54,12 @@ firewall_driver = nova.virt.firewall.NoopFirewallDriver {% if neutron_plugin and neutron_plugin == 'vsp' -%} network_api_class=nova.network.neutronv2.api.API -libvirt_vif_driver=nova.virt.libvirt.vif.LibvirtGenericVIFDriver neutron_ovs_bridge=alubr0 security_group_api=nova firewall_driver = nova.virt.firewall.NoopFirewallDriver {% endif -%} {% if neutron_plugin and (neutron_plugin == 'nvp' or neutron_plugin == 'nsx') -%} -libvirt_vif_driver = nova.virt.libvirt.vif.LibvirtOpenVswitchVirtualPortDriver security_group_api = neutron firewall_driver = nova.virt.firewall.NoopFirewallDriver {% endif -%} From 5dd57d970ad4307c5f0ae5f53bc7370068c17463 Mon Sep 17 00:00:00 2001 From: David Ames Date: Tue, 29 Sep 2015 08:14:35 -0700 Subject: [PATCH 18/27] Database is optional for nova-compute. Fix decorator ordering --- hooks/nova_compute_hooks.py | 4 ++-- hooks/nova_compute_utils.py | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/hooks/nova_compute_hooks.py b/hooks/nova_compute_hooks.py index 7845f42c..a363742e 100755 --- a/hooks/nova_compute_hooks.py +++ b/hooks/nova_compute_hooks.py @@ -288,9 +288,9 @@ def compute_changed(): @hooks.hook('ceph-relation-joined') -@restart_on_change(restart_map()) @os_workload_status(CONFIGS, REQUIRED_INTERFACES, charm_func=check_optional_relations) +@restart_on_change(restart_map()) def ceph_joined(): status_set('maintenance', 'Installing apt packages') apt_install(filter_installed_packages(['ceph-common']), fatal=True) @@ -306,9 +306,9 @@ def get_ceph_request(): @hooks.hook('ceph-relation-changed') -@restart_on_change(restart_map()) @os_workload_status(CONFIGS, REQUIRED_INTERFACES, charm_func=check_optional_relations) +@restart_on_change(restart_map()) def ceph_changed(): if 'ceph' not in CONFIGS.complete_contexts(): log('ceph relation incomplete. Peer not ready?') diff --git a/hooks/nova_compute_utils.py b/hooks/nova_compute_utils.py index 3d5ec788..338f48f0 100644 --- a/hooks/nova_compute_utils.py +++ b/hooks/nova_compute_utils.py @@ -253,7 +253,6 @@ LIBVIRT_URIS = { # 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'], } @@ -849,6 +848,9 @@ def check_optional_relations(configs): if relation_ids('neutron-plugin'): required_interfaces['neutron-plugin'] = ['neutron-plugin'] + if relation_ids('shared-db') or relation_ids('pgsql-db'): + required_interfaces['database'] = ['shared-db', 'pgsql-db'] + if required_interfaces: set_os_workload_status(configs, required_interfaces) return status_get() From d72ff76017a4c3946c3ee5fcb7f06148ca2b8e34 Mon Sep 17 00:00:00 2001 From: Christopher Glass Date: Wed, 30 Sep 2015 11:23:25 +0200 Subject: [PATCH 19/27] Added a api-rate-limit-rules charm config option controlling the rate-limiting of the nova API. --- config.yaml | 10 +++ hooks/nova_compute_context.py | 9 +++ hooks/nova_compute_utils.py | 5 ++ templates/api-paste.ini | 141 ++++++++++++++++++++++++++++++++++ tests/basic_deployment.py | 15 +++- 5 files changed, 179 insertions(+), 1 deletion(-) create mode 100644 templates/api-paste.ini diff --git a/config.yaml b/config.yaml index 38594672..8e5fe1d4 100644 --- a/config.yaml +++ b/config.yaml @@ -265,3 +265,13 @@ options: description: | The pecentage of system memory to use for hugepages eg '10%' or the total number of 2M hugepages - eg "1024". + api-rate-limit-rules: + type: string + default: + description: | + The API rate-limit rules to use for the deployed nova API, if any. + Contents of this config options will be inserted in the api-paste.ini file + under the "filter:ratelimit" section as "limits". The syntax for these + rules is documented at + http://docs.openstack.org/kilo/config-reference/content/configuring-compute-API.html + diff --git a/hooks/nova_compute_context.py b/hooks/nova_compute_context.py index bcd0e9be..0b2c7e7b 100644 --- a/hooks/nova_compute_context.py +++ b/hooks/nova_compute_context.py @@ -496,3 +496,12 @@ class HostIPContext(context.OSContextGenerator): ctxt['host_ip'] = host_ip return ctxt + + +class APIRateLimitingContext(context.OSContextGenerator): + def __call__(self): + ctxt = {} + rate_rules = config('api-rate-limit-rules') + if rate_rules: + ctxt['api_rate_limit_rules'] = rate_rules + return ctxt diff --git a/hooks/nova_compute_utils.py b/hooks/nova_compute_utils.py index 338f48f0..c0a1761f 100644 --- a/hooks/nova_compute_utils.py +++ b/hooks/nova_compute_utils.py @@ -74,6 +74,7 @@ from nova_compute_context import ( CEPH_CONF, ceph_config_file, HostIPContext, + APIRateLimitingContext ) CA_CERT_PATH = '/usr/local/share/ca-certificates/keystone_juju_ca_cert.crt' @@ -150,6 +151,7 @@ LIBVIRTD_CONF = '/etc/libvirt/libvirtd.conf' LIBVIRT_BIN = '/etc/default/libvirt-bin' LIBVIRT_BIN_OVERRIDES = '/etc/init/libvirt-bin.override' NOVA_CONF = '%s/nova.conf' % NOVA_CONF_DIR +API_PASTE_INI = '%s/api-paste.ini' % NOVA_CONF_DIR BASE_RESOURCE_MAP = { NOVA_CONF: { @@ -175,6 +177,9 @@ BASE_RESOURCE_MAP = { HostIPContext(), context.LogLevelContext()], }, + API_PASTE_INI: { + 'services': ['nova-compute'], + 'contexts': [APIRateLimitingContext]} } LIBVIRT_RESOURCE_MAP = { diff --git a/templates/api-paste.ini b/templates/api-paste.ini new file mode 100644 index 00000000..ff0b9336 --- /dev/null +++ b/templates/api-paste.ini @@ -0,0 +1,141 @@ +############################################################################### +# [ WARNING ] +# Configuration file maintained by Juju. Local changes may be overwritten. +############################################################################### +############ +# Metadata # +############ +[composite:metadata] +use = egg:Paste#urlmap +/: meta + +[pipeline:meta] +pipeline = ec2faultwrap logrequest metaapp + +[app:metaapp] +paste.app_factory = nova.api.metadata.handler:MetadataRequestHandler.factory + +####### +# EC2 # +####### + +[composite:ec2] +use = egg:Paste#urlmap +/: ec2cloud + +[composite:ec2cloud] +use = call:nova.api.auth:pipeline_factory +noauth = ec2faultwrap logrequest ec2noauth cloudrequest validator ec2executor +noauth2 = ec2faultwrap logrequest ec2noauth cloudrequest validator ec2executor +keystone = ec2faultwrap logrequest ec2keystoneauth cloudrequest validator ec2executor + +[filter:ec2faultwrap] +paste.filter_factory = nova.api.ec2:FaultWrapper.factory + +[filter:logrequest] +paste.filter_factory = nova.api.ec2:RequestLogging.factory + +[filter:ec2lockout] +paste.filter_factory = nova.api.ec2:Lockout.factory + +[filter:ec2keystoneauth] +paste.filter_factory = nova.api.ec2:EC2KeystoneAuth.factory + +[filter:ec2noauth] +paste.filter_factory = nova.api.ec2:NoAuth.factory + +[filter:cloudrequest] +controller = nova.api.ec2.cloud.CloudController +paste.filter_factory = nova.api.ec2:Requestify.factory + +[filter:authorizer] +paste.filter_factory = nova.api.ec2:Authorizer.factory + +[filter:validator] +paste.filter_factory = nova.api.ec2:Validator.factory + +[app:ec2executor] +paste.app_factory = nova.api.ec2:Executor.factory + +############# +# OpenStack # +############# + +[composite:osapi_compute] +use = call:nova.api.openstack.urlmap:urlmap_factory +/: oscomputeversions +/v1.1: openstack_compute_api_v2 +/v2: openstack_compute_api_v2 +/v2.1: openstack_compute_api_v21 +/v3: openstack_compute_api_v3 + +[composite:openstack_compute_api_v2] +use = call:nova.api.auth:pipeline_factory +noauth = compute_req_id faultwrap sizelimit noauth ratelimit osapi_compute_app_v2 +noauth2 = compute_req_id faultwrap sizelimit noauth2 ratelimit osapi_compute_app_v2 +keystone = compute_req_id faultwrap sizelimit authtoken keystonecontext ratelimit osapi_compute_app_v2 +keystone_nolimit = compute_req_id faultwrap sizelimit authtoken keystonecontext osapi_compute_app_v2 + +[composite:openstack_compute_api_v21] +use = call:nova.api.auth:pipeline_factory_v21 +noauth = compute_req_id faultwrap sizelimit noauth osapi_compute_app_v21 +noauth2 = compute_req_id faultwrap sizelimit noauth2 osapi_compute_app_v21 +keystone = compute_req_id faultwrap sizelimit authtoken keystonecontext osapi_compute_app_v21 + +[composite:openstack_compute_api_v3] +use = call:nova.api.auth:pipeline_factory_v21 +noauth = request_id faultwrap sizelimit noauth_v3 osapi_compute_app_v3 +noauth2 = request_id faultwrap sizelimit noauth_v3 osapi_compute_app_v3 +keystone = request_id faultwrap sizelimit authtoken keystonecontext osapi_compute_app_v3 + +[filter:request_id] +paste.filter_factory = oslo.middleware:RequestId.factory + +[filter:compute_req_id] +paste.filter_factory = nova.api.compute_req_id:ComputeReqIdMiddleware.factory + +[filter:faultwrap] +paste.filter_factory = nova.api.openstack:FaultWrapper.factory + +[filter:noauth] +paste.filter_factory = nova.api.openstack.auth:NoAuthMiddlewareOld.factory + +[filter:noauth2] +paste.filter_factory = nova.api.openstack.auth:NoAuthMiddleware.factory + +[filter:noauth_v3] +paste.filter_factory = nova.api.openstack.auth:NoAuthMiddlewareV3.factory + +[filter:ratelimit] +paste.filter_factory = nova.api.openstack.compute.limits:RateLimitingMiddleware.factory +{% if api_rate_limit_rules -%} +limits = {{ api_rate_limit_rules}} +{% endif -%} + +[filter:sizelimit] +paste.filter_factory = oslo.middleware:RequestBodySizeLimiter.factory + +[app:osapi_compute_app_v2] +paste.app_factory = nova.api.openstack.compute:APIRouter.factory + +[app:osapi_compute_app_v21] +paste.app_factory = nova.api.openstack.compute:APIRouterV21.factory + +[app:osapi_compute_app_v3] +paste.app_factory = nova.api.openstack.compute:APIRouterV3.factory + +[pipeline:oscomputeversions] +pipeline = faultwrap oscomputeversionapp + +[app:oscomputeversionapp] +paste.app_factory = nova.api.openstack.compute.versions:Versions.factory + +########## +# Shared # +########## + +[filter:keystonecontext] +paste.filter_factory = nova.api.auth:NovaKeystoneContext.factory + +[filter:authtoken] +paste.filter_factory = keystonemiddleware.auth_token:filter_factory diff --git a/tests/basic_deployment.py b/tests/basic_deployment.py index 320eafcc..f3e3b48e 100644 --- a/tests/basic_deployment.py +++ b/tests/basic_deployment.py @@ -68,7 +68,9 @@ class NovaBasicDeployment(OpenStackAmuletDeployment): def _configure_services(self): """Configure all of the services.""" nova_config = {'config-flags': 'auto_assign_floating_ip=False', - 'enable-live-migration': 'False'} + 'enable-live-migration': 'False', + 'api-rate-limit-rules': + '( POST, *, .*, 9999, MINUTE );'} nova_cc_config = {} if self.git: amulet_http_proxy = os.environ.get('AMULET_HTTP_PROXY') @@ -466,6 +468,17 @@ class NovaBasicDeployment(OpenStackAmuletDeployment): message = "nova config error: {}".format(ret) amulet.raise_status(amulet.FAIL, msg=message) + def test_api_paste_config(self): + """Check that the rate limiting is set on the nova api (for POSTs).""" + unit = self.nova_compute_sentry + conf = '/etc/nova/api-paste.ini' + section = "filter:ratelimit" + factory = ("nova.api.openstack.compute.limits:RateLimitingMiddleware" + ".factory") + expected = {"paste.filter_factory": factory, + "limits": "( POST, *, .*, 9999, MINUTE );"} + u.validate_config_data(unit, conf, section, expected) + def test_image_instance_create(self): """Create an image/instance, verify they exist, and delete them.""" # NOTE(coreycb): Skipping failing test on essex until resolved. essex From ee28bb43c5c97b54d2add7b98fb8afc4712aaccb Mon Sep 17 00:00:00 2001 From: Christopher Glass Date: Wed, 30 Sep 2015 11:29:29 +0200 Subject: [PATCH 20/27] Forgot to check the output. --- tests/basic_deployment.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/basic_deployment.py b/tests/basic_deployment.py index f3e3b48e..dcdc33e8 100644 --- a/tests/basic_deployment.py +++ b/tests/basic_deployment.py @@ -477,7 +477,10 @@ class NovaBasicDeployment(OpenStackAmuletDeployment): ".factory") expected = {"paste.filter_factory": factory, "limits": "( POST, *, .*, 9999, MINUTE );"} - u.validate_config_data(unit, conf, section, expected) + ret = u.validate_config_data(unit, conf, section, expected) + if ret: + message = "api paste config error: {}".format(ret) + amulet.raise_status(amulet.FAIL, msg=message) def test_image_instance_create(self): """Create an image/instance, verify they exist, and delete them.""" From 955d5599fa22a51afab59a3a6f76bcab55751b45 Mon Sep 17 00:00:00 2001 From: James Page Date: Thu, 1 Oct 2015 08:57:52 +0100 Subject: [PATCH 21/27] Revert previous commit --- templates/kilo/nova.conf | 3 +++ 1 file changed, 3 insertions(+) diff --git a/templates/kilo/nova.conf b/templates/kilo/nova.conf index db395656..a8f92d18 100644 --- a/templates/kilo/nova.conf +++ b/templates/kilo/nova.conf @@ -46,6 +46,7 @@ novnc_enabled = False {% endif -%} {% if neutron_plugin and neutron_plugin == 'ovs' -%} +libvirt_vif_driver = nova.virt.libvirt.vif.LibvirtGenericVIFDriver {% if neutron_security_groups -%} security_group_api = neutron firewall_driver = nova.virt.firewall.NoopFirewallDriver @@ -54,12 +55,14 @@ firewall_driver = nova.virt.firewall.NoopFirewallDriver {% if neutron_plugin and neutron_plugin == 'vsp' -%} network_api_class=nova.network.neutronv2.api.API +libvirt_vif_driver=nova.virt.libvirt.vif.LibvirtGenericVIFDriver neutron_ovs_bridge=alubr0 security_group_api=nova firewall_driver = nova.virt.firewall.NoopFirewallDriver {% endif -%} {% if neutron_plugin and (neutron_plugin == 'nvp' or neutron_plugin == 'nsx') -%} +libvirt_vif_driver = nova.virt.libvirt.vif.LibvirtOpenVswitchVirtualPortDriver security_group_api = neutron firewall_driver = nova.virt.firewall.NoopFirewallDriver {% endif -%} From cf4893aa7ebcf10c74ef45c2310d42e0b2e70be5 Mon Sep 17 00:00:00 2001 From: Christopher Glass Date: Thu, 1 Oct 2015 17:07:37 +0200 Subject: [PATCH 22/27] Fixing iterable idiocy. --- hooks/nova_compute_utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hooks/nova_compute_utils.py b/hooks/nova_compute_utils.py index c0a1761f..ffc38532 100644 --- a/hooks/nova_compute_utils.py +++ b/hooks/nova_compute_utils.py @@ -179,7 +179,7 @@ BASE_RESOURCE_MAP = { }, API_PASTE_INI: { 'services': ['nova-compute'], - 'contexts': [APIRateLimitingContext]} + 'contexts': [APIRateLimitingContext()]} } LIBVIRT_RESOURCE_MAP = { From 6c58e72f323a44c04c96acf34fc122d740677f0c Mon Sep 17 00:00:00 2001 From: James Page Date: Thu, 1 Oct 2015 18:01:21 +0100 Subject: [PATCH 23/27] Fixup unit tests --- unit_tests/test_nova_compute_utils.py | 19 ++----------------- 1 file changed, 2 insertions(+), 17 deletions(-) diff --git a/unit_tests/test_nova_compute_utils.py b/unit_tests/test_nova_compute_utils.py index 878045ab..fd9440ca 100644 --- a/unit_tests/test_nova_compute_utils.py +++ b/unit_tests/test_nova_compute_utils.py @@ -463,37 +463,22 @@ class NovaComputeUtilsTests(CharmTestCase): compute_context.CEPH_SECRET_UUID, '--base64', key]) - @patch.object(utils, 'check_call') - @patch.object(utils, 'check_output') - def test_configure_lxd_daemon(self, _check_output, _check_call): - self.test_config.set('virt-type', 'lxd') - utils.configure_lxd_daemon('nova') - self.add_user_to_group.assert_called_with('nova', 'lxd') - self.service_restart.assert_called_with('lxd') - _check_output.assert_called_wth(['sudo', '-u', 'nova', 'lxc', 'list']) - - @patch.object(utils, 'configure_lxd_daemon') @patch.object(utils, 'configure_subuid') - def test_configure_lxd_vivid(self, _configure_subuid, - _configure_lxd_daemon): + def test_configure_lxd_vivid(self, _configure_subuid): self.lsb_release.return_value = { 'DISTRIB_CODENAME': 'vivid' } utils.configure_lxd('nova') _configure_subuid.assert_called_with(user='nova') - _configure_lxd_daemon.assert_called_with(user='nova') - @patch.object(utils, 'configure_lxd_daemon') @patch.object(utils, 'configure_subuid') - def test_configure_lxd_pre_vivid(self, _configure_subuid, - _configure_lxd_daemon): + def test_configure_lxd_pre_vivid(self, _configure_subuid): self.lsb_release.return_value = { 'DISTRIB_CODENAME': 'trusty' } with self.assertRaises(Exception): utils.configure_lxd('nova') self.assertFalse(_configure_subuid.called) - self.assertFalse(_configure_lxd_daemon.called) def test_enable_nova_metadata(self): class DummyContext(): From f756705e8f4e5f6a60c483121b1fd6ec00098c38 Mon Sep 17 00:00:00 2001 From: James Page Date: Thu, 1 Oct 2015 18:04:09 +0100 Subject: [PATCH 24/27] Fixup lint --- hooks/nova_compute_utils.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/hooks/nova_compute_utils.py b/hooks/nova_compute_utils.py index 72c4babb..e7120f5f 100644 --- a/hooks/nova_compute_utils.py +++ b/hooks/nova_compute_utils.py @@ -6,8 +6,6 @@ import subprocess from base64 import b64decode from copy import deepcopy from subprocess import ( - PIPE, - Popen, check_call, check_output, CalledProcessError From 883ecb3892a4c247d8dcf6b2a48bfc96627b1b24 Mon Sep 17 00:00:00 2001 From: Christopher Glass Date: Fri, 2 Oct 2015 11:40:38 +0200 Subject: [PATCH 25/27] Reverting previous merge - the amulet tests broke on Precise. Investigating. --- config.yaml | 10 --- hooks/nova_compute_context.py | 9 --- hooks/nova_compute_utils.py | 5 -- templates/api-paste.ini | 141 ---------------------------------- tests/basic_deployment.py | 18 +---- 5 files changed, 1 insertion(+), 182 deletions(-) delete mode 100644 templates/api-paste.ini diff --git a/config.yaml b/config.yaml index 8e5fe1d4..38594672 100644 --- a/config.yaml +++ b/config.yaml @@ -265,13 +265,3 @@ options: description: | The pecentage of system memory to use for hugepages eg '10%' or the total number of 2M hugepages - eg "1024". - api-rate-limit-rules: - type: string - default: - description: | - The API rate-limit rules to use for the deployed nova API, if any. - Contents of this config options will be inserted in the api-paste.ini file - under the "filter:ratelimit" section as "limits". The syntax for these - rules is documented at - http://docs.openstack.org/kilo/config-reference/content/configuring-compute-API.html - diff --git a/hooks/nova_compute_context.py b/hooks/nova_compute_context.py index 0b2c7e7b..bcd0e9be 100644 --- a/hooks/nova_compute_context.py +++ b/hooks/nova_compute_context.py @@ -496,12 +496,3 @@ class HostIPContext(context.OSContextGenerator): ctxt['host_ip'] = host_ip return ctxt - - -class APIRateLimitingContext(context.OSContextGenerator): - def __call__(self): - ctxt = {} - rate_rules = config('api-rate-limit-rules') - if rate_rules: - ctxt['api_rate_limit_rules'] = rate_rules - return ctxt diff --git a/hooks/nova_compute_utils.py b/hooks/nova_compute_utils.py index ffc38532..338f48f0 100644 --- a/hooks/nova_compute_utils.py +++ b/hooks/nova_compute_utils.py @@ -74,7 +74,6 @@ from nova_compute_context import ( CEPH_CONF, ceph_config_file, HostIPContext, - APIRateLimitingContext ) CA_CERT_PATH = '/usr/local/share/ca-certificates/keystone_juju_ca_cert.crt' @@ -151,7 +150,6 @@ LIBVIRTD_CONF = '/etc/libvirt/libvirtd.conf' LIBVIRT_BIN = '/etc/default/libvirt-bin' LIBVIRT_BIN_OVERRIDES = '/etc/init/libvirt-bin.override' NOVA_CONF = '%s/nova.conf' % NOVA_CONF_DIR -API_PASTE_INI = '%s/api-paste.ini' % NOVA_CONF_DIR BASE_RESOURCE_MAP = { NOVA_CONF: { @@ -177,9 +175,6 @@ BASE_RESOURCE_MAP = { HostIPContext(), context.LogLevelContext()], }, - API_PASTE_INI: { - 'services': ['nova-compute'], - 'contexts': [APIRateLimitingContext()]} } LIBVIRT_RESOURCE_MAP = { diff --git a/templates/api-paste.ini b/templates/api-paste.ini deleted file mode 100644 index ff0b9336..00000000 --- a/templates/api-paste.ini +++ /dev/null @@ -1,141 +0,0 @@ -############################################################################### -# [ WARNING ] -# Configuration file maintained by Juju. Local changes may be overwritten. -############################################################################### -############ -# Metadata # -############ -[composite:metadata] -use = egg:Paste#urlmap -/: meta - -[pipeline:meta] -pipeline = ec2faultwrap logrequest metaapp - -[app:metaapp] -paste.app_factory = nova.api.metadata.handler:MetadataRequestHandler.factory - -####### -# EC2 # -####### - -[composite:ec2] -use = egg:Paste#urlmap -/: ec2cloud - -[composite:ec2cloud] -use = call:nova.api.auth:pipeline_factory -noauth = ec2faultwrap logrequest ec2noauth cloudrequest validator ec2executor -noauth2 = ec2faultwrap logrequest ec2noauth cloudrequest validator ec2executor -keystone = ec2faultwrap logrequest ec2keystoneauth cloudrequest validator ec2executor - -[filter:ec2faultwrap] -paste.filter_factory = nova.api.ec2:FaultWrapper.factory - -[filter:logrequest] -paste.filter_factory = nova.api.ec2:RequestLogging.factory - -[filter:ec2lockout] -paste.filter_factory = nova.api.ec2:Lockout.factory - -[filter:ec2keystoneauth] -paste.filter_factory = nova.api.ec2:EC2KeystoneAuth.factory - -[filter:ec2noauth] -paste.filter_factory = nova.api.ec2:NoAuth.factory - -[filter:cloudrequest] -controller = nova.api.ec2.cloud.CloudController -paste.filter_factory = nova.api.ec2:Requestify.factory - -[filter:authorizer] -paste.filter_factory = nova.api.ec2:Authorizer.factory - -[filter:validator] -paste.filter_factory = nova.api.ec2:Validator.factory - -[app:ec2executor] -paste.app_factory = nova.api.ec2:Executor.factory - -############# -# OpenStack # -############# - -[composite:osapi_compute] -use = call:nova.api.openstack.urlmap:urlmap_factory -/: oscomputeversions -/v1.1: openstack_compute_api_v2 -/v2: openstack_compute_api_v2 -/v2.1: openstack_compute_api_v21 -/v3: openstack_compute_api_v3 - -[composite:openstack_compute_api_v2] -use = call:nova.api.auth:pipeline_factory -noauth = compute_req_id faultwrap sizelimit noauth ratelimit osapi_compute_app_v2 -noauth2 = compute_req_id faultwrap sizelimit noauth2 ratelimit osapi_compute_app_v2 -keystone = compute_req_id faultwrap sizelimit authtoken keystonecontext ratelimit osapi_compute_app_v2 -keystone_nolimit = compute_req_id faultwrap sizelimit authtoken keystonecontext osapi_compute_app_v2 - -[composite:openstack_compute_api_v21] -use = call:nova.api.auth:pipeline_factory_v21 -noauth = compute_req_id faultwrap sizelimit noauth osapi_compute_app_v21 -noauth2 = compute_req_id faultwrap sizelimit noauth2 osapi_compute_app_v21 -keystone = compute_req_id faultwrap sizelimit authtoken keystonecontext osapi_compute_app_v21 - -[composite:openstack_compute_api_v3] -use = call:nova.api.auth:pipeline_factory_v21 -noauth = request_id faultwrap sizelimit noauth_v3 osapi_compute_app_v3 -noauth2 = request_id faultwrap sizelimit noauth_v3 osapi_compute_app_v3 -keystone = request_id faultwrap sizelimit authtoken keystonecontext osapi_compute_app_v3 - -[filter:request_id] -paste.filter_factory = oslo.middleware:RequestId.factory - -[filter:compute_req_id] -paste.filter_factory = nova.api.compute_req_id:ComputeReqIdMiddleware.factory - -[filter:faultwrap] -paste.filter_factory = nova.api.openstack:FaultWrapper.factory - -[filter:noauth] -paste.filter_factory = nova.api.openstack.auth:NoAuthMiddlewareOld.factory - -[filter:noauth2] -paste.filter_factory = nova.api.openstack.auth:NoAuthMiddleware.factory - -[filter:noauth_v3] -paste.filter_factory = nova.api.openstack.auth:NoAuthMiddlewareV3.factory - -[filter:ratelimit] -paste.filter_factory = nova.api.openstack.compute.limits:RateLimitingMiddleware.factory -{% if api_rate_limit_rules -%} -limits = {{ api_rate_limit_rules}} -{% endif -%} - -[filter:sizelimit] -paste.filter_factory = oslo.middleware:RequestBodySizeLimiter.factory - -[app:osapi_compute_app_v2] -paste.app_factory = nova.api.openstack.compute:APIRouter.factory - -[app:osapi_compute_app_v21] -paste.app_factory = nova.api.openstack.compute:APIRouterV21.factory - -[app:osapi_compute_app_v3] -paste.app_factory = nova.api.openstack.compute:APIRouterV3.factory - -[pipeline:oscomputeversions] -pipeline = faultwrap oscomputeversionapp - -[app:oscomputeversionapp] -paste.app_factory = nova.api.openstack.compute.versions:Versions.factory - -########## -# Shared # -########## - -[filter:keystonecontext] -paste.filter_factory = nova.api.auth:NovaKeystoneContext.factory - -[filter:authtoken] -paste.filter_factory = keystonemiddleware.auth_token:filter_factory diff --git a/tests/basic_deployment.py b/tests/basic_deployment.py index dcdc33e8..320eafcc 100644 --- a/tests/basic_deployment.py +++ b/tests/basic_deployment.py @@ -68,9 +68,7 @@ class NovaBasicDeployment(OpenStackAmuletDeployment): def _configure_services(self): """Configure all of the services.""" nova_config = {'config-flags': 'auto_assign_floating_ip=False', - 'enable-live-migration': 'False', - 'api-rate-limit-rules': - '( POST, *, .*, 9999, MINUTE );'} + 'enable-live-migration': 'False'} nova_cc_config = {} if self.git: amulet_http_proxy = os.environ.get('AMULET_HTTP_PROXY') @@ -468,20 +466,6 @@ class NovaBasicDeployment(OpenStackAmuletDeployment): message = "nova config error: {}".format(ret) amulet.raise_status(amulet.FAIL, msg=message) - def test_api_paste_config(self): - """Check that the rate limiting is set on the nova api (for POSTs).""" - unit = self.nova_compute_sentry - conf = '/etc/nova/api-paste.ini' - section = "filter:ratelimit" - factory = ("nova.api.openstack.compute.limits:RateLimitingMiddleware" - ".factory") - expected = {"paste.filter_factory": factory, - "limits": "( POST, *, .*, 9999, MINUTE );"} - ret = u.validate_config_data(unit, conf, section, expected) - if ret: - message = "api paste config error: {}".format(ret) - amulet.raise_status(amulet.FAIL, msg=message) - def test_image_instance_create(self): """Create an image/instance, verify they exist, and delete them.""" # NOTE(coreycb): Skipping failing test on essex until resolved. essex From d58138ff59f986adaaff7225df639a1445a0b022 Mon Sep 17 00:00:00 2001 From: David Ames Date: Fri, 2 Oct 2015 14:36:48 -0700 Subject: [PATCH 26/27] [thedac, trivial] s/message/messaging --- hooks/nova_compute_utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hooks/nova_compute_utils.py b/hooks/nova_compute_utils.py index eaec4a09..a9045ee0 100644 --- a/hooks/nova_compute_utils.py +++ b/hooks/nova_compute_utils.py @@ -263,7 +263,7 @@ LIBVIRT_URIS = { # The interface is said to be satisfied if anyone of the interfaces in the # list has a complete context. REQUIRED_INTERFACES = { - 'message': ['amqp', 'zeromq-configuration'], + 'messaging': ['amqp', 'zeromq-configuration'], 'image': ['image-service'], } From 391e84e6c490f6efc945d5ff653950d6680acba8 Mon Sep 17 00:00:00 2001 From: James Page Date: Tue, 6 Oct 2015 10:04:58 +0100 Subject: [PATCH 27/27] [trivial] Fixup failing LXD unit tests, refactor invalid assert calls --- unit_tests/test_nova_compute_hooks.py | 9 ++++----- unit_tests/test_nova_compute_utils.py | 12 +++++++++--- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/unit_tests/test_nova_compute_hooks.py b/unit_tests/test_nova_compute_hooks.py index 70440773..c8438705 100644 --- a/unit_tests/test_nova_compute_hooks.py +++ b/unit_tests/test_nova_compute_hooks.py @@ -82,7 +82,7 @@ class NovaComputeRelationsTests(CharmTestCase): self.configure_installation_source.assert_called_with(repo) self.assertTrue(self.apt_update.called) self.apt_install.assert_called_with(['foo', 'bar'], fatal=True) - self.execd_preinstall.assert_called() + self.assertTrue(self.execd_preinstall.called) def test_install_hook_git(self): self.git_install_requested.return_value = True @@ -107,7 +107,7 @@ class NovaComputeRelationsTests(CharmTestCase): self.assertTrue(self.apt_update.called) self.apt_install.assert_called_with(['foo', 'bar'], fatal=True) self.git_install.assert_called_with(projects_yaml) - self.execd_preinstall.assert_called() + self.assertTrue(self.execd_preinstall.called) def test_config_changed_with_upgrade(self): self.git_install_requested.return_value = False @@ -185,7 +185,7 @@ class NovaComputeRelationsTests(CharmTestCase): self.git_install_requested.return_value = False self.test_config.set('sysctl', '{ kernel.max_pid : "1337" }') hooks.config_changed() - self.create_sysctl.assert_called() + self.assertTrue(self.create_sysctl.called) @patch.object(hooks, 'config_value_changed') def test_config_changed_git(self, config_val_changed): @@ -226,7 +226,7 @@ class NovaComputeRelationsTests(CharmTestCase): self.migration_enabled.return_value = False self.is_relation_made.return_value = True hooks.config_changed() - self.update_nrpe_config.assert_called_once() + self.assertTrue(self.update_nrpe_config.called) def test_amqp_joined(self): hooks.amqp_joined() @@ -369,7 +369,6 @@ class NovaComputeRelationsTests(CharmTestCase): def test_compute_joined_no_migration_no_resize(self): self.migration_enabled.return_value = False hooks.compute_joined() - self.relation_set.assertCalledWith(hostname='arm') self.assertFalse(self.relation_set.called) def test_compute_joined_with_ssh_migration(self): diff --git a/unit_tests/test_nova_compute_utils.py b/unit_tests/test_nova_compute_utils.py index fd9440ca..e367df28 100644 --- a/unit_tests/test_nova_compute_utils.py +++ b/unit_tests/test_nova_compute_utils.py @@ -463,16 +463,22 @@ class NovaComputeUtilsTests(CharmTestCase): compute_context.CEPH_SECRET_UUID, '--base64', key]) + @patch.object(utils, 'lxc_list') @patch.object(utils, 'configure_subuid') - def test_configure_lxd_vivid(self, _configure_subuid): + def test_configure_lxd_vivid(self, _configure_subuid, _lxc_list): self.lsb_release.return_value = { 'DISTRIB_CODENAME': 'vivid' } utils.configure_lxd('nova') - _configure_subuid.assert_called_with(user='nova') + _configure_subuid.assert_called_with('nova') + _lxc_list.assert_called_with('nova') + @patch.object(utils, 'git_install_requested') + @patch.object(utils, 'lxc_list') @patch.object(utils, 'configure_subuid') - def test_configure_lxd_pre_vivid(self, _configure_subuid): + def test_configure_lxd_pre_vivid(self, _configure_subuid, _lxc_list, + _git_install): + _git_install.return_value = False self.lsb_release.return_value = { 'DISTRIB_CODENAME': 'trusty' }