Add snap support
Update core charms.openstack classes to support installation from snap as an alternative to installation from deb packages. Introduce a new property 'package_type' supported on the OpenStackCharm base class which can be set to 'deb' (default) or 'snap' to indicate which type of install a specific OpenStackCharm subclass supports. The list of snaps is detailed in the 'snaps' property, and the mode for installation of snaps is configured using the 'snap_mode' property; as for packages, a specific snap can be chosen to drive the application version that is used for the deployed workload. This is supported by an additional default package type selector which, in conjunction with the existing release selector, will pick the correct subclass of the OpenStackCharm class to use for the configured installation source. Snap installation is configured using the openstack-origin charm configuration option - for example: openstack-origin=snap:ocata/stable If no suitable class can be discovered for the configured origin, the charm will throw an error as it does today for missing openstack release support for deb based installations. The linked gerrit review is the first charm implementation of snap support based on these set of changes. Required-By: I464025a2b72aba8c31a4a97ade39d2b2980c3a92 Change-Id: Iea33a939a6422da94d3c2c5b9a0748a47bfde11a
This commit is contained in:
parent
42ee4248b7
commit
43f32232aa
|
@ -660,6 +660,14 @@ class APIConfigurationAdapter(ConfigurationAdapter):
|
|||
"""
|
||||
return charms.reactive.bus.get_state('ssl.enabled')
|
||||
|
||||
@property
|
||||
def ssl(self):
|
||||
"""Whether SSL is being used for this service
|
||||
|
||||
@return True is SSL has been enable
|
||||
"""
|
||||
return charms.reactive.bus.get_state('ssl.enabled')
|
||||
|
||||
def determine_service_port(self, port):
|
||||
"""Calculate port service should use given external port
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@ from charms_openstack.charm.core import (
|
|||
BaseOpenStackCharm,
|
||||
BaseOpenStackCharmActions,
|
||||
BaseOpenStackCharmAssessStatus,
|
||||
get_snap_version,
|
||||
)
|
||||
from charms_openstack.charm.utils import (
|
||||
get_upstream_version,
|
||||
|
@ -50,15 +51,28 @@ class OpenStackCharm(BaseOpenStackCharm,
|
|||
# first_release = this is the first release in which this charm works
|
||||
release = 'icehouse'
|
||||
|
||||
# package type - package type (deb or snap) in which this charm works
|
||||
package_type = 'deb'
|
||||
|
||||
# The name of the charm (for printing, etc.)
|
||||
name = 'charmname'
|
||||
|
||||
# List of packages to install
|
||||
packages = []
|
||||
|
||||
# List of snaps to install
|
||||
snaps = []
|
||||
|
||||
# Mode to install snaps in (jailmode/devmode/classic)
|
||||
snap_mode = 'jailmode'
|
||||
|
||||
# Package to determine application version from
|
||||
# defaults to first in packages if not provided
|
||||
version_package = None
|
||||
version_package = release_pkg = None
|
||||
|
||||
# Snap to determine application version from;
|
||||
# defaults to first in snaps if not provided
|
||||
version_snap = release_snap = None
|
||||
|
||||
# Keystone endpoint type
|
||||
service_type = None
|
||||
|
@ -121,15 +135,26 @@ class OpenStackCharm(BaseOpenStackCharm,
|
|||
@property
|
||||
def application_version(self):
|
||||
"""Return the current version of the application being deployed by
|
||||
the charm, as indicated by the version_package attribute
|
||||
the charm, as indicated by the version_package or version_snap
|
||||
attribute
|
||||
"""
|
||||
if not self.version_package:
|
||||
self.version_package = self.packages[0]
|
||||
version = get_upstream_version(
|
||||
self.version_package
|
||||
)
|
||||
if not version:
|
||||
version = os_utils.os_release(self.version_package)
|
||||
if os_utils.snap_install_requested():
|
||||
if not self.version_snap:
|
||||
self.version_snap = self.snaps[0]
|
||||
version = get_snap_version(self.version_snap,
|
||||
fatal=False)
|
||||
if not version:
|
||||
version = os_utils.get_os_codename_install_source(
|
||||
self.config['openstack-origin']
|
||||
)
|
||||
else:
|
||||
if not self.version_package:
|
||||
self.version_package = self.packages[0]
|
||||
version = get_upstream_version(
|
||||
self.version_package
|
||||
)
|
||||
if not version:
|
||||
version = os_utils.os_release(self.version_package)
|
||||
return version
|
||||
|
||||
|
||||
|
@ -250,6 +275,14 @@ class OpenStackAPICharm(OpenStackCharm):
|
|||
return (super(OpenStackAPICharm, self).all_packages +
|
||||
self.token_cache_pkgs())
|
||||
|
||||
@property
|
||||
def all_snaps(self):
|
||||
"""List of snaps to be installed
|
||||
|
||||
@return ['snap1', 'snap2', ...]
|
||||
"""
|
||||
return super().all_snaps
|
||||
|
||||
@property
|
||||
def full_restart_map(self):
|
||||
"""Map of services to be restarted if a file changes
|
||||
|
@ -278,7 +311,7 @@ class HAOpenStackCharm(OpenStackAPICharm):
|
|||
self.set_haproxy_stat_password()
|
||||
|
||||
@property
|
||||
def apache_vhost_file(self):
|
||||
def apache_ssl_vhost_file(self):
|
||||
"""Apache vhost for SSL termination
|
||||
|
||||
:returns: string
|
||||
|
@ -291,8 +324,8 @@ class HAOpenStackCharm(OpenStackAPICharm):
|
|||
Enable Apache vhost for SSL termination if vhost exists and it is not
|
||||
curently enabled
|
||||
"""
|
||||
if not os.path.exists(self.apache_vhost_file):
|
||||
open(self.apache_vhost_file, 'a').close()
|
||||
if not os.path.exists(self.apache_ssl_vhost_file):
|
||||
open(self.apache_ssl_vhost_file, 'a').close()
|
||||
|
||||
check_enabled = subprocess.call(
|
||||
['a2query', '-s', 'openstack_https_frontend'])
|
||||
|
@ -315,10 +348,20 @@ class HAOpenStackCharm(OpenStackAPICharm):
|
|||
_packages = super(HAOpenStackCharm, self).all_packages
|
||||
if self.haproxy_enabled():
|
||||
_packages.append('haproxy')
|
||||
if self.apache_enabled():
|
||||
_packages.append('apache2')
|
||||
if not os_utils.snap_install_requested():
|
||||
if self.apache_enabled():
|
||||
_packages.append('apache2')
|
||||
return _packages
|
||||
|
||||
@property
|
||||
def all_snaps(self):
|
||||
"""List of snaps to be installed
|
||||
|
||||
@return ['snap1', 'snap2', ...]
|
||||
"""
|
||||
_snaps = super().all_snaps
|
||||
return _snaps
|
||||
|
||||
@property
|
||||
def full_restart_map(self):
|
||||
"""Map of services to be restarted if a file changes
|
||||
|
@ -332,16 +375,33 @@ class HAOpenStackCharm(OpenStackAPICharm):
|
|||
_restart_map = super(HAOpenStackCharm, self).full_restart_map
|
||||
if self.haproxy_enabled():
|
||||
_restart_map[self.HAPROXY_CONF] = ['haproxy']
|
||||
if self.apache_enabled():
|
||||
_restart_map[self.apache_vhost_file] = ['apache2']
|
||||
if os_utils.snap_install_requested():
|
||||
# TODO(coreycb): add nginx config/service for ssl vhost
|
||||
pass
|
||||
else:
|
||||
if self.apache_enabled():
|
||||
_restart_map[self.apache_ssl_vhost_file] = ['apache2']
|
||||
return _restart_map
|
||||
|
||||
def apache_enabled(self):
|
||||
"""Determine if apache is being used
|
||||
|
||||
@return True if apache is being used"""
|
||||
return (self.get_state('ssl.enabled') or
|
||||
self.get_state('ssl.requested'))
|
||||
if os_utils.snap_install_requested():
|
||||
return False
|
||||
else:
|
||||
return (self.get_state('ssl.enabled') or
|
||||
self.get_state('ssl.requested'))
|
||||
|
||||
def nginx_ssl_enabled(self):
|
||||
"""Determine if nginx is being used
|
||||
|
||||
@return True if nginx is being used"""
|
||||
if os_utils.snap_install_requested():
|
||||
return (self.get_state('ssl.enabled') or
|
||||
self.get_state('ssl.requested'))
|
||||
else:
|
||||
return False
|
||||
|
||||
def haproxy_enabled(self):
|
||||
"""Determine if haproxy is fronting the services
|
||||
|
@ -394,6 +454,8 @@ class HAOpenStackCharm(OpenStackAPICharm):
|
|||
|
||||
def enable_apache_modules(self):
|
||||
"""Enable Apache modules needed for SSL termination"""
|
||||
if os_utils.snap_install_requested():
|
||||
return
|
||||
restart = False
|
||||
for module in ['ssl', 'proxy', 'proxy_http']:
|
||||
check_enabled = subprocess.call(['a2query', '-m', module])
|
||||
|
@ -412,9 +474,14 @@ class HAOpenStackCharm(OpenStackAPICharm):
|
|||
@param key string SSL Key
|
||||
@param cn string Canonical name for service
|
||||
"""
|
||||
if os_utils.snap_install_requested():
|
||||
ssl_dir = '/var/snap/{snap_name}/etc/nginx/ssl'.format(
|
||||
snap_name=self.primary_snap)
|
||||
else:
|
||||
ssl_dir = os.path.join('/etc/apache2/ssl/', self.name)
|
||||
|
||||
if not cn:
|
||||
cn = os_ip.resolve_address(endpoint_type=os_ip.INTERNAL)
|
||||
ssl_dir = os.path.join('/etc/apache2/ssl/', self.name)
|
||||
ch_host.mkdir(path=ssl_dir)
|
||||
if cn:
|
||||
cert_filename = 'cert_{}'.format(cn)
|
||||
|
@ -535,7 +602,10 @@ class HAOpenStackCharm(OpenStackAPICharm):
|
|||
self.configure_cert(
|
||||
ssl['cert'], ssl['key'], cn=ssl['cn'])
|
||||
self.configure_ca(ssl['ca'])
|
||||
self.configure_apache()
|
||||
|
||||
if not os_utils.snap_install_requested():
|
||||
self.configure_apache()
|
||||
|
||||
self.remove_state('ssl.requested')
|
||||
self.set_state('ssl.enabled', True)
|
||||
else:
|
||||
|
@ -563,6 +633,7 @@ class HAOpenStackCharm(OpenStackAPICharm):
|
|||
|
||||
def configure_ca(self, ca_cert, update_certs=True):
|
||||
"""Write Certificate Authority certificate"""
|
||||
# TODO(jamespage): work this out for snap based installations
|
||||
cert_file = (
|
||||
'/usr/local/share/ca-certificates/keystone_juju_ca_cert.crt')
|
||||
if ca_cert:
|
||||
|
|
|
@ -36,6 +36,12 @@ _singleton = None
|
|||
# This is to enable the defining code to define which release is used.
|
||||
_release_selector_function = None
|
||||
|
||||
# `_package_type_selector_function` holds a function that optionally takes a
|
||||
# package type and commutes it to another package type or just returns a
|
||||
# package type. This is to enable the defining code to define which
|
||||
# package type is used.
|
||||
_package_type_selector_function = None
|
||||
|
||||
|
||||
def optional_interfaces(args, *interfaces):
|
||||
"""Return a tuple with possible optional interfaces
|
||||
|
@ -85,7 +91,7 @@ class provide_charm_instance(object):
|
|||
return False
|
||||
|
||||
|
||||
def get_charm_instance(release=None, *args, **kwargs):
|
||||
def get_charm_instance(release=None, package_type='deb', *args, **kwargs):
|
||||
"""Get an instance of the charm based on the release (or use the
|
||||
default if release is None).
|
||||
|
||||
|
@ -96,17 +102,18 @@ def get_charm_instance(release=None, *args, **kwargs):
|
|||
Note that it passes args and kwargs to the class __init__() method.
|
||||
|
||||
:param release: lc string representing release wanted.
|
||||
:param package_type: string representing the package type required
|
||||
:returns: BaseOpenStackCharm() derived class according to cls.releases
|
||||
"""
|
||||
if len(_releases.keys()) == 0:
|
||||
raise RuntimeError(
|
||||
"No derived BaseOpenStackCharm() classes registered")
|
||||
# Note that this relies on OS releases being in alphabetica order
|
||||
# Note that this relies on OS releases being in alphabetical order
|
||||
known_releases = sorted(_releases.keys())
|
||||
cls = None
|
||||
if release is None:
|
||||
# take the latest version of the charm if no release is passed.
|
||||
cls = _releases[known_releases[-1]]
|
||||
cls = _releases[known_releases[-1]][package_type]
|
||||
else:
|
||||
# check that the release is a valid release
|
||||
if release not in os_utils.OPENSTACK_RELEASES:
|
||||
|
@ -122,8 +129,9 @@ def get_charm_instance(release=None, *args, **kwargs):
|
|||
# try to find the release that is supported.
|
||||
for known_release in reversed(known_releases):
|
||||
if (release_index >=
|
||||
os_utils.OPENSTACK_RELEASES.index(known_release)):
|
||||
cls = _releases[known_release]
|
||||
os_utils.OPENSTACK_RELEASES.index(known_release) and
|
||||
package_type in _releases[known_release]):
|
||||
cls = _releases[known_release][package_type]
|
||||
break
|
||||
if cls is None:
|
||||
raise RuntimeError("Release {} is not supported".format(release))
|
||||
|
@ -154,6 +162,57 @@ def register_os_release_selector(f):
|
|||
return f
|
||||
|
||||
|
||||
def register_package_type_selector(f):
|
||||
"""Register a function that determines what the package type is for the
|
||||
invocation run. This allows the charm to define HOW the package type is
|
||||
determined.
|
||||
|
||||
Usage:
|
||||
|
||||
@register_package_type_selector
|
||||
def my_package_type_selector():
|
||||
return package_type_chooser()
|
||||
|
||||
The function should return a string which is 'snap' or 'deb'.
|
||||
"""
|
||||
global _package_type_selector_function
|
||||
if _package_type_selector_function is None:
|
||||
# we can only do this once in a system invocation.
|
||||
_package_type_selector_function = f
|
||||
else:
|
||||
raise RuntimeError(
|
||||
"Only a single package_type_selector_function is supported."
|
||||
" Called with {}".format(f.__name__))
|
||||
return f
|
||||
|
||||
|
||||
# TODO(jamespage): move to snap charmhelper
|
||||
def get_snap_version(snap, fatal=True):
|
||||
"""Determine version for an installed snap.
|
||||
|
||||
:param package: str Snap name to lookup (ie. in snap list)
|
||||
:param fatal: bool Raise exception if snap not installed
|
||||
:returns: str version of snap installed
|
||||
"""
|
||||
cmd = ['snap', 'list', snap]
|
||||
try:
|
||||
out = subprocess.check_output(cmd).decode('UTF-8')
|
||||
except subprocess.CalledProcessError:
|
||||
if not fatal:
|
||||
return None
|
||||
# the snap is unknown to snapd
|
||||
e = ('Could not determine version of snap: {} as it\'s'
|
||||
' not installed'.format(snap))
|
||||
raise Exception(e)
|
||||
|
||||
lines = out.splitlines()
|
||||
for line in lines:
|
||||
if snap in line:
|
||||
# Second item in list is version or a codename
|
||||
return line.split()[1]
|
||||
return None
|
||||
|
||||
|
||||
class BaseOpenStackCharmMeta(type):
|
||||
"""Metaclass to provide a classproperty of 'singleton' so that class
|
||||
methods in the derived BaseOpenStackCharm() class can simply use
|
||||
|
@ -190,18 +249,28 @@ class BaseOpenStackCharmMeta(type):
|
|||
if members.get('abstract_class', False):
|
||||
return
|
||||
if 'release' in members.keys():
|
||||
package_type = members.get('package_type', 'deb')
|
||||
if package_type not in ('deb', 'snap'):
|
||||
raise RuntimeError(
|
||||
"Package type {} is not a known type"
|
||||
.format(package_type))
|
||||
release = members['release']
|
||||
if release not in os_utils.OPENSTACK_RELEASES:
|
||||
raise RuntimeError(
|
||||
"Release {} is not a known OpenStack release"
|
||||
.format(release))
|
||||
if release in _releases.keys():
|
||||
if (release in _releases.keys() and
|
||||
package_type in _releases[release].keys()):
|
||||
raise RuntimeError(
|
||||
"Release {} defined more than once in classes {} and {} "
|
||||
" (at least)"
|
||||
.format(release, _releases[release].__name__, name))
|
||||
.format(release,
|
||||
_releases[release][package_type].__name__,
|
||||
name))
|
||||
# store the class against the release.
|
||||
_releases[release] = cls
|
||||
if release not in _releases:
|
||||
_releases[release] = {}
|
||||
_releases[release][package_type] = cls
|
||||
else:
|
||||
raise RuntimeError(
|
||||
"class '{}' does not define a release that it supports. "
|
||||
|
@ -218,10 +287,14 @@ class BaseOpenStackCharmMeta(type):
|
|||
global _singleton
|
||||
if _singleton is None:
|
||||
release = None
|
||||
package_type = None
|
||||
# see if a _release_selector_function has been registered.
|
||||
if _release_selector_function is not None:
|
||||
release = _release_selector_function()
|
||||
_singleton = get_charm_instance(release=release)
|
||||
if _package_type_selector_function is not None:
|
||||
package_type = _package_type_selector_function()
|
||||
_singleton = get_charm_instance(release=release,
|
||||
package_type=package_type or 'deb')
|
||||
return _singleton
|
||||
|
||||
|
||||
|
@ -347,12 +420,48 @@ class BaseOpenStackCharm(object, metaclass=BaseOpenStackCharmMeta):
|
|||
"""proxy for charms.reactive.bus.get_state()"""
|
||||
return reactive.bus.get_state(state)
|
||||
|
||||
@staticmethod
|
||||
def get_os_codename_snap(snap, codenames, fatal=True):
|
||||
"""Derive OpenStack release codename from an installed snap.
|
||||
|
||||
:param package: str Snap name to lookup (ie. in snap list)
|
||||
:param codenames: dict of OrderedDict
|
||||
{
|
||||
'snap1': collections.OrderedDict([
|
||||
('2', 'mitaka'),
|
||||
('3', 'newton'),
|
||||
('4', 'ocata'), ]),
|
||||
'snap2': collections.OrderedDict([
|
||||
('12', 'mitaka'),
|
||||
('13', 'newton'),
|
||||
('14', 'ocata'), ]),
|
||||
}
|
||||
:param fatal: bool Raise exception if snap not installed
|
||||
:returns: str OpenStack version name corresponding to package
|
||||
"""
|
||||
version_or_codename = get_snap_version(snap, fatal)
|
||||
|
||||
match = re.match('^(\d+)\.(\d+)', version_or_codename)
|
||||
if match:
|
||||
version = match.group(0)
|
||||
# Generate a major version number for newer semantic
|
||||
# versions of openstack projects
|
||||
major_vers = version.split('.')[0]
|
||||
try:
|
||||
return codenames[snap][major_vers]
|
||||
except KeyError:
|
||||
# NOTE(jamespage): fallthrough to codename assumption
|
||||
pass
|
||||
|
||||
# NOTE(jamespage): fallback to codename assumption
|
||||
return version_or_codename
|
||||
|
||||
@staticmethod
|
||||
def get_os_codename_package(package, codenames, fatal=True):
|
||||
"""Derive OpenStack release codename from an installed package.
|
||||
|
||||
:param package: str Package name to lookup in apt cache
|
||||
:param codenames: dict of OrderedDict eg
|
||||
:param package: str Package name to lookup (ie. in apt cache)
|
||||
:param codenames: dict of OrderedDict eg (not applicable for snap pkgs)
|
||||
{
|
||||
'pkg1': collections.OrderedDict([
|
||||
('2', 'mitaka'),
|
||||
|
@ -396,6 +505,26 @@ class BaseOpenStackCharm(object, metaclass=BaseOpenStackCharmMeta):
|
|||
major_vers in codenames[package]):
|
||||
return codenames[package][major_vers]
|
||||
|
||||
def get_os_version_snap(self, snap, fatal=True):
|
||||
"""Derive OpenStack version number from an installed snap.
|
||||
|
||||
:param package: str Snap name to lookup in snap list
|
||||
:param fatal: bool Raise exception if snap not installed
|
||||
:returns: str OpenStack version number corresponding to snap
|
||||
"""
|
||||
if os_utils.snap_install_requested():
|
||||
codename = self.get_os_codename_snap(snap,
|
||||
self.snap_codenames,
|
||||
fatal=fatal)
|
||||
if not codename:
|
||||
return None
|
||||
|
||||
for version, cname in os_utils.OPENSTACK_CODENAMES.items():
|
||||
if cname == codename:
|
||||
return version
|
||||
|
||||
return None
|
||||
|
||||
def get_os_version_package(self, package, fatal=True):
|
||||
"""Derive OpenStack version number from an installed package.
|
||||
|
||||
|
@ -403,16 +532,18 @@ class BaseOpenStackCharm(object, metaclass=BaseOpenStackCharmMeta):
|
|||
:param fatal: bool Raise exception if pkg not installed
|
||||
:returns: str OpenStack version number corresponding to package
|
||||
"""
|
||||
codenames = self.package_codenames or os_utils.PACKAGE_CODENAMES
|
||||
codename = self.get_os_codename_package(
|
||||
package, codenames, fatal=fatal)
|
||||
if not codename:
|
||||
return None
|
||||
if not os_utils.snap_install_requested():
|
||||
codename = self.get_os_codename_package(
|
||||
package, self.package_codenames or os_utils.PACKAGE_CODENAMES,
|
||||
fatal=fatal)
|
||||
if not codename:
|
||||
return None
|
||||
|
||||
vers_map = os_utils.OPENSTACK_CODENAMES
|
||||
for version, cname in vers_map.items():
|
||||
if cname == codename:
|
||||
return version
|
||||
for version, cname in os_utils.OPENSTACK_CODENAMES.items():
|
||||
if cname == codename:
|
||||
return version
|
||||
|
||||
return None
|
||||
|
||||
|
||||
class BaseOpenStackCharmActions(object):
|
||||
|
@ -440,15 +571,48 @@ class BaseOpenStackCharmActions(object):
|
|||
"""
|
||||
return self.packages
|
||||
|
||||
@property
|
||||
def all_snaps(self):
|
||||
"""List of snaps to be installed
|
||||
|
||||
Relies on the class variable 'snaps'
|
||||
|
||||
@return ['snap1', 'snap2', ...]
|
||||
"""
|
||||
return self.snaps
|
||||
|
||||
@property
|
||||
def primary_snap(self):
|
||||
"""Primary snap to use for configuration
|
||||
|
||||
Relies on the class variable 'snaps'
|
||||
|
||||
:return string: first snap found in 'snaps'
|
||||
"""
|
||||
if self.snaps:
|
||||
return self.snaps[0]
|
||||
return None
|
||||
|
||||
def install(self):
|
||||
"""Install packages related to this charm based on
|
||||
contents of self.packages attribute.
|
||||
"""Install packages or snaps related to this charm based on
|
||||
contents of self.packages or self.snaps attribute.
|
||||
"""
|
||||
packages = fetch.filter_installed_packages(
|
||||
self.all_packages)
|
||||
if packages:
|
||||
hookenv.status_set('maintenance', 'Installing packages')
|
||||
fetch.apt_install(packages, fatal=True)
|
||||
|
||||
if os_utils.snap_install_requested():
|
||||
if self.all_snaps:
|
||||
hookenv.status_set('maintenance', 'Installing snaps')
|
||||
os_utils.install_os_snaps(
|
||||
os_utils.get_snaps_install_info_from_origin(
|
||||
self.all_snaps,
|
||||
self.config['openstack-origin'],
|
||||
mode=self.snap_mode)
|
||||
)
|
||||
|
||||
# AJK: we set this as charms can use it to detect installed state
|
||||
self.set_state('{}-installed'.format(self.name))
|
||||
self.update_api_ports()
|
||||
|
@ -652,7 +816,7 @@ class BaseOpenStackCharmActions(object):
|
|||
ports.append(line)
|
||||
return ports
|
||||
|
||||
def openstack_upgrade_available(self, package=None):
|
||||
def openstack_upgrade_available(self, package=None, snap=None):
|
||||
"""Check if an OpenStack upgrade is available
|
||||
|
||||
:param package: str Package name to use to check upgrade availability
|
||||
|
@ -660,10 +824,16 @@ class BaseOpenStackCharmActions(object):
|
|||
"""
|
||||
if not package:
|
||||
package = self.release_pkg
|
||||
if not snap:
|
||||
snap = self.release_snap
|
||||
|
||||
src = self.config['openstack-origin']
|
||||
cur_vers = self.get_os_version_package(package)
|
||||
avail_vers = os_utils.get_os_version_install_source(src)
|
||||
if os_utils.snap_install_requested():
|
||||
cur_vers = self.get_os_version_snap(snap)
|
||||
else:
|
||||
cur_vers = self.get_os_version_package(package)
|
||||
apt.init()
|
||||
return apt.version_compare(avail_vers, cur_vers) == 1
|
||||
|
||||
|
@ -680,7 +850,7 @@ class BaseOpenStackCharmActions(object):
|
|||
self.do_openstack_upgrade_db_migration()
|
||||
|
||||
def do_openstack_pkg_upgrade(self):
|
||||
"""Upgrade OpenStack packages
|
||||
"""Upgrade OpenStack packages and snaps
|
||||
|
||||
:returns: None
|
||||
"""
|
||||
|
@ -688,6 +858,15 @@ class BaseOpenStackCharmActions(object):
|
|||
new_os_rel = os_utils.get_os_codename_install_source(new_src)
|
||||
hookenv.log('Performing OpenStack upgrade to %s.' % (new_os_rel))
|
||||
|
||||
# TODO(jamespage): Deal with deb->snap->deb migrations
|
||||
if os_utils.snap_install_requested() and self.all_snaps:
|
||||
os_utils.install_os_snaps(
|
||||
snaps=os_utils.get_snaps_install_info_from_origin(
|
||||
self.all_snaps,
|
||||
self.config['openstack-origin'],
|
||||
mode=self.snap_mode),
|
||||
refresh=True)
|
||||
|
||||
os_utils.configure_installation_source(new_src)
|
||||
fetch.apt_update()
|
||||
|
||||
|
@ -722,6 +901,15 @@ class BaseOpenStackCharmActions(object):
|
|||
else:
|
||||
hookenv.log("Deferring DB sync to leader", level=hookenv.INFO)
|
||||
|
||||
# NOTE(jamespage): Not currently used - switch from c-h function for perf?
|
||||
def snap_install_requested(self):
|
||||
"""Determine whether a snap based install is configured
|
||||
via the openstack-origin configuration option
|
||||
|
||||
:returns: None
|
||||
"""
|
||||
return self.options.openstack_origin.startswith('snap:')
|
||||
|
||||
|
||||
class BaseOpenStackCharmAssessStatus(object):
|
||||
"""Provides the 'Assess Status' functionality to the OpenStack charm class.
|
||||
|
|
|
@ -4,6 +4,7 @@ import charms.reactive as reactive
|
|||
|
||||
from charms_openstack.charm.classes import OpenStackCharm
|
||||
from charms_openstack.charm.core import register_os_release_selector
|
||||
from charms_openstack.charm.core import register_package_type_selector
|
||||
|
||||
# The default handlers that charms.openstack provides.
|
||||
ALLOWED_DEFAULT_HANDLERS = [
|
||||
|
@ -14,6 +15,7 @@ ALLOWED_DEFAULT_HANDLERS = [
|
|||
'identity-service.available',
|
||||
'config.changed',
|
||||
'charm.default-select-release',
|
||||
'charm.default-select-package-type',
|
||||
'update-status',
|
||||
'upgrade-charm',
|
||||
]
|
||||
|
@ -23,6 +25,7 @@ _default_handler_map = {}
|
|||
|
||||
# Used to store the discovered release version for caching between invocations
|
||||
OPENSTACK_RELEASE_KEY = 'charmers.openstack-release-version'
|
||||
OPENSTACK_PACKAGE_TYPE_KEY = 'charmers.openstack-package-type'
|
||||
|
||||
|
||||
def use_defaults(*defaults):
|
||||
|
@ -98,6 +101,31 @@ def make_default_select_release_handler():
|
|||
return release_version
|
||||
|
||||
|
||||
@_map_default_handler('charm.default-select-package-type')
|
||||
def make_default_select_package_type_handler():
|
||||
"""This handler is a bit more unusual, as it just sets the package type
|
||||
selector using the @register_package_type_selector decorator
|
||||
"""
|
||||
|
||||
@register_package_type_selector
|
||||
def default_select_package_type():
|
||||
"""Determine the package type (snap or deb) based on the
|
||||
openstack-origin setting.
|
||||
|
||||
Note that this function caches the package type after the first
|
||||
install so that it doesn't need to keep going and getting it from
|
||||
the config information.
|
||||
"""
|
||||
package_type = unitdata.kv().get(OPENSTACK_PACKAGE_TYPE_KEY, None)
|
||||
if package_type is None:
|
||||
if os_utils.snap_install_requested():
|
||||
package_type = 'snap'
|
||||
else:
|
||||
package_type = 'deb'
|
||||
unitdata.kv().set(OPENSTACK_PACKAGE_TYPE_KEY, package_type)
|
||||
return package_type
|
||||
|
||||
|
||||
@_map_default_handler('amqp.connected')
|
||||
def make_default_amqp_connection_handler():
|
||||
"""Set the default amqp.connected state so that the default handler in
|
||||
|
|
|
@ -24,7 +24,9 @@ class MyOpenStackCharm(chm_classes.OpenStackCharm):
|
|||
release = 'icehouse'
|
||||
name = 'my-charm'
|
||||
packages = ['p1', 'p2', 'p3', 'package-to-filter']
|
||||
snaps = ['mysnap']
|
||||
version_package = 'p2'
|
||||
version_snap = 'mysnap'
|
||||
api_ports = {
|
||||
'service1': {
|
||||
'public': 1,
|
||||
|
|
|
@ -8,7 +8,8 @@ from unit_tests.charms_openstack.charm.common import MyOpenStackCharm
|
|||
import charms_openstack.charm.classes as chm
|
||||
import charms_openstack.charm.core as chm_core
|
||||
|
||||
TEST_CONFIG = {'config': True}
|
||||
TEST_CONFIG = {'config': True,
|
||||
'openstack-origin': None}
|
||||
|
||||
|
||||
class TestOpenStackCharm__init__(BaseOpenStackCharmTest):
|
||||
|
@ -236,6 +237,8 @@ class TestMyOpenStackCharm(BaseOpenStackCharmTest):
|
|||
self.patch_object(chm.os_utils, 'os_release')
|
||||
self.patch_object(chm, 'get_upstream_version',
|
||||
return_value='1.2.3')
|
||||
self.patch_object(chm.os_utils, 'snap_install_requested',
|
||||
return_value=False)
|
||||
self.target.version_package = None
|
||||
self.assertEqual(self.target.application_version, '1.2.3')
|
||||
self.get_upstream_version.assert_called_once_with('p1')
|
||||
|
@ -244,14 +247,26 @@ class TestMyOpenStackCharm(BaseOpenStackCharmTest):
|
|||
self.patch_object(chm.os_utils, 'os_release')
|
||||
self.patch_object(chm, 'get_upstream_version',
|
||||
return_value='1.2.3')
|
||||
self.patch_object(chm.os_utils, 'snap_install_requested',
|
||||
return_value=False)
|
||||
self.assertEqual(self.target.application_version, '1.2.3')
|
||||
self.get_upstream_version.assert_called_once_with('p2')
|
||||
|
||||
def test_application_version_snap(self):
|
||||
self.patch_object(chm, 'get_snap_version',
|
||||
return_value='4.0.3')
|
||||
self.patch_object(chm.os_utils, 'snap_install_requested',
|
||||
return_value=True)
|
||||
self.assertEqual(self.target.application_version, '4.0.3')
|
||||
self.get_snap_version.assert_called_once_with('mysnap', fatal=False)
|
||||
|
||||
def test_application_version_dfs(self):
|
||||
self.patch_object(chm.os_utils, 'os_release',
|
||||
return_value='mitaka')
|
||||
self.patch_object(chm, 'get_upstream_version',
|
||||
return_value=None)
|
||||
self.patch_object(chm.os_utils, 'snap_install_requested',
|
||||
return_value=False)
|
||||
self.assertEqual(self.target.application_version, 'mitaka')
|
||||
self.get_upstream_version.assert_called_once_with('p2')
|
||||
self.os_release.assert_called_once_with('p2')
|
||||
|
@ -366,6 +381,8 @@ class TestHAOpenStackCharm(BaseOpenStackCharmTest):
|
|||
self.patch_target('token_cache_pkgs', return_value=[])
|
||||
self.patch_target('haproxy_enabled', return_value=False)
|
||||
self.patch_target('apache_enabled', return_value=False)
|
||||
self.patch_object(chm.os_utils, 'snap_install_requested',
|
||||
return_value=False)
|
||||
self.assertEqual(['pkg1'], self.target.all_packages)
|
||||
self.token_cache_pkgs.return_value = ['memcache']
|
||||
self.haproxy_enabled.return_value = True
|
||||
|
@ -391,6 +408,8 @@ class TestHAOpenStackCharm(BaseOpenStackCharmTest):
|
|||
self.patch_target('enable_memcache', return_value=True)
|
||||
self.patch_target('haproxy_enabled', return_value=True)
|
||||
self.patch_target('apache_enabled', return_value=True)
|
||||
self.patch_object(chm.os_utils, 'snap_install_requested',
|
||||
return_value=False)
|
||||
self.assertEqual(
|
||||
self.target.full_restart_map,
|
||||
{'/etc/apache2/sites-available/openstack_https_frontend.conf':
|
||||
|
@ -515,6 +534,8 @@ class TestHAOpenStackCharm(BaseOpenStackCharmTest):
|
|||
self.patch_object(
|
||||
chm.subprocess, 'call',
|
||||
new=lambda x: apache_mods[x.pop()])
|
||||
self.patch_object(chm.os_utils, 'snap_install_requested',
|
||||
return_value=False)
|
||||
self.target.enable_apache_modules()
|
||||
self.check_call.assert_called_once_with(
|
||||
['a2enmod', 'proxy_http'])
|
||||
|
@ -523,6 +544,8 @@ class TestHAOpenStackCharm(BaseOpenStackCharmTest):
|
|||
def test_configure_cert(self):
|
||||
self.patch_object(chm.ch_host, 'mkdir')
|
||||
self.patch_object(chm.ch_host, 'write_file')
|
||||
self.patch_object(chm.os_utils, 'snap_install_requested',
|
||||
return_value=False)
|
||||
self.target.configure_cert('mycert', 'mykey', cn='mycn')
|
||||
self.mkdir.assert_called_once_with(path='/etc/apache2/ssl/charmname')
|
||||
calls = [
|
||||
|
@ -564,6 +587,8 @@ class TestHAOpenStackCharm(BaseOpenStackCharmTest):
|
|||
'ssl_cert': base64.b64encode(b'cert'),
|
||||
'ssl_ca': base64.b64encode(b'ca')}
|
||||
self.patch_target('config', new=config)
|
||||
self.patch_object(chm.os_utils, 'snap_install_requested',
|
||||
return_value=False)
|
||||
self.assertEqual(
|
||||
self.target.get_certs_and_keys(),
|
||||
[{'key': 'key', 'cert': 'cert', 'ca': 'ca', 'cn': None}])
|
||||
|
@ -573,6 +598,8 @@ class TestHAOpenStackCharm(BaseOpenStackCharmTest):
|
|||
'ssl_key': base64.b64encode(b'key'),
|
||||
'ssl_cert': base64.b64encode(b'cert')}
|
||||
self.patch_target('config', new=config)
|
||||
self.patch_object(chm.os_utils, 'snap_install_requested',
|
||||
return_value=False)
|
||||
self.assertEqual(
|
||||
self.target.get_certs_and_keys(),
|
||||
[{'key': 'key', 'cert': 'cert', 'ca': None, 'cn': None}])
|
||||
|
@ -601,6 +628,8 @@ class TestHAOpenStackCharm(BaseOpenStackCharmTest):
|
|||
self.patch_target(
|
||||
'get_local_addresses',
|
||||
return_value=['int_addr', 'priv_addr', 'pub_addr', 'admin_addr'])
|
||||
self.patch_object(chm.os_utils, 'snap_install_requested',
|
||||
return_value=False)
|
||||
expect = [
|
||||
{
|
||||
'ca': 'ca',
|
||||
|
@ -664,6 +693,8 @@ class TestHAOpenStackCharm(BaseOpenStackCharmTest):
|
|||
self.patch_object(chm_core.charmhelpers.fetch,
|
||||
'apt_install',
|
||||
name='apt_install')
|
||||
self.patch_object(chm.os_utils, 'snap_install_requested',
|
||||
return_value=False)
|
||||
self.target.configure_ssl()
|
||||
cert_calls = [
|
||||
mock.call('cert1', 'key1', cn='cn1'),
|
||||
|
@ -684,6 +715,8 @@ class TestHAOpenStackCharm(BaseOpenStackCharmTest):
|
|||
self.patch_object(chm.reactive.bus, 'set_state')
|
||||
self.patch_object(chm.reactive.RelationBase, 'from_state',
|
||||
return_value=None)
|
||||
self.patch_object(chm.os_utils, 'snap_install_requested',
|
||||
return_value=False)
|
||||
self.target.configure_ssl()
|
||||
self.set_state.assert_called_once_with('ssl.enabled', False)
|
||||
|
||||
|
@ -693,6 +726,8 @@ class TestHAOpenStackCharm(BaseOpenStackCharmTest):
|
|||
self.patch_object(chm.reactive.bus, 'set_state')
|
||||
self.patch_object(chm.reactive.RelationBase, 'from_state',
|
||||
return_value='ssl_int')
|
||||
self.patch_object(chm.os_utils, 'snap_install_requested',
|
||||
return_value=False)
|
||||
self.target.configure_ssl()
|
||||
self.set_state.assert_called_once_with('ssl.enabled', False)
|
||||
self.configure_rabbit_cert.assert_called_once_with('ssl_int')
|
||||
|
|
|
@ -13,7 +13,14 @@ from unit_tests.charms_openstack.charm.common import (
|
|||
|
||||
import unit_tests.utils as utils
|
||||
|
||||
TEST_CONFIG = {'config': True}
|
||||
TEST_CONFIG = {'config': True,
|
||||
'openstack-origin': None}
|
||||
SNAP_MAP = {
|
||||
'mysnap': {
|
||||
'channel': 'edge',
|
||||
'mode': 'jailmode',
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class TestRegisterOSReleaseSelector(unittest.TestCase):
|
||||
|
@ -60,10 +67,16 @@ class TestBaseOpenStackCharmMeta(BaseOpenStackCharmTest):
|
|||
class TestC2(chm_core.BaseOpenStackCharm):
|
||||
release = 'mitaka'
|
||||
|
||||
class TestC3(chm_core.BaseOpenStackCharm):
|
||||
release = 'ocata'
|
||||
package_type = 'snap'
|
||||
|
||||
self.assertTrue('liberty' in chm_core._releases.keys())
|
||||
self.assertTrue('mitaka' in chm_core._releases.keys())
|
||||
self.assertEqual(chm_core._releases['liberty'], TestC1)
|
||||
self.assertEqual(chm_core._releases['mitaka'], TestC2)
|
||||
self.assertTrue('ocata' in chm_core._releases.keys())
|
||||
self.assertEqual(chm_core._releases['liberty']['deb'], TestC1)
|
||||
self.assertEqual(chm_core._releases['mitaka']['deb'], TestC2)
|
||||
self.assertEqual(chm_core._releases['ocata']['snap'], TestC3)
|
||||
|
||||
def test_register_unknown_series(self):
|
||||
self.patch_object(chm_core, '_releases', new={})
|
||||
|
@ -351,14 +364,28 @@ class TestMyOpenStackCharm(BaseOpenStackCharmTest):
|
|||
self.patch_object(chm_core.hookenv, 'apt_install')
|
||||
self.patch_object(chm_core.subprocess,
|
||||
'check_output', return_value=b'\n')
|
||||
self.patch_object(chm_core.os_utils, 'snap_install_requested',
|
||||
return_value=True)
|
||||
self.patch_object(chm_core.os_utils, 'install_os_snaps')
|
||||
self.patch_object(chm_core.os_utils,
|
||||
'get_snaps_install_info_from_origin',
|
||||
return_value=SNAP_MAP)
|
||||
|
||||
self.target.install()
|
||||
# TODO: remove next commented line as we don't set this state anymore
|
||||
# self.target.set_state.assert_called_once_with('my-charm-installed')
|
||||
self.fip.assert_called_once_with(self.target.packages)
|
||||
self.status_set.assert_has_calls([
|
||||
mock.call('maintenance', 'Installing packages'),
|
||||
mock.call('maintenance', 'Installing snaps'),
|
||||
mock.call('maintenance',
|
||||
'Installation complete - awaiting next status')])
|
||||
self.install_os_snaps.assert_called_once_with(SNAP_MAP)
|
||||
self.get_snaps_install_info_from_origin.assert_called_once_with(
|
||||
['mysnap'],
|
||||
None,
|
||||
mode='jailmode'
|
||||
)
|
||||
|
||||
def test_api_port(self):
|
||||
self.assertEqual(self.target.api_port('service1'), 1)
|
||||
|
@ -557,6 +584,8 @@ class TestMyOpenStackCharm(BaseOpenStackCharmTest):
|
|||
self.apt_cache.return_value = {
|
||||
'testpkg': pkg_mock}
|
||||
self.patch_object(chm_core.apt, 'upstream_version')
|
||||
self.patch_object(chm_core.os_utils, 'snap_install_requested',
|
||||
return_value=False)
|
||||
self.upstream_version.return_value = '3.0.0~b1'
|
||||
self.assertEqual(
|
||||
chm_core.BaseOpenStackCharm.get_os_codename_package(
|
||||
|
@ -576,6 +605,8 @@ class TestMyOpenStackCharm(BaseOpenStackCharmTest):
|
|||
self.patch_target('package_codenames')
|
||||
self.patch_target('get_os_codename_package',
|
||||
return_value='my-series')
|
||||
self.patch_object(chm_core.os_utils, 'snap_install_requested',
|
||||
return_value=False)
|
||||
self.assertEqual(
|
||||
self.target.get_os_version_package('testpkg'),
|
||||
'2011.2')
|
||||
|
@ -584,15 +615,31 @@ class TestMyOpenStackCharm(BaseOpenStackCharmTest):
|
|||
return_value='unknown-series')
|
||||
self.assertEqual(self.target.get_os_version_package('testpkg'), None)
|
||||
|
||||
def test_openstack_upgrade_available(self):
|
||||
def test_openstack_upgrade_available_package(self):
|
||||
self.patch_target('get_os_version_package')
|
||||
self.patch_object(chm_core.os_utils, 'get_os_version_install_source')
|
||||
self.patch_object(chm_core, 'apt')
|
||||
self.patch_target('config',
|
||||
new={'openstack-origin': 'cloud:natty-folsom'})
|
||||
self.patch_object(chm_core.os_utils, 'snap_install_requested',
|
||||
return_value=False)
|
||||
self.get_os_version_package.return_value = 2
|
||||
self.get_os_version_install_source.return_value = 3
|
||||
self.target.openstack_upgrade_available('testpkg')
|
||||
self.target.openstack_upgrade_available(package='testpkg')
|
||||
self.apt.version_compare.assert_called_once_with(3, 2)
|
||||
|
||||
def test_openstack_upgrade_available_snap(self):
|
||||
self.patch_target('get_os_version_snap')
|
||||
self.patch_object(chm_core.os_utils, 'get_os_version_install_source')
|
||||
self.patch_object(chm_core, 'apt')
|
||||
self.patch_target('config',
|
||||
new={'openstack-origin': 'snap:ocata/stable'})
|
||||
self.patch_object(chm_core.os_utils, 'snap_install_requested',
|
||||
return_value=True)
|
||||
self.get_os_version_snap.return_value = 2
|
||||
self.get_os_version_install_source.return_value = 3
|
||||
self.target.openstack_upgrade_available(snap='testsnap')
|
||||
self.get_os_version_snap.assert_called_once_with('testsnap')
|
||||
self.apt.version_compare.assert_called_once_with(3, 2)
|
||||
|
||||
def test_upgrade_if_available(self):
|
||||
|
@ -618,7 +665,7 @@ class TestMyOpenStackCharm(BaseOpenStackCharmTest):
|
|||
'int_list')
|
||||
self.do_openstack_upgrade_db_migration.assert_called_once_with()
|
||||
|
||||
def test_do_openstack_pkg_upgrade(self):
|
||||
def test_do_openstack_pkg_upgrade_package(self):
|
||||
self.patch_target('config',
|
||||
new={'openstack-origin': 'cloud:natty-kilo'})
|
||||
self.patch_object(chm_core.os_utils, 'get_os_codename_install_source')
|
||||
|
@ -627,6 +674,8 @@ class TestMyOpenStackCharm(BaseOpenStackCharmTest):
|
|||
self.patch_object(chm_core.charmhelpers.fetch, 'apt_update')
|
||||
self.patch_object(chm_core.charmhelpers.fetch, 'apt_upgrade')
|
||||
self.patch_object(chm_core.charmhelpers.fetch, 'apt_install')
|
||||
self.patch_object(chm_core.os_utils, 'snap_install_requested',
|
||||
return_value=False)
|
||||
self.target.do_openstack_pkg_upgrade()
|
||||
self.configure_installation_source.assert_called_once_with(
|
||||
'cloud:natty-kilo')
|
||||
|
@ -643,6 +692,44 @@ class TestMyOpenStackCharm(BaseOpenStackCharmTest):
|
|||
'Dpkg::Options::=--force-confdef'],
|
||||
fatal=True)
|
||||
|
||||
def test_do_openstack_pkg_upgrade_snap(self):
|
||||
self.patch_target('config',
|
||||
new={'openstack-origin': 'snap:ocata/stable'})
|
||||
self.patch_object(chm_core.os_utils, 'get_os_codename_install_source')
|
||||
self.patch_object(chm_core.hookenv, 'log')
|
||||
self.patch_object(chm_core.os_utils, 'configure_installation_source')
|
||||
self.patch_object(chm_core.charmhelpers.fetch, 'apt_update')
|
||||
self.patch_object(chm_core.charmhelpers.fetch, 'apt_upgrade')
|
||||
self.patch_object(chm_core.charmhelpers.fetch, 'apt_install')
|
||||
self.patch_object(chm_core.os_utils, 'snap_install_requested',
|
||||
return_value=True)
|
||||
self.patch_object(chm_core.os_utils, 'install_os_snaps')
|
||||
self.patch_object(chm_core.os_utils,
|
||||
'get_snaps_install_info_from_origin',
|
||||
return_value=SNAP_MAP)
|
||||
self.target.do_openstack_pkg_upgrade()
|
||||
self.configure_installation_source.assert_called_once_with(
|
||||
'snap:ocata/stable')
|
||||
self.apt_update.assert_called_once_with()
|
||||
self.apt_upgrade.assert_called_once_with(
|
||||
dist=True, fatal=True,
|
||||
options=[
|
||||
'--option', 'Dpkg::Options::=--force-confnew', '--option',
|
||||
'Dpkg::Options::=--force-confdef'])
|
||||
self.apt_install.assert_called_once_with(
|
||||
packages=['p1', 'p2', 'p3', 'package-to-filter'],
|
||||
options=[
|
||||
'--option', 'Dpkg::Options::=--force-confnew', '--option',
|
||||
'Dpkg::Options::=--force-confdef'],
|
||||
fatal=True)
|
||||
self.install_os_snaps.assert_called_once_with(snaps=SNAP_MAP,
|
||||
refresh=True)
|
||||
self.get_snaps_install_info_from_origin.assert_called_once_with(
|
||||
['mysnap'],
|
||||
'snap:ocata/stable',
|
||||
mode='jailmode',
|
||||
)
|
||||
|
||||
def test_do_openstack_upgrade_config_render(self):
|
||||
self.patch_target('render_with_interfaces')
|
||||
self.target.do_openstack_upgrade_config_render('int_list')
|
||||
|
|
|
@ -120,6 +120,49 @@ class TestDefaults(BaseOpenStackCharmTest):
|
|||
kv.set.assert_called_once_with(chm.OPENSTACK_RELEASE_KEY, 'two')
|
||||
self.os_release.assert_called_once_with('python-keystonemiddleware')
|
||||
|
||||
def test_default_select_package_type_handler(self):
|
||||
self.assertIn('charm.default-select-package-type',
|
||||
chm._default_handler_map)
|
||||
self.patch_object(chm, 'register_package_type_selector')
|
||||
h = self.mock_decorator_gen_simple()
|
||||
self.register_package_type_selector.side_effect = h.decorator
|
||||
# call the default handler installer function, and check its map.
|
||||
f = chm._default_handler_map['charm.default-select-package-type']
|
||||
f()
|
||||
self.assertIsNotNone(h.map['function'])
|
||||
# verify that the installed function works
|
||||
kv = mock.MagicMock()
|
||||
self.patch_object(chm.unitdata, 'kv', new=lambda: kv)
|
||||
self.patch_object(chm.os_utils, 'snap_install_requested',
|
||||
return_value=False)
|
||||
# set a package_type
|
||||
kv.get.return_value = 'deb'
|
||||
package_type = h.map['function']()
|
||||
self.assertEqual(package_type, 'deb')
|
||||
kv.set.assert_not_called()
|
||||
kv.get.assert_called_once_with(chm.OPENSTACK_PACKAGE_TYPE_KEY, None)
|
||||
|
||||
# No release set, ensure it calls snap_install_requested and
|
||||
# sets package_type to 'snap'
|
||||
kv.reset_mock()
|
||||
kv.get.return_value = None
|
||||
self.snap_install_requested.return_value = True
|
||||
package_type = h.map['function']()
|
||||
self.assertEqual(package_type, 'snap')
|
||||
kv.set.assert_called_once_with(chm.OPENSTACK_PACKAGE_TYPE_KEY, 'snap')
|
||||
self.snap_install_requested.assert_called_once_with()
|
||||
|
||||
# No release set, ensure it calls snap_install_requested and
|
||||
# sets package_type to 'deb'
|
||||
kv.reset_mock()
|
||||
kv.get.return_value = None
|
||||
self.snap_install_requested.reset_mock()
|
||||
self.snap_install_requested.return_value = False
|
||||
package_type = h.map['function']()
|
||||
self.assertEqual(package_type, 'deb')
|
||||
kv.set.assert_called_once_with(chm.OPENSTACK_PACKAGE_TYPE_KEY, 'deb')
|
||||
self.snap_install_requested.assert_called_once_with()
|
||||
|
||||
def test_default_amqp_connection_handler(self):
|
||||
self.assertIn('amqp.connected', chm._default_handler_map)
|
||||
self.patch_object(chm.reactive, 'set_state')
|
||||
|
|
Loading…
Reference in New Issue