conan_deploy 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,494 @@
1
+ require 'rest_client'
2
+ require 'rexml/document'
3
+ require 'properties-ruby'
4
+ require 'json'
5
+ require 'securerandom'
6
+
7
+ require 'conan/output'
8
+ require 'conan/repository'
9
+ require 'conan/stackato'
10
+ require 'conan/newrelic'
11
+
12
+ module ManifestBuilder
13
+ def self.build(options, pipeline_id, env_id, artifact_repo=nil, &block)
14
+ manifest_dir = options[:directory]
15
+ output_type = options[:format]
16
+
17
+
18
+ artifact_repo ||= DefaultArtifactRepository.new
19
+
20
+ # this is a feature toggle to allow the current property file based impl to be migrated to the stackato output impl
21
+ if (output_type == :stackato)
22
+ outthingy = StackatoOutThingy.new(manifest_dir)
23
+ else
24
+ outthingy = PropertiesFileOutThingy.new(manifest_dir)
25
+ end
26
+
27
+ manifest = Manifest.new(options, artifact_repo, outthingy)
28
+ manifest.instance_eval(&block)
29
+ manifest.select(pipeline_id, env_id)
30
+ manifest
31
+ end
32
+ end
33
+
34
+ class Manifest
35
+
36
+ def initialize(options, artifact_repo, output)
37
+ @pipelines = {}
38
+ @environments = {}
39
+ @options = options
40
+ @artifact_repo = artifact_repo
41
+ @output = output
42
+ end
43
+
44
+ # select a pipeline and environment to do operations on
45
+ def select(pipeline_id, env_id)
46
+ env = @environments[env_id]
47
+ raise ArgumentError.new "Invalid environment id: '#{env_id}'. Valid options are #{@environments.keys.join(", ")}" if env.nil?
48
+ @current_environment = env
49
+ pl = @pipelines[pipeline_id]
50
+ raise ArgumentError.new "Invalid pipeline id: '#{pipeline_id}'. Valid options are #{@pipelines.keys.join(", ")}" if pl.nil?
51
+ @current_pipeline = pl
52
+ pl.load!(env, @options[:'deploy-shipcloud'])
53
+ end
54
+
55
+ def pipeline(pipeline_id, &block)
56
+ pl = Pipeline.new(pipeline_id, @artifact_repo, @output)
57
+ pl.instance_eval(&block)
58
+ @pipelines[pipeline_id] = pl
59
+ pl
60
+ end
61
+
62
+ def environment(env_id, &block)
63
+ e = Environment.new(env_id)
64
+ e.instance_eval(&block)
65
+ @environments[env_id] = e
66
+ e
67
+ end
68
+
69
+ def appVersion(pipeline_id, app_id)
70
+ @pipelines[pipeline_id].appVersion(app_id)
71
+ end
72
+
73
+ def provision
74
+ validateThatEnvironmentIsSelected
75
+ # TODO banners
76
+ puts "Update #{@current_environment.id} manifest files for #{@current_pipeline.id} pipeline"
77
+ @current_pipeline.update(@current_environment, @environments[@current_environment.upstream_env])
78
+ end
79
+
80
+ def configure
81
+ validateThatEnvironmentIsSelected
82
+ puts "Configure #{@current_environment.id} manifest files for #{@current_pipeline.id} pipeline"
83
+ @current_pipeline.configure(@current_environment)
84
+ end
85
+
86
+ def bg_configure
87
+ validateThatEnvironmentIsSelected
88
+ puts "Blue/green configure #{@current_environment.id} manifest files for #{@current_pipeline.id} pipeline"
89
+ @current_pipeline.configure(@current_environment, true)
90
+ end
91
+
92
+ def paas
93
+ paas_user = @options[:'paas-user'] || ENV['PAAS_USER']
94
+ paas_pwd = @options[:'paas-password'] || ENV['PAAS_PASSWORD']
95
+ dry_run = @options[:'dry-run'] || false
96
+ trace = @options[:'verbose'] || false
97
+
98
+ Stackato.new(paas_user, paas_pwd, trace, dry_run)
99
+ end
100
+
101
+ def deploy
102
+ validateThatEnvironmentIsSelected
103
+ puts "Deploy #{@current_environment.id} for #{@current_pipeline.id} pipeline"
104
+
105
+ nr_api_key = @options[:'new-relic-api-key'] || ENV['NEWRELIC_API_KEY']
106
+ force = @options[:'force-deploy'] || false
107
+
108
+ @current_pipeline.deploy(@current_environment, paas, force) { |app_name|
109
+ if (nr_api_key)
110
+ puts 'Reporting Deployment to New Relic'
111
+ job = @options[:'job-url'] || 'nexus-app-manifest'
112
+ NewRelic.alertDeployment(nr_api_key, app_name, "Deployed by #{job}")
113
+ else
114
+ puts "WARNING: Skipping New Relic alert. No API defined"
115
+ end
116
+ }
117
+ end
118
+
119
+ def bg_deploy
120
+ validateThatEnvironmentIsSelected
121
+ puts "Blue/green deploy #{@current_environment.id} for #{@current_pipeline.id} pipeline"
122
+
123
+ force = @options[:'force-deploy'] || false
124
+
125
+ @current_pipeline.bg_deploy(@current_environment, paas, force)
126
+ end
127
+
128
+ def bg_switch
129
+ validateThatEnvironmentIsSelected
130
+ puts "Blue/green switch #{@current_environment.id} for #{@current_pipeline.id} pipeline"
131
+
132
+ @current_pipeline.bg_switch(@current_environment, paas)
133
+ end
134
+
135
+ def bg_clean
136
+ validateThatEnvironmentIsSelected
137
+ puts "Blue/green clean #{@current_environment.id} for #{@current_pipeline.id} pipeline"
138
+
139
+ @current_pipeline.bg_clean(@current_environment, paas)
140
+ end
141
+
142
+ def validateThatEnvironmentIsSelected
143
+ unless @current_environment && @current_pipeline
144
+ raise ScriptError, 'Environment and Pipeline must be selected'
145
+ end
146
+ end
147
+ end
148
+
149
+ class Pipeline
150
+ attr_accessor :id, :apps
151
+
152
+ def initialize(id, artifact_repo, output)
153
+ @id = id
154
+ @artifact_repo = artifact_repo
155
+ @output = output
156
+ @apps = {}
157
+ end
158
+
159
+ def app(app_id, project_name, platform_type)
160
+ @apps[app_id] = case platform_type
161
+ when :jvm
162
+ JvmApp.new(app_id, project_name, @artifact_repo)
163
+ when :rails_zip
164
+ RailsZipApp.new(app_id, project_name, @artifact_repo)
165
+ else
166
+ raise "unknown platform type: #{platform_type}"
167
+ end
168
+ end
169
+
170
+ def appVersion(app_id)
171
+ @apps[app_id].version
172
+ end
173
+
174
+ def load!(environment, deploy_shipcloud)
175
+ eachAppDeployment(environment) { |app, deploy|
176
+ # load the persisted meta-data
177
+ @output.loadAppMetadataFromDeploymentIfExists(app, deploy)
178
+ }
179
+ @deploy_shipcloud = deploy_shipcloud
180
+ end
181
+
182
+ def update(environment, from_upstream_env)
183
+ @apps.values.each { |app|
184
+ puts ''
185
+ # promote versions from an upstream deploy
186
+ if (from_upstream_env)
187
+ # TODO: this needs improving
188
+ puts "Promote #{app.id} from #{from_upstream_env.id} to #{environment.id}"
189
+ upstream_deploy = from_upstream_env.deployments.select { |d| d.app_ids.select {|x| x == app.id }.size > 0 }.first
190
+ @output.loadAppMetadataFromDeployment(app, upstream_deploy)
191
+ else
192
+ puts "Find latest #{app.artifact_id}"
193
+ # lookup most recent from repo
194
+ app.findLatestVersion()
195
+ end
196
+ @output.clean(app, environment)
197
+ # download artifacts
198
+ @output.provision(app)
199
+ }
200
+
201
+ # write out deployment artifact meta-data
202
+ eachAppDeployment(environment) { |app, deploy| @output.writeArtifactMetadata(app, deploy) }
203
+ end
204
+
205
+ def configure(environment, bg=false)
206
+ eachAppDeployment(environment) { |app, deploy| @output.writeConfiguration(app, deploy, bg) }
207
+ end
208
+
209
+ def deploy(environment, paas, force=false)
210
+ eachAppDeployment(environment) { |app, deploy|
211
+ work_dir = @output.workingDir(app)
212
+ if (force)
213
+ paas.deploy(work_dir, app, deploy, true)
214
+ else
215
+ paas.deploy(work_dir, app, deploy) unless app.isDeployedAt(deploy.manifest_url(app.id))
216
+ end
217
+ }
218
+ end
219
+
220
+ def bg_deploy(environment, paas, force=false)
221
+ eachAppDeployment(environment) { |app, deploy|
222
+ if (force or !app.isDeployedAt(deploy.manifest_url(app.id)))
223
+ paas.bg_deploy(@output.workingDir(app), app, deploy)
224
+ end
225
+ }
226
+ end
227
+
228
+ def bg_switch(environment, paas)
229
+ eachAppDeployment(environment) { |app, deploy| paas.bg_switch(app, deploy) }
230
+ end
231
+
232
+ def bg_clean(environment, paas)
233
+ eachAppDeployment(environment) { |app, deploy| paas.bg_clean(app, deploy) }
234
+ end
235
+
236
+ def eachAppDeployment(environment)
237
+ selected_deployments = environment.deployments.select{ |d| @deploy_shipcloud.nil? || d.shipcloud == @deploy_shipcloud }
238
+ puts "WARNING no deploys selected: #{@deploy_shipcloud}" if selected_deployments.empty?
239
+ selected_deployments.each { |d|
240
+ d.app_ids.each { |a|
241
+ app = @apps[a]
242
+ yield app, d if app
243
+ }
244
+ }
245
+ end
246
+ end
247
+
248
+ class Application
249
+
250
+ attr_accessor :id, :platform_type, :group_id, :artifact_id, :version, :extension, :sha1, :artifact_meta_data
251
+
252
+ def initialize(id, project_name, platform_type)
253
+ @id = id
254
+ @platform_type = platform_type
255
+ mvn_id = project_name.split(':')
256
+ @group_id = mvn_id[0]
257
+ @artifact_id = mvn_id[1]
258
+ end
259
+
260
+ def findLatestVersion
261
+ extension = case platform_type
262
+ when :jvm
263
+ "jar"
264
+ when :rails_zip
265
+ "tar.gz"
266
+ else
267
+ raise "Unsupported platform type: #{platform_type}"
268
+ end
269
+ readArtifactMetadata(@artifact_repo.resolveArtifact(group_id, artifact_id, extension))
270
+ puts "- Found latest #{@id} artifact\n"+
271
+ " Artifact: #{self}\n" +
272
+ " Checksum: #{@sha1}"
273
+ end
274
+
275
+ def readArtifactMetadata(xml)
276
+ @artifact_meta_data = xml
277
+ begin
278
+ doc = REXML::Document.new(xml)
279
+ rescue Exception => e
280
+ puts "Failed to parse meta-data: #{e}"
281
+ puts "--------------------------------"
282
+ puts xml
283
+ puts "--------------------------------"
284
+ raise "Unreadable artifact meta-data for #{self}"
285
+ end
286
+
287
+ meta_data = doc.elements['/artifact-resolution/data']
288
+ @version = meta_data.elements['version'].text
289
+ @sha1 = meta_data.elements['sha1'].text
290
+ @extension = meta_data.elements['extension'].text
291
+ end
292
+
293
+ def download(location)
294
+ puts "- Provision #{group_id}:#{artifact_id}:#{extension}:#{version}"
295
+ @artifact_repo.downloadArtifact(location, group_id, artifact_id, extension, version, sha1)
296
+ end
297
+
298
+ def isDeployedAt(url)
299
+ # only deploy if an older version is found, or no app found
300
+ res = false
301
+ begin
302
+ response = RestClient::Request.new(
303
+ :method => :get,
304
+ :url => url,
305
+ :headers => {
306
+ 'accept' => :json,
307
+ 'content_type' => :json
308
+ },
309
+ :timeout => 5,
310
+ :open_timeout => 5
311
+ ).execute
312
+ if (response.code == 200)
313
+ build_metadata = JSON.parse(response.to_str)
314
+ puts ''
315
+ puts "+- Currently at #{url}:"
316
+ printM = ->(s) {
317
+ puts " | #{s}: #{build_metadata[s]}"
318
+ }
319
+ printM.call 'Implementation-Title'
320
+ printM.call 'Build-Version'
321
+ printM.call 'Build-Url'
322
+ printM.call 'Git-Commit'
323
+ current_ver = build_metadata["Build-Version"]
324
+ end
325
+ #TODO make sure the artifact id matches too, currently finding "Implementation-Title": "apollo" in build metadata
326
+ if (compareVersion(@version, current_ver))
327
+ puts "#{@artifact_id} #{@version} is newer than version found at #{url}: #{current_ver}"
328
+ else
329
+ puts "#{@artifact_id} #{@version} found at #{url}. (skipping deployment)"
330
+ res = true
331
+ end
332
+ rescue => e
333
+ puts "#{@artifact_id} not found at #{url}: #{e}"
334
+ end
335
+ res
336
+ end
337
+
338
+ def compareVersion(target_version, deployed_version)
339
+ target = Gem::Version.new(target_version)
340
+ begin
341
+ found = Gem::Version.new(deployed_version)
342
+ target > found
343
+ rescue => e
344
+ puts "Error parsing version number: #{e}"
345
+ false
346
+ end
347
+ end
348
+
349
+ def to_s
350
+ "#{artifact_id}-#{version}.#{extension}"
351
+ end
352
+ end
353
+
354
+ class JvmApp < Application
355
+ attr_accessor :sha1, :artifact_repo
356
+
357
+ def initialize(id, project_name, artifact_repo)
358
+ super(id, project_name, :jvm)
359
+ @sha1 = nil
360
+ @artifact_repo = artifact_repo
361
+ end
362
+
363
+ def download(location)
364
+ super
365
+ puts "- Provision NewRelic Agent jar"
366
+ @artifact_repo.downloadNewRelicAgent(File.join(location, @artifact_id), '3.2.3', 'c07cd82e033af9628cd7f90df874daee7000e471')
367
+ end
368
+ end
369
+
370
+ class RailsZipApp < Application
371
+ attr_accessor :sha1, :artifact_repo
372
+
373
+ def initialize(id, project_name, artifact_repo)
374
+ super(id, project_name, :rails_zip)
375
+ @sha1 = nil
376
+ @artifact_repo = artifact_repo
377
+ end
378
+ end
379
+
380
+ class HasOptions
381
+ attr_accessor :options
382
+
383
+ def initialize(options)
384
+ @options = options
385
+ end
386
+
387
+ def option(key, value)
388
+ if @options[key].nil?
389
+ @options[key] = [value]
390
+ else
391
+ @options[key] << value
392
+ end
393
+ end
394
+ end
395
+
396
+ class Environment #< HasOptions
397
+ attr_accessor :id, :upstream_env, :deployments
398
+
399
+ def initialize(env_id)
400
+ #super({})
401
+ @id = env_id
402
+ @deployments = []
403
+ @org_holder = nil
404
+ end
405
+
406
+ def promotes_from(env_id)
407
+ @upstream_env = env_id
408
+ end
409
+
410
+ def org(org_name, &block)
411
+ @org_holder = org_name
412
+ self.instance_eval(&block)
413
+ end
414
+
415
+ def deploy(ship, &block)
416
+ d = Deployment.new(self, @org_holder, ship)
417
+ d.instance_eval(&block)
418
+ @deployments << d
419
+ end
420
+ end
421
+
422
+ class Deployment < HasOptions
423
+
424
+ @@paas_domain = 'mtnsatcloud.com'
425
+
426
+ attr_accessor :environment, :org, :ship, :shipcloud, :app_ids, :facility_id
427
+
428
+ def initialize(environment, org, ship)
429
+ # inherit options from the environment
430
+ #super(environment.options) # TODO: copy?!
431
+ super({})
432
+ @environment = environment
433
+ @org = org
434
+ @ship = ship
435
+ @shipcloud = "#{org}-#{ship}"
436
+ @app_ids = []
437
+ @facility_id = nil
438
+ @enabled = true
439
+ @randomid = SecureRandom.hex(3)
440
+ end
441
+
442
+ def apps(*app_ids)
443
+ @app_ids = app_ids
444
+ end
445
+
446
+ def facility(facility_id)
447
+ @facility_id = facility_id
448
+ end
449
+
450
+ def enabled(b)
451
+ @enabled = b
452
+ end
453
+
454
+ def enabled?
455
+ @enabled
456
+ end
457
+
458
+ def name(app_id)
459
+ "#{app_id}-#{@environment.id}-#{@ship}"
460
+ end
461
+
462
+ def dns_name(app_id)
463
+ "#{@environment.id}.#{app_id}.#{@ship}.#{@org}.#{@@paas_domain}"
464
+ end
465
+
466
+ def agnostic_dns_name(app_id)
467
+ "#{@environment.id}.#{app_id}.#{@@paas_domain}"
468
+ end
469
+
470
+ def unique_name(app_id)
471
+ "#{name(app_id)}-#{@randomid}"
472
+ end
473
+
474
+ def active_urls(app_id)
475
+ [ dns_name(app_id), agnostic_dns_name(app_id) ]
476
+ end
477
+
478
+ def inactive_urls(app_id)
479
+ ["inactive.#{dns_name(app_id)}"]
480
+ end
481
+
482
+ def manifest_url(app_id)
483
+ "http://#{dns_name(app_id)}/status/manifest"
484
+ end
485
+
486
+ def paas_target
487
+ "https://api.paas.#{@ship}.#{@org}.#{@@paas_domain}"
488
+ end
489
+
490
+ def to_s
491
+ "#{org}-#{ship}"
492
+ end
493
+ end
494
+
@@ -0,0 +1,16 @@
1
+ require 'rest_client'
2
+
3
+ module NewRelic
4
+ def self.alertDeployment(api_key, app_name, description)
5
+ response = RestClient.post(
6
+ 'https://api.newrelic.com/deployments.xml',
7
+ :params => {
8
+ :'deployment[app_name]' => app_name,
9
+ :'deployment[description]' => description
10
+ },
11
+ :headers => { 'x-api-key' => api_key }
12
+ )
13
+ puts response
14
+ end
15
+ end
16
+
@@ -0,0 +1,31 @@
1
+ require 'conan/version'
2
+
3
+ module Conan
4
+ class Options
5
+ def initialize(options = {})
6
+ @options = defaults.merge(options)
7
+ end
8
+
9
+ def []=(k, v)
10
+ @options[k] = v
11
+ end
12
+
13
+ def [](k)
14
+ @options[k]
15
+ end
16
+
17
+ def to_s
18
+ @options.to_s
19
+ end
20
+
21
+ private
22
+ def defaults
23
+ {
24
+ :version => Conan::VERSION,
25
+ :directory => Dir.pwd,
26
+ :format => :stackato,
27
+ :action => :provision
28
+ }
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,169 @@
1
+ require 'conan/templates'
2
+
3
+ class OutThingy
4
+ attr_accessor :output_dir, :time
5
+
6
+ def initialize(output_dir)
7
+ @output_dir = output_dir
8
+ @time = Time.new
9
+ end
10
+
11
+ def outputToFile(file, &block)
12
+ o = File.join(@output_dir, file)
13
+ puts "Write: #{o}"
14
+ FileUtils.mkdir_p File.dirname(o)
15
+ File.open(o, 'w') { |f| yield f }
16
+ end
17
+
18
+ def loadAppMetadataFromDeploymentIfExists(app, deploy)
19
+ loadAppMetadataFromDeployment(app, deploy, true)
20
+ end
21
+ end
22
+
23
+ class StackatoOutThingy < OutThingy
24
+
25
+ attr_accessor :environments_dir, :apps_dir
26
+
27
+ @@stackato_file_name = "stackato.yml"
28
+ @@metadata_file_name = "metadata.xml"
29
+ @environments_dir = nil
30
+ @apps_dir = nil
31
+
32
+ def initialize(output_dir)
33
+ super(output_dir)
34
+ workdir = File.join(output_dir,'tmp')
35
+ @environments_dir = File.join(output_dir,'environments')
36
+ @apps_dir = File.join(workdir,'apps')
37
+ FileUtils.mkdir_p environments_dir
38
+ FileUtils.mkdir_p apps_dir
39
+ end
40
+
41
+ def clean(app, environment)
42
+ # TODO: cleanup
43
+ end
44
+
45
+ def provision(app)
46
+ app.download(@apps_dir)
47
+ end
48
+
49
+ def filePath(app, deploy)
50
+ "#{deploy.environment.id}/#{deploy.shipcloud}/#{app.id}"
51
+ end
52
+
53
+ def workingDir(app)
54
+ File.join(apps_dir, app.artifact_id)
55
+ end
56
+
57
+ # TODO this needs a refactor, it's knoted up with App
58
+ def loadAppMetadataFromDeployment(app, deploy, fail_silent=false)
59
+ p = filePath(app, deploy)
60
+ path = File.join(@environments_dir, p)
61
+ metadata_file = File.join(path, @@metadata_file_name)
62
+
63
+ if (File.exists? path)
64
+ File.open(metadata_file, 'r') { |f| app.readArtifactMetadata(f.read) }
65
+ else
66
+ raise "Build meta-data was not found: #{path}" unless fail_silent
67
+ end
68
+ end
69
+
70
+ def writeArtifactMetadata(app, deploy)
71
+ if (deploy.enabled?)
72
+ path = filePath(app, deploy)
73
+ outputToFile("environments/#{path}/#{@@metadata_file_name}") { |f|
74
+ f.write(app.artifact_meta_data)
75
+ }
76
+ end
77
+ end
78
+
79
+ def writeConfiguration(app, deploy, bg=false)
80
+ if (deploy.enabled?)
81
+ target_dir = workingDir(app)
82
+ templates_dir = File.join(target_dir, "deploy-templates")
83
+ n_changes = Templates.evaluate templates_dir, target_dir, {
84
+ :app => app,
85
+ :deploy => deploy,
86
+
87
+ # short-cuts
88
+ :app_id => app.id,
89
+ :deploy_base_name => deploy.name(app.id),
90
+ :deploy_name => bg ? deploy.unique_name(app.id) : deploy.name(app.id),
91
+ :deploy_urls => bg ? deploy.inactive_urls(app.id) : deploy.active_urls(app.id),
92
+ :env => deploy.environment.id,
93
+ :org => deploy.org,
94
+ :ship => deploy.ship,
95
+ :infra => deploy.shipcloud, # TODO: remove infra key, this is just to avoid breaking existing templates
96
+ :shipcloud => deploy.shipcloud,
97
+ :facility => deploy.facility_id,
98
+ :options => deploy.options
99
+ }
100
+ end
101
+ #TODO: can this be used to provide idempotency for config-only deploymnent?
102
+ puts "#{n_changes} files changed"
103
+ end
104
+ end
105
+
106
+ class PropertiesFileOutThingy < OutThingy
107
+
108
+ def clean(app, environment)
109
+ # cleanup current
110
+ FileUtils.rm Dir.glob("#{@output_dir}/#{app.id}-deploy-#{environment.id}-*.properties")
111
+ end
112
+
113
+ def fileName(app, deploy)
114
+ "#{app.id}-deploy-#{deploy.environment.id}-#{deploy.shipcloud}.properties"
115
+ end
116
+
117
+ def loadAppMetadataFromDeployment(app, deploy, fail_silent=false)
118
+ path = File.join(@output_dir, fileName(app, deploy))
119
+ if (File.exists? path)
120
+ props = Utils::Properties.load_from_file(path, true)
121
+ app.version = props.get(:DEPLOY_VERSION) # TODO: preserve SHA1
122
+ else
123
+ raise "File not found: #{path}" unless fail_silent
124
+ end
125
+ end
126
+
127
+ def writeArtifactMetadata(app, deploy)
128
+ file_name = fileName(app, deploy)
129
+ out_file = File.join(@output_dir, file_name)
130
+ if (!deploy.enabled?)
131
+ if (File.exists? out_file)
132
+ File.delete(out_file)
133
+ end
134
+ out_file = File.join(@output_dir, "DISABLED-#{file_name}")
135
+ end
136
+ puts "Write: #{out_file}"
137
+ File.open(out_file, 'w') { |f|
138
+ # TODO: would like @time in the manifest as audit field, but not sure it's such a good idea yet
139
+ # f << "\# #{file_name}\n\# #{@time}\n"
140
+ f << "\# #{file_name}\n"
141
+ f << "DEPLOY_ENV=#{deploy.environment.id}\n"
142
+ f << "DEPLOY_INFRA=#{deploy.shipcloud}\n"
143
+ if (deploy.facility_id)
144
+ f << "FACILITY=facility-#{deploy.facility_id}\n"
145
+ end
146
+ unless (deploy.options.empty?)
147
+ options = []
148
+ deploy.options.each do |k, v|
149
+ options << k + '|' + v.join(',')
150
+ end
151
+ p options.join(';')
152
+ f << "OPTIONS=#{options.join(';')}\n"
153
+ end
154
+ f << "APP=#{app.id}\n"
155
+ f << "DEPLOY_SHA1=#{app.sha1}\n"
156
+ f << "DEPLOY_VERSION=#{app.version}\n"
157
+ f << "TYPE=#{app.platform_type}\n"
158
+ f << "\n"
159
+ }
160
+ end
161
+
162
+ def provision(app)
163
+ #noop
164
+ end
165
+
166
+ def writeConfiguration(app, deploy)
167
+ # noop
168
+ end
169
+ end