covalence 0.0.1 → 0.7.9.rc1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/CHANGELOG.md +164 -0
- data/README.md +489 -19
- data/TODO.md +14 -0
- data/lib/covalence.rb +41 -0
- data/lib/covalence/core/bootstrap.rb +8 -0
- data/lib/covalence/core/cli_wrappers/packer.yml +9 -0
- data/lib/covalence/core/cli_wrappers/packer_cli.rb +27 -0
- data/lib/covalence/core/cli_wrappers/popen_wrapper.rb +123 -0
- data/lib/covalence/core/cli_wrappers/terraform.yml +39 -0
- data/lib/covalence/core/cli_wrappers/terraform_cli.rb +119 -0
- data/lib/covalence/core/data_stores/hiera.rb +50 -0
- data/lib/covalence/core/entities/context.rb +38 -0
- data/lib/covalence/core/entities/environment.rb +24 -0
- data/lib/covalence/core/entities/input.rb +112 -0
- data/lib/covalence/core/entities/stack.rb +74 -0
- data/lib/covalence/core/entities/state_store.rb +65 -0
- data/lib/covalence/core/repositories/context_repository.rb +30 -0
- data/lib/covalence/core/repositories/environment_repository.rb +92 -0
- data/lib/covalence/core/repositories/input_repository.rb +56 -0
- data/lib/covalence/core/repositories/stack_repository.rb +89 -0
- data/lib/covalence/core/repositories/state_store_repository.rb +31 -0
- data/lib/covalence/core/services/hiera_syntax_service.rb +19 -0
- data/lib/covalence/core/services/packer_stack_tasks.rb +104 -0
- data/lib/covalence/core/services/terraform_stack_tasks.rb +212 -0
- data/lib/covalence/core/state_stores/atlas.rb +157 -0
- data/lib/covalence/core/state_stores/consul.rb +153 -0
- data/lib/covalence/core/state_stores/s3.rb +147 -0
- data/lib/covalence/environment_tasks.rb +328 -0
- data/lib/covalence/helpers/shell_interpolation.rb +28 -0
- data/lib/covalence/helpers/spec_dependencies.rb +21 -0
- data/lib/covalence/rake/rspec/envs_spec.rb +75 -0
- data/lib/covalence/rake/rspec/yaml_spec.rb +14 -0
- data/lib/covalence/spec_tasks.rb +59 -0
- data/lib/covalence/version.rb +3 -0
- metadata +344 -26
- data/.gitignore +0 -9
- data/Gemfile +0 -4
- data/LICENSE.txt +0 -21
- data/Rakefile +0 -2
- data/bin/console +0 -14
- data/bin/setup +0 -8
- data/lib/prometheus_unifio.rb +0 -5
- data/lib/prometheus_unifio/version.rb +0 -3
- data/prometheus_unifio.gemspec +0 -32
| @@ -0,0 +1,24 @@ | |
| 1 | 
            +
            require 'virtus'
         | 
| 2 | 
            +
            require 'active_model'
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            require_relative 'stack'
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            module Covalence
         | 
| 7 | 
            +
              class Environment
         | 
| 8 | 
            +
                include Virtus.model
         | 
| 9 | 
            +
                include ActiveModel::Validations
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                attribute :name, String
         | 
| 12 | 
            +
                attribute :stacks, Array[Stack]
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                validates! :name, format: {
         | 
| 15 | 
            +
                  without: /\s+/,
         | 
| 16 | 
            +
                  message: "Environment %{attribute}: \"%{value}\" cannot contain spaces"
         | 
| 17 | 
            +
                }
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                def initialize(attributes = {}, *args)
         | 
| 20 | 
            +
                  super
         | 
| 21 | 
            +
                  self.valid?
         | 
| 22 | 
            +
                end
         | 
| 23 | 
            +
              end
         | 
| 24 | 
            +
            end
         | 
| @@ -0,0 +1,112 @@ | |
| 1 | 
            +
            require 'virtus'
         | 
| 2 | 
            +
            require 'active_support/core_ext/string/inflections'
         | 
| 3 | 
            +
            require 'active_support/core_ext/hash'
         | 
| 4 | 
            +
            require 'active_model'
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            require_relative '../../helpers/shell_interpolation'
         | 
