automan 2.3.8 → 2.4.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
  SHA1:
3
- metadata.gz: cf346dc12fb2e3e0da31e57751b6158b64f58330
4
- data.tar.gz: 9245efb48cab8a750fb4e2d44c8ede1d15652d45
3
+ metadata.gz: 556e8ef30f82380e1d0aa07bf033feb1dd2bf574
4
+ data.tar.gz: cf5aea391bdafeb455f5c9e9b0084797fced6881
5
5
  SHA512:
6
- metadata.gz: f6604efc763560ca09bff13a965fe0c5a62000bde4f53af62c8ea17b2caf96ad693608fb843c258d8d74544d6e0601bdf4adec440b479ae7288fa5b6ba00b798
7
- data.tar.gz: 34464ac37f622f24d4eb2f36c7b6af8a15610e08f85e07ccd5a9094de8f443162e0586f8a260d6d1da1a73e8900325213094c61b67e6f1317ee71be86262053b
6
+ metadata.gz: 9cac1683af9f00f2215e4430bc3787b1ada1f86d23a6de920b7e55cc800de2383aa7d8bbe4ab198474f134b79fdf5df006c88e8f8cb711f4f9d1cd4570379984
7
+ data.tar.gz: 90f61b9c7ccc3f75250e9c2c1efea0f405c31027ed9ae5c18aa6d42414a85cba396650d40630de830d6fe81299a5b97cdcce9e0fa9e03556be164c9365d3dcb3
@@ -7,28 +7,37 @@ module Automan::Cli
7
7
  desc "create", "create a snapshot"
8
8
 
9
9
  option :environment,
10
- aliases: "-e",
11
- desc: "environment of database to snapshot"
10
+ aliases: "-e",
11
+ desc: "environment of database to snapshot"
12
12
 
13
13
  option :database,
14
- aliases: "-d",
15
- desc: "name of the database to snapshot"
14
+ aliases: "-d",
15
+ desc: "name of the database to snapshot"
16
16
 
17
17
  option :name,
18
- aliases: "-n",
19
- desc: "what to name the snapshot"
18
+ aliases: "-n",
19
+ desc: "what to name the snapshot"
20
20
 
21
21
  option :prune,
22
- aliases: "-p",
23
- type: :boolean,
24
- default: true,
25
- desc: "make this snapshot prunable and delete other prunable snapshots older than 30 days"
22
+ aliases: "-p",
23
+ type: :boolean,
24
+ default: true,
25
+ desc: "make this snapshot prunable and delete other prunable snapshots older than 30 days"
26
+
27
+ option :type,
28
+ aliases: "-t",
29
+ desc: "type of snapshot. When pruning, only snapshots of the specified type will be deleted."
30
+
31
+ option :max_snapshots,
32
+ aliases: "-m",
33
+ desc: "Maximum number of snapshots of this type to retain",
34
+ type: :numeric
26
35
 
27
36
  option :wait_for_completion,
28
- aliases: "-w",
29
- type: :boolean,
30
- default: false,
31
- desc: "wait until snapshot is finished before exiting script"
37
+ aliases: "-w",
38
+ type: :boolean,
39
+ default: false,
40
+ desc: "wait until snapshot is finished before exiting script"
32
41
 
33
42
  def create
34
43
  if options[:database].nil? && options[:environment].nil?
@@ -37,6 +46,14 @@ module Automan::Cli
37
46
  exit 1
38
47
  end
39
48
 
49
+ if options[:prune]
50
+ if options[:type].nil? || options[:max_snapshots].nil?
51
+ puts "Must specify snapshot type and max snapshots to retain when pruning"
52
+ help "create"
53
+ exit 1
54
+ end
55
+ end
56
+
40
57
  aws_opts = options.dup
41
58
  aws_opts[:log_aws] = true
42
59
  s = Automan::RDS::Snapshot.new(aws_opts)
@@ -47,9 +64,9 @@ module Automan::Cli
47
64
  desc "delete", "delete a snapshot"
48
65
 
49
66
  option :name,
50
- required: true,
51
- aliases: "-n",
52
- desc: "name of snapshot to delete"
67
+ required: true,
68
+ aliases: "-n",
69
+ desc: "name of snapshot to delete"
53
70
 
54
71
  def delete
55
72
  Automan::RDS::Snapshot.new(options).delete
@@ -58,12 +75,12 @@ module Automan::Cli
58
75
  desc "latest", "find the most recent snapshot"
59
76
 
60
77
  option :database,
