From 86ec74b795b848c2fd5e68c147cffdecc233cae3 Mon Sep 17 00:00:00 2001 From: Tiago Silva Date: Fri, 22 Mar 2024 19:35:46 +0000 Subject: [PATCH] Introduce `patch_type` to `KubernetesWaitingContainer` (#39738) This PR adds the `patch_type` to `KubernetesWaitingContainer` objects. This patch type is used to decode the contents correctly depending on different patch strategies allowed by Kubernetes clients. Signed-off-by: Tiago Silva --- .../v1/kubewaitingcontainer.pb.go | 29 +++++++++++++------ .../v1/kubewaitingcontainer.proto | 2 ++ .../kubewaitingcontainer.go | 29 ++++++++++++++++++- lib/auth/kubewaitingcontainer/service_test.go | 4 +++ lib/cache/cache_test.go | 1 + 5 files changed, 55 insertions(+), 10 deletions(-) diff --git a/api/gen/proto/go/teleport/kubewaitingcontainer/v1/kubewaitingcontainer.pb.go b/api/gen/proto/go/teleport/kubewaitingcontainer/v1/kubewaitingcontainer.pb.go index 5a9bb1ae284..a42f7323929 100644 --- a/api/gen/proto/go/teleport/kubewaitingcontainer/v1/kubewaitingcontainer.pb.go +++ b/api/gen/proto/go/teleport/kubewaitingcontainer/v1/kubewaitingcontainer.pb.go @@ -141,6 +141,8 @@ type KubernetesWaitingContainerSpec struct { // patch is the patch that should be applied to the parent pod // to create this ephemeral container Patch []byte `protobuf:"bytes,6,opt,name=patch,proto3" json:"patch,omitempty"` + // patch_type identifies the patch model to be applied. + PatchType string `protobuf:"bytes,7,opt,name=patch_type,json=patchType,proto3" json:"patch_type,omitempty"` } func (x *KubernetesWaitingContainerSpec) Reset() { @@ -217,6 +219,13 @@ func (x *KubernetesWaitingContainerSpec) GetPatch() []byte { return nil } +func (x *KubernetesWaitingContainerSpec) GetPatchType() string { + if x != nil { + return x.PatchType + } + return "" +} + var File_teleport_kubewaitingcontainer_v1_kubewaitingcontainer_proto protoreflect.FileDescriptor var file_teleport_kubewaitingcontainer_v1_kubewaitingcontainer_proto_rawDesc = []byte{ @@ -243,7 +252,7 @@ var file_teleport_kubewaitingcontainer_v1_kubewaitingcontainer_proto_rawDesc = [ 0x62, 0x65, 0x77, 0x61, 0x69, 0x74, 0x69, 0x6e, 0x67, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x4b, 0x75, 0x62, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x65, 0x73, 0x57, 0x61, 0x69, 0x74, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, - 0x53, 0x70, 0x65, 0x63, 0x52, 0x04, 0x73, 0x70, 0x65, 0x63, 0x22, 0xcc, 0x01, 0x0a, 0x1e, 0x4b, + 0x53, 0x70, 0x65, 0x63, 0x52, 0x04, 0x73, 0x70, 0x65, 0x63, 0x22, 0xeb, 0x01, 0x0a, 0x1e, 0x4b, 0x75, 0x62, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x65, 0x73, 0x57, 0x61, 0x69, 0x74, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x53, 0x70, 0x65, 0x63, 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, @@ -256,14 +265,16 @@ var file_teleport_kubewaitingcontainer_v1_kubewaitingcontainer_proto_rawDesc = [ 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x70, 0x61, 0x74, 0x63, 0x68, 0x18, 0x06, 0x20, 0x01, - 0x28, 0x0c, 0x52, 0x05, 0x70, 0x61, 0x74, 0x63, 0x68, 0x42, 0x6c, 0x5a, 0x6a, 0x67, 0x69, 0x74, - 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x72, 0x61, 0x76, 0x69, 0x74, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x2f, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x61, - 0x70, 0x69, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x6f, 0x2f, - 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x6b, 0x75, 0x62, 0x65, 0x77, 0x61, 0x69, - 0x74, 0x69, 0x6e, 0x67, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x2f, 0x76, 0x31, - 0x3b, 0x6b, 0x75, 0x62, 0x65, 0x77, 0x61, 0x69, 0x74, 0x69, 0x6e, 0x67, 0x63, 0x6f, 0x6e, 0x74, - 0x61, 0x69, 0x6e, 0x65, 0x72, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x28, 0x0c, 0x52, 0x05, 0x70, 0x61, 0x74, 0x63, 0x68, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x61, 0x74, + 0x63, 0x68, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x70, + 0x61, 0x74, 0x63, 0x68, 0x54, 0x79, 0x70, 0x65, 0x42, 0x6c, 0x5a, 0x6a, 0x67, 0x69, 0x74, 0x68, + 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x72, 0x61, 0x76, 0x69, 0x74, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x61, 0x6c, 0x2f, 0x74, 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x61, 0x70, + 0x69, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x6f, 0x2f, 0x74, + 0x65, 0x6c, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x6b, 0x75, 0x62, 0x65, 0x77, 0x61, 0x69, 0x74, + 0x69, 0x6e, 0x67, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x2f, 0x76, 0x31, 0x3b, + 0x6b, 0x75, 0x62, 0x65, 0x77, 0x61, 0x69, 0x74, 0x69, 0x6e, 0x67, 0x63, 0x6f, 0x6e, 0x74, 0x61, + 0x69, 0x6e, 0x65, 0x72, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/api/proto/teleport/kubewaitingcontainer/v1/kubewaitingcontainer.proto b/api/proto/teleport/kubewaitingcontainer/v1/kubewaitingcontainer.proto index a4e6a2cbd95..362f636762e 100644 --- a/api/proto/teleport/kubewaitingcontainer/v1/kubewaitingcontainer.proto +++ b/api/proto/teleport/kubewaitingcontainer/v1/kubewaitingcontainer.proto @@ -51,4 +51,6 @@ message KubernetesWaitingContainerSpec { // patch is the patch that should be applied to the parent pod // to create this ephemeral container bytes patch = 6; + // patch_type identifies the patch model to be applied. + string patch_type = 7; } diff --git a/api/types/kubewaitingcontainer/kubewaitingcontainer.go b/api/types/kubewaitingcontainer/kubewaitingcontainer.go index e1d2a4423fa..219b4d44097 100644 --- a/api/types/kubewaitingcontainer/kubewaitingcontainer.go +++ b/api/types/kubewaitingcontainer/kubewaitingcontainer.go @@ -17,6 +17,7 @@ limitations under the License. package kubewaitingcontainer import ( + "slices" "time" "github.com/gravitational/trace" @@ -27,6 +28,27 @@ import ( "github.com/gravitational/teleport/api/types" ) +const ( + // JSONPatchType is the JSON patch type supported by Kubernetes + JSONPatchType string = "application/json-patch+json" + // MergePatchType is the merge patch type supported by Kubernetes + MergePatchType string = "application/merge-patch+json" + // StrategicMergePatchType is the strategic merge patch type supported by Kubernetes + StrategicMergePatchType string = "application/strategic-merge-patch+json" + // ApplyPatchType is the apply patch type supported by Kubernetes + ApplyPatchType string = "application/apply-patch+yaml" +) + +var ( + // PatchTypes is a list of all supported patch types + PatchTypes = []string{ + JSONPatchType, + MergePatchType, + StrategicMergePatchType, + ApplyPatchType, + } +) + // NewKubeWaitingContainer creates a new Kubernetes ephemeral // container that are waiting to be created until moderated // session conditions are met. @@ -78,7 +100,12 @@ func ValidateKubeWaitingContainer(k *kubewaitingcontainerpb.KubernetesWaitingCon if len(k.Spec.Patch) == 0 { return trace.BadParameter("Patch is unset") } - + if len(k.Spec.PatchType) == 0 { + return trace.BadParameter("PatchType is unset") + } + if !slices.Contains(PatchTypes, k.Spec.PatchType) { + return trace.BadParameter("PatchType is invalid: valid types are %v", PatchTypes) + } if k.Metadata.Name == "" { return trace.BadParameter("Name is unset") } diff --git a/lib/auth/kubewaitingcontainer/service_test.go b/lib/auth/kubewaitingcontainer/service_test.go index 7ada52adeb1..9c660daa601 100644 --- a/lib/auth/kubewaitingcontainer/service_test.go +++ b/lib/auth/kubewaitingcontainer/service_test.go @@ -38,6 +38,7 @@ func TestKubeWaitingContainerServiceCRUD(t *testing.T) { const cluster = "cluster" const namespace = "default" const podName = "pod" + const patchType = kubewaitingcontainer.JSONPatchType sampleKubeWaitingContFn := func(t *testing.T, name string) *kubewaitingcontainerpb.KubernetesWaitingContainer { wc, err := kubewaitingcontainer.NewKubeWaitingContainer( @@ -49,6 +50,7 @@ func TestKubeWaitingContainerServiceCRUD(t *testing.T) { PodName: podName, ContainerName: name, Patch: []byte("patch"), + PatchType: patchType, }, ) require.NoError(t, err) @@ -130,6 +132,7 @@ func TestKubeWaitingContainerServiceCRUD(t *testing.T) { require.Equal(t, namespace, out.Spec.Namespace) require.Equal(t, podName, out.Spec.PodName) require.Equal(t, wcName, out.Spec.ContainerName) + require.Equal(t, patchType, out.Spec.PatchType) }, }, { @@ -186,6 +189,7 @@ func TestKubeWaitingContainerServiceCRUD(t *testing.T) { require.Equal(t, namespace, out.Spec.Namespace) require.Equal(t, podName, out.Spec.PodName) require.Equal(t, wcName, out.Spec.ContainerName) + require.Equal(t, patchType, out.Spec.PatchType) }, }, { diff --git a/lib/cache/cache_test.go b/lib/cache/cache_test.go index 18738f53dea..78c153d1370 100644 --- a/lib/cache/cache_test.go +++ b/lib/cache/cache_test.go @@ -3383,6 +3383,7 @@ func newKubeWaitingContainer(t *testing.T) types.Resource { PodName: "pod", ContainerName: "container", Patch: []byte("patch"), + PatchType: "application/json-patch+json", }) require.NoError(t, err)