dumbwaiter 0.3.2 → 0.3.3

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: 20f20eaec8369f54bbc83d62f0ade5f99a735f98
4
- data.tar.gz: 1c4eca739c2b72e96ee6908df4ace69fc688f081
3
+ metadata.gz: 037e1bc90c9a39f1a16951de02c0e95ea6fc0bcb
4
+ data.tar.gz: 3cf2330286cabb2f654b92a43458ff1177d75eab
5
5
  SHA512:
6
- metadata.gz: fc160beefbabeca4bc392e0b75c8c80d5e94a4abf2aadde4c39c10dbad7e0a5cf3d82cc26164a7d182fb23c7864c2a2bf5a87ba5967b929f434c43fbe7d0b9f7
7
- data.tar.gz: 2bad21df531df0ea6ec2ba1f4b394a2ebc6528f627d0b72ff440035c248f1fa1b5899e9385fdccba0af9ebd24ed6d8433e6b8485dbf91dadc3d0f950b9974d0c
6
+ metadata.gz: f3acb077db8d3514aff5babefb2e783f7fa0b92c70b2cd62240f518452821e4bfbcd8b4d9ef084ff0cba6a1b783ce1e3411b5dcd8587487c86f5e61b2d7e578e
7
+ data.tar.gz: e4ac64be955b4545a0dc4430509dc2541d61bec1b2836da0df9af3f161ce9050c5f9057e5d8063f4cbc032c65cd37e9c7aea6f0ca58aa30a447446f05c1d48e0
data/Guardfile CHANGED
@@ -8,6 +8,5 @@ end
8
8
 
9
9
  guard :bundler do
10
10
  watch('Gemfile')
11
- # Uncomment next line if your Gemfile contains the `gemspec' command.
12
- # watch(/^.+\.gemspec/)
11
+ watch(/^.+\.gemspec/)
13
12
  end
data/README.md CHANGED
@@ -21,7 +21,7 @@ Dumbwaiter prescribes a very specific OpsWorks-centric workflow with the same
21
21
  feeling of the Scalarium gem's CLI:
22
22
 
23
23
  * Create OpsWorks stacks, layers and instances via YAML files
24
- * Collect custom Chef cookbooks via Berkshelf and upload to S3
24
+ * Assign a stack's custom Chef cookbooks as a custom GitHub repo
25
25
  * Create an application corresponding to a GitHub repo
26
26
  * Run versioned deployments, rollbacks and one-off recipes
27
27
 
@@ -61,6 +61,10 @@ Deploy the "cinnamon" branch of the "syrup" application to the "Pancake" stack:
61
61
 
62
62
  `dumbwaiter deploy Pancake syrup cinnamon`
63
63
 
64
+ List all the layers of the "Pizza" stack:
65
+
66
+ `dumbwaiter layers Pizza`
67
+
64
68
  List the deployments on the "Maniacal Checklist" stack:
65
69
 
66
70
  `dumbwaiter list "Maniacal Checklist"`
@@ -73,6 +77,10 @@ Roll back the "Snowman" stack's "dandruff" application:
73
77
 
74
78
  `dumbwaiter rollback Snowman dandruff`
75
79
 
80
+ Run the sneakers recipe on all the angsty instances of the "Documentarian" stack:
81
+
82
+ `dumbwaiter run_recipe Documentarian angsty sneakers`
83
+
76
84
  List the stacks and apps in your OpsWorks environment:
77
85
 
78
86
  `dumbwaiter stacks`
@@ -5,7 +5,7 @@ require "dumbwaiter/stack"
5
5
 
6
6
  module Dumbwaiter
7
7
  class Cli < Thor
8
- desc "deploy STACK_NAME APP_NAME GIT_REF", "Deploy an application revision"
8
+ desc "deploy STACK APP GIT_REF", "Deploy an application revision"
9
9
  def deploy(stack_name, app_name, revision)
10
10
  stack = Stack.find(stack_name)
11
11
  app = App.find(stack, app_name)
@@ -14,12 +14,12 @@ module Dumbwaiter
14
14
  raise Thor::Error.new(e.message)
15
15
  end
