elastic_whenever 0.1.1 → 0.2.0

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: b08fd8f4fb4826af5a1863a42cb29c9ece9ec66a
4
- data.tar.gz: d3030170100ddaa8d00480e0985e14853503ef78
3
+ metadata.gz: 279fa293930adedd6b35d4fbf629c8b647c09b35
4
+ data.tar.gz: d2949e35f69c75489f38fc9e9b45a655c06de5b4
5
5
  SHA512:
6
- metadata.gz: c9e571272b10b3f871773d3326a1bfc16a9fb0fb96a14a2316bfa635840189b176d58244020f696daff20004079f4c00686671b1cdca71e256f4392f4a814370
7
- data.tar.gz: 593d852b48bd44d977379750c9154e65e88218c58ca7fecd28a2701c6e428a01dc82d490a7349fb94c28ef46a8e630dd5186b2748c315c257e08968734789524
6
+ metadata.gz: bdd1cf72a17f318c78ad1e27fb6340761e064ace66c4a45b8942437dc302a8a06b984a0cf16b95afad9199c13b9d650c8d56be5fbb29471d7afc33d2d5599301
7
+ data.tar.gz: 74528044ab14b01dfdf3c40910b2049ffae4b06c56476033d2374910e3a5c58e45793bb7a5f06f70f41a314d1dd6ecd2b2dc56414a5a8500489c30080c10ae6b
data/.travis.yml CHANGED
@@ -1,5 +1,5 @@
1
1
  sudo: false
2
2
  language: ruby
3
3
  rvm:
4
- - 2.3.0
4
+ - 2.4.2
5
5
  before_install: gem install bundler -v 1.15.4
data/README.md CHANGED
@@ -39,7 +39,23 @@ Usage: elastic_whenever [options]
39
39
  -v, --version Print version
