morpheus-cli 3.6.9 → 3.6.11
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/lib/morpheus/api/api_client.rb +0 -4
- data/lib/morpheus/api/deploy_interface.rb +12 -8
- data/lib/morpheus/cli.rb +0 -1
- data/lib/morpheus/cli/access_token_command.rb +3 -4
- data/lib/morpheus/cli/account_groups_command.rb +8 -3
- data/lib/morpheus/cli/apps.rb +10 -5
- data/lib/morpheus/cli/archives_command.rb +20 -6
- data/lib/morpheus/cli/boot_scripts_command.rb +5 -2
- data/lib/morpheus/cli/change_password_command.rb +1 -1
- data/lib/morpheus/cli/cli_command.rb +2 -4
- data/lib/morpheus/cli/cloud_datastores_command.rb +3 -2
- data/lib/morpheus/cli/commands/standard/alias_command.rb +10 -14
- data/lib/morpheus/cli/commands/standard/history_command.rb +0 -20
- data/lib/morpheus/cli/commands/standard/man_command.rb +8 -8
- data/lib/morpheus/cli/containers_command.rb +9 -1
- data/lib/morpheus/cli/credentials.rb +2 -1
- data/lib/morpheus/cli/cypher_command.rb +10 -2
- data/lib/morpheus/cli/dashboard_command.rb +1 -0
- data/lib/morpheus/cli/deployments.rb +5 -1
- data/lib/morpheus/cli/deploys.rb +26 -9
- data/lib/morpheus/cli/execute_schedules_command.rb +9 -1
- data/lib/morpheus/cli/execution_request_command.rb +3 -2
- data/lib/morpheus/cli/file_copy_request_command.rb +3 -2
- data/lib/morpheus/cli/hosts.rb +8 -6
- data/lib/morpheus/cli/image_builder_command.rb +14 -10
- data/lib/morpheus/cli/instance_types.rb +2 -1
- data/lib/morpheus/cli/instances.rb +9 -4
- data/lib/morpheus/cli/key_pairs.rb +33 -21
- data/lib/morpheus/cli/library_container_scripts_command.rb +5 -2
- data/lib/morpheus/cli/library_container_templates_command.rb +5 -2
- data/lib/morpheus/cli/library_container_types_command.rb +5 -3
- data/lib/morpheus/cli/library_instance_types_command.rb +6 -2
- data/lib/morpheus/cli/library_layouts_command.rb +5 -3
- data/lib/morpheus/cli/library_option_lists_command.rb +5 -1
- data/lib/morpheus/cli/library_option_types_command.rb +5 -0
- data/lib/morpheus/cli/library_upgrades_command.rb +5 -3
- data/lib/morpheus/cli/license.rb +3 -0
- data/lib/morpheus/cli/load_balancers.rb +10 -1
- data/lib/morpheus/cli/mixins/processes_helper.rb +10 -4
- data/lib/morpheus/cli/monitoring_apps_command.rb +32 -26
- data/lib/morpheus/cli/monitoring_checks_command.rb +35 -27
- data/lib/morpheus/cli/monitoring_contacts_command.rb +19 -16
- data/lib/morpheus/cli/monitoring_groups_command.rb +32 -26
- data/lib/morpheus/cli/monitoring_incidents_command.rb +39 -30
- data/lib/morpheus/cli/network_domains_command.rb +5 -2
- data/lib/morpheus/cli/network_groups_command.rb +5 -2
- data/lib/morpheus/cli/network_pool_servers_command.rb +5 -2
- data/lib/morpheus/cli/network_pools_command.rb +5 -2
- data/lib/morpheus/cli/network_proxies_command.rb +5 -2
- data/lib/morpheus/cli/network_services_command.rb +1 -0
- data/lib/morpheus/cli/networks_command.rb +5 -2
- data/lib/morpheus/cli/packages_command.rb +6 -3
- data/lib/morpheus/cli/policies_command.rb +17 -3
- data/lib/morpheus/cli/power_schedules_command.rb +9 -1
- data/lib/morpheus/cli/preseed_scripts_command.rb +5 -2
- data/lib/morpheus/cli/processes_command.rb +17 -6
- data/lib/morpheus/cli/recent_activity_command.rb +1 -0
- data/lib/morpheus/cli/remote.rb +1 -0
- data/lib/morpheus/cli/roles.rb +14 -5
- data/lib/morpheus/cli/security_group_rules.rb +8 -4
- data/lib/morpheus/cli/security_groups.rb +4 -0
- data/lib/morpheus/cli/shell.rb +13 -23
- data/lib/morpheus/cli/storage_providers_command.rb +12 -6
- data/lib/morpheus/cli/tasks.rb +6 -0
- data/lib/morpheus/cli/tenants_command.rb +13 -9
- data/lib/morpheus/cli/user_groups_command.rb +7 -1
- data/lib/morpheus/cli/user_settings_command.rb +7 -1
- data/lib/morpheus/cli/user_sources_command.rb +10 -8
- data/lib/morpheus/cli/users.rb +7 -2
- data/lib/morpheus/cli/version.rb +1 -1
- data/lib/morpheus/cli/virtual_images.rb +8 -1
- data/lib/morpheus/cli/whoami.rb +34 -15
- data/lib/morpheus/cli/workflows.rb +5 -0
- data/lib/morpheus/formatters.rb +4 -0
- data/lib/morpheus/rest_client.rb +6 -1
- metadata +2 -4
- data/lib/morpheus/api/app_templates_interface.rb +0 -64
- data/lib/morpheus/cli/app_templates.rb +0 -2019
data/lib/morpheus/cli/whoami.rb
CHANGED
@@ -68,7 +68,7 @@ class Morpheus::Cli::Whoami
|
|
68
68
|
opts.on('-t','--token-only', "Print your access token only") do
|
69
69
|
access_token_only = true
|
70
70
|
end
|
71
|
-
build_common_options(opts, options, [:json, :remote, :dry_run])
|
71
|
+
build_common_options(opts, options, [:json, :remote, :dry_run, :quiet])
|
72
72
|
end
|
73
73
|
optparse.parse!(args)
|
74
74
|
connect(options)
|
@@ -83,10 +83,14 @@ class Morpheus::Cli::Whoami
|
|
83
83
|
end
|
84
84
|
|
85
85
|
if options[:dry_run]
|
86
|
-
print_dry_run @api_client.whoami.dry.get(params
|
86
|
+
print_dry_run @api_client.whoami.setopts(options).dry.get(params)
|
87
87
|
return 0
|
88
88
|
end
|
89
89
|
|
90
|
+
# todo: fix potential issue here, should be able to use --remote-url or --username
|
91
|
+
# in which case you do not have to be logged in (saved credentials)...
|
92
|
+
# maybe just update connect() to do @api_client = establish_remote_appliance_connection(opts)
|
93
|
+
# wallet = Morpheus::Cli::Credentials.new(@appliance_name, @appliance_url).request_credentials(options)
|
90
94
|
wallet = Morpheus::Cli::Credentials.new(@appliance_name, @appliance_url).load_saved_credentials()
|
91
95
|
token = wallet ? wallet['access_token'] : nil
|
92
96
|
if !token
|
@@ -102,16 +106,30 @@ class Morpheus::Cli::Whoami
|
|
102
106
|
end
|
103
107
|
end
|
104
108
|
|
105
|
-
json_response = load_whoami()
|
106
|
-
|
107
|
-
|
109
|
+
#json_response = load_whoami()
|
110
|
+
|
111
|
+
whoami_interface = @api_client.whoami.setopts(options)
|
112
|
+
whoami_response = whoami_interface.get()
|
113
|
+
json_response = whoami_response
|
114
|
+
@current_user = whoami_response["user"]
|
115
|
+
if @current_user.empty?
|
116
|
+
print_red_alert "Unauthenticated. Please login."
|
117
|
+
exit 1
|
118
|
+
end
|
119
|
+
@is_master_account = whoami_response["isMasterAccount"]
|
120
|
+
@user_permissions = whoami_response["permissions"]
|
108
121
|
|
122
|
+
if whoami_response["appliance"]
|
123
|
+
@appliance_build_verison = whoami_response["appliance"]["buildVersion"]
|
124
|
+
else
|
125
|
+
@appliance_build_verison = nil
|
126
|
+
end
|
109
127
|
|
110
128
|
if access_token_only
|
111
129
|
if options[:quiet]
|
112
|
-
return 1
|
130
|
+
return @current_user ? 0 : 1
|
113
131
|
end
|
114
|
-
if
|
132
|
+
if @access_token.nil?
|
115
133
|
print yellow,"\n","No access token. Please login",reset,"\n"
|
116
134
|
return false
|
117
135
|
end
|
@@ -121,14 +139,15 @@ class Morpheus::Cli::Whoami
|
|
121
139
|
|
122
140
|
if username_only
|
123
141
|
if options[:quiet]
|
124
|
-
return 1
|
142
|
+
return @current_user ? 0 : 1
|
125
143
|
end
|
126
|
-
if
|
127
|
-
|
144
|
+
if @current_user.nil?
|
145
|
+
puts_error "(logged out)" # "(anonymous)" || ""
|
128
146
|
return 1
|
147
|
+
else
|
148
|
+
print cyan,@current_user['username'].to_s,reset,"\n"
|
149
|
+
return 0
|
129
150
|
end
|
130
|
-
print cyan,user['username'].to_s,reset,"\n"
|
131
|
-
return 0
|
132
151
|
end
|
133
152
|
|
134
153
|
|
@@ -145,7 +164,7 @@ class Morpheus::Cli::Whoami
|
|
145
164
|
print JSON.pretty_generate(json_response)
|
146
165
|
print "\n"
|
147
166
|
else
|
148
|
-
if
|
167
|
+
if @current_user.nil?
|
149
168
|
print yellow,"\n","No active session. Please login",reset,"\n"
|
150
169
|
exit 1
|
151
170
|
end
|
@@ -162,7 +181,7 @@ class Morpheus::Cli::Whoami
|
|
162
181
|
"Username" => 'username',
|
163
182
|
"Email" => 'email',
|
164
183
|
"Role" => lambda {|it| format_user_role_names(it) }
|
165
|
-
},
|
184
|
+
}, @current_user)
|
166
185
|
print cyan
|
167
186
|
|
168
187
|
if options[:include_feature_access]
|
@@ -211,7 +230,7 @@ class Morpheus::Cli::Whoami
|
|
211
230
|
begin
|
212
231
|
now = Time.now.to_i
|
213
232
|
app_map = ::Morpheus::Cli::Remote.load_remote(@appliance_name)
|
214
|
-
app_map[:username] =
|
233
|
+
app_map[:username] = @current_user['username']
|
215
234
|
app_map[:authenticated] = true
|
216
235
|
app_map[:status] = 'ready'
|
217
236
|
app_map[:build_version] = @appliance_build_verison if @appliance_build_verison
|
@@ -38,6 +38,7 @@ class Morpheus::Cli::Workflows
|
|
38
38
|
begin
|
39
39
|
params = {}
|
40
40
|
params.merge!(parse_list_options(options))
|
41
|
+
@task_sets_interface.setopts(options)
|
41
42
|
if options[:dry_run]
|
42
43
|
print_dry_run @task_sets_interface.dry.get(params)
|
43
44
|
return
|
@@ -127,6 +128,7 @@ class Morpheus::Cli::Workflows
|
|
127
128
|
payload['taskSet']['tasks'] = tasks
|
128
129
|
end
|
129
130
|
end
|
131
|
+
@task_sets_interface.setopts(options)
|
130
132
|
if options[:dry_run]
|
131
133
|
print_dry_run @task_sets_interface.dry.create(payload)
|
132
134
|
return
|
@@ -166,6 +168,7 @@ class Morpheus::Cli::Workflows
|
|
166
168
|
def _get(id, options)
|
167
169
|
workflow_name = id
|
168
170
|
begin
|
171
|
+
@task_sets_interface.setopts(options)
|
169
172
|
if options[:dry_run]
|
170
173
|
if workflow_name.to_s =~ /\A\d{1,}\Z/
|
171
174
|
print_dry_run @task_sets_interface.dry.get(workflow_name.to_i)
|
@@ -288,6 +291,7 @@ class Morpheus::Cli::Workflows
|
|
288
291
|
payload['taskSet']['tasks'] = tasks
|
289
292
|
end
|
290
293
|
end
|
294
|
+
@task_sets_interface.setopts(options)
|
291
295
|
if options[:dry_run]
|
292
296
|
print_dry_run @task_sets_interface.dry.update(workflow['id'], payload)
|
293
297
|
return
|
@@ -324,6 +328,7 @@ class Morpheus::Cli::Workflows
|
|
324
328
|
unless options[:yes] || Morpheus::Cli::OptionTypes.confirm("Are you sure you want to delete the workflow #{workflow['name']}?")
|
325
329
|
exit 1
|
326
330
|
end
|
331
|
+
@task_sets_interface.setopts(options)
|
327
332
|
if options[:dry_run]
|
328
333
|
print_dry_run @task_sets_interface.dry.destroy(workflow['id'])
|
329
334
|
return
|
data/lib/morpheus/formatters.rb
CHANGED
data/lib/morpheus/rest_client.rb
CHANGED
@@ -18,7 +18,12 @@ module Morpheus
|
|
18
18
|
end
|
19
19
|
|
20
20
|
def execute(options)
|
21
|
-
|
21
|
+
default_opts = {}
|
22
|
+
# only read requests get default 30 second timeout.
|
23
|
+
if options[:method] == :get || options[:method] == :head
|
24
|
+
default_opts[:timeout] = 30
|
25
|
+
end
|
26
|
+
opts = default_opts.merge(options)
|
22
27
|
unless ssl_verification_enabled?
|
23
28
|
opts[:verify_ssl] = OpenSSL::SSL::VERIFY_NONE
|
24
29
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: morpheus-cli
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.6.
|
4
|
+
version: 3.6.11
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- David Estes
|
@@ -11,7 +11,7 @@ authors:
|
|
11
11
|
autorequire:
|
12
12
|
bindir: bin
|
13
13
|
cert_chain: []
|
14
|
-
date: 2019-02-
|
14
|
+
date: 2019-02-22 00:00:00.000000000 Z
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
17
|
name: bundler
|
@@ -173,7 +173,6 @@ files:
|
|
173
173
|
- lib/morpheus/api/account_groups_interface.rb
|
174
174
|
- lib/morpheus/api/accounts_interface.rb
|
175
175
|
- lib/morpheus/api/api_client.rb
|
176
|
-
- lib/morpheus/api/app_templates_interface.rb
|
177
176
|
- lib/morpheus/api/apps_interface.rb
|
178
177
|
- lib/morpheus/api/archive_buckets_interface.rb
|
179
178
|
- lib/morpheus/api/archive_files_interface.rb
|
@@ -250,7 +249,6 @@ files:
|
|
250
249
|
- lib/morpheus/cli/access_token_command.rb
|
251
250
|
- lib/morpheus/cli/account_groups_command.rb
|
252
251
|
- lib/morpheus/cli/accounts.rb
|
253
|
-
- lib/morpheus/cli/app_templates.rb
|
254
252
|
- lib/morpheus/cli/apps.rb
|
255
253
|
- lib/morpheus/cli/archives_command.rb
|
256
254
|
- lib/morpheus/cli/auth_command.rb
|
@@ -1,64 +0,0 @@
|
|
1
|
-
require 'morpheus/api/api_client'
|
2
|
-
|
3
|
-
class Morpheus::AppTemplatesInterface < Morpheus::APIClient
|
4
|
-
def initialize(access_token, refresh_token,expires_at = nil, base_url=nil)
|
5
|
-
@access_token = access_token
|
6
|
-
@refresh_token = refresh_token
|
7
|
-
@base_url = base_url
|
8
|
-
@expires_at = expires_at
|
9
|
-
end
|
10
|
-
|
11
|
-
def get(id)
|
12
|
-
raise "#{self.class}.get() passed a blank id!" if id.to_s == ''
|
13
|
-
url = "#{@base_url}/api/app-templates/#{id}"
|
14
|
-
headers = { params: {}, authorization: "Bearer #{@access_token}" }
|
15
|
-
execute(method: :get, url: url, headers: headers)
|
16
|
-
end
|
17
|
-
|
18
|
-
def list(params={})
|
19
|
-
url = "#{@base_url}/api/app-templates"
|
20
|
-
headers = { params: params, authorization: "Bearer #{@access_token}" }
|
21
|
-
execute(method: :get, url: url, headers: headers)
|
22
|
-
end
|
23
|
-
|
24
|
-
def create(payload)
|
25
|
-
url = "#{@base_url}/api/app-templates"
|
26
|
-
headers = { :authorization => "Bearer #{@access_token}", 'Content-Type' => 'application/json' }
|
27
|
-
execute(method: :post, url: url, headers: headers, payload: payload.to_json)
|
28
|
-
end
|
29
|
-
|
30
|
-
def update(id, payload)
|
31
|
-
url = "#{@base_url}/api/app-templates/#{id}"
|
32
|
-
headers = { :authorization => "Bearer #{@access_token}", 'Content-Type' => 'application/json' }
|
33
|
-
execute(method: :put, url: url, headers: headers, payload: payload.to_json)
|
34
|
-
end
|
35
|
-
|
36
|
-
# multipart image upload
|
37
|
-
def save_image(id, image_file, params={})
|
38
|
-
url = "#{@base_url}/api/app-templates/#{id}/image"
|
39
|
-
headers = { :params => params, :authorization => "Bearer #{@access_token}"}
|
40
|
-
payload = {}
|
41
|
-
payload[:templateImage] = image_file
|
42
|
-
payload[:multipart] = true
|
43
|
-
execute(method: :post, url: url, headers: headers, payload: payload)
|
44
|
-
end
|
45
|
-
|
46
|
-
def duplicate(id, payload)
|
47
|
-
url = "#{@base_url}/api/app-templates/#{id}/duplicate"
|
48
|
-
headers = { :authorization => "Bearer #{@access_token}", 'Content-Type' => 'application/json' }
|
49
|
-
execute(method: :post, url: url, headers: headers, payload: payload.to_json)
|
50
|
-
end
|
51
|
-
|
52
|
-
def destroy(id)
|
53
|
-
url = "#{@base_url}/api/app-templates/#{id}"
|
54
|
-
headers = { :authorization => "Bearer #{@access_token}", 'Content-Type' => 'application/json' }
|
55
|
-
execute(method: :delete, url: url, headers: headers)
|
56
|
-
end
|
57
|
-
|
58
|
-
def list_tiers(params={})
|
59
|
-
url = "#{@base_url}/api/app-templates/tiers"
|
60
|
-
headers = { params: params, authorization: "Bearer #{@access_token}" }
|
61
|
-
execute(method: :get, url: url, headers: headers)
|
62
|
-
end
|
63
|
-
|
64
|
-
end
|
@@ -1,2019 +0,0 @@
|
|
1
|
-
require 'io/console'
|
2
|
-
require 'rest_client'
|
3
|
-
require 'optparse'
|
4
|
-
require 'morpheus/cli/cli_command'
|
5
|
-
require 'morpheus/cli/option_types'
|
6
|
-
require 'json'
|
7
|
-
|
8
|
-
# deprecated and replaced with blueprints, hidden for now
|
9
|
-
class Morpheus::Cli::AppTemplates
|
10
|
-
include Morpheus::Cli::CliCommand
|
11
|
-
include Morpheus::Cli::ProvisioningHelper
|
12
|
-
|
13
|
-
set_command_hidden
|
14
|
-
|
15
|
-
register_subcommands :list, :get, :add, :update, :remove
|
16
|
-
register_subcommands :duplicate
|
17
|
-
register_subcommands :'upload-image' => :upload_image
|
18
|
-
register_subcommands :'available-tiers'
|
19
|
-
register_subcommands :'add-tier', :'update-tier', :'remove-tier', :'connect-tiers', :'disconnect-tiers'
|
20
|
-
register_subcommands :'add-instance'
|
21
|
-
#register_subcommands :'update-instance'
|
22
|
-
register_subcommands :'remove-instance'
|
23
|
-
register_subcommands :'add-instance-config'
|
24
|
-
#register_subcommands :'update-instance-config'
|
25
|
-
register_subcommands :'remove-instance-config'
|
26
|
-
# alias_subcommand :details, :get
|
27
|
-
# set_default_subcommand :list
|
28
|
-
|
29
|
-
def initialize()
|
30
|
-
# @appliance_name, @appliance_url = Morpheus::Cli::Remote.active_appliance
|
31
|
-
end
|
32
|
-
|
33
|
-
def connect(opts)
|
34
|
-
@api_client = establish_remote_appliance_connection(opts)
|
35
|
-
@app_templates_interface = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url).app_templates
|
36
|
-
@groups_interface = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url).groups
|
37
|
-
@instances_interface = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url).instances
|
38
|
-
@instance_types_interface = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url).instance_types
|
39
|
-
@options_interface = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url).options
|
40
|
-
@active_group_id = Morpheus::Cli::Groups.active_groups[@appliance_name]
|
41
|
-
end
|
42
|
-
|
43
|
-
def handle(args)
|
44
|
-
handle_subcommand(args)
|
45
|
-
end
|
46
|
-
|
47
|
-
def list(args)
|
48
|
-
options = {}
|
49
|
-
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
50
|
-
opts.banner = subcommand_usage()
|
51
|
-
build_common_options(opts, options, [:list, :json, :yaml, :csv, :fields, :dry_run, :remote])
|
52
|
-
opts.footer = "List app templates."
|
53
|
-
end
|
54
|
-
optparse.parse!(args)
|
55
|
-
connect(options)
|
56
|
-
begin
|
57
|
-
params = {}
|
58
|
-
[:phrase, :offset, :max, :sort, :direction].each do |k|
|
59
|
-
params[k] = options[k] unless options[k].nil?
|
60
|
-
end
|
61
|
-
if options[:dry_run]
|
62
|
-
print_dry_run @app_templates_interface.dry.list(params)
|
63
|
-
return
|
64
|
-
end
|
65
|
-
|
66
|
-
json_response = @app_templates_interface.list(params)
|
67
|
-
app_templates = json_response['appTemplates']
|
68
|
-
|
69
|
-
if options[:json]
|
70
|
-
puts as_json(json_response, options, "appTemplates")
|
71
|
-
return 0
|
72
|
-
elsif options[:csv]
|
73
|
-
puts records_as_csv(json_response['appTemplates'], options)
|
74
|
-
return 0
|
75
|
-
elsif options[:yaml]
|
76
|
-
puts as_yaml(json_response, options, "appTemplates")
|
77
|
-
return 0
|
78
|
-
end
|
79
|
-
|
80
|
-
|
81
|
-
title = "Morpheus App Templates"
|
82
|
-
subtitles = []
|
83
|
-
if params[:phrase]
|
84
|
-
subtitles << "Search: #{params[:phrase]}".strip
|
85
|
-
end
|
86
|
-
print_h1 title, subtitles
|
87
|
-
if app_templates.empty?
|
88
|
-
print cyan,"No app templates found.",reset,"\n"
|
89
|
-
else
|
90
|
-
print_app_templates_table(app_templates, options)
|
91
|
-
print_results_pagination(json_response)
|
92
|
-
end
|
93
|
-
print reset,"\n"
|
94
|
-
return 0
|
95
|
-
|
96
|
-
rescue RestClient::Exception => e
|
97
|
-
print_rest_exception(e, options)
|
98
|
-
exit 1
|
99
|
-
end
|
100
|
-
end
|
101
|
-
|
102
|
-
def get(args)
|
103
|
-
options = {}
|
104
|
-
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
105
|
-
opts.banner = subcommand_usage("[template]")
|
106
|
-
opts.on( '-c', '--config', "Display raw config only. Default is YAML. Combine with -j for JSON instead." ) do
|
107
|
-
options[:show_config] = true
|
108
|
-
end
|
109
|
-
build_common_options(opts, options, [:json, :yaml, :csv, :fields, :dry_run, :remote])
|
110
|
-
opts.footer = "Get details about an app template.\n" +
|
111
|
-
"[template] is required. This is the name or id of an app template."
|
112
|
-
end
|
113
|
-
optparse.parse!(args)
|
114
|
-
if args.count < 1
|
115
|
-
puts optparse
|
116
|
-
exit 1
|
117
|
-
end
|
118
|
-
connect(options)
|
119
|
-
begin
|
120
|
-
if options[:dry_run]
|
121
|
-
if args[0].to_s =~ /\A\d{1,}\Z/
|
122
|
-
print_dry_run @app_templates_interface.dry.get(args[0].to_i)
|
123
|
-
else
|
124
|
-
print_dry_run @app_templates_interface.dry.list({name:args[0]})
|
125
|
-
end
|
126
|
-
return
|
127
|
-
end
|
128
|
-
app_template = find_app_template_by_name_or_id(args[0])
|
129
|
-
exit 1 if app_template.nil?
|
130
|
-
|
131
|
-
json_response = {'appTemplate' => app_template} # skip redundant request
|
132
|
-
#json_response = @app_templates_interface.get(app_template['id'])
|
133
|
-
app_template = json_response['appTemplate']
|
134
|
-
|
135
|
-
if options[:show_config]
|
136
|
-
#print_h2 "RAW"
|
137
|
-
if options[:json]
|
138
|
-
print cyan
|
139
|
-
print "// JSON config for Morpheus App Template: #{app_template['name']}","\n"
|
140
|
-
print reset
|
141
|
-
puts as_json(app_template["config"])
|
142
|
-
else
|
143
|
-
print cyan
|
144
|
-
print "# YAML config for Morpheus App Template: #{app_template['name']}","\n"
|
145
|
-
print reset
|
146
|
-
puts as_yaml(app_template["config"])
|
147
|
-
end
|
148
|
-
return 0
|
149
|
-
end
|
150
|
-
|
151
|
-
if options[:json]
|
152
|
-
puts as_json(json_response, options, "appTemplate")
|
153
|
-
return 0
|
154
|
-
elsif options[:yaml]
|
155
|
-
puts as_yaml(json_response, options, "appTemplate")
|
156
|
-
return 0
|
157
|
-
elsif options[:csv]
|
158
|
-
puts records_as_csv([json_response['appTemplate']], options)
|
159
|
-
return 0
|
160
|
-
end
|
161
|
-
|
162
|
-
print_h1 "App Template Details"
|
163
|
-
|
164
|
-
print_app_template_details(app_template)
|
165
|
-
|
166
|
-
print reset,"\n"
|
167
|
-
|
168
|
-
rescue RestClient::Exception => e
|
169
|
-
print_rest_exception(e, options)
|
170
|
-
exit 1
|
171
|
-
end
|
172
|
-
end
|
173
|
-
|
174
|
-
def add(args)
|
175
|
-
options = {}
|
176
|
-
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
177
|
-
opts.banner = subcommand_usage("[name] [options]")
|
178
|
-
opts.on('--config JSON', String, "App Template Config JSON") do |val|
|
179
|
-
options['config'] = JSON.parse(val.to_s)
|
180
|
-
end
|
181
|
-
opts.on('--config-yaml YAML', String, "App Template Config YAML") do |val|
|
182
|
-
options['config'] = YAML.load(val.to_s)
|
183
|
-
end
|
184
|
-
opts.on('--config-file FILE', String, "App Template Config from a local JSON or YAML file") do |val|
|
185
|
-
options['configFile'] = val.to_s
|
186
|
-
end
|
187
|
-
build_option_type_options(opts, options, add_app_template_option_types(false))
|
188
|
-
build_common_options(opts, options, [:options, :json, :dry_run, :remote])
|
189
|
-
opts.footer = "Create a new app template.\n" +
|
190
|
-
"[name] is optional and can be passed as --name or inside the config instead."
|
191
|
-
"[--config] or [--config-file] can be used to define the app template."
|
192
|
-
end
|
193
|
-
optparse.parse!(args)
|
194
|
-
if args.count > 1
|
195
|
-
print_error Morpheus::Terminal.angry_prompt
|
196
|
-
puts_error "#{command_name} add expects 0-1 arguments and received #{args.count}: #{args.join(' ')}\n#{optparse}"
|
197
|
-
return 1
|
198
|
-
end
|
199
|
-
options[:options] ||= {}
|
200
|
-
if args[0] && !options[:options]['name']
|
201
|
-
options[:options]['name'] = args[0]
|
202
|
-
end
|
203
|
-
connect(options)
|
204
|
-
begin
|
205
|
-
request_payload = nil
|
206
|
-
config_payload = {}
|
207
|
-
if options['config']
|
208
|
-
config_payload = options['config']
|
209
|
-
request_payload = config_payload
|
210
|
-
elsif options['configFile']
|
211
|
-
config_file = File.expand_path(options['configFile'])
|
212
|
-
if !File.exists?(config_file) || !File.file?(config_file)
|
213
|
-
print_red_alert "File not found: #{config_file}"
|
214
|
-
return false
|
215
|
-
end
|
216
|
-
if config_file =~ /\.ya?ml\Z/
|
217
|
-
config_payload = YAML.load_file(config_file)
|
218
|
-
else
|
219
|
-
config_payload = JSON.parse(File.read(config_file))
|
220
|
-
end
|
221
|
-
request_payload = config_payload
|
222
|
-
else
|
223
|
-
params = Morpheus::Cli::OptionTypes.prompt(add_app_template_option_types, options[:options], @api_client, options[:params])
|
224
|
-
app_template_payload = params.select {|k,v| ['name', 'description', 'category'].include?(k) }
|
225
|
-
# expects no namespace, just the config
|
226
|
-
request_payload = app_template_payload
|
227
|
-
end
|
228
|
-
|
229
|
-
if options[:dry_run]
|
230
|
-
print_dry_run @app_templates_interface.dry.create(request_payload)
|
231
|
-
return
|
232
|
-
end
|
233
|
-
|
234
|
-
json_response = @app_templates_interface.create(request_payload)
|
235
|
-
|
236
|
-
if options[:json]
|
237
|
-
print JSON.pretty_generate(json_response)
|
238
|
-
print "\n"
|
239
|
-
else
|
240
|
-
app_template = json_response["appTemplate"]
|
241
|
-
print_green_success "Added app template #{app_template['name']}"
|
242
|
-
if !options[:no_prompt]
|
243
|
-
if ::Morpheus::Cli::OptionTypes::confirm("Would you like to add a tier now?", options.merge({default: false}))
|
244
|
-
add_tier([app_template['id']])
|
245
|
-
while ::Morpheus::Cli::OptionTypes::confirm("Add another tier?", options.merge({default: false})) do
|
246
|
-
add_tier([app_template['id']])
|
247
|
-
end
|
248
|
-
else
|
249
|
-
# print details
|
250
|
-
get([app_template['id']])
|
251
|
-
end
|
252
|
-
end
|
253
|
-
end
|
254
|
-
|
255
|
-
rescue RestClient::Exception => e
|
256
|
-
print_rest_exception(e, options)
|
257
|
-
exit 1
|
258
|
-
end
|
259
|
-
end
|
260
|
-
|
261
|
-
def update(args)
|
262
|
-
options = {}
|
263
|
-
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
264
|
-
opts.banner = subcommand_usage("[template] [options]")
|
265
|
-
opts.on('--config JSON', String, "App Template Config JSON") do |val|
|
266
|
-
options['config'] = JSON.parse(val.to_s)
|
267
|
-
end
|
268
|
-
opts.on('--config-yaml YAML', String, "App Template Config YAML") do |val|
|
269
|
-
options['config'] = YAML.load(val.to_s)
|
270
|
-
end
|
271
|
-
opts.on('--config-file FILE', String, "App Template Config from a local JSON or YAML file") do |val|
|
272
|
-
options['configFile'] = val.to_s
|
273
|
-
end
|
274
|
-
build_option_type_options(opts, options, update_app_template_option_types(false))
|
275
|
-
build_common_options(opts, options, [:options, :json, :dry_run, :quiet, :remote])
|
276
|
-
opts.footer = "Update an app template.\n" +
|
277
|
-
"[template] is required. This is the name or id of an app template.\n" +
|
278
|
-
"[options] Available options include --name and --description. This will update only the specified values.\n" +
|
279
|
-
"[--config] or [--config-file] can be used to replace the entire app template."
|
280
|
-
end
|
281
|
-
optparse.parse!(args)
|
282
|
-
|
283
|
-
if args.count < 1
|
284
|
-
puts optparse
|
285
|
-
exit 1
|
286
|
-
end
|
287
|
-
|
288
|
-
connect(options)
|
289
|
-
|
290
|
-
begin
|
291
|
-
|
292
|
-
app_template = find_app_template_by_name_or_id(args[0])
|
293
|
-
exit 1 if app_template.nil?
|
294
|
-
|
295
|
-
request_payload = nil
|
296
|
-
config_payload = {}
|
297
|
-
if options['config']
|
298
|
-
config_payload = options['config']
|
299
|
-
request_payload = config_payload
|
300
|
-
elsif options['configFile']
|
301
|
-
config_file = options['configFile']
|
302
|
-
if !File.exists?(config_file)
|
303
|
-
print_red_alert "File not found: #{config_file}"
|
304
|
-
return false
|
305
|
-
end
|
306
|
-
if config_file =~ /\.ya?ml\Z/
|
307
|
-
config_payload = YAML.load_file(config_file)
|
308
|
-
else
|
309
|
-
config_payload = JSON.parse(File.read(config_file))
|
310
|
-
end
|
311
|
-
request_payload = config_payload
|
312
|
-
else
|
313
|
-
# update just name,description,category
|
314
|
-
# preserve all other attributes of the config..
|
315
|
-
|
316
|
-
#params = Morpheus::Cli::OptionTypes.prompt(update_app_template_option_types, options[:options], @api_client, options[:params])
|
317
|
-
params = options[:options] || {}
|
318
|
-
|
319
|
-
if params.empty?
|
320
|
-
# print_red_alert "Specify atleast one option to update"
|
321
|
-
print_red_alert "Specify atleast one option to update.\nOr use --config or --config-file to replace the entire config."
|
322
|
-
puts optparse
|
323
|
-
exit 1
|
324
|
-
end
|
325
|
-
|
326
|
-
#puts "parsed params is : #{params.inspect}"
|
327
|
-
app_template_payload = params.select {|k,v| ['name','description','category'].include?(k) }
|
328
|
-
# expects no namespace, just the config
|
329
|
-
# preserve all other attributes of the config.
|
330
|
-
request_payload = app_template["config"].merge(app_template_payload)
|
331
|
-
# todo maybe: put name, description and category at the front.
|
332
|
-
# request_payload = app_template_payload.merge(app_template["config"].merge(app_template_payload))
|
333
|
-
end
|
334
|
-
|
335
|
-
if options[:dry_run]
|
336
|
-
print_dry_run @app_templates_interface.dry.update(app_template['id'], request_payload)
|
337
|
-
return
|
338
|
-
end
|
339
|
-
|
340
|
-
json_response = @app_templates_interface.update(app_template['id'], request_payload)
|
341
|
-
|
342
|
-
if options[:json]
|
343
|
-
print JSON.pretty_generate(json_response)
|
344
|
-
print "\n"
|
345
|
-
else
|
346
|
-
unless options[:quiet]
|
347
|
-
app_template = json_response['appTemplate']
|
348
|
-
print_green_success "Updated app template #{app_template['name']}"
|
349
|
-
details_options = [app_template['id']]
|
350
|
-
get(details_options)
|
351
|
-
end
|
352
|
-
end
|
353
|
-
|
354
|
-
rescue RestClient::Exception => e
|
355
|
-
print_rest_exception(e, options)
|
356
|
-
exit 1
|
357
|
-
end
|
358
|
-
end
|
359
|
-
|
360
|
-
|
361
|
-
def upload_image(args)
|
362
|
-
image_type_name = nil
|
363
|
-
options = {}
|
364
|
-
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
365
|
-
opts.banner = subcommand_usage("[template] [file]")
|
366
|
-
build_common_options(opts, options, [:json, :dry_run, :quiet, :remote])
|
367
|
-
opts.footer = "Upload an image file to be used as the icon for an app template.\n" +
|
368
|
-
"[template] is required. This is the name or id of an app template.\n" +
|
369
|
-
"[file] is required. This is the local path of a file to upload [png|jpg|svg]."
|
370
|
-
end
|
371
|
-
optparse.parse!(args)
|
372
|
-
if args.count != 2
|
373
|
-
print_error Morpheus::Terminal.angry_prompt
|
374
|
-
puts_error "#{command_name} upload-image expects 2 arguments and received #{args.count}: #{args.join(' ')}\n#{optparse}"
|
375
|
-
return 1
|
376
|
-
end
|
377
|
-
app_template_name = args[0]
|
378
|
-
filename = File.expand_path(args[1].to_s)
|
379
|
-
image_file = nil
|
380
|
-
if filename && File.file?(filename)
|
381
|
-
# maybe validate it's an image file? [.png|jpg|svg]
|
382
|
-
image_file = File.new(filename, 'rb')
|
383
|
-
else
|
384
|
-
print_red_alert "File not found: #{filename}"
|
385
|
-
# print_error Morpheus::Terminal.angry_prompt
|
386
|
-
# puts_error "bad argument [file] - File not found: #{filename}\n#{optparse}"
|
387
|
-
return 1
|
388
|
-
end
|
389
|
-
connect(options)
|
390
|
-
begin
|
391
|
-
app_template = find_app_template_by_name_or_id(app_template_name)
|
392
|
-
exit 1 if app_template.nil?
|
393
|
-
if options[:dry_run]
|
394
|
-
print_dry_run @app_templates_interface.dry.save_image(app_template['id'], image_file)
|
395
|
-
return 0
|
396
|
-
end
|
397
|
-
unless options[:quiet] || options[:json]
|
398
|
-
print cyan, "Uploading file #{filename} ...", reset, "\n"
|
399
|
-
end
|
400
|
-
json_response = @app_templates_interface.save_image(app_template['id'], image_file)
|
401
|
-
if options[:json]
|
402
|
-
print JSON.pretty_generate(json_response)
|
403
|
-
elsif !options[:quiet]
|
404
|
-
app_template = json_response['appTemplate']
|
405
|
-
new_image_url = app_template['image']
|
406
|
-
print cyan, "Updated app template #{app_template['name']} image.\nNew image url is: #{new_image_url}", reset, "\n\n"
|
407
|
-
get([app_template['id']])
|
408
|
-
end
|
409
|
-
return 0
|
410
|
-
rescue RestClient::Exception => e
|
411
|
-
print_rest_exception(e, options)
|
412
|
-
return 1
|
413
|
-
end
|
414
|
-
end
|
415
|
-
|
416
|
-
def duplicate(args)
|
417
|
-
options = {}
|
418
|
-
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
419
|
-
opts.banner = subcommand_usage("[template] [new name]")
|
420
|
-
build_common_options(opts, options, [:auto_confirm, :json, :dry_run, :remote])
|
421
|
-
opts.footer = "Duplicate an app template." + "\n" +
|
422
|
-
"[template] is required. This is the name or id of an app template." + "\n" +
|
423
|
-
"[new name] is required. This is the name for the clone."
|
424
|
-
end
|
425
|
-
optparse.parse!(args)
|
426
|
-
|
427
|
-
if args.count < 1
|
428
|
-
puts optparse
|
429
|
-
exit 1
|
430
|
-
end
|
431
|
-
|
432
|
-
request_payload = {"appTemplate" => {}}
|
433
|
-
if args[1]
|
434
|
-
request_payload["appTemplate"]["name"] = args[1]
|
435
|
-
end
|
436
|
-
|
437
|
-
connect(options)
|
438
|
-
begin
|
439
|
-
app_template = find_app_template_by_name_or_id(args[0])
|
440
|
-
exit 1 if app_template.nil?
|
441
|
-
# unless options[:yes] || Morpheus::Cli::OptionTypes.confirm("Are you sure you want to duplicate the app template #{app_template['name']}?")
|
442
|
-
# exit
|
443
|
-
# end
|
444
|
-
if options[:dry_run]
|
445
|
-
print_dry_run @app_templates_interface.dry.duplicate(app_template['id'], request_payload)
|
446
|
-
return
|
447
|
-
end
|
448
|
-
json_response = @app_templates_interface.duplicate(app_template['id'], request_payload)
|
449
|
-
|
450
|
-
if options[:json]
|
451
|
-
print JSON.pretty_generate(json_response)
|
452
|
-
print "\n"
|
453
|
-
else
|
454
|
-
new_app_template = json_response["appTemplate"] || {}
|
455
|
-
print_green_success "Created duplicate app template '#{new_app_template['name']}'"
|
456
|
-
#get([new_app_template["id"]])
|
457
|
-
end
|
458
|
-
|
459
|
-
rescue RestClient::Exception => e
|
460
|
-
print_rest_exception(e, options)
|
461
|
-
exit 1
|
462
|
-
end
|
463
|
-
end
|
464
|
-
|
465
|
-
def remove(args)
|
466
|
-
options = {}
|
467
|
-
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
468
|
-
opts.banner = subcommand_usage("[template]")
|
469
|
-
build_common_options(opts, options, [:auto_confirm, :json, :dry_run, :remote])
|
470
|
-
opts.footer = "Delete an app template." + "\n" +
|
471
|
-
"[template] is required. This is the name or id of an app template."
|
472
|
-
end
|
473
|
-
optparse.parse!(args)
|
474
|
-
|
475
|
-
if args.count < 1
|
476
|
-
puts optparse
|
477
|
-
exit 1
|
478
|
-
end
|
479
|
-
|
480
|
-
connect(options)
|
481
|
-
begin
|
482
|
-
app_template = find_app_template_by_name_or_id(args[0])
|
483
|
-
exit 1 if app_template.nil?
|
484
|
-
unless options[:yes] || Morpheus::Cli::OptionTypes.confirm("Are you sure you want to delete the app template #{app_template['name']}?")
|
485
|
-
exit
|
486
|
-
end
|
487
|
-
if options[:dry_run]
|
488
|
-
print_dry_run @app_templates_interface.dry.destroy(app_template['id'])
|
489
|
-
return
|
490
|
-
end
|
491
|
-
json_response = @app_templates_interface.destroy(app_template['id'])
|
492
|
-
|
493
|
-
if options[:json]
|
494
|
-
print JSON.pretty_generate(json_response)
|
495
|
-
print "\n"
|
496
|
-
else
|
497
|
-
print_green_success "Removed app template #{app_template['name']}"
|
498
|
-
end
|
499
|
-
|
500
|
-
rescue RestClient::Exception => e
|
501
|
-
print_rest_exception(e, options)
|
502
|
-
exit 1
|
503
|
-
end
|
504
|
-
end
|
505
|
-
|
506
|
-
def add_instance(args)
|
507
|
-
options = {}
|
508
|
-
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
509
|
-
opts.banner = subcommand_usage("[template] [tier] [instance-type]")
|
510
|
-
# opts.on( '-g', '--group GROUP', "Group" ) do |val|
|
511
|
-
# options[:group] = val
|
512
|
-
# end
|
513
|
-
# opts.on( '-c', '--cloud CLOUD', "Cloud" ) do |val|
|
514
|
-
# options[:cloud] = val
|
515
|
-
# end
|
516
|
-
opts.on('--name VALUE', String, "Instance Name") do |val|
|
517
|
-
options[:instance_name] = val
|
518
|
-
end
|
519
|
-
build_common_options(opts, options, [:options, :json, :dry_run, :remote])
|
520
|
-
opts.footer = "Update an app template, adding an instance." + "\n" +
|
521
|
-
"[template] is required. This is the name or id of an app template." + "\n" +
|
522
|
-
"[tier] is required and will be prompted for. This is the name of the tier." + "\n" +
|
523
|
-
"[instance-type] is required and will be prompted for. This is the type of instance."
|
524
|
-
end
|
525
|
-
optparse.parse!(args)
|
526
|
-
|
527
|
-
if args.count < 1
|
528
|
-
print_error Morpheus::Terminal.angry_prompt
|
529
|
-
puts_error "#{command_name} add-instance expects 3 arguments and received #{args.count}: #{args.join(' ')}\n#{optparse}"
|
530
|
-
return 1
|
531
|
-
end
|
532
|
-
|
533
|
-
connect(options)
|
534
|
-
|
535
|
-
begin
|
536
|
-
app_template_name = args[0]
|
537
|
-
tier_name = args[1]
|
538
|
-
instance_type_code = args[2]
|
539
|
-
# we also need consider when there is multiple instances of the same type in
|
540
|
-
# a template/tier.. so maybe split instance_type_code as [type-code]:[index].. or...errr
|
541
|
-
|
542
|
-
app_template = find_app_template_by_name_or_id(app_template_name)
|
543
|
-
return 1 if app_template.nil?
|
544
|
-
|
545
|
-
if !tier_name
|
546
|
-
v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'tierName', 'fieldLabel' => 'Tier Name', 'type' => 'text', 'required' => true, 'description' => 'Enter the name of the tier'}], options[:options])
|
547
|
-
tier_name = v_prompt['tierName']
|
548
|
-
end
|
549
|
-
|
550
|
-
if !instance_type_code
|
551
|
-
instance_type_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'type', 'type' => 'select', 'fieldLabel' => 'Type', 'optionSource' => 'instanceTypes', 'required' => true, 'description' => 'Select Instance Type.'}],options[:options],api_client,{})
|
552
|
-
instance_type_code = instance_type_prompt['type']
|
553
|
-
end
|
554
|
-
instance_type = find_instance_type_by_code(instance_type_code)
|
555
|
-
return 1 if instance_type.nil?
|
556
|
-
|
557
|
-
tier_config = nil
|
558
|
-
instance_config = nil
|
559
|
-
|
560
|
-
app_template["config"] ||= {}
|
561
|
-
tiers = app_template["config"]["tiers"]
|
562
|
-
tiers ||= {}
|
563
|
-
# tier identified by name, case sensitive...
|
564
|
-
if !tiers[tier_name]
|
565
|
-
tiers[tier_name] = {}
|
566
|
-
end
|
567
|
-
tier_config = tiers[tier_name]
|
568
|
-
|
569
|
-
tier_config['instances'] ||= []
|
570
|
-
instance_config = tier_config['instances'].find {|it| it["instance"] && it["instance"]["type"] && it["instance"]["type"] == instance_type["code"] }
|
571
|
-
if !instance_config
|
572
|
-
instance_config = {'instance' => {'type' => instance_type['code']} }
|
573
|
-
tier_config['instances'].push(instance_config)
|
574
|
-
end
|
575
|
-
instance_config['instance'] ||= {}
|
576
|
-
|
577
|
-
# just prompts for Instance Name (optional)
|
578
|
-
instance_name = nil
|
579
|
-
if options[:instance_name]
|
580
|
-
instance_name = options[:instance_name]
|
581
|
-
else
|
582
|
-
v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'name', 'fieldLabel' => 'Instance Name', 'type' => 'text', 'defaultValue' => instance_config['instance']['name']}])
|
583
|
-
instance_name = v_prompt['name'] || ''
|
584
|
-
end
|
585
|
-
|
586
|
-
if instance_name
|
587
|
-
if instance_name.to_s == 'null'
|
588
|
-
instance_config['instance'].delete('name')
|
589
|
-
# instance_config['instance']['name'] = ''
|
590
|
-
else
|
591
|
-
instance_config['instance']['name'] = instance_name
|
592
|
-
end
|
593
|
-
end
|
594
|
-
|
595
|
-
# ok, make api request
|
596
|
-
app_template["config"]["tiers"] = tiers
|
597
|
-
request_payload = {appTemplate: app_template}
|
598
|
-
|
599
|
-
if options[:dry_run]
|
600
|
-
print_dry_run @app_templates_interface.dry.update(app_template['id'], request_payload)
|
601
|
-
return 0
|
602
|
-
end
|
603
|
-
|
604
|
-
json_response = @app_templates_interface.update(app_template['id'], request_payload)
|
605
|
-
|
606
|
-
if options[:json]
|
607
|
-
puts JSON.pretty_generate(json_response)
|
608
|
-
elsif !options[:quiet]
|
609
|
-
print_green_success "Instance added to app template #{app_template['name']}"
|
610
|
-
# prompt for new instance
|
611
|
-
if !options[:no_prompt]
|
612
|
-
if ::Morpheus::Cli::OptionTypes::confirm("Would you like to add a config now?", options.merge({default: true}))
|
613
|
-
# todo: this needs to work by index, because you can have multiple instances of the same type
|
614
|
-
add_instance_config([app_template['id'], tier_name, instance_type['code']])
|
615
|
-
while ::Morpheus::Cli::OptionTypes::confirm("Add another config?", options.merge({default: false})) do
|
616
|
-
add_instance_config([app_template['id'], tier_name, instance_type['code']])
|
617
|
-
end
|
618
|
-
else
|
619
|
-
# print details
|
620
|
-
get([app_template['name']])
|
621
|
-
end
|
622
|
-
end
|
623
|
-
end
|
624
|
-
return 0
|
625
|
-
|
626
|
-
rescue RestClient::Exception => e
|
627
|
-
print_rest_exception(e, options)
|
628
|
-
return 1
|
629
|
-
end
|
630
|
-
|
631
|
-
end
|
632
|
-
|
633
|
-
def add_instance_config(args)
|
634
|
-
options = {}
|
635
|
-
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
636
|
-
opts.banner = subcommand_usage("[template] [tier] [instance]")
|
637
|
-
opts.on( '-g', '--group GROUP', "Group" ) do |val|
|
638
|
-
options[:group] = val
|
639
|
-
end
|
640
|
-
opts.on( '-c', '--cloud CLOUD', "Cloud" ) do |val|
|
641
|
-
options[:cloud] = val
|
642
|
-
end
|
643
|
-
opts.on( '-e', '--env ENVIRONMENT', "Environment" ) do |val|
|
644
|
-
options[:environment] = val
|
645
|
-
end
|
646
|
-
opts.on('--name VALUE', String, "Instance Name") do |val|
|
647
|
-
options[:instance_name] = val
|
648
|
-
end
|
649
|
-
build_common_options(opts, options, [:options, :json, :dry_run, :remote])
|
650
|
-
opts.footer = "Update an app template, adding an instance config." + "\n" +
|
651
|
-
"[template] is required. This is the name or id of an app template." + "\n" +
|
652
|
-
"[tier] is required. This is the name of the tier." + "\n" +
|
653
|
-
"[instance] is required. This is the type of instance."
|
654
|
-
end
|
655
|
-
optparse.parse!(args)
|
656
|
-
|
657
|
-
if args.count < 3
|
658
|
-
print_error Morpheus::Terminal.angry_prompt
|
659
|
-
puts_error "Wrong number of arguments"
|
660
|
-
puts_error optparse
|
661
|
-
return 1
|
662
|
-
end
|
663
|
-
|
664
|
-
connect(options)
|
665
|
-
|
666
|
-
begin
|
667
|
-
|
668
|
-
app_template_name = args[0]
|
669
|
-
tier_name = args[1]
|
670
|
-
instance_type_code = args[2]
|
671
|
-
# we also need consider when there is multiple instances of the same type in
|
672
|
-
# a template/tier.. so maybe split instance_type_code as [type-code]:[index].. or...errr
|
673
|
-
|
674
|
-
app_template = find_app_template_by_name_or_id(app_template_name)
|
675
|
-
return 1 if app_template.nil?
|
676
|
-
|
677
|
-
instance_type = find_instance_type_by_code(instance_type_code)
|
678
|
-
return 1 if instance_type.nil?
|
679
|
-
|
680
|
-
tier_config = nil
|
681
|
-
instance_config = nil
|
682
|
-
|
683
|
-
app_template["config"] ||= {}
|
684
|
-
tiers = app_template["config"]["tiers"]
|
685
|
-
tiers ||= {}
|
686
|
-
# tier identified by name, case sensitive...
|
687
|
-
if !tiers[tier_name]
|
688
|
-
tiers[tier_name] = {}
|
689
|
-
end
|
690
|
-
tier_config = tiers[tier_name]
|
691
|
-
|
692
|
-
tier_config['instances'] ||= []
|
693
|
-
instance_config = tier_config['instances'].find {|it| it["instance"] && it["instance"]["type"] && it["instance"]["type"] == instance_type["code"] }
|
694
|
-
if !instance_config
|
695
|
-
instance_config = {'instance' => {'type' => instance_type['code']} }
|
696
|
-
tier_config['instances'].push(instance_config)
|
697
|
-
end
|
698
|
-
instance_config['instance'] ||= {}
|
699
|
-
|
700
|
-
# group prompt
|
701
|
-
|
702
|
-
# use active group by default
|
703
|
-
options[:group] ||= @active_group_id
|
704
|
-
|
705
|
-
|
706
|
-
# available_groups = get_available_groups()
|
707
|
-
# group_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'group', 'fieldLabel' => 'Group', 'type' => 'select', 'selectOptions' => get_available_groups(), 'required' => true, 'defaultValue' => @active_group_id}],options[:options],@api_client,{})
|
708
|
-
|
709
|
-
# group_id = group_prompt['group']
|
710
|
-
# the_group = find_group_by_name_or_id_for_provisioning(group_id)
|
711
|
-
|
712
|
-
# # cloud prompt
|
713
|
-
# cloud_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'cloud', 'type' => 'select', 'fieldLabel' => 'Cloud', 'optionSource' => 'clouds', 'required' => true, 'description' => 'Select Cloud.'}],options[:options],@api_client,{groupId: group_id})
|
714
|
-
# cloud_id = cloud_prompt['cloud']
|
715
|
-
|
716
|
-
# look for existing config for group + cloud
|
717
|
-
|
718
|
-
options[:name_required] = false
|
719
|
-
options[:instance_type_code] = instance_type["code"]
|
720
|
-
|
721
|
-
#options[:options].deep_merge!(specific_config)
|
722
|
-
# this provisioning helper method handles all (most) of the parsing and prompting
|
723
|
-
instance_config_payload = prompt_new_instance(options)
|
724
|
-
|
725
|
-
# strip all empty string and nil, would be problematic for update()
|
726
|
-
instance_config_payload.deep_compact!
|
727
|
-
|
728
|
-
# puts "INSTANCE CONFIG YAML:"
|
729
|
-
# puts as_yaml(instance_config_payload)
|
730
|
-
|
731
|
-
selected_environment = instance_config_payload.delete('instanceContext') || instance_config_payload.delete('environment')
|
732
|
-
# groom provision instance payload for template purposes
|
733
|
-
selected_cloud_id = instance_config_payload.delete('zoneId')
|
734
|
-
selected_site = instance_config_payload['instance'].delete('site')
|
735
|
-
selected_site_id = selected_site['id']
|
736
|
-
|
737
|
-
selected_group = find_group_by_name_or_id_for_provisioning(selected_site_id)
|
738
|
-
selected_cloud = find_cloud_by_name_or_id_for_provisioning(selected_group['id'], selected_cloud_id)
|
739
|
-
|
740
|
-
# store config in environments => env => groups => groupname => clouds => cloudname =>
|
741
|
-
current_config = instance_config
|
742
|
-
if selected_environment.to_s != ''
|
743
|
-
instance_config['environments'] ||= {}
|
744
|
-
instance_config['environments'][selected_environment] ||= {}
|
745
|
-
current_config = instance_config['environments'][selected_environment]
|
746
|
-
end
|
747
|
-
|
748
|
-
current_config['groups'] ||= {}
|
749
|
-
current_config['groups'][selected_group['name']] ||= {}
|
750
|
-
current_config['groups'][selected_group['name']]['clouds'] ||= {}
|
751
|
-
current_config['groups'][selected_group['name']]['clouds'][selected_cloud['name']] = instance_config_payload
|
752
|
-
|
753
|
-
# ok, make api request
|
754
|
-
app_template["config"]["tiers"] = tiers
|
755
|
-
request_payload = {appTemplate: app_template}
|
756
|
-
|
757
|
-
if options[:dry_run]
|
758
|
-
print_dry_run @app_templates_interface.dry.update(app_template['id'], request_payload)
|
759
|
-
return 0
|
760
|
-
end
|
761
|
-
|
762
|
-
json_response = @app_templates_interface.update(app_template['id'], request_payload)
|
763
|
-
|
764
|
-
if options[:json]
|
765
|
-
puts JSON.pretty_generate(json_response)
|
766
|
-
else
|
767
|
-
print_green_success "Instance added to app template #{app_template['name']}"
|
768
|
-
get([app_template['name']])
|
769
|
-
end
|
770
|
-
return 0
|
771
|
-
|
772
|
-
rescue RestClient::Exception => e
|
773
|
-
print_rest_exception(e, options)
|
774
|
-
return 1
|
775
|
-
end
|
776
|
-
|
777
|
-
end
|
778
|
-
|
779
|
-
def remove_instance_config(args)
|
780
|
-
instance_index = nil
|
781
|
-
options = {}
|
782
|
-
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
783
|
-
opts.banner = subcommand_usage("[template] [tier] [instance] -g GROUP -c CLOUD")
|
784
|
-
opts.on( '-g', '--group GROUP', "Group" ) do |val|
|
785
|
-
options[:group] = val
|
786
|
-
end
|
787
|
-
opts.on( '-c', '--cloud CLOUD', "Cloud" ) do |val|
|
788
|
-
options[:cloud] = val
|
789
|
-
end
|
790
|
-
opts.on( '-e', '--env ENV', "Environment" ) do |val|
|
791
|
-
options[:environment] = val
|
792
|
-
end
|
793
|
-
# opts.on( nil, '--index NUMBER', "The index of the instance to remove, starting with 0." ) do |val|
|
794
|
-
# instance_index = val.to_i
|
795
|
-
# end
|
796
|
-
build_common_options(opts, options, [:auto_confirm, :json, :dry_run, :remote])
|
797
|
-
opts.footer = "Update an app template, removing a specified instance config." + "\n" +
|
798
|
-
"[template] is required. This is the name or id of an app template." + "\n" +
|
799
|
-
"[tier] is required. This is the name of the tier." + "\n" +
|
800
|
-
"[instance] is required. This is the type of instance." + "\n" +
|
801
|
-
"The config scope is specified with the -g GROUP, -c CLOUD and -e ENV. The -g and -c options are required."
|
802
|
-
end
|
803
|
-
optparse.parse!(args)
|
804
|
-
|
805
|
-
if args.count < 3
|
806
|
-
print_error Morpheus::Terminal.angry_prompt
|
807
|
-
puts_error "Wrong number of arguments"
|
808
|
-
puts_error optparse
|
809
|
-
return 1
|
810
|
-
end
|
811
|
-
if !options[:group]
|
812
|
-
print_error Morpheus::Terminal.angry_prompt
|
813
|
-
puts_error "Missing required argument -g GROUP"
|
814
|
-
puts_error optparse
|
815
|
-
return 1
|
816
|
-
end
|
817
|
-
if !options[:cloud]
|
818
|
-
print_error Morpheus::Terminal.angry_prompt
|
819
|
-
puts_error "Missing required argument -g CLOUD"
|
820
|
-
puts_error optparse
|
821
|
-
return 1
|
822
|
-
end
|
823
|
-
connect(options)
|
824
|
-
|
825
|
-
begin
|
826
|
-
|
827
|
-
app_template_name = args[0]
|
828
|
-
tier_name = args[1]
|
829
|
-
instance_type_code = args[2]
|
830
|
-
# we also need consider when there is multiple instances of the same type in
|
831
|
-
# a template/tier.. so maybe split instance_type_code as [type-code]:[index].. or...errr
|
832
|
-
|
833
|
-
app_template = find_app_template_by_name_or_id(app_template_name)
|
834
|
-
return 1 if app_template.nil?
|
835
|
-
|
836
|
-
instance_type = find_instance_type_by_code(instance_type_code)
|
837
|
-
return 1 if instance_type.nil?
|
838
|
-
|
839
|
-
tier_config = nil
|
840
|
-
# instance_config = nil
|
841
|
-
|
842
|
-
app_template["config"] ||= {}
|
843
|
-
tiers = app_template["config"]["tiers"]
|
844
|
-
tiers ||= {}
|
845
|
-
# tier identified by name, case sensitive...
|
846
|
-
if !tiers[tier_name]
|
847
|
-
print_red_alert "Tier not found by name #{tier_name}"
|
848
|
-
return 1
|
849
|
-
end
|
850
|
-
tier_config = tiers[tier_name]
|
851
|
-
|
852
|
-
if !tier_config
|
853
|
-
print_red_alert "Tier not found by name #{tier1_name}!"
|
854
|
-
return 1
|
855
|
-
elsif tier_config['instances'].nil? || tier_config['instances'].empty?
|
856
|
-
print_red_alert "Tier #{tier_name} is empty!"
|
857
|
-
return 1
|
858
|
-
end
|
859
|
-
|
860
|
-
matching_indices = []
|
861
|
-
if tier_config['instances']
|
862
|
-
if instance_index
|
863
|
-
matching_indices = [instance_index].compact
|
864
|
-
else
|
865
|
-
tier_config['instances'].each_with_index do |instance_config, index|
|
866
|
-
is_match = instance_config['instance'] && instance_config['instance']['type'] == instance_type['code']
|
867
|
-
if is_match
|
868
|
-
matching_indices << index
|
869
|
-
end
|
870
|
-
end
|
871
|
-
end
|
872
|
-
end
|
873
|
-
|
874
|
-
if matching_indices.size == 0
|
875
|
-
print_red_alert "Instance not found by tier: #{tier_name}, type: #{instance_type_code}"
|
876
|
-
return 1
|
877
|
-
elsif matching_indices.size > 1
|
878
|
-
#print_error Morpheus::Terminal.angry_prompt
|
879
|
-
print_red_alert "More than one instance found by tier: #{tier_name}, type: #{instance_type_code}"
|
880
|
-
puts_error "Try using the --index option to identify the instance you wish to remove."
|
881
|
-
puts_error optparse
|
882
|
-
return 1
|
883
|
-
end
|
884
|
-
|
885
|
-
# ok, find the specified config
|
886
|
-
instance_config = tier_config['instances'][matching_indices[0]]
|
887
|
-
parent_config = nil
|
888
|
-
current_config = instance_config
|
889
|
-
delete_key = nil
|
890
|
-
|
891
|
-
config_description = "type: #{instance_type['code']}"
|
892
|
-
config_description << " environment: #{options[:environment]}" if options[:environment]
|
893
|
-
config_description << " group: #{options[:group]}" if options[:group]
|
894
|
-
config_description << " cloud: #{options[:cloud]}" if options[:cloud]
|
895
|
-
config_description = config_description.strip
|
896
|
-
|
897
|
-
|
898
|
-
# find config in environments => env => groups => groupname => clouds => cloudname =>
|
899
|
-
if options[:environment]
|
900
|
-
if current_config && current_config['environments'] && current_config['environments'][options[:environment]]
|
901
|
-
parent_config = current_config['environments']
|
902
|
-
delete_key = options[:environment]
|
903
|
-
current_config = parent_config[delete_key]
|
904
|
-
else
|
905
|
-
print_red_alert "Instance config not found for scope #{config_description}"
|
906
|
-
return 1
|
907
|
-
end
|
908
|
-
end
|
909
|
-
if options[:group]
|
910
|
-
if current_config && current_config['groups'] && current_config['groups'][options[:group]]
|
911
|
-
parent_config = current_config['groups']
|
912
|
-
delete_key = options[:group]
|
913
|
-
current_config = parent_config[delete_key]
|
914
|
-
else
|
915
|
-
print_red_alert "Instance config not found for scope #{config_description}"
|
916
|
-
return 1
|
917
|
-
end
|
918
|
-
end
|
919
|
-
if options[:cloud]
|
920
|
-
if current_config && current_config['clouds'] && current_config['clouds'][options[:cloud]]
|
921
|
-
parent_config = current_config['clouds']
|
922
|
-
delete_key = options[:cloud]
|
923
|
-
current_config = parent_config[delete_key]
|
924
|
-
else
|
925
|
-
print_red_alert "Instance config not found for scope #{config_description}"
|
926
|
-
return 1
|
927
|
-
end
|
928
|
-
end
|
929
|
-
|
930
|
-
# remove it
|
931
|
-
parent_config.delete(delete_key)
|
932
|
-
|
933
|
-
unless options[:yes] || Morpheus::Cli::OptionTypes.confirm("Are you sure you want to delete this instance config #{config_description} ?")
|
934
|
-
return 9
|
935
|
-
end
|
936
|
-
|
937
|
-
# ok, make api request
|
938
|
-
app_template["config"]["tiers"] = tiers
|
939
|
-
request_payload = {appTemplate: app_template}
|
940
|
-
|
941
|
-
if options[:dry_run]
|
942
|
-
print_dry_run @app_templates_interface.dry.update(app_template['id'], request_payload)
|
943
|
-
return
|
944
|
-
end
|
945
|
-
json_response = @app_templates_interface.update(app_template['id'], request_payload)
|
946
|
-
|
947
|
-
if options[:json]
|
948
|
-
puts JSON.pretty_generate(json_response)
|
949
|
-
else
|
950
|
-
print_green_success "Removed instance from app template."
|
951
|
-
get([app_template['id']])
|
952
|
-
end
|
953
|
-
return 0
|
954
|
-
|
955
|
-
rescue RestClient::Exception => e
|
956
|
-
print_rest_exception(e, options)
|
957
|
-
exit 1
|
958
|
-
end
|
959
|
-
end
|
960
|
-
|
961
|
-
def update_instance(args)
|
962
|
-
print_red_alert "NOT YET SUPPORTED"
|
963
|
-
return 5
|
964
|
-
end
|
965
|
-
|
966
|
-
def update_instance_config(args)
|
967
|
-
print_red_alert "NOT YET SUPPORTED"
|
968
|
-
return 5
|
969
|
-
end
|
970
|
-
|
971
|
-
def remove_instance(args)
|
972
|
-
instance_index = nil
|
973
|
-
options = {}
|
974
|
-
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
975
|
-
opts.banner = subcommand_usage("[template] [tier] [instance]")
|
976
|
-
# opts.on('--index NUMBER', Number, "Identify Instance by index within tier, starting with 0." ) do |val|
|
977
|
-
# instance_index = val.to_i
|
978
|
-
# end
|
979
|
-
build_common_options(opts, options, [:auto_confirm, :json, :dry_run, :remote])
|
980
|
-
end
|
981
|
-
optparse.parse!(args)
|
982
|
-
|
983
|
-
if args.count < 3
|
984
|
-
print_error Morpheus::Terminal.angry_prompt
|
985
|
-
puts_error "Wrong number of arguments"
|
986
|
-
puts_error optparse
|
987
|
-
return 1
|
988
|
-
end
|
989
|
-
|
990
|
-
connect(options)
|
991
|
-
|
992
|
-
begin
|
993
|
-
|
994
|
-
app_template_name = args[0]
|
995
|
-
tier_name = args[1]
|
996
|
-
instance_identier = args[2]
|
997
|
-
|
998
|
-
# instance_type_code = args[2]
|
999
|
-
# we also need consider when there is multiple instances of the same type in
|
1000
|
-
# a template/tier.. so maybe split instance_type_code as [type-code]:[index].. or...errr
|
1001
|
-
|
1002
|
-
app_template = find_app_template_by_name_or_id(app_template_name)
|
1003
|
-
return 1 if app_template.nil?
|
1004
|
-
|
1005
|
-
# instance_type = find_instance_type_by_code(instance_type_code)
|
1006
|
-
# return 1 if instance_type.nil?
|
1007
|
-
|
1008
|
-
tier_config = nil
|
1009
|
-
# instance_config = nil
|
1010
|
-
|
1011
|
-
app_template["config"] ||= {}
|
1012
|
-
tiers = app_template["config"]["tiers"]
|
1013
|
-
tiers ||= {}
|
1014
|
-
# tier identified by name, case sensitive...
|
1015
|
-
if !tiers[tier_name]
|
1016
|
-
print_red_alert "Tier not found by name #{tier_name}"
|
1017
|
-
return 1
|
1018
|
-
end
|
1019
|
-
tier_config = tiers[tier_name]
|
1020
|
-
|
1021
|
-
if tier_config['instances'].nil? || tier_config['instances'].empty?
|
1022
|
-
print_red_alert "Tier #{tier_name} is empty!"
|
1023
|
-
return 1
|
1024
|
-
end
|
1025
|
-
|
1026
|
-
# find instance
|
1027
|
-
matching_indices = []
|
1028
|
-
if tier_config['instances']
|
1029
|
-
if instance_identier.to_s =~ /\A\d{1,}\Z/
|
1030
|
-
matching_indices = [instance_identier.to_i].compact
|
1031
|
-
else
|
1032
|
-
tier_config['instances'].each_with_index do |instance_config, index|
|
1033
|
-
if instance_config['instance'] && instance_config['instance']['type'] == instance_identier
|
1034
|
-
matching_indices << index
|
1035
|
-
elsif instance_config['instance'] && instance_config['instance']['name'] == instance_identier
|
1036
|
-
matching_indices << index
|
1037
|
-
end
|
1038
|
-
end
|
1039
|
-
end
|
1040
|
-
end
|
1041
|
-
if matching_indices.size == 0
|
1042
|
-
print_red_alert "Instance not found by tier: #{tier_name}, instance: #{instance_identier}"
|
1043
|
-
return 1
|
1044
|
-
elsif matching_indices.size > 1
|
1045
|
-
#print_error Morpheus::Terminal.angry_prompt
|
1046
|
-
print_red_alert "More than one instance matched tier: #{tier_name}, instance: #{instance_identier}"
|
1047
|
-
puts_error "Instance can be identified type, name or index within the tier."
|
1048
|
-
puts_error optparse
|
1049
|
-
return 1
|
1050
|
-
end
|
1051
|
-
|
1052
|
-
# remove it
|
1053
|
-
tier_config['instances'].delete_at(matching_indices[0])
|
1054
|
-
|
1055
|
-
unless options[:yes] || Morpheus::Cli::OptionTypes.confirm("Are you sure you want to delete this instance #{instance_type_code} instance from tier: #{tier_name}?")
|
1056
|
-
return 9
|
1057
|
-
end
|
1058
|
-
|
1059
|
-
# ok, make api request
|
1060
|
-
app_template["config"]["tiers"] = tiers
|
1061
|
-
request_payload = {appTemplate: app_template}
|
1062
|
-
|
1063
|
-
if options[:dry_run]
|
1064
|
-
print_dry_run @app_templates_interface.dry.update(app_template['id'], request_payload)
|
1065
|
-
return
|
1066
|
-
end
|
1067
|
-
json_response = @app_templates_interface.update(app_template['id'], request_payload)
|
1068
|
-
|
1069
|
-
if options[:json]
|
1070
|
-
puts JSON.pretty_generate(json_response)
|
1071
|
-
else
|
1072
|
-
print_green_success "Removed instance from app template."
|
1073
|
-
get([app_template['id']])
|
1074
|
-
end
|
1075
|
-
return 0
|
1076
|
-
|
1077
|
-
rescue RestClient::Exception => e
|
1078
|
-
print_rest_exception(e, options)
|
1079
|
-
exit 1
|
1080
|
-
end
|
1081
|
-
end
|
1082
|
-
|
1083
|
-
def add_tier(args)
|
1084
|
-
options = {}
|
1085
|
-
boot_order = nil
|
1086
|
-
linked_tiers = nil
|
1087
|
-
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
1088
|
-
opts.banner = subcommand_usage("[template] [tier]")
|
1089
|
-
opts.on('--name VALUE', String, "Tier Name") do |val|
|
1090
|
-
options[:name] = val
|
1091
|
-
end
|
1092
|
-
opts.on('--bootOrder NUMBER', String, "Boot Order" ) do |val|
|
1093
|
-
boot_order = val
|
1094
|
-
end
|
1095
|
-
opts.on('--linkedTiers x,y,z', Array, "Connected Tiers.") do |val|
|
1096
|
-
linked_tiers = val
|
1097
|
-
end
|
1098
|
-
build_common_options(opts, options, [:options, :json, :dry_run, :remote])
|
1099
|
-
end
|
1100
|
-
optparse.parse!(args)
|
1101
|
-
|
1102
|
-
if args.count < 1
|
1103
|
-
print_error Morpheus::Terminal.angry_prompt
|
1104
|
-
puts_error "#{command_name} add-tier requires argument: [template]\n#{optparse}"
|
1105
|
-
# puts optparse
|
1106
|
-
return 1
|
1107
|
-
end
|
1108
|
-
app_template_name = args[0]
|
1109
|
-
tier_name = args[1]
|
1110
|
-
|
1111
|
-
connect(options)
|
1112
|
-
|
1113
|
-
begin
|
1114
|
-
app_template = find_app_template_by_name_or_id(app_template_name)
|
1115
|
-
return 1 if app_template.nil?
|
1116
|
-
|
1117
|
-
app_template["config"] ||= {}
|
1118
|
-
app_template["config"]["tiers"] ||= {}
|
1119
|
-
tiers = app_template["config"]["tiers"]
|
1120
|
-
|
1121
|
-
# prompt new tier
|
1122
|
-
# Name
|
1123
|
-
# {'fieldName' => 'name', 'fieldLabel' => 'Name', 'type' => 'text', 'required' => true, 'displayOrder' => 1, 'description' => 'A unique name for the app template.'},
|
1124
|
-
# {'fieldName' => 'bootOrder', 'fieldLabel' => 'Boot Order', 'type' => 'text', 'required' => false, 'displayOrder' => 2, 'description' => 'Boot Order'}
|
1125
|
-
if !tier_name
|
1126
|
-
v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'name', 'fieldLabel' => 'Tier Name', 'type' => 'text', 'required' => true, 'description' => 'Enter the name of the tier'}], options[:options])
|
1127
|
-
tier_name = v_prompt['name']
|
1128
|
-
end
|
1129
|
-
# case insensitive match
|
1130
|
-
existing_tier_names = tiers.keys
|
1131
|
-
matching_tier_name = existing_tier_names.find {|k| k.downcase == tier_name.downcase }
|
1132
|
-
if matching_tier_name
|
1133
|
-
# print_red_alert "Tier #{tier_name} already exists"
|
1134
|
-
# return 1
|
1135
|
-
print cyan,"Tier #{tier_name} already exists.",reset,"\n"
|
1136
|
-
return 0
|
1137
|
-
end
|
1138
|
-
# idempotent
|
1139
|
-
if !tiers[tier_name]
|
1140
|
-
tiers[tier_name] = {'instances' => []}
|
1141
|
-
end
|
1142
|
-
tier = tiers[tier_name]
|
1143
|
-
|
1144
|
-
# Boot Order
|
1145
|
-
if !boot_order
|
1146
|
-
v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'bootOrder', 'fieldLabel' => 'Boot Order', 'type' => 'text', 'required' => false, 'description' => 'Sequence order for starting app instances by tier. 0-N', 'defaultValue' => tier['bootOrder']}], options[:options])
|
1147
|
-
boot_order = v_prompt['bootOrder']
|
1148
|
-
end
|
1149
|
-
if boot_order.to_s == 'null'
|
1150
|
-
tier.delete('bootOrder')
|
1151
|
-
elsif boot_order.to_s != ''
|
1152
|
-
tier['bootOrder'] = boot_order.to_i
|
1153
|
-
end
|
1154
|
-
|
1155
|
-
# Connected Tiers
|
1156
|
-
if !linked_tiers
|
1157
|
-
v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'linkedTiers', 'fieldLabel' => 'Connected Tiers', 'type' => 'text', 'required' => false, 'description' => 'Names of connected tiers, comma separated', 'defaultValue' => (linked_tiers ? linked_tiers.join(',') : nil)}], options[:options])
|
1158
|
-
linked_tiers = v_prompt['linkedTiers'].to_s.split(',').collect {|it| it.strip }.select {|it| it != ''}
|
1159
|
-
end
|
1160
|
-
if linked_tiers && !linked_tiers.empty?
|
1161
|
-
linked_tiers.each do |other_tier_name|
|
1162
|
-
link_result = link_tiers(tiers, [tier_name, other_tier_name])
|
1163
|
-
# could just re-prompt unless options[:no_prompt]
|
1164
|
-
return 1 if !link_result
|
1165
|
-
end
|
1166
|
-
end
|
1167
|
-
|
1168
|
-
# ok, make api request
|
1169
|
-
app_template["config"]["tiers"] = tiers
|
1170
|
-
request_payload = app_template["config"]
|
1171
|
-
# request_payload = {appTemplate: app_template}
|
1172
|
-
|
1173
|
-
if options[:dry_run]
|
1174
|
-
print_dry_run @app_templates_interface.dry.update(app_template['id'], request_payload)
|
1175
|
-
return
|
1176
|
-
end
|
1177
|
-
json_response = @app_templates_interface.update(app_template['id'], request_payload)
|
1178
|
-
|
1179
|
-
if options[:json]
|
1180
|
-
puts JSON.pretty_generate(json_response)
|
1181
|
-
elsif !options[:quiet]
|
1182
|
-
print_green_success "Added tier #{tier_name}"
|
1183
|
-
# prompt for new instance
|
1184
|
-
if !options[:no_prompt]
|
1185
|
-
if ::Morpheus::Cli::OptionTypes::confirm("Would you like to add an instance now?", options.merge({default: true}))
|
1186
|
-
add_instance([app_template['id'], tier_name])
|
1187
|
-
while ::Morpheus::Cli::OptionTypes::confirm("Add another instance now?", options.merge({default: false})) do
|
1188
|
-
add_instance([app_template['id'], tier_name])
|
1189
|
-
end
|
1190
|
-
# if !add_instance_result
|
1191
|
-
# end
|
1192
|
-
end
|
1193
|
-
end
|
1194
|
-
# print details
|
1195
|
-
get([app_template['name']])
|
1196
|
-
end
|
1197
|
-
return 0
|
1198
|
-
rescue RestClient::Exception => e
|
1199
|
-
print_rest_exception(e, options)
|
1200
|
-
exit 1
|
1201
|
-
end
|
1202
|
-
end
|
1203
|
-
|
1204
|
-
def update_tier(args)
|
1205
|
-
options = {}
|
1206
|
-
new_tier_name = nil
|
1207
|
-
boot_order = nil
|
1208
|
-
linked_tiers = nil
|
1209
|
-
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
1210
|
-
opts.banner = subcommand_usage("[template] [tier]")
|
1211
|
-
opts.on('--name VALUE', String, "Tier Name") do |val|
|
1212
|
-
new_tier_name = val
|
1213
|
-
end
|
1214
|
-
opts.on('--bootOrder NUMBER', String, "Boot Order" ) do |val|
|
1215
|
-
boot_order = val
|
1216
|
-
end
|
1217
|
-
opts.on('--linkedTiers x,y,z', Array, "Connected Tiers") do |val|
|
1218
|
-
linked_tiers = val
|
1219
|
-
end
|
1220
|
-
build_common_options(opts, options, [:options, :json, :dry_run, :remote])
|
1221
|
-
end
|
1222
|
-
optparse.parse!(args)
|
1223
|
-
|
1224
|
-
if args.count != 2
|
1225
|
-
print_error Morpheus::Terminal.angry_prompt
|
1226
|
-
puts_error "#{command_name} update-tier expects 2 arguments and received #{args.count}: #{args.join(' ')}\n#{optparse}"
|
1227
|
-
return 1
|
1228
|
-
end
|
1229
|
-
app_template_name = args[0]
|
1230
|
-
tier_name = args[1]
|
1231
|
-
|
1232
|
-
connect(options)
|
1233
|
-
|
1234
|
-
begin
|
1235
|
-
app_template = find_app_template_by_name_or_id(app_template_name)
|
1236
|
-
return 1 if app_template.nil?
|
1237
|
-
|
1238
|
-
app_template["config"] ||= {}
|
1239
|
-
app_template["config"]["tiers"] ||= {}
|
1240
|
-
tiers = app_template["config"]["tiers"]
|
1241
|
-
|
1242
|
-
if !tiers[tier_name]
|
1243
|
-
print_red_alert "Tier not found by name #{tier_name}"
|
1244
|
-
return 1
|
1245
|
-
end
|
1246
|
-
tier = tiers[tier_name]
|
1247
|
-
|
1248
|
-
|
1249
|
-
if options[:no_prompt]
|
1250
|
-
if !(new_tier_name || boot_order || linked_tiers)
|
1251
|
-
print_error Morpheus::Terminal.angry_prompt
|
1252
|
-
puts_error "#{command_name} update-tier requires an option to update.\n#{optparse}"
|
1253
|
-
return 1
|
1254
|
-
end
|
1255
|
-
end
|
1256
|
-
|
1257
|
-
# prompt update tier
|
1258
|
-
# Name
|
1259
|
-
if !new_tier_name
|
1260
|
-
v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'name', 'fieldLabel' => 'Tier Name', 'type' => 'text', 'required' => true, 'description' => 'Rename the tier', 'defaultValue' => tier_name}], options[:options])
|
1261
|
-
new_tier_name = v_prompt['name']
|
1262
|
-
end
|
1263
|
-
if new_tier_name && new_tier_name != tier_name
|
1264
|
-
old_tier_name = tier_name
|
1265
|
-
if tiers[new_tier_name]
|
1266
|
-
print_red_alert "A tier named #{tier_name} already exists."
|
1267
|
-
return 1
|
1268
|
-
end
|
1269
|
-
tier = tiers.delete(tier_name)
|
1270
|
-
tiers[new_tier_name] = tier
|
1271
|
-
# Need to fix all the linkedTiers
|
1272
|
-
tiers.each do |k, v|
|
1273
|
-
if v['linkedTiers'] && v['linkedTiers'].include?(tier_name)
|
1274
|
-
v['linkedTiers'] = v['linkedTiers'].map {|it| it == tier_name ? new_tier_name : it }
|
1275
|
-
end
|
1276
|
-
end
|
1277
|
-
# old_tier_name = tier_name
|
1278
|
-
tier_name = new_tier_name
|
1279
|
-
end
|
1280
|
-
|
1281
|
-
# Boot Order
|
1282
|
-
if !boot_order
|
1283
|
-
v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'bootOrder', 'fieldLabel' => 'Boot Order', 'type' => 'text', 'required' => false, 'description' => 'Sequence order for starting app instances by tier. 0-N', 'defaultValue' => tier['bootOrder']}], options[:options])
|
1284
|
-
boot_order = v_prompt['bootOrder']
|
1285
|
-
end
|
1286
|
-
if boot_order.to_s == 'null'
|
1287
|
-
tier.delete('bootOrder')
|
1288
|
-
elsif boot_order.to_s != ''
|
1289
|
-
tier['bootOrder'] = boot_order.to_i
|
1290
|
-
end
|
1291
|
-
|
1292
|
-
# Connected Tiers
|
1293
|
-
if !linked_tiers
|
1294
|
-
v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'linkedTiers', 'fieldLabel' => 'Connected Tiers', 'type' => 'text', 'required' => false, 'description' => 'Names of connected tiers, comma separated', 'defaultValue' => (tier['linkedTiers'] ? tier['linkedTiers'].join(',') : nil)}], options[:options])
|
1295
|
-
linked_tiers = v_prompt['linkedTiers'].to_s.split(',').collect {|it| it.strip }.select {|it| it != ''}
|
1296
|
-
end
|
1297
|
-
current_linked_tiers = tier['linkedTiers'] || []
|
1298
|
-
if linked_tiers && linked_tiers != current_linked_tiers
|
1299
|
-
remove_tiers = current_linked_tiers - linked_tiers
|
1300
|
-
remove_tiers.each do |other_tier_name|
|
1301
|
-
unlink_result = unlink_tiers(tiers, [tier_name, other_tier_name])
|
1302
|
-
# could just re-prompt unless options[:no_prompt]
|
1303
|
-
return 1 if !unlink_result
|
1304
|
-
end
|
1305
|
-
add_tiers = linked_tiers - current_linked_tiers
|
1306
|
-
add_tiers.each do |other_tier_name|
|
1307
|
-
link_result = link_tiers(tiers, [tier_name, other_tier_name])
|
1308
|
-
# could just re-prompt unless options[:no_prompt]
|
1309
|
-
return 1 if !link_result
|
1310
|
-
end
|
1311
|
-
end
|
1312
|
-
|
1313
|
-
# ok, make api request
|
1314
|
-
app_template["config"]["tiers"] = tiers
|
1315
|
-
request_payload = app_template["config"]
|
1316
|
-
# request_payload = {appTemplate: app_template}
|
1317
|
-
|
1318
|
-
if options[:dry_run]
|
1319
|
-
print_dry_run @app_templates_interface.dry.update(app_template['id'], request_payload)
|
1320
|
-
return
|
1321
|
-
end
|
1322
|
-
json_response = @app_templates_interface.update(app_template['id'], request_payload)
|
1323
|
-
|
1324
|
-
if options[:json]
|
1325
|
-
puts JSON.pretty_generate(json_response)
|
1326
|
-
elsif !options[:quiet]
|
1327
|
-
print_green_success "Updated tier #{tier_name}"
|
1328
|
-
get([app_template['id']])
|
1329
|
-
end
|
1330
|
-
return 0
|
1331
|
-
rescue RestClient::Exception => e
|
1332
|
-
print_rest_exception(e, options)
|
1333
|
-
exit 1
|
1334
|
-
end
|
1335
|
-
end
|
1336
|
-
|
1337
|
-
def remove_tier(args)
|
1338
|
-
options = {}
|
1339
|
-
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
1340
|
-
opts.banner = subcommand_usage("[template] [tier]")
|
1341
|
-
build_common_options(opts, options, [:auto_confirm, :json, :dry_run, :remote])
|
1342
|
-
end
|
1343
|
-
optparse.parse!(args)
|
1344
|
-
|
1345
|
-
if args.count < 2
|
1346
|
-
print_error Morpheus::Terminal.angry_prompt
|
1347
|
-
puts_error "#{command_name} remove-tier expects 2 arguments and received #{args.count}: #{args.join(' ')}\n#{optparse}"
|
1348
|
-
return 1
|
1349
|
-
end
|
1350
|
-
app_template_name = args[0]
|
1351
|
-
tier_name = args[1]
|
1352
|
-
|
1353
|
-
connect(options)
|
1354
|
-
|
1355
|
-
begin
|
1356
|
-
app_template = find_app_template_by_name_or_id(app_template_name)
|
1357
|
-
return 1 if app_template.nil?
|
1358
|
-
|
1359
|
-
app_template["config"] ||= {}
|
1360
|
-
app_template["config"]["tiers"] ||= {}
|
1361
|
-
tiers = app_template["config"]["tiers"]
|
1362
|
-
|
1363
|
-
if !tiers[tier_name]
|
1364
|
-
# print_red_alert "Tier not found by name #{tier_name}"
|
1365
|
-
# return 1
|
1366
|
-
print cyan,"Tier #{tier_name} does not exist.",reset,"\n"
|
1367
|
-
return 0
|
1368
|
-
end
|
1369
|
-
|
1370
|
-
unless options[:yes] || Morpheus::Cli::OptionTypes.confirm("Are you sure you want to delete the tier #{tier_name}?")
|
1371
|
-
exit
|
1372
|
-
end
|
1373
|
-
|
1374
|
-
# remove it
|
1375
|
-
tiers.delete(tier_name)
|
1376
|
-
|
1377
|
-
# ok, make api request
|
1378
|
-
app_template["config"]["tiers"] = tiers
|
1379
|
-
request_payload = app_template["config"]
|
1380
|
-
# request_payload = {appTemplate: app_template}
|
1381
|
-
|
1382
|
-
if options[:dry_run]
|
1383
|
-
print_dry_run @app_templates_interface.dry.update(app_template['id'], request_payload)
|
1384
|
-
return
|
1385
|
-
end
|
1386
|
-
|
1387
|
-
json_response = @app_templates_interface.update(app_template['id'], request_payload)
|
1388
|
-
|
1389
|
-
|
1390
|
-
if options[:json]
|
1391
|
-
print JSON.pretty_generate(json_response)
|
1392
|
-
print "\n"
|
1393
|
-
else
|
1394
|
-
print_green_success "Removed tier #{tier_name}"
|
1395
|
-
get([app_template['name']])
|
1396
|
-
end
|
1397
|
-
|
1398
|
-
rescue RestClient::Exception => e
|
1399
|
-
print_rest_exception(e, options)
|
1400
|
-
exit 1
|
1401
|
-
end
|
1402
|
-
end
|
1403
|
-
|
1404
|
-
def connect_tiers(args)
|
1405
|
-
options = {}
|
1406
|
-
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
1407
|
-
opts.banner = subcommand_usage("[template] [Tier1] [Tier2]")
|
1408
|
-
build_common_options(opts, options, [:json, :dry_run, :remote])
|
1409
|
-
end
|
1410
|
-
optparse.parse!(args)
|
1411
|
-
|
1412
|
-
if args.count < 3
|
1413
|
-
print_error Morpheus::Terminal.angry_prompt
|
1414
|
-
puts_error "#{command_name} connect-tiers expects 3 arguments and received #{args.count}: #{args.join(' ')}\n#{optparse}"
|
1415
|
-
# puts optparse
|
1416
|
-
return 1
|
1417
|
-
end
|
1418
|
-
app_template_name = args[0]
|
1419
|
-
tier1_name = args[1]
|
1420
|
-
tier2_name = args[2]
|
1421
|
-
|
1422
|
-
connect(options)
|
1423
|
-
|
1424
|
-
begin
|
1425
|
-
app_template = find_app_template_by_name_or_id(app_template_name)
|
1426
|
-
return 1 if app_template.nil?
|
1427
|
-
|
1428
|
-
app_template["config"] ||= {}
|
1429
|
-
tiers = app_template["config"]["tiers"]
|
1430
|
-
|
1431
|
-
if !tiers || tiers.keys.size == 0
|
1432
|
-
error_msg = "App Template #{app_template['name']} has no tiers."
|
1433
|
-
# print_red_alert "App Template #{app_template['name']} has no tiers."
|
1434
|
-
# raise_command_error "App Template #{app_template['name']} has no tiers."
|
1435
|
-
print_error Morpheus::Terminal.angry_prompt
|
1436
|
-
puts_error "App Template #{app_template['name']} has no tiers."
|
1437
|
-
return 1
|
1438
|
-
end
|
1439
|
-
|
1440
|
-
connect_tiers = []
|
1441
|
-
tier1 = tiers[tier1_name]
|
1442
|
-
tier2 = tiers[tier2_name]
|
1443
|
-
# uhh support N args
|
1444
|
-
|
1445
|
-
if tier1.nil?
|
1446
|
-
print_red_alert "Tier not found by name #{tier1_name}!"
|
1447
|
-
return 1
|
1448
|
-
end
|
1449
|
-
|
1450
|
-
if tier2.nil?
|
1451
|
-
print_red_alert "Tier not found by name #{tier2_name}!"
|
1452
|
-
return 1
|
1453
|
-
end
|
1454
|
-
|
1455
|
-
tier1["linkedTiers"] = tier1["linkedTiers"] || []
|
1456
|
-
tier2["linkedTiers"] = tier2["linkedTiers"] || []
|
1457
|
-
|
1458
|
-
found_edge = tier1["linkedTiers"].include?(tier2_name) || tier2["linkedTiers"].include?(tier1_name)
|
1459
|
-
|
1460
|
-
if found_edge
|
1461
|
-
puts cyan,"Tiers #{tier1_name} and #{tier2_name} are already connected.",reset
|
1462
|
-
return 0
|
1463
|
-
end
|
1464
|
-
|
1465
|
-
# ok to be connect the tiers
|
1466
|
-
# note: the ui doesn't hook up both sides eh?
|
1467
|
-
|
1468
|
-
if !tier1["linkedTiers"].include?(tier2_name)
|
1469
|
-
tier1["linkedTiers"].push(tier2_name)
|
1470
|
-
end
|
1471
|
-
|
1472
|
-
if !tier2["linkedTiers"].include?(tier1_name)
|
1473
|
-
tier2["linkedTiers"].push(tier1_name)
|
1474
|
-
end
|
1475
|
-
|
1476
|
-
# ok, make api request
|
1477
|
-
app_template["config"]["tiers"] = tiers
|
1478
|
-
request_payload = app_template["config"]
|
1479
|
-
# request_payload = {appTemplate: app_template}
|
1480
|
-
|
1481
|
-
if options[:dry_run]
|
1482
|
-
print_dry_run @app_templates_interface.dry.update(app_template['id'], request_payload)
|
1483
|
-
return
|
1484
|
-
end
|
1485
|
-
json_response = @app_templates_interface.update(app_template['id'], request_payload)
|
1486
|
-
|
1487
|
-
|
1488
|
-
if options[:json]
|
1489
|
-
print JSON.pretty_generate(json_response)
|
1490
|
-
print "\n"
|
1491
|
-
else
|
1492
|
-
print_green_success "Connected 2 tiers for app template #{app_template['name']}"
|
1493
|
-
get([app_template['name']])
|
1494
|
-
end
|
1495
|
-
|
1496
|
-
rescue RestClient::Exception => e
|
1497
|
-
print_rest_exception(e, options)
|
1498
|
-
exit 1
|
1499
|
-
end
|
1500
|
-
end
|
1501
|
-
|
1502
|
-
def disconnect_tiers(args)
|
1503
|
-
options = {}
|
1504
|
-
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
1505
|
-
opts.banner = subcommand_usage("[template] [Tier1] [Tier2]")
|
1506
|
-
build_common_options(opts, options, [:json, :dry_run, :remote])
|
1507
|
-
end
|
1508
|
-
optparse.parse!(args)
|
1509
|
-
|
1510
|
-
if args.count < 3
|
1511
|
-
print_error Morpheus::Terminal.angry_prompt
|
1512
|
-
puts_error "#{command_name} disconnect-tiers expects 3 arguments and received #{args.count}: #{args.join(' ')}\n#{optparse}"
|
1513
|
-
# puts optparse
|
1514
|
-
return 1
|
1515
|
-
end
|
1516
|
-
app_template_name = args[0]
|
1517
|
-
tier1_name = args[1]
|
1518
|
-
tier2_name = args[2]
|
1519
|
-
|
1520
|
-
connect(options)
|
1521
|
-
|
1522
|
-
begin
|
1523
|
-
app_template = find_app_template_by_name_or_id(app_template_name)
|
1524
|
-
return 1 if app_template.nil?
|
1525
|
-
|
1526
|
-
app_template["config"] ||= {}
|
1527
|
-
tiers = app_template["config"]["tiers"]
|
1528
|
-
|
1529
|
-
if !tiers || tiers.keys.size == 0
|
1530
|
-
# print_red_alert "App Template #{app_template['name']} has no tiers."
|
1531
|
-
# raise_command_error "App Template #{app_template['name']} has no tiers."
|
1532
|
-
print_error Morpheus::Terminal.angry_prompt
|
1533
|
-
puts_error "App Template #{app_template['name']} has no tiers."
|
1534
|
-
return 1
|
1535
|
-
end
|
1536
|
-
|
1537
|
-
connect_tiers = []
|
1538
|
-
tier1 = tiers[tier1_name]
|
1539
|
-
tier2 = tiers[tier2_name]
|
1540
|
-
# uhh support N args
|
1541
|
-
|
1542
|
-
if tier1.nil?
|
1543
|
-
print_red_alert "Tier not found by name #{tier1_name}!"
|
1544
|
-
return 1
|
1545
|
-
end
|
1546
|
-
|
1547
|
-
if tier2.nil?
|
1548
|
-
print_red_alert "Tier not found by name #{tier2_name}!"
|
1549
|
-
return 1
|
1550
|
-
end
|
1551
|
-
|
1552
|
-
tier1["linkedTiers"] = tier1["linkedTiers"] || []
|
1553
|
-
tier2["linkedTiers"] = tier2["linkedTiers"] || []
|
1554
|
-
|
1555
|
-
found_edge = tier1["linkedTiers"].include?(tier2_name) || tier2["linkedTiers"].include?(tier1_name)
|
1556
|
-
|
1557
|
-
if found_edge
|
1558
|
-
puts cyan,"Tiers #{tier1_name} and #{tier2_name} are not connected.",reset
|
1559
|
-
return 0
|
1560
|
-
end
|
1561
|
-
|
1562
|
-
# remove links
|
1563
|
-
tier1["linkedTiers"] = tier1["linkedTiers"].reject {|it| it == tier2_name }
|
1564
|
-
tier2["linkedTiers"] = tier2["linkedTiers"].reject {|it| it == tier1_name }
|
1565
|
-
|
1566
|
-
# ok, make api request
|
1567
|
-
app_template["config"]["tiers"] = tiers
|
1568
|
-
request_payload = app_template["config"]
|
1569
|
-
# request_payload = {appTemplate: app_template}
|
1570
|
-
|
1571
|
-
if options[:dry_run]
|
1572
|
-
print_dry_run @app_templates_interface.dry.update(app_template['id'], request_payload)
|
1573
|
-
return
|
1574
|
-
end
|
1575
|
-
json_response = @app_templates_interface.update(app_template['id'], request_payload)
|
1576
|
-
|
1577
|
-
|
1578
|
-
if options[:json]
|
1579
|
-
print JSON.pretty_generate(json_response)
|
1580
|
-
print "\n"
|
1581
|
-
else
|
1582
|
-
print_green_success "Connected 2 tiers for app template #{app_template['name']}"
|
1583
|
-
get([app_template['name']])
|
1584
|
-
end
|
1585
|
-
|
1586
|
-
rescue RestClient::Exception => e
|
1587
|
-
print_rest_exception(e, options)
|
1588
|
-
exit 1
|
1589
|
-
end
|
1590
|
-
end
|
1591
|
-
|
1592
|
-
def available_tiers(args)
|
1593
|
-
options = {}
|
1594
|
-
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
1595
|
-
opts.banner = subcommand_usage()
|
1596
|
-
build_common_options(opts, options, [:json, :dry_run, :remote])
|
1597
|
-
end
|
1598
|
-
optparse.parse!(args)
|
1599
|
-
connect(options)
|
1600
|
-
params = {}
|
1601
|
-
|
1602
|
-
begin
|
1603
|
-
if options[:dry_run]
|
1604
|
-
print_dry_run @app_templates_interface.dry.list_tiers(params)
|
1605
|
-
return
|
1606
|
-
end
|
1607
|
-
json_response = @app_templates_interface.list_tiers(params)
|
1608
|
-
tiers = json_response["tiers"] # just a list of names
|
1609
|
-
if options[:json]
|
1610
|
-
puts JSON.pretty_generate(json_response)
|
1611
|
-
else
|
1612
|
-
print_h1 "Available Tiers"
|
1613
|
-
if tiers.empty?
|
1614
|
-
print yellow,"No tiers found.",reset,"\n"
|
1615
|
-
else
|
1616
|
-
# rows = tiers.collect do |tier|
|
1617
|
-
# {
|
1618
|
-
# id: tier['id'],
|
1619
|
-
# name: tier['name'],
|
1620
|
-
# }
|
1621
|
-
# end
|
1622
|
-
# print cyan
|
1623
|
-
# tp rows, [:name]
|
1624
|
-
print cyan
|
1625
|
-
tiers.each do |tier_name|
|
1626
|
-
puts tier_name
|
1627
|
-
end
|
1628
|
-
end
|
1629
|
-
print reset,"\n"
|
1630
|
-
end
|
1631
|
-
return 0
|
1632
|
-
rescue RestClient::Exception => e
|
1633
|
-
print_rest_exception(e, options)
|
1634
|
-
exit 1
|
1635
|
-
end
|
1636
|
-
|
1637
|
-
end
|
1638
|
-
|
1639
|
-
private
|
1640
|
-
|
1641
|
-
|
1642
|
-
def add_app_template_option_types(connected=true)
|
1643
|
-
[
|
1644
|
-
{'fieldName' => 'name', 'fieldLabel' => 'Name', 'type' => 'text', 'required' => true, 'displayOrder' => 1},
|
1645
|
-
{'fieldName' => 'description', 'fieldLabel' => 'Description', 'type' => 'text', 'required' => false, 'displayOrder' => 2},
|
1646
|
-
{'fieldName' => 'category', 'fieldLabel' => 'Category', 'type' => 'text', 'required' => false, 'displayOrder' => 3},
|
1647
|
-
#{'fieldName' => 'group', 'fieldLabel' => 'Group', 'type' => 'select', 'selectOptions' => (connected ? get_available_groups() : []), 'required' => true}
|
1648
|
-
]
|
1649
|
-
end
|
1650
|
-
|
1651
|
-
def update_app_template_option_types(connected=true)
|
1652
|
-
list = add_app_template_option_types(connected)
|
1653
|
-
list = list.reject {|it| ["group"].include? it['fieldName'] }
|
1654
|
-
list.each {|it| it['required'] = false }
|
1655
|
-
list
|
1656
|
-
end
|
1657
|
-
|
1658
|
-
def find_app_template_by_name_or_id(val)
|
1659
|
-
if val.to_s =~ /\A\d{1,}\Z/
|
1660
|
-
return find_app_template_by_id(val)
|
1661
|
-
else
|
1662
|
-
return find_app_template_by_name(val)
|
1663
|
-
end
|
1664
|
-
end
|
1665
|
-
|
1666
|
-
def find_app_template_by_id(id)
|
1667
|
-
begin
|
1668
|
-
json_response = @app_templates_interface.get(id.to_i)
|
1669
|
-
return json_response['appTemplate']
|
1670
|
-
rescue RestClient::Exception => e
|
1671
|
-
if e.response && e.response.code == 404
|
1672
|
-
print_red_alert "App Template not found by id #{id}"
|
1673
|
-
else
|
1674
|
-
raise e
|
1675
|
-
end
|
1676
|
-
end
|
1677
|
-
end
|
1678
|
-
|
1679
|
-
def find_app_template_by_name(name)
|
1680
|
-
app_templates = @app_templates_interface.list({name: name.to_s})['appTemplates']
|
1681
|
-
if app_templates.empty?
|
1682
|
-
print_red_alert "App Template not found by name #{name}"
|
1683
|
-
return nil
|
1684
|
-
elsif app_templates.size > 1
|
1685
|
-
print_red_alert "#{app_templates.size} app templates by name #{name}"
|
1686
|
-
print_app_templates_table(app_templates, {color: red})
|
1687
|
-
print reset,"\n"
|
1688
|
-
return nil
|
1689
|
-
else
|
1690
|
-
return app_templates[0]
|
1691
|
-
end
|
1692
|
-
end
|
1693
|
-
|
1694
|
-
def find_group_by_name(name)
|
1695
|
-
group_results = @groups_interface.get(name)
|
1696
|
-
if group_results['groups'].empty?
|
1697
|
-
print_red_alert "Group not found by name #{name}"
|
1698
|
-
return nil
|
1699
|
-
end
|
1700
|
-
return group_results['groups'][0]
|
1701
|
-
end
|
1702
|
-
|
1703
|
-
def find_cloud_by_name(group_id, name)
|
1704
|
-
option_results = @options_interface.options_for_source('clouds',{groupId: group_id})
|
1705
|
-
match = option_results['data'].find { |grp| grp['value'].to_s == name.to_s || grp['name'].downcase == name.downcase}
|
1706
|
-
if match.nil?
|
1707
|
-
print_red_alert "Cloud not found by name #{name}"
|
1708
|
-
return nil
|
1709
|
-
else
|
1710
|
-
return match['value']
|
1711
|
-
end
|
1712
|
-
end
|
1713
|
-
|
1714
|
-
def print_app_templates_table(app_templates, opts={})
|
1715
|
-
table_color = opts[:color] || cyan
|
1716
|
-
rows = app_templates.collect do |app_template|
|
1717
|
-
#instance_type_names = (app_template['instanceTypes'] || []).collect {|it| it['name'] }.join(', ')
|
1718
|
-
instance_type_names = []
|
1719
|
-
# if app_template['config'] && app_template['config']["tiers"]
|
1720
|
-
# app_template['config']["tiers"]
|
1721
|
-
# end
|
1722
|
-
{
|
1723
|
-
id: app_template['id'],
|
1724
|
-
name: app_template['name'],
|
1725
|
-
description: app_template['description'],
|
1726
|
-
category: app_template['category'],
|
1727
|
-
tiers_summary: format_app_template_tiers_summary(app_template)
|
1728
|
-
}
|
1729
|
-
end
|
1730
|
-
|
1731
|
-
term_width = current_terminal_width()
|
1732
|
-
tiers_col_width = 60
|
1733
|
-
if term_width > 190
|
1734
|
-
tiers_col_width += 130
|
1735
|
-
end
|
1736
|
-
columns = [
|
1737
|
-
:id,
|
1738
|
-
:name,
|
1739
|
-
:description,
|
1740
|
-
:category,
|
1741
|
-
{:tiers_summary => {:display_name => "TIERS", :max_width => tiers_col_width} }
|
1742
|
-
]
|
1743
|
-
if opts[:include_fields]
|
1744
|
-
columns = opts[:include_fields]
|
1745
|
-
end
|
1746
|
-
print table_color
|
1747
|
-
print as_pretty_table(rows, columns, opts)
|
1748
|
-
print reset
|
1749
|
-
end
|
1750
|
-
|
1751
|
-
def generate_id(len=16)
|
1752
|
-
id = ""
|
1753
|
-
len.times { id << (1 + rand(9)).to_s }
|
1754
|
-
id
|
1755
|
-
end
|
1756
|
-
|
1757
|
-
def format_app_template_tiers_summary(app_template)
|
1758
|
-
# don't use colors here, or cell truncation will not work
|
1759
|
-
str = ""
|
1760
|
-
if app_template["config"] && app_template["config"]["tiers"]
|
1761
|
-
tier_descriptions = app_template["config"]["tiers"].collect do |tier_name, tier_config|
|
1762
|
-
# maybe do Tier Name (instance, instance2)
|
1763
|
-
instance_blurbs = []
|
1764
|
-
if tier_config["instances"]
|
1765
|
-
tier_config["instances"].each do |instance_config|
|
1766
|
-
if instance_config["instance"] && instance_config["instance"]["type"]
|
1767
|
-
# only have type: code in the config, rather not name fetch remotely right now..
|
1768
|
-
# instance_blurbs << instance_config["instance"]["type"]
|
1769
|
-
instance_name = instance_config["instance"]["name"] || ""
|
1770
|
-
instance_type_code = instance_config["instance"]["type"]
|
1771
|
-
instances_str = "#{instance_type_code}"
|
1772
|
-
if instance_name.to_s != ""
|
1773
|
-
instances_str << " - #{instance_name}"
|
1774
|
-
end
|
1775
|
-
begin
|
1776
|
-
config_list = parse_scoped_instance_configs(instance_config)
|
1777
|
-
if config_list.size == 0
|
1778
|
-
instances_str << " (No configs)"
|
1779
|
-
elsif config_list.size == 1
|
1780
|
-
# configs_str = config_list.collect {|it|
|
1781
|
-
# str = ""
|
1782
|
-
# it[:scope].to_s.inspect
|
1783
|
-
# }.join(", ")
|
1784
|
-
the_config = config_list[0]
|
1785
|
-
scope_str = the_config[:scope].collect {|k,v| v.to_s }.join("/")
|
1786
|
-
instances_str << " (#{scope_str})"
|
1787
|
-
else
|
1788
|
-
instances_str << " (#{config_list.size} configs)"
|
1789
|
-
end
|
1790
|
-
rescue => err
|
1791
|
-
puts_error "Failed to parse instance scoped instance configs: #{err.class} #{err.message}"
|
1792
|
-
raise err
|
1793
|
-
end
|
1794
|
-
instance_blurbs << instances_str
|
1795
|
-
end
|
1796
|
-
end
|
1797
|
-
end
|
1798
|
-
if instance_blurbs.size > 0
|
1799
|
-
tier_name + ": #{instance_blurbs.join(', ')}"
|
1800
|
-
else
|
1801
|
-
tier_name + ": (empty)"
|
1802
|
-
end
|
1803
|
-
end
|
1804
|
-
str += tier_descriptions.compact.join(", ")
|
1805
|
-
end
|
1806
|
-
str
|
1807
|
-
end
|
1808
|
-
|
1809
|
-
def print_app_template_details(app_template)
|
1810
|
-
print cyan
|
1811
|
-
description_cols = {
|
1812
|
-
"ID" => 'id',
|
1813
|
-
"Name" => 'name',
|
1814
|
-
"Description" => 'description',
|
1815
|
-
"Category" => 'category',
|
1816
|
-
#"Image" => lambda {|it| it['config'] ? it['config']['image'] : '' },
|
1817
|
-
}
|
1818
|
-
if app_template["config"] && app_template["config"]["image"]
|
1819
|
-
description_cols["Image"] = lambda {|it| app_template["config"]["image"] }
|
1820
|
-
# else
|
1821
|
-
# '/assets/apps/template.png'
|
1822
|
-
end
|
1823
|
-
print_description_list(description_cols, app_template)
|
1824
|
-
# print_h2 "Tiers"
|
1825
|
-
if app_template["config"] && app_template["config"]["tiers"] && app_template["config"]["tiers"].keys.size != 0
|
1826
|
-
print cyan
|
1827
|
-
#puts as_yaml(app_template["config"]["tiers"])
|
1828
|
-
app_template["config"]["tiers"].each do |tier_name, tier_config|
|
1829
|
-
# print_h2 "Tier: #{tier_name}"
|
1830
|
-
print_h2 tier_name
|
1831
|
-
# puts " Instances:"
|
1832
|
-
if tier_config['instances'] && tier_config['instances'].size != 0
|
1833
|
-
# puts as_yaml(tier)
|
1834
|
-
tier_config['instances'].each_with_index do |instance_config, instance_index|
|
1835
|
-
instance_name = instance_config["instance"]["name"] || ""
|
1836
|
-
instance_type_code = ""
|
1837
|
-
if instance_config["instance"]["type"]
|
1838
|
-
instance_type_code = instance_config["instance"]["type"]
|
1839
|
-
end
|
1840
|
-
instance_bullet = ""
|
1841
|
-
# instance_bullet += "#{green} - #{bold}#{instance_type_code}#{reset}"
|
1842
|
-
instance_bullet += "#{green}#{bold}#{instance_type_code}#{reset}"
|
1843
|
-
if instance_name.to_s != ""
|
1844
|
-
instance_bullet += "#{green} - #{instance_name}#{reset}"
|
1845
|
-
end
|
1846
|
-
puts instance_bullet
|
1847
|
-
# print "\n"
|
1848
|
-
begin
|
1849
|
-
config_list = parse_scoped_instance_configs(instance_config)
|
1850
|
-
print cyan
|
1851
|
-
if config_list.size > 0
|
1852
|
-
print "\n"
|
1853
|
-
if config_list.size == 1
|
1854
|
-
puts " Config:"
|
1855
|
-
else
|
1856
|
-
puts " Configs (#{config_list.size}):"
|
1857
|
-
end
|
1858
|
-
config_list.each do |config_obj|
|
1859
|
-
# puts " = #{config_obj[:scope].inspect}"
|
1860
|
-
config_scope = config_obj[:scope]
|
1861
|
-
scoped_instance_config = config_obj[:config]
|
1862
|
-
config_description = ""
|
1863
|
-
config_items = []
|
1864
|
-
if config_scope[:environment]
|
1865
|
-
config_items << {label: "Environment", value: config_scope[:environment]}
|
1866
|
-
end
|
1867
|
-
if config_scope[:group]
|
1868
|
-
config_items << {label: "Group", value: config_scope[:group]}
|
1869
|
-
end
|
1870
|
-
if config_scope[:cloud]
|
1871
|
-
config_items << {label: "Cloud", value: config_scope[:cloud]}
|
1872
|
-
end
|
1873
|
-
# if scoped_instance_config['plan'] && scoped_instance_config['plan']['code']
|
1874
|
-
# config_items << {label: "Plan", value: scoped_instance_config['plan']['code']}
|
1875
|
-
# end
|
1876
|
-
config_description = config_items.collect {|item| "#{item[:label]}: #{item[:value]}"}.join(", ")
|
1877
|
-
puts " * #{config_description}"
|
1878
|
-
end
|
1879
|
-
else
|
1880
|
-
print white," Instance has no configs, see `app-templates add-instance-config \"#{app_template['name']}\" \"#{tier_name}\" \"#{instance_type_code}\"`",reset,"\n"
|
1881
|
-
end
|
1882
|
-
rescue => err
|
1883
|
-
#puts_error "Failed to parse instance scoped instance configs for app template #{app_template['id']} #{app_template['name']} Exception: #{err.class} #{err.message}"
|
1884
|
-
end
|
1885
|
-
print "\n"
|
1886
|
-
#puts as_yaml(instance_config)
|
1887
|
-
# todo: iterate over
|
1888
|
-
# instance_config["groups"][group_name]["clouds"][cloud_name]
|
1889
|
-
end
|
1890
|
-
|
1891
|
-
print cyan
|
1892
|
-
if tier_config['bootOrder']
|
1893
|
-
puts "Boot Order: #{tier_config['bootOrder']}"
|
1894
|
-
end
|
1895
|
-
if tier_config['linkedTiers'] && !tier_config['linkedTiers'].empty?
|
1896
|
-
puts "Connected Tiers: #{tier_config['linkedTiers'].join(', ')}"
|
1897
|
-
end
|
1898
|
-
|
1899
|
-
else
|
1900
|
-
print white," Tier is empty, see `app-templates add-instance \"#{app_template['name']}\" \"#{tier_name}\"`",reset,"\n"
|
1901
|
-
end
|
1902
|
-
# print "\n"
|
1903
|
-
|
1904
|
-
end
|
1905
|
-
# print "\n"
|
1906
|
-
|
1907
|
-
else
|
1908
|
-
print white,"\nTemplate is empty, see `app-templates add-tier \"#{app_template['name']}\"`",reset,"\n"
|
1909
|
-
end
|
1910
|
-
end
|
1911
|
-
|
1912
|
-
# this parses the environments => groups => clouds tree structure
|
1913
|
-
# and returns a list of objects like {scope: {group:'thegroup'}, config: Map}
|
1914
|
-
# this would be be better as a recursive function, brute forced for now.
|
1915
|
-
def parse_scoped_instance_configs(instance_config)
|
1916
|
-
config_list = []
|
1917
|
-
if instance_config['environments'] && instance_config['environments'].keys.size > 0
|
1918
|
-
instance_config['environments'].each do |env_name, env_config|
|
1919
|
-
if env_config['groups']
|
1920
|
-
env_config['groups'].each do |group_name, group_config|
|
1921
|
-
if group_config['clouds'] && !group_config['clouds'].empty?
|
1922
|
-
group_config['clouds'].each do |cloud_name, cloud_config|
|
1923
|
-
config_list << {config: cloud_config, scope: {environment: env_name, group: group_name, cloud: cloud_name}}
|
1924
|
-
end
|
1925
|
-
end
|
1926
|
-
if (!group_config['clouds'] || group_config['clouds'].empty?)
|
1927
|
-
config_list << {config: group_config, scope: {environment: env_name, group: group_name}}
|
1928
|
-
end
|
1929
|
-
end
|
1930
|
-
end
|
1931
|
-
if env_config['clouds'] && !env_config['clouds'].empty?
|
1932
|
-
env_config['clouds'].each do |cloud_name, cloud_config|
|
1933
|
-
config_list << {config: cloud_config, scope: {environment: env_name, cloud: cloud_name}}
|
1934
|
-
end
|
1935
|
-
end
|
1936
|
-
if (!env_config['groups'] || env_config['groups'].empty?) && (!env_config['clouds'] || env_config['clouds'].empty?)
|
1937
|
-
config_list << {config: env_config, scope: {environment: env_name}}
|
1938
|
-
end
|
1939
|
-
end
|
1940
|
-
end
|
1941
|
-
if instance_config['groups']
|
1942
|
-
instance_config['groups'].each do |group_name, group_config|
|
1943
|
-
if group_config['clouds'] && !group_config['clouds'].empty?
|
1944
|
-
group_config['clouds'].each do |cloud_name, cloud_config|
|
1945
|
-
config_list << {config: cloud_config, scope: {group: group_name, cloud: cloud_name}}
|
1946
|
-
end
|
1947
|
-
end
|
1948
|
-
if (!group_config['clouds'] || group_config['clouds'].empty?)
|
1949
|
-
config_list << {config: group_config, scope: {group: group_name}}
|
1950
|
-
end
|
1951
|
-
end
|
1952
|
-
end
|
1953
|
-
if instance_config['clouds']
|
1954
|
-
instance_config['clouds'].each do |cloud_name, cloud_config|
|
1955
|
-
config_list << {config: cloud_config, scope: {cloud: cloud_name}}
|
1956
|
-
end
|
1957
|
-
end
|
1958
|
-
return config_list
|
1959
|
-
end
|
1960
|
-
|
1961
|
-
def link_tiers(tiers, tier_names)
|
1962
|
-
# tiers = app_template["config"]["tiers"]
|
1963
|
-
tier_names = [tier_names].flatten.collect {|it| it }.compact.uniq
|
1964
|
-
if !tiers
|
1965
|
-
print_red_alert "No tiers found for template"
|
1966
|
-
return false
|
1967
|
-
end
|
1968
|
-
|
1969
|
-
existing_tier_names = tiers.keys
|
1970
|
-
matching_tier_names = tier_names.map {|tier_name|
|
1971
|
-
existing_tier_names.find {|k| k.downcase == tier_name.downcase }
|
1972
|
-
}.compact
|
1973
|
-
if matching_tier_names.size != tier_names.size
|
1974
|
-
print_red_alert "Template does not contain tiers: '#{tier_names}'"
|
1975
|
-
return false
|
1976
|
-
end
|
1977
|
-
matching_tier_names.each do |tier_name|
|
1978
|
-
tier = tiers[tier_name]
|
1979
|
-
tier['linkedTiers'] ||= []
|
1980
|
-
other_tier_names = matching_tier_names.select {|it| tier_name != it}
|
1981
|
-
other_tier_names.each do |other_tier_name|
|
1982
|
-
if !tier['linkedTiers'].include?(other_tier_name)
|
1983
|
-
tier['linkedTiers'].push(other_tier_name)
|
1984
|
-
end
|
1985
|
-
end
|
1986
|
-
end
|
1987
|
-
return true
|
1988
|
-
end
|
1989
|
-
|
1990
|
-
def unlink_tiers(tiers, tier_names)
|
1991
|
-
# tiers = app_template["config"]["tiers"]
|
1992
|
-
tier_names = [tier_names].flatten.collect {|it| it }.compact.uniq
|
1993
|
-
if !tiers
|
1994
|
-
print_red_alert "No tiers found for template"
|
1995
|
-
return false
|
1996
|
-
end
|
1997
|
-
|
1998
|
-
existing_tier_names = tiers.keys
|
1999
|
-
matching_tier_names = tier_names.map {|tier_name|
|
2000
|
-
existing_tier_names.find {|k| k.downcase == tier_name.downcase }
|
2001
|
-
}.compact
|
2002
|
-
if matching_tier_names.size != tier_names.size
|
2003
|
-
print_red_alert "Template does not contain tiers: '#{tier_names}'"
|
2004
|
-
return false
|
2005
|
-
end
|
2006
|
-
matching_tier_names.each do |tier_name|
|
2007
|
-
tier = tiers[tier_name]
|
2008
|
-
tier['linkedTiers'] ||= []
|
2009
|
-
other_tier_names = matching_tier_names.select {|it| tier_name != it}
|
2010
|
-
other_tier_names.each do |other_tier_name|
|
2011
|
-
if tier['linkedTiers'].include?(other_tier_name)
|
2012
|
-
tier['linkedTiers'] = tier['linkedTiers'].reject {|it| it == other_tier_name }
|
2013
|
-
end
|
2014
|
-
end
|
2015
|
-
end
|
2016
|
-
return true
|
2017
|
-
end
|
2018
|
-
|
2019
|
-
end
|