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

feat(eks): KubernetesPatch #6753

Merged
merged 13 commits into from
Mar 19, 2020
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions 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';
44 changes: 38 additions & 6 deletions packages/@aws-cdk/aws-eks/lib/k8s-patch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,25 @@ import { Construct, Stack } from "@aws-cdk/core";
import { Cluster } from "./cluster";
import { KubectlProvider } from "./kubectl-provider";

export interface CoreDnsComputeTypeProps {
/**
* Properties for KubernetesPatch
*/
export interface KubernetesPatchProps {
/**
* The cluster to apply the patch to.
* [disable-awslint:ref-via-interface]
*/
readonly cluster: Cluster;

/**
* The JSON object to pass to `kubectl patch` when the resource is created/updated.
*/
readonly applyPatch: any;
readonly applyPatch: { [key: string]: any };

/**
* The JSON object to pass to `kubectl patch` when the resource is removed.
*/
readonly restorePatch: any;
readonly restorePatch: { [key: string]: any };

/**
* The full name of the resource to patch (e.g. `deployment/coredns`).
Expand All @@ -30,14 +34,41 @@ 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 PatchType.STRATEGIC
*/
readonly patchType?: PatchType;
}

/**
* Values for `kubectl patch` --type argument
*/
export enum PatchType {
/**
* JSON Patch, RFC 6902
*/
JSON = "json",
/**
* JSON Merge patch
*/
MERGE = "merge",
/**
* Strategic merge patch
*/
STRATEGIC = "strategic"
}

/**
* A CloudFormation resource which applies/restores a JSON patch into a
* Kubernetes resource.
* @see https://kubernetes.io/docs/tasks/run-application/update-api-object-kubectl-patch/
*/
export class KubernetesPatch extends Construct {
eladb marked this conversation as resolved.
Show resolved Hide resolved
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 +83,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();
}
};