Repository: cloud-custodian/cloud-custodian

Issue:
eks update action
https://docs.aws.amazon.com/eks/latest/userguide/cluster-endpoint.html


Discussion:

Resolving patch:
diff --git a/c7n/resources/eks.py b/c7n/resources/eks.py
--- a/c7n/resources/eks.py
+++ b/c7n/resources/eks.py
@@ -19,6 +19,8 @@
 from c7n.query import QueryResourceManager
 from c7n.utils import local_session, type_schema
 
+from .aws import shape_validate
+
 
 @resources.register('eks')
 class EKS(QueryResourceManager):
@@ -52,6 +54,37 @@ class EKSVpcFilter(VpcFilter):
     RelatedIdsExpression = 'resourcesVpcConfig.vpcId'
 
 
+@EKS.action_registry.register('update-config')
+class UpdateConfig(Action):
+
+    schema = type_schema(
+        'update-config', resourcesVpcConfig={'type': 'object'},
+        required=('resourcesVpcConfig',))
+    permissions = ('eks:UpdateClusterConfig',)
+    shape = 'UpdateClusterConfigRequest'
+
+    def validate(self):
+        cfg = dict(self.data)
+        cfg['name'] = 'validate'
+        cfg.pop('type')
+        return shape_validate(
+            cfg, self.shape, self.manager.resource_type.service)
+
+    def process(self, resources):
+        client = local_session(self.manager.session_factory).client('eks')
+        state_filtered = 0
+        for r in resources:
+            if r['status'] != 'ACTIVE':
+                state_filtered += 1
+                continue
+            client.update_cluster_config(
+                name=r['name'],
+                resourcesVpcConfig=self.data['resourcesVpcConfig'])
+        if state_filtered:
+            self.log.warning(
+                "Filtered %d of %d clusters due to state", state_filtered, len(resources))
+
+
 @EKS.action_registry.register('delete')
 class Delete(Action):
 


