Merge branch 'master' of https://github.com/ddelnano/packer-plugin-xenserver into destroy-vifs
This commit is contained in:
commit
30400a41a0
6
.github/dependabot.yml
vendored
Normal file
6
.github/dependabot.yml
vendored
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
version: 2
|
||||||
|
updates:
|
||||||
|
- package-ecosystem: "gomod" # See documentation for possible values
|
||||||
|
directory: "/" # Location of package manifests
|
||||||
|
schedule:
|
||||||
|
interval: "daily"
|
24
.github/workflows/go-test.yml
vendored
Normal file
24
.github/workflows/go-test.yml
vendored
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
name: go-test
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- 'main'
|
||||||
|
pull_request:
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
go-tests:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
- name: Unshallow
|
||||||
|
run: git fetch --prune --unshallow
|
||||||
|
- name: Set up Go
|
||||||
|
uses: actions/setup-go@v2
|
||||||
|
with:
|
||||||
|
go-version: 1.16
|
||||||
|
- name: Run go tests
|
||||||
|
run: go test -race -count 1 ./... -timeout=3m
|
10
.github/workflows/release.yml
vendored
10
.github/workflows/release.yml
vendored
@ -25,16 +25,16 @@ jobs:
|
|||||||
- name: Set up Go
|
- name: Set up Go
|
||||||
uses: actions/setup-go@v2
|
uses: actions/setup-go@v2
|
||||||
with:
|
with:
|
||||||
go-version: 1.17
|
go-version: 1.16
|
||||||
- name: Describe plugin
|
- name: Describe plugin
|
||||||
id: plugin_describe
|
id: plugin_describe
|
||||||
run: echo "::set-output name=api_version::$(go run . describe | jq -r '.api_version')"
|
run: echo "::set-output name=api_version::$(go run . describe | jq -r '.api_version')"
|
||||||
- name: Import GPG key
|
- name: Import GPG key
|
||||||
id: import_gpg
|
id: import_gpg
|
||||||
uses: hashicorp/ghaction-import-gpg@v2.1.0
|
uses: crazy-max/ghaction-import-gpg@v5.0.0
|
||||||
env:
|
with:
|
||||||
GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }}
|
gpg_private_key: ${{ secrets.GPG_PRIVATE_KEY }}
|
||||||
PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }}
|
passphrase: ${{ secrets.GPG_PASSPHRASE }}
|
||||||
- name: Run GoReleaser
|
- name: Run GoReleaser
|
||||||
uses: goreleaser/goreleaser-action@v2
|
uses: goreleaser/goreleaser-action@v2
|
||||||
with:
|
with:
|
||||||
|
@ -62,7 +62,7 @@ $ cp builder-xenserver-iso ~/.packer.d/plugins/packer-builder-xenserver-iso
|
|||||||
# Documentation
|
# Documentation
|
||||||
|
|
||||||
For complete documentation on configuration commands, see [the
|
For complete documentation on configuration commands, see [the
|
||||||
xenserver-iso docs](docs/builders/xenserver-iso.html.markdown)
|
xenserver-iso docs](docs/builders/iso/xenserver-iso.html.markdown)
|
||||||
|
|
||||||
## Support
|
## Support
|
||||||
|
|
||||||
|
@ -624,6 +624,17 @@ func ConnectNetwork(c *Connection, networkRef xenapi.NetworkRef, vmRef xenapi.VM
|
|||||||
return &vif, nil
|
return &vif, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func AddVMTags(c *Connection, vmRef xenapi.VMRef, tags []string) error {
|
||||||
|
for _, tag := range tags {
|
||||||
|
log.Printf("Adding tag %s to VM %s\n", tag, vmRef)
|
||||||
|
err := c.GetClient().VM.AddTags(c.session, vmRef, tag)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// Setters
|
// Setters
|
||||||
|
|
||||||
func (self *VM) SetIsATemplate(is_a_template bool) (err error) {
|
func (self *VM) SetIsATemplate(is_a_template bool) (err error) {
|
||||||
|
@ -20,10 +20,11 @@ type CommonConfig struct {
|
|||||||
VMName string `mapstructure:"vm_name"`
|
VMName string `mapstructure:"vm_name"`
|
||||||
VMDescription string `mapstructure:"vm_description"`
|
VMDescription string `mapstructure:"vm_description"`
|
||||||
SrName string `mapstructure:"sr_name"`
|
SrName string `mapstructure:"sr_name"`
|
||||||
SrISOName string `mapstructure:"sr_iso_name"`
|
SrISOName string `mapstructure:"sr_iso_name" required:"false"`
|
||||||
FloppyFiles []string `mapstructure:"floppy_files"`
|
FloppyFiles []string `mapstructure:"floppy_files"`
|
||||||
NetworkNames []string `mapstructure:"network_names"`
|
NetworkNames []string `mapstructure:"network_names"`
|
||||||
ExportNetworkNames []string `mapstructure:"export_network_names"`
|
ExportNetworkNames []string `mapstructure:"export_network_names"`
|
||||||
|
VMTags []string `mapstructure:"vm_tags"`
|
||||||
|
|
||||||
HostPortMin uint `mapstructure:"host_port_min"`
|
HostPortMin uint `mapstructure:"host_port_min"`
|
||||||
HostPortMax uint `mapstructure:"host_port_max"`
|
HostPortMax uint `mapstructure:"host_port_max"`
|
||||||
@ -225,29 +226,11 @@ func (c CommonConfig) ShouldKeepVM(state multistep.StateBag) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (config CommonConfig) GetSR(c *Connection) (xenapi.SRRef, error) {
|
func (config CommonConfig) GetSR(c *Connection) (xenapi.SRRef, error) {
|
||||||
var srRef xenapi.SRRef
|
|
||||||
if config.SrName == "" {
|
if config.SrName == "" {
|
||||||
hostRef, err := c.GetClient().Session.GetThisHost(c.session, c.session)
|
return getDefaultSR(c)
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return srRef, err
|
|
||||||
}
|
|
||||||
|
|
||||||
pools, err := c.GetClient().Pool.GetAllRecords(c.session)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return srRef, err
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, pool := range pools {
|
|
||||||
if pool.Master == hostRef {
|
|
||||||
return pool.DefaultSR, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return srRef, errors.New(fmt.Sprintf("failed to find default SR on host '%s'", hostRef))
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
var srRef xenapi.SRRef
|
||||||
|
|
||||||
// Use the provided name label to find the SR to use
|
// Use the provided name label to find the SR to use
|
||||||
srs, err := c.GetClient().SR.GetByNameLabel(c.session, config.SrName)
|
srs, err := c.GetClient().SR.GetByNameLabel(c.session, config.SrName)
|
||||||
|
|
||||||
@ -269,11 +252,11 @@ func (config CommonConfig) GetSR(c *Connection) (xenapi.SRRef, error) {
|
|||||||
func (config CommonConfig) GetISOSR(c *Connection) (xenapi.SRRef, error) {
|
func (config CommonConfig) GetISOSR(c *Connection) (xenapi.SRRef, error) {
|
||||||
var srRef xenapi.SRRef
|
var srRef xenapi.SRRef
|
||||||
if config.SrISOName == "" {
|
if config.SrISOName == "" {
|
||||||
return srRef, errors.New("sr_iso_name must be specified in the packer configuration")
|
return getDefaultSR(c)
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// Use the provided name label to find the SR to use
|
// Use the provided name label to find the SR to use
|
||||||
srs, err := c.GetClient().SR.GetByNameLabel(c.session, config.SrName)
|
srs, err := c.GetClient().SR.GetByNameLabel(c.session, config.SrISOName)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return srRef, err
|
return srRef, err
|
||||||
@ -281,11 +264,42 @@ func (config CommonConfig) GetISOSR(c *Connection) (xenapi.SRRef, error) {
|
|||||||
|
|
||||||
switch {
|
switch {
|
||||||
case len(srs) == 0:
|
case len(srs) == 0:
|
||||||
return srRef, fmt.Errorf("Couldn't find a SR with the specified name-label '%s'", config.SrName)
|
return srRef, fmt.Errorf("Couldn't find a SR with the specified name-label '%s'", config.SrISOName)
|
||||||
case len(srs) > 1:
|
case len(srs) > 1:
|
||||||
return srRef, fmt.Errorf("Found more than one SR with the name '%s'. The name must be unique", config.SrName)
|
return srRef, fmt.Errorf("Found more than one SR with the name '%s'. The name must be unique", config.SrISOName)
|
||||||
}
|
}
|
||||||
|
|
||||||
return srs[0], nil
|
return srs[0], nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getDefaultSR(c *Connection) (xenapi.SRRef, error) {
|
||||||
|
var srRef xenapi.SRRef
|
||||||
|
client := c.GetClient()
|
||||||
|
hostRef, err := client.Session.GetThisHost(c.session, c.session)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return srRef, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// The current version of the go-xen-api-client does not fully support XenAPI version 8.2
|
||||||
|
// In particular, some values for the pool `allowed_operations` are not recognised, resulting
|
||||||
|
// in a parse error when retrieving pool records. As a workaround, we only fetch pool refs.
|
||||||
|
pool_refs, err := client.Pool.GetAll(c.session)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return srRef, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, pool_ref := range pool_refs {
|
||||||
|
pool_master, err := client.Pool.GetMaster(c.session, pool_ref)
|
||||||
|
if err != nil {
|
||||||
|
return srRef, err
|
||||||
|
}
|
||||||
|
if pool_master == hostRef {
|
||||||
|
return client.Pool.GetDefaultSR(c.session, pool_ref)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return srRef, errors.New(fmt.Sprintf("failed to find default SR on host '%s'", hostRef))
|
||||||
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
//go:generate mapstructure-to-hcl2 -type Config
|
//go:generate packer-sdc mapstructure-to-hcl2 -type Config
|
||||||
package common
|
package common
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@ -20,9 +20,9 @@ type Config struct {
|
|||||||
DiskSize uint `mapstructure:"disk_size"`
|
DiskSize uint `mapstructure:"disk_size"`
|
||||||
CloneTemplate string `mapstructure:"clone_template"`
|
CloneTemplate string `mapstructure:"clone_template"`
|
||||||
VMOtherConfig map[string]string `mapstructure:"vm_other_config"`
|
VMOtherConfig map[string]string `mapstructure:"vm_other_config"`
|
||||||
|
VMTags []string `mapstructure:"vm_tags"`
|
||||||
|
|
||||||
ISOChecksum string `mapstructure:"iso_checksum"`
|
ISOChecksum string `mapstructure:"iso_checksum"`
|
||||||
ISOChecksumType string `mapstructure:"iso_checksum_type"`
|
|
||||||
ISOUrls []string `mapstructure:"iso_urls"`
|
ISOUrls []string `mapstructure:"iso_urls"`
|
||||||
ISOUrl string `mapstructure:"iso_url"`
|
ISOUrl string `mapstructure:"iso_url"`
|
||||||
ISOName string `mapstructure:"iso_name"`
|
ISOName string `mapstructure:"iso_name"`
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Code generated by "mapstructure-to-hcl2 -type Config"; DO NOT EDIT.
|
// Code generated by "packer-sdc mapstructure-to-hcl2"; DO NOT EDIT.
|
||||||
|
|
||||||
package common
|
package common
|
||||||
|
|
||||||
@ -12,6 +12,7 @@ import (
|
|||||||
type FlatConfig struct {
|
type FlatConfig struct {
|
||||||
PackerBuildName *string `mapstructure:"packer_build_name" cty:"packer_build_name" hcl:"packer_build_name"`
|
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"`
|
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"`
|
PackerDebug *bool `mapstructure:"packer_debug" cty:"packer_debug" hcl:"packer_debug"`
|
||||||
PackerForce *bool `mapstructure:"packer_force" cty:"packer_force" hcl:"packer_force"`
|
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"`
|
PackerOnError *string `mapstructure:"packer_on_error" cty:"packer_on_error" hcl:"packer_on_error"`
|
||||||
@ -23,10 +24,11 @@ type FlatConfig struct {
|
|||||||
VMName *string `mapstructure:"vm_name" cty:"vm_name" hcl:"vm_name"`
|
VMName *string `mapstructure:"vm_name" cty:"vm_name" hcl:"vm_name"`
|
||||||
VMDescription *string `mapstructure:"vm_description" cty:"vm_description" hcl:"vm_description"`
|
VMDescription *string `mapstructure:"vm_description" cty:"vm_description" hcl:"vm_description"`
|
||||||
SrName *string `mapstructure:"sr_name" cty:"sr_name" hcl:"sr_name"`
|
SrName *string `mapstructure:"sr_name" cty:"sr_name" hcl:"sr_name"`
|
||||||
SrISOName *string `mapstructure:"sr_iso_name" cty:"sr_iso_name" hcl:"sr_iso_name"`
|
SrISOName *string `mapstructure:"sr_iso_name" required:"false" cty:"sr_iso_name" hcl:"sr_iso_name"`
|
||||||
FloppyFiles []string `mapstructure:"floppy_files" cty:"floppy_files" hcl:"floppy_files"`
|
FloppyFiles []string `mapstructure:"floppy_files" cty:"floppy_files" hcl:"floppy_files"`
|
||||||
NetworkNames []string `mapstructure:"network_names" cty:"network_names" hcl:"network_names"`
|
NetworkNames []string `mapstructure:"network_names" cty:"network_names" hcl:"network_names"`
|
||||||
ExportNetworkNames []string `mapstructure:"export_network_names" cty:"export_network_names" hcl:"export_network_names"`
|
ExportNetworkNames []string `mapstructure:"export_network_names" cty:"export_network_names" hcl:"export_network_names"`
|
||||||
|
VMTags []string `mapstructure:"vm_tags" cty:"vm_tags" hcl:"vm_tags"`
|
||||||
HostPortMin *uint `mapstructure:"host_port_min" cty:"host_port_min" hcl:"host_port_min"`
|
HostPortMin *uint `mapstructure:"host_port_min" cty:"host_port_min" hcl:"host_port_min"`
|
||||||
HostPortMax *uint `mapstructure:"host_port_max" cty:"host_port_max" hcl:"host_port_max"`
|
HostPortMax *uint `mapstructure:"host_port_max" cty:"host_port_max" hcl:"host_port_max"`
|
||||||
BootCommand []string `mapstructure:"boot_command" cty:"boot_command" hcl:"boot_command"`
|
BootCommand []string `mapstructure:"boot_command" cty:"boot_command" hcl:"boot_command"`
|
||||||
@ -100,7 +102,6 @@ type FlatConfig struct {
|
|||||||
CloneTemplate *string `mapstructure:"clone_template" cty:"clone_template" hcl:"clone_template"`
|
CloneTemplate *string `mapstructure:"clone_template" cty:"clone_template" hcl:"clone_template"`
|
||||||
VMOtherConfig map[string]string `mapstructure:"vm_other_config" cty:"vm_other_config" hcl:"vm_other_config"`
|
VMOtherConfig map[string]string `mapstructure:"vm_other_config" cty:"vm_other_config" hcl:"vm_other_config"`
|
||||||
ISOChecksum *string `mapstructure:"iso_checksum" cty:"iso_checksum" hcl:"iso_checksum"`
|
ISOChecksum *string `mapstructure:"iso_checksum" cty:"iso_checksum" hcl:"iso_checksum"`
|
||||||
ISOChecksumType *string `mapstructure:"iso_checksum_type" cty:"iso_checksum_type" hcl:"iso_checksum_type"`
|
|
||||||
ISOUrls []string `mapstructure:"iso_urls" cty:"iso_urls" hcl:"iso_urls"`
|
ISOUrls []string `mapstructure:"iso_urls" cty:"iso_urls" hcl:"iso_urls"`
|
||||||
ISOUrl *string `mapstructure:"iso_url" cty:"iso_url" hcl:"iso_url"`
|
ISOUrl *string `mapstructure:"iso_url" cty:"iso_url" hcl:"iso_url"`
|
||||||
ISOName *string `mapstructure:"iso_name" cty:"iso_name" hcl:"iso_name"`
|
ISOName *string `mapstructure:"iso_name" cty:"iso_name" hcl:"iso_name"`
|
||||||
@ -125,6 +126,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
|
|||||||
s := map[string]hcldec.Spec{
|
s := map[string]hcldec.Spec{
|
||||||
"packer_build_name": &hcldec.AttrSpec{Name: "packer_build_name", Type: cty.String, Required: false},
|
"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_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_debug": &hcldec.AttrSpec{Name: "packer_debug", Type: cty.Bool, Required: false},
|
||||||
"packer_force": &hcldec.AttrSpec{Name: "packer_force", 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_on_error": &hcldec.AttrSpec{Name: "packer_on_error", Type: cty.String, Required: false},
|
||||||
@ -140,6 +142,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
|
|||||||
"floppy_files": &hcldec.AttrSpec{Name: "floppy_files", Type: cty.List(cty.String), Required: false},
|
"floppy_files": &hcldec.AttrSpec{Name: "floppy_files", Type: cty.List(cty.String), Required: false},
|
||||||
"network_names": &hcldec.AttrSpec{Name: "network_names", Type: cty.List(cty.String), Required: false},
|
"network_names": &hcldec.AttrSpec{Name: "network_names", Type: cty.List(cty.String), Required: false},
|
||||||
"export_network_names": &hcldec.AttrSpec{Name: "export_network_names", Type: cty.List(cty.String), Required: false},
|
"export_network_names": &hcldec.AttrSpec{Name: "export_network_names", Type: cty.List(cty.String), Required: false},
|
||||||
|
"vm_tags": &hcldec.AttrSpec{Name: "vm_tags", Type: cty.List(cty.String), Required: false},
|
||||||
"host_port_min": &hcldec.AttrSpec{Name: "host_port_min", Type: cty.Number, Required: false},
|
"host_port_min": &hcldec.AttrSpec{Name: "host_port_min", Type: cty.Number, Required: false},
|
||||||
"host_port_max": &hcldec.AttrSpec{Name: "host_port_max", Type: cty.Number, Required: false},
|
"host_port_max": &hcldec.AttrSpec{Name: "host_port_max", Type: cty.Number, Required: false},
|
||||||
"boot_command": &hcldec.AttrSpec{Name: "boot_command", Type: cty.List(cty.String), Required: false},
|
"boot_command": &hcldec.AttrSpec{Name: "boot_command", Type: cty.List(cty.String), Required: false},
|
||||||
@ -213,7 +216,6 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
|
|||||||
"clone_template": &hcldec.AttrSpec{Name: "clone_template", Type: cty.String, Required: false},
|
"clone_template": &hcldec.AttrSpec{Name: "clone_template", Type: cty.String, Required: false},
|
||||||
"vm_other_config": &hcldec.AttrSpec{Name: "vm_other_config", Type: cty.Map(cty.String), Required: false},
|
"vm_other_config": &hcldec.AttrSpec{Name: "vm_other_config", Type: cty.Map(cty.String), Required: false},
|
||||||
"iso_checksum": &hcldec.AttrSpec{Name: "iso_checksum", Type: cty.String, Required: false},
|
"iso_checksum": &hcldec.AttrSpec{Name: "iso_checksum", Type: cty.String, Required: false},
|
||||||
"iso_checksum_type": &hcldec.AttrSpec{Name: "iso_checksum_type", Type: cty.String, Required: false},
|
|
||||||
"iso_urls": &hcldec.AttrSpec{Name: "iso_urls", Type: cty.List(cty.String), Required: false},
|
"iso_urls": &hcldec.AttrSpec{Name: "iso_urls", Type: cty.List(cty.String), Required: false},
|
||||||
"iso_url": &hcldec.AttrSpec{Name: "iso_url", Type: cty.String, Required: false},
|
"iso_url": &hcldec.AttrSpec{Name: "iso_url", Type: cty.String, Required: false},
|
||||||
"iso_name": &hcldec.AttrSpec{Name: "iso_name", Type: cty.String, Required: false},
|
"iso_name": &hcldec.AttrSpec{Name: "iso_name", Type: cty.String, Required: false},
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
package iso
|
package common
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
@ -9,18 +9,21 @@ import (
|
|||||||
"github.com/hashicorp/packer-plugin-sdk/packer"
|
"github.com/hashicorp/packer-plugin-sdk/packer"
|
||||||
xenapi "github.com/terra-farm/go-xen-api-client"
|
xenapi "github.com/terra-farm/go-xen-api-client"
|
||||||
xsclient "github.com/terra-farm/go-xen-api-client"
|
xsclient "github.com/terra-farm/go-xen-api-client"
|
||||||
xscommon "github.com/xenserver/packer-builder-xenserver/builder/xenserver/common"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type stepCreateInstance struct {
|
type StepCreateInstance struct {
|
||||||
|
// The XVA builder assumes it will boot an instance with an OS installed on its disks
|
||||||
|
// while the ISO builder needs packer to create a disk for an OS to be installed on.
|
||||||
|
AssumePreInstalledOS bool
|
||||||
|
|
||||||
instance *xsclient.VMRef
|
instance *xsclient.VMRef
|
||||||
vdi *xsclient.VDIRef
|
vdi *xsclient.VDIRef
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *stepCreateInstance) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
|
func (self *StepCreateInstance) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
|
||||||
|
|
||||||
c := state.Get("client").(*xscommon.Connection)
|
c := state.Get("client").(*Connection)
|
||||||
config := state.Get("config").(xscommon.Config)
|
config := state.Get("config").(Config)
|
||||||
ui := state.Get("ui").(packer.Ui)
|
ui := state.Get("ui").(packer.Ui)
|
||||||
|
|
||||||
ui.Say("Step: Create Instance")
|
ui.Say("Step: Create Instance")
|
||||||
@ -101,6 +104,13 @@ func (self *stepCreateInstance) Run(ctx context.Context, state multistep.StateBa
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !self.AssumePreInstalledOS {
|
||||||
|
err = c.GetClient().VM.RemoveFromOtherConfig(c.GetSessionRef(), instance, "disks")
|
||||||
|
if err != nil {
|
||||||
|
ui.Error(fmt.Sprintf("Error removing disks from VM other-config: %s", err.Error()))
|
||||||
|
return multistep.ActionHalt
|
||||||
|
}
|
||||||
|
|
||||||
// Create VDI for the instance
|
// Create VDI for the instance
|
||||||
sr, err := config.GetSR(c)
|
sr, err := config.GetSR(c)
|
||||||
|
|
||||||
@ -128,11 +138,12 @@ func (self *stepCreateInstance) Run(ctx context.Context, state multistep.StateBa
|
|||||||
}
|
}
|
||||||
self.vdi = &vdi
|
self.vdi = &vdi
|
||||||
|
|
||||||
err = xscommon.ConnectVdi(c, instance, vdi, xsclient.VbdTypeDisk)
|
err = ConnectVdi(c, instance, vdi, xsclient.VbdTypeDisk)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ui.Error(fmt.Sprintf("Unable to connect packer disk VDI: %s", err.Error()))
|
ui.Error(fmt.Sprintf("Unable to connect packer disk VDI: %s", err.Error()))
|
||||||
return multistep.ActionHalt
|
return multistep.ActionHalt
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Connect Network
|
// Connect Network
|
||||||
|
|
||||||
@ -168,7 +179,7 @@ func (self *stepCreateInstance) Run(ctx context.Context, state multistep.StateBa
|
|||||||
}
|
}
|
||||||
|
|
||||||
log.Printf("Creating VIF on network '%s' on VM '%s'\n", network, instance)
|
log.Printf("Creating VIF on network '%s' on VM '%s'\n", network, instance)
|
||||||
_, err = xscommon.ConnectNetwork(c, network, instance, "0")
|
_, err = ConnectNetwork(c, network, instance, "0")
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ui.Error(fmt.Sprintf("Failed to create VIF with error: %v", err))
|
ui.Error(fmt.Sprintf("Failed to create VIF with error: %v", err))
|
||||||
@ -197,7 +208,7 @@ func (self *stepCreateInstance) Run(ctx context.Context, state multistep.StateBa
|
|||||||
|
|
||||||
//we need the VIF index string
|
//we need the VIF index string
|
||||||
vifIndexString := fmt.Sprintf("%d", i)
|
vifIndexString := fmt.Sprintf("%d", i)
|
||||||
_, err = xscommon.ConnectNetwork(c, networks[0], instance, vifIndexString)
|
_, err = ConnectNetwork(c, networks[0], instance, vifIndexString)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ui.Say(fmt.Sprintf("Failed to connect VIF with error: %v", err.Error()))
|
ui.Say(fmt.Sprintf("Failed to connect VIF with error: %v", err.Error()))
|
||||||
@ -205,6 +216,12 @@ func (self *stepCreateInstance) Run(ctx context.Context, state multistep.StateBa
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
err = AddVMTags(c, instance, config.VMTags)
|
||||||
|
if err != nil {
|
||||||
|
ui.Error(fmt.Sprintf("Failed to add tags: %s", err.Error()))
|
||||||
|
return multistep.ActionHalt
|
||||||
|
}
|
||||||
|
|
||||||
instanceId, err := c.GetClient().VM.GetUUID(c.GetSessionRef(), instance)
|
instanceId, err := c.GetClient().VM.GetUUID(c.GetSessionRef(), instance)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ui.Error(fmt.Sprintf("Unable to get VM UUID: %s", err.Error()))
|
ui.Error(fmt.Sprintf("Unable to get VM UUID: %s", err.Error()))
|
||||||
@ -217,14 +234,14 @@ func (self *stepCreateInstance) Run(ctx context.Context, state multistep.StateBa
|
|||||||
return multistep.ActionContinue
|
return multistep.ActionContinue
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *stepCreateInstance) Cleanup(state multistep.StateBag) {
|
func (self *StepCreateInstance) Cleanup(state multistep.StateBag) {
|
||||||
config := state.Get("config").(xscommon.Config)
|
config := state.Get("config").(Config)
|
||||||
if config.ShouldKeepVM(state) {
|
if config.ShouldKeepVM(state) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
ui := state.Get("ui").(packer.Ui)
|
ui := state.Get("ui").(packer.Ui)
|
||||||
c := state.Get("client").(*xscommon.Connection)
|
c := state.Get("client").(*Connection)
|
||||||
|
|
||||||
if self.instance != nil {
|
if self.instance != nil {
|
||||||
ui.Say("Destroying VM")
|
ui.Say("Destroying VM")
|
44
builder/xenserver/common/step_find_or_upload_vdi.go
Normal file
44
builder/xenserver/common/step_find_or_upload_vdi.go
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
package common
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/hashicorp/packer-plugin-sdk/multistep"
|
||||||
|
"github.com/hashicorp/packer-plugin-sdk/packer"
|
||||||
|
)
|
||||||
|
|
||||||
|
type StepFindOrUploadVdi struct {
|
||||||
|
StepUploadVdi
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *StepFindOrUploadVdi) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
|
||||||
|
ui := state.Get("ui").(packer.Ui)
|
||||||
|
c := state.Get("client").(*Connection)
|
||||||
|
vdiName := self.VdiNameFunc()
|
||||||
|
|
||||||
|
ui.Say(fmt.Sprintf("Attemping to find VDI '%s'", vdiName))
|
||||||
|
|
||||||
|
vdis, err := c.client.VDI.GetByNameLabel(c.session, vdiName)
|
||||||
|
if err != nil {
|
||||||
|
ui.Error(fmt.Sprintf("Failed to find VDI '%s' by name label: %s", vdiName, err.Error()))
|
||||||
|
return multistep.ActionHalt
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(vdis) > 1 {
|
||||||
|
ui.Error(fmt.Sprintf("Found more than one VDI with name '%s'. Name must be unique", vdiName))
|
||||||
|
return multistep.ActionHalt
|
||||||
|
} else if len(vdis) == 1 {
|
||||||
|
|
||||||
|
vdi := vdis[0]
|
||||||
|
|
||||||
|
vdiUuid, err := c.client.VDI.GetUUID(c.session, vdi)
|
||||||
|
if err != nil {
|
||||||
|
ui.Error(fmt.Sprintf("Unable to get UUID of VDI '%s': %s", vdiName, err.Error()))
|
||||||
|
return multistep.ActionHalt
|
||||||
|
}
|
||||||
|
state.Put(self.VdiUuidKey, vdiUuid)
|
||||||
|
return multistep.ActionContinue
|
||||||
|
}
|
||||||
|
return self.uploadVdi(ctx, state)
|
||||||
|
}
|
@ -18,7 +18,7 @@ type StepUploadVdi struct {
|
|||||||
VdiUuidKey string
|
VdiUuidKey string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *StepUploadVdi) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
|
func (self *StepUploadVdi) uploadVdi(ctx context.Context, state multistep.StateBag) multistep.StepAction {
|
||||||
config := state.Get("commonconfig").(CommonConfig)
|
config := state.Get("commonconfig").(CommonConfig)
|
||||||
ui := state.Get("ui").(packer.Ui)
|
ui := state.Get("ui").(packer.Ui)
|
||||||
c := state.Get("client").(*Connection)
|
c := state.Get("client").(*Connection)
|
||||||
@ -33,10 +33,8 @@ func (self *StepUploadVdi) Run(ctx context.Context, state multistep.StateBag) mu
|
|||||||
ui.Say(fmt.Sprintf("Step: Upload VDI '%s'", vdiName))
|
ui.Say(fmt.Sprintf("Step: Upload VDI '%s'", vdiName))
|
||||||
|
|
||||||
// Create VDI for the image
|
// Create VDI for the image
|
||||||
srs, err := c.client.SR.GetAll(c.session)
|
|
||||||
ui.Say(fmt.Sprintf("Step: Found SRs '%v'", srs))
|
|
||||||
|
|
||||||
sr, err := config.GetISOSR(c)
|
sr, err := config.GetISOSR(c)
|
||||||
|
ui.Say(fmt.Sprintf("Step: Found SR for upload '%v'", sr))
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ui.Error(fmt.Sprintf("Unable to get SR: %v", err))
|
ui.Error(fmt.Sprintf("Unable to get SR: %v", err))
|
||||||
@ -96,6 +94,10 @@ func (self *StepUploadVdi) Run(ctx context.Context, state multistep.StateBag) mu
|
|||||||
return multistep.ActionContinue
|
return multistep.ActionContinue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (self *StepUploadVdi) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
|
||||||
|
return self.uploadVdi(ctx, state)
|
||||||
|
}
|
||||||
|
|
||||||
func (self *StepUploadVdi) Cleanup(state multistep.StateBag) {
|
func (self *StepUploadVdi) Cleanup(state multistep.StateBag) {
|
||||||
config := state.Get("commonconfig").(CommonConfig)
|
config := state.Get("commonconfig").(CommonConfig)
|
||||||
ui := state.Get("ui").(packer.Ui)
|
ui := state.Get("ui").(packer.Ui)
|
||||||
|
@ -40,7 +40,7 @@ func (self *Builder) Prepare(raws ...interface{}) (params []string, warns []stri
|
|||||||
}, raws...)
|
}, raws...)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
packer.MultiErrorAppend(errs, err)
|
errs = packer.MultiErrorAppend(errs, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
errs = packer.MultiErrorAppend(
|
errs = packer.MultiErrorAppend(
|
||||||
@ -97,7 +97,6 @@ func (self *Builder) Prepare(raws ...interface{}) (params []string, warns []stri
|
|||||||
templates := map[string]*string{
|
templates := map[string]*string{
|
||||||
"clone_template": &self.config.CloneTemplate,
|
"clone_template": &self.config.CloneTemplate,
|
||||||
"iso_checksum": &self.config.ISOChecksum,
|
"iso_checksum": &self.config.ISOChecksum,
|
||||||
"iso_checksum_type": &self.config.ISOChecksumType,
|
|
||||||
"iso_url": &self.config.ISOUrl,
|
"iso_url": &self.config.ISOUrl,
|
||||||
"iso_name": &self.config.ISOName,
|
"iso_name": &self.config.ISOName,
|
||||||
"install_timeout": &self.config.RawInstallTimeout,
|
"install_timeout": &self.config.RawInstallTimeout,
|
||||||
@ -115,23 +114,8 @@ func (self *Builder) Prepare(raws ...interface{}) (params []string, warns []stri
|
|||||||
}
|
}
|
||||||
|
|
||||||
if self.config.ISOName == "" {
|
if self.config.ISOName == "" {
|
||||||
|
|
||||||
// If ISO name is not specified, assume a URL and checksum has been provided.
|
// If ISO name is not specified, assume a URL and checksum has been provided.
|
||||||
|
|
||||||
if self.config.ISOChecksumType == "" {
|
|
||||||
errs = packer.MultiErrorAppend(
|
|
||||||
errs, errors.New("The iso_checksum_type must be specified."))
|
|
||||||
} else {
|
|
||||||
self.config.ISOChecksumType = strings.ToLower(self.config.ISOChecksumType)
|
|
||||||
if self.config.ISOChecksumType != "none" {
|
|
||||||
if self.config.ISOChecksum == "" {
|
|
||||||
errs = packer.MultiErrorAppend(
|
|
||||||
errs, errors.New("Due to the file size being large, an iso_checksum is required."))
|
|
||||||
} else {
|
|
||||||
self.config.ISOChecksum = strings.ToLower(self.config.ISOChecksum)
|
self.config.ISOChecksum = strings.ToLower(self.config.ISOChecksum)
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(self.config.ISOUrls) == 0 {
|
if len(self.config.ISOUrls) == 0 {
|
||||||
if self.config.ISOUrl == "" {
|
if self.config.ISOUrl == "" {
|
||||||
@ -140,10 +124,25 @@ func (self *Builder) Prepare(raws ...interface{}) (params []string, warns []stri
|
|||||||
} else {
|
} else {
|
||||||
self.config.ISOUrls = []string{self.config.ISOUrl}
|
self.config.ISOUrls = []string{self.config.ISOUrl}
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if self.config.ISOUrl != "" {
|
} else if self.config.ISOUrl != "" {
|
||||||
errs = packer.MultiErrorAppend(
|
errs = packer.MultiErrorAppend(
|
||||||
errs, errors.New("Only one of iso_url or iso_urls may be specified."))
|
errs, errors.New("Only one of iso_url or iso_urls may be specified."))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//The SDK can validate the ISO checksum and other sanity checks on the url.
|
||||||
|
iso_config := commonsteps.ISOConfig{
|
||||||
|
ISOChecksum: self.config.ISOChecksum,
|
||||||
|
ISOUrls: self.config.ISOUrls,
|
||||||
|
}
|
||||||
|
|
||||||
|
_, iso_errs := iso_config.Prepare(nil)
|
||||||
|
if iso_errs != nil {
|
||||||
|
for _, this_err := range iso_errs {
|
||||||
|
errs = packer.MultiErrorAppend(errs, this_err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
// An ISO name has been provided. It should be attached from an available SR.
|
// An ISO name has been provided. It should be attached from an available SR.
|
||||||
@ -187,7 +186,6 @@ func (self *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (p
|
|||||||
Url: self.config.ISOUrls,
|
Url: self.config.ISOUrls,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
steps := []multistep.Step{
|
steps := []multistep.Step{
|
||||||
&xscommon.StepPrepareOutputDir{
|
&xscommon.StepPrepareOutputDir{
|
||||||
Force: self.config.PackerForce,
|
Force: self.config.PackerForce,
|
||||||
@ -212,7 +210,8 @@ func (self *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (p
|
|||||||
},
|
},
|
||||||
VdiUuidKey: "floppy_vdi_uuid",
|
VdiUuidKey: "floppy_vdi_uuid",
|
||||||
},
|
},
|
||||||
&xscommon.StepUploadVdi{
|
&xscommon.StepFindOrUploadVdi{
|
||||||
|
xscommon.StepUploadVdi{
|
||||||
VdiNameFunc: func() string {
|
VdiNameFunc: func() string {
|
||||||
if len(self.config.ISOUrls) > 0 {
|
if len(self.config.ISOUrls) > 0 {
|
||||||
return path.Base(self.config.ISOUrls[0])
|
return path.Base(self.config.ISOUrls[0])
|
||||||
@ -227,6 +226,7 @@ func (self *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (p
|
|||||||
},
|
},
|
||||||
VdiUuidKey: "iso_vdi_uuid",
|
VdiUuidKey: "iso_vdi_uuid",
|
||||||
},
|
},
|
||||||
|
},
|
||||||
&xscommon.StepFindVdi{
|
&xscommon.StepFindVdi{
|
||||||
VdiName: self.config.ToolsIsoName,
|
VdiName: self.config.ToolsIsoName,
|
||||||
VdiUuidKey: "tools_vdi_uuid",
|
VdiUuidKey: "tools_vdi_uuid",
|
||||||
@ -235,7 +235,9 @@ func (self *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (p
|
|||||||
VdiName: self.config.ISOName,
|
VdiName: self.config.ISOName,
|
||||||
VdiUuidKey: "isoname_vdi_uuid",
|
VdiUuidKey: "isoname_vdi_uuid",
|
||||||
},
|
},
|
||||||
new(stepCreateInstance),
|
&xscommon.StepCreateInstance{
|
||||||
|
AssumePreInstalledOS: false,
|
||||||
|
},
|
||||||
&xscommon.StepAttachVdi{
|
&xscommon.StepAttachVdi{
|
||||||
VdiUuidKey: "floppy_vdi_uuid",
|
VdiUuidKey: "floppy_vdi_uuid",
|
||||||
VdiType: xsclient.VbdTypeFloppy,
|
VdiType: xsclient.VbdTypeFloppy,
|
||||||
|
@ -5,21 +5,22 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/hashicorp/packer-plugin-sdk/packer"
|
"github.com/hashicorp/packer-plugin-sdk/packer"
|
||||||
|
"github.com/hashicorp/packer-plugin-sdk/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
func testConfig() map[string]interface{} {
|
func testConfig() map[string]interface{} {
|
||||||
return map[string]interface{}{
|
return map[string]interface{}{
|
||||||
"remote_host": "localhost",
|
"remote_host": "localhost",
|
||||||
"remote_username": "admin",
|
"remote_username": "admin",
|
||||||
"remote_password": "admin",
|
"remote_password": "admin",
|
||||||
"vm_name": "foo",
|
"vm_name": "foo",
|
||||||
"iso_checksum": "foo",
|
"iso_checksum": "md5:A221725EE181A44C67E25BD6A2516742",
|
||||||
"iso_checksum_type": "md5",
|
|
||||||
"iso_url": "http://www.google.com/",
|
"iso_url": "http://www.google.com/",
|
||||||
"shutdown_command": "yes",
|
"shutdown_command": "yes",
|
||||||
"ssh_username": "foo",
|
"ssh_username": "foo",
|
||||||
|
|
||||||
packer.BuildNameConfigKey: "foo",
|
common.BuildNameConfigKey: "foo",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -179,64 +180,19 @@ func TestBuilderPrepare_ISOChecksum(t *testing.T) {
|
|||||||
var b Builder
|
var b Builder
|
||||||
config := testConfig()
|
config := testConfig()
|
||||||
|
|
||||||
|
// Test good
|
||||||
|
|
||||||
|
b = Builder{}
|
||||||
|
_, warns, err := b.Prepare(config)
|
||||||
|
if len(warns) > 0 {
|
||||||
|
t.Fatalf("bad: %#v", warns)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("should not have error: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
// Test bad
|
// Test bad
|
||||||
config["iso_checksum"] = ""
|
config["iso_checksum"] = ""
|
||||||
_, warns, err := b.Prepare(config)
|
|
||||||
if len(warns) > 0 {
|
|
||||||
t.Fatalf("bad: %#v", warns)
|
|
||||||
}
|
|
||||||
if err == nil {
|
|
||||||
t.Fatal("should have error")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test good
|
|
||||||
config["iso_checksum"] = "FOo"
|
|
||||||
b = Builder{}
|
|
||||||
_, warns, err = b.Prepare(config)
|
|
||||||
if len(warns) > 0 {
|
|
||||||
t.Fatalf("bad: %#v", warns)
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("should not have error: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if b.config.ISOChecksum != "foo" {
|
|
||||||
t.Fatalf("should've lowercased: %s", b.config.ISOChecksum)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestBuilderPrepare_ISOChecksumType(t *testing.T) {
|
|
||||||
var b Builder
|
|
||||||
config := testConfig()
|
|
||||||
|
|
||||||
// Test bad
|
|
||||||
config["iso_checksum_type"] = ""
|
|
||||||
_, warns, err := b.Prepare(config)
|
|
||||||
if len(warns) > 0 {
|
|
||||||
t.Fatalf("bad: %#v", warns)
|
|
||||||
}
|
|
||||||
if err == nil {
|
|
||||||
t.Fatal("should have error")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test good
|
|
||||||
config["iso_checksum_type"] = "mD5"
|
|
||||||
b = Builder{}
|
|
||||||
_, warns, err = b.Prepare(config)
|
|
||||||
if len(warns) > 0 {
|
|
||||||
t.Fatalf("bad: %#v", warns)
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("should not have error: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if b.config.ISOChecksumType != "md5" {
|
|
||||||
t.Fatalf("should've lowercased: %s", b.config.ISOChecksumType)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test unknown
|
|
||||||
config["iso_checksum_type"] = "fake"
|
|
||||||
b = Builder{}
|
|
||||||
_, warns, err = b.Prepare(config)
|
_, warns, err = b.Prepare(config)
|
||||||
if len(warns) > 0 {
|
if len(warns) > 0 {
|
||||||
t.Fatalf("bad: %#v", warns)
|
t.Fatalf("bad: %#v", warns)
|
||||||
@ -245,24 +201,9 @@ func TestBuilderPrepare_ISOChecksumType(t *testing.T) {
|
|||||||
t.Fatal("should have error")
|
t.Fatal("should have error")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test none
|
|
||||||
config["iso_checksum_type"] = "none"
|
|
||||||
b = Builder{}
|
|
||||||
_, warns, err = b.Prepare(config)
|
|
||||||
// @todo: give warning in this case?
|
|
||||||
/*
|
|
||||||
if len(warns) == 0 {
|
|
||||||
t.Fatalf("bad: %#v", warns)
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("should not have error: %s", err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if b.config.ISOChecksumType != "none" {
|
|
||||||
t.Fatalf("should've lowercased: %s", b.config.ISOChecksumType)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestBuilderPrepare_ISOUrl(t *testing.T) {
|
func TestBuilderPrepare_ISOUrl(t *testing.T) {
|
||||||
var b Builder
|
var b Builder
|
||||||
|
@ -3,7 +3,6 @@ package xva
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/hashicorp/hcl/v2/hcldec"
|
"github.com/hashicorp/hcl/v2/hcldec"
|
||||||
@ -38,11 +37,12 @@ func (self *Builder) Prepare(raws ...interface{}) (params []string, warns []stri
|
|||||||
}, raws...)
|
}, raws...)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
packer.MultiErrorAppend(errs, err)
|
errs = packer.MultiErrorAppend(errs, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
errs = packer.MultiErrorAppend(
|
errs = packer.MultiErrorAppend(
|
||||||
errs, self.config.CommonConfig.Prepare(self.config.GetInterpContext(), &self.config.PackerConfig)...)
|
errs, self.config.CommonConfig.Prepare(self.config.GetInterpContext(), &self.config.PackerConfig)...)
|
||||||
|
errs = packer.MultiErrorAppend(errs, self.config.SSHConfig.Prepare(self.config.GetInterpContext())...)
|
||||||
|
|
||||||
// Set default values
|
// Set default values
|
||||||
if self.config.VCPUsMax == 0 {
|
if self.config.VCPUsMax == 0 {
|
||||||
@ -74,8 +74,12 @@ func (self *Builder) Prepare(raws ...interface{}) (params []string, warns []stri
|
|||||||
|
|
||||||
// Validation
|
// Validation
|
||||||
|
|
||||||
if self.config.SourcePath == "" {
|
if self.config.SourcePath == "" && self.config.CloneTemplate == "" {
|
||||||
errs = packer.MultiErrorAppend(errs, fmt.Errorf("A source_path must be specified"))
|
errs = packer.MultiErrorAppend(
|
||||||
|
errs, errors.New("Either source_path or clone_template must be specified"))
|
||||||
|
} else if self.config.SourcePath != "" && self.config.CloneTemplate != "" {
|
||||||
|
errs = packer.MultiErrorAppend(
|
||||||
|
errs, errors.New("Only one of source_path and clone_template must be specified"))
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(errs.Errors) > 0 {
|
if len(errs.Errors) > 0 {
|
||||||
@ -101,7 +105,7 @@ func (self *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (p
|
|||||||
//Share state between the other steps using a statebag
|
//Share state between the other steps using a statebag
|
||||||
state := new(multistep.BasicStateBag)
|
state := new(multistep.BasicStateBag)
|
||||||
state.Put("client", c)
|
state.Put("client", c)
|
||||||
// state.Put("config", self.config)
|
state.Put("config", self.config)
|
||||||
state.Put("commonconfig", self.config.CommonConfig)
|
state.Put("commonconfig", self.config.CommonConfig)
|
||||||
state.Put("hook", hook)
|
state.Put("hook", hook)
|
||||||
state.Put("ui", ui)
|
state.Put("ui", ui)
|
||||||
@ -116,8 +120,11 @@ func (self *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (p
|
|||||||
},
|
},
|
||||||
&commonsteps.StepCreateFloppy{
|
&commonsteps.StepCreateFloppy{
|
||||||
Files: self.config.FloppyFiles,
|
Files: self.config.FloppyFiles,
|
||||||
|
Label: "cidata",
|
||||||
|
},
|
||||||
|
&xscommon.StepHTTPServer{
|
||||||
|
Chan: httpReqChan,
|
||||||
},
|
},
|
||||||
new(xscommon.StepHTTPServer),
|
|
||||||
&xscommon.StepUploadVdi{
|
&xscommon.StepUploadVdi{
|
||||||
VdiNameFunc: func() string {
|
VdiNameFunc: func() string {
|
||||||
return "Packer-floppy-disk"
|
return "Packer-floppy-disk"
|
||||||
@ -134,6 +141,9 @@ func (self *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (p
|
|||||||
VdiName: self.config.ToolsIsoName,
|
VdiName: self.config.ToolsIsoName,
|
||||||
VdiUuidKey: "tools_vdi_uuid",
|
VdiUuidKey: "tools_vdi_uuid",
|
||||||
},
|
},
|
||||||
|
&xscommon.StepCreateInstance{
|
||||||
|
AssumePreInstalledOS: true,
|
||||||
|
},
|
||||||
new(stepImportInstance),
|
new(stepImportInstance),
|
||||||
&xscommon.StepAttachVdi{
|
&xscommon.StepAttachVdi{
|
||||||
VdiUuidKey: "floppy_vdi_uuid",
|
VdiUuidKey: "floppy_vdi_uuid",
|
||||||
@ -153,20 +163,28 @@ func (self *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (p
|
|||||||
Chan: httpReqChan,
|
Chan: httpReqChan,
|
||||||
Timeout: 300 * time.Minute, /*self.config.InstallTimeout*/ // @todo change this
|
Timeout: 300 * time.Minute, /*self.config.InstallTimeout*/ // @todo change this
|
||||||
},
|
},
|
||||||
|
&xscommon.StepForwardPortOverSSH{
|
||||||
|
RemotePort: xscommon.InstanceSSHPort,
|
||||||
|
RemoteDest: xscommon.InstanceSSHIP,
|
||||||
|
HostPortMin: self.config.HostPortMin,
|
||||||
|
HostPortMax: self.config.HostPortMax,
|
||||||
|
ResultKey: "local_ssh_port",
|
||||||
|
},
|
||||||
&communicator.StepConnect{
|
&communicator.StepConnect{
|
||||||
Config: &self.config.SSHConfig.Comm,
|
Config: &self.config.SSHConfig.Comm,
|
||||||
Host: xscommon.CommHost,
|
Host: xscommon.InstanceSSHIP,
|
||||||
SSHConfig: xscommon.SSHConfigFunc(self.config.CommonConfig.SSHConfig),
|
SSHConfig: self.config.Comm.SSHConfigFunc(),
|
||||||
SSHPort: xscommon.SSHPort,
|
SSHPort: xscommon.InstanceSSHPort,
|
||||||
},
|
},
|
||||||
new(commonsteps.StepProvision),
|
new(commonsteps.StepProvision),
|
||||||
new(xscommon.StepShutdown),
|
new(xscommon.StepShutdown),
|
||||||
&xscommon.StepDetachVdi{
|
new(xscommon.StepSetVmToTemplate),
|
||||||
VdiUuidKey: "floppy_vdi_uuid",
|
|
||||||
},
|
|
||||||
&xscommon.StepDetachVdi{
|
&xscommon.StepDetachVdi{
|
||||||
VdiUuidKey: "tools_vdi_uuid",
|
VdiUuidKey: "tools_vdi_uuid",
|
||||||
},
|
},
|
||||||
|
&xscommon.StepDetachVdi{
|
||||||
|
VdiUuidKey: "floppy_vdi_uuid",
|
||||||
|
},
|
||||||
new(xscommon.StepDestroyVIFs),
|
new(xscommon.StepDestroyVIFs),
|
||||||
new(xscommon.StepExport),
|
new(xscommon.StepExport),
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/hashicorp/packer-plugin-sdk/packer"
|
"github.com/hashicorp/packer-plugin-sdk/packer"
|
||||||
|
"github.com/hashicorp/packer-plugin-sdk/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
func testConfig() map[string]interface{} {
|
func testConfig() map[string]interface{} {
|
||||||
@ -16,7 +17,7 @@ func testConfig() map[string]interface{} {
|
|||||||
"ssh_username": "foo",
|
"ssh_username": "foo",
|
||||||
"source_path": ".",
|
"source_path": ".",
|
||||||
|
|
||||||
packer.BuildNameConfigKey: "foo",
|
common.BuildNameConfigKey: "foo",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,6 +3,7 @@ package xva
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"log"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/hashicorp/packer-plugin-sdk/multistep"
|
"github.com/hashicorp/packer-plugin-sdk/multistep"
|
||||||
@ -24,6 +25,11 @@ func (self *stepImportInstance) Run(ctx context.Context, state multistep.StateBa
|
|||||||
|
|
||||||
ui.Say("Step: Import Instance")
|
ui.Say("Step: Import Instance")
|
||||||
|
|
||||||
|
if config.SourcePath == "" {
|
||||||
|
log.Println("Skipping imporing instance - no `source_path` configured.")
|
||||||
|
return multistep.ActionContinue
|
||||||
|
}
|
||||||
|
|
||||||
// find the SR
|
// find the SR
|
||||||
srs, err := c.GetClient().SR.GetAll(c.GetSessionRef())
|
srs, err := c.GetClient().SR.GetAll(c.GetSessionRef())
|
||||||
sr := srs[0]
|
sr := srs[0]
|
||||||
@ -80,6 +86,12 @@ func (self *stepImportInstance) Run(ctx context.Context, state multistep.StateBa
|
|||||||
return multistep.ActionHalt
|
return multistep.ActionHalt
|
||||||
}
|
}
|
||||||
|
|
||||||
|
err = xscommon.AddVMTags(c, instance, config.VMTags)
|
||||||
|
if err != nil {
|
||||||
|
ui.Error(fmt.Sprintf("Failed to add tags: %s", err.Error()))
|
||||||
|
return multistep.ActionHalt
|
||||||
|
}
|
||||||
|
|
||||||
ui.Say(fmt.Sprintf("Imported instance '%s'", instanceId))
|
ui.Say(fmt.Sprintf("Imported instance '%s'", instanceId))
|
||||||
|
|
||||||
return multistep.ActionContinue
|
return multistep.ActionContinue
|
||||||
|
@ -29,21 +29,34 @@ each category, the available options are alphabetized and described.
|
|||||||
|
|
||||||
* `iso_checksum` (string) - The checksum for the OS ISO file. Because ISO
|
* `iso_checksum` (string) - The checksum for the OS ISO file. Because ISO
|
||||||
files are so large, this is required and Packer will verify it prior
|
files are so large, this is required and Packer will verify it prior
|
||||||
to booting a virtual machine with the ISO attached. The type of the
|
to booting a virtual machine with the ISO attached. The type of
|
||||||
checksum is specified with `iso_checksum_type`, documented below.
|
the checksum is specified within the checksum field as a prefix, ex:
|
||||||
|
"md5:{$checksum}". The type of the checksum can also be omitted and
|
||||||
|
Packer will try to infer it based on string length. Valid values are
|
||||||
|
"none", "{$checksum}", "md5:{$checksum}", "sha1:{$checksum}",
|
||||||
|
"sha256:{$checksum}", "sha512:{$checksum}" or "file:{$path}". Here is a
|
||||||
|
list of valid checksum values:
|
||||||
|
* md5:090992ba9fd140077b0661cb75f7ce13
|
||||||
|
* 090992ba9fd140077b0661cb75f7ce13
|
||||||
|
* sha1:ebfb681885ddf1234c18094a45bbeafd91467911
|
||||||
|
* ebfb681885ddf1234c18094a45bbeafd91467911
|
||||||
|
* sha256:ed363350696a726b7932db864dda019bd2017365c9e299627830f06954643f93
|
||||||
|
* ed363350696a726b7932db864dda019bd2017365c9e299627830f06954643f93
|
||||||
|
* file:http://releases.ubuntu.com/20.04/SHA256SUMS
|
||||||
|
* file:file://./local/path/file.sum
|
||||||
|
* file:./local/path/file.sum
|
||||||
|
* none
|
||||||
|
Although the checksum will not be verified when it is set to "none",
|
||||||
|
this is not recommended since these files can be very large and
|
||||||
|
corruption does happen from time to time.
|
||||||
|
|
||||||
* `iso_checksum_type` (string) - The type of the checksum specified in
|
|
||||||
`iso_checksum`. Valid values are "none", "md5", "sha1", "sha256", or
|
|
||||||
"sha512" currently. While "none" will skip checksumming, this is not
|
|
||||||
recommended since ISO files are generally large and corruption does happen
|
|
||||||
from time to time.
|
|
||||||
|
|
||||||
* `iso_url` (string) - A URL to the ISO containing the installation image.
|
* `iso_url` (string) - A URL to the ISO containing the installation image.
|
||||||
This URL can be either an HTTP URL or a file URL (or path to a file).
|
This URL can be either an HTTP URL or a file URL (or path to a file).
|
||||||
If this is an HTTP URL, Packer will download it and cache it between
|
If this is an HTTP URL, Packer will download it and cache it between
|
||||||
runs.
|
runs.
|
||||||
|
|
||||||
* `remote_host` (string) - The host of the Xenserver / XCP-ng pool primary. Typically these will be specified through environment variables as seen in the [examples](../../examples/centos8.json).
|
* `remote_host` (string) - The host of the Xenserver / XCP-ng pool primary. Typically these will be specified through environment variables as seen in the [examples](../../../examples).
|
||||||
|
|
||||||
* `remote_username` (string) - The XenServer username used to access the remote machine.
|
* `remote_username` (string) - The XenServer username used to access the remote machine.
|
||||||
|
|
||||||
@ -59,7 +72,7 @@ each category, the available options are alphabetized and described.
|
|||||||
be to type just enough to initialize the operating system installer. Special
|
be to type just enough to initialize the operating system installer. Special
|
||||||
keys can be typed as well, and are covered in the section below on the boot
|
keys can be typed as well, and are covered in the section below on the boot
|
||||||
command. If this is not specified, it is assumed the installer will start
|
command. If this is not specified, it is assumed the installer will start
|
||||||
itself. See the [Ubuntu](../../examples/ubuntu-2004.json) and [centos](../../examples/centos8.json) examples to see how these are used to launch autoinstall and kickstart respectively.
|
itself. See the [Ubuntu](../../../examples/ubuntu) and [centos](../../../examples/centos) examples to see how these are used to launch autoinstall and kickstart respectively.
|
||||||
|
|
||||||
* `boot_wait` (string) - The time to wait after booting the initial virtual
|
* `boot_wait` (string) - The time to wait after booting the initial virtual
|
||||||
machine before typing the `boot_command`. The value of this should be
|
machine before typing the `boot_command`. The value of this should be
|
||||||
@ -198,6 +211,8 @@ each category, the available options are alphabetized and described.
|
|||||||
* `vm_memory` (integer) - The size, in megabytes, of the amount of memory to
|
* `vm_memory` (integer) - The size, in megabytes, of the amount of memory to
|
||||||
allocate for the VM. By default, this is 1024 (1 GB).
|
allocate for the VM. By default, this is 1024 (1 GB).
|
||||||
|
|
||||||
|
* `vm_tags` (array of strings) - A list of tags to add to the VM
|
||||||
|
|
||||||
## Differences with other Packer builders
|
## Differences with other Packer builders
|
||||||
|
|
||||||
Currently the XenServer builder has some quirks when compared with other Packer builders.
|
Currently the XenServer builder has some quirks when compared with other Packer builders.
|
||||||
@ -256,4 +271,4 @@ The available variables are:
|
|||||||
configuration parameter. If `http_directory` isn't specified, these will be
|
configuration parameter. If `http_directory` isn't specified, these will be
|
||||||
blank!
|
blank!
|
||||||
|
|
||||||
See the [examples](../../examples/) for working boot commands.
|
See the [examples](../../../examples) for working boot commands.
|
||||||
|
@ -47,8 +47,7 @@ locals {
|
|||||||
}
|
}
|
||||||
|
|
||||||
source "xenserver-iso" "centos8-local" {
|
source "xenserver-iso" "centos8-local" {
|
||||||
iso_checksum = "aaf9d4b3071c16dbbda01dfe06085e5d0fdac76df323e3bbe87cce4318052247"
|
iso_checksum = "sha1:aaf9d4b3071c16dbbda01dfe06085e5d0fdac76df323e3bbe87cce4318052247"
|
||||||
iso_checksum_type = "sha1"
|
|
||||||
iso_url = "http://mirrors.ocf.berkeley.edu/centos/8.3.2011/isos/x86_64/CentOS-8.3.2011-x86_64-dvd1.iso"
|
iso_url = "http://mirrors.ocf.berkeley.edu/centos/8.3.2011/isos/x86_64/CentOS-8.3.2011-x86_64-dvd1.iso"
|
||||||
|
|
||||||
sr_iso_name = var.sr_iso_name
|
sr_iso_name = var.sr_iso_name
|
||||||
|
@ -47,8 +47,7 @@ locals {
|
|||||||
}
|
}
|
||||||
|
|
||||||
source "xenserver-iso" "centos8-netinstall" {
|
source "xenserver-iso" "centos8-netinstall" {
|
||||||
iso_checksum = "07a8e59c42cc086ec4c49bdce4fae5a17b077dea"
|
iso_checksum = "sha1:07a8e59c42cc086ec4c49bdce4fae5a17b077dea"
|
||||||
iso_checksum_type = "sha1"
|
|
||||||
iso_url = "http://mirrors.ocf.berkeley.edu/centos/8.3.2011/isos/x86_64/CentOS-8.3.2011-x86_64-boot.iso"
|
iso_url = "http://mirrors.ocf.berkeley.edu/centos/8.3.2011/isos/x86_64/CentOS-8.3.2011-x86_64-boot.iso"
|
||||||
|
|
||||||
sr_iso_name = var.sr_iso_name
|
sr_iso_name = var.sr_iso_name
|
||||||
|
@ -1,12 +1,43 @@
|
|||||||
packer {
|
packer {
|
||||||
required_plugins {
|
required_plugins {
|
||||||
xenserver= {
|
xenserver= {
|
||||||
version = ">= v0.3.2"
|
version = ">= v0.5.2"
|
||||||
source = "github.com/ddelnano/xenserver"
|
source = "github.com/ddelnano/xenserver"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# The ubuntu_version value determines what Ubuntu iso URL and sha256 hash we lookup. Updating
|
||||||
|
# this will allow a new version to be pulled in.
|
||||||
|
data "null" "ubuntu_version" {
|
||||||
|
input = "20.04"
|
||||||
|
}
|
||||||
|
|
||||||
|
locals {
|
||||||
|
timestamp = regex_replace(timestamp(), "[- TZ:]", "")
|
||||||
|
ubuntu_version = data.null.ubuntu_version.output
|
||||||
|
|
||||||
|
# Update this map to support future releases. At this time, the Ubuntu
|
||||||
|
# jammy template is not available yet.
|
||||||
|
ubuntu_template_name = {
|
||||||
|
20.04 = "Ubuntu Focal Fossa 20.04"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# TODO(ddelnano): Update this to use a local once https://github.com/hashicorp/packer/issues/11011
|
||||||
|
# is fixed.
|
||||||
|
data "http" "ubuntu_sha_and_release" {
|
||||||
|
url = "https://releases.ubuntu.com/${data.null.ubuntu_version.output}/SHA256SUMS"
|
||||||
|
}
|
||||||
|
|
||||||
|
local "ubuntu_sha256" {
|
||||||
|
expression = regex("([A-Za-z0-9]+)[\\s\\*]+ubuntu-.*server", data.http.ubuntu_sha_and_release.body)
|
||||||
|
}
|
||||||
|
|
||||||
|
local "ubuntu_url_path" {
|
||||||
|
expression = regex("[A-Za-z0-9]+[\\s\\*]+ubuntu-${local.ubuntu_version}.(\\d+)-live-server-amd64.iso", data.http.ubuntu_sha_and_release.body)
|
||||||
|
}
|
||||||
|
|
||||||
variable "remote_host" {
|
variable "remote_host" {
|
||||||
type = string
|
type = string
|
||||||
description = "The ip or fqdn of your XenServer. This will be pulled from the env var 'PKR_VAR_XAPI_HOST'"
|
description = "The ip or fqdn of your XenServer. This will be pulled from the env var 'PKR_VAR_XAPI_HOST'"
|
||||||
@ -42,15 +73,9 @@ variable "sr_name" {
|
|||||||
description = "The name of the SR to packer will use"
|
description = "The name of the SR to packer will use"
|
||||||
}
|
}
|
||||||
|
|
||||||
locals {
|
|
||||||
timestamp = regex_replace(timestamp(), "[- TZ:]", "")
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
source "xenserver-iso" "ubuntu-2004" {
|
source "xenserver-iso" "ubuntu-2004" {
|
||||||
iso_checksum = "d1f2bf834bbe9bb43faf16f9be992a6f3935e65be0edece1dee2aa6eb1767423"
|
iso_checksum = "sha256:${local.ubuntu_sha256.0}"
|
||||||
iso_checksum_type = "sha256"
|
iso_url = "https://releases.ubuntu.com/${local.ubuntu_version}/ubuntu-${local.ubuntu_version}.${local.ubuntu_url_path.0}-live-server-amd64.iso"
|
||||||
iso_url = "http://releases.ubuntu.com/20.04/ubuntu-20.04.2-live-server-amd64.iso"
|
|
||||||
|
|
||||||
sr_iso_name = var.sr_iso_name
|
sr_iso_name = var.sr_iso_name
|
||||||
sr_name = var.sr_name
|
sr_name = var.sr_name
|
||||||
@ -60,10 +85,12 @@ source "xenserver-iso" "ubuntu-2004" {
|
|||||||
remote_password = var.remote_password
|
remote_password = var.remote_password
|
||||||
remote_username = var.remote_username
|
remote_username = var.remote_username
|
||||||
|
|
||||||
vm_name = "packer-ubuntu-2004-${local.timestamp}"
|
# Change this to match the ISO of ubuntu you are using in the iso_url variable
|
||||||
|
clone_template = local.ubuntu_template_name[data.null.ubuntu_version.output]
|
||||||
|
vm_name = "packer-ubuntu-${data.null.ubuntu_version.output}-${local.timestamp}"
|
||||||
vm_description = "Build started: ${local.timestamp}"
|
vm_description = "Build started: ${local.timestamp}"
|
||||||
vm_memory = 4096
|
vm_memory = 4096
|
||||||
disk_size = 20000
|
disk_size = 30720
|
||||||
|
|
||||||
floppy_files = [
|
floppy_files = [
|
||||||
"examples/http/ubuntu-2004/meta-data",
|
"examples/http/ubuntu-2004/meta-data",
|
||||||
|
Loading…
Reference in New Issue
Block a user