Skip to content

Commit

Permalink
feat: allow arbitrary construct names (#64)
Browse files Browse the repository at this point in the history
To improve interoperability of cdk8s with other frameworks, do not impose DNS_LABEL constraints on construct names. Instead, normalize them to DNS_LABEL in case they don't comply.

Related to #48
  • Loading branch information
Elad Ben-Israel authored Mar 10, 2020
1 parent 80e8402 commit 1309960
Show file tree
Hide file tree
Showing 2 changed files with 21 additions and 23 deletions.
27 changes: 13 additions & 14 deletions packages/cdk8s/lib/names.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,24 +39,16 @@ export class Names {
throw new Error(`minimum max length for object names is ${HASH_LEN} (required for hash)`);
}

const components = path.split('/');
let components = path.split('/');

// verify components only use allowed chars.
for (const comp of components) {
if (!VALIDATE.test(comp)) {
throw new Error(`"${comp}" is not a valid object name. The characters allowed in names are: digits (0-9), lower case letters (a-z), -, and .`);
}

if (comp.length > maxLen) {
throw new Error(`Object name "${comp}" is too long. Maximum allowed length is ${maxLen}`);
}
}

// special case: if we only have one component in our path, we don't decorate it
if (components.length === 1) {
// special case: if we only have one component in our path and it adheres to DNS_NAME, we don't decorate it
if (components.length === 1 && VALIDATE.test(components[0]) && components[0].length <= maxLen) {
return components[0];
}

// okay, now we need to normalize all components to adhere to DNS_NAME and append the hash of the full path.
components = components.map(c => normalizeToDnsName(c, maxLen));

components.push(calcHash(path, HASH_LEN));

return components
Expand All @@ -75,6 +67,13 @@ export class Names {
}
}

function normalizeToDnsName(c: string, maxLen: number) {
return c
.toLocaleLowerCase() // lower case
.replace(/[^0-9a-z-]/g, '') // remove non-allowed characters
.substr(0, maxLen) // trim to maxLength
}

function calcHash(path: string, maxLen: number) {
const hash = crypto.createHash('sha256');
hash.update(path);
Expand Down
17 changes: 8 additions & 9 deletions packages/cdk8s/test/names.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,17 @@ import { Names } from "../lib/names";

const toDnsName = Names.toDnsLabel;

test('allowed characters', () => {
const expected = /is not a valid object name/;
expect(() => toDnsName(' ')).toThrow(expected);
expect(() => toDnsName('')).toThrow(expected);
expect(() => toDnsName('Hello')).toThrow(expected);
expect(() => toDnsName('hey*')).toThrow(expected);
expect(() => toDnsName('not allowed')).toThrow(expected);
test('normalize to dns_name', () => {
expect(toDnsName(' ')).toEqual('36a9e7f1');
expect(toDnsName('')).toEqual('e3b0c442');
expect(toDnsName('Hello')).toEqual('hello-185f8db3');
expect(toDnsName('hey*')).toEqual('hey-96c05e6c');
expect(toDnsName('not allowed')).toEqual('notallowed-a26075ed');
});

test('maximum length for a single term', () => {
expect(() => toDnsName('1234567890a', 10)).toThrow(/Maximum allowed length is 10/);
expect(() => toDnsName('a'.repeat(64))).toThrow(/Maximum allowed length is 63/);
expect(toDnsName('1234567890abcdef', 15)).toEqual('123456-8e9916c5');
expect(toDnsName('x' + 'a'.repeat(64))).toEqual('xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa-f69f4ba1');
});

test('single term is not decorated with a hash', () => {
Expand Down

0 comments on commit 1309960

Please sign in to comment.