16
16
 
17
- desc "list STACK_NAME", "List all the deployments for a stack"
17
+ desc "list STACK", "List all the deployments for a stack"
18
18
  def list(stack_name)
19
19
  stack = Stack.find(stack_name)
20
20
 
21
21
  deployments = stack.deployments.select do |deployment|
22
- %w(rollback deploy update_custom_cookbooks).include?(deployment.command_name)
22
+ %w(rollback deploy update_custom_cookbooks execute_recipes).include?(deployment.command_name)
23
23
  end
24
24
 
25
25
  deployments.each do |deployment|
@@ -36,7 +36,7 @@ module Dumbwaiter
36
36
  raise Thor::Error.new(e.message)
37
37
  end
38
38
 
39
- desc "rollback STACK_NAME APP_NAME", "Roll back an application"
39
+ desc "rollback STACK APP", "Roll back an application"
40
40
  def rollback(stack_name, app_name)
41
41
  stack = Stack.find(stack_name)
42
42
  app = App.find(stack, app_name)
@@ -45,9 +45,27 @@ module Dumbwaiter
45
45
  raise Thor::Error.new(e.message)
46
46
  end
47
47
 
48
+ desc "run_recipe STACK LAYER RECIPE", "Run a recipe against a stack's layer"
49
+ def run_recipe(stack_name, layer_name, recipe)
50
+ stack = Stack.find(stack_name)
51
+ layer = Layer.find(stack, layer_name)
52
+ layer.run_recipe(recipe)
53
+ rescue Dumbwaiter::Stack::NotFound, Dumbwaiter::Layer::NotFound => e
54
+ raise Thor::Error.new(e.message)
55
+ end
56
+
48
57
  desc "stacks", "List all the stacks"
49
58
  def stacks
50
59
  Stack.all.each { |stack| Kernel.puts("#{stack.name}: #{stack.apps.map(&:name).join(', ')}") }
51
60
  end
61
+
62
+ desc "layers STACK", "List all the layers for a stack"
63
+ def layers(stack_name)
64
+ stack = Stack.find(stack_name)
65
+ layer_names = stack.layers.map(&:shortname)
66
+ Kernel.puts(layer_names.join(', '))
67
+ rescue Dumbwaiter::Stack::NotFound => e
68
+ raise Thor::Error.new(e.message)
69
+ end
52
70
  end
53
71
  end
@@ -0,0 +1,18 @@
1
+ class Dumbwaiter::Instance
2
+ attr_reader :layer, :opsworks_instance, :opsworks
3
+
4
+ def self.all(layer, opsworks = Aws::OpsWorks.new(region: "us-east-1"))
5
+ instances = opsworks.describe_instances(layer_id: layer.id).instances
6
+ instances.map { |instance| new(layer, instance, opsworks) }
7
+ end
8
+
9
+ def initialize(layer, opsworks_instance, opsworks)
10
+ @layer = layer
11
+ @opsworks_instance = opsworks_instance
12
+ @opsworks = opsworks
13
+ end
14
+
15
+ def id
16
+ opsworks_instance.instance_id
17
+ end
18
+ end
@@ -0,0 +1,46 @@
1
+ require "dumbwaiter/instance"
2
+
3
+ class Dumbwaiter::Layer
4
+ attr_reader :stack, :opsworks_layer, :opsworks
5
+
6
+ class NotFound < Exception; end
7
+
8
+ def self.all(stack, opsworks = Aws::OpsWorks.new(region: "us-east-1"))
9
+ opsworks.describe_layers(stack_id: stack.id).layers.map { |layer| new(stack, layer, opsworks) }
10
+ end
11
+
12
+ def self.find(stack, layer_name, opsworks = Aws::OpsWorks.new(region: "us-east-1"))
13
+ layer = all(stack, opsworks).detect { |layer| layer.shortname == layer_name }
14
+ raise NotFound.new("No layer found with name #{layer_name}") if layer.nil?
15
+ layer
16
+ end
17
+
18
+ def initialize(stack, opsworks_layer, opsworks)
19
+ @stack = stack
20
+ @opsworks_layer = opsworks_layer
21
+ @opsworks = opsworks
22
+ end
23
+
24
+ def id
25
+ opsworks_layer.layer_id
26
+ end
27
+
28
+ def shortname
29
+ opsworks_layer.shortname
30
+ end
31
+
32
+ def run_recipe(recipe)
33
+ opsworks.create_deployment(
34
+ stack_id: stack.id,
35
+ instance_ids: instances.map(&:id),
36
+ command: {
37
+ name: "execute_recipes",
38
+ args: {recipes: [recipe]}
39
+ }
40
+ )
41
+ end
42
+
43
+ def instances
44
+ @instances ||= Dumbwaiter::Instance.all(self, opsworks)
45
+ end
46
+ end
@@ -1,5 +1,6 @@
1
1
  require "dumbwaiter/app"
2
2
  require "dumbwaiter/deployment"
3
+ require "dumbwaiter/layer"
3
4
 
4
5
  class Dumbwaiter::Stack
5
6
  attr_reader :opsworks, :opsworks_stack
@@ -37,6 +38,10 @@ class Dumbwaiter::Stack
37
38
  @deployments ||= Dumbwaiter::Deployment.all(self, opsworks)
38
39
  end
39
40
 
41
+ def layers
42
+ @layers ||= Dumbwaiter::Layer.all(self, opsworks)
43
+ end
44
+
40
45
  def rechef
41
46
  opsworks.create_deployment(stack_id: id, command: {name: "update_custom_cookbooks"})
42
47
  end
@@ -1,3 +1,3 @@
1
1
  module Dumbwaiter
2
- VERSION = "0.3.2"
2
+ VERSION = "0.3.3"
3
3
  end
@@ -2,6 +2,7 @@ require "spec_helper"
2
2
 
3
3
  describe Dumbwaiter::Cli do
4
4
  let(:fake_app) { double(:app, name: "reifel") }
5
+ let(:fake_layer) { double(:layer, shortname: "beans") }
5
6
  let(:fake_stack) { double(:stack, name: "ducks", id: "wat", apps: [fake_app]) }
6
7
 
7
8
  subject(:cli) { Dumbwaiter::Cli.new }
@@ -9,6 +10,7 @@ describe Dumbwaiter::Cli do
9
10
  before do
10
11
  Dumbwaiter::Stack.stub(all: [fake_stack])
11
12
  Dumbwaiter::App.stub(all: [fake_app])
13
+ Dumbwaiter::Layer.stub(all: [fake_layer])
12
14
  end
13
15
 
14
16
  describe "#deploy" do
@@ -88,6 +90,15 @@ describe Dumbwaiter::Cli do
88
90
  end
89
91
  end
90
92
 
93
+ context "when the deployment is a recipe execution" do
94
+ let(:fake_deployment) { double(:deployment, command_name: "execute_recipes", to_log: "whee!") }
95
+
96
+ it "lists the deployment" do
97
+ Kernel.should_receive(:puts).with("whee!")
98
+ cli.list("ducks")
99
+ end
100
+ end
101
+
91
102
  context "when the deployment is something else" do
92
103
  let(:fake_deployment) { double(:deployment, command_name: "gargle", to_log: "brblrgl") }
93
104
 
@@ -105,10 +116,20 @@ describe Dumbwaiter::Cli do
105
116
  end
106
117
  end
107
118
 
108
- describe "#stacks" do
109
- it "lists the stacks" do
110
- Kernel.should_receive(:puts).with("ducks: reifel")
111
- cli.stacks
119
+ describe "#layers" do
120
+ context "when the stack exists" do
121
+ before { fake_stack.stub(layers: [fake_layer]) }
122
+
123
+ it "lists the layers" do
124
+ Kernel.should_receive(:puts).with("beans")
125
+ cli.layers("ducks")
126
+ end
127
+ end
128
+
129
+ context "when the stack does not exist" do
130
+ it "blows up" do
131
+ expect { cli.layers("wat") }.to raise_error(Thor::Error)
132
+ end
112
133
  end
113
134
  end
114
135
 
@@ -126,4 +147,34 @@ describe Dumbwaiter::Cli do
126
147
  end
