full360-sequencer 0.0.2

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.
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: []