morpheus-cli 2.11.1 → 2.11.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 7a9c598b82ebbf8eea995f58a454bf8a52defef0
4
- data.tar.gz: 6a81fff1ddc710ca3d56488670586caf7844ab93
3
+ metadata.gz: 6d561294737f605bb14714d84f21984797f012b2
4
+ data.tar.gz: 857aa6f016e8f4db4cfaea280703a7f71adac83a
5
5
  SHA512:
6
- metadata.gz: 5821cf3be29b11830eab7cf6e87f15ebb3f0e783d3d49664c5dbd6b824e775e6546b2da09a52983edf1dfd60058c51f40c9ae3cd591ea61fb5fb730b2766da6a
7
- data.tar.gz: 356f77e67812b6f8b63e85f3c1a95c0206e5a5f456c912a65aae311f0040ad1eea4fae2d77d840a85be1a03bbc342db0b1097dfa07eb623ef1bb71e699b21786
6
+ metadata.gz: 941e2fd2a2478c7af97e604f3bbea977874a585b5a4dcd0d526bce39434b4461b9859556f509054239b0fd957919f36b5606304e314f2befda86667d888aec15
7
+ data.tar.gz: 1fe0c7f8d07df32dd4ea2b771ef2b21106831115d3d3c0a51358e8b9c640be215a3057b12f8f3608524fb46aee02b8f6fa5eef2f60599b6653e1553df6e3cb16
@@ -3,13 +3,14 @@ require 'uri'
3
3
  require 'rest-client'
4
4
 
5
5
  class Morpheus::APIClient
6
- def initialize(access_token, refresh_token=nil,expires_in = nil, base_url=nil)
6
+ def initialize(access_token, refresh_token=nil,expires_in = nil, base_url=nil, verify_ssl=true)
7
7
  @access_token = access_token
8
8
  @refresh_token = refresh_token
9
9
  @base_url = base_url
10
10
  if expires_in != nil
11
11
  @expires_at = DateTime.now + expires_in.seconds
12
12
  end
13
+ set_ssl_verification_enabled(verify_ssl)
13
14
  end
14
15
 
15
16
  def dry_run(val=true)
@@ -21,7 +22,23 @@ class Morpheus::APIClient
21
22
  dry_run(true)
22
23
  end
23
24
 
25
+ def ssl_verification_enabled?
26
+ @verify_ssl
27
+ end
28
+
29
+ def set_ssl_verification_enabled(val)
30
+ @verify_ssl = !!val
31
+ end
32
+
24
33
  def execute(opts, parse_json=true)
34
+ # @verify_ssl is not used atm
35
+ # todo: finish this and use it instead of the global variable RestClient.ssl_verification_enabled?
36
+ # gotta clean up all APIClient subclasses new() methods to support this
37
+ # the CliCommand subclasses should be changed to @users_interface = @api_client.users
38
+ # also.. Credentials.new()
39
+ if @verify_ssl == false
40
+ opts[:verify_ssl] = OpenSSL::SSL::VERIFY_NONE
41
+ end
25
42
  if @dry_run
26
43
  # JD: could return a Request object instead...
27
44
  return opts
@@ -20,7 +20,7 @@ class Morpheus::DashboardInterface < Morpheus::APIClient
20
20
  end
21
21
 
22
22
  def recent_activity(account_id=nil, options={})
23
- url = "#{@base_url}/api/dashboard/recentActivity"
23
+ url = "#{@base_url}/api/dashboard/recent-activity"
24
24
  headers = { params: {}, authorization: "Bearer #{@access_token}" }
25
25
  headers[:params].merge!(options)
26
26
  headers[:params]['accountId'] = account_id if account_id
@@ -547,6 +547,20 @@ module Morpheus
547
547
  @appliance_name = appliance[:name]
548
548
  @appliance_url = appliance[:host] || appliance[:url] # it's :host in the YAML..heh
549
549
 
550
+ # instead of toggling this global value
551
+ # this should just be an attribute of the api client
552
+ # for now, this fixes the issue where passing --insecure or --remote
553
+ # would then apply to all subsequent commands...
554
+ if options[:insecure]
555
+ Morpheus::RestClient.enable_ssl_verification = false
556
+ else
557
+ if appliance[:insecure] && Morpheus::RestClient.ssl_verification_enabled?
558
+ Morpheus::RestClient.enable_ssl_verification = false
559
+ elsif !appliance[:insecure] && !Morpheus::RestClient.ssl_verification_enabled?
560
+ Morpheus::RestClient.enable_ssl_verification = true
561
+ end
562
+ end
563
+
550
564
  # todo: support old way of accepting --username and --password on the command line
