Refactoring to include external network setup as part of charm

This commit is contained in:
James Page 2012-11-07 12:11:38 +00:00
parent 75baba6431
commit d5a60ecd53
6 changed files with 268 additions and 78 deletions

View File

@ -8,12 +8,53 @@ options:
nodes. Supported values include:
.
ovs - OpenVSwitch
nvp - Nicera
ext-port:
type: string
description: |
External port to use for routing of instance
traffic to the external public network.
region:
type: string
default: RegionOne
description: |
OpenStack region that this quantum service supports.
conf-ext-net:
type: string
default: doti
description: Configure external network for quantum using
network configuration below.
ext-net-name:
type: string
default: ext_net
description: |
Name of external network configuration to create for
public access to instances/floating IP's.
ext-gw-ip:
type: string
default: 192.168.21.100
description: |
IP address to assign to external bridge for external network
access.
ext-net-cidr:
type: string
default: 192.168.21.0/24
description: |
External network addressing
ext-net-gateway:
type: string
default: 192.168.21.1
description: |
IP of the public network gateway (i.e. external router)
pool-floating-start:
type: string
default: 192.168.21.130
description: |
Start of default floating IP range.
pool-floating-end:
type: string
default: 192.168.21.200
description: |
End of default floating IP range.
source:
type: string
description: |

View File

