cron-kubernetes 0.1.0 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f95641f4e595e197c2205b213097349df8b5f93c4f4c6556416f66bb6c1dd636
4
- data.tar.gz: 3fb3993388b2f631c1b73e297a18340b45c197368a24486b7b5f3ca7cb7395bc
3
+ metadata.gz: 218b54415c313d661475b6f73f5cf3218b2a928e8fc65d7236a06ac480f07db1
4
+ data.tar.gz: 4d9a5e7687abe849a14ee8c9d817ee418be6ca22738177c65d21be1f0724f526
5
5
  SHA512:
6
- metadata.gz: 128dc9682185ff67c49804d099a05056f6403ef4f25ad6161401d8fbf10881b325e141b2dd631445db2570e67c8ba499fb05eef433372e1feedc08a813c4f03e
7
- data.tar.gz: 267f422c41cceee4a2bef3293918504322c6f468573eb4158898c71027b3d6ee28973178021af25cc951f9b7d26606c12c9fc77e65a132ca442a6ca6bb506584
6
+ metadata.gz: 545a23464d897e6b6591e5ed37c017e6330692bdbc8892f5ffccb023b32c41292af8a7ab8add6de0dc60018eb30299a56bc442166a794956f51ee547938fe62e
7
+ data.tar.gz: 262182d7eda44214339da475f0fd488dd20ffd702310267b34b5f80dd3e62d4da298788b88a87c76d60735ecd88334a86e00dc88d7e7df22c10cc75200684d17
data/.gitignore CHANGED
@@ -1,4 +1,4 @@
1
- /.bundle/
1
+ **/.bundle/
2
2
  /.yardoc
3
3
  /_yardoc/
4
4
  /coverage/
@@ -7,7 +7,7 @@
7
7
  /spec/reports/
8
8
  /tmp/
9
9
  /Gemfile.lock
10
-
10
+ **/*.gemfile.lock
11
11
 
12
12
  # rspec failure tracking
13
13
  .rspec_status
@@ -1,3 +1,7 @@
1
+ AllCops:
2
+ Exclude:
3
+ - "gemfiles/*"
4
+
1
5
  Documentation:
2
6
  Exclude:
3
7
  - "**/railtie.rb"
@@ -31,7 +35,9 @@ Style/FormatStringToken:
31
35
  EnforcedStyle: template
32
36
  Style/AsciiComments:
33
37
  Enabled: false
34
-
38
+ Naming/FileName:
39
+ Exclude:
40
+ - "lib/cron-kubernetes.rb"
35
41
  Metrics/BlockLength:
36
42
  Exclude:
37
43
  - "*.gemspec"
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ appraise "kubeclient-3" do
4
+ gem "kubeclient", "3.1.2"
5
+ end
6
+
7
+ appraise "kubeclient-4" do
8
+ gem "kubeclient", "4.0.0"
9
+ end
@@ -1,2 +1,13 @@
1
+ # v1.1.0
2
+ - Fix issue where all cron jobs in a cluster would be removed, not just ones matching `identifier`
3
+
4
+ # v1.0.0
5
+ **Breaking Change:**
6
+ - Requires `kubeclient` 3.1.2 or 4.x
7
+
8
+ **Changes:**
9
+ - Add `kubeclient` configuration option for connecting to any Kubernetes server
10
+ - Add Appraisal for testing with kubeclient 3.1.2 and 4.x
11
+
1
12
  # v0.1.0
2
13
  - Initial Release
data/README.md CHANGED
@@ -95,6 +95,29 @@ replace both `ENTRYPOINT` and `CMD` in the Docker image. See
95
95
  [Define a Command and Arguments for a Container](https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/)
96
96
  for a discussion of how `command` works in Kubernetes.
97
97
 
