diff --git a/apis/gkebackup/v1alpha1/generate.sh b/apis/gkebackup/v1alpha1/generate.sh index 779c33175e1..8729f896ffb 100755 --- a/apis/gkebackup/v1alpha1/generate.sh +++ b/apis/gkebackup/v1alpha1/generate.sh @@ -26,7 +26,8 @@ go run . generate-types \ --api-version gkebackup.cnrm.cloud.google.com/v1alpha1 \ --resource GKEBackupBackupPlan:BackupPlan \ --resource GKEBackupRestorePlan:RestorePlan \ - --resource GKEBackupBackup:Backup + --resource GKEBackupBackup:Backup \ + --resource GKEBackupRestore:Restore go run . generate-mapper \ --service google.cloud.gkebackup.v1 \ diff --git a/apis/gkebackup/v1alpha1/restore_identity.go b/apis/gkebackup/v1alpha1/restore_identity.go new file mode 100644 index 00000000000..7a938730237 --- /dev/null +++ b/apis/gkebackup/v1alpha1/restore_identity.go @@ -0,0 +1,106 @@ +// Copyright 2025 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package v1alpha1 + +import ( + "context" + "fmt" + "strings" + + "github.com/GoogleCloudPlatform/k8s-config-connector/apis/common" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +// RestoreIdentity defines the resource reference to GKEBackupRestore, which "External" field +// holds the GCP identifier for the KRM object. +type RestoreIdentity struct { + parent *RestoreParent + id string +} + +func (i *RestoreIdentity) String() string { + return i.parent.String() + "/restores/" + i.id +} + +func (i *RestoreIdentity) ID() string { + return i.id +} + +func (i *RestoreIdentity) Parent() *RestoreParent { + return i.parent +} + +type RestoreParent struct { + RestorePlan string +} + +func (p *RestoreParent) String() string { + return p.RestorePlan +} + +// New builds a RestoreIdentity from the Config Connector Restore object. +func NewRestoreIdentity(ctx context.Context, reader client.Reader, obj *GKEBackupRestore) (*RestoreIdentity, error) { + // Get Parent + restorePlanRef := obj.Spec.RestorePlanRef + restorePlan, err := restorePlanRef.NormalizedExternal(ctx, reader, obj.GetNamespace()) + if err != nil { + return nil, err + } + + // 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 := ParseRestoreExternal(externalRef) + if err != nil { + return nil, err + } + if actualParent.RestorePlan != restorePlan { + return nil, fmt.Errorf("spec.restorePlanRef changed, expect %s, got %s", actualParent.RestorePlan, restorePlan) + } + 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 &RestoreIdentity{ + parent: &RestoreParent{ + RestorePlan: restorePlan, + }, + id: resourceID, + }, nil +} + +func ParseRestoreExternal(external string) (parent *RestoreParent, resourceID string, err error) { + tokens := strings.Split(external, "/") + if len(tokens) != 8 || tokens[0] != "projects" || tokens[2] != "locations" || tokens[4] != "restorePlans" || tokens[6] != "restores" { + return nil, "", fmt.Errorf("format of GKEBackupRestore external=%q was not known (use projects/{{projectID}}/locations/{{location}}/restorePlans/{{restoreplanID}}/restores/{{restoreID}})", external) + } + restorePlan := strings.Join(tokens[:len(tokens)-2], "/") + parent = &RestoreParent{ + RestorePlan: restorePlan, + } + resourceID = tokens[7] + return parent, resourceID, nil +} diff --git a/apis/gkebackup/v1alpha1/restore_reference.go b/apis/gkebackup/v1alpha1/restore_reference.go new file mode 100644 index 00000000000..dfec15080f0 --- /dev/null +++ b/apis/gkebackup/v1alpha1/restore_reference.go @@ -0,0 +1,83 @@ +// Copyright 2025 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package v1alpha1 + +import ( + "context" + "fmt" + + 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 = &RestoreRef{} + +// RestoreRef defines the resource reference to GKEBackupRestore, which "External" field +// holds the GCP identifier for the KRM object. +type RestoreRef struct { + // A reference to an externally managed GKEBackupRestore resource. + // Should be in the format "projects/{{projectID}}/locations/{{location}}/restorePlans/{{restoreplanID}}/restores/{{restoreID}}". + External string `json:"external,omitempty"` + + // The name of a GKEBackupRestore resource. + Name string `json:"name,omitempty"` + + // The namespace of a GKEBackupRestore resource. + Namespace string `json:"namespace,omitempty"` +} + +// NormalizedExternal provision the "External" value for other resource that depends on GKEBackupRestore. +// If the "External" is given in the other resource's spec.GKEBackupRestoreRef, the given value will be used. +// Otherwise, the "Name" and "Namespace" will be used to query the actual GKEBackupRestore object from the cluster. +func (r *RestoreRef) 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", GKEBackupRestoreGVK.Kind) + } + // From given External + if r.External != "" { + if _, _, err := ParseRestoreExternal(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(GKEBackupRestoreGVK) + 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", GKEBackupRestoreGVK, 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/gkebackup/v1alpha1/restore_types.go b/apis/gkebackup/v1alpha1/restore_types.go new file mode 100644 index 00000000000..8f388f8dfdf --- /dev/null +++ b/apis/gkebackup/v1alpha1/restore_types.go @@ -0,0 +1,196 @@ +// Copyright 2025 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package v1alpha1 + +import ( + "github.com/GoogleCloudPlatform/k8s-config-connector/pkg/apis/k8s/v1alpha1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +var GKEBackupRestoreGVK = GroupVersion.WithKind("GKEBackupRestore") + +// GKEBackupRestoreSpec defines the desired state of GKEBackupRestore +// +kcc:proto=google.cloud.gkebackup.v1.Restore +type GKEBackupRestoreSpec struct { + // The GKEBackupRestore name. If not given, the metadata.name will be used. + ResourceID *string `json:"resourceID,omitempty"` + + // Required. The RestorePlan from which this Restore is created. + // +required + RestorePlanRef *RestorePlanRef `json:"restorePlanRef,omitempty"` + + // User specified descriptive string for this Restore. + // +kcc:proto:field=google.cloud.gkebackup.v1.Restore.description + Description *string `json:"description,omitempty"` + + // Required. Immutable. A reference to the + // [Backup][google.cloud.gkebackup.v1.Backup] used as the source from which + // this Restore will restore. Note that this Backup must be a sub-resource of + // the RestorePlan's + // [backup_plan][google.cloud.gkebackup.v1.RestorePlan.backup_plan]. + // +kcc:proto:field=google.cloud.gkebackup.v1.Restore.backup + BackupRef *BackupRef `json:"backupRef,omitempty"` + + // A set of custom labels supplied by user. + // +kcc:proto:field=google.cloud.gkebackup.v1.Restore.labels + Labels map[string]string `json:"labels,omitempty"` + + // Optional. Immutable. Filters resources for `Restore`. If not specified, the + // scope of the restore will remain the same as defined in the `RestorePlan`. + // If this is specified, and no resources are matched by the + // `inclusion_filters` or everything is excluded by the `exclusion_filters`, + // nothing will be restored. This filter can only be specified if the value of + // [namespaced_resource_restore_mode][google.cloud.gkebackup.v1.RestoreConfig.namespaced_resource_restore_mode] + // is set to `MERGE_SKIP_ON_CONFLICT`, `MERGE_REPLACE_VOLUME_ON_CONFLICT` or + // `MERGE_REPLACE_ON_CONFLICT`. + // +kcc:proto:field=google.cloud.gkebackup.v1.Restore.filter + Filter *Restore_Filter `json:"filter,omitempty"` + + // Optional. Immutable. Overrides the volume data restore policies selected in + // the Restore Config for override-scoped resources. + // +kcc:proto:field=google.cloud.gkebackup.v1.Restore.volume_data_restore_policy_overrides + VolumeDataRestorePolicyOverrides []VolumeDataRestorePolicyOverride `json:"volumeDataRestorePolicyOverrides,omitempty"` +} + +// GKEBackupRestoreStatus defines the config connector machine state of GKEBackupRestore +type GKEBackupRestoreStatus 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 GKEBackupRestore resource in GCP. + ExternalRef *string `json:"externalRef,omitempty"` + + // ObservedState is the state of the resource as most recently observed in GCP. + ObservedState *GKEBackupRestoreObservedState `json:"observedState,omitempty"` +} + +// GKEBackupRestoreObservedState is the state of the GKEBackupRestore resource as most recently observed in GCP. +// +kcc:proto=google.cloud.gkebackup.v1.Restore +type GKEBackupRestoreObservedState struct { + // Output only. The full name of the Restore resource. + // Format: `projects/*/locations/*/restorePlans/*/restores/*` + // +kcc:proto:field=google.cloud.gkebackup.v1.Restore.name + // NOTYET: this field serves the same purpose as externalRef + // Name *string `json:"name,omitempty"` + + // Output only. Server generated global unique identifier of + // [UUID](https://en.wikipedia.org/wiki/Universally_unique_identifier) format. + // +kcc:proto:field=google.cloud.gkebackup.v1.Restore.uid + UID *string `json:"uid,omitempty"` + + // Output only. The timestamp when this Restore resource was created. + // +kcc:proto:field=google.cloud.gkebackup.v1.Restore.create_time + CreateTime *string `json:"createTime,omitempty"` + + // Output only. The timestamp when this Restore resource was last + // updated. + // +kcc:proto:field=google.cloud.gkebackup.v1.Restore.update_time + UpdateTime *string `json:"updateTime,omitempty"` + + // Output only. The target cluster into which this Restore will restore data. + // Valid formats: + // + // - `projects/*/locations/*/clusters/*` + // - `projects/*/zones/*/clusters/*` + // + // Inherited from parent RestorePlan's + // [cluster][google.cloud.gkebackup.v1.RestorePlan.cluster] value. + // +kcc:proto:field=google.cloud.gkebackup.v1.Restore.cluster + Cluster *string `json:"cluster,omitempty"` + + // Output only. Configuration of the Restore. Inherited from parent + // RestorePlan's + // [restore_config][google.cloud.gkebackup.v1.RestorePlan.restore_config]. + // +kcc:proto:field=google.cloud.gkebackup.v1.Restore.restore_config + RestoreConfig *RestoreConfig `json:"restoreConfig,omitempty"` + + // Output only. The current state of the Restore. + // +kcc:proto:field=google.cloud.gkebackup.v1.Restore.state + State *string `json:"state,omitempty"` + + // Output only. Human-readable description of why the Restore is in its + // current state. + // +kcc:proto:field=google.cloud.gkebackup.v1.Restore.state_reason + StateReason *string `json:"stateReason,omitempty"` + + // Output only. Timestamp of when the restore operation completed. + // +kcc:proto:field=google.cloud.gkebackup.v1.Restore.complete_time + CompleteTime *string `json:"completeTime,omitempty"` + + // Output only. Number of resources restored during the restore execution. + // +kcc:proto:field=google.cloud.gkebackup.v1.Restore.resources_restored_count + ResourcesRestoredCount *int32 `json:"resourcesRestoredCount,omitempty"` + + // Output only. Number of resources excluded during the restore execution. + // +kcc:proto:field=google.cloud.gkebackup.v1.Restore.resources_excluded_count + ResourcesExcludedCount *int32 `json:"resourcesExcludedCount,omitempty"` + + // Output only. Number of resources that failed to be restored during the + // restore execution. + // +kcc:proto:field=google.cloud.gkebackup.v1.Restore.resources_failed_count + ResourcesFailedCount *int32 `json:"resourcesFailedCount,omitempty"` + + // Output only. Number of volumes restored during the restore execution. + // +kcc:proto:field=google.cloud.gkebackup.v1.Restore.volumes_restored_count + VolumesRestoredCount *int32 `json:"volumesRestoredCount,omitempty"` + + // Output only. `etag` is used for optimistic concurrency control as a way to + // help prevent simultaneous updates of a restore from overwriting each other. + // It is strongly suggested that systems make use of the `etag` in the + // read-modify-write cycle to perform restore updates in order to avoid + // race conditions: An `etag` is returned in the response to `GetRestore`, + // and systems are expected to put that etag in the request to + // `UpdateRestore` or `DeleteRestore` to ensure that their change will be + // applied to the same version of the resource. + // +kcc:proto:field=google.cloud.gkebackup.v1.Restore.etag + Etag *string `json:"etag,omitempty"` +} + +// +genclient +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object +// +kubebuilder:resource:categories=gcp,shortName=gcpgkebackuprestore;gcpgkebackuprestores +// +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'" + +// GKEBackupRestore is the Schema for the GKEBackupRestore API +// +k8s:openapi-gen=true +type GKEBackupRestore struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + // +required + Spec GKEBackupRestoreSpec `json:"spec,omitempty"` + Status GKEBackupRestoreStatus `json:"status,omitempty"` +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object +// GKEBackupRestoreList contains a list of GKEBackupRestore +type GKEBackupRestoreList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []GKEBackupRestore `json:"items"` +} + +func init() { + SchemeBuilder.Register(&GKEBackupRestore{}, &GKEBackupRestoreList{}) +} diff --git a/apis/gkebackup/v1alpha1/types.generated.go b/apis/gkebackup/v1alpha1/types.generated.go index ba6881e7acb..2169728f684 100644 --- a/apis/gkebackup/v1alpha1/types.generated.go +++ b/apis/gkebackup/v1alpha1/types.generated.go @@ -19,6 +19,7 @@ // resource: GKEBackupBackupPlan:BackupPlan // resource: GKEBackupRestorePlan:RestorePlan // resource: GKEBackupBackup:Backup +// resource: GKEBackupRestore:Restore package v1alpha1 @@ -145,6 +146,53 @@ type Namespaces struct { Namespaces []string `json:"namespaces,omitempty"` } +// +kcc:proto=google.cloud.gkebackup.v1.ResourceSelector +type ResourceSelector struct { + // Optional. Selects resources using their Kubernetes GroupKinds. If + // specified, only resources of provided GroupKind will be selected. + // +kcc:proto:field=google.cloud.gkebackup.v1.ResourceSelector.group_kind + GroupKind *RestoreConfig_GroupKind `json:"groupKind,omitempty"` + + // Optional. Selects resources using their resource names. If specified, + // only resources with the provided name will be selected. + // +kcc:proto:field=google.cloud.gkebackup.v1.ResourceSelector.name + Name *string `json:"name,omitempty"` + + // Optional. Selects resources using their namespaces. This only applies to + // namespace scoped resources and cannot be used for selecting + // cluster scoped resources. If specified, only resources in the provided + // namespace will be selected. If not specified, the filter will apply to + // both cluster scoped and namespace scoped resources (e.g. name or label). + // The [Namespace](https://pkg.go.dev/k8s.io/api/core/v1#Namespace) resource + // itself will be restored if and only if any resources within the namespace + // are restored. + // +kcc:proto:field=google.cloud.gkebackup.v1.ResourceSelector.namespace + Namespace *string `json:"namespace,omitempty"` + + // Optional. Selects resources using Kubernetes + // [labels](https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/). + // If specified, a resource will be selected if and only if the resource + // has all of the provided labels and all the label values match. + // +kcc:proto:field=google.cloud.gkebackup.v1.ResourceSelector.labels + Labels map[string]string `json:"labels,omitempty"` +} + +// +kcc:proto=google.cloud.gkebackup.v1.Restore.Filter +type Restore_Filter struct { + // Optional. Selects resources for restoration. If specified, only resources + // which match `inclusion_filters` will be selected for restoration. A + // resource will be selected if it matches any `ResourceSelector` of the + // `inclusion_filters`. + // +kcc:proto:field=google.cloud.gkebackup.v1.Restore.Filter.inclusion_filters + InclusionFilters []ResourceSelector `json:"inclusionFilters,omitempty"` + + // Optional. Excludes resources from restoration. If specified, + // a resource will not be restored if it matches + // any `ResourceSelector` of the `exclusion_filters`. + // +kcc:proto:field=google.cloud.gkebackup.v1.Restore.Filter.exclusion_filters + ExclusionFilters []ResourceSelector `json:"exclusionFilters,omitempty"` +} + // +kcc:proto=google.cloud.gkebackup.v1.RestoreConfig type RestoreConfig struct { // Optional. Specifies the mechanism to be used to restore volume data. @@ -278,6 +326,18 @@ type RestoreConfig_RestoreOrder struct { GroupKindDependencies []RestoreConfig_RestoreOrder_GroupKindDependency `json:"groupKindDependencies,omitempty"` } +// +kcc:proto=google.cloud.gkebackup.v1.VolumeDataRestorePolicyOverride +type VolumeDataRestorePolicyOverride struct { + // Required. The VolumeDataRestorePolicy to apply when restoring volumes in + // scope. + // +kcc:proto:field=google.cloud.gkebackup.v1.VolumeDataRestorePolicyOverride.policy + Policy *string `json:"policy,omitempty"` + + // A list of PVCs to apply the policy override to. + // +kcc:proto:field=google.cloud.gkebackup.v1.VolumeDataRestorePolicyOverride.selected_pvcs + SelectedPvcs *NamespacedNames `json:"selectedPvcs,omitempty"` +} + // +kcc:proto=google.type.Date type Date struct { // Year of the date. Must be from 1 to 9999, or 0 to specify a date without diff --git a/apis/gkebackup/v1alpha1/zz_generated.deepcopy.go b/apis/gkebackup/v1alpha1/zz_generated.deepcopy.go index 553d92568b0..c5b8dc8adc4 100644 --- a/apis/gkebackup/v1alpha1/zz_generated.deepcopy.go +++ b/apis/gkebackup/v1alpha1/zz_generated.deepcopy.go @@ -915,6 +915,145 @@ func (in *GKEBackupBackupStatus) DeepCopy() *GKEBackupBackupStatus { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *GKEBackupRestore) DeepCopyInto(out *GKEBackupRestore) { + *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 GKEBackupRestore. +func (in *GKEBackupRestore) DeepCopy() *GKEBackupRestore { + if in == nil { + return nil + } + out := new(GKEBackupRestore) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *GKEBackupRestore) 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 *GKEBackupRestoreList) DeepCopyInto(out *GKEBackupRestoreList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]GKEBackupRestore, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GKEBackupRestoreList. +func (in *GKEBackupRestoreList) DeepCopy() *GKEBackupRestoreList { + if in == nil { + return nil + } + out := new(GKEBackupRestoreList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *GKEBackupRestoreList) 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 *GKEBackupRestoreObservedState) DeepCopyInto(out *GKEBackupRestoreObservedState) { + *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.Cluster != nil { + in, out := &in.Cluster, &out.Cluster + *out = new(string) + **out = **in + } + if in.RestoreConfig != nil { + in, out := &in.RestoreConfig, &out.RestoreConfig + *out = new(RestoreConfig) + (*in).DeepCopyInto(*out) + } + if in.State != nil { + in, out := &in.State, &out.State + *out = new(string) + **out = **in + } + if in.StateReason != nil { + in, out := &in.StateReason, &out.StateReason + *out = new(string) + **out = **in + } + if in.CompleteTime != nil { + in, out := &in.CompleteTime, &out.CompleteTime + *out = new(string) + **out = **in + } + if in.ResourcesRestoredCount != nil { + in, out := &in.ResourcesRestoredCount, &out.ResourcesRestoredCount + *out = new(int32) + **out = **in + } + if in.ResourcesExcludedCount != nil { + in, out := &in.ResourcesExcludedCount, &out.ResourcesExcludedCount + *out = new(int32) + **out = **in + } + if in.ResourcesFailedCount != nil { + in, out := &in.ResourcesFailedCount, &out.ResourcesFailedCount + *out = new(int32) + **out = **in + } + if in.VolumesRestoredCount != nil { + in, out := &in.VolumesRestoredCount, &out.VolumesRestoredCount + *out = new(int32) + **out = **in + } + if in.Etag != nil { + in, out := &in.Etag, &out.Etag + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GKEBackupRestoreObservedState. +func (in *GKEBackupRestoreObservedState) DeepCopy() *GKEBackupRestoreObservedState { + if in == nil { + return nil + } + out := new(GKEBackupRestoreObservedState) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *GKEBackupRestorePlan) DeepCopyInto(out *GKEBackupRestorePlan) { *out = *in @@ -1102,6 +1241,95 @@ func (in *GKEBackupRestorePlanStatus) DeepCopy() *GKEBackupRestorePlanStatus { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *GKEBackupRestoreSpec) DeepCopyInto(out *GKEBackupRestoreSpec) { + *out = *in + if in.ResourceID != nil { + in, out := &in.ResourceID, &out.ResourceID + *out = new(string) + **out = **in + } + if in.RestorePlanRef != nil { + in, out := &in.RestorePlanRef, &out.RestorePlanRef + *out = new(RestorePlanRef) + **out = **in + } + if in.Description != nil { + in, out := &in.Description, &out.Description + *out = new(string) + **out = **in + } + if in.BackupRef != nil { + in, out := &in.BackupRef, &out.BackupRef + *out = new(BackupRef) + **out = **in + } + if in.Labels != nil { + in, out := &in.Labels, &out.Labels + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + if in.Filter != nil { + in, out := &in.Filter, &out.Filter + *out = new(Restore_Filter) + (*in).DeepCopyInto(*out) + } + if in.VolumeDataRestorePolicyOverrides != nil { + in, out := &in.VolumeDataRestorePolicyOverrides, &out.VolumeDataRestorePolicyOverrides + *out = make([]VolumeDataRestorePolicyOverride, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GKEBackupRestoreSpec. +func (in *GKEBackupRestoreSpec) DeepCopy() *GKEBackupRestoreSpec { + if in == nil { + return nil + } + out := new(GKEBackupRestoreSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *GKEBackupRestoreStatus) DeepCopyInto(out *GKEBackupRestoreStatus) { + *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(GKEBackupRestoreObservedState) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GKEBackupRestoreStatus. +func (in *GKEBackupRestoreStatus) DeepCopy() *GKEBackupRestoreStatus { + if in == nil { + return nil + } + out := new(GKEBackupRestoreStatus) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *NamespacedName) DeepCopyInto(out *NamespacedName) { *out = *in @@ -1216,6 +1444,43 @@ func (in *RPOConfig) DeepCopy() *RPOConfig { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ResourceSelector) DeepCopyInto(out *ResourceSelector) { + *out = *in + if in.GroupKind != nil { + in, out := &in.GroupKind, &out.GroupKind + *out = new(RestoreConfig_GroupKind) + (*in).DeepCopyInto(*out) + } + if in.Name != nil { + in, out := &in.Name, &out.Name + *out = new(string) + **out = **in + } + if in.Namespace != nil { + in, out := &in.Namespace, &out.Namespace + *out = new(string) + **out = **in + } + if in.Labels != nil { + in, out := &in.Labels, &out.Labels + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ResourceSelector. +func (in *ResourceSelector) DeepCopy() *ResourceSelector { + if in == nil { + return nil + } + out := new(ResourceSelector) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *RestoreConfig) DeepCopyInto(out *RestoreConfig) { *out = *in @@ -1579,6 +1844,41 @@ func (in *RestoreConfig_VolumeDataRestorePolicyBinding) DeepCopy() *RestoreConfi return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *RestoreIdentity) DeepCopyInto(out *RestoreIdentity) { + *out = *in + if in.parent != nil { + in, out := &in.parent, &out.parent + *out = new(RestoreParent) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RestoreIdentity. +func (in *RestoreIdentity) DeepCopy() *RestoreIdentity { + if in == nil { + return nil + } + out := new(RestoreIdentity) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *RestoreParent) DeepCopyInto(out *RestoreParent) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RestoreParent. +func (in *RestoreParent) DeepCopy() *RestoreParent { + if in == nil { + return nil + } + out := new(RestoreParent) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *RestorePlanIdentity) DeepCopyInto(out *RestorePlanIdentity) { *out = *in @@ -1629,6 +1929,50 @@ func (in *RestorePlanRef) DeepCopy() *RestorePlanRef { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *RestoreRef) DeepCopyInto(out *RestoreRef) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RestoreRef. +func (in *RestoreRef) DeepCopy() *RestoreRef { + if in == nil { + return nil + } + out := new(RestoreRef) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Restore_Filter) DeepCopyInto(out *Restore_Filter) { + *out = *in + if in.InclusionFilters != nil { + in, out := &in.InclusionFilters, &out.InclusionFilters + *out = make([]ResourceSelector, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.ExclusionFilters != nil { + in, out := &in.ExclusionFilters, &out.ExclusionFilters + *out = make([]ResourceSelector, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Restore_Filter. +func (in *Restore_Filter) DeepCopy() *Restore_Filter { + if in == nil { + return nil + } + out := new(Restore_Filter) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *TimeOfDay) DeepCopyInto(out *TimeOfDay) { *out = *in @@ -1663,3 +2007,28 @@ func (in *TimeOfDay) DeepCopy() *TimeOfDay { in.DeepCopyInto(out) return out } + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *VolumeDataRestorePolicyOverride) DeepCopyInto(out *VolumeDataRestorePolicyOverride) { + *out = *in + if in.Policy != nil { + in, out := &in.Policy, &out.Policy + *out = new(string) + **out = **in + } + if in.SelectedPvcs != nil { + in, out := &in.SelectedPvcs, &out.SelectedPvcs + *out = new(NamespacedNames) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VolumeDataRestorePolicyOverride. +func (in *VolumeDataRestorePolicyOverride) DeepCopy() *VolumeDataRestorePolicyOverride { + if in == nil { + return nil + } + out := new(VolumeDataRestorePolicyOverride) + in.DeepCopyInto(out) + return out +} diff --git a/config/crds/resources/apiextensions.k8s.io_v1_customresourcedefinition_gkebackuprestores.gkebackup.cnrm.cloud.google.com.yaml b/config/crds/resources/apiextensions.k8s.io_v1_customresourcedefinition_gkebackuprestores.gkebackup.cnrm.cloud.google.com.yaml new file mode 100644 index 00000000000..01161e2291a --- /dev/null +++ b/config/crds/resources/apiextensions.k8s.io_v1_customresourcedefinition_gkebackuprestores.gkebackup.cnrm.cloud.google.com.yaml @@ -0,0 +1,777 @@ +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: gkebackuprestores.gkebackup.cnrm.cloud.google.com +spec: + group: gkebackup.cnrm.cloud.google.com + names: + categories: + - gcp + kind: GKEBackupRestore + listKind: GKEBackupRestoreList + plural: gkebackuprestores + shortNames: + - gcpgkebackuprestore + - gcpgkebackuprestores + singular: gkebackuprestore + 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: GKEBackupRestore is the Schema for the GKEBackupRestore 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: GKEBackupRestoreSpec defines the desired state of GKEBackupRestore + properties: + backupRef: + description: Required. Immutable. A reference to the [Backup][google.cloud.gkebackup.v1.Backup] + used as the source from which this Restore will restore. Note that + this Backup must be a sub-resource of the RestorePlan's [backup_plan][google.cloud.gkebackup.v1.RestorePlan.backup_plan]. + oneOf: + - not: + required: + - external + required: + - name + - not: + anyOf: + - required: + - name + - required: + - namespace + required: + - external + properties: + external: + description: A reference to an externally managed GKEBackupBackup + resource. Should be in the format "projects/{{projectID}}/locations/{{location}}/backups/{{backupID}}". + type: string + name: + description: The name of a GKEBackupBackup resource. + type: string + namespace: + description: The namespace of a GKEBackupBackup resource. + type: string + type: object + description: + description: User specified descriptive string for this Restore. + type: string + filter: + description: Optional. Immutable. Filters resources for `Restore`. + If not specified, the scope of the restore will remain the same + as defined in the `RestorePlan`. If this is specified, and no resources + are matched by the `inclusion_filters` or everything is excluded + by the `exclusion_filters`, nothing will be restored. This filter + can only be specified if the value of [namespaced_resource_restore_mode][google.cloud.gkebackup.v1.RestoreConfig.namespaced_resource_restore_mode] + is set to `MERGE_SKIP_ON_CONFLICT`, `MERGE_REPLACE_VOLUME_ON_CONFLICT` + or `MERGE_REPLACE_ON_CONFLICT`. + properties: + exclusionFilters: + description: Optional. Excludes resources from restoration. If + specified, a resource will not be restored if it matches any + `ResourceSelector` of the `exclusion_filters`. + items: + properties: + groupKind: + description: Optional. Selects resources using their Kubernetes + GroupKinds. If specified, only resources of provided GroupKind + will be selected. + properties: + resourceGroup: + description: 'Optional. API group string of a Kubernetes + resource, e.g. "apiextensions.k8s.io", "storage.k8s.io", + etc. Note: use empty string for core API group' + type: string + resourceKind: + description: Optional. Kind of a Kubernetes resource, + must be in UpperCamelCase (PascalCase) and singular + form. E.g. "CustomResourceDefinition", "StorageClass", + etc. + type: string + type: object + labels: + additionalProperties: + type: string + description: Optional. Selects resources using Kubernetes + [labels](https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/). + If specified, a resource will be selected if and only + if the resource has all of the provided labels and all + the label values match. + type: object + name: + description: Optional. Selects resources using their resource + names. If specified, only resources with the provided + name will be selected. + type: string + namespace: + description: Optional. Selects resources using their namespaces. + This only applies to namespace scoped resources and cannot + be used for selecting cluster scoped resources. If specified, + only resources in the provided namespace will be selected. + If not specified, the filter will apply to both cluster + scoped and namespace scoped resources (e.g. name or label). + The [Namespace](https://pkg.go.dev/k8s.io/api/core/v1#Namespace) + resource itself will be restored if and only if any resources + within the namespace are restored. + type: string + type: object + type: array + inclusionFilters: + description: Optional. Selects resources for restoration. If specified, + only resources which match `inclusion_filters` will be selected + for restoration. A resource will be selected if it matches any + `ResourceSelector` of the `inclusion_filters`. + items: + properties: + groupKind: + description: Optional. Selects resources using their Kubernetes + GroupKinds. If specified, only resources of provided GroupKind + will be selected. + properties: + resourceGroup: + description: 'Optional. API group string of a Kubernetes + resource, e.g. "apiextensions.k8s.io", "storage.k8s.io", + etc. Note: use empty string for core API group' + type: string + resourceKind: + description: Optional. Kind of a Kubernetes resource, + must be in UpperCamelCase (PascalCase) and singular + form. E.g. "CustomResourceDefinition", "StorageClass", + etc. + type: string + type: object + labels: + additionalProperties: + type: string + description: Optional. Selects resources using Kubernetes + [labels](https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/). + If specified, a resource will be selected if and only + if the resource has all of the provided labels and all + the label values match. + type: object + name: + description: Optional. Selects resources using their resource + names. If specified, only resources with the provided + name will be selected. + type: string + namespace: + description: Optional. Selects resources using their namespaces. + This only applies to namespace scoped resources and cannot + be used for selecting cluster scoped resources. If specified, + only resources in the provided namespace will be selected. + If not specified, the filter will apply to both cluster + scoped and namespace scoped resources (e.g. name or label). + The [Namespace](https://pkg.go.dev/k8s.io/api/core/v1#Namespace) + resource itself will be restored if and only if any resources + within the namespace are restored. + type: string + type: object + type: array + type: object + labels: + additionalProperties: + type: string + description: A set of custom labels supplied by user. + type: object + resourceID: + description: The GKEBackupRestore name. If not given, the metadata.name + will be used. + type: string + restorePlanRef: + description: Required. The RestorePlan from which this Restore is + created. + oneOf: + - not: + required: + - external + required: + - name + - not: + anyOf: + - required: + - name + - required: + - namespace + required: + - external + properties: + external: + description: A reference to an externally managed GKEBackupRestorePlan + resource. Should be in the format "projects/{{projectID}}/locations/{{location}}/restorePlans/{{restoreplanID}}". + type: string + name: + description: The name of a GKEBackupRestorePlan resource. + type: string + namespace: + description: The namespace of a GKEBackupRestorePlan resource. + type: string + type: object + volumeDataRestorePolicyOverrides: + description: Optional. Immutable. Overrides the volume data restore + policies selected in the Restore Config for override-scoped resources. + items: + properties: + policy: + description: Required. The VolumeDataRestorePolicy to apply + when restoring volumes in scope. + type: string + selectedPvcs: + description: A list of PVCs to apply the policy override to. + properties: + namespacedNames: + description: Optional. A list of namespaced Kubernetes resources. + items: + properties: + name: + description: Optional. The name of the Kubernetes + resource. + type: string + namespace: + description: Optional. The Namespace of the Kubernetes + resource. + type: string + type: object + type: array + type: object + type: object + type: array + required: + - restorePlanRef + type: object + status: + description: GKEBackupRestoreStatus defines the config connector machine + state of GKEBackupRestore + 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 GKEBackupRestore 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: + cluster: + description: |- + Output only. The target cluster into which this Restore will restore data. + Valid formats: + + - `projects/*/locations/*/clusters/*` + - `projects/*/zones/*/clusters/*` + + Inherited from parent RestorePlan's + [cluster][google.cloud.gkebackup.v1.RestorePlan.cluster] value. + type: string + completeTime: + description: Output only. Timestamp of when the restore operation + completed. + type: string + createTime: + description: Output only. The timestamp when this Restore resource + was created. + type: string + etag: + description: 'Output only. `etag` is used for optimistic concurrency + control as a way to help prevent simultaneous updates of a restore + from overwriting each other. It is strongly suggested that systems + make use of the `etag` in the read-modify-write cycle to perform + restore updates in order to avoid race conditions: An `etag` + is returned in the response to `GetRestore`, and systems are + expected to put that etag in the request to `UpdateRestore` + or `DeleteRestore` to ensure that their change will be applied + to the same version of the resource.' + type: string + resourcesExcludedCount: + description: Output only. Number of resources excluded during + the restore execution. + format: int32 + type: integer + resourcesFailedCount: + description: Output only. Number of resources that failed to be + restored during the restore execution. + format: int32 + type: integer + resourcesRestoredCount: + description: Output only. Number of resources restored during + the restore execution. + format: int32 + type: integer + restoreConfig: + description: Output only. Configuration of the Restore. Inherited + from parent RestorePlan's [restore_config][google.cloud.gkebackup.v1.RestorePlan.restore_config]. + properties: + allNamespaces: + description: Restore all namespaced resources in the Backup + if set to "True". Specifying this field to "False" is an + error. + type: boolean + clusterResourceConflictPolicy: + description: Optional. Defines the behavior for handling the + situation where cluster-scoped resources being restored + already exist in the target cluster. This MUST be set to + a value other than CLUSTER_RESOURCE_CONFLICT_POLICY_UNSPECIFIED + if [cluster_resource_restore_scope][google.cloud.gkebackup.v1.RestoreConfig.cluster_resource_restore_scope] + is not empty. + type: string + clusterResourceRestoreScope: + description: Optional. Identifies the cluster-scoped resources + to restore from the Backup. Not specifying it means NO cluster + resource will be restored. + properties: + allGroupKinds: + description: Optional. If True, all valid cluster-scoped + resources will be restored. Mutually exclusive to any + other field in the message. + type: boolean + excludedGroupKinds: + description: Optional. A list of cluster-scoped resource + group kinds to NOT restore from the backup. If specified, + all valid cluster-scoped resources will be restored + except for those specified in the list. Mutually exclusive + to any other field in the message. + items: + properties: + resourceGroup: + description: 'Optional. API group string of a Kubernetes + resource, e.g. "apiextensions.k8s.io", "storage.k8s.io", + etc. Note: use empty string for core API group' + type: string + resourceKind: + description: Optional. Kind of a Kubernetes resource, + must be in UpperCamelCase (PascalCase) and singular + form. E.g. "CustomResourceDefinition", "StorageClass", + etc. + type: string + type: object + type: array + noGroupKinds: + description: Optional. If True, no cluster-scoped resources + will be restored. This has the same restore scope as + if the message is not defined. Mutually exclusive to + any other field in the message. + type: boolean + selectedGroupKinds: + description: Optional. A list of cluster-scoped resource + group kinds to restore from the backup. If specified, + only the selected resources will be restored. Mutually + exclusive to any other field in the message. + items: + properties: + resourceGroup: + description: 'Optional. API group string of a Kubernetes + resource, e.g. "apiextensions.k8s.io", "storage.k8s.io", + etc. Note: use empty string for core API group' + type: string + resourceKind: + description: Optional. Kind of a Kubernetes resource, + must be in UpperCamelCase (PascalCase) and singular + form. E.g. "CustomResourceDefinition", "StorageClass", + etc. + type: string + type: object + type: array + type: object + excludedNamespaces: + description: A list of selected namespaces excluded from restoration. + All namespaces except those in this list will be restored. + properties: + namespaces: + description: Optional. A list of Kubernetes Namespaces + items: + type: string + type: array + type: object + namespacedResourceRestoreMode: + description: Optional. Defines the behavior for handling the + situation where sets of namespaced resources being restored + already exist in the target cluster. This MUST be set to + a value other than NAMESPACED_RESOURCE_RESTORE_MODE_UNSPECIFIED. + type: string + noNamespaces: + description: Do not restore any namespaced resources if set + to "True". Specifying this field to "False" is not allowed. + type: boolean + restoreOrder: + description: Optional. RestoreOrder contains custom ordering + to use on a Restore. + properties: + groupKindDependencies: + description: Optional. Contains a list of group kind dependency + pairs provided by the customer, that is used by Backup + for GKE to generate a group kind restore order. + items: + properties: + requiring: + description: Required. The requiring group kind + requires that the other group kind be restored + first. + properties: + resourceGroup: + description: 'Optional. API group string of + a Kubernetes resource, e.g. "apiextensions.k8s.io", + "storage.k8s.io", etc. Note: use empty string + for core API group' + type: string + resourceKind: + description: Optional. Kind of a Kubernetes + resource, must be in UpperCamelCase (PascalCase) + and singular form. E.g. "CustomResourceDefinition", + "StorageClass", etc. + type: string + type: object + satisfying: + description: Required. The satisfying group kind + must be restored first in order to satisfy the + dependency. + properties: + resourceGroup: + description: 'Optional. API group string of + a Kubernetes resource, e.g. "apiextensions.k8s.io", + "storage.k8s.io", etc. Note: use empty string + for core API group' + type: string + resourceKind: + description: Optional. Kind of a Kubernetes + resource, must be in UpperCamelCase (PascalCase) + and singular form. E.g. "CustomResourceDefinition", + "StorageClass", etc. + type: string + type: object + required: + - requiring + - satisfying + type: object + type: array + type: object + selectedApplications: + description: A list of selected ProtectedApplications to restore. + The listed ProtectedApplications and all the resources to + which they refer will be restored. + properties: + namespacedNames: + description: Optional. A list of namespaced Kubernetes + resources. + items: + properties: + name: + description: Optional. The name of the Kubernetes + resource. + type: string + namespace: + description: Optional. The Namespace of the Kubernetes + resource. + type: string + type: object + type: array + type: object + selectedNamespaces: + description: A list of selected Namespaces to restore from + the Backup. The listed Namespaces and all resources contained + in them will be restored. + properties: + namespaces: + description: Optional. A list of Kubernetes Namespaces + items: + type: string + type: array + type: object + substitutionRules: + description: Optional. A list of transformation rules to be + applied against Kubernetes resources as they are selected + for restoration from a Backup. Rules are executed in order + defined - this order matters, as changes made by a rule + may impact the filtering logic of subsequent rules. An empty + list means no substitution will occur. + items: + properties: + newValue: + description: Optional. This is the new value to set + for any fields that pass the filtering and selection + criteria. To remove a value from a Kubernetes resource, + either leave this field unspecified, or set it to + the empty string (""). + type: string + originalValuePattern: + description: Optional. (Filtering parameter) This is + a [regular expression] (https://en.wikipedia.org/wiki/Regular_expression) + that is compared against the fields matched by the + target_json_path expression (and must also have passed + the previous filters). Substitution will not be performed + against fields whose value does not match this expression. + If this field is NOT specified, then ALL fields matched + by the target_json_path expression will undergo substitution. + Note that an empty (e.g., "", rather than unspecified) + value for this field will only match empty fields. + type: string + targetGroupKinds: + description: Optional. (Filtering parameter) Any resource + subject to substitution must belong to one of the + listed "types". If this field is not provided, no + type filtering will be performed (all resources of + all types matching previous filtering parameters will + be candidates for substitution). + items: + properties: + resourceGroup: + description: 'Optional. API group string of a + Kubernetes resource, e.g. "apiextensions.k8s.io", + "storage.k8s.io", etc. Note: use empty string + for core API group' + type: string + resourceKind: + description: Optional. Kind of a Kubernetes resource, + must be in UpperCamelCase (PascalCase) and singular + form. E.g. "CustomResourceDefinition", "StorageClass", + etc. + type: string + type: object + type: array + targetJSONPath: + description: Required. This is a [JSONPath] (https://kubernetes.io/docs/reference/kubectl/jsonpath/) + expression that matches specific fields of candidate + resources and it operates as both a filtering parameter + (resources that are not matched with this expression + will not be candidates for substitution) as well as + a field identifier (identifies exactly which fields + out of the candidate resources will be modified). + type: string + targetNamespaces: + description: Optional. (Filtering parameter) Any resource + subject to substitution must be contained within one + of the listed Kubernetes Namespace in the Backup. + If this field is not provided, no namespace filtering + will be performed (all resources in all Namespaces, + including all cluster-scoped resources, will be candidates + for substitution). To mix cluster-scoped and namespaced + resources in the same rule, use an empty string ("") + as one of the target namespaces. + items: + type: string + type: array + required: + - targetJSONPath + type: object + type: array + transformationRules: + description: Optional. A list of transformation rules to be + applied against Kubernetes resources as they are selected + for restoration from a Backup. Rules are executed in order + defined - this order matters, as changes made by a rule + may impact the filtering logic of subsequent rules. An empty + list means no transformation will occur. + items: + properties: + description: + description: Optional. The description is a user specified + string description of the transformation rule. + type: string + fieldActions: + description: Required. A list of transformation rule + actions to take against candidate resources. Actions + are executed in order defined - this order matters, + as they could potentially interfere with each other + and the first operation could affect the outcome of + the second operation. + items: + properties: + fromPath: + description: Optional. A string containing a JSON + Pointer value that references the location in + the target document to move the value from. + type: string + op: + description: Required. op specifies the operation + to perform. + type: string + path: + description: Optional. A string containing a JSON-Pointer + value that references a location within the + target document where the operation is performed. + type: string + value: + description: Optional. A string that specifies + the desired value in string format to use for + transformation. + type: string + required: + - op + type: object + type: array + resourceFilter: + description: Optional. This field is used to specify + a set of fields that should be used to determine which + resources in backup should be acted upon by the supplied + transformation rule actions, and this will ensure + that only specific resources are affected by transformation + rule actions. + properties: + groupKinds: + description: Optional. (Filtering parameter) Any + resource subject to transformation must belong + to one of the listed "types". If this field is + not provided, no type filtering will be performed + (all resources of all types matching previous + filtering parameters will be candidates for transformation). + items: + properties: + resourceGroup: + description: 'Optional. API group string of + a Kubernetes resource, e.g. "apiextensions.k8s.io", + "storage.k8s.io", etc. Note: use empty string + for core API group' + type: string + resourceKind: + description: Optional. Kind of a Kubernetes + resource, must be in UpperCamelCase (PascalCase) + and singular form. E.g. "CustomResourceDefinition", + "StorageClass", etc. + type: string + type: object + type: array + jsonPath: + description: Optional. This is a [JSONPath] (https://github.com/json-path/JsonPath/blob/master/README.md) + expression that matches specific fields of candidate + resources and it operates as a filtering parameter + (resources that are not matched with this expression + will not be candidates for transformation). + type: string + namespaces: + description: Optional. (Filtering parameter) Any + resource subject to transformation must be contained + within one of the listed Kubernetes Namespace + in the Backup. If this field is not provided, + no namespace filtering will be performed (all + resources in all Namespaces, including all cluster-scoped + resources, will be candidates for transformation). + items: + type: string + type: array + type: object + required: + - fieldActions + type: object + type: array + volumeDataRestorePolicy: + description: 'Optional. Specifies the mechanism to be used + to restore volume data. Default: VOLUME_DATA_RESTORE_POLICY_UNSPECIFIED + (will be treated as NO_VOLUME_DATA_RESTORATION).' + type: string + volumeDataRestorePolicyBindings: + description: Optional. A table that binds volumes by their + scope to a restore policy. Bindings must have a unique scope. + Any volumes not scoped in the bindings are subject to the + policy defined in volume_data_restore_policy. + items: + properties: + policy: + description: Required. The VolumeDataRestorePolicy to + apply when restoring volumes in scope. + type: string + volumeType: + description: The volume type, as determined by the PVC's + bound PV, to apply the policy to. + type: string + required: + - policy + type: object + type: array + type: object + state: + description: Output only. The current state of the Restore. + type: string + stateReason: + description: Output only. Human-readable description of why the + Restore is in its current state. + type: string + uid: + description: Output only. Server generated global unique identifier + of [UUID](https://en.wikipedia.org/wiki/Universally_unique_identifier) + format. + type: string + updateTime: + description: Output only. The timestamp when this Restore resource + was last updated. + type: string + volumesRestoredCount: + description: Output only. Number of volumes restored during the + restore execution. + format: int32 + type: integer + type: object + type: object + required: + - spec + type: object + served: true + storage: true + subresources: + status: {} diff --git a/pkg/controller/direct/gkebackup/mapper.generated.go b/pkg/controller/direct/gkebackup/mapper.generated.go index e0f53d67453..15b3f19d09b 100644 --- a/pkg/controller/direct/gkebackup/mapper.generated.go +++ b/pkg/controller/direct/gkebackup/mapper.generated.go @@ -21,11 +21,11 @@ package gkebackup import ( pb "cloud.google.com/go/gkebackup/apiv1/gkebackuppb" - krm "github.com/GoogleCloudPlatform/k8s-config-connector/apis/gkebackup/v1alpha1" + krmv1alpha1 "github.com/GoogleCloudPlatform/k8s-config-connector/apis/gkebackup/v1alpha1" "github.com/GoogleCloudPlatform/k8s-config-connector/pkg/controller/direct" ) -func BackupPlan_BackupConfig_ToProto(mapCtx *direct.MapContext, in *krm.BackupPlan_BackupConfig) *pb.BackupPlan_BackupConfig { +func BackupPlan_BackupConfig_ToProto(mapCtx *direct.MapContext, in *krmv1alpha1.BackupPlan_BackupConfig) *pb.BackupPlan_BackupConfig { if in == nil { return nil } @@ -45,17 +45,17 @@ func BackupPlan_BackupConfig_ToProto(mapCtx *direct.MapContext, in *krm.BackupPl out.PermissiveMode = direct.ValueOf(in.PermissiveMode) return out } -func BackupPlan_RetentionPolicy_FromProto(mapCtx *direct.MapContext, in *pb.BackupPlan_RetentionPolicy) *krm.BackupPlan_RetentionPolicy { +func BackupPlan_RetentionPolicy_FromProto(mapCtx *direct.MapContext, in *pb.BackupPlan_RetentionPolicy) *krmv1alpha1.BackupPlan_RetentionPolicy { if in == nil { return nil } - out := &krm.BackupPlan_RetentionPolicy{} + out := &krmv1alpha1.BackupPlan_RetentionPolicy{} out.BackupDeleteLockDays = direct.LazyPtr(in.GetBackupDeleteLockDays()) out.BackupRetainDays = direct.LazyPtr(in.GetBackupRetainDays()) out.Locked = direct.LazyPtr(in.GetLocked()) return out } -func BackupPlan_RetentionPolicy_ToProto(mapCtx *direct.MapContext, in *krm.BackupPlan_RetentionPolicy) *pb.BackupPlan_RetentionPolicy { +func BackupPlan_RetentionPolicy_ToProto(mapCtx *direct.MapContext, in *krmv1alpha1.BackupPlan_RetentionPolicy) *pb.BackupPlan_RetentionPolicy { if in == nil { return nil } @@ -65,18 +65,18 @@ func BackupPlan_RetentionPolicy_ToProto(mapCtx *direct.MapContext, in *krm.Backu out.Locked = direct.ValueOf(in.Locked) return out } -func BackupPlan_ScheduleObservedState_FromProto(mapCtx *direct.MapContext, in *pb.BackupPlan_Schedule) *krm.BackupPlan_ScheduleObservedState { +func BackupPlan_ScheduleObservedState_FromProto(mapCtx *direct.MapContext, in *pb.BackupPlan_Schedule) *krmv1alpha1.BackupPlan_ScheduleObservedState { if in == nil { return nil } - out := &krm.BackupPlan_ScheduleObservedState{} + out := &krmv1alpha1.BackupPlan_ScheduleObservedState{} // MISSING: CronSchedule // MISSING: Paused // MISSING: RpoConfig out.NextScheduledBackupTime = direct.StringTimestamp_FromProto(mapCtx, in.GetNextScheduledBackupTime()) return out } -func BackupPlan_ScheduleObservedState_ToProto(mapCtx *direct.MapContext, in *krm.BackupPlan_ScheduleObservedState) *pb.BackupPlan_Schedule { +func BackupPlan_ScheduleObservedState_ToProto(mapCtx *direct.MapContext, in *krmv1alpha1.BackupPlan_ScheduleObservedState) *pb.BackupPlan_Schedule { if in == nil { return nil } @@ -87,11 +87,11 @@ func BackupPlan_ScheduleObservedState_ToProto(mapCtx *direct.MapContext, in *krm out.NextScheduledBackupTime = direct.StringTimestamp_ToProto(mapCtx, in.NextScheduledBackupTime) return out } -func ExclusionWindow_FromProto(mapCtx *direct.MapContext, in *pb.ExclusionWindow) *krm.ExclusionWindow { +func ExclusionWindow_FromProto(mapCtx *direct.MapContext, in *pb.ExclusionWindow) *krmv1alpha1.ExclusionWindow { if in == nil { return nil } - out := &krm.ExclusionWindow{} + out := &krmv1alpha1.ExclusionWindow{} out.StartTime = TimeOfDay_FromProto(mapCtx, in.GetStartTime()) out.Duration = direct.StringDuration_FromProto(mapCtx, in.GetDuration()) out.SingleOccurrenceDate = Date_FromProto(mapCtx, in.GetSingleOccurrenceDate()) @@ -99,7 +99,7 @@ func ExclusionWindow_FromProto(mapCtx *direct.MapContext, in *pb.ExclusionWindow out.DaysOfWeek = ExclusionWindow_DayOfWeekList_FromProto(mapCtx, in.GetDaysOfWeek()) return out } -func ExclusionWindow_ToProto(mapCtx *direct.MapContext, in *krm.ExclusionWindow) *pb.ExclusionWindow { +func ExclusionWindow_ToProto(mapCtx *direct.MapContext, in *krmv1alpha1.ExclusionWindow) *pb.ExclusionWindow { if in == nil { return nil } @@ -117,15 +117,15 @@ func ExclusionWindow_ToProto(mapCtx *direct.MapContext, in *krm.ExclusionWindow) } return out } -func ExclusionWindow_DayOfWeekList_FromProto(mapCtx *direct.MapContext, in *pb.ExclusionWindow_DayOfWeekList) *krm.ExclusionWindow_DayOfWeekList { +func ExclusionWindow_DayOfWeekList_FromProto(mapCtx *direct.MapContext, in *pb.ExclusionWindow_DayOfWeekList) *krmv1alpha1.ExclusionWindow_DayOfWeekList { if in == nil { return nil } - out := &krm.ExclusionWindow_DayOfWeekList{} + out := &krmv1alpha1.ExclusionWindow_DayOfWeekList{} out.DaysOfWeek = direct.EnumSlice_FromProto(mapCtx, in.DaysOfWeek) return out } -func GKEBackupBackupPlanSpec_ToProto(mapCtx *direct.MapContext, in *krm.GKEBackupBackupPlanSpec) *pb.BackupPlan { +func GKEBackupBackupPlanSpec_ToProto(mapCtx *direct.MapContext, in *krmv1alpha1.GKEBackupBackupPlanSpec) *pb.BackupPlan { if in == nil { return nil } @@ -145,11 +145,11 @@ func GKEBackupBackupPlanSpec_ToProto(mapCtx *direct.MapContext, in *krm.GKEBacku // MISSING: RpoRiskReason return out } -func GKEBackupBackupSpec_FromProto(mapCtx *direct.MapContext, in *pb.Backup) *krm.GKEBackupBackupSpec { +func GKEBackupBackupSpec_FromProto(mapCtx *direct.MapContext, in *pb.Backup) *krmv1alpha1.GKEBackupBackupSpec { if in == nil { return nil } - out := &krm.GKEBackupBackupSpec{} + out := &krmv1alpha1.GKEBackupBackupSpec{} // MISSING: Name // MISSING: Uid out.Labels = in.Labels @@ -158,7 +158,7 @@ func GKEBackupBackupSpec_FromProto(mapCtx *direct.MapContext, in *pb.Backup) *kr out.Description = direct.LazyPtr(in.GetDescription()) return out } -func GKEBackupBackupSpec_ToProto(mapCtx *direct.MapContext, in *krm.GKEBackupBackupSpec) *pb.Backup { +func GKEBackupBackupSpec_ToProto(mapCtx *direct.MapContext, in *krmv1alpha1.GKEBackupBackupSpec) *pb.Backup { if in == nil { return nil } @@ -171,7 +171,7 @@ func GKEBackupBackupSpec_ToProto(mapCtx *direct.MapContext, in *krm.GKEBackupBac out.Description = direct.ValueOf(in.Description) return out } -func GKEBackupRestorePlanSpec_ToProto(mapCtx *direct.MapContext, in *krm.GKEBackupRestorePlanSpec) *pb.RestorePlan { +func GKEBackupRestorePlanSpec_ToProto(mapCtx *direct.MapContext, in *krmv1alpha1.GKEBackupRestorePlanSpec) *pb.RestorePlan { if in == nil { return nil } @@ -189,16 +189,32 @@ func GKEBackupRestorePlanSpec_ToProto(mapCtx *direct.MapContext, in *krm.GKEBack out.Labels = in.Labels return out } -func NamespacedName_FromProto(mapCtx *direct.MapContext, in *pb.NamespacedName) *krm.NamespacedName { +func GKEBackupRestoreSpec_ToProto(mapCtx *direct.MapContext, in *krmv1alpha1.GKEBackupRestoreSpec) *pb.Restore { if in == nil { return nil } - out := &krm.NamespacedName{} + out := &pb.Restore{} + // MISSING: Name + // MISSING: Uid + out.Description = direct.ValueOf(in.Description) + if in.BackupRef != nil { + out.Backup = in.BackupRef.External + } + out.Labels = in.Labels + out.Filter = Restore_Filter_ToProto(mapCtx, in.Filter) + out.VolumeDataRestorePolicyOverrides = direct.Slice_ToProto(mapCtx, in.VolumeDataRestorePolicyOverrides, VolumeDataRestorePolicyOverride_ToProto) + return out +} +func NamespacedName_FromProto(mapCtx *direct.MapContext, in *pb.NamespacedName) *krmv1alpha1.NamespacedName { + if in == nil { + return nil + } + out := &krmv1alpha1.NamespacedName{} out.Namespace = direct.LazyPtr(in.GetNamespace()) out.Name = direct.LazyPtr(in.GetName()) return out } -func NamespacedName_ToProto(mapCtx *direct.MapContext, in *krm.NamespacedName) *pb.NamespacedName { +func NamespacedName_ToProto(mapCtx *direct.MapContext, in *krmv1alpha1.NamespacedName) *pb.NamespacedName { if in == nil { return nil } @@ -207,15 +223,15 @@ func NamespacedName_ToProto(mapCtx *direct.MapContext, in *krm.NamespacedName) * out.Name = direct.ValueOf(in.Name) return out } -func NamespacedNames_FromProto(mapCtx *direct.MapContext, in *pb.NamespacedNames) *krm.NamespacedNames { +func NamespacedNames_FromProto(mapCtx *direct.MapContext, in *pb.NamespacedNames) *krmv1alpha1.NamespacedNames { if in == nil { return nil } - out := &krm.NamespacedNames{} + out := &krmv1alpha1.NamespacedNames{} out.NamespacedNames = direct.Slice_FromProto(mapCtx, in.NamespacedNames, NamespacedName_FromProto) return out } -func NamespacedNames_ToProto(mapCtx *direct.MapContext, in *krm.NamespacedNames) *pb.NamespacedNames { +func NamespacedNames_ToProto(mapCtx *direct.MapContext, in *krmv1alpha1.NamespacedNames) *pb.NamespacedNames { if in == nil { return nil } @@ -223,15 +239,15 @@ func NamespacedNames_ToProto(mapCtx *direct.MapContext, in *krm.NamespacedNames) out.NamespacedNames = direct.Slice_ToProto(mapCtx, in.NamespacedNames, NamespacedName_ToProto) return out } -func Namespaces_FromProto(mapCtx *direct.MapContext, in *pb.Namespaces) *krm.Namespaces { +func Namespaces_FromProto(mapCtx *direct.MapContext, in *pb.Namespaces) *krmv1alpha1.Namespaces { if in == nil { return nil } - out := &krm.Namespaces{} + out := &krmv1alpha1.Namespaces{} out.Namespaces = in.Namespaces return out } -func Namespaces_ToProto(mapCtx *direct.MapContext, in *krm.Namespaces) *pb.Namespaces { +func Namespaces_ToProto(mapCtx *direct.MapContext, in *krmv1alpha1.Namespaces) *pb.Namespaces { if in == nil { return nil } @@ -239,7 +255,29 @@ func Namespaces_ToProto(mapCtx *direct.MapContext, in *krm.Namespaces) *pb.Names out.Namespaces = in.Namespaces return out } -func RestoreConfig_ToProto(mapCtx *direct.MapContext, in *krm.RestoreConfig) *pb.RestoreConfig { +func ResourceSelector_FromProto(mapCtx *direct.MapContext, in *pb.ResourceSelector) *krmv1alpha1.ResourceSelector { + if in == nil { + return nil + } + out := &krmv1alpha1.ResourceSelector{} + out.GroupKind = RestoreConfig_GroupKind_FromProto(mapCtx, in.GetGroupKind()) + out.Name = direct.LazyPtr(in.GetName()) + out.Namespace = direct.LazyPtr(in.GetNamespace()) + out.Labels = in.Labels + return out +} +func ResourceSelector_ToProto(mapCtx *direct.MapContext, in *krmv1alpha1.ResourceSelector) *pb.ResourceSelector { + if in == nil { + return nil + } + out := &pb.ResourceSelector{} + out.GroupKind = RestoreConfig_GroupKind_ToProto(mapCtx, in.GroupKind) + out.Name = direct.ValueOf(in.Name) + out.Namespace = direct.ValueOf(in.Namespace) + out.Labels = in.Labels + return out +} +func RestoreConfig_ToProto(mapCtx *direct.MapContext, in *krmv1alpha1.RestoreConfig) *pb.RestoreConfig { if in == nil { return nil } @@ -269,18 +307,18 @@ func RestoreConfig_ToProto(mapCtx *direct.MapContext, in *krm.RestoreConfig) *pb out.RestoreOrder = RestoreConfig_RestoreOrder_ToProto(mapCtx, in.RestoreOrder) return out } -func RestoreConfig_ClusterResourceRestoreScope_FromProto(mapCtx *direct.MapContext, in *pb.RestoreConfig_ClusterResourceRestoreScope) *krm.RestoreConfig_ClusterResourceRestoreScope { +func RestoreConfig_ClusterResourceRestoreScope_FromProto(mapCtx *direct.MapContext, in *pb.RestoreConfig_ClusterResourceRestoreScope) *krmv1alpha1.RestoreConfig_ClusterResourceRestoreScope { if in == nil { return nil } - out := &krm.RestoreConfig_ClusterResourceRestoreScope{} + out := &krmv1alpha1.RestoreConfig_ClusterResourceRestoreScope{} out.SelectedGroupKinds = direct.Slice_FromProto(mapCtx, in.SelectedGroupKinds, RestoreConfig_GroupKind_FromProto) out.ExcludedGroupKinds = direct.Slice_FromProto(mapCtx, in.ExcludedGroupKinds, RestoreConfig_GroupKind_FromProto) out.AllGroupKinds = direct.LazyPtr(in.GetAllGroupKinds()) out.NoGroupKinds = direct.LazyPtr(in.GetNoGroupKinds()) return out } -func RestoreConfig_ClusterResourceRestoreScope_ToProto(mapCtx *direct.MapContext, in *krm.RestoreConfig_ClusterResourceRestoreScope) *pb.RestoreConfig_ClusterResourceRestoreScope { +func RestoreConfig_ClusterResourceRestoreScope_ToProto(mapCtx *direct.MapContext, in *krmv1alpha1.RestoreConfig_ClusterResourceRestoreScope) *pb.RestoreConfig_ClusterResourceRestoreScope { if in == nil { return nil } @@ -291,16 +329,16 @@ func RestoreConfig_ClusterResourceRestoreScope_ToProto(mapCtx *direct.MapContext out.NoGroupKinds = direct.ValueOf(in.NoGroupKinds) return out } -func RestoreConfig_GroupKind_FromProto(mapCtx *direct.MapContext, in *pb.RestoreConfig_GroupKind) *krm.RestoreConfig_GroupKind { +func RestoreConfig_GroupKind_FromProto(mapCtx *direct.MapContext, in *pb.RestoreConfig_GroupKind) *krmv1alpha1.RestoreConfig_GroupKind { if in == nil { return nil } - out := &krm.RestoreConfig_GroupKind{} + out := &krmv1alpha1.RestoreConfig_GroupKind{} out.ResourceGroup = direct.LazyPtr(in.GetResourceGroup()) out.ResourceKind = direct.LazyPtr(in.GetResourceKind()) return out } -func RestoreConfig_GroupKind_ToProto(mapCtx *direct.MapContext, in *krm.RestoreConfig_GroupKind) *pb.RestoreConfig_GroupKind { +func RestoreConfig_GroupKind_ToProto(mapCtx *direct.MapContext, in *krmv1alpha1.RestoreConfig_GroupKind) *pb.RestoreConfig_GroupKind { if in == nil { return nil } @@ -309,15 +347,15 @@ func RestoreConfig_GroupKind_ToProto(mapCtx *direct.MapContext, in *krm.RestoreC out.ResourceKind = direct.ValueOf(in.ResourceKind) return out } -func RestoreConfig_RestoreOrder_FromProto(mapCtx *direct.MapContext, in *pb.RestoreConfig_RestoreOrder) *krm.RestoreConfig_RestoreOrder { +func RestoreConfig_RestoreOrder_FromProto(mapCtx *direct.MapContext, in *pb.RestoreConfig_RestoreOrder) *krmv1alpha1.RestoreConfig_RestoreOrder { if in == nil { return nil } - out := &krm.RestoreConfig_RestoreOrder{} + out := &krmv1alpha1.RestoreConfig_RestoreOrder{} out.GroupKindDependencies = direct.Slice_FromProto(mapCtx, in.GroupKindDependencies, RestoreConfig_RestoreOrder_GroupKindDependency_FromProto) return out } -func RestoreConfig_RestoreOrder_ToProto(mapCtx *direct.MapContext, in *krm.RestoreConfig_RestoreOrder) *pb.RestoreConfig_RestoreOrder { +func RestoreConfig_RestoreOrder_ToProto(mapCtx *direct.MapContext, in *krmv1alpha1.RestoreConfig_RestoreOrder) *pb.RestoreConfig_RestoreOrder { if in == nil { return nil } @@ -325,16 +363,16 @@ func RestoreConfig_RestoreOrder_ToProto(mapCtx *direct.MapContext, in *krm.Resto out.GroupKindDependencies = direct.Slice_ToProto(mapCtx, in.GroupKindDependencies, RestoreConfig_RestoreOrder_GroupKindDependency_ToProto) return out } -func RestoreConfig_RestoreOrder_GroupKindDependency_FromProto(mapCtx *direct.MapContext, in *pb.RestoreConfig_RestoreOrder_GroupKindDependency) *krm.RestoreConfig_RestoreOrder_GroupKindDependency { +func RestoreConfig_RestoreOrder_GroupKindDependency_FromProto(mapCtx *direct.MapContext, in *pb.RestoreConfig_RestoreOrder_GroupKindDependency) *krmv1alpha1.RestoreConfig_RestoreOrder_GroupKindDependency { if in == nil { return nil } - out := &krm.RestoreConfig_RestoreOrder_GroupKindDependency{} + out := &krmv1alpha1.RestoreConfig_RestoreOrder_GroupKindDependency{} out.Satisfying = RestoreConfig_GroupKind_FromProto(mapCtx, in.GetSatisfying()) out.Requiring = RestoreConfig_GroupKind_FromProto(mapCtx, in.GetRequiring()) return out } -func RestoreConfig_RestoreOrder_GroupKindDependency_ToProto(mapCtx *direct.MapContext, in *krm.RestoreConfig_RestoreOrder_GroupKindDependency) *pb.RestoreConfig_RestoreOrder_GroupKindDependency { +func RestoreConfig_RestoreOrder_GroupKindDependency_ToProto(mapCtx *direct.MapContext, in *krmv1alpha1.RestoreConfig_RestoreOrder_GroupKindDependency) *pb.RestoreConfig_RestoreOrder_GroupKindDependency { if in == nil { return nil } @@ -343,17 +381,17 @@ func RestoreConfig_RestoreOrder_GroupKindDependency_ToProto(mapCtx *direct.MapCo out.Requiring = RestoreConfig_GroupKind_ToProto(mapCtx, in.Requiring) return out } -func RestoreConfig_TransformationRule_FromProto(mapCtx *direct.MapContext, in *pb.RestoreConfig_TransformationRule) *krm.RestoreConfig_TransformationRule { +func RestoreConfig_TransformationRule_FromProto(mapCtx *direct.MapContext, in *pb.RestoreConfig_TransformationRule) *krmv1alpha1.RestoreConfig_TransformationRule { if in == nil { return nil } - out := &krm.RestoreConfig_TransformationRule{} + out := &krmv1alpha1.RestoreConfig_TransformationRule{} out.FieldActions = direct.Slice_FromProto(mapCtx, in.FieldActions, RestoreConfig_TransformationRuleAction_FromProto) out.ResourceFilter = RestoreConfig_ResourceFilter_FromProto(mapCtx, in.GetResourceFilter()) out.Description = direct.LazyPtr(in.GetDescription()) return out } -func RestoreConfig_TransformationRule_ToProto(mapCtx *direct.MapContext, in *krm.RestoreConfig_TransformationRule) *pb.RestoreConfig_TransformationRule { +func RestoreConfig_TransformationRule_ToProto(mapCtx *direct.MapContext, in *krmv1alpha1.RestoreConfig_TransformationRule) *pb.RestoreConfig_TransformationRule { if in == nil { return nil } @@ -363,18 +401,18 @@ func RestoreConfig_TransformationRule_ToProto(mapCtx *direct.MapContext, in *krm out.Description = direct.ValueOf(in.Description) return out } -func RestoreConfig_TransformationRuleAction_FromProto(mapCtx *direct.MapContext, in *pb.RestoreConfig_TransformationRuleAction) *krm.RestoreConfig_TransformationRuleAction { +func RestoreConfig_TransformationRuleAction_FromProto(mapCtx *direct.MapContext, in *pb.RestoreConfig_TransformationRuleAction) *krmv1alpha1.RestoreConfig_TransformationRuleAction { if in == nil { return nil } - out := &krm.RestoreConfig_TransformationRuleAction{} + out := &krmv1alpha1.RestoreConfig_TransformationRuleAction{} out.Op = direct.Enum_FromProto(mapCtx, in.GetOp()) out.FromPath = direct.LazyPtr(in.GetFromPath()) out.Path = direct.LazyPtr(in.GetPath()) out.Value = direct.LazyPtr(in.GetValue()) return out } -func RestoreConfig_TransformationRuleAction_ToProto(mapCtx *direct.MapContext, in *krm.RestoreConfig_TransformationRuleAction) *pb.RestoreConfig_TransformationRuleAction { +func RestoreConfig_TransformationRuleAction_ToProto(mapCtx *direct.MapContext, in *krmv1alpha1.RestoreConfig_TransformationRuleAction) *pb.RestoreConfig_TransformationRuleAction { if in == nil { return nil } @@ -385,7 +423,7 @@ func RestoreConfig_TransformationRuleAction_ToProto(mapCtx *direct.MapContext, i out.Value = direct.ValueOf(in.Value) return out } -func RestoreConfig_VolumeDataRestorePolicyBinding_ToProto(mapCtx *direct.MapContext, in *krm.RestoreConfig_VolumeDataRestorePolicyBinding) *pb.RestoreConfig_VolumeDataRestorePolicyBinding { +func RestoreConfig_VolumeDataRestorePolicyBinding_ToProto(mapCtx *direct.MapContext, in *krmv1alpha1.RestoreConfig_VolumeDataRestorePolicyBinding) *pb.RestoreConfig_VolumeDataRestorePolicyBinding { if in == nil { return nil } @@ -396,3 +434,41 @@ func RestoreConfig_VolumeDataRestorePolicyBinding_ToProto(mapCtx *direct.MapCont } return out } +func Restore_Filter_FromProto(mapCtx *direct.MapContext, in *pb.Restore_Filter) *krmv1alpha1.Restore_Filter { + if in == nil { + return nil + } + out := &krmv1alpha1.Restore_Filter{} + out.InclusionFilters = direct.Slice_FromProto(mapCtx, in.InclusionFilters, ResourceSelector_FromProto) + out.ExclusionFilters = direct.Slice_FromProto(mapCtx, in.ExclusionFilters, ResourceSelector_FromProto) + return out +} +func Restore_Filter_ToProto(mapCtx *direct.MapContext, in *krmv1alpha1.Restore_Filter) *pb.Restore_Filter { + if in == nil { + return nil + } + out := &pb.Restore_Filter{} + out.InclusionFilters = direct.Slice_ToProto(mapCtx, in.InclusionFilters, ResourceSelector_ToProto) + out.ExclusionFilters = direct.Slice_ToProto(mapCtx, in.ExclusionFilters, ResourceSelector_ToProto) + return out +} +func VolumeDataRestorePolicyOverride_FromProto(mapCtx *direct.MapContext, in *pb.VolumeDataRestorePolicyOverride) *krmv1alpha1.VolumeDataRestorePolicyOverride { + if in == nil { + return nil + } + out := &krmv1alpha1.VolumeDataRestorePolicyOverride{} + out.Policy = direct.Enum_FromProto(mapCtx, in.GetPolicy()) + out.SelectedPvcs = NamespacedNames_FromProto(mapCtx, in.GetSelectedPvcs()) + return out +} +func VolumeDataRestorePolicyOverride_ToProto(mapCtx *direct.MapContext, in *krmv1alpha1.VolumeDataRestorePolicyOverride) *pb.VolumeDataRestorePolicyOverride { + if in == nil { + return nil + } + out := &pb.VolumeDataRestorePolicyOverride{} + out.Policy = direct.Enum_ToProto[pb.RestoreConfig_VolumeDataRestorePolicy](mapCtx, in.Policy) + if oneof := NamespacedNames_ToProto(mapCtx, in.SelectedPvcs); oneof != nil { + out.Scope = &pb.VolumeDataRestorePolicyOverride_SelectedPvcs{SelectedPvcs: oneof} + } + return out +} diff --git a/pkg/controller/direct/gkebackup/restore_fuzzer.go b/pkg/controller/direct/gkebackup/restore_fuzzer.go new file mode 100644 index 00000000000..7d788691bf4 --- /dev/null +++ b/pkg/controller/direct/gkebackup/restore_fuzzer.go @@ -0,0 +1,63 @@ +// Copyright 2025 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// +tool:fuzz-gen +// proto.message: google.cloud.gkebackup.v1.Restore +// api.group: gkebackup.cnrm.cloud.google.com + +package gkebackup + +import ( + pb "cloud.google.com/go/gkebackup/apiv1/gkebackuppb" + "github.com/GoogleCloudPlatform/k8s-config-connector/pkg/fuzztesting" +) + +func init() { + fuzztesting.RegisterKRMFuzzer(gkeBackupRestoreFuzzer()) +} + +func gkeBackupRestoreFuzzer() fuzztesting.KRMFuzzer { + f := fuzztesting.NewKRMTypedFuzzer(&pb.Restore{}, + GKEBackupRestoreSpec_FromProto, GKEBackupRestoreSpec_ToProto, + GKEBackupRestoreObservedState_FromProto, GKEBackupRestoreObservedState_ToProto, + ) + + f.UnimplementedFields.Insert(".name") // special field + + f.SpecFields.Insert(".description") + f.SpecFields.Insert(".backup") + f.SpecFields.Insert(".labels") + f.SpecFields.Insert(".filter") + f.SpecFields.Insert(".volume_data_restore_policy_overrides") + + f.StatusFields.Insert(".uid") + f.StatusFields.Insert(".create_time") + f.StatusFields.Insert(".update_time") + f.StatusFields.Insert(".cluster") + f.StatusFields.Insert(".restore_config") + f.StatusFields.Insert(".state") + f.StatusFields.Insert(".state_reason") + f.StatusFields.Insert(".complete_time") + f.StatusFields.Insert(".resources_restored_count") + f.StatusFields.Insert(".resources_excluded_count") + f.StatusFields.Insert(".resources_failed_count") + f.StatusFields.Insert(".volumes_restored_count") + f.StatusFields.Insert(".etag") + + // The default value of `.restore_config.volume_data_restore_policy_bindings.volume_type` is + // VolumeTypeEnum_VOLUME_TYPE_UNSPECIFIED, which does not roundtrip due to our Enum_FromProto implementation. + f.UnimplementedFields.Insert(".restore_config.volume_data_restore_policy_bindings") + + return f +} diff --git a/pkg/controller/direct/gkebackup/restore_mappers.go b/pkg/controller/direct/gkebackup/restore_mappers.go new file mode 100644 index 00000000000..de300e035c2 --- /dev/null +++ b/pkg/controller/direct/gkebackup/restore_mappers.go @@ -0,0 +1,79 @@ +// Copyright 2025 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package gkebackup + +import ( + pb "cloud.google.com/go/gkebackup/apiv1/gkebackuppb" + krmv1alpha1 "github.com/GoogleCloudPlatform/k8s-config-connector/apis/gkebackup/v1alpha1" + "github.com/GoogleCloudPlatform/k8s-config-connector/pkg/controller/direct" +) + +func GKEBackupRestoreObservedState_FromProto(mapCtx *direct.MapContext, in *pb.Restore) *krmv1alpha1.GKEBackupRestoreObservedState { + if in == nil { + return nil + } + out := &krmv1alpha1.GKEBackupRestoreObservedState{} + // MISSING: Name + out.UID = direct.LazyPtr(in.GetUid()) + out.CreateTime = direct.StringTimestamp_FromProto(mapCtx, in.GetCreateTime()) + out.UpdateTime = direct.StringTimestamp_FromProto(mapCtx, in.GetUpdateTime()) + out.Cluster = direct.LazyPtr(in.GetCluster()) + out.RestoreConfig = RestoreConfig_FromProto(mapCtx, in.GetRestoreConfig()) + out.State = direct.Enum_FromProto(mapCtx, in.GetState()) + out.StateReason = direct.LazyPtr(in.GetStateReason()) + out.CompleteTime = direct.StringTimestamp_FromProto(mapCtx, in.GetCompleteTime()) + out.ResourcesRestoredCount = direct.LazyPtr(in.GetResourcesRestoredCount()) + out.ResourcesExcludedCount = direct.LazyPtr(in.GetResourcesExcludedCount()) + out.ResourcesFailedCount = direct.LazyPtr(in.GetResourcesFailedCount()) + out.VolumesRestoredCount = direct.LazyPtr(in.GetVolumesRestoredCount()) + out.Etag = direct.LazyPtr(in.GetEtag()) + return out +} +func GKEBackupRestoreObservedState_ToProto(mapCtx *direct.MapContext, in *krmv1alpha1.GKEBackupRestoreObservedState) *pb.Restore { + if in == nil { + return nil + } + out := &pb.Restore{} + // MISSING: Name + out.Uid = direct.ValueOf(in.UID) + out.CreateTime = direct.StringTimestamp_ToProto(mapCtx, in.CreateTime) + out.UpdateTime = direct.StringTimestamp_ToProto(mapCtx, in.UpdateTime) + out.Cluster = direct.ValueOf(in.Cluster) + out.RestoreConfig = RestoreConfig_ToProto(mapCtx, in.RestoreConfig) + out.State = direct.Enum_ToProto[pb.Restore_State](mapCtx, in.State) + out.StateReason = direct.ValueOf(in.StateReason) + out.CompleteTime = direct.StringTimestamp_ToProto(mapCtx, in.CompleteTime) + out.ResourcesRestoredCount = direct.ValueOf(in.ResourcesRestoredCount) + out.ResourcesExcludedCount = direct.ValueOf(in.ResourcesExcludedCount) + out.ResourcesFailedCount = direct.ValueOf(in.ResourcesFailedCount) + out.VolumesRestoredCount = direct.ValueOf(in.VolumesRestoredCount) + out.Etag = direct.ValueOf(in.Etag) + return out +} +func GKEBackupRestoreSpec_FromProto(mapCtx *direct.MapContext, in *pb.Restore) *krmv1alpha1.GKEBackupRestoreSpec { + if in == nil { + return nil + } + out := &krmv1alpha1.GKEBackupRestoreSpec{} + // MISSING: Name + out.Description = direct.LazyPtr(in.GetDescription()) + if in.GetBackup() != "" { + out.BackupRef = &krmv1alpha1.BackupRef{External: in.GetBackup()} + } + out.Labels = in.Labels + out.Filter = Restore_Filter_FromProto(mapCtx, in.GetFilter()) + out.VolumeDataRestorePolicyOverrides = direct.Slice_FromProto(mapCtx, in.VolumeDataRestorePolicyOverrides, VolumeDataRestorePolicyOverride_FromProto) + return out +} diff --git a/pkg/gvks/supportedgvks/gvks_generated.go b/pkg/gvks/supportedgvks/gvks_generated.go index c73453e89bb..c56868cc868 100644 --- a/pkg/gvks/supportedgvks/gvks_generated.go +++ b/pkg/gvks/supportedgvks/gvks_generated.go @@ -3157,6 +3157,16 @@ var SupportedGVKs = map[schema.GroupVersionKind]GVKMetadata{ "cnrm.cloud.google.com/system": "true", }, }, + { + Group: "gkebackup.cnrm.cloud.google.com", + Version: "v1alpha1", + Kind: "GKEBackupRestore", + }: { + Labels: map[string]string{ + "cnrm.cloud.google.com/managed-by-kcc": "true", + "cnrm.cloud.google.com/system": "true", + }, + }, { Group: "gkehub.cnrm.cloud.google.com", Version: "v1beta1",