sensu-plugins-kubernetes 0.0.1 → 0.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,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- YzEzYTU0MzBhOWY3ZDRkZTNlYTIyMmEyOTIwYmQwYjA1Y2QxMzVjZQ==
4
+ ZGI5NmFlZDdkYjgyNGZiNjUwYTk3MGM1Y2M4OWQ1ZmZhY2Q5MmUwMw==
5
5
  data.tar.gz: !binary |-
6
- NGY2YTVmMWE5MGI3YTExZjIwZmE1ZTA2NWIzMmZiYmI1MWM1ZmYwYg==
6
+ Njk1NGYyNTU0YjUxZmZkNGI5NjFiMTgzNTNhNjJiNDVlMTIzMTRhYw==
7
7
  SHA512:
8
8
  metadata.gz: !binary |-
9
- M2VkZTE3OThlNTUzNTM2NmI1ZWYxYWY1ODFkMDUzYTc3OWY3M2RhMzgzMzQz
10
- ZWRhZDcyYTYyNzYxMzFmNWFkOWQ1MzY4OTRlOWIzNDZhNDdhMWJhNGU1ZDA4
11
- ZTI5ZTU5MDg5MzBhODljZmQwMDk3ZTRmYjFlNDY3OTI1Y2YwNjY=
9
+ YjNlOGZhZjFlOTRiNTBmMTBkODlhNTAzYWI3NWFkYTg0YjhiMTNiNmQzODFi
10
+ NTk0ZDlhNWQxYTkwN2M1M2M5NTcwMTgxNTZiNjZkODkyZThmMWVlNDFiMjJj
11
+ NWZmMTAwMWI2NzRmNzMyZmVkMmNhNWRhZDdmYTY5NTI1MDYzMWU=
12
12
  data.tar.gz: !binary |-