127
148
  end
128
149
  end
150
+
151
+ describe "#run_recipe" do
152
+ context "when the stack exists" do
153
+ context "when the layer exists" do
154
+ it "runs the recipe on the layer" do
155
+ fake_layer.should_receive(:run_recipe).with("meatballs")
156
+ cli.run_recipe("ducks", "beans", "meatballs")
157
+ end
158
+ end
159
+
160
+ context "when the layer does not exist" do
161
+ it "blows up" do
162
+ expect { cli.run_recipe("ducks", "brick", "meatballs") }.to raise_error(Thor::Error)
163
+ end
164
+ end
165
+ end
166
+
167
+ context "when the stack does not exist" do
168
+ it "blows up" do
169
+ expect { cli.run_recipe("toques", "beans", "meatballs") }.to raise_error(Thor::Error)
170
+ end
171
+ end
172
+ end
173
+
174
+ describe "#stacks" do
175
+ it "lists the stacks" do
176
+ Kernel.should_receive(:puts).with("ducks: reifel")
177
+ cli.stacks
178
+ end
179
+ end
129
180
  end
@@ -38,6 +38,7 @@ describe Dumbwaiter::Deployment do
38
38
 
39
39
  describe ".all" do
40
40
  let(:fake_stack) { double(:stack, id: "pancakes") }
41
+
41
42
  it "fetches all the deployments" do
42
43
  fake_opsworks.should_receive(:describe_deployments).with(stack_id: "pancakes")
43
44
  Dumbwaiter::Deployment.all(fake_stack, fake_opsworks).should have(1).app
@@ -0,0 +1,22 @@
1
+ require "spec_helper"
2
+
3
+ describe Dumbwaiter::Instance do
4
+ let(:fake_stack) { double(:stack, id: "pancakes") }
5
+ let(:fake_layer) { double(:layer, id: "pinto", stack: fake_stack) }
6
+
7
+ let(:fake_instance) { double(:instance, instance_id: "dragons") }
8
+ let(:fake_instances) { double(:instances, instances: [fake_instance]) }
9
+ let(:fake_opsworks) { double(:opsworks, describe_instances: fake_instances) }
10
+
11
+ subject(:instance) { Dumbwaiter::Instance.new(fake_layer, fake_instance, fake_opsworks) }
12
+
13
+ its(:opsworks_instance) { should == fake_instance }
14
+ its(:id) { should == "dragons" }
15
+
16
+ describe ".all" do
17
+ it "fetches all the instances" do
18
+ fake_opsworks.should_receive(:describe_instances).with(layer_id: "pinto")
19
+ Dumbwaiter::Instance.all(fake_layer, fake_opsworks).should have(1).instance
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,56 @@
1
+ require "spec_helper"
2
+
3
+ describe Dumbwaiter::Layer do
4
+ let(:fake_stack) { double(:stack, id: "pancakes") }
5
+ let(:fake_layer) { double(:layer, shortname: "meaty", layer_id: "pinto") }
6
+ let(:fake_layers) { double(:layers, layers: [fake_layer]) }
7
+ let(:fake_instance) { double(:instance, id: "dragons") }
8
+ let(:fake_instances) { double(:instances, instances: [fake_instance]) }
9
+ let(:fake_opsworks) { double(:opsworks, describe_layers: fake_layers, describe_instances: fake_instances) }
10
+
11
+ before do
12
+ Dumbwaiter::Instance.stub(all: [fake_instance])
13
+ end
14
+
15
+ subject(:layer) { Dumbwaiter::Layer.new(fake_stack, fake_layer, fake_opsworks) }
16
+
17
+ its(:opsworks_layer) { should == fake_layer }
18
+ its(:id) { should == "pinto" }
19
+ its(:shortname) { should == "meaty" }
20
+
21
+ its(:instances) { should == [fake_instance] }
22
+
23
+ describe ".all" do
24
+ it "fetches all the deployments" do
25
+ fake_opsworks.should_receive(:describe_layers).with(stack_id: "pancakes")
26
+ Dumbwaiter::Layer.all(fake_stack, fake_opsworks).should have(1).layer
27
+ end
28
+ end
29
+
30
+ describe ".find" do
31
+ context "when the layer exists" do
32
+ it "finds the layer by name" do
33
+ Dumbwaiter::Layer.find(fake_stack, "meaty", fake_opsworks).shortname.should == "meaty"
34
+ end
35
+ end
36
+
37
+ context "when the layer does not exist" do
38
+ it "blows up" do
39
+ expect {
40
+ Dumbwaiter::Layer.find(fake_stack, "brick", fake_opsworks)
41
+ }.to raise_error(Dumbwaiter::Layer::NotFound)
42
+ end
43
+ end
44
+ end
45
+
46
+ describe "#run_recipe" do
47
+ it "executes a recipe" do
48
+ fake_opsworks.should_receive(:create_deployment) do |params|
49
+ params[:stack_id].should == "pancakes"
50
+ params[:instance_ids].should == ["dragons"]
51
+ params[:command].should == {name: "execute_recipes", args: {recipes: ["meatballs"]}}
52
+ end
53
+ layer.run_recipe("meatballs")
54
+ end
55
+ end
56
+ end
@@ -6,12 +6,14 @@ describe Dumbwaiter::Stack do
6
6
  let(:fake_opsworks) { double(:opsworks, describe_stacks: fake_stacks) }
