Add support for PLUMgrid via Ansible playbook

Support Compass OpenStack installation with integrated PLUMgrid Open
Networking Suite.  PLUMgrid ONS is a comprehensive software-only
networking solution for OpenStack which integrates with Neutron.  The
current implementation supports OpenStack Juno with a single
controller.

* add role for core plumgrid software

* add role for plugin to neutron

* add single-controller playbook to include plumgrid roles

Change-Id: I4c320e9282bcafe450556e70020505fdb5aaf396
This commit is contained in:
Brian Matheson 2015-05-27 10:36:12 -04:00
parent 70360bca6a
commit 701a0b8fef
11 changed files with 1515 additions and 0 deletions

View File

@ -0,0 +1,35 @@
---
- hosts: controller
sudo: True
roles:
- common
- database
- mq
- keystone
- nova-controller
- neutron-controller
- dashboard
- cinder-controller
- glance
- plumgrid
- plumgrid-plugin
- hosts: network
sudo: True
roles:
- common
- plumgrid
- hosts: storage
sudo: True
roles:
- common
- cinder-volume
- hosts: compute
sudo: True
roles:
- common
- nova-compute
- neutron-compute
- plumgrid

View File

@ -0,0 +1,148 @@
#
# Copyright (c) 2012-2015, PLUMgrid, http://plumgrid.com
#
# Create a PLUMgrid sources.list
- name: Create plumgrid sources.list
lineinfile:
dest: /etc/apt/sources.list.d/plumgrid.list
line: "deb {{ plumgrid_repo }}/plumgrid ./"
state: present
create: yes
# Point to LCM repo create a PLUMgrid sources.list
- name: Add plumgrid-images to repo
lineinfile:
dest: /etc/apt/sources.list.d/plumgrid.list
line: "deb {{ plumgrid_repo }}/plumgrid-images ./"
state: present
# Update repositories
- name: Running apt-update
apt:
update_cache: yes
# Install package neutron-plugin-plumgrid
- name: Install neutron-plugin-plumgrid
apt:
name: neutron-plugin-plumgrid
state: present
# Install package plumgrid-pythonlib
- name: Install plumgrid-pythonlib
apt:
name: plumgrid-pythonlib
state: present
# Modify template fies
- name: Setup plumgrid.ini
template: >
src=plumgrid.ini
dest=/etc/neutron/plugins/plumgrid/plumgrid.ini
owner={{ system_group }}
group={{ system_user }}
- name: Replace plugin.ini reference
replace:
dest: /etc/default/neutron-server
regexp: "^NEUTRON_PLUGIN_CONFIG.*"
replace: "NEUTRON_PLUGIN_CONFIG=\"/etc/neutron/plugins/plumgrid/plumgrid.ini\""
# Modify neutron configuration
- name: Add plumlib template
template: >
src=plumlib.py
dest=/usr/lib/python2.7/dist-packages/neutron/plugins/plumgrid/drivers/plumlib.py
owner={{ system_group }}
group={{ system_user }}
- name: Replace plugin with Plumgrid
replace:
dest: /etc/neutron/neutron.conf
regexp: '^core_plugin.*'
replace: 'core_plugin = neutron.plugins.plumgrid.plumgrid_plugin.plumgrid_plugin.NeutronPluginPLUMgridV2'
- name: Replace mysql connection spec
replace:
dest: /etc/neutron/neutron.conf
regexp: '^connection.*'
replace: 'connection = mysql://neutron:{{ NEUTRON_DBPASS }}@{{ db_host }}/ovs_neutron'
- name: Comment service_plugins
replace:
dest: /etc/neutron/neutron.conf
regexp: '^service_plugins'
replace: '#service_plugins'
- name: Update nova.conf
lineinfile:
dest: "/etc/nova/nova.conf"
insertafter: "DEFAULT"
state: present
create: yes
line: "{{ item }}"
with_items:
- libvirt_cpu_mode=none
- libvirt_vif_type=ethernet
- scheduler_driver=nova.scheduler.filter_scheduler.FilterScheduler
- name: Add plumgrid_plugin template
template: >
src=plumgrid_plugin.py
dest=/usr/lib/python2.7/dist-packages/neutron/plugins/plumgrid/plumgrid_plugin/plumgrid_plugin.py
owner={{ system_group }}
group={{ system_user }}
- name: Add plumlib filters
template: >
src=plumlib.filters
dest=/etc/neutron/rootwrap.d/plumlib.filters
owner={{ system_group }}
group={{ system_user }}
- name: Update Plumlib authentication
replace:
dest: /etc/neutron/plugins/plumgrid/plumlib.ini
regexp: '#admin_user = admin_username'
replace: 'admin_user = neutron'
- replace:
dest: /etc/neutron/plugins/plumgrid/plumlib.ini
regexp: '#admin_password = admin_password'
replace: 'admin_password = {{ neutron_service_password }}'
- replace:
dest: /etc/neutron/plugins/plumgrid/plumlib.ini
regexp: '#auth_uri = http://127.0.0.1:35357/v2.0/'
replace: 'auth_uri = http://{{ internal_lb_vip_address }}:5000/v2.0'
- replace:
dest: /etc/neutron/plugins/plumgrid/plumlib.ini
regexp: '#admin_tenant_name = admin_tenant_name'
replace: 'admin_tenant_name = service'
# Enable Metadata
- name: Enable Metadata
replace:
dest: /etc/neutron/plugins/plumgrid/plumlib.ini
regexp: 'enable_pg_metadata = False'
replace: 'enable_pg_metadata = True'
when: enable_pg_metadata == True
- name: Enable Metadata mode
replace:
dest: /etc/neutron/plugins/plumgrid/plumlib.ini
regexp: 'metadata_mode = tunnel'
replace: 'metadata_mode = local'
when: enable_pg_metadata == True
- name: Replace plugin config file
replace:
dest: /etc/init/neutron-server.conf
regexp: '/etc/neutron/plugins/ml2/ml2_conf.ini'
replace: '/etc/neutron/plugins/plumgrid/plumgrid.ini'
- name: Start neutron server
service: name=neutron-server state=restarted
register: service_started
failed_when: "'msg' in service_started and 'FAIL' in service_started.msg|upper"

