diff --git a/extended/src/main/java/io/kubernetes/client/extended/kubectl/KubectlRollout.java b/extended/src/main/java/io/kubernetes/client/extended/kubectl/KubectlRollout.java index 96236dfe0a..31a4cf41c0 100644 --- a/extended/src/main/java/io/kubernetes/client/extended/kubectl/KubectlRollout.java +++ b/extended/src/main/java/io/kubernetes/client/extended/kubectl/KubectlRollout.java @@ -25,6 +25,7 @@ import io.kubernetes.client.openapi.models.V1ObjectMeta; import io.kubernetes.client.openapi.models.V1PodTemplateSpec; import io.kubernetes.client.openapi.models.V1ReplicaSet; +import io.kubernetes.client.openapi.models.V1StatefulSet; import io.kubernetes.client.util.labels.LabelSelector; import java.util.ArrayList; import java.util.HashMap; @@ -77,6 +78,10 @@ public List execute() throws KubectlException { } else if (apiTypeClass.equals(V1DaemonSet.class)) { V1DaemonSet daemonSet = api.readNamespacedDaemonSet(name, namespace, null, null, null); daemonSetViewHistory(daemonSet, api); + } else if (apiTypeClass.equals(V1StatefulSet.class)) { + V1StatefulSet statefulSet = + api.readNamespacedStatefulSet(name, namespace, null, null, null); + statefulSetViewHistory(statefulSet, api); } else { throw new KubectlException("Unsupported class for rollout history: " + apiTypeClass); } @@ -171,6 +176,25 @@ private V1DaemonSet applyDaemonSetHistory(V1ControllerRevision history) PatchHelper.dryRunStrategyMergePatch(getGenericApi(), patch, namespace, name); } + private void statefulSetViewHistory(V1StatefulSet statefulSet, AppsV1Api api) + throws ApiException, KubectlException { + LabelSelector selector = LabelSelector.parse(statefulSet.getSpec().getSelector()); + List historyList = controlledHistory(api, statefulSet, selector); + parseHistory( + historyList, + history -> { + V1StatefulSet stsOfHistory = applyStatefulSetHistory(history); + return stsOfHistory.getSpec().getTemplate(); + }); + } + + private V1StatefulSet applyStatefulSetHistory(V1ControllerRevision history) + throws KubectlException, ApiException { + String patch = apiClient.getJSON().serialize(history.getData()); + return (V1StatefulSet) + PatchHelper.dryRunStrategyMergePatch(getGenericApi(), patch, namespace, name); + } + private void parseHistory(List historyList, PodTemplateParser parser) throws ApiException, KubectlException { Map historyInfo = new HashMap<>(); diff --git a/extended/src/test/java/io/kubernetes/client/extended/kubectl/KubectlRolloutTest.java b/extended/src/test/java/io/kubernetes/client/extended/kubectl/KubectlRolloutTest.java index 85aae082a2..b6239a3e25 100644 --- a/extended/src/test/java/io/kubernetes/client/extended/kubectl/KubectlRolloutTest.java +++ b/extended/src/test/java/io/kubernetes/client/extended/kubectl/KubectlRolloutTest.java @@ -30,6 +30,8 @@ import io.kubernetes.client.openapi.models.V1Deployment; import io.kubernetes.client.openapi.models.V1DeploymentList; import io.kubernetes.client.openapi.models.V1PodTemplateSpec; +import io.kubernetes.client.openapi.models.V1StatefulSet; +import io.kubernetes.client.openapi.models.V1StatefulSetList; import io.kubernetes.client.util.ClientBuilder; import io.kubernetes.client.util.ModelMapper; import java.io.IOException; @@ -65,6 +67,18 @@ public class KubectlRolloutTest { .getResource("daemonset-controllerrevision-list.json") .getPath(); + private static final String STATEFUL_SET = + KubectlRolloutTest.class.getClassLoader().getResource("statefulset.json").getPath(); + + private static final String PATCHED_STATEFUL_SET = + KubectlRolloutTest.class.getClassLoader().getResource("patched-statefulset.json").getPath(); + + private static final String STATEFUL_SET_CONTROLLER_REVISION_LIST = + KubectlRolloutTest.class + .getClassLoader() + .getResource("statefulset-controllerrevision-list.json") + .getPath(); + @Before public void setup() throws IOException { ModelMapper.addModelMap( @@ -77,6 +91,14 @@ public void setup() throws IOException { V1DeploymentList.class); ModelMapper.addModelMap( "apps", "v1", "DaemonSet", "daemonsets", true, V1DaemonSet.class, V1DaemonSetList.class); + ModelMapper.addModelMap( + "apps", + "v1", + "StatefulSet", + "statefulsets", + true, + V1StatefulSet.class, + V1StatefulSetList.class); apiClient = new ClientBuilder().setBasePath("http://localhost:" + wireMockRule.port()).build(); } @@ -223,6 +245,87 @@ public void testKubectlRolloutHistoryDaemonSetWithRevisionShouldWork() Assert.assertNotNull(template); } + @Test + public void testKubectlRolloutHistoryStatefulSetShouldWork() + throws KubectlException, IOException { + wireMockRule.stubFor( + get(urlPathEqualTo("/apis/apps/v1/namespaces/default/statefulsets/foo")) + .willReturn( + aResponse() + .withStatus(200) + .withBody(new String(Files.readAllBytes(Paths.get(STATEFUL_SET)))))); + wireMockRule.stubFor( + get(urlPathEqualTo("/apis/apps/v1/namespaces/default/controllerrevisions")) + .willReturn( + aResponse() + .withStatus(200) + .withBody( + new String( + Files.readAllBytes( + Paths.get(STATEFUL_SET_CONTROLLER_REVISION_LIST)))))); + List histories = + Kubectl.rollout(V1StatefulSet.class) + .history() + .apiClient(apiClient) + .name("foo") + .namespace("default") + .skipDiscovery() + .execute(); + wireMockRule.verify( + 1, getRequestedFor((urlPathEqualTo("/apis/apps/v1/namespaces/default/statefulsets/foo")))); + wireMockRule.verify( + 1, + getRequestedFor((urlPathEqualTo("/apis/apps/v1/namespaces/default/controllerrevisions"))) + .withQueryParam("labelSelector", new EqualToPattern("app = bar"))); + Assert.assertEquals(3, histories.size()); + } + + @Test + public void testKubectlRolloutHistoryStatefulSetWithRevisionShouldWork() + throws KubectlException, IOException { + wireMockRule.stubFor( + get(urlPathEqualTo("/apis/apps/v1/namespaces/default/statefulsets/foo")) + .willReturn( + aResponse() + .withStatus(200) + .withBody(new String(Files.readAllBytes(Paths.get(STATEFUL_SET)))))); + wireMockRule.stubFor( + get(urlPathEqualTo("/apis/apps/v1/namespaces/default/controllerrevisions")) + .willReturn( + aResponse() + .withStatus(200) + .withBody( + new String( + Files.readAllBytes( + Paths.get(STATEFUL_SET_CONTROLLER_REVISION_LIST)))))); + wireMockRule.stubFor( + patch(urlPathEqualTo("/apis/apps/v1/namespaces/default/statefulsets/foo")) + .willReturn( + aResponse() + .withStatus(200) + .withBody(new String(Files.readAllBytes(Paths.get(PATCHED_STATEFUL_SET)))))); + V1PodTemplateSpec template = + Kubectl.rollout(V1StatefulSet.class) + .history() + .apiClient(apiClient) + .name("foo") + .namespace("default") + .revision(2) + .skipDiscovery() + .execute(); + wireMockRule.verify( + 1, getRequestedFor((urlPathEqualTo("/apis/apps/v1/namespaces/default/statefulsets/foo")))); + wireMockRule.verify( + 1, + getRequestedFor((urlPathEqualTo("/apis/apps/v1/namespaces/default/controllerrevisions"))) + .withQueryParam("labelSelector", new EqualToPattern("app = bar"))); + wireMockRule.verify( + 1, + patchRequestedFor((urlPathEqualTo("/apis/apps/v1/namespaces/default/statefulsets/foo"))) + .withQueryParam("dryRun", new EqualToPattern("All"))); + Assert.assertNotNull(template); + } + @Test public void testKubectlRolloutHistoryWithInvalidRevisionShouldThrow() throws IOException { wireMockRule.stubFor( diff --git a/extended/src/test/resources/patched-statefulset.json b/extended/src/test/resources/patched-statefulset.json new file mode 100644 index 0000000000..a1addfe0a3 --- /dev/null +++ b/extended/src/test/resources/patched-statefulset.json @@ -0,0 +1,151 @@ +{ + "apiVersion": "apps/v1", + "kind": "StatefulSet", + "metadata": { + "annotations": { + "kubernetes.io/change-cause": "kubectl.exe create --filename\u003dstatefulset.yaml --record\u003dtrue" + }, + "creationTimestamp": "2021-08-13T09:44:24.000000Z", + "generation": 4, + "managedFields": [{ + "apiVersion": "apps/v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:metadata": { + "f:annotations": { + ".": {}, + "f:kubernetes.io/change-cause": {} + } + }, + "f:spec": { + "f:podManagementPolicy": {}, + "f:replicas": {}, + "f:revisionHistoryLimit": {}, + "f:selector": {}, + "f:serviceName": {}, + "f:template": { + "f:metadata": { + "f:labels": { + ".": {}, + "f:app": {} + } + }, + "f:spec": { + "f:containers": { + "k:{\"name\":\"busybox-host\"}": { + ".": {}, + "f:args": {}, + "f:command": {}, + "f:image": {}, + "f:imagePullPolicy": {}, + "f:name": {}, + "f:resources": {}, + "f:terminationMessagePath": {}, + "f:terminationMessagePolicy": {} + } + }, + "f:dnsPolicy": {}, + "f:restartPolicy": {}, + "f:schedulerName": {}, + "f:securityContext": {}, + "f:terminationGracePeriodSeconds": {} + } + }, + "f:updateStrategy": { + "f:rollingUpdate": { + ".": {}, + "f:partition": {} + }, + "f:type": {} + } + } + }, + "manager": "kubectl-create", + "operation": "Update", + "time": "2021-08-13T09:44:24.000000Z" + }, { + "apiVersion": "apps/v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:spec": { + "f:template": { + "f:metadata": { + "f:annotations": {} + } + } + } + }, + "manager": "kubectl-rollout", + "operation": "Update", + "time": "2021-08-13T09:47:22.000000Z" + }, { + "apiVersion": "apps/v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:spec": { + "f:template": { + "f:metadata": { + "f:annotations": { + "f:kubectl.kubernetes.io/restartedAt": {} + } + } + } + } + }, + "manager": "Kubernetes Java Client", + "operation": "Update", + "time": "2021-08-17T11:13:42.000000Z" + }], + "name": "foo", + "namespace": "default", + "resourceVersion": "103707", + "uid": "9a968c95-4b78-4b72-baf9-fa18bab00155" + }, + "spec": { + "podManagementPolicy": "OrderedReady", + "replicas": 2, + "revisionHistoryLimit": 10, + "selector": { + "matchLabels": { + "app": "bar" + } + }, + "serviceName": "busybox-service\"", + "template": { + "metadata": { + "annotations": { + "kubectl.kubernetes.io/restartedAt": "2021-08-13T17:47:22+08:00" + }, + "labels": { + "app": "bar" + } + }, + "spec": { + "containers": [{ + "args": ["1000"], + "command": ["sleep"], + "image": "busybox:1.31.1", + "imagePullPolicy": "IfNotPresent", + "name": "busybox-host", + "resources": {}, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File" + }], + "dnsPolicy": "ClusterFirst", + "restartPolicy": "Always", + "schedulerName": "default-scheduler", + "securityContext": {}, + "terminationGracePeriodSeconds": 30 + } + }, + "updateStrategy": { + "rollingUpdate": { + "partition": 0 + }, + "type": "RollingUpdate" + } + }, + "status": { + "replicas": 0 + } +} \ No newline at end of file diff --git a/extended/src/test/resources/statefulset-controllerrevision-list.json b/extended/src/test/resources/statefulset-controllerrevision-list.json new file mode 100644 index 0000000000..89867e585c --- /dev/null +++ b/extended/src/test/resources/statefulset-controllerrevision-list.json @@ -0,0 +1,552 @@ +{ + "apiVersion": "apps/v1", + "items": [{ + "data": { + "spec": { + "template": { + "$patch": "replace", + "metadata": { + "annotations": { + "kubectl.kubernetes.io/restartedAt": "2021-08-13T17:47:28+08:00" + }, + "labels": { + "app": "bar" + } + }, + "spec": { + "containers": [{ + "args": ["1000"], + "command": ["sleep"], + "image": "busybox:1.31.1", + "imagePullPolicy": "IfNotPresent", + "name": "busybox-host", + "resources": {}, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File" + }], + "dnsPolicy": "ClusterFirst", + "restartPolicy": "Always", + "schedulerName": "default-scheduler", + "securityContext": {}, + "terminationGracePeriodSeconds": 30.0 + } + } + } + }, + "metadata": { + "annotations": { + "kubernetes.io/change-cause": "kubectl.exe create --filename\u003dstatefulset.yaml --record\u003dtrue" + }, + "creationTimestamp": "2021-08-13T09:47:28.000000Z", + "labels": { + "app": "bar", + "controller.kubernetes.io/hash": "5c85d48f56" + }, + "managedFields": [{ + "apiVersion": "apps/v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:data": {}, + "f:metadata": { + "f:annotations": { + ".": {}, + "f:kubernetes.io/change-cause": {} + }, + "f:labels": { + ".": {}, + "f:app": {}, + "f:controller.kubernetes.io/hash": {} + }, + "f:ownerReferences": { + ".": {}, + "k:{\"uid\":\"9a968c95-4b78-4b72-baf9-fa18bab00155\"}": { + ".": {}, + "f:apiVersion": {}, + "f:blockOwnerDeletion": {}, + "f:controller": {}, + "f:kind": {}, + "f:name": {}, + "f:uid": {} + } + } + }, + "f:revision": {} + }, + "manager": "kube-controller-manager", + "operation": "Update", + "time": "2021-08-13T09:47:28.000000Z" + }], + "name": "foo-5c85d48f56", + "namespace": "default", + "ownerReferences": [{ + "apiVersion": "apps/v1", + "blockOwnerDeletion": true, + "controller": true, + "kind": "StatefulSet", + "name": "foo", + "uid": "9a968c95-4b78-4b72-baf9-fa18bab00155" + }], + "resourceVersion": "103708", + "uid": "efee2112-3410-4a12-94f7-b8c99596f0c2" + }, + "revision": 3 + }, { + "data": { + "spec": { + "template": { + "$patch": "replace", + "metadata": { + "labels": { + "app": "bar" + } + }, + "spec": { + "containers": [{ + "args": ["1000"], + "command": ["sleep"], + "image": "busybox:1.31.1", + "imagePullPolicy": "IfNotPresent", + "name": "busybox-host", + "resources": {}, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File" + }], + "dnsPolicy": "ClusterFirst", + "restartPolicy": "Always", + "schedulerName": "default-scheduler", + "securityContext": {}, + "terminationGracePeriodSeconds": 30.0 + } + } + } + }, + "metadata": { + "annotations": { + "deprecated.daemonset.template.generation": "1", + "kubectl.kubernetes.io/last-applied-configuration": "{\"apiVersion\":\"apps/v1\",\"kind\":\"DaemonSet\",\"metadata\":{\"annotations\":{\"kubernetes.io/change-cause\":\"kubectl.exe apply --filename\u003d./daemonSet.Yaml --record\u003dtrue\"},\"name\":\"foo\",\"namespace\":\"default\"},\"spec\":{\"selector\":{\"matchLabels\":{\"app\":\"bar\"}},\"template\":{\"metadata\":{\"labels\":{\"app\":\"bar\"}},\"spec\":{\"containers\":[{\"args\":[\"1000\"],\"command\":[\"sleep\"],\"image\":\"busybox:1.31.1\",\"name\":\"busybox-host\"}]}}}}\n", + "kubernetes.io/change-cause": "kubectl.exe apply --filename\u003d./daemonSet.Yaml --record\u003dtrue" + }, + "creationTimestamp": "2021-08-13T07:13:06.000000Z", + "labels": { + "app": "bar", + "controller-revision-hash": "69b77bc98d" + }, + "managedFields": [{ + "apiVersion": "apps/v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:data": {}, + "f:metadata": { + "f:annotations": { + ".": {}, + "f:deprecated.daemonset.template.generation": {}, + "f:kubectl.kubernetes.io/last-applied-configuration": {}, + "f:kubernetes.io/change-cause": {} + }, + "f:labels": { + ".": {}, + "f:app": {}, + "f:controller-revision-hash": {} + }, + "f:ownerReferences": { + ".": {}, + "k:{\"uid\":\"d3774f2a-e492-4968-a888-23b71e4c13a9\"}": { + ".": {}, + "f:apiVersion": {}, + "f:blockOwnerDeletion": {}, + "f:controller": {}, + "f:kind": {}, + "f:name": {}, + "f:uid": {} + } + } + }, + "f:revision": {} + }, + "manager": "kube-controller-manager", + "operation": "Update", + "time": "2021-08-13T07:13:06.000000Z" + }], + "name": "foo-69b77bc98d", + "namespace": "default", + "ownerReferences": [{ + "apiVersion": "apps/v1", + "blockOwnerDeletion": true, + "controller": true, + "kind": "DaemonSet", + "name": "foo", + "uid": "d3774f2a-e492-4968-a888-23b71e4c13a9" + }], + "resourceVersion": "96595", + "uid": "e684a7d1-34c1-4f59-8ebe-f026f5fb9910" + }, + "revision": 1 + }, { + "data": { + "spec": { + "template": { + "$patch": "replace", + "metadata": { + "labels": { + "app": "bar" + } + }, + "spec": { + "containers": [{ + "args": ["1000"], + "command": ["sleep"], + "image": "busybox:1.31.1", + "imagePullPolicy": "IfNotPresent", + "name": "busybox-host", + "resources": {}, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File" + }], + "dnsPolicy": "ClusterFirst", + "restartPolicy": "Always", + "schedulerName": "default-scheduler", + "securityContext": {}, + "terminationGracePeriodSeconds": 30.0 + } + } + } + }, + "metadata": { + "annotations": { + "kubernetes.io/change-cause": "kubectl.exe create --filename\u003dstatefulset.yaml --record\u003dtrue" + }, + "creationTimestamp": "2021-08-13T09:44:24.000000Z", + "labels": { + "app": "bar", + "controller.kubernetes.io/hash": "6cdc5c7f8c" + }, + "managedFields": [{ + "apiVersion": "apps/v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:data": {}, + "f:metadata": { + "f:annotations": { + ".": {}, + "f:kubernetes.io/change-cause": {} + }, + "f:labels": { + ".": {}, + "f:app": {}, + "f:controller.kubernetes.io/hash": {} + }, + "f:ownerReferences": { + ".": {}, + "k:{\"uid\":\"9a968c95-4b78-4b72-baf9-fa18bab00155\"}": { + ".": {}, + "f:apiVersion": {}, + "f:blockOwnerDeletion": {}, + "f:controller": {}, + "f:kind": {}, + "f:name": {}, + "f:uid": {} + } + } + }, + "f:revision": {} + }, + "manager": "kube-controller-manager", + "operation": "Update", + "time": "2021-08-13T09:44:24.000000Z" + }], + "name": "foo-6cdc5c7f8c", + "namespace": "default", + "ownerReferences": [{ + "apiVersion": "apps/v1", + "blockOwnerDeletion": true, + "controller": true, + "kind": "StatefulSet", + "name": "foo", + "uid": "9a968c95-4b78-4b72-baf9-fa18bab00155" + }], + "resourceVersion": "103557", + "uid": "2554e01c-0e44-49c2-ac14-a721a6df9e99" + }, + "revision": 1 + }, { + "data": { + "spec": { + "template": { + "$patch": "replace", + "metadata": { + "annotations": { + "kubectl.kubernetes.io/restartedAt": "2021-08-13T17:47:22+08:00" + }, + "labels": { + "app": "bar" + } + }, + "spec": { + "containers": [{ + "args": ["1000"], + "command": ["sleep"], + "image": "busybox:1.31.1", + "imagePullPolicy": "IfNotPresent", + "name": "busybox-host", + "resources": {}, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File" + }], + "dnsPolicy": "ClusterFirst", + "restartPolicy": "Always", + "schedulerName": "default-scheduler", + "securityContext": {}, + "terminationGracePeriodSeconds": 30.0 + } + } + } + }, + "metadata": { + "annotations": { + "kubernetes.io/change-cause": "kubectl.exe create --filename\u003dstatefulset.yaml --record\u003dtrue" + }, + "creationTimestamp": "2021-08-13T09:47:22.000000Z", + "labels": { + "app": "bar", + "controller.kubernetes.io/hash": "77cc88b7c4" + }, + "managedFields": [{ + "apiVersion": "apps/v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:data": {}, + "f:metadata": { + "f:annotations": { + ".": {}, + "f:kubernetes.io/change-cause": {} + }, + "f:labels": { + ".": {}, + "f:app": {}, + "f:controller.kubernetes.io/hash": {} + }, + "f:ownerReferences": { + ".": {}, + "k:{\"uid\":\"9a968c95-4b78-4b72-baf9-fa18bab00155\"}": { + ".": {}, + "f:apiVersion": {}, + "f:blockOwnerDeletion": {}, + "f:controller": {}, + "f:kind": {}, + "f:name": {}, + "f:uid": {} + } + } + }, + "f:revision": {} + }, + "manager": "kube-controller-manager", + "operation": "Update", + "time": "2021-08-13T09:47:22.000000Z" + }], + "name": "foo-77cc88b7c4", + "namespace": "default", + "ownerReferences": [{ + "apiVersion": "apps/v1", + "blockOwnerDeletion": true, + "controller": true, + "kind": "StatefulSet", + "name": "foo", + "uid": "9a968c95-4b78-4b72-baf9-fa18bab00155" + }], + "resourceVersion": "103700", + "uid": "282d7799-5fb2-4c70-a949-300dd6f81bd2" + }, + "revision": 2 + }, { + "data": { + "spec": { + "template": { + "$patch": "replace", + "metadata": { + "annotations": { + "kubectl.kubernetes.io/restartedAt": "2021-08-13T16:53:21+08:00" + }, + "labels": { + "app": "bar" + } + }, + "spec": { + "containers": [{ + "args": ["1000"], + "command": ["sleep"], + "image": "busybox:1.31.1", + "imagePullPolicy": "IfNotPresent", + "name": "busybox-host", + "resources": {}, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File" + }], + "dnsPolicy": "ClusterFirst", + "restartPolicy": "Always", + "schedulerName": "default-scheduler", + "securityContext": {}, + "terminationGracePeriodSeconds": 30.0 + } + } + } + }, + "metadata": { + "annotations": { + "deprecated.daemonset.template.generation": "3", + "kubectl.kubernetes.io/last-applied-configuration": "{\"apiVersion\":\"apps/v1\",\"kind\":\"DaemonSet\",\"metadata\":{\"annotations\":{},\"name\":\"foo\",\"namespace\":\"default\"},\"spec\":{\"selector\":{\"matchLabels\":{\"app\":\"bar\"}},\"template\":{\"metadata\":{\"labels\":{\"app\":\"bar\"}},\"spec\":{\"containers\":[{\"args\":[\"1000\"],\"command\":[\"sleep\"],\"image\":\"busybox:1.31.1\",\"name\":\"busybox-host\"}]}}}}\n" + }, + "creationTimestamp": "2021-08-13T08:53:21.000000Z", + "labels": { + "app": "bar", + "controller-revision-hash": "797f8dc6b5" + }, + "managedFields": [{ + "apiVersion": "apps/v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:data": {}, + "f:metadata": { + "f:annotations": { + ".": {}, + "f:deprecated.daemonset.template.generation": {}, + "f:kubectl.kubernetes.io/last-applied-configuration": {} + }, + "f:labels": { + ".": {}, + "f:app": {}, + "f:controller-revision-hash": {} + }, + "f:ownerReferences": { + ".": {}, + "k:{\"uid\":\"d3774f2a-e492-4968-a888-23b71e4c13a9\"}": { + ".": {}, + "f:apiVersion": {}, + "f:blockOwnerDeletion": {}, + "f:controller": {}, + "f:kind": {}, + "f:name": {}, + "f:uid": {} + } + } + }, + "f:revision": {} + }, + "manager": "kube-controller-manager", + "operation": "Update", + "time": "2021-08-13T08:53:21.000000Z" + }], + "name": "foo-797f8dc6b5", + "namespace": "default", + "ownerReferences": [{ + "apiVersion": "apps/v1", + "blockOwnerDeletion": true, + "controller": true, + "kind": "DaemonSet", + "name": "foo", + "uid": "d3774f2a-e492-4968-a888-23b71e4c13a9" + }], + "resourceVersion": "101207", + "uid": "37be558a-ba1e-4182-bc5a-ca0ed324cdf7" + }, + "revision": 3 + }, { + "data": { + "spec": { + "template": { + "$patch": "replace", + "metadata": { + "annotations": { + "kubectl.kubernetes.io/restartedAt": "2021-08-13T15:14:35+08:00" + }, + "labels": { + "app": "bar" + } + }, + "spec": { + "containers": [{ + "args": ["1000"], + "command": ["sleep"], + "image": "busybox:1.31.1", + "imagePullPolicy": "IfNotPresent", + "name": "busybox-host", + "resources": {}, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File" + }], + "dnsPolicy": "ClusterFirst", + "restartPolicy": "Always", + "schedulerName": "default-scheduler", + "securityContext": {}, + "terminationGracePeriodSeconds": 30.0 + } + } + } + }, + "metadata": { + "annotations": { + "deprecated.daemonset.template.generation": "2", + "kubectl.kubernetes.io/last-applied-configuration": "{\"apiVersion\":\"apps/v1\",\"kind\":\"DaemonSet\",\"metadata\":{\"annotations\":{\"kubernetes.io/change-cause\":\"kubectl.exe apply --filename\u003d./daemonSet.Yaml --record\u003dtrue\"},\"name\":\"foo\",\"namespace\":\"default\"},\"spec\":{\"selector\":{\"matchLabels\":{\"app\":\"bar\"}},\"template\":{\"metadata\":{\"labels\":{\"app\":\"bar\"}},\"spec\":{\"containers\":[{\"args\":[\"1000\"],\"command\":[\"sleep\"],\"image\":\"busybox:1.31.1\",\"name\":\"busybox-host\"}]}}}}\n", + "kubernetes.io/change-cause": "kubectl.exe apply --filename\u003d./daemonSet.Yaml --record\u003dtrue" + }, + "creationTimestamp": "2021-08-13T07:14:35.000000Z", + "labels": { + "app": "bar", + "controller-revision-hash": "7f9dcff8b8" + }, + "managedFields": [{ + "apiVersion": "apps/v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:data": {}, + "f:metadata": { + "f:annotations": { + ".": {}, + "f:deprecated.daemonset.template.generation": {}, + "f:kubectl.kubernetes.io/last-applied-configuration": {}, + "f:kubernetes.io/change-cause": {} + }, + "f:labels": { + ".": {}, + "f:app": {}, + "f:controller-revision-hash": {} + }, + "f:ownerReferences": { + ".": {}, + "k:{\"uid\":\"d3774f2a-e492-4968-a888-23b71e4c13a9\"}": { + ".": {}, + "f:apiVersion": {}, + "f:blockOwnerDeletion": {}, + "f:controller": {}, + "f:kind": {}, + "f:name": {}, + "f:uid": {} + } + } + }, + "f:revision": {} + }, + "manager": "kube-controller-manager", + "operation": "Update", + "time": "2021-08-13T07:14:35.000000Z" + }], + "name": "foo-7f9dcff8b8", + "namespace": "default", + "ownerReferences": [{ + "apiVersion": "apps/v1", + "blockOwnerDeletion": true, + "controller": true, + "kind": "DaemonSet", + "name": "foo", + "uid": "d3774f2a-e492-4968-a888-23b71e4c13a9" + }], + "resourceVersion": "96669", + "uid": "b8f45530-23a9-4fea-94b5-778f65117c43" + }, + "revision": 2 + }], + "kind": "ControllerRevisionList", + "metadata": { + "resourceVersion": "105278" + } +} \ No newline at end of file diff --git a/extended/src/test/resources/statefulset.json b/extended/src/test/resources/statefulset.json new file mode 100644 index 0000000000..144df2db91 --- /dev/null +++ b/extended/src/test/resources/statefulset.json @@ -0,0 +1,137 @@ +{ + "apiVersion": "apps/v1", + "kind": "StatefulSet", + "metadata": { + "annotations": { + "kubernetes.io/change-cause": "kubectl.exe create --filename\u003dstatefulset.yaml --record\u003dtrue" + }, + "creationTimestamp": "2021-08-13T09:44:24.000000Z", + "generation": 3, + "managedFields": [{ + "apiVersion": "apps/v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:metadata": { + "f:annotations": { + ".": {}, + "f:kubernetes.io/change-cause": {} + } + }, + "f:spec": { + "f:podManagementPolicy": {}, + "f:replicas": {}, + "f:revisionHistoryLimit": {}, + "f:selector": {}, + "f:serviceName": {}, + "f:template": { + "f:metadata": { + "f:labels": { + ".": {}, + "f:app": {} + } + }, + "f:spec": { + "f:containers": { + "k:{\"name\":\"busybox-host\"}": { + ".": {}, + "f:args": {}, + "f:command": {}, + "f:image": {}, + "f:imagePullPolicy": {}, + "f:name": {}, + "f:resources": {}, + "f:terminationMessagePath": {}, + "f:terminationMessagePolicy": {} + } + }, + "f:dnsPolicy": {}, + "f:restartPolicy": {}, + "f:schedulerName": {}, + "f:securityContext": {}, + "f:terminationGracePeriodSeconds": {} + } + }, + "f:updateStrategy": { + "f:rollingUpdate": { + ".": {}, + "f:partition": {} + }, + "f:type": {} + } + } + }, + "manager": "kubectl-create", + "operation": "Update", + "time": "2021-08-13T09:44:24.000000Z" + }, { + "apiVersion": "apps/v1", + "fieldsType": "FieldsV1", + "fieldsV1": { + "f:spec": { + "f:template": { + "f:metadata": { + "f:annotations": { + ".": {}, + "f:kubectl.kubernetes.io/restartedAt": {} + } + } + } + } + }, + "manager": "kubectl-rollout", + "operation": "Update", + "time": "2021-08-13T09:47:22.000000Z" + }], + "name": "foo", + "namespace": "default", + "resourceVersion": "103707", + "uid": "9a968c95-4b78-4b72-baf9-fa18bab00155" + }, + "spec": { + "podManagementPolicy": "OrderedReady", + "replicas": 2, + "revisionHistoryLimit": 10, + "selector": { + "matchLabels": { + "app": "bar" + } + }, + "serviceName": "busybox-service\"", + "template": { + "metadata": { + "annotations": { + "kubectl.kubernetes.io/restartedAt": "2021-08-13T17:47:28+08:00" + }, + "labels": { + "app": "bar" + } + }, + "spec": { + "containers": [{ + "args": ["1000"], + "command": ["sleep"], + "image": "busybox:1.31.1", + "imagePullPolicy": "IfNotPresent", + "name": "busybox-host", + "resources": {}, + "terminationMessagePath": "/dev/termination-log", + "terminationMessagePolicy": "File" + }], + "dnsPolicy": "ClusterFirst", + "restartPolicy": "Always", + "schedulerName": "default-scheduler", + "securityContext": {}, + "terminationGracePeriodSeconds": 30 + } + }, + "updateStrategy": { + "rollingUpdate": { + "partition": 0 + }, + "type": "RollingUpdate" + } + }, + "status": { + "replicas": 0 + } +} \ No newline at end of file