morpheus-cli 5.4.0 → 5.4.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 (92) hide show
  1. checksums.yaml +4 -4
  2. data/Dockerfile +1 -1
  3. data/lib/morpheus/api/account_users_interface.rb +68 -0
  4. data/lib/morpheus/api/api_client.rb +55 -10
  5. data/lib/morpheus/api/audit_interface.rb +9 -0
  6. data/lib/morpheus/api/catalog_item_types_interface.rb +20 -0
  7. data/lib/morpheus/api/instances_interface.rb +49 -0
  8. data/lib/morpheus/api/load_balancer_monitors_interface.rb +9 -0
  9. data/lib/morpheus/api/load_balancer_pools_interface.rb +4 -4
  10. data/lib/morpheus/api/load_balancer_profiles_interface.rb +4 -5
  11. data/lib/morpheus/api/load_balancer_virtual_servers_interface.rb +13 -4
  12. data/lib/morpheus/api/load_balancers_interface.rb +5 -0
  13. data/lib/morpheus/api/network_routers_interface.rb +9 -0
  14. data/lib/morpheus/api/network_static_routes_interface.rb +36 -0
  15. data/lib/morpheus/api/ping_interface.rb +2 -0
  16. data/lib/morpheus/api/read_interface.rb +4 -3
  17. data/lib/morpheus/api/rest_interface.rb +3 -3
  18. data/lib/morpheus/api/secondary_read_interface.rb +1 -1
  19. data/lib/morpheus/api/secondary_rest_interface.rb +19 -19
  20. data/lib/morpheus/api/setup_interface.rb +4 -0
  21. data/lib/morpheus/api/snapshots_interface.rb +19 -0
  22. data/lib/morpheus/api/storage_server_types_interface.rb +14 -0
  23. data/lib/morpheus/api/storage_servers_interface.rb +9 -0
  24. data/lib/morpheus/api/storage_volume_types_interface.rb +9 -0
  25. data/lib/morpheus/api/storage_volumes_interface.rb +9 -0
  26. data/lib/morpheus/api/users_interface.rb +16 -63
  27. data/lib/morpheus/cli/cli_command.rb +253 -5
  28. data/lib/morpheus/cli/cli_registry.rb +1 -1
  29. data/lib/morpheus/cli/commands/alias_command.rb +1 -1
  30. data/lib/morpheus/cli/commands/apps.rb +14 -78
  31. data/lib/morpheus/cli/commands/audit.rb +188 -0
  32. data/lib/morpheus/cli/commands/blueprints_command.rb +1 -1
  33. data/lib/morpheus/cli/commands/catalog_item_types_command.rb +88 -0
  34. data/lib/morpheus/cli/commands/change_password_command.rb +4 -4
  35. data/lib/morpheus/cli/commands/clusters.rb +96 -58
  36. data/lib/morpheus/cli/commands/hosts.rb +27 -15
  37. data/lib/morpheus/cli/commands/image_builder_command.rb +4 -8
  38. data/lib/morpheus/cli/commands/instances.rb +359 -3
  39. data/lib/morpheus/cli/commands/integrations_command.rb +1 -12
  40. data/lib/morpheus/cli/commands/library_instance_types_command.rb +3 -0
  41. data/lib/morpheus/cli/commands/load_balancer_monitors.rb +70 -0
  42. data/lib/morpheus/cli/commands/load_balancer_pools.rb +29 -50
  43. data/lib/morpheus/cli/commands/load_balancer_profiles.rb +64 -0
  44. data/lib/morpheus/cli/commands/load_balancer_types.rb +9 -4
  45. data/lib/morpheus/cli/commands/load_balancer_virtual_servers.rb +69 -58
  46. data/lib/morpheus/cli/commands/load_balancers.rb +109 -6
  47. data/lib/morpheus/cli/commands/network_firewalls_command.rb +22 -5
  48. data/lib/morpheus/cli/commands/network_routers_command.rb +96 -45
  49. data/lib/morpheus/cli/commands/network_static_routes_command.rb +451 -0
  50. data/lib/morpheus/cli/commands/network_transport_zones_command.rb +4 -4
  51. data/lib/morpheus/cli/commands/networks_command.rb +2 -2
  52. data/lib/morpheus/cli/commands/open_command.rb +30 -0
  53. data/lib/morpheus/cli/commands/options.rb +98 -0
  54. data/lib/morpheus/cli/commands/ping.rb +3 -5
  55. data/lib/morpheus/cli/commands/policies_command.rb +2 -2
  56. data/lib/morpheus/cli/commands/prices_command.rb +7 -7
  57. data/lib/morpheus/cli/commands/provisioning_settings_command.rb +1 -0
  58. data/lib/morpheus/cli/commands/remote.rb +20 -12
  59. data/lib/morpheus/cli/commands/roles.rb +1 -1
  60. data/lib/morpheus/cli/commands/security_groups.rb +2 -2
  61. data/lib/morpheus/cli/commands/service_plans_command.rb +1 -1
  62. data/lib/morpheus/cli/commands/setup.rb +1 -1
  63. data/lib/morpheus/cli/commands/shell.rb +2 -2
  64. data/lib/morpheus/cli/commands/snapshots.rb +139 -0
  65. data/lib/morpheus/cli/commands/storage_server_types.rb +50 -0
  66. data/lib/morpheus/cli/commands/storage_servers.rb +122 -0
  67. data/lib/morpheus/cli/commands/storage_volume_types.rb +50 -0
  68. data/lib/morpheus/cli/commands/storage_volumes.rb +103 -0
  69. data/lib/morpheus/cli/commands/tasks.rb +5 -5
  70. data/lib/morpheus/cli/commands/tenants_command.rb +1 -1
  71. data/lib/morpheus/cli/commands/user_groups_command.rb +1 -1
  72. data/lib/morpheus/cli/commands/user_settings_command.rb +3 -2
  73. data/lib/morpheus/cli/commands/user_sources_command.rb +1 -1
  74. data/lib/morpheus/cli/commands/users.rb +28 -28
  75. data/lib/morpheus/cli/commands/view.rb +102 -0
  76. data/lib/morpheus/cli/commands/virtual_images.rb +4 -1
  77. data/lib/morpheus/cli/mixins/accounts_helper.rb +5 -5
  78. data/lib/morpheus/cli/mixins/load_balancers_helper.rb +24 -4
  79. data/lib/morpheus/cli/mixins/print_helper.rb +50 -18
  80. data/lib/morpheus/cli/mixins/processes_helper.rb +1 -2
  81. data/lib/morpheus/cli/mixins/provisioning_helper.rb +96 -6
  82. data/lib/morpheus/cli/mixins/rest_command.rb +148 -74
  83. data/lib/morpheus/cli/mixins/secondary_rest_command.rb +174 -82
  84. data/lib/morpheus/cli/mixins/storage_servers_helper.rb +156 -0
  85. data/lib/morpheus/cli/mixins/storage_volumes_helper.rb +119 -0
  86. data/lib/morpheus/cli/option_types.rb +95 -28
  87. data/lib/morpheus/cli/version.rb +1 -1
  88. data/lib/morpheus/cli.rb +1 -0
  89. data/lib/morpheus/ext/string.rb +29 -6
  90. data/lib/morpheus/routes.rb +238 -0
  91. data/lib/morpheus/util.rb +6 -1
  92. metadata +26 -2
