rscalr 0.0.1
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/.gitignore +18 -0
- data/README.md +4 -0
- data/lib/rscalr.rb +7 -0
- data/lib/rscalr/api/scalr.rb +150 -0
- data/lib/rscalr/model/dashboard.rb +69 -0
- data/lib/rscalr/model/farm.rb +64 -0
- data/lib/rscalr/model/farm_role.rb +14 -0
- data/lib/rscalr/model/role.rb +7 -0
- data/lib/rscalr/model/script.rb +88 -0
- data/lib/rscalr/model/server.rb +7 -0
- data/lib/rscalr/version.rb +3 -0
- data/rscalr.gemspec +16 -0
- metadata +58 -0
data/.gitignore
ADDED
data/README.md
ADDED
data/lib/rscalr.rb
ADDED
@@ -0,0 +1,150 @@
|
|
1
|
+
require 'openssl'
|
2
|
+
require 'net/http'
|
3
|
+
require 'cgi'
|
4
|
+
require 'rexml/document'
|
5
|
+
|
6
|
+
class Scalr
|
7
|
+
attr_accessor :config
|
8
|
+
|
9
|
+
# Default versions
|
10
|
+
$DEFAULT_VERSION = '2.3.0'
|
11
|
+
$DEFAULT_AUTH_VERSION = '3'
|
12
|
+
|
13
|
+
def initialize(config)
|
14
|
+
@config = config
|
15
|
+
@config[:version] = $DEFAULT_VERSION if @config[:version].nil?
|
16
|
+
@config[:auth_version] = $DEFAULT_AUTH_VERSION if @config[:auth_version].nil?
|
17
|
+
end
|
18
|
+
|
19
|
+
def generate_sig(action, timestamp)
|
20
|
+
message = action + ':' + @config[:key_id] + ':' + timestamp
|
21
|
+
hexdigest = OpenSSL::HMAC.hexdigest('sha256', @config[:key_secret], message)
|
22
|
+
[[hexdigest].pack("H*")].pack("m0")
|
23
|
+
end
|
24
|
+
|
25
|
+
def execute_api_call(action, action_params=nil)
|
26
|
+
|
27
|
+
begin
|
28
|
+
params = { :Action => action, :TimeStamp => Time.now.strftime("%Y-%m-%dT%H:%M:%SZ") }
|
29
|
+
params.merge!(action_params) unless action_params.nil?
|
30
|
+
|
31
|
+
params[:Signature] = generate_sig(action, params[:TimeStamp])
|
32
|
+
params[:Version] = @config[:version]
|
33
|
+
params[:AuthVersion] = @config[:auth_version]
|
34
|
+
params[:KeyID] = @config[:key_id]
|
35
|
+
|
36
|
+
uri = URI("https://api.scalr.net/?" + hash_to_querystring(params))
|
37
|
+
|
38
|
+
response = Net::HTTP.start(uri.host, uri.port, :use_ssl => true) do |http|
|
39
|
+
request = Net::HTTP::Get.new uri.request_uri
|
40
|
+
http.request request # Net::HTTPResponse object
|
41
|
+
end
|
42
|
+
|
43
|
+
case response
|
44
|
+
when Net::HTTPSuccess then
|
45
|
+
result = ScalrResponse.new response.body
|
46
|
+
else
|
47
|
+
result = build_error_response(response)
|
48
|
+
end
|
49
|
+
|
50
|
+
rescue => ex
|
51
|
+
result = build_error_response(ex.message)
|
52
|
+
end
|
53
|
+
|
54
|
+
result
|
55
|
+
end
|
56
|
+
|
57
|
+
def build_error_response(message)
|
58
|
+
result = ScalrResponse.new "<?xml version='1.0?>"
|
59
|
+
result.add_element("Error")
|
60
|
+
ele = REXML::Element.new "TransactionID"
|
61
|
+
ele.text = generate_sig(message, Time.now.strftime("%Y-%m-%dT%H:%M:%SZ"))
|
62
|
+
result.root.elements << ele
|
63
|
+
ele = REXML::Element.new "Message"
|
64
|
+
ele.text = message
|
65
|
+
result.root.elements << ele
|
66
|
+
|
67
|
+
result
|
68
|
+
end
|
69
|
+
|
70
|
+
def hash_to_querystring(h)
|
71
|
+
h.map{|k,v| "#{k.to_s}=#{CGI::escape(v.to_s)}"}.join('&')
|
72
|
+
end
|
73
|
+
|
74
|
+
|
75
|
+
#=================== API Section ===================================
|
76
|
+
|
77
|
+
def farms_list
|
78
|
+
execute_api_call('FarmsList')
|
79
|
+
end
|
80
|
+
|
81
|
+
def scripts_list
|
82
|
+
execute_api_call('ScriptsList')
|
83
|
+
end
|
84
|
+
|
85
|
+
def farm_get_details(farm_id)
|
86
|
+
execute_api_call('FarmGetDetails', { :FarmID => farm_id })
|
87
|
+
end
|
88
|
+
|
89
|
+
def script_execute(farm_id, script_id, timeout=30, async=:no_async, farm_role_id=nil, server_id=nil, revsion=nil, config_vars=nil)
|
90
|
+
async_int = 0
|
91
|
+
async_int = 1 if async == :async
|
92
|
+
|
93
|
+
params = { :FarmID => farm_id, :ScriptID => script_id, :Timeout => timeout, :Async => async_int }
|
94
|
+
params[:FarmRoleID] = farm_role_id unless farm_role_id.nil?
|
95
|
+
params[:ServerID] = server_id unless server_id.nil?
|
96
|
+
params[:Revision] = revsion unless revsion.nil?
|
97
|
+
if config_vars != nil
|
98
|
+
config_vars.each {|key, value|
|
99
|
+
params["ConfigVariables[#{CGI::escape(key)}]"] = value
|
100
|
+
}
|
101
|
+
end
|
102
|
+
|
103
|
+
execute_api_call('ScriptExecute', params)
|
104
|
+
end
|
105
|
+
|
106
|
+
def script_get_details(script_id)
|
107
|
+
execute_api_call('ScriptGetDetails', { :ScriptID => script_id })
|
108
|
+
end
|
109
|
+
|
110
|
+
def farm_role_parameters_list(farm_role_id)
|
111
|
+
execute_api_call('FarmRoleParametersList', { :FarmRoleID => farm_role_id })
|
112
|
+
end
|
113
|
+
|
114
|
+
def farm_role_update_parameter_value(farm_role_id, param_name, param_value)
|
115
|
+
execute_api_call('FarmRoleUpdateParameterValue', { :FarmRoleID => farm_role_id, :ParamName => param_name, :ParamValue => param_value })
|
116
|
+
end
|
117
|
+
|
118
|
+
def scripting_logs_list(farm_id, server_id=nil, start=nil, limit=nil)
|
119
|
+
params = { :FarmID => farm_id }
|
120
|
+
params[:ServerID] = server_id unless server_id.nil?
|
121
|
+
params[:StartFrom] = start unless start.nil?
|
122
|
+
params[:RecordsLimit] = limit unless limit.nil?
|
123
|
+
|
124
|
+
execute_api_call('ScriptingLogsList', params)
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
class ScalrResponse < REXML::Document
|
129
|
+
|
130
|
+
def initialize http_response_body=nil
|
131
|
+
if http_response_body.nil?
|
132
|
+
super
|
133
|
+
else
|
134
|
+
super http_response_body
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
def success?
|
139
|
+
root.name != 'Error'
|
140
|
+
end
|
141
|
+
|
142
|
+
def error_message
|
143
|
+
if success?
|
144
|
+
nil
|
145
|
+
else
|
146
|
+
root.elements['Message'].text
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
@@ -0,0 +1,69 @@
|
|
1
|
+
require 'rscalr/model/farm'
|
2
|
+
require 'rscalr/model/script'
|
3
|
+
|
4
|
+
class Dashboard
|
5
|
+
|
6
|
+
def initialize client
|
7
|
+
@client = client
|
8
|
+
end
|
9
|
+
|
10
|
+
def get_farm(name)
|
11
|
+
if @farms.nil?
|
12
|
+
load_farms
|
13
|
+
end
|
14
|
+
@farms[name]
|
15
|
+
end
|
16
|
+
|
17
|
+
def load_farms
|
18
|
+
@farms = {} if @farms == nil
|
19
|
+
|
20
|
+
scalr_response = @client.farms_list
|
21
|
+
scalr_response.root.each_element('FarmSet/Item') { |row|
|
22
|
+
farm = Farm.new @client
|
23
|
+
|
24
|
+
row.each_element { |prop|
|
25
|
+
if "ID" == prop.name
|
26
|
+
farm.id = prop.text
|
27
|
+
elsif "Name" == prop.name
|
28
|
+
farm.name = prop.text
|
29
|
+
elsif "Status" == prop.name
|
30
|
+
farm.status = prop.text
|
31
|
+
end
|
32
|
+
}
|
33
|
+
@farms[farm.name] = farm
|
34
|
+
}
|
35
|
+
|
36
|
+
@farms
|
37
|
+
end
|
38
|
+
|
39
|
+
def get_script(name)
|
40
|
+
if @scripts.nil?
|
41
|
+
load_scripts
|
42
|
+
end
|
43
|
+
@scripts[name]
|
44
|
+
end
|
45
|
+
|
46
|
+
def load_scripts
|
47
|
+
@scripts = {}
|
48
|
+
|
49
|
+
scalr_response = @client.scripts_list
|
50
|
+
scalr_response.root.each_element('ScriptSet/Item') { |row|
|
51
|
+
script = Script.new @client
|
52
|
+
|
53
|
+
row.each_element { |prop|
|
54
|
+
if "ID" == prop.name
|
55
|
+
script.id = prop.text
|
56
|
+
elsif "Name" == prop.name
|
57
|
+
script.name = prop.text
|
58
|
+
elsif "Description" == prop.name
|
59
|
+
script.description = prop.text
|
60
|
+
elsif "LatestRevision" == prop.name
|
61
|
+
script.latest_revision = prop.text.to_i
|
62
|
+
end
|
63
|
+
}
|
64
|
+
@scripts[script.name] = script
|
65
|
+
}
|
66
|
+
|
67
|
+
@scripts
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
class Farm
|
2
|
+
attr_accessor :id, :name, :status
|
3
|
+
|
4
|
+
def initialize client
|
5
|
+
@client = client
|
6
|
+
end
|
7
|
+
|
8
|
+
def get_role(name)
|
9
|
+
if @farm_roles.nil?
|
10
|
+
load_details
|
11
|
+
end
|
12
|
+
@farm_roles[name]
|
13
|
+
end
|
14
|
+
|
15
|
+
def load_details
|
16
|
+
@farm_roles = {}
|
17
|
+
|
18
|
+
scalr_response = @client.farm_get_details @id
|
19
|
+
scalr_response.root.each_element('FarmRoleSet/Item') { |row|
|
20
|
+
role = FarmRole.new
|
21
|
+
|
22
|
+
row.each_element { |prop|
|
23
|
+
if "ID" == prop.name
|
24
|
+
role.farm_role_id = prop.text
|
25
|
+
elsif "RoleID" == prop.name
|
26
|
+
role.role_id = prop.text
|
27
|
+
elsif "Name" == prop.name
|
28
|
+
role.name = prop.text
|
29
|
+
elsif "ServerSet" == prop.name
|
30
|
+
prop.each_element { |server_element|
|
31
|
+
server = Server.new
|
32
|
+
server.role = role
|
33
|
+
|
34
|
+
server_element.each_element { |server_prop|
|
35
|
+
if "ServerID" == prop.name
|
36
|
+
server.server_id = prop.text
|
37
|
+
elsif "ExternalIP" == prop.name
|
38
|
+
server.external_ip = prop.text
|
39
|
+
elsif "InternalIP" == prop.name
|
40
|
+
server.external_ip = prop.text
|
41
|
+
elsif "Status" == prop.name
|
42
|
+
server.status = prop.text
|
43
|
+
elsif "Index" == prop.name
|
44
|
+
server.index = prop.text.to_i
|
45
|
+
elsif "Uptime" == prop.name
|
46
|
+
server.uptime = prop.text.to_f
|
47
|
+
end
|
48
|
+
}
|
49
|
+
role.servers << server
|
50
|
+
}
|
51
|
+
end
|
52
|
+
}
|
53
|
+
|
54
|
+
@farm_roles[role.name] = role
|
55
|
+
}
|
56
|
+
|
57
|
+
@farm_roles
|
58
|
+
end
|
59
|
+
|
60
|
+
def to_s
|
61
|
+
"{ type: \"farm\", id: #{@id}, name: \"#{@name}\", status: #{@status} }"
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'rscalr/model/role'
|
2
|
+
|
3
|
+
class FarmRole < Role
|
4
|
+
attr_accessor :farm_role_id, :servers
|
5
|
+
|
6
|
+
def initialize
|
7
|
+
@servers = []
|
8
|
+
end
|
9
|
+
|
10
|
+
def to_s
|
11
|
+
"{ type: \"farm_role\", farm_role_id: #{@farm_role_id}, role_id: #{@role_id}, name: \"#{@name}\", num_servers: #{@servers.size} }"
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
require 'time'
|
2
|
+
|
3
|
+
class Script
|
4
|
+
attr_accessor :id, :name, :description, :latest_revision, :details
|
5
|
+
|
6
|
+
def initialize client
|
7
|
+
@client = client
|
8
|
+
end
|
9
|
+
|
10
|
+
def execute(farm_id, timeout=30, async=:no_async, farm_role_id=nil, server_id=nil, revision=nil, config_vars=nil)
|
11
|
+
set_revision(revision) # Side effect!
|
12
|
+
@client.script_execute farm_id, @id, timeout, async, farm_role_id, server_id, @revision, config_vars
|
13
|
+
end
|
14
|
+
|
15
|
+
def load_details
|
16
|
+
@details = ScriptDetails.new @id
|
17
|
+
scalr_response = @client.script_get_details @id
|
18
|
+
scalr_response.root.each_element('ScriptRevisionSet/Item') { |row|
|
19
|
+
revision = ScriptRevision.new
|
20
|
+
|
21
|
+
row.each_element { |prop|
|
22
|
+
if "Revision" == prop.name
|
23
|
+
revision.revision = prop.text.to_i
|
24
|
+
elsif "Date" == prop.name
|
25
|
+
revision.date = Time.parse(prop.text)
|
26
|
+
elsif "ConfigVariables" == prop.name
|
27
|
+
prop.each_element { |configvar_element|
|
28
|
+
configvar_element.each_element { |configvar_prop|
|
29
|
+
if "Name" == prop.name
|
30
|
+
revision.config_variables << prop.text
|
31
|
+
end
|
32
|
+
}
|
33
|
+
}
|
34
|
+
end
|
35
|
+
}
|
36
|
+
|
37
|
+
@details.revisions[revision.revision] = revision
|
38
|
+
}
|
39
|
+
|
40
|
+
@details
|
41
|
+
end
|
42
|
+
|
43
|
+
def get_config_variables
|
44
|
+
load_details unless @details != nil
|
45
|
+
@revision = @latest_revision unless @revision != nil
|
46
|
+
puts "Rev: #{@revision} -- Deets: #{@details}"
|
47
|
+
@details.revisions[@revision].config_variables
|
48
|
+
end
|
49
|
+
|
50
|
+
def set_revision(revision)
|
51
|
+
if revision.nil? || revision >= @latest_revision
|
52
|
+
@revision = @latest_revision
|
53
|
+
elsif revision < 1
|
54
|
+
@revision = 1
|
55
|
+
else
|
56
|
+
@revision = revision
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def to_s
|
61
|
+
"{ type: \"script\", id: #{@id}, name: \"#{@name}\" }"
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
class ScriptDetails
|
66
|
+
attr_accessor :id, :revisions
|
67
|
+
|
68
|
+
def initialize id
|
69
|
+
@id = id
|
70
|
+
@revisions = {}
|
71
|
+
end
|
72
|
+
|
73
|
+
def to_s
|
74
|
+
"{ type: \"script-details\", script_id: #{@id}, num_revisions: #{@revisions.size}}"
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
class ScriptRevision
|
79
|
+
attr_accessor :revision, :date, :config_variables
|
80
|
+
|
81
|
+
def initialize
|
82
|
+
@config_variables = []
|
83
|
+
end
|
84
|
+
|
85
|
+
def to_s
|
86
|
+
"{ type: \"script-revision\", revision: #{@revision}, date: \"#{@date}\", vars: \"#{@config_variables}\"}"
|
87
|
+
end
|
88
|
+
end
|
data/rscalr.gemspec
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "rscalr/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "rscalr"
|
7
|
+
s.version = Rscalr::VERSION
|
8
|
+
s.authors = ["Nathan Smith"]
|
9
|
+
s.email = ["nate@branchout.com"]
|
10
|
+
s.summary = %q{Ruby implementation of the Scalr API}
|
11
|
+
s.description = %q{Rscalr is a Ruby implementation of the Scalr API, written to interface cleanly with Chef and other internal release management tasks.}
|
12
|
+
s.files = `git ls-files`.split("\n")
|
13
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
14
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
15
|
+
s.require_paths = ["lib"]
|
16
|
+
end
|
metadata
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rscalr
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Nathan Smith
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-02-03 00:00:00.000000000 Z
|
13
|
+
dependencies: []
|
14
|
+
description: Rscalr is a Ruby implementation of the Scalr API, written to interface
|
15
|
+
cleanly with Chef and other internal release management tasks.
|
16
|
+
email:
|
17
|
+
- nate@branchout.com
|
18
|
+
executables: []
|
19
|
+
extensions: []
|
20
|
+
extra_rdoc_files: []
|
21
|
+
files:
|
22
|
+
- .gitignore
|
23
|
+
- README.md
|
24
|
+
- lib/rscalr.rb
|
25
|
+
- lib/rscalr/api/scalr.rb
|
26
|
+
- lib/rscalr/model/dashboard.rb
|
27
|
+
- lib/rscalr/model/farm.rb
|
28
|
+
- lib/rscalr/model/farm_role.rb
|
29
|
+
- lib/rscalr/model/role.rb
|
30
|
+
- lib/rscalr/model/script.rb
|
31
|
+
- lib/rscalr/model/server.rb
|
32
|
+
- lib/rscalr/version.rb
|
33
|
+
- rscalr.gemspec
|
34
|
+
homepage:
|
35
|
+
licenses: []
|
36
|
+
post_install_message:
|
37
|
+
rdoc_options: []
|
38
|
+
require_paths:
|
39
|
+
- lib
|
40
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
47
|
+
none: false
|
48
|
+
requirements:
|
49
|
+
- - ! '>='
|
50
|
+
- !ruby/object:Gem::Version
|
51
|
+
version: '0'
|
52
|
+
requirements: []
|
53
|
+
rubyforge_project:
|
54
|
+
rubygems_version: 1.8.24
|
55
|
+
signing_key:
|
56
|
+
specification_version: 3
|
57
|
+
summary: Ruby implementation of the Scalr API
|
58
|
+
test_files: []
|