broadside 2.0.0 → 3.0.0.pre.prerelease

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.
@@ -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