foghorn 0.0.3
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 +15 -0
- data/.gitignore +19 -0
- data/.rubocop.yml +10 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +31 -0
- data/Rakefile +1 -0
- data/foghorn.gemspec +30 -0
- data/lib/foghorn.rb +118 -0
- data/lib/foghorn/capistrano.rb +12 -0
- data/lib/foghorn/recipes.rb +48 -0
- data/lib/foghorn/tasks/foghorn.rake +0 -0
- data/lib/foghorn/version.rb +5 -0
- data/spec.rb +286 -0
- metadata +169 -0
checksums.yaml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
NDVlMjM2NGIwMTRkNjBkMDgwOWU2MDQ5MWE4MTRlNTQ4Mjc1NDRiYg==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
NTAxNzE0OTM2ZGVkMzIwZjMzNzMwMzg0ZmRiNGJkMGJmY2MwY2E1Nw==
|
7
|
+
SHA512:
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
NWM5ZGZjOThjMzk2MTIzODNmYmI3OThjN2E5NzI5MGYwMzA0ZjI4NzQxYmZk
|
10
|
+
YjdhOGYyZGQyNWNjMDlkYzFjNGJhZDJlYTM3ZWFhODhhMDAwNjE4N2IxYTEx
|
11
|
+
MjM4MmY1YzkyNGI1YWE5OWM3NzE5NmVlODI4NmRmN2JjYWJiZDI=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
ZmQ4Y2FhZDcxNTM1YTcyYTNhMmM2NmRiNmNiZDNjOGIyN2IwNmFjY2E1ZTQ1
|
14
|
+
MjE1MTA1ODEzYWIxYTk4Y2RhNmViMWRmNjU3YTBiNDQ0YWFjNTFkMTk0NzIy
|
15
|
+
MjdhOWFhZjM0YzI2NzhhMTYyNDQ5MGJhZjlmYWNiZWNhNWQ4ZWQ=
|
data/.gitignore
ADDED
data/.rubocop.yml
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 Dolphin Micro
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
# Foghorn
|
2
|
+
|
3
|
+
Deploy to the cloud without specifying specific servers
|
4
|
+
|
5
|
+
## Requirements
|
6
|
+
|
7
|
+
Currently only works with Capistrano 2.15
|
8
|
+
|
9
|
+
## Installation
|
10
|
+
|
11
|
+
Add this line to your application's Gemfile:
|
12
|
+
|
13
|
+
gem 'foghorn', '0.0.3', git: 'git@bitbucket.org:dolphinmicro/foghorn.git'
|
14
|
+
|
15
|
+
Require Foghorn in your deploy.rb
|
16
|
+
# this must go before loading stages!
|
17
|
+
set :foghorn_config,
|
18
|
+
provider: 'AWS',
|
19
|
+
aws_access_key_id: 'rotpacxullos',
|
20
|
+
aws_secret_access_key: '12345',
|
21
|
+
region: 'us-west-2'
|
22
|
+
require 'foghorn/capistrano'
|
23
|
+
|
24
|
+
## Usage
|
25
|
+
|
26
|
+
In your individual stages, you can now set roles based on the Roles tag in the cloud:
|
27
|
+
role_by_tag :app, :staging_app
|
28
|
+
role_by_tag :db, :staging_db
|
29
|
+
|
30
|
+
You can test your configuration with foghorn:blow
|
31
|
+
bundle exec cap production foghorn:blow
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'bundler/gem_tasks'
|
data/foghorn.gemspec
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'foghorn/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = 'foghorn'
|
8
|
+
spec.version = Foghorn::VERSION
|
9
|
+
spec.authors = ['Chris Dollard']
|
10
|
+
spec.email = ['chrisdollard@dolphinmicro.com']
|
11
|
+
spec.description = %q(Deploy to the cloud)
|
12
|
+
spec.summary = %q(Tag roles in EC2, not in your deploy scripts)
|
13
|
+
spec.homepage = 'https://bitbucket.org/dolphinmicro/foghorn'
|
14
|
+
spec.license = 'MIT'
|
15
|
+
|
16
|
+
spec.files = `git ls-files`.split($INPUT_RECORD_SEPARATOR)
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ['lib']
|
20
|
+
|
21
|
+
spec.add_development_dependency 'bundler', '~> 1.3'
|
22
|
+
spec.add_development_dependency 'rake'
|
23
|
+
spec.add_development_dependency 'rb-readline'
|
24
|
+
spec.add_development_dependency 'pry'
|
25
|
+
spec.add_development_dependency 'pry_debug'
|
26
|
+
spec.add_development_dependency 'rubocop'
|
27
|
+
spec.add_development_dependency 'rspec', '~> 3.0'
|
28
|
+
|
29
|
+
spec.add_runtime_dependency 'fog', '>= 1.19'
|
30
|
+
end
|
data/lib/foghorn.rb
ADDED
@@ -0,0 +1,118 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
require 'foghorn/version'
|
3
|
+
require 'fog'
|
4
|
+
require 'set'
|
5
|
+
|
6
|
+
# Foghorn
|
7
|
+
module Foghorn
|
8
|
+
def self.roles_for(object)
|
9
|
+
(object.tags['Roles'] || '').split(/\W+/)
|
10
|
+
end
|
11
|
+
|
12
|
+
# This is the class that interacts with fog
|
13
|
+
class Horn
|
14
|
+
def initialize(cxt)
|
15
|
+
if cxt.respond_to? :[]
|
16
|
+
@context = cxt
|
17
|
+
else
|
18
|
+
@context = ->(v) {cxt.fetch(v) }
|
19
|
+
end
|
20
|
+
@fog = Fog::Compute.new(@context['foghorn_config'])
|
21
|
+
@active_servers = Set.new
|
22
|
+
end
|
23
|
+
|
24
|
+
attr_reader :active_servers, :context
|
25
|
+
|
26
|
+
# Get list of servers, optionally filtered by a list of roles
|
27
|
+
def servers(*roles)
|
28
|
+
if @servers.nil?
|
29
|
+
@servers = @fog.servers
|
30
|
+
@servers_by_role = Hash.new { |h, k| h[k] = [] }
|
31
|
+
@servers.each do |server|
|
32
|
+
Foghorn.roles_for(server).each do |role|
|
33
|
+
@servers_by_role[role] << server
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
if roles.empty?
|
38
|
+
return @servers
|
39
|
+
else
|
40
|
+
roles = roles.flatten(1) if roles.length == 1
|
41
|
+
return roles
|
42
|
+
.map { |role| @servers_by_role[role.to_s] }
|
43
|
+
.inject([], :|)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
# Safeguards against forgetting to tag a server
|
48
|
+
def safeguard
|
49
|
+
servers
|
50
|
+
.reject { |server| server.tags['Roles'] }
|
51
|
+
.each do |server|
|
52
|
+
fail "Server #{server.tags['Name']} has no tagged Roles! "\
|
53
|
+
'Add a Roles tag to this server before deploying.'
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
# Creates snapshots of all active servers
|
58
|
+
def snapshots
|
59
|
+
active_servers.each do |server|
|
60
|
+
next unless server.tags['Snapshot']
|
61
|
+
|
62
|
+
server.volumes.each.with_index do |volume, index|
|
63
|
+
date = Time.now.strftime('%Y%m%d-%H%M')
|
64
|
+
|
65
|
+
name = "#{server.tags['Name']}-volume#{index}-#{date}"
|
66
|
+
|
67
|
+
snapshot = @fog.snapshots.new
|
68
|
+
snapshot.description = name
|
69
|
+
snapshot.volume_id = volume.id
|
70
|
+
|
71
|
+
#puts "Saving snapshot #{name}"
|
72
|
+
snapshot.save
|
73
|
+
snapshot.reload # to get id for tags
|
74
|
+
|
75
|
+
{
|
76
|
+
Name: name,
|
77
|
+
Time: Time.now.to_i,
|
78
|
+
Server: server.tags['Name'],
|
79
|
+
Revision: context['current_revision']
|
80
|
+
}.each do |key, value|
|
81
|
+
@fog.tags.create resource_id: snapshot.id, key: key, value: value
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
# Delete old snapshots - all but 2
|
88
|
+
def snapshots_cleanup
|
89
|
+
server_names = servers
|
90
|
+
.select { |server| server.tags['Snapshot']}
|
91
|
+
.map { |server| server.tags['Name'] }
|
92
|
+
|
93
|
+
snaps_by_server = Hash.new { |h, k| h[k] = [] }
|
94
|
+
@fog.snapshots
|
95
|
+
.select { |snapshot| server_names.include? snapshot.tags['Server'] }
|
96
|
+
.each do |snapshot|
|
97
|
+
snaps_by_server[snapshot.tags['Server']] << snapshot
|
98
|
+
end
|
99
|
+
|
100
|
+
snaps_by_server.each do |_server, snapshots|
|
101
|
+
snapshots.sort_by! do |snapshot|
|
102
|
+
(snapshot.tags['Time'] || 0).to_i * -1
|
103
|
+
end
|
104
|
+
|
105
|
+
snapshots.shift 2
|
106
|
+
|
107
|
+
snapshots.each do |snapshot|
|
108
|
+
begin
|
109
|
+
#puts "Deleting snapshot #{snapshot.tags['Name']}"
|
110
|
+
@fog.delete_snapshot snapshot.id
|
111
|
+
rescue => e
|
112
|
+
puts e.message
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
require 'capistrano/version'
|
3
|
+
|
4
|
+
if defined?(Capistrano::VERSION) &&
|
5
|
+
Gem::Version.new(Capistrano::VERSION).release >= Gem::Version.new('3.0.0')
|
6
|
+
load File.expand_path File.join File.dirname(__FILE__),
|
7
|
+
'tasks',
|
8
|
+
'foghorn.rake'
|
9
|
+
else
|
10
|
+
load File.expand_path File.join File.dirname(__FILE__),
|
11
|
+
'recipes.rb'
|
12
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
require 'foghorn'
|
3
|
+
|
4
|
+
Capistrano::Configuration.instance.load do
|
5
|
+
|
6
|
+
def role_by_tag(r, *tags)
|
7
|
+
servers = foghorn.horn.servers(tags)
|
8
|
+
.select { |server| server.dns_name }
|
9
|
+
fail "Couldn't find any servers tagged with #{tags}" if servers.empty?
|
10
|
+
puts r
|
11
|
+
servers.each do |server|
|
12
|
+
puts " #{server.tags['Name']}"
|
13
|
+
foghorn.horn.active_servers << server
|
14
|
+
role r, server.dns_name
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
namespace :foghorn do
|
19
|
+
def horn
|
20
|
+
@foghorn ||= Foghorn::Horn.new(self)
|
21
|
+
end
|
22
|
+
|
23
|
+
desc 'Show roles for all servers'
|
24
|
+
task :blow do
|
25
|
+
horn.servers.each do |server|
|
26
|
+
puts(
|
27
|
+
([server.tags['Name']] + Foghorn.roles_for(server))
|
28
|
+
.map { |col| col.ljust(16) }
|
29
|
+
.join)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
desc 'Ensure all servers have tags'
|
34
|
+
task :safeguard do
|
35
|
+
horn.safeguard
|
36
|
+
end
|
37
|
+
|
38
|
+
desc 'Snapshot all deployable servers tagged "snapshot"'
|
39
|
+
task :snapshots do
|
40
|
+
horn.snapshots
|
41
|
+
end
|
42
|
+
|
43
|
+
desc 'Clean up old snapshots'
|
44
|
+
task :snapshots_cleanup do
|
45
|
+
horn.snapshots_cleanup
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
File without changes
|
data/spec.rb
ADDED
@@ -0,0 +1,286 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
require 'foghorn'
|
3
|
+
|
4
|
+
# A fake Fog module to test Foghorn without a cloud
|
5
|
+
module FakeFog
|
6
|
+
# Compute
|
7
|
+
class Compute
|
8
|
+
def initialize(opts)
|
9
|
+
@servers = opts[:servers]
|
10
|
+
@snapshots = opts[:snapshots]
|
11
|
+
@tags = opts[:tags]
|
12
|
+
end
|
13
|
+
|
14
|
+
def delete_snapshot(id)
|
15
|
+
@snapshots.each do |snapshot|
|
16
|
+
if snapshot.id == id
|
17
|
+
snapshot.delete
|
18
|
+
return
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
attr_reader :servers, :snapshots, :tags
|
24
|
+
end
|
25
|
+
|
26
|
+
class Snapshot
|
27
|
+
attr_accessor :description, :volume_id, :id
|
28
|
+
|
29
|
+
def save
|
30
|
+
end
|
31
|
+
|
32
|
+
def reload
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
RSpec.describe Foghorn do
|
38
|
+
describe '#roles_for' do
|
39
|
+
it 'returns empty for nil Roles' do
|
40
|
+
obj = double('obj')
|
41
|
+
allow(obj).to receive(:tags) { {} }
|
42
|
+
expect(Foghorn.roles_for obj).to eq([])
|
43
|
+
end
|
44
|
+
it 'returns empty for blank Roles' do
|
45
|
+
obj = double('obj')
|
46
|
+
allow(obj).to receive(:tags) { { 'Roles' => '' } }
|
47
|
+
expect(Foghorn.roles_for obj).to eq([])
|
48
|
+
end
|
49
|
+
it 'returns a single Role' do
|
50
|
+
obj = double('obj')
|
51
|
+
allow(obj).to receive(:tags) { { 'Roles' => 'server' } }
|
52
|
+
expect(Foghorn.roles_for obj).to eq(%w(server))
|
53
|
+
end
|
54
|
+
it 'returns multiple Roles separated by spaces' do
|
55
|
+
obj = double('obj')
|
56
|
+
allow(obj).to receive(:tags) { { 'Roles' => 'server db cron' } }
|
57
|
+
expect(Foghorn.roles_for obj).to eq(%w(server db cron))
|
58
|
+
end
|
59
|
+
it 'returns multiple Roles separated by commas' do
|
60
|
+
obj = double('obj')
|
61
|
+
allow(obj).to receive(:tags) { { 'Roles' => 'server, db, cron' } }
|
62
|
+
expect(Foghorn.roles_for obj).to eq(%w(server db cron))
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
describe 'Horn' do
|
67
|
+
describe '#servers' do
|
68
|
+
it 'returns empty with no servers' do
|
69
|
+
stub_const('Fog', FakeFog)
|
70
|
+
horn = Foghorn::Horn.new(
|
71
|
+
'foghorn_config' => { servers: [] })
|
72
|
+
|
73
|
+
expect(horn.servers).to eq([])
|
74
|
+
end
|
75
|
+
|
76
|
+
it 'lists servers' do
|
77
|
+
app1 = double('app1')
|
78
|
+
allow(app1).to receive(:tags) {
|
79
|
+
{ 'Name' => 'app-001', 'Roles' => 'app db' }
|
80
|
+
}
|
81
|
+
app2 = double('app2')
|
82
|
+
allow(app2).to receive(:tags) {
|
83
|
+
{ 'Name' => 'app-002', 'Roles' => 'app' }
|
84
|
+
}
|
85
|
+
|
86
|
+
stub_const('Fog', FakeFog)
|
87
|
+
horn = Foghorn::Horn.new(
|
88
|
+
'foghorn_config' => { servers: [app1, app2] })
|
89
|
+
|
90
|
+
expect(horn.servers).to eq([app1, app2])
|
91
|
+
end
|
92
|
+
|
93
|
+
it 'lists servers by roles' do
|
94
|
+
app1 = double('app1')
|
95
|
+
allow(app1).to receive(:tags) {
|
96
|
+
{ 'Name' => 'app-001', 'Roles' => 'app db' }
|
97
|
+
}
|
98
|
+
app2 = double('app2')
|
99
|
+
allow(app2).to receive(:tags) {
|
100
|
+
{ 'Name' => 'app-002', 'Roles' => 'app' }
|
101
|
+
}
|
102
|
+
|
103
|
+
stub_const('Fog', FakeFog)
|
104
|
+
horn = Foghorn::Horn.new(
|
105
|
+
'foghorn_config' => { servers: [app1, app2] })
|
106
|
+
|
107
|
+
expect(horn.servers('app')).to eq([app1, app2])
|
108
|
+
expect(horn.servers('db')).to eq([app1])
|
109
|
+
expect(horn.servers('cron')).to eq([])
|
110
|
+
|
111
|
+
expect(horn.servers('app', 'db', 'cron')).to eq([app1, app2])
|
112
|
+
expect(horn.servers('db', 'cron')).to eq([app1])
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
describe '#safeguard' do
|
117
|
+
it 'passes with no servers' do
|
118
|
+
stub_const('Fog', FakeFog)
|
119
|
+
horn = Foghorn::Horn.new(
|
120
|
+
'foghorn_config' => { servers: [] })
|
121
|
+
|
122
|
+
horn.safeguard
|
123
|
+
end
|
124
|
+
|
125
|
+
it 'passes when servers are properly tagged' do
|
126
|
+
app1 = double('app1')
|
127
|
+
allow(app1).to receive(:tags) {
|
128
|
+
{ 'Name' => 'app-001', 'Roles' => 'app db' }
|
129
|
+
}
|
130
|
+
app2 = double('app2')
|
131
|
+
allow(app2).to receive(:tags) {
|
132
|
+
{ 'Name' => 'app-002', 'Roles' => 'app' }
|
133
|
+
}
|
134
|
+
|
135
|
+
stub_const('Fog', FakeFog)
|
136
|
+
horn = Foghorn::Horn.new(
|
137
|
+
'foghorn_config' => { servers: [app1, app2] })
|
138
|
+
|
139
|
+
horn.safeguard
|
140
|
+
end
|
141
|
+
|
142
|
+
it 'fails when a server is not tagged' do
|
143
|
+
app1 = double('app1')
|
144
|
+
allow(app1).to receive(:tags) {
|
145
|
+
{ 'Name' => 'app-001', 'Roles' => 'app db' }
|
146
|
+
}
|
147
|
+
app2 = double('app2')
|
148
|
+
allow(app2).to receive(:tags) {
|
149
|
+
{ 'Name' => 'app-002' }
|
150
|
+
}
|
151
|
+
|
152
|
+
stub_const('Fog', FakeFog)
|
153
|
+
horn = Foghorn::Horn.new(
|
154
|
+
'foghorn_config' => { servers: [app1, app2] })
|
155
|
+
|
156
|
+
expect { horn.safeguard }.to raise_error
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
describe '#snapshot' do
|
161
|
+
it 'makes snapshots' do
|
162
|
+
app1 = double('app1')
|
163
|
+
allow(app1).to receive(:tags) {
|
164
|
+
{ 'Name' => 'app-001', 'Snapshot' => 'app' }
|
165
|
+
}
|
166
|
+
vol0 = double('volume')
|
167
|
+
allow(vol0).to receive(:id) { 'sda' }
|
168
|
+
allow(app1).to receive(:volumes) { [ vol0 ] }
|
169
|
+
|
170
|
+
snaps = double('snaps')
|
171
|
+
expect(snaps).to receive(:new){ FakeFog::Snapshot.new }.once
|
172
|
+
|
173
|
+
tags = double('tags')
|
174
|
+
expect(tags).to receive(:create).exactly(4).times
|
175
|
+
|
176
|
+
stub_const('Fog', FakeFog)
|
177
|
+
horn = Foghorn::Horn.new(
|
178
|
+
'foghorn_config' => { servers: [app1], snapshots: snaps, tags: tags })
|
179
|
+
horn.active_servers << app1
|
180
|
+
|
181
|
+
horn.snapshots
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
describe '#snapshots_cleanup' do
|
186
|
+
it 'deletes old snapshots' do
|
187
|
+
app1 = double('app1')
|
188
|
+
allow(app1).to receive(:tags) {
|
189
|
+
{ 'Name' => 'app-001', 'Snapshot' => 'app' }
|
190
|
+
}
|
191
|
+
snap1 = double('snap1')
|
192
|
+
allow(snap1).to receive(:id) { 'snap-1' }
|
193
|
+
expect(snap1).to receive(:delete).once
|
194
|
+
allow(snap1).to receive(:tags) {
|
195
|
+
{ 'Server' => 'app-001', 'Time' => 413}
|
196
|
+
}
|
197
|
+
snap2 = double('snap2')
|
198
|
+
allow(snap2).to receive(:id) { 'snap-2' }
|
199
|
+
allow(snap2).to receive(:tags) {
|
200
|
+
{ 'Server' => 'app-001', 'Time' => 1024}
|
201
|
+
}
|
202
|
+
snap3 = double('snap3')
|
203
|
+
allow(snap3).to receive(:id) { 'snap-3' }
|
204
|
+
allow(snap3).to receive(:tags) {
|
205
|
+
{ 'Server' => 'app-001', 'Time' => 612}
|
206
|
+
}
|
207
|
+
|
208
|
+
stub_const('Fog', FakeFog)
|
209
|
+
horn = Foghorn::Horn.new(
|
210
|
+
'foghorn_config' => {
|
211
|
+
servers: [app1],
|
212
|
+
snapshots: [snap1, snap2, snap3] })
|
213
|
+
|
214
|
+
horn.snapshots_cleanup
|
215
|
+
end
|
216
|
+
|
217
|
+
it 'preserves irrelevant snapshots' do
|
218
|
+
app1 = double('app1')
|
219
|
+
allow(app1).to receive(:tags) {
|
220
|
+
{ 'Name' => 'app-001', 'Snapshot' => 'app' }
|
221
|
+
}
|
222
|
+
app2 = double('app2')
|
223
|
+
allow(app2).to receive(:tags) {
|
224
|
+
{ 'Name' => 'app-002' }
|
225
|
+
}
|
226
|
+
snap1 = double('snap1')
|
227
|
+
allow(snap1).to receive(:id) { 'snap-1' }
|
228
|
+
allow(snap1).to receive(:tags) {
|
229
|
+
{ 'Server' => 'app-002', 'Time' => 413}
|
230
|
+
}
|
231
|
+
snap2 = double('snap2')
|
232
|
+
allow(snap2).to receive(:id) { 'snap-2' }
|
233
|
+
allow(snap2).to receive(:tags) {
|
234
|
+
{ 'Server' => 'app-002', 'Time' => 1024}
|
235
|
+
}
|
236
|
+
snap3 = double('snap3')
|
237
|
+
allow(snap3).to receive(:id) { 'snap-3' }
|
238
|
+
allow(snap3).to receive(:tags) {
|
239
|
+
{ 'Server' => 'app-002', 'Time' => 612}
|
240
|
+
}
|
241
|
+
|
242
|
+
stub_const('Fog', FakeFog)
|
243
|
+
horn = Foghorn::Horn.new(
|
244
|
+
'foghorn_config' => {
|
245
|
+
servers: [app1, app2],
|
246
|
+
snapshots: [snap1, snap2, snap3] })
|
247
|
+
|
248
|
+
horn.snapshots_cleanup
|
249
|
+
end
|
250
|
+
|
251
|
+
it 'keeps 2 snapshots from each server' do
|
252
|
+
app1 = double('app1')
|
253
|
+
allow(app1).to receive(:tags) {
|
254
|
+
{ 'Name' => 'app-001', 'Snapshot' => 'app' }
|
255
|
+
}
|
256
|
+
api1 = double('app1')
|
257
|
+
allow(api1).to receive(:tags) {
|
258
|
+
{ 'Name' => 'api-001', 'Snapshot' => 'api' }
|
259
|
+
}
|
260
|
+
snap1 = double('snap1')
|
261
|
+
allow(snap1).to receive(:id) { 'snap-1' }
|
262
|
+
allow(snap1).to receive(:tags) {
|
263
|
+
{ 'Server' => 'app-001', 'Time' => 413}
|
264
|
+
}
|
265
|
+
snap2 = double('snap2')
|
266
|
+
allow(snap2).to receive(:id) { 'snap-2' }
|
267
|
+
allow(snap2).to receive(:tags) {
|
268
|
+
{ 'Server' => 'api-001', 'Time' => 1024}
|
269
|
+
}
|
270
|
+
snap3 = double('snap3')
|
271
|
+
allow(snap3).to receive(:id) { 'snap-3' }
|
272
|
+
allow(snap3).to receive(:tags) {
|
273
|
+
{ 'Server' => 'api-001', 'Time' => 612}
|
274
|
+
}
|
275
|
+
|
276
|
+
stub_const('Fog', FakeFog)
|
277
|
+
horn = Foghorn::Horn.new(
|
278
|
+
'foghorn_config' => {
|
279
|
+
servers: [app1, api1],
|
280
|
+
snapshots: [snap1, snap2, snap3] })
|
281
|
+
|
282
|
+
horn.snapshots_cleanup
|
283
|
+
end
|
284
|
+
end
|
285
|
+
end
|
286
|
+
end
|
metadata
ADDED
@@ -0,0 +1,169 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: foghorn
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.3
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Chris Dollard
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-08-03 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ~>
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.3'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ~>
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.3'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ! '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ! '>='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rb-readline
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ! '>='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ! '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: pry
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ! '>='
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: pry_debug
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ! '>='
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ! '>='
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rubocop
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ! '>='
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ! '>='
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: rspec
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ~>
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '3.0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ~>
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '3.0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: fog
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ! '>='
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '1.19'
|
118
|
+
type: :runtime
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ! '>='
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '1.19'
|
125
|
+
description: Deploy to the cloud
|
126
|
+
email:
|
127
|
+
- chrisdollard@dolphinmicro.com
|
128
|
+
executables: []
|
129
|
+
extensions: []
|
130
|
+
extra_rdoc_files: []
|
131
|
+
files:
|
132
|
+
- .gitignore
|
133
|
+
- .rubocop.yml
|
134
|
+
- Gemfile
|
135
|
+
- LICENSE.txt
|
136
|
+
- README.md
|
137
|
+
- Rakefile
|
138
|
+
- foghorn.gemspec
|
139
|
+
- lib/foghorn.rb
|
140
|
+
- lib/foghorn/capistrano.rb
|
141
|
+
- lib/foghorn/recipes.rb
|
142
|
+
- lib/foghorn/tasks/foghorn.rake
|
143
|
+
- lib/foghorn/version.rb
|
144
|
+
- spec.rb
|
145
|
+
homepage: https://bitbucket.org/dolphinmicro/foghorn
|
146
|
+
licenses:
|
147
|
+
- MIT
|
148
|
+
metadata: {}
|
149
|
+
post_install_message:
|
150
|
+
rdoc_options: []
|
151
|
+
require_paths:
|
152
|
+
- lib
|
153
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
154
|
+
requirements:
|
155
|
+
- - ! '>='
|
156
|
+
- !ruby/object:Gem::Version
|
157
|
+
version: '0'
|
158
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
159
|
+
requirements:
|
160
|
+
- - ! '>='
|
161
|
+
- !ruby/object:Gem::Version
|
162
|
+
version: '0'
|
163
|
+
requirements: []
|
164
|
+
rubyforge_project:
|
165
|
+
rubygems_version: 2.4.1
|
166
|
+
signing_key:
|
167
|
+
specification_version: 4
|
168
|
+
summary: Tag roles in EC2, not in your deploy scripts
|
169
|
+
test_files: []
|