@@ -0,0 +1,122 @@
1
+ require 'morpheus/cli/cli_command'
2
+
3
+ class Morpheus::Cli::StorageServers
4
+ include Morpheus::Cli::CliCommand
5
+ include Morpheus::Cli::RestCommand
6
+ include Morpheus::Cli::StorageServersHelper
7
+
8
+ set_command_name :'storage-servers'
9
+ set_command_description "View and manage storage servers."
10
+ register_subcommands :list, :get, :add, :update, :remove
11
+
12
+ # RestCommand settings
13
+ register_interfaces :storage_servers, :storage_server_types
14
+ set_rest_has_type true
15
+ # set_rest_type :storage_server_types
16
+
17
+ def render_response_for_get(json_response, options)
18
+ render_response(json_response, options, rest_object_key) do
19
+ record = json_response[rest_object_key]
20
+ print_h1 rest_label, [], options
21
+ print cyan
22
+ print_description_list(rest_column_definitions(options), record, options)
23
+ # show Storage Server Configuration
24
+ config = record['config']
25
+ if config && !config.empty?
26
+ print_h2 "Configuration"
27
+ print_description_list(config.keys, config)
28
+ end
29
+ print reset,"\n"
30
+ end
31
+ end
32
+
33
+ protected
34
+
35
+ def storage_server_list_column_definitions(options)
36
+ {
37
+ "ID" => 'id',
38
+ "Name" => 'name',
39
+ "Type" => lambda {|it| it['type'] ? it['type']['name'] : '' },
40
+ "Service URL" => lambda {|it| it['serviceUrl'] },
41
+ "Tenants" => lambda {|it|
42
+ if it['tenants'] && !it['tenants'].empty?
43
+ it['tenants'].collect {|account| account['name'] }.join(', ')
44
+ else
45
+ it['owner'] ? it['owner']['name'] : (it['account'] ? it['account']['name'] : nil)
46
+ end
47
+ },
48
+ "Status" => lambda {|it| format_storage_server_status(it) },
49
+ }
50
+ end
51
+
52
+ def storage_server_column_definitions(options)
53
+ {
54
+ "ID" => 'id',
55
+ "Name" => 'name',
56
+ "Description" => 'description',
57
+ "Type" => lambda {|it| it['type'] ? it['type']['name'] : '' },
58
+ "Service URL" => lambda {|it| it['serviceUrl'] },
59
+ "Service Username" => lambda {|it| it['serviceUsername'] },
60
+ "Tenants" => lambda {|it| it['tenants'].collect {|account| account['name'] }.join(', ') },
61
+ "Owner" => lambda {|it| it['owner'] ? it['owner']['name'] : (it['account'] ? it['account']['name'] : nil) },
62
+ "Enabled" => lambda {|it| format_boolean(it['enabled']) },
63
+ "Status" => lambda {|it| format_storage_server_status(it) },
64
+ "Created" => lambda {|it| format_local_dt(it['dateCreated']) },
65
+ "Updated" => lambda {|it| format_local_dt(it['lastUpdated']) }
66
+ }
67
+ end
68
+
69
+ # overridden to work with name or code
70
+ # nope, api works with name=code now too
71
+ # def find_storage_server_type_by_name_or_id(name)
72
+ # storage_server_type_for_name_or_id(name)
73
+ # end
74
+
75
+ def add_storage_server_option_types()
76
+ [
77
+ {'fieldName' => 'name', 'fieldLabel' => 'Name', 'type' => 'text', 'required' => true},
78
+ {'fieldName' => 'description', 'fieldLabel' => 'Description', 'type' => 'text', 'required' => false},
79
+ {'fieldName' => 'enabled', 'fieldLabel' => 'Enabled', 'type' => 'checkbox', 'required' => false, 'defaultValue' => true},
80
+ # {'fieldName' => 'type', 'fieldLabel' => 'Storage Server Type', 'type' => 'select', 'optionSource' => 'storageServerTypes', 'required' => true},
81
+ ]
82
+ end
83
+
84
+ def add_storage_server_advanced_option_types()
85
+ [
86
+ {'fieldName' => 'visibility', 'fieldLabel' => 'Visibility', 'fieldGroup' => 'Advanced', 'type' => 'select', 'selectOptions' => [{'name' => 'Private', 'value' => 'private'},{'name' => 'Public', 'value' => 'public'}], 'required' => false, 'description' => 'Visibility', 'category' => 'permissions'},
87
+ {'fieldName' => 'tenants', 'fieldLabel' => 'Tenants', 'fieldGroup' => 'Advanced', 'type' => 'multiSelect', 'optionSource' => lambda { |api_client, api_params|
88
+ api_client.options.options_for_source("allTenants", {})['data']
89
+ }},
90
+ ]
91
+ end
92
+
93
+ def update_storage_server_option_types()
94
+ [
95
+ {'fieldName' => 'name', 'fieldLabel' => 'Name', 'type' => 'text'},
96
+ {'fieldName' => 'description', 'fieldLabel' => 'Description', 'type' => 'text'},
97
+ {'fieldName' => 'enabled', 'fieldLabel' => 'Enabled', 'type' => 'checkbox'},
98
+ ]
99
+ end
100
+
101
+ def update_storage_server_advanced_option_types()
102
+ add_storage_server_advanced_option_types()
103
+ end
104
+
105
+ def format_storage_server_status(storage_server, return_color=cyan)
106
+ out = ""
107
+ status_string = storage_server['status']
108
+ if storage_server['enabled'] == false
109
+ out << "#{red}DISABLED#{return_color}"
110
+ elsif status_string.nil? || status_string.empty? || status_string == "unknown"
111
+ out << "#{white}UNKNOWN#{return_color}"
112
+ elsif status_string == 'ok'
113
+ out << "#{green}#{status_string.upcase}#{return_color}"
114
+ elsif status_string == 'syncing'
115
+ out << "#{yellow}#{status_string.upcase}#{return_color}"
116
+ else
117
+ out << "#{red}#{status_string ? status_string.upcase : 'N/A'}#{storage_server['statusMessage'] ? "#{return_color} - #{storage_server['statusMessage']}" : ''}#{return_color}"
118
+ end
119
+ out
120
+ end
121
+
122
+ end
@@ -0,0 +1,50 @@
1
+ require 'morpheus/cli/cli_command'
2
+
3
+ class Morpheus::Cli::StorageVolumeTypes
4
+ include Morpheus::Cli::CliCommand
5
+ include Morpheus::Cli::RestCommand
6
+ include Morpheus::Cli::StorageVolumesHelper
7
+
8
+ set_command_name :'storage-volume-types'
9
+ register_subcommands :list, :get
10
+
11
+ # register_interfaces :storage_volume_types
12
+
13
+ protected
14
+
15
+ def build_list_options(opts, options, params)
16
+ opts.on('--name VALUE', String, "Filter by name") do |val|
17
+ params['name'] = val
18
+ end
19
+ opts.on('--category VALUE', String, "Filter by category") do |val|
20
+ params['category'] = val
21
+ end
22
+ # build_standard_list_options(opts, options)
23
+ super
24
+ end
25
+
26
+ def storage_volume_type_list_column_definitions(options)
27
+ {
28
+ "ID" => 'id',
29
+ "Name" => 'name',
30
+ "Code" => 'code',
31
+ "Description" => 'description',
32
+ }
33
+ end
34
+
35
+ def storage_volume_type_column_definitions(options)
36
+ {
37
+ "ID" => 'id',
38
+ "Name" => 'name',
39
+ "Code" => 'code',
40
+ "Description" => 'description',
41
+ }
42
+ end
43
+
44
+ # overridden to support name or code
45
+ def find_storage_volume_type_by_name_or_id(name)
46
+ storage_volume_type_for_name_or_id(name)
47
+ end
48
+
49
+ end
50
+
@@ -0,0 +1,103 @@
1
+ require 'morpheus/cli/cli_command'
2
+
3
+ class Morpheus::Cli::StorageVolumes
4
+ include Morpheus::Cli::CliCommand
5
+ include Morpheus::Cli::RestCommand
6
+ include Morpheus::Cli::StorageVolumesHelper
7
+
8
+ set_command_name :'storage-volumes'
9
+ set_command_description "View and manage storage volumes."
10
+ register_subcommands %w{list get add remove}
11
+
12
+ # RestCommand settings
13
+ register_interfaces :storage_volumes, :storage_volume_types
14
+ set_rest_has_type true
15
+
16
+ protected
17
+
18
+ def build_list_options(opts, options, params)
19
+ opts.on('--storage-server VALUE', String, "Storage Server Name or ID") do |val|
20
+ options[:storage_server] = val
21
+ end
22
+ opts.on('-t', '--type TYPE', "Filter by type") do |val|
23
+ params['type'] = val
24
+ end
25
+ opts.on('--name VALUE', String, "Filter by name") do |val|
26
+ params['name'] = val
27
+ end
28
+ opts.on('--category VALUE', String, "Filter by category") do |val|
29
+ params['category'] = val
30
+ end
31
+ # build_standard_list_options(opts, options)
32
+ super
33
+ end
34
+
35
+ def parse_list_options!(args, options, params)
36
+ parse_parameter_as_resource_id!(:storage_server, options, params)
37
+ super
38
+ end
39
+
40
+ def storage_volume_list_column_definitions(options)
41
+ {
42
+ "ID" => 'id',
43
+ "Name" => 'name',
44
+ "Type" => lambda {|it| it['type'] ? it['type']['name'] : '' },
45
+ "Source" => lambda {|it| format_storage_volume_source(it) },
46
+ "Storage" => lambda {|it| format_bytes(it['maxStorage']) },
47
+ "Status" => lambda {|it| format_storage_volume_status(it) },
48
+ }
49
+ end
50
+
51
+ def storage_volume_column_definitions(options)
52
+ {
53
+ "ID" => 'id',
54
+ "Name" => 'name',
55
+ "Description" => 'description',
56
+ "Type" => lambda {|it| it['type'] ? it['type']['name'] : '' },
57
+ "Owner" => lambda {|it| it['owner'] ? it['owner']['name'] : (it['account'] ? it['account']['name'] : nil) },
58
+ "Cloud" => lambda {|it| it['zone']['name'] rescue '' },
59
+ "Datastore" => lambda {|it| it['datastore']['name'] rescue '' },
60
+ "Storage Group" => lambda {|it| it['storageGroup']['name'] rescue '' },
61
+ "Storage Server" => lambda {|it| it['storageServer']['name'] rescue '' },
62
+ "Source" => lambda {|it| format_storage_volume_source(it) },
63
+ "Storage" => lambda {|it| format_bytes(it['maxStorage']) },
64
+ "Status" => lambda {|it| format_storage_volume_status(it) },
65
+ }
66
+ end
67
+
68
+ # overridden to work with name or code
69
+ # nope, api works with name=code now too
70
+ # def find_storage_volume_type_by_name_or_id(name)
71
+ # storage_volume_type_for_name_or_id(name)
72
+ # end
73
+
74
+ def add_storage_volume_option_types()
75
+ [
76
+ {'fieldContext' => 'storageServer', 'fieldName' => 'id', 'fieldLabel' => 'Storage Server', 'type' => 'select', 'optionSource' => 'storageServers', 'optionParams' => {'createType' => 'block'}, 'required' => true},
77
+ {'fieldContext' => 'storageGroup', 'fieldName' => 'id', 'fieldLabel' => 'Storage Group', 'type' => 'select', 'optionSource' => 'storageGroups', 'required' => true},
78
+ {'shorthand' => '-t', 'fieldName' => 'type', 'fieldLabel' => 'Storage Volume Type', 'type' => 'select', 'optionSource' => 'storageVolumeTypes', 'required' => true},
79
+ {'fieldName' => 'name', 'fieldLabel' => 'Name', 'type' => 'text', 'required' => true},
80
+ ]
81
+ end
82
+
83
+ def update_storage_volume_option_types()
84
+ [
85
+ {'fieldName' => 'name', 'fieldLabel' => 'Name', 'type' => 'text'},
86
+ ]
87
+ end
88
+
89
+ def load_option_types_for_storage_volume(type_record, parent_record)
90
+ storage_volume_type = type_record
91
+ option_types = storage_volume_type['optionTypes']
92
+ # ughhh, all this to change a label for API which uses bytes and not MB
93
+ if option_types
94
+ size_option_type = option_types.find {|it| it['fieldName'] == 'maxStorage' }
95
+ if size_option_type
96
+ #size_option_type['fieldLabel'] = "Volume Size (bytes)"
97
+ size_option_type['fieldAddOn'] = "bytes"
98
+ end
99
+ end
100
+ return option_types
101
+ end
102
+
103
+ end
@@ -179,7 +179,7 @@ class Morpheus::Cli::Tasks
179
179
  task_option_config = {}
