ilorb 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 4dda8bc7feb3994e4cfbd360716f380af125b2e0
4
+ data.tar.gz: 9c2b8b3d6f61d440df5039feaf2f94769b9c2ec9
5
+ SHA512:
6
+ metadata.gz: 423966543881ffd1e3720fdc0d44bd2858dd4f4cbd2681c72d2ed7d7b9b64b92b4b796d733df0e0d2120c4f8adf1e2e698350e1a24e0377e6a6c3c90e81a76f2
7
+ data.tar.gz: d43910027cb1dc97efe24c9f81c743d49fc56731d744a73f7f508b9b3755998949b64a2ae9361599b61af2cbf4348e636d83e61f632a3305e7623b08e78b3a57
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- ilorb (0.0.1)
4
+ ilorb (0.0.2)
5
5
  nokogiri
6
6
  nori
7
7
 
@@ -14,10 +14,10 @@ GEM
14
14
  safe_yaml (~> 0.9.0)
15
15
  diff-lcs (1.2.4)
16
16
  method_source (0.8.1)
17
- mini_portile (0.5.0)
18
- nokogiri (1.6.0)
17
+ mini_portile (0.5.3)
18
+ nokogiri (1.6.1)
19
19
  mini_portile (~> 0.5.0)
20
- nori (2.2.0)
20
+ nori (2.4.0)
21
21
  pry (0.9.12.2)
22
22
  coderay (~> 1.0.5)
23
23
  method_source (~> 0.8)
data/README.md CHANGED
@@ -16,11 +16,13 @@ HP, Integrated Lights Out and iLO are trademarks of HP, with whom the author of
16
16
 
17
17
  ## Examples
18
18
 
