diff --git a/lib/puppet/provider/neutron_network/neutron.rb b/lib/puppet/provider/neutron_network/neutron.rb index 5ecfeb685..a0addd32a 100644 --- a/lib/puppet/provider/neutron_network/neutron.rb +++ b/lib/puppet/provider/neutron_network/neutron.rb @@ -41,7 +41,8 @@ Puppet::Type.type(:neutron_network).provide( :provider_segmentation_id => attrs['provider:segmentation_id'], :router_external => attrs['router:external'], :shared => attrs['shared'], - :tenant_id => attrs['tenant_id'] + :tenant_id => attrs['tenant_id'], + :availability_zone_hint => attrs['availability_zone_hint'] ) end self.do_not_manage = false @@ -99,6 +100,11 @@ Puppet::Type.type(:neutron_network).provide( network_opts << '--router:external' end + if @resource[:availability_zone_hint] + network_opts << \ + "--availability-zone-hint=#{@resource[:availability_zone_hint]}" + end + results = auth_neutron('net-create', '--format=shell', network_opts, resource[:name]) @@ -114,6 +120,7 @@ Puppet::Type.type(:neutron_network).provide( :router_external => attrs['router:external'], :shared => attrs['shared'], :tenant_id => attrs['tenant_id'], + :availability_zone_hint => attrs['availability_zone_hint'] } end @@ -150,6 +157,13 @@ Puppet::Type.type(:neutron_network).provide( end end + def availability_zone_hint=(value) + if self.class.do_not_manage + fail("Not managing Neutron_network[#{@resource[:name]}] due to earlier Neutron API failures.") + end + auth_neutron('net-update', "--availability-zone-hint=#{value}", name) + end + [ :provider_network_type, :provider_physical_network, diff --git a/lib/puppet/provider/neutron_router/neutron.rb b/lib/puppet/provider/neutron_router/neutron.rb index fdc512ea9..0fc3e5c1a 100644 --- a/lib/puppet/provider/neutron_router/neutron.rb +++ b/lib/puppet/provider/neutron_router/neutron.rb @@ -36,7 +36,8 @@ Puppet::Type.type(:neutron_router).provide( :status => attrs['status'], :distributed => attrs['distributed'], :ha => attrs['ha'], - :tenant_id => attrs['tenant_id'] + :tenant_id => attrs['tenant_id'], + :availability_zone_hint => attrs['availability_zone_hint'] ) end self.do_not_manage = false @@ -83,6 +84,10 @@ Puppet::Type.type(:neutron_router).provide( opts << "--ha=#{@resource[:ha]}" end + if @resource[:availability_zone_hint] + opts << "--availability-zone-hint=#{@resource[:availability_zone_hint]}" + end + results = auth_neutron("router-create", '--format=shell', opts, resource[:name]) @@ -95,6 +100,7 @@ Puppet::Type.type(:neutron_router).provide( :external_gateway_info => attrs['external_gateway_info'], :status => attrs['status'], :tenant_id => attrs['tenant_id'], + :availability_zone_hint => attrs['availability_zone_hint'] } if @resource[:gateway_network_name] @@ -188,4 +194,16 @@ Puppet::Type.type(:neutron_router).provide( end end + def availability_zone_hint=(value) + if self.class.do_not_manage + fail("Not managing Neutron_router[#{@resource[:name]}] due to earlier Neutron API failures.") + end + results = auth_neutron("router-show", '--format=shell', resource[:name]) + attrs = self.class.parse_creation_output(results) + set_admin_state_up(false) + auth_neutron('router-update', "--availability-zone-hint=#{value}", name) + if attrs['admin_state_up'] == 'True' + set_admin_state_up(true) + end + end end diff --git a/lib/puppet/type/neutron_network.rb b/lib/puppet/type/neutron_network.rb index ca4573a1b..84eb4637d 100644 --- a/lib/puppet/type/neutron_network.rb +++ b/lib/puppet/type/neutron_network.rb @@ -69,6 +69,10 @@ Puppet::Type.newtype(:neutron_network) do end end + newproperty(:availability_zone_hint) do + desc 'The availability zone hint to provide the scheduler' + end + # Require the neutron-server service to be running autorequire(:service) do ['neutron-server'] diff --git a/lib/puppet/type/neutron_router.rb b/lib/puppet/type/neutron_router.rb index c29abcbf2..a85d03a41 100644 --- a/lib/puppet/type/neutron_router.rb +++ b/lib/puppet/type/neutron_router.rb @@ -92,6 +92,10 @@ Puppet::Type.newtype(:neutron_router) do end end + newproperty(:availability_zone_hint) do + desc 'The availability zone hint to provide the scheduler' + end + validate do if self[:ensure] != :present return diff --git a/manifests/agents/dhcp.pp b/manifests/agents/dhcp.pp index 3cb93f5a5..bbc26dc24 100644 --- a/manifests/agents/dhcp.pp +++ b/manifests/agents/dhcp.pp @@ -69,6 +69,11 @@ # in the dhcp config. # Defaults to false. # +# [*availability_zone*] +# (optional) The availability zone of the agent. +# Neutron will only schedule dhcp on the agent based on availability zone +# Defaults to $::os_service_default +# # === Deprecated Parameters # # [*dhcp_domain*] @@ -92,6 +97,7 @@ class neutron::agents::dhcp ( $enable_metadata_network = false, $dhcp_broadcast_reply = $::os_service_default, $purge_config = false, + $availability_zone = $::os_service_default, # DEPRECATED PARAMETERS $dhcp_domain = $::os_service_default, ) { @@ -142,6 +148,7 @@ class neutron::agents::dhcp ( 'DEFAULT/dhcp_broadcast_reply': value => $dhcp_broadcast_reply; 'DEFAULT/dnsmasq_config_file': value => $dnsmasq_config_file; 'DEFAULT/dnsmasq_dns_servers': value => join(any2array($dnsmasq_dns_servers), ','); + 'AGENT/availability_zone': value => $availability_zone; } if ! is_service_default ($dhcp_domain) { diff --git a/manifests/agents/l3.pp b/manifests/agents/l3.pp index 2eaf48f18..c6a700ea7 100644 --- a/manifests/agents/l3.pp +++ b/manifests/agents/l3.pp @@ -83,6 +83,11 @@ # in the l3 config. # Defaults to false. # +# [*availability_zone*] +# (optional) The availability zone of the agent. +# Neutron will only schedule routers on the agent based on availability zone +# Defaults to $::os_service_default +# # === Deprecated Parameters # # [*external_network_bridge*] @@ -112,6 +117,7 @@ class neutron::agents::l3 ( $ha_vrrp_advert_int = '3', $agent_mode = 'legacy', $purge_config = false, + $availability_zone = $::os_service_default, # DEPRECATED PARAMETERS $external_network_bridge = $::os_service_default, $router_id = $::os_service_default, @@ -152,6 +158,7 @@ class neutron::agents::l3 ( 'DEFAULT/periodic_fuzzy_delay': value => $periodic_fuzzy_delay; 'DEFAULT/enable_metadata_proxy': value => $enable_metadata_proxy; 'DEFAULT/agent_mode': value => $agent_mode; + 'AGENT/availability_zone': value => $availability_zone; } if $::neutron::params::l3_agent_package { diff --git a/manifests/server.pp b/manifests/server.pp index 0158d54a3..0ca85d258 100644 --- a/manifests/server.pp +++ b/manifests/server.pp @@ -154,10 +154,22 @@ # [*lock_path*] # (optional) Deprecated. Use lock_path parameter on base neutron class instead. # +# [*network_scheduler_driver*] +# (optional) The scheduler used when scheduling networks +# neutron.scheduler.dhcp_agent_scheduler.AZAwareWeightScheduler to use availability zone hints scheduling. +# Defaults to $::os_service_default +# +# Example: +# +# class { 'neutron': +# network_scheduler_driver => 'neutron.scheduler.dhcp_agent_scheduler.AZAwareWeightScheduler' +# } +# # [*router_scheduler_driver*] # (optional) Driver to use for scheduling router to a default L3 agent. Could be: # neutron.scheduler.l3_agent_scheduler.ChanceScheduler to schedule a router in a random way # neutron.scheduler.l3_agent_scheduler.LeastRoutersScheduler to allocate on an L3 agent with the least number of routers bound. +# neutron.scheduler.l3_agent_scheduler.AZLeastRoutersScheduler to use availability zone hints. # Defaults to: neutron.scheduler.l3_agent_scheduler.ChanceScheduler # # [*router_distributed*] @@ -166,6 +178,28 @@ # Also can be the type of the router on the create request (admin-only attribute). # Defaults to $::os_service_default # +# [*dhcp_load_type*] +# (optional) The resource type whos load is being reported by the agent. +# The expected values are either 'networks', 'subnets', 'ports'. +# Defaults to $::os_service_default +# +# Example: +# +# class { 'neutron': +# dhcp_load_type => 'networks' +# } +# +# [*default_availability_zones*] +# (optional) A list of availability zones that are picked when availability zone is not specified +# The expected input is an array when specified. +# Defaults to $::os_service_default +# +# Example: +# +# class { 'neutron': +# default_availability_zones => ['zone1', 'zone2'] +# } +# # [*allow_automatic_l3agent_failover*] # (optional) Allow automatic rescheduling of routers from dead L3 agents with # admin_state_up set to True to alive agents. @@ -281,6 +315,9 @@ class neutron::server ( $agent_down_time = $::os_service_default, $router_scheduler_driver = 'neutron.scheduler.l3_agent_scheduler.ChanceScheduler', $router_distributed = $::os_service_default, + $network_scheduler_driver = $::os_service_default, + $dhcp_load_type = $::os_service_default, + $default_availability_zones = $::os_service_default, $allow_automatic_l3agent_failover = $::os_service_default, $l3_ha = false, $max_l3_agents_per_router = 3, @@ -311,6 +348,14 @@ class neutron::server ( # Work-around LP#1551974. neutron requires the keystoneclient to auth tokens include ::keystone::client + if !is_service_default($default_availability_zones) { + validate_array($default_availability_zones) + } + + if !is_service_default($dhcp_load_type) { + validate_re($dhcp_load_type, ['^networks$', '^subnets$', '^ports$'], 'Must pass either networks, subnets, or ports as values for dhcp_load_type') + } + if $ensure_fwaas_package { if ($::osfamily == 'Debian') { # Debian platforms @@ -391,6 +436,9 @@ class neutron::server ( 'DEFAULT/router_scheduler_driver': value => $router_scheduler_driver; 'DEFAULT/router_distributed': value => $router_distributed; 'DEFAULT/allow_automatic_l3agent_failover': value => $allow_automatic_l3agent_failover; + 'DEFAULT/network_scheduler_driver': value => $network_scheduler_driver; + 'DEFAULT/dhcp_load_type': value => $dhcp_load_type; + 'DEFAULT/default_availability_zones': value => join(any2array($default_availability_zones), ','); } if $state_path { diff --git a/releasenotes/notes/neutron_availability_zones-80246c2af9a7be08.yaml b/releasenotes/notes/neutron_availability_zones-80246c2af9a7be08.yaml new file mode 100644 index 000000000..49fa8bc5f --- /dev/null +++ b/releasenotes/notes/neutron_availability_zones-80246c2af9a7be08.yaml @@ -0,0 +1,6 @@ +--- +features: + - Added the configuration options to configure neutron availability zones + for server and agents. + - Providers updated to being able to configure router/network with availability + zone. diff --git a/spec/classes/neutron_agents_dhcp_spec.rb b/spec/classes/neutron_agents_dhcp_spec.rb index 3cbb597be..e9d17c613 100644 --- a/spec/classes/neutron_agents_dhcp_spec.rb +++ b/spec/classes/neutron_agents_dhcp_spec.rb @@ -50,6 +50,7 @@ describe 'neutron::agents::dhcp' do is_expected.to contain_neutron_dhcp_agent_config('DEFAULT/force_metadata').with_value(''); is_expected.to contain_neutron_dhcp_agent_config('DEFAULT/enable_metadata_network').with_value(p[:enable_metadata_network]); is_expected.to contain_neutron_dhcp_agent_config('DEFAULT/dhcp_broadcast_reply').with_value(''); + is_expected.to contain_neutron_dhcp_agent_config('AGENT/availability_zone').with_value(''); end it 'installs neutron dhcp agent package' do @@ -140,6 +141,15 @@ describe 'neutron::agents::dhcp' do is_expected.to contain_neutron_dhcp_agent_config('DEFAULT/enable_metadata_network').with_value('true'); end end + + context 'when availability zone is set' do + before :each do + params.merge!(:availability_zone => 'zone1') + end + it 'should configure availability zone' do + is_expected.to contain_neutron_dhcp_agent_config('AGENT/availability_zone').with_value(p[:availability_zone]); + end + end end shared_examples_for 'neutron dhcp agent with dnsmasq_config_file specified' do diff --git a/spec/classes/neutron_agents_l3_spec.rb b/spec/classes/neutron_agents_l3_spec.rb index 3331d9ad0..33d0959ca 100644 --- a/spec/classes/neutron_agents_l3_spec.rb +++ b/spec/classes/neutron_agents_l3_spec.rb @@ -47,6 +47,7 @@ describe 'neutron::agents::l3' do is_expected.to contain_neutron_l3_agent_config('DEFAULT/periodic_interval').with_value('') is_expected.to contain_neutron_l3_agent_config('DEFAULT/periodic_fuzzy_delay').with_value('') is_expected.to contain_neutron_l3_agent_config('DEFAULT/enable_metadata_proxy').with_value('') + is_expected.to contain_neutron_l3_agent_config('AGENT/availability_zone').with_value('') end it 'passes purge to resource' do @@ -105,6 +106,16 @@ describe 'neutron::agents::l3' do is_expected.to contain_neutron_l3_agent_config('DEFAULT/ha_vrrp_advert_int').with_value(p[:ha_vrrp_advert_int]) end end + + context 'with availability zone' do + before :each do + params.merge!(:availability_zone => 'zone1') + end + + it 'configures availability zone' do + is_expected.to contain_neutron_l3_agent_config('AGENT/availability_zone').with_value(p[:availability_zone]) + end + end end context 'on Debian platforms' do diff --git a/spec/classes/neutron_server_spec.rb b/spec/classes/neutron_server_spec.rb index 3b5975101..25c738ccb 100644 --- a/spec/classes/neutron_server_spec.rb +++ b/spec/classes/neutron_server_spec.rb @@ -200,6 +200,32 @@ describe 'neutron::server' do is_expected.not_to contain_neutron_config('keystone_authtoken/auth_type') end end + + context 'with a bad dhcp_load_type value' do + before :each do + params.merge!(:dhcp_load_type => 'badvalue') + end + + it_raises 'a Puppet::Error', /Must pass either networks, subnets, or ports as values for dhcp_load_type/ + end + + context 'with availability zone hints set' do + before :each do + params.merge!(:dhcp_load_type => 'networks', + :router_scheduler_driver => 'neutron.scheduler.l3_agent_scheduler.AZLeastRoutersScheduler', + :network_scheduler_driver => 'neutron.scheduler.dhcp_agent_scheduler.AZAwareWeightScheduler', + :default_availability_zones => ['zone1', 'zone2'] + ) + end + + it 'should configure neutron server for availability zones' do + is_expected.to contain_neutron_config('DEFAULT/default_availability_zones').with_value('zone1,zone2') + is_expected.to contain_neutron_config('DEFAULT/router_scheduler_driver').with_value('neutron.scheduler.l3_agent_scheduler.AZLeastRoutersScheduler') + is_expected.to contain_neutron_config('DEFAULT/network_scheduler_driver').with_value('neutron.scheduler.dhcp_agent_scheduler.AZAwareWeightScheduler') + is_expected.to contain_neutron_config('DEFAULT/dhcp_load_type').with_value('networks') + end + + end end shared_examples_for 'a neutron server with broken authentication' do diff --git a/spec/unit/provider/neutron_router/neutron_spec.rb b/spec/unit/provider/neutron_router/neutron_spec.rb index 4c7e9eb82..4bec1a337 100644 --- a/spec/unit/provider/neutron_router/neutron_spec.rb +++ b/spec/unit/provider/neutron_router/neutron_spec.rb @@ -13,12 +13,13 @@ describe provider_class do let :router_attrs do { - :name => router_name, - :ensure => 'present', - :admin_state_up => 'True', - :distributed => 'True', - :ha => 'False', - :tenant_id => '60f9544eb94c42a6b7e8e98c2be981b1', + :name => router_name, + :ensure => 'present', + :admin_state_up => 'True', + :distributed => 'True', + :ha => 'False', + :tenant_id => '60f9544eb94c42a6b7e8e98c2be981b1', + :availability_zone_hint => 'zone1', } end @@ -43,12 +44,14 @@ name="router1" status="ACTIVE" distributed="True" ha="False" -tenant_id="60f9544eb94c42a6b7e8e98c2be981b1"' +tenant_id="60f9544eb94c42a6b7e8e98c2be981b1" +availability-zone-hint="zone1"' provider.expects(:auth_neutron).with('router-create', '--format=shell', ["--tenant_id=#{router_attrs[:tenant_id]}", "--distributed=#{router_attrs[:distributed]}", - "--ha=#{router_attrs[:ha]}"], + "--ha=#{router_attrs[:ha]}", + "--availability-zone-hint=#{router_attrs[:availability_zone_hint]}"], router_name).returns(output) provider.create