diff --git a/hooks/amqp-relation-changed b/hooks/amqp-relation-changed new file mode 120000 index 00000000..9416ca6a --- /dev/null +++ b/hooks/amqp-relation-changed @@ -0,0 +1 @@ +hooks.py \ No newline at end of file diff --git a/hooks/amqp-relation-joined b/hooks/amqp-relation-joined new file mode 120000 index 00000000..9416ca6a --- /dev/null +++ b/hooks/amqp-relation-joined @@ -0,0 +1 @@ +hooks.py \ No newline at end of file diff --git a/hooks/hooks.py b/hooks/hooks.py index 4c65e1e9..b5d9c548 100755 --- a/hooks/hooks.py +++ b/hooks/hooks.py @@ -3,6 +3,7 @@ import utils import sys import quantum_utils +import os PLUGIN_PKGS = { @@ -26,7 +27,9 @@ def install(): # Install OVS DKMS first to ensure that the ovs module # loaded supports GRE tunnels utils.install('openvswitch-datapath-dkms') - utils.install(['quantum-server'].extend(PLUGIN_PKGS[plugin])) + utils.install('quantum-server', + 'python-mysqldb', + *PLUGIN_PKGS[plugin]) else: utils.juju_log('ERROR', 'Please provide a valid plugin config') sys.exit(1) @@ -35,22 +38,66 @@ def install(): def config_changed(): plugin = utils.config_get('plugin') if plugin in 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-ext') + quantum_utils.add_bridge('br-ex') ext_port = utils.config_get('ext-port') if ext_port: quantum_utils.add_bridge_port('br-ex', ext_port) - quantum_utils.configure_core_plugin(plugin) - quantum_utils.configure_local_ip(plugin, - utils.unit_get('private-address')) + render_l3_agent_conf() + utils.restart('quantum-l3-agent', + 'quantum-plugin-openvswitch-agent', + 'quantum-dhcp-agent') + utils.restart('quantum-server') else: utils.juju_log('ERROR', 'Please provide a valid plugin config') sys.exit(1) +def upgrade_charm(): + install() + config_changed() + + +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)) + + +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)) + + +def render_quantum_conf(): + context = get_rabbit_conf() + if context: + 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)) + + +def render_plugin_conf(): + context = get_db_conf() + if context: + context['local_ip'] = utils.unit_get('private-address') + plugin = utils.config_get('plugin') + conf_file = quantum_utils.PLUGIN_CONF[plugin] + with open(conf_file, "w") as conf: + 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", @@ -61,34 +108,36 @@ def keystone_joined(): def keystone_changed(): - token = utils.relation_get('admin_token') - service_port = utils.relation_get('service_port') - auth_port = utils.relation_get('auth_port') - service_username = utils.relation_get('service_username') - service_password = utils.relation_get('service_password') - service_tenant = utils.relation_get('service_tenant') - if not (token and - service_port and - auth_port and - service_username and - service_password and - service_tenant): - utils.juju_log('INFO', - 'keystone peer not ready yet') - return - if token == "-1": - utils.juju_log('ERROR', - 'Admin token error') - sys.exit(1) - keystone_host = utils.relation_get('private-address') - utils.juju_log('INFO', 'Configuring quantum for keystone authentication') - quantum_utils.configure_keystone(keystone_host, - token, - service_port, - auth_port, - service_username, - service_password, - service_tenant) + 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') + notify_agents() + + +def get_keystone_conf(): + for relid in utils.relation_ids('identity-service'): + for unit in utils.relation_list(relid): + conf = { + "keystone_host": utils.relation_get('private-address', + unit, relid), + "token": utils.relation_get('admin_token', unit, relid), + "service_port": utils.relation_get('service_port', + unit, relid), + "auth_port": utils.relation_get('auth_port', unit, relid), + "service_username": utils.relation_get('service_username', + unit, relid), + "service_password": utils.relation_get('service_password', + unit, relid), + "service_tenant": utils.relation_get('service_tenant', + unit, relid) + } + if None not in conf.itervalues(): + return conf + return None def db_joined(): @@ -98,32 +147,83 @@ def db_joined(): def db_changed(): - host = utils.relation_get('private-address') - password = utils.relation_get('password') - if not (host and password): - return - else: - quantum_utils.configure_db_connection(utils.config_get('plugin'), - host, password) + render_plugin_conf() + utils.restart('quantum-server') + if utils.config_get('plugin') == 'ovs': + utils.restart('quantum-plugin-openvswitch-agent') + + +def get_db_conf(): + for relid in utils.relation_ids('shared-db'): + for unit in utils.relation_list(relid): + conf = { + "host": utils.relation_get('private-address', + unit, relid), + "user": quantum_utils.DB_USER, + "password": utils.relation_get('password', + unit, relid), + "db": quantum_utils.QUANTUM_DB + } + if None not in conf.itervalues(): + return conf + return None def amqp_joined(): - pass + utils.relation_set(username=quantum_utils.RABBIT_USER, + vhost=quantum_utils.RABBIT_VHOST) def amqp_changed(): - pass + render_quantum_conf() + utils.restart('quantum-server', 'quantum-dhcp-agent') + if utils.config_get('plugin') == 'ovs': + utils.restart('quantum-plugin-openvswitch-agent') + + +def get_rabbit_conf(): + for relid in utils.relation_ids('amqp'): + for unit in utils.relation_list(relid): + conf = { + "rabbit_host": utils.relation_get('private-address', + unit, relid), + "rabbit_virtual_host": quantum_utils.RABBIT_VHOST, + "rabbit_userid": quantum_utils.RABBIT_USER, + "rabbit_password": utils.relation_get('password', + unit, relid) + } + if None not in conf.itervalues(): + return conf + return None + + +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')) + + +def notify_agents(): + keystone_conf = get_keystone_conf() + if keystone_conf: + for relid in utils.relation_ids('network-manager'): + utils.relation_set(relid=relid, + plugin=utils.config_get('plugin'), + **keystone_conf) utils.do_hooks({ "install": install, "config-changed": config_changed, + "upgrade-charm": upgrade_charm, "identity-service-relation-joined": keystone_joined, "identity-service-relation-changed": keystone_changed, "shared-db-relation-joined": db_joined, "shared-db-relation-changed": db_changed, "amqp-relation-joined": amqp_joined, - "amqp-relation-changed": amqp_changed + "amqp-relation-changed": amqp_changed, + "network-manager-relation-joined": nm_joined, }) sys.exit(0) diff --git a/hooks/network-manager-relation-changed b/hooks/network-manager-relation-changed new file mode 120000 index 00000000..9416ca6a --- /dev/null +++ b/hooks/network-manager-relation-changed @@ -0,0 +1 @@ +hooks.py \ No newline at end of file diff --git a/hooks/network-manager-relation-joined b/hooks/network-manager-relation-joined new file mode 120000 index 00000000..9416ca6a --- /dev/null +++ b/hooks/network-manager-relation-joined @@ -0,0 +1 @@ +hooks.py \ No newline at end of file diff --git a/hooks/packages b/hooks/packages deleted file mode 100644 index c7b8e626..00000000 --- a/hooks/packages +++ /dev/null @@ -1,47 +0,0 @@ -Quantum Server -============== - -quantum-server - -# OVS -quantum-plugin-openvswitch quantum-plugin-openvswitch-agent - -# Configure connection to the database - -> store in sql_connection in plugins. - -# OVS - -/etc/quantum/plugins/openvswitch/ovs_quantum_plugin.ini - -enable_tunneling=True -tenant_network_type=gre -tunnel_id_ranges=1:1000 -# only if node is running the agent -local_ip=$(unit-get private-address) # data network - -service quantum-server restart - -# Add internal bridge - -ovs-vsctl add-br br-int - -# restart openvswitch plugin - -# Same everywhere - -quantum-dhcp-agent -quantum-l3-agent - -ovs-vsctl add-br br-ex -ovs-vsctl add-port br-ex $(config-get external-port) - -# Keystone - need to review keystone charm to see how this works. - -keystone service-create --name quantum --type network --description 'OpenStack Networking Service' -keystone endpoint-create --region $REGION --service-id $ID --publicurl \ - 'http://$IP:9696/' --adminurl 'http://$IP:9696/' --internalurl 'http://$IP:9696/' - - -keystone user-create --name=quantum --pass=$SERVICE_PASSWORD --tenant-id service -keystone user-role-add --user_id 45e9461fa61e48f99de1adcd0b38eae7 --role_id e45af7cf33be4dac8070aa8310144ce3 \ - --tenant_id 950fe8e5ed5f4659a8556ac836e8943d diff --git a/hooks/quantum-hooks b/hooks/quantum-hooks deleted file mode 100755 index 09bb5aff..00000000 --- a/hooks/quantum-hooks +++ /dev/null @@ -1,131 +0,0 @@ -#!/bin/bash -e -# vim: set ts=2:set et: - -[ -f hooks/openstack-common ] && . hooks/openstack-common - -ARG0=${0##*/} -PLUGIN=$(config-get plugin) -EXT_PORT=$(config-get ext-port) -PRIVATE_ADDRESS=$(unit-get private-address) -DB_USER=quantum -QUANTUM_DB=quantum - -OVS_PLUGIN_CONF="/etc/quantum/plugins/openvswitch/ovs_quantum_plugin.ini" -NVP_PLUGIN_CONF="/etc/quantum/plugins/nicira/nvp.ini" - -case $PLUGIN in - "ovs") PLUGIN_CONF=$OVS_PLUGIN_CONF ;; - "nvp") PLUGIN_CONF=$NVP_PLUGIN_CONF ;; -esac - -function install_hook() { - case $PLUGIN in - "ovs") - PLUGIN_PKGS="quantum-plugin-openvswitch quantum-plugin-openvswitch-agent" - ;; - "nvp") - # XXX implement nvp - ;; - *) - juju-log "Unsupported plugin specified" - exit 1 - ;; - esac - - apt-get install quantum-server $PLUGIN_PKGS \ - quantum-dhcp-agent \ - quantum-l3-agent \ - openvswitch-datapath-dkms - - ovs-vsctl add-br br-int - ovs-vsctl add-br br-ex -} - -function config_changed_hook() { - ovs-vsctl add-br br-int - ovs-vsctl add-br br-ex - if [ -n "$EXT_PORT" ]; then - juju-log "Adding $EXT_PORT to external bridge for external access" - ovs-vsctl add-port br-ex $EXT_PORT - fi - - case $PLUGIN in - "ovs") - CORE_PLUGIN="quantum.plugins.openvswitch.ovs_quantum_plugin.OVSQuantumPluginV2" - ;; - "nvp") - CORE_PLUGIN="quantum.plugins.nicira.nicira_nvp_plugin.QuantumPlugin.NvpPluginV2" - ;; - esac - juju-log "Configuring quantum with core_plugin: $CORE_PLUGIN" - set_or_update core_plugin $CORE_PLUGIN /etc/quantum/quantum.conf -} - -function start() { - -} - -function stop() { - -} - -function keystone_joined { - # advertise our API endpoint to keystone - url="http://$(unit-get private-address):9696/v1" - public_url="http://$(unit-get public-address):9696/v1" - relation-set service="quantum" \ - region="RegionOne" public_url=$public_url admin_url=$url internal_url=$url -} - -function keystone_changed { - # we hopefully get a token in return. configure middleware accordingly - token=$(relation-get admin_token) - service_port=$(relation-get service_port) - auth_port=$(relation-get auth_port) - service_username=$(relation-get service_username) - service_password=$(relation-get service_password) - service_tenant=$(relation-get service_tenant) - [[ -z "$token" ]] || [[ -z "$service_port" ]] || [[ -z "$auth_port" ]] || - [[ -z "$service_username" ]] || [[ -z "$service_password" ]] || - [[ -z "$service_tenant" ]] && juju-log "Peer not ready" && - exit 0 - [[ "$token" == "-1" ]] && - juju-log "admin token error" && exit 1 - juju-log "Acquired admin. token" - keystone_host=$(relation-get private-address) -} - -function db_joined { - juju-log "Requesting access to $QUANTUM_DB for $DB_USER@$PRIVATE_ADDRESS" - relation-set database=$QUANTUM_DB username=$DB_USER hostname=$PRIVATE_ADDRESS -} - -function db_changed { - DB_HOST=$(relation-get private-address) - DB_PASSWORD=$(relation-get password) - if [ -z "$DB_HOST" ] || [ -z "$DB_PASSWORD" ] ; then - echo "DB_HOST || DB_PASSWORD not yet set. Exit 0 and retry" - exit 0 - else - echo "Received password from $DB_HOST" - fi - juju-log "Configuring registry for access to $QUANTUM_DB@$DB_HOST" - set_or_update sql_connection \ - "mysql://$DB_USER:$DB_PASSWORD@$DB_HOST/$QUANTUM_DB?charset=utf8" \ - $PLUGIN_CONF -} - - -case $ARG0 in - "install") install_hook ;; - "config-changed") config_changed_hook ;; - "identity-service-relation-joined") keystone_joined ;; - "identity-service-relation-changed") keystone_changed ;; - "shared-db-relation-joined") db_joined ;; - "shared-db-relation-changed") db_changed;; -esac - -# TODO: Add hooks for rabbitmq integration - dhcpagent seems to require: -# /etc/quantum/quantum.conf: -# rabbit_password = openstack -# rabbit_host = 100.1.1.10 diff --git a/hooks/quantum_utils.py b/hooks/quantum_utils.py index 30777254..5c3da020 100644 --- a/hooks/quantum_utils.py +++ b/hooks/quantum_utils.py @@ -1,7 +1,5 @@ -import utils import subprocess -import os OVS_PLUGIN = \ "quantum.plugins.openvswitch.ovs_quantum_plugin.OVSQuantumPluginV2" @@ -27,115 +25,10 @@ QUANTUM_DB = "quantum" QUANTUM_CONF = "/etc/quantum/quantum.conf" L3_AGENT_CONF = "/etc/quantum/l3_agent.ini" QUANTUM_API_CONF = "/etc/quantum/api-paste.ini" +DHCP_AGENT_CONF = "/etc/quantum/dhcp_agent.ini" -MYSQL_CS = "mysql://%(user)s:%(password)s@%(host)s/%(db)s?charset=utf8" - - -def update_config_block(block, conf, **kwargs): - """ - Updates configuration file blocks given kwargs. - Can be used to update driver settings for a particular backend, - setting the sql connection, etc. - - Parses block heading as '[block]' - - If block does not exist, a new block will be created at end of file with - given kwargs - """ - f = open(conf, "r+") - orig = f.readlines() - new = [] - heading = "[{}]\n".format(block) - - lines = len(orig) - ln = 0 - - def update_block(block): - for k, v in kwargs.iteritems(): - for l in block: - if l.strip().split(" ")[0] == k: - block[block.index(l)] = "{} = {}\n".format(k, v) - return - block.append('{} = {}\n'.format(k, v)) - block.append('\n') - - found = False - while ln < lines: - if orig[ln] != heading: - new.append(orig[ln]) - ln += 1 - else: - new.append(orig[ln]) - ln += 1 - block = [] - while orig[ln].strip() != '': - block.append(orig[ln]) - ln += 1 - update_block(block) - new += block - found = True - - if not found: - if new[(len(new) - 1)].strip() != '': - new.append('\n') - new.append('{}'.format(heading)) - for k, v in kwargs.iteritems(): - new.append('{} = {}\n'.format(k, v)) - new.append('\n') - - # backup original config - backup = open(conf + '.juju-back', 'w+') - for l in orig: - backup.write(l) - backup.close() - - # update config - f.seek(0) - f.truncate() - for l in new: - f.write(l) - - -def configure_core_plugin(plugin): - update_config_block("DEFAULT", QUANTUM_CONF, - core_plugin=CORE_PLUGIN[plugin]) - - -def configure_db_connection(plugin, host, password): - update_config_block( - "DATABASE", PLUGIN_CONF[plugin], - sql_connection=MYSQL_CS.format(host=host, - user=DB_USER, - password=password, - db=QUANTUM_DB) - ) - - -def configure_local_ip(plugin, address): - update_config_block("OVS", PLUGIN_CONF[plugin], local_ip=address) - - -def configure_keystone(keystone_host, - token, - service_port, - auth_port, - username, - password, - tenant): - if os.path.exists(L3_AGENT_CONF): # Indicated OVS model is in use. - update_config_block("DEFAULT", L3_AGENT_CONF, - auth_url="http://{}:{}/v2.0".format(keystone_host, - auth_port), - auth_region="RegionOne", - admin_tenant_name=tenant, - admin_user=username, - admin_password=password) - update_config_block("filter:authtoken", QUANTUM_API_CONF, - auth_host=keystone_host, - auth_port=auth_port, - admin_tenant_name=tenant, - admin_user=username, - admin_password=password) +RABBIT_USER = "nova" +RABBIT_VHOST = "nova" def add_bridge(name): @@ -152,7 +45,8 @@ def del_bridge(name): def add_bridge_port(name, port): status = subprocess.check_output(["ovs-vsctl", "show"]) - if "Bridge {}".format(name) in status: + if ("Bridge {}".format(name) in status and + "Interface \"{}\"".format(port) not in status): subprocess.check_call(["ovs-vsctl", "add-port", name, port]) diff --git a/hooks/upgrade-charm b/hooks/upgrade-charm new file mode 120000 index 00000000..9416ca6a --- /dev/null +++ b/hooks/upgrade-charm @@ -0,0 +1 @@ +hooks.py \ No newline at end of file diff --git a/hooks/utils.py b/hooks/utils.py index d1a14411..96a25d92 100644 --- a/hooks/utils.py +++ b/hooks/utils.py @@ -65,7 +65,7 @@ def configure_source(): with open('/etc/apt/sources.list.d/ceph.list', 'w') as apt: apt.write("deb " + source + "\n") key = config_get('key') - if key != "": + if key: cmd = [ 'apt-key', 'adv', '--keyserver keyserver.ubuntu.com', @@ -183,3 +183,8 @@ def get_host_ip(hostname=unit_get('private-address')): hostname ] return subprocess.check_output(cmd).strip() # IGNORE:E1103 + + +def restart(*services): + for service in services: + subprocess.check_call(['service', service, 'restart']) diff --git a/metadata.yaml b/metadata.yaml index 8333af66..2b559030 100644 --- a/metadata.yaml +++ b/metadata.yaml @@ -14,8 +14,6 @@ provides: network-manager: interface: quantum requires: - cloud-compute: - interface: nova-compute shared-db: interface: mysql-shared amqp: diff --git a/revision b/revision index d00491fd..40994076 100644 --- a/revision +++ b/revision @@ -1 +1 @@ -1 +23 diff --git a/templates/api-paste.ini b/templates/api-paste.ini new file mode 100644 index 00000000..10d86c37 --- /dev/null +++ b/templates/api-paste.ini @@ -0,0 +1,30 @@ +[composite:quantum] +use = egg:Paste#urlmap +/: quantumversions +/v2.0: quantumapi_v2_0 + +[composite:quantumapi_v2_0] +use = call:quantum.auth:pipeline_factory +noauth = extensions quantumapiapp_v2_0 +keystone = authtoken keystonecontext extensions quantumapiapp_v2_0 + +[filter:keystonecontext] +paste.filter_factory = quantum.auth:QuantumKeystoneContext.factory + +[filter:authtoken] +paste.filter_factory = keystone.middleware.auth_token:filter_factory +auth_host = {{ keystone_host }} +auth_port = {{ auth_port }} +auth_protocol = http +admin_tenant_name = {{ service_tenant }} +admin_user = {{ service_username }} +admin_password = {{ service_password }} + +[filter:extensions] +paste.filter_factory = quantum.extensions.extensions:plugin_aware_extension_middleware_factory + +[app:quantumversions] +paste.app_factory = quantum.api.versions:Versions.factory + +[app:quantumapiapp_v2_0] +paste.app_factory = quantum.api.v2.router:APIRouter.factory diff --git a/templates/dhcp_agent.ini b/templates/dhcp_agent.ini new file mode 100644 index 00000000..97d112ef --- /dev/null +++ b/templates/dhcp_agent.ini @@ -0,0 +1,5 @@ +[DEFAULT] +state_path = /var/lib/quantum +interface_driver = quantum.agent.linux.interface.OVSInterfaceDriver +dhcp_driver = quantum.agent.linux.dhcp.Dnsmasq +root_helper = sudo /usr/bin/quantum-rootwrap /etc/quantum/rootwrap.conf diff --git a/templates/l3_agent.ini b/templates/l3_agent.ini new file mode 100644 index 00000000..ed3b8e13 --- /dev/null +++ b/templates/l3_agent.ini @@ -0,0 +1,8 @@ +[DEFAULT] +interface_driver = quantum.agent.linux.interface.OVSInterfaceDriver +auth_url = http://{{ keystone_host }}:{{ service_port }}/v2.0 +auth_region = RegionOne +admin_tenant_name = {{ service_tenant }} +admin_user = {{ service_username }} +admin_password = {{ service_password }} +root_helper = sudo /usr/bin/quantum-rootwrap /etc/quantum/rootwrap.conf diff --git a/templates/ovs_quantum_plugin.ini b/templates/ovs_quantum_plugin.ini new file mode 100644 index 00000000..e064976d --- /dev/null +++ b/templates/ovs_quantum_plugin.ini @@ -0,0 +1,11 @@ +[DATABASE] +sql_connection = mysql://{{ user }}:{{ password }}@{{ host }}/{{ db }}?charset=utf8 +reconnect_interval = 2 +[OVS] +local_ip = {{ local_ip }} +tenant_network_type = gre +enable_tunneling = True +tunnel_id_ranges = 1:1000 +[AGENT] +polling_interval = 2 +root_helper = sudo /usr/bin/quantum-rootwrap /etc/quantum/rootwrap.conf diff --git a/templates/quantum.conf b/templates/quantum.conf new file mode 100644 index 00000000..5e0508c2 --- /dev/null +++ b/templates/quantum.conf @@ -0,0 +1,15 @@ +[DEFAULT] +verbose = True +rabbit_userid = {{ rabbit_userid }} +rabbit_virtual_host = {{ rabbit_virtual_host }} +rabbit_host = {{ rabbit_host }} +rabbit_password = {{ rabbit_password }} +debug = True +bind_host = 0.0.0.0 +bind_port = 9696 +core_plugin = {{ core_plugin }} +api_paste_config = /etc/quantum/api-paste.ini +control_exchange = quantum +notification_driver = quantum.openstack.common.notifier.list_notifier +list_notifier_drivers = quantum.openstack.common.notifier.rabbit_notifier +[QUOTAS]