ami_spec 1.4.0 → 1.8.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 +73 -30
- data/lib/ami_spec/aws_default_vpc.rb +10 -0
- data/lib/ami_spec/aws_instance.rb +2 -1
- data/lib/ami_spec/aws_instance_options.rb +1 -0
- 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_ssh.rb +1 -1
- data/lib/ami_spec.rb +53 -26
- metadata +7 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a2a7a5034e02deb64f10fae91426c5771688bbae9c8e56764c6af2faa13ebe7c
|
4
|
+
data.tar.gz: b006c1eeeae2d04e63d077717fabf1aa0ebe29a8361f88c6958d92401866ff7f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c9e66fea702fe7f9edf9aa8679ec2c386e1c46079c9371b5cbae2964b25b9d84eb60ed65a54b34e54d123ab27e7bc2756dd4c9ee2fefffdd751187802d74976a
|
7
|
+
data.tar.gz: 1aaf85899a5269204bc817680c83c386e1b8132727712c49145cfa52627b72ea7301c8be6d08b28ae143daab2aa67aa0a61ec07854fb6b4a896c230b5843ccde
|
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,36 +33,40 @@ 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
|
-
|
59
|
-
-
|
60
|
-
-
|
61
|
-
--
|
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 and use that IP for SSH
|
58
|
+
-q, --associate-public-ip Launch instances with a public IP and use the Private IP for SSH
|
59
|
+
-t, --ssh-retries=<i> The number of times we should try sshing to the ec2 instance
|
60
|
+
before giving up. Defaults to 30 (default: 30)
|
61
|
+
-g, --tags=<s> Additional tags to add to launched instances in the form of
|
62
|
+
comma separated key=value pairs. i.e. Name=AmiSpec (default: )
|
63
|
+
-d, --debug Don't terminate instances on exit
|
64
|
+
-b, --buildkite Output section separators for buildkite
|
65
|
+
-f, --wait-for-rc Wait for oldschool SystemV scripts to run before conducting
|
66
|
+
tests. Currently only supports Ubuntu with upstart
|
67
|
+
-l, --user-data-file=<s> File path for aws ec2 user data
|
68
|
+
-m, --iam-instance-profile-arn=<s> IAM instance profile to use
|
69
|
+
--help Show this message
|
62
70
|
|
63
71
|
```
|
64
72
|
|
@@ -68,6 +76,41 @@ When the instances becomes reachable it will run all Specs inside the role spec
|
|
68
76
|
|
69
77
|
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`.
|
70
78
|
|
79
|
+
## ServerSpec test layout
|
80
|
+
|
81
|
+
AmiSpec expects the usual ServerSpec configuration layout as generated by "serverspec-init":
|
82
|
+
|
83
|
+
spec/
|
84
|
+
├── webserver
|
85
|
+
│ └── webserver_spec.rb
|
86
|
+
└── spec_helper.rb
|
87
|
+
|
88
|
+
The \*\_spec.rb files under the role (e.g. webserver) contain the ServerSpec
|
89
|
+
tests that you want to run. The spec_helper.rb file can be very simple:
|
90
|
+
|
91
|
+
require 'serverspec'
|
92
|
+
|
93
|
+
set :backend, :ssh
|
94
|
+
|
95
|
+
Note that the backend *needs* to be :ssh or ami_spec might run the tests on
|
96
|
+
your local machine, not in EC2.
|
97
|
+
|
98
|
+
## Example usage
|
99
|
+
|
100
|
+
To test a custom AMI using a pre-created security group that allows SSH from anywhere:
|
101
|
+
|
102
|
+
```cli
|
103
|
+
ami_spec --role webserver\
|
104
|
+
--specs spec\
|
105
|
+
--aws-region us-east-1\
|
106
|
+
--ami ami-0123456789abcdef0\
|
107
|
+
--key-name default\
|
108
|
+
--key-file ~/.ssh/default.pem\
|
109
|
+
--ssh-user ubuntu\
|
110
|
+
--aws-public-ip\
|
111
|
+
--aws-security-groups sg-0123456789abcdef0
|
112
|
+
```
|
113
|
+
|
71
114
|
## Known caveats
|
72
115
|
|
73
116
|
### RSpec conditions in examples
|
@@ -19,6 +19,7 @@ module AmiSpec
|
|
19
19
|
@key_name = options.fetch(:key_name)
|
20
20
|
@instance_type = options.fetch(:aws_instance_type)
|
21
21
|
@public_ip = options.fetch(:aws_public_ip)
|
22
|
+
@associate_public_ip = options.fetch(:associate_public_ip)
|
22
23
|
@region = options.fetch(:aws_region)
|
23
24
|
@security_group_ids = options.fetch(:aws_security_groups)
|
24
25
|
@tags = ec2ify_tags(options.fetch(:tags))
|
@@ -61,7 +62,7 @@ module AmiSpec
|
|
61
62
|
key_name: @key_name,
|
62
63
|
network_interfaces: [{
|
63
64
|
device_index: 0,
|
64
|
-
associate_public_ip_address: @public_ip,
|
65
|
+
associate_public_ip_address: @public_ip || @associate_public_ip,
|
65
66
|
subnet_id: @subnet_id,
|
66
67
|
}]
|
67
68
|
}
|
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
|
@@ -9,7 +9,7 @@ module AmiSpec
|
|
9
9
|
while retries < max_retries
|
10
10
|
begin
|
11
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 => error
|
12
|
+
rescue Errno::ETIMEDOUT, Errno::ECONNREFUSED, Timeout::Error, Net::SSH::Exception => error
|
13
13
|
last_error = error
|
14
14
|
sleep 1
|
15
15
|
else
|
data/lib/ami_spec.rb
CHANGED
@@ -1,11 +1,13 @@
|
|
1
1
|
require 'ami_spec/aws_instance'
|
2
2
|
require 'ami_spec/aws_instance_options'
|
3
|
+
require 'ami_spec/aws_default_vpc'
|
3
4
|
require 'ami_spec/aws_key_pair'
|
4
5
|
require 'ami_spec/aws_security_group'
|
5
6
|
require 'ami_spec/server_spec'
|
6
7
|
require 'ami_spec/server_spec_options'
|
7
8
|
require 'ami_spec/wait_for_ssh'
|
8
9
|
require 'ami_spec/wait_for_rc'
|
10
|
+
require 'ami_spec/wait_for_cloud_init'
|
9
11
|
require 'optimist'
|
10
12
|
require 'logger'
|
11
13
|
|
@@ -36,7 +38,9 @@ module AmiSpec
|
|
36
38
|
# aws_instance_type::
|
37
39
|
# AWS ec2 instance type
|
38
40
|
# aws_public_ip::
|
39
|
-
# Should the instances get a public IP address
|
41
|
+
# Should the instances get a public IP address and use that IP for SSH
|
42
|
+
# associate_public_ip::
|
43
|
+
# Launch instances with a public IP but don't use that IP for SSH
|
40
44
|
# ssh_user::
|
41
45
|
# The username to SSH to the AMI with.
|
42
46
|
# ssh_retries::
|
@@ -54,6 +58,13 @@ module AmiSpec
|
|
54
58
|
|
55
59
|
ec2 = Aws::EC2::Resource.new(options[:aws_region] ? {region: options[:aws_region]} : {})
|
56
60
|
|
61
|
+
if options[:subnet_id].nil?
|
62
|
+
default_vpc_subnet = AwsDefaultVpc.find_subnet(ec2: ec2)
|
63
|
+
raise 'No default VPC subnet found. Please specify a subnet id.' if default_vpc_subnet.nil?
|
64
|
+
options[:subnet_id] = default_vpc_subnet.id
|
65
|
+
logger.info("Using subnet #{options[:subnet_id]} from the default VPC")
|
66
|
+
end
|
67
|
+
|
57
68
|
unless options[:key_name]
|
58
69
|
key_pair = AwsKeyPair.create(ec2: ec2, logger: logger)
|
59
70
|
options[:key_name] = key_pair.key_name
|
@@ -81,6 +92,7 @@ module AmiSpec
|
|
81
92
|
ip_address = options[:aws_public_ip] ? instance.public_ip_address : instance.private_ip_address
|
82
93
|
WaitForSSH.wait(ip_address, options[:ssh_user], options[:key_file], options[:ssh_retries])
|
83
94
|
WaitForRC.wait(ip_address, options[:ssh_user], options[:key_file]) if options[:wait_for_rc]
|
95
|
+
WaitForCloudInit.wait(ip_address, options[:ssh_user], options[:key_file]) if options[:wait_for_cloud_init]
|
84
96
|
|
85
97
|
server_spec_options = ServerSpecOptions.new(options.merge(instance: instance))
|
86
98
|
results << ServerSpec.new(server_spec_options).run
|
@@ -94,7 +106,7 @@ module AmiSpec
|
|
94
106
|
end
|
95
107
|
|
96
108
|
def self.stop_instances(instances, debug)
|
97
|
-
instances.each do |instance|
|
109
|
+
instances && instances.each do |instance|
|
98
110
|
begin
|
99
111
|
if debug
|
100
112
|
puts "EC2 instance ##{instance.instance_id} has not been stopped due to debug mode."
|
@@ -111,30 +123,45 @@ module AmiSpec
|
|
111
123
|
|
112
124
|
def self.invoke
|
113
125
|
options = Optimist::options do
|
114
|
-
opt :role,
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
opt :
|
119
|
-
|
120
|
-
|
121
|
-
type: :string
|
122
|
-
opt :
|
123
|
-
|
124
|
-
opt :
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
opt :
|
130
|
-
opt :
|
131
|
-
|
132
|
-
|
133
|
-
opt :
|
134
|
-
|
135
|
-
opt :
|
136
|
-
|
137
|
-
|
126
|
+
opt :role,
|
127
|
+
'The role to test, this should map to a directory in the spec folder',
|
128
|
+
type: :string, short: :r
|
129
|
+
opt :ami, 'The ami ID to run tests against', type: :string, short: :a
|
130
|
+
opt :role_ami_file,
|
131
|
+
'A file containing comma separated roles and amis. i.e.
|
132
|
+
web_server,ami-id.',
|
133
|
+
type: :string, short: :o
|
134
|
+
opt :specs, 'The directory to find ServerSpecs',
|
135
|
+
type: :string, required: true, short: :s
|
136
|
+
opt :subnet_id,
|
137
|
+
'The subnet to start the instance in. If not provided a subnet will be chosen from the default VPC',
|
138
|
+
type: :string, short: :u
|
139
|
+
opt :key_name, 'The SSH key name to assign to instances. If not provided a temporary key pair will be generated in AWS',
|
140
|
+
type: :string, short: :k
|
141
|
+
opt :key_file, 'The SSH private key file associated to the key_name', type: :string, short: :e
|
142
|
+
opt :ssh_user, 'The user to ssh to the instance as', type: :string, required: true, short: :h
|
143
|
+
opt :aws_region, 'The AWS region, defaults to AWS_DEFAULT_REGION environment variable',
|
144
|
+
type: :string, short: :w
|
145
|
+
opt :aws_instance_type, 'The ec2 instance type, defaults to t2.micro',
|
146
|
+
type: :string, default: 't2.micro', short: :i
|
147
|
+
opt :aws_security_groups,
|
148
|
+
'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',
|
149
|
+
type: :string, default: nil, multi: true, short: :c
|
150
|
+
opt :allow_any_temporary_security_group, 'The temporary security group will allow SSH connections from any IP address (0.0.0.0/0)',
|
151
|
+
short: :n
|
152
|
+
opt :aws_public_ip, 'Launch instances with a public IP and use that IP for SSH', short: :p
|
153
|
+
opt :associate_public_ip, "Launch instances with a public IP but don't use that IP for SSH", short: :q
|
154
|
+
opt :ssh_retries, 'The number of times we should try sshing to the ec2 instance before giving up. Defaults to 30',
|
155
|
+
type: :int, default: 30, short: :t
|
156
|
+
opt :tags, 'Additional tags to add to launched instances in the form of comma separated key=value pairs. i.e. Name=AmiSpec',
|
157
|
+
type: :string, default: '', short: :g
|
158
|
+
opt :debug, "Don't terminate instances on exit", short: :d
|
159
|
+
opt :buildkite, 'Output section separators for buildkite', short: :b
|
160
|
+
opt :wait_for_rc, 'Wait for oldschool SystemV scripts to run before conducting tests. Currently only supports Ubuntu with upstart',
|
161
|
+
short: :f
|
162
|
+
opt :wait_for_cloud_init, 'Wait for Cloud Init to complete before running tests'
|
163
|
+
opt :user_data_file, 'File path for aws ec2 user data', type: :string, default: nil, short: :l
|
164
|
+
opt :iam_instance_profile_arn, 'IAM instance profile to use', type: :string, short: :m
|
138
165
|
end
|
139
166
|
|
140
167
|
if options[:role] && options[:ami]
|
metadata
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ami_spec
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.8.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-11-25 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: aws-sdk-ec2
|
@@ -120,6 +120,7 @@ files:
|
|
120
120
|
- README.md
|
121
121
|
- bin/ami_spec
|
122
122
|
- lib/ami_spec.rb
|
123
|
+
- lib/ami_spec/aws_default_vpc.rb
|
123
124
|
- lib/ami_spec/aws_instance.rb
|
124
125
|
- lib/ami_spec/aws_instance_options.rb
|
125
126
|
- lib/ami_spec/aws_key_pair.rb
|
@@ -127,12 +128,13 @@ files:
|
|
127
128
|
- lib/ami_spec/server_spec.rb
|
128
129
|
- lib/ami_spec/server_spec_options.rb
|
129
130
|
- lib/ami_spec/version.rb
|
131
|
+
- lib/ami_spec/wait_for_cloud_init.rb
|
130
132
|
- lib/ami_spec/wait_for_rc.rb
|
131
133
|
- lib/ami_spec/wait_for_ssh.rb
|
132
134
|
homepage: https://github.com/envato/ami-spec
|
133
135
|
licenses: []
|
134
136
|
metadata: {}
|
135
|
-
post_install_message:
|
137
|
+
post_install_message:
|
136
138
|
rdoc_options: []
|
137
139
|
require_paths:
|
138
140
|
- lib
|
@@ -148,7 +150,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
148
150
|
version: '0'
|
149
151
|
requirements: []
|
150
152
|
rubygems_version: 3.0.4
|
151
|
-
signing_key:
|
153
|
+
signing_key:
|
152
154
|
specification_version: 4
|
153
155
|
summary: Acceptance testing your AMIs
|
154
156
|
test_files: []
|