@depup/kubernetes-client 9.0.0-depup.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.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2016 GoDaddy Operating Company, LLC.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,39 @@
1
+ # @depup/kubernetes-client
2
+
3
+ > Dependency-bumped version of [kubernetes-client](https://www.npmjs.com/package/kubernetes-client)
4
+
5
+ Generated by [DepUp](https://github.com/depup/npm) -- all production
6
+ dependencies bumped to latest versions.
7
+
8
+ ## Installation
9
+
10
+ ```bash
11
+ npm install @depup/kubernetes-client
12
+ ```
13
+
14
+ | Field | Value |
15
+ |-------|-------|
16
+ | Original | [kubernetes-client](https://www.npmjs.com/package/kubernetes-client) @ 9.0.0 |
17
+ | Processed | 2026-03-17 |
18
+ | Smoke test | passed |
19
+ | Deps updated | 9 |
20
+
21
+ ## Dependency Changes
22
+
23
+ | Dependency | From | To |
24
+ |------------|------|-----|
25
+ | @kubernetes/client-node | 0.10.2 | ^1.4.0 |
26
+ | camelcase | ^6.0.0 | ^9.0.0 |
27
+ | deepmerge | ^4.2.2 | ^4.3.1 |
28
+ | js-yaml | ^3.13.1 | ^4.1.1 |
29
+ | openid-client | ^3.14.0 | ^6.8.2 |
30
+ | pump | ^3.0.0 | ^3.0.4 |
31
+ | qs | ^6.9.0 | ^6.15.0 |
32
+ | url-join | ^4.0.1 | ^5.0.0 |
33
+ | ws | ^7.2.3 | ^8.19.0 |
34
+
35
+ ---
36
+
37
+ Source: https://github.com/depup/npm | Original: https://www.npmjs.com/package/kubernetes-client
38
+
39
+ License inherited from the original package.
@@ -0,0 +1,153 @@
1
+ 'use strict'
2
+
3
+ const camelCase = require('camelcase')
4
+ const k8s = require('@kubernetes/client-node')
5
+ const { PassThrough, Readable } = require('stream')
6
+
7
+ //
8
+ // https://github.com/kubernetes-client/javascript
9
+ //
10
+ class ClientNodeBackend {
11
+ constructor (options) {
12
+ this.client = options.client || k8s
13
+ this.kubeconfig = options.kubeconfig
14
+ this.apiClients = { }
15
+ }
16
+
17
+ _getApiClient (tag) {
18
+ const apiType = camelCase(tag, { pascalCase: true }) + 'Api'
19
+ if (!(apiType in this.apiClients)) {
20
+ this.apiClients[apiType] = this.kubeconfig.makeApiClient(this.client[apiType])
21
+ }
22
+ return this.apiClients[apiType]
23
+ }
24
+
25
+ getLogByteStream (options) {
26
+ const log = new this.client.Log(this.kubeconfig)
27
+ const qs = options.qs || options.parameters || {}
28
+ const containerName = qs.container
29
+ const stream = new PassThrough()
30
+
31
+ //
32
+ // node-client pipes to the log stream iff the apiserver returns 200. Assume
33
+ // that if the stream is readable, then node-client has attached the pipe
34
+ // and the call was successful.
35
+ //
36
+ // Otherwise, node-client calls the callback with an err.
37
+ //
38
+ // node-client also calls the callback when the connection terminates. We
39
+ // ignore that.
40
+ //
41
+ return new Promise((resolve, reject) => {
42
+ stream.once('readable', () => {
43
+ resolve(stream)
44
+ })
45
+ log.log(options.pathnameParameters.namespace,
46
+ options.pathnameParameters.name,
47
+ containerName,
48
+ stream,
49
+ err => { if (err) return reject(err) },
50
+ qs)
51
+ })
52
+ }
53
+
54
+ async getWatchObjectStream (options) {
55
+ const watch = new this.client.Watch(this.kubeconfig)
56
+
57
+ const stream = new Readable({
58
+ objectMode: true,
59
+ read: () => { /* .watch callback pushes to stream below */ },
60
+ destroy: (err, cb) => {
61
+ req.destroy(err)
62
+ req.abort()
63
+ cb(err)
64
+ }
65
+ })
66
+
67
+ const req = watch.watch(
68
+ options.pathname,
69
+ Object.assign({}, options.qs, options.parameters),
70
+ (type, object) => stream.push({ type, object }),
71
+ err => stream.destroy(err)
72
+ )
73
+
74
+ return stream
75
+ }
76
+
77
+ http (options) {
78
+ const pathItemObject = options.pathItemObject
79
+ const operationObject = pathItemObject[options.method.toLowerCase()]
80
+ const tag = operationObject.tags[0]
81
+
82
+ const apiClient = this._getApiClient(tag)
83
+
84
+ //
85
+ // In older Kubernetes API OpenAPI specifications the Operation IDs include
86
+ // the tag, but in newer versions (including the ones used to generate
87
+ // @kubernetes/client-node), the tag is absent.
88
+ //
89
+ // Support older versions of the Swagger specifications by removing the tag
90
+ // part.
91
+ //
92
+ const method = operationObject.operationId.replace(camelCase(tag, { pascalCase: true }), '')
93
+
94
+ //
95
+ // @kubernetes/client-node methods take parameters in the order the OpenAPI
96
+ // specification declares them.
97
+ //
98
+ const parameterObjects = (pathItemObject.parameters || []).concat(operationObject.parameters || [])
99
+ const orderedParameterObjects = parameterObjects
100
+ .filter(parameterObject => parameterObject.required)
101
+ .concat(parameterObjects
102
+ .filter(parameterObject => !parameterObject.required))
103
+
104
+ //
105
+ // Older versions of the Kubernetes API OpenAPI specifications requires body
106
+ // for _some_ delete operations (e.g., deleteNamespacedDeployment). The API
107
+ // does not actually require it and newer specifications remove the
108
+ // requirement. Try to Workaround this issue by adding an empty body to
109
+ // @kubernetes/client-node calls.
110
+ //
111
+ let body = options.body
112
+ if (options.method.toLowerCase() === 'delete' && !body) {
113
+ body = {}
114
+ }
115
+
116
+ const parameters = Object.assign(
117
+ { body },
118
+ options.pathnameParameters,
119
+ options.qs,
120
+ options.parameters)
121
+ const args = orderedParameterObjects.reduce((acc, operationParameter) => {
122
+ const name = operationParameter.name
123
+ if (name in parameters) {
124
+ acc.push(parameters[name])
125
+ } else {
126
+ acc.push(undefined)
127
+ }
128
+ return acc
129
+ }, [])
130
+
131
+ const extraOptions = {}
132
+ if (options.headers) {
133
+ extraOptions.headers = options.headers
134
+ }
135
+ args.push(extraOptions)
136
+
137
+ return apiClient[method].apply(apiClient, args)
138
+ .then(res => {
139
+ res.statusCode = res.response.statusCode
140
+ return res
141
+ })
142
+ .catch(err => {
143
+ if (!err.body) throw err
144
+ const error = new Error(err.body.message)
145
+ // .code is backwards compatible with pre-5.0.0 code.
146
+ error.code = err.response.statusCode
147
+ error.statusCode = err.response.statusCode
148
+ throw error
149
+ })
150
+ }
151
+ }
152
+
153
+ module.exports = ClientNodeBackend
@@ -0,0 +1,62 @@
1
+ /**
2
+ * Fetches a bearer token via comamnd
3
+ */
4
+
5
+ 'use strict'
6
+
7
+ // for API compatability
8
+ /* eslint no-sync: 0 */
9
+ const spawnSync = require('child_process').spawnSync
10
+
11
+ function getProperty (propertyName, object) {
12
+ // remove leading .
13
+ if (propertyName.match(/^\./)) {
14
+ propertyName = propertyName.replace(/^\./, '')
15
+ }
16
+
17
+ const parts = propertyName.split('.')
18
+ const length = parts.length
19
+
20
+ let property = object || this
21
+ for (let i = 0; i < length; i++) {
22
+ property = property[parts[i]]
23
+ }
24
+
25
+ return property
26
+ }
27
+
28
+ module.exports = {
29
+ refresh: function (config) {
30
+ return new Promise((resolve, reject) => {
31
+ const cmd = config['cmd-path']
32
+ const args = config['cmd-args'].split(' ')
33
+ const cmdEnv = config['cmd-env']
34
+
35
+ let output
36
+
37
+ if (process.platform === 'win32') {
38
+ output = spawnSync(cmd, args, {
39
+ env: Object.assign({}, process.env, cmdEnv),
40
+ windowsHide: true,
41
+ shell: true
42
+ })
43
+ } else {
44
+ output = spawnSync(cmd, args, {
45
+ env: Object.assign({}, process.env, cmdEnv),
46
+ windowsHide: true
47
+ })
48
+ }
49
+
50
+ let result
51
+ try {
52
+ result = JSON.parse(output.stdout.toString('utf8'))
53
+ } catch (err) {
54
+ return reject(new Error('Failed to run cmd.'))
55
+ }
56
+
57
+ const token = getProperty(config['token-key'].replace(/[{}]+/g, ''), result)
58
+
59
+ return resolve(token)
60
+ })
61
+ }
62
+ }
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Refreshes a OpenID token.
3
+ */
4
+
5
+ 'use strict'
6
+
7
+ const Issuer = require('openid-client').Issuer
8
+
9
+ module.exports = {
10
+ refresh: function (config) {
11
+ return new Promise((resolve, reject) => {
12
+ Issuer.discover(config['idp-issuer-url'])
13
+ .then(function (ourIssuer) {
14
+ const client = new ourIssuer.Client({
15
+ client_id: config['client-id'],
16
+ client_secret: config['client-secret']
17
+ })
18
+
19
+ return client.refresh(config['refresh-token'])
20
+ })
21
+ .then(tokenSet => {
22
+ return resolve(tokenSet.id_token)
23
+ })
24
+ .catch(reject)
25
+ })
26
+ }
27
+ }
@@ -0,0 +1,243 @@
1
+ 'use strict'
2
+
3
+ const { convertKubeconfig } = require('./config')
4
+ const deprecate = require('depd')('kubernetes-client')
5
+ const JSONStream = require('json-stream')
6
+ const pump = require('pump')
7
+ const qs = require('qs')
8
+ const request = require('request')
9
+ const urljoin = require('url-join')
10
+ const WebSocket = require('ws')
11
+
12
+ /**
13
+ * Refresh whatever authentication {type} is.
14
+ * @param {String} type - type of authentication
15
+ * @param {Object} config - auth provider config
16
+ * @returns {Promise} with request friendly auth object
17
+ */
18
+ function refreshAuth (type, config) {
19
+ return new Promise((resolve, reject) => {
20
+ const provider = require(`./auth-providers/${type}.js`)
21
+ provider.refresh(config)
22
+ .then(result => {
23
+ const auth = {
24
+ bearer: result
25
+ }
26
+
27
+ return resolve(auth)
28
+ })
29
+ .catch(err => reject(err))
30
+ })
31
+ }
32
+
33
+ const execChannels = [
34
+ 'stdin',
35
+ 'stdout',
36
+ 'stderr',
37
+ 'error',
38
+ 'resize'
39
+ ]
40
+
41
+ /**
42
+ * Determine whether a failed Kubernetes API response is asking for an upgrade
43
+ * @param {object} body - response body object from Kubernetes
44
+ * @property {string} status - request status
45
+ * @property {number} code - previous request's response code
46
+ * @property {message} message - previous request response message
47
+ * @returns {boolean} Upgrade the request
48
+ */
49
+
50
+ function isUpgradeRequired (body) {
51
+ return body.status === 'Failure' &&
52
+ body.code === 400 &&
53
+ body.message === 'Upgrade request required'
54
+ }
55
+
56
+ /**
57
+ * Upgrade a request into a Websocket transaction & process the result
58
+ * @param {ApiRequestOptions} options - Options object
59
+ * @param {callback} cb - The callback that handles the response
60
+ */
61
+
62
+ function upgradeRequest (options, cb) {
63
+ const queryParams = qs.stringify(options.qs, { indices: false })
64
+ const wsUrl = urljoin(options.baseUrl, options.uri, `?${queryParams}`)
65
+ const protocol = 'base64.channel.k8s.io'
66
+
67
+ // Passing authorization header
68
+ options.headers = {
69
+ ...options.headers,
70
+ authorization: `Bearer ${options.auth.bearer}`
71
+ }
72
+ const ws = new WebSocket(wsUrl, protocol, options)
73
+
74
+ const messages = []
75
+ ws.on('message', (msg) => {
76
+ const channel = execChannels[msg.slice(0, 1)]
77
+ const message = Buffer.from(msg.slice(1), 'base64').toString('ascii')
78
+ messages.push({ channel, message })
79
+ })
80
+
81
+ ws.on('error', (err) => {
82
+ err.messages = messages
83
+ cb(err, messages)
84
+ })
85
+
86
+ ws.on('close', (code, reason) => cb(null, {
87
+ messages,
88
+ body: messages.map(({ message }) => message).join(''),
89
+ code,
90
+ reason
91
+ }))
92
+
93
+ return ws
94
+ }
95
+
96
+ class Request {
97
+ /**
98
+ * Internal representation of HTTP request object.
99
+ *
100
+ * @param {object} options - Options object
101
+ * @param {string} options.url - Kubernetes API URL
102
+ * @param {object} options.auth - request library auth object
103
+ * @param {string} options.ca - Certificate authority
104
+ * @param {string} options.cert - Client certificate
105
+ * @param {string} options.key - Client key
106
+ * @param {boolean} options.insecureSkipTlsVerify - Skip the validity check
107
+ * on the server's certificate.
108
+ */
109
+ constructor (options) {
110
+ this.requestOptions = options.request || {}
111
+
112
+ let convertedOptions
113
+ if (!options.kubeconfig) {
114
+ deprecate('Request() without a .kubeconfig option, see ' +
115
+ 'https://github.com/godaddy/kubernetes-client/blob/master/merging-with-kubernetes.md')
116
+ convertedOptions = options
117
+ } else {
118
+ convertedOptions = convertKubeconfig(options.kubeconfig)
119
+ }
120
+
121
+ this.requestOptions.qsStringifyOptions = { indices: false }
122
+ this.requestOptions.baseUrl = convertedOptions.url
123
+ this.requestOptions.ca = convertedOptions.ca
124
+ this.requestOptions.cert = convertedOptions.cert
125
+ this.requestOptions.key = convertedOptions.key
126
+ if ('insecureSkipTlsVerify' in convertedOptions) {
127
+ this.requestOptions.strictSSL = !convertedOptions.insecureSkipTlsVerify
128
+ }
129
+ if ('timeout' in convertedOptions) {
130
+ this.requestOptions.timeout = convertedOptions.timeout
131
+ }
132
+
133
+ this.authProvider = {
134
+ type: null
135
+ }
136
+ if (convertedOptions.auth) {
137
+ this.requestOptions.auth = convertedOptions.auth
138
+ if (convertedOptions.auth.provider) {
139
+ this.requestOptions.auth = convertedOptions.auth.request
140
+ this.authProvider = convertedOptions.auth.provider
141
+ }
142
+ }
143
+ }
144
+
145
+ _request (options, cb) {
146
+ const auth = this.authProvider
147
+ return request(options, (err, res, body) => {
148
+ if (err) return cb(err)
149
+
150
+ if (body && isUpgradeRequired(body)) {
151
+ return upgradeRequest(options, cb)
152
+ }
153
+
154
+ // Refresh auth if 401 or 403
155
+ if ((res.statusCode === 401 || res.statusCode === 403) && auth.type) {
156
+ return refreshAuth(auth.type, auth.config)
157
+ .then(newAuth => {
158
+ this.requestOptions.auth = newAuth
159
+ options.auth = newAuth
160
+ return request(options, (err, res, body) => {
161
+ if (err) return cb(err)
162
+ return cb(null, { statusCode: res.statusCode, body })
163
+ })
164
+ })
165
+ .catch(err => cb(err))
166
+ }
167
+
168
+ return cb(null, { statusCode: res.statusCode, body: body })
169
+ })
170
+ }
171
+
172
+ async getLogByteStream (options) {
173
+ return this.http(Object.assign({ stream: true }, options))
174
+ }
175
+
176
+ async getWatchObjectStream (options) {
177
+ const jsonStream = new JSONStream()
178
+ const stream = this.http(Object.assign({ stream: true }, options))
179
+ pump(stream, jsonStream)
180
+ return jsonStream
181
+ }
182
+
183
+ /**
184
+ * @param {object} options - Options object
185
+ * @param {Stream} options.stdin - optional stdin Readable stream
186
+ * @param {Stream} options.stdout - optional stdout Writeable stream
187
+ * @param {Stream} options.stderr - optional stdout Writeable stream
188
+ * @returns {Promise} Promise resolving to a Kubernetes V1 Status object and a WebSocket
189
+ */
190
+ async getWebSocket (options) {
191
+ throw new Error('Request.getWebSocket not implemented')
192
+ }
193
+
194
+ /**
195
+ * @typedef {object} ApiRequestOptions
196
+ * @property {object} body - Request body
197
+ * @property {object} headers - Headers object
198
+ * @property {string} path - version-less path
199
+ * @property {object} qs - {@link https://www.npmjs.com/package/request#requestoptions-callback|
200
+ * request query parameter}
201
+ */
202
+
203
+ /**
204
+ * Invoke a REST request against the Kubernetes API server
205
+ * @param {string} method - HTTP method, passed directly to `request`
206
+ * @param {ApiRequestOptions} options - Options object
207
+ * @param {callback} cb - The callback that handles the response
208
+ * @returns {Stream} If cb is falsy, return a stream
209
+ */
210
+ http (options) {
211
+ const uri = options.pathname
212
+ const requestOptions = Object.assign({
213
+ method: options.method,
214
+ uri,
215
+ body: options.body,
216
+ json: 'json' in options ? Boolean(options.json) : true,
217
+ qs: options.parameters || options.qs,
218
+ headers: options.headers
219
+ }, this.requestOptions)
220
+
221
+ if (options.noAuth) {
222
+ delete requestOptions.auth
223
+ }
224
+
225
+ if (options.stream) return request(requestOptions)
226
+
227
+ return new Promise((resolve, reject) => {
228
+ this._request(requestOptions, (err, res) => {
229
+ if (err) return reject(err)
230
+ if (res.statusCode < 200 || res.statusCode > 299) {
231
+ const error = new Error(res.body.message || res.body)
232
+ // .code is backwards compatible with pre-5.0.0 code.
233
+ error.code = res.statusCode
234
+ error.statusCode = res.statusCode
235
+ return reject(error)
236
+ }
237
+ resolve(res)
238
+ })
239
+ })
240
+ }
241
+ }
242
+
243
+ module.exports = Request