morpheus-cli 4.2.14 → 4.2.19
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/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 +44 -55
- 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 +4 -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/blueprints_command.rb +27 -61
- data/lib/morpheus/cli/boot_scripts_command.rb +1 -1
- data/lib/morpheus/cli/cli_command.rb +183 -45
- data/lib/morpheus/cli/cli_registry.rb +3 -0
- data/lib/morpheus/cli/clouds.rb +7 -10
- data/lib/morpheus/cli/clusters.rb +0 -18
- data/lib/morpheus/cli/commands/standard/benchmark_command.rb +23 -20
- 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 +339 -225
- data/lib/morpheus/cli/jobs_command.rb +2 -2
- data/lib/morpheus/cli/library_layouts_command.rb +1 -1
- data/lib/morpheus/cli/library_option_lists_command.rb +61 -125
- data/lib/morpheus/cli/library_option_types_command.rb +32 -37
- 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/library_helper.rb +32 -0
- data/lib/morpheus/cli/mixins/option_source_helper.rb +1 -1
- data/lib/morpheus/cli/mixins/print_helper.rb +149 -84
- 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 +46 -10
- data/lib/morpheus/cli/price_sets_command.rb +1 -1
- data/lib/morpheus/cli/projects_command.rb +7 -7
- 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/tasks.rb +24 -10
- 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 +11 -8
- data/lib/morpheus/ext/hash.rb +21 -0
- data/lib/morpheus/formatters.rb +7 -19
- data/lib/morpheus/terminal.rb +1 -0
- metadata +12 -3
- data/lib/morpheus/cli/auth_command.rb +0 -105
@@ -7,11 +7,14 @@ class Morpheus::Cli::BenchmarkCommand
|
|
7
7
|
include Morpheus::Cli::CliCommand
|
8
8
|
set_command_name :'benchmark'
|
9
9
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
10
|
+
register_subcommand :on, "Enable global benchmarking."
|
11
|
+
register_subcommand :off, "Disable global benchmarking."
|
12
|
+
register_subcommand :on?, "Print the value of the global benchmark setting. Exit 0 if on."
|
13
|
+
register_subcommand :off?, "Print the value of the global benchmark setting. Exit 0 if off."
|
14
|
+
register_subcommand :start, "Start recording a benchmark."
|
15
|
+
register_subcommand :stop, "Stop recording a benchmark."
|
16
|
+
register_subcommand :status, "Print status of benchmark."
|
17
|
+
register_subcommand :exec, :execute, "Benchmark a specified command or expression."
|
15
18
|
|
16
19
|
# this would be cool, we should store all benchmarking results in memory or on disk =o
|
17
20
|
# register_subcommands :list, :get, :put, :remove
|
@@ -35,7 +38,7 @@ class Morpheus::Cli::BenchmarkCommand
|
|
35
38
|
opts.banner = subcommand_usage("")
|
36
39
|
build_common_options(opts, options, [:quiet])
|
37
40
|
opts.footer = <<-EOT
|
38
|
-
|
41
|
+
#{subcommand_description}
|
39
42
|
This behaves the same as if you were to add the -B switch to every command.
|
40
43
|
EOT
|
41
44
|
end
|
@@ -65,7 +68,7 @@ EOT
|
|
65
68
|
opts.banner = subcommand_usage("")
|
66
69
|
build_common_options(opts, options, [:quiet])
|
67
70
|
opts.footer = <<-EOT
|
68
|
-
|
71
|
+
#{subcommand_description}
|
69
72
|
The default state for this setting is off.
|
70
73
|
EOT
|
71
74
|
end
|
@@ -95,7 +98,7 @@ EOT
|
|
95
98
|
opts.banner = subcommand_usage("")
|
96
99
|
build_common_options(opts, options, [:quiet])
|
97
100
|
opts.footer = <<-EOT
|
98
|
-
|
101
|
+
#{subcommand_description}
|
99
102
|
Exit 0 if on.
|
100
103
|
EOT
|
101
104
|
end
|
@@ -121,7 +124,7 @@ EOT
|
|
121
124
|
opts.banner = subcommand_usage("")
|
122
125
|
build_common_options(opts, options, [:quiet])
|
123
126
|
opts.footer = <<-EOT
|
124
|
-
|
127
|
+
#{subcommand_description}
|
125
128
|
Exit 0 if off.
|
126
129
|
EOT
|
127
130
|
end
|
@@ -149,7 +152,7 @@ EOT
|
|
149
152
|
opts.banner = subcommand_usage("[name]")
|
150
153
|
build_common_options(opts, options, [:quiet])
|
151
154
|
opts.footer = <<-EOT
|
152
|
-
|
155
|
+
#{subcommand_description}
|
153
156
|
[name] is required. This is just a name for the routine.
|
154
157
|
This allows you to record how long it takes to run a series of commands.
|
155
158
|
Just run `benchmark stop` when you are finished.
|
@@ -194,7 +197,7 @@ EOT
|
|
194
197
|
end
|
195
198
|
build_common_options(opts, options, [:quiet])
|
196
199
|
opts.footer = <<-EOT
|
197
|
-
|
200
|
+
#{subcommand_description}
|
198
201
|
[name] is optional. This is the name of the benchmark to stop.
|
199
202
|
The last benchmark is used by default.
|
200
203
|
EOT
|
@@ -254,7 +257,7 @@ EOT
|
|
254
257
|
opts.banner = subcommand_usage("[name]")
|
255
258
|
build_common_options(opts, options, [:quiet])
|
256
259
|
opts.footer = <<-EOT
|
257
|
-
|
260
|
+
#{subcommand_description}
|
258
261
|
[name] is optional. This is the name of the benchmark to inspect.
|
259
262
|
The last benchmark is used by default.
|
260
263
|
EOT
|
@@ -309,7 +312,7 @@ EOT
|
|
309
312
|
end
|
310
313
|
build_common_options(opts, options, [:quiet])
|
311
314
|
opts.footer = <<-EOT
|
312
|
-
|
315
|
+
#{subcommand_description}
|
313
316
|
[command] is required. This is the command to execute
|
314
317
|
EOT
|
315
318
|
end
|
@@ -360,7 +363,7 @@ EOT
|
|
360
363
|
else
|
361
364
|
out << "\texit: 0 "
|
362
365
|
end
|
363
|
-
total_time_str = "#{benchmark_record.duration.round((benchmark_record.duration > 0.002) ? 3 : 6)}s"
|
366
|
+
total_time_str = "#{benchmark_record.duration.round((benchmark_record.duration > 0.002) ? 3 : 6)} s"
|
364
367
|
out << "\t #{total_time_str.ljust(9, ' ')}"
|
365
368
|
else
|
366
369
|
benchmark_records = []
|
@@ -381,8 +384,8 @@ EOT
|
|
381
384
|
# all_durations = benchmark_records.collect {|benchmark_record| benchmark_record.duration }
|
382
385
|
# total_duration = all_durations.inject(0.0) {|acc, i| acc + i }
|
383
386
|
# avg_duration = total_duration / all_durations.size
|
384
|
-
# total_time_str = "#{total_duration.round((total_duration > 0.002) ? 3 : 6)}s"
|
385
|
-
# avg_time_str = "#{avg_duration.round((total_duration > 0.002) ? 3 : 6)}s"
|
387
|
+
# total_time_str = "#{total_duration.round((total_duration > 0.002) ? 3 : 6)} s"
|
388
|
+
# avg_time_str = "#{avg_duration.round((total_duration > 0.002) ? 3 : 6)} s"
|
386
389
|
|
387
390
|
all_durations = []
|
388
391
|
stats = {total: 0, avg: nil, min: nil, max: nil}
|
@@ -403,10 +406,10 @@ EOT
|
|
403
406
|
stats[:avg] = stats[:total].to_f / all_durations.size
|
404
407
|
end
|
405
408
|
|
406
|
-
total_time_str = "#{stats[:total].round((stats[:total] > 0.002) ? 3 : 6)}s"
|
407
|
-
min_time_str = stats[:min] ? "#{stats[:min].round((stats[:min] > 0.002) ? 3 : 6)}s" : ""
|
408
|
-
max_time_str = stats[:max] ? "#{stats[:max].round((stats[:max] > 0.002) ? 3 : 6)}s" : ""
|
409
|
-
avg_time_str = stats[:avg] ? "#{stats[:avg].round((stats[:avg] > 0.002) ? 3 : 6)}s" : ""
|
409
|
+
total_time_str = "#{stats[:total].round((stats[:total] > 0.002) ? 3 : 6)} s"
|
410
|
+
min_time_str = stats[:min] ? "#{stats[:min].round((stats[:min] > 0.002) ? 3 : 6)} s" : ""
|
411
|
+
max_time_str = stats[:max] ? "#{stats[:max].round((stats[:max] > 0.002) ? 3 : 6)} s" : ""
|
412
|
+
avg_time_str = stats[:avg] ? "#{stats[:avg].round((stats[:avg] > 0.002) ? 3 : 6)} s" : ""
|
410
413
|
|
411
414
|
out = ""
|
412
415
|
# <benchmark name or command>
|
@@ -176,7 +176,7 @@ morpheus v#{Morpheus::Cli::VERSION}
|
|
176
176
|
|
177
177
|
To learn more about the Morpheus Appliance, visit https://www.morpheusdata.com/features
|
178
178
|
|
179
|
-
To learn more about the Morpheus API, visit
|
179
|
+
To learn more about the Morpheus API, visit https://apidocs.morpheusdata.com
|
180
180
|
|
181
181
|
## GLOBAL OPTIONS
|
182
182
|
|
@@ -87,7 +87,7 @@ module Morpheus
|
|
87
87
|
rescue ::RestClient::Exception => e
|
88
88
|
#raise e
|
89
89
|
print_red_alert "Token not valid."
|
90
|
-
if options[:debug]
|
90
|
+
if options[:debug]
|
91
91
|
print_rest_exception(e, options)
|
92
92
|
end
|
93
93
|
wallet = nil
|
@@ -255,8 +255,7 @@ module Morpheus
|
|
255
255
|
true
|
256
256
|
end
|
257
257
|
|
258
|
-
def use_refresh_token(options = {})
|
259
|
-
#puts "use_refresh_token(#{options})"
|
258
|
+
def use_refresh_token(refresh_token_value, options = {})
|
260
259
|
|
261
260
|
wallet = load_saved_credentials
|
262
261
|
|
@@ -265,22 +264,25 @@ module Morpheus
|
|
265
264
|
return nil
|
266
265
|
end
|
267
266
|
|
268
|
-
if
|
269
|
-
|
270
|
-
|
267
|
+
if refresh_token_value.nil?
|
268
|
+
if wallet['refresh_token']
|
269
|
+
refresh_token_value = wallet['refresh_token']
|
270
|
+
else
|
271
|
+
print_red_alert yellow,"No refresh token found for #{display_appliance(@appliance_name, @appliance_url)}",reset,"\n"
|
272
|
+
return nil
|
273
|
+
end
|
271
274
|
end
|
272
275
|
|
273
|
-
|
274
276
|
username = wallet['username']
|
275
277
|
|
276
278
|
begin
|
277
279
|
auth_interface = Morpheus::AuthInterface.new({url:@appliance_url})
|
278
280
|
auth_interface.setopts(options)
|
279
281
|
if options[:dry_run]
|
280
|
-
print_dry_run auth_interface.dry.use_refresh_token(
|
282
|
+
print_dry_run auth_interface.dry.use_refresh_token(refresh_token_value)
|
281
283
|
return nil
|
282
284
|
end
|
283
|
-
json_response = auth_interface.use_refresh_token(
|
285
|
+
json_response = auth_interface.use_refresh_token(refresh_token_value)
|
284
286
|
#wallet = json_response
|
285
287
|
login_date = Time.now
|
286
288
|
expire_date = nil
|
@@ -311,6 +313,8 @@ module Morpheus
|
|
311
313
|
print_rest_exception(e, options)
|
312
314
|
end
|
313
315
|
wallet = nil
|
316
|
+
# return now or else it will log them out
|
317
|
+
return nil
|
314
318
|
end
|
315
319
|
|
316
320
|
# save wallet to credentials file
|
@@ -0,0 +1,374 @@
|
|
1
|
+
require 'morpheus/cli/cli_command'
|
2
|
+
require 'yaml'
|
3
|
+
|
4
|
+
class Morpheus::Cli::Deploy
|
5
|
+
include Morpheus::Cli::CliCommand
|
6
|
+
include Morpheus::Cli::DeploymentsHelper
|
7
|
+
|
8
|
+
set_command_name :deploy
|
9
|
+
|
10
|
+
def connect(opts)
|
11
|
+
@api_client = establish_remote_appliance_connection(opts)
|
12
|
+
@instances_interface = @api_client.instances
|
13
|
+
@deploy_interface = @api_client.deploy
|
14
|
+
@deployments_interface = @api_client.deployments
|
15
|
+
end
|
16
|
+
|
17
|
+
def handle(args)
|
18
|
+
options={}
|
19
|
+
optparse = Morpheus::Cli::OptionParser.new do|opts|
|
20
|
+
opts.banner = "Usage: morpheus deploy [environment]"
|
21
|
+
build_common_options(opts, options, [:auto_confirm, :remote, :dry_run])
|
22
|
+
opts.footer = <<-EOT
|
23
|
+
Deploy to an instance using the morpheus.yml file, located in the working directory.
|
24
|
+
[environment] is optional. Merge settings under environments.{environment}. Default is no environment.
|
25
|
+
|
26
|
+
First this parses the morpheus.yml file and merges the specified environment settings.
|
27
|
+
The specified instance must exist and the specified version must not exist.
|
28
|
+
If the settings are valid, the new deployment version will be created and
|
29
|
+
all the specified files are uploaded to the new deployment version.
|
30
|
+
Finally, it deploys the new version to the instance.
|
31
|
+
|
32
|
+
The morpheus.yml should be located in the working directory.
|
33
|
+
This file contains the information necessary to perform a deployment via the cli.
|
34
|
+
|
35
|
+
File Settings
|
36
|
+
==================
|
37
|
+
|
38
|
+
* name - (required) The instance name we are deploying to and, by default, name of the deployment being created.
|
39
|
+
* version - (required) The version identifier of the deployment being created (userVersion)
|
40
|
+
* deployment - The name of the deployment being created, name is used by default
|
41
|
+
* script - The initial script to run before looking for files to upload.
|
42
|
+
* files - List of file patterns to use for uploading files and their target destination.
|
43
|
+
Each item should contain path and pattern, path may be relative to the working directory, default pattern is: '**/*'
|
44
|
+
* options - Map of deployment options depending on deployment type
|
45
|
+
* post_script - A post operation script to be run on the local machine
|
46
|
+
* stage_only - If set to true the deploy will only be staged and not actually run
|
47
|
+
* environments - Map of objects that contain nested properties for each environment name
|
48
|
+
|
49
|
+
It is possible to nest these properties in an "environments" map to override based on a passed environment.
|
50
|
+
|
51
|
+
Example
|
52
|
+
==================
|
53
|
+
|
54
|
+
name: neatsite
|
55
|
+
version: 5.0
|
56
|
+
script: "rake build"
|
57
|
+
files:
|
58
|
+
- path: build
|
59
|
+
environments:
|
60
|
+
production:
|
61
|
+
files:
|
62
|
+
- path: production-build
|
63
|
+
EOT
|
64
|
+
end
|
65
|
+
optparse.parse!(args)
|
66
|
+
verify_args!(args:args, optparse:optparse, min:0, max:1)
|
67
|
+
options[:options]['name'] = args[0] if args[0]
|
68
|
+
connect(options)
|
69
|
+
payload = {}
|
70
|
+
|
71
|
+
environment = default_deploy_environment
|
72
|
+
if args.count > 0
|
73
|
+
environment = args[0]
|
74
|
+
end
|
75
|
+
if load_deploy_file().nil?
|
76
|
+
raise_command_error "Morpheus Deploy File `morpheus.yml` not detected. Please create one and try again."
|
77
|
+
end
|
78
|
+
|
79
|
+
# Parse and validate config, need instance + deployment + version + files
|
80
|
+
# name can be specified as a single value for both instance and deployment
|
81
|
+
|
82
|
+
deploy_args = merged_deploy_args(environment)
|
83
|
+
|
84
|
+
instance_name = deploy_args['name']
|
85
|
+
if deploy_args['instance'].is_a?(String)
|
86
|
+
instance_name = deploy_args['instance']
|
87
|
+
end
|
88
|
+
if instance_name.nil?
|
89
|
+
raise_command_error "Instance not specified. Please specify the instance name and try again."
|
90
|
+
end
|
91
|
+
|
92
|
+
deployment_name = deploy_args['name'] || instance_name
|
93
|
+
if deploy_args['deployment'].is_a?(String)
|
94
|
+
deployment_name = deploy_args['deployment']
|
95
|
+
end
|
96
|
+
|
97
|
+
version_number = deploy_args['version']
|
98
|
+
if version_number.nil?
|
99
|
+
raise_command_error "Version not specified. Please specify the version and try again."
|
100
|
+
end
|
101
|
+
|
102
|
+
instance_results = @instances_interface.list(name: instance_name)
|
103
|
+
if instance_results['instances'].empty?
|
104
|
+
raise_command_error "Instance not found by name '#{instance_name}'"
|
105
|
+
end
|
106
|
+
instance = instance_results['instances'][0]
|
107
|
+
instance_id = instance['id']
|
108
|
+
|
109
|
+
# ok do it
|
110
|
+
# fetch/create deployment, create deployment version, upload files, and deploy it to instance.
|
111
|
+
|
112
|
+
print_h1 "Morpheus Deployment"
|
113
|
+
|
114
|
+
columns = {
|
115
|
+
"Instance" => :name,
|
116
|
+
"Deployment" => :deployment,
|
117
|
+
"Version" => :version,
|
118
|
+
"Script" => :script,
|
119
|
+
"Post Script" => :post_script,
|
120
|
+
"Files" => :files,
|
121
|
+
"Environment" => :environment,
|
122
|
+
}
|
123
|
+
pretty_file_config = deploy_args['files'].collect {|it|
|
124
|
+
[(it['path'] ? "path: #{it['path']}" : nil), (it['pattern'] ? "pattern: #{it['pattern']}" : nil)].compact.join(", ")
|
125
|
+
}.join(", ")
|
126
|
+
deploy_settings = {
|
127
|
+
:name => instance_name,
|
128
|
+
:deployment => deployment_name,
|
129
|
+
:version => version_number,
|
130
|
+
:script => deploy_args['script'],
|
131
|
+
:post_script => deploy_args['post_script'],
|
132
|
+
:files => pretty_file_config,
|
133
|
+
# :files => deploy_args['files'],
|
134
|
+
# :files => deploy_files.size,
|
135
|
+
# :file_config => (deploy_files.size == 1 ? deploy_files[0][:destination] : deploy_args['files'])
|
136
|
+
:environment => environment
|
137
|
+
}
|
138
|
+
columns.delete("Script") if deploy_settings[:script].nil?
|
139
|
+
columns.delete("Post Script") if deploy_settings[:post_script].nil?
|
140
|
+
columns.delete("Environment") if deploy_settings[:environment].nil?
|
141
|
+
print_description_list(columns, deploy_settings)
|
142
|
+
print reset, "\n"
|
143
|
+
|
144
|
+
if !deploy_args['script'].nil?
|
145
|
+
# do this for dry run too since this is usually what creates the files to be uploaded
|
146
|
+
print cyan, "Executing Pre Deploy Script...", reset, "\n"
|
147
|
+
puts "running command: #{deploy_args['script']}"
|
148
|
+
if !system(deploy_args['script'])
|
149
|
+
raise_command_error "Error executing pre script..."
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
# Find Files to Upload
|
154
|
+
deploy_files = []
|
155
|
+
if deploy_args['files'].nil? || deploy_args['files'].empty? || !deploy_args['files'].is_a?(Array)
|
156
|
+
raise_command_error "Files not specified. Please specify files array, each item may specify a path or pattern of file(s) to upload"
|
157
|
+
else
|
158
|
+
#print "\n",cyan, "Finding Files...", reset, "\n"
|
159
|
+
current_working_dir = Dir.pwd
|
160
|
+
deploy_args['files'].each do |fmap|
|
161
|
+
Dir.chdir(fmap['path'] || current_working_dir)
|
162
|
+
files = Dir.glob(fmap['pattern'] || '**/*')
|
163
|
+
files.each do |file|
|
164
|
+
if File.file?(file)
|
165
|
+
destination = file.split("/")[0..-2].join("/")
|
166
|
+
# deploy_files << {filepath: File.expand_path(file), destination: destination}
|
167
|
+
deploy_files << {filepath: File.expand_path(file), destination: file}
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
171
|
+
#print cyan, "Found #{deploy_files.size} Files to Upload!", reset, "\n"
|
172
|
+
Dir.chdir(current_working_dir)
|
173
|
+
end
|
174
|
+
|
175
|
+
if deploy_files.empty?
|
176
|
+
raise_command_error "0 files found for: #{deploy_args['files'].inspect}"
|
177
|
+
else
|
178
|
+
print cyan, "Found #{deploy_files.size} Files to Upload!", reset, "\n"
|
179
|
+
end
|
180
|
+
|
181
|
+
unless options[:yes] || Morpheus::Cli::OptionTypes.confirm("Are you sure you want to create deployment version #{version_number} (#{deploy_files.size} #{deploy_files.size == 1 ? 'file' : 'files'}) and deploy it to instance #{instance['name']}?")
|
182
|
+
return 9, "aborted command"
|
183
|
+
end
|
184
|
+
|
185
|
+
# Find or Create Deployment
|
186
|
+
deployment = nil
|
187
|
+
deployments = @deployments_interface.list(name: deployment_name)['deployments']
|
188
|
+
|
189
|
+
@instances_interface.setopts(options)
|
190
|
+
@deploy_interface.setopts(options)
|
191
|
+
@deployments_interface.setopts(options)
|
192
|
+
|
193
|
+
if deployments.size > 1
|
194
|
+
raise_command_error "#{deployments.size} deployment versions found by deployment '#{name}'"
|
195
|
+
elsif deployments.size == 1
|
196
|
+
deployment = deployments[0]
|
197
|
+
# should update here, eg description
|
198
|
+
else
|
199
|
+
# create it
|
200
|
+
payload = {
|
201
|
+
'deployment' => {
|
202
|
+
'name' => deployment_name
|
203
|
+
}
|
204
|
+
}
|
205
|
+
payload['deployment']['description'] = deploy_args['description'] if deploy_args['description']
|
206
|
+
|
207
|
+
if options[:dry_run]
|
208
|
+
print_dry_run @deployments_interface.dry.create(payload)
|
209
|
+
# return 0, nil
|
210
|
+
deployment = {'id' => ':deploymentId', 'name' => deployment_name}
|
211
|
+
else
|
212
|
+
json_response = @deployments_interface.create(payload)
|
213
|
+
deployment = json_response['deployment']
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
# Find or Create Deployment Version
|
218
|
+
# Actually, for now this this errors if the version already exists, but it should update it.
|
219
|
+
|
220
|
+
@deployments_interface = @api_client.deployments
|
221
|
+
deployment_version = nil
|
222
|
+
if options[:dry_run]
|
223
|
+
print_dry_run @deployments_interface.dry.list_versions(deployment['id'], {userVersion: version_number})
|
224
|
+
# return 0, nil
|
225
|
+
#deployment_versions =[{'id' => ':versionId', 'version' => version_number}]
|
226
|
+
deployment_versions = []
|
227
|
+
else
|
228
|
+
deployment_versions = @deployments_interface.list_versions(deployment['id'], {userVersion: version_number})['versions']
|
229
|
+
@deployments_interface.setopts(options)
|
230
|
+
end
|
231
|
+
|
232
|
+
|
233
|
+
if deployment_versions.size > 0
|
234
|
+
raise_command_error "Deployment '#{deployment['name']}' version '#{version_number}' already exists. Specify a new version or delete the existing version."
|
235
|
+
# if deployment_versions.size > 1
|
236
|
+
# raise_command_error "#{deployment_versions.size} versions found by version '#{name}'"
|
237
|
+
# elsif deployment_versions.size == 1
|
238
|
+
# deployment_version = deployment_versions[0]
|
239
|
+
# # should update here, eg description
|
240
|
+
else
|
241
|
+
# create it
|
242
|
+
payload = {
|
243
|
+
'version' => {
|
244
|
+
'userVersion' => version_number,
|
245
|
+
'deployType' => (deploy_args['type'] || deploy_args['deployType'] || 'file')
|
246
|
+
}
|
247
|
+
}
|
248
|
+
payload['version']['fetchUrl'] = deploy_args['fetchUrl'] if deploy_args['fetchUrl']
|
249
|
+
payload['version']['gitUrl'] = deploy_args['gitUrl'] if deploy_args['gitUrl']
|
250
|
+
payload['version']['gitRef'] = deploy_args['gitRef'] if deploy_args['gitRef']
|
251
|
+
|
252
|
+
if options[:dry_run]
|
253
|
+
print_dry_run @deployments_interface.dry.create_version(deployment['id'], payload)
|
254
|
+
# return 0, nil
|
255
|
+
deployment_version = {'id' => ':versionId', 'version' => version_number}
|
256
|
+
else
|
257
|
+
json_response = @deployments_interface.create_version(deployment['id'], payload)
|
258
|
+
deployment_version = json_response['version']
|
259
|
+
end
|
260
|
+
end
|
261
|
+
|
262
|
+
|
263
|
+
# Upload Files
|
264
|
+
if deploy_files && !deploy_files.empty?
|
265
|
+
print "\n",cyan, "Uploading #{deploy_files.size} Files...", reset, "\n"
|
266
|
+
current_working_dir = Dir.pwd
|
267
|
+
deploy_files.each do |f|
|
268
|
+
destination = f[:destination]
|
269
|
+
if options[:dry_run]
|
270
|
+
print_dry_run @deployments_interface.upload_file(deployment['id'], deployment_version['id'], f[:filepath], f[:destination])
|
271
|
+
else
|
272
|
+
print cyan," - Uploading #{f[:destination]} ...", reset if !options[:quiet]
|
273
|
+
upload_result = @deployments_interface.upload_file(deployment['id'], deployment_version['id'], f[:filepath], f[:destination])
|
274
|
+
#print green + "SUCCESS" + reset + "\n" if !options[:quiet]
|
275
|
+
print reset, "\n" if !options[:quiet]
|
276
|
+
end
|
277
|
+
end
|
278
|
+
print cyan, "Upload Complete!", reset, "\n"
|
279
|
+
Dir.chdir(current_working_dir)
|
280
|
+
else
|
281
|
+
print "\n",cyan, "0 files to upload", reset, "\n"
|
282
|
+
end
|
283
|
+
|
284
|
+
# TODO: support deploying other deployTypes too, git and fetch
|
285
|
+
|
286
|
+
if !deploy_args['post_script'].nil?
|
287
|
+
print cyan, "Executing Post Script...", reset, "\n"
|
288
|
+
puts "running command: #{deploy_args['post_script']}"
|
289
|
+
if !system(deploy_args['post_script'])
|
290
|
+
raise_command_error "Error executing post script..."
|
291
|
+
end
|
292
|
+
end
|
293
|
+
|
294
|
+
# JD: restart for evars eh?
|
295
|
+
if deploy_args['env']
|
296
|
+
evars = []
|
297
|
+
deploy_args['env'].each_pair do |key, value|
|
298
|
+
evars << {name: key, value: value, export: false}
|
299
|
+
end
|
300
|
+
payload = {envs: evars}
|
301
|
+
if options[:dry_run]
|
302
|
+
print_dry_run @instances_interface.dry.create_env(instance_id, payload)
|
303
|
+
print_dry_run @instances_interface.dry.restart(instance_id)
|
304
|
+
else
|
305
|
+
@instances_interface.create_env(instance_id, payload)
|
306
|
+
@instances_interface.restart(instance_id)
|
307
|
+
end
|
308
|
+
end
|
309
|
+
# Create the AppDeploy, this does the deploy async (as of 4.2.2-3)
|
310
|
+
payload = {'appDeploy' => {} }
|
311
|
+
payload['appDeploy']['versionId'] = deployment_version['id']
|
312
|
+
if deploy_args['options']
|
313
|
+
payload['appDeploy']['config'] = deploy_args['options']
|
314
|
+
end
|
315
|
+
# stageOnly means do not actually deploy yet, can invoke @deploy_interface.deploy(deployment['id']) later
|
316
|
+
# there is no cli command for that yet though..
|
317
|
+
stage_only = deploy_args['stage_deploy'] || deploy_args['stage_only'] || deploy_args['stageOnly']
|
318
|
+
if stage_only
|
319
|
+
payload['appDeploy']['stageOnly'] = true
|
320
|
+
end
|
321
|
+
app_deploy_id = nil
|
322
|
+
if options[:dry_run]
|
323
|
+
print_dry_run @deploy_interface.dry.create(instance_id, payload)
|
324
|
+
# return 0, nil
|
325
|
+
app_deploy_id = ':appDeployId'
|
326
|
+
else
|
327
|
+
# Create a new appDeploy record, without stageOnly, this actually does the deployment
|
328
|
+
print cyan, "Deploying #{deployment_name} version #{version_number} to instance #{instance_name} ...", reset, "\n"
|
329
|
+
deploy_result = @deploy_interface.create(instance_id, payload)
|
330
|
+
app_deploy = deploy_result['appDeploy']
|
331
|
+
app_deploy_id = app_deploy['id']
|
332
|
+
print_green_success "Deploy Successful!"
|
333
|
+
end
|
334
|
+
return 0, nil
|
335
|
+
end
|
336
|
+
|
337
|
+
protected
|
338
|
+
|
339
|
+
# Loads a morpheus.yml file from within the current working directory.
|
340
|
+
# This file contains information necessary to perform a deployment via the cli.
|
341
|
+
#
|
342
|
+
# === Example File Attributes
|
343
|
+
# * +script+ - The initial script to run before uploading files
|
344
|
+
# * +name+ - The instance name we are deploying to (can be overridden in CLI)
|
345
|
+
# * +files+ - List of file patterns to use for uploading files and their target destination
|
346
|
+
# * +options+ - Map of deployment options depending on deployment type
|
347
|
+
# * +post_script+ - A post operation script to be run on the local machine
|
348
|
+
# * +stage_deploy+ - If set to true the deploy will only be staged and not actually run
|
349
|
+
#
|
350
|
+
# +NOTE: + It is also possible to nest these properties in an "environments" map to override based on a passed environment deploy name
|
351
|
+
#
|
352
|
+
def load_deploy_file
|
353
|
+
if !File.exist? "morpheus.yml"
|
354
|
+
puts "No morpheus.yml file detected in the current directory. Nothing to do."
|
355
|
+
return nil
|
356
|
+
end
|
357
|
+
|
358
|
+
@deploy_file = YAML.load_file("morpheus.yml")
|
359
|
+
return @deploy_file
|
360
|
+
end
|
361
|
+
|
362
|
+
def merged_deploy_args(environment)
|
363
|
+
deploy_args = @deploy_file.reject { |key,value| key == 'environment'}
|
364
|
+
if environment && !@deploy_file['environment'].nil? && !@deploy_file['environment'][environment].nil?
|
365
|
+
deploy_args = deploy_args.merge(@deploy_file['environment'][environment])
|
366
|
+
end
|
367
|
+
return deploy_args
|
368
|
+
end
|
369
|
+
|
370
|
+
def default_deploy_environment
|
371
|
+
nil
|
372
|
+
end
|
373
|
+
|
374
|
+
end
|