61
- aliases: "-d",
62
- desc: "name of the database to snapshot"
78
+ aliases: "-d",
79
+ desc: "name of the database to snapshot"
63
80
 
64
81
  option :environment,
65
- aliases: "-e",
66
- desc: "environment of database to snapshot"
82
+ aliases: "-e",
83
+ desc: "environment of database to snapshot"
67
84
 
68
85
  def latest
69
86
  if options[:database].nil? && options[:environment].nil?
@@ -78,12 +95,12 @@ module Automan::Cli
78
95
  desc "count", "return the number of snapshots"
79
96
 
80
97
  option :environment,
81
- aliases: "-e",
82
- desc: "environment of database to snapshot"
98
+ aliases: "-e",
99
+ desc: "environment of database to snapshot"
83
100
 
84
101
  option :database,
85
- aliases: "-d",
86
- desc: "name of the database to snapshot"
102
+ aliases: "-d",
103
+ desc: "name of the database to snapshot"
87
104
 
88
105
  def count
89
106
  if options[:database].nil? && options[:environment].nil?
@@ -94,6 +111,6 @@ module Automan::Cli
94
111
 
95
112
  Automan::RDS::Snapshot.new(options).count_snapshots
96
113
  end
97
-
114
+
98
115
  end
99
116
  end
@@ -8,13 +8,14 @@ module Automan::RDS
8
8
  :name,
9
9
  :environment,
10
10
  :prune,
11
+ :type,
12
+ :max_snapshots,
11
13
  :wait_for_completion
12
14
 
13
- attr_accessor :max_snapshots
14
-
15
15
  def initialize(options={})
16
16
  @prune = true
17
17
  @wait_for_completion = false
18
+ @max_snapshots = 50
18
19
  super
19
20
  @wait = Wait.new({
20
21
  delay: 30,
@@ -24,9 +25,8 @@ module Automan::RDS
24
25
  logger: @logger
25
26
  })
26
27
 
27
- if ENV['MAX_SNAPSHOTS'].nil?
28
- @max_snapshots = 50
29
- else
28
+ # DEPRECATED: use --max-snapshots instead
29
+ if ENV['MAX_SNAPSHOTS']
30
30
  @max_snapshots = ENV['MAX_SNAPSHOTS'].to_i
31
31
  end
32
32
  end
@@ -83,22 +83,12 @@ module Automan::RDS
83
83
 
84
84
  wait_until_database_available(db)
85
85
 
86
- if snapshot_count >= max_snapshots
87
- logger.info "Too many snapshots (>= #{max_snapshots}), deleting oldest prunable."
88
- old = nil
89
- AWS.memoize do
90
- old = oldest_prunable_snapshot
91
- end
92
- logger.info "Deleting #{old.id}"
93
- old.delete
94
- end
95
-
96
86
  logger.info "Creating snapshot #{myname} for #{db.id}"
97
87
  snap = db.create_snapshot(myname)
98
88
 
99
89
  if prune == true
100
90
  logger.info "Setting snapshot to be prunable and tagging environment"
101
- set_prunable_and_env(snap,environment)
91
+ set_prunable_and_env(snap)
102
92
  end
103
93
 
104
94
  if wait_for_completion == true
@@ -118,8 +108,7 @@ module Automan::RDS
118
108
  end
119
109
 
120
110
  def db_environment(db)
121
- arn = db_arn(db)
122
- return tags(arn)['Name']
111
+ return db_tags(db)['Name']
123
112
  end
124
113
 
125
114
  def default_snapshot_name(db)
@@ -149,10 +138,14 @@ module Automan::RDS
149
138
  end
150
139
 
151
140
  # tag with CanPrune
152
- def set_prunable_and_env(snapshot,environment)
141
+ def set_prunable_and_env(snapshot)
153
142
  opts = {
154
143
  resource_name: snapshot_arn(snapshot),
155
- tags: [ {key: 'CanPrune', value: 'yes'}, {key: 'Environment', value: environment} ]
144
+ tags: [
145
+ { key: 'CanPrune', value: 'yes'},
146
+ { key: 'Environment', value: environment},
147
+ { key: 'Type', value: type }
148
+ ]
156
149
  }
157
150
  response = rds.client.add_tags_to_resource opts
158
151
 
@@ -168,7 +161,17 @@ module Automan::RDS
168
161
  rds.db_snapshots[name].delete
169
162
  end
170
163
 
