diff --git a/OWNERS b/OWNERS index 9ea2b344..09cf511f 100644 --- a/OWNERS +++ b/OWNERS @@ -6,5 +6,7 @@ approvers: - saad-ali - xing-yang - wlan0 - - brahmaroutu - - rrati + - mukhoakash + - BlaineEXE + - shanduur + diff --git a/README.md b/README.md index dec59e69..e73a2f00 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ -![version](https://img.shields.io/badge/status-pre--alpha-lightgrey) ![apiVersion](https://img.shields.io/badge/apiVersion-v1alpha1-lightgreen) +# MOVED: **This repo has been moved to https://github.com/kubernetes-sigs/container-object-storage-interface : see `client` directory** + +![version](https://img.shields.io/badge/status-pre--alpha-lightgrey) ![apiVersion](https://img.shields.io/badge/apiVersion-v1alpha1-lightgreen) # Container Object Storage Interface API diff --git a/apis/bucket_info.go b/apis/bucket_info.go index ff1dee4d..c5717ffb 100644 --- a/apis/bucket_info.go +++ b/apis/bucket_info.go @@ -30,7 +30,7 @@ type SecretS3 struct { } type SecretAzure struct { - AccessToken string `json:"acessToken"` + AccessToken string `json:"accessToken"` ExpiryTimeStamp *metav1.Time `json:"expiryTimeStamp"` } diff --git a/apis/objectstorage/v1alpha1/types.go b/apis/objectstorage/v1alpha1/types.go index 44c2be41..1519ccc9 100644 --- a/apis/objectstorage/v1alpha1/types.go +++ b/apis/objectstorage/v1alpha1/types.go @@ -33,8 +33,8 @@ func init() { type DeletionPolicy string const ( - DeletionPolicyRetain DeletionPolicy = "Retain" - DeletionPolicyDelete DeletionPolicy = "Delete" + DeletionPolicyRetain DeletionPolicy = "Retain" + DeletionPolicyDelete DeletionPolicy = "Delete" ) type Protocol string @@ -60,8 +60,8 @@ const ( // +kubebuilder:subresource:status type Bucket struct { metav1.TypeMeta `json:",inline"` - // +optional + // +optional metav1.ObjectMeta `json:"metadata,omitempty"` Spec BucketSpec `json:"spec,omitempty"` @@ -77,7 +77,7 @@ type BucketSpec struct { // Name of the BucketClass specified in the BucketRequest BucketClassName string `json:"bucketClassName"` - // Name of the BucketClaim that resulted in the creation of this Bucket + // Name of the BucketClaim that resulted in the creation of this Bucket // In case the Bucket object was created manually, then this should refer // to the BucketClaim with which this Bucket should be bound BucketClaim *corev1.ObjectReference `json:"bucketClaim"` @@ -98,7 +98,7 @@ type BucketSpec struct { // - Delete: Indicates that the bucket should be deleted from the OSP // once all the workloads accessing this bucket are done // +optional - // +kubebuilder:default:=retain + // +kubebuilder:default:=Retain DeletionPolicy DeletionPolicy `json:"deletionPolicy"` // ExistingBucketID is the unique id of the bucket in the OSP. This field should be @@ -120,7 +120,6 @@ type BucketStatus struct { } // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object - type BucketList struct { metav1.TypeMeta `json:",inline"` metav1.ListMeta `json:"metadata,omitempty"` @@ -134,8 +133,8 @@ type BucketList struct { // +kubebuilder:storageversion type BucketClaim struct { metav1.TypeMeta `json:",inline"` - // +optional + // +optional metav1.ObjectMeta `json:"metadata,omitempty"` Spec BucketClaimSpec `json:"spec,omitempty"` @@ -168,14 +167,13 @@ type BucketClaimStatus struct { BucketReady bool `json:"bucketReady"` // BucketName is the name of the provisioned Bucket in response - // to this BucketClaim. It is generated and set by the COSI controller + // to this BucketClaim. It is generated and set by the COSI controller // before making the creation request to the OSP backend. // +optional BucketName string `json:"bucketName,omitempty"` } // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object - type BucketClaimList struct { metav1.TypeMeta `json:",inline"` metav1.ListMeta `json:"metadata,omitempty"` @@ -202,7 +200,7 @@ type BucketClass struct { // - Retain: Indicates that the bucket should not be deleted from the OSP // - Delete: Indicates that the bucket should be deleted from the OSP // once all the workloads accessing this bucket are done - // +kubebuilder:default:=retain + // +kubebuilder:default:=Retain DeletionPolicy DeletionPolicy `json:"deletionPolicy"` // Parameters is an opaque map for passing in configuration to a driver @@ -212,7 +210,6 @@ type BucketClass struct { } // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object - type BucketClassList struct { metav1.TypeMeta `json:",inline"` metav1.ListMeta `json:"metadata,omitempty"` @@ -237,7 +234,7 @@ type BucketAccessClass struct { // AuthenticationType denotes the style of authentication // It can be one of - // KEY - access, secret tokens based authentication + // Key - access, secret tokens based authentication // IAM - implicit authentication of pods to the OSP based on service account mappings AuthenticationType AuthenticationType `json:"authenticationType"` @@ -276,11 +273,11 @@ type BucketAccessSpec struct { // BucketClaimName is the name of the BucketClaim. BucketClaimName string `json:"bucketClaimName"` - // Protocol is the name of the Protocol + // Protocol is the name of the Protocol // that this access credential is supposed to support // If left empty, it will choose the protocol supported // by the bucket. If the bucket supports multiple protocols, - // the end protocol is determined by the driver. + // the end protocol is determined by the driver. // +optional Protocol Protocol `json:"protocol,omitempty"` @@ -317,4 +314,3 @@ type BucketAccessList struct { metav1.ListMeta `json:"metadata,omitempty"` Items []BucketAccess `json:"items"` } - diff --git a/controller/controller.go b/controller/controller.go index c44b7875..5c698d4e 100644 --- a/controller/controller.go +++ b/controller/controller.go @@ -3,7 +3,6 @@ package controller import ( "context" "fmt" - "io/ioutil" "os" "reflect" "regexp" @@ -81,17 +80,20 @@ type ObjectStorageController struct { RenewDeadline time.Duration RetryPeriod time.Duration + eventBroadcaster record.EventBroadcaster + eventRecorder record.EventRecorder + // Controller ResyncPeriod time.Duration queue workqueue.RateLimitingInterface threadiness int // Listeners - BucketListener BucketListener - BucketClaimListener BucketClaimListener - BucketAccessListener BucketAccessListener - BucketClassListener BucketClassListener - BucketAccessClassListener BucketAccessClassListener + BucketListener BucketListener + BucketClaimListener BucketClaimListener + BucketAccessListener BucketAccessListener + BucketClassListener BucketClassListener + BucketAccessClassListener BucketAccessClassListener // leader election leaderLock string @@ -148,7 +150,17 @@ func NewObjectStorageControllerWithClientset(identity string, leaderLockName str } } + rb := record.NewBroadcaster() + + extendedScheme := scheme.Scheme + if err := v1alpha1.AddToScheme(extendedScheme); err != nil { + return nil, err + } + return &ObjectStorageController{ + eventBroadcaster: rb, + eventRecorder: rb.NewRecorder(extendedScheme, v1.EventSource{Component: id}), + identity: id, kubeClient: kubeClient, bucketClient: bucketClient, @@ -178,7 +190,7 @@ func (c *ObjectStorageController) Run(ctx context.Context) error { return ns } - if data, err := ioutil.ReadFile("/var/run/secrets/kubernetes.io/serviceaccount/namespace"); err == nil { + if data, err := os.ReadFile("/var/run/secrets/kubernetes.io/serviceaccount/namespace"); err == nil { if ns := strings.TrimSpace(string(data)); len(ns) > 0 { return ns } @@ -186,31 +198,20 @@ func (c *ObjectStorageController) Run(ctx context.Context) error { return "default" }() - sanitize := func(n string) string { - re := regexp.MustCompile("[^a-zA-Z0-9-]") - name := strings.ToLower(re.ReplaceAllString(n, "-")) - if name[len(name)-1] == '-' { - // name must not end with '-' - name = name + "X" - } - return name - } - - leader := sanitize(fmt.Sprintf("%s/%s", c.leaderLock, c.identity)) id, err := os.Hostname() if err != nil { return fmt.Errorf("error getting the default leader identity: %v", err) } - recorder := record.NewBroadcaster() - recorder.StartRecordingToSink(&corev1.EventSinkImpl{Interface: c.kubeClient.CoreV1().Events(ns)}) - eRecorder := recorder.NewRecorder(scheme.Scheme, v1.EventSource{Component: leader}) + c.eventBroadcaster.StartRecordingToSink(&corev1.EventSinkImpl{Interface: c.kubeClient.CoreV1().Events(ns)}) + defer c.eventBroadcaster.Shutdown() rlConfig := resourcelock.ResourceLockConfig{ Identity: sanitize(id), - EventRecorder: eRecorder, + EventRecorder: c.eventRecorder, } + leader := sanitize(fmt.Sprintf("%s/%s", c.leaderLock, c.identity)) l, err := resourcelock.New(resourcelock.LeasesResourceLock, ns, leader, c.kubeClient.CoreV1(), c.kubeClient.CoordinationV1(), rlConfig) if err != nil { return err @@ -423,6 +424,7 @@ func (c *ObjectStorageController) runController(ctx context.Context) { if c.BucketListener != nil { c.BucketListener.InitializeKubeClient(c.kubeClient) c.BucketListener.InitializeBucketClient(c.bucketClient) + c.BucketListener.InitializeEventRecorder(c.eventRecorder) addFunc := func(ctx context.Context, obj interface{}) error { return c.BucketListener.Add(ctx, obj.(*v1alpha1.Bucket)) } @@ -437,6 +439,7 @@ func (c *ObjectStorageController) runController(ctx context.Context) { if c.BucketClaimListener != nil { c.BucketClaimListener.InitializeKubeClient(c.kubeClient) c.BucketClaimListener.InitializeBucketClient(c.bucketClient) + c.BucketClaimListener.InitializeEventRecorder(c.eventRecorder) addFunc := func(ctx context.Context, obj interface{}) error { return c.BucketClaimListener.Add(ctx, obj.(*v1alpha1.BucketClaim)) } @@ -451,6 +454,7 @@ func (c *ObjectStorageController) runController(ctx context.Context) { if c.BucketAccessListener != nil { c.BucketAccessListener.InitializeKubeClient(c.kubeClient) c.BucketAccessListener.InitializeBucketClient(c.bucketClient) + c.BucketAccessListener.InitializeEventRecorder(c.eventRecorder) addFunc := func(ctx context.Context, obj interface{}) error { return c.BucketAccessListener.Add(ctx, obj.(*v1alpha1.BucketAccess)) } @@ -465,6 +469,7 @@ func (c *ObjectStorageController) runController(ctx context.Context) { if c.BucketClassListener != nil { c.BucketClassListener.InitializeKubeClient(c.kubeClient) c.BucketClassListener.InitializeBucketClient(c.bucketClient) + c.BucketClassListener.InitializeEventRecorder(c.eventRecorder) addFunc := func(ctx context.Context, obj interface{}) error { return c.BucketClassListener.Add(ctx, obj.(*v1alpha1.BucketClass)) } @@ -479,6 +484,7 @@ func (c *ObjectStorageController) runController(ctx context.Context) { if c.BucketAccessClassListener != nil { c.BucketAccessClassListener.InitializeKubeClient(c.kubeClient) c.BucketAccessClassListener.InitializeBucketClient(c.bucketClient) + c.BucketAccessClassListener.InitializeEventRecorder(c.eventRecorder) addFunc := func(ctx context.Context, obj interface{}) error { return c.BucketAccessClassListener.Add(ctx, obj.(*v1alpha1.BucketAccessClass)) } @@ -493,3 +499,13 @@ func (c *ObjectStorageController) runController(ctx context.Context) { <-ctx.Done() } + +func sanitize(n string) string { + re := regexp.MustCompile("[^a-zA-Z0-9-]") + name := strings.ToLower(re.ReplaceAllString(n, "-")) + if name[len(name)-1] == '-' { + // name must not end with '-' + name = name + "X" + } + return name +} diff --git a/controller/events/events.go b/controller/events/events.go new file mode 100644 index 00000000..a30e4521 --- /dev/null +++ b/controller/events/events.go @@ -0,0 +1,11 @@ +package events + +// COSI relevant event reasons +const ( + FailedCreateBucket = "FailedCreateBucket" + FailedDeleteBucket = "FailedDeleteBucket" + WaitingForBucket = "WaitingForBucket" + + FailedGrantAccess = "FailedGrantAccess" + FailedRevokeAccess = "FailedRevokeAccess" +) diff --git a/controller/interfaces.go b/controller/interfaces.go index 366adb21..d3d34e88 100644 --- a/controller/interfaces.go +++ b/controller/interfaces.go @@ -9,12 +9,14 @@ import ( // k8s client kubeclientset "k8s.io/client-go/kubernetes" + "k8s.io/client-go/tools/record" ) // Set the clients for each of the listeners type GenericListener interface { InitializeKubeClient(kubeclientset.Interface) InitializeBucketClient(bucketclientset.Interface) + InitializeEventRecorder(record.EventRecorder) } type BucketListener interface { diff --git a/crds/objectstorage.k8s.io_bucketaccessclasses.yaml b/crds/objectstorage.k8s.io_bucketaccessclasses.yaml index e21e3c53..07d27bb5 100644 --- a/crds/objectstorage.k8s.io_bucketaccessclasses.yaml +++ b/crds/objectstorage.k8s.io_bucketaccessclasses.yaml @@ -26,7 +26,7 @@ spec: type: string authenticationType: description: AuthenticationType denotes the style of authentication It - can be one of KEY - access, secret tokens based authentication IAM - + can be one of Key - access, secret tokens based authentication IAM - implicit authentication of pods to the OSP based on service account mappings type: string diff --git a/crds/objectstorage.k8s.io_bucketclasses.yaml b/crds/objectstorage.k8s.io_bucketclasses.yaml index bb2c5bd7..b5836c22 100644 --- a/crds/objectstorage.k8s.io_bucketclasses.yaml +++ b/crds/objectstorage.k8s.io_bucketclasses.yaml @@ -25,7 +25,7 @@ spec: internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' type: string deletionPolicy: - default: retain + default: Retain description: 'DeletionPolicy is used to specify how COSI should handle deletion of this bucket. There are 2 possible values: - Retain: Indicates that the bucket should not be deleted from the OSP - Delete: Indicates diff --git a/crds/objectstorage.k8s.io_buckets.yaml b/crds/objectstorage.k8s.io_buckets.yaml index a4b8c712..a1df592c 100644 --- a/crds/objectstorage.k8s.io_buckets.yaml +++ b/crds/objectstorage.k8s.io_buckets.yaml @@ -77,7 +77,7 @@ spec: description: Name of the BucketClass specified in the BucketRequest type: string deletionPolicy: - default: retain + default: Retain description: 'DeletionPolicy is used to specify how COSI should handle deletion of this bucket. There are 2 possible values: - Retain: Indicates that the bucket should not be deleted from the OSP (default)