Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions PROJECT
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,13 @@ resources:
kind: MustGather
path: github.com/openshift/must-gather-operator/api/v1alpha1
version: v1alpha1
- api:
crdVersion: v1
namespaced: true
controller: true
domain: openshift.io
group: operator
kind: MustGather
path: github.com/openshift/must-gather-operator/api/v1
version: v1
version: "3"
36 changes: 36 additions & 0 deletions api/v1/groupversion_info.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*
Copyright 2022.

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 v1 contains API Schema definitions for the operator v1 API group
// +kubebuilder:object:generate=true
// +groupName=operator.openshift.io
package v1

import (
"k8s.io/apimachinery/pkg/runtime/schema"
"sigs.k8s.io/controller-runtime/pkg/scheme"
)

var (
// GroupVersion is group version used to register these objects
GroupVersion = schema.GroupVersion{Group: "operator.openshift.io", Version: "v1"}

// SchemeBuilder is used to add go types to the GroupVersionKind scheme
SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion}

// AddToScheme adds the types in this group-version to the given scheme.
AddToScheme = SchemeBuilder.AddToScheme
)
250 changes: 250 additions & 0 deletions api/v1/mustgather_types.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,250 @@
/*
Copyright 2022.

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 v1

import (
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

// MustGatherSpec defines the desired state of MustGather
// +kubebuilder:validation:XValidation:rule="!(has(self.imageStreamRef) && has(self.gatherSpec) && has(self.gatherSpec.audit) && self.gatherSpec.audit)",message="audit mode is only supported with the default must-gather image"
// +kubebuilder:validation:XValidation:rule="!(!has(self.imageStreamRef) && has(self.gatherSpec) && has(self.gatherSpec.command) && size(self.gatherSpec.command) > 0 && has(self.gatherSpec.audit) && self.gatherSpec.audit)",message="audit mode cannot be combined with custom gather commands"
type MustGatherSpec struct {
// ServiceAccountName is the name of the ServiceAccount to use for running the must-gather Job.
// This field is required and must reference a ServiceAccount with sufficient RBAC permissions
// to collect cluster data. The operator will verify the ServiceAccount exists before creating the Job.
// +kubebuilder:validation:Required
// +kubebuilder:validation:MinLength=1
ServiceAccountName string `json:"serviceAccountName"`

// ImageStreamRef specifies a custom image from the allowlist to be used for the
// must-gather run.
// +kubebuilder:validation:Optional
ImageStreamRef *ImageStreamTagRef `json:"imageStreamRef,omitempty"`

// GatherSpec allows overriding the command and/or arguments for the must-gather container
// (default or custom image from imageStreamRef) and configures time-based collection filters.
// Time-based filters (since, sinceTime) apply regardless of imageStreamRef.
// Audit is only allowed with the default image and default gather command (see CRD validation rules).
// +kubebuilder:validation:Optional
GatherSpec *GatherSpec `json:"gatherSpec,omitempty"`

// A time limit for gather command to complete a floating point number with a suffix:
// "s" for seconds, "m" for minutes, "h" for hours.
// Will default to no time limit.
// +kubebuilder:validation:Optional
// +kubebuilder:validation:Format=duration
MustGatherTimeout *metav1.Duration `json:"mustGatherTimeout,omitempty"`

// The target location for the must-gather bundle to be uploaded to.
// If not specified, the bundle will not be uploaded.
// +kubebuilder:validation:Optional
UploadTarget *UploadTargetSpec `json:"uploadTarget,omitempty"`

// A flag to specify if resources (secret, job, pods) should be retained when the MustGather completes.
// If set to true, resources will be retained. If false or not set, resources will be deleted (default behavior).
// +kubebuilder:default:=false
RetainResourcesOnCompletion *bool `json:"retainResourcesOnCompletion,omitempty"`

// The storage configuration for persisting the collected must-gather tar archive.
// If not specified, an ephemeral volume is used which will not persist
// the tar archive on the cluster.
// +optional
Storage *Storage `json:"storage,omitempty"`
}

// GatherSpec allows specifying the execution details for a must-gather run and the collection behavior.
// +kubebuilder:validation:XValidation:rule="!(has(self.since) && has(self.sinceTime))",message="only one of since or sinceTime may be specified"
type GatherSpec struct {
// +kubebuilder:validation:Optional
// Audit requests audit log collection via the default gather entrypoint.
// It must be false when imageStreamRef is set or when gatherSpec.command is set without imageStreamRef.
Audit bool `json:"audit,omitempty"`

// +kubebuilder:validation:Optional
// Command is a string array representing the container entrypoint.
// When set, it replaces the default gather wrapper for both the default must-gather image and custom images.
// +kubebuilder:validation:MaxItems=256
// +kubebuilder:validation:Items:MaxLength=256
Command []string `json:"command,omitempty"`

// +kubebuilder:validation:Optional
// Args is a string array of arguments passed to the container command.
// +kubebuilder:validation:MaxItems=256
// +kubebuilder:validation:Items:MaxLength=256
Args []string `json:"args,omitempty"`

// Since only returns logs newer than a relative duration like "2h" or "30m".
// This is passed to the must-gather script to filter log collection.
// Only one of since or sinceTime may be specified.
// +kubebuilder:validation:Optional
// +kubebuilder:validation:Format=duration
Since *metav1.Duration `json:"since,omitempty"`

// SinceTime only returns logs after a specific date/time (RFC3339 format).
// This is passed to the must-gather script to filter log collection.
// Only one of since or sinceTime may be specified.
// +kubebuilder:validation:Optional
// +kubebuilder:validation:Format=date-time
SinceTime *metav1.Time `json:"sinceTime,omitempty"`
}

// ImageStreamTagRef provides a structured reference to a specific tag within an ImageStream.
type ImageStreamTagRef struct {
// +kubebuilder:validation:Required
// Name is the name of the ImageStream resource in the operator's namespace.
Name string `json:"name"`

// +kubebuilder:validation:Required
// Tag is the name of the tag within the ImageStream.
Tag string `json:"tag"`
}

// SFTPSpec defines the desired state of SFTPSpec
// +kubebuilder:validation:XValidation:rule="size(self.caseID) > 0",message="caseID must not be empty"
// +kubebuilder:validation:XValidation:rule="size(self.caseManagementAccountSecretRef.name) > 0",message="caseManagementAccountSecretRef.name must not be empty"
type SFTPSpec struct {
// The ID of the case this must gather will be uploaded to
// +kubebuilder:validation:Required
CaseID string `json:"caseID"`

// the secret container a username and password field to be used to authenticate with red hat case management systems
// +kubebuilder:validation:Required
CaseManagementAccountSecretRef corev1.LocalObjectReference `json:"caseManagementAccountSecretRef"`

// A flag to specify if the upload user provided in the caseManagementAccountSecret is a RH internal user.
// See documentation for further information.
// +kubebuilder:default:=false
InternalUser bool `json:"internalUser,omitempty"`

// host specifies the SFTP server hostname.
// The host name of the SFTP server
// +kubebuilder:default:="sftp.access.redhat.com"
// +optional
Host string `json:"host,omitempty"`
}

// UploadType defines the type of upload target.
type UploadType string

const (
// UploadTypeSFTP corresponds to the SFTP upload type.
UploadTypeSFTP UploadType = "SFTP"
)

// UploadTargetSpec defines the desired state of UploadTargetSpec
// +kubebuilder:validation:XValidation:rule="has(self.type) && self.type == 'SFTP' ? has(self.sftp) : !has(self.sftp)",message="sftp upload target config is required when upload type is SFTP, and forbidden otherwise"
// +union
type UploadTargetSpec struct {
// type defines the method used for uploading to a specific target.
// +unionDiscriminator
// +kubebuilder:validation:Required
// +kubebuilder:validation:Enum=SFTP
// +required
Type UploadType `json:"type"`

// SFTP details for the upload.
// +unionMember
// +optional
SFTP *SFTPSpec `json:"sftp,omitempty"`
}

// StorageType defines the type of storage to use for the must-gather collection.
// +kubebuilder:validation:Enum=PersistentVolume
type StorageType string

const (
// StorageTypePersistentVolume corresponds to the PersistentVolume storage type.
StorageTypePersistentVolume StorageType = "PersistentVolume"
)

// Storage defines the desired state of Storage
type Storage struct {
// type defines the type of storage to use.
// Available storage types are PersistentVolume only.
// +required
Type StorageType `json:"type"`
// persistentVolume defines the configuration for a PersistentVolume.
// +required
PersistentVolume PersistentVolumeConfig `json:"persistentVolume"`
}

// PersistentVolumeConfig defines the configuration for a PersistentVolume.
type PersistentVolumeConfig struct {
// claim defines the PersistentVolumeClaim to use.
// +required
Claim PersistentVolumeClaimReference `json:"claim"`
// subPath defines the path to a sub directory within the PersistentVolume to use.
// +optional
SubPath string `json:"subPath,omitempty"`
}

// PersistentVolumeClaimReference defines the reference to a PersistentVolumeClaim.
type PersistentVolumeClaimReference struct {
// name defines the PersistentVolumeClaim to use,
// should be already present in the same namespace.
// +kubebuilder:validation:MaxLength=253
// +kubebuilder:validation:XValidation:rule="!format.dns1123Subdomain().validate(self).hasValue()",message="a lowercase RFC 1123 subdomain must consist of lower case alphanumeric characters, '-' or '.', and must start and end with an alphanumeric character."
// +required
Name string `json:"name"`
}

// MustGatherStatus defines the observed state of MustGather
type MustGatherStatus struct {
Status string `json:"status,omitempty"`
LastUpdate metav1.Time `json:"lastUpdate,omitempty"`
Reason string `json:"reason,omitempty"`
Conditions []metav1.Condition `json:"conditions,omitempty" patchStrategy:"merge" patchMergeKey:"type"`
Completed bool `json:"completed"`
}

func (m *MustGather) GetConditions() []metav1.Condition {
return m.Status.Conditions
}

func (m *MustGather) SetConditions(conditions []metav1.Condition) {
m.Status.Conditions = conditions
}

//+kubebuilder:object:root=true
//+kubebuilder:subresource:status
//+kubebuilder:storageversion

// MustGather is the Schema for the mustgathers API
// +kubebuilder:validation:XValidation:rule="!has(oldSelf.spec) || self.spec == oldSelf.spec",message="spec values are immutable once set"
type MustGather struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`

// +kubebuilder:validation:Required
Spec MustGatherSpec `json:"spec"`
Status MustGatherStatus `json:"status,omitempty"`
}

//+kubebuilder:object:root=true

// MustGatherList contains a list of MustGather
type MustGatherList struct {
metav1.TypeMeta `json:",inline"`
metav1.ListMeta `json:"metadata,omitempty"`
Items []MustGather `json:"items"`
}

func init() {
SchemeBuilder.Register(&MustGather{}, &MustGatherList{})
}
Loading