View File

@ -0,0 +1,14 @@
# Config file for Neutron PLUMgrid Plugin
[plumgriddirector]
# This line should be pointing to the PLUMgrid Director,
# for the PLUMgrid platform.
director_server={{ pg_vip }}
director_server_port=443
# Authentification parameters for the Director.
# These are the admin credentials to manage and control
# the PLUMgrid Director server.
username=plumgrid
password=plumgrid
servertimeout=70
connection = mysql://neutron:{{ neutron_container_mysql_password }}@{{ internal_lb_vip_address }}/neutron?charset=utf8

View File

@ -0,0 +1,811 @@
# Copyright 2013 PLUMgrid, Inc. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
#
# @author: Fawad Khaliq, fawad@plumgrid.com, PLUMgrid, Inc.
"""
Neutron Plug-in for PLUMgrid Virtual Networking Infrastructure (VNI)
This plugin will forward authenticated REST API calls
to the PLUMgrid Network Management System called Director
"""
import netaddr
from oslo.config import cfg
from sqlalchemy.orm import exc as sa_exc
from neutron.api.v2 import attributes
from neutron.common import constants
from neutron.common import utils
from neutron.db import db_base_plugin_v2
from neutron.db import external_net_db
from neutron.db import extraroute_db
from neutron.db import l3_db
from neutron.db import portbindings_db
from neutron.db import quota_db # noqa
from neutron.db import securitygroups_db
from neutron.extensions import portbindings
from neutron.extensions import extraroute
from neutron.extensions import securitygroup as sec_grp
from neutron.openstack.common import importutils
from neutron.openstack.common import log as logging
from neutron.plugins.plumgrid.common import exceptions as plum_excep
from neutron.plugins.plumgrid.plumgrid_plugin.plugin_ver import VERSION
LOG = logging.getLogger(__name__)
director_server_opts = [
cfg.StrOpt('director_server', default='localhost',
help=_("PLUMgrid Director server to connect to")),
cfg.StrOpt('director_server_port', default='8080',
help=_("PLUMgrid Director server port to connect to")),
cfg.StrOpt('username', default='username',
help=_("PLUMgrid Director admin username")),
cfg.StrOpt('password', default='password', secret=True,
help=_("PLUMgrid Director admin password")),
cfg.IntOpt('servertimeout', default=5,
help=_("PLUMgrid Director server timeout")),
cfg.StrOpt('driver',
default="neutron.plugins.plumgrid.drivers.plumlib.Plumlib",
help=_("PLUMgrid Driver")), ]
cfg.CONF.register_opts(director_server_opts, "plumgriddirector")
class NeutronPluginPLUMgridV2(db_base_plugin_v2.NeutronDbPluginV2,
external_net_db.External_net_db_mixin,
extraroute_db.ExtraRoute_db_mixin,
l3_db.L3_NAT_db_mixin,
portbindings_db.PortBindingMixin,
securitygroups_db.SecurityGroupDbMixin):
supported_extension_aliases = ["binding", "external-net", "provider",
"quotas", "router", "security-group", "extraroute"]
binding_view = "extension:port_binding:view"
binding_set = "extension:port_binding:set"
def __init__(self):
LOG.info(_('Neutron PLUMgrid Director: Starting Plugin'))
super(NeutronPluginPLUMgridV2, self).__init__()
self.plumgrid_init()
LOG.debug(_('Neutron PLUMgrid Director: Neutron server with '
'PLUMgrid Plugin has started'))
def plumgrid_init(self):
"""PLUMgrid initialization."""
director_plumgrid = cfg.CONF.plumgriddirector.director_server
director_port = cfg.CONF.plumgriddirector.director_server_port
director_admin = cfg.CONF.plumgriddirector.username
director_password = cfg.CONF.plumgriddirector.password
timeout = cfg.CONF.plumgriddirector.servertimeout
plum_driver = cfg.CONF.plumgriddirector.driver
# PLUMgrid Director info validation
LOG.info(_('Neutron PLUMgrid Director: %s'), director_plumgrid)
self._plumlib = importutils.import_object(plum_driver)
self._plumlib.director_conn(director_plumgrid, director_port, timeout,
director_admin, director_password)
def create_network(self, context, network):
"""Create Neutron network.
Creates a PLUMgrid-based bridge.
"""
LOG.debug(_('Neutron PLUMgrid Director: create_network() called'))
# Plugin DB - Network Create and validation
tenant_id = self._get_tenant_id_for_create(context,
network["network"])
self._network_admin_state(network)
with context.session.begin(subtransactions=True):
net_db = super(NeutronPluginPLUMgridV2,
self).create_network(context, network)
# Propagate all L3 data into DB
self._process_l3_create(context, net_db, network['network'])
self._ensure_default_security_group(context, tenant_id)
try:
LOG.debug(_('PLUMgrid Library: create_network() called'))
self._plumlib.create_network(tenant_id, net_db, network)
except Exception as err_message:
raise plum_excep.PLUMgridException(err_msg=err_message)
# Return created network
return net_db
def update_network(self, context, net_id, network):
"""Update Neutron network.
Updates a PLUMgrid-based bridge.
"""
LOG.debug(_("Neutron PLUMgrid Director: update_network() called"))
self._network_admin_state(network)
tenant_id = self._get_tenant_id_for_create(context, network["network"])
with context.session.begin(subtransactions=True):
# Plugin DB - Network Update
net_db = super(
NeutronPluginPLUMgridV2, self).update_network(context,
net_id, network)
self._process_l3_update(context, net_db, network['network'])
try:
LOG.debug(_("PLUMgrid Library: update_network() called"))
self._plumlib.update_network(tenant_id, net_id, network)
except Exception as err_message:
raise plum_excep.PLUMgridException(err_msg=err_message)
# Return updated network
return net_db
def delete_network(self, context, net_id):
"""Delete Neutron network.
Deletes a PLUMgrid-based bridge.
"""
LOG.debug(_("Neutron PLUMgrid Director: delete_network() called"))
net_db = super(NeutronPluginPLUMgridV2,
self).get_network(context, net_id)
with context.session.begin(subtransactions=True):
# Plugin DB - Network Delete
super(NeutronPluginPLUMgridV2, self).delete_network(context,
net_id)
try:
LOG.debug(_("PLUMgrid Library: update_network() called"))
self._plumlib.delete_network(net_db, net_id)
except Exception as err_message:
raise plum_excep.PLUMgridException(err_msg=err_message)
@utils.synchronized('plumlib', external=True)
def create_port(self, context, port):
"""Create Neutron port.
Creates a PLUMgrid-based port on the specific Virtual Network
Function (VNF).
"""
LOG.debug(_("Neutron PLUMgrid Director: create_port() called"))
# Port operations on PLUMgrid Director is an automatic operation
# from the VIF driver operations in Nova.
# It requires admin_state_up to be True
port["port"]["admin_state_up"] = True
port_data = port["port"]
with context.session.begin(subtransactions=True):
# Plugin DB - Port Create and Return port
port_db = super(NeutronPluginPLUMgridV2, self).create_port(context,
port)
# Update port security
port_data.update(port_db)
self._ensure_default_security_group_on_port(context, port)
port_data[sec_grp.SECURITYGROUPS] = (
self._get_security_groups_on_port(context, port))
self._process_port_create_security_group(
context, port_db, port_data[sec_grp.SECURITYGROUPS])
self._process_portbindings_create_and_update(context,
port_data, port_db)
device_id = port_db["device_id"]
if port_db["device_owner"] == constants.DEVICE_OWNER_ROUTER_GW:
router_db = self._get_router(context, device_id)
else:
router_db = None
try:
LOG.debug(_("PLUMgrid Library: create_port() called"))
self._plumlib.create_port(port_db, router_db)
except Exception as err_message:
raise plum_excep.PLUMgridException(err_msg=err_message)
# Plugin DB - Port Create and Return port
return self._port_viftype_binding(context, port_db)
@utils.synchronized('plumlib', external=True)
def update_port(self, context, port_id, port):
"""Update Neutron port.
Updates a PLUMgrid-based port on the specific Virtual Network
Function (VNF).
"""
LOG.debug(_("Neutron PLUMgrid Director: update_port() called"))
with context.session.begin(subtransactions=True):
# Plugin DB - Port Create and Return port
port_db = super(NeutronPluginPLUMgridV2, self).update_port(
context, port_id, port)
device_id = port_db["device_id"]
if port_db["device_owner"] == constants.DEVICE_OWNER_ROUTER_GW:
router_db = self._get_router(context, device_id)
else:
router_db = None
if (self._check_update_deletes_security_groups(port) or
self._check_update_has_security_groups(port)):
self._delete_port_security_group_bindings(context,
port_db["id"])
sg_ids = self._get_security_groups_on_port(context, port)
self._process_port_create_security_group(context,
port_db,
sg_ids)
self._process_portbindings_create_and_update(context,
port['port'],
port_db)
try:
LOG.debug(_("PLUMgrid Library: create_port() called"))
self._plumlib.update_port(port_db, router_db)
except Exception as err_message:
raise plum_excep.PLUMgridException(err_msg=err_message)
# Plugin DB - Port Update
return self._port_viftype_binding(context, port_db)
@utils.synchronized('plumlib', external=True)
def delete_port(self, context, port_id, l3_port_check=True):
"""Delete Neutron port.
Deletes a PLUMgrid-based port on the specific Virtual Network
Function (VNF).
"""
LOG.debug(_("Neutron PLUMgrid Director: delete_port() called"))
with context.session.begin(subtransactions=True):
# Plugin DB - Port Create and Return port
port_db = super(NeutronPluginPLUMgridV2,
self).get_port(context, port_id)
router_ids = self.disassociate_floatingips(
context, port_id, do_notify=False)
super(NeutronPluginPLUMgridV2, self).delete_port(context, port_id)
if port_db["device_owner"] == constants.DEVICE_OWNER_ROUTER_GW:
device_id = port_db["device_id"]
router_db = self._get_router(context, device_id)
else:
router_db = None
try:
LOG.debug(_("PLUMgrid Library: delete_port() called"))
self._plumlib.delete_port(port_db, router_db)
except Exception as err_message:
raise plum_excep.PLUMgridException(err_msg=err_message)
# now that we've left db transaction, we are safe to notify
self.notify_routers_updated(context, router_ids)
def get_port(self, context, id, fields=None):
with context.session.begin(subtransactions=True):
port_db = super(NeutronPluginPLUMgridV2,
self).get_port(context, id, fields)
self._port_viftype_binding(context, port_db)
return self._fields(port_db, fields)
def get_ports(self, context, filters=None, fields=None):
with context.session.begin(subtransactions=True):
ports_db = super(NeutronPluginPLUMgridV2,
self).get_ports(context, filters, fields)
for port_db in ports_db:
self._port_viftype_binding(context, port_db)
return [self._fields(port, fields) for port in ports_db]
def create_subnet(self, context, subnet):
"""Create Neutron subnet.
Creates a PLUMgrid-based DHCP and NAT Virtual Network
Functions (VNFs).
"""
LOG.debug(_("Neutron PLUMgrid Director: create_subnet() called"))
with context.session.begin(subtransactions=True):
# Plugin DB - Subnet Create
net_db = super(NeutronPluginPLUMgridV2, self).get_network(
context, subnet['subnet']['network_id'], fields=None)
s = subnet['subnet']
ipnet = netaddr.IPNetwork(s['cidr'])
# PLUMgrid Director reserves the last IP address for GW
# when is not defined
if s['gateway_ip'] is attributes.ATTR_NOT_SPECIFIED:
gw_ip = str(netaddr.IPAddress(ipnet.last - 1))
subnet['subnet']['gateway_ip'] = gw_ip
# PLUMgrid reserves the first IP
if s['allocation_pools'] == attributes.ATTR_NOT_SPECIFIED:
allocation_pool = self._allocate_pools_for_subnet(context, s)
subnet['subnet']['allocation_pools'] = allocation_pool
sub_db = super(NeutronPluginPLUMgridV2, self).create_subnet(
context, subnet)
try:
LOG.debug(_("PLUMgrid Library: create_subnet() called"))
self._plumlib.create_subnet(sub_db, net_db, ipnet)
except Exception as err_message:
raise plum_excep.PLUMgridException(err_msg=err_message)
return sub_db
def delete_subnet(self, context, subnet_id):
"""Delete subnet core Neutron API."""
LOG.debug(_("Neutron PLUMgrid Director: delete_subnet() called"))
# Collecting subnet info
sub_db = self._get_subnet(context, subnet_id)
net_id = sub_db["network_id"]
net_db = self.get_network(context, net_id)
tenant_id = net_db["tenant_id"]
with context.session.begin(subtransactions=True):
# Plugin DB - Subnet Delete
super(NeutronPluginPLUMgridV2, self).delete_subnet(
context, subnet_id)
try:
LOG.debug(_("PLUMgrid Library: delete_subnet() called"))
self._plumlib.delete_subnet(tenant_id, net_db, net_id)
except Exception as err_message:
raise plum_excep.PLUMgridException(err_msg=err_message)
def update_subnet(self, context, subnet_id, subnet):
"""Update subnet core Neutron API."""
LOG.debug(_("update_subnet() called"))
# Collecting subnet info
orig_sub_db = self._get_subnet(context, subnet_id)
with context.session.begin(subtransactions=True):
# Plugin DB - Subnet Update
new_sub_db = super(NeutronPluginPLUMgridV2,
self).update_subnet(context, subnet_id, subnet)
ipnet = netaddr.IPNetwork(new_sub_db['cidr'])
try:
# PLUMgrid Server does not support updating resources yet
LOG.debug(_("PLUMgrid Library: update_network() called"))
self._plumlib.update_subnet(orig_sub_db, new_sub_db, ipnet)
except Exception as err_message:
raise plum_excep.PLUMgridException(err_msg=err_message)
return new_sub_db
def create_router(self, context, router):
"""
Create router extension Neutron API
"""
LOG.debug(_("Neutron PLUMgrid Director: create_router() called"))
tenant_id = self._get_tenant_id_for_create(context, router["router"])
with context.session.begin(subtransactions=True):
# Create router in DB
router_db = super(NeutronPluginPLUMgridV2,
self).create_router(context, router)
# Create router on the network controller
try:
# Add Router to VND
LOG.debug(_("PLUMgrid Library: create_router() called"))
self._plumlib.create_router(tenant_id, router_db)
except Exception as err_message:
raise plum_excep.PLUMgridException(err_msg=err_message)
# Return created router
return router_db
def update_router(self, context, router_id, router):
LOG.debug(_("Neutron PLUMgrid Director: update_router() called"))
with context.session.begin(subtransactions=True):
router_db = super(NeutronPluginPLUMgridV2,
self).update_router(context, router_id, router)
try:
LOG.debug(_("PLUMgrid Library: update_router() called"))
self._plumlib.update_router(router_db, router_id)
except Exception as err_message:
raise plum_excep.PLUMgridException(err_msg=err_message)
# Return updated router
return router_db
def delete_router(self, context, router_id):
LOG.debug(_("Neutron PLUMgrid Director: delete_router() called"))
with context.session.begin(subtransactions=True):
orig_router = self._get_router(context, router_id)
tenant_id = orig_router["tenant_id"]
super(NeutronPluginPLUMgridV2, self).delete_router(context,
router_id)
try:
LOG.debug(_("PLUMgrid Library: delete_router() called"))
self._plumlib.delete_router(tenant_id, router_id)
except Exception as err_message:
raise plum_excep.PLUMgridException(err_msg=err_message)
def add_router_interface(self, context, router_id, interface_info):
LOG.debug(_("Neutron PLUMgrid Director: "
"add_router_interface() called"))
with context.session.begin(subtransactions=True):
# Validate args
router_db = self._get_router(context, router_id)
tenant_id = router_db['tenant_id']
# Create interface in DB
int_router = super(NeutronPluginPLUMgridV2,
self).add_router_interface(context,
router_id,
interface_info)
port_db = self._get_port(context, int_router['port_id'])
subnet_id = port_db["fixed_ips"][0]["subnet_id"]
subnet_db = super(NeutronPluginPLUMgridV2,
self)._get_subnet(context, subnet_id)
ipnet = netaddr.IPNetwork(subnet_db['cidr'])
# Create interface on the network controller
try:
LOG.debug(_("PLUMgrid Library: add_router_interface() called"))
self._plumlib.add_router_interface(tenant_id, router_id,
port_db, ipnet)
except Exception as err_message:
raise plum_excep.PLUMgridException(err_msg=err_message)
return int_router
def remove_router_interface(self, context, router_id, int_info):
LOG.debug(_("Neutron PLUMgrid Director: "
"remove_router_interface() called"))
with context.session.begin(subtransactions=True):
# Validate args
router_db = self._get_router(context, router_id)
tenant_id = router_db['tenant_id']
if 'port_id' in int_info:
port = self._get_port(context, int_info['port_id'])
net_id = port['network_id']
elif 'subnet_id' in int_info:
subnet_id = int_info['subnet_id']
subnet = self._get_subnet(context, subnet_id)
net_id = subnet['network_id']
# Remove router in DB
del_int_router = super(NeutronPluginPLUMgridV2,
self).remove_router_interface(context,
router_id,
int_info)
try:
LOG.debug(_("PLUMgrid Library: "
"remove_router_interface() called"))
self._plumlib.remove_router_interface(tenant_id,
net_id, router_id)
except Exception as err_message:
raise plum_excep.PLUMgridException(err_msg=err_message)
return del_int_router
def create_floatingip(self, context, floatingip):
LOG.debug(_("Neutron PLUMgrid Director: create_floatingip() called"))
try:
floating_ip = None
floating_ip = super(NeutronPluginPLUMgridV2,
self).create_floatingip(context, floatingip)
LOG.debug(_("PLUMgrid Library: create_floatingip() called"))
self._plumlib.create_floatingip(floating_ip)
return floating_ip
except Exception as err_message:
if floating_ip is not None:
self.delete_floatingip(context, floating_ip["id"])
raise plum_excep.PLUMgridException(err_msg=err_message)
def update_floatingip(self, context, id, floatingip):
LOG.debug(_("Neutron PLUMgrid Director: update_floatingip() called"))
try:
floating_ip_orig = super(NeutronPluginPLUMgridV2,
self).get_floatingip(context, id)
floating_ip = super(NeutronPluginPLUMgridV2,
self).update_floatingip(context, id,
floatingip)
LOG.debug(_("PLUMgrid Library: update_floatingip() called"))
self._plumlib.update_floatingip(floating_ip_orig, floating_ip,
id)
return floating_ip
except Exception as err_message:
if floatingip['floatingip']['port_id']:
self.disassociate_floatingips(context,
floatingip['floatingip']['port_id'],
do_notify=False)
raise plum_excep.PLUMgridException(err_msg=err_message)
def delete_floatingip(self, context, id):
LOG.debug(_("Neutron PLUMgrid Director: delete_floatingip() called"))
floating_ip_orig = super(NeutronPluginPLUMgridV2,
self).get_floatingip(context, id)
try:
LOG.debug(_("PLUMgrid Library: delete_floatingip() called"))
self._plumlib.delete_floatingip(floating_ip_orig, id)
except Exception as err_message:
raise plum_excep.PLUMgridException(err_msg=err_message)
super(NeutronPluginPLUMgridV2, self).delete_floatingip(context, id)
def disassociate_floatingips(self, context, port_id, do_notify=True):
LOG.debug(_("Neutron PLUMgrid Director: disassociate_floatingips() "
"called"))
try:
fip_qry = context.session.query(l3_db.FloatingIP)
floating_ip = fip_qry.filter_by(fixed_port_id=port_id).one()
LOG.debug(_("PLUMgrid Library: disassociate_floatingips()"
" called"))
self._plumlib.disassociate_floatingips(floating_ip, port_id)
except sa_exc.NoResultFound:
pass
except Exception as err_message:
raise plum_excep.PLUMgridException(err_msg=err_message)
return super(NeutronPluginPLUMgridV2,
self).disassociate_floatingips(
context, port_id, do_notify=do_notify)
def create_security_group(self, context, security_group, default_sg=False):
"""Create a security group
Create a new security group, including the default security group
"""
LOG.debug("Neutron PLUMgrid Director: create_security_group()"
" called")
with context.session.begin(subtransactions=True):
sg = security_group.get('security_group')
tenant_id = self._get_tenant_id_for_create(context, sg)
if not default_sg:
self._ensure_default_security_group(context, tenant_id)
sg_db = super(NeutronPluginPLUMgridV2,
self).create_security_group(context, security_group,
default_sg)
try:
LOG.debug("PLUMgrid Library: create_security_group()"
" called")
self._plumlib.create_security_group(sg_db)
except Exception as err_message:
raise plum_excep.PLUMgridException(err_msg=err_message)
return sg_db
def update_security_group(self, context, sg_id, security_group):
"""Update a security group
Update security group name/description in Neutron and PLUMgrid
platform
"""
with context.session.begin(subtransactions=True):
sg_db = (super(NeutronPluginPLUMgridV2,
self).update_security_group(context,
sg_id,
security_group))
if ('name' in security_group['security_group'] and
sg_db['name'] != 'default'):
try:
LOG.debug("PLUMgrid Library: update_security_group()"
" called")
self._plumlib.update_security_group(sg_db)
except Exception as err_message:
raise plum_excep.PLUMgridException(err_msg=err_message)
return sg_db
def delete_security_group(self, context, sg_id):
"""Delete a security group
Delete security group from Neutron and PLUMgrid Platform
:param sg_id: security group ID of the rule to be removed
"""
with context.session.begin(subtransactions=True):
sg = super(NeutronPluginPLUMgridV2, self).get_security_group(
context, sg_id)
if not sg:
raise sec_grp.SecurityGroupNotFound(id=sg_id)
if sg['name'] == 'default' and not context.is_admin:
raise sec_grp.SecurityGroupCannotRemoveDefault()
sec_grp_ip = sg['id']
filters = {'security_group_id': [sec_grp_ip]}
if super(NeutronPluginPLUMgridV2,
self)._get_port_security_group_bindings(context,
filters):
raise sec_grp.SecurityGroupInUse(id=sec_grp_ip)
sec_db = super(NeutronPluginPLUMgridV2,
self).delete_security_group(context, sg_id)
try:
LOG.debug("PLUMgrid Library: delete_security_group()"
" called")
self._plumlib.delete_security_group(sg)
except Exception as err_message:
raise plum_excep.PLUMgridException(err_msg=err_message)
return sec_db
def create_security_group_rule(self, context, security_group_rule):
"""Create a security group rule
Create a security group rule in Neutron and PLUMgrid Platform
"""
LOG.debug("Neutron PLUMgrid Director: create_security_group_rule()"
" called")
bulk_rule = {'security_group_rules': [security_group_rule]}
return self.create_security_group_rule_bulk(context, bulk_rule)[0]
def create_security_group_rule_bulk(self, context, security_group_rule):
"""Create security group rules
Create security group rules in Neutron and PLUMgrid Platform
:param security_group_rule: list of rules to create
"""
sg_rules = security_group_rule.get('security_group_rules')
with context.session.begin(subtransactions=True):
sg_id = super(NeutronPluginPLUMgridV2,
self)._validate_security_group_rules(
context, security_group_rule)
# Check to make sure security group exists
security_group = super(NeutronPluginPLUMgridV2,
self).get_security_group(context,
sg_id)
if not security_group:
raise sec_grp.SecurityGroupNotFound(id=sg_id)
# Check for duplicate rules
self._check_for_duplicate_rules(context, sg_rules)
sec_db = (super(NeutronPluginPLUMgridV2,
self).create_security_group_rule_bulk_native(
context, security_group_rule))
try:
LOG.debug(_("PLUMgrid Library: create_security_"
"group_rule_bulk() called"))
self._plumlib.create_security_group_rule_bulk(sec_db)
except Exception as err_message:
raise plum_excep.PLUMgridException(err_msg=err_message)
return sec_db
def delete_security_group_rule(self, context, sgr_id):
"""Delete a security group rule
Delete a security group rule in Neutron and PLUMgrid Platform
"""
LOG.debug("Neutron PLUMgrid Director: delete_security_group_rule()"
" called")
sgr = (super(NeutronPluginPLUMgridV2,
self).get_security_group_rule(context, sgr_id))
if not sgr:
raise sec_grp.SecurityGroupRuleNotFound(id=sgr_id)
super(NeutronPluginPLUMgridV2,
self).delete_security_group_rule(context, sgr_id)
try:
LOG.debug("PLUMgrid Library: delete_security_"
"group_rule() called")
self._plumlib.delete_security_group_rule(sgr)
except Exception as err_message:
raise plum_excep.PLUMgridException(err_msg=err_message)
"""
Internal PLUMgrid Functions
"""
def _get_plugin_version(self):
return VERSION
def _port_viftype_binding(self, context, port):
port[portbindings.VIF_TYPE] = portbindings.VIF_TYPE_IOVISOR
port[portbindings.VIF_DETAILS] = {
# TODO(rkukura): Replace with new VIF security details
portbindings.CAP_PORT_FILTER:
'security-group' in self.supported_extension_aliases}
return port
def _network_admin_state(self, network):
if network["network"].get("admin_state_up") is False:
LOG.warning("Networks with admin_state_up=False are not "
"supported by PLUMgrid plugin yet.")
return network
def _allocate_pools_for_subnet(self, context, subnet):
"""Create IP allocation pools for a given subnet
Pools are defined by the 'allocation_pools' attribute,
a list of dict objects with 'start' and 'end' keys for
defining the pool range.
Modified from Neutron DB based class
"""
pools = []
# Auto allocate the pool around gateway_ip
net = netaddr.IPNetwork(subnet['cidr'])
boundary = int(netaddr.IPAddress(subnet['gateway_ip'] or net.last))
potential_dhcp_ip = int(net.first + 1)
if boundary == potential_dhcp_ip:
first_ip = net.first + 3
boundary = net.first + 2
else:
first_ip = net.first + 2
last_ip = net.last - 1
# Use the gw_ip to find a point for splitting allocation pools
# for this subnet
split_ip = min(max(boundary, net.first), net.last)
if split_ip > first_ip:
pools.append({'start': str(netaddr.IPAddress(first_ip)),
'end': str(netaddr.IPAddress(split_ip - 1))})
if split_ip < last_ip:
pools.append({'start': str(netaddr.IPAddress(split_ip + 1)),
'end': str(netaddr.IPAddress(last_ip))})
# return auto-generated pools
# no need to check for their validity
return pools

