beanstalkify 0.0.3 → 0.0.4

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.
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- beanstalkify (0.0.3)
4
+ beanstalkify (0.0.4)
5
5
  aws-sdk
6
6
 
7
7
  GEM
data/README.md CHANGED
@@ -24,8 +24,8 @@ Should do the following
24
24
  - Connect to aws using the credentials in `credentials.yml`
25
25
  - Publish `app-version.zip` to s3
26
26
  - Ensure that a beanstalk application called 'app' exists, and add a version called 'version', linked to the archive in that s3 bucket
27
- - Ensure that the environment `env` exists (with optional settings overrides in `config.yml` - see below), running the specified stack.
28
- - Deploy the provided version of the application into `env`
27
+ - Ensure that the environment `app-env` exists (with optional settings overrides in `config.yml` - see below), running the specified stack.
28
+ - Deploy the provided version of the application into `app-env`
29
29
  - Report progress. When complete report the URL where the app can be hit (note: this will be the URL of the ELB).
30
30
 
31
31
  # Settings overrides
data/bin/beanstalkify CHANGED
@@ -3,6 +3,9 @@ require 'optparse'
3
3
  require 'yaml'
4
4
  Dir.glob(File.join(File.dirname(__FILE__), "../lib/beanstalkify", "*.rb")).each { |f| require f }
5
5
 
6
+ # Flush all logging immediately so that scripts invoking beanstalkify can choose to merge the info.
7
+ $stdout.sync = true
8
+
6
9
  options = {}
7
10
  OptionParser.new do |opts|
8
11
  opts.on("-k", "--keyfile [file]", "Load credentials from yaml file") do |v|
@@ -27,17 +30,18 @@ end.parse!
27
30
 
28
31
  required_params = [:credentials, :archive, :environment, :stack]
29
32
  unless (required_params - options.keys).empty?
30
- puts "Example usage: beanstalkify -k credentials.yml -a AppName-version.zip -e AppName-test -s '64bit Amazon Linux running Node.js' [-c config.yml] [-o info.yml]"
33
+ puts "Example usage: beanstalkify -k credentials.yml -a AppName-version.zip -e Test -s '64bit Amazon Linux running Node.js' [-c config.yml] [-o info.yml]"
31
34
  exit
32
35
  end
33
36
 
34
37
  Beanstalkify::Beanstalk.configure! options[:credentials]
35
38
 
36
39
  app = Beanstalkify::Application.new(options[:stack], options[:config] || [])
37
- deployment = Beanstalkify::Deploy.new(options[:archive])
38
- environment = Beanstalkify::Environment.new(options[:environment])
40
+ archive = Beanstalkify::Archive.new(options[:archive])
41
+ environment = Beanstalkify::Environment.new(archive, options[:environment])
39
42
 
40
- deployment_info = app.deploy! deployment, environment
43
+ deployment_info = app.deploy! archive, environment
41
44
 
42
45
  File.open(options[:outfile], 'w') { |f| f.puts deployment_info.to_yaml } if options[:outfile]
43
46
 
47
+ raise("Deployed environment is not healthy") unless environment.healthy?
@@ -11,24 +11,20 @@ module Beanstalkify
11
11
 
12
12
  # Deploy an archive to an environment.
13
13
  # If the environment doesn't exist, it will be created.
14
- def deploy!(deployment, env)
15
- if deployment.deployed?
16
- puts "#{deployment.archive.version} is already uploaded."
17
- else
18
- deployment.upload!
19
- deployment.wait!
20
- end
14
+ def deploy!(archive, env)
15
+ archive.upload(Beanstalk.api)
16
+
21
17
  if env.status.empty?
22
- puts "Creating stack '#{@stack}' for #{deployment.archive.name}-#{deployment.archive.version}..."
23
- env.create!(deployment.archive, @stack, @config)
18
+ puts "Creating stack '#{@stack}' for #{archive.app_name}-#{archive.version}..."
19
+ env.create!(archive, @stack, @config)
24
20
  env.wait!("Launching")
25
21
  else
26
- puts "Deploying #{deployment.archive.version} to #{env.name}..."
27
- env.deploy!(deployment.archive, @config)
22
+ puts "Deploying #{archive.version} to #{env.name}..."
23
+ env.deploy!(archive, @config)
28
24
  env.wait!("Updating")
29
25
  end
30
26
  puts "Done. Visit http://#{env.url} in your browser."
31
- DeploymentInfo.new env, deployment.archive
27
+ DeploymentInfo.new env, archive
32
28
  end
33
29
  end
34
30
  end
@@ -1,23 +1,53 @@
1
+ require 'aws-sdk'
1
2
 
2
3
  module Beanstalkify
