aws_pocketknife 0.1.7

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.
Files changed (53) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +11 -0
  3. data/.rspec +2 -0
  4. data/.ruby-gemset +1 -0
  5. data/.ruby-version +1 -0
  6. data/.travis.yml +1 -0
  7. data/CODE_OF_CONDUCT.md +49 -0
  8. data/Gemfile +4 -0
  9. data/LICENSE.txt +21 -0
  10. data/README.md +115 -0
  11. data/Rakefile +22 -0
  12. data/aws_pocketknife.gemspec +40 -0
  13. data/bin/console +14 -0
  14. data/bin/setup +8 -0
  15. data/cert/ca-bundle.crt +3988 -0
  16. data/exe/pocketknife +5 -0
  17. data/lib/aws_pocketknife.rb +88 -0
  18. data/lib/aws_pocketknife/admin/policies/developer_dev_acc.json +10 -0
  19. data/lib/aws_pocketknife/admin/policies/developer_prd_acc.json +15 -0
  20. data/lib/aws_pocketknife/admin/policies/tc_devops.json.erb +207 -0
  21. data/lib/aws_pocketknife/admin/policies/tester_dev_acc.json +176 -0
  22. data/lib/aws_pocketknife/admin/policies/tester_prd_acc.json +176 -0
  23. data/lib/aws_pocketknife/admin/policies/web_front_end.json.erb +59 -0
  24. data/lib/aws_pocketknife/admin/trust_relationships/ec2.json +13 -0
  25. data/lib/aws_pocketknife/asg.rb +56 -0
  26. data/lib/aws_pocketknife/cli/ami.rb +24 -0
  27. data/lib/aws_pocketknife/cli/asg.rb +40 -0
  28. data/lib/aws_pocketknife/cli/eb.rb +49 -0
  29. data/lib/aws_pocketknife/cli/ec2.rb +61 -0
  30. data/lib/aws_pocketknife/cli/elb.rb +20 -0
  31. data/lib/aws_pocketknife/cli/iam.rb +31 -0
  32. data/lib/aws_pocketknife/cli/main.rb +34 -0
  33. data/lib/aws_pocketknife/cli/rds.rb +13 -0
  34. data/lib/aws_pocketknife/cli/rds_snapshot.rb +44 -0
  35. data/lib/aws_pocketknife/cli/route53.rb +56 -0
  36. data/lib/aws_pocketknife/cloudwatch_logs.rb +25 -0
  37. data/lib/aws_pocketknife/common/logging.rb +31 -0
  38. data/lib/aws_pocketknife/common/utils.rb +63 -0
  39. data/lib/aws_pocketknife/ec2.rb +308 -0
  40. data/lib/aws_pocketknife/elastic_beanstalk.rb +62 -0
  41. data/lib/aws_pocketknife/elb.rb +25 -0
  42. data/lib/aws_pocketknife/iam.rb +135 -0
  43. data/lib/aws_pocketknife/rds.rb +84 -0
  44. data/lib/aws_pocketknife/route53.rb +234 -0
  45. data/lib/aws_pocketknife/tasks/asg.rake +18 -0
  46. data/lib/aws_pocketknife/tasks/cloudwatch.rake +12 -0
  47. data/lib/aws_pocketknife/tasks/ec2.rake +57 -0
  48. data/lib/aws_pocketknife/tasks/elastic_beanstalk.rake +25 -0
  49. data/lib/aws_pocketknife/tasks/elb.rake +13 -0
  50. data/lib/aws_pocketknife/tasks/iam.rake +57 -0
  51. data/lib/aws_pocketknife/tasks/route53.rake +64 -0
  52. data/lib/aws_pocketknife/version.rb +3 -0
  53. metadata +284 -0
