constellation/internal/osimage/imageinfo/imageinfo.go
Otto Bittner 97dc15b1d1 staticupload: correctly set invalidation timeout
Previously the timeout was not set in the client's constructor, thus the
zero value was used. The client did not wait for invalidation.
To prevent this in the future a warning is logged if wait is disabled.

Co-authored-by: Daniel Weiße <dw@edgeless.systems>
2023-09-04 11:20:13 +02:00

101 lines
3.1 KiB
Go

/*
Copyright (c) Edgeless Systems GmbH
SPDX-License-Identifier: AGPL-3.0-only
*/
// package imageinfo is used to upload image info JSON files to S3.
package imageinfo
import (
"bytes"
"context"
"encoding/json"
"fmt"
"net/url"
"time"
s3manager "github.com/aws/aws-sdk-go-v2/feature/s3/manager"
"github.com/aws/aws-sdk-go-v2/service/s3"
s3types "github.com/aws/aws-sdk-go-v2/service/s3/types"
"github.com/edgelesssys/constellation/v2/internal/api/versionsapi"
"github.com/edgelesssys/constellation/v2/internal/constants"
"github.com/edgelesssys/constellation/v2/internal/logger"
"github.com/edgelesssys/constellation/v2/internal/staticupload"
)
// Uploader uploads image info to S3.
type Uploader struct {
uploadClient uploadClient
uploadClientClose func(ctx context.Context) error
// bucket is the name of the S3 bucket to use.
bucket string
log *logger.Logger
}
// New creates a new Uploader.
func New(ctx context.Context, region, bucket, distributionID string, log *logger.Logger) (*Uploader, CloseFunc, error) {
staticUploadClient, staticUploadClientClose, err := staticupload.New(ctx, staticupload.Config{
Region: region,
Bucket: bucket,
DistributionID: distributionID,
CacheInvalidationStrategy: staticupload.CacheInvalidateBatchOnFlush,
CacheInvalidationWaitTimeout: 10 * time.Minute,
}, log)
if err != nil {
return nil, nil, err
}
uploader := &Uploader{
uploadClient: staticUploadClient,
uploadClientClose: staticUploadClientClose,
bucket: bucket,
log: log,
}
uploaderClose := func(ctx context.Context) error {
return uploader.Close(ctx)
}
return uploader, uploaderClose, nil
}
// Close closes the uploader.
// It invalidates the CDN cache for all uploaded files.
func (a *Uploader) Close(ctx context.Context) error {
if a.uploadClientClose == nil {
return nil
}
return a.uploadClientClose(ctx)
}
// Upload marshals the image info to JSON and uploads it to S3.
func (a *Uploader) Upload(ctx context.Context, imageInfo versionsapi.ImageInfo) (string, error) {
ver, err := versionsapi.NewVersion(imageInfo.Ref, imageInfo.Stream, imageInfo.Version, versionsapi.VersionKindImage)
if err != nil {
return "", fmt.Errorf("creating version: %w", err)
}
key, err := url.JoinPath(ver.ArtifactPath(versionsapi.APIV2), ver.Kind().String(), "info.json")
if err != nil {
return "", err
}
a.log.Debugf("Archiving image info to s3://%v/%v", a.bucket, key)
buf := &bytes.Buffer{}
if err := json.NewEncoder(buf).Encode(imageInfo); err != nil {
return "", err
}
_, err = a.uploadClient.Upload(ctx, &s3.PutObjectInput{
Bucket: &a.bucket,
Key: &key,
Body: buf,
ChecksumAlgorithm: s3types.ChecksumAlgorithmSha256,
})
return constants.CDNRepositoryURL + "/" + key, err
}
type uploadClient interface {
Upload(ctx context.Context, input *s3.PutObjectInput, opts ...func(*s3manager.Uploader)) (*s3manager.UploadOutput, error)
}
// CloseFunc is a function that closes the client.
type CloseFunc func(ctx context.Context) error