dumbwaiter 0.3.2 → 0.3.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 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