ilorb 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +2 -0
- data/Gemfile.lock +47 -0
- data/README.md +98 -0
- data/ilorb.gemspec +28 -0
- data/lib/ilorb/definitions/rib.rb +102 -0
- data/lib/ilorb/definitions/server.rb +51 -0
- data/lib/ilorb/definitions/user.rb +19 -0
- data/lib/ilorb/ilo.rb +207 -0
- data/lib/ilorb/ribcl.rb +135 -0
- data/lib/ilorb/version.rb +3 -0
- data/lib/ilorb.rb +5 -0
- data/spec/assets/basic_response.xml +7 -0
- data/spec/assets/get_network_settings_response.xml +87 -0
- data/spec/ilo_spec.rb +79 -0
- data/spec/spec_helper.rb +9 -0
- metadata +161 -0
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
ilorb (0.0.1)
|
5
|
+
nokogiri
|
6
|
+
nori
|
7
|
+
|
8
|
+
GEM
|
9
|
+
remote: https://rubygems.org/
|
10
|
+
specs:
|
11
|
+
addressable (2.3.5)
|
12
|
+
coderay (1.0.9)
|
13
|
+
crack (0.4.1)
|
14
|
+
safe_yaml (~> 0.9.0)
|
15
|
+
diff-lcs (1.2.4)
|
16
|
+
method_source (0.8.1)
|
17
|
+
mini_portile (0.5.0)
|
18
|
+
nokogiri (1.6.0)
|
19
|
+
mini_portile (~> 0.5.0)
|
20
|
+
nori (2.2.0)
|
21
|
+
pry (0.9.12.2)
|
22
|
+
coderay (~> 1.0.5)
|
23
|
+
method_source (~> 0.8)
|
24
|
+
slop (~> 3.4)
|
25
|
+
rspec (2.14.1)
|
26
|
+
rspec-core (~> 2.14.0)
|
27
|
+
rspec-expectations (~> 2.14.0)
|
28
|
+
rspec-mocks (~> 2.14.0)
|
29
|
+
rspec-core (2.14.3)
|
30
|
+
rspec-expectations (2.14.0)
|
31
|
+
diff-lcs (>= 1.1.3, < 2.0)
|
32
|
+
rspec-mocks (2.14.1)
|
33
|
+
safe_yaml (0.9.4)
|
34
|
+
slop (3.4.5)
|
35
|
+
webmock (1.13.0)
|
36
|
+
addressable (>= 2.2.7)
|
37
|
+
crack (>= 0.3.2)
|
38
|
+
|
39
|
+
PLATFORMS
|
40
|
+
ruby
|
41
|
+
|
42
|
+
DEPENDENCIES
|
43
|
+
bundler (~> 1.2)
|
44
|
+
ilorb!
|
45
|
+
pry
|
46
|
+
rspec (~> 2.14)
|
47
|
+
webmock (~> 1.13)
|
data/README.md
ADDED
@@ -0,0 +1,98 @@
|
|
1
|
+
# ILORb
|
2
|
+
|
3
|
+
ILORb is a library created to ease interaction with HP servers baseboard management cards (ILO), using their XML interface.
|
4
|
+
|
5
|
+
It is primarily meant to integrate with Chef config management system, but it can of course be used standalone.
|
6
|
+
|
7
|
+
It supports RIB, SERVER and USER commands for ILO 2, 3 and 4 (no other hardware to test on).
|
8
|
+
|
9
|
+
* By default, it will try to query the BMC through HTTP POST (available from ILO version 3)
|
10
|
+
* It will fall back to raw XML through TCP socket (SSL-wrapped) for earlier ILO versions
|
11
|
+
|
12
|
+
Supported commands and parameters are defined using a little DSL, under [definitions](lib/ilorb/definitions), sorted by "context".
|
13
|
+
|
14
|
+
|
15
|
+
HP, Integrated Lights Out and iLO are trademarks of HP, with whom the author of this software is not affiliated in any way other than using some of their hardware.
|
16
|
+
|
17
|
+
## Examples
|
18
|
+
|
19
|
+
```ruby
|
20
|
+
require 'json'
|
21
|
+
require 'ilorb'
|
22
|
+
|
23
|
+
ilo = ILORb::ILO.new(
|
24
|
+
:hostname => "10.200.0.1",
|
25
|
+
:login => "Admin",
|
26
|
+
:password => "SECRET",
|
27
|
+
# :protocol => :raw, # for old ILOs, defaults to :http
|
28
|
+
)
|
29
|
+
|
30
|
+
result = ilo.get_network_settings
|
31
|
+
puts JSON.pretty_generate(result)
|
32
|
+
```
|
33
|
+
generates and sends :
|
34
|
+
|
35
|
+
```xml
|
36
|
+
<?xml version="1.0"?>
|
37
|
+
<ribcl version="2.0">
|
38
|
+
<login password="SECRET" user_login="Admin">
|
39
|
+
<rib_info mode="read">
|
40
|
+
<get_network_settings/>
|
41
|
+
</rib_info>
|
42
|
+
</login>
|
43
|
+
</ribcl>
|
44
|
+
```
|
45
|
+
result:
|
46
|
+
```json
|
47
|
+
{
|
48
|
+
"status": {
|
49
|
+
"code": 0,
|
50
|
+
"message": "No error"
|
51
|
+
},
|
52
|
+
"get_network_settings": {
|
53
|
+
"enable_nic": {
|
54
|
+
"@value": "Y"
|
55
|
+
},
|
56
|
+
"shared_network_port": {
|
57
|
+
"@value": "N"
|
58
|
+
},
|
59
|
+
"vlan_enabled": {
|
60
|
+
"@value": "N"
|
61
|
+
},
|
62
|
+
"vlan_id": {
|
63
|
+
"@value": "0"
|
64
|
+
},
|
65
|
+
"speed_autoselect": {
|
66
|
+
"@value": "Y"
|
67
|
+
},
|
68
|
+
"dhcp_enable": {
|
69
|
+
"@value": "N"
|
70
|
+
},
|
71
|
+
{ ... }
|
72
|
+
}
|
73
|
+
}
|
74
|
+
```
|
75
|
+
|
76
|
+
## TODO
|
77
|
+
|
78
|
+
* Tests
|
79
|
+
* Use a custom parser instead of Nori, to avoid one-element-hashes and cast responses to actual objects (e.g Y/N to true/false)
|
80
|
+
* See for mandatory parameters
|
81
|
+
* Add a CLI tool
|
82
|
+
|
83
|
+
## Setup
|
84
|
+
|
85
|
+
Only tested with MRI >= 1.9.3
|
86
|
+
|
87
|
+
Dependencies:
|
88
|
+
* nokogiri
|
89
|
+
* nori
|
90
|
+
|
91
|
+
Install:
|
92
|
+
* git clone https://github.com/josqu4red/ilorb
|
93
|
+
OR
|
94
|
+
* gem install ilorb (soon)
|
95
|
+
|
96
|
+
## Credits
|
97
|
+
|
98
|
+
ilorb is inspired by [python-hpilo](https://github.com/seveas/python-hpilo)
|
data/ilorb.gemspec
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
|
5
|
+
require 'ilorb/version'
|
6
|
+
|
7
|
+
Gem::Specification.new do |spec|
|
8
|
+
spec.name = "ilorb"
|
9
|
+
spec.version = ILORb::VERSION
|
10
|
+
spec.authors = ["Jonathan Amiez"]
|
11
|
+
spec.email = ["jonathan.amiez@gmail.com"]
|
12
|
+
spec.description = "HP ILO Ruby interface"
|
13
|
+
spec.summary = "Configure and retrieve data from server's ILO management card"
|
14
|
+
spec.homepage = "https://github.com/josqu4red/ilorb"
|
15
|
+
spec.license = "MIT"
|
16
|
+
|
17
|
+
spec.files = `git ls-files`.split($/)
|
18
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
19
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
20
|
+
spec.require_paths = ["lib"]
|
21
|
+
|
22
|
+
spec.add_development_dependency "bundler", "~> 1.2"
|
23
|
+
spec.add_development_dependency "rspec", "~> 2.14"
|
24
|
+
spec.add_development_dependency "webmock", "~> 1.13"
|
25
|
+
spec.add_development_dependency "pry"
|
26
|
+
spec.add_dependency "nokogiri"
|
27
|
+
spec.add_dependency "nori"
|
28
|
+
end
|
@@ -0,0 +1,102 @@
|
|
1
|
+
context :rib_info do
|
2
|
+
read_cmd :get_ahs_status
|
3
|
+
read_cmd :get_all_languages
|
4
|
+
read_cmd :get_all_licenses
|
5
|
+
read_cmd :get_asset_tag
|
6
|
+
read_cmd :get_ers_settings
|
7
|
+
read_cmd :get_event_log
|
8
|
+
read_cmd :get_fips_status
|
9
|
+
read_cmd :get_fw_version
|
10
|
+
read_cmd :get_global_settings
|
11
|
+
read_cmd :get_hotkey_config
|
12
|
+
read_cmd :get_language
|
13
|
+
read_cmd :get_all_languages
|
14
|
+
read_cmd :get_network_settings
|
15
|
+
read_cmd :get_security_msg
|
16
|
+
read_cmd :get_snmp_im_settings
|
17
|
+
read_cmd :get_spatial
|
18
|
+
read_cmd :get_vm_status do
|
19
|
+
attributes :device
|
20
|
+
end
|
21
|
+
read_cmd :profile_apply_get_results do
|
22
|
+
not_implemented
|
23
|
+
end
|
24
|
+
read_cmd :profile_list do
|
25
|
+
not_implemented
|
26
|
+
end
|
27
|
+
|
28
|
+
write_cmd :ahs_clear_data
|
29
|
+
write_cmd :brownout_recovery # > mod_global_settings
|
30
|
+
write_cmd :certificate_signing_request
|
31
|
+
write_cmd :clear_eventlog
|
32
|
+
write_cmd :computer_lock do
|
33
|
+
not_implemented
|
34
|
+
end
|
35
|
+
write_cmd :disable_ers
|
36
|
+
write_cmd :eject_virtual_media do
|
37
|
+
attributes :device
|
38
|
+
end
|
39
|
+
write_cmd :factory_defaults
|
40
|
+
write_cmd :fips_enable
|
41
|
+
write_cmd :hotkey_config do
|
42
|
+
not_implemented
|
43
|
+
end
|
44
|
+
write_cmd :import_certificate do #TODO
|
45
|
+
not_implemented
|
46
|
+
text :certificate
|
47
|
+
end
|
48
|
+
write_cmd :insert_virtual_media do
|
49
|
+
attributes :device, :image_url
|
50
|
+
end
|
51
|
+
write_cmd :license do
|
52
|
+
elements :activate => :key
|
53
|
+
end
|
54
|
+
write_cmd :mod_global_settings do #TODO
|
55
|
+
not_implemented
|
56
|
+
end
|
57
|
+
write_cmd :mod_network_settings do #TODO
|
58
|
+
not_implemented
|
59
|
+
end
|
60
|
+
write_cmd :mod_snmp_im_settings do #TODO
|
61
|
+
not_implemented
|
62
|
+
end
|
63
|
+
write_cmd :profile_apply do
|
64
|
+
not_implemented
|
65
|
+
end
|
66
|
+
write_cmd :profile_delete do
|
67
|
+
not_implemented
|
68
|
+
end
|
69
|
+
write_cmd :profile_desc_download do
|
70
|
+
not_implemented
|
71
|
+
end
|
72
|
+
write_cmd :reset_rib
|
73
|
+
write_cmd :set_ahs_status do
|
74
|
+
attributes :value
|
75
|
+
end
|
76
|
+
write_cmd :set_asset_tag do
|
77
|
+
attributes :value
|
78
|
+
end
|
79
|
+
write_cmd :set_ers_irs_connect do
|
80
|
+
elements :ers_destination_url, :ers_destination_port
|
81
|
+
end
|
82
|
+
write_cmd :set_language do
|
83
|
+
attributes :lang_id
|
84
|
+
end
|
85
|
+
write_cmd :set_security_msg do
|
86
|
+
not_implemented
|
87
|
+
elements :security_msg, :security_msg_text => :cdata
|
88
|
+
end
|
89
|
+
write_cmd :set_vm_status do
|
90
|
+
attributes :device
|
91
|
+
elements :vm_boot_option, :vm_write_protect
|
92
|
+
end
|
93
|
+
write_cmd :trigger_l2_collection do
|
94
|
+
not_implemented
|
95
|
+
end
|
96
|
+
write_cmd :trigger_test_event do
|
97
|
+
not_implemented
|
98
|
+
end
|
99
|
+
write_cmd :update_firmware do #TODO
|
100
|
+
not_implemented
|
101
|
+
end
|
102
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
context :server_info do
|
2
|
+
read_cmd :get_embedded_health
|
3
|
+
read_cmd :get_host_power_saver_status
|
4
|
+
read_cmd :get_host_power_status
|
5
|
+
read_cmd :get_host_pwr_micro_ver
|
6
|
+
read_cmd :get_one_time_boot
|
7
|
+
read_cmd :get_persistent_boot
|
8
|
+
read_cmd :get_power_cap
|
9
|
+
read_cmd :get_power_readings
|
10
|
+
read_cmd :get_pwreg
|
11
|
+
read_cmd :get_server_auto_pwr
|
12
|
+
read_cmd :get_server_name
|
13
|
+
read_cmd :get_server_power_on_time
|
14
|
+
read_cmd :get_uid_status
|
15
|
+
|
16
|
+
write_cmd :clear_server_power_on_time
|
17
|
+
write_cmd :cold_boot_server
|
18
|
+
write_cmd :hold_pwr_btn do
|
19
|
+
attributes :toggle
|
20
|
+
end
|
21
|
+
write_cmd :press_power_btn
|
22
|
+
write_cmd :reset_server
|
23
|
+
write_cmd :server_auto_pwr do
|
24
|
+
attributes :value
|
25
|
+
end
|
26
|
+
write_cmd :server_name do
|
27
|
+
attributes :value
|
28
|
+
end
|
29
|
+
write_cmd :set_host_power do
|
30
|
+
attributes :host_power
|
31
|
+
end
|
32
|
+
write_cmd :set_host_power_saver do
|
33
|
+
attributes :host_power_saver
|
34
|
+
end
|
35
|
+
write_cmd :set_one_time_boot do
|
36
|
+
attributes :value
|
37
|
+
end
|
38
|
+
write_cmd :set_persistent_boot do
|
39
|
+
elements :device => [ :value ]
|
40
|
+
end
|
41
|
+
write_cmd :set_power_cap do
|
42
|
+
attributes :power_cap
|
43
|
+
end
|
44
|
+
write_cmd :set_pwreg do
|
45
|
+
elements :pwralert => :type, :pwralert_settings => [:threshold, :duration]
|
46
|
+
end
|
47
|
+
write_cmd :uid_control do
|
48
|
+
attributes :uid
|
49
|
+
end
|
50
|
+
write_cmd :warm_boot_server
|
51
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
context :user_info do
|
2
|
+
read_cmd :get_user do
|
3
|
+
attributes :user_login
|
4
|
+
end
|
5
|
+
read_cmd :get_all_users
|
6
|
+
read_cmd :get_all_user_info
|
7
|
+
|
8
|
+
write_cmd :add_user do
|
9
|
+
attributes :user_name, :user_login, :password
|
10
|
+
elements :admin_priv, :remote_cons_priv, :reset_server_priv, :virtual_media_priv, :config_ilo_priv
|
11
|
+
end
|
12
|
+
write_cmd :delete_user do
|
13
|
+
attributes :user_login
|
14
|
+
end
|
15
|
+
write_cmd :mod_user do
|
16
|
+
attributes :user_login
|
17
|
+
elements :user_name, :user_login, :password, :admin_priv, :remote_cons_priv, :reset_server_priv, :virtual_media_priv, :config_ilo_priv, :del_users_ssh_key
|
18
|
+
end
|
19
|
+
end
|
data/lib/ilorb/ilo.rb
ADDED
@@ -0,0 +1,207 @@
|
|
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
|
data/lib/ilorb/ribcl.rb
ADDED
@@ -0,0 +1,135 @@
|
|
1
|
+
module ILORb
|
2
|
+
class RIBCL < Hash
|
3
|
+
def initialize
|
4
|
+
super
|
5
|
+
end
|
6
|
+
|
7
|
+
# meaningful aliases
|
8
|
+
alias_method :has_command?, :has_key?
|
9
|
+
alias_method :command, :fetch
|
10
|
+
|
11
|
+
# mapping between Ruby objects and api format
|
12
|
+
VALUES = {
|
13
|
+
true => "yes",
|
14
|
+
false => "no",
|
15
|
+
}
|
16
|
+
|
17
|
+
def self.load(path)
|
18
|
+
obj = new
|
19
|
+
Dir.glob(path).each do |file|
|
20
|
+
obj.instance_eval(File.read(file), file)
|
21
|
+
end
|
22
|
+
obj
|
23
|
+
end
|
24
|
+
|
25
|
+
def encode(value)
|
26
|
+
VALUES[value] ? VALUES[value] : value
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
# private methods are used by DSL
|
31
|
+
|
32
|
+
def context(name, &block)
|
33
|
+
context = Context.new(name)
|
34
|
+
context.instance_eval(&block)
|
35
|
+
merge!(context.commands)
|
36
|
+
end
|
37
|
+
|
38
|
+
class Context
|
39
|
+
attr_reader :commands
|
40
|
+
|
41
|
+
def initialize(name)
|
42
|
+
@name = name.to_sym
|
43
|
+
@commands = {}
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
# private methods are used by DSL
|
48
|
+
|
49
|
+
[:read, :write].each do |mode|
|
50
|
+
define_method "#{mode}_cmd" do |name, &block|
|
51
|
+
command = Command.new(name, @name, mode)
|
52
|
+
command.instance_eval(&block) if block
|
53
|
+
@commands[name] = command
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
class Command
|
59
|
+
attr_reader :name, :context, :mode
|
60
|
+
|
61
|
+
def initialize(name, context, mode)
|
62
|
+
@name, @context, @mode = name.to_sym, context, mode
|
63
|
+
@attributes = []
|
64
|
+
@elements = {}
|
65
|
+
@text = nil
|
66
|
+
@supported = true
|
67
|
+
end
|
68
|
+
|
69
|
+
[:attributes, :elements, :text].each do |key|
|
70
|
+
define_method "get_#{key}" do
|
71
|
+
instance_variable_get("@#{key}")
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def supported?
|
76
|
+
@supported
|
77
|
+
end
|
78
|
+
|
79
|
+
def map_elements
|
80
|
+
map = {}
|
81
|
+
@elements.each do |name, type|
|
82
|
+
if type == :value
|
83
|
+
map.store(name, [name, type])
|
84
|
+
elsif type.is_a?(Array)
|
85
|
+
type.each do |elt|
|
86
|
+
map.store("#{name}_#{elt}".to_sym, [name, elt])
|
87
|
+
end
|
88
|
+
else
|
89
|
+
map.store("#{name}_#{type}".to_sym, [name, type])
|
90
|
+
end
|
91
|
+
end
|
92
|
+
map
|
93
|
+
end
|
94
|
+
|
95
|
+
def get_params
|
96
|
+
params = []
|
97
|
+
params += @attributes
|
98
|
+
params << @text if @text
|
99
|
+
params += map_elements.keys
|
100
|
+
params
|
101
|
+
end
|
102
|
+
|
103
|
+
private
|
104
|
+
# private methods are used by DSL
|
105
|
+
|
106
|
+
def attributes(*params)
|
107
|
+
@attributes += params
|
108
|
+
end
|
109
|
+
|
110
|
+
def elements(*params)
|
111
|
+
if @text.nil?
|
112
|
+
hash = {}
|
113
|
+
params.each do |param|
|
114
|
+
if param.is_a?(Hash)
|
115
|
+
hash.merge!(param)
|
116
|
+
else
|
117
|
+
hash.store(param, :value)
|
118
|
+
end
|
119
|
+
end
|
120
|
+
@elements.merge!(hash)
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
def text(param)
|
125
|
+
if @elements.empty?
|
126
|
+
@text = param
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
def not_implemented
|
131
|
+
@supported = false
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
data/lib/ilorb.rb
ADDED
@@ -0,0 +1,87 @@
|
|
1
|
+
<?xml version="1.0"?>
|
2
|
+
<RIBCL VERSION="2.22">
|
3
|
+
<RESPONSE
|
4
|
+
STATUS="0x0000"
|
5
|
+
MESSAGE='No error'
|
6
|
+
/>
|
7
|
+
<GET_NETWORK_SETTINGS>
|
8
|
+
<ENABLE_NIC VALUE="Y"/>
|
9
|
+
<SHARED_NETWORK_PORT VALUE="N"/>
|
10
|
+
<VLAN_ENABLED VALUE="N"/>
|
11
|
+
<VLAN_ID VALUE="0"/>
|
12
|
+
<SPEED_AUTOSELECT VALUE="Y"/>
|
13
|
+
<NIC_SPEED VALUE="Automatic"/>
|
14
|
+
<FULL_DUPLEX VALUE="Automatic"/>
|
15
|
+
<DHCP_ENABLE VALUE="Y"/>
|
16
|
+
<DHCP_GATEWAY VALUE="N"/>
|
17
|
+
<DHCP_DNS_SERVER VALUE="Y"/>
|
18
|
+
<DHCP_WINS_SERVER VALUE="N"/>
|
19
|
+
<DHCP_STATIC_ROUTE VALUE="N"/>
|
20
|
+
<DHCP_DOMAIN_NAME VALUE="N"/>
|
21
|
+
<DHCP_SNTP_SETTINGS VALUE="Y"/>
|
22
|
+
<REG_WINS_SERVER VALUE="N"/>
|
23
|
+
<REG_DDNS_SERVER VALUE="N"/>
|
24
|
+
<PING_GATEWAY VALUE="N"/>
|
25
|
+
<MAC_ADDRESS VALUE="1c:c1:de:17:b3:90"/>
|
26
|
+
<IP_ADDRESS VALUE="192.168.1.13"/>
|
27
|
+
<SUBNET_MASK VALUE="255.255.255.0"/>
|
28
|
+
<GATEWAY_IP_ADDRESS VALUE="0.0.0.0"/>
|
29
|
+
<DNS_NAME VALUE="weezer"/>
|
30
|
+
<DOMAIN_NAME VALUE="ilotest.com."/>
|
31
|
+
<PRIM_DNS_SERVER VALUE="0.0.0.0"/>
|
32
|
+
<SEC_DNS_SERVER VALUE="0.0.0.0"/>
|
33
|
+
<TER_DNS_SERVER VALUE="0.0.0.0"/>
|
34
|
+
<PRIM_WINS_SERVER VALUE="0.0.0.0"/>
|
35
|
+
<SEC_WINS_SERVER VALUE="0.0.0.0"/>
|
36
|
+
<SNTP_SERVER1 VALUE="192.168.1.5"/>
|
37
|
+
<SNTP_SERVER2 VALUE=""/>
|
38
|
+
<TIMEZONE VALUE="CST6CDT"/>
|
39
|
+
<STATIC_ROUTE_1 DEST="0.0.0.0"
|
40
|
+
MASK="0.0.0.0"
|
41
|
+
GATEWAY="0.0.0.0"/>
|
42
|
+
<STATIC_ROUTE_2 DEST="0.0.0.0"
|
43
|
+
MASK="0.0.0.0"
|
44
|
+
GATEWAY="0.0.0.0"/>
|
45
|
+
<STATIC_ROUTE_3 DEST="0.0.0.0"
|
46
|
+
MASK="0.0.0.0"
|
47
|
+
GATEWAY="0.0.0.0"/>
|
48
|
+
<IPV6_ADDRESS VALUE="2001:2:1::15"
|
49
|
+
PREFIXLEN="64"
|
50
|
+
ADDR_SOURCE="STATIC"
|
51
|
+
ADDR_STATUS="ACTIVE"/>
|
52
|
+
<IPV6_ADDRESS VALUE="2001:db8:1::50"
|
53
|
+
PREFIXLEN="64"
|
54
|
+
ADDR_SOURCE="STATIC"
|
55
|
+
ADDR_STATUS="ACTIVE"/>
|
56
|
+
<IPV6_ADDRESS VALUE="fe80::1ec1:deff:fe17:b390"
|
57
|
+
PREFIXLEN="64"
|
58
|
+
ADDR_SOURCE="SLAAC"
|
59
|
+
ADDR_STATUS="ACTIVE"/>
|
60
|
+
<IPV6_ADDRESS VALUE="2001:2:1:0:1ec1:deff:fe17:b390"
|
61
|
+
PREFIXLEN="64"
|
62
|
+
ADDR_SOURCE="SLAAC"
|
63
|
+
ADDR_STATUS="ACTIVE"/>
|
64
|
+
<IPV6_STATIC_ROUTE_1
|
65
|
+
IPV6_DEST="2001:2:2::20"
|
66
|
+
PREFIXLEN="64"
|
67
|
+
IPV6_GATEWAY="fe80::1:2:3"
|
68
|
+
ADDR_STATUS="ACTIVE"/>
|
69
|
+
<IPV6_STATIC_ROUTE_2
|
70
|
+
IPV6_DEST="::"
|
71
|
+
PREFIXLEN="0"
|
72
|
+
IPV6_GATEWAY="::"
|
73
|
+
ADDR_STATUS="INACTIVE"/>
|
74
|
+
<IPV6_STATIC_ROUTE_3
|
75
|
+
IPV6_DEST="2001:1001:2002:3003::"
|
76
|
+
PREFIXLEN="64"
|
77
|
+
IPV6_GATEWAY="2001:db8:1::40"
|
78
|
+
ADDR_STATUS="ACTIVE"/>
|
79
|
+
<IPV6_PRIM_DNS_SERVER VALUE="2001:1:2::5"/>
|
80
|
+
<IPV6_SEC_DNS_SERVER VALUE="2001:1:2::6"/>
|
81
|
+
<IPV6_TER_DNS_SERVER VALUE="::"/>
|
82
|
+
<IPV6_DEFAULT_GATEWAY VALUE="fe80::21c:c4ff:fe18:9cbd"/>
|
83
|
+
<IPV6_PREFERRED_PROTOCOL VALUE="Y"/>
|
84
|
+
<IPV6_ADDR_AUTOCFG VALUE="Y"/>
|
85
|
+
<IPV6_REG_DDNS_SERVER VALUE="Y"/>
|
86
|
+
</GET_NETWORK_SETTINGS>
|
87
|
+
</RIBCL>
|
data/spec/ilo_spec.rb
ADDED
@@ -0,0 +1,79 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe ILORb::ILO do
|
4
|
+
let(:hostname) { "10.200.0.1" }
|
5
|
+
let(:login) { "Admin" }
|
6
|
+
let(:password) { "SECRET" }
|
7
|
+
let(:ilo) { ILORb::ILO.new(hostname: hostname, login: login, password: password) }
|
8
|
+
|
9
|
+
describe "#get_network_settings" do
|
10
|
+
before do
|
11
|
+
stub_request(:post, "https://10.200.0.1/ribcl").
|
12
|
+
with(:body => "<?xml version=\"1.0\"?>\n<ribcl version=\"2.0\">\n <login password=\"SECRET\" user_login=\"Admin\">\n <rib_info mode=\"read\">\n <get_network_settings/>\n </rib_info>\n </login>\n</ribcl>\n").
|
13
|
+
to_return(:status => 200, :body => asset_file('get_network_settings_response.xml'))
|
14
|
+
end
|
15
|
+
|
16
|
+
subject { ilo.get_network_settings }
|
17
|
+
|
18
|
+
its([:status]) { should include(code: 0, message: 'No error') }
|
19
|
+
its([:get_network_settings]) { should_not be_empty }
|
20
|
+
end
|
21
|
+
|
22
|
+
describe "#set_one_time_boot" do
|
23
|
+
before do
|
24
|
+
stub_request(:post, "https://10.200.0.1/ribcl").
|
25
|
+
with(:body => "<?xml version=\"1.0\"?>\n<ribcl version=\"2.0\">\n <login password=\"SECRET\" user_login=\"Admin\">\n <server_info mode=\"write\">\n <set_one_time_boot value=\"FLOPPY\"/>\n </server_info>\n </login>\n</ribcl>\n").
|
26
|
+
to_return(:status => 200, :body => asset_file('basic_response.xml'))
|
27
|
+
end
|
28
|
+
|
29
|
+
subject { ilo.set_one_time_boot(value: "FLOPPY") }
|
30
|
+
|
31
|
+
its([:status]) { should include(code: 0, message: 'No error') }
|
32
|
+
end
|
33
|
+
|
34
|
+
describe "#set_pwreg" do
|
35
|
+
before do
|
36
|
+
stub_request(:post, "https://10.200.0.1/ribcl").
|
37
|
+
with(:body => "<?xml version=\"1.0\"?>\n<ribcl version=\"2.0\">\n <login password=\"SECRET\" user_login=\"Admin\">\n <server_info mode=\"write\">\n <set_pwreg>\n <pwralert type=\"PEAK\"/>\n <pwralert_settings threshold=\"200\" duration=\"35\"/>\n </set_pwreg>\n </server_info>\n </login>\n</ribcl>\n").
|
38
|
+
to_return(:status => 200, :body => asset_file('basic_response.xml'))
|
39
|
+
end
|
40
|
+
|
41
|
+
subject { ilo.set_pwreg pwralert_type: "PEAK",
|
42
|
+
pwralert_settings_threshold: 200,
|
43
|
+
pwralert_settings_duration: 35 }
|
44
|
+
|
45
|
+
its([:status]) { should include(code: 0, message: 'No error') }
|
46
|
+
end
|
47
|
+
|
48
|
+
describe "#set_one_time_boot" do
|
49
|
+
before do
|
50
|
+
stub_request(:post, "https://10.200.0.1/ribcl").
|
51
|
+
with(:body => "<?xml version=\"1.0\"?>\n<ribcl version=\"2.0\">\n <login password=\"SECRET\" user_login=\"Admin\">\n <server_info mode=\"write\">\n <set_one_time_boot value=\"FLOPPY\"/>\n </server_info>\n </login>\n</ribcl>\n").
|
52
|
+
to_return(:status => 200, :body => asset_file('basic_response.xml'))
|
53
|
+
end
|
54
|
+
|
55
|
+
subject { ilo.set_one_time_boot(value: "FLOPPY") }
|
56
|
+
|
57
|
+
its([:status]) { should include(code: 0, message: 'No error') }
|
58
|
+
end
|
59
|
+
|
60
|
+
describe "#set_persistent_boot" do
|
61
|
+
before do
|
62
|
+
stub_request(:post, "https://10.200.0.1/ribcl").
|
63
|
+
with(:body => "<?xml version=\"1.0\"?>\n<ribcl version=\"2.0\">\n <login password=\"SECRET\" user_login=\"Admin\">\n <server_info mode=\"write\">\n <set_persistent_boot>\n <device value=\"FLOPPY\"/>\n <device value=\"CDROM\"/>\n </set_persistent_boot>\n </server_info>\n </login>\n</ribcl>\n").
|
64
|
+
to_return(:status => 200, :body => asset_file('basic_response.xml'))
|
65
|
+
end
|
66
|
+
|
67
|
+
subject { ilo.set_persistent_boot([{ device_value: "FLOPPY" },
|
68
|
+
{ device_value: "CDROM" }]) }
|
69
|
+
|
70
|
+
its([:status]) { should include(code: 0, message: 'No error') }
|
71
|
+
end
|
72
|
+
|
73
|
+
private
|
74
|
+
|
75
|
+
def asset_file(asset)
|
76
|
+
path = File.join(File.dirname(__FILE__), 'assets', asset)
|
77
|
+
File.new(path)
|
78
|
+
end
|
79
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,161 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ilorb
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Jonathan Amiez
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-07-25 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: bundler
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '1.2'
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '1.2'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: rspec
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ~>
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '2.14'
|
38
|
+
type: :development
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ~>
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '2.14'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: webmock
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ~>
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '1.13'
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ~>
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '1.13'
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: pry
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ! '>='
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0'
|
70
|
+
type: :development
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
78
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: nokogiri
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ! '>='
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '0'
|
86
|
+
type: :runtime
|
87
|
+
prerelease: false
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ! '>='
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: '0'
|
94
|
+
- !ruby/object:Gem::Dependency
|
95
|
+
name: nori
|
96
|
+
requirement: !ruby/object:Gem::Requirement
|
97
|
+
none: false
|
98
|
+
requirements:
|
99
|
+
- - ! '>='
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: '0'
|
102
|
+
type: :runtime
|
103
|
+
prerelease: false
|
104
|
+
version_requirements: !ruby/object:Gem::Requirement
|
105
|
+
none: false
|
106
|
+
requirements:
|
107
|
+
- - ! '>='
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '0'
|
110
|
+
description: HP ILO Ruby interface
|
111
|
+
email:
|
112
|
+
- jonathan.amiez@gmail.com
|
113
|
+
executables: []
|
114
|
+
extensions: []
|
115
|
+
extra_rdoc_files: []
|
116
|
+
files:
|
117
|
+
- Gemfile
|
118
|
+
- Gemfile.lock
|
119
|
+
- README.md
|
120
|
+
- ilorb.gemspec
|
121
|
+
- lib/ilorb.rb
|
122
|
+
- lib/ilorb/definitions/rib.rb
|
123
|
+
- lib/ilorb/definitions/server.rb
|
124
|
+
- lib/ilorb/definitions/user.rb
|
125
|
+
- lib/ilorb/ilo.rb
|
126
|
+
- lib/ilorb/ribcl.rb
|
127
|
+
- lib/ilorb/version.rb
|
128
|
+
- spec/assets/basic_response.xml
|
129
|
+
- spec/assets/get_network_settings_response.xml
|
130
|
+
- spec/ilo_spec.rb
|
131
|
+
- spec/spec_helper.rb
|
132
|
+
homepage: https://github.com/josqu4red/ilorb
|
133
|
+
licenses:
|
134
|
+
- MIT
|
135
|
+
post_install_message:
|
136
|
+
rdoc_options: []
|
137
|
+
require_paths:
|
138
|
+
- lib
|
139
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
140
|
+
none: false
|
141
|
+
requirements:
|
142
|
+
- - ! '>='
|
143
|
+
- !ruby/object:Gem::Version
|
144
|
+
version: '0'
|
145
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
146
|
+
none: false
|
147
|
+
requirements:
|
148
|
+
- - ! '>='
|
149
|
+
- !ruby/object:Gem::Version
|
150
|
+
version: '0'
|
151
|
+
requirements: []
|
152
|
+
rubyforge_project:
|
153
|
+
rubygems_version: 1.8.25
|
154
|
+
signing_key:
|
155
|
+
specification_version: 3
|
156
|
+
summary: Configure and retrieve data from server's ILO management card
|
157
|
+
test_files:
|
158
|
+
- spec/assets/basic_response.xml
|
159
|
+
- spec/assets/get_network_settings_response.xml
|
160
|
+
- spec/ilo_spec.rb
|
161
|
+
- spec/spec_helper.rb
|