Module: AmiSpec
- Defined in:
- lib/ami_spec.rb,
lib/ami_spec/version.rb,
lib/ami_spec/server_spec.rb,
lib/ami_spec/wait_for_rc.rb,
lib/ami_spec/aws_instance.rb,
lib/ami_spec/aws_key_pair.rb,
lib/ami_spec/wait_for_ssh.rb,
lib/ami_spec/aws_default_vpc.rb,
lib/ami_spec/aws_security_group.rb,
lib/ami_spec/server_spec_options.rb,
lib/ami_spec/wait_for_cloud_init.rb,
lib/ami_spec/aws_instance_options.rb
Defined Under Namespace
Classes: AwsDefaultVpc, AwsInstance, AwsInstanceOptions, AwsKeyPair, AwsSecurityGroup, InstanceConnectionTimeout, ServerSpec, ServerSpecOptions, WaitForCloudInit, WaitForRC, WaitForSSH
Constant Summary collapse
- VERSION =
'1.8.2'
Class Method Summary collapse
- .invoke ⇒ Object
- .parse_tags(tags) ⇒ Object
-
.run(options) ⇒ Object
Parameters: amis:: A hash of roles and amis in the format of: => ami_id.
Class Method Details
.invoke ⇒ Object
132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 |
# File 'lib/ami_spec.rb', line 132 def self.invoke = Optimist:: do opt :role, 'The role to test, this should map to a directory in the spec folder', type: :string, short: :r opt :ami, 'The ami ID to run tests against', type: :string, short: :a opt :role_ami_file, 'A file containing comma separated roles and amis. i.e. web_server,ami-id.', type: :string, short: :o opt :specs, 'The directory to find ServerSpecs', type: :string, required: true, short: :s opt :subnet_id, 'The subnet to start the instance in. If not provided a subnet will be chosen from the default VPC', type: :string, short: :u opt :key_name, 'The SSH key name to assign to instances. If not provided a temporary key pair will be generated in AWS', type: :string, short: :k opt :key_file, 'The SSH private key file associated to the key_name', type: :string, short: :e opt :ssh_user, 'The user to ssh to the instance as', type: :string, required: true, short: :h opt :aws_region, 'The AWS region, defaults to AWS_DEFAULT_REGION environment variable', type: :string, short: :w opt :aws_instance_type, 'The ec2 instance type, defaults to t2.micro', type: :string, default: 't2.micro', short: :i 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', type: :string, default: nil, multi: true, short: :c opt :allow_any_temporary_security_group, 'The temporary security group will allow SSH connections from any IP address (0.0.0.0/0)', short: :n opt :aws_public_ip, 'Launch instances with a public IP and use that IP for SSH', short: :p opt :associate_public_ip, "Launch instances with a public IP but don't use that IP for SSH", short: :q opt :ssh_retries, 'The number of times we should try sshing to the ec2 instance before giving up. Defaults to 30', type: :int, default: 30, short: :t 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: '', short: :g opt :debug, "Don't terminate instances on exit", short: :d opt :buildkite, 'Output section separators for buildkite', short: :b opt :wait_for_rc, 'Wait for oldschool SystemV scripts to run before conducting tests. Currently only supports Ubuntu with upstart', short: :f opt :wait_for_cloud_init, 'Wait for Cloud Init to complete before running tests' opt :user_data_file, 'File path for aws ec2 user data', type: :string, default: nil, short: :l opt :iam_instance_profile_arn, 'IAM instance profile to use', type: :string, short: :m end if [:role] && [:ami] [:amis] = { [:role] => [:ami] } .delete(:role) .delete(:ami) elsif [:role_ami_file] file_lines = File.read([:role_ami_file]).split("\n") file_array = file_lines.collect { |line| line.split(',') }.flatten [:amis] = Hash[*file_array] .delete(:role_ami_file) else fail "You must specify either role and ami or role_ami_file" end fail "Key file #{[:key_file]} not found" if [:key_name] && !File.exist?(.fetch(:key_file)) if [:user_data_file] and !File.exist? [:user_data_file] fail "User Data file #{[:user_data_file]} not found" end [:tags] = ([:tags]) [:amis].each_pair do |role, _| unless Dir.exist?("#{[:specs]}/#{role}") fail "Role directory #{[: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)." end end exit run() end |
.parse_tags(tags) ⇒ Object
205 206 207 208 209 |
# File 'lib/ami_spec.rb', line 205 def self.() tag_pairs = .split(',') tag_key_values = tag_pairs.collect{ |pair| pair.split('=')}.flatten Hash[*tag_key_values] end |
.run(options) ⇒ Object
Parameters:
- amis
-
A hash of roles and amis in the format of: => ami_id. i.e. => ‘ami-abcd1234’
- specs
-
A string of the directory to find ServerSpecs. There should be a folder in this directory for each role found in ::amis
- subnet_id
-
The subnet_id to start instances in.
- key_name
-
The SSH key name to assign to instances. If not provided a temporary key pair will be generated in AWS
- key_file
-
The SSH key file to use to connect to the host.
- aws_region
-
AWS region to connect to Defaults to AWS_DEFAULT_REGION
- aws_security_group_ids
-
AWS Security groups to assign to the instances If not provided a temporary security group will be generated in AWS
- allow_any_temporary_security_group
-
The temporary security group will allow SSH connections from any IP address (0.0.0.0/0)
- aws_instance_type
-
AWS ec2 instance type
- aws_public_ip
-
Should the instances get a public IP address and use that IP for SSH
- associate_public_ip
-
Launch instances with a public IP but don’t use that IP for SSH
- ssh_user
-
The username to SSH to the AMI with.
- ssh_retries
-
Set the maximum number of ssh retries while waiting for the instance to boot.
- tags:
-
Additional tags to add to launched instances in the form of comma separated key=value pairs
- debug
-
Don’t terminate the instances on exit
- buildkite
-
Output section separators for buildkite
Returns:
Boolean - The result of all the server specs.
56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 |
# File 'lib/ami_spec.rb', line 56 def self.run() logger = Logger.new(STDOUT, formatter: proc { |_sev, _time, _name, | "#{}\n" }) ec2 = Aws::EC2::Resource.new([:aws_region] ? {region: [:aws_region]} : {}) if [:subnet_id].nil? default_vpc_subnet = AwsDefaultVpc.find_subnet(ec2: ec2) raise 'No default VPC subnet found. Please specify a subnet id.' if default_vpc_subnet.nil? [:subnet_id] = default_vpc_subnet.id logger.info("Using subnet #{[:subnet_id]} from the default VPC") end unless [:key_name] key_pair = AwsKeyPair.create(ec2: ec2, logger: logger) [:key_name] = key_pair.key_name [:key_file] = key_pair.key_file end if [:aws_security_groups].nil? || [:aws_security_groups].empty? temporary_security_group = AwsSecurityGroup.create( ec2: ec2, subnet_id: [:subnet_id], allow_any_ip: [:allow_any_temporary_security_group], logger: logger ) [:aws_security_groups] = [temporary_security_group.group_id] end instances = [] [:amis].each_pair do |role, ami| = AwsInstanceOptions.new(.merge(role: role, ami: ami, logger: logger)) instances << AwsInstance.start() end results = [] instances.each do |instance| ip_address = [:aws_public_ip] ? instance.public_ip_address : instance.private_ip_address logger.info("Waiting for SSH…") WaitForSSH.wait(ip_address, [:ssh_user], [:key_file], [:ssh_retries]) if [:wait_for_rc] logger.info("Waiting for RC…") WaitForRC.wait(ip_address, [:ssh_user], [:key_file]) end if [:wait_for_cloud_init] logger.info("Waiting for cloud init…") WaitForCloudInit.wait(ip_address, [:ssh_user], [:key_file]) end logger.info("Running serverspec…") = ServerSpecOptions.new(.merge(instance: instance)) results << ServerSpec.new().run end results.all? ensure stop_instances(instances, [:debug]) key_pair.delete if key_pair temporary_security_group.delete if temporary_security_group end |