morpheus-cli 4.2.8 → 4.2.10
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.rb +1 -1
- data/lib/morpheus/api/activity_interface.rb +9 -0
- data/lib/morpheus/api/api_client.rb +83 -27
- data/lib/morpheus/api/apps_interface.rb +21 -0
- data/lib/morpheus/api/dashboard_interface.rb +5 -21
- data/lib/morpheus/api/instances_interface.rb +3 -10
- data/lib/morpheus/api/invoice_line_items_interface.rb +14 -0
- data/lib/morpheus/api/invoices_interface.rb +7 -12
- data/lib/morpheus/api/library_layouts_interface.rb +8 -0
- data/lib/morpheus/api/ping_interface.rb +20 -0
- data/lib/morpheus/api/projects_interface.rb +33 -0
- data/lib/morpheus/api/setup_interface.rb +19 -36
- data/lib/morpheus/api/user_settings_interface.rb +0 -6
- data/lib/morpheus/api/whoami_interface.rb +4 -8
- data/lib/morpheus/benchmarking.rb +16 -26
- data/lib/morpheus/cli.rb +10 -5
- data/lib/morpheus/cli/access_token_command.rb +5 -8
- data/lib/morpheus/cli/activity_command.rb +146 -0
- data/lib/morpheus/cli/apps.rb +312 -121
- data/lib/morpheus/cli/archives_command.rb +1 -1
- data/lib/morpheus/cli/auth_command.rb +4 -11
- data/lib/morpheus/cli/blueprints_command.rb +196 -137
- data/lib/morpheus/cli/change_password_command.rb +1 -1
- data/lib/morpheus/cli/cli_command.rb +225 -72
- data/lib/morpheus/cli/cli_registry.rb +2 -2
- data/lib/morpheus/cli/cloud_datastores_command.rb +1 -1
- data/lib/morpheus/cli/clouds.rb +5 -20
- data/lib/morpheus/cli/clusters.rb +4 -28
- data/lib/morpheus/cli/commands/standard/alias_command.rb +2 -9
- data/lib/morpheus/cli/commands/standard/benchmark_command.rb +2 -0
- data/lib/morpheus/cli/commands/standard/curl_command.rb +2 -3
- data/lib/morpheus/cli/commands/standard/history_command.rb +3 -6
- data/lib/morpheus/cli/commands/standard/man_command.rb +10 -7
- data/lib/morpheus/cli/commands/standard/ssl_verification_command.rb +10 -9
- data/lib/morpheus/cli/containers_command.rb +3 -3
- data/lib/morpheus/cli/credentials.rb +13 -16
- data/lib/morpheus/cli/error_handler.rb +18 -12
- data/lib/morpheus/cli/errors.rb +45 -0
- data/lib/morpheus/cli/execute_schedules_command.rb +1 -1
- data/lib/morpheus/cli/execution_request_command.rb +4 -4
- data/lib/morpheus/cli/groups.rb +84 -132
- data/lib/morpheus/cli/hosts.rb +6 -16
- data/lib/morpheus/cli/instances.rb +100 -183
- data/lib/morpheus/cli/invoices_command.rb +505 -71
- data/lib/morpheus/cli/library_layouts_command.rb +254 -166
- data/lib/morpheus/cli/library_option_lists_command.rb +0 -87
- data/lib/morpheus/cli/library_option_types_command.rb +0 -96
- data/lib/morpheus/cli/license.rb +3 -0
- data/lib/morpheus/cli/login.rb +17 -37
- data/lib/morpheus/cli/logout.rb +9 -5
- data/lib/morpheus/cli/mixins/accounts_helper.rb +83 -7
- data/lib/morpheus/cli/mixins/operations_helper.rb +41 -0
- data/lib/morpheus/cli/mixins/option_source_helper.rb +255 -0
- data/lib/morpheus/cli/mixins/print_helper.rb +18 -4
- data/lib/morpheus/cli/mixins/provisioning_helper.rb +222 -13
- data/lib/morpheus/cli/mixins/remote_helper.rb +139 -0
- data/lib/morpheus/cli/monitoring_checks_command.rb +11 -3
- data/lib/morpheus/cli/network_groups_command.rb +8 -2
- data/lib/morpheus/cli/option_types.rb +1 -1
- data/lib/morpheus/cli/ping.rb +252 -0
- data/lib/morpheus/cli/price_sets_command.rb +16 -27
- data/lib/morpheus/cli/prices_command.rb +34 -27
- data/lib/morpheus/cli/processes_command.rb +81 -7
- data/lib/morpheus/cli/projects_command.rb +607 -0
- data/lib/morpheus/cli/recent_activity_command.rb +87 -65
- data/lib/morpheus/cli/remote.rb +965 -974
- data/lib/morpheus/cli/reports_command.rb +3 -15
- data/lib/morpheus/cli/roles.rb +8 -31
- data/lib/morpheus/cli/service_plans_command.rb +25 -31
- data/lib/morpheus/cli/setup.rb +392 -0
- data/lib/morpheus/cli/shell.rb +144 -56
- data/lib/morpheus/cli/subnets_command.rb +71 -11
- data/lib/morpheus/cli/tasks.rb +3 -3
- data/lib/morpheus/cli/user_sources_command.rb +4 -4
- data/lib/morpheus/cli/users.rb +135 -109
- data/lib/morpheus/cli/version.rb +1 -1
- data/lib/morpheus/cli/whitelabel_settings_command.rb +7 -7
- data/lib/morpheus/cli/whoami.rb +90 -129
- data/lib/morpheus/cli/wiki_command.rb +2 -14
- data/lib/morpheus/ext/rest_client.rb +36 -0
- data/lib/morpheus/formatters.rb +42 -5
- data/lib/morpheus/rest_client.rb +0 -10
- data/lib/morpheus/terminal.rb +41 -1
- data/lib/morpheus/util.rb +24 -0
- metadata +16 -3
- data/lib/morpheus/cli/command_error.rb +0 -22
|
@@ -39,30 +39,20 @@ class Morpheus::Cli::PriceSetsCommand
|
|
|
39
39
|
end
|
|
40
40
|
optparse.parse!(args)
|
|
41
41
|
connect(options)
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
42
|
+
params.merge!(parse_list_options(options))
|
|
43
|
+
params['phrase'] = args.join(' ') if args.count > 0 && params['phrase'].nil? # pass args as phrase, every list command should do this
|
|
44
|
+
@price_sets_interface.setopts(options)
|
|
45
|
+
if options[:dry_run]
|
|
46
|
+
print_dry_run @price_sets_interface.dry.list(params)
|
|
47
|
+
return
|
|
45
48
|
end
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
@price_sets_interface.setopts(options)
|
|
51
|
-
if options[:dry_run]
|
|
52
|
-
print_dry_run @price_sets_interface.dry.list(params)
|
|
53
|
-
return
|
|
54
|
-
end
|
|
55
|
-
json_response = @price_sets_interface.list(params)
|
|
56
|
-
|
|
57
|
-
render_result = render_with_format(json_response, options, 'priceSets')
|
|
58
|
-
return 0 if render_result
|
|
59
|
-
|
|
49
|
+
json_response = @price_sets_interface.list(params)
|
|
50
|
+
price_sets = json_response['priceSets']
|
|
51
|
+
render_response(json_response, options, 'priceSets') do
|
|
60
52
|
title = "Morpheus Price Sets"
|
|
61
53
|
subtitles = []
|
|
62
54
|
subtitles += parse_list_subtitles(options)
|
|
63
55
|
print_h1 title, subtitles
|
|
64
|
-
|
|
65
|
-
price_sets = json_response['priceSets']
|
|
66
56
|
if price_sets.empty?
|
|
67
57
|
print cyan,"No price sets found.",reset,"\n"
|
|
68
58
|
else
|
|
@@ -71,25 +61,24 @@ class Morpheus::Cli::PriceSetsCommand
|
|
|
71
61
|
id: (it['active'] ? cyan : yellow) + it['id'].to_s,
|
|
72
62
|
name: it['name'],
|
|
73
63
|
active: format_boolean(it['active']),
|
|
74
|
-
|
|
64
|
+
priceUnit: it['priceUnit'],
|
|
75
65
|
type: price_set_type_label(it['type']),
|
|
76
66
|
price_count: it['prices'].count.to_s + cyan
|
|
77
67
|
}
|
|
78
68
|
end
|
|
79
69
|
columns = [
|
|
80
|
-
:id, :name, :active, :
|
|
70
|
+
:id, :name, :active, :priceUnit, :type, '# OF PRICES' => :price_count
|
|
81
71
|
]
|
|
82
72
|
columns.delete(:active) if !params['includeInactive']
|
|
83
|
-
|
|
84
73
|
print as_pretty_table(rows, columns, options)
|
|
85
74
|
print_results_pagination(json_response)
|
|
86
|
-
print reset,"\n"
|
|
87
75
|
end
|
|
88
76
|
print reset,"\n"
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
77
|
+
end
|
|
78
|
+
if price_sets.empty?
|
|
79
|
+
return 1, "0 price sets found"
|
|
80
|
+
else
|
|
81
|
+
return 0, nil
|
|
93
82
|
end
|
|
94
83
|
end
|
|
95
84
|
|
|
@@ -30,35 +30,40 @@ class Morpheus::Cli::PricesCommand
|
|
|
30
30
|
opts.on('-i', '--include-inactive [on|off]', String, "Can be used to enable / disable inactive filter. Default is on") do |val|
|
|
31
31
|
params['includeInactive'] = val.to_s == 'on' || val.to_s == 'true' || val.to_s == '1' || val.to_s == ''
|
|
32
32
|
end
|
|
33
|
+
opts.on('--platform PLATFORM', Array, "Filter by platform eg. linux, windows") do |val|
|
|
34
|
+
params['platform'] = val.collect {|it| it.to_s.strip.empty? ? nil : it.to_s.strip }.compact
|
|
35
|
+
end
|
|
36
|
+
opts.on('--price-unit UNIT', Array, "Filter by priceUnit eg. hour, month") do |val|
|
|
37
|
+
params['priceUnit'] = val.collect {|it| it.to_s.strip.empty? ? nil : it.to_s.strip }.compact
|
|
38
|
+
end
|
|
39
|
+
opts.on('--currency CURRENCY', Array, "Filter by currency eg. usd") do |val|
|
|
40
|
+
params['currency'] = val.collect {|it| it.to_s.strip.empty? ? nil : it.to_s.strip }.compact
|
|
41
|
+
end
|
|
42
|
+
opts.on('--price-type TYPE', Array, "Filter by priceType eg. fixed,platform,software,compute,storage,datastore,memory,cores,cpu") do |val|
|
|
43
|
+
params['priceType'] = val.collect {|it| it.to_s.strip.empty? ? nil : it.to_s.strip }.compact
|
|
44
|
+
end
|
|
33
45
|
build_common_options(opts, options, [:list, :query, :json, :yaml, :csv, :fields, :dry_run, :remote])
|
|
34
46
|
opts.footer = "List prices."
|
|
35
47
|
end
|
|
36
48
|
optparse.parse!(args)
|
|
49
|
+
#verify_args!(args:args, optparse:optparse, count:0)
|
|
37
50
|
connect(options)
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
51
|
+
|
|
52
|
+
params.merge!(parse_list_options(options))
|
|
53
|
+
params['phrase'] = args.join(' ') if args.count > 0 && params['phrase'].nil? # pass args as phrase, every list command should do this
|
|
54
|
+
load_whoami()
|
|
55
|
+
@prices_interface.setopts(options)
|
|
56
|
+
if options[:dry_run]
|
|
57
|
+
print_dry_run @prices_interface.dry.list(params)
|
|
58
|
+
return
|
|
41
59
|
end
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
@prices_interface.setopts(options)
|
|
47
|
-
if options[:dry_run]
|
|
48
|
-
print_dry_run @prices_interface.dry.list(params)
|
|
49
|
-
return
|
|
50
|
-
end
|
|
51
|
-
json_response = @prices_interface.list(params)
|
|
52
|
-
|
|
53
|
-
render_result = render_with_format(json_response, options, 'prices')
|
|
54
|
-
return 0 if render_result
|
|
55
|
-
|
|
60
|
+
json_response = @prices_interface.list(params)
|
|
61
|
+
prices = json_response['prices']
|
|
62
|
+
render_response(json_response, options, 'prices') do
|
|
56
63
|
title = "Morpheus Prices"
|
|
57
64
|
subtitles = []
|
|
58
65
|
subtitles += parse_list_subtitles(options)
|
|
59
66
|
print_h1 title, subtitles
|
|
60
|
-
|
|
61
|
-
prices = json_response['prices']
|
|
62
67
|
if prices.empty?
|
|
63
68
|
print yellow,"No prices found.",reset,"\n"
|
|
64
69
|
else
|
|
@@ -77,20 +82,17 @@ class Morpheus::Cli::PricesCommand
|
|
|
77
82
|
}
|
|
78
83
|
end
|
|
79
84
|
columns = [
|
|
80
|
-
:id, :name, :active, :priceType, :tenant, :priceUnit, :priceAdjustment, :cost, :markup, :price
|
|
85
|
+
:id, :name, :active, {'PRICE TYPE' => :priceType}, :tenant, {'PRICE UNIT' => :priceUnit}, {'PRICE ADJUSTMENT' => :priceAdjustment}, :cost, :markup, :price
|
|
81
86
|
]
|
|
82
87
|
columns.delete(:active) if !params['includeInactive']
|
|
83
88
|
|
|
84
89
|
print as_pretty_table(rows, columns, options)
|
|
85
90
|
print_results_pagination(json_response)
|
|
86
|
-
print reset,"\n"
|
|
87
91
|
end
|
|
88
92
|
print reset,"\n"
|
|
89
|
-
return 0
|
|
90
|
-
rescue RestClient::Exception => e
|
|
91
|
-
print_rest_exception(e, options)
|
|
92
|
-
exit 1
|
|
93
93
|
end
|
|
94
|
+
return 1, "0 prices found" if prices.empty?
|
|
95
|
+
return 0, nil
|
|
94
96
|
end
|
|
95
97
|
|
|
96
98
|
def get(args)
|
|
@@ -552,7 +554,12 @@ class Morpheus::Cli::PricesCommand
|
|
|
552
554
|
end
|
|
553
555
|
|
|
554
556
|
def currency_sym(currency)
|
|
555
|
-
|
|
557
|
+
begin
|
|
558
|
+
Money::Currency.new((currency.to_s.empty? ? 'usd' : currency).to_sym).symbol
|
|
559
|
+
rescue
|
|
560
|
+
# sometimes '' is getting passed in here, so figure that out...
|
|
561
|
+
Money::Currency.new(:usd).symbol
|
|
562
|
+
end
|
|
556
563
|
end
|
|
557
564
|
|
|
558
565
|
def price_prefix(price)
|
|
@@ -570,7 +577,7 @@ class Morpheus::Cli::PricesCommand
|
|
|
570
577
|
end
|
|
571
578
|
|
|
572
579
|
def price_type_label(type)
|
|
573
|
-
price_types[type] || type.capitalize
|
|
580
|
+
price_types[type] || type.to_s.capitalize
|
|
574
581
|
end
|
|
575
582
|
|
|
576
583
|
def price_types
|
|
@@ -4,6 +4,9 @@ require 'morpheus/cli/mixins/processes_helper'
|
|
|
4
4
|
class Morpheus::Cli::Processes
|
|
5
5
|
include Morpheus::Cli::CliCommand
|
|
6
6
|
include Morpheus::Cli::ProcessesHelper
|
|
7
|
+
include Morpheus::Cli::ProvisioningHelper
|
|
8
|
+
include Morpheus::Cli::InfrastructureHelper
|
|
9
|
+
include Morpheus::Cli::OptionSourceHelper
|
|
7
10
|
|
|
8
11
|
set_command_name :'process'
|
|
9
12
|
|
|
@@ -16,9 +19,11 @@ class Morpheus::Cli::Processes
|
|
|
16
19
|
#@appliance_name, @appliance_url = Morpheus::Cli::Remote.active_appliance
|
|
17
20
|
end
|
|
18
21
|
|
|
19
|
-
def connect(
|
|
20
|
-
@api_client = establish_remote_appliance_connection(
|
|
22
|
+
def connect(options)
|
|
23
|
+
@api_client = establish_remote_appliance_connection(options)
|
|
21
24
|
@processes_interface = @api_client.processes
|
|
25
|
+
#@instances_interface = @api_client.instances
|
|
26
|
+
@clouds_interface = @api_client.clouds
|
|
22
27
|
end
|
|
23
28
|
|
|
24
29
|
def handle(args)
|
|
@@ -42,21 +47,29 @@ class Morpheus::Cli::Processes
|
|
|
42
47
|
options[:show_output] = true
|
|
43
48
|
options[:details] = true
|
|
44
49
|
end
|
|
45
|
-
opts.on('--app
|
|
50
|
+
opts.on('--app APP', String, "Limit results to specific app(s).") do |val|
|
|
46
51
|
params['appIds'] = val.split(',').collect {|it| it.to_s.strip }.reject { |it| it.empty? }
|
|
47
52
|
end
|
|
48
|
-
opts.on('--instance
|
|
53
|
+
opts.on('--instance INSTANCE', String, "Limit results to specific instance(s).") do |val|
|
|
49
54
|
params['instanceIds'] = val.split(',').collect {|it| it.to_s.strip }.reject { |it| it.empty? }
|
|
50
55
|
end
|
|
51
|
-
opts.on('--container
|
|
56
|
+
opts.on('--container CONTAINER', String, "Limit results to specific container(s).") do |val|
|
|
52
57
|
params['containerIds'] = val.split(',').collect {|it| it.to_s.strip }.reject { |it| it.empty? }
|
|
53
58
|
end
|
|
54
|
-
opts.on('--host
|
|
59
|
+
opts.on('--host HOST', String, "Limit results to specific host(s).") do |val|
|
|
55
60
|
params['serverIds'] = val.split(',').collect {|it| it.to_s.strip }.reject { |it| it.empty? }
|
|
56
61
|
end
|
|
57
|
-
opts.on('--
|
|
62
|
+
opts.on('--server HOST', String, "Limit results to specific servers(s).") do |val|
|
|
63
|
+
params['serverIds'] = val.split(',').collect {|it| it.to_s.strip }.reject { |it| it.empty? }
|
|
64
|
+
end
|
|
65
|
+
opts.add_hidden_option('--server')
|
|
66
|
+
opts.on('--cloud CLOUD', String, "Limit results to specific cloud(s).") do |val|
|
|
58
67
|
params['zoneIds'] = val.split(',').collect {|it| it.to_s.strip }.reject { |it| it.empty? }
|
|
59
68
|
end
|
|
69
|
+
opts.on('--user USER', String, "Limit results to user(s).") do |val|
|
|
70
|
+
#params['userId'] = val.split(',').collect {|it| it.to_s.strip }.reject { |it| it.empty? }
|
|
71
|
+
options[:user] = val
|
|
72
|
+
end
|
|
60
73
|
build_common_options(opts, options, [:list, :query, :json, :yaml, :csv, :fields, :dry_run, :remote])
|
|
61
74
|
opts.footer = "List historical processes."
|
|
62
75
|
end
|
|
@@ -69,6 +82,67 @@ class Morpheus::Cli::Processes
|
|
|
69
82
|
connect(options)
|
|
70
83
|
begin
|
|
71
84
|
params.merge!(parse_list_options(options))
|
|
85
|
+
if params['instanceIds']
|
|
86
|
+
params['instanceIds'] = params['instanceIds'].collect do |instance_id|
|
|
87
|
+
if instance_id.to_s =~ /\A\d{1,}\Z/
|
|
88
|
+
# just allow instance IDs
|
|
89
|
+
instance_id.to_i
|
|
90
|
+
else
|
|
91
|
+
instance = find_instance_by_name_or_id(instance_id)
|
|
92
|
+
if instance.nil?
|
|
93
|
+
return 1, "instance not found for '#{instance_id}'" # never happens because find exits
|
|
94
|
+
end
|
|
95
|
+
instance['id']
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
if params['serverIds']
|
|
100
|
+
params['serverIds'] = params['serverIds'].collect do |server_id|
|
|
101
|
+
if server_id.to_s =~ /\A\d{1,}\Z/
|
|
102
|
+
# just allow server IDs
|
|
103
|
+
server_id.to_i
|
|
104
|
+
else
|
|
105
|
+
server = find_server_by_name_or_id(server_id)
|
|
106
|
+
if server.nil?
|
|
107
|
+
return 1, "server not found for '#{server_id}'" # never happens because find exits
|
|
108
|
+
end
|
|
109
|
+
server['id']
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
if params['appIds']
|
|
114
|
+
params['appIds'] = params['appIds'].collect do |app_id|
|
|
115
|
+
if app_id.to_s =~ /\A\d{1,}\Z/
|
|
116
|
+
# just allow app IDs
|
|
117
|
+
app_id.to_i
|
|
118
|
+
else
|
|
119
|
+
app = find_app_by_name_or_id(app_id)
|
|
120
|
+
if app.nil?
|
|
121
|
+
return 1, "app not found for '#{app_id}'" # never happens because find exits
|
|
122
|
+
end
|
|
123
|
+
app['id']
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
if params['zoneIds']
|
|
128
|
+
params['zoneIds'] = params['zoneIds'].collect do |zone_id|
|
|
129
|
+
if zone_id.to_s =~ /\A\d{1,}\Z/
|
|
130
|
+
# just allow zone IDs
|
|
131
|
+
zone_id.to_i
|
|
132
|
+
else
|
|
133
|
+
zone = find_cloud_by_name_or_id(zone_id)
|
|
134
|
+
if zone.nil?
|
|
135
|
+
return 1, "cloud not found for '#{zone_id}'" # never happens because find exits
|
|
136
|
+
end
|
|
137
|
+
zone['id']
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
if options[:user]
|
|
142
|
+
user = find_available_user_option(options[:user])
|
|
143
|
+
return 1, "user not found by '#{options[:user]}'" if user.nil?
|
|
144
|
+
params['userId'] = user['id']
|
|
145
|
+
end
|
|
72
146
|
@processes_interface.setopts(options)
|
|
73
147
|
if options[:dry_run]
|
|
74
148
|
print_dry_run @processes_interface.dry.list(params)
|
|
@@ -0,0 +1,607 @@
|
|
|
1
|
+
require 'morpheus/cli/cli_command'
|
|
2
|
+
|
|
3
|
+
class Morpheus::Cli::Projects
|
|
4
|
+
include Morpheus::Cli::CliCommand
|
|
5
|
+
include Morpheus::Cli::ProvisioningHelper
|
|
6
|
+
include Morpheus::Cli::OptionSourceHelper
|
|
7
|
+
# include Morpheus::Cli::InfrastructureHelper
|
|
8
|
+
# include Morpheus::Cli::AccountsHelper
|
|
9
|
+
|
|
10
|
+
register_subcommands :list, :get, :add, :update, :remove,
|
|
11
|
+
# :add_tags, :remove_tags,
|
|
12
|
+
#:add_instance, :remove_instance
|
|
13
|
+
#:add_host, :remove_host
|
|
14
|
+
|
|
15
|
+
def connect(opts)
|
|
16
|
+
@api_client = establish_remote_appliance_connection(opts)
|
|
17
|
+
@projects_interface = @api_client.projects
|
|
18
|
+
@instances_interface = @api_client.instances
|
|
19
|
+
@servers_interface = @api_client.servers
|
|
20
|
+
@clouds_interface = @api_client.clouds
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def handle(args)
|
|
24
|
+
handle_subcommand(args)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def list(args)
|
|
28
|
+
params = {}
|
|
29
|
+
options = {}
|
|
30
|
+
instance_ids, server_ids, cloud_ids = nil, nil, nil
|
|
31
|
+
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
|
32
|
+
opts.banner = subcommand_usage()
|
|
33
|
+
opts.on('--instances [LIST]', Array, "Filter by Instance, comma separated list of instance names or IDs.") do |list|
|
|
34
|
+
instance_ids = list.collect {|it| it.to_s.strip.empty? ? nil : it.to_s.strip }.compact.uniq
|
|
35
|
+
end
|
|
36
|
+
opts.on('--servers [LIST]', Array, "Filter by Server, comma separated list of server (host) names or IDs.") do |list|
|
|
37
|
+
server_ids = list.collect {|it| it.to_s.strip.empty? ? nil : it.to_s.strip }.compact.uniq
|
|
38
|
+
end
|
|
39
|
+
opts.on('--clouds [LIST]', Array, "Filter by Cloud, comma separated list of cloud (zone) names or IDs.") do |list|
|
|
40
|
+
cloud_ids = list.collect {|it| it.to_s.strip.empty? ? nil : it.to_s.strip }.compact.uniq
|
|
41
|
+
end
|
|
42
|
+
# opts.on('--owner [LIST]', Array, "Owner, comma separated list of usernames or IDs.") do |list|
|
|
43
|
+
# params['ownerId'] = list.collect {|it| it.to_s.strip.empty? ? nil : it.to_s.strip }.compact.uniq
|
|
44
|
+
# end
|
|
45
|
+
build_standard_get_options(opts, options)
|
|
46
|
+
opts.footer = <<-EOT
|
|
47
|
+
List projects.
|
|
48
|
+
EOT
|
|
49
|
+
end
|
|
50
|
+
optparse.parse!(args)
|
|
51
|
+
#verify_args!(args:args, optparse:optparse, count:0)
|
|
52
|
+
connect(options)
|
|
53
|
+
options[:phrase] = args.join(' ') if args.count > 0 && params[:phrase].nil? # pass args as phrase, every list command should do this
|
|
54
|
+
params.merge!(parse_list_options(options))
|
|
55
|
+
params['instanceId'] = parse_instance_id_list(instance_ids) if instance_ids
|
|
56
|
+
# todo server and cloud, missing parse_server_id_list() too
|
|
57
|
+
params['serverId'] = parse_server_id_list(server_ids) if server_ids
|
|
58
|
+
params['cloudId'] = parse_cloud_id_list(cloud_ids) if cloud_ids
|
|
59
|
+
@projects_interface.setopts(options)
|
|
60
|
+
if options[:dry_run]
|
|
61
|
+
print_dry_run @projects_interface.dry.list(params)
|
|
62
|
+
return
|
|
63
|
+
end
|
|
64
|
+
json_response = @projects_interface.list(params)
|
|
65
|
+
projects = json_response['projects']
|
|
66
|
+
render_response(json_response, options, 'projects') do
|
|
67
|
+
title = "Morpheus Projects"
|
|
68
|
+
subtitles = []
|
|
69
|
+
subtitles += parse_list_subtitles(options)
|
|
70
|
+
print_h1 title, subtitles
|
|
71
|
+
if projects.empty?
|
|
72
|
+
print yellow,"No projects found.",reset,"\n"
|
|
73
|
+
else
|
|
74
|
+
print cyan
|
|
75
|
+
columns = [
|
|
76
|
+
{"ID" => lambda {|it| it['id'] } },
|
|
77
|
+
{"NAME" => lambda {|it| it['name'] } },
|
|
78
|
+
{"DESCRIPTION" => lambda {|it| it['description'] } },
|
|
79
|
+
{"INSTANCES" => lambda {|it| it['instances'].size rescue '' } },
|
|
80
|
+
{"SERVERS" => lambda {|it| it['servers'].size rescue '' } },
|
|
81
|
+
{"CLOUDS" => lambda {|it| it['clouds'].size rescue '' } },
|
|
82
|
+
{"OWNER" => lambda {|it| it['owner'] ? it['owner']['username'] : '' } },
|
|
83
|
+
{"DATE CREATED" => lambda {|it| format_local_dt(it['dateCreated']) } },
|
|
84
|
+
{"LAST UPDATED" => lambda {|it| format_local_dt(it['lastUpdated']) } },
|
|
85
|
+
]
|
|
86
|
+
print as_pretty_table(projects, columns, options)
|
|
87
|
+
print_results_pagination(json_response)
|
|
88
|
+
end
|
|
89
|
+
print reset,"\n"
|
|
90
|
+
end
|
|
91
|
+
if projects.empty?
|
|
92
|
+
return 1, "No projects found"
|
|
93
|
+
else
|
|
94
|
+
return 0, nil
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def get(args)
|
|
99
|
+
options = {}
|
|
100
|
+
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
|
101
|
+
opts.banner = subcommand_usage("[workflow]")
|
|
102
|
+
opts.on('--no-content', "Do not display script content." ) do
|
|
103
|
+
options[:no_content] = true
|
|
104
|
+
end
|
|
105
|
+
build_common_options(opts, options, [:json, :yaml, :csv, :fields, :dry_run, :remote])
|
|
106
|
+
opts.footer = <<-EOT
|
|
107
|
+
Get details about a project.
|
|
108
|
+
[project] is required. This is the name or id of a project.
|
|
109
|
+
EOT
|
|
110
|
+
end
|
|
111
|
+
optparse.parse!(args)
|
|
112
|
+
verify_args!(args:args, optparse:optparse, min:1)
|
|
113
|
+
connect(options)
|
|
114
|
+
id_list = parse_id_list(args)
|
|
115
|
+
return run_command_for_each_arg(id_list) do |arg|
|
|
116
|
+
_get(arg, options)
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def _get(id, options)
|
|
121
|
+
@projects_interface.setopts(options)
|
|
122
|
+
if options[:dry_run]
|
|
123
|
+
if id.to_s =~ /\A\d{1,}\Z/
|
|
124
|
+
print_dry_run @projects_interface.dry.get(id.to_i)
|
|
125
|
+
else
|
|
126
|
+
print_dry_run @projects_interface.dry.get({name: id})
|
|
127
|
+
end
|
|
128
|
+
return
|
|
129
|
+
end
|
|
130
|
+
project = find_project_by_name_or_id(id)
|
|
131
|
+
exit 1 if project.nil?
|
|
132
|
+
# refetch it by id
|
|
133
|
+
json_response = {'project' => project}
|
|
134
|
+
unless id.to_s =~ /\A\d{1,}\Z/
|
|
135
|
+
json_response = @projects_interface.get(project['id'])
|
|
136
|
+
end
|
|
137
|
+
project = json_response['project']
|
|
138
|
+
render_response(json_response, options, 'project') do
|
|
139
|
+
print_h1 "Project Details"
|
|
140
|
+
print cyan
|
|
141
|
+
description_cols = {
|
|
142
|
+
"ID" => 'id',
|
|
143
|
+
"Name" => 'name',
|
|
144
|
+
"Description" => 'description',
|
|
145
|
+
"Tags" => lambda {|it| it['tags'] ? it['tags'].collect {|m| "#{m['name']}: #{m['value']}" }.join(', ') : '' },
|
|
146
|
+
"Owner" => lambda {|it| it['owner'] ? it['owner']['username'] : '' },
|
|
147
|
+
"Date Created" => lambda {|it| format_local_dt(it['dateCreated']) },
|
|
148
|
+
"Last Updated" => lambda {|it| format_local_dt(it['lastUpdated']) }
|
|
149
|
+
}
|
|
150
|
+
print_description_list(description_cols, project)
|
|
151
|
+
|
|
152
|
+
project_instances = project["instances"]
|
|
153
|
+
if project_instances && project_instances.size > 0
|
|
154
|
+
print_h2 "Instances"
|
|
155
|
+
print cyan
|
|
156
|
+
print as_pretty_table(project_instances, [:id, :name], options)
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
project_hosts = project["servers"] || project["hosts"]
|
|
160
|
+
if project_hosts && project_hosts.size > 0
|
|
161
|
+
print_h2 "Hosts"
|
|
162
|
+
print cyan
|
|
163
|
+
print as_pretty_table(project_hosts, [:id, :name], options)
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
project_clouds = project["clouds"] || project["zones"]
|
|
167
|
+
if project_clouds && project_clouds.size > 0
|
|
168
|
+
print_h2 "Clouds"
|
|
169
|
+
print cyan
|
|
170
|
+
print as_pretty_table(project_clouds, [:id, :name], options)
|
|
171
|
+
end
|
|
172
|
+
print reset,"\n"
|
|
173
|
+
end
|
|
174
|
+
return 0, nil
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
def add(args)
|
|
178
|
+
exit_code, err = 0, nil
|
|
179
|
+
params, options, payload = {}, {}, {}
|
|
180
|
+
project_name, description, metadata, instance_ids, server_ids, cloud_ids = nil, nil, nil, nil, nil, nil
|
|
181
|
+
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
|
182
|
+
opts.banner = subcommand_usage("[name]")
|
|
183
|
+
opts.on('--name NAME', String, "Project Name" ) do |val|
|
|
184
|
+
project_name = val
|
|
185
|
+
end
|
|
186
|
+
opts.on('--description NAME', String, "Project Description" ) do |val|
|
|
187
|
+
description = val
|
|
188
|
+
end
|
|
189
|
+
opts.on('--tags TAGS', String, "Tags in the format 'name:value, name:value'") do |val|
|
|
190
|
+
metadata = val
|
|
191
|
+
end
|
|
192
|
+
opts.on('--instances [LIST]', Array, "Instances, comma separated list of instance names or IDs.") do |list|
|
|
193
|
+
instance_ids = list.collect {|it| it.to_s.strip.empty? ? nil : it.to_s.strip }.compact.uniq
|
|
194
|
+
end
|
|
195
|
+
opts.on('--servers [LIST]', Array, "Servers, comma separated list of server (host) names or IDs.") do |list|
|
|
196
|
+
server_ids = list.collect {|it| it.to_s.strip.empty? ? nil : it.to_s.strip }.compact.uniq
|
|
197
|
+
end
|
|
198
|
+
opts.on('--clouds [LIST]', Array, "Clouds, comma separated list of cloud names or IDs.") do |list|
|
|
199
|
+
cloud_ids = list.collect {|it| it.to_s.strip.empty? ? nil : it.to_s.strip }.compact.uniq
|
|
200
|
+
end
|
|
201
|
+
build_standard_add_options(opts, options)
|
|
202
|
+
opts.footer = <<-EOT
|
|
203
|
+
Create a project.
|
|
204
|
+
[name] is required. This is the name of the new project.
|
|
205
|
+
EOT
|
|
206
|
+
end
|
|
207
|
+
optparse.parse!(args)
|
|
208
|
+
verify_args!(args:args, optparse:optparse, max:1)
|
|
209
|
+
if args[0]
|
|
210
|
+
project_name = args[0]
|
|
211
|
+
end
|
|
212
|
+
connect(options)
|
|
213
|
+
exit_code, err = 0, nil
|
|
214
|
+
# construct payload
|
|
215
|
+
if options[:payload]
|
|
216
|
+
payload = options[:payload]
|
|
217
|
+
payload.deep_merge!({'project' => parse_passed_options(options)})
|
|
218
|
+
else
|
|
219
|
+
payload['project'] = {}
|
|
220
|
+
payload.deep_merge!({'project' => parse_passed_options(options)})
|
|
221
|
+
payload['project']['name'] = project_name ? project_name : Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'name', 'fieldLabel' => 'Name', 'type' => 'text', 'required' => true, 'description' => 'Project Name'}], options[:options], @api_client)['name']
|
|
222
|
+
payload['project']['description'] = description ? description : Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'description', 'fieldLabel' => 'Description', 'type' => 'text', 'required' => false, 'description' => 'Project Description'}], options[:options], @api_client)['description']
|
|
223
|
+
# metadata tags
|
|
224
|
+
if metadata
|
|
225
|
+
metadata = parse_metadata(metadata)
|
|
226
|
+
payload['project']['tags'] = metadata if metadata
|
|
227
|
+
else
|
|
228
|
+
metadata = prompt_metadata(options)
|
|
229
|
+
payload['project']['tags'] = metadata if metadata
|
|
230
|
+
end
|
|
231
|
+
if instance_ids != nil
|
|
232
|
+
payload['project']['instances'] = parse_instance_id_list(instance_ids).collect { |it| {'id': it.to_i} }
|
|
233
|
+
else
|
|
234
|
+
# could prompt
|
|
235
|
+
end
|
|
236
|
+
# --instances
|
|
237
|
+
if instance_ids
|
|
238
|
+
payload['project']['instances'] = parse_instance_id_list(instance_ids).collect { |it| {'id': it.to_i} }
|
|
239
|
+
end
|
|
240
|
+
# --servers
|
|
241
|
+
if server_ids
|
|
242
|
+
payload['project']['servers'] = parse_server_id_list(server_ids).collect { |it| {'id': it.to_i} }
|
|
243
|
+
end
|
|
244
|
+
# --clouds
|
|
245
|
+
if cloud_ids
|
|
246
|
+
payload['project']['clouds'] = parse_cloud_id_list(cloud_ids).collect { |it| {'id': it.to_i} }
|
|
247
|
+
end
|
|
248
|
+
end
|
|
249
|
+
@projects_interface.setopts(options)
|
|
250
|
+
if options[:dry_run]
|
|
251
|
+
print_dry_run @projects_interface.dry.create(payload)
|
|
252
|
+
return
|
|
253
|
+
end
|
|
254
|
+
json_response = @projects_interface.create(payload)
|
|
255
|
+
project = json_response['project']
|
|
256
|
+
render_response(json_response, options, 'project') do
|
|
257
|
+
print_green_success "Project #{project['name']} created"
|
|
258
|
+
exit_code, err = get([project['id']] + (options[:remote] ? ["-r",options[:remote]] : []))
|
|
259
|
+
end
|
|
260
|
+
return exit_code, err
|
|
261
|
+
end
|
|
262
|
+
|
|
263
|
+
def update(args)
|
|
264
|
+
exit_code, err = 0, nil
|
|
265
|
+
params, options, payload = {}, {}, {}
|
|
266
|
+
project_name, description, metadata, add_metadata, remove_metadata = nil, nil, nil, nil, nil
|
|
267
|
+
instance_ids, server_ids, cloud_ids = nil, nil, nil
|
|
268
|
+
add_instance_ids, remove_instance_ids = nil, nil
|
|
269
|
+
add_server_ids, remove_server_ids = nil, nil
|
|
270
|
+
add_cloud_ids, remove_cloud_ids = nil, nil
|
|
271
|
+
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
|
272
|
+
opts.banner = subcommand_usage("[project] [options]")
|
|
273
|
+
opts.on('--name NAME', String, "Project Name" ) do |val|
|
|
274
|
+
project_name = val
|
|
275
|
+
end
|
|
276
|
+
opts.on('--description NAME', String, "Project Description" ) do |val|
|
|
277
|
+
description = val
|
|
278
|
+
end
|
|
279
|
+
opts.on('--tags [TAGS]', String, "Project Tags in the format 'name:value, name:value'. This replaces all project tags.") do |val|
|
|
280
|
+
metadata = val ? val : []
|
|
281
|
+
end
|
|
282
|
+
opts.on('--add-tags TAGS', String, "Add Project Tags in the format 'name:value, name:value'. This will add/update project tags.") do |val|
|
|
283
|
+
add_metadata = val
|
|
284
|
+
end
|
|
285
|
+
opts.on('--remove-tags TAGS', String, "Remove Project Tags in the format 'name, name:value'. This removes project tags, the :value component is optional and must match if passed.") do |val|
|
|
286
|
+
remove_metadata = val
|
|
287
|
+
end
|
|
288
|
+
opts.on('--instances [LIST]', Array, "Instances, comma separated list of instance names or IDs.") do |list|
|
|
289
|
+
instance_ids = list ? list.collect {|it| it.to_s.strip.empty? ? nil : it.to_s.strip }.compact.uniq : []
|
|
290
|
+
end
|
|
291
|
+
opts.on('--add-instances LIST', Array, "Add Instances, comma separated list of instance names or IDs to add.") do |list|
|
|
292
|
+
add_instance_ids = list.collect {|it| it.to_s.strip.empty? ? nil : it.to_s.strip }.compact.uniq
|
|
293
|
+
end
|
|
294
|
+
opts.on('--remove-instances LIST', Array, "Remove Instances, comma separated list of instance names or IDs to remove.") do |list|
|
|
295
|
+
remove_instance_ids = list.collect {|it| it.to_s.strip.empty? ? nil : it.to_s.strip }.compact.uniq
|
|
296
|
+
end
|
|
297
|
+
opts.on('--servers [LIST]', Array, "Servers, comma separated list of server (host) names or IDs.") do |list|
|
|
298
|
+
server_ids = list ? list.collect {|it| it.to_s.strip.empty? ? nil : it.to_s.strip }.compact.uniq : []
|
|
299
|
+
end
|
|
300
|
+
opts.on('--add-servers LIST', Array, "Add Servers, comma separated list of server names or IDs to add.") do |list|
|
|
301
|
+
add_server_ids = list.collect {|it| it.to_s.strip.empty? ? nil : it.to_s.strip }.compact.uniq
|
|
302
|
+
end
|
|
303
|
+
opts.on('--remove-servers LIST', Array, "Remove Servers, comma separated list of server names or IDs to remove.") do |list|
|
|
304
|
+
remove_server_ids = list.collect {|it| it.to_s.strip.empty? ? nil : it.to_s.strip }.compact.uniq
|
|
305
|
+
end
|
|
306
|
+
opts.on('--clouds [LIST]', Array, "Clouds, comma separated list of cloud names or IDs.") do |list|
|
|
307
|
+
cloud_ids = list ? list.collect {|it| it.to_s.strip.empty? ? nil : it.to_s.strip }.compact.uniq : []
|
|
308
|
+
end
|
|
309
|
+
opts.on('--add-clouds LIST', Array, "Add Clouds, comma separated list of cloud names or IDs to add.") do |list|
|
|
310
|
+
add_cloud_ids = list.collect {|it| it.to_s.strip.empty? ? nil : it.to_s.strip }.compact.uniq
|
|
311
|
+
end
|
|
312
|
+
opts.on('--remove-clouds LIST', Array, "Remove Clouds, comma separated list of cloud names or IDs to remove.") do |list|
|
|
313
|
+
remove_cloud_ids = list.collect {|it| it.to_s.strip.empty? ? nil : it.to_s.strip }.compact.uniq
|
|
314
|
+
end
|
|
315
|
+
build_standard_update_options(opts, options)
|
|
316
|
+
opts.footer = <<-EOT
|
|
317
|
+
Update a project.
|
|
318
|
+
[project] is required. This is the name or id of a project.
|
|
319
|
+
EOT
|
|
320
|
+
end
|
|
321
|
+
optparse.parse!(args)
|
|
322
|
+
verify_args!(args:args, optparse:optparse, count:1)
|
|
323
|
+
connect(options)
|
|
324
|
+
exit_code, err = 0, nil
|
|
325
|
+
project = find_project_by_name_or_id(args[0])
|
|
326
|
+
return 1, "project not found by '#{args[0]}'" if project.nil?
|
|
327
|
+
# construct payload
|
|
328
|
+
if options[:payload]
|
|
329
|
+
payload = options[:payload]
|
|
330
|
+
payload.deep_merge!({'project' => parse_passed_options(options)})
|
|
331
|
+
else
|
|
332
|
+
payload['project'] = {}
|
|
333
|
+
payload.deep_merge!({'project' => parse_passed_options(options)})
|
|
334
|
+
payload['project']['name'] = project_name if project_name
|
|
335
|
+
payload['project']['description'] = description if description
|
|
336
|
+
# metadata tags
|
|
337
|
+
if metadata
|
|
338
|
+
payload['project']['tags'] = parse_metadata(metadata)
|
|
339
|
+
end
|
|
340
|
+
if add_metadata
|
|
341
|
+
payload['project']['addTags'] = parse_metadata(add_metadata)
|
|
342
|
+
end
|
|
343
|
+
if remove_metadata
|
|
344
|
+
payload['project']['removeTags'] = parse_metadata(remove_metadata)
|
|
345
|
+
end
|
|
346
|
+
# --instances
|
|
347
|
+
if instance_ids
|
|
348
|
+
payload['project']['instances'] = parse_instance_id_list(instance_ids).collect { |it| {'id': it.to_i} }
|
|
349
|
+
end
|
|
350
|
+
if add_instance_ids
|
|
351
|
+
payload['project']['addInstances'] = parse_instance_id_list(add_instance_ids).collect { |it| {'id': it.to_i} }
|
|
352
|
+
end
|
|
353
|
+
if remove_instance_ids
|
|
354
|
+
payload['project']['removeInstances'] = parse_instance_id_list(remove_instance_ids).collect { |it| {'id': it.to_i} }
|
|
355
|
+
end
|
|
356
|
+
# --servers
|
|
357
|
+
if server_ids
|
|
358
|
+
payload['project']['servers'] = parse_server_id_list(server_ids).collect { |it| {'id': it.to_i} }
|
|
359
|
+
end
|
|
360
|
+
if add_server_ids
|
|
361
|
+
payload['project']['addServers'] = parse_server_id_list(add_server_ids).collect { |it| {'id': it.to_i} }
|
|
362
|
+
end
|
|
363
|
+
if remove_server_ids
|
|
364
|
+
payload['project']['removeServers'] = parse_server_id_list(remove_server_ids).collect { |it| {'id': it.to_i} }
|
|
365
|
+
end
|
|
366
|
+
# --clouds
|
|
367
|
+
if cloud_ids
|
|
368
|
+
cloud_ids = parse_cloud_id_list(cloud_ids)
|
|
369
|
+
return 1, "clouds not found" if cloud_ids.nil?
|
|
370
|
+
payload['project']['clouds'] = cloud_ids.collect { |it| {'id': it.to_i} }
|
|
371
|
+
end
|
|
372
|
+
if add_cloud_ids
|
|
373
|
+
add_cloud_ids = parse_cloud_id_list(add_cloud_ids)
|
|
374
|
+
return 1, "clouds not found" if add_cloud_ids.nil?
|
|
375
|
+
payload['project']['addClouds'] = add_cloud_ids.collect { |it| {'id': it.to_i} }
|
|
376
|
+
end
|
|
377
|
+
if remove_cloud_ids
|
|
378
|
+
remove_cloud_ids = parse_cloud_id_list(remove_cloud_ids)
|
|
379
|
+
return 1, "clouds not found" if remove_cloud_ids.nil?
|
|
380
|
+
payload['project']['removeClouds'] = remove_cloud_ids.collect { |it| {'id': it.to_i} }
|
|
381
|
+
end
|
|
382
|
+
end
|
|
383
|
+
@projects_interface.setopts(options)
|
|
384
|
+
if options[:dry_run]
|
|
385
|
+
print_dry_run @projects_interface.dry.update(project['id'], payload)
|
|
386
|
+
return
|
|
387
|
+
end
|
|
388
|
+
json_response = @projects_interface.update(project['id'], payload)
|
|
389
|
+
project = json_response['project']
|
|
390
|
+
render_response(json_response, options, 'project') do
|
|
391
|
+
print_green_success "Project #{project['name']} updated"
|
|
392
|
+
exit_code, err = get([project['id']] + (options[:remote] ? ["-r",options[:remote]] : []))
|
|
393
|
+
end
|
|
394
|
+
return exit_code, err
|
|
395
|
+
end
|
|
396
|
+
|
|
397
|
+
def add_tags(args)
|
|
398
|
+
params = {}
|
|
399
|
+
options = {}
|
|
400
|
+
payload = {}
|
|
401
|
+
metadata = nil
|
|
402
|
+
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
|
403
|
+
opts.banner = subcommand_usage("[project] [tag=value] [tag=value]")
|
|
404
|
+
opts.on('--tags TAGS', String, "Project Tags in the format 'name:value, name:value'. This will add/update project tags.") do |val|
|
|
405
|
+
metadata = val
|
|
406
|
+
end
|
|
407
|
+
build_standard_update_options(opts, options)
|
|
408
|
+
opts.footer = <<-EOT
|
|
409
|
+
Add metadata tags to a project.
|
|
410
|
+
[project] is required. This is the name or id of a project.
|
|
411
|
+
[tag=value] is required. This is a metadata tag in the format name=value, 1-N may be passed.
|
|
412
|
+
EOT
|
|
413
|
+
end
|
|
414
|
+
optparse.parse!(args)
|
|
415
|
+
verify_args!(args:args, optparse:optparse, min:1) # maybe min:2 instead ?
|
|
416
|
+
connect(options)
|
|
417
|
+
exit_code, err = 0, nil
|
|
418
|
+
if args.count > 1
|
|
419
|
+
metadata = args[1..-1].join(" ")
|
|
420
|
+
end
|
|
421
|
+
project = find_project_by_name_or_id(args[0])
|
|
422
|
+
return 1, "project not found by '#{args[0]}'" if project.nil?
|
|
423
|
+
# construct payload
|
|
424
|
+
|
|
425
|
+
if options[:payload]
|
|
426
|
+
payload = options[:payload]
|
|
427
|
+
payload.deep_merge!({'project' => parse_passed_options(options)})
|
|
428
|
+
else
|
|
429
|
+
payload['project'] = {}
|
|
430
|
+
payload.deep_merge!({'project' => parse_passed_options(options)})
|
|
431
|
+
if options[:metadata]
|
|
432
|
+
payload['project']['addTags'] = parse_metadata(metadata)
|
|
433
|
+
end
|
|
434
|
+
end
|
|
435
|
+
@projects_interface.setopts(options)
|
|
436
|
+
if options[:dry_run]
|
|
437
|
+
print_dry_run @projects_interface.dry.update(project['id'], payload)
|
|
438
|
+
return
|
|
439
|
+
end
|
|
440
|
+
json_response = @projects_interface.update(project['id'], payload)
|
|
441
|
+
project = json_response['project']
|
|
442
|
+
render_response(json_response, options, 'project') do
|
|
443
|
+
print_green_success "Project #{project['name']} updated"
|
|
444
|
+
exit_code, err = get([project['id']] + (options[:remote] ? ["-r",options[:remote]] : []))
|
|
445
|
+
end
|
|
446
|
+
return exit_code, err
|
|
447
|
+
end
|
|
448
|
+
|
|
449
|
+
def remove_tags(args)
|
|
450
|
+
params = {}
|
|
451
|
+
options = {}
|
|
452
|
+
payload = {}
|
|
453
|
+
metadata = nil
|
|
454
|
+
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
|
455
|
+
opts.banner = subcommand_usage("[project] [tags]")
|
|
456
|
+
opts.on('--tags TAGS', String, "Project Tags in the format 'name=value, name=value'. This will add/update project tags.") do |val|
|
|
457
|
+
metadata = val
|
|
458
|
+
end
|
|
459
|
+
build_standard_update_options(opts, options)
|
|
460
|
+
opts.footer = <<-EOT
|
|
461
|
+
Remove metadata tags from a project.
|
|
462
|
+
[project] is required. This is the name or id of a project.
|
|
463
|
+
[tags] is required. This is a metadata tag in the format tag=value, tag2, tag3, 1-N may be passed, value is optional and must match if passed.
|
|
464
|
+
EOT
|
|
465
|
+
end
|
|
466
|
+
optparse.parse!(args)
|
|
467
|
+
verify_args!(args:args, optparse:optparse, min:1) # maybe min:2 instead ?
|
|
468
|
+
connect(options)
|
|
469
|
+
exit_code, err = 0, nil
|
|
470
|
+
if args.count > 1
|
|
471
|
+
metadata = args[1..-1].join(" ")
|
|
472
|
+
end
|
|
473
|
+
project = find_project_by_name_or_id(args[0])
|
|
474
|
+
return 1, "project not found by '#{args[0]}'" if project.nil?
|
|
475
|
+
# construct payload
|
|
476
|
+
|
|
477
|
+
if options[:payload]
|
|
478
|
+
payload = options[:payload]
|
|
479
|
+
payload.deep_merge!({'project' => parse_passed_options(options)})
|
|
480
|
+
else
|
|
481
|
+
payload['project'] = {}
|
|
482
|
+
payload.deep_merge!({'project' => parse_passed_options(options)})
|
|
483
|
+
if metadata
|
|
484
|
+
payload['project']['removeTags'] = parse_metadata(metadata)
|
|
485
|
+
end
|
|
486
|
+
end
|
|
487
|
+
@projects_interface.setopts(options)
|
|
488
|
+
if options[:dry_run]
|
|
489
|
+
print_dry_run @projects_interface.dry.update(project['id'], payload)
|
|
490
|
+
return
|
|
491
|
+
end
|
|
492
|
+
json_response = @projects_interface.update(project['id'], payload)
|
|
493
|
+
project = json_response['project']
|
|
494
|
+
render_response(json_response, options, 'project') do
|
|
495
|
+
print_green_success "Project #{project['name']} updated"
|
|
496
|
+
exit_code, err = get([project['id']] + (options[:remote] ? ["-r",options[:remote]] : []))
|
|
497
|
+
end
|
|
498
|
+
return exit_code, err
|
|
499
|
+
end
|
|
500
|
+
|
|
501
|
+
def remove(args)
|
|
502
|
+
params = {}
|
|
503
|
+
options = {}
|
|
504
|
+
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
|
505
|
+
opts.banner = subcommand_usage("[project]")
|
|
506
|
+
build_common_options(opts, options, [:auto_confirm, :json, :dry_run, :quiet, :remote])
|
|
507
|
+
# opts.on( '-f', '--force', "Force Delete" ) do
|
|
508
|
+
# params[:force] = true
|
|
509
|
+
# end
|
|
510
|
+
opts.footer = <<-EOT
|
|
511
|
+
Delete a project.
|
|
512
|
+
[project] is required. This is the name or id of a project.
|
|
513
|
+
EOT
|
|
514
|
+
end
|
|
515
|
+
optparse.parse!(args)
|
|
516
|
+
verify_args!(args:args, optparse:optparse, count:1)
|
|
517
|
+
connect(options)
|
|
518
|
+
exit_code, err = 0, nil
|
|
519
|
+
project = find_project_by_name_or_id(args[0])
|
|
520
|
+
return 1, "project not found by '#{args[0]}'" if project.nil?
|
|
521
|
+
unless options[:yes] || Morpheus::Cli::OptionTypes.confirm("Are you sure you want to delete the project #{project['name']}?")
|
|
522
|
+
return 9, "aborted command"
|
|
523
|
+
end
|
|
524
|
+
@projects_interface.setopts(options)
|
|
525
|
+
if options[:dry_run]
|
|
526
|
+
print_dry_run @projects_interface.dry.destroy(project['id'], params)
|
|
527
|
+
return
|
|
528
|
+
end
|
|
529
|
+
json_response = @projects_interface.destroy(project['id'], params)
|
|
530
|
+
render_response(json_response, options) do
|
|
531
|
+
print_green_success "Project #{project['name']} removed"
|
|
532
|
+
end
|
|
533
|
+
return exit_code, err
|
|
534
|
+
end
|
|
535
|
+
|
|
536
|
+
private
|
|
537
|
+
|
|
538
|
+
def find_project_by_name_or_id(val)
|
|
539
|
+
if val.to_s =~ /\A\d{1,}\Z/
|
|
540
|
+
return find_project_by_id(val)
|
|
541
|
+
else
|
|
542
|
+
return find_project_by_name(val)
|
|
543
|
+
end
|
|
544
|
+
end
|
|
545
|
+
|
|
546
|
+
def find_project_by_id(id)
|
|
547
|
+
begin
|
|
548
|
+
json_response = @projects_interface.get(id.to_i)
|
|
549
|
+
return json_response['project']
|
|
550
|
+
rescue RestClient::Exception => e
|
|
551
|
+
if e.response && e.response.code == 404
|
|
552
|
+
print_red_alert "Project not found by id #{id}"
|
|
553
|
+
return nil
|
|
554
|
+
else
|
|
555
|
+
raise e
|
|
556
|
+
end
|
|
557
|
+
end
|
|
558
|
+
end
|
|
559
|
+
|
|
560
|
+
def find_project_by_name(name)
|
|
561
|
+
projects = @projects_interface.list({name: name.to_s})['projects']
|
|
562
|
+
if projects.empty?
|
|
563
|
+
print_red_alert "Project not found by name #{name}"
|
|
564
|
+
return nil
|
|
565
|
+
elsif projects.size > 1
|
|
566
|
+
print_red_alert "#{projects.size} projects by name #{name}"
|
|
567
|
+
print_error "\n"
|
|
568
|
+
puts_error as_pretty_table(projects, [:id, :name], {color:red})
|
|
569
|
+
print_red_alert "Try passing ID instead"
|
|
570
|
+
return nil
|
|
571
|
+
else
|
|
572
|
+
return projects[0]
|
|
573
|
+
end
|
|
574
|
+
end
|
|
575
|
+
|
|
576
|
+
def find_project_type_by_name(val)
|
|
577
|
+
raise "find_project_type_by_name passed a bad name: #{val.inspect}" if val.to_s == ''
|
|
578
|
+
@all_project_types ||= @projects_interface.list_types({max:1000})['projectTypes']
|
|
579
|
+
|
|
580
|
+
if @all_project_types.nil? && !@all_project_types.empty?
|
|
581
|
+
print_red_alert "No project types found"
|
|
582
|
+
return nil
|
|
583
|
+
end
|
|
584
|
+
matching_project_types = @all_project_types.select { |it| val && (it['name'] == val || it['code'] == val || it['id'].to_s == val.to_s) }
|
|
585
|
+
if matching_project_types.size == 1
|
|
586
|
+
return matching_project_types[0]
|
|
587
|
+
elsif matching_project_types.size == 0
|
|
588
|
+
print_red_alert "Project Type not found by '#{val}'"
|
|
589
|
+
else
|
|
590
|
+
print_red_alert "#{matching_project_types.size} project types found by name #{name}"
|
|
591
|
+
rows = matching_project_types.collect do |it|
|
|
592
|
+
{id: it['id'], name: it['name'], code: it['code']}
|
|
593
|
+
end
|
|
594
|
+
print "\n"
|
|
595
|
+
puts as_pretty_table(rows, [:name, :code], {color:red})
|
|
596
|
+
return nil
|
|
597
|
+
end
|
|
598
|
+
end
|
|
599
|
+
|
|
600
|
+
def update_project_option_types(project_type)
|
|
601
|
+
[
|
|
602
|
+
{'fieldName' => 'name', 'fieldLabel' => 'Name', 'type' => 'text', 'required' => true, 'displayOrder' => 0}
|
|
603
|
+
] + project_type['optionTypes']
|
|
604
|
+
end
|
|
605
|
+
|
|
606
|
+
|
|
607
|
+
end
|