264 lines
8.4 KiB
Python
264 lines
8.4 KiB
Python
from charmhelpers.contrib.openstack import context
|
|
|
|
from charmhelpers.core.host import apt_install, filter_installed_packages
|
|
|
|
from charmhelpers.core.hookenv import (
|
|
config,
|
|
log,
|
|
relation_get,
|
|
relation_ids,
|
|
service_name,
|
|
unit_private_ip,
|
|
ERROR,
|
|
WARNING,
|
|
)
|
|
|
|
from charmhelpers.contrib.openstack.utils import get_os_codename_package
|
|
|
|
|
|
# This is just a label and it must be consistent across
|
|
# nova-compute nodes to support live migration.
|
|
CEPH_SECRET_UUID = '514c9fca-8cbe-11e2-9c52-3bc8c7819472'
|
|
|
|
|
|
def _save_flag_file(path, data):
|
|
'''
|
|
Saves local state about plugin or manager to specified file.
|
|
'''
|
|
# Wonder if we can move away from this now?
|
|
with open(path, 'wb') as out:
|
|
out.write(data)
|
|
|
|
|
|
class NovaComputeLibvirtContext(context.OSContextGenerator):
|
|
'''
|
|
Determines various libvirt options depending on live migration
|
|
configuration.
|
|
'''
|
|
interfaces = []
|
|
|
|
def __call__(self):
|
|
# distro defaults
|
|
ctxt = {
|
|
# /etc/default/libvirt-bin
|
|
'libvirtd_opts': '-d',
|
|
# /etc/libvirt/libvirtd.conf (
|
|
'listen_tls': 1,
|
|
}
|
|
|
|
# enable tcp listening if configured for live migration.
|
|
if config('enable-live-migration'):
|
|
ctxt['libvirtd_opts'] += ' -l'
|
|
|
|
if config('migration-auth-type') in ['none', 'None', 'ssh']:
|
|
ctxt['listen_tls'] = 0
|
|
|
|
return ctxt
|
|
|
|
|
|
class NovaComputeVirtContext(context.OSContextGenerator):
|
|
interfaces = []
|
|
|
|
def __call__(self):
|
|
return {}
|
|
|
|
|
|
class NovaComputeCephContext(context.CephContext):
|
|
def __call__(self):
|
|
ctxt = super(NovaComputeCephContext, self).__call__()
|
|
if not ctxt:
|
|
return {}
|
|
svc = service_name()
|
|
# secret.xml
|
|
ctxt['ceph_secret_uuid'] = CEPH_SECRET_UUID
|
|
# nova.conf
|
|
ctxt['service_name'] = svc
|
|
ctxt['rbd_user'] = svc
|
|
ctxt['rbd_secret_uuid'] = CEPH_SECRET_UUID
|
|
ctxt['rbd_pool'] = 'nova'
|
|
return ctxt
|
|
|
|
|
|
class CloudComputeContext(context.OSContextGenerator):
|
|
'''
|
|
Generates main context for writing nova.conf and quantum.conf templates
|
|
from a cloud-compute relation changed hook. Mainly used for determinig
|
|
correct network and volume service configuration on the compute node,
|
|
as advertised by the cloud-controller.
|
|
|
|
Note: individual quantum plugin contexts are handled elsewhere.
|
|
'''
|
|
interfaces = ['cloud-compute']
|
|
|
|
def _ensure_packages(self, packages):
|
|
'''Install but do not upgrade required packages'''
|
|
required = filter_installed_packages(packages)
|
|
if required:
|
|
apt_install(required)
|
|
|
|
def flat_dhcp_context(self):
|
|
ec2_host = relation_get('ec2_host')
|
|
if not ec2_host:
|
|
return {}
|
|
|
|
if config('multi-host').lower() == 'yes':
|
|
self._ensure_packages(['nova-api', 'nova-network'])
|
|
|
|
return {
|
|
'network_manager': 'nova.network.manager.FlatDHCPManager',
|
|
'flat_interface': config('flat-interface'),
|
|
'ec2_dmz_host': ec2_host,
|
|
}
|
|
|
|
def quantum_context(self):
|
|
quantum_ctxt = {
|
|
'quantum_auth_strategy': 'keystone',
|
|
'keystone_host': relation_get('keystone_host'),
|
|
'auth_port': relation_get('auth_port'),
|
|
'quantum_url': relation_get('quantum_url'),
|
|
'quantum_admin_tenant_name': relation_get('service_tenant'),
|
|
'quantum_admin_username': relation_get('service_username'),
|
|
'quantum_admin_password': relation_get('service_password'),
|
|
'quantum_security_groups': relation_get('quantum_security_groups'),
|
|
'quantum_plugin': relation_get('quantum_plugin'),
|
|
}
|
|
missing = [k for k, v in quantum_ctxt.iteritems() if v is None]
|
|
if missing:
|
|
log('Missing required relation settings for Quantum: ' +
|
|
' '.join(missing))
|
|
return {}
|
|
|
|
ks_url = 'http://%s:%s/v2.0' % (quantum_ctxt['keystone_host'],
|
|
quantum_ctxt['auth_port'])
|
|
quantum_ctxt['quantum_admin_auth_url'] = ks_url
|
|
quantum_ctxt['network_api_class'] = 'nova.network.quantumv2.api.API'
|
|
return quantum_ctxt
|
|
|
|
def volume_context(self):
|
|
vol_service = relation_get('volume_service')
|
|
if not vol_service:
|
|
return {}
|
|
vol_ctxt = {}
|
|
if vol_service == 'cinder':
|
|
vol_ctxt['volume_api_class'] = 'nova.volume.cinder.API'
|
|
elif vol_service == 'nova-volume':
|
|
if get_os_codename_package('nova-common') in ['essex', 'folsom']:
|
|
vol_ctxt['volume_api_class'] = 'nova.volume.api.API'
|
|
else:
|
|
log('Invalid volume service received via cloud-compute: %s' %
|
|
vol_service, level=ERROR)
|
|
raise
|
|
return vol_ctxt
|
|
|
|
def __call__(self):
|
|
rids = relation_ids('cloud-compute')
|
|
if not rids:
|
|
return {}
|
|
|
|
ctxt = {}
|
|
|
|
net_manager = relation_get('network_manager')
|
|
if net_manager:
|
|
if net_manager.lower() == 'flatdhcpmanager':
|
|
ctxt.update({
|
|
'network_manager_config': self.flat_dhcp_context()
|
|
})
|
|
elif net_manager.lower() == 'quantum':
|
|
ctxt.update({
|
|
'network_manager_config': self.quantum_context()
|
|
})
|
|
_save_flag_file(path='/etc/nova/nm.conf', data=net_manager)
|
|
|
|
vol_service = self.volume_context()
|
|
if vol_service:
|
|
ctxt.update({'volume_service_config': vol_service})
|
|
|
|
return ctxt
|
|
|
|
|
|
class OSConfigFlagContext(context.OSContextGenerator):
|
|
'''
|
|
Responsible adding user-defined config-flags in charm config to a
|
|
to a template context.
|
|
'''
|
|
# this can be moved to charm-helpers?
|
|
def __call__(self):
|
|
config_flags = config('config-flags')
|
|
if not config_flags:
|
|
return {}
|
|
config_flags = config_flags.split(',')
|
|
flags = {}
|
|
for flag in config_flags:
|
|
if '=' not in flag:
|
|
log('Impoperly formatted config-flag, expected k=v '
|
|
' got %s' % flag, level=WARNING)
|
|
continue
|
|
k, v = flag.split('=')
|
|
flags[k.strip()] = v
|
|
ctxt = {'user_config_flags': flags}
|
|
return ctxt
|
|
|
|
|
|
class QuantumPluginContext(context.OSContextGenerator):
|
|
interfaces = []
|
|
|
|
def _ensure_packages(self, packages):
|
|
'''Install but do not upgrade required plugin packages'''
|
|
required = filter_installed_packages(packages)
|
|
if required:
|
|
apt_install(required)
|
|
|
|
def ovs_context(self):
|
|
q_driver = 'quantum.plugins.openvswitch.ovs_quantum_plugin.'\
|
|
'OVSQuantumPluginV2'
|
|
q_fw_driver = 'quantum.agent.linux.iptables_firewall.'\
|
|
'OVSHybridIptablesFirewallDriver'
|
|
|
|
if get_os_codename_package('nova-common') in ['essex', 'folsom']:
|
|
n_driver = 'nova.virt.libvirt.vif.LibvirtHybridOVSBridgeDriver'
|
|
else:
|
|
n_driver = 'nova.virt.libvirt.vif.LibvirtGenericVIFDriver'
|
|
n_fw_driver = 'nova.virt.firewall.NoopFirewallDriver'
|
|
|
|
ovs_ctxt = {
|
|
'quantum_plugin': 'ovs',
|
|
# quantum.conf
|
|
'core_plugin': q_driver,
|
|
# nova.conf
|
|
'libvirt_vif_driver': n_driver,
|
|
'libvirt_use_virtio_for_bridges': True,
|
|
# ovs config
|
|
'tenant_network_type': 'gre',
|
|
'enable_tunneling': True,
|
|
'tunnel_id_ranges': '1:1000',
|
|
'local_ip': unit_private_ip(),
|
|
}
|
|
|
|
q_sec_groups = relation_get('quantum_security_groups')
|
|
if q_sec_groups and q_sec_groups.lower() == 'yes':
|
|
ovs_ctxt['quantum_security_groups'] = True
|
|
# nova.conf
|
|
ovs_ctxt['nova_firewall_driver'] = n_fw_driver
|
|
# ovs conf
|
|
ovs_ctxt['ovs_firewall_driver'] = q_fw_driver
|
|
|
|
return ovs_ctxt
|
|
|
|
def __call__(self):
|
|
from nova_compute_utils import quantum_attribute
|
|
|
|
plugin = relation_get('quantum_plugin')
|
|
if not plugin:
|
|
return {}
|
|
|
|
self._ensure_packages(quantum_attribute(plugin, 'packages'))
|
|
|
|
ctxt = {}
|
|
|
|
if plugin == 'ovs':
|
|
ctxt.update(self.ovs_context())
|
|
|
|
_save_flag_file(path='/etc/nova/quantum_plugin.conf', data=plugin)
|
|
|
|
return ctxt
|