morpheus-cli 3.6.31 → 3.6.32

Sign up to get free protection for your applications and to get access to all the features.
@@ -94,10 +94,10 @@ class Morpheus::Cli::KeyPairs
94
94
 
95
95
  @key_pairs_interface.setopts(options)
96
96
  if options[:dry_run]
97
- if val.to_s =~ /\A\d{1,}\Z/
98
- print_dry_run @key_pairs_interface.dry.get(account_id, id.to_i)
97
+ if args[0].to_s =~ /\A\d{1,}\Z/
98
+ print_dry_run @key_pairs_interface.dry.get(account_id, args[0])
99
99
  else
100
- print_dry_run @key_pairs_interface.dry.list(account_id, {name: name.to_s})
100
+ print_dry_run @key_pairs_interface.dry.list(account_id, {name: args[0]})
101
101
  end
102
102
  return 0
103
103
  end
@@ -380,6 +380,10 @@ class Morpheus::Cli::LibraryContainerTypesCommand
380
380
  end
381
381
 
382
382
  end
383
+ # avoid API bug in 3.6.3
384
+ if payload['containerType']
385
+ payload['containerType']['config'] ||= {}
386
+ end
383
387
  @library_container_types_interface.setopts(options)
384
388
  if options[:dry_run]
385
389
  print_dry_run @library_container_types_interface.dry.create(layout_id, payload)
@@ -445,14 +449,16 @@ class Morpheus::Cli::LibraryContainerTypesCommand
445
449
  return 1
446
450
  end
447
451
  # construct payload
452
+ passed_options = options[:options] ? options[:options].reject {|k,v| k.is_a?(Symbol) } : {}
448
453
  payload = nil
449
454
  if options[:payload]
450
455
  payload = options[:payload]
456
+ payload.deep_merge!({'containerType' => passed_options}) unless passed_options.empty?
451
457
  else
452
- payload = {}
458
+ payload = {'containerType' => {} }
453
459
  # option_types = update_layout_option_types(instance_type)
454
460
  # params = Morpheus::Cli::OptionTypes.prompt(option_types, options[:options], @api_client, options[:params])
455
- payload.deep_merge!(options[:options].reject {|k,v| k.is_a?(Symbol) }) if options[:options]
461
+ payload.deep_merge!({'containerType' => passed_options}) unless passed_options.empty?
456
462
 
457
463
  # ENVIRONMENT VARIABLES
458
464
  if evars
@@ -475,9 +481,8 @@ class Morpheus::Cli::LibraryContainerTypesCommand
475
481
  # prompt
476
482
  end
477
483
 
478
- if params.empty?
479
- puts optparse
480
- exit 1
484
+ if params.empty? && passed_options.empty?
485
+ raise_command_error "Specify at least one option to update.\n#{optparse}"
481
486
  end
482
487
 
483
488
  # payload = {'containerType' => params}
@@ -293,6 +293,7 @@ module Morpheus::Cli::ProvisioningHelper
293
293
  arbitrary_options.delete('layout')
294
294
  arbitrary_options.delete('servicePlan')
295
295
  arbitrary_options.delete('description')
296
+ arbitrary_options.delete('environment')
296
297
  arbitrary_options.delete('instanceContext')
297
298
  arbitrary_options.delete('tags')
298
299
  payload.deep_merge!(arbitrary_options)
@@ -306,7 +307,12 @@ module Morpheus::Cli::ProvisioningHelper
306
307
  payload['instance']['description'] = v_prompt['description'] if !v_prompt['description'].empty?
307
308
 
308
309
  # Environment
309
- v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'instanceContext', 'fieldLabel' => 'Environment', 'type' => 'select', 'required' => false, 'selectOptions' => instance_context_options()}], options[:options])
310
+ if options[:environment]
311
+ options[:options]['environment'] = options[:environment]
312
+ elsif options[:options]['instanceContext'] && !options[:options]['environment']
313
+ options[:options]['environment'] = options[:options]['instanceContext']
314
+ end
315
+ v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'environment', 'fieldLabel' => 'Environment', 'type' => 'select', 'required' => false, 'selectOptions' => get_available_environments()}], options[:options])
310
316
  payload['instance']['instanceContext'] = v_prompt['instanceContext'] if !v_prompt['instanceContext'].empty?
311
317
 
312
318
  # Tags
@@ -384,7 +390,7 @@ module Morpheus::Cli::ProvisioningHelper
384
390
  # prompt for resource pool
385
391
  has_zone_pools = layout["provisionType"] && layout["provisionType"]["id"] && layout["provisionType"]["hasZonePools"]
386
392
  if has_zone_pools
387
- resource_pool_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldContext' => 'config', 'fieldName' => 'resourcePoolId', 'type' => 'select', 'fieldLabel' => 'Resource Pool', 'optionSource' => 'zonePools', 'required' => true, 'skipSingleOption' => true, 'description' => 'Select resource pool.'}],options[:options],api_client,{groupId: group_id, zoneId: cloud_id, cloudId: cloud_id, instanceTypeId: instance_type['id'], planId: service_plan["id"]})
393
+ resource_pool_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldContext' => 'config', 'fieldName' => 'resourcePoolId', 'type' => 'select', 'fieldLabel' => 'Resource Pool', 'optionSource' => 'zonePools', 'required' => true, 'skipSingleOption' => true, 'description' => 'Select resource pool.'}],options[:options],api_client,{groupId: group_id, siteId: group_id, zoneId: cloud_id, cloudId: cloud_id, instanceTypeId: instance_type['id'], planId: service_plan["id"], layoutId: layout["id"]})
388
394
  if resource_pool_prompt['config'] && resource_pool_prompt['config']['resourcePoolId']