40
40
  ```
41
41
 
42
- However, please be aware that you must specify an identifier.
42
+ However, please be aware that you must specify an identifier. Also, you must specify the cluster, task definition and container name in schedule file.
43
+
44
+ ```ruby
45
+ set :cluster, 'ecs-test' # ECS cluster name
46
+ set :task_definition, 'oneoff-application:2' # Task definition name, If omit the revision, use the latest revision of family automatically.
47
+ set :container, 'oneoff' # Container name of task definition
48
+
49
+ every :day, at: '03:00am' do
50
+ runner 'Hoge.run'
51
+ end
52
+ ```
53
+
54
+ If you do not write it in the schedule file, specify it with arguments.
55
+
56
+ ```
57
+ $ elastic_whenever -i test --set 'environment=staging&cluster=ecs-test&task_definition=oneoff-application:2&container=oneoff'
58
+ ```
43
59
 
44
60
  NOTE: Currently, it supports only the syntax of whenever partially. We recommend to check what happens beforehand with the `elastic_whenever` command.
45
61
 
@@ -28,10 +28,15 @@ module ElasticWhenever
28
28
  end
29
29
 
30
30
  SUCCESS_EXIT_CODE
31
+ rescue Aws::Errors::MissingRegionError
32
+ Logger.instance.fail("missing region error occurred; please use `--region` option or export `AWS_REGION` environment variable.")
33
+ ERROR_EXIT_CODE
34
+ rescue Aws::Errors::MissingCredentialsError
35
+ Logger.instance.fail("missing credential error occurred; please specify it with arguments, use shared credentials, or export `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY` environment variable.")
36
+ ERROR_EXIT_CODE
31
37
  rescue OptionParser::MissingArgument,
32
38
  Option::InvalidOptionException,
33
- Schedule::InvalidScheduleException,
34
- Aws::Errors::MissingCredentialsError => exn
39
+ Schedule::InvalidScheduleException => exn
35
40
 
36
41
  Logger.instance.fail(exn.message)
37
42
  ERROR_EXIT_CODE
@@ -40,10 +45,7 @@ module ElasticWhenever
40
45
  private
41
46
 
42
47
  def update_tasks(option, dry_run:)
43
- schedule = Schedule.new(option.schedule_file)
44
- option.variables.each do |var|
45
- schedule.set(var[:key], var[:value])
46
- end
48
+ schedule = Schedule.new(option.schedule_file, option.variables)
47
49
  schedule.validate!
48
50
 
49
51
  cluster = Task::Cluster.new(option, schedule.cluster)
@@ -55,7 +57,12 @@ module ElasticWhenever
55
57
 
56
58
  clear_tasks(option) unless dry_run
57
59
  schedule.tasks.each do |task|
58
- rule = Task::Rule.convert(option, task)
60
+ begin
61
+ rule = Task::Rule.convert(option, task, schedule.chronic_options)
62
+ rescue Task::Rule::UnsupportedOptionException => exn
63
+ Logger.instance.warn(exn.message)
64
+ next
65
+ end
59
66
  targets = task.commands.map do |command|
60
67
  Task::Target.new(
61
68
  option,
@@ -71,7 +78,12 @@ module ElasticWhenever
71
78
  if dry_run
72
79
  print_task(rule, targets)
73
80
  else
74
- rule.create
81
+ begin
82
+ rule.create
83
+ rescue Aws::CloudWatchEvents::Errors::ValidationException => exn
84
+ Logger.instance.warn("#{exn.message} Ignore this task: name=#{rule.name} expression=#{rule.expression}")
85
+ next
86
+ end
75
87
  targets.each(&:create)
76
88
  end
77
89
  end
@@ -83,8 +95,8 @@ module ElasticWhenever
83
95
 
84
96
  def list_tasks(option)
85
97
  Task::Rule.fetch(option).each do |rule|
86
- target = Task::Target.fetch(option, rule)
87
- print_task(rule, target)
98
+ targets = Task::Target.fetch(option, rule)
99
+ print_task(rule, targets)
88
100
  end
89
101
  end
90
102
 
@@ -3,11 +3,11 @@ module ElasticWhenever
3
3
  include Singleton
4
4
 
5
5
  def fail(message)
6
- puts "[fail] #{message}"
6
+ STDERR.puts "[fail] #{message}"
7
7
  end
8
8
 
9
9
  def warn(message)
10
- puts "[warn] #{message}"
10
+ STDERR.puts "[warn] #{message}"
11
11
  end
12
12
 
13
13
  def log(event, message)
@@ -18,4 +18,4 @@ module ElasticWhenever
18
18
  puts "## [message] #{message}"
19
19
  end
20
20
  end
21
- end
21
+ end
@@ -4,15 +4,21 @@ module ElasticWhenever
4
4
  attr_reader :cluster
5
5
  attr_reader :task_definition
6
6
  attr_reader :container
7
+ attr_reader :chronic_options
8
+ attr_reader :bundle_command
7
9
 
8
10
  class InvalidScheduleException < StandardError; end
9
11
 
10
- def initialize(file, environment: "production")
11
- @environment = environment
12
+ def initialize(file, variables)
13
+ @environment = "production"
12
14
  @tasks = []
13
15
  @cluster = nil
14
16
  @task_definition = nil
15
17
  @container = nil
18
+ @chronic_options = {}
19
+ @bundle_command = "bundle exec"
20
+
21
+ variables.each { |var| set(var[:key], var[:value]) }
16
22
  instance_eval(File.read(file), file)
17
23
  end
18
24
 
@@ -21,7 +27,7 @@ module ElasticWhenever
21
27
  end
22
28
 
23
29
  def every(frequency, options = {}, &block)
24
- @tasks << Task.new(@environment, frequency, options).tap do |task|
30
+ @tasks << Task.new(@environment, @bundle_command, frequency, options).tap do |task|
25
31
  task.instance_eval(&block)
26
32
  end
27
33
  end
@@ -31,5 +37,9 @@ module ElasticWhenever
31
37
  raise InvalidScheduleException.new("You must set task definition") unless task_definition
32
38
  raise InvalidScheduleException.new("You must set container") unless container
33
39
  end
40
+
41
+ def method_missing(name, *args)
42
+ Logger.instance.warn("Skipping unsupported method: #{name}")
43
+ end
34
44
  end
35
45
  end
@@ -4,33 +4,32 @@ module ElasticWhenever
4
4
  attr_reader :frequency
5
5
  attr_reader :options
6
6
 
7
- def initialize(environment, frequency, options = {})
7
+ def initialize(environment, bundle_command, frequency, options = {})
8
8
  @environment = environment
9
+ @bundle_command = bundle_command.split(" ")
9
10
  @frequency = frequency
10
11
  @options = options
11
12
  @commands = []
12
13
  end
13
14
 
14
- def runner(src)
15
- @commands << [
16
- "bundle",
17
- "exec",
18
- "bin/rails",
19
- "runner",
20
- "-e",
21
- @environment,
22
- src
23
- ]
15
+ def command(task)
16
+ @commands << task.split(" ")
24
17
  end
25
18
 
26
19
  def rake(task)
27
- @commands << [
28
- "bundle",
29
- "exec",
30
- "rake",
31
- task,
32
- "--silent"
33
- ]
20
+ @commands << [@bundle_command, "rake", task, "--silent"].flatten
21
+ end
22
+
23
+ def runner(src)
24
+ @commands << [@bundle_command, "bin/rails", "runner", "-e", @environment, src].flatten
25
+ end
26
+
27
+ def script(script)
28
+ @commands << [@bundle_command, "script/#{script}"].flatten
29
+ end
30
+
31
+ def method_missing(name, *args)
32
+ Logger.instance.warn("Skipping unsupported method: #{name}")
34
33
  end
35
34
  end
36
35
  end
@@ -4,6 +4,8 @@ module ElasticWhenever
4
4
  attr_reader :name
5
5
  attr_reader :expression
6
6
 
7
+ class UnsupportedOptionException < StandardError; end
8
+
7
9
  def self.fetch(option)
8
10
  client = Aws::CloudWatchEvents::Client.new(option.aws_config)
9
11
  client.list_rules(name_prefix: option.identifier).rules.map do |rule|
@@ -15,11 +17,11 @@ module ElasticWhenever
15
17
  end
16
18
  end
17
19
 
18
- def self.convert(option, task)
20
+ def self.convert(option, task, chronic_options)
19
21
  self.new(
20
22
  option,
21
23
  name: rule_name(option.identifier, task.commands),
22
- expression: schedule_expression(task.frequency, task.options)
24
+ expression: schedule_expression(task.frequency, task.options, chronic_options)
23
25
  )
24
26
  end
25
27
 
@@ -39,7 +41,7 @@ module ElasticWhenever
39
41
 
40
42
  def delete
41
43
  targets = client.list_targets_by_rule(rule: name).targets
42
- client.remove_targets(rule: name, ids: targets.map(&:id))
44
+ client.remove_targets(rule: name, ids: targets.map(&:id)) unless targets.empty?
43
45
  client.delete_rule(name: name)
44
46
  end
45
47
 
@@ -49,19 +51,53 @@ module ElasticWhenever
49
51
  "#{identifier}_#{Digest::SHA1.hexdigest(commands.map { |command| command.join("-") }.join("-"))}"
50
52
  end
51
53
 
52
- def self.schedule_expression(frequency, options)
53
- time = Chronic.parse(options[:at]) || Time.new(2017, 9, 9, 0, 0, 0)
54
+ def self.schedule_expression(frequency, options, chronic_options)
55
+ time = Chronic.parse(options[:at], chronic_options) || Time.new(2017, 12, 1, 0, 0, 0)
54
56
 
55
57
  case frequency
56
58
  when :hour
57
- "cron(#{time.hour} * * * ? *)"
59
+ "cron(#{time.min} * * * ? *)"
58
60
  when :day
59
61
  "cron(#{time.min} #{time.hour} * * ? *)"
60
- else
62
+ when :month
63
+ "cron(#{time.min} #{time.hour} #{time.day} * ? *)"
64
+ when :year
65
+ "cron(#{time.min} #{time.hour} #{time.day} #{time.month} ? *)"
66
+ when :sunday
67
+ "cron(#{time.min} #{time.hour} ? * 1 *)"
68
+ when :monday
69
+ "cron(#{time.min} #{time.hour} ? * 2 *)"
70
+ when :tuesday
71
+ "cron(#{time.min} #{time.hour} ? * 3 *)"
72
+ when :wednesday
73
+ "cron(#{time.min} #{time.hour} ? * 4 *)"
74
+ when :thursday
75
+ "cron(#{time.min} #{time.hour} ? * 5 *)"
76
+ when :friday
77
+ "cron(#{time.min} #{time.hour} ? * 6 *)"
78
+ when :saturday
79
+ "cron(#{time.min} #{time.hour} ? * 7 *)"
80
+ when :weekend
81
+ "cron(#{time.min} #{time.hour} ? * 1,7 *)"
82
+ when :weekday
83
+ "cron(#{time.min} #{time.hour} ? * 2-6 *)"
84
+ # cron syntax
85
+ when /^((\*?[\d\/,\-]*)\s*){5}$/
61
86
  min, hour, day, mon, week, year = frequency.split(" ")
62
- week.gsub!("*", "?")
87
+ # You can't specify the Day-of-month and Day-of-week fields in the same Cron expression.
88
+ # If you specify a value in one of the fields, you must use a ? (question mark) in the other.
89
+ week.gsub!("*", "?") if day != "?"
90
+ day.gsub!("*", "?") if week != "?"
91
+ # cron syntax: sunday -> 0
92
+ # scheduled expression: sunday -> 1
93
+ week.gsub!(/(\d)/) { (Integer($1) + 1) % 7 }
63
94
  year = year || "*"
64
95
  "cron(#{min} #{hour} #{day} #{mon} #{week} #{year})"
96
+ # schedule expression syntax
97
+ when /^((\*?\??L?W?[\d\/,\-]*)\s*){6}$/
98
+ "cron(#{frequency})"
99
+ else
100
+ raise UnsupportedOptionException.new("`#{frequency}` is not supported option. Ignore this task.")
65
101
  end
66
102
  end
67
103
 
@@ -1,3 +1,3 @@
1
1
  module ElasticWhenever
2
- VERSION = "0.1.1"
2
+ VERSION = "0.2.0"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: elastic_whenever
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kazuma Watanabe
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2017-09-12 00:00:00.000000000 Z
11
+ date: 2017-09-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -157,9 +157,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
157
157
  version: '0'
158
158
  requirements: []
159
159
  rubyforge_project:
160
- rubygems_version: 2.6.11
160
+ rubygems_version: 2.6.13
161
161
  signing_key:
162
162
  specification_version: 4
163
163
  summary: Manage ECS Scheduled Tasks like Whenever
164
164
  test_files: []
165
- has_rdoc: