Compare commits
132 Commits
testing-xo
...
main
Author | SHA1 | Date | |
---|---|---|---|
|
756f4d7e1a | ||
|
4894eca5d3 | ||
|
d111a01612 | ||
|
fc6694679c | ||
|
36658a7875 | ||
|
deba45ef3a | ||
|
1e9c3eb66a | ||
|
7077d1e374 | ||
|
54738803d5 | ||
|
0ff8fa1e77 | ||
|
4b07607b11 | ||
|
bf1383d1e8 | ||
|
13c2a1d78a | ||
|
2a36fae810 | ||
|
c411df4b02 | ||
|
cc03e4a10c | ||
|
7147cb4592 | ||
|
1b20fbac99 | ||
|
6c9ee9dc94 | ||
|
b38a3b67bc | ||
|
a776a46e1e | ||
|
d11786a294 | ||
|
7a9e710071 | ||
|
88e56ca729 | ||
|
81c1ea03ee | ||
|
5a826dfbce | ||
|
bc21b3cfac | ||
|
e62c1a1373 | ||
|
30498d8258 | ||
|
e460d5bd58 | ||
|
eac40a8976 | ||
|
5dc6c311f0 | ||
|
af169dfed0 | ||
|
3a92c96509 | ||
|
ac530c5628 | ||
|
dc743791d9 | ||
|
3b40f051bb | ||
|
8f73b0d338 | ||
|
6bf1ad468c | ||
|
e64dd4897f | ||
|
23fdf2286d | ||
|
3a07cb9e0a | ||
|
84a3a2389a | ||
|
5194dec899 | ||
|
9d57d14f3e | ||
|
a9e5f30a55 | ||
|
4438cdce28 | ||
|
757529e20b | ||
|
8fe24bddcd | ||
|
6af6320f8a | ||
|
3cd902b9b6 | ||
|
2379ca3afc | ||
|
58fc1930bc | ||
|
02280e60e4 | ||
|
524ef18847 | ||
|
dac47c649b | ||
|
8ef30c26e4 | ||
|
609ef7317e | ||
|
7841481ee0 | ||
|
0b9d7be27e | ||
|
767809c80f | ||
|
785b62ad24 | ||
|
5759ecea09 | ||
|
4646bde57c | ||
|
a7ec448ce6 | ||
|
bea09bb3ed | ||
|
83b1052bb4 | ||
|
de1a62d88c | ||
|
ea70f903c7 | ||
|
5c090071a9 | ||
|
f6a317cb41 | ||
|
2fe14d14ac | ||
|
7c4b652c17 | ||
|
461367ad1c | ||
|
0bb70e8957 | ||
|
17c58e8d24 | ||
|
de46bb8b2f | ||
|
bb64b86619 | ||
|
3f0a2186bf | ||
|
cda48bd66e | ||
|
3c5fc29b36 | ||
|
70fd83e803 | ||
|
d8294d3ccd | ||
|
ffc0ffb5cd | ||
|
416c734853 | ||
|
b55b096836 | ||
|
6c808da038 | ||
|
6b0b4baf2f | ||
|
c49d4ebf12 | ||
|
880d12c66f | ||
|
9cc7249127 | ||
|
b4d83eb533 | ||
|
a267698fad | ||
|
5d0cff3fc6 | ||
|
479e16a2c1 | ||
|
d15616c1d2 | ||
|
dcb839e131 | ||
|
8c58db3504 | ||
|
6eeea7dc64 | ||
|
52cd604a9b | ||
|
73e173370a | ||
|
4f90bf5f17 | ||
|
0ccc53b8b5 | ||
|
55e3b071e3 | ||
|
752bd52f61 | ||
|
f72f00341c | ||
|
69bae007b6 | ||
|
88e52b581f | ||
|
f7a8fa4959 | ||
|
e9f55883e3 | ||
|
4df2465c06 | ||
|
8a823a13eb | ||
|
79c6b508a4 | ||
|
4b531de0ff | ||
|
f7de8aace4 | ||
|
1e35a0da41 | ||
|
88e403f87c | ||
|
6fc83b9e4b | ||
|
7b40fd4424 | ||
|
c6147b13c9 | ||
|
c5e5a86607 | ||
|
38ef07516e | ||
|
ac90dec7ea | ||
|
f4a161e806 | ||
|
5525b73b73 | ||
|
8b8bd284f5 | ||
|
509b6b3c25 | ||
|
7a4a1d0b9b | ||
|
d9cb44c847 | ||
|
aa4ea9d5c8 | ||
|
31683d2758 | ||
|
ac62f77e36 |
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"
|
14
.github/release.yml
vendored
Normal file
14
.github/release.yml
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
changelog:
|
||||
categories:
|
||||
- title: Breaking Changes 🛠
|
||||
labels:
|
||||
- breaking-change
|
||||
- title: New Features 🎉
|
||||
labels:
|
||||
- enhancement
|
||||
- title: Bug fixes
|
||||
labels:
|
||||
- bug
|
||||
- title: Other Changes
|
||||
labels:
|
||||
- "*"
|
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.20"
|
||||
- name: Run go tests
|
||||
run: go test -race -count 1 ./... -timeout=3m
|
20
.github/workflows/release.yml
vendored
20
.github/workflows/release.yml
vendored
@ -1,12 +1,12 @@
|
||||
# This GitHub action can publish assets for release when a tag is created.
|
||||
# Currently its setup to run on any tag that matches the pattern "v*" (ie. v0.1.0).
|
||||
#
|
||||
# This uses an action (paultyng/ghaction-import-gpg) that assumes you set your
|
||||
# private key in the `GPG_PRIVATE_KEY` secret and passphrase in the `PASSPHRASE`
|
||||
# This uses an action (hashicorp/ghaction-import-gpg) that assumes you set your
|
||||
# private key in the `GPG_PRIVATE_KEY` secret and passphrase in the `GPG_PASSPHRASE`
|
||||
# secret. If you would rather own your own GPG handling, please fork this action
|
||||
# or use an alternative one for key handling.
|
||||
#
|
||||
# You will need to pass the `--batch` flag to `gpg` in your signing step
|
||||
# You will need to pass the `--batch` flag to `gpg` in your signing step
|
||||
# in `goreleaser` to indicate this is being used in a non-interactive mode.
|
||||
#
|
||||
name: release
|
||||
@ -25,21 +25,21 @@ jobs:
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: 1.16
|
||||
go-version: "1.20"
|
||||
- name: Describe plugin
|
||||
id: plugin_describe
|
||||
run: echo "::set-output name=api_version::$(go run . describe | jq -r '.api_version')"
|
||||
- name: Import GPG key
|
||||
id: import_gpg
|
||||
uses: paultyng/ghaction-import-gpg@v2.1.0
|
||||
env:
|
||||
GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }}
|
||||
PASSPHRASE: ${{ secrets.PASSPHRASE }}
|
||||
uses: crazy-max/ghaction-import-gpg@v5.0.0
|
||||
with:
|
||||
gpg_private_key: ${{ secrets.GPG_PRIVATE_KEY }}
|
||||
passphrase: ${{ secrets.GPG_PASSPHRASE }}
|
||||
- name: Run GoReleaser
|
||||
uses: goreleaser/goreleaser-action@v2
|
||||
uses: goreleaser/goreleaser-action@f82d6c1c344bcacabba2c841718984797f664a6b # v4.2.0
|
||||
with:
|
||||
version: latest
|
||||
args: release --rm-dist
|
||||
args: release --clean
|
||||
env:
|
||||
GPG_FINGERPRINT: ${{ steps.import_gpg.outputs.fingerprint }}
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
1
.go-version
Normal file
1
.go-version
Normal file
@ -0,0 +1 @@
|
||||
1.20.11
|
@ -1,41 +1,36 @@
|
||||
|
||||
version: 2
|
||||
# This is an example goreleaser.yaml file with some sane defaults.
|
||||
# Make sure to check the documentation at http://goreleaser.com
|
||||
env:
|
||||
- CGO_ENABLED=0
|
||||
before:
|
||||
hooks:
|
||||
# We strongly recommend running tests to catch any regression before release.
|
||||
# Even though, this an optional step.
|
||||
# - go test ./...
|
||||
|
||||
- go test ./...
|
||||
# As part of the release doc files are included as a separate deliverable for
|
||||
# consumption by Packer.io. To include a separate docs.zip uncomment the following command.
|
||||
#- make ci-release-docs
|
||||
# Check plugin compatibility with required version of the Packer SDK
|
||||
- make plugin-check
|
||||
builds:
|
||||
# A separated build to run the packer-plugins-check only once for a linux_amd64 binary
|
||||
-
|
||||
id: plugin-check
|
||||
mod_timestamp: '{{ .CommitTimestamp }}'
|
||||
hooks:
|
||||
post:
|
||||
# This will check plugin compatibility against latest version of Packer
|
||||
- cmd: |
|
||||
go install github.com/hashicorp/packer/cmd/packer-plugins-check@latest &&
|
||||
packer-plugins-check -load={{ .Name }}
|
||||
dir: "{{ dir .Path}}"
|
||||
flags:
|
||||
- -trimpath #removes all file system paths from the compiled executable
|
||||
ldflags:
|
||||
- '-s -w -X main.Version={{.Version}} -X main.VersionPrerelease= '
|
||||
- '-s -w -X {{ .ModulePath }}/version.Version={{.Version}} -X {{ .ModulePath }}/version.VersionPrerelease= '
|
||||
goos:
|
||||
- linux
|
||||
goarch:
|
||||
- amd64
|
||||
binary: '{{ .ProjectName }}_v{{ .Version }}_{{ .Env.API_VERSION }}_{{ .Os }}_{{ .Arch }}'
|
||||
-
|
||||
-
|
||||
mod_timestamp: '{{ .CommitTimestamp }}'
|
||||
flags:
|
||||
- -trimpath #removes all file system paths from the compiled executable
|
||||
ldflags:
|
||||
- '-s -w -X main.version={{.Version}} -X main.VersionPrerelease= '
|
||||
- '-s -w -X {{ .ModulePath }}/version.Version={{.Version}} -X {{ .ModulePath }}/version.VersionPrerelease= '
|
||||
goos:
|
||||
- freebsd
|
||||
- windows
|
||||
@ -51,10 +46,11 @@ builds:
|
||||
goarch: '386'
|
||||
- goos: linux
|
||||
goarch: amd64
|
||||
|
||||
binary: '{{ .ProjectName }}_v{{ .Version }}_{{ .Env.API_VERSION }}_{{ .Os }}_{{ .Arch }}'
|
||||
archives:
|
||||
- format: zip
|
||||
files:
|
||||
- none*
|
||||
name_template: '{{ .ProjectName }}_v{{ .Version }}_{{ .Env.API_VERSION }}_{{ .Os }}_{{ .Arch }}'
|
||||
checksum:
|
||||
name_template: '{{ .ProjectName }}_v{{ .Version }}_SHA256SUMS'
|
||||
@ -62,7 +58,7 @@ checksum:
|
||||
signs:
|
||||
- artifacts: checksum
|
||||
args:
|
||||
# if you are using this is in a GitHub action or some other automated pipeline, you
|
||||
# if you are using this is in a GitHub action or some other automated pipeline, you
|
||||
# need to pass the batch flag to indicate its not interactive.
|
||||
- "--batch"
|
||||
- "--local-user"
|
||||
@ -72,7 +68,7 @@ signs:
|
||||
- "--detach-sign"
|
||||
- "${artifact}"
|
||||
release:
|
||||
# If you want to manually examine the release before its live, uncomment this line:
|
||||
draft: true
|
||||
draft: false
|
||||
|
||||
changelog:
|
||||
skip: true
|
||||
disable: true
|
||||
|
@ -1,7 +0,0 @@
|
||||
language: go
|
||||
go:
|
||||
# Test with the first and the latest go release - to ensure compatibility
|
||||
- 1.6
|
||||
- tip
|
||||
script:
|
||||
- gofmtresult=$(gofmt -s -l .); if [[ -n $gofmtresult ]]; then echo -e "Please run \"gofmt -s -w .\" before committing for the below:\n$gofmtresult"; false; fi
|
34
GNUmakefile
Normal file
34
GNUmakefile
Normal file
@ -0,0 +1,34 @@
|
||||
NAME=xenserver
|
||||
BINARY=packer-plugin-${NAME}
|
||||
|
||||
COUNT?=1
|
||||
TEST?=$(shell go list ./...)
|
||||
HASHICORP_PACKER_PLUGIN_SDK_VERSION?=$(shell go list -m github.com/hashicorp/packer-plugin-sdk | cut -d " " -f2)
|
||||
|
||||
.PHONY: dev
|
||||
|
||||
build:
|
||||
@go build -o ${BINARY}
|
||||
|
||||
dev: build
|
||||
@mkdir -p ~/.packer.d/plugins/
|
||||
@mv ${BINARY} ~/.packer.d/plugins/${BINARY}
|
||||
|
||||
test:
|
||||
@go test -race -count $(COUNT) $(TEST) -timeout=3m
|
||||
|
||||
install-packer-sdc: ## Install packer sofware development command
|
||||
@go install github.com/hashicorp/packer-plugin-sdk/cmd/packer-sdc@${HASHICORP_PACKER_PLUGIN_SDK_VERSION}
|
||||
|
||||
ci-release-docs: install-packer-sdc
|
||||
@packer-sdc renderdocs -src docs -partials docs-partials/ -dst docs/
|
||||
@/bin/sh -c "[ -d docs ] && zip -r docs.zip docs/"
|
||||
|
||||
plugin-check: install-packer-sdc build
|
||||
@packer-sdc plugin-check ${BINARY}
|
||||
|
||||
testacc: dev
|
||||
@PACKER_ACC=1 go test -count $(COUNT) -v $(TEST) -timeout=120m
|
||||
|
||||
generate: install-packer-sdc
|
||||
@go generate ./...
|
36
README.md
36
README.md
@ -2,7 +2,7 @@
|
||||
|
||||
This builder plugin extends packer.io to support building images for XenServer.
|
||||
|
||||
This is a fork of the original builder since the original project was abandoned and no longer compilied with recent versions of Go or worked with Xenserver 7.6 and later.
|
||||
This is a fork of the original builder since the original project was abandoned and no longer compiled with recent versions of Go or worked with Xenserver 7.6 and later.
|
||||
|
||||
It improves the original project in the following ways:
|
||||
1. Developed alongside the [Xenorchestra terraform provider](https://github.com/ddelnano/terraform-provider-xenorchestra) to ensure the hashicorp ecosystem is interoperable.
|
||||
@ -13,6 +13,7 @@ It improves the original project in the following ways:
|
||||
At the time of this writing the packer builder has been verified to work with Xenserver 7.6 and can launch VMs with the packer output through the xenorchestra terraform provider.
|
||||
|
||||
The following list contains things that are incomplete but will be worked on soon:
|
||||
|
||||
- The documentation is still in an inconsistent state with upstream
|
||||
- XVA builder is untested
|
||||
- Lots of dead code to remove from upstream
|
||||
@ -24,7 +25,7 @@ The packer builder can be installed via `packer init` as long as the packer temp
|
||||
packer {
|
||||
required_plugins {
|
||||
xenserver= {
|
||||
version = ">= v0.3.2"
|
||||
version = ">= v0.6.0"
|
||||
source = "github.com/ddelnano/xenserver"
|
||||
}
|
||||
}
|
||||
@ -44,26 +45,43 @@ If you are using an older version of packer or are still using json templates yo
|
||||
### Dependencies
|
||||
* Packer >= v1.7.1 (https://packer.io)
|
||||
* XenServer / Citrix Hypervisor > 7.6
|
||||
* Golang 1.16
|
||||
* Golang 1.20
|
||||
|
||||
## Compile the plugin
|
||||
|
||||
Once you have installed Packer, you must compile this plugin and install the
|
||||
resulting binary.
|
||||
|
||||
```shell
|
||||
$ go build -o packer-plugin-xenserver
|
||||
Documentation for Plugins directory: [Official Docs](https://developer.hashicorp.com/packer/docs/configure#packer-s-plugin-directory)
|
||||
|
||||
# Add the builder to the location packer expects it to be installed in
|
||||
$ mkdir -p ~/.packer.d/plugins/
|
||||
$ cp builder-xenserver-iso ~/.packer.d/plugins/packer-builder-xenserver-iso
|
||||
### Linux/MacOS
|
||||
|
||||
```shell
|
||||
go build -o packer-plugin-xenserver
|
||||
|
||||
# Add the plugin to the location packer expects it to be installed in
|
||||
mkdir -p ~/.packer.d/plugins/
|
||||
cp packer-plugin-xenserver ~/.packer.d/plugins
|
||||
```
|
||||
|
||||
### Windows (Powershell)
|
||||
|
||||
```powershell
|
||||
go build -o packer-plugin-xenserver
|
||||
|
||||
mkdir "%APPDATA%\packer.d\plugins"
|
||||
cp packer-plugin-xenserver "%APPDATA%\packer.d\plugins"
|
||||
```
|
||||
|
||||
# Documentation
|
||||
|
||||
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
|
||||
|
||||
You can discuss any issues you have or feature requests in [Discord](https://discord.gg/ZpNq8ez).
|
||||
|
||||
If you'd like to support my effort on the project, please consider buying me a coffee
|
||||
|
||||
[!["Buy Me A Coffee"](https://www.buymeacoffee.com/assets/img/custom_images/orange_img.png)](https://www.buymeacoffee.com/ddelnano)
|
||||
|
@ -624,6 +624,17 @@ func ConnectNetwork(c *Connection, networkRef xenapi.NetworkRef, vmRef xenapi.VM
|
||||
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
|
||||
|
||||
func (self *VM) SetIsATemplate(is_a_template bool) (err error) {
|
||||
|
@ -13,17 +13,19 @@ import (
|
||||
)
|
||||
|
||||
type CommonConfig struct {
|
||||
Username string `mapstructure:"remote_username"`
|
||||
Password string `mapstructure:"remote_password"`
|
||||
HostIp string `mapstructure:"remote_host"`
|
||||
Username string `mapstructure:"remote_username"`
|
||||
Password string `mapstructure:"remote_password"`
|
||||
HostIp string `mapstructure:"remote_host"`
|
||||
HostSshPort uint `mapstructure:"remote_ssh_port"`
|
||||
|
||||
VMName string `mapstructure:"vm_name"`
|
||||
VMDescription string `mapstructure:"vm_description"`
|
||||
SrName string `mapstructure:"sr_name"`
|
||||
SrISOName string `mapstructure:"sr_iso_name"`
|
||||
SrISOName string `mapstructure:"sr_iso_name" required:"false"`
|
||||
FloppyFiles []string `mapstructure:"floppy_files"`
|
||||
NetworkNames []string `mapstructure:"network_names"`
|
||||
ExportNetworkNames []string `mapstructure:"export_network_names"`
|
||||
VMTags []string `mapstructure:"vm_tags"`
|
||||
|
||||
HostPortMin uint `mapstructure:"host_port_min"`
|
||||
HostPortMax uint `mapstructure:"host_port_max"`
|
||||
@ -63,6 +65,10 @@ func (c *CommonConfig) Prepare(ctx *interpolate.Context, pc *common.PackerConfig
|
||||
|
||||
// Set default values
|
||||
|
||||
if c.HostSshPort == 0 {
|
||||
c.HostSshPort = 22
|
||||
}
|
||||
|
||||
if c.HostPortMin == 0 {
|
||||
c.HostPortMin = 5900
|
||||
}
|
||||
@ -75,10 +81,6 @@ func (c *CommonConfig) Prepare(ctx *interpolate.Context, pc *common.PackerConfig
|
||||
c.RawBootWait = "5s"
|
||||
}
|
||||
|
||||
if c.ToolsIsoName == "" {
|
||||
c.ToolsIsoName = "xs-tools.iso"
|
||||
}
|
||||
|
||||
if c.HTTPPortMin == 0 {
|
||||
c.HTTPPortMin = 8000
|
||||
}
|
||||
@ -223,29 +225,11 @@ func (c CommonConfig) ShouldKeepVM(state multistep.StateBag) bool {
|
||||
}
|
||||
|
||||
func (config CommonConfig) GetSR(c *Connection) (xenapi.SRRef, error) {
|
||||
var srRef xenapi.SRRef
|
||||
if config.SrName == "" {
|
||||
hostRef, err := c.GetClient().Session.GetThisHost(c.session, c.session)
|
||||
|
||||
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))
|
||||
|
||||
return getDefaultSR(c)
|
||||
} else {
|
||||
var srRef xenapi.SRRef
|
||||
|
||||
// Use the provided name label to find the SR to use
|
||||
srs, err := c.GetClient().SR.GetByNameLabel(c.session, config.SrName)
|
||||
|
||||
@ -267,11 +251,11 @@ func (config CommonConfig) GetSR(c *Connection) (xenapi.SRRef, error) {
|
||||
func (config CommonConfig) GetISOSR(c *Connection) (xenapi.SRRef, error) {
|
||||
var srRef xenapi.SRRef
|
||||
if config.SrISOName == "" {
|
||||
return srRef, errors.New("sr_iso_name must be specified in the packer configuration")
|
||||
return getDefaultSR(c)
|
||||
|
||||
} else {
|
||||
// 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 {
|
||||
return srRef, err
|
||||
@ -279,11 +263,42 @@ func (config CommonConfig) GetISOSR(c *Connection) (xenapi.SRRef, error) {
|
||||
|
||||
switch {
|
||||
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:
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
import (
|
||||
@ -17,15 +17,16 @@ type Config struct {
|
||||
VCPUsMax uint `mapstructure:"vcpus_max"`
|
||||
VCPUsAtStartup uint `mapstructure:"vcpus_atstartup"`
|
||||
VMMemory uint `mapstructure:"vm_memory"`
|
||||
DiskName string `mapstructure:"disk_name"`
|
||||
DiskSize uint `mapstructure:"disk_size"`
|
||||
CloneTemplate string `mapstructure:"clone_template"`
|
||||
VMOtherConfig map[string]string `mapstructure:"vm_other_config"`
|
||||
VMTags []string `mapstructure:"vm_tags"`
|
||||
|
||||
ISOChecksum string `mapstructure:"iso_checksum"`
|
||||
ISOChecksumType string `mapstructure:"iso_checksum_type"`
|
||||
ISOUrls []string `mapstructure:"iso_urls"`
|
||||
ISOUrl string `mapstructure:"iso_url"`
|
||||
ISOName string `mapstructure:"iso_name"`
|
||||
ISOChecksum string `mapstructure:"iso_checksum"`
|
||||
ISOUrls []string `mapstructure:"iso_urls"`
|
||||
ISOUrl string `mapstructure:"iso_url"`
|
||||
ISOName string `mapstructure:"iso_name"`
|
||||
|
||||
PlatformArgs map[string]string `mapstructure:"platform_args"`
|
||||
|
||||
@ -33,6 +34,9 @@ type Config struct {
|
||||
InstallTimeout time.Duration ``
|
||||
SourcePath string `mapstructure:"source_path"`
|
||||
|
||||
Firmware string `mapstructure:"firmware"`
|
||||
SkipSetTemplate bool `mapstructure:"skip_set_template"`
|
||||
|
||||
ctx interpolate.Context
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
||||
@ -12,6 +12,7 @@ import (
|
||||
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"`
|
||||
@ -20,13 +21,15 @@ type FlatConfig struct {
|
||||
Username *string `mapstructure:"remote_username" cty:"remote_username" hcl:"remote_username"`
|
||||
Password *string `mapstructure:"remote_password" cty:"remote_password" hcl:"remote_password"`
|
||||
HostIp *string `mapstructure:"remote_host" cty:"remote_host" hcl:"remote_host"`
|
||||
HostSshPort *uint `mapstructure:"remote_ssh_port" cty:"remote_ssh_port" hcl:"remote_ssh_port"`
|
||||
VMName *string `mapstructure:"vm_name" cty:"vm_name" hcl:"vm_name"`
|
||||
VMDescription *string `mapstructure:"vm_description" cty:"vm_description" hcl:"vm_description"`
|
||||
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"`
|
||||
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"`
|
||||
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"`
|
||||
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"`
|
||||
@ -96,17 +99,19 @@ type FlatConfig struct {
|
||||
VCPUsMax *uint `mapstructure:"vcpus_max" cty:"vcpus_max" hcl:"vcpus_max"`
|
||||
VCPUsAtStartup *uint `mapstructure:"vcpus_atstartup" cty:"vcpus_atstartup" hcl:"vcpus_atstartup"`
|
||||
VMMemory *uint `mapstructure:"vm_memory" cty:"vm_memory" hcl:"vm_memory"`
|
||||
DiskName *string `mapstructure:"disk_name" cty:"disk_name" hcl:"disk_name"`
|
||||
DiskSize *uint `mapstructure:"disk_size" cty:"disk_size" hcl:"disk_size"`
|
||||
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"`
|
||||
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"`
|
||||
ISOUrl *string `mapstructure:"iso_url" cty:"iso_url" hcl:"iso_url"`
|
||||
ISOName *string `mapstructure:"iso_name" cty:"iso_name" hcl:"iso_name"`
|
||||
PlatformArgs map[string]string `mapstructure:"platform_args" cty:"platform_args" hcl:"platform_args"`
|
||||
RawInstallTimeout *string `mapstructure:"install_timeout" cty:"install_timeout" hcl:"install_timeout"`
|
||||
SourcePath *string `mapstructure:"source_path" cty:"source_path" hcl:"source_path"`
|
||||
Firmware *string `mapstructure:"firmware" cty:"firmware" hcl:"firmware"`
|
||||
SkipSetTemplate *bool `mapstructure:"skip_set_template" cty:"skip_set_template" hcl:"skip_set_template"`
|
||||
}
|
||||
|
||||
// FlatMapstructure returns a new FlatConfig.
|
||||
@ -123,6 +128,7 @@ 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},
|
||||
@ -131,6 +137,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
|
||||
"remote_username": &hcldec.AttrSpec{Name: "remote_username", Type: cty.String, Required: false},
|
||||
"remote_password": &hcldec.AttrSpec{Name: "remote_password", Type: cty.String, Required: false},
|
||||
"remote_host": &hcldec.AttrSpec{Name: "remote_host", Type: cty.String, Required: false},
|
||||
"remote_ssh_port": &hcldec.AttrSpec{Name: "remote_ssh_port", Type: cty.Number, Required: false},
|
||||
"vm_name": &hcldec.AttrSpec{Name: "vm_name", Type: cty.String, Required: false},
|
||||
"vm_description": &hcldec.AttrSpec{Name: "vm_description", Type: cty.String, Required: false},
|
||||
"sr_name": &hcldec.AttrSpec{Name: "sr_name", Type: cty.String, Required: false},
|
||||
@ -138,6 +145,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
|
||||
"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},
|
||||
"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_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},
|
||||
@ -207,17 +215,19 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
|
||||
"vcpus_max": &hcldec.AttrSpec{Name: "vcpus_max", Type: cty.Number, Required: false},
|
||||
"vcpus_atstartup": &hcldec.AttrSpec{Name: "vcpus_atstartup", Type: cty.Number, Required: false},
|
||||
"vm_memory": &hcldec.AttrSpec{Name: "vm_memory", Type: cty.Number, Required: false},
|
||||
"disk_name": &hcldec.AttrSpec{Name: "disk_name", Type: cty.String, Required: false},
|
||||
"disk_size": &hcldec.AttrSpec{Name: "disk_size", Type: cty.Number, 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},
|
||||
"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_url": &hcldec.AttrSpec{Name: "iso_url", Type: cty.String, Required: false},
|
||||
"iso_name": &hcldec.AttrSpec{Name: "iso_name", Type: cty.String, Required: false},
|
||||
"platform_args": &hcldec.AttrSpec{Name: "platform_args", Type: cty.Map(cty.String), Required: false},
|
||||
"install_timeout": &hcldec.AttrSpec{Name: "install_timeout", Type: cty.String, Required: false},
|
||||
"source_path": &hcldec.AttrSpec{Name: "source_path", Type: cty.String, Required: false},
|
||||
"firmware": &hcldec.AttrSpec{Name: "firmware", Type: cty.String, Required: false},
|
||||
"skip_set_template": &hcldec.AttrSpec{Name: "skip_set_template", Type: cty.Bool, Required: false},
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
@ -17,7 +17,7 @@ import (
|
||||
|
||||
func SSHAddress(state multistep.StateBag) (string, error) {
|
||||
sshIP := state.Get("ssh_address").(string)
|
||||
sshHostPort := 22
|
||||
sshHostPort := state.Get("ssh_port").(uint)
|
||||
return fmt.Sprintf("%s:%d", sshIP, sshHostPort), nil
|
||||
}
|
||||
|
||||
@ -114,10 +114,10 @@ func ExecuteGuestSSHCmd(state multistep.StateBag, cmd string) (stdout string, er
|
||||
return doExecuteSSHCmd(cmd, localAddress, sshConfig)
|
||||
}
|
||||
|
||||
func forward(local_conn net.Conn, config *gossh.ClientConfig, server, remote_dest string, remote_port uint) error {
|
||||
func forward(local_conn net.Conn, config *gossh.ClientConfig, server string, server_ssh_port int, remote_dest string, remote_port uint) error {
|
||||
defer local_conn.Close()
|
||||
|
||||
ssh_client_conn, err := gossh.Dial("tcp", server+":22", config)
|
||||
ssh_client_conn, err := gossh.Dial("tcp", fmt.Sprintf("%s:%d", server, server_ssh_port), config)
|
||||
if err != nil {
|
||||
log.Printf("local ssh.Dial error: %s", err)
|
||||
return err
|
||||
@ -157,7 +157,7 @@ func forward(local_conn net.Conn, config *gossh.ClientConfig, server, remote_des
|
||||
return nil
|
||||
}
|
||||
|
||||
func ssh_port_forward(local_listener net.Listener, remote_port int, remote_dest, host, username, password string) error {
|
||||
func ssh_port_forward(local_listener net.Listener, remote_port int, remote_dest, host string, host_ssh_port int, username, password string) error {
|
||||
|
||||
config := &gossh.ClientConfig{
|
||||
User: username,
|
||||
@ -176,7 +176,7 @@ func ssh_port_forward(local_listener net.Listener, remote_port int, remote_dest,
|
||||
}
|
||||
|
||||
// Forward to a remote port
|
||||
go forward(local_connection, config, host, remote_dest, uint(remote_port))
|
||||
go forward(local_connection, config, host, host_ssh_port, remote_dest, uint(remote_port))
|
||||
}
|
||||
|
||||
return nil
|
||||
|
@ -1,4 +1,4 @@
|
||||
package iso
|
||||
package common
|
||||
|
||||
import (
|
||||
"context"
|
||||
@ -9,18 +9,21 @@ import (
|
||||
"github.com/hashicorp/packer-plugin-sdk/packer"
|
||||
xenapi "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
|
||||
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)
|
||||
config := state.Get("config").(xscommon.Config)
|
||||
c := state.Get("client").(*Connection)
|
||||
config := state.Get("config").(Config)
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
|
||||
ui.Say("Step: Create Instance")
|
||||
@ -101,37 +104,45 @@ func (self *stepCreateInstance) Run(ctx context.Context, state multistep.StateBa
|
||||
}
|
||||
}
|
||||
|
||||
// Create VDI for the instance
|
||||
sr, err := config.GetSR(c)
|
||||
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
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
ui.Error(fmt.Sprintf("Unable to get SR: %s", err.Error()))
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
// Create VDI for the instance
|
||||
sr, err := config.GetSR(c)
|
||||
|
||||
ui.Say(fmt.Sprintf("Using the following SR for the VM: %s", sr))
|
||||
if err != nil {
|
||||
ui.Error(fmt.Sprintf("Unable to get SR: %s", err.Error()))
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
vdi, err := c.GetClient().VDI.Create(c.GetSessionRef(), xenapi.VDIRecord{
|
||||
NameLabel: "Packer-disk",
|
||||
VirtualSize: int(config.DiskSize * 1024 * 1024),
|
||||
Type: "user",
|
||||
Sharable: false,
|
||||
ReadOnly: false,
|
||||
SR: sr,
|
||||
OtherConfig: map[string]string{
|
||||
"temp": "temp",
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
ui.Error(fmt.Sprintf("Unable to create packer disk VDI: %s", err.Error()))
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
self.vdi = &vdi
|
||||
ui.Say(fmt.Sprintf("Using the following SR for the VM: %s", sr))
|
||||
|
||||
err = xscommon.ConnectVdi(c, instance, vdi, xsclient.VbdTypeDisk)
|
||||
if err != nil {
|
||||
ui.Error(fmt.Sprintf("Unable to connect packer disk VDI: %s", err.Error()))
|
||||
return multistep.ActionHalt
|
||||
vdi, err := c.GetClient().VDI.Create(c.GetSessionRef(), xenapi.VDIRecord{
|
||||
NameLabel: config.DiskName,
|
||||
VirtualSize: int(config.DiskSize * 1024 * 1024),
|
||||
Type: "user",
|
||||
Sharable: false,
|
||||
ReadOnly: false,
|
||||
SR: sr,
|
||||
OtherConfig: map[string]string{
|
||||
"temp": "temp",
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
ui.Error(fmt.Sprintf("Unable to create packer disk VDI: %s", err.Error()))
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
self.vdi = &vdi
|
||||
|
||||
err = ConnectVdi(c, instance, vdi, xsclient.VbdTypeDisk)
|
||||
if err != nil {
|
||||
ui.Error(fmt.Sprintf("Unable to connect packer disk VDI: %s", err.Error()))
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
}
|
||||
|
||||
// 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)
|
||||
_, err = xscommon.ConnectNetwork(c, network, instance, "0")
|
||||
_, err = ConnectNetwork(c, network, instance, "0")
|
||||
|
||||
if err != nil {
|
||||
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
|
||||
vifIndexString := fmt.Sprintf("%d", i)
|
||||
_, err = xscommon.ConnectNetwork(c, networks[0], instance, vifIndexString)
|
||||
_, err = ConnectNetwork(c, networks[0], instance, vifIndexString)
|
||||
|
||||
if err != nil {
|
||||
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)
|
||||
if err != nil {
|
||||
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
|
||||
}
|
||||
|
||||
func (self *stepCreateInstance) Cleanup(state multistep.StateBag) {
|
||||
config := state.Get("config").(xscommon.Config)
|
||||
func (self *StepCreateInstance) Cleanup(state multistep.StateBag) {
|
||||
config := state.Get("config").(Config)
|
||||
if config.ShouldKeepVM(state) {
|
||||
return
|
||||
}
|
||||
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
c := state.Get("client").(*xscommon.Connection)
|
||||
c := state.Get("client").(*Connection)
|
||||
|
||||
if self.instance != nil {
|
||||
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)
|
||||
}
|
@ -35,10 +35,11 @@ func (self *StepForwardPortOverSSH) Run(ctx context.Context, state multistep.Sta
|
||||
ui.Say(fmt.Sprintf("Creating a local port forward over SSH on local port %d", sshHostPort))
|
||||
|
||||
hostAddress, _ := state.Get("ssh_address").(string)
|
||||
hostSshPort, _ := state.Get("ssh_port").(int)
|
||||
remotePort, _ := self.RemotePort(state)
|
||||
remoteDest, _ := self.RemoteDest(state)
|
||||
|
||||
go ssh_port_forward(l, remotePort, remoteDest, hostAddress, config.Username, config.Password)
|
||||
go ssh_port_forward(l, remotePort, remoteDest, hostAddress, hostSshPort, config.Username, config.Password)
|
||||
ui.Say(fmt.Sprintf("Port forward setup. %d ---> %s:%d on %s", sshHostPort, remoteDest, remotePort, hostAddress))
|
||||
|
||||
// Provide the local port to future steps.
|
||||
|
@ -13,6 +13,7 @@ type StepSetVmHostSshAddress struct{}
|
||||
func (self *StepSetVmHostSshAddress) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
|
||||
|
||||
c := state.Get("client").(*Connection)
|
||||
config := state.Get("config").(Config)
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
|
||||
ui.Say("Step: Set SSH address to VM host IP")
|
||||
@ -37,6 +38,9 @@ func (self *StepSetVmHostSshAddress) Run(ctx context.Context, state multistep.St
|
||||
state.Put("ssh_address", address)
|
||||
ui.Say(fmt.Sprintf("Set host SSH address to '%s'.", address))
|
||||
|
||||
state.Put("ssh_port", config.HostSshPort)
|
||||
ui.Say(fmt.Sprintf("Set host SSH port to %d.", config.HostSshPort))
|
||||
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
|
@ -16,6 +16,7 @@ func (self *StepStartVmPaused) Run(ctx context.Context, state multistep.StateBag
|
||||
|
||||
c := state.Get("client").(*Connection)
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
config := state.Get("config").(Config)
|
||||
|
||||
ui.Say("Step: Start VM Paused")
|
||||
|
||||
@ -34,7 +35,7 @@ func (self *StepStartVmPaused) Run(ctx context.Context, state multistep.StateBag
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
err = c.client.VM.SetHVMBootParams(c.session, instance, map[string]string{"order": "cd"})
|
||||
err = c.client.VM.SetHVMBootParams(c.session, instance, map[string]string{"order": "cd", "firmware": config.Firmware})
|
||||
if err != nil {
|
||||
ui.Error(fmt.Sprintf("Unable to set HVM boot params: %s", err.Error()))
|
||||
return multistep.ActionHalt
|
||||
|
@ -32,8 +32,8 @@ type StepTypeBootCommand struct {
|
||||
Ctx interpolate.Context
|
||||
}
|
||||
|
||||
func (self *StepTypeBootCommand) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
|
||||
config := state.Get("commonconfig").(CommonConfig)
|
||||
func (step *StepTypeBootCommand) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
|
||||
config := state.Get("config").(Config)
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
c := state.Get("client").(*Connection)
|
||||
httpPort := state.Get("http_port").(int)
|
||||
@ -74,7 +74,8 @@ func (self *StepTypeBootCommand) Run(ctx context.Context, state multistep.StateB
|
||||
}
|
||||
locationPieces := strings.SplitAfter(location, "/")
|
||||
consoleHost := strings.TrimSuffix(locationPieces[2], "/")
|
||||
ui.Say(fmt.Sprintf("Connecting to the VM console VNC over xapi via %s", consoleHost))
|
||||
ui.Say("Connecting to VNC over XAPI...")
|
||||
log.Printf("Connecting to host: %s", consoleHost)
|
||||
conn, err := net.Dial("tcp", fmt.Sprintf("%s:443", consoleHost))
|
||||
|
||||
if err != nil {
|
||||
@ -95,7 +96,7 @@ func (self *StepTypeBootCommand) Run(ctx context.Context, state multistep.StateB
|
||||
httpReq := fmt.Sprintf("CONNECT %s HTTP/1.0\r\nHost: %s\r\nCookie: session_id=%s\r\n\r\n", consoleLocation, consoleHost, c.session)
|
||||
fmt.Printf("Sending the follow http req: %v", httpReq)
|
||||
|
||||
ui.Say(fmt.Sprintf("Making HTTP request to initiate VNC connection: %s", httpReq))
|
||||
ui.Message(fmt.Sprintf("Making HTTP request to initiate VNC connection: %s", httpReq))
|
||||
_, err = io.WriteString(tlsConn, httpReq)
|
||||
|
||||
if err != nil {
|
||||
@ -114,9 +115,9 @@ func (self *StepTypeBootCommand) Run(ctx context.Context, state multistep.StateB
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
ui.Say(fmt.Sprintf("Received response: %s", string(buffer)))
|
||||
ui.Message(fmt.Sprintf("Received response: %s", string(buffer)))
|
||||
|
||||
vncClient, err := vnc.Client(tlsConn, &vnc.ClientConfig{Exclusive: true})
|
||||
vncClient, err := vnc.Client(tlsConn, &vnc.ClientConfig{Exclusive: !config.PackerDebug})
|
||||
|
||||
if err != nil {
|
||||
err := fmt.Errorf("Error establishing VNC session: %s", err)
|
||||
@ -142,7 +143,7 @@ func (self *StepTypeBootCommand) Run(ctx context.Context, state multistep.StateB
|
||||
localIp := strings.Split(envVar, " ")[0]
|
||||
ui.Message(fmt.Sprintf("Found local IP: %s", localIp))
|
||||
|
||||
self.Ctx.Data = &bootCommandTemplateData{
|
||||
step.Ctx.Data = &bootCommandTemplateData{
|
||||
config.VMName,
|
||||
localIp,
|
||||
uint(httpPort),
|
||||
@ -151,7 +152,7 @@ func (self *StepTypeBootCommand) Run(ctx context.Context, state multistep.StateB
|
||||
ui.Say("Typing boot commands over VNC...")
|
||||
for _, command := range config.BootCommand {
|
||||
|
||||
command, err := interpolate.Render(command, &self.Ctx)
|
||||
command, err := interpolate.Render(command, &step.Ctx)
|
||||
if err != nil {
|
||||
err := fmt.Errorf("Error preparing boot command: %s", err)
|
||||
state.Put("error", err)
|
||||
@ -167,12 +168,10 @@ func (self *StepTypeBootCommand) Run(ctx context.Context, state multistep.StateB
|
||||
vncSendString(vncClient, command)
|
||||
}
|
||||
|
||||
ui.Say("Finished typing.")
|
||||
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
func (self *StepTypeBootCommand) Cleanup(multistep.StateBag) {}
|
||||
func (step *StepTypeBootCommand) Cleanup(multistep.StateBag) {}
|
||||
|
||||
// Taken from qemu's builder plugin - not an exported function.
|
||||
func vncSendString(c *vnc.ClientConn, original string) {
|
||||
|
@ -18,7 +18,7 @@ type StepUploadVdi struct {
|
||||
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)
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
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))
|
||||
|
||||
// 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)
|
||||
ui.Say(fmt.Sprintf("Step: Found SR for upload '%v'", sr))
|
||||
|
||||
if err != nil {
|
||||
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
|
||||
}
|
||||
|
||||
func (self *StepUploadVdi) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
|
||||
return self.uploadVdi(ctx, state)
|
||||
}
|
||||
|
||||
func (self *StepUploadVdi) Cleanup(state multistep.StateBag) {
|
||||
config := state.Get("commonconfig").(CommonConfig)
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
|
@ -60,7 +60,8 @@ func (self *StepWaitForIP) Run(ctx context.Context, state multistep.StateBag) mu
|
||||
return false, err
|
||||
}
|
||||
networks := metrics.Networks
|
||||
if ip, ok := networks["0/ip"]; ok {
|
||||
var ok bool
|
||||
if ip, ok = networks["0/ip"]; ok {
|
||||
if ip != "" {
|
||||
ui.Message(fmt.Sprintf("Got IP '%s' from XenServer tools", ip))
|
||||
return true, nil
|
||||
|
@ -40,7 +40,7 @@ func (self *Builder) Prepare(raws ...interface{}) (params []string, warns []stri
|
||||
}, raws...)
|
||||
|
||||
if err != nil {
|
||||
packer.MultiErrorAppend(errs, err)
|
||||
errs = packer.MultiErrorAppend(errs, err)
|
||||
}
|
||||
|
||||
errs = packer.MultiErrorAppend(
|
||||
@ -53,6 +53,10 @@ func (self *Builder) Prepare(raws ...interface{}) (params []string, warns []stri
|
||||
self.config.RawInstallTimeout = "200m"
|
||||
}
|
||||
|
||||
if self.config.DiskName == "" {
|
||||
self.config.DiskName = "Packer-disk"
|
||||
}
|
||||
|
||||
if self.config.DiskSize == 0 {
|
||||
self.config.DiskSize = 40000
|
||||
}
|
||||
@ -77,6 +81,10 @@ func (self *Builder) Prepare(raws ...interface{}) (params []string, warns []stri
|
||||
self.config.CloneTemplate = "Other install media"
|
||||
}
|
||||
|
||||
if self.config.Firmware == "" {
|
||||
self.config.Firmware = "bios"
|
||||
}
|
||||
|
||||
if len(self.config.PlatformArgs) == 0 {
|
||||
pargs := make(map[string]string)
|
||||
pargs["viridian"] = "false"
|
||||
@ -91,12 +99,11 @@ func (self *Builder) Prepare(raws ...interface{}) (params []string, warns []stri
|
||||
// Template substitution
|
||||
|
||||
templates := map[string]*string{
|
||||
"clone_template": &self.config.CloneTemplate,
|
||||
"iso_checksum": &self.config.ISOChecksum,
|
||||
"iso_checksum_type": &self.config.ISOChecksumType,
|
||||
"iso_url": &self.config.ISOUrl,
|
||||
"iso_name": &self.config.ISOName,
|
||||
"install_timeout": &self.config.RawInstallTimeout,
|
||||
"clone_template": &self.config.CloneTemplate,
|
||||
"iso_checksum": &self.config.ISOChecksum,
|
||||
"iso_url": &self.config.ISOUrl,
|
||||
"iso_name": &self.config.ISOName,
|
||||
"install_timeout": &self.config.RawInstallTimeout,
|
||||
}
|
||||
for i := range self.config.ISOUrls {
|
||||
templates[fmt.Sprintf("iso_urls[%d]", i)] = &self.config.ISOUrls[i]
|
||||
@ -111,23 +118,8 @@ func (self *Builder) Prepare(raws ...interface{}) (params []string, warns []stri
|
||||
}
|
||||
|
||||
if self.config.ISOName == "" {
|
||||
|
||||
// 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 self.config.ISOUrl == "" {
|
||||
@ -136,10 +128,25 @@ func (self *Builder) Prepare(raws ...interface{}) (params []string, warns []stri
|
||||
} else {
|
||||
self.config.ISOUrls = []string{self.config.ISOUrl}
|
||||
}
|
||||
|
||||
} else if self.config.ISOUrl != "" {
|
||||
errs = packer.MultiErrorAppend(
|
||||
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 {
|
||||
|
||||
// An ISO name has been provided. It should be attached from an available SR.
|
||||
@ -183,7 +190,6 @@ func (self *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (p
|
||||
Url: self.config.ISOUrls,
|
||||
},
|
||||
}
|
||||
|
||||
steps := []multistep.Step{
|
||||
&xscommon.StepPrepareOutputDir{
|
||||
Force: self.config.PackerForce,
|
||||
@ -191,6 +197,7 @@ func (self *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (p
|
||||
},
|
||||
&commonsteps.StepCreateFloppy{
|
||||
Files: self.config.FloppyFiles,
|
||||
Label: "cidata",
|
||||
},
|
||||
&xscommon.StepHTTPServer{
|
||||
Chan: httpReqChan,
|
||||
@ -207,20 +214,22 @@ func (self *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (p
|
||||
},
|
||||
VdiUuidKey: "floppy_vdi_uuid",
|
||||
},
|
||||
&xscommon.StepUploadVdi{
|
||||
VdiNameFunc: func() string {
|
||||
if len(self.config.ISOUrls) > 0 {
|
||||
return path.Base(self.config.ISOUrls[0])
|
||||
}
|
||||
return ""
|
||||
&xscommon.StepFindOrUploadVdi{
|
||||
xscommon.StepUploadVdi{
|
||||
VdiNameFunc: func() string {
|
||||
if len(self.config.ISOUrls) > 0 {
|
||||
return path.Base(self.config.ISOUrls[0])
|
||||
}
|
||||
return ""
|
||||
},
|
||||
ImagePathFunc: func() string {
|
||||
if isoPath, ok := state.GetOk("iso_path"); ok {
|
||||
return isoPath.(string)
|
||||
}
|
||||
return ""
|
||||
},
|
||||
VdiUuidKey: "iso_vdi_uuid",
|
||||
},
|
||||
ImagePathFunc: func() string {
|
||||
if isoPath, ok := state.GetOk("iso_path"); ok {
|
||||
return isoPath.(string)
|
||||
}
|
||||
return ""
|
||||
},
|
||||
VdiUuidKey: "iso_vdi_uuid",
|
||||
},
|
||||
&xscommon.StepFindVdi{
|
||||
VdiName: self.config.ToolsIsoName,
|
||||
@ -230,7 +239,9 @@ func (self *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (p
|
||||
VdiName: self.config.ISOName,
|
||||
VdiUuidKey: "isoname_vdi_uuid",
|
||||
},
|
||||
new(stepCreateInstance),
|
||||
&xscommon.StepCreateInstance{
|
||||
AssumePreInstalledOS: false,
|
||||
},
|
||||
&xscommon.StepAttachVdi{
|
||||
VdiUuidKey: "floppy_vdi_uuid",
|
||||
VdiType: xsclient.VbdTypeFloppy,
|
||||
@ -279,7 +290,14 @@ func (self *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (p
|
||||
},
|
||||
new(commonsteps.StepProvision),
|
||||
new(xscommon.StepShutdown),
|
||||
new(xscommon.StepSetVmToTemplate),
|
||||
}
|
||||
|
||||
if !self.config.SkipSetTemplate {
|
||||
steps = append(steps,
|
||||
new(xscommon.StepSetVmToTemplate))
|
||||
}
|
||||
|
||||
steps = append(steps,
|
||||
&xscommon.StepDetachVdi{
|
||||
VdiUuidKey: "iso_vdi_uuid",
|
||||
},
|
||||
@ -292,8 +310,7 @@ func (self *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (p
|
||||
&xscommon.StepDetachVdi{
|
||||
VdiUuidKey: "floppy_vdi_uuid",
|
||||
},
|
||||
new(xscommon.StepExport),
|
||||
}
|
||||
new(xscommon.StepExport))
|
||||
|
||||
if self.config.ISOName == "" {
|
||||
steps = append(download_steps, steps...)
|
||||
|
@ -4,22 +4,22 @@ import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/packer-plugin-sdk/common"
|
||||
"github.com/hashicorp/packer-plugin-sdk/packer"
|
||||
)
|
||||
|
||||
func testConfig() map[string]interface{} {
|
||||
return map[string]interface{}{
|
||||
"remote_host": "localhost",
|
||||
"remote_username": "admin",
|
||||
"remote_password": "admin",
|
||||
"vm_name": "foo",
|
||||
"iso_checksum": "foo",
|
||||
"iso_checksum_type": "md5",
|
||||
"iso_url": "http://www.google.com/",
|
||||
"shutdown_command": "yes",
|
||||
"ssh_username": "foo",
|
||||
"remote_host": "localhost",
|
||||
"remote_username": "admin",
|
||||
"remote_password": "admin",
|
||||
"vm_name": "foo",
|
||||
"iso_checksum": "md5:A221725EE181A44C67E25BD6A2516742",
|
||||
"iso_url": "http://www.google.com/",
|
||||
"shutdown_command": "yes",
|
||||
"ssh_username": "foo",
|
||||
|
||||
packer.BuildNameConfigKey: "foo",
|
||||
common.BuildNameConfigKey: "foo",
|
||||
}
|
||||
}
|
||||
|
||||
@ -42,7 +42,7 @@ func TestBuilderPrepare_Defaults(t *testing.T) {
|
||||
t.Fatalf("should not have error: %s", err)
|
||||
}
|
||||
|
||||
if b.config.ToolsIsoName != "xs-tools.iso" {
|
||||
if b.config.ToolsIsoName != "" {
|
||||
t.Errorf("bad tools ISO name: %s", b.config.ToolsIsoName)
|
||||
}
|
||||
|
||||
@ -61,6 +61,10 @@ func TestBuilderPrepare_Defaults(t *testing.T) {
|
||||
if b.config.KeepVM != "never" {
|
||||
t.Errorf("bad keep instance: %s", b.config.KeepVM)
|
||||
}
|
||||
|
||||
if b.config.HostSshPort != 22 {
|
||||
t.Errorf("bad ssh port: %d", b.config.HostSshPort)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuilderPrepare_DiskSize(t *testing.T) {
|
||||
@ -179,64 +183,19 @@ func TestBuilderPrepare_ISOChecksum(t *testing.T) {
|
||||
var b Builder
|
||||
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
|
||||
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)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
@ -245,23 +204,6 @@ func TestBuilderPrepare_ISOChecksumType(t *testing.T) {
|
||||
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) {
|
||||
|
@ -3,7 +3,6 @@ package xva
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/hcl/v2/hcldec"
|
||||
@ -38,11 +37,12 @@ func (self *Builder) Prepare(raws ...interface{}) (params []string, warns []stri
|
||||
}, raws...)
|
||||
|
||||
if err != nil {
|
||||
packer.MultiErrorAppend(errs, err)
|
||||
errs = packer.MultiErrorAppend(errs, err)
|
||||
}
|
||||
|
||||
errs = packer.MultiErrorAppend(
|
||||
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
|
||||
if self.config.VCPUsMax == 0 {
|
||||
@ -74,8 +74,12 @@ func (self *Builder) Prepare(raws ...interface{}) (params []string, warns []stri
|
||||
|
||||
// Validation
|
||||
|
||||
if self.config.SourcePath == "" {
|
||||
errs = packer.MultiErrorAppend(errs, fmt.Errorf("A source_path must be specified"))
|
||||
if self.config.SourcePath == "" && self.config.CloneTemplate == "" {
|
||||
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 {
|
||||
@ -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
|
||||
state := new(multistep.BasicStateBag)
|
||||
state.Put("client", c)
|
||||
// state.Put("config", self.config)
|
||||
state.Put("config", self.config)
|
||||
state.Put("commonconfig", self.config.CommonConfig)
|
||||
state.Put("hook", hook)
|
||||
state.Put("ui", ui)
|
||||
@ -116,8 +120,11 @@ func (self *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (p
|
||||
},
|
||||
&commonsteps.StepCreateFloppy{
|
||||
Files: self.config.FloppyFiles,
|
||||
Label: "cidata",
|
||||
},
|
||||
&xscommon.StepHTTPServer{
|
||||
Chan: httpReqChan,
|
||||
},
|
||||
new(xscommon.StepHTTPServer),
|
||||
&xscommon.StepUploadVdi{
|
||||
VdiNameFunc: func() string {
|
||||
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,
|
||||
VdiUuidKey: "tools_vdi_uuid",
|
||||
},
|
||||
&xscommon.StepCreateInstance{
|
||||
AssumePreInstalledOS: true,
|
||||
},
|
||||
new(stepImportInstance),
|
||||
&xscommon.StepAttachVdi{
|
||||
VdiUuidKey: "floppy_vdi_uuid",
|
||||
@ -153,20 +163,28 @@ func (self *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (p
|
||||
Chan: httpReqChan,
|
||||
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{
|
||||
Config: &self.config.SSHConfig.Comm,
|
||||
Host: xscommon.CommHost,
|
||||
SSHConfig: xscommon.SSHConfigFunc(self.config.CommonConfig.SSHConfig),
|
||||
SSHPort: xscommon.SSHPort,
|
||||
Host: xscommon.InstanceSSHIP,
|
||||
SSHConfig: self.config.Comm.SSHConfigFunc(),
|
||||
SSHPort: xscommon.InstanceSSHPort,
|
||||
},
|
||||
new(commonsteps.StepProvision),
|
||||
new(xscommon.StepShutdown),
|
||||
&xscommon.StepDetachVdi{
|
||||
VdiUuidKey: "floppy_vdi_uuid",
|
||||
},
|
||||
new(xscommon.StepSetVmToTemplate),
|
||||
&xscommon.StepDetachVdi{
|
||||
VdiUuidKey: "tools_vdi_uuid",
|
||||
},
|
||||
&xscommon.StepDetachVdi{
|
||||
VdiUuidKey: "floppy_vdi_uuid",
|
||||
},
|
||||
new(xscommon.StepExport),
|
||||
}
|
||||
|
||||
|
@ -3,6 +3,7 @@ package xva
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/packer-plugin-sdk/common"
|
||||
"github.com/hashicorp/packer-plugin-sdk/packer"
|
||||
)
|
||||
|
||||
@ -16,7 +17,7 @@ func testConfig() map[string]interface{} {
|
||||
"ssh_username": "foo",
|
||||
"source_path": ".",
|
||||
|
||||
packer.BuildNameConfigKey: "foo",
|
||||
common.BuildNameConfigKey: "foo",
|
||||
}
|
||||
}
|
||||
|
||||
@ -39,7 +40,7 @@ func TestBuilderPrepare_Defaults(t *testing.T) {
|
||||
t.Fatalf("should not have error: %s", err)
|
||||
}
|
||||
|
||||
if b.config.ToolsIsoName != "xs-tools.iso" {
|
||||
if b.config.ToolsIsoName != "" {
|
||||
t.Errorf("bad tools ISO name: %s", b.config.ToolsIsoName)
|
||||
}
|
||||
|
||||
@ -54,6 +55,10 @@ func TestBuilderPrepare_Defaults(t *testing.T) {
|
||||
if b.config.KeepVM != "never" {
|
||||
t.Errorf("bad keep instance: %s", b.config.KeepVM)
|
||||
}
|
||||
|
||||
if b.config.HostSshPort != 22 {
|
||||
t.Errorf("bad ssh port: %d", b.config.HostSshPort)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuilderPrepare_Format(t *testing.T) {
|
||||
|
@ -3,6 +3,7 @@ package xva
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"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")
|
||||
|
||||
if config.SourcePath == "" {
|
||||
log.Println("Skipping importing instance - no `source_path` configured.")
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
// find the SR
|
||||
srs, err := c.GetClient().SR.GetAll(c.GetSessionRef())
|
||||
sr := srs[0]
|
||||
@ -80,6 +86,12 @@ func (self *stepImportInstance) Run(ctx context.Context, state multistep.StateBa
|
||||
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))
|
||||
|
||||
return multistep.ActionContinue
|
||||
|
@ -18,7 +18,6 @@ the OS, then shutting it down. The result of the XenServer builder is a
|
||||
directory containing all the files necessary to run the virtual machine
|
||||
portably.
|
||||
|
||||
|
||||
## Configuration Reference
|
||||
|
||||
There are many configuration options available for the XenServer builder.
|
||||
@ -29,21 +28,37 @@ each category, the available options are alphabetized and described.
|
||||
|
||||
* `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
|
||||
to booting a virtual machine with the ISO attached. The type of the
|
||||
checksum is specified with `iso_checksum_type`, documented below.
|
||||
to booting a virtual machine with the ISO attached. The type of
|
||||
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
|
||||
an example 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.
|
||||
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
|
||||
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_ssh_port` (integer) - The port that SSH will be listening on in the Xenserver / XCP-ng pool primary. By default this is 22.
|
||||
|
||||
* `remote_username` (string) - The XenServer username used to access the remote machine.
|
||||
|
||||
@ -59,11 +74,12 @@ each category, the available options are alphabetized and described.
|
||||
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
|
||||
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
|
||||
machine before typing the `boot_command`. The value of this should be
|
||||
a duration. Examples are "5s" and "1m30s" which will cause Packer to wait
|
||||
a duration. Examples are `5s` and `1m30s` which will cause Packer to wait
|
||||
five seconds and one minute 30 seconds, respectively. If this isn't specified,
|
||||
the default is 10 seconds.
|
||||
|
||||
@ -73,9 +89,15 @@ each category, the available options are alphabetized and described.
|
||||
run `xe template-list`. Setting the correct value hints to XenServer how to
|
||||
optimize the virtual hardware to work best with that operating system.
|
||||
|
||||
* `disk_name` (string) - The name of the hard disk to create for the VM.
|
||||
By default, the name is "Packer-disk".
|
||||
|
||||
* `disk_size` (integer) - The size, in megabytes, of the hard disk to create
|
||||
for the VM. By default, this is 40000 (about 40 GB).
|
||||
|
||||
* `firmware` (string) - Whether to use `bios` or `uefi` as the boot firmware
|
||||
for the resulting VM. Defaults to `bios`.
|
||||
|
||||
* `floppy_files` (array of strings) - A list of files to place onto a floppy
|
||||
disk that is attached when the VM is booted. This is most useful
|
||||
for unattended Windows installs, which look for an `Autounattend.xml` file
|
||||
@ -86,15 +108,15 @@ each category, the available options are alphabetized and described.
|
||||
characters (\*, ?, and []) are allowed. Directory names are also allowed,
|
||||
which will add all the files found in the directory to the floppy.
|
||||
|
||||
* `format` (string) - Either "xva", "vdi_raw" or "none", this specifies the
|
||||
* `format` (string) - Either "xva", "xva_compressed", "vdi_raw" or "none", this specifies the
|
||||
output format of the exported virtual machine. This defaults to "xva". Set to
|
||||
"vdi_raw" to export just the raw disk image. Set to "none" to export nothing;
|
||||
this is only useful with "keep_vm" set to "always" or "on_success".
|
||||
|
||||
* `http_directory` (string) - Path to a directory to serve using an HTTP
|
||||
server. The files in this directory will be available over HTTP that will
|
||||
server. The files in this directory will be available over HTTP which will
|
||||
be requestable from the virtual machine. This is useful for hosting
|
||||
kickstart files and so on. By default this is "", which means no HTTP
|
||||
kickstart files and so on. By default, this is `""`, which means no HTTP
|
||||
server will be started. The address and port of the HTTP server will be
|
||||
available as variables in `boot_command`. This is covered in more detail
|
||||
below.
|
||||
@ -104,7 +126,7 @@ each category, the available options are alphabetized and described.
|
||||
Because Packer often runs in parallel, Packer will choose a randomly available
|
||||
port in this range to run the HTTP server. If you want to force the HTTP
|
||||
server to be on one port, make this minimum and maximum port the same.
|
||||
By default the values are 8000 and 9000, respectively.
|
||||
By default, the values are 8000 and 9000, respectively.
|
||||
|
||||
* `install_timeout` (string) - The amount of time to wait after booting the VM
|
||||
for the installer to shut itself down.
|
||||
@ -114,38 +136,55 @@ each category, the available options are alphabetized and described.
|
||||
* `iso_urls` (array of strings) - Multiple URLs for the ISO to download.
|
||||
Packer will try these in order. If anything goes wrong attempting to download
|
||||
or while downloading a single URL, it will move on to the next. All URLs
|
||||
must point to the same file (same checksum). By default this is empty
|
||||
must point to the same file (same checksum). By default, this is empty
|
||||
and `iso_url` is used. Only one of `iso_url` or `iso_urls` can be specified.
|
||||
|
||||
* `tools_iso_name` (string) - Choose the tools iso you want to use.
|
||||
Usually "guest-tools.iso", or "xs-tools.iso". Not setting this variable causes no tools-related
|
||||
ISO to be attached.
|
||||
|
||||
* `keep_vm` (string) - Determine when to keep the VM and when to clean it up. This
|
||||
can be "always", "never" or "on_success". By default this is "never", and Packer
|
||||
can be `always`, `never` or `on_success`. The default is `never`, and Packer
|
||||
always deletes the VM regardless of whether the process succeeded and an artifact
|
||||
was produced. "always" asks Packer to leave the VM at the end of the process
|
||||
regardless of success. "on_success" requests that the VM only be cleaned up if an
|
||||
was produced. `always` asks Packer to leave the VM at the end of the process
|
||||
regardless of success. `on_success` requests that the VM only be cleaned up if an
|
||||
artifact was produced. The latter is useful for debugging templates that fail.
|
||||
|
||||
* `network_names` (array of strings) - A list of networks identified by their name label which
|
||||
* `ip_getter` (string) - Defines the method by which the IP of the guest machine is
|
||||
identified. Options are: `auto`, `tools`, `http`. The default is `auto`, which will
|
||||
attempt both methods. `tools` requires that the guest tools be installed and functional
|
||||
inside the quest machine.
|
||||
|
||||
* `skip_set_template` (bool) - If you want to get the full XVA, to be able to import the VM directly
|
||||
instead of using the output template, you can set this to `true`.
|
||||
|
||||
* `network_names` (array of strings) - A list of networks identified by their name label which
|
||||
will be used for the VM during creation. The first network will correspond to the VM's
|
||||
first network interface (VIF), the second will corespond to the second VIF and so on.
|
||||
first network interface (VIF), the second will correspond to the second VIF and so on.
|
||||
|
||||
* `export_network_names` (array of strings) - A list of networks identified by their name label which
|
||||
will be attached to the export. The first network will correspond to the VM's
|
||||
first network interface (VIF), the second will correspond to the second VIF and so on.
|
||||
|
||||
* `output_directory` (string) - This is the path to the directory where the
|
||||
resulting virtual machine will be created. This may be relative or absolute.
|
||||
If relative, the path is relative to the working directory when `packer`
|
||||
is executed. This directory must not exist or be empty prior to running the builder.
|
||||
By default this is "output-BUILDNAME" where "BUILDNAME" is the name
|
||||
By default, this is "output-BUILDNAME" where "BUILDNAME" is the name
|
||||
of the build.
|
||||
|
||||
* `platform_args` (object of key/value strings) - The platform args.
|
||||
Defaults to
|
||||
```javascript
|
||||
Defaults to
|
||||
|
||||
```json
|
||||
{
|
||||
"viridian": "false",
|
||||
"nx": "true",
|
||||
"pae": "true",
|
||||
"apic": "true",
|
||||
"timeoffset": "0",
|
||||
"acpi": "1",
|
||||
"cores-per-socket": "1"
|
||||
"viridian": "false",
|
||||
"nx": "true",
|
||||
"pae": "true",
|
||||
"apic": "true",
|
||||
"timeoffset": "0",
|
||||
"acpi": "1",
|
||||
"cores-per-socket": "1"
|
||||
}
|
||||
```
|
||||
|
||||
@ -154,6 +193,12 @@ each category, the available options are alphabetized and described.
|
||||
will shut down the VM gracefully through the Xen api's vm shutdown command. Unless
|
||||
you have special requirements this should typically be left to its default.
|
||||
|
||||
* `sr_name` (string) - The SR to use for storing the disk for the VM that Packer
|
||||
creates. By default, the default SR of the system will be used.
|
||||
|
||||
* `sr_iso_name` (string) - The SR to use for uploading the provided ISO.
|
||||
By default, the default SR of the system will be used.
|
||||
|
||||
* `ssh_host_port_min` and `ssh_host_port_max` (integer) - The minimum and
|
||||
maximum port to use for the SSH port on the host machine which is forwarded
|
||||
to the SSH port on the guest machine. Because Packer often runs in parallel,
|
||||
@ -161,46 +206,50 @@ each category, the available options are alphabetized and described.
|
||||
host port.
|
||||
|
||||
* `ssh_key_path` (string) - Path to a private key to use for authenticating
|
||||
with SSH. By default this is not set (key-based auth won't be used).
|
||||
with SSH. By default, this is not set (key-based auth won't be used).
|
||||
The associated public key is expected to already be configured on the
|
||||
VM being prepared by some other process (kickstart, etc.).
|
||||
|
||||
* `ssh_password` (string) - The password for `ssh_username` to use to
|
||||
authenticate with SSH. By default this is the empty string.
|
||||
authenticate with SSH. By default, this is the empty string.
|
||||
|
||||
* `ssh_port` (integer) - The port that SSH will be listening on in the guest
|
||||
virtual machine. By default this is 22.
|
||||
virtual machine. By default, this is `22`.
|
||||
|
||||
* `ssh_wait_timeout` (string) - The duration to wait for SSH to become
|
||||
available. By default this is "20m", or 20 minutes. Note that this should
|
||||
available. By default, this is `20m`, or 20 minutes. **Note**: that this should
|
||||
be quite long since the timer begins as soon as the virtual machine is booted.
|
||||
|
||||
* `tools_iso_name` (string) - The name of the XenServer Tools ISO. Defaults to
|
||||
"xs-tools.iso".
|
||||
`xs-tools.iso`.
|
||||
|
||||
* `vm_description` (string) - The description of the new virtual
|
||||
machine. By default this is the empty string.
|
||||
machine. By default, this is an empty string.
|
||||
|
||||
* `vm_name` (string) - This is the name of the new virtual
|
||||
machine, without the file extension. By default this is
|
||||
"packer-BUILDNAME-TIMESTAMP", where "BUILDNAME" is the name of the build.
|
||||
machine, without the file extension. By default, this is
|
||||
`packer-BUILDNAME-TIMESTAMP`, where "BUILDNAME" is the name of the build.
|
||||
|
||||
* `vcpus_max` (integer) - The maximum number of VCPUs for the VM.
|
||||
By default this is 1.
|
||||
By default, this is `1`.
|
||||
|
||||
* `vcpus_atstartup` (integer) - The number of startup VCPUs for the VM.
|
||||
By default this is 1.
|
||||
By default, this is `1`.
|
||||
|
||||
* `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
|
||||
|
||||
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.
|
||||
|
||||
The builder currently only works remotely.
|
||||
|
||||
The installer is expected to shut down the VM to indicate that it has completed. This is in contrast to other builders, which instead detect completion by a successful SSH connection. The reason for this difference is that currently the builder has no way of knowing what the IP address of the VM is without starting it on the HIMN.
|
||||
The installer is expected to shut down the VM to indicate that it has completed. This is in contrast to other builders,
|
||||
which instead detect completion by a successful SSH connection. The reason for this difference is that currently the
|
||||
builder has no way of knowing what the IP address of the VM is without starting it on the HIMN.
|
||||
|
||||
## Boot Command
|
||||
|
||||
@ -213,8 +262,8 @@ As documented above, the `boot_command` is an array of strings. The
|
||||
strings are all typed in sequence. It is an array only to improve readability
|
||||
within the template.
|
||||
|
||||
The boot command is "typed" character for character over a VNC connection
|
||||
to the machine, simulating a human actually typing the keyboard. There are
|
||||
The boot command is "typed" character by character over a VNC connection
|
||||
to the machine, simulating a human actually typing on the keyboard. There are
|
||||
a set of special keys available. If these are in your boot command, they
|
||||
will be replaced by the proper key:
|
||||
|
||||
@ -245,6 +294,7 @@ will be replaced by the proper key:
|
||||
|
||||
In addition to the special keys, each command to type is treated as a
|
||||
configuration template.
|
||||
|
||||
The available variables are:
|
||||
|
||||
* `HTTPIP` and `HTTPPort` - The IP and port, respectively of an HTTP server
|
||||
@ -252,4 +302,4 @@ The available variables are:
|
||||
configuration parameter. If `http_directory` isn't specified, these will be
|
||||
blank!
|
||||
|
||||
See the [examples](../../examples/) for working boot commands.
|
||||
See the [examples](../../../examples) for working boot commands.
|
||||
|
@ -1,7 +1,7 @@
|
||||
packer {
|
||||
required_plugins {
|
||||
xenserver= {
|
||||
version = ">= v0.3.2"
|
||||
version = ">= v0.6.0"
|
||||
source = "github.com/ddelnano/xenserver"
|
||||
}
|
||||
}
|
||||
@ -47,8 +47,7 @@ locals {
|
||||
}
|
||||
|
||||
source "xenserver-iso" "centos8-local" {
|
||||
iso_checksum = "aaf9d4b3071c16dbbda01dfe06085e5d0fdac76df323e3bbe87cce4318052247"
|
||||
iso_checksum_type = "sha1"
|
||||
iso_checksum = "sha1:aaf9d4b3071c16dbbda01dfe06085e5d0fdac76df323e3bbe87cce4318052247"
|
||||
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
|
||||
|
@ -1,7 +1,7 @@
|
||||
packer {
|
||||
required_plugins {
|
||||
xenserver= {
|
||||
version = ">= v0.3.2"
|
||||
version = ">= v0.6.0"
|
||||
source = "github.com/ddelnano/xenserver"
|
||||
}
|
||||
}
|
||||
@ -47,8 +47,7 @@ locals {
|
||||
}
|
||||
|
||||
source "xenserver-iso" "centos8-netinstall" {
|
||||
iso_checksum = "07a8e59c42cc086ec4c49bdce4fae5a17b077dea"
|
||||
iso_checksum_type = "sha1"
|
||||
iso_checksum = "sha1:07a8e59c42cc086ec4c49bdce4fae5a17b077dea"
|
||||
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
|
||||
|
@ -1,4 +1,13 @@
|
||||
#cloud-config
|
||||
|
||||
# hack for cloud-init per:
|
||||
# https://github.com/leakespeake/packer/blob/3f3e361751b4be9326b66771d96f2519bc8f885e/builders/vmware/vsphere-iso/ubuntu-server-20-04/hcl2/http/ubuntu-server-subiquity/user-data
|
||||
runcmd:
|
||||
# to enable true auto-install for Ubuntu 20.04 with cloud-init nocloud (eliminates "Continue with autoinstall?" prompt)
|
||||
- [eval, 'echo $(cat /proc/cmdline) "autoinstall" > /root/cmdline']
|
||||
- [eval, 'mount -n --bind -o ro /root/cmdline /proc/cmdline']
|
||||
- [eval, 'snap restart subiquity.subiquity-service']
|
||||
|
||||
autoinstall:
|
||||
version: 1
|
||||
identity:
|
||||
@ -6,6 +15,8 @@ autoinstall:
|
||||
# This is the crypted pass of 'ubuntu'
|
||||
password: "$6$exDY1mhS4KUYCE/2$zmn9ToZwTKLhCw.b4/b.ZRTIZM30JZ4QrOQ2aOXJ8yk96xpcCof0kxKwuX1kqLG/ygbJ1f8wxED22bTL4F46P0"
|
||||
username: testuser
|
||||
packages:
|
||||
- xe-guest-utilities
|
||||
ssh:
|
||||
install-server: yes
|
||||
allow-pw: yes
|
||||
|
@ -1,12 +1,43 @@
|
||||
packer {
|
||||
required_plugins {
|
||||
xenserver= {
|
||||
version = ">= v0.3.2"
|
||||
version = ">= v0.5.2"
|
||||
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" {
|
||||
type = string
|
||||
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"
|
||||
}
|
||||
|
||||
locals {
|
||||
timestamp = regex_replace(timestamp(), "[- TZ:]", "")
|
||||
}
|
||||
|
||||
|
||||
source "xenserver-iso" "ubuntu-2004" {
|
||||
iso_checksum = "d1f2bf834bbe9bb43faf16f9be992a6f3935e65be0edece1dee2aa6eb1767423"
|
||||
iso_checksum_type = "sha256"
|
||||
iso_url = "http://releases.ubuntu.com/20.04/ubuntu-20.04.2-live-server-amd64.iso"
|
||||
iso_checksum = "sha256:${local.ubuntu_sha256.0}"
|
||||
iso_url = "https://releases.ubuntu.com/${local.ubuntu_version}/ubuntu-${local.ubuntu_version}.${local.ubuntu_url_path.0}-live-server-amd64.iso"
|
||||
|
||||
sr_iso_name = var.sr_iso_name
|
||||
sr_name = var.sr_name
|
||||
@ -60,17 +85,17 @@ source "xenserver-iso" "ubuntu-2004" {
|
||||
remote_password = var.remote_password
|
||||
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_memory = 4096
|
||||
disk_size = 20000
|
||||
disk_size = 30720
|
||||
|
||||
http_directory = "examples/http/ubuntu-2004"
|
||||
boot_command = [
|
||||
"<esc><f6> autoinstall ds=nocloud-net;s=http://{{ .HTTPIP }}:{{ .HTTPPort }}/<enter><wait>",
|
||||
"<f6><wait><esc><wait> autoinstall ds=nocloud-net;s=http://{{ .HTTPIP }}:{{ .HTTPPort }}/<enter><wait>"
|
||||
floppy_files = [
|
||||
"examples/http/ubuntu-2004/meta-data",
|
||||
"examples/http/ubuntu-2004/user-data",
|
||||
]
|
||||
boot_wait = "10s"
|
||||
|
||||
ssh_username = "testuser"
|
||||
ssh_password = "ubuntu"
|
||||
@ -83,4 +108,4 @@ source "xenserver-iso" "ubuntu-2004" {
|
||||
|
||||
build {
|
||||
sources = ["xenserver-iso.ubuntu-2004"]
|
||||
}
|
||||
}
|
||||
|
105
go.mod
105
go.mod
@ -1,15 +1,104 @@
|
||||
module github.com/xenserver/packer-builder-xenserver
|
||||
|
||||
go 1.16
|
||||
go 1.20
|
||||
|
||||
require (
|
||||
github.com/amfranz/go-xmlrpc-client v0.0.0-20190612172737-76858463955d
|
||||
github.com/hashicorp/hcl/v2 v2.8.0
|
||||
github.com/hashicorp/packer-plugin-sdk v0.1.0
|
||||
github.com/hashicorp/hcl/v2 v2.20.1
|
||||
github.com/hashicorp/packer-plugin-sdk v0.3.0
|
||||
github.com/mitchellh/go-vnc v0.0.0-20150629162542-723ed9867aed
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect
|
||||
github.com/terra-farm/go-xen-api-client v0.0.1
|
||||
github.com/zclconf/go-cty v1.7.0
|
||||
golang.org/x/crypto v0.0.0-20201208171446-5f87f3452ae9
|
||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect
|
||||
github.com/terra-farm/go-xen-api-client v0.0.2
|
||||
github.com/zclconf/go-cty v1.14.4
|
||||
golang.org/x/crypto v0.24.0
|
||||
)
|
||||
|
||||
require (
|
||||
cloud.google.com/go v0.110.0 // indirect
|
||||
cloud.google.com/go/compute v1.19.1 // indirect
|
||||
cloud.google.com/go/compute/metadata v0.2.3 // indirect
|
||||
cloud.google.com/go/iam v0.13.0 // indirect
|
||||
cloud.google.com/go/storage v1.28.1 // indirect
|
||||
github.com/Azure/go-ntlmssp v0.0.0-20200615164410-66371956d46c // indirect
|
||||
github.com/ChrisTrenkamp/goxpath v0.0.0-20210404020558-97928f7e12b6 // indirect
|
||||
github.com/agext/levenshtein v1.2.3 // indirect
|
||||
github.com/apparentlymart/go-textseg/v13 v13.0.0 // indirect
|
||||
github.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect
|
||||
github.com/armon/go-metrics v0.3.9 // indirect
|
||||
github.com/aws/aws-sdk-go v1.40.34 // indirect
|
||||
github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d // indirect
|
||||
github.com/cenkalti/backoff/v3 v3.2.2 // indirect
|
||||
github.com/dylanmei/iso8601 v0.1.0 // indirect
|
||||
github.com/fatih/color v1.12.0 // indirect
|
||||
github.com/gofrs/flock v0.8.1 // indirect
|
||||
github.com/gofrs/uuid v4.0.0+incompatible // indirect
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
||||
github.com/golang/protobuf v1.5.3 // indirect
|
||||
github.com/golang/snappy v0.0.4 // indirect
|
||||
github.com/google/go-cmp v0.6.0 // indirect
|
||||
github.com/google/uuid v1.3.0 // indirect
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.2.3 // indirect
|
||||
github.com/googleapis/gax-go/v2 v2.7.1 // indirect
|
||||
github.com/hashicorp/consul/api v1.10.1 // indirect
|
||||
github.com/hashicorp/errwrap v1.1.0 // indirect
|
||||
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
|
||||
github.com/hashicorp/go-getter/gcs/v2 v2.1.0 // indirect
|
||||
github.com/hashicorp/go-getter/s3/v2 v2.1.0 // indirect
|
||||
github.com/hashicorp/go-getter/v2 v2.1.0 // indirect
|
||||
github.com/hashicorp/go-hclog v0.16.2 // indirect
|
||||
github.com/hashicorp/go-immutable-radix v1.3.1 // indirect
|
||||
github.com/hashicorp/go-multierror v1.1.1 // indirect
|
||||
github.com/hashicorp/go-retryablehttp v0.7.0 // indirect
|
||||
github.com/hashicorp/go-rootcerts v1.0.2 // indirect
|
||||
github.com/hashicorp/go-safetemp v1.0.0 // indirect
|
||||
github.com/hashicorp/go-sockaddr v1.0.2 // indirect
|
||||
github.com/hashicorp/go-version v1.3.0 // indirect
|
||||
github.com/hashicorp/golang-lru v0.5.4 // indirect
|
||||
github.com/hashicorp/hcl v1.0.0 // indirect
|
||||
github.com/hashicorp/serf v0.9.5 // indirect
|
||||
github.com/hashicorp/vault/api v1.1.1 // indirect
|
||||
github.com/hashicorp/vault/sdk v0.2.1 // indirect
|
||||
github.com/hashicorp/yamux v0.0.0-20210826001029-26ff87cf9493 // indirect
|
||||
github.com/jehiah/go-strftime v0.0.0-20171201141054-1d33003b3869 // indirect
|
||||
github.com/jmespath/go-jmespath v0.4.0 // indirect
|
||||
github.com/kr/fs v0.1.0 // indirect
|
||||
github.com/masterzen/simplexml v0.0.0-20190410153822-31eea3082786 // indirect
|
||||
github.com/masterzen/winrm v0.0.0-20210623064412-3b76017826b0 // indirect
|
||||
github.com/mattn/go-colorable v0.1.8 // indirect
|
||||
github.com/mattn/go-isatty v0.0.13 // indirect
|
||||
github.com/mitchellh/go-fs v0.0.0-20180402235330-b7b9ca407fff // indirect
|
||||
github.com/mitchellh/go-homedir v1.1.0 // indirect
|
||||
github.com/mitchellh/go-testing-interface v1.14.1 // indirect
|
||||
github.com/mitchellh/go-wordwrap v1.0.1 // indirect
|
||||
github.com/mitchellh/iochan v1.0.0 // indirect
|
||||
github.com/mitchellh/mapstructure v1.4.1 // indirect
|
||||
github.com/mitchellh/reflectwalk v1.0.0 // indirect
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect
|
||||
github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d // indirect
|
||||
github.com/packer-community/winrmcp v0.0.0-20180921211025-c76d91c1e7db // indirect
|
||||
github.com/pierrec/lz4 v2.6.1+incompatible // indirect
|
||||
github.com/pkg/sftp v1.13.2 // indirect
|
||||
github.com/ryanuber/go-glob v1.0.0 // indirect
|
||||
github.com/ugorji/go/codec v1.2.6 // indirect
|
||||
github.com/ulikunitz/xz v0.5.10 // indirect
|
||||
go.opencensus.io v0.24.0 // indirect
|
||||
golang.org/x/mod v0.17.0 // indirect
|
||||
golang.org/x/net v0.25.0 // indirect
|
||||
golang.org/x/oauth2 v0.7.0 // indirect
|
||||
golang.org/x/sync v0.7.0 // indirect
|
||||
golang.org/x/sys v0.21.0 // indirect
|
||||
golang.org/x/term v0.21.0 // indirect
|
||||
golang.org/x/text v0.16.0 // indirect
|
||||
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac // indirect
|
||||
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect
|
||||
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
|
||||
google.golang.org/api v0.114.0 // indirect
|
||||
google.golang.org/appengine v1.6.7 // indirect
|
||||
google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect
|
||||
google.golang.org/grpc v1.56.3 // indirect
|
||||
google.golang.org/protobuf v1.33.0 // indirect
|
||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect
|
||||
gopkg.in/square/go-jose.v2 v2.6.0 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
)
|
||||
|
||||
replace github.com/zclconf/go-cty => github.com/nywilken/go-cty v1.13.3 // added by packer-sdc fix as noted in github.com/hashicorp/packer-plugin-sdk/issues/187
|
||||
|
18
main.go
18
main.go
@ -6,30 +6,16 @@ import (
|
||||
|
||||
"github.com/xenserver/packer-builder-xenserver/builder/xenserver/iso"
|
||||
"github.com/xenserver/packer-builder-xenserver/builder/xenserver/xva"
|
||||
"github.com/xenserver/packer-builder-xenserver/version"
|
||||
|
||||
"github.com/hashicorp/packer-plugin-sdk/plugin"
|
||||
"github.com/hashicorp/packer-plugin-sdk/version"
|
||||
)
|
||||
|
||||
var (
|
||||
// Version is the main version number that is being run at the moment.
|
||||
Version = "v0.3.0"
|
||||
|
||||
// VersionPrerelease is A pre-release marker for the Version. If this is ""
|
||||
// (empty string) then it means that it is a final release. Otherwise, this
|
||||
// is a pre-release such as "dev" (in development), "beta", "rc1", etc.
|
||||
VersionPrerelease = ""
|
||||
|
||||
// PluginVersion is used by the plugin set to allow Packer to recognize
|
||||
// what version this plugin is.
|
||||
PluginVersion = version.InitializePluginVersion(Version, VersionPrerelease)
|
||||
)
|
||||
|
||||
func main() {
|
||||
pps := plugin.NewSet()
|
||||
pps.RegisterBuilder("iso", new(iso.Builder))
|
||||
pps.RegisterBuilder("xva", new(xva.Builder))
|
||||
pps.SetVersion(PluginVersion)
|
||||
pps.SetVersion(version.PluginVersion)
|
||||
err := pps.Run()
|
||||
if err != nil {
|
||||
fmt.Fprintln(os.Stderr, err.Error())
|
||||
|
@ -1,6 +0,0 @@
|
||||
{
|
||||
"builders": [{
|
||||
"type": "xenserver-iso",
|
||||
"tools_iso_name": "guest-tools.iso"
|
||||
}]
|
||||
}
|
19
version/version.go
Normal file
19
version/version.go
Normal file
@ -0,0 +1,19 @@
|
||||
package version
|
||||
|
||||
import (
|
||||
"github.com/hashicorp/packer-plugin-sdk/version"
|
||||
)
|
||||
|
||||
var (
|
||||
// Version is the main version number that is being run at the moment.
|
||||
Version = "v0.6.0"
|
||||
|
||||
// VersionPrerelease is A pre-release marker for the Version. If this is ""
|
||||
// (empty string) then it means that it is a final release. Otherwise, this
|
||||
// is a pre-release such as "dev" (in development), "beta", "rc1", etc.
|
||||
VersionPrerelease = "dev"
|
||||
|
||||
// PluginVersion is used by the plugin set to allow Packer to recognize
|
||||
// what version this plugin is.
|
||||
PluginVersion = version.InitializePluginVersion(Version, VersionPrerelease)
|
||||
)
|
Loading…
Reference in New Issue
Block a user