oneview-sdk 4.0.0 → 4.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b2cf0ee2e24d1983a8a7bdd7f5e37cf9980117b3
4
- data.tar.gz: 38377447be77b778441fd237d8ff1e6c25a89140
3
+ metadata.gz: 33d01d70d21a357c6e0c4f9295f039d874aea7b1
4
+ data.tar.gz: f5bd6ddea83a0124bf87c034b2107b7949a1004b
5
5
  SHA512:
6
- metadata.gz: c288b678eeca3f9bc01230993f76d351410d76a402b1bc85be631177fc09a758eebf9f9e3c130419c9c16632d3a62aab986f0a5a0863810747011071ab6927d8
7
- data.tar.gz: 5e2a9af5bd94afdbdf6438fac6a03a2250117dfa87299d6ddce45e1a77491e16ab68c557a9a41714a819f1768f28190a273fb46460ff6aa92e4dc9659ea77f96
6
+ metadata.gz: 81644b00704bc889c5f62fbeb98fc2ef00fd7c0ba2a66631016aa867a298207bfc109eb904a8f404768779447f34b9f40a1cc17c3fb1efea46f2be3bd64811ae
7
+ data.tar.gz: d469232c518d22bc5ec52d828b929093a5bdac8a7d8ac12bbf647d4c1ca7f6be6f60ac817638e805d2d47dad578649e3ca7d4a310e9251a2bbdb34ab2c3304eb
@@ -1,4 +1,30 @@
1
1
  # Unreleased Changes
