ami_spec 1.1.0 → 1.7.0
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 +72 -27
- data/bin/ami_spec +0 -1
- data/lib/ami_spec.rb +87 -30
- data/lib/ami_spec/aws_default_vpc.rb +10 -0
- data/lib/ami_spec/aws_instance.rb +7 -2
- data/lib/ami_spec/aws_key_pair.rb +36 -0
- data/lib/ami_spec/aws_security_group.rb +72 -0
- data/lib/ami_spec/server_spec.rb +6 -2
- data/lib/ami_spec/version.rb +1 -1
- data/lib/ami_spec/wait_for_cloud_init.rb +11 -0
- data/lib/ami_spec/wait_for_rc.rb +1 -1
- data/lib/ami_spec/wait_for_ssh.rb +2 -2
- metadata +29 -60
- data/.gitignore +0 -2
- data/.ruby-version +0 -1
- data/.travis.yml +0 -6
- data/Gemfile +0 -3
- data/Rakefile +0 -8
- data/ami_spec.gemspec +0 -27
- data/spec/ami_spec_spec.rb +0 -74
- data/spec/aws_instance_spec.rb +0 -142
- data/spec/containers/Dockerfile.amazon_linux +0 -9
- data/spec/containers/Dockerfile.trusty +0 -8
- data/spec/containers/Dockerfile.xenial +0 -22
- data/spec/containers/README.md +0 -5
- data/spec/containers/ami-spec +0 -27
- data/spec/containers/ami-spec.pub +0 -1
- data/spec/containers/docker-compose.yml +0 -28
- data/spec/containers/rc.conf +0 -17
- data/spec/containers/sshd_config +0 -17
- data/spec/spec_helper.rb +0 -2
- data/spec/wait_for_rc_spec.rb +0 -25
- data/spec/wait_for_ssh_spec.rb +0 -39
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 718f947b58e6bedd2093507f23b7bcc1c8deae4503dde3603c6768700729948a
|
4
|
+
data.tar.gz: b8c05a3702f5951932d372f6c3788a2ee71f9d0ead934a4bdfb52cae382bbe70
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a2ceb57cf5b2ea84f085a835e47e1533065338479c23bf3da88ff962d5c046c6109f2c0b93461ac4c1d5093a14bc7d522e4c154d1f34225ef3813ebd70f6ecda
|
7
|
+
data.tar.gz: ca6403909f96efb50c412ed722e6449b51ea147677f10d2e7729e31d02adc8ae82561eeaf2bbe054ab774bdf9086fe7b690254512f590c49d977920f99e2f371
|
data/README.md
CHANGED
@@ -1,5 +1,9 @@
|
|
1
1
|
# AmiSpec
|
2
2
|
|
3
|
+
[](https://github.com/envato/ami-spec/blob/master/LICENSE.txt)
|
4
|
+
[](https://badge.fury.io/rb/ami_spec)
|
5
|
+
[](https://github.com/envato/ami-spec/actions?query=branch%3Amaster+workflow%3Atests)
|
6
|
+
|
3
7
|
Acceptance testing your AMIs.
|
4
8
|
|
5
9
|
AmiSpec is a RubyGem used to launch an Amazon Machine Image (AMI) and run ServerSpecs against it. It wraps around the AWS API and ServerSpec to spin up, test and tear down instances.
|
@@ -29,33 +33,39 @@ Run `bundle install`
|
|
29
33
|
```cli
|
30
34
|
$ bundle exec ami_spec --help
|
31
35
|
Options:
|
32
|
-
-r, --role=<s>
|
33
|
-
|
34
|
-
-a, --ami=<s>
|
35
|
-
-o, --role-ami-file=<s>
|
36
|
-
|
37
|
-
-s, --specs=<s>
|
38
|
-
-u, --subnet-id=<s>
|
39
|
-
|
40
|
-
-
|
41
|
-
|
42
|
-
-
|
43
|
-
|
44
|
-
-
|
45
|
-
|
46
|
-
-
|
47
|
-
|
48
|
-
-
|
49
|
-
|
50
|
-
|
51
|
-
-
|
52
|
-
|
53
|
-
-
|
54
|
-
-
|
55
|
-
|
56
|
-
-
|
57
|
-
|
58
|
-
--
|
36
|
+
-r, --role=<s> The role to test, this should map to a directory in the spec
|
37
|
+
folder
|
38
|
+
-a, --ami=<s> The ami ID to run tests against
|
39
|
+
-o, --role-ami-file=<s> A file containing comma separated roles and amis. i.e.
|
40
|
+
web_server,ami-id.
|
41
|
+
-s, --specs=<s> The directory to find ServerSpecs
|
42
|
+
-u, --subnet-id=<s> The subnet to start the instance in. If not provided a subnet
|
43
|
+
will be chosen from the default VPC
|
44
|
+
-k, --key-name=<s> The SSH key name to assign to instances. If not provided a
|
45
|
+
temporary key pair will be generated in AWS
|
46
|
+
-e, --key-file=<s> The SSH private key file associated to the key_name
|
47
|
+
-h, --ssh-user=<s> The user to ssh to the instance as
|
48
|
+
-w, --aws-region=<s> The AWS region, defaults to AWS_DEFAULT_REGION environment
|
49
|
+
variable
|
50
|
+
-i, --aws-instance-type=<s> The ec2 instance type, defaults to t2.micro (default:
|
51
|
+
t2.micro)
|
52
|
+
-c, --aws-security-groups=<s> Security groups IDs to associate to the launched instances. May be
|
53
|
+
specified multiple times. If not provided a temporary security
|
54
|
+
group will be generated in AWS
|
55
|
+
-n, --allow-any-temporary-security-group The temporary security group will allow SSH connections
|
56
|
+
from any IP address (0.0.0.0/0), otherwise allow the subnet's block
|
57
|
+
-p, --aws-public-ip Launch instances with a public IP
|
58
|
+
-t, --ssh-retries=<i> The number of times we should try sshing to the ec2 instance
|
59
|
+
before giving up. Defaults to 30 (default: 30)
|
60
|
+
-g, --tags=<s> Additional tags to add to launched instances in the form of
|
61
|
+
comma separated key=value pairs. i.e. Name=AmiSpec (default: )
|
62
|
+
-d, --debug Don't terminate instances on exit
|
63
|
+
-b, --buildkite Output section separators for buildkite
|
64
|
+
-f, --wait-for-rc Wait for oldschool SystemV scripts to run before conducting
|
65
|
+
tests. Currently only supports Ubuntu with upstart
|
66
|
+
-l, --user-data-file=<s> File path for aws ec2 user data
|
67
|
+
-m, --iam-instance-profile-arn=<s> IAM instance profile to use
|
68
|
+
--help Show this message
|
59
69
|
|
60
70
|
```
|
61
71
|
|
@@ -65,6 +75,41 @@ When the instances becomes reachable it will run all Specs inside the role spec
|
|
65
75
|
|
66
76
|
Alternative to the `--ami` and `--role` variables, a file of comma separated roles and AMIs (`ROLE,AMI\n`) can be supplied to `--role-ami-file`.
|
67
77
|
|
78
|
+
## ServerSpec test layout
|
79
|
+
|
80
|
+
AmiSpec expects the usual ServerSpec configuration layout as generated by "serverspec-init":
|
81
|
+
|
82
|
+
spec/
|
83
|
+
├── webserver
|
84
|
+
│ └── webserver_spec.rb
|
85
|
+
└── spec_helper.rb
|
86
|
+
|
87
|
+
The \*\_spec.rb files under the role (e.g. webserver) contain the ServerSpec
|
88
|
+
tests that you want to run. The spec_helper.rb file can be very simple:
|
89
|
+
|
90
|
+
require 'serverspec'
|
91
|
+
|
92
|
+
set :backend, :ssh
|
93
|
+
|
94
|
+
Note that the backend *needs* to be :ssh or ami_spec might run the tests on
|
95
|
+
your local machine, not in EC2.
|
96
|
+
|
97
|
+
## Example usage
|
98
|
+
|
99
|
+
To test a custom AMI using a pre-created security group that allows SSH from anywhere:
|
100
|
+
|
101
|
+
```cli
|
102
|
+
ami_spec --role webserver\
|
103
|
+
--specs spec\
|
104
|
+
--aws-region us-east-1\
|
105
|
+
--ami ami-0123456789abcdef0\
|
106
|
+
--key-name default\
|
107
|
+
--key-file ~/.ssh/default.pem\
|
108
|
+
--ssh-user ubuntu\
|
109
|
+
--aws-public-ip\
|
110
|
+
--aws-security-groups sg-0123456789abcdef0
|
111
|
+
```
|
112
|
+
|
68
113
|
## Known caveats
|
69
114
|
|
70
115
|
### RSpec conditions in examples
|
data/bin/ami_spec
CHANGED
data/lib/ami_spec.rb
CHANGED
@@ -1,10 +1,15 @@
|
|
1
1
|
require 'ami_spec/aws_instance'
|
2
2
|
require 'ami_spec/aws_instance_options'
|
3
|
+
require 'ami_spec/aws_default_vpc'
|
4
|
+
require 'ami_spec/aws_key_pair'
|
5
|
+
require 'ami_spec/aws_security_group'
|
3
6
|
require 'ami_spec/server_spec'
|
4
7
|
require 'ami_spec/server_spec_options'
|
5
8
|
require 'ami_spec/wait_for_ssh'
|
6
9
|
require 'ami_spec/wait_for_rc'
|
7
|
-
require '
|
10
|
+
require 'ami_spec/wait_for_cloud_init'
|
11
|
+
require 'optimist'
|
12
|
+
require 'logger'
|
8
13
|
|
9
14
|
module AmiSpec
|
10
15
|
class InstanceConnectionTimeout < StandardError; end
|
@@ -19,7 +24,7 @@ module AmiSpec
|
|
19
24
|
# subnet_id::
|
20
25
|
# The subnet_id to start instances in.
|
21
26
|
# key_name::
|
22
|
-
# The SSH key name to assign to instances.
|
27
|
+
# The SSH key name to assign to instances. If not provided a temporary key pair will be generated in AWS
|
23
28
|
# key_file::
|
24
29
|
# The SSH key file to use to connect to the host.
|
25
30
|
# aws_region::
|
@@ -27,7 +32,9 @@ module AmiSpec
|
|
27
32
|
# Defaults to AWS_DEFAULT_REGION
|
28
33
|
# aws_security_group_ids::
|
29
34
|
# AWS Security groups to assign to the instances
|
30
|
-
#
|
35
|
+
# If not provided a temporary security group will be generated in AWS
|
36
|
+
# allow_any_temporary_security_group::
|
37
|
+
# The temporary security group will allow SSH connections from any IP address (0.0.0.0/0)
|
31
38
|
# aws_instance_type::
|
32
39
|
# AWS ec2 instance type
|
33
40
|
# aws_public_ip::
|
@@ -45,6 +52,33 @@ module AmiSpec
|
|
45
52
|
# == Returns:
|
46
53
|
# Boolean - The result of all the server specs.
|
47
54
|
def self.run(options)
|
55
|
+
logger = Logger.new(STDOUT, formatter: proc { |_sev, _time, _name, message| "#{message}\n" })
|
56
|
+
|
57
|
+
ec2 = Aws::EC2::Resource.new(options[:aws_region] ? {region: options[:aws_region]} : {})
|
58
|
+
|
59
|
+
if options[:subnet_id].nil?
|
60
|
+
default_vpc_subnet = AwsDefaultVpc.find_subnet(ec2: ec2)
|
61
|
+
raise 'No default VPC subnet found. Please specify a subnet id.' if default_vpc_subnet.nil?
|
62
|
+
options[:subnet_id] = default_vpc_subnet.id
|
63
|
+
logger.info("Using subnet #{options[:subnet_id]} from the default VPC")
|
64
|
+
end
|
65
|
+
|
66
|
+
unless options[:key_name]
|
67
|
+
key_pair = AwsKeyPair.create(ec2: ec2, logger: logger)
|
68
|
+
options[:key_name] = key_pair.key_name
|
69
|
+
options[:key_file] = key_pair.key_file
|
70
|
+
end
|
71
|
+
|
72
|
+
if options[:aws_security_groups].nil? || options[:aws_security_groups].empty?
|
73
|
+
temporary_security_group = AwsSecurityGroup.create(
|
74
|
+
ec2: ec2,
|
75
|
+
subnet_id: options[:subnet_id],
|
76
|
+
allow_any_ip: options[:allow_any_temporary_security_group],
|
77
|
+
logger: logger
|
78
|
+
)
|
79
|
+
options[:aws_security_groups] = [temporary_security_group.group_id]
|
80
|
+
end
|
81
|
+
|
48
82
|
instances = []
|
49
83
|
options[:amis].each_pair do |role, ami|
|
50
84
|
aws_instance_options = AwsInstanceOptions.new(options.merge(role: role, ami: ami))
|
@@ -56,6 +90,7 @@ module AmiSpec
|
|
56
90
|
ip_address = options[:aws_public_ip] ? instance.public_ip_address : instance.private_ip_address
|
57
91
|
WaitForSSH.wait(ip_address, options[:ssh_user], options[:key_file], options[:ssh_retries])
|
58
92
|
WaitForRC.wait(ip_address, options[:ssh_user], options[:key_file]) if options[:wait_for_rc]
|
93
|
+
WaitForCloudInit.wait(ip_address, options[:ssh_user], options[:key_file]) if options[:wait_for_cloud_init]
|
59
94
|
|
60
95
|
server_spec_options = ServerSpecOptions.new(options.merge(instance: instance))
|
61
96
|
results << ServerSpec.new(server_spec_options).run
|
@@ -64,10 +99,12 @@ module AmiSpec
|
|
64
99
|
results.all?
|
65
100
|
ensure
|
66
101
|
stop_instances(instances, options[:debug])
|
102
|
+
key_pair.delete if key_pair
|
103
|
+
temporary_security_group.delete if temporary_security_group
|
67
104
|
end
|
68
105
|
|
69
106
|
def self.stop_instances(instances, debug)
|
70
|
-
instances.each do |instance|
|
107
|
+
instances && instances.each do |instance|
|
71
108
|
begin
|
72
109
|
if debug
|
73
110
|
puts "EC2 instance ##{instance.instance_id} has not been stopped due to debug mode."
|
@@ -83,29 +120,45 @@ module AmiSpec
|
|
83
120
|
private_class_method :stop_instances
|
84
121
|
|
85
122
|
def self.invoke
|
86
|
-
options =
|
87
|
-
opt :role,
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
opt :
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
opt :
|
96
|
-
|
97
|
-
opt :
|
98
|
-
|
99
|
-
type: :
|
100
|
-
opt :
|
101
|
-
|
102
|
-
|
103
|
-
opt :
|
104
|
-
opt :
|
105
|
-
|
106
|
-
opt :
|
107
|
-
|
108
|
-
opt :
|
123
|
+
options = Optimist::options do
|
124
|
+
opt :role,
|
125
|
+
'The role to test, this should map to a directory in the spec folder',
|
126
|
+
type: :string, short: :r
|
127
|
+
opt :ami, 'The ami ID to run tests against', type: :string, short: :a
|
128
|
+
opt :role_ami_file,
|
129
|
+
'A file containing comma separated roles and amis. i.e.
|
130
|
+
web_server,ami-id.',
|
131
|
+
type: :string, short: :o
|
132
|
+
opt :specs, 'The directory to find ServerSpecs',
|
133
|
+
type: :string, required: true, short: :s
|
134
|
+
opt :subnet_id,
|
135
|
+
'The subnet to start the instance in. If not provided a subnet will be chosen from the default VPC',
|
136
|
+
type: :string, short: :u
|
137
|
+
opt :key_name, 'The SSH key name to assign to instances. If not provided a temporary key pair will be generated in AWS',
|
138
|
+
type: :string, short: :k
|
139
|
+
opt :key_file, 'The SSH private key file associated to the key_name', type: :string, short: :e
|
140
|
+
opt :ssh_user, 'The user to ssh to the instance as', type: :string, required: true, short: :h
|
141
|
+
opt :aws_region, 'The AWS region, defaults to AWS_DEFAULT_REGION environment variable',
|
142
|
+
type: :string, short: :w
|
143
|
+
opt :aws_instance_type, 'The ec2 instance type, defaults to t2.micro',
|
144
|
+
type: :string, default: 't2.micro', short: :i
|
145
|
+
opt :aws_security_groups,
|
146
|
+
'Security groups to associate to the launched instances. May be specified multiple times. If not provided a temporary security group will be generated in AWS',
|
147
|
+
type: :string, default: nil, multi: true, short: :c
|
148
|
+
opt :allow_any_temporary_security_group, 'The temporary security group will allow SSH connections from any IP address (0.0.0.0/0)',
|
149
|
+
short: :n
|
150
|
+
opt :aws_public_ip, 'Launch instances with a public IP', short: :p
|
151
|
+
opt :ssh_retries, 'The number of times we should try sshing to the ec2 instance before giving up. Defaults to 30',
|
152
|
+
type: :int, default: 30, short: :t
|
153
|
+
opt :tags, 'Additional tags to add to launched instances in the form of comma separated key=value pairs. i.e. Name=AmiSpec',
|
154
|
+
type: :string, default: '', short: :g
|
155
|
+
opt :debug, "Don't terminate instances on exit", short: :d
|
156
|
+
opt :buildkite, 'Output section separators for buildkite', short: :b
|
157
|
+
opt :wait_for_rc, 'Wait for oldschool SystemV scripts to run before conducting tests. Currently only supports Ubuntu with upstart',
|
158
|
+
short: :f
|
159
|
+
opt :wait_for_cloud_init, 'Wait for Cloud Init to complete before running tests'
|
160
|
+
opt :user_data_file, 'File path for aws ec2 user data', type: :string, default: nil, short: :l
|
161
|
+
opt :iam_instance_profile_arn, 'IAM instance profile to use', type: :string, short: :m
|
109
162
|
end
|
110
163
|
|
111
164
|
if options[:role] && options[:ami]
|
@@ -121,9 +174,7 @@ module AmiSpec
|
|
121
174
|
fail "You must specify either role and ami or role_ami_file"
|
122
175
|
end
|
123
176
|
|
124
|
-
|
125
|
-
fail "Key file #{options[:key_file]} not found"
|
126
|
-
end
|
177
|
+
fail "Key file #{options[:key_file]} not found" if options[:key_name] && !File.exist?(options.fetch(:key_file))
|
127
178
|
|
128
179
|
if options[:user_data_file] and !File.exist? options[:user_data_file]
|
129
180
|
fail "User Data file #{options[:user_data_file]} not found"
|
@@ -131,6 +182,12 @@ module AmiSpec
|
|
131
182
|
|
132
183
|
options[:tags] = parse_tags(options[:tags])
|
133
184
|
|
185
|
+
options[:amis].each_pair do |role, _|
|
186
|
+
unless Dir.exist?("#{options[:specs]}/#{role}")
|
187
|
+
fail "Role directory #{options[:specs]}/#{role} does not exist. If you'd like to skip the role '#{role}', create the directory but leave it empty (except for a .gitignore file)."
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
134
191
|
exit run(options)
|
135
192
|
end
|
136
193
|
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require 'aws-sdk'
|
1
|
+
require 'aws-sdk-ec2'
|
2
2
|
require 'forwardable'
|
3
3
|
require 'base64'
|
4
4
|
|
@@ -26,7 +26,7 @@ module AmiSpec
|
|
26
26
|
@iam_instance_profile_arn = options.fetch(:iam_instance_profile_arn, nil)
|
27
27
|
end
|
28
28
|
|
29
|
-
def_delegators :@instance, :instance_id, :tags, :
|
29
|
+
def_delegators :@instance, :instance_id, :tags, :private_ip_address, :public_ip_address
|
30
30
|
|
31
31
|
def start
|
32
32
|
client = Aws::EC2::Client.new(client_options)
|
@@ -37,6 +37,11 @@ module AmiSpec
|
|
37
37
|
tag_instance
|
38
38
|
end
|
39
39
|
|
40
|
+
def terminate
|
41
|
+
@instance.terminate
|
42
|
+
@instance.wait_until_terminated
|
43
|
+
end
|
44
|
+
|
40
45
|
private
|
41
46
|
|
42
47
|
def client_options
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'aws-sdk-ec2'
|
2
|
+
require 'logger'
|
3
|
+
require 'securerandom'
|
4
|
+
require 'tempfile'
|
5
|
+
require 'pathname'
|
6
|
+
|
7
|
+
module AmiSpec
|
8
|
+
class AwsKeyPair
|
9
|
+
|
10
|
+
def self.create(**args)
|
11
|
+
new(**args).tap(&:create)
|
12
|
+
end
|
13
|
+
|
14
|
+
def initialize(ec2: Aws::EC2::Resource.new, key_name_prefix: 'ami-spec-', logger: Logger.new(STDOUT))
|
15
|
+
@ec2 = ec2
|
16
|
+
@key_name = "#{key_name_prefix}#{SecureRandom.uuid}"
|
17
|
+
@logger = logger
|
18
|
+
end
|
19
|
+
|
20
|
+
attr_reader :key_name, :key_file
|
21
|
+
|
22
|
+
def create
|
23
|
+
@logger.info "Creating temporary AWS key pair: #{@key_name}"
|
24
|
+
@key_pair = @ec2.create_key_pair(key_name: @key_name)
|
25
|
+
@temp_file = Tempfile.new('key')
|
26
|
+
@temp_file.write(@key_pair.key_material)
|
27
|
+
@temp_file.close
|
28
|
+
@key_file = Pathname.new(@temp_file.path)
|
29
|
+
end
|
30
|
+
|
31
|
+
def delete
|
32
|
+
@logger.info "Deleting temporary AWS key pair: #{@key_name}"
|
33
|
+
@key_pair.delete
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
require 'aws-sdk-ec2'
|
2
|
+
require 'forwardable'
|
3
|
+
require 'securerandom'
|
4
|
+
|
5
|
+
module AmiSpec
|
6
|
+
class AwsSecurityGroup
|
7
|
+
extend Forwardable
|
8
|
+
|
9
|
+
def self.create(**args)
|
10
|
+
new(**args).tap(&:create)
|
11
|
+
end
|
12
|
+
|
13
|
+
def initialize(ec2: Aws::EC2::Resource.new,
|
14
|
+
group_name_prefix: "ami-spec-",
|
15
|
+
connection_port: 22,
|
16
|
+
subnet_id:,
|
17
|
+
allow_any_ip: false,
|
18
|
+
logger: Logger.new(STDOUT))
|
19
|
+
@ec2 = ec2
|
20
|
+
@group_name = "#{group_name_prefix}#{SecureRandom.uuid}"
|
21
|
+
@connection_port = connection_port
|
22
|
+
@subnet_id = subnet_id
|
23
|
+
@allow_any_ip = allow_any_ip
|
24
|
+
@logger = logger
|
25
|
+
end
|
26
|
+
|
27
|
+
def_delegators :@security_group, :group_id
|
28
|
+
attr_reader :group_name
|
29
|
+
|
30
|
+
def create
|
31
|
+
@logger.info "Creating temporary AWS security group: #{@group_name}"
|
32
|
+
create_security_group
|
33
|
+
allow_ingress_via_connection_port
|
34
|
+
end
|
35
|
+
|
36
|
+
def delete
|
37
|
+
@logger.info "Deleting temporary AWS security group: #{@group_name}"
|
38
|
+
@security_group.delete
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
def create_security_group
|
44
|
+
@security_group = @ec2.create_security_group(
|
45
|
+
group_name: @group_name,
|
46
|
+
description: "A temporary security group for running AmiSpec",
|
47
|
+
vpc_id: subnet.vpc_id,
|
48
|
+
)
|
49
|
+
end
|
50
|
+
|
51
|
+
def allow_ingress_via_connection_port
|
52
|
+
@security_group.authorize_ingress(
|
53
|
+
ip_permissions: [
|
54
|
+
{
|
55
|
+
ip_protocol: "tcp",
|
56
|
+
from_port: @connection_port,
|
57
|
+
to_port: @connection_port,
|
58
|
+
ip_ranges: [{cidr_ip: cidr_block}],
|
59
|
+
},
|
60
|
+
],
|
61
|
+
)
|
62
|
+
end
|
63
|
+
|
64
|
+
def cidr_block
|
65
|
+
@allow_any_ip ? "0.0.0.0/0" : subnet.cidr_block
|
66
|
+
end
|
67
|
+
|
68
|
+
def subnet
|
69
|
+
@subnet ||= @ec2.subnet(@subnet_id)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
data/lib/ami_spec/server_spec.rb
CHANGED
@@ -28,11 +28,15 @@ module AmiSpec
|
|
28
28
|
end
|
29
29
|
|
30
30
|
$LOAD_PATH.unshift(@spec) unless $LOAD_PATH.include?(@spec)
|
31
|
-
|
31
|
+
begin
|
32
|
+
require File.join(@spec, 'spec_helper')
|
33
|
+
rescue LoadError
|
34
|
+
puts 'Spec Helper does not exist. Skipping!'
|
35
|
+
end
|
32
36
|
|
33
37
|
set :backend, :ssh
|
34
38
|
set :host, @ip
|
35
|
-
set :ssh_options, :user => @user, :keys => [@key_file], :
|
39
|
+
set :ssh_options, :user => @user, :keys => [@key_file], :verify_host_key => :never
|
36
40
|
|
37
41
|
RSpec.configuration.fail_fast = true if @debug
|
38
42
|
|
data/lib/ami_spec/version.rb
CHANGED
@@ -0,0 +1,11 @@
|
|
1
|
+
require 'net/ssh'
|
2
|
+
|
3
|
+
module AmiSpec
|
4
|
+
class WaitForCloudInit
|
5
|
+
def self.wait(ip_address, user, key, port=22)
|
6
|
+
Net::SSH.start(ip_address, user, keys: [key], :verify_host_key => :never, port: port) do |ssh|
|
7
|
+
ssh.exec! '/usr/bin/cloud-init status --wait'
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
data/lib/ami_spec/wait_for_rc.rb
CHANGED
@@ -3,7 +3,7 @@ require 'net/ssh'
|
|
3
3
|
module AmiSpec
|
4
4
|
class WaitForRC
|
5
5
|
def self.wait(ip_address, user, key, port=22)
|
6
|
-
Net::SSH.start(ip_address, user, keys: [key],
|
6
|
+
Net::SSH.start(ip_address, user, keys: [key], :verify_host_key => :never, port: port) do |ssh|
|
7
7
|
distrib_stdout = ""
|
8
8
|
# Determine the OS family
|
9
9
|
ssh.exec!("source /etc/*release && echo -n $DISTRIB_ID && echo -n $ID") do |channel, stream, data|
|
@@ -8,8 +8,8 @@ module AmiSpec
|
|
8
8
|
|
9
9
|
while retries < max_retries
|
10
10
|
begin
|
11
|
-
Net::SSH.start(ip_address, user, keys: [key],
|
12
|
-
rescue Errno::ETIMEDOUT, Errno::ECONNREFUSED, Timeout::Error => error
|
11
|
+
Net::SSH.start(ip_address, user, keys: [key], :verify_host_key => :never) { |ssh| ssh.exec 'echo boo!' }
|
12
|
+
rescue Errno::ETIMEDOUT, Errno::ECONNREFUSED, Timeout::Error, Net::SSH::Exception => error
|
13
13
|
last_error = error
|
14
14
|
sleep 1
|
15
15
|
else
|
metadata
CHANGED
@@ -1,30 +1,30 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ami_spec
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.7.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Patrick Robinson
|
8
8
|
- Martin Jagusch
|
9
|
-
autorequire:
|
9
|
+
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2021-07-01 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
|
-
name: aws-sdk
|
15
|
+
name: aws-sdk-ec2
|
16
16
|
requirement: !ruby/object:Gem::Requirement
|
17
17
|
requirements:
|
18
18
|
- - "~>"
|
19
19
|
- !ruby/object:Gem::Version
|
20
|
-
version: '
|
20
|
+
version: '1'
|
21
21
|
type: :runtime
|
22
22
|
prerelease: false
|
23
23
|
version_requirements: !ruby/object:Gem::Requirement
|
24
24
|
requirements:
|
25
25
|
- - "~>"
|
26
26
|
- !ruby/object:Gem::Version
|
27
|
-
version: '
|
27
|
+
version: '1'
|
28
28
|
- !ruby/object:Gem::Dependency
|
29
29
|
name: rake
|
30
30
|
requirement: !ruby/object:Gem::Requirement
|
@@ -32,7 +32,7 @@ dependencies:
|
|
32
32
|
- - ">="
|
33
33
|
- !ruby/object:Gem::Version
|
34
34
|
version: '0'
|
35
|
-
type: :
|
35
|
+
type: :development
|
36
36
|
prerelease: false
|
37
37
|
version_requirements: !ruby/object:Gem::Requirement
|
38
38
|
requirements:
|
@@ -43,16 +43,16 @@ dependencies:
|
|
43
43
|
name: serverspec
|
44
44
|
requirement: !ruby/object:Gem::Requirement
|
45
45
|
requirements:
|
46
|
-
- - "
|
46
|
+
- - "~>"
|
47
47
|
- !ruby/object:Gem::Version
|
48
|
-
version: '
|
48
|
+
version: '2'
|
49
49
|
type: :runtime
|
50
50
|
prerelease: false
|
51
51
|
version_requirements: !ruby/object:Gem::Requirement
|
52
52
|
requirements:
|
53
|
-
- - "
|
53
|
+
- - "~>"
|
54
54
|
- !ruby/object:Gem::Version
|
55
|
-
version: '
|
55
|
+
version: '2'
|
56
56
|
- !ruby/object:Gem::Dependency
|
57
57
|
name: specinfra
|
58
58
|
requirement: !ruby/object:Gem::Requirement
|
@@ -68,19 +68,19 @@ dependencies:
|
|
68
68
|
- !ruby/object:Gem::Version
|
69
69
|
version: '2.45'
|
70
70
|
- !ruby/object:Gem::Dependency
|
71
|
-
name:
|
71
|
+
name: optimist
|
72
72
|
requirement: !ruby/object:Gem::Requirement
|
73
73
|
requirements:
|
74
|
-
- - "
|
74
|
+
- - "~>"
|
75
75
|
- !ruby/object:Gem::Version
|
76
|
-
version: '
|
76
|
+
version: '3'
|
77
77
|
type: :runtime
|
78
78
|
prerelease: false
|
79
79
|
version_requirements: !ruby/object:Gem::Requirement
|
80
80
|
requirements:
|
81
|
-
- - "
|
81
|
+
- - "~>"
|
82
82
|
- !ruby/object:Gem::Version
|
83
|
-
version: '
|
83
|
+
version: '3'
|
84
84
|
- !ruby/object:Gem::Dependency
|
85
85
|
name: hashie
|
86
86
|
requirement: !ruby/object:Gem::Requirement
|
@@ -99,16 +99,16 @@ dependencies:
|
|
99
99
|
name: net-ssh
|
100
100
|
requirement: !ruby/object:Gem::Requirement
|
101
101
|
requirements:
|
102
|
-
- - "
|
102
|
+
- - "~>"
|
103
103
|
- !ruby/object:Gem::Version
|
104
|
-
version: '
|
104
|
+
version: '5'
|
105
105
|
type: :runtime
|
106
106
|
prerelease: false
|
107
107
|
version_requirements: !ruby/object:Gem::Requirement
|
108
108
|
requirements:
|
109
|
-
- - "
|
109
|
+
- - "~>"
|
110
110
|
- !ruby/object:Gem::Version
|
111
|
-
version: '
|
111
|
+
version: '5'
|
112
112
|
description: Acceptance testing your AMIs
|
113
113
|
email: []
|
114
114
|
executables:
|
@@ -116,41 +116,25 @@ executables:
|
|
116
116
|
extensions: []
|
117
117
|
extra_rdoc_files: []
|
118
118
|
files:
|
119
|
-
- ".gitignore"
|
120
|
-
- ".ruby-version"
|
121
|
-
- ".travis.yml"
|
122
|
-
- Gemfile
|
123
119
|
- LICENSE.txt
|
124
120
|
- README.md
|
125
|
-
- Rakefile
|
126
|
-
- ami_spec.gemspec
|
127
121
|
- bin/ami_spec
|
128
122
|
- lib/ami_spec.rb
|
123
|
+
- lib/ami_spec/aws_default_vpc.rb
|
129
124
|
- lib/ami_spec/aws_instance.rb
|
130
125
|
- lib/ami_spec/aws_instance_options.rb
|
126
|
+
- lib/ami_spec/aws_key_pair.rb
|
127
|
+
- lib/ami_spec/aws_security_group.rb
|
131
128
|
- lib/ami_spec/server_spec.rb
|
132
129
|
- lib/ami_spec/server_spec_options.rb
|
133
130
|
- lib/ami_spec/version.rb
|
131
|
+
- lib/ami_spec/wait_for_cloud_init.rb
|
134
132
|
- lib/ami_spec/wait_for_rc.rb
|
135
133
|
- lib/ami_spec/wait_for_ssh.rb
|
136
|
-
- spec/ami_spec_spec.rb
|
137
|
-
- spec/aws_instance_spec.rb
|
138
|
-
- spec/containers/Dockerfile.amazon_linux
|
139
|
-
- spec/containers/Dockerfile.trusty
|
140
|
-
- spec/containers/Dockerfile.xenial
|
141
|
-
- spec/containers/README.md
|
142
|
-
- spec/containers/ami-spec
|
143
|
-
- spec/containers/ami-spec.pub
|
144
|
-
- spec/containers/docker-compose.yml
|
145
|
-
- spec/containers/rc.conf
|
146
|
-
- spec/containers/sshd_config
|
147
|
-
- spec/spec_helper.rb
|
148
|
-
- spec/wait_for_rc_spec.rb
|
149
|
-
- spec/wait_for_ssh_spec.rb
|
150
134
|
homepage: https://github.com/envato/ami-spec
|
151
135
|
licenses: []
|
152
136
|
metadata: {}
|
153
|
-
post_install_message:
|
137
|
+
post_install_message:
|
154
138
|
rdoc_options: []
|
155
139
|
require_paths:
|
156
140
|
- lib
|
@@ -158,30 +142,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
158
142
|
requirements:
|
159
143
|
- - ">="
|
160
144
|
- !ruby/object:Gem::Version
|
161
|
-
version:
|
145
|
+
version: 2.2.6
|
162
146
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
163
147
|
requirements:
|
164
148
|
- - ">="
|
165
149
|
- !ruby/object:Gem::Version
|
166
150
|
version: '0'
|
167
151
|
requirements: []
|
168
|
-
|
169
|
-
|
170
|
-
signing_key:
|
152
|
+
rubygems_version: 3.0.4
|
153
|
+
signing_key:
|
171
154
|
specification_version: 4
|
172
155
|
summary: Acceptance testing your AMIs
|
173
|
-
test_files:
|
174
|
-
- spec/ami_spec_spec.rb
|
175
|
-
- spec/aws_instance_spec.rb
|
176
|
-
- spec/containers/Dockerfile.amazon_linux
|
177
|
-
- spec/containers/Dockerfile.trusty
|
178
|
-
- spec/containers/Dockerfile.xenial
|
179
|
-
- spec/containers/README.md
|
180
|
-
- spec/containers/ami-spec
|
181
|
-
- spec/containers/ami-spec.pub
|
182
|
-
- spec/containers/docker-compose.yml
|
183
|
-
- spec/containers/rc.conf
|
184
|
-
- spec/containers/sshd_config
|
185
|
-
- spec/spec_helper.rb
|
186
|
-
- spec/wait_for_rc_spec.rb
|
187
|
-
- spec/wait_for_ssh_spec.rb
|
156
|
+
test_files: []
|
data/.gitignore
DELETED
data/.ruby-version
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
1.9.3-p551
|
data/.travis.yml
DELETED
data/Gemfile
DELETED
data/Rakefile
DELETED
data/ami_spec.gemspec
DELETED
@@ -1,27 +0,0 @@
|
|
1
|
-
lib = File.expand_path('../lib', __FILE__)
|
2
|
-
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
3
|
-
|
4
|
-
require 'ami_spec/version'
|
5
|
-
|
6
|
-
Gem::Specification.new do |gem|
|
7
|
-
gem.name = 'ami_spec'
|
8
|
-
gem.version = AmiSpec::VERSION
|
9
|
-
gem.authors = ['Patrick Robinson', 'Martin Jagusch']
|
10
|
-
gem.email = []
|
11
|
-
gem.description = 'Acceptance testing your AMIs'
|
12
|
-
gem.summary = gem.description
|
13
|
-
gem.homepage = 'https://github.com/envato/ami-spec'
|
14
|
-
|
15
|
-
gem.files = `git ls-files`.split($/)
|
16
|
-
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
17
|
-
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
18
|
-
gem.require_paths = ['lib']
|
19
|
-
|
20
|
-
gem.add_dependency 'aws-sdk', '~> 2'
|
21
|
-
gem.add_dependency 'rake'
|
22
|
-
gem.add_dependency 'serverspec'
|
23
|
-
gem.add_dependency 'specinfra', '>= 2.45'
|
24
|
-
gem.add_dependency 'trollop'
|
25
|
-
gem.add_dependency 'hashie'
|
26
|
-
gem.add_dependency 'net-ssh', '< 3.0'
|
27
|
-
end
|
data/spec/ami_spec_spec.rb
DELETED
@@ -1,74 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe AmiSpec do
|
4
|
-
let(:amis) { {'web_server' => 'ami-1234abcd', 'db_server' => 'ami-1234abcd'} }
|
5
|
-
let(:ec2_double) { instance_double(AmiSpec::AwsInstance) }
|
6
|
-
let(:state) { double(name: 'running') }
|
7
|
-
let(:test_result) { true }
|
8
|
-
let(:server_spec_double) { double(run: test_result) }
|
9
|
-
subject do
|
10
|
-
described_class.run(
|
11
|
-
amis: amis,
|
12
|
-
specs: '/tmp/foobar',
|
13
|
-
subnet_id: 'subnet-1234abcd',
|
14
|
-
key_name: 'key',
|
15
|
-
key_file: 'key.pem',
|
16
|
-
aws_public_ip: false,
|
17
|
-
aws_instance_type: 't2.micro',
|
18
|
-
ssh_user: 'ubuntu',
|
19
|
-
debug: false,
|
20
|
-
ssh_retries: 30,
|
21
|
-
)
|
22
|
-
end
|
23
|
-
|
24
|
-
describe '#invoke' do
|
25
|
-
it 'raises a system exit with no arguments' do
|
26
|
-
expect{ described_class.invoke }.to raise_error(SystemExit)
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
describe '#run' do
|
31
|
-
before do
|
32
|
-
allow(AmiSpec::WaitForSSH).to receive(:wait).and_return(true)
|
33
|
-
allow(AmiSpec::AwsInstance).to receive(:start).and_return(ec2_double)
|
34
|
-
allow(AmiSpec::ServerSpec).to receive(:new).and_return(server_spec_double)
|
35
|
-
allow(ec2_double).to receive(:terminate).and_return(true)
|
36
|
-
allow(ec2_double).to receive(:private_ip_address).and_return('127.0.0.1')
|
37
|
-
allow_any_instance_of(Object).to receive(:sleep)
|
38
|
-
end
|
39
|
-
|
40
|
-
context 'successful tests' do
|
41
|
-
it 'calls aws instance for each ami' do
|
42
|
-
expect(AmiSpec::AwsInstance).to receive(:start).with(hash_including(role: 'web_server'))
|
43
|
-
expect(AmiSpec::AwsInstance).to receive(:start).with(hash_including(role: 'db_server'))
|
44
|
-
subject
|
45
|
-
end
|
46
|
-
|
47
|
-
it 'returns true' do
|
48
|
-
expect(subject).to be_truthy
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
context 'failed tests' do
|
53
|
-
let(:test_result) { false }
|
54
|
-
|
55
|
-
it 'returns false' do
|
56
|
-
expect(subject).to be_falsey
|
57
|
-
end
|
58
|
-
end
|
59
|
-
end
|
60
|
-
|
61
|
-
describe '#parse_tags' do
|
62
|
-
it 'parses a single key/value pair' do
|
63
|
-
expect(described_class.parse_tags("Name=AmiSpec")).to eq( { "Name"=>"AmiSpec" } )
|
64
|
-
end
|
65
|
-
|
66
|
-
it 'parses multiple key/value pairs' do
|
67
|
-
expect(described_class.parse_tags("Name=AmiSpec,Owner=Me")).to eq( { "Name"=>"AmiSpec", "Owner"=>"Me" } )
|
68
|
-
end
|
69
|
-
|
70
|
-
it 'parses an empty string' do
|
71
|
-
expect(described_class.parse_tags("")).to eq({})
|
72
|
-
end
|
73
|
-
end
|
74
|
-
end
|
data/spec/aws_instance_spec.rb
DELETED
@@ -1,142 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
require 'base64'
|
3
|
-
require 'tempfile'
|
4
|
-
|
5
|
-
describe AmiSpec::AwsInstance do
|
6
|
-
let(:role) { 'web_server' }
|
7
|
-
let(:sec_group_id) { nil }
|
8
|
-
let(:region) { nil }
|
9
|
-
let(:client_double) { instance_double(Aws::EC2::Client) }
|
10
|
-
let(:new_ec2_double) { instance_double(Aws::EC2::Types::Instance) }
|
11
|
-
let(:ec2_double) { instance_double(Aws::EC2::Instance) }
|
12
|
-
let(:tags) { {} }
|
13
|
-
let(:iam_instance_profile_arn) { nil }
|
14
|
-
let(:user_data_file) { nil }
|
15
|
-
|
16
|
-
subject(:aws_instance) do
|
17
|
-
described_class.new(
|
18
|
-
role: role,
|
19
|
-
ami: 'ami',
|
20
|
-
subnet_id: 'subnet',
|
21
|
-
key_name: 'key',
|
22
|
-
aws_instance_type: 't2.micro',
|
23
|
-
aws_public_ip: false,
|
24
|
-
aws_security_groups: sec_group_id,
|
25
|
-
aws_region: region,
|
26
|
-
tags: tags,
|
27
|
-
user_data_file: user_data_file,
|
28
|
-
iam_instance_profile_arn: iam_instance_profile_arn
|
29
|
-
)
|
30
|
-
end
|
31
|
-
|
32
|
-
before do
|
33
|
-
allow(Aws::EC2::Client).to receive(:new).and_return(client_double)
|
34
|
-
allow(client_double).to receive(:run_instances).and_return(double(instances: [new_ec2_double]))
|
35
|
-
allow(ec2_double).to receive(:create_tags).and_return(double)
|
36
|
-
allow(Aws::EC2::Instance).to receive(:new).and_return(ec2_double)
|
37
|
-
allow(new_ec2_double).to receive(:instance_id)
|
38
|
-
allow(ec2_double).to receive(:instance_id)
|
39
|
-
allow(ec2_double).to receive(:wait_until_running)
|
40
|
-
end
|
41
|
-
|
42
|
-
describe '#start' do
|
43
|
-
subject(:start) { aws_instance.start }
|
44
|
-
context 'without optional values' do
|
45
|
-
it 'does not include the security group' do
|
46
|
-
expect(client_double).to receive(:run_instances).with(
|
47
|
-
hash_excluding(:network_interfaces=>array_including(hash_including(:groups)))
|
48
|
-
)
|
49
|
-
start
|
50
|
-
end
|
51
|
-
|
52
|
-
it 'does include the region' do
|
53
|
-
expect(Aws::EC2::Client).to receive(:new).with(
|
54
|
-
hash_excluding(:region => region)
|
55
|
-
)
|
56
|
-
start
|
57
|
-
end
|
58
|
-
end
|
59
|
-
|
60
|
-
context 'with security group' do
|
61
|
-
let(:sec_group_id) { ['1234'] }
|
62
|
-
|
63
|
-
it 'does include security groups' do
|
64
|
-
expect(client_double).to receive(:run_instances).with(
|
65
|
-
hash_including(:network_interfaces=>array_including(hash_including(:groups)))
|
66
|
-
)
|
67
|
-
start
|
68
|
-
end
|
69
|
-
end
|
70
|
-
|
71
|
-
context 'with region' do
|
72
|
-
let(:region) { 'us-east-1' }
|
73
|
-
|
74
|
-
it 'does include the region in the intial connection' do
|
75
|
-
expect(Aws::EC2::Client).to receive(:new).with(
|
76
|
-
hash_including(:region => region)
|
77
|
-
)
|
78
|
-
start
|
79
|
-
end
|
80
|
-
|
81
|
-
it 'does include the region in the subsequent connection' do
|
82
|
-
expect(Aws::EC2::Instance).to receive(:new).with(
|
83
|
-
anything,
|
84
|
-
hash_including(:region => region)
|
85
|
-
)
|
86
|
-
start
|
87
|
-
end
|
88
|
-
end
|
89
|
-
|
90
|
-
context 'with tags' do
|
91
|
-
let(:tags) { {"Name" => "AmiSpec"} }
|
92
|
-
|
93
|
-
it 'tags the instance' do
|
94
|
-
expect(ec2_double).to receive(:create_tags).with(
|
95
|
-
{tags: [{ key: 'AmiSpec', value: role}, { key: "Name", value: "AmiSpec"}]}
|
96
|
-
)
|
97
|
-
start
|
98
|
-
end
|
99
|
-
end
|
100
|
-
|
101
|
-
context 'with user_data' do
|
102
|
-
let(:user_data_file) {
|
103
|
-
file = Tempfile.new('user_data.txt')
|
104
|
-
file.write("my file\ncontent")
|
105
|
-
file.close
|
106
|
-
file.path
|
107
|
-
}
|
108
|
-
|
109
|
-
it 'does include user_data' do
|
110
|
-
expect(client_double).to receive(:run_instances).with(
|
111
|
-
hash_including(:user_data => Base64.encode64("my file\ncontent"))
|
112
|
-
)
|
113
|
-
start
|
114
|
-
end
|
115
|
-
end
|
116
|
-
|
117
|
-
context 'with iam_instance_profile_arn' do
|
118
|
-
let(:iam_instance_profile_arn) { "my_arn" }
|
119
|
-
|
120
|
-
it 'does include iam_instance_profile_arn' do
|
121
|
-
expect(client_double).to receive(:run_instances).with(
|
122
|
-
hash_including(:iam_instance_profile => { arn: 'my_arn'})
|
123
|
-
)
|
124
|
-
start
|
125
|
-
end
|
126
|
-
end
|
127
|
-
|
128
|
-
it 'tags the instance with a role' do
|
129
|
-
expect(ec2_double).to receive(:create_tags).with(
|
130
|
-
hash_including(tags: [{ key: 'AmiSpec', value: role}])
|
131
|
-
)
|
132
|
-
start
|
133
|
-
end
|
134
|
-
|
135
|
-
it 'delegates some methods to the instance variable' do
|
136
|
-
expect(ec2_double).to receive(:instance_id)
|
137
|
-
start
|
138
|
-
aws_instance.instance_id
|
139
|
-
end
|
140
|
-
end
|
141
|
-
|
142
|
-
end
|
@@ -1,22 +0,0 @@
|
|
1
|
-
FROM ubuntu:xenial
|
2
|
-
|
3
|
-
RUN cd /lib/systemd/system/sysinit.target.wants/; ls | grep -v systemd-tmpfiles-setup | xargs rm -f $1 \
|
4
|
-
rm -f /lib/systemd/system/multi-user.target.wants/*;\
|
5
|
-
rm -f /etc/systemd/system/*.wants/*;\
|
6
|
-
rm -f /lib/systemd/system/local-fs.target.wants/*; \
|
7
|
-
rm -f /lib/systemd/system/sockets.target.wants/*udev*; \
|
8
|
-
rm -f /lib/systemd/system/sockets.target.wants/*initctl*; \
|
9
|
-
rm -f /lib/systemd/system/basic.target.wants/*;\
|
10
|
-
rm -f /lib/systemd/system/anaconda.target.wants/*; \
|
11
|
-
rm -f /lib/systemd/system/plymouth*; \
|
12
|
-
rm -f /lib/systemd/system/systemd-update-utmp*;
|
13
|
-
|
14
|
-
RUN apt-get update && apt-get install -y openssh-server dbus && apt-get clean
|
15
|
-
|
16
|
-
RUN systemctl set-default multi-user.target
|
17
|
-
|
18
|
-
COPY ami-spec.pub /root/.ssh/authorized_keys
|
19
|
-
|
20
|
-
EXPOSE 22
|
21
|
-
|
22
|
-
CMD ["/bin/bash", "-c", "exec /sbin/init --log-target=journal 3>&1"]
|
data/spec/containers/README.md
DELETED
@@ -1,5 +0,0 @@
|
|
1
|
-
## Integration test containers
|
2
|
-
|
3
|
-
This directory is used to create containers that can be used to test the `WaitForRC` class. Because they require upstart/systemd to exist we have to install and start the init environment. We also setup SSH so that we can simple call the `wait` function and have it SSH to our container to execute.
|
4
|
-
|
5
|
-
Refer to the [README](../../README.md#running-tests) for how to execute them.
|
data/spec/containers/ami-spec
DELETED
@@ -1,27 +0,0 @@
|
|
1
|
-
-----BEGIN RSA PRIVATE KEY-----
|
2
|
-
MIIEowIBAAKCAQEAwWn2++lylp8RcHzy7H9QpYli3nxLDh769DDbnb9cw2UDd9OH
|
3
|
-
6JZKaT3xe3IbMr39SmkGlOygkBmeH43VxAkiVJv3awDPRU0UvDyUvCsbaYj1/cOS
|
4
|
-
8Vxr7ENExoiKkengcg6k3mFj65ooJ1pf8RoXuj+0+YU0fgejuR/M4x6V8GKFCJhU
|
5
|
-
wFmRs3mcoCx0EiJtTx40IW87uOQUruDX5HcgTUInRhyRxltNrXJaap1weMGpIA/o
|
6
|
-
Bo8foOx1Os9o3YKQlkPF4iqk2AVJ4FZGbMay0cIq3075Jeig6bdlIhRpYA+w+SAI
|
7
|
-
y/yT/K3U1ciQqKtPgahGEyihrh7Ks2F2FSLhdwIDAQABAoIBABWt/QNLrY54kgnb
|
8
|
-
15buxmlntu9dW0Rf8J1ChLtv4cP9JKBf05IcloapbNH7flT3utaGYzh6NZ0xYeoD
|
9
|
-
ifyJUZHOUbNqydDozPQ0ji9xXYc81OX28Beh1m8LM0BVucKVRpVCUvSiUgLsqqeO
|
10
|
-
l8Z8uEAmN/DoH3QpAw8TI3Ip0YC6OHA2aRV9PXuDnR5OTdBPOBj33Fdtf0rUAk41
|
11
|
-
UFe/BHFyACfTK05+bcQz9DvRV/H+SnBeOCqDie1eNDnEgza4NS2cnBUCogKsaCrY
|
12
|
-
gV06pivS2aHsK5CuNB1lcZi1tVf3DnDwPvFWqLLG9PIHaevPDpDURECirCrpCWJT
|
13
|
-
VSHm7KECgYEA4K5jSna4Jzo9FlHzF+yGEju5QwEJTjnhunNw1FpcgPAddFQ4hs3w
|
14
|
-
0EhyPlZyf3vwhfdH4vBhTLjRTrOF2SIvSSPwrkWlAhaluVvpVRFd/ncYW4kAVwhQ
|
15
|
-
15/ZBtvu8OQnKeeztsLlkEi4ik3cKjeXyeDQReb2Guvc6IM4fr6ZrlkCgYEA3F/S
|
16
|
-
uJr04UgzX0cQuNLX7uXz6oeyJupwFkTuAhvLcHDsDHFkP1M9zfFzg5aEcQungz/l
|
17
|
-
5s/vFJmfLBrzhSoYY1T9PDdLwEL/JKaxhKNEV9lExF4exMui6QPWdTMA8ndvB7r5
|
18
|
-
Ur85X8scH1qJo99fsEmNmG5O72PGXmltOB0sNE8CgYEApeuCPYIweh+C7xGzkE5F
|
19
|
-
r/9Uz4tbYN5TuMn5X4gfWcR4K+jqGXrJxDZLz4ctZMGVHIlBF/DmGa8+On1OccvR
|
20
|
-
2ZRl73xU35bz6U9bn0uE+x7d6PLiQmNMt/8+WNdfu5rw5PxLdcK1nnhldxUKak7F
|
21
|
-
k/qmM4jc44Kcj0QgG1EL0nkCgYAFbV61KSvKuIp7WDazNo4W1hbxubHLf46PHdd2
|
22
|
-
udSCymUl0U0UuioVflLH9NcCKbVQaCxzSL+slDP1VByXNPgwyhEKgJoe/Adokaph
|
23
|
-
h9vRBgrJgz/ivNkgP/XyIPVvAz36xMILJaZ2E3x30TT+kiu7HbSdAmpzPtPN027b
|
24
|
-
KOzDxQKBgEv2OvEtpvpv9DgPHs9Mq4haTh2o8c8JW7kwHqbbZOZjZ/4daEh89FhH
|
25
|
-
gjvJV5NjaNhFqBWTnNfjSr4o09WFDoQyVwEUrWNJXXZmsjOHqMDT/kwVoAsld1tO
|
26
|
-
N+JW6/4M+EMYvF39yWzdQn/U3A1gZIfzAC6S3HUCi9BgKLBMKEN3
|
27
|
-
-----END RSA PRIVATE KEY-----
|
@@ -1 +0,0 @@
|
|
1
|
-
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDBafb76XKWnxFwfPLsf1CliWLefEsOHvr0MNudv1zDZQN304folkppPfF7chsyvf1KaQaU7KCQGZ4fjdXECSJUm/drAM9FTRS8PJS8KxtpiPX9w5LxXGvsQ0TGiIqR6eByDqTeYWPrmignWl/xGhe6P7T5hTR+B6O5H8zjHpXwYoUImFTAWZGzeZygLHQSIm1PHjQhbzu45BSu4NfkdyBNQidGHJHGW02tclpqnXB4wakgD+gGjx+g7HU6z2jdgpCWQ8XiKqTYBUngVkZsxrLRwirfTvkl6KDpt2UiFGlgD7D5IAjL/JP8rdTVyJCoq0+BqEYTKKGuHsqzYXYVIuF3
|
@@ -1,28 +0,0 @@
|
|
1
|
-
version: '3'
|
2
|
-
services:
|
3
|
-
xenial:
|
4
|
-
build:
|
5
|
-
context: .
|
6
|
-
dockerfile: Dockerfile.xenial
|
7
|
-
ports:
|
8
|
-
- "1122:22"
|
9
|
-
# --security-opt seccomp=unconfined --tmpfs /run --tmpfs /run/lock -v /sys/fs/cgroup:/sys/fs/cgroup:ro
|
10
|
-
security_opt:
|
11
|
-
- seccomp:unconfined
|
12
|
-
tmpfs:
|
13
|
-
- /run
|
14
|
-
- /run/lock
|
15
|
-
volumes:
|
16
|
-
- /sys/fs/cgroup:/sys/fs/cgroup:ro
|
17
|
-
trusty:
|
18
|
-
build:
|
19
|
-
context: .
|
20
|
-
dockerfile: Dockerfile.trusty
|
21
|
-
ports:
|
22
|
-
- "1123:22"
|
23
|
-
amazon_linux:
|
24
|
-
build:
|
25
|
-
context: .
|
26
|
-
dockerfile: Dockerfile.amazon_linux
|
27
|
-
ports:
|
28
|
-
- "1124:22"
|
data/spec/containers/rc.conf
DELETED
@@ -1,17 +0,0 @@
|
|
1
|
-
# rc - System V runlevel compatibility
|
2
|
-
#
|
3
|
-
# This task runs the old sysv-rc runlevel scripts. It
|
4
|
-
# is usually started by the telinit compatibility wrapper.
|
5
|
-
#
|
6
|
-
# Do not edit this file directly. If you want to change the behaviour,
|
7
|
-
# please create a file rc.override and put your changes there.
|
8
|
-
|
9
|
-
start on runlevel [0123456]
|
10
|
-
|
11
|
-
stop on runlevel [!$RUNLEVEL]
|
12
|
-
|
13
|
-
task
|
14
|
-
|
15
|
-
export RUNLEVEL
|
16
|
-
console output
|
17
|
-
exec /etc/rc.d/rc $RUNLEVEL
|
data/spec/containers/sshd_config
DELETED
@@ -1,17 +0,0 @@
|
|
1
|
-
HostKey /etc/ssh/ssh_host_rsa_key
|
2
|
-
HostKey /etc/ssh/ssh_host_ecdsa_key
|
3
|
-
HostKey /etc/ssh/ssh_host_ed25519_key
|
4
|
-
SyslogFacility AUTHPRIV
|
5
|
-
AuthorizedKeysFile .ssh/authorized_keys
|
6
|
-
PasswordAuthentication no
|
7
|
-
ChallengeResponseAuthentication no
|
8
|
-
UsePAM yes
|
9
|
-
X11Forwarding yes
|
10
|
-
PrintLastLog yes
|
11
|
-
UsePrivilegeSeparation sandbox
|
12
|
-
AcceptEnv LANG LC_CTYPE LC_NUMERIC LC_TIME LC_COLLATE LC_MONETARY LC_MESSAGES
|
13
|
-
AcceptEnv LC_PAPER LC_NAME LC_ADDRESS LC_TELEPHONE LC_MEASUREMENT
|
14
|
-
AcceptEnv LC_IDENTIFICATION LC_ALL LANGUAGE
|
15
|
-
AcceptEnv XMODIFIERS
|
16
|
-
Subsystem sftp /usr/libexec/openssh/sftp-server
|
17
|
-
PermitRootLogin yes
|
data/spec/spec_helper.rb
DELETED
data/spec/wait_for_rc_spec.rb
DELETED
@@ -1,25 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe AmiSpec::WaitForRC, integration: true do
|
4
|
-
let(:private_key_file) { File.expand_path(File.join('..', 'containers', 'ami-spec'), __FILE__) }
|
5
|
-
context 'xenial server' do
|
6
|
-
let(:ssh_port) { 1122 }
|
7
|
-
it 'executes without printing any errors' do
|
8
|
-
expect { described_class.wait("localhost", "root", private_key_file, ssh_port) }.to_not output.to_stdout
|
9
|
-
end
|
10
|
-
end
|
11
|
-
|
12
|
-
context 'trusty server' do
|
13
|
-
let(:ssh_port) { 1123 }
|
14
|
-
it 'executes without printing any errors' do
|
15
|
-
expect { described_class.wait("localhost", "root", private_key_file, ssh_port) }.to_not output.to_stdout
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
context 'amazon linux server' do
|
20
|
-
let(:ssh_port) { 1124 }
|
21
|
-
it 'executes without printing any errors' do
|
22
|
-
expect { described_class.wait("localhost", "root", private_key_file, ssh_port) }.to_not output.to_stdout
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
data/spec/wait_for_ssh_spec.rb
DELETED
@@ -1,39 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe AmiSpec::WaitForSSH do
|
4
|
-
describe '#wait' do
|
5
|
-
let(:retries) { 30 }
|
6
|
-
subject { described_class.wait('127.0.0.1', 'ubuntu', 'key.pem', 30) }
|
7
|
-
|
8
|
-
before do
|
9
|
-
allow_any_instance_of(Object).to receive(:sleep)
|
10
|
-
end
|
11
|
-
|
12
|
-
it 'returns after one attempt if ssh connection succeeds' do
|
13
|
-
expect(Net::SSH).to receive(:start)
|
14
|
-
|
15
|
-
subject
|
16
|
-
end
|
17
|
-
|
18
|
-
context 'ssh fails' do
|
19
|
-
before do
|
20
|
-
allow(Net::SSH).to receive(:start).and_raise(Errno::ECONNREFUSED, 'ssh failed')
|
21
|
-
end
|
22
|
-
|
23
|
-
it 'raises an exception' do
|
24
|
-
expect{subject}.to raise_error(AmiSpec::InstanceConnectionTimeout)
|
25
|
-
end
|
26
|
-
|
27
|
-
it 'returns the last error' do
|
28
|
-
expect(Net::SSH).to receive(:start).and_raise(Errno::ECONNREFUSED, 'some other error')
|
29
|
-
expect{subject}.to raise_error(AmiSpec::InstanceConnectionTimeout, /ssh failed/)
|
30
|
-
end
|
31
|
-
|
32
|
-
it 'tries the number of retries specified' do
|
33
|
-
expect(Net::SSH).to receive(:start).exactly(retries).times
|
34
|
-
|
35
|
-
expect{subject}.to raise_error(AmiSpec::InstanceConnectionTimeout)
|
36
|
-
end
|
37
|
-
end
|
38
|
-
end
|
39
|
-
end
|