Test patch:
diff --git a/tests/data/placebo/test_eks_update_config/eks.DescribeCluster_1.json b/tests/data/placebo/test_eks_update_config/eks.DescribeCluster_1.json
new file mode 100644
--- /dev/null
+++ b/tests/data/placebo/test_eks_update_config/eks.DescribeCluster_1.json
@@ -0,0 +1,57 @@
+{
+    "status_code": 200,
+    "data": {
+        "ResponseMetadata": {
+            "RequestId": "d8b9812d-4c93-11e9-9a82-3902379ea347",
+            "HTTPStatusCode": 200,
+            "HTTPHeaders": {
+                "date": "Fri, 22 Mar 2019 11:15:49 GMT",
+                "content-type": "application/json",
+                "content-length": "2113",
+                "connection": "keep-alive",
+                "x-amzn-requestid": "d8b9812d-4c93-11e9-9a82-3902379ea347",
+                "x-amz-apigw-id": "W8OLzFyKiYcFgYw=",
+                "x-amzn-trace-id": "Root=1-5c94c3e5-4c4b264e24782f7c8a87b9fc;Sampled=1"
+            },
+            "RetryAttempts": 0
+        },
+        "cluster": {
+            "name": "devk8s",
+            "arn": "arn:aws:eks:us-east-2:644160558196:cluster/devk8s",
+            "createdAt": {
+                "__class__": "datetime",
+                "year": 2019,
+                "month": 3,
+                "day": 21,
+                "hour": 13,
+                "minute": 28,
+                "second": 49,
+                "microsecond": 811000
+            },
+            "version": "1.11",
+            "endpoint": "https://1BB97D4E9CC38ECDAB839C96D222D3F6.sk1.us-east-2.eks.amazonaws.com",
+            "roleArn": "arn:aws:iam::644160558196:role/eksctl-devk8s-cluster-ServiceRole-1JNA85I5147VF",
+            "resourcesVpcConfig": {
+                "subnetIds": [
+                    "subnet-0dcc27692f82648fe",
+                    "subnet-07ac22c0a96699e69",
+                    "subnet-029219d5cf80bc951",
+                    "subnet-0c58f79d941cb9b0a",
+                    "subnet-0836bdf0c7d7afee1",
+                    "subnet-05374ecec3d67653c"
+                ],
+                "securityGroupIds": [
+                    "sg-0e7a18bc9826f06a1"
+                ],
+                "vpcId": "vpc-08948fb33475791d9",
+                "endpointPublicAccess": true,
+                "endpointPrivateAccess": true
+            },
+            "status": "ACTIVE",
+            "certificateAuthority": {
+                "data": "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUN5RENDQWJDZ0F3SUJBZ0lCQURBTkJna3Foa2lHOXcwQkFRc0ZBREFWTVJNd0VRWURWUVFERXdwcmRXSmwKY201bGRHVnpNQjRYRFRFNU1ETXlNVEUzTXpZd09Gb1hEVEk1TURNeE9ERTNNell3T0Zvd0ZURVRNQkVHQTFVRQpBeE1LYTNWaVpYSnVaWFJsY3pDQ0FTSXdEUVlKS29aSWh2Y05BUUVCQlFBRGdnRVBBRENDQVFvQ2dnRUJBS3BFCmVvWTIvVTVuYXY2UVZCdFVjZHlTTVRsMTRhUkRORUxJZ2s2QStBQ1hST1BuTFJiY0hYd3B1RVh6anM3Z0J5ZisKblhPZ0t0MERmb0tBME96VEx2enlycnpST0l3bUZTTC91R1FybWFaL2RwWVlTNGx6UzFkVTJOVUFLeXFoTVE0ago5MyttbnFhK1czVjk1SzVNbytmN1JwbFYvNEV0QkFDMXMrUmZ3ekNKQWtiUUNJMmRSNDB2Vmo3SjlTNm95MWh0CkVBRWMycms1b3N1YmdXeUY1RGhRbEFMdXkranBoMnRnejhIYWo3a1IyV3hvcjBCcDJjc3E1aTR0anNlR0lEUVMKK1VzK2ZscHV0ZTI0MjgwWmhyaDJ4QUltLy80ODBGVDQ3KzJLNWNTL0FPSDY0N2QvUWQyZ0V4RXVBQ21tRWZGLwpqa3ZnbUV3OHRBZXJrOGpwSXBzQ0F3RUFBYU1qTUNFd0RnWURWUjBQQVFIL0JBUURBZ0trTUE4R0ExVWRFd0VCCi93UUZNQU1CQWY4d0RRWUpLb1pJaHZjTkFRRUxCUUFEZ2dFQkFIN2FFU1hzdS95Z3hmd1hRdUdBQzFDdGw4dU0KTHBOd0sraC9weDdsbk1jNitQQkhhTFlZQ0pvMVlKZ0xqdE5EN29CNUhiVnZJTGpLdjV3WkptUEQraDFYeHV0bAp3SGFhNnU5RlZRVzg3V0lXMTQ1RDNJNnhOczBybXd5NDhMcDZpbG5FQkJjWEdRS2tVVGhKQ29VT1RzRDBkaDM0ClVveUtvM0Z0YWsxSG5pZldTVUhHbWZ3aVpPdklWQVluUEZ0YUNSZ2VKZzFCVEZtTWFQTmt0SlFPRjBvek0zZ1IKZ283V2RIR2c5YTQ5Tlg2TE5GRlpQSWQ2TXhWaEJhcTNFK2FySThJVGZSOTA0RlYvYVlYYmxNYWJ6cHJXKzdIRgo0Q3hkeG54WEIwZUlNQmZIYVJXNlUvZ0ZPMTEvTndVYjZyWHBXTG5CVHJpdW9kVytsTnRNRE9iRzZXYz0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo="
+            },
+            "platformVersion": "eks.2"
+        }
+    }
+}
\ No newline at end of file
diff --git a/tests/data/placebo/test_eks_update_config/eks.DescribeCluster_2.json b/tests/data/placebo/test_eks_update_config/eks.DescribeCluster_2.json
new file mode 100644
--- /dev/null
+++ b/tests/data/placebo/test_eks_update_config/eks.DescribeCluster_2.json
@@ -0,0 +1,57 @@
+{
+    "status_code": 200,
+    "data": {
+        "ResponseMetadata": {
+            "RequestId": "df7e725d-4c93-11e9-8884-b58447eeb81e",
+            "HTTPStatusCode": 200,
+            "HTTPHeaders": {
+                "date": "Fri, 22 Mar 2019 11:16:00 GMT",
+                "content-type": "application/json",
+                "content-length": "2115",
+                "connection": "keep-alive",
+                "x-amzn-requestid": "df7e725d-4c93-11e9-8884-b58447eeb81e",
+                "x-amz-apigw-id": "W8ONlFigCYcFmAA=",
+                "x-amzn-trace-id": "Root=1-5c94c3f0-9b8e0462f41e6ca93e9c2106;Sampled=0"
+            },
+            "RetryAttempts": 0
+        },
+        "cluster": {
+            "name": "devk8s",
+            "arn": "arn:aws:eks:us-east-2:644160558196:cluster/devk8s",
+            "createdAt": {
+                "__class__": "datetime",
+                "year": 2019,
+                "month": 3,
+                "day": 21,
+                "hour": 13,
+                "minute": 28,
+                "second": 49,
+                "microsecond": 811000
+            },
+            "version": "1.11",
+            "endpoint": "https://1BB97D4E9CC38ECDAB839C96D222D3F6.sk1.us-east-2.eks.amazonaws.com",
+            "roleArn": "arn:aws:iam::644160558196:role/eksctl-devk8s-cluster-ServiceRole-1JNA85I5147VF",
+            "resourcesVpcConfig": {
+                "subnetIds": [
+                    "subnet-0dcc27692f82648fe",
+                    "subnet-07ac22c0a96699e69",
+                    "subnet-029219d5cf80bc951",
+                    "subnet-0c58f79d941cb9b0a",
+                    "subnet-0836bdf0c7d7afee1",
+                    "subnet-05374ecec3d67653c"
+                ],
+                "securityGroupIds": [
+                    "sg-0e7a18bc9826f06a1"
+                ],
+                "vpcId": "vpc-08948fb33475791d9",
+                "endpointPublicAccess": true,
+                "endpointPrivateAccess": true
+            },
+            "status": "UPDATING",
+            "certificateAuthority": {
+                "data": "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUN5RENDQWJDZ0F3SUJBZ0lCQURBTkJna3Foa2lHOXcwQkFRc0ZBREFWTVJNd0VRWURWUVFERXdwcmRXSmwKY201bGRHVnpNQjRYRFRFNU1ETXlNVEUzTXpZd09Gb1hEVEk1TURNeE9ERTNNell3T0Zvd0ZURVRNQkVHQTFVRQpBeE1LYTNWaVpYSnVaWFJsY3pDQ0FTSXdEUVlKS29aSWh2Y05BUUVCQlFBRGdnRVBBRENDQVFvQ2dnRUJBS3BFCmVvWTIvVTVuYXY2UVZCdFVjZHlTTVRsMTRhUkRORUxJZ2s2QStBQ1hST1BuTFJiY0hYd3B1RVh6anM3Z0J5ZisKblhPZ0t0MERmb0tBME96VEx2enlycnpST0l3bUZTTC91R1FybWFaL2RwWVlTNGx6UzFkVTJOVUFLeXFoTVE0ago5MyttbnFhK1czVjk1SzVNbytmN1JwbFYvNEV0QkFDMXMrUmZ3ekNKQWtiUUNJMmRSNDB2Vmo3SjlTNm95MWh0CkVBRWMycms1b3N1YmdXeUY1RGhRbEFMdXkranBoMnRnejhIYWo3a1IyV3hvcjBCcDJjc3E1aTR0anNlR0lEUVMKK1VzK2ZscHV0ZTI0MjgwWmhyaDJ4QUltLy80ODBGVDQ3KzJLNWNTL0FPSDY0N2QvUWQyZ0V4RXVBQ21tRWZGLwpqa3ZnbUV3OHRBZXJrOGpwSXBzQ0F3RUFBYU1qTUNFd0RnWURWUjBQQVFIL0JBUURBZ0trTUE4R0ExVWRFd0VCCi93UUZNQU1CQWY4d0RRWUpLb1pJaHZjTkFRRUxCUUFEZ2dFQkFIN2FFU1hzdS95Z3hmd1hRdUdBQzFDdGw4dU0KTHBOd0sraC9weDdsbk1jNitQQkhhTFlZQ0pvMVlKZ0xqdE5EN29CNUhiVnZJTGpLdjV3WkptUEQraDFYeHV0bAp3SGFhNnU5RlZRVzg3V0lXMTQ1RDNJNnhOczBybXd5NDhMcDZpbG5FQkJjWEdRS2tVVGhKQ29VT1RzRDBkaDM0ClVveUtvM0Z0YWsxSG5pZldTVUhHbWZ3aVpPdklWQVluUEZ0YUNSZ2VKZzFCVEZtTWFQTmt0SlFPRjBvek0zZ1IKZ283V2RIR2c5YTQ5Tlg2TE5GRlpQSWQ2TXhWaEJhcTNFK2FySThJVGZSOTA0RlYvYVlYYmxNYWJ6cHJXKzdIRgo0Q3hkeG54WEIwZUlNQmZIYVJXNlUvZ0ZPMTEvTndVYjZyWHBXTG5CVHJpdW9kVytsTnRNRE9iRzZXYz0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo="
+            },
+            "platformVersion": "eks.2"
+        }
+    }
+}
\ No newline at end of file
diff --git a/tests/data/placebo/test_eks_update_config/eks.ListClusters_1.json b/tests/data/placebo/test_eks_update_config/eks.ListClusters_1.json
new file mode 100644
--- /dev/null
+++ b/tests/data/placebo/test_eks_update_config/eks.ListClusters_1.json
@@ -0,0 +1,22 @@
+{
+    "status_code": 200,
+    "data": {
+        "ResponseMetadata": {
+            "RequestId": "d89ea67a-4c93-11e9-ba79-550a3be32b59",
+            "HTTPStatusCode": 200,
+            "HTTPHeaders": {
+                "date": "Fri, 22 Mar 2019 11:15:49 GMT",
+                "content-type": "application/json",
+                "content-length": "40",
+                "connection": "keep-alive",
+                "x-amzn-requestid": "d89ea67a-4c93-11e9-ba79-550a3be32b59",
+                "x-amz-apigw-id": "W8OLxF4EiYcFqfQ=",
+                "x-amzn-trace-id": "Root=1-5c94c3e4-d8cf66eebeafb54aa0e9edbe;Sampled=1"
+            },
+            "RetryAttempts": 0
+        },
+        "clusters": [
+            "devk8s"
+        ]
+    }
+}
\ No newline at end of file
diff --git a/tests/data/placebo/test_eks_update_config/eks.UpdateClusterConfig_1.json b/tests/data/placebo/test_eks_update_config/eks.UpdateClusterConfig_1.json
new file mode 100644
--- /dev/null
+++ b/tests/data/placebo/test_eks_update_config/eks.UpdateClusterConfig_1.json
@@ -0,0 +1,45 @@
+{
+    "status_code": 200,
+    "data": {
+        "ResponseMetadata": {
+            "RequestId": "d8d9da1e-4c93-11e9-b780-851217557d54",
+            "HTTPStatusCode": 200,
+            "HTTPHeaders": {
+                "date": "Fri, 22 Mar 2019 11:15:50 GMT",
+                "content-type": "application/json",
+                "content-length": "254",
+                "connection": "keep-alive",
+                "x-amzn-requestid": "d8d9da1e-4c93-11e9-b780-851217557d54",
+                "x-amz-apigw-id": "W8OL1EqgiYcFnvQ=",
+                "x-amzn-trace-id": "Root=1-5c94c3e5-40a49fa43e329e4831df943a;Sampled=1"
+            },
+            "RetryAttempts": 0
+        },
+        "update": {
+            "id": "adebf3ee-dc26-48d2-963c-8b755ad715dc",
+            "status": "InProgress",
+            "type": "EndpointAccessUpdate",
+            "params": [
+                {
+                    "type": "EndpointPublicAccess",
+                    "value": "false"
+                },
+                {
+                    "type": "EndpointPrivateAccess",
+                    "value": "true"
+                }
+            ],
+            "createdAt": {
+                "__class__": "datetime",
+                "year": 2019,
+                "month": 3,
+                "day": 22,
+                "hour": 7,
+                "minute": 15,
+                "second": 50,
+                "microsecond": 192000
+            },
+            "errors": []
+        }
+    }
+}
\ No newline at end of file
diff --git a/tests/test_eks.py b/tests/test_eks.py
--- a/tests/test_eks.py
+++ b/tests/test_eks.py
@@ -13,7 +13,7 @@
 # limitations under the License.
 from __future__ import absolute_import, division, print_function, unicode_literals
 
