yandex-import: allow create image based on another one

Allow as source for a new Compute Image not only  URL to Storage Object but also a another one Compute Image
Details at official doc about ImageCreateRequest https://cloud.yandex.com/docs/compute/grpc/image_service#CreateImageRequest
This commit is contained in:
Gennady Lipenkov 2020-07-20 20:26:22 +03:00
parent ea4aa67f78
commit e0cc7b9d8c
3 changed files with 35 additions and 25 deletions

View File

@ -67,6 +67,7 @@
file [GH-9379] file [GH-9379]
* post-processor/yandex-import: Support using URL from yandex-export pp * post-processor/yandex-import: Support using URL from yandex-export pp
[GH-9601] [GH-9601]
* post-processor/yandex-import: Support create the new Image based on another one
* provisioner/ansible: Add template option for templating the inventory file * provisioner/ansible: Add template option for templating the inventory file
lines [GH-9438] lines [GH-9438]

View File

@ -8,7 +8,7 @@ const BuilderId = "packer.post-processor.yandex-import"
type Artifact struct { type Artifact struct {
imageID string imageID string
sourceURL string imageSource string
} }
func (*Artifact) BuilderId() string { func (*Artifact) BuilderId() string {
@ -16,7 +16,7 @@ func (*Artifact) BuilderId() string {
} }
func (a *Artifact) Id() string { func (a *Artifact) Id() string {
return a.sourceURL return a.imageSource
} }
func (a *Artifact) Files() []string { func (a *Artifact) Files() []string {
@ -24,7 +24,7 @@ func (a *Artifact) Files() []string {
} }
func (a *Artifact) String() string { func (a *Artifact) String() string {
return fmt.Sprintf("Create image %v from URL %v", a.imageID, a.sourceURL) return fmt.Sprintf("Create image %v from source URL/image %v", a.imageID, a.imageSource)
} }
func (*Artifact) State(name string) interface{} { func (*Artifact) State(name string) interface{} {

View File

@ -6,6 +6,7 @@ package yandeximport
import ( import (
"context" "context"
"fmt" "fmt"
"net/url"
"os" "os"
"strings" "strings"
@ -171,7 +172,7 @@ func (p *PostProcessor) PostProcess(ctx context.Context, ui packer.Ui, artifact
return nil, false, false, fmt.Errorf("error rendering object_name template: %s", err) return nil, false, false, fmt.Errorf("error rendering object_name template: %s", err)
} }
var url string var imageSource string
var fileSource bool var fileSource bool
// Create temporary storage Access Key // Create temporary storage Access Key
@ -198,18 +199,22 @@ func (p *PostProcessor) PostProcess(ctx context.Context, ui packer.Ui, artifact
return nil, false, false, fmt.Errorf("To upload artfact you need to specify `bucket` value") return nil, false, false, fmt.Errorf("To upload artfact you need to specify `bucket` value")
} }
url, err = uploadToBucket(storageClient, ui, artifact, p.config.Bucket, p.config.ObjectName) imageSource, err = uploadToBucket(storageClient, ui, artifact, p.config.Bucket, p.config.ObjectName)
if err != nil { if err != nil {
return nil, false, false, err return nil, false, false, err
} }
case yandexexport.BuilderId: case yandexexport.BuilderId, BuilderId:
// Artifact already in storage, just get URL // Artifact already in storage, just get URL
url = artifact.Id() // OR artifact from prev yandex-import PP, reuse URL
imageSource, err = presignUrl(storageClient, ui, artifact.Id())
if err != nil {
return nil, false, false, err
}
case BuilderId: case yandex.BuilderID:
// Artifact from prev yandex-import PP, reuse URL // Artifact is plain Yandex Compute Image, just create new one based on provided.
url = artifact.Id() imageSource = artifact.Id()
default: default:
err := fmt.Errorf( err := fmt.Errorf(
@ -218,18 +223,13 @@ func (p *PostProcessor) PostProcess(ctx context.Context, ui packer.Ui, artifact
return nil, false, false, err return nil, false, false, err
} }
presignedUrl, err := presignUrl(storageClient, ui, url) ycImage, err := createYCImage(ctx, client, ui, p.config.FolderID, imageSource, p.config.ImageName, p.config.ImageDescription, p.config.ImageFamily, p.config.ImageLabels)
if err != nil {
return nil, false, false, err
}
ycImage, err := createYCImage(ctx, client, ui, p.config.FolderID, presignedUrl, p.config.ImageName, p.config.ImageDescription, p.config.ImageFamily, p.config.ImageLabels)
if err != nil { if err != nil {
return nil, false, false, err return nil, false, false, err
} }
if fileSource && !p.config.SkipClean { if fileSource && !p.config.SkipClean {
err = deleteFromBucket(storageClient, ui, url) err = deleteFromBucket(storageClient, ui, imageSource)
if err != nil { if err != nil {
return nil, false, false, err return nil, false, false, err
} }
@ -245,7 +245,7 @@ func (p *PostProcessor) PostProcess(ctx context.Context, ui packer.Ui, artifact
return &Artifact{ return &Artifact{
imageID: ycImage.GetId(), imageID: ycImage.GetId(),
sourceURL: url, imageSource: imageSource,
}, false, false, nil }, false, false, nil
} }
@ -294,21 +294,30 @@ func uploadToBucket(s3conn *s3.S3, ui packer.Ui, artifact packer.Artifact, bucke
return req.HTTPRequest.URL.String(), nil return req.HTTPRequest.URL.String(), nil
} }
func createYCImage(ctx context.Context, driver yandex.Driver, ui packer.Ui, folderID string, rawImageURL string, imageName string, imageDescription string, imageFamily string, imageLabels map[string]string) (*compute.Image, error) { func createYCImage(ctx context.Context, driver yandex.Driver, ui packer.Ui, folderID string, imageSource string, imageName string, imageDescription string, imageFamily string, imageLabels map[string]string) (*compute.Image, error) {
op, err := driver.SDK().WrapOperation(driver.SDK().Compute().Image().Create(ctx, &compute.CreateImageRequest{ req := &compute.CreateImageRequest{
FolderId: folderID, FolderId: folderID,
Name: imageName, Name: imageName,
Description: imageDescription, Description: imageDescription,
Labels: imageLabels, Labels: imageLabels,
Family: imageFamily, Family: imageFamily,
Source: &compute.CreateImageRequest_Uri{Uri: rawImageURL}, }
}))
// switch on imageSource value: cloud image id or storage URL
_, err := url.Parse(imageSource)
if err == nil {
req.Source = &compute.CreateImageRequest_Uri{Uri: imageSource}
} else {
req.Source = &compute.CreateImageRequest_ImageId{ImageId: imageSource}
}
op, err := driver.SDK().WrapOperation(driver.SDK().Compute().Image().Create(ctx, req))
if err != nil { if err != nil {
ui.Say("Error creating Yandex Compute Image") ui.Say("Error creating Yandex Compute Image")
return nil, err return nil, err
} }
ui.Say(fmt.Sprintf("Source url for Image creation: %v", rawImageURL)) ui.Say(fmt.Sprintf("Source url for Image creation: %v", imageSource))
ui.Say(fmt.Sprintf("Creating Yandex Compute Image %v within operation %#v", imageName, op.Id())) ui.Say(fmt.Sprintf("Creating Yandex Compute Image %v within operation %#v", imageName, op.Id()))