diff --git a/CHANGELOG.md b/CHANGELOG.md index 709f24f703..b2cc47f33d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,22 +4,22 @@ Breaking changes: -- Enable Server-side Apply by default (https://github.com/pulumi/pulumi-kubernetes/pull/2398) - Remove deprecated enableDryRun provider flag (https://github.com/pulumi/pulumi-kubernetes/pull/2400) - Remove deprecated helm/v2 SDK (https://github.com/pulumi/pulumi-kubernetes/pull/2396) - Remove deprecated enableReplaceCRD provider flag (https://github.com/pulumi/pulumi-kubernetes/pull/2402) - Drop support for Kubernetes clusters older than v1.13 (https://github.com/pulumi/pulumi-kubernetes/pull/2414) - Make all resource output properties required (https://github.com/pulumi/pulumi-kubernetes/pull/2422) -- Drop support for legacy pulumi.com/initialApiVersion annotation (https://github.com/pulumi/pulumi-kubernetes/pull/2443) Other changes: -- Automatically fall back to client-side preview if server-side preview fails (https://github.com/pulumi/pulumi-kubernetes/pull/2419) - Enable Server-side Apply by default (https://github.com/pulumi/pulumi-kubernetes/pull/2398) -- Remove deprecated enableDryRun provider flag (https://github.com/pulumi/pulumi-kubernetes/pull/2400) -- Remove deprecated helm/v2 SDK (https://github.com/pulumi/pulumi-kubernetes/pull/2396) -- Remove deprecated enableReplaceCRD provider flag (https://github.com/pulumi/pulumi-kubernetes/pull/2402) -- Drop support for Kubernetes clusters older than v1.13 (https://github.com/pulumi/pulumi-kubernetes/pull/2414) +- Automatically fall back to client-side preview if server-side preview fails (https://github.com/pulumi/pulumi-kubernetes/pull/2419) +- Drop support for legacy pulumi.com/initialApiVersion annotation (https://github.com/pulumi/pulumi-kubernetes/pull/2443) +- Overhaul logic for resource diffing (https://github.com/pulumi/pulumi-kubernetes/pull/2445) + - Drop usage of the "kubectl.kubernetes.io/last-applied-configuration" annotation. + - Compute preview diffs using resource inputs rather than making a dry-run API call. + - Automatically update .metadata.managedFields to work with resources that were managed with client-side apply, and later upgraded to use server-side apply. + - Fix a bug with the diff calculation so that resource drift is detected accurately after a refresh. ## 3.30.2 (July 11, 2023) diff --git a/provider/go.mod b/provider/go.mod index 7343fec990..5a753e9399 100644 --- a/provider/go.mod +++ b/provider/go.mod @@ -5,6 +5,7 @@ go 1.19 require ( github.com/ahmetb/go-linq v3.0.0+incompatible github.com/evanphx/json-patch v5.6.0+incompatible + github.com/fluxcd/pkg/ssa v0.28.1 github.com/golang/protobuf v1.5.3 github.com/google/gnostic v0.5.7-v3refs github.com/imdario/mergo v0.3.14 @@ -18,11 +19,11 @@ require ( google.golang.org/grpc v1.55.0 gopkg.in/yaml.v3 v3.0.1 helm.sh/helm/v3 v3.12.0 - k8s.io/api v0.27.1 - k8s.io/apimachinery v0.27.1 + k8s.io/api v0.27.2 + k8s.io/apimachinery v0.27.2 k8s.io/cli-runtime v0.27.1 - k8s.io/client-go v0.27.1 - k8s.io/kube-openapi v0.0.0-20230308215209-15aac26d736a + k8s.io/client-go v0.27.2 + k8s.io/kube-openapi v0.0.0-20230501164219-8b0f38b5fd1f k8s.io/kubectl v0.27.1 sigs.k8s.io/kustomize/api v0.13.2 sigs.k8s.io/kustomize/kyaml v0.14.1 @@ -92,7 +93,7 @@ require ( github.com/gedex/inflector v0.0.0-20170307190818-16278e9db813 // indirect github.com/go-errors/errors v1.4.2 // indirect github.com/go-gorp/gorp/v3 v3.0.5 // indirect - github.com/go-logr/logr v1.2.3 // indirect + github.com/go-logr/logr v1.2.4 // indirect github.com/go-openapi/jsonpointer v0.19.6 // indirect github.com/go-openapi/jsonreference v0.20.1 // indirect github.com/go-openapi/swag v0.22.3 // indirect @@ -168,10 +169,10 @@ require ( github.com/pierrec/lz4 v2.6.1+incompatible // indirect github.com/pkg/term v1.1.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/prometheus/client_golang v1.14.0 // indirect - github.com/prometheus/client_model v0.3.0 // indirect - github.com/prometheus/common v0.37.0 // indirect - github.com/prometheus/procfs v0.8.0 // indirect + github.com/prometheus/client_golang v1.15.1 // indirect + github.com/prometheus/client_model v0.4.0 // indirect + github.com/prometheus/common v0.42.0 // indirect + github.com/prometheus/procfs v0.9.0 // indirect github.com/rivo/uniseg v0.4.4 // indirect github.com/rogpeppe/go-internal v1.10.0 // indirect github.com/rubenv/sql-migrate v1.3.1 // indirect @@ -201,13 +202,13 @@ require ( go.uber.org/atomic v1.9.0 // indirect gocloud.dev v0.27.0 // indirect gocloud.dev/secrets/hashivault v0.27.0 // indirect - golang.org/x/net v0.8.0 // indirect + golang.org/x/net v0.10.0 // indirect golang.org/x/oauth2 v0.6.0 // indirect - golang.org/x/sync v0.1.0 // indirect - golang.org/x/sys v0.6.0 // indirect - golang.org/x/term v0.6.0 // indirect + golang.org/x/sync v0.2.0 // indirect + golang.org/x/sys v0.8.0 // indirect + golang.org/x/term v0.8.0 // indirect golang.org/x/text v0.9.0 // indirect - golang.org/x/time v0.0.0-20220722155302-e5dcc9cfc0b9 // indirect + golang.org/x/time v0.3.0 // indirect golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect google.golang.org/api v0.110.0 // indirect google.golang.org/appengine v1.6.7 // indirect @@ -217,9 +218,9 @@ require ( gopkg.in/square/go-jose.v2 v2.6.0 // indirect gopkg.in/warnings.v0 v0.1.2 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect - k8s.io/apiextensions-apiserver v0.27.1 // indirect - k8s.io/apiserver v0.27.1 // indirect - k8s.io/component-base v0.27.1 // indirect + k8s.io/apiextensions-apiserver v0.27.2 // indirect + k8s.io/apiserver v0.27.2 // indirect + k8s.io/component-base v0.27.2 // indirect k8s.io/klog/v2 v2.90.1 // indirect k8s.io/utils v0.0.0-20230220204549-a5ecb0141aa5 // indirect oras.land/oras-go v1.2.2 // indirect @@ -257,6 +258,7 @@ require ( github.com/docker/cli v20.10.21+incompatible // indirect github.com/edsrzf/mmap-go v1.1.0 // indirect github.com/emicklei/go-restful/v3 v3.10.1 // indirect + github.com/evanphx/json-patch/v5 v5.6.0 // indirect github.com/go-git/gcfg v1.5.0 // indirect github.com/go-git/go-billy/v5 v5.4.0 // indirect github.com/go-git/go-git/v5 v5.6.0 // indirect @@ -287,6 +289,8 @@ require ( go.opentelemetry.io/otel v1.14.0 // indirect go.opentelemetry.io/otel/trace v1.14.0 // indirect golang.org/x/mod v0.10.0 // indirect - golang.org/x/tools v0.7.0 // indirect + golang.org/x/tools v0.9.1 // indirect lukechampine.com/frand v1.4.2 // indirect + sigs.k8s.io/cli-utils v0.34.0 // indirect + sigs.k8s.io/controller-runtime v0.15.0 // indirect ) diff --git a/provider/go.sum b/provider/go.sum index d75ea397a7..433746ad05 100644 --- a/provider/go.sum +++ b/provider/go.sum @@ -637,6 +637,8 @@ github.com/evanphx/json-patch v4.12.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQL github.com/evanphx/json-patch v5.6.0+incompatible h1:jBYDEEiFBPxA0v50tFdvOzQQTCvpL6mnFh5mB2/l16U= github.com/evanphx/json-patch v5.6.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch/v5 v5.5.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= +github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= +github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d h1:105gxyaGwCFad8crR9dcMQWvV9Hvulu6hwUh4tWPJnM= github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d/go.mod h1:ZZMPRZwes7CROmyNKgQzC3XPs6L/G2EJLHddWejkmf4= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= @@ -650,6 +652,8 @@ github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSw github.com/felixge/httpsnoop v1.0.2/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk= github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/fluxcd/pkg/ssa v0.28.1 h1:h5r5irAgDjgkmIqagOLOa/U7/Rx2fT2NKIb+vDTYOMg= +github.com/fluxcd/pkg/ssa v0.28.1/go.mod h1:o55eBzWz7P/tqnCn5c622RZvjTP/GqvitqZUbsMIRwk= github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= github.com/form3tech-oss/jwt-go v3.2.3+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= @@ -665,6 +669,7 @@ github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMo github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU= github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= +github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= github.com/fullsailor/pkcs7 v0.0.0-20190404230743-d7302db945fa/go.mod h1:KnogPXtdwXqoenmZCw6S+25EAm2MkxbG0deNDu4cbSA= github.com/garyburd/redigo v0.0.0-20150301180006-535138d7bcd7/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY= github.com/gedex/inflector v0.0.0-20170307190818-16278e9db813 h1:Uc+IZ7gYqAf/rSGFplbWBSHaGolEQlNLgMgSE3ccnIQ= @@ -713,11 +718,13 @@ github.com/go-logr/logr v0.4.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTg github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.1/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0= github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= +github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/stdr v1.2.0/go.mod h1:YkVgnZu1ZjjL7xTxrfm/LLZBfkhTqSR1ydtm6jTKKwI= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/go-logr/zapr v1.2.4 h1:QHVo+6stLbfJmYGkQ7uGHUCu5hnAFAj6mDe6Ea0SeOo= github.com/go-openapi/analysis v0.21.2/go.mod h1:HZwRk4RRisyG8vx2Oe6aqeSQcoxRp47Xkp3+K6q+LdY= github.com/go-openapi/errors v0.19.8/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M= github.com/go-openapi/errors v0.19.9/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M= @@ -763,8 +770,8 @@ github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfC github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-stack/stack v1.8.1/go.mod h1:dcoOX6HbPZSZptuspn9bctJ+N/CnF5gGygcUP3XYfe4= -github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= +github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= github.com/go-test/deep v1.0.2/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= github.com/go-test/deep v1.0.3 h1:ZrJSEWsXzPOxaZnFteGEfooLba+ju3FYIbOrS+rQd68= github.com/go-zookeeper/zk v1.0.2/go.mod h1:nOB03cncLtlp4t+UAkGSV+9beXP/akpekBwL+UX1Qcw= @@ -1448,7 +1455,7 @@ github.com/onsi/ginkgo v1.13.0/go.mod h1:+REjRxOmWfHCjfv9TTWB1jD1Frx4XydAD3zm1ls github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc= github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= -github.com/onsi/ginkgo/v2 v2.9.1 h1:zie5Ly042PD3bsCvsSOPvRnFwyo3rKe64TJlD6nu0mk= +github.com/onsi/ginkgo/v2 v2.9.5 h1:+6Hr4uxzP4XIUyAkg61dWBw8lb/gc4/X5luuxN/EC+Q= github.com/onsi/gomega v0.0.0-20151007035656-2152b45fa28a/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= @@ -1459,7 +1466,7 @@ github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoT github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.10.3/go.mod h1:V9xEwhxec5O8UDM77eCW8vLymOMltsqPVYWrpDsH8xc= github.com/onsi/gomega v1.15.0/go.mod h1:cIuvLEne0aoVhAgh/O6ac0Op8WWw9H6eYCriF+tEHG0= -github.com/onsi/gomega v1.27.4 h1:Z2AnStgsdSayCMDiCU42qIz+HLqEPcgiOCXjAU/w+8E= +github.com/onsi/gomega v1.27.7 h1:fVih9JD6ogIiHUN6ePK7HJidyEDpWGVB5mzM7cWNXoU= github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= github.com/opencontainers/go-digest v0.0.0-20170106003457-a6d0ee40d420/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= @@ -1561,8 +1568,8 @@ github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= github.com/prometheus/client_golang v1.12.2/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= -github.com/prometheus/client_golang v1.14.0 h1:nJdhIvne2eSX/XRAFV9PcvFFRbrjbcTUj0VP62TMhnw= -github.com/prometheus/client_golang v1.14.0/go.mod h1:8vpkKitgIVNcqrRBWh1C4TIUQgYNtG/XQE4E/Zae36Y= +github.com/prometheus/client_golang v1.15.1 h1:8tXpTmJbyH5lydzFPoxSIJ0J46jdh3tylbvM1xCv0LI= +github.com/prometheus/client_golang v1.15.1/go.mod h1:e9yaBhRPU2pPNsZwE+JdQl0KEt1N9XgF6zxWmaC0xOk= github.com/prometheus/client_model v0.0.0-20171117100541-99fa1f4be8e5/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= @@ -1570,8 +1577,8 @@ github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1: github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.1.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4= -github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= +github.com/prometheus/client_model v0.4.0 h1:5lQXD3cAg1OXBf4Wq03gTrXHeaV0TQvGfUooCfx1yqY= +github.com/prometheus/client_model v0.4.0/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU= github.com/prometheus/common v0.0.0-20180110214958-89604d197083/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= @@ -1586,8 +1593,9 @@ github.com/prometheus/common v0.29.0/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+ github.com/prometheus/common v0.30.0/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= github.com/prometheus/common v0.34.0/go.mod h1:gB3sOl7P0TvJabZpLY5uQMpUqRCPPCyRLCZYc7JZTNE= -github.com/prometheus/common v0.37.0 h1:ccBbHCgIiT9uSoFY0vX8H3zsNR5eLt17/RQLUvn8pXE= github.com/prometheus/common v0.37.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA= +github.com/prometheus/common v0.42.0 h1:EKsfXEYo4JpWMHH5cg+KOUWeuJSov1Id8zGR8eeI1YM= +github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr1yjz4b7Zbc= github.com/prometheus/common/assets v0.1.0/go.mod h1:D17UVUE12bHbim7HzwUvtqm6gwBEaDQ0F+hIGbFbccI= github.com/prometheus/common/assets v0.2.0/go.mod h1:D17UVUE12bHbim7HzwUvtqm6gwBEaDQ0F+hIGbFbccI= github.com/prometheus/common/sigv4 v0.1.0/go.mod h1:2Jkxxk9yYvCkE5G1sQT7GuEXm57JrvHu9k5YwTjsNtI= @@ -1605,8 +1613,8 @@ github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4O github.com/prometheus/procfs v0.2.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= -github.com/prometheus/procfs v0.8.0 h1:ODq8ZFEaYeCaZOJlZZdJA2AbQR98dSHSM1KW/You5mo= -github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4= +github.com/prometheus/procfs v0.9.0 h1:wzCHvIvM5SxWqYvwgVL7yJY8Lz3PKn49KQtpgMYJfhI= +github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB/chUwxUZY= github.com/prometheus/prometheus v0.35.0/go.mod h1:7HaLx5kEPKJ0GDgbODG0fZgXbQ8K/XjZNJXQmbmgQlY= github.com/prometheus/prometheus v0.37.0/go.mod h1:egARUgz+K93zwqsVIAneFlLZefyGOON44WyAp4Xqbbk= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= @@ -1915,6 +1923,7 @@ go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/ go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= +go.uber.org/multierr v1.8.0 h1:dg6GjLku4EH+249NNmoIciG9N/jURbDG+pFlTkhzIC8= go.uber.org/multierr v1.8.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak= go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= @@ -1922,6 +1931,7 @@ go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw= +go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60= gocloud.dev v0.27.0 h1:j0WTUsnKTxCsWO7y8T+YCiBZUmLl9w/WIowqAY3yo0g= gocloud.dev v0.27.0/go.mod h1:YlYKhYsY5/1JdHGWQDkAuqkezVKowu7qbe9aIeUF6p0= gocloud.dev/secrets/hashivault v0.27.0 h1:AAeGJXr0tiHHJgg5tL8atOGktB4eK9EJAqkZbPKAcOo= @@ -2097,8 +2107,8 @@ golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b/go.mod h1:YDH+HFinaLZZlnHAfS golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws= -golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= -golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M= +golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -2141,8 +2151,8 @@ golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= -golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.2.0 h1:PUR+T4wwASmuSTYdKjYHI5TD22Wy5ogLU5qZCOLxBrI= +golang.org/x/sync v0.2.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -2295,8 +2305,8 @@ golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= -golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= @@ -2306,8 +2316,8 @@ golang.org/x/term v0.0.0-20220722155259-a9ba230a4035/go.mod h1:jbD1KX2456YbFQfuX golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ= -golang.org/x/term v0.6.0 h1:clScbb1cHjoCkyRbWwBEUZ5H/tIFu5TAXIqaZD0Gcjw= -golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= +golang.org/x/term v0.8.0 h1:n5xxQn2i3PC0yLAbjTpNT85q/Kgzcr2gIoX9OrJUols= +golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -2332,8 +2342,9 @@ golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxb golang.org/x/time v0.0.0-20220210224613-90d013bbcef8/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20220224211638-0e9765cccd65/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20220609170525-579cf78fd858/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20220722155302-e5dcc9cfc0b9 h1:ftMN5LMiBFjbzleLqtoBZk7KdJwhuybIU+FckUHgoyQ= golang.org/x/time v0.0.0-20220722155302-e5dcc9cfc0b9/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= +golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -2421,8 +2432,8 @@ golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E golang.org/x/tools v0.1.11/go.mod h1:SgwaegtQh8clINPpECJMqnxLv9I09HLqnW3RMqW0CA4= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA= -golang.org/x/tools v0.7.0 h1:W4OVu8VVOaIO0yzWMNdepAulS7YfoS3Zabrm8DOXXU4= -golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s= +golang.org/x/tools v0.9.1 h1:8WMNJAz3zrtPmnYC7ISf5dEn3MT0gY7jBJfw27yrrLo= +golang.org/x/tools v0.9.1/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc= golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -2434,6 +2445,7 @@ golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNq golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk= golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= +gomodules.xyz/jsonpatch/v2 v2.3.0 h1:8NFhfS6gzxNqjLIYnZxg319wZ5Qjnx4m/CcX+Klzazc= google.golang.org/api v0.0.0-20160322025152-9bf6e6e569ff/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= @@ -2730,10 +2742,10 @@ k8s.io/api v0.20.6/go.mod h1:X9e8Qag6JV/bL5G6bU8sdVRltWKmdHsFUGS3eVndqE8= k8s.io/api v0.22.5/go.mod h1:mEhXyLaSD1qTOf40rRiKXkc+2iCem09rWLlFwhCEiAs= k8s.io/api v0.23.5/go.mod h1:Na4XuKng8PXJ2JsploYYrivXrINeTaycCGcYgF91Xm8= k8s.io/api v0.24.2/go.mod h1:AHqbSkTm6YrQ0ObxjO3Pmp/ubFF/KuM7jU+3khoBsOg= -k8s.io/api v0.27.1 h1:Z6zUGQ1Vd10tJ+gHcNNNgkV5emCyW+v2XTmn+CLjSd0= -k8s.io/api v0.27.1/go.mod h1:z5g/BpAiD+f6AArpqNjkY+cji8ueZDU/WV1jcj5Jk4E= -k8s.io/apiextensions-apiserver v0.27.1 h1:Hp7B3KxKHBZ/FxmVFVpaDiXI6CCSr49P1OJjxKO6o4g= -k8s.io/apiextensions-apiserver v0.27.1/go.mod h1:8jEvRDtKjVtWmdkhOqE84EcNWJt/uwF8PC4627UZghY= +k8s.io/api v0.27.2 h1:+H17AJpUMvl+clT+BPnKf0E3ksMAzoBBg7CntpSuADo= +k8s.io/api v0.27.2/go.mod h1:ENmbocXfBT2ADujUXcBhHV55RIT31IIEvkntP6vZKS4= +k8s.io/apiextensions-apiserver v0.27.2 h1:iwhyoeS4xj9Y7v8YExhUwbVuBhMr3Q4bd/laClBV6Bo= +k8s.io/apiextensions-apiserver v0.27.2/go.mod h1:Oz9UdvGguL3ULgRdY9QMUzL2RZImotgxvGjdWRq6ZXQ= k8s.io/apimachinery v0.20.1/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRpU= k8s.io/apimachinery v0.20.4/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRpU= k8s.io/apimachinery v0.20.6/go.mod h1:ejZXtW1Ra6V1O5H8xPBGz+T3+4gfkTCeExAHKU57MAc= @@ -2741,14 +2753,14 @@ k8s.io/apimachinery v0.22.1/go.mod h1:O3oNtNadZdeOMxHFVxOreoznohCpy0z6mocxbZr7oJ k8s.io/apimachinery v0.22.5/go.mod h1:xziclGKwuuJ2RM5/rSFQSYAj0zdbci3DH8kj+WvyN0U= k8s.io/apimachinery v0.23.5/go.mod h1:BEuFMMBaIbcOqVIJqNZJXGFTP4W6AycEpb5+m/97hrM= k8s.io/apimachinery v0.24.2/go.mod h1:82Bi4sCzVBdpYjyI4jY6aHX+YCUchUIrZrXKedjd2UM= -k8s.io/apimachinery v0.27.1 h1:EGuZiLI95UQQcClhanryclaQE6xjg1Bts6/L3cD7zyc= -k8s.io/apimachinery v0.27.1/go.mod h1:5ikh59fK3AJ287GUvpUsryoMFtH9zj/ARfWCo3AyXTM= +k8s.io/apimachinery v0.27.2 h1:vBjGaKKieaIreI+oQwELalVG4d8f3YAMNpWLzDXkxeg= +k8s.io/apimachinery v0.27.2/go.mod h1:XNfZ6xklnMCOGGFNqXG7bUrQCoR04dh/E7FprV6pb+E= k8s.io/apiserver v0.20.1/go.mod h1:ro5QHeQkgMS7ZGpvf4tSMx6bBOgPfE+f52KwvXfScaU= k8s.io/apiserver v0.20.4/go.mod h1:Mc80thBKOyy7tbvFtB4kJv1kbdD0eIH8k8vianJcbFM= k8s.io/apiserver v0.20.6/go.mod h1:QIJXNt6i6JB+0YQRNcS0hdRHJlMhflFmsBDeSgT1r8Q= k8s.io/apiserver v0.22.5/go.mod h1:s2WbtgZAkTKt679sYtSudEQrTGWUSQAPe6MupLnlmaQ= -k8s.io/apiserver v0.27.1 h1:phY+BtXjjzd+ta3a4kYbomC81azQSLa1K8jo9RBw7Lg= -k8s.io/apiserver v0.27.1/go.mod h1:UGrOjLY2KsieA9Fw6lLiTObxTb8Z1xEba4uqSuMY0WU= +k8s.io/apiserver v0.27.2 h1:p+tjwrcQEZDrEorCZV2/qE8osGTINPuS5ZNqWAvKm5E= +k8s.io/apiserver v0.27.2/go.mod h1:EsOf39d75rMivgvvwjJ3OW/u9n1/BmUMK5otEOJrb1Y= k8s.io/cli-runtime v0.27.1 h1:MMzp5Q/Xmr5L1Lrowuc+Y/r95XINC6c6/fE3aN7JDRM= k8s.io/cli-runtime v0.27.1/go.mod h1:tEbTB1XP/nTH3wujsi52bw91gWpErtWiS15R6CwYsAI= k8s.io/client-go v0.20.1/go.mod h1:/zcHdt1TeWSd5HoUe6elJmHSQ6uLLgp4bIJHVEuy+/Y= @@ -2757,15 +2769,15 @@ k8s.io/client-go v0.20.6/go.mod h1:nNQMnOvEUEsOzRRFIIkdmYOjAZrC8bgq0ExboWSU1I0= k8s.io/client-go v0.22.5/go.mod h1:cs6yf/61q2T1SdQL5Rdcjg9J1ElXSwbjSrW2vFImM4Y= k8s.io/client-go v0.23.5/go.mod h1:flkeinTO1CirYgzMPRWxUCnV0G4Fbu2vLhYCObnt/r4= k8s.io/client-go v0.24.2/go.mod h1:zg4Xaoo+umDsfCWr4fCnmLEtQXyCNXCvJuSsglNcV30= -k8s.io/client-go v0.27.1 h1:oXsfhW/qncM1wDmWBIuDzRHNS2tLhK3BZv512Nc59W8= -k8s.io/client-go v0.27.1/go.mod h1:f8LHMUkVb3b9N8bWturc+EDtVVVwZ7ueTVquFAJb2vA= +k8s.io/client-go v0.27.2 h1:vDLSeuYvCHKeoQRhCXjxXO45nHVv2Ip4Fe0MfioMrhE= +k8s.io/client-go v0.27.2/go.mod h1:tY0gVmUsHrAmjzHX9zs7eCjxcBsf8IiNe7KQ52biTcQ= k8s.io/code-generator v0.19.7/go.mod h1:lwEq3YnLYb/7uVXLorOJfxg+cUu2oihFhHZ0n9NIla0= k8s.io/component-base v0.20.1/go.mod h1:guxkoJnNoh8LNrbtiQOlyp2Y2XFCZQmrcg2n/DeYNLk= k8s.io/component-base v0.20.4/go.mod h1:t4p9EdiagbVCJKrQ1RsA5/V4rFQNDfRlevJajlGwgjI= k8s.io/component-base v0.20.6/go.mod h1:6f1MPBAeI+mvuts3sIdtpjljHWBQ2cIy38oBIWMYnrM= k8s.io/component-base v0.22.5/go.mod h1:VK3I+TjuF9eaa+Ln67dKxhGar5ynVbwnGrUiNF4MqCI= -k8s.io/component-base v0.27.1 h1:kEB8p8lzi4gCs5f2SPU242vOumHJ6EOsOnDM3tTuDTM= -k8s.io/component-base v0.27.1/go.mod h1:UGEd8+gxE4YWoigz5/lb3af3Q24w98pDseXcXZjw+E0= +k8s.io/component-base v0.27.2 h1:neju+7s/r5O4x4/txeUONNTS9r1HsPbyoPBAtHsDCpo= +k8s.io/component-base v0.27.2/go.mod h1:5UPk7EjfgrfgRIuDBFtsEFAe4DAvP3U+M8RTzoSJkpo= k8s.io/cri-api v0.17.3/go.mod h1:X1sbHmuXhwaHs9xxYffLqJogVsnI+f6cPRcgPel7ywM= k8s.io/cri-api v0.20.1/go.mod h1:2JRbKt+BFLTjtrILYVqQK5jqhI+XNdF6UiGMgczeBCI= k8s.io/cri-api v0.20.4/go.mod h1:2JRbKt+BFLTjtrILYVqQK5jqhI+XNdF6UiGMgczeBCI= @@ -2792,8 +2804,8 @@ k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e/go.mod h1:vHXdDvt9+2spS2R k8s.io/kube-openapi v0.0.0-20211109043538-20434351676c/go.mod h1:vHXdDvt9+2spS2Rx9ql3I8tycm3H9FDfdUoIuKCefvw= k8s.io/kube-openapi v0.0.0-20211115234752-e816edb12b65/go.mod h1:sX9MT8g7NVZM5lVL/j8QyCCJe8YSMW30QvGZWaCIDIk= k8s.io/kube-openapi v0.0.0-20220328201542-3ee0da9b0b42/go.mod h1:Z/45zLw8lUo4wdiUkI+v/ImEGAvu3WatcZl3lPMR4Rk= -k8s.io/kube-openapi v0.0.0-20230308215209-15aac26d736a h1:gmovKNur38vgoWfGtP5QOGNOA7ki4n6qNYoFAgMlNvg= -k8s.io/kube-openapi v0.0.0-20230308215209-15aac26d736a/go.mod h1:y5VtZWM9sHHc2ZodIH/6SHzXj+TPU5USoA8lcIeKEKY= +k8s.io/kube-openapi v0.0.0-20230501164219-8b0f38b5fd1f h1:2kWPakN3i/k81b0gvD5C5FJ2kxm1WrQFanWchyKuqGg= +k8s.io/kube-openapi v0.0.0-20230501164219-8b0f38b5fd1f/go.mod h1:byini6yhqGC14c3ebc/QwanvYwhuMWF6yz2F8uwW8eg= k8s.io/kubectl v0.27.1 h1:9T5c5KdpburYiW8XKQSH0Uly1kMNE90aGSnbYUZNdcA= k8s.io/kubectl v0.27.1/go.mod h1:QsAkSmrRsKTPlAFzF8kODGDl4p35BIwQnc9XFhkcsy8= k8s.io/kubernetes v1.13.0/go.mod h1:ocZa8+6APFNC2tX1DZASIbocyYT5jHzqFVsY5aoB7Jk= @@ -2818,6 +2830,10 @@ rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.14/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.15/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.22/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg= +sigs.k8s.io/cli-utils v0.34.0 h1:zCUitt54f0/MYj/ajVFnG6XSXMhpZ72O/3RewIchW8w= +sigs.k8s.io/cli-utils v0.34.0/go.mod h1:EXyMwPMu9OL+LRnj0JEMsGG/fRvbgFadcVlSnE8RhFs= +sigs.k8s.io/controller-runtime v0.15.0 h1:ML+5Adt3qZnMSYxZ7gAverBLNPSMQEibtzAgp0UPojU= +sigs.k8s.io/controller-runtime v0.15.0/go.mod h1:7ngYvp1MLT+9GeZ+6lH3LOlcHkp/+tzA/fmHa4iq9kk= sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6/go.mod h1:p4QtZmO4uMYipTQNzagwnNoseA6OxSUutVw05NhYDRs= sigs.k8s.io/json v0.0.0-20211208200746-9f7c6b3444d2/go.mod h1:B+TnT182UBxE84DiCz4CVE26eOSDAeYCpfDnC2kdKMY= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= diff --git a/provider/pkg/await/await.go b/provider/pkg/await/await.go index 0d1d61a486..8717958cf9 100644 --- a/provider/pkg/await/await.go +++ b/provider/pkg/await/await.go @@ -16,10 +16,11 @@ package await import ( "context" + "encoding/json" "fmt" "os" - "regexp" + fluxssa "github.com/fluxcd/pkg/ssa" "github.com/pulumi/pulumi-kubernetes/provider/v3/pkg/clients" "github.com/pulumi/pulumi-kubernetes/provider/v3/pkg/cluster" "github.com/pulumi/pulumi-kubernetes/provider/v3/pkg/kinds" @@ -142,11 +143,6 @@ func skipRetry(gvk schema.GroupVersionKind, k8sVersion *cluster.ServerVersion, e const ssaConflictDocLink = "https://www.pulumi.com/registry/packages/kubernetes/how-to-guides/managing-resources-with-server-side-apply/#handle-field-conflicts-on-existing-resources" -// Resources created with Client-side Apply (CSA) will assign a field manager with an operation of type "Update" that -// conflicts with Server-side Apply (SSA) field managers that use type "Apply". This regex is used to check for known -// CSA field manager names to determine if the apply operation should be retried. -var csaConflictRegex = regexp.MustCompile(`conflict with "(pulumi-resource-kubernetes|pulumi-resource-kubernetes.exe|pulumi-kubernetes)"`) - // Creation (as the usage, `await.Creation`, implies) will block until one of the following is true: // (1) the Kubernetes resource is reported to be initialized; (2) the initialization timeout has // occurred; or (3) an error has occurred while the resource was being initialized. @@ -188,8 +184,7 @@ func Creation(c CreateConfig) (*unstructured.Unstructured, error) { } if c.ServerSideApply { - // Always force on preview to avoid erroneous conflict errors for resource replacements - force := c.Preview || patchForce(c.Inputs) + force := patchForce(c.Inputs, nil, c.Preview) options := metav1.PatchOptions{ FieldManager: c.FieldManager, Force: &force, @@ -342,14 +337,9 @@ func Read(c ReadConfig) (*unstructured.Unstructured, error) { return live, nil } -// Update takes `lastSubmitted` (the last version of a Kubernetes API object submitted to the API -// server) and `currentSubmitted` (the version of the Kubernetes API object being submitted for an -// update currently) and blocks until one of the following is true: (1) the Kubernetes resource is -// reported to be updated; (2) the update timeout has occurred; or (3) an error has occurred while -// the resource was being updated. -// -// Update updates an existing resource with new values. Currently, this client supports the -// Kubernetes-standard three-way JSON patch, and the newer Server-side Apply patch. See references [1], [2], [3]. +// Update updates an existing resource with new values. This client uses a Server-side Apply (SSA) patch by default, but +// also supports the older three-way JSON patch and the strategic merge patch as fallback options. +// See references [1], [2], [3]. // // nolint // [1]: @@ -359,48 +349,6 @@ func Read(c ReadConfig) (*unstructured.Unstructured, error) { // [3]: // https://kubernetes.io/docs/reference/using-api/server-side-apply func Update(c UpdateConfig) (*unstructured.Unstructured, error) { - // - // TREAD CAREFULLY. The semantics of a Kubernetes update are subtle, and you should proceed to - // change them only if you understand them deeply. - // - // Briefly: when a user updates an existing resource definition (e.g., by modifying YAML), the API - // server must decide how to apply the changes inside it, to the version of the resource that it - // has stored in etcd. In Kubernetes this decision is turns out to be quite complex. `kubectl` - // currently uses the three-way "strategic merge" and falls back to the three-way JSON merge. We - // currently support the second, but eventually we'll have to support the first, too. - // - // (NOTE: This comment is scoped to the question of how to patch an existing resource, rather than - // how to recognize when a resource needs to be re-created from scratch.) - // - // There are several reasons for this complexity: - // - // * It's important not to clobber fields set or default-set by the server (e.g., NodePort, - // namespace, service type, etc.), or by out-of-band tooling like admission controllers - // (which, e.g., might do something like add a sidecar to a container list). - // * For example, consider a scenario where a user renames a container. It is a reasonable - // expectation the old version of the container gets destroyed when the update is applied. And - // if the update strategy is set to three-way JSON merge patching, it is. - // * But, consider if their administrator has set up (say) the Istio admission controller, which - // embeds a sidecar container in pods submitted to the API. This container would not be present - // in the YAML file representing that pod, but when an update is applied by the user, they - // not want it to get destroyed. And, so, when the strategy is set to three-way strategic - // merge, the container is not destroyed. (With this strategy, fields can have "merge keys" as - // part of their schema, which tells the API server how to merge each particular field.) - // - // What's worse is, currently nearly all of this logic exists on the client rather than the - // server, though there is work moving forward to move this to the server. - // - // So the roadmap is: - // - // - [x] Implement `Update` using the three-way JSON merge strategy. - // - [x] Cause `Update` to default to the three-way JSON merge patch strategy. (This will require - // plumbing, because it expects nominal types representing the API schema, but the - // discovery client is completely dynamic.) - // - [x] Support server-side apply. - // - // In the next major release, we will default to using Server-side Apply, which will simplify this logic. - // - client, err := c.ClientSet.ResourceClientForObject(c.Inputs) if err != nil { return nil, err @@ -427,11 +375,18 @@ func Update(c UpdateConfig) (*unstructured.Unstructured, error) { } } else { if c.ServerSideApply { + if !c.Preview { + err = fixCSAFieldManagers(c, liveOldObj, client) + if err != nil { + return nil, err + } + } + objYAML, err := yaml.Marshal(c.Inputs.Object) if err != nil { return nil, err } - force := patchForce(c.Inputs) + force := patchForce(c.Inputs, liveOldObj, c.Preview) options := metav1.PatchOptions{ FieldManager: c.FieldManager, Force: &force, @@ -443,23 +398,10 @@ func Update(c UpdateConfig) (*unstructured.Unstructured, error) { // Issue patch request. // NOTE: We can use the same client because if the `kind` changes, this will cause // a replace (i.e., destroy and create). - maybeRetry := true for { currentOutputs, err = client.Patch(c.Context, c.Inputs.GetName(), types.ApplyPatchType, objYAML, options) if err != nil { if errors.IsConflict(err) { - if maybeRetry { - // If the patch failed, use heuristics to determine if the resource was created using - // Client-side Apply. If so, retry once with the force patch option. - if csaConflictRegex.MatchString(err.Error()) && - metadata.GetLabel(c.Inputs, metadata.LabelManagedBy) == "pulumi" { - force = true - options.Force = &force - maybeRetry = false // Only retry once - continue - } - } - err = fmt.Errorf("Server-Side Apply field conflict detected. see %s for troubleshooting help\n: %w", ssaConflictDocLink, err) } @@ -547,6 +489,60 @@ func Update(c UpdateConfig) (*unstructured.Unstructured, error) { return live, nil } +// fixCSAFieldManagers patches the field managers for an existing resource that was managed using client-side apply. +// The new server-side apply field manager takes ownership of all these fields to avoid conflicts. +func fixCSAFieldManagers(c UpdateConfig, live *unstructured.Unstructured, client dynamic.ResourceInterface) error { + if managedFields := live.GetManagedFields(); len(managedFields) > 0 { + patches, err := fluxssa.PatchReplaceFieldsManagers(live, []fluxssa.FieldManager{ + { + // take ownership of changes made with 'kubectl apply --server-side --force-conflicts' + Name: "kubectl", + OperationType: metav1.ManagedFieldsOperationApply, + }, + { + // take ownership of changes made with 'kubectl apply' + Name: "kubectl", + OperationType: metav1.ManagedFieldsOperationUpdate, + }, + { + // take ownership of changes made with 'kubectl apply' + Name: "before-first-apply", + OperationType: metav1.ManagedFieldsOperationUpdate, + }, + // The following are possible field manager values for resources that were created using this provider under + // CSA mode. Note the "Update" operation type, which Kubernetes treats as a separate field manager even if + // the name is identical. See https://github.com/kubernetes/kubernetes/issues/99003 + { + // take ownership of changes made with pulumi-kubernetes CSA + Name: "pulumi-kubernetes", + OperationType: metav1.ManagedFieldsOperationUpdate, + }, + { + // take ownership of changes made with pulumi-kubernetes CSA + Name: "pulumi-kubernetes.exe", + OperationType: metav1.ManagedFieldsOperationUpdate, + }, + { + // take ownership of changes made with pulumi-kubernetes CSA + Name: "pulumi-resource-kubernetes", + OperationType: metav1.ManagedFieldsOperationUpdate, + }, + }, c.FieldManager) + if err != nil { + return err + } + patch, err := json.Marshal(patches) + if err != nil { + return err + } + live, err = client.Patch(c.Context, live.GetName(), types.JSONPatchType, patch, metav1.PatchOptions{}) + if err != nil { + return err + } + } + return nil +} + // Deletion (as the usage, `await.Deletion`, implies) will block until one of the following is true: // (1) the Kubernetes resource is reported to be deleted; (2) the initialization timeout has // occurred; or (3) an error has occurred while the resource was being deleted. @@ -712,12 +708,30 @@ func clearStatus(context context.Context, host *pulumiprovider.HostClient, urn r } // patchForce decides whether to overwrite patch conflicts. -func patchForce(obj *unstructured.Unstructured) bool { - if metadata.IsAnnotationTrue(obj, metadata.AnnotationPatchForce) { +func patchForce(inputs, live *unstructured.Unstructured, preview bool) bool { + if metadata.IsAnnotationTrue(inputs, metadata.AnnotationPatchForce) { return true } if enabled, exists := os.LookupEnv("PULUMI_K8S_ENABLE_PATCH_FORCE"); exists { return enabled == "true" } + if preview { + // Always force on preview if no previous state to avoid erroneous conflict errors for resource replacements. + if live == nil { + return true + } + // If the resource includes a CSA field manager for this provider, then force the update. Field managers will be + // adjusted before this on real updates, so only force on preview. + for _, managedField := range live.GetManagedFields() { + if managedField.Operation != metav1.ManagedFieldsOperationUpdate { + continue + } + switch managedField.Manager { + case "pulumi-resource-kubernetes", "pulumi-kubernetes", "pulumi-kubernetes.exe": + return true + } + } + } + return false } diff --git a/provider/pkg/clients/unstructured.go b/provider/pkg/clients/unstructured.go index e13ea3ca0f..97c336c59d 100644 --- a/provider/pkg/clients/unstructured.go +++ b/provider/pkg/clients/unstructured.go @@ -50,6 +50,27 @@ func FromUnstructured(uns *unstructured.Unstructured) (metav1.Object, error) { return metaObj, nil } +// ToUnstructured converts a typed Kubernetes resource into the Unstructured equivalent. +func ToUnstructured(object metav1.Object) (*unstructured.Unstructured, error) { + result, err := runtime.DefaultUnstructuredConverter.ToUnstructured(object) + if err != nil { + return nil, err + } + return &unstructured.Unstructured{ + Object: result, + }, nil +} + +// Normalize converts an Unstructured Kubernetes resource into the typed equivalent and then back to Unstructured. +// This process normalizes semantically-equivalent resources into an identical output, which is important for diffing. +func Normalize(uns *unstructured.Unstructured) (*unstructured.Unstructured, error) { + obj, err := FromUnstructured(uns) + if err != nil { + return nil, err + } + return ToUnstructured(obj) +} + func PodFromUnstructured(uns *unstructured.Unstructured) (*corev1.Pod, error) { const expectedAPIVersion = "v1" diff --git a/provider/pkg/provider/provider.go b/provider/pkg/provider/provider.go index 6f35d57c72..362458093a 100644 --- a/provider/pkg/provider/provider.go +++ b/provider/pkg/provider/provider.go @@ -35,7 +35,6 @@ import ( "github.com/golang/protobuf/ptypes/empty" pbempty "github.com/golang/protobuf/ptypes/empty" structpb "github.com/golang/protobuf/ptypes/struct" - "github.com/imdario/mergo" pkgerrors "github.com/pkg/errors" checkjob "github.com/pulumi/cloud-ready-checks/pkg/kubernetes/job" "github.com/pulumi/pulumi-kubernetes/provider/v3/pkg/await" @@ -65,7 +64,6 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime/schema" - "k8s.io/apimachinery/pkg/types" "k8s.io/client-go/rest" "k8s.io/client-go/tools/clientcmd" clientapi "k8s.io/client-go/tools/clientcmd/api" @@ -1291,6 +1289,11 @@ func (k *kubeProvider) Check(ctx context.Context, req *pulumirpc.CheckRequest) ( oldInputs := propMapToUnstructured(olds) newInputs := propMapToUnstructured(news) + newInputs, err = normalize(newInputs) + if err != nil { + return nil, err + } + if k.serverSideApplyMode && isPatchURN(urn) { if len(newInputs.GetName()) == 0 { return nil, fmt.Errorf("patch resources require the resource `.metadata.name` to be set") @@ -1463,17 +1466,24 @@ func (k *kubeProvider) helmHookWarning(ctx context.Context, newInputs *unstructu // Diff checks what impacts a hypothetical update will have on the resource's properties. func (k *kubeProvider) Diff(ctx context.Context, req *pulumirpc.DiffRequest) (*pulumirpc.DiffResponse, error) { // - // Behavior as of v0.12.x: We take 2 inputs: + // Behavior as of v4.0: We take 2 inputs: // // 1. req.News, the new resource inputs, i.e., the property bag coming from a custom resource like // k8s.core.v1.Service - // 2. req.Olds, the old _state_ returned by a `Create` or an `Update`. The old state has the form - // {inputs: {...}, live: {...}}, and is a struct that contains the old inputs as well as the - // last computed value obtained from the Kubernetes API server. + // 2. req.Olds, the old _state_ returned by a `Create` or an `Update`. // - // The list of properties that would cause replacement is then computed between the old and new - // _inputs_, as in Kubernetes this captures changes the user made that result in replacement - // (which is not true of the old computed values). + // Kubernetes sets many additional fields that are not present in the resource inputs. We want to compare new inputs + // to the most recent "live" values for the resource, but also don't want to show diffs for fields that are managed + // by the cluster. We accomplish this by pruning the live state to match the shape of the old inputs, and then + // comparing between the "pruned live" inputs and the new inputs. + // + // Note that comparing the old inputs to the new inputs will miss resource drift caused by other controllers + // modifying the resources because the Pulumi inputs have not changed. Prior versions (pre-4.0) of the provider + // used the "kubectl.kubernetes.io/last-applied-configuration" annotation to partially work around this problem. + // This annotation was updated by the provider and some `kubectl` commands to capture the most recent set of inputs + // used to produce the current resource state. When the annotation was present, this value was used instead of the + // old inputs for the diff computation. This approach led to many problems, so the v4.0 release of the provider + // removed the use of this annotation in favor of the "pruned live" input approach. // urn := resource.URN(req.GetUrn()) @@ -1481,8 +1491,7 @@ func (k *kubeProvider) Diff(ctx context.Context, req *pulumirpc.DiffRequest) (*p label := fmt.Sprintf("%s.Diff(%s)", k.label(), urn) logger.V(9).Infof("%s executing", label) - // Get old state. This is an object of the form {inputs: {...}, live: {...}} where `inputs` is the - // previous resource inputs supplied by the user, and `live` is the computed state of that inputs + // Get old state. This is an object that includes `inputs` previously supplied by the user, and the live state // we received back from the API server. oldState, err := plugin.UnmarshalProperties(req.GetOlds(), plugin.MarshalOptions{ Label: fmt.Sprintf("%s.olds", label), KeepUnknowns: true, SkipNulls: true, KeepSecrets: true, @@ -1503,7 +1512,18 @@ func (k *kubeProvider) Diff(ctx context.Context, req *pulumirpc.DiffRequest) (*p } newInputs := propMapToUnstructured(newResInputs) - oldInputs, _ := parseCheckpointObject(oldState) + + oldInputs, oldLive := parseCheckpointObject(oldState) + + oldInputs, err = normalize(oldInputs) + if err != nil { + return nil, err + } + newInputs, err = normalize(newInputs) + if err != nil { + return nil, err + } + oldLivePruned := pruneLiveState(oldLive, oldInputs) gvk := k.gvkFromUnstructured(newInputs) @@ -1526,33 +1546,32 @@ func (k *kubeProvider) Diff(ctx context.Context, req *pulumirpc.DiffRequest) (*p if namespacedKind { // Explicitly set the "default" namespace if unset so that the diff ignores it. - oldInputs.SetNamespace(canonicalNamespace(oldInputs.GetNamespace())) + oldLivePruned.SetNamespace(canonicalNamespace(oldLivePruned.GetNamespace())) newInputs.SetNamespace(canonicalNamespace(newInputs.GetNamespace())) } else { // Clear the namespace if it was set erroneously. - oldInputs.SetNamespace("") + oldLivePruned.SetNamespace("") newInputs.SetNamespace("") } - if oldInputs.GroupVersionKind().Empty() { - oldInputs.SetGroupVersionKind(gvk) + if oldLivePruned.GroupVersionKind().Empty() { + oldLivePruned.SetGroupVersionKind(gvk) } // If a resource was created without SSA enabled, and then the related provider was changed to enable SSA, a // resourceVersion may have been set on the old resource state. This produces erroneous diffs, so remove the - // value from the oldInputs prior to computing the diff. - if k.serverSideApplyMode && len(oldInputs.GetResourceVersion()) > 0 { - oldInputs.SetResourceVersion("") + // value from the oldLivePruned prior to computing the diff. + if k.serverSideApplyMode && len(oldLivePruned.GetResourceVersion()) > 0 { + oldLivePruned.SetResourceVersion("") } var patch []byte - var patchBase map[string]any + patchBase := oldLivePruned.Object - // Always compute a client-side patch. - patch, err = k.inputPatch(oldInputs, newInputs) + // Compute a diff between the pruned live state and the new inputs. + patch, err = k.inputPatch(oldLivePruned, newInputs) if err != nil { return nil, pkgerrors.Wrapf( err, "Failed to check for changes in resource %s/%s", newInputs.GetNamespace(), newInputs.GetName()) } - patchBase = oldInputs.Object patchObj := map[string]any{} if err = json.Unmarshal(patch, &patchObj); err != nil { @@ -1562,41 +1581,6 @@ func (k *kubeProvider) Diff(ctx context.Context, req *pulumirpc.DiffRequest) (*p newInputs.GetNamespace(), newInputs.GetName()) } - fieldManager := k.fieldManagerName(nil, newResInputs, newInputs) - - // Try to compute a server-side patch. - ssPatch, ssPatchBase, ssPatchOk, err := k.tryServerSidePatch(oldInputs, newInputs, gvk, fieldManager) - if err != nil { - return nil, err - } - - // If the server-side patch succeeded, then merge that patch into the client-side patch and override any conflicts - // with the server-side values. - if ssPatchOk { - logger.V(1).Infof("calculated diffs for %s/%s using dry-run and inputs", newInputs.GetNamespace(), newInputs.GetName()) - // Merge the server-side patch into the client-side patch, and ensure that any fields that are set to null in the - // server-side patch are set to null in the client-side patch. - err = mergo.Merge(&patchBase, ssPatchBase, mergo.WithOverwriteWithEmptyValue) - if err != nil { - return nil, err - } - - ssPatchObj := map[string]any{} - if err = json.Unmarshal(ssPatch, &ssPatchObj); err != nil { - return nil, pkgerrors.Wrapf( - err, "Failed to check for changes in resource %s/%s because of an error serializing "+ - "the JSON patch describing resource changes", - newInputs.GetNamespace(), newInputs.GetName()) - } - err = mergo.Merge(&patchObj, ssPatchObj, mergo.WithOverride) - if err != nil { - return nil, err - } - } else { - logger.V(1).Infof("calculated diffs for %s/%s using inputs only", newInputs.GetNamespace(), newInputs.GetName()) - } - - // Pack up PB, ship response back. hasChanges := pulumirpc.DiffResponse_DIFF_NONE var replaces []string @@ -1605,9 +1589,9 @@ func (k *kubeProvider) Diff(ctx context.Context, req *pulumirpc.DiffRequest) (*p // Changing the identity of the resource always causes a replacement. forceNewFields := []string{".metadata.name", ".metadata.namespace"} if !isPatchURN(urn) { // Patch resources can be updated in place for all other properties. - forceNewFields = k.forceNewProperties(oldInputs) + forceNewFields = k.forceNewProperties(newInputs) } - if detailedDiff, err = convertPatchToDiff(patchObj, patchBase, newInputs.Object, oldInputs.Object, forceNewFields...); err != nil { + if detailedDiff, err = convertPatchToDiff(patchObj, patchBase, newInputs.Object, oldLivePruned.Object, forceNewFields...); err != nil { return nil, pkgerrors.Wrapf( err, "Failed to check for changes in resource %s/%s because of an error "+ "converting JSON patch describing resource changes to a diff", @@ -1685,10 +1669,10 @@ func (k *kubeProvider) Diff(ctx context.Context, req *pulumirpc.DiffRequest) (*p // auto-generate the name). !metadata.IsAutonamed(newInputs) && // 3. The new, user-specified name is the same as the old name. - newInputs.GetName() == oldInputs.GetName() && + newInputs.GetName() == oldLivePruned.GetName() && // 4. The resource is being deployed to the same namespace (i.e., we aren't creating the // object in a new namespace and then deleting the old one). - newInputs.GetNamespace() == oldInputs.GetNamespace() + newInputs.GetNamespace() == oldLivePruned.GetNamespace() return &pulumirpc.DiffResponse{ Changes: hasChanges, @@ -1700,23 +1684,22 @@ func (k *kubeProvider) Diff(ctx context.Context, req *pulumirpc.DiffRequest) (*p }, nil } -// Create allocates a new instance of the provided resource and returns its unique ID afterwards. +// Create allocates a new instance of the provided resource and returns its unique ID. // (The input ID must be blank.) If this call fails, the resource must not have been created (i.e., // it is "transactional"). func (k *kubeProvider) Create( ctx context.Context, req *pulumirpc.CreateRequest, ) (*pulumirpc.CreateResponse, error) { // - // Behavior as of v0.12.x: We take 1 input: + // Behavior as of v4.0: We take 1 input: // // 1. `req.Properties`, the new resource inputs submitted by the user, after having been returned // by `Check`. // // This is used to create a new resource, and the computed values are returned. Importantly: // - // * The return is formatted as a "checkpoint object", i.e., an object of the form - // {inputs: {...}, live: {...}}. This is important both for `Diff` and for `Update`. See - // comments in those methods for details. + // * The return is formatted as a "checkpoint object", which includes both inputs and the live state of the + // resource. This is important both for `Diff` and for `Update`. See comments in those methods for details. // urn := resource.URN(req.GetUrn()) @@ -1758,14 +1741,6 @@ func (k *kubeProvider) Create( return &pulumirpc.CreateResponse{Id: "", Properties: req.GetProperties()}, nil } - annotatedInputs, err := k.withLastAppliedConfig(newInputs) - if err != nil { - return nil, pkgerrors.Wrapf( - err, "Failed to create resource %s/%s because of an error generating the %s value in "+ - "`.metadata.annotations`", - newInputs.GetNamespace(), newInputs.GetName(), lastAppliedConfigKey) - } - initialAPIVersion := newInputs.GetAPIVersion() fieldManager := k.fieldManagerName(nil, newResInputs, newInputs) @@ -1773,14 +1748,14 @@ func (k *kubeProvider) Create( if newResInputs.ContainsSecrets() { _ = k.host.Log(ctx, diag.Warning, urn, fmt.Sprintf( "rendered file %s contains a secret value in plaintext", - renderPathForResource(annotatedInputs, k.yamlDirectory))) + renderPathForResource(newInputs, k.yamlDirectory))) } - err := renderYaml(annotatedInputs, k.yamlDirectory) + err := renderYaml(newInputs, k.yamlDirectory) if err != nil { return nil, err } - obj := checkpointObject(newInputs, annotatedInputs, newResInputs, initialAPIVersion, fieldManager) + obj := checkpointObject(newInputs, newInputs, newResInputs, initialAPIVersion, fieldManager) inputsAndComputed, err := plugin.MarshalProperties( obj, plugin.MarshalOptions{ Label: fmt.Sprintf("%s.inputsAndComputed", label), @@ -1793,10 +1768,10 @@ func (k *kubeProvider) Create( } _ = k.host.LogStatus(ctx, diag.Info, urn, fmt.Sprintf( - "rendered %s", renderPathForResource(annotatedInputs, k.yamlDirectory))) + "rendered %s", renderPathForResource(newInputs, k.yamlDirectory))) return &pulumirpc.CreateResponse{ - Id: fqObjName(annotatedInputs), Properties: inputsAndComputed, + Id: fqObjName(newInputs), Properties: inputsAndComputed, }, nil } @@ -1817,7 +1792,7 @@ func (k *kubeProvider) Create( Resources: resources, ServerSideApply: k.serverSideApplyMode, }, - Inputs: annotatedInputs, + Inputs: newInputs, Timeout: req.Timeout, Preview: req.GetPreview(), } @@ -1905,17 +1880,17 @@ func (k *kubeProvider) Create( // include some properties. func (k *kubeProvider) Read(ctx context.Context, req *pulumirpc.ReadRequest) (*pulumirpc.ReadResponse, error) { // - // Behavior as of v0.12.x: We take 1 input: + // Behavior as of v4.0: We take 2 inputs: // - // 1. `req.Properties`, the new resource inputs submitted by the user, after having been persisted + // 1. `req.Properties`, the previous state of the resource. + // 2. `req.Inputs`, the old resource inputs submitted by the user, after having been persisted // (e.g., by `Create` or `Update`). // // We use this information to read the live version of a Kubernetes resource. This is sometimes // then checkpointed (e.g., in the case of `refresh`). Specifically: // - // * The return is formatted as a "checkpoint object", i.e., an object of the form - // {inputs: {...}, live: {...}}. This is important both for `Diff` and for `Update`. See - // comments in those methods for details. + // * The return is formatted as a "checkpoint object", which includes both inputs and the live state of the + // resource. This is important both for `Diff` and for `Update`. See comments in those methods for details. // urn := resource.URN(req.GetUrn()) @@ -1966,7 +1941,14 @@ func (k *kubeProvider) Read(ctx context.Context, req *pulumirpc.ReadRequest) (*p } readFromCluster := false - oldInputs, oldLive := parseCheckpointObject(oldState) + oldInputs := propMapToUnstructured(oldInputsPM) + _, oldLive := parseCheckpointObject(oldState) + + oldInputs, err = normalize(oldInputs) + if err != nil { + return nil, err + } + if oldInputs.GroupVersionKind().Empty() { if oldLive.GroupVersionKind().Empty() { gvk, err := k.gvkFromURN(urn) @@ -2065,8 +2047,8 @@ func (k *kubeProvider) Read(ctx context.Context, req *pulumirpc.ReadRequest) (*p // initialize. } - // Attempt to parse the inputs for this object. If parsing was unsuccessful, retain the old inputs. - liveInputs := parseLiveInputs(liveObj, oldInputs) + // Prune the live inputs to remove properties that are not present in the program inputs. + liveInputs := pruneLiveState(liveObj, oldInputs) if readFromCluster { // If no previous inputs were known, populate the inputs from the live cluster state for the resource. @@ -2089,6 +2071,7 @@ func (k *kubeProvider) Read(ctx context.Context, req *pulumirpc.ReadRequest) (*p unstructured.RemoveNestedField(liveInputs.Object, "metadata", "managedFields") unstructured.RemoveNestedField(liveInputs.Object, "metadata", "resourceVersion") unstructured.RemoveNestedField(liveInputs.Object, "metadata", "uid") + unstructured.RemoveNestedField(liveInputs.Object, "metadata", "annotations", "deployment.kubernetes.io/revision") unstructured.RemoveNestedField(liveInputs.Object, "metadata", "annotations", lastAppliedConfigKey) } @@ -2130,8 +2113,9 @@ func (k *kubeProvider) Read(ctx context.Context, req *pulumirpc.ReadRequest) (*p return &pulumirpc.ReadResponse{Id: id, Properties: state, Inputs: inputs}, nil } -// Update updates an existing resource with new values. Currently, this client supports the -// Kubernetes-standard three-way JSON patch, and the newer Server-side Apply patch. See references [1], [2], [3]. +// Update updates an existing resource with new values. This client uses a Server-side Apply (SSA) patch by default, but +// also supports the older three-way JSON patch and the strategic merge patch as fallback options. +// See references [1], [2], [3]. // // nolint // [1]: @@ -2144,61 +2128,25 @@ func (k *kubeProvider) Update( ctx context.Context, req *pulumirpc.UpdateRequest, ) (*pulumirpc.UpdateResponse, error) { // - // Behavior as of v3.20.0: We take 2 inputs: + // Behavior as of v4.0: We take 2 inputs: // // 1. req.News, the new resource inputs, i.e., the property bag coming from a custom resource like // k8s.core.v1.Service - // 2. req.Olds, the old _state_ returned by a `Create` or an `Update`. The old state has the form - // {inputs: {...}, live: {...}}, and is a struct that contains the old inputs as well as the - // last computed value obtained from the Kubernetes API server. + // 2. req.Olds, the old _state_ returned by a `Create` or an `Update`. The old state is a struct that + // contains the old inputs as well as the last computed value obtained from the Kubernetes API server. + // + // The provider uses Server-side Apply (SSA) patches by default, which allows the provider to send the desired + // state of the resource to Kubernetes, and let the server decide how to merge in the changes. Previews are + // computed using the dry-run option for the API call, which computes the result on the server without persisting + // the changes. // - // Unlike other providers, the update is computed as a three-way merge between: (1) the new - // inputs, (2) the computed state returned by the API server, and (3) the old inputs. This is the + // Previous versions of the provider used Client-side Apply (CSA) instead, which required the provider to compute + // the merge patch, and then send the patch to the server. This patch is computed as a three-way merge between: + // (1) the new inputs, (2) the computed state returned by the API server, and (3) the old inputs. This is the // main reason why the old state is an object with both the old inputs and the live version of the - // object. + // object. CSA is provided as a fallback option, but is generally less reliable than using SSA. // - // - // TREAD CAREFULLY. The semantics of a Kubernetes update are subtle, and you should proceed to - // change them only if you understand them deeply. - // - // Briefly: when a user updates an existing resource definition (e.g., by modifying YAML), the API - // server must decide how to apply the changes inside it, to the version of the resource that it - // has stored in etcd. In Kubernetes this decision is turns out to be quite complex. `kubectl` - // currently uses the three-way "strategic merge" and falls back to the three-way JSON merge. We - // currently support the second, but eventually we'll have to support the first, too. - // - // (NOTE: This comment is scoped to the question of how to patch an existing resource, rather than - // how to recognize when a resource needs to be re-created from scratch.) - // - // There are several reasons for this complexity: - // - // * It's important not to clobber fields set or default-set by the server (e.g., NodePort, - // namespace, service type, etc.), or by out-of-band tooling like admission controllers - // (which, e.g., might do something like add a sidecar to a container list). - // * For example, consider a scenario where a user renames a container. It is a reasonable - // expectation the old version of the container gets destroyed when the update is applied. And - // if the update strategy is set to three-way JSON merge patching, it is. - // * But, consider if their administrator has set up (say) the Istio admission controller, which - // embeds a sidecar container in pods submitted to the API. This container would not be present - // in the YAML file representing that pod, but when an update is applied by the user, they - // not want it to get destroyed. And, so, when the strategy is set to three-way strategic - // merge, the container is not destroyed. (With this strategy, fields can have "merge keys" as - // part of their schema, which tells the API server how to merge each particular field.) - // - // What's worse is, currently nearly all of this logic exists on the client rather than the - // server, though there is work moving forward to move this to the server. - // - // So the roadmap is: - // - // - [x] Implement `Update` using the three-way JSON merge strategy. - // - [x] Cause `Update` to default to the three-way JSON merge patch strategy. (This will require - // plumbing, because it expects nominal types representing the API schema, but the - // discovery client is completely dynamic.) - // - [x] Support server-side apply. - // - // In the next major release, we will default to using Server-side Apply, which will simplify this logic. - // urn := resource.URN(req.GetUrn()) label := fmt.Sprintf("%s.Update(%s)", k.label(), urn) logger.V(9).Infof("%s executing", label) @@ -2228,6 +2176,10 @@ func (k *kubeProvider) Update( return nil, pkgerrors.Wrapf(err, "update failed because malformed resource inputs") } newInputs := propMapToUnstructured(newResInputs) + newInputs, err = normalize(newInputs) + if err != nil { + return nil, err + } // If this is a preview and the input values contain unknowns, or an unregistered GVK, return them as-is. This is // compatible with prior behavior implemented by the Pulumi engine. @@ -2240,15 +2192,21 @@ func (k *kubeProvider) Update( return k.helmReleaseProvider.Update(ctx, req) } // Ignore old state; we'll get it from Kubernetes later. - oldInputs, _ := parseCheckpointObject(oldState) + oldInputs, oldLive := parseCheckpointObject(oldState) + + // Pre-4.0 versions of the provider used the last-applied-configuration annotation for client-side diffing. This + // annotation was automatically added to all resources by Pulumi. This annotation is no longer used, and needs to + // be removed from resources where it is present. To avoid causing a large update after upgrading to a 4.x release, + // only perform this operation during Update for resources that include other changes. This removal will not show + // up in the preview, which is symmetric with the previous creation behavior, which also does not show this + // annotation during preview. + removeLastAppliedConfigurationAnnotation(oldLive, oldInputs) - annotatedInputs, err := k.withLastAppliedConfig(newInputs) + oldInputs, err = normalize(oldInputs) if err != nil { - return nil, pkgerrors.Wrapf( - err, "Failed to update resource %s/%s because of an error generating the %s value in "+ - "`.metadata.annotations`", - newInputs.GetNamespace(), newInputs.GetName(), lastAppliedConfigKey) + return nil, err } + oldLivePruned := pruneLiveState(oldLive, oldInputs) initialAPIVersion := initialAPIVersion(oldState, oldInputs) fieldManagerOld := k.fieldManagerName(nil, oldState, oldInputs) @@ -2258,14 +2216,14 @@ func (k *kubeProvider) Update( if newResInputs.ContainsSecrets() { _ = k.host.LogStatus(ctx, diag.Warning, urn, fmt.Sprintf( "rendered file %s contains a secret value in plaintext", - renderPathForResource(annotatedInputs, k.yamlDirectory))) + renderPathForResource(newInputs, k.yamlDirectory))) } - err := renderYaml(annotatedInputs, k.yamlDirectory) + err := renderYaml(newInputs, k.yamlDirectory) if err != nil { return nil, err } - obj := checkpointObject(newInputs, annotatedInputs, newResInputs, initialAPIVersion, fieldManager) + obj := checkpointObject(newInputs, oldLive, newResInputs, initialAPIVersion, fieldManager) inputsAndComputed, err := plugin.MarshalProperties( obj, plugin.MarshalOptions{ Label: fmt.Sprintf("%s.inputsAndComputed", label), @@ -2278,7 +2236,7 @@ func (k *kubeProvider) Update( } _ = k.host.LogStatus(ctx, diag.Info, urn, fmt.Sprintf( - "rendered %s", renderPathForResource(annotatedInputs, k.yamlDirectory))) + "rendered %s", renderPathForResource(newInputs, k.yamlDirectory))) return &pulumirpc.UpdateResponse{Properties: inputsAndComputed}, nil } @@ -2299,8 +2257,8 @@ func (k *kubeProvider) Update( Resources: resources, ServerSideApply: k.serverSideApplyMode, }, - Previous: oldInputs, - Inputs: annotatedInputs, + Previous: oldLivePruned, + Inputs: newInputs, Timeout: req.Timeout, Preview: req.GetPreview(), } @@ -2590,121 +2548,6 @@ func (k *kubeProvider) readLiveObject(obj *unstructured.Unstructured) (*unstruct return rc.Get(k.canceler.context, obj.GetName(), metav1.GetOptions{}) } -func (k *kubeProvider) serverSidePatch(oldInputs, newInputs *unstructured.Unstructured, fieldManager string, -) ([]byte, map[string]any, error) { - - client, err := k.clientSet.ResourceClient(oldInputs.GroupVersionKind(), oldInputs.GetNamespace()) - if err != nil { - return nil, nil, err - } - - liveObject, err := client.Get(k.canceler.context, oldInputs.GetName(), metav1.GetOptions{}) - if err != nil { - return nil, nil, err - } - - // If the new resource does not exist, we need to dry-run a Create rather than a Patch. - var newObject *unstructured.Unstructured - _, err = client.Get(k.canceler.context, newInputs.GetName(), metav1.GetOptions{}) - switch { - case apierrors.IsNotFound(err): - newObject, err = client.Create(k.canceler.context, newInputs, metav1.CreateOptions{ - DryRun: []string{metav1.DryRunAll}, - }) - case newInputs.GetNamespace() != oldInputs.GetNamespace(): - client, err := k.clientSet.ResourceClient(newInputs.GroupVersionKind(), newInputs.GetNamespace()) - if err != nil { - return nil, nil, err - } - newObject, err = client.Create(k.canceler.context, newInputs, metav1.CreateOptions{ - DryRun: []string{metav1.DryRunAll}, - }) - if err != nil { - return nil, nil, err - } - case err == nil: - if k.serverSideApplyMode { - objYAML, err := yaml.Marshal(newInputs.Object) - if err != nil { - return nil, nil, err - } - - // Always force on diff to avoid erroneous conflict errors for resource replacements - force := true - if v := metadata.GetAnnotationValue(newInputs, metadata.AnnotationPatchFieldManager); len(v) > 0 { - fieldManager = v - } - - newObject, err = client.Patch( - k.canceler.context, newInputs.GetName(), types.ApplyPatchType, objYAML, metav1.PatchOptions{ - DryRun: []string{metav1.DryRunAll}, - FieldManager: fieldManager, - FieldValidation: metav1.FieldValidationWarn, - Force: &force, - }) - if err != nil { - return nil, nil, err - } - } else { - liveInputs := parseLiveInputs(liveObject, oldInputs) - - resources, err := k.getResources() - if err != nil { - return nil, nil, err - } - - patch, patchType, _, err := openapi.PatchForResourceUpdate(resources, liveInputs, newInputs, liveObject) - if err != nil { - return nil, nil, err - } - - newObject, err = client.Patch(k.canceler.context, newInputs.GetName(), patchType, patch, metav1.PatchOptions{ - DryRun: []string{metav1.DryRunAll}, - }) - if err != nil { - return nil, nil, err - } - } - - default: - return nil, nil, err - } - if err != nil { - return nil, nil, err - } - - if k.serverSideApplyMode { - objMetadata := newObject.Object["metadata"].(map[string]any) - if len(objMetadata) == 1 { - delete(newObject.Object, "metadata") - } else { - delete(newObject.Object["metadata"].(map[string]any), "managedFields") - } - objMetadata = liveObject.Object["metadata"].(map[string]any) - if len(objMetadata) == 1 { - delete(liveObject.Object, "metadata") - } else { - delete(liveObject.Object["metadata"].(map[string]any), "managedFields") - } - } - - liveJSON, err := liveObject.MarshalJSON() - if err != nil { - return nil, nil, err - } - newJSON, err := newObject.MarshalJSON() - if err != nil { - return nil, nil, err - } - - patch, err := jsonpatch.CreateMergePatch(liveJSON, newJSON) - if err != nil { - return nil, nil, err - } - - return patch, liveObject.Object, nil -} - // inputPatch calculates a patch on the client-side by comparing old inputs to the current inputs. func (k *kubeProvider) inputPatch( oldInputs, newInputs *unstructured.Unstructured, @@ -2733,101 +2576,6 @@ func (k *kubeProvider) isDryRunDisabledError(err error) bool { strings.Contains(se.Status().Message, "does not support dry run")) } -// tryServerSidePatch attempts to compute a server-side patch. Returns true iff the operation succeeded. -// The following are expected ways in which the server-side apply can not work; -// we return no error, but a `false` value indicating that there's no result either. -// The caller will fall back to using the client-side diff. In the particular case of an -// update to an immutable field, it is already known from the schema when -// replacement will be necessary. -func (k *kubeProvider) tryServerSidePatch( - oldInputs, newInputs *unstructured.Unstructured, - gvk schema.GroupVersionKind, - fieldManager string, -) (ssPatch []byte, ssPatchBase map[string]interface{}, ok bool, err error) { - // If the cluster is unreachable, compute patch using inputs. - if k.clusterUnreachable { - return nil, nil, false, nil - } - - // If the resource's GVK changed, so compute patch using inputs. - if oldInputs.GroupVersionKind().String() != gvk.String() { - return nil, nil, false, nil - } - // If the GVK is unregistered, compute the patch using inputs. - if !k.gvkExists(newInputs) { - return nil, nil, false, nil - } - // TODO: Skipping server-side diff for resources with computed values is a hack. We will want to address this - // more granularly so that previews are as accurate as possible, but this is an easy workaround for a critical - // bug. - if hasComputedValue(newInputs) || hasComputedValue(oldInputs) { - return nil, nil, false, nil - } - - ssPatch, ssPatchBase, err = k.serverSidePatch(oldInputs, newInputs, fieldManager) - if err == nil { - // The server-side patch succeeded. - return ssPatch, ssPatchBase, true, nil - } - - if apierrors.IsForbidden(err) { - // If the user doesn't have permission to run a Server-side preview, compute the patch using inputs - logger.V(1).Infof("unable to compute Server-side patch: %s", err) - return nil, nil, false, nil - } - if k.isDryRunDisabledError(err) { - return nil, nil, false, err - } - if se, isStatusError := err.(*apierrors.StatusError); isStatusError { - if se.Status().Code == http.StatusUnprocessableEntity && - strings.Contains(se.ErrStatus.Message, "field is immutable") { - // This error occurs if the resource field is immutable. - // Ignore this error since this case is handled by the replacement logic. - return nil, nil, false, nil - } - } - if err.Error() == "name is required" { - // If the name was removed in this update, then the resource will be replaced with an auto-named resource. - // Ignore this error since this case is handled by the replacement logic. - return nil, nil, false, nil - } - - return nil, nil, false, err -} - -func (k *kubeProvider) withLastAppliedConfig(config *unstructured.Unstructured) (*unstructured.Unstructured, error) { - if k.serverSideApplyMode { - // Skip last-applied-config annotation if the resource supports server-side apply. - return config, nil - } - - // CRDs are updated using a separate mechanism, so skip the last-applied-configuration annotation, and delete it - // if it was present from a previous update. - if clients.IsCRD(config) { - // Deep copy the config before returning. - config = config.DeepCopy() - - annotations := getAnnotations(config) - delete(annotations, lastAppliedConfigKey) - config.SetAnnotations(annotations) - return config, nil - } - - // Serialize the inputs and add the last-applied-configuration annotation. - marshaled, err := config.MarshalJSON() - if err != nil { - return nil, err - } - - // Deep copy the config before returning. - config = config.DeepCopy() - - annotations := getAnnotations(config) - annotations[lastAppliedConfigKey] = string(marshaled) - config.SetAnnotations(annotations) - return config, nil -} - // fieldManagerName returns the name to use for the Server-Side Apply fieldManager. The values are looked up with the // following precedence: // 1. Resource annotation (this will likely change to a typed option field in the next major release) @@ -2899,6 +2647,50 @@ func (k *kubeProvider) loadPulumiConfig() (map[string]any, bool) { return pConfig, true } +// removeLastAppliedConfigurationAnnotation is used by the Update method to remove an existing +// last-applied-configuration annotation from a resource. This annotation was set automatically by the provider, so it +// does not show up in the resource inputs. If the value is present in the live state, copy that value into the old +// inputs so that a negative diff will be generated for it. +func removeLastAppliedConfigurationAnnotation(oldLive, oldInputs *unstructured.Unstructured) { + oldLiveValue, existsInOldLive, _ := unstructured.NestedString(oldLive.Object, + "metadata", "annotations", lastAppliedConfigKey) + _, existsInOldInputs, _ := unstructured.NestedString(oldInputs.Object, + "metadata", "annotations", lastAppliedConfigKey) + + if existsInOldLive && !existsInOldInputs { + contract.IgnoreError(unstructured.SetNestedField( + oldInputs.Object, oldLiveValue, "metadata", "annotations", lastAppliedConfigKey)) + } +} + +// pruneLiveState prunes a live resource object to match the shape of the input object that created the resource. +func pruneLiveState(live, oldInputs *unstructured.Unstructured) *unstructured.Unstructured { + oldLivePruned := &unstructured.Unstructured{ + Object: pruneMap(live.Object, oldInputs.Object), + } + + return oldLivePruned +} + +// shouldNormalize returns false for CRDs and CustomResources, and true otherwise. +func shouldNormalize(uns *unstructured.Unstructured) bool { + return !clients.IsCRD(uns) && kinds.KnownGroupVersions.Has(uns.GetAPIVersion()) +} + +// normalize converts an Unstructured resource into a normalized form so that semantically equivalent representations +// are set to the same output shape. This is important to avoid generating diffs for inputs that will produce the same +// result on the cluster. +func normalize(uns *unstructured.Unstructured) (*unstructured.Unstructured, error) { + if shouldNormalize(uns) { + normalized, err := clients.Normalize(uns) + if err != nil { + return nil, err + } + uns = pruneLiveState(normalized, uns) + } + return uns, nil +} + func mapReplStripSecrets(v resource.PropertyValue) (any, bool) { if v.IsSecret() { return v.SecretValue().Element.MapRepl(nil, mapReplStripSecrets), true @@ -2934,15 +2726,6 @@ func propMapToUnstructured(pm resource.PropertyMap) *unstructured.Unstructured { return &unstructured.Unstructured{Object: pm.MapRepl(mapReplUnderscoreToDash, mapReplStripSecrets)} } -func getAnnotations(config *unstructured.Unstructured) map[string]string { - annotations := config.GetAnnotations() - if annotations == nil { - annotations = make(map[string]string) - } - - return annotations -} - // initialAPIVersion retrieves the initialAPIVersion property from the checkpoint file and falls back to using // the version from the resource metadata if that property is not present. func initialAPIVersion(state resource.PropertyMap, oldInputs *unstructured.Unstructured) string { @@ -2982,21 +2765,6 @@ func checkpointObject(inputs, live *unstructured.Unstructured, fromInputs resour } } - // Ensure that the annotation we add for lastAppliedConfig is treated as a secret if any of the inputs were secret - // (the value of this annotation is a string-ified JSON so marking the entire thing as a secret is really the best - // that we can do). - if fromInputs.ContainsSecrets() || isSecretKind { - if _, has := object["metadata"]; has && object["metadata"].IsObject() { - metadata := object["metadata"].ObjectValue() - if _, has := metadata["annotations"]; has && metadata["annotations"].IsObject() { - annotations := metadata["annotations"].ObjectValue() - if lastAppliedConfig, has := annotations[lastAppliedConfigKey]; has && !lastAppliedConfig.IsSecret() { - annotations[lastAppliedConfigKey] = resource.MakeSecret(lastAppliedConfig) - } - } - } - } - object["__inputs"] = resource.NewObjectProperty(inputsPM) object[initialAPIVersionKey] = resource.NewStringProperty(initialAPIVersion) object[fieldManagerKey] = resource.NewStringProperty(fieldManager) @@ -3064,54 +2832,6 @@ func canonicalNamespace(ns string) string { // deleteResponse causes the resource to be deleted from the state. var deleteResponse = &pulumirpc.ReadResponse{Id: "", Properties: nil} -// parseLastAppliedConfig attempts to find and parse an annotation that records the last applied configuration for the -// given live object state. -func parseLastAppliedConfig(live *unstructured.Unstructured) *unstructured.Unstructured { - // If `kubectl.kubernetes.io/last-applied-configuration` metadata annotation is present, parse it into a real object - // and use it as the current set of live inputs. Otherwise, return nil. - if live == nil { - return nil - } - - annotations := live.GetAnnotations() - if annotations == nil { - return nil - } - lastAppliedConfig, ok := annotations[lastAppliedConfigKey] - if !ok { - return nil - } - - liveInputs := &unstructured.Unstructured{} - if err := liveInputs.UnmarshalJSON([]byte(lastAppliedConfig)); err != nil { - return nil - } - return liveInputs -} - -// parseLiveInputs attempts to parse the provider inputs that produced the given live object out of the object's state. -// This is used by Read. -func parseLiveInputs(live, oldInputs *unstructured.Unstructured) *unstructured.Unstructured { - // First try to find and parse a `kubectl.kubernetes.io/last-applied-configuration` metadata anotation. If that - // succeeds, we are done. - if inputs := parseLastAppliedConfig(live); inputs != nil { - return inputs - } - - // If no such annotation was present--or if parsing failed--either retain the old inputs if they exist, or - // attempt to propagate the live object's GVK, any Pulumi-generated autoname and its annotation, and return - // the result. - if oldInputs != nil && len(oldInputs.Object) > 0 { - return oldInputs - } - - inputs := &unstructured.Unstructured{Object: map[string]any{}} - inputs.SetGroupVersionKind(live.GroupVersionKind()) - metadata.AdoptOldAutonameIfUnnamed(inputs, live) - - return inputs -} - // convertPatchToDiff converts the given JSON merge patch to a Pulumi detailed diff. func convertPatchToDiff( patch, oldLiveState, newInputs, oldInputs map[string]any, forceNewFields ...string, diff --git a/provider/pkg/provider/util.go b/provider/pkg/provider/util.go index b3986382e7..d50bafa81b 100644 --- a/provider/pkg/provider/util.go +++ b/provider/pkg/provider/util.go @@ -155,14 +155,10 @@ func pruneMap(source, target map[string]any) map[string]any { switch valueT.Kind() { case reflect.Map: nestedResult := pruneMap(value.(map[string]any), targetValue.(map[string]any)) - if len(nestedResult) > 0 { - result[key] = nestedResult - } + result[key] = nestedResult case reflect.Slice: nestedResult := pruneSlice(value.([]any), targetValue.([]any)) - if len(nestedResult) > 0 { - result[key] = nestedResult - } + result[key] = nestedResult default: result[key] = value } diff --git a/provider/pkg/provider/util_test.go b/provider/pkg/provider/util_test.go index d7802fa06a..c033341881 100644 --- a/provider/pkg/provider/util_test.go +++ b/provider/pkg/provider/util_test.go @@ -846,6 +846,24 @@ func TestPruneMap(t *testing.T) { }, }, }, + { + name: "nested empty map", + description: "a map with an empty nested map where target matches", + args: args{ + source: map[string]any{ + "a": "a", + "b": map[string]any{}, + }, + target: map[string]any{ + "a": "a", + "b": map[string]any{}, + }, + }, + want: map[string]any{ + "a": "a", + "b": map[string]any{}, + }, + }, { name: "nested value slice", description: "a map with a nested slice of simple values where target matches", @@ -896,6 +914,24 @@ func TestPruneMap(t *testing.T) { "b": []any{"c", "d"}, }, }, + { + name: "nested empty slice", + description: "a map with an empty nested slice of simple values where target matches", + args: args{ + source: map[string]any{ + "a": "a", + "b": []any{}, + }, + target: map[string]any{ + "a": "a", + "b": []any{}, + }, + }, + want: map[string]any{ + "a": "a", + "b": []any{}, + }, + }, { name: "nested map slice", description: "a map with a nested slice of map values where target matches", diff --git a/tests/go.mod b/tests/go.mod index 5983c5ebba..e0300b66b3 100644 --- a/tests/go.mod +++ b/tests/go.mod @@ -13,9 +13,9 @@ require ( github.com/pulumi/pulumi/pkg/v3 v3.74.0 github.com/pulumi/pulumi/sdk/v3 v3.74.0 github.com/stretchr/testify v1.8.3 - helm.sh/helm/v3 v3.11.3 - k8s.io/apimachinery v0.27.1 - k8s.io/client-go v0.27.1 + helm.sh/helm/v3 v3.12.0 + k8s.io/apimachinery v0.27.2 + k8s.io/client-go v0.27.2 ) require ( @@ -106,14 +106,16 @@ require ( github.com/emicklei/go-restful/v3 v3.10.1 // indirect github.com/emirpasic/gods v1.18.1 // indirect github.com/evanphx/json-patch v5.6.0+incompatible // indirect + github.com/evanphx/json-patch/v5 v5.6.0 // indirect github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d // indirect github.com/fatih/color v1.13.0 // indirect + github.com/fluxcd/pkg/ssa v0.28.1 // indirect github.com/go-errors/errors v1.4.2 // indirect github.com/go-git/gcfg v1.5.0 // indirect github.com/go-git/go-billy/v5 v5.4.0 // indirect github.com/go-git/go-git/v5 v5.6.0 // indirect github.com/go-gorp/gorp/v3 v3.0.5 // indirect - github.com/go-logr/logr v1.2.3 // indirect + github.com/go-logr/logr v1.2.4 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-openapi/jsonpointer v0.19.6 // indirect github.com/go-openapi/jsonreference v0.20.1 // indirect @@ -214,10 +216,10 @@ require ( github.com/pkg/errors v0.9.1 // indirect github.com/pkg/term v1.1.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/prometheus/client_golang v1.14.0 // indirect - github.com/prometheus/client_model v0.3.0 // indirect - github.com/prometheus/common v0.37.0 // indirect - github.com/prometheus/procfs v0.8.0 // indirect + github.com/prometheus/client_golang v1.15.1 // indirect + github.com/prometheus/client_model v0.4.0 // indirect + github.com/prometheus/common v0.42.0 // indirect + github.com/prometheus/procfs v0.9.0 // indirect github.com/pulumi/cloud-ready-checks v1.0.1-0.20230201174945-00fe9c1b68fd // indirect github.com/rivo/uniseg v0.4.4 // indirect github.com/rogpeppe/go-internal v1.10.0 // indirect @@ -254,14 +256,14 @@ require ( gocloud.dev/secrets/hashivault v0.27.0 // indirect golang.org/x/crypto v0.5.0 // indirect golang.org/x/mod v0.10.0 // indirect - golang.org/x/net v0.8.0 // indirect + golang.org/x/net v0.10.0 // indirect golang.org/x/oauth2 v0.6.0 // indirect - golang.org/x/sync v0.1.0 // indirect - golang.org/x/sys v0.6.0 // indirect - golang.org/x/term v0.6.0 // indirect + golang.org/x/sync v0.2.0 // indirect + golang.org/x/sys v0.8.0 // indirect + golang.org/x/term v0.8.0 // indirect golang.org/x/text v0.9.0 // indirect - golang.org/x/time v0.0.0-20220722155302-e5dcc9cfc0b9 // indirect - golang.org/x/tools v0.7.0 // indirect + golang.org/x/time v0.3.0 // indirect + golang.org/x/tools v0.9.1 // indirect golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect google.golang.org/api v0.110.0 // indirect google.golang.org/appengine v1.6.7 // indirect @@ -273,17 +275,19 @@ require ( gopkg.in/warnings.v0 v0.1.2 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - k8s.io/api v0.27.1 // indirect - k8s.io/apiextensions-apiserver v0.27.1 // indirect - k8s.io/apiserver v0.27.1 // indirect + k8s.io/api v0.27.2 // indirect + k8s.io/apiextensions-apiserver v0.27.2 // indirect + k8s.io/apiserver v0.27.2 // indirect k8s.io/cli-runtime v0.27.1 // indirect - k8s.io/component-base v0.27.1 // indirect + k8s.io/component-base v0.27.2 // indirect k8s.io/klog/v2 v2.90.1 // indirect - k8s.io/kube-openapi v0.0.0-20230308215209-15aac26d736a // indirect + k8s.io/kube-openapi v0.0.0-20230501164219-8b0f38b5fd1f // indirect k8s.io/kubectl v0.27.1 // indirect k8s.io/utils v0.0.0-20230220204549-a5ecb0141aa5 // indirect lukechampine.com/frand v1.4.2 // indirect oras.land/oras-go v1.2.2 // indirect + sigs.k8s.io/cli-utils v0.34.0 // indirect + sigs.k8s.io/controller-runtime v0.15.0 // indirect sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect sigs.k8s.io/kustomize/api v0.13.2 // indirect sigs.k8s.io/kustomize/kyaml v0.14.1 // indirect diff --git a/tests/go.sum b/tests/go.sum index 51c3470df7..ca93e07557 100644 --- a/tests/go.sum +++ b/tests/go.sum @@ -634,6 +634,8 @@ github.com/evanphx/json-patch v4.12.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQL github.com/evanphx/json-patch v5.6.0+incompatible h1:jBYDEEiFBPxA0v50tFdvOzQQTCvpL6mnFh5mB2/l16U= github.com/evanphx/json-patch v5.6.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch/v5 v5.5.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= +github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= +github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d h1:105gxyaGwCFad8crR9dcMQWvV9Hvulu6hwUh4tWPJnM= github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d/go.mod h1:ZZMPRZwes7CROmyNKgQzC3XPs6L/G2EJLHddWejkmf4= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= @@ -647,6 +649,8 @@ github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSw github.com/felixge/httpsnoop v1.0.2/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk= github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/fluxcd/pkg/ssa v0.28.1 h1:h5r5irAgDjgkmIqagOLOa/U7/Rx2fT2NKIb+vDTYOMg= +github.com/fluxcd/pkg/ssa v0.28.1/go.mod h1:o55eBzWz7P/tqnCn5c622RZvjTP/GqvitqZUbsMIRwk= github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= github.com/form3tech-oss/jwt-go v3.2.3+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= @@ -662,6 +666,7 @@ github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMo github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU= github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= +github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= github.com/fullsailor/pkcs7 v0.0.0-20190404230743-d7302db945fa/go.mod h1:KnogPXtdwXqoenmZCw6S+25EAm2MkxbG0deNDu4cbSA= github.com/garyburd/redigo v0.0.0-20150301180006-535138d7bcd7/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY= github.com/getkin/kin-openapi v0.76.0/go.mod h1:660oXbgy5JFMKreazJaQTw7o+X00qeSyhcnluiMv+Xg= @@ -708,11 +713,13 @@ github.com/go-logr/logr v0.4.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTg github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.1/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0= github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= +github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/stdr v1.2.0/go.mod h1:YkVgnZu1ZjjL7xTxrfm/LLZBfkhTqSR1ydtm6jTKKwI= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/go-logr/zapr v1.2.4 h1:QHVo+6stLbfJmYGkQ7uGHUCu5hnAFAj6mDe6Ea0SeOo= github.com/go-openapi/analysis v0.21.2/go.mod h1:HZwRk4RRisyG8vx2Oe6aqeSQcoxRp47Xkp3+K6q+LdY= github.com/go-openapi/errors v0.19.8/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M= github.com/go-openapi/errors v0.19.9/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M= @@ -758,8 +765,8 @@ github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfC github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-stack/stack v1.8.1/go.mod h1:dcoOX6HbPZSZptuspn9bctJ+N/CnF5gGygcUP3XYfe4= -github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= +github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= github.com/go-test/deep v1.0.2/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= github.com/go-test/deep v1.0.3 h1:ZrJSEWsXzPOxaZnFteGEfooLba+ju3FYIbOrS+rQd68= github.com/go-zookeeper/zk v1.0.2/go.mod h1:nOB03cncLtlp4t+UAkGSV+9beXP/akpekBwL+UX1Qcw= @@ -1440,7 +1447,7 @@ github.com/onsi/ginkgo v1.13.0/go.mod h1:+REjRxOmWfHCjfv9TTWB1jD1Frx4XydAD3zm1ls github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc= github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= -github.com/onsi/ginkgo/v2 v2.9.1 h1:zie5Ly042PD3bsCvsSOPvRnFwyo3rKe64TJlD6nu0mk= +github.com/onsi/ginkgo/v2 v2.9.5 h1:+6Hr4uxzP4XIUyAkg61dWBw8lb/gc4/X5luuxN/EC+Q= github.com/onsi/gomega v0.0.0-20151007035656-2152b45fa28a/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= @@ -1451,7 +1458,7 @@ github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoT github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.10.3/go.mod h1:V9xEwhxec5O8UDM77eCW8vLymOMltsqPVYWrpDsH8xc= github.com/onsi/gomega v1.15.0/go.mod h1:cIuvLEne0aoVhAgh/O6ac0Op8WWw9H6eYCriF+tEHG0= -github.com/onsi/gomega v1.27.4 h1:Z2AnStgsdSayCMDiCU42qIz+HLqEPcgiOCXjAU/w+8E= +github.com/onsi/gomega v1.27.7 h1:fVih9JD6ogIiHUN6ePK7HJidyEDpWGVB5mzM7cWNXoU= github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= github.com/opencontainers/go-digest v0.0.0-20170106003457-a6d0ee40d420/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= @@ -1552,8 +1559,8 @@ github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= github.com/prometheus/client_golang v1.12.2/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= -github.com/prometheus/client_golang v1.14.0 h1:nJdhIvne2eSX/XRAFV9PcvFFRbrjbcTUj0VP62TMhnw= -github.com/prometheus/client_golang v1.14.0/go.mod h1:8vpkKitgIVNcqrRBWh1C4TIUQgYNtG/XQE4E/Zae36Y= +github.com/prometheus/client_golang v1.15.1 h1:8tXpTmJbyH5lydzFPoxSIJ0J46jdh3tylbvM1xCv0LI= +github.com/prometheus/client_golang v1.15.1/go.mod h1:e9yaBhRPU2pPNsZwE+JdQl0KEt1N9XgF6zxWmaC0xOk= github.com/prometheus/client_model v0.0.0-20171117100541-99fa1f4be8e5/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= @@ -1561,8 +1568,8 @@ github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1: github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.1.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4= -github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= +github.com/prometheus/client_model v0.4.0 h1:5lQXD3cAg1OXBf4Wq03gTrXHeaV0TQvGfUooCfx1yqY= +github.com/prometheus/client_model v0.4.0/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU= github.com/prometheus/common v0.0.0-20180110214958-89604d197083/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= @@ -1577,8 +1584,9 @@ github.com/prometheus/common v0.29.0/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+ github.com/prometheus/common v0.30.0/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= github.com/prometheus/common v0.34.0/go.mod h1:gB3sOl7P0TvJabZpLY5uQMpUqRCPPCyRLCZYc7JZTNE= -github.com/prometheus/common v0.37.0 h1:ccBbHCgIiT9uSoFY0vX8H3zsNR5eLt17/RQLUvn8pXE= github.com/prometheus/common v0.37.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA= +github.com/prometheus/common v0.42.0 h1:EKsfXEYo4JpWMHH5cg+KOUWeuJSov1Id8zGR8eeI1YM= +github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr1yjz4b7Zbc= github.com/prometheus/common/assets v0.1.0/go.mod h1:D17UVUE12bHbim7HzwUvtqm6gwBEaDQ0F+hIGbFbccI= github.com/prometheus/common/assets v0.2.0/go.mod h1:D17UVUE12bHbim7HzwUvtqm6gwBEaDQ0F+hIGbFbccI= github.com/prometheus/common/sigv4 v0.1.0/go.mod h1:2Jkxxk9yYvCkE5G1sQT7GuEXm57JrvHu9k5YwTjsNtI= @@ -1596,8 +1604,8 @@ github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4O github.com/prometheus/procfs v0.2.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= -github.com/prometheus/procfs v0.8.0 h1:ODq8ZFEaYeCaZOJlZZdJA2AbQR98dSHSM1KW/You5mo= -github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4= +github.com/prometheus/procfs v0.9.0 h1:wzCHvIvM5SxWqYvwgVL7yJY8Lz3PKn49KQtpgMYJfhI= +github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB/chUwxUZY= github.com/prometheus/prometheus v0.35.0/go.mod h1:7HaLx5kEPKJ0GDgbODG0fZgXbQ8K/XjZNJXQmbmgQlY= github.com/prometheus/prometheus v0.37.0/go.mod h1:egARUgz+K93zwqsVIAneFlLZefyGOON44WyAp4Xqbbk= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= @@ -1904,6 +1912,7 @@ go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/ go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= +go.uber.org/multierr v1.8.0 h1:dg6GjLku4EH+249NNmoIciG9N/jURbDG+pFlTkhzIC8= go.uber.org/multierr v1.8.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak= go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= @@ -1911,6 +1920,7 @@ go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw= +go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60= gocloud.dev v0.27.0 h1:j0WTUsnKTxCsWO7y8T+YCiBZUmLl9w/WIowqAY3yo0g= gocloud.dev v0.27.0/go.mod h1:YlYKhYsY5/1JdHGWQDkAuqkezVKowu7qbe9aIeUF6p0= gocloud.dev/secrets/hashivault v0.27.0 h1:AAeGJXr0tiHHJgg5tL8atOGktB4eK9EJAqkZbPKAcOo= @@ -2085,8 +2095,8 @@ golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b/go.mod h1:YDH+HFinaLZZlnHAfS golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws= -golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= -golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M= +golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -2129,8 +2139,8 @@ golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= -golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.2.0 h1:PUR+T4wwASmuSTYdKjYHI5TD22Wy5ogLU5qZCOLxBrI= +golang.org/x/sync v0.2.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -2282,8 +2292,8 @@ golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= -golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= @@ -2293,8 +2303,8 @@ golang.org/x/term v0.0.0-20220722155259-a9ba230a4035/go.mod h1:jbD1KX2456YbFQfuX golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ= -golang.org/x/term v0.6.0 h1:clScbb1cHjoCkyRbWwBEUZ5H/tIFu5TAXIqaZD0Gcjw= -golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= +golang.org/x/term v0.8.0 h1:n5xxQn2i3PC0yLAbjTpNT85q/Kgzcr2gIoX9OrJUols= +golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -2319,8 +2329,9 @@ golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxb golang.org/x/time v0.0.0-20220210224613-90d013bbcef8/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20220224211638-0e9765cccd65/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20220609170525-579cf78fd858/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20220722155302-e5dcc9cfc0b9 h1:ftMN5LMiBFjbzleLqtoBZk7KdJwhuybIU+FckUHgoyQ= golang.org/x/time v0.0.0-20220722155302-e5dcc9cfc0b9/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= +golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -2407,8 +2418,8 @@ golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E golang.org/x/tools v0.1.11/go.mod h1:SgwaegtQh8clINPpECJMqnxLv9I09HLqnW3RMqW0CA4= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA= -golang.org/x/tools v0.7.0 h1:W4OVu8VVOaIO0yzWMNdepAulS7YfoS3Zabrm8DOXXU4= -golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s= +golang.org/x/tools v0.9.1 h1:8WMNJAz3zrtPmnYC7ISf5dEn3MT0gY7jBJfw27yrrLo= +golang.org/x/tools v0.9.1/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc= golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -2420,6 +2431,7 @@ golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNq golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk= golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= +gomodules.xyz/jsonpatch/v2 v2.3.0 h1:8NFhfS6gzxNqjLIYnZxg319wZ5Qjnx4m/CcX+Klzazc= google.golang.org/api v0.0.0-20160322025152-9bf6e6e569ff/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= @@ -2714,10 +2726,10 @@ k8s.io/api v0.20.6/go.mod h1:X9e8Qag6JV/bL5G6bU8sdVRltWKmdHsFUGS3eVndqE8= k8s.io/api v0.22.5/go.mod h1:mEhXyLaSD1qTOf40rRiKXkc+2iCem09rWLlFwhCEiAs= k8s.io/api v0.23.5/go.mod h1:Na4XuKng8PXJ2JsploYYrivXrINeTaycCGcYgF91Xm8= k8s.io/api v0.24.2/go.mod h1:AHqbSkTm6YrQ0ObxjO3Pmp/ubFF/KuM7jU+3khoBsOg= -k8s.io/api v0.27.1 h1:Z6zUGQ1Vd10tJ+gHcNNNgkV5emCyW+v2XTmn+CLjSd0= -k8s.io/api v0.27.1/go.mod h1:z5g/BpAiD+f6AArpqNjkY+cji8ueZDU/WV1jcj5Jk4E= -k8s.io/apiextensions-apiserver v0.27.1 h1:Hp7B3KxKHBZ/FxmVFVpaDiXI6CCSr49P1OJjxKO6o4g= -k8s.io/apiextensions-apiserver v0.27.1/go.mod h1:8jEvRDtKjVtWmdkhOqE84EcNWJt/uwF8PC4627UZghY= +k8s.io/api v0.27.2 h1:+H17AJpUMvl+clT+BPnKf0E3ksMAzoBBg7CntpSuADo= +k8s.io/api v0.27.2/go.mod h1:ENmbocXfBT2ADujUXcBhHV55RIT31IIEvkntP6vZKS4= +k8s.io/apiextensions-apiserver v0.27.2 h1:iwhyoeS4xj9Y7v8YExhUwbVuBhMr3Q4bd/laClBV6Bo= +k8s.io/apiextensions-apiserver v0.27.2/go.mod h1:Oz9UdvGguL3ULgRdY9QMUzL2RZImotgxvGjdWRq6ZXQ= k8s.io/apimachinery v0.20.1/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRpU= k8s.io/apimachinery v0.20.4/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRpU= k8s.io/apimachinery v0.20.6/go.mod h1:ejZXtW1Ra6V1O5H8xPBGz+T3+4gfkTCeExAHKU57MAc= @@ -2725,14 +2737,14 @@ k8s.io/apimachinery v0.22.1/go.mod h1:O3oNtNadZdeOMxHFVxOreoznohCpy0z6mocxbZr7oJ k8s.io/apimachinery v0.22.5/go.mod h1:xziclGKwuuJ2RM5/rSFQSYAj0zdbci3DH8kj+WvyN0U= k8s.io/apimachinery v0.23.5/go.mod h1:BEuFMMBaIbcOqVIJqNZJXGFTP4W6AycEpb5+m/97hrM= k8s.io/apimachinery v0.24.2/go.mod h1:82Bi4sCzVBdpYjyI4jY6aHX+YCUchUIrZrXKedjd2UM= -k8s.io/apimachinery v0.27.1 h1:EGuZiLI95UQQcClhanryclaQE6xjg1Bts6/L3cD7zyc= -k8s.io/apimachinery v0.27.1/go.mod h1:5ikh59fK3AJ287GUvpUsryoMFtH9zj/ARfWCo3AyXTM= +k8s.io/apimachinery v0.27.2 h1:vBjGaKKieaIreI+oQwELalVG4d8f3YAMNpWLzDXkxeg= +k8s.io/apimachinery v0.27.2/go.mod h1:XNfZ6xklnMCOGGFNqXG7bUrQCoR04dh/E7FprV6pb+E= k8s.io/apiserver v0.20.1/go.mod h1:ro5QHeQkgMS7ZGpvf4tSMx6bBOgPfE+f52KwvXfScaU= k8s.io/apiserver v0.20.4/go.mod h1:Mc80thBKOyy7tbvFtB4kJv1kbdD0eIH8k8vianJcbFM= k8s.io/apiserver v0.20.6/go.mod h1:QIJXNt6i6JB+0YQRNcS0hdRHJlMhflFmsBDeSgT1r8Q= k8s.io/apiserver v0.22.5/go.mod h1:s2WbtgZAkTKt679sYtSudEQrTGWUSQAPe6MupLnlmaQ= -k8s.io/apiserver v0.27.1 h1:phY+BtXjjzd+ta3a4kYbomC81azQSLa1K8jo9RBw7Lg= -k8s.io/apiserver v0.27.1/go.mod h1:UGrOjLY2KsieA9Fw6lLiTObxTb8Z1xEba4uqSuMY0WU= +k8s.io/apiserver v0.27.2 h1:p+tjwrcQEZDrEorCZV2/qE8osGTINPuS5ZNqWAvKm5E= +k8s.io/apiserver v0.27.2/go.mod h1:EsOf39d75rMivgvvwjJ3OW/u9n1/BmUMK5otEOJrb1Y= k8s.io/cli-runtime v0.27.1 h1:MMzp5Q/Xmr5L1Lrowuc+Y/r95XINC6c6/fE3aN7JDRM= k8s.io/cli-runtime v0.27.1/go.mod h1:tEbTB1XP/nTH3wujsi52bw91gWpErtWiS15R6CwYsAI= k8s.io/client-go v0.20.1/go.mod h1:/zcHdt1TeWSd5HoUe6elJmHSQ6uLLgp4bIJHVEuy+/Y= @@ -2741,15 +2753,15 @@ k8s.io/client-go v0.20.6/go.mod h1:nNQMnOvEUEsOzRRFIIkdmYOjAZrC8bgq0ExboWSU1I0= k8s.io/client-go v0.22.5/go.mod h1:cs6yf/61q2T1SdQL5Rdcjg9J1ElXSwbjSrW2vFImM4Y= k8s.io/client-go v0.23.5/go.mod h1:flkeinTO1CirYgzMPRWxUCnV0G4Fbu2vLhYCObnt/r4= k8s.io/client-go v0.24.2/go.mod h1:zg4Xaoo+umDsfCWr4fCnmLEtQXyCNXCvJuSsglNcV30= -k8s.io/client-go v0.27.1 h1:oXsfhW/qncM1wDmWBIuDzRHNS2tLhK3BZv512Nc59W8= -k8s.io/client-go v0.27.1/go.mod h1:f8LHMUkVb3b9N8bWturc+EDtVVVwZ7ueTVquFAJb2vA= +k8s.io/client-go v0.27.2 h1:vDLSeuYvCHKeoQRhCXjxXO45nHVv2Ip4Fe0MfioMrhE= +k8s.io/client-go v0.27.2/go.mod h1:tY0gVmUsHrAmjzHX9zs7eCjxcBsf8IiNe7KQ52biTcQ= k8s.io/code-generator v0.19.7/go.mod h1:lwEq3YnLYb/7uVXLorOJfxg+cUu2oihFhHZ0n9NIla0= k8s.io/component-base v0.20.1/go.mod h1:guxkoJnNoh8LNrbtiQOlyp2Y2XFCZQmrcg2n/DeYNLk= k8s.io/component-base v0.20.4/go.mod h1:t4p9EdiagbVCJKrQ1RsA5/V4rFQNDfRlevJajlGwgjI= k8s.io/component-base v0.20.6/go.mod h1:6f1MPBAeI+mvuts3sIdtpjljHWBQ2cIy38oBIWMYnrM= k8s.io/component-base v0.22.5/go.mod h1:VK3I+TjuF9eaa+Ln67dKxhGar5ynVbwnGrUiNF4MqCI= -k8s.io/component-base v0.27.1 h1:kEB8p8lzi4gCs5f2SPU242vOumHJ6EOsOnDM3tTuDTM= -k8s.io/component-base v0.27.1/go.mod h1:UGEd8+gxE4YWoigz5/lb3af3Q24w98pDseXcXZjw+E0= +k8s.io/component-base v0.27.2 h1:neju+7s/r5O4x4/txeUONNTS9r1HsPbyoPBAtHsDCpo= +k8s.io/component-base v0.27.2/go.mod h1:5UPk7EjfgrfgRIuDBFtsEFAe4DAvP3U+M8RTzoSJkpo= k8s.io/cri-api v0.17.3/go.mod h1:X1sbHmuXhwaHs9xxYffLqJogVsnI+f6cPRcgPel7ywM= k8s.io/cri-api v0.20.1/go.mod h1:2JRbKt+BFLTjtrILYVqQK5jqhI+XNdF6UiGMgczeBCI= k8s.io/cri-api v0.20.4/go.mod h1:2JRbKt+BFLTjtrILYVqQK5jqhI+XNdF6UiGMgczeBCI= @@ -2776,8 +2788,8 @@ k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e/go.mod h1:vHXdDvt9+2spS2R k8s.io/kube-openapi v0.0.0-20211109043538-20434351676c/go.mod h1:vHXdDvt9+2spS2Rx9ql3I8tycm3H9FDfdUoIuKCefvw= k8s.io/kube-openapi v0.0.0-20211115234752-e816edb12b65/go.mod h1:sX9MT8g7NVZM5lVL/j8QyCCJe8YSMW30QvGZWaCIDIk= k8s.io/kube-openapi v0.0.0-20220328201542-3ee0da9b0b42/go.mod h1:Z/45zLw8lUo4wdiUkI+v/ImEGAvu3WatcZl3lPMR4Rk= -k8s.io/kube-openapi v0.0.0-20230308215209-15aac26d736a h1:gmovKNur38vgoWfGtP5QOGNOA7ki4n6qNYoFAgMlNvg= -k8s.io/kube-openapi v0.0.0-20230308215209-15aac26d736a/go.mod h1:y5VtZWM9sHHc2ZodIH/6SHzXj+TPU5USoA8lcIeKEKY= +k8s.io/kube-openapi v0.0.0-20230501164219-8b0f38b5fd1f h1:2kWPakN3i/k81b0gvD5C5FJ2kxm1WrQFanWchyKuqGg= +k8s.io/kube-openapi v0.0.0-20230501164219-8b0f38b5fd1f/go.mod h1:byini6yhqGC14c3ebc/QwanvYwhuMWF6yz2F8uwW8eg= k8s.io/kubectl v0.27.1 h1:9T5c5KdpburYiW8XKQSH0Uly1kMNE90aGSnbYUZNdcA= k8s.io/kubectl v0.27.1/go.mod h1:QsAkSmrRsKTPlAFzF8kODGDl4p35BIwQnc9XFhkcsy8= k8s.io/kubernetes v1.13.0/go.mod h1:ocZa8+6APFNC2tX1DZASIbocyYT5jHzqFVsY5aoB7Jk= @@ -2802,6 +2814,10 @@ rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.14/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.15/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.22/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg= +sigs.k8s.io/cli-utils v0.34.0 h1:zCUitt54f0/MYj/ajVFnG6XSXMhpZ72O/3RewIchW8w= +sigs.k8s.io/cli-utils v0.34.0/go.mod h1:EXyMwPMu9OL+LRnj0JEMsGG/fRvbgFadcVlSnE8RhFs= +sigs.k8s.io/controller-runtime v0.15.0 h1:ML+5Adt3qZnMSYxZ7gAverBLNPSMQEibtzAgp0UPojU= +sigs.k8s.io/controller-runtime v0.15.0/go.mod h1:7ngYvp1MLT+9GeZ+6lH3LOlcHkp/+tzA/fmHa4iq9kk= sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6/go.mod h1:p4QtZmO4uMYipTQNzagwnNoseA6OxSUutVw05NhYDRs= sigs.k8s.io/json v0.0.0-20211208200746-9f7c6b3444d2/go.mod h1:B+TnT182UBxE84DiCz4CVE26eOSDAeYCpfDnC2kdKMY= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= diff --git a/tests/sdk/dotnet/dotnet_test.go b/tests/sdk/dotnet/dotnet_test.go index b4be8a16cf..871dc04750 100644 --- a/tests/sdk/dotnet/dotnet_test.go +++ b/tests/sdk/dotnet/dotnet_test.go @@ -96,8 +96,9 @@ func TestDotnet_YamlLocal(t *testing.T) { func TestDotnet_Helm(t *testing.T) { test := baseOptions.With(integration.ProgramTestOptions{ - Dir: filepath.Join("helm", "step1"), - Quick: true, + Dir: filepath.Join("helm", "step1"), + Quick: true, + ExpectRefreshChanges: true, ExtraRuntimeValidation: func(t *testing.T, stackInfo integration.RuntimeValidationStackInfo) { // Ensure that all `Services` have `status` marked as a `Secret` for _, res := range stackInfo.Deployment.Resources { @@ -118,8 +119,9 @@ func TestDotnet_Helm(t *testing.T) { func TestDotnet_HelmLocal(t *testing.T) { test := baseOptions.With(integration.ProgramTestOptions{ - Dir: filepath.Join("helm-local", "step1"), - Quick: true, + Dir: filepath.Join("helm-local", "step1"), + Quick: true, + ExpectRefreshChanges: true, ExtraRuntimeValidation: func(t *testing.T, stackInfo integration.RuntimeValidationStackInfo) { assert.NotNil(t, stackInfo.Deployment) assert.Equal(t, 12, len(stackInfo.Deployment.Resources)) @@ -151,21 +153,15 @@ func TestDotnet_HelmLocal(t *testing.T) { } } }, - EditDirs: []integration.EditDir{ - { - Dir: filepath.Join("helm-local", "step2"), - Additive: true, - ExpectNoChanges: true, - }, - }, }) integration.ProgramTest(t, &test) } func TestDotnet_HelmApiVersions(t *testing.T) { test := baseOptions.With(integration.ProgramTestOptions{ - Dir: filepath.Join("helm-api-versions", "step1"), - Quick: true, + Dir: filepath.Join("helm-api-versions", "step1"), + Quick: true, + ExpectRefreshChanges: true, OrderedConfig: []integration.ConfigValue{ { Key: "pulumi:disable-default-providers[0]", @@ -183,9 +179,10 @@ func TestDotnet_HelmApiVersions(t *testing.T) { func TestDotnet_HelmAllowCRDRendering(t *testing.T) { test := baseOptions.With(integration.ProgramTestOptions{ - Dir: filepath.Join("helm-skip-crd-rendering", "step1"), - Quick: true, - SkipRefresh: true, + Dir: filepath.Join("helm-skip-crd-rendering", "step1"), + Quick: true, + SkipRefresh: true, + ExpectRefreshChanges: true, ExtraRuntimeValidation: func(t *testing.T, stackInfo integration.RuntimeValidationStackInfo) { assert.NotNil(t, stackInfo.Deployment) assert.Equal(t, 8, len(stackInfo.Deployment.Resources)) diff --git a/tests/sdk/go/go_test.go b/tests/sdk/go/go_test.go index fa27caab3e..62d9dc894f 100644 --- a/tests/sdk/go/go_test.go +++ b/tests/sdk/go/go_test.go @@ -76,8 +76,9 @@ func TestGo(t *testing.T) { t.Run("Helm Local", func(t *testing.T) { options := baseOptions.With(integration.ProgramTestOptions{ - Dir: filepath.Join(cwd, "helm-local", "step1"), - Quick: true, + Dir: filepath.Join(cwd, "helm-local", "step1"), + Quick: true, + ExpectRefreshChanges: true, ExtraRuntimeValidation: func(t *testing.T, stackInfo integration.RuntimeValidationStackInfo) { // Verify resource creation order using the Event stream. The Chart resources must be created // first, followed by the dependent ConfigMap. (The ConfigMap doesn't actually need the Chart, but @@ -122,6 +123,7 @@ func TestGo(t *testing.T) { Config: map[string]string{ "namespace": namespace, }, + ExpectRefreshChanges: true, ExtraRuntimeValidation: func(t *testing.T, stack integration.RuntimeValidationStackInfo) { assert.NotEmpty(t, stack.Outputs["svc_ip"]) }, @@ -142,32 +144,36 @@ func TestGo(t *testing.T) { Config: map[string]string{ "namespace": namespace, }, - NoParallel: true, - Verbose: true, + ExpectRefreshChanges: true, + NoParallel: true, + Verbose: true, }) integration.ProgramTest(t, &options) }) t.Run("Helm Remote", func(t *testing.T) { options := baseOptions.With(integration.ProgramTestOptions{ - Dir: filepath.Join(cwd, "helm", "step1"), - Quick: true, + Dir: filepath.Join(cwd, "helm", "step1"), + Quick: true, + ExpectRefreshChanges: true, }) integration.ProgramTest(t, &options) }) t.Run("Helm Release", func(t *testing.T) { options := baseOptions.With(integration.ProgramTestOptions{ - Dir: filepath.Join(cwd, "helm-release", "step1"), - Quick: true, + Dir: filepath.Join(cwd, "helm-release", "step1"), + Quick: true, + ExpectRefreshChanges: true, }) integration.ProgramTest(t, &options) }) t.Run("Helm Release With Empty Local Folder", func(t *testing.T) { options := baseOptions.With(integration.ProgramTestOptions{ - Dir: filepath.Join(cwd, "helm-release", "step1"), - Quick: true, + Dir: filepath.Join(cwd, "helm-release", "step1"), + Quick: true, + ExpectRefreshChanges: true, PrePulumiCommand: func(verb string) (func(err error) error, error) { // Create an empty folder to test that the Helm provider doesn't fail when the folder is empty, and we should // be fetching from remote. @@ -183,16 +189,18 @@ func TestGo(t *testing.T) { t.Run("Helm Release Local", func(t *testing.T) { options := baseOptions.With(integration.ProgramTestOptions{ - Dir: filepath.Join(cwd, "helm-release-local", "step1"), - Quick: true, + Dir: filepath.Join(cwd, "helm-release-local", "step1"), + Quick: true, + ExpectRefreshChanges: true, }) integration.ProgramTest(t, &options) }) t.Run("Helm Release Local Compressed", func(t *testing.T) { options := baseOptions.With(integration.ProgramTestOptions{ - Dir: filepath.Join(cwd, "helm-release-local-tar", "step1"), - Quick: true, + Dir: filepath.Join(cwd, "helm-release-local-tar", "step1"), + Quick: true, + ExpectRefreshChanges: true, }) integration.ProgramTest(t, &options) }) @@ -236,8 +244,9 @@ func TestGo(t *testing.T) { t.Run("Helm API Versions", func(t *testing.T) { options := baseOptions.With(integration.ProgramTestOptions{ - Dir: filepath.Join(cwd, "helm-api-versions", "step1"), - Quick: true, + Dir: filepath.Join(cwd, "helm-api-versions", "step1"), + Quick: true, + ExpectRefreshChanges: true, }) integration.ProgramTest(t, &options) }) diff --git a/tests/sdk/nodejs/drift-correct/configmap-csa/Pulumi.yaml b/tests/sdk/nodejs/drift-correct/configmap-csa/Pulumi.yaml new file mode 100644 index 0000000000..8ce897523d --- /dev/null +++ b/tests/sdk/nodejs/drift-correct/configmap-csa/Pulumi.yaml @@ -0,0 +1,3 @@ +name: drift-correct-tests +description: Tests handling of drift correction with refresh an reapply +runtime: nodejs diff --git a/tests/sdk/nodejs/drift-correct/configmap-csa/index.ts b/tests/sdk/nodejs/drift-correct/configmap-csa/index.ts new file mode 100644 index 0000000000..903b2d24ae --- /dev/null +++ b/tests/sdk/nodejs/drift-correct/configmap-csa/index.ts @@ -0,0 +1,39 @@ +// Copyright 2016-2022, Pulumi Corporation. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import * as k8s from "@pulumi/kubernetes"; + +// This test creates a Provider with `enableServerSideApply` disabled. The following scenarios are tested: +// 1. Create a Namespace and ConfigMap with pulumi. +// 2. Externally delete labels in the ConfigMap using kubectl. +// 3. Rerun the pulumi program and verify that the labels are restored. + +// Create provider with CSA enabled. +const provider = new k8s.Provider("k8s", { + enableServerSideApply: false, + enableConfigMapMutable: true, // Reuse the same ConfigMap rather than replacing on change. +}); + +// Create a randomly-named Namespace. +const ns = new k8s.core.v1.Namespace("test", undefined, {provider}); + +export const cm = new k8s.core.v1.ConfigMap("test", { + metadata: { + namespace: ns.metadata.name, + annotations: { + "pulumi.com/patchForce": "true", + }, + }, + data: {foo: "bar"}, +}, {provider}); diff --git a/tests/sdk/nodejs/drift-correct/configmap-csa/package.json b/tests/sdk/nodejs/drift-correct/configmap-csa/package.json new file mode 100644 index 0000000000..8cd8d8e38e --- /dev/null +++ b/tests/sdk/nodejs/drift-correct/configmap-csa/package.json @@ -0,0 +1,11 @@ +{ + "name": "drift-correct", + "version": "0.1.0", + "dependencies": { + "@pulumi/pulumi": "latest", + "@pulumi/random": "latest" + }, + "peerDependencies": { + "@pulumi/kubernetes": "latest" + } +} diff --git a/tests/sdk/nodejs/drift-correct/configmap-csa/tsconfig.json b/tests/sdk/nodejs/drift-correct/configmap-csa/tsconfig.json new file mode 100644 index 0000000000..5dacccbd42 --- /dev/null +++ b/tests/sdk/nodejs/drift-correct/configmap-csa/tsconfig.json @@ -0,0 +1,22 @@ +{ + "compilerOptions": { + "outDir": "bin", + "target": "es6", + "module": "commonjs", + "moduleResolution": "node", + "declaration": true, + "sourceMap": true, + "stripInternal": true, + "experimentalDecorators": true, + "pretty": true, + "noFallthroughCasesInSwitch": true, + "noImplicitAny": true, + "noImplicitReturns": true, + "forceConsistentCasingInFileNames": true, + "strictNullChecks": true + }, + "files": [ + "index.ts" + ] +} + diff --git a/tests/sdk/nodejs/drift-correct/configmap-ssa/Pulumi.yaml b/tests/sdk/nodejs/drift-correct/configmap-ssa/Pulumi.yaml new file mode 100644 index 0000000000..8ce897523d --- /dev/null +++ b/tests/sdk/nodejs/drift-correct/configmap-ssa/Pulumi.yaml @@ -0,0 +1,3 @@ +name: drift-correct-tests +description: Tests handling of drift correction with refresh an reapply +runtime: nodejs diff --git a/tests/sdk/nodejs/drift-correct/configmap-ssa/index.ts b/tests/sdk/nodejs/drift-correct/configmap-ssa/index.ts new file mode 100644 index 0000000000..8fb7d2934a --- /dev/null +++ b/tests/sdk/nodejs/drift-correct/configmap-ssa/index.ts @@ -0,0 +1,39 @@ +// Copyright 2016-2022, Pulumi Corporation. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import * as k8s from "@pulumi/kubernetes"; + +// This test creates a Provider with `enableServerSideApply` enabled. The following scenarios are tested: +// 1. Create a Namespace and ConfigMap with pulumi. +// 2. Externally delete labels in the ConfigMap using kubectl. +// 3. Rerun the pulumi program and verify that the labels are restored. + +// Create provider with SSA enabled. +const provider = new k8s.Provider("k8s", { + enableServerSideApply: false, + enableConfigMapMutable: true, // Reuse the same ConfigMap rather than replacing on change. +}); + +// Create a randomly-named Namespace. +const ns = new k8s.core.v1.Namespace("test", undefined, {provider}); + +export const cm = new k8s.core.v1.ConfigMap("test", { + metadata: { + namespace: ns.metadata.name, + annotations: { + "pulumi.com/patchForce": "true", + }, + }, + data: {foo: "bar"}, +}, {provider}); diff --git a/tests/sdk/nodejs/drift-correct/configmap-ssa/package.json b/tests/sdk/nodejs/drift-correct/configmap-ssa/package.json new file mode 100644 index 0000000000..8cd8d8e38e --- /dev/null +++ b/tests/sdk/nodejs/drift-correct/configmap-ssa/package.json @@ -0,0 +1,11 @@ +{ + "name": "drift-correct", + "version": "0.1.0", + "dependencies": { + "@pulumi/pulumi": "latest", + "@pulumi/random": "latest" + }, + "peerDependencies": { + "@pulumi/kubernetes": "latest" + } +} diff --git a/tests/sdk/nodejs/drift-correct/configmap-ssa/tsconfig.json b/tests/sdk/nodejs/drift-correct/configmap-ssa/tsconfig.json new file mode 100644 index 0000000000..5dacccbd42 --- /dev/null +++ b/tests/sdk/nodejs/drift-correct/configmap-ssa/tsconfig.json @@ -0,0 +1,22 @@ +{ + "compilerOptions": { + "outDir": "bin", + "target": "es6", + "module": "commonjs", + "moduleResolution": "node", + "declaration": true, + "sourceMap": true, + "stripInternal": true, + "experimentalDecorators": true, + "pretty": true, + "noFallthroughCasesInSwitch": true, + "noImplicitAny": true, + "noImplicitReturns": true, + "forceConsistentCasingInFileNames": true, + "strictNullChecks": true + }, + "files": [ + "index.ts" + ] +} + diff --git a/tests/sdk/nodejs/examples/examples_test.go b/tests/sdk/nodejs/examples/examples_test.go index 7cd541bf96..fca339b533 100644 --- a/tests/sdk/nodejs/examples/examples_test.go +++ b/tests/sdk/nodejs/examples/examples_test.go @@ -45,7 +45,8 @@ func TestAccGuestbook(t *testing.T) { skipIfShort(t) test := getBaseOptions(t). With(integration.ProgramTestOptions{ - Dir: filepath.Join(getCwd(t), "guestbook"), + Dir: filepath.Join(getCwd(t), "guestbook"), + ExpectRefreshChanges: true, ExtraRuntimeValidation: func( t *testing.T, stackInfo integration.RuntimeValidationStackInfo, ) { @@ -386,6 +387,7 @@ func TestHelmRelease(t *testing.T) { SkipRefresh: false, Verbose: true, ExtraRuntimeValidation: validationFunc, + ExpectRefreshChanges: true, EditDirs: []integration.EditDir{ { Dir: filepath.Join(getCwd(t), "helm-release", "step2"), @@ -404,9 +406,10 @@ func TestHelmReleaseCRD(t *testing.T) { skipIfShort(t) test := getBaseOptions(t). With(integration.ProgramTestOptions{ - Dir: filepath.Join(getCwd(t), "helm-release-crd", "step1"), - SkipRefresh: false, - Verbose: true, + Dir: filepath.Join(getCwd(t), "helm-release-crd", "step1"), + SkipRefresh: false, + ExpectRefreshChanges: true, + Verbose: true, EditDirs: []integration.EditDir{ { Dir: filepath.Join(getCwd(t), "helm-release-crd", "step2"), @@ -423,9 +426,10 @@ func TestHelmReleaseNamespace(t *testing.T) { skipIfShort(t) test := getBaseOptions(t). With(integration.ProgramTestOptions{ - Dir: filepath.Join(getCwd(t), "helm-release-namespace"), - SkipRefresh: false, - Verbose: true, + Dir: filepath.Join(getCwd(t), "helm-release-namespace"), + SkipRefresh: false, + Verbose: true, + ExpectRefreshChanges: true, // Ensure that the rule was found in the release's namespace. ExtraRuntimeValidation: func(t *testing.T, stackInfo integration.RuntimeValidationStackInfo) { assert.NotEmpty(t, stackInfo.Outputs["alertManagerNamespace"].(string)) @@ -466,10 +470,11 @@ func TestHelmReleaseRedis(t *testing.T) { skipIfShort(t) test := getBaseOptions(t). With(integration.ProgramTestOptions{ - Dir: filepath.Join(getCwd(t), "helm-release-redis", "step1"), - SkipRefresh: false, - Verbose: true, - Quick: true, + Dir: filepath.Join(getCwd(t), "helm-release-redis", "step1"), + SkipRefresh: false, + ExpectRefreshChanges: true, + Verbose: true, + Quick: true, EditDirs: []integration.EditDir{ { Dir: filepath.Join(getCwd(t), "helm-release-redis", "step2"), diff --git a/tests/sdk/nodejs/nodejs_test.go b/tests/sdk/nodejs/nodejs_test.go index c112068029..1b00887fc7 100644 --- a/tests/sdk/nodejs/nodejs_test.go +++ b/tests/sdk/nodejs/nodejs_test.go @@ -1175,6 +1175,7 @@ func TestServerSideApplyEmptyMaps(t *testing.T) { ExpectRefreshChanges: true, // Enable destroy-on-cleanup so we can shell out to kubectl to make external changes to the resource and reuse the same stack. DestroyOnCleanup: true, + Quick: true, OrderedConfig: []integration.ConfigValue{ { Key: "pulumi:disable-default-providers[0]", @@ -1221,7 +1222,13 @@ func TestServerSideApplyEmptyMaps(t *testing.T) { assert.NoError(t, err) assert.NotContains(t, string(out), "bar") // ConfigMap should no longer have label foo=bar. - // Re-run `pulumi up --refresh` to update the ConfigMap and re-add the label. + // Run `pulumi up` + `pulumi refresh` to refresh the state and detect the missing label. + // (The program tester runs these as separate steps, so the `pulumi up` doesn't detect a change until after the + // subsequent refresh is performed.) + err = pt.TestPreviewUpdateAndEdits() + assert.NoError(t, err) + + // Re-run `pulumi up` to update the ConfigMap and re-add the label. err = pt.TestPreviewUpdateAndEdits() assert.NoError(t, err) @@ -1338,6 +1345,19 @@ func TestServerSideApplyUpgrade(t *testing.T) { assert.True(t, ok) assert.NoError(t, err) assert.Equalf(t, "false", enableSSA, "SSA should be disabled") + for _, res := range stackInfo.Deployment.Resources { + if res.Type == "kubernetes:apps/v1:Deployment" { + live := &unstructured.Unstructured{Object: res.Outputs} + foundExpectedManager := false + for _, managedField := range live.GetManagedFields() { + if managedField.Manager == "pulumi-kubernetes" && managedField.Operation == "Update" { + foundExpectedManager = true + break + } + } + assert.Truef(t, foundExpectedManager, "missing expected pulumi-kubernetes field manager with operation type Update") + } + } }, EditDirs: []integration.EditDir{ { @@ -1350,6 +1370,19 @@ func TestServerSideApplyUpgrade(t *testing.T) { assert.True(t, ok) assert.NoError(t, err) assert.Equalf(t, "true", enableSSA, "SSA should be enabled") + for _, res := range stackInfo.Deployment.Resources { + if res.Type == "kubernetes:apps/v1:Deployment" { + live := &unstructured.Unstructured{Object: res.Outputs} + foundExpectedManager := false + for _, managedField := range live.GetManagedFields() { + if managedField.Manager == "pulumi-kubernetes" && managedField.Operation == "Update" { + foundExpectedManager = true + break + } + } + assert.Truef(t, foundExpectedManager, "missing expected pulumi-kubernetes field manager with operation type Update") + } + } }, }, { @@ -1358,11 +1391,26 @@ func TestServerSideApplyUpgrade(t *testing.T) { ExtraRuntimeValidation: func(t *testing.T, stackInfo integration.RuntimeValidationStackInfo) { for _, res := range stackInfo.Deployment.Resources { if res.Type == "kubernetes:apps/v1:Deployment" { + live := &unstructured.Unstructured{Object: res.Outputs} + foundExpectedManager := false + for _, managedField := range live.GetManagedFields() { + // Operation type should change to Apply on first update to the Deployment. + if managedField.Manager == "pulumi-kubernetes" && managedField.Operation == "Apply" { + foundExpectedManager = true + break + } + } + assert.Truef(t, foundExpectedManager, "missing expected pulumi-kubernetes field manager with operation type Apply") containers, ok := openapi.Pluck(res.Outputs, "spec", "template", "spec", "containers") - assert.True(t, ok) + assert.Truef(t, ok, "failed to get containers") containerStatus := containers.([]any)[0].(map[string]any) image := containerStatus["image"] assert.Equalf(t, image.(string), "nginx:1.17", "image should be updated") + portsRaw := containerStatus["ports"] + portsArray := portsRaw.([]any) + assert.Equalf(t, len(portsArray), 1, "only one port should be set") + portMap := portsArray[0].(map[string]any) + assert.Equalf(t, portMap["containerPort"], float64(81), "port should be updated to 81") } } }, @@ -1520,3 +1568,157 @@ func TestStrictMode(t *testing.T) { }) integration.ProgramTest(t, &test) } + +// TestClientSideDriftCorrectCSA tests that we can successfully reapply a resource that has been +// modified outside of Pulumi using the client-side apply strategy. +func TestClientSideDriftCorrectCSA(t *testing.T) { + var ns, cmName string + + applyStep := baseOptions.With(integration.ProgramTestOptions{ + Dir: filepath.Join("drift-correct", "configmap-csa"), + ExpectRefreshChanges: true, + // Enable destroy-on-cleanup so we can shell out to kubectl to make external changes to the resource and reuse the same stack. + DestroyOnCleanup: true, + OrderedConfig: []integration.ConfigValue{ + { + Key: "pulumi:disable-default-providers[0]", + Value: "kubernetes", + Path: true, + }, + }, + ExtraRuntimeValidation: func(t *testing.T, stackInfo integration.RuntimeValidationStackInfo) { + cm, ok := stackInfo.Outputs["cm"].(map[string]interface{}) + assert.True(t, ok) + + // Save the name and namespace for later use with kubectl. We check that the vars are empty, + // in case pulumi up creates a new ConfigMap/Namespace instead of updating the existing one on + // subsequent runs. + if ns == "" && cmName == "" { + ns = cm["metadata"].(map[string]interface{})["namespace"].(string) + cmName = cm["metadata"].(map[string]interface{})["name"].(string) + } + + // Validate we applied ConfigMap with data. + fooV, ok, err := unstructured.NestedString(cm, "data", "foo") + assert.True(t, ok) + assert.NoError(t, err) + assert.Equal(t, "bar", fooV) + }, + }) + + // Use manual lifecycle management since we need to run external commands in between pulumi up steps, while referencing + // the same stack. + pt := integration.ProgramTestManualLifeCycle(t, &applyStep) + err := pt.TestLifeCycleInitAndDestroy() + assert.NoError(t, err) + + // Sanity check with kubectl to verify that the ConfigMap was created with the wanted label. + out, err := exec.Command("kubectl", "get", "configmap", "-o", "yaml", "-n", ns, cmName).CombinedOutput() + assert.NoError(t, err) + assert.Contains(t, string(out), "bar") // ConfigMap should have been created with data foo: bar. + + // Update the ConfigMap and change the data foo: bar to foo: baz. + out, err = exec.Command("kubectl", "patch", "configmap", "-n", ns, cmName, "-p", `{"data":{"foo":"baz"}}`).CombinedOutput() + assert.NoError(t, err) + assert.Contains(t, string(out), "configmap/"+cmName+" patched") // Ensure CM was patched. + + // Use kubectl to verify that the ConfigMap was updated and now has data foo: baz. + out, err = exec.Command("kubectl", "get", "configmap", "-o", "yaml", "-n", ns, cmName).CombinedOutput() + assert.NoError(t, err) + assert.NotContains(t, string(out), "foo: bar") // ConfigMap should no longer have data foo: bar. + assert.Contains(t, string(out), "foo: baz") // ConfigMap should have data foo: baz. + + // Run `pulumi up` + `pulumi refresh` to refresh the state and detect the missing label. + // (The program tester runs these as separate steps, so the `pulumi up` doesn't detect a change until after the + // subsequent refresh is performed.) + err = pt.TestPreviewUpdateAndEdits() + assert.NoError(t, err) + + // Re-run `pulumi up` to update the ConfigMap and re-add the label. + err = pt.TestPreviewUpdateAndEdits() + assert.NoError(t, err) + + // Use kubectl to verify that the ConfigMap was updated and has the label again. + out, err = exec.Command("kubectl", "get", "configmap", "-o", "yaml", "-n", ns, cmName).CombinedOutput() + assert.NoError(t, err) + + assert.Contains(t, string(out), "foo: bar") // ConfigMap should have been updated with data foo: bar. + assert.NotContains(t, string(out), "foo: baz") // ConfigMap should no longer have data foo: baz. +} + +// TestClientSideDriftCorrectSSA tests that we can successfully reapply a resource that has been +// modified outside of Pulumi, with SSA enabled. +func TestClientSideDriftCorrectSSA(t *testing.T) { + var ns, cmName string + + applyStep := baseOptions.With(integration.ProgramTestOptions{ + Dir: filepath.Join("drift-correct", "configmap-ssa"), + ExpectRefreshChanges: true, + // Enable destroy-on-cleanup so we can shell out to kubectl to make external changes to the resource and reuse the same stack. + DestroyOnCleanup: true, + OrderedConfig: []integration.ConfigValue{ + { + Key: "pulumi:disable-default-providers[0]", + Value: "kubernetes", + Path: true, + }, + }, + ExtraRuntimeValidation: func(t *testing.T, stackInfo integration.RuntimeValidationStackInfo) { + cm, ok := stackInfo.Outputs["cm"].(map[string]interface{}) + assert.True(t, ok) + + // Save the name and namespace for later use with kubectl. We check that the vars are empty, + // in case pulumi up creates a new ConfigMap/Namespace instead of updating the existing one on + // subsequent runs. + if ns == "" && cmName == "" { + ns = cm["metadata"].(map[string]interface{})["namespace"].(string) + cmName = cm["metadata"].(map[string]interface{})["name"].(string) + } + + // Validate we applied ConfigMap with data. + fooV, ok, err := unstructured.NestedString(cm, "data", "foo") + assert.True(t, ok) + assert.NoError(t, err) + assert.Equal(t, "bar", fooV) + }, + }) + + // Use manual lifecycle management since we need to run external commands in between pulumi up steps, while referencing + // the same stack. + pt := integration.ProgramTestManualLifeCycle(t, &applyStep) + err := pt.TestLifeCycleInitAndDestroy() + assert.NoError(t, err) + + // Sanity check with kubectl to verify that the ConfigMap was created with the wanted label. + out, err := exec.Command("kubectl", "get", "configmap", "-o", "yaml", "-n", ns, cmName).CombinedOutput() + assert.NoError(t, err) + assert.Contains(t, string(out), "bar") // ConfigMap should have been created with data foo: bar. + + // Update the ConfigMap and change the data foo: bar to foo: baz. + out, err = exec.Command("kubectl", "patch", "configmap", "-n", ns, cmName, "-p", `{"data":{"foo":"baz"}}`).CombinedOutput() + assert.NoError(t, err) + assert.Contains(t, string(out), "configmap/"+cmName+" patched") // Ensure CM was patched. + + // Use kubectl to verify that the ConfigMap was updated and now has data foo: baz. + out, err = exec.Command("kubectl", "get", "configmap", "-o", "yaml", "-n", ns, cmName).CombinedOutput() + assert.NoError(t, err) + assert.NotContains(t, string(out), "foo: bar") // ConfigMap should no longer have data foo: bar. + assert.Contains(t, string(out), "foo: baz") // ConfigMap should have data foo: baz. + + // Run `pulumi up` + `pulumi refresh` to refresh the state and detect the missing label. + // (The program tester runs these as separate steps, so the `pulumi up` doesn't detect a change until after the + // subsequent refresh is performed.) + err = pt.TestPreviewUpdateAndEdits() + assert.NoError(t, err) + + // Re-run `pulumi up` to update the ConfigMap and re-add the label. + err = pt.TestPreviewUpdateAndEdits() + assert.NoError(t, err) + + // Use kubectl to verify that the ConfigMap was updated and has the label again. + out, err = exec.Command("kubectl", "get", "configmap", "-o", "yaml", "-n", ns, cmName).CombinedOutput() + assert.NoError(t, err) + + assert.Contains(t, string(out), "foo: bar") // ConfigMap should have been updated with data foo: bar. + assert.NotContains(t, string(out), "foo: baz") // ConfigMap should no longer have data foo: baz. +} diff --git a/tests/sdk/nodejs/server-side-apply-upgrade/step1/index.ts b/tests/sdk/nodejs/server-side-apply-upgrade/step1/index.ts index de35c43c00..13f8655af0 100644 --- a/tests/sdk/nodejs/server-side-apply-upgrade/step1/index.ts +++ b/tests/sdk/nodejs/server-side-apply-upgrade/step1/index.ts @@ -19,7 +19,7 @@ import * as k8s from "@pulumi/kubernetes"; // Server-side Apply (SSA). This test validates the following scenario does not fail with a field manager conflict: // 1. Create a Deployment with Client-side Apply. // 2. Update the Provider to use Server-side Apply. -// 3. Change a field in the Deployment. +// 3. Change fields in the Deployment. // Create provider with SSA disabled. export const provider = new k8s.Provider("k8s", {enableServerSideApply: false}); @@ -40,6 +40,7 @@ const deployment = new k8s.apps.v1.Deployment("nginx", { containers: [{ name: "nginx", image: "nginx:1.16", + ports: [{containerPort: 80}], }], } } diff --git a/tests/sdk/nodejs/server-side-apply-upgrade/step2/index.ts b/tests/sdk/nodejs/server-side-apply-upgrade/step2/index.ts index 4a309b4d7c..784ff917fa 100644 --- a/tests/sdk/nodejs/server-side-apply-upgrade/step2/index.ts +++ b/tests/sdk/nodejs/server-side-apply-upgrade/step2/index.ts @@ -19,7 +19,7 @@ import * as k8s from "@pulumi/kubernetes"; // Server-side Apply (SSA). This test validates the following scenario does not fail with a field manager conflict: // 1. Create a Deployment with Client-side Apply. // 2. Update the Provider to use Server-side Apply. -// 3. Change a field in the Deployment. +// 3. Change fields in the Deployment. // Create provider with SSA disabled. export const provider = new k8s.Provider("k8s", {enableServerSideApply: true}); // Enable SSA @@ -40,6 +40,7 @@ const deployment = new k8s.apps.v1.Deployment("nginx", { containers: [{ name: "nginx", image: "nginx:1.16", + ports: [{containerPort: 80}], }], } } diff --git a/tests/sdk/nodejs/server-side-apply-upgrade/step3/index.ts b/tests/sdk/nodejs/server-side-apply-upgrade/step3/index.ts index 5cfa114ff1..e69b66fa34 100644 --- a/tests/sdk/nodejs/server-side-apply-upgrade/step3/index.ts +++ b/tests/sdk/nodejs/server-side-apply-upgrade/step3/index.ts @@ -19,7 +19,7 @@ import * as k8s from "@pulumi/kubernetes"; // Server-side Apply (SSA). This test validates the following scenario does not fail with a field manager conflict: // 1. Create a Deployment with Client-side Apply. // 2. Update the Provider to use Server-side Apply. -// 3. Change a field in the Deployment. +// 3. Change fields in the Deployment. // Create provider with SSA disabled. export const provider = new k8s.Provider("k8s", {enableServerSideApply: true}); @@ -40,6 +40,10 @@ const deployment = new k8s.apps.v1.Deployment("nginx", { containers: [{ name: "nginx", image: "nginx:1.17", // Update a field to ensure that field manager conflicts don't cause an error + ports: [ + // Change the port to ensure that the existing value is updated rather than adding a second port to the array + {containerPort: 81}, + ], }], } } diff --git a/tests/sdk/python/guestbook-old/__main__.py b/tests/sdk/python/guestbook-old/__main__.py index 952f955ddf..840507cebf 100644 --- a/tests/sdk/python/guestbook-old/__main__.py +++ b/tests/sdk/python/guestbook-old/__main__.py @@ -25,7 +25,7 @@ redis_leader_deployment = Deployment( "redis-leader", metadata={ - "namespace": namespace + "namespace": namespace.metadata.apply(lambda x: x.name), }, spec={ "selector": { @@ -57,7 +57,7 @@ redis_leader_service = Service( "redis-leader", metadata={ - "namespace": namespace, + "namespace": namespace.metadata.apply(lambda x: x.name), "labels": redis_leader_labels }, spec={ @@ -77,7 +77,7 @@ redis_follower_deployment = Deployment( "redis-follower", metadata={ - "namespace": namespace + "namespace": namespace.metadata.apply(lambda x: x.name), }, spec={ "selector": { @@ -117,7 +117,7 @@ redis_follower_service = Service( "redis-follower", metadata={ - "namespace": namespace, + "namespace": namespace.metadata.apply(lambda x: x.name), "labels": redis_follower_labels }, spec={ @@ -136,7 +136,7 @@ frontend_service = Service( "frontend", metadata={ - "namespace": namespace, + "namespace": namespace.metadata.apply(lambda x: x.name), "labels": frontend_labels }, spec={ @@ -152,7 +152,7 @@ frontend_deployment = Deployment( "frontend", metadata={ - "namespace": namespace, + "namespace": namespace.metadata.apply(lambda x: x.name), }, spec={ "selector": { diff --git a/tests/sdk/python/guestbook/__main__.py b/tests/sdk/python/guestbook/__main__.py index 5bfe677dea..89422f5c38 100644 --- a/tests/sdk/python/guestbook/__main__.py +++ b/tests/sdk/python/guestbook/__main__.py @@ -37,7 +37,7 @@ redis_leader_deployment = Deployment( "redis-leader", metadata=ObjectMetaArgs( - namespace=namespace + namespace=namespace.metadata.apply(lambda x: x.name), ), spec=DeploymentSpecArgs( selector=LabelSelectorArgs( @@ -69,7 +69,7 @@ redis_leader_service = Service( "redis-leader", metadata=ObjectMetaArgs( - namespace=namespace, + namespace=namespace.metadata.apply(lambda x: x.name), labels=redis_leader_labels ), spec=ServiceSpecArgs( @@ -89,7 +89,7 @@ redis_follower_deployment = Deployment( "redis-follower", metadata=ObjectMetaArgs( - namespace=namespace + namespace=namespace.metadata.apply(lambda x: x.name), ), spec=DeploymentSpecArgs( selector=LabelSelectorArgs( @@ -129,7 +129,7 @@ redis_follower_service = Service( "redis-follower", metadata=ObjectMetaArgs( - namespace=namespace, + namespace=namespace.metadata.apply(lambda x: x.name), labels=redis_follower_labels ), spec=ServiceSpecArgs( @@ -148,7 +148,7 @@ frontend_service = Service( "frontend", metadata=ObjectMetaArgs( - namespace=namespace, + namespace=namespace.metadata.apply(lambda x: x.name), labels=frontend_labels ), spec=ServiceSpecArgs( @@ -164,7 +164,7 @@ frontend_deployment = Deployment( "frontend", metadata=ObjectMetaArgs( - namespace=namespace, + namespace=namespace.metadata.apply(lambda x: x.name), ), spec=DeploymentSpecArgs( selector=LabelSelectorArgs( diff --git a/tests/sdk/python/provider-old/__main__.py b/tests/sdk/python/provider-old/__main__.py index 354180f517..919601cfad 100644 --- a/tests/sdk/python/provider-old/__main__.py +++ b/tests/sdk/python/provider-old/__main__.py @@ -23,7 +23,7 @@ nginx = Pod( "nginx", metadata={ - "namespace": namespace, + "namespace": namespace.metadata.apply(lambda x: x.name), }, spec={ "containers": [{ diff --git a/tests/sdk/python/provider/__main__.py b/tests/sdk/python/provider/__main__.py index f842bbd1e7..9781aa372b 100644 --- a/tests/sdk/python/provider/__main__.py +++ b/tests/sdk/python/provider/__main__.py @@ -24,7 +24,7 @@ nginx = Pod( "nginx", metadata=ObjectMetaArgs( - namespace=namespace, + namespace=namespace.metadata.apply(lambda x: x.name), ), spec=PodSpecArgs( containers=[ContainerArgs( diff --git a/tests/sdk/python/python_test.go b/tests/sdk/python/python_test.go index d633c84121..7e091eda07 100644 --- a/tests/sdk/python/python_test.go +++ b/tests/sdk/python/python_test.go @@ -239,8 +239,9 @@ func TestGuestbook(t *testing.T) { for _, dir := range []string{"guestbook", "guestbook-old"} { t.Run(dir, func(t *testing.T) { options := baseOptions.With(integration.ProgramTestOptions{ - Dir: filepath.Join(cwd, dir), - NoParallel: true, + Dir: filepath.Join(cwd, dir), + NoParallel: true, + ExpectRefreshChanges: true, ExtraRuntimeValidation: func(t *testing.T, stackInfo integration.RuntimeValidationStackInfo) { assert.NotNil(t, stackInfo.Deployment) assert.Equal(t, 9, len(stackInfo.Deployment.Resources)) @@ -351,7 +352,8 @@ func TestHelm(t *testing.T) { t.FailNow() } options := baseOptions.With(integration.ProgramTestOptions{ - Dir: filepath.Join(cwd, "helm", "step1"), + Dir: filepath.Join(cwd, "helm", "step1"), + ExpectRefreshChanges: true, }) integration.ProgramTest(t, &options) } @@ -362,7 +364,8 @@ func TestHelmRelease(t *testing.T) { t.FailNow() } options := baseOptions.With(integration.ProgramTestOptions{ - Dir: filepath.Join(cwd, "helm-release", "step1"), + Dir: filepath.Join(cwd, "helm-release", "step1"), + ExpectRefreshChanges: true, EditDirs: []integration.EditDir{ { Dir: filepath.Join(cwd, "helm-release", "step2"), @@ -380,7 +383,8 @@ func TestHelmLocal(t *testing.T) { t.FailNow() } options := baseOptions.With(integration.ProgramTestOptions{ - Dir: filepath.Join(cwd, "helm-local", "step1"), + Dir: filepath.Join(cwd, "helm-local", "step1"), + ExpectRefreshChanges: true, ExtraRuntimeValidation: func(t *testing.T, stackInfo integration.RuntimeValidationStackInfo) { // Verify resource creation order using the Event stream. The Chart resources must be created // first, followed by the dependent ConfigMap. (The ConfigMap doesn't actually need the Chart, but @@ -419,7 +423,8 @@ func TestHelmApiVersions(t *testing.T) { t.FailNow() } options := baseOptions.With(integration.ProgramTestOptions{ - Dir: filepath.Join(cwd, "helm-api-versions", "step1"), + Dir: filepath.Join(cwd, "helm-api-versions", "step1"), + ExpectRefreshChanges: true, }) integration.ProgramTest(t, &options) } diff --git a/tests/sdk/python/smoke-test-old/__main__.py b/tests/sdk/python/smoke-test-old/__main__.py index 5ab8d9eff2..16cc958232 100644 --- a/tests/sdk/python/smoke-test-old/__main__.py +++ b/tests/sdk/python/smoke-test-old/__main__.py @@ -19,7 +19,7 @@ pod = Pod( "smoke-test", metadata={ - "namespace": namespace, + "namespace": namespace.metadata.apply(lambda x: x.name), }, spec={ "containers": [ diff --git a/tests/sdk/python/smoke-test/__main__.py b/tests/sdk/python/smoke-test/__main__.py index 1551b0c1cf..c9486ecbc2 100644 --- a/tests/sdk/python/smoke-test/__main__.py +++ b/tests/sdk/python/smoke-test/__main__.py @@ -20,7 +20,7 @@ pod = Pod( "smoke-test", metadata=ObjectMetaArgs( - namespace=namespace, + namespace=namespace.metadata.apply(lambda x: x.name), ), spec=PodSpecArgs( containers=[ diff --git a/tests/sdk/python/yaml-test/manifest.yaml b/tests/sdk/python/yaml-test/manifest.yaml index 908721f96f..008f43ccc9 100644 --- a/tests/sdk/python/yaml-test/manifest.yaml +++ b/tests/sdk/python/yaml-test/manifest.yaml @@ -46,6 +46,11 @@ spec: type: object spec: type: object + properties: + foo: + type: string + bar: + type: string type: object served: true storage: true