180
180
  task_option_columns = []
181
181
  task_type['optionTypes'].sort { |x,y| x['displayOrder'].to_i <=> y['displayOrder'].to_i }.each do |optionType|
182
- if optionType['fieldLabel'].to_s.downcase == 'script'
182
+ if optionType['code'] == 'script'
183
183
  script_content = task['taskOptions'][optionType['fieldName']]
184
184
  elsif optionType['fieldName'] == 'httpHeaders' || optionType['fieldName'] == 'webHeaders'
185
185
  http_headers = task['taskOptions']['httpHeaders'] || task['taskOptions']['webHeaders']
@@ -553,11 +553,11 @@ class Morpheus::Cli::Tasks
553
553
  payload['task']['retryCount'] = v_prompt['retryCount'].to_i unless v_prompt['retryCount'].nil?
554
554
  end
555
555
  # Retry Delay
556
- if options[:options]['retryDelay']
557
- payload['task']['retryDelay'] = options[:options]['retryDelay'].to_i
556
+ if options[:options]['retryDelaySeconds']
557
+ payload['task']['retryDelaySeconds'] = options[:options]['retryDelaySeconds'].to_i
558
558
  else
559
- v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'retryDelay', 'fieldLabel' => 'Retry Delay', 'type' => 'number', 'defaultValue' => 10}], options[:options], @api_client)
560
- payload['task']['retryDelay'] = v_prompt['retryDelay'].to_i unless v_prompt['retryDelay'].nil?
559
+ v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'retryDelaySeconds', 'fieldLabel' => 'Retry Delay', 'type' => 'number', 'defaultValue' => 10}], options[:options], @api_client)
560
+ payload['task']['retryDelaySeconds'] = v_prompt['retryDelaySeconds'].to_i unless v_prompt['retryDelaySeconds'].nil?
561
561
  end
