diff --git a/deployment_scripts/puppet/manifests/contrail-compute-aggregate.pp b/deployment_scripts/puppet/manifests/contrail-compute-aggregate.pp new file mode 100644 index 000000000..dc8245f2d --- /dev/null +++ b/deployment_scripts/puppet/manifests/contrail-compute-aggregate.pp @@ -0,0 +1,19 @@ +# Copyright 2016 Mirantis, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +notice('MODULAR: contrail/contrail-compute-aggregate.pp') + +include contrail + +class { 'contrail::compute::aggregate': } diff --git a/deployment_scripts/puppet/manifests/contrail-compute-hugepages.pp b/deployment_scripts/puppet/manifests/contrail-compute-hugepages.pp new file mode 100644 index 000000000..0c2f9c8e7 --- /dev/null +++ b/deployment_scripts/puppet/manifests/contrail-compute-hugepages.pp @@ -0,0 +1,18 @@ +# Copyright 2016 Mirantis, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +notice('MODULAR: contrail/contrail-compute-hugepages.pp') + +include contrail +class { 'contrail::compute::hugepages': } diff --git a/deployment_scripts/puppet/manifests/contrail-db-provision.pp b/deployment_scripts/puppet/manifests/contrail-db-provision.pp old mode 100755 new mode 100644 diff --git a/deployment_scripts/puppet/modules/contrail/lib/puppet/provider/augeasprovider/default.rb b/deployment_scripts/puppet/modules/contrail/lib/puppet/provider/augeasprovider/default.rb new file mode 100644 index 000000000..79df767a4 --- /dev/null +++ b/deployment_scripts/puppet/modules/contrail/lib/puppet/provider/augeasprovider/default.rb @@ -0,0 +1,959 @@ +require 'augeas' if Puppet.features.augeas? + +# Base Augeas provider +# Handles basics such as opening, accessing and saving changes via an Augeas +# handle, plus standard configuration from a Puppet resource (e.g. the `target` +# parameter). +# +# To use, include as parent provider: +# +# Puppet::Type.type(:example).provide( +# :augeas, +# :parent => Puppet::Type.type(:augeasprovider).provider(:default) +# ) do +# # [..] +# end +# +Puppet::Type.type(:augeasprovider).provide(:default) do + # Class methods automatically added to a Puppet provider by including the + # {AugeasProviders::Provider} mixin. + + # Returns the Augeas version used + # + # @return [String] Augeas version in use + # @api public + def self.aug_version + @aug_version ||= Augeas.open(nil, nil, Augeas::NO_MODL_AUTOLOAD) { |aug| aug.get('/augeas/version') } + end + + # Returns whether a feature is supported. + # + # The following features are currently supported: + # + # * `:regexpi`: whether Augeas supports an 'i' flag in regexp expressions + # * `:post_resource_eval`: whether Puppet supports `post_resource_eval` hooks + # + # @param [Symbol] feature the feature to check + # @return [Boolean] whether feature is supported + # @api public + def self.supported?(feature) + case feature + when :regexpi + Puppet::Util::Package.versioncmp(aug_version, '1.0.0') >= 0 + when :post_resource_eval + Puppet::Util::Package.versioncmp(Puppet.version, '3.4.0') >= 0 + else + raise Puppet::Error, "Unknown feature '#{feature}'" + end + end + + # Returns a node label to use for creating a new entry in an Augeas sequence + # (seq), given the current list, e.g. '1' if it's the first. Supply + # aug.match('$target/*') or similar. + # + # @param [Array] existing paths, from Augeas#match + # @return [String] new node label + def self.next_seq(matches) + last = matches.map {|p| path_label(nil, p).to_i }.max || 0 + (last + 1).to_s + end + + # Returns an Augeas handler. + # + # On Puppet >= 3.4, stores and returns a shared Augeas handler + # for all instances of the class + # + # @return [Augeas] Augeas shared Augeas handle + # @api private + def self.aug_handler + if supported?(:post_resource_eval) + @aug ||= Augeas.open(nil, loadpath, Augeas::NO_MODL_AUTOLOAD) + else + Augeas.open(nil, loadpath, Augeas::NO_MODL_AUTOLOAD) + end + end + + # Close the shared Augeas handler. + # + # @param [Augeas] aug open Augeas handle + # @api public + def self.augclose!(aug) + aug.close + end + + # Opens Augeas and returns a handle to use. It loads only the file + # identified by {#target} (and the supplied `resource`) using {#lens}. + # + # If called with a block, this will be yielded to and the Augeas handle + # closed after the block has executed (on Puppet < 3.4.0). + # Otherwise, the handle will be returned and not closed automatically. + # On Puppet >= 3.4, the handle will be closed by `post_resource_eval`. + # On older versions, the caller is responsible for closing it to free + # resources. + # + # If `yield_resource` is set to true, the supplied `resource` will be passed + # as a yieldparam to the block, after the `aug` handle. Any arguments passed + # after `yield_resource` will be added as yieldparams to the block. + # + # @param [Puppet::Resource] resource resource being evaluated + # @param [Boolean] yield_resource whether to send `resource` as a yieldparam + # @param [Splat] yield_params a splat of parameters to pass as yieldparams if `yield_resource` is true + # @return [Augeas] Augeas handle if no block is given + # @yield [aug, resource, *yield_params] block that uses the Augeas handle + # @yieldparam [Augeas] aug open Augeas handle + # @yieldparam [Puppet::Resource] resource the supplied Puppet resource, passed if `yield_resource` is set to true + # @yieldparam [Splat] *yield_params a splat of additional arguments sent to the block, if `yield_resource` is set to true + # @raise [Puppet::Error] if Augeas did not load the file + # @api public + def self.augopen(resource = nil, yield_resource = false, *yield_params, &block) + augopen_internal(resource, false, yield_resource, *yield_params, &block) + end + + # Opens Augeas and returns a handle to use. It loads only the file + # for the current Puppet resource using {AugeasProviders::Provider::ClassMethods#lens}. + # #augsave! is called after the block is evaluated. + # + # If called with a block, this will be yielded to and the Augeas handle + # closed after the block has executed (on Puppet < 3.4.0). + # Otherwise, the handle will be returned and not closed automatically. + # On Puppet >= 3.4, the handle will be closed by `post_resource_eval`. + # On older versions, the caller is responsible for closing it to free + # resources. + # + # If `yield_resource` is set to true, the supplied `resource` will be passed + # as a yieldparam to the block, after the `aug` handle. Any arguments passed + # after `yield_resource` will be added as yieldparams to the block. + # + # @param [Puppet::Resource] resource resource being evaluated + # @param [Boolean] yield_resource whether to send `resource` as a yieldparam + # @param [Splat] yield_params a splat of parameters to pass as yieldparams if `yield_resource` is true + # @return [Augeas] Augeas handle if no block is given + # @yield [aug, resource, *yield_params] block that uses the Augeas handle + # @yieldparam [Augeas] aug open Augeas handle + # @yieldparam [Puppet::Resource] resource the supplied Puppet resource, passed if `yield_resource` is set to true + # @yieldparam [Splat] *yield_params a splat of additional arguments sent to the block, if `yield_resource` is set to true + # @raise [Puppet::Error] if Augeas did not load the file + # @api public + def self.augopen!(resource = nil, yield_resource = false, *yield_params, &block) + augopen_internal(resource, true, yield_resource, *yield_params, &block) + end + + # Saves all changes made in the current Augeas handle and checks for any + # errors while doing so. + # Reloads the tree afterwards to remove specific changes for next resource. + # + # @param [Augeas] aug open Augeas handle + # @param [Boolean] reload whether to reload the tree after saving + # @raise [Augeas::Error] if saving fails + # @api public + def self.augsave!(aug, reload = false) + begin + aug.save! + rescue Augeas::Error + errors = [] + aug.match("/augeas//error").each do |errnode| + aug.match("#{errnode}/*").each do |subnode| + subvalue = aug.get(subnode) + errors << "#{subnode} = #{subvalue}" + end + end + debug("Save failure details:\n" + errors.join("\n")) + raise Augeas::Error, 'Failed to save Augeas tree to file. See debug logs for details.' + ensure + aug.load! if reload + end + end + + # Define a method with a block passed to #augopen + # + # @param [Symbol] method the name of the method to create + # @yield [aug, resource, *args] block that uses the Augeas handle + # @yieldparam [Augeas] aug open Augeas handle + # @yieldparam [Puppet::Resource] resource the supplied Puppet resource + # @yieldparam [Splat] *args a splat of additional arguments sent to the block + # @api public + def self.define_aug_method(method, &block) + define_method(method) do |*args| + # We are calling the resource's augopen here, not the class + augopen(true, *args, &block) + end + end + + # Define a method with a block passed to #augopen! + # + # @param [Symbol] method the name of the method to create + # @yield [aug, resource, *args] block that uses the Augeas handle + # @yieldparam [Augeas] aug open Augeas handle + # @yieldparam [Puppet::Resource] resource the supplied Puppet resource + # @yieldparam [Splat] *args a splat of additional arguments sent to the block + # @api public + def self.define_aug_method!(method, &block) + define_method(method) do |*args| + # We are calling the resource's augopen! here, not the class + augopen!(true, *args, &block) + end + end + + # Defines a property getter with a provided implementation. It works from + # a node identified with the given `label` beneath the resource. + # + # Supports three implementations based on the type specified: + # + # :string causes the getter to return the value of the node below + # resource with the label given in opts + # + # :array causes the getter to return an array of values matching the label. + # If sublabel is given, values of matching nodes beneath the + # label node will be returned in an array. If sublabel is :seq, values of + # nodes matching a numbered seq will be returned. + # + # :hash causes the getter to return a hash of the value of each matching + # label node against the value of each sublabel node. + # + # @param [String] name the name of the property + # @param [Hash] opts the options to create the setter + # @option opts [String] label node label to match beneath resource, default is `name.to_s`. When the value is `:resource`, `$resource` will be used as the path to the node + # @option opts [Symbol] type either :string, :array or :hash + # @option opts [String] default default value for hash values if sublabel doesn't exist + # @option opts [String] sublabel label of next node(s) beneath node label, used in array and hash values, or :seq for array values representing a numbered seq + # @api public + def self.attr_aug_reader(name, opts = {}) + label = opts[:label] || name.to_s + default = opts[:default] || nil + type = opts[:type] || :string + sublabel = opts[:sublabel] || nil + + rpath = label == :resource ? '$resource' : "$resource/#{label}" + + if type == :hash and sublabel.nil? + fail "You must provide a sublabel for type hash" + end + + unless [:string, :array, :hash].include? type + fail "Invalid type: #{type}" + end + + # Class getter method using an existing aug handler + # Emulate define_singleton_method for Ruby 1.8 + metaclass = class << self; self; end + metaclass.send(:define_method, "attr_aug_reader_#{name}") do |aug, *args| + case type + when :string + aug.get(rpath) + when :array + aug.match(rpath).map do |p| + if sublabel.nil? + aug.get(p) + else + if sublabel == :seq + sp = "#{p}/*[label()=~regexp('[0-9]+')]" + else + sp = "#{p}/#{sublabel}" + end + aug.match(sp).map { |spp| aug.get(spp) } + end + end.flatten + when :hash + values = {} + aug.match(rpath).each do |p| + sp = "#{p}/#{sublabel}" + values[aug.get(p)] = aug.get(sp) || default + end + values + end + end + + # Instance getter method for the instance + define_method("attr_aug_reader_#{name}") do |aug, *args| + self.class.send("attr_aug_reader_#{name}", aug, *args) + end + + # We are calling the resource's augopen here, not the class + define_method(name) do |*args| + augopen do |aug| + self.send("attr_aug_reader_#{name}", aug, *args) + end + end + end + + # Defines a property setter using #augopen + # + # @param [String] name the name of the property + # @param [Hash] opts the options to create the setter + # @option opts [String] label node label to match beneath resource, default is `name.to_s`. When the value is `:resource`, `$resource` will be used as the path to the node + # @option opts [Symbol] type either :string, :array or :hash + # @option opts [String] default default value for hash values if sublabel doesn't exist + # @option opts [String] sublabel label of next node(s) beneath node label, used in array and hash values, or :seq for array values representing a numbered seq + # @option opts [Boolean] purge_ident whether to purge other matches (keeps the last one only) + # @option opts [Boolean] rm_node whether setting a string value to `nil` removes the node (default is to clear its value) + # @api public + def self.attr_aug_writer(name, opts = {}) + label = opts[:label] || name.to_s + default = opts[:default] || nil + type = opts[:type] || :string + sublabel = opts[:sublabel] || nil + purge_ident = opts[:purge_ident] || false + rm_node = opts[:rm_node] || false + + rpath = label == :resource ? '$resource' : "$resource/#{label}" + + if type == :hash and sublabel.nil? + fail "You must provide a sublabel for type hash" + end + + unless [:string, :array, :hash].include? type + fail "Invalid type: #{type}" + end + + # Class setter method using an existing aug handler + # Emulate define_singleton_method for Ruby 1.8 + metaclass = class << self; self; end + metaclass.send(:define_method, "attr_aug_writer_#{name}") do |aug, *args| + aug.rm("#{rpath}[position() != 1]") if purge_ident + case type + when :string + if args[0] + aug.set(rpath, args[0].to_s) + elsif rm_node + aug.rm(rpath) + else + aug.clear(rpath) + end + when :array + if args[0].nil? + aug.rm(rpath) + else + if sublabel.nil? + aug.rm(rpath) + count = 0 + args[0].each do |v| + count += 1 + aug.set("#{rpath}[#{count}]", v) + end + elsif sublabel == :seq + # Make sure only our values are used + aug.rm("#{rpath}/*[label()=~regexp('[0-9]+')]") + count = 0 + args[0].each do |v| + count += 1 + aug.set("#{rpath}/#{count}", v) + end + else + # Make sure only our values are used + aug.rm("#{rpath}/#{sublabel}") + count = 0 + args[0].each do |v| + count += 1 + aug.set("#{rpath}/#{sublabel}[#{count}]", v) + end + end + end + when :hash + # First get rid of all entries + aug.rm(rpath) + args[0].each do |k, v| + aug.set("#{rpath}[.='#{k}']", k) + unless v == default + aug.set("#{rpath}[.='#{k}']/#{sublabel}", v) + end + end + end + end + + # Instance setter method for the instance + define_method("attr_aug_writer_#{name}") do |aug, *args| + self.class.send("attr_aug_writer_#{name}", aug, *args) + end + + # We are calling the resource's augopen here, not the class + define_method("#{name}=") do |*args| + augopen! do |aug| + self.send("attr_aug_writer_#{name}", aug, *args) + end + end + end + + # Define getter and setter for a property + # + # @param [Symbol] name the name of the property + # @param [Hash] opts the options to create the setter + # @option opts [String] label node label to match beneath resource, default is `name.to_s`. When the value is `:resource`, `$resource` will be used as the path to the node + # @option opts [Symbol] type either :string, :array or :hash + # @option opts [String] default default value for hash values if sublabel doesn't exist + # @option opts [String] sublabel label of next node(s) beneath node label, used in array and hash values, or :seq for array values representing a numbered seq + # @option opts [Boolean] purge_ident whether to purge other matches (keeps the last one only) + # @api public + def self.attr_aug_accessor(name, opts = {}) + attr_aug_reader(name, opts) + attr_aug_writer(name, opts) + end + + # Setter for the default file path managed by the provider. + # + # Takes a block to store, but doesn't yield. Will be called when it's + # needed. + # + # @yield block that identifies the default file path managed by the provider + # @yieldreturn [String] default file path + # @api public + def self.default_file(&block) + @default_file_block = block + end + + # Getter and setter for the Augeas lens used for this provider. + # + # When called with a block, will only store the block - it doesn't yield. + # + # When called without a block, expects `resource` parameter which is + # passed into the block, which returns the lens to be used. + # + # @param resource [Puppet::Resource] required for getter, resource being evaluated + # @yield [resource] block that identifies the lens to use + # @yieldparam [Puppet::Resource] resource resource being evaluted + # @yieldreturn [String] Augeas lens to use, e.g. `'Hosts.lns'` + # @return [String] Augeas lens to use, e.g. `'Hosts.lns'` + # @raise [Puppet::Error] if no block has been set when getting + # @api public + def self.lens(resource = nil, &block) + if block_given? + @lens_block = block + else + fail 'Lens is not provided' unless @lens_block + @lens_block.call(resource) + end + end + + # Wrapper around aug.label for older versions of Augeas + # and values not found in the tree. + # + # @param [Augeas] aug Augeas handler + # @param [String] path expression to get the label from + # @return [String] label of the given path + # @api public + def self.path_label(aug, path) + if aug.respond_to? :label + label = aug.label(path) + end + + # Fallback + label || path.split("/")[-1].split("[")[0] + end + + # Determine which quote is needed + # + # @param [String] value the value to quote + # @param [String] oldvalue the optional old value, used to auto-detect existing quoting + # @return [String] the quoted value + # @api public + def self.whichquote(value, resource = nil, oldvalue = nil) + oldquote = readquote oldvalue + + if resource and resource.parameters.include? :quoted + quote = resource[:quoted] + else + quote = :auto + end + + if quote == :auto + quote = if oldquote + oldquote + elsif value =~ /[|&;()<>\s]/ + :double + else + :none + end + end + + case quote + when :double + '"' + when :single + "'" + else + '' + end + end + + # Automatically quote a value + # + # @param [String] value the value to quote + # @param [String] oldvalue the optional old value, used to auto-detect existing quoting + # @return [String] the quoted value + # @api public + def self.quoteit(value, resource = nil, oldvalue = nil) + quote = whichquote(value, resource, oldvalue) + "#{quote}#{value}#{quote}" + end + + # Detect what type of quoting a value uses + # + # @param [String] value the value to be analyzed + # @return [Symbol] the type of quoting used (:double, :single or nil) + # @api public + def self.readquote(value) + if value =~ /^(["'])(.*)(?:\1)$/ + case $1 + when '"' then :double + when "'" then :single + else nil end + else + nil + end + end + + # Getter and setter for the Augeas path expression representing an + # individual resource inside a file, that's managed by this provider. + # + # When called with a block, will only store the block - it doesn't yield. + # The block is later used to generate the path expression. + # + # When called without a block, expects `resource` parameter which is + # passed into the block, which returns the path expression representing + # the supplied resource. + # + # If no block has already been set, it returns the path expression + # representing the top-level of the file. + # + # @param resource [Puppet::Resource] required for getter, resource being evaluated + # @yield [resource] block that identifies the path expression + # @yieldparam [Puppet::Resource] resource resource being evaluted + # @yieldreturn [String] Augeas path expression, e.g. `'/files/etc/hosts/1'` + # @return [String] Augeas path expression to use, e.g. `'/files/etc/hosts/1'` + # @raise [Puppet::Error] if no default file block is set and no resource is passed + # @see AugeasProviders::Provider#resource_path + # @see #target + # @api public + def self.resource_path(resource = nil, &block) + if block_given? + @resource_path_block = block + else + if @resource_path_block + path = "/files#{target(resource)}" + @resource_path_block.call(resource) + else + "#{target(resource)}/#{resource[:name]}" + end + end + end + + # Sets useful Augeas variables for the session. + # + # * `$target` points to the root of the target file + # * `$resource` points to path defined by #resource_path + # + # It also sets `/augeas/context` to the target file so + # relative paths can be used, before the variables are set. + # + # If supplied with a resource, it will be used to determine the + # path to the used file. + # + # @param [Augeas] aug Augeas handle + # @param [Puppet::Resource] resource resource being evaluated + # @see #resource_path + # @api public + def self.setvars(aug, resource = nil) + aug.set('/augeas/context', "/files#{target(resource)}") + aug.defnode('target', "/files#{target(resource)}", nil) + aug.defvar('resource', resource_path(resource)) if resource + end + + # Gets the path expression representing the file being managed. + # + # If supplied with a resource, this will represent the file identified by + # the resource, else the default file that the provider manages. + # + # @param [Puppet::Resource] resource resource being evaluated + # @return [String] path expression representing the file being managed + # @raise [Puppet::Error] if no default block is set and no resource is passed + # @see AugeasProviders::Provider#target + # @see #resource_path + # @api public + def self.target(resource = nil) + file = @default_file_block.call if @default_file_block + file = resource[:target] if resource and resource[:target] + fail 'No target file given' if file.nil? + file.chomp('/') + end + + # Automatically unquote a value + # + # @param [String] value the value to unquote + # @return [String] the unquoted value + # @api public + def self.unquoteit(value) + if value =~ /^(["'])(.*)(?:\1)$/ + $2 + else + value + end + end + + # Returns whether text is parsed as path using lens + # + # @param [String] text the text to test + # @param [String] path the relative path to test + # @param [String] lens the lens to use for parsing + # @return [Boolean] whether the path was found when parsing text with lens + # @api public + def self.parsed_as?(text, path, lens) + Augeas.open(nil, nil, Augeas::NO_MODL_AUTOLOAD) do |aug| + if aug.respond_to? :text_store + aug.set('/input', text) + if aug.text_store(lens, '/input', '/parsed') + return aug.match("/parsed/#{path}").any? + end + else + # ruby-augeas < 0.5 doesn't support text_store + Tempfile.open('aug_text_store') do |tmpfile| + tmpfile.write(text) + tmpfile.flush + aug.transform( + :lens => lens, + :name => 'Text_store', + :incl => tmpfile.path.to_s, + :excl => [] + ) + aug.load! + return aug.match("/files#{tmpfile.path.to_s}/#{path}").any? + end + end + end + return false + end + + # Sets the post_resource_eval class hook for Puppet + # This is only used with Puppet > 3.4.0 + # and allows to clean the shared Augeas handler. + def self.post_resource_eval + augclose!(aug_handler) + @aug = nil + end + + # Returns a set of load paths to use when initialising Augeas. + # + # @return [String] colon-separated string of module paths, or nil if defaults are to be used + def self.loadpath + loadpath = nil + plugins = File.join(Puppet[:libdir], 'augeas', 'lenses') + if File.exists?(plugins) + loadpath = loadpath.to_s.split(File::PATH_SEPARATOR).push(plugins).join(File::PATH_SEPARATOR) + end + loadpath + end + + # Opens Augeas and returns a handle to use. It loads only the file + # identified by {#target} (and the supplied `resource`) using {#lens}. + # + # If called with a block, this will be yielded to and the Augeas handle + # closed after the block has executed (on Puppet < 3.4.0). + # Otherwise, the handle will be returned and not closed automatically. + # On Puppet >= 3.4, the handle will be closed by `post_resource_eval`. + # On older versions, the caller is responsible for closing it to free + # resources. + # + # If `yield_resource` is set to true, the supplied `resource` will be passed + # as a yieldparam to the block, after the `aug` handle. Any arguments passed + # after `yield_resource` will be added as yieldparams to the block. + # + # @param [Puppet::Resource] resource resource being evaluated + # @param [Boolean] autosave whether to call augsave! automatically after the block evaluation + # @param [Boolean] yield_resource whether to send `resource` as a yieldparam + # @param [Splat] yield_params a splat of parameters to pass as yieldparams if `yield_resource` is true + # @return [Augeas] Augeas handle if no block is given + # @yield [aug, resource, *yield_params] block that uses the Augeas handle + # @yieldparam [Augeas] aug open Augeas handle + # @yieldparam [Puppet::Resource] resource the supplied Puppet resource, passed if `yield_resource` is set to true + # @yieldparam [Splat] *yield_params a splat of additional arguments sent to the block, if `yield_resource` is set to true + # @raise [Puppet::Error] if Augeas did not load the file + # @api private + def self.augopen_internal(resource = nil, autosave = false, yield_resource = false, *yield_params, &block) + aug = aug_handler + file = target(resource) + begin + lens_name = lens[/[^\.]+/] + if aug.match("/augeas/load/#{lens_name}").empty? + aug.transform( + :lens => lens, + :name => lens_name, + :incl => file, + :excl => [] + ) + aug.load! + elsif aug.match("/augeas/load/#{lens_name}/incl[.='#{file}']").empty? + # Only add missing file + aug.set("/augeas/load/#{lens_name}/incl[.='#{file}']", file) + aug.load! + end + + if File.exist?(file) && aug.match("/files#{file}").empty? + message = aug.get("/augeas/files#{file}/error/message") + unless aug.match("/augeas/files#{file}/error/pos").empty? + line = aug.get("/augeas/files#{file}/error/line") + char = aug.get("/augeas/files#{file}/error/char") + message += " (line:#{line}, character:#{char})" + end + from = loadpath.nil? ? '' : " from #{loadpath}" + fail("Augeas didn't load #{file} with #{lens}#{from}: #{message}") + end + + if block_given? + setvars(aug, resource) + if yield_resource + block.call(aug, resource, *yield_params) + else + block.call(aug) + end + else + aug + end + rescue + autosave = false + raise + ensure + if aug && block_given? && !supported?(:post_resource_eval) + augsave!(aug) if autosave + augclose!(aug) + end + end + end + + # Returns the Augeas version used + # + # @return [String] Augeas version in use + # @api public + def aug_version + self.class.aug_version + end + + # Returns whether a feature is supported. + # + # The following features are currently supported: + # + # * `:regexpi`: whether Augeas supports an 'i' flag in regexp expressions + # * `:post_resource_eval`: whether Puppet supports `post_resource_eval` hooks + # + # @param [Symbol] feature the feature to check + # @return [Boolean] whether feature is supported + # @api public + def supported?(feature) + self.class.supported?(feature) + end + + # Opens Augeas and returns a handle to use. It loads only the file + # for the current Puppet resource using {AugeasProviders::Provider::ClassMethods#lens}. + # + # If called with a block, this will be yielded to and the Augeas handle + # closed after the block has executed (on Puppet < 3.4.0). + # Otherwise, the handle will be returned and not closed automatically. + # On Puppet >= 3.4, the handle will be closed by `post_resource_eval`. + # On older versions, the caller is responsible for closing it to free + # resources. + # + # If `yield_resource` is set to true, the supplied `resource` will be passed + # as a yieldparam to the block, after the `aug` handle. Any arguments passed + # after `yield_resource` will be added as yieldparams to the block. + # + # @return [Augeas] Augeas handle if no block is given + # @yield [aug, resource, *yield_params] block that uses the Augeas handle + # @yieldparam [Augeas] aug open Augeas handle + # @yieldparam [Puppet::Resource] resource the supplied Puppet resource, passed if `yield_resource` is set to true + # @yieldparam [Splat] *yield_params a splat of additional arguments sent to the block, if `yield_resource` is set to true + # @raise [Puppet::Error] if Augeas did not load the file + # @api public + def augopen(yield_resource = false, *yield_params, &block) + self.class.augopen(self.resource, yield_resource, *yield_params, &block) + end + + # Opens Augeas and returns a handle to use. It loads only the file + # for the current Puppet resource using {AugeasProviders::Provider::ClassMethods#lens}. + # #augsave! is called after the block is evaluated. + # + # If called with a block, this will be yielded to and the Augeas handle + # closed after the block has executed (on Puppet < 3.4.0). + # Otherwise, the handle will be returned and not closed automatically. + # On Puppet >= 3.4, the handle will be closed by `post_resource_eval`. + # On older versions, the caller is responsible for closing it to free + # resources. + # + # @return [Augeas] Augeas handle if no block is given + # @yield [aug, resource, *yield_params] block that uses the Augeas handle + # @yieldparam [Augeas] aug open Augeas handle + # @yieldparam [Puppet::Resource] resource the supplied Puppet resource, passed if `yield_resource` is set to true + # @yieldparam [Splat] *yield_params a splat of additional arguments sent to the block, if `yield_resource` is set to true + # @raise [Puppet::Error] if Augeas did not load the file + # @api public + def augopen!(yield_resource = false, *yield_params, &block) + self.class.augopen!(self.resource, yield_resource, *yield_params, &block) + end + + # Saves all changes made in the current Augeas handle and checks for any + # errors while doing so. + # + # @param [Augeas] aug open Augeas handle + # @param [Boolean] reload whether to reload the tree after saving + # @raise [Augeas::Error] if saving fails + # @api public + def augsave!(aug, reload = false) + self.class.augsave!(aug, reload) + end + + # Close the shared Augeas handler. + # + # @param [Augeas] aug open Augeas handle + # @api public + def augclose!(aug) + self.class.augclose!(aug) + end + + # Returns an Augeas handler. + # + # On Puppet >= 3.4, stores and returns a shared Augeas handler + # for all instances of the class + # + # @return [Augeas] Augeas shared Augeas handle + # @api private + def aug_handler + self.class.aug_handler + end + + # Wrapper around Augeas#label for older versions of Augeas + # + # @param [Augeas] aug Augeas handler + # @param [String] path expression to get the label from + # @return [String] label of the given path + # @api public + def path_label(aug, path) + self.class.path_label(aug, path) + end + + # Determine which quote is needed + # + # @param [String] value the value to quote + # @param [String] oldvalue the optional old value, used to auto-detect existing quoting + # @return [String] the quoted value + # @api public + def whichquote(value, oldvalue = nil) + self.class.whichquote(value, self.resource, oldvalue) + end + + # Automatically quote a value + # + # @param [String] value the value to quote + # @param [String] oldvalue the optional old value, used to auto-detect existing quoting + # @return [String] the quoted value + # @api public + def quoteit(value, oldvalue = nil) + self.class.quoteit(value, self.resource, oldvalue) + end + + # Detect what type of quoting a value uses + # + # @param [String] value the value to be analyzed + # @return [Symbol] the type of quoting used (:double, :single or nil) + # @api public + def readquote(value) + self.class.readquote(value) + end + + # Gets the Augeas path expression representing the individual resource inside + # the file, that represents the current Puppet resource. + # + # If no block was set by the provider's class method, it returns the path + # expression representing the top-level of the file. + # + # @return [String] Augeas path expression to use, e.g. `'/files/etc/hosts/1'` + # @see AugeasProviders::Provider::ClassMethods#resource_path + # @see #target + # @api public + def resource_path + self.class.resource_path(self.resource) + end + + # Sets useful Augeas variables for the session: + # + # * `$target` points to the root of the target file + # * `$resource` points to path defined by #resource_path + # + # It also sets `/augeas/context` to the target file so + # relative paths can be used, before the variables are set. + # + # If supplied with a resource, it will be used to determine the + # path to the used file. + # + # @param [Augeas] aug Augeas handle + # @see #resource_path + # @api public + def setvars(aug) + self.class.setvars(aug, self.resource) + end + + # Gets the path expression representing the file being managed for the + # current Puppet resource. + # + # @return [String] path expression representing the file being managed + # @see AugeasProviders::Provider::ClassMethods#target + # @see #resource_path + # @api public + def target + self.class.target(self.resource) + end + + # Automatically unquote a value + # + # @param [String] value the value to unquote + # @return [String] the unquoted value + # @api public + def unquoteit(value) + self.class.unquoteit(value) + end + + # Returns whether text is parsed as path using lens + # + # @param [String] text the text to test + # @param [String] path the relative path to test + # @param [String] lens the lens to use for parsing + # @return [Boolean] whether the path was found when parsing text with lens + # @api public + def parsed_as?(text, path, lens = nil) + lens ||= self.class.lens(self.resource) + self.class.parsed_as?(text, path, lens) + end + + # Default method to determine the existence of a resource + # can be overridden if necessary + def exists? + augopen do |aug| + not aug.match('$resource').empty? + end + end + + # Default method to destroy a resource + # can be overridden if necessary + def destroy + augopen! do |aug| + aug.rm('$resource') + end + end + + # Default method to flush a resource + # + # On Puppet >= 3.4, this takes care of + # saving the tree for the shared Augeas handler. + # + # This method can be overridden in your provider + # but you should make sure to call `super` + # to ensure that the tree will be saved in Puppet >= 3.4 + def flush + augsave!(aug_handler, true) if supported?(:post_resource_eval) + end + + # Returns a node label to use for creating a new entry in an Augeas sequence + # (seq), given the current list, e.g. '1' if it's the first. Supply + # aug.match('$target/*') or similar. + # + # @param [Array] existing paths, from Augeas#match + # @return [String] new node label + def next_seq(matches) + self.class.next_seq(matches) + end +end diff --git a/deployment_scripts/puppet/modules/contrail/lib/puppet/provider/kernel_parameter/grub2.rb b/deployment_scripts/puppet/modules/contrail/lib/puppet/provider/kernel_parameter/grub2.rb new file mode 100644 index 000000000..cbf37830c --- /dev/null +++ b/deployment_scripts/puppet/modules/contrail/lib/puppet/provider/kernel_parameter/grub2.rb @@ -0,0 +1,160 @@ +# GRUB 2 support for kernel parameters, edits /etc/default/grub +# +# Copyright (c) 2012 Dominic Cleal +# Licensed under the Apache License, Version 2.0 + +Puppet::Type.type(:kernel_parameter).provide(:grub2, :parent => Puppet::Type.type(:augeasprovider).provider(:default)) do + desc "Uses Augeas API to update kernel parameters in GRUB2's /etc/default/grub" + + default_file { '/etc/default/grub' } + + lens { 'Shellvars_list.lns' } + + resource_path do |resource| + "$target/#{section(resource)}/value[.=~regexp('^#{resource[:name]}(=.*)?$')]" + end + + def self.mkconfig_path + which("grub2-mkconfig") or which("grub-mkconfig") or '/usr/sbin/grub-mkconfig' + end + + defaultfor :osfamily => 'Redhat', :operatingsystemmajrelease => [ '7' ] + defaultfor :operatingsystem => 'Debian', :operatingsystemmajrelease => [ '8' ] + defaultfor :operatingsystem => 'Ubuntu', :operatingsystemmajrelease => [ '14.04' ] + + confine :feature => :augeas + commands :mkconfig => mkconfig_path + + def self.instances + augopen do |aug| + resources = [] + + # Params are nicely separated, but no recovery-only setting (hard-coded) + sections = { 'all' => "GRUB_CMDLINE_LINUX", + 'normal' => "GRUB_CMDLINE_LINUX_DEFAULT", + 'default' => "GRUB_CMDLINE_LINUX_DEFAULT" } + sections.keys.sort.each do |bootmode| + key = sections[bootmode] + # Get all unique param names + params = aug.match("$target/#{key}/value").map { |pp| + aug.get(pp).split("=")[0] + }.uniq + + # Find all values for each param name + params.each do |param| + vals = aug.match("$target/#{key}/value[.=~regexp('^#{param}(=.*)?$')]").map {|vp| + aug.get(vp).split("=", 2)[1] + } + vals = vals[0] if vals.size == 1 + + param = {:ensure => :present, :name => param, :value => vals, :bootmode => bootmode} + resources << new(param) + end + end + resources + end + end + + def self.section(resource) + case resource[:bootmode].to_s + when "default", "normal" + "GRUB_CMDLINE_LINUX_DEFAULT" + when "all" + "GRUB_CMDLINE_LINUX" + else + fail("Unsupported bootmode for #{self.class.to_s} provider") + end + end + + def create + self.value=(resource[:value]) + end + + def value + augopen do |aug| + aug.match('$resource').map {|vp| + aug.get(vp).split("=", 2)[1] + } + end + end + + # If GRUB_CMDLINE_LINUX_DEFAULT does not exist, it should be set to the + # present contents of GRUB_CMDLINE_LINUX. + # If this is not done, you may end up with garbage on your next kernel + # upgrade! + def munge_grub_cmdline_linux_default(aug) + src_path = '$target/GRUB_CMDLINE_LINUX/value' + dest_path = '$target/GRUB_CMDLINE_LINUX_DEFAULT' + + if aug.match("#{dest_path}/value").empty? + aug.match(src_path).each do |val| + src_val = aug.get(val) + + # Need to let the rest of the code work on the actual value properly. + unless src_val.split('=').first.strip == resource[:name] + val_target = val.split('/').last + + aug.set("#{dest_path}/#{val_target}", src_val) + end + end + end + end + + def value=(newval) + augopen! do |aug| + # If we don't have the section at all, add it. Otherwise, any + # manipulation will result in a parse error. + current_section = self.class.section(resource) + has_section = aug.match("$target/#{current_section}") + + if !has_section || has_section.empty? + aug.set("$target/#{current_section}/quote",'"') + end + + if current_section == 'GRUB_CMDLINE_LINUX_DEFAULT' + munge_grub_cmdline_linux_default(aug) + end + + if newval && !newval.empty? + vals = newval.clone + else + # If no value (e.g. "quiet") then clear the value from the first and + # delete the rest + vals = nil + aug.set("#{resource_path}[1]", resource[:name]) + aug.rm("#{resource_path}[position() > 1]") + end + + # Set any existing parameters with this name, remove excess ones + if vals + aug.match('$resource').each do |ppath| + val = vals.shift + if val.nil? + aug.rm(ppath) + else + aug.set(ppath, "#{resource[:name]}=#{val}") + end + end + end + + # Add new parameters where there are more values than existing params + if vals && !vals.empty? + vals.each do |val| + aug.set("$target/#{current_section}/value[last()+1]", "#{resource[:name]}=#{val}") + end + end + end + end + + def flush + cfg = nil + ["/boot/grub/grub.cfg", "/boot/grub2/grub.cfg", "/boot/efi/EFI/fedora/grub.cfg"].each {|c| + cfg = c if FileTest.file? c + } + fail("Cannot find grub.cfg location to use with grub-mkconfig") unless cfg + + super + mkconfig "-o", cfg + end +end + diff --git a/deployment_scripts/puppet/modules/contrail/lib/puppet/type/augeasprovider.rb b/deployment_scripts/puppet/modules/contrail/lib/puppet/type/augeasprovider.rb new file mode 100644 index 000000000..77eded6bd --- /dev/null +++ b/deployment_scripts/puppet/modules/contrail/lib/puppet/type/augeasprovider.rb @@ -0,0 +1,5 @@ +# Dumb augeasprovider type + +Puppet::Type.newtype(:augeasprovider) do + @doc = 'Dumb Augeas provider type' +end diff --git a/deployment_scripts/puppet/modules/contrail/lib/puppet/type/kernel_parameter.rb b/deployment_scripts/puppet/modules/contrail/lib/puppet/type/kernel_parameter.rb new file mode 100644 index 000000000..41d9ce486 --- /dev/null +++ b/deployment_scripts/puppet/modules/contrail/lib/puppet/type/kernel_parameter.rb @@ -0,0 +1,36 @@ +# Manages kernel parameters stored in bootloaders such as GRUB. +# +# Copyright (c) 2012 Dominic Cleal +# Licensed under the Apache License, Version 2.0 + +Puppet::Type.newtype(:kernel_parameter) do + @doc = "Manages kernel parameters stored in bootloaders." + + ensurable + + newparam(:name) do + desc "The parameter name, e.g. 'quiet' or 'vga'." + isnamevar + end + + newproperty(:value, :array_matching => :all) do + desc "Value of the parameter if applicable. Many parameters are just keywords so this must be left blank, while others (e.g. 'vga') will take a value." + end + + newparam(:target) do + desc "The bootloader configuration file, if in a non-default location for the provider." + end + + newparam(:bootmode) do + desc "Boot mode(s) to apply the parameter to. Either 'all' (default) to use the parameter on all boots (normal and recovery mode), 'default' for just the default boot entry, 'normal' for just normal boots or 'recovery' for just recovery boots." + + newvalues :all, :default, :normal, :recovery + + defaultto :all + end + + autorequire(:file) do + self[:target] + end +end + diff --git a/deployment_scripts/puppet/modules/contrail/manifests/compute/aggregate.pp b/deployment_scripts/puppet/modules/contrail/manifests/compute/aggregate.pp new file mode 100644 index 000000000..28908a761 --- /dev/null +++ b/deployment_scripts/puppet/modules/contrail/manifests/compute/aggregate.pp @@ -0,0 +1,79 @@ +# Copyright 2016 Mirantis, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +class contrail::compute::aggregate { + + define contrail::provision::aggr_add_host { + exec { "aggr_add_host_${name}": + command => "bash -c \"nova aggregate-add-host hpgs-aggr ${name}\"", + returns => [0,1], + } + } + + if $contrail::dpdk_enabled { + + $nodes_hash = hiera('nodes') + $dpdk_compute_nodes = nodes_with_roles(['dpdk'], 'fqdn') + $dpdk_hosts = join($dpdk_compute_nodes, ',') + $nova_hash = hiera_hash('nova', {}) + $keystone_tenant = pick($nova_hash['tenant'], 'services') + $keystone_user = pick($nova_hash['user'], 'nova') + $service_endpoint = hiera('service_endpoint') + $region = hiera('region', 'RegionOne') + + Exec { + provider => 'shell', + path => '/sbin:/usr/sbin:/bin:/usr/bin', + tries => 10, + try_sleep => 2, + environment => [ + "OS_TENANT_NAME=${keystone_tenant}", + "OS_USERNAME=${keystone_user}", + "OS_PASSWORD=${nova_hash['user_password']}", + "OS_AUTH_URL=http://${service_endpoint}:5000/v2.0/", + 'OS_ENDPOINT_TYPE=internalURL', + "OS_REGION_NAME=${region}", + 'NOVA_ENDPOINT_TYPE=internalURL', + ], + } + + exec {'create-hpgs-aggr': + command => 'bash -c "nova aggregate-create hpgs-aggr hpgs"', + unless => 'bash -c "nova aggregate-list | grep -q hpgs-aggr"', + } -> + exec {'aggr-set-metadata': + command => 'bash -c "nova aggregate-set-metadata hpgs-aggr hpgs=true"', + unless => 'bash -c "nova aggregate-details hpgs-aggr | grep hpgs=true"', + } + if $dpdk_hosts { + contrail::provision::aggr_add_host { $dpdk_hosts: + require => Exec['aggr-set-metadata'], + } + } + +# Create flavor for huge pages use +# + exec { 'create-m1.small.hpgs-flavor' : + command => 'bash -c "nova flavor-create --is-public true m1.small.hpgs auto 512 20 2"', + unless => 'bash -c "nova flavor-list | grep -q m1.small.hpgs"', + } -> + exec { 'create-m1.small.hpgs-mempage' : + command => 'bash -c "nova flavor-key m1.small.hpgs set hw:mem_page_size=large"', + } -> + exec { 'create-m1.small.hpgs-aggregate' : + command => 'bash -c "nova flavor-key m1.small.hpgs set aggregate_instance_extra_specs:hpgs=true"', + require => Exec['aggr-set-metadata'], + } + } +} diff --git a/deployment_scripts/puppet/modules/contrail/manifests/compute/hugepages.pp b/deployment_scripts/puppet/modules/contrail/manifests/compute/hugepages.pp new file mode 100644 index 000000000..ec4df6265 --- /dev/null +++ b/deployment_scripts/puppet/modules/contrail/manifests/compute/hugepages.pp @@ -0,0 +1,92 @@ +# Copyright 2016 Mirantis, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +class contrail::compute::hugepages { + + if $contrail::dpdk_enabled { + # NOTE: To use hugepages we have to upgrade qemu packages to version 2.4 + # The kernel configuration for hugepages + Kernel_parameter { + provider => 'grub2', + } + + if $contrail::hugepages_size == 2 { + sysctl::value { 'vm.nr_hugepages': + value => "${contrail::hugepages_number} ", + } + + kernel_parameter { 'hugepagesz': + ensure => absent, + } + + kernel_parameter { 'hugepages': + ensure => absent, + } + } + elsif $contrail::hugepages_size == 1024 { + kernel_parameter { 'hugepagesz': + ensure => present, + value => "${contrail::hugepages_size}M", + } -> + + kernel_parameter { 'hugepages': + ensure => present, + value => $contrail::hugepages_size, + } + + #This need for vrouter start when 1Gb hugepages not enabled yet + exec { 'temporary_add_hugepages': + path => ['/sbin', '/usr/bin'], + command => 'sysctl -w vm.nr_hugepages=256', + onlyif => 'test ! -d /sys/kernel/mm/hugepages/hugepages-1048576kB', + } + + + exec { 'reboot_require': + path => ['/bin', '/usr/bin'], + command => 'touch /tmp/contrail-reboot-require', + onlyif => 'test ! -d /sys/kernel/mm/hugepages/hugepages-1048576kB', + } + } + + file { '/hugepages': + ensure => 'directory', + group => 'kvm', + } -> + + mount { '/hugepages': + ensure => 'mounted', + fstype => 'hugetlbfs', + device => 'hugetlbfs', + options => 'mode=775,gid=kvm', + atboot => true, + } -> + + file_line { 'hugepages_mountpoint': + path => '/etc/libvirt/qemu.conf', + match => '#hugetlbfs_mount', + line => 'hugetlbfs_mount = "/hugepages"', + } ~> + + service { 'qemu-kvm': + ensure => running, + enable => true, + } ~> + + service { 'libvirtd': + ensure => running, + enable => true, + } + } +} diff --git a/deployment_scripts/puppet/modules/contrail/manifests/init.pp b/deployment_scripts/puppet/modules/contrail/manifests/init.pp index 3cfe2de80..ef17c2011 100644 --- a/deployment_scripts/puppet/modules/contrail/manifests/init.pp +++ b/deployment_scripts/puppet/modules/contrail/manifests/init.pp @@ -55,10 +55,14 @@ class contrail { $admin_tenant = $admin_settings['tenant'] # Contrail settings - $asnum = $settings['contrail_asnum'] - $external = $settings['contrail_external'] - $route_target = $settings['contrail_route_target'] - $gateways = split($settings['contrail_gateways'], ',') + $asnum = $settings['contrail_asnum'] + $external = $settings['contrail_external'] + $route_target = $settings['contrail_route_target'] + $gateways = split($settings['contrail_gateways'], ',') + # Hugepages configuration for DPDK vrouter + $hugepages_size = pick($settings['hugepages_size'],2) + $hugepages_amount = pick($settings['hugepages_amount'],10) + $hugepages_number = floor($::memorysize_mb * $hugepages_amount / '100' / $hugepages_size) # Custom mount point for contrail-db $cassandra_path = '/var/lib/contrail_db' @@ -79,6 +83,10 @@ class contrail { $netmask_short = netmask_to_cidr($netmask) $phys_dev = get_private_ifname($interface) + # DPDK settings + $dpdk_enabled = 'dpdk' in hiera_array('roles') + + $mos_mgmt_vip = $network_metadata['vips']['management']['ipaddr'] $mos_public_vip = $network_metadata['vips']['public']['ipaddr'] diff --git a/deployment_scripts/puppet/modules/contrail/manifests/provision/config.pp b/deployment_scripts/puppet/modules/contrail/manifests/provision/config.pp old mode 100755 new mode 100644 diff --git a/deployment_scripts/puppet/modules/contrail/manifests/provision/db.pp b/deployment_scripts/puppet/modules/contrail/manifests/provision/db.pp old mode 100755 new mode 100644 diff --git a/deployment_tasks.yaml b/deployment_tasks.yaml index be5895c6d..8818d0acf 100644 --- a/deployment_tasks.yaml +++ b/deployment_tasks.yaml @@ -9,6 +9,7 @@ parameters: strategy: type: one_by_one + - id: contrail-db type: group role: [contrail-db] @@ -29,6 +30,7 @@ parameters: strategy: type: one_by_one + - id: contrail-config type: group role: [contrail-config] @@ -49,6 +51,7 @@ parameters: strategy: type: one_by_one + - id: contrail-control type: group role: [contrail-control] @@ -83,6 +86,7 @@ parameters: strategy: type: parallel + # Tasks # Install Contrail utils, java - id: contrail-utils @@ -324,6 +328,17 @@ type: skipped # Remove Open vSwitch packages, install and configure Contrail vRouter dkms kernel module +# Configures hugepages kernel settings if dpdk is enabled +- id: contrail-compute-hugepages + type: puppet + role: [compute] + required_for: [post_deployment_end, contrail-compute-provision] + requires: [post_deployment_start] + parameters: + puppet_manifest: puppet/manifests/contrail-compute-hugepages.pp + puppet_modules: puppet/modules:/etc/puppet/modules + timeout: 720 + - id: contrail-compute-provision type: puppet role: [compute] @@ -333,6 +348,7 @@ puppet_manifest: puppet/manifests/contrail-compute-provision.pp puppet_modules: puppet/modules:/etc/puppet/modules timeout: 720 + - id: contrail-compute-network type: puppet role: [compute] @@ -342,6 +358,7 @@ puppet_manifest: puppet/manifests/contrail-compute-network.pp puppet_modules: puppet/modules:/etc/puppet/modules timeout: 720 + - id: contrail-compute-nova type: puppet role: [compute] @@ -351,6 +368,7 @@ puppet_manifest: puppet/manifests/contrail-compute-nova.pp puppet_modules: puppet/modules:/etc/puppet/modules timeout: 720 + - id: contrail-compute-firewall type: puppet role: [compute] @@ -360,12 +378,34 @@ puppet_manifest: puppet/manifests/contrail-compute-firewall.pp puppet_modules: puppet/modules:/etc/puppet/modules timeout: 720 + - id: contrail-compute-vrouter type: puppet role: [compute] - required_for: [post_deployment_end] + required_for: [post_deployment_end, contrail-compute-aggregate] requires: [post_deployment_start] parameters: puppet_manifest: puppet/manifests/contrail-compute-vrouter.pp puppet_modules: puppet/modules:/etc/puppet/modules timeout: 720 + +# Creates aggregate for DPDK +- id: contrail-compute-aggregate + type: puppet + role: [compute] + required_for: [post_deployment_end, compute-reboot] + requires: [post_deployment_start] + parameters: + puppet_manifest: puppet/manifests/contrail-compute-aggregate.pp + puppet_modules: puppet/modules:/etc/puppet/modules + timeout: 120 + +# Reboot compute nodes, if it need. +- id: compute-reboot + type: shell + role: [compute] + required_for: [post_deployment_end] + requires: [configure_default_route] + parameters: + cmd: if [ -f /tmp/contrail-reboot-require ]; then /sbin/reboot; fi + timeout: 720 diff --git a/environment_config.yaml b/environment_config.yaml index ca7a4f064..57148ddfd 100644 --- a/environment_config.yaml +++ b/environment_config.yaml @@ -40,3 +40,23 @@ attributes: regex: source: '^(?:(6553[0-5])|(655[0-2]\d)|(65[0-4]\d{2})|(6[0-4]\d{3})|([1-5]\d{4})|([1-9]\d{1,3})|([1-9]))$' error: "Invalid target" + hugepages_size: + type: 'select' + weight: 120 + value: '2' + label: 'Hugepage size' + description: 'Choose the size of hugepages that will be used for dpdk feature. Check if 1GB pages are supported on target compute node. # grep pdpe1gb /proc/cpuinfo | uniq' + values: + - data: '2' + label: '2M' + - data: '1024' + label: "1G" + hugepages_amount: + value: '10' + label: 'Hugepages amount (%)' + description: 'The amount of memory allocated on each compute-node for hugepages in percent' + weight: 130 + type: 'text' + regex: + source: '^[1-9][0-9]?$|^100$' + error: "Invalid amount of percent"