155 lines
4.0 KiB
Go
155 lines
4.0 KiB
Go
|
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"
|
||
|
"github.com/hashicorp/packer/builder/yandex"
|
||
|
"github.com/hashicorp/packer/packer-plugin-sdk/multistep"
|
||
|
"github.com/hashicorp/packer/packer-plugin-sdk/packer"
|
||
|
"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)
|
||
|
}
|
||
|
}
|
||
|
}
|