-
+import time
 from .common import BaseTest
 
 
@@ -39,6 +39,29 @@ def test_query_with_subnet_sg_filter(self):
         self.assertEqual(len(resources), 1)
         self.assertEqual(resources[0]['name'], 'dev')
 
+    def test_update_config(self):
+        factory = self.replay_flight_data('test_eks_update_config')
+        p = self.load_policy({
+            'name': 'eksupdate',
+            'resource': 'eks',
+            'filters': [
+                {'name': 'devk8s'},
+                {'resourcesVpcConfig.endpointPublicAccess': True}],
+            'actions': [{
+                'type': 'update-config',
+                'resourcesVpcConfig': {
+                    'endpointPublicAccess': False,
+                    'endpointPrivateAccess': True
+                }}]}, session_factory=factory, config={'region': 'us-east-2'})
+        resources = p.run()
+        self.assertEqual(len(resources), 1)
+        if self.recording:
+            time.sleep(10)
+        client = factory().client('eks')
+        info = client.describe_cluster(name='devk8s')['cluster']
+        self.assertEqual(resources[0]['status'], 'ACTIVE')
+        self.assertEqual(info['status'], 'UPDATING')
+
     def test_delete_eks(self):
         factory = self.replay_flight_data("test_eks_delete")
         p = self.load_policy(