389
395
  payload['config'] ||= {}
390
396
  payload['config']['resourcePoolId'] = resource_pool_prompt['config']['resourcePoolId']
@@ -1185,7 +1191,26 @@ module Morpheus::Cli::ProvisioningHelper
1185
1191
  }
1186
1192
  end
1187
1193
 
1188
- def instance_context_options
1194
+ def get_available_environments(refresh=false)
1195
+ if !@available_environments || refresh
1196
+ begin
1197
+ option_results = options_interface.options_for_source('environments',{})
1198
+ @available_environments = option_results['data'].collect {|it|
1199
+ {"code" => (it["code"] || it["value"]), "name" => it["name"], "value" => it["value"]}
1200
+ }
1201
+ rescue RestClient::Exception => e
1202
+ # if e.response && e.response.code == 404
1203
+ Morpheus::Logging::DarkPrinter.puts "Unable to determine available environments, using default options" if Morpheus::Logging.debug?
1204
+ @available_environments = get_static_environments()
1205
+ # else
1206
+ # raise e
1207
+ # end
1208
+ end
1209
+ end
1210
+ return @available_environments
1211
+ end
1212
+
1213
+ def get_static_environments
1189
1214
  [{'name' => 'Dev', 'value' => 'dev'}, {'name' => 'Test', 'value' => 'qa'}, {'name' => 'Staging', 'value' => 'staging'}, {'name' => 'Production', 'value' => 'production'}]
1190
1215
  end
1191
1216
 
@@ -36,6 +36,9 @@ class Morpheus::Cli::NetworksCommand
36
36
  params = {}
37
37
  optparse = Morpheus::Cli::OptionParser.new do |opts|
38
38
  opts.banner = subcommand_usage()
39
+ opts.on( '-c', '--cloud CLOUD', "Cloud" ) do |val|
40
+ options[:cloud] = val
41
+ end
39
42
  opts.on('--cidr VALUE', String, "Filter by cidr, matches beginning of value.") do |val|
40
43
  params['cidr'] = val
41
44
  end
@@ -46,6 +49,12 @@ class Morpheus::Cli::NetworksCommand
46
49
  connect(options)
47
50
  begin
48
51
  params.merge!(parse_list_options(options))
52
+ cloud = nil
53
+ if options[:cloud]
54
+ cloud = find_cloud_by_name_or_id(options[:cloud])
55
+ return 1 if cloud.nil?
56
+ params['zoneId'] = cloud['id']
57
+ end
49
58
  @networks_interface.setopts(options)
50
59
  if options[:dry_run]
51
60
  print_dry_run @networks_interface.dry.list(params)
@@ -65,6 +74,9 @@ class Morpheus::Cli::NetworksCommand
65
74
  end
66
75
  title = "Morpheus Networks"
67
76
  subtitles = []
77
+ if cloud
78
+ subtitles << "Cloud: #{cloud['id']}"
79
+ end
68
80
  subtitles += parse_list_subtitles(options)
69
81
  print_h1 title, subtitles
70
82
  if networks.empty?
@@ -31,12 +31,12 @@ class Morpheus::Cli::RecentActivityCommand
31
31
  optparse = Morpheus::Cli::OptionParser.new do |opts|
32
32
  opts.banner = usage
33
33
  opts.on('--start TIMESTAMP','--start TIMESTAMP', "Start timestamp. Default is 30 days ago.") do |val|
34
- options[:start] = parse_time(val).iso8601
34
+ options[:start] = parse_time(val).utc.iso8601
35
35
  end
36
36
  opts.on('--end TIMESTAMP','--end TIMESTAMP', "End timestamp. Default is now.") do |val|
37
- options[:end] = parse_time(val).iso8601
37
+ options[:end] = parse_time(val).utc.iso8601
38
38
  end
39
- build_common_options(opts, options, [:account, :list, :json, :yaml, :csv, :fields, :dry_run, :remote])
39
+ build_common_options(opts, options, [:account, :query, :list, :json, :yaml, :csv, :fields, :dry_run, :remote])
40
40
  end
41
41
  optparse.parse!(args)
42
42
  connect(options)
@@ -45,6 +45,12 @@ class Morpheus::Cli::RecentActivityCommand
45
45
  account_id = account ? account['id'] : nil
46
46
  params = {}
47
47
  params.merge!(parse_list_options(options))
48
+ if options[:start]
49
+ params['start'] = options[:start]
50
+ end
51
+ if options[:end]
52
+ params['end'] = options[:end]
53
+ end
48
54
  @dashboard_interface.setopts(options)
49
55
  if options[:dry_run]
50
56
  print_dry_run @dashboard_interface.dry.recent_activity(account_id, params)