171
- def tags(arn)
164
+ def db_tags(db)
165
+ arn = db_arn(db)
166
+ resource_tags(arn)
167
+ end
168
+
169
+ def snapshot_tags(snapshot)
170
+ arn = snapshot_arn(snapshot)
171
+ resource_tags(arn)
172
+ end
173
+
174
+ def resource_tags(arn)
172
175
  opts = {
173
176
  resource_name: arn
174
177
  }
@@ -185,67 +188,63 @@ module Automan::RDS
185
188
  result
186
189
  end
187
190
 
188
- def can_prune?(snapshot)
189
- tagged_can_prune?(snapshot) && available?(snapshot) && manual?(snapshot)
190
- end
191
-
192
- def is_env?(snapshot,environment)
193
- tagged_env?(snapshot,environment) && available?(snapshot) && manual?(snapshot)
194
- end
195
-
196
- def tagged_env?(snapshot,environment)
197
- arn = snapshot_arn(snapshot)
198
- tags(arn)['Environment'] == environment
199
- end
200
-
201
- def tagged_can_prune?(snapshot)
202
- arn = snapshot_arn(snapshot)
203
- tags(arn)['CanPrune'] == 'yes'
204
- end
205
-
206
191
  def available?(snapshot)
207
192
  snapshot.status == 'available'
208
193
  end
209
194
 
210
- def manual?(snapshot)
211
- snapshot.snapshot_type == 'manual'
212
- end
213
-
214
- # older than a month?
215
- def too_old?(time)
216
- time.utc < (Time.now.utc - 60*60*24*30)
217
- end
218
-
219
195
  def get_all_snapshots
220
196
  rds.snapshots
221
197
  end
222
198
 
223
- def get_all_env_snapshots
224
- rds.db_instances[find_db.id].snapshots
225
- end
226
-
227
- def prunable_snapshots
228
- snapshots = get_all_env_snapshots
229
- snapshots.select { |s| can_prune?(s) }
199
+ # tags = {'mytagkey' => 'mytagvalue', ...}
200
+ def snapshot_has_tags?(snapshot, tags)
201
+ snap_tags = snapshot_tags(snapshot)
202
+ tags.each do |tk,tv|
203
+ if snap_tags[tk] != tv
204
+ #logger.info("qtags: #{tags.to_json} snap_tags: #{snap_tags.to_json}")
205
+ return false
206
+ end
207
+ end
208
+ true
230
209
  end
231
210
 
232
- def oldest_prunable_snapshot
233
- prunable_snapshots.sort_by { |s| s.created_at }.first
211
+ # tags = {'mytagkey' => 'mytagvalue', ...}
212
+ def snapshots_with_tags(tags)
213
+ rds.snapshots.select {|s| snapshot_has_tags?(s, tags)}
234
214
  end
235
215
 
216
+ #
217
+ # There is a big broken assumption here!
218
+ # We enumerate all snapshots of the *current* environment db
219
+ # What if that db is new and we have snapshots from previous
220
+ # dbs? The dev1 db is replaced every day!
221
+ # So prunable_snapshots will only return the list of snapshots
222
+ # from the *current* dev1 db and ignore all others!
223
+ #
236
224
  def prune_snapshots
237
225
  logger.info "Pruning old db snapshots"
238
226
 
227
+ tags = {
228
+ 'Environment' => environment,
229
+ 'Type' => type,
230
+ 'CanPrune' => 'yes'
231
+ }
232
+ sorted_snaps = nil
239
233
  AWS.memoize do
240
- prunable_snapshots.each do |snapshot|
234
+ sorted_snaps = snapshots_with_tags(tags).sort_by {|s| s.created_at}
235
+ end
241
236
 
242
- timestamp = snapshot.created_at
243
- snapshot_name = snapshot.db_snapshot_identifier
237
+ logger.info "snaps #{sorted_snaps.count} max #{max_snapshots}"
244
238
 
245
- if too_old?(timestamp)
246
- logger.info "Deleting #{snapshot_name} because it is too old."
247
- snapshot.delete
248
- end
239
+ if sorted_snaps.count >= max_snapshots
240
+ logger.info "Too many snapshots ( #{sorted_snaps.count} >= #{max_snapshots})."
241
+ number_to_delete = sorted_snaps.count - max_snapshots + 1
242
+ logger.info "deleting #{number_to_delete}."
243
+
244
+ condemned = sorted_snaps.take(number_to_delete)
245
+ condemned.each do |snap|
246
+ logger.info "Deleting #{snap.id}"
247
+ snap.delete
249
248
  end
250
249
  end
251
250
  end
@@ -265,16 +264,9 @@ module Automan::RDS
265
264
  log_options
