packer-cn/post-processor/yandex-export/step-create-s3-keys.go

155 lines
4.0 KiB
Go
Raw Normal View History

package yandexexport
import (
"context"
"fmt"
"log"
"net/url"
"path/filepath"
"strings"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/credentials"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/s3"
2020-12-17 16:29:25 -05:00
"github.com/hashicorp/packer-plugin-sdk/multistep"
"github.com/hashicorp/packer-plugin-sdk/packer"
"github.com/hashicorp/packer/builder/yandex"
"github.com/yandex-cloud/go-genproto/yandex/cloud/iam/v1/awscompatibility"
)
type StepCreateS3Keys struct {
ServiceAccountID string
Paths []string
}
func (c *StepCreateS3Keys) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
driver := state.Get("driver").(yandex.Driver)
ui := state.Get("ui").(packer.Ui)
ui.Say("Create temporary storage Access Key")
// Create temporary storage Access Key
respWithKey, err := driver.SDK().IAM().AWSCompatibility().AccessKey().Create(ctx, &awscompatibility.CreateAccessKeyRequest{
ServiceAccountId: c.ServiceAccountID,
Description: "this temporary key is for upload image to storage; created by Packer",
})
if err != nil {
err := fmt.Errorf("Error waiting for cloud-init script to finish: %s", err)
return yandex.StepHaltWithError(state, err)
}
state.Put("s3_secret", respWithKey)
ui.Say("Verify access to paths")
if err := verfiyAccess(respWithKey.GetAccessKey().GetKeyId(), respWithKey.Secret, c.Paths); err != nil {
return yandex.StepHaltWithError(state, err)
}
return multistep.ActionContinue
}
func (s *StepCreateS3Keys) Cleanup(state multistep.StateBag) {
driver := state.Get("driver").(yandex.Driver)
ui := state.Get("ui").(packer.Ui)
if val, ok := state.GetOk("s3_secret"); ok {
ui.Say("S3 secrets have been found")
s3Secret := val.(*awscompatibility.CreateAccessKeyResponse)
ui.Message("Cleanup empty objects...")
cleanUpEmptyObjects(s3Secret.GetAccessKey().GetKeyId(), s3Secret.GetSecret(), s.Paths)
ui.Say("Delete S3 secrets...")
_, err := driver.SDK().IAM().AWSCompatibility().AccessKey().Delete(context.Background(), &awscompatibility.DeleteAccessKeyRequest{
AccessKeyId: s3Secret.GetAccessKey().GetId(),
})
if err != nil {
ui.Error(err.Error())
}
}
}
func verfiyAccess(keyID, secret string, paths []string) error {
newSession, err := session.NewSession(&aws.Config{
Endpoint: aws.String(defaultStorageEndpoint),
Region: aws.String(defaultStorageRegion),
Credentials: credentials.NewStaticCredentials(
keyID, secret, "",
),
})
if err != nil {
return err
}
s3Conn := s3.New(newSession)
for _, path := range paths {
u, err := url.Parse(path)
if err != nil {
return err
}
key := u.Path
if strings.HasSuffix(key, "/") {
key = filepath.Join(key, "disk.qcow2")
}
_, err = s3Conn.PutObject(&s3.PutObjectInput{
Body: aws.ReadSeekCloser(strings.NewReader("")),
Bucket: aws.String(u.Host),
Key: aws.String(key),
})
if err != nil {
return err
}
}
return nil
}
func cleanUpEmptyObjects(keyID, secret string, paths []string) {
newSession, err := session.NewSession(&aws.Config{
Endpoint: aws.String(defaultStorageEndpoint),
Region: aws.String(defaultStorageRegion),
Credentials: credentials.NewStaticCredentials(
keyID, secret, "",
),
})
if err != nil {
log.Printf("[WARN] %s", err)
return
}
s3Conn := s3.New(newSession)
for _, path := range paths {
u, err := url.Parse(path)
if err != nil {
log.Printf("[WARN] %s", err)
continue
}
key := u.Path
if strings.HasSuffix(key, "/") {
key = filepath.Join(key, "disk.qcow2")
}
log.Printf("Check object: '%s'", path)
respHead, err := s3Conn.HeadObject(&s3.HeadObjectInput{
Bucket: aws.String(u.Host),
Key: aws.String(key),
})
if err != nil {
log.Printf("[WARN] %s", err)
continue
}
if *respHead.ContentLength > 0 {
continue
}
log.Printf("[DEBUG] Delete object: '%s'", path)
_, err = s3Conn.DeleteObject(&s3.DeleteObjectInput{
Bucket: aws.String(u.Host),
Key: aws.String(key),
})
if err != nil {
log.Printf("[WARN] %s", err)
}
}
}