conan_deploy 0.0.9 → 0.0.12

Sign up to get free protection for your applications and to get access to all the features.
data/lib/conan/output.rb CHANGED
@@ -10,15 +10,15 @@ class OutThingy
10
10
  end
11
11
 
12
12
  def outputToFile(file, &block)
13
- o = File.join(@output_dir, file)
14
- puts "Write: #{o}"
13
+ o = File.join(@output_dir, file)
14
+ puts "Write: #{o}"
15
15
  FileUtils.mkdir_p File.dirname(o)
16
16
  File.open(o, 'w') { |f| yield f }
17
17
  end
18
18
 
19
19
  def loadAppMetadataFromDeploymentIfExists(app, deploy)
20
20
  loadAppMetadataFromDeployment(app, deploy, true)
21
- end
21
+ end
22
22
  end
23
23
 
24
24
  class StackatoOutThingy < OutThingy
@@ -39,15 +39,15 @@ class StackatoOutThingy < OutThingy
39
39
  FileUtils.mkdir_p apps_dir
40
40
  end
41
41
 
42
- def clean(app, environment)
42
+ def clean(app, environment)
43
43
  # TODO: cleanup
44
44
  end
45
45
 
46
46
  def provision(app)
47
- app.download(@apps_dir)
47
+ app.download(@apps_dir)
48
48
  end
49
49
 
50
- def filePath(app, deploy)
50
+ def filePath(app, deploy)
51
51
  "#{deploy.environment.id}/#{deploy.shipcloud}/#{app.id}"
52
52
  end
53
53
 
@@ -56,9 +56,9 @@ class StackatoOutThingy < OutThingy
56
56
  end
57
57
 
58
58
  # TODO this needs a refactor, it's knoted up with App
59
- def loadAppMetadataFromDeployment(app, deploy, fail_silent=false)
59
+ def loadAppMetadataFromDeployment(app, deploy, fail_silent=false)
60
60
  p = filePath(app, deploy)
61
- path = File.join(@environments_dir, p)
61
+ path = File.join(@environments_dir, p)
62
62
  metadata_file = File.join(path, @@metadata_file_name)
63
63
 
64
64
  if (File.exists? path)
@@ -66,7 +66,7 @@ class StackatoOutThingy < OutThingy
66
66
  else
67
67
  raise "Build meta-data was not found: #{path}" unless fail_silent
68
68
  end
69
- end
69
+ end
70
70
 
71
71
  def writeArtifactMetadata(app, deploy)
72
72
  if (deploy.enabled?)
@@ -76,15 +76,15 @@ class StackatoOutThingy < OutThingy
76
76
  }
77
77
  end
78
78
  end
79
-
79
+
80
80
  def writeConfiguration(app, deploy, bg=false)
81
- if (deploy.enabled?)
81
+ if (deploy.enabled?)
82
82
  target_dir = workingDir(app)
83
83
  templates_dir = File.join(target_dir, "deploy-templates")
84
84
 
85
- daphne_tokens = [ "#{app.id}", "#{deploy.environment.id}" ]
85
+ daphne_tokens = [ "#{app.id}", "#{deploy.environment.id}" ]
86
86
  daphne_tokens = daphne_tokens << "facility-#{deploy.facility_id}" unless deploy.facility_id.nil?
87
-
87
+
88
88
  n_changes = Templates.evaluate templates_dir, target_dir, {
89
89
  :app => app,
90
90
  :deploy => deploy,
@@ -95,10 +95,10 @@ class StackatoOutThingy < OutThingy
95
95
  :oauth_secret => DaphneUtil.generate_secret(*daphne_tokens),
96
96
  :api_key => DaphneUtil.generate_api_key(*daphne_tokens),
97
97
 
98
- # short-cuts
98
+ # short-cuts
99
99
  :app_id => app.id,
100
100
  :deploy_base_name => deploy.name(app),
101
- :deploy_name => bg ? deploy.unique_name(app) : deploy.name(app),
101
+ :deploy_name => bg ? app.unique_name : deploy.name(app),
102
102
  :deploy_urls => bg ? deploy.inactive_urls(app) : deploy.active_urls(app),
103
103
  :env => deploy.environment.id,
104
104
  :org => deploy.org,
@@ -106,7 +106,7 @@ class StackatoOutThingy < OutThingy
106
106
  :infra => deploy.shipcloud, # TODO: remove infra key, this is just to avoid breaking existing templates
107
107
  :shipcloud => deploy.shipcloud,
108
108
  :facility => deploy.facility_id,
109
- :options => deploy.options
109
+ :options => deploy.options
110
110
  }
