scheduled cloud cleaner now uses a new method to remove azure resources. So cloud cleaner code is not used
99 lines
2.9 KiB
Go
99 lines
2.9 KiB
Go
package gcp
|
|
|
|
import (
|
|
"context"
|
|
// gcp uses MD5 hashes
|
|
/* #nosec G501 */
|
|
"crypto/md5"
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
|
|
"cloud.google.com/go/storage"
|
|
"google.golang.org/api/option"
|
|
)
|
|
|
|
const (
|
|
// MetadataKeyImageName contains a key name used to store metadata on
|
|
// a Storage object with the intended name of the image.
|
|
// The metadata can be then used to associate the object with actual
|
|
// image build using the image name.
|
|
MetadataKeyImageName string = "osbuild-composer-image-name"
|
|
)
|
|
|
|
// StorageObjectUpload uploads an OS image to specified Cloud Storage bucket and object.
|
|
// The bucket must exist. MD5 sum of the image file and uploaded object is
|
|
// compared after the upload to verify the integrity of the uploaded image.
|
|
//
|
|
// The ObjectAttrs is returned if the object has been created.
|
|
//
|
|
// Uses:
|
|
// - Storage API
|
|
func (g *GCP) StorageObjectUpload(ctx context.Context, filename, bucket, object string, metadata map[string]string) (*storage.ObjectAttrs, error) {
|
|
storageClient, err := storage.NewClient(ctx, option.WithCredentials(g.creds))
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to get Storage client: %v", err)
|
|
}
|
|
defer storageClient.Close()
|
|
|
|
// Open the image file
|
|
imageFile, err := os.Open(filename)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("cannot open the image: %v", err)
|
|
}
|
|
defer imageFile.Close()
|
|
|
|
// Compute MD5 checksum of the image file for later verification
|
|
// gcp uses MD5 hashes
|
|
/* #nosec G401 */
|
|
imageFileHash := md5.New()
|
|
if _, err := io.Copy(imageFileHash, imageFile); err != nil {
|
|
return nil, fmt.Errorf("cannot create md5 of the image: %v", err)
|
|
}
|
|
// Move the cursor of opened file back to the start
|
|
if _, err := imageFile.Seek(0, 0); err != nil {
|
|
return nil, fmt.Errorf("cannot seek the image: %v", err)
|
|
}
|
|
|
|
// Upload the image
|
|
// The Bucket MUST exist and be of a STANDARD storage class
|
|
obj := storageClient.Bucket(bucket).Object(object)
|
|
wc := obj.NewWriter(ctx)
|
|
|
|
// Uploaded data is rejected if its MD5 hash does not match the set value.
|
|
wc.MD5 = imageFileHash.Sum(nil)
|
|
|
|
if metadata != nil {
|
|
wc.ObjectAttrs.Metadata = metadata
|
|
}
|
|
|
|
if _, err = io.Copy(wc, imageFile); err != nil {
|
|
return nil, fmt.Errorf("uploading the image failed: %v", err)
|
|
}
|
|
|
|
// The object will not be available until Close has been called.
|
|
if err := wc.Close(); err != nil {
|
|
return nil, fmt.Errorf("Writer.Close: %v", err)
|
|
}
|
|
|
|
return wc.Attrs(), nil
|
|
}
|
|
|
|
// StorageObjectDelete deletes the given object from a bucket.
|
|
//
|
|
// Uses:
|
|
// - Storage API
|
|
func (g *GCP) StorageObjectDelete(ctx context.Context, bucket, object string) error {
|
|
storageClient, err := storage.NewClient(ctx, option.WithCredentials(g.creds))
|
|
if err != nil {
|
|
return fmt.Errorf("failed to get Storage client: %v", err)
|
|
}
|
|
defer storageClient.Close()
|
|
|
|
objectHandle := storageClient.Bucket(bucket).Object(object)
|
|
if err = objectHandle.Delete(ctx); err != nil {
|
|
return fmt.Errorf("failed to delete image file object: %v", err)
|
|
}
|
|
|
|
return nil
|
|
}
|