@@ -74,7 +74,7 @@ EOT
74
74
  columns = [
75
75
  {:active => {:display_name => "", :display_method => lambda {|it| it[:active] ? "=>" : "" } } },
76
76
  # {:name => {display_method: lambda {|it| it[:active] ? "#{green}#{it[:name]}#{reset}#{cyan}" : it[:name] }, :width => 16 } },
77
- {:name => {display_method: lambda {|it| it[:name] }, :width => 16 } },
77
+ {:name => {display_method: lambda {|it| it[:name] } } },
78
78
  {:url => {display_method: lambda {|it| it[:host] || it[:url] }, :width => 40 } },
79
79
  {:version => lambda {|it| it[:build_version] } },
80
80
  {:status => lambda {|it| format_appliance_status(it, cyan) } },
@@ -104,6 +104,9 @@ class Morpheus::Cli::ReportsCommand
104
104
  opts.on('--rows', '--rows', "Print Report Data rows too.") do
105
105
  options[:show_data_rows] = true
106
106
  end
107
+ opts.on('--view', '--view', "View report result in web browser too.") do
108
+ options[:view_report] = true
109
+ end
107
110
  build_common_options(opts, options, [:json, :yaml, :csv, :fields, :outfile, :dry_run, :remote])
108
111
  opts.footer = "Get details about a report result." + "\n"
109
112
  + "[id] is required. This is the id of the report result."
@@ -166,11 +169,11 @@ class Morpheus::Cli::ReportsCommand
166
169
  if data_width < 0
167
170
  data_wdith = 10
168
171
  end
169
- puts as_pretty_table(report_result['rows'], {
172
+ puts as_pretty_table(report_result['rows'], options[:include_fields] || {
170
173
  "ID" => lambda {|it| it['id'] },
171
174
  "SECTION" => lambda {|it| it['section'] },
172
175
  "DATA" => lambda {|it| truncate_string(it['data'], data_width) }
173
- })
176
+ }, options.merge({:responsive_table => false}))
174
177
 
175
178
  else
176
179
  print yellow, "No report data found.", reset, "\n"
@@ -193,6 +196,9 @@ class Morpheus::Cli::ReportsCommand
193
196
  get(original_args)
194
197
  end
195
198
  end
199
+ if options[:view_report]
200
+ view([report_result['id']])
201
+ end
196
202
  return 0
197
203
  rescue RestClient::Exception => e
198
204
  print_rest_exception(e, options)
@@ -218,6 +224,9 @@ class Morpheus::Cli::ReportsCommand
218
224
  opts.on('--rows', '--rows', "Print Report Data rows too.") do
219
225
  options[:show_data_rows] = true
220
226
  end
227
+ opts.on('--view', '--view', "View report result in web browser when it is finished.") do
228
+ options[:view_report] = true
229
+ end
221
230
  build_common_options(opts, options, [:options, :payload, :json, :dry_run, :remote])
222
231
  opts.footer = "Run a report to generate a new result." + "\n" +
223
232
  "[type] is required. This is code of the report type."
@@ -257,16 +266,27 @@ class Morpheus::Cli::ReportsCommand
257
266
  return 1 if report_type.nil?
258
267
  payload['report']['type'] = report_type['code']
259
268
 
260
- # Report Types need to tell us what the available filters are...
269
+ # Report Types tell us what the available filters are...
270
+ report_option_types = report_type['optionTypes'] || []
271
+ # pluck out optionTypes like the UI does..
272
+ metadata_option_type = nil
273
+ if report_option_types.find {|it| it['fieldName'] == 'metadata' }
274
+ metadata_option_type = report_option_types.delete_if {|it| it['fieldName'] == 'metadata' }
275
+ end
261
276
 
262
- # Start Date
263
- v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'startDate', 'fieldLabel' => 'Start Date', 'type' => 'text', 'required' => false}], options[:options])
264
- payload['report']['startDate'] = v_prompt['startDate'] unless v_prompt['startDate'].to_s.empty?
277
+ v_prompt = Morpheus::Cli::OptionTypes.prompt(report_option_types, options[:options], @api_client)
265
278
 
266
- # End Date
267
- v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'endDate', 'fieldLabel' => 'End Date', 'type' => 'text', 'required' => false}], options[:options])
268
- payload['report']['endDate'] = v_prompt['endDate'] unless v_prompt['endDate'].to_s.empty?
279
+ if metadata_option_type
280
+ if !options[:options]['metadata']
281
+ metadata_filter = prompt_metadata(options)
282
+ if metadata_filter && !metadata_filter.empty?
283
+ payload['report']['metadata'] = metadata_filter
284
+ end
285
+ end
286
+ end
269
287
 
288
+ # payload.deep_merge!({'report' => v_prompt}) unless v_prompt.empty?
289
+ payload.deep_merge!(v_prompt) unless v_prompt.empty?
270
290
  end
271
291
 
272
292
  @reports_interface.setopts(options)
@@ -284,6 +304,7 @@ class Morpheus::Cli::ReportsCommand
284
304
  print_args = [json_response['reportResult']['id']]
285
305
  print_args << "--refresh" if do_refresh
286
306
  print_args << "--rows" if options[:show_data_rows]
307
+ print_args << "--view" if options[:view_report]
287
308
  get(print_args)
288
309
  return 0
289
310
  rescue RestClient::Exception => e
@@ -296,9 +317,9 @@ class Morpheus::Cli::ReportsCommand
296
317
  options = {}
297
318
  optparse = Morpheus::Cli::OptionParser.new do |opts|
298
319
  opts.banner = subcommand_usage("[id]")
299
- build_common_options(opts, options, [:auto_confirm, :json, :dry_run, :remote])
320
+ build_common_options(opts, options, [:dry_run, :remote])
300
321
  opts.footer = "View a report result in a web browser" + "\n" +
301
- "[id] is required. This is id of the report result."
322
+ "[id] is required. This is the id of the report result."
302
323
  end
303
324
  optparse.parse!(args)
304
325
  if args.count != 1
@@ -590,5 +611,33 @@ class Morpheus::Cli::ReportsCommand
590
611
  out
591
612
  end
592
613
 
614
+ # Prompts user for metadata for report filter
615
+ # returns array of metadata objects {id: null, name: "MYTAG", value: "myvalue"}
616
+ def prompt_metadata(options={})
617
+ #puts "Configure Environment Variables:"
618
+ no_prompt = (options[:no_prompt] || (options[:options] && options[:options][:no_prompt]))
619
+ metadata_filter = {}
620
+ metadata_index = 0
621
+ has_another_metadata = options[:options] && options[:options]["metadata#{metadata_index}"]
622
+ add_another_metadata = has_another_metadata || (!no_prompt && Morpheus::Cli::OptionTypes.confirm("Add a metadata tag filter?", {default: false}))
623
+ while add_another_metadata do
624
+ field_context = "metadata#{metadata_index}"
625
+ metadata = {}
626
+ metadata['id'] = nil
627
+ metadata_label = metadata_index == 0 ? "Metadata Tag" : "Metadata Tag [#{metadata_index+1}]"
628
+ v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldContext' => field_context, 'fieldName' => 'name', 'type' => 'text', 'fieldLabel' => "#{metadata_label} Name", 'required' => true, 'description' => 'Metadata Tag Name.', 'defaultValue' => metadata['name']}], options[:options])
629
+ # todo: metadata.type ?
630
+ metadata['name'] = v_prompt[field_context]['name'].to_s
631
+ v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldContext' => field_context, 'fieldName' => 'value', 'type' => 'text', 'fieldLabel' => "#{metadata_label} Value", 'required' => true, 'description' => 'Metadata Tag Value', 'defaultValue' => metadata['value']}], options[:options])
632
+ metadata['value'] = v_prompt[field_context]['value'].to_s
633
+ metadata_filter[metadata['name']] = metadata['value']
634
+ metadata_index += 1
635
+ has_another_metadata = options[:options] && options[:options]["metadata#{metadata_index}"]
636
+ add_another_metadata = has_another_metadata || (!no_prompt && Morpheus::Cli::OptionTypes.confirm("Add another metadata tag filter?", {default: false}))
637
+ end
638
+
639
+ return metadata_filter
640
+ end
641
+
593
642
  end
594
643
 
@@ -42,7 +42,7 @@ class Morpheus::Cli::TenantsCommand
42
42
  options = {}
43
43
  optparse = Morpheus::Cli::OptionParser.new do |opts|
44
44
  opts.banner = subcommand_usage()
45
- build_common_options(opts, options, [:list, :query, :json, :remote, :dry_run])
45
+ build_common_options(opts, options, [:list, :query, :json, :yaml, :csv, :fields, :dry_run, :remote])
46
46
  opts.footer = "List tenants (accounts)."
47
47
  end
48
48
  optparse.parse!(args)
@@ -56,23 +56,21 @@ class Morpheus::Cli::TenantsCommand
56
56
  return
57
57
  end
58
58
  json_response = @accounts_interface.list(params)
59
+ render_result = render_with_format(json_response, options, 'accounts')
60
+ return 0 if render_result
59
61
  accounts = json_response['accounts']
60
- if options[:json]
61
- print JSON.pretty_generate(json_response)
62
- print "\n"
62
+ title = "Morpheus Tenants"
63
+ subtitles = []
64
+ subtitles += parse_list_subtitles(options)
65
+ print_h1 title, subtitles
66
+ if accounts.empty?
67
+ puts yellow,"No tenants found.",reset
63
68
  else
64
- title = "Morpheus Tenants"
65
- subtitles = []
66
- subtitles += parse_list_subtitles(options)
67
- print_h1 title, subtitles
68
- if accounts.empty?
69
- puts yellow,"No tenants found.",reset
70
- else
71
- print_accounts_table(accounts)
72
- print_results_pagination(json_response)
73
- end
74
- print reset,"\n"
69
+ print_accounts_table(accounts)
70
+ print_results_pagination(json_response)
75
71
  end
72
+ print reset,"\n"
73
+ return 0
76
74
  rescue RestClient::Exception => e
77
75
  print_rest_exception(e, options)
78
76
  exit 1
@@ -113,7 +111,7 @@ class Morpheus::Cli::TenantsCommand
113
111
  options = {}
114
112
  optparse = Morpheus::Cli::OptionParser.new do |opts|
115
113
  opts.banner = subcommand_usage("[name]")
116
- build_common_options(opts, options, [:json, :remote, :dry_run])
114
+ build_common_options(opts, options, [:json, :yaml, :csv, :fields, :outfile, :dry_run, :remote])
117
115
  end
118
116
  optparse.parse!(args)
119
117
  if args.count != 1
@@ -132,36 +130,35 @@ class Morpheus::Cli::TenantsCommand
132
130
  end
133
131
  account = find_account_by_name_or_id(args[0])
134
132
  exit 1 if account.nil?
