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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4504c60fd0ce24f40be03e192159fcc9c8509cddbc2642cb0c8c50e351a7c7fa
4
- data.tar.gz: 8fc38e659fb6436b8ad37467564445de49c92940991d3f8b820d1b2f6927355a
3
+ metadata.gz: 718f947b58e6bedd2093507f23b7bcc1c8deae4503dde3603c6768700729948a
4
+ data.tar.gz: b8c05a3702f5951932d372f6c3788a2ee71f9d0ead934a4bdfb52cae382bbe70
5
5
  SHA512:
6
- metadata.gz: 1a86bbfccdfbbe323eea7cea45bc9450d41626d3a40ed456a41b4228ef4eb1b211e23268a024dbecd81ebb768a06f00ac19e99f31387ce14e6b32635c99886cf
7
- data.tar.gz: 65effb5f2d0a7053c645c79b9ffa0c42ca93c4ee4183cdfbc7ab909263affb431d54ba0ea7f0dcb339bc5f3b81466ed765393d644886910b499e6a8df501c673
6
+ metadata.gz: a2ceb57cf5b2ea84f085a835e47e1533065338479c23bf3da88ff962d5c046c6109f2c0b93461ac4c1d5093a14bc7d522e4c154d1f34225ef3813ebd70f6ecda
7
+ data.tar.gz: ca6403909f96efb50c412ed722e6449b51ea147677f10d2e7729e31d02adc8ae82561eeaf2bbe054ab774bdf9086fe7b690254512f590c49d977920f99e2f371
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,33 +33,39 @@ 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
40
- -e, --key-file=<s> The SSH private key file associated to the key_name
41
- -h, --ssh-user=<s> The user to ssh to the instance as
42
- -w, --aws-region=<s> The AWS region, defaults to AWS_DEFAULT_REGION environment
43
- variable
44
- -i, --aws-instance-type=<s> The ec2 instance type, defaults to t2.micro (default:
45
- t2.micro)
46
- -c, --aws-security-groups=<s+> Security groups to associate to the launched instances. May be
47
- specified multiple times
48
- -p, --aws-public-ip Launch instances with a public IP
49
- -t, --ssh-retries=<i> The number of times we should try sshing to the ec2 instance
50
- before giving up. Defaults to 30 (default: 30)
51
- -g, --tags=<s> Additional tags to add to launched instances in the form of
52
- comma separated key=value pairs. i.e. Name=AmiSpec (default: )
53
- -d, --debug Don't terminate instances on exit
54
- -f, --wait-for-rc Wait for oldschool SystemV scripts to run before conducting
55
- tests. Currently only supports Ubuntu with upstart
56
- -l, --user-data-file=<s> File path for aws ec2 user data
57
- -m, --iam-instance-profile-arn=<s> IAM instance profile to use
58
- --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
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
@@ -1,6 +1,5 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
- require 'trollop'
4
3
  require 'ami_spec'
5
4
 
6
5
  AmiSpec.invoke
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 'trollop'
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. This key name must exist on the executing host for passwordless login.
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
- # Defaults to the default security group for the VPC
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 = Trollop::options do
87
- opt :role, "The role to test, this should map to a directory in the spec folder", type: :string
88
- opt :ami, "The ami ID to run tests against", type: :string
89
- opt :role_ami_file, "A file containing comma separated roles and amis. i.e.\nweb_server,ami-id.",
90
- type: :string
91
- opt :specs, "The directory to find ServerSpecs", type: :string, required: true
92
- opt :subnet_id, "The subnet to start the instance in", type: :string, required: true
93
- opt :key_name, "The SSH key name to assign to instances", type: :string, required: true
94
- opt :key_file, "The SSH private key file associated to the key_name", type: :string, required: true
95
- opt :ssh_user, "The user to ssh to the instance as", type: :string, required: true
96
- opt :aws_region, "The AWS region, defaults to AWS_DEFAULT_REGION environment variable", type: :string
97
- opt :aws_instance_type, "The ec2 instance type, defaults to t2.micro", type: :string, default: 't2.micro'
98
- opt :aws_security_groups, "Security groups to associate to the launched instances. May be specified multiple times",
99
- type: :strings, default: nil
100
- opt :aws_public_ip, "Launch instances with a public IP"
101
- opt :ssh_retries, "The number of times we should try sshing to the ec2 instance before giving up. Defaults to 30",
102
- type: :int, default: 30
103
- 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: ""
104
- opt :debug, "Don't terminate instances on exit"
105
- opt :buildkite, "Output section separators for buildkite"
106
- opt :wait_for_rc, "Wait for oldschool SystemV scripts to run before conducting tests. Currently only supports Ubuntu with upstart"
107
- opt :user_data_file, "File path for aws ec2 user data", type: :string, default: nil
108
- opt :iam_instance_profile_arn, "IAM instance profile to use", type: :string
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
- unless File.exist? options[:key_file]
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
 
