cron-kubernetes 0.1.0 → 1.1.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 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