551
565
  # it's probably better not to do that tho, just so it stays out of history files
552
566
 
@@ -277,7 +277,7 @@ class Morpheus::Cli::Groups
277
277
  print JSON.pretty_generate(json_response)
278
278
  print "\n"
279
279
  else
280
- print_green_success "Added cloud #{cloud["id"]} to group #{group['name']}"
280
+ print_green_success "Added cloud #{cloud["name"]} to group #{group['name']}"
281
281
  #list([])
282
282
  get([group["id"]])
283
283
  end
@@ -93,13 +93,18 @@ class Morpheus::Cli::InstanceTypes
93
93
 
94
94
  if options[:json]
95
95
  print JSON.pretty_generate(json_response), "\n"
96
- return
96
+ return 0
97
97
  end
98
98
 
99
99
  instance_types = json_response['instanceTypes']
100
- print_h1 "Morpheus Instance Types"
100
+ title = "Morpheus Instance Types"
101
+ subtitles = []
102
+ if params[:phrase]
103
+ subtitles << "Search: #{params[:phrase]}".strip
104
+ end
105
+ print_h1 title, subtitles
101
106
  if instance_types.empty?
102
- puts yellow,"No instance types currently configured.",reset
107
+ print yellow,"No instance types found.",reset,"\n"
103
108
  else
104
109
  instance_types.each do |instance_type|
105
110
  versions = instance_type['versions'].join(', ')
@@ -113,12 +118,12 @@ class Morpheus::Cli::InstanceTypes
113
118
  # end
114
119
  #print JSON.pretty_generate(instance_type['instanceTypeLayouts'].first), "\n"
115
120
  end
116
-
117
121
  end
118
122
  print reset,"\n"
123
+ return 0
119
124
  rescue RestClient::Exception => e
120
125
  print_rest_exception(e, options)
121
- exit 1
126
+ return 1
122
127
  end
123
128
  end
124
129
  end
@@ -171,7 +171,8 @@ class Morpheus::Cli::Instances
171
171
  def add(args)
172
172
  options = {}
173
173
  optparse = OptionParser.new do|opts|
174
- opts.banner = subcommand_usage("[type] [name]")
174
+ # opts.banner = subcommand_usage("[type] [name]")
175
+ opts.banner = subcommand_usage("[name] -c CLOUD -t TYPE")
175
176
  opts.on( '-g', '--group GROUP', "Group Name or ID" ) do |val|
176
177
  options[:group] = val
177
178
  end
@@ -187,32 +188,73 @@ class Morpheus::Cli::Instances
187
188
  opts.on("--layout-size NUMBER", Integer, "Apply a multiply factor of containers/vms within the instance") do |val|
188
189
  options[:layout_size] = val.to_i
189
190
  end
191
+ opts.on("--workflow ID", String, "Automation: Workflow ID") do |val|
192
+ options[:workflow_id] = val.to_i
193
+ end
194
+ # opts.on('-L', "--lb", "Enable Load Balancer") do
195
+ # options[:enable_load_balancer] = true
196
+ # end
197
+ opts.on("--shutdown-days NUMBER", Integer, "Automation: Shutdown Days") do |val|
198
+ options[:expire_days] = val.to_i
199
+ end
200
+ opts.on("--expire-days NUMBER", Integer, "Automation: Expiration Days") do |val|
201
+ options[:expire_days] = val.to_i
202
+ end
203
+ opts.on("--create-backup on|off", String, "Automation: Create Backups. Default is off") do |val|
204
+ options[:create_backup] = ['on','true','1'].include?(val.to_s.downcase) ? 'on' : 'off'
205
+ end
190
206
  build_common_options(opts, options, [:options, :json, :dry_run, :remote])
191
207
  end
192
208
 
193
209
  optparse.parse!(args)
194
210
  connect(options)
195
211
 
196
- # support old format of `instance add TYPE NAME`
212
+ # this is the old format of `instance add TYPE NAME`
213
+ # JD: it seems confusing, let's deprecate and go with `instances add [NAME] -t TYPE`
197
214
  if args[0]
198
215
  options[:instance_type_code] = args[0]
199
216
  end
200
217
  if args[1]
201
218
  options[:instance_name] = args[1]
