ecs_compose 0.1.0.pre7 → 0.1.0.pre8

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 0ae0188dc62e80cc71af5875294462deda6c5edd
4
- data.tar.gz: 8e6f777891d855a5199eb117370be12596a4fb5a
3
+ metadata.gz: b1650cd5ac69bc7a05d43dfb153cecd2a399c3d6
4
+ data.tar.gz: 2ec1eabb033e0b12c7cb7a4c16b1b945913cf2cc
5
5
  SHA512:
6
- metadata.gz: e14d979474af2e9a368b1a6973fff7b0571480c55da159fad7bdee7fc0b4cf311f8a720e8dfea12196c4a5c553ddf39804d08f503270997aaacce325c117fb59
7
- data.tar.gz: e880db7381c14d238fd36c12d86f42704c552e540fab0088b018375bfd1d5bcf745d1842fb590bd7bd08081a58bfa4ee5eb60a54603b294f855dd8bf334bbedd
6
+ metadata.gz: b7528f64aac476b999b960c3baeaa93e86f9e17422e84e4a30c2e1d0f6fe8e5395b89948cdbfa8076bc94aed51e2d8d0c15d8d12cb2e3c55cd131688061483a3
7
+ data.tar.gz: 538236cee418cd6cb01a26dfded1d813a5dab847a63e03776bb34783c23123a9c9535c58f8b2028581f42670bb4d9d8e228e82b1d661a9ee1c707115f56a13c9
data/ecs_compose.gemspec CHANGED
@@ -27,7 +27,7 @@ Gem::Specification.new do |spec|
27
27
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
28
28
  spec.require_paths = ["lib"]
29
29
 
30
- spec.add_dependency "thor", "~> 0.19.1"
30
+ spec.add_dependency "docopt", "~> 0.5.0"
31
31
  spec.add_dependency "colorize", "~> 0.7.7"
32
32
 
33
33
  spec.add_development_dependency "bundler", "~> 1.10"
data/exe/ecs-compose CHANGED
@@ -1,5 +1,185 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
- require "ecs_compose/cli"
3
+ require "docopt"
4
+ require "ecs_compose"
4
5
 
