Refactoring to include external network setup as part of charm
This commit is contained in:
parent
75baba6431
commit
d5a60ecd53
43
config.yaml
43
config.yaml
|
@ -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: |
|
||||
|
|
159
hooks/hooks.py
159
hooks/hooks.py
|
@ -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)
|
||||
|
||||
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
hooks.py
|
|
@ -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'])
|
||||
|
|
|
@ -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:
|
||||
|
|
Loading…
Reference in New Issue