diff --git a/lib/container-base-object.js b/lib/container-base-object.js new file mode 100644 index 00000000..58fd0ec2 --- /dev/null +++ b/lib/container-base-object.js @@ -0,0 +1,49 @@ +'use strict'; + +const BaseObject = require('./base'); + +class ContainerBaseObject extends BaseObject { + /** + * Create generic Kubernetes API object that might contain other resources. + * For example, a named Pod contains .log resources (core.ns.pods('foo').log). + * + * @param {object} options - Options object + * @param {string} options.resources - Array of resources to add + */ + constructor(options) { + super(options); + if (options.resources) { + options.resources.forEach(resource => this.addResource(resource)); + } + } + + /** + * Add a resource to the container object. + * @param {string|object} options - resource name or options object + * @param {string} options.name - resource name + * @param {fn} options.Constructor - constructor for new resource + * @returns {object} returns this to facilitate chaining + */ + addResource(options) { + if (typeof options === 'string') { + options = { name: options, Constructor: BaseObject }; + } else if (!options.name || !options.Constructor) { + throw new RangeError( + 'NamedBaseObject.addResource: options requires .name and .Constructor'); + } + + if (this[options.name]) { + throw new RangeError( + `NamedBaseObject.addResource: .${ options.name } already exists`); + } + this[options.name] = new options.Constructor({ + api: this.api, + name: options.name, + parentPath: this.path + }); + + return this; + } +} + +module.exports = ContainerBaseObject; diff --git a/lib/pods.js b/lib/pods.js index 105862f2..bc7d4bbe 100644 --- a/lib/pods.js +++ b/lib/pods.js @@ -3,8 +3,9 @@ const util = require('util'); const BaseObject = require('./base'); +const ContainerBaseObject = require('./container-base-object'); -class NamedPods extends BaseObject { +class NamedPods extends ContainerBaseObject { /** * Create a named Pod Kubernetes object with a log. * @extends BaseObject @@ -14,12 +15,9 @@ class NamedPods extends BaseObject { * @param {string} options.path - Optional path of this resource */ constructor(options) { - super(options); - this.log = new BaseObject({ - api: this.api, - name: 'log', - parentPath: this.path - }); + super(Object.assign({ + resources: ['log'] + }, options)); } } diff --git a/test/container-base-object.test.js b/test/container-base-object.test.js new file mode 100644 index 00000000..e61940b1 --- /dev/null +++ b/test/container-base-object.test.js @@ -0,0 +1,30 @@ +'use strict'; + +const assume = require('assume'); + +const ContainerBaseObject = require('../lib/container-base-object'); + +describe('lib.container-base-object', () => { + describe('.ContainerBaseObject', () => { + it('adds resources specified in the constructor', () => { + const fake = new ContainerBaseObject({ resources: ['foo'] }); + assume(fake.foo).is.a('function'); + }); + + it('throws an error if missing resource name', () => { + const fn = () => new ContainerBaseObject({ resources: [{ Constructor: 'fake' }] }); + assume(fn).throws(); + }); + + it('throws an error if missing resource Constructor', () => { + const fn = () => new ContainerBaseObject({ resources: [{ name: 'fake' }] }); + assume(fn).throws(); + }); + + it('throws an error for adding the resource', () => { + const fake = new ContainerBaseObject({ resources: ['foo'] }); + const fn = () => fake.addResource('foo'); + assume(fn).throws(); + }); + }); +});