Compare commits
36 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 28c7d09630 | |||
| 75cb9a2fa4 | |||
| b4ebbbca6d | |||
| 7d5df873df | |||
| 64ca82293c | |||
| 12db775411 | |||
| 8b491ec8cf | |||
| 4ae26a13b1 | |||
| f026b409f4 | |||
| 252a774572 | |||
| a32c433156 | |||
| bfcfb98398 | |||
| 1b20d9617f | |||
| 4586c4c575 | |||
| 8e39636515 | |||
| 679dca9a72 | |||
| 511b4954a6 | |||
| 31f4b94e13 | |||
| b8df98f0bd | |||
| b49876d1f5 | |||
| a40ff611e4 | |||
| 920f96e2e8 | |||
| 7f1597d140 | |||
| 514d8d88da | |||
| e8780bf7b8 | |||
| 3b0226d496 | |||
| 4c08789642 | |||
| 634bf87d99 | |||
| d566419c45 | |||
| cce1f5c1e3 | |||
| 7f26429a2a | |||
| d81c02b456 | |||
| 794e83b171 | |||
| 58fb58c2ea | |||
| fb04fa7a25 | |||
| 830140157d |
@@ -1,5 +1,17 @@
|
||||
## 1.7.2 (Upcoming)
|
||||
|
||||
### IMPROVEMENTS:
|
||||
|
||||
* builder/alicloud: Add `ramrole` configuration to ECS instance. [GH-10845]
|
||||
|
||||
### BUG FIXES:
|
||||
|
||||
* builder/proxmox: Update Proxmox Go API to ensure only the first non-loopback
|
||||
IPv4 address gets returned. [GH-10858]
|
||||
* builder/vsphere: Fix primary disk resize on clone. [GH-10848]
|
||||
* core: Fix bug where call to "packer version" sent output to stderr instead of
|
||||
stdout. [GH-10850]
|
||||
|
||||
## 1.7.1 (March 31, 2021)
|
||||
|
||||
### NOTES:
|
||||
|
||||
@@ -135,6 +135,7 @@ func (b *Builder) Run(ctx context.Context, ui packersdk.Ui, hook packersdk.Hook)
|
||||
InstanceType: b.config.InstanceType,
|
||||
UserData: b.config.UserData,
|
||||
UserDataFile: b.config.UserDataFile,
|
||||
RamRoleName: b.config.RamRoleName,
|
||||
RegionId: b.config.AlicloudRegion,
|
||||
InternetChargeType: b.config.InternetChargeType,
|
||||
InternetMaxBandwidthOut: b.config.InternetMaxBandwidthOut,
|
||||
|
||||
@@ -88,6 +88,7 @@ type FlatConfig struct {
|
||||
AlicloudSourceImage *string `mapstructure:"source_image" required:"true" cty:"source_image" hcl:"source_image"`
|
||||
ForceStopInstance *bool `mapstructure:"force_stop_instance" required:"false" cty:"force_stop_instance" hcl:"force_stop_instance"`
|
||||
DisableStopInstance *bool `mapstructure:"disable_stop_instance" required:"false" cty:"disable_stop_instance" hcl:"disable_stop_instance"`
|
||||
RamRoleName *string `mapstructure:"ram_role_name" required:"false" cty:"ram_role_name" hcl:"ram_role_name"`
|
||||
SecurityGroupId *string `mapstructure:"security_group_id" required:"false" cty:"security_group_id" hcl:"security_group_id"`
|
||||
SecurityGroupName *string `mapstructure:"security_group_name" required:"false" cty:"security_group_name" hcl:"security_group_name"`
|
||||
UserData *string `mapstructure:"user_data" required:"false" cty:"user_data" hcl:"user_data"`
|
||||
@@ -205,6 +206,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
|
||||
"source_image": &hcldec.AttrSpec{Name: "source_image", Type: cty.String, Required: false},
|
||||
"force_stop_instance": &hcldec.AttrSpec{Name: "force_stop_instance", Type: cty.Bool, Required: false},
|
||||
"disable_stop_instance": &hcldec.AttrSpec{Name: "disable_stop_instance", Type: cty.Bool, Required: false},
|
||||
"ram_role_name": &hcldec.AttrSpec{Name: "ram_role_name", Type: cty.String, Required: false},
|
||||
"security_group_id": &hcldec.AttrSpec{Name: "security_group_id", Type: cty.String, Required: false},
|
||||
"security_group_name": &hcldec.AttrSpec{Name: "security_group_name", Type: cty.String, Required: false},
|
||||
"user_data": &hcldec.AttrSpec{Name: "user_data", Type: cty.String, Required: false},
|
||||
|
||||
@@ -47,6 +47,8 @@ type RunConfig struct {
|
||||
// E.g., Sysprep a windows which may shutdown the instance within its command.
|
||||
// The default value is false.
|
||||
DisableStopInstance bool `mapstructure:"disable_stop_instance" required:"false"`
|
||||
// Ram Role to apply when launching the instance.
|
||||
RamRoleName string `mapstructure:"ram_role_name" required:"false"`
|
||||
// ID of the security group to which a newly
|
||||
// created instance belongs. Mutual access is allowed between instances in one
|
||||
// security group. If not specified, the newly created instance will be added
|
||||
|
||||
@@ -23,6 +23,7 @@ type stepCreateAlicloudInstance struct {
|
||||
UserData string
|
||||
UserDataFile string
|
||||
instanceId string
|
||||
RamRoleName string
|
||||
RegionId string
|
||||
InternetChargeType string
|
||||
InternetMaxBandwidthOut int
|
||||
@@ -115,6 +116,7 @@ func (s *stepCreateAlicloudInstance) buildCreateInstanceRequest(state multistep.
|
||||
request.RegionId = s.RegionId
|
||||
request.InstanceType = s.InstanceType
|
||||
request.InstanceName = s.InstanceName
|
||||
request.RamRoleName = s.RamRoleName
|
||||
request.ZoneId = s.ZoneId
|
||||
|
||||
sourceImage := state.Get("source_image").(*ecs.Image)
|
||||
|
||||
@@ -158,6 +158,9 @@ func getVMIP(state multistep.StateBag) (string, error) {
|
||||
if addr.IsLoopback() {
|
||||
continue
|
||||
}
|
||||
if addr.To4() == nil {
|
||||
continue
|
||||
}
|
||||
return addr.String(), nil
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,7 +75,7 @@ type StepCloneVM struct {
|
||||
|
||||
func (s *StepCloneVM) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
|
||||
ui := state.Get("ui").(packersdk.Ui)
|
||||
d := state.Get("driver").(*driver.VCenterDriver)
|
||||
d := state.Get("driver").(driver.Driver)
|
||||
vmPath := path.Join(s.Location.Folder, s.Location.VMName)
|
||||
|
||||
err := d.PreCleanVM(ui, vmPath, s.Force)
|
||||
@@ -102,17 +102,18 @@ func (s *StepCloneVM) Run(ctx context.Context, state multistep.StateBag) multist
|
||||
}
|
||||
|
||||
vm, err := template.Clone(ctx, &driver.CloneConfig{
|
||||
Name: s.Location.VMName,
|
||||
Folder: s.Location.Folder,
|
||||
Cluster: s.Location.Cluster,
|
||||
Host: s.Location.Host,
|
||||
ResourcePool: s.Location.ResourcePool,
|
||||
Datastore: s.Location.Datastore,
|
||||
LinkedClone: s.Config.LinkedClone,
|
||||
Network: s.Config.Network,
|
||||
MacAddress: s.Config.MacAddress,
|
||||
Annotation: s.Config.Notes,
|
||||
VAppProperties: s.Config.VAppConfig.Properties,
|
||||
Name: s.Location.VMName,
|
||||
Folder: s.Location.Folder,
|
||||
Cluster: s.Location.Cluster,
|
||||
Host: s.Location.Host,
|
||||
ResourcePool: s.Location.ResourcePool,
|
||||
Datastore: s.Location.Datastore,
|
||||
LinkedClone: s.Config.LinkedClone,
|
||||
Network: s.Config.Network,
|
||||
MacAddress: s.Config.MacAddress,
|
||||
Annotation: s.Config.Notes,
|
||||
VAppProperties: s.Config.VAppConfig.Properties,
|
||||
PrimaryDiskSize: s.Config.DiskSize,
|
||||
StorageConfig: driver.StorageConfig{
|
||||
DiskControllerType: s.Config.StorageConfig.DiskControllerType,
|
||||
Storage: disks,
|
||||
@@ -127,14 +128,6 @@ func (s *StepCloneVM) Run(ctx context.Context, state multistep.StateBag) multist
|
||||
}
|
||||
state.Put("vm", vm)
|
||||
|
||||
if s.Config.DiskSize > 0 {
|
||||
err = vm.ResizeDisk(s.Config.DiskSize)
|
||||
if err != nil {
|
||||
state.Put("error", err)
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
}
|
||||
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,251 @@
|
||||
package clone
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"path"
|
||||
"testing"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/hashicorp/packer-plugin-sdk/multistep"
|
||||
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
|
||||
"github.com/hashicorp/packer/builder/vsphere/common"
|
||||
"github.com/hashicorp/packer/builder/vsphere/driver"
|
||||
)
|
||||
|
||||
func TestCreateConfig_Prepare(t *testing.T) {
|
||||
tc := []struct {
|
||||
name string
|
||||
config *CloneConfig
|
||||
fail bool
|
||||
expectedErrMsg string
|
||||
}{
|
||||
{
|
||||
name: "Valid config",
|
||||
config: &CloneConfig{
|
||||
Template: "template name",
|
||||
StorageConfig: common.StorageConfig{
|
||||
DiskControllerType: []string{"test"},
|
||||
Storage: []common.DiskConfig{
|
||||
{
|
||||
DiskSize: 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
fail: true,
|
||||
expectedErrMsg: "storage[0].'disk_size' is required",
|
||||
},
|
||||
{
|
||||
name: "Storage validate disk_size",
|
||||
config: &CloneConfig{
|
||||
StorageConfig: common.StorageConfig{
|
||||
Storage: []common.DiskConfig{
|
||||
{
|
||||
DiskSize: 0,
|
||||
DiskThinProvisioned: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
fail: true,
|
||||
expectedErrMsg: "storage[0].'disk_size' is required",
|
||||
},
|
||||
{
|
||||
name: "Storage validate disk_controller_index",
|
||||
config: &CloneConfig{
|
||||
StorageConfig: common.StorageConfig{
|
||||
Storage: []common.DiskConfig{
|
||||
{
|
||||
DiskSize: 32768,
|
||||
DiskControllerIndex: 3,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
fail: true,
|
||||
expectedErrMsg: "storage[0].'disk_controller_index' references an unknown disk controller",
|
||||
},
|
||||
{
|
||||
name: "Validate template is set",
|
||||
config: &CloneConfig{
|
||||
StorageConfig: common.StorageConfig{
|
||||
DiskControllerType: []string{"test"},
|
||||
Storage: []common.DiskConfig{
|
||||
{
|
||||
DiskSize: 32768,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
fail: true,
|
||||
expectedErrMsg: "'template' is required",
|
||||
},
|
||||
{
|
||||
name: "Validate LinkedClone and DiskSize set at the same time",
|
||||
config: &CloneConfig{
|
||||
Template: "template name",
|
||||
LinkedClone: true,
|
||||
DiskSize: 32768,
|
||||
StorageConfig: common.StorageConfig{
|
||||
DiskControllerType: []string{"test"},
|
||||
Storage: []common.DiskConfig{
|
||||
{
|
||||
DiskSize: 32768,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
fail: true,
|
||||
expectedErrMsg: "'linked_clone' and 'disk_size' cannot be used together",
|
||||
},
|
||||
{
|
||||
name: "Validate MacAddress and Network not set at the same time",
|
||||
config: &CloneConfig{
|
||||
Template: "template name",
|
||||
MacAddress: "some mac address",
|
||||
StorageConfig: common.StorageConfig{
|
||||
DiskControllerType: []string{"test"},
|
||||
Storage: []common.DiskConfig{
|
||||
{
|
||||
DiskSize: 32768,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
fail: true,
|
||||
expectedErrMsg: "'network' is required when 'mac_address' is specified",
|
||||
},
|
||||
}
|
||||
|
||||
for _, c := range tc {
|
||||
t.Run(c.name, func(t *testing.T) {
|
||||
errs := c.config.Prepare()
|
||||
if c.fail {
|
||||
if len(errs) == 0 {
|
||||
t.Fatalf("Config preprare should fail")
|
||||
}
|
||||
if errs[0].Error() != c.expectedErrMsg {
|
||||
t.Fatalf("Expected error message: %s but was '%s'", c.expectedErrMsg, errs[0].Error())
|
||||
}
|
||||
} else {
|
||||
if len(errs) != 0 {
|
||||
t.Fatalf("Config preprare should not fail: %s", errs[0])
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestStepCreateVM_Run(t *testing.T) {
|
||||
state := new(multistep.BasicStateBag)
|
||||
state.Put("ui", &packersdk.BasicUi{
|
||||
Reader: new(bytes.Buffer),
|
||||
Writer: new(bytes.Buffer),
|
||||
})
|
||||
driverMock := driver.NewDriverMock()
|
||||
state.Put("driver", driverMock)
|
||||
step := basicStepCloneVM()
|
||||
step.Force = true
|
||||
vmPath := path.Join(step.Location.Folder, step.Location.VMName)
|
||||
vmMock := new(driver.VirtualMachineMock)
|
||||
driverMock.VM = vmMock
|
||||
|
||||
if action := step.Run(context.TODO(), state); action == multistep.ActionHalt {
|
||||
t.Fatalf("Should not halt.")
|
||||
}
|
||||
|
||||
// Pre clean VM
|
||||
if !driverMock.PreCleanVMCalled {
|
||||
t.Fatalf("driver.PreCleanVM should be called.")
|
||||
}
|
||||
if driverMock.PreCleanForce != step.Force {
|
||||
t.Fatalf("Force PreCleanVM should be %t but was %t.", step.Force, driverMock.PreCleanForce)
|
||||
}
|
||||
if driverMock.PreCleanVMPath != vmPath {
|
||||
t.Fatalf("VM path expected to be %s but was %s", vmPath, driverMock.PreCleanVMPath)
|
||||
}
|
||||
|
||||
if !driverMock.FindVMCalled {
|
||||
t.Fatalf("driver.FindVM should be called.")
|
||||
}
|
||||
if !vmMock.CloneCalled {
|
||||
t.Fatalf("vm.Clone should be called.")
|
||||
}
|
||||
|
||||
if diff := cmp.Diff(vmMock.CloneConfig, driverCreateConfig(step.Config, step.Location)); diff != "" {
|
||||
t.Fatalf("wrong driver.CreateConfig: %s", diff)
|
||||
}
|
||||
vm, ok := state.GetOk("vm")
|
||||
if !ok {
|
||||
t.Fatal("state must contain the VM")
|
||||
}
|
||||
if vm != driverMock.VM {
|
||||
t.Fatalf("state doesn't contain the created VM.")
|
||||
}
|
||||
}
|
||||
|
||||
func basicStepCloneVM() *StepCloneVM {
|
||||
step := &StepCloneVM{
|
||||
Config: createConfig(),
|
||||
Location: basicLocationConfig(),
|
||||
}
|
||||
return step
|
||||
}
|
||||
|
||||
func basicLocationConfig() *common.LocationConfig {
|
||||
return &common.LocationConfig{
|
||||
VMName: "test-vm",
|
||||
Folder: "test-folder",
|
||||
Cluster: "test-cluster",
|
||||
Host: "test-host",
|
||||
ResourcePool: "test-resource-pool",
|
||||
Datastore: "test-datastore",
|
||||
}
|
||||
}
|
||||
|
||||
func createConfig() *CloneConfig {
|
||||
return &CloneConfig{
|
||||
Template: "template name",
|
||||
StorageConfig: common.StorageConfig{
|
||||
DiskControllerType: []string{"pvscsi"},
|
||||
Storage: []common.DiskConfig{
|
||||
{
|
||||
DiskSize: 32768,
|
||||
DiskThinProvisioned: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func driverCreateConfig(config *CloneConfig, location *common.LocationConfig) *driver.CloneConfig {
|
||||
var disks []driver.Disk
|
||||
for _, disk := range config.StorageConfig.Storage {
|
||||
disks = append(disks, driver.Disk{
|
||||
DiskSize: disk.DiskSize,
|
||||
DiskEagerlyScrub: disk.DiskEagerlyScrub,
|
||||
DiskThinProvisioned: disk.DiskThinProvisioned,
|
||||
ControllerIndex: disk.DiskControllerIndex,
|
||||
})
|
||||
}
|
||||
|
||||
return &driver.CloneConfig{
|
||||
StorageConfig: driver.StorageConfig{
|
||||
DiskControllerType: config.StorageConfig.DiskControllerType,
|
||||
Storage: disks,
|
||||
},
|
||||
Annotation: config.Notes,
|
||||
Name: location.VMName,
|
||||
Folder: location.Folder,
|
||||
Cluster: location.Cluster,
|
||||
Host: location.Host,
|
||||
ResourcePool: location.ResourcePool,
|
||||
Datastore: location.Datastore,
|
||||
LinkedClone: config.LinkedClone,
|
||||
Network: config.Network,
|
||||
MacAddress: config.MacAddress,
|
||||
VAppProperties: config.VAppConfig.Properties,
|
||||
PrimaryDiskSize: config.DiskSize,
|
||||
}
|
||||
}
|
||||
@@ -24,6 +24,9 @@ type DriverMock struct {
|
||||
CreateVMCalled bool
|
||||
CreateConfig *CreateConfig
|
||||
VM VirtualMachine
|
||||
|
||||
FindVMCalled bool
|
||||
FindVMName string
|
||||
}
|
||||
|
||||
func NewDriverMock() *DriverMock {
|
||||
@@ -45,7 +48,12 @@ func (d *DriverMock) NewVM(ref *types.ManagedObjectReference) VirtualMachine {
|
||||
}
|
||||
|
||||
func (d *DriverMock) FindVM(name string) (VirtualMachine, error) {
|
||||
return nil, nil
|
||||
d.FindVMCalled = true
|
||||
if d.VM == nil {
|
||||
d.VM = new(VirtualMachineMock)
|
||||
}
|
||||
d.FindVMName = name
|
||||
return d.VM, d.FindDatastoreErr
|
||||
}
|
||||
|
||||
func (d *DriverMock) FindCluster(name string) (*Cluster, error) {
|
||||
|
||||
@@ -32,7 +32,7 @@ type VirtualMachine interface {
|
||||
Destroy() error
|
||||
Configure(config *HardwareConfig) error
|
||||
Customize(spec types.CustomizationSpec) error
|
||||
ResizeDisk(diskSize int64) error
|
||||
ResizeDisk(diskSize int64) ([]types.BaseVirtualDeviceConfigSpec, error)
|
||||
WaitForIP(ctx context.Context, ipNet *net.IPNet) (string, error)
|
||||
PowerOn() error
|
||||
PowerOff() error
|
||||
@@ -68,18 +68,19 @@ type VirtualMachineDriver struct {
|
||||
}
|
||||
|
||||
type CloneConfig struct {
|
||||
Name string
|
||||
Folder string
|
||||
Cluster string
|
||||
Host string
|
||||
ResourcePool string
|
||||
Datastore string
|
||||
LinkedClone bool
|
||||
Network string
|
||||
MacAddress string
|
||||
Annotation string
|
||||
VAppProperties map[string]string
|
||||
StorageConfig StorageConfig
|
||||
Name string
|
||||
Folder string
|
||||
Cluster string
|
||||
Host string
|
||||
ResourcePool string
|
||||
Datastore string
|
||||
LinkedClone bool
|
||||
Network string
|
||||
MacAddress string
|
||||
Annotation string
|
||||
VAppProperties map[string]string
|
||||
PrimaryDiskSize int64
|
||||
StorageConfig StorageConfig
|
||||
}
|
||||
|
||||
type HardwareConfig struct {
|
||||
@@ -339,6 +340,15 @@ func (vm *VirtualMachineDriver) Clone(ctx context.Context, config *CloneConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if config.PrimaryDiskSize > 0 {
|
||||
deviceResizeSpec, err := vm.ResizeDisk(config.PrimaryDiskSize)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to resize primary disk: %s", err.Error())
|
||||
}
|
||||
configSpec.DeviceChange = append(configSpec.DeviceChange, deviceResizeSpec...)
|
||||
}
|
||||
|
||||
virtualDisks := devices.SelectByType((*types.VirtualDisk)(nil))
|
||||
virtualControllers := devices.SelectByType((*types.VirtualController)(nil))
|
||||
|
||||
@@ -349,7 +359,7 @@ func (vm *VirtualMachineDriver) Clone(ctx context.Context, config *CloneConfig)
|
||||
|
||||
storageConfigSpec, err := config.StorageConfig.AddStorageDevices(existingDevices)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("failed to add storage devices: %s", err.Error())
|
||||
}
|
||||
configSpec.DeviceChange = append(configSpec.DeviceChange, storageConfigSpec...)
|
||||
|
||||
@@ -597,35 +607,25 @@ func (vm *VirtualMachineDriver) Customize(spec types.CustomizationSpec) error {
|
||||
return task.Wait(vm.driver.ctx)
|
||||
}
|
||||
|
||||
func (vm *VirtualMachineDriver) ResizeDisk(diskSize int64) error {
|
||||
var confSpec types.VirtualMachineConfigSpec
|
||||
|
||||
func (vm *VirtualMachineDriver) ResizeDisk(diskSize int64) ([]types.BaseVirtualDeviceConfigSpec, error) {
|
||||
devices, err := vm.vm.Device(vm.driver.ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
disk, err := findDisk(devices)
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
disk.CapacityInKB = diskSize * 1024
|
||||
|
||||
confSpec.DeviceChange = []types.BaseVirtualDeviceConfigSpec{
|
||||
return []types.BaseVirtualDeviceConfigSpec{
|
||||
&types.VirtualDeviceConfigSpec{
|
||||
Device: disk,
|
||||
Operation: types.VirtualDeviceConfigSpecOperationEdit,
|
||||
},
|
||||
}
|
||||
|
||||
task, err := vm.vm.Reconfigure(vm.driver.ctx, confSpec)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = task.WaitForResult(vm.driver.ctx, nil)
|
||||
return err
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (vm *VirtualMachineDriver) PowerOn() error {
|
||||
|
||||
@@ -55,6 +55,9 @@ type VirtualMachineMock struct {
|
||||
|
||||
RemoveCdromsCalled bool
|
||||
RemoveCdromsErr error
|
||||
CloneCalled bool
|
||||
CloneConfig *CloneConfig
|
||||
CloneError error
|
||||
}
|
||||
|
||||
func (vm *VirtualMachineMock) Info(params ...string) (*mo.VirtualMachine, error) {
|
||||
@@ -71,7 +74,9 @@ func (vm *VirtualMachineMock) FloppyDevices() (object.VirtualDeviceList, error)
|
||||
}
|
||||
|
||||
func (vm *VirtualMachineMock) Clone(ctx context.Context, config *CloneConfig) (VirtualMachine, error) {
|
||||
return nil, nil
|
||||
vm.CloneCalled = true
|
||||
vm.CloneConfig = config
|
||||
return vm, vm.CloneError
|
||||
}
|
||||
|
||||
func (vm *VirtualMachineMock) updateVAppConfig(ctx context.Context, newProps map[string]string) (*types.VmConfigSpec, error) {
|
||||
@@ -107,8 +112,8 @@ func (vm *VirtualMachineMock) Customize(spec types.CustomizationSpec) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (vm *VirtualMachineMock) ResizeDisk(diskSize int64) error {
|
||||
return nil
|
||||
func (vm *VirtualMachineMock) ResizeDisk(diskSize int64) ([]types.BaseVirtualDeviceConfigSpec, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (vm *VirtualMachineMock) PowerOn() error {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package driver
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/vmware/govmomi/simulator"
|
||||
@@ -61,7 +62,7 @@ func TestVirtualMachineDriver_Configure(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestVirtualMachineDriver_CreateVM(t *testing.T) {
|
||||
func TestVirtualMachineDriver_CreateVMWithMultipleDisks(t *testing.T) {
|
||||
sim, err := NewVCenterSimulator()
|
||||
if err != nil {
|
||||
t.Fatalf("should not fail: %s", err.Error())
|
||||
@@ -71,10 +72,9 @@ func TestVirtualMachineDriver_CreateVM(t *testing.T) {
|
||||
_, datastore := sim.ChooseSimulatorPreCreatedDatastore()
|
||||
|
||||
config := &CreateConfig{
|
||||
Annotation: "mock annotation",
|
||||
Name: "mock name",
|
||||
Host: "DC0_H0",
|
||||
Datastore: datastore.Name,
|
||||
Name: "mock name",
|
||||
Host: "DC0_H0",
|
||||
Datastore: datastore.Name,
|
||||
NICs: []NIC{
|
||||
{
|
||||
Network: "VM Network",
|
||||
@@ -98,8 +98,90 @@ func TestVirtualMachineDriver_CreateVM(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
_, err = sim.driver.CreateVM(config)
|
||||
vm, err := sim.driver.CreateVM(config)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error %s", err.Error())
|
||||
}
|
||||
|
||||
devices, err := vm.Devices()
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error %s", err.Error())
|
||||
}
|
||||
|
||||
var disks []*types.VirtualDisk
|
||||
for _, device := range devices {
|
||||
switch d := device.(type) {
|
||||
case *types.VirtualDisk:
|
||||
disks = append(disks, d)
|
||||
}
|
||||
}
|
||||
|
||||
if len(disks) != 2 {
|
||||
t.Fatalf("unexpected number of devices")
|
||||
}
|
||||
}
|
||||
|
||||
func TestVirtualMachineDriver_CloneWithPrimaryDiskResize(t *testing.T) {
|
||||
sim, err := NewVCenterSimulator()
|
||||
if err != nil {
|
||||
t.Fatalf("should not fail: %s", err.Error())
|
||||
}
|
||||
defer sim.Close()
|
||||
|
||||
_, datastore := sim.ChooseSimulatorPreCreatedDatastore()
|
||||
vm, _ := sim.ChooseSimulatorPreCreatedVM()
|
||||
|
||||
config := &CloneConfig{
|
||||
Name: "mock name",
|
||||
Host: "DC0_H0",
|
||||
Datastore: datastore.Name,
|
||||
PrimaryDiskSize: 204800,
|
||||
StorageConfig: StorageConfig{
|
||||
DiskControllerType: []string{"pvscsi"},
|
||||
Storage: []Disk{
|
||||
{
|
||||
DiskSize: 3072,
|
||||
DiskThinProvisioned: true,
|
||||
ControllerIndex: 0,
|
||||
},
|
||||
{
|
||||
DiskSize: 20480,
|
||||
DiskThinProvisioned: true,
|
||||
ControllerIndex: 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
clonedVM, err := vm.Clone(context.TODO(), config)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error %s", err.Error())
|
||||
}
|
||||
|
||||
devices, err := clonedVM.Devices()
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error %s", err.Error())
|
||||
}
|
||||
|
||||
var disks []*types.VirtualDisk
|
||||
for _, device := range devices {
|
||||
switch d := device.(type) {
|
||||
case *types.VirtualDisk:
|
||||
disks = append(disks, d)
|
||||
}
|
||||
}
|
||||
|
||||
if len(disks) != 3 {
|
||||
t.Fatalf("unexpected number of devices")
|
||||
}
|
||||
|
||||
if disks[0].CapacityInKB != config.PrimaryDiskSize*1024 {
|
||||
t.Fatalf("unexpected disk size for primary disk: %d", disks[0].CapacityInKB)
|
||||
}
|
||||
if disks[1].CapacityInKB != config.StorageConfig.Storage[0].DiskSize*1024 {
|
||||
t.Fatalf("unexpected disk size for primary disk: %d", disks[1].CapacityInKB)
|
||||
}
|
||||
if disks[2].CapacityInKB != config.StorageConfig.Storage[1].DiskSize*1024 {
|
||||
t.Fatalf("unexpected disk size for primary disk: %d", disks[2].CapacityInKB)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ require (
|
||||
github.com/Azure/go-autorest/autorest/to v0.3.0
|
||||
github.com/ChrisTrenkamp/goxpath v0.0.0-20170922090931-c385f95c6022
|
||||
github.com/NaverCloudPlatform/ncloud-sdk-go-v2 v1.1.0
|
||||
github.com/Telmate/proxmox-api-go v0.0.0-20210320143302-fea68269e6b0
|
||||
github.com/Telmate/proxmox-api-go v0.0.0-20210331182840-ff89a0cebcfa
|
||||
github.com/aliyun/alibaba-cloud-sdk-go v0.0.0-20190418113227-25233c783f4e
|
||||
github.com/aliyun/aliyun-oss-go-sdk v0.0.0-20170113022742-e6dbea820a9f
|
||||
github.com/antihax/optional v1.0.0
|
||||
|
||||
@@ -82,8 +82,8 @@ github.com/NaverCloudPlatform/ncloud-sdk-go-v2 v1.1.0/go.mod h1:P+3VS0ETiQPyWOx3
|
||||
github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d h1:G0m3OIz70MZUWq3EgK3CesDbo8upS2Vm9/P3FtgI+Jk=
|
||||
github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg=
|
||||
github.com/Telmate/proxmox-api-go v0.0.0-20200715182505-ec97c70ba887/go.mod h1:OGWyIMJ87/k/GCz8CGiWB2HOXsOVDM6Lpe/nFPkC4IQ=
|
||||
github.com/Telmate/proxmox-api-go v0.0.0-20210320143302-fea68269e6b0 h1:LeBf+Ex12uqA6dWZp73Qf3dzpV/LvB9SRmHgPBwnXrQ=
|
||||
github.com/Telmate/proxmox-api-go v0.0.0-20210320143302-fea68269e6b0/go.mod h1:ayPkdmEKnlssqLQ9K1BE1jlsaYhXVwkoduXI30oQF0I=
|
||||
github.com/Telmate/proxmox-api-go v0.0.0-20210331182840-ff89a0cebcfa h1:n4g0+o4DDX6WGTRfdj1Ux+49vSwtxtqFGB5XtxoDphI=
|
||||
github.com/Telmate/proxmox-api-go v0.0.0-20210331182840-ff89a0cebcfa/go.mod h1:ayPkdmEKnlssqLQ9K1BE1jlsaYhXVwkoduXI30oQF0I=
|
||||
github.com/abdullin/seq v0.0.0-20160510034733-d5467c17e7af h1:DBNMBMuMiWYu0b+8KMJuWmfCkcxl09JwdlqwDZZ6U14=
|
||||
github.com/abdullin/seq v0.0.0-20160510034733-d5467c17e7af/go.mod h1:5Jv4cbFiHJMsVxt52+i0Ha45fjshj6wxYr1r19tB9bw=
|
||||
github.com/agext/levenshtein v1.2.1 h1:QmvMAjj2aEICytGiWzmxoE0x2KZvE0fvmqMOfy2tjT8=
|
||||
|
||||
@@ -126,6 +126,15 @@ func realMain() int {
|
||||
// wrappedMain is called only when we're wrapped by panicwrap and
|
||||
// returns the exit status to exit with.
|
||||
func wrappedMain() int {
|
||||
// WARNING: WrappedMain causes unexpected behaviors when writing to stderr
|
||||
// and stdout. Anything in this function written to stderr will be captured
|
||||
// by the logger, but will not be written to the terminal. Anything in
|
||||
// this function written to standard out must be prefixed with ErrorPrefix
|
||||
// or OutputPrefix to be sent to the right terminal stream, but adding
|
||||
// these prefixes can cause nondeterministic results for output from
|
||||
// other, asynchronous methods. Try to avoid modifying output in this
|
||||
// function if at all possible.
|
||||
|
||||
// If there is no explicit number of Go threads to use, then set it
|
||||
if os.Getenv("GOMAXPROCS") == "" {
|
||||
runtime.GOMAXPROCS(runtime.NumCPU())
|
||||
@@ -466,6 +475,7 @@ func inPlugin() bool {
|
||||
return os.Getenv(pluginsdk.MagicCookieKey) == pluginsdk.MagicCookieValue
|
||||
}
|
||||
|
||||
// junk
|
||||
func init() {
|
||||
// Seed the random number generator
|
||||
rand.Seed(time.Now().UTC().UnixNano())
|
||||
|
||||
@@ -52,6 +52,7 @@ type FlatConfig struct {
|
||||
AlicloudSourceImage *string `mapstructure:"source_image" required:"true" cty:"source_image" hcl:"source_image"`
|
||||
ForceStopInstance *bool `mapstructure:"force_stop_instance" required:"false" cty:"force_stop_instance" hcl:"force_stop_instance"`
|
||||
DisableStopInstance *bool `mapstructure:"disable_stop_instance" required:"false" cty:"disable_stop_instance" hcl:"disable_stop_instance"`
|
||||
RamRoleName *string `mapstructure:"ram_role_name" required:"false" cty:"ram_role_name" hcl:"ram_role_name"`
|
||||
SecurityGroupId *string `mapstructure:"security_group_id" required:"false" cty:"security_group_id" hcl:"security_group_id"`
|
||||
SecurityGroupName *string `mapstructure:"security_group_name" required:"false" cty:"security_group_name" hcl:"security_group_name"`
|
||||
UserData *string `mapstructure:"user_data" required:"false" cty:"user_data" hcl:"user_data"`
|
||||
@@ -177,6 +178,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
|
||||
"source_image": &hcldec.AttrSpec{Name: "source_image", Type: cty.String, Required: false},
|
||||
"force_stop_instance": &hcldec.AttrSpec{Name: "force_stop_instance", Type: cty.Bool, Required: false},
|
||||
"disable_stop_instance": &hcldec.AttrSpec{Name: "disable_stop_instance", Type: cty.Bool, Required: false},
|
||||
"ram_role_name": &hcldec.AttrSpec{Name: "ram_role_name", Type: cty.String, Required: false},
|
||||
"security_group_id": &hcldec.AttrSpec{Name: "security_group_id", Type: cty.String, Required: false},
|
||||
"security_group_name": &hcldec.AttrSpec{Name: "security_group_name", Type: cty.String, Required: false},
|
||||
"user_data": &hcldec.AttrSpec{Name: "user_data", Type: cty.String, Required: false},
|
||||
|
||||
+1
-1
@@ -301,7 +301,7 @@ func (a *AgentNetworkInterface) UnmarshalJSON(b []byte) error {
|
||||
|
||||
a.IPAddresses = make([]net.IP, len(intermediate.IPAddresses))
|
||||
for idx, ip := range intermediate.IPAddresses {
|
||||
a.IPAddresses[idx] = net.ParseIP(ip.IPAddress)
|
||||
a.IPAddresses[idx] = net.ParseIP((strings.Split(ip.IPAddress, "%"))[0])
|
||||
if a.IPAddresses[idx] == nil {
|
||||
return fmt.Errorf("Could not parse %s as IP", ip.IPAddress)
|
||||
}
|
||||
|
||||
+5
@@ -628,6 +628,11 @@ func NewConfigQemuFromApi(vmr *VmRef, client *Client) (config *ConfigQemu, err e
|
||||
|
||||
diskConfMap["storage_type"] = storageType
|
||||
|
||||
// cloud-init disks not always have the size sent by the API, which results in a crash
|
||||
if diskConfMap["size"] == nil && strings.Contains(fileName.(string), "cloudinit") {
|
||||
diskConfMap["size"] = "4M" // default cloud-init disk size
|
||||
}
|
||||
|
||||
// Convert to gigabytes if disk size was received in terabytes
|
||||
sizeIsInTerabytes, err := regexp.MatchString("[0-9]+T", diskConfMap["size"].(string))
|
||||
if err != nil {
|
||||
|
||||
Vendored
+1
-1
@@ -78,7 +78,7 @@ github.com/NaverCloudPlatform/ncloud-sdk-go-v2/ncloud
|
||||
github.com/NaverCloudPlatform/ncloud-sdk-go-v2/services/server
|
||||
# github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d
|
||||
github.com/StackExchange/wmi
|
||||
# github.com/Telmate/proxmox-api-go v0.0.0-20210320143302-fea68269e6b0
|
||||
# github.com/Telmate/proxmox-api-go v0.0.0-20210331182840-ff89a0cebcfa
|
||||
## explicit
|
||||
github.com/Telmate/proxmox-api-go/proxmox
|
||||
# github.com/agext/levenshtein v1.2.1
|
||||
|
||||
+1
-1
@@ -14,7 +14,7 @@ const Version = "1.7.2"
|
||||
// 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.
|
||||
const VersionPrerelease = "dev"
|
||||
const VersionPrerelease = ""
|
||||
|
||||
var PackerVersion *pluginVersion.PluginVersion
|
||||
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
import CommandLineTerminal from '@hashicorp/react-command-line-terminal'
|
||||
import { useEffect, useState } from 'react'
|
||||
|
||||
export default function AnimatedTerminal({
|
||||
lines,
|
||||
frameLength = 1000,
|
||||
paused,
|
||||
loop,
|
||||
}) {
|
||||
// Determine the total number of frames
|
||||
let totalFrames = 0
|
||||
lines.forEach((line) => {
|
||||
let frames = line.frames ? line.frames : 1
|
||||
if (Array.isArray(line.code)) {
|
||||
totalFrames += line.code.length * frames
|
||||
} else {
|
||||
totalFrames += frames
|
||||
}
|
||||
})
|
||||
|
||||
// Set up Animation
|
||||
const [frame, setFrame] = useState(0)
|
||||
useEffect(() => {
|
||||
let interval = setInterval(() => {
|
||||
if (paused) return
|
||||
if (loop) return setFrame((frame) => frame + 1)
|
||||
if (frame + 1 < totalFrames) {
|
||||
setFrame((frame) => frame + 1)
|
||||
}
|
||||
}, frameLength)
|
||||
return () => clearInterval(interval)
|
||||
}, [frame])
|
||||
|
||||
// Reset Frames if our lines change
|
||||
useEffect(() => {
|
||||
setFrame(0)
|
||||
}, [lines])
|
||||
|
||||
const renderedLines = [...lines.slice(0, frame)]
|
||||
|
||||
return <CommandLineTerminal product="packer" lines={renderedLines} />
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
import s from './style.module.css'
|
||||
import Button from '@hashicorp/react-button'
|
||||
|
||||
export default function BrandedCta({ heading, content, links }) {
|
||||
return (
|
||||
<div className={s.brandedCta}>
|
||||
<div className={`g-grid-container ${s.contentContainer}`}>
|
||||
<h2 className={`g-type-display-2 ${s.heading}`}>{heading}</h2>
|
||||
<div className="content-and-links">
|
||||
<p className={`g-type-body-large ${s.content}`}>{content}</p>
|
||||
<div className={s.links}>
|
||||
{links.map((link, stableIdx) => {
|
||||
return (
|
||||
<Button
|
||||
// eslint-disable-next-line react/no-array-index-key
|
||||
key={stableIdx}
|
||||
linkType={link.type || ''}
|
||||
theme={{
|
||||
variant: stableIdx === 0 ? 'primary' : 'secondary',
|
||||
brand: 'packer',
|
||||
background: 'light',
|
||||
}}
|
||||
title={link.text}
|
||||
url={link.url}
|
||||
/>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
.brandedCta {
|
||||
padding: 88px 0;
|
||||
background-color: var(--packer-secondary);
|
||||
background-image: url('/img/branded-cta/cta-right.svg');
|
||||
background-position: bottom right;
|
||||
background-size: auto 100%;
|
||||
background-repeat: no-repeat;
|
||||
|
||||
@media (--small) {
|
||||
background-position: bottom 0 right -130px;
|
||||
}
|
||||
|
||||
@media (462px <= width < 600px) {
|
||||
background-position: bottom 0 right -260px;
|
||||
}
|
||||
|
||||
@media (width < 462px) {
|
||||
background-position: bottom 0 right -170px;
|
||||
}
|
||||
}
|
||||
|
||||
.contentContainer {
|
||||
@media (width >= 992px) {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
@media (width < 992px) {
|
||||
flex-direction: column;
|
||||
}
|
||||
}
|
||||
|
||||
.heading {
|
||||
color: var(--black);
|
||||
margin-top: 0;
|
||||
|
||||
@media (width >= 992px) {
|
||||
flex-basis: 33.3%;
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.content {
|
||||
max-width: 647px;
|
||||
margin: 0;
|
||||
color: var(--gray-2);
|
||||
}
|
||||
|
||||
.content-and-links {
|
||||
@media (width >= 992px) {
|
||||
flex-basis: 66.6%;
|
||||
margin-left: 32px;
|
||||
}
|
||||
|
||||
& .g-type-body-large {
|
||||
max-width: 35em;
|
||||
}
|
||||
}
|
||||
|
||||
.links {
|
||||
margin-top: 40px;
|
||||
margin-bottom: -16px;
|
||||
|
||||
& a {
|
||||
margin-right: 16px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
<svg width="18" height="18" fill="none" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M17.25 9A8.25 8.25 0 1 1 .75 9a8.25 8.25 0 0 1 16.5 0zm-11.47.223l1.72 1.72 4.19-4.504A.75.75 0 1 1 12.75 7.5l-4.72 5.034a.748.748 0 0 1-1.06 0l-2.25-2.25a.75.75 0 1 1 1.06-1.06z" fill="#2E71E5"/></svg>
|
||||
|
After Width: | Height: | Size: 326 B |
@@ -0,0 +1,5 @@
|
||||
import s from './style.module.css'
|
||||
|
||||
export default function ChecklistWrapper({ children }) {
|
||||
return <div className={s.root}>{children}</div>
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
.root {
|
||||
& ul {
|
||||
list-style: none;
|
||||
margin-left: 2rem;
|
||||
|
||||
& li {
|
||||
color: #525252;
|
||||
|
||||
&::before {
|
||||
content: '';
|
||||
display: block;
|
||||
width: 18px;
|
||||
margin-left: calc(-1 * 1.6rem);
|
||||
height: 18px;
|
||||
top: 7px;
|
||||
background: url('./check-circle-filled.svg');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
import Alert from '@hashicorp/react-alert'
|
||||
import Button from '@hashicorp/react-button'
|
||||
import s from './style.module.css'
|
||||
|
||||
export default function HomepageHero({
|
||||
heading,
|
||||
heroFeature,
|
||||
subheading,
|
||||
links,
|
||||
alert,
|
||||
}) {
|
||||
return (
|
||||
<div className={s.homepageHero}>
|
||||
<div className={s.gridContainer}>
|
||||
<div className={s.content}>
|
||||
{alert ? (
|
||||
<Alert
|
||||
url={alert.url}
|
||||
tag={alert.tag}
|
||||
product="packer"
|
||||
text={alert.text}
|
||||
textColor="dark"
|
||||
/>
|
||||
) : null}
|
||||
<h1 className={s.heading}>{heading}</h1>
|
||||
<p className={s.subheading}>{subheading}</p>
|
||||
<div className={s.links}>
|
||||
{links.map((link, index) => (
|
||||
<Button
|
||||
key={link.text}
|
||||
title={link.text}
|
||||
linkType={link.type}
|
||||
url={link.url}
|
||||
theme={{
|
||||
variant: index === 0 ? 'primary' : 'secondary',
|
||||
brand: index === 0 ? 'packer' : 'neutral',
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<div className={s.heroFeature}>
|
||||
<div className={s.heroFeatureFrame}>{heroFeature}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
.homepageHero {
|
||||
min-height: min(45vw, 600px);
|
||||
padding: 64px 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
background-color: #f0fbff;
|
||||
background-image: url(/img/homepage-hero/hero-right.svg);
|
||||
background-position: bottom -250px right;
|
||||
background-repeat: no-repeat;
|
||||
background-size: contain;
|
||||
@media (--medium-up) {
|
||||
background-position: top right;
|
||||
}
|
||||
}
|
||||
|
||||
.gridContainer {
|
||||
composes: g-grid-container from global;
|
||||
position: relative;
|
||||
@media (--large) {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.content {
|
||||
max-width: 350px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
text-align: center;
|
||||
color: var(--gray-2);
|
||||
@media (--medium-up) {
|
||||
max-width: 550px;
|
||||
}
|
||||
@media (--large) {
|
||||
align-items: flex-start;
|
||||
text-align: left;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.heading {
|
||||
composes: g-type-display-1 from global;
|
||||
margin-top: 12px;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.heroFeature {
|
||||
display: none;
|
||||
position: relative;
|
||||
@media (--large) {
|
||||
display: flex;
|
||||
min-height: 500px;
|
||||
}
|
||||
}
|
||||
|
||||
.heroFeatureFrame {
|
||||
position: absolute;
|
||||
width: calc(100% + 80px);
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.links {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
|
||||
& a {
|
||||
margin-right: 8px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
@media (--large) {
|
||||
width: auto;
|
||||
justify-content: flex-start;
|
||||
}
|
||||
}
|
||||
|
||||
.subheading {
|
||||
composes: g-type-body-large from global;
|
||||
color: inherit;
|
||||
margin: 0;
|
||||
font-size: 17px;
|
||||
line-height: 25px;
|
||||
margin-bottom: 40px;
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
import TextSplitWithImage from '@hashicorp/react-text-split-with-image'
|
||||
|
||||
export default function IntegrationsTextSplit({
|
||||
heading,
|
||||
links,
|
||||
content,
|
||||
image,
|
||||
}) {
|
||||
return (
|
||||
<TextSplitWithImage
|
||||
textSplit={{
|
||||
heading,
|
||||
product: 'packer',
|
||||
content,
|
||||
linkStyle: 'buttons',
|
||||
links,
|
||||
}}
|
||||
image={image}
|
||||
/>
|
||||
)
|
||||
}
|
||||
@@ -29,12 +29,6 @@ to match Terraform Registry tier labels.
|
||||
}
|
||||
}
|
||||
|
||||
/* add margin-top to separate from the adjacent
|
||||
search bar present on docs pages */
|
||||
:global(.g-search) + .root {
|
||||
margin-top: 40px;
|
||||
}
|
||||
|
||||
.text {
|
||||
/* composes */
|
||||
composes: g-type-body-small-strong from global;
|
||||
|
||||
@@ -7,24 +7,37 @@ import {
|
||||
import renderPageMdx from '@hashicorp/react-docs-page/render-page-mdx'
|
||||
import resolveNavData from './utils/resolve-nav-data'
|
||||
|
||||
async function generateStaticPaths(navDataFile, contentDir, options = {}) {
|
||||
const navData = await resolveNavData(navDataFile, contentDir, options)
|
||||
async function generateStaticPaths({
|
||||
navDataFile,
|
||||
localContentDir,
|
||||
remotePluginsFile,
|
||||
}) {
|
||||
const navData = await resolveNavData(navDataFile, localContentDir, {
|
||||
remotePluginsFile,
|
||||
})
|
||||
const paths = await getPathsFromNavData(navData)
|
||||
return paths
|
||||
}
|
||||
|
||||
async function generateStaticProps(
|
||||
navDataFile,
|
||||
async function generateStaticProps({
|
||||
additionalComponents,
|
||||
localContentDir,
|
||||
mainBranch = 'main',
|
||||
navDataFile,
|
||||
params,
|
||||
product,
|
||||
{ remotePluginsFile, additionalComponents, mainBranch = 'main' } = {}
|
||||
) {
|
||||
remotePluginsFile,
|
||||
}) {
|
||||
// Build the currentPath from page parameters
|
||||
const currentPath = params.page ? params.page.join('/') : ''
|
||||
// Resolve navData, including the possibility that this
|
||||
// page is a remote plugin docs, in which case we'll provide
|
||||
// the MDX fileString in the resolved navData
|
||||
const navData = await resolveNavData(navDataFile, localContentDir, {
|
||||
remotePluginsFile,
|
||||
currentPath,
|
||||
})
|
||||
const pathToMatch = params.page ? params.page.join('/') : ''
|
||||
const navNode = getNodeFromPath(pathToMatch, navData, localContentDir)
|
||||
const navNode = getNodeFromPath(currentPath, navData, localContentDir)
|
||||
const { filePath, remoteFile, pluginTier } = navNode
|
||||
// Fetch the MDX file content
|
||||
const mdxString = remoteFile
|
||||
@@ -41,7 +54,7 @@ async function generateStaticProps(
|
||||
// (current options are "Official" or "Community")
|
||||
function mdxContentHook(mdxContent) {
|
||||
if (pluginTier) {
|
||||
const tierMdx = `<PluginTierLabel tier="${pluginTier}" />\n\n`
|
||||
const tierMdx = `<br/><PluginTierLabel tier="${pluginTier}" />\n\n`
|
||||
mdxContent = tierMdx + mdxContent
|
||||
}
|
||||
return mdxContent
|
||||
@@ -51,8 +64,6 @@ async function generateStaticProps(
|
||||
productName: product.name,
|
||||
mdxContentHook,
|
||||
})
|
||||
// Build the currentPath from page parameters
|
||||
const currentPath = !params.page ? '' : params.page.join('/')
|
||||
|
||||
return {
|
||||
currentPath,
|
||||
|
||||
@@ -16,7 +16,7 @@ const validateRouteStructure = require('@hashicorp/react-docs-sidenav/utils/vali
|
||||
* @returns {array} the resolved navData. This includes NavBranch nodes pulled from remote plugin repositories, as well as filePath properties on all local NavLeaf nodes, and remoteFile properties on all NavLeafRemote nodes.
|
||||
*/
|
||||
async function resolveNavData(navDataFile, localContentDir, options = {}) {
|
||||
const { remotePluginsFile } = options
|
||||
const { remotePluginsFile, currentPath } = options
|
||||
// Read in files
|
||||
const navDataPath = path.join(process.cwd(), navDataFile)
|
||||
const navData = JSON.parse(fs.readFileSync(navDataPath, 'utf8'))
|
||||
@@ -24,7 +24,11 @@ async function resolveNavData(navDataFile, localContentDir, options = {}) {
|
||||
let withPlugins = navData
|
||||
if (remotePluginsFile) {
|
||||
// Resolve plugins, this yields branches with NavLeafRemote nodes
|
||||
withPlugins = await mergeRemotePlugins(remotePluginsFile, navData)
|
||||
withPlugins = await mergeRemotePlugins(
|
||||
remotePluginsFile,
|
||||
navData,
|
||||
currentPath
|
||||
)
|
||||
}
|
||||
// Resolve local filePaths for NavLeaf nodes
|
||||
const withFilePaths = await validateFilePaths(withPlugins, localContentDir)
|
||||
@@ -40,14 +44,16 @@ async function resolveNavData(navDataFile, localContentDir, options = {}) {
|
||||
// fetch and parse all remote plugin docs, merge them into the
|
||||
// broader tree of docs navData, and return the docs navData
|
||||
// with the merged plugin docs
|
||||
async function mergeRemotePlugins(remotePluginsFile, navData) {
|
||||
async function mergeRemotePlugins(remotePluginsFile, navData, currentPath) {
|
||||
// Read in and parse the plugin configuration JSON
|
||||
const remotePluginsPath = path.join(process.cwd(), remotePluginsFile)
|
||||
const pluginEntries = JSON.parse(fs.readFileSync(remotePluginsPath, 'utf-8'))
|
||||
// Add navData for each plugin's component.
|
||||
// Note that leaf nodes include a remoteFile property object with the full MDX fileString
|
||||
const pluginEntriesWithDocs = await Promise.all(
|
||||
pluginEntries.map(resolvePluginEntryDocs)
|
||||
pluginEntries.map(
|
||||
async (entry) => await resolvePluginEntryDocs(entry, currentPath)
|
||||
)
|
||||
)
|
||||
// group navData by component type, to prepare to merge plugin docs
|
||||
// into the broader tree of navData.
|
||||
@@ -113,7 +119,7 @@ async function mergeRemotePlugins(remotePluginsFile, navData) {
|
||||
return { ...n, routes: routesWithPlugins }
|
||||
})
|
||||
// return the merged navData, which now includes special NavLeaf nodes
|
||||
// for plugin docs with { filePath, fileString } remoteFile properties
|
||||
// for plugin docs with remoteFile properties
|
||||
return navDataWithPlugins
|
||||
}
|
||||
|
||||
@@ -125,8 +131,14 @@ async function mergeRemotePlugins(remotePluginsFile, navData) {
|
||||
// Note that navData leaf nodes have a special remoteFile property,
|
||||
// which contains { filePath, fileString } data for the remote
|
||||
// plugin doc .mdx file
|
||||
async function resolvePluginEntryDocs(pluginConfigEntry) {
|
||||
const { title, path: slug, repo, version } = pluginConfigEntry
|
||||
async function resolvePluginEntryDocs(pluginConfigEntry, currentPath) {
|
||||
const {
|
||||
title,
|
||||
path: slug,
|
||||
repo,
|
||||
version,
|
||||
sourceBranch = 'main',
|
||||
} = pluginConfigEntry
|
||||
const docsMdxFiles = await fetchPluginDocs({ repo, tag: version })
|
||||
// We construct a special kind of "NavLeaf" node, with a remoteFile property,
|
||||
// consisting of a { filePath, fileString, sourceUrl }, where:
|
||||
@@ -149,7 +161,7 @@ async function resolvePluginEntryDocs(pluginConfigEntry) {
|
||||
const { nav_title, sidebar_title } = frontmatter
|
||||
const title = nav_title || sidebar_title || basename
|
||||
// construct sourceUrl (used for "Edit this page" link)
|
||||
const sourceUrl = `https://github.com/${repo}/blob/${version}/${filePath}`
|
||||
const sourceUrl = `https://github.com/${repo}/blob/${sourceBranch}/${filePath}`
|
||||
// determine pluginTier
|
||||
const pluginOwner = repo.split('/')[0]
|
||||
const pluginTier = pluginOwner === 'hashicorp' ? 'official' : 'community'
|
||||
@@ -192,8 +204,21 @@ async function resolvePluginEntryDocs(pluginConfigEntry) {
|
||||
const prefixedPath = path.join(pathPrefix, n.path)
|
||||
return { ...n, path: prefixedPath }
|
||||
})
|
||||
//
|
||||
return { type, navData: withPrefixedPaths }
|
||||
// If currentPath is provided, then remove the remoteFile
|
||||
// from all nodes except the currentPath. This ensures we deliver
|
||||
// only a single fileString in our getStaticProps JSON.
|
||||
// Without this optimization, we would send all fileStrings
|
||||
// for all NavLeafRemote nodes
|
||||
const withOptimizedFileStrings = visitNavLeaves(withPrefixedPaths, (n) => {
|
||||
if (!n.remoteFile) return n
|
||||
const noCurrentPath = typeof currentPath === 'undefined'
|
||||
const isPathMatch = currentPath === n.path
|
||||
if (noCurrentPath || isPathMatch) return n
|
||||
const { filePath } = n.remoteFile
|
||||
return { ...n, remoteFile: { filePath } }
|
||||
})
|
||||
// Return the component, with processed navData
|
||||
return { type, navData: withOptimizedFileStrings }
|
||||
})
|
||||
const componentsObj = components.reduce((acc, component) => {
|
||||
if (!component) return acc
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
import Button from '@hashicorp/react-button'
|
||||
import s from './style.module.css'
|
||||
|
||||
export default function SectionBreakCta({ heading, link }) {
|
||||
return (
|
||||
<div className={s.sectionBreakCta}>
|
||||
<hr />
|
||||
<h4 className={s.heading}>{heading}</h4>
|
||||
<Button
|
||||
title={link.text}
|
||||
url={link.url}
|
||||
theme={{
|
||||
brand: 'neutral',
|
||||
variant: 'tertiary-neutral',
|
||||
background: 'light',
|
||||
}}
|
||||
linkType="outbound"
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
.sectionBreakCta {
|
||||
padding: 88px 24px;
|
||||
max-width: 800px;
|
||||
display: grid;
|
||||
grid-gap: 24px;
|
||||
text-align: center;
|
||||
position: relative;
|
||||
box-shadow: 0 8px 12px rgba(37, 38, 45, 0.08);
|
||||
margin: 0 16px;
|
||||
background-color: var(--white);
|
||||
align-items: center;
|
||||
|
||||
@media (--medium-up) {
|
||||
margin: 0 auto 104px auto;
|
||||
}
|
||||
& hr {
|
||||
position: absolute;
|
||||
top: 56px;
|
||||
left: calc(50% - 32px);
|
||||
width: 64px;
|
||||
background-color: var(--packer);
|
||||
margin-top: 0;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
}
|
||||
|
||||
.heading {
|
||||
composes: g-type-display-4 from global;
|
||||
margin: 0;
|
||||
@media (--medium-up) {
|
||||
padding: 0 88px;
|
||||
}
|
||||
}
|
||||
@@ -14,7 +14,7 @@ export default function PackerSubnav() {
|
||||
{ text: 'GitHub', url: 'https://www.github.com/hashicorp/packer' },
|
||||
{ text: 'Download', url: '/downloads' },
|
||||
]}
|
||||
currentPath={router.pathname}
|
||||
currentPath={router.asPath}
|
||||
menuItemsAlign="right"
|
||||
menuItems={subnavItems}
|
||||
constrainWidth
|
||||
|
||||
@@ -3,7 +3,6 @@ description: |
|
||||
The `alicloud-ecs` Packer builder plugin provide the capability to build
|
||||
customized images based on an existing base images.
|
||||
page_title: Alicloud Image Builder
|
||||
sidebar_title: Alicloud ECS
|
||||
---
|
||||
|
||||
# Alicloud Image Builder
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
---
|
||||
description: Packer supports building VHDs in Azure Resource manager.
|
||||
page_title: Azure arm - Builders
|
||||
sidebar_title: ARM
|
||||
---
|
||||
|
||||
# Azure Resource Manager Builder
|
||||
|
||||
@@ -5,7 +5,6 @@ description: >
|
||||
|
||||
a VM in Azure.
|
||||
page_title: Azure chroot - Builders
|
||||
sidebar_title: chroot
|
||||
---
|
||||
|
||||
# Azure Builder (chroot)
|
||||
@@ -261,36 +260,36 @@ build {
|
||||
</Tab>
|
||||
<Tab heading="JSON">
|
||||
|
||||
```json
|
||||
{
|
||||
"variables": {
|
||||
"client_id": "{{env `ARM_CLIENT_ID`}}",
|
||||
"client_secret": "{{env `ARM_CLIENT_SECRET`}}",
|
||||
"subscription_id": "{{env `ARM_SUBSCRIPTION_ID`}}",
|
||||
"resource_group": "{{env `ARM_IMAGE_RESOURCEGROUP_ID`}}"
|
||||
},
|
||||
"builders": [
|
||||
{
|
||||
"type": "azure-chroot",
|
||||
```json
|
||||
{
|
||||
"variables": {
|
||||
"client_id": "{{env `ARM_CLIENT_ID`}}",
|
||||
"client_secret": "{{env `ARM_CLIENT_SECRET`}}",
|
||||
"subscription_id": "{{env `ARM_SUBSCRIPTION_ID`}}",
|
||||
"resource_group": "{{env `ARM_IMAGE_RESOURCEGROUP_ID`}}"
|
||||
},
|
||||
"builders": [
|
||||
{
|
||||
"type": "azure-chroot",
|
||||
|
||||
"client_id": "{{user `client_id`}}",
|
||||
"client_secret": "{{user `client_secret`}}",
|
||||
"subscription_id": "{{user `subscription_id`}}",
|
||||
"client_id": "{{user `client_id`}}",
|
||||
"client_secret": "{{user `client_secret`}}",
|
||||
"subscription_id": "{{user `subscription_id`}}",
|
||||
|
||||
"image_resource_id": "/subscriptions/{{user `subscription_id`}}/resourceGroups/{{user `resource_group`}}/providers/Microsoft.Compute/images/MyDebianOSImage-{{timestamp}}",
|
||||
"image_resource_id": "/subscriptions/{{user `subscription_id`}}/resourceGroups/{{user `resource_group`}}/providers/Microsoft.Compute/images/MyDebianOSImage-{{timestamp}}",
|
||||
|
||||
"source": "credativ:Debian:9:latest"
|
||||
}
|
||||
],
|
||||
"provisioners": [
|
||||
{
|
||||
"inline": ["apt-get update", "apt-get upgrade -y"],
|
||||
"inline_shebang": "/bin/sh -x",
|
||||
"type": "shell"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
"source": "credativ:Debian:9:latest"
|
||||
}
|
||||
],
|
||||
"provisioners": [
|
||||
{
|
||||
"inline": ["apt-get update", "apt-get upgrade -y"],
|
||||
"inline_shebang": "/bin/sh -x",
|
||||
"type": "shell"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
||||
@@ -5,7 +5,6 @@ description: >
|
||||
multiple builders depending on the strategy you want to use to build the
|
||||
images.
|
||||
page_title: Azure images - Builders
|
||||
sidebar_title: Azure
|
||||
---
|
||||
|
||||
# Azure Virtual Machine Image Builders
|
||||
|
||||
@@ -5,7 +5,6 @@ description: |
|
||||
source, runs any provisioning necessary on the instance after launching it and
|
||||
then creates a new template from that instance.
|
||||
page_title: CloudStack - Builders
|
||||
sidebar_title: CloudStack
|
||||
---
|
||||
|
||||
# CloudStack Builder
|
||||
|
||||
@@ -3,7 +3,6 @@ description: |
|
||||
Community-maintained builders are not part of the core Packer binary, but
|
||||
can run alongside Packer with minimal extra effort.
|
||||
page_title: Community - Builders
|
||||
sidebar_title: Community-Supported
|
||||
---
|
||||
|
||||
# Community Builders
|
||||
|
||||
@@ -4,7 +4,6 @@ description: |
|
||||
modify the core source code of Packer itself. Documentation for creating new
|
||||
builders is covered in the custom builders page of the Packer plugin section.
|
||||
page_title: Custom - Builders
|
||||
sidebar_title: Custom
|
||||
---
|
||||
|
||||
# Custom Builder
|
||||
|
||||
@@ -11,7 +11,6 @@ description: >
|
||||
|
||||
launched within DigitalOcean.
|
||||
page_title: DigitalOcean - Builders
|
||||
sidebar_title: DigitalOcean
|
||||
---
|
||||
|
||||
# DigitalOcean Builder
|
||||
@@ -67,4 +66,4 @@ In addition to the builder options, a
|
||||
|
||||
@include 'packer-plugin-sdk/communicator/SSH-not-required.mdx'
|
||||
|
||||
@include 'packer-plugin-sdk/communicator/SSH-Private-Key-File-not-required.mdx'
|
||||
@include 'packer-plugin-sdk/communicator/SSH-Private-Key-File-not-required.mdx'
|
||||
|
||||
@@ -4,7 +4,6 @@ description: |
|
||||
from a file. It can be used to debug post-processors without incurring high
|
||||
wait times.
|
||||
page_title: File - Builders
|
||||
sidebar_title: File
|
||||
---
|
||||
|
||||
# File Builder
|
||||
|
||||
@@ -3,7 +3,6 @@ description: |
|
||||
The googlecompute Packer builder is able to create images for use with Google
|
||||
Cloud Compute Engine (GCE) based on existing images.
|
||||
page_title: Google Compute - Builders
|
||||
sidebar_title: Google Cloud
|
||||
---
|
||||
|
||||
# Google Compute Builder
|
||||
|
||||
@@ -6,7 +6,6 @@ description: |
|
||||
image. This reusable image can then be used as the foundation of new servers
|
||||
that are launched within the Hetzner Cloud.
|
||||
page_title: Hetzner Cloud - Builders
|
||||
sidebar_title: Hetzner Cloud
|
||||
---
|
||||
|
||||
# Hetzner Cloud Builder
|
||||
|
||||
@@ -4,7 +4,6 @@ description: |
|
||||
The builder takes a source image, runs any provisioning necessary on
|
||||
the image after launching it, then creates a reusable image.
|
||||
page_title: HyperOne - Builders
|
||||
sidebar_title: HyperOne
|
||||
---
|
||||
|
||||
# HyperOne Builder
|
||||
|
||||
@@ -3,7 +3,6 @@ description: |
|
||||
The Hyper-V Packer builder is able to create Hyper-V virtual machines and
|
||||
export them.
|
||||
page_title: Hyper-V - Builders
|
||||
sidebar_title: Hyper-V
|
||||
---
|
||||
|
||||
# HyperV Builder
|
||||
|
||||
@@ -5,7 +5,6 @@ description: |
|
||||
The Hyper-V Packer builder is able to create Hyper-V virtual machines and
|
||||
export them.
|
||||
page_title: Hyper-V ISO - Builders
|
||||
sidebar_title: ISO
|
||||
---
|
||||
|
||||
# Hyper-V Builder (from an ISO)
|
||||
|
||||
@@ -5,7 +5,6 @@ description: >-
|
||||
The Hyper-V Packer builder is able to clone an existing Hyper-V virtual
|
||||
machine and export them.
|
||||
page_title: Hyper-V Builder (from a vmcx)
|
||||
sidebar_title: VMCX
|
||||
---
|
||||
|
||||
# Hyper-V Builder (from a vmcx)
|
||||
|
||||
@@ -3,7 +3,6 @@ description: |
|
||||
Builders are responsible for creating machines and generating images from them
|
||||
for various platforms.
|
||||
page_title: Builders
|
||||
sidebar_title: Builders
|
||||
---
|
||||
|
||||
# Builders
|
||||
@@ -17,4 +16,3 @@ See the [`source`](/docs/templates/hcl_templates/blocks/source) block documentat
|
||||
about configuring builders in the Packer language.
|
||||
For information on an individual builder, choose it from the sidebar. Each
|
||||
builder has its own configuration options and parameters.
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@ description: |
|
||||
The `jdcloud` Packer builder helps you to build instance images
|
||||
based on an existing image
|
||||
page_title: JDCloud Image Builder
|
||||
sidebar_title: JDCloud
|
||||
---
|
||||
|
||||
# JDCloud Image Builder
|
||||
|
||||
@@ -11,7 +11,6 @@ description: >
|
||||
|
||||
within all Linode regions.
|
||||
page_title: Linode - Builders
|
||||
sidebar_title: Linode
|
||||
---
|
||||
|
||||
# Linode Builder
|
||||
@@ -48,6 +47,7 @@ can also be supplied to override the typical auto-generated key:
|
||||
|
||||
See https://github.com/tcort/markdown-link-check/issues/109
|
||||
-->
|
||||
|
||||
### Required
|
||||
|
||||
- `linode_token` (string) - The client TOKEN to use to access your account.
|
||||
|
||||
@@ -4,7 +4,6 @@ description: |
|
||||
container, runs provisioners within this container, then exports the container
|
||||
as a tar.gz of the root file system.
|
||||
page_title: LXC - Builders
|
||||
sidebar_title: LXC
|
||||
---
|
||||
|
||||
# LXC Builder
|
||||
|
||||
@@ -7,7 +7,6 @@ description: >
|
||||
|
||||
an LXD image.
|
||||
page_title: LXD - Builders
|
||||
sidebar_title: LXD
|
||||
---
|
||||
|
||||
# LXD Builder
|
||||
|
||||
@@ -3,7 +3,6 @@ description: |
|
||||
The ncloud builder allows you to create server images using the NAVER Cloud
|
||||
Platform.
|
||||
page_title: Naver Cloud Platform - Builders
|
||||
sidebar_title: NAVER Cloud
|
||||
---
|
||||
|
||||
# NAVER CLOUD PLATFORM Builder
|
||||
|
||||
@@ -5,7 +5,6 @@ description: |
|
||||
without incurring high wait times. It does not create any kind of image or
|
||||
artifact.
|
||||
page_title: Null - Builders
|
||||
sidebar_title: 'Null'
|
||||
---
|
||||
|
||||
# Null Builder
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
---
|
||||
description: The 1&1 builder is able to create images for 1&1 cloud.
|
||||
page_title: 1&1 - Builders
|
||||
sidebar_title: 1&1
|
||||
---
|
||||
|
||||
# 1&1 Builder
|
||||
@@ -47,8 +46,9 @@ can also be supplied to override the typical auto-generated key:
|
||||
while waiting for the build to complete. Default value "600".
|
||||
|
||||
<!-- markdown-link-check-disable -->
|
||||
|
||||
- `url` (string) - Endpoint for the 1&1 REST API. Default URL
|
||||
"<https://cloudpanel-api.1and1.com/v1>"
|
||||
"<https://cloudpanel-api.1and1.com/v1>"
|
||||
<!-- markdown-link-check-enable -->
|
||||
|
||||
## Example
|
||||
|
||||
@@ -11,7 +11,6 @@ description: >
|
||||
|
||||
within OpenStack.
|
||||
page_title: OpenStack - Builders
|
||||
sidebar_title: OpenStack
|
||||
---
|
||||
|
||||
# OpenStack Builder
|
||||
@@ -132,6 +131,7 @@ builders "openstack" {
|
||||
insecure = "true"
|
||||
}
|
||||
```
|
||||
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
||||
@@ -155,6 +155,7 @@ Here is a basic example. This is a working example to build a Ubuntu 12.04 LTS
|
||||
"flavor": "2"
|
||||
}
|
||||
```
|
||||
|
||||
</Tab>
|
||||
|
||||
<Tab heading="HCL2">
|
||||
@@ -170,6 +171,7 @@ builders "openstack" {
|
||||
flavor = "2"
|
||||
}
|
||||
```
|
||||
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
||||
@@ -190,6 +192,7 @@ by Metacloud.
|
||||
"flavor": "2"
|
||||
}
|
||||
```
|
||||
|
||||
</Tab>
|
||||
|
||||
<Tab heading="HCL2">
|
||||
@@ -202,10 +205,10 @@ builders "openstack" {
|
||||
flavor = "2"
|
||||
}
|
||||
```
|
||||
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
||||
|
||||
In this case, the connection information for connecting to OpenStack doesn't
|
||||
appear in the template. That is because I source a standard OpenStack script
|
||||
with environment variables set before I run this. This script is setting
|
||||
@@ -266,6 +269,7 @@ by Selectel VPC.
|
||||
"volume_type": "fast.ru-3a"
|
||||
}
|
||||
```
|
||||
|
||||
</Tab>
|
||||
|
||||
<Tab heading="HCL2">
|
||||
@@ -287,10 +291,10 @@ builders "openstack" {
|
||||
volume_type = "fast.ru-3a"
|
||||
}
|
||||
```
|
||||
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
||||
|
||||
## Notes on OpenStack Authorization
|
||||
|
||||
The simplest way to get all settings for authorization against OpenStack is to
|
||||
|
||||
@@ -3,7 +3,6 @@ description: |
|
||||
The oracle-classic builder is able to create new custom images for use with
|
||||
Oracle Cloud Infrastructure Classic Compute.
|
||||
page_title: Oracle Cloud Infrastructure Classic - Builders
|
||||
sidebar_title: Oracle Classic
|
||||
---
|
||||
|
||||
# Oracle Cloud Infrastructure Classic Compute Builder
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
---
|
||||
description: Packer is able to create custom images using Oracle Cloud Infrastructure.
|
||||
page_title: Oracle - Builders
|
||||
sidebar_title: Oracle
|
||||
---
|
||||
|
||||
# Oracle Builder
|
||||
|
||||
@@ -3,7 +3,6 @@ description: |
|
||||
The oracle-oci builder is able to create new custom images for use with Oracle
|
||||
Cloud Infrastructure (OCI).
|
||||
page_title: Oracle OCI - Builders
|
||||
sidebar_title: Oracle OCI
|
||||
---
|
||||
|
||||
# Oracle Cloud Infrastructure (OCI) Builder
|
||||
@@ -189,18 +188,19 @@ can also be supplied to override the typical auto-generated key:
|
||||
- `use_private_ip` (boolean) - Use private ip addresses to connect to the
|
||||
instance via ssh.
|
||||
|
||||
- `shape_config` (object) - The shape configuration for an instance. The shape configuration determines the resources
|
||||
- `shape_config` (object) - The shape configuration for an instance. The shape configuration determines the resources
|
||||
allocated to an instance. Options:
|
||||
- `ocpus` (required when using flexible shapes or memory_in_gbs is set) (float32) - The total number of OCPUs available to the instance.
|
||||
- `memory_in_gbs` (optional) (float32) - The total amount of memory, in gigabytes, available to the instance.
|
||||
|
||||
<!-- markdown-link-check-disable -->
|
||||
|
||||
- `metadata` (map of strings) - Metadata optionally contains custom metadata
|
||||
key/value pairs provided in the configuration. While this can be used to
|
||||
set metadata\["user_data"\] the explicit "user_data" and
|
||||
"user_data_file" values will have precedence. An instance's metadata can
|
||||
be obtained from at [http://169.254.169.254](http://169.254.169.254) on
|
||||
the launched instance.
|
||||
key/value pairs provided in the configuration. While this can be used to
|
||||
set metadata\["user_data"\] the explicit "user_data" and
|
||||
"user_data_file" values will have precedence. An instance's metadata can
|
||||
be obtained from at [http://169.254.169.254](http://169.254.169.254) on
|
||||
the launched instance.
|
||||
<!-- markdown-link-check-enable -->
|
||||
|
||||
- `user_data` (string) - User data to be used by cloud-init. See [the Oracle
|
||||
|
||||
@@ -7,7 +7,6 @@ description: >
|
||||
|
||||
the root device section in the Outscale documentation.
|
||||
page_title: Outscale BSU - Builders
|
||||
sidebar_title: BSU
|
||||
---
|
||||
|
||||
# OMI Builder (BSU backed)
|
||||
|
||||
@@ -3,7 +3,6 @@ description: |
|
||||
The osc-bsusurrogate Packer builder is like the chroot builder, but does not
|
||||
require running inside an Outscale virtual machine.
|
||||
page_title: Outscale BSU Surrogate - Builders
|
||||
sidebar_title: BSU Surrogate
|
||||
---
|
||||
|
||||
# BSU Surrogate Builder
|
||||
|
||||
@@ -3,7 +3,6 @@ description: |
|
||||
The osc-bsuvolume Packer builder is like the BSU builder, but is intended to
|
||||
create BSU volumes rather than a machine image.
|
||||
page_title: Outscale BSU Volume - Builders
|
||||
sidebar_title: BSU Volume
|
||||
---
|
||||
|
||||
# BSU Volume Builder
|
||||
|
||||
@@ -9,7 +9,6 @@ description: >
|
||||
|
||||
in the Outscale documentation.
|
||||
page_title: Outscale chroot - Builders
|
||||
sidebar_title: chroot
|
||||
---
|
||||
|
||||
# OMI Builder (chroot)
|
||||
|
||||
@@ -5,7 +5,6 @@ description: >
|
||||
|
||||
multiple builders depending on the strategy you want to use to build the OMI.
|
||||
page_title: Outscale OMI - Builders
|
||||
sidebar_title: Outscale
|
||||
---
|
||||
|
||||
# Outscale OMI Builder
|
||||
|
||||
@@ -3,7 +3,6 @@ description: |
|
||||
The Parallels Packer builder is able to create Parallels Desktop for Mac
|
||||
virtual machines and export them in the PVM format.
|
||||
page_title: Parallels - Builders
|
||||
sidebar_title: Parallels
|
||||
---
|
||||
|
||||
# Parallels Builder
|
||||
|
||||
@@ -6,7 +6,6 @@ description: |
|
||||
virtual machines and export them in the PVM format, starting from an ISO
|
||||
image.
|
||||
page_title: Parallels ISO - Builders
|
||||
sidebar_title: ISO
|
||||
---
|
||||
|
||||
# Parallels Builder (from an ISO)
|
||||
|
||||
@@ -6,7 +6,6 @@ description: |
|
||||
machines and export them in the PVM format, starting from an existing PVM
|
||||
(exported virtual machine image).
|
||||
page_title: Parallels PVM - Builders
|
||||
sidebar_title: PVM
|
||||
---
|
||||
|
||||
# Parallels Builder (from a PVM)
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
---
|
||||
description: The ProfitBricks builder is able to create images for ProfitBricks cloud.
|
||||
page_title: ProfitBricks - Builders
|
||||
sidebar_title: ProfitBricks
|
||||
---
|
||||
|
||||
# ProfitBricks Builder
|
||||
@@ -63,7 +62,7 @@ can also be supplied to override the typical auto-generated key:
|
||||
- `snapshot_password` (string) - Password for the snapshot.
|
||||
<!-- markdown-link-check-disable -->
|
||||
- `url` (string) - Endpoint for the ProfitBricks REST API. Default URL
|
||||
"<https://api.profitbricks.com/rest/v2>"
|
||||
"<https://api.profitbricks.com/rest/v2>"
|
||||
<!-- markdown-link-check-enable -->
|
||||
|
||||
## Example
|
||||
|
||||
@@ -5,7 +5,6 @@ description: |
|
||||
template name, runs any provisioning necessary on the image after
|
||||
launching it, then creates a virtual machine template.
|
||||
page_title: Proxmox Clone - Builders
|
||||
sidebar_title: Clone
|
||||
---
|
||||
|
||||
# Proxmox Builder (from an image)
|
||||
|
||||
@@ -3,14 +3,13 @@ description: >
|
||||
The Proxmox Packer builder is able to create Cloud-Init virtual machine images
|
||||
on a Proxmox server.
|
||||
page_title: Proxmox - Builders
|
||||
sidebar_title: Proxmox
|
||||
---
|
||||
|
||||
# Proxmox Builder
|
||||
|
||||
The Proxmox Packer builder is able to create
|
||||
[Proxmox](https://www.proxmox.com/en/proxmox-ve) virtual
|
||||
machines and store them as new Proxmox Virutal Machine images.
|
||||
machines and store them as new Proxmox Virtual Machine images.
|
||||
|
||||
Packer is able to target both ISO and existing Cloud-Init images:
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@ description: |
|
||||
necessary on the image after launching it, then creates a virtual machine
|
||||
template.
|
||||
page_title: Proxmox ISO - Builders
|
||||
sidebar_title: ISO
|
||||
---
|
||||
|
||||
# Proxmox Builder (from an ISO)
|
||||
@@ -223,7 +222,7 @@ builder.
|
||||
Defaults to `lsi`.
|
||||
|
||||
- `cloud_init` (bool) - If true, add a Cloud-Init CDROM drive after the virtual machine has been converted to a template.
|
||||
Defaults to `false`.
|
||||
Defaults to `false`.
|
||||
|
||||
- `cloud_init_storage_pool` - (string) - Name of the Proxmox storage pool
|
||||
to store the Cloud-Init CDROM on. If not given, the storage pool of the boot device will be used.
|
||||
|
||||
@@ -4,7 +4,6 @@ modeline: |
|
||||
description: |
|
||||
The Qemu Packer builder is able to create KVM virtual machine images.
|
||||
page_title: QEMU - Builders
|
||||
sidebar_title: QEMU
|
||||
---
|
||||
|
||||
# QEMU Builder
|
||||
|
||||
@@ -11,7 +11,6 @@ description: >
|
||||
|
||||
servers that are launched within Scaleway.
|
||||
page_title: Scaleway - Builders
|
||||
sidebar_title: Scaleway
|
||||
---
|
||||
|
||||
# Scaleway Builder
|
||||
@@ -70,6 +69,7 @@ access tokens:
|
||||
"ssh_private_key_file": "~/.ssh/id_rsa"
|
||||
}
|
||||
```
|
||||
|
||||
</Tab>
|
||||
|
||||
<Tab heading="HCL2">
|
||||
@@ -86,10 +86,10 @@ builders "scaleway" {
|
||||
ssh_private_key_file = "~/.ssh/id_rsa"
|
||||
}
|
||||
```
|
||||
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
||||
|
||||
When you do not specify the `ssh_private_key_file`, a temporary SSH keypair
|
||||
is generated to connect the server. This key will only allow the `root` user to
|
||||
connect the server.
|
||||
|
||||
@@ -3,7 +3,6 @@ description: |
|
||||
The `tencentcloud-cvm` Packer builder plugin provide the capability to build
|
||||
customized images based on an existing base images.
|
||||
page_title: Tencentcloud Image Builder
|
||||
sidebar_title: Tencent Cloud
|
||||
---
|
||||
|
||||
# Tencentcloud Image Builder
|
||||
|
||||
@@ -10,7 +10,6 @@ description: >
|
||||
|
||||
Cloud API to create images.
|
||||
page_title: Triton - Builders
|
||||
sidebar_title: Triton
|
||||
---
|
||||
|
||||
# Triton Builder
|
||||
|
||||
@@ -3,7 +3,6 @@ description: |
|
||||
The `ucloud-uhost` Packer builder plugin provides the capability to build
|
||||
customized images based on an existing base image for use in UHost Instance.
|
||||
page_title: UCloud Image Builder
|
||||
sidebar_title: UCloud
|
||||
---
|
||||
|
||||
# UCloud Image Builder
|
||||
|
||||
@@ -3,7 +3,6 @@ description: |
|
||||
The Vagrant Packer builder is able to launch Vagrant boxes and
|
||||
re-package them into .box files
|
||||
page_title: Vagrant - Builders
|
||||
sidebar_title: Vagrant
|
||||
---
|
||||
|
||||
# Vagrant Builder
|
||||
@@ -185,13 +184,13 @@ build {
|
||||
|
||||
## Regarding output directory and new box
|
||||
|
||||
After Packer completes building and provisioning a new Vagrant Box file, it is worth
|
||||
noting that the new box file will need to be added to Vagrant. For a beginner to Packer
|
||||
After Packer completes building and provisioning a new Vagrant Box file, it is worth
|
||||
noting that the new box file will need to be added to Vagrant. For a beginner to Packer
|
||||
and Vagrant, it may seem as if a simple 'vagrant up' in the output directory will run the
|
||||
the newly created Box. This is not the case.
|
||||
the newly created Box. This is not the case.
|
||||
|
||||
Rather, create a new directory (to avoid Vagarant init collisions), add the new
|
||||
package.box to Vagrant and init. Then run vagrant up to bring up the new box created
|
||||
Rather, create a new directory (to avoid Vagarant init collisions), add the new
|
||||
package.box to Vagrant and init. Then run vagrant up to bring up the new box created
|
||||
by Packer. You will now be able to connect to the new box with provisioned changes.
|
||||
|
||||
```
|
||||
|
||||
@@ -5,7 +5,6 @@ description: >
|
||||
|
||||
export them in the OVA or OVF format.
|
||||
page_title: VirtualBox - Builders
|
||||
sidebar_title: VirtualBox
|
||||
---
|
||||
|
||||
# VirtualBox Builder
|
||||
|
||||
@@ -5,7 +5,6 @@ description: |
|
||||
The VirtualBox Packer builder is able to create VirtualBox virtual machines
|
||||
and export them in the OVF format, starting from an ISO image.
|
||||
page_title: VirtualBox ISO - Builders
|
||||
sidebar_title: ISO
|
||||
---
|
||||
|
||||
# VirtualBox Builder (from an ISO)
|
||||
|
||||
@@ -6,7 +6,6 @@ description: |
|
||||
and export them in the OVF format, starting from an existing OVF/OVA (exported
|
||||
virtual machine image).
|
||||
page_title: VirtualBox OVF/OVA - Builders
|
||||
sidebar_title: OVF
|
||||
---
|
||||
|
||||
# VirtualBox Builder (from an OVF/OVA)
|
||||
|
||||
@@ -7,7 +7,6 @@ description: >
|
||||
|
||||
and export them in the OVF format, starting from an ISO image.
|
||||
page_title: VirtualBox Snapshot - Builders
|
||||
sidebar_title: VM
|
||||
---
|
||||
|
||||
# VirtualBox Builder (from an existing VM)
|
||||
|
||||
@@ -3,7 +3,6 @@ description: |
|
||||
The VMware Packer builder is able to create VMware virtual machines for use
|
||||
with any VMware product.
|
||||
page_title: VMware - Builders
|
||||
sidebar_title: VMware
|
||||
---
|
||||
|
||||
# VMware Builder
|
||||
|
||||
@@ -8,7 +8,6 @@ description: |
|
||||
VMware Player on Linux. It can also build machines directly on VMware vSphere
|
||||
Hypervisor using SSH as opposed to the vSphere API.
|
||||
page_title: VMware ISO - Builders
|
||||
sidebar_title: VMWare ISO
|
||||
---
|
||||
|
||||
# VMware Builder (from ISO)
|
||||
|
||||
@@ -7,7 +7,6 @@ description: |
|
||||
virtual machines on hosts running VMware Fusion Professional for OS X, VMware
|
||||
Workstation for Linux and Windows, and VMware Player on Linux.
|
||||
page_title: VMware VMX - Builders
|
||||
sidebar_title: VMWare VMX
|
||||
---
|
||||
|
||||
# VMware Builder (from VMX)
|
||||
|
||||
@@ -5,7 +5,6 @@ description: >
|
||||
This VMware Packer builder uses the vSphere API to clone an existing vSphere
|
||||
template and create a new virtual machine remotely.
|
||||
page_title: VSphere Clone - Builders
|
||||
sidebar_title: VSphere Clone
|
||||
---
|
||||
|
||||
# VMWare Vsphere Clone Builder
|
||||
|
||||
@@ -5,7 +5,6 @@ description: |
|
||||
This VMware Packer builder starts from an ISO and creates a vm using the
|
||||
vSphere API to build on a remote VMWare machine.
|
||||
page_title: VSphere ISO - Builders
|
||||
sidebar_title: VSphere ISO
|
||||
---
|
||||
|
||||
# Packer Builder for VMware vSphere
|
||||
|
||||
@@ -3,7 +3,6 @@ description: |
|
||||
The yandex Packer builder is able to create images for use with
|
||||
Yandex.Cloud based on existing images.
|
||||
page_title: Yandex Compute - Builders
|
||||
sidebar_title: Yandex.Cloud
|
||||
---
|
||||
|
||||
# Yandex Compute Builder
|
||||
|
||||
@@ -5,7 +5,6 @@ description: |
|
||||
template are executed in parallel, unless otherwise specified. And the
|
||||
artifacts that are created will be outputted at the end of the build.
|
||||
page_title: packer build - Commands
|
||||
sidebar_title: <tt>build</tt>
|
||||
---
|
||||
|
||||
# `build` Command
|
||||
|
||||
@@ -3,7 +3,6 @@ description: |
|
||||
The `packer console` command allows you to experiment with Packer variable
|
||||
interpolations.
|
||||
page_title: packer console - Commands
|
||||
sidebar_title: <tt>console</tt>
|
||||
---
|
||||
|
||||
# `console` Command
|
||||
|
||||
@@ -5,7 +5,6 @@ description: |
|
||||
of Packer. After you update to a new Packer release, you should run the fix
|
||||
command to make sure your templates work with the new release.
|
||||
page_title: packer fix - Commands
|
||||
sidebar_title: <tt>fix</tt>
|
||||
---
|
||||
|
||||
# `fix` Command
|
||||
|
||||
@@ -3,7 +3,6 @@ description: |
|
||||
The `packer fmt` Packer command is used to format HCL2
|
||||
configuration files to a canonical format and style.
|
||||
page_title: packer fmt - Commands
|
||||
sidebar_title: <tt>fmt</tt>
|
||||
---
|
||||
|
||||
# `fmt` Command
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
---
|
||||
description: |
|
||||
The `packer hcl2_upgrade` Packer command is used to transpile a JSON
|
||||
configuration template to it's formatted HCL2 counterpart. The command will
|
||||
configuration template to its formatted HCL2 counterpart. The command will
|
||||
return a zero exit status on success, and a non-zero exit status on failure.
|
||||
page_title: packer hcl2_upgrade - Commands
|
||||
sidebar_title: <tt>hcl2_upgrade</tt>
|
||||
---
|
||||
|
||||
-> **Note:** This command is Beta, and currently being improved upon; do not
|
||||
@@ -35,16 +34,13 @@ From **v1.7.1**, the `hcl2_upgrade` command can upgrade a variables file.
|
||||
|
||||
```json
|
||||
{
|
||||
"variables": {
|
||||
"aws_region": null,
|
||||
"aws_secondary_region": "{{ env `AWS_DEFAULT_REGION` }}",
|
||||
"aws_secret_key": "",
|
||||
"aws_access_key": "",
|
||||
},
|
||||
"sensitive-variables": [
|
||||
"aws_secret_key",
|
||||
"aws_access_key",
|
||||
]
|
||||
"variables": {
|
||||
"aws_region": null,
|
||||
"aws_secondary_region": "{{ env `AWS_DEFAULT_REGION` }}",
|
||||
"aws_secret_key": "",
|
||||
"aws_access_key": ""
|
||||
},
|
||||
"sensitive-variables": ["aws_secret_key", "aws_access_key"]
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -6,7 +6,6 @@ description: |
|
||||
additional options as well. Subcommands are executed with `packer SUBCOMMAND`,
|
||||
where "SUBCOMMAND" is the actual command you wish to execute.
|
||||
page_title: Commands
|
||||
sidebar_title: Commands (CLI)
|
||||
---
|
||||
|
||||
# Packer Commands (CLI)
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
description: |
|
||||
The `packer init` Packer command is used to download Packer plugin binaries.
|
||||
page_title: packer init - Commands
|
||||
sidebar_title: <tt>init</tt>
|
||||
---
|
||||
|
||||
# `init` Command
|
||||
@@ -37,7 +36,6 @@ for the ones that are missing.
|
||||
|
||||
`packer init -upgrade` will try to get the latest versions for all plugins.
|
||||
|
||||
|
||||
Import a plugin using the [`required_plugin`](/docs/templates/hcl_templates/blocks/packer#specifying-plugin-requirements)
|
||||
block :
|
||||
|
||||
@@ -55,6 +53,7 @@ packer {
|
||||
HashiCorp does not officially verify third party Packer plugins, plugins not under the HashiCorp namespace `hashicorp/*`; as with all open source tools, please do your own due diligence when using a new tool.
|
||||
|
||||
## Plugin Selection
|
||||
|
||||
Plugin selection depends on the source and version constraints defined within the `required_plugins` block.
|
||||
For each of the required plugins Packer will query the source repository `github.com/azr/happycloud` whose fully qualified address
|
||||
is `https://github.com/azr/packer-plugin-happycloud` for a plugin matching the version constraints for the host operating system.
|
||||
|
||||
@@ -11,7 +11,6 @@ description: >
|
||||
|
||||
provisioners it defines and the order they'll run, and more.
|
||||
page_title: packer inspect - Commands
|
||||
sidebar_title: <tt>inspect</tt>
|
||||
---
|
||||
|
||||
# `inspect` Command
|
||||
|
||||
@@ -5,7 +5,6 @@ description: |
|
||||
success, and a non-zero exit status on failure. Additionally, if a template
|
||||
doesn't validate, any error messages will be outputted.
|
||||
page_title: packer validate - Commands
|
||||
sidebar_title: <tt>validate</tt>
|
||||
---
|
||||
|
||||
# `validate` Command
|
||||
|
||||
@@ -3,7 +3,6 @@ description: |
|
||||
Communicators are the mechanism Packer uses to upload files, execute
|
||||
scripts, etc. with the machine being created.
|
||||
page_title: Communicators
|
||||
sidebar_title: Communicators
|
||||
---
|
||||
|
||||
# Communicators
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user