562
562
  end
563
563
 
@@ -18,7 +18,7 @@ class Morpheus::Cli::TenantsCommand
18
18
 
19
19
  def connect(opts)
20
20
  @api_client = establish_remote_appliance_connection(opts)
21
- @users_interface = @api_client.users
21
+ @account_users_interface = @api_client.account_users
22
22
  @accounts_interface = @api_client.accounts
23
23
  @roles_interface = @api_client.roles
24
24
  end
@@ -12,7 +12,7 @@ class Morpheus::Cli::UserGroupsCommand
12
12
  def connect(opts)
13
13
  @api_client = establish_remote_appliance_connection(opts)
14
14
  @user_groups_interface = @api_client.user_groups
15
- @users_interface = @api_client.users
15
+ @account_users_interface = @api_client.account_users
16
16
  @accounts_interface = @api_client.accounts
17
17
  end
18
18
 
@@ -17,7 +17,8 @@ class Morpheus::Cli::UserSettingsCommand
17
17
  def connect(opts)
18
18
  @api_client = establish_remote_appliance_connection(opts)
19
19
  @user_settings_interface = @api_client.user_settings
20
- @users_interface = @api_client.users
20
+ @accounts_interface = @api_client.accounts
21
+ @account_users_interface = @api_client.account_users
21
22
  end
