Add quantum/neutron support to openstack-compute

This commit introduces a new node attribute which will
turn off nova-networking and enable quantum/neutron
style networking and install the appropriate dependant
packages.

Change-Id: Ia9dadf736e6e916f4b25c202cb88cb8a030d54c0
This commit is contained in:
Alan Meadows 2013-07-30 11:18:54 -07:00
parent 64d9a4e168
commit f256a391ea
12 changed files with 281 additions and 97 deletions

View File

@ -6,5 +6,7 @@ cookbook "openstack-identity",
git: "git://github.com/stackforge/cookbook-openstack-identity.git"
cookbook "openstack-common",
git: "git://github.com/stackforge/cookbook-openstack-common.git"
cookbook "openstack-network",
git: "git://github.com/stackforge/cookbook-openstack-network.git"
cookbook "sysctl",
git: "git://github.com/Fewbytes/sysctl-cookbook.git"

View File

@ -76,6 +76,27 @@ default["openstack"]["compute"]["region"] = "RegionOne"
default["openstack"]["compute"]["floating_cmd"] = "/usr/local/bin/add_floaters.py"
# Support multiple network types. Default network type is "nova"
# with the other option supported being "quantum"
default["openstack"]["compute"]["network"]["service_type"] = "nova"
# if the network type is not nova, we will load the following
# plugins from openstack-network
default["openstack"]["compute"]["network"]["plugins"] = ["openvswitch", "dhcp_agent"]
# Quantum options
default["openstack"]["compute"]["network"]["quantum"]["network_api_class"] = "nova.network.quantumv2.api.API"
default["openstack"]["compute"]["network"]["quantum"]["auth_strategy"] = "keystone"
default["openstack"]["compute"]["network"]["quantum"]["admin_tenant_name"] = "service"
default["openstack"]["compute"]["network"]["quantum"]["admin_username"] = "quantum"
default["openstack"]["compute"]["network"]["quantum"]["libvirt_vif_driver"] = "nova.virt.libvirt.vif.LibvirtHybridOVSBridgeDriver"
default["openstack"]["compute"]["network"]["quantum"]["linuxnet_interface_driver"] = "nova.network.linux_net.LinuxOVSInterfaceDriver"
default["openstack"]["compute"]["network"]["quantum"]["security_group_api"] = "quantum"
default["openstack"]["compute"]["network"]["quantum"]["service_quantum_metadata_proxy"] = true
default["openstack"]["compute"]["network"]["quantum"]["metadata_secret_name"] = "quantum_metadata_shared_secret"
default["openstack"]["compute"]["network"]["quantum"]["public_network_name"] = "public"
default["openstack"]["compute"]["network"]["quantum"]["dns_server"] = "8.8.8.8"
# TODO(shep): This should probably be ["openstack"]["compute"]["network"]["fixed"]
default["openstack"]["compute"]["networks"] = [
{

View File

@ -1,7 +1,7 @@
#! /usr/bin/env python
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2012 AT&T
# Copyright 2013 AT&T Services, Inc.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
@ -21,7 +21,7 @@ import subprocess
import netaddr
DESCRIPTION = "A `nova-manage floating create` wrapper."
DESCRIPTION = "A `nova-manage floating create` and `quantum net create` wrapper."
class FloatingAddress(object):
@ -37,19 +37,16 @@ class FloatingAddress(object):
self._pool = args.pool
self._interface = args.interface
def _add_cidr(self, cidr):
def nova_add_cidr(self, cidr):
"""
Validates the provided cider address, and passes it to nova-manage.
:param cidr: A string containing a valid CIDR address.
"""
try:
netaddr.IPNetwork(cidr)
self._add_floating(cidr)
except netaddr.core.AddrFormatError:
raise
netaddr.IPNetwork(cidr)
self.nova_add_floating(cidr)
def _add_range(self, start, end):
def nova_add_range(self, start, end):
"""
Takes a start and end range, and creates individual host addresses.
@ -58,9 +55,9 @@ class FloatingAddress(object):
"""
ip_list = list(netaddr.iter_iprange(start, end))
for ip in ip_list:
self._add_floating(ip)
self.nova_add_floating(ip)
def _add_floating(self, ip):
def nova_add_floating(self, ip):
cmd = "nova-manage floating create --ip_range={0}".format(ip)
if self._pool:
cmd += ' --pool={0}'.format(self._pool)
@ -69,28 +66,68 @@ class FloatingAddress(object):
subprocess.check_call(cmd, shell=True)
def _parse_args():
def neutron_add_floating(self, cidr):
# convert cidr string to IPNetwork object
cidr = netaddr.IPNetwork(cidr)
# ensure we have a public network and we only ever create one
cmd = "if ! quantum net-show public; then quantum net-create %s -- --router:external=True; fi" % self._pool
subprocess.check_call(cmd, shell=True)
# calculate the start and end values
ip_start = cidr.ip
ip_end = netaddr.IPAddress(cidr.last-1)
# create a new subnet
cmd = "quantum subnet-create --allocation-pool start=%s,end=%s %s %s -- --enable_dhcp=False" % \
(ip_start, ip_end, self._pool, cidr)
subprocess.check_call(cmd, shell=True)
def parse_args():
ap = argparse.ArgumentParser(description=DESCRIPTION)
ap.add_argument('--pool',
help="Name of the floating pool")
ap.add_argument('--interface',
help="Network interface to bring the floating "
"addresses up on")
group = ap.add_mutually_exclusive_group()
subparsers = ap.add_subparsers(help='sub-command help')
# create the parser for the "nova" command
parser_nova = subparsers.add_parser('nova', help='Use Nova Backend')
parser_nova.add_argument('--pool',
required=True,
help="Name of the floating pool")
parser_nova.add_argument('--interface',
required=False,
help="Network interface to bring the floating "
"addresses up on")
group = parser_nova.add_mutually_exclusive_group(required=True)
group.add_argument('--cidr',
help="A CIDR notation of addresses to add "
"(e.g. 192.168.0.0/24)")
group.add_argument('--ip-range',
help="A range of addresses to add "
"(e.g. 192.168.0.10,192.168.0.50)")
# create the parser for the "neutron command"
parser_neutron = subparsers.add_parser('neutron', help='Use Neutron Backend')
parser_neutron.add_argument('--cidr',
required=True,
help="A CIDR notation of addresses to add "
"(e.g. 192.168.0.11/24 to start at .11 "
"and end at .254)")
parser_neutron.add_argument('--pool',
required=True,
help="Name of the public network")
return ap.parse_args()
if __name__ == '__main__':
args = _parse_args()
args = parse_args()
fa = FloatingAddress(args)
if args.cidr:
fa._add_cidr(args.cidr)
elif args.ip_range:
start, end = args.ip_range.split(',')
fa._add_range(start, end)
if args.nova:
if args.cidr:
fa.nova_add_cidr(args.cidr)
elif args.ip_range:
start, end = args.ip_range.split(',')
fa.nova_add_range(start, end)
elif args.neutron:
fa.neutron_add_cidr(args.cidr)

View File

@ -27,6 +27,7 @@ depends "apache2"
depends "openstack-common", "~> 0.4.0"
depends "openstack-identity", "~> 7.0.0"
depends "openstack-image", "~> 7.0.0"
depends "openstack-network", "~> 7.0.0"
depends "selinux"
depends "sysctl"
depends "yum"

View File

@ -22,18 +22,31 @@ include_recipe "openstack-compute::nova-common"
platform_options = node["openstack"]["compute"]["platform"]
platform_options["compute_network_packages"].each do |pkg|
package pkg do
options platform_options["package_overrides"]
# the only type of network we process here is nova, otherwise for
# quantum, the network will be setup by the inclusion of
# openstack-network recipes
action :upgrade
if node["openstack"]["compute"]["network"]["service_type"] == "nova"
platform_options["compute_network_packages"].each do |pkg|
package pkg do
options platform_options["package_overrides"]
action :upgrade
end
end
end
service "nova-network" do
service_name platform_options["compute_network_service"]
supports :status => true, :restart => true
subscribes :restart, resources("template[/etc/nova/nova.conf]")
service "nova-network" do
service_name platform_options["compute_network_service"]
supports :status => true, :restart => true
subscribes :restart, resources("template[/etc/nova/nova.conf]")
action :enable
end
else
node["openstack"]["compute"]["network"]["plugins"].each do |plugin|
include_recipe "openstack-network::#{plugin}"
end
action :enable
end

View File

@ -90,6 +90,7 @@ xvpvnc_endpoint = endpoint "compute-xvpvnc" || {}
novnc_endpoint = endpoint "compute-novnc" || {}
compute_api_endpoint = endpoint "compute-api" || {}
ec2_public_endpoint = endpoint "compute-ec2-api" || {}
network_endpoint = endpoint "network-api" || {}
image_endpoint = endpoint "image-api"
Chef::Log.debug("openstack-compute::nova-common:keystone|#{keystone}")
@ -98,12 +99,21 @@ Chef::Log.debug("openstack-compute::nova-common:xvpvnc_endpoint|#{xvpvnc_endpoin
Chef::Log.debug("openstack-compute::nova-common:novnc_endpoint|#{novnc_endpoint.to_s}")
Chef::Log.debug("openstack-compute::nova-common:compute_api_endpoint|#{::URI.decode compute_api_endpoint.to_s}")
Chef::Log.debug("openstack-compute::nova-common:ec2_public_endpoint|#{ec2_public_endpoint.to_s}")
Chef::Log.debug("openstack-compute::nova-common:network_endpoint|#{network_endpoint.to_s}")
Chef::Log.debug("openstack-compute::nova-common:image_endpoint|#{image_endpoint.to_s}")
vnc_bind_ip = address_for node["openstack"]["compute"]["libvirt"]["bind_interface"]
xvpvnc_proxy_ip = address_for node["openstack"]["compute"]["xvpvnc_proxy"]["bind_interface"]
novnc_proxy_ip = address_for node["openstack"]["compute"]["novnc_proxy"]["bind_interface"]
if node["openstack"]["compute"]["network"]["service_type"] == "quantum"
quantum_admin_password = service_password "openstack-network"
quantum_metadata_proxy_shared_secret = secret "secrets", "quantum_metadata_secret"
else
quantum_admin_password = nil
quantum_metadata_proxy_shared_secret = nil
end
template "/etc/nova/nova.conf" do
source "nova.conf.erb"
owner node["openstack"]["compute"]["user"]
@ -127,7 +137,10 @@ template "/etc/nova/nova.conf" do
:glance_api_port => image_endpoint.port,
:iscsi_helper => platform_options["iscsi_helper"],
:scheduler_default_filters => node["openstack"]["compute"]["scheduler"]["default_filters"].join(","),
:osapi_compute_link_prefix => compute_api_endpoint.to_s
:osapi_compute_link_prefix => compute_api_endpoint.to_s,
:network_endpoint => network_endpoint,
:quantum_admin_password => quantum_admin_password,
:quantum_metadata_proxy_shared_secret => quantum_metadata_proxy_shared_secret
)
end

View File

@ -29,71 +29,106 @@ execute "nova-manage db sync" do
action :run
end
next_vlan = 100
node["openstack"]["compute"]["networks"].each do |net|
execute "nova-manage network create --label=#{net['label']}" do
# The only two required keys in each network Hash
# are "label" and "ipv4_cidr".
cmd = "nova-manage network create --label=#{net['label']} --fixed_range_v4=#{net['ipv4_cidr']}"
if net.has_key?("multi_host")
cmd += " --multi_host='#{net['multi_host']}'"
end
if net.has_key?("num_networks")
cmd += " --num_networks=#{net['num_networks']}"
end
if net.has_key?("network_size")
cmd += " --network_size=#{net['network_size']}"
end
if net.has_key?("bridge")
cmd += " --bridge=#{net['bridge']}"
end
# Older attributes have the key as "bridge_dev" instead
# of "bridge_interface"...
if net.has_key?("bridge_interface") or net.has_key?("bridge_dev")
val = net.has_key?("bridge_interface") ? net["bridge_interface"] : net["bridge_dev"]
cmd += " --bridge_interface=#{val}"
end
if net.has_key?("dns1")
cmd += " --dns1=#{net['dns1']}"
end
if net.has_key?("dns2")
cmd += " --dns2=#{net['dns2']}"
end
if net.has_key?("vlan")
cmd += " --vlan=#{net['vlan']}"
elsif node["openstack"]["compute"]["network"]["network_manager"] == "nova.network.manager.VlanManager"
cmd += " --vlan=#{next_vlan}"
next_vlan = next_vlan + 1
end
case node["openstack"]["compute"]["network"]["service_type"]
when "nova"
command cmd
not_if "nova-manage network list | grep #{net['ipv4_cidr']}"
next_vlan = 100
node["openstack"]["compute"]["networks"].each do |net|
execute "nova-manage network create --label=#{net['label']}" do
# The only two required keys in each network Hash
# are "label" and "ipv4_cidr".
cmd = "nova-manage network create --label=#{net['label']} --fixed_range_v4=#{net['ipv4_cidr']}"
if net.has_key?("multi_host")
cmd += " --multi_host='#{net['multi_host']}'"
end
if net.has_key?("num_networks")
cmd += " --num_networks=#{net['num_networks']}"
end
if net.has_key?("network_size")
cmd += " --network_size=#{net['network_size']}"
end
if net.has_key?("bridge")
cmd += " --bridge=#{net['bridge']}"
end
# Older attributes have the key as "bridge_dev" instead
# of "bridge_interface"...
if net.has_key?("bridge_interface") or net.has_key?("bridge_dev")
val = net.has_key?("bridge_interface") ? net["bridge_interface"] : net["bridge_dev"]
cmd += " --bridge_interface=#{val}"
end
if net.has_key?("dns1")
cmd += " --dns1=#{net['dns1']}"
end
if net.has_key?("dns2")
cmd += " --dns2=#{net['dns2']}"
end
if net.has_key?("vlan")
cmd += " --vlan=#{net['vlan']}"
elsif node["openstack"]["compute"]["network"]["network_manager"] == "nova.network.manager.VlanManager"
cmd += " --vlan=#{next_vlan}"
next_vlan = next_vlan + 1
end
action :run
end
end
command cmd
not_if "nova-manage network list | grep #{net['ipv4_cidr']}"
cookbook_file node["openstack"]["compute"]["floating_cmd"] do
source "add_floaters.py"
mode 00755
action :create
end
floating = node["openstack"]["compute"]["network"]["floating"]
if floating && (floating["ipv4_cidr"] || floating["ipv4_range"])
cmd = ""
if floating["ipv4_cidr"]
cmd = "#{node["openstack"]["compute"]["floating_cmd"]} --cidr=#{floating["ipv4_cidr"]}"
elsif floating["ipv4_range"]
cmd = "#{node["openstack"]["compute"]["floating_cmd"]} --ip-range=#{floating["ipv4_range"]}"
action :run
end
end
execute "nova-manage floating create" do
command cmd
cookbook_file node["openstack"]["compute"]["floating_cmd"] do
source "add_floaters.py"
mode 00755
not_if "nova-manage floating list |grep -E '.*([0-9]{1,3}[\.]){3}[0-9]{1,3}*'"
action :create
end
action :run
floating = node["openstack"]["compute"]["network"]["floating"]
if floating && (floating["ipv4_cidr"] || floating["ipv4_range"])
cmd = ""
if floating["ipv4_cidr"]
cmd = "#{node["openstack"]["compute"]["floating_cmd"]} nova --cidr=#{floating["ipv4_cidr"]}"
elsif floating["ipv4_range"]
cmd = "#{node["openstack"]["compute"]["floating_cmd"]} nova --ip-range=#{floating["ipv4_range"]}"
end
execute "nova-manage floating create" do
command cmd
not_if "nova-manage floating list |grep -E '.*([0-9]{1,3}[\.]){3}[0-9]{1,3}*'"
action :run
end
end
when "quantum", "neutron"
# ensure we have access to the latest version
# of the quantum client which floating_cmd will
# require
include_recipe "python::pip"
python_pip "python-quantumclient" do
action :upgrade
only_if { platform?("ubuntu", "debian") }
end
cookbook_file node["openstack"]["compute"]["floating_cmd"] do
source "add_floaters.py"
mode 00755
action :create
end
floating = node["openstack"]["compute"]["network"]["floating"]
if floating && floating["ipv4_cidr"]
cmd = ". /root/openrc && #{node["openstack"]["compute"]["floating_cmd"]} neutron --cidr=#{floating["ipv4_cidr"]} --pool=#{floating["public_network_name"]}"
execute "quantum floating create" do
command cmd
not_if ". /root/openrc && quantum floatingip-list |grep -E '.*([0-9]{1,3}[\.]){3}[0-9]{1,3}*'"
only_if { File.exists?("/root/openrc") }
action :run
end
end
end

View File

@ -5,6 +5,8 @@ describe "openstack-compute::network" do
describe "ubuntu" do
before do
@chef_run = ::ChefSpec::ChefRunner.new ::UBUNTU_OPTS
@node = @chef_run.node
@node.set["openstack"]["compute"]["network"]["service_type"] = "nova"
@chef_run.converge "openstack-compute::network"
end
@ -18,5 +20,15 @@ describe "openstack-compute::network" do
it "starts nova network on boot" do
expect(@chef_run).to set_service_to_start_on_boot "nova-network"
end
it "includes openstack-network recipes for quantum when service type is quantum" do
@chef_run = ::ChefSpec::ChefRunner.new ::UBUNTU_OPTS
@node = @chef_run.node
@node.set["openstack"]["compute"]["network"]["service_type"] = "quantum"
@chef_run.converge "openstack-compute::network"
expect(@chef_run).to include_recipe "openstack-network::openvswitch"
expect(@chef_run).to include_recipe "openstack-network::dhcp_agent"
end
end
end

View File

@ -24,10 +24,16 @@ describe "openstack-compute::nova-common" do
it "doesn't run logging recipe" do
chef_run = ::ChefSpec::ChefRunner.new ::UBUNTU_OPTS
chef_run.converge "openstack-compute::nova-common"
expect(chef_run).not_to include_recipe "openstack-common::logging"
end
it "can converge with quantum service type" do
chef_run = ::ChefSpec::ChefRunner.new ::UBUNTU_OPTS
node = chef_run.node
node.set["openstack"]["compute"]["network"]["service_type"] = "quantum"
chef_run.converge "openstack-compute::nova-common"
end
it "installs nova common packages" do
expect(@chef_run).to upgrade_package "nova-common"
end

View File

@ -39,7 +39,7 @@ describe "openstack-compute::nova-setup" do
node.set["openstack"]["compute"]["network"]["floating"]["ipv4_cidr"] = "10.10.10.0/24"
chef_run.converge "openstack-compute::nova-setup"
cmd = "/usr/local/bin/add_floaters.py --cidr=10.10.10.0/24"
cmd = "/usr/local/bin/add_floaters.py nova --cidr=10.10.10.0/24"
expect(chef_run).to execute_command cmd
end
@ -53,7 +53,18 @@ describe "openstack-compute::nova-setup" do
}
chef_run.converge "openstack-compute::nova-setup"
cmd = "/usr/local/bin/add_floaters.py --ip-range=10.10.10.1,10.10.10.5"
cmd = "/usr/local/bin/add_floaters.py nova --ip-range=10.10.10.1,10.10.10.5"
expect(chef_run).to execute_command cmd
end
it "adds cidr range of floating ipv4 addresses to neutron" do
chef_run = ::ChefSpec::ChefRunner.new ::UBUNTU_OPTS
node = chef_run.node
node.set["openstack"]["compute"]["network"]["service_type"] = "neutron"
node.set["openstack"]["compute"]["network"]["floating"]["ipv4_cidr"] = "10.10.10.0/24"
node.set["openstack"]["compute"]["network"]["floating"]["public_network_name"] = "public"
chef_run.converge "openstack-compute::nova-setup"
cmd = ". /root/openrc && /usr/local/bin/add_floaters.py neutron --cidr=10.10.10.0/24 --pool=public"
expect(chef_run).to execute_command cmd
end
end

View File

@ -37,6 +37,9 @@ def compute_stubs
::Chef::Recipe.any_instance.stub(:secret).
with("secrets", "openstack_identity_bootstrap_token").
and_return "bootstrap-token"
::Chef::Recipe.any_instance.stub(:secret).
with("secrets", "quantum_metadata_secret").
and_return "metadata-secret"
::Chef::Recipe.any_instance.stub(:db_password).and_return String.new
::Chef::Recipe.any_instance.stub(:user_password).and_return String.new
::Chef::Recipe.any_instance.stub(:user_password).
@ -44,6 +47,8 @@ def compute_stubs
and_return "rabbit-pass"
::Chef::Recipe.any_instance.stub(:service_password).with("openstack-compute").
and_return "nova-pass"
::Chef::Recipe.any_instance.stub(:service_password).with("openstack-network").
and_return "quantum-pass"
::Chef::Recipe.any_instance.stub(:memcached_servers).and_return []
::Chef::Recipe.any_instance.stub(:system).
with("grub2-set-default 'openSUSE GNU/Linux, with Xen hypervisor'").

View File

@ -38,6 +38,32 @@ default_schedule_zone=<%= node["openstack"]["compute"]["config"]["default_schedu
storage_availability_zone=<%= node["openstack"]["compute"]["config"]["storage_availability_zone"] %>
##### NETWORK #####
<% case node["openstack"]["compute"]["network"]["service_type"]
when "quantum" -%>
# N.B. due to https://bugs.launchpad.net/nova/+bug/1206330
# we override the endpoint scheme below, ignore the port
# and essentially force http
network_api_class=<%= node["openstack"]["compute"]["network"]["quantum"]["network_api_class"] %>
quantum_url=http://<%= @network_endpoint.host %>:<%= @network_endpoint.port %>
quantum_auth_strategy=<%= node["openstack"]["compute"]["network"]["quantum"]["auth_strategy"] %>
quantum_admin_tenant_name=<%= node["openstack"]["compute"]["network"]["quantum"]["admin_tenant_name"] %>
quantum_admin_username=<%= node["openstack"]["compute"]["network"]["quantum"]["admin_username"] %>
quantum_admin_password=<%= @quantum_admin_password %>
quantum_admin_auth_url=<%= @identity_endpoint.to_s %>
libvirt_vif_driver=<%= node["openstack"]["compute"]["network"]["quantum"]["libvirt_vif_driver"] %>
linuxnet_interface_driver=<%= node["openstack"]["compute"]["network"]["quantum"]["linuxnet_interface_driver"] %>
firewall_driver = nova.virt.firewall.NoopFirewallDriver
security_group_api=<%= node["openstack"]["compute"]["network"]["quantum"]["security_group_api"] %>
service_quantum_metadata_proxy=<%= node["openstack"]["compute"]["network"]["quantum"]["service_quantum_metadata_proxy"] %>
quantum_metadata_proxy_shared_secret=<%= @quantum_metadata_proxy_shared_secret %>
default_floating_pool=<%= node["openstack"]["compute"]["network"]["quantum"]["public_network_name"] %>
dns_server=<%= node["openstack"]["compute"]["network"]["quantum"]["dns_server"] %>
<% when "nova" -%>
multi_host=<%= node["openstack"]["compute"]["network"]["multi_host"] %>
network_manager=<%= node["openstack"]["compute"]["network"]["network_manager"] %>
public_interface=<%= node["openstack"]["compute"]["network"]["public_interface"] %>
@ -61,6 +87,8 @@ libvirt_use_virtio_for_bridges=true
<% end -%>
vlan_interface=<%= node["openstack"]["compute"]["network"]["vlan_interface"] %>
<% end -%>
##### GLANCE #####
image_service=nova.image.glance.GlanceImageService
glance_api_servers=<%= @glance_api_ipaddress %>:<%= @glance_api_port %>