Skip to content

Commit

Permalink
Add support for kong >=0.10.x, resolve #63
Browse files Browse the repository at this point in the history
  • Loading branch information
CyExy committed Apr 13, 2017
1 parent fe36df0 commit 3aaa289
Show file tree
Hide file tree
Showing 11 changed files with 221 additions and 61 deletions.
45 changes: 38 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,11 +78,19 @@ apis:
- name: mockbin # unique api name
ensure: "present" # Set to "removed" to have Kongfig ensure the API is removed. Default is present.
attributes:
request_host:
request_path:
strip_request_path:
preserve_host:
upstream_url: # (required)
upstream_url: string # (required)
hosts: [string]
uris: [string]
methods: ["POST", "GET"]
strip_uri: bool
preserve_host: bool
retries: int
upstream_connect_timeout: int
upstream_read_timeout: int
upstream_send_timeout: int
https_only: bool # (required)
http_if_terminated: bool

```

Api plugin schema:
Expand Down Expand Up @@ -213,7 +221,7 @@ consumers:
name:
client_id: # required
client_secret:
redirect_uri: # required by kong
redirect_uri: string | [string] # required by kong
```
[HMAC Authentication](https://getkong.org/plugins/hmac-authentication/)
Expand Down Expand Up @@ -285,7 +293,7 @@ consumers:

credentialSchema:
custom_jwt:
id: "key" # credential id name
id: "key" # credential id name
```
Expand Down Expand Up @@ -314,6 +322,29 @@ consumers:
ensure: "present"
```
## Migrating from Kong <=0.9 to >=0.10
kongfig translates pre `>=0.10` kong config files automatically when applying them.

So you can export your config from `<=0.9` kong instance by running:

```bash
kongfig dump --host kong_9:8001 > config.v9.yml
```

Then apply it to kong `0.10` instance

```bash
kongfig apply --path config.v9.yml --host kong_10:8001
```

`apis` endpoint changed between `<=0.9` and `>=0.10`:
* `request_host: string` to `hosts: [string]`
* `request_path: string` to `uris: [string]`
* `strip_request_path: bool` -> `strip_uri: bool`
* Adds `methods`, `retries`, `upstream_connect_timeout`, `upstream_read_timeout`, `upstream_send_timeout`, `https_only`, `http_if_terminated`

---
Created by [MyBuilder](http://www.mybuilder.com/) - Check out our [blog](http://tech.mybuilder.com/) for more information and our other open-source projects.

Expand Down
11 changes: 3 additions & 8 deletions config.js.sample
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ module.exports = {
name: "mockbin",
ensure: "present",
attributes: {
upstream_url: "http://mockbin.com/",
request_host: "mockbin.com"
upstream_url: "http://mockbin.com",
hosts: ["mockbin.com"]
},
plugins: [
{
Expand Down Expand Up @@ -43,10 +43,5 @@ module.exports = {
username: "ie",
ensure: "removed"
}
],
credentialSchemas: {
custom_jwt: {
id: "key"
}
}
]
};
11 changes: 3 additions & 8 deletions config.json.sample
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
"name": "mockbin",
"ensure": "present",
"attributes": {
"upstream_url": "http://mockbin.com/",
"request_host": "mockbin.com"
"upstream_url": "http://mockbin.com",
"hosts": ["mockbin.com"]
},
"plugins": [
{
Expand Down Expand Up @@ -43,10 +43,5 @@
"username": "ie",
"ensure": "removed"
}
],
"credentialSchemas": {
"custom_jwt": {
"id": "key"
}
}
]
}
9 changes: 3 additions & 6 deletions config.yml.sample
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@
- name: "mockbin"
ensure: "present"
attributes:
upstream_url: "http://mockbin.com/"
request_host: "mockbin.com"
upstream_url: "http://mockbin.com"
hosts:
- "mockbin.com"
plugins:
- name: "key-auth"
- name: cors
Expand All @@ -26,7 +27,3 @@

- username: "ie"
ensure: "removed"