111
111
  end
112
112
  #TODO: can this be used to provide idempotency for config-only deploymnent?
@@ -116,19 +116,19 @@ end
116
116
 
117
117
  class PropertiesFileOutThingy < OutThingy
118
118
 
119
- def clean(app, environment)
119
+ def clean(app, environment)
120
120
  # cleanup current
121
- FileUtils.rm Dir.glob("#{@output_dir}/#{app.id}-deploy-#{environment.id}-*.properties")
121
+ FileUtils.rm Dir.glob("#{@output_dir}/#{app.id}-deploy-#{environment.id}-*.properties")
122
122
  end
123
123
 
124
- def fileName(app, deploy)
124
+ def fileName(app, deploy)
125
125
  "#{app.id}-deploy-#{deploy.environment.id}-#{deploy.shipcloud}.properties"
126
126
  end
127
127
 
128
128
  def loadAppMetadataFromDeployment(app, deploy, fail_silent=false)
129
129
  path = File.join(@output_dir, fileName(app, deploy))
130
130
  if (File.exists? path)
131
- props = Utils::Properties.load_from_file(path, true)
131
+ props = Utils::Properties.load_from_file(path, true)
132
132
  app.version = props.get(:DEPLOY_VERSION) # TODO: preserve SHA1
133
133
  else
134
134
  raise "File not found: #{path}" unless fail_silent
@@ -138,16 +138,16 @@ class PropertiesFileOutThingy < OutThingy
138
138
  def writeArtifactMetadata(app, deploy)
139
139
  file_name = fileName(app, deploy)
140
140
  out_file = File.join(@output_dir, file_name)
141
- if (!deploy.enabled?)
142
- if (File.exists? out_file)
141
+ if (!deploy.enabled?)
142
+ if (File.exists? out_file)
143
143
  File.delete(out_file)
144
144
  end
145
- out_file = File.join(@output_dir, "DISABLED-#{file_name}")
145
+ out_file = File.join(@output_dir, "DISABLED-#{file_name}")
146
146
  end
147
147
  puts "Write: #{out_file}"