22
23
 
23
24
  def handle(args)
@@ -802,7 +803,7 @@ EOT
802
803
  {'fieldName' => 'windowsPassword', 'fieldLabel' => 'Windows Password', 'type' => 'password'},
803
804
  {'fieldName' => 'defaultGroup', 'fieldLabel' => 'Default Group ID', 'type' => 'text'},
804
805
  {'fieldName' => 'defaultCloud', 'fieldLabel' => 'Default Cloud ID', 'type' => 'text'},
805
- {'fieldName' => 'defaultPersona', 'fieldLabel' => 'Default Persona Name or Code or ID', 'type' => 'text'},
806
+ {'fieldName' => 'defaultPersona', 'fieldLabel' => 'Default Persona Name or Code or ID eg. standard, serviceCatalog or vdi', 'type' => 'text'},
806
807
  {'switch' => 'change-password', 'fieldName' => 'password', 'fieldLabel' => 'Password', 'type' => 'password', 'description' => 'Change user credentials to use a new password'},
807
808
  {'fieldName' => 'avatar', 'fieldLabel' => 'Avatar', 'type' => 'file', 'description' => 'Local filepath of image file to upload as user avatar'},
808
809
  {'fieldName' => 'desktopBackground', 'fieldLabel' => 'Desktop Background', 'type' => 'file', 'description' => 'Local filepath of image file to upload as user desktop background'},
