Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

auto-kubernetes-client

Package Overview
Dependencies
Maintainers
1
Versions
14
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

auto-kubernetes-client - npm Package Compare versions

Comparing version 0.4.3 to 0.5.0

34

.eslintrc.json

@@ -5,4 +5,3 @@ {

"es6": true,
"node": true,
"mocha": true
"node": true
},

@@ -15,14 +14,21 @@ "parserOptions": {

},
"rules": {
"no-const-assign": "error",
"no-this-before-super": "warn",
"no-undef": "error",
"no-unreachable": "error",
"no-unused-vars": "warn",
"constructor-super": "warn",
"valid-typeof": "warn",
"indent": ["warn", "tab"],
"quotes": ["error", "single"],
"no-extra-parens": "warn"
}
"extends": "eslint-config-collaborne",
"overrides": [
{
"files": "examples/*/index.js",
"parserOptions": {
"sourceType": "script"
}
},
{
"files": "src/index.js",
"rules": {
"sort-keys": "warn"
}
}
]
}

@@ -10,9 +10,9 @@ 'use strict';

const config = {
url: 'https://192.168.99.100:8443',
ca: fs.readFileSync(path.resolve(userDir, '.minikube/ca.crt'), 'UTF-8'),
cert: fs.readFileSync(path.resolve(userDir, '.minikube/apiserver.crt'), 'UTF-8'),
key: fs.readFileSync(path.resolve(userDir, '.minikube/apiserver.key'), 'UTF-8')
key: fs.readFileSync(path.resolve(userDir, '.minikube/apiserver.key'), 'UTF-8'),
url: 'https://192.168.99.100:8443',
};
K8sClient(config).then(function(client) {
K8sClient(config).then(client => {
return client.namespaces.list()

@@ -23,4 +23,4 @@ .then(nsList => nsList.items.map(ns => client.ns(ns.metadata.name).pods.list()))

.then(pods => pods.forEach(pod => console.log(`Discovered pod ${pod.metadata.namespace}/${pod.metadata.name}`)));
}).catch(function(err) {
}).catch(err => {
console.error(`Error: ${err.message}`);
});

@@ -10,15 +10,15 @@ 'use strict';

const config = {
url: 'https://192.168.99.100:8443',
ca: fs.readFileSync(path.resolve(userDir, '.minikube/ca.crt'), 'UTF-8'),
cert: fs.readFileSync(path.resolve(userDir, '.minikube/apiserver.crt'), 'UTF-8'),
key: fs.readFileSync(path.resolve(userDir, '.minikube/apiserver.key'), 'UTF-8')
key: fs.readFileSync(path.resolve(userDir, '.minikube/apiserver.key'), 'UTF-8'),
url: 'https://192.168.99.100:8443',
};
K8sClient(config).then(function(client) {
K8sClient(config).then(client => {
const watchPipe = client.ns('master').pods.watch();
watchPipe.on('data', function(event) {
watchPipe.on('data', event => {
console.log(`${event.type} ${event.object.metadata.name}`);
});
}, function(err) {
}, err => {
console.error(`Cannot connect to cluster: ${err.message}`);
});
{
"name": "auto-kubernetes-client",
"version": "0.4.3",
"description": "NodeJS Kubernetes Client with automatic API discoveryEdit",
"version": "0.5.0",
"description": "NodeJS Kubernetes Client with automatic API discovery",
"main": "src/index.js",
"scripts": {
"install": "check-node-version --package",
"prepublish": "eslint src examples",
"lint": "eslint src examples",
"prepublish": "npm run lint",
"test": "echo 'No tests yet'"

@@ -25,7 +26,8 @@ },

"devDependencies": {
"eslint": "^3.18.0"
"eslint": "^4.0.0",
"eslint-config-collaborne": "^1.1.1"
},
"dependencies": {
"check-node-version": "^2.0.1",
"deepmerge": "^1.3.2",
"check-node-version": "^3.0.0",
"deepmerge": "^2.0.0",
"flatmap": "0.0.3",

@@ -32,0 +34,0 @@ "request": "^2.81.0",

@@ -1,3 +0,1 @@

'use strict';
const request = require('request');

@@ -14,2 +12,3 @@ const url = require('url');

* @property {string} url
* @property {string} [version='v1'] requested API version for the "core" group
* @property {boolean} [insecureSkipTlsVerify]

@@ -39,8 +38,10 @@ * @property {string} [ca]

*
* @param {Configuration} config
* @return {Promise<Client>}
* @param {Configuration} config client configuration
* @return {Promise<Client>} a promise that resolves to a connected client
*/
module.exports = function connect(config) {
function connect(config) {
// Ensure that the config.url ends with a '/'
const configOptions = Object.assign({}, config, { url: config.url.endsWith('/') ? config.url : config.url + '/' });
const configOptions = Object.assign({}, config, {
url: config.url.endsWith('/') ? config.url : `${config.url}/`
});

@@ -50,5 +51,5 @@ /**

*
* @param {string} path
* @param {Object} [extraOptions={}]
* @return {Stream}
* @param {string} path path to query, relative to the API server URL
* @param {Object} [extraOptions={}] additional options for use with `request`
* @return {Request} a stream of the query results
*/

@@ -67,42 +68,42 @@ function streamK8sRequest(path, extraOptions = {}) {

*
* @param {any} path
* @param {any} [extraOptions={}]
* @returns {Promise<>}
* @param {string} path path to query, relative to the API server URL
* @param {Object} [extraOptions={}] additional options for use with `request`
* @returns {Promise<Object>} a promise that resolves to the result of the query
*/
function k8sRequest(path, extraOptions = {}) {
const cooked = !extraOptions.rawResponse;
const options = Object.assign({}, configOptions, { json: true }, extraOptions);
const options = Object.assign({}, configOptions, {json: true}, extraOptions);
return new Promise(function(resolve, reject) {
return request(url.resolve(configOptions.url, path), options, function(err, response, data) {
return new Promise((resolve, reject) => {
return request(url.resolve(configOptions.url, path), options, (err, response, data) => {
if (err) {
return reject(err);
} else {
if (cooked) {
let maybeStatus;
if (typeof data === 'string') {
// The server doesn't (always?) produce a Status for 401/403 errors it seems.
// It should according to https://github.com/kubernetes/community/blob/master/contributors/devel/api-conventions.md#http-status-codes,
// but likely the authentication/authorization layer prevents that.
// See https://github.com/kubernetes/kubernetes/issues/45970
maybeStatus = {
kind: 'Status',
apiVersion: 'v1',
metadata: {},
status: 'Failure',
message: data,
reason: response.statusMessage,
code: response.statusCode,
};
} else {
maybeStatus = data;
}
}
if (maybeStatus.kind === 'Status' && maybeStatus.status === 'Failure') {
// Synthesize an error from the status
return reject(Object.assign(maybeStatus, new Error(maybeStatus.message)));
}
if (cooked) {
let maybeStatus;
if (typeof data === 'string') {
// The server doesn't (always?) produce a Status for 401/403 errors it seems.
// It should according to https://github.com/kubernetes/community/blob/master/contributors/devel/api-conventions.md#http-status-codes,
// but likely the authentication/authorization layer prevents that.
// See https://github.com/kubernetes/kubernetes/issues/45970
maybeStatus = {
apiVersion: 'v1',
code: response.statusCode,
kind: 'Status',
message: data,
metadata: {},
reason: response.statusMessage,
status: 'Failure',
};
} else {
maybeStatus = data;
}
return resolve(data);
if (maybeStatus.kind === 'Status' && maybeStatus.status === 'Failure') {
// Synthesize an error from the status
return reject(Object.assign(maybeStatus, new Error(maybeStatus.message)));
}
}
return resolve(data);
});

@@ -112,5 +113,5 @@ });

function createApi(name, groupPath, version, preferred) {
function createApi(apiName, groupPath, version, preferred) { // eslint-disable-line max-params
// Query that API for all possible operations, and map them.
return k8sRequest(groupPath, {}).then(function(apiResources) {
function createApiFromResources(apiResources) {
// TODO: Transform the API information (APIResourceList) into functions.

@@ -124,5 +125,5 @@ // Basically we have resources[] with each

function createResourceCollection(resource, pathPrefix = '', extraOptions = {}) {
let resourcePath = groupPath + '/';
let resourcePath = `${groupPath}/`;
if (pathPrefix) {
resourcePath += pathPrefix + '/';
resourcePath += `${pathPrefix}/`;
}

@@ -132,11 +133,11 @@ resourcePath += resource.name;

return {
options: function(options) {
options(options) {
return createResourceCollection(resource, pathPrefix, Object.assign({}, extraOptions, options));
},
watch: function(resourceVersion = '', qs = {}) {
watch(resourceVersion = '', qs = {}) {
let buffer = Buffer.alloc(0);
let bufferLength = 0;
const parseJSONStream = through2.obj(function(chunk, enc, callback) {
const parseJSONStream = through2.obj((chunk, enc, callback) => {
// Find a newline in the buffer: everything up to it together with the current buffer contents is for the callback,

@@ -150,3 +151,3 @@ // and the rest forms the new buffer.

chunk.copy(contents, bufferLength, startIndex, newlineIndex);
this.push(JSON.parse(contents.toString('UTF-8')));
parseJSONStream.push(JSON.parse(contents.toString('UTF-8')));

@@ -171,5 +172,5 @@ // Clear the buffer if we used it.

return callback();
}, function(callback) {
}, callback => {
if (bufferLength > 0) {
this.push(JSON.parse(buffer.toString('UTF-8', 0, bufferLength)));
parseJSONStream.push(JSON.parse(buffer.toString('UTF-8', 0, bufferLength)));
bufferLength = 0;

@@ -181,53 +182,81 @@ }

return streamK8sRequest(resourcePath, Object.assign({}, extraOptions, { method: 'GET', json: false, qs: Object.assign({}, qs, { watch: 'true', resourceVersion }) }))
return streamK8sRequest(resourcePath, Object.assign({}, extraOptions, {
json: false,
method: 'GET',
qs: Object.assign({}, qs, {
resourceVersion,
watch: 'true',
})
}))
.pipe(parseJSONStream);
},
list: function(qs = {}) {
return k8sRequest(resourcePath, Object.assign({}, extraOptions, { qs, method: 'GET' }));
list(qs = {}) {
return k8sRequest(resourcePath, Object.assign({}, extraOptions, {
method: 'GET',
qs,
}));
},
create: function(object, qs = {}) {
return k8sRequest(resourcePath, Object.assign({}, extraOptions, { qs, method: 'POST', body: object }));
create(object, qs = {}) {
return k8sRequest(resourcePath, Object.assign({}, extraOptions, {
body: object,
method: 'POST',
qs,
}));
},
deletecollection: function(qs = {}) {
return k8sRequest(resourcePath, Object.assign({}, extraOptions, { qs, method: 'DELETE' }));
deletecollection(qs = {}) {
return k8sRequest(resourcePath, Object.assign({}, extraOptions, {
method: 'DELETE',
qs,
}));
},
}
};
}
function createResource(resource, name, pathPrefix = '', extraOptions = {}) {
let resourcePath = groupPath + '/';
function createResource(resource, name, pathPrefix = '', extraOptions = {}) { // eslint-disable-line max-params
let resourcePath = `${groupPath}/`;
if (pathPrefix) {
resourcePath += pathPrefix + '/';
resourcePath += `${pathPrefix}/`;
}
resourcePath += resource.name + '/';
resourcePath += `${resource.name}/`;
resourcePath += name;
return {
options: function(options) {
options(options) {
return createResource(resource, name, pathPrefix, Object.assign({}, extraOptions, options));
},
get: function(qs = {}) {
return k8sRequest(resourcePath, Object.assign({}, extraOptions, { qs, method: 'GET' }));
get(qs = {}) {
return k8sRequest(resourcePath, Object.assign({}, extraOptions, {
method: 'GET',
qs,
}));
},
create: function(object, qs = {}) {
const createObject = deepMerge({ metadata: { name }}, object);
create(object, qs = {}) {
const createObject = deepMerge({metadata: {name}}, object);
// Creating happens by posting to the list:
let listPath = groupPath + '/';
let listPath = `${groupPath}/`;
if (pathPrefix) {
listPath += pathPrefix + '/';
listPath += `${pathPrefix}/`;
}
listPath += resource.name;
return k8sRequest(listPath, Object.assign({}, extraOptions, { qs, method: 'POST', body: createObject }));
return k8sRequest(listPath, Object.assign({}, extraOptions, {
body: createObject,
method: 'POST',
qs,
}));
},
update: function(object, qs = {}) {
const updateObject = deepMerge({ metadata: { name }}, object);
return k8sRequest(resourcePath, Object.assign({}, extraOptions, { qs, method: 'PUT', body: updateObject }));
update(object, qs = {}) {
const updateObject = deepMerge({metadata: {name}}, object);
return k8sRequest(resourcePath, Object.assign({}, extraOptions, {
body: updateObject,
method: 'PUT',
qs,
}));
},

@@ -248,15 +277,29 @@

* @param {Object} [qs] additional query parameters
* @return {Promise<Object>} promise that resolves to the response of the request
*/
patch: function(object, contentType = 'application/strategic-merge-patch+json', qs = {}) {
patch(object, contentType = 'application/strategic-merge-patch+json', qs = {}) {
// Handle cases where qs is given but not contentType
let realQS;
let realContentType;
if (typeof contentType === 'object') {
qs = contentType;
contentType = 'application/strategic-merge-patch+json';
realQS = contentType;
realContentType = 'application/strategic-merge-patch+json';
} else {
realQS = qs;
realContentType = contentType;
}
return k8sRequest(resourcePath, Object.assign({}, extraOptions, { qs, method: 'PATCH', headers: { 'content-type': contentType }, body: object }));
return k8sRequest(resourcePath, Object.assign({}, extraOptions, {
body: object,
headers: {'content-type': realContentType},
method: 'PATCH',
qs: realQS,
}));
},
delete: function(qs = {}) {
return k8sRequest(resourcePath, Object.assign({}, extraOptions, { qs, method: 'DELETE' }));
delete(qs = {}) {
return k8sRequest(resourcePath, Object.assign({}, extraOptions, {
method: 'DELETE',
qs,
}));
},

@@ -269,6 +312,4 @@ };

[resource.name.toLowerCase()]: createResourceCollection(resource, pathPrefix),
[resource.kind.toLowerCase()]: function(name) {
return createResource(resource, name, pathPrefix)
}
}
[resource.kind.toLowerCase()]: resourceName => createResource(resource, resourceName, pathPrefix)
};
}

@@ -278,25 +319,27 @@

const api = {
name,
apiName,
version: version.version,
preferred,
ns: function(namespace) {
// Return adapted nsResources for this namespace
return Object.keys(nsResources).reduce(function(result, resourceKey) {
return Object.assign(result, createResourceAPI(nsResources[resourceKey], `namespaces/${namespace}`));
}, {});
},
/**
* Get information about the resource with the given kind
*
* @param {String} kind
*/
// XXX: Should this instead exist on the collection or on the single resource via an 'info'/'explain' method?
resource: function(kind) {
return apiResources.resources.find(resource => kind === resource.kind);
},
// Other properties here represent non-namespaced resources
};
// other properties here represent non-namespaced resources
api.ns = namespace => {
// Return adapted nsResources for this namespace
return Object.keys(nsResources).reduce((result, resourceKey) => {
return Object.assign(result, createResourceAPI(nsResources[resourceKey], `namespaces/${namespace}`));
}, {});
};
return apiResources.resources.reduce(function(api, resource) {
/**
* Get information about the resource with the given kind
*
* @param {String} kind
*/
// XXX: Should this instead exist on the collection or on the single resource via an 'info'/'explain' method?
api.resource = kind => {
return apiResources.resources.find(resource => kind === resource.kind);
};
return apiResources.resources.reduce((targetApi, resource) => {
const slashIndex = resource.name.indexOf('/');

@@ -314,7 +357,9 @@ if (slashIndex !== -1) {

} else {
Object.assign(api, createResourceAPI(resource));
Object.assign(targetApi, createResourceAPI(resource));
}
return api;
return targetApi;
}, api);
});
}
return k8sRequest(groupPath, {}).then(createApiFromResources);
}

@@ -324,11 +369,12 @@

return k8sRequest('apis').then(function(apiGroups) {
return k8sRequest('apis').then(apiGroups => {
// Initialize the APIs
const apiPromises = flatMap(apiGroups.groups, function(group) {
const apiPromises = flatMap(apiGroups.groups, group => {
return group.versions.map(version => createApi(group.name, `apis/${version.groupVersion}`, version, version.version === group.preferredVersion.version));
});
apiPromises.push(createApi('', `api/${coreVersion}`, { groupVersion: coreVersion, version: coreVersion }, true));
apiPromises.push(createApi('', `api/${coreVersion}`, {groupVersion: coreVersion,
version: coreVersion}, true));
return Promise.all(apiPromises);
}).then(function(apis) {
return apis.reduce(function(result, api) {
}).then(apis => {
return apis.reduce((result, api) => {
// Build a compatible name for this API. Note that both api.name and api.version can end up empty here.

@@ -341,16 +387,19 @@ const apiNamePrefix = api.name ? `${api.name}/` : '';

return result;
}, {})
}).then(function(apis) {
}, {});
}).then(apis => {
const coreApi = Object.assign({}, apis[coreVersion]);
// Remove the 'name' field from the root object
delete coreApi.name;
delete coreApi.name;
return Object.assign({}, coreApi, {
return Object.assign({}, coreApi, {
/**
* Get the API group with the given name and version
*
* @param {String} groupName name of the group, may optionally contain a '/version' specification
* @param {String} [versionName] version of the group, if not given defaults to the "preferred" version as reported by the server
* @param {string} groupName name of the group, may optionally contain a '/version' specification
* @param {string} [versionName] version of the group, if not given defaults to the "preferred" version as reported by the server
* @return {Object} an API for the given group
* @throws {Error} when no API group is available with that name (and version)
*/
group: function(groupName, versionName) {
group(groupName, versionName) {
// Calculate a full API name from groupName and version name.

@@ -380,1 +429,3 @@ let apiName;

}
module.exports = connect;

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc