rebase on trunk
This commit is contained in:
commit
b49ab82a19
11
config.yaml
11
config.yaml
|
@ -26,6 +26,12 @@ options:
|
|||
default: openstack
|
||||
type: string
|
||||
decsription: Rabbitmq vhost
|
||||
use-syslog:
|
||||
type: boolean
|
||||
default: False
|
||||
description: |
|
||||
By default, all services will log into their corresponding log files.
|
||||
Setting this to True will force all services to log to the syslog.
|
||||
database-user:
|
||||
default: nova
|
||||
type: string
|
||||
|
@ -50,6 +56,11 @@ options:
|
|||
default: "yes"
|
||||
type: string
|
||||
description: Whether to run nova-api and nova-network on the compute nodes.
|
||||
enable-resize:
|
||||
default: False
|
||||
type: boolean
|
||||
description: Enable instance resizing, which requires that passwordless SSH
|
||||
access be setup between compute hosts.
|
||||
enable-live-migration:
|
||||
default: False
|
||||
type: boolean
|
||||
|
|
|
@ -26,9 +26,11 @@ from charmhelpers.core.hookenv import (
|
|||
)
|
||||
|
||||
from charmhelpers.contrib.hahelpers.cluster import (
|
||||
determine_apache_port,
|
||||
determine_api_port,
|
||||
determine_haproxy_port,
|
||||
https,
|
||||
is_clustered,
|
||||
peer_units,
|
||||
)
|
||||
|
||||
from charmhelpers.contrib.hahelpers.apache import (
|
||||
|
@ -216,12 +218,7 @@ class AMQPContext(OSContextGenerator):
|
|||
# Sufficient information found = break out!
|
||||
break
|
||||
# Used for active/active rabbitmq >= grizzly
|
||||
if ('clustered' not in ctxt or relation_get('ha-vip-only') == 'True') and \
|
||||
len(related_units(rid)) > 1:
|
||||
if relation_get('ha_queues'):
|
||||
ctxt['rabbitmq_ha_queues'] = relation_get('ha_queues')
|
||||
else:
|
||||
ctxt['rabbitmq_ha_queues'] = False
|
||||
if 'clustered' not in ctxt and len(related_units(rid)) > 1:
|
||||
rabbitmq_hosts = []
|
||||
for unit in related_units(rid):
|
||||
rabbitmq_hosts.append(relation_get('private-address',
|
||||
|
@ -250,13 +247,11 @@ class CephContext(OSContextGenerator):
|
|||
unit=unit))
|
||||
auth = relation_get('auth', rid=rid, unit=unit)
|
||||
key = relation_get('key', rid=rid, unit=unit)
|
||||
use_syslog = str(config('use-syslog')).lower()
|
||||
|
||||
ctxt = {
|
||||
'mon_hosts': ' '.join(mon_hosts),
|
||||
'auth': auth,
|
||||
'key': key,
|
||||
'use_syslog': use_syslog
|
||||
}
|
||||
|
||||
if not os.path.isdir('/etc/ceph'):
|
||||
|
@ -385,9 +380,11 @@ class ApacheSSLContext(OSContextGenerator):
|
|||
'private_address': unit_get('private-address'),
|
||||
'endpoints': []
|
||||
}
|
||||
for api_port in self.external_ports:
|
||||
ext_port = determine_apache_port(api_port)
|
||||
int_port = determine_api_port(api_port)
|
||||
for ext_port in self.external_ports:
|
||||
if peer_units() or is_clustered():
|
||||
int_port = determine_haproxy_port(ext_port)
|
||||
else:
|
||||
int_port = determine_api_port(ext_port)
|
||||
portmap = (int(ext_port), int(int_port))
|
||||
ctxt['endpoints'].append(portmap)
|
||||
return ctxt
|
||||
|
@ -589,7 +586,6 @@ class SubordinateConfigContext(OSContextGenerator):
|
|||
|
||||
|
||||
class SyslogContext(OSContextGenerator):
|
||||
|
||||
def __call__(self):
|
||||
ctxt = {
|
||||
'use_syslog': config('use-syslog')
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
nova_compute_hooks.py
|
|
@ -0,0 +1 @@
|
|||
nova_compute_hooks.py
|
|
@ -48,7 +48,8 @@ from nova_compute_utils import (
|
|||
register_configs,
|
||||
NOVA_CONF,
|
||||
QUANTUM_CONF, NEUTRON_CONF,
|
||||
ceph_config_file, CEPH_SECRET
|
||||
ceph_config_file, CEPH_SECRET,
|
||||
enable_shell, disable_shell
|
||||
)
|
||||
|
||||
from nova_compute_context import CEPH_SECRET_UUID
|
||||
|
@ -75,7 +76,14 @@ def config_changed():
|
|||
# Check-in with nova-c-c and register new ssh key, if it has just been
|
||||
# generated.
|
||||
initialize_ssh_keys()
|
||||
[compute_joined(rid) for rid in relation_ids('cloud-compute')]
|
||||
|
||||
if config('enable-resize') is True:
|
||||
enable_shell(user='nova')
|
||||
initialize_ssh_keys(user='nova')
|
||||
else:
|
||||
disable_shell(user='nova')
|
||||
|
||||
[compute_joined(rid) for rid in relation_ids('cloud-compute')]
|
||||
|
||||
CONFIGS.write_all()
|
||||
|
||||
|
@ -140,15 +148,19 @@ def image_service_changed():
|
|||
|
||||
@hooks.hook('cloud-compute-relation-joined')
|
||||
def compute_joined(rid=None):
|
||||
if not migration_enabled():
|
||||
return
|
||||
auth_type = config('migration-auth-type')
|
||||
settings = {
|
||||
'migration_auth_type': auth_type
|
||||
}
|
||||
if auth_type == 'ssh':
|
||||
settings['ssh_public_key'] = public_ssh_key()
|
||||
relation_set(relation_id=rid, **settings)
|
||||
if migration_enabled():
|
||||
auth_type = config('migration-auth-type')
|
||||
settings = {
|
||||
'migration_auth_type': auth_type
|
||||
}
|
||||
if auth_type == 'ssh':
|
||||
settings['ssh_public_key'] = public_ssh_key()
|
||||
relation_set(relation_id=rid, **settings)
|
||||
if config('enable-resize'):
|
||||
settings = {
|
||||
'nova_ssh_public_key': public_ssh_key(user='nova')
|
||||
}
|
||||
relation_set(relation_id=rid, **settings)
|
||||
|
||||
|
||||
@hooks.hook('cloud-compute-relation-changed')
|
||||
|
@ -158,6 +170,7 @@ def compute_changed():
|
|||
# config advertised from controller.
|
||||
CONFIGS.write_all()
|
||||
import_authorized_keys()
|
||||
import_authorized_keys(user='nova', prefix='nova')
|
||||
import_keystone_ca_cert()
|
||||
if (network_manager() in ['quantum', 'neutron']
|
||||
and neutron_plugin() == 'ovs'):
|
||||
|
@ -209,6 +222,12 @@ def upgrade_charm():
|
|||
amqp_joined(relation_id=r_id)
|
||||
|
||||
|
||||
@hooks.hook('nova-ceilometer-relation-changed')
|
||||
@restart_on_change(restart_map())
|
||||
def nova_ceilometer_relation_changed():
|
||||
CONFIGS.write_all()
|
||||
|
||||
|
||||
def main():
|
||||
try:
|
||||
hooks.execute(sys.argv)
|
||||
|
|
|
@ -69,7 +69,13 @@ BASE_RESOURCE_MAP = {
|
|||
context.OSConfigFlagContext(),
|
||||
CloudComputeContext(),
|
||||
NovaComputeLibvirtContext(),
|
||||
NovaComputeCephContext()],
|
||||
NovaComputeCephContext(),
|
||||
context.SyslogContext(),
|
||||
context.SubordinateConfigContext(
|
||||
interface='nova-ceilometer',
|
||||
service='nova',
|
||||
config_file=NOVA_CONF,
|
||||
)],
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -89,7 +95,9 @@ QUANTUM_CONF = '/etc/quantum/quantum.conf'
|
|||
QUANTUM_RESOURCES = {
|
||||
QUANTUM_CONF: {
|
||||
'services': [],
|
||||
'contexts': [context.AMQPContext(), NeutronComputeContext()],
|
||||
'contexts': [context.AMQPContext(),
|
||||
NeutronComputeContext(),
|
||||
context.SyslogContext()],
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -98,7 +106,9 @@ NEUTRON_CONF = '/etc/neutron/neutron.conf'
|
|||
NEUTRON_RESOURCES = {
|
||||
NEUTRON_CONF: {
|
||||
'services': [],
|
||||
'contexts': [context.AMQPContext(), NeutronComputeContext()],
|
||||
'contexts': [context.AMQPContext(),
|
||||
NeutronComputeContext(),
|
||||
context.SyslogContext()],
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -310,13 +320,18 @@ def initialize_ssh_keys(user='root'):
|
|||
check_output(['chown', '-R', user, ssh_dir])
|
||||
|
||||
|
||||
def import_authorized_keys(user='root'):
|
||||
def import_authorized_keys(user='root', prefix=None):
|
||||
"""Import SSH authorized_keys + known_hosts from a cloud-compute relation
|
||||
and store in user's $HOME/.ssh.
|
||||
"""
|
||||
# XXX: Should this be managed via templates + contexts?
|
||||
hosts = relation_get('known_hosts')
|
||||
auth_keys = relation_get('authorized_keys')
|
||||
if prefix:
|
||||
hosts = relation_get('{}_known_hosts'.format(prefix))
|
||||
auth_keys = relation_get('{}_authorized_keys'.format(prefix))
|
||||
else:
|
||||
# XXX: Should this be managed via templates + contexts?
|
||||
hosts = relation_get('known_hosts')
|
||||
auth_keys = relation_get('authorized_keys')
|
||||
|
||||
# XXX: Need to fix charm-helpers to return None for empty settings,
|
||||
# in all cases.
|
||||
if not hosts or not auth_keys:
|
||||
|
@ -331,25 +346,6 @@ def import_authorized_keys(user='root'):
|
|||
_hosts.write(b64decode(hosts))
|
||||
|
||||
|
||||
def configure_live_migration(configs=None):
|
||||
"""
|
||||
Ensure libvirt live migration is properly configured or disabled,
|
||||
depending on current config setting.
|
||||
"""
|
||||
# dont think we need this
|
||||
return
|
||||
configs = configs or register_configs()
|
||||
configs.write(LIBVIRTD_CONF)
|
||||
configs.write(LIBVIRT_BIN)
|
||||
configs.write(NOVA_CONF)
|
||||
|
||||
if not migration_enabled():
|
||||
return
|
||||
|
||||
if config('migration-auth-type') == 'ssh':
|
||||
initialize_ssh_keys()
|
||||
|
||||
|
||||
def do_openstack_upgrade(configs):
|
||||
new_src = config('openstack-origin')
|
||||
new_os_rel = get_os_codename_install_source(new_src)
|
||||
|
@ -394,3 +390,13 @@ def create_libvirt_secret(secret_file, secret_uuid, key):
|
|||
cmd = ['virsh', 'secret-set-value', '--secret', secret_uuid,
|
||||
'--base64', key]
|
||||
check_call(cmd)
|
||||
|
||||
|
||||
def enable_shell(user):
|
||||
cmd = ['usermod', '-s', '/bin/bash', user]
|
||||
check_call(cmd)
|
||||
|
||||
|
||||
def disable_shell(user):
|
||||
cmd = ['usermod', '-s', '/bin/false', user]
|
||||
check_call(cmd)
|
||||
|
|
|
@ -6,7 +6,7 @@ description: |
|
|||
addition to its "native" API (the OpenStack API), it also supports the Amazon
|
||||
EC2 API.
|
||||
categories:
|
||||
- openstack
|
||||
- openstack
|
||||
provides:
|
||||
cloud-compute:
|
||||
interface: nova-compute
|
||||
|
@ -22,6 +22,9 @@ requires:
|
|||
nrpe-external-master:
|
||||
interface: nrpe-external-master
|
||||
scope: container
|
||||
nova-ceilometer:
|
||||
interface: nova-ceilometer
|
||||
scope: container
|
||||
peers:
|
||||
compute-peer:
|
||||
interface: nova
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
--connection_type=libvirt
|
||||
--root_helper=sudo nova-rootwrap
|
||||
--verbose
|
||||
--use_syslog={{ use_syslog }}
|
||||
--ec2_private_dns_show_ip
|
||||
{% if database_host -%}
|
||||
--sql_connection=mysql://{{ database_user }}:{{ database_password }}@{{ database_host }}/{{ database }}
|
||||
|
|
|
@ -18,6 +18,7 @@ libvirt_use_virtio_for_bridges=True
|
|||
connection_type=libvirt
|
||||
root_helper=sudo nova-rootwrap /etc/nova/rootwrap.conf
|
||||
verbose=True
|
||||
use_syslog = {{ use_syslog }}
|
||||
ec2_private_dns_show_ip=True
|
||||
api_paste_config=/etc/nova/api-paste.ini
|
||||
volumes_path=/var/lib/nova/volumes
|
||||
|
|
|
@ -3,6 +3,9 @@
|
|||
# [ WARNING ]
|
||||
# Configuration file maintained by Juju. Local changes may be overwritten.
|
||||
###############################################################################
|
||||
[DEFAULT]
|
||||
use_syslog = {{ use_syslog }}
|
||||
|
||||
[OVS]
|
||||
tunnel_id_ranges = 1:1000
|
||||
tenant_network_type = gre
|
||||
|
|
|
@ -11,6 +11,7 @@ bind_port = 9696
|
|||
{% if core_plugin -%}
|
||||
core_plugin = {{ core_plugin }}
|
||||
{% endif -%}
|
||||
use_syslog = {{ use_syslog }}
|
||||
api_paste_config = /etc/quantum/api-paste.ini
|
||||
auth_strategy = keystone
|
||||
notification_driver = quantum.openstack.common.notifier.rpc_notifier
|
||||
|
|
|
@ -18,6 +18,7 @@ libvirt_use_virtio_for_bridges=True
|
|||
connection_type=libvirt
|
||||
root_helper=sudo nova-rootwrap /etc/nova/rootwrap.conf
|
||||
verbose=True
|
||||
use_syslog = {{ use_syslog }}
|
||||
ec2_private_dns_show_ip=True
|
||||
api_paste_config=/etc/nova/api-paste.ini
|
||||
volumes_path=/var/lib/nova/volumes
|
||||
|
|
|
@ -16,6 +16,7 @@ core_plugin = {{ core_plugin }}
|
|||
api_paste_config = /etc/neutron/api-paste.ini
|
||||
auth_strategy = keystone
|
||||
notification_driver = neutron.openstack.common.notifier.rpc_notifier
|
||||
use_syslog = {{ use_syslog }}
|
||||
default_notification_level = INFO
|
||||
notification_topics = notifications
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@ libvirt_use_virtio_for_bridges=True
|
|||
connection_type=libvirt
|
||||
root_helper=sudo nova-rootwrap /etc/nova/rootwrap.conf
|
||||
verbose=True
|
||||
use_syslog = {{ use_syslog }}
|
||||
ec2_private_dns_show_ip=True
|
||||
api_paste_config=/etc/nova/api-paste.ini
|
||||
volumes_path=/var/lib/nova/volumes
|
||||
|
@ -84,3 +85,9 @@ volume_api_class = nova.volume.cinder.API
|
|||
{% if live_migration_uri -%}
|
||||
live_migration_uri = {{ live_migration_uri }}
|
||||
{% endif -%}
|
||||
|
||||
{% if sections and 'DEFAULT' in sections -%}
|
||||
{% for key, value in sections['DEFAULT'] -%}
|
||||
{{ key }} = {{ value }}
|
||||
{% endfor -%}
|
||||
{% endif -%}
|
||||
|
|
|
@ -48,6 +48,8 @@ TO_PATCH = [
|
|||
'neutron_plugin',
|
||||
'public_ssh_key',
|
||||
'register_configs',
|
||||
'disable_shell',
|
||||
'enable_shell',
|
||||
# misc_utils
|
||||
'ensure_ceph_keyring',
|
||||
'execd_preinstall'
|
||||
|
@ -95,6 +97,38 @@ class NovaComputeRelationsTests(CharmTestCase):
|
|||
call('cloud-compute:1'),
|
||||
]
|
||||
self.assertEquals(ex, compute_joined.call_args_list)
|
||||
self.assertTrue(self.initialize_ssh_keys.called)
|
||||
|
||||
@patch.object(hooks, 'compute_joined')
|
||||
def test_config_changed_with_resize(self, compute_joined):
|
||||
self.test_config.set('enable-resize', True)
|
||||
self.relation_ids.return_value = [
|
||||
'cloud-compute:0',
|
||||
'cloud-compute:1'
|
||||
]
|
||||
hooks.config_changed()
|
||||
ex = [
|
||||
call('cloud-compute:0'),
|
||||
call('cloud-compute:1'),
|
||||
]
|
||||
self.assertEquals(ex, compute_joined.call_args_list)
|
||||
self.initialize_ssh_keys.assert_called_with(user='nova')
|
||||
self.enable_shell.assert_called_with(user='nova')
|
||||
|
||||
@patch.object(hooks, 'compute_joined')
|
||||
def test_config_changed_without_resize(self, compute_joined):
|
||||
self.test_config.set('enable-resize', False)
|
||||
self.relation_ids.return_value = [
|
||||
'cloud-compute:0',
|
||||
'cloud-compute:1'
|
||||
]
|
||||
hooks.config_changed()
|
||||
ex = [
|
||||
call('cloud-compute:0'),
|
||||
call('cloud-compute:1'),
|
||||
]
|
||||
self.assertEquals(ex, compute_joined.call_args_list)
|
||||
self.disable_shell.assert_called_with(user='nova')
|
||||
|
||||
@patch.object(hooks, 'compute_joined')
|
||||
def test_config_changed_no_upgrade_no_migration(self, compute_joined):
|
||||
|
@ -239,7 +273,7 @@ class NovaComputeRelationsTests(CharmTestCase):
|
|||
hooks.image_service_changed()
|
||||
configs.write.assert_called_with('/etc/nova/nova.conf')
|
||||
|
||||
def test_compute_joined_no_migration(self):
|
||||
def test_compute_joined_no_migration_no_resize(self):
|
||||
self.migration_enabled.return_value = False
|
||||
hooks.compute_joined()
|
||||
self.assertFalse(self.relation_set.called)
|
||||
|
@ -261,14 +295,27 @@ class NovaComputeRelationsTests(CharmTestCase):
|
|||
migration_auth_type='ssh'
|
||||
)
|
||||
|
||||
def test_compute_joined_with_resize(self):
|
||||
self.test_config.set('enable-resize', True)
|
||||
self.public_ssh_key.return_value = 'bar'
|
||||
hooks.compute_joined()
|
||||
self.relation_set.assert_called_with(
|
||||
relation_id=None,
|
||||
nova_ssh_public_key='bar'
|
||||
)
|
||||
hooks.compute_joined(rid='cloud-compute:2')
|
||||
self.relation_set.assert_called_with(
|
||||
relation_id='cloud-compute:2',
|
||||
nova_ssh_public_key='bar'
|
||||
)
|
||||
|
||||
def test_compute_changed(self):
|
||||
hooks.compute_changed()
|
||||
expected_funcs = [
|
||||
self.import_authorized_keys,
|
||||
self.import_keystone_ca_cert,
|
||||
]
|
||||
for func in expected_funcs:
|
||||
self.assertTrue(func.called)
|
||||
self.assertTrue(self.import_keystone_ca_cert.called)
|
||||
self.import_authorized_keys.assert_has_calls([
|
||||
call(),
|
||||
call(user='nova', prefix='nova'),
|
||||
])
|
||||
|
||||
def test_ceph_joined(self):
|
||||
hooks.ceph_joined()
|
||||
|
|
|
@ -179,7 +179,7 @@ class NovaComputeUtilsTests(CharmTestCase):
|
|||
self.assertFalse(_open.called)
|
||||
|
||||
@patch('pwd.getpwnam')
|
||||
def test_import_authorized_keys(self, getpwnam):
|
||||
def _test_import_authorized_keys_base(self, getpwnam, prefix=None):
|
||||
getpwnam.return_value = self.fake_user('foo')
|
||||
self.relation_get.side_effect = [
|
||||
'Zm9vX2tleQo=', # relation_get('known_hosts')
|
||||
|
@ -200,6 +200,38 @@ class NovaComputeUtilsTests(CharmTestCase):
|
|||
self.assertEquals(ex_open, _open.call_args_list)
|
||||
self.assertEquals(ex_write, _file.write.call_args_list)
|
||||
|
||||
self.relation_get.assert_has_called([
|
||||
call('known_hosts').
|
||||
call('authorized_keys')
|
||||
])
|
||||
|
||||
@patch('pwd.getpwnam')
|
||||
def test_import_authorized_keys_prefix(self, getpwnam):
|
||||
getpwnam.return_value = self.fake_user('foo')
|
||||
self.relation_get.side_effect = [
|
||||
'Zm9vX2tleQo=', # relation_get('known_hosts')
|
||||
'Zm9vX2hvc3QK', # relation_get('authorized_keys')
|
||||
]
|
||||
|
||||
ex_open = [
|
||||
call('/home/foo/.ssh/authorized_keys', 'wb'),
|
||||
call('/home/foo/.ssh/known_hosts', 'wb')
|
||||
]
|
||||
ex_write = [
|
||||
call('foo_host\n'),
|
||||
call('foo_key\n'),
|
||||
]
|
||||
|
||||
with patch_open() as (_open, _file):
|
||||
utils.import_authorized_keys(user='foo', prefix='bar')
|
||||
self.assertEquals(ex_open, _open.call_args_list)
|
||||
self.assertEquals(ex_write, _file.write.call_args_list)
|
||||
|
||||
self.relation_get.assert_has_called([
|
||||
call('bar_known_hosts').
|
||||
call('bar_authorized_keys')
|
||||
])
|
||||
|
||||
@patch('subprocess.check_call')
|
||||
def test_import_keystone_cert_missing_data(self, check_call):
|
||||
self.relation_get.return_value = None
|
||||
|
@ -247,3 +279,14 @@ class NovaComputeUtilsTests(CharmTestCase):
|
|||
call('/etc/nova/nova.conf', [ctxt1])
|
||||
]
|
||||
self.assertEquals(fake_renderer.register.call_args_list, ex_reg)
|
||||
|
||||
@patch.object(utils, 'check_call')
|
||||
def test_enable_shell(self, _check_call):
|
||||
utils.enable_shell('dummy')
|
||||
_check_call.assert_called_with(['usermod', '-s', '/bin/bash', 'dummy'])
|
||||
|
||||
@patch.object(utils, 'check_call')
|
||||
def test_disable_shell(self, _check_call):
|
||||
utils.disable_shell('dummy')
|
||||
_check_call.assert_called_with(['usermod', '-s', '/bin/false',
|
||||
'dummy'])
|
||||
|
|
Loading…
Reference in New Issue