135
- if options[:json]
136
- print JSON.pretty_generate({account: account})
137
- print "\n"
138
- else
139
- print_h1 "Tenant Details"
140
- print cyan
141
- puts "ID: #{account['id']}"
142
- puts "Name: #{account['name']}"
143
- puts "Description: #{account['description']}"
144
- puts "Subdomain: #{account['subdomain']}" if !account['subdomain'].to_s.empty?
145
- puts "Currency: #{account['currency']}"
146
- # puts "# Users: #{account['usersCount']}"
147
- # puts "# Instances: #{account['instancesCount']}"
148
- puts "Date Created: #{format_local_dt(account['dateCreated'])}"
149
- puts "Last Updated: #{format_local_dt(account['lastUpdated'])}"
150
- status_state = nil
151
- if account['active']
152
- status_state = "#{green}ACTIVE#{cyan}"
153
- else
154
- status_state = "#{red}INACTIVE#{cyan}"
155
- end
156
- puts "Status: #{status_state}"
157
- # JD: pretty sure this is deprecated
158
- # print_h2 "Tenant Instance Limits"
159
- # print cyan
160
- # puts "Max Storage (bytes): #{account['instanceLimits'] ? account['instanceLimits']['maxStorage'] : 0}"
161
- # puts "Max Memory (bytes): #{account['instanceLimits'] ? account['instanceLimits']['maxMemory'] : 0}"
162
- # puts "CPU Count: #{account['instanceLimits'] ? account['instanceLimits']['maxCpu'] : 0}"
163
- print reset,"\n"
164
- end
133
+
134
+ json_response = {'account' => account}
135
+ render_result = render_with_format(json_response, options, 'account')
136
+ return 0 if render_result
137
+
138
+ print_h1 "Tenant Details", [], options
139
+
140
+ description_cols = {
141
+ "ID" => 'id',
142
+ "Name" => 'name',
143
+ "Description" => 'description',
144
+ "Subdomain" => 'subdomain',
145
+ "Currency" => 'currency',
146
+ "Created" => lambda {|it| format_local_dt(it['dateCreated']) },
147
+ "Updated" => lambda {|it| format_local_dt(it['lastUpdated']) },
148
+ "Status" => lambda {|it|
149
+ status_state = nil
150
+ if account['active']
151
+ status_state = "#{green}ACTIVE#{cyan}"
152
+ else
153
+ status_state = "#{red}INACTIVE#{cyan}"
154
+ end
155
+ status_state
156
+ },
157
+ }
158
+ print_description_list(description_cols, account)
159
+
160
+ print reset,"\n"
161
+ return 0
165
162
  rescue RestClient::Exception => e
166
163
  print_rest_exception(e, options)
167
164
  exit 1
@@ -1,6 +1,6 @@
1
1
 
2
2
  module Morpheus
3
3
  module Cli
4
- VERSION = "3.6.31"
4
+ VERSION = "3.6.32"
5
5
  end
6
6
  end