View File

@ -0,0 +1,23 @@
# neutron-rootwrap command filters for nodes on which neutron is
# expected to control network
#
# This file should be owned by (and only-writeable by) the root user
# format seems to be
# cmd-name: filter-name, raw-command, user, args
[Filters]
# neutron/agent/linux/iptables_manager.py
# "iptables-save", ...
python: CommandFilter, python, root
ip: CommandFilter, ip, root
kill: CommandFilter, kill, root
rm: CommandFilter, rm, root
ifc_ctl: CommandFilter, /opt/pg/bin/ifc_ctl, root, ifc_ctl
neutron-ns-metadata-proxy: CommandFilter, /usr/bin/neutron-ns-metadata-proxy, root
pg-local-metadata: CommandFilter, /usr/local/bin/pg-local-metadata, pg-local-metadata, root
pg-tunnel-metadata: CommandFilter, /usr/local/bin/pg-tunnel-metadata, pg-tunnel-metadata, root
ping: RegExpFilter, /bin/ping, root, ping, -w, \d+, -c, \d+, [0-9\.]+
ping: IpNetnsExecFilter, ping, root
ping: CommandFilter, ping, root

View File

@ -0,0 +1,118 @@
# Copyright 2013 PLUMgrid, Inc. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
#
# @author: Fawad Khaliq, fawad@plumgrid.com, PLUMgrid, Inc.
"""
Neutron Plug-in for PLUMgrid Virtual Networking Infrastructure (VNI)
This plugin will forward authenticated REST API calls
to the PLUMgrid Network Management System called Director
"""
from plumgridlib import plumlib
from neutron.openstack.common import log as logging
LOG = logging.getLogger(__name__)
class Plumlib(object):
"""
Class PLUMgrid Python Library. This library is a third-party tool
needed by PLUMgrid plugin to implement all core API in Neutron.
"""
def __init__(self):
LOG.info(_('Python PLUMgrid Library Started '))
def director_conn(self, director_plumgrid, director_port, timeout,
director_admin, director_password):
self.plumlib = plumlib.Plumlib(director_plumgrid,
director_port,
timeout,
director_admin,
director_password)
def create_network(self, tenant_id, net_db, network):
self.plumlib.create_network(tenant_id, net_db, network)
def update_network(self, tenant_id, net_id, network):
self.plumlib.update_network(tenant_id, net_id, network)
def delete_network(self, net_db, net_id):
self.plumlib.delete_network(net_db, net_id)
def create_subnet(self, sub_db, net_db, ipnet):
self.plumlib.create_subnet(sub_db, net_db, ipnet)
def update_subnet(self, orig_sub_db, new_sub_db, ipnet):
self.plumlib.update_subnet(orig_sub_db, new_sub_db, ipnet)
def delete_subnet(self, tenant_id, net_db, net_id):
self.plumlib.delete_subnet(tenant_id, net_db, net_id)
def create_port(self, port_db, router_db):
self.plumlib.create_port(port_db, router_db)
def update_port(self, port_db, router_db):
self.plumlib.update_port(port_db, router_db)
def delete_port(self, port_db, router_db):
self.plumlib.delete_port(port_db, router_db)
def create_router(self, tenant_id, router_db):
self.plumlib.create_router(tenant_id, router_db)
def update_router(self, router_db, router_id):
self.plumlib.update_router(router_db, router_id)
def delete_router(self, tenant_id, router_id):
self.plumlib.delete_router(tenant_id, router_id)
def add_router_interface(self, tenant_id, router_id, port_db, ipnet):
self.plumlib.add_router_interface(tenant_id, router_id, port_db, ipnet)
def remove_router_interface(self, tenant_id, net_id, router_id):
self.plumlib.remove_router_interface(tenant_id, net_id, router_id)
def create_floatingip(self, floating_ip):
self.plumlib.create_floatingip(floating_ip)
def update_floatingip(self, floating_ip_orig, floating_ip, id):
self.plumlib.update_floatingip(floating_ip_orig, floating_ip, id)
def delete_floatingip(self, floating_ip_orig, id):
self.plumlib.delete_floatingip(floating_ip_orig, id)
def disassociate_floatingips(self, floating_ip, port_id):
self.plumlib.disassociate_floatingips(floating_ip, port_id)
def create_security_group(self, sg_db):
self.plumlib.create_security_group(sg_db)
def update_security_group(self, sg_db):
self.plumlib.update_security_group(sg_db)
def delete_security_group(self, sg_db):
self.plumlib.delete_security_group(sg_db)
def create_security_group_rule(self, sg_rule_db):
self.plumlib.create_security_group_rule(sg_rule_db)
def create_security_group_rule_bulk(self, sg_rule_db):
self.plumlib.create_security_group_rule_bulk(sg_rule_db)
def delete_security_group_rule(self, sg_rule_db):
self.plumlib.delete_security_group_rule(sg_rule_db)

