github.com/openshift/installer@v1.4.17/pkg/asset/ignition/bootstrap/gcp/storage.go (about) 1 package gcp 2 3 import ( 4 "context" 5 "fmt" 6 "time" 7 8 "cloud.google.com/go/storage" 9 "google.golang.org/api/option" 10 11 "github.com/openshift/installer/pkg/asset/installconfig" 12 gcpic "github.com/openshift/installer/pkg/asset/installconfig/gcp" 13 gcpconsts "github.com/openshift/installer/pkg/constants/gcp" 14 ) 15 16 const ( 17 bootstrapIgnitionBucketObjName = "bootstrap.ign" 18 ) 19 20 // GetBootstrapStorageName gets the name of the storage bucket for the bootstrap process. 21 func GetBootstrapStorageName(clusterID string) string { 22 return fmt.Sprintf("%s-bootstrap-ignition", clusterID) 23 } 24 25 // NewStorageClient creates a new Google storage client. 26 func NewStorageClient(ctx context.Context) (*storage.Client, error) { 27 ssn, err := gcpic.GetSession(ctx) 28 if err != nil { 29 return nil, fmt.Errorf("failed to get session while creating gcp storage client: %w", err) 30 } 31 32 client, err := storage.NewClient(ctx, option.WithCredentials(ssn.Credentials)) 33 if err != nil { 34 return nil, fmt.Errorf("failed to create client: %w", err) 35 } 36 37 return client, nil 38 } 39 40 // CreateStorage creates the gcp bucket/storage. The storage bucket does Not include the bucket object. The 41 // bucket object is created as a separate process/function, so that the two are not tied together, and 42 // the data stored inside the object can be set at a later time. 43 func CreateStorage(ctx context.Context, ic *installconfig.InstallConfig, bucketHandle *storage.BucketHandle, clusterID string) error { 44 labels := map[string]string{} 45 labels[fmt.Sprintf(gcpconsts.ClusterIDLabelFmt, clusterID)] = "owned" 46 for _, label := range ic.Config.GCP.UserLabels { 47 labels[label.Key] = label.Value 48 } 49 50 bucketAttrs := storage.BucketAttrs{ 51 UniformBucketLevelAccess: storage.UniformBucketLevelAccess{ 52 Enabled: true, 53 }, 54 Location: ic.Config.GCP.Region, 55 Labels: labels, 56 } 57 58 ctx, cancel := context.WithTimeout(ctx, time.Minute*1) 59 defer cancel() 60 61 if err := bucketHandle.Create(ctx, ic.Config.GCP.ProjectID, &bucketAttrs); err != nil { 62 return fmt.Errorf("failed to create bucket: %w", err) 63 } 64 return nil 65 } 66 67 // CreateSignedURL creates a signed url and correlates the signed url with a storage bucket. 68 func CreateSignedURL(clusterID string) (string, error) { 69 bucketName := GetBootstrapStorageName(clusterID) 70 71 client, err := NewStorageClient(context.TODO()) 72 if err != nil { 73 return "", fmt.Errorf("failed to create storage client: %w", err) 74 } 75 76 // Signing a URL requires credentials authorized to sign a URL. You can pass 77 // these in through SignedURLOptions with a Google Access ID with 78 // iam.serviceAccounts.signBlob permissions. 79 opts := storage.SignedURLOptions{ 80 Scheme: storage.SigningSchemeV4, 81 Method: "GET", 82 Expires: time.Now().Add(time.Minute * 60), 83 } 84 85 // The object has not been created yet. This is ok, it is expected to be created after this call. 86 // However, if the object is never created this could cause major issues. 87 url, err := client.Bucket(bucketName).SignedURL(bootstrapIgnitionBucketObjName, &opts) 88 if err != nil { 89 return "", fmt.Errorf("failed to create a signed url: %w", err) 90 } 91 92 return url, nil 93 } 94 95 // FillBucket will add the contents to the bootstrap storage bucket object. 96 func FillBucket(ctx context.Context, bucketHandle *storage.BucketHandle, contents string) error { 97 ctx, cancel := context.WithTimeout(ctx, time.Minute*1) 98 defer cancel() 99 100 objWriter := bucketHandle.Object(bootstrapIgnitionBucketObjName).NewWriter(ctx) 101 if _, err := fmt.Fprint(objWriter, contents); err != nil { 102 return fmt.Errorf("failed to store content in bucket object: %w", err) 103 } 104 105 if err := objWriter.Close(); err != nil { 106 return fmt.Errorf("failed to close bucket object writer: %w", err) 107 } 108 109 return nil 110 } 111 112 // DestroyStorage Destroy the bucket and the bucket objects that are associated with the bucket. 113 func DestroyStorage(ctx context.Context, clusterID string) error { 114 client, err := NewStorageClient(ctx) 115 if err != nil { 116 return fmt.Errorf("failed to create storage client: %w", err) 117 } 118 bucketName := GetBootstrapStorageName(clusterID) 119 120 ctx, cancel := context.WithTimeout(ctx, time.Minute*1) 121 defer cancel() 122 if err := client.Bucket(bucketName).Object(bootstrapIgnitionBucketObjName).Delete(ctx); err != nil { 123 return fmt.Errorf("failed to delete bucket object %s: %w", bootstrapIgnitionBucketObjName, err) 124 } 125 126 // Deleting a bucket will delete the managed folders and bucket objects. 127 if err := client.Bucket(bucketName).Delete(ctx); err != nil { 128 return fmt.Errorf("failed to delete bucket %s: %w", bucketName, err) 129 } 130 return nil 131 }