restfully-addons 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE ADDED
@@ -0,0 +1 @@
1
+ TODO
data/README.md ADDED
@@ -0,0 +1,24 @@
1
+ # restfully-addons
2
+
3
+ Some additional helpers for RESTful APIs, to deal with SSH connections or
4
+ other protocols.
5
+
6
+ Long-term goal is to add support for these protocols into Restfully.
7
+
8
+ ## Installation
9
+
10
+ $ gem install restfully-addons
11
+
12
+ ## Usage
13
+
14
+ Just require the library you need in your scripts. For instance, requiring
15
+ addons for the BonFIRE API would be done as follows:
16
+
17
+ require 'restfully'
18
+ require 'restfully/addons/bonfire'
19
+
20
+ # your code
21
+
22
+ ## Authors
23
+
24
+ * Cyril Rohr <cyril.rohr@inria.fr>
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ # TODO: test
@@ -0,0 +1,62 @@
1
+ require 'net/ssh/gateway'
2
+ require 'net/scp'
3
+ require 'net/sftp'
4
+
5
+ module Restfully
6
+ class Resource
7
+ def ssh(user = nil, opts = {}, &block)
8
+ raise NotImplementedError unless uri.to_s =~ /\/computes\/\w+$/
9
+ @ssh ||= SSH.new(session, self)
10
+ @ssh.run(@ssh.ip, user, opts, &block) if block
11
+ @ssh
12
+ end
13
+ end
14
+
15
+ class SSH
16
+ attr_reader :session, :resource
17
+
18
+ def initialize(session, resource)
19
+ @session = session
20
+ @resource = resource
21
+ end
22
+
23
+ def run(fqdn, user, options = {}, &block)
24
+ user ||= 'root'
25
+ session.logger.info "Trying to SSH into #{user}@#{fqdn}..."
26
+ options[:keys] ||= session.config[:keys]
27
+ gateway = session.config[:gateway]
28
+ if gateway
29
+ gateway_handler = Net::SSH::Gateway.new(gateway, session.config[:username], options)
30
+ gateway_handler.ssh(fqdn, user, options, &block)
31
+ gateway_handler.shutdown!
32
+ else
33
+ Net::SSH.start(fqdn, user, options, &block)
34
+ end
35
+ end
36
+
37
+ def ip
38
+ @ip ||= accessible?
39
+ end
40
+
41
+ def accessible?
42
+ return false if resource['nic'].empty?
43
+ accessible_nic = resource['nic'].find{|nic|
44
+ ip = nic['ip']
45
+ if ip.nil? || ip =~ /^192.168/
46
+ true
47
+ else
48
+ begin
49
+ Timeout.timeout(10) do
50
+ run(ip, 'root') {|s| s.exec!("hostname") }
51
+ end
52
+ true
53
+ rescue Exception => e
54
+ session.logger.info "Can't SSH yet to #{ip}. Reason: #{e.class.name}, #{e.message}."
55
+ false
56
+ end
57
+ end
58
+ }
59
+ accessible_nic && accessible_nic['ip']
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,130 @@
1
+ require 'json'
2
+
3
+ class Array
4
+ def sum
5
+ inject(:+)
6
+ end
7
+
8
+ def avg
9
+ sum.to_f / size
10
+ end
11
+
12
+ def median
13
+ sorted = sort
14
+ (sorted[size/2] + sorted[(size+1)/2]) / 2
15
+ end
16
+ end
17
+
18
+ module Restfully
19
+ class Resource
20
+ def zabbix
21
+ raise NotImplementedError unless uri.to_s =~ /\/experiments\/[0-9]+$/
22
+ @zabbix ||= Zabbix.new(session, self)
23
+ end
24
+ end
25
+
26
+ class Zabbix
27
+ attr_reader :session, :experiment
28
+ def initialize(session, experiment, opts = {})
29
+ @session = session
30
+ @username = opts[:username] || "Admin"
31
+ @password = opts[:password] || "zabbix"
32
+ @experiment = experiment
33
+ @token, @request_id = nil, 0
34
+ @uri = @experiment.uri.to_s+"/zabbix"
35
+ @max_attempts = 5
36
+ end
37
+
38
+ def request(method, params = {})
39
+ begin
40
+ authenticate if @token.nil? && method != "user.authenticate"
41
+ @request_id += 1
42
+ q = { "jsonrpc" => "2.0", "auth" => @token, "id" => @request_id,
43
+ "method" => method, "params" => params }
44
+ resource = @session.post(@uri,
45
+ JSON.dump(q),
46
+ :head => {
47
+ 'Content-Type' => 'application/json',
48
+ 'Accept' => 'application/json'
49
+ }
50
+ )
51
+
52
+ # That fucking zabbix API returns "text/plain" as content-type...
53
+ h = JSON.parse(resource.response.body)
54
+
55
+ if h['error']
56
+ if h['error']['data'] == "Not authorized"
57
+ @token = nil
58
+ request(method, params)
59
+ else
60
+ raise StandardError, "Received error: #{h.inspect}" if h['error']
61
+ end
62
+ else
63
+ h['result']
64
+ end
65
+ rescue Restfully::HTTP::Error => e
66
+ # retry ad vitam eternam
67
+ sleep 5
68
+ retry
69
+ end
70
+ end
71
+
72
+ def authenticate
73
+ @token = request("user.authenticate", {"user" => @username, "password" => @password})
74
+ end
75
+
76
+ def metric(name, options = {})
77
+ hosts = [options.delete(:hosts) || []].flatten.map{|h|
78
+ [h['name'], h['id']].join("-")
79
+ }
80
+ items = request("item.get", {
81
+ :filter => {
82
+ "host" => hosts[0],
83
+ "key_" => name.to_s
84
+ },
85
+ "output" => "extend"
86
+ }).map{|i| i['itemid']}
87
+
88
+ history = case options[:type]
89
+ when :numeric
90
+ 0
91
+ else
92
+ 1 # STRING
93
+ end
94
+
95
+ # Most recent last
96
+ now = Time.now.to_i
97
+ results = request("history.get", {
98
+ "itemids" => items[0..1],
99
+ # FIX once we can correctly specify metric type
100
+ "history" => history,
101
+ "output" => "extend",
102
+ "time_from" => now-3600,
103
+ "time_till" => now
104
+ })
105
+
106
+ Metric.new(name, results, options)
107
+ end
108
+
109
+ class Metric
110
+ def initialize(name, results, opts = {})
111
+ @name = name
112
+ @results = results
113
+ @opts = opts
114
+ end
115
+
116
+ def values
117
+ @results.map{|r|
118
+ case @opts[:type]
119
+ when :numeric
120
+ r['value'].to_f
121
+ else
122
+ r['value']
123
+ end
124
+ }.reverse
125
+ end
126
+ end
127
+
128
+ end
129
+
130
+ end
@@ -0,0 +1,3 @@
1
+ require 'restfully'
2
+ require 'restfully/addons/bonfire/ssh'
3
+ require 'restfully/addons/bonfire/zabbix'
@@ -0,0 +1,5 @@
1
+ module Restfully
2
+ module Addons
3
+ VERSION = "1.0.0"
4
+ end
5
+ end
@@ -0,0 +1 @@
1
+ require 'restfully/addons/bonfire'
metadata ADDED
@@ -0,0 +1,135 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: restfully-addons
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Cyril Rohr
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2011-07-29 00:00:00.000000000 +02:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: restfully
17
+ requirement: &2156314120 !ruby/object:Gem::Requirement
18
+ none: false
19
+ requirements:
20
+ - - ! '>='
21
+ - !ruby/object:Gem::Version
22
+ version: '0'
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: *2156314120
26
+ - !ruby/object:Gem::Dependency
27
+ name: net-ssh-gateway
28
+ requirement: &2156313660 !ruby/object:Gem::Requirement
29
+ none: false
30
+ requirements:
31
+ - - ! '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: *2156313660
37
+ - !ruby/object:Gem::Dependency
38
+ name: net-scp
39
+ requirement: &2156313240 !ruby/object:Gem::Requirement
40
+ none: false
41
+ requirements:
42
+ - - ! '>='
43
+ - !ruby/object:Gem::Version
44
+ version: '0'
45
+ type: :runtime
46
+ prerelease: false
47
+ version_requirements: *2156313240
48
+ - !ruby/object:Gem::Dependency
49
+ name: net-sftp
50
+ requirement: &2156312820 !ruby/object:Gem::Requirement
51
+ none: false
52
+ requirements:
53
+ - - ! '>='
54
+ - !ruby/object:Gem::Version
55
+ version: '0'
56
+ type: :runtime
57
+ prerelease: false
58
+ version_requirements: *2156312820
59
+ - !ruby/object:Gem::Dependency
60
+ name: net-ssh-multi
61
+ requirement: &2156312400 !ruby/object:Gem::Requirement
62
+ none: false
63
+ requirements:
64
+ - - ! '>='
65
+ - !ruby/object:Gem::Version
66
+ version: '0'
67
+ type: :runtime
68
+ prerelease: false
69
+ version_requirements: *2156312400
70
+ - !ruby/object:Gem::Dependency
71
+ name: libxml-ruby
72
+ requirement: &2156311980 !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ type: :runtime
79
+ prerelease: false
80
+ version_requirements: *2156311980
81
+ - !ruby/object:Gem::Dependency
82
+ name: rake
83
+ requirement: &2156563360 !ruby/object:Gem::Requirement
84
+ none: false
85
+ requirements:
86
+ - - ~>
87
+ - !ruby/object:Gem::Version
88
+ version: '0.8'
89
+ type: :development
90
+ prerelease: false
91
+ version_requirements: *2156563360
92
+ description: Addons for Restfully
93
+ email:
94
+ - cyril.rohr@inria.fr
95
+ executables: []
96
+ extensions: []
97
+ extra_rdoc_files:
98
+ - LICENSE
99
+ - README.md
100
+ files:
101
+ - lib/restfully/addons/bonfire/ssh.rb
102
+ - lib/restfully/addons/bonfire/zabbix.rb
103
+ - lib/restfully/addons/bonfire.rb
104
+ - lib/restfully/addons/version.rb
105
+ - lib/restfully/addons.rb
106
+ - Rakefile
107
+ - LICENSE
108
+ - README.md
109
+ has_rdoc: true
110
+ homepage: http://github.com/crohr/restfully-addons
111
+ licenses: []
112
+ post_install_message:
113
+ rdoc_options:
114
+ - --charset=UTF-8
115
+ require_paths:
116
+ - lib
117
+ required_ruby_version: !ruby/object:Gem::Requirement
118
+ none: false
119
+ requirements:
120
+ - - ! '>='
121
+ - !ruby/object:Gem::Version
122
+ version: '1.8'
123
+ required_rubygems_version: !ruby/object:Gem::Requirement
124
+ none: false
125
+ requirements:
126
+ - - ! '>='
127
+ - !ruby/object:Gem::Version
128
+ version: '1.3'
129
+ requirements: []
130
+ rubyforge_project:
131
+ rubygems_version: 1.6.2
132
+ signing_key:
133
+ specification_version: 3
134
+ summary: Addons for Restfully
135
+ test_files: []