Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add support for vmrest #161

Closed
wants to merge 24 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 69 additions & 3 deletions .web-docs/components/builder/vmx/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
Type: `vmware-vmx`
Artifact BuilderId: `mitchellh.vmware`
If remote_type is esx: Artifact BuilderId: `mitchellh.vmware-esx`
If remote_type is vmrest: Artifact BuilderId: `niwamo.vmware-vmrest`

This VMware Packer builder is able to create VMware virtual machines from an
existing VMware virtual machine (a VMX file). It currently supports building
Expand Down Expand Up @@ -1065,12 +1066,18 @@ Ubuntu 12.04 installer:
For more examples of various boot commands, see the sample projects from our
[community templates page](/community-tools#templates).

## Building on a Remote vSphere Hypervisor
## Remote Builds

In addition to using the desktop products of VMware locally to build virtual
machines, Packer can use a remote VMware Hypervisor to build the virtual
machine.

Packer supports two remote build types:
- ESXi 5.1 and above
- the VMware Workstation Pro API (tested on v1.3.1)

### Building on a Remote vSphere Hypervisor

-> **Note:** Packer supports ESXi 5.1 and above.

Before using a remote vSphere Hypervisor, you need to enable GuestIPHack by
Expand All @@ -1083,7 +1090,8 @@ $ esxcli system settings advanced set -o /Net/GuestIPHack -i 1
When using a remote VMware Hypervisor, the builder still downloads the ISO and
various files locally, and uploads these to the remote machine. Packer currently
uses SSH to communicate to the ESXi machine rather than the vSphere API.
If you want to use vSphere API, see the [vsphere-iso](/packer/integrations/hashicorp/vsphere/latest/components/builder/vsphere-iso) builder.
If you want to use vSphere API, see the
[vsphere-iso](/packer/integrations/hashicorp/vsphere/latest/components/builder/vsphere-iso) builder.

Packer also requires VNC to issue boot commands during a build, which may be
disabled on some remote VMware Hypervisors. Please consult the appropriate
Expand Down Expand Up @@ -1132,7 +1140,65 @@ Since ovftool is only capable of password based authentication
- `vnc_disable_password` - This must be set to "true" when using VNC with
ESXi 6.5 or 6.7.

### SSH key pair automation
### Building with the VMware Workstation Pro API (vmrest)

VMware Workstation Pro ships with a 'vmrest' executable enabling programmatic
access via a REST API. The API does not run automatically or as a service by
default. The API is also limited in its functionality and does not support:
- the vmware-iso builder
- creating new virtual machines "from scratch" (it does support cloning)
- creating or modifying disks
- installing VMware Tools
- taking snapshots

To use the VMware Workstation Pro API with the vmware-vmx builder:
- Set the API credentials
- On Windows: `& 'C:\Program Files (x86)\VMware\VMware Workstation\vmrest.exe' -C`
- Run the API executable
- On Windows: `& 'C:\Program Files (x86)\VMware\VMware Workstation\vmrest.exe'`
- Validate connectivity between the host running Packer and the API
- Run Packer with a valid vmware-vmx configuration

Required Configuration Parameters:

- `remote_type` - This must be set to "vmrest".

- `remote_username` - The username set for API authentication

- `remote_password` - The password set for API authentication

- `skip_export` - This must be set to `false`. The vmrest driver does not support
exports.

Optional Configuration Parameters:

- `remote_host` - The hostname or IP (preferred) of the machine running the API.
Defaults to "127.0.0.1" if not provided.

- `remote_port` - The port the API is listening on. Defaults to "8697" if not
provided.

Ignored Configuration Parameters:

- All `remote_*` parameters not described in the previous two sections are ignored.

- `output_directory`. VMware will place the cloned VM in the system's default VM
location (typically `~/Documents/Virtual Machines`).

- `keep_registered`. The driver will leave all VMs registered.

- `linked`. The driver only supports 'full' clones.

Unsupported Parameters:

- All `tools_*` parameters (the API does not support installing VMware Tools)

- `vnc_over_websocket` cannot be set to true.

- `attach_snapshot` and `snapshot_name` - the API does not support snapshot
operations

## SSH key pair automation

The VMware builders can inject the current SSH key pair's public key into
the template using the `SSHPublicKey` template engine. This is the SSH public
Expand Down
10 changes: 7 additions & 3 deletions builder/vmware/common/artifact.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,9 @@ import (

const (
// BuilderId for the local artifacts
BuilderId = "mitchellh.vmware"
BuilderIdESX = "mitchellh.vmware-esx"
BuilderId = "mitchellh.vmware"
BuilderIdESX = "mitchellh.vmware-esx"
BuilderIdVMRest = "niwamo.vmware-vmrest"

ArtifactConfFormat = "artifact.conf.format"
ArtifactConfKeepRegistered = "artifact.conf.keep_registered"
Expand Down Expand Up @@ -82,8 +83,11 @@ func NewArtifact(remoteType string, format string, exportOutputPath string, vmNa

// Set the proper builder ID
builderId := BuilderId
if remoteType != "" {
switch remoteType {
case "esx5":
builderId = BuilderIdESX
case "vmrest":
builderId = BuilderIdVMRest
}

config := make(map[string]string)
Expand Down
18 changes: 13 additions & 5 deletions builder/vmware/common/driver.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,12 +98,20 @@ func NewDriver(dconfig *DriverConfig, config *SSHConfig, vmName string) (Driver,
var drivers []Driver

if dconfig.RemoteType != "" {
esx5Driver, err := NewESX5Driver(dconfig, config, vmName)
if err != nil {
return nil, err
switch dconfig.RemoteType {
case "esx5":
esx5Driver, err := NewESX5Driver(dconfig, config, vmName)
if err != nil {
return nil, err
}
drivers = []Driver{esx5Driver}
case "vmrest":
vmrestDriver, err := NewVMRestDriver(dconfig, config, vmName)
if err != nil {
return nil, err
}
drivers = []Driver{vmrestDriver}
}
drivers = []Driver{esx5Driver}

} else {
switch runtime.GOOS {
case "darwin":
Expand Down
65 changes: 45 additions & 20 deletions builder/vmware/common/driver_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ package common

import (
"fmt"
"log"
"os"

"github.com/hashicorp/packer-plugin-sdk/template/interpolate"
Expand Down Expand Up @@ -63,31 +64,55 @@ func (c *DriverConfig) Prepare(ctx *interpolate.Context) []error {
if c.FusionAppPath == "" {
c.FusionAppPath = "/Applications/VMware Fusion.app"
}
if c.RemoteUser == "" {
c.RemoteUser = "root"
}
if c.RemoteDatastore == "" {
c.RemoteDatastore = "datastore1"
}
if c.RemoteCacheDatastore == "" {
c.RemoteCacheDatastore = c.RemoteDatastore
}
if c.RemoteCacheDirectory == "" {
c.RemoteCacheDirectory = "packer_cache"
}
if c.RemotePort == 0 {
c.RemotePort = 22
}

if c.RemoteType != "" {
if c.RemoteHost == "" {
if c.RemoteType != "esx5" && c.RemoteType != "vmrest" {
errs = append(errs,
fmt.Errorf("remote_host must be specified"))
fmt.Errorf("Only the values 'esx5' or 'vmrest' are accepted for remote_type"))
}

if c.RemoteType != "esx5" {
errs = append(errs,
fmt.Errorf("Only 'esx5' value is accepted for remote_type"))
if c.RemoteType == "esx5" {
// we should only set exs5-relevant default values if esx5 is selected
if c.RemoteHost == "" {
errs = append(errs,
fmt.Errorf("remote_host must be specified"))
}

if c.RemoteUser == "" {
c.RemoteUser = "root"
}
if c.RemoteDatastore == "" {
c.RemoteDatastore = "datastore1"
}
if c.RemoteCacheDatastore == "" {
c.RemoteCacheDatastore = c.RemoteDatastore
}
if c.RemoteCacheDirectory == "" {
c.RemoteCacheDirectory = "packer_cache"
}
if c.RemotePort == 0 {
c.RemotePort = 22
}
}

if c.RemoteType == "vmrest" {
if c.RemoteHost == "" {
log.Print("Warning: Remote host not set. Defaulting to localhost.")
c.RemoteHost = "127.0.0.1"
}

if c.RemotePort == 0 {
log.Print("Warning: Remote port not set. Defaulting to 8697.")
c.RemotePort = 8697
}

if c.RemoteUser == "" {
errs = append(errs, fmt.Errorf("remote_username must be specified"))
}

if c.RemotePassword == "" {
errs = append(errs, fmt.Errorf("remote_password must be specified"))
}
}
}

Expand Down
12 changes: 6 additions & 6 deletions builder/vmware/common/driver_config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,11 @@ func TestDriverConfigPrepare(t *testing.T) {
config: new(DriverConfig),
expectedConfig: &DriverConfig{
FusionAppPath: "/Applications/VMware Fusion.app",
RemoteDatastore: "datastore1",
RemoteCacheDatastore: "datastore1",
RemoteCacheDirectory: "packer_cache",
RemotePort: 22,
RemoteUser: "root",
RemoteDatastore: "",
RemoteCacheDatastore: "",
RemoteCacheDirectory: "",
RemotePort: 0,
RemoteUser: "",
},
errs: nil,
},
Expand Down Expand Up @@ -59,7 +59,7 @@ func TestDriverConfigPrepare(t *testing.T) {
RemoteHost: "host",
},
expectedConfig: nil,
errs: []error{fmt.Errorf("Only 'esx5' value is accepted for remote_type")},
errs: []error{fmt.Errorf("Only the values 'esx5' or 'vmrest' are accepted for remote_type")},
},
{
name: "Remote host not set",
Expand Down
Loading