Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Load from cluster spec #218

Merged
merged 7 commits into from
May 21, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,16 @@ const openshiftRestClient = require('openshift-rest-client').OpenshiftClient;

To see more examples of how to customize your config, check out the [kubernetes-client Initializing section](https://www.npmjs.com/package/kubernetes-client#initializing)

#### Load API from a Remote Cluster

By default, the openshift-rest-client, will load a swagger spec file that is included with the module. This has all the basic API's that come with Openshift and Kubernetes. If you are using operators to extend your cluster, the openshift-rest-client, by default, won't know about them.
lholmquist marked this conversation as resolved.
Show resolved Hide resolved

To fix this, you can tell the openshift-rest-client to load the spec file from your remote cluster using the `loadSpecFromCluster` option. Setting this to true, will try to load the spec file from your clusters `/openapi/v2` endpoint. If that doesn't exist, it will also try, `/swagger.json`

If the remote spec cannot be loaded, a warning will be output to the console and the default spec will be loaded.

In a future version of this client, this might become the default.



#### Changes in 2.0
Expand Down
22 changes: 20 additions & 2 deletions lib/openshift-rest-client.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ const spec = JSON.parse(zlib.gunzipSync(fs.readFileSync(path.join(__dirname, 'sp
* Builds the rest client based on provided or default kubernetes configuration.
*
* @param {object} [settings] - settings object for the openshiftClient function
* @param {boolean} [settings.loadSpecFromCluster] - load the api spec from a remote cluster. Defaults to false
* @param {object|string} [settings.config] - custom config object. String value will assume a config file location
* @param {string} [settings.config.url] - Openshift cluster url
* @param {string} [settings.config.authUrl] - Openshift Basic auth url
Expand All @@ -72,7 +73,13 @@ const spec = JSON.parse(zlib.gunzipSync(fs.readFileSync(path.join(__dirname, 'sp
*/
async function openshiftClient (settings = {}) {
let config = settings.config;
const clientConfig = { backend: null, spec, getNames };

const clientConfig = { backend: null, /* spec, */ getNames };

if (!settings.loadSpecFromCluster) {
clientConfig.spec = spec;
}

const kubeconfig = new KubeConfig();

let fullyUserDefined = false;
Expand Down Expand Up @@ -143,7 +150,18 @@ async function openshiftClient (settings = {}) {
clientConfig.backend = new Request({ kubeconfig });
}

const client = new Client(clientConfig);
let client = new Client(clientConfig);
if (settings.loadSpecFromCluster) {
try {
await client.loadSpec();
} catch (err) {
// Warn the user there was an error and loading the other spec
console.warn('Warning: Remote client spec unable to load', err.message);
console.warn('Warning: Loading default spec instead');
clientConfig.spec = spec;
client = new Client(clientConfig);
}
}

// CRD with the service instance stuff, but only to this client, not the cluster
client.addCustomResourceDefinition(serviceCatalogCRD);
Expand Down
83 changes: 83 additions & 0 deletions test/openshift-client-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

const test = require('tape');
const proxyquire = require('proxyquire');
const nock = require('nock');

const userDefinedConfig = require('./test-config.json');

Expand Down Expand Up @@ -189,3 +190,85 @@ test('test different config - different location as a string', async (t) => {
t.equal(kubeconfig.currentContext, 'for-node-client-testing/192-168-99-100:8443/developer', 'current context is correctly loaded');
t.end();
});

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add a test for the failing condition perhaps?

test('openshift client tests - loadSpecFromCluster', async (t) => {
const openshiftRestClient = require('../');

openshiftRestClient.config.loadFromString(JSON.stringify(userDefinedConfig));
const settings = {
loadSpecFromCluster: true,
config: openshiftRestClient.config
};

nock('https://192.168.99.100:8443')
.matchHeader('authorization', 'Bearer zVBd1ZFeJqEAILJgimm4-gZJauaw3PW4EVqV_peEZ3U')
.get('/openapi/v2')
.reply(201, { paths: {} });

const osClient = await openshiftRestClient.OpenshiftClient(settings);

t.pass('client created using the loadSpec function and hitting the /openapi/v2');

t.ok(osClient.kubeconfig, 'client should have the kubeconfig object');
t.end();
});

test('openshift client tests - loadSpecFromCluster - Fail to load remote and load default spec', async (t) => {
const openshiftRestClient = require('../');

openshiftRestClient.config.loadFromString(JSON.stringify(userDefinedConfig));
const settings = {
loadSpecFromCluster: true,
config: openshiftRestClient.config
};

nock('https://192.168.99.100:8443')
.matchHeader('authorization', 'Bearer zVBd1ZFeJqEAILJgimm4-gZJauaw3PW4EVqV_peEZ3U')
.get('/openapi/v2')
.reply(404, { message: 'Nope' })
.get('/swagger.json')
.reply(404, { message: 'Nope' });

const osClient = await openshiftRestClient.OpenshiftClient(settings);

t.pass('Failing client load should load default spec');

t.ok(osClient.apis['build.openshift.io'], 'client object should have a build object');
t.ok(osClient.apis.build, 'build object is aliased');

t.ok(osClient.apis['apps.openshift.io'], 'client object should have a apps object');
t.ok(osClient.apis.app, 'apps object is aliased to app');

t.ok(osClient.apis['authorization.openshift.io'], 'client object should have a authorization object');
t.ok(osClient.apis.authorization, 'authorization object is aliased to authorization');

t.ok(osClient.apis['image.openshift.io'], 'client object should have a image object');
t.ok(osClient.apis.image, 'image object is aliased to image');

t.ok(osClient.apis['network.openshift.io'], 'osClient object should have a network object');
t.ok(osClient.apis.network, 'network object is aliased to network');

t.ok(osClient.apis['oauth.openshift.io'], 'osClient object should have a oauth object');
t.ok(osClient.apis.oauth, 'oauth object is aliased to oauth');

t.ok(osClient.apis['project.openshift.io'], 'osClient object should have a project object');
t.ok(osClient.apis.project, 'project object is aliased to project');

t.ok(osClient.apis['quota.openshift.io'], 'osClient object should have a quota object');
t.ok(osClient.apis.quota, 'quota object is aliased to quota');

t.ok(osClient.apis['route.openshift.io'], 'osClient object should have a route object');
t.ok(osClient.apis.route, 'route object is aliased to route');

t.ok(osClient.apis['security.openshift.io'], 'osClient object should have a security object');
t.ok(osClient.apis.security, 'security object is aliased to security');

t.ok(osClient.apis['template.openshift.io'], 'osClient object should have a template object');
t.ok(osClient.apis.template, 'template object is aliased to template');

t.ok(osClient.apis['user.openshift.io'], 'osClient object should have a user object');
t.ok(osClient.apis.user, 'user object is aliased to user');

t.ok(osClient.kubeconfig, 'client should have the kubeconfig object');
t.end();
});