From c446d864df9ba85e8653d0009635e5073bda86ee Mon Sep 17 00:00:00 2001 From: Jason Vigil Date: Fri, 13 Dec 2024 19:15:40 +0000 Subject: [PATCH 1/7] feat: Generate Workstations types --- apis/workstations/v1alpha1/config_identity.go | 3 +- apis/workstations/v1alpha1/types.generated.go | 53 ++++ .../v1alpha1/workstation_identity.go | 141 +++++++++++ .../v1alpha1/workstation_reference.go | 83 ++++++ .../v1alpha1/workstation_types.go | 131 ++++++++++ .../v1alpha1/zz_generated.deepcopy.go | 239 ++++++++++++++++++ ...ns.workstations.cnrm.cloud.google.com.yaml | 217 ++++++++++++++++ dev/tools/controllerbuilder/generate.sh | 5 + pkg/gvks/supportedgvks/gvks_generated.go | 10 + 9 files changed, 880 insertions(+), 2 deletions(-) create mode 100644 apis/workstations/v1alpha1/workstation_identity.go create mode 100644 apis/workstations/v1alpha1/workstation_reference.go create mode 100644 apis/workstations/v1alpha1/workstation_types.go create mode 100644 config/crds/resources/apiextensions.k8s.io_v1_customresourcedefinition_workstations.workstations.cnrm.cloud.google.com.yaml diff --git a/apis/workstations/v1alpha1/config_identity.go b/apis/workstations/v1alpha1/config_identity.go index 8721b783df..7ea038fd91 100644 --- a/apis/workstations/v1alpha1/config_identity.go +++ b/apis/workstations/v1alpha1/config_identity.go @@ -23,8 +23,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" ) -// WorkstationConfigIdentity defines the resource reference to WorkstationConfig, which "External" field -// holds the GCP identifier for the KRM object. +// WorkstationConfigIdentity defines the resource reference to WorkstationConfig. type WorkstationConfigIdentity struct { parent *WorkstationConfigParent id string diff --git a/apis/workstations/v1alpha1/types.generated.go b/apis/workstations/v1alpha1/types.generated.go index e5add0428f..058344bcbd 100644 --- a/apis/workstations/v1alpha1/types.generated.go +++ b/apis/workstations/v1alpha1/types.generated.go @@ -530,4 +530,57 @@ type Status struct { // message types for APIs to use. Details []Any `json:"details,omitempty"` } + +// +kcc:proto=google.cloud.workstations.v1.Workstation +type Workstation struct { + // Full name of this workstation. + Name *string `json:"name,omitempty"` + + // Optional. Human-readable name for this workstation. + DisplayName *string `json:"displayName,omitempty"` + + // Output only. A system-assigned unique identifier for this workstation. + Uid *string `json:"uid,omitempty"` + + // Output only. Indicates whether this workstation is currently being updated + // to match its intended state. + Reconciling *bool `json:"reconciling,omitempty"` + + // Optional. Client-specified annotations. + Annotations map[string]string `json:"annotations,omitempty"` + + // Optional. + // [Labels](https://cloud.google.com/workstations/docs/label-resources) that + // are applied to the workstation and that are also propagated to the + // underlying Compute Engine resources. + Labels map[string]string `json:"labels,omitempty"` + + // Output only. Time when this workstation was created. + CreateTime *string `json:"createTime,omitempty"` + + // Output only. Time when this workstation was most recently updated. + UpdateTime *string `json:"updateTime,omitempty"` + + // Output only. Time when this workstation was most recently successfully + // started, regardless of the workstation's initial state. + StartTime *string `json:"startTime,omitempty"` + + // Output only. Time when this workstation was soft-deleted. + DeleteTime *string `json:"deleteTime,omitempty"` + + // Optional. Checksum computed by the server. May be sent on update and delete + // requests to make sure that the client has an up-to-date value before + // proceeding. + Etag *string `json:"etag,omitempty"` + + // Output only. Current state of the workstation. + State *string `json:"state,omitempty"` + + // Output only. Host to which clients can send HTTPS traffic that will be + // received by the workstation. Authorized traffic will be received to the + // workstation as HTTP on port 80. To send traffic to a different port, + // clients may prefix the host with the destination port in the format + // `{port}-{host}`. + Host *string `json:"host,omitempty"` +} */ diff --git a/apis/workstations/v1alpha1/workstation_identity.go b/apis/workstations/v1alpha1/workstation_identity.go new file mode 100644 index 0000000000..16cb819ce7 --- /dev/null +++ b/apis/workstations/v1alpha1/workstation_identity.go @@ -0,0 +1,141 @@ +// Copyright 2024 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" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +// WorkstationIdentity defines the resource reference to Workstation. +type WorkstationIdentity struct { + parent *WorkstationParent + id string +} + +func (i *WorkstationIdentity) String() string { + return i.parent.String() + "/workstations/" + i.id +} + +func (i *WorkstationIdentity) ID() string { + return i.id +} + +func (i *WorkstationIdentity) Parent() *WorkstationParent { + return i.parent +} + +type WorkstationParent struct { + ProjectID string + Location string + Cluster string + Config string +} + +func (p *WorkstationParent) String() string { + return "projects/" + p.ProjectID + "/locations/" + p.Location + "/workstationClusters/" + p.Cluster + "/workstationConfigs/" + p.Config +} + +// New builds a WorkstationIdentity from the Config Connector Workstation object. +func NewWorkstationIdentity(ctx context.Context, reader client.Reader, obj *Workstation) (*WorkstationIdentity, error) { + // Get Parent + configRef := obj.Spec.Parent + if configRef == nil { + return nil, fmt.Errorf("no parent config") + } + configExternal, err := configRef.NormalizedExternal(ctx, reader, obj.Namespace) + if err != nil { + return nil, fmt.Errorf("cannot resolve config: %w", err) + } + configParent, config, err := ParseWorkstationConfigExternal(configExternal) + if err != nil { + return nil, fmt.Errorf("cannot parse external config: %w", err) + } + projectID := configParent.ProjectID + if projectID == "" { + return nil, fmt.Errorf("cannot resolve project") + } + location := configParent.Location + if location == "" { + return nil, fmt.Errorf("cannot resolve location") + } + cluster := configParent.Cluster + if cluster == "" { + return nil, fmt.Errorf("cannot resolve cluster") + } + + // 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 := ParseWorkstationExternal(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.location changed, expect %s, got %s", actualParent.Location, location) + } + if actualParent.Cluster != cluster { + return nil, fmt.Errorf("spec.cluster changed, expect %s, got %s", actualParent.Cluster, cluster) + } + if actualParent.Config != config { + return nil, fmt.Errorf("spec.config changed, expect %s, got %s", actualParent.Config, config) + } + 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 &WorkstationIdentity{ + parent: &WorkstationParent{ + ProjectID: projectID, + Location: location, + Cluster: cluster, + Config: config, + }, + id: resourceID, + }, nil +} + +func ParseWorkstationExternal(external string) (parent *WorkstationParent, resourceID string, err error) { + tokens := strings.Split(external, "/") + if len(tokens) != 10 || tokens[0] != "projects" || tokens[2] != "locations" || tokens[4] != "workstationClusters" || tokens[6] != "workstationConfigs" || tokens[8] != "workstations" { + return nil, "", fmt.Errorf("format of Workstation external=%q was not known (use projects//locations//workstationClusters//workstationConfigs//workstations/)", external) + } + parent = &WorkstationParent{ + ProjectID: tokens[1], + Location: tokens[3], + Cluster: tokens[5], + Config: tokens[7], + } + resourceID = tokens[9] + return parent, resourceID, nil +} diff --git a/apis/workstations/v1alpha1/workstation_reference.go b/apis/workstations/v1alpha1/workstation_reference.go new file mode 100644 index 0000000000..ea9fe5101a --- /dev/null +++ b/apis/workstations/v1alpha1/workstation_reference.go @@ -0,0 +1,83 @@ +// Copyright 2024 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" + + refsv1beta1 "github.com/GoogleCloudPlatform/k8s-config-connector/apis/refs/v1beta1" + "github.com/GoogleCloudPlatform/k8s-config-connector/pkg/k8s" + apierrors "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +var _ refsv1beta1.ExternalNormalizer = &WorkstationRef{} + +// WorkstationRef defines the resource reference to Workstation, which "External" field +// holds the GCP identifier for the KRM object. +type WorkstationRef struct { + // A reference to an externally managed Workstation resource. + // Should be in the format "projects//locations//workstationClusters//workstationConfigs//workstations/". + External string `json:"external,omitempty"` + + // The name of a Workstation resource. + Name string `json:"name,omitempty"` + + // The namespace of a Workstation resource. + Namespace string `json:"namespace,omitempty"` +} + +// NormalizedExternal provision the "External" value for other resource that depends on Workstation. +// If the "External" is given in the other resource's spec.WorkstationRef, the given value will be used. +// Otherwise, the "Name" and "Namespace" will be used to query the actual Workstation object from the cluster. +func (r *WorkstationRef) NormalizedExternal(ctx context.Context, reader client.Reader, otherNamespace string) (string, error) { + if r.External != "" && r.Name != "" { + return "", fmt.Errorf("cannot specify both name and external on %s reference", WorkstationGVK.Kind) + } + // From given External + if r.External != "" { + if _, _, err := ParseWorkstationExternal(r.External); err != nil { + return "", err + } + return r.External, nil + } + + // From the Config Connector object + if r.Namespace == "" { + r.Namespace = otherNamespace + } + key := types.NamespacedName{Name: r.Name, Namespace: r.Namespace} + u := &unstructured.Unstructured{} + u.SetGroupVersionKind(WorkstationGVK) + if err := reader.Get(ctx, key, u); err != nil { + if apierrors.IsNotFound(err) { + return "", k8s.NewReferenceNotFoundError(u.GroupVersionKind(), key) + } + return "", fmt.Errorf("reading referenced %s %s: %w", WorkstationGVK, key, err) + } + // Get external from status.externalRef. This is the most trustworthy place. + actualExternalRef, _, err := unstructured.NestedString(u.Object, "status", "externalRef") + if err != nil { + return "", fmt.Errorf("reading status.externalRef: %w", err) + } + if actualExternalRef == "" { + return "", k8s.NewReferenceNotReadyError(u.GroupVersionKind(), key) + } + r.External = actualExternalRef + return r.External, nil +} diff --git a/apis/workstations/v1alpha1/workstation_types.go b/apis/workstations/v1alpha1/workstation_types.go new file mode 100644 index 0000000000..04eaecaf22 --- /dev/null +++ b/apis/workstations/v1alpha1/workstation_types.go @@ -0,0 +1,131 @@ +// Copyright 2024 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 ( + "github.com/GoogleCloudPlatform/k8s-config-connector/pkg/apis/k8s/v1alpha1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +var WorkstationGVK = GroupVersion.WithKind("Workstation") + +// WorkstationSpec defines the desired state of Workstation +// +kcc:proto=google.cloud.workstations.v1.Workstation +type WorkstationSpec struct { + // Parent is a reference to the parent WorkstationConfig for this Workstation. + Parent *WorkstationConfigRef `json:"parentRef"` + + // +kubebuilder:validation:XValidation:rule="self == oldSelf",message="ResourceID field is immutable" + // Immutable. + // The Workstation name. If not given, the metadata.name will be used. + ResourceID *string `json:"resourceID,omitempty"` + + // Optional. Human-readable name for this workstation. + DisplayName *string `json:"displayName,omitempty"` + + // Optional. Client-specified annotations. + Annotations []WorkstationAnnotation `json:"annotations,omitempty"` + + // Optional. + // [Labels](https://cloud.google.com/workstations/docs/label-resources) that + // are applied to the workstation and that are also propagated to the + // underlying Compute Engine resources. + Labels []WorkstationLabel `json:"labels,omitempty"` +} + +// WorkstationStatus defines the config connector machine state of Workstation +type WorkstationStatus struct { + /* Conditions represent the latest available observations of the + object's current state. */ + Conditions []v1alpha1.Condition `json:"conditions,omitempty"` + + // ObservedGeneration is the generation of the resource that was most recently observed by the Config Connector controller. If this is equal to metadata.generation, then that means that the current reported status reflects the most recent desired state of the resource. + ObservedGeneration *int64 `json:"observedGeneration,omitempty"` + + // A unique specifier for the Workstation resource in GCP. + ExternalRef *string `json:"externalRef,omitempty"` + + // ObservedState is the state of the resource as most recently observed in GCP. + ObservedState *WorkstationObservedState `json:"observedState,omitempty"` +} + +// WorkstationSpec defines the desired state of Workstation +// +kcc:proto=google.cloud.workstations.v1.Workstation +// WorkstationObservedState is the state of the Workstation resource as most recently observed in GCP. +type WorkstationObservedState struct { + // Output only. A system-assigned unique identifier for this workstation. + UID *string `json:"uid,omitempty"` + + // Output only. Time when this workstation was created. + CreateTime *string `json:"createTime,omitempty"` + + // Output only. Time when this workstation was most recently updated. + UpdateTime *string `json:"updateTime,omitempty"` + + // Output only. Time when this workstation was most recently successfully + // started, regardless of the workstation's initial state. + StartTime *string `json:"startTime,omitempty"` + + // Output only. Time when this workstation was soft-deleted. + DeleteTime *string `json:"deleteTime,omitempty"` + + // Output only. Checksum computed by the server. May be sent on update and + // delete requests to make sure that the client has an up-to-date value + // before proceeding. + Etag *string `json:"etag,omitempty"` + + // Output only. Current state of the workstation. + State *string `json:"state,omitempty"` + + // Output only. Host to which clients can send HTTPS traffic that will be + // received by the workstation. Authorized traffic will be received to the + // workstation as HTTP on port 80. To send traffic to a different port, + // clients may prefix the host with the destination port in the format + // `{port}-{host}`. + Host *string `json:"host,omitempty"` +} + +// +genclient +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object +// +kubebuilder:resource:categories=gcp,shortName=gcpworkstation;gcpworkstations +// +kubebuilder:subresource:status +// +kubebuilder:metadata:labels="cnrm.cloud.google.com/managed-by-kcc=true";"cnrm.cloud.google.com/system=true" +// +kubebuilder:printcolumn:name="Age",JSONPath=".metadata.creationTimestamp",type="date" +// +kubebuilder:printcolumn:name="Ready",JSONPath=".status.conditions[?(@.type=='Ready')].status",type="string",description="When 'True', the most recent reconcile of the resource succeeded" +// +kubebuilder:printcolumn:name="Status",JSONPath=".status.conditions[?(@.type=='Ready')].reason",type="string",description="The reason for the value in 'Ready'" +// +kubebuilder:printcolumn:name="Status Age",JSONPath=".status.conditions[?(@.type=='Ready')].lastTransitionTime",type="date",description="The last transition time for the value in 'Status'" + +// Workstation is the Schema for the Workstation API +// +k8s:openapi-gen=true +type Workstation struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + // +required + Spec WorkstationSpec `json:"spec,omitempty"` + Status WorkstationStatus `json:"status,omitempty"` +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object +// WorkstationList contains a list of Workstation +type WorkstationList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []Workstation `json:"items"` +} + +func init() { + SchemeBuilder.Register(&Workstation{}, &WorkstationList{}) +} diff --git a/apis/workstations/v1alpha1/zz_generated.deepcopy.go b/apis/workstations/v1alpha1/zz_generated.deepcopy.go index 2812dc9670..04974bafa7 100644 --- a/apis/workstations/v1alpha1/zz_generated.deepcopy.go +++ b/apis/workstations/v1alpha1/zz_generated.deepcopy.go @@ -24,6 +24,33 @@ import ( runtime "k8s.io/apimachinery/pkg/runtime" ) +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Workstation) DeepCopyInto(out *Workstation) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Workstation. +func (in *Workstation) DeepCopy() *Workstation { + if in == nil { + return nil + } + out := new(Workstation) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *Workstation) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *WorkstationAnnotation) DeepCopyInto(out *WorkstationAnnotation) { *out = *in @@ -938,6 +965,26 @@ func (in *WorkstationConfig_ReadinessCheck) DeepCopy() *WorkstationConfig_Readin return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *WorkstationIdentity) DeepCopyInto(out *WorkstationIdentity) { + *out = *in + if in.parent != nil { + in, out := &in.parent, &out.parent + *out = new(WorkstationParent) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new WorkstationIdentity. +func (in *WorkstationIdentity) DeepCopy() *WorkstationIdentity { + if in == nil { + return nil + } + out := new(WorkstationIdentity) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *WorkstationLabel) DeepCopyInto(out *WorkstationLabel) { *out = *in @@ -953,6 +1000,123 @@ func (in *WorkstationLabel) DeepCopy() *WorkstationLabel { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *WorkstationList) DeepCopyInto(out *WorkstationList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]Workstation, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new WorkstationList. +func (in *WorkstationList) DeepCopy() *WorkstationList { + if in == nil { + return nil + } + out := new(WorkstationList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *WorkstationList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *WorkstationObservedState) DeepCopyInto(out *WorkstationObservedState) { + *out = *in + if in.UID != nil { + in, out := &in.UID, &out.UID + *out = new(string) + **out = **in + } + if in.CreateTime != nil { + in, out := &in.CreateTime, &out.CreateTime + *out = new(string) + **out = **in + } + if in.UpdateTime != nil { + in, out := &in.UpdateTime, &out.UpdateTime + *out = new(string) + **out = **in + } + if in.StartTime != nil { + in, out := &in.StartTime, &out.StartTime + *out = new(string) + **out = **in + } + if in.DeleteTime != nil { + in, out := &in.DeleteTime, &out.DeleteTime + *out = new(string) + **out = **in + } + if in.Etag != nil { + in, out := &in.Etag, &out.Etag + *out = new(string) + **out = **in + } + if in.State != nil { + in, out := &in.State, &out.State + *out = new(string) + **out = **in + } + if in.Host != nil { + in, out := &in.Host, &out.Host + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new WorkstationObservedState. +func (in *WorkstationObservedState) DeepCopy() *WorkstationObservedState { + if in == nil { + return nil + } + out := new(WorkstationObservedState) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *WorkstationParent) DeepCopyInto(out *WorkstationParent) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new WorkstationParent. +func (in *WorkstationParent) DeepCopy() *WorkstationParent { + if in == nil { + return nil + } + out := new(WorkstationParent) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *WorkstationRef) DeepCopyInto(out *WorkstationRef) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new WorkstationRef. +func (in *WorkstationRef) DeepCopy() *WorkstationRef { + if in == nil { + return nil + } + out := new(WorkstationRef) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *WorkstationServiceGCPCondition) DeepCopyInto(out *WorkstationServiceGCPCondition) { *out = *in @@ -977,3 +1141,78 @@ func (in *WorkstationServiceGCPCondition) DeepCopy() *WorkstationServiceGCPCondi in.DeepCopyInto(out) return out } + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *WorkstationSpec) DeepCopyInto(out *WorkstationSpec) { + *out = *in + if in.Parent != nil { + in, out := &in.Parent, &out.Parent + *out = new(WorkstationConfigRef) + **out = **in + } + if in.ResourceID != nil { + in, out := &in.ResourceID, &out.ResourceID + *out = new(string) + **out = **in + } + if in.DisplayName != nil { + in, out := &in.DisplayName, &out.DisplayName + *out = new(string) + **out = **in + } + if in.Annotations != nil { + in, out := &in.Annotations, &out.Annotations + *out = make([]WorkstationAnnotation, len(*in)) + copy(*out, *in) + } + if in.Labels != nil { + in, out := &in.Labels, &out.Labels + *out = make([]WorkstationLabel, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new WorkstationSpec. +func (in *WorkstationSpec) DeepCopy() *WorkstationSpec { + if in == nil { + return nil + } + out := new(WorkstationSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *WorkstationStatus) DeepCopyInto(out *WorkstationStatus) { + *out = *in + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]k8sv1alpha1.Condition, len(*in)) + copy(*out, *in) + } + if in.ObservedGeneration != nil { + in, out := &in.ObservedGeneration, &out.ObservedGeneration + *out = new(int64) + **out = **in + } + if in.ExternalRef != nil { + in, out := &in.ExternalRef, &out.ExternalRef + *out = new(string) + **out = **in + } + if in.ObservedState != nil { + in, out := &in.ObservedState, &out.ObservedState + *out = new(WorkstationObservedState) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new WorkstationStatus. +func (in *WorkstationStatus) DeepCopy() *WorkstationStatus { + if in == nil { + return nil + } + out := new(WorkstationStatus) + in.DeepCopyInto(out) + return out +} diff --git a/config/crds/resources/apiextensions.k8s.io_v1_customresourcedefinition_workstations.workstations.cnrm.cloud.google.com.yaml b/config/crds/resources/apiextensions.k8s.io_v1_customresourcedefinition_workstations.workstations.cnrm.cloud.google.com.yaml new file mode 100644 index 0000000000..b7d420f4b8 --- /dev/null +++ b/config/crds/resources/apiextensions.k8s.io_v1_customresourcedefinition_workstations.workstations.cnrm.cloud.google.com.yaml @@ -0,0 +1,217 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + cnrm.cloud.google.com/version: 0.0.0-dev + creationTimestamp: null + labels: + cnrm.cloud.google.com/managed-by-kcc: "true" + cnrm.cloud.google.com/system: "true" + name: workstations.workstations.cnrm.cloud.google.com +spec: + group: workstations.cnrm.cloud.google.com + names: + categories: + - gcp + kind: Workstation + listKind: WorkstationList + plural: workstations + shortNames: + - gcpworkstation + - gcpworkstations + singular: workstation + preserveUnknownFields: false + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + - description: When 'True', the most recent reconcile of the resource succeeded + jsonPath: .status.conditions[?(@.type=='Ready')].status + name: Ready + type: string + - description: The reason for the value in 'Ready' + jsonPath: .status.conditions[?(@.type=='Ready')].reason + name: Status + type: string + - description: The last transition time for the value in 'Status' + jsonPath: .status.conditions[?(@.type=='Ready')].lastTransitionTime + name: Status Age + type: date + name: v1alpha1 + schema: + openAPIV3Schema: + description: Workstation is the Schema for the Workstation API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: WorkstationSpec defines the desired state of Workstation + properties: + annotations: + description: Optional. Client-specified annotations. + items: + properties: + key: + description: Key for the annotation. + type: string + value: + description: Value for the annotation. + type: string + type: object + type: array + displayName: + description: Optional. Human-readable name for this workstation. + type: string + labels: + description: Optional. [Labels](https://cloud.google.com/workstations/docs/label-resources) + that are applied to the workstation and that are also propagated + to the underlying Compute Engine resources. + items: + properties: + key: + description: Key for the label. + type: string + value: + description: Value for the label. + type: string + type: object + type: array + parentRef: + description: Parent is a reference to the parent WorkstationConfig + for this Workstation. + oneOf: + - not: + required: + - external + required: + - name + - not: + anyOf: + - required: + - name + - required: + - namespace + required: + - external + properties: + external: + description: A reference to an externally managed WorkstationConfig + resource. Should be in the format "projects//locations//workstationClusters//workstationConfigs/". + type: string + name: + description: The name of a WorkstationConfig resource. + type: string + namespace: + description: The namespace of a WorkstationConfig resource. + type: string + type: object + resourceID: + description: Immutable. The Workstation name. If not given, the metadata.name + will be used. + type: string + x-kubernetes-validations: + - message: ResourceID field is immutable + rule: self == oldSelf + required: + - parentRef + type: object + status: + description: WorkstationStatus defines the config connector machine state + of Workstation + properties: + conditions: + description: Conditions represent the latest available observations + of the object's current state. + items: + properties: + lastTransitionTime: + description: Last time the condition transitioned from one status + to another. + type: string + message: + description: Human-readable message indicating details about + last transition. + type: string + reason: + description: Unique, one-word, CamelCase reason for the condition's + last transition. + type: string + status: + description: Status is the status of the condition. Can be True, + False, Unknown. + type: string + type: + description: Type is the type of the condition. + type: string + type: object + type: array + externalRef: + description: A unique specifier for the Workstation resource in GCP. + type: string + observedGeneration: + description: ObservedGeneration is the generation of the resource + that was most recently observed by the Config Connector controller. + If this is equal to metadata.generation, then that means that the + current reported status reflects the most recent desired state of + the resource. + format: int64 + type: integer + observedState: + description: ObservedState is the state of the resource as most recently + observed in GCP. + properties: + createTime: + description: Output only. Time when this workstation was created. + type: string + deleteTime: + description: Output only. Time when this workstation was soft-deleted. + type: string + etag: + description: Output only. Checksum computed by the server. May + be sent on update and delete requests to make sure that the + client has an up-to-date value before proceeding. + type: string + host: + description: Output only. Host to which clients can send HTTPS + traffic that will be received by the workstation. Authorized + traffic will be received to the workstation as HTTP on port + 80. To send traffic to a different port, clients may prefix + the host with the destination port in the format `{port}-{host}`. + type: string + startTime: + description: Output only. Time when this workstation was most + recently successfully started, regardless of the workstation's + initial state. + type: string + state: + description: Output only. Current state of the workstation. + type: string + uid: + description: Output only. A system-assigned unique identifier + for this workstation. + type: string + updateTime: + description: Output only. Time when this workstation was most + recently updated. + type: string + type: object + type: object + required: + - spec + type: object + served: true + storage: true + subresources: + status: {} diff --git a/dev/tools/controllerbuilder/generate.sh b/dev/tools/controllerbuilder/generate.sh index 80ce03b7d8..832710034b 100755 --- a/dev/tools/controllerbuilder/generate.sh +++ b/dev/tools/controllerbuilder/generate.sh @@ -148,6 +148,11 @@ go run . generate-types \ --api-version workstations.cnrm.cloud.google.com/v1alpha1 \ --resource WorkstationConfig:WorkstationConfig +go run . generate-types \ + --service google.cloud.workstations.v1 \ + --api-version workstations.cnrm.cloud.google.com/v1alpha1 \ + --resource Workstation:Workstation + go run . generate-mapper \ --service google.cloud.workstations.v1 \ --api-version workstations.cnrm.cloud.google.com/v1beta1 diff --git a/pkg/gvks/supportedgvks/gvks_generated.go b/pkg/gvks/supportedgvks/gvks_generated.go index a7d44d8495..50e7d765ac 100644 --- a/pkg/gvks/supportedgvks/gvks_generated.go +++ b/pkg/gvks/supportedgvks/gvks_generated.go @@ -4497,4 +4497,14 @@ var SupportedGVKs = map[schema.GroupVersionKind]GVKMetadata{ "cnrm.cloud.google.com/managed-by-kcc": "true", "cnrm.cloud.google.com/system": "true", }, + }, + { + Group: "workstations.cnrm.cloud.google.com", + Version: "v1alpha1", + Kind: "Workstation", + }: { + Labels: map[string]string{ + "cnrm.cloud.google.com/managed-by-kcc": "true", + "cnrm.cloud.google.com/system": "true", + }, }} From 2289a1ac60303fa36b4e2711ef632bdc838415fc Mon Sep 17 00:00:00 2001 From: Jason Vigil Date: Thu, 5 Dec 2024 17:51:18 +0000 Subject: [PATCH 2/7] feat: Add workstation mappings --- .../direct/workstations/mapper.generated.go | 60 +++++++++++++++ .../workstations/workstation_mappings.go | 75 +++++++++++++++++++ 2 files changed, 135 insertions(+) create mode 100644 pkg/controller/direct/workstations/workstation_mappings.go diff --git a/pkg/controller/direct/workstations/mapper.generated.go b/pkg/controller/direct/workstations/mapper.generated.go index ea54f656f1..11caaee8f0 100644 --- a/pkg/controller/direct/workstations/mapper.generated.go +++ b/pkg/controller/direct/workstations/mapper.generated.go @@ -386,4 +386,64 @@ func WorkstationConfig_ReadinessCheck_ToProto(mapCtx *direct.MapContext, in *krm out.Port = direct.ValueOf(in.Port) return out } +func WorkstationObservedState_FromProto(mapCtx *direct.MapContext, in *pb.Workstation) *krm.WorkstationObservedState { + if in == nil { + return nil + } + out := &krm.WorkstationObservedState{} + // MISSING: Name + // MISSING: Uid + // MISSING: Reconciling + out.CreateTime = direct.StringTimestamp_FromProto(mapCtx, in.GetCreateTime()) + out.UpdateTime = direct.StringTimestamp_FromProto(mapCtx, in.GetUpdateTime()) + out.StartTime = direct.StringTimestamp_FromProto(mapCtx, in.GetStartTime()) + out.DeleteTime = direct.StringTimestamp_FromProto(mapCtx, in.GetDeleteTime()) + out.Etag = direct.LazyPtr(in.GetEtag()) + out.State = direct.Enum_FromProto(mapCtx, in.GetState()) + out.Host = direct.LazyPtr(in.GetHost()) + return out +} +func WorkstationObservedState_ToProto(mapCtx *direct.MapContext, in *krm.WorkstationObservedState) *pb.Workstation { + if in == nil { + return nil + } + out := &pb.Workstation{} + // MISSING: Name + // MISSING: Uid + // MISSING: Reconciling + out.CreateTime = direct.StringTimestamp_ToProto(mapCtx, in.CreateTime) + out.UpdateTime = direct.StringTimestamp_ToProto(mapCtx, in.UpdateTime) + out.StartTime = direct.StringTimestamp_ToProto(mapCtx, in.StartTime) + out.DeleteTime = direct.StringTimestamp_ToProto(mapCtx, in.DeleteTime) + out.Etag = direct.ValueOf(in.Etag) + out.State = direct.Enum_ToProto[pb.Workstation_State](mapCtx, in.State) + out.Host = direct.ValueOf(in.Host) + return out +} +func WorkstationSpec_FromProto(mapCtx *direct.MapContext, in *pb.Workstation) *krm.WorkstationSpec { + if in == nil { + return nil + } + out := &krm.WorkstationSpec{} + // MISSING: Name + out.DisplayName = direct.LazyPtr(in.GetDisplayName()) + // MISSING: Uid + // MISSING: Reconciling + out.Annotations = in.Annotations + out.Labels = in.Labels + return out +} +func WorkstationSpec_ToProto(mapCtx *direct.MapContext, in *krm.WorkstationSpec) *pb.Workstation { + if in == nil { + return nil + } + out := &pb.Workstation{} + // MISSING: Name + out.DisplayName = direct.ValueOf(in.DisplayName) + // MISSING: Uid + // MISSING: Reconciling + out.Annotations = in.Annotations + out.Labels = in.Labels + return out +} */ diff --git a/pkg/controller/direct/workstations/workstation_mappings.go b/pkg/controller/direct/workstations/workstation_mappings.go new file mode 100644 index 0000000000..aafc953062 --- /dev/null +++ b/pkg/controller/direct/workstations/workstation_mappings.go @@ -0,0 +1,75 @@ +// Copyright 2024 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 workstations + +import ( + pb "cloud.google.com/go/workstations/apiv1/workstationspb" + krm "github.com/GoogleCloudPlatform/k8s-config-connector/apis/workstations/v1alpha1" + "github.com/GoogleCloudPlatform/k8s-config-connector/pkg/controller/direct" +) + +func WorkstationObservedState_FromProto(mapCtx *direct.MapContext, in *pb.Workstation) *krm.WorkstationObservedState { + if in == nil { + return nil + } + out := &krm.WorkstationObservedState{} + out.UID = direct.LazyPtr(in.GetUid()) + out.CreateTime = direct.StringTimestamp_FromProto(mapCtx, in.GetCreateTime()) + out.UpdateTime = direct.StringTimestamp_FromProto(mapCtx, in.GetUpdateTime()) + out.StartTime = direct.StringTimestamp_FromProto(mapCtx, in.GetStartTime()) + out.DeleteTime = direct.StringTimestamp_FromProto(mapCtx, in.GetDeleteTime()) + out.Etag = direct.LazyPtr(in.GetEtag()) + out.State = direct.Enum_FromProto(mapCtx, in.GetState()) + out.Host = direct.LazyPtr(in.GetHost()) + return out +} + +func WorkstationObservedState_ToProto(mapCtx *direct.MapContext, in *krm.WorkstationObservedState) *pb.Workstation { + if in == nil { + return nil + } + out := &pb.Workstation{} + out.Uid = direct.ValueOf(in.UID) + out.CreateTime = direct.StringTimestamp_ToProto(mapCtx, in.CreateTime) + out.UpdateTime = direct.StringTimestamp_ToProto(mapCtx, in.UpdateTime) + out.StartTime = direct.StringTimestamp_ToProto(mapCtx, in.StartTime) + out.DeleteTime = direct.StringTimestamp_ToProto(mapCtx, in.DeleteTime) + out.Etag = direct.ValueOf(in.Etag) + out.State = direct.Enum_ToProto[pb.Workstation_State](mapCtx, in.State) + out.Host = direct.ValueOf(in.Host) + return out +} + +func WorkstationSpec_FromProto(mapCtx *direct.MapContext, in *pb.Workstation) *krm.WorkstationSpec { + if in == nil { + return nil + } + out := &krm.WorkstationSpec{} + out.DisplayName = direct.LazyPtr(in.GetDisplayName()) + out.Annotations = WorkstationAnnotations_FromProto_Alpha(mapCtx, in.Annotations) + out.Labels = WorkstationLabels_FromProto_Alpha(mapCtx, in.Labels) + return out +} + +func WorkstationSpec_ToProto(mapCtx *direct.MapContext, in *krm.WorkstationSpec) *pb.Workstation { + if in == nil { + return nil + } + out := &pb.Workstation{} + out.DisplayName = direct.ValueOf(in.DisplayName) + out.Annotations = WorkstationAnnotations_ToProto_Alpha(mapCtx, in.Annotations) + out.Labels = WorkstationLabels_ToProto_Alpha(mapCtx, in.Labels) + return out +} From 9963a30171b6b6384ad88711598c35a8e7b0240c Mon Sep 17 00:00:00 2001 From: Jason Vigil Date: Thu, 5 Dec 2024 20:23:39 +0000 Subject: [PATCH 3/7] feat: Add Workstation controller, record GCP --- .../direct/workstations/config_controller.go | 4 +- .../workstations/workstation_controller.go | 256 +++ ...erated_object_workstation-full.golden.yaml | 40 + .../workstation/workstation-full/_http.log | 1463 +++++++++++++++++ .../workstation/workstation-full/create.yaml | 28 + .../workstation-full/dependencies.yaml | 52 + .../workstation/workstation-full/update.yaml | 32 + ...ted_object_workstation-minimal.golden.yaml | 30 + .../workstation/workstation-minimal/_http.log | 1388 ++++++++++++++++ .../workstation-minimal/create.yaml | 22 + .../workstation-minimal/dependencies.yaml | 52 + 11 files changed, 3365 insertions(+), 2 deletions(-) create mode 100644 pkg/controller/direct/workstations/workstation_controller.go create mode 100644 pkg/test/resourcefixture/testdata/basic/workstations/workstation/workstation-full/_generated_object_workstation-full.golden.yaml create mode 100644 pkg/test/resourcefixture/testdata/basic/workstations/workstation/workstation-full/_http.log create mode 100644 pkg/test/resourcefixture/testdata/basic/workstations/workstation/workstation-full/create.yaml create mode 100644 pkg/test/resourcefixture/testdata/basic/workstations/workstation/workstation-full/dependencies.yaml create mode 100644 pkg/test/resourcefixture/testdata/basic/workstations/workstation/workstation-full/update.yaml create mode 100644 pkg/test/resourcefixture/testdata/basic/workstations/workstation/workstation-minimal/_generated_object_workstation-minimal.golden.yaml create mode 100644 pkg/test/resourcefixture/testdata/basic/workstations/workstation/workstation-minimal/_http.log create mode 100644 pkg/test/resourcefixture/testdata/basic/workstations/workstation/workstation-minimal/create.yaml create mode 100644 pkg/test/resourcefixture/testdata/basic/workstations/workstation/workstation-minimal/dependencies.yaml diff --git a/pkg/controller/direct/workstations/config_controller.go b/pkg/controller/direct/workstations/config_controller.go index 9e7f2ec0ae..b55118a1dc 100644 --- a/pkg/controller/direct/workstations/config_controller.go +++ b/pkg/controller/direct/workstations/config_controller.go @@ -151,7 +151,7 @@ func (a *WorkstationConfigAdapter) Create(ctx context.Context, createOp *directb } created, err := op.Wait(ctx) if err != nil { - return fmt.Errorf("WorkstationConfig %s waiting creation: %w", a.id.String(), err) + return fmt.Errorf("waiting WorkstationConfig %s creation: %w", a.id.String(), err) } log.V(2).Info("successfully created WorkstationConfig", "name", a.id.String()) @@ -209,7 +209,7 @@ func (a *WorkstationConfigAdapter) Update(ctx context.Context, updateOp *directb } updated, err := op.Wait(ctx) if err != nil { - return fmt.Errorf("WorkstationConfig %s waiting update: %w", a.id.String(), err) + return fmt.Errorf("waiting WorkstationConfig %s update: %w", a.id.String(), err) } log.V(2).Info("successfully updated WorkstationConfig", "name", a.id.String()) diff --git a/pkg/controller/direct/workstations/workstation_controller.go b/pkg/controller/direct/workstations/workstation_controller.go new file mode 100644 index 0000000000..3d6657dce4 --- /dev/null +++ b/pkg/controller/direct/workstations/workstation_controller.go @@ -0,0 +1,256 @@ +// Copyright 2024 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 workstations + +import ( + "context" + "fmt" + + krm "github.com/GoogleCloudPlatform/k8s-config-connector/apis/workstations/v1alpha1" + "github.com/GoogleCloudPlatform/k8s-config-connector/pkg/config" + "github.com/GoogleCloudPlatform/k8s-config-connector/pkg/controller/direct" + "github.com/GoogleCloudPlatform/k8s-config-connector/pkg/controller/direct/common" + "github.com/GoogleCloudPlatform/k8s-config-connector/pkg/controller/direct/directbase" + "github.com/GoogleCloudPlatform/k8s-config-connector/pkg/controller/direct/registry" + + gcp "cloud.google.com/go/workstations/apiv1" + "cloud.google.com/go/workstations/apiv1/workstationspb" + "google.golang.org/api/option" + "google.golang.org/protobuf/types/known/fieldmaskpb" + + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/util/sets" + "k8s.io/klog/v2" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +func init() { + registry.RegisterModel(krm.WorkstationGVK, NewWorkstationModel) +} + +func NewWorkstationModel(ctx context.Context, config *config.ControllerConfig) (directbase.Model, error) { + return &modelWorkstation{config: *config}, nil +} + +var _ directbase.Model = &modelWorkstation{} + +type modelWorkstation struct { + config config.ControllerConfig +} + +func (m *modelWorkstation) client(ctx context.Context) (*gcp.Client, error) { + var opts []option.ClientOption + opts, err := m.config.RESTClientOptions() + if err != nil { + return nil, err + } + gcpClient, err := gcp.NewRESTClient(ctx, opts...) + if err != nil { + return nil, fmt.Errorf("building Workstation client: %w", err) + } + return gcpClient, err +} + +func (m *modelWorkstation) AdapterForObject(ctx context.Context, reader client.Reader, u *unstructured.Unstructured) (directbase.Adapter, error) { + obj := &krm.Workstation{} + if err := runtime.DefaultUnstructuredConverter.FromUnstructured(u.Object, &obj); err != nil { + return nil, fmt.Errorf("error converting to %T: %w", obj, err) + } + + id, err := krm.NewWorkstationIdentity(ctx, reader, obj) + if err != nil { + return nil, err + } + + // Get workstations GCP client + gcpClient, err := m.client(ctx) + if err != nil { + return nil, err + } + return &WorkstationAdapter{ + id: id, + gcpClient: gcpClient, + desired: obj, + }, nil +} + +func (m *modelWorkstation) AdapterForURL(ctx context.Context, url string) (directbase.Adapter, error) { + // TODO: Support URLs + return nil, nil +} + +type WorkstationAdapter struct { + id *krm.WorkstationIdentity + gcpClient *gcp.Client + desired *krm.Workstation + actual *workstationspb.Workstation +} + +var _ directbase.Adapter = &WorkstationAdapter{} + +// Find retrieves the GCP resource. +// Return true means the object is found. This triggers Adapter `Update` call. +// Return true means the object is not found. This triggers Adapter `Create` call. +// Return a non-nil error requeues the requests. +func (a *WorkstationAdapter) Find(ctx context.Context) (bool, error) { + log := klog.FromContext(ctx) + log.V(2).Info("getting Workstation", "name", a.id) + + req := &workstationspb.GetWorkstationRequest{Name: a.id.String()} + workstationpb, err := a.gcpClient.GetWorkstation(ctx, req) + if err != nil { + if direct.IsNotFound(err) { + return false, nil + } + return false, fmt.Errorf("getting Workstation %q: %w", a.id, err) + } + + a.actual = workstationpb + return true, nil +} + +// Create creates the resource in GCP based on `spec` and update the Config Connector object `status` based on the GCP response. +func (a *WorkstationAdapter) Create(ctx context.Context, createOp *directbase.CreateOperation) error { + log := klog.FromContext(ctx) + log.V(2).Info("creating Workstation", "name", a.id) + mapCtx := &direct.MapContext{} + + desired := a.desired.DeepCopy() + resource := WorkstationSpec_ToProto(mapCtx, &desired.Spec) + if mapCtx.Err() != nil { + return mapCtx.Err() + } + + req := &workstationspb.CreateWorkstationRequest{ + Parent: a.id.Parent().String(), + WorkstationId: a.id.ID(), + Workstation: resource, + } + op, err := a.gcpClient.CreateWorkstation(ctx, req) + if err != nil { + return fmt.Errorf("creating Workstation %s: %w", a.id, err) + } + created, err := op.Wait(ctx) + if err != nil { + return fmt.Errorf("waiting Workstation %s creation: %w", a.id.String(), err) + } + log.V(2).Info("successfully created Workstation", "name", a.id) + + status := &krm.WorkstationStatus{} + status.ObservedState = WorkstationObservedState_FromProto(mapCtx, created) + if mapCtx.Err() != nil { + return mapCtx.Err() + } + status.ExternalRef = direct.PtrTo(a.id.String()) + return createOp.UpdateStatus(ctx, status, nil) +} + +// Update updates the resource in GCP based on `spec` and update the Config Connector object `status` based on the GCP response. +func (a *WorkstationAdapter) Update(ctx context.Context, updateOp *directbase.UpdateOperation) error { + log := klog.FromContext(ctx) + log.V(2).Info("updating Workstation", "name", a.id) + mapCtx := &direct.MapContext{} + + desiredPb := WorkstationSpec_ToProto(mapCtx, &a.desired.DeepCopy().Spec) + if mapCtx.Err() != nil { + return mapCtx.Err() + } + + // Set name and etag manually, because they are not filled-in by WorkstationConfigSpec_ToProto. + desiredPb.Name = a.id.String() + desiredPb.Etag = a.actual.Etag + + paths, err := common.CompareProtoMessage(desiredPb, a.actual, common.BasicDiff) + if err != nil { + return err + } + if len(paths) == 0 { + log.V(2).Info("no field needs update", "name", a.id.String()) + status := &krm.WorkstationStatus{} + status.ObservedState = WorkstationObservedState_FromProto(mapCtx, a.actual) + if mapCtx.Err() != nil { + return mapCtx.Err() + } + return updateOp.UpdateStatus(ctx, status, nil) + } + updateMask := &fieldmaskpb.FieldMask{Paths: sets.List(paths)} + + req := &workstationspb.UpdateWorkstationRequest{ + Workstation: desiredPb, + UpdateMask: updateMask, + } + op, err := a.gcpClient.UpdateWorkstation(ctx, req) + if err != nil { + return fmt.Errorf("updating Workstation %s: %w", a.id.String(), err) + } + updated, err := op.Wait(ctx) + if err != nil { + return fmt.Errorf("waiting Workstation %s update: %w", a.id.String(), err) + } + log.V(2).Info("successfully updated Workstation", "name", a.id.String()) + + status := &krm.WorkstationStatus{} + status.ObservedState = WorkstationObservedState_FromProto(mapCtx, updated) + if mapCtx.Err() != nil { + return mapCtx.Err() + } + return updateOp.UpdateStatus(ctx, status, nil) +} + +// Export maps the GCP object to a Config Connector resource `spec`. +func (a *WorkstationAdapter) Export(ctx context.Context) (*unstructured.Unstructured, error) { + if a.actual == nil { + return nil, fmt.Errorf("Find() not called") + } + u := &unstructured.Unstructured{} + + obj := &krm.Workstation{} + mapCtx := &direct.MapContext{} + obj.Spec = direct.ValueOf(WorkstationSpec_FromProto(mapCtx, a.actual)) + if mapCtx.Err() != nil { + return nil, mapCtx.Err() + } + obj.Spec.Parent = &krm.WorkstationConfigRef{External: a.id.Parent().String()} + uObj, err := runtime.DefaultUnstructuredConverter.ToUnstructured(obj) + if err != nil { + return nil, err + } + + u.SetName(a.id.ID()) + u.SetGroupVersionKind(krm.WorkstationGVK) + + u.Object = uObj + return u, nil +} + +// Delete the resource from GCP service when the corresponding Config Connector resource is deleted. +func (a *WorkstationAdapter) Delete(ctx context.Context, deleteOp *directbase.DeleteOperation) (bool, error) { + log := klog.FromContext(ctx) + log.V(2).Info("deleting Workstation", "name", a.id) + + req := &workstationspb.DeleteWorkstationRequest{Name: a.id.String()} + op, err := a.gcpClient.DeleteWorkstation(ctx, req) + if err != nil { + return false, fmt.Errorf("deleting Workstation %s: %w", a.id, err) + } + log.V(2).Info("successfully deleted Workstation", "name", a.id) + + _, err = op.Wait(ctx) + if err != nil { + return false, fmt.Errorf("waiting delete Workstation %s: %w", a.id, err) + } + return true, nil +} diff --git a/pkg/test/resourcefixture/testdata/basic/workstations/workstation/workstation-full/_generated_object_workstation-full.golden.yaml b/pkg/test/resourcefixture/testdata/basic/workstations/workstation/workstation-full/_generated_object_workstation-full.golden.yaml new file mode 100644 index 0000000000..7d1168b79d --- /dev/null +++ b/pkg/test/resourcefixture/testdata/basic/workstations/workstation/workstation-full/_generated_object_workstation-full.golden.yaml @@ -0,0 +1,40 @@ +apiVersion: workstations.cnrm.cloud.google.com/v1alpha1 +kind: Workstation +metadata: + finalizers: + - cnrm.cloud.google.com/finalizer + - cnrm.cloud.google.com/deletion-defender + generation: 2 + labels: + cnrm-test: "true" + name: workstation-${uniqueId} + namespace: ${uniqueId} +spec: + annotations: + - key: a-key1 + value: a-value1 + - key: a-key2 + value: a-value2 + displayName: workstation-${uniqueId} + labels: + - key: l-key1 + value: l-value1 + - key: l-key2 + value: l-value2 + parentRef: + name: workstationconfig-${uniqueId} +status: + conditions: + - lastTransitionTime: "1970-01-01T00:00:00Z" + message: The resource is up to date + reason: UpToDate + status: "True" + type: Ready + externalRef: projects/${projectId}/locations/us-west1/workstationClusters/workstationcluster-${uniqueId}/workstationConfigs/workstationconfig-${uniqueId}/workstations/workstation-${uniqueId} + observedGeneration: 2 + observedState: + createTime: "1970-01-01T00:00:00Z" + etag: abcdef123456 + state: STATE_STOPPED + uid: 0123456789abcdef + updateTime: "1970-01-01T00:00:00Z" diff --git a/pkg/test/resourcefixture/testdata/basic/workstations/workstation/workstation-full/_http.log b/pkg/test/resourcefixture/testdata/basic/workstations/workstation/workstation-full/_http.log new file mode 100644 index 0000000000..74a484a489 --- /dev/null +++ b/pkg/test/resourcefixture/testdata/basic/workstations/workstation/workstation-full/_http.log @@ -0,0 +1,1463 @@ +GET https://compute.googleapis.com/compute/v1/projects/${projectId}/global/networks/${networkID}?alt=json +Content-Type: application/json +User-Agent: Terraform/ (+https://www.terraform.io) Terraform-Plugin-SDK/2.10.1 terraform-provider-google-beta/kcc/controller-manager + +404 Not Found +Cache-Control: private +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "error": { + "code": 404, + "errors": [ + { + "domain": "global", + "message": "The resource 'projects/${projectId}/global/networks/computenetwork-${uniqueId}' was not found", + "reason": "notFound" + } + ], + "message": "The resource 'projects/${projectId}/global/networks/computenetwork-${uniqueId}' was not found" + } +} + +--- + +POST https://compute.googleapis.com/compute/v1/projects/${projectId}/global/networks?alt=json +Content-Type: application/json +User-Agent: Terraform/ (+https://www.terraform.io) Terraform-Plugin-SDK/2.10.1 terraform-provider-google-beta/kcc/controller-manager + +{ + "autoCreateSubnetworks": false, + "name": "computenetwork-${uniqueId}", + "networkFirewallPolicyEnforcementOrder": "AFTER_CLASSIC_FIREWALL", + "routingConfig": { + "routingMode": "GLOBAL" + } +} + +200 OK +Cache-Control: private +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "id": "000000000000000000000", + "insertTime": "2024-04-01T12:34:56.123456Z", + "kind": "compute#operation", + "name": "${operationID}", + "operationType": "insert", + "progress": 0, + "selfLink": "https://www.googleapis.com/compute/v1/projects/${projectId}/global/operations/${operationID}", + "startTime": "2024-04-01T12:34:56.123456Z", + "status": "RUNNING", + "targetId": "${networkID}", + "targetLink": "https://www.googleapis.com/compute/v1/projects/${projectId}/global/networks/computenetwork-${uniqueId}", + "user": "user@example.com" +} + +--- + +GET https://compute.googleapis.com/compute/v1/projects/${projectId}/global/operations/${operationID}?alt=json&prettyPrint=false +User-Agent: google-api-go-client/0.5 Terraform/ (+https://www.terraform.io) Terraform-Plugin-SDK/2.10.1 terraform-provider-google-beta/kcc/controller-manager + +200 OK +Cache-Control: private +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "endTime": "2024-04-01T12:34:56.123456Z", + "id": "000000000000000000000", + "insertTime": "2024-04-01T12:34:56.123456Z", + "kind": "compute#operation", + "name": "${operationID}", + "operationType": "insert", + "progress": 100, + "selfLink": "https://www.googleapis.com/compute/v1/projects/${projectId}/global/operations/${operationID}", + "startTime": "2024-04-01T12:34:56.123456Z", + "status": "DONE", + "targetId": "${networkID}", + "targetLink": "https://www.googleapis.com/compute/v1/projects/${projectId}/global/networks/computenetwork-${uniqueId}", + "user": "user@example.com" +} + +--- + +GET https://compute.googleapis.com/compute/v1/projects/${projectId}/global/networks/${networkID}?alt=json +Content-Type: application/json +User-Agent: Terraform/ (+https://www.terraform.io) Terraform-Plugin-SDK/2.10.1 terraform-provider-google-beta/kcc/controller-manager + +200 OK +Cache-Control: private +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "autoCreateSubnetworks": false, + "creationTimestamp": "2024-04-01T12:34:56.123456Z", + "id": "000000000000000000000", + "kind": "compute#network", + "name": "computenetwork-${uniqueId}", + "networkFirewallPolicyEnforcementOrder": "AFTER_CLASSIC_FIREWALL", + "routingConfig": { + "bgpBestPathSelectionMode": "LEGACY", + "routingMode": "GLOBAL" + }, + "selfLink": "https://www.googleapis.com/compute/v1/projects/${projectId}/global/networks/computenetwork-${uniqueId}", + "selfLinkWithId": "https://www.googleapis.com/compute/v1/projects/${projectId}/global/networks/${networkID}" +} + +--- + +GET https://compute.googleapis.com/compute/v1/projects/${projectId}/regions/us-west1/subnetworks/${subnetworkID}?alt=json +Content-Type: application/json +User-Agent: Terraform/ (+https://www.terraform.io) Terraform-Plugin-SDK/2.10.1 terraform-provider-google-beta/kcc/controller-manager + +404 Not Found +Cache-Control: private +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "error": { + "code": 404, + "errors": [ + { + "domain": "global", + "message": "The resource 'projects/${projectId}/regions/us-west1/subnetworks/computesubnetwork-${uniqueId}' was not found", + "reason": "notFound" + } + ], + "message": "The resource 'projects/${projectId}/regions/us-west1/subnetworks/computesubnetwork-${uniqueId}' was not found" + } +} + +--- + +POST https://compute.googleapis.com/compute/v1/projects/${projectId}/regions/us-west1/subnetworks?alt=json +Content-Type: application/json +User-Agent: Terraform/ (+https://www.terraform.io) Terraform-Plugin-SDK/2.10.1 terraform-provider-google-beta/kcc/controller-manager + +{ + "ipCidrRange": "10.0.0.0/24", + "logConfig": { + "enable": false + }, + "name": "computesubnetwork-${uniqueId}", + "network": "projects/${projectId}/global/networks/computenetwork-${uniqueId}", + "region": "projects/${projectId}/global/regions/us-west1" +} + +200 OK +Cache-Control: private +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "id": "000000000000000000000", + "insertTime": "2024-04-01T12:34:56.123456Z", + "kind": "compute#operation", + "name": "${operationID}", + "operationType": "insert", + "progress": 0, + "region": "https://www.googleapis.com/compute/v1/projects/${projectId}/regions/us-west1", + "selfLink": "https://www.googleapis.com/compute/v1/projects/${projectId}/regions/us-west1/operations/${operationID}", + "startTime": "2024-04-01T12:34:56.123456Z", + "status": "RUNNING", + "targetId": "${subnetworkID}", + "targetLink": "https://www.googleapis.com/compute/v1/projects/${projectId}/regions/us-west1/subnetworks/computesubnetwork-${uniqueId}", + "user": "user@example.com" +} + +--- + +GET https://compute.googleapis.com/compute/v1/projects/${projectId}/regions/us-west1/operations/${operationID}?alt=json&prettyPrint=false +User-Agent: google-api-go-client/0.5 Terraform/ (+https://www.terraform.io) Terraform-Plugin-SDK/2.10.1 terraform-provider-google-beta/kcc/controller-manager + +200 OK +Cache-Control: private +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "endTime": "2024-04-01T12:34:56.123456Z", + "id": "000000000000000000000", + "insertTime": "2024-04-01T12:34:56.123456Z", + "kind": "compute#operation", + "name": "${operationID}", + "operationType": "insert", + "progress": 100, + "region": "https://www.googleapis.com/compute/v1/projects/${projectId}/regions/us-west1", + "selfLink": "https://www.googleapis.com/compute/v1/projects/${projectId}/regions/us-west1/operations/${operationID}", + "startTime": "2024-04-01T12:34:56.123456Z", + "status": "DONE", + "targetId": "${subnetworkID}", + "targetLink": "https://www.googleapis.com/compute/v1/projects/${projectId}/regions/us-west1/subnetworks/computesubnetwork-${uniqueId}", + "user": "user@example.com" +} + +--- + +GET https://compute.googleapis.com/compute/v1/projects/${projectId}/regions/us-west1/subnetworks/${subnetworkID}?alt=json +Content-Type: application/json +User-Agent: Terraform/ (+https://www.terraform.io) Terraform-Plugin-SDK/2.10.1 terraform-provider-google-beta/kcc/controller-manager + +200 OK +Cache-Control: private +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "allowSubnetCidrRoutesOverlap": false, + "creationTimestamp": "2024-04-01T12:34:56.123456Z", + "enableFlowLogs": false, + "fingerprint": "abcdef0123A=", + "gatewayAddress": "10.0.0.1", + "id": "000000000000000000000", + "ipCidrRange": "10.0.0.0/24", + "kind": "compute#subnetwork", + "logConfig": { + "enable": false + }, + "name": "computesubnetwork-${uniqueId}", + "network": "https://www.googleapis.com/compute/v1/projects/${projectId}/global/networks/computenetwork-${uniqueId}", + "privateIpGoogleAccess": false, + "privateIpv6GoogleAccess": "DISABLE_GOOGLE_ACCESS", + "purpose": "PRIVATE", + "region": "https://www.googleapis.com/compute/v1/projects/${projectId}/regions/us-west1", + "selfLink": "https://www.googleapis.com/compute/v1/projects/${projectId}/regions/us-west1/subnetworks/computesubnetwork-${uniqueId}", + "stackType": "IPV4_ONLY" +} + +--- + +GET https://workstations.googleapis.com/v1/projects/${projectId}/locations/us-west1/workstationClusters/workstationcluster-${uniqueId}?%24alt=json%3Benum-encoding%3Dint +Content-Type: application/json +User-Agent: kcc/controller-manager +x-goog-request-params: name=projects%2F${projectId}%2Flocations%2Fus-west1%2FworkstationClusters%2Fworkstationcluster-${uniqueId} + +404 Not Found +Cache-Control: private +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "error": { + "code": 404, + "message": "Resource 'projects/${projectId}/locations/us-west1/workstationClusters/workstationcluster-${uniqueId}' was not found", + "status": "NOT_FOUND" + } +} + +--- + +POST https://workstations.googleapis.com/v1/projects/${projectId}/locations/us-west1/workstationClusters?%24alt=json%3Benum-encoding%3Dint&workstationClusterId=workstationcluster-${uniqueId} +Content-Type: application/json +User-Agent: kcc/controller-manager +x-goog-request-params: parent=projects%2F${projectId}%2Flocations%2Fus-west1 + +{ + "network": "projects/${projectId}/global/networks/computenetwork-${uniqueId}", + "subnetwork": "projects/${projectId}/regions/us-west1/subnetworks/computesubnetwork-${uniqueId}" +} + +200 OK +Cache-Control: private +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "done": false, + "metadata": { + "@type": "type.googleapis.com/google.cloud.workstations.v1.OperationMetadata", + "apiVersion": "v1", + "createTime": "2024-04-01T12:34:56.123456Z", + "requestedCancellation": false, + "target": "projects/${projectId}/locations/us-west1/workstationClusters/workstationcluster-${uniqueId}", + "verb": "create" + }, + "name": "projects/${projectId}/locations/us-west1/operations/${operationID}" +} + +--- + +GET https://compute.googleapis.com/compute/v1/projects/${projectId}/global/networks/${networkID}?alt=json +Content-Type: application/json +User-Agent: Terraform/ (+https://www.terraform.io) Terraform-Plugin-SDK/2.10.1 terraform-provider-google-beta/kcc/controller-manager + +200 OK +Cache-Control: private +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "autoCreateSubnetworks": false, + "creationTimestamp": "2024-04-01T12:34:56.123456Z", + "id": "000000000000000000000", + "kind": "compute#network", + "name": "computenetwork-${uniqueId}", + "networkFirewallPolicyEnforcementOrder": "AFTER_CLASSIC_FIREWALL", + "routingConfig": { + "bgpBestPathSelectionMode": "LEGACY", + "routingMode": "GLOBAL" + }, + "selfLink": "https://www.googleapis.com/compute/v1/projects/${projectId}/global/networks/computenetwork-${uniqueId}", + "selfLinkWithId": "https://www.googleapis.com/compute/v1/projects/${projectId}/global/networks/${networkID}", + "subnetworks": [ + "https://www.googleapis.com/compute/v1/projects/${projectId}/regions/us-west1/subnetworks/computesubnetwork-${uniqueId}" + ] +} + +--- + +GET https://compute.googleapis.com/compute/v1/projects/${projectId}/regions/us-west1/subnetworks/${subnetworkID}?alt=json +Content-Type: application/json +User-Agent: Terraform/ (+https://www.terraform.io) Terraform-Plugin-SDK/2.10.1 terraform-provider-google-beta/kcc/controller-manager + +200 OK +Cache-Control: private +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "allowSubnetCidrRoutesOverlap": false, + "creationTimestamp": "2024-04-01T12:34:56.123456Z", + "enableFlowLogs": false, + "fingerprint": "abcdef0123A=", + "gatewayAddress": "10.0.0.1", + "id": "000000000000000000000", + "ipCidrRange": "10.0.0.0/24", + "kind": "compute#subnetwork", + "logConfig": { + "enable": false + }, + "name": "computesubnetwork-${uniqueId}", + "network": "https://www.googleapis.com/compute/v1/projects/${projectId}/global/networks/computenetwork-${uniqueId}", + "privateIpGoogleAccess": false, + "privateIpv6GoogleAccess": "DISABLE_GOOGLE_ACCESS", + "purpose": "PRIVATE", + "region": "https://www.googleapis.com/compute/v1/projects/${projectId}/regions/us-west1", + "selfLink": "https://www.googleapis.com/compute/v1/projects/${projectId}/regions/us-west1/subnetworks/computesubnetwork-${uniqueId}", + "stackType": "IPV4_ONLY" +} + +--- + +GET https://compute.googleapis.com/compute/v1/projects/${projectId}/global/networks/${networkID}?alt=json +Content-Type: application/json +User-Agent: Terraform/ (+https://www.terraform.io) Terraform-Plugin-SDK/2.10.1 terraform-provider-google-beta/kcc/controller-manager + +200 OK +Cache-Control: private +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "autoCreateSubnetworks": false, + "creationTimestamp": "2024-04-01T12:34:56.123456Z", + "id": "000000000000000000000", + "kind": "compute#network", + "name": "computenetwork-${uniqueId}", + "networkFirewallPolicyEnforcementOrder": "AFTER_CLASSIC_FIREWALL", + "routingConfig": { + "bgpBestPathSelectionMode": "LEGACY", + "routingMode": "GLOBAL" + }, + "selfLink": "https://www.googleapis.com/compute/v1/projects/${projectId}/global/networks/computenetwork-${uniqueId}", + "selfLinkWithId": "https://www.googleapis.com/compute/v1/projects/${projectId}/global/networks/${networkID}", + "subnetworks": [ + "https://www.googleapis.com/compute/v1/projects/${projectId}/regions/us-west1/subnetworks/computesubnetwork-${uniqueId}" + ] +} + +--- + +GET https://workstations.googleapis.com/v1/projects/${projectId}/locations/us-west1/operations/${operationID} +Content-Type: application/json +User-Agent: kcc/controller-manager +x-goog-request-params: name=projects%2F${projectId}%2Flocations%2Fus-west1%2Foperations%2F${operationID} + +200 OK +Cache-Control: private +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "done": true, + "metadata": { + "@type": "type.googleapis.com/google.cloud.workstations.v1.OperationMetadata", + "apiVersion": "v1", + "createTime": "2024-04-01T12:34:56.123456Z", + "endTime": "2024-04-01T12:34:56.123456Z", + "requestedCancellation": false, + "target": "projects/${projectId}/locations/us-west1/workstationClusters/workstationcluster-${uniqueId}", + "verb": "create" + }, + "name": "projects/${projectId}/locations/us-west1/operations/${operationID}", + "response": { + "@type": "type.googleapis.com/google.cloud.workstations.v1.WorkstationCluster", + "controlPlaneIp": "10.0.0.2", + "createTime": "2024-04-01T12:34:56.123456Z", + "etag": "abcdef0123A=", + "name": "projects/${projectId}/locations/us-west1/workstationClusters/workstationcluster-${uniqueId}", + "network": "projects/${projectId}/global/networks/computenetwork-${uniqueId}", + "privateClusterConfig": {}, + "subnetwork": "projects/${projectId}/regions/us-west1/subnetworks/computesubnetwork-${uniqueId}", + "uid": "111111111111111111111", + "updateTime": "2024-04-01T12:34:56.123456Z" + } +} + +--- + +GET https://workstations.googleapis.com/v1/projects/${projectId}/locations/us-west1/workstationClusters/workstationcluster-${uniqueId}/workstationConfigs/workstationconfig-${uniqueId}?%24alt=json%3Benum-encoding%3Dint +Content-Type: application/json +User-Agent: kcc/controller-manager +x-goog-request-params: name=projects%2F${projectId}%2Flocations%2Fus-west1%2FworkstationClusters%2Fworkstationcluster-${uniqueId}%2FworkstationConfigs%2Fworkstationconfig-${uniqueId} + +404 Not Found +Cache-Control: private +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "error": { + "code": 404, + "message": "Resource 'projects/${projectId}/locations/us-west1/workstationClusters/workstationcluster-${uniqueId}/workstationConfigs/workstationconfig-${uniqueId}' was not found", + "status": "NOT_FOUND" + } +} + +--- + +POST https://workstations.googleapis.com/v1/projects/${projectId}/locations/us-west1/workstationClusters/workstationcluster-${uniqueId}/workstationConfigs?%24alt=json%3Benum-encoding%3Dint&workstationConfigId=workstationconfig-${uniqueId} +Content-Type: application/json +User-Agent: kcc/controller-manager +x-goog-request-params: parent=projects%2F${projectId}%2Flocations%2Fus-west1%2FworkstationClusters%2Fworkstationcluster-${uniqueId} + +{ + "idleTimeout": "1200s", + "runningTimeout": "43200s" +} + +200 OK +Cache-Control: private +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "done": false, + "metadata": { + "@type": "type.googleapis.com/google.cloud.workstations.v1.OperationMetadata", + "apiVersion": "v1", + "createTime": "2024-04-01T12:34:56.123456Z", + "requestedCancellation": false, + "target": "projects/${projectId}/locations/us-west1/workstationClusters/workstationcluster-${uniqueId}/workstationConfigs/workstationconfig-${uniqueId}", + "verb": "create" + }, + "name": "projects/${projectId}/locations/us-west1/operations/${operationID}" +} + +--- + +GET https://workstations.googleapis.com/v1/projects/${projectId}/locations/us-west1/operations/${operationID} +Content-Type: application/json +User-Agent: kcc/controller-manager +x-goog-request-params: name=projects%2F${projectId}%2Flocations%2Fus-west1%2Foperations%2F${operationID} + +200 OK +Cache-Control: private +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "done": true, + "metadata": { + "@type": "type.googleapis.com/google.cloud.workstations.v1.OperationMetadata", + "apiVersion": "v1", + "createTime": "2024-04-01T12:34:56.123456Z", + "endTime": "2024-04-01T12:34:56.123456Z", + "requestedCancellation": false, + "target": "projects/${projectId}/locations/us-west1/workstationClusters/workstationcluster-${uniqueId}/workstationConfigs/workstationconfig-${uniqueId}", + "verb": "create" + }, + "name": "projects/${projectId}/locations/us-west1/operations/${operationID}", + "response": { + "@type": "type.googleapis.com/google.cloud.workstations.v1.WorkstationConfig", + "allowedPorts": [ + { + "first": 22, + "last": 22 + }, + { + "first": 80, + "last": 80 + }, + { + "first": 1024, + "last": 65535 + } + ], + "container": { + "image": "us-west1-docker.pkg.dev/cloud-workstations-images/predefined/code-oss:latest" + }, + "createTime": "2024-04-01T12:34:56.123456Z", + "etag": "abcdef0123A=", + "host": { + "gceInstance": { + "bootDiskSizeGb": 50, + "confidentialInstanceConfig": {}, + "machineType": "e2-standard-4", + "serviceAccount": "service-${projectNumber}@gcp-sa-workstationsvm.iam.gserviceaccount.com", + "shieldedInstanceConfig": {} + } + }, + "idleTimeout": "1200s", + "name": "projects/${projectId}/locations/us-west1/workstationClusters/workstationcluster-${uniqueId}/workstationConfigs/workstationconfig-${uniqueId}", + "replicaZones": [ + "us-west1-a", + "us-west1-b" + ], + "runningTimeout": "43200s", + "uid": "111111111111111111111", + "updateTime": "2024-04-01T12:34:56.123456Z" + } +} + +--- + +GET https://workstations.googleapis.com/v1/projects/${projectId}/locations/us-west1/workstationClusters/workstationcluster-${uniqueId}/workstationConfigs/workstationconfig-${uniqueId}/workstations/workstation-${uniqueId}?%24alt=json%3Benum-encoding%3Dint +Content-Type: application/json +User-Agent: kcc/controller-manager +x-goog-request-params: name=projects%2F${projectId}%2Flocations%2Fus-west1%2FworkstationClusters%2Fworkstationcluster-${uniqueId}%2FworkstationConfigs%2Fworkstationconfig-${uniqueId}%2Fworkstations%2Fworkstation-${uniqueId} + +404 Not Found +Cache-Control: private +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "error": { + "code": 404, + "message": "Resource 'projects/${projectId}/locations/us-west1/workstationClusters/workstationcluster-${uniqueId}/workstationConfigs/workstationconfig-${uniqueId}/workstations/workstation-${uniqueId}' was not found", + "status": "NOT_FOUND" + } +} + +--- + +POST https://workstations.googleapis.com/v1/projects/${projectId}/locations/us-west1/workstationClusters/workstationcluster-${uniqueId}/workstationConfigs/workstationconfig-${uniqueId}/workstations?%24alt=json%3Benum-encoding%3Dint&workstationId=workstation-${uniqueId} +Content-Type: application/json +User-Agent: kcc/controller-manager +x-goog-request-params: parent=projects%2F${projectId}%2Flocations%2Fus-west1%2FworkstationClusters%2Fworkstationcluster-${uniqueId}%2FworkstationConfigs%2Fworkstationconfig-${uniqueId} + +{ + "annotations": { + "a-key1": "a-value1" + }, + "displayName": "workstation-${uniqueId}", + "labels": { + "l-key1": "l-value1" + } +} + +200 OK +Cache-Control: private +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "done": false, + "metadata": { + "@type": "type.googleapis.com/google.cloud.workstations.v1.OperationMetadata", + "apiVersion": "v1", + "createTime": "2024-04-01T12:34:56.123456Z", + "requestedCancellation": false, + "target": "projects/${projectId}/locations/us-west1/workstationClusters/workstationcluster-${uniqueId}/workstationConfigs/workstationconfig-${uniqueId}/workstations/workstation-${uniqueId}", + "verb": "create" + }, + "name": "projects/${projectId}/locations/us-west1/operations/${operationID}" +} + +--- + +GET https://workstations.googleapis.com/v1/projects/${projectId}/locations/us-west1/operations/${operationID} +Content-Type: application/json +User-Agent: kcc/controller-manager +x-goog-request-params: name=projects%2F${projectId}%2Flocations%2Fus-west1%2Foperations%2F${operationID} + +200 OK +Cache-Control: private +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "done": true, + "metadata": { + "@type": "type.googleapis.com/google.cloud.workstations.v1.OperationMetadata", + "apiVersion": "v1", + "createTime": "2024-04-01T12:34:56.123456Z", + "endTime": "2024-04-01T12:34:56.123456Z", + "requestedCancellation": false, + "target": "projects/${projectId}/locations/us-west1/workstationClusters/workstationcluster-${uniqueId}/workstationConfigs/workstationconfig-${uniqueId}/workstations/workstation-${uniqueId}", + "verb": "create" + }, + "name": "projects/${projectId}/locations/us-west1/operations/${operationID}", + "response": { + "@type": "type.googleapis.com/google.cloud.workstations.v1.Workstation", + "annotations": { + "a-key1": "a-value1" + }, + "createTime": "2024-04-01T12:34:56.123456Z", + "displayName": "workstation-${uniqueId}", + "etag": "abcdef0123A=", + "labels": { + "l-key1": "l-value1" + }, + "name": "projects/${projectId}/locations/us-west1/workstationClusters/workstationcluster-${uniqueId}/workstationConfigs/workstationconfig-${uniqueId}/workstations/workstation-${uniqueId}", + "state": "STATE_STOPPED", + "uid": "111111111111111111111", + "updateTime": "2024-04-01T12:34:56.123456Z" + } +} + +--- + +GET https://workstations.googleapis.com/v1/projects/${projectId}/locations/us-west1/workstationClusters/workstationcluster-${uniqueId}/workstationConfigs/workstationconfig-${uniqueId}/workstations/workstation-${uniqueId}?%24alt=json%3Benum-encoding%3Dint +Content-Type: application/json +User-Agent: kcc/controller-manager +x-goog-request-params: name=projects%2F${projectId}%2Flocations%2Fus-west1%2FworkstationClusters%2Fworkstationcluster-${uniqueId}%2FworkstationConfigs%2Fworkstationconfig-${uniqueId}%2Fworkstations%2Fworkstation-${uniqueId} + +200 OK +Cache-Control: private +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "annotations": { + "a-key1": "a-value1" + }, + "createTime": "2024-04-01T12:34:56.123456Z", + "displayName": "workstation-${uniqueId}", + "etag": "abcdef0123A=", + "labels": { + "l-key1": "l-value1" + }, + "name": "projects/${projectId}/locations/us-west1/workstationClusters/workstationcluster-${uniqueId}/workstationConfigs/workstationconfig-${uniqueId}/workstations/workstation-${uniqueId}", + "state": 4, + "uid": "111111111111111111111", + "updateTime": "2024-04-01T12:34:56.123456Z" +} + +--- + +PATCH https://workstations.googleapis.com/v1/projects/${projectId}/locations/us-west1/workstationClusters/workstationcluster-${uniqueId}/workstationConfigs/workstationconfig-${uniqueId}/workstations/workstation-${uniqueId}?%24alt=json%3Benum-encoding%3Dint&updateMask=annotations%2Clabels +Content-Type: application/json +User-Agent: kcc/controller-manager +x-goog-request-params: workstation.name=projects%2F${projectId}%2Flocations%2Fus-west1%2FworkstationClusters%2Fworkstationcluster-${uniqueId}%2FworkstationConfigs%2Fworkstationconfig-${uniqueId}%2Fworkstations%2Fworkstation-${uniqueId} + +{ + "annotations": { + "a-key1": "a-value1", + "a-key2": "a-value2" + }, + "displayName": "workstation-${uniqueId}", + "etag": "abcdef0123A=", + "labels": { + "l-key1": "l-value1", + "l-key2": "l-value2" + }, + "name": "projects/${projectId}/locations/us-west1/workstationClusters/workstationcluster-${uniqueId}/workstationConfigs/workstationconfig-${uniqueId}/workstations/workstation-${uniqueId}" +} + +200 OK +Cache-Control: private +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "done": false, + "metadata": { + "@type": "type.googleapis.com/google.cloud.workstations.v1.OperationMetadata", + "apiVersion": "v1", + "createTime": "2024-04-01T12:34:56.123456Z", + "requestedCancellation": false, + "target": "projects/${projectId}/locations/us-west1/workstationClusters/workstationcluster-${uniqueId}/workstationConfigs/workstationconfig-${uniqueId}/workstations/workstation-${uniqueId}", + "verb": "update" + }, + "name": "projects/${projectId}/locations/us-west1/operations/${operationID}" +} + +--- + +GET https://workstations.googleapis.com/v1/projects/${projectId}/locations/us-west1/operations/${operationID} +Content-Type: application/json +User-Agent: kcc/controller-manager +x-goog-request-params: name=projects%2F${projectId}%2Flocations%2Fus-west1%2Foperations%2F${operationID} + +200 OK +Cache-Control: private +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "done": true, + "metadata": { + "@type": "type.googleapis.com/google.cloud.workstations.v1.OperationMetadata", + "apiVersion": "v1", + "createTime": "2024-04-01T12:34:56.123456Z", + "endTime": "2024-04-01T12:34:56.123456Z", + "requestedCancellation": false, + "target": "projects/${projectId}/locations/us-west1/workstationClusters/workstationcluster-${uniqueId}/workstationConfigs/workstationconfig-${uniqueId}/workstations/workstation-${uniqueId}", + "verb": "update" + }, + "name": "projects/${projectId}/locations/us-west1/operations/${operationID}", + "response": { + "@type": "type.googleapis.com/google.cloud.workstations.v1.Workstation", + "annotations": { + "a-key1": "a-value1", + "a-key2": "a-value2" + }, + "createTime": "2024-04-01T12:34:56.123456Z", + "displayName": "workstation-${uniqueId}", + "etag": "abcdef0123A=", + "labels": { + "l-key1": "l-value1", + "l-key2": "l-value2" + }, + "name": "projects/${projectId}/locations/us-west1/workstationClusters/workstationcluster-${uniqueId}/workstationConfigs/workstationconfig-${uniqueId}/workstations/workstation-${uniqueId}", + "state": "STATE_STOPPED", + "uid": "111111111111111111111", + "updateTime": "2024-04-01T12:34:56.123456Z" + } +} + +--- + +GET https://workstations.googleapis.com/v1/projects/${projectId}/locations/us-west1/workstationClusters/workstationcluster-${uniqueId}/workstationConfigs/workstationconfig-${uniqueId}/workstations/workstation-${uniqueId}?%24alt=json%3Benum-encoding%3Dint +Content-Type: application/json +User-Agent: kcc/controller-manager +x-goog-request-params: name=projects%2F${projectId}%2Flocations%2Fus-west1%2FworkstationClusters%2Fworkstationcluster-${uniqueId}%2FworkstationConfigs%2Fworkstationconfig-${uniqueId}%2Fworkstations%2Fworkstation-${uniqueId} + +200 OK +Cache-Control: private +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "annotations": { + "a-key1": "a-value1", + "a-key2": "a-value2" + }, + "createTime": "2024-04-01T12:34:56.123456Z", + "displayName": "workstation-${uniqueId}", + "etag": "abcdef0123A=", + "labels": { + "l-key1": "l-value1", + "l-key2": "l-value2" + }, + "name": "projects/${projectId}/locations/us-west1/workstationClusters/workstationcluster-${uniqueId}/workstationConfigs/workstationconfig-${uniqueId}/workstations/workstation-${uniqueId}", + "state": 4, + "uid": "111111111111111111111", + "updateTime": "2024-04-01T12:34:56.123456Z" +} + +--- + +DELETE https://workstations.googleapis.com/v1/projects/${projectId}/locations/us-west1/workstationClusters/workstationcluster-${uniqueId}/workstationConfigs/workstationconfig-${uniqueId}/workstations/workstation-${uniqueId}?%24alt=json%3Benum-encoding%3Dint +Content-Type: application/json +User-Agent: kcc/controller-manager +x-goog-request-params: name=projects%2F${projectId}%2Flocations%2Fus-west1%2FworkstationClusters%2Fworkstationcluster-${uniqueId}%2FworkstationConfigs%2Fworkstationconfig-${uniqueId}%2Fworkstations%2Fworkstation-${uniqueId} + +200 OK +Cache-Control: private +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "done": false, + "metadata": { + "@type": "type.googleapis.com/google.cloud.workstations.v1.OperationMetadata", + "apiVersion": "v1", + "createTime": "2024-04-01T12:34:56.123456Z", + "requestedCancellation": false, + "target": "projects/${projectId}/locations/us-west1/workstationClusters/workstationcluster-${uniqueId}/workstationConfigs/workstationconfig-${uniqueId}/workstations/workstation-${uniqueId}", + "verb": "delete" + }, + "name": "projects/${projectId}/locations/us-west1/operations/${operationID}" +} + +--- + +GET https://workstations.googleapis.com/v1/projects/${projectId}/locations/us-west1/operations/${operationID} +Content-Type: application/json +User-Agent: kcc/controller-manager +x-goog-request-params: name=projects%2F${projectId}%2Flocations%2Fus-west1%2Foperations%2F${operationID} + +200 OK +Cache-Control: private +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "done": true, + "metadata": { + "@type": "type.googleapis.com/google.cloud.workstations.v1.OperationMetadata", + "apiVersion": "v1", + "createTime": "2024-04-01T12:34:56.123456Z", + "endTime": "2024-04-01T12:34:56.123456Z", + "requestedCancellation": false, + "target": "projects/${projectId}/locations/us-west1/workstationClusters/workstationcluster-${uniqueId}/workstationConfigs/workstationconfig-${uniqueId}/workstations/workstation-${uniqueId}", + "verb": "delete" + }, + "name": "projects/${projectId}/locations/us-west1/operations/${operationID}", + "response": { + "@type": "type.googleapis.com/google.cloud.workstations.v1.Workstation" + } +} + +--- + +GET https://workstations.googleapis.com/v1/projects/${projectId}/locations/us-west1/workstationClusters/workstationcluster-${uniqueId}/workstationConfigs/workstationconfig-${uniqueId}?%24alt=json%3Benum-encoding%3Dint +Content-Type: application/json +User-Agent: kcc/controller-manager +x-goog-request-params: name=projects%2F${projectId}%2Flocations%2Fus-west1%2FworkstationClusters%2Fworkstationcluster-${uniqueId}%2FworkstationConfigs%2Fworkstationconfig-${uniqueId} + +200 OK +Cache-Control: private +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "allowedPorts": [ + { + "first": 22, + "last": 22 + }, + { + "first": 80, + "last": 80 + }, + { + "first": 1024, + "last": 65535 + } + ], + "container": { + "image": "us-west1-docker.pkg.dev/cloud-workstations-images/predefined/code-oss:latest" + }, + "createTime": "2024-04-01T12:34:56.123456Z", + "etag": "abcdef0123A=", + "host": { + "gceInstance": { + "bootDiskSizeGb": 50, + "confidentialInstanceConfig": {}, + "machineType": "e2-standard-4", + "serviceAccount": "service-${projectNumber}@gcp-sa-workstationsvm.iam.gserviceaccount.com", + "shieldedInstanceConfig": {} + } + }, + "idleTimeout": "1200s", + "name": "projects/${projectId}/locations/us-west1/workstationClusters/workstationcluster-${uniqueId}/workstationConfigs/workstationconfig-${uniqueId}", + "replicaZones": [ + "us-west1-a", + "us-west1-b" + ], + "runningTimeout": "43200s", + "uid": "111111111111111111111", + "updateTime": "2024-04-01T12:34:56.123456Z" +} + +--- + +DELETE https://workstations.googleapis.com/v1/projects/${projectId}/locations/us-west1/workstationClusters/workstationcluster-${uniqueId}/workstationConfigs/workstationconfig-${uniqueId}?%24alt=json%3Benum-encoding%3Dint +Content-Type: application/json +User-Agent: kcc/controller-manager +x-goog-request-params: name=projects%2F${projectId}%2Flocations%2Fus-west1%2FworkstationClusters%2Fworkstationcluster-${uniqueId}%2FworkstationConfigs%2Fworkstationconfig-${uniqueId} + +200 OK +Cache-Control: private +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "done": false, + "metadata": { + "@type": "type.googleapis.com/google.cloud.workstations.v1.OperationMetadata", + "apiVersion": "v1", + "createTime": "2024-04-01T12:34:56.123456Z", + "requestedCancellation": false, + "target": "projects/${projectId}/locations/us-west1/workstationClusters/workstationcluster-${uniqueId}/workstationConfigs/workstationconfig-${uniqueId}", + "verb": "delete" + }, + "name": "projects/${projectId}/locations/us-west1/operations/${operationID}" +} + +--- + +GET https://workstations.googleapis.com/v1/projects/${projectId}/locations/us-west1/operations/${operationID} +Content-Type: application/json +User-Agent: kcc/controller-manager +x-goog-request-params: name=projects%2F${projectId}%2Flocations%2Fus-west1%2Foperations%2F${operationID} + +200 OK +Cache-Control: private +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "done": true, + "metadata": { + "@type": "type.googleapis.com/google.cloud.workstations.v1.OperationMetadata", + "apiVersion": "v1", + "createTime": "2024-04-01T12:34:56.123456Z", + "endTime": "2024-04-01T12:34:56.123456Z", + "requestedCancellation": false, + "target": "projects/${projectId}/locations/us-west1/workstationClusters/workstationcluster-${uniqueId}/workstationConfigs/workstationconfig-${uniqueId}", + "verb": "delete" + }, + "name": "projects/${projectId}/locations/us-west1/operations/${operationID}" +} + +--- + +GET https://workstations.googleapis.com/v1/projects/${projectId}/locations/us-west1/workstationClusters/workstationcluster-${uniqueId}?%24alt=json%3Benum-encoding%3Dint +Content-Type: application/json +User-Agent: kcc/controller-manager +x-goog-request-params: name=projects%2F${projectId}%2Flocations%2Fus-west1%2FworkstationClusters%2Fworkstationcluster-${uniqueId} + +200 OK +Cache-Control: private +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "controlPlaneIp": "10.0.0.2", + "createTime": "2024-04-01T12:34:56.123456Z", + "etag": "abcdef0123A=", + "name": "projects/${projectId}/locations/us-west1/workstationClusters/workstationcluster-${uniqueId}", + "network": "projects/${projectId}/global/networks/computenetwork-${uniqueId}", + "privateClusterConfig": {}, + "subnetwork": "projects/${projectId}/regions/us-west1/subnetworks/computesubnetwork-${uniqueId}", + "uid": "111111111111111111111", + "updateTime": "2024-04-01T12:34:56.123456Z" +} + +--- + +DELETE https://workstations.googleapis.com/v1/projects/${projectId}/locations/us-west1/workstationClusters/workstationcluster-${uniqueId}?%24alt=json%3Benum-encoding%3Dint +Content-Type: application/json +User-Agent: kcc/controller-manager +x-goog-request-params: name=projects%2F${projectId}%2Flocations%2Fus-west1%2FworkstationClusters%2Fworkstationcluster-${uniqueId} + +200 OK +Cache-Control: private +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "done": false, + "metadata": { + "@type": "type.googleapis.com/google.cloud.workstations.v1.OperationMetadata", + "apiVersion": "v1", + "createTime": "2024-04-01T12:34:56.123456Z", + "requestedCancellation": false, + "target": "projects/${projectId}/locations/us-west1/workstationClusters/workstationcluster-${uniqueId}", + "verb": "delete" + }, + "name": "projects/${projectId}/locations/us-west1/operations/${operationID}" +} + +--- + +GET https://compute.googleapis.com/compute/v1/projects/${projectId}/regions/us-west1/subnetworks/${subnetworkID}?alt=json +Content-Type: application/json +User-Agent: Terraform/ (+https://www.terraform.io) Terraform-Plugin-SDK/2.10.1 terraform-provider-google-beta/kcc/controller-manager + +200 OK +Cache-Control: private +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "allowSubnetCidrRoutesOverlap": false, + "creationTimestamp": "2024-04-01T12:34:56.123456Z", + "enableFlowLogs": false, + "fingerprint": "abcdef0123A=", + "gatewayAddress": "10.0.0.1", + "id": "000000000000000000000", + "ipCidrRange": "10.0.0.0/24", + "kind": "compute#subnetwork", + "logConfig": { + "enable": false + }, + "name": "computesubnetwork-${uniqueId}", + "network": "https://www.googleapis.com/compute/v1/projects/${projectId}/global/networks/computenetwork-${uniqueId}", + "privateIpGoogleAccess": false, + "privateIpv6GoogleAccess": "DISABLE_GOOGLE_ACCESS", + "purpose": "PRIVATE", + "region": "https://www.googleapis.com/compute/v1/projects/${projectId}/regions/us-west1", + "selfLink": "https://www.googleapis.com/compute/v1/projects/${projectId}/regions/us-west1/subnetworks/computesubnetwork-${uniqueId}", + "stackType": "IPV4_ONLY" +} + +--- + +GET https://compute.googleapis.com/compute/v1/projects/${projectId}/global/networks/${networkID}?alt=json +Content-Type: application/json +User-Agent: Terraform/ (+https://www.terraform.io) Terraform-Plugin-SDK/2.10.1 terraform-provider-google-beta/kcc/controller-manager + +200 OK +Cache-Control: private +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "autoCreateSubnetworks": false, + "creationTimestamp": "2024-04-01T12:34:56.123456Z", + "id": "000000000000000000000", + "kind": "compute#network", + "name": "computenetwork-${uniqueId}", + "networkFirewallPolicyEnforcementOrder": "AFTER_CLASSIC_FIREWALL", + "routingConfig": { + "bgpBestPathSelectionMode": "LEGACY", + "routingMode": "GLOBAL" + }, + "selfLink": "https://www.googleapis.com/compute/v1/projects/${projectId}/global/networks/computenetwork-${uniqueId}", + "selfLinkWithId": "https://www.googleapis.com/compute/v1/projects/${projectId}/global/networks/${networkID}", + "subnetworks": [ + "https://www.googleapis.com/compute/v1/projects/${projectId}/regions/us-west1/subnetworks/computesubnetwork-${uniqueId}" + ] +} + +--- + +GET https://workstations.googleapis.com/v1/projects/${projectId}/locations/us-west1/operations/${operationID} +Content-Type: application/json +User-Agent: kcc/controller-manager +x-goog-request-params: name=projects%2F${projectId}%2Flocations%2Fus-west1%2Foperations%2F${operationID} + +200 OK +Cache-Control: private +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "done": true, + "metadata": { + "@type": "type.googleapis.com/google.cloud.workstations.v1.OperationMetadata", + "apiVersion": "v1", + "createTime": "2024-04-01T12:34:56.123456Z", + "endTime": "2024-04-01T12:34:56.123456Z", + "requestedCancellation": false, + "target": "projects/${projectId}/locations/us-west1/workstationClusters/workstationcluster-${uniqueId}", + "verb": "delete" + }, + "name": "projects/${projectId}/locations/us-west1/operations/${operationID}" +} + +--- + +GET https://compute.googleapis.com/compute/v1/projects/${projectId}/regions/us-west1/subnetworks/${subnetworkID}?alt=json +Content-Type: application/json +User-Agent: Terraform/ (+https://www.terraform.io) Terraform-Plugin-SDK/2.10.1 terraform-provider-google-beta/kcc/controller-manager + +200 OK +Cache-Control: private +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "allowSubnetCidrRoutesOverlap": false, + "creationTimestamp": "2024-04-01T12:34:56.123456Z", + "enableFlowLogs": false, + "fingerprint": "abcdef0123A=", + "gatewayAddress": "10.0.0.1", + "id": "000000000000000000000", + "ipCidrRange": "10.0.0.0/24", + "kind": "compute#subnetwork", + "logConfig": { + "enable": false + }, + "name": "computesubnetwork-${uniqueId}", + "network": "https://www.googleapis.com/compute/v1/projects/${projectId}/global/networks/computenetwork-${uniqueId}", + "privateIpGoogleAccess": false, + "privateIpv6GoogleAccess": "DISABLE_GOOGLE_ACCESS", + "purpose": "PRIVATE", + "region": "https://www.googleapis.com/compute/v1/projects/${projectId}/regions/us-west1", + "selfLink": "https://www.googleapis.com/compute/v1/projects/${projectId}/regions/us-west1/subnetworks/computesubnetwork-${uniqueId}", + "stackType": "IPV4_ONLY" +} + +--- + +DELETE https://compute.googleapis.com/compute/v1/projects/${projectId}/regions/us-west1/subnetworks/${subnetworkID}?alt=json +Content-Type: application/json +User-Agent: Terraform/ (+https://www.terraform.io) Terraform-Plugin-SDK/2.10.1 terraform-provider-google-beta/kcc/controller-manager + +200 OK +Cache-Control: private +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "id": "000000000000000000000", + "insertTime": "2024-04-01T12:34:56.123456Z", + "kind": "compute#operation", + "name": "${operationID}", + "operationType": "delete", + "progress": 0, + "region": "https://www.googleapis.com/compute/v1/projects/${projectId}/regions/us-west1", + "selfLink": "https://www.googleapis.com/compute/v1/projects/${projectId}/regions/us-west1/operations/${operationID}", + "startTime": "2024-04-01T12:34:56.123456Z", + "status": "RUNNING", + "targetId": "${subnetworkID}", + "targetLink": "https://www.googleapis.com/compute/v1/projects/${projectId}/regions/us-west1/subnetworks/computesubnetwork-${uniqueId}", + "user": "user@example.com" +} + +--- + +GET https://compute.googleapis.com/compute/v1/projects/${projectId}/regions/us-west1/operations/${operationID}?alt=json&prettyPrint=false +User-Agent: google-api-go-client/0.5 Terraform/ (+https://www.terraform.io) Terraform-Plugin-SDK/2.10.1 terraform-provider-google-beta/kcc/controller-manager + +200 OK +Cache-Control: private +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "endTime": "2024-04-01T12:34:56.123456Z", + "id": "000000000000000000000", + "insertTime": "2024-04-01T12:34:56.123456Z", + "kind": "compute#operation", + "name": "${operationID}", + "operationType": "delete", + "progress": 100, + "region": "https://www.googleapis.com/compute/v1/projects/${projectId}/regions/us-west1", + "selfLink": "https://www.googleapis.com/compute/v1/projects/${projectId}/regions/us-west1/operations/${operationID}", + "startTime": "2024-04-01T12:34:56.123456Z", + "status": "DONE", + "targetId": "${subnetworkID}", + "targetLink": "https://www.googleapis.com/compute/v1/projects/${projectId}/regions/us-west1/subnetworks/computesubnetwork-${uniqueId}", + "user": "user@example.com" +} + +--- + +GET https://compute.googleapis.com/compute/v1/projects/${projectId}/global/networks/${networkID}?alt=json +Content-Type: application/json +User-Agent: Terraform/ (+https://www.terraform.io) Terraform-Plugin-SDK/2.10.1 terraform-provider-google-beta/kcc/controller-manager + +200 OK +Cache-Control: private +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "autoCreateSubnetworks": false, + "creationTimestamp": "2024-04-01T12:34:56.123456Z", + "id": "000000000000000000000", + "kind": "compute#network", + "name": "computenetwork-${uniqueId}", + "networkFirewallPolicyEnforcementOrder": "AFTER_CLASSIC_FIREWALL", + "routingConfig": { + "bgpBestPathSelectionMode": "LEGACY", + "routingMode": "GLOBAL" + }, + "selfLink": "https://www.googleapis.com/compute/v1/projects/${projectId}/global/networks/computenetwork-${uniqueId}", + "selfLinkWithId": "https://www.googleapis.com/compute/v1/projects/${projectId}/global/networks/${networkID}" +} + +--- + +DELETE https://compute.googleapis.com/compute/v1/projects/${projectId}/global/networks/${networkID}?alt=json +Content-Type: application/json +User-Agent: Terraform/ (+https://www.terraform.io) Terraform-Plugin-SDK/2.10.1 terraform-provider-google-beta/kcc/controller-manager + +200 OK +Cache-Control: private +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "id": "000000000000000000000", + "insertTime": "2024-04-01T12:34:56.123456Z", + "kind": "compute#operation", + "name": "${operationID}", + "operationType": "delete", + "progress": 0, + "selfLink": "https://www.googleapis.com/compute/v1/projects/${projectId}/global/operations/${operationID}", + "startTime": "2024-04-01T12:34:56.123456Z", + "status": "RUNNING", + "targetId": "${networkID}", + "targetLink": "https://www.googleapis.com/compute/v1/projects/${projectId}/global/networks/computenetwork-${uniqueId}", + "user": "user@example.com" +} + +--- + +GET https://compute.googleapis.com/compute/v1/projects/${projectId}/global/operations/${operationID}?alt=json&prettyPrint=false +User-Agent: google-api-go-client/0.5 Terraform/ (+https://www.terraform.io) Terraform-Plugin-SDK/2.10.1 terraform-provider-google-beta/kcc/controller-manager + +200 OK +Cache-Control: private +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "endTime": "2024-04-01T12:34:56.123456Z", + "id": "000000000000000000000", + "insertTime": "2024-04-01T12:34:56.123456Z", + "kind": "compute#operation", + "name": "${operationID}", + "operationType": "delete", + "progress": 100, + "selfLink": "https://www.googleapis.com/compute/v1/projects/${projectId}/global/operations/${operationID}", + "startTime": "2024-04-01T12:34:56.123456Z", + "status": "DONE", + "targetId": "${networkID}", + "targetLink": "https://www.googleapis.com/compute/v1/projects/${projectId}/global/networks/computenetwork-${uniqueId}", + "user": "user@example.com" +} \ No newline at end of file diff --git a/pkg/test/resourcefixture/testdata/basic/workstations/workstation/workstation-full/create.yaml b/pkg/test/resourcefixture/testdata/basic/workstations/workstation/workstation-full/create.yaml new file mode 100644 index 0000000000..2e3c5ea7a9 --- /dev/null +++ b/pkg/test/resourcefixture/testdata/basic/workstations/workstation/workstation-full/create.yaml @@ -0,0 +1,28 @@ +# Copyright 2024 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. + +apiVersion: workstations.cnrm.cloud.google.com/v1alpha1 +kind: Workstation +metadata: + name: workstation-${uniqueId} +spec: + parentRef: + name: workstationconfig-${uniqueId} + displayName: workstation-${uniqueId} + annotations: + - key: a-key1 + value: a-value1 + labels: + - key: l-key1 + value: l-value1 \ No newline at end of file diff --git a/pkg/test/resourcefixture/testdata/basic/workstations/workstation/workstation-full/dependencies.yaml b/pkg/test/resourcefixture/testdata/basic/workstations/workstation/workstation-full/dependencies.yaml new file mode 100644 index 0000000000..36297f9d45 --- /dev/null +++ b/pkg/test/resourcefixture/testdata/basic/workstations/workstation/workstation-full/dependencies.yaml @@ -0,0 +1,52 @@ +# Copyright 2024 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. + +apiVersion: compute.cnrm.cloud.google.com/v1beta1 +kind: ComputeNetwork +metadata: + name: computenetwork-${uniqueId} +spec: + routingMode: GLOBAL + autoCreateSubnetworks: false +--- +apiVersion: compute.cnrm.cloud.google.com/v1beta1 +kind: ComputeSubnetwork +metadata: + name: computesubnetwork-${uniqueId} +spec: + ipCidrRange: 10.0.0.0/24 + region: us-west1 + networkRef: + name: computenetwork-${uniqueId} +--- +apiVersion: workstations.cnrm.cloud.google.com/v1beta1 +kind: WorkstationCluster +metadata: + name: workstationcluster-${uniqueId} +spec: + projectRef: + external: ${projectId} + location: us-west1 + networkRef: + name: computenetwork-${uniqueId} + subnetworkRef: + name: computesubnetwork-${uniqueId} +--- +apiVersion: workstations.cnrm.cloud.google.com/v1alpha1 +kind: WorkstationConfig +metadata: + name: workstationconfig-${uniqueId} +spec: + parentRef: + name: workstationcluster-${uniqueId} \ No newline at end of file diff --git a/pkg/test/resourcefixture/testdata/basic/workstations/workstation/workstation-full/update.yaml b/pkg/test/resourcefixture/testdata/basic/workstations/workstation/workstation-full/update.yaml new file mode 100644 index 0000000000..c0338722d1 --- /dev/null +++ b/pkg/test/resourcefixture/testdata/basic/workstations/workstation/workstation-full/update.yaml @@ -0,0 +1,32 @@ +# Copyright 2024 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. + +apiVersion: workstations.cnrm.cloud.google.com/v1alpha1 +kind: Workstation +metadata: + name: workstation-${uniqueId} +spec: + parentRef: + name: workstationconfig-${uniqueId} + displayName: workstation-${uniqueId} + annotations: + - key: a-key1 + value: a-value1 + - key: a-key2 + value: a-value2 + labels: + - key: l-key1 + value: l-value1 + - key: l-key2 + value: l-value2 \ No newline at end of file diff --git a/pkg/test/resourcefixture/testdata/basic/workstations/workstation/workstation-minimal/_generated_object_workstation-minimal.golden.yaml b/pkg/test/resourcefixture/testdata/basic/workstations/workstation/workstation-minimal/_generated_object_workstation-minimal.golden.yaml new file mode 100644 index 0000000000..d3e94a02e4 --- /dev/null +++ b/pkg/test/resourcefixture/testdata/basic/workstations/workstation/workstation-minimal/_generated_object_workstation-minimal.golden.yaml @@ -0,0 +1,30 @@ +apiVersion: workstations.cnrm.cloud.google.com/v1alpha1 +kind: Workstation +metadata: + finalizers: + - cnrm.cloud.google.com/finalizer + - cnrm.cloud.google.com/deletion-defender + generation: 1 + labels: + cnrm-test: "true" + name: workstation-${uniqueId} + namespace: ${uniqueId} +spec: + displayName: workstation-${uniqueId} + parentRef: + name: workstationconfig-${uniqueId} +status: + conditions: + - lastTransitionTime: "1970-01-01T00:00:00Z" + message: The resource is up to date + reason: UpToDate + status: "True" + type: Ready + externalRef: projects/${projectId}/locations/us-west1/workstationClusters/workstationcluster-${uniqueId}/workstationConfigs/workstationconfig-${uniqueId}/workstations/workstation-${uniqueId} + observedGeneration: 1 + observedState: + createTime: "1970-01-01T00:00:00Z" + etag: abcdef123456 + state: STATE_STOPPED + uid: 0123456789abcdef + updateTime: "1970-01-01T00:00:00Z" diff --git a/pkg/test/resourcefixture/testdata/basic/workstations/workstation/workstation-minimal/_http.log b/pkg/test/resourcefixture/testdata/basic/workstations/workstation/workstation-minimal/_http.log new file mode 100644 index 0000000000..afd7aa5c82 --- /dev/null +++ b/pkg/test/resourcefixture/testdata/basic/workstations/workstation/workstation-minimal/_http.log @@ -0,0 +1,1388 @@ +GET https://compute.googleapis.com/compute/v1/projects/${projectId}/global/networks/${networkID}?alt=json +Content-Type: application/json +User-Agent: Terraform/ (+https://www.terraform.io) Terraform-Plugin-SDK/2.10.1 terraform-provider-google-beta/kcc/controller-manager + +404 Not Found +Cache-Control: private +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "error": { + "code": 404, + "errors": [ + { + "domain": "global", + "message": "The resource 'projects/${projectId}/global/networks/computenetwork-${uniqueId}' was not found", + "reason": "notFound" + } + ], + "message": "The resource 'projects/${projectId}/global/networks/computenetwork-${uniqueId}' was not found" + } +} + +--- + +POST https://compute.googleapis.com/compute/v1/projects/${projectId}/global/networks?alt=json +Content-Type: application/json +User-Agent: Terraform/ (+https://www.terraform.io) Terraform-Plugin-SDK/2.10.1 terraform-provider-google-beta/kcc/controller-manager + +{ + "autoCreateSubnetworks": false, + "name": "computenetwork-${uniqueId}", + "networkFirewallPolicyEnforcementOrder": "AFTER_CLASSIC_FIREWALL", + "routingConfig": { + "routingMode": "GLOBAL" + } +} + +200 OK +Cache-Control: private +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "id": "000000000000000000000", + "insertTime": "2024-04-01T12:34:56.123456Z", + "kind": "compute#operation", + "name": "${operationID}", + "operationType": "insert", + "progress": 0, + "selfLink": "https://www.googleapis.com/compute/v1/projects/${projectId}/global/operations/${operationID}", + "startTime": "2024-04-01T12:34:56.123456Z", + "status": "RUNNING", + "targetId": "${networkID}", + "targetLink": "https://www.googleapis.com/compute/v1/projects/${projectId}/global/networks/computenetwork-${uniqueId}", + "user": "user@example.com" +} + +--- + +GET https://compute.googleapis.com/compute/v1/projects/${projectId}/global/operations/${operationID}?alt=json&prettyPrint=false +User-Agent: google-api-go-client/0.5 Terraform/ (+https://www.terraform.io) Terraform-Plugin-SDK/2.10.1 terraform-provider-google-beta/kcc/controller-manager + +200 OK +Cache-Control: private +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "endTime": "2024-04-01T12:34:56.123456Z", + "id": "000000000000000000000", + "insertTime": "2024-04-01T12:34:56.123456Z", + "kind": "compute#operation", + "name": "${operationID}", + "operationType": "insert", + "progress": 100, + "selfLink": "https://www.googleapis.com/compute/v1/projects/${projectId}/global/operations/${operationID}", + "startTime": "2024-04-01T12:34:56.123456Z", + "status": "DONE", + "targetId": "${networkID}", + "targetLink": "https://www.googleapis.com/compute/v1/projects/${projectId}/global/networks/computenetwork-${uniqueId}", + "user": "user@example.com" +} + +--- + +GET https://compute.googleapis.com/compute/v1/projects/${projectId}/global/networks/${networkID}?alt=json +Content-Type: application/json +User-Agent: Terraform/ (+https://www.terraform.io) Terraform-Plugin-SDK/2.10.1 terraform-provider-google-beta/kcc/controller-manager + +200 OK +Cache-Control: private +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "autoCreateSubnetworks": false, + "creationTimestamp": "2024-04-01T12:34:56.123456Z", + "id": "000000000000000000000", + "kind": "compute#network", + "name": "computenetwork-${uniqueId}", + "networkFirewallPolicyEnforcementOrder": "AFTER_CLASSIC_FIREWALL", + "routingConfig": { + "bgpBestPathSelectionMode": "LEGACY", + "routingMode": "GLOBAL" + }, + "selfLink": "https://www.googleapis.com/compute/v1/projects/${projectId}/global/networks/computenetwork-${uniqueId}", + "selfLinkWithId": "https://www.googleapis.com/compute/v1/projects/${projectId}/global/networks/${networkID}" +} + +--- + +GET https://compute.googleapis.com/compute/v1/projects/${projectId}/regions/us-west1/subnetworks/${subnetworkID}?alt=json +Content-Type: application/json +User-Agent: Terraform/ (+https://www.terraform.io) Terraform-Plugin-SDK/2.10.1 terraform-provider-google-beta/kcc/controller-manager + +404 Not Found +Cache-Control: private +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "error": { + "code": 404, + "errors": [ + { + "domain": "global", + "message": "The resource 'projects/${projectId}/regions/us-west1/subnetworks/computesubnetwork-${uniqueId}' was not found", + "reason": "notFound" + } + ], + "message": "The resource 'projects/${projectId}/regions/us-west1/subnetworks/computesubnetwork-${uniqueId}' was not found" + } +} + +--- + +POST https://compute.googleapis.com/compute/v1/projects/${projectId}/regions/us-west1/subnetworks?alt=json +Content-Type: application/json +User-Agent: Terraform/ (+https://www.terraform.io) Terraform-Plugin-SDK/2.10.1 terraform-provider-google-beta/kcc/controller-manager + +{ + "ipCidrRange": "10.0.0.0/24", + "logConfig": { + "enable": false + }, + "name": "computesubnetwork-${uniqueId}", + "network": "projects/${projectId}/global/networks/computenetwork-${uniqueId}", + "region": "projects/${projectId}/global/regions/us-west1" +} + +200 OK +Cache-Control: private +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "id": "000000000000000000000", + "insertTime": "2024-04-01T12:34:56.123456Z", + "kind": "compute#operation", + "name": "${operationID}", + "operationType": "insert", + "progress": 0, + "region": "https://www.googleapis.com/compute/v1/projects/${projectId}/regions/us-west1", + "selfLink": "https://www.googleapis.com/compute/v1/projects/${projectId}/regions/us-west1/operations/${operationID}", + "startTime": "2024-04-01T12:34:56.123456Z", + "status": "RUNNING", + "targetId": "${subnetworkID}", + "targetLink": "https://www.googleapis.com/compute/v1/projects/${projectId}/regions/us-west1/subnetworks/computesubnetwork-${uniqueId}", + "user": "user@example.com" +} + +--- + +GET https://compute.googleapis.com/compute/v1/projects/${projectId}/regions/us-west1/operations/${operationID}?alt=json&prettyPrint=false +User-Agent: google-api-go-client/0.5 Terraform/ (+https://www.terraform.io) Terraform-Plugin-SDK/2.10.1 terraform-provider-google-beta/kcc/controller-manager + +200 OK +Cache-Control: private +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "endTime": "2024-04-01T12:34:56.123456Z", + "id": "000000000000000000000", + "insertTime": "2024-04-01T12:34:56.123456Z", + "kind": "compute#operation", + "name": "${operationID}", + "operationType": "insert", + "progress": 100, + "region": "https://www.googleapis.com/compute/v1/projects/${projectId}/regions/us-west1", + "selfLink": "https://www.googleapis.com/compute/v1/projects/${projectId}/regions/us-west1/operations/${operationID}", + "startTime": "2024-04-01T12:34:56.123456Z", + "status": "DONE", + "targetId": "${subnetworkID}", + "targetLink": "https://www.googleapis.com/compute/v1/projects/${projectId}/regions/us-west1/subnetworks/computesubnetwork-${uniqueId}", + "user": "user@example.com" +} + +--- + +GET https://compute.googleapis.com/compute/v1/projects/${projectId}/regions/us-west1/subnetworks/${subnetworkID}?alt=json +Content-Type: application/json +User-Agent: Terraform/ (+https://www.terraform.io) Terraform-Plugin-SDK/2.10.1 terraform-provider-google-beta/kcc/controller-manager + +200 OK +Cache-Control: private +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "allowSubnetCidrRoutesOverlap": false, + "creationTimestamp": "2024-04-01T12:34:56.123456Z", + "enableFlowLogs": false, + "fingerprint": "abcdef0123A=", + "gatewayAddress": "10.0.0.1", + "id": "000000000000000000000", + "ipCidrRange": "10.0.0.0/24", + "kind": "compute#subnetwork", + "logConfig": { + "enable": false + }, + "name": "computesubnetwork-${uniqueId}", + "network": "https://www.googleapis.com/compute/v1/projects/${projectId}/global/networks/computenetwork-${uniqueId}", + "privateIpGoogleAccess": false, + "privateIpv6GoogleAccess": "DISABLE_GOOGLE_ACCESS", + "purpose": "PRIVATE", + "region": "https://www.googleapis.com/compute/v1/projects/${projectId}/regions/us-west1", + "selfLink": "https://www.googleapis.com/compute/v1/projects/${projectId}/regions/us-west1/subnetworks/computesubnetwork-${uniqueId}", + "stackType": "IPV4_ONLY" +} + +--- + +GET https://workstations.googleapis.com/v1/projects/${projectId}/locations/us-west1/workstationClusters/workstationcluster-${uniqueId}?%24alt=json%3Benum-encoding%3Dint +Content-Type: application/json +User-Agent: kcc/controller-manager +x-goog-request-params: name=projects%2F${projectId}%2Flocations%2Fus-west1%2FworkstationClusters%2Fworkstationcluster-${uniqueId} + +404 Not Found +Cache-Control: private +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "error": { + "code": 404, + "message": "Resource 'projects/${projectId}/locations/us-west1/workstationClusters/workstationcluster-${uniqueId}' was not found", + "status": "NOT_FOUND" + } +} + +--- + +POST https://workstations.googleapis.com/v1/projects/${projectId}/locations/us-west1/workstationClusters?%24alt=json%3Benum-encoding%3Dint&workstationClusterId=workstationcluster-${uniqueId} +Content-Type: application/json +User-Agent: kcc/controller-manager +x-goog-request-params: parent=projects%2F${projectId}%2Flocations%2Fus-west1 + +{ + "network": "projects/${projectId}/global/networks/computenetwork-${uniqueId}", + "subnetwork": "projects/${projectId}/regions/us-west1/subnetworks/computesubnetwork-${uniqueId}" +} + +200 OK +Cache-Control: private +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "done": false, + "metadata": { + "@type": "type.googleapis.com/google.cloud.workstations.v1.OperationMetadata", + "apiVersion": "v1", + "createTime": "2024-04-01T12:34:56.123456Z", + "requestedCancellation": false, + "target": "projects/${projectId}/locations/us-west1/workstationClusters/workstationcluster-${uniqueId}", + "verb": "create" + }, + "name": "projects/${projectId}/locations/us-west1/operations/${operationID}" +} + +--- + +GET https://compute.googleapis.com/compute/v1/projects/${projectId}/global/networks/${networkID}?alt=json +Content-Type: application/json +User-Agent: Terraform/ (+https://www.terraform.io) Terraform-Plugin-SDK/2.10.1 terraform-provider-google-beta/kcc/controller-manager + +200 OK +Cache-Control: private +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "autoCreateSubnetworks": false, + "creationTimestamp": "2024-04-01T12:34:56.123456Z", + "id": "000000000000000000000", + "kind": "compute#network", + "name": "computenetwork-${uniqueId}", + "networkFirewallPolicyEnforcementOrder": "AFTER_CLASSIC_FIREWALL", + "routingConfig": { + "bgpBestPathSelectionMode": "LEGACY", + "routingMode": "GLOBAL" + }, + "selfLink": "https://www.googleapis.com/compute/v1/projects/${projectId}/global/networks/computenetwork-${uniqueId}", + "selfLinkWithId": "https://www.googleapis.com/compute/v1/projects/${projectId}/global/networks/${networkID}", + "subnetworks": [ + "https://www.googleapis.com/compute/v1/projects/${projectId}/regions/us-west1/subnetworks/computesubnetwork-${uniqueId}" + ] +} + +--- + +GET https://compute.googleapis.com/compute/v1/projects/${projectId}/regions/us-west1/subnetworks/${subnetworkID}?alt=json +Content-Type: application/json +User-Agent: Terraform/ (+https://www.terraform.io) Terraform-Plugin-SDK/2.10.1 terraform-provider-google-beta/kcc/controller-manager + +200 OK +Cache-Control: private +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "allowSubnetCidrRoutesOverlap": false, + "creationTimestamp": "2024-04-01T12:34:56.123456Z", + "enableFlowLogs": false, + "fingerprint": "abcdef0123A=", + "gatewayAddress": "10.0.0.1", + "id": "000000000000000000000", + "ipCidrRange": "10.0.0.0/24", + "kind": "compute#subnetwork", + "logConfig": { + "enable": false + }, + "name": "computesubnetwork-${uniqueId}", + "network": "https://www.googleapis.com/compute/v1/projects/${projectId}/global/networks/computenetwork-${uniqueId}", + "privateIpGoogleAccess": false, + "privateIpv6GoogleAccess": "DISABLE_GOOGLE_ACCESS", + "purpose": "PRIVATE", + "region": "https://www.googleapis.com/compute/v1/projects/${projectId}/regions/us-west1", + "selfLink": "https://www.googleapis.com/compute/v1/projects/${projectId}/regions/us-west1/subnetworks/computesubnetwork-${uniqueId}", + "stackType": "IPV4_ONLY" +} + +--- + +GET https://compute.googleapis.com/compute/v1/projects/${projectId}/global/networks/${networkID}?alt=json +Content-Type: application/json +User-Agent: Terraform/ (+https://www.terraform.io) Terraform-Plugin-SDK/2.10.1 terraform-provider-google-beta/kcc/controller-manager + +200 OK +Cache-Control: private +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "autoCreateSubnetworks": false, + "creationTimestamp": "2024-04-01T12:34:56.123456Z", + "id": "000000000000000000000", + "kind": "compute#network", + "name": "computenetwork-${uniqueId}", + "networkFirewallPolicyEnforcementOrder": "AFTER_CLASSIC_FIREWALL", + "routingConfig": { + "bgpBestPathSelectionMode": "LEGACY", + "routingMode": "GLOBAL" + }, + "selfLink": "https://www.googleapis.com/compute/v1/projects/${projectId}/global/networks/computenetwork-${uniqueId}", + "selfLinkWithId": "https://www.googleapis.com/compute/v1/projects/${projectId}/global/networks/${networkID}", + "subnetworks": [ + "https://www.googleapis.com/compute/v1/projects/${projectId}/regions/us-west1/subnetworks/computesubnetwork-${uniqueId}" + ] +} + +--- + +GET https://workstations.googleapis.com/v1/projects/${projectId}/locations/us-west1/operations/${operationID} +Content-Type: application/json +User-Agent: kcc/controller-manager +x-goog-request-params: name=projects%2F${projectId}%2Flocations%2Fus-west1%2Foperations%2F${operationID} + +200 OK +Cache-Control: private +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "done": true, + "metadata": { + "@type": "type.googleapis.com/google.cloud.workstations.v1.OperationMetadata", + "apiVersion": "v1", + "createTime": "2024-04-01T12:34:56.123456Z", + "endTime": "2024-04-01T12:34:56.123456Z", + "requestedCancellation": false, + "target": "projects/${projectId}/locations/us-west1/workstationClusters/workstationcluster-${uniqueId}", + "verb": "create" + }, + "name": "projects/${projectId}/locations/us-west1/operations/${operationID}", + "response": { + "@type": "type.googleapis.com/google.cloud.workstations.v1.WorkstationCluster", + "controlPlaneIp": "10.0.0.2", + "createTime": "2024-04-01T12:34:56.123456Z", + "etag": "abcdef0123A=", + "name": "projects/${projectId}/locations/us-west1/workstationClusters/workstationcluster-${uniqueId}", + "network": "projects/${projectId}/global/networks/computenetwork-${uniqueId}", + "privateClusterConfig": {}, + "subnetwork": "projects/${projectId}/regions/us-west1/subnetworks/computesubnetwork-${uniqueId}", + "uid": "111111111111111111111", + "updateTime": "2024-04-01T12:34:56.123456Z" + } +} + +--- + +GET https://workstations.googleapis.com/v1/projects/${projectId}/locations/us-west1/workstationClusters/workstationcluster-${uniqueId}/workstationConfigs/workstationconfig-${uniqueId}?%24alt=json%3Benum-encoding%3Dint +Content-Type: application/json +User-Agent: kcc/controller-manager +x-goog-request-params: name=projects%2F${projectId}%2Flocations%2Fus-west1%2FworkstationClusters%2Fworkstationcluster-${uniqueId}%2FworkstationConfigs%2Fworkstationconfig-${uniqueId} + +404 Not Found +Cache-Control: private +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "error": { + "code": 404, + "message": "Resource 'projects/${projectId}/locations/us-west1/workstationClusters/workstationcluster-${uniqueId}/workstationConfigs/workstationconfig-${uniqueId}' was not found", + "status": "NOT_FOUND" + } +} + +--- + +POST https://workstations.googleapis.com/v1/projects/${projectId}/locations/us-west1/workstationClusters/workstationcluster-${uniqueId}/workstationConfigs?%24alt=json%3Benum-encoding%3Dint&workstationConfigId=workstationconfig-${uniqueId} +Content-Type: application/json +User-Agent: kcc/controller-manager +x-goog-request-params: parent=projects%2F${projectId}%2Flocations%2Fus-west1%2FworkstationClusters%2Fworkstationcluster-${uniqueId} + +{ + "idleTimeout": "1200s", + "runningTimeout": "43200s" +} + +200 OK +Cache-Control: private +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "done": false, + "metadata": { + "@type": "type.googleapis.com/google.cloud.workstations.v1.OperationMetadata", + "apiVersion": "v1", + "createTime": "2024-04-01T12:34:56.123456Z", + "requestedCancellation": false, + "target": "projects/${projectId}/locations/us-west1/workstationClusters/workstationcluster-${uniqueId}/workstationConfigs/workstationconfig-${uniqueId}", + "verb": "create" + }, + "name": "projects/${projectId}/locations/us-west1/operations/${operationID}" +} + +--- + +GET https://workstations.googleapis.com/v1/projects/${projectId}/locations/us-west1/operations/${operationID} +Content-Type: application/json +User-Agent: kcc/controller-manager +x-goog-request-params: name=projects%2F${projectId}%2Flocations%2Fus-west1%2Foperations%2F${operationID} + +200 OK +Cache-Control: private +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "done": true, + "metadata": { + "@type": "type.googleapis.com/google.cloud.workstations.v1.OperationMetadata", + "apiVersion": "v1", + "createTime": "2024-04-01T12:34:56.123456Z", + "endTime": "2024-04-01T12:34:56.123456Z", + "requestedCancellation": false, + "target": "projects/${projectId}/locations/us-west1/workstationClusters/workstationcluster-${uniqueId}/workstationConfigs/workstationconfig-${uniqueId}", + "verb": "create" + }, + "name": "projects/${projectId}/locations/us-west1/operations/${operationID}", + "response": { + "@type": "type.googleapis.com/google.cloud.workstations.v1.WorkstationConfig", + "allowedPorts": [ + { + "first": 22, + "last": 22 + }, + { + "first": 80, + "last": 80 + }, + { + "first": 1024, + "last": 65535 + } + ], + "container": { + "image": "us-west1-docker.pkg.dev/cloud-workstations-images/predefined/code-oss:latest" + }, + "createTime": "2024-04-01T12:34:56.123456Z", + "etag": "abcdef0123A=", + "host": { + "gceInstance": { + "bootDiskSizeGb": 50, + "confidentialInstanceConfig": {}, + "machineType": "e2-standard-4", + "serviceAccount": "service-${projectNumber}@gcp-sa-workstationsvm.iam.gserviceaccount.com", + "shieldedInstanceConfig": {} + } + }, + "idleTimeout": "1200s", + "name": "projects/${projectId}/locations/us-west1/workstationClusters/workstationcluster-${uniqueId}/workstationConfigs/workstationconfig-${uniqueId}", + "replicaZones": [ + "us-west1-a", + "us-west1-b" + ], + "runningTimeout": "43200s", + "uid": "111111111111111111111", + "updateTime": "2024-04-01T12:34:56.123456Z" + } +} + +--- + +GET https://workstations.googleapis.com/v1/projects/${projectId}/locations/us-west1/workstationClusters/workstationcluster-${uniqueId}/workstationConfigs/workstationconfig-${uniqueId}/workstations/workstation-${uniqueId}?%24alt=json%3Benum-encoding%3Dint +Content-Type: application/json +User-Agent: kcc/controller-manager +x-goog-request-params: name=projects%2F${projectId}%2Flocations%2Fus-west1%2FworkstationClusters%2Fworkstationcluster-${uniqueId}%2FworkstationConfigs%2Fworkstationconfig-${uniqueId}%2Fworkstations%2Fworkstation-${uniqueId} + +404 Not Found +Cache-Control: private +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "error": { + "code": 404, + "message": "Resource 'projects/${projectId}/locations/us-west1/workstationClusters/workstationcluster-${uniqueId}/workstationConfigs/workstationconfig-${uniqueId}/workstations/workstation-${uniqueId}' was not found", + "status": "NOT_FOUND" + } +} + +--- + +POST https://workstations.googleapis.com/v1/projects/${projectId}/locations/us-west1/workstationClusters/workstationcluster-${uniqueId}/workstationConfigs/workstationconfig-${uniqueId}/workstations?%24alt=json%3Benum-encoding%3Dint&workstationId=workstation-${uniqueId} +Content-Type: application/json +User-Agent: kcc/controller-manager +x-goog-request-params: parent=projects%2F${projectId}%2Flocations%2Fus-west1%2FworkstationClusters%2Fworkstationcluster-${uniqueId}%2FworkstationConfigs%2Fworkstationconfig-${uniqueId} + +{ + "displayName": "workstation-${uniqueId}" +} + +200 OK +Cache-Control: private +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "done": false, + "metadata": { + "@type": "type.googleapis.com/google.cloud.workstations.v1.OperationMetadata", + "apiVersion": "v1", + "createTime": "2024-04-01T12:34:56.123456Z", + "requestedCancellation": false, + "target": "projects/${projectId}/locations/us-west1/workstationClusters/workstationcluster-${uniqueId}/workstationConfigs/workstationconfig-${uniqueId}/workstations/workstation-${uniqueId}", + "verb": "create" + }, + "name": "projects/${projectId}/locations/us-west1/operations/${operationID}" +} + +--- + +GET https://workstations.googleapis.com/v1/projects/${projectId}/locations/us-west1/operations/${operationID} +Content-Type: application/json +User-Agent: kcc/controller-manager +x-goog-request-params: name=projects%2F${projectId}%2Flocations%2Fus-west1%2Foperations%2F${operationID} + +200 OK +Cache-Control: private +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "done": true, + "metadata": { + "@type": "type.googleapis.com/google.cloud.workstations.v1.OperationMetadata", + "apiVersion": "v1", + "createTime": "2024-04-01T12:34:56.123456Z", + "endTime": "2024-04-01T12:34:56.123456Z", + "requestedCancellation": false, + "target": "projects/${projectId}/locations/us-west1/workstationClusters/workstationcluster-${uniqueId}/workstationConfigs/workstationconfig-${uniqueId}/workstations/workstation-${uniqueId}", + "verb": "create" + }, + "name": "projects/${projectId}/locations/us-west1/operations/${operationID}", + "response": { + "@type": "type.googleapis.com/google.cloud.workstations.v1.Workstation", + "createTime": "2024-04-01T12:34:56.123456Z", + "displayName": "workstation-${uniqueId}", + "etag": "abcdef0123A=", + "name": "projects/${projectId}/locations/us-west1/workstationClusters/workstationcluster-${uniqueId}/workstationConfigs/workstationconfig-${uniqueId}/workstations/workstation-${uniqueId}", + "state": "STATE_STOPPED", + "uid": "111111111111111111111", + "updateTime": "2024-04-01T12:34:56.123456Z" + } +} + +--- + +GET https://workstations.googleapis.com/v1/projects/${projectId}/locations/us-west1/workstationClusters/workstationcluster-${uniqueId}/workstationConfigs/workstationconfig-${uniqueId}/workstations/workstation-${uniqueId}?%24alt=json%3Benum-encoding%3Dint +Content-Type: application/json +User-Agent: kcc/controller-manager +x-goog-request-params: name=projects%2F${projectId}%2Flocations%2Fus-west1%2FworkstationClusters%2Fworkstationcluster-${uniqueId}%2FworkstationConfigs%2Fworkstationconfig-${uniqueId}%2Fworkstations%2Fworkstation-${uniqueId} + +200 OK +Cache-Control: private +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "createTime": "2024-04-01T12:34:56.123456Z", + "displayName": "workstation-${uniqueId}", + "etag": "abcdef0123A=", + "name": "projects/${projectId}/locations/us-west1/workstationClusters/workstationcluster-${uniqueId}/workstationConfigs/workstationconfig-${uniqueId}/workstations/workstation-${uniqueId}", + "state": 4, + "uid": "111111111111111111111", + "updateTime": "2024-04-01T12:34:56.123456Z" +} + +--- + +DELETE https://workstations.googleapis.com/v1/projects/${projectId}/locations/us-west1/workstationClusters/workstationcluster-${uniqueId}/workstationConfigs/workstationconfig-${uniqueId}/workstations/workstation-${uniqueId}?%24alt=json%3Benum-encoding%3Dint +Content-Type: application/json +User-Agent: kcc/controller-manager +x-goog-request-params: name=projects%2F${projectId}%2Flocations%2Fus-west1%2FworkstationClusters%2Fworkstationcluster-${uniqueId}%2FworkstationConfigs%2Fworkstationconfig-${uniqueId}%2Fworkstations%2Fworkstation-${uniqueId} + +200 OK +Cache-Control: private +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "done": false, + "metadata": { + "@type": "type.googleapis.com/google.cloud.workstations.v1.OperationMetadata", + "apiVersion": "v1", + "createTime": "2024-04-01T12:34:56.123456Z", + "requestedCancellation": false, + "target": "projects/${projectId}/locations/us-west1/workstationClusters/workstationcluster-${uniqueId}/workstationConfigs/workstationconfig-${uniqueId}/workstations/workstation-${uniqueId}", + "verb": "delete" + }, + "name": "projects/${projectId}/locations/us-west1/operations/${operationID}" +} + +--- + +GET https://compute.googleapis.com/compute/v1/projects/${projectId}/regions/us-west1/subnetworks/${subnetworkID}?alt=json +Content-Type: application/json +User-Agent: Terraform/ (+https://www.terraform.io) Terraform-Plugin-SDK/2.10.1 terraform-provider-google-beta/kcc/controller-manager + +200 OK +Cache-Control: private +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "allowSubnetCidrRoutesOverlap": false, + "creationTimestamp": "2024-04-01T12:34:56.123456Z", + "enableFlowLogs": false, + "fingerprint": "abcdef0123A=", + "gatewayAddress": "10.0.0.1", + "id": "000000000000000000000", + "ipCidrRange": "10.0.0.0/24", + "kind": "compute#subnetwork", + "logConfig": { + "enable": false + }, + "name": "computesubnetwork-${uniqueId}", + "network": "https://www.googleapis.com/compute/v1/projects/${projectId}/global/networks/computenetwork-${uniqueId}", + "privateIpGoogleAccess": false, + "privateIpv6GoogleAccess": "DISABLE_GOOGLE_ACCESS", + "purpose": "PRIVATE", + "region": "https://www.googleapis.com/compute/v1/projects/${projectId}/regions/us-west1", + "selfLink": "https://www.googleapis.com/compute/v1/projects/${projectId}/regions/us-west1/subnetworks/computesubnetwork-${uniqueId}", + "stackType": "IPV4_ONLY" +} + +--- + +GET https://workstations.googleapis.com/v1/projects/${projectId}/locations/us-west1/operations/${operationID} +Content-Type: application/json +User-Agent: kcc/controller-manager +x-goog-request-params: name=projects%2F${projectId}%2Flocations%2Fus-west1%2Foperations%2F${operationID} + +200 OK +Cache-Control: private +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "done": true, + "metadata": { + "@type": "type.googleapis.com/google.cloud.workstations.v1.OperationMetadata", + "apiVersion": "v1", + "createTime": "2024-04-01T12:34:56.123456Z", + "endTime": "2024-04-01T12:34:56.123456Z", + "requestedCancellation": false, + "target": "projects/${projectId}/locations/us-west1/workstationClusters/workstationcluster-${uniqueId}/workstationConfigs/workstationconfig-${uniqueId}/workstations/workstation-${uniqueId}", + "verb": "delete" + }, + "name": "projects/${projectId}/locations/us-west1/operations/${operationID}", + "response": { + "@type": "type.googleapis.com/google.cloud.workstations.v1.Workstation" + } +} + +--- + +GET https://workstations.googleapis.com/v1/projects/${projectId}/locations/us-west1/workstationClusters/workstationcluster-${uniqueId}/workstationConfigs/workstationconfig-${uniqueId}?%24alt=json%3Benum-encoding%3Dint +Content-Type: application/json +User-Agent: kcc/controller-manager +x-goog-request-params: name=projects%2F${projectId}%2Flocations%2Fus-west1%2FworkstationClusters%2Fworkstationcluster-${uniqueId}%2FworkstationConfigs%2Fworkstationconfig-${uniqueId} + +200 OK +Cache-Control: private +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "allowedPorts": [ + { + "first": 22, + "last": 22 + }, + { + "first": 80, + "last": 80 + }, + { + "first": 1024, + "last": 65535 + } + ], + "container": { + "image": "us-west1-docker.pkg.dev/cloud-workstations-images/predefined/code-oss:latest" + }, + "createTime": "2024-04-01T12:34:56.123456Z", + "etag": "abcdef0123A=", + "host": { + "gceInstance": { + "bootDiskSizeGb": 50, + "confidentialInstanceConfig": {}, + "machineType": "e2-standard-4", + "serviceAccount": "service-${projectNumber}@gcp-sa-workstationsvm.iam.gserviceaccount.com", + "shieldedInstanceConfig": {} + } + }, + "idleTimeout": "1200s", + "name": "projects/${projectId}/locations/us-west1/workstationClusters/workstationcluster-${uniqueId}/workstationConfigs/workstationconfig-${uniqueId}", + "replicaZones": [ + "us-west1-a", + "us-west1-b" + ], + "runningTimeout": "43200s", + "uid": "111111111111111111111", + "updateTime": "2024-04-01T12:34:56.123456Z" +} + +--- + +DELETE https://workstations.googleapis.com/v1/projects/${projectId}/locations/us-west1/workstationClusters/workstationcluster-${uniqueId}/workstationConfigs/workstationconfig-${uniqueId}?%24alt=json%3Benum-encoding%3Dint +Content-Type: application/json +User-Agent: kcc/controller-manager +x-goog-request-params: name=projects%2F${projectId}%2Flocations%2Fus-west1%2FworkstationClusters%2Fworkstationcluster-${uniqueId}%2FworkstationConfigs%2Fworkstationconfig-${uniqueId} + +200 OK +Cache-Control: private +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "done": false, + "metadata": { + "@type": "type.googleapis.com/google.cloud.workstations.v1.OperationMetadata", + "apiVersion": "v1", + "createTime": "2024-04-01T12:34:56.123456Z", + "requestedCancellation": false, + "target": "projects/${projectId}/locations/us-west1/workstationClusters/workstationcluster-${uniqueId}/workstationConfigs/workstationconfig-${uniqueId}", + "verb": "delete" + }, + "name": "projects/${projectId}/locations/us-west1/operations/${operationID}" +} + +--- + +GET https://compute.googleapis.com/compute/v1/projects/${projectId}/global/networks/${networkID}?alt=json +Content-Type: application/json +User-Agent: Terraform/ (+https://www.terraform.io) Terraform-Plugin-SDK/2.10.1 terraform-provider-google-beta/kcc/controller-manager + +200 OK +Cache-Control: private +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "autoCreateSubnetworks": false, + "creationTimestamp": "2024-04-01T12:34:56.123456Z", + "id": "000000000000000000000", + "kind": "compute#network", + "name": "computenetwork-${uniqueId}", + "networkFirewallPolicyEnforcementOrder": "AFTER_CLASSIC_FIREWALL", + "routingConfig": { + "bgpBestPathSelectionMode": "LEGACY", + "routingMode": "GLOBAL" + }, + "selfLink": "https://www.googleapis.com/compute/v1/projects/${projectId}/global/networks/computenetwork-${uniqueId}", + "selfLinkWithId": "https://www.googleapis.com/compute/v1/projects/${projectId}/global/networks/${networkID}", + "subnetworks": [ + "https://www.googleapis.com/compute/v1/projects/${projectId}/regions/us-west1/subnetworks/computesubnetwork-${uniqueId}" + ] +} + +--- + +GET https://workstations.googleapis.com/v1/projects/${projectId}/locations/us-west1/operations/${operationID} +Content-Type: application/json +User-Agent: kcc/controller-manager +x-goog-request-params: name=projects%2F${projectId}%2Flocations%2Fus-west1%2Foperations%2F${operationID} + +200 OK +Cache-Control: private +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "done": true, + "metadata": { + "@type": "type.googleapis.com/google.cloud.workstations.v1.OperationMetadata", + "apiVersion": "v1", + "createTime": "2024-04-01T12:34:56.123456Z", + "endTime": "2024-04-01T12:34:56.123456Z", + "requestedCancellation": false, + "target": "projects/${projectId}/locations/us-west1/workstationClusters/workstationcluster-${uniqueId}/workstationConfigs/workstationconfig-${uniqueId}", + "verb": "delete" + }, + "name": "projects/${projectId}/locations/us-west1/operations/${operationID}" +} + +--- + +GET https://workstations.googleapis.com/v1/projects/${projectId}/locations/us-west1/workstationClusters/workstationcluster-${uniqueId}?%24alt=json%3Benum-encoding%3Dint +Content-Type: application/json +User-Agent: kcc/controller-manager +x-goog-request-params: name=projects%2F${projectId}%2Flocations%2Fus-west1%2FworkstationClusters%2Fworkstationcluster-${uniqueId} + +200 OK +Cache-Control: private +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "controlPlaneIp": "10.0.0.2", + "createTime": "2024-04-01T12:34:56.123456Z", + "etag": "abcdef0123A=", + "name": "projects/${projectId}/locations/us-west1/workstationClusters/workstationcluster-${uniqueId}", + "network": "projects/${projectId}/global/networks/computenetwork-${uniqueId}", + "privateClusterConfig": {}, + "subnetwork": "projects/${projectId}/regions/us-west1/subnetworks/computesubnetwork-${uniqueId}", + "uid": "111111111111111111111", + "updateTime": "2024-04-01T12:34:56.123456Z" +} + +--- + +DELETE https://workstations.googleapis.com/v1/projects/${projectId}/locations/us-west1/workstationClusters/workstationcluster-${uniqueId}?%24alt=json%3Benum-encoding%3Dint +Content-Type: application/json +User-Agent: kcc/controller-manager +x-goog-request-params: name=projects%2F${projectId}%2Flocations%2Fus-west1%2FworkstationClusters%2Fworkstationcluster-${uniqueId} + +200 OK +Cache-Control: private +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "done": false, + "metadata": { + "@type": "type.googleapis.com/google.cloud.workstations.v1.OperationMetadata", + "apiVersion": "v1", + "createTime": "2024-04-01T12:34:56.123456Z", + "requestedCancellation": false, + "target": "projects/${projectId}/locations/us-west1/workstationClusters/workstationcluster-${uniqueId}", + "verb": "delete" + }, + "name": "projects/${projectId}/locations/us-west1/operations/${operationID}" +} + +--- + +GET https://compute.googleapis.com/compute/v1/projects/${projectId}/global/networks/${networkID}?alt=json +Content-Type: application/json +User-Agent: Terraform/ (+https://www.terraform.io) Terraform-Plugin-SDK/2.10.1 terraform-provider-google-beta/kcc/controller-manager + +200 OK +Cache-Control: private +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "autoCreateSubnetworks": false, + "creationTimestamp": "2024-04-01T12:34:56.123456Z", + "id": "000000000000000000000", + "kind": "compute#network", + "name": "computenetwork-${uniqueId}", + "networkFirewallPolicyEnforcementOrder": "AFTER_CLASSIC_FIREWALL", + "routingConfig": { + "bgpBestPathSelectionMode": "LEGACY", + "routingMode": "GLOBAL" + }, + "selfLink": "https://www.googleapis.com/compute/v1/projects/${projectId}/global/networks/computenetwork-${uniqueId}", + "selfLinkWithId": "https://www.googleapis.com/compute/v1/projects/${projectId}/global/networks/${networkID}", + "subnetworks": [ + "https://www.googleapis.com/compute/v1/projects/${projectId}/regions/us-west1/subnetworks/computesubnetwork-${uniqueId}" + ] +} + +--- + +GET https://compute.googleapis.com/compute/v1/projects/${projectId}/regions/us-west1/subnetworks/${subnetworkID}?alt=json +Content-Type: application/json +User-Agent: Terraform/ (+https://www.terraform.io) Terraform-Plugin-SDK/2.10.1 terraform-provider-google-beta/kcc/controller-manager + +200 OK +Cache-Control: private +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "allowSubnetCidrRoutesOverlap": false, + "creationTimestamp": "2024-04-01T12:34:56.123456Z", + "enableFlowLogs": false, + "fingerprint": "abcdef0123A=", + "gatewayAddress": "10.0.0.1", + "id": "000000000000000000000", + "ipCidrRange": "10.0.0.0/24", + "kind": "compute#subnetwork", + "logConfig": { + "enable": false + }, + "name": "computesubnetwork-${uniqueId}", + "network": "https://www.googleapis.com/compute/v1/projects/${projectId}/global/networks/computenetwork-${uniqueId}", + "privateIpGoogleAccess": false, + "privateIpv6GoogleAccess": "DISABLE_GOOGLE_ACCESS", + "purpose": "PRIVATE", + "region": "https://www.googleapis.com/compute/v1/projects/${projectId}/regions/us-west1", + "selfLink": "https://www.googleapis.com/compute/v1/projects/${projectId}/regions/us-west1/subnetworks/computesubnetwork-${uniqueId}", + "stackType": "IPV4_ONLY" +} + +--- + +GET https://workstations.googleapis.com/v1/projects/${projectId}/locations/us-west1/operations/${operationID} +Content-Type: application/json +User-Agent: kcc/controller-manager +x-goog-request-params: name=projects%2F${projectId}%2Flocations%2Fus-west1%2Foperations%2F${operationID} + +200 OK +Cache-Control: private +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "done": true, + "metadata": { + "@type": "type.googleapis.com/google.cloud.workstations.v1.OperationMetadata", + "apiVersion": "v1", + "createTime": "2024-04-01T12:34:56.123456Z", + "endTime": "2024-04-01T12:34:56.123456Z", + "requestedCancellation": false, + "target": "projects/${projectId}/locations/us-west1/workstationClusters/workstationcluster-${uniqueId}", + "verb": "delete" + }, + "name": "projects/${projectId}/locations/us-west1/operations/${operationID}" +} + +--- + +GET https://compute.googleapis.com/compute/v1/projects/${projectId}/regions/us-west1/subnetworks/${subnetworkID}?alt=json +Content-Type: application/json +User-Agent: Terraform/ (+https://www.terraform.io) Terraform-Plugin-SDK/2.10.1 terraform-provider-google-beta/kcc/controller-manager + +200 OK +Cache-Control: private +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "allowSubnetCidrRoutesOverlap": false, + "creationTimestamp": "2024-04-01T12:34:56.123456Z", + "enableFlowLogs": false, + "fingerprint": "abcdef0123A=", + "gatewayAddress": "10.0.0.1", + "id": "000000000000000000000", + "ipCidrRange": "10.0.0.0/24", + "kind": "compute#subnetwork", + "logConfig": { + "enable": false + }, + "name": "computesubnetwork-${uniqueId}", + "network": "https://www.googleapis.com/compute/v1/projects/${projectId}/global/networks/computenetwork-${uniqueId}", + "privateIpGoogleAccess": false, + "privateIpv6GoogleAccess": "DISABLE_GOOGLE_ACCESS", + "purpose": "PRIVATE", + "region": "https://www.googleapis.com/compute/v1/projects/${projectId}/regions/us-west1", + "selfLink": "https://www.googleapis.com/compute/v1/projects/${projectId}/regions/us-west1/subnetworks/computesubnetwork-${uniqueId}", + "stackType": "IPV4_ONLY" +} + +--- + +DELETE https://compute.googleapis.com/compute/v1/projects/${projectId}/regions/us-west1/subnetworks/${subnetworkID}?alt=json +Content-Type: application/json +User-Agent: Terraform/ (+https://www.terraform.io) Terraform-Plugin-SDK/2.10.1 terraform-provider-google-beta/kcc/controller-manager + +200 OK +Cache-Control: private +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "id": "000000000000000000000", + "insertTime": "2024-04-01T12:34:56.123456Z", + "kind": "compute#operation", + "name": "${operationID}", + "operationType": "delete", + "progress": 0, + "region": "https://www.googleapis.com/compute/v1/projects/${projectId}/regions/us-west1", + "selfLink": "https://www.googleapis.com/compute/v1/projects/${projectId}/regions/us-west1/operations/${operationID}", + "startTime": "2024-04-01T12:34:56.123456Z", + "status": "RUNNING", + "targetId": "${subnetworkID}", + "targetLink": "https://www.googleapis.com/compute/v1/projects/${projectId}/regions/us-west1/subnetworks/computesubnetwork-${uniqueId}", + "user": "user@example.com" +} + +--- + +GET https://compute.googleapis.com/compute/v1/projects/${projectId}/regions/us-west1/operations/${operationID}?alt=json&prettyPrint=false +User-Agent: google-api-go-client/0.5 Terraform/ (+https://www.terraform.io) Terraform-Plugin-SDK/2.10.1 terraform-provider-google-beta/kcc/controller-manager + +200 OK +Cache-Control: private +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "endTime": "2024-04-01T12:34:56.123456Z", + "id": "000000000000000000000", + "insertTime": "2024-04-01T12:34:56.123456Z", + "kind": "compute#operation", + "name": "${operationID}", + "operationType": "delete", + "progress": 100, + "region": "https://www.googleapis.com/compute/v1/projects/${projectId}/regions/us-west1", + "selfLink": "https://www.googleapis.com/compute/v1/projects/${projectId}/regions/us-west1/operations/${operationID}", + "startTime": "2024-04-01T12:34:56.123456Z", + "status": "DONE", + "targetId": "${subnetworkID}", + "targetLink": "https://www.googleapis.com/compute/v1/projects/${projectId}/regions/us-west1/subnetworks/computesubnetwork-${uniqueId}", + "user": "user@example.com" +} + +--- + +GET https://compute.googleapis.com/compute/v1/projects/${projectId}/global/networks/${networkID}?alt=json +Content-Type: application/json +User-Agent: Terraform/ (+https://www.terraform.io) Terraform-Plugin-SDK/2.10.1 terraform-provider-google-beta/kcc/controller-manager + +200 OK +Cache-Control: private +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "autoCreateSubnetworks": false, + "creationTimestamp": "2024-04-01T12:34:56.123456Z", + "id": "000000000000000000000", + "kind": "compute#network", + "name": "computenetwork-${uniqueId}", + "networkFirewallPolicyEnforcementOrder": "AFTER_CLASSIC_FIREWALL", + "routingConfig": { + "bgpBestPathSelectionMode": "LEGACY", + "routingMode": "GLOBAL" + }, + "selfLink": "https://www.googleapis.com/compute/v1/projects/${projectId}/global/networks/computenetwork-${uniqueId}", + "selfLinkWithId": "https://www.googleapis.com/compute/v1/projects/${projectId}/global/networks/${networkID}" +} + +--- + +DELETE https://compute.googleapis.com/compute/v1/projects/${projectId}/global/networks/${networkID}?alt=json +Content-Type: application/json +User-Agent: Terraform/ (+https://www.terraform.io) Terraform-Plugin-SDK/2.10.1 terraform-provider-google-beta/kcc/controller-manager + +200 OK +Cache-Control: private +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "id": "000000000000000000000", + "insertTime": "2024-04-01T12:34:56.123456Z", + "kind": "compute#operation", + "name": "${operationID}", + "operationType": "delete", + "progress": 0, + "selfLink": "https://www.googleapis.com/compute/v1/projects/${projectId}/global/operations/${operationID}", + "startTime": "2024-04-01T12:34:56.123456Z", + "status": "RUNNING", + "targetId": "${networkID}", + "targetLink": "https://www.googleapis.com/compute/v1/projects/${projectId}/global/networks/computenetwork-${uniqueId}", + "user": "user@example.com" +} + +--- + +GET https://compute.googleapis.com/compute/v1/projects/${projectId}/global/operations/${operationID}?alt=json&prettyPrint=false +User-Agent: google-api-go-client/0.5 Terraform/ (+https://www.terraform.io) Terraform-Plugin-SDK/2.10.1 terraform-provider-google-beta/kcc/controller-manager + +200 OK +Cache-Control: private +Content-Type: application/json; charset=UTF-8 +Server: ESF +Vary: Origin +Vary: X-Origin +Vary: Referer +X-Content-Type-Options: nosniff +X-Frame-Options: SAMEORIGIN +X-Xss-Protection: 0 + +{ + "endTime": "2024-04-01T12:34:56.123456Z", + "id": "000000000000000000000", + "insertTime": "2024-04-01T12:34:56.123456Z", + "kind": "compute#operation", + "name": "${operationID}", + "operationType": "delete", + "progress": 100, + "selfLink": "https://www.googleapis.com/compute/v1/projects/${projectId}/global/operations/${operationID}", + "startTime": "2024-04-01T12:34:56.123456Z", + "status": "DONE", + "targetId": "${networkID}", + "targetLink": "https://www.googleapis.com/compute/v1/projects/${projectId}/global/networks/computenetwork-${uniqueId}", + "user": "user@example.com" +} \ No newline at end of file diff --git a/pkg/test/resourcefixture/testdata/basic/workstations/workstation/workstation-minimal/create.yaml b/pkg/test/resourcefixture/testdata/basic/workstations/workstation/workstation-minimal/create.yaml new file mode 100644 index 0000000000..6c3ebd4ef9 --- /dev/null +++ b/pkg/test/resourcefixture/testdata/basic/workstations/workstation/workstation-minimal/create.yaml @@ -0,0 +1,22 @@ +# Copyright 2024 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. + +apiVersion: workstations.cnrm.cloud.google.com/v1alpha1 +kind: Workstation +metadata: + name: workstation-${uniqueId} +spec: + parentRef: + name: workstationconfig-${uniqueId} + displayName: workstation-${uniqueId} \ No newline at end of file diff --git a/pkg/test/resourcefixture/testdata/basic/workstations/workstation/workstation-minimal/dependencies.yaml b/pkg/test/resourcefixture/testdata/basic/workstations/workstation/workstation-minimal/dependencies.yaml new file mode 100644 index 0000000000..36297f9d45 --- /dev/null +++ b/pkg/test/resourcefixture/testdata/basic/workstations/workstation/workstation-minimal/dependencies.yaml @@ -0,0 +1,52 @@ +# Copyright 2024 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. + +apiVersion: compute.cnrm.cloud.google.com/v1beta1 +kind: ComputeNetwork +metadata: + name: computenetwork-${uniqueId} +spec: + routingMode: GLOBAL + autoCreateSubnetworks: false +--- +apiVersion: compute.cnrm.cloud.google.com/v1beta1 +kind: ComputeSubnetwork +metadata: + name: computesubnetwork-${uniqueId} +spec: + ipCidrRange: 10.0.0.0/24 + region: us-west1 + networkRef: + name: computenetwork-${uniqueId} +--- +apiVersion: workstations.cnrm.cloud.google.com/v1beta1 +kind: WorkstationCluster +metadata: + name: workstationcluster-${uniqueId} +spec: + projectRef: + external: ${projectId} + location: us-west1 + networkRef: + name: computenetwork-${uniqueId} + subnetworkRef: + name: computesubnetwork-${uniqueId} +--- +apiVersion: workstations.cnrm.cloud.google.com/v1alpha1 +kind: WorkstationConfig +metadata: + name: workstationconfig-${uniqueId} +spec: + parentRef: + name: workstationcluster-${uniqueId} \ No newline at end of file From 3c67f4f8846ba0ee0e96e580d98f235748d5f10a Mon Sep 17 00:00:00 2001 From: Jason Vigil Date: Thu, 5 Dec 2024 20:50:27 +0000 Subject: [PATCH 4/7] feat: Add mockgcp for Workstation --- config/tests/samples/create/harness.go | 1 + mockgcp/mockworkstations/workstations.go | 130 +++++++ .../workstations/workstation_controller.go | 3 + .../workstation/workstation-full/_http.log | 282 ++------------ .../workstation/workstation-minimal/_http.log | 352 ++---------------- 5 files changed, 208 insertions(+), 560 deletions(-) diff --git a/config/tests/samples/create/harness.go b/config/tests/samples/create/harness.go index 3fdddc071d..9a999ec696 100644 --- a/config/tests/samples/create/harness.go +++ b/config/tests/samples/create/harness.go @@ -880,6 +880,7 @@ func MaybeSkip(t *testing.T, name string, resources []*unstructured.Unstructured case schema.GroupKind{Group: "workstations.cnrm.cloud.google.com", Kind: "WorkstationCluster"}: case schema.GroupKind{Group: "workstations.cnrm.cloud.google.com", Kind: "WorkstationConfig"}: + case schema.GroupKind{Group: "workstations.cnrm.cloud.google.com", Kind: "Workstation"}: case schema.GroupKind{Group: "vertexai.cnrm.cloud.google.com", Kind: "VertexAIDataset"}: case schema.GroupKind{Group: "vertexai.cnrm.cloud.google.com", Kind: "VertexAITensorboard"}: diff --git a/mockgcp/mockworkstations/workstations.go b/mockgcp/mockworkstations/workstations.go index 810785f2c5..5b9cd3333c 100644 --- a/mockgcp/mockworkstations/workstations.go +++ b/mockgcp/mockworkstations/workstations.go @@ -244,6 +244,113 @@ func (s *WorkstationsService) DeleteWorkstationConfig(ctx context.Context, req * return op, err } +func (s *WorkstationsService) GetWorkstation(ctx context.Context, req *pb.GetWorkstationRequest) (*pb.Workstation, error) { + fqn := req.GetName() + + obj := &pb.Workstation{} + if err := s.storage.Get(ctx, fqn, obj); err != nil { + if status.Code(err) == codes.NotFound { + return nil, status.Errorf(codes.NotFound, "Requested entity was not found.") + } + return nil, err + } + + return obj, nil +} + +func (s *WorkstationsService) CreateWorkstation(ctx context.Context, req *pb.CreateWorkstationRequest) (*longrunningpb.Operation, error) { + fqn := req.GetParent() + "/workstations/" + req.GetWorkstationId() + location, err := getWorkstationLocation(fqn) + if err != nil { + return nil, err + } + + obj := proto.Clone(req.Workstation).(*pb.Workstation) + populateDefaultsForWorkstation(obj, false) + if err := s.storage.Create(ctx, fqn, obj); err != nil { + return nil, err + } + + t := timestamppb.New(time.Now()) + metadata := &pb.OperationMetadata{ + CreateTime: t, + ApiVersion: "v1", + RequestedCancellation: false, + Target: fqn, + Verb: "create", + } + op, err := s.operations.StartLRO(ctx, location, metadata, func() (proto.Message, error) { + metadata.EndTime = t + result := proto.Clone(obj).(*pb.Workstation) + s.storage.Update(ctx, fqn, result) + return result, nil + }) + return op, err +} + +func (s *WorkstationsService) UpdateWorkstation(ctx context.Context, req *pb.UpdateWorkstationRequest) (*longrunningpb.Operation, error) { + fqn := req.GetWorkstation().GetName() + location, err := getWorkstationLocation(fqn) + if err != nil { + return nil, err + } + + existing := &pb.Workstation{} + if err := s.storage.Get(ctx, fqn, existing); err != nil { + return nil, err + } + + updated := proto.Clone(req.Workstation).(*pb.Workstation) + populateDefaultsForWorkstation(updated, true) + if err := s.storage.Update(ctx, fqn, updated); err != nil { + return nil, err + } + + t := timestamppb.New(time.Now()) + metadata := &pb.OperationMetadata{ + CreateTime: t, + ApiVersion: "v1", + RequestedCancellation: false, + Target: fqn, + Verb: "update", + } + op, err := s.operations.StartLRO(ctx, location, metadata, func() (proto.Message, error) { + result := proto.Clone(updated).(*pb.Workstation) + return result, nil + }) + if err != nil { + return op, err + } + return op, err +} + +func (s *WorkstationsService) DeleteWorkstation(ctx context.Context, req *pb.DeleteWorkstationRequest) (*longrunningpb.Operation, error) { + fqn := req.GetName() + location, err := getWorkstationLocation(fqn) + if err != nil { + return nil, err + } + + deleted := &pb.Workstation{} + if err := s.storage.Delete(ctx, fqn, deleted); err != nil { + return nil, err + } + + t := timestamppb.New(time.Now()) + metadata := &pb.OperationMetadata{ + CreateTime: t, + ApiVersion: "v1", + RequestedCancellation: false, + Target: fqn, + Verb: "delete", + } + op, err := s.operations.StartLRO(ctx, location, metadata, func() (proto.Message, error) { + metadata.EndTime = t + return &pb.Workstation{}, nil + }) + return op, err +} + func getWorkstationClusterParent(fqn string) (string, error) { tokens := strings.Split(fqn, "/") if len(tokens) != 6 || tokens[0] != "projects" || tokens[2] != "locations" || tokens[4] != "workstationClusters" { @@ -260,6 +367,14 @@ func getWorkstationConfigLocation(fqn string) (string, error) { return tokens[0] + "/" + tokens[1] + "/" + tokens[2] + "/" + tokens[3], nil } +func getWorkstationLocation(fqn string) (string, error) { + tokens := strings.Split(fqn, "/") + if len(tokens) != 10 || tokens[0] != "projects" || tokens[2] != "locations" || tokens[4] != "workstationClusters" || tokens[6] != "workstationConfigs" || tokens[8] != "workstations" { + return "", fmt.Errorf("fqn should be projects//locations//workstationClusters//workstationConfigs//workstations/, got %s", fqn) + } + return tokens[0] + "/" + tokens[1] + "/" + tokens[2] + "/" + tokens[3], nil +} + func populateDefaultsForWorkstationCluster(obj *pb.WorkstationCluster, update bool) { if obj.Uid == "" { obj.Uid = fmt.Sprintf("%x", time.Now().UnixNano()) @@ -315,6 +430,21 @@ func populateDefaultsForWorkstationConfig(obj *pb.WorkstationConfig, update bool obj.Etag = computeEtag(obj) } +func populateDefaultsForWorkstation(obj *pb.Workstation, update bool) { + if obj.Uid == "" { + obj.Uid = fmt.Sprintf("%x", time.Now().UnixNano()) + } + t := timestamppb.New(time.Now()) + if obj.CreateTime == nil { + obj.CreateTime = t + } + if obj.UpdateTime == nil || update { + obj.UpdateTime = t + } + obj.Etag = computeEtag(obj) + obj.State = pb.Workstation_STATE_STOPPED +} + func populateOutputsForWorkstationCluster(obj *pb.WorkstationCluster, fqn string) { if obj.Name == "" { obj.Name = fqn diff --git a/pkg/controller/direct/workstations/workstation_controller.go b/pkg/controller/direct/workstations/workstation_controller.go index 3d6657dce4..b33aee0d49 100644 --- a/pkg/controller/direct/workstations/workstation_controller.go +++ b/pkg/controller/direct/workstations/workstation_controller.go @@ -134,6 +134,9 @@ func (a *WorkstationAdapter) Create(ctx context.Context, createOp *directbase.Cr return mapCtx.Err() } + // Set name manually, because it is not filled-in by WorkstationSpec_ToProto. + resource.Name = a.id.String() + req := &workstationspb.CreateWorkstationRequest{ Parent: a.id.Parent().String(), WorkstationId: a.id.ID(), diff --git a/pkg/test/resourcefixture/testdata/basic/workstations/workstation/workstation-full/_http.log b/pkg/test/resourcefixture/testdata/basic/workstations/workstation/workstation-full/_http.log index 74a484a489..dcdbd6ca12 100644 --- a/pkg/test/resourcefixture/testdata/basic/workstations/workstation/workstation-full/_http.log +++ b/pkg/test/resourcefixture/testdata/basic/workstations/workstation/workstation-full/_http.log @@ -125,7 +125,6 @@ X-Xss-Protection: 0 "name": "computenetwork-${uniqueId}", "networkFirewallPolicyEnforcementOrder": "AFTER_CLASSIC_FIREWALL", "routingConfig": { - "bgpBestPathSelectionMode": "LEGACY", "routingMode": "GLOBAL" }, "selfLink": "https://www.googleapis.com/compute/v1/projects/${projectId}/global/networks/computenetwork-${uniqueId}", @@ -257,11 +256,10 @@ X-Frame-Options: SAMEORIGIN X-Xss-Protection: 0 { - "allowSubnetCidrRoutesOverlap": false, "creationTimestamp": "2024-04-01T12:34:56.123456Z", "enableFlowLogs": false, "fingerprint": "abcdef0123A=", - "gatewayAddress": "10.0.0.1", + "gatewayAddress": "10.2.0.1", "id": "000000000000000000000", "ipCidrRange": "10.0.0.0/24", "kind": "compute#subnetwork", @@ -299,7 +297,14 @@ X-Xss-Protection: 0 { "error": { "code": 404, - "message": "Resource 'projects/${projectId}/locations/us-west1/workstationClusters/workstationcluster-${uniqueId}' was not found", + "errors": [ + { + "domain": "global", + "message": "Requested entity was not found.", + "reason": "notFound" + } + ], + "message": "Requested entity was not found.", "status": "NOT_FOUND" } } @@ -328,12 +333,10 @@ X-Frame-Options: SAMEORIGIN X-Xss-Protection: 0 { - "done": false, "metadata": { "@type": "type.googleapis.com/google.cloud.workstations.v1.OperationMetadata", "apiVersion": "v1", "createTime": "2024-04-01T12:34:56.123456Z", - "requestedCancellation": false, "target": "projects/${projectId}/locations/us-west1/workstationClusters/workstationcluster-${uniqueId}", "verb": "create" }, @@ -342,115 +345,6 @@ X-Xss-Protection: 0 --- -GET https://compute.googleapis.com/compute/v1/projects/${projectId}/global/networks/${networkID}?alt=json -Content-Type: application/json -User-Agent: Terraform/ (+https://www.terraform.io) Terraform-Plugin-SDK/2.10.1 terraform-provider-google-beta/kcc/controller-manager - -200 OK -Cache-Control: private -Content-Type: application/json; charset=UTF-8 -Server: ESF -Vary: Origin -Vary: X-Origin -Vary: Referer -X-Content-Type-Options: nosniff -X-Frame-Options: SAMEORIGIN -X-Xss-Protection: 0 - -{ - "autoCreateSubnetworks": false, - "creationTimestamp": "2024-04-01T12:34:56.123456Z", - "id": "000000000000000000000", - "kind": "compute#network", - "name": "computenetwork-${uniqueId}", - "networkFirewallPolicyEnforcementOrder": "AFTER_CLASSIC_FIREWALL", - "routingConfig": { - "bgpBestPathSelectionMode": "LEGACY", - "routingMode": "GLOBAL" - }, - "selfLink": "https://www.googleapis.com/compute/v1/projects/${projectId}/global/networks/computenetwork-${uniqueId}", - "selfLinkWithId": "https://www.googleapis.com/compute/v1/projects/${projectId}/global/networks/${networkID}", - "subnetworks": [ - "https://www.googleapis.com/compute/v1/projects/${projectId}/regions/us-west1/subnetworks/computesubnetwork-${uniqueId}" - ] -} - ---- - -GET https://compute.googleapis.com/compute/v1/projects/${projectId}/regions/us-west1/subnetworks/${subnetworkID}?alt=json -Content-Type: application/json -User-Agent: Terraform/ (+https://www.terraform.io) Terraform-Plugin-SDK/2.10.1 terraform-provider-google-beta/kcc/controller-manager - -200 OK -Cache-Control: private -Content-Type: application/json; charset=UTF-8 -Server: ESF -Vary: Origin -Vary: X-Origin -Vary: Referer -X-Content-Type-Options: nosniff -X-Frame-Options: SAMEORIGIN -X-Xss-Protection: 0 - -{ - "allowSubnetCidrRoutesOverlap": false, - "creationTimestamp": "2024-04-01T12:34:56.123456Z", - "enableFlowLogs": false, - "fingerprint": "abcdef0123A=", - "gatewayAddress": "10.0.0.1", - "id": "000000000000000000000", - "ipCidrRange": "10.0.0.0/24", - "kind": "compute#subnetwork", - "logConfig": { - "enable": false - }, - "name": "computesubnetwork-${uniqueId}", - "network": "https://www.googleapis.com/compute/v1/projects/${projectId}/global/networks/computenetwork-${uniqueId}", - "privateIpGoogleAccess": false, - "privateIpv6GoogleAccess": "DISABLE_GOOGLE_ACCESS", - "purpose": "PRIVATE", - "region": "https://www.googleapis.com/compute/v1/projects/${projectId}/regions/us-west1", - "selfLink": "https://www.googleapis.com/compute/v1/projects/${projectId}/regions/us-west1/subnetworks/computesubnetwork-${uniqueId}", - "stackType": "IPV4_ONLY" -} - ---- - -GET https://compute.googleapis.com/compute/v1/projects/${projectId}/global/networks/${networkID}?alt=json -Content-Type: application/json -User-Agent: Terraform/ (+https://www.terraform.io) Terraform-Plugin-SDK/2.10.1 terraform-provider-google-beta/kcc/controller-manager - -200 OK -Cache-Control: private -Content-Type: application/json; charset=UTF-8 -Server: ESF -Vary: Origin -Vary: X-Origin -Vary: Referer -X-Content-Type-Options: nosniff -X-Frame-Options: SAMEORIGIN -X-Xss-Protection: 0 - -{ - "autoCreateSubnetworks": false, - "creationTimestamp": "2024-04-01T12:34:56.123456Z", - "id": "000000000000000000000", - "kind": "compute#network", - "name": "computenetwork-${uniqueId}", - "networkFirewallPolicyEnforcementOrder": "AFTER_CLASSIC_FIREWALL", - "routingConfig": { - "bgpBestPathSelectionMode": "LEGACY", - "routingMode": "GLOBAL" - }, - "selfLink": "https://www.googleapis.com/compute/v1/projects/${projectId}/global/networks/computenetwork-${uniqueId}", - "selfLinkWithId": "https://www.googleapis.com/compute/v1/projects/${projectId}/global/networks/${networkID}", - "subnetworks": [ - "https://www.googleapis.com/compute/v1/projects/${projectId}/regions/us-west1/subnetworks/computesubnetwork-${uniqueId}" - ] -} - ---- - GET https://workstations.googleapis.com/v1/projects/${projectId}/locations/us-west1/operations/${operationID} Content-Type: application/json User-Agent: kcc/controller-manager @@ -474,7 +368,6 @@ X-Xss-Protection: 0 "apiVersion": "v1", "createTime": "2024-04-01T12:34:56.123456Z", "endTime": "2024-04-01T12:34:56.123456Z", - "requestedCancellation": false, "target": "projects/${projectId}/locations/us-west1/workstationClusters/workstationcluster-${uniqueId}", "verb": "create" }, @@ -514,7 +407,14 @@ X-Xss-Protection: 0 { "error": { "code": 404, - "message": "Resource 'projects/${projectId}/locations/us-west1/workstationClusters/workstationcluster-${uniqueId}/workstationConfigs/workstationconfig-${uniqueId}' was not found", + "errors": [ + { + "domain": "global", + "message": "Requested entity was not found.", + "reason": "notFound" + } + ], + "message": "Requested entity was not found.", "status": "NOT_FOUND" } } @@ -528,6 +428,7 @@ x-goog-request-params: parent=projects%2F${projectId}%2Flocations%2Fus-west1%2Fw { "idleTimeout": "1200s", + "name": "projects/${projectId}/locations/us-west1/workstationClusters/workstationcluster-${uniqueId}/workstationConfigs/workstationconfig-${uniqueId}", "runningTimeout": "43200s" } @@ -543,12 +444,10 @@ X-Frame-Options: SAMEORIGIN X-Xss-Protection: 0 { - "done": false, "metadata": { "@type": "type.googleapis.com/google.cloud.workstations.v1.OperationMetadata", "apiVersion": "v1", "createTime": "2024-04-01T12:34:56.123456Z", - "requestedCancellation": false, "target": "projects/${projectId}/locations/us-west1/workstationClusters/workstationcluster-${uniqueId}/workstationConfigs/workstationconfig-${uniqueId}", "verb": "create" }, @@ -580,27 +479,12 @@ X-Xss-Protection: 0 "apiVersion": "v1", "createTime": "2024-04-01T12:34:56.123456Z", "endTime": "2024-04-01T12:34:56.123456Z", - "requestedCancellation": false, "target": "projects/${projectId}/locations/us-west1/workstationClusters/workstationcluster-${uniqueId}/workstationConfigs/workstationconfig-${uniqueId}", "verb": "create" }, "name": "projects/${projectId}/locations/us-west1/operations/${operationID}", "response": { "@type": "type.googleapis.com/google.cloud.workstations.v1.WorkstationConfig", - "allowedPorts": [ - { - "first": 22, - "last": 22 - }, - { - "first": 80, - "last": 80 - }, - { - "first": 1024, - "last": 65535 - } - ], "container": { "image": "us-west1-docker.pkg.dev/cloud-workstations-images/predefined/code-oss:latest" }, @@ -648,7 +532,14 @@ X-Xss-Protection: 0 { "error": { "code": 404, - "message": "Resource 'projects/${projectId}/locations/us-west1/workstationClusters/workstationcluster-${uniqueId}/workstationConfigs/workstationconfig-${uniqueId}/workstations/workstation-${uniqueId}' was not found", + "errors": [ + { + "domain": "global", + "message": "Requested entity was not found.", + "reason": "notFound" + } + ], + "message": "Requested entity was not found.", "status": "NOT_FOUND" } } @@ -667,7 +558,8 @@ x-goog-request-params: parent=projects%2F${projectId}%2Flocations%2Fus-west1%2Fw "displayName": "workstation-${uniqueId}", "labels": { "l-key1": "l-value1" - } + }, + "name": "projects/${projectId}/locations/us-west1/workstationClusters/workstationcluster-${uniqueId}/workstationConfigs/workstationconfig-${uniqueId}/workstations/workstation-${uniqueId}" } 200 OK @@ -682,12 +574,10 @@ X-Frame-Options: SAMEORIGIN X-Xss-Protection: 0 { - "done": false, "metadata": { "@type": "type.googleapis.com/google.cloud.workstations.v1.OperationMetadata", "apiVersion": "v1", "createTime": "2024-04-01T12:34:56.123456Z", - "requestedCancellation": false, "target": "projects/${projectId}/locations/us-west1/workstationClusters/workstationcluster-${uniqueId}/workstationConfigs/workstationconfig-${uniqueId}/workstations/workstation-${uniqueId}", "verb": "create" }, @@ -719,7 +609,6 @@ X-Xss-Protection: 0 "apiVersion": "v1", "createTime": "2024-04-01T12:34:56.123456Z", "endTime": "2024-04-01T12:34:56.123456Z", - "requestedCancellation": false, "target": "projects/${projectId}/locations/us-west1/workstationClusters/workstationcluster-${uniqueId}/workstationConfigs/workstationconfig-${uniqueId}/workstations/workstation-${uniqueId}", "verb": "create" }, @@ -809,12 +698,10 @@ X-Frame-Options: SAMEORIGIN X-Xss-Protection: 0 { - "done": false, "metadata": { "@type": "type.googleapis.com/google.cloud.workstations.v1.OperationMetadata", "apiVersion": "v1", "createTime": "2024-04-01T12:34:56.123456Z", - "requestedCancellation": false, "target": "projects/${projectId}/locations/us-west1/workstationClusters/workstationcluster-${uniqueId}/workstationConfigs/workstationconfig-${uniqueId}/workstations/workstation-${uniqueId}", "verb": "update" }, @@ -845,8 +732,6 @@ X-Xss-Protection: 0 "@type": "type.googleapis.com/google.cloud.workstations.v1.OperationMetadata", "apiVersion": "v1", "createTime": "2024-04-01T12:34:56.123456Z", - "endTime": "2024-04-01T12:34:56.123456Z", - "requestedCancellation": false, "target": "projects/${projectId}/locations/us-west1/workstationClusters/workstationcluster-${uniqueId}/workstationConfigs/workstationconfig-${uniqueId}/workstations/workstation-${uniqueId}", "verb": "update" }, @@ -926,12 +811,10 @@ X-Frame-Options: SAMEORIGIN X-Xss-Protection: 0 { - "done": false, "metadata": { "@type": "type.googleapis.com/google.cloud.workstations.v1.OperationMetadata", "apiVersion": "v1", "createTime": "2024-04-01T12:34:56.123456Z", - "requestedCancellation": false, "target": "projects/${projectId}/locations/us-west1/workstationClusters/workstationcluster-${uniqueId}/workstationConfigs/workstationconfig-${uniqueId}/workstations/workstation-${uniqueId}", "verb": "delete" }, @@ -963,7 +846,6 @@ X-Xss-Protection: 0 "apiVersion": "v1", "createTime": "2024-04-01T12:34:56.123456Z", "endTime": "2024-04-01T12:34:56.123456Z", - "requestedCancellation": false, "target": "projects/${projectId}/locations/us-west1/workstationClusters/workstationcluster-${uniqueId}/workstationConfigs/workstationconfig-${uniqueId}/workstations/workstation-${uniqueId}", "verb": "delete" }, @@ -992,20 +874,6 @@ X-Frame-Options: SAMEORIGIN X-Xss-Protection: 0 { - "allowedPorts": [ - { - "first": 22, - "last": 22 - }, - { - "first": 80, - "last": 80 - }, - { - "first": 1024, - "last": 65535 - } - ], "container": { "image": "us-west1-docker.pkg.dev/cloud-workstations-images/predefined/code-oss:latest" }, @@ -1050,12 +918,10 @@ X-Frame-Options: SAMEORIGIN X-Xss-Protection: 0 { - "done": false, "metadata": { "@type": "type.googleapis.com/google.cloud.workstations.v1.OperationMetadata", "apiVersion": "v1", "createTime": "2024-04-01T12:34:56.123456Z", - "requestedCancellation": false, "target": "projects/${projectId}/locations/us-west1/workstationClusters/workstationcluster-${uniqueId}/workstationConfigs/workstationconfig-${uniqueId}", "verb": "delete" }, @@ -1087,11 +953,13 @@ X-Xss-Protection: 0 "apiVersion": "v1", "createTime": "2024-04-01T12:34:56.123456Z", "endTime": "2024-04-01T12:34:56.123456Z", - "requestedCancellation": false, "target": "projects/${projectId}/locations/us-west1/workstationClusters/workstationcluster-${uniqueId}/workstationConfigs/workstationconfig-${uniqueId}", "verb": "delete" }, - "name": "projects/${projectId}/locations/us-west1/operations/${operationID}" + "name": "projects/${projectId}/locations/us-west1/operations/${operationID}", + "response": { + "@type": "type.googleapis.com/google.cloud.workstations.v1.WorkstationConfig" + } } --- @@ -1143,12 +1011,10 @@ X-Frame-Options: SAMEORIGIN X-Xss-Protection: 0 { - "done": false, "metadata": { "@type": "type.googleapis.com/google.cloud.workstations.v1.OperationMetadata", "apiVersion": "v1", "createTime": "2024-04-01T12:34:56.123456Z", - "requestedCancellation": false, "target": "projects/${projectId}/locations/us-west1/workstationClusters/workstationcluster-${uniqueId}", "verb": "delete" }, @@ -1157,80 +1023,6 @@ X-Xss-Protection: 0 --- -GET https://compute.googleapis.com/compute/v1/projects/${projectId}/regions/us-west1/subnetworks/${subnetworkID}?alt=json -Content-Type: application/json -User-Agent: Terraform/ (+https://www.terraform.io) Terraform-Plugin-SDK/2.10.1 terraform-provider-google-beta/kcc/controller-manager - -200 OK -Cache-Control: private -Content-Type: application/json; charset=UTF-8 -Server: ESF -Vary: Origin -Vary: X-Origin -Vary: Referer -X-Content-Type-Options: nosniff -X-Frame-Options: SAMEORIGIN -X-Xss-Protection: 0 - -{ - "allowSubnetCidrRoutesOverlap": false, - "creationTimestamp": "2024-04-01T12:34:56.123456Z", - "enableFlowLogs": false, - "fingerprint": "abcdef0123A=", - "gatewayAddress": "10.0.0.1", - "id": "000000000000000000000", - "ipCidrRange": "10.0.0.0/24", - "kind": "compute#subnetwork", - "logConfig": { - "enable": false - }, - "name": "computesubnetwork-${uniqueId}", - "network": "https://www.googleapis.com/compute/v1/projects/${projectId}/global/networks/computenetwork-${uniqueId}", - "privateIpGoogleAccess": false, - "privateIpv6GoogleAccess": "DISABLE_GOOGLE_ACCESS", - "purpose": "PRIVATE", - "region": "https://www.googleapis.com/compute/v1/projects/${projectId}/regions/us-west1", - "selfLink": "https://www.googleapis.com/compute/v1/projects/${projectId}/regions/us-west1/subnetworks/computesubnetwork-${uniqueId}", - "stackType": "IPV4_ONLY" -} - ---- - -GET https://compute.googleapis.com/compute/v1/projects/${projectId}/global/networks/${networkID}?alt=json -Content-Type: application/json -User-Agent: Terraform/ (+https://www.terraform.io) Terraform-Plugin-SDK/2.10.1 terraform-provider-google-beta/kcc/controller-manager - -200 OK -Cache-Control: private -Content-Type: application/json; charset=UTF-8 -Server: ESF -Vary: Origin -Vary: X-Origin -Vary: Referer -X-Content-Type-Options: nosniff -X-Frame-Options: SAMEORIGIN -X-Xss-Protection: 0 - -{ - "autoCreateSubnetworks": false, - "creationTimestamp": "2024-04-01T12:34:56.123456Z", - "id": "000000000000000000000", - "kind": "compute#network", - "name": "computenetwork-${uniqueId}", - "networkFirewallPolicyEnforcementOrder": "AFTER_CLASSIC_FIREWALL", - "routingConfig": { - "bgpBestPathSelectionMode": "LEGACY", - "routingMode": "GLOBAL" - }, - "selfLink": "https://www.googleapis.com/compute/v1/projects/${projectId}/global/networks/computenetwork-${uniqueId}", - "selfLinkWithId": "https://www.googleapis.com/compute/v1/projects/${projectId}/global/networks/${networkID}", - "subnetworks": [ - "https://www.googleapis.com/compute/v1/projects/${projectId}/regions/us-west1/subnetworks/computesubnetwork-${uniqueId}" - ] -} - ---- - GET https://workstations.googleapis.com/v1/projects/${projectId}/locations/us-west1/operations/${operationID} Content-Type: application/json User-Agent: kcc/controller-manager @@ -1254,11 +1046,13 @@ X-Xss-Protection: 0 "apiVersion": "v1", "createTime": "2024-04-01T12:34:56.123456Z", "endTime": "2024-04-01T12:34:56.123456Z", - "requestedCancellation": false, "target": "projects/${projectId}/locations/us-west1/workstationClusters/workstationcluster-${uniqueId}", "verb": "delete" }, - "name": "projects/${projectId}/locations/us-west1/operations/${operationID}" + "name": "projects/${projectId}/locations/us-west1/operations/${operationID}", + "response": { + "@type": "type.googleapis.com/google.cloud.workstations.v1.WorkstationCluster" + } } --- @@ -1279,11 +1073,10 @@ X-Frame-Options: SAMEORIGIN X-Xss-Protection: 0 { - "allowSubnetCidrRoutesOverlap": false, "creationTimestamp": "2024-04-01T12:34:56.123456Z", "enableFlowLogs": false, "fingerprint": "abcdef0123A=", - "gatewayAddress": "10.0.0.1", + "gatewayAddress": "10.2.0.1", "id": "000000000000000000000", "ipCidrRange": "10.0.0.0/24", "kind": "compute#subnetwork", @@ -1391,7 +1184,6 @@ X-Xss-Protection: 0 "name": "computenetwork-${uniqueId}", "networkFirewallPolicyEnforcementOrder": "AFTER_CLASSIC_FIREWALL", "routingConfig": { - "bgpBestPathSelectionMode": "LEGACY", "routingMode": "GLOBAL" }, "selfLink": "https://www.googleapis.com/compute/v1/projects/${projectId}/global/networks/computenetwork-${uniqueId}", diff --git a/pkg/test/resourcefixture/testdata/basic/workstations/workstation/workstation-minimal/_http.log b/pkg/test/resourcefixture/testdata/basic/workstations/workstation/workstation-minimal/_http.log index afd7aa5c82..984547719d 100644 --- a/pkg/test/resourcefixture/testdata/basic/workstations/workstation/workstation-minimal/_http.log +++ b/pkg/test/resourcefixture/testdata/basic/workstations/workstation/workstation-minimal/_http.log @@ -125,7 +125,6 @@ X-Xss-Protection: 0 "name": "computenetwork-${uniqueId}", "networkFirewallPolicyEnforcementOrder": "AFTER_CLASSIC_FIREWALL", "routingConfig": { - "bgpBestPathSelectionMode": "LEGACY", "routingMode": "GLOBAL" }, "selfLink": "https://www.googleapis.com/compute/v1/projects/${projectId}/global/networks/computenetwork-${uniqueId}", @@ -257,11 +256,10 @@ X-Frame-Options: SAMEORIGIN X-Xss-Protection: 0 { - "allowSubnetCidrRoutesOverlap": false, "creationTimestamp": "2024-04-01T12:34:56.123456Z", "enableFlowLogs": false, "fingerprint": "abcdef0123A=", - "gatewayAddress": "10.0.0.1", + "gatewayAddress": "10.2.0.1", "id": "000000000000000000000", "ipCidrRange": "10.0.0.0/24", "kind": "compute#subnetwork", @@ -299,7 +297,14 @@ X-Xss-Protection: 0 { "error": { "code": 404, - "message": "Resource 'projects/${projectId}/locations/us-west1/workstationClusters/workstationcluster-${uniqueId}' was not found", + "errors": [ + { + "domain": "global", + "message": "Requested entity was not found.", + "reason": "notFound" + } + ], + "message": "Requested entity was not found.", "status": "NOT_FOUND" } } @@ -328,12 +333,10 @@ X-Frame-Options: SAMEORIGIN X-Xss-Protection: 0 { - "done": false, "metadata": { "@type": "type.googleapis.com/google.cloud.workstations.v1.OperationMetadata", "apiVersion": "v1", "createTime": "2024-04-01T12:34:56.123456Z", - "requestedCancellation": false, "target": "projects/${projectId}/locations/us-west1/workstationClusters/workstationcluster-${uniqueId}", "verb": "create" }, @@ -342,115 +345,6 @@ X-Xss-Protection: 0 --- -GET https://compute.googleapis.com/compute/v1/projects/${projectId}/global/networks/${networkID}?alt=json -Content-Type: application/json -User-Agent: Terraform/ (+https://www.terraform.io) Terraform-Plugin-SDK/2.10.1 terraform-provider-google-beta/kcc/controller-manager - -200 OK -Cache-Control: private -Content-Type: application/json; charset=UTF-8 -Server: ESF -Vary: Origin -Vary: X-Origin -Vary: Referer -X-Content-Type-Options: nosniff -X-Frame-Options: SAMEORIGIN -X-Xss-Protection: 0 - -{ - "autoCreateSubnetworks": false, - "creationTimestamp": "2024-04-01T12:34:56.123456Z", - "id": "000000000000000000000", - "kind": "compute#network", - "name": "computenetwork-${uniqueId}", - "networkFirewallPolicyEnforcementOrder": "AFTER_CLASSIC_FIREWALL", - "routingConfig": { - "bgpBestPathSelectionMode": "LEGACY", - "routingMode": "GLOBAL" - }, - "selfLink": "https://www.googleapis.com/compute/v1/projects/${projectId}/global/networks/computenetwork-${uniqueId}", - "selfLinkWithId": "https://www.googleapis.com/compute/v1/projects/${projectId}/global/networks/${networkID}", - "subnetworks": [ - "https://www.googleapis.com/compute/v1/projects/${projectId}/regions/us-west1/subnetworks/computesubnetwork-${uniqueId}" - ] -} - ---- - -GET https://compute.googleapis.com/compute/v1/projects/${projectId}/regions/us-west1/subnetworks/${subnetworkID}?alt=json -Content-Type: application/json -User-Agent: Terraform/ (+https://www.terraform.io) Terraform-Plugin-SDK/2.10.1 terraform-provider-google-beta/kcc/controller-manager - -200 OK -Cache-Control: private -Content-Type: application/json; charset=UTF-8 -Server: ESF -Vary: Origin -Vary: X-Origin -Vary: Referer -X-Content-Type-Options: nosniff -X-Frame-Options: SAMEORIGIN -X-Xss-Protection: 0 - -{ - "allowSubnetCidrRoutesOverlap": false, - "creationTimestamp": "2024-04-01T12:34:56.123456Z", - "enableFlowLogs": false, - "fingerprint": "abcdef0123A=", - "gatewayAddress": "10.0.0.1", - "id": "000000000000000000000", - "ipCidrRange": "10.0.0.0/24", - "kind": "compute#subnetwork", - "logConfig": { - "enable": false - }, - "name": "computesubnetwork-${uniqueId}", - "network": "https://www.googleapis.com/compute/v1/projects/${projectId}/global/networks/computenetwork-${uniqueId}", - "privateIpGoogleAccess": false, - "privateIpv6GoogleAccess": "DISABLE_GOOGLE_ACCESS", - "purpose": "PRIVATE", - "region": "https://www.googleapis.com/compute/v1/projects/${projectId}/regions/us-west1", - "selfLink": "https://www.googleapis.com/compute/v1/projects/${projectId}/regions/us-west1/subnetworks/computesubnetwork-${uniqueId}", - "stackType": "IPV4_ONLY" -} - ---- - -GET https://compute.googleapis.com/compute/v1/projects/${projectId}/global/networks/${networkID}?alt=json -Content-Type: application/json -User-Agent: Terraform/ (+https://www.terraform.io) Terraform-Plugin-SDK/2.10.1 terraform-provider-google-beta/kcc/controller-manager - -200 OK -Cache-Control: private -Content-Type: application/json; charset=UTF-8 -Server: ESF -Vary: Origin -Vary: X-Origin -Vary: Referer -X-Content-Type-Options: nosniff -X-Frame-Options: SAMEORIGIN -X-Xss-Protection: 0 - -{ - "autoCreateSubnetworks": false, - "creationTimestamp": "2024-04-01T12:34:56.123456Z", - "id": "000000000000000000000", - "kind": "compute#network", - "name": "computenetwork-${uniqueId}", - "networkFirewallPolicyEnforcementOrder": "AFTER_CLASSIC_FIREWALL", - "routingConfig": { - "bgpBestPathSelectionMode": "LEGACY", - "routingMode": "GLOBAL" - }, - "selfLink": "https://www.googleapis.com/compute/v1/projects/${projectId}/global/networks/computenetwork-${uniqueId}", - "selfLinkWithId": "https://www.googleapis.com/compute/v1/projects/${projectId}/global/networks/${networkID}", - "subnetworks": [ - "https://www.googleapis.com/compute/v1/projects/${projectId}/regions/us-west1/subnetworks/computesubnetwork-${uniqueId}" - ] -} - ---- - GET https://workstations.googleapis.com/v1/projects/${projectId}/locations/us-west1/operations/${operationID} Content-Type: application/json User-Agent: kcc/controller-manager @@ -474,7 +368,6 @@ X-Xss-Protection: 0 "apiVersion": "v1", "createTime": "2024-04-01T12:34:56.123456Z", "endTime": "2024-04-01T12:34:56.123456Z", - "requestedCancellation": false, "target": "projects/${projectId}/locations/us-west1/workstationClusters/workstationcluster-${uniqueId}", "verb": "create" }, @@ -514,7 +407,14 @@ X-Xss-Protection: 0 { "error": { "code": 404, - "message": "Resource 'projects/${projectId}/locations/us-west1/workstationClusters/workstationcluster-${uniqueId}/workstationConfigs/workstationconfig-${uniqueId}' was not found", + "errors": [ + { + "domain": "global", + "message": "Requested entity was not found.", + "reason": "notFound" + } + ], + "message": "Requested entity was not found.", "status": "NOT_FOUND" } } @@ -528,6 +428,7 @@ x-goog-request-params: parent=projects%2F${projectId}%2Flocations%2Fus-west1%2Fw { "idleTimeout": "1200s", + "name": "projects/${projectId}/locations/us-west1/workstationClusters/workstationcluster-${uniqueId}/workstationConfigs/workstationconfig-${uniqueId}", "runningTimeout": "43200s" } @@ -543,12 +444,10 @@ X-Frame-Options: SAMEORIGIN X-Xss-Protection: 0 { - "done": false, "metadata": { "@type": "type.googleapis.com/google.cloud.workstations.v1.OperationMetadata", "apiVersion": "v1", "createTime": "2024-04-01T12:34:56.123456Z", - "requestedCancellation": false, "target": "projects/${projectId}/locations/us-west1/workstationClusters/workstationcluster-${uniqueId}/workstationConfigs/workstationconfig-${uniqueId}", "verb": "create" }, @@ -580,27 +479,12 @@ X-Xss-Protection: 0 "apiVersion": "v1", "createTime": "2024-04-01T12:34:56.123456Z", "endTime": "2024-04-01T12:34:56.123456Z", - "requestedCancellation": false, "target": "projects/${projectId}/locations/us-west1/workstationClusters/workstationcluster-${uniqueId}/workstationConfigs/workstationconfig-${uniqueId}", "verb": "create" }, "name": "projects/${projectId}/locations/us-west1/operations/${operationID}", "response": { "@type": "type.googleapis.com/google.cloud.workstations.v1.WorkstationConfig", - "allowedPorts": [ - { - "first": 22, - "last": 22 - }, - { - "first": 80, - "last": 80 - }, - { - "first": 1024, - "last": 65535 - } - ], "container": { "image": "us-west1-docker.pkg.dev/cloud-workstations-images/predefined/code-oss:latest" }, @@ -648,7 +532,14 @@ X-Xss-Protection: 0 { "error": { "code": 404, - "message": "Resource 'projects/${projectId}/locations/us-west1/workstationClusters/workstationcluster-${uniqueId}/workstationConfigs/workstationconfig-${uniqueId}/workstations/workstation-${uniqueId}' was not found", + "errors": [ + { + "domain": "global", + "message": "Requested entity was not found.", + "reason": "notFound" + } + ], + "message": "Requested entity was not found.", "status": "NOT_FOUND" } } @@ -661,7 +552,8 @@ User-Agent: kcc/controller-manager x-goog-request-params: parent=projects%2F${projectId}%2Flocations%2Fus-west1%2FworkstationClusters%2Fworkstationcluster-${uniqueId}%2FworkstationConfigs%2Fworkstationconfig-${uniqueId} { - "displayName": "workstation-${uniqueId}" + "displayName": "workstation-${uniqueId}", + "name": "projects/${projectId}/locations/us-west1/workstationClusters/workstationcluster-${uniqueId}/workstationConfigs/workstationconfig-${uniqueId}/workstations/workstation-${uniqueId}" } 200 OK @@ -676,12 +568,10 @@ X-Frame-Options: SAMEORIGIN X-Xss-Protection: 0 { - "done": false, "metadata": { "@type": "type.googleapis.com/google.cloud.workstations.v1.OperationMetadata", "apiVersion": "v1", "createTime": "2024-04-01T12:34:56.123456Z", - "requestedCancellation": false, "target": "projects/${projectId}/locations/us-west1/workstationClusters/workstationcluster-${uniqueId}/workstationConfigs/workstationconfig-${uniqueId}/workstations/workstation-${uniqueId}", "verb": "create" }, @@ -713,7 +603,6 @@ X-Xss-Protection: 0 "apiVersion": "v1", "createTime": "2024-04-01T12:34:56.123456Z", "endTime": "2024-04-01T12:34:56.123456Z", - "requestedCancellation": false, "target": "projects/${projectId}/locations/us-west1/workstationClusters/workstationcluster-${uniqueId}/workstationConfigs/workstationconfig-${uniqueId}/workstations/workstation-${uniqueId}", "verb": "create" }, @@ -777,12 +666,10 @@ X-Frame-Options: SAMEORIGIN X-Xss-Protection: 0 { - "done": false, "metadata": { "@type": "type.googleapis.com/google.cloud.workstations.v1.OperationMetadata", "apiVersion": "v1", "createTime": "2024-04-01T12:34:56.123456Z", - "requestedCancellation": false, "target": "projects/${projectId}/locations/us-west1/workstationClusters/workstationcluster-${uniqueId}/workstationConfigs/workstationconfig-${uniqueId}/workstations/workstation-${uniqueId}", "verb": "delete" }, @@ -791,45 +678,6 @@ X-Xss-Protection: 0 --- -GET https://compute.googleapis.com/compute/v1/projects/${projectId}/regions/us-west1/subnetworks/${subnetworkID}?alt=json -Content-Type: application/json -User-Agent: Terraform/ (+https://www.terraform.io) Terraform-Plugin-SDK/2.10.1 terraform-provider-google-beta/kcc/controller-manager - -200 OK -Cache-Control: private -Content-Type: application/json; charset=UTF-8 -Server: ESF -Vary: Origin -Vary: X-Origin -Vary: Referer -X-Content-Type-Options: nosniff -X-Frame-Options: SAMEORIGIN -X-Xss-Protection: 0 - -{ - "allowSubnetCidrRoutesOverlap": false, - "creationTimestamp": "2024-04-01T12:34:56.123456Z", - "enableFlowLogs": false, - "fingerprint": "abcdef0123A=", - "gatewayAddress": "10.0.0.1", - "id": "000000000000000000000", - "ipCidrRange": "10.0.0.0/24", - "kind": "compute#subnetwork", - "logConfig": { - "enable": false - }, - "name": "computesubnetwork-${uniqueId}", - "network": "https://www.googleapis.com/compute/v1/projects/${projectId}/global/networks/computenetwork-${uniqueId}", - "privateIpGoogleAccess": false, - "privateIpv6GoogleAccess": "DISABLE_GOOGLE_ACCESS", - "purpose": "PRIVATE", - "region": "https://www.googleapis.com/compute/v1/projects/${projectId}/regions/us-west1", - "selfLink": "https://www.googleapis.com/compute/v1/projects/${projectId}/regions/us-west1/subnetworks/computesubnetwork-${uniqueId}", - "stackType": "IPV4_ONLY" -} - ---- - GET https://workstations.googleapis.com/v1/projects/${projectId}/locations/us-west1/operations/${operationID} Content-Type: application/json User-Agent: kcc/controller-manager @@ -853,7 +701,6 @@ X-Xss-Protection: 0 "apiVersion": "v1", "createTime": "2024-04-01T12:34:56.123456Z", "endTime": "2024-04-01T12:34:56.123456Z", - "requestedCancellation": false, "target": "projects/${projectId}/locations/us-west1/workstationClusters/workstationcluster-${uniqueId}/workstationConfigs/workstationconfig-${uniqueId}/workstations/workstation-${uniqueId}", "verb": "delete" }, @@ -882,20 +729,6 @@ X-Frame-Options: SAMEORIGIN X-Xss-Protection: 0 { - "allowedPorts": [ - { - "first": 22, - "last": 22 - }, - { - "first": 80, - "last": 80 - }, - { - "first": 1024, - "last": 65535 - } - ], "container": { "image": "us-west1-docker.pkg.dev/cloud-workstations-images/predefined/code-oss:latest" }, @@ -940,12 +773,10 @@ X-Frame-Options: SAMEORIGIN X-Xss-Protection: 0 { - "done": false, "metadata": { "@type": "type.googleapis.com/google.cloud.workstations.v1.OperationMetadata", "apiVersion": "v1", "createTime": "2024-04-01T12:34:56.123456Z", - "requestedCancellation": false, "target": "projects/${projectId}/locations/us-west1/workstationClusters/workstationcluster-${uniqueId}/workstationConfigs/workstationconfig-${uniqueId}", "verb": "delete" }, @@ -954,41 +785,6 @@ X-Xss-Protection: 0 --- -GET https://compute.googleapis.com/compute/v1/projects/${projectId}/global/networks/${networkID}?alt=json -Content-Type: application/json -User-Agent: Terraform/ (+https://www.terraform.io) Terraform-Plugin-SDK/2.10.1 terraform-provider-google-beta/kcc/controller-manager - -200 OK -Cache-Control: private -Content-Type: application/json; charset=UTF-8 -Server: ESF -Vary: Origin -Vary: X-Origin -Vary: Referer -X-Content-Type-Options: nosniff -X-Frame-Options: SAMEORIGIN -X-Xss-Protection: 0 - -{ - "autoCreateSubnetworks": false, - "creationTimestamp": "2024-04-01T12:34:56.123456Z", - "id": "000000000000000000000", - "kind": "compute#network", - "name": "computenetwork-${uniqueId}", - "networkFirewallPolicyEnforcementOrder": "AFTER_CLASSIC_FIREWALL", - "routingConfig": { - "bgpBestPathSelectionMode": "LEGACY", - "routingMode": "GLOBAL" - }, - "selfLink": "https://www.googleapis.com/compute/v1/projects/${projectId}/global/networks/computenetwork-${uniqueId}", - "selfLinkWithId": "https://www.googleapis.com/compute/v1/projects/${projectId}/global/networks/${networkID}", - "subnetworks": [ - "https://www.googleapis.com/compute/v1/projects/${projectId}/regions/us-west1/subnetworks/computesubnetwork-${uniqueId}" - ] -} - ---- - GET https://workstations.googleapis.com/v1/projects/${projectId}/locations/us-west1/operations/${operationID} Content-Type: application/json User-Agent: kcc/controller-manager @@ -1012,11 +808,13 @@ X-Xss-Protection: 0 "apiVersion": "v1", "createTime": "2024-04-01T12:34:56.123456Z", "endTime": "2024-04-01T12:34:56.123456Z", - "requestedCancellation": false, "target": "projects/${projectId}/locations/us-west1/workstationClusters/workstationcluster-${uniqueId}/workstationConfigs/workstationconfig-${uniqueId}", "verb": "delete" }, - "name": "projects/${projectId}/locations/us-west1/operations/${operationID}" + "name": "projects/${projectId}/locations/us-west1/operations/${operationID}", + "response": { + "@type": "type.googleapis.com/google.cloud.workstations.v1.WorkstationConfig" + } } --- @@ -1068,12 +866,10 @@ X-Frame-Options: SAMEORIGIN X-Xss-Protection: 0 { - "done": false, "metadata": { "@type": "type.googleapis.com/google.cloud.workstations.v1.OperationMetadata", "apiVersion": "v1", "createTime": "2024-04-01T12:34:56.123456Z", - "requestedCancellation": false, "target": "projects/${projectId}/locations/us-west1/workstationClusters/workstationcluster-${uniqueId}", "verb": "delete" }, @@ -1082,80 +878,6 @@ X-Xss-Protection: 0 --- -GET https://compute.googleapis.com/compute/v1/projects/${projectId}/global/networks/${networkID}?alt=json -Content-Type: application/json -User-Agent: Terraform/ (+https://www.terraform.io) Terraform-Plugin-SDK/2.10.1 terraform-provider-google-beta/kcc/controller-manager - -200 OK -Cache-Control: private -Content-Type: application/json; charset=UTF-8 -Server: ESF -Vary: Origin -Vary: X-Origin -Vary: Referer -X-Content-Type-Options: nosniff -X-Frame-Options: SAMEORIGIN -X-Xss-Protection: 0 - -{ - "autoCreateSubnetworks": false, - "creationTimestamp": "2024-04-01T12:34:56.123456Z", - "id": "000000000000000000000", - "kind": "compute#network", - "name": "computenetwork-${uniqueId}", - "networkFirewallPolicyEnforcementOrder": "AFTER_CLASSIC_FIREWALL", - "routingConfig": { - "bgpBestPathSelectionMode": "LEGACY", - "routingMode": "GLOBAL" - }, - "selfLink": "https://www.googleapis.com/compute/v1/projects/${projectId}/global/networks/computenetwork-${uniqueId}", - "selfLinkWithId": "https://www.googleapis.com/compute/v1/projects/${projectId}/global/networks/${networkID}", - "subnetworks": [ - "https://www.googleapis.com/compute/v1/projects/${projectId}/regions/us-west1/subnetworks/computesubnetwork-${uniqueId}" - ] -} - ---- - -GET https://compute.googleapis.com/compute/v1/projects/${projectId}/regions/us-west1/subnetworks/${subnetworkID}?alt=json -Content-Type: application/json -User-Agent: Terraform/ (+https://www.terraform.io) Terraform-Plugin-SDK/2.10.1 terraform-provider-google-beta/kcc/controller-manager - -200 OK -Cache-Control: private -Content-Type: application/json; charset=UTF-8 -Server: ESF -Vary: Origin -Vary: X-Origin -Vary: Referer -X-Content-Type-Options: nosniff -X-Frame-Options: SAMEORIGIN -X-Xss-Protection: 0 - -{ - "allowSubnetCidrRoutesOverlap": false, - "creationTimestamp": "2024-04-01T12:34:56.123456Z", - "enableFlowLogs": false, - "fingerprint": "abcdef0123A=", - "gatewayAddress": "10.0.0.1", - "id": "000000000000000000000", - "ipCidrRange": "10.0.0.0/24", - "kind": "compute#subnetwork", - "logConfig": { - "enable": false - }, - "name": "computesubnetwork-${uniqueId}", - "network": "https://www.googleapis.com/compute/v1/projects/${projectId}/global/networks/computenetwork-${uniqueId}", - "privateIpGoogleAccess": false, - "privateIpv6GoogleAccess": "DISABLE_GOOGLE_ACCESS", - "purpose": "PRIVATE", - "region": "https://www.googleapis.com/compute/v1/projects/${projectId}/regions/us-west1", - "selfLink": "https://www.googleapis.com/compute/v1/projects/${projectId}/regions/us-west1/subnetworks/computesubnetwork-${uniqueId}", - "stackType": "IPV4_ONLY" -} - ---- - GET https://workstations.googleapis.com/v1/projects/${projectId}/locations/us-west1/operations/${operationID} Content-Type: application/json User-Agent: kcc/controller-manager @@ -1179,11 +901,13 @@ X-Xss-Protection: 0 "apiVersion": "v1", "createTime": "2024-04-01T12:34:56.123456Z", "endTime": "2024-04-01T12:34:56.123456Z", - "requestedCancellation": false, "target": "projects/${projectId}/locations/us-west1/workstationClusters/workstationcluster-${uniqueId}", "verb": "delete" }, - "name": "projects/${projectId}/locations/us-west1/operations/${operationID}" + "name": "projects/${projectId}/locations/us-west1/operations/${operationID}", + "response": { + "@type": "type.googleapis.com/google.cloud.workstations.v1.WorkstationCluster" + } } --- @@ -1204,11 +928,10 @@ X-Frame-Options: SAMEORIGIN X-Xss-Protection: 0 { - "allowSubnetCidrRoutesOverlap": false, "creationTimestamp": "2024-04-01T12:34:56.123456Z", "enableFlowLogs": false, "fingerprint": "abcdef0123A=", - "gatewayAddress": "10.0.0.1", + "gatewayAddress": "10.2.0.1", "id": "000000000000000000000", "ipCidrRange": "10.0.0.0/24", "kind": "compute#subnetwork", @@ -1316,7 +1039,6 @@ X-Xss-Protection: 0 "name": "computenetwork-${uniqueId}", "networkFirewallPolicyEnforcementOrder": "AFTER_CLASSIC_FIREWALL", "routingConfig": { - "bgpBestPathSelectionMode": "LEGACY", "routingMode": "GLOBAL" }, "selfLink": "https://www.googleapis.com/compute/v1/projects/${projectId}/global/networks/computenetwork-${uniqueId}", From 8dee4f4b781ed9389970a1d3b115a279ab6b0019 Mon Sep 17 00:00:00 2001 From: Jason Vigil Date: Thu, 12 Dec 2024 19:41:07 +0000 Subject: [PATCH 5/7] fix: Do not error if Workstation resources are already deleted Skip sending GCP API delete request if resource does not exist. --- pkg/controller/direct/workstations/cluster_controller.go | 4 ++++ pkg/controller/direct/workstations/config_controller.go | 4 ++++ pkg/controller/direct/workstations/workstation_controller.go | 4 ++++ 3 files changed, 12 insertions(+) diff --git a/pkg/controller/direct/workstations/cluster_controller.go b/pkg/controller/direct/workstations/cluster_controller.go index 1edc2044d6..2f44fd9ff3 100644 --- a/pkg/controller/direct/workstations/cluster_controller.go +++ b/pkg/controller/direct/workstations/cluster_controller.go @@ -313,6 +313,10 @@ func (a *Adapter) Delete(ctx context.Context, deleteOp *directbase.DeleteOperati req := &pb.DeleteWorkstationClusterRequest{Name: a.id.FullyQualifiedName()} op, err := a.gcpClient.DeleteWorkstationCluster(ctx, req) if err != nil { + if direct.IsNotFound(err) { + // Return success if workstation is not found (assume it was already deleted). + return true, nil + } return false, fmt.Errorf("deleting WorkstationCluster %s: %w", a.id.FullyQualifiedName(), err) } diff --git a/pkg/controller/direct/workstations/config_controller.go b/pkg/controller/direct/workstations/config_controller.go index b55118a1dc..806af1efa9 100644 --- a/pkg/controller/direct/workstations/config_controller.go +++ b/pkg/controller/direct/workstations/config_controller.go @@ -254,6 +254,10 @@ func (a *WorkstationConfigAdapter) Delete(ctx context.Context, deleteOp *directb req := &pb.DeleteWorkstationConfigRequest{Name: a.id.String()} op, err := a.gcpClient.DeleteWorkstationConfig(ctx, req) if err != nil { + if direct.IsNotFound(err) { + // Return success if workstation is not found (assume it was already deleted). + return true, nil + } return false, fmt.Errorf("deleting WorkstationConfig %s: %w", a.id.String(), err) } log.V(2).Info("successfully deleted WorkstationConfig", "name", a.id.String()) diff --git a/pkg/controller/direct/workstations/workstation_controller.go b/pkg/controller/direct/workstations/workstation_controller.go index b33aee0d49..99af8f83e8 100644 --- a/pkg/controller/direct/workstations/workstation_controller.go +++ b/pkg/controller/direct/workstations/workstation_controller.go @@ -247,6 +247,10 @@ func (a *WorkstationAdapter) Delete(ctx context.Context, deleteOp *directbase.De req := &workstationspb.DeleteWorkstationRequest{Name: a.id.String()} op, err := a.gcpClient.DeleteWorkstation(ctx, req) if err != nil { + if direct.IsNotFound(err) { + // Return success if workstation is not found (assume it was already deleted). + return true, nil + } return false, fmt.Errorf("deleting Workstation %s: %w", a.id, err) } log.V(2).Info("successfully deleted Workstation", "name", a.id) From ec7560feb9af5e07fd976e1073c79a442ca39e8b Mon Sep 17 00:00:00 2001 From: Jason Vigil Date: Thu, 12 Dec 2024 19:43:03 +0000 Subject: [PATCH 6/7] fix: Update controller comment boolean value Return true if object is found, false if object is not found. --- dev/tools/controllerbuilder/template/controller/controller.go | 2 +- pkg/controller/direct/workstations/workstation_controller.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/dev/tools/controllerbuilder/template/controller/controller.go b/dev/tools/controllerbuilder/template/controller/controller.go index 9ddd54f465..8ff96e1d37 100644 --- a/dev/tools/controllerbuilder/template/controller/controller.go +++ b/dev/tools/controllerbuilder/template/controller/controller.go @@ -139,7 +139,7 @@ var _ directbase.Adapter = &{{.ProtoResource}}Adapter{} // Find retrieves the GCP resource. // Return true means the object is found. This triggers Adapter ` + "`" + `Update` + "`" + ` call. -// Return true means the object is not found. This triggers Adapter ` + "`" + `Create` + "`" + ` call. +// Return false means the object is not found. This triggers Adapter ` + "`" + `Create` + "`" + ` call. // Return a non-nil error requeues the requests. func (a *{{.ProtoResource}}Adapter) Find(ctx context.Context) (bool, error) { log := klog.FromContext(ctx) diff --git a/pkg/controller/direct/workstations/workstation_controller.go b/pkg/controller/direct/workstations/workstation_controller.go index 99af8f83e8..744d871fe8 100644 --- a/pkg/controller/direct/workstations/workstation_controller.go +++ b/pkg/controller/direct/workstations/workstation_controller.go @@ -103,7 +103,7 @@ var _ directbase.Adapter = &WorkstationAdapter{} // Find retrieves the GCP resource. // Return true means the object is found. This triggers Adapter `Update` call. -// Return true means the object is not found. This triggers Adapter `Create` call. +// Return false means the object is not found. This triggers Adapter `Create` call. // Return a non-nil error requeues the requests. func (a *WorkstationAdapter) Find(ctx context.Context) (bool, error) { log := klog.FromContext(ctx) From b61af081918026ad6be01eb38d5466d3e5da3ce1 Mon Sep 17 00:00:00 2001 From: Jason Vigil Date: Thu, 12 Dec 2024 19:46:43 +0000 Subject: [PATCH 7/7] fix: Make Workstation displayName updates during fixture tests Also, it is not a required field. So, remove from minimal suite. --- .../_generated_object_workstation-full.golden.yaml | 2 +- .../workstation/workstation-full/_http.log | 14 +++++++------- .../workstation/workstation-full/create.yaml | 2 +- .../workstation/workstation-full/update.yaml | 2 +- ...enerated_object_workstation-minimal.golden.yaml | 1 - .../workstation/workstation-minimal/_http.log | 3 --- .../workstation/workstation-minimal/create.yaml | 3 +-- 7 files changed, 11 insertions(+), 16 deletions(-) diff --git a/pkg/test/resourcefixture/testdata/basic/workstations/workstation/workstation-full/_generated_object_workstation-full.golden.yaml b/pkg/test/resourcefixture/testdata/basic/workstations/workstation/workstation-full/_generated_object_workstation-full.golden.yaml index 7d1168b79d..64a0e4bac2 100644 --- a/pkg/test/resourcefixture/testdata/basic/workstations/workstation/workstation-full/_generated_object_workstation-full.golden.yaml +++ b/pkg/test/resourcefixture/testdata/basic/workstations/workstation/workstation-full/_generated_object_workstation-full.golden.yaml @@ -15,7 +15,7 @@ spec: value: a-value1 - key: a-key2 value: a-value2 - displayName: workstation-${uniqueId} + displayName: workstation-${uniqueId}-displayname-updated labels: - key: l-key1 value: l-value1 diff --git a/pkg/test/resourcefixture/testdata/basic/workstations/workstation/workstation-full/_http.log b/pkg/test/resourcefixture/testdata/basic/workstations/workstation/workstation-full/_http.log index dcdbd6ca12..2ce183ca44 100644 --- a/pkg/test/resourcefixture/testdata/basic/workstations/workstation/workstation-full/_http.log +++ b/pkg/test/resourcefixture/testdata/basic/workstations/workstation/workstation-full/_http.log @@ -555,7 +555,7 @@ x-goog-request-params: parent=projects%2F${projectId}%2Flocations%2Fus-west1%2Fw "annotations": { "a-key1": "a-value1" }, - "displayName": "workstation-${uniqueId}", + "displayName": "workstation-${uniqueId}-displayname", "labels": { "l-key1": "l-value1" }, @@ -619,7 +619,7 @@ X-Xss-Protection: 0 "a-key1": "a-value1" }, "createTime": "2024-04-01T12:34:56.123456Z", - "displayName": "workstation-${uniqueId}", + "displayName": "workstation-${uniqueId}-displayname", "etag": "abcdef0123A=", "labels": { "l-key1": "l-value1" @@ -654,7 +654,7 @@ X-Xss-Protection: 0 "a-key1": "a-value1" }, "createTime": "2024-04-01T12:34:56.123456Z", - "displayName": "workstation-${uniqueId}", + "displayName": "workstation-${uniqueId}-displayname", "etag": "abcdef0123A=", "labels": { "l-key1": "l-value1" @@ -667,7 +667,7 @@ X-Xss-Protection: 0 --- -PATCH https://workstations.googleapis.com/v1/projects/${projectId}/locations/us-west1/workstationClusters/workstationcluster-${uniqueId}/workstationConfigs/workstationconfig-${uniqueId}/workstations/workstation-${uniqueId}?%24alt=json%3Benum-encoding%3Dint&updateMask=annotations%2Clabels +PATCH https://workstations.googleapis.com/v1/projects/${projectId}/locations/us-west1/workstationClusters/workstationcluster-${uniqueId}/workstationConfigs/workstationconfig-${uniqueId}/workstations/workstation-${uniqueId}?%24alt=json%3Benum-encoding%3Dint&updateMask=annotations%2CdisplayName%2Clabels Content-Type: application/json User-Agent: kcc/controller-manager x-goog-request-params: workstation.name=projects%2F${projectId}%2Flocations%2Fus-west1%2FworkstationClusters%2Fworkstationcluster-${uniqueId}%2FworkstationConfigs%2Fworkstationconfig-${uniqueId}%2Fworkstations%2Fworkstation-${uniqueId} @@ -677,7 +677,7 @@ x-goog-request-params: workstation.name=projects%2F${projectId}%2Flocations%2Fus "a-key1": "a-value1", "a-key2": "a-value2" }, - "displayName": "workstation-${uniqueId}", + "displayName": "workstation-${uniqueId}-displayname-updated", "etag": "abcdef0123A=", "labels": { "l-key1": "l-value1", @@ -743,7 +743,7 @@ X-Xss-Protection: 0 "a-key2": "a-value2" }, "createTime": "2024-04-01T12:34:56.123456Z", - "displayName": "workstation-${uniqueId}", + "displayName": "workstation-${uniqueId}-displayname-updated", "etag": "abcdef0123A=", "labels": { "l-key1": "l-value1", @@ -780,7 +780,7 @@ X-Xss-Protection: 0 "a-key2": "a-value2" }, "createTime": "2024-04-01T12:34:56.123456Z", - "displayName": "workstation-${uniqueId}", + "displayName": "workstation-${uniqueId}-displayname-updated", "etag": "abcdef0123A=", "labels": { "l-key1": "l-value1", diff --git a/pkg/test/resourcefixture/testdata/basic/workstations/workstation/workstation-full/create.yaml b/pkg/test/resourcefixture/testdata/basic/workstations/workstation/workstation-full/create.yaml index 2e3c5ea7a9..75eeee204e 100644 --- a/pkg/test/resourcefixture/testdata/basic/workstations/workstation/workstation-full/create.yaml +++ b/pkg/test/resourcefixture/testdata/basic/workstations/workstation/workstation-full/create.yaml @@ -19,7 +19,7 @@ metadata: spec: parentRef: name: workstationconfig-${uniqueId} - displayName: workstation-${uniqueId} + displayName: workstation-${uniqueId}-displayname annotations: - key: a-key1 value: a-value1 diff --git a/pkg/test/resourcefixture/testdata/basic/workstations/workstation/workstation-full/update.yaml b/pkg/test/resourcefixture/testdata/basic/workstations/workstation/workstation-full/update.yaml index c0338722d1..b1108aebce 100644 --- a/pkg/test/resourcefixture/testdata/basic/workstations/workstation/workstation-full/update.yaml +++ b/pkg/test/resourcefixture/testdata/basic/workstations/workstation/workstation-full/update.yaml @@ -19,7 +19,7 @@ metadata: spec: parentRef: name: workstationconfig-${uniqueId} - displayName: workstation-${uniqueId} + displayName: workstation-${uniqueId}-displayname-updated annotations: - key: a-key1 value: a-value1 diff --git a/pkg/test/resourcefixture/testdata/basic/workstations/workstation/workstation-minimal/_generated_object_workstation-minimal.golden.yaml b/pkg/test/resourcefixture/testdata/basic/workstations/workstation/workstation-minimal/_generated_object_workstation-minimal.golden.yaml index d3e94a02e4..32121607e4 100644 --- a/pkg/test/resourcefixture/testdata/basic/workstations/workstation/workstation-minimal/_generated_object_workstation-minimal.golden.yaml +++ b/pkg/test/resourcefixture/testdata/basic/workstations/workstation/workstation-minimal/_generated_object_workstation-minimal.golden.yaml @@ -10,7 +10,6 @@ metadata: name: workstation-${uniqueId} namespace: ${uniqueId} spec: - displayName: workstation-${uniqueId} parentRef: name: workstationconfig-${uniqueId} status: diff --git a/pkg/test/resourcefixture/testdata/basic/workstations/workstation/workstation-minimal/_http.log b/pkg/test/resourcefixture/testdata/basic/workstations/workstation/workstation-minimal/_http.log index 984547719d..fa2544245a 100644 --- a/pkg/test/resourcefixture/testdata/basic/workstations/workstation/workstation-minimal/_http.log +++ b/pkg/test/resourcefixture/testdata/basic/workstations/workstation/workstation-minimal/_http.log @@ -552,7 +552,6 @@ User-Agent: kcc/controller-manager x-goog-request-params: parent=projects%2F${projectId}%2Flocations%2Fus-west1%2FworkstationClusters%2Fworkstationcluster-${uniqueId}%2FworkstationConfigs%2Fworkstationconfig-${uniqueId} { - "displayName": "workstation-${uniqueId}", "name": "projects/${projectId}/locations/us-west1/workstationClusters/workstationcluster-${uniqueId}/workstationConfigs/workstationconfig-${uniqueId}/workstations/workstation-${uniqueId}" } @@ -610,7 +609,6 @@ X-Xss-Protection: 0 "response": { "@type": "type.googleapis.com/google.cloud.workstations.v1.Workstation", "createTime": "2024-04-01T12:34:56.123456Z", - "displayName": "workstation-${uniqueId}", "etag": "abcdef0123A=", "name": "projects/${projectId}/locations/us-west1/workstationClusters/workstationcluster-${uniqueId}/workstationConfigs/workstationconfig-${uniqueId}/workstations/workstation-${uniqueId}", "state": "STATE_STOPPED", @@ -639,7 +637,6 @@ X-Xss-Protection: 0 { "createTime": "2024-04-01T12:34:56.123456Z", - "displayName": "workstation-${uniqueId}", "etag": "abcdef0123A=", "name": "projects/${projectId}/locations/us-west1/workstationClusters/workstationcluster-${uniqueId}/workstationConfigs/workstationconfig-${uniqueId}/workstations/workstation-${uniqueId}", "state": 4, diff --git a/pkg/test/resourcefixture/testdata/basic/workstations/workstation/workstation-minimal/create.yaml b/pkg/test/resourcefixture/testdata/basic/workstations/workstation/workstation-minimal/create.yaml index 6c3ebd4ef9..933f13f50c 100644 --- a/pkg/test/resourcefixture/testdata/basic/workstations/workstation/workstation-minimal/create.yaml +++ b/pkg/test/resourcefixture/testdata/basic/workstations/workstation/workstation-minimal/create.yaml @@ -18,5 +18,4 @@ metadata: name: workstation-${uniqueId} spec: parentRef: - name: workstationconfig-${uniqueId} - displayName: workstation-${uniqueId} \ No newline at end of file + name: workstationconfig-${uniqueId} \ No newline at end of file