github.com/kyma-project/kyma/components/asset-store-controller-manager@v0.0.0-20191203152857-3792b5df17c5/internal/handler/bucket/bucket.go (about)

     1  package bucket
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"github.com/pkg/errors"
     7  	"time"
     8  
     9  	"github.com/go-logr/logr"
    10  	"github.com/kyma-project/kyma/components/asset-store-controller-manager/internal/store"
    11  	"github.com/kyma-project/kyma/components/asset-store-controller-manager/pkg/apis/assetstore/v1alpha2"
    12  	"k8s.io/apimachinery/pkg/apis/meta/v1"
    13  	"k8s.io/apimachinery/pkg/runtime"
    14  	"k8s.io/apimachinery/pkg/runtime/schema"
    15  	"k8s.io/client-go/tools/record"
    16  )
    17  
    18  type Handler interface {
    19  	Do(ctx context.Context, now time.Time, instance MetaAccessor, spec v1alpha2.CommonBucketSpec, status v1alpha2.CommonBucketStatus) (*v1alpha2.CommonBucketStatus, error)
    20  }
    21  
    22  type MetaAccessor interface {
    23  	GetNamespace() string
    24  	GetName() string
    25  	GetGeneration() int64
    26  	GetDeletionTimestamp() *v1.Time
    27  	GetFinalizers() []string
    28  	SetFinalizers(finalizers []string)
    29  	GetObjectKind() schema.ObjectKind
    30  	DeepCopyObject() runtime.Object
    31  }
    32  
    33  var _ Handler = &bucketHandler{}
    34  
    35  type bucketHandler struct {
    36  	recorder         record.EventRecorder
    37  	store            store.Store
    38  	externalEndpoint string
    39  	log              logr.Logger
    40  	relistInterval   time.Duration
    41  }
    42  
    43  func New(log logr.Logger, recorder record.EventRecorder, store store.Store, externalEndpoint string, relistInterval time.Duration) Handler {
    44  	return &bucketHandler{
    45  		recorder:         recorder,
    46  		store:            store,
    47  		externalEndpoint: externalEndpoint,
    48  		log:              log,
    49  		relistInterval:   relistInterval,
    50  	}
    51  }
    52  
    53  func (h *bucketHandler) Do(ctx context.Context, now time.Time, instance MetaAccessor, spec v1alpha2.CommonBucketSpec, status v1alpha2.CommonBucketStatus) (*v1alpha2.CommonBucketStatus, error) {
    54  	h.logInfof("Start common Bucket handling")
    55  	defer h.logInfof("Finish common Bucket handling")
    56  
    57  	switch {
    58  	case h.isOnDelete(instance):
    59  		return h.onDelete(ctx, instance, status)
    60  	case h.isOnAddOrUpdate(instance, status):
    61  		return h.onAddOrUpdate(instance, spec, status)
    62  	case h.isOnReady(status, now):
    63  		return h.onReady(instance, spec, status)
    64  	case h.isOnFailed(status):
    65  		return h.onFailed(instance, spec, status)
    66  	default:
    67  		h.logInfof("Action not taken")
    68  		return nil, nil
    69  	}
    70  }
    71  
    72  func (h *bucketHandler) isOnReady(status v1alpha2.CommonBucketStatus, now time.Time) bool {
    73  	return status.Phase == v1alpha2.BucketReady && now.After(status.LastHeartbeatTime.Add(h.relistInterval))
    74  }
    75  
    76  func (*bucketHandler) isOnAddOrUpdate(object MetaAccessor, status v1alpha2.CommonBucketStatus) bool {
    77  	return status.ObservedGeneration != object.GetGeneration()
    78  }
    79  
    80  func (*bucketHandler) isOnFailed(status v1alpha2.CommonBucketStatus) bool {
    81  	return status.Phase == v1alpha2.BucketFailed
    82  }
    83  
    84  func (*bucketHandler) isOnDelete(object MetaAccessor) bool {
    85  	return !object.GetDeletionTimestamp().IsZero()
    86  }
    87  
    88  func (h *bucketHandler) onFailed(object MetaAccessor, spec v1alpha2.CommonBucketSpec, status v1alpha2.CommonBucketStatus) (*v1alpha2.CommonBucketStatus, error) {
    89  	switch status.Reason {
    90  	case v1alpha2.BucketNotFound:
    91  		return h.onAddOrUpdate(object, spec, status)
    92  	case v1alpha2.BucketCreationFailure:
    93  		return h.onAddOrUpdate(object, spec, status)
    94  	case v1alpha2.BucketVerificationFailure:
    95  		return h.onReady(object, spec, status)
    96  	case v1alpha2.BucketPolicyUpdateFailed:
    97  		return h.onReady(object, spec, status)
    98  	}
    99  
   100  	return nil, nil
   101  }
   102  
   103  func (h *bucketHandler) onReady(object MetaAccessor, spec v1alpha2.CommonBucketSpec, status v1alpha2.CommonBucketStatus) (*v1alpha2.CommonBucketStatus, error) {
   104  	h.logInfof("Checking if bucket exists")
   105  	exists, err := h.store.BucketExists(status.RemoteName)
   106  	if err != nil {
   107  		h.recordWarningEventf(object, v1alpha2.BucketVerificationFailure, err.Error())
   108  		return h.getStatus(object, status.RemoteName, status.URL, v1alpha2.BucketFailed, v1alpha2.BucketVerificationFailure, err.Error()), err
   109  	}
   110  	if !exists {
   111  		h.recordWarningEventf(object, v1alpha2.BucketNotFound, status.RemoteName)
   112  		return h.getStatus(object, "", "", v1alpha2.BucketFailed, v1alpha2.BucketNotFound, status.RemoteName), errors.Errorf(v1alpha2.BucketNotFound.String(), status.RemoteName)
   113  	}
   114  	h.logInfof("Bucket exists")
   115  
   116  	h.logInfof("Comparing bucket policy")
   117  	equal, err := h.store.CompareBucketPolicy(status.RemoteName, spec.Policy)
   118  	if err != nil {
   119  		h.recordWarningEventf(object, v1alpha2.BucketPolicyVerificationFailed, err.Error())
   120  		return h.getStatus(object, status.RemoteName, status.URL, v1alpha2.BucketFailed, v1alpha2.BucketPolicyVerificationFailed, status.RemoteName), err
   121  	}
   122  	if equal {
   123  		h.logInfof("Bucket is up-to-date")
   124  		return h.getStatus(object, status.RemoteName, status.URL, v1alpha2.BucketReady, v1alpha2.BucketPolicyUpdated), nil
   125  	}
   126  
   127  	h.logInfof("Updating bucket policy")
   128  	h.recordWarningEventf(object, v1alpha2.BucketPolicyHasBeenChanged)
   129  	if err := h.store.SetBucketPolicy(status.RemoteName, spec.Policy); err != nil {
   130  		h.recordWarningEventf(object, v1alpha2.BucketPolicyUpdateFailed, err.Error())
   131  		return h.getStatus(object, status.RemoteName, status.URL, v1alpha2.BucketFailed, v1alpha2.BucketPolicyUpdateFailed, err.Error()), err
   132  	}
   133  	h.recordNormalEventf(object, v1alpha2.BucketPolicyUpdated)
   134  	h.logInfof("Bucket policy updated")
   135  
   136  	return h.getStatus(object, status.RemoteName, status.URL, v1alpha2.BucketReady, v1alpha2.BucketPolicyUpdated), nil
   137  }
   138  
   139  func (h *bucketHandler) onAddOrUpdate(object MetaAccessor, spec v1alpha2.CommonBucketSpec, status v1alpha2.CommonBucketStatus) (*v1alpha2.CommonBucketStatus, error) {
   140  	h.logInfof("Checking if bucket was previously created")
   141  	if status.RemoteName != "" {
   142  		h.logInfof("Bucket was created")
   143  		return h.onReady(object, spec, status)
   144  	}
   145  
   146  	h.logInfof("Creating bucket")
   147  	remoteName, err := h.store.CreateBucket(object.GetNamespace(), object.GetName(), string(spec.Region))
   148  	if err != nil {
   149  		h.recordWarningEventf(object, v1alpha2.BucketCreationFailure, err.Error())
   150  		return h.getStatus(object, "", "", v1alpha2.BucketFailed, v1alpha2.BucketCreationFailure, err.Error()), err
   151  	}
   152  	h.recordNormalEventf(object, v1alpha2.BucketCreated)
   153  	h.logInfof("Bucket created")
   154  
   155  	externalUrl := h.getBucketUrl(remoteName)
   156  
   157  	h.logInfof("Updating bucket policy")
   158  	if err := h.store.SetBucketPolicy(remoteName, spec.Policy); err != nil {
   159  		h.recordWarningEventf(object, v1alpha2.BucketPolicyUpdateFailed, err.Error())
   160  		return h.getStatus(object, remoteName, externalUrl, v1alpha2.BucketFailed, v1alpha2.BucketPolicyUpdateFailed, err.Error()), err
   161  	}
   162  	h.recordNormalEventf(object, v1alpha2.BucketPolicyUpdated)
   163  	h.logInfof("Bucket policy updated")
   164  
   165  	return h.getStatus(object, remoteName, externalUrl, v1alpha2.BucketReady, v1alpha2.BucketPolicyUpdated), nil
   166  }
   167  
   168  func (h *bucketHandler) onDelete(ctx context.Context, object MetaAccessor, status v1alpha2.CommonBucketStatus) (*v1alpha2.CommonBucketStatus, error) {
   169  	h.logInfof("Deleting Bucket")
   170  	if status.RemoteName == "" || status.Reason == v1alpha2.BucketNotFound {
   171  		h.logInfof("Nothing to delete, there is no remote bucket")
   172  		return nil, nil
   173  	}
   174  
   175  	if err := h.store.DeleteBucket(ctx, status.RemoteName); err != nil {
   176  		return nil, errors.Wrap(err, "while deleting remote bucket")
   177  	}
   178  	h.logInfof("Remote bucket %s deleted", status.RemoteName)
   179  
   180  	return nil, nil
   181  }
   182  
   183  func (h *bucketHandler) getBucketUrl(name string) string {
   184  	return fmt.Sprintf("%s/%s", h.externalEndpoint, name)
   185  }
   186  
   187  func (h *bucketHandler) recordNormalEventf(object MetaAccessor, reason v1alpha2.BucketReason, args ...interface{}) {
   188  	h.recordEventf(object, "Normal", reason, args...)
   189  }
   190  
   191  func (h *bucketHandler) recordWarningEventf(object MetaAccessor, reason v1alpha2.BucketReason, args ...interface{}) {
   192  	h.recordEventf(object, "Warning", reason, args...)
   193  }
   194  
   195  func (h *bucketHandler) logInfof(message string, args ...interface{}) {
   196  	h.log.Info(fmt.Sprintf(message, args...))
   197  }
   198  
   199  func (h *bucketHandler) recordEventf(object MetaAccessor, eventType string, reason v1alpha2.BucketReason, args ...interface{}) {
   200  	h.recorder.Eventf(object, eventType, reason.String(), reason.Message(), args...)
   201  }
   202  
   203  func (*bucketHandler) getStatus(object MetaAccessor, remoteName, url string, phase v1alpha2.BucketPhase, reason v1alpha2.BucketReason, args ...interface{}) *v1alpha2.CommonBucketStatus {
   204  	return &v1alpha2.CommonBucketStatus{
   205  		LastHeartbeatTime:  v1.Now(),
   206  		ObservedGeneration: object.GetGeneration(),
   207  		Phase:              phase,
   208  		RemoteName:         remoteName,
   209  		URL:                url,
   210  		Reason:             reason,
   211  		Message:            fmt.Sprintf(reason.Message(), args...),
   212  	}
   213  }