rest_connection 0.0.9 → 0.0.10

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore CHANGED
@@ -1,2 +1,3 @@
1
1
  *.swp
2
2
  *.swo
3
+ pkg/*
data/README.rdoc ADDED
@@ -0,0 +1,49 @@
1
+ = rest_connection Quick Start
2
+ == Install
3
+ ==== Installing with rubygems
4
+ "gem install rest_connection"
5
+
6
+ ==== Installing from source
7
+ "git clone http://github.com/jeremyd/rest_connection.git"
8
+ "gem install jeweler rspec"
9
+ "rake check_dependencies" <- Install any gems listed.
10
+ "rake install"
11
+
12
+ == Configuration
13
+
14
+ You must setup ~/.rest_connection/rest_api_config.yaml or /etc/rest_connection/rest_api_config.yaml
15
+
16
+ Copy the example from GEMHOME/rest_connection/examples/rest_api_config.yaml.sample and fill in your connection info.
17
+
18
+ Pro Tip: to find a GEMHOME, use gemedit
19
+ "gem install gemedit"
20
+ "gem edit rest_connection"
21
+
22
+ == Usage: some IRB samples
23
+
24
+ $ irb
25
+ ruby> require 'rubygems'; require 'rest_connection'
26
+
27
+ === Lookup and run a RightScript
28
+
29
+ first_fe = Server.find(:first) { |s| s.nickname =~ /Front End/ }
30
+ st = ServerTemplate.find(first_fe.server_template_href)
31
+ connect_script = st.executables.detect { |ex| ex.name =~ /LB [app|mongrels]+ to HA proxy connect/i }
32
+ state = first_fe.run_executable(connect_script)
33
+ state.wait_for_completed
34
+
35
+ === Stop a Deployment
36
+
37
+ deployment = Deployment.find(opts[:id])
38
+ my_servers = deployment.servers
39
+ my_servers.each { |s| s.stop }
40
+ my_servers.each { |s| s.wait_for_state("stopped") }
41
+
42
+ === Activate an Ec2ServerArray / Display instances IPs
43
+
44
+ my_array = Ec2ServerArray.find(opts[:href])
45
+ my_array.active = true
46
+ my_array.save
47
+
48
+ puts my_array.instances.map { |i| i['ip-address'] }
49
+
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.9
1
+ 0.0.10
@@ -1,4 +1,4 @@
1
- #!/usr/bin/ruby
1
+ #!/usr/bin/env ruby
2
2
  require 'rubygems'
3
3
  require 'trollop'
4
4
  require 'rest_connection'
@@ -0,0 +1,27 @@
1
+ # This file is part of RestConnection
2
+ #
3
+ # RestConnection is free software: you can redistribute it and/or modify
4
+ # it under the terms of the GNU General Public License as published by
5
+ # the Free Software Foundation, either version 3 of the License, or
6
+ # (at your option) any later version.
7
+ #
8
+ # RestConnection is distributed in the hope that it will be useful,
9
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
+ # GNU General Public License for more details.
12
+ #
13
+ # You should have received a copy of the GNU General Public License
14
+ # along with RestConnection. If not, see <http://www.gnu.org/licenses/>.
15
+ #
16
+ class AlertSpec
17
+ include RightScale::Api::Base
18
+ extend RightScale::Api::BaseExtend
19
+
20
+
21
+
22
+ def attach(params)
23
+ connection.post('alert_spec_subjects.js' , :alert_spec_subject => params)
24
+ end
25
+
26
+
27
+ end
@@ -28,16 +28,18 @@ class AuditEntry
28
28
  include RightScale::Api::Base
29
29
  extend RightScale::Api::BaseExtend
30
30
 
31
- def wait_for_state(state)
32
- while(1)
31
+ def wait_for_state(state, timeout=900)
32
+ while(timeout > 0)
33
33
  reload
34
34
  connection.logger("state is #{self.state}, waiting for #{state}")
35
35
  friendly_url = "https://my.rightscale.com/audit_entries/"
36
36
  friendly_url += self.href.split(/\//).last
37
37
  raise "FATAL error, #{self.summary}\nSee Audit: API:#{self.href}, WWW:<a href='#{friendly_url}'>#{friendly_url}</a>\n" if self.state == 'failed'
38
- sleep 5
38
+ sleep 30
39
+ timeout -= 30
39
40
  return true if state == self.state
40
41
  end
42
+ raise "FATAL: Timeout waiting for Executable to complete. State was #{self.state}" if timeout <= 0
41
43
  end
42
44
 
43
45
  def wait_for_completed(legacy=nil)
@@ -17,4 +17,8 @@
17
17
  class Ec2EbsVolume
18
18
  include RightScale::Api::Base
19
19
  extend RightScale::Api::BaseExtend
20
+
21
+ def attach(params)
22
+ connection.post('component_ec2_ebs_volumes.js' , :component_ec2_ebs_volume => params)
23
+ end
20
24
  end
@@ -13,16 +13,13 @@
13
13
  # You should have received a copy of the GNU General Public License
14
14
  # along with RestConnection. If not, see <http://www.gnu.org/licenses/>.
15
15
 
16
- # Example:
17
- # a = Ec2ServerArray.new(:href => "https://validhref")
18
- # st = ServerTemplate.new(:href => "https://validhref")
19
- # st.executables.find(:nickname
20
- # a.run_script_on_all(
21
-
22
16
  class Ec2ServerArray
23
17
  include RightScale::Api::Base
24
18
  extend RightScale::Api::BaseExtend
25
19
 
20
+ # Example:
21
+ # right_script = @server_template.executables.first
22
+ # result = @my_array.run_script_on_all(right_script, [@server_template.href])
26
23
  def run_script_on_all(script, server_template_hrefs, inputs=nil)
27
24
  serv_href = URI.parse(self.href)
28
25
  options = Hash.new
@@ -29,6 +29,7 @@ require 'rest_connection/rightscale/multi_cloud_image'
29
29
  require 'rest_connection/rightscale/tag'
30
30
  require 'rest_connection/rightscale/rs_internal'
31
31
  require 'rest_connection/rightscale/audit_entry'
32
+ require 'rest_connection/rightscale/alert_spec'
32
33
  require 'rest_connection/rightscale/ec2_ebs_volume'
33
34
  require 'rest_connection/rightscale/ec2_ebs_snapshot'
34
35
  require 'rest_connection/rightscale/server_internal'
@@ -30,27 +30,36 @@ class Server
30
30
  newrecord
31
31
  end
32
32
 
33
- def wait_for_state(st)
33
+ # waits until the specified state is reached for this Server
34
+ # *st <~String> the name of the state to wait for, eg. "operational"
35
+ # *timeout <~Integer> optional, how long to wait for the state before declare failure (in seconds).
36
+ def wait_for_state(st,timeout=1200)
34
37
  reload
35
38
  connection.logger("#{nickname} is #{self.state}")
36
- while(1)
39
+ while(timeout > 0)
37
40
  return true if state == st
38
41
  raise "FATAL error, this server is stranded and needs to be #{st}: #{nickname}, see audit: #{self.audit_link}" if state.include?('stranded')
39
- sleep 5
42
+ sleep 30
43
+ timeout -= 30
40
44
  connection.logger("waiting for server #{nickname} to go #{st}, state is #{state}")
41
45
  reload
42
46
  end
47
+ raise "FATAL, this server #{self.audit_link} timed out waiting for the state to be #{st}" if timeout <= 0
43
48
  end
44
49
 
50
+ # waits until the server is operational and dns_name is available
45
51
  def wait_for_operational_with_dns
52
+ timeout = 600
46
53
  wait_for_state("operational")
47
- while(1)
48
- connection.logger "waiting for dns-name for #{self.nickname}"
49
- break if self['dns-name'] && !self['dns-name'].empty?
54
+ while(timeout > 0)
50
55
  self.settings
51
- sleep 2
56
+ break if self['dns-name'] && !self['dns-name'].empty?
57
+ connection.logger "waiting for dns-name for #{self.nickname}"
58
+ sleep 30
59
+ timeout -= 30
52
60
  end
53
61
  connection.logger "got DNS: #{self['dns-name']}"
62
+ raise "FATAL, this server #{self.audit_link} timed out waiting for DNS" if timeout <= 0
54
63
  end
55
64
 
56
65
  def audit_link
@@ -89,8 +98,8 @@ class Server
89
98
  @server_internal.stop
90
99
  end
91
100
 
92
- # This should be used with v5 images only.
93
- # executable to run can be an Executable or RightScript object
101
+ # Works on v4 and v5 images.
102
+ # *executable can be an <~Executable> or <~RightScript>
94
103
  def run_executable(executable, opts=nil)
95
104
  script_options = Hash.new
96
105
  script_options[:server] = Hash.new
@@ -141,6 +150,13 @@ class Server
141
150
  @params.merge! connection.get(serv_href.path + "/settings")
142
151
  end
143
152
 
153
+ def attach_volume(params)
154
+ hash = {}
155
+ hash[:server] = params
156
+ serv_href = URI.parse(self.href)
157
+ connection.post(serv_href.path + "/attach_volume", hash)
158
+ end
159
+
144
160
  def get_sketchy_data
145
161
  serv_href = URI.parse(self.href)
146
162
  @params.merge! connection.get(serv_href.path + "/get_sketchy_data")
@@ -162,12 +178,6 @@ class Server
162
178
  end
163
179
  end
164
180
 
165
- def events
166
- my_events = Event.new
167
- id = self.href.split(/\//).last
168
- my_events.filter_by(:server_id, id)
169
- end
170
-
171
181
  def relaunch
172
182
  self.stop
173
183
  self.wait_for_state("stopped")
@@ -182,31 +192,12 @@ class Server
182
192
  old_state = self.state unless old_state
183
193
  connection.logger("#{nickname} is #{self.state}")
184
194
  return true if self.state != old_state
185
- sleep 5
186
- timer += 5
195
+ sleep 30
196
+ timer += 30
187
197
  connection.logger("waiting for server #{nickname} to change from #{old_state} state.")
188
198
  end
189
199
  raise("FATAL: timeout after #{timeout}s waiting for state change")
190
200
  end
191
201
 
192
- # DOES NOT WORK: fragile web scraping
193
- # def relaunch
194
- # unless state == "stopped"
195
- # wind_monkey
196
- # server_id = self.href.split(/\//).last
197
- # base_url = URI.parse(self.href)
198
- # base_url.path = "/servers/#{server_id}"
199
- #
200
- # s = agent.get(base_url.to_s)
201
- # relaunch = s.links.detect {|d| d.to_s == "Relaunch"}
202
- # prelaunch_page = agent.get(relaunch.href)
203
- # debugger
204
- # launch_form = prelaunch_page.forms[2]
205
- # launch_form.radiobuttons_with(:name => 'launch_immediately').first.check
206
- # agent.submit(launch_form, launch_form.buttons.first)
207
- # else
208
- # connection.logger("WARNING: detected server is #{self.state}, skipping relaunch")
209
- # end
210
- # end
211
202
  end
212
203
 
@@ -20,13 +20,15 @@
20
20
  class Status
21
21
  include RightScale::Api::Base
22
22
  extend RightScale::Api::BaseExtend
23
- def wait_for_completed(audit_link = "no audit link available")
24
- while(1)
23
+ def wait_for_completed(audit_link = "no audit link available", timeout = 900)
24
+ while(timeout > 0)
25
25
  reload
26
26
  return true if self.state == "completed"
27
27
  raise "FATAL error, script failed\nSee Audit: #{audit_link}" if self.state == 'failed'
28
- sleep 5
28
+ sleep 30
29
+ timeout -= 30
29
30
  connection.logger("querying status of right_script.. got: #{self.state}")
30
31
  end
32
+ raise "FATAL: Timeout waiting for Executable to complete. State was #{self.state}" if timeout <= 0
31
33
  end
32
34
  end
@@ -42,7 +42,7 @@ module SshHax
42
42
  result = nil
43
43
  output = ""
44
44
  connection.logger("Running: #{run_this}")
45
- Net::SSH.start(host_dns, 'root', :keys => ssh_key_config(ssh_key)) do |ssh|
45
+ Net::SSH.start(host_dns, 'root', :keys => ssh_key_config(ssh_key), :user_known_hosts_file => "/dev/null") do |ssh|
46
46
  cmd_channel = ssh.open_channel do |ch1|
47
47
  ch1.on_request('exit-status') do |ch, data|
48
48
  status = data.read_long
@@ -152,15 +152,13 @@ module SshHax
152
152
  retry_count = 0
153
153
  while (!success && retry_count < SSH_RETRY_COUNT) do
154
154
  begin
155
- Net::SSH.start(host_dns, 'root', :keys => ssh_key_config(ssh_key)) do |ssh|
155
+ Net::SSH.start(host_dns, 'root', :keys => ssh_key_config(ssh_key), :user_known_hosts_file => "/dev/null") do |ssh|
156
156
  cmd_channel = ssh.open_channel do |ch1|
157
157
  ch1.on_request('exit-status') do |ch, data|
158
158
  status = data.read_long
159
159
  end
160
- output += "Running: #{command}\n"
161
160
  ch1.exec(command) do |ch2, success|
162
161
  unless success
163
- output = "ERROR: SSH cmd failed to exec"
164
162
  status = 1
165
163
  end
166
164
  ch2.on_data do |ch, data|
@@ -174,10 +172,11 @@ module SshHax
174
172
  end
175
173
  rescue Exception => e
176
174
  retry_count += 1 # opening the ssh channel failed -- try again.
175
+ connection.logger "ERROR during SSH session to #{host_dns}, retrying #{retry_count}: #{e} #{e.backtrace}"
177
176
  sleep 10
178
177
  end
179
178
  end
180
- connection.logger output
179
+ connection.logger "SSH Run: #{command} on #{host_dns}. Retry was #{retry_count}. Exit status was #{status}. Output below ---\n#{output}\n---"
181
180
  return {:status => status, :output => output}
182
181
  end
183
182
 
@@ -5,19 +5,19 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{rest_connection}
8
- s.version = "0.0.9"
8
+ s.version = "0.0.10"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Jeremy Deininger"]
12
- s.date = %q{2010-06-23}
12
+ s.date = %q{2010-09-02}
13
13
  s.description = %q{provides rest_connection}
14
14
  s.email = %q{jeremy@rubyonlinux.org}
15
15
  s.extra_rdoc_files = [
16
- "README"
16
+ "README.rdoc"
17
17
  ]
18
18
  s.files = [
19
19
  ".gitignore",
20
- "README",
20
+ "README.rdoc",
21
21
  "Rakefile",
22
22
  "VERSION",
23
23
  "config/rest_api_config.yaml.sample",
@@ -31,6 +31,7 @@ Gem::Specification.new do |s|
31
31
  "examples/relaunch_deployment.rb",
32
32
  "examples/right_scale_ec2_instances_api_test.rb",
33
33
  "lib/rest_connection.rb",
34
+ "lib/rest_connection/rightscale/alert_spec.rb",
34
35
  "lib/rest_connection/rightscale/audit_entry.rb",
35
36
  "lib/rest_connection/rightscale/deployment.rb",
36
37
  "lib/rest_connection/rightscale/ec2_ebs_snapshot.rb",
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rest_connection
3
3
  version: !ruby/object:Gem::Version
4
- hash: 13
4
+ hash: 11
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
8
  - 0
9
- - 9
10
- version: 0.0.9
9
+ - 10
10
+ version: 0.0.10
11
11
  platform: ruby
12
12
  authors:
13
13
  - Jeremy Deininger
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2010-06-23 00:00:00 -07:00
18
+ date: 2010-09-02 00:00:00 -07:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
@@ -67,10 +67,10 @@ executables: []
67
67
  extensions: []
68
68
 
69
69
  extra_rdoc_files:
70
- - README
70
+ - README.rdoc
71
71
  files:
72
72
  - .gitignore
73
- - README
73
+ - README.rdoc
74
74
  - Rakefile
75
75
  - VERSION
76
76
  - config/rest_api_config.yaml.sample
@@ -84,6 +84,7 @@ files:
84
84
  - examples/relaunch_deployment.rb
85
85
  - examples/right_scale_ec2_instances_api_test.rb
86
86
  - lib/rest_connection.rb
87
+ - lib/rest_connection/rightscale/alert_spec.rb
87
88
  - lib/rest_connection/rightscale/audit_entry.rb
88
89
  - lib/rest_connection/rightscale/deployment.rb
89
90
  - lib/rest_connection/rightscale/ec2_ebs_snapshot.rb
data/README DELETED
@@ -1,7 +0,0 @@
1
- RestConnection is a library designed to facilitate Restful connections to APIs using Basic auth and more. However! If you've done any API work you know that every API is different. The goal of RestConnection is to be as lean as possible and a EXAMPLE of how to use Net::HTTP in a restful way. Right now RestConnection uses JSON and Basic Auth, this is easy to change or expand on and it's written to give more control to the user of the library (You).
2
-
3
- My hope is to include 'helper resources' for common API endpoints while maintaining a somewhat universal 'Connection' class that can be easily understood and modified to suit any Restful API needs. These resources will have a similar usage to ActiveResource.
4
-
5
- The first API we will be supporting is the RightScale API.
6
-
7
- I welcome any contributions or suggestions. Thanks!