morpheus-cli 4.2.16 → 4.2.17
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Dockerfile +1 -1
- data/README.md +8 -6
- data/lib/morpheus/api/api_client.rb +32 -14
- data/lib/morpheus/api/auth_interface.rb +4 -2
- data/lib/morpheus/api/backup_jobs_interface.rb +9 -0
- data/lib/morpheus/api/backups_interface.rb +16 -0
- data/lib/morpheus/api/deploy_interface.rb +25 -56
- data/lib/morpheus/api/deployments_interface.rb +43 -54
- data/lib/morpheus/api/doc_interface.rb +57 -0
- data/lib/morpheus/api/instances_interface.rb +5 -0
- data/lib/morpheus/api/rest_interface.rb +40 -0
- data/lib/morpheus/api/user_sources_interface.rb +0 -15
- data/lib/morpheus/api/users_interface.rb +2 -3
- data/lib/morpheus/benchmarking.rb +2 -2
- data/lib/morpheus/cli.rb +3 -1
- data/lib/morpheus/cli/access_token_command.rb +27 -10
- data/lib/morpheus/cli/apps.rb +21 -15
- data/lib/morpheus/cli/backup_jobs_command.rb +276 -0
- data/lib/morpheus/cli/backups_command.rb +271 -0
- data/lib/morpheus/cli/boot_scripts_command.rb +1 -1
- data/lib/morpheus/cli/cli_command.rb +92 -41
- data/lib/morpheus/cli/clusters.rb +0 -18
- data/lib/morpheus/cli/commands/standard/benchmark_command.rb +7 -7
- data/lib/morpheus/cli/commands/standard/man_command.rb +1 -1
- data/lib/morpheus/cli/credentials.rb +13 -9
- data/lib/morpheus/cli/deploy.rb +374 -0
- data/lib/morpheus/cli/deployments.rb +521 -197
- data/lib/morpheus/cli/deploys.rb +271 -126
- data/lib/morpheus/cli/doc.rb +182 -0
- data/lib/morpheus/cli/error_handler.rb +23 -8
- data/lib/morpheus/cli/errors.rb +3 -2
- data/lib/morpheus/cli/image_builder_command.rb +2 -2
- data/lib/morpheus/cli/instances.rb +136 -17
- data/lib/morpheus/cli/invoices_command.rb +51 -38
- data/lib/morpheus/cli/library_layouts_command.rb +1 -1
- data/lib/morpheus/cli/login.rb +9 -3
- data/lib/morpheus/cli/mixins/accounts_helper.rb +158 -100
- data/lib/morpheus/cli/mixins/backups_helper.rb +115 -0
- data/lib/morpheus/cli/mixins/deployments_helper.rb +135 -0
- data/lib/morpheus/cli/mixins/option_source_helper.rb +1 -1
- data/lib/morpheus/cli/mixins/print_helper.rb +110 -74
- data/lib/morpheus/cli/mixins/provisioning_helper.rb +2 -2
- data/lib/morpheus/cli/mixins/whoami_helper.rb +19 -6
- data/lib/morpheus/cli/network_routers_command.rb +1 -1
- data/lib/morpheus/cli/option_parser.rb +48 -5
- data/lib/morpheus/cli/option_types.rb +1 -1
- data/lib/morpheus/cli/remote.rb +3 -2
- data/lib/morpheus/cli/roles.rb +49 -92
- data/lib/morpheus/cli/security_groups.rb +7 -1
- data/lib/morpheus/cli/service_plans_command.rb +10 -10
- data/lib/morpheus/cli/setup.rb +1 -1
- data/lib/morpheus/cli/shell.rb +7 -6
- data/lib/morpheus/cli/subnets_command.rb +1 -1
- data/lib/morpheus/cli/tenants_command.rb +133 -163
- data/lib/morpheus/cli/user_groups_command.rb +20 -65
- data/lib/morpheus/cli/user_settings_command.rb +115 -13
- data/lib/morpheus/cli/user_sources_command.rb +57 -24
- data/lib/morpheus/cli/users.rb +210 -186
- data/lib/morpheus/cli/version.rb +1 -1
- data/lib/morpheus/cli/whitelabel_settings_command.rb +29 -5
- data/lib/morpheus/cli/whoami.rb +113 -6
- data/lib/morpheus/cli/workflows.rb +1 -1
- data/lib/morpheus/ext/hash.rb +21 -0
- data/lib/morpheus/terminal.rb +1 -0
- metadata +12 -3
- data/lib/morpheus/cli/auth_command.rb +0 -105
data/lib/morpheus/cli/deploys.rb
CHANGED
@@ -1,176 +1,321 @@
|
|
1
|
-
# require 'yaml'
|
2
|
-
require 'io/console'
|
3
|
-
require 'rest_client'
|
4
|
-
require 'filesize'
|
5
1
|
require 'morpheus/cli/cli_command'
|
2
|
+
require 'yaml'
|
6
3
|
|
7
4
|
class Morpheus::Cli::Deploys
|
8
5
|
include Morpheus::Cli::CliCommand
|
6
|
+
include Morpheus::Cli::DeploymentsHelper
|
9
7
|
|
10
|
-
|
8
|
+
# hidden until api support is added
|
9
|
+
set_command_hidden
|
10
|
+
|
11
|
+
set_command_name :deploys
|
11
12
|
|
12
|
-
|
13
|
-
# @appliance_name, @appliance_url = Morpheus::Cli::Remote.active_appliance
|
14
|
-
end
|
13
|
+
register_subcommands :list, :get, :add, :remove, :deploy
|
15
14
|
|
16
15
|
def connect(opts)
|
17
16
|
@api_client = establish_remote_appliance_connection(opts)
|
18
|
-
@instances_interface =
|
19
|
-
@deploy_interface =
|
17
|
+
@instances_interface = @api_client.instances
|
18
|
+
@deploy_interface = @api_client.deploy
|
19
|
+
@deployments_interface = @api_client.deployments
|
20
20
|
end
|
21
21
|
|
22
22
|
def handle(args)
|
23
|
-
|
23
|
+
handle_subcommand(args)
|
24
24
|
end
|
25
25
|
|
26
|
-
def
|
27
|
-
options={}
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
opts.
|
32
|
-
|
26
|
+
def list(args)
|
27
|
+
options = {}
|
28
|
+
params = {}
|
29
|
+
ref_ids = []
|
30
|
+
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
31
|
+
opts.banner = subcommand_usage("[search]")
|
32
|
+
build_standard_list_options(opts, options)
|
33
|
+
opts.footer = <<-EOT
|
34
|
+
List deploys.
|
35
|
+
EOT
|
33
36
|
end
|
34
37
|
optparse.parse!(args)
|
35
38
|
connect(options)
|
36
|
-
|
39
|
+
# verify_args!(args:args, optparse:optparse, count:0)
|
37
40
|
if args.count > 0
|
38
|
-
|
41
|
+
options[:phrase] = args.join(" ")
|
39
42
|
end
|
40
|
-
|
41
|
-
|
43
|
+
params.merge!(parse_list_options(options))
|
44
|
+
@deploy_interface.setopts(options)
|
45
|
+
if options[:dry_run]
|
46
|
+
print_dry_run @deploy_interface.dry.list(params)
|
42
47
|
return
|
43
48
|
end
|
49
|
+
json_response = @deploy_interface.list(params)
|
50
|
+
app_deploys = json_response[app_deploy_list_key]
|
51
|
+
render_response(json_response, options, app_deploy_list_key) do
|
52
|
+
print_h1 "Morpheus Deploys", parse_list_subtitles(options), options
|
53
|
+
if app_deploys.empty?
|
54
|
+
print cyan,"No deploys found.",reset,"\n"
|
55
|
+
else
|
56
|
+
print as_pretty_table(app_deploys, app_deploy_column_definitions.upcase_keys!, options)
|
57
|
+
print_results_pagination(json_response)
|
58
|
+
end
|
59
|
+
print reset,"\n"
|
60
|
+
end
|
61
|
+
if app_deploys.empty?
|
62
|
+
return 1, "no deploys found"
|
63
|
+
else
|
64
|
+
return 0, nil
|
65
|
+
end
|
66
|
+
end
|
44
67
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
68
|
+
def get(args)
|
69
|
+
params = {}
|
70
|
+
options = {}
|
71
|
+
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
72
|
+
opts.banner = subcommand_usage("[id]")
|
73
|
+
build_standard_get_options(opts, options)
|
74
|
+
opts.footer = <<-EOT
|
75
|
+
Get details about a specific instance deploy.
|
76
|
+
[id] is required. This is the name or id of a deployment.
|
77
|
+
EOT
|
49
78
|
end
|
79
|
+
optparse.parse!(args)
|
80
|
+
verify_args!(args:args, optparse:optparse, min:1)
|
81
|
+
connect(options)
|
82
|
+
id_list = parse_id_list(args)
|
83
|
+
return run_command_for_each_arg(id_list) do |arg|
|
84
|
+
_get(arg, params, options)
|
85
|
+
end
|
86
|
+
end
|
50
87
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
88
|
+
def _get(id, params, options)
|
89
|
+
@deploy_interface.setopts(options)
|
90
|
+
if options[:dry_run]
|
91
|
+
print_dry_run @deploy_interface.dry.get(id, params)
|
92
|
+
return 0
|
93
|
+
end
|
94
|
+
json_response = @deploy_interface.get(id, params)
|
95
|
+
app_deploy = json_response[app_deploy_object_key]
|
96
|
+
render_response(json_response, options, app_deploy_object_key) do
|
97
|
+
print_h1 "Deploy Details", [], options
|
98
|
+
print cyan
|
99
|
+
print_description_list(app_deploy_column_definitions, app_deploy)
|
100
|
+
print reset,"\n"
|
55
101
|
end
|
56
|
-
|
57
|
-
|
58
|
-
print_h1 "Morpheus Deployment"
|
59
|
-
if !deploy_args['script'].nil?
|
60
|
-
print cyan, bold, " - Executing Pre Deploy Script...", reset, "\n"
|
102
|
+
return 0, nil
|
103
|
+
end
|
61
104
|
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
105
|
+
def add(args)
|
106
|
+
options = {}
|
107
|
+
params = {}
|
108
|
+
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
109
|
+
opts.banner = subcommand_usage("[instance] [deployment] [version] [options]")
|
110
|
+
build_option_type_options(opts, options, add_app_deploy_option_types)
|
111
|
+
build_option_type_options(opts, options, add_app_deploy_advanced_option_types)
|
112
|
+
build_standard_add_options(opts, options)
|
113
|
+
opts.footer = <<-EOT
|
114
|
+
Create a new instance deploy.
|
115
|
+
EOT
|
116
|
+
end
|
117
|
+
optparse.parse!(args)
|
118
|
+
verify_args!(args:args, optparse:optparse, min:0, max:3)
|
119
|
+
options[:options]['instance'] = args[0] if args[0]
|
120
|
+
options[:options]['deployment'] = args[1] if args[1]
|
121
|
+
options[:options]['version'] = args[2] if args[2]
|
122
|
+
connect(options)
|
123
|
+
payload = {}
|
124
|
+
if options[:payload]
|
125
|
+
payload = options[:payload]
|
126
|
+
payload.deep_merge!({app_deploy_object_key => parse_passed_options(options)})
|
127
|
+
else
|
128
|
+
payload.deep_merge!({app_deploy_object_key => parse_passed_options(options)})
|
129
|
+
v_prompt = Morpheus::Cli::OptionTypes.prompt(add_app_deploy_option_types, options[:options], @api_client, options[:params])
|
130
|
+
params.deep_merge!(v_prompt)
|
131
|
+
advanced_config = Morpheus::Cli::OptionTypes.no_prompt(add_app_deploy_advanced_option_types, options[:options], @api_client, options[:params])
|
132
|
+
advanced_config.deep_compact!
|
133
|
+
params.deep_merge!(advanced_config)
|
134
|
+
payload[app_deploy_object_key].deep_merge!(params)
|
66
135
|
end
|
67
136
|
@deploy_interface.setopts(options)
|
68
|
-
@instances_interface.setopts(options)
|
69
137
|
if options[:dry_run]
|
70
|
-
print_dry_run @deploy_interface.create(
|
71
|
-
|
72
|
-
# Create a new deployment record
|
73
|
-
deploy_result = @deploy_interface.create(instance_id)
|
74
|
-
app_deploy = deploy_result['appDeploy']
|
75
|
-
deployment_id = app_deploy['id']
|
76
|
-
|
77
|
-
# Upload Files
|
78
|
-
print "\n",cyan, bold, "Uploading Files...", reset, "\n"
|
79
|
-
current_working_dir = Dir.pwd
|
80
|
-
deploy_args['files'].each do |fmap|
|
81
|
-
Dir.chdir(fmap['path'] || current_working_dir)
|
82
|
-
files = Dir.glob(fmap['pattern'] || '**/*')
|
83
|
-
files.each do |file|
|
84
|
-
if File.file?(file)
|
85
|
-
print cyan,bold, " - Uploading #{file} ...", reset, "\n"
|
86
|
-
destination = file.split("/")[0..-2].join("/")
|
87
|
-
if options[:dry_run]
|
88
|
-
print_dry_run @deploy_interface.upload_file(deployment_id,file,destination)
|
89
|
-
else
|
90
|
-
upload_result = @deploy_interface.upload_file(deployment_id,file,destination)
|
91
|
-
end
|
92
|
-
end
|
93
|
-
end
|
138
|
+
print_dry_run @deploy_interface.dry.create(payload)
|
139
|
+
return 0, nil
|
94
140
|
end
|
95
|
-
|
96
|
-
|
141
|
+
json_response = @deploy_interface.create(payload)
|
142
|
+
app_deploy = json_response[app_deploy_object_key]
|
143
|
+
render_response(json_response, options, app_deploy_object_key) do
|
144
|
+
print_green_success "Deploying..."
|
145
|
+
return _get(app_deploy["id"], {}, options)
|
146
|
+
end
|
147
|
+
return 0, nil
|
148
|
+
end
|
97
149
|
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
150
|
+
def remove(args)
|
151
|
+
options = {}
|
152
|
+
params = {}
|
153
|
+
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
154
|
+
opts.banner = subcommand_usage("[id] [options]")
|
155
|
+
build_standard_remove_options(opts, options)
|
156
|
+
opts.footer = <<-EOT
|
157
|
+
Delete an instance deploy.
|
158
|
+
[id] is required. This is the name or id of a deploy.
|
159
|
+
EOT
|
160
|
+
end
|
161
|
+
optparse.parse!(args)
|
162
|
+
verify_args!(args:args, optparse:optparse, count:1)
|
163
|
+
connect(options)
|
164
|
+
app_deploy = find_app_deploy_by_id(args[0])
|
165
|
+
return 1 if app_deploy.nil?
|
166
|
+
@deploy_interface.setopts(options)
|
167
|
+
if options[:dry_run]
|
168
|
+
print_dry_run @deploy_interface.dry.destroy(app_deploy['id'], params)
|
169
|
+
return
|
170
|
+
end
|
171
|
+
json_response = @deploy_interface.destroy(app_deploy['id'], params)
|
172
|
+
render_response(json_response, options) do
|
173
|
+
print_green_success "Removed deploy #{app_deploy['name']}"
|
104
174
|
end
|
175
|
+
return 0, nil
|
176
|
+
end
|
105
177
|
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
end
|
178
|
+
def deploy(args)
|
179
|
+
options = {}
|
180
|
+
params = {}
|
181
|
+
payload = {}
|
182
|
+
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
183
|
+
opts.banner = subcommand_usage("[id] [options]")
|
184
|
+
build_option_type_options(opts, options, update_app_deploy_option_types)
|
185
|
+
build_option_type_options(opts, options, update_app_deploy_advanced_option_types)
|
186
|
+
build_standard_update_options(opts, options)
|
187
|
+
opts.footer = <<-EOT
|
188
|
+
Update an instance deploy.
|
189
|
+
[id] is required. This is the name or id of an instance deploy.
|
190
|
+
EOT
|
120
191
|
end
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
192
|
+
optparse.parse!(args)
|
193
|
+
verify_args!(args:args, optparse:optparse, count:1)
|
194
|
+
connect(options)
|
195
|
+
app_deploy = find_app_deploy_by_id(args[0])
|
196
|
+
return 1 if app_deploy.nil?
|
197
|
+
payload = {}
|
198
|
+
if options[:payload]
|
199
|
+
payload = options[:payload]
|
200
|
+
payload.deep_merge!({app_deploy_object_key => parse_passed_options(options)})
|
201
|
+
else
|
202
|
+
payload.deep_merge!({app_deploy_object_key => parse_passed_options(options)})
|
203
|
+
# do not prompt on update
|
204
|
+
v_prompt = Morpheus::Cli::OptionTypes.no_prompt(update_app_deploy_option_types, options[:options], @api_client, options[:params])
|
205
|
+
v_prompt.deep_compact!
|
206
|
+
params.deep_merge!(v_prompt)
|
207
|
+
advanced_config = Morpheus::Cli::OptionTypes.no_prompt(update_app_deploy_advanced_option_types, options[:options], @api_client, options[:params])
|
208
|
+
advanced_config.deep_compact!
|
209
|
+
params.deep_merge!(advanced_config)
|
210
|
+
payload.deep_merge!({app_deploy_object_key => params})
|
211
|
+
if payload[app_deploy_object_key].empty? # || options[:no_prompt]
|
212
|
+
raise_command_error "Specify at least one option to update.\n#{optparse}"
|
213
|
+
end
|
127
214
|
end
|
215
|
+
@deploy_interface.setopts(options)
|
128
216
|
if options[:dry_run]
|
129
|
-
print_dry_run @deploy_interface.
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
217
|
+
print_dry_run @deploy_interface.dry.update(app_deploy['id'], payload)
|
218
|
+
return
|
219
|
+
end
|
220
|
+
json_response = @deploy_interface.update(app_deploy['id'], payload)
|
221
|
+
app_deploy = json_response[app_deploy_object_key]
|
222
|
+
render_response(json_response, options, app_deploy_object_key) do
|
223
|
+
print_green_success "Deploying..."
|
224
|
+
return _get(app_deploy["id"], {}, options)
|
134
225
|
end
|
135
|
-
|
226
|
+
return 0, nil
|
136
227
|
end
|
137
|
-
|
228
|
+
private
|
229
|
+
|
230
|
+
## Deploys (AppDeploy)
|
231
|
+
|
232
|
+
def app_deploy_object_key
|
233
|
+
'appDeploy'
|
138
234
|
end
|
139
235
|
|
140
|
-
def
|
236
|
+
def app_deploy_list_key
|
237
|
+
'appDeploys'
|
141
238
|
end
|
142
239
|
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
# * +stage_deploy+ - If set to true the deploy will only be staged and not actually run
|
154
|
-
#
|
155
|
-
# +NOTE: + It is also possible to nest these properties in an "environments" map to override based on a passed environment deploy name
|
156
|
-
#
|
157
|
-
def load_deploy_file
|
158
|
-
if !File.exist? "morpheus.yml"
|
159
|
-
puts "No morpheus.yml file detected in the current directory. Nothing to do."
|
160
|
-
return nil
|
240
|
+
def find_app_deploy_by_id(id)
|
241
|
+
begin
|
242
|
+
json_response = @deploy_interface.get(id.to_i)
|
243
|
+
return json_response[app_deploy_object_key]
|
244
|
+
rescue RestClient::Exception => e
|
245
|
+
if e.response && e.response.code == 404
|
246
|
+
print_red_alert "Deploy not found by id '#{id}'"
|
247
|
+
else
|
248
|
+
raise e
|
249
|
+
end
|
161
250
|
end
|
251
|
+
end
|
162
252
|
|
163
|
-
|
164
|
-
|
253
|
+
def app_deploy_column_definitions
|
254
|
+
{
|
255
|
+
"ID" => 'id',
|
256
|
+
"Instance" => lambda {|it| it['instance'] ? it['instance']['name'] : it['instanceId'] },
|
257
|
+
"Deployment" => lambda {|it| it['deployment']['name'] rescue '' },
|
258
|
+
"Version" => lambda {|it| (it['deploymentVersion']['userVersion'] || it['deploymentVersion']['version']) rescue '' },
|
259
|
+
# "Version ID" => lambda {|it| (it['deploymentVersion']['id']) rescue '' },
|
260
|
+
"Deploy Date" => lambda {|it| format_local_dt(it['deployDate']) },
|
261
|
+
"Status" => lambda {|it| format_app_deploy_status(it['status']) },
|
262
|
+
}
|
165
263
|
end
|
166
264
|
|
167
|
-
def
|
168
|
-
|
265
|
+
def add_app_deploy_option_types
|
266
|
+
[
|
267
|
+
{'fieldName' => 'instance', 'fieldLabel' => 'Instance', 'type' => 'select', 'optionSource' => lambda { |api_client, api_params|
|
268
|
+
@instances_interface.list({max:10000}.merge(api_params))['instances'].collect {|it|
|
269
|
+
{'name' => it['name'], 'value' => it['id'], 'id' => it['id']}
|
270
|
+
}
|
271
|
+
}, 'required' => true, 'displayOrder' => 1},
|
272
|
+
{'fieldName' => 'deployment', 'fieldLabel' => 'Deployment', 'type' => 'select', 'optionSource' => lambda { |api_client, api_params|
|
273
|
+
@deployments_interface.list({max:10000})['deployments'].collect {|it|
|
274
|
+
{'name' => it['name'], 'value' => it['id'], 'id' => it['id']}
|
275
|
+
}
|
276
|
+
}, 'required' => true, 'displayOrder' => 2},
|
277
|
+
{'fieldName' => 'version', 'fieldLabel' => 'Version', 'type' => 'select', 'optionSource' => lambda { |api_client, api_params|
|
278
|
+
@deployments_interface.list_versions(api_params['deployment'], {max:10000})['versions'].collect {|it|
|
279
|
+
{'name' => (it['userVersion'] || it['version']), 'value' => it['id'], 'id' => it['id']}
|
280
|
+
}
|
281
|
+
}, 'required' => true, 'displayOrder' => 3}
|
282
|
+
]
|
283
|
+
end
|
169
284
|
|
170
|
-
|
171
|
-
|
172
|
-
|
285
|
+
def add_app_deploy_advanced_option_types
|
286
|
+
[{'fieldName' => 'stageOnly', 'fieldLabel' => 'Stage Only', 'type' => 'checkbox', 'description' => 'If set to true the deploy will only be staged and not actually run', 'displayOrder' => 10}]
|
287
|
+
end
|
288
|
+
|
289
|
+
def update_app_deploy_option_types
|
290
|
+
add_app_deploy_option_types.collect {|it|
|
291
|
+
it.delete('required')
|
292
|
+
it.delete('defaultValue')
|
293
|
+
it
|
294
|
+
}
|
295
|
+
end
|
296
|
+
|
297
|
+
def update_app_deploy_advanced_option_types
|
298
|
+
add_app_deploy_advanced_option_types.collect {|it|
|
299
|
+
it.delete('required')
|
300
|
+
it.delete('defaultValue')
|
301
|
+
it
|
302
|
+
}
|
303
|
+
end
|
304
|
+
|
305
|
+
def format_app_deploy_status(status, return_color=cyan)
|
306
|
+
out = ""
|
307
|
+
s = status.to_s.downcase
|
308
|
+
if s == 'deployed'
|
309
|
+
out << "#{green}#{s.upcase}#{return_color}"
|
310
|
+
elsif s == 'open' || s == 'archived' || s == 'committed'
|
311
|
+
out << "#{cyan}#{s.upcase}#{return_color}"
|
312
|
+
elsif s == 'failed'
|
313
|
+
out << "#{red}#{s.upcase}#{return_color}"
|
314
|
+
else
|
315
|
+
out << "#{yellow}#{s.upcase}#{return_color}"
|
173
316
|
end
|
174
|
-
|
317
|
+
out
|
175
318
|
end
|
319
|
+
|
176
320
|
end
|
321
|
+
|
@@ -0,0 +1,182 @@
|
|
1
|
+
require 'morpheus/cli/cli_command'
|
2
|
+
|
3
|
+
# This provides commands for authentication
|
4
|
+
# This also includes credential management.
|
5
|
+
class Morpheus::Cli::DocCommand
|
6
|
+
include Morpheus::Cli::CliCommand
|
7
|
+
|
8
|
+
set_command_name :'doc'
|
9
|
+
#set_command_name :'access'
|
10
|
+
register_subcommands :list
|
11
|
+
register_subcommands :get => :swagger
|
12
|
+
register_subcommands :download => :download_swagger
|
13
|
+
|
14
|
+
# hidden until doc complete (or close to it)
|
15
|
+
set_command_hidden
|
16
|
+
|
17
|
+
def initialize()
|
18
|
+
# @appliance_name, @appliance_url = Morpheus::Cli::Remote.active_appliance
|
19
|
+
end
|
20
|
+
|
21
|
+
def handle(args)
|
22
|
+
handle_subcommand(args)
|
23
|
+
end
|
24
|
+
|
25
|
+
def connect(options)
|
26
|
+
@api_client = establish_remote_appliance_connection(options.merge({:no_prompt => true, :skip_verify_access_token => true, :skip_login => true}))
|
27
|
+
@doc_interface = @api_client.doc
|
28
|
+
end
|
29
|
+
|
30
|
+
def list(args)
|
31
|
+
exit_code, err = 0, nil
|
32
|
+
params, options = {}, {}
|
33
|
+
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
34
|
+
opts.banner = subcommand_usage()
|
35
|
+
build_standard_get_options(opts, options)
|
36
|
+
opts.footer = <<-EOT
|
37
|
+
List documentation links.
|
38
|
+
EOT
|
39
|
+
end
|
40
|
+
optparse.parse!(args)
|
41
|
+
verify_args!(args:args, optparse:optparse, count:0)
|
42
|
+
connect(options)
|
43
|
+
# construct the api request
|
44
|
+
params.merge!(parse_list_options(options))
|
45
|
+
# execute the api request
|
46
|
+
@doc_interface.setopts(options)
|
47
|
+
if options[:dry_run]
|
48
|
+
print_dry_run @doc_interface.dry.list(params)
|
49
|
+
return 0, nil
|
50
|
+
end
|
51
|
+
json_response = @doc_interface.list(params)
|
52
|
+
render_response(json_response, options, "links") do
|
53
|
+
title = "Morpheus Documentation"
|
54
|
+
print_h1 title, options
|
55
|
+
if json_response['links'].empty?
|
56
|
+
print yellow, "No help links found.",reset,"\n"
|
57
|
+
else
|
58
|
+
columns = {
|
59
|
+
"Link Name" => 'name',
|
60
|
+
"URL" => 'url',
|
61
|
+
"Description" => {display_method:'description', max_width: (options[:wrap] ? nil : 50)},
|
62
|
+
}
|
63
|
+
print as_pretty_table(json_response['links'], columns.upcase_keys!, options)
|
64
|
+
# print_results_pagination(json_response)
|
65
|
+
end
|
66
|
+
print reset,"\n"
|
67
|
+
end
|
68
|
+
return exit_code, err
|
69
|
+
end
|
70
|
+
|
71
|
+
def swagger(args)
|
72
|
+
exit_code, err = 0, nil
|
73
|
+
params, options = {}, {}
|
74
|
+
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
75
|
+
opts.banner = subcommand_usage()
|
76
|
+
opts.on(nil, "--refresh", "Refresh the document. By default the swagger.yml and swagger.json are cached by the server.") do
|
77
|
+
params['refresh'] = true
|
78
|
+
end
|
79
|
+
opts.on('-g', '--generate', "Alias for --refresh") do
|
80
|
+
params['refresh'] = true
|
81
|
+
end
|
82
|
+
build_standard_get_options(opts, options, [], [:csv])
|
83
|
+
opts.footer = <<-EOT
|
84
|
+
Print the Morpheus API Swagger Documentation (openapi).
|
85
|
+
The default format is JSON. Supports json or yaml.
|
86
|
+
EOT
|
87
|
+
end
|
88
|
+
optparse.parse!(args)
|
89
|
+
verify_args!(args:args, optparse:optparse, count:0)
|
90
|
+
connect(options)
|
91
|
+
# construct the api request
|
92
|
+
params.merge!(parse_list_options(options))
|
93
|
+
# for now, always use .json, and just convert to yaml for display on cli side
|
94
|
+
openapi_format = options[:yaml] ? "yaml" : "json"
|
95
|
+
# params['format'] = openapi_format
|
96
|
+
# execute the api request
|
97
|
+
@doc_interface.setopts(options)
|
98
|
+
if options[:dry_run]
|
99
|
+
params['format'] = openapi_format
|
100
|
+
print_dry_run @doc_interface.dry.swagger(params)
|
101
|
+
return 0, nil
|
102
|
+
end
|
103
|
+
json_response = @doc_interface.swagger(params)
|
104
|
+
# default format is to print header and json
|
105
|
+
render_response(json_response, options) do
|
106
|
+
title = "Morpheus API swagger.#{openapi_format}"
|
107
|
+
print_h1 title, options
|
108
|
+
print cyan
|
109
|
+
print as_json(json_response, options)
|
110
|
+
print reset,"\n"
|
111
|
+
end
|
112
|
+
return exit_code, err
|
113
|
+
end
|
114
|
+
|
115
|
+
def download_swagger(args)
|
116
|
+
exit_code, err = 0, nil
|
117
|
+
params, options = {}, {}
|
118
|
+
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
119
|
+
opts.banner = subcommand_usage("[local-file]")
|
120
|
+
# build_standard_get_options(opts, options, [], [:csv,:out])
|
121
|
+
opts.on(nil, '--yaml', "YAML Output") do
|
122
|
+
options[:yaml] = true
|
123
|
+
options[:format] = :yaml
|
124
|
+
end
|
125
|
+
opts.on(nil, "--refresh", "Refresh the document. By default the swagger.yml and swagger.json are cached by the server.") do
|
126
|
+
params['refresh'] = true
|
127
|
+
end
|
128
|
+
opts.on('-g', '--generate', "Alias for --refresh") do
|
129
|
+
params['refresh'] = true
|
130
|
+
end
|
131
|
+
opts.on( '-f', '--force', "Overwrite existing [local-file] if it exists." ) do
|
132
|
+
options[:overwrite] = true
|
133
|
+
end
|
134
|
+
opts.on( '-p', '--mkdir', "Create missing directories for [local-file] if they do not exist." ) do
|
135
|
+
options[:mkdir] = true
|
136
|
+
end
|
137
|
+
build_common_options(opts, options, [:dry_run, :quiet, :remote])
|
138
|
+
opts.footer = <<-EOT
|
139
|
+
Download the Morpheus API Swagger Documentation (openapi).
|
140
|
+
[local-file] is required. This is the full local filepath for the downloaded file.
|
141
|
+
The default format is JSON. Supports json or yaml.
|
142
|
+
EOT
|
143
|
+
end
|
144
|
+
optparse.parse!(args)
|
145
|
+
verify_args!(args:args, optparse:optparse, count:1)
|
146
|
+
connect(options)
|
147
|
+
# parse args
|
148
|
+
outfile = args[0]
|
149
|
+
if !validate_outfile(outfile, options)
|
150
|
+
return 1, "Failed to validate outfile"
|
151
|
+
end
|
152
|
+
# construct the api request
|
153
|
+
params.merge!(parse_list_options(options))
|
154
|
+
if outfile.include?(".yml") || outfile.include?(".yaml")
|
155
|
+
options[:yaml] = true
|
156
|
+
end
|
157
|
+
openapi_format = options[:yaml] ? "yaml" : "json"
|
158
|
+
params['format'] = openapi_format
|
159
|
+
# execute the api request
|
160
|
+
@doc_interface.setopts(options)
|
161
|
+
if options[:dry_run]
|
162
|
+
print_dry_run @doc_interface.dry.download_swagger(outfile, params)
|
163
|
+
return 0, nil
|
164
|
+
end
|
165
|
+
print cyan + "Downloading swagger.#{openapi_format} to #{outfile} ... " if !options[:quiet]
|
166
|
+
http_response = @doc_interface.download_swagger(outfile, params)
|
167
|
+
if http_response.code.to_i == 200
|
168
|
+
print green + "SUCCESS" + reset + "\n" if !options[:quiet]
|
169
|
+
return 0, nil
|
170
|
+
else
|
171
|
+
print red + "ERROR" + reset + " HTTP #{http_response.code}" + "\n" if !options[:quiet]
|
172
|
+
if File.exists?(outfile) && File.file?(outfile)
|
173
|
+
Morpheus::Logging::DarkPrinter.puts "Deleting bad file download: #{outfile}" if Morpheus::Logging.debug?
|
174
|
+
File.delete(outfile)
|
175
|
+
end
|
176
|
+
return 1, "HTTP #{http_response.code}"
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
protected
|
181
|
+
|
182
|
+
end
|