7
7
  let(:fake_app) { double(:app) }
8
8
  let(:fake_deployment) { double(:deployment) }
9
+ let(:fake_layer) { double(:layer) }
9
10
 
10
11
  subject(:stack) { Dumbwaiter::Stack.new(fake_stack, fake_opsworks) }
11
12
 
12
13
  before do
13
14
  Dumbwaiter::App.stub(all: [fake_app])
14
15
  Dumbwaiter::Deployment.stub(all: [fake_deployment])
16
+ Dumbwaiter::Layer.stub(all: [fake_layer])
15
17
  end
16
18
 
17
19
  its(:opsworks_stack) { should == fake_stack }
@@ -20,6 +22,7 @@ describe Dumbwaiter::Stack do
20
22
 
21
23
  its(:apps) { should == [fake_app] }
22
24
  its(:deployments) { should == [fake_deployment] }
25
+ its(:layers) { should == [fake_layer] }
23
26
 
24
27
  describe ".all" do
25
28
  it "fetches all the stacks" do
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dumbwaiter
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.2
4
+ version: 0.3.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Doc Ritezel
@@ -118,6 +118,8 @@ files:
118
118
  - lib/dumbwaiter/cli.rb
119
119
  - lib/dumbwaiter/deployment.rb
120
120
  - lib/dumbwaiter/deployment_custom_json.rb
121
+ - lib/dumbwaiter/instance.rb
122
+ - lib/dumbwaiter/layer.rb
121
123
  - lib/dumbwaiter/stack.rb
122
124
  - lib/dumbwaiter/version.rb
123
125
  - script/ci.sh
@@ -125,6 +127,8 @@ files:
125
127
  - spec/lib/dumbwaiter/cli_spec.rb
126
128
  - spec/lib/dumbwaiter/deployment_custom_json_spec.rb
127
129
  - spec/lib/dumbwaiter/deployment_spec.rb
130
+ - spec/lib/dumbwaiter/instance_spec.rb
131
+ - spec/lib/dumbwaiter/layer_spec.rb
128
132
  - spec/lib/dumbwaiter/stack_spec.rb
129
133
  - spec/spec_helper.rb
130
134
  homepage: https://github.com/minifast/dumbwaiter
@@ -156,5 +160,7 @@ test_files:
156
160
  - spec/lib/dumbwaiter/cli_spec.rb
157
161
  - spec/lib/dumbwaiter/deployment_custom_json_spec.rb
158
162
  - spec/lib/dumbwaiter/deployment_spec.rb
163
+ - spec/lib/dumbwaiter/instance_spec.rb
164
+ - spec/lib/dumbwaiter/layer_spec.rb
159
165
  - spec/lib/dumbwaiter/stack_spec.rb
160
166
  - spec/spec_helper.rb