335 lines
9.8 KiB
Python
Raw Normal View History

2013-01-18 08:51:11 +00:00
import os
import uuid
import socket
from charmhelpers.core.hookenv import (
log,
config,
unit_get,
cached
)
from charmhelpers.core.host import (
apt_install,
apt_update
)
from charmhelpers.contrib.network.ovs import (
add_bridge,
add_bridge_port
)
from charmhelpers.contrib.openstack.utils import (
configure_installation_source,
get_os_codename_package,
get_os_codename_install_source
)
import charmhelpers.contrib.openstack.context as context
import charmhelpers.contrib.openstack.templating as templating
import quantum_contexts
from collections import OrderedDict
OVS = "ovs"
2013-06-26 17:02:28 +01:00
NVP = "nvp"
2012-10-26 17:56:42 +02:00
OVS_PLUGIN = \
"quantum.plugins.openvswitch.ovs_quantum_plugin.OVSQuantumPluginV2"
2013-06-26 17:02:28 +01:00
NVP_PLUGIN = \
"quantum.plugins.nicira.nicira_nvp_plugin.QuantumPlugin.NvpPluginV2"
2012-10-26 17:56:42 +02:00
CORE_PLUGIN = {
OVS: OVS_PLUGIN,
2013-06-26 17:02:28 +01:00
NVP: NVP_PLUGIN
}
2012-10-26 17:56:42 +02:00
def valid_plugin():
return config('plugin') in CORE_PLUGIN
2012-10-26 17:56:42 +02:00
OVS_PLUGIN_CONF = \
"/etc/quantum/plugins/openvswitch/ovs_quantum_plugin.ini"
2013-06-26 17:02:28 +01:00
NVP_PLUGIN_CONF = \
"/etc/quantum/plugins/nicira/nvp.ini"
2012-10-26 17:56:42 +02:00
PLUGIN_CONF = {
OVS: OVS_PLUGIN_CONF,
2013-06-26 17:02:28 +01:00
NVP: NVP_PLUGIN_CONF
}
2012-10-26 17:56:42 +02:00
GATEWAY_PKGS = {
OVS: [
"quantum-plugin-openvswitch-agent",
"quantum-l3-agent",
"quantum-dhcp-agent",
2013-01-18 08:51:11 +00:00
'python-mysqldb',
"nova-api-metadata"
],
2013-06-26 17:02:28 +01:00
NVP: [
2013-06-27 22:20:07 +01:00
"openvswitch-switch",
2013-06-26 17:02:28 +01:00
"quantum-dhcp-agent",
'python-mysqldb',
"nova-api-metadata"
]
}
EARLY_PACKAGES = {
OVS: ['openvswitch-datapath-dkms']
}
2013-02-08 16:20:03 +00:00
def get_early_packages():
'''Return a list of package for pre-install based on configured plugin'''
if config('plugin') in EARLY_PACKAGES:
return EARLY_PACKAGES[config('plugin')]
2013-03-20 16:08:54 +00:00
else:
return []
2013-03-20 16:08:54 +00:00
def get_packages():
'''Return a list of packages for install based on the configured plugin'''
return GATEWAY_PKGS[config('plugin')]
2013-01-18 08:51:11 +00:00
EXT_PORT_CONF = '/etc/init/ext-port.conf'
TEMPLATES = 'templates'
2012-10-26 17:56:42 +02:00
QUANTUM_CONF = "/etc/quantum/quantum.conf"
L3_AGENT_CONF = "/etc/quantum/l3_agent.ini"
2012-11-05 11:59:27 +00:00
DHCP_AGENT_CONF = "/etc/quantum/dhcp_agent.ini"
2013-01-18 08:51:11 +00:00
METADATA_AGENT_CONF = "/etc/quantum/metadata_agent.ini"
NOVA_CONF = "/etc/nova/nova.conf"
2012-10-26 17:56:42 +02:00
SHARED_CONFIG_FILES = {
DHCP_AGENT_CONF: {
'hook_contexts': [quantum_contexts.QuantumGatewayContext()],
'services': ['quantum-dhcp-agent']
},
METADATA_AGENT_CONF: {
'hook_contexts': [quantum_contexts.NetworkServiceContext()],
'services': ['quantum-metadata-agent']
},
NOVA_CONF: {
'hook_contexts': [context.AMQPContext(),
2013-07-19 11:04:17 +01:00
quantum_contexts.QuantumSharedDBContext(),
quantum_contexts.NetworkServiceContext(),
quantum_contexts.QuantumGatewayContext()],
'services': ['nova-api-metadata']
},
}
2013-04-12 15:56:50 +01:00
OVS_CONFIG_FILES = {
QUANTUM_CONF: {
'hook_contexts': [context.AMQPContext(),
quantum_contexts.QuantumGatewayContext()],
'services': ['quantum-l3-agent',
'quantum-dhcp-agent',
'quantum-metadata-agent',
'quantum-plugin-openvswitch-agent']
},
L3_AGENT_CONF: {
'hook_contexts': [quantum_contexts.NetworkServiceContext()],
'services': ['quantum-l3-agent']
},
# TODO: Check to see if this is actually required
OVS_PLUGIN_CONF: {
2013-07-19 11:04:17 +01:00
'hook_contexts': [quantum_contexts.QuantumSharedDBContext(),
quantum_contexts.QuantumGatewayContext()],
'services': ['quantum-plugin-openvswitch-agent']
},
EXT_PORT_CONF: {
'hook_contexts': [quantum_contexts.ExternalPortContext()],
'services': []
}
}
2013-07-19 10:55:29 +01:00
OVS_CONFIG_FILES.update(SHARED_CONFIG_FILES)
2013-07-01 17:35:04 +01:00
NVP_CONFIG_FILES = {
QUANTUM_CONF: {
'hook_contexts': [context.AMQPContext()],
'services': ['quantum-dhcp-agent', 'quantum-metadata-agent']
},
}
2013-07-19 10:55:29 +01:00
NVP_CONFIG_FILES.update(SHARED_CONFIG_FILES)
2013-07-01 17:35:04 +01:00
CONFIG_FILES = {
2013-07-19 10:55:29 +01:00
NVP: NVP_CONFIG_FILES,
OVS: OVS_CONFIG_FILES,
}
2013-07-01 17:35:04 +01:00
def register_configs():
''' Register config files with their respective contexts. '''
release = get_os_codename_package('quantum-common', fatal=False) or \
'essex'
configs = templating.OSConfigRenderer(templates_dir=TEMPLATES,
openstack_release=release)
plugin = config('plugin')
2013-07-19 10:50:13 +01:00
for conf in CONFIG_FILES[plugin]:
2013-07-19 10:56:34 +01:00
configs.register(conf, CONFIG_FILES[plugin][conf]['hook_contexts'])
return configs
def restart_map():
'''
Determine the correct resource map to be passed to
charmhelpers.core.restart_on_change() based on the services configured.
:returns: dict: A dictionary mapping config file to lists of services
that should be restarted when file changes.
'''
_map = []
for f, ctxt in CONFIG_FILES[config('plugin')].iteritems():
svcs = []
for svc in ctxt['services']:
svcs.append(svc)
if svcs:
_map.append((f, svcs))
return OrderedDict(_map)
DB_USER = "quantum"
QUANTUM_DB = "quantum"
KEYSTONE_SERVICE = "quantum"
NOVA_DB_USER = "nova"
NOVA_DB = "nova"
2012-11-05 11:59:27 +00:00
RABBIT_USER = "nova"
RABBIT_VHOST = "nova"
2012-10-26 17:56:42 +02:00
2012-12-03 15:16:55 +00:00
INT_BRIDGE = "br-int"
EXT_BRIDGE = "br-ex"
2013-01-18 08:51:11 +00:00
SHARED_SECRET = "/etc/quantum/secret.txt"
def get_shared_secret():
secret = None
if not os.path.exists(SHARED_SECRET):
secret = str(uuid.uuid4())
with open(SHARED_SECRET, 'w') as secret_file:
secret_file.write(secret)
else:
with open(SHARED_SECRET, 'r') as secret_file:
secret = secret_file.read().strip()
return secret
2013-02-08 16:10:48 +00:00
2013-03-20 16:08:54 +00:00
DHCP_AGENT = "DHCP Agent"
L3_AGENT = "L3 Agent"
def reassign_agent_resources():
2013-03-20 16:08:54 +00:00
''' Use agent scheduler API to detect down agents and re-schedule '''
env = quantum_contexts.NetworkServiceContext()()
if not env:
log('Unable to re-assign resources at this time')
return
try:
from quantumclient.v2_0 import client
except ImportError:
''' Try to import neutronclient instead for havana+ '''
from neutronclient.v2_0 import client
2013-03-20 16:08:54 +00:00
# TODO: Fixup for https keystone
2013-03-20 16:20:51 +00:00
auth_url = 'http://%(keystone_host)s:%(auth_port)s/v2.0' % env
2013-03-20 16:08:54 +00:00
quantum = client.Client(username=env['service_username'],
password=env['service_password'],
tenant_name=env['service_tenant'],
auth_url=auth_url,
region_name=env['region'])
agents = quantum.list_agents(agent_type=DHCP_AGENT)
dhcp_agents = []
l3_agents = []
2013-03-20 16:08:54 +00:00
networks = {}
for agent in agents['agents']:
if not agent['alive']:
log('DHCP Agent %s down' % agent['id'])
2013-03-20 16:08:54 +00:00
for network in \
quantum.list_networks_on_dhcp_agent(agent['id'])['networks']:
networks[network['id']] = agent['id']
else:
dhcp_agents.append(agent['id'])
2013-03-20 16:08:54 +00:00
agents = quantum.list_agents(agent_type=L3_AGENT)
routers = {}
for agent in agents['agents']:
if not agent['alive']:
log('L3 Agent %s down' % agent['id'])
2013-03-20 16:08:54 +00:00
for router in \
quantum.list_routers_on_l3_agent(agent['id'])['routers']:
routers[router['id']] = agent['id']
else:
l3_agents.append(agent['id'])
2013-03-20 16:08:54 +00:00
index = 0
2013-03-20 16:08:54 +00:00
for router_id in routers:
agent = index % len(l3_agents)
log('Moving router %s from %s to %s' %
(router_id, routers[router_id], l3_agents[agent]))
2013-03-20 16:08:54 +00:00
quantum.remove_router_from_l3_agent(l3_agent=routers[router_id],
router_id=router_id)
quantum.add_router_to_l3_agent(l3_agent=l3_agents[agent],
2013-03-20 16:08:54 +00:00
body={'router_id': router_id})
index += 1
2013-03-20 16:08:54 +00:00
index = 0
2013-03-20 16:08:54 +00:00
for network_id in networks:
agent = index % len(dhcp_agents)
log('Moving network %s from %s to %s' %
(network_id, networks[network_id], dhcp_agents[agent]))
2013-03-20 16:08:54 +00:00
quantum.remove_network_from_dhcp_agent(dhcp_agent=networks[network_id],
network_id=network_id)
quantum.add_network_to_dhcp_agent(dhcp_agent=dhcp_agents[agent],
2013-03-20 16:08:54 +00:00
body={'network_id': network_id})
index += 1
def do_openstack_upgrade(configs):
"""
Perform an upgrade. Takes care of upgrading packages, rewriting
configs, database migrations and potentially any other post-upgrade
actions.
:param configs: The charms main OSConfigRenderer object.
"""
new_src = config('openstack-origin')
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',
]
apt_update(fatal=True)
apt_install(packages=GATEWAY_PKGS[config('plugin')], options=dpkg_opts,
fatal=True)
# set CONFIGS to load templates from new release
configs.set_release(openstack_release=new_os_rel)
@cached
def get_host_ip(hostname=None):
try:
import dns.resolver
except ImportError:
apt_install('python-dnspython', fatal=True)
import dns.resolver
hostname = hostname or unit_get('private-address')
try:
# Test to see if already an IPv4 address
socket.inet_aton(hostname)
return hostname
except socket.error:
answers = dns.resolver.query(hostname, 'A')
if answers:
return answers[0].address
def configure_ovs():
if config('plugin') == OVS:
add_bridge(INT_BRIDGE)
add_bridge(EXT_BRIDGE)
ext_port = config('ext-port')
if ext_port:
add_bridge_port(EXT_BRIDGE, ext_port)
if config('plugin') == NVP:
add_bridge(INT_BRIDGE)