2
+ (none)
3
+
4
+ # v4.1.0
5
+
6
+ #### New Resources:
7
+ Added full support to Image Streamer Rest API version 300:
8
+ - Artifact Bundle
9
+ - Build Plan
10
+ - Deployment Group
11
+ - Deployment Plan
12
+ - Golden Image
13
+ - OS Volume
14
+ - Plan Script
15
+
16
+ #### Bug fixes & Enhancements:
17
+ - Give custom exception classes a data attribute for more error context and default message
18
+ - [#116](https://github.com/HewlettPackard/oneview-sdk-ruby/issues/112) VolumeAttachment::remove_extra_unmanaged_volume throw Unexpected Http Error
19
+ - [#135](https://github.com/HewlettPackard/oneview-sdk-ruby/issues/135) Firmware Bundle timeout does not give proper instructions for user post failure
20
+ - [#146](https://github.com/HewlettPackard/oneview-sdk-ruby/issues/146) Why is Switch the only resource that directly implements #set_scope_uris?
21
+ - [#166](https://github.com/HewlettPackard/oneview-sdk-ruby/issues/166) I3S - Simplify login to i3s through oneview client
22
+ - [#178](https://github.com/HewlettPackard/oneview-sdk-ruby/issues/178) Add client destroy_session method and domain attribute
23
+ - [#174](https://github.com/HewlettPackard/oneview-sdk-ruby/issues/174) I3S - Integration test for Build Plan failing
24
+ - [#176](https://github.com/HewlettPackard/oneview-sdk-ruby/issues/176) OneviewSDK.resource_named now finds resources that are not children of Resource
25
+ - [#183](https://github.com/HewlettPackard/oneview-sdk-ruby/issues/183) Image Streamer Client cannot be created with the OneView environment variables
26
+ - [#184](https://github.com/HewlettPackard/oneview-sdk-ruby/issues/184) Coveralls badge showing coverage as unknown
27
+ - [#196](https://github.com/HewlettPackard/oneview-sdk-ruby/issues/196) Missing endpoint for extract backup in Artifact Bundle
2
28
 
3
29
  # v4.0.0
4
30
 
data/README.md CHANGED
@@ -1,17 +1,18 @@
1
1
  # oneview-sdk for Ruby
2
2
  [![Gem Version](https://badge.fury.io/rb/oneview-sdk.svg)](https://badge.fury.io/rb/oneview-sdk)
3
+ [![Yard Docs](https://img.shields.io/badge/yard-docs-yellow.svg)](http://www.rubydoc.info/gems/oneview-sdk)
3
4
 
5
+ [![Build Status](https://travis-ci.org/HewlettPackard/oneview-sdk-ruby.svg?branch=master)](https://travis-ci.org/HewlettPackard/oneview-sdk-ruby)
6
+ [![Coverage Status](https://coveralls.io/repos/github/HewlettPackard/oneview-sdk-ruby/badge.svg)](https://coveralls.io/github/HewlettPackard/oneview-sdk-ruby)
7
+ [![Code Climate](https://codeclimate.com/github/HewlettPackard/oneview-sdk-ruby/badges/gpa.svg)](https://codeclimate.com/github/HewlettPackard/oneview-sdk-ruby)
4
8
 
5
9
  The OneView SDK provides a Ruby library to easily interact with HPE OneView and Image Streamer APIs. The Ruby SDK enables developers to easily build integrations and scalable solutions with HPE OneView and Image Streamer.
6
10
 
7
- Note that currently the Image Streamer resources are a work in progress, so should be treated as experimental.
8
- Many of these resources are unimplemented, and all are subject to change in ways that are incompatible with current usage & docs.
9
-
10
11
  ## Installation
11
12
  - Require the gem in your Gemfile:
12
13
 
13
14
  ```ruby
14
- gem 'oneview-sdk', '~> 4.0'
15
+ gem 'oneview-sdk', '~> 4.1'
15
16
  ```
16
17
 
17
18
  Then run `$ bundle install`
@@ -36,6 +37,7 @@ client = OneviewSDK::Client.new(
36
37
  ssl_enabled: true, # This is the default and strongly encouraged
37
38
  logger: Logger.new(STDOUT), # This is the default
38
39
  log_level: :info, # This is the default
40
+ domain: 'LOCAL', # This is the default
39
41
  api_version: 200 # Defaults to minimum of 200 and appliance's max API version
40
42
  )
41
43
  ```
@@ -60,6 +62,19 @@ i3s_client = OneviewSDK::ImageStreamer::Client.new(
60
62
  )
61
63
  ```
62
64
 
65
+ You can also create the i3s client through the Oneview client instance.
66
+ ```ruby
67
+ # Create an Image Streamer client object through the Oneview client object:
68
+ require 'oneview-sdk'
69
+ i3s_client = client.new_i3s_client(
70
+ url: 'https://image-streamer.example.com',
71
+ ssl_enabled: true, # This is the default and strongly encouraged
72
+ logger: Logger.new(STDOUT), # This is the default
73
+ log_level: :info, # This is the default
74
+ api_version: 300 # Defaults to minimum of 300 and appliance's max API version
75
+ )
76
+ ```
77
+
63
78
  ##### Environment Variables
64
79
 
65
80
  You can also set many of the client attributes using environment variables. To set these variables in bash:
@@ -67,6 +82,7 @@ You can also set many of the client attributes using environment variables. To s
67
82
  ```bash
68
83
  # OneView client options:
69
84
  export ONEVIEWSDK_URL='https://oneview.example.com'
85
+ export ONEVIEWSDK_DOMAIN='LOCAL'
70
86
  # You can set the token if you know it, or set the user and password to generate one:
71
87
  export ONEVIEWSDK_TOKEN='xxxx...'
72
88
  export ONEVIEWSDK_USER='Administrator'
@@ -76,7 +92,6 @@ export ONEVIEWSDK_SSL_ENABLED=false
76
92
 
77
93
  # Image Streamer (I3S) client options:
78
94
  export I3S_URL='https://image-streamer.example.com'
79
- export I3S_TOKEN='xxxx...'
80
95
  export I3S_SSL_ENABLED=false
81
96
  # NOTE: Disabling SSL is strongly discouraged. Please see the CLI section for import instructions.
82
97
  ```
@@ -88,7 +103,18 @@ Then you can leave out these options from your config, enabling you to just do:
88
103
  ```ruby
89
104
  require 'oneview-sdk'
90
105
  client = OneviewSDK::Client.new
91
- # and/or
106
+ ```
107
+
108
+ You can create the i3s client with environment variables in the following ways:
109
+ ```ruby
110
+ require 'oneview-sdk'
111
+ # Note: Both options require the I3S_URL environment variable to be set.
112
+
113
+ # This way uses the ONEVIEWSDK_URL, ONEVIEWSDK_USER and ONEVIEWSDK_PASSWORD environment variables to generate a token:
114
+ client = OneviewSDK::Client.new
115
+ i3s_client = client.new_i3s_client
116
+
117
+ # This way uses the ONEVIEWSDK_TOKEN environment variable directly:
92
118
  i3s_client = OneviewSDK::ImageStreamer::Client.new
93
119
  ```
94
120
 
@@ -152,7 +178,7 @@ OneviewSDK.api_version = 300
152
178
  OneviewSDK.api_version # 300
153
179
  OneviewSDK.api_version_updated? # true
154
180
 
155
- # The API200 module has only 1 variant, but API300 has 2 (C7000 & Synergy):
181
+ # The API200 module has no variants, but API300 has 2 (C7000 & Synergy):
156
182
  OneviewSDK::API300::SUPPORTED_VARIANTS # ['C7000', 'Synergy']
157
183
  OneviewSDK::API300::DEFAULT_VARIANT # 'C7000'
158
184
  OneviewSDK::API300.variant # 'C7000'
@@ -406,7 +432,4 @@ First run `$ bundle` (requires the bundler gem), then...
406
432
  Note: run `$ rake -T` to get a list of all the available rake tasks.
407
433
 
408
434
  ## Authors
409
- - Jared Smartt - [@jsmartt](https://github.com/jsmartt)
410
- - Henrique Diomede - [@hdiomede](https://github.com/hdiomede)
411
- - Thiago Miotto - [@tmiotto](https://github.com/tmiotto)
412
- - Ricardo Piantola - [@piantola](https://github.com/piantola)
435
+ See the [contributors graph](https://github.com/HewlettPackard/oneview-sdk-ruby/graphs/contributors)
data/Rakefile CHANGED
@@ -252,6 +252,5 @@ end
252
252
  desc 'Run rubocop & integration tests for Image Streamer & specified path'
253
253
  task 'test:i3s:path', [:path] do |_t, spec|
254
254
  spec_pattern = spec['path']
255
- Rake::Task[:rubocop].invoke
256
255
  Rake::Task['spec:integration:i3s'].invoke
257
256
  end
@@ -19,9 +19,9 @@ require_relative 'oneview-sdk/image_streamer'
19
19
 
20
20
  # Module for interacting with the HPE OneView API
21
21
  module OneviewSDK
22
- env_sdk = %w(ONEVIEWSDK_URL ONEVIEWSDK_USER ONEVIEWSDK_PASSWORD ONEVIEWSDK_TOKEN)
22
+ env_sdk = %w(ONEVIEWSDK_URL ONEVIEWSDK_USER ONEVIEWSDK_PASSWORD ONEVIEWSDK_TOKEN ONEVIEWSDK_DOMAIN)
23
23
  env_sdk.concat %w(ONEVIEWSDK_SSL_ENABLED ONEVIEWSDK_API_VERSION ONEVIEWSDK_VARIANT)
24
- env_i3s = %w(I3S_URL I3S_TOKEN I3S_SSL_ENABLED)
24
+ env_i3s = %w(I3S_URL I3S_SSL_ENABLED)
25
25
  ENV_VARS = env_sdk.concat(env_i3s).freeze
26
26
 
27
27
  SUPPORTED_API_VERSIONS = [200, 300].freeze
@@ -37,8 +37,10 @@ module OneviewSDK
37
37
  # Set the default API version
38
38
  def self.api_version=(version)
39
39
  version = version.to_i rescue version
40
- raise "API version #{version} is not supported!" unless SUPPORTED_API_VERSIONS.include?(version)
41
- raise "The module for API version #{@api_version} is undefined" unless constants.include?("API#{@api_version}".to_sym)
40
+ raise UnsupportedVersion, "API version #{version} is not supported!"\
41
+ unless SUPPORTED_API_VERSIONS.include?(version)
42
+ raise UnsupportedVariant, "The module for API version #{@api_version} is undefined"\
43
+ unless constants.include?("API#{@api_version}".to_sym)
42
44
  @api_version_updated = true
43
45
  @api_version = version
44
46
  end
@@ -466,13 +466,13 @@ module OneviewSDK
466
466
  r = OneviewSDK.resource_named(type, api_ver, variant)
467
467
  # Try default API version as last resort
468
468
  r ||= OneviewSDK.resource_named(type, OneviewSDK.api_version, variant) unless api_ver == OneviewSDK.api_version
469
- return r if r
469
+ return r if r && r.respond_to?(:find_by)
470
470
  valid_classes = []
471
471
  api_module = OneviewSDK.const_get("API#{api_ver}")
472
472
  api_module = api_module.const_get(variant.to_s) unless api_ver.to_i == 200
473
473
  api_module.constants.each do |c|
474
474
  klass = api_module.const_get(c)
475
- next unless klass.is_a?(Class) && klass < OneviewSDK::Resource
475
+ next unless klass.is_a?(Class) && klass.respond_to?(:find_by)
476
476
  valid_classes.push(klass.name.split('::').last)
477
477
  end
478
478
  vc = valid_classes.sort_by!(&:downcase).join("\n ")
@@ -1,7 +1,7 @@
1
- # (C) Copyright 2016 Hewlett Packard Enterprise Development LP
1
+ # (c) Copyright 2016-2017 Hewlett Packard Enterprise Development LP
2
2
  #
3
3
  # Licensed under the Apache License, Version 2.0 (the "License");
4
- # You may not use this file except in compliance with the License.
4
+ # you may not use this file except in compliance with the License.
5
5
  # You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
6
6
  #
7
7
  # Unless required by applicable law or agreed to in writing, software distributed
@@ -18,7 +18,7 @@ module OneviewSDK
18
18
  # The client defines the connection to the OneView server and handles communication with it.
19
19
  class Client
20
20
  attr_reader :max_api_version
21
- attr_accessor :url, :user, :token, :password, :ssl_enabled, :api_version, \
21
+ attr_accessor :url, :user, :token, :password, :domain, :ssl_enabled, :api_version, \
22
22
  :logger, :log_level, :cert_store, :print_wait_dots, :timeout
23
23
 
24
24
  include Rest
@@ -32,6 +32,7 @@ module OneviewSDK
32
32
  # @option options [String] :url URL of OneView appliance
33
33
  # @option options [String] :user ('Administrator') The username to use for authentication with the OneView appliance
34
34
  # @option options [String] :password (ENV['ONEVIEWSDK_PASSWORD']) The password to use for authentication with OneView appliance
35
+ # @option options [String] :domain ('LOCAL') The name of the domain directory used for authentication
35
36
  # @option options [String] :token (ENV['ONEVIEWSDK_TOKEN']) The token to use for authentication with OneView appliance
36
37
  # Use the token or the username and password (not both). The token has precedence.
37
38
  # @option options [Integer] :api_version (200) This is the API version to use by default for requests
@@ -65,12 +66,12 @@ module OneviewSDK
65
66
  @timeout = options[:timeout] unless options[:timeout].nil?
66
67
  @cert_store = OneviewSDK::SSLHelper.load_trusted_certs if @ssl_enabled
67
68
  @token = options[:token] || ENV['ONEVIEWSDK_TOKEN']
68
- return if @token
69
- @logger.warn 'User option not set. Using default (Administrator)' unless options[:user] || ENV['ONEVIEWSDK_USER']
69
+ @logger.warn 'User option not set. Using default (Administrator)' unless @token || options[:user] || ENV['ONEVIEWSDK_USER']
70
70
  @user = options[:user] || ENV['ONEVIEWSDK_USER'] || 'Administrator'
71
71
  @password = options[:password] || ENV['ONEVIEWSDK_PASSWORD']
72
- raise InvalidClient, 'Must set user & password options or token option' unless @password
73
- @token = login
72
+ raise InvalidClient, 'Must set user & password options or token option' unless @token || @password
73
+ @domain = options[:domain] || ENV['ONEVIEWSDK_DOMAIN'] || 'LOCAL'
74
+ @token ||= login
74
75
  end
75
76
 
76
77
  def log_level=(level)
@@ -157,6 +158,30 @@ module OneviewSDK
157
158
  self
158
159
  end
159
160
 
161
+ # Delete the session on the appliance, invalidating the client's token.
162
+ # To generate a new token after calling this method, use the refresh_login method.
163
+ # Call this after a token expires or the user and/or password is updated on the client object.
164
+ # @return [OneviewSDK::Client] self
165
+ def destroy_session
166
+ response_handler(rest_delete('/rest/login-sessions'))
167
+ self
168
+ end
169
+
170
+ # Creates the image streamer client object.
171
+ # @param [Hash] options the options to configure the client
172
+ # @option options [Logger] :logger (Logger.new(STDOUT)) Logger object to use.
173
+ # Must implement debug(String), info(String), warn(String), error(String), & level=
174
+ # @option options [Symbol] :log_level (:info) Log level. Logger must define a constant with this name. ie Logger::INFO
175
+ # @option options [Boolean] :print_wait_dots (false) When true, prints status dots while waiting on the tasks to complete.
176
+ # @option options [String] :url URL of Image Streamer
177
+ # @option options [Integer] :api_version (300) This is the API version to use by default for requests
178
+ # @option options [Boolean] :ssl_enabled (true) Use ssl for requests? Respects ENV['I3S_SSL_ENABLED']
179
+ # @option options [Integer] :timeout (nil) Override the default request timeout value
180
+ # @return [OneviewSDK::ImageStreamer::Client] New instance of image streamer client
181
+ def new_i3s_client(options = {})
182
+ OneviewSDK::ImageStreamer::Client.new(options.merge(token: @token))
183
+ end
184
+
160
185
 
161
186
  private
162
187
 
@@ -179,7 +204,7 @@ module OneviewSDK
179
204
  'body' => {
180
205
  'userName' => @user,
181
206
  'password' => @password,
182
- 'authLoginDomain' => 'LOCAL'
207
+ 'authLoginDomain' => @domain
183
208
  }
184
209
  }
185
210
  response = rest_post('/rest/login-sessions', options)
@@ -1,7 +1,7 @@
1
- # (C) Copyright 2016 Hewlett Packard Enterprise Development LP
1
+ # (c) Copyright 2016-2017 Hewlett Packard Enterprise Development LP
2
2
  #
3
3
  # Licensed under the Apache License, Version 2.0 (the "License");
4
- # You may not use this file except in compliance with the License.
4
+ # you may not use this file except in compliance with the License.
5
5
  # You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
6
6
  #
7
7
  # Unless required by applicable law or agreed to in writing, software distributed
@@ -11,45 +11,81 @@
11
11
 
12
12
  # Contains all the custom Exception classes
13
13
  module OneviewSDK
14
- class ConnectionError < StandardError # Cannot connect to client/resource
14
+ # Error class allowing storage of a data attribute
15
+ class OneViewError < ::StandardError
16
+ attr_accessor :data
17
+ MESSAGE = '(No message)'.freeze
18
+
19
+ def initialize(msg = self.class::MESSAGE, data = nil)
20
+ @data = data
21
+ super(msg)
22
+ end
23
+
24
+ # Shorthand method to raise an error.
25
+ # @example
26
+ # OneviewSDK::OneViewError.raise! 'Message', { data: 'stuff' }
27
+ def self.raise!(msg = self::MESSAGE, data = nil)
28
+ raise new(msg, data)
29
+ end
30
+ end
31
+
32
+ class ConnectionError < OneViewError # Cannot connect to client/resource
33
+ MESSAGE = 'Cannot connect to client/resource'.freeze
34
+ end
35
+
36
+ class InvalidURL < OneViewError # URL is invalid
37
+ MESSAGE = 'URL is invalid'.freeze
15
38
  end
16
39
 
17
- class InvalidURL < StandardError # URL is invalid
40
+ class InvalidClient < OneViewError # Client configuration is invalid
41
+ MESSAGE = 'Client configuration is invalid'.freeze
18
42
  end
19
43
 
20
- class InvalidClient < StandardError # Client configuration is invalid
44
+ class InvalidResource < OneViewError # Failed resource validations
45
+ MESSAGE = 'Failed resource validations'.freeze
21
46
  end
22
47
 
23
- class InvalidResource < StandardError # Failed resource validations
48
+ class IncompleteResource < OneViewError # Missing required resource data to complete action
49
+ MESSAGE = 'Missing required resource data to complete action'.freeze
24
50
  end
25
51
 
26
- class IncompleteResource < StandardError # Missing required resource data to complete action
52
+ class MethodUnavailable < OneViewError # Resource does not support this method
53
+ MESSAGE = 'Resource does not support this method'.freeze
27
54
  end
28
55
 
29
- class MethodUnavailable < StandardError # Resource does not support this method
56
+ class UnsupportedVariant < OneViewError # Variant is not supported
57
+ MESSAGE = 'Variant is not supported'.freeze
30
58
  end
31
59
 
32
- class UnsupportedVersion < StandardError # Resource not supported on this API version
60
+ class UnsupportedVersion < OneViewError # Resource not supported on this API version
61
+ MESSAGE = 'Resource not supported on this API version'.freeze
33
62
  end
34
63
 
35
- class InvalidRequest < StandardError # Could not make request
64
+ class InvalidRequest < OneViewError # Could not make request
65
+ MESSAGE = 'Could not make request'.freeze
36
66
  end
37
67
 
38
- class BadRequest < StandardError # 400
68
+ class BadRequest < OneViewError # 400
69
+ MESSAGE = '400'.freeze
39
70
  end
40
71
 
41
- class Unauthorized < StandardError # 401
72
+ class Unauthorized < OneViewError # 401
73
+ MESSAGE = '401'.freeze
42
74
  end
43
75
 
44
- class NotFound < StandardError # 404
76
+ class NotFound < OneViewError # 404
77
+ MESSAGE = '404'.freeze
45
78
  end
46
79
 
47
- class RequestError < StandardError # Other bad response codes
80
+ class RequestError < OneViewError # Other bad response codes
81
+ MESSAGE = 'Bad response code'.freeze
48
82
  end
49
83
 
50
- class TaskError < StandardError # Task ended in a bad state
84
+ class TaskError < OneViewError # Task ended in a bad state
85
+ MESSAGE = 'Task ended in a bad state'.freeze
51
86
  end
52
87
 
53
- class InvalidFormat < StandardError # File format is invalid
88
+ class InvalidFormat < OneViewError # File format is invalid
89
+ MESSAGE = 'File format is invalid'.freeze
54
90
  end
55
91
  end
@@ -19,7 +19,10 @@ module OneviewSDK
19
19
  undef :user=
20
20
  undef :password
21
21
  undef :password=
22
+ undef :domain
23
+ undef :domain=
22
24
  undef :refresh_login
25
+ undef :destroy_session
23
26
 
24
27
  # Creates client object, establish connection, and set up logging and api version.
25
28
  # @param [Hash] options the options to configure the client
@@ -28,7 +31,7 @@ module OneviewSDK
28
31
  # @option options [Symbol] :log_level (:info) Log level. Logger must define a constant with this name. ie Logger::INFO
29
32
  # @option options [Boolean] :print_wait_dots (false) When true, prints status dots while waiting on the tasks to complete.
30
33
  # @option options [String] :url URL of Image Streamer
31
- # @option options [String] :token (ENV['I3S_TOKEN']) The token to use for authentication with Image Streamer
34
+ # @option options [String] :token (ENV['ONEVIEWSDK_TOKEN']) The token to use for authentication
32
35
  # @option options [Integer] :api_version (300) This is the API version to use by default for requests
33
36
  # @option options [Boolean] :ssl_enabled (true) Use ssl for requests? Respects ENV['I3S_SSL_ENABLED']
34
37
  # @option options [Integer] :timeout (nil) Override the default request timeout value
@@ -60,8 +63,8 @@ module OneviewSDK
60
63
  @ssl_enabled = options[:ssl_enabled] unless options[:ssl_enabled].nil?
61
64
  @timeout = options[:timeout] unless options[:timeout].nil?
62
65
  @cert_store = OneviewSDK::SSLHelper.load_trusted_certs if @ssl_enabled
63
- raise InvalidClient, 'Must set token option' unless options[:token] || ENV['I3S_TOKEN']
64
- @token = options[:token] || ENV['I3S_TOKEN']
66
+ raise InvalidClient, 'Must set token option' unless options[:token] || ENV['ONEVIEWSDK_TOKEN']
67
+ @token = options[:token] || ENV['ONEVIEWSDK_TOKEN']
65
68
  end
66
69
 
67
70
  # Get array of all resources of a specified type
@@ -0,0 +1,215 @@
1
+ # (C) Copyright 2017 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_relative 'resource'
13
+
14
+ module OneviewSDK
15
+ module ImageStreamer
16
+ module API300
17
+ # Artifacts Bundle resource implementation for Image Streamer
18
+ class ArtifactBundle < Resource
19
+ ACCEPTED_FORMATS = %w(.zip .ZIP).freeze # Supported upload extensions
20
+
21
+ BASE_URI = '/rest/artifact-bundles'.freeze
22
+ BACKUPS_URI = "#{BASE_URI}/backups".freeze
23
+ BACKUPS_ARCHIVE_URI = "#{BACKUPS_URI}/archive".freeze
24
+
25
+ # Create a resource object, associate it with a client, and set its properties.
26
+ # @param [OneviewSDK::ImageStreamer::Client] client The client object for the Image Streamer appliance
27
+ # @param [Hash] params The options for this resource (key-value pairs)
28
+ # @param [Integer] api_ver The api version to use when interracting with this resource.
29
+ def initialize(client, params = {}, api_ver = nil)
30
+ super
31
+ @data['buildPlans'] ||= []
32
+ @data['planScripts'] ||= []
33
+ @data['deploymentPlans'] ||= []
34
+ @data['goldenImages'] ||= []
35
+ end
36
+
37
+ # Creates an artifact bundle resource from the file that is uploaded from admin's local drive
38
+ # @param [OneviewSDK::ImageStreamer::Client] client The client object for the Image Streamer appliance
39
+ # @param [String] file_path The file path with file extension
40
+ # @param [String] artifact_name The name for the artifact that will be created
41
+ # @param [Integer] timeout The number of seconds to wait for completing the request. Default is 300.
42
+ # @return [OneviewSDK::ImageStreamer::API300::ArtifactBundle] if the upload was successful, return a ArtifactBundle object
43
+ def self.create_from_file(client, file_path, artifact_name, timeout = OneviewSDK::Rest::READ_TIMEOUT)
44
+ ensure_file_path_extension!(file_path)
45
+
46
+ file_name = artifact_name.dup
47
+ if file_name && !file_name.empty?
48
+ file_name += File.extname(file_path)
49
+ else
50
+ file_name = File.basename(file_path)
51
+ end
52
+
53
+ params = { 'name' => file_name }
54
+ body = client.upload_file(file_path, BASE_URI, params, timeout)
55
+ ArtifactBundle.new(client, body)
56
+ end
57
+
58
+ # Gets the backup bundles created
59
+ # @param [OneviewSDK::ImageStreamer::Client] client The client object for the Image Streamer appliance
60
+ # @return [Array<ArtifactBundle>] Array of ArtifactBundle
61
+ def self.get_backups(client)
62
+ find_by(client, {}, BACKUPS_URI)
63
+ end
64
+
65
+ # Creates a backup bundle with all the artifacts present on the appliance.
66
+ # @param [OneviewSDK::ImageStreamer::Client] client The client object for the Image Streamer appliance
67
+ # @param [DeploymentGroup] deployment_group The DeploymentGroup with name or uri
68
+ # @return [Hash] The result hash with DeploymentGroup data
69
+ def self.create_backup(client, deployment_group)
70
+ ensure_resource!(deployment_group)
71
+ response = client.rest_post(BACKUPS_URI, 'body' => { 'deploymentGroupURI' => deployment_group['uri'] })
72
+ client.response_handler(response)
73
+ end
74
+
75
+ # Creates a backup bundle from the zip file and extract all the artifacts present in the uploaded file
76
+ # If there are any artifacts existing, they will be removed before the extract operation.
77
+ # @param [OneviewSDK::ImageStreamer::Client] client The client object for the Image Streamer appliance
78
+ # @param [String] file_path The file path with file extension
79
+ # @param [String] artifact_name The name for the artifact that will be created
80
+ # @param [Integer] timeout The number of seconds to wait for completing the request. Default is 300.
81
+ # @return [Hash] The result hash with DeploymentGroup data
82
+ def self.create_backup_from_file!(client, deployment_group, file_path, artifact_name, timeout = OneviewSDK::Rest::READ_TIMEOUT)
83
+ ensure_resource!(deployment_group)
84
+ ensure_file_path_extension!(file_path)
85
+
86
+ file_name = artifact_name.dup
87
+ if file_name && !file_name.empty?
88
+ file_name += File.extname(file_path)
89
+ else
90
+ file_name = File.basename(file_path)
91
+ end
92
+
93
+ params = { 'name' => file_name, 'deploymentGrpUri' => deployment_group['uri'] }
94
+ client.upload_file(file_path, BACKUPS_ARCHIVE_URI, params, timeout)
95
+ end
96
+
97
+ # Download the backup bundle
98
+ # @param [OneviewSDK::ImageStreamer::Client] client The client object for the Image Streamer appliance
99
+ # @param [String] local_drive_path The path where file will be saved
100
+ # @param [ArtifactBundle] bundle_backup The backup ArtifactBundle with 'downloadURI'
101
+ # @return [Boolean] true if backup was downloaded
102
+ def self.download_backup(client, local_drive_path, bundle_backup)
103
+ raise IncompleteResource, "Missing required attribute 'downloadURI'" unless bundle_backup['downloadURI']
104
+ client.download_file(bundle_backup['downloadURI'], local_drive_path)
105
+ end
106
+
107
+ # Extracts the existing backup bundle on the appliance and creates all the artifacts.
108
+ # If there are any artifacts existing, they will be removed before the extract operation.
109
+ # @param [DeploymentGroup] deployment_group The DeploymentGroup with 'name' or 'uri'
110
+ # @param [ArtifactBundle] bundle_backup The backup ArtifactBundle with 'uri'
111
+ # @return [Boolean] true if backup bundle was extracted
112
+ # @raise [OneviewSDK::IncompleteResource] if the client or uri is not set
113
+ def self.extract_backup(client, deployment_group, bundle_backup)
114
+ ensure_resource!(deployment_group)
115
+ raise IncompleteResource, "Missing required attribute 'uri' of backup bundle" unless bundle_backup['uri']
116
+ id = bundle_backup['uri'].split('/').last
117
+ response = client.rest_put("#{BACKUPS_URI}/#{id}", 'body' => { 'deploymentGroupURI' => deployment_group['uri'] })
118
+ client.response_handler(response)
119
+ true
120
+ end
121
+
122
+ # Method is not available
123
+ # @raise [OneviewSDK::MethodUnavailable] method is not available
124
+ def update(*)
125
+ unavailable_method
126
+ end
127
+
128
+ # Update the name of Artifact Bundle
129
+ # @param [String] new_name Name to update the Artifact Bundle
130
+ # @return [Boolean] true if name was updated
131
+ # @raise [OneviewSDK::IncompleteResource] if the client or uri is not set
132
+ def update_name(new_name)
133
+ ensure_uri
134
+ response = @client.rest_put(@data['uri'], 'body' => { 'name' => new_name, 'type' => 'ArtifactsBundle' })
135
+ @client.response_handler(response)
136
+ @data['name'] = new_name
137
+ true
138
+ end
139
+
140
+ # Extracts the artifact bundle and creates the artifacts on the appliance
141
+ # @param [Boolean] force Forces the extract operation even when there are any conflicts
142
+ # @return [Boolean] true if artifact bundle was extracted
143
+ # @raise [OneviewSDK::IncompleteResource] if the client or uri is not set
144
+ def extract(force = true)
145
+ ensure_uri
146
+ options = { 'Content-Type' => 'text/plain' }
147
+ response = @client.rest_put(@data['uri'] + "?extract=true&forceImport=#{force}", options)
148
+ @client.response_handler(response)
149
+ true
150
+ end
151
+
152
+ # Downloads the content of the selected artifact bundle to the admin's local drive.
153
+ # @param [String] local_drive_path Path to save file downloaded
154
+ # @return [Boolean] true if the file was downloaded
155
+ def download(local_drive_path)
156
+ raise IncompleteResource, "Missing required attribute 'downloadURI'" unless @data['downloadURI']
157
+ client.download_file(@data['downloadURI'], local_drive_path)
158
+ end
159
+
160
+ # Add a Build Plan to this ArtifactBundle
161
+ # @param [OneviewSDK::ImageStreamer::API300::BuildPlan] resource The BuildPlan resource with uri
162
+ # @param [TrueClass, FalseClass] read_only Indicates whether the BuildPlan will be readonly in artifact bundle package
163
+ # @raise [RuntimeError] if the BuildPlan uri is not set or it is not valid
164
+ def add_build_plan(resource, read_only = true)
165
+ add_resource(resource, 'buildPlans', read_only)
166
+ end
167
+
168
+ # Add a Plan Script to this ArtifactBundle
169
+ # @param [OneviewSDK::ImageStreamer::API300::PlanScript] resource The PlanScripts resource with uri
170
+ # @param [TrueClass, FalseClass] read_only Indicates whether the PlanScripts will be readonly in artifact bundle package
171
+ # @raise [RuntimeError] if the PlanScripts uri is not set or it is not valid
172
+ def add_plan_script(resource, read_only = true)
173
+ add_resource(resource, 'planScripts', read_only)
174
+ end
175
+
176
+ # Add a Deployment Plan to this ArtifactBundle
177
+ # @param [OneviewSDK::ImageStreamer::API300::DeploymentPlans] resource The DeploymentPlans resource with uri
178
+ # @param [TrueClass, FalseClass] read_only Indicates whether the DeploymentPlans will be readonly in artifact bundle package
179
+ # @raise [RuntimeError] if the DeploymentPlans uri is not set or it is not valid
180
+ def add_deployment_plan(resource, read_only = true)
181
+ add_resource(resource, 'deploymentPlans', read_only)
182
+ end
183
+
184
+ # Add a Golden Image to this ArtifactBundle
185
+ # @param [OneviewSDK::ImageStreamer::API300::GoldenImage] resource The GoldenImage resource with uri
186
+ # @param [TrueClass, FalseClass] read_only Indicates whether the GoldenImage will be readonly in artifact bundle package
187
+ # @raise [RuntimeError] if the GoldenImage uri is not set or it is not valid
188
+ def add_golden_image(resource, read_only = true)
189
+ add_resource(resource, 'goldenImages', read_only)
190
+ end
191
+
192
+ # Fail unless resource can be retrieved
193
+ def self.ensure_resource!(resource)
194
+ raise IncompleteResource, "The resource #{resource.class} can not be retrieved. Ensure it can be retrieved." unless resource.retrieve!
195
+ end
196
+
197
+ # Fail unless file extension of file_path is in ACCEPTED_FORMATS array
198
+ def self.ensure_file_path_extension!(file_path)
199
+ raise InvalidFormat, "File extension should be #{ACCEPTED_FORMATS}" unless ACCEPTED_FORMATS.include?(File.extname(file_path))
200
+ end
201
+
202
+ private
203
+
204
+ # Add resource data to data hash
205
+ # @param [OneviewSDK::Resource] resource The resource with uri
206
+ # @param [String] key_name The hash key of data hash
207
+ # @param [TrueClass, FalseClass] read_only The value of readOnly attribute
208
+ def add_resource(resource, key_name, read_only)
209
+ self.class.ensure_resource!(resource)
210
+ @data[key_name] << { 'resourceUri' => resource['uri'], 'readOnly' => read_only }
211
+ end
212
+ end
213
+ end
214
+ end
215
+ end
@@ -15,11 +15,18 @@ module OneviewSDK
15
15
  module ImageStreamer
16
16
  module API300
17
17
  # Build Plan resource implementation for Image Streamer
18
- # @note This resource is unimplemented/unfinished at this point, so use at your own risk.
19
- # This resource is subject to change drastically in the near future without a major version
20
- # bump, which may break your code.
21
18
  class BuildPlan < Resource
22
19
  BASE_URI = '/rest/build-plans'.freeze
20
+
21
+ # Create a resource object, associate it with a client, and set its properties.
22
+ # @param [OneviewSDK::ImageStreamer::Client] client The client object for the Image Streamer appliance
23
+ # @param [Hash] params The options for this resource (key-value pairs)
24
+ # @param [Integer] api_ver The api version to use when interracting with this resource.
25
+ def initialize(client, params = {}, api_ver = nil)
26
+ super
27
+ # Default values:
28
+ @data['type'] ||= 'OeBuildPlan'
29
+ end
23
30
  end
24
31
  end
25
32
  end
@@ -14,12 +14,27 @@ require_relative 'resource'
14
14
  module OneviewSDK
15
15
  module ImageStreamer
16
16
  module API300
17
- # Artifacts Bundle resource implementation for Image Streamer
18
- # @note This resource is unimplemented/unfinished at this point, so use at your own risk.
19
- # This resource is subject to change drastically in the near future without a major version
20
- # bump, which may break your code.
21
- class ArtifactsBundle < Resource
22
- BASE_URI = '/rest/artifact-bundles'.freeze
17
+ # Deployment Group resource implementation for Image Streamer
18
+ class DeploymentGroup < Resource
19
+ BASE_URI = '/rest/deployment-groups'.freeze
20
+
21
+ # Method is not available
22
+ # @raise [OneviewSDK::MethodUnavailable] method is not available
23
+ def create(*)
24
+ unavailable_method
25
+ end
26
+
27
+ # Method is not available
28
+ # @raise [OneviewSDK::MethodUnavailable] method is not available
29
+ def update(*)
30
+ unavailable_method
31
+ end
32
+
33
+ # Method is not available
34
+ # @raise [OneviewSDK::MethodUnavailable] method is not available
35
+ def delete(*)
36
+ unavailable_method
37
+ end
23
38
  end
24
39
  end
25
40
  end
@@ -15,11 +15,18 @@ module OneviewSDK
15
15
  module ImageStreamer
16
16
  module API300
17
17
  # Deployment Plan resource implementation for Image Streamer
18
- # @note This resource is unimplemented/unfinished at this point, so use at your own risk.
19
- # This resource is subject to change drastically in the near future without a major version
20
- # bump, which may break your code.
21
18
  class DeploymentPlan < Resource
22
19
  BASE_URI = '/rest/deployment-plans'.freeze
20
+
21
+ # Create a resource object, associate it with a client, and set its properties.
22
+ # @param [OneviewSDK::ImageStreamer::Client] client The client object for the Image Streamer appliance
23
+ # @param [Hash] params The options for this resource (key-value pairs)
24
+ # @param [Integer] api_ver The api version to use when interracting with this resource.
25
+ def initialize(client, params = {}, api_ver = nil)
26
+ super
27
+ # Default values:
28
+ @data['type'] ||= 'OEDeploymentPlan'
29
+ end
23
30
  end
24
31
  end
25
32
  end
@@ -10,16 +10,134 @@
10
10
  # language governing permissions and limitations under the License.
11
11
 
12
12
  require_relative 'resource'
13
+ require 'net/http/post/multipart'
13
14
 
14
15
  module OneviewSDK
15
16
  module ImageStreamer
16
17
  module API300
17
18
  # Golden Image resource implementation for Image Streamer
18
- # @note This resource is unimplemented/unfinished at this point, so use at your own risk.
19
- # This resource is subject to change drastically in the near future without a major version
20
- # bump, which may break your code.
21
19
  class GoldenImage < Resource
22
20
  BASE_URI = '/rest/golden-images'.freeze
21
+ READ_TIMEOUT = 300 # in seconds (5 minutes)
22
+ ACCEPTED_FORMATS = %w(.zip .ZIP).freeze # Supported upload extensions
23
+
24
+ # Create a resource object, associate it with a client, and set its properties.
25
+ # @param [OneviewSDK::ImageStreamer::Client] client The client object for the Image Streamer appliance
26
+ # @param [Hash] params The options for this resource (key-value pairs)
27
+ # @param [Integer] api_ver The api version to use when interracting with this resource.
28
+ def initialize(client, params = {}, api_ver = nil)
29
+ super
30
+ # Default values:
31
+ @data['type'] ||= 'GoldenImage'
32
+ end
33
+
34
+ # Download the details of the golden image capture logs which has been archived based on the specific attribute ID.
35
+ # @param [String] file_path
36
+ # @return [True] When was saved successfully
37
+ def download_details_archive(file_path)
38
+ ensure_client && ensure_uri
39
+ resp = @client.rest_api(:get, "#{BASE_URI}/archive/#{@data['uri'].split('/').last}")
40
+ File.open(file_path, 'wb') { |file| file.write(resp.body) }
41
+ true
42
+ end
43
+
44
+ # Downloads the content of the selected golden image to the specified file path.
45
+ # @param [String] file_path
46
+ # @param [Integer] timeout The number of seconds to wait for the request to complete
47
+ # @return [True] When was saved successfully
48
+ def download(file_path, timeout = READ_TIMEOUT)
49
+ ensure_client && ensure_uri
50
+ uri = URI.parse(URI.escape("#{client.url}#{BASE_URI}/download/#{@data['uri'].split('/').last}"))
51
+ req = Net::HTTP::Get.new(uri.request_uri)
52
+
53
+ options = {}
54
+ options['Content-Type'] = 'application/json'
55
+ options['X-Api-Version'] = @client.api_version.to_s
56
+ options['auth'] = @client.token
57
+ options.each do |key, val|
58
+ req[key] = val
59
+ end
60
+
61
+ http_request = Net::HTTP.new(uri.host, uri.port)
62
+ http_request.use_ssl = true
63
+ http_request.verify_mode = OpenSSL::SSL::VERIFY_NONE
64
+ http_request.read_timeout = timeout
65
+
66
+ http_request.start do |http|
67
+ http.request(req) do |res|
68
+ client.response_handler(res) unless res.code.to_i.between?(200, 204)
69
+ File.open(file_path, 'wb') do |file|
70
+ res.read_body do |segment|
71
+ file.write(segment)
72
+ end
73
+ end
74
+ end
75
+ end
76
+ true
77
+ end
78
+
79
+ # Upload a golden image from the specified local file path.
80
+ # Only the .zip format file can be used for upload.
81
+ # @param [OneviewSDK::ImageStreamer::Client] client The client object for the Image Streamer appliance
82
+ # @param [String] file_path
83
+ # @param [Hash] data_options Attributes of the golden image, passed in the request
84
+ # @option data_options [String] :name The name of the Golden Image (required)
85
+ # @option data_options [String] :description The description of the Golden Image (required)
86
+ # @param [Integer] timeout The number of seconds to wait for the request to complete
87
+ # @return [OneviewSDK::ImageStreamer::API300::GoldenImage] if the upload was successful, return a GoldenImage object
88
+ def self.add(client, file_path, data_options, timeout = READ_TIMEOUT)
89
+ data_options = Hash[data_options.map { |k, v| [k.to_s, v] }] # Convert symbols hash keys to string
90
+ raise NotFound, "ERROR: File '#{file_path}' not found!" unless File.file?(file_path)
91
+ raise InvalidFormat, 'ERROR: File with extension not supported!' unless ACCEPTED_FORMATS.include? File.extname(file_path)
92
+ raise IncompleteResource, 'Please set the name of the golden image!' unless data_options['name']
93
+ raise IncompleteResource, 'Please set the description of the golden image!' unless data_options['description']
94
+ options = {}
95
+ options['Content-Type'] = 'multipart/form-data'
96
+ options['X-Api-Version'] = client.api_version.to_s
97
+ options['auth'] = client.token
98
+ options['file'] = File.basename(file_path)
99
+ url = URI.parse(URI.escape("#{client.url}#{BASE_URI}"))
100
+
101
+ File.open(file_path) do |file|
102
+ req = Net::HTTP::Post::Multipart.new(
103
+ url.path,
104
+ { 'file' => UploadIO.new(file, 'application/octet-stream', File.basename(file_path)) }.merge(data_options),
105
+ options
106
+ )
107
+
108
+ http_request = Net::HTTP.new(url.host, url.port)
109
+ http_request.use_ssl = true if url.scheme == 'https'
110
+ if client.ssl_enabled
111
+ http_request.cert_store = client.cert_store if client.cert_store
112
+ else http_request.verify_mode = OpenSSL::SSL::VERIFY_NONE
113
+ end
114
+ http_request.read_timeout = timeout
115
+
116
+ http_request.start do |http|
117
+ response = http.request(req)
118
+ data = client.response_handler(response)
119
+ return OneviewSDK::ImageStreamer::API300::GoldenImage.new(client, data)
120
+ end
121
+ end
122
+ end
123
+
124
+ # Sets the OS volume
125
+ # @param [OneviewSDK::ImageStreamer::API300::OSVolume] os_volume
126
+ # @raise [OneviewSDK::NotFound] if the os volume uri is not set and cannot be retrieved
127
+ def set_os_volume(os_volume)
128
+ os_volume.retrieve! unless os_volume['uri']
129
+ raise NotFound, 'The os volume was not found!' unless os_volume['uri']
130
+ set('osVolumeURI', os_volume['uri'])
131
+ end
132
+
133
+ # Sets the build plan
134
+ # @param [OneviewSDK::ImageStreamer::API300::BuildPlan] build_plan
135
+ # @raise [OneviewSDK::NotFound] if the build plan uri is not set and cannot be retrieved
136
+ def set_build_plan(build_plan)
137
+ build_plan.retrieve! unless build_plan['uri']
138
+ raise NotFound, 'The build plan was not found!' unless build_plan['uri']
139
+ set('buildPlanUri', build_plan['uri'])
140
+ end
23
141
  end
24
142
  end
25
143
  end
@@ -31,7 +31,8 @@ module OneviewSDK
31
31
  # @param [Integer] api_ver The api version to use when interracting with this resource.
32
32
  # Defaults to the client.api_version if it exists, or the OneviewSDK::Client::DEFAULT_API_VERSION.
33
33
  def initialize(client, params = {}, api_ver = nil)
34
- raise InvalidClient, 'Must specify a valid client' unless client.is_a?(OneviewSDK::Client) || client.is_a?(OneviewSDK::ImageStreamer::Client)
34
+ raise InvalidClient, 'Must specify a valid client'\
35
+ unless client.is_a?(OneviewSDK::Client) || client.is_a?(OneviewSDK::ImageStreamer::Client)
35
36
  @client = client
36
37
  @logger = @client.logger
37
38
  @api_version = api_ver || @client.api_version
@@ -364,9 +365,8 @@ module OneviewSDK
364
365
  # @param [String] variant API module variant to fetch resource from
365
366
  # @return [Class] Resource class or nil if not found
366
367
  def self.resource_named(type, api_ver = @api_version, variant = nil)
367
- unless SUPPORTED_API_VERSIONS.include?(api_ver)
368
- raise UnsupportedVersion, "API version #{api_ver} is not supported! Try one of: #{SUPPORTED_API_VERSIONS}"
369
- end
368
+ raise UnsupportedVersion, "API version #{api_ver} is not supported! Try one of: #{SUPPORTED_API_VERSIONS}"\
369
+ unless SUPPORTED_API_VERSIONS.include?(api_ver)
370
370
  api_module = OneviewSDK.const_get("API#{api_ver}")
371
371
  variant ? api_module.resource_named(type, variant) : api_module.resource_named(type)
372
372
  end
@@ -21,7 +21,7 @@ module OneviewSDK
21
21
  new_type = type.to_s.downcase.gsub(/[ -_]/, '')
22
22
  constants.each do |c|
23
23
  klass = const_get(c)
24
- next unless klass.is_a?(Class) && klass < OneviewSDK::Resource
24
+ next unless klass.is_a?(Class)
25
25
  name = klass.name.split('::').last.downcase.delete('_').delete('-')
26
26
  return klass if new_type =~ /^#{name}[s]?$/
27
27
  end
@@ -22,7 +22,7 @@ module OneviewSDK
22
22
  # @param [OneviewSDK::Client] client The client object for the OneView appliance
23
23
  # @param [String] file_path
24
24
  # @param [Integer] timeout The number of seconds to wait for completing the request
25
- # @return [OneviewSDK::FirmwareDriver] if the upload was sucessful, return a FirmwareDriver object
25
+ # @return [OneviewSDK::FirmwareDriver] if the upload was successful, return a FirmwareDriver object
26
26
  def self.add(client, file_path, timeout = READ_TIMEOUT)
27
27
  raise NotFound, "ERROR: File '#{file_path}' not found!" unless File.file?(file_path)
28
28
  options = {}
@@ -45,9 +45,16 @@ module OneviewSDK
45
45
  http_request.read_timeout = timeout
46
46
 
47
47
  http_request.start do |http|
48
- response = http.request(req)
49
- data = client.response_handler(response)
50
- return OneviewSDK::FirmwareDriver.new(client, data)
48
+ begin
49
+ response = http.request(req)
50
+ data = client.response_handler(response)
51
+ return OneviewSDK::FirmwareDriver.new(client, data)
52
+ rescue Net::ReadTimeout
53
+ raise "The connection was closed because the timeout of #{timeout} seconds has expired."\
54
+ 'You can specify the timeout in seconds by passing the timeout on the method call.'\
55
+ 'Interrupted firmware uploads may result in corrupted firmware remaining in the appliance.'\
56
+ 'HPE recommends checking the appliance for corrupted firmware and removing it.'
57
+ end
51
58
  end
52
59
  end
53
60
  end
@@ -60,7 +60,7 @@ module OneviewSDK
60
60
  type: 'ExtraUnmanagedStorageVolumes',
61
61
  resourceUri: resource['uri']
62
62
  }
63
- response = client.rest_post(BASE_URI + '/repair', 'body' => requestBody)
63
+ response = client.rest_post(BASE_URI + '/repair', { 'Accept-Language' => 'en_US', 'body' => requestBody }, client.api_version)
64
64
  client.response_handler(response)
65
65
  end
66
66
 
@@ -27,7 +27,7 @@ module OneviewSDK
27
27
  api_module = OneviewSDK::API300.const_get(variant)
28
28
  api_module.constants.each do |c|
29
29
  klass = api_module.const_get(c)
30
- next unless klass.is_a?(Class) && klass < OneviewSDK::Resource
30
+ next unless klass.is_a?(Class)
31
31
  name = klass.name.split('::').last.downcase.delete('_').delete('-')
32
32
  return klass if new_type =~ /^#{name}[s]?$/
33
33
  end
@@ -10,20 +10,20 @@
10
10
  # language governing permissions and limitations under the License.
11
11
 
12
12
  require_relative '../../api200/switch'
13
+ require_relative 'scope'
13
14
 
14
15
  module OneviewSDK
15
16
  module API300
16
17
  module C7000
17
18
  # Switch resource implementation
18
19
  class Switch < OneviewSDK::API200::Switch
20
+ include OneviewSDK::API300::C7000::Scope::ScopeHelperMethods
19
21
 
20
22
  # Updates the scope URIs of a specific switch
21
23
  # @param [Array] scope_uris Array of scope uri strings
24
+ # @deprecated Use {#add_scope}, {#remove_scope}, and {#replace_scopes} instead.
22
25
  def set_scope_uris(scope_uris)
23
- ensure_client && ensure_uri
24
- body = { op: 'replace', path: '/scopeUris', value: scope_uris }
25
- response = @client.rest_patch(@data['uri'], { 'body' => [body] }, @api_version)
26
- @client.response_handler(response)
26
+ patch('replace', '/scopeUris', scope_uris)
27
27
  end
28
28
  end
29
29
  end
@@ -13,10 +13,13 @@ require 'uri'
13
13
  require 'net/http'
14
14
  require 'openssl'
15
15
  require 'json'
16
+ require 'net/http/post/multipart'
16
17
 
17
18
  module OneviewSDK
18
19
  # Contains all of the methods for making API REST calls
19
20
  module Rest
21
+ READ_TIMEOUT = 300 # in seconds, 5 minutes
22
+
20
23
  # Makes a restful API request to OneView
21
24
  # @param [Symbol] type The rest method/type Options: [:get, :post, :delete, :patch, :put]
22
25
  # @param [String] path The path for the request. Usually starts with "/rest/"
@@ -32,17 +35,8 @@ module OneviewSDK
32
35
  def rest_api(type, path, options = {}, api_ver = @api_version, redirect_limit = 3)
33
36
  @logger.debug "Making :#{type} rest call to #{@url}#{path}"
34
37
  raise InvalidRequest, 'Must specify path' unless path
35
-
36
38
  uri = URI.parse(URI.escape(@url + path))
37
- http = Net::HTTP.new(uri.host, uri.port)
38
- http.use_ssl = true if uri.scheme == 'https'
39
- if @ssl_enabled
40
- http.cert_store = @cert_store if @cert_store
41
- else http.verify_mode = OpenSSL::SSL::VERIFY_NONE
42
- end
43
- http.read_timeout = @timeout if @timeout # Timeout for a request
44
- http.open_timeout = @timeout if @timeout # Timeout for a connection
45
-
39
+ http = build_http_object(uri)
46
40
  request = build_request(type, uri, options.dup, api_ver)
47
41
  response = http.request(request)
48
42
  @logger.debug " Response: Code=#{response.code}. Headers=#{response.to_hash}\n Body=#{response.body}"
@@ -121,6 +115,64 @@ module OneviewSDK
121
115
  rest_api(:delete, path, options, api_ver)
122
116
  end
123
117
 
118
+ # Uploads a file to a specific uri
119
+ # @param [String] file_path
120
+ # @param [String] path The url path starting with "/"
121
+ # @param [Hash] body_params The params to append to body of http request. Default is {}.
122
+ # @option body_params [String] 'name' The name to show (when resource accepts a name)
123
+ # @param [Integer] timeout The number of seconds to wait for completing the request. Default is 300.
124
+ # @return [Hash] The parsed JSON body of response
125
+ def upload_file(file_path, path, body_params = {}, timeout = READ_TIMEOUT)
126
+ raise NotFound, "ERROR: File '#{file_path}' not found!" unless File.file?(file_path)
127
+ options = {
128
+ 'Content-Type' => 'multipart/form-data',
129
+ 'X-Api-Version' => @api_version.to_s,
130
+ 'auth' => @token
131
+ }
132
+
133
+ File.open(file_path) do |file|
134
+ name_to_show = body_params.delete('name') || body_params.delete(:name) || File.basename(file_path)
135
+ body_params['file'] = UploadIO.new(file, 'application/octet-stream', name_to_show)
136
+
137
+ uri = URI.parse(URI.escape(@url + path))
138
+ http_request = build_http_object(uri)
139
+ http_request.read_timeout = timeout
140
+
141
+ req = Net::HTTP::Post::Multipart.new(
142
+ uri.path,
143
+ body_params,
144
+ options
145
+ )
146
+
147
+ http_request.start do |http|
148
+ response = http.request(req)
149
+ return response_handler(response)
150
+ end
151
+ end
152
+ end
153
+
154
+ # Download a file from a specific uri
155
+ # @param [String] path The url path starting with "/"
156
+ # @param [String] local_drive_path Path to save file downloaded
157
+ # @return [Boolean] if file was downloaded
158
+ def download_file(path, local_drive_path)
159
+ uri = URI.parse(URI.escape(@url + path))
160
+ http_request = build_http_object(uri)
161
+ req = build_request(:get, uri, {}, @api_version.to_s)
162
+
163
+ http_request.start do |http|
164
+ http.request(req) do |res|
165
+ response_handler(res) unless res.code.to_i.between?(200, 204)
166
+ File.open(local_drive_path, 'wb') do |file|
167
+ res.read_body do |segment|
168
+ file.write(segment)
169
+ end
170
+ end
171
+ end
172
+ end
173
+ true
174
+ end
175
+
124
176
  RESPONSE_CODE_OK = 200
125
177
  RESPONSE_CODE_CREATED = 201
126
178
  RESPONSE_CODE_ACCEPTED = 202
@@ -133,8 +185,7 @@ module OneviewSDK
133
185
  # If an asynchronous task was started, this waits for it to complete.
134
186
  # @param [HTTPResponse] response HTTP response
135
187
  # @param [Boolean] wait_on_task Wait on task (or just return task details)
136
- # @raise [StandardError] if the request failed
137
- # @raise [StandardError] if a task was returned that did not complete successfully
188
+ # @raise [OneviewSDK::OneViewError] if the request failed or a task did not complete successfully
138
189
  # @return [Hash] The parsed JSON body
139
190
  def response_handler(response, wait_on_task = true)
140
191
  case response.code.to_i
@@ -158,19 +209,32 @@ module OneviewSDK
158
209
  when RESPONSE_CODE_NO_CONTENT # Synchronous delete
159
210
  return {}
160
211
  when RESPONSE_CODE_BAD_REQUEST
161
- raise BadRequest, "400 BAD REQUEST #{response.body}"
212
+ BadRequest.raise! "400 BAD REQUEST #{response.body}", response
162
213
  when RESPONSE_CODE_UNAUTHORIZED
163
- raise Unauthorized, "401 UNAUTHORIZED #{response.body}"
214
+ Unauthorized.raise! "401 UNAUTHORIZED #{response.body}", response
164
215
  when RESPONSE_CODE_NOT_FOUND
165
- raise NotFound, "404 NOT FOUND #{response.body}"
216
+ NotFound.raise! "404 NOT FOUND #{response.body}", response
166
217
  else
167
- raise RequestError, "#{response.code} #{response.body}"
218
+ RequestError.raise! "#{response.code} #{response.body}", response
168
219
  end
169
220
  end
170
221
 
171
222
 
172
223
  private
173
224
 
225
+ # Builds a http object using the data given
226
+ def build_http_object(uri)
227
+ http = Net::HTTP.new(uri.host, uri.port)
228
+ http.use_ssl = true if uri.scheme == 'https'
229
+ if @ssl_enabled
230
+ http.cert_store = @cert_store if @cert_store
231
+ else http.verify_mode = OpenSSL::SSL::VERIFY_NONE
232
+ end
233
+ http.read_timeout = @timeout if @timeout # Timeout for a request
234
+ http.open_timeout = @timeout if @timeout # Timeout for a connection
235
+ http
236
+ end
237
+
174
238
  # Builds a request object using the data given
175
239
  def build_request(type, uri, options, api_ver)
176
240
  case type.downcase.to_sym
@@ -11,5 +11,5 @@
11
11
 
12
12
  # Gem version defined here
13
13
  module OneviewSDK
14
- VERSION = '4.0.0'.freeze
14
+ VERSION = '4.1.0'.freeze
15
15
  end
@@ -34,11 +34,11 @@ Gem::Specification.new do |spec|
34
34
  spec.add_runtime_dependency 'pry'
35
35
  spec.add_runtime_dependency 'multipart-post'
36
36
 
37
+ spec.add_development_dependency 'coveralls'
37
38
  spec.add_development_dependency 'bundler'
38
- spec.add_development_dependency 'rspec'
39
+ spec.add_development_dependency 'byebug'
39
40
  spec.add_development_dependency 'rake'
40
- spec.add_development_dependency 'simplecov'
41
+ spec.add_development_dependency 'rspec'
41
42
  spec.add_development_dependency 'rubocop', '= 0.42.0'
42
- spec.add_development_dependency 'byebug'
43
-
43
+ spec.add_development_dependency 'simplecov'
44
44
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: oneview-sdk
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.0.0
4
+ version: 4.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Henrique Diomede
@@ -11,7 +11,7 @@ authors:
11
11
  autorequire:
12
12
  bindir: bin
13
13
  cert_chain: []
14
- date: 2017-02-10 00:00:00.000000000 Z
14
+ date: 2017-02-24 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: thor
@@ -69,6 +69,20 @@ dependencies:
69
69
  - - ">="
70
70
  - !ruby/object:Gem::Version
71
71
  version: '0'
72
+ - !ruby/object:Gem::Dependency
73
+ name: coveralls
74
+ requirement: !ruby/object:Gem::Requirement
75
+ requirements:
76
+ - - ">="
77
+ - !ruby/object:Gem::Version
78
+ version: '0'
79
+ type: :development
80
+ prerelease: false
81
+ version_requirements: !ruby/object:Gem::Requirement
82
+ requirements:
83
+ - - ">="
84
+ - !ruby/object:Gem::Version
85
+ version: '0'
72
86
  - !ruby/object:Gem::Dependency
73
87
  name: bundler
74
88
  requirement: !ruby/object:Gem::Requirement
@@ -84,7 +98,7 @@ dependencies:
84
98
  - !ruby/object:Gem::Version
85
99
  version: '0'
86
100
  - !ruby/object:Gem::Dependency
87
- name: rspec
101
+ name: byebug
88
102
  requirement: !ruby/object:Gem::Requirement
89
103
  requirements:
90
104
  - - ">="
@@ -112,7 +126,7 @@ dependencies:
112
126
  - !ruby/object:Gem::Version
113
127
  version: '0'
114
128
  - !ruby/object:Gem::Dependency
115
- name: simplecov
129
+ name: rspec
116
130
  requirement: !ruby/object:Gem::Requirement
117
131
  requirements:
118
132
  - - ">="
@@ -140,7 +154,7 @@ dependencies:
140
154
  - !ruby/object:Gem::Version
141
155
  version: 0.42.0
142
156
  - !ruby/object:Gem::Dependency
143
- name: byebug
157
+ name: simplecov
144
158
  requirement: !ruby/object:Gem::Requirement
145
159
  requirements:
146
160
  - - ">="
@@ -176,8 +190,9 @@ files:
176
190
  - lib/oneview-sdk/config_loader.rb
177
191
  - lib/oneview-sdk/exceptions.rb
178
192
  - lib/oneview-sdk/image-streamer/client.rb
179
- - lib/oneview-sdk/image-streamer/resource/api300/artifacts_bundle.rb
193
+ - lib/oneview-sdk/image-streamer/resource/api300/artifact_bundle.rb
180
194
  - lib/oneview-sdk/image-streamer/resource/api300/build_plan.rb
195
+ - lib/oneview-sdk/image-streamer/resource/api300/deployment_group.rb
181
196
  - lib/oneview-sdk/image-streamer/resource/api300/deployment_plan.rb
182
197
  - lib/oneview-sdk/image-streamer/resource/api300/golden_image.rb
183
198
  - lib/oneview-sdk/image-streamer/resource/api300/os_volume.rb