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.
Files changed (51) hide show
  1. checksums.yaml +4 -4
  2. data/Dockerfile +1 -1
  3. data/README.md +1 -3
  4. data/lib/morpheus/api/api_client.rb +48 -14
  5. data/lib/morpheus/api/certificate_types_interface.rb +14 -0
  6. data/lib/morpheus/api/certificates_interface.rb +9 -0
  7. data/lib/morpheus/api/integration_types_interface.rb +14 -0
  8. data/lib/morpheus/api/integrations_interface.rb +7 -22
  9. data/lib/morpheus/api/network_services_interface.rb +14 -0
  10. data/lib/morpheus/api/read_interface.rb +23 -0
  11. data/lib/morpheus/api/rest_interface.rb +12 -10
  12. data/lib/morpheus/api/roles_interface.rb +7 -0
  13. data/lib/morpheus/api/servers_interface.rb +7 -0
  14. data/lib/morpheus/api/user_settings_interface.rb +38 -18
  15. data/lib/morpheus/api/vdi_allocations_interface.rb +9 -0
  16. data/lib/morpheus/api/vdi_apps_interface.rb +9 -0
  17. data/lib/morpheus/api/vdi_gateways_interface.rb +9 -0
  18. data/lib/morpheus/api/vdi_interface.rb +28 -0
  19. data/lib/morpheus/api/vdi_pools_interface.rb +19 -0
  20. data/lib/morpheus/cli.rb +9 -2
  21. data/lib/morpheus/cli/apps.rb +59 -75
  22. data/lib/morpheus/cli/catalog_item_types_command.rb +13 -13
  23. data/lib/morpheus/cli/certificates_command.rb +575 -0
  24. data/lib/morpheus/cli/cli_command.rb +61 -6
  25. data/lib/morpheus/cli/clouds.rb +1 -0
  26. data/lib/morpheus/cli/clusters.rb +1 -1
  27. data/lib/morpheus/cli/commands/standard/man_command.rb +4 -5
  28. data/lib/morpheus/cli/hosts.rb +245 -224
  29. data/lib/morpheus/cli/instances.rb +150 -167
  30. data/lib/morpheus/cli/integrations_command.rb +588 -41
  31. data/lib/morpheus/cli/login.rb +7 -0
  32. data/lib/morpheus/cli/mixins/print_helper.rb +33 -18
  33. data/lib/morpheus/cli/mixins/provisioning_helper.rb +3 -3
  34. data/lib/morpheus/cli/mixins/vdi_helper.rb +246 -0
  35. data/lib/morpheus/cli/network_routers_command.rb +22 -9
  36. data/lib/morpheus/cli/networks_command.rb +2 -2
  37. data/lib/morpheus/cli/option_types.rb +34 -33
  38. data/lib/morpheus/cli/remote.rb +1 -1
  39. data/lib/morpheus/cli/reports_command.rb +4 -1
  40. data/lib/morpheus/cli/roles.rb +215 -55
  41. data/lib/morpheus/cli/subnets_command.rb +11 -2
  42. data/lib/morpheus/cli/user_settings_command.rb +268 -57
  43. data/lib/morpheus/cli/vdi_allocations_command.rb +159 -0
  44. data/lib/morpheus/cli/vdi_apps_command.rb +317 -0
  45. data/lib/morpheus/cli/vdi_command.rb +359 -0
  46. data/lib/morpheus/cli/vdi_gateways_command.rb +290 -0
  47. data/lib/morpheus/cli/vdi_pools_command.rb +571 -0
  48. data/lib/morpheus/cli/version.rb +1 -1
  49. data/lib/morpheus/rest_client.rb +30 -0
  50. data/lib/morpheus/terminal.rb +15 -7
  51. metadata +18 -2