@@ -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
@@ -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, :terminate, :private_ip_address, :public_ip_address
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
@@ -28,11 +28,15 @@ module AmiSpec
28
28
  end
29
29
 
30
30
  $LOAD_PATH.unshift(@spec) unless $LOAD_PATH.include?(@spec)
31
- require File.join(@spec, 'spec_helper')
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], :paranoid => false
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
 
@@ -1,3 +1,3 @@
1
1
  module AmiSpec
2
- VERSION = '1.1.0'
2
+ VERSION = '1.7.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
@@ -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], paranoid: false, port: port) do |ssh|
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], paranoid: false) { |ssh| ssh.exec 'echo boo!' }
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.1.0
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: 2018-08-03 00:00:00.000000000 Z
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: '2'
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: '2'
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: :runtime
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: '0'
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: '0'
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: trollop
71
+ name: optimist
72
72
  requirement: !ruby/object:Gem::Requirement
73
73
  requirements:
74
- - - ">="
74
+ - - "~>"
75
75
  - !ruby/object:Gem::Version
76
- version: '0'
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: '0'
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: '3.0'
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: '3.0'
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: '0'
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
- rubyforge_project:
169
- rubygems_version: 2.7.6
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
@@ -1,2 +0,0 @@
1
- Gemfile.lock
2
- *.gem
data/.ruby-version DELETED
@@ -1 +0,0 @@
1
- 1.9.3-p551
data/.travis.yml DELETED
@@ -1,6 +0,0 @@
1
- language: ruby
2
- rvm:
3
- - 1.9.3
4
- - 2.1.8
5
- - 2.2.4
6
- script: bundle exec rake spec
data/Gemfile DELETED
@@ -1,3 +0,0 @@
1
- source 'https://rubygems.org'
2
-
3
- gemspec
data/Rakefile DELETED
@@ -1,8 +0,0 @@
1
- require "bundler/gem_tasks"
2
- require "rspec/core/rake_task"
3
-
4
- RSpec::Core::RakeTask.new(:spec) do |t|
5
- t.rspec_opts = "--tag ~integration"
6
- end
7
-
8
- task :default => :spec
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
@@ -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
@@ -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,9 +0,0 @@
1
- FROM amazonlinux:1
2
-
3
- RUN yum install -y upstart openssh-server && yum clean all
4
- ADD rc.conf /etc/init/rc.conf
5
-
6
- COPY ami-spec.pub /root/.ssh/authorized_keys
7
- COPY sshd_config /etc/ssh/sshd_config
8
-
9
- CMD ["/bin/bash", "-c", "exec /sbin/init"]
@@ -1,8 +0,0 @@
1
- FROM ubuntu-upstart:trusty
2
-
3
- ENV DEBIAN_FRONTEND noninteractive
4
- RUN apt-get update && apt-get install -y openssh-server && apt-get clean
5
-
6
- COPY ami-spec.pub /root/.ssh/authorized_keys
7
-
8
- EXPOSE 22
@@ -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"]
@@ -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.
@@ -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"
@@ -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
@@ -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
@@ -1,2 +0,0 @@
1
- $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
2
- require 'ami_spec'
@@ -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
@@ -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