@@ -0,0 +1,20 @@
1
+ require "thor"
2
+ require "aws_pocketknife"
3
+
4
+ module AwsPocketknife
5
+ module Cli
6
+ class Elb < Thor
7
+
8
+ desc "desc ELB_NAME", "describe elastic load balancer"
9
+ def desc(elb_name)
10
+ elb = AwsPocketknife::Elb.describe_elb_by_name(name: elb_name)
11
+ if elb.nil?
12
+ puts "ELB #{elb_name} not found"
13
+ else
14
+ AwsPocketknife::Ec2.nice_print(object: elb.to_h)
15
+ end
16
+ end
17
+
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,31 @@
1
+ require "thor"
2
+ require "aws_pocketknife"
3
+
4
+ module AwsPocketknife
5
+ module Cli
6
+ class Iam < Thor
7
+
8
+ desc "list_ssl_certs", "list ssl certs"
9
+ def list_ssl_certs
10
+ certs = AwsPocketknife::Iam.list_ssl_certificates
11
+ AwsPocketknife::Iam.nice_print(object: certs.to_h)
12
+ end
13
+
14
+ desc "create_user USERNAME", "create user"
15
+ def create_user(username)
16
+ AwsPocketknife::Iam.create_iam_user username
17
+ end
18
+
19
+ desc "create_group GROUP_NAME", "create group"
20
+ def create_group(group_name)
21
+ AwsPocketknife::Iam.create_group group_name
22
+ end
23
+
24
+ desc "add_user_to_group USERNAME GROUP_NAME", "add user to group"
25
+ def add_user_to_group(username, group_name)
26
+ AwsPocketknife::Iam.add_user_to_group username, group_name
27
+ end
28
+
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,34 @@
1
+ require "thor"
2
+ require "aws_pocketknife"
3
+
4
+ module AwsPocketknife
5
+ module Cli
6
+ class Main < Thor
7
+
8
+ desc "ec2 SUBCOMMAND ...ARGS", "ec2 command lines"
9
+ subcommand "ec2", AwsPocketknife::Cli::Ec2
10
+
11
+ desc "ami SUBCOMMAND ...ARGS", "ami command lines"
12
+ subcommand "ami", AwsPocketknife::Cli::Ami
13
+
14
+ desc "eb SUBCOMMAND ...ARGS", "elastic beanstalk command lines"
15
+ subcommand "eb", AwsPocketknife::Cli::Eb
16
+
17
+ desc "route53 SUBCOMMAND ...ARGS", "route53 command lines"
18
+ subcommand "route53", AwsPocketknife::Cli::Route53
19
+
20
+ desc "iam SUBCOMMAND ...ARGS", "iam command lines"
21
+ subcommand "iam", AwsPocketknife::Cli::Iam
22
+
23
+ desc "rds SUBCOMMAND ...ARGS", "rds command lines"
24
+ subcommand "rds", AwsPocketknife::Cli::Rds
25
+
26
+ desc "asg SUBCOMMAND ...ARGS", "asg command lines"
27
+ subcommand "asg", AwsPocketknife::Cli::Asg
28
+
29
+ desc "elb SUBCOMMAND ...ARGS", "elb command lines"
30
+ subcommand "elb", AwsPocketknife::Cli::Elb
31
+
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,13 @@
1
+ require "thor"
2
+ require "aws_pocketknife"
3
+
4
+ module AwsPocketknife
5
+ module Cli
6
+ class Rds < Thor
7
+
8
+ desc "snapshot SUBCOMMAND ...ARGS", "snapshot command lines"
9
+ subcommand "snapshot", AwsPocketknife::Cli::RdsSnapshot
10
+
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,44 @@
1
+ require "thor"
2
+ require "aws_pocketknife"
3
+
4
+ module AwsPocketknife
5
+ module Cli
6
+ class RdsSnapshot < Thor
7
+
8
+ desc "list_snapshots DB_NAME", "list snapshots"
9
+ def list(db_name)
10
+ snapshots = AwsPocketknife::Rds.describe_snapshots(db_name: db_name)
11
+ headers = [ 'Name', 'Creation Time', 'Snapshot Type', 'Status','Port', 'Engine', 'Version', 'Storage (Gb)', 'IOPS']
12
+ data = []
13
+ snapshots.each do |h|
14
+ data << [h.db_snapshot_identifier,
15
+ h.snapshot_create_time,
16
+ h.snapshot_type,
17
+ h.status,
18
+ h.port,
19
+ h.engine,
20
+ h.engine_version,
21
+ h.allocated_storage,
22
+ h.iops
23
+ ]
24
+ end
25
+ AwsPocketknife::Rds.pretty_table(headers: headers, data: data)
26
+ end
27
+
28
+ desc "clean DB_NAME DAYS --dry_run", "Remove manual snapshots with creation time lower than DAYS for database_name."
29
+ option :dry_run, :type => :boolean, :default => true, :desc => 'just show images that would be deleted'
30
+ def clean(db_name, days)
31
+ dry_run = options.fetch("dry_run", true)
32
+ AwsPocketknife::Rds.clean_snapshots db_name: db_name,
33
+ days: days,
34
+ dry_run: dry_run
35
+ end
36
+
37
+ desc "create DB_NAME", "Creates a snapshot for database_name."
38
+ def create(db_name)
39
+ AwsPocketknife::Rds.create_snapshot db_name: db_name
40
+ end
41
+
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,56 @@
1
+ require "thor"
2
+ require "aws_pocketknife"
3
+
4
+ module AwsPocketknife
5
+ module Cli
6
+ class Route53 < Thor
7
+
8
+ desc "describe_hosted_zone HOSTED_ZONE", "describe hosted zone"
9
+ def describe_hosted_zone(hosted_zone)
10
+ hosted_zone = AwsPocketknife::Route53.describe_hosted_zone(hosted_zone: hosted_zone)
11
+ unless hosted_zone.nil?
12
+ AwsPocketknife::Route53.nice_print(object: hosted_zone.to_h)
13
+ else
14
+ puts "#{hosted_zone} not found"
15
+ end
16
+ end
17
+
18
+ desc "list", "list hosted zones"
19
+ def list
20
+ hosted_zones = AwsPocketknife::Route53.list_hosted_zones
21
+ headers = [ 'Name', 'Zone ID', 'Comment']
22
+ data = []
23
+ hosted_zones.each do |h|
24
+ data << [h.name,
25
+ AwsPocketknife::Route53.get_hosted_zone_id(hosted_zone: h.id),
26
+ h.config.comment]
27
+ end
28
+ AwsPocketknife::Route53.pretty_table(headers: headers, data: data)
29
+ end
30
+
31
+ desc "list_records HOSTED_ZONE", "list records for hosted zone"
32
+ def list_records(hosted_zone)
33
+ records = AwsPocketknife::Route53.list_records_for_zone_name(hosted_zone_name: hosted_zone)
34
+ headers = ["Name", "Type", "DNS Name"]
35
+ data = []
36
+ if records.length > 0
37
+ records.each do |record|
38
+ if record.type == 'CNAME'
39
+ data << [record.name, record.type, record.resource_records[0].value]
40
+ else
41
+ if record.alias_target.nil?
42
+ data << [record.name, record.type, "N/A"]
43
+ else
44
+ data << [record.name, record.type, record.alias_target.dns_name]
45
+ end
46
+ end
47
+ end
48
+ AwsPocketknife::Route53.pretty_table(headers: headers, data: data)
49
+ else
50
+ puts "No records found hosted zone #{hosted_zone}"
51
+ end
52
+ end
53
+
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,25 @@
1
+ require 'aws_pocketknife'
2
+ require 'base64'
3
+ require 'openssl'
4
+ require 'recursive-open-struct'
5
+
6
+ module AwsPocketknife
7
+ module CloudwatchLogs
8
+
9
+ class << self
10
+ include AwsPocketknife::Common::Utils
11
+
12
+ def create_log_group(log_group_name: "")
13
+
14
+ unless log_group_name.empty?
15
+ cloudwatch_logs_client.create_log_group({
16
+ log_group_name: log_group_name, # required
17
+ })
18
+ end
19
+
20
+ end
21
+
22
+ end
23
+
24
+ end
25
+ end
@@ -0,0 +1,31 @@
1
+ require 'log4r'
2
+
3
+ module AwsPocketknife
4
+ module Common
5
+ module Logging
6
+
7
+ include Log4r
8
+ Logger = Log4r::Logger
9
+ Log4r::Logger.root.level = Log4r::INFO
10
+
11
+ class << self
12
+
13
+ def logger
14
+ @log ||= initialize_log
15
+ end
16
+
17
+ def initialize_log(name: "aws_pocketknife", pattern: "[%l] %d %m")
18
+ log = Logger.new(name)
19
+
20
+ log_format = Log4r::PatternFormatter.new(:pattern => pattern)
21
+ log_output = Log4r::StdoutOutputter.new 'console'
22
+ log_output.formatter = log_format
23
+ log.add(log_output)
24
+
25
+ return log
26
+ end
27
+
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,63 @@
1
+ require "pretty_table"
2
+ require "awesome_print"
3
+ require_relative "logging"
4
+
5
+ module AwsPocketknife
6
+ module Common
7
+ module Utils
8
+ #include AwsPocketknife::Common::Logging
9
+
10
+ def ec2_client
11
+ @ec2_client ||= AwsPocketknife.ec2_client
12
+ end
13
+
14
+ def iam_client
15
+ @iam_client ||= AwsPocketknife.iam_client
16
+ end
17
+
18
+ def route53_client
19
+ @route53_client ||= AwsPocketknife.route53_client
20
+ end
21
+
22
+ def rds_client
23
+ @rds_client ||= AwsPocketknife.rds_client
24
+ end
25
+
26
+ def elb_client
27
+ @elb_client ||= AwsPocketknife.elb_client
28
+ end
29
+
30
+ def asg_client
31
+ @asg_client ||= AwsPocketknife.asg_client
32
+ end
33
+
34
+ def cloudwatch_logs_client
35
+ @cloudwatch_logs_client ||= AwsPocketknife.cloudwatch_logs_client
36
+ end
37
+
38
+ def elastic_beanstalk_client
39
+ @elastic_beanstalk_client ||= AwsPocketknife.elastic_beanstalk_client
40
+ end
41
+
42
+ def pretty_table(headers: [], data: [])
43
+ puts PrettyTable.new(data, headers).to_s
44
+ end
45
+
46
+ # https://github.com/michaeldv/awesome_print
47
+ def nice_print(object: nil)
48
+ ap object
49
+ end
50
+
51
+ def get_tag_value(tags: [], tag_key: "")
52
+ unless tags.empty? or tag_key.length == 0
53
+ tag = tags.select { |tag| tag.key == tag_key }
54
+ return tag[0].value if tag.length == 1
55
+ return "" if tag.length == 0
56
+ else
57
+ return ""
58
+ end
59
+ end
60
+
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,308 @@
1
+ require 'aws_pocketknife'
2
+ require 'base64'
3
+ require 'openssl'
4
+ require 'retryable'
5
+ require 'recursive-open-struct'
6
+
7
+ module AwsPocketknife
8
+ module Ec2
9
+
10
+ MAX_ATTEMPTS = 15
11
+ DELAY_SECONDS = 10
12
+
13
+ STATE_PENDING = 'pending'
14
+ STATE_AVAILABLE = 'available'
15
+ STATE_DEREGISTERED = 'deregistered'
16
+ STATE_INVALID = 'invalid'
17
+ STATE_FAILED = 'failed'
18
+ STATE_ERROR = 'error'
19
+
20
+ class << self
21
+ include AwsPocketknife::Common::Utils
22
+ #include AwsPocketknife::Common::Logging
23
+
24
+ Logging = Common::Logging.logger
25
+
26
+ def find_ami_by_name(name: '')
27
+ ec2_client.describe_images({dry_run: false,
28
+ filters: [
29
+ {
30
+ name: "tag:Name",
31
+ values: [name]
32
+ }
33
+ ]}).images
34
+ end
35
+
36
+ def find_ami_by_id(id: '')
37
+ ec2_client.describe_images({dry_run: false,
38
+ image_ids: [id]}).images.first
39
+ end
40
+
41
+ def delete_ami_by_id(id: '')
42
+ image = find_ami_by_id(id: id)
43
+ snapshot_ids = snapshot_ids(image)
44
+ ec2_client.deregister_image(image_id: id)
45
+
46
+ Retryable.retryable(:tries => 20, :sleep => lambda { |n| 2**n }, :on => StandardError) do |retries, exception|
47
+ image = find_ami_by_id(id: id)
48
+ message = "retry #{retries} - Deleting image #{id}"
49
+ message << " State: #{image.state}" if image
50
+ Logging.info message
51
+ raise StandardError unless image.nil?
52
+ end
53
+
54
+ delete_snapshots(snapshot_ids: snapshot_ids)
55
+ end
56
+
57
+ def delete_snapshots(snapshot_ids: [])
58
+ snapshot_ids.each do |snapshot_id|
59
+ Logging.info "Deleting Snapshot: #{snapshot_id}"
60
+ ec2_client.delete_snapshot(snapshot_id: snapshot_id)
61
+ end
62
+ end
63
+
64
+ def snapshot_ids(image)
65
+ snapshot_ids = []
66
+ image.block_device_mappings.each do |device_mapping|
67
+ ebs = device_mapping.ebs
68
+ snapshot_ids << ebs.snapshot_id if ebs && !ebs.snapshot_id.to_s.empty?
69
+ end
70
+ snapshot_ids
71
+ end
72
+
73
+ def clean_ami(options)
74
+ Logging.info "options: #{options}"
75
+
76
+ dry_run = options.fetch(:dry_run, true)
77
+ image_ids = find_ami_by_creation_time(options)
78
+ images_to_delete = find_unused_ami(image_ids: image_ids)
79
+
80
+ Logging.info "images (#{image_ids.length}): #{image_ids}"
81
+ Logging.info "images to delete (#{images_to_delete.length}): #{images_to_delete}"
82
+
83
+ unless dry_run
84
+ images_to_delete.each do |image_id|
85
+ Logging.info "deleting image #{image_id}"
86
+ delete_ami_by_id(id: image_id)
87
+ end
88
+ end
89
+
90
+ end
91
+
92
+ def find_unused_ami(image_ids: [])
93
+ images_to_delete = []
94
+ image_ids.each do |image_id|
95
+ # check if there is any instance using the image id
96
+ instances = describe_instances_by_image_id(image_id_list: [image_id])
97
+ if instances.empty?
98
+ images_to_delete << image_id
99
+ else
100
+ Logging.info "#{image_id} is used by instance #{instances.map { |instance| instance.instance_id }}"
101
+ end
102
+ Kernel.sleep 2
103
+ end
104
+ return images_to_delete
105
+ end
106
+
107
+ def find_ami_by_creation_time(options)
108
+
109
+ days = options.fetch(:days, '30').to_i * 24 * 3600
110
+ creation_time = Time.now-days
111
+ Logging.info "Cleaning up images older than #{days} days, i.e, with creation_time < #{creation_time})"
112
+
113
+ image_ids = []
114
+ images = find_ami_by_name(name: options.fetch(:ami_name_pattern, ''))
115
+ images.each do |image|
116
+ image_creation_time = Time.parse(image.creation_date)
117
+ msg = "image #{image.image_id} (#{creation_time}) < (image_creation_time: #{image_creation_time})? "
118
+ if creation_time <= image_creation_time
119
+ image_ids << image.image_id
120
+ msg << "YES, marking to be deleted"
121
+ else
122
+ msg << "NO"
123
+ end
124
+ Logging.info msg
125
+ end
126
+ return image_ids
127
+ end
128
+
129
+ def share_ami(image_id: '', user_id: '', options: {})
130
+ begin
131
+ options = {}
132
+ options[:image_id] = image_id
133
+ options[:launch_permission] = create_launch_permission(user_id)
134
+ Logging.info "Sharing Image #{image_id} with #{user_id} with options #{options}"
135
+ response = @ec2_client.modify_image_attribute(options=options)
136
+ return response
137
+ rescue Exception => e
138
+ Logging.error "## Got an error when sharing the image... #{e.cause} -> #{e.message}"
139
+ raise
140
+ end
141
+ end
142
+
143
+
144
+ def create_image(instance_id: "", name: "", description: "Created at #{Time.now}",
145
+ timeout: 1800, publish_to_account: "",
146
+ volume_type: "gp2",
147
+ iops: 3,
148
+ encrypted: false,
149
+ volume_size: 60
150
+ )
151
+
152
+ begin
153
+ Logging.info "creating image"
154
+ instance = find_by_id(instance_id: instance_id)
155
+ instance = ec2.instances[instance_id]
156
+ image = instance.create_image(name, :description => description)
157
+ sleep 2 until image.exists?
158
+ Logging.info "image #{image.id} state: #{image.state}"
159
+ sleep 10 until image.state != :pending
160
+ if image.state == :failed
161
+ raise "Create image failed"
162
+ end
163
+ Logging.info "image created"
164
+ rescue => e
165
+ Logging.error "Creating AMI failed #{e.message}"
166
+ Logging.error e.backtrace.join("\n")
167
+ raise e
168
+ end
169
+ if publish_to_account.length != 0
170
+ Logging.info "add permissions for #{publish_to_account}"
171
+ image.permissions.add(publish_to_account.gsub(/-/, ''))
172
+ end
173
+ image.id.tap do |image_id|
174
+ Logging.info "Image #{@name}[#{image_id}] created"
175
+ return image_id
176
+ end
177
+ end
178
+
179
+ def stop_instance_by_id(instance_ids)
180
+ instance_id_list = get_instance_id_list(instance_ids: instance_ids)
181
+ Logging.info "Stoping instance id: #{instance_id_list}"
182
+ resp = ec2_client.stop_instances({ instance_ids: instance_id_list })
183
+ wait_till_instance_is_stopped(instance_id_list, max_attempts: MAX_ATTEMPTS, delay_seconds: DELAY_SECONDS)
184
+ Logging.info "Stopped ec2 instance #{instance_id_list}"
185
+ end
186
+
187
+ def start_instance_by_id(instance_ids)
188
+ instance_id_list = get_instance_id_list(instance_ids: instance_ids)
189
+ Logging.info "Start instance id: #{instance_id_list}"
190
+ ec2_client.start_instances({ instance_ids: instance_id_list })
191
+ end
192
+
193
+ # http://serverfault.com/questions/560337/search-ec2-instance-by-its-name-from-aws-command-line-tool
194
+ def find_by_name(name: "")
195
+ instances = []
196
+ resp = ec2_client.describe_instances({dry_run: false,
197
+ filters: [
198
+ {
199
+ name: "tag:Name",
200
+ values: [name]
201
+ }
202
+ ]})
203
+ resp.reservations.each do |reservation|
204
+ reservation.instances.each do |instance|
205
+ instances << instance
206
+ end
207
+ end
208
+ instances
209
+ end
210
+
211
+ def describe_instances_by_image_id(image_id_list: [])
212
+ instances = []
213
+ resp = ec2_client.describe_instances({dry_run: false,
214
+ filters: [
215
+ {
216
+ name: "image-id",
217
+ values: image_id_list
218
+ }
219
+ ]})
220
+ resp.reservations.each do |reservation|
221
+ reservation.instances.each do |instance|
222
+ instances << instance
223
+ end
224
+ end
225
+ instances
226
+ end
227
+
228
+ def find_by_id(instance_id: "")
229
+ resp = ec2_client.describe_instances({dry_run: false, instance_ids: [instance_id.to_s]})
230
+ if resp.nil? or resp.reservations.length == 0 or resp.reservations[0].instances.length == 0
231
+ return nil
232
+ else
233
+ return resp.reservations.first.instances.first
234
+ end
235
+ end
236
+
237
+ def get_windows_password(instance_id: "")
238
+
239
+ private_keyfile_dir = ENV["AWS_POCKETKNIFE_KEYFILE_DIR"] || ""
240
+ raise "Environment variable AWS_POCKETKNIFE_KEYFILE_DIR is not defined" if private_keyfile_dir.length == 0
241
+
242
+ instance = find_by_id(instance_id: instance_id)
243
+ key_name = instance.key_name
244
+ private_keyfile = File.join(private_keyfile_dir, "#{key_name}.pem")
245
+ raise "File #{private_keyfile} not found" unless File.exist?(private_keyfile)
246
+
247
+ resp = ec2_client.get_password_data({dry_run: false,
248
+ instance_id: instance_id})
249
+ encrypted_password = resp.password_data
250
+ decrypted_password = decrypt_windows_password(encrypted_password, private_keyfile)
251
+
252
+ RecursiveOpenStruct.new({password: decrypted_password,
253
+ instance_id: instance.instance_id,
254
+ private_ip_address: instance.private_ip_address,
255
+ public_ip_address: instance.public_ip_address}, recurse_over_arrays: true)
256
+ end
257
+
258
+ # def ec2
259
+ # @ec2 ||= Aws::EC2.new(:ec2_endpoint => "ec2.#{AwsPocketknife::AWS_REGION}.amazonaws.com")
260
+ # end
261
+
262
+ private
263
+
264
+ def create_launch_permission(user_id)
265
+ {
266
+ add: [
267
+ {
268
+ user_id: user_id
269
+ },
270
+ ]
271
+ }
272
+ end
273
+
274
+ # Decrypts an encrypted password using a provided RSA
275
+ # private key file (PEM-format).
276
+ def decrypt_windows_password(encrypted_password, private_keyfile)
277
+ encrypted_password_bytes = Base64.decode64(encrypted_password)
278
+ private_keydata = File.open(private_keyfile, "r").read
279
+ private_key = OpenSSL::PKey::RSA.new(private_keydata)
280
+ private_key.private_decrypt(encrypted_password_bytes)
281
+ end
282
+
283
+ def get_instance_id_list(instance_ids: "")
284
+ instance_ids.strip.split(";")
285
+ end
286
+
287
+ def wait_till_instance_is_stopped(instance_ids, max_attempts: 12, delay_seconds: 10)
288
+ total_wait_seconds = max_attempts * delay_seconds;
289
+ Logging.info "Waiting up to #{total_wait_seconds} seconds with #{delay_seconds} seconds delay for ec2 instance #{instance_ids} to be stopped"
290
+ ec2_client.wait_until(:instance_stopped, { instance_ids: instance_ids }) do |w|
291
+ w.max_attempts = max_attempts
292
+ w.delay = delay_seconds
293
+ end
294
+ end
295
+
296
+ def wait_till_instance_is_terminated(instance_ids, max_attempts: 12, delay_seconds: 10)
297
+ total_wait_seconds = max_attempts * delay_seconds;
298
+ Logging.info "Waiting up to #{total_wait_seconds} seconds with #{delay_seconds} seconds delay for ec2 instance #{instance_ids} to be terminated"
299
+ ec2_client.wait_until(:instance_terminated, { instance_ids: instance_ids }) do |w|
300
+ w.max_attempts = max_attempts
301
+ w.delay = delay_seconds
302
+ end
303
+ end
304
+
305
+ end
306
+
307
+ end
308
+ end