aws-must-templates 0.1.6 → 0.2.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +97 -44
- data/lib/tasks/cross-ref.rb +6 -0
- data/lib/tasks/suite.rake +150 -48
- data/lib/test-suites/test_suites.rb +13 -13
- data/mustache/commonDependsOn.mustache +24 -2
- data/mustache/commonRef.mustache +22 -0
- data/mustache/commonValue.mustache +1 -1
- data/mustache/commonXGressRule.mustache +31 -0
- data/mustache/mapping.mustache +3 -1
- data/mustache/mappingAmazonVpcNat.mustache +38 -0
- data/mustache/resource.mustache +4 -0
- data/mustache/resourceInstance.mustache +26 -7
- data/mustache/resourceInternetGateway.mustache +30 -16
- data/mustache/resourceRoute.mustache +50 -0
- data/mustache/resourceRouteTable.mustache +67 -0
- data/mustache/resourceSecurityGroup.mustache +13 -12
- data/mustache/resourceSubnet.mustache +20 -8
- data/mustache/root.mustache +26 -11
- data/spec/aws-must-templates/AllwaysOk/AllwaysOk_spec.rb +35 -0
- data/spec/aws-must-templates/AwsCommandLineInterfaceInstalled/AwsCommandLineInterfaceInstalled_spec.rb +19 -1
- data/spec/aws-must-templates/AwsMustTestRunnerProperties/AwsMustTestRunnerProperties_spec.rb +16 -1
- data/spec/aws-must-templates/CloudFormationHelperScriptsInstalled/CloudFormationHelperScriptsInstalled_spec.rb +17 -0
- data/spec/aws-must-templates/Ec2InstanceType/Ec2InstanceType_spec.rb +47 -0
- data/spec/aws-must-templates/Ec2PrivateIp/Ec2PrivateIp_spec.rb +49 -0
- data/spec/aws-must-templates/Ec2PublicIp/Ec2PublicIp_spec.rb +68 -0
- data/spec/aws-must-templates/Ec2Routes/Ec2Routes_spec.rb +69 -0
- data/spec/aws-must-templates/Ec2SecurityGroups/Ec2SecurityGroups_spec.rb +151 -0
- data/spec/aws-must-templates/Ec2StatusNormal/Ec2StatusNormal_spec.rb +55 -0
- data/spec/aws-must-templates/NetworkCanPing/NetworkCanPing_spec.rb +36 -0
- data/spec/aws-must-templates/ParameterTest/ParameterTest_spec.rb +17 -1
- data/spec/aws-must-templates/RespondsToPing/RespondsToPing_spec.rb +46 -0
- data/spec/aws-must-templates/S3NoAccess/S3NoAccess_spec.rb +17 -3
- data/spec/aws-must-templates/S3ReadAccessAllowed/S3ReadAccessAllowed_spec.rb +18 -1
- data/spec/aws-must-templates/Stack/Stack_spec.rb +28 -1
- data/spec/aws-must-templates/ValidOSVersion/ValidOSVersion_spec.rb +16 -1
- data/spec/aws-must-templates/Vpc/vpc_spec.rb +51 -0
- data/spec/aws-must-templates/table_of_content.mustache +67 -0
- data/spec/lib/test_suites_spec.rb +101 -28
- data/spec/mustache/commonDependsOn_spec.rb +57 -2
- data/spec/mustache/commonInstanceType_spec.rb +1 -1
- data/spec/mustache/mappingAmazonVpcNat_spec.rb +56 -0
- data/spec/mustache/mapping_spec.rb +48 -7
- data/spec/mustache/resourceInstance_spec.rb +102 -1
- data/spec/mustache/resourceInternetGateway_spec.rb +14 -9
- data/spec/mustache/resourcePolicy_spec.rb +1 -1
- data/spec/mustache/resourceS3Bucket_spec.rb +1 -1
- data/spec/mustache/resourceSecurityGroup_spec.rb +3 -3
- data/spec/mustache/resourceSubnet_spec.rb +50 -3
- data/spec/support/lib/aws/aws.rb +6 -0
- data/spec/support/lib/aws/ec2_resource.rb +177 -0
- data/spec/support/lib/aws/mixin_cidr.rb +18 -0
- data/spec/support/lib/aws/mixin_ec2.rb +53 -0
- data/spec/support/lib/aws/mixin_security_group.rb +15 -0
- data/spec/support/lib/aws/mixin_subnet.rb +77 -0
- data/spec/support/lib/aws/mixin_vpc.rb +10 -0
- data/spec/support/lib/aws/route_resource.rb +86 -0
- data/spec/support/lib/aws/security_group_resource.rb +120 -0
- data/spec/support/lib/aws/vpc_resource.rb +69 -0
- data/spec/support/lib/suite_value.rb +38 -0
- data/spec/support/lib/test_parameter.rb +12 -8
- data/spec/support/lib/valid_property.rb +29 -9
- data/spec/support/spec_helper.rb +75 -44
- data/spec/support/utils.rb +4 -0
- metadata +34 -24
@@ -0,0 +1,86 @@
|
|
1
|
+
require 'aws-sdk'
|
2
|
+
require 'serverspec'
|
3
|
+
|
4
|
+
|
5
|
+
|
6
|
+
module Serverspec
|
7
|
+
module Type
|
8
|
+
class AwsRoute < Base
|
9
|
+
|
10
|
+
# ------------------------------------------------------------------
|
11
|
+
# attrbutes
|
12
|
+
|
13
|
+
attr_accessor :instanceName # tagged
|
14
|
+
|
15
|
+
|
16
|
+
# ------------------------------------------------------------------
|
17
|
+
# constrcutore
|
18
|
+
|
19
|
+
def self.new_for_ec2( instanceName )
|
20
|
+
raise "must set a 'instanceName' " unless instanceName
|
21
|
+
|
22
|
+
awsRoute = AwsRoute.new
|
23
|
+
awsRoute.instanceName = instanceName
|
24
|
+
return awsRoute
|
25
|
+
end
|
26
|
+
|
27
|
+
def initialize
|
28
|
+
end
|
29
|
+
|
30
|
+
# ------------------------------------------------------------------
|
31
|
+
# public interface
|
32
|
+
|
33
|
+
def to_s
|
34
|
+
"awsRoute: " +
|
35
|
+
( @instanceName ? " instanceName=#{@instanceName}" : "" )
|
36
|
+
end
|
37
|
+
|
38
|
+
|
39
|
+
def subnet_routes
|
40
|
+
subnetId = describe_instance.subnet_id
|
41
|
+
subnet_routes_as_array_of_hashes( subnetId )
|
42
|
+
end
|
43
|
+
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
# ------------------------------------------------------------------
|
48
|
+
# mixin interface
|
49
|
+
|
50
|
+
def client
|
51
|
+
@ec2Client = Aws::EC2::Client.new
|
52
|
+
return @ec2Client
|
53
|
+
end
|
54
|
+
|
55
|
+
def get_instanceId
|
56
|
+
return @instanceId if @instanceId
|
57
|
+
options = {
|
58
|
+
dry_run: false,
|
59
|
+
filters: [
|
60
|
+
{ name: "tag:Name", values: [ instanceName ]},
|
61
|
+
{ name: "instance-state-name", values: [ "running" ]},
|
62
|
+
],
|
63
|
+
}
|
64
|
+
|
65
|
+
@instanceId = describe_instances(options).reservations.first.instances.first.instance_id
|
66
|
+
return @instanceId
|
67
|
+
end
|
68
|
+
|
69
|
+
# ------------------------------------------------------------------
|
70
|
+
# mixin services included
|
71
|
+
|
72
|
+
include AwsMustTemplates::Mixin::EC2
|
73
|
+
include AwsMustTemplates::Mixin::Subnet
|
74
|
+
|
75
|
+
end # class Vpc < Base
|
76
|
+
|
77
|
+
def route_resource_for_ec2( instanceName )
|
78
|
+
AwsRoute.new_for_ec2( instanceName.kind_of?(Serverspec::Type::ValidProperty) ? instanceName.value : instanceName )
|
79
|
+
end
|
80
|
+
|
81
|
+
|
82
|
+
end # module Type
|
83
|
+
end
|
84
|
+
|
85
|
+
include Serverspec::Type
|
86
|
+
|
@@ -0,0 +1,120 @@
|
|
1
|
+
require 'aws-sdk'
|
2
|
+
require 'serverspec'
|
3
|
+
|
4
|
+
require_relative "./mixin_security_group"
|
5
|
+
|
6
|
+
module Serverspec
|
7
|
+
module Type
|
8
|
+
class SecurityGroup < Base
|
9
|
+
|
10
|
+
# ------------------------------------------------------------------
|
11
|
+
# attrbutes
|
12
|
+
|
13
|
+
attr_accessor :instanceName # ec2 tagged with 'Name' = @instanceName
|
14
|
+
|
15
|
+
|
16
|
+
# ------------------------------------------------------------------
|
17
|
+
# constrcutore
|
18
|
+
|
19
|
+
def self.new_for_ec2( instanceName )
|
20
|
+
raise "must set a 'instanceName' " unless instanceName
|
21
|
+
|
22
|
+
sg = SecurityGroup.new
|
23
|
+
sg.instanceName = instanceName
|
24
|
+
return sg
|
25
|
+
end
|
26
|
+
|
27
|
+
def initialize
|
28
|
+
end
|
29
|
+
|
30
|
+
# ------------------------------------------------------------------
|
31
|
+
# public interface
|
32
|
+
|
33
|
+
def to_s
|
34
|
+
"Security group: " +
|
35
|
+
( @instanceName ? " instanceName=#{@instanceName}" : "" )
|
36
|
+
end
|
37
|
+
|
38
|
+
# http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/using-network-security.html#security-group-rules
|
39
|
+
# Security group rules are always permissive; you can't create
|
40
|
+
# rules that deny access.
|
41
|
+
def instance_ingress_rules
|
42
|
+
instance_security_group_ip_permissions
|
43
|
+
end
|
44
|
+
|
45
|
+
def instance_egress_rules
|
46
|
+
instance_security_group_ip_permissions_egress
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
# collect all ingress permissions to an array
|
52
|
+
def instance_security_group_ip_permissions
|
53
|
+
ret = [];
|
54
|
+
describe_security_groups(instance_security_group_ids).
|
55
|
+
inject( ret ){ |ret,group|
|
56
|
+
group.ip_permissions.each{ |ip_permission| ret << ip_permission.to_h }}
|
57
|
+
return ret
|
58
|
+
end
|
59
|
+
|
60
|
+
# collect all egress permissions to an array
|
61
|
+
def instance_security_group_ip_permissions_egress
|
62
|
+
ret = [];
|
63
|
+
describe_security_groups(instance_security_group_ids).
|
64
|
+
inject( ret ){ |ret,group|
|
65
|
+
group.ip_permissions_egress.each{ |ip_permission_egress| ret << ip_permission_egress.to_h }}
|
66
|
+
return ret
|
67
|
+
end
|
68
|
+
|
69
|
+
|
70
|
+
# security group ids for an instance
|
71
|
+
def instance_security_group_ids
|
72
|
+
instance_security_groups.map{ |group| group.group_id }
|
73
|
+
end
|
74
|
+
|
75
|
+
|
76
|
+
# for an instance
|
77
|
+
def instance_security_groups
|
78
|
+
describe_instance.security_groups
|
79
|
+
end
|
80
|
+
|
81
|
+
|
82
|
+
# ------------------------------------------------------------------
|
83
|
+
# mixin interface
|
84
|
+
|
85
|
+
def client
|
86
|
+
@ec2Client = Aws::EC2::Client.new
|
87
|
+
return @ec2Client
|
88
|
+
end
|
89
|
+
|
90
|
+
def get_instanceId
|
91
|
+
return @instanceId if @instanceId
|
92
|
+
options = {
|
93
|
+
dry_run: false,
|
94
|
+
filters: [
|
95
|
+
{ name: "tag:Name", values: [ instanceName ]},
|
96
|
+
{ name: "instance-state-name", values: [ "running" ]},
|
97
|
+
],
|
98
|
+
}
|
99
|
+
|
100
|
+
@instanceId = describe_instances(options).reservations.first.instances.first.instance_id
|
101
|
+
return @instanceId
|
102
|
+
end
|
103
|
+
|
104
|
+
# ------------------------------------------------------------------
|
105
|
+
# mixin services included
|
106
|
+
|
107
|
+
include AwsMustTemplates::Mixin::EC2
|
108
|
+
include AwsMustTemplates::Mixin::SecurityGroup
|
109
|
+
|
110
|
+
end # class Vpc < Base
|
111
|
+
|
112
|
+
def security_group_resource_for_ec2( instanceName )
|
113
|
+
SecurityGroup.new_for_ec2( instanceName.kind_of?(Serverspec::Type::ValidProperty) ? instanceName.value : instanceName )
|
114
|
+
end
|
115
|
+
|
116
|
+
end # module Type
|
117
|
+
end
|
118
|
+
|
119
|
+
include Serverspec::Type
|
120
|
+
|
@@ -0,0 +1,69 @@
|
|
1
|
+
require 'aws-sdk'
|
2
|
+
require 'serverspec'
|
3
|
+
|
4
|
+
|
5
|
+
|
6
|
+
module Serverspec
|
7
|
+
module Type
|
8
|
+
|
9
|
+
class VpcResource < Base
|
10
|
+
|
11
|
+
def initialize( vpcName )
|
12
|
+
raise "must set a 'vpcName' " unless vpcName
|
13
|
+
@vpcName = vpcName
|
14
|
+
end
|
15
|
+
|
16
|
+
def to_s
|
17
|
+
"vpc: '#{@vpcName}'"
|
18
|
+
end
|
19
|
+
|
20
|
+
def is_default?
|
21
|
+
return describe_vpc.is_default
|
22
|
+
end
|
23
|
+
|
24
|
+
# convinience routine to check value of state
|
25
|
+
def is_available?
|
26
|
+
return state == "available"
|
27
|
+
end
|
28
|
+
|
29
|
+
# String, one of "pending", "available"
|
30
|
+
def state
|
31
|
+
return describe_vpc.state
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def client
|
37
|
+
@ec2Client = Aws::EC2::Client.new
|
38
|
+
return @ec2Client
|
39
|
+
end
|
40
|
+
|
41
|
+
def describe_vpc
|
42
|
+
vpcs = describe_vpcs
|
43
|
+
# vpc tagged `Name`== @vpcName
|
44
|
+
vpc = vpcs.vpcs.select {|vpc| vpc.tags.select{ |tag| tag['key'] == 'Name' && tag['value'] == @vpcName }.any? }.first
|
45
|
+
raise "No vpc tagged 'Name'='#{@vpcName}'" if vpc.nil?
|
46
|
+
return vpc
|
47
|
+
end
|
48
|
+
|
49
|
+
# read all vpc
|
50
|
+
def describe_vpcs
|
51
|
+
options = {
|
52
|
+
dry_run: false,
|
53
|
+
}
|
54
|
+
client.describe_vpcs( options )
|
55
|
+
end
|
56
|
+
|
57
|
+
|
58
|
+
end # class Vpc < Base
|
59
|
+
|
60
|
+
def vpc_resource_by_name( vpcName )
|
61
|
+
VpcResource.new( vpcName )
|
62
|
+
end
|
63
|
+
|
64
|
+
|
65
|
+
end # module Type
|
66
|
+
end
|
67
|
+
|
68
|
+
include Serverspec::Type
|
69
|
+
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module Serverspec
|
2
|
+
module Type
|
3
|
+
|
4
|
+
class SuiteValue < ValidProperty
|
5
|
+
|
6
|
+
VALID_VALUES = [ :host,
|
7
|
+
:instance_name,
|
8
|
+
:stack_id,
|
9
|
+
:suite_id
|
10
|
+
]
|
11
|
+
|
12
|
+
def initialize(key)
|
13
|
+
raise <<-EOS unless VALID_VALUES.include?(key)
|
14
|
+
Invalid suite value #{key}
|
15
|
+
|
16
|
+
Valid values #{VALID_VALUES.join( ', ')}
|
17
|
+
EOS
|
18
|
+
keys = []
|
19
|
+
keys << key
|
20
|
+
@key = key
|
21
|
+
super( keys )
|
22
|
+
end
|
23
|
+
|
24
|
+
def to_s
|
25
|
+
"Suite value '#{@key}'"
|
26
|
+
end
|
27
|
+
|
28
|
+
end # class
|
29
|
+
|
30
|
+
def suite_value( key )
|
31
|
+
SuiteValue.new( key )
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
include Serverspec::Type
|
38
|
+
|
@@ -3,7 +3,7 @@ module Serverspec
|
|
3
3
|
|
4
4
|
class TestParameter < ValidProperty
|
5
5
|
|
6
|
-
def initialize( role_id, test_parameter_name )
|
6
|
+
def initialize( role_id, test_parameter_name, mandatory )
|
7
7
|
|
8
8
|
keys = ["Roles"]
|
9
9
|
keys << role_id
|
@@ -12,9 +12,10 @@ module Serverspec
|
|
12
12
|
@role_id = role_id
|
13
13
|
@test_parameter_name = test_parameter_name
|
14
14
|
|
15
|
-
|
15
|
+
super( keys )
|
16
|
+
|
17
|
+
validate if mandatory
|
16
18
|
|
17
|
-
validate
|
18
19
|
end
|
19
20
|
|
20
21
|
# rpsec description text
|
@@ -24,18 +25,18 @@ module Serverspec
|
|
24
25
|
|
25
26
|
# error string
|
26
27
|
def to_error_s
|
27
|
-
"Test paramater '#{@test_parameter_name}' configuration error in suite '#{ @runner.property[:suite_id]}' test '#{@role_id}'"
|
28
|
+
"Test paramater '#{@test_parameter_name}' configuration error in suite '#{ @runner.property[:suite_id]}' #{ @runner.property[:instance_name] ? 'instance \'' + @runner.property[:instance_name] + '\'' : ' common ' } test '#{@role_id}' "
|
28
29
|
end
|
29
30
|
|
30
31
|
# definition in test_suite.yaml (nil if not defined)
|
31
32
|
def definition_in_test_suite
|
32
|
-
self.class.superclass.instance_method(:
|
33
|
+
self.class.superclass.instance_method(:defined?).bind(self).call
|
33
34
|
# method( :value ).super_method.call
|
34
35
|
end
|
35
36
|
|
36
37
|
# exception unless definition ok
|
37
38
|
def validate
|
38
|
-
raise to_error_s unless
|
39
|
+
raise to_error_s unless definition_in_test_suite
|
39
40
|
end
|
40
41
|
|
41
42
|
# evaluated value
|
@@ -45,16 +46,19 @@ module Serverspec
|
|
45
46
|
end
|
46
47
|
|
47
48
|
private
|
49
|
+
|
50
|
+
# value starts with '@' --> lookup in 'properties'
|
48
51
|
def param_evaluate( val )
|
49
52
|
return val if val.nil?
|
53
|
+
return val if !!val == val
|
50
54
|
return val unless val[0] == "@"
|
51
55
|
return resolve_value_for_keys( val[1..-1].split( '.' ) )
|
52
56
|
end
|
53
57
|
|
54
58
|
end # class
|
55
59
|
|
56
|
-
def test_parameter( role_id, test_parameter_name )
|
57
|
-
TestParameter.new( role_id, test_parameter_name )
|
60
|
+
def test_parameter( role_id, test_parameter_name, mandatory=true )
|
61
|
+
TestParameter.new( role_id, test_parameter_name, mandatory )
|
58
62
|
end
|
59
63
|
|
60
64
|
end
|
@@ -17,37 +17,57 @@ module Serverspec
|
|
17
17
|
@value
|
18
18
|
end
|
19
19
|
|
20
|
+
# key exist (may be nil)
|
20
21
|
# RSpec document output
|
21
22
|
def to_s
|
22
23
|
"property with keys #{@keys}" # + " in @runner.property= #{@runner.property}"
|
23
24
|
end
|
24
25
|
|
25
|
-
#
|
26
|
-
def
|
27
|
-
|
28
|
-
props = @runner.property
|
26
|
+
# yield block for final value iterating 'keys' in 'props'
|
27
|
+
def iterate_keys(keys, props )
|
29
28
|
|
30
29
|
# iterate keys
|
31
|
-
keys.
|
30
|
+
keys.each_with_index do |k,index|
|
32
31
|
# puts "Prrops=#{props}, k=#{k}"
|
33
32
|
if props.nil? then
|
34
33
|
# fixed point reached
|
35
34
|
props = nil
|
36
35
|
elsif props.is_a?( Hash ) then
|
37
36
|
# recurse down a hash
|
38
|
-
props = props[k]
|
37
|
+
# props = props[k]
|
38
|
+
if index == (keys.size() -1 ) then
|
39
|
+
props = yield props, k
|
40
|
+
else
|
41
|
+
props = props[k]
|
42
|
+
end
|
39
43
|
elsif props.is_a?( Array ) then
|
40
44
|
# choose hash with a matching key from an array
|
41
|
-
props = props.select{ |e| e.is_a?(Hash) && e.keys.first == k }.first
|
42
|
-
props = props
|
45
|
+
# props = props.select{ |e| e.is_a?(Hash) && e.keys.first == k }.first
|
46
|
+
props = props.select{ |e| e.is_a?(Hash) && e.keys.include?(k) }.first
|
47
|
+
if props then
|
48
|
+
if index == (keys.size() -1) then
|
49
|
+
props = yield props, k
|
50
|
+
else
|
51
|
+
props = props[k]
|
52
|
+
end
|
53
|
+
# props = props[k]
|
54
|
+
end
|
43
55
|
else
|
44
56
|
# unknown case
|
45
57
|
props = nil
|
46
58
|
end
|
47
59
|
end
|
48
|
-
|
49
60
|
return props
|
61
|
+
end
|
50
62
|
|
63
|
+
# is last key defined (value maybe whatever)
|
64
|
+
def defined?
|
65
|
+
iterate_keys( @keys, @runner.property) { |hash,key| hash.has_key?(key) }
|
66
|
+
end
|
67
|
+
|
68
|
+
# return value for 'keys' in '@runner.property'
|
69
|
+
def resolve_value_for_keys( keys )
|
70
|
+
iterate_keys( keys, @runner.property) { |hash,key| hash[key] }
|
51
71
|
end
|
52
72
|
|
53
73
|
end
|
data/spec/support/spec_helper.rb
CHANGED
@@ -8,7 +8,68 @@ require_relative "./utils.rb"
|
|
8
8
|
# test-suites interface
|
9
9
|
require_relative "../../lib/test-suites/test_suites.rb"
|
10
10
|
|
11
|
-
|
11
|
+
|
12
|
+
# ------------------------------------------------------------------
|
13
|
+
# Constants
|
14
|
+
|
15
|
+
describe_stacks_command =
|
16
|
+
"aws cloudformation describe-stacks" # read json using aws cli
|
17
|
+
|
18
|
+
# SSH client configuration to use
|
19
|
+
ssh_config_file = "ssh/config.aws"
|
20
|
+
# file to use
|
21
|
+
# stack states
|
22
|
+
|
23
|
+
SUCESS_STATES = ["CREATE_COMPLETE", "UPDATE_COMPLETE"]
|
24
|
+
FAILURE_STATES = ["CREATE_FAILED", "DELETE_FAILED", "UPDATE_ROLLBACK_FAILED", "ROLLBACK_FAILED", "ROLLBACK_COMPLETE","ROLLBACK_FAILED","UPDATE_ROLLBACK_COMPLETE","UPDATE_ROLLBACK_FAILED"]
|
25
|
+
END_STATES = SUCESS_STATES + FAILURE_STATES
|
26
|
+
|
27
|
+
|
28
|
+
# return ssh options for 'hostname_for_instance'
|
29
|
+
def read_ssh_options( instance_name, ssh_config_file, options_init )
|
30
|
+
|
31
|
+
|
32
|
+
raise <<-EOS unless File.exist?( ssh_config_file )
|
33
|
+
|
34
|
+
Could not find ssh configuration file in '#{ssh_config_file}'.
|
35
|
+
|
36
|
+
Serverspec uses ssh to connect to #{instance_name}, but no configuration found!
|
37
|
+
|
38
|
+
EOS
|
39
|
+
|
40
|
+
|
41
|
+
# start search for an instance id
|
42
|
+
# puts "read_ssh_options: instance_name:#{instance_name}"
|
43
|
+
host = instance_name
|
44
|
+
|
45
|
+
options = Net::SSH::Config.for( host, [ ssh_config_file ] )
|
46
|
+
# puts "read_ssh_options: host:#{host} --> options#{options}"
|
47
|
+
# options[:verbose] = :info # :debug, :info, :warn, :error, :fatal
|
48
|
+
|
49
|
+
# mapped to another name?
|
50
|
+
if options[:host_name] then
|
51
|
+
host = options[:host_name]
|
52
|
+
options2 = Net::SSH::Config.for( host, [ ssh_config_file ] )
|
53
|
+
# puts "read_ssh_options: host:#{host} --> options2#{options2}"
|
54
|
+
if options2[:proxy] then
|
55
|
+
# use proxy - if defined
|
56
|
+
options = options2
|
57
|
+
# keep original host_name where to connect
|
58
|
+
options[:host_name] = host
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
# puts "read_ssh_options: result host:#{host} --> options#{options}"
|
63
|
+
return options
|
64
|
+
|
65
|
+
end
|
66
|
+
|
67
|
+
# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
68
|
+
# Main
|
69
|
+
|
70
|
+
# ------------------------------------------------------------------
|
71
|
+
# load test-suites.yaml to an object
|
72
|
+
|
12
73
|
test_suites = AwsMustTemplates::TestSuites::TestSuites.new
|
13
74
|
|
14
75
|
# ------------------------------------------------------------------
|
@@ -31,31 +92,14 @@ end
|
|
31
92
|
# suite.rake sets target ENV for suite and instance id
|
32
93
|
|
33
94
|
suite_id = ENV['TARGET_SUITE_ID'] # test suite being processed
|
34
|
-
|
95
|
+
instance_name = ENV['TARGET_INSTANCE_NAME'] # instance being tested (if any)
|
35
96
|
|
36
97
|
# map suite_id to stack_id
|
37
98
|
stack_id = test_suites.get_suite_stack_id( suite_id )
|
38
99
|
|
39
100
|
puts "------------------------------------------------------------------"
|
40
|
-
puts "
|
41
|
-
|
42
|
-
# ------------------------------------------------------------------
|
43
|
-
# Constants used in stack
|
44
|
-
|
45
|
-
output_key_for_hostname = instance_id # Stack Output variable for
|
46
|
-
# ip/hostname for the instance
|
47
|
-
|
48
|
-
describe_stacks_command =
|
49
|
-
"aws cloudformation describe-stacks" # read json using aws cli
|
101
|
+
puts "instance_name #{instance_name}" if instance_name
|
50
102
|
|
51
|
-
# SSH client configuration must be in CWD (=user directory)
|
52
|
-
ssh_config_file = "ssh/config"
|
53
|
-
# file to use
|
54
|
-
# stack states
|
55
|
-
|
56
|
-
SUCESS_STATES = ["CREATE_COMPLETE", "UPDATE_COMPLETE"]
|
57
|
-
FAILURE_STATES = ["CREATE_FAILED", "DELETE_FAILED", "UPDATE_ROLLBACK_FAILED", "ROLLBACK_FAILED", "ROLLBACK_COMPLETE","ROLLBACK_FAILED","UPDATE_ROLLBACK_COMPLETE","UPDATE_ROLLBACK_FAILED"]
|
58
|
-
END_STATES = SUCESS_STATES + FAILURE_STATES
|
59
103
|
|
60
104
|
# ------------------------------------------------------------------
|
61
105
|
# access cloudformation stacks using aws cli
|
@@ -78,19 +122,16 @@ EOS
|
|
78
122
|
|
79
123
|
raise "Stack '#{stack_id}' status='#{stack_json["StackStatus"]} is not ready (=#{SUCESS_STATES}) '" unless SUCESS_STATES.include?( stack_json["StackStatus"] )
|
80
124
|
|
81
|
-
|
82
|
-
|
83
|
-
hostname_in_stack=stack_json["Outputs"].select {|a| a["OutputKey"] == output_key_for_hostname }.first["OutputValue"]
|
84
|
-
raise "Could not find OutputKey '#{output_key_for_hostname}' in stack '#{stack}' for instance_id '#{instance_id}'" unless hostname_in_stack
|
85
|
-
end
|
125
|
+
# ------------------------------------------------------------------
|
126
|
+
# hash in accessible in spec tests with name 'property'
|
86
127
|
|
87
|
-
# create a hash, which is accessible in spec tests are 'property'
|
88
128
|
properties = {
|
89
129
|
"Outputs" => stack_json["Outputs"] ? stack_json["Outputs"].inject( {} ) { |r,e| r[e["OutputKey"]] = e["OutputValue"] ; r } : {},
|
90
130
|
"Parameters" => stack_json["Parameters"] ? stack_json["Parameters"].inject( {} ) { |r,e| r[e["ParameterKey"]] = e["ParameterValue"] ; r }: {},
|
91
131
|
# Roles for test (from instance or from common suites)
|
92
|
-
"Roles" => (
|
93
|
-
:host =>
|
132
|
+
"Roles" => ( instance_name ? test_suites.suite_instance_roles( suite_id, instance_name ) : test_suites.suite_roles( suite_id ) ),
|
133
|
+
:host => instance_name,
|
134
|
+
:instance_name => instance_name,
|
94
135
|
:stack_id => stack_id,
|
95
136
|
:suite_id=> suite_id,
|
96
137
|
}
|
@@ -104,25 +145,13 @@ set_property properties
|
|
104
145
|
|
105
146
|
# CloudFormatio instance resources are defined in 'ssh_config_file'
|
106
147
|
|
107
|
-
|
108
|
-
|
109
|
-
Could not find ssh configuration file in '#{ssh_config_file}'.
|
110
|
-
|
111
|
-
Serverspec uses ssh to connect to #{instance_id}, but no configuration found!
|
112
|
-
|
113
|
-
EOS
|
114
|
-
|
115
|
-
options = Net::SSH::Config.for(instance_id, [ ssh_config_file ] )
|
116
|
-
# puts "instance_id #{instance_id}, options=#{options}"
|
117
|
-
|
118
|
-
# use ip host_name to access stack resource `instance_id`
|
119
|
-
options[:host_name] = hostname_in_stack
|
148
|
+
options = read_ssh_options( instance_name, ssh_config_file, {} )
|
149
|
+
# puts "instance_name #{instance_name}--> options=#{options}"
|
120
150
|
|
121
|
-
options[:
|
122
|
-
|
123
|
-
set :host, options[:host_name] || instance_id
|
151
|
+
set :host, options[:host_name]# || instance_name
|
124
152
|
set :ssh_options, options
|
125
153
|
|
154
|
+
set :request_pty, true
|
126
155
|
# Disable sudo
|
127
156
|
# set :disable_sudo, true
|
128
157
|
|
@@ -132,3 +161,5 @@ set :ssh_options, options
|
|
132
161
|
|
133
162
|
# Set PATH
|
134
163
|
# set :path, '/sbin:/usr/local/sbin:$PATH'
|
164
|
+
|
165
|
+
|
data/spec/support/utils.rb
CHANGED