packer-cn/builder/scaleway/config.go

266 lines
8.6 KiB
Go
Raw Normal View History

//go:generate struct-markdown
//go:generate mapstructure-to-hcl2 -type Config
2017-04-06 05:19:17 -04:00
package scaleway
import (
"errors"
"fmt"
"log"
"os"
2017-04-06 05:19:17 -04:00
2020-12-17 16:29:25 -05:00
"github.com/hashicorp/packer-plugin-sdk/common"
"github.com/hashicorp/packer-plugin-sdk/communicator"
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
"github.com/hashicorp/packer-plugin-sdk/template/config"
"github.com/hashicorp/packer-plugin-sdk/template/interpolate"
"github.com/hashicorp/packer-plugin-sdk/useragent"
"github.com/hashicorp/packer-plugin-sdk/uuid"
"github.com/hashicorp/packer/builder/scaleway/version"
2017-04-06 05:19:17 -04:00
"github.com/mitchellh/mapstructure"
"github.com/scaleway/scaleway-sdk-go/api/instance/v1"
"github.com/scaleway/scaleway-sdk-go/scw"
2017-04-06 05:19:17 -04:00
)
type Config struct {
common.PackerConfig `mapstructure:",squash"`
Comm communicator.Config `mapstructure:",squash"`
// The AccessKey corresponding to the secret key.
2020-10-29 12:45:03 -04:00
// Will be fetched first from the [scaleway configuration file](https://github.com/scaleway/scaleway-sdk-go/blob/master/scw/README.md).
// It can also be specified via the environment variable SCW_ACCESS_KEY.
AccessKey string `mapstructure:"access_key" required:"true"`
// The SecretKey to authenticate against the Scaleway API.
2020-10-29 12:45:03 -04:00
// Will be fetched first from the [scaleway configuration file](https://github.com/scaleway/scaleway-sdk-go/blob/master/scw/README.md).
// It can also be specified via the environment variable SCW_SECRET_KEY.
SecretKey string `mapstructure:"secret_key" required:"true"`
// The Project ID in which the instances, volumes and snapshots will be created.
2020-10-29 12:45:03 -04:00
// Will be fetched first from the [scaleway configuration file](https://github.com/scaleway/scaleway-sdk-go/blob/master/scw/README.md).
// It can also be specified via the environment variable SCW_DEFAULT_PROJECT_ID.
ProjectID string `mapstructure:"project_id" required:"true"`
// The Zone in which the instances, volumes and snapshots will be created.
2020-10-29 12:45:03 -04:00
// Will be fetched first from the [scaleway configuration file](https://github.com/scaleway/scaleway-sdk-go/blob/master/scw/README.md).
// It can also be specified via the environment variable SCW_DEFAULT_ZONE
Zone string `mapstructure:"zone" required:"true"`
// The Scaleway API URL to use
2020-10-29 12:45:03 -04:00
// Will be fetched first from the [scaleway configuration file](https://github.com/scaleway/scaleway-sdk-go/blob/master/scw/README.md).
// It can also be specified via the environment variable SCW_API_URL
APIURL string `mapstructure:"api_url"`
// The UUID of the base image to use. This is the image
2019-06-06 10:29:25 -04:00
// that will be used to launch a new server and provision it. See
// the images list
// get the complete list of the accepted image UUID.
// The marketplace image label (eg `ubuntu_focal`) also works.
2019-06-06 10:29:25 -04:00
Image string `mapstructure:"image" required:"true"`
// The name of the server commercial type:
// C1, C2L, C2M, C2S, DEV1-S, DEV1-M, DEV1-L, DEV1-XL,
// GP1-XS, GP1-S, GP1-M, GP1-L, GP1-XL, RENDER-S
CommercialType string `mapstructure:"commercial_type" required:"true"`
// The name of the resulting snapshot that will
2019-06-06 10:29:25 -04:00
// appear in your account. Default packer-TIMESTAMP
SnapshotName string `mapstructure:"snapshot_name" required:"false"`
// The name of the resulting image that will appear in
2019-06-06 10:29:25 -04:00
// your account. Default packer-TIMESTAMP
ImageName string `mapstructure:"image_name" required:"false"`
// The name assigned to the server. Default
2019-06-06 10:29:25 -04:00
// packer-UUID
ServerName string `mapstructure:"server_name" required:"false"`
// The id of an existing bootscript to use when
2019-06-06 10:29:25 -04:00
// booting the server.
Bootscript string `mapstructure:"bootscript" required:"false"`
// The type of boot, can be either local or
2019-06-06 10:29:25 -04:00
// bootscript, Default bootscript
BootType string `mapstructure:"boottype" required:"false"`
2017-04-06 05:19:17 -04:00
RemoveVolume bool `mapstructure:"remove_volume"`
UserAgent string `mapstructure-to-hcl2:",skip"`
2017-04-06 05:19:17 -04:00
ctx interpolate.Context
// Deprecated configs
// The token to use to authenticate with your account.
// It can also be specified via environment variable SCALEWAY_API_TOKEN. You
// can see and generate tokens in the "Credentials"
// section of the control panel.
// Deprecated, use SecretKey instead
Token string `mapstructure:"api_token" required:"false"`
// The organization id to use to identify your
// organization. It can also be specified via environment variable
// SCALEWAY_ORGANIZATION. Your organization id is available in the
// "Account" section of the
// control panel.
// Previously named: api_access_key with environment variable: SCALEWAY_API_ACCESS_KEY
// Deprecated, use ProjectID instead
Organization string `mapstructure:"organization_id" required:"false"`
// The name of the region to launch the server in (par1
// or ams1). Consequently, this is the region where the snapshot will be
// available.
// Deprecated, use Zone instead
Region string `mapstructure:"region" required:"false"`
2017-04-06 05:19:17 -04:00
}
build using HCL2 (#8423) This follows #8232 which added the code to generate the code required to parse HCL files for each packer component. All old config files of packer will keep on working the same. Packer takes one argument. When a directory is passed, all files in the folder with a name ending with “.pkr.hcl” or “.pkr.json” will be parsed using the HCL2 format. When a file ending with “.pkr.hcl” or “.pkr.json” is passed it will be parsed using the HCL2 format. For every other case; the old packer style will be used. ## 1. the hcl2template pkg can create a packer.Build from a set of HCL (v2) files I had to make the packer.coreBuild (which is our one and only packer.Build ) a public struct with public fields ## 2. Components interfaces get a new ConfigSpec Method to read a file from an HCL file. This is a breaking change for packer plugins. a packer component can be a: builder/provisioner/post-processor each component interface now gets a `ConfigSpec() hcldec.ObjectSpec` which allows packer to tell what is the layout of the hcl2 config meant to configure that specific component. This ObjectSpec is sent through the wire (RPC) and a cty.Value is now sent through the already existing configuration entrypoints: Provisioner.Prepare(raws ...interface{}) error Builder.Prepare(raws ...interface{}) ([]string, error) PostProcessor.Configure(raws ...interface{}) error close #1768 Example hcl files: ```hcl // file amazon-ebs-kms-key/run.pkr.hcl build { sources = [ "source.amazon-ebs.first", ] provisioner "shell" { inline = [ "sleep 5" ] } post-processor "shell-local" { inline = [ "sleep 5" ] } } // amazon-ebs-kms-key/source.pkr.hcl source "amazon-ebs" "first" { ami_name = "hcl2-test" region = "us-east-1" instance_type = "t2.micro" kms_key_id = "c729958f-c6ba-44cd-ab39-35ab68ce0a6c" encrypt_boot = true source_ami_filter { filters { virtualization-type = "hvm" name = "amzn-ami-hvm-????.??.?.????????-x86_64-gp2" root-device-type = "ebs" } most_recent = true owners = ["amazon"] } launch_block_device_mappings { device_name = "/dev/xvda" volume_size = 20 volume_type = "gp2" delete_on_termination = "true" } launch_block_device_mappings { device_name = "/dev/xvdf" volume_size = 500 volume_type = "gp2" delete_on_termination = true encrypted = true } ami_regions = ["eu-central-1"] run_tags { Name = "packer-solr-something" stack-name = "DevOps Tools" } communicator = "ssh" ssh_pty = true ssh_username = "ec2-user" associate_public_ip_address = true } ```
2019-12-17 05:25:56 -05:00
func (c *Config) Prepare(raws ...interface{}) ([]string, error) {
2017-04-06 05:19:17 -04:00
var md mapstructure.Metadata
err := config.Decode(c, &config.DecodeOpts{
Metadata: &md,
PluginType: BuilderId,
2017-04-06 05:19:17 -04:00
Interpolate: true,
InterpolateContext: &c.ctx,
InterpolateFilter: &interpolate.RenderFilter{
Exclude: []string{
"run_command",
},
},
}, raws...)
if err != nil {
build using HCL2 (#8423) This follows #8232 which added the code to generate the code required to parse HCL files for each packer component. All old config files of packer will keep on working the same. Packer takes one argument. When a directory is passed, all files in the folder with a name ending with “.pkr.hcl” or “.pkr.json” will be parsed using the HCL2 format. When a file ending with “.pkr.hcl” or “.pkr.json” is passed it will be parsed using the HCL2 format. For every other case; the old packer style will be used. ## 1. the hcl2template pkg can create a packer.Build from a set of HCL (v2) files I had to make the packer.coreBuild (which is our one and only packer.Build ) a public struct with public fields ## 2. Components interfaces get a new ConfigSpec Method to read a file from an HCL file. This is a breaking change for packer plugins. a packer component can be a: builder/provisioner/post-processor each component interface now gets a `ConfigSpec() hcldec.ObjectSpec` which allows packer to tell what is the layout of the hcl2 config meant to configure that specific component. This ObjectSpec is sent through the wire (RPC) and a cty.Value is now sent through the already existing configuration entrypoints: Provisioner.Prepare(raws ...interface{}) error Builder.Prepare(raws ...interface{}) ([]string, error) PostProcessor.Configure(raws ...interface{}) error close #1768 Example hcl files: ```hcl // file amazon-ebs-kms-key/run.pkr.hcl build { sources = [ "source.amazon-ebs.first", ] provisioner "shell" { inline = [ "sleep 5" ] } post-processor "shell-local" { inline = [ "sleep 5" ] } } // amazon-ebs-kms-key/source.pkr.hcl source "amazon-ebs" "first" { ami_name = "hcl2-test" region = "us-east-1" instance_type = "t2.micro" kms_key_id = "c729958f-c6ba-44cd-ab39-35ab68ce0a6c" encrypt_boot = true source_ami_filter { filters { virtualization-type = "hvm" name = "amzn-ami-hvm-????.??.?.????????-x86_64-gp2" root-device-type = "ebs" } most_recent = true owners = ["amazon"] } launch_block_device_mappings { device_name = "/dev/xvda" volume_size = 20 volume_type = "gp2" delete_on_termination = "true" } launch_block_device_mappings { device_name = "/dev/xvdf" volume_size = 500 volume_type = "gp2" delete_on_termination = true encrypted = true } ami_regions = ["eu-central-1"] run_tags { Name = "packer-solr-something" stack-name = "DevOps Tools" } communicator = "ssh" ssh_pty = true ssh_username = "ec2-user" associate_public_ip_address = true } ```
2019-12-17 05:25:56 -05:00
return nil, err
2017-04-06 05:19:17 -04:00
}
var warnings []string
c.UserAgent = useragent.String(version.ScalewayPluginVersion.FormattedVersion())
2017-04-06 05:19:17 -04:00
configFile, err := scw.LoadConfig()
// If the config file do not exist, don't return an error as we may find config in ENV or flags.
if _, isNotFoundError := err.(*scw.ConfigFileNotFoundError); isNotFoundError {
configFile = &scw.Config{}
} else if err != nil {
return nil, err
}
activeProfile, err := configFile.GetActiveProfile()
if err != nil {
return nil, err
}
envProfile := scw.LoadEnvProfile()
profile := scw.MergeProfiles(activeProfile, envProfile)
// Deprecated variables
if c.Organization == "" {
if os.Getenv("SCALEWAY_ORGANIZATION") != "" {
c.Organization = os.Getenv("SCALEWAY_ORGANIZATION")
} else {
log.Printf("Deprecation warning: Use SCALEWAY_ORGANIZATION environment variable and organization_id argument instead of api_access_key argument and SCALEWAY_API_ACCESS_KEY environment variable.")
c.Organization = os.Getenv("SCALEWAY_API_ACCESS_KEY")
}
}
if c.Organization != "" {
warnings = append(warnings, "organization_id is deprecated in favor of project_id")
c.ProjectID = c.Organization
}
if c.Token == "" {
c.Token = os.Getenv("SCALEWAY_API_TOKEN")
}
if c.Token != "" {
warnings = append(warnings, "token is deprecated in favor of secret_key")
c.SecretKey = c.Token
}
if c.Region != "" {
warnings = append(warnings, "region is deprecated in favor of zone")
c.Zone = c.Region
}
if c.AccessKey == "" {
2020-10-29 06:09:04 -04:00
if profile.AccessKey != nil {
c.AccessKey = *profile.AccessKey
}
}
if c.SecretKey == "" {
2020-10-29 06:09:04 -04:00
if profile.SecretKey != nil {
c.SecretKey = *profile.SecretKey
}
}
if c.ProjectID == "" {
2020-10-29 06:09:04 -04:00
if profile.DefaultProjectID != nil {
c.ProjectID = *profile.DefaultProjectID
}
}
if c.Zone == "" {
2020-10-29 06:09:04 -04:00
if profile.DefaultZone != nil {
c.Zone = *profile.DefaultZone
}
}
if c.APIURL == "" {
2020-10-29 06:09:04 -04:00
if profile.APIURL != nil {
c.APIURL = *profile.APIURL
}
}
2017-04-06 05:19:17 -04:00
if c.SnapshotName == "" {
def, err := interpolate.Render("snapshot-packer-{{timestamp}}", nil)
2017-04-06 05:19:17 -04:00
if err != nil {
panic(err)
}
c.SnapshotName = def
}
if c.ImageName == "" {
def, err := interpolate.Render("image-packer-{{timestamp}}", nil)
if err != nil {
panic(err)
}
c.ImageName = def
}
2017-04-06 05:19:17 -04:00
if c.ServerName == "" {
// Default to packer-[time-ordered-uuid]
c.ServerName = fmt.Sprintf("packer-%s", uuid.TimeOrderedUUID())
}
if c.BootType == "" {
c.BootType = instance.BootTypeLocal.String()
}
var errs *packersdk.MultiError
2017-04-06 05:19:17 -04:00
if es := c.Comm.Prepare(&c.ctx); len(es) > 0 {
errs = packersdk.MultiErrorAppend(errs, es...)
2017-04-06 05:19:17 -04:00
}
if c.ProjectID == "" {
errs = packersdk.MultiErrorAppend(
2020-10-29 06:09:04 -04:00
errs, errors.New("scaleway Project ID must be specified"))
2017-04-06 05:19:17 -04:00
}
if c.SecretKey == "" {
errs = packersdk.MultiErrorAppend(
2020-10-29 06:09:04 -04:00
errs, errors.New("scaleway Secret Key must be specified"))
}
if c.AccessKey == "" {
warnings = append(warnings, "access_key will be required in future versions")
c.AccessKey = "SCWXXXXXXXXXXXXXXXXX"
2017-04-06 05:19:17 -04:00
}
if c.Zone == "" {
errs = packersdk.MultiErrorAppend(
errs, errors.New("Scaleway Zone is required"))
2017-04-06 05:19:17 -04:00
}
if c.CommercialType == "" {
errs = packersdk.MultiErrorAppend(
2017-04-06 05:19:17 -04:00
errs, errors.New("commercial type is required"))
}
if c.Image == "" {
errs = packersdk.MultiErrorAppend(
2017-04-06 05:19:17 -04:00
errs, errors.New("image is required"))
}
if errs != nil && len(errs.Errors) > 0 {
return warnings, errs
2017-04-06 05:19:17 -04:00
}
2020-11-19 17:03:11 -05:00
packersdk.LogSecretFilter.Set(c.Token)
packersdk.LogSecretFilter.Set(c.SecretKey)
return warnings, nil
2017-04-06 05:19:17 -04:00
}