Skip to content

Commit

Permalink
feat(Support for more APIs): Apps, Batch, and RBAC (#78)
Browse files Browse the repository at this point in the history
  • Loading branch information
silasbw committed Feb 26, 2017
1 parent d7509ee commit 3734e12
Show file tree
Hide file tree
Showing 11 changed files with 280 additions and 2 deletions.
14 changes: 13 additions & 1 deletion lib/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,15 @@

const Core = require('./core');
const Extensions = require('./extensions');
const Apps = require('./apps');
const Batch = require('./batch');
const Rbac = require('./rbac');

const groups = {
extensions: Extensions
extensions: Extensions,
apps: Apps,
batch: Batch,
'rbac.authorization.k8s.io': Rbac
};

class Api {
Expand All @@ -13,11 +19,17 @@ class Api {
* @param {object} options - Options to pass to client constructors
* @param {object} options.core - Optional default Core client
* @param {object} options.extensions - Optional default Extensions client
* @param {object} options.apps - Optional default Apps client
* @param {object} options.batch - Optional default Batch client
* @param {object} options.rbac - Optional default RBAC client
*/
constructor(options) {
this.options = options;
this.core = options.core || new Core(options);
this.extensions = options.extensions || new Extensions(options);
this.apps = options.apps || new Apps(options);
this.batch = options.batch || new Batch(options);
this.rbac = options.rbac || new Rbac(options);
}

/**
Expand Down
21 changes: 21 additions & 0 deletions lib/apps.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
'use strict';

const ApiGroup = require('./api-group');

class Apps extends ApiGroup {
constructor(options) {
const genericTypes = [
// Deprecated name of statefulsets in kubernetes 1.4
'petsets',
'statefulsets'
];
options = Object.assign({}, options, {
path: 'apis/apps',
version: options.version || 'v1beta1',
genericTypes: genericTypes
});
super(options);
}
}

module.exports = Apps;
22 changes: 22 additions & 0 deletions lib/batch.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
'use strict';

const ApiGroup = require('./api-group');

class Batch extends ApiGroup {
constructor(options) {
const genericTypes = [
'cronjobs',
'jobs',
// Deprecated name for cronjobs in kubernetes 1.4
'scheduledjobs'
];
options = Object.assign({}, options, {
path: 'apis/batch',
version: options.version || 'v1',
genericTypes: genericTypes
});
super(options);
}
}

module.exports = Batch;
10 changes: 10 additions & 0 deletions lib/common.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,11 @@ module.exports.aliasResources = function (resourceObject) {
// http://kubernetes.io/docs/user-guide/kubectl-overview/
// and anything else we think is useful.
const resourceAliases = {
clusterroles: [],
clusterrolebindings: [],
componentstatuses: ['cs'],
configmaps: ['cm'],
cronjobs: [],
daemonsets: ['ds'],
deployments: ['deploy'],
events: ['ev'],
Expand All @@ -19,13 +22,20 @@ module.exports.aliasResources = function (resourceObject) {
nodes: ['no'],
persistentvolumes: ['pv'],
persistentvolumeclaims: ['pvc'],
// Deprecated name of statefulsets in kubernetes 1.4
petsets: [],
pods: ['po'],
replicationcontrollers: ['rc'],
replicasets: ['rs'],
resourcequotas: ['quota'],
roles: [],
rolebindings: [],
// Deprecated name of cronjobs in kubernetes 1.4
scheduledjobs: [],
secrets: [],
serviceaccounts: [],
services: ['svc'],
statefulsets: [],
thirdpartyresources: []
};

Expand Down
3 changes: 3 additions & 0 deletions lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ module.exports.Core = core;
module.exports.Extensions = require('./extensions');
module.exports.ThirdPartyResources = require('./third-party-resources');
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
};
12 changes: 11 additions & 1 deletion lib/namespaces.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,10 @@ const DEFAULT_RESOURCES = [
{ name: 'replicationcontrollers', Constructor: ReplicationControllers },
{ name: 'pods', Constructor: Pods }
].concat([
'clusterroles',
'clusterrolebindings',
'configmaps',
'cronjobs',
'daemonsets',
'deployments',
'endpoints',
Expand All @@ -21,11 +24,18 @@ const DEFAULT_RESOURCES = [
'jobs',
'limitranges',
'persistentvolumeclaims',
// Deprecated name of statefulsets in kubernetes 1.4,
'petsets',
'replicasets',
'resourcequotas',
'roles',
'rolebindings',
// Deprecated name of cronjobs in kubernetes 1.4
'scheduledjobs',
'secrets',
'serviceaccounts',
'services'
'services',
'statefulsets'
]);

class Namespaces extends BaseObject {
Expand Down
22 changes: 22 additions & 0 deletions lib/rbac.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
'use strict';

const ApiGroup = require('./api-group');

class Rbac extends ApiGroup {
constructor(options) {
const genericTypes = [
'clusterroles',
'clusterrolebindings',
'roles',
'rolebindings'
];
options = Object.assign({}, options, {
path: 'apis/rbac.authorization.k8s.io',
version: options.version || 'v1alpha1',
genericTypes: genericTypes
});
super(options);
}
}

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

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

const common = require('./common');
const beforeTesting = common.beforeTesting;

const testStatefulSet = {
apiVersion: 'apps/v1beta1',
kind: 'StatefulSet',
metadata: {
name: 'web'
},
spec: {
serviceName: 'nginx',
template: {
spec: {
containers: [
{
image: 'fake-image-kubernetes-client',
name: 'nginx'
}
]
},
metadata: {
labels: {
app: 'nginx'
}
}
},
replicas: 1
}
};

describe('lib.apps', () => {
describe('.statefulsets', () => {
const testStatefuleSetName = testStatefulSet.metadata.name;

beforeTesting('int', common.changeName);
beforeTesting('unit', () => {
nock(common.apps.url)
.post(`${ common.apps.path }/namespaces/${ common.currentName }/statefulsets`)
.reply(201, testStatefulSet)
.get(`${ common.apps.path }/namespaces/${ common.currentName }/statefulsets/${ testStatefuleSetName }`)
.reply(200, testStatefulSet);
});

it('can POST and GET', done => {
async.series([
next => common.apps.ns.statefulsets.post({ body: testStatefulSet }, next),
next => common.apps.ns.statefulsets.get(testStatefuleSetName, next)
], (err, results) => {
assume(err).is.falsy();
const getResult = results[1];
assume(getResult.metadata.name).is.equal(testStatefuleSetName);
done();
});
});
});
});
60 changes: 60 additions & 0 deletions test/batch.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
'use strict';

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

const common = require('./common');
const beforeTesting = common.beforeTesting;

const testJob = {
apiVersion: 'batch/v1',
kind: 'Job',
metadata: {
name: 'pi'
},
spec: {
template: {
spec: {
restartPolicy: 'Never',
containers: [
{
image: 'perl',
command: ['perl', '-Mbignum=bpi', '-wle', 'print bpi(2000)'],
name: 'pi'
}
]
},
metadata: {
name: 'pi'
}
}
}
};

describe('lib.batch', () => {
describe('.jobs', () => {
const testJobName = testJob.metadata.name;

beforeTesting('int', common.changeName);
beforeTesting('unit', () => {
nock(common.batch.url)
.post(`${ common.batch.path }/namespaces/${ common.currentName }/jobs`)
.reply(201, testJob)
.get(`${ common.batch.path }/namespaces/${ common.currentName }/jobs/${ testJobName }`)
.reply(200, testJob);
});

it('can POST and GET', done => {
async.series([
next => common.batch.ns.jobs.post({ body: testJob }, next),
next => common.batch.ns.jobs.get(testJobName, next)
], (err, results) => {
assume(err).is.falsy();
const getResult = results[1];
assume(getResult.metadata.name).is.equal(testJobName);
done();
});
});
});
});
6 changes: 6 additions & 0 deletions test/common.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,11 @@ const path = require('path');
const yaml = require('js-yaml');

const Api = require('../lib/api');
const Apps = require('../lib/apps');
const Batch = require('../lib/batch');
const Core = require('../lib/core');
const Extensions = require('../lib/extensions');
const Rbac = require('../lib/rbac');
const ThirdPartyResources = require('../lib/third-party-resources');

const defaultName = process.env.NAMESPACE || 'integration-tests';
Expand Down Expand Up @@ -66,7 +69,10 @@ function injectApis(options) {
const apis = {
api: { cls: Core },
apiGroup: { cls: Api },
apps: { cls: Apps },
batch: { cls: Batch },
extensions: { cls: Extensions },
rbac: { cls: Rbac },
thirdPartyResources: { cls: ThirdPartyResources, options: { group: 'kubernetes-client.com' } }
};
Object.keys(apis).forEach(apiName => {
Expand Down
50 changes: 50 additions & 0 deletions test/rbac.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
'use strict';

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

const common = require('./common');
const beforeTesting = common.beforeTesting;

const testRbac = {
kind: 'Role',
apiVersion: 'rbac.authorization.k8s.io/v1alpha1',
metadata: {
name: 'pod-reader'
},
rules: [{
apiGroups: [''],
resources: ['pods'],
verbs: ['get', 'watch', 'list']
}]
};

describe('lib.rbac', () => {
describe('.Rbac', () => {
const testRbacName = testRbac.metadata.name;

beforeTesting('unit', () => {
nock(common.rbac.url)
.post(`${ common.rbac.path }/namespaces/${ common.currentName }/roles`)
.reply(201, testRbac)
.get(`${ common.rbac.path }/namespaces/${ common.currentName }/roles/${ testRbacName }`)
.reply(200, testRbac);
});

// NOTE: Running only unit tests. Setting up RBAC is more involved, and it
// makes it cumbersome to run the other integration tests. We need
// improvements to our integration test harness to make this work well.
common.only('unit', 'can POST and GET', done => {
async.series([
next => common.rbac.ns.roles.post({ body: testRbac }, next),
next => common.rbac.ns.roles.get(testRbacName, next)
], (err, results) => {
assume(err).is.falsy();
const getResult = results[1];
assume(getResult.metadata.name).is.equal(testRbacName);
done();
});
});
});
});

0 comments on commit 3734e12

Please sign in to comment.