@@ -21,7 +21,7 @@ class Morpheus::Cli::UserSourcesCommand
21
21
  @api_client = establish_remote_appliance_connection(opts)
22
22
  @user_sources_interface = @api_client.user_sources
23
23
  @accounts_interface = @api_client.accounts
24
- @users_interface = @api_client.users
24
+ @account_users_interface = @api_client.account_users
25
25
  end
26
26
 
27
27
  def handle(args)
@@ -15,7 +15,7 @@ class Morpheus::Cli::Users
15
15
 
16
16
  def connect(opts)
17
17
  @api_client = establish_remote_appliance_connection(opts)
18
- @users_interface = @api_client.users
18
+ @account_users_interface = @api_client.account_users
19
19
  @accounts_interface = @api_client.accounts
20
20
  @roles_interface = @api_client.roles
21
21
  end
@@ -55,12 +55,12 @@ class Morpheus::Cli::Users
55
55
  account_id = account ? account['id'] : nil
56
56
  params['global'] = true if options[:global]
57
57
  params.merge!(parse_list_options(options))
58
- @users_interface.setopts(options)
58
+ @account_users_interface.setopts(options)
59
59
  if options[:dry_run]
60
- print_dry_run @users_interface.dry.list(account_id, params)
60
+ print_dry_run @account_users_interface.dry.list(account_id, params)
61
61
  return 0, nil
62
62
  end
63
- json_response = @users_interface.list(account_id, params)
63
+ json_response = @account_users_interface.list(account_id, params)
64
64
  render_response(json_response, options, "users") do
65
65
  users = json_response['users']
66
66
  title = "Morpheus Users"
@@ -103,12 +103,12 @@ class Morpheus::Cli::Users
103
103
  account_id = account ? account['id'] : nil
104
104
  params['global'] = true if options[:global]
105
105
  params.merge!(parse_list_options(options))
106
- @users_interface.setopts(options)
106
+ @account_users_interface.setopts(options)
107
107
  if options[:dry_run]
108
- print_dry_run @users_interface.dry.list(account_id, params)
108
+ print_dry_run @account_users_interface.dry.list(account_id, params)
109
109
  return
110
110
  end
111
- json_response = @users_interface.list(account_id, params)
111
+ json_response = @account_users_interface.list(account_id, params)
112
112
  # print number only
113
113
  if json_response['meta'] && json_response['meta']['total']
114
114
  print cyan, json_response['meta']['total'], reset, "\n"
@@ -195,12 +195,12 @@ EOT
195
195
  account = find_account_from_options(options)
196
196
  account_id = account ? account['id'] : nil
197
197
  params['global'] = true if options[:global]
198
- @users_interface.setopts(options)
198
+ @account_users_interface.setopts(options)
199
199
  if options[:dry_run]
200
200
  if args[0].to_s =~ /\A\d{1,}\Z/
201
- print_dry_run @users_interface.dry.get(account_id, args[0].to_i, params)
201
+ print_dry_run @account_users_interface.dry.get(account_id, args[0].to_i, params)
202
202
  else
203
- print_dry_run @users_interface.dry.list(account_id, params.merge({username: args[0]}))
203
+ print_dry_run @account_users_interface.dry.list(account_id, params.merge({username: args[0]}))
204
204
  end
205
205
  return
206
206
  end
@@ -213,7 +213,7 @@ EOT
213
213
  user_id = user['id']
214
214
  end
215
215
  # always get by id, index does not return 'access'
216
- json_response = @users_interface.get(account_id, user_id, params)
216
+ json_response = @account_users_interface.get(account_id, user_id, params)
217
217
  user = json_response['user']
218
218
  render_response(json_response, options, "user") do
219
219
  is_tenant_account = current_account['id'] != user['account']['id']
@@ -223,7 +223,7 @@ EOT
223
223
 
224
224
  # backward compatibility
225
225
  if user['access'].nil? && options[:include_features_access]
