Skip to content

Commit 711387e

Browse files
authored
update ResourceGroup CRD (#2794)
- Add the new fields for capturing the apply and reconcile status - Update the pre-steps of apply. If the ResourceGroup CRD is installed but doesn't match the latest declaration, the ResourceGroup CRD should be re-applied.
1 parent c5e8647 commit 711387e

File tree

6 files changed

+223
-5
lines changed

6 files changed

+223
-5
lines changed

e2e/live/end-to-end-test.sh

Lines changed: 89 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,30 @@ function downloadPreviousKpt {
129129
fi
130130
tar -xvf kpt.tar.gz > $OUTPUT_DIR/kptdownload 2>&1
131131
mv kpt $BIN_DIR/previouskpt
132-
echo "Downloading latest kpt binary...SUCCESS"
132+
echo "Downloading previous kpt binary...SUCCESS"
133+
rm kpt.tar.gz LICENSES.txt lib.zip
134+
set +e
135+
}
136+
137+
function downloadKpt1.0 {
138+
set -e
139+
echo "Downloading v1.0.0-beta.13 kpt binary..."
140+
uname="$(uname -s)"
141+
if [[ "$uname" == "Linux" ]]
142+
then
143+
echo "Running on Linux"
144+
curl -LJ -o kpt.tar.gz https://github.com/GoogleContainerTools/kpt/releases/download/v1.0.0-beta.13/kpt_linux_amd64-1.0.0-beta.13.tar.gz > $OUTPUT_DIR/kptdownload 2>&1
145+
elif [[ "$uname" == "Darwin" ]]
146+
then
147+
echo "Running on Darwin"
148+
curl -LJ -o kpt.tar.gz https://github.com/GoogleContainerTools/kpt/releases/download/v1.0.0-beta.13/kpt_darwin_amd64-1.0.0-beta.13.tar.gz > $OUTPUT_DIR/kptdownload 2>&1
149+
else
150+
echo "ERROR: Unknown OS $uname"
151+
exit 1
152+
fi
153+
tar -xvf kpt.tar.gz > $OUTPUT_DIR/kptdownload 2>&1
154+
mv kpt $BIN_DIR/kpt1.0.0
155+
echo "Downloading 1.0.0 kpt binary...SUCCESS"
133156
rm kpt.tar.gz LICENSES.txt lib.zip
134157
set +e
135158
}
@@ -409,6 +432,7 @@ echo
409432
buildKpt
410433

411434
downloadPreviousKpt
435+
downloadKpt1.0
412436

413437
echo
414438
set +e # Do not stop the test for errors
@@ -836,6 +860,70 @@ assertPodExists "pod-c" "test-rg-namespace"
836860
assertPodExists "pod-d" "test-rg-namespace"
837861
printResult
838862

863+
###########################################################
864+
# Test Update ResourceGroup CRD during apply
865+
###########################################################
866+
867+
createTestSuite
868+
waitForDefaultServiceAccount
869+
870+
# This test first applies a kpt package with kpt1.0.0,
871+
# which uses the previous ResourceGroup CRD.
872+
# Then it re-apply the same kpt package with the built kpt,
873+
# which uses a new ResourceGroup CRD.
874+
# It updates the ResourceGroup CRD and apply/prune works as expected.
875+
echo "Testing apply with kpt 1.0.0 and re-apply/prune with built kpt"
876+
echo "cat e2e/live/testdata/stdin-test/pods.yaml | kpt1.0.0 live apply -"
877+
cat e2e/live/testdata/stdin-test/pods.yaml | ${BIN_DIR}/kpt1.0.0 live apply - > $OUTPUT_DIR/status 2>&1
878+
assertContains "pod/pod-a created"
879+
assertContains "pod/pod-b created"
880+
assertContains "pod/pod-c created"
881+
assertContains "4 resource(s) applied. 3 created, 1 unchanged, 0 configured, 0 failed"
882+
printResult
883+
echo "cat e2e/live/testdata/stdin-test/pods.yaml | kpt live apply -"
884+
cat e2e/live/testdata/stdin-test/pods.yaml | ${BIN_DIR}/kpt live apply - > $OUTPUT_DIR/status 2>&1
885+
assertContains "namespace/stdin-test-namespace unchanged"
886+
assertContains "pod/pod-a unchanged"
887+
assertContains "pod/pod-b unchanged"
888+
assertContains "pod/pod-c unchanged"
889+
printResult
890+
echo "cat e2e/live/testdata/stdin-test/pods.yaml | kpt live destroy -"
891+
cat e2e/live/testdata/stdin-test/pods.yaml | ${BIN_DIR}/kpt live destroy - > $OUTPUT_DIR/status 2>&1
892+
assertContains "pod/pod-a deleted"
893+
assertContains "pod/pod-b deleted"
894+
assertContains "pod/pod-c deleted"
895+
assertContains "4 resource(s) deleted, 0 skipped"
896+
printResult
897+
898+
# Test: don't have permission to update the ResourceGroup CRD
899+
# should see an error message
900+
echo "Testing updating ResourceGroup CRD during apply"
901+
echo "Apply the previous ResourceGroup CRD"
902+
${BIN_DIR}/kpt1.0.0 live install-resource-group > $OUTPUT_DIR/status 2>&1
903+
echo "kubectl apply -f e2e/live/testdata/update-rg-crd"
904+
# Setup: create a service account and bind a Role to it so it has administrative
905+
# privileges on the "test" namespace, but no permissions to Get or Update CRD.
906+
kubectl apply -f e2e/live/testdata/rbac-error-step-1 > $OUTPUT_DIR/status
907+
assertContains "namespace/rbac-error created"
908+
assertContains "rolebinding.rbac.authorization.k8s.io/admin created"
909+
assertContains "serviceaccount/user created"
910+
wait 2
911+
912+
# Setup: use the service account just created. It does not have permissions
913+
# on the default namespace, so it will give a permissions error on apply
914+
# for anything attempted to apply to the default namespace.
915+
kubectl config set-credentials user --token="$(kubectl get secrets -ojsonpath='{.data.token}' \
916+
"$(kubectl get sa user -ojsonpath='{.secrets[0].name}')" \
917+
| base64 -d)" > $OUTPUT_DIR/status
918+
kubectl config set-context kind-kind:user --cluster=kind-kind --user=user > $OUTPUT_DIR/status
919+
kubectl config use-context kind-kind:user > $OUTPUT_DIR/status
920+
wait 2
921+
922+
# Attempt to apply a kpt package. It fails with an error message.
923+
${BIN_DIR}/kpt live apply e2e/live/testdata/rbac-error-step-2 > $OUTPUT_DIR/status 2>&1
924+
assertContains "error: Type ResourceGroup CRD needs update."
925+
printResult
926+
839927
# Clean-up the k8s cluster
840928
echo "Cleaning up cluster"
841929
cp -f e2e/live/testdata/Kptfile e2e/live/testdata/rg-test-case-1a

