morpheus-cli 4.2.16 → 4.2.17

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.
Files changed (67) hide show
  1. checksums.yaml +4 -4
  2. data/Dockerfile +1 -1
  3. data/README.md +8 -6
  4. data/lib/morpheus/api/api_client.rb +32 -14
  5. data/lib/morpheus/api/auth_interface.rb +4 -2
  6. data/lib/morpheus/api/backup_jobs_interface.rb +9 -0
  7. data/lib/morpheus/api/backups_interface.rb +16 -0
  8. data/lib/morpheus/api/deploy_interface.rb +25 -56
  9. data/lib/morpheus/api/deployments_interface.rb +43 -54
  10. data/lib/morpheus/api/doc_interface.rb +57 -0
  11. data/lib/morpheus/api/instances_interface.rb +5 -0
  12. data/lib/morpheus/api/rest_interface.rb +40 -0
  13. data/lib/morpheus/api/user_sources_interface.rb +0 -15
  14. data/lib/morpheus/api/users_interface.rb +2 -3
  15. data/lib/morpheus/benchmarking.rb +2 -2
  16. data/lib/morpheus/cli.rb +3 -1
  17. data/lib/morpheus/cli/access_token_command.rb +27 -10
  18. data/lib/morpheus/cli/apps.rb +21 -15
  19. data/lib/morpheus/cli/backup_jobs_command.rb +276 -0
  20. data/lib/morpheus/cli/backups_command.rb +271 -0
  21. data/lib/morpheus/cli/boot_scripts_command.rb +1 -1
  22. data/lib/morpheus/cli/cli_command.rb +92 -41
  23. data/lib/morpheus/cli/clusters.rb +0 -18
  24. data/lib/morpheus/cli/commands/standard/benchmark_command.rb +7 -7
  25. data/lib/morpheus/cli/commands/standard/man_command.rb +1 -1
  26. data/lib/morpheus/cli/credentials.rb +13 -9
  27. data/lib/morpheus/cli/deploy.rb +374 -0
  28. data/lib/morpheus/cli/deployments.rb +521 -197
  29. data/lib/morpheus/cli/deploys.rb +271 -126
  30. data/lib/morpheus/cli/doc.rb +182 -0
  31. data/lib/morpheus/cli/error_handler.rb +23 -8
  32. data/lib/morpheus/cli/errors.rb +3 -2
  33. data/lib/morpheus/cli/image_builder_command.rb +2 -2
  34. data/lib/morpheus/cli/instances.rb +136 -17
  35. data/lib/morpheus/cli/invoices_command.rb +51 -38
  36. data/lib/morpheus/cli/library_layouts_command.rb +1 -1
  37. data/lib/morpheus/cli/login.rb +9 -3
  38. data/lib/morpheus/cli/mixins/accounts_helper.rb +158 -100
  39. data/lib/morpheus/cli/mixins/backups_helper.rb +115 -0
  40. data/lib/morpheus/cli/mixins/deployments_helper.rb +135 -0
  41. data/lib/morpheus/cli/mixins/option_source_helper.rb +1 -1
  42. data/lib/morpheus/cli/mixins/print_helper.rb +110 -74
  43. data/lib/morpheus/cli/mixins/provisioning_helper.rb +2 -2
  44. data/lib/morpheus/cli/mixins/whoami_helper.rb +19 -6
  45. data/lib/morpheus/cli/network_routers_command.rb +1 -1
  46. data/lib/morpheus/cli/option_parser.rb +48 -5
  47. data/lib/morpheus/cli/option_types.rb +1 -1
  48. data/lib/morpheus/cli/remote.rb +3 -2
  49. data/lib/morpheus/cli/roles.rb +49 -92
  50. data/lib/morpheus/cli/security_groups.rb +7 -1
  51. data/lib/morpheus/cli/service_plans_command.rb +10 -10
  52. data/lib/morpheus/cli/setup.rb +1 -1
  53. data/lib/morpheus/cli/shell.rb +7 -6
  54. data/lib/morpheus/cli/subnets_command.rb +1 -1
  55. data/lib/morpheus/cli/tenants_command.rb +133 -163
  56. data/lib/morpheus/cli/user_groups_command.rb +20 -65
  57. data/lib/morpheus/cli/user_settings_command.rb +115 -13
  58. data/lib/morpheus/cli/user_sources_command.rb +57 -24
  59. data/lib/morpheus/cli/users.rb +210 -186
  60. data/lib/morpheus/cli/version.rb +1 -1
  61. data/lib/morpheus/cli/whitelabel_settings_command.rb +29 -5
  62. data/lib/morpheus/cli/whoami.rb +113 -6
  63. data/lib/morpheus/cli/workflows.rb +1 -1
  64. data/lib/morpheus/ext/hash.rb +21 -0
  65. data/lib/morpheus/terminal.rb +1 -0
  66. metadata +12 -3
  67. data/lib/morpheus/cli/auth_command.rb +0 -105