5
- EcsCompose::CLI.start(ARGV)
6
+ USAGE = <<DOCOPT
7
+ ecs-compose - Like docker-compose, but for AWS EC2 Container Service
8
+
9
+ Usage:
10
+ ecs-compose --help
11
+ ecs-compose --version
12
+ ecs-compose [options] register [<task_def>...]
13
+ ecs-compose [options] up [<service>...]
14
+ ecs-compose [options] run [-e <name>=<value>]... [--entrypoint <entrypoint>] <task> [--] [<arg>...]
15
+ ecs-compose [options] json [<task_def>]
16
+
17
+ Options:
18
+ -h, --help Show this help message
19
+ --version Print the version of this program
20
+ -m, --manifest <manifest>
21
+ Path to an ecs-compose manifest (defaults to
22
+ deploy/DEPLOY-MANIFEST.yml, takes precedence over --file)
23
+ -f, --file <file> Path to docker-compose.yml file (defaults to
24
+ docker-compose.yml)
25
+ -i, --file-info (task:<name> | service:<name>)
26
+ Specify the task type and task name for a
27
+ docker-compose.yml file
28
+ -e <name>=<value> Set an environment variable
29
+ --entrypoint <entrypoint>
30
+ Override the container's regular entrypoint
31
+
32
+ Commands:
33
+ register Registers the specified ECS task definitions (defaults to all)
34
+ up Updates the specified ECS services (defaults to all)
35
+ run Runs the specified task
36
+ json Generate JSON for a specific task definition
37
+ DOCOPT
38
+
39
+ # Our command-line application. Parses our rather complicated arguments,
40
+ # then delegates all the real work to our usual internal classes.
41
+ class App
42
+ include EcsCompose
43
+
44
+ DEFAULT_FILE = "docker-compose.yml"
45
+ DEFAULT_MANIFEST = "deploy/DEPLOY-MANIFEST.yml"
46
+
47
+ attr_reader :options, :manifest
48
+
49
+ def initialize
50
+ @options = Docopt::docopt(USAGE, version: EcsCompose::VERSION)
51
+ @manifest = load_manifest()
52
+
53
+ # Uncomment to dump the docopt parser output, which can be non-obvious.
54
+ #require "pp"
55
+ #pp(options)
56
+ end
57
+
58
+ # Figure out which subcommand was chosen, and run it.
59
+ def run
60
+ for command in %w{register up run json}
61
+ if options.fetch(command)
62
+ send("command_#{command}")
63
+ return
64
+ end
65
+ end
66
+ # We shouldn't ever get here.
67
+ raise "Unknown command: #{command}"
68
+ end
69
+
70
+ protected
71
+
72
+ def command_register
73
+ available = manifest.task_definitions
74
+ chosen = all_or_specified(available, options.fetch('<task_def>'))
75
+ chosen.each {|td| td.register }
76
+ end
77
+
78
+ def command_up
79
+ available = manifest.task_definitions.select {|td| td.type == :service }
80
+ chosen = all_or_specified(available, options.fetch('<service>'))
81
+ chosen.each {|td| td.up }
82
+ end
83
+
84
+ def command_run
85
+ available = manifest.task_definitions.select {|td| td.type == :task }
86
+ task_name = options.fetch('<task>')
87
+ task = available.find {|td| td.name == task_name } or
88
+ fatal_err("Cannot find task '#{task_name}'")
89
+
90
+ env = options.fetch('-e').flatten.inject({}) do |hsh, e_opt|
91
+ e_opt =~ /\A([^=]+)=(.*)/ or
92
+ fatal_err "Can't parse '-e #{e_opt}'"
93
+ hsh[$1] = $2
94
+ hsh
95
+ end
96
+
97
+ command = options.fetch('<arg>')
98
+ command = nil if command.empty?
99
+
100
+ task.run(environment: env,
101
+ entrypoint: options.fetch('--entrypoint').flatten[0],
102
+ command: command)
103
+ end
104
+
105
+ def command_json
106
+ task_definition = options.fetch('<task_def>')[0]
107
+ if task_definition.nil?
108
+ choices = manifest.task_definitions.map {|td| td.name }
109
+ case choices.length
110
+ when 0
111
+ fatal_err("Please supply a manifest with at least one task definition")
112
+ when 1
113
+ task_definition = choices.first
114
+ else
115
+ fatal_err("Please choose one of: #{choices.join(', ')}")
116
+ end
117
+ end
118
+
119
+ found = manifest.task_definitions.find {|td| td.name } or
120
+ fatal_err("Can't find task definition: #{task_definition}")
121
+ puts found.to_json
122
+ end
123
+
124
+ # Choose either all items in `available`, or just those with the
125
+ # specified `names`.
126
+ def all_or_specified(available, names)
127
+ if names.empty?
128
+ available
129
+ else
130
+ available.select {|td| names.include?(td.name) }
131
+ end
132
+ end
133
+
134
+ # Figure out whether we have a manifest or a docker-compose.yml. We
135
+ # check supplied flags first, then defaults, and we prefer manifests
136
+ # when there's a tie.
137
+ def mode
138
+ if options.fetch('--manifest')
139
+ :manifest
140
+ elsif options.fetch('--file')
141
+ :file
142
+ elsif File.exist?(DEFAULT_MANIFEST)
143
+ :manifest
144
+ elsif File.exist?(DEFAULT_FILE)
145
+ :file
146
+ else
147
+ fatal_err("Unable to find either #{DEFAULT_FILE} or #{DEFAULT_MANIFEST}")
148
+ end
149
+ end
150
+
151
+ # Create a manifest, either by reading it in, or synthesizing it from a
152
+ # `docker-compose.yml` file and some extra arguments.
153
+ def load_manifest
154
+ case mode
155
+ when :manifest
156
+ Manifest.read_from_manifest(options.fetch('--manifest') || DEFAULT_MANIFEST)
157
+ when :file
158
+ info = options.fetch('--file-info')
159
+ if info.nil?
160
+ fatal_err("Must pass -i option when using docker-compose.yml")
161
+ end
162
+ unless info =~ /\A(service|task):([-_A-Za-z0-9\z]+)/
163
+ fatal_err("Incorrectly formatted -i option")
164
+ end
165
+ type, name = $1, $2
166
+ Manifest.read_from_file(options.fetch('--file') || DEFAULT_FILE,
167
+ type.to_sym, name)
168
+ else raise "Unknown mode: #{mode}"
169
+ end
170
+ end
171
+
172
+ # Print an error and quit.
173
+ def fatal_err(msg)
174
+ STDERR.puts(msg.red)
175
+ exit(1)
176
+ end
177
+ end
178
+
179
+ # Run our application.
180
+ begin
181
+ App.new.run
182
+ rescue Docopt::Exit => e
183
+ puts e.message
184
+ exit(1)
185
+ end
@@ -1,13 +1,52 @@
1
1
  module EcsCompose