internal/cmdapply/cmdapply.go

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -201,12 +201,20 @@ func runApply(r *Runner, invInfo inventory.InventoryInfo, objs []*unstructured.U
201201
dryRunStrategy common.DryRunStrategy) error {
202202
if r.installCRD {
203203
f := r.factory
204-
// Only install the ResourceGroup CRD if it is not already installed.
205-
if err := cmdutil.VerifyResourceGroupCRD(f); err != nil {
206-
err = cmdutil.InstallResourceGroupCRD(r.ctx, f)
207-
if err != nil {
204+
// Install the ResourceGroup CRD if it is not already installed
205+
// or if the ResourceGroup CRD doesn't match the CRD in the
206+
// kpt binary.
207+
err := cmdutil.VerifyResourceGroupCRD(f)
208+
if err != nil {
209+
if err = cmdutil.InstallResourceGroupCRD(r.ctx, f); err != nil {
208210
return err
209211
}
212+
} else if !live.ResourceGroupCRDMatched(f) {
213+
if err = cmdutil.InstallResourceGroupCRD(r.ctx, f); err != nil {
214+
return &cmdutil.ResourceGroupCRDNotLatestError{
215+
Err: err,
216+
}
217+
}
210218
}
211219
}
212220

internal/cmdutil/util.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ package cmdutil
1616

1717
import (
1818
"context"
19+
"fmt"
1920

2021
"github.com/GoogleContainerTools/kpt/internal/printer"
2122
"github.com/GoogleContainerTools/kpt/pkg/live"
@@ -73,3 +74,16 @@ type NoResourceGroupCRDError struct{}
7374
func (*NoResourceGroupCRDError) Error() string {
7475
return "type ResourceGroup not found"
7576
}
77+
78+
// ResourceGroupCRDNotLatestError is an error type that will be used when a
79+
// cluster has a ResourceGroup CRD that doesn't match the
80+
// latest declaration.
81+
type ResourceGroupCRDNotLatestError struct{
82+
Err error
83+
}
84+
85+
func (e *ResourceGroupCRDNotLatestError) Error() string {
86+
return fmt.Sprintf(
87+
"Type ResourceGroup CRD needs update. Please make sure you have the permission " +
88+
"to update CRD then run `kpt live install-resource-group`.\n %v", e.Err)
89+
}

pkg/live/example-resource-group-crd-for-v1.yaml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,10 @@ spec:
149149
description: ResourceStatus contains the status of a given resource
150150
uniquely identified by its group, kind, name and namespace.
151151
properties:
152+
actuation:
153+
description: actuation indicates whether actuation has been
154+
performed yet and how it went.
155+
type: string
152156
conditions:
153157
items:
154158
properties:
@@ -184,9 +188,19 @@ spec:
184188
type: string
185189
namespace:
186190
type: string
191+
reconcile:
192+
description: reconcile indicates whether reconciliation has
193+
been performed yet and how it went.
194+
type: string
195+
sourceHash:
196+
type: string
187197
status:
188198
description: Status describes the status of a resource
189199
type: string
200+
strategy:
201+
description: strategy indicates the method of actuation (apply
202+
or delete) used or planned to be used.
203+
type: string
190204
required:
191205
- group
192206
- kind

pkg/live/example-resource-group-crd.yaml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,10 @@ spec:
150150
description: ResourceStatus contains the status of a given resource
151151
uniquely identified by its group, kind, name and namespace.
152152
properties:
153+
actuation:
154+
description: actuation indicates whether actuation has been
155+
performed yet and how it went.
156+
type: string
153157
conditions:
154158
items:
155159
properties:
@@ -185,9 +189,19 @@ spec:
185189
type: string
186190
namespace:
187191
type: string
192+
reconcile:
193+
description: reconcile indicates whether reconciliation has
194+
been performed yet and how it went.
195+
type: string
196+
sourceHash:
197+
type: string
188198
status:
189199
description: Status describes the status of a resource
190200
type: string
201+
strategy:
202+
description: strategy indicates the method of actuation (apply
203+
or delete) used or planned to be used.
204+
type: string
191205
required:
192206
- group
193207
- kind

pkg/live/inventoryrg.go

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,14 @@ package live
1717
import (
1818
"context"
1919
"fmt"
20+
"reflect"
2021
"strings"
2122
"time"
2223

2324
"github.com/GoogleContainerTools/kpt/pkg/status"
2425
apierrors "k8s.io/apimachinery/pkg/api/errors"
2526
"k8s.io/apimachinery/pkg/api/meta"
27+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2628
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
2729
"k8s.io/apimachinery/pkg/runtime/schema"
2830
"k8s.io/klog/v2"
@@ -244,6 +246,56 @@ func ResourceGroupCRDApplied(factory cmdutil.Factory) bool {
244246
return true
245247
}
246248

249+
// ResourceGroupCRDMatched checks if the ResourceGroup CRD
250+
// in the cluster matches the CRD in the kpt binary.
251+
func ResourceGroupCRDMatched(factory cmdutil.Factory) bool {
252+
mapper, err := factory.ToRESTMapper()
253+
if err != nil {
254+
klog.V(4).Infof("error retrieving RESTMapper when checking ResourceGroup CRD: %s\n", err)
255+
return false
256+
}
257+
crd, err := rgCRD(mapper)
258+
if err != nil {
259+
klog.V(7).Infof("failed to get ResourceGroup CRD from string: %s", err)
260+
return false
261+
}
262+
263+
dc, err := factory.DynamicClient()
264+
if err != nil {
265+
klog.V(7).Infof("error getting the dynamic client: %s\n", err)
266+
return false
267+
}
268+
269+
mapping, err := mapper.RESTMapping(crdGroupKind)
270+
if err != nil {
271+
klog.V(7).Infof("Failed to get mapping of CRD type: %s", err)
272+
return false
273+
}
274+
275+
liveCRD, err := dc.Resource(mapping.Resource).Get(context.TODO(), "resourcegroups.kpt.dev", metav1.GetOptions{
276+
TypeMeta: metav1.TypeMeta{
277+
APIVersion: crd.GetAPIVersion(),
278+
Kind: "CustomResourceDefinition",
279+
},
280+
})
281+
if err != nil {
282+
klog.V(7).Infof("error getting the ResourceGroup CRD from cluster: %s\n", err)
283+
return false
284+
}
285+
286+
liveSpec, _, err := unstructured.NestedMap(liveCRD.Object, "spec")
287+
if err != nil {
288+
klog.V(7).Infof("error getting the ResourceGroup CRD spec from cluster: %s\n", err)
289+
return false
290+
}
291+
latestspec, _, err := unstructured.NestedMap(crd.Object, "spec")
292+
if err != nil {
293+
klog.V(7).Infof("error getting the ResourceGroup CRD spec from string: %s\n", err)
294+
return false
295+
}
296+
return reflect.DeepEqual(liveSpec, latestspec)
297+
}
298+
247299
// InstallResourceGroupCRD applies the custom resource definition for the
248300
// ResourceGroup by creating and running a TaskQueue of Tasks necessary.
249301
// The Tasks are 1) Apply CRD task, 2) Wait Task (for CRD to become
@@ -510,6 +562,10 @@ spec:
510562
description: ResourceStatus contains the status of a given resource
511563
uniquely identified by its group, kind, name and namespace.
512564
properties:
565+
actuation:
566+
description: actuation indicates whether actuation has been
567+
performed yet and how it went.
568+
type: string
513569
conditions:
514570
items:
515571
properties:
@@ -545,9 +601,19 @@ spec:
545601
type: string
546602
namespace:
547603
type: string
604+
reconcile:
605+
description: reconcile indicates whether reconciliation has
606+
been performed yet and how it went.
607+
type: string
608+
sourceHash:
609+
type: string
548610
status:
549611
description: Status describes the status of a resource
550612
type: string
613+
strategy:
614+
description: strategy indicates the method of actuation (apply
615+
or delete) used or planned to be used.
616+
type: string
551617
required:
552618
- group
553619
- kind
@@ -716,6 +782,10 @@ spec:
716782
description: ResourceStatus contains the status of a given resource
717783
uniquely identified by its group, kind, name and namespace.
718784
properties:
785+
actuation:
786+
description: actuation indicates whether actuation has been
787+
performed yet and how it went.
788+
type: string
719789
conditions:
720790
items:
721791
properties:
@@ -751,9 +821,19 @@ spec:
751821
type: string
752822
namespace:
753823
type: string
824+
reconcile:
825+
description: reconcile indicates whether reconciliation has
826+
been performed yet and how it went.
827+
type: string
828+
sourceHash:
829+
type: string
754830
status:
755831
description: Status describes the status of a resource
756832
type: string
833+
strategy:
834+
description: strategy indicates the method of actuation (apply
835+
or delete) used or planned to be used.
836+
type: string
757837
required:
758838
- group
759839
- kind

0 commit comments

Comments
 (0)