Uploaded image for project: 'OpenShift CFE'
  1. OpenShift CFE
  2. CFE-919

Add support for tags in gcp-filestore-csi-driver

XMLWordPrintable

    • Icon: Story Story
    • Resolution: Done
    • Icon: Normal Normal
    • openshift-4.17
    • openshift-4.15
    • None
    • None
    • BU Product Work
    • 8
    • False
    • None
    • False
    • OCPSTRAT-768 - Apply user defined tags to all resources created by OpenShift (GCP) GA
    • CFE Sprint 242, CFE Sprint 243, CFE Sprint 244, CFE Sprint 245, CFE Sprint 246, CFE Sprint 247, CFE Sprint 252, CFE Sprint 253

      Issue(Feature Request): https://github.com/kubernetes-sigs/gcp-filestore-csi-driver/issues/567

      Driver should be added with the functionality to accept user-defined tags as process arguments and these tags must be added to the resources managed by the driver i.e. Filestore Instances.
      Adding tags to a resource in controlled through quota and hence the implementation should have logic for proactively limiting request rate and to retry to quota exceeded error, and also should have handling for ignoring already exist error.

      import "golang.org/x/time/rate"
      
      // newLimiter returns token bucket based request rate limiter after initializing
      // the passed values for limit, burst(or token bucket) size. If opted for emptyBucket
      // all initial tokens are reserved for the first burst.
      func newLimiter(limit, burst int, emptyBucket bool) *rate.Limiter {
      	limiter := rate.NewLimiter(rate.Every(time.Second/time.Duration(limit)), burst)
      
      	if emptyBucket {
      		limiter.AllowN(time.Now(), burst)
      	}
      
      	return limiter
      }
      
      import (
      	rscmgr "cloud.google.com/go/resourcemanager/apiv3"
      	rscmgrpb "cloud.google.com/go/resourcemanager/apiv3/resourcemanagerpb"
      	"github.com/googleapis/gax-go/v2"
      	"github.com/googleapis/gax-go/v2/apierror"
      	"google.golang.org/api/iterator"
      	"google.golang.org/api/option"
      )
      
      // getCreateCallOptions returns a list of additional call options to use for
      // the create operations.
      func getCreateCallOptions() []gax.CallOption {
      	return []gax.CallOption{
      		gax.WithRetry(func() gax.Retryer {
      			return gax.OnHTTPCodes(gax.Backoff{
      				Initial:    90 * time.Second,
      				Max:        5 * time.Minute,
      				Multiplier: 2,
      			},
      				http.StatusTooManyRequests)
      		}),
      	}
      }
      
      // getTagBindingsClient returns the client to be used for creating tag bindings to
      // the resources.
      func getTagBindingsClient(ctx context.Context) (*rscmgr.TagBindingsClient, error) {
      	cred, err := GetCredentialsSecret(tags.CoreClient, tags.Namespace, tags.ProviderSpec)
      	if err != nil {
      		return nil, fmt.Errorf("failed to read to gcp config: %w", err)
      	}
      
      	endpoint := fmt.Sprintf("https://%s-%s", tags.InstanceZone, resourceManagerHostSubPath)
      	opts := []option.ClientOption{
      		option.WithCredentialsJSON([]byte(cred)),
      		option.WithEndpoint(endpoint),
      	}
      	return rscmgr.NewTagBindingsRESTClient(ctx, opts...)
      }
      
      func addTags() {
      	client, err := getTagBindingsClient(ctx)
      	if err != nil {
      		return err
      	}
      	defer client.Close()
      
      	// GCP has a rate limit of 600 requests per minute, restricting
      	// here to 8 requests per second.
      	limiter := newLimiter(8, 8, true)
      
      	tagBindingReq := &rscmgrpb.CreateTagBindingRequest{
      		TagBinding: &rscmgrpb.TagBinding{
      			Parent: parent,
      		},
      	}
      
      	for _, value := range userTags {
      		if err := limiter.Wait(ctx); err != nil {
      			errFlag = true
      			continue
      		}
      
      		tagBindingReq.TagBinding.TagValueNamespacedName = value
      		result, err := client.CreateTagBinding(ctx, tagBindingReq, getCreateCallOptions()...)
      		if err != nil {
      			e, ok := err.(*apierror.APIError)
      			if ok && e.HTTPCode() == http.StatusConflict {
      				klog.Infof("tag binding %s/%s already exists", instanceID, value)
      				continue
      			}
      			errFlag = true
      			klog.Errorf("request to add %s tag to %d compute instance failed: %v", value, instanceID, err)
      			continue
      		}
      
      		if _, err = result.Wait(ctx); err != nil {
      			errFlag = true
      			klog.Errorf("failed to add %s tag to %d compute instance: %v", value, instanceID, err)
      		}
      	}
      }
      

       

      Acceptance Criteria

      • Code linting, validation and best practices adhered to
      • Unit tests for applicable changes.
      • gcp-filestore-disk-csi-driver managed resources should have user-defined tags.

              bhb@redhat.com Bharath B
              bhb@redhat.com Bharath B
              Votes:
              0 Vote for this issue
              Watchers:
              2 Start watching this issue

                Created:
                Updated:
                Resolved:

                  Estimated:
                  Original Estimate - 0 minutes
                  0m
                  Remaining:
                  Remaining Estimate - 0 minutes
                  0m
                  Logged:
                  Time Spent - 3 days
                  3d