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: I19732b50483ab7284723f847f182fd1cfa67e425
This commit is contained in:
James Page 2018-01-08 15:09:53 +00:00
parent e8febc0eb6
commit b4019e45bf
22 changed files with 146 additions and 1288 deletions

2
.gitignore vendored
View File

@ -6,3 +6,5 @@ tags
*.sw[nop]
*.pyc
.unit-state.db
.settings
.stestr

View File

@ -2,7 +2,5 @@ pause:
description: Pause the openstack-dashboard unit.
resume:
descrpition: Resume the openstack-dashboard unit.
git-reinstall:
description: Reinstall openstack-dashboard from the openstack-origin-git repositories.
openstack-upgrade:
description: Perform openstack upgrades. Config option action-managed-upgrade must be set to True.

View File

@ -1,60 +0,0 @@
#!/usr/bin/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.
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 horizon_utils import (
git_install,
)
from horizon_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

@ -27,30 +27,6 @@ options:
NOTE: updating this setting to a source that is known to provide
a later version of OpenStack will trigger a software upgrade unless
action-managed-upgrade is set to True.
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 and horizon repositories,
and may also include repositories for other dependencies:
repositories:
- {name: requirements,
repository: 'git://github.com/openstack/requirements',
branch: master}
- {name: horizon,
repository: 'git://github.com/openstack/horizon',
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

@ -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

@ -31,10 +31,6 @@ from charmhelpers.contrib.openstack.context import (
HAProxyContext,
context_complete
)
from charmhelpers.contrib.openstack.utils import (
git_default_repos,
git_pip_venv_dir,
)
from charmhelpers.contrib.hahelpers.apache import (
get_ca_cert,
get_cert,
@ -177,7 +173,6 @@ class IdentityServiceContext(OSContextGenerator):
class HorizonContext(OSContextGenerator):
def __call__(self):
''' Provide all configuration for Horizon '''
projects_yaml = git_default_repos(config('openstack-origin-git'))
ctxt = {
'compress_offline':
bool_from_string(config('offline-compression')),
@ -199,8 +194,6 @@ class HorizonContext(OSContextGenerator):
"allow_password_autocompletion":
config("allow-password-autocompletion"),
"password_retrieve": config("password-retrieve"),
'virtualenv': git_pip_venv_dir(projects_yaml)
if config('openstack-origin-git') else None,
'default_domain': config('default-domain'),
'multi_domain': False if config('default-domain') else True,
"default_create_volume": config("default-create-volume"),

View File

@ -40,10 +40,7 @@ from charmhelpers.core.host import (
lsb_release,
)
from charmhelpers.contrib.openstack.utils import (
config_value_changed,
configure_installation_source,
git_install_requested,
git_pip_venv_dir,
openstack_upgrade_available,
os_release,
save_script_rc,
@ -61,8 +58,6 @@ from horizon_utils import (
LOCAL_SETTINGS, HAPROXY_CONF,
enable_ssl,
do_openstack_upgrade,
git_install,
git_post_install_late,
setup_ipv6,
INSTALL_DIR,
restart_on_change,
@ -105,9 +100,6 @@ def install():
status_set('maintenance', 'Installing packages')
apt_install(packages, fatal=True)
status_set('maintenance', 'Git install')
git_install(config('openstack-origin-git'))
@hooks.hook('upgrade-charm')
@restart_on_change(restart_map(), stopstart=True, sleep=3)
@ -139,11 +131,7 @@ def config_changed():
keystone_joined(relid)
enable_ssl()
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('openstack-dashboard'):
status_set('maintenance', 'Upgrading to new OpenStack release')
do_openstack_upgrade(configs=CONFIGS)
@ -164,9 +152,6 @@ def config_changed():
open_port(80)
open_port(443)
if git_install_requested():
git_post_install_late(config('openstack-origin-git'))
@hooks.hook('identity-service-relation-joined')
def keystone_joined(rel_id=None):
@ -299,10 +284,7 @@ def update_nrpe_config():
@hooks.hook('dashboard-plugin-relation-joined')
def plugin_relation_joined(rel_id=None):
if git_install_requested():
bin_path = git_pip_venv_dir(config('openstack-origin-git'))
else:
bin_path = '/usr/bin'
bin_path = '/usr/bin'
relation_set(release=os_release("openstack-dashboard"),
relation_id=rel_id,
bin_path=bin_path,

View File

@ -13,12 +13,9 @@
# limitations under the License.
# vim: set ts=4:et
import grp
import horizon_contexts
import os
import pwd
import subprocess
import shutil
import time
from collections import OrderedDict
@ -28,13 +25,7 @@ import charmhelpers.contrib.openstack.templating as templating
from charmhelpers.contrib.openstack.utils import (
configure_installation_source,
get_os_codename_install_source,
git_install_requested,
git_clone_and_install,
git_default_repos,
os_release,
git_src_dir,
git_pip_venv_dir,
git_yaml_value,
pause_unit,
resume_unit,
make_assess_status_func,
@ -43,21 +34,13 @@ from charmhelpers.contrib.openstack.utils import (
CompareOpenStackReleases,
reset_os_release,
)
from charmhelpers.contrib.python.packages import (
pip_install,
)
from charmhelpers.core.hookenv import (
config,
log
)
from charmhelpers.core.host import (
adduser,
add_group,
add_user_to_group,
cmp_pkgrevno,
lsb_release,
mkdir,
service_restart,
path_hash,
service,
CompareHostReleases,
@ -81,32 +64,9 @@ BASE_PACKAGES = [
VERSION_PACKAGE = 'openstack-dashboard'
BASE_GIT_PACKAGES = [
'apache2',
'libapache2-mod-wsgi',
'libffi-dev',
'libpcre3-dev',
'libssl-dev',
'libxml2-dev',
'libxslt1-dev',
'libyaml-dev',
'python-dev',
'python-lesscpy',
'python-pip',
'python-setuptools',
'zlib1g-dev',
]
REQUIRED_INTERFACES = {
'identity': ['identity-service'],
}
# ubuntu packages that should not be installed when deploying from git
GIT_PACKAGE_BLACKLIST = [
'openstack-dashboard',
'openstack-dashboard-ubuntu-theme',
'python-keystoneclient',
'python-novaclient',
]
APACHE_CONF_DIR = "/etc/apache2"
LOCAL_SETTINGS = "/etc/openstack-dashboard/local_settings.py"
@ -271,14 +231,6 @@ def enable_ssl():
def determine_packages():
"""Determine packages to install"""
packages = BASE_PACKAGES
if git_install_requested():
packages.extend(BASE_GIT_PACKAGES)
# don't include packages that will be installed from git
packages = list(set(packages))
for p in GIT_PACKAGE_BLACKLIST:
packages.remove(p)
release = get_os_codename_install_source(config('openstack-origin'))
# Really should be handled as a dep in the openstack-dashboard package
if CompareOpenStackReleases(release) >= 'mitaka':
@ -332,146 +284,6 @@ def setup_ipv6():
apt_install('haproxy/trusty-backports', fatal=True)
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='horizon')
git_post_install(projects_yaml)
def git_pre_install():
"""Perform horizon pre-install setup."""
dirs = [
'/etc/openstack-dashboard',
'/usr/share/openstack-dashboard',
'/usr/share/openstack-dashboard/bin/less',
'/usr/share/openstack-dashboard-ubuntu-theme/static/ubuntu/css',
'/usr/share/openstack-dashboard-ubuntu-theme/static/ubuntu/img',
'/usr/share/openstack-dashboard-ubuntu-theme/templates',
'/var/lib/openstack-dashboard',
]
adduser('horizon', shell='/bin/bash', system_user=True)
subprocess.check_call(['usermod', '--home',
'/usr/share/openstack-dashboard/', 'horizon'])
add_group('horizon', system_group=True)
add_user_to_group('horizon', 'horizon')
for d in dirs:
if d is '/var/lib/openstack-dashboard':
mkdir(d, owner='horizon', group='horizon', perms=0700, force=False)
else:
mkdir(d, owner='root', group='root', perms=0755, force=False)
def git_post_install(projects_yaml):
"""Perform horizon post-install setup."""
projects_yaml = git_default_repos(projects_yaml)
src_dir = git_src_dir(projects_yaml, 'horizon')
copy_files = {
'manage': {
'src': os.path.join(src_dir, 'manage.py'),
'dest': '/usr/share/openstack-dashboard/manage.py',
},
'settings': {
'src': os.path.join(src_dir, 'openstack_dashboard/settings.py'),
'dest': '/usr/share/openstack-dashboard/settings.py',
},
'local_settings_example': {
'src': os.path.join(src_dir, 'openstack_dashboard/local',
'local_settings.py.example'),
'dest': '/etc/openstack-dashboard/local_settings.py',
},
}
for name, files in copy_files.iteritems():
if os.path.exists(files['dest']):
os.remove(files['dest'])
shutil.copyfile(files['src'], files['dest'])
copy_trees = {
'openstack_dashboard': {
'src': os.path.join(src_dir, 'openstack_dashboard'),
'dest': '/usr/share/openstack-dashboard/openstack_dashboard',
},
}
for name, dirs in copy_trees.iteritems():
if os.path.exists(dirs['dest']):
shutil.rmtree(dirs['dest'])
shutil.copytree(dirs['src'], dirs['dest'])
share_dir = '/usr/share/openstack-dashboard/openstack_dashboard'
symlinks = [
{'src': '/usr/share/openstack-dashboard/openstack_dashboard/static',
'link': '/usr/share/openstack-dashboard/static'},
{'src': '/usr/bin/lessc',
'link': '/usr/share/openstack-dashboard/bin/less/lessc'},
{'src': '/etc/openstack-dashboard/local_settings.py',
'link': os.path.join(share_dir, 'local/local_settings.py')},
{'src': os.path.join(git_pip_venv_dir(projects_yaml),
'local/lib/python2.7/site-packages/horizon/static/horizon/'),
'link': os.path.join(share_dir, 'static/horizon')},
]
for s in symlinks:
if os.path.lexists(s['link']):
os.remove(s['link'])
os.symlink(s['src'], s['link'])
os.chmod('/var/lib/openstack-dashboard', 0o750)
os.chmod('/usr/share/openstack-dashboard/manage.py', 0o755),
http_proxy = git_yaml_value(projects_yaml, 'http_proxy')
if http_proxy:
pip_install('python-memcached', proxy=http_proxy,
venv=git_pip_venv_dir(projects_yaml))
else:
pip_install('python-memcached',
venv=git_pip_venv_dir(projects_yaml))
python = os.path.join(git_pip_venv_dir(projects_yaml), 'bin/python')
subprocess.check_call([python, '/usr/share/openstack-dashboard/manage.py',
'collectstatic', '--noinput'])
subprocess.check_call([python, '/usr/share/openstack-dashboard/manage.py',
'compress', '--force'])
uid = pwd.getpwnam('horizon').pw_uid
gid = grp.getgrnam('horizon').gr_gid
os.chown('/etc/openstack-dashboard', uid, gid)
os.chown('/usr/share/openstack-dashboard/openstack_dashboard/static',
uid, gid)
os.chown('/var/lib/openstack-dashboard', uid, gid)
static_dir = '/usr/share/openstack-dashboard/openstack_dashboard/static'
for root, dirs, files in os.walk(static_dir):
for d in dirs:
os.lchown(os.path.join(root, d), uid, gid)
for f in files:
os.lchown(os.path.join(root, f), uid, gid)
if not is_unit_paused_set():
service_restart('apache2')
def git_post_install_late(projects_yaml):
"""Perform horizon post-install setup."""
projects_yaml = git_default_repos(projects_yaml)
subprocess.check_call(['a2enconf', 'openstack-dashboard'])
if not is_unit_paused_set():
service_restart('apache2')
python = os.path.join(git_pip_venv_dir(projects_yaml), 'bin/python')
subprocess.check_call([python, '/usr/share/openstack-dashboard/manage.py',
'collectstatic', '--noinput'])
subprocess.check_call([python, '/usr/share/openstack-dashboard/manage.py',
'compress', '--force'])
# [thedac] Work around apache restart Bug#1552822
# Allow for sleep time between stop and start
def restart_on_change(restart_map, stopstart=False, sleep=0):

View File

@ -1,9 +1,6 @@
WSGIScriptAlias {{ webroot }} /usr/share/openstack-dashboard/openstack_dashboard/wsgi/django.wsgi
WSGIDaemonProcess horizon user=horizon group=horizon processes=3 threads=10
WSGIProcessGroup horizon
{% if virtualenv %}
WSGIPythonHome {{ virtualenv }}
{% endif %}
Alias /static /usr/share/openstack-dashboard/openstack_dashboard/static/
Alias /horizon/static /usr/share/openstack-dashboard/openstack_dashboard/static/
<Directory /usr/share/openstack-dashboard/openstack_dashboard/wsgi>

View File

@ -1,9 +1,6 @@
WSGIScriptAlias {{ webroot }} /usr/share/openstack-dashboard/openstack_dashboard/wsgi/django.wsgi
WSGIDaemonProcess horizon user=horizon group=horizon processes=3 threads=10
WSGIProcessGroup horizon
{% if virtualenv %}
WSGIPythonHome {{ virtualenv }}
{% endif %}
Alias /static /usr/share/openstack-dashboard/openstack_dashboard/static/
Alias /horizon/static /usr/share/openstack-dashboard/openstack_dashboard/static/
<Directory /usr/share/openstack-dashboard/openstack_dashboard/wsgi>

View File

@ -1,9 +1,6 @@
WSGIScriptAlias {{ webroot }} /usr/share/openstack-dashboard/openstack_dashboard/wsgi/django.wsgi
WSGIDaemonProcess horizon user=www-data group=www-data processes=3 threads=10
WSGIProcessGroup horizon
{% if virtualenv %}
WSGIPythonHome {{ virtualenv }}
{% endif %}
Alias /static /var/lib/openstack-dashboard/static/
Alias /horizon/static /var/lib/openstack-dashboard/static/
<Directory /usr/share/openstack-dashboard/openstack_dashboard/wsgi>

View File

@ -1,9 +1,6 @@
WSGIScriptAlias {{ webroot }} /usr/share/openstack-dashboard/openstack_dashboard/wsgi/django.wsgi
WSGIDaemonProcess horizon user=horizon group=horizon processes=3 threads=10
WSGIProcessGroup horizon
{% if virtualenv %}
WSGIPythonHome {{ virtualenv }}
{% endif %}
Alias /static /var/lib/openstack-dashboard/static/
Alias /horizon/static /var/lib/openstack-dashboard/static/
<Directory /usr/share/openstack-dashboard/openstack_dashboard/wsgi>

View File

@ -15,9 +15,7 @@
# limitations under the License.
import amulet
import os
import urllib2
import yaml
import time
from charmhelpers.contrib.openstack.amulet.deployment import (
@ -37,14 +35,13 @@ u = OpenStackAmuletUtils(DEBUG)
class OpenstackDashboardBasicDeployment(OpenStackAmuletDeployment):
"""Amulet tests on a basic openstack-dashboard deployment."""
def __init__(self, series, openstack=None, source=None, git=False,
def __init__(self, series, openstack=None, source=None,
stable=False):
"""Deploy the entire test environment."""
super(OpenstackDashboardBasicDeployment, self).__init__(series,
openstack,
source,
stable)
self.git = git
self._add_services()
self._add_relations()
self._configure_services()
@ -86,34 +83,6 @@ class OpenstackDashboardBasicDeployment(OpenStackAmuletDeployment):
def _configure_services(self):
"""Configure all of the services."""
horizon_config = {}
if self.git:
amulet_http_proxy = os.environ.get('AMULET_HTTP_PROXY')
reqs_repo = 'git://github.com/openstack/requirements'
horizon_repo = 'git://github.com/openstack/horizon'
if self._get_openstack_release() == self.trusty_icehouse:
reqs_repo = 'git://github.com/coreycb/requirements'
horizon_repo = 'git://github.com/coreycb/horizon'
branch = 'stable/' + self._get_openstack_release_string()
openstack_origin_git = {
'repositories': [
{'name': 'requirements',
'repository': reqs_repo,
'branch': branch},
{'name': 'horizon',
'repository': horizon_repo,
'branch': branch},
],
'directory': '/mnt/openstack-git',
'http_proxy': amulet_http_proxy,
'https_proxy': amulet_http_proxy,
}
horizon_config['openstack-origin-git'] = \
yaml.dump(openstack_origin_git)
keystone_config = {
'admin-password': 'openstack',
'admin-token': 'ubuntutesting',

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 openstack-dashboard git deployment on trusty-icehouse."""
from basic_deployment import OpenstackDashboardBasicDeployment
if __name__ == '__main__':
deployment = OpenstackDashboardBasicDeployment(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 openstack-dashboard git deployment on trusty-kilo."""
from basic_deployment import OpenstackDashboardBasicDeployment
if __name__ == '__main__':
deployment = OpenstackDashboardBasicDeployment(series='trusty',
openstack='cloud:trusty-kilo',
source='cloud:trusty-updates/kilo',
git=True)
deployment.run_tests()

View File

@ -1,121 +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 os
import sys
from mock import patch, MagicMock
os.environ['JUJU_UNIT_NAME'] = 'horizon'
# python-apt is not installed as part of test-requirements but is imported by
# some charmhelpers modules so create a fake import.
mock_apt = MagicMock()
sys.modules['apt'] = mock_apt
mock_apt.apt_pkg = MagicMock()
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('horizon_utils.register_configs') as 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: horizon,
repository: 'git://git.openstack.org/openstack/horizon',
branch: stable/juno}"""
class TestHorizonActions(CharmTestCase):
def setUp(self):
super(TestHorizonActions, 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')
@patch('charmhelpers.contrib.openstack.utils.config')
def test_git_reinstall(self, _config, config_changed, git_install,
action_fail, action_set):
_config.return_value = openstack_origin_git
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

@ -49,11 +49,9 @@ class TestHorizonUpgradeActions(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')
def test_openstack_upgrade_true(self, upgrade_avail, git_requested,
def test_openstack_upgrade_true(self, upgrade_avail,
action_set, config):
git_requested.return_value = False
upgrade_avail.return_value = True
config.return_value = True
@ -64,11 +62,9 @@ class TestHorizonUpgradeActions(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')
def test_openstack_upgrade_false(self, upgrade_avail, git_requested,
def test_openstack_upgrade_false(self, upgrade_avail,
action_set, config):
git_requested.return_value = False
upgrade_avail.return_value = True
config.return_value = False

View File

@ -125,7 +125,6 @@ class TestHorizonContexts(CharmTestCase):
'default_role': 'Member', 'webroot': '/horizon',
'ubuntu_theme': True,
'default_theme': None,
'virtualenv': None,
'secret': 'secret',
'support_profile': None,
"neutron_network_dvr": False,
@ -151,7 +150,6 @@ class TestHorizonContexts(CharmTestCase):
'default_role': 'Member', 'webroot': '/horizon',
'ubuntu_theme': True,
'default_theme': None,
'virtualenv': None,
'secret': 'secret',
'support_profile': None,
"neutron_network_dvr": False,
@ -177,7 +175,6 @@ class TestHorizonContexts(CharmTestCase):
'default_role': 'Member', 'webroot': '/horizon',
'ubuntu_theme': True,
'default_theme': None,
'virtualenv': None,
'secret': 'secret',
'support_profile': None,
"neutron_network_dvr": False,
@ -203,7 +200,6 @@ class TestHorizonContexts(CharmTestCase):
'default_role': 'Member', 'webroot': '/horizon',
'ubuntu_theme': False,
'default_theme': None,
'virtualenv': None,
'secret': 'secret',
'support_profile': None,
"neutron_network_dvr": False,
@ -230,7 +226,6 @@ class TestHorizonContexts(CharmTestCase):
'default_role': 'Member', 'webroot': '/horizon',
'ubuntu_theme': False,
'default_theme': 'material',
'virtualenv': None,
'secret': 'secret',
'support_profile': None,
"neutron_network_dvr": False,
@ -260,7 +255,6 @@ class TestHorizonContexts(CharmTestCase):
'default_role': 'Member', 'webroot': '/horizon',
'ubuntu_theme': True,
'default_theme': None,
'virtualenv': None,
'secret': 'secret',
'support_profile': None,
"neutron_network_dvr": False,
@ -286,7 +280,6 @@ class TestHorizonContexts(CharmTestCase):
'default_role': 'foo', 'webroot': '/horizon',
'ubuntu_theme': True,
'default_theme': None,
'virtualenv': None,
'secret': 'secret',
'support_profile': None,
"neutron_network_dvr": False,
@ -312,7 +305,6 @@ class TestHorizonContexts(CharmTestCase):
'default_role': 'Member', 'webroot': '/',
'ubuntu_theme': True,
'default_theme': None,
'virtualenv': None,
'secret': 'secret',
'support_profile': None,
"neutron_network_dvr": False,
@ -343,7 +335,6 @@ class TestHorizonContexts(CharmTestCase):
'default_role': 'Member', 'webroot': '/horizon',
'ubuntu_theme': True,
'default_theme': None,
'virtualenv': None,
'secret': 'secret',
'support_profile': None,
"neutron_network_dvr": True,
@ -369,7 +360,6 @@ class TestHorizonContexts(CharmTestCase):
'default_role': 'Member', 'webroot': '/horizon',
'ubuntu_theme': True,
'default_theme': None,
'virtualenv': None,
'secret': 'secret',
'support_profile': None,
"neutron_network_dvr": False,
@ -395,7 +385,6 @@ class TestHorizonContexts(CharmTestCase):
'default_role': 'Member', 'webroot': '/horizon',
'ubuntu_theme': True,
'default_theme': None,
'virtualenv': None,
'secret': 'secret',
'support_profile': None,
"neutron_network_dvr": False,
@ -422,7 +411,6 @@ class TestHorizonContexts(CharmTestCase):
'default_role': 'Member', 'webroot': '/horizon',
'ubuntu_theme': True,
'default_theme': None,
'virtualenv': None,
'secret': 'secret',
'support_profile': None,
"neutron_network_dvr": False,
@ -449,7 +437,6 @@ class TestHorizonContexts(CharmTestCase):
'default_role': 'Member', 'webroot': '/horizon',
'ubuntu_theme': True,
'default_theme': None,
'virtualenv': None,
'secret': 'secret',
'support_profile': None,
"neutron_network_dvr": False,
@ -476,7 +463,6 @@ class TestHorizonContexts(CharmTestCase):
'default_role': 'Member', 'webroot': '/horizon',
'ubuntu_theme': True,
'default_theme': None,
'virtualenv': None,
'secret': 'secret',
'support_profile': None,
"neutron_network_dvr": False,

View File

@ -12,7 +12,6 @@
# See the License for the specific language governing permissions and
# limitations under the License.
import yaml
import sys
from mock import MagicMock, patch, call
@ -61,8 +60,6 @@ TO_PATCH = [
'os_release',
'get_iface_for_address',
'get_netmask_for_address',
'git_install',
'git_post_install_late',
'update_nrpe_config',
'lsb_release',
'status_set',
@ -87,10 +84,8 @@ class TestHorizonHooks(CharmTestCase):
'hooks/{}'.format(hookname)])
@patch.object(hooks, 'determine_packages')
@patch.object(utils, 'git_install_requested')
def test_install_hook(self, _git_requested, _determine_packages):
def test_install_hook(self, _determine_packages):
_determine_packages.return_value = []
_git_requested.return_value = False
self.filter_installed_packages.return_value = ['foo', 'bar']
self.os_release.return_value = 'icehouse'
self._call_hook('install.real')
@ -99,10 +94,8 @@ class TestHorizonHooks(CharmTestCase):
self.apt_install.assert_called_with(['foo', 'bar'], fatal=True)
@patch.object(hooks, 'determine_packages')
@patch.object(utils, 'git_install_requested')
def test_install_hook_precise(self, _git_requested, _determine_packages):
def test_install_hook_precise(self, _determine_packages):
_determine_packages.return_value = []
_git_requested.return_value = False
self.filter_installed_packages.return_value = ['foo', 'bar']
self.os_release.return_value = 'icehouse'
self.lsb_release.return_value = {'DISTRIB_CODENAME': 'precise'}
@ -116,11 +109,9 @@ class TestHorizonHooks(CharmTestCase):
self.apt_install.assert_has_calls(calls)
@patch.object(hooks, 'determine_packages')
@patch.object(utils, 'git_install_requested')
def test_install_hook_icehouse_pkgs(self, _git_requested,
def test_install_hook_icehouse_pkgs(self,
_determine_packages):
_determine_packages.return_value = []
_git_requested.return_value = False
self.os_release.return_value = 'icehouse'
self._call_hook('install.real')
for pkg in ['nodejs', 'node-less']:
@ -130,11 +121,9 @@ class TestHorizonHooks(CharmTestCase):
self.assertTrue(self.apt_install.called)
@patch.object(hooks, 'determine_packages')
@patch.object(utils, 'git_install_requested')
def test_install_hook_pre_icehouse_pkgs(self, _git_requested,
def test_install_hook_pre_icehouse_pkgs(self,
_determine_packages):
_determine_packages.return_value = []
_git_requested.return_value = False
self.os_release.return_value = 'grizzly'
self._call_hook('install.real')
for pkg in ['nodejs', 'node-less']:
@ -143,43 +132,12 @@ class TestHorizonHooks(CharmTestCase):
)
self.assertTrue(self.apt_install.called)
@patch.object(hooks, 'determine_packages')
@patch.object(utils, 'git_install_requested')
def test_install_hook_git(self, _git_requested, _determine_packages):
self.os_release.return_value = 'havana'
_determine_packages.return_value = []
_git_requested.return_value = True
self.filter_installed_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': 'horizon',
'repository': 'git://git.openstack.org/openstack/horizon',
'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._call_hook('install.real')
self.assertTrue(self.execd_preinstall.called)
self.configure_installation_source.assert_called_with(repo)
self.apt_update.assert_called_with(fatal=True)
self.apt_install.assert_called_with(['foo', 'bar'], fatal=True)
self.git_install.assert_called_with(projects_yaml)
@patch.object(hooks, 'determine_packages')
@patch.object(utils, 'path_hash')
@patch.object(utils, 'service')
@patch.object(utils, 'git_install_requested')
def test_upgrade_charm_hook(self, _git_requested, _service, _hash,
def test_upgrade_charm_hook(self, _service, _hash,
_determine_packages):
_determine_packages.return_value = []
_git_requested.return_value = False
side_effects = []
[side_effects.append(None) for f in RESTART_MAP.keys()]
[side_effects.append('bar') for f in RESTART_MAP.keys()]
@ -301,9 +259,7 @@ class TestHorizonHooks(CharmTestCase):
self.relation_set.assert_called_with(**args)
@patch('horizon_hooks.keystone_joined')
@patch.object(hooks, 'git_install_requested')
def test_config_changed_no_upgrade(self, _git_requested, _joined):
_git_requested.return_value = False
def test_config_changed_no_upgrade(self, _joined):
self.relation_ids.return_value = ['identity/0']
self.openstack_upgrade_available.return_value = False
self._call_hook('config-changed')
@ -317,39 +273,13 @@ class TestHorizonHooks(CharmTestCase):
self.assertTrue(self.CONFIGS.write_all.called)
self.open_port.assert_has_calls([call(80), call(443)])
@patch.object(hooks, 'git_install_requested')
def test_config_changed_do_upgrade(self, _git_requested):
_git_requested.return_value = False
def test_config_changed_do_upgrade(self):
self.relation_ids.return_value = []
self.test_config.set('openstack-origin', 'cloud:precise-grizzly')
self.openstack_upgrade_available.return_value = True
self._call_hook('config-changed')
self.assertTrue(self.do_openstack_upgrade.called)
@patch.object(hooks, 'git_install_requested')
@patch.object(hooks, 'config_value_changed')
def test_config_changed_git_updated(self, _config_val_changed,
_git_requested):
_git_requested.return_value = True
repo = 'cloud:trusty-juno'
openstack_origin_git = {
'repositories': [
{'name': 'requirements',
'repository': 'git://git.openstack.org/openstack/requirements', # noqa
'branch': 'stable/juno'},
{'name': 'horizon',
'repository': 'git://git.openstack.org/openstack/horizon',
'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._call_hook('config-changed')
self.git_install.assert_called_with(projects_yaml)
self.assertFalse(self.do_openstack_upgrade.called)
def test_keystone_joined_in_relation(self):
self._call_hook('identity-service-relation-joined')
self.relation_set.assert_called_with(
@ -392,10 +322,7 @@ class TestHorizonHooks(CharmTestCase):
self.relation_set.assert_called_with(port=70, hostname='192.168.1.1')
@patch.object(hooks, 'os_release')
@patch.object(hooks, 'git_install_requested')
def test_dashboard_config_joined_not_git(
self, _git_requested, _os_release):
_git_requested.return_value = False
def test_dashboard_config_joined(self, _os_release):
_os_release.return_value = 'vivid'
self._call_hook('dashboard-plugin-relation-joined')
self.relation_set.assert_called_with(
@ -404,20 +331,3 @@ class TestHorizonHooks(CharmTestCase):
openstack_dir='/usr/share/openstack-dashboard',
relation_id=None
)
@patch.object(hooks, 'os_release')
@patch.object(hooks, 'git_pip_venv_dir')
@patch.object(hooks, 'git_install_requested')
def test_dashboard_config_joined_git(
self, _git_requested, _git_pip_venv_dir, _os_release):
expected_bin_path = '/mnt/fuji/venv'
_git_requested.return_value = True
_git_pip_venv_dir.return_value = expected_bin_path
_os_release.return_value = 'wily'
self._call_hook('dashboard-plugin-relation-joined')
self.relation_set.assert_called_with(
release='wily',
bin_path=expected_bin_path,
openstack_dir='/usr/share/openstack-dashboard',
relation_id=None
)

View File

@ -13,7 +13,6 @@
# limitations under the License.
from mock import MagicMock, patch, call
import os
from collections import OrderedDict
import charmhelpers.contrib.openstack.templating as templating
templating.OSConfigRenderer = MagicMock()
@ -37,26 +36,15 @@ TO_PATCH = [
'reset_os_release',
]
openstack_origin_git = \
"""repositories:
- {name: requirements,
repository: 'git://git.openstack.org/openstack/requirements',
branch: stable/juno}
- {name: horizon,
repository: 'git://git.openstack.org/openstack/horizon',
branch: stable/juno}"""
class TestHorizohorizon_utils(CharmTestCase):
class TestHorizonUtils(CharmTestCase):
def setUp(self):
super(TestHorizohorizon_utils, self).setUp(horizon_utils, TO_PATCH)
super(TestHorizonUtils, self).setUp(horizon_utils, TO_PATCH)
@patch.object(horizon_utils, 'get_os_codename_install_source')
@patch.object(horizon_utils, 'git_install_requested')
def test_determine_packages(self, _git_install_requested,
def test_determine_packages(self,
_get_os_codename_install_source):
_git_install_requested.return_value = False
_get_os_codename_install_source.return_value = 'icehouse'
self.assertEqual(horizon_utils.determine_packages(), [
'haproxy',
@ -68,10 +56,7 @@ class TestHorizohorizon_utils(CharmTestCase):
'memcached'])
@patch.object(horizon_utils, 'get_os_codename_install_source')
@patch.object(horizon_utils, 'git_install_requested')
def test_determine_packages_mitaka(self, _git_install_requested,
_get_os_codename_install_source):
_git_install_requested.return_value = False
def test_determine_packages_mitaka(self, _get_os_codename_install_source):
_get_os_codename_install_source.return_value = 'mitaka'
self.assertTrue('python-pymysql' in horizon_utils.determine_packages())
@ -200,162 +185,6 @@ class TestHorizohorizon_utils(CharmTestCase):
call(conf, horizon_utils.CONFIG_FILES[conf]['hook_contexts']))
configs.register.assert_has_calls(calls)
@patch.object(horizon_utils, 'git_install_requested')
@patch.object(horizon_utils, 'git_clone_and_install')
@patch.object(horizon_utils, 'git_post_install')
@patch.object(horizon_utils, 'git_pre_install')
def test_git_install(self, git_pre, git_post, git_clone_and_install,
git_requested):
projects_yaml = openstack_origin_git
git_requested.return_value = True
horizon_utils.git_install(projects_yaml)
self.assertTrue(git_pre.called)
git_clone_and_install.assert_called_with(openstack_origin_git,
core_project='horizon')
self.assertTrue(git_post.called)
@patch.object(horizon_utils, 'mkdir')
@patch.object(horizon_utils, 'add_user_to_group')
@patch.object(horizon_utils, 'add_group')
@patch.object(horizon_utils, 'adduser')
@patch('subprocess.check_call')
def test_git_pre_install(self, check_call, adduser, add_group,
add_user_to_group, mkdir):
horizon_utils.git_pre_install()
adduser.assert_called_with('horizon', shell='/bin/bash',
system_user=True)
check_call.assert_called_with(['usermod', '--home',
'/usr/share/openstack-dashboard/',
'horizon'])
add_group.assert_called_with('horizon', system_group=True)
add_user_to_group.assert_called_with('horizon', 'horizon')
them_dir = '/usr/share/openstack-dashboard-ubuntu-theme'
expected = [
call('/etc/openstack-dashboard', owner='root',
group='root', perms=0755, force=False),
call('/usr/share/openstack-dashboard', owner='root',
group='root', perms=0755, force=False),
call('/usr/share/openstack-dashboard/bin/less', owner='root',
group='root', perms=0755, force=False),
call(os.path.join(them_dir, 'static/ubuntu/css'),
owner='root', group='root', perms=0755, force=False),
call(os.path.join(them_dir, 'static/ubuntu/img'),
owner='root', group='root', perms=0755, force=False),
call(os.path.join(them_dir, 'templates'),
owner='root', group='root', perms=0755, force=False),
call('/var/lib/openstack-dashboard', owner='horizon',
group='horizon', perms=0700, force=False),
]
self.assertEqual(mkdir.call_args_list, expected)
@patch.object(horizon_utils, 'git_src_dir')
@patch.object(horizon_utils, 'service_restart')
@patch('shutil.copyfile')
@patch('shutil.copytree')
@patch('os.path.join')
@patch('os.path.exists')
@patch('os.symlink')
@patch('os.chmod')
@patch('os.chown')
@patch('os.lchown')
@patch('os.walk')
@patch('subprocess.check_call')
@patch('pwd.getpwnam')
@patch('grp.getgrnam')
def test_git_post_install(self, grnam, pwnam, check_call, walk, lchown,
chown, chmod, symlink, exists, join, copytree,
copyfile, service_restart, git_src_dir):
class IDs(object):
pw_uid = 999
gr_gid = 999
pwnam.return_value = IDs
grnam.return_value = IDs
projects_yaml = openstack_origin_git
join.return_value = 'joined-string'
walk.return_value = yield '/root', ['dir'], ['file']
exists.return_value = False
horizon_utils.git_post_install(projects_yaml)
expected = [
call('joined-string',
'/usr/share/openstack-dashboard/manage.py'),
call('joined-string',
'/usr/share/openstack-dashboard/settings.py'),
call('joined-string',
'/etc/openstack-dashboard/local_settings.py'),
call('joined-string',
'/etc/apache2/conf-available/openstack-dashboard.conf'),
call('joined-string',
'/etc/openstack-dashboard/ubuntu_theme.py'),
]
copyfile.assert_has_calls(expected, any_order=True)
expected = [
call('joined-string',
'/usr/share/openstack-dashboard/openstack_dashboard'),
call('joined-string', 'joined-string'),
call('joined-string', 'joined-string'),
call('joined-string', 'joined-string'),
]
copytree.assert_has_calls(expected)
expected = [
call('/usr/share/openstack-dashboard/static'),
call('joined-string'),
call('joined-string'),
call('joined-string'),
call('joined-string'),
]
exists.assert_has_calls(expected, any_order=True)
dist_pkgs_dir = '/usr/local/lib/python2.7/dist-packages'
expected = [
call('/usr/share/openstack-dashboard/openstack_dashboard/static',
'/usr/share/openstack-dashboard/static'),
call('/etc/openstack-dashboard/ubuntu_theme.py', 'joined-string'),
call('/usr/share/openstack-dashboard-ubuntu-theme/static/ubuntu',
'joined-string'),
call('/etc/openstack-dashboard/local_settings.py',
'joined-string'),
call(os.path.join(dist_pkgs_dir, 'horizon/static/horizon/'),
'joined-string'),
]
symlink.assert_has_calls(expected, any_order=True)
expected = [
call('/var/lib/openstack-dashboard', 0o750),
call('/share/openstack-dashboard/manage.py', 0o755),
]
chmod.assert_has_calls(expected)
expected = [
call(['/usr/share/openstack-dashboard/manage.py',
'collectstatic', '--noinput']),
call(['/usr/share/openstack-dashboard/manage.py',
'compress', '--force']),
call(['a2enconf', 'openstack-dashboard']),
]
check_call.assert_has_calls(expected)
expected = [
call('horizon'),
]
pwnam.assert_has_calls(expected)
grnam.assert_has_calls(expected)
expected = [
call('/etc/openstack-dashboard', 999, 999),
call('/usr/share/openstack-dashboard/openstack_dashboard/static',
999, 999),
call('/var/lib/openstack-dashboard', 999, 999),
]
chown.assert_has_calls(expected)
expected = [
call('/share/openstack-dashboard/openstack_dashboard/static'),
]
walk.assert_has_calls(expected)
expected = [
call('/root/dir', 999, 999),
call('/root/file', 999, 999),
]
lchown.assert_has_calls(expected)
expected = [
call('apache2'),
]
self.assertEqual(service_restart.call_args_list, expected)
def test_assess_status(self):
with patch.object(horizon_utils, 'assess_status_func') as asf:
callee = MagicMock()