| 7 | 
            +
             | 
| 8 | 
            +
            module Covalence
         | 
| 9 | 
            +
              class Input
         | 
| 10 | 
            +
                include Virtus.model
         | 
| 11 | 
            +
                include ActiveModel::Validations
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                attribute :name, String
         | 
| 14 | 
            +
                # unprocessed value, could be remote
         | 
| 15 | 
            +
                attribute :raw_value, Object
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                def initialize(attributes = {}, *args)
         | 
| 18 | 
            +
                  super
         | 
| 19 | 
            +
                  self.valid?
         | 
| 20 | 
            +
                end
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                def value
         | 
| 23 | 
            +
                  return raw_value if !raw_value.is_a?(Hash)
         | 
| 24 | 
            +
                  get_value(raw_value)
         | 
| 25 | 
            +
                end
         | 
| 26 | 
            +
             | 
| 27 | 
            +
                def to_command_option
         | 
| 28 | 
            +
                  "#{name} = #{parse_input(value())}"
         | 
| 29 | 
            +
                end
         | 
| 30 | 
            +
             | 
| 31 | 
            +
                private
         | 
| 32 | 
            +
             | 
| 33 | 
            +
                def get_value(input)
         | 
| 34 | 
            +
                  backend, type = parse_type(input)
         | 
| 35 | 
            +
             | 
| 36 | 
            +
                  if backend != "local"
         | 
| 37 | 
            +
                    remote_value = backend::lookup(type, input)
         | 
| 38 | 
            +
                    if remote_value.is_a?(Hash)
         | 
| 39 | 
            +
                      get_value(remote_value)
         | 
| 40 | 
            +
                    else
         | 
| 41 | 
            +
                      remote_value
         | 
| 42 | 
            +
                    end
         | 
| 43 | 
            +
                  elsif input.stringify_keys.has_key?('value')
         | 
| 44 | 
            +
                    input.stringify_keys.fetch('value')
         | 
| 45 | 
            +
                  else
         | 
| 46 | 
            +
                    input
         | 
| 47 | 
            +
                  end
         | 
| 48 | 
            +
                end
         | 
| 49 | 
            +
             | 
| 50 | 
            +
                def parse_array(input)
         | 
| 51 | 
            +
                  config = "[\n"
         | 
| 52 | 
            +
                  input.each do |v|
         | 
| 53 | 
            +
                    config += "  #{parse_input(v)},\n"
         | 
| 54 | 
            +
                  end
         | 
| 55 | 
            +
                  config += "]"
         | 
| 56 | 
            +
                end
         | 
| 57 | 
            +
             | 
| 58 | 
            +
                def parse_hash(input)
         | 
| 59 | 
            +
                  config = "{\n"
         | 
| 60 | 
            +
                  input.each do |k,v|
         | 
| 61 | 
            +
                    config += "  \"#{k}\" = #{parse_input(v)}\n"
         | 
| 62 | 
            +
                  end
         | 
| 63 | 
            +
                  config += "}"
         | 
| 64 | 
            +
                end
         | 
| 65 | 
            +
             | 
| 66 | 
            +
                def parse_input(input)
         | 
| 67 | 
            +
                  if input.nil?
         | 
| 68 | 
            +
                    "\"\""
         | 
| 69 | 
            +
             | 
| 70 | 
            +
                  elsif input.is_a?(Hash)
         | 
| 71 | 
            +
                    parse_hash(input)
         | 
| 72 | 
            +
             | 
| 73 | 
            +
                  elsif input.is_a?(Array)
         | 
| 74 | 
            +
                    parse_array(input)
         | 
| 75 | 
            +
             | 
| 76 | 
            +
                  elsif input.to_s.include?("$(")
         | 
| 77 | 
            +
                    "\"#{Covalence::Helpers::ShellInterpolation.parse_shell(input)}\""
         | 
| 78 | 
            +
             | 
| 79 | 
            +
                  else
         | 
| 80 | 
            +
                    "\"#{input}\""
         | 
| 81 | 
            +
                  end
         | 
| 82 | 
            +
                end
         | 
| 83 | 
            +
             | 
| 84 | 
            +
                # :reek:FeatureEnvy
         | 
| 85 | 
            +
                def parse_type(input)
         | 
| 86 | 
            +
                  if input.stringify_keys.has_key?('type')
         | 
| 87 | 
            +
                    type = input.stringify_keys.fetch('type')
         | 
| 88 | 
            +
             | 
| 89 | 
            +
                    local_types = %w(
         | 
| 90 | 
            +
                      list
         | 
| 91 | 
            +
                      map
         | 
| 92 | 
            +
                      string
         | 
| 93 | 
            +
                    )
         | 
| 94 | 
            +
             | 
| 95 | 
            +
                    if local_types.any? {|local_type| type == local_type }
         | 
| 96 | 
            +
                      return [ "local", type ]
         | 
| 97 | 
            +
                    elsif type.include?('.')
         | 
| 98 | 
            +
                      pieces = type.split('.', 2)
         | 
| 99 | 
            +
                      return [ "Covalence::#{pieces.first.camelize}".constantize,
         | 
| 100 | 
            +
                               pieces[1] ]
         | 
| 101 | 
            +
                    else
         | 
| 102 | 
            +
                      errors.add(:base,
         | 
| 103 | 
            +
                                 "invalid input type specified: #{type}",
         | 
| 104 | 
            +
                                 strict: true)
         | 
| 105 | 
            +
                    end
         | 
| 106 | 
            +
                  else
         | 
| 107 | 
            +
                    return [ "local", "map" ]
         | 
| 108 | 
            +
                  end
         | 
| 109 | 
            +
                end
         | 
| 110 | 
            +
             | 
| 111 | 
            +
              end
         | 
| 112 | 
            +
            end
         | 
| @@ -0,0 +1,74 @@ | |
| 1 | 
            +
            require 'virtus'
         | 
| 2 | 
            +
            require 'active_model'
         | 
| 3 | 
            +
            require 'semantic'
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            require_relative '../../../covalence'
         | 
| 6 | 
            +
            require_relative 'state_store'
         | 
| 7 | 
            +
            require_relative 'input'
         | 
| 8 | 
            +
            require_relative 'context'
         | 
| 9 | 
            +
             | 
| 10 | 
            +
            module Covalence
         | 
| 11 | 
            +
              class Stack
         | 
| 12 | 
            +
                include Virtus.model
         | 
| 13 | 
            +
                include ActiveModel::Validations
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                attribute :type, String
         | 
| 16 | 
            +
                attribute :name, String
         | 
| 17 | 
            +
                attribute :environment_name, String
         | 
| 18 | 
            +
                attribute :module_path, String
         | 
| 19 | 
            +
                attribute :dependencies, Array[String]
         | 
| 20 | 
            +
                attribute :packer_template, String
         | 
| 21 | 
            +
                attribute :state_stores, Array[StateStore]
         | 
| 22 | 
            +
                attribute :contexts, Array[Context]
         | 
| 23 | 
            +
                attribute :inputs, Hash[String => Input]
         | 
| 24 | 
            +
                attribute :args, String
         | 
| 25 | 
            +
                attribute :workspace, String
         | 
| 26 | 
            +
             | 
| 27 | 
            +
                validates! :type, inclusion: {
         | 
| 28 | 
            +
                  in: %w(terraform packer)
         | 
| 29 | 
            +
                }
         | 
| 30 | 
            +
                validates! :name, format: {
         | 
| 31 | 
            +
                  without: /\s+/,
         | 
| 32 | 
            +
                  message: "Stack %{attribute}: \"%{value}\" cannot contain spaces"
         | 
| 33 | 
            +
                }
         | 
| 34 | 
            +
             | 
| 35 | 
            +
                def initialize(attributes = {}, *arguments)
         | 
| 36 | 
            +
                  super
         | 
| 37 | 
            +
                  self.valid?
         | 
| 38 | 
            +
                end
         | 
| 39 | 
            +
             | 
| 40 | 
            +
                def full_name
         | 
| 41 | 
            +
                  "#{environment_name}-#{name}"
         | 
| 42 | 
            +
                end
         | 
| 43 | 
            +
             | 
| 44 | 
            +
                def materialize_cmd_inputs
         | 
| 45 | 
            +
                  if type == "terraform"
         | 
| 46 | 
            +
                    config = ""
         | 
| 47 | 
            +
                    inputs.values.map(&:to_command_option).each do |input|
         | 
| 48 | 
            +
                      config += input + "\n"
         | 
| 49 | 
            +
                    end
         | 
| 50 | 
            +
                    logger.info "\nStack inputs:\n\n#{config}"
         | 
| 51 | 
            +
                    File.open('covalence-inputs.tfvars','w') {|f| f.write(config)}
         | 
| 52 | 
            +
                  elsif type == "packer"
         | 
| 53 | 
            +
                    config = Hash.new
         | 
| 54 | 
            +
                    inputs.each do |name, input|
         | 
| 55 | 
            +
                      config[name] = input.value
         | 
| 56 | 
            +
                    end
         | 
| 57 | 
            +
                    config_json = JSON.generate(config)
         | 
| 58 | 
            +
                    logger.info "\nStack inputs:\n\n#{config_json}"
         | 
| 59 | 
            +
                    File.open('covalence-inputs.json','w') {|f| f.write(config_json)}
         | 
| 60 | 
            +
                  end
         | 
| 61 | 
            +
                end
         | 
| 62 | 
            +
             | 
| 63 | 
            +
                def materialize_state_inputs(store: state_stores.first)
         | 
| 64 | 
            +
                  config = store.get_config
         | 
| 65 | 
            +
                  logger.info "\nState store configuration:\n\n#{config}"
         | 
| 66 | 
            +
                  File.open('covalence-state.tf','w') {|f| f.write(config)}
         | 
| 67 | 
            +
                end
         | 
| 68 | 
            +
             | 
| 69 | 
            +
                def logger
         | 
| 70 | 
            +
                  Covalence::LOGGER
         | 
| 71 | 
            +
                end
         | 
| 72 | 
            +
             | 
| 73 | 
            +
              end
         | 
| 74 | 
            +
            end
         | 
| @@ -0,0 +1,65 @@ | |
| 1 | 
            +
            require 'virtus'
         | 
| 2 | 
            +
            require 'active_support/core_ext/string/inflections'
         | 
| 3 | 
            +
            require 'active_support/core_ext/hash'
         | 
| 4 | 
            +
            require 'active_model'
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            # check to see how this works with plugins
         | 
| 7 | 
            +
            Dir[File.expand_path('../state_stores/*.rb', File.dirname(__FILE__))].each do |file|
         | 
| 8 | 
            +
              require file
         | 
| 9 | 
            +
            end
         | 
| 10 | 
            +
             | 
| 11 | 
            +
            module Covalence
         | 
| 12 | 
            +
              class StateStore
         | 
| 13 | 
            +
                include Virtus.model
         | 
| 14 | 
            +
                include ActiveModel::Validations
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                attribute :params, Hash, :writer => :private
         | 
| 17 | 
            +
                attribute :backend, Object, :writer => :private
         | 
| 18 | 
            +
                attribute :workspace_enabled, Boolean
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                validate :validate_params_has_name,
         | 
| 21 | 
            +
                  :backend_has_state_store
         | 
| 22 | 
            +
             | 
| 23 | 
            +
                def initialize(attributes = {}, *args)
         | 
| 24 | 
            +
                  super
         | 
| 25 | 
            +
                  self.valid?
         | 
| 26 | 
            +
                end
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                def name
         | 
| 29 | 
            +
                  params.fetch('name')
         | 
| 30 | 
            +
                end
         | 
| 31 | 
            +
             | 
| 32 | 
            +
                # :reek:FeatureEnvy
         | 
| 33 | 
            +
                def params=(params)
         | 
| 34 | 
            +
                  super(params.stringify_keys)
         | 
| 35 | 
            +
                end
         | 
| 36 | 
            +
             | 
| 37 | 
            +
                #TODO: prep different backend for plugins
         | 
| 38 | 
            +
                # :reek:FeatureEnvy
         | 
| 39 | 
            +
                def backend=(backend_name)
         | 
| 40 | 
            +
                  super("Covalence::#{backend_name.camelize}".constantize)
         | 
| 41 | 
            +
                end
         | 
| 42 | 
            +
             | 
| 43 | 
            +
                def get_config
         | 
| 44 | 
            +
                  backend::get_state_store(@params, @workspace_enabled)
         | 
| 45 | 
            +
                end
         | 
| 46 | 
            +
             | 
| 47 | 
            +
                private
         | 
| 48 | 
            +
                def validate_params_has_name
         | 
| 49 | 
            +
                  if !params.has_key?('name')
         | 
| 50 | 
            +
                    errors.add(:base,
         | 
| 51 | 
            +
                               "Params #{params} missing 'name' parameter for the #{backend} state store",
         | 
| 52 | 
            +
                               strict: true)
         | 
| 53 | 
            +
                  end
         | 
| 54 | 
            +
                end
         | 
| 55 | 
            +
             | 
| 56 | 
            +
                def backend_has_state_store
         | 
| 57 | 
            +
                  backend_has_no_state_store = !backend.has_state_store? rescue true
         | 
| 58 | 
            +
                  if backend_has_no_state_store
         | 
| 59 | 
            +
                    errors.add(:base,
         | 
| 60 | 
            +
                               "#{backend} backend module does not support state storage",
         | 
| 61 | 
            +
                               strict: true)
         | 
| 62 | 
            +
                  end
         | 
| 63 | 
            +
                end
         | 
| 64 | 
            +
              end
         | 
| 65 | 
            +
            end
         | 
| @@ -0,0 +1,30 @@ | |
| 1 | 
            +
            require 'active_support/core_ext/object/blank'
         | 
| 2 | 
            +
            require_relative '../entities/context'
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            module Covalence
         | 
| 5 | 
            +
              class ContextRepository
         | 
| 6 | 
            +
                class << self
         | 
| 7 | 
            +
                  def query_by_namespace(data_store, namespace, tool)
         | 
| 8 | 
            +
                    if tool == 'terraform'
         | 
| 9 | 
            +
                      query_tool_by_namespace(data_store, namespace)
         | 
| 10 | 
            +
                    else
         | 
| 11 | 
            +
                      Array.new(1, Context.new())
         | 
| 12 | 
            +
                    end
         | 
| 13 | 
            +
                  end
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                  private
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                  def query_tool_by_namespace(data_store, namespace)
         | 
| 18 | 
            +
                    targets = data_store.hash_lookup("#{namespace}::targets", {})
         | 
| 19 | 
            +
                    contexts = targets.map do |name, values|
         | 
| 20 | 
            +
                      next if name.blank?
         | 
| 21 | 
            +
                      Context.new(name: name, values: values)
         | 
| 22 | 
            +
                    end
         | 
| 23 | 
            +
                    contexts.compact!
         | 
| 24 | 
            +
                    # always append blank context at the end.
         | 
| 25 | 
            +
                    contexts << Context.new()
         | 
| 26 | 
            +
                    contexts
         | 
| 27 | 
            +
                  end
         | 
| 28 | 
            +
                end
         | 
| 29 | 
            +
              end
         | 
| 30 | 
            +
            end
         | 
| @@ -0,0 +1,92 @@ | |
| 1 | 
            +
            require_relative '../../../covalence'
         | 
| 2 | 
            +
            require_relative '../data_stores/hiera'
         | 
| 3 | 
            +
            require_relative '../entities/environment'
         | 
| 4 | 
            +
            require_relative 'stack_repository'
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            module Covalence
         | 
| 7 | 
            +
              class EnvironmentRepository
         | 
| 8 | 
            +
                class << self
         | 
| 9 | 
            +
                  def find_all(data_store = HieraDB::Client.new(Covalence::CONFIG))
         | 
| 10 | 
            +
                    environments_hash = lookup_environments(data_store)
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                    environments_hash.map do |environment_name, stack_names|
         | 
| 13 | 
            +
                      stacks = stack_names.map do |stack_name|
         | 
| 14 | 
            +
                        StackRepository.find(data_store, environment_name, stack_name)
         | 
| 15 | 
            +
                      end.compact
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                      check_all_stacks_valid!(environment_name,
         | 
| 18 | 
            +
                                              stack_names,
         | 
| 19 | 
            +
                                              stacks)
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                      Environment.new(name: environment_name,
         | 
| 22 | 
            +
                                      stacks: stacks)
         | 