3
- class Archive
4
- attr_accessor :path
5
-
6
- def initialize(path)
7
- @path = path
8
- end
9
-
10
- def name
11
- f = filename
12
- f[0..f.rindex('-')-1]
13
- end
14
-
15
- def version
16
- File.basename(@path, '.*').split('-')[-1]
17
- end
4
+ class Archive
5
+ attr_reader :app_name, :version
6
+
7
+ def initialize(filename)
8
+ @filename = filename
9
+ @archive_name = File.basename(@filename)
10
+ @app_name, hyphen, @version = File.basename(filename, '.*').rpartition("-")
11
+ end
18
12
 
19
- def filename
20
- File.basename(@path)
21
- end
13
+ def upload(beanstalk_api, s3_client=AWS::S3.new.client)
14
+ if already_uploaded?(beanstalk_api)
15
+ return puts "#{version} is already uploaded."
16
+ end
17
+ bucket = beanstalk_api.create_storage_location.data[:s3_bucket]
18
+ upload_to_s3(s3_client, bucket)
19
+ make_application_version_available_to_beanstalk(beanstalk_api, bucket)
20
+ end
21
+
22
+ private
23
+
24
+ def upload_to_s3(s3_client, bucket)
25
+ puts "Uploading #{@archive_name} to bucket #{bucket}..."
26
+ s3_client.put_object(
27
+ bucket_name: bucket,
28
+ key: @archive_name,
29
+ data: File.open(@filename)
30
+ )
31
+ end
32
+
33
+ def make_application_version_available_to_beanstalk(beanstalk_api, bucket)
34
+ puts "Making version #{version} of #{app_name} available to Beanstalk..."
35
+ beanstalk_api.create_application_version(
36
+ application_name: app_name,
37
+ version_label: version,
38
+ source_bundle: {
39
+ s3_bucket: bucket,
40
+ s3_key: @archive_name
41
+ },
42
+ auto_create_application: true
43
+ )
44
+ end
45
+
46
+ def already_uploaded?(beanstalk_api)
47
+ beanstalk_api.describe_application_versions(
48
+ application_name: app_name,
49
+ version_labels: [version]
50
+ ).data[:application_versions].count > 0
22
51
  end
52
+ end
23
53
  end
@@ -6,7 +6,7 @@ module Beanstalkify
6
6
 
7
7
  def to_yaml
8
8
  {
9
- 'app_name' => @archive.name,
9
+ 'app_name' => @archive.app_name,
10
10
  'app_version' => @archive.version,
11
11
  'env_name' => @environment.name,
12
12
  'env_url' => @environment.url
@@ -4,8 +4,8 @@ module Beanstalkify
4
4
  class Environment
5
5
  attr_accessor :name
6
6
 
7
- def initialize(name)
8
- @name = name
7
+ def initialize(archive, name)
8
+ @name = [archive.app_name, name].join("-")
9
9
  @beanstalk = Beanstalk.api
10
10
  end
11
11
 
@@ -20,12 +20,12 @@ module Beanstalkify
20
20
  })
21
21
  end
22
22
 
23
- # Assuming the app has already been uploaded,
23
+ # Assuming the archive has already been uploaded,
24
24
  # create a new environment with the app deployed onto the provided stack.
