Remove deploy from source support

Drop support for deployment from Git repositories, as deprecated
in the 17.02 charm release.  This feature is unmaintained and has
no known users.

Change-Id: I44a7a92d5d4ae493bab4d5b81e9757cb12149a66
This commit is contained in:
James Page 2017-12-21 14:55:43 +00:00
parent 7b9feea400
commit c4574ef859
32 changed files with 214 additions and 1960 deletions

View File

@ -1,5 +1,3 @@
git-reinstall:
description: Reinstall nova-compute from the openstack-origin-git repositories.
openstack-upgrade:
description: Perform openstack upgrades. Config option action-managed-upgrade must be set to True.
pause:

View File

@ -1,60 +0,0 @@
#!/usr/bin/env python3
#
# Copyright 2016 Canonical Ltd
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import sys
import traceback
sys.path.append('hooks/')
from charmhelpers.contrib.openstack.utils import (
git_install_requested,
)
from charmhelpers.core.hookenv import (
action_set,
action_fail,
config,
)
from nova_compute_utils import (
git_install,
)
from nova_compute_hooks import (
config_changed,
)
def git_reinstall():
"""Reinstall from source and restart services.
If the openstack-origin-git config option was used to install openstack
from source git repositories, then this action can be used to reinstall
from updated git repositories, followed by a restart of services."""
if not git_install_requested():
action_fail('openstack-origin-git is not configured')
return
try:
git_install(config('openstack-origin-git'))
config_changed()
except:
action_set({'traceback': traceback.format_exc()})
action_fail('git-reinstall resulted in an unexpected error')
if __name__ == '__main__':
git_reinstall()

View File

@ -38,33 +38,6 @@ options:
NOTE: updating this setting to a source that is known to provide
a later version of OpenStack will trigger a software upgrade.
.
openstack-origin-git:
type: string
default:
description: |
Specifies a default OpenStack release name, or a YAML dictionary
listing the git repositories to install from.
.
The default Openstack release name may be one of the following, where
the corresponding OpenStack github branch will be used:
* liberty
* mitaka
* newton
* master
.
The YAML must minimally include requirements, neutron, and nova
repositories, and may also include repositories for other dependencies:
repositories:
- {name: requirements,
repository: 'git://github.com/openstack/requirements',
branch: master}
- {name: neutron,
repository: 'git://github.com/openstack/neutron',
branch: master}
- {name: nova,
repository: 'git://github.com/openstack/nova',
branch: master
release: master
action-managed-upgrade:
type: boolean
default: False

View File

@ -97,8 +97,6 @@ from charmhelpers.contrib.network.ip import (
from charmhelpers.contrib.openstack.utils import (
config_flags_parser,
get_host_ip,
git_determine_usr_bin,
git_determine_python_path,
enable_memcache,
snap_install_requested,
CompareOpenStackReleases,
@ -334,10 +332,7 @@ class IdentityServiceContext(OSContextGenerator):
self.rel_name = rel_name
self.interfaces = [self.rel_name]
def __call__(self):
log('Generating template context for ' + self.rel_name, level=DEBUG)
ctxt = {}
def _setup_pki_cache(self):
if self.service and self.service_user:
# This is required for pki token signing if we don't want /tmp to
# be used.
@ -347,6 +342,15 @@ class IdentityServiceContext(OSContextGenerator):
mkdir(path=cachedir, owner=self.service_user,
group=self.service_user, perms=0o700)
return cachedir
return None
def __call__(self):
log('Generating template context for ' + self.rel_name, level=DEBUG)
ctxt = {}
cachedir = self._setup_pki_cache()
if cachedir:
ctxt['signing_dir'] = cachedir
for rid in relation_ids(self.rel_name):
@ -385,6 +389,62 @@ class IdentityServiceContext(OSContextGenerator):
return {}
class IdentityCredentialsContext(IdentityServiceContext):
'''Context for identity-credentials interface type'''
def __init__(self,
service=None,
service_user=None,
rel_name='identity-credentials'):
super(IdentityCredentialsContext, self).__init__(service,
service_user,
rel_name)
def __call__(self):
log('Generating template context for ' + self.rel_name, level=DEBUG)
ctxt = {}
cachedir = self._setup_pki_cache()
if cachedir:
ctxt['signing_dir'] = cachedir
for rid in relation_ids(self.rel_name):
self.related = True
for unit in related_units(rid):
rdata = relation_get(rid=rid, unit=unit)
credentials_host = rdata.get('credentials_host')
credentials_host = (
format_ipv6_addr(credentials_host) or credentials_host
)
auth_host = rdata.get('auth_host')
auth_host = format_ipv6_addr(auth_host) or auth_host
svc_protocol = rdata.get('credentials_protocol') or 'http'
auth_protocol = rdata.get('auth_protocol') or 'http'
api_version = rdata.get('api_version') or '2.0'
ctxt.update({
'service_port': rdata.get('credentials_port'),
'service_host': credentials_host,
'auth_host': auth_host,
'auth_port': rdata.get('auth_port'),
'admin_tenant_name': rdata.get('credentials_project'),
'admin_tenant_id': rdata.get('credentials_project_id'),
'admin_user': rdata.get('credentials_username'),
'admin_password': rdata.get('credentials_password'),
'service_protocol': svc_protocol,
'auth_protocol': auth_protocol,
'api_version': api_version
})
if float(api_version) > 2:
ctxt.update({'admin_domain_name':
rdata.get('domain')})
if self.context_complete(ctxt):
return ctxt
return {}
class AMQPContext(OSContextGenerator):
def __init__(self, ssl_dir=None, rel_name='amqp', relation_prefix=None):
@ -1323,8 +1383,6 @@ class WSGIWorkerConfigContext(WorkerConfigContext):
"public_processes": int(math.ceil(self.public_process_weight *
total_processes)),
"threads": 1,
"usr_bin": git_determine_usr_bin(),
"python_path": git_determine_python_path(),
}
return ctxt

View File

@ -17,22 +17,22 @@ defaults
{%- if haproxy_queue_timeout %}
timeout queue {{ haproxy_queue_timeout }}
{%- else %}
timeout queue 5000
timeout queue 9000
{%- endif %}
{%- if haproxy_connect_timeout %}
timeout connect {{ haproxy_connect_timeout }}
{%- else %}
timeout connect 5000
timeout connect 9000
{%- endif %}
{%- if haproxy_client_timeout %}
timeout client {{ haproxy_client_timeout }}
{%- else %}
timeout client 30000
timeout client 90000
{%- endif %}
{%- if haproxy_server_timeout %}
timeout server {{ haproxy_server_timeout }}
{%- else %}
timeout server 30000
timeout server 90000
{%- endif %}
listen stats

View File

@ -23,7 +23,6 @@ import sys
import re
import itertools
import functools
import shutil
import six
import traceback
@ -47,7 +46,6 @@ from charmhelpers.core.hookenv import (
related_units,
relation_ids,
relation_set,
service_name,
status_set,
hook_name,
application_version_set,
@ -68,11 +66,6 @@ from charmhelpers.contrib.network.ip import (
port_has_listener,
)
from charmhelpers.contrib.python.packages import (
pip_create_virtualenv,
pip_install,
)
from charmhelpers.core.host import (
lsb_release,
mounts,
@ -84,7 +77,6 @@ from charmhelpers.core.host import (
)
from charmhelpers.fetch import (
apt_cache,
install_remote,
import_key as fetch_import_key,
add_source as fetch_add_source,
SourceConfigError,
@ -278,27 +270,6 @@ PACKAGE_CODENAMES = {
]),
}
GIT_DEFAULT_REPOS = {
'requirements': 'git://github.com/openstack/requirements',
'cinder': 'git://github.com/openstack/cinder',
'glance': 'git://github.com/openstack/glance',
'horizon': 'git://github.com/openstack/horizon',
'keystone': 'git://github.com/openstack/keystone',
'networking-hyperv': 'git://github.com/openstack/networking-hyperv',
'neutron': 'git://github.com/openstack/neutron',
'neutron-fwaas': 'git://github.com/openstack/neutron-fwaas',
'neutron-lbaas': 'git://github.com/openstack/neutron-lbaas',
'neutron-vpnaas': 'git://github.com/openstack/neutron-vpnaas',
'nova': 'git://github.com/openstack/nova',
}
GIT_DEFAULT_BRANCHES = {
'liberty': 'stable/liberty',
'mitaka': 'stable/mitaka',
'newton': 'stable/newton',
'master': 'master',
}
DEFAULT_LOOPBACK_SIZE = '5G'
@ -530,7 +501,6 @@ def os_release(package, base='essex', reset_cache=False):
if _os_rel:
return _os_rel
_os_rel = (
git_os_codename_install_source(config('openstack-origin-git')) or
get_os_codename_package(package, fatal=False) or
get_os_codename_install_source(config('openstack-origin')) or
base)
@ -771,417 +741,6 @@ def os_requires_version(ostack_release, pkg):
return wrap
def git_install_requested():
"""
Returns true if openstack-origin-git is specified.
"""
return config('openstack-origin-git') is not None
def git_os_codename_install_source(projects_yaml):
"""
Returns OpenStack codename of release being installed from source.
"""
if git_install_requested():
projects = _git_yaml_load(projects_yaml)
if projects in GIT_DEFAULT_BRANCHES.keys():
if projects == 'master':
return 'ocata'
return projects
if 'release' in projects:
if projects['release'] == 'master':
return 'ocata'
return projects['release']
return None
def git_default_repos(projects_yaml):
"""
Returns default repos if a default openstack-origin-git value is specified.
"""
service = service_name()
core_project = service
for default, branch in six.iteritems(GIT_DEFAULT_BRANCHES):
if projects_yaml == default:
# add the requirements repo first
repo = {
'name': 'requirements',
'repository': GIT_DEFAULT_REPOS['requirements'],
'branch': branch,
}
repos = [repo]
# neutron-* and nova-* charms require some additional repos
if service in ['neutron-api', 'neutron-gateway',
'neutron-openvswitch']:
core_project = 'neutron'
if service == 'neutron-api':
repo = {
'name': 'networking-hyperv',
'repository': GIT_DEFAULT_REPOS['networking-hyperv'],
'branch': branch,
}
repos.append(repo)
for project in ['neutron-fwaas', 'neutron-lbaas',
'neutron-vpnaas', 'nova']:
repo = {
'name': project,
'repository': GIT_DEFAULT_REPOS[project],
'branch': branch,
}
repos.append(repo)
elif service in ['nova-cloud-controller', 'nova-compute']:
core_project = 'nova'
repo = {
'name': 'neutron',
'repository': GIT_DEFAULT_REPOS['neutron'],
'branch': branch,
}
repos.append(repo)
elif service == 'openstack-dashboard':
core_project = 'horizon'
# finally add the current service's core project repo
repo = {
'name': core_project,
'repository': GIT_DEFAULT_REPOS[core_project],
'branch': branch,
}
repos.append(repo)
return yaml.dump(dict(repositories=repos, release=default))
return projects_yaml
def _git_yaml_load(projects_yaml):
"""
Load the specified yaml into a dictionary.
"""
if not projects_yaml:
return None
return yaml.load(projects_yaml)
requirements_dir = None
def git_clone_and_install(projects_yaml, core_project):
"""
Clone/install all specified OpenStack repositories.
The expected format of projects_yaml is:
repositories:
- {name: keystone,
repository: 'git://git.openstack.org/openstack/keystone.git',
branch: 'stable/icehouse'}
- {name: requirements,
repository: 'git://git.openstack.org/openstack/requirements.git',
branch: 'stable/icehouse'}
directory: /mnt/openstack-git
http_proxy: squid-proxy-url
https_proxy: squid-proxy-url
The directory, http_proxy, and https_proxy keys are optional.
"""
global requirements_dir
parent_dir = '/mnt/openstack-git'
http_proxy = None
projects = _git_yaml_load(projects_yaml)
_git_validate_projects_yaml(projects, core_project)
old_environ = dict(os.environ)
if 'http_proxy' in projects.keys():
http_proxy = projects['http_proxy']
os.environ['http_proxy'] = projects['http_proxy']
if 'https_proxy' in projects.keys():
os.environ['https_proxy'] = projects['https_proxy']
if 'directory' in projects.keys():
parent_dir = projects['directory']
pip_create_virtualenv(os.path.join(parent_dir, 'venv'))
# Upgrade setuptools and pip from default virtualenv versions. The default
# versions in trusty break master OpenStack branch deployments.
for p in ['pip', 'setuptools']:
pip_install(p, upgrade=True, proxy=http_proxy,
venv=os.path.join(parent_dir, 'venv'))
constraints = None
for p in projects['repositories']:
repo = p['repository']
branch = p['branch']
depth = '1'
if 'depth' in p.keys():
depth = p['depth']
if p['name'] == 'requirements':
repo_dir = _git_clone_and_install_single(repo, branch, depth,
parent_dir, http_proxy,
update_requirements=False)
requirements_dir = repo_dir
constraints = os.path.join(repo_dir, "upper-constraints.txt")
# upper-constraints didn't exist until after icehouse
if not os.path.isfile(constraints):
constraints = None
# use constraints unless project yaml sets use_constraints to false
if 'use_constraints' in projects.keys():
if not projects['use_constraints']:
constraints = None
else:
repo_dir = _git_clone_and_install_single(repo, branch, depth,
parent_dir, http_proxy,
update_requirements=True,
constraints=constraints)
os.environ = old_environ
def _git_validate_projects_yaml(projects, core_project):
"""
Validate the projects yaml.
"""
_git_ensure_key_exists('repositories', projects)
for project in projects['repositories']:
_git_ensure_key_exists('name', project.keys())
_git_ensure_key_exists('repository', project.keys())
_git_ensure_key_exists('branch', project.keys())
if projects['repositories'][0]['name'] != 'requirements':
error_out('{} git repo must be specified first'.format('requirements'))
if projects['repositories'][-1]['name'] != core_project:
error_out('{} git repo must be specified last'.format(core_project))
_git_ensure_key_exists('release', projects)
def _git_ensure_key_exists(key, keys):
"""
Ensure that key exists in keys.
"""
if key not in keys:
error_out('openstack-origin-git key \'{}\' is missing'.format(key))
def _git_clone_and_install_single(repo, branch, depth, parent_dir, http_proxy,
update_requirements, constraints=None):
"""
Clone and install a single git repository.
"""
if not os.path.exists(parent_dir):
juju_log('Directory already exists at {}. '
'No need to create directory.'.format(parent_dir))
os.mkdir(parent_dir)
juju_log('Cloning git repo: {}, branch: {}'.format(repo, branch))
repo_dir = install_remote(
repo, dest=parent_dir, branch=branch, depth=depth)
venv = os.path.join(parent_dir, 'venv')
if update_requirements:
if not requirements_dir:
error_out('requirements repo must be cloned before '
'updating from global requirements.')
_git_update_requirements(venv, repo_dir, requirements_dir)
juju_log('Installing git repo from dir: {}'.format(repo_dir))
if http_proxy:
pip_install(repo_dir, proxy=http_proxy, venv=venv,
constraints=constraints)
else:
pip_install(repo_dir, venv=venv, constraints=constraints)
return repo_dir
def _git_update_requirements(venv, package_dir, reqs_dir):
"""
Update from global requirements.
Update an OpenStack git directory's requirements.txt and
test-requirements.txt from global-requirements.txt.
"""
orig_dir = os.getcwd()
os.chdir(reqs_dir)
python = os.path.join(venv, 'bin/python')
cmd = [python, 'update.py', package_dir]
try:
subprocess.check_call(cmd)
except subprocess.CalledProcessError:
package = os.path.basename(package_dir)
error_out("Error updating {} from "
"global-requirements.txt".format(package))
os.chdir(orig_dir)
def git_pip_venv_dir(projects_yaml):
"""
Return the pip virtualenv path.
"""
parent_dir = '/mnt/openstack-git'
projects = _git_yaml_load(projects_yaml)
if 'directory' in projects.keys():
parent_dir = projects['directory']
return os.path.join(parent_dir, 'venv')
def git_src_dir(projects_yaml, project):
"""
Return the directory where the specified project's source is located.
"""
parent_dir = '/mnt/openstack-git'
projects = _git_yaml_load(projects_yaml)
if 'directory' in projects.keys():
parent_dir = projects['directory']
for p in projects['repositories']:
if p['name'] == project:
return os.path.join(parent_dir, os.path.basename(p['repository']))
return None
def git_yaml_value(projects_yaml, key):
"""
Return the value in projects_yaml for the specified key.
"""
projects = _git_yaml_load(projects_yaml)
if key in projects.keys():
return projects[key]
return None
def git_generate_systemd_init_files(templates_dir):
"""
Generate systemd init files.
Generates and installs systemd init units and script files based on the
*.init.in files contained in the templates_dir directory.
This code is based on the openstack-pkg-tools package and its init
script generation, which is used by the OpenStack packages.
"""
for f in os.listdir(templates_dir):
# Create the init script and systemd unit file from the template
if f.endswith(".init.in"):
init_in_file = f
init_file = f[:-8]
service_file = "{}.service".format(init_file)
init_in_source = os.path.join(templates_dir, init_in_file)
init_source = os.path.join(templates_dir, init_file)
service_source = os.path.join(templates_dir, service_file)
init_dest = os.path.join('/etc/init.d', init_file)
service_dest = os.path.join('/lib/systemd/system', service_file)
shutil.copyfile(init_in_source, init_source)
with open(init_source, 'a') as outfile:
template = ('/usr/share/openstack-pkg-tools/'
'init-script-template')
with open(template) as infile:
outfile.write('\n\n{}'.format(infile.read()))
cmd = ['pkgos-gen-systemd-unit', init_in_source]
subprocess.check_call(cmd)
if os.path.exists(init_dest):
os.remove(init_dest)
if os.path.exists(service_dest):
os.remove(service_dest)
shutil.copyfile(init_source, init_dest)
shutil.copyfile(service_source, service_dest)
os.chmod(init_dest, 0o755)
for f in os.listdir(templates_dir):
# If there's a service.in file, use it instead of the generated one
if f.endswith(".service.in"):
service_in_file = f
service_file = f[:-3]
service_in_source = os.path.join(templates_dir, service_in_file)
service_source = os.path.join(templates_dir, service_file)
service_dest = os.path.join('/lib/systemd/system', service_file)
shutil.copyfile(service_in_source, service_source)
if os.path.exists(service_dest):
os.remove(service_dest)
shutil.copyfile(service_source, service_dest)
for f in os.listdir(templates_dir):
# Generate the systemd unit if there's no existing .service.in
if f.endswith(".init.in"):
init_in_file = f
init_file = f[:-8]
service_in_file = "{}.service.in".format(init_file)
service_file = "{}.service".format(init_file)
init_in_source = os.path.join(templates_dir, init_in_file)
service_in_source = os.path.join(templates_dir, service_in_file)
service_source = os.path.join(templates_dir, service_file)
service_dest = os.path.join('/lib/systemd/system', service_file)
if not os.path.exists(service_in_source):
cmd = ['pkgos-gen-systemd-unit', init_in_source]
subprocess.check_call(cmd)
if os.path.exists(service_dest):
os.remove(service_dest)
shutil.copyfile(service_source, service_dest)
def git_determine_usr_bin():
"""Return the /usr/bin path for Apache2 config.
The /usr/bin path will be located in the virtualenv if the charm
is configured to deploy from source.
"""
if git_install_requested():
projects_yaml = config('openstack-origin-git')
projects_yaml = git_default_repos(projects_yaml)
return os.path.join(git_pip_venv_dir(projects_yaml), 'bin')
else:
return '/usr/bin'
def git_determine_python_path():
"""Return the python-path for Apache2 config.
Returns 'None' unless the charm is configured to deploy from source,
in which case the path of the virtualenv's site-packages is returned.
"""
if git_install_requested():
projects_yaml = config('openstack-origin-git')
projects_yaml = git_default_repos(projects_yaml)
return os.path.join(git_pip_venv_dir(projects_yaml),
'lib/python2.7/site-packages')
else:
return None
def os_workload_status(configs, required_interfaces, charm_func=None):
"""
Decorator to set workload status based on complete contexts
@ -1615,27 +1174,24 @@ def do_action_openstack_upgrade(package, upgrade_callback, configs):
"""
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')
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 Exception:
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.'})
try:
upgrade_callback(configs=configs)
action_set({'outcome': 'success, upgrade completed.'})
ret = True
except Exception:
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': 'no upgrade available.'})
action_set({'outcome': 'action-managed-upgrade config is '
'False, skipped upgrade.'})
else:
action_set({'outcome': 'no upgrade available.'})
return ret
@ -2045,14 +1601,25 @@ def token_cache_pkgs(source=None, release=None):
def update_json_file(filename, items):
"""Updates the json `filename` with a given dict.
:param filename: json filename (i.e.: /etc/glance/policy.json)
:param filename: path to json file (e.g. /etc/glance/policy.json)
:param items: dict of items to update
"""
if not items:
return
with open(filename) as fd:
policy = json.load(fd)
# Compare before and after and if nothing has changed don't write the file
# since that could cause unnecessary service restarts.
before = json.dumps(policy, indent=4, sort_keys=True)
policy.update(items)
after = json.dumps(policy, indent=4, sort_keys=True)
if before == after:
return
with open(filename, "w") as fd:
fd.write(json.dumps(policy, indent=4))
fd.write(after)
@cached

View File

@ -113,7 +113,7 @@ def validator(value, valid_type, valid_range=None):
assert isinstance(valid_range, list), \
"valid_range must be a list, was given {}".format(valid_range)
# If we're dealing with strings
if valid_type is six.string_types:
if isinstance(value, six.string_types):
assert value in valid_range, \
"{} is not in the list {}".format(value, valid_range)
# Integer, float should have a min and max
@ -517,7 +517,8 @@ def pool_set(service, pool_name, key, value):
:param value:
:return: None. Can raise CalledProcessError
"""
cmd = ['ceph', '--id', service, 'osd', 'pool', 'set', pool_name, key, value]
cmd = ['ceph', '--id', service, 'osd', 'pool', 'set', pool_name, key,
str(value).lower()]
try:
check_call(cmd)
except CalledProcessError:
@ -621,16 +622,24 @@ def create_erasure_profile(service, profile_name, erasure_plugin_name='jerasure'
:param durability_estimator: int
:return: None. Can raise CalledProcessError
"""
version = ceph_version()
# Ensure this failure_domain is allowed by Ceph
validator(failure_domain, six.string_types,
['chassis', 'datacenter', 'host', 'osd', 'pdu', 'pod', 'rack', 'region', 'room', 'root', 'row'])
cmd = ['ceph', '--id', service, 'osd', 'erasure-code-profile', 'set', profile_name,
'plugin=' + erasure_plugin_name, 'k=' + str(data_chunks), 'm=' + str(coding_chunks),
'ruleset_failure_domain=' + failure_domain]
'plugin=' + erasure_plugin_name, 'k=' + str(data_chunks), 'm=' + str(coding_chunks)
]
if locality is not None and durability_estimator is not None:
raise ValueError("create_erasure_profile should be called with k, m and one of l or c but not both.")
# failure_domain changed in luminous
if version and version >= '12.0.0':
cmd.append('crush-failure-domain=' + failure_domain)
else:
cmd.append('ruleset-failure-domain=' + failure_domain)
# Add plugin specific information
if locality is not None:
# For local erasure codes
@ -1064,14 +1073,24 @@ class CephBrokerRq(object):
self.ops = []
def add_op_request_access_to_group(self, name, namespace=None,
permission=None, key_name=None):
permission=None, key_name=None,
object_prefix_permissions=None):
"""
Adds the requested permissions to the current service's Ceph key,
allowing the key to access only the specified pools
allowing the key to access only the specified pools or
object prefixes. object_prefix_permissions should be a dictionary
keyed on the permission with the corresponding value being a list
of prefixes to apply that permission to.
{
'rwx': ['prefix1', 'prefix2'],
'class-read': ['prefix3']}
"""
self.ops.append({'op': 'add-permissions-to-key', 'group': name,
'namespace': namespace, 'name': key_name or service_name(),
'group-permission': permission})
self.ops.append({
'op': 'add-permissions-to-key', 'group': name,
'namespace': namespace,
'name': key_name or service_name(),
'group-permission': permission,
'object-prefix-permissions': object_prefix_permissions})
def add_op_create_pool(self, name, replica_count=3, pg_num=None,
weight=None, group=None, namespace=None):
@ -1107,7 +1126,10 @@ class CephBrokerRq(object):
def _ops_equal(self, other):
if len(self.ops) == len(other.ops):
for req_no in range(0, len(self.ops)):
for key in ['replicas', 'name', 'op', 'pg_num', 'weight']:
for key in [
'replicas', 'name', 'op', 'pg_num', 'weight',
'group', 'group-namespace', 'group-permission',
'object-prefix-permissions']:
if self.ops[req_no].get(key) != other.ops[req_no].get(key):
return False
else:

View File

@ -51,9 +51,7 @@ from charmhelpers.fetch import (
)
from charmhelpers.contrib.openstack.utils import (
config_value_changed,
configure_installation_source,
git_install_requested,
openstack_upgrade_available,
is_unit_paused_set,
pausable_restart_on_change as restart_on_change,
@ -72,7 +70,6 @@ from charmhelpers.payload.execd import execd_preinstall
from nova_compute_utils import (
create_libvirt_secret,
determine_packages,
git_install,
import_authorized_keys,
import_keystone_ca_cert,
initialize_ssh_keys,
@ -135,9 +132,6 @@ def install():
apt_update()
apt_install(determine_packages(), fatal=True)
status_set('maintenance', 'Git install')
git_install(config('openstack-origin-git'))
@hooks.hook('config-changed')
@restart_on_change(restart_map())
@ -154,11 +148,7 @@ def config_changed():
raise Exception(message)
global CONFIGS
send_remote_restart = False
if git_install_requested():
if config_value_changed('openstack-origin-git'):
status_set('maintenance', 'Running Git install')
git_install(config('openstack-origin-git'))
elif not config('action-managed-upgrade'):
if not config('action-managed-upgrade'):
if openstack_upgrade_available('nova-common'):
status_set('maintenance', 'Running openstack upgrade')
do_openstack_upgrade(CONFIGS)

View File

@ -14,7 +14,6 @@
import os
import re
import shutil
import pwd
import subprocess
import platform
@ -36,13 +35,9 @@ from charmhelpers.fetch import (
from charmhelpers.core.fstab import Fstab
from charmhelpers.core.host import (
adduser,
add_group,
add_user_to_group,
mkdir,
service_restart,
lsb_release,
write_file,
rsync,
CompareHostReleases,
)
@ -60,7 +55,6 @@ from charmhelpers.core.hookenv import (
WARNING,
)
from charmhelpers.core.templating import render
from charmhelpers.core.decorators import retry_on_exception
from charmhelpers.contrib.openstack import templating, context
from charmhelpers.contrib.openstack.alternatives import install_alternative
@ -68,13 +62,6 @@ from charmhelpers.contrib.openstack.alternatives import install_alternative
from charmhelpers.contrib.openstack.utils import (
configure_installation_source,
get_os_codename_install_source,
git_clone_and_install,
git_default_repos,
git_generate_systemd_init_files,
git_install_requested,
git_pip_venv_dir,
git_src_dir,
git_yaml_value,
os_release,
reset_os_release,
is_unit_paused_set,
@ -85,10 +72,6 @@ from charmhelpers.contrib.openstack.utils import (
CompareOpenStackReleases,
)
from charmhelpers.contrib.python.packages import (
pip_install,
)
from charmhelpers.core.hugepage import hugepage_support
from nova_compute_context import (
@ -130,61 +113,6 @@ BASE_PACKAGES = [
VERSION_PACKAGE = 'nova-common'
BASE_GIT_PACKAGES = [
'libffi-dev',
'libssl-dev',
'libvirt-bin',
'libxml2-dev',
'libxslt1-dev',
'libvirt-dev',
'libyaml-dev',
'openstack-pkg-tools',
'python-dev',
'python-pip',
'python-setuptools',
'zlib1g-dev',
]
LATE_GIT_PACKAGES = [
'bridge-utils',
'dnsmasq-base',
'dnsmasq-utils',
'ebtables',
'genisoimage',
'iptables',
'iputils-arping',
'kpartx',
'kvm',
'netcat',
'open-iscsi',
'parted',
'python-libvirt',
'qemu',
'qemu-system',
'qemu-utils',
'vlan',
]
# ubuntu packages that should not be installed when deploying from git
GIT_PACKAGE_BLACKLIST = [
'neutron-plugin-openvswitch',
'neutron-plugin-openvswitch-agent',
'neutron-server',
'nova-api',
'nova-api-metadata',
'nova-compute',
'nova-compute-kvm',
'nova-compute-lxc',
'nova-compute-lxd',
'nova-compute-qemu',
'nova-compute-uml',
'nova-network',
'python-six',
'quantum-plugin-openvswitch',
'quantum-plugin-openvswitch-agent',
'quantum-server',
]
DEFAULT_INSTANCE_PATH = '/var/lib/nova/instances'
NOVA_CONF_DIR = "/etc/nova"
QEMU_CONF = '/etc/libvirt/qemu.conf'
@ -445,14 +373,6 @@ def determine_packages():
packages.extend(determine_packages_arch())
if git_install_requested():
packages = list(set(packages))
packages.extend(BASE_GIT_PACKAGES)
# don't include packages that will be installed from git
for p in GIT_PACKAGE_BLACKLIST:
if p in packages:
packages.remove(p)
return packages
@ -697,11 +617,10 @@ def destroy_libvirt_network(netname):
def configure_lxd(user='nova'):
''' Configure lxd use for nova user '''
if not git_install_requested():
_release = lsb_release()['DISTRIB_CODENAME'].lower()
if CompareHostReleases(_release) < "vivid":
raise Exception("LXD is not supported for Ubuntu "
"versions less than 15.04 (vivid)")
_release = lsb_release()['DISTRIB_CODENAME'].lower()
if CompareHostReleases(_release) < "vivid":
raise Exception("LXD is not supported for Ubuntu "
"versions less than 15.04 (vivid)")
configure_subuid(user)
lxc_list(user)
@ -741,168 +660,6 @@ def assert_charm_supports_ipv6():
"versions less than Trusty 14.04")
def git_install(projects_yaml):
"""Perform setup, and install git repos specified in yaml parameter."""
if git_install_requested():
git_pre_install()
projects_yaml = git_default_repos(projects_yaml)
git_clone_and_install(projects_yaml, core_project='nova')
git_post_install(projects_yaml)
def git_pre_install():
"""Perform pre-install setup."""
dirs = [
'/var/lib/nova',
'/var/lib/nova/buckets',
'/var/lib/nova/CA',
'/var/lib/nova/CA/INTER',
'/var/lib/nova/CA/newcerts',
'/var/lib/nova/CA/private',
'/var/lib/nova/CA/reqs',
'/var/lib/nova/images',
'/var/lib/nova/instances',
'/var/lib/nova/keys',
'/var/lib/nova/networks',
'/var/lib/nova/tmp',
'/var/log/nova',
]
logs = [
'/var/log/nova/nova-api.log',
'/var/log/nova/nova-compute.log',
'/var/log/nova/nova-manage.log',
'/var/log/nova/nova-network.log',
]
adduser('nova', shell='/bin/bash', system_user=True)
check_call(['usermod', '--home', '/var/lib/nova', 'nova'])
add_group('nova', system_group=True)
add_user_to_group('nova', 'nova')
add_user_to_group('nova', 'libvirtd')
for d in dirs:
mkdir(d, owner='nova', group='nova', perms=0o0755, force=False)
for l in logs:
write_file(l, '', owner='nova', group='nova', perms=0o0644)
def git_post_install(projects_yaml):
"""Perform post-install setup."""
http_proxy = git_yaml_value(projects_yaml, 'http_proxy')
if http_proxy:
pip_install('libvirt-python', proxy=http_proxy,
venv=git_pip_venv_dir(projects_yaml))
else:
pip_install('libvirt-python',
venv=git_pip_venv_dir(projects_yaml))
src_etc = os.path.join(git_src_dir(projects_yaml, 'nova'), 'etc/nova')
configs = [
{'src': src_etc,
'dest': '/etc/nova'},
]
for c in configs:
if os.path.exists(c['dest']):
shutil.rmtree(c['dest'])
shutil.copytree(c['src'], c['dest'])
# NOTE(coreycb): Need to find better solution than bin symlinks.
symlinks = [
{'src': os.path.join(git_pip_venv_dir(projects_yaml),
'bin/nova-rootwrap'),
'link': '/usr/local/bin/nova-rootwrap'},
{'src': os.path.join(git_pip_venv_dir(projects_yaml),
'bin/privsep-helper'),
'link': '/usr/local/bin/privsep-helper'},
]
for s in symlinks:
if os.path.lexists(s['link']):
os.remove(s['link'])
os.symlink(s['src'], s['link'])
virt_type = VIRT_TYPES[config('virt-type')][0]
nova_compute_conf = 'git/{}.conf'.format(virt_type)
render(nova_compute_conf, '/etc/nova/nova-compute.conf', {}, perms=0o644)
render('git/nova_sudoers', '/etc/sudoers.d/nova_sudoers', {}, perms=0o440)
bin_dir = os.path.join(git_pip_venv_dir(projects_yaml), 'bin')
# Use systemd init units/scripts from ubuntu wily onward
if lsb_release()['DISTRIB_RELEASE'] >= '15.10':
templates_dir = os.path.join(charm_dir(), 'templates/git')
daemons = ['nova-api', 'nova-api-metadata', 'nova-compute',
'nova-network']
for daemon in daemons:
nova_compute_context = {
'daemon_path': os.path.join(bin_dir, daemon),
}
template_file = 'git/{}.init.in.template'.format(daemon)
init_in_file = '{}.init.in'.format(daemon)
render(template_file, os.path.join(templates_dir, init_in_file),
nova_compute_context, perms=0o644)
git_generate_systemd_init_files(templates_dir)
else:
service_name = 'nova-compute'
nova_user = 'nova'
start_dir = '/var/lib/nova'
nova_conf = '/etc/nova/nova.conf'
nova_api_context = {
'service_description': 'Nova API server',
'service_name': service_name,
'user_name': nova_user,
'start_dir': start_dir,
'process_name': 'nova-api',
'executable_name': os.path.join(bin_dir, 'nova-api'),
'config_files': [nova_conf],
}
nova_api_metadata_context = {
'service_description': 'Nova Metadata API server',
'service_name': service_name,
'user_name': nova_user,
'start_dir': start_dir,
'process_name': 'nova-api-metadata',
'executable_name': os.path.join(bin_dir, 'nova-api-metadata'),
'config_files': [nova_conf],
}
nova_compute_context = {
'service_description': 'Nova compute worker',
'service_name': service_name,
'user_name': nova_user,
'process_name': 'nova-compute',
'executable_name': os.path.join(bin_dir, 'nova-compute'),
'config_files': [nova_conf, '/etc/nova/nova-compute.conf'],
}
nova_network_context = {
'service_description': 'Nova network worker',
'service_name': service_name,
'user_name': nova_user,
'start_dir': start_dir,
'process_name': 'nova-network',
'executable_name': os.path.join(bin_dir, 'nova-network'),
'config_files': [nova_conf],
}
templates_dir = 'hooks/charmhelpers/contrib/openstack/templates'
templates_dir = os.path.join(charm_dir(), templates_dir)
render('git.upstart', '/etc/init/nova-api-metadata.conf',
nova_api_metadata_context, perms=0o644,
templates_dir=templates_dir)
render('git.upstart', '/etc/init/nova-api.conf',
nova_api_context, perms=0o644,
templates_dir=templates_dir)
render('git/upstart/nova-compute.upstart',
'/etc/init/nova-compute.conf',
nova_compute_context, perms=0o644)
render('git.upstart', '/etc/init/nova-network.conf',
nova_network_context, perms=0o644,
templates_dir=templates_dir)
apt_update()
apt_install(LATE_GIT_PACKAGES, fatal=True)
def get_hugepage_number():
# TODO: defaults to 2M - this should probably be configurable
# and support multiple pool sizes - e.g. 2M and 1G.

View File

@ -1,21 +0,0 @@
#!/bin/sh
### BEGIN INIT INFO
# Provides: nova-api-metadata
# Required-Start: $network $local_fs $remote_fs $syslog
# Required-Stop: $remote_fs
# Should-Start: postgresql mysql keystone rabbitmq-server ntp
# Should-Stop: postgresql mysql keystone rabbitmq-server ntp
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: Nova API metadata server
# Description: Frontend Nova API metadata server
### END INIT INFO
# Author: Julien Danjou <acid@debian.org>
# PATH should only include /usr/* if it runs after the mountnfs.sh script
PATH=/sbin:/usr/sbin:/bin:/usr/bin
DESC="OpenStack Compute metadata API"
PROJECT_NAME=nova
NAME=${PROJECT_NAME}-api-metadata
DAEMON={{ daemon_path }}

View File

@ -1,21 +0,0 @@
#!/bin/sh
### BEGIN INIT INFO
# Provides: nova-api
# Required-Start: $network $local_fs $remote_fs $syslog
# Required-Stop: $remote_fs
# Should-Start: postgresql mysql keystone rabbitmq-server ntp
# Should-Stop: postgresql mysql keystone rabbitmq-server ntp
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: Nova API server
# Description: Frontend Nova API server
### END INIT INFO
# Author: Julien Danjou <acid@debian.org>
# PATH should only include /usr/* if it runs after the mountnfs.sh script
PATH=/sbin:/usr/sbin:/bin:/usr/bin
DESC="OpenStack Compute API"
PROJECT_NAME=nova
NAME=${PROJECT_NAME}-api
DAEMON={{ daemon_path }}

View File

@ -1,4 +0,0 @@
[DEFAULT]
compute_driver=libvirt.LibvirtDriver
[libvirt]
virt_type=kvm

View File

@ -1,4 +0,0 @@
[DEFAULT]
compute_driver=libvirt.LibvirtDriver
[libvirt]
virt_type=lxc

View File

@ -1,2 +0,0 @@
[DEFAULT]
compute_driver=nova_lxd.nova.virt.lxd.LXDDriver

View File

@ -1,4 +0,0 @@
[DEFAULT]
compute_driver=libvirt.LibvirtDriver
[libvirt]
virt_type=qemu

View File

@ -1,2 +0,0 @@
[DEFAULT]
compute_driver=vmwareapi.VMwareVCDriver

View File

@ -1,4 +0,0 @@
[DEFAULT]
compute_driver=libvirt.LibvirtDriver
[libvirt]
virt_type=xen

View File

@ -1,27 +0,0 @@
#!/bin/sh
### BEGIN INIT INFO
# Provides: nova-compute
# Required-Start: $network $local_fs $remote_fs $syslog
# Required-Stop: $remote_fs
# Should-Start: libvirt-bin postgresql mysql keystone rabbitmq-server ntp neutron-ovs-cleanup
# Should-Stop: libvirt-bin postgresql mysql keystone rabbitmq-server ntp
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: Nova Compute server
# Description: Provides compute server resources for the
# OpenStack cloud computing system
### END INIT INFO
# Author: Julien Danjou <acid@debian.org>
# PATH should only include /usr/* if it runs after the mountnfs.sh script
PATH=/sbin:/usr/sbin:/bin:/usr/bin
DESC="OpenStack Compute"
PROJECT_NAME=nova
NAME=${PROJECT_NAME}-compute
DAEMON={{ daemon_path }}
DAEMON_ARGS=""
if [ -f '/etc/nova/nova-compute.conf' ] ; then
DAEMON_ARGS="--config-file=/etc/nova/nova-compute.conf"
fi

View File

@ -1,19 +0,0 @@
#!/bin/sh
### BEGIN INIT INFO
# Provides: nova-network
# Required-Start: $network $local_fs $remote_fs $syslog
# Required-Stop: $remote_fs
# Should-Start: postgresql mysql keystone
# Should-Stop: postgresql mysql keystone
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: Nova Network
# Description: Provides network resources
### END INIT INFO
# Author: Thomas Goirand <zigo@debian.org>
DESC="OpenStack Compute Network"
PROJECT_NAME=nova
NAME=${PROJECT_NAME}-network
DAEMON={{ daemon_path }}

View File

@ -1,4 +0,0 @@
Defaults:nova !requiretty
nova ALL = (root) NOPASSWD: /usr/local/bin/nova-rootwrap /etc/nova/rootwrap.conf *

View File

@ -1 +0,0 @@
include /var/lib/nova/volumes/*

View File

@ -1,27 +0,0 @@
description "{{ service_description }}"
author "Juju {{ service_name }} Charm <juju@localhost>"
start on runlevel [2345]
stop on runlevel [!2345]
chdir /var/run
pre-start script
mkdir -p /var/run/nova
chown nova:root /var/run/nova/
mkdir -p /var/lock/nova
chown nova:root /var/lock/nova/
modprobe nbd
# If libvirt-bin is installed, always wait for it to start first
if status libvirt-bin; then
start wait-for-state WAIT_FOR=libvirt-bin WAIT_STATE=running WAITER={{ process_name }}
fi
end script
exec start-stop-daemon --start --chuid {{ user_name }} --exec {{ executable_name }} -- \
{% for config_file in config_files -%}
--config-file={{ config_file }} \
{% endfor -%}

View File

@ -13,8 +13,6 @@
# limitations under the License.
import amulet
import os
import yaml
from charmhelpers.contrib.openstack.amulet.deployment import (
OpenStackAmuletDeployment
@ -52,11 +50,10 @@ class NovaBasicDeployment(OpenStackAmuletDeployment):
"""Amulet tests on a basic nova compute deployment."""
def __init__(self, series=None, openstack=None, source=None,
git=False, stable=False):
stable=False):
"""Deploy the entire test environment."""
super(NovaBasicDeployment, self).__init__(series, openstack,
source, stable)
self.git = git
self._add_services()
self._add_relations()
self._configure_services()
@ -137,41 +134,6 @@ class NovaBasicDeployment(OpenStackAmuletDeployment):
'enable-live-migration': 'False',
'aa-profile-mode': 'enforce'}
nova_cc_config = {}
if self.git:
amulet_http_proxy = os.environ.get('AMULET_HTTP_PROXY')
reqs_repo = 'git://github.com/openstack/requirements'
neutron_repo = 'git://github.com/openstack/neutron'
nova_repo = 'git://github.com/openstack/nova'
if self._get_openstack_release() == self.trusty_icehouse:
reqs_repo = 'git://github.com/coreycb/requirements'
neutron_repo = 'git://github.com/coreycb/neutron'
nova_repo = 'git://github.com/coreycb/nova'
branch = 'stable/' + self._get_openstack_release_string()
openstack_origin_git = {
'repositories': [
{'name': 'requirements',
'repository': reqs_repo,
'branch': branch},
{'name': 'neutron',
'repository': neutron_repo,
'branch': branch},
{'name': 'nova',
'repository': nova_repo,
'branch': branch},
],
'directory': '/mnt/openstack-git',
'http_proxy': amulet_http_proxy,
'https_proxy': amulet_http_proxy,
}
nova_config['openstack-origin-git'] = \
yaml.dump(openstack_origin_git)
nova_cc_config['openstack-origin-git'] = \
yaml.dump(openstack_origin_git)
if self._get_openstack_release() >= self.xenial_ocata:
nova_cc_config['network-manager'] = 'Neutron'

View File

@ -23,7 +23,6 @@ import sys
import re
import itertools
import functools
import shutil
import six
import traceback
@ -47,7 +46,6 @@ from charmhelpers.core.hookenv import (
related_units,
relation_ids,
relation_set,
service_name,
status_set,
hook_name,
application_version_set,
@ -68,11 +66,6 @@ from charmhelpers.contrib.network.ip import (
port_has_listener,
)
from charmhelpers.contrib.python.packages import (
pip_create_virtualenv,
pip_install,
)
from charmhelpers.core.host import (
lsb_release,
mounts,
@ -84,7 +77,6 @@ from charmhelpers.core.host import (
)
from charmhelpers.fetch import (
apt_cache,
install_remote,
import_key as fetch_import_key,
add_source as fetch_add_source,
SourceConfigError,
@ -278,27 +270,6 @@ PACKAGE_CODENAMES = {
]),
}
GIT_DEFAULT_REPOS = {
'requirements': 'git://github.com/openstack/requirements',
'cinder': 'git://github.com/openstack/cinder',
'glance': 'git://github.com/openstack/glance',
'horizon': 'git://github.com/openstack/horizon',
'keystone': 'git://github.com/openstack/keystone',
'networking-hyperv': 'git://github.com/openstack/networking-hyperv',
'neutron': 'git://github.com/openstack/neutron',
'neutron-fwaas': 'git://github.com/openstack/neutron-fwaas',
'neutron-lbaas': 'git://github.com/openstack/neutron-lbaas',
'neutron-vpnaas': 'git://github.com/openstack/neutron-vpnaas',
'nova': 'git://github.com/openstack/nova',
}
GIT_DEFAULT_BRANCHES = {
'liberty': 'stable/liberty',
'mitaka': 'stable/mitaka',
'newton': 'stable/newton',
'master': 'master',
}
DEFAULT_LOOPBACK_SIZE = '5G'
@ -530,7 +501,6 @@ def os_release(package, base='essex', reset_cache=False):
if _os_rel:
return _os_rel
_os_rel = (
git_os_codename_install_source(config('openstack-origin-git')) or
get_os_codename_package(package, fatal=False) or
get_os_codename_install_source(config('openstack-origin')) or
base)
@ -771,417 +741,6 @@ def os_requires_version(ostack_release, pkg):
return wrap
def git_install_requested():
"""
Returns true if openstack-origin-git is specified.
"""
return config('openstack-origin-git') is not None
def git_os_codename_install_source(projects_yaml):
"""
Returns OpenStack codename of release being installed from source.
"""
if git_install_requested():
projects = _git_yaml_load(projects_yaml)
if projects in GIT_DEFAULT_BRANCHES.keys():
if projects == 'master':
return 'ocata'
return projects
if 'release' in projects:
if projects['release'] == 'master':
return 'ocata'
return projects['release']
return None
def git_default_repos(projects_yaml):
"""
Returns default repos if a default openstack-origin-git value is specified.
"""
service = service_name()
core_project = service
for default, branch in six.iteritems(GIT_DEFAULT_BRANCHES):
if projects_yaml == default:
# add the requirements repo first
repo = {
'name': 'requirements',
'repository': GIT_DEFAULT_REPOS['requirements'],
'branch': branch,
}
repos = [repo]
# neutron-* and nova-* charms require some additional repos
if service in ['neutron-api', 'neutron-gateway',
'neutron-openvswitch']:
core_project = 'neutron'
if service == 'neutron-api':
repo = {
'name': 'networking-hyperv',
'repository': GIT_DEFAULT_REPOS['networking-hyperv'],
'branch': branch,
}
repos.append(repo)
for project in ['neutron-fwaas', 'neutron-lbaas',
'neutron-vpnaas', 'nova']:
repo = {
'name': project,
'repository': GIT_DEFAULT_REPOS[project],
'branch': branch,
}
repos.append(repo)
elif service in ['nova-cloud-controller', 'nova-compute']:
core_project = 'nova'
repo = {
'name': 'neutron',
'repository': GIT_DEFAULT_REPOS['neutron'],
'branch': branch,
}
repos.append(repo)
elif service == 'openstack-dashboard':
core_project = 'horizon'
# finally add the current service's core project repo
repo = {
'name': core_project,
'repository': GIT_DEFAULT_REPOS[core_project],
'branch': branch,
}
repos.append(repo)
return yaml.dump(dict(repositories=repos, release=default))
return projects_yaml
def _git_yaml_load(projects_yaml):
"""
Load the specified yaml into a dictionary.
"""
if not projects_yaml:
return None
return yaml.load(projects_yaml)
requirements_dir = None
def git_clone_and_install(projects_yaml, core_project):
"""
Clone/install all specified OpenStack repositories.
The expected format of projects_yaml is:
repositories:
- {name: keystone,
repository: 'git://git.openstack.org/openstack/keystone.git',
branch: 'stable/icehouse'}
- {name: requirements,
repository: 'git://git.openstack.org/openstack/requirements.git',
branch: 'stable/icehouse'}
directory: /mnt/openstack-git
http_proxy: squid-proxy-url
https_proxy: squid-proxy-url
The directory, http_proxy, and https_proxy keys are optional.
"""
global requirements_dir
parent_dir = '/mnt/openstack-git'
http_proxy = None
projects = _git_yaml_load(projects_yaml)
_git_validate_projects_yaml(projects, core_project)
old_environ = dict(os.environ)
if 'http_proxy' in projects.keys():
http_proxy = projects['http_proxy']
os.environ['http_proxy'] = projects['http_proxy']
if 'https_proxy' in projects.keys():
os.environ['https_proxy'] = projects['https_proxy']
if 'directory' in projects.keys():
parent_dir = projects['directory']
pip_create_virtualenv(os.path.join(parent_dir, 'venv'))
# Upgrade setuptools and pip from default virtualenv versions. The default
# versions in trusty break master OpenStack branch deployments.
for p in ['pip', 'setuptools']:
pip_install(p, upgrade=True, proxy=http_proxy,
venv=os.path.join(parent_dir, 'venv'))
constraints = None
for p in projects['repositories']:
repo = p['repository']
branch = p['branch']
depth = '1'
if 'depth' in p.keys():
depth = p['depth']
if p['name'] == 'requirements':
repo_dir = _git_clone_and_install_single(repo, branch, depth,
parent_dir, http_proxy,
update_requirements=False)
requirements_dir = repo_dir
constraints = os.path.join(repo_dir, "upper-constraints.txt")
# upper-constraints didn't exist until after icehouse
if not os.path.isfile(constraints):
constraints = None
# use constraints unless project yaml sets use_constraints to false
if 'use_constraints' in projects.keys():
if not projects['use_constraints']:
constraints = None
else:
repo_dir = _git_clone_and_install_single(repo, branch, depth,
parent_dir, http_proxy,
update_requirements=True,
constraints=constraints)
os.environ = old_environ
def _git_validate_projects_yaml(projects, core_project):
"""
Validate the projects yaml.
"""
_git_ensure_key_exists('repositories', projects)
for project in projects['repositories']:
_git_ensure_key_exists('name', project.keys())
_git_ensure_key_exists('repository', project.keys())
_git_ensure_key_exists('branch', project.keys())
if projects['repositories'][0]['name'] != 'requirements':
error_out('{} git repo must be specified first'.format('requirements'))
if projects['repositories'][-1]['name'] != core_project:
error_out('{} git repo must be specified last'.format(core_project))
_git_ensure_key_exists('release', projects)
def _git_ensure_key_exists(key, keys):
"""
Ensure that key exists in keys.
"""
if key not in keys:
error_out('openstack-origin-git key \'{}\' is missing'.format(key))
def _git_clone_and_install_single(repo, branch, depth, parent_dir, http_proxy,
update_requirements, constraints=None):
"""
Clone and install a single git repository.
"""
if not os.path.exists(parent_dir):
juju_log('Directory already exists at {}. '
'No need to create directory.'.format(parent_dir))
os.mkdir(parent_dir)
juju_log('Cloning git repo: {}, branch: {}'.format(repo, branch))
repo_dir = install_remote(
repo, dest=parent_dir, branch=branch, depth=depth)
venv = os.path.join(parent_dir, 'venv')
if update_requirements:
if not requirements_dir:
error_out('requirements repo must be cloned before '
'updating from global requirements.')
_git_update_requirements(venv, repo_dir, requirements_dir)
juju_log('Installing git repo from dir: {}'.format(repo_dir))
if http_proxy:
pip_install(repo_dir, proxy=http_proxy, venv=venv,
constraints=constraints)
else:
pip_install(repo_dir, venv=venv, constraints=constraints)
return repo_dir
def _git_update_requirements(venv, package_dir, reqs_dir):
"""
Update from global requirements.
Update an OpenStack git directory's requirements.txt and
test-requirements.txt from global-requirements.txt.
"""
orig_dir = os.getcwd()
os.chdir(reqs_dir)
python = os.path.join(venv, 'bin/python')
cmd = [python, 'update.py', package_dir]
try:
subprocess.check_call(cmd)
except subprocess.CalledProcessError:
package = os.path.basename(package_dir)
error_out("Error updating {} from "
"global-requirements.txt".format(package))
os.chdir(orig_dir)
def git_pip_venv_dir(projects_yaml):
"""
Return the pip virtualenv path.
"""
parent_dir = '/mnt/openstack-git'
projects = _git_yaml_load(projects_yaml)
if 'directory' in projects.keys():
parent_dir = projects['directory']
return os.path.join(parent_dir, 'venv')
def git_src_dir(projects_yaml, project):
"""
Return the directory where the specified project's source is located.
"""
parent_dir = '/mnt/openstack-git'
projects = _git_yaml_load(projects_yaml)
if 'directory' in projects.keys():
parent_dir = projects['directory']
for p in projects['repositories']:
if p['name'] == project:
return os.path.join(parent_dir, os.path.basename(p['repository']))
return None
def git_yaml_value(projects_yaml, key):
"""
Return the value in projects_yaml for the specified key.
"""
projects = _git_yaml_load(projects_yaml)
if key in projects.keys():
return projects[key]
return None
def git_generate_systemd_init_files(templates_dir):
"""
Generate systemd init files.
Generates and installs systemd init units and script files based on the
*.init.in files contained in the templates_dir directory.
This code is based on the openstack-pkg-tools package and its init
script generation, which is used by the OpenStack packages.
"""
for f in os.listdir(templates_dir):
# Create the init script and systemd unit file from the template
if f.endswith(".init.in"):
init_in_file = f
init_file = f[:-8]
service_file = "{}.service".format(init_file)
init_in_source = os.path.join(templates_dir, init_in_file)
init_source = os.path.join(templates_dir, init_file)
service_source = os.path.join(templates_dir, service_file)
init_dest = os.path.join('/etc/init.d', init_file)
service_dest = os.path.join('/lib/systemd/system', service_file)
shutil.copyfile(init_in_source, init_source)
with open(init_source, 'a') as outfile:
template = ('/usr/share/openstack-pkg-tools/'
'init-script-template')
with open(template) as infile:
outfile.write('\n\n{}'.format(infile.read()))
cmd = ['pkgos-gen-systemd-unit', init_in_source]
subprocess.check_call(cmd)
if os.path.exists(init_dest):
os.remove(init_dest)
if os.path.exists(service_dest):
os.remove(service_dest)
shutil.copyfile(init_source, init_dest)
shutil.copyfile(service_source, service_dest)
os.chmod(init_dest, 0o755)
for f in os.listdir(templates_dir):
# If there's a service.in file, use it instead of the generated one
if f.endswith(".service.in"):
service_in_file = f
service_file = f[:-3]
service_in_source = os.path.join(templates_dir, service_in_file)
service_source = os.path.join(templates_dir, service_file)
service_dest = os.path.join('/lib/systemd/system', service_file)
shutil.copyfile(service_in_source, service_source)
if os.path.exists(service_dest):
os.remove(service_dest)
shutil.copyfile(service_source, service_dest)
for f in os.listdir(templates_dir):
# Generate the systemd unit if there's no existing .service.in
if f.endswith(".init.in"):
init_in_file = f
init_file = f[:-8]
service_in_file = "{}.service.in".format(init_file)
service_file = "{}.service".format(init_file)
init_in_source = os.path.join(templates_dir, init_in_file)
service_in_source = os.path.join(templates_dir, service_in_file)
service_source = os.path.join(templates_dir, service_file)
service_dest = os.path.join('/lib/systemd/system', service_file)
if not os.path.exists(service_in_source):
cmd = ['pkgos-gen-systemd-unit', init_in_source]
subprocess.check_call(cmd)
if os.path.exists(service_dest):
os.remove(service_dest)
shutil.copyfile(service_source, service_dest)
def git_determine_usr_bin():
"""Return the /usr/bin path for Apache2 config.
The /usr/bin path will be located in the virtualenv if the charm
is configured to deploy from source.
"""
if git_install_requested():
projects_yaml = config('openstack-origin-git')
projects_yaml = git_default_repos(projects_yaml)
return os.path.join(git_pip_venv_dir(projects_yaml), 'bin')
else:
return '/usr/bin'
def git_determine_python_path():
"""Return the python-path for Apache2 config.
Returns 'None' unless the charm is configured to deploy from source,
in which case the path of the virtualenv's site-packages is returned.
"""
if git_install_requested():
projects_yaml = config('openstack-origin-git')
projects_yaml = git_default_repos(projects_yaml)
return os.path.join(git_pip_venv_dir(projects_yaml),
'lib/python2.7/site-packages')
else:
return None
def os_workload_status(configs, required_interfaces, charm_func=None):
"""
Decorator to set workload status based on complete contexts
@ -1615,27 +1174,24 @@ def do_action_openstack_upgrade(package, upgrade_callback, configs):
"""
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')
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 Exception:
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.'})
try:
upgrade_callback(configs=configs)
action_set({'outcome': 'success, upgrade completed.'})
ret = True
except Exception:
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': 'no upgrade available.'})
action_set({'outcome': 'action-managed-upgrade config is '
'False, skipped upgrade.'})
else:
action_set({'outcome': 'no upgrade available.'})
return ret
@ -2045,14 +1601,25 @@ def token_cache_pkgs(source=None, release=None):
def update_json_file(filename, items):
"""Updates the json `filename` with a given dict.
:param filename: json filename (i.e.: /etc/glance/policy.json)
:param filename: path to json file (e.g. /etc/glance/policy.json)
:param items: dict of items to update
"""
if not items:
return
with open(filename) as fd:
policy = json.load(fd)
# Compare before and after and if nothing has changed don't write the file
# since that could cause unnecessary service restarts.
before = json.dumps(policy, indent=4, sort_keys=True)
policy.update(items)
after = json.dumps(policy, indent=4, sort_keys=True)
if before == after:
return
with open(filename, "w") as fd:
fd.write(json.dumps(policy, indent=4))
fd.write(after)
@cached

View File

@ -113,7 +113,7 @@ def validator(value, valid_type, valid_range=None):
assert isinstance(valid_range, list), \
"valid_range must be a list, was given {}".format(valid_range)
# If we're dealing with strings
if valid_type is six.string_types:
if isinstance(value, six.string_types):
assert value in valid_range, \
"{} is not in the list {}".format(value, valid_range)
# Integer, float should have a min and max
@ -517,7 +517,8 @@ def pool_set(service, pool_name, key, value):
:param value:
:return: None. Can raise CalledProcessError
"""
cmd = ['ceph', '--id', service, 'osd', 'pool', 'set', pool_name, key, value]
cmd = ['ceph', '--id', service, 'osd', 'pool', 'set', pool_name, key,
str(value).lower()]
try:
check_call(cmd)
except CalledProcessError:
@ -621,16 +622,24 @@ def create_erasure_profile(service, profile_name, erasure_plugin_name='jerasure'
:param durability_estimator: int
:return: None. Can raise CalledProcessError
"""
version = ceph_version()
# Ensure this failure_domain is allowed by Ceph
validator(failure_domain, six.string_types,
['chassis', 'datacenter', 'host', 'osd', 'pdu', 'pod', 'rack', 'region', 'room', 'root', 'row'])
cmd = ['ceph', '--id', service, 'osd', 'erasure-code-profile', 'set', profile_name,
'plugin=' + erasure_plugin_name, 'k=' + str(data_chunks), 'm=' + str(coding_chunks),
'ruleset_failure_domain=' + failure_domain]
'plugin=' + erasure_plugin_name, 'k=' + str(data_chunks), 'm=' + str(coding_chunks)
]
if locality is not None and durability_estimator is not None:
raise ValueError("create_erasure_profile should be called with k, m and one of l or c but not both.")
# failure_domain changed in luminous
if version and version >= '12.0.0':
cmd.append('crush-failure-domain=' + failure_domain)
else:
cmd.append('ruleset-failure-domain=' + failure_domain)
# Add plugin specific information
if locality is not None:
# For local erasure codes
@ -1064,14 +1073,24 @@ class CephBrokerRq(object):
self.ops = []
def add_op_request_access_to_group(self, name, namespace=None,
permission=None, key_name=None):
permission=None, key_name=None,
object_prefix_permissions=None):
"""
Adds the requested permissions to the current service's Ceph key,
allowing the key to access only the specified pools
allowing the key to access only the specified pools or
object prefixes. object_prefix_permissions should be a dictionary
keyed on the permission with the corresponding value being a list
of prefixes to apply that permission to.
{
'rwx': ['prefix1', 'prefix2'],
'class-read': ['prefix3']}
"""
self.ops.append({'op': 'add-permissions-to-key', 'group': name,
'namespace': namespace, 'name': key_name or service_name(),
'group-permission': permission})
self.ops.append({
'op': 'add-permissions-to-key', 'group': name,
'namespace': namespace,
'name': key_name or service_name(),
'group-permission': permission,
'object-prefix-permissions': object_prefix_permissions})
def add_op_create_pool(self, name, replica_count=3, pg_num=None,
weight=None, group=None, namespace=None):
@ -1107,7 +1126,10 @@ class CephBrokerRq(object):
def _ops_equal(self, other):
if len(self.ops) == len(other.ops):
for req_no in range(0, len(self.ops)):
for key in ['replicas', 'name', 'op', 'pg_num', 'weight']:
for key in [
'replicas', 'name', 'op', 'pg_num', 'weight',
'group', 'group-namespace', 'group-permission',
'object-prefix-permissions']:
if self.ops[req_no].get(key) != other.ops[req_no].get(key):
return False
else:

View File

@ -1,23 +0,0 @@
#!/usr/bin/env python
#
# Copyright 2016 Canonical Ltd
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Amulet tests on a basic nova compute git deployment on trusty-icehouse."""
from basic_deployment import NovaBasicDeployment
if __name__ == '__main__':
deployment = NovaBasicDeployment(series='trusty', git=True)
deployment.run_tests()

View File

@ -1,26 +0,0 @@
#!/usr/bin/env python
#
# Copyright 2016 Canonical Ltd
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Amulet tests on a basic nova-compute git deployment on trusty-kilo."""
from basic_deployment import NovaBasicDeployment
if __name__ == '__main__':
deployment = NovaBasicDeployment(series='trusty',
openstack='cloud:trusty-kilo',
source='cloud:trusty-updates/kilo',
git=True)
deployment.run_tests()

View File

@ -13,6 +13,12 @@
# limitations under the License.
import sys
from mock import MagicMock
# python-apt is not installed as part of test-requirements but is imported by
# some charmhelpers modules so create a fake import.
sys.modules['apt'] = MagicMock()
sys.modules['apt_pkg'] = MagicMock()
sys.path.append('actions/')
sys.path.append('hooks/')

View File

@ -1,120 +0,0 @@
# Copyright 2016 Canonical Ltd
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import sys
from mock import patch, MagicMock
# python-apt is not installed as part of test-requirements but is imported by
# some charmhelpers modules so create a fake import.
sys.modules['apt'] = MagicMock()
sys.modules['apt_pkg'] = MagicMock()
with patch('charmhelpers.core.hookenv.config') as config:
config.return_value = 'nova'
import nova_compute_utils as utils # noqa
with patch('charmhelpers.contrib.hardening.harden.harden') as mock_dec:
mock_dec.side_effect = (lambda *dargs, **dkwargs: lambda f:
lambda *args, **kwargs: f(*args, **kwargs))
with patch('nova_compute_utils.restart_map'):
with patch('nova_compute_utils.register_configs'):
import git_reinstall
from test_utils import (
CharmTestCase
)
TO_PATCH = [
'config',
]
openstack_origin_git = \
"""repositories:
- {name: requirements,
repository: 'git://git.openstack.org/openstack/requirements',
branch: stable/juno}
- {name: nova,
repository: 'git://git.openstack.org/openstack/nova',
branch: stable/juno}"""
class TestnovaAPIActions(CharmTestCase):
def setUp(self):
super(TestnovaAPIActions, self).setUp(git_reinstall, TO_PATCH)
self.config.side_effect = self.test_config.get
@patch.object(git_reinstall, 'action_set')
@patch.object(git_reinstall, 'action_fail')
@patch.object(git_reinstall, 'git_install')
@patch.object(git_reinstall, 'config_changed')
def test_git_reinstall(self, config_changed, git_install, action_fail,
action_set):
self.test_config.set('openstack-origin-git', openstack_origin_git)
git_reinstall.git_reinstall()
git_install.assert_called_with(openstack_origin_git)
self.assertTrue(git_install.called)
self.assertTrue(config_changed.called)
self.assertFalse(action_set.called)
self.assertFalse(action_fail.called)
@patch.object(git_reinstall, 'action_set')
@patch.object(git_reinstall, 'action_fail')
@patch.object(git_reinstall, 'git_install')
@patch.object(git_reinstall, 'config_changed')
@patch('charmhelpers.contrib.openstack.utils.config')
def test_git_reinstall_not_configured(self, _config, config_changed,
git_install, action_fail,
action_set):
_config.return_value = None
git_reinstall.git_reinstall()
msg = 'openstack-origin-git is not configured'
action_fail.assert_called_with(msg)
self.assertFalse(git_install.called)
self.assertFalse(action_set.called)
@patch.object(git_reinstall, 'action_set')
@patch.object(git_reinstall, 'action_fail')
@patch.object(git_reinstall, 'git_install')
@patch.object(git_reinstall, 'config_changed')
@patch('traceback.format_exc')
@patch('charmhelpers.contrib.openstack.utils.config')
def test_git_reinstall_exception(self, _config, format_exc,
config_changed, git_install, action_fail,
action_set):
_config.return_value = openstack_origin_git
e = OSError('something bad happened')
git_install.side_effect = e
traceback = (
"Traceback (most recent call last):\n"
" File \"actions/git_reinstall.py\", line 37, in git_reinstall\n"
" git_install(config(\'openstack-origin-git\'))\n"
" File \"/usr/lib/python2.7/dist-packages/mock.py\", line 964, in __call__\n" # noqa
" return _mock_self._mock_call(*args, **kwargs)\n"
" File \"/usr/lib/python2.7/dist-packages/mock.py\", line 1019, in _mock_call\n" # noqa
" raise effect\n"
"OSError: something bad happened\n")
format_exc.return_value = traceback
git_reinstall.git_reinstall()
msg = 'git-reinstall resulted in an unexpected error'
action_fail.assert_called_with(msg)
action_set.assert_called_with({'traceback': traceback})

View File

@ -43,13 +43,11 @@ class TestNovaComputeUpgradeActions(CharmTestCase):
@patch('charmhelpers.contrib.openstack.utils.config')
@patch('charmhelpers.contrib.openstack.utils.action_set')
@patch('charmhelpers.contrib.openstack.utils.git_install_requested')
@patch('charmhelpers.contrib.openstack.utils.openstack_upgrade_available')
@patch('charmhelpers.contrib.openstack.utils.juju_log')
def test_openstack_upgrade_true(self, log, upgrade_avail, git_requested,
def test_openstack_upgrade_true(self, log, upgrade_avail,
action_set, config):
git_requested.return_value = False
upgrade_avail.return_value = True
config.return_value = True
@ -60,13 +58,11 @@ class TestNovaComputeUpgradeActions(CharmTestCase):
@patch('charmhelpers.contrib.openstack.utils.config')
@patch('charmhelpers.contrib.openstack.utils.action_set')
@patch('charmhelpers.contrib.openstack.utils.git_install_requested') # noqa
@patch('charmhelpers.contrib.openstack.utils.openstack_upgrade_available') # noqa
@patch('charmhelpers.contrib.openstack.utils.juju_log')
def test_openstack_upgrade_false(self, log, upgrade_avail, git_requested,
def test_openstack_upgrade_false(self, log, upgrade_avail,
action_set, config):
git_requested.return_value = False
upgrade_avail.return_value = True
config.return_value = False

View File

@ -12,8 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
import sys
import yaml
import importlib
from mock import (
ANY,
@ -24,11 +23,6 @@ from mock import (
from nova_compute_hooks import update_nrpe_config
# python-apt is not installed as part of test-requirements but is imported by
# some charmhelpers modules so create a fake import.
sys.modules['apt'] = MagicMock()
sys.modules['apt_pkg'] = MagicMock()
from test_utils import CharmTestCase
with patch('charmhelpers.contrib.hardening.harden.harden') as mock_dec:
@ -37,6 +31,7 @@ with patch('charmhelpers.contrib.hardening.harden.harden') as mock_dec:
with patch("nova_compute_utils.restart_map"):
with patch("nova_compute_utils.register_configs"):
import nova_compute_hooks as hooks
importlib.reload(hooks)
TO_PATCH = [
@ -80,8 +75,6 @@ TO_PATCH = [
'disable_shell',
'enable_shell',
'update_nrpe_config',
'git_install',
'git_install_requested',
'network_manager',
'libvirt_daemon',
# misc_utils
@ -124,36 +117,10 @@ class NovaComputeRelationsTests(CharmTestCase):
self.apt_install.assert_called_with(['foo', 'bar'], fatal=True)
self.assertTrue(self.execd_preinstall.called)
def test_install_hook_git(self):
self.git_install_requested.return_value = True
self.determine_packages.return_value = ['foo', 'bar']
repo = 'cloud:trusty-juno'
openstack_origin_git = {
'repositories': [
{'name': 'requirements',
'repository': 'git://git.openstack.org/openstack/requirements', # noqa
'branch': 'stable/juno'},
{'name': 'nova',
'repository': 'git://git.openstack.org/openstack/nova',
'branch': 'stable/juno'}
],
'directory': '/mnt/openstack-git',
}
projects_yaml = yaml.dump(openstack_origin_git)
self.test_config.set('openstack-origin', repo)
self.test_config.set('openstack-origin-git', projects_yaml)
hooks.install()
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.git_install.assert_called_with(projects_yaml)
self.assertTrue(self.execd_preinstall.called)
@patch.object(hooks, 'ceph_changed')
@patch.object(hooks, 'neutron_plugin_joined')
def test_config_changed_with_upgrade(self, neutron_plugin_joined,
ceph_changed):
self.git_install_requested.return_value = False
self.openstack_upgrade_available.return_value = True
def rel_ids(x):
@ -167,9 +134,7 @@ class NovaComputeRelationsTests(CharmTestCase):
neutron_plugin_joined.assert_called_with('rid1', remote_restart=True)
ceph_changed.assert_called_with(rid='ceph:0', unit='ceph/0')
@patch.object(hooks, 'git_install_requested')
def test_config_changed_with_openstack_upgrade_action(self, git_requested):
git_requested.return_value = False
def test_config_changed_with_openstack_upgrade_action(self):
self.openstack_upgrade_available.return_value = True
self.test_config.set('action-managed-upgrade', True)
self.migration_enabled.return_value = False
@ -181,7 +146,6 @@ class NovaComputeRelationsTests(CharmTestCase):
@patch.object(hooks, 'compute_joined')
def test_config_changed_with_migration(self, compute_joined,
neutron_plugin_joined):
self.git_install_requested.return_value = False
self.migration_enabled.return_value = True
self.test_config.set('migration-auth-type', 'ssh')
self.relation_ids.return_value = [
@ -200,7 +164,6 @@ class NovaComputeRelationsTests(CharmTestCase):
@patch.object(hooks, 'compute_joined')
def test_config_changed_with_resize(self, compute_joined,
neutron_plugin_joined):
self.git_install_requested.return_value = False
self.test_config.set('enable-resize', True)
self.migration_enabled.return_value = False
self.relation_ids.return_value = [
@ -220,7 +183,6 @@ class NovaComputeRelationsTests(CharmTestCase):
@patch.object(hooks, 'compute_joined')
def test_config_changed_without_resize(self, compute_joined,
neutron_plugin_joined):
self.git_install_requested.return_value = False
self.test_config.set('enable-resize', False)
self.migration_enabled.return_value = False
self.relation_ids.return_value = [
@ -237,7 +199,6 @@ class NovaComputeRelationsTests(CharmTestCase):
@patch.object(hooks, 'compute_joined')
def test_config_changed_no_upgrade_no_migration(self, compute_joined):
self.git_install_requested.return_value = False
self.openstack_upgrade_available.return_value = False
self.migration_enabled.return_value = False
hooks.config_changed()
@ -246,7 +207,6 @@ class NovaComputeRelationsTests(CharmTestCase):
@patch.object(hooks, 'compute_joined')
def test_config_changed_with_sysctl(self, compute_joined):
self.git_install_requested.return_value = False
self.migration_enabled.return_value = False
self.test_config.set(
'sysctl',
@ -258,7 +218,6 @@ class NovaComputeRelationsTests(CharmTestCase):
@patch.object(hooks, 'compute_joined')
def test_config_changed_with_sysctl_swappy_default(self, compute_joined):
self.git_install_requested.return_value = False
self.test_config.set(
'sysctl',
'{ kernel.max_pid : "1337" }')
@ -268,33 +227,8 @@ class NovaComputeRelationsTests(CharmTestCase):
"{kernel.max_pid: '1337', vm.swappiness: 1}\n",
'/etc/sysctl.d/50-nova-compute.conf')
@patch.object(hooks, 'config_value_changed')
def test_config_changed_git(self, config_val_changed):
self.git_install_requested.return_value = True
repo = 'cloud:trusty-juno'
openstack_origin_git = {
'repositories': [
{'name': 'requirements',
'repository':
'git://git.openstack.org/openstack/requirements',
'branch': 'stable/juno'},
{'name': 'nova',
'repository': 'git://git.openstack.org/openstack/nova',
'branch': 'stable/juno'}
],
'directory': '/mnt/openstack-git',
}
projects_yaml = yaml.dump(openstack_origin_git)
self.test_config.set('openstack-origin', repo)
self.test_config.set('openstack-origin-git', projects_yaml)
self.migration_enabled.return_value = False
hooks.config_changed()
self.git_install.assert_called_with(projects_yaml)
self.assertFalse(self.do_openstack_upgrade.called)
@patch.object(hooks, 'compute_joined')
def test_config_changed_no_nrpe(self, compute_joined):
self.git_install_requested.return_value = False
self.openstack_upgrade_available.return_value = False
self.migration_enabled.return_value = False
self.is_relation_made.return_value = False
@ -303,7 +237,6 @@ class NovaComputeRelationsTests(CharmTestCase):
@patch.object(hooks, 'compute_joined')
def test_config_changed_nrpe(self, compute_joined):
self.git_install_requested.return_value = False
self.openstack_upgrade_available.return_value = False
self.migration_enabled.return_value = False
self.is_relation_made.return_value = True

View File

@ -39,19 +39,14 @@ TO_PATCH = [
'apt_install',
'apt_update',
'config',
'git_src_dir',
'git_pip_venv_dir',
'os_release',
'log',
'pip_install',
'related_units',
'relation_ids',
'relation_get',
'render',
'service_restart',
'mkdir',
'install_alternative',
'add_user_to_group',
'MetadataServiceContext',
'lsb_release',
'charm_dir',
@ -62,15 +57,6 @@ TO_PATCH = [
'lsb_release',
]
openstack_origin_git = \
"""repositories:
- {name: requirements,
repository: 'git://git.openstack.org/openstack/requirements',
branch: stable/juno}
- {name: nova,
repository: 'git://git.openstack.org/openstack/nova',
branch: stable/juno}"""
class NovaComputeUtilsTests(CharmTestCase):
@ -82,12 +68,10 @@ class NovaComputeUtilsTests(CharmTestCase):
@patch.object(utils, 'nova_metadata_requirement')
@patch.object(utils, 'network_manager')
@patch.object(utils, 'git_install_requested')
@patch('platform.machine')
def test_determine_packages_nova_network(self, machine, git_requested,
def test_determine_packages_nova_network(self, machine,
net_man, en_meta):
self.os_release.return_value = 'icehouse'
git_requested.return_value = False
en_meta.return_value = (False, None)
net_man.return_value = 'flatdhcpmanager'
machine.return_value = 'x86_64'
@ -102,13 +86,10 @@ class NovaComputeUtilsTests(CharmTestCase):
@patch.object(utils, 'nova_metadata_requirement')
@patch.object(utils, 'network_manager')
@patch.object(utils, 'git_install_requested')
@patch('platform.machine')
def test_determine_packages_nova_network_ocata(self, machine,
git_requested,
net_man, en_meta):
self.os_release.return_value = 'ocata'
git_requested.return_value = False
en_meta.return_value = (False, None)
net_man.return_value = 'flatdhcpmanager'
machine.return_value = 'x86_64'
@ -122,11 +103,9 @@ class NovaComputeUtilsTests(CharmTestCase):
@patch.object(utils, 'nova_metadata_requirement')
@patch.object(utils, 'neutron_plugin')
@patch.object(utils, 'network_manager')
@patch.object(utils, 'git_install_requested')
@patch('platform.machine')
def test_determine_packages_neutron(self, machine, git_requested, net_man,
def test_determine_packages_neutron(self, machine, net_man,
n_plugin, en_meta):
git_requested.return_value = False
en_meta.return_value = (False, None)
net_man.return_value = 'neutron'
n_plugin.return_value = 'ovs'
@ -139,16 +118,13 @@ class NovaComputeUtilsTests(CharmTestCase):
@patch.object(utils, 'nova_metadata_requirement')
@patch.object(utils, 'neutron_plugin')
@patch.object(utils, 'network_manager')
@patch.object(utils, 'git_install_requested')
@patch('platform.machine')
def test_determine_packages_neutron_aarch64_xenial(self, machine,
git_requested,
net_man, n_plugin,
en_meta):
self.lsb_release.return_value = {
'DISTRIB_CODENAME': 'xenial'
}
git_requested.return_value = False
en_meta.return_value = (False, None)
net_man.return_value = 'neutron'
n_plugin.return_value = 'ovs'
@ -161,16 +137,13 @@ class NovaComputeUtilsTests(CharmTestCase):
@patch.object(utils, 'nova_metadata_requirement')
@patch.object(utils, 'neutron_plugin')
@patch.object(utils, 'network_manager')
@patch.object(utils, 'git_install_requested')
@patch('platform.machine')
def test_determine_packages_neutron_aarch64_trusty(self, machine,
git_requested,
net_man, n_plugin,
en_meta):
self.lsb_release.return_value = {
'DISTRIB_CODENAME': 'trusty'
}
git_requested.return_value = False
en_meta.return_value = (False, None)
net_man.return_value = 'neutron'
n_plugin.return_value = 'ovs'
@ -183,11 +156,9 @@ class NovaComputeUtilsTests(CharmTestCase):
@patch.object(utils, 'nova_metadata_requirement')
@patch.object(utils, 'neutron_plugin')
@patch.object(utils, 'network_manager')
@patch.object(utils, 'git_install_requested')
@patch('platform.machine')
def test_determine_packages_neutron_ceph(self, machine, git_requested,
def test_determine_packages_neutron_ceph(self, machine,
net_man, n_plugin, en_meta):
git_requested.return_value = False
en_meta.return_value = (False, None)
net_man.return_value = 'neutron'
n_plugin.return_value = 'ovs'
@ -200,10 +171,8 @@ class NovaComputeUtilsTests(CharmTestCase):
@patch.object(utils, 'nova_metadata_requirement')
@patch.object(utils, 'neutron_plugin')
@patch.object(utils, 'network_manager')
@patch.object(utils, 'git_install_requested')
def test_determine_packages_metadata(self, git_requested, net_man,
def test_determine_packages_metadata(self, net_man,
n_plugin, en_meta):
git_requested.return_value = False
en_meta.return_value = (True, None)
net_man.return_value = 'bob'
n_plugin.return_value = 'ovs'
@ -686,12 +655,9 @@ class NovaComputeUtilsTests(CharmTestCase):
_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, _lxc_list,
_git_install):
_git_install.return_value = False
def test_configure_lxd_pre_vivid(self, _configure_subuid, _lxc_list):
self.lsb_release.return_value = {
'DISTRIB_CODENAME': 'trusty'
}
@ -699,200 +665,6 @@ class NovaComputeUtilsTests(CharmTestCase):
utils.configure_lxd('nova')
self.assertFalse(_configure_subuid.called)
@patch.object(utils, 'git_default_repos')
@patch.object(utils, 'git_install_requested')
@patch.object(utils, 'git_clone_and_install')
@patch.object(utils, 'git_post_install')
@patch.object(utils, 'git_pre_install')
def test_git_install(self, git_pre, git_post, git_clone_and_install,
git_requested, git_default_repos):
projects_yaml = openstack_origin_git
git_default_repos.return_value = projects_yaml
git_requested.return_value = True
utils.git_install(projects_yaml)
self.assertTrue(git_pre.called)
git_clone_and_install.assert_called_with(openstack_origin_git,
core_project='nova')
self.assertTrue(git_post.called)
@patch.object(utils, 'mkdir')
@patch.object(utils, 'write_file')
@patch.object(utils, 'add_user_to_group')
@patch.object(utils, 'add_group')
@patch.object(utils, 'adduser')
@patch.object(utils, 'check_call')
def test_git_pre_install(self, check_call, adduser, add_group,
add_user_to_group, write_file, mkdir):
utils.git_pre_install()
adduser.assert_called_with('nova', shell='/bin/bash',
system_user=True)
check_call.assert_called_with(['usermod', '--home', '/var/lib/nova',
'nova'])
add_group.assert_called_with('nova', system_group=True)
expected = [
call('nova', 'nova'),
call('nova', 'libvirtd'),
]
self.assertEqual(add_user_to_group.call_args_list, expected)
expected = [
call('/var/lib/nova', owner='nova',
group='nova', perms=0o0755, force=False),
call('/var/lib/nova/buckets', owner='nova',
group='nova', perms=0o0755, force=False),
call('/var/lib/nova/CA', owner='nova',
group='nova', perms=0o0755, force=False),
call('/var/lib/nova/CA/INTER', owner='nova',
group='nova', perms=0o0755, force=False),
call('/var/lib/nova/CA/newcerts', owner='nova',
group='nova', perms=0o0755, force=False),
call('/var/lib/nova/CA/private', owner='nova',
group='nova', perms=0o0755, force=False),
call('/var/lib/nova/CA/reqs', owner='nova',
group='nova', perms=0o0755, force=False),
call('/var/lib/nova/images', owner='nova',
group='nova', perms=0o0755, force=False),
call('/var/lib/nova/instances', owner='nova',
group='nova', perms=0o0755, force=False),
call('/var/lib/nova/keys', owner='nova',
group='nova', perms=0o0755, force=False),
call('/var/lib/nova/networks', owner='nova',
group='nova', perms=0o0755, force=False),
call('/var/lib/nova/tmp', owner='nova',
group='nova', perms=0o0755, force=False),
call('/var/log/nova', owner='nova',
group='nova', perms=0o0755, force=False),
]
self.assertEqual(mkdir.call_args_list, expected)
expected = [
call('/var/log/nova/nova-api.log', '', owner='nova',
group='nova', perms=0o0644),
call('/var/log/nova/nova-compute.log', '', owner='nova',
group='nova', perms=0o0644),
call('/var/log/nova/nova-manage.log', '', owner='nova',
group='nova', perms=0o0644),
call('/var/log/nova/nova-network.log', '', owner='nova',
group='nova', perms=0o0644),
]
self.assertEqual(write_file.call_args_list, expected)
@patch('os.path.join')
@patch('os.path.exists')
@patch('os.symlink')
@patch('shutil.copytree')
@patch('shutil.rmtree')
@patch('subprocess.check_call')
def test_git_post_install_upstart(self, check_call, rmtree, copytree,
symlink, exists, join):
projects_yaml = openstack_origin_git
join.return_value = 'joined-string'
self.lsb_release.return_value = {'DISTRIB_RELEASE': '15.04'}
self.git_pip_venv_dir.return_value = '/mnt/openstack-git/venv'
utils.git_post_install(projects_yaml)
expected = [
call('joined-string', '/etc/nova'),
]
copytree.assert_has_calls(expected)
expected = [
call('joined-string', '/usr/local/bin/nova-rootwrap'),
]
symlink.assert_has_calls(expected, any_order=True)
service_name = 'nova-compute'
nova_user = 'nova'
start_dir = '/var/lib/nova'
nova_conf = '/etc/nova/nova.conf'
nova_api_metadata_context = {
'service_description': 'Nova Metadata API server',
'service_name': service_name,
'user_name': nova_user,
'start_dir': start_dir,
'process_name': 'nova-api-metadata',
'executable_name': 'joined-string',
'config_files': [nova_conf],
}
nova_api_context = {
'service_description': 'Nova API server',
'service_name': service_name,
'user_name': nova_user,
'start_dir': start_dir,
'process_name': 'nova-api',
'executable_name': 'joined-string',
'config_files': [nova_conf],
}
nova_compute_context = {
'service_description': 'Nova compute worker',
'service_name': service_name,
'user_name': nova_user,
'process_name': 'nova-compute',
'executable_name': 'joined-string',
'config_files': [nova_conf, '/etc/nova/nova-compute.conf'],
}
nova_network_context = {
'service_description': 'Nova network worker',
'service_name': service_name,
'user_name': nova_user,
'start_dir': start_dir,
'process_name': 'nova-network',
'executable_name': 'joined-string',
'config_files': [nova_conf],
}
expected = [
call('git/nova-compute-kvm.conf', '/etc/nova/nova-compute.conf',
{}, perms=0o644),
call('git/nova_sudoers', '/etc/sudoers.d/nova_sudoers',
{}, perms=0o440),
call('git.upstart', '/etc/init/nova-api-metadata.conf',
nova_api_metadata_context, perms=0o644,
templates_dir='joined-string'),
call('git.upstart', '/etc/init/nova-api.conf',
nova_api_context, perms=0o644,
templates_dir='joined-string'),
call('git/upstart/nova-compute.upstart',
'/etc/init/nova-compute.conf',
nova_compute_context, perms=420),
call('git.upstart', '/etc/init/nova-network.conf',
nova_network_context, perms=0o644,
templates_dir='joined-string'),
]
self.assertEqual(self.render.call_args_list, expected)
self.assertTrue(self.apt_update.called)
self.apt_install.assert_called_with(
['bridge-utils', 'dnsmasq-base',
'dnsmasq-utils', 'ebtables', 'genisoimage', 'iptables',
'iputils-arping', 'kpartx', 'kvm', 'netcat', 'open-iscsi',
'parted', 'python-libvirt', 'qemu', 'qemu-system',
'qemu-utils', 'vlan'], fatal=True)
@patch('os.listdir')
@patch('os.path.join')
@patch('os.path.exists')
@patch('os.symlink')
@patch('shutil.copytree')
@patch('shutil.rmtree')
@patch('subprocess.check_call')
def test_git_post_install_systemd(self, check_call, rmtree, copytree,
symlink, exists, join, listdir):
projects_yaml = openstack_origin_git
join.return_value = 'joined-string'
self.lsb_release.return_value = {'DISTRIB_RELEASE': '15.10'}
self.git_pip_venv_dir.return_value = '/mnt/openstack-git/venv'
utils.git_post_install(projects_yaml)
expected = [
call('git/nova-compute-kvm.conf', '/etc/nova/nova-compute.conf',
{}, perms=420),
call('git/nova_sudoers', '/etc/sudoers.d/nova_sudoers',
{}, perms=288),
call('git/nova-api.init.in.template', 'joined-string',
{'daemon_path': 'joined-string'}, perms=420),
call('git/nova-api-metadata.init.in.template', 'joined-string',
{'daemon_path': 'joined-string'}, perms=420),
call('git/nova-compute.init.in.template', 'joined-string',
{'daemon_path': 'joined-string'}, perms=420),
call('git/nova-network.init.in.template', 'joined-string',
{'daemon_path': 'joined-string'}, perms=420),
]
self.assertEqual(self.render.call_args_list, expected)
@patch('psutil.virtual_memory')
@patch('subprocess.check_call')
@patch('subprocess.call')