morpheus-cli 3.6.31 → 3.6.32

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.
@@ -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