266
265
  logger.info "Finding most recent snapshot for #{environment}"
267
266
 
268
- allsnaps=get_all_snapshots
269
-
270
- envsnaps=[]
271
- allsnaps.each do |onesnap|
272
- if is_env?(onesnap,environment)
273
- envsnaps.push(onesnap)
274
- end
275
- end
267
+ tags = { 'Environment' => environment }
268
+ s = snapshots_with_tags(tags).sort_by {|s| s.created_at}.last
276
269
 
277
- s=envsnaps.sort_by {|i| i.created_at }.last
278
270
  logger.info "Most recent snapshot is #{s.id}"
279
271
  s.id
280
272
  end
@@ -1,3 +1,3 @@
1
1
  module Automan
2
- VERSION = "2.3.8"
2
+ VERSION = "2.4.0"
3
3
  end
@@ -58,36 +58,6 @@ describe Automan::RDS::Snapshot do
58
58
 
59
59
  end
60
60
 
61
- describe '#tagged_can_prune?' do
62
- subject() do
63
- AWS.stub!
64
- s = Automan::RDS::Snapshot.new
65
- s.logger = Logger.new('/dev/null')
66
- allow(s).to receive(:snapshot_arn)
67
- s
68
- end
69
-
70
- it 'returns true if snapshot is tagged with CanPrune=yes' do
71
- allow(subject).to receive(:tags).and_return( {'CanPrune' => 'yes'} )
72
- expect(subject.tagged_can_prune?( double() )).to be_truthy
73
- end
74
-
75
- it 'returns false if snapshot is missing CanPrune tag' do
76
- allow(subject).to receive(:tags).and_return( {} )
77
- expect(subject.tagged_can_prune?( double() )).to be_falsey
78
- end
79
-
80
- it 'returns false if snapshot is tagged with CanPrune=nil' do
81
- allow(subject).to receive(:tags).and_return( {'CanPrune' => nil} )
82
- expect(subject.tagged_can_prune?( double() )).to be_falsey
83
- end
84
-
85
- it 'returns false if snapshot is tagged with CanPrune=foo' do
86
- allow(subject).to receive(:tags).and_return( {'CanPrune' => 'foo'} )
87
- expect(subject.tagged_can_prune?( double() )).to be_falsey
88
- end
89
- end
90
-
91
61
  describe '#available?' do
92
62
  subject() do
93
63
  AWS.stub!
@@ -106,45 +76,4 @@ describe Automan::RDS::Snapshot do
106
76
  expect(subject.available?(snap)).to be_falsey
107
77
  end
108
78
  end
109
-
110
- describe '#manual?' do
111
- let(:snap) { double }
112
- subject() do
113
- AWS.stub!
114
- s = Automan::RDS::Snapshot.new
115
- s.logger = Logger.new('/dev/null')
116
- s
117
- end
118
-
119
- it 'returns true if type is "manual"' do
120
- allow(snap).to receive(:snapshot_type).and_return('manual')
121
- expect(subject.manual?(snap)).to be_truthy
122
- end
123
-
124
- it 'returns false if type is foo' do
125
- allow(snap).to receive(:snapshot_type).and_return('foo')
126
- expect(subject.manual?(snap)).to be_falsey
127
- end
128
- end
129
-
130
- describe '#prunable_snapshots' do
131
- let(:snap) { double }
132
- subject() do
133
- AWS.stub!
134
- s = Automan::RDS::Snapshot.new
135
- s.logger = Logger.new('/dev/null')
136
- allow(s).to receive(:get_all_snapshots).and_return( [ snap ] )
137
- s
138
- end
139
-
140
- it 'includes snapshots which can be pruned' do
141
- allow(subject).to receive(:can_prune?).and_return(true)
142
- expect(subject.prunable_snapshots).to include(snap)
143
- end
144
-
145
- it 'excludes snapshots which should not be pruned' do
146
- allow(subject).to receive(:can_prune?).and_return(false)
147
- expect(subject.prunable_snapshots).to_not include(snap)
148
- end
149
- end
150
- end
79
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: automan
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.3.8
4
+ version: 2.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Chris Chalfant
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2015-10-19 00:00:00.000000000 Z
12
+ date: 2015-11-23 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bundler
@@ -262,7 +262,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
262
262
  version: '0'
263
263
  requirements: []
264
264
  rubyforge_project:
265
- rubygems_version: 2.4.8
265
+ rubygems_version: 2.2.2
266
266
  signing_key:
267
267
  specification_version: 4
268
268
  summary: Automates common AWS ops