oneview-sdk 4.0.0 → 4.1.0

Sign up to get free protection for your applications and to get access to all the features.
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