ami_spec 1.4.0 → 1.8.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 87eebf7f488963ef90dec3e34678f6c75bd36eaf896467edaeb1651271ad8d8a
4
- data.tar.gz: 6425586e1732b2e78cb4099047f1ba6e5e99d08deb0dbd5aa4031daa24beb597
3
+ metadata.gz: a2a7a5034e02deb64f10fae91426c5771688bbae9c8e56764c6af2faa13ebe7c
4
+ data.tar.gz: b006c1eeeae2d04e63d077717fabf1aa0ebe29a8361f88c6958d92401866ff7f
5
5
  SHA512:
6
- metadata.gz: 93dd91143f960c39da8cfdf24522a9daf271d4aaf3a69db345d4621e40c9a10ca43158abe19a0e2268cca9bbc699267fe9c54b954275d5e7bccb404eb2e487f7
7
- data.tar.gz: 7e1a7762ed90bfd5266ab9a869fe1a78af16e065fe8d5c8ac0663376195e9029d7b23c8d8d7ab818cba7fdf5d2ee821eab723b8b176459880685851e4a055ebe
6
+ metadata.gz: c9e66fea702fe7f9edf9aa8679ec2c386e1c46079c9371b5cbae2964b25b9d84eb60ed65a54b34e54d123ab27e7bc2756dd4c9ee2fefffdd751187802d74976a
7
+ data.tar.gz: 1aaf85899a5269204bc817680c83c386e1b8132727712c49145cfa52627b72ea7301c8be6d08b28ae143daab2aa67aa0a61ec07854fb6b4a896c230b5843ccde
data/README.md CHANGED
@@ -1,5 +1,9 @@
1
1
  # AmiSpec
2
2
 
3
+ [![License MIT](https://img.shields.io/badge/license-MIT-brightgreen.svg)](https://github.com/envato/ami-spec/blob/master/LICENSE.txt)
4
+ [![Gem Version](https://badge.fury.io/rb/ami_spec.svg)](https://badge.fury.io/rb/ami_spec)
5
+ [![Build Status](https://github.com/envato/ami-spec/workflows/tests/badge.svg?branch=master)](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> The role to test, this should map to a directory in the spec
33
- folder
34
- -a, --ami=<s> The ami ID to run tests against
35
- -o, --role-ami-file=<s> A file containing comma separated roles and amis. i.e.
36
- web_server,ami-id.
37
- -s, --specs=<s> The directory to find ServerSpecs
38
- -u, --subnet-id=<s> The subnet to start the instance in
39
- -k, --key-name=<s> The SSH key name to assign to instances. If not provided a
40
- temporary key pair will be generated in AWS
41
- -e, --key-file=<s> The SSH private key file associated to the key_name
42
- -h, --ssh-user=<s> The user to ssh to the instance as
43
- -w, --aws-region=<s> The AWS region, defaults to AWS_DEFAULT_REGION environment
44
- variable
45
- -i, --aws-instance-type=<s> The ec2 instance type, defaults to t2.micro (default:
46
- t2.micro)
47
- -c, --aws-security-groups=<s> Security groups to associate to the launched instances. May be
48
- specified multiple times. If not provided a temporary security
49
- group will be generated in AWS
50
- -p, --aws-public-ip Launch instances with a public IP
51
- -t, --ssh-retries=<i> The number of times we should try sshing to the ec2 instance
52
- before giving up. Defaults to 30 (default: 30)
53
- -g, --tags=<s> Additional tags to add to launched instances in the form of
54
- comma separated key=value pairs. i.e. Name=AmiSpec (default: )
55
- -d, --debug Don't terminate instances on exit
56
- -b, --buildkite Output section separators for buildkite
57
- -f, --wait-for-rc Wait for oldschool SystemV scripts to run before conducting
58
- tests. Currently only supports Ubuntu with upstart
59
- -l, --user-data-file=<s> File path for aws ec2 user data
60
- -m, --iam-instance-profile-arn=<s> IAM instance profile to use
61
- --help Show this message
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
@@ -0,0 +1,10 @@
1
+ require 'aws-sdk-ec2'
2
+
3
+ module AmiSpec
4
+ class AwsDefaultVpc
5
+ def self.find_subnet(ec2: Aws::EC2::Resource.new)
6
+ default_vpc = ec2.vpcs(filters: [{name: 'isDefault', values: ['true']}]).first
7
+ default_vpc && default_vpc.subnets.first
8
+ end
9
+ end
10
+ end
@@ -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
  }
@@ -12,6 +12,7 @@ module AmiSpec
12
12
  property :aws_public_ip
13
13
  property :aws_region
14
14
  property :aws_security_groups
15
+ property :associate_public_ip
15
16
  property :tags
16
17
  property :user_data_file
17
18
  property :iam_instance_profile_arn
@@ -1,3 +1,3 @@
1
1
  module AmiSpec
2
- VERSION = '1.4.0'
2
+ VERSION = '1.8.0'
3
3
  end
@@ -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, "The role to test, this should map to a directory in the spec folder", type: :string
115
- opt :ami, "The ami ID to run tests against", type: :string
116
- opt :role_ami_file, "A file containing comma separated roles and amis. i.e.\nweb_server,ami-id.",
117
- type: :string
118
- opt :specs, "The directory to find ServerSpecs", type: :string, required: true
119
- opt :subnet_id, "The subnet to start the instance in", type: :string, required: true
120
- opt :key_name, "The SSH key name to assign to instances. If not provided a temporary key pair will be generated in AWS",
121
- type: :string
122
- opt :key_file, "The SSH private key file associated to the key_name", type: :string
123
- opt :ssh_user, "The user to ssh to the instance as", type: :string, required: true
124
- opt :aws_region, "The AWS region, defaults to AWS_DEFAULT_REGION environment variable", type: :string
125
- opt :aws_instance_type, "The ec2 instance type, defaults to t2.micro", type: :string, default: 't2.micro'
126
- opt :aws_security_groups, "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",
127
- type: :string, default: nil, multi: true
128
- opt :allow_any_temporary_security_group, "The temporary security group will allow SSH connections from any IP address (0.0.0.0/0)"
129
- opt :aws_public_ip, "Launch instances with a public IP"
130
- opt :ssh_retries, "The number of times we should try sshing to the ec2 instance before giving up. Defaults to 30",
131
- type: :int, default: 30
132
- opt :tags, "Additional tags to add to launched instances in the form of comma separated key=value pairs. i.e. Name=AmiSpec", type: :string, default: ""
133
- opt :debug, "Don't terminate instances on exit"
134
- opt :buildkite, "Output section separators for buildkite"
135
- opt :wait_for_rc, "Wait for oldschool SystemV scripts to run before conducting tests. Currently only supports Ubuntu with upstart"
136
- opt :user_data_file, "File path for aws ec2 user data", type: :string, default: nil
137
- opt :iam_instance_profile_arn, "IAM instance profile to use", type: :string
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.0
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: 2019-07-29 00:00:00.000000000 Z
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: []