├── .gitignore ├── .rubocop.yml ├── .travis.yml ├── CHANGELOG.md ├── Gemfile ├── LICENSE ├── README.md ├── Rakefile ├── bin └── ilo-ruby ├── ilo-sdk.gemspec ├── lib ├── ilo-sdk.rb └── ilo-sdk │ ├── cli.rb │ ├── client.rb │ ├── exceptions.rb │ ├── helpers │ ├── account_service_helper.rb │ ├── bios_helper.rb │ ├── boot_settings_helper.rb │ ├── chassis_helper.rb │ ├── computer_details_helper.rb │ ├── computer_system_helper.rb │ ├── date_time_helper.rb │ ├── ethernet_interface_helper.rb │ ├── firmware_update.rb │ ├── https_cert_helper.rb │ ├── log_entry_helper.rb │ ├── manager_account_helper.rb │ ├── manager_network_protocol_helper.rb │ ├── power_helper.rb │ ├── secure_boot_helper.rb │ ├── service_root_helper.rb │ ├── snmp_service_helper.rb │ └── virtual_media_helper.rb │ ├── rest.rb │ └── version.rb └── spec ├── shared_context.rb ├── spec_helper.rb ├── support └── fake_response.rb └── unit ├── cli ├── cli_spec.rb ├── console_spec.rb ├── env_spec.rb ├── login_spec.rb ├── output_spec.rb ├── rest_spec.rb └── version_spec.rb ├── client_spec.rb ├── helpers ├── account_service_spec.rb ├── bios_spec.rb ├── boot_settings_spec.rb ├── chassis_spec.rb ├── computer_system_spec.rb ├── date_time_spec.rb ├── ethernet_interface_helper_spec.rb ├── firmware_update_spec.rb ├── https_cert_spec.rb ├── log_entry_spec.rb ├── manager_account_spec.rb ├── manager_network_protocol_spec.rb ├── power_spec.rb ├── secure_boot_spec.rb ├── service_root_spec.rb ├── snmp_service_spec.rb └── virtual_media_spec.rb └── rest_spec.rb /.gitignore: -------------------------------------------------------------------------------- 1 | *.gem 2 | *.rbc 3 | .bundle 4 | .config 5 | .yardoc 6 | Gemfile.lock 7 | Berksfile.lock 8 | InstalledFiles 9 | _yardoc 10 | coverage 11 | doc/ 12 | lib/bundler/man 13 | pkg 14 | rdoc 15 | spec/reports 16 | test/tmp 17 | test/version_tmp 18 | tmp 19 | *.bundle 20 | *.so 21 | *.o 22 | *.a 23 | mkmf.log 24 | *.sw* 25 | -------------------------------------------------------------------------------- /.rubocop.yml: -------------------------------------------------------------------------------- 1 | # See default at https://github.com/bbatsov/rubocop/blob/master/config/default.yml 2 | AllCops: 3 | TargetRubyVersion: 2.1 4 | 5 | Metrics/ClassLength: 6 | Max: 200 7 | 8 | Metrics/LineLength: 9 | Max: 155 10 | 11 | Metrics/ModuleLength: 12 | Max: 150 13 | 14 | Metrics/ParameterLists: 15 | Max: 6 16 | 17 | Style/IndentationWidth: 18 | Width: 2 19 | 20 | Style/VariableName: 21 | EnforcedStyle: snake_case 22 | 23 | Style/FileName: 24 | Exclude: 25 | - 'lib/ilo-sdk.rb' 26 | 27 | Style/AlignParameters: 28 | Exclude: 29 | - 'lib/ilo-sdk/cli.rb' 30 | 31 | 32 | Style/AccessorMethodName: 33 | Enabled: false 34 | 35 | Style/ClassAndModuleCamelCase: 36 | Enabled: false 37 | 38 | Style/EmptyLines: 39 | Enabled: false 40 | 41 | Style/RescueModifier: 42 | Enabled: false 43 | 44 | Style/EmptyLinesAroundBlockBody: 45 | Enabled: false 46 | 47 | Style/EmptyLinesAroundClassBody: 48 | Enabled: false 49 | 50 | Metrics/AbcSize: 51 | Enabled: false 52 | 53 | Metrics/CyclomaticComplexity: 54 | Enabled: false 55 | 56 | Metrics/MethodLength: 57 | Enabled: false 58 | 59 | Metrics/PerceivedComplexity: 60 | Enabled: false 61 | 62 | Performance/Casecmp: 63 | Enabled: false 64 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: ruby 2 | rvm: 3 | - 2.1 4 | 5 | script: 6 | - rake build 7 | - rake test 8 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ### New (Unreleased) 2 | - (none) 3 | 4 | #### v1.2.2 5 | - Fixed log_entry helper methods 6 | 7 | #### v1.2.1 8 | - Added rest command to cli 9 | 10 | ### v1.2.0 11 | - Added custom exception classes 12 | - Added disable_proxy client option 13 | - Added CLI 14 | - Support environment variables 15 | - New BIOS and ComputerSystem helper methods (deprecated old ones) 16 | 17 | ### v1.1.0 18 | - Added ManagerAccountHelper (to allow setting user permissions) 19 | 20 | ### v1.0.2 21 | - Make client.get_certificate return the full X509 object 22 | 23 | ### v1.0.1 24 | - Added SSL certificate helper methods 25 | - Make `pry` a development dependency, not a runtime dependency. 26 | 27 | ## v1.0.0 28 | Initial release 29 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | gemspec 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright 2016 Hewlett Packard Enterprise Development LP 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Ruby SDK for HPE iLO 2 | 3 | [![Gem Version](https://badge.fury.io/rb/ilo-sdk.svg)](https://badge.fury.io/rb/ilo-sdk) 4 | [![Yard Docs](http://img.shields.io/badge/yard-docs-blue.svg)](http://www.rubydoc.info/gems/ilo-sdk) 5 | 6 | Software Development Kit for interacting with the Hewlett Packard Enterprise iLO (Integrated Lights-Out) server management technology. 7 | 8 | ### Supported iLO versions: 9 | 10 | - iLO 4 11 | 12 | ## Installation 13 | 14 | - Require the gem in your Gemfile: 15 | 16 | ```ruby 17 | gem 'ilo-sdk' 18 | ``` 19 | 20 | Then run `$ bundle install` 21 | - Or run the command: 22 | 23 | ```bash 24 | $ gem install ilo-sdk 25 | ``` 26 | 27 | 28 | ## Client 29 | 30 | Everything you do with this API happens through a client object. 31 | Creating the client object is the first step; then you can perform actions on the client. 32 | 33 | ```ruby 34 | require 'ilo-sdk' 35 | client = ILO_SDK::Client.new( 36 | host: 'https://ilo.example.com', 37 | user: 'Administrator', # This is the default 38 | password: 'secret123', 39 | ssl_enabled: true, # This is the default and strongly encouraged 40 | logger: Logger.new(STDOUT), # This is the default 41 | log_level: :info, # This is the default 42 | disable_proxy: true # Default is false. Set to disable, even if ENV['http_proxy'] is set 43 | ) 44 | ``` 45 | 46 | :lock: Tip: Check the file permissions when storing passwords in clear-text. 47 | 48 | #### Environment Variables 49 | 50 | You can also set many client options using environment variables. For bash: 51 | 52 | ```bash 53 | export ILO_HOST='https://oneview.example.com' 54 | export ILO_USER='Administrator' 55 | export ILO_PASSWORD='secret123' 56 | export ILO_SSL_ENABLED=false # NOTE: Disabling SSL is strongly discouraged. Please see the CLI section for import instructions. 57 | ``` 58 | 59 | :lock: Tip: Be sure nobody can access to your environment variables 60 | 61 | ### Custom logging 62 | 63 | The default logger is a standard logger to STDOUT, but if you want to specify your own, you can. However, your logger must implement the following methods: 64 | 65 | ```ruby 66 | debug(String) 67 | info(String) 68 | warn(String) 69 | error(String) 70 | level=(Symbol, etc.) # The parameter here will be the log_level attribute 71 | ``` 72 | 73 | 74 | ## Actions 75 | 76 | Actions are performed on the client, and defined in the [helper modules](lib/ilo-sdk/helpers). 77 | 78 | #### Account Service 79 | 80 | ```ruby 81 | # Get list of users: 82 | users = client.get_users 83 | 84 | # Create a user: 85 | client.create_user('user1', 'password123') 86 | 87 | # Change a user's password: 88 | client.change_password('user1', 'newpassword123') 89 | 90 | # Delete a user: 91 | client.delete_user('user1') 92 | ``` 93 | 94 | #### Bios 95 | 96 | ```ruby 97 | # Get all BIOS settings 98 | settings = client.get_bios_settings 99 | 100 | # Set BIOS settings 101 | client.set_bios_settings( 102 | UefiShellStartup: 'Enabled', 103 | Ipv4Gateway: '10.0.1.1', 104 | ServiceEmail: 'admin@domain.com' 105 | # Note: You can set many more options here. This is just an example. 106 | ) 107 | 108 | # Get BIOS base configuration: 109 | baseconfig = client.get_bios_baseconfig 110 | 111 | # Revert BIOS: 112 | client.revert_bios 113 | 114 | # Get UEFI shell startup settings: 115 | uefi_shell_startup = client.get_uefi_shell_startup 116 | 117 | # Set UEFI shell startup settings: 118 | uefi_shell_startup_location = 'Auto' 119 | uefi_shell_startup_url = 'http://wwww.uefi.com' 120 | client.uefi_shell_startup('Enabled', uefi_shell_startup_location, uefi_shell_startup_url) 121 | 122 | # Get BIOS DHCP settings: 123 | bios_dhcp = client.get_bios_dhcp 124 | 125 | # Set BIOS DHCP settings: 126 | ipv4_address = '10.1.1.111' 127 | ipv4_gateway = '10.1.1.0' 128 | ipv4_primary_dns = '10.1.1.1' 129 | ipv4_secondary_dns = '10.1.1.2' 130 | ipv4_subnet_mark = '255.255.255.0' 131 | client.set_bios_dhcp('Disabled', ipv4_address, ipv4_gateway, ipv4_primary_dns, ipv4_secondary_dns, ipv4_subnet_mark) 132 | 133 | # Get the URL boot file: 134 | url_boot_file = client.get_url_boot_file 135 | 136 | # Set the URL boot file: 137 | client.set_url_boot_file('http://www.urlbootfile.iso') 138 | 139 | # Get BIOS service settings: 140 | bios_service_settings = client.get_bios_service 141 | 142 | # Set BIOS service settings: 143 | service_name = 'my_name' 144 | service_email = 'my_name@domain.com' 145 | client.set_bios_service(service_name, service_email) 146 | ``` 147 | 148 | #### Boot Settings 149 | 150 | ```ruby 151 | # Get boot order base configuration: 152 | baseconfig = client.get_boot_baseconfig 153 | 154 | # Revert the boot: 155 | client.revert_boot 156 | 157 | # Get boot order: 158 | boot_order = client.get_boot_order 159 | 160 | # Set boot order: 161 | client.set_boot_order([ 162 | "Generic.USB.1.1", 163 | "NIC.LOM.1.1.IPv4", 164 | "NIC.LOM.1.1.IPv6", 165 | "NIC.Slot.1.1.IPv6", 166 | "HD.Emb.5.2", 167 | "HD.Emb.5.1", 168 | "NIC.Slot.1.1.IPv4" 169 | ]) 170 | 171 | # Get temporary boot order: 172 | temporary_boot_order = client.get_temporary_boot_order 173 | 174 | # Set temporary boot order: 175 | boot_source_override_target = 'CD' 176 | client.set_temporary_boot_order(boot_source_override_target) 177 | ``` 178 | 179 | #### Chassis 180 | 181 | ```ruby 182 | # Get power metrics information: 183 | power_metrics = client.get_power_metrics 184 | 185 | # Get thermal metrics information: 186 | thermal_metrics = client.get_thermal_metrics 187 | ``` 188 | 189 | #### Computer Details 190 | 191 | ```ruby 192 | # Get computer details (including general, network, and array controller details): 193 | computer_details = client.get_computer_details 194 | 195 | # Get general computer details: 196 | general_details = client.get_general_computer_details 197 | 198 | # Get computer network details: 199 | network_details = client.get_computer_network_details 200 | 201 | # Get array controller details: 202 | array_controller_details = client.get_array_controller_details 203 | ``` 204 | 205 | #### Computer System 206 | 207 | ```ruby 208 | # Get computer system settings 209 | settings = client.get_system_settings 210 | 211 | # Set computer system settings 212 | client.set_system_settings( 213 | AssetTag: 'HP001', 214 | IndicatorLED: 'Lit' 215 | # Note: You can set more options here. This is just an example. 216 | ) 217 | ``` 218 | 219 | #### Date Time 220 | 221 | ```ruby 222 | # Get the time zone: 223 | time_zone = client.get_time_zone 224 | 225 | # Set the time zone: 226 | client.set_time_zone('Africa/Abidjan') 227 | 228 | # Get whether or not NTP servers are in use (true or false): 229 | ntp_server_use = client.get_ntp 230 | 231 | # Set whether or not to use NTP servers: 232 | client.set_ntp(true) 233 | 234 | # Get a list of NTP servers: 235 | ntp_servers = client.get_ntp_servers 236 | 237 | # Set the NTP servers: 238 | ntp_servers = ['10.1.1.1', '10.1.1.2'] 239 | client.set_ntp_server(ntp_servers) 240 | ``` 241 | 242 | #### Manager EthernetInterface settings 243 | 244 | ```ruby 245 | # Get EthernetInteface settings 246 | client.get_ilo_ethernet_interface 247 | 248 | # Set EthernetInterface to obtain all IPv4 parameters from DHCP server 249 | client.set_ilo_ipv4_dhcp 250 | 251 | # Set static IPv4 address, netmask and gateway 252 | client.set_ilo_ipv4_static(ip: '192.168.1.1', netmask: '255.255.255.0', gateway: '192.168.1.254') 253 | 254 | # Set IPv4 DNS servers 255 | client.set_ilo_ipv4_dns_servers(dns_servers: ['2.2.2.2', '4.4.4.4', '8.8.8.8']) 256 | 257 | # Set hostname and domain name 'server-ilo.domain.local' 258 | client.set_ilo_hostname(hostname: 'server-ilo', domain_name: 'domain.local') 259 | ``` 260 | 261 | #### Firmware 262 | 263 | ```ruby 264 | # Get the firmware version: 265 | fw_version = client.get_fw_version 266 | 267 | # Set the firmware URI for a firmware upgrade: 268 | client.set_fw_upgrade('www.firmwareupgrade.com') 269 | ``` 270 | 271 | #### HTTPS Certificate 272 | 273 | ```ruby 274 | # Get the current SSL Certificate and check to see if expires within 24 hours 275 | expiration = client.get_certificate.not_after.to_datetime 276 | tomorrow = DateTime.now + 1 277 | 278 | if expiration < tomorrow 279 | # Generate a Certificate Signing Request: 280 | # Params: country_code, state, city, organization, organizational_unit, common_name 281 | client.generate_csr('US', 'Texas', 'Houston', 'myCompany', 'myUnit', 'example.com') 282 | 283 | # Wait for the CSR to be generated (will take about 10 minutes): 284 | csr = nil 285 | while(csr.nil?) do 286 | sleep(60) # 60 seconds 287 | csr = client.get_csr 288 | end 289 | 290 | # Here you'll need to have a step that submits the csr to a certificate authority 291 | # (or self-signs it) and gets back the signed certificate. It will look something like: 292 | # -----BEGIN CERTIFICATE----- 293 | # lines_of_secret_text 294 | # -----END CERTIFICATE----- 295 | # For this example, we're assuming we've read in the content of the certificate to the 296 | # "cert" variable (as a string). 297 | 298 | client.import_certificate(cert) 299 | end 300 | ``` 301 | 302 | #### Log Entry 303 | 304 | ```ruby 305 | # Clear a specific type of logs: 306 | log_type = 'IEL' 307 | client.clear_logs(log_type) 308 | 309 | # Check to see if a specific type of logs are empty: 310 | empty = client.logs_empty?(log_type) 311 | 312 | # Get a specific type of logs based on severity level and duration: 313 | severity_level = 'OK' 314 | duration = 10 # hours 315 | logs = client.get_logs(severity_level, duration, log_type) 316 | ``` 317 | 318 | #### Manager Account 319 | 320 | ```ruby 321 | # Get the Account Privileges for a specific user: 322 | username = 'Administrator' 323 | client.get_account_privileges(username) 324 | 325 | # Set the Login Privilege to true for a specific user: 326 | client.set_account_privileges(username, LoginPriv: true) 327 | 328 | # Set all of the Account Privileges for a specific user: 329 | privileges = { 330 | 'LoginPriv' => true, 331 | 'RemoteConsolePriv' => true, 332 | 'UserConfigPriv' => true, 333 | 'VirtualMediaPriv' => true, 334 | 'VirtualPowerAndResetPriv' => true, 335 | 'iLOConfigPriv' => true 336 | } 337 | client.set_account_privileges(username, privileges) 338 | ``` 339 | 340 | #### Manager Network Protocol 341 | 342 | ```ruby 343 | # Get the minutes until session timeout: 344 | timeout = client.get_timeout 345 | 346 | # Set the minutes until session timeout: 347 | client.set_timeout(60) 348 | ``` 349 | 350 | #### Power 351 | 352 | ```ruby 353 | # Get the power state of the system: 354 | power_state = client.get_power_state 355 | 356 | # Set the power state of the system: 357 | client.set_power_state('On') 358 | 359 | # Reset the iLO: 360 | client.reset_ilo 361 | ``` 362 | 363 | #### Secure Boot 364 | 365 | ```ruby 366 | # Get whether or not UEFI secure boot is enabled: 367 | uefi_secure_boot = client.get_uefi_secure_boot 368 | 369 | # Set whether or not UEFI secure boot is enabled: 370 | client.set_uefi_secure_boot(true) 371 | ``` 372 | 373 | #### Service Root 374 | 375 | ```ruby 376 | # Get the schema information with a given prefix: 377 | schema_prefix = 'Account' 378 | schema = client.get_schema(schema_prefix) 379 | 380 | # Get the registry information with a given prefix: 381 | registry_prefix = 'Base' 382 | registry = client.get_registry(registry_prefix) 383 | ``` 384 | 385 | #### SNMP 386 | 387 | ```ruby 388 | # Get the SNMP mode: 389 | snmp_mode = client.get_snmp_mode 390 | 391 | # Get whether or not SNMP Alerts are enabled: 392 | snmp_alerts_enabled = client.get_snmp_alerts_enabled 393 | 394 | # Set the SNMP mode and whether or not SNMP Alerts are enabled: 395 | snmp_mode = 'Agentless' 396 | snmp_alerts_enabled = true 397 | client.set_snmp(snmp_mode, snmp_alerts_enabled) 398 | ``` 399 | 400 | #### Virtual Media 401 | 402 | ```ruby 403 | # Get the virtual media information: 404 | virtual_media = client.get_virtual_media 405 | 406 | # Get whether or not virtual media is inserted for a certain id: 407 | id = 1 408 | virtual_media_inserted = client.virtual_media_inserted?(id) 409 | 410 | # Insert virtual media at a certain id: 411 | image = 'http://10.254.224.38:5000/ubuntu-15.04-desktop-amd64.iso' 412 | client.insert_virtual_media(id, image) 413 | 414 | # Eject virtual media at a certain id: 415 | client.eject_virtual_media(id) 416 | ``` 417 | 418 | ## Custom requests 419 | 420 | This gem includes some useful helper methods, but sometimes you need to make your own custom requests to the iLO. 421 | This project makes it extremely easy to do with some built-in methods for the client object. Here are some examples: 422 | 423 | ```ruby 424 | # Get a list of schemas: 425 | response = client.rest_api(:get, '/rest/v1/Schemas') 426 | # or even more simple: 427 | response = client.rest_get('/rest/v1/Schemas') 428 | 429 | # Then we can validate the response and convert the response body into a hash... 430 | data = client.response_handler(response) 431 | 432 | # For updating iLO resources, use patch: 433 | options = { ServiceName: 'iLO Admin', ServiceEmail: 'admin@domain.com' } 434 | response = client.rest_patch('/redfish/v1/Systems/1/bios/Settings/', body: options) 435 | 436 | # For creating new iLO resources, use post: 437 | options = { UserName: 'admin', Password: '123' } 438 | response = client.rest_post('/redfish/v1/AccountService/Accounts/', body: options) 439 | ``` 440 | 441 | These example are about as basic as it gets, but you can make any type of iLO API request. 442 | If a helper does not do what you need, this will allow you to do it. 443 | Please refer to the documentation and [code](lib/ilo-sdk/rest.rb) for complete list of methods and information about how to use them. 444 | 445 | 446 | ## CLI 447 | 448 | This gem also comes with a command-line interface to make interacting with the iLO API possible without needing to create a Ruby program. 449 | 450 | Note: In order to use this, you will need to make sure your ruby bin directory is in your path. Run $ gem environment to see where the executable paths are for your Ruby installation. 451 | 452 | To get started, run `$ ilo-ruby --help`. 453 | 454 | To communicate with an appliance, you will need to set up a few environment variables so it knows how to communicate. Run $ ilo-ruby env to see the available environment variables. 455 | 456 | Here are a few examples of how you might want to use the CLI: 457 | 458 | ##### Start an interactive console session with an iLO connection: 459 | 460 | ```bash 461 | $ ilo-ruby console 462 | Connected to https://ilo.example.com 463 | HINT: The @client object is available to you 464 | > 465 | ``` 466 | 467 | 468 | ## License 469 | 470 | This project is licensed under the Apache 2.0 license. Please see [LICENSE](LICENSE) for more info. 471 | 472 | 473 | ## Contributing and feature requests 474 | 475 | **Contributing:** You know the drill. Fork it, branch it, change it, commit it, and pull-request it. 476 | We are passionate about improving this project, and glad to accept help to make it better. However, keep the following in mind: 477 | 478 | - You must sign a Contributor License Agreement first. Contact one of the authors (from Hewlett Packard Enterprise) for details and the CLA. 479 | - All pull requests must contain complete test code also. See the testing section below. 480 | - We reserve the right to reject changes that we feel do not fit the scope of this project, so for feature additions, please open an issue to discuss your ideas before doing the work. 481 | 482 | **Feature Requests:** If you have a need that is not met by the current implementation, please let us know (via a new issue). 483 | This feedback is crucial for us to deliver a useful product. Do not assume we have already thought of everything, because we assure you that is not the case. 484 | 485 | ### Building the Gem 486 | 487 | First run `$ bundle` (requires the bundler gem), then... 488 | - To build only, run `$ rake build`. 489 | - To build and install the gem, run `$ rake install`. 490 | 491 | ### Testing 492 | 493 | - RuboCop: `$ rake rubocop` 494 | - Unit: `$ rake spec` 495 | - All test: `$ rake test` 496 | 497 | Note: run `$ rake -T` to get a list of all the available rake tasks. 498 | 499 | ## Authors 500 | 501 | - Anirudh Gupta - [@Anirudh-Gupta](https://github.com/Anirudh-Gupta) 502 | - Bik Bajwa - [@bikbajwa](https://github.com/bikbajwa) 503 | - Jared Smartt - [@jsmartt](https://github.com/jsmartt) 504 | - Vivek Bhatia - [@vivekbhatia14] (https://github.com/vivekbhatia14) 505 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | # (C) Copyright 2016 Hewlett Packard Enterprise Development LP 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # You may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software distributed 8 | # under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 9 | # CONDITIONS OF ANY KIND, either express or implied. See the License for the 10 | # specific language governing permissions and limitations under the License. 11 | 12 | require 'bundler' 13 | require 'bundler/gem_tasks' 14 | require 'bundler/setup' 15 | require 'rspec/core/rake_task' 16 | require 'rubocop/rake_task' 17 | 18 | task default: :test 19 | 20 | desc 'Run unit tests only' 21 | RSpec::Core::RakeTask.new(:spec) do |spec| 22 | spec.pattern = 'spec/**/*_spec.rb' 23 | spec.rspec_opts = '--color ' 24 | end 25 | 26 | RuboCop::RakeTask.new do |task| 27 | task.options << '--display-cop-names' 28 | end 29 | 30 | desc 'Runs rubocop and unit tests' 31 | task test: [:rubocop, :spec] 32 | -------------------------------------------------------------------------------- /bin/ilo-ruby: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | require 'ilo-sdk' 3 | ILO_SDK::Cli::Runner.new(ARGV.dup).execute! 4 | -------------------------------------------------------------------------------- /ilo-sdk.gemspec: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | # http://guides.rubygems.org/specification-reference 3 | 4 | # (c) Copyright 2016 Hewlett Packard Enterprise Development LP 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software distributed 11 | # under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 12 | # CONDITIONS OF ANY KIND, either express or implied. See the License for the 13 | # specific language governing permissions and limitations under the License. 14 | 15 | require_relative './lib/ilo-sdk/version' 16 | 17 | Gem::Specification.new do |spec| 18 | spec.name = 'ilo-sdk' 19 | spec.version = ILO_SDK::VERSION 20 | spec.authors = ['Anirudh Gupta', 'Bik Bajwa', 'Jared Smartt', 'Vivek Bhatia'] 21 | spec.email = ['anirudhg@hpe.com', 'bik.bajwa@hpe.com', 'jared.smartt@hpe.com', 'vivek.bhatia@hpe.com'] 22 | spec.summary = 'Gem to interact with iLO API' 23 | spec.description = 'Gem to interact with iLO API' 24 | spec.license = 'Apache-2.0' 25 | spec.homepage = 'https://github.com/HewlettPackard/ilo-sdk-ruby' 26 | 27 | all_files = `git ls-files -z`.split("\x0") 28 | spec.files = all_files.reject { |f| f.match(%r{^(examples\/)|(spec\/)}) } 29 | spec.executables = all_files.grep(%r{^bin/}) { |f| File.basename(f) } 30 | spec.require_paths = ['lib'] 31 | 32 | spec.add_runtime_dependency 'thor' 33 | spec.add_runtime_dependency 'pry' 34 | 35 | spec.add_development_dependency 'bundler' 36 | spec.add_development_dependency 'rspec' 37 | spec.add_development_dependency 'rake' 38 | spec.add_development_dependency 'simplecov' 39 | spec.add_development_dependency 'rubocop', '= 0.39.0' 40 | 41 | end 42 | -------------------------------------------------------------------------------- /lib/ilo-sdk.rb: -------------------------------------------------------------------------------- 1 | # (c) Copyright 2016 Hewlett Packard Enterprise Development LP 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software distributed 8 | # under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 9 | # CONDITIONS OF ANY KIND, either express or implied. See the License for the 10 | # specific language governing permissions and limitations under the License. 11 | 12 | require_relative 'ilo-sdk/version' 13 | require_relative 'ilo-sdk/client' 14 | require_relative 'ilo-sdk/exceptions' 15 | require_relative 'ilo-sdk/cli' 16 | 17 | # Module for interracting with the HPE iLO API 18 | module ILO_SDK 19 | ENV_VARS = %w(ILO_HOST ILO_USER ILO_PASSWORD ILO_SSL_ENABLED).freeze 20 | end 21 | -------------------------------------------------------------------------------- /lib/ilo-sdk/cli.rb: -------------------------------------------------------------------------------- 1 | # (c) Copyright 2016 Hewlett Packard Enterprise Development LP 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software distributed 8 | # under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 9 | # CONDITIONS OF ANY KIND, either express or implied. See the License for the specific 10 | # language governing permissions and limitations under the License. 11 | 12 | require 'thor' 13 | require 'json' 14 | require 'yaml' 15 | 16 | module ILO_SDK 17 | # cli for ilo-sdk 18 | class Cli < Thor 19 | # Runner class to enable testing 20 | class Runner 21 | def initialize(argv, stdin = STDIN, stdout = STDOUT, stderr = STDERR, kernel = Kernel) 22 | @argv = argv 23 | @stdin = stdin 24 | @stdout = stdout 25 | @stderr = stderr 26 | @kernel = kernel 27 | end 28 | 29 | def execute! 30 | exit_code = begin 31 | $stderr = @stderr 32 | $stdin = @stdin 33 | $stdout = @stdout 34 | 35 | ILO_SDK::Cli.start(@argv) 36 | 0 37 | rescue StandardError => e 38 | b = e.backtrace 39 | @stderr.puts("#{b.shift}: #{e.message} (#{e.class})") 40 | @stderr.puts(b.map { |s| "\tfrom #{s}" }.join("\n")) 41 | 1 42 | rescue SystemExit => e 43 | e.status 44 | end 45 | 46 | # Proxy our exit code back to the injected kernel. 47 | @kernel.exit(exit_code) 48 | end 49 | end 50 | 51 | class_option :ssl_verify, 52 | type: :boolean, 53 | desc: 'Enable/Disable SSL verification for requests. Can also use ENV[\'ILO_SSL_ENABLED\']', 54 | default: nil 55 | 56 | class_option :host, 57 | desc: 'Hostname or URL of iLO. Can also use ENV[\'ILO_HOST\']' 58 | 59 | class_option :user, 60 | desc: 'Username. Can also use ENV[\'ILO_USER\']', 61 | aliases: '-u' 62 | 63 | class_option :password, 64 | desc: 'Password. Can also use ENV[\'ILO_PASSWORD\']', 65 | aliases: '-p' 66 | 67 | class_option :log_level, 68 | desc: 'Log level to use', 69 | aliases: '-l', 70 | enum: %w(debug info warn error), 71 | default: 'warn' 72 | 73 | map ['-v', '--version'] => :version 74 | 75 | 76 | method_option :format, 77 | desc: 'Output format', 78 | aliases: '-f', 79 | enum: %w(json yaml human), 80 | default: 'human' 81 | desc 'env', 'Show environment variables for ilo-sdk for Ruby' 82 | def env 83 | data = {} 84 | ILO_SDK::ENV_VARS.each { |k| data[k] = ENV[k] } 85 | if @options['format'] == 'human' 86 | data.each do |key, value| 87 | value = "'#{value}'" if value && ! %w(true false).include?(value) 88 | printf "%-#{data.keys.max_by(&:length).length}s = %s\n", key, value || 'nil' 89 | end 90 | else 91 | output(parse_hash(data, true)) 92 | end 93 | end 94 | 95 | desc 'console', 'Open a Ruby console with a connection to iLO' 96 | def console 97 | client_setup({}, true, true) 98 | puts "Connected to #{@client.host}" 99 | puts "HINT: The @client object is available to you\n\n" 100 | rescue 101 | puts "WARNING: Couldn't connect to #{@options['host'] || ENV['ILO_HOST'] || 'nil (host not set)'}\n\n" 102 | ensure 103 | require 'pry' 104 | Pry.config.prompt = proc { '> ' } 105 | Pry.plugins['stack_explorer'] && Pry.plugins['stack_explorer'].disable! 106 | Pry.plugins['byebug'] && Pry.plugins['byebug'].disable! 107 | Pry.start(ILO_SDK::Console.new(@client)) 108 | end 109 | 110 | desc 'version', 'Print gem and iLO API versions' 111 | def version 112 | puts "Gem Version: #{ILO_SDK::VERSION}" 113 | client_setup({ 'log_level' => :error }, true) 114 | ver = @client.response_handler(@client.rest_get('/redfish/v1/'))['RedfishVersion'] 115 | puts "iLO Redfish API version: #{ver}" 116 | rescue StandardError, SystemExit 117 | puts 'iLO API version unknown' 118 | end 119 | 120 | desc 'login', 'Attempt loading an authenticated API endpoint' 121 | def login 122 | client_setup 123 | @client.response_handler(@client.rest_get('/redfish/v1/Sessions/')) 124 | puts 'Login Successful!' 125 | rescue StandardError => e 126 | fail_nice(e.message) 127 | end 128 | 129 | method_option :format, 130 | desc: 'Output format (for response)', 131 | aliases: '-f', 132 | enum: %w(json yaml raw), 133 | default: 'json' 134 | method_option :data, 135 | desc: 'Data to pass in the request body (in JSON format)', 136 | aliases: '-d' 137 | rest_examples = "\n ilo-ruby rest get redfish/v1/" 138 | rest_examples << "\n ilo-ruby rest patch redfish/v1/Systems/1/bios/Settings/" 139 | rest_examples << " -d '{\"ServiceName\":\"iLO Admin\",\"ServiceEmail\":\"admin@domain.com\"}'" 140 | rest_examples << "\n ilo-ruby rest post redfish/v1/Managers/1/LogServices/IEL/ -d '{\"Action\":\"ClearLog\"}'" 141 | desc 'rest METHOD URI', "Make REST call to the iLO API. Examples:#{rest_examples}" 142 | def rest(method, uri) 143 | client_setup('log_level' => :error) 144 | uri_copy = uri.dup 145 | uri_copy.prepend('/') unless uri_copy.start_with?('/') 146 | if @options['data'] 147 | begin 148 | data = { body: JSON.parse(@options['data']) } 149 | rescue JSON::ParserError => e 150 | fail_nice("Failed to parse data as JSON\n#{e.message}") 151 | end 152 | end 153 | data ||= {} 154 | response = @client.rest_api(method, uri_copy, data) 155 | if response.code.to_i.between?(200, 299) 156 | case @options['format'] 157 | when 'yaml' 158 | puts JSON.parse(response.body).to_yaml 159 | when 'json' 160 | puts JSON.pretty_generate(JSON.parse(response.body)) 161 | else # raw 162 | puts response.body 163 | end 164 | else 165 | fail_nice("Request failed: #{response.inspect}\nHeaders: #{response.to_hash}\nBody: #{response.body}") 166 | end 167 | rescue ILO_SDK::InvalidRequest => e 168 | fail_nice(e.message) 169 | end 170 | 171 | private 172 | 173 | def fail_nice(msg = nil) 174 | $stderr.puts "ERROR: #{msg}" if msg 175 | exit 1 176 | end 177 | 178 | def client_setup(client_params = {}, quiet = false, throw_errors = false) 179 | client_params['ssl_enabled'] = true if @options['ssl_verify'] == true 180 | client_params['ssl_enabled'] = false if @options['ssl_verify'] == false 181 | client_params['host'] ||= @options['host'] if @options['host'] 182 | client_params['user'] ||= @options['user'] if @options['user'] 183 | client_params['password'] ||= @options['password'] if @options['password'] 184 | client_params['log_level'] ||= @options['log_level'].to_sym if @options['log_level'] 185 | @client = ILO_SDK::Client.new(client_params) 186 | rescue StandardError => e 187 | raise e if throw_errors 188 | fail_nice if quiet 189 | fail_nice "Failed to login to iLO at '#{client_params['host'] || ENV['ILO_HOST']}'. Message: #{e}" 190 | end 191 | 192 | # Parse options hash from input. Handles chaining and keywords such as true/false & nil 193 | # Returns new hash with proper nesting and formatting 194 | def parse_hash(hash, convert_types = false) 195 | new_hash = {} 196 | hash.each do |k, v| 197 | if convert_types 198 | v = v.to_i if v && v.match(/^\d+$/) 199 | v = true if v == 'true' 200 | v = false if v == 'false' 201 | v = nil if v == 'nil' 202 | end 203 | if k =~ /\./ 204 | sub_hash = new_hash 205 | split = k.split('.') 206 | split.each do |sub_key| 207 | if sub_key == split.last 208 | sub_hash[sub_key] = v 209 | else 210 | sub_hash[sub_key] ||= {} 211 | sub_hash = sub_hash[sub_key] 212 | end 213 | end 214 | new_hash[split.first] ||= {} 215 | else 216 | new_hash[k] = v 217 | end 218 | end 219 | new_hash 220 | end 221 | 222 | # Print output in a given format. 223 | def output(data = {}, indent = 0) 224 | case @options['format'] 225 | when 'json' 226 | puts JSON.pretty_generate(data) 227 | when 'yaml' 228 | puts data.to_yaml 229 | else 230 | # rubocop:disable Metrics/BlockNesting 231 | if data.class == Hash 232 | data.each do |k, v| 233 | if v.class == Hash || v.class == Array 234 | puts "#{' ' * indent}#{k.nil? ? 'nil' : k}:" 235 | output(v, indent + 2) 236 | else 237 | puts "#{' ' * indent}#{k.nil? ? 'nil' : k}: #{v.nil? ? 'nil' : v}" 238 | end 239 | end 240 | elsif data.class == Array 241 | data.each do |d| 242 | if d.class == Hash || d.class == Array 243 | output(d, indent + 2) 244 | else 245 | puts "#{' ' * indent}#{d.nil? ? 'nil' : d}" 246 | end 247 | end 248 | puts "\nTotal: #{data.size}" if indent < 1 249 | else 250 | puts "#{' ' * indent}#{data.nil? ? 'nil' : data}" 251 | end 252 | # rubocop:enable Metrics/BlockNesting 253 | end 254 | end 255 | end 256 | 257 | # Console class 258 | class Console 259 | def initialize(client) 260 | @client = client 261 | end 262 | end 263 | end 264 | -------------------------------------------------------------------------------- /lib/ilo-sdk/client.rb: -------------------------------------------------------------------------------- 1 | # (C) Copyright 2016 Hewlett Packard Enterprise Development LP 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # You may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software distributed 8 | # under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 9 | # CONDITIONS OF ANY KIND, either express or implied. See the License for the 10 | # specific language governing permissions and limitations under the License. 11 | 12 | require 'logger' 13 | require_relative 'rest' 14 | # Load all helpers: 15 | Dir[File.join(File.dirname(__FILE__), '/helpers/*.rb')].each { |file| require file } 16 | 17 | module ILO_SDK 18 | # The client defines the connection to the iLO and handles communication with it 19 | class Client 20 | attr_accessor :host, :user, :password, :ssl_enabled, :disable_proxy, :logger, :log_level 21 | 22 | # Create a client object 23 | # @param [Hash] options the options to configure the client 24 | # @option options [String] :host (ENV['ILO_HOST']) URL, hostname, or IP address of the iLO 25 | # @option options [String] :user ('Administrator') Username to use for authentication with the iLO 26 | # @option options [String] :password Password to use for authentication with the iLO 27 | # @option options [Logger] :logger (Logger.new(STDOUT)) Logger object to use. 28 | # Must implement debug(String), info(String), warn(String), error(String), & level= 29 | # @option options [Symbol] :log_level (:info) Log level. Logger must define a constant with this name. ie Logger::INFO 30 | # @option options [Boolean] :ssl_enabled (true) Use ssl for requests? 31 | # @option options [Boolean] :disable_proxy (false) Disable usage of a proxy for requests? 32 | def initialize(options = {}) 33 | options = Hash[options.map { |k, v| [k.to_sym, v] }] # Convert string hash keys to symbols 34 | @logger = options[:logger] || Logger.new(STDOUT) 35 | [:debug, :info, :warn, :error, :level=].each { |m| raise "Logger must respond to #{m} method " unless @logger.respond_to?(m) } 36 | @log_level = options[:log_level] || :info 37 | @logger.level = @logger.class.const_get(@log_level.upcase) rescue @log_level 38 | @host = options[:host] || ENV['ILO_HOST'] 39 | raise InvalidClient, 'Must set the host option' unless @host 40 | @host = 'https://' + @host unless @host.start_with?('http://', 'https://') 41 | @ssl_enabled = true # Default 42 | if ENV.key?('ILO_SSL_ENABLED') 43 | @ssl_enabled = case ENV['ILO_SSL_ENABLED'] 44 | when 'true', '1' then true 45 | when 'false', '0' then false 46 | else ENV['ILO_SSL_ENABLED'] 47 | end 48 | end 49 | @ssl_enabled = options[:ssl_enabled] unless options[:ssl_enabled].nil? 50 | unless [true, false].include?(@ssl_enabled) 51 | raise InvalidClient, "ssl_enabled option must be true or false. Got '#{@ssl_enabled}'" 52 | end 53 | unless @ssl_enabled 54 | @logger.warn "SSL is disabled for all requests to #{@host}! We recommend you import the necessary certificates instead. of disabling SSL" 55 | end 56 | @disable_proxy = options[:disable_proxy] 57 | raise InvalidClient, 'disable_proxy option must be true, false, or nil' unless [true, false, nil].include?(@disable_proxy) 58 | @logger.warn 'User option not set. Using default (Administrator)' unless options[:user] || ENV['ILO_USER'] 59 | @user = options[:user] || ENV['ILO_USER'] || 'Administrator' 60 | @password = options[:password] || ENV['ILO_PASSWORD'] 61 | raise InvalidClient, 'Must set the password option' unless @password 62 | end 63 | 64 | include Rest 65 | 66 | # Include helper modules: 67 | include ManagerNetworkProtocolHelper 68 | include DateTimeHelper 69 | include ComputerDetailsHelper 70 | include SNMPServiceHelper 71 | include PowerHelper 72 | include AccountServiceHelper 73 | include LogEntryHelper 74 | include ManagerAccountHelper 75 | include SecureBootHelper 76 | include BiosHelper 77 | include BootSettingsHelper 78 | include FirmwareUpdateHelper 79 | include VirtualMediaHelper 80 | include ComputerSystemHelper 81 | include ChassisHelper 82 | include ServiceRootHelper 83 | include HttpsCertHelper 84 | include EthernetInterfaceHelper 85 | end 86 | end 87 | -------------------------------------------------------------------------------- /lib/ilo-sdk/exceptions.rb: -------------------------------------------------------------------------------- 1 | # (c) Copyright 2016 Hewlett Packard Enterprise Development LP 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # You may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software distributed 8 | # under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 9 | # CONDITIONS OF ANY KIND, either express or implied. See the License for the specific 10 | # language governing permissions and limitations under the License. 11 | 12 | # Contains all the custom Exception classes 13 | module ILO_SDK 14 | class InvalidClient < StandardError # Client configuration is invalid 15 | end 16 | 17 | class InvalidRequest < StandardError # Could not make request 18 | end 19 | 20 | class BadRequest < StandardError # 400 21 | end 22 | 23 | class Unauthorized < StandardError # 401 24 | end 25 | 26 | class NotFound < StandardError # 404 27 | end 28 | 29 | class RequestError < StandardError # Other bad response codes 30 | end 31 | end 32 | -------------------------------------------------------------------------------- /lib/ilo-sdk/helpers/account_service_helper.rb: -------------------------------------------------------------------------------- 1 | # (C) Copyright 2016 Hewlett Packard Enterprise Development LP 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # You may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software distributed 8 | # under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 9 | # CONDITIONS OF ANY KIND, either express or implied. See the License for the 10 | # specific language governing permissions and limitations under the License. 11 | 12 | module ILO_SDK 13 | # Contains helper methods for Account Service actions 14 | module AccountServiceHelper 15 | # Get the HREF for a user with a specific username 16 | # @param [String, Symbol] uri 17 | # @param [String, Symbol] username 18 | # @raise [RuntimeError] if the request failed 19 | # @return [String] userhref 20 | def userhref(uri, username) 21 | response = rest_get(uri) 22 | items = response_handler(response)['Items'] 23 | items.each do |it| 24 | return it['links']['self']['href'] if it['UserName'] == username 25 | end 26 | end 27 | 28 | # Get the users 29 | # @raise [RuntimeError] if the request failed 30 | # @return [String[]] users 31 | def get_users 32 | response = rest_get('/redfish/v1/AccountService/Accounts/') 33 | response_handler(response)['Items'].collect { |user| user['UserName'] } 34 | end 35 | 36 | # Create a user 37 | # @param [String, Symbol] username 38 | # @param [String, Symbol] password 39 | # @raise [RuntimeError] if the request failed 40 | # @return true 41 | def create_user(username, password) 42 | new_action = { 'UserName' => username, 'Password' => password, 'Oem' => { 'Hp' => { 'LoginName' => username } } } 43 | response = rest_post('/redfish/v1/AccountService/Accounts/', body: new_action) 44 | response_handler(response) 45 | true 46 | end 47 | 48 | # Change the password for a user 49 | # @param [String, Symbol] username 50 | # @param [String, Symbol] password 51 | # @raise [RuntimeError] if the request failed 52 | # @return true 53 | def change_password(username, password) 54 | new_action = { 'Password' => password } 55 | userhref = userhref('/redfish/v1/AccountService/Accounts/', username) 56 | response = rest_patch(userhref, body: new_action) 57 | response_handler(response) 58 | true 59 | end 60 | 61 | # Delete a specific user 62 | # @param [String, Symbol] username 63 | # @raise [RuntimeError] if the request failed 64 | # @return true 65 | def delete_user(username) 66 | userhref = userhref('/redfish/v1/AccountService/Accounts/', username) 67 | response = rest_delete(userhref) 68 | response_handler(response) 69 | true 70 | end 71 | end 72 | end 73 | -------------------------------------------------------------------------------- /lib/ilo-sdk/helpers/bios_helper.rb: -------------------------------------------------------------------------------- 1 | # (C) Copyright 2016 Hewlett Packard Enterprise Development LP 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # You may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software distributed 8 | # under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 9 | # CONDITIONS OF ANY KIND, either express or implied. See the License for the 10 | # specific language governing permissions and limitations under the License. 11 | 12 | module ILO_SDK 13 | # Contains helper methods for Bios actions 14 | module BiosHelper 15 | # Get all the BIOS settings 16 | # @param system_id [Integer, String] ID of the system 17 | # @raise [RuntimeError] if the request failed 18 | # @return [Hash] BIOS settings 19 | def get_bios_settings(system_id = 1) 20 | response_handler(rest_get("/redfish/v1/Systems/#{system_id}/bios/Settings/")) 21 | end 22 | 23 | # Set BIOS settings 24 | # @param options [Hash] Hash of options to set 25 | # @param system_id [Integer, String] ID of the system 26 | # @raise [RuntimeError] if the request failed 27 | # @return true 28 | def set_bios_settings(options, system_id = 1) 29 | r = response_handler(rest_patch("/redfish/v1/Systems/#{system_id}/bios/Settings/", body: options)) 30 | @logger.warn(r) if r['error'] 31 | true 32 | end 33 | 34 | # Get the bios base config 35 | # @raise [RuntimeError] if the request failed 36 | # @return [Fixnum] bios_baseconfig 37 | def get_bios_baseconfig 38 | response = rest_get('/redfish/v1/Systems/1/bios/Settings/') 39 | response_handler(response)['BaseConfig'] 40 | end 41 | 42 | # Revert the BIOS 43 | # @raise [RuntimeError] if the request failed 44 | # @return true 45 | def revert_bios 46 | new_action = { 'BaseConfig' => 'default' } 47 | response = rest_patch('/redfish/v1/systems/1/bios/Settings/', body: new_action) 48 | response_handler(response) 49 | true 50 | end 51 | 52 | # Get the UEFI shell start up 53 | # @raise [RuntimeError] if the request failed 54 | # @return [Hash] uefi_shell_startup 55 | def get_uefi_shell_startup 56 | response = rest_get('/redfish/v1/Systems/1/bios/Settings/') 57 | bios = response_handler(response) 58 | { 59 | 'UefiShellStartup' => bios['UefiShellStartup'], 60 | 'UefiShellStartupLocation' => bios['UefiShellStartupLocation'], 61 | 'UefiShellStartupUrl' => bios['UefiShellStartupUrl'] 62 | } 63 | end 64 | 65 | # Set the UEFI shell start up 66 | # @param uefi_shell_startup [String, Symbol] 67 | # @param uefi_shell_startup_location [String, Symbol] 68 | # @param uefi_shell_startup_url [String, Symbol] 69 | # @raise [RuntimeError] if the request failed 70 | # @return true 71 | def set_uefi_shell_startup(uefi_shell_startup, uefi_shell_startup_location, uefi_shell_startup_url) 72 | new_action = { 73 | 'UefiShellStartup' => uefi_shell_startup, 74 | 'UefiShellStartupLocation' => uefi_shell_startup_location, 75 | 'UefiShellStartupUrl' => uefi_shell_startup_url 76 | } 77 | response = rest_patch('/redfish/v1/Systems/1/bios/Settings/', body: new_action) 78 | response_handler(response) 79 | true 80 | end 81 | 82 | # Get the BIOS DHCP 83 | # @raise [RuntimeError] if the request failed 84 | # @return [String] bios_dhcp 85 | def get_bios_dhcp 86 | response = rest_get('/redfish/v1/Systems/1/bios/Settings/') 87 | bios = response_handler(response) 88 | { 89 | 'Dhcpv4' => bios['Dhcpv4'], 90 | 'Ipv4Address' => bios['Ipv4Address'], 91 | 'Ipv4Gateway' => bios['Ipv4Gateway'], 92 | 'Ipv4PrimaryDNS' => bios['Ipv4PrimaryDNS'], 93 | 'Ipv4SecondaryDNS' => bios['Ipv4SecondaryDNS'], 94 | 'Ipv4SubnetMask' => bios['Ipv4SubnetMask'] 95 | } 96 | end 97 | 98 | # Set the BIOS DHCP 99 | # @param dhcpv4 [String, Symbol] 100 | # @param ipv4_address [String, Symbol] 101 | # @param ipv4_gateway [String, Symbol] 102 | # @param ipv4_primary_dns [String, Symbol] 103 | # @param ipv4_secondary_dns [String, Symbol] 104 | # @param ipv4_subnet_mask [String, Symbol] 105 | # @raise [RuntimeError] if the request failed 106 | # @return true 107 | def set_bios_dhcp(dhcpv4, ipv4_address = '', ipv4_gateway = '', ipv4_primary_dns = '', ipv4_secondary_dns = '', ipv4_subnet_mask = '') 108 | new_action = { 109 | 'Dhcpv4' => dhcpv4, 110 | 'Ipv4Address' => ipv4_address, 111 | 'Ipv4Gateway' => ipv4_gateway, 112 | 'Ipv4PrimaryDNS' => ipv4_primary_dns, 113 | 'Ipv4SecondaryDNS' => ipv4_secondary_dns, 114 | 'Ipv4SubnetMask' => ipv4_subnet_mask 115 | } 116 | response = rest_patch('/redfish/v1/Systems/1/bios/Settings/', body: new_action) 117 | response_handler(response) 118 | true 119 | end 120 | 121 | # Get the URL boot file 122 | # @raise [RuntimeError] if the request failed 123 | # @return [String] url_boot_file 124 | def get_url_boot_file 125 | response = rest_get('/redfish/v1/Systems/1/bios/Settings/') 126 | response_handler(response)['UrlBootFile'] 127 | end 128 | 129 | # Set the URL boot file 130 | # @param url_boot_file [String, Symbol] 131 | # @raise [RuntimeError] if the request failed 132 | # @return true 133 | def set_url_boot_file(url_boot_file) 134 | new_action = { 'UrlBootFile' => url_boot_file } 135 | response = rest_patch('/redfish/v1/Systems/1/bios/Settings/', body: new_action) 136 | response_handler(response) 137 | true 138 | end 139 | 140 | # Get the BIOS service 141 | # @raise [RuntimeError] if the request failed 142 | # @return [String] bios_service 143 | def get_bios_service 144 | response = rest_get('/redfish/v1/Systems/1/bios/Settings/') 145 | bios = response_handler(response) 146 | { 147 | 'ServiceName' => bios['ServiceName'], 148 | 'ServiceEmail' => bios['ServiceEmail'] 149 | } 150 | end 151 | 152 | # Set the BIOS service 153 | # @param name [String, Symbol] 154 | # @param email [String, Symbol] 155 | # @raise [RuntimeError] if the request failed 156 | # @return true 157 | def set_bios_service(name, email) 158 | new_action = { 159 | 'ServiceName' => name, 160 | 'ServiceEmail' => email 161 | } 162 | response = rest_patch('/redfish/v1/Systems/1/bios/Settings/', body: new_action) 163 | response_handler(response) 164 | true 165 | end 166 | end 167 | end 168 | -------------------------------------------------------------------------------- /lib/ilo-sdk/helpers/boot_settings_helper.rb: -------------------------------------------------------------------------------- 1 | # (C) Copyright 2016 Hewlett Packard Enterprise Development LP 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # You may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software distributed 8 | # under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 9 | # CONDITIONS OF ANY KIND, either express or implied. See the License for the 10 | # specific language governing permissions and limitations under the License. 11 | 12 | module ILO_SDK 13 | # Contains helper methods for Boot Settings actions 14 | module BootSettingsHelper 15 | # Get the boot base config 16 | # @raise [RuntimeError] if the request failed 17 | # @return [Fixnum] boot_baseconfig 18 | def get_boot_baseconfig 19 | response = rest_get('/redfish/v1/Systems/1/bios/Boot/Settings/') 20 | response_handler(response)['BaseConfig'] 21 | end 22 | 23 | # Revert the boot 24 | # @raise [RuntimeError] if the request failed 25 | # @return true 26 | def revert_boot 27 | new_action = { 'BaseConfig' => 'default' } 28 | response = rest_patch('/redfish/v1/systems/1/bios/Boot/Settings/', body: new_action) 29 | response_handler(response) 30 | true 31 | end 32 | 33 | # Get the boot order 34 | # @raise [RuntimeError] if the request failed 35 | # @return [Fixnum] boot_order 36 | def get_boot_order 37 | response = rest_get('/redfish/v1/systems/1/bios/Boot/Settings/') 38 | response_handler(response)['PersistentBootConfigOrder'] 39 | end 40 | 41 | # Set the boot order 42 | # @param [Fixnum] boot_order 43 | # @raise [RuntimeError] if the request failed 44 | # @return true 45 | def set_boot_order(boot_order) 46 | new_action = { 'PersistentBootConfigOrder' => boot_order } 47 | response = rest_patch('/redfish/v1/systems/1/bios/Boot/Settings/', body: new_action) 48 | response_handler(response) 49 | true 50 | end 51 | 52 | # Get the temporary boot order 53 | # @raise [RuntimeError] if the request failed 54 | # @return [Fixnum] temporary_boot_order 55 | def get_temporary_boot_order 56 | response = rest_get('/redfish/v1/Systems/1/') 57 | response_handler(response)['Boot']['BootSourceOverrideTarget'] 58 | end 59 | 60 | # Set the temporary boot order 61 | # @param [Fixnum] boot_target 62 | # @raise [RuntimeError] if the request failed 63 | # @return true 64 | def set_temporary_boot_order(boot_target) 65 | response = rest_get('/redfish/v1/Systems/1/') 66 | boottargets = response_handler(response)['Boot']['BootSourceOverrideSupported'] 67 | unless boottargets.include? boot_target 68 | raise "BootSourceOverrideTarget value - #{boot_target} is not supported. Valid values are: #{boottargets}" 69 | end 70 | new_action = { 'Boot' => { 'BootSourceOverrideTarget' => boot_target } } 71 | response = rest_patch('/redfish/v1/Systems/1/', body: new_action) 72 | response_handler(response) 73 | true 74 | end 75 | end 76 | end 77 | -------------------------------------------------------------------------------- /lib/ilo-sdk/helpers/chassis_helper.rb: -------------------------------------------------------------------------------- 1 | # (C) Copyright 2016 Hewlett Packard Enterprise Development LP 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # You may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software distributed 8 | # under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 9 | # CONDITIONS OF ANY KIND, either express or implied. See the License for the 10 | # specific language governing permissions and limitations under the License. 11 | 12 | module ILO_SDK 13 | # Contains helper methods for Chassis actions 14 | module ChassisHelper 15 | # Get the power metrics 16 | # @raise [RuntimeError] if the request failed 17 | # @return [Hash] power_metrics 18 | def get_power_metrics 19 | chassis = rest_get('/redfish/v1/Chassis/') 20 | chassis_uri = response_handler(chassis)['links']['Member'][0]['href'] 21 | power_metrics_uri = response_handler(rest_get(chassis_uri))['links']['PowerMetrics']['href'] 22 | response = rest_get(power_metrics_uri) 23 | metrics = response_handler(response) 24 | power_supplies = [] 25 | metrics['PowerSupplies'].each do |ps| 26 | power_supply = { 27 | 'LineInputVoltage' => ps['LineInputVoltage'], 28 | 'LineInputVoltageType' => ps['LineInputVoltageType'], 29 | 'PowerCapacityWatts' => ps['PowerCapacityWatts'], 30 | 'PowerSupplyType' => ps['PowerSupplyType'], 31 | 'Health' => ps['Status']['Health'], 32 | 'State' => ps['Status']['State'] 33 | } 34 | power_supplies.push(power_supply) 35 | end 36 | { 37 | @host => { 38 | 'PowerCapacityWatts' => metrics['PowerCapacityWatts'], 39 | 'PowerConsumedWatts' => metrics['PowerConsumedWatts'], 40 | 'PowerSupplies' => power_supplies 41 | } 42 | } 43 | end 44 | 45 | # Get the thermal metrics 46 | # @raise [RuntimeError] if the request failed 47 | # @return [Hash] thermal_metrics 48 | def get_thermal_metrics 49 | chassis = rest_get('/redfish/v1/Chassis/') 50 | chassis_uri = response_handler(chassis)['links']['Member'][0]['href'] 51 | thermal_metrics_uri = response_handler(rest_get(chassis_uri))['links']['ThermalMetrics']['href'] 52 | response = rest_get(thermal_metrics_uri) 53 | temperatures = response_handler(response)['Temperatures'] 54 | temp_details = [] 55 | temperatures.each do |temp| 56 | temp_detail = { 57 | 'PhysicalContext' => temp['PhysicalContext'], 58 | 'Name' => temp['Name'], 59 | 'CurrentReading' => temp['ReadingCelsius'], 60 | 'CriticalThreshold' => temp['LowerThresholdCritical'], 61 | 'Health' => temp['Status']['Health'], 62 | 'State' => temp['Status']['State'] 63 | } 64 | temp_details.push(temp_detail) 65 | end 66 | { @host => temp_details } 67 | end 68 | end 69 | end 70 | -------------------------------------------------------------------------------- /lib/ilo-sdk/helpers/computer_details_helper.rb: -------------------------------------------------------------------------------- 1 | # (C) Copyright 2016 Hewlett Packard Enterprise Development LP 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # You may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software distributed 8 | # under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 9 | # CONDITIONS OF ANY KIND, either express or implied. See the License for the 10 | # specific language governing permissions and limitations under the License. 11 | 12 | module ILO_SDK 13 | # Contains helper methods for computer details actions 14 | module ComputerDetailsHelper 15 | # Get all of the computer details 16 | # @raise [RuntimeError] if the request failed 17 | # @return [Hash] computer_details 18 | def get_computer_details 19 | general_computer_details = get_general_computer_details 20 | computer_network_details = get_computer_network_details 21 | array_controller_details = get_array_controller_details 22 | general_computer_details.merge(computer_network_details).merge(array_controller_details) 23 | end 24 | 25 | # Get the general computer details 26 | # @raise [RuntimeError] if the request failed 27 | # @return [Fixnum] general_computer_details 28 | def get_general_computer_details 29 | response = rest_get('/redfish/v1/Systems/1/') 30 | details = response_handler(response) 31 | { 32 | 'GeneralDetails' => { 33 | 'manufacturer' => details['Manufacturer'], 34 | 'model' => details['Model'], 35 | 'AssetTag' => details['AssetTag'], 36 | 'bios_version' => details['Bios']['Current']['VersionString'], 37 | 'memory' => details['Memory']['TotalSystemMemoryGB'].to_s + ' GB', 38 | 'processors' => details['Processors']['Count'].to_s + ' x ' + details['Processors']['ProcessorFamily'].to_s 39 | } 40 | } 41 | end 42 | 43 | # Get the computer network details 44 | # @raise [RuntimeError] if the request failed 45 | # @return [Hash] computer_network_details 46 | def get_computer_network_details 47 | network_adapters = [] 48 | response = rest_get('/redfish/v1/Systems/1/NetworkAdapters/') 49 | networks = response_handler(response)['links']['Member'] 50 | networks.each do |network| 51 | response = rest_get(network['href']) 52 | detail = response_handler(response) 53 | physical_ports = [] 54 | detail['PhysicalPorts'].each do |port| 55 | n = { 56 | 'Name' => port['Name'], 57 | 'StructuredName' => port['Oem']['Hp']['StructuredName'], 58 | 'MacAddress' => port['MacAddress'], 59 | 'State' => port['Status']['State'] 60 | } 61 | physical_ports.push(n) 62 | end 63 | nets = { 64 | 'Name' => detail['Name'], 65 | 'StructuredName' => detail['StructuredName'], 66 | 'PartNumber' => detail['PartNumber'], 67 | 'State' => detail['Status']['State'], 68 | 'Health' => detail['Status']['Health'], 69 | 'PhysicalPorts' => physical_ports 70 | } 71 | network_adapters.push(nets) 72 | end 73 | { 74 | 'NetworkAdapters' => network_adapters 75 | } 76 | end 77 | 78 | # Get the array controller details 79 | # @raise [RuntimeError] if the request failed 80 | # @return [Hash] array_controller_details 81 | def get_array_controller_details 82 | response = rest_get('/redfish/v1/Systems/1/SmartStorage/') 83 | storages = response_handler(response) 84 | array_controllers = [] 85 | response = rest_get(storages['links']['ArrayControllers']['href']) 86 | array_ctrls = response_handler(response) 87 | if array_ctrls['links'].key? 'Member' 88 | array_ctrls['links']['Member'].each do |array_controller| 89 | response = rest_get(array_controller['href']) 90 | controller = response_handler(response) 91 | storage_enclosures = [] 92 | response = rest_get(controller['links']['StorageEnclosures']['href']) 93 | response_handler(response)['links']['Member'].each do |enclosure| 94 | response = rest_get(enclosure['href']) 95 | enclsr = response_handler(response) 96 | enc = { 97 | 'Model' => enclsr['Model'], 98 | 'SerialNumber' => enclsr['SerialNumber'], 99 | 'DriveBayCount' => enclsr['DriveBayCount'], 100 | 'State' => enclsr['Status']['State'], 101 | 'Health' => enclsr['Status']['Health'], 102 | 'Location' => enclsr['Location'].to_s + ' (' + enclsr['LocationFormat'].to_s + ')', 103 | 'FirmwareVersion' => enclsr['FirmwareVersion']['Current']['VersionString'] 104 | } 105 | storage_enclosures.push(enc) 106 | end 107 | 108 | logical_drives = [] 109 | response = rest_get(controller['links']['LogicalDrives']['href']) 110 | response_handler(response)['links']['Member'].each do |logicaldrive| 111 | response = rest_get(logicaldrive['href']) 112 | lds = response_handler(response) 113 | data_drives = [] 114 | response = rest_get(lds['links']['DataDrives']['href']) 115 | response_handler(response)['links']['Member'].each do |datadrives| 116 | response = rest_get(datadrives['href']) 117 | disk_drive = response_handler(response) 118 | dd = { 119 | 'Model' => disk_drive['Model'], 120 | 'Name' => disk_drive['Name'], 121 | 'RotationalSpeedRpm' => disk_drive['RotationalSpeedRpm'], 122 | 'SerialNumber' => disk_drive['SerialNumber'], 123 | 'State' => disk_drive['Status']['State'], 124 | 'Health' => disk_drive['Status']['Health'], 125 | 'CapacityMiB' => disk_drive['CapacityMiB'], 126 | 'CurrentTemperatureCelsius' => disk_drive['CurrentTemperatureCelsius'] 127 | } 128 | data_drives.push(dd) 129 | end 130 | ld = { 131 | 'Size' => lds['CapacityMiB'], 132 | 'Raid' => lds['Raid'], 133 | 'Status' => lds['Status']['State'], 134 | 'Health' => lds['Status']['Health'], 135 | 'DataDrives' => data_drives 136 | } 137 | logical_drives.push(ld) 138 | end 139 | ac = { 140 | 'Model' => controller['Model'], 141 | 'SerialNumber' => controller['SerialNumber'], 142 | 'State' => controller['Status']['State'], 143 | 'Health' => controller['Status']['Health'], 144 | 'Location' => controller['Location'], 145 | 'FirmWareVersion' => controller['FirmwareVersion']['Current']['VersionString'], 146 | 'LogicalDrives' => logical_drives, 147 | 'Enclosures' => storage_enclosures 148 | } 149 | array_controllers.push(ac) 150 | end 151 | end 152 | { 153 | 'HPSmartStorage' => { 154 | 'Health' => storages['Status']['Health'], 155 | 'ArrayControllers' => array_controllers 156 | } 157 | } 158 | end 159 | end 160 | end 161 | -------------------------------------------------------------------------------- /lib/ilo-sdk/helpers/computer_system_helper.rb: -------------------------------------------------------------------------------- 1 | # (c) Copyright 2016 Hewlett Packard Enterprise Development LP 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software distributed 8 | # under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 9 | # CONDITIONS OF ANY KIND, either express or implied. See the License for the 10 | # specific language governing permissions and limitations under the License. 11 | 12 | module ILO_SDK 13 | # Contains helper methods for Computer System actions 14 | module ComputerSystemHelper 15 | # Get the computer system settings 16 | # @param system_id [Integer, String] ID of the system 17 | # @raise [RuntimeError] if the request failed 18 | # @return [Hash] Computer system settings 19 | def get_system_settings(system_id = 1) 20 | response_handler(rest_get("/redfish/v1/Systems/#{system_id}/")) 21 | end 22 | 23 | # Set computer system settings 24 | # @param options [Hash] Hash of options to set 25 | # @param system_id [Integer, String] ID of the system 26 | # @raise [RuntimeError] if the request failed 27 | # @return true 28 | def set_system_settings(options, system_id = 1) 29 | response_handler(rest_patch("/redfish/v1/Systems/#{system_id}/", body: options)) 30 | true 31 | end 32 | 33 | # Get the Asset Tag 34 | # @deprecated Use {#get_system_settings} instead 35 | # @raise [RuntimeError] if the request failed 36 | # @return [String] asset_tag 37 | def get_asset_tag 38 | @logger.warn '[Deprecated] `get_asset_tag` is deprecated. Please use `get_system_settings[\'AssetTag\']` instead.' 39 | response = rest_get('/redfish/v1/Systems/1/') 40 | response_handler(response)['AssetTag'] 41 | end 42 | 43 | # Set the Asset Tag 44 | # @deprecated Use {#set_system_settings} instead 45 | # @param asset_tag [String, Symbol] 46 | # @raise [RuntimeError] if the request failed 47 | # @return true 48 | def set_asset_tag(asset_tag) 49 | @logger.warn '[Deprecated] `set_asset_tag` is deprecated. Please use `set_system_settings(AssetTag: )` instead.' 50 | new_action = { 'AssetTag' => asset_tag } 51 | response = rest_patch('/redfish/v1/Systems/1/', body: new_action) 52 | response_handler(response) 53 | true 54 | end 55 | 56 | # Get the UID indicator LED state 57 | # @deprecated Use {#get_system_settings} instead 58 | # @raise [RuntimeError] if the request failed 59 | # @return [String] indicator_led 60 | def get_indicator_led 61 | @logger.warn '[Deprecated] `get_indicator_led` is deprecated. Please use `get_system_settings[\'IndicatorLED\']` instead.' 62 | response = rest_get('/redfish/v1/Systems/1/') 63 | response_handler(response)['IndicatorLED'] 64 | end 65 | 66 | # Set the UID indicator LED 67 | # @deprecated Use {#set_system_settings} instead 68 | # @param state [String, Symbol] 69 | # @raise [RuntimeError] if the request failed 70 | # @return true 71 | def set_indicator_led(state) 72 | @logger.warn '[Deprecated] `set_indicator_led` is deprecated. Please use `set_system_settings(IndicatorLED: )` instead.' 73 | new_action = { 'IndicatorLED' => state } 74 | response = rest_patch('/redfish/v1/Systems/1/', body: new_action) 75 | response_handler(response) 76 | true 77 | end 78 | end 79 | end 80 | -------------------------------------------------------------------------------- /lib/ilo-sdk/helpers/date_time_helper.rb: -------------------------------------------------------------------------------- 1 | # (C) Copyright 2016 Hewlett Packard Enterprise Development LP 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # You may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software distributed 8 | # under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 9 | # CONDITIONS OF ANY KIND, either express or implied. See the License for the 10 | # specific language governing permissions and limitations under the License. 11 | 12 | module ILO_SDK 13 | # Contains helper methods for Date and Time actions 14 | module DateTimeHelper 15 | # Get the Time Zone 16 | # @raise [RuntimeError] if the request failed 17 | # @return [String] time_zone 18 | def get_time_zone 19 | response = rest_get('/redfish/v1/Managers/1/DateTime/') 20 | response_handler(response)['TimeZone']['Name'] 21 | end 22 | 23 | # Set the Time Zone 24 | # @param [Fixnum] time_zone 25 | # @raise [RuntimeError] if the request failed 26 | # @return true 27 | def set_time_zone(time_zone) 28 | time_response = rest_get('/redfish/v1/Managers/1/DateTime/') 29 | new_time_zone = response_handler(time_response)['TimeZoneList'].select { |timezone| timezone['Name'] == time_zone } 30 | new_action = { 'TimeZone' => { 'Index' => new_time_zone[0]['Index'] } } 31 | response = rest_patch('/redfish/v1/Managers/1/DateTime/', body: new_action) 32 | response_handler(response) 33 | true 34 | end 35 | 36 | # Get whether or not ntp servers are being used 37 | # @raise [RuntimeError] if the request failed 38 | # @return [TrueClass, FalseClass] use_ntp 39 | def get_ntp 40 | response = rest_get('/redfish/v1/Managers/1/EthernetInterfaces/1/') 41 | response_handler(response)['Oem']['Hp']['DHCPv4']['UseNTPServers'] 42 | end 43 | 44 | # Set whether or not ntp servers are being used 45 | # @param [TrueClass, FalseClass] use_ntp 46 | # @raise [RuntimeError] if the request failed 47 | # @return true 48 | def set_ntp(use_ntp) 49 | new_action = { 'Oem' => { 'Hp' => { 'DHCPv4' => { 'UseNTPServers' => use_ntp } } } } 50 | response = rest_patch('/redfish/v1/Managers/1/EthernetInterfaces/1/', body: new_action) 51 | response_handler(response) 52 | true 53 | end 54 | 55 | # Get the NTP Servers 56 | # @raise [RuntimeError] if the request failed 57 | # @return [Array] ntp_servers 58 | def get_ntp_servers 59 | response = rest_get('/redfish/v1/Managers/1/DateTime/') 60 | response_handler(response)['StaticNTPServers'] 61 | end 62 | 63 | # Set the NTP Servers 64 | # @param [Fixnum] ntp_servers 65 | # @raise [RuntimeError] if the request failed 66 | # @return true 67 | def set_ntp_servers(ntp_servers) 68 | new_action = { 'StaticNTPServers' => ntp_servers } 69 | response = rest_patch('/redfish/v1/Managers/1/DateTime/', body: new_action) 70 | response_handler(response) 71 | true 72 | end 73 | end 74 | end 75 | -------------------------------------------------------------------------------- /lib/ilo-sdk/helpers/ethernet_interface_helper.rb: -------------------------------------------------------------------------------- 1 | # (C) Copyright 2016 Hewlett Packard Enterprise Development LP 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # You may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software distributed 8 | # under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 9 | # CONDITIONS OF ANY KIND, either express or implied. See the License for the 10 | # specific language governing permissions and limitations under the License. 11 | 12 | module ILO_SDK 13 | # Contains helper methods for EthernetInterface IPv4 actions 14 | module EthernetInterfaceHelper 15 | # Get all the Ethernet Interface settings 16 | # @param manager_id [Integer, String] ID of the Manager 17 | # @param ethernet_interface [Integer, String] ID of the EthernetInterface 18 | # @raise [RuntimeError] if the request failed 19 | # @return [Hash] EthernetInterface settings 20 | def get_ilo_ethernet_interface(manager_id: 1, ethernet_interface: 1) 21 | response_handler(rest_get("/redfish/v1/Managers/#{manager_id}/EthernetInterfaces/#{ethernet_interface}/")) 22 | end 23 | 24 | # Set EthernetInterface to obtain IPv4 settings from DHCP 25 | # @param manager_id [Integer, String] ID of the Manager 26 | # @param ethernet_interface [Integer, String] ID of the EthernetInterface 27 | # @raise [RuntimeError] if the request failed 28 | # @return true 29 | def set_ilo_ipv4_dhcp(manager_id: 1, ethernet_interface: 1) 30 | new_action = { 31 | 'Oem' => { 32 | 'Hp' => { 33 | 'DHCPv4' => { 34 | 'Enabled' => true, 35 | 'UseDNSServers' => true, 36 | 'UseDomainName' => true, 37 | 'UseGateway' => true, 38 | 'UseNTPServers' => true, 39 | 'UseStaticRoutes' => true, 40 | 'UseWINSServers' => true 41 | } 42 | } 43 | } 44 | } 45 | response = rest_patch("/redfish/v1/Managers/#{manager_id}/EthernetInterfaces/#{ethernet_interface}/", body: new_action) 46 | response_handler(response) 47 | true 48 | end 49 | 50 | # Set EthernetInterface to static IPv4 address 51 | # @param ip [String] IPv4 address 52 | # @param netmask [String] IPv4 subnet mask 53 | # @param gateway [String] IPv4 default gateway 54 | # @param manager_id [Integer, String] ID of the Manager 55 | # @param ethernet_interface [Integer, String] ID of the EthernetInterface 56 | # @raise [RuntimeError] if the request failed 57 | # @return true 58 | def set_ilo_ipv4_static(ip:, netmask:, gateway: '0.0.0.0', manager_id: 1, ethernet_interface: 1) 59 | new_action = { 60 | 'Oem' => { 'Hp' => { 'DHCPv4' => { 'Enabled' => false } } }, 61 | 'IPv4Addresses' => [ 62 | 'Address' => ip, 'SubnetMask' => netmask, 'Gateway' => gateway 63 | ] 64 | } 65 | response = rest_patch("/redfish/v1/Managers/#{manager_id}/EthernetInterfaces/#{ethernet_interface}/", body: new_action) 66 | response_handler(response) 67 | true 68 | end 69 | 70 | # Set EthernetInterface DNS servers 71 | # @param dns_servers [Array] list of DNS servers 72 | # @param manager_id [Integer, String] ID of the Manager 73 | # @param ethernet_interface [Integer, String] ID of the EthernetInterface 74 | # @raise [RuntimeError] if the request failed 75 | # @return true 76 | def set_ilo_ipv4_dns_servers(dns_servers:, manager_id: 1, ethernet_interface: 1) 77 | new_action = { 78 | 'Oem' => { 79 | 'Hp' => { 80 | 'DHCPv4' => { 'UseDNSServers' => false }, 81 | 'IPv4' => { 'DNSServers' => dns_servers } 82 | } 83 | } 84 | } 85 | response = rest_patch("/redfish/v1/Managers/#{manager_id}/EthernetInterfaces/#{ethernet_interface}/", body: new_action) 86 | response_handler(response) 87 | true 88 | end 89 | 90 | # Set iLO hostname and domain name 91 | # @param hostname [String] iLO hostname 92 | # @param domain_name [String] iLO domain name 93 | # @param manager_id [Integer, String] ID of the Manager 94 | # @param ethernet_interface [Integer, String] ID of the EthernetInterface 95 | # @raise [RuntimeError] if the request failed 96 | # @return true 97 | def set_ilo_hostname(hostname:, domain_name: nil, manager_id: 1, ethernet_interface: 1) 98 | new_action = { 'Oem' => { 'Hp' => { 'HostName' => hostname } } } 99 | new_action['Oem']['Hp'].merge!('DHCPv4' => {}, 'DHCPv6' => {}) if domain_name 100 | new_action['Oem']['Hp']['DHCPv4']['UseDomainName'] = false if domain_name 101 | new_action['Oem']['Hp']['DHCPv6']['UseDomainName'] = false if domain_name 102 | new_action['Oem']['Hp']['DomainName'] = domain_name if domain_name 103 | response = rest_patch("/redfish/v1/Managers/#{manager_id}/EthernetInterfaces/#{ethernet_interface}/", body: new_action) 104 | response_handler(response) 105 | true 106 | end 107 | end 108 | end 109 | -------------------------------------------------------------------------------- /lib/ilo-sdk/helpers/firmware_update.rb: -------------------------------------------------------------------------------- 1 | # (C) Copyright 2016 Hewlett Packard Enterprise Development LP 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # You may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software distributed 8 | # under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 9 | # CONDITIONS OF ANY KIND, either express or implied. See the License for the 10 | # specific language governing permissions and limitations under the License. 11 | 12 | module ILO_SDK 13 | # Contains helper methods for Firmware Update actions 14 | module FirmwareUpdateHelper 15 | # Get the Firmware Version 16 | # @raise [RuntimeError] if the request failed 17 | # @return [String] fw_version 18 | def get_fw_version 19 | response = rest_get('/redfish/v1/Systems/1/FirmWareInventory/') 20 | response_handler(response)['Current']['SystemBMC'][0]['VersionString'] 21 | end 22 | 23 | # Set the Firmware Upgrade 24 | # @param [String, Symbol] uri 25 | # @raise [RuntimeError] if the request failed 26 | # @return true 27 | def set_fw_upgrade(uri, tpm_override_flag = true) 28 | new_action = { 'Action' => 'InstallFromURI', 'FirmwareURI' => uri, 'TPMOverrideFlag' => tpm_override_flag } 29 | response = rest_post('/redfish/v1/Managers/1/UpdateService/', body: new_action) 30 | response_handler(response) 31 | true 32 | end 33 | end 34 | end 35 | -------------------------------------------------------------------------------- /lib/ilo-sdk/helpers/https_cert_helper.rb: -------------------------------------------------------------------------------- 1 | # (C) Copyright 2016 Hewlett Packard Enterprise Development LP 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # You may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software distributed 8 | # under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 9 | # CONDITIONS OF ANY KIND, either express or implied. See the License for the 10 | # specific language governing permissions and limitations under the License. 11 | 12 | module ILO_SDK 13 | # Contains helper methods for HTTPS Certificates 14 | module HttpsCertHelper 15 | # Get the SSL Certificate 16 | # @raise [RuntimeError] if the request failed 17 | # @return [OpenSSL::X509::Certificate] x509_certificate 18 | # rubocop:disable Style/SymbolProc 19 | def get_certificate 20 | uri = URI.parse(URI.escape(@host)) 21 | options = { use_ssl: true, verify_mode: OpenSSL::SSL::VERIFY_NONE } 22 | Net::HTTP.start(uri.host, uri.port, options) do |http| 23 | http.peer_cert 24 | end 25 | end 26 | # rubocop:enable Style/SymbolProc 27 | 28 | # Import the x509 certificate 29 | # @param [String] certificate 30 | # @raise [RuntimeError] if the request failed 31 | # @return true 32 | def import_certificate(certificate) 33 | new_action = { 34 | 'Action' => 'ImportCertificate', 35 | 'Certificate' => certificate 36 | } 37 | response = rest_post('/redfish/v1/Managers/1/SecurityService/HttpsCert/', body: new_action) 38 | response_handler(response) 39 | true 40 | end 41 | 42 | # Generate a Certificate Signing Request 43 | # @param [String] country 44 | # @param [String] state 45 | # @param [String] city 46 | # @param [String] orgName 47 | # @param [String] orgUnit 48 | # @param [String] commonName 49 | # @raise [RuntimeError] if the request failed 50 | # @return true 51 | def generate_csr(country, state, city, org_name, org_unit, common_name) 52 | new_action = { 53 | 'Action' => 'GenerateCSR', 54 | 'Country' => country, 55 | 'State' => state, 56 | 'City' => city, 57 | 'OrgName' => org_name, 58 | 'OrgUnit' => org_unit, 59 | 'CommonName' => common_name 60 | } 61 | response = rest_post('/redfish/v1/Managers/1/SecurityService/HttpsCert/', body: new_action) 62 | response_handler(response) 63 | true 64 | end 65 | 66 | # Get the Certificate Signing Request 67 | # @raise [RuntimeError] if the request failed 68 | # @return [String] certificate_signing_request 69 | def get_csr 70 | response = rest_get('/redfish/v1/Managers/1/SecurityService/HttpsCert/') 71 | response_handler(response)['CertificateSigningRequest'] 72 | end 73 | end 74 | end 75 | -------------------------------------------------------------------------------- /lib/ilo-sdk/helpers/log_entry_helper.rb: -------------------------------------------------------------------------------- 1 | # (c) Copyright 2016 Hewlett Packard Enterprise Development LP 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software distributed 8 | # under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 9 | # CONDITIONS OF ANY KIND, either express or implied. See the License for the 10 | # specific language governing permissions and limitations under the License. 11 | 12 | require 'time' 13 | 14 | module ILO_SDK 15 | # Contains helper methods for Log Entry actions 16 | module LogEntryHelper 17 | # Get the URI for the specified log type 18 | # @param [String, Symbol] log_type 19 | # @raise [RuntimeError] if type is invalid 20 | # @return [String] URI of log service 21 | def uri_for_log_type(log_type, id = 1) 22 | resource = case log_type.to_s.upcase 23 | when 'IEL' then 'Managers' 24 | when 'IML' then 'Systems' 25 | else raise "Invalid log_type '#{log_type}'. Valid options are IEL and IML" 26 | end 27 | "/redfish/v1/#{resource}/#{id}/LogServices/#{log_type.upcase}/" 28 | end 29 | 30 | # Clear the specified logs 31 | # @param [String, Symbol] log_type 32 | # @raise [RuntimeError] if the request failed 33 | # @return true 34 | def clear_logs(log_type) 35 | new_action = { 'Action' => 'ClearLog' } 36 | response = rest_post(uri_for_log_type(log_type), body: new_action) 37 | response_handler(response) 38 | true 39 | end 40 | 41 | # Check to see if the specified logs are empty 42 | # @param [String, Symbol] log_type 43 | # @raise [RuntimeError] if the request failed 44 | # @return [TrueClass, FalseClass] logs_empty 45 | def logs_empty?(log_type) 46 | response = rest_get("#{uri_for_log_type(log_type)}Entries/") 47 | response_handler(response)['Items'].empty? 48 | end 49 | 50 | # Get the specified logs 51 | # @param [String, Symbol, NilClass] severity_level Set to nil to get all logs 52 | # @param [String, Symbol] duration Up to this many hours ago 53 | # @param [String, Symbol] log_type IEL or IML 54 | # @raise [RuntimeError] if the request failed 55 | # @return [Array] log entries 56 | def get_logs(severity_level, duration, log_type) 57 | response = rest_get("#{uri_for_log_type(log_type)}Entries/") 58 | entries = response_handler(response)['Items'] 59 | start_time = Time.now.utc - (duration * 3600) 60 | if severity_level.nil? 61 | entries.select { |e| Time.parse(e['Created']) > start_time } 62 | else 63 | entries.select { |e| severity_level.to_s.casecmp(e['Severity']) == 0 && Time.parse(e['Created']) > start_time } 64 | end 65 | end 66 | end 67 | end 68 | -------------------------------------------------------------------------------- /lib/ilo-sdk/helpers/manager_account_helper.rb: -------------------------------------------------------------------------------- 1 | # (C) Copyright 2016 Hewlett Packard Enterprise Development LP 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # You may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software distributed 8 | # under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 9 | # CONDITIONS OF ANY KIND, either express or implied. See the License for the 10 | # specific language governing permissions and limitations under the License. 11 | 12 | module ILO_SDK 13 | # Contains helper methods for Manager Account actions 14 | module ManagerAccountHelper 15 | # Get the Privileges for a user 16 | # @param [String, Symbol] username 17 | # @raise [RuntimeError] if the request failed 18 | # @return [Hash] privileges 19 | def get_account_privileges(username) 20 | response = rest_get('/redfish/v1/AccountService/Accounts/') 21 | accounts = response_handler(response)['Items'] 22 | accounts.each do |account| 23 | if account['Oem']['Hp']['LoginName'] == username 24 | return account['Oem']['Hp']['Privileges'] 25 | end 26 | end 27 | end 28 | 29 | # Set the privileges for a user 30 | # @param [TrueClass, FalseClass] username 31 | # @param [Hash] privileges 32 | # @option privileges [TrueClass, FalseClass] :LoginPriv 33 | # @option privileges [TrueClass, FalseClass] :RemoteConsolePriv 34 | # @option privileges [TrueClass, FalseClass] :UserConfigPriv 35 | # @option privileges [TrueClass, FalseClass] :VirtualMediaPriv 36 | # @option privileges [TrueClass, FalseClass] :VirtualPowerAndResetPriv 37 | # @option privileges [TrueClass, FalseClass] :iLOConfigPriv 38 | # @raise [RuntimeError] if the request failed 39 | # @return true 40 | def set_account_privileges(username, privileges) 41 | response = rest_get('/redfish/v1/AccountService/Accounts/') 42 | accounts = response_handler(response)['Items'] 43 | id = '0' 44 | accounts.each do |account| 45 | if account['Oem']['Hp']['LoginName'] == username 46 | id = account['Id'] 47 | break 48 | end 49 | end 50 | new_action = { 51 | 'Oem' => { 52 | 'Hp' => { 53 | 'Privileges' => privileges 54 | } 55 | } 56 | } 57 | response = rest_patch("/redfish/v1/AccountService/Accounts/#{id}/", body: new_action) 58 | response_handler(response) 59 | true 60 | end 61 | end 62 | end 63 | -------------------------------------------------------------------------------- /lib/ilo-sdk/helpers/manager_network_protocol_helper.rb: -------------------------------------------------------------------------------- 1 | # (C) Copyright 2016 Hewlett Packard Enterprise Development LP 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # You may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software distributed 8 | # under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 9 | # CONDITIONS OF ANY KIND, either express or implied. See the License for the 10 | # specific language governing permissions and limitations under the License. 11 | 12 | module ILO_SDK 13 | # Contains helper methods for Manager Network Protocol actions 14 | module ManagerNetworkProtocolHelper 15 | # Get the Session Timeout Minutes 16 | # @raise [RuntimeError] if the request failed 17 | # @return [Fixnum] timeout 18 | def get_timeout 19 | response = rest_get('/redfish/v1/Managers/1/NetworkService/') 20 | response_handler(response)['SessionTimeoutMinutes'] 21 | end 22 | 23 | # Set the Session Timeout Minutes 24 | # @param [Fixnum] timeout 25 | # @raise [RuntimeError] if the request failed 26 | # @return true 27 | def set_timeout(timeout) 28 | new_action = { 'SessionTimeoutMinutes' => timeout } 29 | response = rest_patch('/redfish/v1/Managers/1/NetworkService/', body: new_action) 30 | response_handler(response) 31 | true 32 | end 33 | end 34 | end 35 | -------------------------------------------------------------------------------- /lib/ilo-sdk/helpers/power_helper.rb: -------------------------------------------------------------------------------- 1 | # (C) Copyright 2016 Hewlett Packard Enterprise Development LP 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # You may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software distributed 8 | # under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 9 | # CONDITIONS OF ANY KIND, either express or implied. See the License for the 10 | # specific language governing permissions and limitations under the License. 11 | 12 | module ILO_SDK 13 | # Contains helper methods for Power actions 14 | module PowerHelper 15 | # Get the Power State 16 | # @raise [RuntimeError] if the request failed 17 | # @return [String] power_state 18 | def get_power_state 19 | response = rest_get('/redfish/v1/Systems/1/') 20 | response_handler(response)['PowerState'] 21 | end 22 | 23 | # Set the Power State 24 | # @param [String, Symbol] state 25 | # @raise [RuntimeError] if the request failed 26 | # @return true 27 | def set_power_state(state) 28 | new_action = { 'Action' => 'Reset', 'ResetType' => state } 29 | response = rest_post('/redfish/v1/Systems/1/', body: new_action) 30 | response_handler(response) 31 | true 32 | end 33 | 34 | # Reset the iLO 35 | # @raise [RuntimeError] if the request failed 36 | # @return true 37 | def reset_ilo 38 | new_action = { 'Action' => 'Reset' } 39 | response = rest_post('/redfish/v1/Managers/1/', body: new_action) 40 | response_handler(response) 41 | true 42 | end 43 | end 44 | end 45 | -------------------------------------------------------------------------------- /lib/ilo-sdk/helpers/secure_boot_helper.rb: -------------------------------------------------------------------------------- 1 | # (C) Copyright 2016 Hewlett Packard Enterprise Development LP 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # You may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software distributed 8 | # under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 9 | # CONDITIONS OF ANY KIND, either express or implied. See the License for the 10 | # specific language governing permissions and limitations under the License. 11 | 12 | module ILO_SDK 13 | # Contains helper methods for Secure Boot actions 14 | module SecureBootHelper 15 | # Get the UEFI secure boot 16 | # @raise [RuntimeError] if the request failed 17 | # @return [TrueClass, FalseClass] uefi_secure_boot 18 | def get_uefi_secure_boot 19 | response = rest_get('/redfish/v1/Systems/1/SecureBoot/') 20 | response_handler(response)['SecureBootEnable'] 21 | end 22 | 23 | # Set the UEFI secure boot true or false 24 | # @param [Boolean] secure_boot_enable 25 | # @raise [RuntimeError] if the request failed 26 | # @return true 27 | def set_uefi_secure_boot(secure_boot_enable) 28 | new_action = { 'SecureBootEnable' => secure_boot_enable } 29 | response = rest_patch('/redfish/v1/Systems/1/SecureBoot/', body: new_action) 30 | response_handler(response) 31 | true 32 | end 33 | end 34 | end 35 | -------------------------------------------------------------------------------- /lib/ilo-sdk/helpers/service_root_helper.rb: -------------------------------------------------------------------------------- 1 | # (C) Copyright 2016 Hewlett Packard Enterprise Development LP 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # You may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software distributed 8 | # under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 9 | # CONDITIONS OF ANY KIND, either express or implied. See the License for the 10 | # specific language governing permissions and limitations under the License. 11 | 12 | module ILO_SDK 13 | # Contains helper methods for Service Root Actions 14 | module ServiceRootHelper 15 | # Get the schema information with given prefix 16 | # @param [String, Symbol] schema_prefix 17 | # @raise [RuntimeError] if the request failed 18 | # @return [Array] schema 19 | def get_schema(schema_prefix) 20 | response = rest_get('/redfish/v1/Schemas/') 21 | schemas = response_handler(response)['Items'] 22 | schema = schemas.select { |s| s['Schema'].start_with?(schema_prefix) } 23 | raise "NO schema found with this schema prefix : #{schema_prefix}" if schema.empty? 24 | info = [] 25 | schema.each do |sc| 26 | response = rest_get(sc['Location'][0]['Uri']['extref']) 27 | schema_store = response_handler(response) 28 | info.push(schema_store) 29 | end 30 | info 31 | end 32 | 33 | # Get the Registry with given registry_prefix 34 | # @param [String, Symbol] registry_prefix 35 | # @raise [RuntimeError] if the request failed 36 | # @return [Array] registry 37 | def get_registry(registry_prefix) 38 | response = rest_get('/redfish/v1/Registries/') 39 | registries = response_handler(response)['Items'] 40 | registry = registries.select { |reg| reg['Schema'].start_with?(registry_prefix) } 41 | info = [] 42 | registry.each do |reg| 43 | response = rest_get(reg['Location'][0]['Uri']['extref']) 44 | registry_store = response_handler(response) 45 | info.push(registry_store) 46 | end 47 | info 48 | end 49 | end 50 | end 51 | -------------------------------------------------------------------------------- /lib/ilo-sdk/helpers/snmp_service_helper.rb: -------------------------------------------------------------------------------- 1 | # (C) Copyright 2016 Hewlett Packard Enterprise Development LP 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # You may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software distributed 8 | # under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 9 | # CONDITIONS OF ANY KIND, either express or implied. See the License for the 10 | # specific language governing permissions and limitations under the License. 11 | 12 | module ILO_SDK 13 | # Contains helper methods for SNMP Service actions 14 | module SNMPServiceHelper 15 | # Get the SNMP Mode 16 | # @raise [RuntimeError] if the request failed 17 | # @return [String] snmp_mode 18 | def get_snmp_mode 19 | response = rest_get('/redfish/v1/Managers/1/SnmpService/') 20 | response_handler(response)['Mode'] 21 | end 22 | 23 | # Get the SNMP Alerts Enabled value 24 | # @raise [RuntimeError] if the request failed 25 | # @return [String] snmp_alerts_enabled 26 | def get_snmp_alerts_enabled 27 | response = rest_get('/redfish/v1/Managers/1/SnmpService/') 28 | response_handler(response)['AlertsEnabled'] 29 | end 30 | 31 | # Set the SNMP Mode and Alerts Enabled value 32 | # @param [String, Symbol] snmp_mode 33 | # @param [Boolean] snmp_alerts 34 | # @raise [RuntimeError] if the request failed 35 | # @return true 36 | def set_snmp(snmp_mode, snmp_alerts) 37 | new_action = { 'Mode' => snmp_mode, 'AlertsEnabled' => snmp_alerts } 38 | response = rest_patch('/redfish/v1/Managers/1/SnmpService/', body: new_action) 39 | response_handler(response) 40 | true 41 | end 42 | end 43 | end 44 | -------------------------------------------------------------------------------- /lib/ilo-sdk/helpers/virtual_media_helper.rb: -------------------------------------------------------------------------------- 1 | # (C) Copyright 2016 Hewlett Packard Enterprise Development LP 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # You may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software distributed 8 | # under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 9 | # CONDITIONS OF ANY KIND, either express or implied. See the License for the 10 | # specific language governing permissions and limitations under the License. 11 | 12 | module ILO_SDK 13 | # Contains helper methods for Virtual Media actions 14 | module VirtualMediaHelper 15 | # Get the Virtual Media Information 16 | # @raise [RuntimeError] if the request failed 17 | # @return [String] virtual_media 18 | def get_virtual_media 19 | response = rest_get('/redfish/v1/Managers/1/VirtualMedia/') 20 | media = {} 21 | response_handler(response)['links']['Member'].each do |vm| 22 | response = rest_get(vm['href']) 23 | virtual_media = response_handler(response) 24 | media[virtual_media['Id']] = { 25 | 'Image' => virtual_media['Image'], 26 | 'MediaTypes' => virtual_media['MediaTypes'] 27 | } 28 | end 29 | media 30 | end 31 | 32 | # Return whether Virtual Media is inserted 33 | # @raise [RuntimeError] if the request failed 34 | # @return [TrueClass, FalseClass] virtual_media_inserted 35 | def virtual_media_inserted?(id) 36 | response = rest_get("/redfish/v1/Managers/1/VirtualMedia/#{id}/") 37 | response_handler(response)['Inserted'] 38 | end 39 | 40 | # Insert Virtual Media 41 | # @param [String, Symbol] id 42 | # @param [String, Symbol] image 43 | # @return true 44 | def insert_virtual_media(id, image) 45 | new_action = { 46 | 'Action' => 'InsertVirtualMedia', 47 | 'Target' => '/Oem/Hp', 48 | 'Image' => image 49 | } 50 | response = rest_post("/redfish/v1/Managers/1/VirtualMedia/#{id}/", body: new_action) 51 | response_handler(response) 52 | true 53 | end 54 | 55 | # Eject Virtual Media 56 | # @param [String, Symbol] id 57 | # @return true 58 | def eject_virtual_media(id) 59 | new_action = { 60 | 'Action' => 'EjectVirtualMedia', 61 | 'Target' => '/Oem/Hp' 62 | } 63 | response = rest_post("/redfish/v1/Managers/1/VirtualMedia/#{id}/", body: new_action) 64 | response_handler(response) 65 | true 66 | end 67 | end 68 | end 69 | -------------------------------------------------------------------------------- /lib/ilo-sdk/rest.rb: -------------------------------------------------------------------------------- 1 | # (c) Copyright 2016 Hewlett Packard Enterprise Development LP 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # You may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software distributed 8 | # under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 9 | # CONDITIONS OF ANY KIND, either express or implied. See the License for the 10 | # specific language governing permissions and limitations under the License. 11 | 12 | require 'uri' 13 | require 'net/http' 14 | require 'openssl' 15 | require 'json' 16 | 17 | module ILO_SDK 18 | # Contains all the methods for making API REST calls 19 | module Rest 20 | # Make a restful API request to the iLO 21 | # @param [Symbol] type the rest method/type Options are :get, :post, :put, :patch, and :delete 22 | # @param [String] path the path for the request. Usually starts with "/rest/" 23 | # @param [Hash] options the options for the request 24 | # @option options [String] :body Hash to be converted into json and set as the request body 25 | # @option options [String] :Content-Type ('application/json') Set to nil or :none to have this option removed 26 | # @raise [InvalidRequest] if the request is invalid 27 | # @raise [SocketError] if a connection could not be made 28 | # @raise [OpenSSL::SSL::SSLError] if SSL validation of the iLO's certificate failed 29 | # @return [NetHTTPResponse] The response object 30 | def rest_api(type, path, options = {}) 31 | raise InvalidRequest, 'Must specify path' unless path 32 | raise InvalidRequest, 'Must specify type' unless type 33 | @logger.debug "Making :#{type} rest call to #{@host}#{path}" 34 | 35 | uri = URI.parse(URI.escape("#{@host}#{path}")) 36 | http = @disable_proxy ? Net::HTTP.new(uri.host, uri.port, nil, nil) : Net::HTTP.new(uri.host, uri.port) 37 | http.use_ssl = true if uri.scheme == 'https' 38 | http.verify_mode = OpenSSL::SSL::VERIFY_NONE unless @ssl_enabled 39 | 40 | request = build_request(type, uri, options) 41 | response = http.request(request) 42 | @logger.debug " Response: Code=#{response.code}. Headers=#{response.to_hash}\n Body=#{response.body}" 43 | response 44 | rescue OpenSSL::SSL::SSLError => e 45 | msg = 'SSL verification failed for the request. Please either:' 46 | msg += "\n 1. Install the necessary certificate(s) into your cert store" 47 | msg += ". Using cert store: #{ENV['SSL_CERT_FILE']}" if ENV['SSL_CERT_FILE'] 48 | msg += "\n 2. Set the :ssl_enabled option to false for your iLO client (not recommended)" 49 | @logger.error msg 50 | raise e 51 | rescue SocketError => e 52 | e.message.prepend("Failed to connect to iLO host #{@host}!\n") 53 | raise e 54 | end 55 | 56 | # Make a restful GET request 57 | # Parameters & return value align with those of the {ILO_SDK::Rest::rest_api} method above 58 | def rest_get(path) 59 | rest_api(:get, path, {}) 60 | end 61 | 62 | # Make a restful POST request 63 | # Parameters & return value align with those of the {ILO_SDK::Rest::rest_api} method above 64 | def rest_post(path, options = {}) 65 | rest_api(:post, path, options) 66 | end 67 | 68 | # Make a restful PUT request 69 | # Parameters & return value align with those of the {ILO_SDK::Rest::rest_api} method above 70 | def rest_put(path, options = {}) 71 | rest_api(:put, path, options) 72 | end 73 | 74 | # Make a restful PATCH request 75 | # Parameters & return value align with those of the {ILO_SDK::Rest::rest_api} method above 76 | def rest_patch(path, options = {}) 77 | rest_api(:patch, path, options) 78 | end 79 | 80 | # Make a restful DELETE request 81 | # Parameters & return value align with those of the {ILO_SDK::Rest::rest_api} method above 82 | def rest_delete(path, options = {}) 83 | rest_api(:delete, path, options) 84 | end 85 | 86 | RESPONSE_CODE_OK = 200 87 | RESPONSE_CODE_CREATED = 201 88 | RESPONSE_CODE_ACCEPTED = 202 89 | RESPONSE_CODE_NO_CONTENT = 204 90 | RESPONSE_CODE_BAD_REQUEST = 400 91 | RESPONSE_CODE_UNAUTHORIZED = 401 92 | RESPONSE_CODE_NOT_FOUND = 404 93 | 94 | # Handle the response for rest call. 95 | # If an asynchronous task was started, this waits for it to complete. 96 | # @param [HTTPResponse] HTTP response 97 | # @raise [ILO_SDK::BadRequest] if the request failed with a 400 status 98 | # @raise [ILO_SDK::Unauthorized] if the request failed with a 401 status 99 | # @raise [ILO_SDK::NotFound] if the request failed with a 404 status 100 | # @raise [ILO_SDK::RequestError] if the request failed with any other status 101 | # @return [Hash] The parsed JSON body 102 | def response_handler(response) 103 | case response.code.to_i 104 | when RESPONSE_CODE_OK # Synchronous read/query 105 | begin 106 | return JSON.parse(response.body) 107 | rescue JSON::ParserError => e 108 | @logger.warn "Failed to parse JSON response. #{e}" 109 | return response.body 110 | end 111 | when RESPONSE_CODE_CREATED # Synchronous add 112 | return JSON.parse(response.body) 113 | when RESPONSE_CODE_ACCEPTED # Asynchronous add, update or delete 114 | return JSON.parse(response.body) # TODO: Remove when tested 115 | # TODO: Make this actually wait for the task 116 | # @logger.debug "Waiting for task: #{response.header['location']}" 117 | # task = wait_for(response.header['location']) 118 | # return true unless task['associatedResource'] && task['associatedResource']['resourceUri'] 119 | # resource_data = rest_get(task['associatedResource']['resourceUri']) 120 | # return JSON.parse(resource_data.body) 121 | when RESPONSE_CODE_NO_CONTENT # Synchronous delete 122 | return {} 123 | when RESPONSE_CODE_BAD_REQUEST 124 | raise BadRequest, "400 BAD REQUEST #{response.body}" 125 | when RESPONSE_CODE_UNAUTHORIZED 126 | raise Unauthorized, "401 UNAUTHORIZED #{response.body}" 127 | when RESPONSE_CODE_NOT_FOUND 128 | raise NotFound, "404 NOT FOUND #{response.body}" 129 | else 130 | raise RequestError, "#{response.code} #{response.body}" 131 | end 132 | end 133 | 134 | 135 | private 136 | 137 | # @param type [Symbol] The type of request object to build (get, post, put, patch, or delete) 138 | # @param uri [URI] URI object 139 | # @param options [Hash] Options for building the request. All options except "body" are set as headers. 140 | # @raise [ILO_SDK::InvalidRequest] if the request type is not recognized 141 | def build_request(type, uri, options) 142 | case type.downcase 143 | when 'get', :get 144 | request = Net::HTTP::Get.new(uri.request_uri) 145 | when 'post', :post 146 | request = Net::HTTP::Post.new(uri.request_uri) 147 | when 'put', :put 148 | request = Net::HTTP::Put.new(uri.request_uri) 149 | when 'patch', :patch 150 | request = Net::HTTP::Patch.new(uri.request_uri) 151 | when 'delete', :delete 152 | request = Net::HTTP::Delete.new(uri.request_uri) 153 | else 154 | raise InvalidRequest, "Invalid rest method: #{type}. Valid methods are: get, post, put, patch, delete" 155 | end 156 | options['Content-Type'] ||= 'application/json' 157 | options.delete('Content-Type') if [:none, 'none', nil].include?(options['Content-Type']) 158 | auth = true 159 | if [:none, 'none'].include?(options['auth']) 160 | options.delete('auth') 161 | auth = false 162 | end 163 | options.each do |key, val| 164 | if key.to_s.downcase == 'body' 165 | request.body = val.to_json rescue val 166 | else 167 | request[key] = val 168 | end 169 | end 170 | 171 | filtered_options = options.to_s 172 | filtered_options.gsub!(@password, 'filtered') if @password 173 | @logger.debug " Options: #{filtered_options}" 174 | 175 | request.basic_auth(@user, @password) if auth 176 | request 177 | end 178 | end 179 | end 180 | -------------------------------------------------------------------------------- /lib/ilo-sdk/version.rb: -------------------------------------------------------------------------------- 1 | # (c) Copyright 2016 Hewlett Packard Enterprise Development LP 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software distributed 8 | # under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 9 | # CONDITIONS OF ANY KIND, either express or implied. See the License for the 10 | # specific language governing permissions and limitations under the License. 11 | 12 | # Gem version defined here 13 | module ILO_SDK 14 | VERSION = '1.3.0'.freeze 15 | end 16 | -------------------------------------------------------------------------------- /spec/shared_context.rb: -------------------------------------------------------------------------------- 1 | # General context for unit testing: 2 | RSpec.shared_context 'shared context', a: :b do 3 | before :each do 4 | options = { host: 'ilo1.example.com', user: 'Administrator', password: 'secret123' } 5 | @client = ILO_SDK::Client.new(options) 6 | end 7 | end 8 | 9 | # Context for CLI testing: 10 | RSpec.shared_context 'cli context', a: :b do 11 | before :each do 12 | ENV['ILO_HOST'] = 'https://ilo.example.com' 13 | ENV['ILO_USER'] = 'Admin' 14 | ENV['ILO_PASSWORD'] = 'secret123' 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | require 'pry' 2 | require 'simplecov' 3 | 4 | client_files = %w(client.rb rest.rb) 5 | helper_path = 'lib/ilo-sdk/helpers' 6 | 7 | SimpleCov.start do 8 | add_filter 'spec/' 9 | add_group 'Client', client_files 10 | add_group 'Helpers', helper_path 11 | minimum_coverage 90 # TODO: bump up as we increase coverage. Goal: 95% 12 | minimum_coverage_by_file 10 # TODO: bump up as we increase coverage. Goal: 90% 13 | end 14 | 15 | require 'ilo-sdk' 16 | require_relative 'shared_context' 17 | require_relative 'support/fake_response' 18 | 19 | RSpec.configure do |config| 20 | config.before(:each) do 21 | ILO_SDK::ENV_VARS.each { |e| ENV[e] = nil } # Clear environment variables 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /spec/support/fake_response.rb: -------------------------------------------------------------------------------- 1 | require 'json' 2 | 3 | # Helper for mocking responses 4 | class FakeResponse 5 | attr_reader :body, :code, :header 6 | 7 | def initialize(body = {}, code = 200, header = {}) 8 | @body = body 9 | @body = @body.to_json unless @body.class == String 10 | @code = code 11 | @header = header 12 | end 13 | 14 | def[](key) 15 | header[key] 16 | end 17 | 18 | def to_hash 19 | header 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /spec/unit/cli/cli_spec.rb: -------------------------------------------------------------------------------- 1 | require_relative './../../spec_helper' 2 | 3 | # Class to mock Kernel interractions 4 | class FakeKernel 5 | def self.exit(*) 6 | end 7 | end 8 | 9 | # Class to mock STDOUT, etc. 10 | class FakeOut < IO 11 | def self.puts(*) 12 | end 13 | end 14 | 15 | RSpec.describe ILO_SDK::Cli::Runner do 16 | include_context 'cli context' 17 | 18 | describe '#new' do 19 | it 'can be initialized' do 20 | expect { described_class.new(ARGV) }.to_not raise_error 21 | end 22 | end 23 | 24 | describe '#execute!' do 25 | it 'exits with 0 when the runner returns without errors' do 26 | expect(ILO_SDK::Cli).to receive(:start).and_return(true) 27 | expect(FakeKernel).to receive(:exit).with(0).and_return(true) 28 | r = described_class.new(ARGV, STDIN, STDOUT, STDERR, FakeKernel) 29 | expect { r.execute! }.to_not raise_error 30 | end 31 | 32 | it 'exits with 1 when the runner returns with an error' do 33 | expect(ILO_SDK::Cli).to receive(:start).and_raise('FakeError') 34 | expect(FakeKernel).to receive(:exit).with(1).and_return(true) 35 | expect(FakeOut).to receive(:puts).with(/FakeError/).and_return(true) 36 | expect(FakeOut).to receive(:puts).with(/from/).and_return(true) 37 | r = described_class.new(ARGV, STDIN, STDOUT, FakeOut, FakeKernel) 38 | expect { r.execute! }.to_not raise_error 39 | end 40 | end 41 | end 42 | -------------------------------------------------------------------------------- /spec/unit/cli/console_spec.rb: -------------------------------------------------------------------------------- 1 | require_relative './../../spec_helper' 2 | 3 | RSpec.describe ILO_SDK::Cli do 4 | include_context 'cli context' 5 | 6 | describe '#console' do 7 | let(:command) { ILO_SDK::Cli.start(['console']) } 8 | 9 | context 'with a valid @client object' do 10 | it 'starts a Pry session' do 11 | expect(Pry).to receive(:start).and_return true 12 | expect(STDOUT).to receive(:puts).with(/Connected to/) 13 | expect(STDOUT).to receive(:puts).with(/HINT: The @client object is available to you/) 14 | allow_any_instance_of(Object).to receive(:warn).with(/was not found/).and_return true 15 | command 16 | end 17 | end 18 | 19 | context 'with no @client object' do 20 | it 'starts a Pry session' do 21 | expect(ILO_SDK::Client).to receive(:new).and_raise 'Error' 22 | expect(Pry).to receive(:start).and_return true 23 | expect(STDOUT).to receive(:puts).with(/WARNING: Couldn't connect to/) 24 | allow_any_instance_of(Object).to receive(:warn).with(/was not found/).and_return true 25 | command 26 | end 27 | end 28 | end 29 | end 30 | -------------------------------------------------------------------------------- /spec/unit/cli/env_spec.rb: -------------------------------------------------------------------------------- 1 | require_relative './../../spec_helper' 2 | 3 | RSpec.describe ILO_SDK::Cli do 4 | include_context 'cli context' 5 | 6 | describe '#env' do 7 | let(:command) { ILO_SDK::Cli.start(['env']) } 8 | let(:data) { ILO_SDK::ENV_VARS.collect { |e| [e, ENV[e]] }.to_h } 9 | 10 | it 'shows ILO_HOST' do 11 | expect { command }.to output(%r{ILO_HOST\s+=\s'https:\/\/ilo\.example\.com'}).to_stdout_from_any_process 12 | end 13 | 14 | it 'shows ILO_USER' do 15 | expect { command }.to output(/ILO_USER\s+=\s'Admin'/).to_stdout_from_any_process 16 | end 17 | 18 | it 'shows ILO_PASSWORD' do 19 | ENV['ILO_PASSWORD'] = 'secret123' 20 | expect { command }.to output(/ILO_PASSWORD\s+=\s'secret123'/).to_stdout_from_any_process 21 | end 22 | 23 | it 'shows ILO_SSL_ENABLED as nil' do 24 | expect { command }.to output(/ILO_SSL_ENABLED\s+=\snil/).to_stdout_from_any_process 25 | end 26 | 27 | it 'shows ILO_SSL_ENABLED when set' do 28 | ENV['ILO_SSL_ENABLED'] = 'false' 29 | expect { command }.to output(/ILO_SSL_ENABLED\s+=\sfalse/).to_stdout_from_any_process 30 | end 31 | 32 | it 'prints the output in json format' do 33 | expect { ILO_SDK::Cli.start(%w(env -f json)) }.to output(JSON.pretty_generate(data) + "\n").to_stdout_from_any_process 34 | end 35 | 36 | it 'prints the output in yaml format' do 37 | expect { ILO_SDK::Cli.start(%w(env -f yaml)) }.to output(data.to_yaml).to_stdout_from_any_process 38 | end 39 | end 40 | end 41 | -------------------------------------------------------------------------------- /spec/unit/cli/login_spec.rb: -------------------------------------------------------------------------------- 1 | require_relative './../../spec_helper' 2 | 3 | RSpec.describe ILO_SDK::Cli do 4 | include_context 'cli context' 5 | 6 | describe '#login' do 7 | let(:command) { ILO_SDK::Cli.start(['login']) } 8 | 9 | it 'prints a success message' do 10 | expect_any_instance_of(ILO_SDK::Client).to receive(:rest_get).with('/redfish/v1/Sessions/') 11 | .and_return(FakeResponse.new) 12 | expect { command }.to output(/Login Successful!/).to_stdout_from_any_process 13 | end 14 | 15 | it 'errors out if the login fails' do 16 | expect_any_instance_of(ILO_SDK::Client).to receive(:rest_get).with('/redfish/v1/Sessions/') 17 | .and_return(FakeResponse.new({}, 401)) 18 | expect($stderr).to receive(:puts).with(/Unauthorized/i) 19 | expect { command }.to raise_error SystemExit 20 | end 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /spec/unit/cli/output_spec.rb: -------------------------------------------------------------------------------- 1 | require_relative './../../spec_helper' 2 | 3 | RSpec.describe ILO_SDK::Cli do 4 | include_context 'cli context' 5 | 6 | let(:cli) do 7 | ILO_SDK::Cli.new 8 | end 9 | 10 | describe '#output' do 11 | context 'with the default format' do 12 | it 'prints nil for nil' do 13 | expect { cli.instance_eval { output(nil) } }.to output("nil\n").to_stdout_from_any_process 14 | end 15 | 16 | it 'prints nil in arrays' do 17 | expect { cli.instance_eval { output([nil]) } }.to output("nil\n\nTotal: 1\n").to_stdout_from_any_process 18 | end 19 | 20 | it 'prints nil in hash keys and values' do 21 | expect { cli.instance_eval { output(nil => nil) } }.to output("nil: nil\n").to_stdout_from_any_process 22 | end 23 | 24 | it 'prints single values' do 25 | expect { cli.instance_eval { output('val') } }.to output("val\n").to_stdout_from_any_process 26 | end 27 | 28 | it 'prints arrays' do 29 | expect { cli.instance_eval { output(%w(val val2)) } }.to output("val\nval2\n\nTotal: 2\n").to_stdout_from_any_process 30 | end 31 | 32 | it 'prints nested arrays' do 33 | expect { cli.instance_eval { output(['val', %w(val2 val3)]) } }.to output("val\n val2\n val3\n\nTotal: 2\n").to_stdout_from_any_process 34 | end 35 | 36 | it 'prints hashes' do 37 | expect { cli.instance_eval { output(key: 'val', key2: 'val2') } }.to output("key: val\nkey2: val2\n").to_stdout_from_any_process 38 | end 39 | 40 | it 'prints nested hashes' do 41 | expect { cli.instance_eval { output(key: { key2: 'val2' }) } }.to output("key:\n key2: val2\n").to_stdout_from_any_process 42 | end 43 | end 44 | end 45 | end 46 | -------------------------------------------------------------------------------- /spec/unit/cli/rest_spec.rb: -------------------------------------------------------------------------------- 1 | require_relative './../../spec_helper' 2 | 3 | RSpec.describe ILO_SDK::Cli do 4 | include_context 'cli context' 5 | 6 | let(:response) { { 'key1' => 'val1', 'key2' => 'val2', 'key3' => { 'key4' => 'val4' } } } 7 | 8 | describe '#rest get' do 9 | it 'requires a URI' do 10 | expect($stderr).to receive(:puts).with(/ERROR.*arguments/) 11 | ILO_SDK::Cli.start(%w(rest get)) 12 | end 13 | 14 | it 'sends any data that is passed in' do 15 | data = { 'ServiceName' => 'iLO Admin', 'ServiceEmail' => 'admin@domain.com' } 16 | expect_any_instance_of(ILO_SDK::Client).to receive(:rest_api) 17 | .with('get', '/redfish/v1/', body: data).and_return FakeResponse.new(response) 18 | expect { ILO_SDK::Cli.start(['rest', 'get', 'redfish/v1/', '-d', data.to_json]) } 19 | .to output(JSON.pretty_generate(response) + "\n").to_stdout_from_any_process 20 | end 21 | 22 | context 'output formats' do 23 | before :each do 24 | expect_any_instance_of(ILO_SDK::Client).to receive(:rest_api) 25 | .with('get', '/redfish/v1/', {}).and_return FakeResponse.new(response) 26 | end 27 | 28 | it 'makes a GET call to the URI and outputs the response in json format' do 29 | expect { ILO_SDK::Cli.start(%w(rest get redfish/v1/)) } 30 | .to output(JSON.pretty_generate(response) + "\n").to_stdout_from_any_process 31 | end 32 | 33 | it 'can output the response in raw format' do 34 | expect { ILO_SDK::Cli.start(%w(rest get redfish/v1/ -f raw)) } 35 | .to output(response.to_json + "\n").to_stdout_from_any_process 36 | end 37 | 38 | it 'can output the response in yaml format' do 39 | expect { ILO_SDK::Cli.start(%w(rest get redfish/v1/ -f yaml)) } 40 | .to output(response.to_yaml).to_stdout_from_any_process 41 | end 42 | end 43 | 44 | context 'bad requests' do 45 | it 'fails if the data cannot be parsed as json' do 46 | expect($stderr).to receive(:puts).with(/Failed to parse data as JSON/) 47 | expect { ILO_SDK::Cli.start(%w(rest get redfish/v1/ -d fake_json)) } 48 | .to raise_error SystemExit 49 | end 50 | 51 | it 'fails if the request method is invalid' do 52 | expect($stderr).to receive(:puts).with(/Invalid rest method/) 53 | expect { ILO_SDK::Cli.start(%w(rest blah redfish/v1/)) } 54 | .to raise_error SystemExit 55 | end 56 | 57 | it 'fails if the response code is 3XX' do 58 | headers = { 'location' => ['redfish/v1/Systems/1/'] } 59 | body = {} 60 | expect_any_instance_of(ILO_SDK::Client).to receive(:rest_api) 61 | .with('get', '/redfish/v1', {}).and_return FakeResponse.new(body, 308, headers) 62 | expect($stderr).to receive(:puts).with(/308.*location/m) 63 | expect { ILO_SDK::Cli.start(%w(rest get redfish/v1)) } 64 | .to raise_error SystemExit 65 | end 66 | 67 | it 'fails if the response code is 4XX' do 68 | headers = { 'content-type' => ['text/plain'] } 69 | body = { 'Message' => 'Not found!' } 70 | expect_any_instance_of(ILO_SDK::Client).to receive(:rest_api) 71 | .with('get', '/redfish/v1', {}).and_return FakeResponse.new(body, 404, headers) 72 | expect($stderr).to receive(:puts).with(/404.*content-type.*Not found/m) 73 | expect { ILO_SDK::Cli.start(%w(rest get redfish/v1)) } 74 | .to raise_error SystemExit 75 | end 76 | 77 | it 'fails if the response code is 4XX' do 78 | headers = { 'content-type' => ['text/plain'] } 79 | body = { 'Message' => 'Server error!' } 80 | expect_any_instance_of(ILO_SDK::Client).to receive(:rest_api) 81 | .with('get', '/redfish/v1', {}).and_return FakeResponse.new(body, 500, headers) 82 | expect($stderr).to receive(:puts).with(/500.*content-type.*Server error/m) 83 | expect { ILO_SDK::Cli.start(%w(rest get redfish/v1)) } 84 | .to raise_error SystemExit 85 | end 86 | end 87 | 88 | end 89 | end 90 | -------------------------------------------------------------------------------- /spec/unit/cli/version_spec.rb: -------------------------------------------------------------------------------- 1 | require_relative './../../spec_helper' 2 | 3 | RSpec.describe ILO_SDK::Cli do 4 | include_context 'cli context' 5 | 6 | describe '#version' do 7 | let(:command) { ILO_SDK::Cli.start(['version']) } 8 | 9 | before :each do 10 | allow_any_instance_of(ILO_SDK::Client).to receive(:rest_get).with('/redfish/v1/') 11 | .and_return(FakeResponse.new('RedfishVersion' => '1.0.0')) 12 | end 13 | 14 | it 'prints the gem version' do 15 | expect { command }.to output(/Gem Version: #{ILO_SDK::VERSION}/).to_stdout_from_any_process 16 | end 17 | 18 | it 'prints the appliance version' do 19 | expect { command }.to output(/iLO Redfish API version: 1.0.0/).to_stdout_from_any_process 20 | end 21 | 22 | it 'requires the url to be set' do 23 | ENV.delete('ILO_HOST') 24 | expect(STDOUT).to receive(:puts).with(/Gem Version/) 25 | expect(STDOUT).to receive(:puts).with(/iLO API version unknown/) 26 | command 27 | end 28 | end 29 | end 30 | -------------------------------------------------------------------------------- /spec/unit/client_spec.rb: -------------------------------------------------------------------------------- 1 | require_relative './../spec_helper' 2 | 3 | RSpec.describe ILO_SDK::Client do 4 | 5 | describe '#initialize' do 6 | it 'creates a client with valid credentials' do 7 | options = { host: 'https://ilo.example.com', user: 'Administrator', password: 'secret123' } 8 | client = described_class.new(options) 9 | expect(client.host).to eq('https://ilo.example.com') 10 | expect(client.user).to eq('Administrator') 11 | expect(client.password).to eq('secret123') 12 | expect(client.ssl_enabled).to eq(true) 13 | expect(client.disable_proxy).to eq(nil) 14 | expect(client.log_level).to eq(:info) 15 | expect(client.logger).to be_a(Logger) 16 | end 17 | 18 | it 'requires the host attribute to be set' do 19 | expect { described_class.new({}) }.to raise_error(ILO_SDK::InvalidClient, /Must set the host option/) 20 | end 21 | 22 | it 'automatically prepends the host with "https://"' do 23 | options = { host: 'ilo.example.com', user: 'Administrator', password: 'secret123' } 24 | client = described_class.new(options) 25 | expect(client.host).to eq('https://ilo.example.com') 26 | end 27 | 28 | it 'requires the password attribute to be set' do 29 | options = { host: 'ilo.example.com', user: 'Administrator' } 30 | expect { described_class.new(options) }.to raise_error(ILO_SDK::InvalidClient, /Must set the password/) 31 | end 32 | 33 | it 'sets the username to "Administrator" by default' do 34 | options = { host: 'ilo.example.com', password: 'secret123' } 35 | client = nil 36 | expect { client = described_class.new(options) }.to output(/User option not set. Using default/).to_stdout_from_any_process 37 | expect(client.user).to eq('Administrator') 38 | end 39 | 40 | it 'allows the ssl_enabled attribute to be set' do 41 | expect_any_instance_of(Logger).to receive(:warn).with(/SSL is disabled/).and_return(true) 42 | options = { host: 'ilo.example.com', user: 'Administrator', password: 'secret123', ssl_enabled: false } 43 | client = described_class.new(options) 44 | expect(client.ssl_enabled).to eq(false) 45 | end 46 | 47 | it 'does not allow invalid ssl_enabled attributes' do 48 | options = { host: 'ilo.example.com', user: 'Administrator', password: 'secret123', ssl_enabled: 'bad' } 49 | expect { described_class.new(options) }.to raise_error(ILO_SDK::InvalidClient, /must be true or false/) 50 | end 51 | 52 | it 'allows the disable_proxy attribute to be set' do 53 | options = { host: 'ilo.example.com', user: 'Administrator', password: 'secret123', disable_proxy: true } 54 | client = described_class.new(options) 55 | expect(client.disable_proxy).to eq(true) 56 | end 57 | 58 | it 'allows the log level to be set' do 59 | options = { host: 'ilo.example.com', user: 'Administrator', password: 'secret123', log_level: :error } 60 | client = described_class.new(options) 61 | expect(client.log_level).to eq(:error) 62 | end 63 | 64 | it 'respects environment variables' do 65 | ENV['ILO_HOST'] = 'ilo.example.com' 66 | ENV['ILO_USER'] = 'Admin' 67 | ENV['ILO_PASSWORD'] = 'secret456' 68 | ENV['ILO_SSL_ENABLED'] = 'false' 69 | expect_any_instance_of(Logger).to receive(:warn).with(/SSL is disabled/).and_return(true) 70 | client = described_class.new 71 | expect(client.host).to eq('https://ilo.example.com') 72 | expect(client.user).to eq('Admin') 73 | expect(client.password).to eq('secret456') 74 | expect(client.ssl_enabled).to eq(false) 75 | ENV['ILO_SSL_ENABLED'] = 'true' 76 | client = described_class.new 77 | expect(client.ssl_enabled).to eq(true) 78 | end 79 | 80 | it 'does not allow invalid ssl_enabled attributes set as an environment variable' do 81 | ENV['ILO_SSL_ENABLED'] = 'bad' 82 | options = { host: 'ilo.example.com', user: 'Administrator', password: 'secret123' } 83 | expect { described_class.new(options) }.to raise_error(ILO_SDK::InvalidClient, /must be true or false/) 84 | end 85 | end 86 | end 87 | -------------------------------------------------------------------------------- /spec/unit/helpers/account_service_spec.rb: -------------------------------------------------------------------------------- 1 | require_relative './../../spec_helper' 2 | 3 | RSpec.describe ILO_SDK::Client do 4 | include_context 'shared context' 5 | 6 | describe '#userhref' do 7 | it 'makes a GET rest call' do 8 | body = { 9 | 'Items' => [ 10 | { 11 | 'UserName' => 'username', 12 | 'links' => { 13 | 'self' => { 14 | 'href' => '/redfish/v1/AccountService/Accounts/1/' 15 | } 16 | } 17 | } 18 | ] 19 | } 20 | fake_response = FakeResponse.new(body) 21 | expect(@client).to receive(:rest_get).with('/redfish/v1/AccountService/Accounts/').and_return(fake_response) 22 | href = @client.userhref('/redfish/v1/AccountService/Accounts/', 'username') 23 | expect(href).to eq('/redfish/v1/AccountService/Accounts/1/') 24 | end 25 | end 26 | 27 | describe '#get_users' do 28 | it 'makes a GET rest call' do 29 | body = { 30 | 'Items' => [ 31 | { 32 | 'UserName' => 'username', 33 | 'links' => { 34 | 'self' => { 35 | 'href' => '/redfish/v1/AccountService/Accounts/1/' 36 | } 37 | } 38 | } 39 | ] 40 | } 41 | fake_response = FakeResponse.new(body) 42 | expect(@client).to receive(:rest_get).with('/redfish/v1/AccountService/Accounts/').and_return(fake_response) 43 | users = @client.get_users 44 | expect(users).to eq(['username']) 45 | end 46 | end 47 | 48 | describe '#create_user' do 49 | it 'makes POST rest call' do 50 | new_action = { 51 | 'UserName' => 'username', 52 | 'Password' => 'password', 53 | 'Oem' => { 54 | 'Hp' => { 55 | 'LoginName' => 'username' 56 | } 57 | } 58 | } 59 | expect(@client).to receive(:rest_post).with('/redfish/v1/AccountService/Accounts/', body: new_action).and_return(FakeResponse.new) 60 | ret_val = @client.create_user('username', 'password') 61 | expect(ret_val).to eq(true) 62 | end 63 | end 64 | 65 | describe '#change_password' do 66 | it 'makes PATCH rest call' do 67 | new_action = { 68 | 'Password' => 'password' 69 | } 70 | expect(@client).to receive(:userhref).with('/redfish/v1/AccountService/Accounts/', 'username').and_return('/redfish/v1/AccountService/Accounts/1/') 71 | expect(@client).to receive(:rest_patch).with('/redfish/v1/AccountService/Accounts/1/', body: new_action).and_return(FakeResponse.new) 72 | ret_val = @client.change_password('username', 'password') 73 | expect(ret_val).to eq(true) 74 | end 75 | end 76 | 77 | describe '#delete_user' do 78 | it 'makes DELETE rest call' do 79 | expect(@client).to receive(:userhref).with('/redfish/v1/AccountService/Accounts/', 'username').and_return('/redfish/v1/AccountService/Accounts/1/') 80 | expect(@client).to receive(:rest_delete).with('/redfish/v1/AccountService/Accounts/1/').and_return(FakeResponse.new) 81 | ret_val = @client.delete_user('username') 82 | expect(ret_val).to eq(true) 83 | end 84 | end 85 | end 86 | -------------------------------------------------------------------------------- /spec/unit/helpers/bios_spec.rb: -------------------------------------------------------------------------------- 1 | require_relative './../../spec_helper' 2 | 3 | RSpec.describe ILO_SDK::Client do 4 | include_context 'shared context' 5 | 6 | let(:settings) do 7 | { 'key1' => 'val1', 'key2' => 'val2', 'key3' => 'val3' } 8 | end 9 | 10 | describe '#get_bios_settings' do 11 | it 'makes a GET rest call' do 12 | fake_response = FakeResponse.new(settings) 13 | expect(@client).to receive(:rest_get).with('/redfish/v1/Systems/1/bios/Settings/').and_return(fake_response) 14 | expect(@client.get_bios_settings).to eq(settings) 15 | end 16 | 17 | it 'allows the system_id to be set' do 18 | fake_response = FakeResponse.new(settings) 19 | expect(@client).to receive(:rest_get).with('/redfish/v1/Systems/3/bios/Settings/').and_return(fake_response) 20 | expect(@client.get_bios_settings(3)).to eq(settings) 21 | end 22 | end 23 | 24 | describe '#set_bios_settings' do 25 | it 'makes a PATCH rest call' do 26 | expect(@client).to receive(:rest_patch).with('/redfish/v1/Systems/1/bios/Settings/', body: settings).and_return(FakeResponse.new) 27 | expect(@client.set_bios_settings(settings)).to eq(true) 28 | end 29 | 30 | it 'allows the system_id to be set' do 31 | expect(@client).to receive(:rest_patch).with('/redfish/v1/Systems/3/bios/Settings/', body: settings).and_return(FakeResponse.new) 32 | @client.set_bios_settings(settings, 3) 33 | end 34 | 35 | it 'prints a warning if one is returned' do 36 | fake_response = FakeResponse.new('error' => 'Message') 37 | expect(@client).to receive(:rest_patch).with('/redfish/v1/Systems/1/bios/Settings/', body: settings).and_return(fake_response) 38 | expect(@client.logger).to receive(:warn).with('error' => 'Message').and_return true 39 | @client.set_bios_settings(settings) 40 | end 41 | end 42 | 43 | describe '#get_bios_baseconfig' do 44 | it 'makes a GET rest call' do 45 | fake_response = FakeResponse.new('BaseConfig' => 'default') 46 | expect(@client).to receive(:rest_get).with('/redfish/v1/Systems/1/bios/Settings/').and_return(fake_response) 47 | base_config = @client.get_bios_baseconfig 48 | expect(base_config).to eq('default') 49 | end 50 | end 51 | 52 | describe '#revert_bios' do 53 | it 'makes a PATCH rest call' do 54 | new_action = { 'BaseConfig' => 'default' } 55 | expect(@client).to receive(:rest_patch).with('/redfish/v1/systems/1/bios/Settings/', body: new_action).and_return(FakeResponse.new) 56 | ret_val = @client.revert_bios 57 | expect(ret_val).to eq(true) 58 | end 59 | end 60 | 61 | describe '#get_uefi_shell_startup' do 62 | it 'makes a GET rest call' do 63 | body = { 64 | 'UefiShellStartup' => 'UefiShellStartup', 65 | 'UefiShellStartupLocation' => 'UefiShellStartupLocation', 66 | 'UefiShellStartupUrl' => 'UefiShellStartupUrl' 67 | } 68 | fake_response = FakeResponse.new(body) 69 | expect(@client).to receive(:rest_get).with('/redfish/v1/Systems/1/bios/Settings/').and_return(fake_response) 70 | uefi_shell_startup = @client.get_uefi_shell_startup 71 | expect(uefi_shell_startup).to eq( 72 | 'UefiShellStartup' => 'UefiShellStartup', 73 | 'UefiShellStartupLocation' => 'UefiShellStartupLocation', 74 | 'UefiShellStartupUrl' => 'UefiShellStartupUrl' 75 | ) 76 | end 77 | end 78 | 79 | describe '#set_uefi_shell_startup' do 80 | it 'makes a PATCH rest call' do 81 | new_action = { 82 | 'UefiShellStartup' => 'uefi_shell_startup', 83 | 'UefiShellStartupLocation' => 'uefi_shell_startup_location', 84 | 'UefiShellStartupUrl' => 'uefi_shell_startup_url' 85 | } 86 | expect(@client).to receive(:rest_patch).with('/redfish/v1/Systems/1/bios/Settings/', body: new_action).and_return(FakeResponse.new) 87 | ret_val = @client.set_uefi_shell_startup('uefi_shell_startup', 'uefi_shell_startup_location', 'uefi_shell_startup_url') 88 | expect(ret_val).to eq(true) 89 | end 90 | end 91 | 92 | describe '#get_bios_dhcp' do 93 | it 'makes a GET rest call' do 94 | body = { 95 | 'Dhcpv4' => 'Enabled', 96 | 'Ipv4Address' => '0.0.0.0', 97 | 'Ipv4Gateway' => '0.0.0.0', 98 | 'Ipv4PrimaryDNS' => '0.0.0.0', 99 | 'Ipv4SecondaryDNS' => '0.0.0.0', 100 | 'Ipv4SubnetMask' => '0.0.0.0' 101 | } 102 | fake_response = FakeResponse.new(body) 103 | expect(@client).to receive(:rest_get).with('/redfish/v1/Systems/1/bios/Settings/').and_return(fake_response) 104 | bios_dhcp = @client.get_bios_dhcp 105 | expect(bios_dhcp).to eq( 106 | 'Dhcpv4' => 'Enabled', 107 | 'Ipv4Address' => '0.0.0.0', 108 | 'Ipv4Gateway' => '0.0.0.0', 109 | 'Ipv4PrimaryDNS' => '0.0.0.0', 110 | 'Ipv4SecondaryDNS' => '0.0.0.0', 111 | 'Ipv4SubnetMask' => '0.0.0.0' 112 | ) 113 | end 114 | end 115 | 116 | describe '#set_bios_dhcp' do 117 | it 'makes a PATCH rest call' do 118 | new_action = { 119 | 'Dhcpv4' => 'Enabled', 120 | 'Ipv4Address' => '0.0.0.0', 121 | 'Ipv4Gateway' => '0.0.0.0', 122 | 'Ipv4PrimaryDNS' => '0.0.0.0', 123 | 'Ipv4SecondaryDNS' => '0.0.0.0', 124 | 'Ipv4SubnetMask' => '0.0.0.0' 125 | } 126 | expect(@client).to receive(:rest_patch).with('/redfish/v1/Systems/1/bios/Settings/', body: new_action).and_return(FakeResponse.new) 127 | ret_val = @client.set_bios_dhcp('Enabled', '0.0.0.0', '0.0.0.0', '0.0.0.0', '0.0.0.0', '0.0.0.0') 128 | expect(ret_val).to eq(true) 129 | end 130 | end 131 | 132 | describe '#get_url_boot_file' do 133 | it 'makes a GET rest call' do 134 | fake_response = FakeResponse.new('UrlBootFile' => 'http://wwww.urlbootfiletest.iso') 135 | expect(@client).to receive(:rest_get).with('/redfish/v1/Systems/1/bios/Settings/').and_return(fake_response) 136 | url_boot_file = @client.get_url_boot_file 137 | expect(url_boot_file).to eq('http://wwww.urlbootfiletest.iso') 138 | end 139 | end 140 | 141 | describe '#set_url_boot_file' do 142 | it 'makes a PATCH rest call' do 143 | new_action = { 'UrlBootFile' => 'http://wwww.urlbootfiletest.iso' } 144 | expect(@client).to receive(:rest_patch).with('/redfish/v1/Systems/1/bios/Settings/', body: new_action).and_return(FakeResponse.new) 145 | ret_val = @client.set_url_boot_file('http://wwww.urlbootfiletest.iso') 146 | expect(ret_val).to eq(true) 147 | end 148 | end 149 | 150 | describe '#get_bios_service' do 151 | it 'makes a GET rest call' do 152 | body = { 153 | 'ServiceName' => 'John Doe', 154 | 'ServiceEmail' => 'john.doe@hpe.com' 155 | } 156 | fake_response = FakeResponse.new(body) 157 | expect(@client).to receive(:rest_get).with('/redfish/v1/Systems/1/bios/Settings/').and_return(fake_response) 158 | bios_service = @client.get_bios_service 159 | expect(bios_service).to eq( 160 | 'ServiceName' => 'John Doe', 161 | 'ServiceEmail' => 'john.doe@hpe.com' 162 | ) 163 | end 164 | end 165 | 166 | describe '#set_bios_service' do 167 | it 'makes a PATCH rest call' do 168 | new_action = { 169 | 'ServiceName' => 'John Doe', 170 | 'ServiceEmail' => 'john.doe@hpe.com' 171 | } 172 | expect(@client).to receive(:rest_patch).with('/redfish/v1/Systems/1/bios/Settings/', body: new_action).and_return(FakeResponse.new) 173 | ret_val = @client.set_bios_service('John Doe', 'john.doe@hpe.com') 174 | expect(ret_val).to eq(true) 175 | end 176 | end 177 | end 178 | -------------------------------------------------------------------------------- /spec/unit/helpers/boot_settings_spec.rb: -------------------------------------------------------------------------------- 1 | require_relative './../../spec_helper' 2 | 3 | RSpec.describe ILO_SDK::Client do 4 | include_context 'shared context' 5 | 6 | describe '#get_boot_baseconfig' do 7 | it 'makes a GET rest call' do 8 | fake_response = FakeResponse.new('BaseConfig' => 'default') 9 | expect(@client).to receive(:rest_get).with('/redfish/v1/Systems/1/bios/Boot/Settings/').and_return(fake_response) 10 | base_config = @client.get_boot_baseconfig 11 | expect(base_config).to eq('default') 12 | end 13 | end 14 | 15 | describe '#revert_boot' do 16 | it 'makes a PATCH rest call' do 17 | new_action = { 'BaseConfig' => 'default' } 18 | expect(@client).to receive(:rest_patch).with('/redfish/v1/systems/1/bios/Boot/Settings/', body: new_action).and_return(FakeResponse.new) 19 | ret_val = @client.revert_boot 20 | expect(ret_val).to eq(true) 21 | end 22 | end 23 | 24 | describe '#get_boot_order' do 25 | it 'makes a GET rest call' do 26 | fake_response = FakeResponse.new('PersistentBootConfigOrder' => 'PersistentBootConfigOrder') 27 | expect(@client).to receive(:rest_get).with('/redfish/v1/systems/1/bios/Boot/Settings/').and_return(fake_response) 28 | boot_order = @client.get_boot_order 29 | expect(boot_order).to eq('PersistentBootConfigOrder') 30 | end 31 | end 32 | 33 | describe '#set_boot_order' do 34 | it 'makes a PATCH rest call' do 35 | new_action = { 'PersistentBootConfigOrder' => 'PersistentBootConfigOrder' } 36 | expect(@client).to receive(:rest_patch).with('/redfish/v1/systems/1/bios/Boot/Settings/', body: new_action).and_return(FakeResponse.new) 37 | ret_val = @client.set_boot_order('PersistentBootConfigOrder') 38 | expect(ret_val).to eq(true) 39 | end 40 | end 41 | 42 | describe '#get_temporary_boot_order' do 43 | it 'makes a GET rest call' do 44 | body = { 45 | 'Boot' => { 46 | 'BootSourceOverrideTarget' => 'BootSourceOverrideTarget' 47 | } 48 | } 49 | fake_response = FakeResponse.new(body) 50 | expect(@client).to receive(:rest_get).with('/redfish/v1/Systems/1/').and_return(fake_response) 51 | temporary_boot_order = @client.get_temporary_boot_order 52 | expect(temporary_boot_order).to eq('BootSourceOverrideTarget') 53 | end 54 | end 55 | 56 | describe '#set_temporary_boot_order' do 57 | it 'makes a PATCH rest call' do 58 | new_action = { 59 | 'Boot' => { 60 | 'BootSourceOverrideTarget' => '1' 61 | } 62 | } 63 | body = { 64 | 'Boot' => { 65 | 'BootSourceOverrideSupported' => %w(1 2 3) 66 | } 67 | } 68 | fake_response = FakeResponse.new(body) 69 | expect(@client).to receive(:rest_get).with('/redfish/v1/Systems/1/').and_return(fake_response) 70 | expect(@client).to receive(:rest_patch).with('/redfish/v1/Systems/1/', body: new_action).and_return(FakeResponse.new) 71 | ret_val = @client.set_temporary_boot_order('1') 72 | expect(ret_val).to eq(true) 73 | end 74 | end 75 | end 76 | -------------------------------------------------------------------------------- /spec/unit/helpers/chassis_spec.rb: -------------------------------------------------------------------------------- 1 | require_relative './../../spec_helper' 2 | 3 | RSpec.describe ILO_SDK::Client do 4 | include_context 'shared context' 5 | 6 | describe '#get_power_metrics' do 7 | it 'makes a GET rest call' do 8 | body = { 9 | 'links' => { 10 | 'Member' => [ 11 | { 12 | 'href' => '/redfish/v1/Chassis/1/' 13 | } 14 | ] 15 | } 16 | } 17 | fake_response = FakeResponse.new(body) 18 | expect(@client).to receive(:rest_get).with('/redfish/v1/Chassis/').and_return(fake_response) 19 | body = { 20 | 'links' => { 21 | 'PowerMetrics' => { 22 | 'href' => '/redfish/v1/Chassis/PowerMetrics/' 23 | } 24 | } 25 | } 26 | fake_response = FakeResponse.new(body) 27 | expect(@client).to receive(:rest_get).with('/redfish/v1/Chassis/1/').and_return(fake_response) 28 | body = { 29 | 'PowerSupplies' => [ 30 | { 31 | 'LineInputVoltage' => '', 32 | 'LineInputVoltageType' => '', 33 | 'PowerCapacityWatts' => '', 34 | 'PowerSupplyType' => '', 35 | 'Status' => { 36 | 'Health' => '', 37 | 'State' => '' 38 | } 39 | } 40 | ], 41 | 'PowerCapacityWatts' => '', 42 | 'PowerConsumedWatts' => '' 43 | } 44 | fake_response = FakeResponse.new(body) 45 | expect(@client).to receive(:rest_get).with('/redfish/v1/Chassis/PowerMetrics/').and_return(fake_response) 46 | power_metrics = @client.get_power_metrics 47 | expect(power_metrics).to eq( 48 | @client.host => { 49 | 'PowerCapacityWatts' => '', 50 | 'PowerConsumedWatts' => '', 51 | 'PowerSupplies' => [ 52 | { 53 | 'LineInputVoltage' => '', 54 | 'LineInputVoltageType' => '', 55 | 'PowerCapacityWatts' => '', 56 | 'PowerSupplyType' => '', 57 | 'Health' => '', 58 | 'State' => '' 59 | } 60 | ] 61 | } 62 | ) 63 | end 64 | end 65 | 66 | describe '#get_thermal_metrics' do 67 | it 'makes a GET rest call' do 68 | body = { 69 | 'links' => { 70 | 'Member' => [ 71 | { 72 | 'href' => '/redfish/v1/Chassis/1/' 73 | } 74 | ] 75 | } 76 | } 77 | fake_response = FakeResponse.new(body) 78 | expect(@client).to receive(:rest_get).with('/redfish/v1/Chassis/').and_return(fake_response) 79 | body = { 80 | 'links' => { 81 | 'ThermalMetrics' => { 82 | 'href' => '/redfish/v1/Chassis/ThermalMetrics/' 83 | } 84 | } 85 | } 86 | fake_response = FakeResponse.new(body) 87 | expect(@client).to receive(:rest_get).with('/redfish/v1/Chassis/1/').and_return(fake_response) 88 | body = { 89 | 'Temperatures' => [ 90 | { 91 | 'PhysicalContext' => '', 92 | 'Name' => '', 93 | 'ReadingCelsius' => '', 94 | 'LowerThresholdCritical' => '', 95 | 'Status' => { 96 | 'Health' => '', 97 | 'State' => '' 98 | } 99 | } 100 | ] 101 | } 102 | fake_response = FakeResponse.new(body) 103 | expect(@client).to receive(:rest_get).with('/redfish/v1/Chassis/ThermalMetrics/').and_return(fake_response) 104 | thermal_metrics = @client.get_thermal_metrics 105 | expect(thermal_metrics).to eq( 106 | @client.host => [ 107 | { 108 | 'PhysicalContext' => '', 109 | 'Name' => '', 110 | 'CurrentReading' => '', 111 | 'CriticalThreshold' => '', 112 | 'Health' => '', 113 | 'State' => '' 114 | } 115 | ] 116 | ) 117 | end 118 | end 119 | end 120 | -------------------------------------------------------------------------------- /spec/unit/helpers/computer_system_spec.rb: -------------------------------------------------------------------------------- 1 | require_relative './../../spec_helper' 2 | 3 | RSpec.describe ILO_SDK::Client do 4 | include_context 'shared context' 5 | 6 | let(:settings) do 7 | { 'key1' => 'val1', 'key2' => 'val2', 'key3' => 'val3' } 8 | end 9 | 10 | describe '#get_system_settings' do 11 | it 'makes a GET rest call' do 12 | fake_response = FakeResponse.new(settings) 13 | expect(@client).to receive(:rest_get).with('/redfish/v1/Systems/1/').and_return(fake_response) 14 | expect(@client.get_system_settings).to eq(settings) 15 | end 16 | 17 | it 'allows the system_id to be set' do 18 | fake_response = FakeResponse.new(settings) 19 | expect(@client).to receive(:rest_get).with('/redfish/v1/Systems/3/').and_return(fake_response) 20 | expect(@client.get_system_settings(3)).to eq(settings) 21 | end 22 | end 23 | 24 | describe '#set_system_settings' do 25 | it 'makes a PATCH rest call' do 26 | expect(@client).to receive(:rest_patch).with('/redfish/v1/Systems/1/', body: settings).and_return(FakeResponse.new) 27 | expect(@client.set_system_settings(settings)).to eq(true) 28 | end 29 | 30 | it 'allows the system_id to be set' do 31 | expect(@client).to receive(:rest_patch).with('/redfish/v1/Systems/3/', body: settings).and_return(FakeResponse.new) 32 | @client.set_system_settings(settings, 3) 33 | end 34 | end 35 | 36 | describe '#get_asset_tag' do 37 | it 'makes a GET rest call' do 38 | expect(@client.logger).to receive(:warn).with(/Deprecated/).and_return(true) 39 | fake_response = FakeResponse.new('AssetTag' => 'HP001') 40 | expect(@client).to receive(:rest_get).with('/redfish/v1/Systems/1/').and_return(fake_response) 41 | state = @client.get_asset_tag 42 | expect(state).to eq('HP001') 43 | end 44 | end 45 | 46 | describe '#set_asset_tag' do 47 | it 'makes a PATCH rest call' do 48 | expect(@client.logger).to receive(:warn).with(/Deprecated/).and_return(true) 49 | options = { 'AssetTag' => 'HP002' } 50 | expect(@client).to receive(:rest_patch).with('/redfish/v1/Systems/1/', body: options).and_return(FakeResponse.new) 51 | ret_val = @client.set_asset_tag('HP002') 52 | expect(ret_val).to eq(true) 53 | end 54 | end 55 | 56 | describe '#get_indicator_led' do 57 | it 'makes a GET rest call' do 58 | expect(@client.logger).to receive(:warn).with(/Deprecated/).and_return(true) 59 | fake_response = FakeResponse.new('IndicatorLED' => 'Off') 60 | expect(@client).to receive(:rest_get).with('/redfish/v1/Systems/1/').and_return(fake_response) 61 | state = @client.get_indicator_led 62 | expect(state).to eq('Off') 63 | end 64 | end 65 | 66 | describe '#set_indicator_led' do 67 | it 'makes a PATCH rest call' do 68 | expect(@client.logger).to receive(:warn).with(/Deprecated/).and_return(true) 69 | options = { 'IndicatorLED' => :Lit } 70 | expect(@client).to receive(:rest_patch).with('/redfish/v1/Systems/1/', body: options).and_return(FakeResponse.new) 71 | ret_val = @client.set_indicator_led(:Lit) 72 | expect(ret_val).to eq(true) 73 | end 74 | end 75 | end 76 | -------------------------------------------------------------------------------- /spec/unit/helpers/date_time_spec.rb: -------------------------------------------------------------------------------- 1 | require_relative './../../spec_helper' 2 | 3 | RSpec.describe ILO_SDK::Client do 4 | include_context 'shared context' 5 | 6 | describe '#get_time_zone' do 7 | it 'makes a GET rest call' do 8 | body = { 9 | 'TimeZone' => { 10 | 'Name' => 'Africa/Azerbaijan' 11 | } 12 | } 13 | fake_response = FakeResponse.new(body) 14 | expect(@client).to receive(:rest_get).with('/redfish/v1/Managers/1/DateTime/').and_return(fake_response) 15 | time_zone = @client.get_time_zone 16 | expect(time_zone).to eq('Africa/Azerbaijan') 17 | end 18 | end 19 | 20 | describe '#set_time_zone' do 21 | it 'makes a GET and PATCH rest call' do 22 | body = { 23 | 'TimeZoneList' => [ 24 | { 25 | 'Index' => 0, 26 | 'Name' => 'Africa/Azerbaijan' 27 | } 28 | ] 29 | } 30 | fake_response = FakeResponse.new(body) 31 | expect(@client).to receive(:rest_get).with('/redfish/v1/Managers/1/DateTime/').and_return(fake_response) 32 | new_action = { 33 | 'TimeZone' => { 34 | 'Index' => 0 35 | } 36 | } 37 | expect(@client).to receive(:rest_patch).with('/redfish/v1/Managers/1/DateTime/', body: new_action).and_return(FakeResponse.new) 38 | ret_val = @client.set_time_zone('Africa/Azerbaijan') 39 | expect(ret_val).to eq(true) 40 | end 41 | end 42 | 43 | describe '#get_ntp' do 44 | it 'makes a GET rest call' do 45 | body = { 46 | 'Oem' => { 47 | 'Hp' => { 48 | 'DHCPv4' => { 49 | 'UseNTPServers' => false 50 | } 51 | } 52 | } 53 | } 54 | fake_response = FakeResponse.new(body) 55 | expect(@client).to receive(:rest_get).with('/redfish/v1/Managers/1/EthernetInterfaces/1/').and_return(fake_response) 56 | ntp = @client.get_ntp 57 | expect(ntp).to eq(false) 58 | end 59 | end 60 | 61 | describe '#set_ntp' do 62 | it 'makes a PATCH rest call' do 63 | new_action = { 64 | 'Oem' => { 65 | 'Hp' => { 66 | 'DHCPv4' => { 67 | 'UseNTPServers' => true 68 | } 69 | } 70 | } 71 | } 72 | expect(@client).to receive(:rest_patch).with('/redfish/v1/Managers/1/EthernetInterfaces/1/', body: new_action).and_return(FakeResponse.new) 73 | ret_val = @client.set_ntp(true) 74 | expect(ret_val).to eq(true) 75 | end 76 | end 77 | 78 | describe '#get_ntp_servers' do 79 | it 'makes a GET rest call' do 80 | fake_response = FakeResponse.new('StaticNTPServers' => '') 81 | expect(@client).to receive(:rest_get).with('/redfish/v1/Managers/1/DateTime/').and_return(fake_response) 82 | ntp_servers = @client.get_ntp_servers 83 | expect(ntp_servers).to eq('') 84 | end 85 | end 86 | 87 | describe '#set_ntp_servers' do 88 | it 'makes a SET rest call' do 89 | new_action = { 'StaticNTPServers' => '' } 90 | expect(@client).to receive(:rest_patch).with('/redfish/v1/Managers/1/DateTime/', body: new_action).and_return(FakeResponse.new) 91 | ret_val = @client.set_ntp_servers('') 92 | expect(ret_val).to eq(true) 93 | end 94 | end 95 | end 96 | -------------------------------------------------------------------------------- /spec/unit/helpers/ethernet_interface_helper_spec.rb: -------------------------------------------------------------------------------- 1 | require_relative './../../spec_helper' 2 | 3 | RSpec.describe ILO_SDK::Client do 4 | include_context 'shared context' 5 | 6 | describe '#get_ilo_ethernet_interface' do 7 | before(:all) do 8 | @settings = { 'key1' => 'val1', 'key2' => 'val2', 'key3' => 'val3' } 9 | end 10 | 11 | it 'makes a GET rest call' do 12 | fake_response = FakeResponse.new(@settings) 13 | expect(@client).to receive(:rest_get).with('/redfish/v1/Managers/1/EthernetInterfaces/1/').and_return(fake_response) 14 | expect(@client.get_ilo_ethernet_interface).to eq(@settings) 15 | end 16 | 17 | it 'allows the system_id to be set' do 18 | fake_response = FakeResponse.new(@settings) 19 | expect(@client).to receive(:rest_get).with('/redfish/v1/Managers/2/EthernetInterfaces/1/').and_return(fake_response) 20 | expect(@client.get_ilo_ethernet_interface(manager_id: 2)).to eq(@settings) 21 | end 22 | 23 | it 'allows system_id and ethernet_interface to be set' do 24 | fake_response = FakeResponse.new(@settings) 25 | expect(@client).to receive(:rest_get).with('/redfish/v1/Managers/2/EthernetInterfaces/2/').and_return(fake_response) 26 | expect(@client.get_ilo_ethernet_interface(manager_id: 2, ethernet_interface: 2)).to eq(@settings) 27 | end 28 | 29 | end 30 | 31 | describe '#set_ilo_dhcp' do 32 | before(:all) do 33 | @enable_dhcp_body = { 34 | 'Oem' => { 35 | 'Hp' => { 36 | 'DHCPv4' => { 37 | 'Enabled' => true, 38 | 'UseDNSServers' => true, 39 | 'UseDomainName' => true, 40 | 'UseGateway' => true, 41 | 'UseNTPServers' => true, 42 | 'UseStaticRoutes' => true, 43 | 'UseWINSServers' => true 44 | } 45 | } 46 | } 47 | } 48 | end 49 | 50 | it 'makes a PATCH rest call' do 51 | expect(@client).to receive(:rest_patch).with('/redfish/v1/Managers/1/EthernetInterfaces/1/', body: @enable_dhcp_body).and_return(FakeResponse.new) 52 | expect(@client.set_ilo_ipv4_dhcp).to eq(true) 53 | end 54 | 55 | it 'allows the system_id to be set' do 56 | expect(@client).to receive(:rest_patch).with('/redfish/v1/Managers/2/EthernetInterfaces/1/', body: @enable_dhcp_body).and_return(FakeResponse.new) 57 | expect(@client.set_ilo_ipv4_dhcp(manager_id: 2)).to eq(true) 58 | end 59 | 60 | it 'allows system_id and ethernet_interface to be set' do 61 | expect(@client).to receive(:rest_patch).with('/redfish/v1/Managers/2/EthernetInterfaces/2/', body: @enable_dhcp_body).and_return(FakeResponse.new) 62 | expect(@client.set_ilo_ipv4_dhcp(manager_id: 2, ethernet_interface: 2)).to eq(true) 63 | end 64 | end 65 | 66 | describe '#set_ilo_ipv4_static' do 67 | before(:all) do 68 | @body = { 69 | 'Oem' => { 'Hp' => { 'DHCPv4' => { 'Enabled' => false } } }, 70 | 'IPv4Addresses' => ['Address' => '192.168.1.1', 'SubnetMask' => '255.255.255.0', 'Gateway' => '0.0.0.0'] 71 | } 72 | end 73 | 74 | it 'makes a PATCH rest call' do 75 | expect(@client).to receive(:rest_patch).with('/redfish/v1/Managers/1/EthernetInterfaces/1/', body: @body).and_return(FakeResponse.new) 76 | expect(@client.set_ilo_ipv4_static(ip: '192.168.1.1', netmask: '255.255.255.0')).to eq(true) 77 | end 78 | 79 | it 'allows the gateway to be set' do 80 | body = Marshal.load(Marshal.dump(@body)) 81 | body['IPv4Addresses'][0]['Gateway'] = '192.168.1.254' 82 | expect(@client).to receive(:rest_patch).with('/redfish/v1/Managers/1/EthernetInterfaces/1/', body: body).and_return(FakeResponse.new) 83 | expect(@client.set_ilo_ipv4_static(ip: '192.168.1.1', netmask: '255.255.255.0', gateway: '192.168.1.254')).to eq(true) 84 | end 85 | 86 | it 'allows the system_id to be set' do 87 | expect(@client).to receive(:rest_patch).with('/redfish/v1/Managers/2/EthernetInterfaces/1/', body: @body).and_return(FakeResponse.new) 88 | expect(@client.set_ilo_ipv4_static(ip: '192.168.1.1', netmask: '255.255.255.0', manager_id: 2)).to eq(true) 89 | end 90 | 91 | it 'allows system_id and ethernet_interface to be set' do 92 | expect(@client).to receive(:rest_patch).with('/redfish/v1/Managers/2/EthernetInterfaces/2/', body: @body).and_return(FakeResponse.new) 93 | expect(@client.set_ilo_ipv4_static(ip: '192.168.1.1', netmask: '255.255.255.0', manager_id: 2, ethernet_interface: 2)).to eq(true) 94 | end 95 | end 96 | 97 | describe '#set_ilo_ipv4_dns_servers' do 98 | before(:all) do 99 | @dns_servers = ['2.2.2.2', '4.4.4.4', '8.8.8.8'] 100 | @body = { 'Oem' => { 'Hp' => { 'DHCPv4' => { 'UseDNSServers' => false }, 'IPv4' => { 'DNSServers' => @dns_servers } } } } 101 | end 102 | 103 | it 'makes a PATCH rest call' do 104 | expect(@client).to receive(:rest_patch).with('/redfish/v1/Managers/1/EthernetInterfaces/1/', body: @body).and_return(FakeResponse.new) 105 | expect(@client.set_ilo_ipv4_dns_servers(dns_servers: @dns_servers)).to eq(true) 106 | end 107 | 108 | it 'allows the system_id to be set' do 109 | expect(@client).to receive(:rest_patch).with('/redfish/v1/Managers/2/EthernetInterfaces/1/', body: @body).and_return(FakeResponse.new) 110 | expect(@client.set_ilo_ipv4_dns_servers(dns_servers: @dns_servers, manager_id: 2)).to eq(true) 111 | end 112 | 113 | it 'allows system_id and ethernet_interface to be set' do 114 | expect(@client).to receive(:rest_patch).with('/redfish/v1/Managers/2/EthernetInterfaces/2/', body: @body).and_return(FakeResponse.new) 115 | expect(@client.set_ilo_ipv4_dns_servers(dns_servers: @dns_servers, manager_id: 2, ethernet_interface: 2)).to eq(true) 116 | end 117 | end 118 | 119 | describe '#set_ilo_hostname' do 120 | before(:all) do 121 | @body = { 'Oem' => { 'Hp' => { 'HostName' => 'server-ilo' } } } 122 | end 123 | 124 | it 'makes a PATCH rest call' do 125 | expect(@client).to receive(:rest_patch).with('/redfish/v1/Managers/1/EthernetInterfaces/1/', body: @body).and_return(FakeResponse.new) 126 | expect(@client.set_ilo_hostname(hostname: 'server-ilo')).to eq(true) 127 | end 128 | 129 | it 'allows domain_name to be set' do 130 | body = Marshal.load(Marshal.dump(@body)) 131 | body['Oem']['Hp'].merge!('DHCPv4' => { 'UseDomainName' => false }, 'DHCPv6' => { 'UseDomainName' => false }) 132 | body['Oem']['Hp']['DomainName'] = 'domain.local' 133 | expect(@client).to receive(:rest_patch).with('/redfish/v1/Managers/1/EthernetInterfaces/1/', body: body).and_return(FakeResponse.new) 134 | expect(@client.set_ilo_hostname(hostname: 'server-ilo', domain_name: 'domain.local')).to eq(true) 135 | end 136 | 137 | it 'allows the system_id to be set' do 138 | expect(@client).to receive(:rest_patch).with('/redfish/v1/Managers/2/EthernetInterfaces/1/', body: @body).and_return(FakeResponse.new) 139 | expect(@client.set_ilo_hostname(hostname: 'server-ilo', manager_id: 2)).to eq(true) 140 | end 141 | 142 | it 'allows system_id and ethernet_interface to be set' do 143 | expect(@client).to receive(:rest_patch).with('/redfish/v1/Managers/2/EthernetInterfaces/2/', body: @body).and_return(FakeResponse.new) 144 | expect(@client.set_ilo_hostname(hostname: 'server-ilo', manager_id: 2, ethernet_interface: 2)).to eq(true) 145 | end 146 | end 147 | end 148 | -------------------------------------------------------------------------------- /spec/unit/helpers/firmware_update_spec.rb: -------------------------------------------------------------------------------- 1 | require_relative './../../spec_helper' 2 | 3 | RSpec.describe ILO_SDK::Client do 4 | include_context 'shared context' 5 | 6 | describe '#get_fw_version' do 7 | it 'makes a GET rest call' do 8 | body = { 9 | 'Current' => { 10 | 'SystemBMC' => [ 11 | { 12 | 'VersionString' => 2.5 13 | } 14 | ] 15 | } 16 | } 17 | fake_response = FakeResponse.new(body) 18 | expect(@client).to receive(:rest_get).with('/redfish/v1/Systems/1/FirmWareInventory/').and_return(fake_response) 19 | fw_version = @client.get_fw_version 20 | expect(fw_version).to eq(2.5) 21 | end 22 | end 23 | 24 | describe 'set_fw_upgrade' do 25 | it 'makes a POST rest call' do 26 | new_action = { 27 | 'Action' => 'InstallFromURI', 28 | 'FirmwareURI' => 'www.testuri.com', 29 | 'TPMOverrideFlag' => true 30 | } 31 | expect(@client).to receive(:rest_post).with('/redfish/v1/Managers/1/UpdateService/', body: new_action).and_return(FakeResponse.new) 32 | ret_val = @client.set_fw_upgrade('www.testuri.com') 33 | expect(ret_val).to eq(true) 34 | end 35 | end 36 | end 37 | -------------------------------------------------------------------------------- /spec/unit/helpers/https_cert_spec.rb: -------------------------------------------------------------------------------- 1 | require_relative './../../spec_helper' 2 | 3 | RSpec.describe ILO_SDK::Client do 4 | include_context 'shared context' 5 | 6 | describe '#get_certificate' do 7 | it 'it makes an HTTP call' do 8 | allow(Net::HTTP).to receive(:start) { 'fake_cert' } 9 | ret_val = @client.get_certificate 10 | expect(ret_val).to eq('fake_cert') 11 | end 12 | end 13 | 14 | describe '#import_certificate' do 15 | it 'makes a POST rest call' do 16 | certificate = '-----BEGIN CERTIFICATE----- 17 | skjfhsjkhjhsgdjkhsjdewrhghkjshgsdfghsdfkjhsdk 18 | -----END CERTIFICATE-----' 19 | new_action = { 20 | 'Action' => 'ImportCertificate', 21 | 'Certificate' => certificate 22 | } 23 | expect(@client).to receive(:rest_post).with('/redfish/v1/Managers/1/SecurityService/HttpsCert/', body: new_action).and_return(FakeResponse.new) 24 | ret_val = @client.import_certificate(certificate) 25 | expect(ret_val).to eq(true) 26 | end 27 | end 28 | 29 | describe '#generate_csr' do 30 | it 'makes a POST rest call' do 31 | new_action = { 32 | 'Action' => 'GenerateCSR', 33 | 'Country' => 'US', 34 | 'State' => 'Texas', 35 | 'City' => 'Houston', 36 | 'OrgName' => 'Hewlett Packard Enterprise Company', 37 | 'OrgUnit' => 'ISS', 38 | 'CommonName' => 'ILO123.americas.hpqcorp.net' 39 | } 40 | expect(@client).to receive(:rest_post).with('/redfish/v1/Managers/1/SecurityService/HttpsCert/', body: new_action).and_return(FakeResponse.new) 41 | ret_val = @client.generate_csr('US', 'Texas', 'Houston', 'Hewlett Packard Enterprise Company', 'ISS', 'ILO123.americas.hpqcorp.net') 42 | expect(ret_val).to eq(true) 43 | end 44 | end 45 | 46 | describe '#get_csr' do 47 | it 'makes a GET rest call' do 48 | certificate_signing_request = '-----BEGIN CERTIFICATE REQUEST----- 49 | MIIDJzCCAg8CAQAwgZAxJDAiBgNVBAMMG0lMTzEyMy5hbWVyaWNhcy5ocHFjb3Jw 50 | -----END CERTIFICATE REQUEST-----' 51 | body = { 52 | 'CertificateSigningRequest' => certificate_signing_request 53 | } 54 | fake_response = FakeResponse.new(body) 55 | expect(@client).to receive(:rest_get).with('/redfish/v1/Managers/1/SecurityService/HttpsCert/').and_return(fake_response) 56 | csr = @client.get_csr 57 | expect(csr).to eq(certificate_signing_request) 58 | end 59 | end 60 | end 61 | -------------------------------------------------------------------------------- /spec/unit/helpers/log_entry_spec.rb: -------------------------------------------------------------------------------- 1 | require_relative './../../spec_helper' 2 | 3 | RSpec.describe ILO_SDK::Client do 4 | include_context 'shared context' 5 | 6 | describe '#uri_for_log_type' do 7 | it 'gets the IEL logs URI' do 8 | expect(@client.uri_for_log_type('IEL')).to eq('/redfish/v1/Managers/1/LogServices/IEL/') 9 | end 10 | 11 | it 'gets the IML logs URI' do 12 | expect(@client.uri_for_log_type('IML')).to eq('/redfish/v1/Systems/1/LogServices/IML/') 13 | end 14 | 15 | it 'converts the type to upcase' do 16 | expect(@client.uri_for_log_type('iml')).to eq('/redfish/v1/Systems/1/LogServices/IML/') 17 | end 18 | 19 | it 'allows you to pass in a resource ID' do 20 | expect(@client.uri_for_log_type('IML', 2)).to eq('/redfish/v1/Systems/2/LogServices/IML/') 21 | end 22 | 23 | it 'fails for invalid resource types' do 24 | expect { @client.uri_for_log_type('Fake') }.to raise_error(/Invalid log_type/) 25 | end 26 | end 27 | 28 | describe '#clear_logs' do 29 | let(:new_action) { { 'Action' => 'ClearLog' } } 30 | 31 | it 'makes a POST rest call for IEL logs' do 32 | log_type = 'IEL' 33 | expect(@client).to receive(:rest_post).with("/redfish/v1/Managers/1/LogServices/#{log_type}/", body: new_action) 34 | .and_return(FakeResponse.new) 35 | ret_val = @client.clear_logs(log_type) 36 | expect(ret_val).to eq(true) 37 | end 38 | 39 | it 'makes a POST rest call for IML logs' do 40 | log_type = 'IML' 41 | expect(@client).to receive(:rest_post).with("/redfish/v1/Systems/1/LogServices/#{log_type}/", body: new_action) 42 | .and_return(FakeResponse.new) 43 | ret_val = @client.clear_logs(log_type) 44 | expect(ret_val).to eq(true) 45 | end 46 | end 47 | 48 | describe '#logs_empty?' do 49 | before :each do 50 | body = { 51 | 'Items' => [ 52 | { 'it' => 1 }, 53 | { 'it' => 2 } 54 | ] 55 | } 56 | @fake_response = FakeResponse.new(body) 57 | end 58 | 59 | it 'makes a GET rest call for IEL logs' do 60 | log_type = 'IEL' 61 | expect(@client).to receive(:rest_get).with("/redfish/v1/Managers/1/LogServices/#{log_type}/Entries/") 62 | .and_return(@fake_response) 63 | ret_val = @client.logs_empty?(log_type) 64 | expect(ret_val).to eq(false) 65 | end 66 | 67 | it 'makes a GET rest call for IML logs' do 68 | log_type = 'IML' 69 | expect(@client).to receive(:rest_get).with("/redfish/v1/Systems/1/LogServices/#{log_type}/Entries/") 70 | .and_return(@fake_response) 71 | ret_val = @client.logs_empty?(log_type) 72 | expect(ret_val).to eq(false) 73 | end 74 | end 75 | 76 | describe '#get_logs' do 77 | before :each do 78 | @duration = 10 # (hours) 79 | @now = Time.now.utc 80 | @entries = [ 81 | { 82 | 'Severity' => 'OK', 83 | 'Message' => 'First IEL Log', 84 | 'Created' => (@now - (@duration * 3600) + 2).to_s # In the time range 85 | }, 86 | { 87 | 'Severity' => 'OK', 88 | 'Message' => 'Second IEL Log', 89 | 'Created' => (@now - (@duration * 3600) + 1).to_s # In the time range 90 | }, 91 | { 92 | 'Severity' => 'OK', 93 | 'Message' => 'Third IEL Log', 94 | 'Created' => (@now - (@duration * 3600)).to_s # Outside the time range 95 | } 96 | ] 97 | @fake_response = FakeResponse.new('Items' => @entries) 98 | end 99 | 100 | it 'makes a GET rest call for IEL logs' do 101 | log_type = 'IEL' 102 | expect(@client).to receive(:rest_get).with("/redfish/v1/Managers/1/LogServices/#{log_type}/Entries/") 103 | .and_return(@fake_response) 104 | log_entries = @client.get_logs('OK', @duration, log_type) 105 | expect(log_entries).to eq([@entries[0], @entries[1]]) 106 | end 107 | 108 | it 'makes a GET rest call for IML logs' do 109 | log_type = 'IML' 110 | expect(@client).to receive(:rest_get).with("/redfish/v1/Systems/1/LogServices/#{log_type}/Entries/") 111 | .and_return(@fake_response) 112 | log_entries = @client.get_logs(:ok, @duration, log_type) 113 | expect(log_entries).to eq([@entries[0], @entries[1]]) 114 | end 115 | end 116 | end 117 | -------------------------------------------------------------------------------- /spec/unit/helpers/manager_account_spec.rb: -------------------------------------------------------------------------------- 1 | require_relative './../../spec_helper' 2 | 3 | RSpec.describe ILO_SDK::Client do 4 | include_context 'shared context' 5 | 6 | describe '#get_account_privileges' do 7 | it 'makes a GET rest call' do 8 | body = { 9 | 'Items' => [ 10 | { 11 | 'Id' => '1', 12 | 'Oem' => { 13 | 'Hp' => { 14 | 'LoginName' => 'test1', 15 | 'Privileges' => { 16 | 'LoginPriv' => true, 17 | 'RemoteConsolePriv' => true, 18 | 'UserConfigPriv' => true, 19 | 'VirtualMediaPriv' => true, 20 | 'VirtualPowerAndResetPriv' => true, 21 | 'iLOConfigPriv' => true 22 | } 23 | } 24 | } 25 | }, 26 | { 27 | 'Id' => '2', 28 | 'Oem' => { 29 | 'Hp' => { 30 | 'LoginName' => 'test2', 31 | 'Privileges' => { 32 | 'LoginPriv' => false, 33 | 'RemoteConsolePriv' => false, 34 | 'UserConfigPriv' => false, 35 | 'VirtualMediaPriv' => false, 36 | 'VirtualPowerAndResetPriv' => false, 37 | 'iLOConfigPriv' => false 38 | } 39 | } 40 | } 41 | } 42 | ] 43 | } 44 | fake_response = FakeResponse.new(body) 45 | expect(@client).to receive(:rest_get).with('/redfish/v1/AccountService/Accounts/').and_return(fake_response) 46 | privileges = @client.get_account_privileges('test1') 47 | expect(privileges).to eq(body['Items'][0]['Oem']['Hp']['Privileges']) 48 | end 49 | end 50 | 51 | describe '#set_account_privileges' do 52 | it 'makes a GET and a PATCH rest call' do 53 | body = { 54 | 'Items' => [ 55 | { 56 | 'Id' => '1', 57 | 'Oem' => { 58 | 'Hp' => { 59 | 'LoginName' => 'test1', 60 | 'Privileges' => { 61 | 'LoginPriv' => true, 62 | 'RemoteConsolePriv' => true, 63 | 'UserConfigPriv' => true, 64 | 'VirtualMediaPriv' => true, 65 | 'VirtualPowerAndResetPriv' => true, 66 | 'iLOConfigPriv' => true 67 | } 68 | } 69 | } 70 | }, 71 | { 72 | 'Id' => '2', 73 | 'Oem' => { 74 | 'Hp' => { 75 | 'LoginName' => 'test2', 76 | 'Privileges' => { 77 | 'LoginPriv' => false, 78 | 'RemoteConsolePriv' => false, 79 | 'UserConfigPriv' => false, 80 | 'VirtualMediaPriv' => false, 81 | 'VirtualPowerAndResetPriv' => false, 82 | 'iLOConfigPriv' => false 83 | } 84 | } 85 | } 86 | } 87 | ] 88 | } 89 | fake_response = FakeResponse.new(body) 90 | expect(@client).to receive(:rest_get).with('/redfish/v1/AccountService/Accounts/').and_return(fake_response) 91 | username = 'test1' 92 | privileges = { 93 | 'LoginPriv' => false, 94 | 'RemoteConsolePriv' => false, 95 | 'UserConfigPriv' => false, 96 | 'VirtualMediaPriv' => false, 97 | 'VirtualPowerAndResetPriv' => false, 98 | 'iLOConfigPriv' => false 99 | } 100 | new_action = { 101 | 'Oem' => { 102 | 'Hp' => { 103 | 'Privileges' => privileges 104 | } 105 | } 106 | } 107 | expect(@client).to receive(:rest_patch).with('/redfish/v1/AccountService/Accounts/1/', body: new_action).and_return(FakeResponse.new) 108 | ret_val = @client.set_account_privileges(username, privileges) 109 | expect(ret_val).to eq(true) 110 | end 111 | 112 | it 'makes a GET and a PATCH (only on some attributes) rest call' do 113 | body = { 114 | 'Items' => [ 115 | { 116 | 'Id' => '1', 117 | 'Oem' => { 118 | 'Hp' => { 119 | 'LoginName' => 'test1', 120 | 'Privileges' => { 121 | 'LoginPriv' => true, 122 | 'RemoteConsolePriv' => true, 123 | 'UserConfigPriv' => true, 124 | 'VirtualMediaPriv' => true, 125 | 'VirtualPowerAndResetPriv' => true, 126 | 'iLOConfigPriv' => true 127 | } 128 | } 129 | } 130 | }, 131 | { 132 | 'Id' => '2', 133 | 'Oem' => { 134 | 'Hp' => { 135 | 'LoginName' => 'test2', 136 | 'Privileges' => { 137 | 'LoginPriv' => false, 138 | 'RemoteConsolePriv' => false, 139 | 'UserConfigPriv' => false, 140 | 'VirtualMediaPriv' => false, 141 | 'VirtualPowerAndResetPriv' => false, 142 | 'iLOConfigPriv' => false 143 | } 144 | } 145 | } 146 | } 147 | ] 148 | } 149 | fake_response = FakeResponse.new(body) 150 | expect(@client).to receive(:rest_get).with('/redfish/v1/AccountService/Accounts/').and_return(fake_response) 151 | username = 'test1' 152 | privileges = { 153 | 'LoginPriv' => false, 154 | 'RemoteConsolePriv' => false, 155 | 'UserConfigPriv' => false 156 | } 157 | new_action = { 158 | 'Oem' => { 159 | 'Hp' => { 160 | 'Privileges' => privileges 161 | } 162 | } 163 | } 164 | expect(@client).to receive(:rest_patch).with('/redfish/v1/AccountService/Accounts/1/', body: new_action).and_return(FakeResponse.new) 165 | ret_val = @client.set_account_privileges(username, privileges) 166 | expect(ret_val).to eq(true) 167 | end 168 | end 169 | end 170 | -------------------------------------------------------------------------------- /spec/unit/helpers/manager_network_protocol_spec.rb: -------------------------------------------------------------------------------- 1 | require_relative './../../spec_helper' 2 | 3 | RSpec.describe ILO_SDK::Client do 4 | include_context 'shared context' 5 | 6 | describe '#get_timeout' do 7 | it 'makes a GET rest call' do 8 | fake_response = FakeResponse.new('SessionTimeoutMinutes' => 60) 9 | expect(@client).to receive(:rest_get).with('/redfish/v1/Managers/1/NetworkService/').and_return(fake_response) 10 | timeout = @client.get_timeout 11 | expect(timeout).to eq(60) 12 | end 13 | end 14 | 15 | describe '#set_timeout' do 16 | it 'makes a PATCH rest call' do 17 | new_action = { 'SessionTimeoutMinutes' => 60 } 18 | expect(@client).to receive(:rest_patch).with('/redfish/v1/Managers/1/NetworkService/', body: new_action).and_return(FakeResponse.new) 19 | ret_val = @client.set_timeout(60) 20 | expect(ret_val).to eq(true) 21 | end 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /spec/unit/helpers/power_spec.rb: -------------------------------------------------------------------------------- 1 | require_relative './../../spec_helper' 2 | 3 | RSpec.describe ILO_SDK::Client do 4 | include_context 'shared context' 5 | 6 | describe '#get_power_state' do 7 | it 'makes a GET rest call' do 8 | fake_response = FakeResponse.new('PowerState' => 'On') 9 | expect(@client).to receive(:rest_get).with('/redfish/v1/Systems/1/').and_return(fake_response) 10 | power_state = @client.get_power_state 11 | expect(power_state).to eq('On') 12 | end 13 | end 14 | 15 | describe '#set_power_state' do 16 | it 'makes a POST rest call' do 17 | new_action = { 'Action' => 'Reset', 'ResetType' => 'ForceRestart' } 18 | expect(@client).to receive(:rest_post).with('/redfish/v1/Systems/1/', body: new_action).and_return(FakeResponse.new) 19 | ret_val = @client.set_power_state('ForceRestart') 20 | expect(ret_val).to eq(true) 21 | end 22 | end 23 | 24 | describe '#reset_ilo' do 25 | it 'makes a POST rest call' do 26 | new_action = { 'Action' => 'Reset' } 27 | expect(@client).to receive(:rest_post).with('/redfish/v1/Managers/1/', body: new_action).and_return(FakeResponse.new) 28 | ret_val = @client.reset_ilo 29 | expect(ret_val).to eq(true) 30 | end 31 | end 32 | end 33 | -------------------------------------------------------------------------------- /spec/unit/helpers/secure_boot_spec.rb: -------------------------------------------------------------------------------- 1 | require_relative './../../spec_helper' 2 | 3 | RSpec.describe ILO_SDK::Client do 4 | include_context 'shared context' 5 | 6 | describe '#get_uefi_secure_boot' do 7 | it 'makes a GET rest call' do 8 | fake_response = FakeResponse.new('SecureBootEnable' => true) 9 | expect(@client).to receive(:rest_get).with('/redfish/v1/Systems/1/SecureBoot/').and_return(fake_response) 10 | secure_boot = @client.get_uefi_secure_boot 11 | expect(secure_boot).to eq(true) 12 | end 13 | end 14 | 15 | describe '#set_uefi_secure_boot' do 16 | it 'makes a PATCH rest call' do 17 | new_action = { 'SecureBootEnable' => true } 18 | expect(@client).to receive(:rest_patch).with('/redfish/v1/Systems/1/SecureBoot/', body: new_action).and_return(FakeResponse.new) 19 | ret_val = @client.set_uefi_secure_boot(true) 20 | expect(ret_val).to eq(true) 21 | end 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /spec/unit/helpers/service_root_spec.rb: -------------------------------------------------------------------------------- 1 | require_relative './../../spec_helper' 2 | 3 | RSpec.describe ILO_SDK::Client do 4 | include_context 'shared context' 5 | 6 | describe '#get_schema' do 7 | it 'makes a GET rest call' do 8 | body = { 9 | 'Items' => [ 10 | { 11 | 'Schema' => 'AccountService.1.0.0', 12 | 'Location' => [ 13 | { 14 | 'Uri' => { 15 | 'extref' => '/redfish/v1/SchemaStore/en/AccountService.json/' 16 | } 17 | } 18 | ] 19 | }, 20 | { 21 | 'Schema' => 'BaseNetworkAdapter.1.1.0', 22 | 'Location' => [ 23 | { 24 | 'Uri' => { 25 | 'extref' => '/redfish/v1/SchemaStore/en/BaseNetworkAdapter.json/' 26 | } 27 | } 28 | ] 29 | } 30 | ] 31 | } 32 | fake_response = FakeResponse.new(body) 33 | expect(@client).to receive(:rest_get).with('/redfish/v1/Schemas/').and_return(fake_response) 34 | body = { 35 | 'title' => 'AccountService.1.0.0' 36 | } 37 | fake_response = FakeResponse.new(body) 38 | expect(@client).to receive(:rest_get).with('/redfish/v1/SchemaStore/en/AccountService.json/').and_return(fake_response) 39 | schema = @client.get_schema('AccountService') 40 | expect(schema).to eq(['title' => 'AccountService.1.0.0']) 41 | end 42 | end 43 | 44 | describe '#get_registry' do 45 | it 'makes a GET rest call' do 46 | body = { 47 | 'Items' => [ 48 | { 49 | 'Schema' => 'Base.0.10.0', 50 | 'Location' => [ 51 | { 52 | 'Uri' => { 53 | 'extref' => '/redfish/v1/RegistryStore/registries/en/Base.json/' 54 | } 55 | } 56 | ] 57 | }, 58 | { 59 | 'Schema' => 'HpCommon.0.10.0', 60 | 'Location' => [ 61 | { 62 | 'Uri' => { 63 | 'extref' => '/redfish/v1/RegistryStore/registries/en/HpCommon.json/' 64 | } 65 | } 66 | ] 67 | } 68 | ] 69 | } 70 | fake_response = FakeResponse.new(body) 71 | expect(@client).to receive(:rest_get).with('/redfish/v1/Registries/').and_return(fake_response) 72 | body = { 73 | 'Name' => 'Base Message Registry' 74 | } 75 | fake_response = FakeResponse.new(body) 76 | expect(@client).to receive(:rest_get).with('/redfish/v1/RegistryStore/registries/en/Base.json/').and_return(fake_response) 77 | registry = @client.get_registry('Base') 78 | expect(registry).to eq(['Name' => 'Base Message Registry']) 79 | end 80 | end 81 | end 82 | -------------------------------------------------------------------------------- /spec/unit/helpers/snmp_service_spec.rb: -------------------------------------------------------------------------------- 1 | require_relative './../../spec_helper' 2 | 3 | RSpec.describe ILO_SDK::Client do 4 | include_context 'shared context' 5 | 6 | describe '#get_snmp_mode' do 7 | it 'makes a GET rest call' do 8 | fake_response = FakeResponse.new('Mode' => 'Agentless') 9 | expect(@client).to receive(:rest_get).with('/redfish/v1/Managers/1/SnmpService/').and_return(fake_response) 10 | snmp_mode = @client.get_snmp_mode 11 | expect(snmp_mode).to eq('Agentless') 12 | end 13 | end 14 | 15 | describe '#get_snmp_alerts_enabled' do 16 | it 'makes a GET rest call' do 17 | fake_response = FakeResponse.new('AlertsEnabled' => false) 18 | expect(@client).to receive(:rest_get).with('/redfish/v1/Managers/1/SnmpService/').and_return(fake_response) 19 | snmp_alerts_enabled = @client.get_snmp_alerts_enabled 20 | expect(snmp_alerts_enabled).to eq(false) 21 | end 22 | end 23 | 24 | describe '#set_snmp' do 25 | it 'makes a PATCH rest call' do 26 | mode = 'Agentless' 27 | alerts_enabled = true 28 | new_action = { 'Mode' => mode, 'AlertsEnabled' => alerts_enabled } 29 | expect(@client).to receive(:rest_patch).with('/redfish/v1/Managers/1/SnmpService/', body: new_action).and_return(FakeResponse.new) 30 | ret_val = @client.set_snmp(mode, alerts_enabled) 31 | expect(ret_val).to eq(true) 32 | end 33 | end 34 | end 35 | -------------------------------------------------------------------------------- /spec/unit/helpers/virtual_media_spec.rb: -------------------------------------------------------------------------------- 1 | require_relative './../../spec_helper' 2 | 3 | RSpec.describe ILO_SDK::Client do 4 | include_context 'shared context' 5 | 6 | describe '#get_virtual_media' do 7 | it 'makes a GET rest call' do 8 | body = { 9 | 'links' => { 10 | 'Member' => [ 11 | { 12 | 'href' => '/redfish/v1/Managers/1/VirtualMedia/1/' 13 | }, 14 | { 15 | 'href' => '/redfish/v1/Managers/1/VirtualMedia/2/' 16 | } 17 | ] 18 | } 19 | } 20 | fake_response = FakeResponse.new(body) 21 | expect(@client).to receive(:rest_get).with('/redfish/v1/Managers/1/VirtualMedia/').and_return(fake_response) 22 | body = { 23 | 'Id' => '1', 24 | 'Image' => '', 25 | 'MediaTypes' => %w(Floppy USBStick) 26 | } 27 | fake_response = FakeResponse.new(body) 28 | expect(@client).to receive(:rest_get).with('/redfish/v1/Managers/1/VirtualMedia/1/').and_return(fake_response) 29 | body = { 30 | 'Id' => '2', 31 | 'Image' => '', 32 | 'MediaTypes' => %w(CD DVD) 33 | } 34 | fake_response = FakeResponse.new(body) 35 | expect(@client).to receive(:rest_get).with('/redfish/v1/Managers/1/VirtualMedia/2/').and_return(fake_response) 36 | media = @client.get_virtual_media 37 | expect(media).to eq( 38 | '1' => { 39 | 'Image' => '', 40 | 'MediaTypes' => %w(Floppy USBStick) 41 | }, 42 | '2' => { 43 | 'Image' => '', 44 | 'MediaTypes' => %w(CD DVD) 45 | } 46 | ) 47 | end 48 | end 49 | 50 | describe '#virtual_media_inserted?' do 51 | it 'makes a GET rest call' do 52 | id = 1 53 | fake_response = FakeResponse.new('Inserted' => true) 54 | expect(@client).to receive(:rest_get).with("/redfish/v1/Managers/1/VirtualMedia/#{id}/").and_return(fake_response) 55 | media_inserted = @client.virtual_media_inserted?(id) 56 | expect(media_inserted).to eq(true) 57 | end 58 | end 59 | 60 | describe '#insert_virtual_media' do 61 | it 'makes a POST rest call' do 62 | id = 1 63 | image = '' 64 | new_action = { 65 | 'Action' => 'InsertVirtualMedia', 66 | 'Target' => '/Oem/Hp', 67 | 'Image' => image 68 | } 69 | expect(@client).to receive(:rest_post).with("/redfish/v1/Managers/1/VirtualMedia/#{id}/", body: new_action).and_return(FakeResponse.new) 70 | ret_val = @client.insert_virtual_media(id, image) 71 | expect(ret_val).to eq(true) 72 | end 73 | end 74 | 75 | describe '#eject_virtual_media' do 76 | it 'makes a POST rest call' do 77 | id = 1 78 | new_action = { 79 | 'Action' => 'EjectVirtualMedia', 80 | 'Target' => '/Oem/Hp' 81 | } 82 | expect(@client).to receive(:rest_post).with("/redfish/v1/Managers/1/VirtualMedia/#{id}/", body: new_action).and_return(FakeResponse.new) 83 | ret_val = @client.eject_virtual_media(id) 84 | expect(ret_val).to eq(true) 85 | end 86 | end 87 | end 88 | -------------------------------------------------------------------------------- /spec/unit/rest_spec.rb: -------------------------------------------------------------------------------- 1 | require_relative './../spec_helper' 2 | 3 | RSpec.describe ILO_SDK::Client do 4 | include_context 'shared context' 5 | 6 | let(:path) { '/redfish/v1/fake' } 7 | let(:data) { { 'name' => 'Fake', 'description' => 'Fake Resource', 'uri' => path } } 8 | 9 | describe '#rest_api' do 10 | before :each do 11 | fake_response = FakeResponse.new({ name: 'New' }, 200, location: path) 12 | allow_any_instance_of(Net::HTTP).to receive(:request).and_return(fake_response) 13 | end 14 | 15 | it 'requires a path' do 16 | expect { @client.rest_api(:get, nil) }.to raise_error(ILO_SDK::InvalidRequest, /Must specify path/) 17 | end 18 | 19 | it 'logs the request type and path (debug level)' do 20 | @client.logger.level = @client.logger.class.const_get('DEBUG') 21 | %w(get post put patch delete).each do |type| 22 | expect { @client.rest_api(type, path) } 23 | .to output(/Making :#{type} rest call to #{@client.host + path}/).to_stdout_from_any_process 24 | end 25 | end 26 | 27 | it 'respects the disable_proxy client option' do 28 | @client.disable_proxy = true 29 | expect(Net::HTTP).to receive(:new).with(anything, anything, nil, nil).and_raise('Fake Error') 30 | expect { @client.rest_api(:get, path) }.to raise_error('Fake Error') 31 | end 32 | 33 | it 'does not disable the proxy unless the disable_proxy client option is set' do 34 | expect(Net::HTTP).to receive(:new).with(anything, anything).and_raise('Fake Error') 35 | expect { @client.rest_api(:get, path) }.to raise_error('Fake Error') 36 | end 37 | 38 | it 'raises an error when the ssl validation fails' do 39 | allow_any_instance_of(Net::HTTP).to receive(:request).and_raise(OpenSSL::SSL::SSLError, 'Msg') 40 | expect(@client.logger).to receive(:error).with(/SSL verification failed/) 41 | expect { @client.rest_api(:get, path) }.to raise_error(OpenSSL::SSL::SSLError) 42 | end 43 | end 44 | 45 | describe '#rest_get' do 46 | it 'calls rest_api' do 47 | expect(@client).to receive(:rest_api).with(:get, path, {}) 48 | @client.rest_get(path) 49 | end 50 | end 51 | 52 | describe '#rest_post' do 53 | it 'calls rest_api' do 54 | expect(@client).to receive(:rest_api).with(:post, path, body: data) 55 | @client.rest_post(path, body: data) 56 | end 57 | 58 | it 'has default options and api_ver' do 59 | expect(@client).to receive(:rest_api).with(:post, path, {}) 60 | @client.rest_post(path) 61 | end 62 | end 63 | 64 | describe '#rest_put' do 65 | it 'calls rest_api' do 66 | expect(@client).to receive(:rest_api).with(:put, path, {}) 67 | @client.rest_put(path, {}) 68 | end 69 | 70 | it 'has default options and api_ver' do 71 | expect(@client).to receive(:rest_api).with(:put, path, {}) 72 | @client.rest_put(path) 73 | end 74 | end 75 | 76 | describe '#rest_patch' do 77 | it 'calls rest_api' do 78 | expect(@client).to receive(:rest_api).with(:patch, path, {}) 79 | @client.rest_patch(path, {}) 80 | end 81 | 82 | it 'has default options and api_ver' do 83 | expect(@client).to receive(:rest_api).with(:patch, path, {}) 84 | @client.rest_patch(path) 85 | end 86 | end 87 | 88 | describe '#rest_delete' do 89 | it 'calls rest_api' do 90 | expect(@client).to receive(:rest_api).with(:delete, path, {}) 91 | @client.rest_delete(path, {}) 92 | end 93 | 94 | it 'has default options and api_ver' do 95 | expect(@client).to receive(:rest_api).with(:delete, path, {}) 96 | @client.rest_delete(path) 97 | end 98 | end 99 | 100 | describe '#response_handler' do 101 | it 'returns the JSON-parsed body for 200 status' do 102 | expect(@client.response_handler(FakeResponse.new(data))).to eq(data) 103 | end 104 | 105 | it 'returns the body if it cannot be JSON-parsed for 200 status' do 106 | expect_any_instance_of(Logger).to receive(:warn).with(/Failed to parse JSON response/).and_return(true) 107 | expect(@client.response_handler(FakeResponse.new('Fake JSON'))).to eq('Fake JSON') 108 | end 109 | 110 | it 'returns the JSON-parsed body for 201 status' do 111 | expect(@client.response_handler(FakeResponse.new(data, 201))).to eq(data) 112 | end 113 | 114 | # it 'waits on the task completion for 202 status' do 115 | # initial_response = FakeResponse.new(data, 202, 'location' => '/rest/task/fake') 116 | # wait_response = FakeResponse.new({}, 200, 'associatedResource' => { 'resourceUri' => data['uri'] }) 117 | # expect(@client).to receive(:wait_for).with('/rest/task/fake').and_return(wait_response) 118 | # expect(@client).to receive(:rest_get).with(data['uri']).and_return(FakeResponse.new(data)) 119 | # expect(@client.response_handler(initial_response)).to eq(data) 120 | # end 121 | 122 | # it 'allows you to set wait_for_task to false' do 123 | # response = FakeResponse.new(data, 202, 'location' => '/rest/task/fake') 124 | # expect(@client.response_handler(response, false)).to eq(data) 125 | # end 126 | 127 | it 'returns an empty hash for 204 status' do 128 | expect(@client.response_handler(FakeResponse.new({}, 204))).to eq({}) 129 | end 130 | 131 | it 'raises an error for 400 status' do 132 | resp = FakeResponse.new({ message: 'Blah' }, 400) 133 | expect { @client.response_handler(resp) }.to raise_error(ILO_SDK::BadRequest, /400 BAD REQUEST.*Blah/) 134 | end 135 | 136 | it 'raises an error for 401 status' do 137 | resp = FakeResponse.new({ message: 'Blah' }, 401) 138 | expect { @client.response_handler(resp) }.to raise_error(ILO_SDK::Unauthorized, /401 UNAUTHORIZED.*Blah/) 139 | end 140 | 141 | it 'raises an error for 404 status' do 142 | resp = FakeResponse.new({ message: 'Blah' }, 404) 143 | expect { @client.response_handler(resp) }.to raise_error(ILO_SDK::NotFound, /404 NOT FOUND.*Blah/) 144 | end 145 | 146 | it 'raises an error for undefined status codes' do 147 | [0, 19, 199, 203, 399, 402, 500].each do |status| 148 | resp = FakeResponse.new({ message: 'Blah' }, status) 149 | expect { @client.response_handler(resp) }.to raise_error(ILO_SDK::RequestError, /#{status}.*Blah/) 150 | end 151 | end 152 | end 153 | 154 | describe '#build_request' do 155 | before :each do 156 | @uri = URI.parse(URI.escape(@client.host + path)) 157 | end 158 | 159 | it 'fails when an invalid request type is given' do 160 | expect { @client.send(:build_request, :fake, @uri, {}) }.to raise_error(/Invalid rest method/) 161 | end 162 | 163 | context 'default header values' do 164 | before :each do 165 | @req = @client.send(:build_request, :get, @uri, {}) 166 | end 167 | 168 | it 'sets the basic_auth values' do 169 | expect(@req['authorization']).to match(/Basic/) 170 | end 171 | 172 | it 'sets the Content-Type' do 173 | expect(@req['Content-Type']).to eq('application/json') 174 | end 175 | end 176 | 177 | it 'allows deletion of default headers' do 178 | options = { 'Content-Type' => :none, 'auth' => 'none' } 179 | req = @client.send(:build_request, :get, @uri, options) 180 | expect(req['Content-Type']).to eq(nil) 181 | expect(req['authorization']).to eq(nil) 182 | end 183 | 184 | it 'allows additional headers to be set' do 185 | options = { 'My-Header' => 'blah' } 186 | req = @client.send(:build_request, :get, @uri, options) 187 | expect(req['My-Header']).to eq('blah') 188 | end 189 | 190 | it 'sets the body option to the request body' do 191 | options = { 'body' => { name: 'New', uri: path } } 192 | req = @client.send(:build_request, :get, @uri, options) 193 | expect(req.body).to eq(options['body'].to_json) 194 | end 195 | 196 | it 'logs the filtered request options (debug level)' do 197 | body = { 'key1' => 'val1' } 198 | expected_options = { 'body' => body, 'Content-Type' => 'application/json' } 199 | @client.logger.level = @client.logger.class.const_get('DEBUG') 200 | expect { @client.send(:build_request, :post, @uri, 'body' => body) } 201 | .to output(/Options: #{expected_options}/).to_stdout_from_any_process 202 | end 203 | end 204 | end 205 | --------------------------------------------------------------------------------