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 +4 -4
- data/.travis.yml +1 -1
- data/README.md +17 -1
- data/lib/elastic_whenever/cli.rb +22 -10
- data/lib/elastic_whenever/logger.rb +3 -3
- data/lib/elastic_whenever/schedule.rb +13 -3
- data/lib/elastic_whenever/task.rb +17 -18
- data/lib/elastic_whenever/task/rule.rb +44 -8
- data/lib/elastic_whenever/version.rb +1 -1
- metadata +3 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 279fa293930adedd6b35d4fbf629c8b647c09b35
|
4
|
+
data.tar.gz: d2949e35f69c75489f38fc9e9b45a655c06de5b4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bdd1cf72a17f318c78ad1e27fb6340761e064ace66c4a45b8942437dc302a8a06b984a0cf16b95afad9199c13b9d650c8d56be5fbb29471d7afc33d2d5599301
|
7
|
+
data.tar.gz: 74528044ab14b01dfdf3c40910b2049ffae4b06c56476033d2374910e3a5c58e45793bb7a5f06f70f41a314d1dd6ecd2b2dc56414a5a8500489c30080c10ae6b
|
data/.travis.yml
CHANGED
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
|
|
data/lib/elastic_whenever/cli.rb
CHANGED
@@ -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
|
-
|
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
|
-
|
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
|
-
|
87
|
-
print_task(rule,
|
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,
|
11
|
-
@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
|
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
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
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,
|
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.
|
59
|
+
"cron(#{time.min} * * * ? *)"
|
58
60
|
when :day
|
59
61
|
"cron(#{time.min} #{time.hour} * * ? *)"
|
60
|
-
|
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.
|
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
|
|
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.
|
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-
|
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.
|
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:
|