apis/notebooks/v1alpha1/instance_identity.go (83 lines of code) (raw):

// Copyright 2025 Google LLC // // 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. package v1alpha1 import ( "context" "fmt" "strings" "github.com/GoogleCloudPlatform/k8s-config-connector/apis/common" refsv1beta1 "github.com/GoogleCloudPlatform/k8s-config-connector/apis/refs/v1beta1" "sigs.k8s.io/controller-runtime/pkg/client" ) // InstanceIdentity defines the resource reference to NotebookInstance, which "External" field // holds the GCP identifier for the KRM object. type InstanceIdentity struct { parent *InstanceParent id string } func (i *InstanceIdentity) String() string { return i.parent.String() + "/instances/" + i.id } func (i *InstanceIdentity) ID() string { return i.id } func (i *InstanceIdentity) Parent() *InstanceParent { return i.parent } type InstanceParent struct { ProjectID string Location string } func (p *InstanceParent) String() string { return "projects/" + p.ProjectID + "/locations/" + p.Location } // New builds a InstanceIdentity from the Config Connector Instance object. func NewInstanceIdentity(ctx context.Context, reader client.Reader, obj *NotebookInstance) (*InstanceIdentity, error) { // Get Parent projectRef, err := refsv1beta1.ResolveProject(ctx, reader, obj.GetNamespace(), obj.Spec.ProjectRef) if err != nil { return nil, err } projectID := projectRef.ProjectID if projectID == "" { return nil, fmt.Errorf("cannot resolve project") } location := obj.Spec.Zone // Get desired ID resourceID := common.ValueOf(obj.Spec.ResourceID) if resourceID == "" { resourceID = obj.GetName() } if resourceID == "" { return nil, fmt.Errorf("cannot resolve resource ID") } // Use approved External externalRef := common.ValueOf(obj.Status.ExternalRef) if externalRef != "" { // Validate desired with actual actualParent, actualResourceID, err := ParseInstanceExternal(externalRef) if err != nil { return nil, err } if actualParent.ProjectID != projectID { return nil, fmt.Errorf("spec.projectRef changed, expect %s, got %s", actualParent.ProjectID, projectID) } if actualParent.Location != location { return nil, fmt.Errorf("spec.zone changed, expect %s, got %s", actualParent.Location, location) } if actualResourceID != resourceID { return nil, fmt.Errorf("cannot reset `metadata.name` or `spec.resourceID` to %s, since it has already assigned to %s", resourceID, actualResourceID) } } return &InstanceIdentity{ parent: &InstanceParent{ ProjectID: projectID, Location: location, }, id: resourceID, }, nil } func ParseInstanceExternal(external string) (parent *InstanceParent, resourceID string, err error) { tokens := strings.Split(external, "/") if len(tokens) != 6 || tokens[0] != "projects" || tokens[2] != "locations" || tokens[4] != "instances" { return nil, "", fmt.Errorf("format of NotebookInstance external=%q was not known (use projects/{{projectID}}/locations/{{location}}/instances/{{instanceID}})", external) } parent = &InstanceParent{ ProjectID: tokens[1], Location: tokens[3], } resourceID = tokens[5] return parent, resourceID, nil }