From ea6188c9c044fdd40e02e352e51cce4d7df9579e Mon Sep 17 00:00:00 2001 From: Nikita Koshikov Date: Fri, 10 Apr 2015 14:10:06 +0300 Subject: [PATCH] Puppet providers added Change-Id: I67ad59731df43423dd210150c2b68dfec9cff8b4 --- .../heat_api_cfn_config/ini_setting.rb | 22 ++ .../heat_api_cfn_paste_ini/ini_setting.rb | 23 ++ .../heat_api_cloudwatch_config/ini_setting.rb | 22 ++ .../ini_setting.rb | 23 ++ .../provider/heat_api_config/ini_setting.rb | 23 ++ .../heat_api_paste_ini/ini_setting.rb | 23 ++ .../provider/heat_config/ini_setting.rb | 22 ++ .../heat_engine_config/ini_setting.rb | 22 ++ .../lib/puppet/type/heat_api_cfn_config.rb | 19 ++ .../lib/puppet/type/heat_api_cfn_paste_ini.rb | 19 ++ .../puppet/type/heat_api_cloudwatch_config.rb | 19 ++ .../type/heat_api_cloudwatch_paste_ini.rb | 19 ++ .../heat/lib/puppet/type/heat_api_config.rb | 19 ++ .../lib/puppet/type/heat_api_paste_ini.rb | 19 ++ .../heat/lib/puppet/type/heat_config.rb | 19 ++ .../lib/puppet/type/heat_engine_config.rb | 20 ++ .../neutron/lib/puppet/provider/neutron.rb | 272 ++++++++++++++++++ .../provider/neutron_config/ini_setting.rb | 22 ++ .../provider/neutron_network/neutron.rb | 140 +++++++++ .../neutron_plugin_ml2/ini_setting.rb | 22 ++ .../neutron_plugin_ml2_cisco/ini_setting.rb | 22 ++ .../puppet/provider/neutron_port/neutron.rb | 192 +++++++++++++ .../puppet/provider/neutron_router/neutron.rb | 139 +++++++++ .../neutron_router_interface/neutron.rb | 93 ++++++ .../puppet/provider/neutron_subnet/neutron.rb | 220 ++++++++++++++ .../neutron/lib/puppet/type/neutron_config.rb | 47 +++ .../lib/puppet/type/neutron_network.rb | 90 ++++++ .../lib/puppet/type/neutron_plugin_ml2.rb | 20 ++ .../puppet/type/neutron_plugin_ml2_cisco.rb | 47 +++ .../neutron/lib/puppet/type/neutron_port.rb | 98 +++++++ .../neutron/lib/puppet/type/neutron_router.rb | 91 ++++++ .../puppet/type/neutron_router_interface.rb | 51 ++++ .../neutron/lib/puppet/type/neutron_subnet.rb | 114 ++++++++ 33 files changed, 2013 insertions(+) create mode 100644 deployment_scripts/puppet/modules/heat/lib/puppet/provider/heat_api_cfn_config/ini_setting.rb create mode 100644 deployment_scripts/puppet/modules/heat/lib/puppet/provider/heat_api_cfn_paste_ini/ini_setting.rb create mode 100644 deployment_scripts/puppet/modules/heat/lib/puppet/provider/heat_api_cloudwatch_config/ini_setting.rb create mode 100644 deployment_scripts/puppet/modules/heat/lib/puppet/provider/heat_api_cloudwatch_paste_ini/ini_setting.rb create mode 100644 deployment_scripts/puppet/modules/heat/lib/puppet/provider/heat_api_config/ini_setting.rb create mode 100644 deployment_scripts/puppet/modules/heat/lib/puppet/provider/heat_api_paste_ini/ini_setting.rb create mode 100644 deployment_scripts/puppet/modules/heat/lib/puppet/provider/heat_config/ini_setting.rb create mode 100644 deployment_scripts/puppet/modules/heat/lib/puppet/provider/heat_engine_config/ini_setting.rb create mode 100644 deployment_scripts/puppet/modules/heat/lib/puppet/type/heat_api_cfn_config.rb create mode 100644 deployment_scripts/puppet/modules/heat/lib/puppet/type/heat_api_cfn_paste_ini.rb create mode 100644 deployment_scripts/puppet/modules/heat/lib/puppet/type/heat_api_cloudwatch_config.rb create mode 100644 deployment_scripts/puppet/modules/heat/lib/puppet/type/heat_api_cloudwatch_paste_ini.rb create mode 100644 deployment_scripts/puppet/modules/heat/lib/puppet/type/heat_api_config.rb create mode 100644 deployment_scripts/puppet/modules/heat/lib/puppet/type/heat_api_paste_ini.rb create mode 100644 deployment_scripts/puppet/modules/heat/lib/puppet/type/heat_config.rb create mode 100644 deployment_scripts/puppet/modules/heat/lib/puppet/type/heat_engine_config.rb create mode 100644 deployment_scripts/puppet/modules/neutron/lib/puppet/provider/neutron.rb create mode 100644 deployment_scripts/puppet/modules/neutron/lib/puppet/provider/neutron_config/ini_setting.rb create mode 100644 deployment_scripts/puppet/modules/neutron/lib/puppet/provider/neutron_network/neutron.rb create mode 100644 deployment_scripts/puppet/modules/neutron/lib/puppet/provider/neutron_plugin_ml2/ini_setting.rb create mode 100644 deployment_scripts/puppet/modules/neutron/lib/puppet/provider/neutron_plugin_ml2_cisco/ini_setting.rb create mode 100644 deployment_scripts/puppet/modules/neutron/lib/puppet/provider/neutron_port/neutron.rb create mode 100644 deployment_scripts/puppet/modules/neutron/lib/puppet/provider/neutron_router/neutron.rb create mode 100644 deployment_scripts/puppet/modules/neutron/lib/puppet/provider/neutron_router_interface/neutron.rb create mode 100644 deployment_scripts/puppet/modules/neutron/lib/puppet/provider/neutron_subnet/neutron.rb create mode 100644 deployment_scripts/puppet/modules/neutron/lib/puppet/type/neutron_config.rb create mode 100644 deployment_scripts/puppet/modules/neutron/lib/puppet/type/neutron_network.rb create mode 100644 deployment_scripts/puppet/modules/neutron/lib/puppet/type/neutron_plugin_ml2.rb create mode 100644 deployment_scripts/puppet/modules/neutron/lib/puppet/type/neutron_plugin_ml2_cisco.rb create mode 100644 deployment_scripts/puppet/modules/neutron/lib/puppet/type/neutron_port.rb create mode 100644 deployment_scripts/puppet/modules/neutron/lib/puppet/type/neutron_router.rb create mode 100644 deployment_scripts/puppet/modules/neutron/lib/puppet/type/neutron_router_interface.rb create mode 100644 deployment_scripts/puppet/modules/neutron/lib/puppet/type/neutron_subnet.rb diff --git a/deployment_scripts/puppet/modules/heat/lib/puppet/provider/heat_api_cfn_config/ini_setting.rb b/deployment_scripts/puppet/modules/heat/lib/puppet/provider/heat_api_cfn_config/ini_setting.rb new file mode 100644 index 0000000..ca4261b --- /dev/null +++ b/deployment_scripts/puppet/modules/heat/lib/puppet/provider/heat_api_cfn_config/ini_setting.rb @@ -0,0 +1,22 @@ +Puppet::Type.type(:heat_api_cfn_config).provide( + :ini_setting, + :parent => Puppet::Type.type(:ini_setting).provider(:ruby) +) do + + def section + resource[:name].split('/', 2).first + end + + def setting + resource[:name].split('/', 2).last + end + + def separator + '=' + end + + def file_path + '/etc/heat/heat-api-cfn.conf' + end + +end diff --git a/deployment_scripts/puppet/modules/heat/lib/puppet/provider/heat_api_cfn_paste_ini/ini_setting.rb b/deployment_scripts/puppet/modules/heat/lib/puppet/provider/heat_api_cfn_paste_ini/ini_setting.rb new file mode 100644 index 0000000..e15c4c7 --- /dev/null +++ b/deployment_scripts/puppet/modules/heat/lib/puppet/provider/heat_api_cfn_paste_ini/ini_setting.rb @@ -0,0 +1,23 @@ +Puppet::Type.type(:heat_api_cfn_paste_ini).provide( + :ini_setting, + :parent => Puppet::Type.type(:ini_setting).provider(:ruby) +) do + + def section + resource[:name].split('/', 2).first + + end + + def setting + resource[:name].split('/', 2).last + end + + def separator + '=' + end + + def file_path + '/etc/heat/heat-api-cfn-paste.ini' + end + +end diff --git a/deployment_scripts/puppet/modules/heat/lib/puppet/provider/heat_api_cloudwatch_config/ini_setting.rb b/deployment_scripts/puppet/modules/heat/lib/puppet/provider/heat_api_cloudwatch_config/ini_setting.rb new file mode 100644 index 0000000..507663e --- /dev/null +++ b/deployment_scripts/puppet/modules/heat/lib/puppet/provider/heat_api_cloudwatch_config/ini_setting.rb @@ -0,0 +1,22 @@ +Puppet::Type.type(:heat_api_cloudwatch_config).provide( + :ini_setting, + :parent => Puppet::Type.type(:ini_setting).provider(:ruby) +) do + + def section + resource[:name].split('/', 2).first + end + + def setting + resource[:name].split('/', 2).last + end + + def separator + '=' + end + + def file_path + '/etc/heat/heat-api-cloudwatch.conf' + end + +end diff --git a/deployment_scripts/puppet/modules/heat/lib/puppet/provider/heat_api_cloudwatch_paste_ini/ini_setting.rb b/deployment_scripts/puppet/modules/heat/lib/puppet/provider/heat_api_cloudwatch_paste_ini/ini_setting.rb new file mode 100644 index 0000000..9a6a001 --- /dev/null +++ b/deployment_scripts/puppet/modules/heat/lib/puppet/provider/heat_api_cloudwatch_paste_ini/ini_setting.rb @@ -0,0 +1,23 @@ +Puppet::Type.type(:heat_api_cloudwatch_paste_ini).provide( + :ini_setting, + :parent => Puppet::Type.type(:ini_setting).provider(:ruby) +) do + + def section + resource[:name].split('/', 2).first + + end + + def setting + resource[:name].split('/', 2).last + end + + def separator + '=' + end + + def file_path + '/etc/heat/heat-api-cloudwatch-paste.ini' + end + +end diff --git a/deployment_scripts/puppet/modules/heat/lib/puppet/provider/heat_api_config/ini_setting.rb b/deployment_scripts/puppet/modules/heat/lib/puppet/provider/heat_api_config/ini_setting.rb new file mode 100644 index 0000000..4eba227 --- /dev/null +++ b/deployment_scripts/puppet/modules/heat/lib/puppet/provider/heat_api_config/ini_setting.rb @@ -0,0 +1,23 @@ +Puppet::Type.type(:heat_api_config).provide( + :ini_setting, + :parent => Puppet::Type.type(:ini_setting).provider(:ruby) +) do + + def section + resource[:name].split('/', 2).first + + end + + def setting + resource[:name].split('/', 2).last + end + + def separator + '=' + end + + def file_path + '/etc/heat/heat-api.conf' + end + +end diff --git a/deployment_scripts/puppet/modules/heat/lib/puppet/provider/heat_api_paste_ini/ini_setting.rb b/deployment_scripts/puppet/modules/heat/lib/puppet/provider/heat_api_paste_ini/ini_setting.rb new file mode 100644 index 0000000..6c91853 --- /dev/null +++ b/deployment_scripts/puppet/modules/heat/lib/puppet/provider/heat_api_paste_ini/ini_setting.rb @@ -0,0 +1,23 @@ +Puppet::Type.type(:heat_api_paste_ini).provide( + :ini_setting, + :parent => Puppet::Type.type(:ini_setting).provider(:ruby) +) do + + def section + resource[:name].split('/', 2).first + + end + + def setting + resource[:name].split('/', 2).last + end + + def separator + '=' + end + + def file_path + '/etc/heat/heat-api-paste.ini' + end + +end diff --git a/deployment_scripts/puppet/modules/heat/lib/puppet/provider/heat_config/ini_setting.rb b/deployment_scripts/puppet/modules/heat/lib/puppet/provider/heat_config/ini_setting.rb new file mode 100644 index 0000000..2c3ab5f --- /dev/null +++ b/deployment_scripts/puppet/modules/heat/lib/puppet/provider/heat_config/ini_setting.rb @@ -0,0 +1,22 @@ +Puppet::Type.type(:heat_config).provide( + :ini_setting, + :parent => Puppet::Type.type(:ini_setting).provider(:ruby) +) do + + def section + resource[:name].split('/', 2).first + end + + def setting + resource[:name].split('/', 2).last + end + + def separator + '=' + end + + def file_path + '/etc/heat/heat.conf' + end + +end diff --git a/deployment_scripts/puppet/modules/heat/lib/puppet/provider/heat_engine_config/ini_setting.rb b/deployment_scripts/puppet/modules/heat/lib/puppet/provider/heat_engine_config/ini_setting.rb new file mode 100644 index 0000000..72e6834 --- /dev/null +++ b/deployment_scripts/puppet/modules/heat/lib/puppet/provider/heat_engine_config/ini_setting.rb @@ -0,0 +1,22 @@ +Puppet::Type.type(:heat_engine_config).provide( + :ini_setting, + :parent => Puppet::Type.type(:ini_setting).provider(:ruby) +) do + + def section + resource[:name].split('/', 2).first + end + + def setting + resource[:name].split('/', 2).last + end + + def separator + '=' + end + + def file_path + '/etc/heat/heat-engine.conf' + end + +end diff --git a/deployment_scripts/puppet/modules/heat/lib/puppet/type/heat_api_cfn_config.rb b/deployment_scripts/puppet/modules/heat/lib/puppet/type/heat_api_cfn_config.rb new file mode 100644 index 0000000..98230b9 --- /dev/null +++ b/deployment_scripts/puppet/modules/heat/lib/puppet/type/heat_api_cfn_config.rb @@ -0,0 +1,19 @@ +Puppet::Type.newtype(:heat_api_cfn_config) do + + ensurable + + newparam(:name, :namevar => true) do + desc 'Section/setting name to manage from heat_api_cfn.conf' + newvalues(/\S+\/\S+/) + end + + newproperty(:value) do + desc 'The value of the setting to be defined.' + munge do |value| + value = value.to_s.strip + value.capitalize! if value =~ /^(true|false)$/i + value + end + end + +end diff --git a/deployment_scripts/puppet/modules/heat/lib/puppet/type/heat_api_cfn_paste_ini.rb b/deployment_scripts/puppet/modules/heat/lib/puppet/type/heat_api_cfn_paste_ini.rb new file mode 100644 index 0000000..65fa133 --- /dev/null +++ b/deployment_scripts/puppet/modules/heat/lib/puppet/type/heat_api_cfn_paste_ini.rb @@ -0,0 +1,19 @@ +Puppet::Type.newtype(:heat_api_cfn_paste_ini) do + + ensurable + + newparam(:name, :namevar => true) do + desc 'Section/setting name to manage from heat-api.conf' + newvalues(/\S+\/\S+/) + end + + newproperty(:value) do + desc 'The value of the setting to be defined.' + munge do |value| + value = value.to_s.strip + value.capitalize! if value =~ /^(true|false)$/i + value + end + end + +end diff --git a/deployment_scripts/puppet/modules/heat/lib/puppet/type/heat_api_cloudwatch_config.rb b/deployment_scripts/puppet/modules/heat/lib/puppet/type/heat_api_cloudwatch_config.rb new file mode 100644 index 0000000..90b2749 --- /dev/null +++ b/deployment_scripts/puppet/modules/heat/lib/puppet/type/heat_api_cloudwatch_config.rb @@ -0,0 +1,19 @@ +Puppet::Type.newtype(:heat_api_cloudwatch_config) do + + ensurable + + newparam(:name, :namevar => true) do + desc 'Section/setting name to manage from heat-api-cloudwatch.conf' + newvalues(/\S+\/\S+/) + end + + newproperty(:value) do + desc 'The value of the setting to be defined.' + munge do |value| + value = value.to_s.strip + value.capitalize! if value =~ /^(true|false)$/i + value + end + end + +end diff --git a/deployment_scripts/puppet/modules/heat/lib/puppet/type/heat_api_cloudwatch_paste_ini.rb b/deployment_scripts/puppet/modules/heat/lib/puppet/type/heat_api_cloudwatch_paste_ini.rb new file mode 100644 index 0000000..af7d927 --- /dev/null +++ b/deployment_scripts/puppet/modules/heat/lib/puppet/type/heat_api_cloudwatch_paste_ini.rb @@ -0,0 +1,19 @@ +Puppet::Type.newtype(:heat_api_cloudwatch_paste_ini) do + + ensurable + + newparam(:name, :namevar => true) do + desc 'Section/setting name to manage from heat-api.conf' + newvalues(/\S+\/\S+/) + end + + newproperty(:value) do + desc 'The value of the setting to be defined.' + munge do |value| + value = value.to_s.strip + value.capitalize! if value =~ /^(true|false)$/i + value + end + end + +end diff --git a/deployment_scripts/puppet/modules/heat/lib/puppet/type/heat_api_config.rb b/deployment_scripts/puppet/modules/heat/lib/puppet/type/heat_api_config.rb new file mode 100644 index 0000000..c943329 --- /dev/null +++ b/deployment_scripts/puppet/modules/heat/lib/puppet/type/heat_api_config.rb @@ -0,0 +1,19 @@ +Puppet::Type.newtype(:heat_api_config) do + + ensurable + + newparam(:name, :namevar => true) do + desc 'Section/setting name to manage from heat-api.conf' + newvalues(/\S+\/\S+/) + end + + newproperty(:value) do + desc 'The value of the setting to be defined.' + munge do |value| + value = value.to_s.strip + value.capitalize! if value =~ /^(true|false)$/i + value + end + end + +end diff --git a/deployment_scripts/puppet/modules/heat/lib/puppet/type/heat_api_paste_ini.rb b/deployment_scripts/puppet/modules/heat/lib/puppet/type/heat_api_paste_ini.rb new file mode 100644 index 0000000..a389ef4 --- /dev/null +++ b/deployment_scripts/puppet/modules/heat/lib/puppet/type/heat_api_paste_ini.rb @@ -0,0 +1,19 @@ +Puppet::Type.newtype(:heat_api_paste_ini) do + + ensurable + + newparam(:name, :namevar => true) do + desc 'Section/setting name to manage from heat-api.conf' + newvalues(/\S+\/\S+/) + end + + newproperty(:value) do + desc 'The value of the setting to be defined.' + munge do |value| + value = value.to_s.strip + value.capitalize! if value =~ /^(true|false)$/i + value + end + end + +end diff --git a/deployment_scripts/puppet/modules/heat/lib/puppet/type/heat_config.rb b/deployment_scripts/puppet/modules/heat/lib/puppet/type/heat_config.rb new file mode 100644 index 0000000..3534e22 --- /dev/null +++ b/deployment_scripts/puppet/modules/heat/lib/puppet/type/heat_config.rb @@ -0,0 +1,19 @@ +Puppet::Type.newtype(:heat_config) do + + ensurable + + newparam(:name, :namevar => true) do + desc 'Section/setting name to manage from heat.conf' + newvalues(/\S+\/\S+/) + end + + newproperty(:value) do + desc 'The value of the setting to be defined.' + munge do |value| + value = value.to_s.strip + value.capitalize! if value =~ /^(true|false)$/i + value + end + end + +end diff --git a/deployment_scripts/puppet/modules/heat/lib/puppet/type/heat_engine_config.rb b/deployment_scripts/puppet/modules/heat/lib/puppet/type/heat_engine_config.rb new file mode 100644 index 0000000..2faed47 --- /dev/null +++ b/deployment_scripts/puppet/modules/heat/lib/puppet/type/heat_engine_config.rb @@ -0,0 +1,20 @@ +Puppet::Type.newtype(:heat_engine_config) do + + ensurable + + newparam(:name, :namevar => true) do + desc 'Section/setting name to manage from heat-engine.conf' + newvalues(/\S+\/\S+/) + end + + newproperty(:value) do + desc 'The value of the setting to be defined.' + munge do |value| + puts value + value = value.to_s.strip + value.capitalize! if value =~ /^(true|false)$/i + value + end + end + +end diff --git a/deployment_scripts/puppet/modules/neutron/lib/puppet/provider/neutron.rb b/deployment_scripts/puppet/modules/neutron/lib/puppet/provider/neutron.rb new file mode 100644 index 0000000..0179613 --- /dev/null +++ b/deployment_scripts/puppet/modules/neutron/lib/puppet/provider/neutron.rb @@ -0,0 +1,272 @@ +require 'csv' +require 'puppet/util/inifile' + +class Puppet::Provider::Neutron < Puppet::Provider + + #NOTE(xenolog): self.prefetch was removed with comment: + # FIXME:(xarses) needs to be abstraced from subresources and re-written here + + def self.conf_filename + '/etc/neutron/neutron.conf' + end + + def self.withenv(hash, &block) + saved = ENV.to_hash + hash.each do |name, val| + ENV[name.to_s] = val + end + + yield + ensure + ENV.clear + saved.each do |name, val| + ENV[name] = val + end + end + + def self.neutron_credentials + @neutron_credentials ||= get_neutron_credentials + end + + def self.get_neutron_credentials + auth_keys = ['auth_host', 'auth_port', 'auth_protocol', + 'admin_tenant_name', 'admin_user', 'admin_password'] + conf = neutron_conf + if conf and conf['keystone_authtoken'] and + auth_keys.all?{|k| !conf['keystone_authtoken'][k].nil?} + creds = Hash[ auth_keys.map \ + { |k| [k, conf['keystone_authtoken'][k].strip] } ] + if conf['DEFAULT'] and !conf['DEFAULT']['nova_region_name'].nil? + creds['nova_region_name'] = conf['DEFAULT']['nova_region_name'] + end + return creds + else + raise(Puppet::Error, "File: #{conf_filename} does not contain all \ +required sections. Neutron types will not work if neutron is not \ +correctly configured.") + end + end + + def neutron_credentials + self.class.neutron_credentials + end + + def self.auth_endpoint + @auth_endpoint ||= get_auth_endpoint + end + + def self.get_auth_endpoint + q = neutron_credentials + "#{q['auth_protocol']}://#{q['auth_host']}:#{q['auth_port']}/v2.0/" + end + + def self.neutron_conf + return @neutron_conf if @neutron_conf + @neutron_conf = Puppet::Util::IniConfig::File.new + @neutron_conf.read(conf_filename) + @neutron_conf + end + + def self.auth_neutron(*args) + q = neutron_credentials + authenv = { + :OS_AUTH_URL => self.auth_endpoint, + :OS_USERNAME => q['admin_user'], + :OS_TENANT_NAME => q['admin_tenant_name'], + :OS_PASSWORD => q['admin_password'] + } + if q.key?('nova_region_name') + authenv[:OS_REGION_NAME] = q['nova_region_name'] + end + # NOTE(bogdando) contribute change to upstream #1384097: + # enhanced message checks within a given time frame + rv = nil + timeout = 120 + end_time = Time.now.to_i + timeout + loop do + begin + withenv authenv do + rv = neutron(args) + end + break + rescue Puppet::ExecutionFailure => e + if ! e.message =~ /(\(HTTP\s+400\))| + (400-\{\'message\'\:\s+\'\'\})| + (\[Errno 111\]\s+Connection\s+refused)| + (503\s+Service\s+Unavailable)| + (504\s+Gateway\s+Time-out)| + (\:\s+Maximum\s+attempts\s+reached)| + (Unauthorized\:\s+bad\s+credentials)| + (Max\s+retries\s+exceeded)/ + raise(e) + end + current_time = Time.now.to_i + if current_time > end_time + break + else + wait = end_time - current_time + Puppet::debug("Non-fatal error: \"#{e.message}\"") + notice("Neutron API not avalaible. Wait up to #{wait} sec.") + end + sleep(2) + # Note(xarses): Don't remove, we know that there is one of the + # Recoverable erros above, So we will retry a few more times + end + end + return rv + end + + def auth_neutron(*args) + self.class.auth_neutron(args) + end + + def self.reset + @neutron_conf = nil + @neutron_credentials = nil + end + + def self.list_neutron_resources(type) + ids = [] + list = auth_neutron("#{type}-list", '--format=csv', + '--column=id', '--quote=none') + # NOTE(bogdando) contribute change to upstream #1384101: + # raise Puppet exception, if resources list is empty + if list.nil? + raise(Puppet::ExecutionFailure, "Can't prefetch #{type}-list Neutron or Keystone API is not avalaible.") + end + + (list.split("\n")[1..-1] || []).compact.collect do |line| + ids << line.strip + end + return ids + end + + def self.get_neutron_resource_attrs(type, id) + attrs = {} + net = auth_neutron("#{type}-show", '--format=shell', id) + # NOTE(bogdando) contribute change to upstream #1384101: + # raise Puppet exception, if list of resources' attributes is empty + if net.nil? + raise(Puppet::ExecutionFailure, "Can't prefetch #{type}-show Neutron or Keystone API is not avalaible.") + end + last_key = nil + (net.split("\n") || []).compact.collect do |line| + if line.include? '=' + k, v = line.split('=', 2) + attrs[k] = v.gsub(/\A"|"\Z/, '') + last_key = k + else + # Handle the case of a list of values + v = line.gsub(/\A"|"\Z/, '') + attrs[last_key] = [attrs[last_key], v].flatten + end + end + return attrs + end + + def self.list_router_ports(router_name_or_id) + results = [] + cmd_output = auth_neutron("router-port-list", + '--format=csv', + router_name_or_id) + if ! cmd_output + return results + end + + headers = nil + CSV.parse(cmd_output) do |row| + if headers == nil + headers = row + else + result = Hash[*headers.zip(row).flatten] + match_data = /.*"subnet_id": "(.*)", .*/.match(result['fixed_ips']) + if match_data + result['subnet_id'] = match_data[1] + end + results << result + end + end + return results + end + + def self.auth_keystone(*args) + q = neutron_credentials + authenv = { + :OS_AUTH_URL => self.auth_endpoint, + :OS_USERNAME => q['admin_user'], + :OS_TENANT_NAME => q['admin_tenant_name'], + :OS_PASSWORD => q['admin_password'] + } + if q.key?('nova_region_name') + authenv[:OS_REGION_NAME] = q['nova_region_name'] + end + + rv = nil + timeout = 120 + end_time = Time.now.to_i + timeout + loop do + begin + withenv authenv do + rv = keystone(args) + end + break + rescue Puppet::ExecutionFailure => e + if ! e.message =~ /(\(HTTP\s+400\))| + (400-\{\'message\'\:\s+\'\'\})| + (\[Errno 111\]\s+Connection\s+refused)| + (503\s+Service\s+Unavailable)| + (504\s+Gateway\s+Time-out)| + (\:\s+Maximum\s+attempts\s+reached)| + (Unauthorized\:\s+bad\s+credentials)| + (Max\s+retries\s+exceeded)/ + raise(e) + end + current_time = Time.now.to_i + if current_time > end_time + #raise(e) + break + else + wait = end_time - current_time + Puppet::debug("Non-fatal error: \"#{e.message}\"") + notice("Keystone API not avalaible. Wait up to #{wait} sec.") + end + sleep(2) + # Note(xarses): Don't remove, we know that there is one of the + # Recoverable erros above, So we will retry a few more times + end + end + return rv + end + + def auth_keystone(*args) + self.class.auth_neutron(args) + end + + def self.get_tenant_id(catalog, name) + rv = nil + auth_keystone('tenant-list').each do |line| + fields=line.split(/\s*\|\s*/) + if fields[1] and fields[1].size == 32 + if fields[2] == name + rv = fields[1] + break + end + end + end + if rv.nil? + fail("Unable to get tenant-ID for tenant '#{name}'") + end + return rv + end + + def self.parse_creation_output(data) + hash = {} + data.split("\n").compact.each do |line| + if line.include? '=' + hash[line.split('=').first] = line.split('=', 2)[1].gsub(/\A"|"\Z/, '') + end + end + hash + end + +end diff --git a/deployment_scripts/puppet/modules/neutron/lib/puppet/provider/neutron_config/ini_setting.rb b/deployment_scripts/puppet/modules/neutron/lib/puppet/provider/neutron_config/ini_setting.rb new file mode 100644 index 0000000..a1e97b0 --- /dev/null +++ b/deployment_scripts/puppet/modules/neutron/lib/puppet/provider/neutron_config/ini_setting.rb @@ -0,0 +1,22 @@ +Puppet::Type.type(:neutron_config).provide( + :ini_setting, + :parent => Puppet::Type.type(:ini_setting).provider(:ruby) +) do + + def section + resource[:name].split('/', 2).first + end + + def setting + resource[:name].split('/', 2).last + end + + def separator + '=' + end + + def file_path + '/etc/neutron/neutron.conf' + end + +end diff --git a/deployment_scripts/puppet/modules/neutron/lib/puppet/provider/neutron_network/neutron.rb b/deployment_scripts/puppet/modules/neutron/lib/puppet/provider/neutron_network/neutron.rb new file mode 100644 index 0000000..e285504 --- /dev/null +++ b/deployment_scripts/puppet/modules/neutron/lib/puppet/provider/neutron_network/neutron.rb @@ -0,0 +1,140 @@ +require File.join(File.dirname(__FILE__), '..','..','..', + 'puppet/provider/neutron') + +Puppet::Type.type(:neutron_network).provide( + :neutron, + :parent => Puppet::Provider::Neutron +) do + desc <<-EOT + Neutron provider to manage neutron_network type. + + Assumes that the neutron service is configured on the same host. + EOT + + commands :neutron => 'neutron' + commands :keystone => 'keystone' + + mk_resource_methods + + def self.neutron_type + 'net' + end + + def self.instances + list_neutron_resources(neutron_type).collect do |id| + attrs = get_neutron_resource_attrs(neutron_type, id) + new( + :ensure => :present, + :name => attrs['name'], + :id => attrs['id'], + :admin_state_up => attrs['admin_state_up'], + :provider_network_type => attrs['provider:network_type'], + :provider_physical_network => attrs['provider:physical_network'], + :provider_segmentation_id => attrs['provider:segmentation_id'], + :router_external => attrs['router:external'], + :shared => attrs['shared'], + :tenant_id => attrs['tenant_id'] + ) + end + end + + def self.prefetch(resources) + networks = instances + resources.keys.each do |name| + if provider = networks.find{ |net| net.name == name } + resources[name].provider = provider + end + end + end + + def exists? + @property_hash[:ensure] == :present + end + + def create + network_opts = Array.new + + if @resource[:shared] =~ /true/i + network_opts << '--shared' + end + + if @resource[:tenant_name] + tenant_id = self.class.get_tenant_id(model.catalog, + @resource[:tenant_name]) + notice("***N*** neutron_network::create *** tenant_id='#{tenant_id.inspect}'") + + network_opts << "--tenant_id=#{tenant_id}" + elsif @resource[:tenant_id] + network_opts << "--tenant_id=#{@resource[:tenant_id]}" + end + + if @resource[:provider_network_type] + network_opts << \ + "--provider:network_type=#{@resource[:provider_network_type]}" + end + + if @resource[:provider_physical_network] + network_opts << \ + "--provider:physical_network=#{@resource[:provider_physical_network]}" + end + + if @resource[:provider_segmentation_id] + network_opts << \ + "--provider:segmentation_id=#{@resource[:provider_segmentation_id]}" + end + + if @resource[:router_external] + network_opts << "--router:external=#{@resource[:router_external]}" + end + + results = auth_neutron('net-create', '--format=shell', + network_opts, resource[:name]) + + if results =~ /Created a new network:/ + attrs = self.class.parse_creation_output(results) + @property_hash = { + :ensure => :present, + :name => resource[:name], + :id => attrs['id'], + :admin_state_up => attrs['admin_state_up'], + :provider_network_type => attrs['provider:network_type'], + :provider_physical_network => attrs['provider:physical_network'], + :provider_segmentation_id => attrs['provider:segmentation_id'], + :router_external => attrs['router:external'], + :shared => attrs['shared'], + :tenant_id => attrs['tenant_id'], + } + else + fail("did not get expected message on network creation, got #{results}") + end + end + + def destroy + auth_neutron('net-delete', name) + @property_hash[:ensure] = :absent + end + + def admin_state_up=(value) + auth_neutron('net-update', "--admin_state_up=#{value}", name) + end + + def shared=(value) + auth_neutron('net-update', "--shared=#{value}", name) + end + + def router_external=(value) + auth_neutron('net-update', "--router:external=#{value}", name) + end + + [ + :provider_network_type, + :provider_physical_network, + :provider_segmentation_id, + :tenant_id, + ].each do |attr| + define_method(attr.to_s + "=") do |value| + fail("Property #{attr.to_s} does not support being updated") + end + end + +end diff --git a/deployment_scripts/puppet/modules/neutron/lib/puppet/provider/neutron_plugin_ml2/ini_setting.rb b/deployment_scripts/puppet/modules/neutron/lib/puppet/provider/neutron_plugin_ml2/ini_setting.rb new file mode 100644 index 0000000..9f724b5 --- /dev/null +++ b/deployment_scripts/puppet/modules/neutron/lib/puppet/provider/neutron_plugin_ml2/ini_setting.rb @@ -0,0 +1,22 @@ +Puppet::Type.type(:neutron_plugin_ml2).provide( + :ini_setting, + :parent => Puppet::Type.type(:ini_setting).provider(:ruby) +) do + + def section + resource[:name].split('/', 2).first + end + + def setting + resource[:name].split('/', 2).last + end + + def separator + '=' + end + + def file_path + '/etc/neutron/plugins/ml2/ml2_conf.ini' + end + +end diff --git a/deployment_scripts/puppet/modules/neutron/lib/puppet/provider/neutron_plugin_ml2_cisco/ini_setting.rb b/deployment_scripts/puppet/modules/neutron/lib/puppet/provider/neutron_plugin_ml2_cisco/ini_setting.rb new file mode 100644 index 0000000..81e60f0 --- /dev/null +++ b/deployment_scripts/puppet/modules/neutron/lib/puppet/provider/neutron_plugin_ml2_cisco/ini_setting.rb @@ -0,0 +1,22 @@ +Puppet::Type.type(:neutron_plugin_ml2_cisco).provide( + :ini_setting, + :parent => Puppet::Type.type(:ini_setting).provider(:ruby) +) do + + def section + resource[:name].split('/', 2).first + end + + def setting + resource[:name].split('/', 2).last + end + + def separator + '=' + end + + def file_path + '/etc/neutron/plugins/ml2/ml2_conf_cisco.ini' + end + +end diff --git a/deployment_scripts/puppet/modules/neutron/lib/puppet/provider/neutron_port/neutron.rb b/deployment_scripts/puppet/modules/neutron/lib/puppet/provider/neutron_port/neutron.rb new file mode 100644 index 0000000..38a317e --- /dev/null +++ b/deployment_scripts/puppet/modules/neutron/lib/puppet/provider/neutron_port/neutron.rb @@ -0,0 +1,192 @@ +require File.join(File.dirname(__FILE__), "..","..","..", + "puppet/provider/neutron") + +Puppet::Type.type(:neutron_port).provide( + :neutron, + :parent => Puppet::Provider::Neutron +) do + desc <<-EOT + Neutron provider to manage neutron_port type. + + Assumes that the neutron service is configured on the same host. + EOT + #TODO No security group support + + commands :neutron => "neutron" + commands :keystone => 'keystone' + + mk_resource_methods + + def self.instances + list_neutron_resources("port").collect do |id| + attrs = get_neutron_resource_attrs("port", id) + attrs["name"] = attrs["id"] if attrs["name"].empty? + new( + :ensure => :present, + :name => attrs["name"], + :id => attrs["id"], + :status => attrs["status"], + :tenant_id => attrs["tenant_id"], + :network_id => attrs["network_id"], + :admin_state_up => attrs["admin_state_up"], + :network_name => get_network_name(attrs["network_id"]), + :subnet_name => get_subnet_name(parse_subnet_id(attrs["fixed_ips"])), + :subnet_id => parse_subnet_id(attrs["fixed_ips"]), + :ip_address => parse_ip_address(attrs["fixed_ips"]) + ) + end + end + + def self.prefetch(resources) + instances_ = instances + resources.keys.each do |name| + if provider = instances_.find{ |instance| instance.name == name } + resources[name].provider = provider + end + end + end + + def exists? + @property_hash[:ensure] == :present + end + + def create + opts = Array.new + + if @resource[:admin_state_up] == "False" + opts << "--admin-state-down" + end + + if @resource[:ip_address] + # The spec says that multiple ip addresses may be specified, but this + # doesn't seem to work yet. + opts << "--fixed-ip" + opts << @resource[:ip_address].map{|ip|"ip_address=#{ip}"}.join(',') + end + + if @resource[:subnet_name] + # The spec says that multiple subnets may be specified, but this doesn't + # seem to work yet. + opts << "--fixed-ip" + opts << @resource[:subnet_name].map{|s|"subnet_id=#{s}"}.join(',') + end + + if @resource[:tenant_name] + tenant_id = self.class.get_tenant_id( + model.catalog, + @resource[:tenant_name] + ) + opts << "--tenant_id=#{tenant_id}" + elsif @resource[:tenant_id] + opts << "--tenant_id=#{@resource[:tenant_id]}" + end + + results = auth_neutron( + "port-create", + "--format=shell", + "--name=#{resource[:name]}", + opts, + resource[:network_name] + ) + + if results =~ /Created a new port:/ + attrs = self.class.parse_creation_output(results) + @property_hash = { + :ensure => :present, + :name => resource[:name], + :id => attrs["id"], + :status => attrs["status"], + :tenant_id => attrs["tenant_id"], + :network_id => attrs["network_id"], + :admin_state_up => attrs["admin_state_up"], + :network_name => resource[:network_name], + :subnet_name => resource[:subnet_name], + :subnet_id => self.class.parse_subnet_id(attrs["fixed_ips"]), + :ip_address => self.class.parse_ip_address(attrs["fixed_ips"]) + } + else + fail("did not get expected message on port creation, got #{results}") + end + end + + def destroy + auth_neutron("port-delete", name) + @property_hash[:ensure] = :absent + end + + def admin_state_up=(value) + auth_neutron("port-update", "--admin-state-up=#{value}", name) + end + + private + + def self.get_network_name(network_id_) + if network_id_ + network_instances = Puppet::Type.type("neutron_network").instances + network_name = network_instances.find do |instance| + instance.provider.id == network_id_ + end.provider.name + end + network_name + end + + def get_network_name(network_id_) + @get_network_name ||= self.class.get_network_name(network_id_) + end + + def self.get_subnet_name(subnet_id_) + if subnet_id_ + subnet_ids = Array(subnet_id_) + subnet_instances = Puppet::Type.type("neutron_subnet").instances + subnet_names = subnet_instances.collect do |instance| + if subnet_ids.include?(instance.provider.id) + instance.provider.name + else + nil + end + end.compact + if subnet_names.length > 1 + subnet_names + else + subnet_names.first + end + end + end + + def get_subnet_name(subnet_id_) + @subnet_name ||= self.class.subnet_name(subnet_id_) + end + + def self.parse_subnet_id(fixed_ips_) + subnet_ids = Array(fixed_ips_).collect do |json| + match_data = /\{"subnet_id": "(.*)", /.match(json) + if match_data + match_data[1] + else + nil + end + end.compact + if subnet_ids.length > 1 + subnet_ids + else + subnet_ids.first + end + end + + def self.parse_ip_address(fixed_ips_) + ip_addresses = Array(fixed_ips_).collect do |json| + match_data = /"ip_address": "(.*)"\}/.match(json) + if match_data + match_data[1] + else + nil + end + end.compact + if ip_addresses.length > 1 + ip_addresses + else + ip_addresses.first + end + end + +end diff --git a/deployment_scripts/puppet/modules/neutron/lib/puppet/provider/neutron_router/neutron.rb b/deployment_scripts/puppet/modules/neutron/lib/puppet/provider/neutron_router/neutron.rb new file mode 100644 index 0000000..d3d099b --- /dev/null +++ b/deployment_scripts/puppet/modules/neutron/lib/puppet/provider/neutron_router/neutron.rb @@ -0,0 +1,139 @@ +require File.join(File.dirname(__FILE__), '..','..','..', + 'puppet/provider/neutron') + +Puppet::Type.type(:neutron_router).provide( + :neutron, + :parent => Puppet::Provider::Neutron +) do + desc <<-EOT + Neutron provider to manage neutron_router type. + + Assumes that the neutron service is configured on the same host. + EOT + + commands :neutron => 'neutron' + commands :keystone => 'keystone' + + mk_resource_methods + + def self.instances + list_neutron_resources('router').collect do |id| + attrs = get_neutron_resource_attrs('router', id) + new( + :ensure => :present, + :name => attrs['name'], + :id => attrs['id'], + :admin_state_up => attrs['admin_state_up'], + :external_gateway_info => attrs['external_gateway_info'], + :status => attrs['status'], + :tenant_id => attrs['tenant_id'] + ) + end + end + + def self.prefetch(resources) + instances_ = instances + resources.keys.each do |name| + if provider = instances_.find{ |instance| instance.name == name } + resources[name].provider = provider + end + end + end + + def exists? + @property_hash[:ensure] == :present + end + + def create + opts = Array.new + + if @resource[:admin_state_up] == 'False' + opts << '--admin-state-down' + end + + if @resource[:tenant_name] + tenant_id = self.class.get_tenant_id(model.catalog, + @resource[:tenant_name]) + opts << "--tenant_id=#{tenant_id}" + elsif @resource[:tenant_id] + opts << "--tenant_id=#{@resource[:tenant_id]}" + end + + results = auth_neutron("router-create", '--format=shell', + opts, resource[:name]) + + if results =~ /Created a new router:/ + attrs = self.class.parse_creation_output(results) + @property_hash = { + :ensure => :present, + :name => resource[:name], + :id => attrs['id'], + :admin_state_up => attrs['admin_state_up'], + :external_gateway_info => attrs['external_gateway_info'], + :status => attrs['status'], + :tenant_id => attrs['tenant_id'], + } + + if @resource[:gateway_network_name] + results = auth_neutron('router-gateway-set', + @resource[:name], + @resource[:gateway_network_name]) + if results =~ /Set gateway for router/ + attrs = self.class.get_neutron_resource_attrs('router', + @resource[:name]) + @property_hash[:external_gateway_info] = \ + attrs['external_gateway_info'] + else + fail(<<-EOT +did not get expected message on setting router gateway, got #{results} +EOT + ) + end + end + else + fail("did not get expected message on router creation, got #{results}") + end + end + + def destroy + auth_neutron('router-delete', name) + @property_hash[:ensure] = :absent + end + + def gateway_network_name + if @gateway_network_name == nil and gateway_network_id + Puppet::Type.type('neutron_network').instances.each do |instance| + if instance.provider.id == gateway_network_id + @gateway_network_name = instance.provider.name + end + end + end + @gateway_network_name + end + + def gateway_network_name=(value) + if value == '' + auth_neutron('router-gateway-clear', name) + else + auth_neutron('router-gateway-set', name, value) + end + end + + def parse_gateway_network_id(external_gateway_info_) + match_data = /\{"network_id": "(.*?)"/.match(external_gateway_info_) + if match_data + match_data[1] + else + '' + end + end + + def gateway_network_id + @gateway_network_id ||= parse_gateway_network_id(external_gateway_info) + end + + def admin_state_up=(value) + auth_neutron('router-update', "--admin-state-up=#{value}", name) + end + +end diff --git a/deployment_scripts/puppet/modules/neutron/lib/puppet/provider/neutron_router_interface/neutron.rb b/deployment_scripts/puppet/modules/neutron/lib/puppet/provider/neutron_router_interface/neutron.rb new file mode 100644 index 0000000..4637846 --- /dev/null +++ b/deployment_scripts/puppet/modules/neutron/lib/puppet/provider/neutron_router_interface/neutron.rb @@ -0,0 +1,93 @@ +require File.join(File.dirname(__FILE__), '..','..','..', + 'puppet/provider/neutron') + +Puppet::Type.type(:neutron_router_interface).provide( + :neutron, + :parent => Puppet::Provider::Neutron +) do + desc <<-EOT + Neutron provider to manage neutron_router_interface type. + + Assumes that the neutron service is configured on the same host. + + It is not possible to manage an interface for the subnet used by + the gateway network, and such an interface will appear in the list + of resources ('puppet resource [type]'). Attempting to manage the + gateway interfae will result in an error. + + EOT + + commands :neutron => 'neutron' + + mk_resource_methods + + def self.instances + subnet_name_hash = {} + Puppet::Type.type('neutron_subnet').instances.each do |instance| + subnet_name_hash[instance.provider.id] = instance.provider.name + end + instances_ = [] + Puppet::Type.type('neutron_router').instances.each do |instance| + list_router_ports(instance.provider.id).each do |port_hash| + router_name = instance.provider.name + subnet_name = subnet_name_hash[port_hash['subnet_id']] + name = "#{router_name}:#{subnet_name}" + instances_ << new( + :ensure => :present, + :name => name, + :id => port_hash['id'], + :port => port_hash['name'] + ) + end + end + return instances_ + end + + def self.prefetch(resources) + instances_ = instances + resources.keys.each do |name| + if provider = instances_.find{ |instance| instance.name == name } + resources[name].provider = provider + end + end + end + + def exists? + @property_hash[:ensure] == :present + end + + def create + router,subnet = resource[:name].split(':', 2) + port = resource[:port] + args = ["router-interface-add", "--format=shell", router] + if port + args << "port=#{port}" + else + args << "subnet=#{subnet}" + end + results = auth_neutron(args) + + if results =~ /Added interface.* to router/ + @property_hash = { + :ensure => :present, + :name => resource[:name], + } + else + fail("did not get expected message on interface addition, got #{results}") + end + end + + def router_name + name.split(':', 2).first + end + + def subnet_name + name.split(':', 2).last + end + + def destroy + auth_neutron('router-interface-delete', router_name, subnet_name) + @property_hash[:ensure] = :absent + end + +end diff --git a/deployment_scripts/puppet/modules/neutron/lib/puppet/provider/neutron_subnet/neutron.rb b/deployment_scripts/puppet/modules/neutron/lib/puppet/provider/neutron_subnet/neutron.rb new file mode 100644 index 0000000..e044203 --- /dev/null +++ b/deployment_scripts/puppet/modules/neutron/lib/puppet/provider/neutron_subnet/neutron.rb @@ -0,0 +1,220 @@ +require File.join(File.dirname(__FILE__), '..','..','..', + 'puppet/provider/neutron') + +Puppet::Type.type(:neutron_subnet).provide( + :neutron, + :parent => Puppet::Provider::Neutron +) do + desc <<-EOT + Neutron provider to manage neutron_subnet type. + + Assumes that the neutron service is configured on the same host. + EOT + + commands :neutron => 'neutron' + commands :keystone => 'keystone' + + mk_resource_methods + + def self.neutron_type + 'subnet' + end + + def self.instances + list_neutron_resources(neutron_type).collect do |id| + attrs = get_neutron_resource_attrs(neutron_type, id) + new( + :ensure => :present, + :name => attrs['name'], + :id => attrs['id'], + :cidr => attrs['cidr'], + :ip_version => attrs['ip_version'], + :gateway_ip => parse_gateway_ip(attrs['gateway_ip']), + :allocation_pools => parse_allocation_pool(attrs['allocation_pools']), + :host_routes => parse_host_routes(attrs['host_routes']), + :dns_nameservers => parse_dns_nameservers(attrs['dns_nameservers']), + :enable_dhcp => attrs['enable_dhcp'], + :network_id => attrs['network_id'], + :tenant_id => attrs['tenant_id'] + ) + end + end + + def self.prefetch(resources) + subnets = instances + resources.keys.each do |name| + if provider = subnets.find{ |subnet| subnet.name == name } + resources[name].provider = provider + end + end + end + + def self.parse_gateway_ip(value) + return '' if value.nil? + return value + end + + def self.parse_allocation_pool(values) + allocation_pools = [] + return [] if values.empty? + for value in Array(values) + matchdata = /\{\s*"start"\s*:\s*"(.*)"\s*,\s*"end"\s*:\s*"(.*)"\s*\}/.match(value.gsub(/\\"/,'"')) + start_ip = matchdata[1] + end_ip = matchdata[2] + allocation_pools << "start=#{start_ip},end=#{end_ip}" + end + return allocation_pools + end + + def self.parse_host_routes(values) + host_routes = [] + return [] if values.empty? + for value in Array(values) + matchdata = /\{\s*"destination"\s*:\s*"(.*)"\s*,\s*"nexthop"\s*:\s*"(.*)"\s*\}/.match(value) + destination = matchdata[1] + nexthop = matchdata[2] + host_routes << "destination=#{destination},nexthop=#{nexthop}" + end + return host_routes + end + + def self.parse_dns_nameservers(values) + # just enforce that this is actually an array + return Array(values) + end + + def exists? + @property_hash[:ensure] == :present + end + + def create + opts = ["--name=#{@resource[:name]}"] + + if @resource[:ip_version] + opts << "--ip-version=#{@resource[:ip_version]}" + end + + if @resource[:gateway_ip] + if @resource[:gateway_ip] == '' + opts << '--no-gateway' + else + opts << "--gateway-ip=#{@resource[:gateway_ip]}" + end + end + + if @resource[:enable_dhcp] == 'False' + opts << "--disable-dhcp" + else + opts << "--enable-dhcp" + end + + if @resource[:allocation_pools] + Array(@resource[:allocation_pools]).each do |allocation_pool| + opts << "--allocation-pool=#{allocation_pool}" + end + end + + if @resource[:dns_nameservers] + Array(@resource[:dns_nameservers]).each do |nameserver| + opts << "--dns-nameserver=#{nameserver}" + end + end + + if @resource[:host_routes] + Array(@resource[:host_routes]).each do |host_route| + opts << "--host-route=#{host_route}" + end + end + + if @resource[:tenant_name] + tenant_id = self.class.get_tenant_id(model.catalog, + @resource[:tenant_name]) + opts << "--tenant_id=#{tenant_id}" + elsif @resource[:tenant_id] + opts << "--tenant_id=#{@resource[:tenant_id]}" + end + + if @resource[:network_name] + opts << resource[:network_name] + elsif @resource[:network_id] + opts << resource[:network_id] + end + + results = auth_neutron('subnet-create', '--format=shell', + opts, resource[:cidr]) + + if results =~ /Created a new subnet:/ + attrs = self.class.parse_creation_output(results) + @property_hash = { + :ensure => :present, + :name => resource[:name], + :id => attrs['id'], + :cidr => attrs['cidr'], + :ip_version => attrs['ip_version'], + :gateway_ip => self.class.parse_gateway_ip(attrs['gateway_ip']), + :allocation_pools => self.class.parse_allocation_pool(attrs['allocation_pools']), + :host_routes => self.class.parse_host_routes(attrs['host_routes']), + :dns_nameservers => self.class.parse_dns_nameservers(attrs['dns_nameservers']), + :enable_dhcp => attrs['enable_dhcp'], + :network_id => attrs['network_id'], + :tenant_id => attrs['tenant_id'], + } + else + fail("did not get expected message on subnet creation, got #{results}") + end + end + + def destroy + auth_neutron('subnet-delete', name) + @property_hash[:ensure] = :absent + end + + def gateway_ip=(value) + if value == '' + auth_neutron('subnet-update', '--no-gateway', name) + else + auth_neutron('subnet-update', "--gateway-ip=#{value}", name) + end + end + + def enable_dhcp=(value) + if value == 'False' + auth_neutron('subnet-update', "--disable-dhcp", name) + else + auth_neutron('subnet-update', "--enable-dhcp", name) + end + end + + def dns_nameservers=(values) + unless values.empty? + opts = ["#{name}", "--dns-nameservers", "list=true"] + for value in values + opts << value + end + auth_neutron('subnet-update', opts) + end + end + + def host_routes=(values) + unless values.empty? + opts = ["#{name}", "--host-routes", "type=dict", "list=true"] + for value in values + opts << value + end + auth_neutron('subnet-update', opts) + end + end + + [ + :cidr, + :ip_version, + :network_id, + :allocation_pools, + :tenant_id, + ].each do |attr| + define_method(attr.to_s + "=") do |value| + fail("Property #{attr.to_s} does not support being updated") + end + end + +end diff --git a/deployment_scripts/puppet/modules/neutron/lib/puppet/type/neutron_config.rb b/deployment_scripts/puppet/modules/neutron/lib/puppet/type/neutron_config.rb new file mode 100644 index 0000000..e83547b --- /dev/null +++ b/deployment_scripts/puppet/modules/neutron/lib/puppet/type/neutron_config.rb @@ -0,0 +1,47 @@ +Puppet::Type.newtype(:neutron_config) do + + ensurable + + newparam(:name, :namevar => true) do + desc 'Section/setting name to manage from neutron.conf' + newvalues(/\S+\/\S+/) + end + + newproperty(:value) do + desc 'The value of the setting to be defined.' + munge do |value| + value = value.to_s.strip + value.capitalize! if value =~ /^(true|false)$/i + value + end + + def is_to_s( currentvalue ) + if resource.secret? + return '[old secret redacted]' + else + return currentvalue + end + end + + def should_to_s( newvalue ) + if resource.secret? + return '[new secret redacted]' + else + return newvalue + end + end + end + + newparam(:secret, :boolean => true) do + desc 'Whether to hide the value from Puppet logs. Defaults to `false`.' + + newvalues(:true, :false) + + defaultto false + end + + def create + provider.create + end + +end diff --git a/deployment_scripts/puppet/modules/neutron/lib/puppet/type/neutron_network.rb b/deployment_scripts/puppet/modules/neutron/lib/puppet/type/neutron_network.rb new file mode 100644 index 0000000..d151e5c --- /dev/null +++ b/deployment_scripts/puppet/modules/neutron/lib/puppet/type/neutron_network.rb @@ -0,0 +1,90 @@ +Puppet::Type.newtype(:neutron_network) do + + ensurable + + newparam(:name, :namevar => true) do + desc 'Symbolic name for the network' + newvalues(/.*/) + end + + newproperty(:id) do + desc 'The unique id of the network' + validate do |v| + raise(Puppet::Error, 'This is a read only property') + end + end + + newproperty(:admin_state_up) do + desc 'The administrative status of the network' + newvalues(/(t|T)rue/, /(f|F)alse/) + munge do |v| + v.to_s.capitalize + end + end + + newproperty(:shared) do + desc 'Whether this network should be shared across all tenants or not' + newvalues(/(t|T)rue/, /(f|F)alse/) + munge do |v| + v.to_s.capitalize + end + end + + newparam(:tenant_name) do + desc 'The name of the tenant which will own the network.' + end + + newproperty(:tenant_id) do + desc 'A uuid identifying the tenant which will own the network.' + end + + newproperty(:provider_network_type) do + desc 'The physical mechanism by which the virtual network is realized.' + newvalues(:flat, :vlan, :local, :gre) + end + + newproperty(:provider_physical_network) do + desc <<-EOT + The name of the physical network over which the virtual network + is realized for flat and VLAN networks. + EOT + newvalues(/\S+/) + end + + newproperty(:provider_segmentation_id) do + desc 'Identifies an isolated segment on the physical network.' + munge do |v| + Integer(v) + end + end + + newproperty(:router_external) do + desc 'Whether this router will route traffic to an external network' + newvalues(/(t|T)rue/, /(f|F)alse/) + munge do |v| + v.to_s.capitalize + end + end + + # Require the neutron-server service to be running + autorequire(:service) do + ['neutron-server'] + end + + autorequire(:keystone_tenant) do + [self[:tenant_name]] if self[:tenant_name] + end + + validate do + if self[:ensure] != :present + return + end + if self[:tenant_id] && self[:tenant_name] + raise(Puppet::Error, <<-EOT +Please provide a value for only one of tenant_name and tenant_id. +EOT + ) + end + end + +end diff --git a/deployment_scripts/puppet/modules/neutron/lib/puppet/type/neutron_plugin_ml2.rb b/deployment_scripts/puppet/modules/neutron/lib/puppet/type/neutron_plugin_ml2.rb new file mode 100644 index 0000000..e121a11 --- /dev/null +++ b/deployment_scripts/puppet/modules/neutron/lib/puppet/type/neutron_plugin_ml2.rb @@ -0,0 +1,20 @@ +Puppet::Type.newtype(:neutron_plugin_ml2) do + + ensurable + + newparam(:name, :namevar => true) do + desc 'Section/setting name to manage from ml2_conf.ini' + newvalues(/\S+\/\S+/) + end + + autorequire(:package) do ['neutron'] end + + newproperty(:value) do + desc 'The value of the setting to be defined.' + munge do |value| + value = value.to_s.strip + value.capitalize! if value =~ /^(true|false)$/i + value + end + end +end diff --git a/deployment_scripts/puppet/modules/neutron/lib/puppet/type/neutron_plugin_ml2_cisco.rb b/deployment_scripts/puppet/modules/neutron/lib/puppet/type/neutron_plugin_ml2_cisco.rb new file mode 100644 index 0000000..c27ebd7 --- /dev/null +++ b/deployment_scripts/puppet/modules/neutron/lib/puppet/type/neutron_plugin_ml2_cisco.rb @@ -0,0 +1,47 @@ +Puppet::Type.newtype(:neutron_plugin_ml2_cisco) do + + ensurable + + newparam(:name, :namevar => true) do + desc 'Section/setting name to manage from cisco_plugins.ini' + newvalues(/\S+\/\S+/) + end + + autorequire(:file) do + ['/etc/neutron/plugins/ml2/ml2_conf_cisco.ini'] + end + + newproperty(:value) do + desc 'The value of the setting to be defined.' + munge do |value| + value = value.to_s.strip + value.capitalize! if value =~ /^(true|false)$/i + value + end + + def is_to_s( currentvalue ) + if resource.secret? + return '[old secret redacted]' + else + return currentvalue + end + end + + def should_to_s( newvalue ) + if resource.secret? + return '[new secret redacted]' + else + return newvalue + end + end + end + + newparam(:secret, :boolean => true) do + desc 'Whether to hide the value from Puppet logs. Defaults to `false`.' + + newvalues(:true, :false) + + defaultto false + end + +end diff --git a/deployment_scripts/puppet/modules/neutron/lib/puppet/type/neutron_port.rb b/deployment_scripts/puppet/modules/neutron/lib/puppet/type/neutron_port.rb new file mode 100644 index 0000000..03d2d9b --- /dev/null +++ b/deployment_scripts/puppet/modules/neutron/lib/puppet/type/neutron_port.rb @@ -0,0 +1,98 @@ +Puppet::Type.newtype(:neutron_port) do + desc <<-EOT + This is currently used to model the creation of neutron ports. + + Ports are used when associating a network and a router interface. + EOT + + ensurable + + newparam(:name, :namevar => true) do + desc 'Symbolic name for the port' + newvalues(/.*/) + end + + newproperty(:id) do + desc 'The unique id of the port' + validate do |v| + raise(Puppet::Error, 'This is a read only property') + end + end + + newproperty(:admin_state_up) do + desc 'The administrative status of the router' + newvalues(/(t|T)rue/, /(f|F)alse/) + munge do |v| + v.to_s.capitalize + end + end + + newproperty(:network_name) do + desc <<-EOT + The name of the network that this port is assigned to on creation. + EOT + end + + newproperty(:network_id) do + desc <<-EOT + The uuid of the network that this port is assigned to on creation. + EOT + validate do |v| + raise(Puppet::Error, 'This is a read only property') + end + end + + newproperty(:subnet_name) do + desc 'A subnet to which the port is assigned on creation.' + end + + newproperty(:subnet_id) do + desc <<-EOT + The uuid of the subnet on which this ports ip exists. + EOT + validate do |v| + raise(Puppet::Error, 'This is a read only property') + end + end + + newproperty(:ip_address) do + desc 'A static ip address given to the port on creation.' + end + + newproperty(:status) do + desc 'Whether the port is currently operational or not.' + validate do |v| + raise(Puppet::Error, 'This is a read only property') + end + end + + newparam(:tenant_name) do + desc 'The name of the tenant which will own the port.' + end + + newproperty(:tenant_id) do + desc 'A uuid identifying the tenant which will own the port.' + end + + autorequire(:service) do + ['neutron-server'] + end + + autorequire(:keystone_tenant) do + [self[:tenant_name]] if self[:tenant_name] + end + + autorequire(:neutron_network) do + [self[:name]] + end + + validate do + if self[:tenant_id] && self[:tenant_name] + raise(Puppet::Error, 'Please provide a value for only one of tenant_name and tenant_id.') + end + if self[:ip_address] && self[:subnet_name] + raise(Puppet::Error, 'Please provide a value for only one of ip_address and subnet_name.') + end + end + +end diff --git a/deployment_scripts/puppet/modules/neutron/lib/puppet/type/neutron_router.rb b/deployment_scripts/puppet/modules/neutron/lib/puppet/type/neutron_router.rb new file mode 100644 index 0000000..36835f0 --- /dev/null +++ b/deployment_scripts/puppet/modules/neutron/lib/puppet/type/neutron_router.rb @@ -0,0 +1,91 @@ +Puppet::Type.newtype(:neutron_router) do + + ensurable + + newparam(:name, :namevar => true) do + desc 'Symbolic name for the router' + newvalues(/.*/) + end + + newproperty(:id) do + desc 'The unique id of the router' + validate do |v| + raise(Puppet::Error, 'This is a read only property') + end + end + + newproperty(:admin_state_up) do + desc 'The administrative status of the router' + newvalues(/(t|T)rue/, /(f|F)alse/) + munge do |v| + v.to_s.capitalize + end + end + + newproperty(:external_gateway_info) do + desc <<-EOT + External network that this router connects to for gateway services + (e.g., NAT). + EOT + validate do |v| + raise(Puppet::Error, 'This is a read only property') + end + end + + newproperty(:gateway_network_name) do + desc <<-EOT + The name of the external network that this router connects to + for gateway services (e.g. NAT). + EOT + end + + newproperty(:gateway_network_id) do + desc <<-EOT + The uuid of the external network that this router connects to + for gateway services (e.g. NAT). + EOT + validate do |v| + raise(Puppet::Error, 'This is a read only property') + end + end + + newproperty(:status) do + desc 'Whether the router is currently operational or not.' + validate do |v| + raise(Puppet::Error, 'This is a read only property') + end + end + + newparam(:tenant_name) do + desc 'The name of the tenant which will own the router.' + end + + newproperty(:tenant_id) do + desc 'A uuid identifying the tenant which will own the router.' + end + + autorequire(:service) do + ['neutron-server'] + end + + autorequire(:keystone_tenant) do + [self[:tenant_name]] if self[:tenant_name] + end + + autorequire(:neutron_network) do + [self[:gateway_network_name]] if self[:gateway_network_name] + end + + validate do + if self[:ensure] != :present + return + end + if self[:tenant_id] && self[:tenant_name] + raise(Puppet::Error, <<-EOT +Please provide a value for only one of tenant_name and tenant_id. +EOT + ) + end + end + +end diff --git a/deployment_scripts/puppet/modules/neutron/lib/puppet/type/neutron_router_interface.rb b/deployment_scripts/puppet/modules/neutron/lib/puppet/type/neutron_router_interface.rb new file mode 100644 index 0000000..b4d15b6 --- /dev/null +++ b/deployment_scripts/puppet/modules/neutron/lib/puppet/type/neutron_router_interface.rb @@ -0,0 +1,51 @@ +Puppet::Type.newtype(:neutron_router_interface) do + + desc <<-EOT + This is currently used to model the creation of + neutron router interfaces. + + Router interfaces are an association between a router and a + subnet. + EOT + + ensurable + + newparam(:name, :namevar => true) do + newvalues(/^\S+:\S+$/) + end + + newproperty(:id) do + validate do |v| + raise(Puppet::Error, 'This is a read only property') + end + end + + newproperty(:router_name) do + validate do |v| + raise(Puppet::Error, 'This is a read only property') + end + end + + newproperty(:subnet_name) do + validate do |v| + raise(Puppet::Error, 'This is a read only property') + end + end + + newproperty(:port) do + desc 'An existing neutron port to which a rounter interface should be assigned' + end + + autorequire(:service) do + ['neutron-server'] + end + + autorequire(:neutron_router) do + self[:name].split(':', 2).first + end + + autorequire(:neutron_subnet) do + self[:name].split(':', 2).last + end + +end diff --git a/deployment_scripts/puppet/modules/neutron/lib/puppet/type/neutron_subnet.rb b/deployment_scripts/puppet/modules/neutron/lib/puppet/type/neutron_subnet.rb new file mode 100644 index 0000000..fb37363 --- /dev/null +++ b/deployment_scripts/puppet/modules/neutron/lib/puppet/type/neutron_subnet.rb @@ -0,0 +1,114 @@ +Puppet::Type.newtype(:neutron_subnet) do + + ensurable + + newparam(:name, :namevar => true) do + desc 'Symbolic name for the subnet' + newvalues(/.*/) + end + + newproperty(:id) do + desc 'The unique id of the subnet' + validate do |v| + raise(Puppet::Error, 'This is a read only property') + end + end + + newproperty(:cidr) do + desc 'CIDR representing IP range for this subnet, based on IP version' + end + + newproperty(:ip_version) do + desc 'The IP version of the CIDR' + newvalues('4', '6') + end + + newproperty(:allocation_pools, :array_matching => :all) do + desc <<-EOT + Array of Sub-ranges of cidr available for dynamic allocation to ports. + Syntax:["start=IPADDR,end=IPADDR", ...] + EOT + end + + newproperty(:gateway_ip) do + desc <<-EOT + The default gateway provided by DHCP to devices in this subnet. If set to + '' then no gateway IP address will be provided via DHCP. + EOT + end + + newproperty(:enable_dhcp) do + desc 'Whether DHCP is enabled for this subnet or not.' + newvalues(/(t|T)rue/, /(f|F)alse/) + munge do |v| + v.to_s.capitalize + end + end + + newproperty(:host_routes, :array_matching => :all) do + desc <<-EOT + Array of routes that should be used by devices with IPs from this subnet + (not including local subnet route). + Syntax:["destination=CIDR,nexhop=IP_ADDR", ...] + EOT + end + + newproperty(:dns_nameservers, :array_matching => :all) do + desc <<-EOT + 'Array of DNS name servers used by hosts in this subnet.' + EOT + end + + newproperty(:network_id) do + desc 'A uuid identifying the network this subnet is associated with.' + end + + newparam(:network_name) do + desc 'The name of the network this subnet is associated with.' + end + + newparam(:tenant_name) do + desc 'The name of the tenant which will own the subnet.' + end + + newproperty(:tenant_id) do + desc 'A uuid identifying the tenant which will own the subnet.' + end + + autorequire(:service) do + ['neutron-server'] + end + + autorequire(:keystone_tenant) do + [self[:tenant_name]] if self[:tenant_name] + end + + autorequire(:neutron_network) do + [self[:network_name]] if self[:network_name] + end + + validate do + if self[:ensure] != :present + return + end + if ! self[:cidr] + raise(Puppet::Error, 'Please provide a valid CIDR') + elsif ! (self[:network_id] || self[:network_name]) + raise(Puppet::Error, <<-EOT +A value for one of network_name or network_id must be provided. +EOT + ) + elsif self[:network_id] && self[:network_name] + raise(Puppet::Error, <<-EOT +Please provide a value for only one of network_name and network_id. +EOT + ) + elsif self[:tenant_id] && self[:tenant_name] + raise(Puppet::Error, <<-EOT +Please provide a value for only one of tenant_name and tenant_id. +EOT + ) + end + end + +end