whenever-eb-shipoffers 1.0.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 391a39f62b49a6e75cf82937fd402d956e536ca8
4
+ data.tar.gz: 81a687b539838ba6d9a20b518d6331c774fbf8b1
5
+ SHA512:
6
+ metadata.gz: 079e8f42b72422c5319667f8832aaf80354b426083ac52356b4a6134725bb7182fbc31187893dc67decf75c39ecf5a505a54621f6b70f851aa0312d58a26e0e0
7
+ data.tar.gz: ce3c643622b2ca6e5a0b7c688f04d5537f4de52449a55dde8eba81780fd8d1b781001686a93649941b6d2a8b386670e627d89de7a995cda9a53bba23900e25fe
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in whenever-elasticbeanstalk.gemspec
4
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2016 Zachary Green
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,102 @@
1
+ # Whenever::Elasticbeanstalk for ShipOffers
2
+
3
+ Whenever-elasticbeanstalk is an extension gem to [Whenever](https://github.com/javan/whenever) that automatically ensures that one instance in an AWS Elastic Beanstalk environment is set as leader. This allows you to run cron jobs on all instances, or just on the leader. This is required since Elastic Beanstalk may start or stop any instance as it scales up or down.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem 'whenever-elasticbeanstalk'
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ ```bash
16
+ $ bundle
17
+ ```
18
+
19
+ Or install it yourself as:
20
+
21
+ ```bash
22
+ $ gem install whenever-elasticbeanstalk
23
+ ```
24
+
25
+ ## Getting started
26
+ ```bash
27
+ $ cd /apps/my-great-project
28
+ $ wheneverize-eb .
29
+ ```
30
+
31
+ This will create an initial `config/schedule.rb` file for you with the `ensure_leader` job set to run every minute. It will also create a `.ebextensions/cron.config` file that will automatically choose a leader on environment initialization, and start up Whenever with the correct `leader` role. Lastly, it creates the `config/whenever-elasticbeanstalk.yml` file that will contain your AWS credentials for retrieving your environment information.
32
+
33
+ ### Manually updating schedule
34
+
35
+ If you are already using Whenever, running `wheneverize-eb .` won't overwrite your `config/schedule.rb` file. You'll need to add the following lines in order for your environment to always have one leader.
36
+
37
+ ```ruby
38
+ every 1.minute do
39
+ command "cd /var/app/current && bundle exec ensure_one_cron_leader"
40
+ end
41
+ ```
42
+
43
+ ### EC2 Instance IAM Role Permissions
44
+
45
+ In order for the scripts to work, you need to ensure that the EC2 Instance Role has access to EC2 instances and tags (further reading at [AWS Documentation](http://docs.aws.amazon.com/elasticbeanstalk/latest/dg/AWSHowTo.iam.roles.aeb.html) ). Ensure that your EC2 instance has at a minimum the following permissions:
46
+
47
+ Example policy:
48
+ ```json
49
+ {
50
+ "Version": "2012-10-17",
51
+ "Statement": [
52
+ {
53
+ "Action": [
54
+ "ec2:DescribeInstanceAttribute",
55
+ "ec2:DescribeInstanceStatus",
56
+ "ec2:DescribeInstances",
57
+ "ec2:DescribeTags",
58
+ "ec2:CreateTags"
59
+ ],
60
+ "Resource": [
61
+ "*"
62
+ ],
63
+ "Effect": "Allow"
64
+ }
65
+ ]
66
+ }
67
+ ```
68
+
69
+ Make sure to add the `RACK_ENV` environment variable to your environment if you haven't already done so. This variable is not created automatically by AWS. You can add the following line to your `.elasticbeanstalk/optionsettings.appname-env` file:
70
+ ```yaml
71
+ RACK_ENV=staging
72
+ ```
73
+
74
+ ## Usage
75
+
76
+ For `config/schedule.rb` usage, please see the documentation for the [Whenever gem](https://github.com/javan/whenever).
77
+
78
+ ### Run a task on only one instance
79
+
80
+ To run a task only on one instance, assign the task to the `leader` role.
81
+ ```ruby
82
+ every :day, :at => "12:30am", :roles => [:leader] do
83
+ runner "MyModel.task_to_run_nightly_only_on_one_instance"
84
+ end
85
+ ```
86
+
87
+ ### Run a task on all instances
88
+
89
+ To run a task on all instance, omit the `roles` option.
90
+ ```ruby
91
+ every 1.minute do
92
+ command "touch $EB_CONFIG_APP_SUPPORT/.cron_check"
93
+ end
94
+ ```
95
+
96
+ ## Contributing
97
+
98
+ 1. Fork it
99
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
100
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
101
+ 4. Push to the branch (`git push origin my-new-feature`)
102
+ 5. Create new Pull Request
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,61 @@
1
+ #!/usr/bin/ruby
2
+
3
+ require 'optparse'
4
+ require 'rubygems'
5
+ gem 'aws-sdk', '~> 2'
6
+ require 'aws-sdk'
7
+ require 'erb'
8
+
9
+ EB_CONFIG_APP_SUPPORT = "/opt/elasticbeanstalk/support"
10
+ ENVIRONMENT_NAME_FILE = File.join(EB_CONFIG_APP_SUPPORT,'env_name')
11
+
12
+ # Options Parsing
13
+ options = {}
14
+ optparse = OptionParser.new do |opts|
15
+ opts.banner = "Usage: #{File.basename($0)} [options]"
16
+
17
+ # Define the options, and what they do
18
+ options[:no_update] = false
19
+ opts.on( '--no-update', 'Do not update crontab after making leader' ) do
20
+ options[:no_update] = true
21
+ end
22
+
23
+ options[:instance] = ''
24
+ opts.on( '-i', '--instance', 'Instance to make leader' ) do |i|
25
+ options[:instance] = i
26
+ end
27
+
28
+
29
+ # This displays the help screen, all programs are
30
+ # assumed to have this option.
31
+ opts.on( '-h', '--help', 'Display this screen' ) do
32
+ puts opts
33
+ exit
34
+ end
35
+ end
36
+ optparse.parse!
37
+
38
+ instance_id = `/opt/aws/bin/ec2-metadata -i | awk '{print $2}'`.strip
39
+ availability_zone = `/opt/aws/bin/ec2-metadata -z | awk '{print $2}'`.strip
40
+ region = availability_zone.slice(0..availability_zone.length-2)
41
+
42
+ Aws.config.update({
43
+ region: region,
44
+ credentials: Aws::Credentials.new(ENV['ACCCESS_KEY_ID'], ENV['SECRET_ACCESS_TOKEN'])
45
+ })
46
+ ec2 = ec2 = Aws::EC2::Client.new
47
+
48
+
49
+ tags = ec2.describe_tags({filters: [{name: "key", values: ["leader"]}]})
50
+ ids = tags.tags.each {|t| m = []; m << t[:resource_id]; m}
51
+ if options[:instance].empty?
52
+ puts "Changing all set leader tags to false"
53
+ ec2.create_tags({dry_run: false, resources: ids, tags: [{key: "leader", value: "false"}]})
54
+ else
55
+ ec2.create_tags({dry_run: false, resources: [instance_id], tags: [{key: "leader", value: "true"}]})
56
+ end
57
+
58
+
59
+ unless options[:no_update]
60
+ `setup_cron`
61
+ end
@@ -0,0 +1,59 @@
1
+ #!/usr/bin/ruby
2
+
3
+ require 'optparse'
4
+ require 'rubygems'
5
+ gem 'aws-sdk', '~> 2'
6
+ require 'aws-sdk'
7
+ require 'erb'
8
+
9
+ EB_CONFIG_APP_SUPPORT = "/opt/elasticbeanstalk/support"
10
+ ENVIRONMENT_NAME_FILE = File.join(EB_CONFIG_APP_SUPPORT,'env_name')
11
+
12
+ # Options Parsing
13
+ options = {}
14
+ optparse = OptionParser.new do |opts|
15
+ opts.banner = "Usage: #{File.basename($0)} [options]"
16
+
17
+ # Define the options, and what they do
18
+ options[:no_update] = false
19
+ opts.on( '--no-update', 'Do not update crontab after making leader' ) do
20
+ options[:no_update] = true
21
+ end
22
+
23
+ # This displays the help screen, all programs are
24
+ # assumed to have this option.
25
+ opts.on( '-h', '--help', 'Display this screen' ) do
26
+ puts opts
27
+ exit
28
+ end
29
+ end
30
+ optparse.parse!
31
+
32
+ instance_id = `/opt/aws/bin/ec2-metadata -i | awk '{print $2}'`.strip
33
+ availability_zone = `/opt/aws/bin/ec2-metadata -z | awk '{print $2}'`.strip
34
+ region = availability_zone.slice(0..availability_zone.length-2)
35
+
36
+ Aws.config.update({
37
+ region: region,
38
+ credentials: Aws::Credentials.new(ENV['ACCCESS_KEY_ID'], ENV['SECRET_ACCESS_TOKEN'])
39
+ })
40
+ ec2 = ec2 = Aws::EC2::Client.new
41
+ tags = ec2.describe_tags({filters: [{name: "key", values: ["leader"]}]})
42
+ ids = tags.tags.each {|t| m = []; m << t[:resource_id]; m}
43
+
44
+ if !tags.tags.empty?
45
+ ids = tags.tags.each {|t| m = []; m << t[:resource_id]; m.delete_if {|f| f == instance_id}}
46
+ if tags.tags.count > 1
47
+ tags.tags.each do |t|
48
+ ec2.create_tags({dry_run: false, resources: m, tags: [{key: "leader", value: "false"}]})
49
+ end
50
+ else
51
+ ec2.create_tags({dry_run: false, resources: [instance_id], tags: [{key: "leader", value: "true"}]})
52
+ end
53
+ else
54
+ ec2.create_tags({dry_run: false, resources: [instance_id], tags: [{key: "leader", value: "true"}]})
55
+ end
56
+
57
+ unless options[:no_update]
58
+ `setup_cron`
59
+ end
@@ -0,0 +1,28 @@
1
+ #!/usr/bin/ruby
2
+
3
+ require 'rubygems'
4
+ gem 'aws-sdk', '~> 2'
5
+ require 'aws-sdk'
6
+ require 'erb'
7
+
8
+ ENVIRONMENT = ENV["RACK_ENV"]
9
+
10
+ instance_id = `/opt/aws/bin/ec2-metadata -i | awk '{print $2}'`.strip
11
+ availability_zone = `/opt/aws/bin/ec2-metadata -z | awk '{print $2}'`.strip
12
+ region = availability_zone.slice(0..availability_zone.length-2)
13
+
14
+ Aws.config.update({
15
+ region: region,
16
+ credentials: Aws::Credentials.new(ENV['ACCCESS_KEY_ID'], ENV['SECRET_ACCESS_TOKEN'])
17
+ })
18
+ ec2 = ec2 = Aws::EC2::Client.new
19
+
20
+ unless (`echo $PATH`).match("/usr/local/bin")
21
+ `export PATH=/usr/local/bin:$PATH`
22
+ end
23
+
24
+ tags = ec2.describe_tags({filters: [{name: "key", values: ["leader"]}]})
25
+ leader = tags.tags.each {|t| t.resource_id == instance_id ? t[:value] : "false"}
26
+
27
+ roles = leader.eql?("true") ? ["leader", ENVIRONMENT] : ["non-leader"]
28
+ `bundle exec whenever --roles #{roles.join(',')} --set 'environment=#{ENVIRONMENT}&path=/var/app/current' --update-crontab --user root`
@@ -0,0 +1,128 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # This file is based heavily on Whenever's 'wheneverize' command
4
+
5
+ require 'optparse'
6
+ require 'fileutils'
7
+ require 'erb'
8
+
9
+ OptionParser.new do |opts|
10
+ opts.banner = "Usage: #{File.basename($0)} [path]"
11
+
12
+ begin
13
+ opts.parse!(ARGV)
14
+ rescue OptionParser::ParseError => e
15
+ warn e.message
16
+ puts opts
17
+ exit 1
18
+ end
19
+ end
20
+
21
+ unless ARGV.empty?
22
+ if !File.exists?(ARGV.first)
23
+ abort "`#{ARGV.first}' does not exist."
24
+ elsif !File.directory?(ARGV.first)
25
+ abort "`#{ARGV.first}' is not a directory."
26
+ elsif ARGV.length > 1
27
+ abort "Too many arguments; please specify only the directory to wheneverize."
28
+ end
29
+ end
30
+
31
+ base = ARGV.empty? ? '.' : ARGV.shift
32
+
33
+ schedule_content = <<-FILE
34
+ # Use this file to easily define all of your cron jobs.
35
+ #
36
+ # It's helpful, but not entirely necessary to understand cron before proceeding.
37
+ # http://en.wikipedia.org/wiki/Cron
38
+
39
+ # Example:
40
+ #
41
+ # set :output, "/path/to/my/cron_log.log"
42
+ #
43
+ # every 2.hours do
44
+ # command "/usr/bin/some_great_command"
45
+ # runner "MyModel.some_method"
46
+ # rake "some:great:rake:task"
47
+ # end
48
+ #
49
+ # every 4.days do
50
+ # runner "AnotherModel.prune_old_records"
51
+ # end
52
+
53
+ # Learn more: http://github.com/javan/whenever
54
+
55
+ every 1.minute do
56
+ command "cd /var/app/current && bundle exec ensure_one_cron_leader"
57
+ end
58
+ FILE
59
+
60
+ file = 'config/schedule.rb'
61
+ file = File.join(base, file)
62
+ if File.exists?(file)
63
+ warn "[skip] `#{file}' already exists"
64
+ elsif File.exists?(file.downcase)
65
+ warn "[skip] `#{file.downcase}' exists, which could conflict with `#{file}'"
66
+ elsif !File.exists?(File.dirname(file))
67
+ warn "[skip] directory `#{File.dirname(file)}' does not exist"
68
+ else
69
+ puts "[add] writing `#{file}'"
70
+ File.open(file, "w") { |f| f.write(schedule_content) }
71
+ end
72
+
73
+
74
+ eb_config_content = <<-FILE
75
+ files:
76
+ # Reload the on deployment
77
+ /opt/elasticbeanstalk/hooks/appdeploy/post/10_reload_cron.sh:
78
+ mode: "00700"
79
+ owner: root
80
+ group: root
81
+ content: |
82
+ #!/usr/bin/env bash
83
+ # Loading environment data
84
+ EB_SCRIPT_DIR=$(/opt/elasticbeanstalk/bin/get-config container -k script_dir)
85
+ EB_SUPPORT_DIR=$(/opt/elasticbeanstalk/bin/get-config container -k support_dir)
86
+ EB_APP_CURRENT_DIR=$(/opt/elasticbeanstalk/bin/get-config container -k app_deploy_dir)
87
+
88
+ # Setting up correct environment and ruby version so that bundle can load all gems
89
+ . $EB_SUPPORT_DIR/envvars
90
+ . $EB_SCRIPT_DIR/use-app-ruby.sh
91
+
92
+ cd $EB_APP_CURRENT_DIR
93
+ /usr/local/bin/bundle exec setup_cron
94
+ commands:
95
+ create_bundle_symlink_patch:
96
+ test: test ! -f /usr/local/bin/bundle
97
+ command: ln -s `su -l -s /bin/bash -c "which bundle" $(/opt/elasticbeanstalk/bin/get-config container -k app_user)` /usr/local/bin/bundle
98
+ ignoreErrors: true
99
+ container_commands:
100
+ cron_01_set_leader:
101
+ test: test ! -f /opt/elasticbeanstalk/containerfiles/.cron-setup-complete || test ! -f /opt/elasticbeanstalk/support/.cron-setup-complete
102
+ leader_only: true
103
+ cwd: /var/app/ondeck
104
+ command: su -l -s /bin/bash -c "/usr/local/bin/bundle exec create_cron_leader --no-update" $(/opt/elasticbeanstalk/bin/get-config container -k app_user)
105
+ cron_02_write_cron_setup_complete_file_containerfiles:
106
+ test: test -d /opt/elasticbeanstalk/containerfiles
107
+ command: touch /opt/elasticbeanstalk/containerfiles/.cron-setup-complete
108
+ ignoreErrors: true
109
+ cron_02_write_cron_setup_complete_file_support:
110
+ test: test -d /opt/elasticbeanstalk/support
111
+ command: touch /opt/elasticbeanstalk/support/.cron-setup-complete
112
+ ignoreErrors: true
113
+ FILE
114
+
115
+ file = '.ebextensions/cron.config'
116
+ file = File.join(base, file)
117
+ if File.exists?(file)
118
+ warn "[skip] `#{file}' already exists"
119
+ elsif File.exists?(file.downcase)
120
+ warn "[skip] `#{file.downcase}' exists, which could conflict with `#{file}'"
121
+ elsif !File.exists?(File.dirname(file))
122
+ warn "[skip] directory `#{File.dirname(file)}' does not exist"
123
+ else
124
+ puts "[add] writing `#{file}'"
125
+ File.open(file, "w") { |f| f.write(eb_config_content) }
126
+ end
127
+
128
+ puts "[done] wheneverized for Elastic Beanstalk!"
@@ -0,0 +1,7 @@
1
+ require "whenever-elasticbeanstalk/version"
2
+
3
+ module Whenever
4
+ module Elasticbeanstalk
5
+ # Your code goes here...
6
+ end
7
+ end
@@ -0,0 +1,5 @@
1
+ module Whenever
2
+ module Elasticbeanstalk
3
+ VERSION = "1.0.3"
4
+ end
5
+ end
@@ -0,0 +1,24 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'whenever-elasticbeanstalk/version'
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.name = "whenever-eb-shipoffers"
8
+ gem.version = Whenever::Elasticbeanstalk::VERSION
9
+ gem.platform = Gem::Platform::RUBY
10
+ gem.authors = ["Zachary Green"]
11
+ gem.email = ["zach@shipoffers.com"]
12
+ gem.description = %q{Use Whenever on AWS Elastic Beanstalk}
13
+ gem.summary = %q{Allows you to run cron jobs easily on one or all AWS Elastic Beanstalk instances.}
14
+ gem.homepage = "https://github.com/ShipOffers/whenever-elasticbeanstalk"
15
+ # gem.license = 'MIT'
16
+
17
+ gem.add_dependency('whenever','~> 0.9.4')
18
+ gem.add_dependency('aws-sdk', '~> 2.2.12')
19
+
20
+ gem.files = `git ls-files`.split($/)
21
+ gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
22
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
23
+ gem.require_paths = ["lib"]
24
+ end
metadata ADDED
@@ -0,0 +1,87 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: whenever-eb-shipoffers
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.3
5
+ platform: ruby
6
+ authors:
7
+ - Zachary Green
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-01-20 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: whenever
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 0.9.4
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 0.9.4
27
+ - !ruby/object:Gem::Dependency
28
+ name: aws-sdk
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: 2.2.12
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: 2.2.12
41
+ description: Use Whenever on AWS Elastic Beanstalk
42
+ email:
43
+ - zach@shipoffers.com
44
+ executables:
45
+ - change_remove_cron_leader
46
+ - create_ensure_one_cron_leader
47
+ - setup_cron
48
+ - wheneverize-eb
49
+ extensions: []
50
+ extra_rdoc_files: []
51
+ files:
52
+ - ".gitignore"
53
+ - Gemfile
54
+ - LICENSE.txt
55
+ - README.md
56
+ - Rakefile
57
+ - bin/change_remove_cron_leader
58
+ - bin/create_ensure_one_cron_leader
59
+ - bin/setup_cron
60
+ - bin/wheneverize-eb
61
+ - lib/whenever-elasticbeanstalk.rb
62
+ - lib/whenever-elasticbeanstalk/version.rb
63
+ - whenever-elasticbeanstalk.gemspec
64
+ homepage: https://github.com/ShipOffers/whenever-elasticbeanstalk
65
+ licenses: []
66
+ metadata: {}
67
+ post_install_message:
68
+ rdoc_options: []
69
+ require_paths:
70
+ - lib
71
+ required_ruby_version: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ required_rubygems_version: !ruby/object:Gem::Requirement
77
+ requirements:
78
+ - - ">="
79
+ - !ruby/object:Gem::Version
80
+ version: '0'
81
+ requirements: []
82
+ rubyforge_project:
83
+ rubygems_version: 2.4.5
84
+ signing_key:
85
+ specification_version: 4
86
+ summary: Allows you to run cron jobs easily on one or all AWS Elastic Beanstalk instances.
87
+ test_files: []