2
2
 
3
- # Information required to create an ECS task definition.
3
+ # Information required to create an ECS task definition, and commands to
4
+ # act upon it.
4
5
  class TaskDefinition
5
6
  attr_reader :type, :name, :yaml
6
7
 
8
+ # Create a new TaskDefinition. The type should be either `:task` or
9
+ # `:service`, the name should be both the name of the ECS task
10
+ # definition and the corresponding ECS service (if any), and the YAML
11
+ # should be `docker-compose`-format YAML describing the containers
12
+ # associated with this task.
7
13
  def initialize(type, name, yaml)
8
14
  @name = name
9
15
  @type = type
10
16
  @yaml = yaml
11
17
  end
18
+
19
+ # Register this task definition with ECS. Will create the task
20
+ # definition if it doesn't exist, and add a new version of the task.
21
+ def register
22
+ EcsCompose::Ecs.register_task_definition(to_json)
23
+ end
24
+
25
+ # Register this task definition with ECS, and update the corresponding
26
+ # service.
27
+ def up
28
+ EcsCompose::Ecs.update_service_with_json(name, to_json)
29
+ end
30
+
31
+ # Run this task definition as a one-shot ECS task, with the specified
32
+ # overrides.
33
+ def run(environment: {}, entrypoint: nil, command: nil)
34
+ puts "environment: #{environment.inspect}"
35
+ puts "entrypoint: #{entrypoint.inspect}"
36
+ puts "command: #{command.inspect}"
37
+ raise "Not yet implemented"
38
+ end
39
+
40
+ # Generate ECS task definition JSON for this instance.
41
+ def to_json
42
+ json_generator.json
43
+ end
44
+
45
+ protected
46
+
47
+ # Return a JSON generator for this task.
48
+ def json_generator
49
+ @json_generator ||= EcsCompose::JsonGenerator.new(name, yaml)
50
+ end
12
51
  end
13
52
  end
metadata CHANGED
@@ -1,29 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ecs_compose
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0.pre7
4
+ version: 0.1.0.pre8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Eric Kidd
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2015-08-07 00:00:00.000000000 Z
11
+ date: 2015-08-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: thor
14
+ name: docopt
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: 0.19.1
19
+ version: 0.5.0
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: 0.19.1
26
+ version: 0.5.0
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: colorize
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -104,7 +104,6 @@ files:
104
104
  - exe/ecs-compose
105
105
  - go-publish.sh
106
106
  - lib/ecs_compose.rb
107
- - lib/ecs_compose/cli.rb
108
107
  - lib/ecs_compose/ecs.rb
109
108
  - lib/ecs_compose/json_generator.rb
110
109
  - lib/ecs_compose/manifest.rb
