aws-must-templates 0.1.6 → 0.2.1
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 +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