View File

@ -0,0 +1,156 @@
#
# Copyright (c) 2012-2015, PLUMgrid, http://plumgrid.com
#
#- include: plumgrid_packages.yml
# when: enable_plumgrid == True
# Create a PLUMgrid sources.list
- name: Create plumgrid sources.list
lineinfile:
dest: /etc/apt/sources.list.d/plumgrid.list
line: "deb {{ plumgrid_repo }}/plumgrid ./"
state: present
create: yes
# Create a PLUMgrid sources.list
- name: Add plumgrid-images to repo
lineinfile:
dest: /etc/apt/sources.list.d/plumgrid.list
line: "deb {{ plumgrid_repo }}/plumgrid-images ./"
state: present
# Copy GPG-key file to target nodes
- name: Copy Plumgrid GPG-key file
command: apt-key adv --keyserver keyserver.ubuntu.com --recv 63F65885554E46B2
# Update repositories
- name: Running apt-update
apt:
update_cache: yes
# for compute hosts
- name: Create nova ifc_ctl_sudoers file
lineinfile:
dest: /etc/sudoers.d/ifc_ctl_sudoers
line: "nova ALL=(root) NOPASSWD: /opt/pg/bin/ifc_ctl_pp *"
state: present
create: yes
owner: root
mode: "644"
when: inventory_hostname in groups['compute']
# Install package iovisor-dkms
- name: Install iovisor
apt:
name: iovisor-dkms
state: present
force: yes
# Install package plumgrid-lxc
- name: Install plumgrid-lxc
apt:
name: plumgrid-lxc
state: present
force: yes
# Install package nova-network
- name: Install nova-network
apt:
name: nova-network
state: present
force: yes
when: inventory_hostname in groups['compute']
- name: Disable nova-network
service:
name: nova-network
enabled: no
when: inventory_hostname in groups['compute']
- name: Stop nova-network
service:
name: nova-network
state: stopped
when: inventory_hostname in groups['compute']
# Remove openvswitch
- name: Remove openvswitch
apt:
state: absent
force: yes
name: "{{ item }}"
with_items:
- openvswitch-common
- openvswitch-datapath-dkms
# Modify template fies
- name: Setup Keepalived Config on Controller
template:
src: keepalived.conf
dest: /var/lib/libvirt/filesystems/plumgrid/etc/keepalived/keepalived.conf
when: inventory_hostname in groups['controller']
- name: Setup nginx Config
template:
src: default.conf
dest: /var/lib/libvirt/filesystems/plumgrid/opt/pg/sal/nginx/conf.d/default.conf
- name: Setup plumgrid Conf
template:
src: plumgrid.conf
dest: /var/lib/libvirt/filesystems/plumgrid/opt/pg/etc/plumgrid.conf
- name: Update qemu settings for compute hosts
template:
src: qemu.conf
dest: /etc/libvirt/qemu.conf
when: inventory_hostname in groups['compute']
# Update hostname
- name: Update Plumgrid hostname
replace:
dest: "/var/lib/libvirt/filesystems/plumgrid-data/conf/etc/hostname"
replace: "pg-{{ inventory_hostname }}"
regexp: "plumgrid"
# Update hosts
- name: Update /etc/hosts
replace:
dest: "/var/lib/libvirt/filesystems/plumgrid-data/conf/etc/hosts"
replace: "pg-{{ inventory_hostname }}"
regexp: "plumgrid"
- name: Create ifcs file
lineinfile:
dest: "/var/lib/libvirt/filesystems/plumgrid-data/conf/pg/ifcs.conf"
line: "{{ fabric_interface }} = fabric_core host"
create: yes
- name: Add gateway int to network node
lineinfile:
dest: "/var/lib/libvirt/filesystems/plumgrid-data/conf/pg/ifcs.conf"
line: "{{ ext_interface }} = access_phys"
create: yes
when: inventory_hostname in groups['network']
- name: Set mtu to 1580 in config file
lineinfile:
dest: "/etc/network/interfaces"
line: " mtu 1580"
create: yes
insertafter: "^iface {{ fabric_interface }}"
- name: Set mtu to 1580 now
command: "ifconfig {{ fabric_interface }} mtu 1580"
- name: Ensure PLUMgrid services are started
service:
name: plumgrid
state: started
- name: Restart libvirt-bin
service:
name: libvirt-bin
state: restarted
pattern: libvirt-bin

