oneview-sdk 1.0.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 +7 -0
- data/.gitattributes +2 -0
- data/.gitignore +29 -0
- data/.rubocop.yml +73 -0
- data/.travis.yml +8 -0
- data/CHANGELOG.md +39 -0
- data/Gemfile +2 -0
- data/LICENSE +201 -0
- data/README.md +317 -0
- data/Rakefile +90 -0
- data/bin/oneview-sdk-ruby +4 -0
- data/lib/oneview-sdk.rb +9 -0
- data/lib/oneview-sdk/cli.rb +407 -0
- data/lib/oneview-sdk/client.rb +163 -0
- data/lib/oneview-sdk/config_loader.rb +20 -0
- data/lib/oneview-sdk/resource.rb +313 -0
- data/lib/oneview-sdk/resource/enclosure.rb +169 -0
- data/lib/oneview-sdk/resource/enclosure_group.rb +98 -0
- data/lib/oneview-sdk/resource/ethernet_network.rb +60 -0
- data/lib/oneview-sdk/resource/fc_network.rb +31 -0
- data/lib/oneview-sdk/resource/fcoe_network.rb +25 -0
- data/lib/oneview-sdk/resource/firmware_bundle.rb +37 -0
- data/lib/oneview-sdk/resource/firmware_driver.rb +21 -0
- data/lib/oneview-sdk/resource/interconnect.rb +87 -0
- data/lib/oneview-sdk/resource/lig_uplink_set.rb +86 -0
- data/lib/oneview-sdk/resource/logical_enclosure.rb +84 -0
- data/lib/oneview-sdk/resource/logical_interconnect.rb +283 -0
- data/lib/oneview-sdk/resource/logical_interconnect_group.rb +92 -0
- data/lib/oneview-sdk/resource/server_hardware.rb +88 -0
- data/lib/oneview-sdk/resource/server_hardware_type.rb +27 -0
- data/lib/oneview-sdk/resource/server_profile.rb +37 -0
- data/lib/oneview-sdk/resource/server_profile_template.rb +24 -0
- data/lib/oneview-sdk/resource/storage_pool.rb +41 -0
- data/lib/oneview-sdk/resource/storage_system.rb +63 -0
- data/lib/oneview-sdk/resource/uplink_set.rb +119 -0
- data/lib/oneview-sdk/resource/volume.rb +188 -0
- data/lib/oneview-sdk/resource/volume_snapshot.rb +27 -0
- data/lib/oneview-sdk/resource/volume_template.rb +106 -0
- data/lib/oneview-sdk/rest.rb +163 -0
- data/lib/oneview-sdk/ssl_helper.rb +75 -0
- data/lib/oneview-sdk/version.rb +4 -0
- data/oneview-sdk.gemspec +31 -0
- metadata +204 -0
data/Rakefile
ADDED
@@ -0,0 +1,90 @@
|
|
1
|
+
require 'bundler'
|
2
|
+
require 'bundler/gem_tasks'
|
3
|
+
require 'bundler/setup'
|
4
|
+
require 'rspec/core/rake_task'
|
5
|
+
require 'rubocop/rake_task'
|
6
|
+
|
7
|
+
task default: :spec
|
8
|
+
spec_pattern = 'spec/**/*_spec.rb'
|
9
|
+
def_spec_options = '--color '
|
10
|
+
def_int_spec_options = '-f d --color '
|
11
|
+
|
12
|
+
desc 'Run unit tests only'
|
13
|
+
RSpec::Core::RakeTask.new(:spec) do |spec|
|
14
|
+
spec.pattern = spec_pattern
|
15
|
+
spec.rspec_opts = def_spec_options
|
16
|
+
spec.rspec_opts << ' --tag ~integration'
|
17
|
+
spec.rspec_opts << ' --tag ~system'
|
18
|
+
end
|
19
|
+
|
20
|
+
desc 'Run integration tests only'
|
21
|
+
RSpec::Core::RakeTask.new('spec:integration') do |spec|
|
22
|
+
spec.pattern = spec_pattern
|
23
|
+
spec.rspec_opts = def_int_spec_options
|
24
|
+
spec.rspec_opts << ' --tag integration'
|
25
|
+
end
|
26
|
+
|
27
|
+
desc 'Run integration creation tests only'
|
28
|
+
RSpec::Core::RakeTask.new('spec:integration:create') do |spec|
|
29
|
+
spec.pattern = 'spec/**/*create_spec.rb'
|
30
|
+
spec.rspec_opts = def_int_spec_options
|
31
|
+
spec.rspec_opts << ' --tag integration'
|
32
|
+
end
|
33
|
+
|
34
|
+
desc 'Run integration update tests only'
|
35
|
+
RSpec::Core::RakeTask.new('spec:integration:update') do |spec|
|
36
|
+
spec.pattern = 'spec/**/*update_spec.rb'
|
37
|
+
spec.rspec_opts = def_int_spec_options
|
38
|
+
spec.rspec_opts << ' --tag integration'
|
39
|
+
end
|
40
|
+
|
41
|
+
desc 'Run integration deletion tests only'
|
42
|
+
RSpec::Core::RakeTask.new('spec:integration:delete') do |spec|
|
43
|
+
spec.pattern = 'spec/**/*delete_spec.rb'
|
44
|
+
spec.rspec_opts = def_int_spec_options
|
45
|
+
spec.rspec_opts << ' --tag integration'
|
46
|
+
end
|
47
|
+
|
48
|
+
desc 'Run System tests'
|
49
|
+
RSpec::Core::RakeTask.new('spec:system') do |spec|
|
50
|
+
spec.pattern = 'spec/**/*_spec.rb'
|
51
|
+
spec.rspec_opts = def_int_spec_options
|
52
|
+
spec.rspec_opts << ' --tag system'
|
53
|
+
end
|
54
|
+
|
55
|
+
desc 'Run System tests Light Profile'
|
56
|
+
RSpec::Core::RakeTask.new('spec:system:light') do |spec|
|
57
|
+
spec.pattern = 'spec/system/light_profile/*_spec.rb'
|
58
|
+
spec.rspec_opts = def_int_spec_options
|
59
|
+
spec.rspec_opts << ' --tag system'
|
60
|
+
end
|
61
|
+
|
62
|
+
desc 'Run System tests Medium Profile'
|
63
|
+
RSpec::Core::RakeTask.new('spec:system:medium') do |spec|
|
64
|
+
spec.pattern = 'spec/system/medium_profile/*_spec.rb'
|
65
|
+
spec.rspec_opts = def_int_spec_options
|
66
|
+
spec.rspec_opts << ' --tag system'
|
67
|
+
end
|
68
|
+
|
69
|
+
desc 'Run System tests Heavy Profile'
|
70
|
+
RSpec::Core::RakeTask.new('spec:system:heavy') do |spec|
|
71
|
+
spec.pattern = 'spec/system/heavy_profile/*_spec.rb'
|
72
|
+
spec.rspec_opts = def_int_spec_options
|
73
|
+
spec.rspec_opts << ' --tag system'
|
74
|
+
end
|
75
|
+
|
76
|
+
RuboCop::RakeTask.new
|
77
|
+
|
78
|
+
desc 'Runs rubocop and unit tests'
|
79
|
+
task :test do
|
80
|
+
Rake::Task[:rubocop].invoke
|
81
|
+
Rake::Task[:spec].invoke
|
82
|
+
end
|
83
|
+
|
84
|
+
desc 'Run rubocop, unit & integration tests'
|
85
|
+
task 'test:all' do
|
86
|
+
Rake::Task[:rubocop].invoke
|
87
|
+
Rake::Task[:spec].invoke
|
88
|
+
Rake::Task['spec:integration'].invoke
|
89
|
+
Rake::Task['spec:system'].invoke
|
90
|
+
end
|
data/lib/oneview-sdk.rb
ADDED
@@ -0,0 +1,9 @@
|
|
1
|
+
require_relative 'oneview-sdk/version'
|
2
|
+
require_relative 'oneview-sdk/client'
|
3
|
+
require_relative 'oneview-sdk/resource'
|
4
|
+
require_relative 'oneview-sdk/cli'
|
5
|
+
|
6
|
+
# Module for interracting with the HPE OneView API
|
7
|
+
module OneviewSDK
|
8
|
+
ENV_VARS = %w(ONEVIEWSDK_URL ONEVIEWSDK_USER ONEVIEWSDK_PASSWORD ONEVIEWSDK_TOKEN ONEVIEWSDK_SSL_ENABLED).freeze
|
9
|
+
end
|
@@ -0,0 +1,407 @@
|
|
1
|
+
require 'thor'
|
2
|
+
require 'json'
|
3
|
+
require 'yaml'
|
4
|
+
require 'highline/import'
|
5
|
+
|
6
|
+
module OneviewSDK
|
7
|
+
# cli for oneview-sdk
|
8
|
+
class Cli < Thor
|
9
|
+
# Runner class to enable testing
|
10
|
+
class Runner
|
11
|
+
def initialize(argv, stdin = STDIN, stdout = STDOUT, stderr = STDERR, kernel = Kernel)
|
12
|
+
@argv = argv
|
13
|
+
@stdin = stdin
|
14
|
+
@stdout = stdout
|
15
|
+
@stderr = stderr
|
16
|
+
@kernel = kernel
|
17
|
+
end
|
18
|
+
|
19
|
+
def execute!
|
20
|
+
exit_code = begin
|
21
|
+
$stderr = @stderr
|
22
|
+
$stdin = @stdin
|
23
|
+
$stdout = @stdout
|
24
|
+
|
25
|
+
OneviewSDK::Cli.start(@argv)
|
26
|
+
0
|
27
|
+
rescue StandardError => e
|
28
|
+
b = e.backtrace
|
29
|
+
@stderr.puts("#{b.shift}: #{e.message} (#{e.class})")
|
30
|
+
@stderr.puts(b.map { |s| "\tfrom #{s}" }.join("\n"))
|
31
|
+
1
|
32
|
+
rescue SystemExit => e
|
33
|
+
e.status
|
34
|
+
end
|
35
|
+
|
36
|
+
# Proxy our exit code back to the injected kernel.
|
37
|
+
@kernel.exit(exit_code)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
class_option :ssl_verify,
|
42
|
+
type: :boolean,
|
43
|
+
desc: 'Enable/Disable SSL verification for requests. Can also use ENV[\'ONEVIEWSDK_SSL_ENABLED\']',
|
44
|
+
default: nil
|
45
|
+
|
46
|
+
class_option :url,
|
47
|
+
desc: 'URL of OneView appliance. Can also use ENV[\'ONEVIEWSDK_URL\']',
|
48
|
+
aliases: '-u'
|
49
|
+
|
50
|
+
class_option :api_version,
|
51
|
+
type: :numeric,
|
52
|
+
banner: 'VERSION',
|
53
|
+
desc: 'API version to use'
|
54
|
+
|
55
|
+
class_option :log_level,
|
56
|
+
desc: 'Log level to use',
|
57
|
+
aliases: '-l',
|
58
|
+
enum: %w(debug info warn error),
|
59
|
+
default: 'warn'
|
60
|
+
|
61
|
+
map ['-v', '--version'] => :version
|
62
|
+
|
63
|
+
|
64
|
+
desc 'console', 'Open a Ruby console with a connection to OneView'
|
65
|
+
def console
|
66
|
+
client_setup({}, true, true)
|
67
|
+
puts "Console Connected to #{@client.url}"
|
68
|
+
puts "HINT: The @client object is available to you\n\n"
|
69
|
+
rescue
|
70
|
+
puts "WARNING: Couldn't connect to #{@options['url'] || ENV['ONEVIEWSDK_URL']}\n\n"
|
71
|
+
ensure
|
72
|
+
require 'pry'
|
73
|
+
Pry.config.prompt = proc { '> ' }
|
74
|
+
Pry.plugins['stack_explorer'] && Pry.plugins['stack_explorer'].disable!
|
75
|
+
Pry.plugins['byebug'] && Pry.plugins['byebug'].disable!
|
76
|
+
Pry.start(OneviewSDK::Console.new(@client))
|
77
|
+
end
|
78
|
+
|
79
|
+
desc 'version', 'Print gem and OneView appliance versions'
|
80
|
+
def version
|
81
|
+
puts "Gem Version: #{OneviewSDK::VERSION}"
|
82
|
+
client_setup({ 'log_level' => :error }, true)
|
83
|
+
puts "OneView appliance API version at '#{@client.url}' = #{@client.max_api_version}"
|
84
|
+
rescue StandardError, SystemExit
|
85
|
+
puts 'OneView appliance API version unknown'
|
86
|
+
end
|
87
|
+
|
88
|
+
method_option :format,
|
89
|
+
desc: 'Output format',
|
90
|
+
aliases: '-f',
|
91
|
+
enum: %w(json yaml human),
|
92
|
+
default: 'human'
|
93
|
+
desc 'env', 'Show environment variables for oneview-sdk-ruby'
|
94
|
+
def env
|
95
|
+
data = {}
|
96
|
+
OneviewSDK::ENV_VARS.each { |k| data[k] = ENV[k] }
|
97
|
+
if @options['format'] == 'human'
|
98
|
+
data.each do |key, value|
|
99
|
+
value = "'#{value}'" if value && ! %w(true false).include?(value)
|
100
|
+
printf "%-#{data.keys.max_by(&:length).length}s = %s\n", key, value || 'nil'
|
101
|
+
end
|
102
|
+
else
|
103
|
+
output(parse_hash(data, true))
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
desc 'login', 'Attempt authentication and return token'
|
108
|
+
def login
|
109
|
+
client_setup
|
110
|
+
puts "Login Successful! Token = #{@client.token}"
|
111
|
+
end
|
112
|
+
|
113
|
+
method_option :format,
|
114
|
+
desc: 'Output format',
|
115
|
+
aliases: '-f',
|
116
|
+
enum: %w(json yaml human),
|
117
|
+
default: 'human'
|
118
|
+
desc 'list TYPE', 'List names of resources'
|
119
|
+
def list(type)
|
120
|
+
resource_class = parse_type(type)
|
121
|
+
client_setup
|
122
|
+
data = []
|
123
|
+
resource_class.get_all(@client).each { |r| data.push(r[:name]) }
|
124
|
+
output data
|
125
|
+
end
|
126
|
+
|
127
|
+
method_option :format,
|
128
|
+
desc: 'Output format',
|
129
|
+
aliases: '-f',
|
130
|
+
enum: %w(json yaml human),
|
131
|
+
default: 'human'
|
132
|
+
method_option :attribute,
|
133
|
+
type: :string,
|
134
|
+
desc: 'Comma-seperated list of attributes to show',
|
135
|
+
aliases: '-a'
|
136
|
+
desc 'show TYPE NAME', 'Show resource details'
|
137
|
+
def show(type, name)
|
138
|
+
resource_class = parse_type(type)
|
139
|
+
client_setup
|
140
|
+
matches = resource_class.find_by(@client, name: name)
|
141
|
+
fail_nice 'Not Found' if matches.empty?
|
142
|
+
data = matches.first.data
|
143
|
+
if options['attribute']
|
144
|
+
new_data = {}
|
145
|
+
options['attribute'].split(',').each do |attr|
|
146
|
+
new_data[attr] = data[attr]
|
147
|
+
end
|
148
|
+
data = new_data
|
149
|
+
end
|
150
|
+
output data
|
151
|
+
end
|
152
|
+
|
153
|
+
method_option :format,
|
154
|
+
desc: 'Output format',
|
155
|
+
aliases: '-f',
|
156
|
+
enum: %w(json yaml human),
|
157
|
+
default: 'human'
|
158
|
+
method_option :attribute,
|
159
|
+
type: :string,
|
160
|
+
desc: 'Comma-seperated list of attributes to show',
|
161
|
+
aliases: '-a'
|
162
|
+
method_option :filter,
|
163
|
+
type: :hash,
|
164
|
+
desc: 'Hash of key/value pairs to filter on',
|
165
|
+
required: true
|
166
|
+
desc 'search TYPE', 'Search for resource by key/value pair(s)'
|
167
|
+
def search(type)
|
168
|
+
resource_class = parse_type(type)
|
169
|
+
client_setup
|
170
|
+
filter = parse_hash(options['filter'])
|
171
|
+
matches = resource_class.find_by(@client, filter)
|
172
|
+
if matches.empty? # Search with integers & booleans converted
|
173
|
+
filter = parse_hash(options['filter'], true)
|
174
|
+
matches = resource_class.find_by(@client, filter) unless filter == options['filter']
|
175
|
+
end
|
176
|
+
if options['attribute']
|
177
|
+
data = []
|
178
|
+
matches.each do |d|
|
179
|
+
temp = {}
|
180
|
+
options['attribute'].split(',').each do |attr|
|
181
|
+
temp[attr] = d[attr]
|
182
|
+
end
|
183
|
+
data.push temp
|
184
|
+
end
|
185
|
+
output data
|
186
|
+
else # List names only by default
|
187
|
+
names = []
|
188
|
+
matches.each { |m| names.push(m['name']) }
|
189
|
+
output names
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
method_option :force,
|
194
|
+
desc: 'Delete without confirmation',
|
195
|
+
type: :boolean,
|
196
|
+
aliases: '-f'
|
197
|
+
desc 'delete TYPE NAME', 'Delete resource by name'
|
198
|
+
def delete(type, name)
|
199
|
+
resource_class = parse_type(type)
|
200
|
+
client_setup
|
201
|
+
matches = resource_class.find_by(@client, name: name)
|
202
|
+
fail_nice 'Not Found' if matches.empty?
|
203
|
+
resource = matches.first
|
204
|
+
return unless options['force'] || agree("Delete '#{name}'? [Y/N] ")
|
205
|
+
begin
|
206
|
+
resource.delete
|
207
|
+
output 'Deleted Successfully!'
|
208
|
+
rescue StandardError => e
|
209
|
+
fail_nice "Failed to delete #{resource.class.name.split('::').last} '#{name}': #{e}"
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
method_option :force,
|
214
|
+
desc: 'Delete without confirmation',
|
215
|
+
type: :boolean,
|
216
|
+
aliases: '-f'
|
217
|
+
desc 'delete_from_file FILE_PATH', 'Delete resource defined in file'
|
218
|
+
def delete_from_file(file_path)
|
219
|
+
client_setup
|
220
|
+
resource = OneviewSDK::Resource.from_file(@client, file_path)
|
221
|
+
fail_nice 'File must define name or uri' unless resource[:name] || resource[:uri]
|
222
|
+
found = resource.retrieve! rescue false
|
223
|
+
found ||= resource.refresh rescue false
|
224
|
+
fail_nice "#{resource.class.name.split('::').last} '#{resource[:name] || resource[:uri]}' Not Found" unless found
|
225
|
+
unless options['force'] || agree("Delete '#{resource[:name]}'? [Y/N] ")
|
226
|
+
puts 'OK, exiting.'
|
227
|
+
return
|
228
|
+
end
|
229
|
+
begin
|
230
|
+
resource.delete
|
231
|
+
output 'Deleted Successfully!'
|
232
|
+
rescue StandardError => e
|
233
|
+
fail_nice "Failed to delete #{resource.class.name.split('::').last} '#{resource[:name]}': #{e}"
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
237
|
+
method_option :force,
|
238
|
+
desc: 'Overwrite without confirmation',
|
239
|
+
type: :boolean,
|
240
|
+
aliases: '-f'
|
241
|
+
method_option :if_missing,
|
242
|
+
desc: 'Only create if missing (Don\'t update)',
|
243
|
+
type: :boolean,
|
244
|
+
aliases: '-i'
|
245
|
+
desc 'create_from_file FILE_PATH', 'Create/Overwrite resource defined in file'
|
246
|
+
def create_from_file(file_path)
|
247
|
+
fail_nice "Can't use the 'force' and 'if_missing' flags at the same time." if options['force'] && options['if_missing']
|
248
|
+
client_setup
|
249
|
+
resource = OneviewSDK::Resource.from_file(@client, file_path)
|
250
|
+
resource[:uri] = nil
|
251
|
+
fail_nice 'File must specify a resource name' unless resource[:name]
|
252
|
+
existing_resource = resource.class.find_by(@client, name: resource[:name]).first
|
253
|
+
if existing_resource
|
254
|
+
if options['if_missing']
|
255
|
+
puts "Skipped: '#{resource[:name]}': #{resource.class.name.split('::').last} already exists."
|
256
|
+
return
|
257
|
+
end
|
258
|
+
fail_nice "#{resource.class.name.split('::').last} '#{resource[:name]}' already exists." unless options['force']
|
259
|
+
begin
|
260
|
+
resource.data.delete('uri')
|
261
|
+
existing_resource.update(resource.data)
|
262
|
+
output "Updated Successfully!\n#{resource[:uri]}"
|
263
|
+
rescue StandardError => e
|
264
|
+
fail_nice "Failed to update #{resource.class.name.split('::').last} '#{resource[:name]}': #{e}"
|
265
|
+
end
|
266
|
+
else
|
267
|
+
begin
|
268
|
+
resource.create
|
269
|
+
output "Created Successfully!\n#{resource[:uri]}"
|
270
|
+
rescue StandardError => e
|
271
|
+
fail_nice "Failed to create #{resource.class.name.split('::').last} '#{resource[:name]}': #{e}"
|
272
|
+
end
|
273
|
+
end
|
274
|
+
end
|
275
|
+
|
276
|
+
desc 'cert check|import|list URL', 'Check, import, or list OneView certs'
|
277
|
+
def cert(type, url = ENV['ONEVIEWSDK_URL'])
|
278
|
+
case type.downcase
|
279
|
+
when 'check'
|
280
|
+
fail_nice 'Must specify a url' unless url
|
281
|
+
puts "Checking certificate for '#{url}' ..."
|
282
|
+
if OneviewSDK::SSLHelper.check_cert(url)
|
283
|
+
puts 'Certificate is valid!'
|
284
|
+
else
|
285
|
+
fail_nice 'Certificate Validation Failed!'
|
286
|
+
end
|
287
|
+
when 'import'
|
288
|
+
fail_nice 'Must specify a url' unless url
|
289
|
+
puts "Importing certificate for '#{url}' into '#{OneviewSDK::SSLHelper::CERT_STORE}'..."
|
290
|
+
OneviewSDK::SSLHelper.install_cert(url)
|
291
|
+
when 'list'
|
292
|
+
if File.file?(OneviewSDK::SSLHelper::CERT_STORE)
|
293
|
+
puts File.read(OneviewSDK::SSLHelper::CERT_STORE)
|
294
|
+
else
|
295
|
+
puts 'No certs imported!'
|
296
|
+
end
|
297
|
+
else fail_nice "Invalid action '#{type}'. Valid actions are [check, import, list]"
|
298
|
+
end
|
299
|
+
rescue StandardError => e
|
300
|
+
fail_nice e.message
|
301
|
+
end
|
302
|
+
|
303
|
+
private
|
304
|
+
|
305
|
+
def fail_nice(msg = nil)
|
306
|
+
puts "ERROR: #{msg}" if msg
|
307
|
+
exit 1
|
308
|
+
end
|
309
|
+
|
310
|
+
def client_setup(client_params = {}, quiet = false, throw_errors = false)
|
311
|
+
client_params['ssl_enabled'] = true if @options['ssl_verify'] == true
|
312
|
+
client_params['ssl_enabled'] = false if @options['ssl_verify'] == false
|
313
|
+
client_params['url'] ||= @options['url'] if @options['url']
|
314
|
+
client_params['log_level'] ||= @options['log_level'].to_sym if @options['log_level']
|
315
|
+
@client = OneviewSDK::Client.new(client_params)
|
316
|
+
rescue StandardError => e
|
317
|
+
raise e if throw_errors
|
318
|
+
fail_nice if quiet
|
319
|
+
fail_nice "Failed to login to OneView appliance at '#{client_params['url']}'. Message: #{e}"
|
320
|
+
end
|
321
|
+
|
322
|
+
# Get resource class from given string
|
323
|
+
def parse_type(type)
|
324
|
+
valid_classes = []
|
325
|
+
ObjectSpace.each_object(Class).select { |klass| klass < OneviewSDK::Resource }.each do |c|
|
326
|
+
valid_classes.push(c.name.split('::').last)
|
327
|
+
end
|
328
|
+
OneviewSDK.resource_named(type) || fail_nice("Invalid resource type: '#{type}'.\n Valid options are #{valid_classes}")
|
329
|
+
end
|
330
|
+
|
331
|
+
# Parse options hash from input. Handles chaining and keywords such as true/false & nil
|
332
|
+
# Returns new hash with proper nesting and formatting
|
333
|
+
def parse_hash(hash, convert_types = false)
|
334
|
+
new_hash = {}
|
335
|
+
hash.each do |k, v|
|
336
|
+
if convert_types
|
337
|
+
v = v.to_i if v && v.match(/^\d+$/)
|
338
|
+
v = true if v == 'true'
|
339
|
+
v = false if v == 'false'
|
340
|
+
v = nil if v == 'nil'
|
341
|
+
end
|
342
|
+
if k =~ /\./
|
343
|
+
sub_hash = new_hash
|
344
|
+
split = k.split('.')
|
345
|
+
split.each do |sub_key|
|
346
|
+
if sub_key == split.last
|
347
|
+
sub_hash[sub_key] = v
|
348
|
+
else
|
349
|
+
sub_hash[sub_key] ||= {}
|
350
|
+
sub_hash = sub_hash[sub_key]
|
351
|
+
end
|
352
|
+
end
|
353
|
+
new_hash[split.first] ||= {}
|
354
|
+
else
|
355
|
+
new_hash[k] = v
|
356
|
+
end
|
357
|
+
end
|
358
|
+
new_hash
|
359
|
+
end
|
360
|
+
|
361
|
+
# Print output in a given format.
|
362
|
+
def output(data = {}, indent = 0)
|
363
|
+
case @options['format']
|
364
|
+
when 'json'
|
365
|
+
puts JSON.pretty_generate(data)
|
366
|
+
when 'yaml'
|
367
|
+
puts data.to_yaml
|
368
|
+
else
|
369
|
+
if data.class == Hash || data.class <= OneviewSDK::Resource
|
370
|
+
data.each do |k, v|
|
371
|
+
if v.class == Hash || v.class == Array
|
372
|
+
puts "#{' ' * indent}#{k}:"
|
373
|
+
output(v, indent + 2)
|
374
|
+
else
|
375
|
+
puts "#{' ' * indent}#{k}: #{v}"
|
376
|
+
end
|
377
|
+
end
|
378
|
+
elsif data.class == Array
|
379
|
+
data.each do |d|
|
380
|
+
if d.class == Hash || d.class == Array
|
381
|
+
# rubocop:disable Metrics/BlockNesting
|
382
|
+
if indent == 0
|
383
|
+
puts ''
|
384
|
+
output(d, indent)
|
385
|
+
else
|
386
|
+
output(d, indent + 2)
|
387
|
+
end
|
388
|
+
# rubocop:enable Metrics/BlockNesting
|
389
|
+
else
|
390
|
+
puts "#{' ' * indent}#{d}"
|
391
|
+
end
|
392
|
+
end
|
393
|
+
puts "\nTotal: #{data.size}" if indent == 0
|
394
|
+
else
|
395
|
+
puts "#{' ' * indent}#{data}"
|
396
|
+
end
|
397
|
+
end
|
398
|
+
end
|
399
|
+
end
|
400
|
+
|
401
|
+
# Console class
|
402
|
+
class Console
|
403
|
+
def initialize(client)
|
404
|
+
@client = client
|
405
|
+
end
|
406
|
+
end
|
407
|
+
end
|