credentialSchemas:
custom_jwt:
id: key
36 changes: 10 additions & 26 deletions src/core.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import assign from 'object-assign';
import kongState from './kongState';
import {getSchema as getConsumerCredentialSchema} from './consumerCredentials';
import {normalize as normalizeAttributes} from './utils';
import { migrateApiDefinition } from './migrate';
import diff from './diff';
import {
noop,
createApi,
Expand Down Expand Up @@ -120,8 +122,10 @@ function _bindWorldState(adminApi) {
}
}

function _createWorld({apis, consumers, plugins}) {
function _createWorld({apis, consumers, plugins, version}) {
const world = {
getVersion: () => version,

hasApi: apiName => Array.isArray(apis) && apis.some(api => api.name === apiName),
getApi: apiName => {
const api = apis.find(api => api.name === apiName);
Expand Down Expand Up @@ -258,26 +262,14 @@ function _createWorld({apis, consumers, plugins}) {
return consumer.custom_id == custom_id;
},

isApiUpToDate: (api) => {
let current = world.getApi(api.name);

let different = Object.keys(api.attributes).filter(key => {
return api.attributes[key] !== current[key];
});

return different.length == 0;
},
isApiUpToDate: (api) => diff(api.attributes, world.getApi(api.name)).length == 0,

isApiPluginUpToDate: (apiName, plugin) => {
if (false == plugin.hasOwnProperty('attributes')) {
// of a plugin has no attributes, and its been added then it is up to date
return true;
}

const diff = (a, b) => Object.keys(a).filter(key => {
return JSON.stringify(a[key]) !== JSON.stringify(b[key]);
});

let current = world.getPlugin(apiName, plugin.name);
let {config, ...rest} = normalizeAttributes(plugin.attributes);

Expand All @@ -290,10 +282,6 @@ function _createWorld({apis, consumers, plugins}) {
return true;
}

const diff = (a, b) => Object.keys(a).filter(key => {
return JSON.stringify(a[key]) !== JSON.stringify(b[key]);
});

let current = world.getGlobalPlugin(plugin.name);
let {config, ...rest} = normalizeAttributes(plugin.attributes);

Expand All @@ -303,12 +291,8 @@ function _createWorld({apis, consumers, plugins}) {
isConsumerCredentialUpToDate: (username, credential) => {
const current = world.getConsumerCredential(username, credential.name, credential.attributes);

let different = Object.keys(credential.attributes).filter(key => {
return JSON.stringify(credential.attributes[key]) !== JSON.stringify(current[key]);
});

return different.length === 0;
}
return diff(credential.attributes, current).length === 0;
},
};

return world;
Expand All @@ -329,7 +313,7 @@ function _api(api) {
validateEnsure(api.ensure);
validateApiRequiredAttributes(api);

return world => {
return migrateApiDefinition(api, (api, world) => {
if (api.ensure == 'removed') {
return world.hasApi(api.name) ? removeApi(api.name) : noop();
}
Expand All @@ -345,7 +329,7 @@ function _api(api) {
}

return createApi(api.name, api.attributes);
};
});
}

function _apiPlugins(api) {
Expand Down
36 changes: 36 additions & 0 deletions src/diff.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
const isValueSameOneArrayElement = (a, b) => {
return typeof a === 'string'
&& Array.isArray(b)
&& b.length === 1
&& !isValueDifferent(a, b[0]);
};

const isValueDifferent = (a, b) => {
if (Array.isArray(a)) {
return !Array.isArray(b)
|| a.length != b.length
|| a.filter(x => b.indexOf(x) === -1).length > 0;
}

return JSON.stringify(a) !== JSON.stringify(b);
}

export default (defined, server) => {
const keys = Object.keys(defined);

return keys.reduce((changed, key) => {
if (key === 'redirect_uri') {
// hack for >=0.8.2 that allows multiple redirect_uris,
// but accepts a string as well
if (isValueSameOneArrayElement(defined[key], server[key])) {
return changed;
}
}

if (isValueDifferent(defined[key], server[key])) {
return [...changed, key];
}

return changed;
}, []);
};
6 changes: 4 additions & 2 deletions src/kongState.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {getSupportedCredentials} from './consumerCredentials'

export default async ({fetchApis, fetchPlugins, fetchGlobalPlugins, fetchConsumers, fetchConsumerCredentials, fetchConsumerAcls}) => {
export default async ({fetchApis, fetchPlugins, fetchGlobalPlugins, fetchConsumers, fetchConsumerCredentials, fetchConsumerAcls, fetchKongVersion}) => {
const version = await fetchKongVersion();
const apis = await fetchApis();
const apisWithPlugins = await Promise.all(apis.map(async item => {
const plugins = await fetchPlugins(item.id);
Expand Down Expand Up @@ -47,6 +48,7 @@ export default async ({fetchApis, fetchPlugins, fetchGlobalPlugins, fetchConsume
return {
apis: apisWithPlugins,
consumers: consumersWithCredentialsAndAcls,
plugins: globalPlugins
plugins: globalPlugins,
version,
};
};
46 changes: 46 additions & 0 deletions src/migrate.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import semVer from 'semver';

const DEFINITION_V1 = 'v1';
const DEFINITION_V2 = 'v2';

const _removeUndefined = x => JSON.parse(JSON.stringify(x));

const _guessDefinitionVersion = (api) => {
if (['hosts', 'uris', 'methods'].filter(x => api.attributes.hasOwnProperty(x)).length > 0) {
return DEFINITION_V2;
}

return DEFINITION_V1;
};

const _migrateV1toV2 = (api) => {
const {
request_host,
request_path,
strip_request_path,
...oldAttributes,
} = api.attributes;

const newAttributes = {
hosts: api.attributes.request_host ? [api.attributes.request_host] : undefined,
uris: api.attributes.request_path ? [api.attributes.request_path] : undefined,
strip_uri: api.attributes.strip_request_path,
};

return _removeUndefined({ ...api, attributes: { ...oldAttributes, ...newAttributes }});
};

const _migrateApiDefinitionToVersion = (api, kongVersion) => {
switch (_guessDefinitionVersion(api)) {
case DEFINITION_V1:
if (semVer.gte(kongVersion, '0.10.0')) {
return _migrateV1toV2(api);
}

return api;
default:
return api;
}
}

export const migrateApiDefinition = (api, fn) => world => fn(_migrateApiDefinitionToVersion(api, world.getVersion()), world);
9 changes: 5 additions & 4 deletions test/apis.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ describe("apis", () => {
"upstream_url": "bar"
}
}])
.map(x => x({hasApi: () => false}));
.map(x => x({hasApi: () => false, getVersion: () => '0.10.0'}));

expect(actual).to.be.eql([
createApi('leads', {upstream_url: "bar"})
Expand All @@ -34,7 +34,7 @@ describe("apis", () => {
"upstream_url": "bar"
}
}])
.map(x => x({hasApi: () => true}));
.map(x => x({hasApi: () => true, getVersion: () => '0.10.0'}));

expect(actual).to.be.eql([
removeApi('leads')
Expand All @@ -49,7 +49,7 @@ describe("apis", () => {
"upstream_url": "bar"
}
}])
.map(x => x({hasApi: () => false}));
.map(x => x({hasApi: () => false, getVersion: () => '0.10.0'}));

expect(actual).to.be.eql([
noop()
Expand All @@ -64,7 +64,7 @@ describe("apis", () => {
"upstream_url": "bar"
}
}])
.map(x => x({hasApi: () => true, isApiUpToDate: () => false}));
.map(x => x({hasApi: () => true, isApiUpToDate: () => false, getVersion: () => '0.10.0'}));

expect(actual).to.be.eql([
updateApi('leads', {upstream_url: "bar"})
Expand Down Expand Up @@ -96,6 +96,7 @@ describe("apis", () => {
hasApi: () => false,
hasPlugin: () => false,
getApiId: () => 'abcd-1234',
getVersion: () => '0.10.0'
}));

expect(actual).to.be.eql([
Expand Down
Loading

0 comments on commit 3aaa289

Please sign in to comment.