ec2ctl 0.7.9 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: c9d5765abec98bc65ea4dd0c1276041db0c2766c
4
- data.tar.gz: 3ed14b3b91fa16fc850c5f1a567b9f3970df6e86
3
+ metadata.gz: 2db3d33906e470bb3a0e6b4a96e840feae7e0dfd
4
+ data.tar.gz: aac465cbdf09c95ce707088fd6dd705584088290
5
5
  SHA512:
6
- metadata.gz: bc349a68f3004dafea7daf1951f790b8da4ee30a8dd3434ec3429fb5b86a061eb52a42317e44f1081192d4d0e09a87b0ede2377d462e3e7ff82ae22af24f9967
7
- data.tar.gz: da45141f0d9338d1386c4d988741622df08ec521958b4f4146efa9e3bd50bd1d75c4f25c58fa9b9caaf33bcebf3c78067811f63de7bcfbf0af3d63a535ede5f6
6
+ metadata.gz: 14cadc9ca8e185e0b97547b05a155b0fb44ee2be7952430ae27199a292f3dc2594027e24c5fbdc71e3afcf46be780ccba3c2533da63febb972c2de37abcc8aa7
7
+ data.tar.gz: 19ab369c479627d591d68b44e943bcd6d3ce66ae66ec5fde155c634ec49f7afb0a411f1efe162a9b1d95487beaed8c4f26dccb50c900bace55b9bf8b940f8774
data/.travis.yml ADDED
@@ -0,0 +1,5 @@
1
+ sudo: false
2
+ language: ruby
3
+ rvm:
4
+ - 2.3.1
5
+ before_install: gem install bundler -v 1.12.5
@@ -0,0 +1,49 @@
1
+ # Contributor Code of Conduct
2
+
3
+ As contributors and maintainers of this project, and in the interest of
4
+ fostering an open and welcoming community, we pledge to respect all people who
5
+ contribute through reporting issues, posting feature requests, updating
6
+ documentation, submitting pull requests or patches, and other activities.
7
+
8
+ We are committed to making participation in this project a harassment-free
9
+ experience for everyone, regardless of level of experience, gender, gender
10
+ identity and expression, sexual orientation, disability, personal appearance,
11
+ body size, race, ethnicity, age, religion, or nationality.
12
+
13
+ Examples of unacceptable behavior by participants include:
14
+
15
+ * The use of sexualized language or imagery
16
+ * Personal attacks
17
+ * Trolling or insulting/derogatory comments
18
+ * Public or private harassment
19
+ * Publishing other's private information, such as physical or electronic
20
+ addresses, without explicit permission
21
+ * Other unethical or unprofessional conduct
22
+
23
+ Project maintainers have the right and responsibility to remove, edit, or
24
+ reject comments, commits, code, wiki edits, issues, and other contributions
25
+ that are not aligned to this Code of Conduct, or to ban temporarily or
26
+ permanently any contributor for other behaviors that they deem inappropriate,
27
+ threatening, offensive, or harmful.
28
+
29
+ By adopting this Code of Conduct, project maintainers commit themselves to
30
+ fairly and consistently applying these principles to every aspect of managing
31
+ this project. Project maintainers who do not follow or enforce the Code of
32
+ Conduct may be permanently removed from the project team.
33
+
34
+ This code of conduct applies both within project spaces and in public spaces
35
+ when an individual is representing the project or its community.
36
+
37
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be
38
+ reported by contacting a project maintainer at yamaguchi@cloudpack.jp. All
39
+ complaints will be reviewed and investigated and will result in a response that
40
+ is deemed necessary and appropriate to the circumstances. Maintainers are
41
+ obligated to maintain confidentiality with regard to the reporter of an
42
+ incident.
43
+
44
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage],
45
+ version 1.3.0, available at
46
+ [http://contributor-covenant.org/version/1/3/0/][version]
47
+
48
+ [homepage]: http://contributor-covenant.org
49
+ [version]: http://contributor-covenant.org/version/1/3/0/
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2016 Yoriki Yamaguchi
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # EC2Ctl
2
2
 
3
- **!!! Version 0.7 or later is not compatible with 0.6 !!!**
3
+ A small command line tool for managing EC2/ELB.
4
4
 
5
5
  ## Installation
6
6
 
@@ -20,7 +20,37 @@ Or install it yourself as:
20
20
 
21
21
  ## Usage
22
22
 
23
- TODO: Write usage instructions here
23
+ ### `ec2 list`
24
+
25
+ List EC2 instances.
26
+
27
+ ### `ec2 execute`
28
+
29
+ Execute commands in the EC2 instances.
30
+
31
+ ### `elb list`
32
+
33
+ List load balancers.
34
+
35
+ ### `elb status`
36
+
37
+ Show the load balancer's status.
38
+
39
+ ### `elb attach`
40
+
41
+ Attach the instances to the load balancer.
42
+
43
+ ### `elb detach`
44
+
45
+ Detach the instances from the load balancer.
46
+
47
+ ### `elb execute`
48
+
49
+ Execute commands on instance(s) registered to a load balancer.
50
+
51
+ ### `elb graceful`
52
+
53
+ Sequencially deregister instance(s) from load balancer, execute commands, register it back to load balancer and wait until it's in `InService` state.
24
54
 
25
55
  ## Development
26
56
 
data/Rakefile CHANGED
@@ -1,6 +1 @@
1
1
  require "bundler/gem_tasks"
2
- require "rspec/core/rake_task"
3
-
4
- RSpec::Core::RakeTask.new(:spec)
5
-
6
- task :default => :spec
data/ec2ctl.gemspec CHANGED
@@ -4,26 +4,28 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
4
  require 'ec2ctl/version'
5
5
 
6
6
  Gem::Specification.new do |spec|
7
- spec.name = "ec2ctl"
8
- spec.version = EC2Ctl::VERSION
9
- spec.authors = ["y13i"]
10
- spec.email = ["email@y13i.com"]
11
-
12
- spec.summary = %q{A minimum tool for EC2 instances.}
13
- spec.description = %q{A minimum tool for EC2 instances.}
14
- spec.homepage = "https://github.com/y13i/ec2ctl"
7
+ spec.name = "ec2ctl"
8
+ spec.version = EC2Ctl::VERSION
9
+ spec.authors = ["Yoriki Yamaguchi"]
10
+ spec.email = ["email@y13i.com"]
11
+ spec.summary = %(A small command line tool for managing EC2/ELB.)
12
+ spec.description = %(A small command line tool for managing EC2/ELB.)
13
+ spec.homepage = "https://github.com/y13i/ec2ctl"
14
+ spec.license = "MIT"
15
15
 
16
16
  spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
17
17
  spec.bindir = "exe"
18
18
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
19
19
  spec.require_paths = ["lib"]
20
20
 
21
- spec.add_dependency "commander"
22
- spec.add_dependency "aws-sdk", ">= 2.0"
23
- spec.add_dependency "terminal-table"
21
+ spec.required_ruby_version = ">= 2.1.0"
22
+
23
+ spec.add_dependency "aws-sdk", "~> 2.3"
24
+ spec.add_dependency "commander", "~> 4.4"
25
+ spec.add_dependency "coderay", "~> 1.1"
26
+ spec.add_dependency "terminal-table", "~> 1.6"
24
27
 
25
- spec.add_development_dependency "bundler", "~> 1.10"
26
- spec.add_development_dependency "rake", "~> 10.0"
27
- spec.add_development_dependency "rspec"
28
- spec.add_development_dependency "pry"
28
+ spec.add_development_dependency "bundler", "~> 1.12"
29
+ spec.add_development_dependency "rake", "~> 10.0"
30
+ spec.add_development_dependency "pry", "~> 0.10"
29
31
  end
data/lib/ec2ctl/cli.rb CHANGED
@@ -1,108 +1,238 @@
1
1
  require "commander"
2
- require "json"
3
- require "yaml"
4
- require "terminal-table"
2
+ require "ec2ctl/logger"
5
3
 
6
4
  module EC2Ctl
7
5
  class CLI
8
6
  include Commander::Methods
9
7
 
8
+ OptionError = Class.new RuntimeError
9
+
10
10
  def run
11
- program :name, "EC2Ctl"
12
- program :version, EC2Ctl::VERSION
13
- program :description, "A minimum tool for EC2 instances."
11
+ program :name, self.class.to_s
12
+ program :version, VERSION
13
+ program :description, "A small command line tool for managing EC2/ELB."
14
+
15
+ global_option("-V", "--verbose", "Debug output.") {@verbose = true}
16
+ global_option("-P", "--pretty", "Pretty JSON output.") {@pretty = true}
17
+ global_option("-o", "--output #{EC2Ctl::Logger::VALID_FORMATS}", "Log output format.") {|v| @output_format = v.intern}
18
+ global_option("-p", "--profile PROFILE_NAME", "AWS profile name.") {|v| ENV["AWS_PROFILE"] = v}
19
+ global_option("-r", "--region REGION_NAME", "AWS region name.") {|v| ENV["AWS_REGION"] = v}
20
+
21
+ default_command :"ec2 list"
22
+
23
+ command :"ec2 list" do |c|
24
+ c.syntax = "ec2ctl ec2 list"
25
+ c.description = "List EC2 instances."
26
+
27
+ ec2_options c
28
+
29
+ c.action do |args, options|
30
+ options.default attributes: %w(instance_id tag:Name instance_type public_dns_name state.name)
31
+
32
+ invoke options do
33
+ @client.ec2_list
34
+ end
35
+ end
36
+ end
37
+
38
+ command :"ec2 execute" do |c|
39
+ c.syntax = "ec2ctl ec2 execute"
40
+ c.description = "Execute commands in the EC2 instances."
41
+
42
+ ec2_options c
43
+
44
+ c.option "-c", "--commands 'STRING1','STRING2',...", Array, "The commands to execute."
45
+
46
+ c.action do |args, options|
47
+ invoke options do
48
+ mandatory options, :commands
49
+ @client.ec2_execute
50
+ end
51
+ end
52
+ end
14
53
 
15
- global_option "-p", "--profile PROFILE", "Load AWS credentials from shared credentials file by specified name."
16
- global_option "-r", "--region REGION", "Specify AWS region."
54
+ command :"elb list" do |c|
55
+ c.syntax = "ec2ctl elb list"
56
+ c.description = "List load balancers."
17
57
 
18
- default_command :list
58
+ c.action do |args, options|
59
+ invoke options do
60
+ @client.elb_list
61
+ end
62
+ end
63
+ end
19
64
 
20
- command :list do |c|
21
- c.syntax = "list [options]"
22
- c.description = "List EC2 instances"
65
+ command :"elb status" do |c|
66
+ c.syntax = "ec2ctl elb status"
67
+ c.description = "Show the load balancer's status."
23
68
 
24
- c.option "-a", "--attributes STRING", String, "Attribute of EC2 instances separated by commas."
25
- c.option "-s", "--search STRING", String, "Search instance with given KEY=VALUE attributes."
26
- c.option "-o", "--order STRING", String, "Order list by specified attribute."
27
- c.option "-f", "--format STRING", String, "Output format (table/json/yaml)."
69
+ c.option "-b", "--load-balancer-name VALUE", String, "The name of the load balancer."
28
70
 
29
71
  c.action do |args, options|
30
- options.default(
31
- attributes: "instance_id,tag:Name,instance_type,private_ip_address,public_ip_address,state.name",
32
- format: "table",
33
- order: "tag:Name",
34
- )
35
-
36
- set_client(options)
37
-
38
- search = if options.search
39
- options.search.split(",").map {|s| s.split("=")}.inject Hash.new do |acc, pair|
40
- acc.merge pair.first => pair.last
41
- end
42
- else
43
- {}
72
+ invoke options do
73
+ mandatory options, :load_balancer_name
74
+ @client.elb_status
44
75
  end
76
+ end
77
+ end
78
+
79
+ command :"elb attach" do |c|
80
+ c.syntax = "ec2ctl elb attach"
81
+ c.description = "Attach the instances to the load balancer."
82
+
83
+ c.option "-b", "--load-balancer-name VALUE", String, "The name of the load balancer."
84
+ c.option "-i", "--instance-ids STRING1,STRING2", Array, "(Optional) The IDs of the instances to attach."
45
85
 
46
- attributes = (options.attributes.split(",") + search.keys).uniq
47
- instance_infos = client.instance_infos(attributes, search).sort_by {|i| i[options.order]}
48
-
49
- if instance_infos.empty?
50
- say "Instance not found."
51
- else
52
- case options.format
53
- when /table/i
54
- say tableize(attributes, instance_infos)
55
- when /markdown/i
56
- say tableize(attributes, instance_infos, :markdown)
57
- when /backlog/i
58
- say tableize(attributes, instance_infos, :backlog)
59
- when /json/i
60
- say JSON.pretty_generate(instance_infos)
61
- when /yaml/i
62
- say instance_infos.to_yaml
63
- end
86
+ c.action do |args, options|
87
+ invoke options do
88
+ mandatory options, :load_balancer_name, :instance_ids
89
+ @client.elb_attach
64
90
  end
65
91
  end
66
92
  end
67
93
 
68
- alias_command :ls, :list
94
+ command :"elb detach" do |c|
95
+ c.syntax = "ec2ctl elb detach"
96
+ c.description = "Detach the instances from the load balancer."
97
+
98
+ c.option "-b", "--load-balancer-name VALUE", String, "The name of the load balancer."
99
+ c.option "-i", "--instance-ids STRING1,STRING2", Array, "(Optional) The IDs of the instances to detach."
100
+
101
+ c.action do |args, options|
102
+ invoke options do
103
+ mandatory options, :load_balancer_name, :instance_ids
104
+ @client.elb_detach
105
+ end
106
+ end
107
+ end
108
+
109
+ command :"elb execute" do |c|
110
+ c.syntax = "ec2ctl elb execute"
111
+ c.description = "Execute commands on instance(s) registered to a load balancer."
112
+
113
+ elb_execute_options c
114
+
115
+ c.action do |args, options|
116
+ invoke options do
117
+ mandatory options, :load_balancer_name, :commands
118
+ @client.elb_execute
119
+ end
120
+ end
121
+ end
122
+
123
+ command :"elb graceful" do |c|
124
+ c.syntax = "ec2ctl elb graceful"
125
+ c.description = "Sequencially deregister instance(s) from load balancer, execute commands, register it back to load balancer and wait until it's in `InService` state."
126
+
127
+ elb_execute_options c
128
+
129
+ c.action do |args, options|
130
+ invoke options do
131
+ mandatory options, :load_balancer_name, :commands
132
+ @client.elb_graceful
133
+ end
134
+ end
135
+ end
69
136
 
70
137
  run!
71
138
  end
72
139
 
73
140
  private
74
141
 
75
- def tableize(attributes, instance_infos, mode = nil)
76
- table = Terminal::Table.new(
77
- headings: attributes,
78
- rows: instance_infos.map {|i| attributes.map {|a| i[a]}}
142
+ def init_client(options)
143
+ global_options = %i(
144
+ verbose
145
+ pretty
146
+ output
147
+ profile
148
+ region
149
+ trace
150
+ version
151
+ help
152
+ )
153
+
154
+ @client = EC2Ctl::Client.new options.__hash__.reject {|k, v| global_options.include? k}.merge(logger: logger)
155
+ end
156
+
157
+ def logger
158
+ @logger ||= EC2Ctl::Logger.new(
159
+ output_format: (@output_format || :json),
160
+ pretty: @pretty,
161
+ verbose: @verbose,
79
162
  )
163
+ end
164
+
165
+ def invoke(options, &block)
166
+ begin
167
+ debug_init options
168
+ init_client options
169
+ block.call
170
+ rescue => ex
171
+ logger.error(
172
+ error: {
173
+ class: ex.class,
174
+ message: ex.message
175
+ }
176
+ )
177
+
178
+ raise
179
+ end
180
+ end
80
181
 
81
- case mode
82
- when :markdown
83
- lines = table.to_s.lines[1..-2]
84
- lines[1].gsub!("+", "|")
85
- lines.join
86
- when :backlog
87
- lines = table.to_s.lines[1..-2]
88
- lines[0].sub!("\n", "h\n")
89
- lines[1] = nil
90
- lines.compact.join
91
- else
92
- table
182
+ # e.g.
183
+ #
184
+ # mandatory options, :load_balancer_name, :commands
185
+ #
186
+ def mandatory(options, *option_names)
187
+ option_names.each do |option_name|
188
+ fail OptionError, "Option `#{option_name}` is mandatory." if options.__send__(option_name).nil?
93
189
  end
94
190
  end
95
191
 
96
- def client
97
- @client
192
+ # only for debug output
193
+ def aws_env
194
+ {
195
+ AWS_ACCESS_KEY_ID: ("#{ENV["AWS_ACCESS_KEY_ID"][0, 5]}..." if ENV["AWS_ACCESS_KEY_ID"]),
196
+ AWS_SECRET_ACCESS_KEY: ("#{ENV["AWS_SECRET_ACCESS_KEY"][0, 5]}..." if ENV["AWS_SECRET_ACCESS_KEY"]),
197
+ AWS_PROFILE: ENV["AWS_PROFILE"],
198
+ AWS_REGION: ENV["AWS_REGION"],
199
+ }
98
200
  end
99
201
 
100
- def set_client(options)
101
- o = {}
102
- o[:profile] = options.profile if options.profile
103
- o[:region] = options.region if options.region
202
+ def debug_init(options)
203
+ logger.debug options: options.__hash__
204
+ logger.debug aws_env: aws_env
205
+ end
206
+
207
+ def elb_execute_options(_command)
208
+ _command.option "-b", "--load-balancer-name STRING", String, "The name of the load balancer."
209
+ _command.option "-c", "--commands 'STRING1','STRING2',...", Array, "The commands to execute."
210
+ _command.option "-P", "--platform-type Linux|Windows", String, "(Optional) Platform type: `Linux` or `Windows`. Default is `Linux`."
211
+ _command.option "--skip-ping-check", "(Optional) Skip SSM ping check."
212
+ _command.option "--skip-command-waits", "(Optional) Skip waiting command success."
213
+ _command.option "--wait-interval INTEGER", Integer, "(Optional) Waiting interval."
214
+ _command.option "--working-directory STRING", String, "(Optional) The path to the working directory on your instance."
215
+ _command.option "--execution-timeout INTEGER", Integer, "(Optional) The time in seconds for a command to be completed before it is considered to have failed. Default is 3600 (1 hour). Maximum is 28800 (8 hours)."
216
+ _command.option "--timeout-seconds INTEGER", Integer, "(Optional) If this time is reached and the command has not already started executing, it will not execute."
217
+ _command.option "--comment STRING", String, "(Optional) User-specified information about the command, such as a brief description of what the command should do."
218
+ _command.option "--output-s3-bucket-name STRING", String, "(Optional) The name of the S3 bucket where command execution responses should be stored."
219
+ _command.option "--output-s3-key-prefix STRING", String, "(Optional) The directory structure within the S3 bucket where the responses should be stored."
220
+ _command.option "--service-role-arn STRING", String, "(Optional) The IAM role that SSM uses to send notifications."
221
+ _command.option "--notification-arn STRING", String, "(Optional) An Amazon Resource Name (ARN) for a Simple Notification Service (SNS) topic."
222
+ _command.option "--notification-events STRING1,STRING2,...", Array, "(Optional) The different events for which you can receive notifications."
223
+ _command.option "--notification-type STRING", String, "(Optional) Command: Receive notification when the status of a command changes."
224
+ _command.option "--rolling-group-size INTEGER", Integer, "(Optional) The count of instances to register/deregister/execute simultaneously."
225
+ _command.option "--skip-draining-waits", "(Optional) Skip waiting connection draining after deregistering instances from load balancer."
226
+ _command.option "--skip-inservice-waits", "(Optional) Skip waiting `InService` state after registering instances to load balancer."
227
+ _command.option "--inservice-wait-timeout INTEGER", Integer, "(Optional) The time in seconds for instances to be `InService` state after registering to load balancer."
228
+ _command.option "-i", "--instance-ids STRING1,STRING2", Array, "(Optional) The IDs of the instances. If specified, the commands will be executed only on these instances."
229
+ end
104
230
 
105
- @client = EC2Ctl::Client.new(o)
231
+ def ec2_options(_command)
232
+ _command.option "-a", "--attributes KEY1,KEY2...", Array, "(Optional) The instance attribute keys to display."
233
+ _command.option "-f", "--filters KEY1=VALUE1,KEY2=VALUE2...", Array, "(Optional) The key-value pairs to filter instances."
234
+ _command.option "-s", "--search KEY1=VALUE1,KEY2=VALUE2...", Array, "(Optional) The key-value pairs to search instances by Regexp."
235
+ _command.option "-i", "--instance-ids STRING1,STRING2", Array, "(Optional) The IDs of the instances."
106
236
  end
107
237
  end
108
238
  end