| 23 | 
            +
                    end
         | 
| 24 | 
            +
                  end
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                  def find_filtered(task, data_store = HieraDB::Client.new(Covalence::CONFIG))
         | 
| 27 | 
            +
                    environments_hash = lookup_environments(data_store)
         | 
| 28 | 
            +
                    env_request = task['environment']
         | 
| 29 | 
            +
                    stk_request = task['stack']
         | 
| 30 | 
            +
             | 
| 31 | 
            +
                    if (env_request.nil? || !environments_hash.has_key?(env_request))
         | 
| 32 | 
            +
                      if RESERVED_NS.include?(env_request)
         | 
| 33 | 
            +
                        return Array.new(1, Environment.new(name: env_request,
         | 
| 34 | 
            +
                                                 stacks: stk_request))
         | 
| 35 | 
            +
                      else
         | 
| 36 | 
            +
                        raise "'#{env_request}' not found in environments"
         | 
| 37 | 
            +
                      end
         | 
| 38 | 
            +
                    end
         | 
| 39 | 
            +
             | 
| 40 | 
            +
                    stacks = nil
         | 
| 41 | 
            +
                    if (!stk_request.nil? && environments_hash[env_request].include?(stk_request))
         | 
| 42 | 
            +
                      stack_list = Array.new(1, stk_request)
         | 
| 43 | 
            +
                      stacks = Array.new(1, StackRepository.find(data_store, env_request, stk_request))
         | 
| 44 | 
            +
                    else
         | 
| 45 | 
            +
                      stack_list = environments_hash[env_request]
         | 
| 46 | 
            +
                      stacks = stack_list.map do |stack_name|
         | 
| 47 | 
            +
                        StackRepository.find(data_store, env_request, stack_name)
         | 
| 48 | 
            +
                      end.compact
         | 
| 49 | 
            +
                    end
         | 
| 50 | 
            +
             | 
| 51 | 
            +
                    check_all_stacks_valid!(env_request,
         | 
| 52 | 
            +
                                            stack_list,
         | 
| 53 | 
            +
                                            stacks)
         | 
| 54 | 
            +
             | 
| 55 | 
            +
                    Array.new(1, Environment.new(name: env_request,
         | 
| 56 | 
            +
                                                 stacks: stacks))
         | 
| 57 | 
            +
                  end
         | 
| 58 | 
            +
             | 
| 59 | 
            +
                  def populate_stack(stack, data_store = HieraDB::Client.new(Covalence::CONFIG))
         | 
| 60 | 
            +
                    StackRepository.populate(data_store, stack)
         | 
| 61 | 
            +
                  end
         | 
| 62 | 
            +
             | 
| 63 | 
            +
                  private
         | 
| 64 | 
            +
             | 
| 65 | 
            +
                  def lookup_environments(data_store)
         | 
| 66 | 
            +
                    environments_hash = data_store.hash_lookup('environments')
         | 
| 67 | 
            +
                    raise "Missing 'environments' configuration hash" if environments_hash.empty?
         | 
| 68 | 
            +
                    environments_hash
         | 
| 69 | 
            +
                  end
         | 
| 70 | 
            +
             | 
| 71 | 
            +
                  # Stacks are valid if they map to at least one tool (packer or terraform)
         | 
| 72 | 
            +
                  def check_all_stacks_valid!(environment_name, stack_list, stacks)
         | 
| 73 | 
            +
                    stack_names = stacks.map(&:name)
         | 
| 74 | 
            +
                    logger.debug("All stacks: #{stack_list}")
         | 
| 75 | 
            +
                    logger.debug("Targeted stacks: #{stack_names}")
         | 
| 76 | 
            +
             | 
| 77 | 
            +
                    invalid_stacks = stack_list - stack_names
         | 
| 78 | 
            +
             | 
| 79 | 
            +
                    if invalid_stacks.size > 0
         | 
| 80 | 
            +
                      error_string = <<-eos
         | 
| 81 | 
            +
                      Invalid stack(s) #{invalid_stacks} for environment #{environment_name}.
         | 
