morpheus-cli 4.1.12 → 4.1.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Dockerfile +1 -1
- data/lib/morpheus/api/api_client.rb +6 -2
- data/lib/morpheus/api/library_spec_template_types_interface.rb +49 -0
- data/lib/morpheus/api/{library_resource_specs_interface.rb → library_spec_templates_interface.rb} +1 -1
- data/lib/morpheus/api/users_interface.rb +2 -2
- data/lib/morpheus/cli.rb +1 -1
- data/lib/morpheus/cli/hosts.rb +8 -0
- data/lib/morpheus/cli/jobs_command.rb +8 -0
- data/lib/morpheus/cli/library_spec_templates_command.rb +644 -0
- data/lib/morpheus/cli/mixins/accounts_helper.rb +1 -1
- data/lib/morpheus/cli/tasks.rb +17 -8
- data/lib/morpheus/cli/users.rb +90 -12
- data/lib/morpheus/cli/version.rb +1 -1
- data/lib/morpheus/cli/workflows.rb +12 -8
- metadata +6 -4
- data/lib/morpheus/cli/library_resource_specs_command.rb +0 -409
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ac0df1975e8da11d8f660ff39e84e186395b54b32f5022d444a182afc63d3df5
|
4
|
+
data.tar.gz: b3171f8c621d1090962322eb95478653e51740d1d08c9aafb1db9b20d60f619e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d554ef4a1d27f7763e41eebeca34952ee24ce70072148999615bb50cea6863ebb13e9527751ab0701c6ebd5af300986cf12703c4e88059462ee02a05f1d95902
|
7
|
+
data.tar.gz: a223e0e79f20bf202743e2592186c249da94cb81accd63cef4d1f38c44571dce8e761dd8282cc355fdd4e7121f6117c731ed0c081fa4a62cb1d940b0eda344fb
|
data/Dockerfile
CHANGED
@@ -602,8 +602,12 @@ class Morpheus::APIClient
|
|
602
602
|
Morpheus::LibraryClusterLayoutsInterface.new(@access_token, @refresh_token, @expires_at, @base_url).setopts(@options)
|
603
603
|
end
|
604
604
|
|
605
|
-
def
|
606
|
-
Morpheus::
|
605
|
+
def library_spec_templates
|
606
|
+
Morpheus::LibrarySpecTemplatesInterface.new(@access_token, @refresh_token, @expires_at, @base_url).setopts(@options)
|
607
|
+
end
|
608
|
+
|
609
|
+
def library_spec_template_types
|
610
|
+
Morpheus::LibrarySpecTemplateTypesInterface.new(@access_token, @refresh_token, @expires_at, @base_url).setopts(@options)
|
607
611
|
end
|
608
612
|
|
609
613
|
def packages
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'morpheus/api/api_client'
|
2
|
+
|
3
|
+
class Morpheus::LibrarySpecTemplateTypesInterface < 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, params={})
|
12
|
+
raise "#{self.class}.get() passed a blank id!" if id.to_s == ''
|
13
|
+
url = "#{@base_url}/api/library/spec-template-types/#{id}"
|
14
|
+
headers = { params: params, authorization: "Bearer #{@access_token}" }
|
15
|
+
opts = {method: :get, url: url, headers: headers}
|
16
|
+
execute(opts)
|
17
|
+
end
|
18
|
+
|
19
|
+
def list(params={})
|
20
|
+
url = "#{@base_url}/api/library/spec-template-types"
|
21
|
+
headers = { params: params, authorization: "Bearer #{@access_token}" }
|
22
|
+
opts = {method: :get, url: url, headers: headers}
|
23
|
+
execute(opts)
|
24
|
+
end
|
25
|
+
|
26
|
+
# def create(options)
|
27
|
+
# url = "#{@base_url}/api/library/spec-template-types"
|
28
|
+
# headers = { :authorization => "Bearer #{@access_token}", 'Content-Type' => 'application/json' }
|
29
|
+
# payload = options
|
30
|
+
# opts = {method: :post, url: url, headers: headers, payload: payload.to_json}
|
31
|
+
# execute(opts)
|
32
|
+
# end
|
33
|
+
|
34
|
+
# def update(id, options)
|
35
|
+
# url = "#{@base_url}/api/library/spec-template-types/#{id}"
|
36
|
+
# headers = { :authorization => "Bearer #{@access_token}", 'Content-Type' => 'application/json' }
|
37
|
+
# payload = options
|
38
|
+
# opts = {method: :put, url: url, headers: headers, payload: payload.to_json}
|
39
|
+
# execute(opts)
|
40
|
+
# end
|
41
|
+
|
42
|
+
# def destroy(id, payload={})
|
43
|
+
# url = "#{@base_url}/api/library/spec-template-types/#{id}"
|
44
|
+
# headers = { :authorization => "Bearer #{@access_token}", 'Content-Type' => 'application/json' }
|
45
|
+
# opts = {method: :delete, url: url, headers: headers, payload: payload.to_json}
|
46
|
+
# execute(opts)
|
47
|
+
# end
|
48
|
+
|
49
|
+
end
|
data/lib/morpheus/api/{library_resource_specs_interface.rb → library_spec_templates_interface.rb}
RENAMED
@@ -1,6 +1,6 @@
|
|
1
1
|
require 'morpheus/api/api_client'
|
2
2
|
|
3
|
-
class Morpheus::
|
3
|
+
class Morpheus::LibrarySpecTemplatesInterface < Morpheus::APIClient
|
4
4
|
def initialize(access_token, refresh_token,expires_at = nil, base_url=nil)
|
5
5
|
@access_token = access_token
|
6
6
|
@refresh_token = refresh_token
|
@@ -8,10 +8,10 @@ class Morpheus::UsersInterface < Morpheus::APIClient
|
|
8
8
|
@expires_at = expires_at
|
9
9
|
end
|
10
10
|
|
11
|
-
def get(account_id, id)
|
11
|
+
def get(account_id, id, params={})
|
12
12
|
raise "#{self.class}.get() passed a blank id!" if id.to_s == ''
|
13
13
|
url = build_url(account_id, id)
|
14
|
-
headers = { params:
|
14
|
+
headers = { params: params, authorization: "Bearer #{@access_token}" }
|
15
15
|
opts = {method: :get, url: url, timeout: 10, headers: headers}
|
16
16
|
execute(opts)
|
17
17
|
end
|
data/lib/morpheus/cli.rb
CHANGED
@@ -122,7 +122,7 @@ module Morpheus
|
|
122
122
|
load 'morpheus/cli/library_container_templates_command.rb'
|
123
123
|
load 'morpheus/cli/library_option_types_command.rb'
|
124
124
|
load 'morpheus/cli/library_option_lists_command.rb'
|
125
|
-
load 'morpheus/cli/
|
125
|
+
load 'morpheus/cli/library_spec_templates_command.rb'
|
126
126
|
load 'morpheus/cli/monitoring_incidents_command.rb'
|
127
127
|
load 'morpheus/cli/monitoring_checks_command.rb'
|
128
128
|
load 'morpheus/cli/monitoring_contacts_command.rb'
|
data/lib/morpheus/cli/hosts.rb
CHANGED
@@ -1191,6 +1191,9 @@ class Morpheus::Cli::Hosts
|
|
1191
1191
|
opts.on('--install-agent [on|off]', String, "Install Agent? Pass false to manually install agent. Default is true.") do |val|
|
1192
1192
|
options['installAgent'] = val.to_s == 'on' || val.to_s == 'true' || val.to_s == ''
|
1193
1193
|
end
|
1194
|
+
opts.on('-g', '--group GROUP', String, "Group to assign to new instance.") do |val|
|
1195
|
+
options[:group] = val
|
1196
|
+
end
|
1194
1197
|
# opts.on('--instance-type-id ID', String, "Instance Type ID for the new instance.") do |val|
|
1195
1198
|
# options['instanceTypeId'] = val.to_s == 'on' || val.to_s == 'true' || val.to_s == ''
|
1196
1199
|
# end
|
@@ -1222,6 +1225,11 @@ class Morpheus::Cli::Hosts
|
|
1222
1225
|
if account_id
|
1223
1226
|
payload['server']['account'] = {id: account}
|
1224
1227
|
end
|
1228
|
+
if options[:group]
|
1229
|
+
group = options[:group] ? find_group_by_name_or_id_for_provisioning(options[:group]) : nil
|
1230
|
+
return 1 if group.nil?
|
1231
|
+
params['provisionSiteId'] = group['id']
|
1232
|
+
end
|
1225
1233
|
payload['server'].merge!(params)
|
1226
1234
|
['installAgent','instanceTypeId'].each do |k|
|
1227
1235
|
if options[k] != nil
|
@@ -34,6 +34,9 @@ class Morpheus::Cli::JobsCommand
|
|
34
34
|
opts.on("--source [all|user|discovered]", String, "Filters job based upon specified source. Default is all") do |val|
|
35
35
|
options[:source] = val.to_s
|
36
36
|
end
|
37
|
+
opts.on("--internal [true|false]", String, "Filters job based on internal flag. Internal jobs are excluded by default.") do |val|
|
38
|
+
params["internalOnly"] = (val.to_s != "false")
|
39
|
+
end
|
37
40
|
build_common_options(opts, options, [:list, :query, :json, :yaml, :csv, :fields, :dry_run, :remote])
|
38
41
|
opts.footer = "List jobs."
|
39
42
|
end
|
@@ -68,6 +71,9 @@ class Morpheus::Cli::JobsCommand
|
|
68
71
|
title = "Morpheus Jobs"
|
69
72
|
subtitles = []
|
70
73
|
subtitles += parse_list_subtitles(options)
|
74
|
+
if params["internalOnly"]
|
75
|
+
subtitles << "internalOnly: #{params['internalOnly']}"
|
76
|
+
end
|
71
77
|
print_h1 title, subtitles
|
72
78
|
|
73
79
|
jobs = json_response['jobs']
|
@@ -178,6 +184,7 @@ class Morpheus::Cli::JobsCommand
|
|
178
184
|
|
179
185
|
print cyan
|
180
186
|
description_cols = {
|
187
|
+
"ID" => lambda {|it| it['id'] },
|
181
188
|
"Name" => lambda {|it| it['name']},
|
182
189
|
"Job Type" => lambda {|it| it['type']['name']},
|
183
190
|
"Enabled" => lambda {|it| format_boolean(it['enabled'])},
|
@@ -739,6 +746,7 @@ class Morpheus::Cli::JobsCommand
|
|
739
746
|
process = exec['process']
|
740
747
|
print cyan
|
741
748
|
description_cols = {
|
749
|
+
"ID" => lambda {|it| it['id'] },
|
742
750
|
"Job" => lambda {|it| it['job'] ? it['job']['name'] : ''},
|
743
751
|
"Job Type" => lambda {|it| it['job'] && it['job']['type'] ? (it['job']['type']['code'] == 'morpheus.workflow' ? 'Workflow' : 'Task') : ''},
|
744
752
|
# "Description" => lambda {|it| it['description'] || (it['job'] ? it['job']['description'] : '') },
|
@@ -0,0 +1,644 @@
|
|
1
|
+
require 'morpheus/cli/cli_command'
|
2
|
+
|
3
|
+
class Morpheus::Cli::LibrarySpecTemplatesCommand
|
4
|
+
include Morpheus::Cli::CliCommand
|
5
|
+
set_command_name :'library-spec-templates'
|
6
|
+
set_command_hidden
|
7
|
+
register_subcommands :list, :get, :add, :update, :remove, :list_types
|
8
|
+
|
9
|
+
def connect(opts)
|
10
|
+
@api_client = establish_remote_appliance_connection(opts)
|
11
|
+
@spec_templates_interface = @api_client.library_spec_templates
|
12
|
+
@spec_template_types_interface = @api_client.library_spec_template_types
|
13
|
+
end
|
14
|
+
|
15
|
+
def handle(args)
|
16
|
+
handle_subcommand(args)
|
17
|
+
end
|
18
|
+
|
19
|
+
def list(args)
|
20
|
+
options = {}
|
21
|
+
params = {}
|
22
|
+
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
23
|
+
opts.banner = subcommand_usage()
|
24
|
+
build_common_options(opts, options, [:list, :query, :json, :yaml, :csv, :fields, :dry_run, :remote])
|
25
|
+
opts.footer = "List spec templates."
|
26
|
+
end
|
27
|
+
optparse.parse!(args)
|
28
|
+
connect(options)
|
29
|
+
if args.count > 0
|
30
|
+
print_error Morpheus::Terminal.angry_prompt
|
31
|
+
puts_error "wrong number of arguments, expected 0 and got (#{args.count}) #{args.inspect}\n#{optparse}"
|
32
|
+
return 1
|
33
|
+
end
|
34
|
+
begin
|
35
|
+
# construct payload
|
36
|
+
params.merge!(parse_list_options(options))
|
37
|
+
@spec_templates_interface.setopts(options)
|
38
|
+
if options[:dry_run]
|
39
|
+
print_dry_run @spec_templates_interface.dry.list(params)
|
40
|
+
return
|
41
|
+
end
|
42
|
+
# do it
|
43
|
+
json_response = @spec_templates_interface.list(params)
|
44
|
+
render_result = render_with_format(json_response, options, 'specTemplates')
|
45
|
+
return 0 if render_result
|
46
|
+
resource_specs = json_response['specTemplates']
|
47
|
+
title = "Morpheus Library - Spec Templates"
|
48
|
+
subtitles = []
|
49
|
+
subtitles += parse_list_subtitles(options)
|
50
|
+
print_h1 title, subtitles
|
51
|
+
if resource_specs.empty?
|
52
|
+
print cyan,"No spec templates found.",reset,"\n"
|
53
|
+
else
|
54
|
+
# print_resource_specs_table(resource_specs, options)
|
55
|
+
columns = [
|
56
|
+
{"ID" => lambda {|resource_spec| resource_spec['id'] } },
|
57
|
+
{"NAME" => lambda {|resource_spec| resource_spec['name'] } },
|
58
|
+
{"TYPE" => lambda {|resource_spec| resource_spec['type']['name'] rescue '' } },
|
59
|
+
{"SOURCE" => lambda {|resource_spec| resource_spec['file']['sourceType'] rescue '' } },
|
60
|
+
{"CREATED" => lambda {|resource_spec| format_local_dt(resource_spec['dateCreated']) } },
|
61
|
+
]
|
62
|
+
print as_pretty_table(resource_specs, columns, options)
|
63
|
+
print_results_pagination(json_response)
|
64
|
+
end
|
65
|
+
print reset,"\n"
|
66
|
+
rescue RestClient::Exception => e
|
67
|
+
print_rest_exception(e, options)
|
68
|
+
return 1
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def get(args)
|
73
|
+
options = {}
|
74
|
+
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
75
|
+
opts.banner = subcommand_usage("[name]")
|
76
|
+
build_common_options(opts, options, [:json, :yaml, :csv, :fields, :dry_run, :remote])
|
77
|
+
end
|
78
|
+
optparse.parse!(args)
|
79
|
+
if args.count < 1
|
80
|
+
puts optparse
|
81
|
+
return 1
|
82
|
+
end
|
83
|
+
connect(options)
|
84
|
+
id_list = parse_id_list(args)
|
85
|
+
return run_command_for_each_arg(id_list) do |arg|
|
86
|
+
_get(arg, options)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def _get(id, options)
|
91
|
+
|
92
|
+
begin
|
93
|
+
resource_spec = find_resource_spec_by_name_or_id(id)
|
94
|
+
if resource_spec.nil?
|
95
|
+
return 1
|
96
|
+
end
|
97
|
+
@spec_templates_interface.setopts(options)
|
98
|
+
if options[:dry_run]
|
99
|
+
print_dry_run @spec_templates_interface.dry.get(resource_spec['id'])
|
100
|
+
return
|
101
|
+
end
|
102
|
+
json_response = @spec_templates_interface.get(resource_spec['id'])
|
103
|
+
resource_spec = json_response['specTemplate']
|
104
|
+
instances = json_response['instances'] || []
|
105
|
+
servers = json_response['servers'] || []
|
106
|
+
if options[:json]
|
107
|
+
puts as_json(json_response, options, 'specTemplate')
|
108
|
+
return 0
|
109
|
+
elsif options[:yaml]
|
110
|
+
puts as_yaml(json_response, options, 'specTemplate')
|
111
|
+
return 0
|
112
|
+
elsif options[:csv]
|
113
|
+
puts records_as_csv([json_response['specTemplate']], options)
|
114
|
+
return 0
|
115
|
+
end
|
116
|
+
|
117
|
+
print_h1 "Spec Template Details"
|
118
|
+
print cyan
|
119
|
+
description_cols = {
|
120
|
+
"ID" => lambda {|it| it['id'] },
|
121
|
+
"Name" => lambda {|it| it['name'] },
|
122
|
+
"Type" => lambda {|it| it['type']['name'] rescue '' },
|
123
|
+
"Source" => lambda {|it| it['file']['sourceType'] rescue '' },
|
124
|
+
#"Owner" => lambda {|it| it['account'] ? it['account']['name'] : '' },
|
125
|
+
"Created" => lambda {|it| format_local_dt(it['dateCreated']) },
|
126
|
+
"Created By" => lambda {|it| it['createdBy'] },
|
127
|
+
"Updated" => lambda {|it| format_local_dt(it['lastUpdated']) },
|
128
|
+
"Updated By" => lambda {|it| it['updatedBy'] },
|
129
|
+
# "Created" => lambda {|it| format_local_dt(it['dateCreated']) + " by #{it['createdBy']}" },
|
130
|
+
# "Updated" => lambda {|it| format_local_dt(it['lastUpdated']) + " by #{it['updatedBy'] || it['createdBy']}" },
|
131
|
+
}
|
132
|
+
print_description_list(description_cols, resource_spec)
|
133
|
+
|
134
|
+
file_content = resource_spec['file']
|
135
|
+
print_h2 "Content"
|
136
|
+
if file_content
|
137
|
+
if file_content['sourceType'] == 'local'
|
138
|
+
puts file_content['content']
|
139
|
+
elsif file_content['sourceType'] == 'url'
|
140
|
+
puts "URL: #{file_content['contentPath']}"
|
141
|
+
elsif file_content['sourceType'] == 'repository'
|
142
|
+
puts "Repository: #{file_content['repository']['name'] rescue 'n/a'}"
|
143
|
+
puts "Path: #{file_content['contentPath']}"
|
144
|
+
if file_content['contentRef']
|
145
|
+
puts "Ref: #{file_content['contentRef']}"
|
146
|
+
end
|
147
|
+
else
|
148
|
+
puts "Source: #{file_content['sourceType']}"
|
149
|
+
puts "Path: #{file_content['contentPath']}"
|
150
|
+
end
|
151
|
+
else
|
152
|
+
print yellow,"No file content.",reset,"\n"
|
153
|
+
end
|
154
|
+
|
155
|
+
print reset,"\n"
|
156
|
+
return 0
|
157
|
+
rescue RestClient::Exception => e
|
158
|
+
print_rest_exception(e, options)
|
159
|
+
return 1
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
def add(args)
|
164
|
+
options = {}
|
165
|
+
params = {}
|
166
|
+
file_params = {}
|
167
|
+
template_type = nil
|
168
|
+
source_type = nil
|
169
|
+
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
170
|
+
opts.banner = subcommand_usage("[name]")
|
171
|
+
opts.on('--name VALUE', String, "Name") do |val|
|
172
|
+
params['name'] = val
|
173
|
+
end
|
174
|
+
opts.on('--type VALUE', String, "Spec Template Type. kubernetes, helm, terraform") do |val|
|
175
|
+
template_type = val.to_s
|
176
|
+
end
|
177
|
+
opts.on('--source VALUE', String, "Source Type. local, repository, url") do |val|
|
178
|
+
source_type = val.to_s
|
179
|
+
end
|
180
|
+
opts.on('--content TEXT', String, "Contents of the template. This implies source is local.") do |val|
|
181
|
+
source_type = 'local' if source_type.nil?
|
182
|
+
file_params['content'] = val
|
183
|
+
end
|
184
|
+
opts.on('--file FILE', "File containing the template. This can be used instead of --content" ) do |filename|
|
185
|
+
source_type = 'local' if source_type.nil?
|
186
|
+
full_filename = File.expand_path(filename)
|
187
|
+
if File.exists?(full_filename)
|
188
|
+
file_params['content'] = File.read(full_filename)
|
189
|
+
else
|
190
|
+
print_red_alert "File not found: #{full_filename}"
|
191
|
+
exit 1
|
192
|
+
end
|
193
|
+
# use the filename as the name by default.
|
194
|
+
if !params['name']
|
195
|
+
params['name'] = File.basename(full_filename)
|
196
|
+
end
|
197
|
+
end
|
198
|
+
opts.on('--url VALUE', String, "URL, for use when source is url") do |val|
|
199
|
+
file_params['contentPath'] = val
|
200
|
+
end
|
201
|
+
opts.on('--content-path VALUE', String, "Content Path, for use when source is repository or url") do |val|
|
202
|
+
file_params['contentPath'] = val
|
203
|
+
end
|
204
|
+
opts.on('--content-ref VALUE', String, "Content Ref (Version Ref), for use when source is repository") do |val|
|
205
|
+
file_params['contentRef'] = val
|
206
|
+
end
|
207
|
+
# opts.on('--enabled [on|off]', String, "Can be used to disable it") do |val|
|
208
|
+
# options['enabled'] = !(val.to_s == 'off' || val.to_s == 'false')
|
209
|
+
# end
|
210
|
+
build_common_options(opts, options, [:options, :payload, :json, :dry_run, :remote, :quiet])
|
211
|
+
opts.footer = "Create a new spec template."
|
212
|
+
end
|
213
|
+
optparse.parse!(args)
|
214
|
+
# support [name] as first argument
|
215
|
+
if args[0]
|
216
|
+
params['name'] = args[0]
|
217
|
+
end
|
218
|
+
connect(options)
|
219
|
+
begin
|
220
|
+
# construct payload
|
221
|
+
payload = nil
|
222
|
+
if options[:payload]
|
223
|
+
payload = options[:payload]
|
224
|
+
else
|
225
|
+
# merge -O options into normally parsed options
|
226
|
+
params.deep_merge!(options[:options].reject {|k,v| k.is_a?(Symbol) }) if options[:options]
|
227
|
+
# prompt
|
228
|
+
if params['name'].nil?
|
229
|
+
params['name'] = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'name', 'fieldLabel' => 'Name', 'type' => 'text', 'required' => true}], options[:options], @api_client,{})['name']
|
230
|
+
end
|
231
|
+
if template_type.nil?
|
232
|
+
# should use code instead probably...
|
233
|
+
#template_type = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'type', 'fieldLabel' => 'Type', 'type' => 'select', 'optionSource' => 'resourceSpecType', 'required' => true}], options[:options], @api_client,{})['type']
|
234
|
+
#params['type'] = {'id' => template_type}
|
235
|
+
spec_type_dropdown = get_all_spec_template_types.collect { |it| {'value' => it['code'], 'name' => it['name']} }
|
236
|
+
template_type = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'type', 'fieldLabel' => 'Type', 'type' => 'select', 'selectOptions' => spec_type_dropdown, 'required' => true}], options[:options], @api_client,{})['type']
|
237
|
+
params['type'] = {'code' => template_type}
|
238
|
+
else
|
239
|
+
# gotta look up id
|
240
|
+
template_type_obj = find_spec_template_type_by_name_or_code_id(template_type)
|
241
|
+
return 1 if template_type_obj.nil?
|
242
|
+
template_type = template_type_obj['code']
|
243
|
+
params['type'] = {'code' => template_type}
|
244
|
+
end
|
245
|
+
if source_type.nil?
|
246
|
+
source_type = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'source', 'fieldLabel' => 'Source', 'type' => 'select', 'optionSource' => 'fileContentSource', 'required' => true, 'defaultValue' => 'local'}], options[:options], @api_client,{})['source']
|
247
|
+
file_params['sourceType'] = source_type
|
248
|
+
end
|
249
|
+
if source_type == "local"
|
250
|
+
# prompt for content
|
251
|
+
if file_params['content'].nil?
|
252
|
+
file_params['content'] = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'content', 'type' => 'code-editor', 'fieldLabel' => 'Content', 'required' => true, 'description' => 'The file content'}], options[:options])['content']
|
253
|
+
end
|
254
|
+
elsif source_type == "url"
|
255
|
+
if file_params['contentPath'].nil?
|
256
|
+
file_params['contentPath'] = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'url', 'fieldLabel' => 'URL', 'type' => 'text', 'required' => true}], options[:options], @api_client,{})['url']
|
257
|
+
end
|
258
|
+
elsif source_type == "repository"
|
259
|
+
if file_params['repository'].nil?
|
260
|
+
repository_id = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'repositoryId', 'fieldLabel' => 'Repository', 'type' => 'select', 'optionSource' => 'codeRepositories', 'required' => true}], options[:options], @api_client,{})['repositoryId']
|
261
|
+
file_params['repository'] = {'id' => repository_id}
|
262
|
+
end
|
263
|
+
if file_params['contentPath'].nil?
|
264
|
+
file_params['contentPath'] = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'path', 'fieldLabel' => 'File Path', 'type' => 'text', 'required' => true}], options[:options], @api_client,{})['path']
|
265
|
+
end
|
266
|
+
if file_params['contentRef'].nil?
|
267
|
+
file_params['contentRef'] = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'ref', 'fieldLabel' => 'Version Ref', 'type' => 'text'}], options[:options], @api_client,{})['ref']
|
268
|
+
end
|
269
|
+
end
|
270
|
+
if template_type == "cloudFormation" # this right code?
|
271
|
+
# JD: the field names the UI uses are strange, we should make these consistent...
|
272
|
+
cloud_formation_option_types = [
|
273
|
+
{'fieldContext' => 'config', 'fieldName' => 'cloudformation.IAM', 'fieldLabel' => 'CAPABILITY_IAM', 'type' => 'checkbox'},
|
274
|
+
{'fieldContext' => 'config', 'fieldName' => 'cloudformation.CAPABILITY_NAMED_IAM', 'fieldLabel' => 'CAPABILITY_NAMED_IAM', 'type' => 'checkbox'},
|
275
|
+
{'fieldContext' => 'config', 'fieldName' => 'cloudformation.CAPABILITY_AUTO_EXPAND', 'fieldLabel' => 'CAPABILITY_AUTO_EXPAND', 'type' => 'checkbox'}
|
276
|
+
]
|
277
|
+
v_prompt = Morpheus::Cli::OptionTypes.prompt(cloud_formation_option_types, options[:options], @api_client,{})
|
278
|
+
params.deep_merge!(v_prompt)
|
279
|
+
end
|
280
|
+
params['file'] = file_params
|
281
|
+
payload = {'specTemplate' => params}
|
282
|
+
end
|
283
|
+
@spec_templates_interface.setopts(options)
|
284
|
+
if options[:dry_run]
|
285
|
+
print_dry_run @spec_templates_interface.dry.create(payload)
|
286
|
+
return
|
287
|
+
end
|
288
|
+
json_response = @spec_templates_interface.create(payload)
|
289
|
+
if options[:json]
|
290
|
+
puts as_json(json_response, options)
|
291
|
+
elsif !options[:quiet]
|
292
|
+
resource_spec = json_response['specTemplate']
|
293
|
+
print_green_success "Added spec template #{resource_spec['name']}"
|
294
|
+
_get(resource_spec['id'], {})
|
295
|
+
end
|
296
|
+
return 0
|
297
|
+
rescue RestClient::Exception => e
|
298
|
+
print_rest_exception(e, options)
|
299
|
+
return 1
|
300
|
+
end
|
301
|
+
end
|
302
|
+
|
303
|
+
def update(args)
|
304
|
+
options = {}
|
305
|
+
params = {}
|
306
|
+
file_params = {}
|
307
|
+
template_type = nil
|
308
|
+
source_type = nil
|
309
|
+
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
310
|
+
opts.banner = subcommand_usage("[name]")
|
311
|
+
opts.on('--name VALUE', String, "Name") do |val|
|
312
|
+
params['name'] = val
|
313
|
+
end
|
314
|
+
opts.on('--type VALUE', String, "Spec Template Type. kubernetes, helm, terraform") do |val|
|
315
|
+
template_type = val.to_s
|
316
|
+
end
|
317
|
+
opts.on('--source VALUE', String, "Source Type. local, repository, url") do |val|
|
318
|
+
source_type = val.to_s
|
319
|
+
end
|
320
|
+
opts.on('--content TEXT', String, "Contents of the template. This implies source is local.") do |val|
|
321
|
+
source_type = 'local' if source_type.nil?
|
322
|
+
file_params['content'] = val
|
323
|
+
end
|
324
|
+
opts.on('--file FILE', "File containing the template. This can be used instead of --content" ) do |filename|
|
325
|
+
source_type = 'local' if source_type.nil?
|
326
|
+
full_filename = File.expand_path(filename)
|
327
|
+
if File.exists?(full_filename)
|
328
|
+
file_params['content'] = File.read(full_filename)
|
329
|
+
else
|
330
|
+
print_red_alert "File not found: #{full_filename}"
|
331
|
+
exit 1
|
332
|
+
end
|
333
|
+
end
|
334
|
+
opts.on('--url VALUE', String, "File URL, for use when source is url") do |val|
|
335
|
+
file_params['contentPath'] = val
|
336
|
+
end
|
337
|
+
opts.on('--content-path VALUE', String, "Content Path, for use when source is repository or url") do |val|
|
338
|
+
file_params['contentPath'] = val
|
339
|
+
end
|
340
|
+
opts.on('--content-ref VALUE', String, "Content Ref (Version Ref), for use when source is repository") do |val|
|
341
|
+
file_params['contentRef'] = val
|
342
|
+
end
|
343
|
+
build_common_options(opts, options, [:options, :payload, :json, :dry_run, :remote, :quiet])
|
344
|
+
opts.footer = "Update a spec template." + "\n" +
|
345
|
+
"[name] is required. This is the name or id of a spec template."
|
346
|
+
end
|
347
|
+
optparse.parse!(args)
|
348
|
+
if args.count != 1
|
349
|
+
print_error Morpheus::Terminal.angry_prompt
|
350
|
+
puts_error "wrong number of arguments, expected 1 and got (#{args.count}) #{args.inspect}\n#{optparse}"
|
351
|
+
return 1
|
352
|
+
end
|
353
|
+
connect(options)
|
354
|
+
begin
|
355
|
+
resource_spec = find_resource_spec_by_name_or_id(args[0])
|
356
|
+
if resource_spec.nil?
|
357
|
+
return 1
|
358
|
+
end
|
359
|
+
# construct payload
|
360
|
+
payload = nil
|
361
|
+
if options[:payload]
|
362
|
+
payload = options[:payload]
|
363
|
+
else
|
364
|
+
# merge -O options into normally parsed options
|
365
|
+
params.deep_merge!(options[:options].reject {|k,v| k.is_a?(Symbol) }) if options[:options]
|
366
|
+
if params.empty? && file_params.empty?
|
367
|
+
print_red_alert "Specify at least one option to update"
|
368
|
+
puts optparse
|
369
|
+
return 1
|
370
|
+
end
|
371
|
+
# massage special params
|
372
|
+
if !template_type.nil?
|
373
|
+
# gotta look up id
|
374
|
+
template_type_obj = find_spec_template_type_by_name_or_code_id(template_type)
|
375
|
+
return 1 if template_type_obj.nil?
|
376
|
+
template_type = template_type_obj['code']
|
377
|
+
params['type'] = {'code' => template_type}
|
378
|
+
end
|
379
|
+
if !source_type.nil?
|
380
|
+
file_params['sourceType'] = source_type
|
381
|
+
end
|
382
|
+
# if source_type == "local"
|
383
|
+
# # prompt for content
|
384
|
+
# if file_params['content'].nil?
|
385
|
+
# file_params['content'] = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'content', 'type' => 'code-editor', 'fieldLabel' => 'Content', 'required' => true, 'description' => 'The file content'}], options[:options])['content']
|
386
|
+
# end
|
387
|
+
# elsif source_type == "url"
|
388
|
+
# if file_params['contentPath'].nil?
|
389
|
+
# file_params['contentPath'] = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'url', 'fieldLabel' => 'URL', 'type' => 'text', 'required' => true}], options[:options], @api_client,{})['url']
|
390
|
+
# end
|
391
|
+
# elsif source_type == "repository"
|
392
|
+
# if file_params['repository'].nil?
|
393
|
+
# repository_id = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'repositoryId', 'fieldLabel' => 'Repository', 'type' => 'select', 'optionSource' => 'codeRepositories', 'required' => true, 'defaultValue' => 'local'}], options[:options], @api_client,{})['repositoryId']
|
394
|
+
# file_params['repository'] = {'id' => repository_id}
|
395
|
+
# end
|
396
|
+
# end
|
397
|
+
# if template_type == "cloudFormation" # this right code?
|
398
|
+
# # JD: the field names the UI uses are strange, we should make these consistent...
|
399
|
+
# cloud_formation_option_types = [
|
400
|
+
# {'fieldContext' => 'config', 'fieldName' => 'cloudformation.IAM', 'fieldLabel' => 'CAPABILITY_IAM', 'type' => 'checkbox'},
|
401
|
+
# {'fieldContext' => 'config', 'fieldName' => 'cloudformation.CAPABILITY_NAMED_IAM', 'fieldLabel' => 'CAPABILITY_NAMED_IAM', 'type' => 'checkbox'},
|
402
|
+
# {'fieldContext' => 'config', 'fieldName' => 'cloudformation.CAPABILITY_AUTO_EXPAND', 'fieldLabel' => 'CAPABILITY_AUTO_EXPAND', 'type' => 'checkbox'}
|
403
|
+
# ]
|
404
|
+
# v_prompt = Morpheus::Cli::OptionTypes.prompt(cloud_formation_option_types, options[:options], @api_client,{})
|
405
|
+
# params.deep_merge!(v_prompt)
|
406
|
+
# end
|
407
|
+
if !file_params.empty?
|
408
|
+
params['file'] = file_params
|
409
|
+
end
|
410
|
+
payload = {'specTemplate' => params}
|
411
|
+
end
|
412
|
+
@spec_templates_interface.setopts(options)
|
413
|
+
if options[:dry_run]
|
414
|
+
print_dry_run @spec_templates_interface.dry.update(resource_spec["id"], payload)
|
415
|
+
return
|
416
|
+
end
|
417
|
+
json_response = @spec_templates_interface.update(resource_spec["id"], payload)
|
418
|
+
if options[:json]
|
419
|
+
puts as_json(json_response, options)
|
420
|
+
elsif !options[:quiet]
|
421
|
+
print_green_success "Updated spec template #{resource_spec['name']}"
|
422
|
+
_get(resource_spec['id'], {})
|
423
|
+
end
|
424
|
+
return 0
|
425
|
+
rescue RestClient::Exception => e
|
426
|
+
print_rest_exception(e, options)
|
427
|
+
return 1
|
428
|
+
end
|
429
|
+
end
|
430
|
+
|
431
|
+
def remove(args)
|
432
|
+
options = {}
|
433
|
+
params = {}
|
434
|
+
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
435
|
+
opts.banner = subcommand_usage("[name]")
|
436
|
+
build_common_options(opts, options, [:json, :dry_run, :quiet, :auto_confirm])
|
437
|
+
end
|
438
|
+
optparse.parse!(args)
|
439
|
+
if args.count < 1
|
440
|
+
puts optparse
|
441
|
+
return 127
|
442
|
+
end
|
443
|
+
connect(options)
|
444
|
+
|
445
|
+
begin
|
446
|
+
resource_spec = find_resource_spec_by_name_or_id(args[0])
|
447
|
+
if resource_spec.nil?
|
448
|
+
return 1
|
449
|
+
end
|
450
|
+
|
451
|
+
unless options[:yes] || ::Morpheus::Cli::OptionTypes::confirm("Are you sure you would like to delete spec template '#{resource_spec['name']}'?", options)
|
452
|
+
return false
|
453
|
+
end
|
454
|
+
|
455
|
+
# payload = {
|
456
|
+
# 'specTemplate' => {id: resource_spec["id"]}
|
457
|
+
# }
|
458
|
+
# payload['specTemplate'].merge!(resource_spec)
|
459
|
+
payload = params
|
460
|
+
@spec_templates_interface.setopts(options)
|
461
|
+
if options[:dry_run]
|
462
|
+
print_dry_run @spec_templates_interface.dry.destroy(resource_spec["id"])
|
463
|
+
return
|
464
|
+
end
|
465
|
+
|
466
|
+
json_response = @spec_templates_interface.destroy(resource_spec["id"])
|
467
|
+
if options[:json]
|
468
|
+
puts as_json(json_response, options)
|
469
|
+
elsif !options[:quiet]
|
470
|
+
print_green_success "Deleted spec template #{resource_spec['name']}"
|
471
|
+
end
|
472
|
+
return 0, nil
|
473
|
+
rescue RestClient::Exception => e
|
474
|
+
print_rest_exception(e, options)
|
475
|
+
return 1
|
476
|
+
end
|
477
|
+
end
|
478
|
+
|
479
|
+
def list_types(args)
|
480
|
+
options = {}
|
481
|
+
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
482
|
+
opts.banner = subcommand_usage()
|
483
|
+
build_common_options(opts, options, [:list, :query, :json, :yaml, :csv, :fields, :dry_run, :remote])
|
484
|
+
opts.footer = "List spec template types."
|
485
|
+
end
|
486
|
+
optparse.parse!(args)
|
487
|
+
connect(options)
|
488
|
+
begin
|
489
|
+
params = {}
|
490
|
+
params.merge!(parse_list_options(options))
|
491
|
+
@spec_template_types_interface.setopts(options)
|
492
|
+
if options[:dry_run]
|
493
|
+
print_dry_run @spec_template_types_interface.dry.list(params)
|
494
|
+
return
|
495
|
+
end
|
496
|
+
json_response = @spec_template_types_interface.list(params)
|
497
|
+
|
498
|
+
render_result = render_with_format(json_response, options, 'specTemplateTypes')
|
499
|
+
return 0 if render_result
|
500
|
+
|
501
|
+
spec_template_types = json_response['specTemplateTypes']
|
502
|
+
|
503
|
+
title = "Morpheus Spec Template Types"
|
504
|
+
subtitles = []
|
505
|
+
subtitles += parse_list_subtitles(options)
|
506
|
+
print_h1 title, subtitles
|
507
|
+
if spec_template_types.empty?
|
508
|
+
print cyan,"No spec template types found.",reset,"\n"
|
509
|
+
else
|
510
|
+
rows = spec_template_types.collect do |spec_template_type|
|
511
|
+
{
|
512
|
+
id: spec_template_type['id'],
|
513
|
+
code: spec_template_type['code'],
|
514
|
+
name: spec_template_type['name']
|
515
|
+
}
|
516
|
+
end
|
517
|
+
columns = [:id, :name, :code]
|
518
|
+
print cyan
|
519
|
+
print as_pretty_table(rows, columns, options)
|
520
|
+
print reset
|
521
|
+
print_results_pagination(json_response)
|
522
|
+
end
|
523
|
+
print reset,"\n"
|
524
|
+
return 0
|
525
|
+
|
526
|
+
rescue RestClient::Exception => e
|
527
|
+
print_rest_exception(e, options)
|
528
|
+
return 1
|
529
|
+
end
|
530
|
+
end
|
531
|
+
|
532
|
+
private
|
533
|
+
|
534
|
+
def find_resource_spec_by_name_or_id(val)
|
535
|
+
if val.to_s =~ /\A\d{1,}\Z/
|
536
|
+
return find_resource_spec_by_id(val)
|
537
|
+
else
|
538
|
+
return find_resource_spec_by_name(val)
|
539
|
+
end
|
540
|
+
end
|
541
|
+
|
542
|
+
def find_resource_spec_by_id(id)
|
543
|
+
begin
|
544
|
+
json_response = @spec_templates_interface.get(id.to_i)
|
545
|
+
return json_response['specTemplate']
|
546
|
+
rescue RestClient::Exception => e
|
547
|
+
if e.response && e.response.code == 404
|
548
|
+
print_red_alert "Spec Template not found by id #{id}"
|
549
|
+
else
|
550
|
+
raise e
|
551
|
+
end
|
552
|
+
end
|
553
|
+
end
|
554
|
+
|
555
|
+
def find_resource_spec_by_name(name)
|
556
|
+
resource_specs = @spec_templates_interface.list({name: name.to_s})['specTemplates']
|
557
|
+
if resource_specs.empty?
|
558
|
+
print_red_alert "Spec Template not found by name #{name}"
|
559
|
+
return nil
|
560
|
+
elsif resource_specs.size > 1
|
561
|
+
print_red_alert "#{resource_specs.size} spec templates found by name #{name}"
|
562
|
+
print_resource_specs_table(resource_specs, {color: red})
|
563
|
+
print_red_alert "Try using ID instead"
|
564
|
+
print reset,"\n"
|
565
|
+
return nil
|
566
|
+
else
|
567
|
+
return resource_specs[0]
|
568
|
+
end
|
569
|
+
end
|
570
|
+
|
571
|
+
def print_resource_specs_table(resource_specs, opts={})
|
572
|
+
columns = [
|
573
|
+
{"ID" => lambda {|resource_spec| resource_spec['id'] } },
|
574
|
+
{"NAME" => lambda {|resource_spec| resource_spec['name'] } },
|
575
|
+
#{"OWNER" => lambda {|resource_spec| resource_spec['account'] ? resource_spec['account']['name'] : '' } },
|
576
|
+
]
|
577
|
+
if opts[:include_fields]
|
578
|
+
columns = opts[:include_fields]
|
579
|
+
end
|
580
|
+
print as_pretty_table(resource_specs, columns, opts)
|
581
|
+
end
|
582
|
+
|
583
|
+
def find_spec_template_type_by_id(id)
|
584
|
+
begin
|
585
|
+
json_response = @spec_template_types_interface.get(id.to_i)
|
586
|
+
return json_response['networkType']
|
587
|
+
rescue RestClient::Exception => e
|
588
|
+
if e.response && e.response.code == 404
|
589
|
+
print_red_alert "Network Type not found by id #{id}"
|
590
|
+
return nil
|
591
|
+
else
|
592
|
+
raise e
|
593
|
+
end
|
594
|
+
end
|
595
|
+
end
|
596
|
+
|
597
|
+
# def find_spec_template_type_by_name(name)
|
598
|
+
# json_response = @spec_template_types_interface.list({name: name.to_s})
|
599
|
+
# spec_template_types = json_response['networkTypes']
|
600
|
+
# if spec_template_types.empty?
|
601
|
+
# print_red_alert "Network Type not found by name #{name}"
|
602
|
+
# return spec_template_types
|
603
|
+
# elsif spec_template_types.size > 1
|
604
|
+
# print_red_alert "#{spec_template_types.size} network types found by name #{name}"
|
605
|
+
# rows = spec_template_types.collect do |it|
|
606
|
+
# {id: it['id'], name: it['name']}
|
607
|
+
# end
|
608
|
+
# puts as_pretty_table(rows, [:id, :name], {color:red})
|
609
|
+
# return nil
|
610
|
+
# else
|
611
|
+
# return spec_template_types[0]
|
612
|
+
# end
|
613
|
+
# end
|
614
|
+
|
615
|
+
def find_spec_template_type_by_name_or_code(name)
|
616
|
+
spec_template_types = get_all_spec_template_types().select { |it| name && it['code'] == name || it['name'] == name }
|
617
|
+
if spec_template_types.empty?
|
618
|
+
print_red_alert "Spec Template Type not found by code #{name}"
|
619
|
+
return nil
|
620
|
+
elsif spec_template_types.size > 1
|
621
|
+
print_red_alert "#{spec_template_types.size} spec template types found by code #{name}"
|
622
|
+
rows = spec_template_types.collect do |it|
|
623
|
+
{id: it['id'], code: it['code'], name: it['name']}
|
624
|
+
end
|
625
|
+
print "\n"
|
626
|
+
puts as_pretty_table(rows, [:id, :code, :name], {color:red})
|
627
|
+
return nil
|
628
|
+
else
|
629
|
+
return spec_template_types[0]
|
630
|
+
end
|
631
|
+
end
|
632
|
+
|
633
|
+
def find_spec_template_type_by_name_or_code_id(val)
|
634
|
+
if val.to_s =~ /\A\d{1,}\Z/
|
635
|
+
return find_subnet_by_id(val)
|
636
|
+
else
|
637
|
+
return find_spec_template_type_by_name_or_code(val)
|
638
|
+
end
|
639
|
+
end
|
640
|
+
|
641
|
+
def get_all_spec_template_types
|
642
|
+
@all_spec_template_types ||= @spec_template_types_interface.list({max: 1000})['specTemplateTypes'] || []
|
643
|
+
end
|
644
|
+
end
|