@ -2,62 +2,73 @@
import utils
import sys
import quantum_utils
import quantum_utils as qutils
import os
PLUGIN_PKGS = {
"ovs": [ # TODO: Assumes Quantum Provider Gateway
"quantum-plugin-openvswitch",
"quantum-plugin-openvswitch-agent",
"quantum-l3-agent",
"quantum-dhcp-agent"
],
"nvp": ["quantum-plugin-nicira"] # No agent required
}
PLUGIN = utils.config_get('plugin')
def install():
utils.configure_source()
# TODO: when using the nicira plugin /etc/default/quantum-server
# will also need to be updated to point to the correct configuration
plugin = utils.config_get('plugin')
if plugin in PLUGIN_PKGS.keys():
if plugin == "ovs":
if PLUGIN in qutils.PLUGIN_PKGS.keys():
if PLUGIN == "ovs":
# Install OVS DKMS first to ensure that the ovs module
# loaded supports GRE tunnels
utils.install('openvswitch-datapath-dkms')
utils.install('quantum-server',
'python-mysqldb',
*PLUGIN_PKGS[plugin])
*qutils.PLUGIN_PKGS[PLUGIN])
else:
utils.juju_log('ERROR', 'Please provide a valid plugin config')
sys.exit(1)
def config_changed():
plugin = utils.config_get('plugin')
if plugin in PLUGIN_PKGS.keys():
if PLUGIN in qutils.PLUGIN_PKGS.keys():
render_api_paste_conf()
render_quantum_conf()
render_plugin_conf()
if plugin == "ovs":
# TODO: Defaults to Quantum Provider Router
quantum_utils.add_bridge('br-int')
quantum_utils.add_bridge('br-ex')
render_l3_agent_conf()
if PLUGIN == "ovs":
qutils.add_bridge('br-int')
qutils.add_bridge('br-ex')
ext_port = utils.config_get('ext-port')
if ext_port:
quantum_utils.add_bridge_port('br-ex', ext_port)
render_l3_agent_conf()
utils.restart('quantum-l3-agent',
'quantum-plugin-openvswitch-agent',
'quantum-dhcp-agent')
utils.restart('quantum-server')
qutils.add_bridge_port('br-ex', ext_port)
utils.restart(*(qutils.PLUGIN_AGENT[PLUGIN] + \
qutils.GATEWAY_AGENTS[PLUGIN]))
else:
utils.juju_log('ERROR',
'Please provide a valid plugin config')
sys.exit(1)
configure_networking()
def configure_networking():
keystone_conf = get_keystone_conf()
db_conf = get_db_conf()
if (utils.config_get('conf-ext-net') and
keystone_conf and
db_conf):
qutils.configure_ext_net(
username=keystone_conf['service_username'],
password=keystone_conf['service_password'],
tenant=keystone_conf['service_tenant'],
url="http://{}:{}/v2.0/".format(
keystone_conf['keystone_host'],
keystone_conf['auth_port']
),
ext_net_name=utils.config_get('ext-net-name'),
gateway_ip=utils.config_get('ext-gw-ip'),
default_gateway=utils.config_get('ext-net-gateway'),
cidr=utils.config_get('ext-net-cidr'),
start_floating_ip=utils.config_get('pool-floating-start'),
end_floating_ip=utils.config_get('pool-floating-end')
)
def upgrade_charm():
install()
@ -66,56 +77,71 @@ def upgrade_charm():
def render_l3_agent_conf():
context = get_keystone_conf()
if context:
with open(quantum_utils.L3_AGENT_CONF, "w") as conf:
conf.write(utils.render_template("l3_agent.ini", context))
if (context and
os.path.exists(qutils.L3_AGENT_CONF)):
with open(qutils.L3_AGENT_CONF, "w") as conf:
conf.write(utils.render_template(
os.path.basename(qutils.L3_AGENT_CONF),
context
)
)
def render_api_paste_conf():
context = get_keystone_conf()
if context:
with open(quantum_utils.QUANTUM_API_CONF, "w") as conf:
conf.write(utils.render_template("api-paste.ini", context))
if (context and
os.path.exists(qutils.QUANTUM_API_CONF)):
with open(qutils.QUANTUM_API_CONF, "w") as conf:
conf.write(utils.render_template(
os.path.basename(qutils.QUANTUM_API_CONF),
context
)
)
def render_quantum_conf():
context = get_rabbit_conf()
if context:
if (context and
os.path.exists(qutils.QUANTUM_CONF)):
context['core_plugin'] = \
quantum_utils.CORE_PLUGIN[utils.config_get('plugin')]
with open(quantum_utils.QUANTUM_CONF, "w") as conf:
conf.write(utils.render_template("quantum.conf", context))
qutils.CORE_PLUGIN[PLUGIN]
with open(qutils.QUANTUM_CONF, "w") as conf:
conf.write(utils.render_template(
os.path.basename(qutils.QUANTUM_CONF),
context
)
)
def render_plugin_conf():
context = get_db_conf()
if context:
if (context and
os.path.exists(qutils.PLUGIN_CONF[PLUGIN])):
context['local_ip'] = utils.get_host_ip()
plugin = utils.config_get('plugin')
conf_file = quantum_utils.PLUGIN_CONF[plugin]
conf_file = qutils.PLUGIN_CONF[PLUGIN]
with open(conf_file, "w") as conf:
conf.write(utils.render_template(os.path.basename(conf_file),
context))
conf.write(utils.render_template(
os.path.basename(conf_file),
context
)
)
def keystone_joined():
url = "http://{}:9696/".format(utils.unit_get('private-address'))
utils.relation_set(service="quantum",
region="RegionOne",
utils.relation_set(service=qutils.KEYSTONE_SERVICE,
region=utils.config_get('region'),
public_url=url,
admin_url=url,
internal_url=url)
def keystone_changed():
if os.path.exists(quantum_utils.L3_AGENT_CONF):
render_l3_agent_conf() # Restart quantum_l3_agent
utils.restart('quantum-l3-agent')
render_api_paste_conf() # Restart quantum server
utils.restart('quantum-server')
if os.path.exists(quantum_utils.DHCP_AGENT_CONF):
utils.restart('quantum-dhcp-agent')
render_l3_agent_conf()
render_api_paste_conf()
utils.restart(*qutils.GATEWAY_AGENTS[PLUGIN])
notify_agents()
configure_networking()
def get_keystone_conf():
@ -141,16 +167,16 @@ def get_keystone_conf():
def db_joined():
utils.relation_set(username=quantum_utils.DB_USER,
database=quantum_utils.QUANTUM_DB,
utils.relation_set(username=qutils.DB_USER,
database=qutils.QUANTUM_DB,
hostname=utils.unit_get('private-address'))
def db_changed():
render_plugin_conf()
utils.restart('quantum-server')
if utils.config_get('plugin') == 'ovs':
utils.restart('quantum-plugin-openvswitch-agent')
utils.restart(*(qutils.GATEWAY_AGENTS[PLUGIN] + \
qutils.PLUGIN_AGENT[PLUGIN]))
configure_networking()
def get_db_conf():
@ -159,10 +185,10 @@ def get_db_conf():
conf = {
"host": utils.relation_get('private-address',
unit, relid),
"user": quantum_utils.DB_USER,
"user": qutils.DB_USER,
"password": utils.relation_get('password',
unit, relid),
"db": quantum_utils.QUANTUM_DB
"db": qutils.QUANTUM_DB
}
if None not in conf.itervalues():
return conf
@ -170,15 +196,14 @@ def get_db_conf():
def amqp_joined():
utils.relation_set(username=quantum_utils.RABBIT_USER,
vhost=quantum_utils.RABBIT_VHOST)
utils.relation_set(username=qutils.RABBIT_USER,
vhost=qutils.RABBIT_VHOST)
def amqp_changed():
render_quantum_conf()
utils.restart('quantum-server', 'quantum-dhcp-agent')
if utils.config_get('plugin') == 'ovs':
utils.restart('quantum-plugin-openvswitch-agent')
utils.restart(*(qutils.GATEWAY_AGENTS[PLUGIN] + \
qutils.PLUGIN_AGENT[PLUGIN]))
def get_rabbit_conf():
@ -187,8 +212,8 @@ def get_rabbit_conf():
conf = {
"rabbit_host": utils.relation_get('private-address',
unit, relid),
"rabbit_virtual_host": quantum_utils.RABBIT_VHOST,
"rabbit_userid": quantum_utils.RABBIT_USER,
"rabbit_virtual_host": qutils.RABBIT_VHOST,
"rabbit_userid": qutils.RABBIT_USER,
"rabbit_password": utils.relation_get('password',
unit, relid)
}
@ -201,7 +226,7 @@ def nm_joined():
keystone_conf = get_keystone_conf()
if keystone_conf:
utils.relation_set(**keystone_conf) # IGNORE:W0142
utils.relation_set(plugin=utils.config_get('plugin'))
utils.relation_set(plugin=PLUGIN)
def notify_agents():
@ -209,7 +234,7 @@ def notify_agents():
if keystone_conf:
for relid in utils.relation_ids('network-manager'):
utils.relation_set(relid=relid,
plugin=utils.config_get('plugin'),
plugin=PLUGIN,
**keystone_conf)

View File

@ -1 +0,0 @@
hooks.py

View File

@ -1,6 +1,13 @@
import utils
import subprocess
try:
from quantumclient.v2_0 import client
except ImportError:
utils.install('python-quantumclient')
from quantumclient.v2_0 import client
OVS_PLUGIN = \
"quantum.plugins.openvswitch.ovs_quantum_plugin.OVSQuantumPluginV2"
NVP_PLUGIN = \
@ -19,8 +26,35 @@ PLUGIN_CONF = {
"nvp": NVP_PLUGIN_CONF
}
PLUGIN_PKGS = {
"ovs": [
"quantum-plugin-openvswitch",
"quantum-plugin-openvswitch-agent",
"quantum-l3-agent",
"quantum-dhcp-agent"
],
"nvp": [ # No agent required
"quantum-plugin-nicira"
]
}
PLUGIN_AGENT = {
"ovs": [
"quantum-plugin-openvswitch-agent",
]
}
GATEWAY_AGENTS = {
"ovs": [
"quantum-server",
"quantum-l3-agent",
"quantum-dhcp-agent"
]
}
DB_USER = "quantum"
QUANTUM_DB = "quantum"
KEYSTONE_SERVICE = "quantum"
QUANTUM_CONF = "/etc/quantum/quantum.conf"
L3_AGENT_CONF = "/etc/quantum/l3_agent.ini"
@ -30,16 +64,23 @@ DHCP_AGENT_CONF = "/etc/quantum/dhcp_agent.ini"
RABBIT_USER = "nova"
RABBIT_VHOST = "nova"
EXT_BRIDGE = 'br-ex'
INT_BRIDGE = 'br-int'
def add_bridge(name):
status = subprocess.check_output(["ovs-vsctl", "show"])
if "Bridge {}".format(name) not in status:
utils.juju_log('INFO',
'Creating bridge {}'.format(name))
subprocess.check_call(["ovs-vsctl", "add-br", name])
def del_bridge(name):
status = subprocess.check_output(["ovs-vsctl", "show"])
if "Bridge {}".format(name) in status:
utils.juju_log('INFO',
'Deleting bridge {}'.format(name))
subprocess.check_call(["ovs-vsctl", "del-br", name])
@ -47,11 +88,89 @@ def add_bridge_port(name, port):
status = subprocess.check_output(["ovs-vsctl", "show"])
if ("Bridge {}".format(name) in status and
"Interface \"{}\"".format(port) not in status):
utils.juju_log('INFO',
'Adding port {} to bridge {}'
.format(port, name))
subprocess.check_call(["ovs-vsctl", "add-port", name, port])
subprocess.check_call(["ip", "link", "set", port, "up"])
def del_bridge_port(name, port):
status = subprocess.check_output(["ovs-vsctl", "show"])
if ("Bridge {}".format(name) in status and
"Interface \"{}\"".format(port) in status):
utils.juju_log('INFO',
'Deleting port {} from bridge {}'
.format(port, name))
subprocess.check_call(["ovs-vsctl", "del-port", name, port])
subprocess.check_call(["ip", "link", "set", port, "down"])
def configure_ext_net(username,
password,
tenant,
url,
ext_net_name,
gateway_ip,
default_gateway,
cidr,
start_floating_ip,
end_floating_ip):
ext_net_len = cidr.split('/')[1]
quantum = client.Client(username=username,
password=password,
tenant_name=tenant,
auth_url=url)
networks = quantum.list_networks(name=ext_net_name)
if len(networks['networks']) == 0:
utils.juju_log('INFO',
'Configuring external bridge')
network_msg = {
'network': {
'name': ext_net_name,
'router:external': True
}
}
utils.juju_log('INFO',
'Creating new external network definition: {}'
.format(ext_net_name))
network = quantum.create_network(network_msg)
utils.juju_log('INFO',
'New external network created: {}'
.format(network['network']['id']))
subnet_msg = {
'subnet': {
'name': '{}_subnet'.format(ext_net_name),
'network_id': network['network']['id'],
'enable_dhcp': False,
'gateway_ip': default_gateway,
'cidr': cidr,
'ip_version': 4,
'allocation_pools': [
{
'start': start_floating_ip,
'end': end_floating_ip
}
]
}
}
utils.juju_log('INFO',
'Creating new subnet for {}'
.format(ext_net_name))
subnet = quantum.create_subnet(subnet_msg)
utils.juju_log('INFO',
'New subnet created: {}'
.format(subnet['subnet']['id']))
utils.juju_log('INFO',
'Configuring external bridge connectivity')
subprocess.check_call(['ip', 'addr', 'flush',
'dev', EXT_BRIDGE])
subprocess.check_call(['ip', 'addr', 'add',
'{}/{}'.format(gateway_ip, ext_net_len),
'dev', EXT_BRIDGE])
subprocess.check_call(['ip', 'addr', 'set',
EXT_BRIDGE, 'up'])

View File

@ -41,16 +41,13 @@ except ImportError:
install('python-jinja2')
import jinja2
try:
import dns.resolver
import dns.ipv4
import dns.ipv6
except ImportError:
install('python-dnspython')
import dns.resolver
import dns.ipv4
import dns.ipv6
def render_template(template_name, context, template_dir=TEMPLATES_DIR):
@ -60,20 +57,29 @@ def render_template(template_name, context, template_dir=TEMPLATES_DIR):
template = templates.get_template(template_name)
return template.render(context)
CLOUD_ARCHIVE = \
""" # Ubuntu Cloud Archive
deb http://ubuntu-cloud.archive.canonical.com/ubuntu {} main
"""
def configure_source():
source = config_get('source')
source = str(config_get('source'))
if not source:
return
if (source.startswith('ppa:') or
source.startswith('cloud:')):
if source.startswith('ppa:'):
cmd = [
'add-apt-repository',
source
]
subprocess.check_call(cmd)
if source.startswith('cloud:'):
install('ubuntu-cloud-keyring')
pocket = source.split(':')[1]
with open('/etc/apt/sources.list.d/cloud-archive.list', 'w') as apt:
apt.write(CLOUD_ARCHIVE.format(pocket))
if source.startswith('http:'):
with open('/etc/apt/sources.list.d/ceph.list', 'w') as apt:
with open('/etc/apt/sources.list.d/quantum.list', 'w') as apt:
apt.write("deb " + source + "\n")
key = config_get('key')
if key:

View File

@ -1 +1 @@
23
31