Merge with trunk.
This commit is contained in:
commit
b492f1a79e
hooks
templates/mitaka
tests
tox.iniunit_tests
@ -121,11 +121,12 @@ class OpenStackAmuletDeployment(AmuletDeployment):
|
||||
|
||||
# Charms which should use the source config option
|
||||
use_source = ['mysql', 'mongodb', 'rabbitmq-server', 'ceph',
|
||||
'ceph-osd', 'ceph-radosgw']
|
||||
'ceph-osd', 'ceph-radosgw', 'ceph-mon']
|
||||
|
||||
# Charms which can not use openstack-origin, ie. many subordinates
|
||||
no_origin = ['cinder-ceph', 'hacluster', 'neutron-openvswitch', 'nrpe',
|
||||
'openvswitch-odl', 'neutron-api-odl', 'odl-controller']
|
||||
'openvswitch-odl', 'neutron-api-odl', 'odl-controller',
|
||||
'cinder-backup']
|
||||
|
||||
if self.openstack:
|
||||
for svc in services:
|
||||
|
@ -90,6 +90,12 @@ from charmhelpers.contrib.network.ip import (
|
||||
from charmhelpers.contrib.openstack.utils import get_host_ip
|
||||
from charmhelpers.core.unitdata import kv
|
||||
|
||||
try:
|
||||
import psutil
|
||||
except ImportError:
|
||||
apt_install('python-psutil', fatal=True)
|
||||
import psutil
|
||||
|
||||
CA_CERT_PATH = '/usr/local/share/ca-certificates/keystone_juju_ca_cert.crt'
|
||||
ADDRESS_TYPES = ['admin', 'internal', 'public']
|
||||
|
||||
@ -1258,13 +1264,11 @@ class WorkerConfigContext(OSContextGenerator):
|
||||
|
||||
@property
|
||||
def num_cpus(self):
|
||||
try:
|
||||
from psutil import NUM_CPUS
|
||||
except ImportError:
|
||||
apt_install('python-psutil', fatal=True)
|
||||
from psutil import NUM_CPUS
|
||||
|
||||
return NUM_CPUS
|
||||
# NOTE: use cpu_count if present (16.04 support)
|
||||
if hasattr(psutil, 'cpu_count'):
|
||||
return psutil.cpu_count()
|
||||
else:
|
||||
return psutil.NUM_CPUS
|
||||
|
||||
def __call__(self):
|
||||
multiplier = config('worker-multiplier') or 0
|
||||
|
@ -50,7 +50,7 @@ def determine_dkms_package():
|
||||
if kernel_version() >= (3, 13):
|
||||
return []
|
||||
else:
|
||||
return ['openvswitch-datapath-dkms']
|
||||
return [headers_package(), 'openvswitch-datapath-dkms']
|
||||
|
||||
|
||||
# legacy
|
||||
@ -70,7 +70,7 @@ def quantum_plugins():
|
||||
relation_prefix='neutron',
|
||||
ssl_dir=QUANTUM_CONF_DIR)],
|
||||
'services': ['quantum-plugin-openvswitch-agent'],
|
||||
'packages': [[headers_package()] + determine_dkms_package(),
|
||||
'packages': [determine_dkms_package(),
|
||||
['quantum-plugin-openvswitch-agent']],
|
||||
'server_packages': ['quantum-server',
|
||||
'quantum-plugin-openvswitch'],
|
||||
@ -111,7 +111,7 @@ def neutron_plugins():
|
||||
relation_prefix='neutron',
|
||||
ssl_dir=NEUTRON_CONF_DIR)],
|
||||
'services': ['neutron-plugin-openvswitch-agent'],
|
||||
'packages': [[headers_package()] + determine_dkms_package(),
|
||||
'packages': [determine_dkms_package(),
|
||||
['neutron-plugin-openvswitch-agent']],
|
||||
'server_packages': ['neutron-server',
|
||||
'neutron-plugin-openvswitch'],
|
||||
@ -155,7 +155,7 @@ def neutron_plugins():
|
||||
relation_prefix='neutron',
|
||||
ssl_dir=NEUTRON_CONF_DIR)],
|
||||
'services': [],
|
||||
'packages': [[headers_package()] + determine_dkms_package(),
|
||||
'packages': [determine_dkms_package(),
|
||||
['neutron-plugin-cisco']],
|
||||
'server_packages': ['neutron-server',
|
||||
'neutron-plugin-cisco'],
|
||||
@ -174,7 +174,7 @@ def neutron_plugins():
|
||||
'neutron-dhcp-agent',
|
||||
'nova-api-metadata',
|
||||
'etcd'],
|
||||
'packages': [[headers_package()] + determine_dkms_package(),
|
||||
'packages': [determine_dkms_package(),
|
||||
['calico-compute',
|
||||
'bird',
|
||||
'neutron-dhcp-agent',
|
||||
@ -219,7 +219,7 @@ def neutron_plugins():
|
||||
relation_prefix='neutron',
|
||||
ssl_dir=NEUTRON_CONF_DIR)],
|
||||
'services': [],
|
||||
'packages': [[headers_package()] + determine_dkms_package()],
|
||||
'packages': [determine_dkms_package()],
|
||||
'server_packages': ['neutron-server',
|
||||
'python-neutron-plugin-midonet'],
|
||||
'server_services': ['neutron-server']
|
||||
@ -233,6 +233,18 @@ def neutron_plugins():
|
||||
'neutron-plugin-ml2']
|
||||
# NOTE: patch in vmware renames nvp->nsx for icehouse onwards
|
||||
plugins['nvp'] = plugins['nsx']
|
||||
if release >= 'kilo':
|
||||
plugins['midonet']['driver'] = (
|
||||
'neutron.plugins.midonet.plugin.MidonetPluginV2')
|
||||
if release >= 'liberty':
|
||||
midonet_origin = config('midonet-origin')
|
||||
if midonet_origin is not None and midonet_origin[4:5] == '1':
|
||||
plugins['midonet']['driver'] = (
|
||||
'midonet.neutron.plugin_v1.MidonetPluginV2')
|
||||
plugins['midonet']['server_packages'].remove(
|
||||
'python-neutron-plugin-midonet')
|
||||
plugins['midonet']['server_packages'].append(
|
||||
'python-networking-midonet')
|
||||
return plugins
|
||||
|
||||
|
||||
|
@ -25,6 +25,7 @@ import sys
|
||||
import re
|
||||
|
||||
import six
|
||||
import tempfile
|
||||
import traceback
|
||||
import uuid
|
||||
import yaml
|
||||
@ -41,6 +42,7 @@ from charmhelpers.core.hookenv import (
|
||||
config,
|
||||
log as juju_log,
|
||||
charm_dir,
|
||||
DEBUG,
|
||||
INFO,
|
||||
related_units,
|
||||
relation_ids,
|
||||
@ -103,29 +105,28 @@ OPENSTACK_CODENAMES = OrderedDict([
|
||||
('2016.1', 'mitaka'),
|
||||
])
|
||||
|
||||
# The ugly duckling
|
||||
# The ugly duckling - must list releases oldest to newest
|
||||
SWIFT_CODENAMES = OrderedDict([
|
||||
('1.4.3', 'diablo'),
|
||||
('1.4.8', 'essex'),
|
||||
('1.7.4', 'folsom'),
|
||||
('1.8.0', 'grizzly'),
|
||||
('1.7.7', 'grizzly'),
|
||||
('1.7.6', 'grizzly'),
|
||||
('1.10.0', 'havana'),
|
||||
('1.9.1', 'havana'),
|
||||
('1.9.0', 'havana'),
|
||||
('1.13.1', 'icehouse'),
|
||||
('1.13.0', 'icehouse'),
|
||||
('1.12.0', 'icehouse'),
|
||||
('1.11.0', 'icehouse'),
|
||||
('2.0.0', 'juno'),
|
||||
('2.1.0', 'juno'),
|
||||
('2.2.0', 'juno'),
|
||||
('2.2.1', 'kilo'),
|
||||
('2.2.2', 'kilo'),
|
||||
('2.3.0', 'liberty'),
|
||||
('2.4.0', 'liberty'),
|
||||
('2.5.0', 'liberty'),
|
||||
('diablo',
|
||||
['1.4.3']),
|
||||
('essex',
|
||||
['1.4.8']),
|
||||
('folsom',
|
||||
['1.7.4']),
|
||||
('grizzly',
|
||||
['1.7.6', '1.7.7', '1.8.0']),
|
||||
('havana',
|
||||
['1.9.0', '1.9.1', '1.10.0']),
|
||||
('icehouse',
|
||||
['1.11.0', '1.12.0', '1.13.0', '1.13.1']),
|
||||
('juno',
|
||||
['2.0.0', '2.1.0', '2.2.0']),
|
||||
('kilo',
|
||||
['2.2.1', '2.2.2']),
|
||||
('liberty',
|
||||
['2.3.0', '2.4.0', '2.5.0']),
|
||||
('mitaka',
|
||||
['2.5.0']),
|
||||
])
|
||||
|
||||
# >= Liberty version->codename mapping
|
||||
@ -227,6 +228,33 @@ def get_os_version_codename(codename, version_map=OPENSTACK_CODENAMES):
|
||||
error_out(e)
|
||||
|
||||
|
||||
def get_os_version_codename_swift(codename):
|
||||
'''Determine OpenStack version number of swift from codename.'''
|
||||
for k, v in six.iteritems(SWIFT_CODENAMES):
|
||||
if k == codename:
|
||||
return v[-1]
|
||||
e = 'Could not derive swift version for '\
|
||||
'codename: %s' % codename
|
||||
error_out(e)
|
||||
|
||||
|
||||
def get_swift_codename(version):
|
||||
'''Determine OpenStack codename that corresponds to swift version.'''
|
||||
codenames = [k for k, v in six.iteritems(SWIFT_CODENAMES) if version in v]
|
||||
if len(codenames) > 1:
|
||||
# If more than one release codename contains this version we determine
|
||||
# the actual codename based on the highest available install source.
|
||||
for codename in reversed(codenames):
|
||||
releases = UBUNTU_OPENSTACK_RELEASE
|
||||
release = [k for k, v in six.iteritems(releases) if codename in v]
|
||||
ret = subprocess.check_output(['apt-cache', 'policy', 'swift'])
|
||||
if codename in ret or release[0] in ret:
|
||||
return codename
|
||||
elif len(codenames) == 1:
|
||||
return codenames[0]
|
||||
return None
|
||||
|
||||
|
||||
def get_os_codename_package(package, fatal=True):
|
||||
'''Derive OpenStack release codename from an installed package.'''
|
||||
import apt_pkg as apt
|
||||
@ -270,7 +298,7 @@ def get_os_codename_package(package, fatal=True):
|
||||
# < Liberty co-ordinated project versions
|
||||
try:
|
||||
if 'swift' in pkg.name:
|
||||
return SWIFT_CODENAMES[vers]
|
||||
return get_swift_codename(vers)
|
||||
else:
|
||||
return OPENSTACK_CODENAMES[vers]
|
||||
except KeyError:
|
||||
@ -289,12 +317,14 @@ def get_os_version_package(pkg, fatal=True):
|
||||
|
||||
if 'swift' in pkg:
|
||||
vers_map = SWIFT_CODENAMES
|
||||
for cname, version in six.iteritems(vers_map):
|
||||
if cname == codename:
|
||||
return version[-1]
|
||||
else:
|
||||
vers_map = OPENSTACK_CODENAMES
|
||||
|
||||
for version, cname in six.iteritems(vers_map):
|
||||
if cname == codename:
|
||||
return version
|
||||
for version, cname in six.iteritems(vers_map):
|
||||
if cname == codename:
|
||||
return version
|
||||
# e = "Could not determine OpenStack version for package: %s" % pkg
|
||||
# error_out(e)
|
||||
|
||||
@ -319,12 +349,42 @@ def os_release(package, base='essex'):
|
||||
|
||||
|
||||
def import_key(keyid):
|
||||
cmd = "apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 " \
|
||||
"--recv-keys %s" % keyid
|
||||
try:
|
||||
subprocess.check_call(cmd.split(' '))
|
||||
except subprocess.CalledProcessError:
|
||||
error_out("Error importing repo key %s" % keyid)
|
||||
key = keyid.strip()
|
||||
if (key.startswith('-----BEGIN PGP PUBLIC KEY BLOCK-----') and
|
||||
key.endswith('-----END PGP PUBLIC KEY BLOCK-----')):
|
||||
juju_log("PGP key found (looks like ASCII Armor format)", level=DEBUG)
|
||||
juju_log("Importing ASCII Armor PGP key", level=DEBUG)
|
||||
with tempfile.NamedTemporaryFile() as keyfile:
|
||||
with open(keyfile.name, 'w') as fd:
|
||||
fd.write(key)
|
||||
fd.write("\n")
|
||||
|
||||
cmd = ['apt-key', 'add', keyfile.name]
|
||||
try:
|
||||
subprocess.check_call(cmd)
|
||||
except subprocess.CalledProcessError:
|
||||
error_out("Error importing PGP key '%s'" % key)
|
||||
else:
|
||||
juju_log("PGP key found (looks like Radix64 format)", level=DEBUG)
|
||||
juju_log("Importing PGP key from keyserver", level=DEBUG)
|
||||
cmd = ['apt-key', 'adv', '--keyserver',
|
||||
'hkp://keyserver.ubuntu.com:80', '--recv-keys', key]
|
||||
try:
|
||||
subprocess.check_call(cmd)
|
||||
except subprocess.CalledProcessError:
|
||||
error_out("Error importing PGP key '%s'" % key)
|
||||
|
||||
|
||||
def get_source_and_pgp_key(input):
|
||||
"""Look for a pgp key ID or ascii-armor key in the given input."""
|
||||
index = input.strip()
|
||||
index = input.rfind('|')
|
||||
if index < 0:
|
||||
return input, None
|
||||
|
||||
key = input[index + 1:].strip('|')
|
||||
source = input[:index]
|
||||
return source, key
|
||||
|
||||
|
||||
def configure_installation_source(rel):
|
||||
@ -336,16 +396,16 @@ def configure_installation_source(rel):
|
||||
with open('/etc/apt/sources.list.d/juju_deb.list', 'w') as f:
|
||||
f.write(DISTRO_PROPOSED % ubuntu_rel)
|
||||
elif rel[:4] == "ppa:":
|
||||
src = rel
|
||||
src, key = get_source_and_pgp_key(rel)
|
||||
if key:
|
||||
import_key(key)
|
||||
|
||||
subprocess.check_call(["add-apt-repository", "-y", src])
|
||||
elif rel[:3] == "deb":
|
||||
l = len(rel.split('|'))
|
||||
if l == 2:
|
||||
src, key = rel.split('|')
|
||||
juju_log("Importing PPA key from keyserver for %s" % src)
|
||||
src, key = get_source_and_pgp_key(rel)
|
||||
if key:
|
||||
import_key(key)
|
||||
elif l == 1:
|
||||
src = rel
|
||||
|
||||
with open('/etc/apt/sources.list.d/juju_deb.list', 'w') as f:
|
||||
f.write(src)
|
||||
elif rel[:6] == 'cloud:':
|
||||
@ -460,11 +520,16 @@ def openstack_upgrade_available(package):
|
||||
cur_vers = get_os_version_package(package)
|
||||
if "swift" in package:
|
||||
codename = get_os_codename_install_source(src)
|
||||
available_vers = get_os_version_codename(codename, SWIFT_CODENAMES)
|
||||
avail_vers = get_os_version_codename_swift(codename)
|
||||
else:
|
||||
available_vers = get_os_version_install_source(src)
|
||||
avail_vers = get_os_version_install_source(src)
|
||||
apt.init()
|
||||
return apt.version_compare(available_vers, cur_vers) == 1
|
||||
if "swift" in package:
|
||||
major_cur_vers = cur_vers.split('.', 1)[0]
|
||||
major_avail_vers = avail_vers.split('.', 1)[0]
|
||||
major_diff = apt.version_compare(major_avail_vers, major_cur_vers)
|
||||
return avail_vers > cur_vers and (major_diff == 1 or major_diff == 0)
|
||||
return apt.version_compare(avail_vers, cur_vers) == 1
|
||||
|
||||
|
||||
def ensure_block_device(block_device):
|
||||
|
@ -19,20 +19,35 @@
|
||||
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
from charmhelpers.fetch import apt_install, apt_update
|
||||
from charmhelpers.core.hookenv import charm_dir, log
|
||||
|
||||
try:
|
||||
from pip import main as pip_execute
|
||||
except ImportError:
|
||||
apt_update()
|
||||
apt_install('python-pip')
|
||||
from pip import main as pip_execute
|
||||
|
||||
__author__ = "Jorge Niedbalski <jorge.niedbalski@canonical.com>"
|
||||
|
||||
|
||||
def pip_execute(*args, **kwargs):
|
||||
"""Overriden pip_execute() to stop sys.path being changed.
|
||||
|
||||
The act of importing main from the pip module seems to cause add wheels
|
||||
from the /usr/share/python-wheels which are installed by various tools.
|
||||
This function ensures that sys.path remains the same after the call is
|
||||
executed.
|
||||
"""
|
||||
try:
|
||||
_path = sys.path
|
||||
try:
|
||||
from pip import main as _pip_execute
|
||||
except ImportError:
|
||||
apt_update()
|
||||
apt_install('python-pip')
|
||||
from pip import main as _pip_execute
|
||||
_pip_execute(*args, **kwargs)
|
||||
finally:
|
||||
sys.path = _path
|
||||
|
||||
|
||||
def parse_options(given, available):
|
||||
"""Given a set of options, check if available"""
|
||||
for key, value in sorted(given.items()):
|
||||
|
@ -138,7 +138,8 @@ def service_running(service_name):
|
||||
except subprocess.CalledProcessError:
|
||||
return False
|
||||
else:
|
||||
if ("start/running" in output or "is running" in output):
|
||||
if ("start/running" in output or "is running" in output or
|
||||
"up and running" in output):
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
@ -160,13 +161,13 @@ SYSTEMD_SYSTEM = '/run/systemd/system'
|
||||
|
||||
|
||||
def init_is_systemd():
|
||||
"""Return True if the host system uses systemd, False otherwise."""
|
||||
return os.path.isdir(SYSTEMD_SYSTEM)
|
||||
|
||||
|
||||
def adduser(username, password=None, shell='/bin/bash', system_user=False,
|
||||
primary_group=None, secondary_groups=None):
|
||||
"""
|
||||
Add a user to the system.
|
||||
"""Add a user to the system.
|
||||
|
||||
Will log but otherwise succeed if the user already exists.
|
||||
|
||||
@ -174,7 +175,7 @@ def adduser(username, password=None, shell='/bin/bash', system_user=False,
|
||||
:param str password: Password for user; if ``None``, create a system user
|
||||
:param str shell: The default shell for the user
|
||||
:param bool system_user: Whether to create a login or system user
|
||||
:param str primary_group: Primary group for user; defaults to their username
|
||||
:param str primary_group: Primary group for user; defaults to username
|
||||
:param list secondary_groups: Optional list of additional groups
|
||||
|
||||
:returns: The password database entry struct, as returned by `pwd.getpwnam`
|
||||
@ -300,14 +301,12 @@ def write_file(path, content, owner='root', group='root', perms=0o444):
|
||||
|
||||
|
||||
def fstab_remove(mp):
|
||||
"""Remove the given mountpoint entry from /etc/fstab
|
||||
"""
|
||||
"""Remove the given mountpoint entry from /etc/fstab"""
|
||||
return Fstab.remove_by_mountpoint(mp)
|
||||
|
||||
|
||||
def fstab_add(dev, mp, fs, options=None):
|
||||
"""Adds the given device entry to the /etc/fstab file
|
||||
"""
|
||||
"""Adds the given device entry to the /etc/fstab file"""
|
||||
return Fstab.add(dev, mp, fs, options=options)
|
||||
|
||||
|
||||
@ -363,8 +362,7 @@ def fstab_mount(mountpoint):
|
||||
|
||||
|
||||
def file_hash(path, hash_type='md5'):
|
||||
"""
|
||||
Generate a hash checksum of the contents of 'path' or None if not found.
|
||||
"""Generate a hash checksum of the contents of 'path' or None if not found.
|
||||
|
||||
:param str hash_type: Any hash alrgorithm supported by :mod:`hashlib`,
|
||||
such as md5, sha1, sha256, sha512, etc.
|
||||
@ -379,10 +377,9 @@ def file_hash(path, hash_type='md5'):
|
||||
|
||||
|
||||
def path_hash(path):
|
||||
"""
|
||||
Generate a hash checksum of all files matching 'path'. Standard wildcards
|
||||
like '*' and '?' are supported, see documentation for the 'glob' module for
|
||||
more information.
|
||||
"""Generate a hash checksum of all files matching 'path'. Standard
|
||||
wildcards like '*' and '?' are supported, see documentation for the 'glob'
|
||||
module for more information.
|
||||
|
||||
:return: dict: A { filename: hash } dictionary for all matched files.
|
||||
Empty if none found.
|
||||
@ -394,8 +391,7 @@ def path_hash(path):
|
||||
|
||||
|
||||
def check_hash(path, checksum, hash_type='md5'):
|
||||
"""
|
||||
Validate a file using a cryptographic checksum.
|
||||
"""Validate a file using a cryptographic checksum.
|
||||
|
||||
:param str checksum: Value of the checksum used to validate the file.
|
||||
:param str hash_type: Hash algorithm used to generate `checksum`.
|
||||
@ -410,6 +406,7 @@ def check_hash(path, checksum, hash_type='md5'):
|
||||
|
||||
|
||||
class ChecksumError(ValueError):
|
||||
"""A class derived from Value error to indicate the checksum failed."""
|
||||
pass
|
||||
|
||||
|
||||
@ -515,7 +512,7 @@ def get_bond_master(interface):
|
||||
|
||||
|
||||
def list_nics(nic_type=None):
|
||||
'''Return a list of nics of given type(s)'''
|
||||
"""Return a list of nics of given type(s)"""
|
||||
if isinstance(nic_type, six.string_types):
|
||||
int_types = [nic_type]
|
||||
else:
|
||||
@ -557,12 +554,13 @@ def list_nics(nic_type=None):
|
||||
|
||||
|
||||
def set_nic_mtu(nic, mtu):
|
||||
'''Set MTU on a network interface'''
|
||||
"""Set the Maximum Transmission Unit (MTU) on a network interface."""
|
||||
cmd = ['ip', 'link', 'set', nic, 'mtu', mtu]
|
||||
subprocess.check_call(cmd)
|
||||
|
||||
|
||||
def get_nic_mtu(nic):
|
||||
"""Return the Maximum Transmission Unit (MTU) for a network interface."""
|
||||
cmd = ['ip', 'addr', 'show', nic]
|
||||
ip_output = subprocess.check_output(cmd).decode('UTF-8').split('\n')
|
||||
mtu = ""
|
||||
@ -574,6 +572,7 @@ def get_nic_mtu(nic):
|
||||
|
||||
|
||||
def get_nic_hwaddr(nic):
|
||||
"""Return the Media Access Control (MAC) for a network interface."""
|
||||
cmd = ['ip', '-o', '-0', 'addr', 'show', nic]
|
||||
ip_output = subprocess.check_output(cmd).decode('UTF-8')
|
||||
hwaddr = ""
|
||||
@ -584,7 +583,7 @@ def get_nic_hwaddr(nic):
|
||||
|
||||
|
||||
def cmp_pkgrevno(package, revno, pkgcache=None):
|
||||
'''Compare supplied revno with the revno of the installed package
|
||||
"""Compare supplied revno with the revno of the installed package
|
||||
|
||||
* 1 => Installed revno is greater than supplied arg
|
||||
* 0 => Installed revno is the same as supplied arg
|
||||
@ -593,7 +592,7 @@ def cmp_pkgrevno(package, revno, pkgcache=None):
|
||||
This function imports apt_cache function from charmhelpers.fetch if
|
||||
the pkgcache argument is None. Be sure to add charmhelpers.fetch if
|
||||
you call this function, or pass an apt_pkg.Cache() instance.
|
||||
'''
|
||||
"""
|
||||
import apt_pkg
|
||||
if not pkgcache:
|
||||
from charmhelpers.fetch import apt_cache
|
||||
@ -603,19 +602,27 @@ def cmp_pkgrevno(package, revno, pkgcache=None):
|
||||
|
||||
|
||||
@contextmanager
|
||||
def chdir(d):
|
||||
def chdir(directory):
|
||||
"""Change the current working directory to a different directory for a code
|
||||
block and return the previous directory after the block exits. Useful to
|
||||
run commands from a specificed directory.
|
||||
|
||||
:param str directory: The directory path to change to for this context.
|
||||
"""
|
||||
cur = os.getcwd()
|
||||
try:
|
||||
yield os.chdir(d)
|
||||
yield os.chdir(directory)
|
||||
finally:
|
||||
os.chdir(cur)
|
||||
|
||||
|
||||
def chownr(path, owner, group, follow_links=True, chowntopdir=False):
|
||||
"""
|
||||
Recursively change user and group ownership of files and directories
|
||||
"""Recursively change user and group ownership of files and directories
|
||||
in given path. Doesn't chown path itself by default, only its children.
|
||||
|
||||
:param str path: The string path to start changing ownership.
|
||||
:param str owner: The owner string to use when looking up the uid.
|
||||
:param str group: The group string to use when looking up the gid.
|
||||
:param bool follow_links: Also Chown links if True
|
||||
:param bool chowntopdir: Also chown path itself if True
|
||||
"""
|
||||
@ -639,15 +646,23 @@ def chownr(path, owner, group, follow_links=True, chowntopdir=False):
|
||||
|
||||
|
||||
def lchownr(path, owner, group):
|
||||
"""Recursively change user and group ownership of files and directories
|
||||
in a given path, not following symbolic links. See the documentation for
|
||||
'os.lchown' for more information.
|
||||
|
||||
:param str path: The string path to start changing ownership.
|
||||
:param str owner: The owner string to use when looking up the uid.
|
||||
:param str group: The group string to use when looking up the gid.
|
||||
"""
|
||||
chownr(path, owner, group, follow_links=False)
|
||||
|
||||
|
||||
def get_total_ram():
|
||||
'''The total amount of system RAM in bytes.
|
||||
"""The total amount of system RAM in bytes.
|
||||
|
||||
This is what is reported by the OS, and may be overcommitted when
|
||||
there are multiple containers hosted on the same machine.
|
||||
'''
|
||||
"""
|
||||
with open('/proc/meminfo', 'r') as f:
|
||||
for line in f.readlines():
|
||||
if line:
|
||||
|
@ -15,7 +15,7 @@
|
||||
# along with charm-helpers. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import os
|
||||
from subprocess import check_call
|
||||
from subprocess import check_call, CalledProcessError
|
||||
from charmhelpers.fetch import (
|
||||
BaseFetchHandler,
|
||||
UnhandledSource,
|
||||
@ -49,8 +49,8 @@ class GitUrlFetchHandler(BaseFetchHandler):
|
||||
cmd = ['git', '-C', dest, 'pull', source, branch]
|
||||
else:
|
||||
cmd = ['git', 'clone', source, dest, '--branch', branch]
|
||||
if depth:
|
||||
cmd.extend(['--depth', depth])
|
||||
if depth:
|
||||
cmd.extend(['--depth', depth])
|
||||
check_call(cmd)
|
||||
|
||||
def install(self, source, branch="master", dest=None, depth=None):
|
||||
@ -63,6 +63,8 @@ class GitUrlFetchHandler(BaseFetchHandler):
|
||||
branch_name)
|
||||
try:
|
||||
self.clone(source, dest_dir, branch, depth)
|
||||
except CalledProcessError as e:
|
||||
raise UnhandledSource(e)
|
||||
except OSError as e:
|
||||
raise UnhandledSource(e.strerror)
|
||||
return dest_dir
|
||||
|
@ -219,6 +219,12 @@ def install():
|
||||
active=config('service-guard'))
|
||||
@restart_on_change(restart_map(), stopstart=True)
|
||||
def config_changed():
|
||||
# neutron-server runs if < juno. Neutron-server creates mysql tables
|
||||
# which will subsequently cause db migratoins to fail if >= juno.
|
||||
# Disable neutron-server if >= juno
|
||||
if os_release('nova-common') >= 'juno':
|
||||
with open('/etc/init/neutron-server.override', 'wb') as out:
|
||||
out.write('manual\n')
|
||||
if config('prefer-ipv6'):
|
||||
status_set('maintenance', 'configuring ipv6')
|
||||
setup_ipv6()
|
||||
|
@ -162,6 +162,10 @@ BASE_SERVICES = [
|
||||
'nova-scheduler',
|
||||
]
|
||||
|
||||
SERVICE_BLACKLIST = {
|
||||
'liberty': ['nova-api-ec2', 'nova-objectstore']
|
||||
}
|
||||
|
||||
API_PORTS = {
|
||||
'nova-api-ec2': 8773,
|
||||
'nova-api-os-compute': 8774,
|
||||
@ -186,9 +190,20 @@ APACHE_24_CONF = '/etc/apache2/sites-available/openstack_https_frontend.conf'
|
||||
NEUTRON_DEFAULT = '/etc/default/neutron-server'
|
||||
QUANTUM_DEFAULT = '/etc/default/quantum-server'
|
||||
|
||||
|
||||
def resolve_services():
|
||||
_services = deepcopy(BASE_SERVICES)
|
||||
os_rel = get_os_codename_install_source(config('openstack-origin'))
|
||||
for release in SERVICE_BLACKLIST:
|
||||
if os_rel >= release:
|
||||
[_services.remove(service)
|
||||
for service in SERVICE_BLACKLIST[release]]
|
||||
return _services
|
||||
|
||||
|
||||
BASE_RESOURCE_MAP = OrderedDict([
|
||||
(NOVA_CONF, {
|
||||
'services': BASE_SERVICES,
|
||||
'services': resolve_services(),
|
||||
'contexts': [context.AMQPContext(ssl_dir=NOVA_CONF_DIR),
|
||||
context.SharedDBContext(
|
||||
relation_prefix='nova', ssl_dir=NOVA_CONF_DIR),
|
||||
@ -220,7 +235,7 @@ BASE_RESOURCE_MAP = OrderedDict([
|
||||
nova_cc_context.CloudComputeContext()],
|
||||
}),
|
||||
(NOVA_API_PASTE, {
|
||||
'services': [s for s in BASE_SERVICES if 'api' in s],
|
||||
'services': [s for s in resolve_services() if 'api' in s],
|
||||
'contexts': [nova_cc_context.IdentityServiceContext(),
|
||||
nova_cc_context.APIRateLimitingContext()],
|
||||
}),
|
||||
@ -348,8 +363,7 @@ def resource_map():
|
||||
if plugin:
|
||||
conf = neutron_plugin_attribute(plugin, 'config', net_manager)
|
||||
ctxts = (neutron_plugin_attribute(plugin, 'contexts',
|
||||
net_manager) or
|
||||
[])
|
||||
net_manager) or [])
|
||||
services = neutron_plugin_attribute(plugin, 'server_services',
|
||||
net_manager)
|
||||
resource_map[conf] = {}
|
||||
@ -1010,7 +1024,7 @@ def guard_map():
|
||||
'''Map of services and required interfaces that must be present before
|
||||
the service should be allowed to start'''
|
||||
gmap = {}
|
||||
nova_services = deepcopy(BASE_SERVICES)
|
||||
nova_services = resolve_services()
|
||||
if os_release('nova-common') not in ['essex', 'folsom']:
|
||||
nova_services.append('nova-conductor')
|
||||
|
||||
|
174
templates/mitaka/nova.conf
Normal file
174
templates/mitaka/nova.conf
Normal file
@ -0,0 +1,174 @@
|
||||
# mitaka
|
||||
###############################################################################
|
||||
# [ WARNING ]
|
||||
# Configuration file maintained by Juju. Local changes may be overwritten.
|
||||
###############################################################################
|
||||
[DEFAULT]
|
||||
verbose={{ verbose }}
|
||||
debug={{ debug }}
|
||||
dhcpbridge_flagfile=/etc/nova/nova.conf
|
||||
dhcpbridge=/usr/bin/nova-dhcpbridge
|
||||
logdir=/var/log/nova
|
||||
state_path=/var/lib/nova
|
||||
force_dhcp_release=True
|
||||
iscsi_helper=tgtadm
|
||||
libvirt_use_virtio_for_bridges=True
|
||||
connection_type=libvirt
|
||||
root_helper=sudo nova-rootwrap /etc/nova/rootwrap.conf
|
||||
ec2_private_dns_show_ip=True
|
||||
api_paste_config=/etc/nova/api-paste.ini
|
||||
volumes_path=/var/lib/nova/volumes
|
||||
enabled_apis=ec2,osapi_compute,metadata
|
||||
auth_strategy=keystone
|
||||
compute_driver=libvirt.LibvirtDriver
|
||||
use_ipv6 = {{ use_ipv6 }}
|
||||
osapi_compute_listen = {{ bind_host }}
|
||||
metadata_host = {{ bind_host }}
|
||||
s3_listen = {{ bind_host }}
|
||||
ec2_listen = {{ bind_host }}
|
||||
|
||||
osapi_compute_workers = {{ workers }}
|
||||
ec2_workers = {{ workers }}
|
||||
|
||||
scheduler_default_filters = {{ scheduler_default_filters }}
|
||||
cpu_allocation_ratio = {{ cpu_allocation_ratio }}
|
||||
ram_allocation_ratio = {{ ram_allocation_ratio }}
|
||||
|
||||
use_syslog={{ use_syslog }}
|
||||
my_ip = {{ host_ip }}
|
||||
|
||||
{% if memcached_servers %}
|
||||
memcached_servers = {{ memcached_servers }}
|
||||
{% endif %}
|
||||
|
||||
{% include "parts/novnc" %}
|
||||
|
||||
{% if keystone_ec2_url -%}
|
||||
keystone_ec2_url = {{ keystone_ec2_url }}
|
||||
{% endif -%}
|
||||
|
||||
{% if rbd_pool -%}
|
||||
rbd_pool = {{ rbd_pool }}
|
||||
rbd_user = {{ rbd_user }}
|
||||
rbd_secret_uuid = {{ rbd_secret_uuid }}
|
||||
{% endif -%}
|
||||
|
||||
{% if neutron_plugin and neutron_plugin == 'ovs' -%}
|
||||
libvirt_vif_driver = nova.virt.libvirt.vif.LibvirtGenericVIFDriver
|
||||
libvirt_user_virtio_for_bridges = True
|
||||
{% if neutron_security_groups -%}
|
||||
security_group_api = {{ network_manager }}
|
||||
nova_firewall_driver = nova.virt.firewall.NoopFirewallDriver
|
||||
{% endif -%}
|
||||
{% if external_network -%}
|
||||
default_floating_pool = {{ external_network }}
|
||||
{% endif -%}
|
||||
{% endif -%}
|
||||
|
||||
{% if neutron_plugin and neutron_plugin == 'vsp' -%}
|
||||
neutron_ovs_bridge = alubr0
|
||||
{% endif -%}
|
||||
|
||||
{% if neutron_plugin and neutron_plugin == 'nvp' -%}
|
||||
security_group_api = neutron
|
||||
nova_firewall_driver = nova.virt.firewall.NoopFirewallDriver
|
||||
{% if external_network -%}
|
||||
default_floating_pool = {{ external_network }}
|
||||
{% endif -%}
|
||||
{% endif -%}
|
||||
|
||||
{% if neutron_plugin and neutron_plugin == 'Calico' -%}
|
||||
security_group_api = neutron
|
||||
nova_firewall_driver = nova.virt.firewall.NoopFirewallDriver
|
||||
{% endif -%}
|
||||
|
||||
{% if neutron_plugin and neutron_plugin == 'plumgrid' -%}
|
||||
security_group_api=neutron
|
||||
firewall_driver = nova.virt.firewall.NoopFirewallDriver
|
||||
{% endif -%}
|
||||
|
||||
{% if network_manager_config -%}
|
||||
{% for key, value in network_manager_config.iteritems() -%}
|
||||
{{ key }} = {{ value }}
|
||||
{% endfor -%}
|
||||
{% endif -%}
|
||||
|
||||
{% if network_manager and network_manager == 'neutron' -%}
|
||||
network_api_class = nova.network.neutronv2.api.API
|
||||
{% else -%}
|
||||
network_manager = nova.network.manager.FlatDHCPManager
|
||||
{% endif -%}
|
||||
|
||||
{% if default_floating_pool -%}
|
||||
default_floating_pool = {{ default_floating_pool }}
|
||||
{% endif -%}
|
||||
|
||||
{% if volume_service -%}
|
||||
volume_api_class=nova.volume.cinder.API
|
||||
{% endif -%}
|
||||
|
||||
{% if user_config_flags -%}
|
||||
{% for key, value in user_config_flags.iteritems() -%}
|
||||
{{ key }} = {{ value }}
|
||||
{% endfor -%}
|
||||
{% endif -%}
|
||||
|
||||
{% if listen_ports -%}
|
||||
{% for key, value in listen_ports.iteritems() -%}
|
||||
{{ key }} = {{ value }}
|
||||
{% endfor -%}
|
||||
{% endif -%}
|
||||
|
||||
{% if sections and 'DEFAULT' in sections -%}
|
||||
{% for key, value in sections['DEFAULT'] -%}
|
||||
{{ key }} = {{ value }}
|
||||
{% endfor -%}
|
||||
{% endif %}
|
||||
|
||||
{% include "section-zeromq" %}
|
||||
|
||||
{% include "parts/database-v2" %}
|
||||
|
||||
{% if glance_api_servers -%}
|
||||
[glance]
|
||||
api_servers = {{ glance_api_servers }}
|
||||
{% endif -%}
|
||||
|
||||
{% if network_manager and network_manager == 'neutron' -%}
|
||||
[neutron]
|
||||
url = {{ neutron_url }}
|
||||
{% if auth_host -%}
|
||||
auth_plugin = password
|
||||
project_name = {{ admin_tenant_name }}
|
||||
username = {{ admin_user }}
|
||||
password = {{ admin_password }}
|
||||
auth_url = {{ auth_protocol }}://{{ auth_host }}:{{ auth_port }}
|
||||
region = {{ region }}
|
||||
{% endif -%}
|
||||
{% endif -%}
|
||||
|
||||
[keystone_authtoken]
|
||||
{% if auth_host -%}
|
||||
auth_type = password
|
||||
project_name = {{ admin_tenant_name }}
|
||||
username = {{ admin_user }}
|
||||
password = {{ admin_password }}
|
||||
auth_url = {{ auth_protocol }}://{{ auth_host }}:{{ auth_port }}
|
||||
region = {{ region }}
|
||||
{% endif -%}
|
||||
|
||||
[osapi_v3]
|
||||
enabled=True
|
||||
|
||||
{% include "parts/cell" %}
|
||||
|
||||
[conductor]
|
||||
workers = {{ workers }}
|
||||
|
||||
{% include "section-rabbitmq-oslo" %}
|
||||
|
||||
[oslo_concurrency]
|
||||
lock_path=/var/lock/nova
|
||||
|
||||
[spice]
|
||||
{% include "parts/spice" %}
|
@ -195,6 +195,9 @@ class NovaCCBasicDeployment(OpenStackAmuletDeployment):
|
||||
self.keystone_sentry: ['keystone'],
|
||||
self.glance_sentry: ['glance-registry', 'glance-api']
|
||||
}
|
||||
if self._get_openstack_release_string() >= 'liberty':
|
||||
services[self.nova_cc_sentry].remove('nova-api-ec2')
|
||||
services[self.nova_cc_sentry].remove('nova-objectstore')
|
||||
|
||||
ret = u.validate_services_by_name(services)
|
||||
if ret:
|
||||
@ -731,6 +734,10 @@ class NovaCCBasicDeployment(OpenStackAmuletDeployment):
|
||||
'nova-conductor': conf_file
|
||||
}
|
||||
|
||||
if self._get_openstack_release_string() >= 'liberty':
|
||||
del services['nova-api-ec2']
|
||||
del services['nova-objectstore']
|
||||
|
||||
# Expected default and alternate values
|
||||
flags_default = 'quota_cores=20,quota_instances=40,quota_ram=102400'
|
||||
flags_alt = 'quota_cores=10,quota_instances=20,quota_ram=51200'
|
||||
|
@ -121,11 +121,12 @@ class OpenStackAmuletDeployment(AmuletDeployment):
|
||||
|
||||
# Charms which should use the source config option
|
||||
use_source = ['mysql', 'mongodb', 'rabbitmq-server', 'ceph',
|
||||
'ceph-osd', 'ceph-radosgw']
|
||||
'ceph-osd', 'ceph-radosgw', 'ceph-mon']
|
||||
|
||||
# Charms which can not use openstack-origin, ie. many subordinates
|
||||
no_origin = ['cinder-ceph', 'hacluster', 'neutron-openvswitch', 'nrpe',
|
||||
'openvswitch-odl', 'neutron-api-odl', 'odl-controller']
|
||||
'openvswitch-odl', 'neutron-api-odl', 'odl-controller',
|
||||
'cinder-backup']
|
||||
|
||||
if self.openstack:
|
||||
for svc in services:
|
||||
|
4
tox.ini
4
tox.ini
@ -1,5 +1,5 @@
|
||||
[tox]
|
||||
envlist = lint,py27
|
||||
envlist = pep8,py27
|
||||
skipsdist = True
|
||||
|
||||
[testenv]
|
||||
@ -14,7 +14,7 @@ basepython = python2.7
|
||||
deps = -r{toxinidir}/requirements.txt
|
||||
-r{toxinidir}/test-requirements.txt
|
||||
|
||||
[testenv:lint]
|
||||
[testenv:pep8]
|
||||
basepython = python2.7
|
||||
deps = -r{toxinidir}/requirements.txt
|
||||
-r{toxinidir}/test-requirements.txt
|
||||
|
@ -794,6 +794,7 @@ class NovaCCUtilsTests(CharmTestCase):
|
||||
self.relation_ids.return_value = []
|
||||
self.network_manager.return_value = 'neutron'
|
||||
self.os_release.return_value = 'icehouse'
|
||||
self.get_os_codename_install_source.return_value = 'icehouse'
|
||||
self.is_relation_made.return_value = False
|
||||
self.assertEqual(
|
||||
{'neutron-server': ['identity-service', 'amqp', 'shared-db'],
|
||||
@ -807,6 +808,7 @@ class NovaCCUtilsTests(CharmTestCase):
|
||||
)
|
||||
self.network_manager.return_value = 'quantum'
|
||||
self.os_release.return_value = 'grizzly'
|
||||
self.get_os_codename_install_source.return_value = 'grizzly'
|
||||
self.assertEqual(
|
||||
{'quantum-server': ['identity-service', 'amqp', 'shared-db'],
|
||||
'nova-api-ec2': ['identity-service', 'amqp', 'shared-db'],
|
||||
@ -817,6 +819,17 @@ class NovaCCUtilsTests(CharmTestCase):
|
||||
'nova-scheduler': ['identity-service', 'amqp', 'shared-db'], },
|
||||
utils.guard_map()
|
||||
)
|
||||
self.network_manager.return_value = 'neutron'
|
||||
self.os_release.return_value = 'mitaka'
|
||||
self.get_os_codename_install_source.return_value = 'mitaka'
|
||||
self.assertEqual(
|
||||
{'neutron-server': ['identity-service', 'amqp', 'shared-db'],
|
||||
'nova-api-os-compute': ['identity-service', 'amqp', 'shared-db'],
|
||||
'nova-cert': ['identity-service', 'amqp', 'shared-db'],
|
||||
'nova-conductor': ['identity-service', 'amqp', 'shared-db'],
|
||||
'nova-scheduler': ['identity-service', 'amqp', 'shared-db'], },
|
||||
utils.guard_map()
|
||||
)
|
||||
|
||||
def test_guard_map_pgsql(self):
|
||||
self.relation_ids.return_value = ['pgsql:1']
|
||||
|
Loading…
x
Reference in New Issue
Block a user