reuse common configs

This commit is contained in:
Roman Mingazeev 2020-11-30 13:27:45 +03:00
parent adb4a14471
commit 478fda12ba
32 changed files with 713 additions and 464 deletions

View File

@ -12,7 +12,10 @@ import (
"github.com/yandex-cloud/go-sdk/iamkey"
)
const defaultEndpoint = "api.cloud.yandex.net:443"
const (
defaultEndpoint = "api.cloud.yandex.net:443"
defaultMaxRetries = 3
)
// AccessConfig is for common configuration related to Yandex.Cloud API access
type AccessConfig struct {
@ -34,6 +37,10 @@ type AccessConfig struct {
func (c *AccessConfig) Prepare(ctx *interpolate.Context) []error {
var errs []error
if c.MaxRetries == 0 {
c.MaxRetries = defaultMaxRetries
}
if c.Endpoint == "" {
c.Endpoint = defaultEndpoint
}

View File

@ -87,7 +87,9 @@ func (b *Builder) Run(ctx context.Context, ui packersdk.Ui, hook packersdk.Hook)
&commonsteps.StepCleanupTempKeys{
Comm: &b.config.Communicator,
},
&StepTeardownInstance{},
&StepTeardownInstance{
SerialLogFile: b.config.SerialLogFile,
},
&stepCreateImage{
GeneratedData: generatedData,
},

View File

@ -0,0 +1,232 @@
//go:generate struct-markdown
package yandex
import (
"errors"
"fmt"
"os"
"regexp"
"github.com/hashicorp/packer/packer"
"github.com/hashicorp/packer/packer-plugin-sdk/template/interpolate"
"github.com/hashicorp/packer/packer-plugin-sdk/uuid"
)
const (
defaultPlatformID = "standard-v2"
defaultZone = "ru-central1-a"
defaultGpuPlatformID = "gpu-standard-v1"
)
var reImageFamily = regexp.MustCompile(`^[a-z]([-a-z0-9]{0,61}[a-z0-9])?$`)
type CommonConfig struct {
// File path to save serial port output of the launched instance.
SerialLogFile string `mapstructure:"serial_log_file" required:"false"`
InstanceConfig `mapstructure:",squash"`
DiskConfig `mapstructure:",squash"`
NetworkConfig `mapstructure:",squash"`
CloudConfig `mapstructure:",squash"`
}
func (c *CommonConfig) Prepare(errs *packer.MultiError) *packer.MultiError {
if c.SerialLogFile != "" {
if _, err := os.Stat(c.SerialLogFile); os.IsExist(err) {
errs = packer.MultiErrorAppend(errs,
fmt.Errorf("Serial log file %s already exist", c.SerialLogFile))
}
}
errs = c.CloudConfig.Prepare(errs)
errs = c.InstanceConfig.Prepare(errs)
errs = c.DiskConfig.Prepare(errs)
errs = c.NetworkConfig.Prepare(errs)
return errs
}
type CloudConfig struct {
// The folder ID that will be used to launch instances and store images.
// Alternatively you may set value by environment variable `YC_FOLDER_ID`.
// To use a different folder for looking up the source image or saving the target image to
// check options 'source_image_folder_id' and 'target_image_folder_id'.
FolderID string `mapstructure:"folder_id" required:"true"`
}
func (c *CloudConfig) Prepare(errs *packer.MultiError) *packer.MultiError {
if c.FolderID == "" {
c.FolderID = os.Getenv("YC_FOLDER_ID")
}
if c.FolderID == "" {
errs = packer.MultiErrorAppend(
errs, errors.New("a folder_id must be specified"))
}
return errs
}
type DiskConfig struct {
// The name of the disk, if unset the instance name
// will be used.
DiskName string `mapstructure:"disk_name" required:"false"`
// The size of the disk in GB. This defaults to 10/100GB.
DiskSizeGb int `mapstructure:"disk_size_gb" required:"false"`
// Specify disk type for the launched instance. Defaults to `network-ssd`.
DiskType string `mapstructure:"disk_type" required:"false"`
// Key/value pair labels to apply to the disk.
DiskLabels map[string]string `mapstructure:"disk_labels" required:"false"`
}
func (c *DiskConfig) Prepare(errs *packer.MultiError) *packer.MultiError {
if c.DiskSizeGb == 0 {
c.DiskSizeGb = 10
}
if c.DiskType == "" {
c.DiskType = "network-ssd"
}
return errs
}
type NetworkConfig struct {
// The Yandex VPC subnet id to use for
// the launched instance. Note, the zone of the subnet must match the
// zone in which the VM is launched.
SubnetID string `mapstructure:"subnet_id" required:"false"`
// The name of the zone to launch the instance. This defaults to `ru-central1-a`.
Zone string `mapstructure:"zone" required:"false"`
// If set to true, then launched instance will have external internet
// access.
UseIPv4Nat bool `mapstructure:"use_ipv4_nat" required:"false"`
// Set to true to enable IPv6 for the instance being
// created. This defaults to `false`, or not enabled.
//
// -> **Note**: Usage of IPv6 will be available in the future.
UseIPv6 bool `mapstructure:"use_ipv6" required:"false"`
// If true, use the instance's internal IP address
// instead of its external IP during building.
UseInternalIP bool `mapstructure:"use_internal_ip" required:"false"`
}
func (c *NetworkConfig) Prepare(errs *packer.MultiError) *packer.MultiError {
if c.Zone == "" {
c.Zone = defaultZone
}
// if c.UseIPv4Nat && c.UseIPv6 {
// errs = packer.MultiErrorAppend(
// errors.New("one of use_ipv4_nat or use_ipv6 key file must be specified, not both"),
// errs,
// )
// }
return errs
}
type ImageConfig struct {
// The name of the resulting image, which contains 1-63 characters and only
// supports lowercase English characters, numbers and hyphen. Defaults to
// `packer-{{timestamp}}`.
ImageName string `mapstructure:"image_name" required:"false"`
// The description of the image.
ImageDescription string `mapstructure:"image_description" required:"false"`
// The family name of the image.
ImageFamily string `mapstructure:"image_family" required:"false"`
// Key/value pair labels to apply to the image.
ImageLabels map[string]string `mapstructure:"image_labels" required:"false"`
// Minimum size of the disk that will be created from built image, specified in gigabytes.
// Should be more or equal to `disk_size_gb`.
ImageMinDiskSizeGb int `mapstructure:"image_min_disk_size_gb" required:"false"`
// License IDs that indicate which licenses are attached to resulting image.
ImageProductIDs []string `mapstructure:"image_product_ids" required:"false"`
}
func (c *ImageConfig) Prepare(errs *packer.MultiError) *packer.MultiError {
if len(c.ImageFamily) > 63 {
errs = packer.MultiErrorAppend(errs,
errors.New("Invalid image family: Must not be longer than 63 characters"))
}
if c.ImageFamily != "" {
if !reImageFamily.MatchString(c.ImageFamily) {
errs = packer.MultiErrorAppend(errs,
errors.New("Invalid image family: The first character must be a "+
"lowercase letter, and all following characters must be a dash, "+
"lowercase letter, or digit, except the last character, which cannot be a dash"))
}
}
if c.ImageDescription == "" {
c.ImageDescription = "Created by Packer"
}
if c.ImageName == "" {
img, err := interpolate.Render("packer-{{timestamp}}", nil)
if err != nil {
errs = packer.MultiErrorAppend(errs,
fmt.Errorf("Unable to render default image name: %s ", err))
} else {
c.ImageName = img
}
}
return errs
}
type InstanceConfig struct {
// The number of cores available to the instance.
InstanceCores int `mapstructure:"instance_cores" required:"false"`
// The number of GPU available to the instance.
InstanceGpus int `mapstructure:"instance_gpus" required:"false"`
// The amount of memory available to the instance, specified in gigabytes.
InstanceMemory int `mapstructure:"instance_mem_gb" required:"false"`
// The name assigned to the instance.
InstanceName string `mapstructure:"instance_name" required:"false"`
// Identifier of the hardware platform configuration for the instance. This defaults to `standard-v2`.
PlatformID string `mapstructure:"platform_id" required:"false"`
// Key/value pair labels to apply to the launched instance.
Labels map[string]string `mapstructure:"labels" required:"false"`
// Metadata applied to the launched instance.
Metadata map[string]string `mapstructure:"metadata" required:"false"`
// Metadata applied to the launched instance.
// The values in this map are the paths to the content files for the corresponding metadata keys.
MetadataFromFile map[string]string `mapstructure:"metadata_from_file"`
// Launch a preemptible instance. This defaults to `false`.
Preemptible bool `mapstructure:"preemptible"`
}
func (c *InstanceConfig) Prepare(errs *packer.MultiError) *packer.MultiError {
if c.InstanceCores == 0 {
c.InstanceCores = 2
}
if c.InstanceMemory == 0 {
c.InstanceMemory = 4
}
if c.InstanceName == "" {
c.InstanceName = fmt.Sprintf("packer-%s", uuid.TimeOrderedUUID())
}
for key, file := range c.MetadataFromFile {
if _, err := os.Stat(file); err != nil {
errs = packer.MultiErrorAppend(
errs, fmt.Errorf("cannot access file '%s' with content for value of metadata key '%s': %s", file, key, err))
}
}
if c.PlatformID == "" {
c.PlatformID = defaultPlatformID
if c.InstanceGpus != 0 {
c.PlatformID = defaultGpuPlatformID
}
}
return errs
}

View File

@ -6,8 +6,6 @@ package yandex
import (
"errors"
"fmt"
"os"
"regexp"
"time"
"github.com/hashicorp/packer/packer-plugin-sdk/common"
@ -15,72 +13,19 @@ import (
packersdk "github.com/hashicorp/packer/packer-plugin-sdk/packer"
"github.com/hashicorp/packer/packer-plugin-sdk/template/config"
"github.com/hashicorp/packer/packer-plugin-sdk/template/interpolate"
"github.com/hashicorp/packer/packer-plugin-sdk/uuid"
)
const defaultGpuPlatformID = "gpu-standard-v1"
const defaultPlatformID = "standard-v1"
const defaultMaxRetries = 3
const defaultZone = "ru-central1-a"
var reImageFamily = regexp.MustCompile(`^[a-z]([-a-z0-9]{0,61}[a-z0-9])?$`)
type Config struct {
common.PackerConfig `mapstructure:",squash"`
Communicator communicator.Config `mapstructure:",squash"`
AccessConfig `mapstructure:",squash"`
// The folder ID that will be used to launch instances and store images.
// Alternatively you may set value by environment variable `YC_FOLDER_ID`.
// To use a different folder for looking up the source image or saving the target image to
// check options 'source_image_folder_id' and 'target_image_folder_id'.
FolderID string `mapstructure:"folder_id" required:"true"`
CommonConfig `mapstructure:",squash"`
ImageConfig `mapstructure:",squash"`
// Service account identifier to assign to instance.
ServiceAccountID string `mapstructure:"service_account_id" required:"false"`
// The name of the disk, if unset the instance name
// will be used.
DiskName string `mapstructure:"disk_name" required:"false"`
// The size of the disk in GB. This defaults to `10`, which is 10GB.
DiskSizeGb int `mapstructure:"disk_size_gb" required:"false"`
// Specify disk type for the launched instance. Defaults to `network-hdd`.
DiskType string `mapstructure:"disk_type" required:"false"`
// Key/value pair labels to apply to the disk.
DiskLabels map[string]string `mapstructure:"disk_labels" required:"false"`
// The description of the resulting image.
ImageDescription string `mapstructure:"image_description" required:"false"`
// The family name of the resulting image.
ImageFamily string `mapstructure:"image_family" required:"false"`
// Key/value pair labels to apply to the created image.
ImageLabels map[string]string `mapstructure:"image_labels" required:"false"`
// Minimum size of the disk that will be created from built image, specified in gigabytes.
// Should be more or equal to `disk_size_gb`.
ImageMinDiskSizeGb int `mapstructure:"image_min_disk_size_gb" required:"false"`
// The unique name of the resulting image. Defaults to
// `packer-{{timestamp}}`.
ImageName string `mapstructure:"image_name" required:"false"`
// License IDs that indicate which licenses are attached to resulting image.
ImageProductIDs []string `mapstructure:"image_product_ids" required:"false"`
// The number of cores available to the instance.
InstanceCores int `mapstructure:"instance_cores" required:"false"`
// The number of GPU available to the instance.
InstanceGpus int `mapstructure:"instance_gpus"`
// The amount of memory available to the instance, specified in gigabytes.
InstanceMemory int `mapstructure:"instance_mem_gb" required:"false"`
// The name assigned to the instance.
InstanceName string `mapstructure:"instance_name" required:"false"`
// Key/value pair labels to apply to the launched instance.
Labels map[string]string `mapstructure:"labels" required:"false"`
// Identifier of the hardware platform configuration for the instance. This defaults to `standard-v1`.
PlatformID string `mapstructure:"platform_id" required:"false"`
// Metadata applied to the launched instance.
Metadata map[string]string `mapstructure:"metadata" required:"false"`
// Metadata applied to the launched instance.
// The values in this map are the paths to the content files for the corresponding metadata keys.
MetadataFromFile map[string]string `mapstructure:"metadata_from_file"`
// Launch a preemptible instance. This defaults to `false`.
Preemptible bool `mapstructure:"preemptible"`
// File path to save serial port output of the launched instance.
SerialLogFile string `mapstructure:"serial_log_file" required:"false"`
// The source image family to create the new image
// from. You can also specify source_image_id instead. Just one of a source_image_id or
// source_image_family must be specified. Example: `ubuntu-1804-lts`.
@ -92,26 +37,9 @@ type Config struct {
// The source image name to use to create the new image
// from. Name will be looked up in `source_image_folder_id`.
SourceImageName string `mapstructure:"source_image_name"`
// The Yandex VPC subnet id to use for
// the launched instance. Note, the zone of the subnet must match the
// zone in which the VM is launched.
SubnetID string `mapstructure:"subnet_id" required:"false"`
// The ID of the folder to save built image in.
// This defaults to value of 'folder_id'.
TargetImageFolderID string `mapstructure:"target_image_folder_id" required:"false"`
// If set to true, then launched instance will have external internet
// access.
UseIPv4Nat bool `mapstructure:"use_ipv4_nat" required:"false"`
// Set to true to enable IPv6 for the instance being
// created. This defaults to `false`, or not enabled.
//
// -> **Note**: Usage of IPv6 will be available in the future.
UseIPv6 bool `mapstructure:"use_ipv6" required:"false"`
// If true, use the instance's internal IP address
// instead of its external IP during building.
UseInternalIP bool `mapstructure:"use_internal_ip" required:"false"`
// The name of the zone to launch the instance. This defaults to `ru-central1-a`.
Zone string `mapstructure:"zone" required:"false"`
ctx interpolate.Context
// The time to wait for instance state changes.
@ -134,28 +62,8 @@ func (c *Config) Prepare(raws ...interface{}) ([]string, error) {
errs = packersdk.MultiErrorAppend(errs, c.AccessConfig.Prepare(&c.ctx)...)
if c.SerialLogFile != "" {
if _, err := os.Stat(c.SerialLogFile); os.IsExist(err) {
errs = packersdk.MultiErrorAppend(errs,
fmt.Errorf("Serial log file %s already exist", c.SerialLogFile))
}
}
if c.InstanceCores == 0 {
c.InstanceCores = 2
}
if c.InstanceMemory == 0 {
c.InstanceMemory = 4
}
if c.DiskSizeGb == 0 {
c.DiskSizeGb = 10
}
if c.DiskType == "" {
c.DiskType = "network-hdd"
}
errs = c.CommonConfig.Prepare(errs)
errs = c.ImageConfig.Prepare(errs)
if c.ImageMinDiskSizeGb == 0 {
c.ImageMinDiskSizeGb = c.DiskSizeGb
@ -167,49 +75,10 @@ func (c *Config) Prepare(raws ...interface{}) ([]string, error) {
c.ImageMinDiskSizeGb, c.DiskSizeGb))
}
if c.ImageDescription == "" {
c.ImageDescription = "Created by Packer"
}
if c.ImageName == "" {
img, err := interpolate.Render("packer-{{timestamp}}", nil)
if err != nil {
errs = packersdk.MultiErrorAppend(errs,
fmt.Errorf("Unable to render default image name: %s ", err))
} else {
c.ImageName = img
}
}
if len(c.ImageFamily) > 63 {
errs = packersdk.MultiErrorAppend(errs,
errors.New("Invalid image family: Must not be longer than 63 characters"))
}
if c.ImageFamily != "" {
if !reImageFamily.MatchString(c.ImageFamily) {
errs = packersdk.MultiErrorAppend(errs,
errors.New("Invalid image family: The first character must be a "+
"lowercase letter, and all following characters must be a dash, "+
"lowercase letter, or digit, except the last character, which cannot be a dash"))
}
}
if c.InstanceName == "" {
c.InstanceName = fmt.Sprintf("packer-%s", uuid.TimeOrderedUUID())
}
if c.DiskName == "" {
c.DiskName = c.InstanceName + "-disk"
}
if c.PlatformID == "" {
c.PlatformID = defaultPlatformID
if c.InstanceGpus != 0 {
c.PlatformID = defaultGpuPlatformID
}
}
if es := c.Communicator.Prepare(&c.ctx); len(es) > 0 {
errs = packersdk.MultiErrorAppend(errs, es...)
}
@ -226,34 +95,10 @@ func (c *Config) Prepare(raws ...interface{}) ([]string, error) {
}
}
if c.Zone == "" {
c.Zone = defaultZone
}
if c.MaxRetries == 0 {
c.MaxRetries = defaultMaxRetries
}
if c.FolderID == "" {
c.FolderID = os.Getenv("YC_FOLDER_ID")
}
if c.FolderID == "" {
errs = packersdk.MultiErrorAppend(
errs, errors.New("a folder_id must be specified"))
}
if c.TargetImageFolderID == "" {
c.TargetImageFolderID = c.FolderID
}
for key, file := range c.MetadataFromFile {
if _, err := os.Stat(file); err != nil {
errs = packersdk.MultiErrorAppend(
errs, fmt.Errorf("cannot access file '%s' with content for value of metadata key '%s': %s", file, key, err))
}
}
if c.StateTimeout == 0 {
c.StateTimeout = 5 * time.Minute
}

View File

@ -70,38 +70,38 @@ type FlatConfig struct {
ServiceAccountKeyFile *string `mapstructure:"service_account_key_file" required:"false" cty:"service_account_key_file" hcl:"service_account_key_file"`
Token *string `mapstructure:"token" required:"true" cty:"token" hcl:"token"`
MaxRetries *int `mapstructure:"max_retries" cty:"max_retries" hcl:"max_retries"`
FolderID *string `mapstructure:"folder_id" required:"true" cty:"folder_id" hcl:"folder_id"`
ServiceAccountID *string `mapstructure:"service_account_id" required:"false" cty:"service_account_id" hcl:"service_account_id"`
SerialLogFile *string `mapstructure:"serial_log_file" required:"false" cty:"serial_log_file" hcl:"serial_log_file"`
InstanceCores *int `mapstructure:"instance_cores" required:"false" cty:"instance_cores" hcl:"instance_cores"`
InstanceGpus *int `mapstructure:"instance_gpus" required:"false" cty:"instance_gpus" hcl:"instance_gpus"`
InstanceMemory *int `mapstructure:"instance_mem_gb" required:"false" cty:"instance_mem_gb" hcl:"instance_mem_gb"`
InstanceName *string `mapstructure:"instance_name" required:"false" cty:"instance_name" hcl:"instance_name"`
PlatformID *string `mapstructure:"platform_id" required:"false" cty:"platform_id" hcl:"platform_id"`
Labels map[string]string `mapstructure:"labels" required:"false" cty:"labels" hcl:"labels"`
Metadata map[string]string `mapstructure:"metadata" required:"false" cty:"metadata" hcl:"metadata"`
MetadataFromFile map[string]string `mapstructure:"metadata_from_file" cty:"metadata_from_file" hcl:"metadata_from_file"`
Preemptible *bool `mapstructure:"preemptible" cty:"preemptible" hcl:"preemptible"`
DiskName *string `mapstructure:"disk_name" required:"false" cty:"disk_name" hcl:"disk_name"`
DiskSizeGb *int `mapstructure:"disk_size_gb" required:"false" cty:"disk_size_gb" hcl:"disk_size_gb"`
DiskType *string `mapstructure:"disk_type" required:"false" cty:"disk_type" hcl:"disk_type"`
DiskLabels map[string]string `mapstructure:"disk_labels" required:"false" cty:"disk_labels" hcl:"disk_labels"`
SubnetID *string `mapstructure:"subnet_id" required:"false" cty:"subnet_id" hcl:"subnet_id"`
Zone *string `mapstructure:"zone" required:"false" cty:"zone" hcl:"zone"`
UseIPv4Nat *bool `mapstructure:"use_ipv4_nat" required:"false" cty:"use_ipv4_nat" hcl:"use_ipv4_nat"`
UseIPv6 *bool `mapstructure:"use_ipv6" required:"false" cty:"use_ipv6" hcl:"use_ipv6"`
UseInternalIP *bool `mapstructure:"use_internal_ip" required:"false" cty:"use_internal_ip" hcl:"use_internal_ip"`
FolderID *string `mapstructure:"folder_id" required:"true" cty:"folder_id" hcl:"folder_id"`
ImageName *string `mapstructure:"image_name" required:"false" cty:"image_name" hcl:"image_name"`
ImageDescription *string `mapstructure:"image_description" required:"false" cty:"image_description" hcl:"image_description"`
ImageFamily *string `mapstructure:"image_family" required:"false" cty:"image_family" hcl:"image_family"`
ImageLabels map[string]string `mapstructure:"image_labels" required:"false" cty:"image_labels" hcl:"image_labels"`
ImageMinDiskSizeGb *int `mapstructure:"image_min_disk_size_gb" required:"false" cty:"image_min_disk_size_gb" hcl:"image_min_disk_size_gb"`
ImageName *string `mapstructure:"image_name" required:"false" cty:"image_name" hcl:"image_name"`
ImageProductIDs []string `mapstructure:"image_product_ids" required:"false" cty:"image_product_ids" hcl:"image_product_ids"`
InstanceCores *int `mapstructure:"instance_cores" required:"false" cty:"instance_cores" hcl:"instance_cores"`
InstanceGpus *int `mapstructure:"instance_gpus" cty:"instance_gpus" hcl:"instance_gpus"`
InstanceMemory *int `mapstructure:"instance_mem_gb" required:"false" cty:"instance_mem_gb" hcl:"instance_mem_gb"`
InstanceName *string `mapstructure:"instance_name" required:"false" cty:"instance_name" hcl:"instance_name"`
Labels map[string]string `mapstructure:"labels" required:"false" cty:"labels" hcl:"labels"`
PlatformID *string `mapstructure:"platform_id" required:"false" cty:"platform_id" hcl:"platform_id"`
Metadata map[string]string `mapstructure:"metadata" required:"false" cty:"metadata" hcl:"metadata"`
MetadataFromFile map[string]string `mapstructure:"metadata_from_file" cty:"metadata_from_file" hcl:"metadata_from_file"`
Preemptible *bool `mapstructure:"preemptible" cty:"preemptible" hcl:"preemptible"`
SerialLogFile *string `mapstructure:"serial_log_file" required:"false" cty:"serial_log_file" hcl:"serial_log_file"`
ServiceAccountID *string `mapstructure:"service_account_id" required:"false" cty:"service_account_id" hcl:"service_account_id"`
SourceImageFamily *string `mapstructure:"source_image_family" required:"true" cty:"source_image_family" hcl:"source_image_family"`
SourceImageFolderID *string `mapstructure:"source_image_folder_id" required:"false" cty:"source_image_folder_id" hcl:"source_image_folder_id"`
SourceImageID *string `mapstructure:"source_image_id" required:"false" cty:"source_image_id" hcl:"source_image_id"`
SourceImageName *string `mapstructure:"source_image_name" cty:"source_image_name" hcl:"source_image_name"`
SubnetID *string `mapstructure:"subnet_id" required:"false" cty:"subnet_id" hcl:"subnet_id"`
TargetImageFolderID *string `mapstructure:"target_image_folder_id" required:"false" cty:"target_image_folder_id" hcl:"target_image_folder_id"`
UseIPv4Nat *bool `mapstructure:"use_ipv4_nat" required:"false" cty:"use_ipv4_nat" hcl:"use_ipv4_nat"`
UseIPv6 *bool `mapstructure:"use_ipv6" required:"false" cty:"use_ipv6" hcl:"use_ipv6"`
UseInternalIP *bool `mapstructure:"use_internal_ip" required:"false" cty:"use_internal_ip" hcl:"use_internal_ip"`
Zone *string `mapstructure:"zone" required:"false" cty:"zone" hcl:"zone"`
StateTimeout *string `mapstructure:"state_timeout" required:"false" cty:"state_timeout" hcl:"state_timeout"`
}
@ -178,38 +178,38 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"service_account_key_file": &hcldec.AttrSpec{Name: "service_account_key_file", Type: cty.String, Required: false},
"token": &hcldec.AttrSpec{Name: "token", Type: cty.String, Required: false},
"max_retries": &hcldec.AttrSpec{Name: "max_retries", Type: cty.Number, Required: false},
"folder_id": &hcldec.AttrSpec{Name: "folder_id", Type: cty.String, Required: false},
"service_account_id": &hcldec.AttrSpec{Name: "service_account_id", Type: cty.String, Required: false},
"disk_name": &hcldec.AttrSpec{Name: "disk_name", Type: cty.String, Required: false},
"disk_size_gb": &hcldec.AttrSpec{Name: "disk_size_gb", Type: cty.Number, Required: false},
"disk_type": &hcldec.AttrSpec{Name: "disk_type", Type: cty.String, Required: false},
"disk_labels": &hcldec.AttrSpec{Name: "disk_labels", Type: cty.Map(cty.String), Required: false},
"image_description": &hcldec.AttrSpec{Name: "image_description", Type: cty.String, Required: false},
"image_family": &hcldec.AttrSpec{Name: "image_family", Type: cty.String, Required: false},
"image_labels": &hcldec.AttrSpec{Name: "image_labels", Type: cty.Map(cty.String), Required: false},
"image_min_disk_size_gb": &hcldec.AttrSpec{Name: "image_min_disk_size_gb", Type: cty.Number, Required: false},
"image_name": &hcldec.AttrSpec{Name: "image_name", Type: cty.String, Required: false},
"image_product_ids": &hcldec.AttrSpec{Name: "image_product_ids", Type: cty.List(cty.String), Required: false},
"serial_log_file": &hcldec.AttrSpec{Name: "serial_log_file", Type: cty.String, Required: false},
"instance_cores": &hcldec.AttrSpec{Name: "instance_cores", Type: cty.Number, Required: false},
"instance_gpus": &hcldec.AttrSpec{Name: "instance_gpus", Type: cty.Number, Required: false},
"instance_mem_gb": &hcldec.AttrSpec{Name: "instance_mem_gb", Type: cty.Number, Required: false},
"instance_name": &hcldec.AttrSpec{Name: "instance_name", Type: cty.String, Required: false},
"labels": &hcldec.AttrSpec{Name: "labels", Type: cty.Map(cty.String), Required: false},
"platform_id": &hcldec.AttrSpec{Name: "platform_id", Type: cty.String, Required: false},
"labels": &hcldec.AttrSpec{Name: "labels", Type: cty.Map(cty.String), Required: false},
"metadata": &hcldec.AttrSpec{Name: "metadata", Type: cty.Map(cty.String), Required: false},
"metadata_from_file": &hcldec.AttrSpec{Name: "metadata_from_file", Type: cty.Map(cty.String), Required: false},
"preemptible": &hcldec.AttrSpec{Name: "preemptible", Type: cty.Bool, Required: false},
"serial_log_file": &hcldec.AttrSpec{Name: "serial_log_file", Type: cty.String, Required: false},
"disk_name": &hcldec.AttrSpec{Name: "disk_name", Type: cty.String, Required: false},
"disk_size_gb": &hcldec.AttrSpec{Name: "disk_size_gb", Type: cty.Number, Required: false},
"disk_type": &hcldec.AttrSpec{Name: "disk_type", Type: cty.String, Required: false},
"disk_labels": &hcldec.AttrSpec{Name: "disk_labels", Type: cty.Map(cty.String), Required: false},
"subnet_id": &hcldec.AttrSpec{Name: "subnet_id", Type: cty.String, Required: false},
"zone": &hcldec.AttrSpec{Name: "zone", Type: cty.String, Required: false},
"use_ipv4_nat": &hcldec.AttrSpec{Name: "use_ipv4_nat", Type: cty.Bool, Required: false},
"use_ipv6": &hcldec.AttrSpec{Name: "use_ipv6", Type: cty.Bool, Required: false},
"use_internal_ip": &hcldec.AttrSpec{Name: "use_internal_ip", Type: cty.Bool, Required: false},
"folder_id": &hcldec.AttrSpec{Name: "folder_id", Type: cty.String, Required: false},
"image_name": &hcldec.AttrSpec{Name: "image_name", Type: cty.String, Required: false},
"image_description": &hcldec.AttrSpec{Name: "image_description", Type: cty.String, Required: false},
"image_family": &hcldec.AttrSpec{Name: "image_family", Type: cty.String, Required: false},
"image_labels": &hcldec.AttrSpec{Name: "image_labels", Type: cty.Map(cty.String), Required: false},
"image_min_disk_size_gb": &hcldec.AttrSpec{Name: "image_min_disk_size_gb", Type: cty.Number, Required: false},
"image_product_ids": &hcldec.AttrSpec{Name: "image_product_ids", Type: cty.List(cty.String), Required: false},
"service_account_id": &hcldec.AttrSpec{Name: "service_account_id", Type: cty.String, Required: false},
"source_image_family": &hcldec.AttrSpec{Name: "source_image_family", Type: cty.String, Required: false},
"source_image_folder_id": &hcldec.AttrSpec{Name: "source_image_folder_id", Type: cty.String, Required: false},
"source_image_id": &hcldec.AttrSpec{Name: "source_image_id", Type: cty.String, Required: false},
"source_image_name": &hcldec.AttrSpec{Name: "source_image_name", Type: cty.String, Required: false},
"subnet_id": &hcldec.AttrSpec{Name: "subnet_id", Type: cty.String, Required: false},
"target_image_folder_id": &hcldec.AttrSpec{Name: "target_image_folder_id", Type: cty.String, Required: false},
"use_ipv4_nat": &hcldec.AttrSpec{Name: "use_ipv4_nat", Type: cty.Bool, Required: false},
"use_ipv6": &hcldec.AttrSpec{Name: "use_ipv6", Type: cty.Bool, Required: false},
"use_internal_ip": &hcldec.AttrSpec{Name: "use_internal_ip", Type: cty.Bool, Required: false},
"zone": &hcldec.AttrSpec{Name: "zone", Type: cty.String, Required: false},
"state_timeout": &hcldec.AttrSpec{Name: "state_timeout", Type: cty.String, Required: false},
}
return s

View File

@ -76,6 +76,20 @@ func createDisk(ctx context.Context, c *Config, d Driver, sourceImage *Image) (*
}
err = op.Wait(ctx)
if err != nil {
if errors.Is(err, context.DeadlineExceeded) {
resp, err2 := op.Response()
if err2 != nil {
return nil, err
}
disk, ok := resp.(*compute.Disk)
if !ok {
return nil, err
}
sdk.Compute().Disk().Delete(ctx, &compute.DeleteDiskRequest{
DiskId: disk.Id,
})
}
return nil, err
}
resp, err := op.Response()
@ -270,6 +284,8 @@ func (s *StepCreateInstance) Run(ctx context.Context, state multistep.StateBag)
}
}
ui.Message(fmt.Sprint(req))
op, err := sdk.WrapOperation(sdk.Compute().Instance().Create(ctx, req))
if err != nil {
return stepHaltWithError(state, fmt.Errorf("Error create instance: %s", err))
@ -331,7 +347,7 @@ func (s *StepCreateInstance) Cleanup(state multistep.StateBag) {
if s.SerialLogFile != "" {
ui.Say("Current state 'cancelled' or 'halted'...")
err := s.writeSerialLogFile(ctx, state)
err := writeSerialLogFile(ctx, state, s.SerialLogFile)
if err != nil {
ui.Error(err.Error())
}
@ -395,25 +411,6 @@ func (s *StepCreateInstance) Cleanup(state multistep.StateBag) {
}
}
func (s *StepCreateInstance) writeSerialLogFile(ctx context.Context, state multistep.StateBag) error {
sdk := state.Get("sdk").(*ycsdk.SDK)
ui := state.Get("ui").(packersdk.Ui)
instanceID := state.Get("instance_id").(string)
ui.Say("Try get instance's serial port output and write to file " + s.SerialLogFile)
serialOutput, err := sdk.Compute().Instance().GetSerialPortOutput(ctx, &compute.GetInstanceSerialPortOutputRequest{
InstanceId: instanceID,
})
if err != nil {
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 {
return fmt.Errorf("Failed to write serial port output to file: %s", err)
}
ui.Message("Serial port output has been successfully written")
return nil
}
func (c *Config) createInstanceMetadata(sshPublicKey string) (map[string]string, error) {
instanceMetadata := make(map[string]string)

View File

@ -11,7 +11,9 @@ import (
ycsdk "github.com/yandex-cloud/go-sdk"
)
type StepTeardownInstance struct{}
type StepTeardownInstance struct {
SerialLogFile string
}
func (s *StepTeardownInstance) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
sdk := state.Get("sdk").(*ycsdk.SDK)
@ -23,6 +25,14 @@ func (s *StepTeardownInstance) Run(ctx context.Context, state multistep.StateBag
ui.Say("Stopping instance...")
ctx, cancel := context.WithTimeout(ctx, c.StateTimeout)
defer cancel()
if s.SerialLogFile != "" {
err := writeSerialLogFile(ctx, state, s.SerialLogFile)
if err != nil {
ui.Error(err.Error())
}
}
op, err := sdk.WrapOperation(sdk.Compute().Instance().Stop(ctx, &compute.StopInstanceRequest{
InstanceId: instanceID,
}))

View File

@ -19,7 +19,7 @@ type StepWaitCloudInitScript int
// Run reads the instance metadata and looks for the log entry
// indicating the cloud-init script finished.
func (s *StepWaitCloudInitScript) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
func (*StepWaitCloudInitScript) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
_ = state.Get("config").(*Config)
driver := state.Get("driver").(Driver)
ui := state.Get("ui").(packersdk.Ui)

View File

@ -1,9 +1,15 @@
package yandex
import (
"context"
"fmt"
"io/ioutil"
"github.com/c2h5oh/datasize"
"github.com/hashicorp/packer/packer-plugin-sdk/multistep"
packersdk "github.com/hashicorp/packer/packer-plugin-sdk/packer"
"github.com/yandex-cloud/go-genproto/yandex/cloud/compute/v1"
ycsdk "github.com/yandex-cloud/go-sdk"
)
func stepHaltWithError(state multistep.StateBag, err error) multistep.StepAction {
@ -20,3 +26,25 @@ func toGigabytes(bytesCount int64) int {
func toBytes(gigabytesCount int) int64 {
return int64((datasize.ByteSize(gigabytesCount) * datasize.GB).Bytes())
}
func writeSerialLogFile(ctx context.Context, state multistep.StateBag, serialLogFile string) error {
sdk := state.Get("sdk").(*ycsdk.SDK)
ui := state.Get("ui").(packer.Ui)
instanceID := state.Get("instance_id").(string)
if instanceID == "" {
return nil
}
ui.Say("Try get instance's serial port output and write to file " + serialLogFile)
serialOutput, err := sdk.Compute().Instance().GetSerialPortOutput(ctx, &compute.GetInstanceSerialPortOutputRequest{
InstanceId: instanceID,
})
if err != nil {
return fmt.Errorf("Failed to get serial port output for instance (id: %s): %s", instanceID, err)
}
if err := ioutil.WriteFile(serialLogFile, []byte(serialOutput.Contents), 0600); err != nil {
return fmt.Errorf("Failed to write serial port output to file: %s", err)
}
ui.Message("Serial port output has been successfully written")
return nil
}

View File

@ -0,0 +1,23 @@
//go:generate struct-markdown
package yandexexport
import (
"fmt"
"github.com/hashicorp/packer/packer"
)
type ExchangeConfig struct {
// Service Account ID with proper permission to modify an instance, create and attach disk and
// make upload to specific Yandex Object Storage paths.
ServiceAccountID string `mapstructure:"service_account_id" required:"true"`
}
func (c *ExchangeConfig) Prepare(errs *packer.MultiError) *packer.MultiError {
if c.ServiceAccountID == "" {
errs = packer.MultiErrorAppend(
errs, fmt.Errorf("service_account_id must be specified"))
}
return errs
}

View File

@ -8,7 +8,6 @@ import (
"context"
"fmt"
"log"
"os"
"strings"
"time"
@ -32,6 +31,8 @@ const defaultStorageEndpoint = "storage.yandexcloud.net"
type Config struct {
common.PackerConfig `mapstructure:",squash"`
yandex.AccessConfig `mapstructure:",squash"`
yandex.CommonConfig `mapstructure:",squash"`
ExchangeConfig `mapstructure:",squash"`
// List of paths to Yandex Object Storage where exported image will be uploaded.
// Please be aware that use of space char inside path not supported.
@ -39,24 +40,11 @@ type Config struct {
// Check available template data for [Yandex](/docs/builders/yandex#build-template-data) builder.
// Paths to Yandex Object Storage where exported image will be uploaded.
Paths []string `mapstructure:"paths" required:"true"`
// The folder ID that will be used to launch a temporary instance.
// Alternatively you may set value by environment variable `YC_FOLDER_ID`.
FolderID string `mapstructure:"folder_id" required:"true"`
// Service Account ID with proper permission to modify an instance, create and attach disk and
// make upload to specific Yandex Object Storage paths.
ServiceAccountID string `mapstructure:"service_account_id" required:"true"`
// The size of the disk in GB. This defaults to `100`, which is 100GB.
DiskSizeGb int `mapstructure:"disk_size" required:"false"`
// Specify disk type for the launched instance. Defaults to `network-ssd`.
DiskType string `mapstructure:"disk_type" required:"false"`
// Identifier of the hardware platform configuration for the instance. This defaults to `standard-v2`.
PlatformID string `mapstructure:"platform_id" required:"false"`
// The Yandex VPC subnet id to use for
// the launched instance. Note, the zone of the subnet must match the
// zone in which the VM is launched.
SubnetID string `mapstructure:"subnet_id" required:"false"`
// The name of the zone to launch the instance. This defaults to `ru-central1-a`.
Zone string `mapstructure:"zone" required:"false"`
// Path to a PEM encoded private key file to use to authenticate with SSH.
// The `~` can be used in path and will be expanded to the home directory
// of current user. Login for attach: `ubuntu`
SSHPrivateKeyFile string `mapstructure:"ssh_private_key_file" required:"false"`
ctx interpolate.Context
}
@ -88,6 +76,14 @@ func (p *PostProcessor) Configure(raws ...interface{}) error {
errs = packersdk.MultiErrorAppend(errs, p.config.AccessConfig.Prepare(&p.config.ctx)...)
// Set defaults.
if p.config.DiskSizeGb == 0 {
p.config.DiskSizeGb = 100
}
errs = p.config.CommonConfig.Prepare(errs)
errs = p.config.ExchangeConfig.Prepare(errs)
if len(p.config.Paths) == 0 {
errs = packersdk.MultiErrorAppend(
errs, fmt.Errorf("paths must be specified"))
@ -101,31 +97,21 @@ func (p *PostProcessor) Configure(raws ...interface{}) error {
}
}
if p.config.FolderID == "" {
p.config.FolderID = os.Getenv("YC_FOLDER_ID")
}
// Set defaults.
if p.config.DiskSizeGb == 0 {
p.config.DiskSizeGb = 100
}
if p.config.DiskType == "" {
p.config.DiskType = "network-ssd"
}
if p.config.PlatformID == "" {
p.config.PlatformID = "standard-v2"
}
if p.config.Zone == "" {
p.config.Zone = "ru-central1-a"
}
if len(errs.Errors) > 0 {
return errs
}
if p.config.UseIPv4Nat && p.config.UseIPv6 == false {
p.config.UseIPv4Nat = true
}
p.config.Preemptible = true //? safety
if p.config.Labels == nil {
p.config.Labels = make(map[string]string)
}
p.config.Labels["role"] = "exporter"
p.config.Labels["target"] = "object-storage"
return nil
}
@ -168,15 +154,6 @@ func (p *PostProcessor) PostProcess(ctx context.Context, ui packersdk.Ui, artifa
imageID := artifact.State("ImageID").(string)
ui.Say(fmt.Sprintf("Exporting image %v to destination: %v", imageID, p.config.Paths))
// Set up exporter instance configuration.
exporterName := fmt.Sprintf("%s-exporter", artifact.Id())
exporterMetadata := map[string]string{
"image_id": imageID,
"name": exporterName,
"paths": strings.Join(p.config.Paths, " "),
"user-data": CloudInitScript,
"zone": p.config.Zone,
}
driver, err := yandex.NewDriverYC(ui, &p.config.AccessConfig)
if err != nil {
return nil, false, false, err
@ -202,22 +179,19 @@ func (p *PostProcessor) PostProcess(ctx context.Context, ui packersdk.Ui, artifa
},
},
}
yandexConfig := ycSaneDefaults()
// Set up exporter instance configuration.
exporterName := fmt.Sprintf("%s-exporter", artifact.Id())
yandexConfig := ycSaneDefaults(&p.config,
map[string]string{
"image_id": imageID,
"name": exporterName,
"paths": strings.Join(p.config.Paths, " "),
"user-data": CloudInitScript,
"zone": p.config.Zone,
},
)
yandexConfig.InstanceConfig.InstanceName = exporterName
yandexConfig.DiskName = exporterName
yandexConfig.InstanceName = exporterName
yandexConfig.DiskSizeGb = p.config.DiskSizeGb
yandexConfig.Metadata = exporterMetadata
yandexConfig.SubnetID = p.config.SubnetID
yandexConfig.FolderID = p.config.FolderID
yandexConfig.Zone = p.config.Zone
if p.config.ServiceAccountID != "" {
yandexConfig.ServiceAccountID = p.config.ServiceAccountID
}
if p.config.PlatformID != "" {
yandexConfig.PlatformID = p.config.PlatformID
}
ui.Say(fmt.Sprintf("Validating service_account_id: '%s'...", yandexConfig.ServiceAccountID))
if err := validateServiceAccount(ctx, driver.SDK(), yandexConfig.ServiceAccountID); err != nil {
@ -240,10 +214,13 @@ func (p *PostProcessor) PostProcess(ctx context.Context, ui packersdk.Ui, artifa
},
&yandex.StepCreateInstance{
Debug: p.config.PackerDebug,
SerialLogFile: yandexConfig.SerialLogFile,
GeneratedData: &packerbuilderdata.GeneratedData{State: state},
},
new(yandex.StepWaitCloudInitScript),
new(yandex.StepTeardownInstance),
&yandex.StepTeardownInstance{
SerialLogFile: yandexConfig.SerialLogFile,
},
}
// Run the steps.
@ -261,23 +238,30 @@ func (p *PostProcessor) PostProcess(ctx context.Context, ui packersdk.Ui, artifa
return result, false, false, nil
}
func ycSaneDefaults() yandex.Config {
return yandex.Config{
DiskType: "network-ssd",
InstanceCores: 2,
InstanceMemory: 2,
Labels: map[string]string{
"role": "exporter",
"target": "object-storage",
},
PlatformID: "standard-v2",
Preemptible: true,
SourceImageFamily: "ubuntu-1604-lts",
SourceImageFolderID: yandex.StandardImagesFolderID,
UseIPv4Nat: true,
Zone: "ru-central1-a",
StateTimeout: 3 * time.Minute,
func ycSaneDefaults(c *Config, md map[string]string) yandex.Config {
yandexConfig := yandex.Config{
CommonConfig: c.CommonConfig,
AccessConfig: c.AccessConfig,
}
if c.SSHPrivateKeyFile != "" {
yandexConfig.Communicator.SSH.SSHPrivateKeyFile = c.SSHPrivateKeyFile
yandexConfig.Communicator.SSH.SSHUsername = "ubuntu"
}
if yandexConfig.Metadata == nil {
yandexConfig.Metadata = md
} else {
for k, v := range md {
yandexConfig.Metadata[k] = v
}
}
yandexConfig.SourceImageFamily = "ubuntu-1604-lts"
yandexConfig.SourceImageFolderID = yandex.StandardImagesFolderID
yandexConfig.StateTimeout = 3 * time.Minute
yandexConfig.ServiceAccountID = c.ServiceAccountID
return yandexConfig
}
func formUrls(paths []string) []string {

View File

@ -21,14 +21,29 @@ type FlatConfig struct {
ServiceAccountKeyFile *string `mapstructure:"service_account_key_file" required:"false" cty:"service_account_key_file" hcl:"service_account_key_file"`
Token *string `mapstructure:"token" required:"true" cty:"token" hcl:"token"`
MaxRetries *int `mapstructure:"max_retries" cty:"max_retries" hcl:"max_retries"`
Paths []string `mapstructure:"paths" required:"true" cty:"paths" hcl:"paths"`
FolderID *string `mapstructure:"folder_id" required:"true" cty:"folder_id" hcl:"folder_id"`
ServiceAccountID *string `mapstructure:"service_account_id" required:"true" cty:"service_account_id" hcl:"service_account_id"`
DiskSizeGb *int `mapstructure:"disk_size" required:"false" cty:"disk_size" hcl:"disk_size"`
DiskType *string `mapstructure:"disk_type" required:"false" cty:"disk_type" hcl:"disk_type"`
SerialLogFile *string `mapstructure:"serial_log_file" required:"false" cty:"serial_log_file" hcl:"serial_log_file"`
InstanceCores *int `mapstructure:"instance_cores" required:"false" cty:"instance_cores" hcl:"instance_cores"`
InstanceGpus *int `mapstructure:"instance_gpus" required:"false" cty:"instance_gpus" hcl:"instance_gpus"`
InstanceMemory *int `mapstructure:"instance_mem_gb" required:"false" cty:"instance_mem_gb" hcl:"instance_mem_gb"`
InstanceName *string `mapstructure:"instance_name" required:"false" cty:"instance_name" hcl:"instance_name"`
PlatformID *string `mapstructure:"platform_id" required:"false" cty:"platform_id" hcl:"platform_id"`
Labels map[string]string `mapstructure:"labels" required:"false" cty:"labels" hcl:"labels"`
Metadata map[string]string `mapstructure:"metadata" required:"false" cty:"metadata" hcl:"metadata"`
MetadataFromFile map[string]string `mapstructure:"metadata_from_file" cty:"metadata_from_file" hcl:"metadata_from_file"`
Preemptible *bool `mapstructure:"preemptible" cty:"preemptible" hcl:"preemptible"`
DiskName *string `mapstructure:"disk_name" required:"false" cty:"disk_name" hcl:"disk_name"`
DiskSizeGb *int `mapstructure:"disk_size_gb" required:"false" cty:"disk_size_gb" hcl:"disk_size_gb"`
DiskType *string `mapstructure:"disk_type" required:"false" cty:"disk_type" hcl:"disk_type"`
DiskLabels map[string]string `mapstructure:"disk_labels" required:"false" cty:"disk_labels" hcl:"disk_labels"`
SubnetID *string `mapstructure:"subnet_id" required:"false" cty:"subnet_id" hcl:"subnet_id"`
Zone *string `mapstructure:"zone" required:"false" cty:"zone" hcl:"zone"`
UseIPv4Nat *bool `mapstructure:"use_ipv4_nat" required:"false" cty:"use_ipv4_nat" hcl:"use_ipv4_nat"`
UseIPv6 *bool `mapstructure:"use_ipv6" required:"false" cty:"use_ipv6" hcl:"use_ipv6"`
UseInternalIP *bool `mapstructure:"use_internal_ip" required:"false" cty:"use_internal_ip" hcl:"use_internal_ip"`
FolderID *string `mapstructure:"folder_id" required:"true" cty:"folder_id" hcl:"folder_id"`
ServiceAccountID *string `mapstructure:"service_account_id" required:"true" cty:"service_account_id" hcl:"service_account_id"`
Paths []string `mapstructure:"paths" required:"true" cty:"paths" hcl:"paths"`
SSHPrivateKeyFile *string `mapstructure:"ssh_private_key_file" required:"false" cty:"ssh_private_key_file" hcl:"ssh_private_key_file"`
}
// FlatMapstructure returns a new FlatConfig.
@ -55,14 +70,29 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"service_account_key_file": &hcldec.AttrSpec{Name: "service_account_key_file", Type: cty.String, Required: false},
"token": &hcldec.AttrSpec{Name: "token", Type: cty.String, Required: false},
"max_retries": &hcldec.AttrSpec{Name: "max_retries", Type: cty.Number, Required: false},
"paths": &hcldec.AttrSpec{Name: "paths", Type: cty.List(cty.String), Required: false},
"folder_id": &hcldec.AttrSpec{Name: "folder_id", Type: cty.String, Required: false},
"service_account_id": &hcldec.AttrSpec{Name: "service_account_id", Type: cty.String, Required: false},
"disk_size": &hcldec.AttrSpec{Name: "disk_size", Type: cty.Number, Required: false},
"disk_type": &hcldec.AttrSpec{Name: "disk_type", Type: cty.String, Required: false},
"serial_log_file": &hcldec.AttrSpec{Name: "serial_log_file", Type: cty.String, Required: false},
"instance_cores": &hcldec.AttrSpec{Name: "instance_cores", Type: cty.Number, Required: false},
"instance_gpus": &hcldec.AttrSpec{Name: "instance_gpus", Type: cty.Number, Required: false},
"instance_mem_gb": &hcldec.AttrSpec{Name: "instance_mem_gb", Type: cty.Number, Required: false},
"instance_name": &hcldec.AttrSpec{Name: "instance_name", Type: cty.String, Required: false},
"platform_id": &hcldec.AttrSpec{Name: "platform_id", Type: cty.String, Required: false},
"labels": &hcldec.AttrSpec{Name: "labels", Type: cty.Map(cty.String), Required: false},
"metadata": &hcldec.AttrSpec{Name: "metadata", Type: cty.Map(cty.String), Required: false},
"metadata_from_file": &hcldec.AttrSpec{Name: "metadata_from_file", Type: cty.Map(cty.String), Required: false},
"preemptible": &hcldec.AttrSpec{Name: "preemptible", Type: cty.Bool, Required: false},
"disk_name": &hcldec.AttrSpec{Name: "disk_name", Type: cty.String, Required: false},
"disk_size_gb": &hcldec.AttrSpec{Name: "disk_size_gb", Type: cty.Number, Required: false},
"disk_type": &hcldec.AttrSpec{Name: "disk_type", Type: cty.String, Required: false},
"disk_labels": &hcldec.AttrSpec{Name: "disk_labels", Type: cty.Map(cty.String), Required: false},
"subnet_id": &hcldec.AttrSpec{Name: "subnet_id", Type: cty.String, Required: false},
"zone": &hcldec.AttrSpec{Name: "zone", Type: cty.String, Required: false},
"use_ipv4_nat": &hcldec.AttrSpec{Name: "use_ipv4_nat", Type: cty.Bool, Required: false},
"use_ipv6": &hcldec.AttrSpec{Name: "use_ipv6", Type: cty.Bool, Required: false},
"use_internal_ip": &hcldec.AttrSpec{Name: "use_internal_ip", Type: cty.Bool, Required: false},
"folder_id": &hcldec.AttrSpec{Name: "folder_id", Type: cty.String, Required: false},
"service_account_id": &hcldec.AttrSpec{Name: "service_account_id", Type: cty.String, Required: false},
"paths": &hcldec.AttrSpec{Name: "paths", Type: cty.List(cty.String), Required: false},
"ssh_private_key_file": &hcldec.AttrSpec{Name: "ssh_private_key_file", Type: cty.String, Required: false},
}
return s
}

View File

@ -31,6 +31,12 @@ func TestPostProcessor_Configure(t *testing.T) {
Token: "",
ServiceAccountKeyFile: "",
},
ExchangeConfig: ExchangeConfig{
ServiceAccountID: "some-srv-acc-id",
},
CommonConfig: yandex.CommonConfig{
FolderID: "some-folder-id",
},
},
},
wantErr: false,
@ -43,6 +49,12 @@ func TestPostProcessor_Configure(t *testing.T) {
Token: "some-value",
ServiceAccountKeyFile: "path/not-exist.file",
},
ExchangeConfig: ExchangeConfig{
ServiceAccountID: "some-srv-acc-id",
},
CommonConfig: yandex.CommonConfig{
FolderID: "some-folder-id",
},
},
},
wantErr: true,
@ -55,10 +67,50 @@ func TestPostProcessor_Configure(t *testing.T) {
Token: "",
ServiceAccountKeyFile: "testdata/fake-sa-key.json",
},
ExchangeConfig: ExchangeConfig{
ServiceAccountID: "some-srv-acc-id",
},
CommonConfig: yandex.CommonConfig{
FolderID: "some-folder-id",
},
},
},
wantErr: false,
},
{
name: "service_account_id required",
fields: fields{
config: Config{
AccessConfig: yandex.AccessConfig{
Token: "some token",
},
ExchangeConfig: ExchangeConfig{
ServiceAccountID: "",
},
CommonConfig: yandex.CommonConfig{
FolderID: "some-folder-id",
},
},
},
wantErr: true,
},
{
name: "folderID required",
fields: fields{
config: Config{
AccessConfig: yandex.AccessConfig{
Token: "some token",
},
ExchangeConfig: ExchangeConfig{
ServiceAccountID: "some-srv-acc-id",
},
CommonConfig: yandex.CommonConfig{
FolderID: "",
},
},
},
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {

View File

@ -6,7 +6,6 @@ package yandeximport
import (
"context"
"fmt"
"os"
"github.com/hashicorp/hcl/v2/hcldec"
"github.com/hashicorp/packer/builder/file"
@ -24,12 +23,9 @@ import (
type Config struct {
common.PackerConfig `mapstructure:",squash"`
yandex.AccessConfig `mapstructure:",squash"`
// The folder ID that will be used to store imported Image.
FolderID string `mapstructure:"folder_id" required:"true"`
// Service Account ID with proper permission to use Storage service
// for operations 'upload' and 'delete' object to `bucket`.
ServiceAccountID string `mapstructure:"service_account_id" required:"true"`
yandex.CloudConfig `mapstructure:",squash"`
yandexexport.ExchangeConfig `mapstructure:",squash"`
yandex.ImageConfig `mapstructure:",squash"`
// The name of the bucket where the qcow2 file will be uploaded to for import.
// This bucket must exist when the post-processor is run.
@ -46,16 +42,6 @@ type Config struct {
// leave it in the bucket, `false` to remove it. Default is `false`.
SkipClean bool `mapstructure:"skip_clean" required:"false"`
// The name of the image, which contains 1-63 characters and only
// supports lowercase English characters, numbers and hyphen.
ImageName string `mapstructure:"image_name" required:"false"`
// The description of the image.
ImageDescription string `mapstructure:"image_description" required:"false"`
// The family name of the imported image.
ImageFamily string `mapstructure:"image_family" required:"false"`
// Key/value pair labels to apply to the imported image.
ImageLabels map[string]string `mapstructure:"image_labels" required:"false"`
ctx interpolate.Context
}
@ -83,11 +69,10 @@ func (p *PostProcessor) Configure(raws ...interface{}) error {
// Accumulate any errors
var errs *packersdk.MultiError
errs = packersdk.MultiErrorAppend(errs, p.config.AccessConfig.Prepare(&p.config.ctx)...)
if p.config.FolderID == "" {
p.config.FolderID = os.Getenv("YC_FOLDER_ID")
}
errs = packer.MultiErrorAppend(errs, p.config.AccessConfig.Prepare(&p.config.ctx)...)
errs = p.config.CloudConfig.Prepare(errs)
errs = p.config.ImageConfig.Prepare(errs)
errs = p.config.ExchangeConfig.Prepare(errs)
// Set defaults
if p.config.ObjectName == "" {
@ -100,20 +85,6 @@ func (p *PostProcessor) Configure(raws ...interface{}) error {
errs, fmt.Errorf("error parsing object_name template: %s", err))
}
// TODO: make common code to check and prepare Yandex.Cloud auth configuration data
templates := map[string]*string{
"object_name": &p.config.ObjectName,
"folder_id": &p.config.FolderID,
}
for key, ptr := range templates {
if *ptr == "" {
errs = packersdk.MultiErrorAppend(
errs, fmt.Errorf("%s must be set", key))
}
}
if len(errs.Errors) > 0 {
return errs
}
@ -199,7 +170,7 @@ func (p *PostProcessor) PostProcess(ctx context.Context, ui packersdk.Ui, artifa
return nil, false, false, err
}
ycImage, err := createYCImage(ctx, client, ui, p.config.FolderID, imageSrc, p.config.ImageName, p.config.ImageDescription, p.config.ImageFamily, p.config.ImageLabels)
ycImage, err := createYCImage(ctx, client, ui, imageSrc, &p.config)
if err != nil {
return nil, false, false, err
}

View File

@ -23,13 +23,15 @@ type FlatConfig struct {
MaxRetries *int `mapstructure:"max_retries" cty:"max_retries" hcl:"max_retries"`
FolderID *string `mapstructure:"folder_id" required:"true" cty:"folder_id" hcl:"folder_id"`
ServiceAccountID *string `mapstructure:"service_account_id" required:"true" cty:"service_account_id" hcl:"service_account_id"`
Bucket *string `mapstructure:"bucket" required:"false" cty:"bucket" hcl:"bucket"`
ObjectName *string `mapstructure:"object_name" required:"false" cty:"object_name" hcl:"object_name"`
SkipClean *bool `mapstructure:"skip_clean" required:"false" cty:"skip_clean" hcl:"skip_clean"`
ImageName *string `mapstructure:"image_name" required:"false" cty:"image_name" hcl:"image_name"`
ImageDescription *string `mapstructure:"image_description" required:"false" cty:"image_description" hcl:"image_description"`
ImageFamily *string `mapstructure:"image_family" required:"false" cty:"image_family" hcl:"image_family"`
ImageLabels map[string]string `mapstructure:"image_labels" required:"false" cty:"image_labels" hcl:"image_labels"`
ImageMinDiskSizeGb *int `mapstructure:"image_min_disk_size_gb" required:"false" cty:"image_min_disk_size_gb" hcl:"image_min_disk_size_gb"`
ImageProductIDs []string `mapstructure:"image_product_ids" required:"false" cty:"image_product_ids" hcl:"image_product_ids"`
Bucket *string `mapstructure:"bucket" required:"false" cty:"bucket" hcl:"bucket"`
ObjectName *string `mapstructure:"object_name" required:"false" cty:"object_name" hcl:"object_name"`
SkipClean *bool `mapstructure:"skip_clean" required:"false" cty:"skip_clean" hcl:"skip_clean"`
}
// FlatMapstructure returns a new FlatConfig.
@ -58,13 +60,15 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
"max_retries": &hcldec.AttrSpec{Name: "max_retries", Type: cty.Number, Required: false},
"folder_id": &hcldec.AttrSpec{Name: "folder_id", Type: cty.String, Required: false},
"service_account_id": &hcldec.AttrSpec{Name: "service_account_id", Type: cty.String, Required: false},
"bucket": &hcldec.AttrSpec{Name: "bucket", Type: cty.String, Required: false},
"object_name": &hcldec.AttrSpec{Name: "object_name", Type: cty.String, Required: false},
"skip_clean": &hcldec.AttrSpec{Name: "skip_clean", Type: cty.Bool, Required: false},
"image_name": &hcldec.AttrSpec{Name: "image_name", Type: cty.String, Required: false},
"image_description": &hcldec.AttrSpec{Name: "image_description", Type: cty.String, Required: false},
"image_family": &hcldec.AttrSpec{Name: "image_family", Type: cty.String, Required: false},
"image_labels": &hcldec.AttrSpec{Name: "image_labels", Type: cty.Map(cty.String), Required: false},
"image_min_disk_size_gb": &hcldec.AttrSpec{Name: "image_min_disk_size_gb", Type: cty.Number, Required: false},
"image_product_ids": &hcldec.AttrSpec{Name: "image_product_ids", Type: cty.List(cty.String), Required: false},
"bucket": &hcldec.AttrSpec{Name: "bucket", Type: cty.String, Required: false},
"object_name": &hcldec.AttrSpec{Name: "object_name", Type: cty.String, Required: false},
"skip_clean": &hcldec.AttrSpec{Name: "skip_clean", Type: cty.Bool, Required: false},
}
return s
}

View File

@ -66,13 +66,15 @@ func uploadToBucket(s3conn *s3.S3, ui packersdk.Ui, artifact packersdk.Artifact,
}, nil
}
func createYCImage(ctx context.Context, driver yandex.Driver, ui packersdk.Ui, folderID string, imageSrc cloudImageSource, imageName string, imageDescription string, imageFamily string, imageLabels map[string]string) (*compute.Image, error) {
func createYCImage(ctx context.Context, driver yandex.Driver, ui packer.Ui, imageSrc cloudImageSource, c *Config) (*compute.Image, error) {
req := &compute.CreateImageRequest{
FolderId: folderID,
Name: imageName,
Description: imageDescription,
Labels: imageLabels,
Family: imageFamily,
FolderId: c.CloudConfig.FolderID,
Name: c.ImageConfig.ImageName,
Description: c.ImageConfig.ImageDescription,
Labels: c.ImageConfig.ImageLabels,
Family: c.ImageConfig.ImageFamily,
MinDiskSize: int64(c.ImageMinDiskSizeGb),
ProductIds: c.ImageProductIDs,
}
// switch on cloudImageSource type: cloud image id or storage URL
@ -91,7 +93,7 @@ func createYCImage(ctx context.Context, driver yandex.Driver, ui packersdk.Ui, f
ui.Say(fmt.Sprintf("Source of Image creation: %s", imageSrc.Description()))
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", c.ImageName, op.Id()))
ui.Say("Waiting for Yandex Compute Image creation operation to complete...")
err = op.Wait(ctx)

View File

@ -73,16 +73,48 @@ can also be supplied to override the typical auto-generated key:
### Required:
#### Access
@include 'builder/yandex/AccessConfig-required.mdx'
#### Builder
@include 'builder/yandex/Config-required.mdx'
#### Common
@include 'builder/yandex/CloudConfig-required.mdx'
### Optional:
#### Access
@include 'builder/yandex/AccessConfig-not-required.mdx'
#### Builder
@include 'builder/yandex/Config-not-required.mdx'
#### Common
@include 'builder/yandex/CommonConfig-not-required.mdx'
#### Instance
@include 'builder/yandex/InstanceConfig-not-required.mdx'
#### Disk
@include 'builder/yandex/DiskConfig-not-required.mdx'
#### Image
@include 'builder/yandex/ImageConfig-not-required.mdx'
#### Network
@include 'builder/yandex/NetworkConfig-not-required.mdx'
## Build template data
In configuration directives the following variables are available:

View File

@ -33,16 +33,50 @@ image.
### Required:
#### Access
@include 'builder/yandex/AccessConfig-required.mdx'
#### Export
@include 'post-processor/yandex-export/Config-required.mdx'
#### Common
@include 'builder/yandex/CloudConfig-required.mdx'
@include 'post-processor/yandex-export/ExchangeConfig-required.mdx'
### Optional:
#### Access
@include 'builder/yandex/AccessConfig-not-required.mdx'
#### Export
@include 'post-processor/yandex-export/Config-not-required.mdx'
#### Common
@include 'builder/yandex/CommonConfig-not-required.mdx'
#### Instance
@include 'builder/yandex/InstanceConfig-not-required.mdx'
#### Disk
@include 'builder/yandex/DiskConfig-not-required.mdx'
#### Image
@include 'builder/yandex/ImageConfig-not-required.mdx'
#### Network
@include 'builder/yandex/NetworkConfig-not-required.mdx'
## Basic Example
The following example builds a Compute image in the folder with id `b1g8jvfcgmitdrslcn86`, with an

View File

@ -25,16 +25,30 @@ file.
### Required:
#### Access
@include 'builder/yandex/AccessConfig-required.mdx'
@include 'post-processor/yandex-import/Config-required.mdx'
#### Common
@include 'builder/yandex/CloudConfig-required.mdx'
@include 'post-processor/yandex-export/ExchangeConfig-required.mdx'
### Optional:
#### Access
@include 'builder/yandex/AccessConfig-not-required.mdx'
#### Import
@include 'post-processor/yandex-import/Config-not-required.mdx'
#### Image
@include 'builder/yandex/ImageConfig-not-required.mdx'
## Basic Example
TBD

View File

@ -0,0 +1,6 @@
<!-- Code generated from the comments of the CloudConfig struct in builder/yandex/common_config.go; DO NOT EDIT MANUALLY -->
- `folder_id` (string) - The folder ID that will be used to launch instances and store images.
Alternatively you may set value by environment variable `YC_FOLDER_ID`.
To use a different folder for looking up the source image or saving the target image to
check options 'source_image_folder_id' and 'target_image_folder_id'.

View File

@ -0,0 +1,3 @@
<!-- Code generated from the comments of the CommonConfig struct in builder/yandex/common_config.go; DO NOT EDIT MANUALLY -->
- `serial_log_file` (string) - File path to save serial port output of the launched instance.

View File

@ -2,50 +2,6 @@
- `service_account_id` (string) - Service account identifier to assign to instance.
- `disk_name` (string) - The name of the disk, if unset the instance name
will be used.
- `disk_size_gb` (int) - 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_labels` (map[string]string) - Key/value pair labels to apply to the disk.
- `image_description` (string) - The description of the resulting image.
- `image_family` (string) - The family name of the resulting image.
- `image_labels` (map[string]string) - Key/value pair labels to apply to the created image.
- `image_min_disk_size_gb` (int) - Minimum size of the disk that will be created from built image, specified in gigabytes.
Should be more or equal to `disk_size_gb`.
- `image_name` (string) - The unique name of the resulting image. Defaults to
`packer-{{timestamp}}`.
- `image_product_ids` ([]string) - License IDs that indicate which licenses are attached to resulting image.
- `instance_cores` (int) - The number of cores available to the instance.
- `instance_gpus` (int) - The number of GPU available to the instance.
- `instance_mem_gb` (int) - The amount of memory available to the instance, specified in gigabytes.
- `instance_name` (string) - The name assigned to the instance.
- `labels` (map[string]string) - Key/value pair labels to apply to the launched instance.
- `platform_id` (string) - Identifier of the hardware platform configuration for the instance. This defaults to `standard-v1`.
- `metadata` (map[string]string) - Metadata applied to the launched instance.
- `metadata_from_file` (map[string]string) - Metadata applied to the launched instance.
The values in this map are the paths to the content files for the corresponding metadata keys.
- `preemptible` (bool) - Launch a preemptible instance. This defaults to `false`.
- `serial_log_file` (string) - File path to save serial port output of the launched instance.
- `source_image_folder_id` (string) - The ID of the folder containing the source image.
- `source_image_id` (string) - The source image ID to use to create the new image from.
@ -53,25 +9,8 @@
- `source_image_name` (string) - The source image name to use to create the new image
from. Name will be looked up in `source_image_folder_id`.
- `subnet_id` (string) - The Yandex VPC subnet id to use for
the launched instance. Note, the zone of the subnet must match the
zone in which the VM is launched.
- `target_image_folder_id` (string) - The ID of the folder to save built image in.
This defaults to value of 'folder_id'.
- `use_ipv4_nat` (bool) - If set to true, then launched instance will have external internet
access.
- `use_ipv6` (bool) - Set to true to enable IPv6 for the instance being
created. This defaults to `false`, or not enabled.
-> **Note**: Usage of IPv6 will be available in the future.
- `use_internal_ip` (bool) - If true, use the instance's internal IP address
instead of its external IP during building.
- `zone` (string) - The name of the zone to launch the instance. This defaults to `ru-central1-a`.
- `state_timeout` (duration string | ex: "1h5m2s") - The time to wait for instance state changes.
Defaults to `5m`.

View File

@ -1,10 +1,5 @@
<!-- Code generated from the comments of the Config struct in builder/yandex/config.go; DO NOT EDIT MANUALLY -->
- `folder_id` (string) - The folder ID that will be used to launch instances and store images.
Alternatively you may set value by environment variable `YC_FOLDER_ID`.
To use a different folder for looking up the source image or saving the target image to
check options 'source_image_folder_id' and 'target_image_folder_id'.
- `source_image_family` (string) - The source image family to create the new image
from. You can also specify source_image_id instead. Just one of a source_image_id or
source_image_family must be specified. Example: `ubuntu-1804-lts`.

View File

@ -0,0 +1,10 @@
<!-- Code generated from the comments of the DiskConfig struct in builder/yandex/common_config.go; DO NOT EDIT MANUALLY -->
- `disk_name` (string) - The name of the disk, if unset the instance name
will be used.
- `disk_size_gb` (int) - The size of the disk in GB. This defaults to 10/100GB.
- `disk_type` (string) - Specify disk type for the launched instance. Defaults to `network-ssd`.
- `disk_labels` (map[string]string) - Key/value pair labels to apply to the disk.

View File

@ -0,0 +1,16 @@
<!-- Code generated from the comments of the ImageConfig struct in builder/yandex/common_config.go; DO NOT EDIT MANUALLY -->
- `image_name` (string) - The name of the resulting image, which contains 1-63 characters and only
supports lowercase English characters, numbers and hyphen. Defaults to
`packer-{{timestamp}}`.
- `image_description` (string) - The description of the image.
- `image_family` (string) - The family name of the image.
- `image_labels` (map[string]string) - Key/value pair labels to apply to the image.
- `image_min_disk_size_gb` (int) - Minimum size of the disk that will be created from built image, specified in gigabytes.
Should be more or equal to `disk_size_gb`.
- `image_product_ids` ([]string) - License IDs that indicate which licenses are attached to resulting image.

View File

@ -0,0 +1,20 @@
<!-- Code generated from the comments of the InstanceConfig struct in builder/yandex/common_config.go; DO NOT EDIT MANUALLY -->
- `instance_cores` (int) - The number of cores available to the instance.
- `instance_gpus` (int) - The number of GPU available to the instance.
- `instance_mem_gb` (int) - The amount of memory available to the instance, specified in gigabytes.
- `instance_name` (string) - The name assigned to the instance.
- `platform_id` (string) - Identifier of the hardware platform configuration for the instance. This defaults to `standard-v2`.
- `labels` (map[string]string) - Key/value pair labels to apply to the launched instance.
- `metadata` (map[string]string) - Metadata applied to the launched instance.
- `metadata_from_file` (map[string]string) - Metadata applied to the launched instance.
The values in this map are the paths to the content files for the corresponding metadata keys.
- `preemptible` (bool) - Launch a preemptible instance. This defaults to `false`.

View File

@ -0,0 +1,18 @@
<!-- Code generated from the comments of the NetworkConfig struct in builder/yandex/common_config.go; DO NOT EDIT MANUALLY -->
- `subnet_id` (string) - The Yandex VPC subnet id to use for
the launched instance. Note, the zone of the subnet must match the
zone in which the VM is launched.
- `zone` (string) - The name of the zone to launch the instance. This defaults to `ru-central1-a`.
- `use_ipv4_nat` (bool) - If set to true, then launched instance will have external internet
access.
- `use_ipv6` (bool) - Set to true to enable IPv6 for the instance being
created. This defaults to `false`, or not enabled.
-> **Note**: Usage of IPv6 will be available in the future.
- `use_internal_ip` (bool) - If true, use the instance's internal IP address
instead of its external IP during building.

View File

@ -1,13 +1,5 @@
<!-- Code generated from the comments of the Config struct in post-processor/yandex-export/post-processor.go; DO NOT EDIT MANUALLY -->
- `disk_size` (int) - The size of the disk in GB. This defaults to `100`, which is 100GB.
- `disk_type` (string) - Specify disk type for the launched instance. Defaults to `network-ssd`.
- `platform_id` (string) - Identifier of the hardware platform configuration for the instance. This defaults to `standard-v2`.
- `subnet_id` (string) - The Yandex VPC subnet id to use for
the launched instance. Note, the zone of the subnet must match the
zone in which the VM is launched.
- `zone` (string) - The name of the zone to launch the instance. This defaults to `ru-central1-a`.
- `ssh_private_key_file` (string) - Path to a PEM encoded private key file to use to authenticate with SSH.
The `~` can be used in path and will be expanded to the home directory
of current user. Login for attach: `ubuntu`

View File

@ -5,9 +5,3 @@
Also this param support [build](/docs/templates/engine) template function.
Check available template data for [Yandex](/docs/builders/yandex#build-template-data) builder.
Paths to Yandex Object Storage where exported image will be uploaded.
- `folder_id` (string) - The folder ID that will be used to launch a temporary instance.
Alternatively you may set value by environment variable `YC_FOLDER_ID`.
- `service_account_id` (string) - Service Account ID with proper permission to modify an instance, create and attach disk and
make upload to specific Yandex Object Storage paths.

View File

@ -0,0 +1,4 @@
<!-- Code generated from the comments of the ExchangeConfig struct in post-processor/yandex-export/config.go; DO NOT EDIT MANUALLY -->
- `service_account_id` (string) - Service Account ID with proper permission to modify an instance, create and attach disk and
make upload to specific Yandex Object Storage paths.

View File

@ -13,12 +13,3 @@
- `skip_clean` (bool) - Whether skip removing the qcow2 file uploaded to Storage
after the import process has completed. Possible values are: `true` to
leave it in the bucket, `false` to remove it. Default is `false`.
- `image_name` (string) - The name of the image, which contains 1-63 characters and only
supports lowercase English characters, numbers and hyphen.
- `image_description` (string) - The description of the image.
- `image_family` (string) - The family name of the imported image.
- `image_labels` (map[string]string) - Key/value pair labels to apply to the imported image.

View File

@ -1,6 +0,0 @@
<!-- Code generated from the comments of the Config struct in post-processor/yandex-import/post-processor.go; DO NOT EDIT MANUALLY -->
- `folder_id` (string) - The folder ID that will be used to store imported Image.
- `service_account_id` (string) - Service Account ID with proper permission to use Storage service
for operations 'upload' and 'delete' object to `bucket`.