require 'trollop' require 'tempfile' module SimpleDeploy module CLI class Clone include Shared def clone @opts = Trollop::options do version SimpleDeploy::VERSION banner <<-EOS Clone a stack. simple_deploy clone -s SOURCE_STACK_NAME -n NEW_STACK_NAME -e ENVIRONMENT -a ATTRIB1=VALUE -a ATTRIB2=VALUE EOS opt :help, "Display Help" opt :environment, "Set the target environment", :type => :string opt :input_stack, "Read outputs from given stack(s) and map them \ to parameter inputs in the new stack. These will be passed to inputs with \ matching or pluralized names. Can be specified multiple times.", :type => :string, :multi => true opt :log_level, "Log level: debug, info, warn, error", :type => :string, :default => 'info' opt :source_name, "Stack name for the stack to clone", :type => :string opt :new_name, "Stack name for the new stack", :type => :string opt :attributes, "= separated attribute and it's value", :type => :string, :multi => true opt :template, "Path to a new template file", :type => :string opt :read_from_env, "Read credentials and region from environment variables" end valid_options? :provided => @opts, :required => [:environment, :source_name, :new_name, :read_from_env] config_arg = @opts[:read_from_env] ? :read_from_env : @opts[:environment] SimpleDeploy.create_config config_arg SimpleDeploy.logger @opts[:log_level] override_attributes = parse_attributes :attributes => @opts[:attributes] cloned_attributes = filter_attributes source_stack.attributes template_file = Tempfile.new("#{@opts[:new_name]}_template.json") template_file_path = template_file.path if @opts[:template] template_file_path = @opts[:template] else template_file.write source_stack.template end if @opts[:input_stack] input_attributes = mapper.map_outputs_from_stacks :stacks => @opts[:input_stack], :template => template_file_path new_overrides = merge_attributes input_attributes, override_attributes new_overrides += add_attributes input_attributes, override_attributes else new_overrides = override_attributes end new_attributes = merge_attributes cloned_attributes, new_overrides new_attributes += add_attributes cloned_attributes, new_overrides rescue_exceptions_and_exit do new_stack.create :attributes => new_attributes, :template => template_file_path end template_file.close end def command_summary 'Clone a stack' end private def filter_attributes(source_attributes) selected = source_attributes.select { |k| k !~ /^deployment/ } selected.map { |k,v| { k => v } } end def merge_attributes(cloned_attributes, override_attributes) cloned_attributes.map do |clone| key = clone.keys.first override = override_attributes.find { |o| o.has_key? key } override ? override : clone end end def add_attributes(cloned_attributes, override_attributes) override_attributes.map do |override| key = override.keys.first clone = cloned_attributes.find { |c| c.has_key? key } clone ? nil : override end.compact end def mapper @om ||= Stack::OutputMapper.new :environment => @opts[:environment] end def source_stack @source_stack = Stack.new :name => @opts[:source_name], :environment => @opts[:environment] end def new_stack @new_stack = Stack.new :name => @opts[:new_name], :environment => @opts[:environment] end end end end