@@ -1,125 +0,0 @@
1
- require "ecs_compose"
2
- require "thor"
3
-
4
- module EcsCompose
5
- # Our basic command-line interface.
6
- class CLI < Thor
7
- DEFAULT_FILE = "docker-compose.yml"
8
- DEFAULT_MANIFEST = "deploy/DEPLOY-MANIFEST.yml"
9
-
10
- # Force status 1 on exit. See: https://github.com/erikhuda/thor/issues/244
11
- def self.exit_on_failure?
12
- true
13
- end
14
-
15
- class_option(:manifest, type: :string,
16
- aliases: %w(-m),
17
- desc: "Manifest describing a set of tasks and services (takes precedence over --file) [default: #{DEFAULT_MANIFEST}]")
18
- class_option(:file, type: :string,
19
- aliases: %w(-f),
20
- desc: "File describing a single task or service [default: #{DEFAULT_FILE}]")
21
- class_option(:file_info, type: :string,
22
- aliases: %w(-i),
23
- desc: "Type and name for use with --file [ex: 'service:hello' or 'task:migrate']")
24
-
25
- desc("up [SERVICES...]", "Register ECS task definitions and update services")
26
- def up(*services)
27
- available = manifest.task_definitions.select {|td| td.type == :service }
28
- chosen = all_or_specified(available, services)
29
-
30
- chosen.each do |service|
31
- json = EcsCompose::JsonGenerator.new(service.name, service.yaml).json
32
- EcsCompose::Ecs.update_service_with_json(service.name, json)
33
- end
34
- end
35
-
36
- desc("register [TASK_DEFINITIONS...]", "Register ECS task definitions")
37
- def register(*task_definitions)
38
- available = manifest.task_definitions
39
- chosen = all_or_specified(available, task_definitions)
40
-
41
- chosen.each do |td|
42
- json = EcsCompose::JsonGenerator.new(td.name, td.yaml).json
43
- EcsCompose::Ecs.register_task_definition(json)
44
- end
45
- end
46
-
47
- desc("json [TASK_DEFINITION]",
48
- "Convert a task definition to ECS JSON format")
49
- def json(task_definition=nil)
50
- if task_definition.nil?
51
- choices = manifest.task_definitions.map {|td| td.name }
52
- case choices.length
53
- when 0
54
- fatal_err("Please supply a manifest with at least one task definition")
55
- when 1
56
- task_definition = choices.first
57
- else
58
- fatal_err("Please choose one of: #{choices.join(', ')}")
59
- end
60
- end
61
-
62
- found = manifest.task_definitions.find {|td| td.name } or
63
- fatal_err("Can't find task definition: #{task_definition}")
64
- puts EcsCompose::JsonGenerator.new(found.name, found.yaml).json
65
- end
66
-
67
- protected
68
-
69
- # Choose either all items in `available`, or just those with the
70
- # specified `names`.
71
- def all_or_specified(available, names)
72
- if names.empty?
73
- available
74
- else
75
- available.select {|td| names.include?(td.name) }
76
- end
77
- end
78
-
79
- # Figure out whether we have a manifest or a docker-compose.yml. We
80
- # check supplied flags first, then defaults, and we prefer manifests
81
- # when there's a tie.
82
- def mode
83
- @mode ||=
84
- if options.manifest
85
- :manifest
86
- elsif options.file
87
- :file
88
- elsif File.exist?(DEFAULT_MANIFEST)
89
- :manifest
90
- elsif File.exist?(DEFAULT_FILE)
91
- :file
92
- else
93
- fatal_err("Unable to find either #{DEFAULT_FILE} or #{DEFAULT_MANIFEST}")
94
- end
95
- end
96
-
97
- # Create a manifest, either by reading it in, or synthesizing it from a
98
- # `docker-compose.yml` file and some extra arguments.
99
- def manifest
100
- @manifest ||=
101
- case mode
102
- when :manifest
103
- Manifest.read_from_manifest(options.manifest || DEFAULT_MANIFEST)
104
- when :file
105
- info = options.file_info
106
- if info.nil?
107
- fatal_err("Must pass -i option when using docker-compose.yml")
108
- end
109
- unless info =~ /\A(service|task):([-_A-Za-z0-9\z]+)/
110
- fatal_err("Incorrectly formatted -i option")
111
- end
112
- type, name = $1, $2
113
- Manifest.read_from_file(options.file || DEFAULT_FILE,
114
- type.to_sym, name)
115
- else raise "Unknown mode: #{mode}"
116
- end
117
- end
118
-
119
- # Print an error and quit.
120
- def fatal_err(msg)
121
- STDERR.puts(msg.red)
122
- exit(1)
123
- end
124
- end
125
- end