morpheus-cli 2.10.1 → 2.10.2

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.
@@ -151,13 +151,23 @@ class Morpheus::Cli::AppTemplates
151
151
  # options[:options] ||= {}
152
152
  # options[:options]['group'] = group
153
153
  # end
154
+ build_option_type_options(opts, options, add_app_template_option_types(false))
155
+ opts.on( '-g', '--group GROUP', "Group Name or ID" ) do |val|
156
+ options[:options] ||= {}
157
+ options[:options]['group']
158
+ # options[:group] = val
159
+ end
154
160
  build_common_options(opts, options, [:options, :json, :dry_run])
155
161
  end
156
162
  optparse.parse!(args)
157
163
  connect(options)
158
164
  begin
159
-
165
+ options[:options] ||= {}
166
+ # use active group by default
167
+ options[:options]['group'] ||= @active_group_id
168
+
160
169
  params = Morpheus::Cli::OptionTypes.prompt(add_app_template_option_types, options[:options], @api_client, options[:params])
170
+ group = find_group_by_name_or_id_for_provisioning(params.delete('group'))
161
171
 
162
172
  #puts "parsed params is : #{params.inspect}"
163
173
  app_template_keys = ['name']
@@ -202,6 +212,7 @@ class Morpheus::Cli::AppTemplates
202
212
  options = {}
203
213
  optparse = OptionParser.new do|opts|
204
214
  opts.banner = subcommand_usage("[name] [options]")
215
+ build_option_type_options(opts, options, update_app_template_option_types(false))
205
216
  build_common_options(opts, options, [:options, :json, :dry_run])
206
217
  end
207
218
  optparse.parse!(args)
@@ -222,9 +233,8 @@ class Morpheus::Cli::AppTemplates
222
233
  params = options[:options] || {}
223
234
 
224
235
  if params.empty?
236
+ print_red_alert "Specify atleast one option to update"
225
237
  puts optparse
226
- option_lines = update_app_template_option_types.collect {|it| "\t-O #{it['fieldName']}=\"value\"" }.join("\n")
227
- puts "\nAvailable Options:\n#{option_lines}\n\n"
228
238
  exit 1
229
239
  end
230
240
 
@@ -694,6 +704,7 @@ class Morpheus::Cli::AppTemplates
694
704
  def available_tiers(args)
695
705
  options = {}
696
706
  optparse = OptionParser.new do|opts|
707
+ opts.banner = subcommand_usage()
697
708
  build_common_options(opts, options, [:json, :dry_run])
698
709
  end
699
710
  optparse.parse!(args)
@@ -737,6 +748,7 @@ class Morpheus::Cli::AppTemplates
737
748
  def available_types(args)
738
749
  options = {}
739
750
  optparse = OptionParser.new do|opts|
751
+ opts.banner = subcommand_usage()
740
752
  build_common_options(opts, options, [:json])
741
753
  end
742
754
  optparse.parse!(args)
@@ -781,15 +793,18 @@ class Morpheus::Cli::AppTemplates
781
793
  private
782
794
 
783
795
 
784
- def add_app_template_option_types
796
+ def add_app_template_option_types(connected=true)
785
797
  [
786
798
  {'fieldName' => 'name', 'fieldLabel' => 'Name', 'type' => 'text', 'required' => true, 'displayOrder' => 1},
787
- {'fieldName' => 'group', 'fieldLabel' => 'Group', 'type' => 'text', 'required' => true, 'displayOrder' => 2},
799
+ {'fieldName' => 'group', 'fieldLabel' => 'Group', 'type' => 'select', 'selectOptions' => (connected ? get_available_groups() : []), 'required' => true}
788
800
  ]
789
801
  end
790
802
 
791
- def update_app_template_option_types
792
- add_app_template_option_types
803
+ def update_app_template_option_types(connected=true)
804
+ list = add_app_template_option_types(connected)
805
+ list = list.reject {|it| ["group"].include? it['fieldName'] }
806
+ list.each {|it| it['required'] = false }
807
+ list
793
808
  end
794
809
 
795
810
  def find_app_template_by_name_or_id(val)
@@ -77,6 +77,8 @@ class Morpheus::Cli::Apps
77
77
  options = {}
78
78
  optparse = OptionParser.new do|opts|
79
79
  opts.banner = subcommand_usage("[name]")
80
+
81
+ build_option_type_options(opts, options, add_app_option_types(false))
80
82
  opts.on( '-g', '--group GROUP', "Group Name or ID" ) do |val|
81
83
  options[:group] = val
82
84
  end
@@ -85,27 +87,21 @@ class Morpheus::Cli::Apps
85
87
  optparse.parse!(args)
86
88
  connect(options)
87
89
  begin
88
- # use active group by default
89
- options[:group] ||= @active_group_id
90
- group = options[:group] ? find_group_by_name_or_id_for_provisioning(options[:group]) : nil
90
+ options[:options] ||= {}
91
+ # use the -g GROUP or active group by default
92
+ options[:options]['group'] ||= options[:group] || @active_group_id
93
+ # support [name] as first argument still
94
+ if args[0]
95
+ options[:options]['name'] = args[0]
96
+ end
91
97
 
92
98
  payload = {
93
99
  'app' => {}
94
100
  }
95
- if args[0]
96
- payload['app']['name'] = args[0]
97
- else
98
- v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'name', 'fieldLabel' => 'Name', 'type' => 'text', 'required' => true, 'description' => 'Enter a name for this app'}], options[:options])
99
- payload['app']['name'] = v_prompt['name']
100
- end
101
- v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'description', 'fieldLabel' => 'Description', 'type' => 'text', 'required' => false}], options[:options])
102
- payload['app']['description'] = v_prompt['description']
103
- if group
104
- payload['app']['site'] = {id: group["id"]}
105
- else
106
- v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'group', 'fieldLabel' => 'Group', 'type' => 'select', 'selectOptions' => get_available_groups(), 'required' => true}], options[:options])
107
- payload['app']['site'] = {id: v_prompt["group"]}
108
- end
101
+ params = Morpheus::Cli::OptionTypes.prompt(add_app_option_types, options[:options], @api_client, options[:params])
102
+ group = find_group_by_name_or_id_for_provisioning(params.delete('group'))
103
+ payload['app'].merge!(params)
104
+ payload['app']['group'] = {id: group['id']}
109
105
 
110
106
  # todo: allow adding instances with creation..
111
107
 
@@ -217,6 +213,7 @@ class Morpheus::Cli::Apps
217
213
  options = {}
218
214
  optparse = OptionParser.new do|opts|
219
215
  opts.banner = subcommand_usage("[name]")
216
+ build_option_type_options(opts, options, update_app_option_types(false))
220
217
  build_common_options(opts, options, [:options, :json, :dry_run])
221
218
  end
222
219
  optparse.parse!(args)
@@ -233,17 +230,11 @@ class Morpheus::Cli::Apps
233
230
  'app' => {id: app["id"]}
234
231
  }
235
232
 
236
- update_app_option_types = [
237
- {'fieldName' => 'name', 'fieldLabel' => 'Name', 'type' => 'text', 'required' => true, 'description' => 'Enter a name for this app'},
238
- {'fieldName' => 'description', 'fieldLabel' => 'Description', 'type' => 'text', 'required' => false}
239
- ]
240
-
241
233
  params = options[:options] || {}
242
234
 
243
235
  if params.empty?
244
- puts opts
245
- option_lines = update_app_option_types.collect {|it| "\t-O #{it['fieldName']}=\"value\"" }.join("\n")
246
- puts "\nAvailable Options:\n#{option_lines}\n\n"
236
+ print_red_alert "Specify atleast one option to update"
237
+ puts optparse
247
238
  exit 1
248
239
  end
249
240
 
@@ -341,7 +332,7 @@ class Morpheus::Cli::Apps
341
332
  options = {}
342
333
  optparse = OptionParser.new do|opts|
343
334
  opts.banner = subcommand_usage("[name]")
344
- build_common_options(opts, options, [:json, :dry_run, :quiet])
335
+ build_common_options(opts, options, [:json, :dry_run, :quiet, :auto_confirm])
345
336
  end
346
337
  optparse.parse!(args)
347
338
  if args.count < 1
@@ -701,6 +692,21 @@ class Morpheus::Cli::Apps
701
692
 
702
693
  private
703
694
 
695
+ def add_app_option_types(connected=true)
696
+ [
697
+ {'fieldName' => 'name', 'fieldLabel' => 'Name', 'type' => 'text', 'required' => true, 'description' => 'Enter a name for this app'},
698
+ {'fieldName' => 'description', 'fieldLabel' => 'Description', 'type' => 'text', 'required' => false},
699
+ {'fieldName' => 'group', 'fieldLabel' => 'Group', 'type' => 'select', 'selectOptions' => (connected ? get_available_groups() : []), 'required' => true},
700
+ ]
701
+ end
702
+
703
+ def update_app_option_types(connected=true)
704
+ list = add_app_option_types(connected)
705
+ list = list.reject {|it| ["group"].include? it['fieldName'] }
706
+ list.each {|it| it['required'] = false }
707
+ list
708
+ end
709
+
704
710
  def find_app_by_id(id)
705
711
  app_results = @apps_interface.get(id.to_i)
706
712
  if app_results['app'].empty?
@@ -16,7 +16,90 @@ module Morpheus
16
16
  Morpheus::Cli::CliRegistry.add(klass, klass.command_name)
17
17
  end
18
18
 
19
+ # the beginning of instance variables from optparse !
20
+
21
+ # this setting makes it easy for the called to disable prompting
22
+ attr_reader :no_prompt
23
+
24
+ # disabled prompting for this command
25
+ def noninteractive()
26
+ @no_prompt = true
27
+ self
28
+ end
29
+
30
+ # whether to prompt or not, this is true by default.
31
+ def interactive?
32
+ @no_prompt != true
33
+ end
34
+
35
+ # Appends Array of OptionType definitions to an OptionParser instance
36
+ # This adds an option like --fieldContext.fieldName="VALUE"
37
+ # @param opts [OptionParser]
38
+ # @param options [Hash] output map that is being constructed
39
+ # @param option_types [Array] list of OptionType definitions to add
40
+ # @return void, this modifies the opts in place.
41
+ def build_option_type_options(opts, options, option_types=[])
42
+ #opts.separator ""
43
+ #opts.separator "Options:"
44
+ options[:options] ||= {} # this is where these go..for now
45
+ custom_options = options[:options]
46
+
47
+ # add each one to the OptionParser
48
+ option_types.each do |option_type|
49
+ field_namespace = []
50
+ field_name = option_type['fieldName'].to_s
51
+ if field_name.empty?
52
+ puts "Missing fieldName for option type: #{option_type}" if Morpheus::Logging.debug?
53
+ next
54
+ end
55
+
56
+ if !option_type['fieldContext'].to_s.empty?
57
+ option_type['fieldContext'].split(".").each do |ns|
58
+ field_namespace << ns
59
+ end
60
+ end
61
+
62
+ full_field_name = field_name
63
+ if !field_namespace.empty?
64
+ full_field_name = "#{field_namespace.join('.')}.#{field_name}"
65
+ end
66
+
67
+ description = "#{option_type['fieldLabel']}#{option_type['fieldAddOn'] ? ('(' + option_type['fieldAddOn'] + ') ') : '' }#{!option_type['required'] ? ' (optional)' : ''}#{option_type['defaultValue'] ? ' Default: '+option_type['defaultValue'].to_s : ''}"
68
+ # description = option_type['description'].to_s
69
+ # if option_type['defaultValue']
70
+ # description = "#{description} Default: #{option_type['defaultValue']}"
71
+ # end
72
+ # if option_type['required'] == true
73
+ # description = "(Required) #{description}"
74
+ # end
75
+
76
+ opts.on("--#{full_field_name} VALUE", String, description) do |val|
77
+ cur_namespace = custom_options
78
+ field_namespace.each do |ns|
79
+ next if ns.empty?
80
+ cur_namespace[ns.to_s] ||= {}
81
+ cur_namespace = cur_namespace[ns.to_s]
82
+ end
83
+ cur_namespace[field_name] = val
84
+ end
85
+
86
+ # todo: all the various types
87
+ # number
88
+ # checkbox [on|off]
89
+ # select for optionSource and selectOptions
90
+
91
+ end
92
+ opts
93
+ end
94
+
95
+ # appends to the passed OptionParser all the generic options
96
+ # @param opts [OptionParser] the option parser object being constructed
97
+ # @param options [Hash] the output Hash that is to being modified
98
+ # @param includes [Array] which options to include eg. :options, :json, :remote
99
+ # @return opts
19
100
  def build_common_options(opts, options, includes=[])
101
+ #opts.separator ""
102
+ opts.separator "Common options:"
20
103
  includes = includes.clone
21
104
  while (option_key = includes.shift) do
22
105
  case option_key.to_sym
@@ -32,7 +115,9 @@ module Morpheus
32
115
  when :options
33
116
  options[:options] ||= {}
34
117
  opts.on( '-O', '--option OPTION', "Option in the format var=\"value\"" ) do |option|
35
- custom_option_args = option.split('=')
118
+ # todo: look ahead and parse ALL the option=value args after -O switch
119
+ #custom_option_args = option.split('=')
120
+ custom_option_args = option.sub(/\s?\=\s?/, '__OPTION_DELIM__').split('__OPTION_DELIM__')
36
121
  custom_options = options[:options]
37
122
  option_name_args = custom_option_args[0].split('.')
38
123
  if option_name_args.count > 1
@@ -114,21 +199,24 @@ module Morpheus
114
199
  opts.on( '-T', '--token ACCESS_TOKEN', "Access Token" ) do |remote|
115
200
  options[:remote_token] = remote
116
201
  end
117
- when :auto_confirm
202
+
203
+ when :auto_confirm
118
204
  opts.on( '-y', '--yes', "Auto Confirm" ) do
119
205
  options[:yes] = true
120
206
  end
121
- when :json
122
- opts.on('-j','--json', "JSON Output") do |json|
207
+
208
+ when :json
209
+ opts.on('-j','--json', "JSON Output") do
123
210
  options[:json] = true
124
211
  end
125
212
 
126
213
  when :dry_run
127
- opts.on('-d','--dry-run', "Dry Run, print the API request instead of executing it") do |json|
214
+ opts.on('-d','--dry-run', "Dry Run, print the API request instead of executing it") do
128
215
  options[:dry_run] = true
129
216
  end
130
- when :quiet
131
- opts.on('-q','--quiet', "No Output, when successful") do |json|
217
+
218
+ when :quiet
219
+ opts.on('-q','--quiet', "No Output, when successful") do
132
220
  options[:quiet] = true
133
221
  end
134
222
 
@@ -144,9 +232,10 @@ module Morpheus
144
232
  Term::ANSIColor::coloring = false
145
233
  end
146
234
 
147
- opts.on('-V','--debug', "Print extra output for debugging. ") do |json|
235
+ opts.on('-V','--debug', "Print extra output for debugging. ") do
148
236
  options[:debug] = true
149
237
  Morpheus::Logging.set_log_level(Morpheus::Logging::Logger::DEBUG)
238
+ ::RestClient.log = Morpheus::Logging.debug? ? STDOUT : nil
150
239
  # perhaps...
151
240
  # create a new logger instance just for this command instance
152
241
  # this way we don't elevate the global level for subsequent commands in a shell
@@ -160,7 +249,7 @@ module Morpheus
160
249
  puts opts
161
250
  exit
162
251
  end
163
-
252
+ opts
164
253
  end
165
254
 
166
255
  def command_name
@@ -215,17 +304,21 @@ module Morpheus
215
304
  raise "#{self.class} has no available subcommands"
216
305
  end
217
306
  # meh, could deprecate and make subcommand define handle() itself
218
- if args.count == 0 && default_subcommand
219
- # p "using default subcommand #{default_subcommand}"
220
- return self.send(default_subcommand, args || [])
307
+ # if args.count == 0 && default_subcommand
308
+ # # p "using default subcommand #{default_subcommand}"
309
+ # return self.send(default_subcommand, args || [])
310
+ # end
311
+ subcommand_name = args[0]
312
+ if args[0] == "-h" || args[0] == "--help" || args[0] == "help"
313
+ print_usage
314
+ exit
221
315
  end
222
- cmd_name = args[0]
223
- if subcommand_aliases[cmd_name]
224
- cmd_name = subcommand_aliases[cmd_name]
316
+ if subcommand_aliases[subcommand_name]
317
+ subcommand_name = subcommand_aliases[subcommand_name]
225
318
  end
226
- cmd_method = subcommands[cmd_name]
227
- if cmd_name && !cmd_method
228
- #puts "unknown command '#{cmd_name}'"
319
+ cmd_method = subcommands[subcommand_name]
320
+ if subcommand_name && !cmd_method
321
+ puts "unknown command '#{self.command_name} #{subcommand_name}'"
229
322
  end
230
323
  if !cmd_method
231
324
  print_usage
@@ -240,7 +333,8 @@ module Morpheus
240
333
 
241
334
  # This supports the simple remote option eg. `instances add --remote "qa"`
242
335
  # It will establish a connection to the pre-configured appliance named "qa"
243
- # The calling command needs to populate @appliances and/or @appliance_name
336
+ # The calling command can populate @appliances and/or @appliance_name
337
+ # Otherwise, the current active appliance is used...
244
338
  # This returns a new instance of Morpheus::APIClient (and sets @access_token, and @appliance)
245
339
  # Your command should be ready to make api requests after this.
246
340
  # todo: probably don't exit here, just return nil or raise
@@ -284,18 +378,32 @@ module Morpheus
284
378
 
285
379
  # ok, get some credentials.
286
380
  # this prompts for username, password without options[:no_prompt]