@@ -609,15 +609,6 @@ class Morpheus::Cli::Clusters
609
609
  option_type_list = ((controller_type['optionTypes'].reject { |type| !type['enabled'] || type['fieldComponent'] } rescue []) + layout['optionTypes'] +
610
610
  (cluster_type['optionTypes'].reject { |type| !type['enabled'] || !type['creatable'] || type['fieldComponent'] } rescue [])).sort { |type| type['displayOrder'] }
611
611
 
612
- # remove volume options if volumes were configured
613
- if !server_payload['volumes'].empty?
614
- option_type_list = reject_volume_option_types(option_type_list)
615
- end
616
- # remove networkId option if networks were configured above
617
- if !server_payload['networkInterfaces'].empty?
618
- option_type_list = reject_networking_option_types(option_type_list)
619
- end
620
-
621
612
  server_payload.deep_merge!(Morpheus::Cli::OptionTypes.prompt(option_type_list, options[:options], @api_client, {zoneId: cloud['id'], siteId: group['id'], layoutId: layout['id']}))
622
613
 
623
614
  # Worker count
@@ -1197,15 +1188,6 @@ class Morpheus::Cli::Clusters
1197
1188
  (type['fieldContext'] == 'instance.networkDomain' && type['fieldName'] == 'id')
1198
1189
  } rescue [])
1199
1190
 
1200
- # remove volume options if volumes were configured
1201
- if !server_payload['volumes'].empty?
1202
- option_type_list = reject_volume_option_types(option_type_list)
1203
- end
1204
- # remove networkId option if networks were configured above
1205
- if !server_payload['networkInterfaces'].empty?
1206
- option_type_list = reject_networking_option_types(option_type_list)
1207
- end
1208
-
1209
1191
  server_payload.deep_merge!(Morpheus::Cli::OptionTypes.prompt(option_type_list, options[:options], @api_client, {zoneId: cloud['id'], siteId: group['id'], layoutId: layout['id']}))
1210
1192
 
1211
1193
  # Create User
@@ -363,7 +363,7 @@ EOT
363
363
  else
364
364
  out << "\texit: 0 "
365
365
  end
366
- 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"
367
367
  out << "\t #{total_time_str.ljust(9, ' ')}"
368
368
  else
369
369
  benchmark_records = []
@@ -384,8 +384,8 @@ EOT
384
384
  # all_durations = benchmark_records.collect {|benchmark_record| benchmark_record.duration }
385
385
  # total_duration = all_durations.inject(0.0) {|acc, i| acc + i }
386
386
  # avg_duration = total_duration / all_durations.size
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"
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"
389
389
 
390
390
  all_durations = []
391
391
  stats = {total: 0, avg: nil, min: nil, max: nil}
@@ -406,10 +406,10 @@ EOT
406
406
  stats[:avg] = stats[:total].to_f / all_durations.size
407
407
  end
408
408
 
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" : ""
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" : ""
413
413
 
414
414
  out = ""
415
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 http://bertramdev.github.io/morpheus-apidoc/
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] || 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 wallet['refresh_token'].nil?
269
- print_red_alert yellow,"No refresh token found for #{display_appliance(@appliance_name, @appliance_url)}",reset,"\n"
270
- return nil
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(wallet['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(wallet['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