right_api 0.1.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/.gitignore ADDED
@@ -0,0 +1,2 @@
1
+ pkg
2
+ moneypools-right_api.gemspec
data/README ADDED
File without changes
data/Rakefile ADDED
@@ -0,0 +1,37 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "#{ENV['GITHUB'] ? 'moneypools-' : ''}right_api"
8
+ gem.summary = %Q{A ruby wrapper for the RightScale api}
9
+ gem.description = "A ruby wrapper for the RightScale api"
10
+ gem.email = "mpdev@businesslogic.com"
11
+ gem.homepage = "http://github.com/moneypools/right_api"
12
+ gem.authors = ["MoneyPools"]
13
+ gem.add_dependency('hpricot')
14
+ gem.add_dependency('activesupport')
15
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
16
+ end
17
+
18
+ rescue LoadError
19
+ puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
20
+ end
21
+
22
+ require 'rake/rdoctask'
23
+ Rake::RDocTask.new do |rdoc|
24
+ if File.exist?('VERSION.yml')
25
+ config = YAML.load(File.read('VERSION.yml'))
26
+ version = "#{config[:major]}.#{config[:minor]}.#{config[:patch]}"
27
+ else
28
+ version = ""
29
+ end
30
+
31
+ rdoc.rdoc_dir = 'rdoc'
32
+ rdoc.title = "right_api #{version}"
33
+ rdoc.rdoc_files.include('README*')
34
+ rdoc.rdoc_files.include('lib/**/*.rb')
35
+ end
36
+
37
+ task :default => ['gemspec', 'build']
data/VERSION.yml ADDED
@@ -0,0 +1,4 @@
1
+ ---
2
+ :minor: 1
3
+ :patch: 2
4
+ :major: 0
data/install.rb ADDED
@@ -0,0 +1 @@
1
+ # Install hook code here
@@ -0,0 +1,19 @@
1
+ module AccessibleFragment
2
+ def initialize(data, connection)
3
+ @data = data
4
+ @connection = connection
5
+ end
6
+
7
+ def has_element?(elem)
8
+ !@data.search(elem).size.zero?
9
+ end
10
+
11
+ def get_element(elem)
12
+ @data.search(elem).first.inner_text
13
+ end
14
+
15
+ def method_missing(method_name, *args)
16
+ name_with_dashes = method_name.to_s.gsub('_', '-')
17
+ has_element?(name_with_dashes) ? get_element(name_with_dashes) : super
18
+ end
19
+ end
@@ -0,0 +1,144 @@
1
+ require 'net/https'
2
+ require 'cgi'
3
+
4
+ class HttpServer
5
+ attr_accessor :response_error_checker, :handle_errors, :headers
6
+ attr_reader :last_response
7
+
8
+ def initialize(server_config, timeout)
9
+ @server_url, @port, @username, @password = server_config['server_url'], server_config['port'], server_config['username'], server_config['password']
10
+ @timeout = timeout
11
+ raise 'No configuration for timeout length' if @timeout.nil?
12
+
13
+ @handle_errors = true
14
+ @response_error_checker = Proc.new do |response, path|
15
+ false
16
+ end
17
+
18
+ @headers = {
19
+ 'User-Agent' => 'Mozilla/4.0',
20
+ 'Content-Type' => 'application/x-www-form-urlencoded',
21
+ 'Connection' => 'Keep-Alive',
22
+ 'X-API-VERSION' => RightScale::API_VERSION
23
+ }
24
+ end
25
+
26
+ def delete(resource, &block)
27
+ connect(resource, Net::HTTP::Delete, &block)
28
+ end
29
+
30
+ def get(resource, &block)
31
+ connect(resource, Net::HTTP::Get, &block)
32
+ end
33
+
34
+ def get_with_params(resource, params={}, &block)
35
+ connect(resource, Net::HTTP::Get, encode_params(params), &block)
36
+ end
37
+
38
+ def post(resource, params={}, &block)
39
+ connect(resource, Net::HTTP::Post, encode_params(params), &block)
40
+ end
41
+
42
+ def put(resource, params={}, &block)
43
+ connect(resource, Net::HTTP::Put, encode_params(params), &block)
44
+ end
45
+
46
+ def with_error_handling_disabled
47
+ original_handle_errors = handle_errors
48
+ self.handle_errors = false
49
+
50
+ result = yield
51
+ ensure
52
+ self.handle_errors = original_handle_errors
53
+ end
54
+
55
+ private
56
+
57
+ def connect(resource, request_object, *args, &block)
58
+ uri = URI.parse url(resource)
59
+ req = request_object.new(uri.path, @headers)
60
+ req.basic_auth @username, @password if @username
61
+
62
+ response_data = nil
63
+
64
+ begin
65
+ create_http(uri).start do |http|
66
+ response, data = http.request(req, *args)
67
+
68
+ block.call(self, response) if block
69
+
70
+ @last_response = response_data = data_from(response)
71
+ end
72
+ rescue Timeout::Error
73
+ raise "A timeout error occured when connecting to #{resource}.\nThe timeout is currently set to #{@timeout} seconds."
74
+ rescue Errno::ECONNREFUSED
75
+ raise "Could not connect when connecting to #{resource} - the server (#{@server_url}) is down."
76
+ end
77
+
78
+ check_response_for_errors(response_data, uri.path) if handle_errors
79
+
80
+ response_data
81
+ end
82
+
83
+ def data_from(response)
84
+ case response
85
+ when Net::HTTPSuccess
86
+ response.body
87
+ when Net::HTTPRedirection
88
+ response['location']
89
+ end
90
+ end
91
+
92
+ def create_http(uri)
93
+ http = Net::HTTP.new(uri.host, uri.port)
94
+ http.use_ssl = true if uri.port == 443
95
+ http.read_timeout = @timeout
96
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
97
+
98
+ # http.set_debug_output $stderr
99
+
100
+ http
101
+ end
102
+
103
+ def url(resource)
104
+ "#{server_path}/#{resource.sub /^\//, ''}"
105
+ end
106
+
107
+ def server_path
108
+ @port ? "#{@server_url}:#{@port}" : @server_url
109
+ end
110
+
111
+ def encode_params(hash)
112
+ params = transform_params(hash)
113
+ stringify_params(params)
114
+ end
115
+
116
+ def transform_params(hash)
117
+ params = []
118
+
119
+ hash.each do |key, value|
120
+ if value.instance_of? Hash
121
+ params.concat transform_params(value).each{|elements| elements[0].unshift key}
122
+ else
123
+ params.push [[key], value]
124
+ end
125
+ end
126
+
127
+ params
128
+ end
129
+
130
+ def stringify_params(params)
131
+ params.map do |keys, value|
132
+ left = keys.join('[') + (']' * (keys.length - 1))
133
+ "#{left}=#{CGI::escape(value.to_s)}"
134
+ end.join('&')
135
+ end
136
+
137
+ def check_response_for_errors(response, path)
138
+ if response && response.include?('No connection could be made')
139
+ raise Errno::ECONNREFUSED
140
+ elsif @response_error_checker.call(response, path)
141
+ raise "An error occured requesting #{path} - please check the XML response:\n #{response}\nCurrent data:\n#{@data}"
142
+ end
143
+ end
144
+ end
@@ -0,0 +1,148 @@
1
+ require 'hpricot'
2
+ require 'active_support'
3
+
4
+ require 'right_api/http_server'
5
+ require 'right_api/accessible_fragment'
6
+
7
+ # Rightscale
8
+ module RightScale
9
+ API_VERSION = '1.0'
10
+
11
+ class Base
12
+ include AccessibleFragment
13
+
14
+ def initialize(data)
15
+ raise "You must first establish a connection via Base.establish_connection" unless @@connection
16
+ @data = data
17
+ end
18
+
19
+ def id
20
+ @id ||= href.split('/').last
21
+ end
22
+
23
+ def data
24
+ @data ||= @@connection.get("/#{plural_name}/#{id}")
25
+ end
26
+
27
+ def update_attribute(attribute, value)
28
+ @@connection.put("/#{self.class.plural_name}/#{id}", "#{self.class.class_name}[#{attribute}]" => value)
29
+ end
30
+
31
+ def self.class_name
32
+ name.split("::").last.underscore
33
+ end
34
+
35
+ def self.plural_name
36
+ class_name.pluralize
37
+ end
38
+
39
+ def self.xml_name
40
+ class_name.dasherize
41
+ end
42
+
43
+
44
+ def self.establish_connection(user, password, account_id)
45
+ url = "https://my.rightscale.com/api/acct/#{account_id}"
46
+ params = {'server_url' => url, 'username' => user, 'password' => password}
47
+
48
+ @@connection = HttpServer.new(params, 60)
49
+ @@connection.get('/login')
50
+
51
+ params = {'server_url' => "https://my.rightscale.com"}
52
+
53
+ @@non_api_connection = HttpServer.new(params, 60)
54
+ @@non_api_connection.post('/sessions', 'email' => user, 'password' => password) do |server, response|
55
+ cookies = response.response.get_fields('set-cookie')
56
+ session_cookie = cookies.detect { |cookie| cookie =~ /_session_id/ }
57
+ cookie_header_for_request = session_cookie.split(';').first
58
+ server.headers = server.headers.merge('cookie' => cookie_header_for_request, 'HTTP_X_REQUESTED_WITH' => 'XMLHttpRequest')
59
+ end
60
+
61
+ end
62
+
63
+ def self.all(opts={})
64
+ find_with_options(opts)
65
+ end
66
+
67
+ def self.first(opts={})
68
+ find_first_with_options(opts)
69
+ end
70
+
71
+ def self.find(opts=nil)
72
+ if opts.nil?
73
+ raise "Find requires a hash of options or an id"
74
+ elsif opts.is_a?(Hash)
75
+ find_with_options(opts)
76
+ else
77
+ find(:id => opts)
78
+ end
79
+ end
80
+
81
+ private
82
+
83
+ def self.find_with_options(opts)
84
+ find_all
85
+
86
+ @all.select do |member|
87
+ opts.all? {|k, v| member.send(k) == v }
88
+ end
89
+ end
90
+
91
+ def self.find_first_with_options(opts)
92
+ find_all
93
+
94
+ @all.detect do |member|
95
+ opts.all? {|k, v| member.send(k) == v }
96
+ end
97
+ end
98
+
99
+ def self.find_all
100
+ return unless @all.nil?
101
+
102
+ response = @@connection.get("/#{plural_name}")
103
+ doc = Hpricot::XML(response)
104
+ @all = (doc / xml_name).map {|data| new(data)}
105
+ end
106
+ end
107
+
108
+ class Deployment < Base
109
+ def self.find_by_nickname(nickname)
110
+ deployments = all.select { |deployment| deployment.nickname == nickname }
111
+
112
+ if deployments.size != 1
113
+ raise "Found #{deployments.size} deployments matching #{nickname}. Double check your nickname, it should be exact to avoid hitting the deployment."
114
+ end
115
+
116
+ deployments.first
117
+ end
118
+
119
+ def servers
120
+ (@data / 'server').map {|data| Server.new(data)}
121
+ end
122
+ end
123
+
124
+ class Server < Base
125
+ attr_accessor :aws_id
126
+
127
+ def deployment
128
+ @deployment ||= Deployment.all.detect {|deployment| deployment.id == deployment_href.split('/').last}
129
+ end
130
+
131
+ def aws_id
132
+ @aws_id ||= @@non_api_connection.get("/servers/#{id}").scan(/i-[a-f0-9]{8}/i).first
133
+ end
134
+
135
+ def volume_rightscale_ids
136
+ puts @@non_api_connection.get("/servers/#{id}/volumes").scan(/(?=ec2_ebs_volumes\/)\d+/).inspect
137
+ end
138
+ end
139
+
140
+ class RightScript < Base
141
+ end
142
+
143
+ class Ec2EbsVolume < Base
144
+ end
145
+
146
+ class Ec2EbsSnapshot < Base
147
+ end
148
+ end
data/lib/right_api.rb ADDED
@@ -0,0 +1 @@
1
+ # require 'right_api/rightscale'
data/right_api.gemspec ADDED
@@ -0,0 +1,52 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run `rake gemspec`
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{right_api}
8
+ s.version = "0.1.2"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["MoneyPools"]
12
+ s.date = %q{2009-08-24}
13
+ s.description = %q{A ruby wrapper for the RightScale api}
14
+ s.email = %q{mpdev@businesslogic.com}
15
+ s.extra_rdoc_files = [
16
+ "README"
17
+ ]
18
+ s.files = [
19
+ ".gitignore",
20
+ "README",
21
+ "Rakefile",
22
+ "VERSION.yml",
23
+ "install.rb",
24
+ "lib/right_api.rb",
25
+ "lib/right_api/accessible_fragment.rb",
26
+ "lib/right_api/http_server.rb",
27
+ "lib/right_api/rightscale.rb",
28
+ "right_api.gemspec",
29
+ "uninstall.rb"
30
+ ]
31
+ s.homepage = %q{http://github.com/moneypools/right_api}
32
+ s.rdoc_options = ["--charset=UTF-8"]
33
+ s.require_paths = ["lib"]
34
+ s.rubygems_version = %q{1.3.3}
35
+ s.summary = %q{A ruby wrapper for the RightScale api}
36
+
37
+ if s.respond_to? :specification_version then
38
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
39
+ s.specification_version = 3
40
+
41
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
42
+ s.add_runtime_dependency(%q<hpricot>, [">= 0"])
43
+ s.add_runtime_dependency(%q<activesupport>, [">= 0"])
44
+ else
45
+ s.add_dependency(%q<hpricot>, [">= 0"])
46
+ s.add_dependency(%q<activesupport>, [">= 0"])
47
+ end
48
+ else
49
+ s.add_dependency(%q<hpricot>, [">= 0"])
50
+ s.add_dependency(%q<activesupport>, [">= 0"])
51
+ end
52
+ end
data/uninstall.rb ADDED
@@ -0,0 +1 @@
1
+ # Uninstall hook code here
metadata ADDED
@@ -0,0 +1,84 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: right_api
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.2
5
+ platform: ruby
6
+ authors:
7
+ - MoneyPools
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-10-27 00:00:00 -05:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: hpricot
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: "0"
24
+ version:
25
+ - !ruby/object:Gem::Dependency
26
+ name: activesupport
27
+ type: :runtime
28
+ version_requirement:
29
+ version_requirements: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: "0"
34
+ version:
35
+ description: A ruby wrapper for the RightScale api
36
+ email: mpdev@businesslogic.com
37
+ executables: []
38
+
39
+ extensions: []
40
+
41
+ extra_rdoc_files:
42
+ - README
43
+ files:
44
+ - .gitignore
45
+ - README
46
+ - Rakefile
47
+ - VERSION.yml
48
+ - install.rb
49
+ - lib/right_api.rb
50
+ - lib/right_api/accessible_fragment.rb
51
+ - lib/right_api/http_server.rb
52
+ - lib/right_api/rightscale.rb
53
+ - right_api.gemspec
54
+ - uninstall.rb
55
+ has_rdoc: true
56
+ homepage: http://github.com/moneypools/right_api
57
+ licenses: []
58
+
59
+ post_install_message:
60
+ rdoc_options:
61
+ - --charset=UTF-8
62
+ require_paths:
63
+ - lib
64
+ required_ruby_version: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: "0"
69
+ version:
70
+ required_rubygems_version: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - ">="
73
+ - !ruby/object:Gem::Version
74
+ version: "0"
75
+ version:
76
+ requirements: []
77
+
78
+ rubyforge_project:
79
+ rubygems_version: 1.3.5
80
+ signing_key:
81
+ specification_version: 3
82
+ summary: A ruby wrapper for the RightScale api
83
+ test_files: []
84
+