broadside 2.0.0 → 3.0.0.pre.prerelease

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,9 +1,47 @@
1
+ # 3.0.0
2
+ ### Breaking Changes
3
+ - `ssh`, `bash`, `logtail`, `status`, and `run` are now top level commands, not subcommands of `deploy`
4
+ - No more `RAKE_DB_MIGRATE` constant
5
+ - Configuration changes:
6
+ - `config.git_repo=` and `config.type=` were removed.
7
+ - `config.base` and `config.deploy` are no longer backwards compatible - any options configured at `config.base.something` or `config.deploy.something` must now be configured at `config.something`
8
+ - `config.ecs.cluster` and `config.ecs.poll_frequency` are now configured at `config.aws.ecs_default_cluster` and `config.aws.ecs_poll_frequency`
9
+ - `config.docker_image` is now `config.default_docker_image`
10
+ - `instance` can no longer be configured on a per `Target` basis
11
+
12
+ #### Added Features
13
+ - Allow configuration of separate `:docker_image` per target
14
+ - Put back ability to configure a default `:tag` per target
15
+ - Add `broadside targets` command to display all the targets' deployed images and CPU/memory allocations
16
+ - `broadside status` has an added `--verbose` switch that displays service and task information
17
+ - [#11](https://github.com/lumoslabs/broadside/issues/11): Add option for ssh proxy user and proxy keyfile
18
+ - [#2](https://github.com/lumoslabs/broadside/issues/2): Add flag for changing loglevel, and add `--debug` switch that enables GLI debug output
19
+ - Failed deploys will rollback the service to the last successfully running scale
20
+ - Allow setting an environment variable `BROADSIDE_SYSTEM_CONFIG_FILE` to be used instead of `~/.broadside/config.rb`
21
+
22
+ #### General Improvements
23
+ - Only load `env_files` for the selected target (rather than preloading from unrelated targets)
24
+ - Make `env_files` configuration optional
25
+ - `Utils` has been replaced in favor of `LoggingUtils`
26
+ - Exceptions will be raised if a target is configured with an invalid hash key
27
+ - Tasks run have a more relevant `started_by` tag
28
+ - Default log level changed to `INFO`
29
+ - [#21](https://github.com/lumoslabs/broadside/issues/21) Print more useful messages when tasks die without exit codes.
30
+ - `Command` class to encapsulate the running of various commands
31
+
1
32
  # 2.0.0
2
- - **BREAKING CHANGE** `rake db:migrate` is no longer the default `predeploy_command`
33
+ #### Breaking Changes
34
+ - [#27](https://github.com/lumoslabs/broadside/issues/27) `rake db:migrate` is no longer the default `predeploy_command`
35
+ - Remove ability to configure a default tag for each target
36
+
37
+ #### Added Features
38
+ - [#38](https://github.com/lumoslabs/broadside/issues/38) ECS cluster can be configured for each target by setting `config.ecs.cluster`
39
+
40
+ #### General Improvements
41
+ - `base` configuration has been removed - the main `Configuration` object holds all the `base` config. `Broadside.config.base` may be called but will display a deprecation warning.
42
+ - `deploy` configuration has been removed - primarily handled through the main `Configuration` object and in `targets=`. `Broadside.config.deploy` may be called but will display a deprecation warning.
3
43
  - `Target` is a first class object
4
44
  - `Deploy` is composed of a `Target` plus command line options
5
- - There is no more `base` configuration - the main `Configuration` object holds all the `base` config. You can still call `Broadside.config.base` though you will get a deprecation warning.
6
- - There is no more `deploy` configuration - most of that is handled in the main `Configuration` object and in `targets=`. You can still call `Broadside.config.deploy` though you will get a deprecation warning.
7
45
 
8
46
  # 1.4.0
9
47
  - [#42](https://github.com/lumoslabs/broadside/pull/42/files): Update the task definition when running bootstrap
data/README.md CHANGED
@@ -1,93 +1,75 @@
1
1
  # Broadside [![Build Status](https://travis-ci.org/lumoslabs/broadside.svg?branch=master)](https://travis-ci.org/lumoslabs/broadside)
2
- A command-line tool for deploying applications on AWS EC2 Container Service (ECS)
3
-
4
- This tool is primarily intended for use with ruby applications.
5
2
 
3
+ A [GLI](https://github.com/davetron5000/gli) based command-line tool for deploying applications on [AWS EC2 Container Service (ECS)](https://aws.amazon.com/ecs/)
6
4
 
7
5
  ## Overview
8
- Amazon ECS presents a low barrier to entry for production-level docker applications. Combined with ECS's built-in blue-green deployment, Elastic Load Balancers, Autoscale Groups, and CloudWatch, one can set up a robust cluster that can scale to serve any number of applications in a short amount of time. Broadside seeks to leverage these benefits and improve the deployment process for developers.
6
+ Amazon ECS presents a low barrier to entry for production-level docker applications. Combined with ECS's built-in blue-green deployment, Elastic Load Balancers, Autoscale Groups, and CloudWatch, one can theoretically set up a robust cluster that can scale to serve any number of applications in a short amount of time. The ECS GUI, CLI, overall architecture are not the easiest to work with, however, so Broadside seeks to leverage the [ECS ruby API](http://docs.aws.amazon.com/sdkforruby/api/Aws/ECS.html) to dramatically simplify and improve the configuration and deployment process for developers, offering a simple command line interface and configuration format that should meet most needs.
7
+
8
+ Broadside does _not_ attempt to handle operational tasks like infrastructure setup and configuration, which are better suited to tools like [terraform](https://www.terraform.io/).
9
+
10
+ ### Capabilities
9
11
 
10
- Broadside offers a simple command-line interface to perform deployments on ECS. It does not attempt to handle operational tasks like infrastructure setup and configuration, which are better suited for tools like [terraform](https://www.terraform.io/). This allows applications using broadside to employ a clean configuration file that looks something like:
12
+ - **Trigger** ECS deployments
13
+ - **Launch** a bash shell directly onto a running container in the cluster
14
+ - **SSH** directly onto a host running a container
15
+ - **Launch** an ECS task running an arbitrary command
16
+ - **Tail** logs of a running container
17
+ - **Scale** an existing deployment on the fly
18
+
19
+ ### Example Config for Quickstarters
20
+ Applications using broadside employ a configuration file that looks something like:
11
21
 
12
22
  ```ruby
13
23
  Broadside.configure do |config|
14
24
  config.application = 'hello_world'
15
- config.docker_image = 'lumoslabs/hello_world'
16
- config.type = 'ecs'
17
- config.ecs.cluster = 'micro-cluster'
18
- config.deploy.targets = {
25
+ config.default_docker_image = 'lumoslabs/hello_world'
26
+ config.aws.ecs_default_cluster = 'production-cluster'
27
+ config.aws.region = 'us-east-1' # 'us-east-1 is the default
28
+ config.targets = {
19
29
  production_web: {
20
30
  scale: 7,
21
31
  command: ['bundle', 'exec', 'unicorn', '-c', 'config/unicorn.conf.rb'],
22
- env_file: '../.env.production'
32
+ env_file: '.env.production'
23
33
  predeploy_commands: [
24
- Broadside::Predeploy::RAKE_DB_MIGRATE, # RAKE_DB_MIGRATE is just a constant for your convenience
34
+ ['bundle', 'exec', 'rake', 'db:migrate'],
25
35
  ['bundle', 'exec', 'rake', 'data:migrate']
26
36
  ]
27
37
  },
28
- production_worker: {
29
- scale: 15,
30
- command: ['bundle', 'exec', 'rake', 'resque:work'],
31
- env_file: '../.env.production'
32
- },
38
+ # If you have multiple images or clusters, you can configure them per target
33
39
  staging_web: {
34
- cluster: 'staging-cluster', # Overrides config.ecs.cluster
35
40
  scale: 1,
36
41
  command: ['bundle', 'exec', 'puma'],
37
- env_file: '../.env.staging'
42
+ env_file: '.env.staging',
43
+ tag: 'latest', # Set a default tag for this target
44
+ cluster: 'staging-cluster', # Overrides config.ecs.cluster
45
+ docker_image: 'lumoslabs/staging_hello_world' # Overrides config.docker_image
38
46
  },
39
- staging_worker: {
40
- scale: 1,
41
- command: ['bundle', 'exec', 'rake', 'resque:work'],
42
- env_file: '../.env.staging'
43
- },
44
- # Example with a task_definition and service configuration which you use to bootstrap a service and
45
- # initial task definition. Accepts all the options AWS does - read their documentation for details:
46
- #
47
- # Service config: https://docs.aws.amazon.com/sdkforruby/api/Aws/ECS/Client.html#create_service-instance_method
48
- # Task Definition Config: https://docs.aws.amazon.com/sdkforruby/api/Aws/ECS/Client.html#register_task_definition-instance_method
49
- game_save_as_json_blob_stream: {
47
+ json_stream: {
50
48
  scale: 1,
51
49
  command: ['java', '-cp', '*:.', 'path.to.MyClass'],
52
- env_file: '.env.production',
53
- service_config: {
54
- deployment_configuration: {
55
- minimum_healthy_percent: 0.5,
56
- }
57
- },
58
- task_definition_config: {
59
- container_definitions: [
60
- {
61
- cpu: 1,
62
- memory: 2000,
63
- }
64
- ]
65
- }
50
+ # This target has a task_definition and service config which you use to bootstrap a new AWS Service
51
+ service_config: { deployment_configuration: { minimum_healthy_percent: 0.5 } },
52
+ task_definition_config: { container_definitions: [ { cpu: 1, memory: 2000, } ] }
66
53
  }
67
54
  }
68
55
  end
69
56
  ```
70
57
 
71
- From here, developers can use broadside's command-line interface to initiate a basic deployment:
58
+ From here, developers can use broadside's command-line interface to initiate a basic deployment and launch the
59
+ configured `command` as an ECS Service:
72
60
 
73
61
  ```bash
74
- broadside deploy short --target production_web --tag $GIT_SHA
62
+ bundle exec broadside deploy full --target production_web --tag v.1.1.example.tag
75
63
  ```
76
- or run
77
-
78
- ```bash
79
- broadside deploy full --target production_web --tag $GIT_SHA
80
- ```
81
-
82
- which will run the listed `predeploy_commands` listed in the config above prior to the deployment.
83
64
 
84
65
  In the case of an error or timeout during a deploy, broadside will automatically rollback to the latest stable version. You can perform manual rollbacks as well through the command-line.
85
66
 
86
- See the complete command-line reference in the wiki.
67
+ [For more information on broadside commands, see the complete command-line reference in the wiki](https://github.com/lumoslabs/broadside/wiki/CLI-reference).
87
68
 
88
69
 
89
- ## Setup
90
- First, install broadside by adding it to your application gemfile:
70
+ ## Installation
71
+ ### Via Gemfile
72
+ First, install broadside by adding it to your application `Gemfile`:
91
73
  ```ruby
92
74
  gem 'broadside'
93
75
  ```
@@ -95,23 +77,29 @@ gem 'broadside'
95
77
  Then run
96
78
  ```bash
97
79
  bundle install
98
- bundle binstubs broadside
99
80
  ```
100
81
 
101
- It's recommended that you specify broadside as a development gem so it doesn't inflate your production image.
102
-
103
82
  You can now run the executable in your app directory:
104
83
  ```bash
105
- bin/broadside --help
84
+ bundle exec broadside --help
85
+ ```
86
+
87
+ You may also generate binstubs using
88
+ ```bash
89
+ bundle binstubs broadside
106
90
  ```
107
91
 
108
- For a full application setup, see the detailed instructions in the wiki.
92
+ ### System Wide
93
+ Alternatively, you can install broadside using:
94
+ ```
95
+ gem install broadside
96
+ ```
109
97
 
98
+ ## Configuration
99
+ For full application setup, see the [detailed instructions in the wiki](https://github.com/lumoslabs/broadside/wiki).
110
100
 
111
- ## Contributing
112
- Pull requests, bug reports, and feature suggestions are welcome! Before starting on a contribution, I recommend opening an issue or replying to an existing one to give others some initial context on the work needing to be done.
101
+ ## Debugging
102
+ Use the `--debug` switch to enable stacktraces and debug output.
113
103
 
114
- 1. Create your feature branch (`git checkout -b my-new-feature`)
115
- 2. Commit your changes (`git commit -am 'Add some feature'`)
116
- 3. Push to the branch (`git push origin my-new-feature`)
117
- 4. Create a new Pull Request
104
+ ## Contributing
105
+ Pull requests, bug reports, and feature suggestions are welcome! Before starting on a contribution, we recommend opening an issue or replying to an existing one to give others some initial context on the work needing to be done.
@@ -4,187 +4,15 @@ require 'gli'
4
4
  require 'broadside'
5
5
 
6
6
  include GLI::App
7
- include Broadside::Utils
7
+ include Broadside::LoggingUtils
8
8
 
9
9
  program_desc 'A command-line tool for deployment and development of docker applications.'
10
-
11
10
  version Broadside::VERSION
12
11
 
13
12
  subcommand_option_handling :normal
14
13
  arguments :strict
15
14
  synopsis_format :full
16
15
 
17
- desc 'Configuration file to use.'
18
- default_value 'config/broadside.conf.rb'
19
- arg_name 'FILE'
20
- flag [:c, :config]
21
-
22
- def add_shared_deploy_configs(subcmd)
23
- # deployment always requires target
24
- subcmd.desc 'Deployment target to use, e.g. production_web'
25
- subcmd.arg_name 'TARGET'
26
- subcmd.flag [:t, :target], type: Symbol
27
-
28
- subcmd.action do |global_options, options, args|
29
- _DeployObj = Kernel.const_get("Broadside::#{Broadside.config.type.capitalize}Deploy")
30
- _target = Broadside.config.targets.select { |t| t.name == options[:target] }.first
31
- raise "Bad target: #{options[:target]}" unless _target
32
- _DeployObj.new(_target, options).public_send(subcmd.name)
33
- end
34
- end
35
-
36
- # GLI type coercions
37
- accept Symbol do |val|
38
- val.to_sym
39
- end
40
- accept Array do |val|
41
- val.split(' ')
42
- end
43
- accept Fixnum do |val|
44
- val.to_i
45
- end
46
-
47
- desc 'Bootstrap your service and task definition from the configured definition.'
48
- command :bootstrap do |b|
49
- b.desc 'Docker tag for application container'
50
- b.arg_name 'TAG'
51
- b.flag [:tag]
52
-
53
- add_shared_deploy_configs(b)
54
- end
55
-
56
- desc 'Deploy your application.'
57
- command :deploy do |d|
58
- d.desc 'Deploys without running migrations'
59
- d.command :short do |subcmd|
60
- subcmd.desc 'Docker tag for application container'
61
- subcmd.arg_name 'TAG'
62
- subcmd.flag [:tag]
63
-
64
- add_shared_deploy_configs(subcmd)
65
- end
66
-
67
- d.desc 'Performs a full deployment (with migration)'
68
- d.command :full do |subcmd|
69
- subcmd.desc 'Docker tag for application container'
70
- subcmd.arg_name 'TAG'
71
- subcmd.flag [:tag]
72
-
73
- add_shared_deploy_configs(subcmd)
74
- end
75
-
76
- d.desc 'Scales application to a given count'
77
- d.command :scale do |subcmd|
78
- subcmd.desc 'Specify a new scale for application'
79
- subcmd.arg_name 'NUM'
80
- subcmd.flag [:s, :scale], type: Fixnum
81
-
82
- add_shared_deploy_configs(subcmd)
83
- end
84
-
85
- d.desc 'Creates a single instance of the application to run a command.'
86
- d.command :run do |subcmd|
87
- subcmd.desc 'Docker tag for application container'
88
- subcmd.arg_name 'TAG'
89
- subcmd.flag [:tag]
90
-
91
- subcmd.desc 'Command to run (wrap argument in quotes)'
92
- subcmd.arg_name 'COMMAND'
93
- subcmd.flag [:command], type: Array
94
-
95
- add_shared_deploy_configs(subcmd)
96
- end
97
-
98
- d.desc 'Rolls back n releases and deploys'
99
- d.command :rollback do |subcmd|
100
- subcmd.desc 'Number of releases to rollback'
101
- subcmd.arg_name 'COUNT'
102
- subcmd.flag [:r, :rollback], type: Fixnum
103
-
104
- add_shared_deploy_configs(subcmd)
105
- end
106
-
107
- d.desc 'Gets information about what is currently deployed.'
108
- d.command :status do |subcmd|
109
- add_shared_deploy_configs(subcmd)
110
- end
111
-
112
- d.desc 'Tail the logs inside the running container.'
113
- d.command :logtail do |subcmd|
114
- subcmd.desc '0-based instance index'
115
- subcmd.default_value 0
116
- subcmd.arg_name 'INSTANCE'
117
- subcmd.flag [:n, :instance], type: Fixnum
118
-
119
- subcmd.desc 'Number of lines to tail'
120
- subcmd.default_value 10
121
- subcmd.arg_name 'TAIL_LINES'
122
- subcmd.flag [:l, :lines], type: Fixnum
123
-
124
- add_shared_deploy_configs(subcmd)
125
- end
126
-
127
- d.desc 'Establish a secure shell on the instance running the container.'
128
- d.command :ssh do |subcmd|
129
- subcmd.desc '0-based instance index'
130
- subcmd.default_value 0
131
- subcmd.arg_name 'INSTANCE'
132
- subcmd.flag [:n, :instance], type: Fixnum
133
-
134
- add_shared_deploy_configs(subcmd)
135
- end
136
-
137
- d.desc 'Establish a shell inside the running container.'
138
- d.command :bash do |subcmd|
139
- subcmd.desc '0-based instance index'
140
- subcmd.default_value 0
141
- subcmd.arg_name 'INSTANCE'
142
- subcmd.flag [:n, :instance], type: Fixnum
143
-
144
- add_shared_deploy_configs(subcmd)
145
- end
146
- end
147
-
148
- def call_hook(type, command)
149
- hook = Broadside.config.send(type)
150
-
151
- if hook.is_a?(Proc)
152
- hook_args =
153
- if command.parent.is_a?(GLI::Command)
154
- {
155
- command: command.parent.name,
156
- subcommand: command.name
157
- }
158
- else
159
- { command: command.name }
160
- end
161
- debug "Calling", type, "with args", hook_args
162
- hook.call(hook_args)
163
- end
164
- end
165
-
166
- pre do |global, command, options, args|
167
- Broadside.load_config(global[:config])
168
-
169
- call_hook(:prehook, command)
170
- true
171
- end
172
-
173
- post do |global, command, options, args|
174
- call_hook(:posthook, command)
175
- true
176
- end
177
-
178
-
179
- on_error do |exception|
180
- # false skips default error handling
181
- case exception
182
- when Broadside::MissingVariableError
183
- error exception.message, "Run your last command with --help for more information."
184
- false
185
- else
186
- true
187
- end
188
- end
16
+ commands_from File.expand_path(File.join(File.dirname(__FILE__), '/../lib/broadside/gli'))
189
17
 
190
18
  exit run(ARGV)
@@ -12,18 +12,18 @@ Gem::Specification.new do |spec|
12
12
  spec.summary = 'A command-line tool for EC2 Container Service deployment.'
13
13
  spec.homepage = 'https://github.com/lumoslabs/broadside'
14
14
  spec.license = 'MIT'
15
- spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
16
- spec.bindir = "bin"
15
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec)/}) }
16
+ spec.bindir = 'bin'
17
17
  spec.executables = ['broadside']
18
- spec.require_paths = ["lib"]
18
+ spec.require_paths = ['lib']
19
19
 
20
20
  spec.add_dependency 'activesupport', '>= 3', '< 5'
21
+ spec.add_dependency 'activemodel', '>= 3', '< 5'
21
22
  spec.add_dependency 'aws-sdk', '~> 2.3'
22
- spec.add_dependency 'dotenv', '>= 0.9.0'
23
+ spec.add_dependency 'dotenv', '>= 0.9.0', '< 3.0'
23
24
  spec.add_dependency 'gli', '~> 2.13'
24
- spec.add_dependency 'rainbow', '~> 2.1'
25
+ spec.add_dependency 'tty', '~> 0.5'
25
26
 
26
27
  spec.add_development_dependency 'rspec', '~> 3.4.0'
27
28
  spec.add_development_dependency 'bundler', '~> 1.9'
28
- spec.add_development_dependency 'fakefs'
29
29
  end
@@ -1,42 +1,50 @@
1
+ require 'active_model'
2
+ require 'active_support/core_ext'
3
+ require 'aws-sdk'
4
+
1
5
  require 'broadside/error'
2
- require 'broadside/utils'
3
- require 'broadside/configuration/verify_instance_variables'
4
- require 'broadside/configuration'
5
- require 'broadside/configuration/aws_config'
6
- require 'broadside/configuration/ecs_config'
6
+ require 'broadside/logging_utils'
7
+ require 'broadside/configuration/invalid_configuration'
8
+ require 'broadside/configuration/configuration'
9
+ require 'broadside/configuration/aws_configuration'
10
+ require 'broadside/command'
7
11
  require 'broadside/target'
8
12
  require 'broadside/deploy'
9
- require 'broadside/predeploy_commands'
10
13
  require 'broadside/ecs/ecs_deploy'
11
14
  require 'broadside/ecs/ecs_manager'
12
15
  require 'broadside/version'
13
16
 
14
17
  module Broadside
15
- extend Utils
18
+ extend LoggingUtils
16
19
 
17
- SYSTEM_CONFIG_FILE = "#{Dir.home}/.broadside/config.rb"
20
+ USER_CONFIG_FILE = (ENV['BROADSIDE_SYSTEM_CONFIG_FILE'] || File.join(Dir.home, '.broadside', 'config.rb')).freeze
18
21
 
19
22
  def self.configure
20
23
  yield config
24
+ raise ConfigurationError, config.errors.full_messages unless config.valid?
21
25
  end
22
26
 
23
- def self.load_config(config_file)
24
- begin
25
- load SYSTEM_CONFIG_FILE if File.exists?(SYSTEM_CONFIG_FILE)
26
- rescue LoadError => e
27
- error "Encountered an error loading system configuration file '#{SYSTEM_CONFIG_FILE}' !"
28
- raise e
29
- end
27
+ def self.load_config_file(config_file)
28
+ raise ArgumentError, "#{config_file} does not exist" unless File.exist?(config_file)
29
+ config.config_file = config_file
30
30
 
31
31
  begin
32
- config.file = config_file
33
- load config_file
34
- rescue LoadError => e
35
- error "Encountered an error loading required configuration file '#{config_file}' !"
36
- raise e
32
+ if File.exist?(USER_CONFIG_FILE)
33
+ debug "Loading user configuration from #{USER_CONFIG_FILE}"
34
+
35
+ begin
36
+ load(USER_CONFIG_FILE)
37
+ rescue ConfigurationError
38
+ # Suppress the exception because the system config file can be incomplete and validation failure is expected
39
+ end
40
+ end
41
+
42
+ debug "Loading application configuration from #{config_file}"
43
+ load(config_file)
44
+ rescue LoadError
45
+ error 'Encountered an error loading broadside configuration'
46
+ raise
37
47
  end
38
-
39
- config.verify
40
48
  end
41
49
 
42
50
  def self.config
@@ -45,5 +53,7 @@ module Broadside
45
53
 
46
54
  def self.reset!
47
55
  @config = nil
56
+ EcsManager.instance_variable_set(:@ecs_client, nil)
57
+ EcsManager.instance_variable_set(:@ec2_client, nil)
48
58
  end
49
59
  end