1447 lines
48 KiB
Python
Raw Normal View History

2013-08-01 20:42:16 -07:00
import os
2015-04-15 14:17:56 +00:00
import shutil
2013-08-01 20:42:16 -07:00
import subprocess
import ConfigParser
from base64 import b64encode
from collections import OrderedDict
from copy import deepcopy
2013-08-12 13:53:00 -07:00
from charmhelpers.contrib.openstack import context, templating
from charmhelpers.contrib.openstack.neutron import (
network_manager, neutron_plugin_attribute)
2013-08-01 20:42:16 -07:00
2015-10-07 09:32:28 +00:00
from charmhelpers.contrib.hahelpers.cluster import (
is_elected_leader,
get_hacluster_config,
)
2013-08-19 12:16:37 -07:00
from charmhelpers.contrib.peerstorage import (
peer_retrieve,
peer_store,
)
from charmhelpers.contrib.python.packages import (
pip_install,
)
2013-08-01 20:42:16 -07:00
from charmhelpers.contrib.openstack.utils import (
2013-08-19 12:16:37 -07:00
configure_installation_source,
get_host_ip,
get_hostname,
2013-08-19 12:16:37 -07:00
get_os_codename_install_source,
2015-04-15 14:17:56 +00:00
git_install_requested,
git_clone_and_install,
git_src_dir,
2015-05-12 15:17:42 +00:00
git_pip_venv_dir,
git_yaml_value,
incomplete_relation_data,
is_ip,
2013-08-12 13:53:00 -07:00
os_release,
2015-10-07 09:32:28 +00:00
save_script_rc as _save_script_rc,
set_os_workload_status,
)
2013-09-20 17:29:50 +01:00
from charmhelpers.fetch import (
2014-03-06 12:46:15 +00:00
apt_upgrade,
2013-08-19 12:16:37 -07:00
apt_update,
2014-03-14 11:23:48 +00:00
apt_install,
2014-09-18 20:23:54 +08:00
add_source
2013-08-19 12:16:37 -07:00
)
2013-08-01 20:42:16 -07:00
from charmhelpers.core.hookenv import (
2015-04-15 14:17:56 +00:00
charm_dir,
2013-08-01 20:42:16 -07:00
config,
2013-08-10 09:49:47 +01:00
log,
relation_get,
2013-08-01 20:42:16 -07:00
relation_ids,
2013-08-10 09:49:47 +01:00
remote_unit,
2014-05-08 19:36:17 +00:00
is_relation_made,
DEBUG,
2013-08-12 13:53:00 -07:00
INFO,
2013-08-10 09:49:47 +01:00
ERROR,
2015-10-07 09:32:28 +00:00
status_get,
status_set,
related_units,
local_unit,
2013-08-01 20:42:16 -07:00
)
from charmhelpers.core.host import (
2015-04-15 14:17:56 +00:00
adduser,
add_group,
add_user_to_group,
mkdir,
service,
service_start,
service_stop,
2014-09-18 20:23:54 +08:00
service_running,
2015-04-15 14:17:56 +00:00
lsb_release,
)
2015-04-15 14:17:56 +00:00
from charmhelpers.core.templating import render
from charmhelpers.contrib.network.ip import (
2014-09-30 14:48:02 +08:00
is_ipv6
)
from charmhelpers.core.decorators import (
retry_on_exception,
)
2013-08-01 20:42:16 -07:00
import nova_cc_context
TEMPLATES = 'templates/'
CLUSTER_RES = 'grp_nova_vips'
2013-08-01 20:42:16 -07:00
2015-10-07 09:32:28 +00:00
# The interface is said to be satisfied if anyone of the interfaces in the
# list has a complete context.
REQUIRED_INTERFACES = {
'database': ['shared-db', 'pgsql-db'],
'messaging': ['amqp', 'zeromq-configuration'],
'identity': ['identity-service'],
'image': ['image-service'],
'compute': ['nova-compute'],
}
# removed from original: charm-helper-sh
2013-08-01 20:42:16 -07:00
BASE_PACKAGES = [
'apache2',
'haproxy',
'python-keystoneclient',
'python-mysqldb',
2014-03-20 12:07:52 +01:00
'python-psycopg2',
2014-08-12 15:41:11 +01:00
'python-psutil',
2014-12-16 19:31:29 +00:00
'python-six',
2013-08-01 20:42:16 -07:00
'uuid',
2014-10-24 18:04:26 -03:00
'python-memcache',
2013-08-01 20:42:16 -07:00
]
2015-04-15 14:17:56 +00:00
BASE_GIT_PACKAGES = [
2015-05-12 15:17:42 +00:00
'libffi-dev',
'libmysqlclient-dev',
2015-05-12 15:17:42 +00:00
'libssl-dev',
2015-04-15 14:17:56 +00:00
'libxml2-dev',
'libxslt1-dev',
2015-05-12 19:53:58 +00:00
'libyaml-dev',
2015-04-15 14:17:56 +00:00
'python-dev',
'python-pip',
'python-setuptools',
'zlib1g-dev',
]
LATE_GIT_PACKAGES = [
'novnc',
'spice-html5',
'websockify',
]
# ubuntu packages that should not be installed when deploying from git
GIT_PACKAGE_BLACKLIST = [
2015-05-12 15:17:42 +00:00
'neutron-common',
2015-04-15 14:17:56 +00:00
'neutron-server',
'neutron-plugin-ml2',
2015-04-15 14:17:56 +00:00
'nova-api-ec2',
'nova-api-os-compute',
'nova-api-os-volume',
'nova-cert',
'nova-conductor',
'nova-consoleauth',
'nova-novncproxy',
'nova-objectstore',
'nova-scheduler',
'nova-spiceproxy',
'nova-xvpvncproxy',
'python-keystoneclient',
'python-six',
'quantum-server',
]
2013-08-01 20:42:16 -07:00
BASE_SERVICES = [
'nova-api-ec2',
'nova-api-os-compute',
'nova-objectstore',
'nova-cert',
'nova-scheduler',
]
2016-02-09 11:19:34 +00:00
SERVICE_BLACKLIST = {
'liberty': ['nova-api-ec2', 'nova-objectstore']
}
2013-08-01 20:42:16 -07:00
API_PORTS = {
'nova-api-ec2': 8773,
'nova-api-os-compute': 8774,
'nova-api-os-volume': 8776,
'nova-objectstore': 3333,
2013-08-10 14:35:17 +01:00
'neutron-server': 9696,
2013-08-01 20:42:16 -07:00
'quantum-server': 9696,
}
NOVA_CONF_DIR = "/etc/nova"
2014-02-23 17:42:40 -05:00
QUANTUM_CONF_DIR = "/etc/quantum"
NEUTRON_CONF_DIR = "/etc/neutron"
NOVA_CONF = '%s/nova.conf' % NOVA_CONF_DIR
NOVA_API_PASTE = '%s/api-paste.ini' % NOVA_CONF_DIR
2014-02-23 17:42:40 -05:00
QUANTUM_CONF = '%s/quantum.conf' % QUANTUM_CONF_DIR
QUANTUM_API_PASTE = '%s/api-paste.ini' % QUANTUM_CONF_DIR
NEUTRON_CONF = '%s/neutron.conf' % NEUTRON_CONF_DIR
2013-09-25 14:10:26 +01:00
HAPROXY_CONF = '/etc/haproxy/haproxy.cfg'
APACHE_CONF = '/etc/apache2/sites-available/openstack_https_frontend'
2013-09-25 17:21:41 +01:00
APACHE_24_CONF = '/etc/apache2/sites-available/openstack_https_frontend.conf'
NEUTRON_DEFAULT = '/etc/default/neutron-server'
QUANTUM_DEFAULT = '/etc/default/quantum-server'
2013-09-25 14:10:26 +01:00
2016-02-09 11:19:34 +00:00
def resolve_services():
_services = deepcopy(BASE_SERVICES)
os_rel = get_os_codename_install_source(config('openstack-origin'))
for release in SERVICE_BLACKLIST:
if os_rel >= release:
2016-02-09 11:38:46 +00:00
[_services.remove(service)
for service in SERVICE_BLACKLIST[release]]
2016-02-09 11:19:34 +00:00
return _services
2013-08-01 20:42:16 -07:00
BASE_RESOURCE_MAP = OrderedDict([
2013-09-25 14:10:26 +01:00
(NOVA_CONF, {
2016-02-09 11:19:34 +00:00
'services': resolve_services(),
2014-02-23 17:42:40 -05:00
'contexts': [context.AMQPContext(ssl_dir=NOVA_CONF_DIR),
context.SharedDBContext(
relation_prefix='nova', ssl_dir=NOVA_CONF_DIR),
context.OSConfigFlagContext(
charm_flag='nova-alchemy-flags',
template_flag='nova_alchemy_flags'),
2014-03-20 11:18:23 +01:00
nova_cc_context.NovaPostgresqlDBContext(),
2013-08-01 20:42:16 -07:00
context.ImageServiceContext(),
context.OSConfigFlagContext(),
2013-10-08 17:51:27 -07:00
context.SubordinateConfigContext(
interface='nova-vmware',
service='nova',
config_file=NOVA_CONF),
2014-07-11 13:05:35 +00:00
nova_cc_context.NovaCellContext(),
context.SyslogContext(),
2014-07-24 07:05:25 +00:00
context.LogLevelContext(),
nova_cc_context.HAProxyContext(),
nova_cc_context.IdentityServiceContext(
service='nova',
service_user='nova'),
2014-09-09 13:01:37 +00:00
nova_cc_context.VolumeServiceContext(),
2014-09-10 17:17:14 +00:00
context.ZeroMQContext(),
2014-10-15 06:49:03 +00:00
context.NotificationDriverContext(),
nova_cc_context.NovaIPv6Context(),
nova_cc_context.NeutronCCContext(),
nova_cc_context.NovaConfigContext(),
2015-07-21 10:42:36 +08:00
nova_cc_context.InstanceConsoleContext(),
2015-10-07 09:32:28 +00:00
nova_cc_context.ConsoleSSLContext(),
nova_cc_context.CloudComputeContext()],
2013-08-01 20:42:16 -07:00
}),
2013-09-25 14:10:26 +01:00
(NOVA_API_PASTE, {
2016-02-09 11:19:34 +00:00
'services': [s for s in resolve_services() if 'api' in s],
2015-10-02 14:05:06 +02:00
'contexts': [nova_cc_context.IdentityServiceContext(),
nova_cc_context.APIRateLimitingContext()],
2013-08-01 20:42:16 -07:00
}),
2013-09-25 14:10:26 +01:00
(QUANTUM_CONF, {
2013-08-01 20:42:16 -07:00
'services': ['quantum-server'],
2014-02-23 17:42:40 -05:00
'contexts': [context.AMQPContext(ssl_dir=QUANTUM_CONF_DIR),
2014-03-27 11:02:24 +00:00
context.SharedDBContext(
2014-03-28 12:30:45 +01:00
user=config('neutron-database-user'),
database=config('neutron-database'),
relation_prefix='neutron',
ssl_dir=QUANTUM_CONF_DIR),
nova_cc_context.NeutronPostgresqlDBContext(),
2013-08-10 18:35:37 +01:00
nova_cc_context.HAProxyContext(),
nova_cc_context.IdentityServiceContext(
service='neutron',
service_user='neutron'),
2014-04-16 10:07:07 +01:00
nova_cc_context.NeutronCCContext(),
context.SyslogContext()],
2013-08-01 20:42:16 -07:00
}),
(QUANTUM_DEFAULT, {
'services': ['quantum-server'],
'contexts': [nova_cc_context.NeutronCCContext()],
}),
2013-09-25 14:10:26 +01:00
(QUANTUM_API_PASTE, {
2013-08-01 20:42:16 -07:00
'services': ['quantum-server'],
'contexts': [nova_cc_context.IdentityServiceContext()],
2013-08-01 20:42:16 -07:00
}),
2013-09-25 14:10:26 +01:00
(NEUTRON_CONF, {
2013-08-10 14:35:17 +01:00
'services': ['neutron-server'],
2014-02-23 17:42:40 -05:00
'contexts': [context.AMQPContext(ssl_dir=NEUTRON_CONF_DIR),
2014-03-20 16:58:05 +00:00
context.SharedDBContext(
user=config('neutron-database-user'),
database=config('neutron-database'),
2014-03-28 12:30:45 +01:00
relation_prefix='neutron',
ssl_dir=NEUTRON_CONF_DIR),
nova_cc_context.NeutronPostgresqlDBContext(),
nova_cc_context.IdentityServiceContext(
service='neutron',
service_user='neutron'),
2013-08-12 13:53:00 -07:00
nova_cc_context.NeutronCCContext(),
2014-04-16 10:25:57 +01:00
nova_cc_context.HAProxyContext(),
context.SyslogContext(),
nova_cc_context.NovaConfigContext(),
context.BindHostContext()],
2013-08-10 14:35:17 +01:00
}),
(NEUTRON_DEFAULT, {
'services': ['neutron-server'],
'contexts': [nova_cc_context.NeutronCCContext()],
}),
2013-09-25 14:10:26 +01:00
(HAPROXY_CONF, {
'contexts': [context.HAProxyContext(singlenode_mode=True),
2013-08-01 20:42:16 -07:00
nova_cc_context.HAProxyContext()],
'services': ['haproxy'],
}),
2013-09-25 14:10:26 +01:00
(APACHE_CONF, {
2013-09-25 17:21:41 +01:00
'contexts': [nova_cc_context.ApacheSSLContext()],
'services': ['apache2'],
}),
(APACHE_24_CONF, {
2013-08-01 20:42:16 -07:00
'contexts': [nova_cc_context.ApacheSSLContext()],
'services': ['apache2'],
}),
])
CA_CERT_PATH = '/usr/local/share/ca-certificates/keystone_juju_ca_cert.crt'
2013-08-10 09:49:47 +01:00
NOVA_SSH_DIR = '/etc/nova/compute_ssh/'
2014-07-09 14:09:15 +01:00
CONSOLE_CONFIG = {
'spice': {
'packages': ['nova-spiceproxy', 'nova-consoleauth'],
'services': ['nova-spiceproxy', 'nova-consoleauth'],
2014-07-09 16:35:00 +01:00
'proxy-page': '/spice_auto.html',
2014-07-09 14:09:15 +01:00
'proxy-port': 6082,
2014-07-09 16:35:00 +01:00
},
'novnc': {
'packages': ['nova-novncproxy', 'nova-consoleauth'],
'services': ['nova-novncproxy', 'nova-consoleauth'],
'proxy-page': '/vnc_auto.html',
'proxy-port': 6080,
2014-07-10 08:37:39 +01:00
},
'xvpvnc': {
'packages': ['nova-xvpvncproxy', 'nova-consoleauth'],
'services': ['nova-xvpvncproxy', 'nova-consoleauth'],
'proxy-page': '/console',
'proxy-port': 6081,
},
2014-07-09 14:09:15 +01:00
}
2013-08-01 20:42:16 -07:00
def resource_map():
'''
Dynamically generate a map of resources that will be managed for a single
hook execution.
'''
resource_map = deepcopy(BASE_RESOURCE_MAP)
if relation_ids('nova-volume-service'):
# if we have a relation to a nova-volume service, we're
# also managing the nova-volume API endpoint (legacy)
resource_map['/etc/nova/nova.conf']['services'].append(
'nova-api-os-volume')
net_manager = network_manager()
2013-09-25 17:21:41 +01:00
if os.path.exists('/etc/apache2/conf-available'):
2013-09-25 17:24:36 +01:00
resource_map.pop(APACHE_CONF)
2013-09-25 17:21:41 +01:00
else:
2013-09-25 17:24:36 +01:00
resource_map.pop(APACHE_24_CONF)
2013-09-25 17:21:41 +01:00
resource_map[NOVA_CONF]['contexts'].append(
nova_cc_context.NeutronCCContext())
# pop out irrelevant resources from the OrderedDict (easier than adding
# them late)
if net_manager != 'quantum':
[resource_map.pop(k) for k in list(resource_map.iterkeys())
if 'quantum' in k]
if net_manager != 'neutron':
[resource_map.pop(k) for k in list(resource_map.iterkeys())
if 'neutron' in k]
# add neutron plugin requirements. nova-c-c only needs the
# neutron-server associated with configs, not the plugin agent.
if net_manager in ['quantum', 'neutron']:
plugin = neutron_plugin()
if plugin:
conf = neutron_plugin_attribute(plugin, 'config', net_manager)
ctxts = (neutron_plugin_attribute(plugin, 'contexts',
2016-02-09 11:38:46 +00:00
net_manager) or [])
services = neutron_plugin_attribute(plugin, 'server_services',
net_manager)
resource_map[conf] = {}
resource_map[conf]['services'] = services
resource_map[conf]['contexts'] = ctxts
resource_map[conf]['contexts'].append(
nova_cc_context.NeutronCCContext())
# update for postgres
resource_map[conf]['contexts'].append(
nova_cc_context.NeutronPostgresqlDBContext())
if is_relation_made('neutron-api'):
for k in list(resource_map.iterkeys()):
# neutron-api runs neutron services
if 'quantum' in k or 'neutron' in k:
resource_map[k]['services'] = []
2014-05-08 19:36:17 +00:00
resource_map[NOVA_CONF]['contexts'].append(
nova_cc_context.NeutronAPIContext())
2014-03-20 19:17:35 +01:00
# nova-conductor for releases >= G.
if os_release('nova-common') not in ['essex', 'folsom']:
resource_map['/etc/nova/nova.conf']['services'] += ['nova-conductor']
if os_release('nova-common') >= 'mitaka':
resource_map[NOVA_CONF]['contexts'].append(
nova_cc_context.NovaAPISharedDBContext(relation_prefix='novaapi',
database='nova_api',
ssl_dir=NOVA_CONF_DIR)
)
if console_attributes('services'):
2014-07-09 14:09:15 +01:00
resource_map['/etc/nova/nova.conf']['services'] += \
console_attributes('services')
# also manage any configs that are being updated by subordinates.
vmware_ctxt = context.SubordinateConfigContext(interface='nova-vmware',
service='nova',
config_file=NOVA_CONF)
vmware_ctxt = vmware_ctxt()
if vmware_ctxt and 'services' in vmware_ctxt:
for s in vmware_ctxt['services']:
if s not in resource_map[NOVA_CONF]['services']:
resource_map[NOVA_CONF]['services'].append(s)
2014-04-25 16:46:42 +00:00
2013-08-01 20:42:16 -07:00
return resource_map
def register_configs(release=None):
release = release or os_release('nova-common')
2013-08-01 20:42:16 -07:00
configs = templating.OSConfigRenderer(templates_dir=TEMPLATES,
openstack_release=release)
for cfg, rscs in resource_map().iteritems():
2013-08-01 20:42:16 -07:00
configs.register(cfg, rscs['contexts'])
return configs
def restart_map():
2013-08-19 15:36:36 -07:00
return OrderedDict([(cfg, v['services'])
for cfg, v in resource_map().iteritems()
if v['services']])
2013-08-01 20:42:16 -07:00
def services():
''' Returns a list of services associate with this charm '''
_services = []
for v in restart_map().values():
_services = _services + v
return list(set(_services))
2013-08-01 20:42:16 -07:00
def determine_ports():
'''Assemble a list of API ports for services we are managing'''
ports = []
for services in restart_map().values():
for svc in services:
2013-08-01 20:42:16 -07:00
try:
ports.append(API_PORTS[svc])
2013-08-01 20:42:16 -07:00
except KeyError:
pass
return list(set(ports))
2013-08-01 20:42:16 -07:00
2013-08-10 14:35:17 +01:00
def api_port(service):
return API_PORTS[service]
2013-08-01 20:42:16 -07:00
2014-07-10 08:37:39 +01:00
def console_attributes(attr, proto=None):
'''Leave proto unset to query attributes of the protocal specified at
runtime'''
if proto:
console_proto = proto
else:
console_proto = config('console-access-protocol')
2014-07-09 14:09:15 +01:00
if attr == 'protocol':
return console_proto
2014-07-10 08:37:39 +01:00
# 'vnc' is a virtual type made up of novnc and xvpvnc
if console_proto == 'vnc':
if attr in ['packages', 'services']:
return list(set(CONSOLE_CONFIG['novnc'][attr] +
CONSOLE_CONFIG['xvpvnc'][attr]))
else:
return None
2014-07-09 14:09:15 +01:00
if console_proto in CONSOLE_CONFIG:
return CONSOLE_CONFIG[console_proto][attr]
return None
2013-08-01 20:42:16 -07:00
def determine_packages():
# currently all packages match service names
packages = [] + BASE_PACKAGES
for v in resource_map().values():
2013-08-01 20:42:16 -07:00
packages.extend(v['services'])
if network_manager() in ['neutron', 'quantum']:
pkgs = neutron_plugin_attribute(neutron_plugin(), 'server_packages',
network_manager())
2013-10-16 13:12:13 +01:00
packages.extend(pkgs)
if console_attributes('packages'):
packages.extend(console_attributes('packages'))
2015-04-15 14:17:56 +00:00
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)
2013-08-01 20:42:16 -07:00
return list(set(packages))
def save_script_rc():
env_vars = {
'OPENSTACK_PORT_MCASTPORT': config('ha-mcastport'),
'OPENSTACK_SERVICE_API_EC2': 'nova-api-ec2',
'OPENSTACK_SERVICE_API_OS_COMPUTE': 'nova-api-os-compute',
'OPENSTACK_SERVICE_CERT': 'nova-cert',
'OPENSTACK_SERVICE_CONDUCTOR': 'nova-conductor',
'OPENSTACK_SERVICE_OBJECTSTORE': 'nova-objectstore',
'OPENSTACK_SERVICE_SCHEDULER': 'nova-scheduler',
}
if relation_ids('nova-volume-service'):
env_vars['OPENSTACK_SERVICE_API_OS_VOL'] = 'nova-api-os-volume'
2013-08-10 14:35:17 +01:00
if network_manager() == 'quantum':
2013-08-01 20:42:16 -07:00
env_vars['OPENSTACK_SERVICE_API_QUANTUM'] = 'quantum-server'
2013-08-10 14:35:17 +01:00
if network_manager() == 'neutron':
env_vars['OPENSTACK_SERVICE_API_NEUTRON'] = 'neutron-server'
2013-08-01 20:42:16 -07:00
_save_script_rc(**env_vars)
def get_step_upgrade_source(new_src):
'''
Determine if upgrade skips a release and, if so, return source
of skipped release.
'''
sources = {
# target_src: (cur_pocket, step_src)
'cloud:precise-icehouse':
('precise-updates/grizzly', 'cloud:precise-havana'),
'cloud:precise-icehouse/proposed':
('precise-proposed/grizzly', 'cloud:precise-havana/proposed')
}
configure_installation_source(new_src)
with open('/etc/apt/sources.list.d/cloud-archive.list', 'r') as f:
line = f.readline()
for target_src, (cur_pocket, step_src) in sources.items():
if target_src != new_src:
continue
if cur_pocket in line:
return step_src
return None
2014-04-08 23:23:04 +01:00
POLICY_RC_D = """#!/bin/bash
set -e
case $1 in
neutron-server|quantum-server|nova-*)
[ $2 = "start" ] && exit 101
;;
*)
;;
esac
exit 0
"""
def enable_policy_rcd():
with open('/usr/sbin/policy-rc.d', 'w') as policy:
policy.write(POLICY_RC_D)
os.chmod('/usr/sbin/policy-rc.d', 0o755)
def disable_policy_rcd():
os.unlink('/usr/sbin/policy-rc.d')
QUANTUM_DB_MANAGE = "quantum-db-manage"
NEUTRON_DB_MANAGE = "neutron-db-manage"
2014-04-08 23:23:04 +01:00
def reset_os_release():
# Ugly hack to make os_release re-read versions
import charmhelpers.contrib.openstack.utils as utils
utils.os_rel = None
def neutron_db_manage(actions):
net_manager = network_manager()
if net_manager in ['neutron', 'quantum']:
plugin = neutron_plugin()
conf = neutron_plugin_attribute(plugin, 'config', net_manager)
if net_manager == 'quantum':
cmd = QUANTUM_DB_MANAGE
else:
cmd = NEUTRON_DB_MANAGE
subprocess.check_call([
cmd, '--config-file=/etc/{mgr}/{mgr}.conf'.format(mgr=net_manager),
2014-04-09 09:23:23 +01:00
'--config-file={}'.format(conf)] + actions
2014-04-08 23:23:04 +01:00
)
def get_db_connection():
config = ConfigParser.RawConfigParser()
config.read('/etc/neutron/neutron.conf')
try:
return config.get('database', 'connection')
except:
return None
def ml2_migration():
reset_os_release()
net_manager = network_manager()
if net_manager == 'neutron':
plugin = neutron_plugin()
if plugin == 'ovs':
2014-04-09 16:22:15 +01:00
log('Migrating from openvswitch to ml2 plugin')
cmd = [
'python',
'/usr/lib/python2.7/dist-packages/neutron'
'/db/migration/migrate_to_ml2.py',
'--tunnel-type', 'gre',
'--release', 'icehouse',
'openvswitch', get_db_connection()
]
subprocess.check_call(cmd)
def is_db_initialised():
if relation_ids('cluster'):
dbsync_state = peer_retrieve('dbsync_state')
if dbsync_state == 'complete':
log("Database is initialised", level=DEBUG)
return True
log("Database is NOT initialised", level=DEBUG)
return False
def _do_openstack_upgrade(new_src):
2014-04-08 23:23:04 +01:00
enable_policy_rcd()
cur_os_rel = os_release('nova-common')
2013-08-19 12:16:37 -07:00
new_os_rel = get_os_codename_install_source(new_src)
log('Performing OpenStack upgrade to %s.' % (new_os_rel))
configure_installation_source(new_src)
dpkg_opts = [
'--option', 'Dpkg::Options::=--force-confnew',
'--option', 'Dpkg::Options::=--force-confdef',
]
2014-04-09 10:12:01 +01:00
# NOTE(jamespage) pre-stamp neutron database before upgrade from grizzly
if cur_os_rel == 'grizzly':
neutron_db_manage(['stamp', 'grizzly'])
2014-04-08 23:23:04 +01:00
2014-03-14 11:23:48 +00:00
apt_update(fatal=True)
2014-03-06 13:41:46 +00:00
apt_upgrade(options=dpkg_opts, fatal=True, dist=True)
2014-03-14 11:23:48 +00:00
apt_install(determine_packages(), fatal=True)
2013-08-19 12:16:37 -07:00
disable_policy_rcd()
2014-04-09 10:12:01 +01:00
if cur_os_rel == 'grizzly':
# NOTE(jamespage) when upgrading from grizzly->havana, config
# files need to be generated prior to performing the db upgrade
reset_os_release()
configs = register_configs(release=new_os_rel)
configs.write_all()
neutron_db_manage(['upgrade', 'head'])
else:
2015-04-22 14:36:20 +00:00
if new_os_rel < 'kilo':
neutron_db_manage(['stamp', cur_os_rel])
migrate_neutron_database()
2014-04-09 10:12:01 +01:00
# NOTE(jamespage) upgrade with existing config files as the
# havana->icehouse migration enables new service_plugins which
# create issues with db upgrades
reset_os_release()
configs = register_configs(release=new_os_rel)
configs.write_all()
2013-08-19 12:16:37 -07:00
2014-04-08 23:23:04 +01:00
if new_os_rel == 'icehouse':
2014-04-09 10:12:01 +01:00
# NOTE(jamespage) default plugin switch to ml2@icehouse
ml2_migration()
2013-08-19 12:16:37 -07:00
if new_os_rel >= 'mitaka' and not database_setup(prefix='novaapi'):
# NOTE: Defer service restarts and database migrations for now
# as nova_api database is not yet created
if (relation_ids('cluster') and
is_elected_leader(CLUSTER_RES)):
# NOTE: reset dbsync state so that migration will complete
# when the nova_api database is setup.
peer_store('dbsync_state', None)
return configs
if is_elected_leader(CLUSTER_RES):
status_set('maintenance', 'Running nova db migration')
2014-09-26 15:46:53 +00:00
migrate_nova_database()
[service_start(s) for s in services()]
2014-04-08 23:23:04 +01:00
return configs
2013-08-01 20:42:16 -07:00
def database_setup(prefix):
'''
Determine when a specific database is setup
and access is granted to the local unit.
This function only checks the MySQL shared-db
relation name using the provided prefix.
'''
key = '{}_allowed_units'.format(prefix)
for db_rid in relation_ids('shared-db'):
for unit in related_units(db_rid):
allowed_units = relation_get(key, rid=db_rid, unit=unit)
if allowed_units and local_unit() in allowed_units.split():
return True
return False
2015-09-21 16:06:54 -07:00
def do_openstack_upgrade(configs):
new_src = config('openstack-origin')
if new_src[:6] != 'cloud:':
raise ValueError("Unable to perform upgrade to %s" % new_src)
step_src = get_step_upgrade_source(new_src)
if step_src is not None:
_do_openstack_upgrade(step_src)
return _do_openstack_upgrade(new_src)
2013-08-01 20:42:16 -07:00
def volume_service():
'''Specifies correct volume API for specific OS release'''
2013-08-12 13:53:00 -07:00
os_vers = os_release('nova-common')
2013-08-01 20:42:16 -07:00
if os_vers == 'essex':
return 'nova-volume'
elif os_vers == 'folsom': # support both drivers in folsom.
if not relation_ids('cinder-volume-service'):
return 'nova-volume'
return 'cinder'
# NOTE(jamespage): Retry deals with sync issues during one-shot HA deploys.
# mysql might be restarting or suchlike.
@retry_on_exception(5, base_delay=3, exc_type=subprocess.CalledProcessError)
2014-09-26 15:46:53 +00:00
def migrate_nova_database():
2013-08-01 20:42:16 -07:00
'''Runs nova-manage to initialize a new database or migrate existing'''
log('Migrating the nova database.', level=INFO)
2013-08-01 20:42:16 -07:00
cmd = ['nova-manage', 'db', 'sync']
2013-08-15 13:48:37 -07:00
subprocess.check_output(cmd)
if os_release('nova-common') >= 'mitaka':
log('Migrating the nova-api database.', level=INFO)
cmd = ['nova-manage', 'api_db', 'sync']
subprocess.check_output(cmd)
if relation_ids('cluster'):
log('Informing peers that dbsync is complete', level=INFO)
peer_store('dbsync_state', 'complete')
log('Enabling services', level=INFO)
enable_services()
cmd_all_services('start')
2013-08-01 20:42:16 -07:00
# NOTE(jamespage): Retry deals with sync issues during one-shot HA deploys.
# mysql might be restarting or suchlike.
@retry_on_exception(5, base_delay=3, exc_type=subprocess.CalledProcessError)
2014-09-26 15:46:53 +00:00
def migrate_neutron_database():
'''Runs neutron-db-manage to init a new database or migrate existing'''
2014-09-26 15:46:53 +00:00
log('Migrating the neutron database.', level=INFO)
neutron_db_manage(['upgrade', 'head'])
2013-08-01 20:42:16 -07:00
def auth_token_config(setting):
2014-02-24 14:16:35 -05:00
"""
2013-08-01 20:42:16 -07:00
Returns currently configured value for setting in api-paste.ini's
authtoken section, or None.
2014-02-24 14:16:35 -05:00
"""
2013-08-01 20:42:16 -07:00
config = ConfigParser.RawConfigParser()
config.read('/etc/nova/api-paste.ini')
try:
value = config.get('filter:authtoken', setting)
except:
return None
if value.startswith('%'):
return None
return value
def keystone_ca_cert_b64():
'''Returns the local Keystone-provided CA cert if it exists, or None.'''
if not os.path.isfile(CA_CERT_PATH):
return None
with open(CA_CERT_PATH) as _in:
return b64encode(_in.read())
def ssh_directory_for_unit(unit=None, user=None):
if unit:
remote_service = unit.split('/')[0]
else:
remote_service = remote_unit().split('/')[0]
if user:
remote_service = "{}_{}".format(remote_service, user)
2013-08-12 13:53:00 -07:00
_dir = os.path.join(NOVA_SSH_DIR, remote_service)
for d in [NOVA_SSH_DIR, _dir]:
if not os.path.isdir(d):
os.mkdir(d)
for f in ['authorized_keys', 'known_hosts']:
f = os.path.join(_dir, f)
if not os.path.isfile(f):
open(f, 'w').close()
return _dir
2013-08-10 09:49:47 +01:00
def known_hosts(unit=None, user=None):
return os.path.join(ssh_directory_for_unit(unit, user), 'known_hosts')
2013-08-10 09:49:47 +01:00
def authorized_keys(unit=None, user=None):
return os.path.join(ssh_directory_for_unit(unit, user), 'authorized_keys')
2013-08-10 09:49:47 +01:00
def ssh_known_host_key(host, unit=None, user=None):
cmd = ['ssh-keygen', '-f', known_hosts(unit, user), '-H', '-F', host]
try:
2015-08-06 14:04:08 +08:00
# The first line of output is like '# Host xx found: line 1 type RSA',
# which should be excluded.
2015-07-29 18:41:19 +08:00
output = subprocess.check_output(cmd).strip()
except subprocess.CalledProcessError:
return None
2013-08-10 09:49:47 +01:00
2015-10-06 16:47:35 +01:00
if output:
# Bug #1500589 cmd has 0 rc on precise if entry not present
lines = output.split('\n')
if len(lines) > 1:
return lines[1]
return None
2013-08-10 09:49:47 +01:00
def remove_known_host(host, unit=None, user=None):
2013-08-10 09:49:47 +01:00
log('Removing SSH known host entry for compute host at %s' % host)
cmd = ['ssh-keygen', '-f', known_hosts(unit, user), '-R', host]
2013-08-10 09:49:47 +01:00
subprocess.check_call(cmd)
2015-07-29 19:23:06 +08:00
def is_same_key(key_1, key_2):
2015-08-06 14:04:08 +08:00
# The key format get will be like '|1|2rUumCavEXWVaVyB5uMl6m85pZo=|Cp'
# 'EL6l7VTY37T/fg/ihhNb/GPgs= ssh-rsa AAAAB', we only need to compare
# the part start with 'ssh-rsa' followed with '= ', because the hash
# value in the beginning will change each time.
2015-07-29 19:23:06 +08:00
k_1 = key_1.split('= ')[1]
k_2 = key_2.split('= ')[1]
return k_1 == k_2
def add_known_host(host, unit=None, user=None):
2013-08-10 09:49:47 +01:00
'''Add variations of host to a known hosts file.'''
cmd = ['ssh-keyscan', '-H', '-t', 'rsa', host]
try:
remote_key = subprocess.check_output(cmd).strip()
except Exception as e:
log('Could not obtain SSH host key from %s' % host, level=ERROR)
raise e
current_key = ssh_known_host_key(host, unit, user)
2015-07-29 19:23:06 +08:00
if current_key and remote_key:
if is_same_key(remote_key, current_key):
2013-08-10 09:49:47 +01:00
log('Known host key for compute host %s up to date.' % host)
return
else:
remove_known_host(host, unit, user)
2013-08-10 09:49:47 +01:00
log('Adding SSH host key to known hosts for compute node at %s.' % host)
with open(known_hosts(unit, user), 'a') as out:
2013-08-10 09:49:47 +01:00
out.write(remote_key + '\n')
def ssh_authorized_key_exists(public_key, unit=None, user=None):
with open(authorized_keys(unit, user)) as keys:
2013-08-10 09:49:47 +01:00
return (' %s ' % public_key) in keys.read()
def add_authorized_key(public_key, unit=None, user=None):
with open(authorized_keys(unit, user), 'a') as keys:
2013-08-10 09:49:47 +01:00
keys.write(public_key + '\n')
def ssh_compute_add(public_key, rid=None, unit=None, user=None):
# If remote compute node hands us a hostname, ensure we have a
# known hosts entry for its IP, hostname and FQDN.
private_address = relation_get(rid=rid, unit=unit,
attribute='private-address')
hosts = [private_address]
if not is_ipv6(private_address):
if relation_get('hostname'):
hosts.append(relation_get('hostname'))
if not is_ip(private_address):
hosts.append(get_host_ip(private_address))
hosts.append(private_address.split('.')[0])
else:
hn = get_hostname(private_address)
hosts.append(hn)
hosts.append(hn.split('.')[0])
for host in list(set(hosts)):
2015-07-29 17:31:20 +08:00
add_known_host(host, unit, user)
if not ssh_authorized_key_exists(public_key, unit, user):
log('Saving SSH authorized key for compute host at %s.' %
private_address)
add_authorized_key(public_key, unit, user)
2013-08-10 09:49:47 +01:00
def ssh_known_hosts_lines(unit=None, user=None):
known_hosts_list = []
2013-08-10 09:49:47 +01:00
with open(known_hosts(unit, user)) as hosts:
for hosts_line in hosts:
if hosts_line.rstrip():
known_hosts_list.append(hosts_line.rstrip())
return(known_hosts_list)
2013-08-10 09:49:47 +01:00
def ssh_authorized_keys_lines(unit=None, user=None):
authorized_keys_list = []
2013-08-10 09:49:47 +01:00
with open(authorized_keys(unit, user)) as keys:
for authkey_line in keys:
if authkey_line.rstrip():
authorized_keys_list.append(authkey_line.rstrip())
return(authorized_keys_list)
2013-08-10 09:49:47 +01:00
def ssh_compute_remove(public_key, unit=None, user=None):
if not (os.path.isfile(authorized_keys(unit, user)) or
os.path.isfile(known_hosts(unit, user))):
2013-08-10 09:49:47 +01:00
return
with open(authorized_keys(unit, user)) as _keys:
keys = [k.strip() for k in _keys.readlines()]
if public_key not in keys:
return
[keys.remove(key) for key in keys if key == public_key]
with open(authorized_keys(unit, user), 'w') as _keys:
keys = '\n'.join(keys)
if not keys.endswith('\n'):
keys += '\n'
_keys.write(keys)
2013-08-01 20:42:16 -07:00
2014-06-27 11:37:18 +01:00
def determine_endpoints(public_url, internal_url, admin_url):
2013-08-10 14:35:17 +01:00
'''Generates a dictionary containing all relevant endpoints to be
passed to keystone as relation settings.'''
region = config('region')
2014-03-04 16:57:51 +00:00
os_rel = os_release('nova-common')
2013-08-10 14:35:17 +01:00
2014-03-04 16:57:51 +00:00
if os_rel >= 'grizzly':
nova_public_url = ('%s:%s/v2/$(tenant_id)s' %
(public_url, api_port('nova-api-os-compute')))
nova_internal_url = ('%s:%s/v2/$(tenant_id)s' %
(internal_url, api_port('nova-api-os-compute')))
2014-06-27 11:37:18 +01:00
nova_admin_url = ('%s:%s/v2/$(tenant_id)s' %
2014-07-16 14:19:17 +01:00
(admin_url, api_port('nova-api-os-compute')))
2014-03-04 16:57:51 +00:00
else:
nova_public_url = ('%s:%s/v1.1/$(tenant_id)s' %
(public_url, api_port('nova-api-os-compute')))
nova_internal_url = ('%s:%s/v1.1/$(tenant_id)s' %
(internal_url, api_port('nova-api-os-compute')))
2014-06-27 11:37:18 +01:00
nova_admin_url = ('%s:%s/v1.1/$(tenant_id)s' %
2014-07-16 14:19:17 +01:00
(admin_url, api_port('nova-api-os-compute')))
ec2_public_url = '%s:%s/services/Cloud' % (
public_url, api_port('nova-api-ec2'))
ec2_internal_url = '%s:%s/services/Cloud' % (
internal_url, api_port('nova-api-ec2'))
ec2_admin_url = '%s:%s/services/Cloud' % (admin_url,
api_port('nova-api-ec2'))
nova_volume_public_url = ('%s:%s/v1/$(tenant_id)s' %
(public_url, api_port('nova-api-os-compute')))
nova_volume_internal_url = ('%s:%s/v1/$(tenant_id)s' %
2014-07-16 14:19:17 +01:00
(internal_url,
api_port('nova-api-os-compute')))
2014-06-27 11:37:18 +01:00
nova_volume_admin_url = ('%s:%s/v1/$(tenant_id)s' %
2014-07-16 14:19:17 +01:00
(admin_url, api_port('nova-api-os-compute')))
neutron_public_url = '%s:%s' % (public_url, api_port('neutron-server'))
neutron_internal_url = '%s:%s' % (internal_url, api_port('neutron-server'))
2014-06-27 11:37:18 +01:00
neutron_admin_url = '%s:%s' % (admin_url, api_port('neutron-server'))
2014-07-16 14:19:17 +01:00
s3_public_url = '%s:%s' % (public_url, api_port('nova-objectstore'))
s3_internal_url = '%s:%s' % (internal_url, api_port('nova-objectstore'))
2014-06-27 11:37:18 +01:00
s3_admin_url = '%s:%s' % (admin_url, api_port('nova-objectstore'))
2013-08-10 14:35:17 +01:00
# the base endpoints
endpoints = {
'nova_service': 'nova',
'nova_region': region,
'nova_public_url': nova_public_url,
2014-06-27 11:37:18 +01:00
'nova_admin_url': nova_admin_url,
'nova_internal_url': nova_internal_url,
2013-08-10 14:35:17 +01:00
'ec2_service': 'ec2',
'ec2_region': region,
'ec2_public_url': ec2_public_url,
2014-06-27 11:37:18 +01:00
'ec2_admin_url': ec2_admin_url,
'ec2_internal_url': ec2_internal_url,
2013-08-10 14:35:17 +01:00
's3_service': 's3',
's3_region': region,
's3_public_url': s3_public_url,
2014-06-27 11:37:18 +01:00
's3_admin_url': s3_admin_url,
's3_internal_url': s3_internal_url,
2013-08-10 14:35:17 +01:00
}
if relation_ids('nova-volume-service'):
endpoints.update({
'nova-volume_service': 'nova-volume',
'nova-volume_region': region,
'nova-volume_public_url': nova_volume_public_url,
2014-06-27 11:37:18 +01:00
'nova-volume_admin_url': nova_volume_admin_url,
'nova-volume_internal_url': nova_volume_internal_url,
2013-08-10 14:35:17 +01:00
})
2013-08-10 19:06:09 +01:00
# XXX: Keep these relations named quantum_*??
if relation_ids('neutron-api'):
endpoints.update({
2014-06-23 11:59:22 +01:00
'quantum_service': None,
'quantum_region': None,
'quantum_public_url': None,
'quantum_admin_url': None,
'quantum_internal_url': None,
})
elif network_manager() in ['quantum', 'neutron']:
2013-08-10 14:35:17 +01:00
endpoints.update({
'quantum_service': 'quantum',
'quantum_region': region,
'quantum_public_url': neutron_public_url,
2014-06-27 11:37:18 +01:00
'quantum_admin_url': neutron_admin_url,
'quantum_internal_url': neutron_internal_url,
2013-08-10 14:35:17 +01:00
})
2015-03-24 17:48:42 +00:00
if os_rel >= 'kilo':
# NOTE(jamespage) drop endpoints for ec2 and s3
# ec2 is deprecated
2015-03-24 17:49:11 +00:00
# s3 is insecure and should die in flames
2015-03-25 13:34:27 +00:00
endpoints.update({
2015-03-24 17:48:42 +00:00
'ec2_service': None,
'ec2_region': None,
'ec2_public_url': None,
'ec2_admin_url': None,
'ec2_internal_url': None,
's3_service': None,
's3_region': None,
's3_public_url': None,
's3_admin_url': None,
's3_internal_url': None,
2015-03-25 13:34:27 +00:00
})
2015-03-24 17:48:42 +00:00
2013-08-10 14:35:17 +01:00
return endpoints
def neutron_plugin():
# quantum-plugin config setting can be safely overriden
# as we only supported OVS in G/neutron
return config('neutron-plugin') or config('quantum-plugin')
def guard_map():
2014-07-29 12:43:41 +01:00
'''Map of services and required interfaces that must be present before
the service should be allowed to start'''
gmap = {}
2016-02-09 11:19:34 +00:00
nova_services = resolve_services()
2014-07-29 12:43:41 +01:00
if os_release('nova-common') not in ['essex', 'folsom']:
nova_services.append('nova-conductor')
nova_interfaces = ['identity-service', 'amqp']
if relation_ids('pgsql-nova-db'):
2014-07-29 12:43:41 +01:00
nova_interfaces.append('pgsql-nova-db')
else:
2014-07-29 12:43:41 +01:00
nova_interfaces.append('shared-db')
2014-07-29 12:43:41 +01:00
for svc in nova_services:
gmap[svc] = nova_interfaces
net_manager = network_manager()
if net_manager in ['neutron', 'quantum'] and \
not is_relation_made('neutron-api'):
2014-07-29 12:43:41 +01:00
neutron_interfaces = ['identity-service', 'amqp']
if relation_ids('pgsql-neutron-db'):
neutron_interfaces.append('pgsql-neutron-db')
else:
neutron_interfaces.append('shared-db')
2014-07-29 12:43:41 +01:00
if network_manager() == 'quantum':
gmap['quantum-server'] = neutron_interfaces
2014-07-29 12:43:41 +01:00
else:
gmap['neutron-server'] = neutron_interfaces
return gmap
2014-07-29 12:43:41 +01:00
def service_guard(guard_map, contexts, active=False):
'''Inhibit services in guard_map from running unless
required interfaces are found complete in contexts.'''
def wrap(f):
def wrapped_f(*args):
2014-07-29 12:43:41 +01:00
if active is True:
incomplete_services = []
for svc in guard_map:
for interface in guard_map[svc]:
if interface not in contexts.complete_contexts():
incomplete_services.append(svc)
f(*args)
for svc in incomplete_services:
if service_running(svc):
log('Service {} has unfulfilled '
'interface requirements, stopping.'.format(svc))
service_stop(svc)
2014-07-29 12:43:41 +01:00
else:
f(*args)
return wrapped_f
return wrap
2014-09-09 13:01:37 +00:00
def get_topics():
2014-09-10 10:06:26 +00:00
topics = ['scheduler', 'conductor']
2014-09-09 13:01:37 +00:00
if 'nova-consoleauth' in services():
topics.append('consoleauth')
return topics
2014-10-15 06:49:03 +00:00
def cmd_all_services(cmd):
if cmd == 'start':
for svc in services():
if not service_running(svc):
service_start(svc)
else:
for svc in services():
service(cmd, svc)
def disable_services():
for svc in services():
with open('/etc/init/{}.override'.format(svc), 'wb') as out:
out.write('exec true\n')
def enable_services():
for svc in services():
override_file = '/etc/init/{}.override'.format(svc)
if os.path.isfile(override_file):
os.remove(override_file)
2014-09-18 20:23:54 +08:00
def setup_ipv6():
2014-09-30 14:24:53 +01:00
ubuntu_rel = lsb_release()['DISTRIB_CODENAME'].lower()
if ubuntu_rel < "trusty":
raise Exception("IPv6 is not supported in the charms for Ubuntu "
2014-09-18 20:23:54 +08:00
"versions less than Trusty 14.04")
# Need haproxy >= 1.5.3 for ipv6 so for Trusty if we are <= Kilo we need to
# use trusty-backports otherwise we can use the UCA.
if ubuntu_rel == 'trusty' and os_release('nova-api') < 'liberty':
add_source('deb http://archive.ubuntu.com/ubuntu trusty-backports '
'main')
2014-09-18 20:23:54 +08:00
apt_update()
apt_install('haproxy/trusty-backports', fatal=True)
2015-04-15 14:17:56 +00:00
def git_install(projects_yaml):
"""Perform setup, and install git repos specified in yaml parameter."""
if git_install_requested():
git_pre_install()
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',
2015-04-16 18:26:16 +00:00
'/var/lib/neutron',
'/var/lib/neutron/lock',
2015-04-15 14:17:56 +00:00
'/var/log/nova',
2015-04-16 18:26:16 +00:00
'/etc/neutron',
'/etc/neutron/plugins',
'/etc/neutron/plugins/ml2',
2015-04-15 14:17:56 +00:00
]
adduser('nova', shell='/bin/bash', system_user=True)
subprocess.check_call(['usermod', '--home', '/var/lib/nova', 'nova'])
add_group('nova', system_group=True)
add_user_to_group('nova', 'nova')
2015-04-16 18:26:16 +00:00
adduser('neutron', shell='/bin/bash', system_user=True)
add_group('neutron', system_group=True)
add_user_to_group('neutron', 'neutron')
2015-04-15 14:17:56 +00:00
for d in dirs:
mkdir(d, owner='nova', group='nova', perms=0755, force=False)
def git_post_install(projects_yaml):
"""Perform post-install setup."""
http_proxy = git_yaml_value(projects_yaml, 'http_proxy')
if http_proxy:
pip_install('mysql-python', proxy=http_proxy,
venv=git_pip_venv_dir(projects_yaml))
else:
pip_install('mysql-python',
venv=git_pip_venv_dir(projects_yaml))
2015-04-22 19:59:45 +00:00
2015-04-15 14:17:56 +00:00
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'])
2015-05-12 15:46:18 +00:00
# NOTE(coreycb): Need to find better solution than bin symlinks.
2015-05-12 15:17:42 +00:00
symlinks = [
2015-05-12 15:46:18 +00:00
{'src': os.path.join(git_pip_venv_dir(projects_yaml),
'bin/nova-manage'),
'link': '/usr/local/bin/nova-manage'},
2015-05-12 15:17:42 +00:00
{'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/neutron-db-manage'),
'link': '/usr/local/bin/neutron-db-manage'},
2015-05-12 15:17:42 +00:00
]
for s in symlinks:
if os.path.lexists(s['link']):
os.remove(s['link'])
os.symlink(s['src'], s['link'])
2015-04-15 14:17:56 +00:00
render('git/nova_sudoers', '/etc/sudoers.d/nova_sudoers', {}, perms=0o440)
nova_cc = 'nova-cloud-controller'
nova_user = 'nova'
start_dir = '/var/lib/nova'
2015-05-12 15:17:42 +00:00
bin_dir = os.path.join(git_pip_venv_dir(projects_yaml), 'bin')
2015-04-15 14:17:56 +00:00
nova_conf = '/etc/nova/nova.conf'
nova_ec2_api_context = {
'service_description': 'Nova EC2 API server',
'service_name': nova_cc,
'user_name': nova_user,
'start_dir': start_dir,
'process_name': 'nova-api-ec2',
2015-05-12 15:17:42 +00:00
'executable_name': os.path.join(bin_dir, 'nova-api-ec2'),
2015-04-15 14:17:56 +00:00
'config_files': [nova_conf],
}
nova_api_os_compute_context = {
'service_description': 'Nova OpenStack Compute API server',
'service_name': nova_cc,
'user_name': nova_user,
'start_dir': start_dir,
'process_name': 'nova-api-os-compute',
2015-05-12 15:17:42 +00:00
'executable_name': os.path.join(bin_dir, 'nova-api-os-compute'),
2015-04-15 14:17:56 +00:00
'config_files': [nova_conf],
}
nova_cells_context = {
'service_description': 'Nova cells',
'service_name': nova_cc,
'user_name': nova_user,
'start_dir': start_dir,
'process_name': 'nova-cells',
2015-05-12 15:17:42 +00:00
'executable_name': os.path.join(bin_dir, 'nova-cells'),
2015-04-15 14:17:56 +00:00
'config_files': [nova_conf],
}
nova_cert_context = {
'service_description': 'Nova cert',
'service_name': nova_cc,
'user_name': nova_user,
'start_dir': start_dir,
'process_name': 'nova-cert',
2015-05-12 15:17:42 +00:00
'executable_name': os.path.join(bin_dir, 'nova-cert'),
2015-04-15 14:17:56 +00:00
'config_files': [nova_conf],
}
nova_conductor_context = {
'service_description': 'Nova conductor',
'service_name': nova_cc,
'user_name': nova_user,
'start_dir': start_dir,
'process_name': 'nova-conductor',
2015-05-12 15:17:42 +00:00
'executable_name': os.path.join(bin_dir, 'nova-conductor'),
2015-04-15 14:17:56 +00:00
'config_files': [nova_conf],
}
nova_consoleauth_context = {
'service_description': 'Nova console auth',
'service_name': nova_cc,
'user_name': nova_user,
'start_dir': start_dir,
'process_name': 'nova-consoleauth',
2015-05-12 15:17:42 +00:00
'executable_name': os.path.join(bin_dir, 'nova-consoleauth'),
2015-04-15 14:17:56 +00:00
'config_files': [nova_conf],
}
nova_console_context = {
'service_description': 'Nova console',
'service_name': nova_cc,
'user_name': nova_user,
'start_dir': start_dir,
'process_name': 'nova-console',
2015-05-12 15:17:42 +00:00
'executable_name': os.path.join(bin_dir, 'nova-console'),
2015-04-15 14:17:56 +00:00
'config_files': [nova_conf],
}
nova_novncproxy_context = {
'service_description': 'Nova NoVNC proxy',
'service_name': nova_cc,
'user_name': nova_user,
'start_dir': start_dir,
'process_name': 'nova-novncproxy',
2015-05-12 15:17:42 +00:00
'executable_name': os.path.join(bin_dir, 'nova-novncproxy'),
2015-04-15 14:17:56 +00:00
'config_files': [nova_conf],
}
nova_objectstore_context = {
'service_description': 'Nova object store',
'service_name': nova_cc,
'user_name': nova_user,
'start_dir': start_dir,
'process_name': 'nova-objectstore',
2015-05-12 15:17:42 +00:00
'executable_name': os.path.join(bin_dir, 'nova-objectstore'),
2015-04-15 14:17:56 +00:00
'config_files': [nova_conf],
}
nova_scheduler_context = {
'service_description': 'Nova scheduler',
'service_name': nova_cc,
'user_name': nova_user,
'start_dir': start_dir,
'process_name': 'nova-scheduler',
2015-05-12 15:17:42 +00:00
'executable_name': os.path.join(bin_dir, 'nova-scheduler'),
2015-04-15 14:17:56 +00:00
'config_files': [nova_conf],
}
2015-04-22 19:59:45 +00:00
nova_serialproxy_context = {
'service_description': 'Nova serial proxy',
'service_name': nova_cc,
'user_name': nova_user,
'start_dir': start_dir,
'process_name': 'nova-serialproxy',
2015-05-12 15:17:42 +00:00
'executable_name': os.path.join(bin_dir, 'nova-serialproxy'),
2015-04-22 19:59:45 +00:00
'config_files': [nova_conf],
}
2015-04-15 14:17:56 +00:00
nova_spiceproxy_context = {
'service_description': 'Nova spice proxy',
'service_name': nova_cc,
'user_name': nova_user,
'start_dir': start_dir,
'process_name': 'nova-spicehtml5proxy',
2015-05-12 15:17:42 +00:00
'executable_name': os.path.join(bin_dir, 'nova-spicehtml5proxy'),
2015-04-15 14:17:56 +00:00
'config_files': [nova_conf],
}
nova_xvpvncproxy_context = {
'service_description': 'Nova XVPVNC proxy',
'service_name': nova_cc,
'user_name': nova_user,
'start_dir': start_dir,
'process_name': 'nova-xvpvncproxy',
2015-05-12 15:17:42 +00:00
'executable_name': os.path.join(bin_dir, 'nova-xvpvncproxy'),
2015-04-15 14:17:56 +00:00
'config_files': [nova_conf],
}
# NOTE(coreycb): Needs systemd support
templates_dir = 'hooks/charmhelpers/contrib/openstack/templates'
templates_dir = os.path.join(charm_dir(), templates_dir)
os_rel = os_release('nova-common')
2015-04-15 14:17:56 +00:00
render('git.upstart', '/etc/init/nova-api-ec2.conf',
nova_ec2_api_context, perms=0o644,
templates_dir=templates_dir)
render('git.upstart', '/etc/init/nova-api-os-compute.conf',
nova_api_os_compute_context, perms=0o644,
templates_dir=templates_dir)
render('git.upstart', '/etc/init/nova-cells.conf',
nova_cells_context, perms=0o644,
templates_dir=templates_dir)
render('git.upstart', '/etc/init/nova-cert.conf',
nova_cert_context, perms=0o644,
templates_dir=templates_dir)
render('git.upstart', '/etc/init/nova-conductor.conf',
nova_conductor_context, perms=0o644,
templates_dir=templates_dir)
render('git.upstart', '/etc/init/nova-consoleauth.conf',
nova_consoleauth_context, perms=0o644,
templates_dir=templates_dir)
render('git.upstart', '/etc/init/nova-console.conf',
nova_console_context, perms=0o644,
templates_dir=templates_dir)
render('git.upstart', '/etc/init/nova-novncproxy.conf',
nova_novncproxy_context, perms=0o644,
templates_dir=templates_dir)
render('git.upstart', '/etc/init/nova-objectstore.conf',
nova_objectstore_context, perms=0o644,
templates_dir=templates_dir)
render('git.upstart', '/etc/init/nova-scheduler.conf',
nova_scheduler_context, perms=0o644,
templates_dir=templates_dir)
2015-04-22 19:59:45 +00:00
if os_rel >= 'juno':
render('git.upstart', '/etc/init/nova-serialproxy.conf',
nova_serialproxy_context, perms=0o644,
templates_dir=templates_dir)
2015-04-15 14:17:56 +00:00
render('git.upstart', '/etc/init/nova-spiceproxy.conf',
nova_spiceproxy_context, perms=0o644,
templates_dir=templates_dir)
render('git.upstart', '/etc/init/nova-xvpvncproxy.conf',
nova_xvpvncproxy_context, perms=0o644,
templates_dir=templates_dir)
apt_update()
apt_install(LATE_GIT_PACKAGES, fatal=True)
2015-10-07 09:32:28 +00:00
def check_optional_relations(configs):
required_interfaces = {}
if relation_ids('ha'):
required_interfaces['ha'] = ['cluster']
try:
get_hacluster_config()
except:
return ('blocked',
'hacluster missing configuration: '
'vip, vip_iface, vip_cidr')
if relation_ids('quantum-network-service'):
required_interfaces['quantum'] = ['quantum-network-service']
if relation_ids('cinder-volume-service'):
required_interfaces['cinder'] = ['cinder-volume-service']
if relation_ids('neutron-api'):
required_interfaces['neutron-api'] = ['neutron-api']
if required_interfaces:
set_os_workload_status(configs, required_interfaces)
return status_get()
else:
return 'unknown', 'No optional relations'
def is_api_ready(configs):
return (not incomplete_relation_data(configs, REQUIRED_INTERFACES))