automan 2.3.8 → 2.4.0

Sign up to get free protection for your applications and to get access to all the features.
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