13
- ZjI0Y2U2NjU1ZWNlMDVlZDE3MTQ1YmY5YWVlNjFlNzdkMmUxNWJlNDIxMWZh
14
- YWY3MmNmOGQ5NmEwMTJlYzdmMWY5NmE1NzU1NTY0YzNjOTJjOTRiYmU5N2M0
15
- MDlhMTFhNTY1NmNhYzE1ZjExZmFiYmJlMzZlOTlmODBhMTA1MTI=
13
+ N2MxZjNiZmQ2YWM5N2UzYmY4NTMzYTczZTI3YjQzODg4YjYxZjBjZmYzNTVj
14
+ YThiYjBjYjU1ODQwMDlmNzdjNGYwY2ZjNDMzMmJiZmI3ZTIyNzNjNDUxNWZj
15
+ YmEwNzcyM2VhNTBiNjk2ODRkN2I2ZTQ5MjY0NzMxZjYxMzU1YTQ=
@@ -5,6 +5,23 @@ This CHANGELOG follows the format listed at [Keep A Changelog](http://keepachang
5
5
 
6
6
  ## [Unreleased]
7
7
 
8
+ ## [0.1.0] - 2016-05-15
9
+ ### Added
10
+ - Added flag to ignore namespaces in check-kube-pods-pending
11
+ - check-kube-service-available.rb: Will not mark a service is failed if any needed pod is running and ready
12
+ - check-kube-service-available.rb: Added options to allow of pod pending for given time to be counted as valid
13
+ - Factored all checks to share a common base class for connecting to Kubernetes
14
+ - Added flags to specify certificate authority and Kubernetes bearer token
15
+ - Added flags to specify client certificate/key and in-cluster support
16
+ - Support for Ruby 2.3
17
+
18
+ ### Fixed
19
+ - check-kube-service-available.rb: Fixed scope issue in main block that would cause a nil error
20
+
21
+ ### Changed
22
+ - Update to Rubocop 0.40 and cleanup
23
+ - Update to kubeclient 1.1.3
24
+
8
25
  ## 0.0.1 - 2016-03-03
9
26
  ### Added
10
27
  - initial release
data/README.md CHANGED
@@ -14,18 +14,158 @@ This provides functionality to check node and pod status as well as api and serv
14
14
  - bin/check-kube-apiserver-available.rb
15
15
  - bin/check-kube-pods-pending.rb
16
16
  - bin/check-kube-service-available.rb
17
- - bin check/kube-pods-runtime.rb
17
+ - bin/check-kube-pods-runtime.rb
18
18
  - bin/handler-kube-pod.rb
19
19
 
20
20
  ## Usage
21
+
22
+ **check-kube-nodes-ready.rb**
23
+ ```
24
+ Usage: check-kube-nodes-ready.rb (options)
25
+ --ca-file CA-FILE CA file to verify API server cert
26
+ --cert CERT-FILE Client cert to present
27
+ --key KEY-FILE Client key for the client cert
28
+ --in-cluster Use service account authentication
29
+ -p, --password PASSWORD If user is passed, also pass a password
30
+ -s, --api-server URL URL to API server
31
+ -t, --token TOKEN Bearer token for authorization
32
+ --token-file TOKEN-FILE File containing bearer token for authorization
33
+ -u, --user USER User with access to API
34
+ -v, --api-version VERSION API version
35
+ ```
36
+
37
+ **check-kube-apiserver-available.rb**
38
+ ```
39
+ Usage: check-kube-apiserver-available.rb (options)
40
+ --ca-file CA-FILE CA file to verify API server cert
41
+ --cert CERT-FILE Client cert to present
42
+ --key KEY-FILE Client key for the client cert
43
+ --in-cluster Use service account authentication
44
+ -p, --password PASSWORD If user is passed, also pass a password
45
+ -s, --api-server URL URL to API server
46
+ -t, --token TOKEN Bearer token for authorization
47
+ --token-file TOKEN-FILE File containing bearer token for authorization
48
+ -u, --user USER User with access to API
49
+ ```
50
+
51
+ **check-kube-pods-pending.rb**
52
+ ```
53
+ Usage: check-kube-pods-pending.rb (options)
54
+ --ca-file CA-FILE CA file to verify API server cert
55
+ --cert CERT-FILE Client cert to present
56
+ --key KEY-FILE Client key for the client cert
57
+ --in-cluster Use service account authentication
58
+ --password PASSWORD If user is passed, also pass a password
59
+ -s, --api-server URL URL to API server
60
+ --token TOKEN Bearer token for authorization
61
+ --token-file TOKEN-FILE File containing bearer token for authorization
62
+ -u, --user USER User with access to API
63
+ -v, --api-version VERSION API version
64
+ -n NAMESPACES, Exclude the specified list of namespaces
65
+ --exclude-namespace
66
+ -t, --timeout TIMEOUT Threshold for pods to be in the pending state
67
+ -f, --filter FILTER Selector filter for pods to be checked
68
+ -p, --pods PODS List of pods to check
69
+ -r, --restart COUNT Threshold for number of restarts allowed
70
+ ```
71
+
72
+ **check-kube-service-available.rb**
73
+ ```
74
+ Usage: check-kube-service-available.rb (options)
75
+ --ca-file CA-FILE CA file to verify API server cert
76
+ --cert CERT-FILE Client cert to present
77
+ --key KEY-FILE Client key for the client cert
78
+ --in-cluster Use service account authentication
79
+ --password PASSWORD If user is passed, also pass a password
80
+ -s, --api-server URL URL to API server
81
+ -t, --token TOKEN Bearer token for authorization
82
+ --token-file TOKEN-FILE File containing bearer token for authorization
83
+ -u, --user USER User with access to API
84
+ -v, --api-version VERSION API version
85
+ -p, --pending SECONDS Time (in seconds) a pod may be pending for and be valid
86
+ -l, --list SERVICES List of services to check (required)
87
+ ```
88
+
89
+ **check-kube-pods-runtime.rb**
90
+ ```
91
+ Usage: check-kube-pods-runtime.rb (options)
92
+ --ca-file CA-FILE CA file to verify API server cert
93
+ --cert CERT-FILE Client cert to present
94
+ --key KEY-FILE Client key for the client cert
95
+ --in-cluster Use service account authentication
96
+ --password PASSWORD If user is passed, also pass a password
97
+ -s, --api-server URL URL to API server
98
+ -t, --token TOKEN Bearer token for authorization
99
+ --token-file TOKEN-FILE File containing bearer token for authorization
100
+ -u, --user USER User with access to API
101
+ -v, --api-version VERSION API version
102
+ -c, --critical COUNT Threshold for Pods to be critical
103
+ -f, --filter FILTER Selector filter for pods to be checked
104
+ -p, --pods PODS List of pods to check
105
+ -w, --warn TIMEOUT Threshold for pods to be in the pending state
106
+ ```
107
+
108
+ **handler-kube-pod.rb**
21
109
  ```
22
- check-kube-nodes-ready.rb -s SERVER -v API_VERSION
23
- check-kube-apiserver-available.rb -s SERVER
24
- check-kube-pods-pending.rb -s SERVER
25
- check-kube-service-available.rb -s SERVER -l SERVICE1,SERVICE2
110
+ Usage: handler-kube-pod.rb (options)
111
+ -j, --json JSONCONFIG Configuration name
26
112
  ```
113
+
114
+ `JSONCONFIG` defaults to `k8s`.
115
+
116
+ ```
117
+ {
118
+ "k8s": {
119
+ "server": "https://kubernetes/",
120
+ "version": "v1",
121
+ "incluster": false,
122
+ "ca_file": "/certs/ca.crt.pem",
123
+ "client_cert_file": "/certs/client.crt.pem",
124
+ "client_key_file": "/private/client.key.pem",
125
+ "username": "alice",
126
+ "password": "secret",
127
+ "token": "incomprehensible.token.string",
128
+ "token_file": "/secret/token"
129
+ }
130
+ }
131
+ ```
132
+
133
+ `api_server` and `api_version` can still be used for backwards compatibility,
134
+ but `server` and `version` will take precedence.
135
+
27
136
  ## Installation
28
137
 
29
138
  [Installation and Setup](http://sensu-plugins.io/docs/installation_instructions.html)
30
139
 
31
140
  ## Notes
141
+
142
+ Of the Kubernetes connection options:
143
+ ```
144
+ --api-server URL URL to API server
145
+ --api-version VERSION API version
146
+ --in-cluster Use service account authentication
147
+ --ca-file CA-FILE CA file to verify API server cert
148
+ --cert CERT-FILE Client cert to present
149
+ --key KEY-FILE Client key for the client cert
150
+ --user USER User with access to API
151
+ --password PASSWORD If user is passed, also pass a password
152
+ --token TOKEN Bearer token for authorization
153
+ --token-file TOKEN-FILE File containing bearer token for authorization
154
+ ```
155
+ Only the API server option is required, however it does default to the `KUBERNETES_MASTER` environment variable, or you can use the in-cluster option. The other options are to be used as needed.
156
+
157
+ The default API version is `v1`.
158
+
159
+ The in-cluster option provides defaults for:
160
+ - The server URL, using the `KUBERNETES_SERVICE_HOST` and `KUBERNETES_SERVICE_PORT` environment variables.
161
+ - The API CA file, using the service account CA file if it exists. (`/var/run/secrets/kubernetes.io/serviceaccount/ca.crt`)
162
+ - The API token, using the service account token file. (`/var/run/secrets/kubernetes.io/serviceaccount/token`)
163
+
164
+ If the Kubernetes API provides a server certificate, it is only validated if a CA file is provided.
165
+
166
+ The client certificate and client private key are optional, but if one is provided then the other must also be provided.
167
+
168
+ Only one of the authentication methods (user, token, or token file) can be used.
169
+ For example, using a username and a token, or a token and a token file, will produce an error.
170
+
171
+ If the 'user' authentication method is used, a password must also be provided.
@@ -16,8 +16,15 @@
16
16
  # gem: kube-client
17
17
  #
18
18
  # USAGE:
19
- # -s SERVER - The kubernates SERVER
20
- # -v VERSION - The kubernates api VERSION. Defaults to v1
19
+ # -s, --api-server URL URL to API server
20
+ # --in-cluster Use service account authentication
21
+ # --ca-file CA-FILE CA file to verify API server cert
22
+ # --cert CERT-FILE Client cert to present
23
+ # --key KEY-FILE Client key for the client cert
24
+ # -u, --user USER User with access to API
25
+ # -p, --password PASSWORD If user is passed, also pass a password
26
+ # -t, --token TOKEN Bearer token for authorization
27
+ # --token-file TOKEN-FILE File containing bearer token for authorization
21
28
  #
22
29
  # LICENSE:
23
30
  # Kel Cecil <kelcecil@praisechaos.com>
@@ -25,31 +32,25 @@
25
32
  # for details.
26
33
  #
27
34
 
28
- require 'sensu-plugin/check/cli'
29
- require 'net/http'
30
- require 'uri'
35
+ require 'sensu-plugins-kubernetes/cli'
31
36
 
32
- class ApiServerIsAvailable < Sensu::Plugin::Check::CLI
33
- option :api_server,
34
- description: 'URL to API server',
35
- short: '-s URL',
36
- long: '--api-server',
37
- default: ENV['KUBERNETES_MASTER']
37
+ class ApiServerIsAvailable < Sensu::Plugins::Kubernetes::CLI
38
+ @options = Sensu::Plugins::Kubernetes::CLI.options.reject { |k| k == :api_version }
38
39
 
39
40
  def run
40
- cli = ApiServerIsAvailable.new
41
- api_server = cli.config[:api_server]
42
- uri = URI.parse "#{api_server}/healthz"
43
-
44
- begin
45
- response = Net::HTTP.get_response(uri)
46
- rescue
47
- warning 'Host is unavailable'
48
- end
49
-
50
- if response.code.include? '200'
41
+ if healthy?
51
42
  ok 'Kubernetes API server is available'
52
43
  end
53
44
  critical 'Kubernetes API server is unavailable'
54
45
  end
46
+
47
+ # TODO: replace this method when it's added to kubeclient
48
+ def healthy?
49
+ client.handle_exception do
50
+ client.create_rest_client('/healthz').get(client.headers)
51
+ end
52
+ true
53
+ rescue KubeException
54
+ false
55
+ end
55
56
  end
@@ -16,8 +16,16 @@
16
16
  # gem: kube-client
17
17
  #
18
18
  # USAGE:
19
- # -s SERVER - The kubernates SERVER
20
- # -v VERSION - The kubernates api VERSION. Defaults to v1
19
+ # -s, --api-server URL URL to API server
20
+ # -v, --api-version VERSION API version. Defaults to 'v1'
21
+ # --in-cluster Use service account authentication
22
+ # --ca-file CA-FILE CA file to verify API server cert
23
+ # --cert CERT-FILE Client cert to present
24
+ # --key KEY-FILE Client key for the client cert
25
+ # -u, --user USER User with access to API
26
+ # -p, --password PASSWORD If user is passed, also pass a password
27
+ # -t, --token TOKEN Bearer token for authorization
28
+ # --token-file TOKEN-FILE File containing bearer token for authorization
21
29
  #
22
30
  # LICENSE:
23
31
  # Kel Cecil <kelcecil@praisechaos.com>
@@ -25,34 +33,12 @@
25
33
  # for details.
26
34
  #
27
35
 
28
- require 'sensu-plugin/check/cli'
29
- require 'json'
30
- require 'kubeclient'
36
+ require 'sensu-plugins-kubernetes/cli'
31
37
 
32
- class AllNodesAreReady < Sensu::Plugin::Check::CLI
33
- option :api_server,
34
- description: 'URL to API server',
35
- short: '-s URL',
36
- long: '--api-server',
37
- default: ENV['KUBERNETES_MASTER']
38
-
39
- option :api_version,
40
- description: 'API version',
41
- short: '-v VERSION',
42
- long: '--api-version',
43
- default: 'v1'
38
+ class AllNodesAreReady < Sensu::Plugins::Kubernetes::CLI
39
+ @options = Sensu::Plugins::Kubernetes::CLI.options.dup
44
40
 
45
41
  def run
46
- cli = AllNodesAreReady.new
47
- api_server = cli.config[:api_server]
48
- api_version = cli.config[:api_version]
49
-
50
- begin
51
- client = Kubeclient::Client.new(api_server, api_version)
52
- rescue
53
- warning 'Unable to connect to Kubernetes API server'
54
- end
55
-
56
42
  failed_nodes = []
57
43
  client.get_nodes.each do |node|
58
44
  item = node.status.conditions.detect { |condition| condition.type == 'Ready' }
@@ -67,5 +53,7 @@ class AllNodesAreReady < Sensu::Plugin::Check::CLI
67
53
  ok 'All nodes are reporting as ready'
68
54
  end
69
55
  critical "Nodes are not ready: #{failed_nodes.join(' ')}"
56
+ rescue KubeException => e
57
+ critical 'API error: ' << e.message
70
58
  end
71
59
  end
@@ -16,11 +16,23 @@
16
16
  # gem: kube-client
17
17
  #
18
18
  # USAGE:
19
- # -s SERVER - The kubernates SERVER
20
- # -p PODS - Optional, list of specific pods to check. Defaults to all
21
- # -t TIMEOUT - The timeout in seconds to warn on
22
- # -r COUNT - The number of restarts to warn on
23
- # -f FILTER - The selector filter to use to determine the pods to check
19
+ # -s, --api-server URL URL to API server
20
+ # -v, --api-version VERSION API version. Defaults to 'v1'
21
+ # --in-cluster Use service account authentication
22
+ # --ca-file CA-FILE CA file to verify API server cert
23
+ # --cert CERT-FILE Client cert to present
24
+ # --key KEY-FILE Client key for the client cert
25
+ # -u, --user USER User with access to API
26
+ # --password PASSWORD If user is passed, also pass a password
27
+ # --token TOKEN Bearer token for authorization
28
+ # --token-file TOKEN-FILE File containing bearer token for authorization
29
+ # -n NAMESPACES, Exclude the specified list of namespaces
30
+ # --exclude-namespace
31
+ # -t, --timeout TIMEOUT Threshold for pods to be in the pending state
32
+ # -f, --filter FILTER Selector filter for pods to be checked
33
+ # -p, --pods PODS Optional list of pods to check.
34
+ # Defaults to 'all'
35
+ # -r, --restart COUNT Threshold for number of restarts allowed
24
36
  #
25
37
  # NOTES:
26
38
  # => The filter used for the -f flag is in the form key=value. If multiple
@@ -32,22 +44,10 @@
32
44
  # for details.
33
45
  #
34
46
 
35
- require 'sensu-plugin/check/cli'
36
- require 'json'
37
- require 'kubeclient'
47
+ require 'sensu-plugins-kubernetes/cli'
38
48
 
39
- class AllPodsAreReady < Sensu::Plugin::Check::CLI
40
- option :api_server,
41
- description: 'URL to API server',
42
- short: '-s URL',
43
- long: '--api-server',
44
- default: ENV['KUBERNETES_MASTER']
45
-
46
- option :api_version,
47
- description: 'API version',
48
- short: '-v VERSION',
49
- long: '--api-version',
50
- default: 'v1'
49
+ class AllPodsAreReady < Sensu::Plugins::Kubernetes::CLI
50
+ @options = Sensu::Plugins::Kubernetes::CLI.options.dup
51
51
 
52
52
  option :pod_list,
53
53
  description: 'List of pods to check',
@@ -74,26 +74,23 @@ class AllPodsAreReady < Sensu::Plugin::Check::CLI
74
74
  short: '-f FILTER',
75
75
  long: '--filter'
76
76
 
77
- def run
78
- cli = AllPodsAreReady.new
79
- api_server = cli.config[:api_server]
80
- api_version = cli.config[:api_version]
81
-
82
- begin
83
- client = Kubeclient::Client.new(api_server, api_version)
84
- rescue
85
- warning 'Unable to connect to Kubernetes API server'
86
- end
77
+ option :exclude_namespace,
78
+ description: 'Exclude the specified list of namespaces',
79
+ short: '-n NAMESPACES',
80
+ long: '--exclude-namespace',
81
+ proc: proc { |a| a.split(',') },
82
+ default: ''
87
83
 
84
+ def run
88
85
  pods_list = []
89
86
  failed_pods = []
90
87
  restarted_pods = []
91
88
  pods = []
92
- if cli.config[:pod_filter].nil?
93
- pods_list = parse_list(cli.config[:pod_list])
89
+ if config[:pod_filter].nil?
90
+ pods_list = parse_list(config[:pod_list])
94
91
  pods = client.get_pods
95
92
  else
96
- pods = client.get_pods(label_selector: cli.config[:pod_filter].to_s)
93
+ pods = client.get_pods(label_selector: config[:pod_filter].to_s)
97
94
  if pods.empty?
98
95
  unknown 'The filter specified resulted in 0 pods'
99
96
  end
@@ -101,18 +98,19 @@ class AllPodsAreReady < Sensu::Plugin::Check::CLI
101
98
  end
102
99
  pods.each do |pod|
103
100
  next if pod.nil?
101
+ next if config[:exclude_namespace].include?(pod.metadata.namespace)
104
102
  next unless pods_list.include?(pod.metadata.name) || pods_list.include?('all')
105
103
  # Check for pending state
106
104
  if pod.status.phase == 'Pending'
107
105
  pod_stamp = Time.parse(pod.metadata.creationTimestamp)
108
- if (Time.now.utc - pod_stamp.utc).to_i > cli.config[:pending_timeout]
106
+ if (Time.now.utc - pod_stamp.utc).to_i > config[:pending_timeout]
109
107
  failed_pods << pod.metadata.name
110
108
  end
111
109
  end
112
110
  # Check restarts
113
111
  next if pod.status.containerStatuses.nil?
114
112
  pod.status.containerStatuses.each do |container|
115
- if container.restartCount.to_i > cli.config[:restart_count]
113
+ if container.restartCount.to_i > config[:restart_count]
116
114
  restarted_pods << container.name
117
115
  end
118
116
  end
@@ -121,12 +119,14 @@ class AllPodsAreReady < Sensu::Plugin::Check::CLI
121
119
  if failed_pods.empty? && restarted_pods.empty?
122
120
  ok 'All pods are reporting as ready'
123
121
  elsif failed_pods.empty?
124
- critical "Pods exceeded restart threshold: #{restarted_pods.join(' ')}"
122
+ critical "Pods exceeded restart threshold: #{restarted_pods.join(' ')}"
125
123
  elsif restarted_pods.empty?
126
- critical "Pods exceeded pending threshold: #{failed_pods.join(' ')}"
124
+ critical "Pods exceeded pending threshold: #{failed_pods.join(' ')}"
127
125
  else
128
126
  critical "Pod restart and pending thresholds exceeded, pending: #{failed_pods.join(' ')} restarting: #{restarted_pods.join(' ')}"
129
127
  end
128
+ rescue KubeException => e
129
+ critical 'API error: ' << e.message
130
130
  end
131
131
 
132
132
  def parse_list(list)
@@ -16,10 +16,20 @@
16
16
  # gem: kube-client
17
17
  #
18
18
  # USAGE:
19
- # -s SERVER - The kubernates SERVER
20
- # -p PODS - REQUIRED, list of specific pods to check. Defaults to all
21
- # -w WARN - The time in seconds to warn on
22
- # -c CRIT - The time in seconds to flag as critical
19
+ # -s, --api-server URL URL to API server
20
+ # -v, --api-version VERSION API version. Defaults to 'v1'
21
+ # --in-cluster Use service account authentication
22
+ # --ca-file CA-FILE CA file to verify API server cert
23
+ # --cert CERT-FILE Client cert to present
24
+ # --key KEY-FILE Client key for the client cert
25
+ # -u, --user USER User with access to API
26
+ # --password PASSWORD If user is passed, also pass a password
27
+ # --token TOKEN Bearer token for authorization
28
+ # --token-file TOKEN-FILE File containing bearer token for authorization
29
+ # -c, --critical COUNT Threshold for Pods to be critical
30
+ # -f, --filter FILTER Selector filter for pods to be checked
31
+ # -p, --pods PODS List of pods to check
32
+ # -w, --warn TIMEOUT Threshold for pods to be in the pending state
23
33
  #
24
34
  # LICENSE:
25
35
  # Barry Martin <nyxcharon@gmail.com>
@@ -27,22 +37,10 @@
27
37
  # for details.
28
38
  #
29
39
 
30
- require 'sensu-plugin/check/cli'
31
- require 'json'
32
- require 'kubeclient'
40
+ require 'sensu-plugins-kubernetes/cli'
33
41
 
34
- class PodRuntime < Sensu::Plugin::Check::CLI
35
- option :api_server,
36
- description: 'URL to API server',
37
- short: '-s URL',
38
- long: '--api-server',
39
- default: ENV['KUBERNETES_MASTER']
40
-
41
- option :api_version,
42
- description: 'API version',
43
- short: '-v VERSION',
44
- long: '--api-version',
45
- default: 'v1'
42
+ class PodRuntime < Sensu::Plugins::Kubernetes::CLI
43
+ @options = Sensu::Plugins::Kubernetes::CLI.options.dup
46
44
 
47
45
  option :pod_list,
48
46
  description: 'List of pods to check',
@@ -68,27 +66,17 @@ class PodRuntime < Sensu::Plugin::Check::CLI
68
66
  proc: proc(&:to_i)
69
67
 
70
68
  def run
71
- cli = PodRuntime.new
72
- api_server = cli.config[:api_server]
73
- api_version = cli.config[:api_version]
74
-
75
- begin
76
- client = Kubeclient::Client.new(api_server, api_version)
77
- rescue
78
- warning 'Unable to connect to Kubernetes API server'
79
- end
80
-
81
69
  pods_list = []
82
70
  pods = []
83
71
  warn = false
84
72
  crit = false
85
73
  message = ''
86
74
 
87
- if cli.config[:pod_filter].nil?
88
- pods_list = parse_list(cli.config[:pod_list])
75
+ if config[:pod_filter].nil?
76
+ pods_list = parse_list(config[:pod_list])
89
77
  pods = client.get_pods
90
78
  else
91
- pods = client.get_pods(label_selector: cli.config[:pod_filter].to_s)
79
+ pods = client.get_pods(label_selector: config[:pod_filter].to_s)
92
80
  pods_list = ['all']
93
81
  end
94
82
 
@@ -100,11 +88,11 @@ class PodRuntime < Sensu::Plugin::Check::CLI
100
88
  pod_stamp = Time.parse(pod.status.startTime)
101
89
  runtime = (Time.now.utc - pod_stamp.utc).to_i
102
90
 
103
- if !cli.config[:critical_timeout].nil? && runtime > cli.config[:critical_timeout]
104
- message << "#{pod.metadata.name} exceeds threshold #{cli.config[:critical_timeout]} "
91
+ if !config[:critical_timeout].nil? && runtime > config[:critical_timeout]
92
+ message << "#{pod.metadata.name} exceeds threshold #{config[:critical_timeout]} "
105
93
  crit = true
106
- elsif !cli.config[:warn_timeout].nil? && runtime > cli.config[:warn_timeout]
107
- message << "#{pod.metadata.name} exceeds threshold #{cli.config[:warn_timeout]} "
94
+ elsif !config[:warn_timeout].nil? && runtime > config[:warn_timeout]
95
+ message << "#{pod.metadata.name} exceeds threshold #{config[:warn_timeout]} "
108
96
  warn = true
109
97
  end
110
98
  end
@@ -116,6 +104,8 @@ class PodRuntime < Sensu::Plugin::Check::CLI
116
104
  else
117
105
  ok 'All pods within threshold'
118
106
  end
107
+ rescue KubeException => e
108
+ critical 'API error: ' << e.message
119
109
  end
120
110
 
121
111
  def parse_list(list)
@@ -16,8 +16,18 @@
16
16
  # gem: kube-client
17
17
  #
18
18
  # USAGE:
19
- # -s SERVER - The kube server to use
20
- # -l SERVICES - The comma delimited list of services to check
19
+ # -s, --api-server URL URL to API server
20
+ # -v, --api-version VERSION API version. Defaults to 'v1'
21
+ # --in-cluster Use service account authentication
22
+ # --ca-file CA-FILE CA file to verify API server cert
23
+ # --cert CERT-FILE Client cert to present
24
+ # --key KEY-FILE Client key for the client cert
25
+ # -u, --user USER User with access to API
26
+ # --password PASSWORD If user is passed, also pass a password
27
+ # --token TOKEN Bearer token for authorization
28
+ # --token-file TOKEN-FILE File containing bearer token for authorization
29
+ # -l, --list SERVICES List of services to check (required)
30
+ # -p, --pending SECONDS Time (in seconds) a pod may be pending for and be valid
21
31
  #
22
32
  # NOTES:
23
33
  #
@@ -27,22 +37,11 @@
27
37
  # for details.
28
38
  #
29
39
 
30
- require 'sensu-plugin/check/cli'
31
- require 'json'
32
- require 'kubeclient'
40
+ require 'sensu-plugins-kubernetes/cli'
41
+ require 'time'
33
42
 
34
- class AllServicesUp < Sensu::Plugin::Check::CLI
35
- option :api_server,
36
- description: 'URL to API server',
37
- short: '-s URL',
38
- long: '--api-server',
39
- default: ENV['KUBERNETES_MASTER']
40
-
41
- option :api_version,
42
- description: 'API version',
43
- short: '-v VERSION',
44
- long: '--api-version',
45
- default: 'v1'
43
+ class AllServicesUp < Sensu::Plugins::Kubernetes::CLI
44
+ @options = Sensu::Plugins::Kubernetes::CLI.options.dup
46
45
 
47
46
  option :service_list,
48
47
  description: 'List of services to check',
@@ -50,18 +49,15 @@ class AllServicesUp < Sensu::Plugin::Check::CLI
50
49
  long: '--list',
51
50
  required: true
52
51
 
53
- def run
54
- cli = AllServicesUp.new
55
- api_server = cli.config[:api_server]
56
- api_version = cli.config[:api_version]
52
+ option :pendingTime,
53
+ description: 'Time (in seconds) a pod may be pending for and be valid',
54
+ short: '-p SECONDS',
55
+ long: '--pending',
56
+ default: 0,
57
+ proc: proc(&:to_i)
57
58
 
58
- begin
59
- client = Kubeclient::Client.new(api_server, api_version)
60
- rescue
61
- warning 'Unable to connect to Kubernetes API server'
62
- end
63
-
64
- services = parse_list(cli.config[:service_list])
59
+ def run
60
+ services = parse_list(config[:service_list])
65
61
  failed_services = []
66
62
  s = client.get_services
67
63
  s.each do |a|
@@ -81,10 +77,26 @@ class AllServicesUp < Sensu::Plugin::Check::CLI
81
77
  end
82
78
  # Make sure our pod is running
83
79
  next if pod.nil?
80
+ pod_available = false
84
81
  pod.each do |p|
85
- unless p.status.phase.include?('Running')
86
- failed_services << p.metadata.name
82
+ case p.status.phase
83
+ when 'Pending'
84
+ next if p.status.startTime.nil?
85
+ if (Time.now - Time.parse(p.status.startTime)).to_i < config[:pendingTime]
86
+ pod_available = True
87
+ break
88
+ end
89
+ when 'Running'
90
+ p.status.conditions.each do |c|
91
+ next unless c.type == 'Ready'
92
+ if c.status == 'True'
93
+ pod_available = true
94
+ break
95
+ end
96
+ break if pod_available
97
+ end
87
98
  end
99
+ failed_services << p.metadata.name if pod_available == false
88
100
  end
89
101
  end
90
102
 
@@ -97,6 +109,8 @@ class AllServicesUp < Sensu::Plugin::Check::CLI
97
109
  else
98
110
  critical "Some services could not be checked: #{services.join(' ')}"
99
111
  end
112
+ rescue KubeException => e
113
+ critical 'API error: ' << e.message
100
114
  end
101
115
 
102
116
  def parse_list(list)
@@ -17,7 +17,7 @@
17
17
  # gem: kube-client
18
18
  #
19
19
  # USAGE:
20
- # -j JSONCONFIG - The config file to us
20
+ # -j JSONCONFIG - The settings section to use
21
21
  #
22
22
  # NOTES:
23
23
  #
@@ -28,26 +28,32 @@
28
28
  #
29
29
 
30
30
  require 'sensu-handler'
31
- require 'kubeclient'
32
- require 'json'
31
+ require 'sensu-plugins-kubernetes/client'
33
32
 
34
33
  class KubePod < Sensu::Handler
34
+ include Sensu::Plugins::Kubernetes::Client
35
+
35
36
  option :json_config,
36
- description: 'Configuration name',
37
+ description: 'Configuration section name',
37
38
  short: '-j JSONCONFIG',
38
39
  long: '--json JSONCONFIG',
39
40
  default: 'k8s'
40
41
 
41
- def api_server
42
- get_setting('api_server') || ENV['KUBERNETES_MASTER']
43
- end
44
-
45
- def api_version
46
- get_setting('api_version') || 'v1'
47
- end
48
-
49
- def get_setting(name)
50
- settings[config[:json_config]][name]
42
+ def client_config
43
+ defaults = {
44
+ server: ENV['KUBERNETES_MASTER'],
45
+ version: 'v1'
46
+ }
47
+ h = settings[config[:json_config]]
48
+ if h.is_a?(Hash)
49
+ # Maintain backwards compatibility
50
+ h[:server] ||= h[:api_server]
51
+ h[:version] ||= h[:api_version]
52
+ # And merge
53
+ defaults.merge!(h)
54
+ else
55
+ defaults
56
+ end
51
57
  end
52
58
 
53
59
  def handle
@@ -55,8 +61,10 @@ class KubePod < Sensu::Handler
55
61
  response = api_request(:DELETE, '/clients/' + @event['client']['name']).code
56
62
  deletion_status(response)
57
63
  begin
58
- client = Kubeclient::Client.new(api_server, api_version)
64
+ client = kubeclient(client_config)
59
65
  client.delete_pod @event['client']['name']
66
+ rescue ArgumentError => e
67
+ puts "[Kube Pod] Invalid settings: #{e.message}"
60
68
  rescue KubeException => e
61
69
  puts "[Kube Pod] KubeException: #{e.message}"
62
70
  rescue Exception => e # rubocop:disable Lint/RescueException
@@ -0,0 +1,96 @@
1
+ require 'sensu-plugin/check/cli'
2
+ require 'sensu-plugins-kubernetes/client.rb'
3
+
4
+ module Sensu
5
+ module Plugins
6
+ # Namespace for the Kubernetes sensu-plugin.
7
+ module Kubernetes
8
+ # Abstract base class for a Sensu check that also provides
9
+ # Kubernetes client connection support.
10
+ class CLI < Sensu::Plugin::Check::CLI
11
+ include Sensu::Plugins::Kubernetes::Client
12
+
13
+ option :api_server,
14
+ description: 'URL to API server',
15
+ short: '-s URL',
16
+ long: '--api-server',
17
+ default: ENV['KUBERNETES_MASTER']
18
+
19
+ option :api_version,
20
+ description: 'API version',
21
+ short: '-v VERSION',
22
+ long: '--api-version',
23
+ default: 'v1'
24
+
25
+ option :api_incluster,
26
+ description: 'Use service account authentication',
27
+ long: '--in-cluster',
28
+ boolean: true,
29
+ default: false
30
+
31
+ option :api_ca_file,
32
+ description: 'CA file to verify API server cert',
33
+ long: '--ca-file CA-FILE',
34
+ default: nil
35
+
36
+ option :api_client_cert,
37
+ description: 'Client cert to present',
38
+ long: '--cert CERT-FILE',
39
+ default: nil
40
+
41
+ option :api_client_key,
42
+ description: 'Client key for the client cert',
43
+ long: '--key KEY-FILE',
44
+ default: nil
45
+
46
+ option :api_user,
47
+ description: 'User with access to API',
48
+ short: '-u USER',
49
+ long: '--user',
50
+ default: nil
51
+
52
+ option :api_password,
53
+ description: 'If user is passed, also pass a password',
54
+ short: '-p PASSWORD',
55
+ long: '--password',
56
+ default: nil
57
+
58
+ option :api_token,
59
+ description: 'Bearer token for authorization',
60
+ short: '-t TOKEN',
61
+ long: '--token',
62
+ default: nil
63
+
64
+ option :api_token_file,
65
+ description: 'File containing bearer token for authorization',
66
+ long: '--token-file TOKEN-FILE',
67
+ default: nil
68
+
69
+ attr_reader :client
70
+
71
+ # Initializes the Sensu check by creating a Kubernetes client
72
+ # from the given options and will report a critical error if
73
+ # those arguments are incorrect.
74
+ def initialize
75
+ super()
76
+ begin
77
+ @client = kubeclient(
78
+ server: config[:api_server],
79
+ version: config[:api_version],
80
+ incluster: config[:api_incluster],
81
+ ca_file: config[:api_ca_file],
82
+ client_cert_file: config[:api_client_cert],
83
+ client_key_file: config[:api_client_key],
84
+ username: config[:api_user],
85
+ password: config[:api_password],
86
+ token: config[:api_token],
87
+ token_file: config[:api_token_file]
88
+ )
89
+ rescue ArgumentError => e
90
+ critial e.message
91
+ end
92
+ end
93
+ end
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,126 @@
1
+ require 'kubeclient'
2
+ require 'uri'
3
+
4
+ module Sensu
5
+ module Plugins
6
+ # Namespace for the Kubernetes sensu-plugin.
7
+ module Kubernetes
8
+ # A mixin module that provides Kubernetes client (kubeclient) support.
9
+ module Client
10
+ # The location of the service account provided CA.
11
+ # (if the cluster is configured to provide it)
12
+ INCLUSTER_CA_FILE =
13
+ '/var/run/secrets/kubernetes.io/serviceaccount/ca.crt'.freeze
14
+
15
+ # The location of the service account provided authentication token.
16
+ INCLUSTER_TOKEN_FILE =
17
+ '/var/run/secrets/kubernetes.io/serviceaccount/token'.freeze
18
+
19
+ # Creates a new Kubeclient::Client instance using the given SSL
20
+ # and authentication options (if any)
21
+ #
22
+ # @param [Hash] options The Kubernetes API connection details.
23
+ # @option options [String] :server URL to API server
24
+ # @option options [String] :version API version
25
+ # @option options [Boolean] :incluster
26
+ # Use service account authentication if true
27
+ # @option options [String] :ca_file
28
+ # CA file used to verify API server certificate
29
+ # @option options [String] :client_cert_file
30
+ # Client certificate file to present
31
+ # @option options [String] :client_key_file
32
+ # Client private key file for the client certificate
33
+ # @option options [String] :username
34
+ # Username with access to API
35
+ # @option options [String] :password
36
+ # If a username is passed, also pass a password
37
+ # @option options [String] :token
38
+ # The bearer token for Kubernetes authorization
39
+ # @option options [String] :token_file
40
+ # A file containing the bearer token for Kubernetes authorization
41
+ #
42
+ # @raise [ArgumentError] If an invalid option, or combination of options, is given.
43
+ # @raise [Errono::*] If there is a problem reading the client certificate or private key file.
44
+ # @raise [OpenSSL::X509::CertificateError] If there is a problem with the client certificate.
45
+ # @raise [OpenSSL::PKey::RSAError] If there is a problem with the client private key.
46
+ def kubeclient(options = {})
47
+ raise(ArgumentError, 'options must be a hash') unless options.is_a?(Hash)
48
+
49
+ api_server = options[:server]
50
+ api_version = options[:version]
51
+
52
+ ssl_options = {
53
+ ca_file: options[:ca_file]
54
+ }
55
+ auth_options = {
56
+ username: options[:username],
57
+ password: options[:password],
58
+ bearer_token: options[:token],
59
+ bearer_token_file: options[:token_file]
60
+ }
61
+
62
+ if [:client_cert_file, :client_key_file].count { |k| options[k] } == 1
63
+ raise ArgumentError, 'SSL requires both client cert and client key'
64
+ end
65
+
66
+ if options[:client_cert_file]
67
+ begin
68
+ ssl_options[:client_cert] = OpenSSL::X509::Certificate.new(File.read(options[:client_cert_file]))
69
+ rescue => e
70
+ raise e, "Unable to read client certificate: #{e}", e.backtrace
71
+ end
72
+ end
73
+
74
+ if options[:client_key_file]
75
+ begin
76
+ ssl_options[:client_key] = OpenSSL::PKey::RSA.new(File.read(options[:client_key_file]))
77
+ rescue => e
78
+ raise e, "Unable to read client key: #{e}", e.backtrace
79
+ end
80
+ end
81
+
82
+ if options[:incluster]
83
+ # Provide in-cluster defaults, if not already specified
84
+ # (following the kubernetes incluster config code, more or less)
85
+
86
+ # api-server
87
+ # TODO: use in-cluster DNS ??
88
+ if api_server.nil?
89
+ host = ENV['KUBERNETES_SERVICE_HOST']
90
+ port = ENV['KUBERNETES_SERVICE_PORT']
91
+ if host.nil? || port.nil?
92
+ raise ArgumentError, 'unable to load in-cluster configuration,'\
93
+ ' KUBERNETES_SERVICE_HOST and KUBERNETES_SERVICE_PORT'\
94
+ ' must be defined'
95
+ end
96
+ api_server = URI::HTTPS.build(host: host, port: port, path: '/api')
97
+ end
98
+
99
+ # ca file, but only if it exists
100
+ if ssl_options[:ca_file].nil? && File.exist?(INCLUSTER_CA_FILE)
101
+ # Readability/permission issues should be left to kubeclient
102
+ ssl_options[:ca_file] = INCLUSTER_CA_FILE
103
+ end
104
+
105
+ # token file
106
+ if auth_options[:bearer_token_file].nil?
107
+ auth_options[:bearer_token_file] = INCLUSTER_TOKEN_FILE
108
+ end
109
+ end
110
+
111
+ ssl_options[:verify_ssl] = ssl_options[:ca_file] ? OpenSSL::SSL::VERIFY_PEER : OpenSSL::SSL::VERIFY_NONE
112
+
113
+ begin
114
+ # new only throws errors on bad arguments
115
+ Kubeclient::Client.new(api_server, api_version,
116
+ ssl_options: ssl_options,
117
+ auth_options: auth_options)
118
+ rescue URI::InvalidURIError => e
119
+ # except for this one, which we'll re-wrap to make catching easier
120
+ raise ArgumentError, "Invalid API server: #{e}", e.backtrace
121
+ end
122
+ end
123
+ end
124
+ end
125
+ end
126
+ end
@@ -1,8 +1,8 @@
1
1
  module SensuPluginsKubernetes
2
2
  module Version
3
3
  MAJOR = 0
4
- MINOR = 0
5
- PATCH = 1
4
+ MINOR = 1
5
+ PATCH = 0
6
6
 
7
7
  VER_STRING = [MAJOR, MINOR, PATCH].compact.join('.')
8
8
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sensu-plugins-kubernetes
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sensu-Plugins and contributors
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-03-04 00:00:00.000000000 Z
11
+ date: 2016-05-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: sensu-plugin
@@ -30,14 +30,14 @@ dependencies:
30
30
  requirements:
31
31
  - - '='
32
32
  - !ruby/object:Gem::Version
33
- version: 1.1.1
33
+ version: 1.1.3
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - '='
39
39
  - !ruby/object:Gem::Version
40
- version: 1.1.1
40
+ version: 1.1.3
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: bundler
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -128,14 +128,14 @@ dependencies:
128
128
  requirements:
129
129
  - - ~>
130
130
  - !ruby/object:Gem::Version
131
- version: '0.37'
131
+ version: 0.40.0
132
132
  type: :development
133
133
  prerelease: false
134
134
  version_requirements: !ruby/object:Gem::Requirement
135
135
  requirements:
136
136
  - - ~>
137
137
  - !ruby/object:Gem::Version
138
- version: '0.37'
138
+ version: 0.40.0
139
139
  - !ruby/object:Gem::Dependency
140
140
  name: rspec
141
141
  requirement: !ruby/object:Gem::Requirement
@@ -186,6 +186,8 @@ files:
186
186
  - bin/check-kube-service-available.rb
187
187
  - bin/handler-kube-pod.rb
188
188
  - lib/sensu-plugins-kubernetes.rb
189
+ - lib/sensu-plugins-kubernetes/cli.rb
190
+ - lib/sensu-plugins-kubernetes/client.rb
189
191
  - lib/sensu-plugins-kubernetes/version.rb
190
192
  homepage: https://github.com/sensu-plugins/sensu-plugins-kubernetes
191
193
  licenses: