Skip to content

Commit

Permalink
feat(dynamic clients): introduce more user-friendly Client classes (#207
Browse files Browse the repository at this point in the history
)

Client and SyncClient abstract away the HTTP request adapter.
  • Loading branch information
silasbw committed Mar 7, 2018
1 parent e70f9cb commit 162b33e
Show file tree
Hide file tree
Showing 11 changed files with 201 additions and 2 deletions.
20 changes: 20 additions & 0 deletions examples/client-from-apiserver-swagger.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
//
// Create an API client based on the swagger.json from the current kubeconfig
// cluster.
//
const Client = require('kubernetes-client').Client
const config = require('kubernetes-client').config;

const deploymentManifest = require('./nginx-deployment.json');

async function main() {
try {
const client = await new Client({ config: config.fromKubeconfig() });
const create = await client.apis.apps.v1.namespaces('default').deployments.post({ body: deploymentManifest });
console.log('Result: ', create);
} catch (err) {
console.error('Error: ', err);
}
}

main();
38 changes: 38 additions & 0 deletions examples/nginx-deployment.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
{
"kind": "Deployment",
"spec": {
"replicas": 1,
"template": {
"spec": {
"containers": [
{
"image": "nginx:1.7.9",
"name": "nginx",
"ports": [
{
"containerPort": 80
}
]
}
]
},
"metadata": {
"labels": {
"app": "nginx"
}
}
},
"selector": {
"matchLabels": {
"app": "nginx"
}
}
},
"apiVersion": "apps/v1",
"metadata": {
"labels": {
"app": "nginx"
},
"name": "nginx-deployment"
}
}
20 changes: 20 additions & 0 deletions examples/sync-client-version.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
//
// Create an API client based on a specified API version. kubernetes-client uses
// included swagger specification files.
//
const Client = require('kubernetes-client').SyncClient
const config = require('kubernetes-client').config;

const deploymentManifest = require('./nginx-deployment.json');

async function main() {
try {
const client = new Client({ config: config.fromKubeconfig(), version: '1.9' });
const create = await client.apis.apps.v1.namespaces('default').deployments.post({ body: deploymentManifest });
console.log('Result: ', create);
} catch (err) {
console.error('Error: ', err);
}
}

main();
20 changes: 20 additions & 0 deletions lib/client.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
'use strict';
const Request = require('./request');
const SwaggerClient = require('./swagger-client');

class Client extends SwaggerClient {
constructor(options) {
const http = new Request(options.config);
return new Promise((resolve, reject) => {
http.request('GET', { path: '/swagger.json' }, (err, res) => {
if (err) return reject(err);
if (res.statusCode !== 200) {
return reject(new Error(`Failed to get swagger.json: ${ res.statusCode }`));
}
resolve(super({ http, spec: res.body }));
});
});
}
}

module.exports = Client;
12 changes: 10 additions & 2 deletions lib/index.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,24 @@
//
// Deprecated interface
//
const core = require('./core');

module.exports = core;
module.exports.Api = require('./api');
module.exports.ApiExtensions = require('./api-extensions');
module.exports.Core = core;
module.exports.Extensions = require('./extensions');
module.exports.ThirdPartyResources = require('./third-party-resources');
module.exports.CustomResourceDefinitions = require('./custom-resource-definitions');
module.exports.config = require('./config');
module.exports.Apps = require('./apps');
module.exports.Batch = require('./batch');
module.exports.Rbac = require('./rbac');
module.exports.testUtils = {
aliasResources: require('./common').aliasResources
};

//
// Current interface
//
module.exports.SyncClient = require('./sync-client');
module.exports.Client = require('./client');
module.exports.config = require('./config');
Binary file added lib/specs/swagger-1.7.json.gz
Binary file not shown.
Binary file added lib/specs/swagger-1.8.json.gz
Binary file not shown.
Binary file added lib/specs/swagger-1.9.json.gz
Binary file not shown.
26 changes: 26 additions & 0 deletions lib/sync-client.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
'use strict';
/* eslint-disable no-sync */

const fs = require('fs');
const path = require('path');
const zlib = require('zlib');

const Request = require('./request');
const SwaggerClient = require('./swagger-client');

class SyncClient extends SwaggerClient {
constructor(options) {
const http = new Request(options.config);
let spec = options.spec;
if (!spec) {
const swaggerPath = path.join(
__dirname,
'specs',
`swagger-${ options.version }.json.gz`);
spec = JSON.parse(zlib.gunzipSync(fs.readFileSync(swaggerPath)));
}
super({ http, spec });
}
}

module.exports = SyncClient;
36 changes: 36 additions & 0 deletions test/client.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
'use strict';

const assume = require('assume');
const nock = require('nock');

const Client = require('../lib/client');
const common = require('./common');
const beforeTesting = common.beforeTesting;

describe('lib.client', () => {
describe('Client', () => {
beforeTesting('unit', () => {
nock(common.api.url)
.get('/swagger.json')
.reply(200, {
paths: {
'/api/': {
get: {
operationId: 'getCoreAPIVersions'
}
}
}
});
});
it('creates a dynamically generated client', done => {
const config = { url: common.api.url };
const promise = new Client({ config });
promise
.then(client => {
assume(client.api.get).is.a('function');
done();
})
.catch(err => done(err));
});
});
});
31 changes: 31 additions & 0 deletions test/sync-client.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
'use strict';

const assume = require('assume');

const Client = require('../lib/sync-client');

describe('lib.sync-client', () => {
describe('SyncClient', () => {
it('creates a dynamically generated client synchronously based on version', () => {
const options = { config: {}, version: '1.9' };
const client = new Client(options);
assume(client.api.get).is.a('function');
});
it('creates a dynamically generated client synchronously from swagger spec', () => {
const options = {
config: {},
spec: {
paths: {
'/api/': {
get: {
operationId: 'getCoreAPIVersions'
}
}
}
}
};
const client = new Client(options);
assume(client.api.get).is.a('function');
});
});
});

0 comments on commit 162b33e

Please sign in to comment.