287
- @access_token = Morpheus::Cli::Credentials.new(@appliance_name, @appliance_url).request_credentials(options)
288
-
289
- # bail if we got nothing
381
+ # used saved credentials please
382
+ @api_credentials = Morpheus::Cli::Credentials.new(@appliance_name, @appliance_url)
383
+ @access_token = @api_credentials.load_saved_credentials()
384
+ if @access_token.to_s.empty?
385
+ unless options[:no_prompt]
386
+ @access_token = @api_credentials.request_credentials(options)
387
+ end
388
+ end
389
+
390
+ # bail if we got nothing still
391
+ unless options[:skip_verify_access_token]
392
+ verify_access_token!
393
+ end
394
+
395
+ # ok, connect to the appliance.. actually this just instantiates an ApiClient
396
+ api_client = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url)
397
+ @api_client = api_client # meh, just return w/o setting instance attrs
398
+ return api_client
399
+ end
400
+
401
+ def verify_access_token!
290
402
  if @access_token.empty?
291
403
  print_red_alert "Invalid Credentials. Unable to acquire access token. Please verify your credentials and try again."
292
404
  exit 1
293
405
  end
294
-
295
- # ok, connect to the appliance.. actually this just instantiates an ApiClient
296
- # setup our api client for all including commands to use.
297
- @api_client = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url)
298
- return @api_client
406
+ true
299
407
  end
300
408
 
301
409
  module ClassMethods
@@ -229,6 +229,10 @@ class Morpheus::Cli::Clouds
229
229
 
230
230
  all_option_types = add_cloud_option_types(cloud_type)
231
231
  params = Morpheus::Cli::OptionTypes.prompt(all_option_types, options[:options], @api_client, {zoneTypeId: cloud_type['id']})
232
+ # some optionTypes have fieldContext='zone', so move those to the root level of the zone payload
233
+ if params['zone'].is_a?(Hash)
234
+ cloud_payload.merge!(params.delete('zone'))
235
+ end
232
236
  cloud_payload.merge!(params)
233
237
  payload = {zone: cloud_payload}
234
238
  if options[:dry_run]
@@ -284,6 +288,10 @@ class Morpheus::Cli::Clouds
284
288
  print_available_options(all_option_types)
285
289
  exit 1
286
290
  end
291
+ # some optionTypes have fieldContext='zone', so move those to the root level of the zone payload
292
+ if params['zone'].is_a?(Hash)
293
+ cloud_payload.merge!(params.delete('zone'))
294
+ end
287
295
  cloud_payload.merge!(params)
288
296
  payload = {zone: cloud_payload}
289
297
 
@@ -493,9 +501,6 @@ class Morpheus::Cli::Clouds
493
501
  params = {}
494
502
  optparse = OptionParser.new do|opts|
495
503
  opts.banner = subcommand_usage()
496
- opts.on( '-g', '--group GROUP', "Group Name" ) do |group|
497
- options[:group] = group
498
- end
499
504
  build_common_options(opts, options, [:json, :dry_run, :remote])
500
505
  end
501
506
  optparse.parse!(args)
@@ -0,0 +1,39 @@
1
+ require 'optparse'
2
+ require 'morpheus/cli/cli_command'
3
+ require 'json'
4
+
5
+ # This is for use in dotfile scripts
6
+ # It allows you to turn colors on or off globally
7
+ class Morpheus::Cli::ColoringCommand
8
+ include Morpheus::Cli::CliCommand
9
+ set_command_name :coloring
10
+ set_command_hidden
11
+
12
+ def handle(args)
13
+ append_newline = true
14
+ options = {}
15
+ optparse = Morpheus::Cli::OptionParser.new do|opts|
16
+ opts.banner = "Usage: morpheus #{command_name} [on|off]"
17
+ #build_common_options(opts, options, [])
18
+ opts.on('-h', '--help', "Prints this help" ) do
19
+ puts opts
20
+ exit
21
+ end
22
+ opts.footer = "Enable [on] or Disable [off] ANSI Colors for all output."
23
+ end
24
+ optparse.parse!(args)
25
+ if args.count != 1
26
+ puts optparse
27
+ exit 1
28
+ end
29
+ is_on = ["on","true", "1"].include?(args[0].to_s.strip.downcase)
30
+ is_off = ["off","false", "0"].include?(args[0].to_s.strip.downcase)
31
+ if !is_on && !is_off
32
+ puts optparse
33
+ exit 1
34
+ end
35
+ Term::ANSIColor::coloring = is_on
36
+ return true
37
+ end
38
+
39
+ end