require 'spec_helper' describe SimpleDeploy::AWS::InstanceReader do include_context 'double stubbed logger' describe 'temporary credentials' do include_context 'double stubbed config', :access_key => 'key', :secret_key => 'XXX', :security_token => 'the token', :temporary_credentials? => true, :region => 'us-west-1' it 'creates a connection with the temporary credentials' do args = { aws_access_key_id: 'key', aws_secret_access_key: 'XXX', aws_session_token: 'the token', region: 'us-west-1' } Fog::AWS::AutoScaling.should_receive(:new).with(args) Fog::Compute::AWS.should_receive(:new).with(args) SimpleDeploy::AWS::InstanceReader.new end end describe 'with long lived credentials' do include_context 'double stubbed config', :access_key => 'key', :secret_key => 'XXX', :security_token => nil, :temporary_credentials? => false, :region => 'us-west-1' before do @auto_scaling_groups_mock = mock 'auto scaling' @cloud_formation_mock = mock 'cloud formation' @ec2_mock = mock 'ec2' Fog::AWS::AutoScaling.stub(:new).and_return @auto_scaling_groups_mock Fog::Compute::AWS.stub(:new).and_return @ec2_mock SimpleDeploy::AWS::CloudFormation.stub(:new). and_return @cloud_formation_mock end describe "list_stack_instances" do before do instances = ['first',{ 'Instances' => [{ 'InstanceId' => 'i-000001' }, { 'InstanceId' => 'i-000002' }] }] body = { 'DescribeAutoScalingGroupsResult' => { 'AutoScalingGroups' => instances } } @list_response = stub 'Fog::Response', :body => body, :any? => true empty_body = { 'DescribeAutoScalingGroupsResult' => { 'AutoScalingGroups' => [] } } @empty_response = stub 'Fog::Response', :body => empty_body @describe_response = stub 'Excon::Response', :body => { 'reservationSet' => [{ 'instanceSet' => [{'instanceState' => {'name' => 'running'}}, {'ipAddress' => '54.10.10.1'}, {'instanceId' => 'i-123456'}, {'privateIpAddress' => '192.168.1.1'}]}] } end context "with no ASGs" do before do @cloud_formation_mock.should_receive(:stack_resources). exactly(3).times. with('stack'). and_return [] end it "should return an empty array" do instance_reader = SimpleDeploy::AWS::InstanceReader.new instance_reader.list_stack_instances('stack').should == [] end end context "with an ASGs" do before do stack_resource_results = [] @asgs = ['asg1', 'asg2'].each do |asg| stack_resource_results << { 'StackName' => 'stack', 'ResourceType' => 'AWS::AutoScaling::AutoScalingGroup', 'PhysicalResourceId' => asg } end @cloud_formation_mock.should_receive(:stack_resources). exactly(3).times. with('stack'). and_return stack_resource_results end context "with no running instances" do it "should return empty array" do @asgs.each do |asg| @auto_scaling_groups_mock.should_receive(:describe_auto_scaling_groups). with('AutoScalingGroupNames' => [asg]). and_return(@empty_response) end instance_reader = SimpleDeploy::AWS::InstanceReader.new instance_reader.list_stack_instances('stack').should == [] end end context "with running instances" do it "should return the reservation set for each running instance" do @auto_scaling_groups_mock.should_receive(:describe_auto_scaling_groups). with('AutoScalingGroupNames' => ['asg1']). and_return(@list_response) @auto_scaling_groups_mock.should_receive(:describe_auto_scaling_groups). with('AutoScalingGroupNames' => ['asg2']). and_return(@empty_response) @ec2_mock.should_receive(:describe_instances). with('instance-state-name' => 'running', 'instance-id' => ['i-000001', 'i-000002']). and_return @describe_response instance_reader = SimpleDeploy::AWS::InstanceReader.new instance_reader.list_stack_instances('stack').should == [{ 'instanceSet' => [{'instanceState' => {'name' => 'running'}}, {'ipAddress' => '54.10.10.1'}, {'instanceId' => 'i-123456'}, {'privateIpAddress' => '192.168.1.1'}]}] end end end context "with nested stacks and ASGs and EC2 instances" do before do stack_resource_results = [] @nested_stacks = ['nested_stack1', 'nested_stack2'].each do |nested_stack| @cloud_formation_mock.should_receive(:stack_status). with(nested_stack). and_return 'CREATE_COMPLETE' stack_resource_results << { 'StackName' => 'stack', 'ResourceType' => 'AWS::CloudFormation::Stack', 'PhysicalResourceId' => nested_stack } end @asgs = ['asg1', 'asg2'].each do |asg| stack_resource_results << { 'StackName' => 'stack', 'ResourceType' => 'AWS::AutoScaling::AutoScalingGroup', 'PhysicalResourceId' => asg } end @instances = ['i-instance1', 'i-instance2'].each do |instance| stack_resource_results << { 'StackName' => 'stack', 'ResourceType' => 'AWS::EC2::Instance', 'PhysicalResourceId' => instance } end @cloud_formation_mock.should_receive(:stack_resources). exactly(3).times. with('stack'). and_return stack_resource_results end context "with running instances in nested stack and ASG and EC2 instances" do it "should return the reservation set for each running instance" do @cloud_formation_mock.should_receive(:stack_resources). exactly(3).times. with('nested_stack1'). and_return [] nested_stack2_resource_results = [] @asgs = ['nested_stack2_asg1', 'nested_stack2_asg2'].each do |nested_stack2_resource_asg| nested_stack2_resource_results << { 'StackName' => 'nested_stack2', 'ResourceType' => 'AWS::AutoScaling::AutoScalingGroup', 'PhysicalResourceId' => nested_stack2_resource_asg } end @cloud_formation_mock.should_receive(:stack_resources). exactly(3).times. with('nested_stack2'). and_return nested_stack2_resource_results nested_list_response = stub 'Fog::Response', :body => { 'DescribeAutoScalingGroupsResult' => { 'AutoScalingGroups' => ['first', { 'Instances' => [{ 'InstanceId' => 'i-stack001' }, { 'InstanceId' => 'i-stack002' }] }] } }, :any? => true @auto_scaling_groups_mock.should_receive(:describe_auto_scaling_groups). with('AutoScalingGroupNames' => ['nested_stack2_asg1']). and_return(nested_list_response) @auto_scaling_groups_mock.should_receive(:describe_auto_scaling_groups). with('AutoScalingGroupNames' => ['nested_stack2_asg2']). and_return(@empty_response) @auto_scaling_groups_mock.should_receive(:describe_auto_scaling_groups). with('AutoScalingGroupNames' => ['asg1']). and_return(@list_response) @auto_scaling_groups_mock.should_receive(:describe_auto_scaling_groups). with('AutoScalingGroupNames' => ['asg2']). and_return(@empty_response) @ec2_mock.should_receive(:describe_instances). with('instance-state-name' => 'running', 'instance-id' => ['i-stack001', 'i-stack002']). and_return @describe_response @ec2_mock.should_receive(:describe_instances). with('instance-state-name' => 'running', 'instance-id' => ['i-000001', 'i-000002','i-instance1', 'i-instance2'] ). and_return @describe_response instance_reader = SimpleDeploy::AWS::InstanceReader.new instance_reader.list_stack_instances('stack').should == [{ 'instanceSet' => [{'instanceState' => {'name' => 'running'}}, {'ipAddress' => '54.10.10.1'}, {'instanceId' => 'i-123456'}, {'privateIpAddress' => '192.168.1.1'}]}, { 'instanceSet' => [{'instanceState' => {'name' => 'running'}}, {'ipAddress' => '54.10.10.1'}, {'instanceId' => 'i-123456'}, {'privateIpAddress' => '192.168.1.1'}]}] end end end end end end