202
219
  end
220
+
221
+ # if args.count > 1
222
+ # print_error Morpheus::Terminal.angry_prompt
223
+ # puts_error "#{command_name} add has just 1 (optional) argument: NAME. Got #{args.count} arguments: #{args.join(', ')}\n#{optparse}"
224
+ # return 1
225
+ # end
226
+ # if args[0]
227
+ # options[:instance_name] = args[0]
228
+ # end
229
+
203
230
  # use active group by default
204
231
  options[:group] ||= @active_group_id
205
232
 
206
233
  options[:name_required] = true
207
234
  begin
208
-
235
+ # this provisioning helper method handles all (most) of the parsing and prompting
236
+ # and it relies on the method to exit non-zero on error, like a bad CLOUD or TYPE value
209
237
  payload = prompt_new_instance(options)
238
+
239
+ # other stuff
210
240
  payload[:copies] = options[:copies] if options[:copies] && options[:copies] > 0
211
241
  payload[:layoutSize] = options[:layout_size] if options[:layout_size] && options[:layout_size] > 0 # aka Scale Factor
242
+ payload[:createBackup] = options[:create_backup] ? 'on' : 'off' if options[:create_backup] == true
243
+ payload['instance']['expireDays'] = options[:expire_days] if options[:expire_days]
244
+ payload['instance']['shutdownDays'] = options[:shutdown_days] if options[:shutdown_days]
245
+ if options[:workflow_id]
246
+ payload['taskSetId'] = options[:workflow_id]
247
+ end
248
+ if options[:enable_load_balancer]
249
+ lb_payload = prompt_instance_load_balancer(payload['instance'], nil, options)
250
+ payload.deep_merge!(lb_payload)
251
+ end
252
+
212
253
  if options[:dry_run]
213
254
  print_dry_run @instances_interface.dry.create(payload)
214
- return
255
+ return 0
215
256
  end
257
+
216
258
  json_response = @instances_interface.create(payload)
217
259
  if options[:json]
218
260
  puts as_json(json_response, options)
@@ -221,9 +263,10 @@ class Morpheus::Cli::Instances
221
263
  print_green_success "Provisioning instance #{instance_name}"
222
264
  #list([])
223
265
  end
266
+ return 0
224
267
  rescue RestClient::Exception => e
225
268
  print_rest_exception(e, options)
226
- exit 1
269
+ return 1
227
270
  end
228
271
  end
229
272
 
@@ -598,6 +641,20 @@ class Morpheus::Cli::Instances
598
641
  }
599
642
  print_description_list(description_cols, instance)
600
643
 
644
+ if instance['statusMessage']
645
+ print_h2 "Status Message"
646
+ if instance['status'] == 'failed'
647
+ print red, instance['statusMessage'], reset
648
+ else
649
+ print instance['statusMessage']
650
+ end
651
+ print "\n"
652
+ end
653
+ if instance['errorMessage']
654
+ print_h2 "Error Message"
655
+ print red, instance['errorMessage'], reset
656
+ print "\n"
657
+ end
601
658
  if stats
602
659
  print_h2 "Instance Usage"
603
660
  print_stats_usage(stats)
@@ -650,15 +707,16 @@ class Morpheus::Cli::Instances
650
707
  if current_instance_lb
651
708
  print_h2 "Load Balancer"
652
709
  print cyan
710
+ # this api response is going to change again.. port is no longer returned atm.
653
711
  description_cols = {
654
712
  "LB ID" => lambda {|it| it['loadBalancer']['id'] },
655
713
  "Name" => lambda {|it| it['loadBalancer']['name'] },
656
714
  "Type" => lambda {|it| it['loadBalancer']['type'] ? it['loadBalancer']['type']['name'] : '' },
657
715
  "Host Name" => lambda {|it| it['loadBalancer']['host'] }, # instance.hostName ?
658
- "Port" => lambda {|it| it['port']['port'] },
659
- "Protocol" => lambda {|it| it['port']['proxyProtocol'] },
660
- "SSL Enabled" => lambda {|it| format_boolean it['port']['sslEnabled'] },
661
- "Cert" => lambda {|it| it['port']['sslCert'] ? it['port']['sslCert']['name'] : 'N/A' } # api needs to return this too..
716
+ "Port" => lambda {|it| it['port'] ? it['port']['port'] : '' },
717
+ "Protocol" => lambda {|it| it['port'] ? it['port']['proxyProtocol'] : '' },
718
+ "SSL Enabled" => lambda {|it| it['port'] ? format_boolean(it['port']['sslEnabled']) : '' },
719
+ "Cert" => lambda {|it| (it['port'] && it['port']['sslCert']) ? it['port']['sslCert']['name'] : '' }
662
720
  }