98
+ ### kubeclient
99
+ The gem will automatically connect to the Kubernetes server in the following cases:
100
+ - You are running this in [a standard Kubernetes cluster](https://kubernetes.io/docs/tasks/access-application-cluster/access-cluster/#accessing-the-api-from-a-pod)
101
+ - You are running on a system with `kubeclient` installed and
102
+ - the default cluster context has credentials
103
+ - the default cluster is GKE and your system has
104
+ [Google application default credentials](https://developers.google.com/identity/protocols/application-default-credentials)
105
+ installed
106
+
107
+ There are many other ways to connect and you can do so by providing your own
108
+ [configured `kubeclient`](https://github.com/abonas/kubeclient#usage):
109
+
110
+ ```ruby
111
+ # config/initializers/resque-kubernetes.rb
112
+
113
+ CronKubernetes.configuration do |config|
114
+ config.kubeclient = Kubeclient::Client.new("http://localhost:8080/apis/batch", "v1beta1")
115
+ end
116
+ ```
117
+
118
+ Because this uses the `CronJob` resource, make sure to connect to the `/apis/batch` API endpoint and
119
+ API version `v1beta1` in your client.
120
+
98
121
  ## Usage
99
122
 
100
123
  ### Create a Schedule
@@ -111,10 +134,10 @@ CronKubernetes.schedule do
111
134
  end
112
135
  ```
113
136
 
114
- For all jobs the command with change directories to either `Rails.root` if Rails is installed
137
+ For all jobs the command will change directories to either `Rails.root` if Rails is installed
115
138
  or the current working directory. These are evaluated when the scheduled tasks are loaded.
116
139
 
117
- For all jobs you may provide a `name` to name, which will be used with the `identifier` to name the
140
+ For all jobs you may provide a `name` that will be used with the `identifier` to name the
118
141
  CronJob. If you do not provide a name `CronKubernetes` will try to figure one out from the job and
119
142
  pod templates plus a hash of the schedule and command.
120
143
 
@@ -122,15 +145,14 @@ pod templates plus a hash of the schedule and command.
122
145
 
123
146
  A `command` runs any arbitrary shell command on a schedule. The first argument is the command to run.
124
147
 
125
-
126
148
  #### Rake Tasks
127
149
 
128
150
  A `rake` call runs a `rake` task on the schedule. Rake and Bundler must be installed and on the path
129
- in the container The command it executes is `bundle exec rake ...`.
151
+ in the container. The command it executes is `bundle exec rake ...`.
130
152
 
131
153
  #### Runners
132
154
 
133
- A `runner` runs arbitrary ruby code under rails. Rails must be installed at `bin/rails` from the
155
+ A `runner` runs arbitrary ruby code under Rails. Rails must be installed at `bin/rails` from the
134
156
  working folder. The command it executes is `bin/rails runner '...'`.
135
157
 
136
158
  ### Update Your Cluster
@@ -170,21 +192,40 @@ bin/rails runner cron_kubernetes
170
192
  at: "[H]H:mm[am|pm]"
171
193
  ```
172
194
 
173
- ## Development
195
+ ## Contributing
196
+
197
+ Bug reports and pull requests are welcome on GitHub at
198
+ https://github.com/keylime-toolbox/cron-kubernetes-ruby.
174
199
 
175
- After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests.
200
+ 1. Fork it (`https://github.com/[my-github-username]/cron-kubernetes-ruby/fork`)
201
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
202
+ 3. Test your changes with `rake`, add new tests if needed
203
+ 4. Commit your changes (`git commit -am 'Add some feature'`)
204
+ 6. Push to the branch (`git push origin my-new-feature`)
205
+ 7. Open a new Pull Request
176
206
 
177
- You can also run `bin/console` for an interactive prompt that will allow you to experiment.
207
+ ### Development
178
208
 
179
- To install this gem onto your local machine, run `bundle exec rake install`.
209
+ After checking out the repo, run `bin/setup` to install dependencies. Then,
210
+ run `bin/rake` to run the test suite.
180
211
 
181
- To release a new version, update the version number in `lib/cron_kubernets/version.rb` and the `CHANGELOG.md`,
182
- and then run `bundle exec rake release`, which will create a git tag for the version,
183
- push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
212
+ You can run `bin/console` for an interactive prompt that will allow you to
213
+ experiment.
184
214
 
185
- ## Contributing
215
+ Write test for any code that you add. Test all changes by running `bin/rake`.
216
+ This does the following, which you can also run separately while working.
217
+ 1. Run unit tests: `appraisal rake spec`
218
+ 2. Make sure that your code matches the styles: `rubocop`
219
+ 3. Verify if any dependent gems have open CVEs (you must update these):
220
+ `rake bundle:audit`
221
+
222
+ ## Release
186
223
 
187
- Bug reports and pull requests are welcome on GitHub at https://github.com/keylimetoolbox/cron-kubernetes.
224
+ To release a new version, update the version number in
225
+ `lib/cron_kubernetes/version.rb` and the `CHANGELOG.md`, then run
226
+ `bundle exec rake release`, which will create a git tag for the version,
227
+ push git commits and tags, and push the `.gem` file to
228
+ [rubygems.org](https://rubygems.org).
188
229
 
189
230
  ## Acknowledgments
190
231
 
data/Rakefile CHANGED
@@ -1,16 +1,22 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "appraisal/task"
4
+ require "bundler/audit/task"
3
5
  require "bundler/gem_tasks"
4
6
  require "rspec/core/rake_task"
5
7
  require "rubocop/rake_task"
6
- require "bundler/audit/task"
7
8
 
8
9
  RSpec::Core::RakeTask.new(:spec)
9
10
  RuboCop::RakeTask.new
10
11
  Bundler::Audit::Task.new
12
+ Appraisal::Task.new
11
13
 
12
14
  # Remove default and replace with a series of test tasks
13
15
  task default: []
14
16
  Rake::Task[:default].clear
15
17
 
16
- task default: %w[spec rubocop bundle:audit]
18
+ if ENV["APPRAISAL_INITIALIZED"]
19
+ task default: %i[spec]
20
+ else
21
+ task default: %i[rubocop bundle:audit appraisal]
22
+ end
@@ -24,8 +24,9 @@ Gem::Specification.new do |spec|
24
24
  spec.bindir = "bin"
25
25
  spec.executables << "cron_kubernetes"
26
26
 
27
- spec.add_dependency "kubeclient", "~> 3.0"
27
+ spec.add_dependency "kubeclient", ">= 3.1.2", "< 5.0"
28
28
 
29
+ spec.add_development_dependency "appraisal"
29
30
  spec.add_development_dependency "bundler", "~> 1.16"
30
31
  spec.add_development_dependency "bundler-audit", "~> 0"
31
32
  spec.add_development_dependency "mocha", "~> 1.3"
@@ -0,0 +1,7 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "kubeclient", "3.1.2"
6
+
7
+ gemspec path: "../"
@@ -0,0 +1,7 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "kubeclient", "4.0.0"
6
+
7
+ gemspec path: "../"
@@ -1 +1,3 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "cron_kubernetes"
@@ -1,6 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "cron_kubernetes/configurable"
4
+ require "cron_kubernetes/context/kubectl"
5
+ require "cron_kubernetes/context/well_known"
4
6
  require "cron_kubernetes/cron_job"
5
7
  require "cron_kubernetes/cron_tab"
6
8
  require "cron_kubernetes/kubeclient_context"
@@ -26,6 +28,9 @@ module CronKubernetes
26
28
  # Provide an identifier for this schedule (e.g. your application name)
27
29
  define_setting :identifier
28
30
 
31
+ # A `kubeclient` for connection context, default attempts to read from cluster or `~/.kube/config`
32
+ define_setting :kubeclient, nil
33
+
29
34
  class << self
30
35
  def schedule(&block)
31
36
  CronKubernetes::Scheduler.instance.instance_eval(&block)
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CronKubernetes
4
+ module Context
5
+ # Kubeclient Context from `kubectl` config file.
6
+ class Kubectl
7
+ def applicable?
8
+ File.exist?(kubeconfig)
9
+ end
10
+
11
+ def context
12
+ config = Kubeclient::Config.read(kubeconfig)
13
+
14
+ CronKubernetes::KubeclientContext::Context.new(
15
+ config.context.api_endpoint,
16
+ config.context.api_version,
17
+ config.context.namespace,
18
+ auth_options: auth_options(config),
19
+ ssl_options: config.context.ssl_options
20
+ )
21
+ end
22
+
23
+ private
24
+
25
+ def kubeconfig
26
+ File.join(ENV["HOME"], ".kube", "config")
27
+ end
28
+
29
+ def auth_options(config)
30
+ options = config.context.auth_options
31
+ return options unless options.empty?
32
+ google_application_default_credentials
33
+ end
34
+
35
+ def google_application_default_credentials
36
+ return unless defined?(Google) && defined?(Google::Auth)
37
+ {bearer_token: Kubeclient::GoogleApplicationDefaultCredentials.token}
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CronKubernetes
4
+ module Context
5
+ # Kubeclient Context from well-known locations within a Kubernetes cluster.
6
+ class WellKnown
7
+ TOKEN_FILE = "/var/run/secrets/kubernetes.io/serviceaccount/token"
8
+ CA_FILE = "/var/run/secrets/kubernetes.io/serviceaccount/ca.crt"
9
+ NAMESPACE_FILE = "/var/run/secrets/kubernetes.io/serviceaccount/namespace"
10
+
11
+ def applicable?
12
+ File.exist?(TOKEN_FILE)
13
+ end
14
+
15
+ def context
16
+ CronKubernetes::KubeclientContext::Context.new(
17
+ "https://kubernetes.default.svc",
18
+ "v1",
19
+ namespace,
20
+ auth_options: {bearer_token_file: TOKEN_FILE},
21
+ ssl_options: ssl_options
22
+ )
23
+ end
24
+
25
+ private
26
+
27
+ def namespace
28
+ return nil unless File.exist?(NAMESPACE_FILE)
29
+ File.read(NAMESPACE_FILE)
30
+ end
31
+
32
+ def ssl_options
33
+ return {} unless File.exist?(CA_FILE)
34
+ {ca_file: CA_FILE}
35
+ end
36
+ end
37
+ end
38
+ end
@@ -39,7 +39,7 @@ module CronKubernetes
39
39
  private
40
40
 
41
41
  def namespace
42
- return job_manifest["metadata"]["namespace"] if job_manifest["metadata"]
42
+ return job_manifest["metadata"]["namespace"] if job_manifest["metadata"] && job_manifest["metadata"]["namespace"]
43
43
  "default"
44
44
  end
45
45
 
@@ -3,13 +3,6 @@
3
3
  module CronKubernetes
4
4
  # The "table" of Kubernetes CronJobs that we manage in the cluster.
5
5
  class CronTab
6
- attr_reader :client
7
- private :client
8
-
9
- def initialize
10
- @client = CronKubernetes::KubernetesClient.new.batch_beta1_client
11
- end
12
-
13
6
  # "Apply" the new configuration
14
7
  # - remove from cluster any cron_jobs that are no longer in the schedule
15
8
  # - add new jobs
@@ -24,9 +17,13 @@ module CronKubernetes
24
17
 
25
18
  private
26
19
 
20
+ def client
21
+ @client ||= CronKubernetes::KubernetesClient.new.batch_beta1_client
22
+ end
23
+
27
24
  # Define a label for our jobs based on an identifier
28
25
  def label_selector
29
- {"cron-kubernetes-identifier" => CronKubernetes.identifier}
26
+ {label_selector: "cron-kubernetes-identifier=#{CronKubernetes.identifier}"}
30
27
  end
31
28
 
32
29
  # Find all k8s CronJobs by our label for the identifier
@@ -5,64 +5,18 @@ require "kubeclient"
5
5
  module CronKubernetes
6
6
  # Create a context for `Kubeclient` depending on the environment.
7
7
  class KubeclientContext
8
+ Context = Struct.new(:endpoint, :version, :namespace, :options)
9
+
8
10
  class << self
9
11
  def context
10
- # TODO: Add ability to load this from config
11
-
12
- if File.exist?("/var/run/secrets/kubernetes.io/serviceaccount/token")
13
- # When running in k8s cluster, use the service account secret token and ca bundle
14
- well_known_context
15
- elsif File.exist?(kubeconfig)
16
- # When running in development, use the config file for `kubectl` and default application credentials
17
- kubectl_context
12
+ [
13
+ CronKubernetes::Context::WellKnown,
14
+ CronKubernetes::Context::Kubectl
15
+ ].each do |context_type|
16
+ context = context_type.new
17
+ return context.context if context.applicable?
18
18
  end
19
19
  end
20
-
21
- private
22
-
23
- def well_known_context
24
- Kubeclient::Config::Context.new(
25
- "https://kubernetes",
26
- "v1",
27
- {ca_file: "/var/run/secrets/kubernetes.io/serviceaccount/ca.crt"},
28
- bearer_token_file: "/var/run/secrets/kubernetes.io/serviceaccount/token"
29
- )
30
- end
31
-
32
- def kubectl_context
33
- config = Kubeclient::Config.read(kubeconfig)
34
- auth_options = config.context.auth_options
35
-
36
- auth_options = google_default_application_credentials(config) if auth_options.empty?
37
-
38
- Kubeclient::Config::Context.new(
39
- config.context.api_endpoint,
40
- config.context.api_version,
41
- config.context.ssl_options,
42
- auth_options
43
- )
44
- end
45
-
46
- def kubeconfig
47
- File.join(ENV["HOME"], ".kube", "config")
48
- end
49
-
50
- # TODO: Move this logic to kubeclient. See abonas/kubeclient#213
51
- def google_default_application_credentials(config)
52
- return unless defined?(Google) && defined?(Google::Auth)
53
-
54
- _cluster, user = config.send(:fetch_context, config.instance_variable_get(:@kcfg)["current-context"])
55
- return {} unless user["auth-provider"] && user["auth-provider"]["name"] == "gcp"
56
-
57
- {bearer_token: new_google_token}
58
- end
59
-
60
- def new_google_token
61
- scopes = ["https://www.googleapis.com/auth/cloud-platform"]
62
- authorization = Google::Auth.get_application_default(scopes)
63
- authorization.apply({})
64
- authorization.access_token
65
- end
66
20
  end
67
21
  end
68
22
  end
@@ -7,18 +7,21 @@ module CronKubernetes
7
7
  @batch_beta1_client ||= client("/apis/batch", "v1beta1")
8
8
  end
9
9
 
10
+ def namespace
11
+ context&.namespace
12
+ end
13
+
10
14
  private
11
15
 
12
16
  def client(scope, version = nil)
13
- context = KubeclientContext.context
17
+ return CronKubernetes.kubeclient if CronKubernetes.kubeclient
14
18
  return unless context
19
+ Kubeclient::Client.new(context.endpoint + scope, version || context.version, context.options)
20
+ end
15
21
 
16
- Kubeclient::Client.new(
17
- context.api_endpoint + scope,
18
- version || context.api_version,
19
- ssl_options: context.ssl_options,
20
- auth_options: context.auth_options
21
- )
22
+ def context
23
+ return nil if CronKubernetes.kubeclient
24
+ @context ||= KubeclientContext.context
22
25
  end
23
26
  end
24
27
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module CronKubernetes
4
- VERSION = "0.1.0"
4
+ VERSION = "1.1.0"
5
5
  end
metadata CHANGED
@@ -1,29 +1,49 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cron-kubernetes
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jeremy Wadsack
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-04-24 00:00:00.000000000 Z
11
+ date: 2018-10-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: kubeclient
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - "~>"
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: 3.1.2
20
+ - - "<"
18
21
  - !ruby/object:Gem::Version
19
- version: '3.0'
22
+ version: '5.0'
20
23
  type: :runtime
21
24
  prerelease: false
22
25
  version_requirements: !ruby/object:Gem::Requirement
23
26
  requirements:
24
- - - "~>"
27
+ - - ">="
25
28
  - !ruby/object:Gem::Version
26
- version: '3.0'
29
+ version: 3.1.2
30
+ - - "<"
31
+ - !ruby/object:Gem::Version
32
+ version: '5.0'
33
+ - !ruby/object:Gem::Dependency
34
+ name: appraisal
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ version: '0'
40
+ type: :development
41
+ prerelease: false
42
+ version_requirements: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: '0'
27
47
  - !ruby/object:Gem::Dependency
28
48
  name: bundler
29
49
  requirement: !ruby/object:Gem::Requirement
@@ -141,6 +161,7 @@ files:
141
161
  - ".rubocop.yml"
142
162
  - ".ruby-gemset"
143
163
  - ".ruby-version"
164
+ - Appraisals
144
165
  - CHANGELOG.md
145
166
  - Gemfile
146
167
  - LICENSE.txt
@@ -150,9 +171,13 @@ files:
150
171
  - bin/cron_kubernetes
151
172
  - bin/setup
152
173
  - cron-kubernetes.gemspec
174
+ - gemfiles/kubeclient_3.gemfile
175
+ - gemfiles/kubeclient_4.gemfile
153
176
  - lib/cron-kubernetes.rb
154
177
  - lib/cron_kubernetes.rb
155
178
  - lib/cron_kubernetes/configurable.rb
179
+ - lib/cron_kubernetes/context/kubectl.rb
180
+ - lib/cron_kubernetes/context/well_known.rb
156
181
  - lib/cron_kubernetes/cron_job.rb
157
182
  - lib/cron_kubernetes/cron_tab.rb
158
183
  - lib/cron_kubernetes/kubeclient_context.rb