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.
- checksums.yaml +4 -4
- data/Dockerfile +1 -1
- data/lib/morpheus/api/account_users_interface.rb +68 -0
- data/lib/morpheus/api/api_client.rb +55 -10
- data/lib/morpheus/api/audit_interface.rb +9 -0
- data/lib/morpheus/api/catalog_item_types_interface.rb +20 -0
- data/lib/morpheus/api/instances_interface.rb +49 -0
- data/lib/morpheus/api/load_balancer_monitors_interface.rb +9 -0
- data/lib/morpheus/api/load_balancer_pools_interface.rb +4 -4
- data/lib/morpheus/api/load_balancer_profiles_interface.rb +4 -5
- data/lib/morpheus/api/load_balancer_virtual_servers_interface.rb +13 -4
- data/lib/morpheus/api/load_balancers_interface.rb +5 -0
- data/lib/morpheus/api/network_routers_interface.rb +9 -0
- data/lib/morpheus/api/network_static_routes_interface.rb +36 -0
- data/lib/morpheus/api/ping_interface.rb +2 -0
- data/lib/morpheus/api/read_interface.rb +4 -3
- data/lib/morpheus/api/rest_interface.rb +3 -3
- data/lib/morpheus/api/secondary_read_interface.rb +1 -1
- data/lib/morpheus/api/secondary_rest_interface.rb +19 -19
- data/lib/morpheus/api/setup_interface.rb +4 -0
- data/lib/morpheus/api/snapshots_interface.rb +19 -0
- data/lib/morpheus/api/storage_server_types_interface.rb +14 -0
- data/lib/morpheus/api/storage_servers_interface.rb +9 -0
- data/lib/morpheus/api/storage_volume_types_interface.rb +9 -0
- data/lib/morpheus/api/storage_volumes_interface.rb +9 -0
- data/lib/morpheus/api/users_interface.rb +16 -63
- data/lib/morpheus/cli/cli_command.rb +253 -5
- data/lib/morpheus/cli/cli_registry.rb +1 -1
- data/lib/morpheus/cli/commands/alias_command.rb +1 -1
- data/lib/morpheus/cli/commands/apps.rb +14 -78
- data/lib/morpheus/cli/commands/audit.rb +188 -0
- data/lib/morpheus/cli/commands/blueprints_command.rb +1 -1
- data/lib/morpheus/cli/commands/catalog_item_types_command.rb +88 -0
- data/lib/morpheus/cli/commands/change_password_command.rb +4 -4
- data/lib/morpheus/cli/commands/clusters.rb +96 -58
- data/lib/morpheus/cli/commands/hosts.rb +27 -15
- data/lib/morpheus/cli/commands/image_builder_command.rb +4 -8
- data/lib/morpheus/cli/commands/instances.rb +359 -3
- data/lib/morpheus/cli/commands/integrations_command.rb +1 -12
- data/lib/morpheus/cli/commands/library_instance_types_command.rb +3 -0
- data/lib/morpheus/cli/commands/load_balancer_monitors.rb +70 -0
- data/lib/morpheus/cli/commands/load_balancer_pools.rb +29 -50
- data/lib/morpheus/cli/commands/load_balancer_profiles.rb +64 -0
- data/lib/morpheus/cli/commands/load_balancer_types.rb +9 -4
- data/lib/morpheus/cli/commands/load_balancer_virtual_servers.rb +69 -58
- data/lib/morpheus/cli/commands/load_balancers.rb +109 -6
- data/lib/morpheus/cli/commands/network_firewalls_command.rb +22 -5
- data/lib/morpheus/cli/commands/network_routers_command.rb +96 -45
- data/lib/morpheus/cli/commands/network_static_routes_command.rb +451 -0
- data/lib/morpheus/cli/commands/network_transport_zones_command.rb +4 -4
- data/lib/morpheus/cli/commands/networks_command.rb +2 -2
- data/lib/morpheus/cli/commands/open_command.rb +30 -0
- data/lib/morpheus/cli/commands/options.rb +98 -0
- data/lib/morpheus/cli/commands/ping.rb +3 -5
- data/lib/morpheus/cli/commands/policies_command.rb +2 -2
- data/lib/morpheus/cli/commands/prices_command.rb +7 -7
- data/lib/morpheus/cli/commands/provisioning_settings_command.rb +1 -0
- data/lib/morpheus/cli/commands/remote.rb +20 -12
- data/lib/morpheus/cli/commands/roles.rb +1 -1
- data/lib/morpheus/cli/commands/security_groups.rb +2 -2
- data/lib/morpheus/cli/commands/service_plans_command.rb +1 -1
- data/lib/morpheus/cli/commands/setup.rb +1 -1
- data/lib/morpheus/cli/commands/shell.rb +2 -2
- data/lib/morpheus/cli/commands/snapshots.rb +139 -0
- data/lib/morpheus/cli/commands/storage_server_types.rb +50 -0
- data/lib/morpheus/cli/commands/storage_servers.rb +122 -0
- data/lib/morpheus/cli/commands/storage_volume_types.rb +50 -0
- data/lib/morpheus/cli/commands/storage_volumes.rb +103 -0
- data/lib/morpheus/cli/commands/tasks.rb +5 -5
- data/lib/morpheus/cli/commands/tenants_command.rb +1 -1
- data/lib/morpheus/cli/commands/user_groups_command.rb +1 -1
- data/lib/morpheus/cli/commands/user_settings_command.rb +3 -2
- data/lib/morpheus/cli/commands/user_sources_command.rb +1 -1
- data/lib/morpheus/cli/commands/users.rb +28 -28
- data/lib/morpheus/cli/commands/view.rb +102 -0
- data/lib/morpheus/cli/commands/virtual_images.rb +4 -1
- data/lib/morpheus/cli/mixins/accounts_helper.rb +5 -5
- data/lib/morpheus/cli/mixins/load_balancers_helper.rb +24 -4
- data/lib/morpheus/cli/mixins/print_helper.rb +50 -18
- data/lib/morpheus/cli/mixins/processes_helper.rb +1 -2
- data/lib/morpheus/cli/mixins/provisioning_helper.rb +96 -6
- data/lib/morpheus/cli/mixins/rest_command.rb +148 -74
- data/lib/morpheus/cli/mixins/secondary_rest_command.rb +174 -82
- data/lib/morpheus/cli/mixins/storage_servers_helper.rb +156 -0
- data/lib/morpheus/cli/mixins/storage_volumes_helper.rb +119 -0
- data/lib/morpheus/cli/option_types.rb +95 -28
- data/lib/morpheus/cli/version.rb +1 -1
- data/lib/morpheus/cli.rb +1 -0
- data/lib/morpheus/ext/string.rb +29 -6
- data/lib/morpheus/routes.rb +238 -0
- data/lib/morpheus/util.rb +6 -1
- 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['
|
|
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]['
|
|
557
|
-
payload['task']['
|
|
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' => '
|
|
560
|
-
payload['task']['
|
|
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
|
-
@
|
|
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
|
-
@
|
|
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
|
-
@
|
|
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
|
-
@
|
|
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
|
-
@
|
|
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
|
-
@
|
|
58
|
+
@account_users_interface.setopts(options)
|
|
59
59
|
if options[:dry_run]
|
|
60
|
-
print_dry_run @
|
|
60
|
+
print_dry_run @account_users_interface.dry.list(account_id, params)
|
|
61
61
|
return 0, nil
|
|
62
62
|
end
|
|
63
|
-
json_response = @
|
|
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
|
-
@
|
|
106
|
+
@account_users_interface.setopts(options)
|
|
107
107
|
if options[:dry_run]
|
|
108
|
-
print_dry_run @
|
|
108
|
+
print_dry_run @account_users_interface.dry.list(account_id, params)
|
|
109
109
|
return
|
|
110
110
|
end
|
|
111
|
-
json_response = @
|
|
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
|
-
@
|
|
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 @
|
|
201
|
+
print_dry_run @account_users_interface.dry.get(account_id, args[0].to_i, params)
|
|
202
202
|
else
|
|
203
|
-
print_dry_run @
|
|
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 = @
|
|
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 = @
|
|
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
|
-
@
|
|
311
|
+
@account_users_interface.setopts(options)
|
|
312
312
|
if options[:dry_run]
|
|
313
|
-
print_dry_run @
|
|
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 = @
|
|
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
|
-
@
|
|
463
|
+
@account_users_interface.setopts(options)
|
|
464
464
|
if options[:dry_run]
|
|
465
|
-
print_dry_run @
|
|
465
|
+
print_dry_run @account_users_interface.dry.create(account_id, payload)
|
|
466
466
|
return
|
|
467
467
|
end
|
|
468
|
-
json_response = @
|
|
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
|
-
@
|
|
548
|
+
@account_users_interface.setopts(options)
|
|
549
549
|
if options[:dry_run]
|
|
550
|
-
print_dry_run @
|
|
550
|
+
print_dry_run @account_users_interface.dry.update(account_id, user['id'], payload)
|
|
551
551
|
return
|
|
552
552
|
end
|
|
553
|
-
json_response = @
|
|
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
|
-
@
|
|
648
|
+
@account_users_interface.setopts(options)
|
|
649
649
|
if options[:dry_run]
|
|
650
|
-
print_dry_run @
|
|
650
|
+
print_dry_run @account_users_interface.dry.update(account_id, user['id'], payload)
|
|
651
651
|
return
|
|
652
652
|
end
|
|
653
|
-
json_response = @
|
|
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
|
-
@
|
|
687
|
+
@account_users_interface.setopts(options)
|
|
688
688
|
if options[:dry_run]
|
|
689
|
-
print_dry_run @
|
|
689
|
+
print_dry_run @account_users_interface.dry.destroy(account_id, user['id'])
|
|
690
690
|
return 0
|
|
691
691
|
end
|
|
692
|
-
json_response = @
|
|
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 = @
|
|
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)
|