sensu-plugins-kubernetes 0.0.1 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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: