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