Skip to content

Commit

Permalink
fix(import): failure when multiple versions of the same CRD exist in …
Browse files Browse the repository at this point in the history
…different obejcts (#1042)

When a CRD has multiple objects that represent the same *kind* but for different versions, `cdk8s import` will fail with a vague "already exists" error.

For example:

```yaml
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
  name: tenants.capsule.clastix.io
spec:
  group: capsule.clastix.io
  names:
    kind: Tenant
    listKind: TenantList
    plural: tenants
    shortNames:
      - tnt
    singular: tenant
  scope: Cluster
  versions:
    - name: v1beta1
      schema:
        openAPIV3Schema: ...
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
  name: tenants.capsule.clastix.io
spec:
  group: capsule.clastix.io
  names:
    kind: Tenant
    listKind: TenantList
    plural: tenants
    shortNames:
      - tnt
    singular: tenant
  scope: Cluster
  versions:
    - name: v1beta2
      schema:
        openAPIV3Schema: ...

```

Note that if the two versions are defined within the same object, import will succeed. 

For example:

```yaml
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
  name: tenants.capsule.clastix.io
spec:
  group: capsule.clastix.io
  names:
    kind: Tenant
    listKind: TenantList
    plural: tenants
    shortNames:
      - tnt
    singular: tenant
  scope: Cluster
  versions:
    - name: v1beta1
      schema:
        openAPIV3Schema: ...
    - name: v1beta2
      schema:
        openAPIV3Schema: ...
```

This is actually a followup to #387.
  • Loading branch information
iliapolo authored Jun 29, 2023
1 parent 8bd14da commit 18e6eda
Show file tree
Hide file tree
Showing 4 changed files with 13,513 additions and 7 deletions.
33 changes: 26 additions & 7 deletions src/import/crd.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,12 @@ const SUPPORTED_API_VERSIONS = [
'apiextensions.k8s.io/v1',
];

type CustomResourceDefinitionVersion = { name: string; schema?: any };

export class CustomResourceDefinition {

private readonly kind: string;
private readonly versions: { name: string; schema?: any }[];
private readonly versions: CustomResourceDefinitionVersion[] = [];

public readonly group: string;

Expand All @@ -58,18 +60,33 @@ export class CustomResourceDefinition {
throw new Error('manifest does not have a "spec" attribute');
}

this.group = spec.group;
this.kind = spec.names.kind;

if (spec.version) {
this.versions = [{ name: spec.version, schema: spec.validation?.openAPIV3Schema }];
this.addVersions([{ name: spec.version, schema: spec.validation?.openAPIV3Schema }]);
} else {
this.versions = (spec.versions ?? []).map(v => ({ name: v.name, schema: v.schema?.openAPIV3Schema ?? spec.validation?.openAPIV3Schema }));
this.addVersions((spec.versions ?? []).map(v => ({ name: v.name, schema: v.schema?.openAPIV3Schema ?? spec.validation?.openAPIV3Schema })));
}

if (this.versions.length === 0) {
throw new Error('unable to determine CRD versions');
}

this.group = spec.group;
this.kind = spec.names.kind;
}

public merge(crd: CustomResourceDefinition) {
this.addVersions(crd.versions);
}

private addVersions(versions: CustomResourceDefinitionVersion[]) {
for (const v of versions) {
const existingVersions = this.versions.map(ver => ver.name);
if (existingVersions.includes(v.name)) {
throw new Error(`Found multiple occurrences of version ${v.name} for ${this.key}`);
}
this.versions.push({ name: v.name, schema: v.schema });
}
}

public get key() {
Expand Down Expand Up @@ -124,9 +141,11 @@ export class ImportCustomResourceDefinition extends ImportBase {
const key = crd.key;

if (key in crds) {
throw new Error(`${key} already exists`);
// might contain different versions - lets try to merge them in
crds[key].merge(crd);
} else {
crds[key] = crd;
}
crds[key] = crd;
}

//sort to ensure consistent ordering for snapshot compare
Expand Down
Loading

0 comments on commit 18e6eda

Please sign in to comment.