663
721
  print_description_list(description_cols, current_instance_lb)
664
722
  print "\n", reset
@@ -2054,20 +2112,20 @@ class Morpheus::Cli::Instances
2054
2112
  }
2055
2113
 
2056
2114
  cur_host_name = instance['hostName']
2057
- #host_name = params = Morpheus::Cli::OptionTypes.prompt([{fieldName:'hostName'}], options[:options], @api_client, {})
2115
+ #host_name = params = Morpheus::Cli::OptionTypes.prompt([{'fieldName'=>'hostName', 'label'=>'Host Name', 'defaultValue'=>cur_host_name}], options[:options], @api_client, {})
2058
2116
  payload['instance']['hostName'] = instance['hostName']
2059
2117
 
2060
- payload['loadBalancerId'] = 9999
2118
+ #payload['loadBalancerId'] = params['loadBalancerId']
2061
2119
 
2062
2120
  unless options[:yes] || ::Morpheus::Cli::OptionTypes::confirm("Are you sure you would like to update the load balancer for instance '#{instance['name']}'?", options)
2063
2121
  return 9, "aborted command"
2064
2122
  end
2065
2123
 
2066
2124
  if options[:dry_run]
2067
- print_dry_run @instances_interface.dry.update_threshold(instance['id'], payload)
2125
+ print_dry_run @instances_interface.dry.update_load_balancer(instance['id'], payload)
2068
2126
  return
2069
2127
  end
2070
- json_response = @instances_interface.update_threshold(instance['id'], payload)
2128
+ json_response = @instances_interface.update_load_balancer(instance['id'], payload)
2071
2129
  if options[:json]
2072
2130
  puts as_json(json_response, options)
2073
2131
  else
@@ -29,7 +29,7 @@ class Morpheus::Cli::LoadBalancers
29
29
  options = {}
30
30
  optparse = OptionParser.new do|opts|
31
31
  opts.banner = subcommand_usage()
32
- build_common_options(opts, options, [:list, :json, :dry_run, :remote])
32
+ build_common_options(opts, options, [:list, :json, :csv, :yaml, :fields, :dry_run, :remote])
33
33
  end
34
34
  optparse.parse!(args)
35
35
  connect(options)
@@ -44,24 +44,41 @@ class Morpheus::Cli::LoadBalancers
44
44
  end
45
45
  json_response = @load_balancers_interface.get(params)
46
46
  if options[:json]
47
- print JSON.pretty_generate(json_response)
47
+ if options[:include_fields]
48
+ json_response = {"loadBalancers" => filter_data(json_response["loadBalancers"], options[:include_fields]) }
49
+ end
50
+ puts as_json(json_response, options)
51
+ return 0
52
+ elsif options[:csv]
53
+ puts records_as_csv(json_response["loadBalancers"], options)
54
+ return 0
55
+ elsif options[:yaml]
56
+ if options[:include_fields]
57
+ json_response = {"loadBalancers" => filter_data(json_response["loadBalancers"], options[:include_fields]) }
58
+ end
59
+ puts as_yaml(json_response, options)
60
+ return 0
48
61
  else
49
62
  lbs = json_response['loadBalancers']
50
63
  print_h1 "Morpheus Load Balancers"
51
64
  if lbs.empty?
52
- print cyan,"No load balancers found.",reset,"\n"
65
+ print yellow,"No load balancers found.",reset,"\n"
53
66
  else
54
- print cyan
55
- lb_table_data = lbs.collect do |lb|
56
- {name: lb['name'], id: lb['id'], type: lb['type']['name']}
57
- end
58
- tp lb_table_data, :id, :name, :type
67
+ columns = [
68
+ {"ID" => 'id'},
69
+ {"Name" => 'name'},
70
+ {"Type" => lambda {|it| it['type'] ? it['type']['name'] : '' } },
71
+ {"Cloud" => lambda {|it| it['cloud'] ? it['cloud']['name'] : '' } },
72
+ {"Host" => lambda {|it| it['host'] } },
73
+ ]
74
+ print as_pretty_table(lbs, columns, options)
59
75
  end
60
76
  print reset,"\n"
77
+ return 0
61
78
  end
62
- rescue RestClient::Exception => e
79
+ rescue RestClient::Exception => e
63
80
  print_rest_exception(e, options)
64
- exit 1
81
+ return 1
65
82
  end
66
83
  end
67
84
 
@@ -69,7 +86,7 @@ class Morpheus::Cli::LoadBalancers
69
86
  options = {}
70
87
  optparse = OptionParser.new do|opts|
71
88
  opts.banner = subcommand_usage("[name]")
72
- build_common_options(opts, options, [:json, :dry_run, :remote])
89
+ build_common_options(opts, options, [:json, :csv, :yaml, :fields, :dry_run, :remote])
73
90
  end
74
91
  optparse.parse!(args)
75
92
  if args.count < 1
@@ -89,15 +106,62 @@ class Morpheus::Cli::LoadBalancers
89
106
  end
90
107
  lb = find_lb_by_name_or_id(lb_name)
91
108
  exit 1 if lb.nil?
109
+ # refetch
110
+ json_response = @load_balancers_interface.get(lb['id'])
92
111
  lb_type = load_balancer_type_for_name_or_id(lb['type']['code'])
112
+ #puts "LB TYPE: #{lb_type}"
93
113
  if options[:json]
94
114
  puts JSON.pretty_generate({loadBalancer: lb})
115
+ if options[:include_fields]
116
+ json_response = {"loadBalancer" => filter_data(json_response["loadBalancer"], options[:include_fields]) }
117
+ end
118
+ puts as_json(json_response, options)
119
+ return 0
120
+ elsif options[:csv]
121
+ puts records_as_csv(json_response["loadBalancer"], options)
122
+ return 0
123
+ elsif options[:yaml]
124
+ if options[:include_fields]
125
+ json_response = {"loadBalancer" => filter_data(json_response["loadBalancer"], options[:include_fields]) }
126
+ end
127
+ puts as_yaml(json_response, options)
128
+ return 0
95
129
  else
96
- print "\n", cyan, "Lb #{lb['name']} - #{lb['type']['name']}\n\n"
97
- # lb_type['optionTypes'].sort { |x,y| x['displayOrder'].to_i <=> y['displayOrder'].to_i }.each do |optionType|
98
- # puts " #{optionType['fieldLabel']} : " + (optionType['type'] == 'password' ? "#{task['taskOptions'][optionType['fieldName']] ? '************' : ''}" : "#{task['taskOptions'][optionType['fieldName']] || optionType['defaultValue']}")
99
- # end
100
- print reset,"\n\n"
130
+ print_h1 "Load Balancer Details"
131
+ description_cols = {
132
+ "ID" => 'id',
133
+ "Name" => 'name',
134
+ "Description" => 'description',
135
+ "Type" => lambda {|it| it['type'] ? it['type']['name'] : '' },
136
+ "Cloud" => lambda {|it| it['cloud'] ? it['cloud']['name'] : '' },
137
+ "Visibility" => 'visibility',
138
+ "IP" => 'ip',
139
+ "Host" => 'host',
140
+ "Port" => 'port',
141
+ "Username" => 'username',
142
+ # "SSL Enabled" => lambda {|it| format_boolean it['sslEnabled'] },
143
+ # "SSL Cert" => lambda {|it| it['sslCert'] ? it['sslCert']['name'] : '' },
144
+ # "SSL" => lambda {|it| it['sslEnabled'] ? "Yes (#{it['sslCert'] ? it['sslCert']['name'] : 'none'})" : "No" },
145
+ "Created" => lambda {|it| format_local_dt(it['dateCreated']) },
146
+ "Updated" => lambda {|it| format_local_dt(it['lastUpdated']) }
147
+ }
148
+ print_description_list(description_cols, lb)
149
+
150
+
151
+ if lb['ports'] && lb['ports'].size > 0
152
+ print_h2 "LB Ports"
153
+ columns = [
154
+ {"ID" => 'id'},
155
+ {"Name" => 'name'},
156
+ #{"Description" => 'description'},
157
+ {"Port" => lambda {|it| it['port'] } },
158
+ {"Protocol" => lambda {|it| it['proxyProtocol'] } },
159
+ {"SSL" => lambda {|it| it['sslEnabled'] ? "Yes (#{it['sslCert'] ? it['sslCert']['name'] : 'none'})" : "No" } },
160
+ ]
161
+ print as_pretty_table(lb['ports'], columns, options)
162
+ end
163
+ print reset,"\n"
164
+ return 0
101
165
  end
102
166
  rescue RestClient::Exception => e
103
167
  print_rest_exception(e, options)
@@ -482,7 +482,7 @@ module Morpheus::Cli::PrintHelper
482
482
  max_label_width = 0
483
483
  justify = opts.key?(:justify) ? opts[:justify] : "right"
484
484
  do_wrap = opts.key?(:wrap) ? !!opts[:wrap] : true
485
-
485
+ color = opts.key?(:color) ? opts[:color] : cyan
486
486
  rows = []
487
487
 
488
488
  columns.flatten.each do |column_def|
@@ -501,6 +501,7 @@ module Morpheus::Cli::PrintHelper
501
501
  end
502
502
 
503
503
  out = ""
504
+ out << color if color
504
505
  rows.each do |row|
505
506
  value = row[:value].to_s
506
507
  if do_wrap
@@ -511,6 +512,7 @@ module Morpheus::Cli::PrintHelper
511
512
  end
512
513
  out << format_dt_dd(row[:label], value, label_width, justify) + "\n"
513
514
  end
515
+ out << reset if color
514
516
  return out
515
517
  end
516
518
 
@@ -324,6 +324,12 @@ module Morpheus::Cli::ProvisioningHelper
324
324
  payload['evars'] = evars
325
325
  end
326
326
 
327
+ # prompt for metadata variables
328
+ metadata = prompt_metadata(options)
329
+ if !metadata.empty?
330
+ payload['metadata'] = metadata
331
+ end
332
+
327
333
  return payload
328
334
  end
329
335
 
@@ -806,6 +812,10 @@ module Morpheus::Cli::ProvisioningHelper
806
812
  # puts JSON.pretty_generate(zone_network_options_json)
807
813
  zone_network_data = zone_network_options_json['data'] || {}
808
814
  networks = zone_network_data['networks']
815
+ network_groups = zone_network_data['networkGroups']
816
+ if network_groups
817
+ networks = network_groups + networks
818
+ end
809
819
  network_interface_types = (zone_network_data['networkTypes'] || []).sort { |x,y| x['displayOrder'] <=> y['displayOrder'] }
810
820
  enable_network_type_selection = (zone_network_data['enableNetworkTypeSelection'] == 'on' || zone_network_data['enableNetworkTypeSelection'] == true)
811
821
  has_networks = zone_network_data["hasNetworks"] == true
@@ -853,8 +863,8 @@ module Morpheus::Cli::ProvisioningHelper
853
863
  # choose network
854
864
  v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldContext' => field_context, 'fieldName' => 'networkId', 'type' => 'select', 'fieldLabel' => "Network", 'selectOptions' => network_options, 'required' => true, 'skipSingleOption' => false, 'description' => 'Choose a network for this interface.', 'defaultValue' => network_interface['networkId']}], options[:options])
855
865
  network_interface['network'] = {}
856
- network_interface['network']['id'] = v_prompt[field_context]['networkId'].to_i
857
- selected_network = networks.find {|it| it["id"] == network_interface['network']['id'] }
866
+ network_interface['network']['id'] = v_prompt[field_context]['networkId'].to_s
867
+ selected_network = networks.find {|it| it["id"].to_s == network_interface['network']['id'] }
858
868
 
859
869
  if !selected_network
860
870
  print_red_alert "Network not found by id #{network_interface['network']['id']}!"
@@ -868,7 +878,9 @@ module Morpheus::Cli::ProvisioningHelper
868
878
  end
869
879
 
870
880
  # choose IP unless network has a pool configured
871
- if selected_network['pool']
881
+ if selected_network['id'].to_s.include?('networkGroup')
882
+ puts "IP Address: Using network group." if !no_prompt
883
+ elsif selected_network['pool']
872
884
  puts "IP Address: Using pool '#{selected_network['pool']['name']}'" if !no_prompt
873
885
  elsif selected_network['dhcpServer']
874
886
  puts "IP Address: Using DHCP" if !no_prompt
@@ -917,6 +929,73 @@ module Morpheus::Cli::ProvisioningHelper
917
929
  return evars
918
930
  end
919
931
 
