ops_worker 0.0.2
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.
- data/README.md +35 -0
- data/lib/ops_worker/app.rb +119 -0
- data/lib/ops_worker/client.rb +40 -0
- data/lib/ops_worker/deployment_status.rb +17 -0
- data/lib/ops_worker/instance.rb +28 -0
- data/lib/ops_worker/layer.rb +17 -0
- data/lib/ops_worker/logger.rb +15 -0
- data/lib/ops_worker/stack.rb +43 -0
- data/lib/ops_worker/version.rb +3 -0
- data/lib/ops_worker.rb +9 -0
- metadata +87 -0
data/README.md
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
# opsworker
|
2
|
+
|
3
|
+
Quick command line tool for handling servers on OpsWorks.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
gem install ops_worker
|
7
|
+
|
8
|
+
## Example
|
9
|
+
```ruby
|
10
|
+
require 'ops_worker'
|
11
|
+
|
12
|
+
client = OpsWorker::Client.new
|
13
|
+
# or, client = OpsWorker::Client.new(:access_key_id => "foo", :secret_access_key => "bar")
|
14
|
+
|
15
|
+
pp client.stacks
|
16
|
+
# => [#<OpsWorker::Stack f1735a57-51c3-4933-8440-4f7beb2cb2ff, homepage_staging, us-east-1>,
|
17
|
+
#<OpsWorker::Stack 3bf98404-dafc-45c4-9fa2-a17485aba4ec, homepage_production, us-east-1>]
|
18
|
+
|
19
|
+
app = client.find_app_by_name("homepage_staging")
|
20
|
+
app.instances.each do |instance|
|
21
|
+
puts("#{instance.name} is online: #{instance.online?}")
|
22
|
+
end
|
23
|
+
|
24
|
+
# Deploy the current revision branch set
|
25
|
+
app.deploy()
|
26
|
+
|
27
|
+
# Switches the current revision branch to feature/new, deploys, then switches it back
|
28
|
+
app.deploy("feature/new")
|
29
|
+
|
30
|
+
app.update_cookbooks()
|
31
|
+
|
32
|
+
app.execute_recipes(["monit"])
|
33
|
+
|
34
|
+
app.rollback()
|
35
|
+
```
|
@@ -0,0 +1,119 @@
|
|
1
|
+
module OpsWorker
|
2
|
+
class App
|
3
|
+
attr_reader :id, :stack, :name, :revision
|
4
|
+
|
5
|
+
def initialize(id, name, revision, stack, opsworks_client)
|
6
|
+
@id = id
|
7
|
+
@name = name
|
8
|
+
@stack = stack
|
9
|
+
@revision = revision
|
10
|
+
@opsworks_client = opsworks_client
|
11
|
+
end
|
12
|
+
|
13
|
+
def instances
|
14
|
+
if @instances
|
15
|
+
return @instances
|
16
|
+
end
|
17
|
+
|
18
|
+
instances_result = @opsworks_client.describe_instances(:stack_id => @stack.id, :app_id => @id)[:instances]
|
19
|
+
@instances = instances_result.map do |instance_hash|
|
20
|
+
layers = @stack.layers.select {|l| instance_hash[:layer_ids].include?(l.id)}
|
21
|
+
Instance.new(instance_hash[:instance_id],
|
22
|
+
instance_hash[:hostname],
|
23
|
+
instance_hash[:status],
|
24
|
+
instance_hash[:instance_type],
|
25
|
+
instance_hash[:elastic_ip],
|
26
|
+
instance_hash[:availability_zone],
|
27
|
+
self,
|
28
|
+
layers)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
# Updates the revision in this app such that all future deploys pull from this revision
|
33
|
+
# @param revision String revision to update, e.g., "feature/foo" or "d6053592ee39e64c5f092b0ba6e9cd1aa8334828"
|
34
|
+
def update_revision(revision)
|
35
|
+
OpsWorker.logger.info {"Changing revision from #{@revision} to #{revision} for app #{@name}"}
|
36
|
+
|
37
|
+
@opsworks_client.update_app(:app_id => @id, :app_source => {:revision => revision})
|
38
|
+
@revision = revision
|
39
|
+
reload()
|
40
|
+
end
|
41
|
+
|
42
|
+
# @param revision String revision to deploy, e.g., "feature/foo" or "d6053592ee39e64c5f092b0ba6e9cd1aa8334828"
|
43
|
+
def deploy(revision = nil)
|
44
|
+
OpsWorker.logger.info {"Deploying app #{@name} from #{revision || @revision}"}
|
45
|
+
|
46
|
+
if revision
|
47
|
+
existing_revision = @revision.dup()
|
48
|
+
update_revision(revision)
|
49
|
+
end
|
50
|
+
|
51
|
+
deployment_status = create_deployment(:deploy)
|
52
|
+
|
53
|
+
if revision
|
54
|
+
update_revision(existing_revision)
|
55
|
+
end
|
56
|
+
|
57
|
+
deployment_status
|
58
|
+
end
|
59
|
+
|
60
|
+
def rollback
|
61
|
+
OpsWorker.logger.info {"Rolling back #{@name}"}
|
62
|
+
create_deployment(:rollback)
|
63
|
+
end
|
64
|
+
|
65
|
+
def restart
|
66
|
+
OpsWorker.logger.info {"Restarting #{@name}"}
|
67
|
+
create_deployment(:restart)
|
68
|
+
end
|
69
|
+
|
70
|
+
def update_cookbooks
|
71
|
+
OpsWorker.logger.info {"Updating cookbooks for #{@name}"}
|
72
|
+
create_deployment(:update_custom_cookbooks, {}, :all)
|
73
|
+
end
|
74
|
+
|
75
|
+
# @param recipe_names Array of string recipe names, e.g., ["custom::recipe1"]
|
76
|
+
def execute_recipes(recipe_names)
|
77
|
+
OpsWorker.logger.info {"Executing recipes #{recipe_names} on #{@name}"}
|
78
|
+
create_deployment(:execute_recipes, {"recipes" => recipe_names}, :all)
|
79
|
+
end
|
80
|
+
|
81
|
+
def to_s
|
82
|
+
"#<OpsWorker::App #{@id}, #{@name}, stack: #{@stack.name}>"
|
83
|
+
end
|
84
|
+
|
85
|
+
def reload
|
86
|
+
@instances = nil
|
87
|
+
end
|
88
|
+
|
89
|
+
private
|
90
|
+
# @param instance_category Symbol, :all or :app_servers
|
91
|
+
def create_deployment(deployment_name, args = {}, instance_category = :app_servers)
|
92
|
+
case instance_category
|
93
|
+
when :all
|
94
|
+
instances = online_instances()
|
95
|
+
when :app_servers
|
96
|
+
instances = app_server_instances()
|
97
|
+
else
|
98
|
+
raise ArgumentError.new("Unknown instance category argument: #{instance_category}")
|
99
|
+
end
|
100
|
+
instance_ids = instances.map(&:id)
|
101
|
+
result = @opsworks_client.create_deployment(:stack_id => @stack.id,
|
102
|
+
:app_id => @id,
|
103
|
+
:command => {:args => args, :name => deployment_name.to_s()},
|
104
|
+
:instance_ids => instance_ids
|
105
|
+
)
|
106
|
+
DeploymentStatus.new(result[:deployment_id], @opsworks_client)
|
107
|
+
end
|
108
|
+
|
109
|
+
def app_server_instances
|
110
|
+
online_instances().select do |i|
|
111
|
+
i.layers.any? {|l| l.type == "rails-app" || l.type == "custom"}
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
def online_instances
|
116
|
+
instances().select {|i| i.online?}
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'aws-sdk'
|
2
|
+
|
3
|
+
module OpsWorker
|
4
|
+
class Client
|
5
|
+
def initialize(options = {})
|
6
|
+
@opsworks_client = AWS::OpsWorks.new(options).client
|
7
|
+
end
|
8
|
+
|
9
|
+
def find_app_by_name(name)
|
10
|
+
stacks().each do |stack|
|
11
|
+
app = stack.apps.detect {|a| a.name == name}
|
12
|
+
|
13
|
+
if app
|
14
|
+
return app
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
return nil
|
19
|
+
end
|
20
|
+
|
21
|
+
def stacks
|
22
|
+
if @stacks
|
23
|
+
return @stacks
|
24
|
+
end
|
25
|
+
|
26
|
+
stacks = @opsworks_client.describe_stacks()[:stacks]
|
27
|
+
@stacks = stacks.map do |stack_hash|
|
28
|
+
Stack.new(stack_hash[:stack_id], stack_hash[:name], stack_hash[:region], @opsworks_client)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def reload
|
33
|
+
@stacks = nil
|
34
|
+
end
|
35
|
+
|
36
|
+
def method_missing(method_name, *args, &block)
|
37
|
+
@opsworks_client.__send__(method_name, *args, &block)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module OpsWorker
|
2
|
+
class DeploymentStatus
|
3
|
+
def initialize(id, opsworks_client)
|
4
|
+
@id = id
|
5
|
+
@opsworks_client = opsworks_client
|
6
|
+
end
|
7
|
+
|
8
|
+
def status
|
9
|
+
commands().map {|c| c[:status] }
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
def commands
|
14
|
+
@opsworks_client.describe_commands(:deployment_id => @id)[:commands]
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module OpsWorker
|
2
|
+
class Instance
|
3
|
+
attr_reader :id, :hostname, :status, :app, :layers, :elastic_ip, :instance_type, :availability_zone
|
4
|
+
|
5
|
+
def initialize(id, hostname, status, instance_type, elastic_ip, availability_zone, app, layers)
|
6
|
+
@id = id
|
7
|
+
@hostname = hostname
|
8
|
+
@status = status
|
9
|
+
@instance_type = instance_type
|
10
|
+
@elastic_ip = elastic_ip
|
11
|
+
@availability_zone = availability_zone
|
12
|
+
@app = app
|
13
|
+
@layers = layers
|
14
|
+
end
|
15
|
+
|
16
|
+
def stopped?
|
17
|
+
@status == "stopped"
|
18
|
+
end
|
19
|
+
|
20
|
+
def online?
|
21
|
+
@status == "online"
|
22
|
+
end
|
23
|
+
|
24
|
+
def to_s
|
25
|
+
"#<OpsWorker::Instance #{@id}, host: #{@hostname}, status: #{@status}, type: #{@instance_type}, layers: #{@layers.map(&:name)}>"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module OpsWorker
|
2
|
+
class Layer
|
3
|
+
attr_reader :id, :name, :type, :stack
|
4
|
+
|
5
|
+
def initialize(id, name, type, stack, opsworks_client)
|
6
|
+
@id = id
|
7
|
+
@name = name
|
8
|
+
@stack = stack
|
9
|
+
@type = type
|
10
|
+
@opsworks_client = opsworks_client
|
11
|
+
end
|
12
|
+
|
13
|
+
def to_s
|
14
|
+
"#<OpsWorker::Layer #{@id}, #{@name}, stack: #{@stack.name}>"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module OpsWorker
|
2
|
+
class Stack
|
3
|
+
attr_reader :id, :name, :region
|
4
|
+
|
5
|
+
def initialize(id, name, region, opsworks_client)
|
6
|
+
@id = id
|
7
|
+
@name = name
|
8
|
+
@region = region
|
9
|
+
@opsworks_client = opsworks_client
|
10
|
+
end
|
11
|
+
|
12
|
+
def apps
|
13
|
+
if @apps
|
14
|
+
return @apps
|
15
|
+
end
|
16
|
+
|
17
|
+
apps_result = @opsworks_client.describe_apps(:stack_id => @id)[:apps]
|
18
|
+
@apps = apps_result.map do |app_hash|
|
19
|
+
App.new(app_hash[:app_id], app_hash[:name], app_hash[:app_source][:revision], self, @opsworks_client)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def layers
|
24
|
+
if @layers
|
25
|
+
return @layers
|
26
|
+
end
|
27
|
+
|
28
|
+
layers_result = @opsworks_client.describe_layers(:stack_id => @id)[:layers]
|
29
|
+
@layers = layers_result.map do |layer_hash|
|
30
|
+
Layer.new(layer_hash[:layer_id], layer_hash[:name], layer_hash[:type], self, @opsworks_client)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def to_s
|
35
|
+
"#<OpsWorker::Stack #{@id}, #{@name}, #{@region}>"
|
36
|
+
end
|
37
|
+
|
38
|
+
def reload
|
39
|
+
@layers = nil
|
40
|
+
@apps = nil
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
data/lib/ops_worker.rb
ADDED
@@ -0,0 +1,9 @@
|
|
1
|
+
$LOAD_PATH << File.dirname(__FILE__)
|
2
|
+
require 'ops_worker/app'
|
3
|
+
require 'ops_worker/client'
|
4
|
+
require 'ops_worker/deployment_status'
|
5
|
+
require 'ops_worker/instance'
|
6
|
+
require 'ops_worker/layer'
|
7
|
+
require 'ops_worker/logger'
|
8
|
+
require 'ops_worker/stack'
|
9
|
+
require 'ops_worker/version'
|
metadata
ADDED
@@ -0,0 +1,87 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ops_worker
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.2
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Jon Hyman
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-04-13 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: aws-sdk
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: rspec
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
type: :development
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
description: A simple wrapper for common OpsWorks tasks.
|
47
|
+
email: jon@appboy.com
|
48
|
+
executables: []
|
49
|
+
extensions: []
|
50
|
+
extra_rdoc_files: []
|
51
|
+
files:
|
52
|
+
- lib/ops_worker/app.rb
|
53
|
+
- lib/ops_worker/client.rb
|
54
|
+
- lib/ops_worker/deployment_status.rb
|
55
|
+
- lib/ops_worker/instance.rb
|
56
|
+
- lib/ops_worker/layer.rb
|
57
|
+
- lib/ops_worker/logger.rb
|
58
|
+
- lib/ops_worker/stack.rb
|
59
|
+
- lib/ops_worker/version.rb
|
60
|
+
- lib/ops_worker.rb
|
61
|
+
- README.md
|
62
|
+
homepage: https://github.com/jonhyman/opsworker
|
63
|
+
licenses: []
|
64
|
+
post_install_message:
|
65
|
+
rdoc_options: []
|
66
|
+
require_paths:
|
67
|
+
- lib
|
68
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
69
|
+
none: false
|
70
|
+
requirements:
|
71
|
+
- - ! '>='
|
72
|
+
- !ruby/object:Gem::Version
|
73
|
+
version: '0'
|
74
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
75
|
+
none: false
|
76
|
+
requirements:
|
77
|
+
- - ! '>='
|
78
|
+
- !ruby/object:Gem::Version
|
79
|
+
version: '0'
|
80
|
+
requirements: []
|
81
|
+
rubyforge_project:
|
82
|
+
rubygems_version: 1.8.23
|
83
|
+
signing_key:
|
84
|
+
specification_version: 3
|
85
|
+
summary: A simple wrapper for common OpsWorks tasks.
|
86
|
+
test_files: []
|
87
|
+
has_rdoc:
|