Remove "exoscale-import" post-processor

This change removes the `exoscale-import` post-processor from the
upstream Packer repository, following extraction as a standalone plugin
in a dedicated repository (https://github.com/exoscale/packer-post-processor-exoscale-import)
This commit is contained in:
Marc Falzon 2020-08-07 16:15:09 +02:00 committed by Wilken Rivera
parent 3ac5046260
commit 125a2f1f76
7 changed files with 335 additions and 386 deletions

View File

@ -87,7 +87,6 @@
/post-processor/alicloud-import/ dongxiao.zzh@alibaba-inc.com
/post-processor/checksum/ v.tolstov@selfip.ru
/post-processor/exoscale-import/ @falzm @mcorbin
/post-processor/googlecompute-export/ crunkleton@google.com
/post-processor/yandex-export/ @GennadySpb
/post-processor/yandex-import/ @GennadySpb

View File

@ -72,7 +72,6 @@ import (
checksumpostprocessor "github.com/hashicorp/packer/post-processor/checksum"
compresspostprocessor "github.com/hashicorp/packer/post-processor/compress"
digitaloceanimportpostprocessor "github.com/hashicorp/packer/post-processor/digitalocean-import"
exoscaleimportpostprocessor "github.com/hashicorp/packer/post-processor/exoscale-import"
googlecomputeexportpostprocessor "github.com/hashicorp/packer/post-processor/googlecompute-export"
googlecomputeimportpostprocessor "github.com/hashicorp/packer/post-processor/googlecompute-import"
manifestpostprocessor "github.com/hashicorp/packer/post-processor/manifest"
@ -190,7 +189,6 @@ var PostProcessors = map[string]packersdk.PostProcessor{
"checksum": new(checksumpostprocessor.PostProcessor),
"compress": new(compresspostprocessor.PostProcessor),
"digitalocean-import": new(digitaloceanimportpostprocessor.PostProcessor),
"exoscale-import": new(exoscaleimportpostprocessor.PostProcessor),
"googlecompute-export": new(googlecomputeexportpostprocessor.PostProcessor),
"googlecompute-import": new(googlecomputeimportpostprocessor.PostProcessor),
"manifest": new(manifestpostprocessor.PostProcessor),

View File

@ -1,31 +0,0 @@
package exoscaleimport
const BuilderId = "packer.post-processor.exoscale-import"
type Artifact struct {
id string
}
func (a *Artifact) BuilderId() string {
return BuilderId
}
func (a *Artifact) Id() string {
return a.id
}
func (a *Artifact) Files() []string {
return nil
}
func (a *Artifact) String() string {
return a.id
}
func (a *Artifact) State(name string) interface{} {
return nil
}
func (a *Artifact) Destroy() error {
return nil
}

View File

@ -1,270 +0,0 @@
//go:generate mapstructure-to-hcl2 -type Config
package exoscaleimport
import (
"context"
"crypto/md5"
"encoding/base64"
"fmt"
"io"
"os"
"path/filepath"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/credentials"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/s3"
"github.com/aws/aws-sdk-go/service/s3/s3manager"
"github.com/exoscale/egoscale"
"github.com/hashicorp/hcl/v2/hcldec"
"github.com/hashicorp/packer-plugin-sdk/common"
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
"github.com/hashicorp/packer-plugin-sdk/template/config"
"github.com/hashicorp/packer/builder/file"
"github.com/hashicorp/packer/builder/qemu"
"github.com/hashicorp/packer/post-processor/artifice"
"github.com/hashicorp/packer/post-processor/exoscale-import/version"
)
var (
defaultTemplateZone = "ch-gva-2"
defaultAPIEndpoint = "https://api.exoscale.com/compute"
defaultSOSEndpoint = "https://sos-" + defaultTemplateZone + ".exo.io"
)
type Config struct {
common.PackerConfig `mapstructure:",squash"`
SkipClean bool `mapstructure:"skip_clean"`
SOSEndpoint string `mapstructure:"sos_endpoint"`
APIEndpoint string `mapstructure:"api_endpoint"`
APIKey string `mapstructure:"api_key"`
APISecret string `mapstructure:"api_secret"`
ImageBucket string `mapstructure:"image_bucket"`
TemplateZone string `mapstructure:"template_zone"`
TemplateName string `mapstructure:"template_name"`
TemplateDescription string `mapstructure:"template_description"`
TemplateUsername string `mapstructure:"template_username"`
TemplateDisablePassword bool `mapstructure:"template_disable_password"`
TemplateDisableSSHKey bool `mapstructure:"template_disable_sshkey"`
}
func init() {
egoscale.UserAgent = "Packer-Exoscale/" + version.ExoscaleImportPluginVersion.FormattedVersion() + " " + egoscale.UserAgent
}
type PostProcessor struct {
config Config
}
func (p *PostProcessor) ConfigSpec() hcldec.ObjectSpec { return p.config.FlatMapstructure().HCL2Spec() }
func (p *PostProcessor) Configure(raws ...interface{}) error {
p.config.TemplateZone = defaultTemplateZone
p.config.APIEndpoint = defaultAPIEndpoint
p.config.SOSEndpoint = defaultSOSEndpoint
if err := config.Decode(&p.config, nil, raws...); err != nil {
return err
}
if p.config.APIKey == "" {
p.config.APIKey = os.Getenv("EXOSCALE_API_KEY")
}
if p.config.APISecret == "" {
p.config.APISecret = os.Getenv("EXOSCALE_API_SECRET")
}
requiredArgs := map[string]*string{
"api_key": &p.config.APIKey,
"api_secret": &p.config.APISecret,
"api_endpoint": &p.config.APIEndpoint,
"sos_endpoint": &p.config.SOSEndpoint,
"image_bucket": &p.config.ImageBucket,
"template_zone": &p.config.TemplateZone,
"template_name": &p.config.TemplateName,
"template_description": &p.config.TemplateDescription,
}
errs := new(packersdk.MultiError)
for k, v := range requiredArgs {
if *v == "" {
errs = packersdk.MultiErrorAppend(
errs, fmt.Errorf("%s must be set", k))
}
}
if len(errs.Errors) > 0 {
return errs
}
packersdk.LogSecretFilter.Set(p.config.APIKey, p.config.APISecret)
return nil
}
func (p *PostProcessor) PostProcess(ctx context.Context, ui packersdk.Ui, a packersdk.Artifact) (packersdk.Artifact, bool, bool, error) {
switch a.BuilderId() {
case qemu.BuilderId, file.BuilderId, artifice.BuilderId:
break
default:
err := fmt.Errorf(
"Unknown artifact type: %s\nCan only import from QEMU/file builders and Artifice post-processor artifacts.",
a.BuilderId())
return nil, false, false, err
}
ui.Message("Uploading template image")
url, md5sum, err := p.uploadImage(ctx, ui, a)
if err != nil {
return nil, false, false, fmt.Errorf("unable to upload image: %s", err)
}
ui.Message("Registering template")
id, err := p.registerTemplate(ctx, ui, url, md5sum)
if err != nil {
return nil, false, false, fmt.Errorf("unable to register template: %s", err)
}
if !p.config.SkipClean {
ui.Message("Deleting uploaded template image")
if err = p.deleteImage(ctx, ui, a); err != nil {
return nil, false, false, fmt.Errorf("unable to delete uploaded template image: %s", err)
}
}
return &Artifact{id}, false, false, nil
}
func (p *PostProcessor) uploadImage(ctx context.Context, ui packersdk.Ui, a packersdk.Artifact) (string, string, error) {
var (
imageFile = a.Files()[0]
bucketFile = filepath.Base(imageFile)
)
f, err := os.Open(imageFile)
if err != nil {
return "", "", err
}
defer f.Close()
fileInfo, err := f.Stat()
if err != nil {
return "", "", err
}
// For tracking image file upload progress
pf := ui.TrackProgress(imageFile, 0, fileInfo.Size(), f)
defer pf.Close()
hash := md5.New()
if _, err := io.Copy(hash, f); err != nil {
return "", "", fmt.Errorf("image checksumming failed: %s", err)
}
if _, err := f.Seek(0, 0); err != nil {
return "", "", err
}
sess := session.Must(session.NewSessionWithOptions(session.Options{Config: aws.Config{
Region: aws.String(p.config.TemplateZone),
Endpoint: aws.String(p.config.SOSEndpoint),
Credentials: credentials.NewStaticCredentials(p.config.APIKey, p.config.APISecret, "")}}))
uploader := s3manager.NewUploader(sess)
output, err := uploader.UploadWithContext(ctx, &s3manager.UploadInput{
Body: pf,
Bucket: aws.String(p.config.ImageBucket),
Key: aws.String(bucketFile),
ContentMD5: aws.String(base64.StdEncoding.EncodeToString(hash.Sum(nil))),
ACL: aws.String("public-read"),
})
if err != nil {
return "", "", err
}
return output.Location, fmt.Sprintf("%x", hash.Sum(nil)), nil
}
func (p *PostProcessor) deleteImage(ctx context.Context, ui packersdk.Ui, a packersdk.Artifact) error {
var (
imageFile = a.Files()[0]
bucketFile = filepath.Base(imageFile)
)
sess := session.Must(session.NewSessionWithOptions(session.Options{Config: aws.Config{
Region: aws.String(p.config.TemplateZone),
Endpoint: aws.String(p.config.SOSEndpoint),
Credentials: credentials.NewStaticCredentials(p.config.APIKey, p.config.APISecret, "")}}))
svc := s3.New(sess)
if _, err := svc.DeleteObject(&s3.DeleteObjectInput{
Bucket: aws.String(p.config.ImageBucket),
Key: aws.String(bucketFile),
}); err != nil {
return err
}
return nil
}
func (p *PostProcessor) registerTemplate(ctx context.Context, ui packersdk.Ui, url, md5sum string) (string, error) {
var (
passwordEnabled = !p.config.TemplateDisablePassword
sshkeyEnabled = !p.config.TemplateDisableSSHKey
regErr error
)
exo := egoscale.NewClient(p.config.APIEndpoint, p.config.APIKey, p.config.APISecret)
exo.RetryStrategy = egoscale.FibonacciRetryStrategy
zone := egoscale.Zone{Name: p.config.TemplateZone}
if resp, err := exo.GetWithContext(ctx, &zone); err != nil {
return "", fmt.Errorf("template zone lookup failed: %s", err)
} else {
zone.ID = resp.(*egoscale.Zone).ID
}
req := egoscale.RegisterCustomTemplate{
URL: url,
ZoneID: zone.ID,
Name: p.config.TemplateName,
Displaytext: p.config.TemplateDescription,
PasswordEnabled: &passwordEnabled,
SSHKeyEnabled: &sshkeyEnabled,
Details: map[string]string{"username": p.config.TemplateUsername},
Checksum: md5sum,
}
res := make([]egoscale.Template, 0)
exo.AsyncRequestWithContext(ctx, req, func(jobRes *egoscale.AsyncJobResult, err error) bool {
if err != nil {
regErr = fmt.Errorf("request failed: %s", err)
return false
} else if jobRes.JobStatus == egoscale.Pending {
// Job is not completed yet
ui.Message("template registration in progress")
return true
}
if err := jobRes.Result(&res); err != nil {
regErr = err
return false
}
if len(res) != 1 {
regErr = fmt.Errorf("unexpected response from API (expected 1 item, got %d)", len(res))
return false
}
return false
})
if regErr != nil {
return "", regErr
}
return res[0].ID.String(), nil
}

View File

@ -1,69 +0,0 @@
// Code generated by "mapstructure-to-hcl2 -type Config"; DO NOT EDIT.
package exoscaleimport
import (
"github.com/hashicorp/hcl/v2/hcldec"
"github.com/zclconf/go-cty/cty"
)
// FlatConfig is an auto-generated flat version of Config.
// Where the contents of a field with a `mapstructure:,squash` tag are bubbled up.
type FlatConfig struct {
PackerBuildName *string `mapstructure:"packer_build_name" cty:"packer_build_name" hcl:"packer_build_name"`
PackerBuilderType *string `mapstructure:"packer_builder_type" cty:"packer_builder_type" hcl:"packer_builder_type"`
PackerCoreVersion *string `mapstructure:"packer_core_version" cty:"packer_core_version" hcl:"packer_core_version"`
PackerDebug *bool `mapstructure:"packer_debug" cty:"packer_debug" hcl:"packer_debug"`
PackerForce *bool `mapstructure:"packer_force" cty:"packer_force" hcl:"packer_force"`
PackerOnError *string `mapstructure:"packer_on_error" cty:"packer_on_error" hcl:"packer_on_error"`
PackerUserVars map[string]string `mapstructure:"packer_user_variables" cty:"packer_user_variables" hcl:"packer_user_variables"`
PackerSensitiveVars []string `mapstructure:"packer_sensitive_variables" cty:"packer_sensitive_variables" hcl:"packer_sensitive_variables"`
SkipClean *bool `mapstructure:"skip_clean" cty:"skip_clean" hcl:"skip_clean"`
SOSEndpoint *string `mapstructure:"sos_endpoint" cty:"sos_endpoint" hcl:"sos_endpoint"`
APIEndpoint *string `mapstructure:"api_endpoint" cty:"api_endpoint" hcl:"api_endpoint"`
APIKey *string `mapstructure:"api_key" cty:"api_key" hcl:"api_key"`
APISecret *string `mapstructure:"api_secret" cty:"api_secret" hcl:"api_secret"`
ImageBucket *string `mapstructure:"image_bucket" cty:"image_bucket" hcl:"image_bucket"`
TemplateZone *string `mapstructure:"template_zone" cty:"template_zone" hcl:"template_zone"`
TemplateName *string `mapstructure:"template_name" cty:"template_name" hcl:"template_name"`
TemplateDescription *string `mapstructure:"template_description" cty:"template_description" hcl:"template_description"`
TemplateUsername *string `mapstructure:"template_username" cty:"template_username" hcl:"template_username"`
TemplateDisablePassword *bool `mapstructure:"template_disable_password" cty:"template_disable_password" hcl:"template_disable_password"`
TemplateDisableSSHKey *bool `mapstructure:"template_disable_sshkey" cty:"template_disable_sshkey" hcl:"template_disable_sshkey"`
}
// FlatMapstructure returns a new FlatConfig.
// FlatConfig is an auto-generated flat version of Config.
// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up.
func (*Config) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } {
return new(FlatConfig)
}
// HCL2Spec returns the hcl spec of a Config.
// This spec is used by HCL to read the fields of Config.
// The decoded values from this spec will then be applied to a FlatConfig.
func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
s := map[string]hcldec.Spec{
"packer_build_name": &hcldec.AttrSpec{Name: "packer_build_name", Type: cty.String, Required: false},
"packer_builder_type": &hcldec.AttrSpec{Name: "packer_builder_type", Type: cty.String, Required: false},
"packer_core_version": &hcldec.AttrSpec{Name: "packer_core_version", Type: cty.String, Required: false},
"packer_debug": &hcldec.AttrSpec{Name: "packer_debug", Type: cty.Bool, Required: false},
"packer_force": &hcldec.AttrSpec{Name: "packer_force", Type: cty.Bool, Required: false},
"packer_on_error": &hcldec.AttrSpec{Name: "packer_on_error", Type: cty.String, Required: false},
"packer_user_variables": &hcldec.AttrSpec{Name: "packer_user_variables", Type: cty.Map(cty.String), Required: false},
"packer_sensitive_variables": &hcldec.AttrSpec{Name: "packer_sensitive_variables", Type: cty.List(cty.String), Required: false},
"skip_clean": &hcldec.AttrSpec{Name: "skip_clean", Type: cty.Bool, Required: false},
"sos_endpoint": &hcldec.AttrSpec{Name: "sos_endpoint", Type: cty.String, Required: false},
"api_endpoint": &hcldec.AttrSpec{Name: "api_endpoint", Type: cty.String, Required: false},
"api_key": &hcldec.AttrSpec{Name: "api_key", Type: cty.String, Required: false},
"api_secret": &hcldec.AttrSpec{Name: "api_secret", Type: cty.String, Required: false},
"image_bucket": &hcldec.AttrSpec{Name: "image_bucket", Type: cty.String, Required: false},
"template_zone": &hcldec.AttrSpec{Name: "template_zone", Type: cty.String, Required: false},
"template_name": &hcldec.AttrSpec{Name: "template_name", Type: cty.String, Required: false},
"template_description": &hcldec.AttrSpec{Name: "template_description", Type: cty.String, Required: false},
"template_username": &hcldec.AttrSpec{Name: "template_username", Type: cty.String, Required: false},
"template_disable_password": &hcldec.AttrSpec{Name: "template_disable_password", Type: cty.Bool, Required: false},
"template_disable_sshkey": &hcldec.AttrSpec{Name: "template_disable_sshkey", Type: cty.Bool, Required: false},
}
return s
}

View File

@ -1,13 +0,0 @@
package version
import (
"github.com/hashicorp/packer-plugin-sdk/version"
packerVersion "github.com/hashicorp/packer/version"
)
var ExoscaleImportPluginVersion *version.PluginVersion
func init() {
ExoscaleImportPluginVersion = version.InitializePluginVersion(
packerVersion.Version, packerVersion.VersionPrerelease)
}

View File

@ -0,0 +1,335 @@
// The root folder for this documentation category is `pages/docs`
//
// - A string refers to the name of a file
// - A "category" value refers to the name of a directory
// - All directories must have an "index.mdx" file to serve as
// the landing page for the category
export default [
'--------',
'terminology',
{
category: 'commands',
content: ['init', 'build', 'console', 'fix', 'fmt', 'inspect', 'validate', 'hcl2_upgrade'],
},
{
category: 'templates',
content: [
{
category: 'hcl_templates',
content: [
{
category: 'blocks',
content: [
{
category: 'build',
content: [
'source',
'provisioner',
'post-processor',
'post-processors',
],
},
'locals',
'source',
'variable',
'packer',
'data'
],
},
{
category: 'functions',
content: [
{
category: 'contextual',
content: [
'aws_secretsmanager',
'consul',
'env',
'vault',
],
},
{
category: 'numeric',
content: [
'abs',
'ceil',
'floor',
'log',
'max',
'min',
'parseint',
'pow',
'signum',
],
},
{
category: 'string',
content: [
'chomp',
'format',
'formatlist',
'indent',
'join',
'lower',
'replace',
'regex_replace',
'regex',
'regexall',
'split',
'strrev',
'substr',
'title',
'trim',
'trimprefix',
'trimsuffix',
'trimspace',
'upper',
],
},
{
category: 'collection',
content: [
'chunklist',
'coalesce',
'coalescelist',
'compact',
'concat',
'contains',
'distinct',
'element',
'flatten',
'keys',
'length',
'lookup',
'merge',
'range',
'reverse',
'setintersection',
'setproduct',
'setunion',
'slice',
'sort',
'values',
'zipmap',
],
},
{
category: 'encoding',
content: [
'base64decode',
'base64encode',
'csvdecode',
'jsondecode',
'jsonencode',
'urlencode',
'yamldecode',
'yamlencode',
],
},
{
category: 'file',
content: [
'abspath',
'basename',
'dirname',
'file',
'fileexists',
'fileset',
'pathexpand',
],
},
{
category: 'datetime',
content: ['formatdate', 'timeadd', 'timestamp'],
},
{
category: 'crypto',
content: [
'bcrypt',
'md5',
'rsadecrypt',
'sha1',
'sha256',
'sha512',
],
},
{
category: 'uuid',
content: ['uuidv4', 'uuidv5'],
},
{
category: 'ipnet',
content: ['cidrhost', 'cidrnetmask', 'cidrsubnet'],
},
{
category: 'conversion',
content: ['can', 'convert', 'try'],
},
],
},
'variables',
'locals',
'contextual-variables',
'datasources',
'path-variables',
'syntax',
'onlyexcept',
'expressions',
'syntax-json',
],
},
{
category: "legacy_json_templates",
content: [
'builders',
'communicator',
'engine',
'post-processors',
'provisioners',
'user-variables',
]
},
],
},
'----------',
{category: 'communicators', content: ['ssh', 'winrm']},
{
category: 'builders',
content: [
'alicloud-ecs',
{
category: 'amazon',
content: ['chroot', 'ebs', 'ebssurrogate', 'ebsvolume', 'instance'],
},
{
category: 'azure',
content: ['arm', 'chroot'],
},
'cloudstack',
'digitalocean',
'docker',
'file',
'googlecompute',
'hetzner-cloud',
'hyperone',
{category: 'hyperv', content: ['iso', 'vmcx']},
'linode',
'lxc',
'lxd',
'ncloud',
'null',
'oneandone',
'openstack',
{category: 'oracle', content: ['classic', 'oci']},
{
category: 'outscale',
content: ['chroot', 'bsu', 'bsusurrogate', 'bsuvolume'],
},
{category: 'parallels', content: ['iso', 'pvm']},
'profitbricks',
{category: 'proxmox', content: ['iso', 'clone']},
'qemu',
'scaleway',
'tencentcloud-cvm',
'jdcloud',
'triton',
'ucloud-uhost',
'vagrant',
{
category: 'virtualbox',
content: ['iso', 'ovf', 'vm'],
},
{
category: 'vmware',
content: ['iso', 'vmx', 'vsphere-iso', 'vsphere-clone'],
},
'yandex',
'custom',
'community-supported',
],
},
{
category: 'datasources',
content: [
{
category: 'amazon',
content: [
'ami',
'secretsmanager'
],
},
]
},
{
category: 'provisioners',
content: [
'ansible-local',
'ansible',
'breakpoint',
'chef-client',
'chef-solo',
'converge',
'file',
'inspec',
'powershell',
'puppet-masterless',
'puppet-server',
'salt-masterless',
'shell',
'shell-local',
'windows-shell',
'windows-restart',
'custom',
'community-supported',
],
},
{
category: 'post-processors',
content: [
'alicloud-import',
'amazon-import',
'artifice',
'compress',
'checksum',
'digitalocean-import',
'docker-import',
'docker-push',
'docker-save',
'docker-tag',
'googlecompute-export',
'googlecompute-import',
'manifest',
'shell-local',
'ucloud-import',
'vagrant',
'vagrant-cloud',
'vsphere',
'vsphere-template',
'yandex-export',
'yandex-import',
'community-supported',
],
},
'----------',
'install',
'configure',
'----------',
{
category: 'plugins',
content: [
{
category: 'creation',
content: [
'custom-builders',
'custom-post-processors',
'custom-provisioners',
'custom-datasources',
],
},
],
},
'---------',
'debugging',
]