932
+ # Prompts user for environment variables for new instance
933
+ # returns array of metadata objects {id: null, name: "MYTAG", value: "myvalue"}
934
+ def prompt_metadata(options={})
935
+ #puts "Configure Environment Variables:"
936
+ no_prompt = (options[:no_prompt] || (options[:options] && options[:options][:no_prompt]))
937
+ metadata_array = []
938
+ metadata_index = 0
939
+ has_another_metadata = options[:options] && options[:options]["metadata#{metadata_index}"]
940
+ add_another_metadata = has_another_metadata || (!no_prompt && Morpheus::Cli::OptionTypes.confirm("Add a metadata tag?", {default: false}))
941
+ while add_another_metadata do
942
+ field_context = "metadata#{metadata_index}"
943
+ metadata = {}
944
+ metadata['id'] = nil
945
+ metadata_label = metadata_index == 0 ? "Metadata Tag" : "Metadata Tag [#{metadata_index+1}]"
946
+ 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])
947
+ # todo: metadata.type ?
948
+ metadata['name'] = v_prompt[field_context]['name']
949
+ 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])
950
+ metadata['value'] = v_prompt[field_context]['value']
951
+ metadata_array << metadata
952
+ metadata_index += 1
953
+ has_another_metadata = options[:options] && options[:options]["metadata#{metadata_index}"]
954
+ add_another_metadata = has_another_metadata || (!no_prompt && Morpheus::Cli::OptionTypes.confirm("Add another metadata tag?", {default: false}))
955
+ end
956
+
957
+ return metadata_array
958
+ end
959
+
960
+ # Prompts user for load balancer settings
961
+ # returns Hash of parameters like {loadBalancerId: "-1", etc}
962
+ def prompt_instance_load_balancer(instance, default_lb_id, options)
963
+ #puts "Configure Environment Variables:"
964
+ no_prompt = (options[:no_prompt] || (options[:options] && options[:options][:no_prompt]))
965
+ payload = {}
966
+ api_params = {}
967
+ if instance['id']
968
+ api_params['instanceId'] = instance['id']
969
+ end
970
+ if instance['zone']
971
+ api_params['zoneId'] = instance['zone']['id']
972
+ elsif instance['cloud']
973
+ api_params['zoneId'] = instance['cloud']['id']
974
+ end
975
+ if instance['group']
976
+ api_params['siteId'] = instance['group']['id']
977
+ elsif instance['site']
978
+ api_params['siteId'] = instance['site']['id']
979
+ end
980
+ if instance['plan']
981
+ api_params['planId'] = instance['plan']['id']
982
+ end
983
+ v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'loadBalancerId', 'type' => 'select', 'fieldLabel' => "Load Balancer", 'optionSource' => 'loadBalancers', 'required' => true, 'description' => 'Select Load Balancer for instance', 'defaultValue' => default_lb_id || ''}], options[:options], api_client, api_params)
984
+ lb_id = v_prompt['loadBalancerId']
985
+ payload['loadBalancerId'] = lb_id
986
+
987
+ # todo: finish implmenting this
988
+
989
+ # loadBalancerId
990
+ # loadBalancerProxyProtocol
991
+ # loadBalancerName
992
+ # loadBalancerDescription
993
+ # loadBalancerSslCert
994
+ # loadBalancerScheme
995
+
996
+ return payload
997
+ end
998
+
920
999
  # reject old volume option types
921
1000
  # these will eventually get removed from the associated optionTypes
922
1001
  def reject_volume_option_types(option_types)
@@ -8,7 +8,6 @@ class Morpheus::Cli::RecentActivityCommand
8
8
  include Morpheus::Cli::AccountsHelper
9
9
 
10
10
  set_command_name :'recent-activity'
11
- set_command_hidden # remove once this is done
12
11
 
13
12
  def initialize()
14
13
  # @appliance_name, @appliance_url = Morpheus::Cli::Remote.active_appliance
@@ -37,7 +36,7 @@ class Morpheus::Cli::RecentActivityCommand
37
36
  opts.on('--end TIMESTAMP','--end TIMESTAMP', "End timestamp. Default is now.") do |val|
38
37
  options[:end] = parse_time(val).iso8601
39
38
  end
40
- build_common_options(opts, options, [:account, :list, :json, :dry_run])
39
+ build_common_options(opts, options, [:account, :list, :json, :yaml, :csv, :fields, :dry_run, :remote])
41
40
  end
42
41
  optparse.parse!(args)
43
42
  connect(options)
@@ -54,22 +53,90 @@ class Morpheus::Cli::RecentActivityCommand
54
53
  end
55
54
  json_response = @dashboard_interface.recent_activity(account_id, params)
56
55
  if options[:json]
56
+ if options[:include_fields]
57
+ json_response = {"activity" => filter_data(json_response["activity"], options[:include_fields]) }
58
+ end
57
59
  print JSON.pretty_generate(json_response)
58
60
  print "\n"
59
- else
60
-
61
- # todo: impersonate command and show that info here
61
+ return 0
62
+ end
63
+ if options[:csv]
64
+ puts records_as_csv(json_response["activity"], options)
65
+ return 0
66
+ end
67
+ if options[:yaml]
68
+ if options[:include_fields]
69
+ json_response = {"activity" => filter_data(json_response["activity"], options[:include_fields]) }
70
+ end
71
+ puts as_yaml(json_response, options)
72
+ return 0
73
+ end
62
74
 
63
- print_h1 "Recent Activity"
64
- print cyan
65
- puts "Coming soon... see --json"
75
+ print_h1 "Recent Activity"
76
+ print cyan
77
+ items = json_response["activity"]
78
+ if items.empty?
79
+ puts "No activity found."
66
80
  print reset,"\n"
67
-
81
+ return 0
68
82
  end
83
+ # JD: this api response is funky, no meta and it includes date objects
84
+ items = items.select { |item| item['_id'] || item['name'] }
85
+ print_recent_activity_table(items, options)
86
+ print reset,"\n"
87
+ return 0
88
+
69
89
  rescue RestClient::Exception => e
70
90
  print_rest_exception(e, options)
71
- exit 1
91
+ return 1
92
+ end
93
+ end
94
+
95
+ def print_recent_activity_table(items, opts={})
96
+ columns = [
97
+ # {"ID" => lambda {|item| item['id'] } },
98
+ # {"SEVERITY" => lambda {|item| format_activity_severity(item['severity']) } },
99
+ {"TYPE" => lambda {|item| item['activityType'] } },
100
+ {"AUTHOR" => lambda {|item| item['userName'] || '' } },
101
+ {"MESSAGE" => lambda {|item| item['message'] || '' } },
102
+ # {"NAME" => lambda {|item| item['name'] } },
103
+ {"OBJECT" => lambda {|item| format_activity_display_object(item) } },
104
+ {"WHEN" => lambda {|item| format_local_dt(item['ts']) } }
105
+ # {"WHEN" => lambda {|item| "#{format_duration(item['ts'])} ago" } }
106
+ ]
107
+ if opts[:include_fields]
108
+ columns = opts[:include_fields]
109
+ end
110
+ print as_pretty_table(items, columns, opts)
111
+ end
112
+
113
+ def format_activity_severity(severity, return_color=cyan)
114
+ out = ""
115
+ status_string = severity
116
+ if status_string == 'critical'
117
+ out << "#{red}#{status_string.capitalize}#{return_color}"
118
+ elsif status_string == 'warning'
119
+ out << "#{yellow}#{status_string.capitalize}#{return_color}"
120
+ elsif status_string == 'info'
121
+ out << "#{cyan}#{status_string.capitalize}#{return_color}"
122
+ else
123
+ out << "#{cyan}#{status_string}#{return_color}"
124
+ end
125
+ out
126
+ end
127
+
128
+ def format_activity_display_object(item)
129
+ out = ""
130
+ if item['name']
131
+ out << item['name']
132
+ end
133
+ if item['objectType']
134
+ out << " (#{item['objectType']} #{item['objectId']})"
135
+ end
136
+ if item['deleted']
137
+ out << " [deleted]"
72
138
  end
139
+ out
73
140
  end
74
141
 
75
142
  end
@@ -1,6 +1,6 @@
1
1
 
2
2
  module Morpheus
3
3
  module Cli
4
- VERSION = "2.11.1"
4
+ VERSION = "2.11.3"
5
5
  end
6
6
  end
@@ -1,4 +1,4 @@
1
- require 'rest_client'
1
+ require 'rest-client'
2
2
 
3
3
  module Morpheus
4
4
  # A wrapper around rest_client so we can more easily deal with passing options (like turning on/off SSL verification)
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: morpheus-cli
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.11.1
4
+ version: 2.11.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - David Estes
@@ -11,7 +11,7 @@ authors:
11
11
  autorequire:
12
12
  bindir: bin
13
13
  cert_chain: []
14
- date: 2017-04-24 00:00:00.000000000 Z
14
+ date: 2017-06-26 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: bundler