modules/mu/config.rb in cloud-mu-3.0.2 vs modules/mu/config.rb in cloud-mu-3.1.0

- old
+ new

@@ -358,11 +358,11 @@ end # Base configuration schema for declared kittens referencing other cloud objects. This is essentially a set of filters that we're going to pass to {MU::MommaCat.findStray}. # @param aliases [Array<Hash>]: Key => value mappings to set backwards-compatibility aliases for attributes, such as the ubiquitous +vpc_id+ (+vpc_id+ => +id+). # @return [Hash] - def self.schema(aliases = [], type: nil, parent_obj: nil, desc: nil) + def self.schema(aliases = [], type: nil, parent_obj: nil, desc: nil, omit_fields: []) parent_obj ||= caller[1].gsub(/.*?\/([^\.\/]+)\.rb:.*/, '\1') desc ||= "Reference a #{type ? "'#{type}' resource" : "resource" } from this #{parent_obj ? "'#{parent_obj}'" : "" } resource" schema = { "type" => "object", "#MU_REFERENCE" => true, @@ -407,10 +407,16 @@ } if !["folders", "habitats"].include?(type) schema["properties"]["habitat"] = MU::Config::Habitat.reference end + if omit_fields + omit_fields.each { |f| + schema["properties"].delete(f) + } + end + if !type.nil? schema["required"] = ["type"] schema["properties"]["type"]["default"] = type schema["properties"]["type"]["enum"] = [type] end @@ -720,11 +726,11 @@ tail end # Load up our YAML or JSON and parse it through ERB, optionally substituting # externally-supplied parameters. - def resolveConfig(path: @@config_path, param_pass: false) + def resolveConfig(path: @@config_path, param_pass: false, cloud: nil) config = nil @param_pass = param_pass # Catch calls to missing variables in Basket of Kittens files when being # parsed by ERB, and replace with placeholders for parameters. This @@ -809,10 +815,13 @@ raw_json = raw_text end begin config = JSON.parse(raw_json) + if @@parameters['cloud'] + config['cloud'] ||= @@parameters['cloud'].to_s + end if param_pass and config.is_a?(Hash) config.keys.each { |key| if key != "parameters" if key == "appname" and @@parameters["myAppName"].nil? $myAppName = config["appname"].upcase.dup @@ -848,12 +857,13 @@ # Load, resolve, and validate a configuration file ("Basket of Kittens"). # @param path [String]: The path to the master config file to load. Note that this can include other configuration files via ERB. # @param skipinitialupdates [Boolean]: Whether to forcibly apply the *skipinitialupdates* flag to nodes created by this configuration. # @param params [Hash]: Optional name-value parameter pairs, which will be passed to our configuration files as ERB variables. + # @param cloud [String]: Sets a parameter named 'cloud', and insert it as the default cloud platform if not already declared # @return [Hash]: The complete validated configuration for a deployment. - def initialize(path, skipinitialupdates = false, params: {}, updating: nil, default_credentials: nil) + def initialize(path, skipinitialupdates = false, params: {}, updating: nil, default_credentials: nil, cloud: nil) $myPublicIp = MU::Cloud::AWS.getAWSMetaData("public-ipv4") $myRoot = MU.myRoot $myRoot.freeze $myAZ = MU.myAZ.freeze @@ -888,20 +898,31 @@ rescue RuntimeError, SyntaxError => e ok = false MU.log "Error setting $#{name}='#{value}': #{e.message}", MU::ERR end } + + if cloud and !@@parameters["cloud"] + if !MU::Cloud.availableClouds.include?(cloud) + ok = false + MU.log "Provider '#{cloud}' is not listed as an available cloud", MU::ERR, details: MU::Cloud.availableClouds + else + @@parameters["cloud"] = getTail("cloud", value: cloud, pseudo: true) + @@user_supplied_parameters["cloud"] = cloud + eval("$cloud='#{cloud}'") # support old-style $global parameter refs + end + end raise ValidationError if !ok # Run our input through the ERB renderer, a first pass just to extract # the parameters section so that we can resolve all of those to variables # for the rest of the config to reference. # XXX Figure out how to make include() add parameters for us. Right now # you can't specify parameters in an included file, because ERB is what's # doing the including, and parameters need to already be resolved so that # ERB can use them. - param_cfg, raw_erb_params_only = resolveConfig(path: @@config_path, param_pass: true) + param_cfg, raw_erb_params_only = resolveConfig(path: @@config_path, param_pass: true, cloud: cloud) if param_cfg.has_key?("parameters") param_cfg["parameters"].each { |param| if param.has_key?("default") and param["default"].nil? param["default"] = "" end @@ -953,11 +974,11 @@ } raise DeployParamError, "One or more invalid parameters specified" if !ok $parameters = @@parameters.dup $parameters.freeze - tmp_cfg, raw_erb = resolveConfig(path: @@config_path) + tmp_cfg, raw_erb = resolveConfig(path: @@config_path, cloud: cloud) # Convert parameter entries that constitute whole config keys into # {MU::Config::Tail} objects. def resolveTails(tree, indent= "") if tree.is_a?(Hash) @@ -1004,10 +1025,11 @@ types = MU::Cloud.resource_types.values.map { |v| v[:cfg_plural] } MU::Cloud.resource_types.values.map { |v| v[:cfg_plural] }.each { |type| if @config[type] @config[type].each { |k| + next if !k.is_a?(Hash) applyInheritedDefaults(k, type) } end } applySchemaDefaults(@config, MU::Config.schema) @@ -1472,11 +1494,12 @@ ["optional_tags", "tags", "cloud", "project"].each { |param| acl[param] = descriptor[param] if descriptor[param] } descriptor["add_firewall_rules"] ||= [] - descriptor["add_firewall_rules"] << {"rule_name" => fwname, "type" => "firewall_rules" } # XXX why the duck is there a type argument required here? + descriptor["add_firewall_rules"] << {"name" => fwname, "type" => "firewall_rules" } # XXX why the duck is there a type argument required here? + descriptor["add_firewall_rules"].uniq! acl = resolveIntraStackFirewallRefs(acl, delay_validation) ok = false if !insertKitten(acl, "firewall_rules", delay_validation, overwrite: already_exists) end @@ -1505,17 +1528,19 @@ end # Does it declare association with first-class firewall_rules? if !descriptor["add_firewall_rules"].nil? descriptor["add_firewall_rules"].each { |acl_include| - if haveLitterMate?(acl_include["rule_name"], "firewall_rules") + next if !acl_include["name"] and !acl_include["rule_name"] + acl_include["name"] ||= acl_include["rule_name"] + if haveLitterMate?(acl_include["name"], "firewall_rules") descriptor["dependencies"] << { "type" => "firewall_rule", - "name" => acl_include["rule_name"] + "name" => acl_include["name"] } - elsif acl_include["rule_name"] - MU.log shortclass.to_s+" #{descriptor['name']} depends on FirewallRule #{acl_include["rule_name"]}, but no such rule declared.", MU::ERR + elsif acl_include["name"] + MU.log shortclass.to_s+" #{descriptor['name']} depends on FirewallRule #{acl_include["name"]}, but no such rule declared.", MU::ERR ok = false end } end @@ -1832,31 +1857,31 @@ YAML.load(raw.gsub(/<%.*?%>/, "")) rescue Psych::SyntaxError => e # Ok, well neither of those worked, let's assume that filenames are # meaningful. if path.match(/\.(yaml|yml)$/i) - MU.log "Guessing that #{path} is YAML based on filename", MU::NOTICE + MU.log "Guessing that #{path} is YAML based on filename", MU::DEBUG return :yaml elsif path.match(/\.(json|jsn|js)$/i) - MU.log "Guessing that #{path} is JSON based on filename", MU::NOTICE + MU.log "Guessing that #{path} is JSON based on filename", MU::DEBUG return :json else # For real? Ok, let's try the dumbest possible method. dashes = raw.match(/\-/) braces = raw.match(/[{}]/) if dashes.size > braces.size - MU.log "Guessing that #{path} is YAML by... counting dashes.", MU::WARN + MU.log "Guessing that #{path} is YAML by... counting dashes.", MU::NOTICE return :yaml elsif braces.size > dashes.size - MU.log "Guessing that #{path} is JSON by... counting braces.", MU::WARN + MU.log "Guessing that #{path} is JSON by... counting braces.", MU::NOTICE return :json else raise "Unable to guess composition of #{path} by any means" end end end - MU.log "Guessing that #{path} is YAML based on parser", MU::NOTICE + MU.log "Guessing that #{path} is YAML based on parser", MU::DEBUG return :yaml end MU.log "Guessing that #{path} is JSON based on parser", MU::NOTICE return :json end @@ -2157,9 +2182,10 @@ # Given a bare hash describing a resource, insert default values which can # be inherited from its parent or from the root of the BoK. # @param kitten [Hash]: A resource descriptor # @param type [String]: The type of resource this is ("servers" etc) def applyInheritedDefaults(kitten, type) + return if !kitten.is_a?(Hash) kitten['cloud'] ||= @config['cloud'] kitten['cloud'] ||= MU::Config.defaultCloud if !MU::Cloud.supportedClouds.include?(kitten['cloud']) return