charm-nova-compute/hooks/nova_compute_context.py

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