Bulk update 'yandex' builder
Squashed commit of the following: commit ccc020231780179d241d46eef7c0ba103366aed0 Author: Yandex.Cloud Bot <ycloud-bot@yandex.ru> Date: Tue Apr 9 14:38:30 2019 +0000 sync upstream
This commit is contained in:
parent
a12c5d57ec
commit
8e4e314553
|
@ -2,59 +2,45 @@ package yandex
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
|
||||||
|
"github.com/yandex-cloud/go-genproto/yandex/cloud/compute/v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
//revive:disable:var-naming
|
|
||||||
|
|
||||||
// Artifact represents a image as the result of a Packer build.
|
|
||||||
type Artifact struct {
|
type Artifact struct {
|
||||||
image *Image
|
|
||||||
driver Driver
|
|
||||||
config *Config
|
config *Config
|
||||||
|
driver Driver
|
||||||
|
image *compute.Image
|
||||||
}
|
}
|
||||||
|
|
||||||
// BuilderID returns the builder Id.
|
|
||||||
//revive:disable:var-naming
|
//revive:disable:var-naming
|
||||||
func (*Artifact) BuilderId() string {
|
func (*Artifact) BuilderId() string {
|
||||||
return BuilderID
|
return BuilderID
|
||||||
}
|
}
|
||||||
|
|
||||||
// Destroy destroys the image represented by the artifact.
|
func (a *Artifact) Id() string {
|
||||||
func (a *Artifact) Destroy() error {
|
return a.image.Id
|
||||||
log.Printf("Destroying image: %s", a.image.Name)
|
|
||||||
errCh := a.driver.DeleteImage(a.image.Name)
|
|
||||||
return errCh
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Files returns the files represented by the artifact.
|
|
||||||
func (*Artifact) Files() []string {
|
func (*Artifact) Files() []string {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Id returns the image name.
|
//revive:enable:var-naming
|
||||||
//revive:disable:var-naming
|
|
||||||
func (a *Artifact) Id() string {
|
|
||||||
return a.image.Name
|
|
||||||
}
|
|
||||||
|
|
||||||
// String returns the string representation of the artifact.
|
|
||||||
func (a *Artifact) String() string {
|
func (a *Artifact) String() string {
|
||||||
return fmt.Sprintf("A disk image was created: %v (id: %v)", a.image.Name, a.image.ID)
|
return fmt.Sprintf("A disk image was created: %v (id: %v) with family name %v", a.image.Name, a.image.Id, a.image.Family)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *Artifact) State(name string) interface{} {
|
func (a *Artifact) State(name string) interface{} {
|
||||||
switch name {
|
switch name {
|
||||||
case "ImageID":
|
case "ImageID":
|
||||||
return a.image.ID
|
return a.image.Id
|
||||||
case "ImageName":
|
|
||||||
return a.image.Name
|
|
||||||
case "ImageSizeGb":
|
|
||||||
return a.image.SizeGb
|
|
||||||
case "FolderID":
|
case "FolderID":
|
||||||
return a.config.FolderID
|
return a.image.FolderId
|
||||||
case "BuildZone":
|
|
||||||
return a.config.Zone
|
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Artifact) Destroy() error {
|
||||||
|
return a.driver.DeleteImage(a.image.Id)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,46 +0,0 @@
|
||||||
package yandex
|
|
||||||
|
|
||||||
import "fmt"
|
|
||||||
|
|
||||||
type ArtifactMini struct {
|
|
||||||
config *Config
|
|
||||||
imageID string
|
|
||||||
imageName string
|
|
||||||
imageFamily string
|
|
||||||
}
|
|
||||||
|
|
||||||
//revive:disable:var-naming
|
|
||||||
func (*ArtifactMini) BuilderId() string {
|
|
||||||
return BuilderID
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *ArtifactMini) Id() string {
|
|
||||||
return a.imageID
|
|
||||||
}
|
|
||||||
|
|
||||||
func (*ArtifactMini) Files() []string {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
//revive:enable:var-naming
|
|
||||||
func (a *ArtifactMini) String() string {
|
|
||||||
return fmt.Sprintf("A disk image was created: %v (id: %v) (family: %v)", a.imageName, a.imageID, a.imageFamily)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *ArtifactMini) State(name string) interface{} {
|
|
||||||
switch name {
|
|
||||||
case "ImageID":
|
|
||||||
return a.imageID
|
|
||||||
case "FolderID":
|
|
||||||
return a.config.FolderID
|
|
||||||
case "BuildZone":
|
|
||||||
return a.config.Zone
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func (*ArtifactMini) Destroy() error {
|
|
||||||
// no destroy right now
|
|
||||||
return nil
|
|
||||||
}
|
|
|
@ -0,0 +1,43 @@
|
||||||
|
package yandex
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/hashicorp/packer/packer"
|
||||||
|
|
||||||
|
"github.com/yandex-cloud/go-genproto/yandex/cloud/compute/v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestArtifact_impl(t *testing.T) {
|
||||||
|
var _ packer.Artifact = new(Artifact)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestArtifact_Id(t *testing.T) {
|
||||||
|
i := &compute.Image{
|
||||||
|
Id: "test-id-value",
|
||||||
|
FolderId: "test-folder-id",
|
||||||
|
}
|
||||||
|
a := &Artifact{
|
||||||
|
image: i}
|
||||||
|
expected := "test-id-value"
|
||||||
|
|
||||||
|
if a.Id() != expected {
|
||||||
|
t.Fatalf("artifact ID should match: %v", expected)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestArtifact_String(t *testing.T) {
|
||||||
|
i := &compute.Image{
|
||||||
|
Id: "test-id-value",
|
||||||
|
FolderId: "test-folder-id",
|
||||||
|
Name: "test-name",
|
||||||
|
Family: "test-family",
|
||||||
|
}
|
||||||
|
a := &Artifact{
|
||||||
|
image: i}
|
||||||
|
expected := "A disk image was created: test-name (id: test-id-value) with family name test-family"
|
||||||
|
|
||||||
|
if a.String() != expected {
|
||||||
|
t.Fatalf("artifact string should match: %v", expected)
|
||||||
|
}
|
||||||
|
}
|
|
@ -8,6 +8,8 @@ import (
|
||||||
"github.com/hashicorp/packer/helper/communicator"
|
"github.com/hashicorp/packer/helper/communicator"
|
||||||
"github.com/hashicorp/packer/helper/multistep"
|
"github.com/hashicorp/packer/helper/multistep"
|
||||||
"github.com/hashicorp/packer/packer"
|
"github.com/hashicorp/packer/packer"
|
||||||
|
|
||||||
|
"github.com/yandex-cloud/go-genproto/yandex/cloud/compute/v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
// The unique ID for this builder.
|
// The unique ID for this builder.
|
||||||
|
@ -30,9 +32,9 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run executes a yandex Packer build and returns a packer.Artifact
|
// Run executes a yandex Packer build and returns a packer.Artifact
|
||||||
// representing a Yandex Cloud machine image.
|
// representing a Yandex.Cloud compute image.
|
||||||
func (b *Builder) Run(ui packer.Ui, hook packer.Hook) (packer.Artifact, error) {
|
func (b *Builder) Run(ui packer.Ui, hook packer.Hook) (packer.Artifact, error) {
|
||||||
driver, err := NewDriverYandexCloud(ui, b.config)
|
driver, err := NewDriverYC(ui, b.config)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -66,9 +68,7 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook) (packer.Artifact, error) {
|
||||||
&common.StepCleanupTempKeys{
|
&common.StepCleanupTempKeys{
|
||||||
Comm: &b.config.Communicator,
|
Comm: &b.config.Communicator,
|
||||||
},
|
},
|
||||||
&stepTeardownInstance{
|
&stepTeardownInstance{},
|
||||||
Debug: b.config.PackerDebug,
|
|
||||||
},
|
|
||||||
&stepCreateImage{},
|
&stepCreateImage{},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -80,16 +80,15 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook) (packer.Artifact, error) {
|
||||||
if rawErr, ok := state.GetOk("error"); ok {
|
if rawErr, ok := state.GetOk("error"); ok {
|
||||||
return nil, rawErr.(error)
|
return nil, rawErr.(error)
|
||||||
}
|
}
|
||||||
if _, ok := state.GetOk("image_id"); !ok {
|
|
||||||
log.Println("Failed to find image_id in state. Bug?")
|
image, ok := state.GetOk("image")
|
||||||
return nil, nil
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("Failed to find 'image' in state. Bug?")
|
||||||
}
|
}
|
||||||
|
|
||||||
artifact := &ArtifactMini{
|
artifact := &Artifact{
|
||||||
imageID: state.Get("image_id").(string),
|
image: image.(*compute.Image),
|
||||||
imageName: state.Get("image_name").(string),
|
config: b.config,
|
||||||
imageFamily: state.Get("image_family").(string),
|
|
||||||
config: b.config,
|
|
||||||
}
|
}
|
||||||
return artifact, nil
|
return artifact, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
package yandex
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/hashicorp/packer/packer"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestBuilder_ImplementsBuilder(t *testing.T) {
|
||||||
|
var raw interface{} = &Builder{}
|
||||||
|
if _, ok := raw.(packer.Builder); !ok {
|
||||||
|
t.Fatalf("Builder should be a builder")
|
||||||
|
}
|
||||||
|
}
|
|
@ -27,37 +27,36 @@ type Config struct {
|
||||||
Communicator communicator.Config `mapstructure:",squash"`
|
Communicator communicator.Config `mapstructure:",squash"`
|
||||||
|
|
||||||
Endpoint string `mapstructure:"endpoint"`
|
Endpoint string `mapstructure:"endpoint"`
|
||||||
Token string `mapstructure:"token"`
|
|
||||||
ServiceAccountKeyFile string `mapstructure:"service_account_key_file"`
|
|
||||||
FolderID string `mapstructure:"folder_id"`
|
FolderID string `mapstructure:"folder_id"`
|
||||||
Zone string `mapstructure:"zone"`
|
ServiceAccountKeyFile string `mapstructure:"service_account_key_file"`
|
||||||
|
Token string `mapstructure:"token"`
|
||||||
|
|
||||||
SerialLogFile string `mapstructure:"serial_log_file"`
|
DiskName string `mapstructure:"disk_name"`
|
||||||
InstanceCores int `mapstructure:"instance_cores"`
|
|
||||||
InstanceMemory int `mapstructure:"instance_mem_gb"`
|
|
||||||
DiskSizeGb int `mapstructure:"disk_size_gb"`
|
DiskSizeGb int `mapstructure:"disk_size_gb"`
|
||||||
DiskType string `mapstructure:"disk_type"`
|
DiskType string `mapstructure:"disk_type"`
|
||||||
SubnetID string `mapstructure:"subnet_id"`
|
|
||||||
ImageName string `mapstructure:"image_name"`
|
|
||||||
ImageFamily string `mapstructure:"image_family"`
|
|
||||||
ImageDescription string `mapstructure:"image_description"`
|
ImageDescription string `mapstructure:"image_description"`
|
||||||
|
ImageFamily string `mapstructure:"image_family"`
|
||||||
ImageLabels map[string]string `mapstructure:"image_labels"`
|
ImageLabels map[string]string `mapstructure:"image_labels"`
|
||||||
|
ImageName string `mapstructure:"image_name"`
|
||||||
ImageProductIDs []string `mapstructure:"image_product_ids"`
|
ImageProductIDs []string `mapstructure:"image_product_ids"`
|
||||||
|
InstanceCores int `mapstructure:"instance_cores"`
|
||||||
|
InstanceMemory int `mapstructure:"instance_mem_gb"`
|
||||||
InstanceName string `mapstructure:"instance_name"`
|
InstanceName string `mapstructure:"instance_name"`
|
||||||
Labels map[string]string `mapstructure:"labels"`
|
Labels map[string]string `mapstructure:"labels"`
|
||||||
DiskName string `mapstructure:"disk_name"`
|
PlatformID string `mapstructure:"platform_id"`
|
||||||
MachineType string `mapstructure:"machine_type"`
|
|
||||||
Metadata map[string]string `mapstructure:"metadata"`
|
Metadata map[string]string `mapstructure:"metadata"`
|
||||||
SourceImageID string `mapstructure:"source_image_id"`
|
SerialLogFile string `mapstructure:"serial_log_file"`
|
||||||
SourceImageFamily string `mapstructure:"source_image_family"`
|
SourceImageFamily string `mapstructure:"source_image_family"`
|
||||||
SourceImageFolderID string `mapstructure:"source_image_folder_id"`
|
SourceImageFolderID string `mapstructure:"source_image_folder_id"`
|
||||||
UseInternalIP bool `mapstructure:"use_internal_ip"`
|
SourceImageID string `mapstructure:"source_image_id"`
|
||||||
|
SubnetID string `mapstructure:"subnet_id"`
|
||||||
UseIPv4Nat bool `mapstructure:"use_ipv4_nat"`
|
UseIPv4Nat bool `mapstructure:"use_ipv4_nat"`
|
||||||
UseIPv6 bool `mapstructure:"use_ipv6"`
|
UseIPv6 bool `mapstructure:"use_ipv6"`
|
||||||
|
UseInternalIP bool `mapstructure:"use_internal_ip"`
|
||||||
|
Zone string `mapstructure:"zone"`
|
||||||
|
|
||||||
|
ctx interpolate.Context
|
||||||
StateTimeout time.Duration `mapstructure:"state_timeout"`
|
StateTimeout time.Duration `mapstructure:"state_timeout"`
|
||||||
|
|
||||||
ctx interpolate.Context
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewConfig(raws ...interface{}) (*Config, []string, error) {
|
func NewConfig(raws ...interface{}) (*Config, []string, error) {
|
||||||
|
@ -132,8 +131,8 @@ func NewConfig(raws ...interface{}) (*Config, []string, error) {
|
||||||
c.DiskName = c.InstanceName + "-disk"
|
c.DiskName = c.InstanceName + "-disk"
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.MachineType == "" {
|
if c.PlatformID == "" {
|
||||||
c.MachineType = "standard-v1"
|
c.PlatformID = "standard-v1"
|
||||||
}
|
}
|
||||||
|
|
||||||
if es := c.Communicator.Prepare(&c.ctx); len(es) > 0 {
|
if es := c.Communicator.Prepare(&c.ctx); len(es) > 0 {
|
||||||
|
@ -141,7 +140,6 @@ func NewConfig(raws ...interface{}) (*Config, []string, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Process required parameters.
|
// Process required parameters.
|
||||||
|
|
||||||
if c.SourceImageID == "" && c.SourceImageFamily == "" {
|
if c.SourceImageID == "" && c.SourceImageFamily == "" {
|
||||||
errs = packer.MultiErrorAppend(
|
errs = packer.MultiErrorAppend(
|
||||||
errs, errors.New("a source_image_id or source_image_family must be specified"))
|
errs, errors.New("a source_image_id or source_image_family must be specified"))
|
||||||
|
|
|
@ -197,7 +197,6 @@ func TestZone(t *testing.T) {
|
||||||
// Helper stuff below
|
// Helper stuff below
|
||||||
|
|
||||||
func testConfig(t *testing.T) (config map[string]interface{}) {
|
func testConfig(t *testing.T) (config map[string]interface{}) {
|
||||||
|
|
||||||
config = map[string]interface{}{
|
config = map[string]interface{}{
|
||||||
"token": "test_token",
|
"token": "test_token",
|
||||||
"folder_id": "hashicorp",
|
"folder_id": "hashicorp",
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
package yandex
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
ycsdk "github.com/yandex-cloud/go-sdk"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Driver interface {
|
||||||
|
DeleteImage(id string) error
|
||||||
|
SDK() *ycsdk.SDK
|
||||||
|
GetImage(imageID string) (*Image, error)
|
||||||
|
GetImageFromFolder(ctx context.Context, folderID string, family string) (*Image, error)
|
||||||
|
DeleteDisk(ctx context.Context, diskID string) error
|
||||||
|
DeleteInstance(ctx context.Context, instanceID string) error
|
||||||
|
DeleteSubnet(ctx context.Context, subnetID string) error
|
||||||
|
DeleteNetwork(ctx context.Context, networkID string) error
|
||||||
|
}
|
|
@ -11,64 +11,19 @@ import (
|
||||||
|
|
||||||
"github.com/yandex-cloud/go-genproto/yandex/cloud/compute/v1"
|
"github.com/yandex-cloud/go-genproto/yandex/cloud/compute/v1"
|
||||||
"github.com/yandex-cloud/go-genproto/yandex/cloud/endpoint"
|
"github.com/yandex-cloud/go-genproto/yandex/cloud/endpoint"
|
||||||
|
"github.com/yandex-cloud/go-genproto/yandex/cloud/vpc/v1"
|
||||||
ycsdk "github.com/yandex-cloud/go-sdk"
|
ycsdk "github.com/yandex-cloud/go-sdk"
|
||||||
"github.com/yandex-cloud/go-sdk/iamkey"
|
"github.com/yandex-cloud/go-sdk/iamkey"
|
||||||
"github.com/yandex-cloud/go-sdk/pkg/requestid"
|
"github.com/yandex-cloud/go-sdk/pkg/requestid"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Driver interface {
|
|
||||||
DeleteImage(id string) error
|
|
||||||
SDK() *ycsdk.SDK
|
|
||||||
GetImage(imageID string) (*Image, error)
|
|
||||||
GetImageFromFolder(ctx context.Context, folderID string, family string) (*Image, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
type driverYC struct {
|
type driverYC struct {
|
||||||
sdk *ycsdk.SDK
|
sdk *ycsdk.SDK
|
||||||
ui packer.Ui
|
ui packer.Ui
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *driverYC) GetImage(imageID string) (*Image, error) {
|
func NewDriverYC(ui packer.Ui, config *Config) (Driver, error) {
|
||||||
image, err := d.sdk.Compute().Image().Get(context.Background(), &compute.GetImageRequest{
|
log.Printf("[INFO] Initialize Yandex.Cloud client...")
|
||||||
ImageId: imageID,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return &Image{
|
|
||||||
ID: image.Id,
|
|
||||||
Labels: image.Labels,
|
|
||||||
Licenses: image.ProductIds,
|
|
||||||
Name: image.Name,
|
|
||||||
FolderID: image.FolderId,
|
|
||||||
MinDiskSizeGb: toGigabytes(image.MinDiskSize),
|
|
||||||
SizeGb: toGigabytes(image.StorageSize),
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *driverYC) GetImageFromFolder(ctx context.Context, folderID string, family string) (*Image, error) {
|
|
||||||
image, err := d.sdk.Compute().Image().GetLatestByFamily(ctx, &compute.GetImageLatestByFamilyRequest{
|
|
||||||
FolderId: folderID,
|
|
||||||
Family: family,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return &Image{
|
|
||||||
ID: image.Id,
|
|
||||||
Labels: image.Labels,
|
|
||||||
Licenses: image.ProductIds,
|
|
||||||
Name: image.Name,
|
|
||||||
FolderID: image.FolderId,
|
|
||||||
MinDiskSizeGb: toGigabytes(image.MinDiskSize),
|
|
||||||
SizeGb: toGigabytes(image.StorageSize),
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewDriverYandexCloud(ui packer.Ui, config *Config) (Driver, error) {
|
|
||||||
log.Printf("[INFO] Initialize Yandex Cloud client...")
|
|
||||||
|
|
||||||
sdkConfig := ycsdk.Config{}
|
sdkConfig := ycsdk.Config{}
|
||||||
|
|
||||||
|
@ -115,10 +70,134 @@ func NewDriverYandexCloud(ui packer.Ui, config *Config) (Driver, error) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d *driverYC) GetImage(imageID string) (*Image, error) {
|
||||||
|
image, err := d.sdk.Compute().Image().Get(context.Background(), &compute.GetImageRequest{
|
||||||
|
ImageId: imageID,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &Image{
|
||||||
|
ID: image.Id,
|
||||||
|
Labels: image.Labels,
|
||||||
|
Licenses: image.ProductIds,
|
||||||
|
Name: image.Name,
|
||||||
|
FolderID: image.FolderId,
|
||||||
|
MinDiskSizeGb: toGigabytes(image.MinDiskSize),
|
||||||
|
SizeGb: toGigabytes(image.StorageSize),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *driverYC) GetImageFromFolder(ctx context.Context, folderID string, family string) (*Image, error) {
|
||||||
|
image, err := d.sdk.Compute().Image().GetLatestByFamily(ctx, &compute.GetImageLatestByFamilyRequest{
|
||||||
|
FolderId: folderID,
|
||||||
|
Family: family,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &Image{
|
||||||
|
ID: image.Id,
|
||||||
|
Labels: image.Labels,
|
||||||
|
Licenses: image.ProductIds,
|
||||||
|
Name: image.Name,
|
||||||
|
FolderID: image.FolderId,
|
||||||
|
Family: image.Family,
|
||||||
|
MinDiskSizeGb: toGigabytes(image.MinDiskSize),
|
||||||
|
SizeGb: toGigabytes(image.StorageSize),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (d *driverYC) DeleteImage(ID string) error {
|
func (d *driverYC) DeleteImage(ID string) error {
|
||||||
return nil
|
ctx := context.TODO()
|
||||||
|
op, err := d.sdk.WrapOperation(d.sdk.Compute().Image().Delete(ctx, &compute.DeleteImageRequest{
|
||||||
|
ImageId: ID,
|
||||||
|
}))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = op.Wait(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = op.Response()
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *driverYC) SDK() *ycsdk.SDK {
|
func (d *driverYC) SDK() *ycsdk.SDK {
|
||||||
return d.sdk
|
return d.sdk
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d *driverYC) DeleteInstance(ctx context.Context, instanceID string) error {
|
||||||
|
op, err := d.sdk.WrapOperation(d.sdk.Compute().Instance().Delete(ctx, &compute.DeleteInstanceRequest{
|
||||||
|
InstanceId: instanceID,
|
||||||
|
}))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = op.Wait(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = op.Response()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *driverYC) DeleteSubnet(ctx context.Context, subnetID string) error {
|
||||||
|
op, err := d.sdk.WrapOperation(d.sdk.VPC().Subnet().Delete(ctx, &vpc.DeleteSubnetRequest{
|
||||||
|
SubnetId: subnetID,
|
||||||
|
}))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = op.Wait(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = op.Response()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *driverYC) DeleteNetwork(ctx context.Context, networkID string) error {
|
||||||
|
op, err := d.sdk.WrapOperation(d.sdk.VPC().Network().Delete(ctx, &vpc.DeleteNetworkRequest{
|
||||||
|
NetworkId: networkID,
|
||||||
|
}))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = op.Wait(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = op.Response()
|
||||||
|
return err
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *driverYC) DeleteDisk(ctx context.Context, diskID string) error {
|
||||||
|
op, err := d.sdk.WrapOperation(d.sdk.Compute().Disk().Delete(ctx, &compute.DeleteDiskRequest{
|
||||||
|
DiskId: diskID,
|
||||||
|
}))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = op.Wait(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = op.Response()
|
||||||
|
return err
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -7,5 +7,6 @@ type Image struct {
|
||||||
Licenses []string
|
Licenses []string
|
||||||
MinDiskSizeGb int
|
MinDiskSizeGb int
|
||||||
Name string
|
Name string
|
||||||
|
Family string
|
||||||
SizeGb int
|
SizeGb int
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,10 +60,7 @@ func (stepCreateImage) Run(ctx context.Context, state multistep.StateBag) multis
|
||||||
log.Printf("Image Family: %s", image.Family)
|
log.Printf("Image Family: %s", image.Family)
|
||||||
log.Printf("Image Description: %s", image.Description)
|
log.Printf("Image Description: %s", image.Description)
|
||||||
log.Printf("Image Storage size: %d", image.StorageSize)
|
log.Printf("Image Storage size: %d", image.StorageSize)
|
||||||
state.Put("image_id", image.Id)
|
state.Put("image", image)
|
||||||
state.Put("image_name", c.ImageName)
|
|
||||||
state.Put("image_family", c.ImageFamily)
|
|
||||||
state.Put("image_description", c.ImageDescription)
|
|
||||||
|
|
||||||
return multistep.ActionContinue
|
return multistep.ActionContinue
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,6 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/c2h5oh/datasize"
|
"github.com/c2h5oh/datasize"
|
||||||
"github.com/hashicorp/packer/common/uuid"
|
"github.com/hashicorp/packer/common/uuid"
|
||||||
|
@ -17,12 +16,11 @@ import (
|
||||||
ycsdk "github.com/yandex-cloud/go-sdk"
|
ycsdk "github.com/yandex-cloud/go-sdk"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const StandardImagesFolderID = "standard-images"
|
||||||
|
|
||||||
type stepCreateInstance struct {
|
type stepCreateInstance struct {
|
||||||
Debug bool
|
Debug bool
|
||||||
SerialLogFile string
|
SerialLogFile string
|
||||||
cleanupInstanceID string
|
|
||||||
cleanupNetworkID string
|
|
||||||
cleanupSubnetID string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func createNetwork(ctx context.Context, c *Config, d Driver) (*vpc.Network, error) {
|
func createNetwork(ctx context.Context, c *Config, d Driver) (*vpc.Network, error) {
|
||||||
|
@ -81,11 +79,11 @@ func createSubnet(ctx context.Context, c *Config, d Driver, networkID string) (*
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
network, ok := resp.(*vpc.Subnet)
|
subnet, ok := resp.(*vpc.Subnet)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, errors.New("subnet create operation response doesn't contain Network")
|
return nil, errors.New("subnet create operation response doesn't contain Subnet")
|
||||||
}
|
}
|
||||||
return network, nil
|
return subnet, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func getImage(ctx context.Context, c *Config, d Driver) (*Image, error) {
|
func getImage(ctx context.Context, c *Config, d Driver) (*Image, error) {
|
||||||
|
@ -97,63 +95,61 @@ func getImage(ctx context.Context, c *Config, d Driver) (*Image, error) {
|
||||||
if c.SourceImageFolderID != "" {
|
if c.SourceImageFolderID != "" {
|
||||||
return d.GetImageFromFolder(ctx, c.SourceImageFolderID, familyName)
|
return d.GetImageFromFolder(ctx, c.SourceImageFolderID, familyName)
|
||||||
}
|
}
|
||||||
return d.GetImageFromFolder(ctx, "standard-images", familyName)
|
return d.GetImageFromFolder(ctx, StandardImagesFolderID, familyName)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *stepCreateInstance) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
|
func (s *stepCreateInstance) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
|
||||||
sdk := state.Get("sdk").(*ycsdk.SDK)
|
sdk := state.Get("sdk").(*ycsdk.SDK)
|
||||||
ui := state.Get("ui").(packer.Ui)
|
ui := state.Get("ui").(packer.Ui)
|
||||||
c := state.Get("config").(*Config)
|
config := state.Get("config").(*Config)
|
||||||
d := state.Get("driver").(Driver)
|
driver := state.Get("driver").(Driver)
|
||||||
|
|
||||||
ctx, cancel := context.WithTimeout(ctx, c.StateTimeout)
|
ctx, cancel := context.WithTimeout(ctx, config.StateTimeout)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
// create or reuse network configuration
|
sourceImage, err := getImage(ctx, config, driver)
|
||||||
instanceSubnetID := ""
|
|
||||||
if c.SubnetID == "" {
|
|
||||||
// create Network and Subnet
|
|
||||||
ui.Say("Creating network...")
|
|
||||||
network, err := createNetwork(ctx, c, d)
|
|
||||||
if err != nil {
|
|
||||||
return stepHaltWithError(state, fmt.Errorf("Error creating network: %s", err))
|
|
||||||
}
|
|
||||||
state.Put("network_id", network.Id)
|
|
||||||
s.cleanupNetworkID = network.Id
|
|
||||||
|
|
||||||
ui.Say(fmt.Sprintf("Creating subnet in zone %q...", c.Zone))
|
|
||||||
subnet, err := createSubnet(ctx, c, d, network.Id)
|
|
||||||
if err != nil {
|
|
||||||
return stepHaltWithError(state, fmt.Errorf("Error creating subnet: %s", err))
|
|
||||||
}
|
|
||||||
state.Put("subnet_id", subnet.Id)
|
|
||||||
instanceSubnetID = subnet.Id
|
|
||||||
// save for cleanup
|
|
||||||
s.cleanupSubnetID = subnet.Id
|
|
||||||
} else {
|
|
||||||
ui.Say("Use provided subnet id " + c.SubnetID)
|
|
||||||
instanceSubnetID = c.SubnetID
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create an instance based on the configuration
|
|
||||||
ui.Say("Creating instance...")
|
|
||||||
sourceImage, err := getImage(ctx, c, d)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return stepHaltWithError(state, fmt.Errorf("Error getting source image for instance creation: %s", err))
|
return stepHaltWithError(state, fmt.Errorf("Error getting source image for instance creation: %s", err))
|
||||||
}
|
}
|
||||||
|
|
||||||
if sourceImage.MinDiskSizeGb > c.DiskSizeGb {
|
if sourceImage.MinDiskSizeGb > config.DiskSizeGb {
|
||||||
return stepHaltWithError(state, fmt.Errorf("Instance DiskSizeGb (%d) should be equal or greater "+
|
return stepHaltWithError(state, fmt.Errorf("Instance DiskSizeGb (%d) should be equal or greater "+
|
||||||
"than SourceImage disk requirement (%d)", c.DiskSizeGb, sourceImage.MinDiskSizeGb))
|
"than SourceImage disk requirement (%d)", config.DiskSizeGb, sourceImage.MinDiskSizeGb))
|
||||||
}
|
}
|
||||||
|
|
||||||
instanceMetadata, err := c.createInstanceMetadata(string(c.Communicator.SSHPublicKey))
|
ui.Say(fmt.Sprintf("Using as source image: %s (name: %q, family: %q)", sourceImage.ID, sourceImage.Name, sourceImage.Family))
|
||||||
if err != nil {
|
|
||||||
return stepHaltWithError(state, fmt.Errorf("instance metadata prepare error: %s", err))
|
// create or reuse network configuration
|
||||||
|
instanceSubnetID := ""
|
||||||
|
if config.SubnetID == "" {
|
||||||
|
// create Network and Subnet
|
||||||
|
ui.Say("Creating network...")
|
||||||
|
network, err := createNetwork(ctx, config, driver)
|
||||||
|
if err != nil {
|
||||||
|
return stepHaltWithError(state, fmt.Errorf("Error creating network: %s", err))
|
||||||
|
}
|
||||||
|
state.Put("network_id", network.Id)
|
||||||
|
|
||||||
|
ui.Say(fmt.Sprintf("Creating subnet in zone %q...", config.Zone))
|
||||||
|
subnet, err := createSubnet(ctx, config, driver, network.Id)
|
||||||
|
if err != nil {
|
||||||
|
return stepHaltWithError(state, fmt.Errorf("Error creating subnet: %s", err))
|
||||||
|
}
|
||||||
|
instanceSubnetID = subnet.Id
|
||||||
|
// save for cleanup
|
||||||
|
state.Put("subnet_id", subnet.Id)
|
||||||
|
} else {
|
||||||
|
ui.Say("Use provided subnet id " + config.SubnetID)
|
||||||
|
instanceSubnetID = config.SubnetID
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Create an instance based on the configuration
|
||||||
|
ui.Say("Creating instance...")
|
||||||
|
|
||||||
|
instanceMetadata := config.createInstanceMetadata(string(config.Communicator.SSHPublicKey))
|
||||||
|
|
||||||
// TODO make part metadata prepare process
|
// TODO make part metadata prepare process
|
||||||
if c.UseIPv6 {
|
if config.UseIPv6 {
|
||||||
// this ugly hack will replace user provided 'user-data'
|
// this ugly hack will replace user provided 'user-data'
|
||||||
userData := `#cloud-config
|
userData := `#cloud-config
|
||||||
runcmd:
|
runcmd:
|
||||||
|
@ -163,23 +159,23 @@ runcmd:
|
||||||
}
|
}
|
||||||
|
|
||||||
req := &compute.CreateInstanceRequest{
|
req := &compute.CreateInstanceRequest{
|
||||||
FolderId: c.FolderID,
|
FolderId: config.FolderID,
|
||||||
Name: c.InstanceName,
|
Name: config.InstanceName,
|
||||||
Labels: c.Labels,
|
Labels: config.Labels,
|
||||||
ZoneId: c.Zone,
|
ZoneId: config.Zone,
|
||||||
PlatformId: "standard-v1",
|
PlatformId: config.PlatformID,
|
||||||
ResourcesSpec: &compute.ResourcesSpec{
|
ResourcesSpec: &compute.ResourcesSpec{
|
||||||
Memory: toBytes(c.InstanceMemory),
|
Memory: toBytes(config.InstanceMemory),
|
||||||
Cores: int64(c.InstanceCores),
|
Cores: int64(config.InstanceCores),
|
||||||
},
|
},
|
||||||
Metadata: instanceMetadata,
|
Metadata: instanceMetadata,
|
||||||
BootDiskSpec: &compute.AttachedDiskSpec{
|
BootDiskSpec: &compute.AttachedDiskSpec{
|
||||||
AutoDelete: false,
|
AutoDelete: false,
|
||||||
Disk: &compute.AttachedDiskSpec_DiskSpec_{
|
Disk: &compute.AttachedDiskSpec_DiskSpec_{
|
||||||
DiskSpec: &compute.AttachedDiskSpec_DiskSpec{
|
DiskSpec: &compute.AttachedDiskSpec_DiskSpec{
|
||||||
Name: c.DiskName,
|
Name: config.DiskName,
|
||||||
TypeId: c.DiskType,
|
TypeId: config.DiskType,
|
||||||
Size: int64((datasize.ByteSize(c.DiskSizeGb) * datasize.GB).Bytes()),
|
Size: int64((datasize.ByteSize(config.DiskSizeGb) * datasize.GB).Bytes()),
|
||||||
Source: &compute.AttachedDiskSpec_DiskSpec_ImageId{
|
Source: &compute.AttachedDiskSpec_DiskSpec_ImageId{
|
||||||
ImageId: sourceImage.ID,
|
ImageId: sourceImage.ID,
|
||||||
},
|
},
|
||||||
|
@ -194,11 +190,11 @@ runcmd:
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.UseIPv6 {
|
if config.UseIPv6 {
|
||||||
req.NetworkInterfaceSpecs[0].PrimaryV6AddressSpec = &compute.PrimaryAddressSpec{}
|
req.NetworkInterfaceSpecs[0].PrimaryV6AddressSpec = &compute.PrimaryAddressSpec{}
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.UseIPv4Nat {
|
if config.UseIPv4Nat {
|
||||||
req.NetworkInterfaceSpecs[0].PrimaryV4AddressSpec = &compute.PrimaryAddressSpec{
|
req.NetworkInterfaceSpecs[0].PrimaryV4AddressSpec = &compute.PrimaryAddressSpec{
|
||||||
OneToOneNatSpec: &compute.OneToOneNatSpec{
|
OneToOneNatSpec: &compute.OneToOneNatSpec{
|
||||||
IpVersion: compute.IpVersion_IPV4,
|
IpVersion: compute.IpVersion_IPV4,
|
||||||
|
@ -211,6 +207,17 @@ runcmd:
|
||||||
return stepHaltWithError(state, fmt.Errorf("Error create instance: %s", err))
|
return stepHaltWithError(state, fmt.Errorf("Error create instance: %s", err))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
opMetadata, err := op.Metadata()
|
||||||
|
if err != nil {
|
||||||
|
return stepHaltWithError(state, fmt.Errorf("Error get create operation metadata: %s", err))
|
||||||
|
}
|
||||||
|
|
||||||
|
if cimd, ok := opMetadata.(*compute.CreateInstanceMetadata); ok {
|
||||||
|
state.Put("instance_id", cimd.InstanceId)
|
||||||
|
} else {
|
||||||
|
return stepHaltWithError(state, fmt.Errorf("could not get Instance ID from operation metadata"))
|
||||||
|
}
|
||||||
|
|
||||||
err = op.Wait(ctx)
|
err = op.Wait(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return stepHaltWithError(state, fmt.Errorf("Error create instance: %s", err))
|
return stepHaltWithError(state, fmt.Errorf("Error create instance: %s", err))
|
||||||
|
@ -226,137 +233,101 @@ runcmd:
|
||||||
return stepHaltWithError(state, fmt.Errorf("response doesn't contain Instance"))
|
return stepHaltWithError(state, fmt.Errorf("response doesn't contain Instance"))
|
||||||
}
|
}
|
||||||
|
|
||||||
// We use this in cleanup
|
state.Put("disk_id", instance.BootDisk.DiskId)
|
||||||
s.cleanupInstanceID = instance.Id
|
|
||||||
|
|
||||||
if s.Debug {
|
if s.Debug {
|
||||||
ui.Message(fmt.Sprintf("Instance ID %s started. Current instance status %s", instance.Id, instance.Status))
|
ui.Message(fmt.Sprintf("Instance ID %s started. Current instance status %s", instance.Id, instance.Status))
|
||||||
|
ui.Message(fmt.Sprintf("Disk ID %s. ", instance.BootDisk.DiskId))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Store the instance id for later
|
|
||||||
state.Put("instance_id", instance.Id)
|
|
||||||
state.Put("disk_id", instance.BootDisk.DiskId)
|
|
||||||
|
|
||||||
return multistep.ActionContinue
|
return multistep.ActionContinue
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *stepCreateInstance) Cleanup(state multistep.StateBag) {
|
func (s *stepCreateInstance) Cleanup(state multistep.StateBag) {
|
||||||
// If the cleanupInstanceID isn't there, we probably never created it
|
config := state.Get("config").(*Config)
|
||||||
if s.cleanupInstanceID == "" {
|
driver := state.Get("driver").(Driver)
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
c := state.Get("config").(*Config)
|
|
||||||
ui := state.Get("ui").(packer.Ui)
|
ui := state.Get("ui").(packer.Ui)
|
||||||
|
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), config.StateTimeout)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
if s.SerialLogFile != "" {
|
if s.SerialLogFile != "" {
|
||||||
ui.Say("Current state 'cancelled' or 'halted'...")
|
ui.Say("Current state 'cancelled' or 'halted'...")
|
||||||
err := s.writeSerialLogFile(state)
|
err := s.writeSerialLogFile(ctx, state)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ui.Error(err.Error())
|
ui.Error(err.Error())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), c.StateTimeout)
|
instanceIDRaw, ok := state.GetOk("instance_id")
|
||||||
defer cancel()
|
if ok {
|
||||||
|
instanceID := instanceIDRaw.(string)
|
||||||
if s.cleanupSubnetID != "" {
|
if instanceID != "" {
|
||||||
// Destroy the subnet we just created
|
ui.Say("Destroying instance...")
|
||||||
ui.Say("Destroying subnet...")
|
err := driver.DeleteInstance(ctx, instanceID)
|
||||||
err := deleteSubnet(ctx, s.cleanupSubnetID, state)
|
if err != nil {
|
||||||
if err != nil {
|
ui.Error(fmt.Sprintf(
|
||||||
ui.Error(fmt.Sprintf(
|
"Error destroying instance (id: %s). Please destroy it manually: %s", instanceID, err))
|
||||||
"Error destroying subnet (id: %s). Please destroy it manually: %s", s.cleanupSubnetID, err))
|
}
|
||||||
}
|
ui.Message("Instance has been destroyed!")
|
||||||
|
|
||||||
// some sleep before delete network
|
|
||||||
time.Sleep(10 * time.Second)
|
|
||||||
|
|
||||||
// Destroy the network we just created
|
|
||||||
ui.Say("Destroying network...")
|
|
||||||
err = deleteNetwork(ctx, s.cleanupNetworkID, state)
|
|
||||||
if err != nil {
|
|
||||||
ui.Error(fmt.Sprintf(
|
|
||||||
"Error destroying network (id: %s). Please destroy it manually: %s", s.cleanupNetworkID, err))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ui.Say("Destroying boot disk...")
|
subnetIDRaw, ok := state.GetOk("subnet_id")
|
||||||
diskID := state.Get("disk_id").(string)
|
if ok {
|
||||||
err := deleteDisk(ctx, diskID, state)
|
subnetID := subnetIDRaw.(string)
|
||||||
if err != nil {
|
if subnetID != "" {
|
||||||
ui.Error(fmt.Sprintf(
|
// Destroy the subnet we just created
|
||||||
"Error destroying boot disk (id: %s). Please destroy it manually: %s", s.cleanupNetworkID, err))
|
ui.Say("Destroying subnet...")
|
||||||
|
err := driver.DeleteSubnet(ctx, subnetID)
|
||||||
|
if err != nil {
|
||||||
|
ui.Error(fmt.Sprintf(
|
||||||
|
"Error destroying subnet (id: %s). Please destroy it manually: %s", subnetID, err))
|
||||||
|
}
|
||||||
|
ui.Message("Subnet has been deleted!")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Destroy the network we just created
|
||||||
|
networkIDRaw, ok := state.GetOk("network_id")
|
||||||
|
if ok {
|
||||||
|
networkID := networkIDRaw.(string)
|
||||||
|
if networkID != "" {
|
||||||
|
// Destroy the network we just created
|
||||||
|
ui.Say("Destroying network...")
|
||||||
|
err := driver.DeleteNetwork(ctx, networkID)
|
||||||
|
if err != nil {
|
||||||
|
ui.Error(fmt.Sprintf(
|
||||||
|
"Error destroying network (id: %s). Please destroy it manually: %s", networkID, err))
|
||||||
|
}
|
||||||
|
ui.Message("Network has been deleted!")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
diskIDRaw, ok := state.GetOk("disk_id")
|
||||||
|
if ok {
|
||||||
|
ui.Say("Destroying boot disk...")
|
||||||
|
diskID := diskIDRaw.(string)
|
||||||
|
err := driver.DeleteDisk(ctx, diskID)
|
||||||
|
if err != nil {
|
||||||
|
ui.Error(fmt.Sprintf(
|
||||||
|
"Error destroying boot disk (id: %s). Please destroy it manually: %s", diskID, err))
|
||||||
|
}
|
||||||
|
ui.Message("Disk has been deleted!")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func deleteSubnet(ctx context.Context, subnetID string, state multistep.StateBag) error {
|
func (s *stepCreateInstance) writeSerialLogFile(ctx context.Context, state multistep.StateBag) error {
|
||||||
sdk := state.Get("sdk").(*ycsdk.SDK)
|
|
||||||
|
|
||||||
op, err := sdk.WrapOperation(sdk.VPC().Subnet().Delete(ctx, &vpc.DeleteSubnetRequest{
|
|
||||||
SubnetId: subnetID,
|
|
||||||
}))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = op.Wait(ctx)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = op.Response()
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func deleteNetwork(ctx context.Context, networkID string, state multistep.StateBag) error {
|
|
||||||
sdk := state.Get("sdk").(*ycsdk.SDK)
|
|
||||||
|
|
||||||
op, err := sdk.WrapOperation(sdk.VPC().Network().Delete(ctx, &vpc.DeleteNetworkRequest{
|
|
||||||
NetworkId: networkID,
|
|
||||||
}))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = op.Wait(ctx)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = op.Response()
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func deleteDisk(ctx context.Context, diskID string, state multistep.StateBag) error {
|
|
||||||
sdk := state.Get("sdk").(*ycsdk.SDK)
|
|
||||||
|
|
||||||
op, err := sdk.WrapOperation(sdk.Compute().Disk().Delete(ctx, &compute.DeleteDiskRequest{
|
|
||||||
DiskId: diskID,
|
|
||||||
}))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = op.Wait(ctx)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = op.Response()
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *stepCreateInstance) writeSerialLogFile(state multistep.StateBag) error {
|
|
||||||
sdk := state.Get("sdk").(*ycsdk.SDK)
|
sdk := state.Get("sdk").(*ycsdk.SDK)
|
||||||
ui := state.Get("ui").(packer.Ui)
|
ui := state.Get("ui").(packer.Ui)
|
||||||
|
|
||||||
ui.Say("Try get serial port output to file " + s.SerialLogFile)
|
instanceID := state.Get("instance_id").(string)
|
||||||
serialOutput, err := sdk.Compute().Instance().GetSerialPortOutput(context.Background(), &compute.GetInstanceSerialPortOutputRequest{
|
ui.Say("Try get instance's serial port output and write to file " + s.SerialLogFile)
|
||||||
InstanceId: s.cleanupInstanceID,
|
serialOutput, err := sdk.Compute().Instance().GetSerialPortOutput(ctx, &compute.GetInstanceSerialPortOutputRequest{
|
||||||
|
InstanceId: instanceID,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("Failed to get serial port output for instance (id: %s): %s", s.cleanupInstanceID, err)
|
return fmt.Errorf("Failed to get serial port output for instance (id: %s): %s", instanceID, err)
|
||||||
}
|
}
|
||||||
if err := ioutil.WriteFile(s.SerialLogFile, []byte(serialOutput.Contents), 0600); err != nil {
|
if err := ioutil.WriteFile(s.SerialLogFile, []byte(serialOutput.Contents), 0600); err != nil {
|
||||||
return fmt.Errorf("Failed to write serial port output to file: %s", err)
|
return fmt.Errorf("Failed to write serial port output to file: %s", err)
|
||||||
|
@ -365,9 +336,8 @@ func (s *stepCreateInstance) writeSerialLogFile(state multistep.StateBag) error
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Config) createInstanceMetadata(sshPublicKey string) (map[string]string, error) {
|
func (c *Config) createInstanceMetadata(sshPublicKey string) map[string]string {
|
||||||
instanceMetadata := make(map[string]string)
|
instanceMetadata := make(map[string]string)
|
||||||
var err error
|
|
||||||
|
|
||||||
// Copy metadata from config.
|
// Copy metadata from config.
|
||||||
for k, v := range c.Metadata {
|
for k, v := range c.Metadata {
|
||||||
|
@ -383,5 +353,5 @@ func (c *Config) createInstanceMetadata(sshPublicKey string) (map[string]string,
|
||||||
instanceMetadata[sshMetaKey] = sshKeys
|
instanceMetadata[sshMetaKey] = sshKeys
|
||||||
}
|
}
|
||||||
|
|
||||||
return instanceMetadata, err
|
return instanceMetadata
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,6 @@ import (
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"log"
|
"log"
|
||||||
|
|
||||||
"github.com/hashicorp/packer/common/uuid"
|
|
||||||
"github.com/hashicorp/packer/helper/multistep"
|
"github.com/hashicorp/packer/helper/multistep"
|
||||||
"github.com/hashicorp/packer/packer"
|
"github.com/hashicorp/packer/packer"
|
||||||
"golang.org/x/crypto/ssh"
|
"golang.org/x/crypto/ssh"
|
||||||
|
@ -23,11 +22,11 @@ type stepCreateSSHKey struct {
|
||||||
|
|
||||||
func (s *stepCreateSSHKey) Run(_ context.Context, state multistep.StateBag) multistep.StepAction {
|
func (s *stepCreateSSHKey) Run(_ context.Context, state multistep.StateBag) multistep.StepAction {
|
||||||
ui := state.Get("ui").(packer.Ui)
|
ui := state.Get("ui").(packer.Ui)
|
||||||
c := state.Get("config").(*Config)
|
config := state.Get("config").(*Config)
|
||||||
|
|
||||||
if c.Communicator.SSHPrivateKeyFile != "" {
|
if config.Communicator.SSHPrivateKeyFile != "" {
|
||||||
ui.Say("Using existing SSH private key")
|
ui.Say("Using existing SSH private key")
|
||||||
privateKeyBytes, err := c.Communicator.ReadSSHPrivateKeyFile()
|
privateKeyBytes, err := config.Communicator.ReadSSHPrivateKeyFile()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
state.Put("error", err)
|
state.Put("error", err)
|
||||||
return multistep.ActionHalt
|
return multistep.ActionHalt
|
||||||
|
@ -41,8 +40,8 @@ func (s *stepCreateSSHKey) Run(_ context.Context, state multistep.StateBag) mult
|
||||||
return multistep.ActionHalt
|
return multistep.ActionHalt
|
||||||
}
|
}
|
||||||
|
|
||||||
c.Communicator.SSHPublicKey = ssh.MarshalAuthorizedKey(key.PublicKey())
|
config.Communicator.SSHPublicKey = ssh.MarshalAuthorizedKey(key.PublicKey())
|
||||||
c.Communicator.SSHPrivateKey = privateKeyBytes
|
config.Communicator.SSHPrivateKey = privateKeyBytes
|
||||||
|
|
||||||
return multistep.ActionContinue
|
return multistep.ActionContinue
|
||||||
}
|
}
|
||||||
|
@ -63,33 +62,32 @@ func (s *stepCreateSSHKey) Run(_ context.Context, state multistep.StateBag) mult
|
||||||
}
|
}
|
||||||
|
|
||||||
// Marshal the public key into SSH compatible format
|
// Marshal the public key into SSH compatible format
|
||||||
// TODO properly handle the public key error
|
pub, err := ssh.NewPublicKey(&priv.PublicKey)
|
||||||
pub, _ := ssh.NewPublicKey(&priv.PublicKey)
|
if err != nil {
|
||||||
|
err = fmt.Errorf("Error creating public ssh key: %s", err)
|
||||||
|
ui.Error(err.Error())
|
||||||
|
state.Put("error", err)
|
||||||
|
return multistep.ActionHalt
|
||||||
|
}
|
||||||
pubSSHFormat := string(ssh.MarshalAuthorizedKey(pub))
|
pubSSHFormat := string(ssh.MarshalAuthorizedKey(pub))
|
||||||
|
|
||||||
// The name of the public key on DO
|
hashMD5 := ssh.FingerprintLegacyMD5(pub)
|
||||||
name := fmt.Sprintf("packer-%s", uuid.TimeOrderedUUID())
|
hashSHA256 := ssh.FingerprintSHA256(pub)
|
||||||
|
|
||||||
hashMd5 := ssh.FingerprintLegacyMD5(pub)
|
log.Printf("[INFO] md5 hash of ssh pub key: %s", hashMD5)
|
||||||
hashSha256 := ssh.FingerprintSHA256(pub)
|
log.Printf("[INFO] sha256 hash of ssh pub key: %s", hashSHA256)
|
||||||
|
|
||||||
log.Printf("[INFO] temporary ssh key name: %s", name)
|
|
||||||
log.Printf("[INFO] md5 hash of ssh pub key: %s", hashMd5)
|
|
||||||
log.Printf("[INFO] sha256 hash of ssh pub key: %s", hashSha256)
|
|
||||||
|
|
||||||
// Remember some state for the future
|
// Remember some state for the future
|
||||||
//state.Put("ssh_key_id", key.ID)
|
|
||||||
state.Put("ssh_key_public", pubSSHFormat)
|
state.Put("ssh_key_public", pubSSHFormat)
|
||||||
state.Put("ssh_key_name", name)
|
|
||||||
|
|
||||||
// Set the private key in the config for later
|
// Set the private key in the config for later
|
||||||
c.Communicator.SSHPrivateKey = pem.EncodeToMemory(&privBlk)
|
config.Communicator.SSHPrivateKey = pem.EncodeToMemory(&privBlk)
|
||||||
c.Communicator.SSHPublicKey = ssh.MarshalAuthorizedKey(pub)
|
config.Communicator.SSHPublicKey = ssh.MarshalAuthorizedKey(pub)
|
||||||
|
|
||||||
// If we're in debug mode, output the private key to the working directory.
|
// If we're in debug mode, output the private key to the working directory.
|
||||||
if s.Debug {
|
if s.Debug {
|
||||||
ui.Message(fmt.Sprintf("Saving key for debug purposes: %s", s.DebugKeyPath))
|
ui.Message(fmt.Sprintf("Saving key for debug purposes: %s", s.DebugKeyPath))
|
||||||
err := ioutil.WriteFile(s.DebugKeyPath, c.Communicator.SSHPrivateKey, 0600)
|
err := ioutil.WriteFile(s.DebugKeyPath, config.Communicator.SSHPrivateKey, 0600)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return stepHaltWithError(state, fmt.Errorf("Error saving debug key: %s", err))
|
return stepHaltWithError(state, fmt.Errorf("Error saving debug key: %s", err))
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,9 +11,7 @@ import (
|
||||||
ycsdk "github.com/yandex-cloud/go-sdk"
|
ycsdk "github.com/yandex-cloud/go-sdk"
|
||||||
)
|
)
|
||||||
|
|
||||||
type stepTeardownInstance struct {
|
type stepTeardownInstance struct{}
|
||||||
Debug bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *stepTeardownInstance) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
|
func (s *stepTeardownInstance) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
|
||||||
sdk := state.Get("sdk").(*ycsdk.SDK)
|
sdk := state.Get("sdk").(*ycsdk.SDK)
|
||||||
|
|
|
@ -76,14 +76,14 @@ can be configured for this builder.
|
||||||
|
|
||||||
- `instance_cores` (number) - The number of cores available to the instance.
|
- `instance_cores` (number) - The number of cores available to the instance.
|
||||||
|
|
||||||
- `instance_mem_gb` (number) - The amount of memory available to the instance, specified in gigabytes.
|
- `instance_mem_gb` (number) - The amount of memory available to the instance, specified in gigabytes.
|
||||||
|
|
||||||
- `disk_name` (string) - The name of the disk, if unset the instance name
|
- `disk_name` (string) - The name of the disk, if unset the instance name
|
||||||
will be used.
|
will be used.
|
||||||
|
|
||||||
- `disk_size_gb` (number) - The size of the disk in GB. This defaults to `10`, which is 10GB.
|
- `disk_size_gb` (number) - The size of the disk in GB. This defaults to `10`, which is 10GB.
|
||||||
|
|
||||||
- `disk_type` (string) - Specify disk type for the launched instance. Defaults to `network-hdd`.
|
- `disk_type` (string) - Specify disk type for the launched instance. Defaults to `network-hdd`.
|
||||||
|
|
||||||
- `image_description` (string) - The description of the resulting image.
|
- `image_description` (string) - The description of the resulting image.
|
||||||
|
|
||||||
|
@ -97,12 +97,12 @@ can be configured for this builder.
|
||||||
|
|
||||||
- `image_product_ids` (list) - License IDs that indicate which licenses are attached to resulting image.
|
- `image_product_ids` (list) - License IDs that indicate which licenses are attached to resulting image.
|
||||||
|
|
||||||
- `instance_name` (string) - The name assigned to the instance.
|
- `instance_name` (string) - The name assigned to the instance.
|
||||||
|
|
||||||
- `labels` (object of key/value strings) - Key/value pair labels to apply to
|
- `labels` (object of key/value strings) - Key/value pair labels to apply to
|
||||||
the launched instance.
|
the launched instance.
|
||||||
|
|
||||||
- `machine_type` (string) - The type of virtual machine to launch. This defaults to 'standard-v1'.
|
- `platform_id` (string) - Identifier of the hardware platform configuration for the instance. This defaults to `standard-v1`.
|
||||||
|
|
||||||
- `metadata` (object of key/value strings) - Metadata applied to the launched
|
- `metadata` (object of key/value strings) - Metadata applied to the launched
|
||||||
instance.
|
instance.
|
||||||
|
|
Loading…
Reference in New Issue