Skip to content

Commit

Permalink
Merge branch 'master' into ha-feature-exoscale
Browse files Browse the repository at this point in the history
  • Loading branch information
BanzaiMan committed Aug 2, 2016
2 parents 2ac5082 + c4e259d commit 1dc689e
Show file tree
Hide file tree
Showing 5 changed files with 125 additions and 77 deletions.
4 changes: 4 additions & 0 deletions Gemfile
Expand Up @@ -89,3 +89,7 @@ end
group :deis do
gem 'git'
end

group :opsworks do
gem 'aws-sdk', '>= 2.0.18.pre'
end
5 changes: 4 additions & 1 deletion README.md
Expand Up @@ -376,9 +376,11 @@ It is possible to set file-specific `Cache-Control` and `Expires` headers using
* **access-key-id**: AWS Access Key ID. Can be obtained from [here](https://console.aws.amazon.com/iam/home?#security_credential).
* **secret-access-key**: AWS Secret Key. Can be obtained from [here](https://console.aws.amazon.com/iam/home?#security_credential).
* **app-id**: The app ID.
* **instance-ids**: An instance id. (Use this option multiple times to specify multiple instance ids. Default: [])
* **layer-ids**: A layer id. (Use this option multiple times to specify multiple layer ids. Default: [])
* **migrate**: Migrate the database. (Default: false)
* **wait-until-deployed**: Wait until the app is deployed and return the deployment status. (Default: false)
* **custom_json**: Override custom_json options. If using this, default configuration will be overriden. See the code [here](https://github.com/travis-ci/dpl/blob/master/lib/dpl/provider/ops_works.rb#L34). More about `custom_json` [here](http://docs.aws.amazon.com/opsworks/latest/userguide/workingcookbook-json.html).
* **custom_json**: Override custom_json options. If using this, default configuration will be overriden. See the code [here](https://github.com/travis-ci/dpl/blob/master/lib/dpl/provider/ops_works.rb#L43). More about `custom_json` [here](http://docs.aws.amazon.com/opsworks/latest/userguide/workingcookbook-json.html).

#### Environment variables:

Expand All @@ -388,6 +390,7 @@ It is possible to set file-specific `Cache-Control` and `Expires` headers using
#### Examples:

dpl --provider=opsworks --access-key-id=<access-key-id> --secret-access-key=<secret-access-key> --app-id=<app-id> --migrate --wait-until-deployed
dpl --provider=opsworks --access-key-id=<access-key-id> --secret-access-key=<secret-access-key> --app-id=<app-id> --layer-ids=<layer-id>

### Anynines:

Expand Down
40 changes: 22 additions & 18 deletions lib/dpl/provider/ops_works.rb
Expand Up @@ -3,15 +3,18 @@
module DPL
class Provider
class OpsWorks < Provider
requires 'aws-sdk-v1'
requires 'aws-sdk', version: '~> 2'
experimental 'AWS OpsWorks'

def api
@api ||= AWS::OpsWorks.new
def opsworks
@opsworks ||= Aws::OpsWorks::Client.new(opsworks_options)
end

def client
@client ||= api.client
def opsworks_options
{
region: region || 'us-east-1',
credentials: ::Aws::Credentials.new(access_key_id, secret_access_key)
}
end

def needs_key?
Expand All @@ -22,6 +25,10 @@ def check_app

end

def region
options[:region] || context.env['AWS_DEFAULT_REGION']
end

def access_key_id
options[:access_key_id] || context.env['AWS_ACCESS_KEY_ID'] || raise(Error, "missing access_key_id")
end
Expand All @@ -30,13 +37,8 @@ def secret_access_key
options[:secret_access_key] || context.env['AWS_SECRET_ACCESS_KEY'] || raise(Error, "missing secret_access_key")
end

def setup_auth
AWS.config(access_key_id: access_key_id, secret_access_key: secret_access_key)
end

def check_auth
setup_auth
log "Logging in with Access Key: #{option(:access_key_id)[-4..-1].rjust(20, '*')}"
log "Logging in with Access Key: #{access_key_id[-4..-1].rjust(20, '*')}"
end

def custom_json
Expand All @@ -61,7 +63,7 @@ def ops_works_app
end

def fetch_ops_works_app
data = client.describe_apps(app_ids: [option(:app_id)])
data = opsworks.describe_apps(app_ids: [option(:app_id)])
unless data[:apps] && data[:apps].count == 1
raise Error, "App #{option(:app_id)} not found.", error.backtrace
end
Expand All @@ -87,7 +89,11 @@ def create_deployment
if !options[:instance_ids].nil?
deployment_config[:instance_ids] = Array(option(:instance_ids))
end
data = client.create_deployment(deployment_config)
if !options[:layer_ids].nil?
deployment_config[:layer_ids] = Array(option(:layer_ids))
end
log "creating deployment #{deployment_config.to_json}"
data = opsworks.create_deployment(deployment_config)
log "Deployment created: #{data[:deployment_id]}"
return unless options[:wait_until_deployed]
print "Deploying "
Expand All @@ -103,7 +109,7 @@ def create_deployment
def wait_until_deployed(deployment_id)
deployment = nil
loop do
result = client.describe_deployments(deployment_ids: [deployment_id])
result = opsworks.describe_deployments(deployment_ids: [deployment_id])
deployment = result[:deployments].first
break unless deployment[:status] == "running"
print "."
Expand All @@ -118,10 +124,8 @@ def travis_deploy_comment

def deploy
super
rescue AWS::Errors::ClientError => error
raise Error, "Stopping Deploy, OpsWorks error: #{error.message}", error.backtrace
rescue AWS::Errors::ServerError => error
raise Error, "Stopping Deploy, OpsWorks server error: #{error.message}", error.backtrace
rescue Aws::Errors::ServiceError => error
raise Error, "Stopping Deploy, OpsWorks service error: #{error.message}", error.backtrace
end
end
end
Expand Down
3 changes: 2 additions & 1 deletion lib/dpl/provider/s3.rb
Expand Up @@ -52,7 +52,8 @@ def push_app
opts[:expires] = get_option_value_by_filename(options[:expires], filename) if options[:expires]
unless File.directory?(filename)
log "uploading #{filename.inspect} with #{opts.inspect}"
api.bucket(option(:bucket)).object(upload_path(filename)).upload_file(filename, opts)
result = api.bucket(option(:bucket)).object(upload_path(filename)).upload_file(filename, opts)
warn "error while uploading #{filename.inspect}" unless result
end
end
end
Expand Down
150 changes: 93 additions & 57 deletions spec/provider/ops_works_spec.rb
@@ -1,91 +1,127 @@
require 'spec_helper'
require 'aws-sdk-v1'
require 'aws-sdk'
require 'dpl/provider'
require 'dpl/provider/ops_works'

describe DPL::Provider::OpsWorks do

before (:each) do
AWS.stub!
subject :provider do
described_class.new(DummyContext.new, :access_key_id => 'qwertyuiopasdfghjklz', :secret_access_key => 'qwertyuiopasdfghjklzqwertyuiopasdfghjklz')
end

subject :provider do
described_class.new(DummyContext.new, :access_key_id => 'qwertyuiopasdfghjklz', :secret_access_key => 'qwertyuiopasdfghjklzqwertyuiopasdfghjklz', :bucket => 'my-bucket')
describe '#opsworks_options' do
context 'without region' do
example do
options = provider.opsworks_options
expect(options[:region]).to eq('us-east-1')
end
end

context 'with region' do
example do
region = 'us-west-1'
provider.options.update(:region => region)
options = provider.opsworks_options
expect(options[:region]).to eq(region)
end
end
end

describe "#check_auth" do
example do
expect(provider).to receive(:setup_auth)
expect(provider).to receive(:log).with('Logging in with Access Key: ****************jklz')
provider.check_auth
end
end

describe "#setup_auth" do
example do
expect(AWS).to receive(:config).with(:access_key_id => 'qwertyuiopasdfghjklz', :secret_access_key => 'qwertyuiopasdfghjklzqwertyuiopasdfghjklz').once.and_call_original
provider.setup_auth
end
end

describe "#needs_key?" do
example do
expect(provider.needs_key?).to eq(false)
end
end

describe "#push_app" do
let(:client) { double(:ops_works_client) }
let(:ops_works_app) { {shortname: 'app', stack_id: 'stack-id'} }
before do
expect(provider).to receive(:current_sha).and_return('sha')
expect(provider.api).to receive(:client).and_return(client)
expect(provider.context.env).to receive(:[]).with('TRAVIS_BUILD_NUMBER').and_return('123')
end
describe DPL::Provider::OpsWorks do
access_key_id = 'someaccesskey'
secret_access_key = 'somesecretaccesskey'
region = 'us-east-1'

let(:custom_json) { "{\"deploy\":{\"app\":{\"migrate\":false,\"scm\":{\"revision\":\"sha\"}}}}" }
example 'without :migrate option' do
provider.options.update(app_id: 'app-id')
expect(client).to receive(:describe_apps).with(app_ids: ['app-id']).and_return({apps: [ops_works_app]}
)
expect(client).to receive(:create_deployment).with(
stack_id: 'stack-id', app_id: 'app-id', command: {name: 'deploy'}, comment: 'Deploy build 123 via Travis CI', custom_json: custom_json
).and_return({})
provider.push_app
end
client_options = {
stub_responses: true,
region: region,
credentials: Aws::Credentials.new(access_key_id, secret_access_key)
}

let(:custom_json_with_migrate) { "{\"deploy\":{\"app\":{\"migrate\":true,\"scm\":{\"revision\":\"sha\"}}}}" }
example 'with :migrate option' do
provider.options.update(app_id: 'app-id', migrate: true)
expect(client).to receive(:describe_apps).with(app_ids: ['app-id']).and_return({apps: [ops_works_app]})
expect(client).to receive(:create_deployment).with(
stack_id: 'stack-id', app_id: 'app-id', command: {name: 'deploy'}, comment: 'Deploy build 123 via Travis CI', custom_json: custom_json_with_migrate
).and_return({})
provider.push_app
subject :provider do
described_class.new(DummyContext.new, {
access_key_id: access_key_id,
secret_access_key: secret_access_key
})
end

example 'with :wait_until_deployed' do
provider.options.update(app_id: 'app-id', wait_until_deployed: true)
expect(client).to receive(:describe_apps).with(app_ids: ['app-id']).and_return({apps: [ops_works_app]})
expect(client).to receive(:create_deployment).and_return({deployment_id: 'deployment_id'})
expect(client).to receive(:describe_deployments).with({deployment_ids: ['deployment_id']}).and_return({deployments: [status: 'running']}, {deployments: [status: 'successful']})
provider.push_app
before :each do
expect(provider).to receive(:opsworks_options).and_return(client_options)
end

example 'with :instance-ids' do
provider.options.update(app_id: 'app-id', instance_ids: ['instance-id'])
expect(client).to receive(:describe_apps).with(app_ids: ['app-id']).and_return({apps: [ops_works_app]})
expect(client).to receive(:create_deployment).with(
stack_id: 'stack-id', app_id: 'app-id', instance_ids:['instance-id'], command: {name: 'deploy'}, comment: 'Deploy build 123 via Travis CI', custom_json: custom_json
).and_return({})
provider.push_app
describe '#opsworks' do
example do
expect(Aws::OpsWorks::Client).to receive(:new).with(client_options).once
provider.opsworks
end
end
end

describe "#api" do
example do
expect(AWS::OpsWorks).to receive(:new)
provider.api
describe "#push_app" do
let(:client) { provider.opsworks }
let(:ops_works_app) { {shortname: 'app', stack_id: 'stack-id'} }
before do
expect(provider).to receive(:current_sha).and_return('sha')
expect(provider.context.env).to receive(:[]).with('TRAVIS_BUILD_NUMBER').and_return('123')
end

let(:custom_json) { "{\"deploy\":{\"app\":{\"migrate\":false,\"scm\":{\"revision\":\"sha\"}}}}" }
example 'without :migrate option' do
provider.options.update(app_id: 'app-id')
expect(client).to receive(:describe_apps).with(app_ids: ['app-id']).and_return({apps: [ops_works_app]})
expect(client).to receive(:create_deployment).with(
stack_id: 'stack-id', app_id: 'app-id', command: {name: 'deploy'}, comment: 'Deploy build 123 via Travis CI', custom_json: custom_json
).and_return({})
provider.push_app
end

let(:custom_json_with_migrate) { "{\"deploy\":{\"app\":{\"migrate\":true,\"scm\":{\"revision\":\"sha\"}}}}" }
example 'with :migrate option' do
provider.options.update(app_id: 'app-id', migrate: true)
expect(client).to receive(:describe_apps).with(app_ids: ['app-id']).and_return({apps: [ops_works_app]})
expect(client).to receive(:create_deployment).with(
stack_id: 'stack-id', app_id: 'app-id', command: {name: 'deploy'}, comment: 'Deploy build 123 via Travis CI', custom_json: custom_json_with_migrate
).and_return({})
provider.push_app
end

example 'with :wait_until_deployed' do
provider.options.update(app_id: 'app-id', wait_until_deployed: true)
expect(client).to receive(:describe_apps).with(app_ids: ['app-id']).and_return({apps: [ops_works_app]})
expect(client).to receive(:create_deployment).and_return({deployment_id: 'deployment_id'})
expect(client).to receive(:describe_deployments).with({deployment_ids: ['deployment_id']}).and_return({deployments: [status: 'running']}, {deployments: [status: 'successful']})
provider.push_app
end

example 'with :instance-ids' do
provider.options.update(app_id: 'app-id', instance_ids: ['instance-id'])
expect(client).to receive(:describe_apps).with(app_ids: ['app-id']).and_return({apps: [ops_works_app]})
expect(client).to receive(:create_deployment).with(
stack_id: 'stack-id', app_id: 'app-id', instance_ids:['instance-id'], command: {name: 'deploy'}, comment: 'Deploy build 123 via Travis CI', custom_json: custom_json
).and_return({})
provider.push_app
end

example 'with :layer-ids' do
provider.options.update(app_id: 'app-id', layer_ids: ['layer-id'])
expect(client).to receive(:describe_apps).with(app_ids: ['app-id']).and_return({apps: [ops_works_app]})
expect(client).to receive(:create_deployment).with(
stack_id: 'stack-id', app_id: 'app-id', layer_ids:['layer-id'], command: {name: 'deploy'}, comment: 'Deploy build 123 via Travis CI', custom_json: custom_json
).and_return({})
provider.push_app
end
end
end
end

0 comments on commit 1dc689e

Please sign in to comment.