morpheus-cli 5.3.0.3 → 5.3.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Dockerfile +1 -1
- data/README.md +1 -3
- data/lib/morpheus/api/api_client.rb +48 -14
- data/lib/morpheus/api/certificate_types_interface.rb +14 -0
- data/lib/morpheus/api/certificates_interface.rb +9 -0
- data/lib/morpheus/api/integration_types_interface.rb +14 -0
- data/lib/morpheus/api/integrations_interface.rb +7 -22
- data/lib/morpheus/api/network_services_interface.rb +14 -0
- data/lib/morpheus/api/read_interface.rb +23 -0
- data/lib/morpheus/api/rest_interface.rb +12 -10
- data/lib/morpheus/api/roles_interface.rb +7 -0
- data/lib/morpheus/api/servers_interface.rb +7 -0
- data/lib/morpheus/api/user_settings_interface.rb +38 -18
- data/lib/morpheus/api/vdi_allocations_interface.rb +9 -0
- data/lib/morpheus/api/vdi_apps_interface.rb +9 -0
- data/lib/morpheus/api/vdi_gateways_interface.rb +9 -0
- data/lib/morpheus/api/vdi_interface.rb +28 -0
- data/lib/morpheus/api/vdi_pools_interface.rb +19 -0
- data/lib/morpheus/cli.rb +9 -2
- data/lib/morpheus/cli/apps.rb +59 -75
- data/lib/morpheus/cli/catalog_item_types_command.rb +13 -13
- data/lib/morpheus/cli/certificates_command.rb +575 -0
- data/lib/morpheus/cli/cli_command.rb +61 -6
- data/lib/morpheus/cli/clouds.rb +1 -0
- data/lib/morpheus/cli/clusters.rb +1 -1
- data/lib/morpheus/cli/commands/standard/man_command.rb +4 -5
- data/lib/morpheus/cli/hosts.rb +245 -224
- data/lib/morpheus/cli/instances.rb +150 -167
- data/lib/morpheus/cli/integrations_command.rb +588 -41
- data/lib/morpheus/cli/login.rb +7 -0
- data/lib/morpheus/cli/mixins/print_helper.rb +33 -18
- data/lib/morpheus/cli/mixins/provisioning_helper.rb +3 -3
- data/lib/morpheus/cli/mixins/vdi_helper.rb +246 -0
- data/lib/morpheus/cli/network_routers_command.rb +22 -9
- data/lib/morpheus/cli/networks_command.rb +2 -2
- data/lib/morpheus/cli/option_types.rb +34 -33
- data/lib/morpheus/cli/remote.rb +1 -1
- data/lib/morpheus/cli/reports_command.rb +4 -1
- data/lib/morpheus/cli/roles.rb +215 -55
- data/lib/morpheus/cli/subnets_command.rb +11 -2
- data/lib/morpheus/cli/user_settings_command.rb +268 -57
- data/lib/morpheus/cli/vdi_allocations_command.rb +159 -0
- data/lib/morpheus/cli/vdi_apps_command.rb +317 -0
- data/lib/morpheus/cli/vdi_command.rb +359 -0
- data/lib/morpheus/cli/vdi_gateways_command.rb +290 -0
- data/lib/morpheus/cli/vdi_pools_command.rb +571 -0
- data/lib/morpheus/cli/version.rb +1 -1
- data/lib/morpheus/rest_client.rb +30 -0
- data/lib/morpheus/terminal.rb +15 -7
- metadata +18 -2
@@ -204,7 +204,10 @@ module Morpheus
|
|
204
204
|
# elsif option['type'] == 'select'
|
205
205
|
end
|
206
206
|
full_option = "--#{full_field_name} #{value_label}"
|
207
|
-
|
207
|
+
# switch is an alias for the full option name, fieldName is the default
|
208
|
+
if option_type['switch']
|
209
|
+
full_option = "--#{option_type['switch']} #{value_label}"
|
210
|
+
end
|
208
211
|
arg1, arg2 = full_option, String
|
209
212
|
if option_type['shorthand']
|
210
213
|
arg1, arg2 = full_option, option_type['shorthand']
|
@@ -243,7 +246,7 @@ module Morpheus
|
|
243
246
|
## the standard options for a command that makes api requests (most of them)
|
244
247
|
|
245
248
|
def build_standard_get_options(opts, options, includes=[], excludes=[])
|
246
|
-
build_common_options(opts, options, includes + [:query, :json, :yaml, :csv, :fields, :quiet, :dry_run, :remote], excludes)
|
249
|
+
build_common_options(opts, options, includes + [:query, :json, :yaml, :csv, :fields, :select, :delim, :quiet, :dry_run, :remote], excludes)
|
247
250
|
end
|
248
251
|
|
249
252
|
def build_standard_post_options(opts, options, includes=[], excludes=[])
|
@@ -688,36 +691,50 @@ module Morpheus
|
|
688
691
|
options[:format] = :csv
|
689
692
|
#options[:csv_delim] = options[:csv_delim] || ","
|
690
693
|
end
|
691
|
-
|
694
|
+
# deprecated --csv-delim, use --delimiter instead
|
692
695
|
opts.on('--csv-delim CHAR', String, "Delimiter for CSV Output values. Default: ','") do |val|
|
693
696
|
options[:csv] = true
|
694
697
|
options[:format] = :csv
|
695
698
|
val = val.gsub("\\n", "\n").gsub("\\r", "\r").gsub("\\t", "\t") if val.include?("\\")
|
696
699
|
options[:csv_delim] = val
|
697
700
|
end
|
701
|
+
opts.add_hidden_option('--csv-delim') if opts.is_a?(Morpheus::Cli::OptionParser)
|
698
702
|
|
703
|
+
# deprecated --csv-newline, use --newline instead
|
699
704
|
opts.on('--csv-newline [CHAR]', String, "Delimiter for CSV Output rows. Default: '\\n'") do |val|
|
700
705
|
options[:csv] = true
|
701
706
|
options[:format] = :csv
|
702
707
|
if val == "no" || val == "none"
|
703
708
|
options[:csv_newline] = ""
|
704
709
|
else
|
705
|
-
val = val.gsub("\\n", "\n").gsub("\\r", "\r").gsub("\\t", "\t") if val.include?("\\")
|
710
|
+
val = val.to_s.gsub("\\n", "\n").gsub("\\r", "\r").gsub("\\t", "\t") if val.include?("\\")
|
706
711
|
options[:csv_newline] = val
|
707
712
|
end
|
708
713
|
end
|
714
|
+
opts.add_hidden_option('--csv-newline') if opts.is_a?(Morpheus::Cli::OptionParser)
|
709
715
|
|
710
716
|
opts.on(nil, '--csv-quotes', "Wrap CSV values with \". Default: false") do
|
711
717
|
options[:csv] = true
|
712
718
|
options[:format] = :csv
|
713
719
|
options[:csv_quotes] = true
|
714
720
|
end
|
721
|
+
opts.add_hidden_option('--csv-quotes') if opts.is_a?(Morpheus::Cli::OptionParser)
|
715
722
|
|
716
723
|
opts.on(nil, '--csv-no-header', "Exclude header for CSV Output.") do
|
717
724
|
options[:csv] = true
|
718
725
|
options[:format] = :csv
|
719
726
|
options[:csv_no_header] = true
|
720
727
|
end
|
728
|
+
opts.add_hidden_option('--csv-no-header') if opts.is_a?(Morpheus::Cli::OptionParser)
|
729
|
+
|
730
|
+
opts.on(nil, '--quotes', "Wrap CSV values with \". Default: false") do
|
731
|
+
options[:csv_quotes] = true
|
732
|
+
end
|
733
|
+
opts.add_hidden_option('--csv-quotes') if opts.is_a?(Morpheus::Cli::OptionParser)
|
734
|
+
|
735
|
+
opts.on(nil, '--no-header', "Exclude header for CSV Output.") do
|
736
|
+
options[:csv_no_header] = true
|
737
|
+
end
|
721
738
|
|
722
739
|
when :fields
|
723
740
|
opts.on('-f', '--fields x,y,z', Array, "Filter Output to a limited set of fields. Default is all fields for json,csv,yaml.") do |val|
|
@@ -738,10 +755,35 @@ module Morpheus
|
|
738
755
|
opts.on(nil, '--all-fields', "Show all fields present in the data.") do
|
739
756
|
options[:all_fields] = true
|
740
757
|
end
|
741
|
-
#opts.add_hidden_option('--all-fields') if opts.is_a?(Morpheus::Cli::OptionParser)
|
742
758
|
opts.on(nil, '--wrap', "Wrap table columns instead hiding them when terminal is not wide enough.") do
|
743
759
|
options[:wrap] = true
|
744
760
|
end
|
761
|
+
when :select
|
762
|
+
#opts.add_hidden_option('--all-fields') if opts.is_a?(Morpheus::Cli::OptionParser)
|
763
|
+
opts.on('--select x,y,z', String, "Filter Output to just print the value(s) of specific fields.") do |val|
|
764
|
+
options[:select_fields] = val.split(',').collect {|r| r.strip}
|
765
|
+
end
|
766
|
+
|
767
|
+
when :delim
|
768
|
+
opts.on('--delimiter [CHAR]', String, "Delimiter for output values. Default: ',', use with --select and --csv") do |val|
|
769
|
+
options[:csv] = true
|
770
|
+
options[:format] = :csv
|
771
|
+
val = val.to_s
|
772
|
+
val = val.gsub("\\n", "\n").gsub("\\r", "\r").gsub("\\t", "\t") if val.include?("\\")
|
773
|
+
options[:delim] = val
|
774
|
+
end
|
775
|
+
|
776
|
+
opts.on('--newline [CHAR]', String, "Delimiter for output rows. Default: '\\n', use with --select and --csv") do |val|
|
777
|
+
options[:csv] = true
|
778
|
+
options[:format] = :csv
|
779
|
+
val = val.to_s
|
780
|
+
if val == "no" || val == "none"
|
781
|
+
options[:newline] = ""
|
782
|
+
else
|
783
|
+
val = val.to_s.gsub("\\n", "\n").gsub("\\r", "\r").gsub("\\t", "\t") if val.include?("\\")
|
784
|
+
options[:newline] = val
|
785
|
+
end
|
786
|
+
end
|
745
787
|
when :thin
|
746
788
|
opts.on( '--thin', '--thin', "Format headers and columns with thin borders." ) do |val|
|
747
789
|
options[:border_style] = :thin
|
@@ -1285,7 +1327,20 @@ module Morpheus
|
|
1285
1327
|
# returns the string rendered, or nil if nothing was rendered.
|
1286
1328
|
def render_response(json_response, options, object_key=nil, &block)
|
1287
1329
|
output = nil
|
1288
|
-
if options[:
|
1330
|
+
if options[:select_fields]
|
1331
|
+
row = object_key ? json_response[object_key] : json_response
|
1332
|
+
row = [row].flatten()
|
1333
|
+
if row.is_a?(Array)
|
1334
|
+
output = [row].flatten.collect { |record|
|
1335
|
+
options[:select_fields].collect { |field|
|
1336
|
+
value = get_object_value(record, field)
|
1337
|
+
value.is_a?(String) ? value : JSON.fast_generate(value)
|
1338
|
+
}.join(options[:delim] || ",")
|
1339
|
+
}.join(options[:newline] || "\n")
|
1340
|
+
else
|
1341
|
+
output = records_as_csv([row], options)
|
1342
|
+
end
|
1343
|
+
elsif options[:json]
|
1289
1344
|
output = as_json(json_response, options, object_key)
|
1290
1345
|
elsif options[:yaml]
|
1291
1346
|
output = as_yaml(json_response, options, object_key)
|
data/lib/morpheus/cli/clouds.rb
CHANGED
@@ -313,6 +313,7 @@ class Morpheus::Cli::Clouds
|
|
313
313
|
end
|
314
314
|
|
315
315
|
all_option_types = add_cloud_option_types(cloud_type)
|
316
|
+
|
316
317
|
params = Morpheus::Cli::OptionTypes.prompt(all_option_types, options[:options], @api_client, {zoneTypeId: cloud_type['id']})
|
317
318
|
# some optionTypes have fieldContext='zone', so move those to the root level of the zone payload
|
318
319
|
if params['zone'].is_a?(Hash)
|
@@ -515,7 +515,7 @@ class Morpheus::Cli::Clusters
|
|
515
515
|
tags = options[:tags]
|
516
516
|
|
517
517
|
if !tags && !options[:no_prompt]
|
518
|
-
tags = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'tags', 'type' => 'text', 'fieldLabel' => 'Resource
|
518
|
+
tags = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'tags', 'type' => 'text', 'fieldLabel' => 'Resource Labels', 'required' => false, 'description' => 'Resource Tags.'}],options[:options],@api_client,{})['tags']
|
519
519
|
end
|
520
520
|
|
521
521
|
server_payload['tags'] = tags if tags
|
@@ -341,12 +341,12 @@ You can use this to create isolated environments (sandboxes), within which to ex
|
|
341
341
|
|
342
342
|
```shell
|
343
343
|
export MORPHEUS_CLI_HOME=~/morpheus_test
|
344
|
-
morpheus remote add demo https://demo
|
344
|
+
morpheus remote add demo https://demo-morpheus --insecure
|
345
345
|
morpheus instances list
|
346
346
|
```
|
347
347
|
|
348
348
|
Morpheus saves the remote appliance information, including api access tokens,
|
349
|
-
to the
|
349
|
+
to the CLI home directory. These files are saved with file permissions **6000**.
|
350
350
|
So, only one system user should be allowed to execute morpheus with that home directory.
|
351
351
|
See [Configuration](#Configuration) for more information on the files morpheus reads and writes.
|
352
352
|
|
@@ -363,10 +363,9 @@ The `appliances` YAML file contains a list of known appliances, keyed by name.
|
|
363
363
|
Example:
|
364
364
|
```yaml
|
365
365
|
:qa:
|
366
|
-
:host: https://qa
|
367
|
-
:active: true
|
366
|
+
:host: https://qa-morpheus
|
368
367
|
:production:
|
369
|
-
:host: https://
|
368
|
+
:host: https://production-morpheus
|
370
369
|
```
|
371
370
|
|
372
371
|
### credentials file
|
data/lib/morpheus/cli/hosts.rb
CHANGED
@@ -17,7 +17,7 @@ class Morpheus::Cli::Hosts
|
|
17
17
|
set_command_name :hosts
|
18
18
|
set_command_description "View and manage hosts (servers)."
|
19
19
|
register_subcommands :list, :count, :get, :view, :stats, :add, :update, :remove, :logs, :start, :stop, :resize,
|
20
|
-
:run_workflow, :make_managed, :upgrade_agent, :snapshots, :software,
|
20
|
+
:run_workflow, :make_managed, :upgrade_agent, :snapshots, :software, :software_sync,
|
21
21
|
{:'types' => :list_types},
|
22
22
|
{:exec => :execution_request},
|
23
23
|
:wiki, :update_wiki
|
@@ -152,215 +152,206 @@ class Morpheus::Cli::Hosts
|
|
152
152
|
if args.count > 0
|
153
153
|
options[:phrase] = args.join(" ")
|
154
154
|
end
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
end
|
165
|
-
end
|
166
|
-
group = options[:group] ? find_group_by_name_or_id_for_provisioning(options[:group]) : nil
|
167
|
-
if group
|
168
|
-
params['siteId'] = group['id']
|
155
|
+
|
156
|
+
params.merge!(parse_list_options(options))
|
157
|
+
account = nil
|
158
|
+
if options[:account]
|
159
|
+
account = find_account_by_name_or_id(options[:account])
|
160
|
+
if account.nil?
|
161
|
+
return 1
|
162
|
+
else
|
163
|
+
params['accountId'] = account['id']
|
169
164
|
end
|
165
|
+
end
|
166
|
+
group = options[:group] ? find_group_by_name_or_id_for_provisioning(options[:group]) : nil
|
167
|
+
if group
|
168
|
+
params['siteId'] = group['id']
|
169
|
+
end
|
170
170
|
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
171
|
+
# argh, this doesn't work because group_id is required for options/clouds
|
172
|
+
# cloud = options[:cloud] ? find_cloud_by_name_or_id_for_provisioning(group_id, options[:cloud]) : nil
|
173
|
+
cloud = options[:cloud] ? find_zone_by_name_or_id(nil, options[:cloud]) : nil
|
174
|
+
if cloud
|
175
|
+
params['zoneId'] = cloud['id']
|
176
|
+
end
|
177
177
|
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
end
|
178
|
+
if options[:created_by]
|
179
|
+
created_by_ids = find_all_user_ids(account ? account['id'] : nil, options[:created_by])
|
180
|
+
return if created_by_ids.nil?
|
181
|
+
params['createdBy'] = created_by_ids
|
182
|
+
# params['ownerId'] = created_by_ids # 4.2.1+
|
183
|
+
end
|
184
|
+
|
185
|
+
cluster = nil
|
186
|
+
if options[:cluster]
|
187
|
+
if options[:cluster].to_s =~ /\A\d{1,}\Z/
|
188
|
+
params['clusterId'] = options[:cluster]
|
189
|
+
else
|
190
|
+
cluster = find_cluster_by_name_or_id(options[:cluster])
|
191
|
+
return 1 if cluster.nil?
|
192
|
+
params['clusterId'] = cluster['id']
|
194
193
|
end
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
194
|
+
end
|
195
|
+
params['labels'] = options[:labels] if options[:labels]
|
196
|
+
if options[:tags] && !options[:tags].empty?
|
197
|
+
options[:tags].each do |k,v|
|
198
|
+
params['tags.' + k] = v
|
200
199
|
end
|
200
|
+
end
|
201
201
|
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
202
|
+
@servers_interface.setopts(options)
|
203
|
+
if options[:dry_run]
|
204
|
+
print_dry_run @servers_interface.dry.list(params)
|
205
|
+
return
|
206
|
+
end
|
207
|
+
json_response = @servers_interface.list(params)
|
208
208
|
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
json_response.delete('stats') if options[:include_fields]
|
215
|
-
puts as_yaml(json_response, options, "servers")
|
216
|
-
return 0
|
217
|
-
elsif options[:csv]
|
218
|
-
# merge stats to be nice here..
|
219
|
-
if json_response['servers']
|
220
|
-
all_stats = json_response['stats'] || {}
|
209
|
+
# merge stats to be nice here..
|
210
|
+
all_stats = json_response['stats']
|
211
|
+
if options[:include_fields] || options[:all_fields]
|
212
|
+
if json_response['servers']
|
213
|
+
if all_stats
|
221
214
|
json_response['servers'].each do |it|
|
222
215
|
it['stats'] ||= all_stats[it['id'].to_s] || all_stats[it['id']]
|
223
216
|
end
|
224
217
|
end
|
225
|
-
|
226
|
-
|
218
|
+
end
|
219
|
+
end
|
220
|
+
render_response(json_response, options, "servers") do
|
221
|
+
|
222
|
+
servers = json_response['servers']
|
223
|
+
multi_tenant = json_response['multiTenant'] == true
|
224
|
+
title = "Morpheus Hosts"
|
225
|
+
subtitles = []
|
226
|
+
if account
|
227
|
+
subtitles << "Tenant: #{account['name']}".strip
|
228
|
+
end
|
229
|
+
if group
|
230
|
+
subtitles << "Group: #{group['name']}".strip
|
231
|
+
end
|
232
|
+
if cloud
|
233
|
+
subtitles << "Cloud: #{cloud['name']}".strip
|
234
|
+
end
|
235
|
+
if cluster
|
236
|
+
subtitles << "Cluster: #{cluster['name']}".strip
|
237
|
+
elsif params['clusterId']
|
238
|
+
subtitles << "Cluster: #{params['clusterId']}".strip
|
239
|
+
end
|
240
|
+
subtitles += parse_list_subtitles(options)
|
241
|
+
print_h1 title, subtitles, options
|
242
|
+
if servers.empty?
|
243
|
+
print cyan,"No hosts found.",reset,"\n"
|
227
244
|
else
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
subtitles << "Cloud: #{cloud['name']}".strip
|
240
|
-
end
|
241
|
-
if cluster
|
242
|
-
subtitles << "Cluster: #{cluster['name']}".strip
|
243
|
-
elsif params['clusterId']
|
244
|
-
subtitles << "Cluster: #{params['clusterId']}".strip
|
245
|
-
end
|
246
|
-
subtitles += parse_list_subtitles(options)
|
247
|
-
print_h1 title, subtitles, options
|
248
|
-
if servers.empty?
|
249
|
-
print cyan,"No hosts found.",reset,"\n"
|
250
|
-
else
|
251
|
-
# print_servers_table(servers)
|
252
|
-
# server returns stats in a separate key stats => {"id" => {} }
|
253
|
-
# the id is a string right now..for some reason..
|
254
|
-
all_stats = json_response['stats'] || {}
|
255
|
-
servers.each do |it|
|
256
|
-
found_stats = all_stats[it['id'].to_s] || all_stats[it['id']]
|
257
|
-
if found_stats
|
258
|
-
if !it['stats']
|
259
|
-
it['stats'] = found_stats # || {}
|
260
|
-
else
|
261
|
-
it['stats'] = found_stats.merge!(it['stats'])
|
262
|
-
end
|
245
|
+
# print_servers_table(servers)
|
246
|
+
# server returns stats in a separate key stats => {"id" => {} }
|
247
|
+
# the id is a string right now..for some reason..
|
248
|
+
all_stats = json_response['stats'] || {}
|
249
|
+
servers.each do |it|
|
250
|
+
found_stats = all_stats[it['id'].to_s] || all_stats[it['id']]
|
251
|
+
if found_stats
|
252
|
+
if !it['stats']
|
253
|
+
it['stats'] = found_stats # || {}
|
254
|
+
else
|
255
|
+
it['stats'] = found_stats.merge!(it['stats'])
|
263
256
|
end
|
264
257
|
end
|
258
|
+
end
|
265
259
|
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
260
|
+
rows = servers.collect {|server|
|
261
|
+
stats = server['stats']
|
262
|
+
|
263
|
+
if !stats['maxMemory']
|
264
|
+
stats['maxMemory'] = stats['usedMemory'] + stats['freeMemory']
|
265
|
+
end
|
266
|
+
cpu_usage_str = !stats ? "" : generate_usage_bar((stats['usedCpu'] || stats['cpuUsage']).to_f, 100, {max_bars: 10})
|
267
|
+
memory_usage_str = !stats ? "" : generate_usage_bar(stats['usedMemory'], stats['maxMemory'], {max_bars: 10})
|
268
|
+
storage_usage_str = !stats ? "" : generate_usage_bar(stats['usedStorage'], stats['maxStorage'], {max_bars: 10})
|
269
|
+
if options[:details] || options[:stats]
|
270
|
+
if stats['maxMemory'] && stats['maxMemory'].to_i != 0
|
271
|
+
memory_usage_str = memory_usage_str + cyan + format_bytes_short(stats['usedMemory']).strip.rjust(8, ' ') + " / " + format_bytes_short(stats['maxMemory']).strip
|
271
272
|
end
|
272
|
-
|
273
|
-
|
274
|
-
storage_usage_str = !stats ? "" : generate_usage_bar(stats['usedStorage'], stats['maxStorage'], {max_bars: 10})
|
275
|
-
if options[:details] || options[:stats]
|
276
|
-
if stats['maxMemory'] && stats['maxMemory'].to_i != 0
|
277
|
-
memory_usage_str = memory_usage_str + cyan + format_bytes_short(stats['usedMemory']).strip.rjust(8, ' ') + " / " + format_bytes_short(stats['maxMemory']).strip
|
278
|
-
end
|
279
|
-
if stats['maxStorage'] && stats['maxStorage'].to_i != 0
|
280
|
-
storage_usage_str = storage_usage_str + cyan + format_bytes_short(stats['usedStorage']).strip.rjust(8, ' ') + " / " + format_bytes_short(stats['maxStorage']).strip
|
281
|
-
end
|
273
|
+
if stats['maxStorage'] && stats['maxStorage'].to_i != 0
|
274
|
+
storage_usage_str = storage_usage_str + cyan + format_bytes_short(stats['usedStorage']).strip.rjust(8, ' ') + " / " + format_bytes_short(stats['maxStorage']).strip
|
282
275
|
end
|
283
|
-
row = {
|
284
|
-
id: server['id'],
|
285
|
-
name: server['name'],
|
286
|
-
external_name: server['externalName'],
|
287
|
-
hostname: server['hostname'],
|
288
|
-
platform: server['serverOs'] ? server['serverOs']['name'].upcase : 'N/A',
|
289
|
-
type: server['computeServerType'] ? server['computeServerType']['name'] : 'unmanaged',
|
290
|
-
tenant: server['account'] ? server['account']['name'] : server['accountId'],
|
291
|
-
owner: server['owner'] ? server['owner']['username'] : server['owner'],
|
292
|
-
cloud: server['zone'] ? server['zone']['name'] : '',
|
293
|
-
plan: server['plan'] ? server['plan']['name'] : '',
|
294
|
-
ip: server['externalIp'],
|
295
|
-
internal_ip: server['internalIp'],
|
296
|
-
nodes: server['containers'] ? server['containers'].size : '',
|
297
|
-
# status: format_server_status(server, cyan),
|
298
|
-
status: (options[:details]||options[:all_fields]) ? format_server_status(server, cyan) : format_server_status_friendly(server, cyan),
|
299
|
-
power: format_server_power_state(server, cyan),
|
300
|
-
cpu: cpu_usage_str + cyan,
|
301
|
-
memory: memory_usage_str + cyan,
|
302
|
-
storage: storage_usage_str + cyan,
|
303
|
-
created: format_local_dt(server['dateCreated']),
|
304
|
-
updated: format_local_dt(server['lastUpdated']),
|
305
|
-
}
|
306
|
-
row
|
307
|
-
}
|
308
|
-
# columns = [:id, :name, :type, :cloud, :ip, :internal_ip, :nodes, :status, :power]
|
309
|
-
columns = {
|
310
|
-
"ID" => :id,
|
311
|
-
"Name" => :name,
|
312
|
-
"External Name" => :external_name,
|
313
|
-
"Hostname" => :hostname,
|
314
|
-
"Type" => :type,
|
315
|
-
"Owner" => :owner,
|
316
|
-
"Tenant" => :tenant,
|
317
|
-
"Cloud" => :cloud,
|
318
|
-
"Plan" => :plan,
|
319
|
-
"IP" => :ip,
|
320
|
-
"Private IP" => :internal_ip,
|
321
|
-
"Nodes" => :nodes,
|
322
|
-
"Status" => :status,
|
323
|
-
"Power" => :power,
|
324
|
-
"CPU" => :cpu,
|
325
|
-
"Memory" => :memory,
|
326
|
-
"Storage" => :storage,
|
327
|
-
"Created" => :created,
|
328
|
-
"Updated" => :updated,
|
329
|
-
}
|
330
|
-
if options[:details] != true
|
331
|
-
columns.delete("External Name")
|
332
|
-
columns.delete("Hostname")
|
333
|
-
columns.delete("Plan")
|
334
|
-
columns.delete("Private IP")
|
335
|
-
columns.delete("Owner")
|
336
|
-
columns.delete("Tenant")
|
337
|
-
columns.delete("Power")
|
338
|
-
columns.delete("Created")
|
339
|
-
columns.delete("Updated")
|
340
|
-
end
|
341
|
-
# hide External Name if there are none
|
342
|
-
if !servers.find {|it| it['externalName'] && it['externalName'] != it['name']}
|
343
|
-
columns.delete("External Name")
|
344
276
|
end
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
277
|
+
row = {
|
278
|
+
id: server['id'],
|
279
|
+
name: server['name'],
|
280
|
+
external_name: server['externalName'],
|
281
|
+
hostname: server['hostname'],
|
282
|
+
platform: server['serverOs'] ? server['serverOs']['name'].upcase : 'N/A',
|
283
|
+
type: server['computeServerType'] ? server['computeServerType']['name'] : 'unmanaged',
|
284
|
+
tenant: server['account'] ? server['account']['name'] : server['accountId'],
|
285
|
+
owner: server['owner'] ? server['owner']['username'] : server['owner'],
|
286
|
+
cloud: server['zone'] ? server['zone']['name'] : '',
|
287
|
+
plan: server['plan'] ? server['plan']['name'] : '',
|
288
|
+
ip: server['externalIp'],
|
289
|
+
internal_ip: server['internalIp'],
|
290
|
+
nodes: server['containers'] ? server['containers'].size : '',
|
291
|
+
# status: format_server_status(server, cyan),
|
292
|
+
status: (options[:details]||options[:all_fields]) ? format_server_status(server, cyan) : format_server_status_friendly(server, cyan),
|
293
|
+
power: format_server_power_state(server, cyan),
|
294
|
+
cpu: cpu_usage_str + cyan,
|
295
|
+
memory: memory_usage_str + cyan,
|
296
|
+
storage: storage_usage_str + cyan,
|
297
|
+
created: format_local_dt(server['dateCreated']),
|
298
|
+
updated: format_local_dt(server['lastUpdated']),
|
299
|
+
}
|
300
|
+
row
|
301
|
+
}
|
302
|
+
# columns = [:id, :name, :type, :cloud, :ip, :internal_ip, :nodes, :status, :power]
|
303
|
+
columns = {
|
304
|
+
"ID" => :id,
|
305
|
+
"Name" => :name,
|
306
|
+
"External Name" => :external_name,
|
307
|
+
"Hostname" => :hostname,
|
308
|
+
"Type" => :type,
|
309
|
+
"Owner" => :owner,
|
310
|
+
"Tenant" => :tenant,
|
311
|
+
"Cloud" => :cloud,
|
312
|
+
"Plan" => :plan,
|
313
|
+
"IP" => :ip,
|
314
|
+
"Private IP" => :internal_ip,
|
315
|
+
"Nodes" => :nodes,
|
316
|
+
"Status" => :status,
|
317
|
+
"Power" => :power,
|
318
|
+
"CPU" => :cpu,
|
319
|
+
"Memory" => :memory,
|
320
|
+
"Storage" => :storage,
|
321
|
+
"Created" => :created,
|
322
|
+
"Updated" => :updated,
|
323
|
+
}
|
324
|
+
if options[:details] != true
|
325
|
+
columns.delete("External Name")
|
326
|
+
columns.delete("Hostname")
|
327
|
+
columns.delete("Plan")
|
328
|
+
columns.delete("Private IP")
|
329
|
+
columns.delete("Owner")
|
330
|
+
columns.delete("Tenant")
|
331
|
+
columns.delete("Power")
|
332
|
+
columns.delete("Created")
|
333
|
+
columns.delete("Updated")
|
357
334
|
end
|
358
|
-
|
335
|
+
# hide External Name if there are none
|
336
|
+
if !servers.find {|it| it['externalName'] && it['externalName'] != it['name']}
|
337
|
+
columns.delete("External Name")
|
338
|
+
end
|
339
|
+
if !multi_tenant
|
340
|
+
columns.delete("Tenant")
|
341
|
+
end
|
342
|
+
# columns += [:cpu, :memory, :storage]
|
343
|
+
# # custom pretty table columns ...
|
344
|
+
# if options[:include_fields]
|
345
|
+
# columns = options[:include_fields]
|
346
|
+
# end
|
347
|
+
print cyan
|
348
|
+
print as_pretty_table(rows, columns.upcase_keys!, options)
|
349
|
+
print reset
|
350
|
+
print_results_pagination(json_response)
|
359
351
|
end
|
360
|
-
|
361
|
-
print_rest_exception(e, options)
|
362
|
-
exit 1
|
352
|
+
print reset,"\n"
|
363
353
|
end
|
354
|
+
return 0, nil
|
364
355
|
end
|
365
356
|
|
366
357
|
def count(args)
|
@@ -491,7 +482,7 @@ class Morpheus::Cli::Hosts
|
|
491
482
|
opts.on('--refresh-until STATUS', String, "Refresh until a specified status is reached.") do |val|
|
492
483
|
options[:refresh_until_status] = val.to_s.downcase
|
493
484
|
end
|
494
|
-
|
485
|
+
build_standard_get_options(opts, options)
|
495
486
|
end
|
496
487
|
optparse.parse!(args)
|
497
488
|
if args.count < 1
|
@@ -506,37 +497,24 @@ class Morpheus::Cli::Hosts
|
|
506
497
|
end
|
507
498
|
|
508
499
|
def _get(arg, options)
|
509
|
-
|
510
|
-
|
511
|
-
if options[:dry_run]
|
512
|
-
if arg.to_s =~ /\A\d{1,}\Z/
|
513
|
-
print_dry_run @servers_interface.dry.get(arg.to_i)
|
514
|
-
else
|
515
|
-
print_dry_run @servers_interface.dry.list({name: arg})
|
516
|
-
end
|
517
|
-
return
|
518
|
-
end
|
519
|
-
json_response = nil
|
500
|
+
@servers_interface.setopts(options)
|
501
|
+
if options[:dry_run]
|
520
502
|
if arg.to_s =~ /\A\d{1,}\Z/
|
521
|
-
|
503
|
+
print_dry_run @servers_interface.dry.get(arg.to_i)
|
522
504
|
else
|
523
|
-
|
524
|
-
json_response = @servers_interface.get(server['id'])
|
525
|
-
# json_response = {"server" => server} need stats
|
526
|
-
end
|
527
|
-
if options[:json]
|
528
|
-
json_response.delete('stats') if options[:include_fields]
|
529
|
-
puts as_json(json_response, options, "server")
|
530
|
-
return 0
|
531
|
-
elsif options[:yaml]
|
532
|
-
json_response.delete('stats') if options[:include_fields]
|
533
|
-
puts as_yaml(json_response, options, "server")
|
534
|
-
return 0
|
535
|
-
end
|
536
|
-
if options[:csv]
|
537
|
-
puts records_as_csv([json_response['server']], options)
|
538
|
-
return 0
|
505
|
+
print_dry_run @servers_interface.dry.list({name: arg})
|
539
506
|
end
|
507
|
+
return
|
508
|
+
end
|
509
|
+
json_response = nil
|
510
|
+
if arg.to_s =~ /\A\d{1,}\Z/
|
511
|
+
json_response = @servers_interface.get(arg.to_i)
|
512
|
+
else
|
513
|
+
server = find_host_by_name_or_id(arg)
|
514
|
+
json_response = @servers_interface.get(server['id'])
|
515
|
+
# json_response = {"server" => server} need stats
|
516
|
+
end
|
517
|
+
render_response(json_response, options, "server") do
|
540
518
|
server = json_response['server'] || json_response['host'] || {}
|
541
519
|
#stats = server['stats'] || json_response['stats'] || {}
|
542
520
|
stats = json_response['stats'] || {}
|
@@ -622,11 +600,8 @@ class Morpheus::Cli::Hosts
|
|
622
600
|
_get(arg, options)
|
623
601
|
end
|
624
602
|
end
|
625
|
-
|
626
|
-
rescue RestClient::Exception => e
|
627
|
-
print_rest_exception(e, options)
|
628
|
-
exit 1
|
629
603
|
end
|
604
|
+
return 0, nil
|
630
605
|
end
|
631
606
|
|
632
607
|
def stats(args)
|
@@ -781,7 +756,7 @@ class Morpheus::Cli::Hosts
|
|
781
756
|
opts.on( '-t', '--type TYPE', "Server Type Code" ) do |val|
|
782
757
|
options[:server_type_code] = val
|
783
758
|
end
|
784
|
-
opts.on("--security-groups LIST", Integer, "Security Groups, comma
|
759
|
+
opts.on("--security-groups LIST", Integer, "Security Groups, comma separated list of security group IDs") do |val|
|
785
760
|
options[:security_groups] = val.split(",").collect {|s| s.strip }.select {|s| !s.to_s.empty? }
|
786
761
|
end
|
787
762
|
opts.on('--refresh [SECONDS]', String, "Refresh until status is running,failed. Default interval is #{default_refresh_interval} seconds.") do |val|
|
@@ -842,7 +817,7 @@ class Morpheus::Cli::Hosts
|
|
842
817
|
cloud_type = cloud_type_for_id(cloud['zoneTypeId'])
|
843
818
|
|
844
819
|
# Server Type
|
845
|
-
cloud_server_types = cloud_type['serverTypes'].select{|b| b['creatable'] == true }.sort { |x,y| x['displayOrder'] <=> y['displayOrder'] }
|
820
|
+
cloud_server_types = cloud_type['serverTypes'].select{|b| b['creatable'] == true && b['containerHypervisor'] == false }.sort { |x,y| x['displayOrder'] <=> y['displayOrder'] }
|
846
821
|
if options[:server_type_code]
|
847
822
|
server_type_code = options[:server_type_code]
|
848
823
|
else
|
@@ -1982,6 +1957,10 @@ class Morpheus::Cli::Hosts
|
|
1982
1957
|
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
1983
1958
|
opts.banner = subcommand_usage("[host]")
|
1984
1959
|
build_standard_list_options(opts, options)
|
1960
|
+
opts.footer = <<-EOT
|
1961
|
+
List installed software for a host.
|
1962
|
+
[host] is required. This is the name or id of a host.
|
1963
|
+
EOT
|
1985
1964
|
end
|
1986
1965
|
optparse.parse!(args)
|
1987
1966
|
verify_args!(args:args, optparse:optparse, count:1)
|
@@ -2026,6 +2005,48 @@ class Morpheus::Cli::Hosts
|
|
2026
2005
|
end
|
2027
2006
|
end
|
2028
2007
|
|
2008
|
+
def software_sync(args)
|
2009
|
+
options = {}
|
2010
|
+
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
2011
|
+
opts.banner = subcommand_usage("[host]")
|
2012
|
+
build_standard_update_options(opts, options)
|
2013
|
+
opts.footer = <<-EOT
|
2014
|
+
Sync installed software for a host.
|
2015
|
+
[host] is required. This is the name or id of a host.
|
2016
|
+
EOT
|
2017
|
+
end
|
2018
|
+
optparse.parse!(args)
|
2019
|
+
verify_args!(args:args, optparse:optparse, count:1)
|
2020
|
+
connect(options)
|
2021
|
+
begin
|
2022
|
+
server = find_host_by_name_or_id(args[0])
|
2023
|
+
return 1 if server.nil?
|
2024
|
+
payload = {}
|
2025
|
+
if options[:payload]
|
2026
|
+
payload = options[:payload]
|
2027
|
+
payload.deep_merge!(parse_passed_options(options))
|
2028
|
+
else
|
2029
|
+
payload.deep_merge!(parse_passed_options(options))
|
2030
|
+
end
|
2031
|
+
params = {}
|
2032
|
+
params.merge!(parse_query_options(options))
|
2033
|
+
@servers_interface.setopts(options)
|
2034
|
+
if options[:dry_run]
|
2035
|
+
print_dry_run @servers_interface.dry.software_sync(server['id'], payload, params)
|
2036
|
+
return
|
2037
|
+
end
|
2038
|
+
json_response = @servers_interface.software_sync(server['id'], payload, params)
|
2039
|
+
render_response(json_response, options) do
|
2040
|
+
print_green_success "Syncing software for host #{server['name']}"
|
2041
|
+
#get([server['id']])
|
2042
|
+
end
|
2043
|
+
return 0
|
2044
|
+
rescue RestClient::Exception => e
|
2045
|
+
print_rest_exception(e, options)
|
2046
|
+
exit 1
|
2047
|
+
end
|
2048
|
+
end
|
2049
|
+
|
2029
2050
|
private
|
2030
2051
|
|
2031
2052
|
def find_host_by_id(id)
|