Skip to content

Commit

Permalink
fix(eks): KubernetesPatch handling Kubernetes CRDs. fixes #6723
Browse files Browse the repository at this point in the history
Kube CRDs do not support the default "strategic" patch type.

Enable support for KubernetesPatch constructs against Kubernetes CRDs by allowing construct users to specify a kubectl patch 'type'.
  • Loading branch information
mattchrist committed Mar 16, 2020
1 parent e850209 commit f51d868
Show file tree
Hide file tree
Showing 5 changed files with 103 additions and 26 deletions.
3 changes: 2 additions & 1 deletion packages/@aws-cdk/aws-eks/lib/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@ export * from './cluster';
export * from './eks.generated';
export * from './fargate-profile';
export * from './helm-chart';
export * from './k8s-patch';
export * from './k8s-resource';
export * from './fargate-cluster';
export * from './fargate-cluster';
24 changes: 20 additions & 4 deletions packages/@aws-cdk/aws-eks/lib/k8s-patch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ import { Construct, Stack } from "@aws-cdk/core";
import { Cluster } from "./cluster";
import { KubectlProvider } from "./kubectl-provider";

export interface CoreDnsComputeTypeProps {
export interface CoreDnsComputeTypeProps extends KubernetesPatchProps {}
export interface KubernetesPatchProps {
/**
* The cluster to apply the patch to.
*/
Expand All @@ -30,14 +31,28 @@ export interface CoreDnsComputeTypeProps {
* @default "default"
*/
readonly resourceNamespace?: string;

/**
* The patch type to pass to `kubectl patch`.
* The default type used by `kubectl patch` is "strategic".
*
* @default "strategic"
*/
readonly patchType?: PatchType;
}

export enum PatchType {
JSON = "json",
MERGE = "merge",
STRATEGIC = "strategic"
}

/**
* A CloudFormation resource which applies/restores a JSON patch into a
* Kubernetes resource.
*/
export class KubernetesPatch extends Construct {
constructor(scope: Construct, id: string, props: CoreDnsComputeTypeProps) {
constructor(scope: Construct, id: string, props: KubernetesPatchProps) {
super(scope, id);

const stack = Stack.of(this);
Expand All @@ -52,8 +67,9 @@ export class KubernetesPatch extends Construct {
ApplyPatchJson: stack.toJsonString(props.applyPatch),
RestorePatchJson: stack.toJsonString(props.restorePatch),
ClusterName: props.cluster.clusterName,
RoleArn: props.cluster._getKubectlCreationRoleArn(provider.role)
RoleArn: props.cluster._getKubectlCreationRoleArn(provider.role),
PatchType: props.patchType ?? PatchType.STRATEGIC
}
});
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ def patch_handler(event, context):
resource_namespace = props['ResourceNamespace']
apply_patch_json = props['ApplyPatchJson']
restore_patch_json = props['RestorePatchJson']
patch_type = props['PatchType']

patch_json = None
if request_type == 'Create' or request_type == 'Update':
Expand All @@ -42,7 +43,7 @@ def patch_handler(event, context):
else:
raise Exception("invalid request type %s" % request_type)

kubectl([ 'patch', resource_name, '-n', resource_namespace, '-p', patch_json ])
kubectl([ 'patch', resource_name, '-n', resource_namespace, '-p', patch_json, '--type', patch_type ])


def kubectl(args):
Expand Down
38 changes: 19 additions & 19 deletions packages/@aws-cdk/aws-eks/test/integ.eks-cluster.expected.json
Original file line number Diff line number Diff line change
Expand Up @@ -1756,7 +1756,7 @@
},
"/",
{
"Ref": "AssetParameters6a008e167065eeab066c7f96e7f3c21c2636476b93c075681fba2953ae54a859S3BucketBA51B749"
"Ref": "AssetParametersb2a83bc01824acea756ffd355b4f53ae58aacffc1525dc8c75796ebb74cd8f87S3BucketB4483E96"
},
"/",
{
Expand All @@ -1766,7 +1766,7 @@
"Fn::Split": [
"||",
{
"Ref": "AssetParameters6a008e167065eeab066c7f96e7f3c21c2636476b93c075681fba2953ae54a859S3VersionKey723A87EA"
"Ref": "AssetParametersb2a83bc01824acea756ffd355b4f53ae58aacffc1525dc8c75796ebb74cd8f87S3VersionKey0402E731"
}
]
}
Expand All @@ -1779,7 +1779,7 @@
"Fn::Split": [
"||",
{
"Ref": "AssetParameters6a008e167065eeab066c7f96e7f3c21c2636476b93c075681fba2953ae54a859S3VersionKey723A87EA"
"Ref": "AssetParametersb2a83bc01824acea756ffd355b4f53ae58aacffc1525dc8c75796ebb74cd8f87S3VersionKey0402E731"
}
]
}
Expand All @@ -1789,11 +1789,11 @@
]
},
"Parameters": {
"referencetoawscdkeksclustertestAssetParameters809b8ac7e88704d37fac32bbd5cfa56be7ea4d3e9ddb682d216c4b6868cd8fa2S3Bucket5C1311C2Ref": {
"Ref": "AssetParameters809b8ac7e88704d37fac32bbd5cfa56be7ea4d3e9ddb682d216c4b6868cd8fa2S3Bucket8A1A4BE8"
"referencetoawscdkeksclustertestAssetParametersa6d508eaaa0d3cddbb47a84123fc878809c8431c5466f360912f70b5b9770afbS3Bucket6A8A7186Ref": {
"Ref": "AssetParametersa6d508eaaa0d3cddbb47a84123fc878809c8431c5466f360912f70b5b9770afbS3Bucket0C3A00C2"
},
"referencetoawscdkeksclustertestAssetParameters809b8ac7e88704d37fac32bbd5cfa56be7ea4d3e9ddb682d216c4b6868cd8fa2S3VersionKey33922910Ref": {
"Ref": "AssetParameters809b8ac7e88704d37fac32bbd5cfa56be7ea4d3e9ddb682d216c4b6868cd8fa2S3VersionKeyB580A234"
"referencetoawscdkeksclustertestAssetParametersa6d508eaaa0d3cddbb47a84123fc878809c8431c5466f360912f70b5b9770afbS3VersionKeyA18C5C39Ref": {
"Ref": "AssetParametersa6d508eaaa0d3cddbb47a84123fc878809c8431c5466f360912f70b5b9770afbS3VersionKeyBED95764"
},
"referencetoawscdkeksclustertestAssetParameters6c3e21f76e4ba0bc4b901f71bfa9c1eaf7929edcfd9a1591690d12b024100044S3Bucket24E1CF9DRef": {
"Ref": "AssetParameters6c3e21f76e4ba0bc4b901f71bfa9c1eaf7929edcfd9a1591690d12b024100044S3Bucket75CDEB48"
Expand Down Expand Up @@ -1901,29 +1901,29 @@
"Type": "String",
"Description": "Artifact hash for asset \"6c3e21f76e4ba0bc4b901f71bfa9c1eaf7929edcfd9a1591690d12b024100044\""
},
"AssetParameters809b8ac7e88704d37fac32bbd5cfa56be7ea4d3e9ddb682d216c4b6868cd8fa2S3Bucket8A1A4BE8": {
"AssetParametersa6d508eaaa0d3cddbb47a84123fc878809c8431c5466f360912f70b5b9770afbS3Bucket0C3A00C2": {
"Type": "String",
"Description": "S3 bucket for asset \"809b8ac7e88704d37fac32bbd5cfa56be7ea4d3e9ddb682d216c4b6868cd8fa2\""
"Description": "S3 bucket for asset \"a6d508eaaa0d3cddbb47a84123fc878809c8431c5466f360912f70b5b9770afb\""
},
"AssetParameters809b8ac7e88704d37fac32bbd5cfa56be7ea4d3e9ddb682d216c4b6868cd8fa2S3VersionKeyB580A234": {
"AssetParametersa6d508eaaa0d3cddbb47a84123fc878809c8431c5466f360912f70b5b9770afbS3VersionKeyBED95764": {
"Type": "String",
"Description": "S3 key for asset version \"809b8ac7e88704d37fac32bbd5cfa56be7ea4d3e9ddb682d216c4b6868cd8fa2\""
"Description": "S3 key for asset version \"a6d508eaaa0d3cddbb47a84123fc878809c8431c5466f360912f70b5b9770afb\""
},
"AssetParameters809b8ac7e88704d37fac32bbd5cfa56be7ea4d3e9ddb682d216c4b6868cd8fa2ArtifactHash5CE7C76A": {
"AssetParametersa6d508eaaa0d3cddbb47a84123fc878809c8431c5466f360912f70b5b9770afbArtifactHashBF08C2D7": {
"Type": "String",
"Description": "Artifact hash for asset \"809b8ac7e88704d37fac32bbd5cfa56be7ea4d3e9ddb682d216c4b6868cd8fa2\""
"Description": "Artifact hash for asset \"a6d508eaaa0d3cddbb47a84123fc878809c8431c5466f360912f70b5b9770afb\""
},
"AssetParameters6a008e167065eeab066c7f96e7f3c21c2636476b93c075681fba2953ae54a859S3BucketBA51B749": {
"AssetParametersb2a83bc01824acea756ffd355b4f53ae58aacffc1525dc8c75796ebb74cd8f87S3BucketB4483E96": {
"Type": "String",
"Description": "S3 bucket for asset \"6a008e167065eeab066c7f96e7f3c21c2636476b93c075681fba2953ae54a859\""
"Description": "S3 bucket for asset \"b2a83bc01824acea756ffd355b4f53ae58aacffc1525dc8c75796ebb74cd8f87\""
},
"AssetParameters6a008e167065eeab066c7f96e7f3c21c2636476b93c075681fba2953ae54a859S3VersionKey723A87EA": {
"AssetParametersb2a83bc01824acea756ffd355b4f53ae58aacffc1525dc8c75796ebb74cd8f87S3VersionKey0402E731": {
"Type": "String",
"Description": "S3 key for asset version \"6a008e167065eeab066c7f96e7f3c21c2636476b93c075681fba2953ae54a859\""
"Description": "S3 key for asset version \"b2a83bc01824acea756ffd355b4f53ae58aacffc1525dc8c75796ebb74cd8f87\""
},
"AssetParameters6a008e167065eeab066c7f96e7f3c21c2636476b93c075681fba2953ae54a859ArtifactHash22D2ECF0": {
"AssetParametersb2a83bc01824acea756ffd355b4f53ae58aacffc1525dc8c75796ebb74cd8f87ArtifactHash1FD4BC6F": {
"Type": "String",
"Description": "Artifact hash for asset \"6a008e167065eeab066c7f96e7f3c21c2636476b93c075681fba2953ae54a859\""
"Description": "Artifact hash for asset \"b2a83bc01824acea756ffd355b4f53ae58aacffc1525dc8c75796ebb74cd8f87\""
},
"AssetParameters6348c4414dfcbc19ed407c51ecc75d12faf4ee3219e972437d4ceed53e5b79a0S3BucketEF51ACE0": {
"Type": "String",
Expand Down
61 changes: 60 additions & 1 deletion packages/@aws-cdk/aws-eks/test/test.k8s-patch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { expect, haveResource } from '@aws-cdk/assert';
import { Stack } from '@aws-cdk/core';
import { Test } from 'nodeunit';
import * as eks from '../lib';
import { KubernetesPatch } from '../lib/k8s-patch';
import { KubernetesPatch, PatchType } from '../lib/k8s-patch';

export = {
'applies a patch to k8s'(test: Test) {
Expand Down Expand Up @@ -41,5 +41,64 @@ export = {
}
}));
test.done();
},
'defaults to "strategic" patch type if no patchType is specified'(test: Test) {
// GIVEN
const stack = new Stack();
const cluster = new eks.Cluster(stack, 'MyCluster');

// WHEN
new KubernetesPatch(stack, 'MyPatch', {
cluster,
applyPatch: { patch: { to: 'apply' } },
restorePatch: { restore: { patch: 123 }},
resourceName: 'myResourceName',
});
expect(stack).to(haveResource('Custom::AWSCDK-EKS-KubernetesPatch', {
PatchType: "strategic"
}));
test.done();
},
'uses specified to patch type if specified'(test: Test) {
// GIVEN
const stack = new Stack();
const cluster = new eks.Cluster(stack, 'MyCluster');

// WHEN
new KubernetesPatch(stack, 'jsonPatch', {
cluster,
applyPatch: { patch: { to: 'apply' } },
restorePatch: { restore: { patch: 123 }},
resourceName: 'jsonPatchResource',
patchType: PatchType.JSON
});
new KubernetesPatch(stack, 'mergePatch', {
cluster,
applyPatch: { patch: { to: 'apply' } },
restorePatch: { restore: { patch: 123 }},
resourceName: 'mergePatchResource',
patchType: PatchType.MERGE
});
new KubernetesPatch(stack, 'strategicPatch', {
cluster,
applyPatch: { patch: { to: 'apply' } },
restorePatch: { restore: { patch: 123 }},
resourceName: 'strategicPatchResource',
patchType: PatchType.STRATEGIC
});

expect(stack).to(haveResource('Custom::AWSCDK-EKS-KubernetesPatch', {
ResourceName: "jsonPatchResource",
PatchType: "json"
}));
expect(stack).to(haveResource('Custom::AWSCDK-EKS-KubernetesPatch', {
ResourceName: "mergePatchResource",
PatchType: "merge"
}));
expect(stack).to(haveResource('Custom::AWSCDK-EKS-KubernetesPatch', {
ResourceName: "strategicPatchResource",
PatchType: "strategic"
}));
test.done();
}
};

0 comments on commit f51d868

Please sign in to comment.