226
- user_feature_permissions_json = @users_interface.feature_permissions(account_id, user['id'])
226
+ user_feature_permissions_json = @account_users_interface.feature_permissions(account_id, user['id'])
227
227
  user_feature_permissions = user_feature_permissions_json['permissions'] || user_feature_permissions_json['featurePermissions']
228
228
 
229
229
  if user_feature_permissions
@@ -308,15 +308,15 @@ EOT
308
308
  params['global'] = true if options[:global]
309
309
  user = find_user_by_username_or_id(account_id, args[0], params)
310
310
  return 1 if user.nil?
311
- @users_interface.setopts(options)
311
+ @account_users_interface.setopts(options)
312
312
  if options[:dry_run]
313
- print_dry_run @users_interface.dry.permissions(account_id, user['id'])
313
+ print_dry_run @account_users_interface.dry.permissions(account_id, user['id'])
314
314
  return
315
315
  end
316
316
 
317
317
  is_tenant_account = current_account['id'] != user['account']['id']
318
318
 
319
- json_response = @users_interface.permissions(account_id, user['id'])
319
+ json_response = @account_users_interface.permissions(account_id, user['id'])
320
320
 
321
321
  # backward compatibility
322
322
  if !json_response['permissions'].nil?
@@ -460,12 +460,12 @@ EOT
460
460
  puts as_json(payload, options)
461
461
  return 0
462
462
  end
463
- @users_interface.setopts(options)
463
+ @account_users_interface.setopts(options)
464
464
  if options[:dry_run]
465
- print_dry_run @users_interface.dry.create(account_id, payload)
465
+ print_dry_run @account_users_interface.dry.create(account_id, payload)
466
466
  return
467
467
  end
468
- json_response = @users_interface.create(account_id, payload)
468
+ json_response = @account_users_interface.create(account_id, payload)
469
469
  if options[:json]
470
470
  print JSON.pretty_generate(json_response)
471
471
  print "\n"
@@ -545,12 +545,12 @@ EOT
545
545
  end
546
546
  end
547
547
 
548
- @users_interface.setopts(options)
548
+ @account_users_interface.setopts(options)
549
549
  if options[:dry_run]
550
- print_dry_run @users_interface.dry.update(account_id, user['id'], payload)
550
+ print_dry_run @account_users_interface.dry.update(account_id, user['id'], payload)
551
551
  return
552
552
  end
553
- json_response = @users_interface.update(account_id, user['id'], payload)
553
+ json_response = @account_users_interface.update(account_id, user['id'], payload)
554
554
  user = json_response['user']
555
555
  if options[:json]
556
556
  print JSON.pretty_generate(json_response)
@@ -645,12 +645,12 @@ EOT
645
645
  }
646
646
 
647
647
  end
648
- @users_interface.setopts(options)
648
+ @account_users_interface.setopts(options)
649
649
  if options[:dry_run]
650
- print_dry_run @users_interface.dry.update(account_id, user['id'], payload)
650
+ print_dry_run @account_users_interface.dry.update(account_id, user['id'], payload)
651
651
  return
652
652
  end
653
- json_response = @users_interface.update(account_id, user['id'], payload)
653
+ json_response = @account_users_interface.update(account_id, user['id'], payload)
654
654
  render_response(json_response, optparse, "user") do
655
655
  print_green_success "Updated password for user #{user['username']}"
656
656
  end
@@ -684,12 +684,12 @@ EOT
684
684
  unless options[:yes] || Morpheus::Cli::OptionTypes.confirm("Are you sure you want to delete the user #{user['username']}?")
685
685
  exit 9, "arborted"
686
686
  end
687
- @users_interface.setopts(options)
687
+ @account_users_interface.setopts(options)
688
688
  if options[:dry_run]
689
- print_dry_run @users_interface.dry.destroy(account_id, user['id'])
689
+ print_dry_run @account_users_interface.dry.destroy(account_id, user['id'])
690
690
  return 0
691
691
  end
692
- json_response = @users_interface.destroy(account_id, user['id'])
692
+ json_response = @account_users_interface.destroy(account_id, user['id'])
693
693
 
694
694
  if options[:json]
695
695
  print JSON.pretty_generate(json_response)
@@ -759,7 +759,7 @@ EOT
759
759
  end
760
760
  end
761
761
 
762
- available_roles = @users_interface.available_roles(account_id, user_id)['roles']
762
+ available_roles = @account_users_interface.available_roles(account_id, user_id)['roles']
763
763
 
764
764
  if available_roles.empty?
765
765
  print_red_alert "No available roles found."
@@ -0,0 +1,102 @@
1
+ require 'morpheus/cli/cli_command'
2
+ # require 'morpheus/routes'
3
+
4
+ class Morpheus::Cli::View
5
+ include Morpheus::Cli::CliCommand
6
+
7
+ set_command_description "Open the remote appliance in a web browser"
8
+ set_command_name :'view'
9
+
10
+ def connect(opts)
11
+ @api_client = establish_remote_appliance_connection(opts)
12
+ end
13
+
14
+ def handle(args)
15
+ params = {}
16
+ options = {}
17
+ optparse = Morpheus::Cli::OptionParser.new do |opts|
18
+ opts.banner = subcommand_usage("[path] [id]")
19
+ # debate: should login using /login/ouath-redirect
20
+ opts.on('-L', '--login', "Login with the CLI access token before loading the path." ) do
21
+ options[:login] = true
22
+ end
23
+ opts.on('--absolute', "Absolute path, do not search for a matching route to use") do
24
+ options[:absolute_path] = true
25
+ end
26
+ build_common_options(opts, options, [:dry_run, :remote])
27
+ opts.footer = <<-EOT
28
+ View the remote appliance in a web browser.
29
+ [path] is optional. This the path or resource type to load. The default is the index page "/".
30
+ [id] is optional. This is the resource name or id to be append to the path to load details of a specific object.
31
+ The [path] is matched against the #{prog_name} UI site map to find the best matching route.
32
+ Route matching is skipped if the path begins with a "/" or --absolute is used.
33
+ By default no authentication is not done and the existing web browser session used.
34
+ The --login option will authenticate via the CLI access token and create a new browser session.
35
+
36
+ Examples:
37
+ view --login
38
+ view monitoring
39
+ view user 1
40
+ view user administrator
41
+ view /infrastructure/clouds/2
42
+ EOT
43
+ end
44
+ optparse.parse!(args)
45
+ # verify_args!(args:args, optparse:optparse, min: 0, max: 2)
46
+ connect(options)
47
+ # todo: it would actually be cool to use the params and include them on the path..
48
+ # params.merge!(parse_query_options(options))
49
+ path, *ids = args
50
+ # default to index page "/"
51
+ path = path || "/"
52
+ if options[:absolute_path] != true
53
+ if path.start_with?("/")
54
+ # treat like absolute path, no lookup
55
+ else
56
+ # lookup best matching route from sitemap
57
+ # lookup plural routes first, so 'app' finds apps and not approvals
58
+ found_route = Morpheus::Routes.lookup(path)
59
+ if found_route
60
+ # Morpheus::Logging::DarkPrinter.puts "Found matching route: '#{path}' => '#{found_route}'" if Morpheus::Logging.debug?
61
+ path = found_route
62
+ else
63
+ # just use specified path
64
+ end
65
+ end
66
+ # always add a leading slash
67
+ path = path.start_with?("/") ? path : "/#{path}"
68
+ # append id(s) to path if passed
69
+ if ids.size > 0
70
+ # convert names to ids
71
+ # assume the last part of path is the type and use generic finder
72
+ # only lookup names, and allow any id
73
+ ids = ids.collect do |id|
74
+ if id.to_s !~ /\A\d{1,}\Z/
75
+ # assume the last part of path is the type
76
+ record_type = path.split("/").last
77
+ record = find_by_name(record_type, id)
78
+ if record.nil?
79
+ raise_command_error("[id] is invalid. No #{record_type} found for '#{id}'", args, optparse)
80
+ end
81
+ record['id'].to_s
82
+ else
83
+ id
84
+ end
85
+ end
86
+ path = "#{path}/" + ids.join("/")
87
+ end
88
+ end
89
+ # build the link to use, either our path or oauth-redirect to that path
90
+ link = "#{@appliance_url}#{path}"
91
+ if options[:login]
92
+ # uh, this should need CGI::escape(path)
93
+ link = "#{@appliance_url}/login/oauth-redirect?access_token=#{@access_token}\\&redirectUri=#{path}"
94
+ end
95
+ if options[:dry_run]
96
+ print_system_command_dry_run(Morpheus::Util.open_url_command(link), options)
97
+ return 0, nil
98
+ end
99
+ return Morpheus::Util.open_url(link)
100
+ end
101
+
102
+ end
@@ -38,6 +38,9 @@ class Morpheus::Cli::VirtualImages
38
38
  end
39
39
  opts.on('--system', "System Images" ) do
40
40
  options[:filterType] = 'System'
41
+ end
42
+ opts.on('--synced', "Synced Images" ) do
43
+ options[:filterType] = 'Synced'
41
44
  end
42
45
  opts.on('--tags Name=Value',String, "Filter by tags (metadata name value pairs).") do |val|
43
46
  val.split(",").each do |value_pair|
@@ -51,7 +54,7 @@ class Morpheus::Cli::VirtualImages
51
54
  options[:details] = true
52
55
  end
53
56
  build_standard_list_options(opts, options)
54
- opts.footer = "List virtual images."
57
+ opts.footer = "List virtual images. Default list applies User filter"
55
58
  end
56
59
  optparse.parse!(args)
57
60
  connect(options)