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,62 @@
1
+ require 'aws_pocketknife'
2
+
3
+ module AwsPocketknife
4
+ module ElasticBeanstalk
5
+
6
+ class << self
7
+ include AwsPocketknife::Common::Utils
8
+
9
+ def describe_environment_resources(environment_name: '')
10
+ elastic_beanstalk_client.describe_environment_resources({
11
+ environment_name: environment_name,
12
+ })
13
+ end
14
+
15
+ def list_environments()
16
+ describe_environment
17
+ end
18
+
19
+ def describe_environment(environment_name: '')
20
+ resp = nil
21
+ if environment_name.length == 0
22
+ resp = elastic_beanstalk_client.describe_environments({})
23
+ else
24
+ environment_list = environment_name.split(";")
25
+ resp = elastic_beanstalk_client.describe_environments({
26
+ environment_names: environment_list,
27
+ })
28
+ end
29
+
30
+ resp[:environments]
31
+ end
32
+
33
+ def list_environment_variables(environment_name: '')
34
+
35
+ #get application name
36
+ environment = describe_environment(environment_name: environment_name)[0]
37
+ app_name = environment.application_name
38
+
39
+ #get environment_variables
40
+ resp = elastic_beanstalk_client.describe_configuration_settings({
41
+ application_name: app_name,
42
+ environment_name: environment_name,
43
+ })
44
+
45
+ configuration_setting = resp.configuration_settings[0]
46
+ option_settings = configuration_setting.option_settings
47
+ environment_variables = []
48
+ option_settings.each do |option|
49
+ if option.option_name == "EnvironmentVariables"
50
+ environment_variables = option.value.split(",")
51
+ break
52
+ end
53
+ end
54
+
55
+ environment_variables
56
+
57
+ end
58
+
59
+ end
60
+
61
+ end
62
+ end
@@ -0,0 +1,25 @@
1
+ require 'aws_pocketknife'
2
+
3
+ module AwsPocketknife
4
+ module Elb
5
+
6
+ class << self
7
+ include AwsPocketknife::Common::Utils
8
+
9
+ def describe_elb_by_name(name: '')
10
+ resp = elb_client.describe_load_balancers({
11
+ load_balancer_names: [name],
12
+ page_size: 1,
13
+ })
14
+
15
+ if resp.nil? or resp.load_balancer_descriptions.empty?
16
+ return nil
17
+ else
18
+ return resp.load_balancer_descriptions.first
19
+ end
20
+ end
21
+
22
+ end
23
+
24
+ end
25
+ end
@@ -0,0 +1,135 @@
1
+ require 'erubis'
2
+ require 'aws_pocketknife'
3
+
4
+ module AwsPocketknife
5
+ module Iam
6
+
7
+ class << self
8
+ include AwsPocketknife::Common::Utils
9
+
10
+ def list_ssl_certificates
11
+ iam_client.list_server_certificates({})
12
+ end
13
+
14
+ def create_iam_user(username)
15
+ puts "Creating iam user: #{username}"
16
+ iam_client.create_user({user_name: username})
17
+ puts "Iam user: #{username} created"
18
+ end
19
+
20
+ def create_group(group_name)
21
+ puts "Creating group: #{group_name}"
22
+ iam_client.create_group({group_name: group_name})
23
+ puts "Created group: #{group_name}"
24
+ end
25
+
26
+ def create_policy(policy_name, policy)
27
+ puts "Creating policy: #{policy_name}"
28
+ iam_client.create_policy({policy_name: policy_name,policy_document: policy})
29
+ puts "Created policy: #{policy_name}"
30
+ end
31
+
32
+ def create_policy_from_policy_file(policy_name: "", policy_file: "", s3_buckets: "")
33
+ puts "Creating policy #{policy_name} from saved policy #{policy_file}"
34
+ policy = IO.read(policy_file)
35
+ buckets = get_bucket_list(buckets_list: s3_buckets)
36
+ template = Erubis::Eruby.new(policy)
37
+ vars = {buckets: buckets}
38
+
39
+ policy = template.result(vars)
40
+
41
+ puts policy
42
+
43
+ unless (policy.nil?)
44
+ iam_client.create_policy({policy_name: policy_name, policy_document: policy})
45
+ else
46
+ puts 'Policy not found'
47
+ end
48
+ puts "Created Policy #{policy_name}"
49
+ end
50
+
51
+ def attach_policy_to_group(policy_name, group_name )
52
+ puts "Attaching policy #{policy_name} to group #{group_name}"
53
+ arn_number = get_policy_arn(policy_name)
54
+
55
+ unless arn_number.nil?
56
+ iam_client.attach_group_policy(group_name: group_name, policy_arn: arn_number)
57
+ else
58
+ puts "The policy #{policy_name} could not be found"
59
+ end
60
+ puts "Policy #{policy_name} attached to group #{group_name}"
61
+ end
62
+
63
+ def add_user_to_group(username,group_name)
64
+ puts "Attaching user: #{username} to group: #{group_name}"
65
+ iam_client.add_user_to_group(group_name: group_name, user_name: username)
66
+ puts "User: #{username} attached to group: #{group_name}"
67
+
68
+ end
69
+
70
+ def create_role(role_name, trust_relationship_file)
71
+ begin
72
+ if File.exist?(trust_relationship_file)
73
+ trust_relationship = IO.read(trust_relationship_file)
74
+ unless trust_relationship.nil?
75
+ puts "Creating role: #{role_name} with trust relationship #{trust_relationship}"
76
+ iam_client.create_role(role_name: role_name, assume_role_policy_document: trust_relationship)
77
+ puts "Created role: #{role_name} with trust relationship #{trust_relationship}"
78
+ else
79
+ raise "Trust Relationship file could not be loaded"
80
+ end
81
+ else
82
+ raise "Trust Relationship file could not be loaded"
83
+ end
84
+ rescue Exception => e
85
+ puts e
86
+ raise e
87
+ end
88
+ end
89
+
90
+ def attach_policy_to_role(role_name, policy_name)
91
+ arn_number = get_policy_arn(policy_name)
92
+ unless arn_number.nil?
93
+ puts "Attach policy: #{policy_name} to role: #{role_name}"
94
+ iam_client.attach_role_policy(role_name: role_name, policy_arn: arn_number)
95
+ puts "Attached policy: #{policy_name} to role: #{role_name}"
96
+ else
97
+ raise "The policy #{policy_name} could not be found"
98
+ end
99
+ end
100
+
101
+ def create_instance_profile(instance_profile_name)
102
+ puts "Creating instance profile: #{instance_profile_name}"
103
+ iam_client.create_instance_profile(instance_profile_name: instance_profile_name)
104
+ puts "Created instance profile: #{instance_profile_name}"
105
+ end
106
+
107
+ def add_role_to_instance_profile(role_name,instance_profile_name)
108
+ puts "Adding role #{role_name} to instance profile: #{instance_profile_name}"
109
+ iam_client.add_role_to_instance_profile(instance_profile_name: instance_profile_name, role_name: role_name)
110
+ puts "Added role #{role_name} to instance profile: #{instance_profile_name}"
111
+ end
112
+
113
+
114
+ private
115
+
116
+ def get_bucket_list(buckets_list: "")
117
+ buckets_list.strip.split(";")
118
+ end
119
+
120
+ def get_policy_arn(policy_name)
121
+ response = iam_client.list_policies({scope: 'Local'})
122
+ arn_number = nil
123
+ response.policies.each do |value|
124
+ if value.policy_name == policy_name
125
+ arn_number = value.arn
126
+ break;
127
+ end
128
+ end
129
+ arn_number
130
+ end
131
+
132
+ end
133
+
134
+ end
135
+ end
@@ -0,0 +1,84 @@
1
+ require 'aws_pocketknife'
2
+
3
+ module AwsPocketknife
4
+ module Rds
5
+
6
+ AVAILABLE = 'available'.freeze
7
+ CREATING = 'creating'.freeze
8
+ DELETING = 'deleting'.freeze
9
+
10
+ class << self
11
+ include AwsPocketknife::Common::Utils
12
+
13
+ def describe_snapshots(options)
14
+ db_name = options.fetch(:db_name, '')
15
+ rds_client.describe_db_snapshots({db_instance_identifier: db_name}).db_snapshots
16
+ end
17
+
18
+ # creates snapshot for the database name
19
+ def create_snapshot(options)
20
+ db_name = options.fetch(:db_name, 'my-snapshot')
21
+ snapshot_name = get_snapshot_name(db_name)
22
+ rds_client.create_db_snapshot(db_instance_identifier: db_name, db_snapshot_identifier: snapshot_name)
23
+
24
+ Retryable.retryable(:tries => 15, :sleep => lambda { |n| 2**n }, :on => StandardError) do |retries, exception|
25
+ response = rds_client.describe_db_snapshots(db_snapshot_identifier: snapshot_name)
26
+
27
+ snapshot = response.db_snapshots.find { |s| s.db_snapshot_identifier == snapshot_name }
28
+ status = snapshot.status
29
+ percent_progress = snapshot.percent_progress
30
+ puts "RDS Snapshot #{snapshot_name} status: #{status}, progress #{percent_progress}%"
31
+ raise StandardError if status != AwsPocketknife::Rds::AVAILABLE
32
+ end
33
+
34
+ end
35
+
36
+ def get_snapshot_name(db_name)
37
+ now_str = Time.now.strftime('%Y-%m-%d-%H-%M')
38
+ "#{db_name}-#{now_str}"
39
+ end
40
+
41
+ def clean_snapshots(options)
42
+ puts "options: #{options}"
43
+
44
+ db_name = options.fetch(:db_name, '')
45
+ days = options.fetch(:days, '30').to_i * 24 * 3600
46
+ dry_run = options.fetch(:dry_run, true)
47
+
48
+ creation_time = Time.now - days
49
+ puts "Cleaning up MANUAL snapshots older than #{days} days, i.e, with creation_time < #{creation_time} for db [#{db_name}]"
50
+
51
+ snapshots_to_remove = []
52
+ snapshots = describe_snapshots options
53
+ snapshots.each do |snapshot|
54
+ snapshot.snapshot_create_time.is_a?(String) ? snapshot_creation_time = Time.parse(snapshot.snapshot_create_time) : snapshot_creation_time = snapshot.snapshot_create_time
55
+
56
+ msg = "Snapshot #{snapshot.db_snapshot_identifier} (type=#{snapshot.snapshot_type}) (snapshot_creation_time: #{snapshot_creation_time}) > (#{creation_time})? "
57
+ if creation_time <= snapshot_creation_time
58
+ if (snapshot.snapshot_type == 'manual')
59
+ snapshots_to_remove << snapshot
60
+ msg << " YES, marking to be deleted"
61
+ else
62
+ msg << " NO"
63
+ end
64
+ else
65
+ msg << "NO (is not a manual snapshot)"
66
+ end
67
+ puts msg
68
+ end
69
+
70
+ puts "snapshots_to_remove: #{snapshots_to_remove.map { |s| s.db_snapshot_identifier}}"
71
+
72
+ unless dry_run
73
+ snapshots_to_remove.each do |snapshot|
74
+ puts "Removing snapshot #{snapshot.db_snapshot_identifier} (status=#{snapshot.status})"
75
+ rds_client.delete_db_snapshot({db_snapshot_identifier:snapshot.db_snapshot_identifier})
76
+ end
77
+ end
78
+
79
+ end
80
+
81
+ end
82
+
83
+ end
84
+ end
@@ -0,0 +1,234 @@
1
+ require 'aws_pocketknife'
2
+
3
+ module AwsPocketknife
4
+ module Route53
5
+
6
+ class << self
7
+ include AwsPocketknife::Common::Utils
8
+
9
+ Logging = Common::Logging.logger
10
+
11
+ def list_hosted_zones
12
+ result = route53_client.list_hosted_zones
13
+ unless result.nil?
14
+ return result.hosted_zones
15
+ else
16
+ return []
17
+ end
18
+ end
19
+
20
+ def describe_hosted_zone(hosted_zone: "")
21
+ hosted_zones = list_hosted_zones
22
+ zone = find_hosted_zone_id(list: hosted_zones, name: hosted_zone)
23
+ end
24
+
25
+ def get_hosted_zone_id_and_origin_record(origin_dns_name, origin_hosted_zone, record_type)
26
+ hosted_zone = describe_hosted_zone(hosted_zone: origin_hosted_zone)
27
+ hosted_zone_id = get_hosted_zone_id(hosted_zone: hosted_zone.id)
28
+
29
+ # get origin record
30
+ origin_record = get_record(hosted_zone_name: origin_hosted_zone,
31
+ record_name: origin_dns_name,
32
+ record_type: record_type)
33
+
34
+ if origin_record.empty?
35
+ Logging.warn "Could not find record for #{origin_dns_name} at #{origin_hosted_zone}"
36
+ end
37
+ return hosted_zone_id, origin_record
38
+ end
39
+
40
+
41
+ def update_record(origin_hosted_zone: "",
42
+ origin_dns_name: "",
43
+ record_type: "A",
44
+ destiny_dns_name:"",
45
+ destiny_hosted_zone: ""
46
+ )
47
+
48
+
49
+ puts "Updating #{origin_dns_name} at #{origin_hosted_zone} with #{destiny_dns_name} at #{destiny_hosted_zone}"
50
+ if destiny_hosted_zone.empty?
51
+ return update_cname_record(origin_hosted_zone: origin_hosted_zone,
52
+ origin_dns_name: origin_dns_name,
53
+ destiny_dns_name:destiny_dns_name,
54
+ destiny_hosted_zone: destiny_hosted_zone
55
+ )
56
+ else
57
+ return update_record_from_existing_dns_entry(origin_hosted_zone: origin_hosted_zone,
58
+ origin_dns_name: origin_dns_name,
59
+ record_type: record_type,
60
+ destiny_dns_name:destiny_dns_name,
61
+ destiny_hosted_zone: destiny_hosted_zone
62
+ )
63
+ end
64
+
65
+
66
+ end
67
+
68
+ def get_payload_for_record_update(change: "", hosted_zone_id: "")
69
+ {
70
+ hosted_zone_id: hosted_zone_id,
71
+ change_batch: {
72
+ comment: "",
73
+ changes: [change]
74
+ }
75
+
76
+ }
77
+ end
78
+
79
+ def get_record(hosted_zone_name: "", record_name: "", record_type: "")
80
+ record = []
81
+ records = list_records_for_zone_name(
82
+ hosted_zone_name: hosted_zone_name,
83
+ record_name:record_name,
84
+ record_type: record_type)
85
+
86
+ records.each do |r|
87
+ return [r] if r.name == record_name
88
+ end
89
+
90
+ return record
91
+ end
92
+
93
+ def list_records_for_zone_name(hosted_zone_name: "", record_name: "", record_type: "")
94
+ records = []
95
+ hosted_zone = describe_hosted_zone(hosted_zone: hosted_zone_name)
96
+ return records if hosted_zone.nil?
97
+
98
+ hosted_zone_id = get_hosted_zone_id(hosted_zone: hosted_zone.id)
99
+
100
+ result = nil
101
+ if record_name.length != 0 and record_type != 0
102
+ result = route53_client.list_resource_record_sets({hosted_zone_id: hosted_zone_id,
103
+ start_record_name: record_name,
104
+ start_record_type: record_type, # accepts SOA, A, TXT, NS, CNAME, MX, PTR, SRV, SPF, AAAA
105
+ max_items: 1,
106
+ })
107
+ else
108
+ result = route53_client.list_resource_record_sets({hosted_zone_id: hosted_zone_id})
109
+ end
110
+ result.resource_record_sets.each do |record|
111
+ if ["A", "CNAME", "AAAA"].include?record.type
112
+ records << record
113
+ end
114
+ end
115
+ return records
116
+ end
117
+
118
+ def get_hosted_zone_id(hosted_zone: "")
119
+ hosted_zone.split("/").reverse[0]
120
+ end
121
+
122
+ private
123
+
124
+ def update_cname_record(origin_hosted_zone: "",
125
+ origin_dns_name: "",
126
+ record_type: "CNAME",
127
+ destiny_dns_name:"",
128
+ destiny_hosted_zone: ""
129
+ )
130
+
131
+ hosted_zone_id, origin_record = get_hosted_zone_id_and_origin_record(origin_dns_name, origin_hosted_zone, record_type)
132
+
133
+ new_dns_name = destiny_dns_name
134
+ origin_record = origin_record[0]
135
+
136
+ if not origin_record.alias_target.nil? and new_dns_name == origin_record.alias_target.dns_name
137
+ Logging.info "Origin and destiny alias_target.dns_name are the same: #{new_dns_name} Aborting..."
138
+ return false
139
+ elsif origin_record.resource_records.length != 0 and new_dns_name == origin_record.resource_records[0].value
140
+ Loggin.info "Origin and destiny alias_target.dns_name are the same: #{new_dns_name} Aborting..."
141
+ return false
142
+ end
143
+
144
+ change = {
145
+ action: "UPSERT",
146
+ resource_record_set: {
147
+ name: origin_dns_name,
148
+ type: record_type,
149
+ ttl: 300,
150
+ resource_records: [{value: new_dns_name}]
151
+ }
152
+ }
153
+
154
+ payload = get_payload_for_record_update(change: change, hosted_zone_id: hosted_zone_id)
155
+
156
+ nice_print(object: payload)
157
+ result = route53_client.change_resource_record_sets(payload)
158
+
159
+ end
160
+
161
+ def update_record_from_existing_dns_entry(origin_hosted_zone: "",
162
+ origin_dns_name: "",
163
+ record_type: "A",
164
+ destiny_dns_name:"",
165
+ destiny_hosted_zone: ""
166
+ )
167
+
168
+ # get hosted zone
169
+ hosted_zone_id, origin_record = get_hosted_zone_id_and_origin_record(origin_dns_name, origin_hosted_zone, record_type)
170
+
171
+
172
+ # get record for new dns name
173
+ destiny_record = get_record(hosted_zone_name: destiny_hosted_zone,
174
+ record_name: destiny_dns_name,
175
+ record_type: record_type)
176
+
177
+ if destiny_record.empty?
178
+ Logging.warn "Could not find destiny record for #{destiny_dns_name} at #{destiny_hosted_zone}"
179
+ return nil
180
+ end
181
+
182
+ if destiny_record[0].alias_target.nil?
183
+ Logging.warn "DNS #{destiny_dns_name} is invalid"
184
+ return nil
185
+ end
186
+
187
+ destiny_hosted_zone_id = destiny_record[0].alias_target.hosted_zone_id
188
+ new_dns_name = destiny_record[0].alias_target.dns_name
189
+ origin_record = origin_record[0]
190
+
191
+ unless new_dns_name.start_with?("dualstack.")
192
+ Logging.info "Adding dualstack. to #{new_dns_name}"
193
+ new_dns_name = "dualstack." + new_dns_name
194
+ end
195
+
196
+ if not origin_record.alias_target.nil? and new_dns_name == origin_record.alias_target.dns_name
197
+ Logging.info "Origin dns and destiny alias_target.dns_name points to the same record: #{new_dns_name}\nAborting..."
198
+ return false
199
+ elsif origin_record.resource_records.length != 0 and new_dns_name == origin_record.resource_records[0].value
200
+ Logging.info "Origin dns and destiny alias_target.dns_name points to the same record: #{new_dns_name}\nAborting..."
201
+ return false
202
+ end
203
+
204
+ change = {
205
+ action: "UPSERT",
206
+ resource_record_set: {
207
+ name: origin_dns_name,
208
+ type: record_type,
209
+ alias_target: {
210
+ hosted_zone_id: destiny_hosted_zone_id, # required
211
+ dns_name: new_dns_name, # required
212
+ evaluate_target_health: false, # required
213
+ }
214
+ }
215
+ }
216
+
217
+ payload = get_payload_for_record_update(change: change, hosted_zone_id: hosted_zone_id)
218
+
219
+ nice_print(object: payload)
220
+ result = route53_client.change_resource_record_sets(payload)
221
+
222
+ end
223
+
224
+ # Recevies a list of hosted zones and returns the element specified in name
225
+ def find_hosted_zone_id(list: nil, name: nil)
226
+ list.each do |h|
227
+ return h if h.name == name
228
+ end
229
+ return nil
230
+ end
231
+ end
232
+
233
+ end
234
+ end