From 8025026c5d3db09ae9b83a9d82726ad518ace5d4 Mon Sep 17 00:00:00 2001 From: olalekan odukoya Date: Sat, 8 Nov 2025 01:59:38 +0100 Subject: [PATCH] make intiator and terminator workspace URLs distinguishable Signed-off-by: olalekan odukoya --- .../crds/tenancy.kcp.io_workspacetypes.yaml | 8 ++ .../root-phase0/apiexport-tenancy.kcp.io.yaml | 2 +- ...eschema-workspacetypes.tenancy.kcp.io.yaml | 10 ++- pkg/openapi/zz_generated.openapi.go | 7 ++ .../workspacetype_controller_reconcile.go | 14 ++-- ...workspacetype_controller_reconcile_test.go | 77 +++++++++++++++---- .../tenancy/v1alpha1/types_workspacetype.go | 17 ++++ .../tenancy/v1alpha1/virtualworkspace.go | 15 +++- 8 files changed, 126 insertions(+), 24 deletions(-) diff --git a/config/crds/tenancy.kcp.io_workspacetypes.yaml b/config/crds/tenancy.kcp.io_workspacetypes.yaml index 6ab554bbb06..de313da9076 100644 --- a/config/crds/tenancy.kcp.io_workspacetypes.yaml +++ b/config/crds/tenancy.kcp.io_workspacetypes.yaml @@ -316,6 +316,14 @@ spec: URLs. items: properties: + type: + description: |- + type indicates whether this virtual workspace URL is for initializing + or terminating workspaces. + enum: + - initializing + - terminating + type: string url: description: url is a WorkspaceType initialization virtual workspace URL. diff --git a/config/root-phase0/apiexport-tenancy.kcp.io.yaml b/config/root-phase0/apiexport-tenancy.kcp.io.yaml index 7c54b938f44..cc0871be3c1 100644 --- a/config/root-phase0/apiexport-tenancy.kcp.io.yaml +++ b/config/root-phase0/apiexport-tenancy.kcp.io.yaml @@ -19,7 +19,7 @@ spec: crd: {} - group: tenancy.kcp.io name: workspacetypes - schema: v251015-1d163d0e5.workspacetypes.tenancy.kcp.io + schema: v251108-ed46a476c.workspacetypes.tenancy.kcp.io storage: crd: {} status: {} diff --git a/config/root-phase0/apiresourceschema-workspacetypes.tenancy.kcp.io.yaml b/config/root-phase0/apiresourceschema-workspacetypes.tenancy.kcp.io.yaml index 97c843ffbf4..378a6c75c78 100644 --- a/config/root-phase0/apiresourceschema-workspacetypes.tenancy.kcp.io.yaml +++ b/config/root-phase0/apiresourceschema-workspacetypes.tenancy.kcp.io.yaml @@ -2,7 +2,7 @@ apiVersion: apis.kcp.io/v1alpha1 kind: APIResourceSchema metadata: creationTimestamp: null - name: v251015-1d163d0e5.workspacetypes.tenancy.kcp.io + name: v251108-ed46a476c.workspacetypes.tenancy.kcp.io spec: group: tenancy.kcp.io names: @@ -313,6 +313,14 @@ spec: URLs. items: properties: + type: + description: |- + type indicates whether this virtual workspace URL is for initializing + or terminating workspaces. + enum: + - initializing + - terminating + type: string url: description: url is a WorkspaceType initialization virtual workspace URL. diff --git a/pkg/openapi/zz_generated.openapi.go b/pkg/openapi/zz_generated.openapi.go index 4c64c19c1e1..f295a26803f 100644 --- a/pkg/openapi/zz_generated.openapi.go +++ b/pkg/openapi/zz_generated.openapi.go @@ -4492,6 +4492,13 @@ func schema_sdk_apis_tenancy_v1alpha1_VirtualWorkspace(ref common.ReferenceCallb Format: "", }, }, + "type": { + SchemaProps: spec.SchemaProps{ + Description: "type indicates whether this virtual workspace URL is for initializing or terminating workspaces.", + Type: []string{"string"}, + Format: "", + }, + }, }, Required: []string{"url"}, }, diff --git a/pkg/reconciler/tenancy/workspacetype/workspacetype_controller_reconcile.go b/pkg/reconciler/tenancy/workspacetype/workspacetype_controller_reconcile.go index 8bbddc7243e..dd541bfeaa0 100644 --- a/pkg/reconciler/tenancy/workspacetype/workspacetype_controller_reconcile.go +++ b/pkg/reconciler/tenancy/workspacetype/workspacetype_controller_reconcile.go @@ -22,7 +22,6 @@ import ( "net/url" "path" - "k8s.io/apimachinery/pkg/util/sets" "k8s.io/klog/v2" "github.com/kcp-dev/sdk/apis/tenancy/initialization" @@ -63,7 +62,7 @@ func (c *controller) updateVirtualWorkspaceURLs(ctx context.Context, wt *tenancy return fmt.Errorf("error listing Shards: %w", err) } - desiredURLs := sets.New[string]() + desiredURLs := make(map[string]tenancyv1alpha1.VirtualWorkspaceType) for _, shard := range shards { if shard.Spec.VirtualWorkspaceURL == "" { continue @@ -85,9 +84,9 @@ func (c *controller) updateVirtualWorkspaceURLs(ctx context.Context, wt *tenancy string(initialization.InitializerForType(wt)), ) - desiredURLs.Insert(u.String()) + desiredURLs[u.String()] = tenancyv1alpha1.VirtualWorkspaceTypeInitializing - // add finalizing workspace URLs + // add terminating workspace URLs u.Path = path.Join( base, virtualworkspacesoptions.DefaultRootPathPrefix, @@ -95,14 +94,15 @@ func (c *controller) updateVirtualWorkspaceURLs(ctx context.Context, wt *tenancy string(termination.TerminatorForType(wt)), ) - desiredURLs.Insert(u.String()) + desiredURLs[u.String()] = tenancyv1alpha1.VirtualWorkspaceTypeTerminating } wt.Status.VirtualWorkspaces = nil - for _, u := range sets.List(desiredURLs) { + for url, typ := range desiredURLs { wt.Status.VirtualWorkspaces = append(wt.Status.VirtualWorkspaces, tenancyv1alpha1.VirtualWorkspace{ - URL: u, + URL: url, + Type: typ, }) } diff --git a/pkg/reconciler/tenancy/workspacetype/workspacetype_controller_reconcile_test.go b/pkg/reconciler/tenancy/workspacetype/workspacetype_controller_reconcile_test.go index bffd88c8447..6eb2d6d1a4e 100644 --- a/pkg/reconciler/tenancy/workspacetype/workspacetype_controller_reconcile_test.go +++ b/pkg/reconciler/tenancy/workspacetype/workspacetype_controller_reconcile_test.go @@ -137,12 +137,30 @@ func TestReconcile(t *testing.T) { }, Status: tenancyv1alpha1.WorkspaceTypeStatus{ VirtualWorkspaces: []tenancyv1alpha1.VirtualWorkspace{ - {URL: "https://item.com/services/initializingworkspaces/root:org:team:ws:sometype"}, - {URL: "https://item.com/services/terminatingworkspaces/root:org:team:ws:sometype"}, - {URL: "https://something.com/services/initializingworkspaces/root:org:team:ws:sometype"}, - {URL: "https://something.com/services/terminatingworkspaces/root:org:team:ws:sometype"}, - {URL: "https://whatever.com/services/initializingworkspaces/root:org:team:ws:sometype"}, - {URL: "https://whatever.com/services/terminatingworkspaces/root:org:team:ws:sometype"}, + { + URL: "https://item.com/services/initializingworkspaces/root:org:team:ws:sometype", + Type: tenancyv1alpha1.VirtualWorkspaceTypeInitializing, + }, + { + URL: "https://item.com/services/terminatingworkspaces/root:org:team:ws:sometype", + Type: tenancyv1alpha1.VirtualWorkspaceTypeTerminating, + }, + { + URL: "https://something.com/services/initializingworkspaces/root:org:team:ws:sometype", + Type: tenancyv1alpha1.VirtualWorkspaceTypeInitializing, + }, + { + URL: "https://something.com/services/terminatingworkspaces/root:org:team:ws:sometype", + Type: tenancyv1alpha1.VirtualWorkspaceTypeTerminating, + }, + { + URL: "https://whatever.com/services/initializingworkspaces/root:org:team:ws:sometype", + Type: tenancyv1alpha1.VirtualWorkspaceTypeInitializing, + }, + { + URL: "https://whatever.com/services/terminatingworkspaces/root:org:team:ws:sometype", + Type: tenancyv1alpha1.VirtualWorkspaceTypeTerminating, + }, }, Conditions: conditionsv1alpha1.Conditions{ { @@ -173,7 +191,10 @@ func TestReconcile(t *testing.T) { }, Status: tenancyv1alpha1.WorkspaceTypeStatus{ VirtualWorkspaces: []tenancyv1alpha1.VirtualWorkspace{ - {URL: "https://item.com/services/initializingworkspaces/root:org:team:ws:sometype"}, + { + URL: "https://item.com/services/initializingworkspaces/root:org:team:ws:sometype", + Type: tenancyv1alpha1.VirtualWorkspaceTypeInitializing, + }, }, Conditions: conditionsv1alpha1.Conditions{ { @@ -196,12 +217,30 @@ func TestReconcile(t *testing.T) { }, Status: tenancyv1alpha1.WorkspaceTypeStatus{ VirtualWorkspaces: []tenancyv1alpha1.VirtualWorkspace{ - {URL: "https://item.com/services/initializingworkspaces/root:org:team:ws:sometype"}, - {URL: "https://item.com/services/terminatingworkspaces/root:org:team:ws:sometype"}, - {URL: "https://something.com/services/initializingworkspaces/root:org:team:ws:sometype"}, - {URL: "https://something.com/services/terminatingworkspaces/root:org:team:ws:sometype"}, - {URL: "https://whatever.com/services/initializingworkspaces/root:org:team:ws:sometype"}, - {URL: "https://whatever.com/services/terminatingworkspaces/root:org:team:ws:sometype"}, + { + URL: "https://item.com/services/initializingworkspaces/root:org:team:ws:sometype", + Type: tenancyv1alpha1.VirtualWorkspaceTypeInitializing, + }, + { + URL: "https://item.com/services/terminatingworkspaces/root:org:team:ws:sometype", + Type: tenancyv1alpha1.VirtualWorkspaceTypeTerminating, + }, + { + URL: "https://something.com/services/initializingworkspaces/root:org:team:ws:sometype", + Type: tenancyv1alpha1.VirtualWorkspaceTypeInitializing, + }, + { + URL: "https://something.com/services/terminatingworkspaces/root:org:team:ws:sometype", + Type: tenancyv1alpha1.VirtualWorkspaceTypeTerminating, + }, + { + URL: "https://whatever.com/services/initializingworkspaces/root:org:team:ws:sometype", + Type: tenancyv1alpha1.VirtualWorkspaceTypeInitializing, + }, + { + URL: "https://whatever.com/services/terminatingworkspaces/root:org:team:ws:sometype", + Type: tenancyv1alpha1.VirtualWorkspaceTypeTerminating, + }, }, Conditions: conditionsv1alpha1.Conditions{ { @@ -237,7 +276,17 @@ func TestReconcile(t *testing.T) { } c.reconcile(context.TODO(), testCase.wt) c.reconcile(context.TODO(), testCase.wt) // relationships require resolved extensions - if diff := cmp.Diff(testCase.wt, testCase.expected, cmpopts.IgnoreTypes(metav1.Time{})); diff != "" { + if diff := cmp.Diff( + testCase.wt, + testCase.expected, + cmpopts.IgnoreTypes(metav1.Time{}), + cmpopts.SortSlices(func(a, b tenancyv1alpha1.VirtualWorkspace) bool { + if a.URL != b.URL { // SortSlices makes the comparison order-agnostic + return a.URL < b.URL + } + return a.Type < b.Type + }), + ); diff != "" { t.Errorf("incorrect WorkspaceType after reconciliation: %v", diff) } }) diff --git a/staging/src/github.com/kcp-dev/sdk/apis/tenancy/v1alpha1/types_workspacetype.go b/staging/src/github.com/kcp-dev/sdk/apis/tenancy/v1alpha1/types_workspacetype.go index c603e22c6da..f500dee3701 100644 --- a/staging/src/github.com/kcp-dev/sdk/apis/tenancy/v1alpha1/types_workspacetype.go +++ b/staging/src/github.com/kcp-dev/sdk/apis/tenancy/v1alpha1/types_workspacetype.go @@ -244,8 +244,25 @@ type VirtualWorkspace struct { // +kubebuilder:format:URL // +required URL string `json:"url"` + + // type indicates whether this virtual workspace URL is for initializing + // or terminating workspaces. + // + // +optional + // +kubebuilder:validation:Enum=initializing;terminating + Type VirtualWorkspaceType `json:"type,omitempty"` } +// VirtualWorkspaceType indicates the type of virtual workspace. +type VirtualWorkspaceType string + +const ( + // VirtualWorkspaceTypeInitializing indicates this is an initializing workspace URL. + VirtualWorkspaceTypeInitializing VirtualWorkspaceType = "initializing" + // VirtualWorkspaceTypeTerminating indicates this is a terminating workspace URL. + VirtualWorkspaceTypeTerminating VirtualWorkspaceType = "terminating" +) + func (in *WorkspaceType) GetConditions() conditionsv1alpha1.Conditions { return in.Status.Conditions } diff --git a/staging/src/github.com/kcp-dev/sdk/client/applyconfiguration/tenancy/v1alpha1/virtualworkspace.go b/staging/src/github.com/kcp-dev/sdk/client/applyconfiguration/tenancy/v1alpha1/virtualworkspace.go index 18ba0ac0144..1d834f41a9f 100644 --- a/staging/src/github.com/kcp-dev/sdk/client/applyconfiguration/tenancy/v1alpha1/virtualworkspace.go +++ b/staging/src/github.com/kcp-dev/sdk/client/applyconfiguration/tenancy/v1alpha1/virtualworkspace.go @@ -18,10 +18,15 @@ limitations under the License. package v1alpha1 +import ( + tenancyv1alpha1 "github.com/kcp-dev/sdk/apis/tenancy/v1alpha1" +) + // VirtualWorkspaceApplyConfiguration represents a declarative configuration of the VirtualWorkspace type for use // with apply. type VirtualWorkspaceApplyConfiguration struct { - URL *string `json:"url,omitempty"` + URL *string `json:"url,omitempty"` + Type *tenancyv1alpha1.VirtualWorkspaceType `json:"type,omitempty"` } // VirtualWorkspaceApplyConfiguration constructs a declarative configuration of the VirtualWorkspace type for use with @@ -37,3 +42,11 @@ func (b *VirtualWorkspaceApplyConfiguration) WithURL(value string) *VirtualWorks b.URL = &value return b } + +// WithType sets the Type field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Type field is set to the value of the last call. +func (b *VirtualWorkspaceApplyConfiguration) WithType(value tenancyv1alpha1.VirtualWorkspaceType) *VirtualWorkspaceApplyConfiguration { + b.Type = &value + return b +}