View File

@ -0,0 +1,143 @@
upstream sal {
server unix:/opt/pg/tmp/sal-web.socket;
keepalive 16;
}
upstream websocket {
server unix:/opt/pg/tmp/sal-ws.socket;
keepalive 16;
}
upstream pgCli {
server {{ nginx_virtual_ip }}:3000;
}
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
lua_socket_log_errors off;
#lua_code_cache off;
lua_shared_dict rest_servers 16K;
lua_shared_dict apache_servers 16K;
lua_shared_dict tc_servers 16K;
init_by_lua 'lb = require "lb"
init_servers = {
["{{ real1 }}"] = true,
{% if real2 is defined %}
["{{ real2 }}"] = true,
{% endif %}
{% if real3 is defined %}
["{{ real3 }}"] = true,
{% endif %}
}';
# Redirect http to https
server {
listen {{ nginx_virtual_ip }}:9080;
server_name $hostname;
return 301 https://$host$request_uri;
}
server {
listen {{ nginx_virtual_ip }}:443 ssl;
ssl_protocols SSLv3 TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers AES128-SHA:AES256-SHA:RC4-SHA:DES-CBC3-SHA:RC4-MD5;
ssl_certificate /opt/pg/sal/nginx/ssl/default.crt;
ssl_certificate_key /opt/pg/sal/nginx/ssl/default.key;
#ssl_session_cache shared:SSL:10m;
#ssl_session_timeout 10m;
server_name $hostname;
root /opt/pg/web;
index login.html;
location /cli/ {
proxy_pass http://pgCli/;
proxy_redirect off;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
}
location /vtap/ {
alias /opt/pg/vtap;
}
# REST API calls start with /v[0-9]/, a keyword, or a capital letter.
# Note: Regular expressions have higher precedence than prefix matches
# so don't combine with /0/...
location ~ ^/(v[0-9]/|pg/|docs|api-docs|[A-Z]) {
set $active_upstream "http://sal";
access_by_lua 'if ngx.req.get_uri_args()["server"]~=nil then
if ngx.req.get_uri_args()["server"]~=ngx.var.host then
ngx.var.active_upstream = "https://"..ngx.req.get_uri_args()["server"]..ngx.var.request_uri
end
end';
proxy_pass $active_upstream;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
location /0/ {
set $active_upstream "http://sal";
access_by_lua 'if ngx.req.get_uri_args()["server"]~=nil then
if ngx.req.get_uri_args()["server"]~=ngx.var.host then
ngx.var.active_upstream = "https://"..ngx.req.get_uri_args()["server"]..ngx.var.request_uri
end
end';
proxy_pass $active_upstream;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
location /0/websocket {
set $active_upstream "http://websocket";
access_by_lua 'if ngx.req.get_uri_args()["server"]~=nil then
if ngx.req.get_uri_args()["server"]~=ngx.var.host then
ngx.var.active_upstream = "https://"..ngx.req.get_uri_args()["server"]..ngx.var.request_uri
end
end';
proxy_pass $active_upstream;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
}
}
server {
listen unix:/opt/pg/tmp/sal-rest.socket;
# debug socket
listen 127.0.0.1:9080;
location / {
set $active_upstream "";
access_by_lua 'ngx.var.active_upstream = find_next(ngx.shared.rest_servers, {{ rest_port }})';
proxy_pass http://$active_upstream:{{ rest_port }};
}
location /_debug/rest_servers {
access_by_lua 'find_next(ngx.shared.rest_servers, {{ rest_port }})';
content_by_lua '
for _, ip in pairs(ngx.shared.rest_servers:get_keys()) do
ngx.say(ip.."="..ngx.shared.rest_servers:get(ip))
end
';
}
location /_debug/tc_servers {
access_by_lua 'find_next(ngx.shared.tc_servers, 12349)';
content_by_lua '
for _, ip in pairs(ngx.shared.tc_servers:get_keys()) do
ngx.say(ip.."="..ngx.shared.tc_servers:get(ip))
end
';
}
}

View File

@ -0,0 +1,30 @@
global_defs {
router_id {{ hostname }}
}
vrrp_script chk_nginx {
script "killall -0 nginx"
interval 2
}
vrrp_instance nos {
virtual_router_id {{ keepalived_router_id }}
# for electing MASTER, highest priority wins.
priority {{ keepalived_priority }}
state BACKUP
nopreempt
interface {{ management_bridge }}
virtual_ipaddress {
{{ pg_vip }} dev {{ management_bridge }} label {{ management_bridge }}:1
}
track_script {
chk_nginx
}
authentication {
auth_type PASS
auth_pass {{ keepalived_password }}
}
}

View File

@ -0,0 +1,10 @@
plumgrid_ip={{ plumgrid_ip }}
plumgrid_port={{ plumgrid_port }}
mgmt_dev={{ management_bridge }}
label={{ inventory_hostname }}
plumgrid_rsync_port=2222
plumgrid_rest_addr=0.0.0.0:{{ rest_port }}
fabric_mode={{ fabric_mode }}
start_plumgrid_iovisor=yes
start_plumgrid=`/opt/pg/scripts/pg_is_director.sh $plumgrid_ip`
location=

View File

@ -0,0 +1,27 @@
# This file is managed by Managed by Ansible
# This is the basic set of devices allowed / required by
# all virtual machines.
#
cgroup_device_acl = [
"/dev/null", "/dev/full", "/dev/zero",
"/dev/random", "/dev/urandom",
"/dev/ptmx", "/dev/kvm", "/dev/kqemu",
"/dev/rtc","/dev/hpet", "/dev/vfio/vfio",
"/dev/net/tun"
]
# If clear_emulator_capabilities is enabled, libvirt will drop all
# privileged capabilities of the QEmu/KVM emulator. This is enabled by
# default.
clear_emulator_capabilities=0
# The user for QEMU processes run by the system instance. It can be
# specified as a user name or as a user id. The qemu driver will try to
# parse this value first as a name and then, if the name doesn't exist,
# as a user id.
#
user="root"
# The group for QEMU processes run by the system instance.
group="root"