@@ -0,0 +1,159 @@
1
+ require 'morpheus/cli/cli_command'
2
+
3
+ # CLI command VDI Allocation management
4
+ # UI is Tools: VDI Allocations
5
+ # API is /vdi-allocations and returns vdiAllocations
6
+ class Morpheus::Cli::VdiAllocationsCommand
7
+ include Morpheus::Cli::CliCommand
8
+ include Morpheus::Cli::VdiHelper
9
+ include Morpheus::Cli::OptionSourceHelper
10
+
11
+ set_command_name :'vdi-allocations'
12
+ set_command_description "View VDI allocations"
13
+
14
+ register_subcommands :list, :get
15
+
16
+ def connect(opts)
17
+ @api_client = establish_remote_appliance_connection(opts)
18
+ @vdi_pools_interface = @api_client.vdi_pools
19
+ @vdi_allocations_interface = @api_client.vdi_allocations
20
+ @option_types_interface = @api_client.option_types
21
+ end
22
+
23
+ def handle(args)
24
+ handle_subcommand(args)
25
+ end
26
+
27
+ def list(args)
28
+ options = {}
29
+ params = {}
30
+ ref_ids = []
31
+ optparse = Morpheus::Cli::OptionParser.new do |opts|
32
+ opts.banner = subcommand_usage("[search]")
33
+ build_standard_list_options(opts, options)
34
+ opts.on('--id ID', String, "Filter by VDI Allocation ID" ) do |val|
35
+ params['id'] = parse_id_list(val)
36
+ end
37
+ opts.on('--status STATUS', String, "Filter by VDI Allocation Status" ) do |val|
38
+ params['status'] = parse_id_list(val)
39
+ end
40
+ opts.on('--pool POOL', String, "Filter by VDI Pool Name or ID" ) do |val|
41
+ options[:pool] = val
42
+ end
43
+ opts.on('-u', '--user USER', "Filter by User Username or ID" ) do |val|
44
+ options[:user] = val
45
+ end
46
+ opts.footer = "List VDI allocations."
47
+ end
48
+ optparse.parse!(args)
49
+ connect(options)
50
+ if args.count > 0
51
+ options[:phrase] = args.join(" ")
52
+ end
53
+ params.merge!(parse_list_options(options))
54
+ # --id
55
+ if options[:pool]
56
+ pool_ids = parse_id_list(options[:pool]).collect { |it|
57
+ vdi_pool = find_vdi_pool_by_name_or_id(it)
58
+ vdi_pool ? vdi_pool['id'] : nil
59
+ }
60
+ return 1 if pool_ids.include?(nil)
61
+ params['poolId'] = pool_ids
62
+ end
63
+ # --pool
64
+ if options[:pool]
65
+ pool_ids = parse_id_list(options[:pool]).collect { |it|
66
+ vdi_pool = find_vdi_pool_by_name_or_id(it)
67
+ vdi_pool ? vdi_pool['id'] : nil
68
+ }
69
+ return 1 if pool_ids.include?(nil)
70
+ params['poolId'] = pool_ids
71
+ end
72
+ # --user
73
+ if options[:user]
74
+ user_ids = parse_user_id_list(options[:user])
75
+ return 1 if user_ids.nil?
76
+ params['userId'] = user_ids
77
+ end
78
+ @vdi_allocations_interface.setopts(options)
79
+ if options[:dry_run]
80
+ print_dry_run @vdi_allocations_interface.dry.list(params)
81
+ return
82
+ end
83
+ json_response = @vdi_allocations_interface.list(params)
84
+ render_response(json_response, options, vdi_allocation_list_key) do
85
+ vdi_allocations = json_response[vdi_allocation_list_key]
86
+ print_h1 "Morpheus VDI Allocations", parse_list_subtitles(options), options
87
+ if vdi_allocations.empty?
88
+ print cyan,"No VDI allocations found.",reset,"\n"
89
+ else
90
+ list_columns = vdi_allocation_column_definitions.upcase_keys!
91
+ print as_pretty_table(vdi_allocations, list_columns, options)
92
+ print_results_pagination(json_response)
93
+ end
94
+ print reset,"\n"
95
+ end
96
+ return 0, nil
97
+ end
98
+
99
+ def get(args)
100
+ params = {}
101
+ options = {}
102
+ optparse = Morpheus::Cli::OptionParser.new do |opts|
103
+ opts.banner = subcommand_usage("[allocation]")
104
+ build_standard_get_options(opts, options)
105
+ opts.footer = <<-EOT
106
+ Get details about a specific VDI allocation.
107
+ [allocation] is required. This is the id of a VDI allocation.
108
+ EOT
109
+ end
110
+ optparse.parse!(args)
111
+ verify_args!(args:args, optparse:optparse, min:1)
112
+ connect(options)
113
+ params.merge!(parse_query_options(options))
114
+ id_list = parse_id_list(args)
115
+ return run_command_for_each_arg(id_list) do |arg|
116
+ _get(arg, params, options)
117
+ end
118
+ end
119
+
120
+ def _get(id, params, options)
121
+ @vdi_allocations_interface.setopts(options)
122
+ if options[:dry_run]
123
+ print_dry_run @vdi_allocations_interface.dry.get(id, params)
124
+ return
125
+ end
126
+ json_response = @vdi_allocations_interface.get(id, params)
127
+ vdi_allocation = json_response[vdi_allocation_object_key]
128
+ render_response(json_response, options, vdi_allocation_object_key) do
129
+ print_h1 "VDI Allocation Details", [], options
130
+ print cyan
131
+ show_columns = vdi_allocation_column_definitions
132
+ print_description_list(show_columns, vdi_allocation)
133
+ print reset,"\n"
134
+ end
135
+ return 0, nil
136
+ end
137
+
138
+ private
139
+
140
+ def vdi_allocation_column_definitions()
141
+ {
142
+ "ID" => lambda {|it| it['id'] },
143
+ "Pool" => lambda {|it| it['pool'] ? it['pool']['name'] : nil },
144
+ "Instance" => lambda {|it| it['instance'] ? it['instance']['name'] : nil },
145
+ "User" => lambda {|it| it['user'] ? it['user']['username'] : nil },
146
+ "Status" => lambda {|it| format_vdi_allocation_status(it) },
147
+ "Created" => lambda {|it| format_local_dt it['dateCreated'] },
148
+ "Last Reserved" => lambda {|it| format_local_dt it['lastReserved'] },
149
+ "Release Date" => lambda {|it| format_local_dt it['releaseDate'] }
150
+ }
151
+ end
152
+
153
+ def vdi_allocation_list_column_definitions()
154
+ vdi_allocation_column_definitions()
155
+ end
156
+
157
+ # finders are in VdiHelper mixin
158
+
159
+ end
@@ -0,0 +1,317 @@
1
+ require 'morpheus/cli/cli_command'
2
+
3
+ # CLI command VDI App management
4
+ # UI is Tools: VDI Apps
5
+ # API is /vdi-apps and returns vdiApps
6
+ class Morpheus::Cli::VdiAppsCommand
7
+ include Morpheus::Cli::CliCommand
8
+ include Morpheus::Cli::VdiHelper
9
+ include Morpheus::Cli::OptionSourceHelper
10
+
11
+ set_command_name :'vdi-apps'
12
+ set_command_description "View and manage VDI apps"
13
+
14
+ register_subcommands :list, :get, :add, :update, :remove
15
+
16
+ def connect(opts)
17
+ @api_client = establish_remote_appliance_connection(opts)
18
+ @vdi_apps_interface = @api_client.vdi_apps
19
+ @vdi_apps_interface = @api_client.vdi_apps
20
+ @vdi_apps_interface = @api_client.vdi_apps
21
+ @option_types_interface = @api_client.option_types
22
+ end
23
+
24
+ def handle(args)
25
+ handle_subcommand(args)
26
+ end
27
+
28
+ def list(args)
29
+ options = {}
30
+ params = {}
31
+ ref_ids = []
32
+ optparse = Morpheus::Cli::OptionParser.new do |opts|
33
+ opts.banner = subcommand_usage("[search]")
34
+ build_standard_list_options(opts, options)
35
+ opts.footer = "List VDI apps."
36
+ end
37
+ optparse.parse!(args)
38
+ connect(options)
39
+ if args.count > 0
40
+ options[:phrase] = args.join(" ")
41
+ end
42
+ params.merge!(parse_list_options(options))
43
+ @vdi_apps_interface.setopts(options)
44
+ if options[:dry_run]
45
+ print_dry_run @vdi_apps_interface.dry.list(params)
46
+ return
47
+ end
48
+ json_response = @vdi_apps_interface.list(params)
49
+ render_response(json_response, options, vdi_app_list_key) do
50
+ vdi_apps = json_response[vdi_app_list_key]
51
+ print_h1 "Morpheus VDI Apps", parse_list_subtitles(options), options
52
+ if vdi_apps.empty?
53
+ print cyan,"No VDI apps found.",reset,"\n"
54
+ else
55
+ print as_pretty_table(vdi_apps, vdi_app_list_column_definitions.upcase_keys!, options)
56
+ print_results_pagination(json_response)
57
+ end
58
+ print reset,"\n"
59
+ end
60
+ return 0, nil
61
+ end
62
+
63
+ def get(args)
64
+ params = {}
65
+ options = {}
66
+ optparse = Morpheus::Cli::OptionParser.new do |opts|
67
+ opts.banner = subcommand_usage("[app]")
68
+ build_standard_get_options(opts, options)
69
+ opts.footer = <<-EOT
70
+ Get details about a specific VDI app.
71
+ [app] is required. This is the name or id of a VDI app.
72
+ EOT
73
+ end
74
+ optparse.parse!(args)
75
+ verify_args!(args:args, optparse:optparse, min:1)
76
+ connect(options)
77
+ params.merge!(parse_query_options(options))
78
+ id_list = parse_id_list(args)
79
+ return run_command_for_each_arg(id_list) do |arg|
80
+ _get(arg, params, options)
81
+ end
82
+ end
83
+
84
+ def _get(id, params, options)
85
+ vdi_app = nil
86
+ if id.to_s !~ /\A\d{1,}\Z/
87
+ vdi_app = find_vdi_app_by_name(id)
88
+ return 1, "VDI app not found for #{id}" if vdi_app.nil?
89
+ id = vdi_app['id']
90
+ end
91
+ @vdi_apps_interface.setopts(options)
92
+ if options[:dry_run]
93
+ print_dry_run @vdi_apps_interface.dry.get(id, params)
94
+ return
95
+ end
96
+ json_response = @vdi_apps_interface.get(id, params)
97
+ vdi_app = json_response[vdi_app_object_key]
98
+ config = vdi_app['config'] || {}
99
+ # export just the config as json or yaml (default)
100
+ if options[:show_config]
101
+ unless options[:json] || options[:yaml] || options[:csv]
102
+ options[:yaml] = true
103
+ end
104
+ return render_with_format(config, options)
105
+ end
106
+ render_response(json_response, options, vdi_app_object_key) do
107
+ print_h1 "VDI App Details", [], options
108
+ print cyan
109
+ show_columns = vdi_app_column_definitions
110
+ show_columns.delete("VDI Apps") unless vdi_app['apps']
111
+ show_columns.delete("VDI App") unless vdi_app['app']
112
+ show_columns.delete("Guest Console Jump Host") unless vdi_app['guestConsoleJumpHost']
113
+ show_columns.delete("Guest Console Jump Port") unless vdi_app['guestConsoleJumpPort']
114
+ show_columns.delete("Guest Console Jump Username") unless vdi_app['guestConsoleJumpUsername']
115
+ show_columns.delete("Guest Console Jump Password") unless vdi_app['guestConsoleJumpPassword']
116
+ show_columns.delete("Guest Console Jump Keypair") unless vdi_app['guestConsoleJumpKeypair']
117
+ print_description_list(show_columns, vdi_app)
118
+
119
+
120
+ print reset,"\n"
121
+ end
122
+ return 0, nil
123
+ end
124
+
125
+ def add(args)
126
+ options = {}
127
+ params = {}
128
+ optparse = Morpheus::Cli::OptionParser.new do |opts|
129
+ opts.banner = subcommand_usage("[name] [options]")
130
+ build_option_type_options(opts, options, add_vdi_app_option_types)
131
+ build_standard_add_options(opts, options)
132
+ opts.footer = <<-EOT
133
+ Create a new VDI app.
134
+ EOT
135
+ end
136
+ optparse.parse!(args)
137
+ verify_args!(args:args, optparse:optparse, min:0, max:1)
138
+ options[:options]['name'] = args[0] if args[0]
139
+ if options[:options]['logo']
140
+ options[:options]['iconPath'] = 'custom'
141
+ end
142
+ connect(options)
143
+ payload = {}
144
+ if options[:payload]
145
+ payload = options[:payload]
146
+ payload.deep_merge!({vdi_app_object_key => parse_passed_options(options)})
147
+ else
148
+ payload.deep_merge!({vdi_app_object_key => parse_passed_options(options)})
149
+ v_prompt = Morpheus::Cli::OptionTypes.prompt(add_vdi_app_option_types, options[:options], @api_client, options[:params])
150
+ params.deep_merge!(v_prompt)
151
+ params.booleanize!
152
+ # logo upload requires multipart instead of json
153
+ if params['logo']
154
+ params['logo'] = File.new(File.expand_path(params['logo']), 'rb')
155
+ payload[:multipart] = true
156
+ end
157
+ payload[vdi_app_object_key].deep_merge!(params)
158
+ end
159
+ @vdi_apps_interface.setopts(options)
160
+ if options[:dry_run]
161
+ print_dry_run @vdi_apps_interface.dry.create(payload)
162
+ return 0, nil
163
+ end
164
+ json_response = @vdi_apps_interface.create(payload)
165
+ vdi_app = json_response[vdi_app_object_key]
166
+ render_response(json_response, options, vdi_app_object_key) do
167
+ print_green_success "Added VDI app #{vdi_app['name']}"
168
+ return _get(vdi_app["id"], {}, options)
169
+ end
170
+ return 0, nil
171
+ end
172
+
173
+ def update(args)
174
+ options = {}
175
+ params = {}
176
+ payload = {}
177
+ optparse = Morpheus::Cli::OptionParser.new do |opts|
178
+ opts.banner = subcommand_usage("[app] [options]")
179
+ build_option_type_options(opts, options, update_vdi_app_option_types)
180
+ build_standard_update_options(opts, options)
181
+ opts.footer = <<-EOT
182
+ Update a VDI app.
183
+ [app] is required. This is the name or id of a VDI app.
184
+ EOT
185
+ end
186
+ optparse.parse!(args)
187
+ verify_args!(args:args, optparse:optparse, count:1)
188
+ if options[:options]['logo']
189
+ options[:options]['iconPath'] = 'custom'
190
+ end
191
+ connect(options)
192
+ vdi_app = find_vdi_app_by_name_or_id(args[0])
193
+ return 1 if vdi_app.nil?
194
+ payload = {}
195
+ if options[:payload]
196
+ payload = options[:payload]
197
+ payload.deep_merge!({vdi_app_object_key => parse_passed_options(options)})
198
+ else
199
+ payload.deep_merge!({vdi_app_object_key => parse_passed_options(options)})
200
+ v_prompt = Morpheus::Cli::OptionTypes.no_prompt(update_vdi_app_option_types, options[:options], @api_client, options[:params])
201
+ v_prompt.deep_compact!
202
+ params.deep_merge!(v_prompt)
203
+ params.booleanize!
204
+ # logo upload requires multipart instead of json
205
+ if params['logo']
206
+ params['logo'] = File.new(File.expand_path(params['logo']), 'rb')
207
+ payload[:multipart] = true
208
+ end
209
+ payload.deep_merge!({vdi_app_object_key => params})
210
+ if payload[vdi_app_object_key].empty? # || options[:no_prompt]
211
+ raise_command_error "Specify at least one option to update.\n#{optparse}"
212
+ end
213
+ end
214
+ @vdi_apps_interface.setopts(options)
215
+ if options[:dry_run]
216
+ print_dry_run @vdi_apps_interface.dry.update(vdi_app['id'], payload)
217
+ return
218
+ end
219
+ json_response = @vdi_apps_interface.update(vdi_app['id'], payload)
220
+ vdi_app = json_response[vdi_app_object_key]
221
+ render_response(json_response, options, vdi_app_object_key) do
222
+ print_green_success "Updated VDI app #{vdi_app['name']}"
223
+ return _get(vdi_app["id"], {}, options)
224
+ end
225
+ return 0, nil
226
+ end
227
+
228
+ def remove(args)
229
+ options = {}
230
+ params = {}
231
+ optparse = Morpheus::Cli::OptionParser.new do |opts|
232
+ opts.banner = subcommand_usage("[app] [options]")
233
+ build_standard_remove_options(opts, options)
234
+ opts.footer = <<-EOT
235
+ Delete a VDI app.
236
+ [app] is required. This is the name or id of a VDI app.
237
+ EOT
238
+ end
239
+ optparse.parse!(args)
240
+ verify_args!(args:args, optparse:optparse, count:1)
241
+ connect(options)
242
+ vdi_app = find_vdi_app_by_name_or_id(args[0])
243
+ return 1 if vdi_app.nil?
244
+ @vdi_apps_interface.setopts(options)
245
+ if options[:dry_run]
246
+ print_dry_run @vdi_apps_interface.dry.destroy(vdi_app['id'], params)
247
+ return
248
+ end
249
+ unless options[:yes] || Morpheus::Cli::OptionTypes.confirm("Are you sure you want to delete the VDI app #{vdi_app['name']}?")
250
+ return 9, "aborted command"
251
+ end
252
+ json_response = @vdi_apps_interface.destroy(vdi_app['id'], params)
253
+ render_response(json_response, options) do
254
+ print_green_success "Removed VDI app #{vdi_app['name']}"
255
+ end
256
+ return 0, nil
257
+ end
258
+
259
+ private
260
+
261
+ def vdi_app_list_column_definitions()
262
+
263
+ {
264
+ "ID" => 'id',
265
+ "Name" => 'name',
266
+ # "Description" => 'description',
267
+ "Launch Prefix" => 'launchPrefix',
268
+ # "Logo" => 'logo',
269
+ # "Created" => lambda {|it| format_local_dt(it['dateCreated']) },
270
+ # "Updated" => lambda {|it| format_local_dt(it['lastUpdated']) },
271
+ }
272
+ end
273
+
274
+ def vdi_app_column_definitions()
275
+ {
276
+ "ID" => 'id',
277
+ "Name" => 'name',
278
+ "Description" => 'description',
279
+ "Launch Prefix" => 'launchPrefix',
280
+ "Logo" => 'logo',
281
+ "Created" => lambda {|it| format_local_dt(it['dateCreated']) },
282
+ "Updated" => lambda {|it| format_local_dt(it['lastUpdated']) },
283
+ }
284
+ end
285
+
286
+ def add_vdi_app_option_types
287
+ [
288
+ {'fieldName' => 'name', 'fieldLabel' => 'Name', 'type' => 'text', 'required' => true, 'description' => 'Choose a unique name for the VDI App'},
289
+ {'fieldName' => 'description', 'fieldLabel' => 'Description', 'type' => 'text', 'description' => 'Description'},
290
+ {'fieldName' => 'launchPrefix', 'fieldLabel' => 'Launch Prefix', 'type' => 'text', 'required' => true, 'description' => 'The RDS App Name Prefix. Note: Must start with || (i.e. ||notepad) to launch notepad'},
291
+ #{'code' => 'vdiApp.iconPath', 'fieldName' => 'iconPath', 'fieldLabel' => 'Logo', 'type' => 'select', 'optionSource' => 'iconList', 'defaultValue' => 'resource'},
292
+ # iconList does not include custom, so add it ourselves..
293
+ # only prompt for logo file if custom
294
+ {'code' => 'vdiApp.iconPath', 'fieldName' => 'iconPath', 'fieldLabel' => 'Logo', 'type' => 'select', 'optionSource' => lambda { |api_client, api_params|
295
+ dropdown = api_client.options.options_for_source("iconList")['data']
296
+ if !dropdown.find {|it| it['value'] == 'custom'}
297
+ dropdown.push({'name' => 'Custom', 'value' => 'custom'})
298
+ end
299
+ dropdown
300
+ }, 'description' => 'Logo icon path or custom if uploading a custom logo', 'defaultValue' => 'resource'},
301
+ {'dependsOnCode' => 'vdiApp.iconPath:custom', 'fieldName' => 'logo', 'fieldLabel' => 'Logo File', 'type' => 'file', 'required' => true, 'description' => 'Local filepath of image file to upload as custom icon'},
302
+ ]
303
+ end
304
+
305
+ def update_vdi_app_option_types
306
+ list = add_vdi_app_option_types.collect {|it|
307
+ it.delete('required')
308
+ it.delete('defaultValue')
309
+ it
310
+ }
311
+ list = list.reject {|it| ["type"].include? it['fieldName'] }
312
+ list
313
+ end
314
+
315
+ # finders are in VdiHelper mixin
316
+
317
+ end