morpheus-cli 5.3.0.3 → 5.3.1
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.
- 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)
|