25
- def create!(app, stack, settings=[])
25
+ def create!(archive, stack, settings=[])
26
26
  @beanstalk.create_environment({
27
- :application_name => app.name,
28
- :version_label => app.version,
27
+ :application_name => archive.app_name,
28
+ :version_label => archive.version,
29
29
  :environment_name => self.name,
30
30
  :solution_stack_name => stack,
31
31
  :option_settings => settings
@@ -33,28 +33,37 @@ module Beanstalkify
33
33
  end
34
34
 
35
35
  def status
36
- envs = @beanstalk.describe_environments({
37
- :environment_names => [self.name],
38
- :include_deleted => false
39
- }).data[:environments]
40
- e = envs.first
36
+ e = describe_environment
41
37
  e ? e[:status] : ""
42
38
  end
43
39
 
44
40
  def url
45
- envs = @beanstalk.describe_environments({
46
- :environment_names => [self.name]
47
- }).data[:environments]
48
- e = envs.first
49
- e ? e[:endpoint_url] : ""
41
+ e = describe_environment
42
+ e ? e[:cname] : ""
43
+ end
44
+
45
+ def healthy?
46
+ e = describe_environment
47
+ e ? e[:health] == 'Green' : false
50
48
  end
51
49
 
52
50
  # Wait for the status to change from `old_status` to something else
53
51
  def wait!(old_status)
52
+ puts "Waiting for #{self.name} to finish #{old_status.downcase}..."
54
53
  while self.status == old_status
55
- puts "#{self.name} is still #{old_status}..."
56
- sleep 20
54
+ print '.'
55
+ sleep 5
57
56
  end
57
+ puts
58
+ end
59
+
60
+ private
61
+
62
+ def describe_environment
63
+ @beanstalk.describe_environments({
64
+ :environment_names => [name],
65
+ :include_deleted => false
66
+ }).data[:environments].first
58
67
  end
59
68
  end
60
69
  end
@@ -1,3 +1,3 @@
1
1
  module Beanstalkify
2
- VERSION = "0.0.3"
2
+ VERSION = "0.0.4"
3
3
  end
data/test/archive_spec.rb CHANGED
@@ -1,26 +1,86 @@
1
-
2
1
  require './lib/beanstalkify/archive'
3
2
 
4
3
  describe Beanstalkify::Archive do
5
- archive = nil
4
+ ARCHIVE_FILENAME = '/path/to/my/archive/app-name-version.zip'
5
+
6
6
  before do
7
- archive = Beanstalkify::Archive.new '/path/to/my/archive/app-name-version.zip'
7
+ @archive = Beanstalkify::Archive.new ARCHIVE_FILENAME
8
8
  end
9
+
10
+ describe 'parsing the filename' do
11
+ it 'extracts the application name from the filename' do
12
+ @archive.app_name.should eq('app-name')
13
+ end
9
14
 
10
- it 'should store the path' do
11
- archive.path.should eq('/path/to/my/archive/app-name-version.zip')
15
+ it 'extracts the archive version from the filename' do
16
+ @archive.version.should eq('version')
17
+ end
12
18
  end
13
-
14
- it 'extracts the application name from the path' do
15
- archive.name.should eq('app-name')
19
+
20
+ describe 'uploading to AWS' do
21
+ before(:each) do
22
+ @beanstalk_api = double(
23
+ create_storage_location: double(
24
+ data: {s3_bucket: 'mah bukkit'}
25
+ )
26
+ ).as_null_object
27
+ @s3_client = double.as_null_object
28
+ allow(File).to receive(:open).with(ARCHIVE_FILENAME).and_return("fake archive file contents")
29
+ end
30
+
31
+ it 'knows if it has already been uploaded' do
32
+ when_beanstalk_describe_application_versions_returns([])
33
+ @archive.send(:already_uploaded?, @beanstalk_api).should be_false
34
+ when_beanstalk_describe_application_versions_returns(["some version or other"])
35
+ @archive.send(:already_uploaded?, @beanstalk_api).should be_true
36
+ end
37
+
38
+ context "when it has already been uploaded" do
39
+ before(:each) do
40
+ allow(@archive).to receive(:already_uploaded?).and_return true
41
+ end
42
+
43
+ it 'does not re-upload' do
44
+ expect(@s3_client).to_not receive(:put_object)
45
+ expect(@beanstalk_api).to_not receive(:create_application_version)
46
+ @archive.upload @beanstalk_api, @s3_client
47
+ end
48
+ end
49
+
50
+ context "when it hasn't already been uploaded" do
51
+ before(:each) do
52
+ allow(@archive).to receive(:already_uploaded?).and_return false
53
+ end
54
+
55
+ it 'uploads the file to S3' do
56
+ expect(@s3_client).to receive(:put_object).with(
57
+ bucket_name: 'mah bukkit',
58
+ key: 'app-name-version.zip',
59
+ data: "fake archive file contents"
60
+ )
61
+ @archive.upload @beanstalk_api, @s3_client
62
+ end
63
+
64
+ it 'creates an available application version' do
65
+ expect(@beanstalk_api).to receive(:create_application_version).with(
66
+ application_name: "app-name",
67
+ version_label: "version",
68
+ source_bundle: {
69
+ s3_bucket: "mah bukkit",
70
+ s3_key: "app-name-version.zip"
71
+ },
72
+ auto_create_application: true
73
+ )
74
+ @archive.upload @beanstalk_api, @s3_client
75
+ end
76
+ end
16
77
  end
17
-
18
- it 'extracts the version from the path' do
19
- archive.version.should eq('version')
20
- end
21
-
22
- it 'returns the filename of the archive' do
23
- archive.filename.should eq('app-name-version.zip')
78
+
79
+ def when_beanstalk_describe_application_versions_returns(versions)
80
+ expect(@beanstalk_api).to receive(:describe_application_versions).with(
81
+ application_name: "app-name",
82
+ version_labels: ["version"]
83
+ ).and_return(double(data: {application_versions: versions}))
24
84
  end
25
85
  end
26
86
 
@@ -0,0 +1,40 @@
1
+ require './lib/beanstalkify/archive'
2
+ require './lib/beanstalkify/environment'
3
+
4
+ describe Beanstalkify::Environment do
5
+ before do
6
+ allow(Beanstalkify::Beanstalk).to receive(:api).and_return @beanstalk_api = double
7
+ archive = Beanstalkify::Archive.new '/path/to/my/archive/app-name-version.zip'
8
+ @env = Beanstalkify::Environment.new archive, "Test"
9
+ end
10
+
11
+ it 'prepends the application name because environment names must be unique within an AWS account' do
12
+ @env.name.should == "app-name-Test"
13
+ end
14
+
15
+ it 'exposes the Beanstalk status' do
16
+ when_beanstalk_describe_environments_returns(status: 'Uncertain')
17
+ @env.status.should == 'Uncertain'
18
+ end
19
+
20
+ it 'exposes the Beanstalk CNAME URL' do
21
+ when_beanstalk_describe_environments_returns(cname: 'http://cname.elasticbeanstalk.com')
22
+ @env.url.should == 'http://cname.elasticbeanstalk.com'
23
+ end
24
+
25
+ it 'is healthy when Beanstalk reports that it is green' do
26
+ when_beanstalk_describe_environments_returns(health: 'Red')
27
+ @env.should_not be_healthy
28
+ when_beanstalk_describe_environments_returns(health: 'Green')
29
+ @env.should be_healthy
30
+ end
31
+
32
+ def when_beanstalk_describe_environments_returns(env_data)
33
+ expect(@beanstalk_api).to receive(:describe_environments).with(
34
+ environment_names: ["app-name-Test"],
35
+ include_deleted: false
36
+ ).and_return double(
37
+ data: {environments: [env_data]}
38
+ )
39
+ end
40
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: beanstalkify
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.0.4
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-08-09 00:00:00.000000000 Z
12
+ date: 2013-08-21 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: aws-sdk
@@ -62,12 +62,12 @@ files:
62
62
  - lib/beanstalkify/application.rb
63
63
  - lib/beanstalkify/archive.rb
64
64
  - lib/beanstalkify/beanstalk.rb
65
- - lib/beanstalkify/deploy.rb
66
65
  - lib/beanstalkify/deployment_info.rb
67
66
  - lib/beanstalkify/environment.rb
68
67
  - lib/beanstalkify/version.rb
69
68
  - test/archive_spec.rb
70
69
  - test/deployment_info_spec.rb
70
+ - test/environment_spec.rb
71
71
  homepage: https://github.com/pranavraja/beanstalkify
72
72
  licenses:
73
73
  - MIT
@@ -81,12 +81,18 @@ required_ruby_version: !ruby/object:Gem::Requirement
81
81
  - - ! '>='
82
82
  - !ruby/object:Gem::Version
83
83
  version: '0'
84
+ segments:
85
+ - 0
86
+ hash: -4062555010533808231
84
87
  required_rubygems_version: !ruby/object:Gem::Requirement
85
88
  none: false
86
89
  requirements:
87
90
  - - ! '>='
88
91
  - !ruby/object:Gem::Version
89
92
  version: '0'
93
+ segments:
94
+ - 0
95
+ hash: -4062555010533808231
90
96
  requirements: []
91
97
  rubyforge_project:
92
98
  rubygems_version: 1.8.24
@@ -96,3 +102,4 @@ summary: Beanstalk automation for dummies
96
102
  test_files:
97
103
  - test/archive_spec.rb
98
104
  - test/deployment_info_spec.rb
105
+ - test/environment_spec.rb
@@ -1,49 +0,0 @@
1
- require 'beanstalkify/archive'
2
- require 'beanstalkify/beanstalk'
3
- require 'aws-sdk'
4
-
5
- module Beanstalkify
6
- class Deploy
7
- attr_accessor :beanstalk, :archive
8
-
9
- def initialize(path)
10
- @archive = Archive.new(path)
11
- @beanstalk = Beanstalk.api
12
- end
13
-
14
- def bucket
15
- @beanstalk.create_storage_location.data[:s3_bucket]
16
- end
17
-
18
- def upload!
19
- client = AWS::S3.new.client
20
- bucket = self.bucket
21
- puts "Uploading #{@archive.filename} to bucket #{bucket}..."
22
- client.put_object({ :bucket_name => bucket, :key => @archive.filename, :data => File.open(@archive.path) })
23
- puts "Creating #{@archive.name} - #{@archive.version} in beanstalk"
24
- @beanstalk.create_application_version({
25
- :application_name => @archive.name,
26
- :version_label => @archive.version,
27
- :source_bundle => {
28
- :s3_bucket => bucket,
29
- :s3_key => @archive.filename
30
- },
31
- :auto_create_application => true
32
- })
33
- end
34
-
35
- def deployed?
36
- @beanstalk.describe_application_versions({
37
- :application_name => @archive.name,
38
- :version_labels => [@archive.version]
39
- }).data[:application_versions].count > 0
40
- end
41
-
42
- def wait!
43
- while not self.deployed?
44
- puts "Waiting for #{@archive.version} to be available..."
45
- sleep 10
46
- end
47
- end
48
- end
49
- end