148
148
  File.open(out_file, 'w') { |f|
149
149
  # TODO: would like @time in the manifest as audit field, but not sure it's such a good idea yet
150
- # f << "\# #{file_name}\n\# #{@time}\n"
150
+ # f << "\# #{file_name}\n\# #{@time}\n"
151
151
  f << "\# #{file_name}\n"
152
152
  f << "DEPLOY_ENV=#{deploy.environment.id}\n"
153
153
  f << "DEPLOY_INFRA=#{deploy.shipcloud}\n"
@@ -0,0 +1,130 @@
1
+ class Pipeline
2
+ include ApiHelper
3
+
4
+ attr_accessor :id, :apps
5
+
6
+ def initialize(id, artifact_repo, output, options)
7
+ @id = id
8
+ @artifact_repo = artifact_repo
9
+ @output = output
10
+ @apps = {}
11
+ @options = options
12
+ end
13
+
14
+ def app(app_id, project_name, platform_type, url_segment=nil)
15
+ if (@options[:'deploy-app-name'].nil?) || (@options[:'deploy-app-name'] == app_id.to_s)
16
+ puts "No app specified, or we matched the specified app: #{@options[:'deploy-app-name']}"
17
+ @apps[app_id] = case platform_type
18
+ when :jvm
19
+ JvmApp.new(app_id, project_name, @artifact_repo, @options, url_segment)
20
+ when :rails_zip
21
+ RailsZipApp.new(app_id, project_name, @artifact_repo, @options, url_segment)
22
+ else
23
+ raise "unknown platform type: #{platform_type}"
24
+ end
25
+ else
26
+ puts "App #{app_id} doesn't match specified app #{@options[:'deploy-app-name']}, skipping"
27
+ end
28
+ end
29
+
30
+ def appVersion(app_id)
31
+ @apps[app_id].version
32
+ end
33
+
34
+ def load!(environment, deploy_shipcloud)
35
+ eachAppDeployment(environment) { |app, deploy|
36
+ # load the persisted meta-data
37
+ @output.loadAppMetadataFromDeploymentIfExists(app, deploy)
38
+ }
39
+ @deploy_shipcloud = deploy_shipcloud
40
+ end
41
+
42
+ def update(environment, from_upstream_env)
43
+ @apps.values.each { |app|
44
+ puts ''
45
+ if !(@options[:'deploy-app-version'].nil?)
46
+ puts "Using version from options: #{@options[:'deploy-app-version']}"
47
+ app.findRequestedVersion(@options[:'deploy-app-version'])
48
+ elsif (from_upstream_env)
49
+ # promote versions from an upstream deploy
50
+ # TODO: this needs improving
51
+ puts "Promote #{app.id} from #{from_upstream_env.id} to #{environment.id}"
52
+ upstream_deploy = from_upstream_env.deployments.select { |d| d.app_ids.select {|x| x == app.id }.size > 0 }.first
53
+ @output.loadAppMetadataFromDeployment(app, upstream_deploy)
54
+ else
55
+ puts "Find latest #{app.artifact_id}"
56
+ # lookup most recent from repo
57
+ app.findRequestedVersion('LATEST')
58
+ end
59
+ @output.clean(app, environment)
60
+ # download artifacts
61
+ @output.provision(app)
62
+ }
63
+
64
+ # write out deployment artifact meta-data
65
+ eachAppDeployment(environment) { |app, deploy| @output.writeArtifactMetadata(app, deploy) }
66
+ end
67
+
68
+ def configure(environment, bg=false)
69
+ eachAppDeployment(environment) { |app, deploy| @output.writeConfiguration(app, deploy, bg) }
70
+ end
71
+
72
+ def deploy(environment, paas, force=false)
73
+ eachAppDeployment(environment) { |app, deploy|
74
+ work_dir = @output.workingDir(app)
75
+ if (force)
76
+ paas.deploy(work_dir, app, deploy, true)
77
+ else
78
+ paas.deploy(work_dir, app, deploy) unless app.isDeployedAt(deploy.manifest_url(app))
79
+ end
80
+ }
81
+ end
82
+
83
+ def bg_deploy(environment, paas, force=false)
84
+ apps = []
85
+ eachAppDeployment(environment) { |app, deploy|
86
+ if (force or !app.isDeployedAt(deploy.manifest_url(app)))
87
+ paas.bg_deploy(@output.workingDir(app), app, deploy)
88
+ apps << app
89
+ end
90
+ }
91
+ apps
92
+ end
93
+
94
+ def is_inactive_node_operational?(environment, paas)
95
+ eachAppDeployment(environment) { |app, deploy|
96
+ response = ApiHelper.smoke_test(deploy.inactive_smoke_test_url(app), 60)
97
+
98
+ if(response.code != 200)
99
+ puts "Smoke test failed for inactive (Blue) node. Here is the entire response: #{response.inspect}"
100
+ return false
101
+ else
102
+ return true
103
+ end
104
+ }
105
+ end
106
+
107
+ def bg_switch(environment, paas)
108
+ eachAppDeployment(environment) { |app, deploy| paas.bg_switch(app, deploy) }
109
+ end
110
+
111
+ def bg_clean(environment, paas)
112
+ eachAppDeployment(environment) { |app, deploy| paas.bg_clean(app, deploy) }
113
+ end
114
+
115
+ def eachAppDeployment(environment)
116
+ selected_deployments = environment.deployments.select{ |d| @deploy_shipcloud.nil? || d.shipcloud == @deploy_shipcloud }
117
+ puts "WARNING no deploys selected: #{@deploy_shipcloud}" if selected_deployments.empty?
118
+ selected_deployments.each do |d|
119
+ d.app_ids.each do |a|
120
+ unless @apps[a].nil?
121
+ app = @apps[a]
122
+ app.additional_mappings = d.additional_mappings
123
+ app.unique_name = d.unique_name(app)
124
+ app.smoke_test_path = d.smoke_test_path
125
+ yield app, d
126
+ end
127
+ end
128
+ end
129
+ end
130
+ end
@@ -0,0 +1,10 @@
1
+ require 'conan/application'
2
+ class RailsZipApp < Application
3
+ attr_accessor :sha1, :artifact_repo
4
+
5
+ def initialize(id, project_name, artifact_repo, options, url_segment=nil)
6
+ super(id, project_name, :rails_zip, options, url_segment)
7
+ @sha1 = nil
8
+ @artifact_repo = artifact_repo
9
+ end
10
+ end
@@ -3,13 +3,13 @@ require 'json'
3
3
 
4
4
  class Stackato
5
5
 
6
+ @@paas_token_file = File.join(Dir.tmpdir(), "token_#{Time.now.to_i}")
7
+
6
8
  def initialize(paas_user, paas_password, trace=false, dry_run=false)
7
9
  @paas_user = paas_user
8
10
  @paas_password = paas_password
9
11
  @doit = dry_run ? "echo " : ""
10
12
  @trace = trace ? "--trace" : ""
11
- random_str = (0...8).map { ('a'..'z').to_a[rand(26)] }.join
12
- @paas_token_file = File.join(Dir.tmpdir(), "token_#{random_str}")
13
13
  @paas_manifest = "stackato.yml"
14
14
  end
15
15
 
@@ -17,16 +17,67 @@ class Stackato
17
17
  # login only one time per target, and only one target at a time
18
18
  if (@session != paas_target)
19
19
  @session = paas_target
20
- @paas_cmd = "stackato #{@trace} --target #{paas_target} --token-file #{@paas_token_file}"
20
+ @paas_cmd = "stackato #{@trace} --target #{paas_target} --token-file #{@@paas_token_file}"
21
21
  unless @paas_user.nil?
22
22
  system( "#{@paas_cmd} login --user #{@paas_user} --password #{@paas_password}" ) or raise "Stackato login failed on #{paas_target}"
23
23
  end
24
24
  end
25
25
  end
26
26
 
27
- def deploy(work_dir, app, deployment, force=false)
28
- puts ''
29
- Dir.chdir(work_dir){
27
+ def self.static_login(options)
28
+ org = options[:'deploy-shipcloud'].split('-')[0]
29
+ infra = options[:'deploy-shipcloud'].split('-')[1]
30
+ `stackato --target https://api.paas.#{infra}.#{org}.mtnsatcloud.com --token-file #{@@paas_token_file}`
31
+ `stackato login --user #{options[:'paas-user']} --password #{options[:'paas-password']} --token-file #{@@paas_token_file}`
32
+ end
33
+
34
+ def self.unmap(app, domain)
35
+ puts "[#{app.unique_name}] Unmapping #{domain}"
36
+ `stackato unmap #{app.unique_name} #{domain} --token-file #{@@paas_token_file}`
37
+ end
38
+
39
+ def self.map(app, domain)
40
+ puts "[#{app.unique_name}] Mapping #{domain}"
41
+ `stackato map #{app.unique_name} #{domain} --token-file #{@@paas_token_file}`
42
+ end
43
+
44
+ def self.stop(app)
45
+ puts "[#{app.unique_name}] Stopping"
46
+ `stackato stop #{app.unique_name} --token-file #{@@paas_token_file}`
47
+ end
48
+
49
+ def self.delete(app)
50
+ puts "[#{app.unique_name}] Deleting"
51
+ `stackato delete #{app.unique_name} --token-file #{@@paas_token_file}`
52
+ end
53
+
54
+ def self.bg_switch(app)
55
+ app.active_domains.each{ |domain| Stackato.map(app, domain) }
56
+ app.inactive_domains.each{ |domain| Stackato.unmap(app, domain) }
57
+ app.old_versions.each{ |old_app| old_app.active_domains.each { |domain| Stackato.unmap(old_app, domain) } }
58
+ app.old_versions.each{ |old_app| old_app.inactive_domains.each { |domain| Stackato.map(old_app, domain) } }
59
+ end
60
+
61
+ def self.bg_clean(app)
62
+ app.old_versions.each { |old_app| Stackato.stop(old_app) }
63
+ app.old_versions.each { |old_app| Stackato.delete(old_app) }
64
+ end
65
+
66
+ def self.find_old_versions(newly_deployed_app)
67
+ old_apps = []
68
+ JSON.parse(`stackato apps --json --token-file #{@@paas_token_file}`).map do |app|
69
+ if /#{Regexp.escape(newly_deployed_app.stackato_base_name)}/ =~ app["name"] and app["name"] != newly_deployed_app.unique_name
70
+ old_app = newly_deployed_app.clone
71
+ old_app.unique_name = app["name"]
72
+ old_apps << old_app
73
+ end
74
+ end
75
+ old_apps
76
+ end
77
+
78
+ def deploy(work_dir, app, deployment, force=false)
79
+ puts ''
80
+ Dir.chdir(work_dir){
30
81
  login(deployment.paas_target)
31
82
 
32
83
  paas_app_name = deployment.name(app)
@@ -44,7 +95,7 @@ class Stackato
44
95
  stats_status = `#{@paas_cmd} stats #{paas_app_name} 2>&1 >/dev/null`
45
96
  puts stats_status
46
97
  raise ScriptError, "Stackato authorization failure. Provide user and password" if (stats_status =~ /Not Authorized/)
47
-
98
+
48
99
  # print out the stackato.yml for posterity
49
100
  puts '------------------------------------------------------------------------------'
50
101
 
@@ -82,19 +133,22 @@ class Stackato
82
133
  login(deployment.paas_target)
83
134
 
84
135
  app_info = application_info(app, deployment)
85
- raise "Please remove inactive app '#{app_info.inactive_app_name}' before proceeding." unless app_info.inactive_app_name.nil?
136
+ unless app_info.inactive_app_name.nil?
137
+ puts "inactive app [#{deployment.name(app)}]. Deleting it."
138
+ `stackato delete #{deployment.name(app)}`
139
+ end
86
140
 
87
- puts "Deploying inactive app #{deployment.name(app)}"
141
+ puts "Deploying inactive app #{deployment.name(app)}"
88
142
  c = "#{@doit} #{@paas_cmd} --manifest #{@paas_manifest} --no-prompt push"
89
143
  system(c) or raise "Stackato push failed: #{c}"
90
144
  }
91
- end
145
+ end
92
146
 
93
147
  def bg_switch(app, deployment)
94
148
  login(deployment.paas_target)
95
149
 
96
150
  app_info = application_info(app, deployment)
97
-
151
+
98
152
  if app_info.inactive_app_name.nil?
99
153
  puts "No inactive app to switch to."
100
154
  return
data/lib/conan/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Conan
2
- VERSION = "0.0.9"
3
- end
2
+ VERSION = "0.0.12"
3
+ end
metadata CHANGED
@@ -1,7 +1,8 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: conan_deploy
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.9
4
+ version: 0.0.12
5
+ prerelease:
5
6
  platform: ruby
6
7
  authors:
7
8
  - Mike Reardon
@@ -9,11 +10,12 @@ authors:
9
10
  autorequire:
10
11
  bindir: bin
11
12
  cert_chain: []
12
- date: 2014-05-19 00:00:00.000000000 Z
13
+ date: 2014-06-06 00:00:00.000000000 Z
13
14
  dependencies:
14
15
  - !ruby/object:Gem::Dependency
15
16
  name: daphne_util
16
17
  requirement: !ruby/object:Gem::Requirement
18
+ none: false
17
19
  requirements:
18
20
  - - '='
19
21
  - !ruby/object:Gem::Version
@@ -21,6 +23,7 @@ dependencies:
21
23
  type: :runtime
22
24
  prerelease: false
23
25
  version_requirements: !ruby/object:Gem::Requirement
26
+ none: false
24
27
  requirements:
25
28
  - - '='
26
29
  - !ruby/object:Gem::Version
@@ -32,39 +35,48 @@ executables:
32
35
  extensions: []
33
36
  extra_rdoc_files: []
34
37
  files:
35
- - README.md
36
38
  - bin/conan
39
+ - lib/conan/application.rb
37
40
  - lib/conan/application_helper.rb
38
41
  - lib/conan/deploy.rb
42
+ - lib/conan/deployment.rb
43
+ - lib/conan/environment.rb
44
+ - lib/conan/has_options.rb
45
+ - lib/conan/jvm_app.rb
46
+ - lib/conan/manifest.rb
39
47
  - lib/conan/manifest_builder.rb
40
48
  - lib/conan/newrelic.rb
41
49
  - lib/conan/options.rb
42
50
  - lib/conan/output.rb
51
+ - lib/conan/pipeline.rb
52
+ - lib/conan/rails_zip_app.rb
43
53
  - lib/conan/repository.rb
44
54
  - lib/conan/stackato.rb
45
55
  - lib/conan/templates.rb
46
56
  - lib/conan/version.rb
57
+ - README.md
47
58
  homepage: http://github.com/MTNSatelliteComm/conan/README.md
48
59
  licenses: []
49
- metadata: {}
50
60
  post_install_message:
51
61
  rdoc_options: []
52
62
  require_paths:
53
63
  - lib
54
64
  required_ruby_version: !ruby/object:Gem::Requirement
65
+ none: false
55
66
  requirements:
56
67
  - - ! '>='
57
68
  - !ruby/object:Gem::Version
58
69
  version: '0'
59
70
  required_rubygems_version: !ruby/object:Gem::Requirement
71
+ none: false
60
72
  requirements:
61
73
  - - ! '>='
62
74
  - !ruby/object:Gem::Version
63
75
  version: '0'
64
76
  requirements: []
65
77
  rubyforge_project:
66
- rubygems_version: 2.2.2
78
+ rubygems_version: 1.8.23
67
79
  signing_key:
68
- specification_version: 4
80
+ specification_version: 3
69
81
  summary: Conan da Deployer
70
82
  test_files: []