| 82 | 
            +
                      eos
         | 
| 83 | 
            +
                      raise error_string.strip
         | 
| 84 | 
            +
                    end
         | 
| 85 | 
            +
                  end
         | 
| 86 | 
            +
             | 
| 87 | 
            +
                  def logger
         | 
| 88 | 
            +
                    Covalence::LOGGER
         | 
| 89 | 
            +
                  end
         | 
| 90 | 
            +
                end
         | 
| 91 | 
            +
              end
         | 
| 92 | 
            +
            end
         | 
| @@ -0,0 +1,56 @@ | |
| 1 | 
            +
            require 'json'
         | 
| 2 | 
            +
            require 'yaml'
         | 
| 3 | 
            +
            require_relative '../../../covalence'
         | 
| 4 | 
            +
            require_relative '../entities/input'
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            module Covalence
         | 
| 7 | 
            +
              class InputRepository
         | 
| 8 | 
            +
                class << self
         | 
| 9 | 
            +
                  def query_by_namespace(data_store, namespace, tool)
         | 
| 10 | 
            +
                    results = Hash.new
         | 
| 11 | 
            +
                    if tool == 'terraform'
         | 
| 12 | 
            +
                      results = parse_var_file('terraform', data_store, namespace)
         | 
| 13 | 
            +
                    else
         | 
| 14 | 
            +
                      results = parse_var_file('packer', data_store, namespace)
         | 
| 15 | 
            +
                    end
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                    results.merge(query_tool_by_namespace(data_store, namespace))
         | 
| 18 | 
            +
                  end
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                  private
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                  #TODO: refactor nested conditional
         | 
| 23 | 
            +
                  def parse_var_file(tool, data_store, namespace)
         | 
| 24 | 
            +
                    yaml_ext = %w(yaml yml)
         | 
| 25 | 
            +
                    json_ext = %w(json)
         | 
| 26 | 
            +
             | 
| 27 | 
            +
                    varfile = data_store.lookup("#{namespace}::vars-file", nil)
         | 
| 28 | 
            +
                    return {} unless varfile
         | 
| 29 | 
            +
                    tool_module_path ="Covalence::#{tool.upcase}".constantize
         | 
| 30 | 
            +
                    varfile = File.expand_path(File.join(tool_module_path, varfile.to_s))
         | 
| 31 | 
            +
                    if (File.file?(varfile) &&
         | 
| 32 | 
            +
                        (yaml_ext + json_ext).include?(File.extname(varfile)[1..-1]))
         | 
| 33 | 
            +
                      if json_ext.include?(File.extname(varfile)[1..-1])
         | 
| 34 | 
            +
                        tmp_hash = JSON.parse(File.read(varfile))
         | 
| 35 | 
            +
                      else
         | 
| 36 | 
            +
                        tmp_hash = YAML.load_file(varfile)
         | 
| 37 | 
            +
                      end
         | 
| 38 | 
            +
             | 
| 39 | 
            +
                      tmp_hash = tmp_hash.map do |name, raw_value|
         | 
| 40 | 
            +
                        [ name, Input.new(name: name, raw_value: raw_value) ]
         | 
| 41 | 
            +
                      end
         | 
| 42 | 
            +
                      Hash[*tmp_hash.flatten]
         | 
| 43 | 
            +
                    else
         | 
| 44 | 
            +
                      raise ArgumentError, "cannot parse non-yaml or non-json file: #{varfile}"
         | 
| 45 | 
            +
                    end
         | 
| 46 | 
            +
                  end
         | 
| 47 | 
            +
             | 
| 48 | 
            +
                  def query_tool_by_namespace(data_store, namespace)
         | 
| 49 | 
            +
                    tmp_hash = data_store.hash_lookup("#{namespace}::vars", {}).map do |name, raw_value|
         | 
| 50 | 
            +
                      [ name, Input.new(name: name, raw_value: raw_value) ]
         | 
| 51 | 
            +
                    end
         | 
| 52 | 
            +
                    Hash[*tmp_hash.flatten]
         | 
| 53 | 
            +
                  end
         | 
| 54 | 
            +
                end
         | 
| 55 | 
            +
              end
         | 
| 56 | 
            +
            end
         |