19
+ WARNING: as of 0.0.2, `ILORb::ILO` content has been moved to `ILORb`. Just use `ILORb#new`
20
+
19
21
  ```ruby
20
22
  require 'json'
21
23
  require 'ilorb'
22
24
 
23
- ilo = ILORb::ILO.new(
25
+ ilo = ILORb.new(
24
26
  :hostname => "10.200.0.1",
25
27
  :login => "Admin",
26
28
  :password => "SECRET",
@@ -91,7 +93,7 @@ Dependencies:
91
93
  Install:
92
94
  * git clone https://github.com/josqu4red/ilorb
93
95
  OR
94
- * gem install ilorb (soon)
96
+ * gem install ilorb
95
97
 
96
98
  ## Credits
97
99
 
data/lib/ilorb/ribcl.rb CHANGED
@@ -1,4 +1,4 @@
1
- module ILORb
1
+ class ILORb
2
2
  class RIBCL < Hash
3
3
  def initialize
4
4
  super
data/lib/ilorb/version.rb CHANGED
@@ -1,3 +1,3 @@
1
- module ILORb
2
- VERSION = "0.0.1"
1
+ class ILORb
2
+ VERSION = "0.0.2"
3
3
  end
data/lib/ilorb.rb CHANGED
@@ -1,5 +1,206 @@
1
+ require 'logger'
2
+ require 'socket'
3
+ require 'openssl'
4
+ require 'net/https'
5
+ require 'nokogiri'
6
+ require 'nori'
1
7
  require 'ilorb/ribcl'
2
- require 'ilorb/ilo'
3
8
 
4
- module ILORb
9
+ class ILORb
10
+
11
+ class NotImplemented < StandardError; end
12
+
13
+ def initialize(config = {})
14
+ @hostname = config[:hostname]
15
+ @login = config[:login] || "Administrator"
16
+ @password = config[:password]
17
+ @port = config[:port] || 443
18
+ @protocol = config[:protocol] || :http
19
+ @verify_ssl = config[:verify_ssl] || false
20
+ @ribcl_path = "/ribcl"
21
+
22
+ @log = Logger.new(STDOUT)
23
+ @log.level = config[:debug] ? Logger::DEBUG : Logger::WARN
24
+
25
+ @nori = Nori.new(:convert_tags_to => lambda{|tag| tag.downcase.to_sym})
26
+
27
+ setup_commands
28
+ end
29
+
30
+ # args should be empty or contain a hash anytime
31
+ def method_missing(name, *args, &block)
32
+ if @ribcl.has_command?(name)
33
+ command = @ribcl.command(name)
34
+
35
+ raise NotImplemented, "#{name} is not supported" unless command.supported?
36
+
37
+ params = args.first || {}
38
+ attributes = {}
39
+ element_map = nil
40
+
41
+ #TODO check for text
42
+
43
+ command.get_attributes.each do |attr|
44
+ # Attributes are mandatory
45
+ error("Attribute #{attr} missing in #{name} call") unless params.has_key?(attr)
46
+ attributes.store(attr, @ribcl.encode(params.delete(attr)))
47
+ end
48
+
49
+ element_map = command.map_elements
50
+
51
+ elements_array = []
52
+
53
+ [ params ].flatten.each do |params_hash|
54
+ elements = {}
55
+ params_hash.each do |key, value|
56
+ # Elements are not mandatory for now
57
+ elements.store(key, @ribcl.encode(params_hash.delete(key))) if element_map.has_key?(key)
58
+ end
59
+ elements_array << elements
60
+ end
61
+
62
+ #TODO check for CDATA
63
+
64
+ @log.info("Calling method #{name}")
65
+ request = ribcl_request(command, attributes) do |xml|
66
+ elements_array.each do |elements_hash|
67
+ elements_hash.each do |key, value|
68
+ elt = command.get_elements[element_map[key].first]
69
+ if elt.is_a?(Array)
70
+ attrs = Hash[elt.map{|x| [x, elements_hash.delete(element_map.invert[[element_map[key].first, x]])]}]
71
+ else
72
+ attrs = {element_map[key].last => value}
73
+ end
74
+ xml.send(element_map[key].first, attrs)
75
+ end
76
+ end
77
+ end
78
+
79
+ response = send_request(request)
80
+ parse_response(response, name)
81
+ else
82
+ super
83
+ end
84
+ end
85
+
86
+ def respond_to(name)
87
+ @ribcl.has_command?(name) ? true : super
88
+ end
89
+
90
+ def supported_commands
91
+ @ribcl.select{|name, command| command.supported?}.keys
92
+ end
93
+
94
+ private
95
+
96
+ def send_request(xml)
97
+ case @protocol
98
+ when :http
99
+ send_http_request(xml)
100
+ when :raw
101
+ send_raw_request(xml)
102
+ end
103
+ end
104
+
105
+ # ILO >= 3 speak HTTP
106
+ # Send XML request with HTTP POST and get back XML messages
107
+ def send_http_request(xml)
108
+ http = Net::HTTP.new(@hostname, @port)
109
+ http.use_ssl = true
110
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE unless @verify_ssl
111
+
112
+ @log.info("Sending POST request to #{@hostname}:#{@port}#{@ribcl_path}")
113
+ @log.debug("Request:\n#{xml}")
114
+ response = http.post(@ribcl_path, xml)
115
+ if response.is_a?(Net::HTTPNotFound)
116
+ @protocol = :raw
117
+ @log.info("Got 404, switching to RAW protocol")
118
+ send_raw_request(xml)
119
+ else
120
+ response.body
121
+ end
122
+ end
123
+
124
+ # Older ILO just eat raw XML
125
+ # Send XML over raw SSL-wrapped TCP socket and read XML stream
126
+ def send_raw_request(xml)
127
+ sock = TCPSocket.new(@hostname, @port)
128
+
129
+ ctx = OpenSSL::SSL::SSLContext.new(:TLSv1)
130
+ ctx.verify_mode = OpenSSL::SSL::VERIFY_NONE
131
+ ssl_sock = OpenSSL::SSL::SSLSocket.new(sock, ctx)
132
+ ssl_sock.sync_close = true
133
+
134
+ @log.info("Connecting to #{@hostname}:#{@port}")
135
+ ssl_sock.connect
136
+ @log.debug("Request:\n#{xml}")
137
+ ssl_sock.puts("#{xml}\r\n")
138
+ response = ""
139
+ while line = ssl_sock.gets
140
+ response += line
141
+ end
142
+ ssl_sock.close
143
+
144
+ response
145
+ end
146
+
147
+ def parse_response(xml, command)
148
+ @log.debug("Response:\n#{xml}")
149
+
150
+ # ILO sends back multiple XML documents, split by XML header and remove first (empty)
151
+ messages = xml.split(/<\?xml.*?\?>\r?\n/).drop(1)
152
+
153
+ output = {}
154
+
155
+ messages.each do |doc|
156
+ xml_doc = Nokogiri::XML(doc){|cfg| cfg.nonet.noblanks}
157
+
158
+ xml_doc.root.children.each do |node|
159
+ case node.name
160
+ when "RESPONSE"
161
+ code = node.attr("STATUS").to_i(16)
162
+ message = node.attr("MESSAGE")
163
+ if code == 0
164
+ output[:status] = { :code => code, :message => message }
165
+ else
166
+ output[:status] = { :code => code, :message => message }
167
+ @log.error("#{message} (#{code})")
168
+ break
169
+ end
170
+ when "INFORM"
171
+ # OSEF
172
+ else # actual result
173
+ output.merge!(@nori.parse(node.to_s))
174
+ end
175
+ end
176
+ end
177
+
178
+ output
179
+ end
180
+
181
+ def ribcl_request(command, args = {}, &block)
182
+ builder = Nokogiri::XML::Builder.new do |xml|
183
+ xml.ribcl(:version => "2.0") {
184
+ xml.login(:password => @password, :user_login => @login) {
185
+ xml.send(command.context, :mode => command.mode) {
186
+ xml.send(command.name, args) {
187
+ yield xml if block_given?
188
+ }
189
+ }
190
+ }
191
+ }
192
+ end
193
+
194
+ builder.to_xml
195
+ end
196
+
197
+ def setup_commands
198
+ @ribcl = ILORb::RIBCL.load(File.join(File.dirname(__FILE__), "ilorb/definitions", "*.rb"))
199
+ nil
200
+ end
201
+
202
+ def error(message)
203
+ @log.error(message)
204
+ raise message
205
+ end
5
206
  end
data/spec/ilo_spec.rb CHANGED
@@ -1,10 +1,10 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe ILORb::ILO do
3
+ describe ILORb do
4
4
  let(:hostname) { "10.200.0.1" }
5
5
  let(:login) { "Admin" }
6
6
  let(:password) { "SECRET" }
7
- let(:ilo) { ILORb::ILO.new(hostname: hostname, login: login, password: password) }
7
+ let(:ilo) { ILORb.new(hostname: hostname, login: login, password: password) }
8
8
 
9
9
  describe "#get_network_settings" do
10
10
  before do
metadata CHANGED
@@ -1,110 +1,97 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ilorb
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
5
- prerelease:
4
+ version: 0.0.2
6
5
  platform: ruby
7
6
  authors:
8
7
  - Jonathan Amiez
9
8
  autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2013-07-25 00:00:00.000000000 Z
11
+ date: 2014-05-02 00:00:00.000000000 Z
13
12
  dependencies:
14
13
  - !ruby/object:Gem::Dependency
15
14
  name: bundler
16
15
  requirement: !ruby/object:Gem::Requirement
17
- none: false
18
16
  requirements:
19
- - - ~>
17
+ - - "~>"
20
18
  - !ruby/object:Gem::Version
21
19
  version: '1.2'
22
20
  type: :development
23
21
  prerelease: false
24
22
  version_requirements: !ruby/object:Gem::Requirement
25
- none: false
26
23
  requirements:
27
- - - ~>
24
+ - - "~>"
28
25
  - !ruby/object:Gem::Version
29
26
  version: '1.2'
30
27
  - !ruby/object:Gem::Dependency
31
28
  name: rspec
32
29
  requirement: !ruby/object:Gem::Requirement
33
- none: false
34
30
  requirements:
35
- - - ~>
31
+ - - "~>"
36
32
  - !ruby/object:Gem::Version
37
33
  version: '2.14'
38
34
  type: :development
39
35
  prerelease: false
40
36
  version_requirements: !ruby/object:Gem::Requirement
41
- none: false
42
37
  requirements:
43
- - - ~>
38
+ - - "~>"
44
39
  - !ruby/object:Gem::Version
45
40
  version: '2.14'
46
41
  - !ruby/object:Gem::Dependency
47
42
  name: webmock
48
43
  requirement: !ruby/object:Gem::Requirement
49
- none: false
50
44
  requirements:
51
- - - ~>
45
+ - - "~>"
52
46
  - !ruby/object:Gem::Version
53
47
  version: '1.13'
54
48
  type: :development
55
49
  prerelease: false
56
50
  version_requirements: !ruby/object:Gem::Requirement
57
- none: false
58
51
  requirements:
59
- - - ~>
52
+ - - "~>"
60
53
  - !ruby/object:Gem::Version
61
54
  version: '1.13'
62
55
  - !ruby/object:Gem::Dependency
63
56
  name: pry
64
57
  requirement: !ruby/object:Gem::Requirement
65
- none: false
66
58
  requirements:
67
- - - ! '>='
59
+ - - ">="
68
60
  - !ruby/object:Gem::Version
69
61
  version: '0'
70
62
  type: :development
71
63
  prerelease: false
72
64
  version_requirements: !ruby/object:Gem::Requirement
73
- none: false
74
65
  requirements:
75
- - - ! '>='
66
+ - - ">="
76
67
  - !ruby/object:Gem::Version
77
68
  version: '0'
78
69
  - !ruby/object:Gem::Dependency
79
70
  name: nokogiri
80
71
  requirement: !ruby/object:Gem::Requirement
81
- none: false
82
72
  requirements:
83
- - - ! '>='
73
+ - - ">="
84
74
  - !ruby/object:Gem::Version
85
75
  version: '0'
86
76
  type: :runtime
87
77
  prerelease: false
88
78
  version_requirements: !ruby/object:Gem::Requirement
89
- none: false
90
79
  requirements:
91
- - - ! '>='
80
+ - - ">="
92
81
  - !ruby/object:Gem::Version
93
82
  version: '0'
94
83
  - !ruby/object:Gem::Dependency
95
84
  name: nori
96
85
  requirement: !ruby/object:Gem::Requirement
97
- none: false
98
86
  requirements:
99
- - - ! '>='
87
+ - - ">="
100
88
  - !ruby/object:Gem::Version
101
89
  version: '0'
102
90
  type: :runtime
103
91
  prerelease: false
104
92
  version_requirements: !ruby/object:Gem::Requirement
105
- none: false
106
93
  requirements:
107
- - - ! '>='
94
+ - - ">="
108
95
  - !ruby/object:Gem::Version
109
96
  version: '0'
110
97
  description: HP ILO Ruby interface
@@ -122,7 +109,6 @@ files:
122
109
  - lib/ilorb/definitions/rib.rb
123
110
  - lib/ilorb/definitions/server.rb
124
111
  - lib/ilorb/definitions/user.rb
125
- - lib/ilorb/ilo.rb
126
112
  - lib/ilorb/ribcl.rb
127
113
  - lib/ilorb/version.rb
128
114
  - spec/assets/basic_response.xml
@@ -132,27 +118,26 @@ files:
132
118
  homepage: https://github.com/josqu4red/ilorb
133
119
  licenses:
134
120
  - MIT
121
+ metadata: {}
135
122
  post_install_message:
136
123
  rdoc_options: []
137
124
  require_paths:
138
125
  - lib
139
126
  required_ruby_version: !ruby/object:Gem::Requirement
140
- none: false
141
127
  requirements:
142
- - - ! '>='
128
+ - - ">="
143
129
  - !ruby/object:Gem::Version
144
130
  version: '0'
145
131
  required_rubygems_version: !ruby/object:Gem::Requirement
146
- none: false
147
132
  requirements:
148
- - - ! '>='
133
+ - - ">="
149
134
  - !ruby/object:Gem::Version
150
135
  version: '0'
151
136
  requirements: []
152
137
  rubyforge_project:
153
- rubygems_version: 1.8.25
138
+ rubygems_version: 2.2.0
154
139
  signing_key:
155
- specification_version: 3
140
+ specification_version: 4
156
141
  summary: Configure and retrieve data from server's ILO management card
157
142
  test_files:
158
143
  - spec/assets/basic_response.xml
data/lib/ilorb/ilo.rb DELETED
@@ -1,207 +0,0 @@
1
- require 'logger'
2
- require 'socket'
3
- require 'openssl'
4
- require 'net/https'
5
- require 'nokogiri'
6
- require 'nori'
7
-
8
- module ILORb
9
-
10
- class NotImplemented < StandardError; end
11
-
12
- class ILO
13
- def initialize(config = {})
14
- @hostname = config[:hostname]
15
- @login = config[:login] || "Administrator"
16
- @password = config[:password]
17
- @port = config[:port] || 443
18
- @protocol = config[:protocol] || :http
19
- @verify_ssl = config[:verify_ssl] || false
20
- @ribcl_path = "/ribcl"
21
-
22
- @log = Logger.new(STDOUT)
23
- @log.level = config[:debug] ? Logger::DEBUG : Logger::WARN
24
-
25
- @nori = Nori.new(:convert_tags_to => lambda{|tag| tag.downcase.to_sym})
26
-
27
- setup_commands
28
- end
29
-
30
- # args should be empty or contain a hash anytime
31
- def method_missing(name, *args, &block)
32
- if @ribcl.has_command?(name)
33
- command = @ribcl.command(name)
34
-
35
- raise NotImplemented, "#{name} is not supported" unless command.supported?
36
-
37
- params = args.first || {}
38
- attributes = {}
39
- element_map = nil
40
-
41
- #TODO check for text
42
-
43
- command.get_attributes.each do |attr|
44
- # Attributes are mandatory
45
- error("Attribute #{attr} missing in #{name} call") unless params.has_key?(attr)
46
- attributes.store(attr, @ribcl.encode(params.delete(attr)))
47
- end
48
-
49
- element_map = command.map_elements
50
-
51
- elements_array = []
52
-
53
- [ params ].flatten.each do |params_hash|
54
- elements = {}
55
- params_hash.each do |key, value|
56
- # Elements are not mandatory for now
57
- elements.store(key, @ribcl.encode(params_hash.delete(key))) if element_map.has_key?(key)
58
- end
59
- elements_array << elements
60
- end
61
-
62
- #TODO check for CDATA
63
-
64
- @log.info("Calling method #{name}")
65
- request = ribcl_request(command, attributes) do |xml|
66
- elements_array.each do |elements_hash|
67
- elements_hash.each do |key, value|
68
- elt = command.get_elements[element_map[key].first]
69
- if elt.is_a?(Array)
70
- attrs = Hash[elt.map{|x| [x, elements_hash.delete(element_map.invert[[element_map[key].first, x]])]}]
71
- else
72
- attrs = {element_map[key].last => value}
73
- end
74
- xml.send(element_map[key].first, attrs)
75
- end
76
- end
77
- end
78
-
79
- response = send_request(request)
80
- parse_response(response, name)
81
- else
82
- super
83
- end
84
- end
85
-
86
- def respond_to(name)
87
- @ribcl.has_command?(name) ? true : super
88
- end
89
-
90
- def supported_commands
91
- @ribcl.select{|name, command| command.supported?}.keys
92
- end
93
-
94
- private
95
-
96
- def send_request(xml)
97
- case @protocol
98
- when :http
99
- send_http_request(xml)
100
- when :raw
101
- send_raw_request(xml)
102
- end
103
- end
104
-
105
- # ILO >= 3 speak HTTP
106
- # Send XML request with HTTP POST and get back XML messages
107
- def send_http_request(xml)
108
- http = Net::HTTP.new(@hostname, @port)
109
- http.use_ssl = true
110
- http.verify_mode = OpenSSL::SSL::VERIFY_NONE unless @verify_ssl
111
-
112
- @log.info("Sending POST request to #{@hostname}:#{@port}#{@ribcl_path}")
113
- @log.debug("Request:\n#{xml}")
114
- response = http.post(@ribcl_path, xml)
115
- if response.is_a?(Net::HTTPNotFound)
116
- @protocol = :raw
117
- @log.info("Got 404, switching to RAW protocol")
118
- send_raw_request(xml)
119
- else
120
- response.body
121
- end
122
- end
123
-
124
- # Older ILO just eat raw XML
125
- # Send XML over raw SSL-wrapped TCP socket and read XML stream
126
- def send_raw_request(xml)
127
- sock = TCPSocket.new(@hostname, @port)
128
-
129
- ctx = OpenSSL::SSL::SSLContext.new(:TLSv1)
130
- ctx.verify_mode = OpenSSL::SSL::VERIFY_NONE
131
- ssl_sock = OpenSSL::SSL::SSLSocket.new(sock, ctx)
132
- ssl_sock.sync_close = true
133
-
134
- @log.info("Connecting to #{@hostname}:#{@port}")
135
- ssl_sock.connect
136
- @log.debug("Request:\n#{xml}")
137
- ssl_sock.puts("#{xml}\r\n")
138
- response = ""
139
- while line = ssl_sock.gets
140
- response += line
141
- end
142
- ssl_sock.close
143
-
144
- response
145
- end
146
-
147
- def parse_response(xml, command)
148
- @log.debug("Response:\n#{xml}")
149
-
150
- # ILO sends back multiple XML documents, split by XML header and remove first (empty)
151
- messages = xml.split(/<\?xml.*?\?>\r?\n/).drop(1)
152
-
153
- output = {}
154
-
155
- messages.each do |doc|
156
- xml_doc = Nokogiri::XML(doc){|cfg| cfg.nonet.noblanks}
157
-
158
- xml_doc.root.children.each do |node|
159
- case node.name
160
- when "RESPONSE"
161
- code = node.attr("STATUS").to_i(16)
162
- message = node.attr("MESSAGE")
163
- if code == 0
164
- output[:status] = { :code => code, :message => message }
165
- else
166
- output[:status] = { :code => code, :message => message }
167
- @log.error("#{message} (#{code})")
168
- break
169
- end
170
- when "INFORM"
171
- # OSEF
172
- else # actual result
173
- output.merge!(@nori.parse(node.to_s))
174
- end
175
- end
176
- end
177
-
178
- output
179
- end
180
-
181
- def ribcl_request(command, args = {}, &block)
182
- builder = Nokogiri::XML::Builder.new do |xml|
183
- xml.ribcl(:version => "2.0") {
184
- xml.login(:password => @password, :user_login => @login) {
185
- xml.send(command.context, :mode => command.mode) {
186
- xml.send(command.name, args) {
187
- yield xml if block_given?
188
- }
189
- }
190
- }
191
- }
192
- end
193
-
194
- builder.to_xml
195
- end
196
-
197
- def setup_commands
198
- @ribcl = ILORb::RIBCL.load(File.join(File.dirname(__FILE__), "definitions", "*.rb"))
199
- nil
200
- end
201
-
202
- def error(message)
203
- @log.error(message)
204
- raise message
205
- end
206
- end
207
- end