full360-sequencer 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (4) hide show
  1. checksums.yaml +7 -0
  2. data/bin/sequencer +36 -0
  3. data/lib/full360-sequencer.rb +146 -0
  4. metadata +89 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 61e19b3c9ee3020cf5722e1c6caed5168fa5ddd2702105fb4a206bdfa58f9cbe
4
+ data.tar.gz: e2b2f543e1e495c65d7c9556a5bba6c122ca3a802b46acb993e6be61a1b0bc87
5
+ SHA512:
6
+ metadata.gz: 20ea331819a466dd1e91dca8297222ee02f7a9d3393ab77f95a58deaf3a180b4c9c84e59443fafa42c060ce7fc40e16954d30759b813b1ed8047c4791e72da04
7
+ data.tar.gz: efa98dec9320a33e126ccb3e0c7d6c8866218b5d5ef71589e727d07e197eba38dadfaaff3b1a6467bc3ccc7262e29217f16f03b9c7fc4973a5e159296578c591
data/bin/sequencer ADDED
@@ -0,0 +1,36 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'full360-sequencer'
4
+
5
+ config_file = ARGV[0]
6
+
7
+ # configure global logger
8
+ module Sequencer
9
+ Log = Logger.new(STDOUT)
10
+ end
11
+
12
+ def logger
13
+ Sequencer::Log
14
+ end
15
+
16
+ def sequencer_version
17
+ Gem.loaded_specs['full360-sequencer'].version
18
+ end
19
+
20
+ begin
21
+ logger.info("sequencer version #{sequencer_version}")
22
+ logger.level = ENV['SEQUENCER_LOG_DEBUG'] ? Logger::DEBUG : Logger::INFO
23
+
24
+ if config_file == nil
25
+ logger.error('YAML file not provided... exiting with error code 1')
26
+ exit 1
27
+ else
28
+ r = Full360::Sequencer::Runner.new(logger)
29
+ r.config_from_file(config_file)
30
+ r.sleep_between_checks = ENV['SEQUENCER_SLEEP_BETWEEN_CHECKS'].to_i if ENV['SEQUENCER_SLEEP_BETWEEN_CHECKS']
31
+ r.run
32
+ end
33
+ rescue => e
34
+ logger.error(e.message)
35
+ e.backtrace.each { |r| logger.error(r) }
36
+ end
@@ -0,0 +1,146 @@
1
+ #!/usr/bin/ruby
2
+ require 'aws-sdk'
3
+ require 'yaml'
4
+ require 'logger'
5
+ require 'pp'
6
+
7
+ module Full360
8
+ module Sequencer
9
+ class Runner
10
+ attr_accessor :sleep_between_checks
11
+ attr_accessor :config
12
+
13
+ def initialize(logger = nil)
14
+ @logger = logger ? logger : Logger.new(STDOUT)
15
+
16
+ # default 5 seconds between completed? checks
17
+ @sleep_between_checks = 5
18
+ end
19
+
20
+ def config_from_file(yaml_path)
21
+ @config = parse_config_file(yaml_path)
22
+ end
23
+
24
+ def run_task_class(task_type_string)
25
+ case task_type_string
26
+ when 'ecs_task' then Full360::Sequencer::RunECSTask
27
+ else nil
28
+ end
29
+ end
30
+
31
+ def run
32
+ @config.each do |params|
33
+ this_task_name = task_name(params)
34
+ this_task = run_task_class(params[this_task_name]['type']).new(
35
+ this_task_name,
36
+ params[this_task_name]
37
+ )
38
+ this_task.run_task
39
+ until this_task.completed?
40
+ sleep @sleep_between_checks
41
+ end
42
+ raise "task failed error" unless this_task.success
43
+ end
44
+ rescue => e
45
+ @logger.error(e.message)
46
+ e.backtrace.each { |r| @logger.error(r) }
47
+ end
48
+
49
+ def task_name(params)
50
+ params.keys.first
51
+ end
52
+
53
+ def parse_config_file(yaml_path)
54
+ YAML.load_file(yaml_path)
55
+ end
56
+
57
+ def config_valid?(config)
58
+ return false unless config.is_a? Array
59
+ true
60
+ end
61
+ end
62
+
63
+ class RunTaskBase
64
+ attr_reader :success
65
+ attr_reader :exit_code
66
+
67
+ def run_task; end
68
+ def completed?; end
69
+ def kill_task; end #will be used for timeout
70
+ end
71
+
72
+ class RunECSTask < RunTaskBase
73
+ def initialize(task_name, params, logger = nil)
74
+ @logger = logger ? logger : Logger.new(STDOUT)
75
+ @task_name = task_name
76
+ @params = params['parameters']
77
+ @params = keys_to_symbol(@params)
78
+ @cluster = @params[:cluster]
79
+ end
80
+
81
+ def keys_to_symbol(params)
82
+ # replaces string keys with symbol keys
83
+ # required by AWS SDK
84
+ if params.is_a?(Hash)
85
+ params.inject({}){ |memo,(k,v)| memo[k.to_sym] = v; memo }
86
+ else
87
+ nil
88
+ end
89
+ end
90
+
91
+ def run_task
92
+ @logger.info("starting ECS task #{@task_name}")
93
+ @logger.debug("creating AWS client for ECS task #{@task_name}...")
94
+ @ecs_client = ::Aws::ECS::Client.new
95
+ @logger.debug("running ECS task #{@task_name}...")
96
+ @start_time = Time.new
97
+ resp = @ecs_client.run_task(@params)
98
+ @task_arn = resp.tasks[0].task_arn
99
+ @logger.info("#{@task_name} task created #{@task_arn} on cluster #{@cluster}")
100
+ end
101
+
102
+ def ecs_describe_tasks
103
+ @ecs_client.describe_tasks(
104
+ {
105
+ cluster: @cluster,
106
+ tasks: [@task_arn] # required
107
+ }
108
+ )
109
+ end
110
+
111
+ def completed?
112
+ resp = ecs_describe_tasks
113
+ status = last_task_status(resp)
114
+ @logger.info("#{@task_name} : #{@task_arn} current status: #{status}")
115
+ if status == 'STOPPED'
116
+ @logger.info("#{@task_name} completed in #{Time.new - @start_time} seconds")
117
+ # parse exit_code(s) and return completion
118
+ @success = determine_success(resp)
119
+ return true
120
+ end
121
+ false
122
+ rescue => e
123
+ @logger.error(e.message)
124
+ e.backtrace.each { |r| @logger.error(r) }
125
+ end
126
+
127
+ # parses last status from aws API response
128
+ def last_task_status(resp)
129
+ resp.tasks[0].last_status
130
+ end
131
+
132
+ # success is determined by all containers having zero exit code
133
+ def determine_success(resp)
134
+ success = true
135
+ resp.tasks[0].containers.each do |c|
136
+ @logger.info("#{@task_name} : container #{c.name} #{c.container_arn} completed with exit_code #{c.exit_code}")
137
+ if c.exit_code != 0
138
+ # we had a problem!
139
+ success = false
140
+ end
141
+ end
142
+ success
143
+ end
144
+ end
145
+ end
146
+ end
metadata ADDED
@@ -0,0 +1,89 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: full360-sequencer
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.2
5
+ platform: ruby
6
+ authors:
7
+ - pankaj batra
8
+ - jeremy winters
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2017-06-22 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.2'
20
+ name: logger
21
+ prerelease: false
22
+ type: :runtime
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - "~>"
26
+ - !ruby/object:Gem::Version
27
+ version: '1.2'
28
+ - !ruby/object:Gem::Dependency
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '2.9'
34
+ name: aws-sdk
35
+ prerelease: false
36
+ type: :runtime
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - "~>"
40
+ - !ruby/object:Gem::Version
41
+ version: '2.9'
42
+ - !ruby/object:Gem::Dependency
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '5.9'
48
+ name: minitest
49
+ prerelease: false
50
+ type: :development
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - "~>"
54
+ - !ruby/object:Gem::Version
55
+ version: '5.9'
56
+ description: automation for simple batch jobs run in AWS
57
+ email: pankaj.batra@full360.com
58
+ executables:
59
+ - sequencer
60
+ extensions: []
61
+ extra_rdoc_files: []
62
+ files:
63
+ - bin/sequencer
64
+ - lib/full360-sequencer.rb
65
+ homepage: https://www.full360.com
66
+ licenses:
67
+ - MIT
68
+ metadata: {}
69
+ post_install_message:
70
+ rdoc_options: []
71
+ require_paths:
72
+ - lib
73
+ required_ruby_version: !ruby/object:Gem::Requirement
74
+ requirements:
75
+ - - ">="
76
+ - !ruby/object:Gem::Version
77
+ version: '2.0'
78
+ required_rubygems_version: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ requirements: []
84
+ rubyforge_project:
85
+ rubygems_version: 2.6.11
86
+ signing_key:
87
+ specification_version: 4
88
+ summary: full360 sequencer utility
89
+ test_files: []