github.com/olli-ai/jx/v2@v2.0.400-0.20210921045218-14731b4dd448/pkg/cmd/opts/bucket.go (about)

     1  package opts
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"io"
     7  	"net/url"
     8  	"time"
     9  
    10  	v1 "github.com/jenkins-x/jx-api/pkg/apis/jenkins.io/v1"
    11  	"github.com/olli-ai/jx/v2/pkg/cloud/gke"
    12  
    13  	"github.com/jenkins-x/jx-logging/pkg/log"
    14  	"github.com/olli-ai/jx/v2/pkg/cloud/buckets"
    15  	"github.com/olli-ai/jx/v2/pkg/kube"
    16  	"github.com/olli-ai/jx/v2/pkg/kube/cluster"
    17  	"github.com/olli-ai/jx/v2/pkg/util"
    18  	"github.com/pkg/errors"
    19  	"github.com/spf13/cobra"
    20  	"gocloud.dev/blob"
    21  )
    22  
    23  // CreateBucketValues contains the values to create a Bucket on cloud storage
    24  type CreateBucketValues struct {
    25  	Bucket     string
    26  	BucketKind string
    27  
    28  	// GKE specific values
    29  	GKEProjectID string
    30  	GKEZone      string
    31  }
    32  
    33  // AddCreateBucketFlags adds the CLI arguments to be able to specify to create a new bucket along with any cloud specific parameters
    34  func (cb *CreateBucketValues) AddCreateBucketFlags(cmd *cobra.Command) {
    35  	cmd.Flags().StringVarP(&cb.Bucket, "bucket", "", "", "Specify the name of the bucket to use")
    36  	cmd.Flags().StringVarP(&cb.BucketKind, "bucket-kind", "", "", "The kind of bucket to use like 'gs, s3, azure' etc")
    37  	cmd.Flags().StringVarP(&cb.GKEProjectID, "gke-project-id", "", "", "Google Project ID to use for a new bucket")
    38  	cmd.Flags().StringVarP(&cb.GKEZone, "gke-zone", "", "", "The GKE zone (e.g. us-central1-a) where the new bucket will be created")
    39  }
    40  
    41  // IsEmpty returns true if there is no bucket name specified
    42  func (cb *CreateBucketValues) IsEmpty() bool {
    43  	return cb.Bucket == ""
    44  }
    45  
    46  // CreateBucket creates a new bucket using the create bucket values and team settings returning the newly created bucket URL
    47  func (o *CommonOptions) CreateBucket(cb *CreateBucketValues, settings *v1.TeamSettings) (string, error) {
    48  	bucketURL, err := buckets.CreateBucketURL(cb.Bucket, cb.BucketKind, settings)
    49  	if err != nil {
    50  		return bucketURL, errors.Wrapf(err, "failed to create the bucket URL for %s", cb.Bucket)
    51  	}
    52  
    53  	ctx, _ := context.WithTimeout(context.Background(), time.Second*20)
    54  	bucket, err := blob.Open(ctx, bucketURL)
    55  	if err != nil {
    56  		return bucketURL, errors.Wrapf(err, "failed to open the bucket for %s", bucketURL)
    57  	}
    58  
    59  	// lets check if the bucket exists
    60  	iter := bucket.List(nil)
    61  	obj, err := iter.Next(ctx)
    62  	if err != nil {
    63  		if err == io.EOF {
    64  			log.Logger().Infof("bucket %s is empty", bucketURL)
    65  		} else {
    66  			log.Logger().Infof("The bucket %s does not exist yet so lets create it...", util.ColorInfo(bucketURL))
    67  			err = o.CreateBucketFromURL(bucketURL, bucket, cb)
    68  			if err != nil {
    69  				return bucketURL, errors.Wrapf(err, "failed to create the bucket for %s", bucketURL)
    70  			}
    71  		}
    72  	} else {
    73  		log.Logger().Infof("Found item in bucket %s for %s", bucketURL, obj.Key)
    74  	}
    75  	return bucketURL, nil
    76  }
    77  
    78  // CreateBucketFromURL creates a bucket if it does not already exist
    79  func (o *CommonOptions) CreateBucketFromURL(bucketURL string, bucket *blob.Bucket, cb *CreateBucketValues) error {
    80  	u, err := url.Parse(bucketURL)
    81  	if err != nil {
    82  		return err
    83  	}
    84  	switch u.Scheme {
    85  	case "gs":
    86  		return o.createGcsBucket(u, bucket, cb)
    87  	default:
    88  		return fmt.Errorf("Cannot create a bucket for provider %s", bucketURL)
    89  	}
    90  }
    91  
    92  func (o *CommonOptions) createGcsBucket(u *url.URL, bucket *blob.Bucket, cb *CreateBucketValues) error {
    93  	var err error
    94  	if cb.GKEProjectID == "" {
    95  		if kubeClient, ns, err := o.KubeClientAndDevNamespace(); err == nil {
    96  			if data, err := kube.ReadInstallValues(kubeClient, ns); err == nil && data != nil {
    97  				cb.GKEProjectID = data[kube.ProjectID]
    98  				if cb.GKEZone == "" {
    99  					cb.GKEZone = data[kube.Zone]
   100  				}
   101  			}
   102  		}
   103  	}
   104  	if cb.GKEProjectID == "" {
   105  		cb.GKEProjectID, err = o.GetGoogleProjectID("")
   106  		if err != nil {
   107  			return err
   108  		}
   109  	}
   110  
   111  	err = o.RunCommandVerbose(
   112  		"gcloud", "config", "set", "project", cb.GKEProjectID)
   113  	if err != nil {
   114  		return err
   115  	}
   116  
   117  	if cb.GKEZone == "" {
   118  		defaultZone := ""
   119  		if cluster, err := cluster.Name(o.Kube()); err == nil && cluster != "" {
   120  			if clusterZone, err := o.GCloud().ClusterZone(cluster); err == nil {
   121  				defaultZone = clusterZone
   122  			}
   123  		}
   124  
   125  		cb.GKEZone, err = o.GetGoogleZoneWithDefault(cb.GKEProjectID, defaultZone)
   126  		if err != nil {
   127  			return err
   128  		}
   129  	}
   130  
   131  	bucketName := u.Host
   132  	region := gke.GetRegionFromZone(cb.GKEZone)
   133  	err = o.GCloud().CreateBucket(cb.GKEProjectID, bucketName, region)
   134  	if err != nil {
   135  		return errors.Wrapf(err, "creating bucket %s in project %s and region %s", bucketName, cb.GKEProjectID, region)
   136  	}
   137  	return nil
   138  }