@@ -0,0 +1,461 @@
1
+ require 'io/console'
2
+ require 'rest_client'
3
+ require 'optparse'
4
+ require 'morpheus/cli/cli_command'
5
+ require 'morpheus/cli/option_types'
6
+ require 'json'
7
+
8
+ class Morpheus::Cli::WikiCommand
9
+ include Morpheus::Cli::CliCommand
10
+ set_command_name :wiki
11
+ register_subcommands :list, :get, :view, :add, :update, :remove, :'categories'
12
+
13
+ def initialize()
14
+ # @appliance_name, @appliance_url = Morpheus::Cli::Remote.active_appliance
15
+ end
16
+
17
+ def connect(opts)
18
+ @api_client = establish_remote_appliance_connection(opts)
19
+ @wiki_interface = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url).wiki
20
+ end
21
+
22
+ def handle(args)
23
+ handle_subcommand(args)
24
+ end
25
+
26
+ def list(args)
27
+ options = {}
28
+ params = {}
29
+ optparse = Morpheus::Cli::OptionParser.new do |opts|
30
+ opts.banner = subcommand_usage()
31
+ opts.on('--category VALUE', String, "Category") do |val|
32
+ params['category'] = val
33
+ end
34
+ build_common_options(opts, options, [:list, :query, :json, :yaml, :csv, :fields, :dry_run, :remote])
35
+ end
36
+ optparse.parse!(args)
37
+ if args.count != 0
38
+ raise_command_error "wrong number of arguments, expected 0 and got (#{args.count}) #{args}\n#{optparse}"
39
+ end
40
+ connect(options)
41
+ begin
42
+ params.merge!(parse_list_options(options))
43
+ @wiki_interface.setopts(options)
44
+ if options[:dry_run]
45
+ print_dry_run @wiki_interface.dry.list(params)
46
+ return 0
47
+ end
48
+ json_response = @wiki_interface.list(params)
49
+ render_result = render_with_format(json_response, options, 'pages')
50
+ return 0 if render_result
51
+ pages = json_response['pages']
52
+ unless options[:quiet]
53
+ title = "Morpheus Wiki Pages"
54
+ subtitles = []
55
+ if params['category']
56
+ subtitles << "Category: #{params['category']}"
57
+ end
58
+ subtitles += parse_list_subtitles(options)
59
+ print_h1 title, subtitles
60
+ if pages.empty?
61
+ print yellow,"No wiki pages found.",reset
62
+ else
63
+ columns = [
64
+ {"ID" => lambda {|page| page['id'] } },
65
+ {"NAME" => lambda {|page| page['name'] } },
66
+ {"CATEGORY" => lambda {|page| page['category'] } },
67
+ {"AUTHOR" => lambda {|page| page['updatedBy'] ? page['updatedBy']['username'] : '' } },
68
+ {"CREATED" => lambda {|page| format_local_dt(page['dateCreated']) } },
69
+ {"UPDATED" => lambda {|page| format_local_dt(page['lastUpdated']) } },
70
+ ]
71
+ if options[:include_fields]
72
+ columns = options[:include_fields]
73
+ end
74
+ print as_pretty_table(pages, columns, options)
75
+ print_results_pagination(json_response)
76
+ end
77
+ print reset,"\n"
78
+ end
79
+ return 0
80
+ rescue RestClient::Exception => e
81
+ print_rest_exception(e, options)
82
+ exit 1
83
+ end
84
+ end
85
+
86
+ def get(args)
87
+ options = {}
88
+ params = {}
89
+ open_wiki_link = false
90
+ optparse = Morpheus::Cli::OptionParser.new do |opts|
91
+ opts.banner = subcommand_usage("[name]")
92
+ opts.on('--view', '--view', "View wiki page in web browser too.") do
93
+ open_wiki_link = true
94
+ end
95
+ build_common_options(opts, options, [:query, :json, :yaml, :csv, :fields, :dry_run, :remote])
96
+ end
97
+ optparse.parse!(args)
98
+
99
+ if args.count != 1
100
+ raise_command_error "wrong number of arguments, expected 1 and got (#{args.count}) #{args}\n#{optparse}"
101
+ end
102
+
103
+ connect(options)
104
+ begin
105
+ @wiki_interface.setopts(options)
106
+ if options[:dry_run]
107
+ if args[0].to_s =~ /\A\d{1,}\Z/
108
+ print_dry_run @wiki_interface.dry.get(args[0])
109
+ else
110
+ print_dry_run @wiki_interface.dry.list({name: args[0].to_s})
111
+ end
112
+ return 0
113
+ end
114
+ page = find_wiki_page_by_name_or_id(args[0])
115
+ return 1 if page.nil?
116
+ json_response = {'page' => page}
117
+ render_result = render_with_format(json_response, options, 'page')
118
+ return 0 if render_result
119
+
120
+ unless options[:quiet]
121
+ print_h1 "Wiki Page Details"
122
+ print cyan
123
+
124
+ print_description_list({
125
+ "ID" => 'id',
126
+ "Name" => 'name',
127
+ "Category" => 'category',
128
+ "Ref Type" => 'refType',
129
+ "Ref ID" => 'refId',
130
+ #"Owner" => lambda {|it| it['account'] ? it['account']['name'] : '' },
131
+ "Created" => lambda {|it| format_local_dt(it['dateCreated']) },
132
+ "Created By" => lambda {|it| it['createdBy'] ? it['createdBy']['username'] : '' },
133
+ "Updated" => lambda {|it| format_local_dt(it['lastUpdated']) },
134
+ "Updated By" => lambda {|it| it['updatedBy'] ? it['updatedBy']['username'] : '' }
135
+ }, page)
136
+ print reset,"\n"
137
+
138
+ print_h2 "Page Content"
139
+ print cyan, page['content'], reset, "\n"
140
+
141
+ end
142
+ print reset,"\n"
143
+ if open_wiki_link
144
+ return view([page['id']])
145
+ end
146
+ return 0
147
+ rescue RestClient::Exception => e
148
+ print_rest_exception(e, options)
149
+ exit 1
150
+ end
151
+ end
152
+
153
+ def view(args)
154
+ options = {}
155
+ optparse = Morpheus::Cli::OptionParser.new do |opts|
156
+ opts.banner = subcommand_usage("[id]")
157
+ build_common_options(opts, options, [:dry_run, :remote])
158
+ opts.footer = "View a wiki page in a web browser" + "\n" +
159
+ "[id] is required. This is name or id of the wiki page."
160
+ end
161
+ optparse.parse!(args)
162
+ if args.count != 1
163
+ raise_command_error "wrong number of arguments, expected 1 and got (#{args.count}) #{args.join(' ')}\n#{optparse}"
164
+ end
165
+ connect(options)
166
+ begin
167
+ page = find_wiki_page_by_name_or_id(args[0])
168
+ return 1 if page.nil?
169
+
170
+ link = "#{@appliance_url}/login/oauth-redirect?access_token=#{@access_token}\\&redirectUri=/operations/wiki/#{page['urlName']}"
171
+
172
+ open_command = nil
173
+ if RbConfig::CONFIG['host_os'] =~ /mswin|mingw|cygwin/
174
+ open_command = "start #{link}"
175
+ elsif RbConfig::CONFIG['host_os'] =~ /darwin/
176
+ open_command = "open #{link}"
177
+ elsif RbConfig::CONFIG['host_os'] =~ /linux|bsd/
178
+ open_command = "xdg-open #{link}"
179
+ end
180
+
181
+ if options[:dry_run]
182
+ puts "system: #{open_command}"
183
+ return 0
184
+ end
185
+
186
+ system(open_command)
187
+
188
+ return 0
189
+ rescue RestClient::Exception => e
190
+ print_rest_exception(e, options)
191
+ exit 1
192
+ end
193
+ end
194
+
195
+ def add(args)
196
+ options = {}
197
+ optparse = Morpheus::Cli::OptionParser.new do |opts|
198
+ opts.banner = subcommand_usage("[name] [options]")
199
+ build_option_type_options(opts, options, add_wiki_page_option_types)
200
+ build_common_options(opts, options, [:payload, :options, :json, :dry_run, :remote])
201
+ end
202
+ optparse.parse!(args)
203
+ if args.count > 1
204
+ raise_command_error "wrong number of arguments, expected 0-1 and got (#{args.count}) #{args}\n#{optparse}"
205
+ end
206
+ if args[0]
207
+ options[:options] ||= {}
208
+ options[:options]['name'] ||= args[0]
209
+ end
210
+ connect(options)
211
+ begin
212
+ # construct payload
213
+ passed_options = options[:options] ? options[:options].reject {|k,v| k.is_a?(Symbol) } : {}
214
+ payload = nil
215
+ if options[:payload]
216
+ payload = options[:payload]
217
+ payload.deep_merge!({'page' => passed_options}) unless passed_options.empty?
218
+ else
219
+ payload = {
220
+ 'page' => {
221
+ }
222
+ }
223
+ # allow arbitrary -O options
224
+ payload.deep_merge!({'page' => passed_options}) unless passed_options.empty?
225
+ # prompt for options
226
+ params = Morpheus::Cli::OptionTypes.prompt(add_wiki_page_option_types, options[:options], @api_client, options[:params])
227
+ payload.deep_merge!({'page' => params}) unless params.empty?
228
+ end
229
+
230
+ @wiki_interface.setopts(options)
231
+ if options[:dry_run]
232
+ print_dry_run @wiki_interface.dry.create(payload)
233
+ return
234
+ end
235
+ json_response = @wiki_interface.create(payload)
236
+ if options[:json]
237
+ print JSON.pretty_generate(json_response)
238
+ print "\n"
239
+ else
240
+ display_name = json_response['page'] ? json_response['page']['name'] : ''
241
+ print_green_success "Wiki page #{display_name} added"
242
+ get([json_response['page']['id']])
243
+ end
244
+ return 0
245
+ rescue RestClient::Exception => e
246
+ print_rest_exception(e, options)
247
+ exit 1
248
+ end
249
+ end
250
+
251
+ def update(args)
252
+ options = {}
253
+ optparse = Morpheus::Cli::OptionParser.new do |opts|
254
+ opts.banner = subcommand_usage("[name] [options]")
255
+ build_option_type_options(opts, options, update_wiki_page_option_types)
256
+ build_common_options(opts, options, [:payload, :options, :json, :dry_run, :remote])
257
+ end
258
+ optparse.parse!(args)
259
+
260
+ if args.count != 1
261
+ raise_command_error "wrong number of arguments, expected 1 and got (#{args.count}) #{args}\n#{optparse}"
262
+ end
263
+
264
+ connect(options)
265
+ begin
266
+
267
+ page = find_wiki_page_by_name_or_id(args[0])
268
+ return 1 if page.nil?
269
+
270
+ # construct payload
271
+ passed_options = options[:options] ? options[:options].reject {|k,v| k.is_a?(Symbol) } : {}
272
+ payload = nil
273
+ if options[:payload]
274
+ payload = options[:payload]
275
+ payload.deep_merge!({'page' => passed_options}) unless passed_options.empty?
276
+ else
277
+ payload = {
278
+ 'page' => {
279
+ }
280
+ }
281
+ # allow arbitrary -O options
282
+ payload.deep_merge!({'page' => passed_options}) unless passed_options.empty?
283
+ # prompt for options
284
+ #params = Morpheus::Cli::OptionTypes.prompt(update_wiki_page_option_types, options[:options], @api_client, options[:params])
285
+ params = passed_options
286
+
287
+ if params.empty?
288
+ raise_command_error "Specify at least one option to update.\n#{optparse}"
289
+ end
290
+ if params["category"] && (params["category"].strip == "" || params["category"].strip == "null")
291
+ params["category"] = ""
292
+ end
293
+ payload.deep_merge!({'page' => params}) unless params.empty?
294
+ end
295
+ @wiki_interface.setopts(options)
296
+ if options[:dry_run]
297
+ print_dry_run @wiki_interface.dry.update(page['id'], payload)
298
+ return
299
+ end
300
+ json_response = @wiki_interface.update(page['id'], payload)
301
+ if options[:json]
302
+ print JSON.pretty_generate(json_response)
303
+ print "\n"
304
+ else
305
+ display_name = json_response['page'] ? json_response['page']['name'] : ''
306
+ print_green_success "Wiki page #{display_name} updated"
307
+ get([json_response['page']['id']])
308
+ end
309
+ return 0
310
+ rescue RestClient::Exception => e
311
+ print_rest_exception(e, options)
312
+ exit 1
313
+ end
314
+ end
315
+
316
+ def remove(args)
317
+ options = {}
318
+ optparse = Morpheus::Cli::OptionParser.new do |opts|
319
+ opts.banner = subcommand_usage("[name]")
320
+ build_common_options(opts, options, [:auto_confirm, :json, :dry_run, :remote])
321
+ end
322
+ optparse.parse!(args)
323
+
324
+ if args.count != 1
325
+ raise_command_error "wrong number of arguments, expected 1 and got (#{args.count}) #{args}\n#{optparse}"
326
+ end
327
+
328
+ connect(options)
329
+ begin
330
+ page = find_wiki_page_by_name_or_id(args[0])
331
+ return 1 if page.nil?
332
+
333
+ unless options[:yes] || Morpheus::Cli::OptionTypes.confirm("Are you sure you want to delete the page #{page['name']}?")
334
+ return 9, "aborted command"
335
+ end
336
+ @wiki_interface.setopts(options)
337
+ if options[:dry_run]
338
+ print_dry_run @wiki_interface.dry.destroy(page['id'])
339
+ return
340
+ end
341
+ json_response = @wiki_interface.destroy(page['id'])
342
+ if options[:json]
343
+ print JSON.pretty_generate(json_response)
344
+ print "\n"
345
+ else
346
+ print_green_success "Wiki page #{page['name']} removed"
347
+ # list([])
348
+ end
349
+ return 0
350
+ rescue RestClient::Exception => e
351
+ print_rest_exception(e, options)
352
+ exit 1
353
+ end
354
+ end
355
+
356
+ def categories(args)
357
+ options = {}
358
+ params = {}
359
+ optparse = Morpheus::Cli::OptionParser.new do |opts|
360
+ opts.banner = subcommand_usage()
361
+ build_common_options(opts, options, [:list, :query, :json, :yaml, :csv, :fields, :dry_run, :remote])
362
+ end
363
+ optparse.parse!(args)
364
+ if args.count != 0
365
+ raise_command_error "wrong number of arguments, expected 0 and got (#{args.count}) #{args}\n#{optparse}"
366
+ end
367
+ connect(options)
368
+ begin
369
+ params.merge!(parse_list_options(options))
370
+ @wiki_interface.setopts(options)
371
+ if options[:dry_run]
372
+ print_dry_run @wiki_interface.dry.categories(params)
373
+ return 0
374
+ end
375
+ json_response = @wiki_interface.categories(params)
376
+ render_result = render_with_format(json_response, options, 'categories')
377
+ return 0 if render_result
378
+ categories = json_response['categories']
379
+ unless options[:quiet]
380
+ title = "Morpheus Wiki Categories"
381
+ subtitles = []
382
+ subtitles += parse_list_subtitles(options)
383
+ print_h1 title, subtitles
384
+ if categories.empty?
385
+ print yellow,"No wiki categories found.",reset,"\n"
386
+ else
387
+ columns = [
388
+ {"CATEGORY" => lambda {|page| page['name'] } },
389
+ {"# PAGES" => lambda {|it| it['pageCount'] } }
390
+ ]
391
+ if options[:include_fields]
392
+ columns = options[:include_fields]
393
+ end
394
+ print as_pretty_table(categories, columns, options)
395
+ #print_results_pagination(json_response)
396
+ end
397
+ print reset,"\n"
398
+ end
399
+ return 0
400
+ rescue RestClient::Exception => e
401
+ print_rest_exception(e, options)
402
+ exit 1
403
+ end
404
+ end
405
+
406
+ private
407
+ def find_wiki_page_by_name_or_id(val)
408
+ if val.to_s =~ /\A\d{1,}\Z/
409
+ return find_wiki_page_by_id(val)
410
+ else
411
+ return find_wiki_page_by_name(val)
412
+ end
413
+ end
414
+
415
+ def find_wiki_page_by_id(id)
416
+ raise "#{self.class} has not defined @wiki_interface" if @wiki_interface.nil?
417
+ begin
418
+ json_response = @wiki_interface.get(id)
419
+ return json_response['page']
420
+ rescue RestClient::Exception => e
421
+ if e.response && e.response.code == 404
422
+ print_red_alert "Wiki page not found by id #{id}"
423
+ else
424
+ raise e
425
+ end
426
+ end
427
+ end
428
+
429
+ def find_wiki_page_by_name(name)
430
+ raise "#{self.class} has not defined @wiki_interface" if @wiki_interface.nil?
431
+ pages = @wiki_interface.list({name: name.to_s})['pages']
432
+ if pages.empty?
433
+ print_red_alert "Wiki page not found by name #{name}"
434
+ return nil
435
+ elsif pages.size > 1
436
+ print_red_alert "#{pages.size} wiki pages found by name #{name}"
437
+ print as_pretty_table(pages, [:id,:name], {color:red})
438
+ print reset,"\n"
439
+ return nil
440
+ else
441
+ return pages[0]
442
+ end
443
+ end
444
+
445
+ def add_wiki_page_option_types
446
+ [
447
+ {'fieldName' => 'name', 'fieldLabel' => 'Name', 'type' => 'text', 'required' => true, 'displayOrder' => 1},
448
+ {'fieldName' => 'category', 'fieldLabel' => 'Category', 'type' => 'text', 'required' => false, 'displayOrder' => 2},
449
+ {'fieldName' => 'content', 'fieldLabel' => 'Content', 'type' => 'textarea', 'required' => true, 'displayOrder' => 3}
450
+ ]
451
+ end
452
+
453
+ def update_wiki_page_option_types
454
+ [
455
+ {'fieldName' => 'name', 'fieldLabel' => 'Name', 'type' => 'text', 'required' => false, 'displayOrder' => 1},
456
+ {'fieldName' => 'category', 'fieldLabel' => 'Category', 'type' => 'text', 'required' => false, 'displayOrder' => 2},
457
+ {'fieldName' => 'content', 'fieldLabel' => 'Content', 'type' => 'textarea', 'required' => false, 'displayOrder' => 3}
458
+ ]
459
+ end
460
+
461
+ end