rscalr 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,18 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ coverage
6
+ InstalledFiles
7
+ lib/bundler/man
8
+ pkg
9
+ rdoc
10
+ spec/reports
11
+ test/tmp
12
+ test/version_tmp
13
+ tmp
14
+
15
+ # YARD artifacts
16
+ .yardoc
17
+ _yardoc
18
+ doc/
data/README.md ADDED
@@ -0,0 +1,4 @@
1
+ rscalr
2
+ ======
3
+
4
+ Ruby Scalr API implementation
data/lib/rscalr.rb ADDED
@@ -0,0 +1,7 @@
1
+ require 'rscalr/api/scalr'
2
+ require 'rscalr/model/dashboard'
3
+ require 'rscalr/model/farm'
4
+ require 'rscalr/model/farm_role'
5
+ require 'rscalr/model/role'
6
+ require 'rscalr/model/script'
7
+ require 'rscalr/model/server'
@@ -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,7 @@
1
+ class Role
2
+ attr_accessor :role_id, :name
3
+
4
+ def to_s
5
+ "{ type: \"role\", role_id: #{@role_id}, name: \"#{@name}\" }"
6
+ end
7
+ 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
@@ -0,0 +1,7 @@
1
+ class Server
2
+ attr_accessor :server_id, :external_ip, :internal_ip, :status, :index, :uptime, :role
3
+
4
+ def to_s
5
+ "{ type: \"server\", id: \"#{@server_id}\", external_ip: \"#{@external_ip}\", internal_ip: \"#{@internal_ip}\", role: #{@role} }"
6
+ end
7
+ end
@@ -0,0 +1,3 @@
1
+ module Rscalr
2
+ VERSION = "0.0.1"
3
+ 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: []