From 0f4d81e0917c51257d4d746c607f806913376356 Mon Sep 17 00:00:00 2001 From: Sumit Kalra <44450797+sumit-kalra@users.noreply.github.com> Date: Tue, 24 Sep 2019 09:34:19 -0700 Subject: [PATCH 001/155] Adding config to specify allowed inbound IP addresses and CIDR blocks (#1) * Adding config to specify allowed inbound IP addresses * Also allowing CIDR blocks in addition to IP addresses --- builder/azure/arm/config.go | 29 +++++- builder/azure/arm/config_test.go | 102 +++++++++++++++++++++ website/source/docs/builders/azure.html.md | 5 + 3 files changed, 131 insertions(+), 5 deletions(-) diff --git a/builder/azure/arm/config.go b/builder/azure/arm/config.go index 5e9b8905c..aafd1bca4 100644 --- a/builder/azure/arm/config.go +++ b/builder/azure/arm/config.go @@ -10,6 +10,7 @@ import ( "fmt" "io/ioutil" "math/big" + "net" "regexp" "strings" "time" @@ -129,11 +130,12 @@ type Config struct { TempResourceGroupName string `mapstructure:"temp_resource_group_name"` BuildResourceGroupName string `mapstructure:"build_resource_group_name"` storageAccountBlobEndpoint string - PrivateVirtualNetworkWithPublicIp bool `mapstructure:"private_virtual_network_with_public_ip"` - VirtualNetworkName string `mapstructure:"virtual_network_name"` - VirtualNetworkSubnetName string `mapstructure:"virtual_network_subnet_name"` - VirtualNetworkResourceGroupName string `mapstructure:"virtual_network_resource_group_name"` - CustomDataFile string `mapstructure:"custom_data_file"` + PrivateVirtualNetworkWithPublicIp bool `mapstructure:"private_virtual_network_with_public_ip"` + VirtualNetworkName string `mapstructure:"virtual_network_name"` + VirtualNetworkSubnetName string `mapstructure:"virtual_network_subnet_name"` + VirtualNetworkResourceGroupName string `mapstructure:"virtual_network_resource_group_name"` + AllowedInboundIpAddresses []string `mapstructure:"allowed_inbound_ip_addresses"` + CustomDataFile string `mapstructure:"custom_data_file"` customData string PlanInfo PlanInformation `mapstructure:"plan_info"` @@ -673,6 +675,12 @@ func assertRequiredParametersSet(c *Config, errs *packer.MultiError) { errs = packer.MultiErrorAppend(errs, fmt.Errorf("If virtual_network_subnet_name is specified, so must virtual_network_name")) } + if c.AllowedInboundIpAddresses != nil && len(c.AllowedInboundIpAddresses) >= 1 { + if ok, err := assertAllowedInboundIpAddresses(c.AllowedInboundIpAddresses, "allowed_inbound_ip_addresses"); !ok { + errs = packer.MultiErrorAppend(errs, err) + } + } + ///////////////////////////////////////////// // Plan Info if c.PlanInfo.PlanName != "" || c.PlanInfo.PlanProduct != "" || c.PlanInfo.PlanPublisher != "" || c.PlanInfo.PlanPromotionCode != "" { @@ -744,6 +752,17 @@ func assertManagedImageDataDiskSnapshotName(name, setting string) (bool, error) return true, nil } +func assertAllowedInboundIpAddresses(ipAddresses []string, setting string) (bool, error) { + for _, ipAddress := range ipAddresses { + if net.ParseIP(ipAddress) == nil { + if _, _, err := net.ParseCIDR(ipAddress); err != nil { + return false, fmt.Errorf("The setting %s must only contain valid IP addresses or CIDR blocks", setting) + } + } + } + return true, nil +} + func assertResourceGroupName(rgn, setting string) (bool, error) { if !isValidAzureName(reResourceGroupName, rgn) { return false, fmt.Errorf("The setting %s must match the regular expression %q, and not end with a '-' or '.'.", setting, validResourceGroupNameRe) diff --git a/builder/azure/arm/config_test.go b/builder/azure/arm/config_test.go index ef5c9fb93..9175c3d26 100644 --- a/builder/azure/arm/config_test.go +++ b/builder/azure/arm/config_test.go @@ -270,6 +270,108 @@ func TestConfigVirtualNetworkSubnetNameMustBeSetWithVirtualNetworkName(t *testin } } +func TestConfigAllowedInboundIpAddressesIsOptional(t *testing.T) { + config := map[string]string{ + "capture_name_prefix": "ignore", + "capture_container_name": "ignore", + "location": "ignore", + "image_url": "ignore", + "storage_account": "ignore", + "resource_group_name": "ignore", + "subscription_id": "ignore", + "os_type": constants.Target_Linux, + "communicator": "none", + "virtual_network_name": "MyVirtualNetwork", + } + + c, _, err := newConfig(config, getPackerConfiguration()) + if err != nil { + t.Fatal(err) + } + if c.AllowedInboundIpAddresses != nil { + t.Errorf("Expected Config to set allowed_inbound_ip_addresses to nil, but got %v", c.AllowedInboundIpAddresses) + } +} + +func TestConfigShouldAcceptCorrectInboundIpAddresses(t *testing.T) { + ipValue0 := "127.0.0.1" + ipValue1 := "127.0.0.2" + cidrValue2 := "192.168.100.0/24" + cidrValue3 := "10.10.1.16/32" + config := map[string]interface{}{ + "capture_name_prefix": "ignore", + "capture_container_name": "ignore", + "location": "ignore", + "image_url": "ignore", + "storage_account": "ignore", + "resource_group_name": "ignore", + "subscription_id": "ignore", + "os_type": constants.Target_Linux, + "communicator": "none", + "virtual_network_name": "MyVirtualNetwork", + } + + config["allowed_inbound_ip_addresses"] = ipValue0 + c, _, err := newConfig(config, getPackerConfiguration()) + if err != nil { + t.Fatal(err) + } + if c.AllowedInboundIpAddresses == nil || len(c.AllowedInboundIpAddresses) != 1 || + c.AllowedInboundIpAddresses[0] != ipValue0 { + t.Errorf("Expected 'allowed_inbound_ip_addresses' to have one element (%s), but got '%v'.", ipValue0, c.AllowedInboundIpAddresses) + } + + config["allowed_inbound_ip_addresses"] = cidrValue2 + c, _, err = newConfig(config, getPackerConfiguration()) + if err != nil { + t.Fatal(err) + } + if c.AllowedInboundIpAddresses == nil || len(c.AllowedInboundIpAddresses) != 1 || + c.AllowedInboundIpAddresses[0] != cidrValue2 { + t.Errorf("Expected 'allowed_inbound_ip_addresses' to have one element (%s), but got '%v'.", cidrValue2, c.AllowedInboundIpAddresses) + } + + config["allowed_inbound_ip_addresses"] = []string{ipValue0, cidrValue2, ipValue1, cidrValue3} + c, _, err = newConfig(config, getPackerConfiguration()) + if err != nil { + t.Fatal(err) + } + if c.AllowedInboundIpAddresses == nil || len(c.AllowedInboundIpAddresses) != 4 || + c.AllowedInboundIpAddresses[0] != ipValue0 || c.AllowedInboundIpAddresses[1] != cidrValue2 || + c.AllowedInboundIpAddresses[2] != ipValue1 || c.AllowedInboundIpAddresses[3] != cidrValue3 { + t.Errorf("Expected 'allowed_inbound_ip_addresses' to have four elements (%s %s %s %s), but got '%v'.", ipValue0, cidrValue2, ipValue1, + cidrValue3, c.AllowedInboundIpAddresses) + } +} + +func TestConfigShouldRejectIncorrectInboundIpAddresses(t *testing.T) { + config := map[string]interface{}{ + "capture_name_prefix": "ignore", + "capture_container_name": "ignore", + "location": "ignore", + "image_url": "ignore", + "storage_account": "ignore", + "resource_group_name": "ignore", + "subscription_id": "ignore", + "os_type": constants.Target_Linux, + "communicator": "none", + "virtual_network_name": "MyVirtualNetwork", + } + + config["allowed_inbound_ip_addresses"] = []string{"127.0.0.1", "127.0.0.two"} + c, _, err := newConfig(config, getPackerConfiguration()) + if err == nil { + t.Errorf("Expected configuration creation to fail, but it succeeded with the malformed allowed_inbound_ip_addresses set to %v", c.AllowedInboundIpAddresses) + } + + config["allowed_inbound_ip_addresses"] = []string{"192.168.100.1000/24", "10.10.1.16/32"} + c, _, err = newConfig(config, getPackerConfiguration()) + if err == nil { + // 192.168.100.1000/24 is invalid + t.Errorf("Expected configuration creation to fail, but it succeeded with the malformed allowed_inbound_ip_addresses set to %v", c.AllowedInboundIpAddresses) + } +} + func TestConfigShouldDefaultToPublicCloud(t *testing.T) { c, _, _ := newConfig(getArmBuilderConfiguration(), getPackerConfiguration()) diff --git a/website/source/docs/builders/azure.html.md b/website/source/docs/builders/azure.html.md index aa741d675..37c62eda1 100644 --- a/website/source/docs/builders/azure.html.md +++ b/website/source/docs/builders/azure.html.md @@ -336,6 +336,11 @@ Providing `temp_resource_group_name` or `location` in combination with containing the virtual network. If the resource group cannot be found, or it cannot be disambiguated, this value should be set. +- `allowed_inbound_ip_addresses` (array of strings) list of IP addresses and + CIDR blocks that should be allowed access to the VM. If provided, an Azure + Network Security Group will be created with corresponding rules and be bound + to the NIC attached to the VM. + - `virtual_network_subnet_name` (string) If virtual\_network\_name is set, this value **may** also be set. If virtual\_network\_name is set, and this value is not set the builder attempts to determine the subnet to use with From 45840ffc3fd8be633f4a8eed3e7ba4a1f568f0a1 Mon Sep 17 00:00:00 2001 From: Sumit Kalra <44450797+sumit-kalra@users.noreply.github.com> Date: Thu, 26 Sep 2019 15:35:55 -0700 Subject: [PATCH 002/155] Ensuring that specifying allowed inbound IP and VNet are mutually exclusive (#2) --- builder/azure/arm/config.go | 8 +++++-- builder/azure/arm/config_test.go | 28 ++++++++++++++++++++-- website/source/docs/builders/azure.html.md | 3 +++ 3 files changed, 35 insertions(+), 4 deletions(-) diff --git a/builder/azure/arm/config.go b/builder/azure/arm/config.go index aafd1bca4..9e7234e09 100644 --- a/builder/azure/arm/config.go +++ b/builder/azure/arm/config.go @@ -676,8 +676,12 @@ func assertRequiredParametersSet(c *Config, errs *packer.MultiError) { } if c.AllowedInboundIpAddresses != nil && len(c.AllowedInboundIpAddresses) >= 1 { - if ok, err := assertAllowedInboundIpAddresses(c.AllowedInboundIpAddresses, "allowed_inbound_ip_addresses"); !ok { - errs = packer.MultiErrorAppend(errs, err) + if c.VirtualNetworkName != "" { + errs = packer.MultiErrorAppend(errs, fmt.Errorf("If virtual_network_name is specified, allowed_inbound_ip_addresses cannot be specified")) + } else { + if ok, err := assertAllowedInboundIpAddresses(c.AllowedInboundIpAddresses, "allowed_inbound_ip_addresses"); !ok { + errs = packer.MultiErrorAppend(errs, err) + } } } diff --git a/builder/azure/arm/config_test.go b/builder/azure/arm/config_test.go index 9175c3d26..a3617dc19 100644 --- a/builder/azure/arm/config_test.go +++ b/builder/azure/arm/config_test.go @@ -308,7 +308,6 @@ func TestConfigShouldAcceptCorrectInboundIpAddresses(t *testing.T) { "subscription_id": "ignore", "os_type": constants.Target_Linux, "communicator": "none", - "virtual_network_name": "MyVirtualNetwork", } config["allowed_inbound_ip_addresses"] = ipValue0 @@ -355,7 +354,6 @@ func TestConfigShouldRejectIncorrectInboundIpAddresses(t *testing.T) { "subscription_id": "ignore", "os_type": constants.Target_Linux, "communicator": "none", - "virtual_network_name": "MyVirtualNetwork", } config["allowed_inbound_ip_addresses"] = []string{"127.0.0.1", "127.0.0.two"} @@ -372,6 +370,32 @@ func TestConfigShouldRejectIncorrectInboundIpAddresses(t *testing.T) { } } +func TestConfigShouldRejectInboundIpAddressesWithVirtualNetwork(t *testing.T) { + config := map[string]interface{}{ + "capture_name_prefix": "ignore", + "capture_container_name": "ignore", + "location": "ignore", + "image_url": "ignore", + "storage_account": "ignore", + "resource_group_name": "ignore", + "subscription_id": "ignore", + "os_type": constants.Target_Linux, + "communicator": "none", + "allowed_inbound_ip_addresses": "127.0.0.1", + } + + _, _, err := newConfig(config, getPackerConfiguration()) + if err != nil { + t.Fatal(err) + } + + config["virtual_network_name"] = "some_vnet_name" + _, _, err = newConfig(config, getPackerConfiguration()) + if err == nil { + t.Errorf("Expected configuration creation to fail, but it succeeded with allowed_inbound_ip_addresses and virtual_network_name both specified") + } +} + func TestConfigShouldDefaultToPublicCloud(t *testing.T) { c, _, _ := newConfig(getArmBuilderConfiguration(), getPackerConfiguration()) diff --git a/website/source/docs/builders/azure.html.md b/website/source/docs/builders/azure.html.md index 37c62eda1..6b6c09218 100644 --- a/website/source/docs/builders/azure.html.md +++ b/website/source/docs/builders/azure.html.md @@ -341,6 +341,9 @@ Providing `temp_resource_group_name` or `location` in combination with Network Security Group will be created with corresponding rules and be bound to the NIC attached to the VM. + Providing `allowed_inbound_ip_addresses` in combination with + `virtual_network_name` is not allowed. + - `virtual_network_subnet_name` (string) If virtual\_network\_name is set, this value **may** also be set. If virtual\_network\_name is set, and this value is not set the builder attempts to determine the subnet to use with From 132779c343676568778c56de6b4438664e55ab16 Mon Sep 17 00:00:00 2001 From: Sumit Kalra <44450797+sumit-kalra@users.noreply.github.com> Date: Tue, 24 Sep 2019 09:34:19 -0700 Subject: [PATCH 003/155] Adding config to specify allowed inbound IP addresses and CIDR blocks (#1) * Adding config to specify allowed inbound IP addresses * Also allowing CIDR blocks in addition to IP addresses --- builder/azure/arm/config.go | 23 +++++++ builder/azure/arm/config_test.go | 102 +++++++++++++++++++++++++++++++ 2 files changed, 125 insertions(+) diff --git a/builder/azure/arm/config.go b/builder/azure/arm/config.go index 7243bd2a8..6744287cc 100644 --- a/builder/azure/arm/config.go +++ b/builder/azure/arm/config.go @@ -12,6 +12,7 @@ import ( "fmt" "io/ioutil" "math/big" + "net" "regexp" "strings" "time" @@ -342,6 +343,11 @@ type Config struct { // are None, ReadOnly, and ReadWrite. The default value is ReadWrite. DiskCachingType string `mapstructure:"disk_caching_type" required:"false"` diskCachingType compute.CachingTypes + // Specify the list of IP addresses and CIDR blocks that should be + // allowed access to the VM. If provided, an Azure Network Security + // Group will be created with corresponding rules and be bound to + // the NIC attached to the VM. + AllowedInboundIpAddresses []string `mapstructure:"allowed_inbound_ip_addresses"` // Runtime Values UserName string @@ -872,6 +878,12 @@ func assertRequiredParametersSet(c *Config, errs *packer.MultiError) { errs = packer.MultiErrorAppend(errs, fmt.Errorf("If virtual_network_subnet_name is specified, so must virtual_network_name")) } + if c.AllowedInboundIpAddresses != nil && len(c.AllowedInboundIpAddresses) >= 1 { + if ok, err := assertAllowedInboundIpAddresses(c.AllowedInboundIpAddresses, "allowed_inbound_ip_addresses"); !ok { + errs = packer.MultiErrorAppend(errs, err) + } + } + ///////////////////////////////////////////// // Plan Info if c.PlanInfo.PlanName != "" || c.PlanInfo.PlanProduct != "" || c.PlanInfo.PlanPublisher != "" || c.PlanInfo.PlanPromotionCode != "" { @@ -943,6 +955,17 @@ func assertManagedImageDataDiskSnapshotName(name, setting string) (bool, error) return true, nil } +func assertAllowedInboundIpAddresses(ipAddresses []string, setting string) (bool, error) { + for _, ipAddress := range ipAddresses { + if net.ParseIP(ipAddress) == nil { + if _, _, err := net.ParseCIDR(ipAddress); err != nil { + return false, fmt.Errorf("The setting %s must only contain valid IP addresses or CIDR blocks", setting) + } + } + } + return true, nil +} + func assertResourceGroupName(rgn, setting string) (bool, error) { if !isValidAzureName(reResourceGroupName, rgn) { return false, fmt.Errorf("The setting %s must match the regular expression %q, and not end with a '-' or '.'.", setting, validResourceGroupNameRe) diff --git a/builder/azure/arm/config_test.go b/builder/azure/arm/config_test.go index 9ed25fffa..ce446b246 100644 --- a/builder/azure/arm/config_test.go +++ b/builder/azure/arm/config_test.go @@ -270,6 +270,108 @@ func TestConfigVirtualNetworkSubnetNameMustBeSetWithVirtualNetworkName(t *testin } } +func TestConfigAllowedInboundIpAddressesIsOptional(t *testing.T) { + config := map[string]string{ + "capture_name_prefix": "ignore", + "capture_container_name": "ignore", + "location": "ignore", + "image_url": "ignore", + "storage_account": "ignore", + "resource_group_name": "ignore", + "subscription_id": "ignore", + "os_type": constants.Target_Linux, + "communicator": "none", + "virtual_network_name": "MyVirtualNetwork", + } + + c, _, err := newConfig(config, getPackerConfiguration()) + if err != nil { + t.Fatal(err) + } + if c.AllowedInboundIpAddresses != nil { + t.Errorf("Expected Config to set allowed_inbound_ip_addresses to nil, but got %v", c.AllowedInboundIpAddresses) + } +} + +func TestConfigShouldAcceptCorrectInboundIpAddresses(t *testing.T) { + ipValue0 := "127.0.0.1" + ipValue1 := "127.0.0.2" + cidrValue2 := "192.168.100.0/24" + cidrValue3 := "10.10.1.16/32" + config := map[string]interface{}{ + "capture_name_prefix": "ignore", + "capture_container_name": "ignore", + "location": "ignore", + "image_url": "ignore", + "storage_account": "ignore", + "resource_group_name": "ignore", + "subscription_id": "ignore", + "os_type": constants.Target_Linux, + "communicator": "none", + "virtual_network_name": "MyVirtualNetwork", + } + + config["allowed_inbound_ip_addresses"] = ipValue0 + c, _, err := newConfig(config, getPackerConfiguration()) + if err != nil { + t.Fatal(err) + } + if c.AllowedInboundIpAddresses == nil || len(c.AllowedInboundIpAddresses) != 1 || + c.AllowedInboundIpAddresses[0] != ipValue0 { + t.Errorf("Expected 'allowed_inbound_ip_addresses' to have one element (%s), but got '%v'.", ipValue0, c.AllowedInboundIpAddresses) + } + + config["allowed_inbound_ip_addresses"] = cidrValue2 + c, _, err = newConfig(config, getPackerConfiguration()) + if err != nil { + t.Fatal(err) + } + if c.AllowedInboundIpAddresses == nil || len(c.AllowedInboundIpAddresses) != 1 || + c.AllowedInboundIpAddresses[0] != cidrValue2 { + t.Errorf("Expected 'allowed_inbound_ip_addresses' to have one element (%s), but got '%v'.", cidrValue2, c.AllowedInboundIpAddresses) + } + + config["allowed_inbound_ip_addresses"] = []string{ipValue0, cidrValue2, ipValue1, cidrValue3} + c, _, err = newConfig(config, getPackerConfiguration()) + if err != nil { + t.Fatal(err) + } + if c.AllowedInboundIpAddresses == nil || len(c.AllowedInboundIpAddresses) != 4 || + c.AllowedInboundIpAddresses[0] != ipValue0 || c.AllowedInboundIpAddresses[1] != cidrValue2 || + c.AllowedInboundIpAddresses[2] != ipValue1 || c.AllowedInboundIpAddresses[3] != cidrValue3 { + t.Errorf("Expected 'allowed_inbound_ip_addresses' to have four elements (%s %s %s %s), but got '%v'.", ipValue0, cidrValue2, ipValue1, + cidrValue3, c.AllowedInboundIpAddresses) + } +} + +func TestConfigShouldRejectIncorrectInboundIpAddresses(t *testing.T) { + config := map[string]interface{}{ + "capture_name_prefix": "ignore", + "capture_container_name": "ignore", + "location": "ignore", + "image_url": "ignore", + "storage_account": "ignore", + "resource_group_name": "ignore", + "subscription_id": "ignore", + "os_type": constants.Target_Linux, + "communicator": "none", + "virtual_network_name": "MyVirtualNetwork", + } + + config["allowed_inbound_ip_addresses"] = []string{"127.0.0.1", "127.0.0.two"} + c, _, err := newConfig(config, getPackerConfiguration()) + if err == nil { + t.Errorf("Expected configuration creation to fail, but it succeeded with the malformed allowed_inbound_ip_addresses set to %v", c.AllowedInboundIpAddresses) + } + + config["allowed_inbound_ip_addresses"] = []string{"192.168.100.1000/24", "10.10.1.16/32"} + c, _, err = newConfig(config, getPackerConfiguration()) + if err == nil { + // 192.168.100.1000/24 is invalid + t.Errorf("Expected configuration creation to fail, but it succeeded with the malformed allowed_inbound_ip_addresses set to %v", c.AllowedInboundIpAddresses) + } +} + func TestConfigShouldDefaultToPublicCloud(t *testing.T) { c, _, _ := newConfig(getArmBuilderConfiguration(), getPackerConfiguration()) From 91d19adcd7ea9eb1c154ea514301740060bc7e83 Mon Sep 17 00:00:00 2001 From: Sumit Kalra <44450797+sumit-kalra@users.noreply.github.com> Date: Thu, 26 Sep 2019 15:35:55 -0700 Subject: [PATCH 004/155] Ensuring that specifying allowed inbound IP and VNet are mutually exclusive (#2) --- builder/azure/arm/config.go | 8 ++++++-- builder/azure/arm/config_test.go | 28 ++++++++++++++++++++++++++-- 2 files changed, 32 insertions(+), 4 deletions(-) diff --git a/builder/azure/arm/config.go b/builder/azure/arm/config.go index 6744287cc..eef7599a0 100644 --- a/builder/azure/arm/config.go +++ b/builder/azure/arm/config.go @@ -879,8 +879,12 @@ func assertRequiredParametersSet(c *Config, errs *packer.MultiError) { } if c.AllowedInboundIpAddresses != nil && len(c.AllowedInboundIpAddresses) >= 1 { - if ok, err := assertAllowedInboundIpAddresses(c.AllowedInboundIpAddresses, "allowed_inbound_ip_addresses"); !ok { - errs = packer.MultiErrorAppend(errs, err) + if c.VirtualNetworkName != "" { + errs = packer.MultiErrorAppend(errs, fmt.Errorf("If virtual_network_name is specified, allowed_inbound_ip_addresses cannot be specified")) + } else { + if ok, err := assertAllowedInboundIpAddresses(c.AllowedInboundIpAddresses, "allowed_inbound_ip_addresses"); !ok { + errs = packer.MultiErrorAppend(errs, err) + } } } diff --git a/builder/azure/arm/config_test.go b/builder/azure/arm/config_test.go index ce446b246..d90e31f44 100644 --- a/builder/azure/arm/config_test.go +++ b/builder/azure/arm/config_test.go @@ -308,7 +308,6 @@ func TestConfigShouldAcceptCorrectInboundIpAddresses(t *testing.T) { "subscription_id": "ignore", "os_type": constants.Target_Linux, "communicator": "none", - "virtual_network_name": "MyVirtualNetwork", } config["allowed_inbound_ip_addresses"] = ipValue0 @@ -355,7 +354,6 @@ func TestConfigShouldRejectIncorrectInboundIpAddresses(t *testing.T) { "subscription_id": "ignore", "os_type": constants.Target_Linux, "communicator": "none", - "virtual_network_name": "MyVirtualNetwork", } config["allowed_inbound_ip_addresses"] = []string{"127.0.0.1", "127.0.0.two"} @@ -372,6 +370,32 @@ func TestConfigShouldRejectIncorrectInboundIpAddresses(t *testing.T) { } } +func TestConfigShouldRejectInboundIpAddressesWithVirtualNetwork(t *testing.T) { + config := map[string]interface{}{ + "capture_name_prefix": "ignore", + "capture_container_name": "ignore", + "location": "ignore", + "image_url": "ignore", + "storage_account": "ignore", + "resource_group_name": "ignore", + "subscription_id": "ignore", + "os_type": constants.Target_Linux, + "communicator": "none", + "allowed_inbound_ip_addresses": "127.0.0.1", + } + + _, _, err := newConfig(config, getPackerConfiguration()) + if err != nil { + t.Fatal(err) + } + + config["virtual_network_name"] = "some_vnet_name" + _, _, err = newConfig(config, getPackerConfiguration()) + if err == nil { + t.Errorf("Expected configuration creation to fail, but it succeeded with allowed_inbound_ip_addresses and virtual_network_name both specified") + } +} + func TestConfigShouldDefaultToPublicCloud(t *testing.T) { c, _, _ := newConfig(getArmBuilderConfiguration(), getPackerConfiguration()) From 70b2d300e6fae83cda07ce845f9c43f3542c9edb Mon Sep 17 00:00:00 2001 From: Robert Neumayer Date: Fri, 27 Sep 2019 14:49:37 +0200 Subject: [PATCH 005/155] Support defined tags for oci builder --- builder/oracle/oci/config.go | 6 +++++- builder/oracle/oci/config_test.go | 3 +++ builder/oracle/oci/driver_oci.go | 1 + website/source/docs/builders/oracle-oci.html.md | 13 +++++++++++++ 4 files changed, 22 insertions(+), 1 deletion(-) diff --git a/builder/oracle/oci/config.go b/builder/oracle/oci/config.go index d83fa6c15..e0681d8e9 100644 --- a/builder/oracle/oci/config.go +++ b/builder/oracle/oci/config.go @@ -63,7 +63,8 @@ type Config struct { SubnetID string `mapstructure:"subnet_ocid"` // Tagging - Tags map[string]string `mapstructure:"tags"` + Tags map[string]string `mapstructure:"tags"` + DefinedTags map[string]map[string]interface{} `mapstructure:"defined_tags"` ctx interpolate.Context } @@ -207,6 +208,9 @@ func NewConfig(raws ...interface{}) (*Config, error) { } } + //if c.DefinedTags != nil { + // } + if c.ImageName == "" { name, err := interpolate.Render("packer-{{timestamp}}", nil) if err != nil { diff --git a/builder/oracle/oci/config_test.go b/builder/oracle/oci/config_test.go index a5b67d384..7084df61a 100644 --- a/builder/oracle/oci/config_test.go +++ b/builder/oracle/oci/config_test.go @@ -32,6 +32,9 @@ func testConfig(accessConfFile *os.File) map[string]interface{} { "metadata": map[string]string{ "key": "value", }, + "defined_tags": map[string]map[string]interface{}{ + "namespace": {"key": "value"}, + }, } } diff --git a/builder/oracle/oci/driver_oci.go b/builder/oracle/oci/driver_oci.go index db0f2fbc1..3f02aaab0 100644 --- a/builder/oracle/oci/driver_oci.go +++ b/builder/oracle/oci/driver_oci.go @@ -81,6 +81,7 @@ func (d *driverOCI) CreateImage(ctx context.Context, id string) (core.Image, err InstanceId: &id, DisplayName: &d.cfg.ImageName, FreeformTags: d.cfg.Tags, + DefinedTags: d.cfg.DefinedTags, }}) if err != nil { diff --git a/website/source/docs/builders/oracle-oci.html.md b/website/source/docs/builders/oracle-oci.html.md index dad452dcc..c931167d4 100644 --- a/website/source/docs/builders/oracle-oci.html.md +++ b/website/source/docs/builders/oracle-oci.html.md @@ -161,6 +161,19 @@ builder. "tag2": "value2" ``` +- `defined_tags` (map of map of strings) - Add one or more defined tags for a given namespace to the resulting + custom image. See [the Oracle + docs](https://docs.cloud.oracle.com/iaas/Content/Identity/Concepts/taggingoverview.htm) + for more details. Example: + +``` {.yaml} +"tags": + "namespace": { + "tag1": "value1", + "tag2": "value2" + } +``` + ## Basic Example Here is a basic example. Note that account specific configuration has been From 7dd579f6301c3322c0f3201c2b1dafd8415540e9 Mon Sep 17 00:00:00 2001 From: Robert Neumayer Date: Mon, 30 Sep 2019 12:17:47 +0200 Subject: [PATCH 006/155] Remove commented code --- builder/oracle/oci/config.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/builder/oracle/oci/config.go b/builder/oracle/oci/config.go index e0681d8e9..014b9d207 100644 --- a/builder/oracle/oci/config.go +++ b/builder/oracle/oci/config.go @@ -208,9 +208,6 @@ func NewConfig(raws ...interface{}) (*Config, error) { } } - //if c.DefinedTags != nil { - // } - if c.ImageName == "" { name, err := interpolate.Render("packer-{{timestamp}}", nil) if err != nil { From 23c320d59e503df08adca4df26aff69681578934 Mon Sep 17 00:00:00 2001 From: larohra Date: Mon, 30 Sep 2019 16:17:22 -0700 Subject: [PATCH 007/155] Increased the default polling duration to 60mins --- builder/azure/arm/azure_client.go | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/builder/azure/arm/azure_client.go b/builder/azure/arm/azure_client.go index ab4330e37..130eba2a0 100644 --- a/builder/azure/arm/azure_client.go +++ b/builder/azure/arm/azure_client.go @@ -139,72 +139,84 @@ func NewAzureClient(subscriptionID, resourceGroupName, storageAccountName string azureClient.DeploymentsClient.RequestInspector = withInspection(maxlen) azureClient.DeploymentsClient.ResponseInspector = byConcatDecorators(byInspecting(maxlen), errorCapture(azureClient)) azureClient.DeploymentsClient.UserAgent = fmt.Sprintf("%s %s", useragent.String(), azureClient.DeploymentsClient.UserAgent) + azureClient.DeploymentsClient.Client.PollingDuration = SharedGalleryTimeout azureClient.DeploymentOperationsClient = resources.NewDeploymentOperationsClientWithBaseURI(cloud.ResourceManagerEndpoint, subscriptionID) azureClient.DeploymentOperationsClient.Authorizer = autorest.NewBearerAuthorizer(servicePrincipalToken) azureClient.DeploymentOperationsClient.RequestInspector = withInspection(maxlen) azureClient.DeploymentOperationsClient.ResponseInspector = byConcatDecorators(byInspecting(maxlen), errorCapture(azureClient)) azureClient.DeploymentOperationsClient.UserAgent = fmt.Sprintf("%s %s", useragent.String(), azureClient.DeploymentOperationsClient.UserAgent) + azureClient.DeploymentOperationsClient.Client.PollingDuration = SharedGalleryTimeout azureClient.DisksClient = compute.NewDisksClientWithBaseURI(cloud.ResourceManagerEndpoint, subscriptionID) azureClient.DisksClient.Authorizer = autorest.NewBearerAuthorizer(servicePrincipalToken) azureClient.DisksClient.RequestInspector = withInspection(maxlen) azureClient.DisksClient.ResponseInspector = byConcatDecorators(byInspecting(maxlen), errorCapture(azureClient)) azureClient.DisksClient.UserAgent = fmt.Sprintf("%s %s", useragent.String(), azureClient.DisksClient.UserAgent) + azureClient.DisksClient.Client.PollingDuration = SharedGalleryTimeout azureClient.GroupsClient = resources.NewGroupsClientWithBaseURI(cloud.ResourceManagerEndpoint, subscriptionID) azureClient.GroupsClient.Authorizer = autorest.NewBearerAuthorizer(servicePrincipalToken) azureClient.GroupsClient.RequestInspector = withInspection(maxlen) azureClient.GroupsClient.ResponseInspector = byConcatDecorators(byInspecting(maxlen), errorCapture(azureClient)) azureClient.GroupsClient.UserAgent = fmt.Sprintf("%s %s", useragent.String(), azureClient.GroupsClient.UserAgent) + azureClient.GroupsClient.Client.PollingDuration = SharedGalleryTimeout azureClient.ImagesClient = compute.NewImagesClientWithBaseURI(cloud.ResourceManagerEndpoint, subscriptionID) azureClient.ImagesClient.Authorizer = autorest.NewBearerAuthorizer(servicePrincipalToken) azureClient.ImagesClient.RequestInspector = withInspection(maxlen) azureClient.ImagesClient.ResponseInspector = byConcatDecorators(byInspecting(maxlen), errorCapture(azureClient)) azureClient.ImagesClient.UserAgent = fmt.Sprintf("%s %s", useragent.String(), azureClient.ImagesClient.UserAgent) + azureClient.ImagesClient.Client.PollingDuration = SharedGalleryTimeout azureClient.InterfacesClient = network.NewInterfacesClientWithBaseURI(cloud.ResourceManagerEndpoint, subscriptionID) azureClient.InterfacesClient.Authorizer = autorest.NewBearerAuthorizer(servicePrincipalToken) azureClient.InterfacesClient.RequestInspector = withInspection(maxlen) azureClient.InterfacesClient.ResponseInspector = byConcatDecorators(byInspecting(maxlen), errorCapture(azureClient)) azureClient.InterfacesClient.UserAgent = fmt.Sprintf("%s %s", useragent.String(), azureClient.InterfacesClient.UserAgent) + azureClient.InterfacesClient.Client.PollingDuration = SharedGalleryTimeout azureClient.SubnetsClient = network.NewSubnetsClientWithBaseURI(cloud.ResourceManagerEndpoint, subscriptionID) azureClient.SubnetsClient.Authorizer = autorest.NewBearerAuthorizer(servicePrincipalToken) azureClient.SubnetsClient.RequestInspector = withInspection(maxlen) azureClient.SubnetsClient.ResponseInspector = byConcatDecorators(byInspecting(maxlen), errorCapture(azureClient)) azureClient.SubnetsClient.UserAgent = fmt.Sprintf("%s %s", useragent.String(), azureClient.SubnetsClient.UserAgent) + azureClient.SubnetsClient.Client.PollingDuration = SharedGalleryTimeout azureClient.VirtualNetworksClient = network.NewVirtualNetworksClientWithBaseURI(cloud.ResourceManagerEndpoint, subscriptionID) azureClient.VirtualNetworksClient.Authorizer = autorest.NewBearerAuthorizer(servicePrincipalToken) azureClient.VirtualNetworksClient.RequestInspector = withInspection(maxlen) azureClient.VirtualNetworksClient.ResponseInspector = byConcatDecorators(byInspecting(maxlen), errorCapture(azureClient)) azureClient.VirtualNetworksClient.UserAgent = fmt.Sprintf("%s %s", useragent.String(), azureClient.VirtualNetworksClient.UserAgent) + azureClient.VirtualNetworksClient.Client.PollingDuration = SharedGalleryTimeout azureClient.PublicIPAddressesClient = network.NewPublicIPAddressesClientWithBaseURI(cloud.ResourceManagerEndpoint, subscriptionID) azureClient.PublicIPAddressesClient.Authorizer = autorest.NewBearerAuthorizer(servicePrincipalToken) azureClient.PublicIPAddressesClient.RequestInspector = withInspection(maxlen) azureClient.PublicIPAddressesClient.ResponseInspector = byConcatDecorators(byInspecting(maxlen), errorCapture(azureClient)) azureClient.PublicIPAddressesClient.UserAgent = fmt.Sprintf("%s %s", useragent.String(), azureClient.PublicIPAddressesClient.UserAgent) + azureClient.PublicIPAddressesClient.Client.PollingDuration = SharedGalleryTimeout azureClient.VirtualMachinesClient = compute.NewVirtualMachinesClientWithBaseURI(cloud.ResourceManagerEndpoint, subscriptionID) azureClient.VirtualMachinesClient.Authorizer = autorest.NewBearerAuthorizer(servicePrincipalToken) azureClient.VirtualMachinesClient.RequestInspector = withInspection(maxlen) azureClient.VirtualMachinesClient.ResponseInspector = byConcatDecorators(byInspecting(maxlen), templateCapture(azureClient), errorCapture(azureClient)) azureClient.VirtualMachinesClient.UserAgent = fmt.Sprintf("%s %s", useragent.String(), azureClient.VirtualMachinesClient.UserAgent) + azureClient.VirtualMachinesClient.Client.PollingDuration = SharedGalleryTimeout azureClient.SnapshotsClient = compute.NewSnapshotsClientWithBaseURI(cloud.ResourceManagerEndpoint, subscriptionID) azureClient.SnapshotsClient.Authorizer = autorest.NewBearerAuthorizer(servicePrincipalToken) azureClient.SnapshotsClient.RequestInspector = withInspection(maxlen) azureClient.SnapshotsClient.ResponseInspector = byConcatDecorators(byInspecting(maxlen), errorCapture(azureClient)) azureClient.SnapshotsClient.UserAgent = fmt.Sprintf("%s %s", useragent.String(), azureClient.SnapshotsClient.UserAgent) + azureClient.SnapshotsClient.Client.PollingDuration = SharedGalleryTimeout azureClient.AccountsClient = armStorage.NewAccountsClientWithBaseURI(cloud.ResourceManagerEndpoint, subscriptionID) azureClient.AccountsClient.Authorizer = autorest.NewBearerAuthorizer(servicePrincipalToken) azureClient.AccountsClient.RequestInspector = withInspection(maxlen) azureClient.AccountsClient.ResponseInspector = byConcatDecorators(byInspecting(maxlen), errorCapture(azureClient)) azureClient.AccountsClient.UserAgent = fmt.Sprintf("%s %s", useragent.String(), azureClient.AccountsClient.UserAgent) + azureClient.AccountsClient.Client.PollingDuration = SharedGalleryTimeout azureClient.GalleryImageVersionsClient = newCompute.NewGalleryImageVersionsClientWithBaseURI(cloud.ResourceManagerEndpoint, subscriptionID) azureClient.GalleryImageVersionsClient.Authorizer = autorest.NewBearerAuthorizer(servicePrincipalToken) @@ -218,6 +230,7 @@ func NewAzureClient(subscriptionID, resourceGroupName, storageAccountName string azureClient.GalleryImagesClient.RequestInspector = withInspection(maxlen) azureClient.GalleryImagesClient.ResponseInspector = byConcatDecorators(byInspecting(maxlen), errorCapture(azureClient)) azureClient.GalleryImagesClient.UserAgent = fmt.Sprintf("%s %s", useragent.String(), azureClient.GalleryImagesClient.UserAgent) + azureClient.GalleryImageVersionsClient.Client.PollingDuration = SharedGalleryTimeout keyVaultURL, err := url.Parse(cloud.KeyVaultEndpoint) if err != nil { @@ -229,6 +242,7 @@ func NewAzureClient(subscriptionID, resourceGroupName, storageAccountName string azureClient.VaultClient.RequestInspector = withInspection(maxlen) azureClient.VaultClient.ResponseInspector = byConcatDecorators(byInspecting(maxlen), errorCapture(azureClient)) azureClient.VaultClient.UserAgent = fmt.Sprintf("%s %s", useragent.String(), azureClient.VaultClient.UserAgent) + azureClient.VaultClient.Client.PollingDuration = SharedGalleryTimeout // TODO(boumenot) - SDK still does not have a full KeyVault client. // There are two ways that KeyVault has to be accessed, and each one has their own SPN. An authenticated SPN @@ -243,6 +257,7 @@ func NewAzureClient(subscriptionID, resourceGroupName, storageAccountName string azureClient.VaultClientDelete.RequestInspector = withInspection(maxlen) azureClient.VaultClientDelete.ResponseInspector = byConcatDecorators(byInspecting(maxlen), errorCapture(azureClient)) azureClient.VaultClientDelete.UserAgent = fmt.Sprintf("%s %s", useragent.String(), azureClient.VaultClientDelete.UserAgent) + azureClient.VaultClientDelete.Client.PollingDuration = SharedGalleryTimeout // If this is a managed disk build, this should be ignored. if resourceGroupName != "" && storageAccountName != "" { From 859e2524593deab2fb4fb33a31559d24fdff0548 Mon Sep 17 00:00:00 2001 From: Megan Marsh Date: Tue, 1 Oct 2019 11:49:29 -0700 Subject: [PATCH 008/155] update to version 1.5.0-dev --- version/version.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/version/version.go b/version/version.go index 7500feda8..9755bac10 100644 --- a/version/version.go +++ b/version/version.go @@ -9,12 +9,12 @@ import ( var GitCommit string // The main version number that is being run at the moment. -const Version = "1.4.4" +const Version = "1.5.0" // 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 = "" +const VersionPrerelease = "dev" func FormattedVersion() string { var versionString bytes.Buffer From 1ecfa032ba0e0e320f279a79394b6118c775dfb7 Mon Sep 17 00:00:00 2001 From: Kevin Faulkner Date: Sun, 21 Apr 2019 20:35:45 -0400 Subject: [PATCH 009/155] Qemu builder disk size as a string --- builder/qemu/builder.go | 10 ++++------ builder/qemu/builder_test.go | 10 +++++----- builder/qemu/step_create_disk.go | 2 +- builder/qemu/step_resize_disk.go | 3 +-- website/source/docs/builders/qemu.html.md.erb | 2 +- 5 files changed, 12 insertions(+), 15 deletions(-) diff --git a/builder/qemu/builder.go b/builder/qemu/builder.go index a277e1d45..0ee680f56 100644 --- a/builder/qemu/builder.go +++ b/builder/qemu/builder.go @@ -148,7 +148,7 @@ type Config struct { DiskInterface string `mapstructure:"disk_interface" required:"false"` // The size, in megabytes, of the hard disk to create // for the VM. By default, this is 40960 (40 GB). - DiskSize uint `mapstructure:"disk_size" required:"false"` + DiskSize string `mapstructure:"disk_size" required:"false"` // The cache mode to use for disk. Allowed values include any of // `writethrough`, `writeback`, `none`, `unsafe` or `directsync`. By // default, this is set to `writeback`. @@ -316,7 +316,6 @@ type Config struct { // "BUILDNAME" is the name of the build. Currently, no file extension will be // used unless it is specified in this option. VMName string `mapstructure:"vm_name" required:"false"` - // These are deprecated, but we keep them around for BC // TODO(@mitchellh): remove SSHWaitTimeout time.Duration `mapstructure:"ssh_wait_timeout" required:"false"` @@ -344,11 +343,10 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) { var errs *packer.MultiError warnings := make([]string, 0) - errs = packer.MultiErrorAppend(errs, b.config.ShutdownConfig.Prepare(&b.config.ctx)...) - if b.config.DiskSize == 0 { - b.config.DiskSize = 40960 + if b.config.DiskSize == "" || b.config.DiskSize == "0" { + b.config.DiskSize = "40960M" } if b.config.DiskCache == "" { @@ -700,7 +698,7 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack artifact.state["diskPaths"] = diskpaths } artifact.state["diskType"] = b.config.Format - artifact.state["diskSize"] = uint64(b.config.DiskSize) + artifact.state["diskSize"] = b.config.DiskSize artifact.state["domainType"] = b.config.Accelerator return artifact, nil diff --git a/builder/qemu/builder_test.go b/builder/qemu/builder_test.go index 122caa754..15f3db8b3 100644 --- a/builder/qemu/builder_test.go +++ b/builder/qemu/builder_test.go @@ -169,11 +169,11 @@ func TestBuilderPrepare_DiskSize(t *testing.T) { t.Fatalf("bad err: %s", err) } - if b.config.DiskSize != 40960 { - t.Fatalf("bad size: %d", b.config.DiskSize) + if b.config.DiskSize != "40960M" { + t.Fatalf("bad size: %s", b.config.DiskSize) } - config["disk_size"] = 60000 + config["disk_size"] = "60000M" b = Builder{} warns, err = b.Prepare(config) if len(warns) > 0 { @@ -183,8 +183,8 @@ func TestBuilderPrepare_DiskSize(t *testing.T) { t.Fatalf("should not have error: %s", err) } - if b.config.DiskSize != 60000 { - t.Fatalf("bad size: %d", b.config.DiskSize) + if b.config.DiskSize != "60000M" { + t.Fatalf("bad size: %s", b.config.DiskSize) } } diff --git a/builder/qemu/step_create_disk.go b/builder/qemu/step_create_disk.go index 8fb18d025..12041565c 100644 --- a/builder/qemu/step_create_disk.go +++ b/builder/qemu/step_create_disk.go @@ -29,7 +29,7 @@ func (s *stepCreateDisk) Run(ctx context.Context, state multistep.StateBag) mult ui.Say("Creating required virtual machine disks") // The 'main' or 'default' disk diskFullPaths = append(diskFullPaths, filepath.Join(config.OutputDir, name)) - diskSizes = append(diskSizes, fmt.Sprintf("%dM", uint64(config.DiskSize))) + diskSizes = append(diskSizes, fmt.Sprintf("%s", config.DiskSize)) // Additional disks if len(config.AdditionalDiskSize) > 0 { for i, diskSize := range config.AdditionalDiskSize { diff --git a/builder/qemu/step_resize_disk.go b/builder/qemu/step_resize_disk.go index d25ffaff4..f9dd5693e 100644 --- a/builder/qemu/step_resize_disk.go +++ b/builder/qemu/step_resize_disk.go @@ -23,9 +23,8 @@ func (s *stepResizeDisk) Run(ctx context.Context, state multistep.StateBag) mult "resize", "-f", config.Format, path, - fmt.Sprintf("%vM", config.DiskSize), + fmt.Sprintf("%s", config.DiskSize), } - if config.DiskImage == false { return multistep.ActionContinue } diff --git a/website/source/docs/builders/qemu.html.md.erb b/website/source/docs/builders/qemu.html.md.erb index 78cf5f013..2e7db1dfc 100644 --- a/website/source/docs/builders/qemu.html.md.erb +++ b/website/source/docs/builders/qemu.html.md.erb @@ -37,7 +37,7 @@ to files, URLS for ISOs and checksums. "iso_checksum_type": "md5", "output_directory": "output_centos_tdhtest", "shutdown_command": "echo 'packer' | sudo -S shutdown -P now", - "disk_size": 5000, + "disk_size": "5000M", "format": "qcow2", "accelerator": "kvm", "http_directory": "path/to/httpdir", From 19a9d7149f2c902e0ae3e6b1681438224ebd9999 Mon Sep 17 00:00:00 2001 From: Megan Marsh Date: Tue, 1 Oct 2019 13:36:55 -0700 Subject: [PATCH 010/155] fix structs and regenerate partials --- builder/qemu/builder.go | 6 ++++-- .../partials/builder/qemu/_Config-not-required.html.md | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/builder/qemu/builder.go b/builder/qemu/builder.go index 0ee680f56..10c821b7e 100644 --- a/builder/qemu/builder.go +++ b/builder/qemu/builder.go @@ -146,8 +146,10 @@ type Config struct { // one of the other listed interfaces. Using the `scsi` interface under // these circumstances will cause the build to fail. DiskInterface string `mapstructure:"disk_interface" required:"false"` - // The size, in megabytes, of the hard disk to create - // for the VM. By default, this is 40960 (40 GB). + // The size in bytes, suffixes of the first letter of common byte types + // like "k" or "K", "M" for megabytes, G for gigabytes, T for terabytes. + // Will create the of the hard disk of the VM. By default, this is + // `40960M` (40 GB). DiskSize string `mapstructure:"disk_size" required:"false"` // The cache mode to use for disk. Allowed values include any of // `writethrough`, `writeback`, `none`, `unsafe` or `directsync`. By diff --git a/website/source/partials/builder/qemu/_Config-not-required.html.md b/website/source/partials/builder/qemu/_Config-not-required.html.md index 07ac4256a..723c53276 100644 --- a/website/source/partials/builder/qemu/_Config-not-required.html.md +++ b/website/source/partials/builder/qemu/_Config-not-required.html.md @@ -47,8 +47,10 @@ one of the other listed interfaces. Using the `scsi` interface under these circumstances will cause the build to fail. -- `disk_size` (uint) - The size, in megabytes, of the hard disk to create - for the VM. By default, this is 40960 (40 GB). +- `disk_size` (string) - The size in bytes, suffixes of the first letter of common byte types + like "k" or "K", "M" for megabytes, G for gigabytes, T for terabytes. + Will create the of the hard disk of the VM. By default, this is + `40960M` (40 GB). - `disk_cache` (string) - The cache mode to use for disk. Allowed values include any of `writethrough`, `writeback`, `none`, `unsafe` or `directsync`. By From 4a3a011310c196c4740ebd9db950c2560c01e54e Mon Sep 17 00:00:00 2001 From: Lars Lehtonen Date: Tue, 1 Oct 2019 15:54:28 -0700 Subject: [PATCH 011/155] builder/virtualbox/vm: fix dropped error --- builder/virtualbox/vm/step_set_snapshot.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/builder/virtualbox/vm/step_set_snapshot.go b/builder/virtualbox/vm/step_set_snapshot.go index 515d9b2a0..401bacf15 100644 --- a/builder/virtualbox/vm/step_set_snapshot.go +++ b/builder/virtualbox/vm/step_set_snapshot.go @@ -71,6 +71,12 @@ func (s *StepSetSnapshot) Cleanup(state multistep.StateBag) { } else { ui.Say(fmt.Sprintf("Reverting to snapshot %s on virtual machine %s", s.revertToSnapshot, s.Name)) snapshotTree, err := driver.LoadSnapshots(s.Name) + if err != nil { + err := fmt.Errorf("error loading virtual machine %s snapshots: %v", s.Name, err) + state.Put("error", err) + ui.Error(err.Error()) + return + } revertTo := snapshotTree.GetSnapshotByUUID(s.revertToSnapshot) if nil == revertTo { err := fmt.Errorf("Snapshot with UUID %s not found for VM %s", s.revertToSnapshot, s.Name) From ae1bb856a31d0e0846b4dce3db38850831470e90 Mon Sep 17 00:00:00 2001 From: Andrew Starr-Bochicchio Date: Tue, 1 Oct 2019 21:14:15 -0400 Subject: [PATCH 012/155] digitalocean-import: Fix panic when 'image_regions' not set (Fixes: #7843). --- post-processor/digitalocean-import/post-processor.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/post-processor/digitalocean-import/post-processor.go b/post-processor/digitalocean-import/post-processor.go index e20ea2380..80e1d13a8 100644 --- a/post-processor/digitalocean-import/post-processor.go +++ b/post-processor/digitalocean-import/post-processor.go @@ -119,7 +119,6 @@ func (p *PostProcessor) Configure(raws ...interface{}) error { "spaces_region": &p.config.SpacesRegion, "space_name": &p.config.SpaceName, "image_name": &p.config.Name, - "image_regions": &p.config.ImageRegions[0], } for key, ptr := range requiredArgs { if *ptr == "" { @@ -128,6 +127,11 @@ func (p *PostProcessor) Configure(raws ...interface{}) error { } } + if len(p.config.ImageRegions) == 0 { + errs = packer.MultiErrorAppend( + errs, fmt.Errorf("image_regions must be set")) + } + if len(errs.Errors) > 0 { return errs } From 7e6f58f69999492ebf34215e970409d4db8e967d Mon Sep 17 00:00:00 2001 From: Marek Winkler Date: Tue, 1 Oct 2019 15:04:49 +0200 Subject: [PATCH 013/155] builder/openstack: fix issue 5575 - support shutdown by Sysprep --- builder/openstack/step_stop_server.go | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/builder/openstack/step_stop_server.go b/builder/openstack/step_stop_server.go index 9b3deb0ec..9e6f35b74 100644 --- a/builder/openstack/step_stop_server.go +++ b/builder/openstack/step_stop_server.go @@ -3,7 +3,9 @@ package openstack import ( "context" "fmt" + "log" + "github.com/gophercloud/gophercloud" "github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/startstop" "github.com/gophercloud/gophercloud/openstack/compute/v2/servers" "github.com/hashicorp/packer/helper/multistep" @@ -27,9 +29,15 @@ func (s *StepStopServer) Run(ctx context.Context, state multistep.StateBag) mult ui.Say(fmt.Sprintf("Stopping server: %s ...", server.ID)) if err := startstop.Stop(client, server.ID).ExtractErr(); err != nil { - err = fmt.Errorf("Error stopping server: %s", err) - state.Put("error", err) - return multistep.ActionHalt + if _, ok := err.(gophercloud.ErrDefault409); ok { + // The server might have already been shut down by Windows Sysprep + log.Printf("[WARN] 409 on stopping an already stopped server, continuing") + return multistep.ActionContinue + } else { + err = fmt.Errorf("Error stopping server: %s", err) + state.Put("error", err) + return multistep.ActionHalt + } } ui.Message(fmt.Sprintf("Waiting for server to stop: %s ...", server.ID)) @@ -45,7 +53,6 @@ func (s *StepStopServer) Run(ctx context.Context, state multistep.StateBag) mult ui.Error(err.Error()) return multistep.ActionHalt } - return multistep.ActionContinue } From 0bd256326fb5aebf98c98682c13ba0a4d16a1c16 Mon Sep 17 00:00:00 2001 From: Marek Winkler Date: Wed, 2 Oct 2019 22:16:18 +0200 Subject: [PATCH 014/155] builder/openstack: Fix interface conversion panic when attempting to find a volume when not using volumes --- builder/openstack/step_create_image.go | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/builder/openstack/step_create_image.go b/builder/openstack/step_create_image.go index 1b8b02b9e..d70527c31 100644 --- a/builder/openstack/step_create_image.go +++ b/builder/openstack/step_create_image.go @@ -92,16 +92,18 @@ func (s *stepCreateImage) Run(ctx context.Context, state multistep.StateBag) mul return multistep.ActionHalt } - volume := state.Get("volume_id").(string) - if len(config.ImageMetadata) > 0 && s.UseBlockStorageVolume { - err = volumeactions.SetImageMetadata(blockStorageClient, volume, volumeactions.ImageMetadataOpts{ - Metadata: config.ImageMetadata, - }).ExtractErr() - if err != nil { - err := fmt.Errorf("Error setting image metadata: %s", err) - state.Put("error", err) - ui.Error(err.Error()) - return multistep.ActionHalt + if s.UseBlockStorageVolume { + volume := state.Get("volume_id").(string) + if len(config.ImageMetadata) > 0 { + err = volumeactions.SetImageMetadata(blockStorageClient, volume, volumeactions.ImageMetadataOpts{ + Metadata: config.ImageMetadata, + }).ExtractErr() + if err != nil { + err := fmt.Errorf("Error setting image metadata: %s", err) + state.Put("error", err) + ui.Error(err.Error()) + return multistep.ActionHalt + } } } From e16fb19bfc5e0a098a7d5dc7f9bcbc1fd3e51dd3 Mon Sep 17 00:00:00 2001 From: Megan Marsh Date: Wed, 2 Oct 2019 14:06:30 -0700 Subject: [PATCH 015/155] don't abort on a single error if another availability zone was able to create the instance --- .../amazon/common/step_run_spot_instance.go | 21 ++++++++++++------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/builder/amazon/common/step_run_spot_instance.go b/builder/amazon/common/step_run_spot_instance.go index ab15bdff3..d8b1118cd 100644 --- a/builder/amazon/common/step_run_spot_instance.go +++ b/builder/amazon/common/step_run_spot_instance.go @@ -274,15 +274,20 @@ func (s *StepRunSpotInstance) Run(ctx context.Context, state multistep.StateBag) return multistep.ActionHalt } - if len(createOutput.Errors) > 0 { - errString := fmt.Sprintf("Error waiting for fleet request (%s) to become ready:", *createOutput.FleetId) - for _, outErr := range createOutput.Errors { - errString = errString + fmt.Sprintf("%s", *outErr.ErrorMessage) + if len(createOutput.Instances) == 0 { + // We can end up with errors because one of the allowed availability + // zones doesn't have one of the allowed instance types; as long as + // an instance is launched, these errors aren't important. + if len(createOutput.Errors) > 0 { + errString := fmt.Sprintf("Error waiting for fleet request (%s) to become ready:", *createOutput.FleetId) + for _, outErr := range createOutput.Errors { + errString = errString + fmt.Sprintf("%s", *outErr.ErrorMessage) + } + err = fmt.Errorf(errString) + state.Put("error", err) + ui.Error(err.Error()) + return multistep.ActionHalt } - err = fmt.Errorf(errString) - state.Put("error", err) - ui.Error(err.Error()) - return multistep.ActionHalt } instanceId = *createOutput.Instances[0].InstanceIds[0] From 9d17a7f1368f3e7cc86e8d26aeb520c4bebd6d28 Mon Sep 17 00:00:00 2001 From: Ash Jindal Date: Thu, 3 Oct 2019 11:36:10 +0100 Subject: [PATCH 016/155] Fixed CPE in description of `file` builder The description seems to be a CPE from the `null` builder. --- website/source/docs/builders/file.html.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/website/source/docs/builders/file.html.md b/website/source/docs/builders/file.html.md index 7a84fc3f3..8dc0a36b7 100644 --- a/website/source/docs/builders/file.html.md +++ b/website/source/docs/builders/file.html.md @@ -18,8 +18,8 @@ wait times. ## Basic Example -Below is a fully functioning example. It doesn't do anything useful, since no -provisioners are defined, but it will connect to the specified host via ssh. +Below is a fully functioning example. It create a file at `target` with the +specified `content`. ``` json { From 0fcc4688f1115af87741721fa90d9bd21116bb22 Mon Sep 17 00:00:00 2001 From: Adrien Delorme Date: Thu, 3 Oct 2019 17:49:30 +0200 Subject: [PATCH 017/155] default labels per ISSUE_TEMPLATE type --- .github/ISSUE_TEMPLATE/bug_report.md | 2 +- .github/ISSUE_TEMPLATE/feature_requests.md | 2 +- .github/ISSUE_TEMPLATE/question.md | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 611a2c421..e73c0e177 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -1,7 +1,7 @@ --- name: Bug Report about: You're experiencing an issue with Packer that is different than the documented behavior. - +labels: bug --- When filing a bug, please include the following headings if possible. Any diff --git a/.github/ISSUE_TEMPLATE/feature_requests.md b/.github/ISSUE_TEMPLATE/feature_requests.md index ff2a6fb3d..a9a2cdeba 100644 --- a/.github/ISSUE_TEMPLATE/feature_requests.md +++ b/.github/ISSUE_TEMPLATE/feature_requests.md @@ -1,7 +1,7 @@ --- name: Feature Request about: If you have something you think Packer could improve or add support for. - +labels: enhancement --- Please search the existing issues for relevant feature requests, and use the diff --git a/.github/ISSUE_TEMPLATE/question.md b/.github/ISSUE_TEMPLATE/question.md index 79537bfad..09ebbe85d 100644 --- a/.github/ISSUE_TEMPLATE/question.md +++ b/.github/ISSUE_TEMPLATE/question.md @@ -1,7 +1,7 @@ --- name: Question about: If you have a question, please check out our other community resources instead of opening an issue. - +labels: question --- Issues on GitHub are intended to be related to bugs or feature requests, so we From 3951267963c9539600ecca669ae158eaea3d7fc6 Mon Sep 17 00:00:00 2001 From: Adrien Delorme Date: Thu, 3 Oct 2019 17:59:25 +0200 Subject: [PATCH 018/155] Create ssh_or_winrm_times_out.md --- .../ISSUE_TEMPLATE/ssh_or_winrm_times_out.md | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/ssh_or_winrm_times_out.md diff --git a/.github/ISSUE_TEMPLATE/ssh_or_winrm_times_out.md b/.github/ISSUE_TEMPLATE/ssh_or_winrm_times_out.md new file mode 100644 index 000000000..8fdc88b0b --- /dev/null +++ b/.github/ISSUE_TEMPLATE/ssh_or_winrm_times_out.md @@ -0,0 +1,24 @@ +--- +name: SSH or WinRM times out +about: I have a waiting SSH or WinRM error. +labels: communicator-question +--- + +Got one of the following errors ? See if the related guides can help. + +* `Waiting for WinRM to become available` ? + + - See our basic WinRm Packer guide: https://www.packer.io/guides/automatic-operating-system-installs/autounattend_windows.html + +* `Waiting for SSH to become available` ? + + - See our basic SSH Packer guide: https://www.packer.io/guides/automatic-operating-system-installs/preseed_ubuntu.html + + +Issues on GitHub are intended to be related to bugs or feature requests, so we recommend using our other community resources instead of asking here if you have a question. + +- Packer Guides: https://www.packer.io/guides/index.html +- Discussion List: https://groups.google.com/group/packer-tool +- Any other questions can be sent to the packer section of the HashiCorp + forum: https://discuss.hashicorp.com/c/packer +- Packer community links: https://www.packer.io/community.html From ccf58f0c98e754a7e761c70a13cded318b8a3a0e Mon Sep 17 00:00:00 2001 From: Megan Marsh Date: Tue, 1 Oct 2019 08:59:48 -0700 Subject: [PATCH 019/155] major rework of communicator docs and addition of preseed guides --- examples/preseeds/ubuntu_preseed.cfg | 61 ++++++ .../source/docs/communicators/index.html.md | 32 +++ .../ssh.html.md} | 123 ++++------- .../source/docs/communicators/ssh.html.md.erb | 87 ++++++++ .../source/docs/communicators/winrm.html.md | 160 ++++++++++++++ .../docs/communicators/winrm.html.md.erb | 198 ++++++++++++++++++ .../docs/templates/communicator.html.md.erb | 85 +++----- .../autounattend_windows.html.md | 97 +++++++++ .../index.html.md | 26 +++ .../preseed_ubuntu.html.md | 179 ++++++++++++++++ .../workflow-tips-and-tricks/index.html.md | 13 ++ .../isotime-template-function.html.md | 2 +- .../use-packer-with-comment.html.md | 2 +- .../veewee-to-packer.html.md | 2 +- website/source/layouts/docs.erb | 12 ++ website/source/layouts/guides.erb | 32 ++- 16 files changed, 962 insertions(+), 149 deletions(-) create mode 100644 examples/preseeds/ubuntu_preseed.cfg create mode 100644 website/source/docs/communicators/index.html.md rename website/source/docs/{templates/communicator.html.md => communicators/ssh.html.md} (60%) create mode 100644 website/source/docs/communicators/ssh.html.md.erb create mode 100644 website/source/docs/communicators/winrm.html.md create mode 100644 website/source/docs/communicators/winrm.html.md.erb create mode 100644 website/source/guides/automatic-operating-system-installs/autounattend_windows.html.md create mode 100644 website/source/guides/automatic-operating-system-installs/index.html.md create mode 100644 website/source/guides/automatic-operating-system-installs/preseed_ubuntu.html.md create mode 100644 website/source/guides/workflow-tips-and-tricks/index.html.md rename website/source/guides/{ => workflow-tips-and-tricks}/isotime-template-function.html.md (96%) rename website/source/guides/{ => workflow-tips-and-tricks}/use-packer-with-comment.html.md (96%) rename website/source/guides/{ => workflow-tips-and-tricks}/veewee-to-packer.html.md (97%) diff --git a/examples/preseeds/ubuntu_preseed.cfg b/examples/preseeds/ubuntu_preseed.cfg new file mode 100644 index 000000000..1786445fd --- /dev/null +++ b/examples/preseeds/ubuntu_preseed.cfg @@ -0,0 +1,61 @@ +# Preseeding only locale sets language, country and locale. +d-i debian-installer/locale string en_US + +# Keyboard selection. +d-i console-setup/ask_detect boolean false +d-i keyboard-configuration/xkb-keymap select us + +choose-mirror-bin mirror/http/proxy string + +### Clock and time zone setup +d-i clock-setup/utc boolean true +d-i time/zone string UTC + +# Avoid that last message about the install being complete. +d-i finish-install/reboot_in_progress note + +# This is fairly safe to set, it makes grub install automatically to the MBR +# if no other operating system is detected on the machine. +d-i grub-installer/only_debian boolean true + +# This one makes grub-installer install to the MBR if it also finds some other +# OS, which is less safe as it might not be able to boot that other OS. +d-i grub-installer/with_other_os boolean true + +### Mirror settings +# If you select ftp, the mirror/country string does not need to be set. +d-i mirror/country string manual +d-i mirror/http/directory string /ubuntu/ +d-i mirror/http/hostname string archive.ubuntu.com +d-i mirror/http/proxy string + +### Partitioning +d-i partman-auto/method string lvm + +# This makes partman automatically partition without confirmation. +d-i partman-md/confirm boolean true +d-i partman-partitioning/confirm_write_new_label boolean true +d-i partman/choose_partition select finish +d-i partman/confirm boolean true +d-i partman/confirm_nooverwrite boolean true + +### Account setup +d-i passwd/user-fullname string vagrant +d-i passwd/user-uid string 1000 +d-i passwd/user-password password vagrant +d-i passwd/user-password-again password vagrant +d-i passwd/username string vagrant + +# The installer will warn about weak passwords. If you are sure you know +# what you're doing and want to override it, uncomment this. +d-i user-setup/allow-password-weak boolean true +d-i user-setup/encrypt-home boolean false + +### Package selection +tasksel tasksel/first standard +d-i pkgsel/include string openssh-server build-essential +d-i pkgsel/install-language-support boolean false + +# disable automatic package updates +d-i pkgsel/update-policy select none +d-i pkgsel/upgrade select full-upgrade \ No newline at end of file diff --git a/website/source/docs/communicators/index.html.md b/website/source/docs/communicators/index.html.md new file mode 100644 index 000000000..802d79fdf --- /dev/null +++ b/website/source/docs/communicators/index.html.md @@ -0,0 +1,32 @@ +--- +description: | + Communicators are the mechanism Packer uses to upload files, execute + scripts, etc. with the machine being created. +layout: docs +page_title: Communicators +sidebar_current: 'docs-communicators' +--- + +# Communicators + +Communicators are the mechanism Packer uses to upload files, execute scripts, +etc. with the machine being created. + +Communicators are configured within the +[builder](/docs/templates/builders.html) section. Packer currently supports +three kinds of communicators: + +- `none` - No communicator will be used. If this is set, most provisioners + also can't be used. + +- [ssh](/docs/communicators/ssh.html) - An SSH connection will be established to the machine. This is + usually the default. + +- [winrm](/docs/communicators/winrm.html) - A WinRM connection will be established. + +In addition to the above, some builders have custom communicators they can use. +For example, the Docker builder has a "docker" communicator that uses +`docker exec` and `docker cp` to execute scripts and copy files. + +For more details on how to use each communicator, click the links above to be +taken to each communicator's page. \ No newline at end of file diff --git a/website/source/docs/templates/communicator.html.md b/website/source/docs/communicators/ssh.html.md similarity index 60% rename from website/source/docs/templates/communicator.html.md rename to website/source/docs/communicators/ssh.html.md index de5c91c43..2065d2dd4 100644 --- a/website/source/docs/templates/communicator.html.md +++ b/website/source/docs/communicators/ssh.html.md @@ -1,41 +1,60 @@ --- description: | - Communicators are the mechanism Packer uses to upload files, execute scripts, - etc. with the machine being created. + The SSH communicator uses SSH to upload files, execute scripts, etc. on + the machine being created. layout: docs -page_title: 'Communicators - Templates' -sidebar_current: 'docs-templates-communicators' +page_title: 'Communicators - SSH' +sidebar_current: 'docs-communicators-ssh' --- -# Template Communicators +# SSH Communicator Communicators are the mechanism Packer uses to upload files, execute scripts, -etc. with the machine being created. +etc. on the machine being created, and ar configured within the +[builder](/docs/templates/builders.html) section. -Communicators are configured within the -[builder](/docs/templates/builders.html) section. Packer currently supports -three kinds of communicators: +The SSH communicator does this by using the SSH protocol. It is the default +communicator for a majority of builders. -- `none` - No communicator will be used. If this is set, most provisioners - also can't be used. +If you have an SSH agent configured on the host running Packer, and SSH agent +authentication is enabled in the communicator config, Packer will automatically +forward the SSH agent to the remote host. -- `ssh` - An SSH connection will be established to the machine. This is - usually the default. +## Getting Ready to Use the SSH Communicator -- `winrm` - A WinRM connection will be established. +The SSH communicator is the default communicator for a majority of builders, but +depending on your builder it may not work "out of the box". -In addition to the above, some builders have custom communicators they can use. -For example, the Docker builder has a "docker" communicator that uses -`docker exec` and `docker cp` to execute scripts and copy files. +If you are building from a cloud image (for example, building on Amazon), there +is a good chance that your cloud provider has already preconfigured SSH on the +image for you, meaning that all you have to do is configure the communicator in +the Packer template. -## Using a Communicator +However, if you are building from a brand-new and unconfigured operating system +image, you will almost always have to perform some extra work to configure SSH +on the guest machine. For most operating system distributions, this work will +be performed by a +(boot command)[/docs/builders/vmware-iso.html#boot-configuration] +that references a file which provides answers to the normally-interactive +questions you get asked when installing an operating system. The name of this +file varies by operating system; some common examples are the "preseed" file +required by Debian, the "kickstart" file required by CentOS or the +"answer file", also known as the Autounattend.xml file, required by Windows. +For simplicity's sake, we'll refer to this file as the "preseed" file in the +rest of the documentation. -By default, the SSH communicator is usually used. Additional configuration may -not even be necessary, since some builders such as Amazon automatically -configure everything. +If you are unfamiliar with how to use a preseed file for automatic +bootstrapping of an image, please either take a look at our [quick guides](/guides/automatic-operating-system-installs/index.html) to +image bootstrapping, or research automatic configuration for your specific +guest operating system. Knowing how to automatically initalize your operating +system is critical for being able to successfully use Packer. -However, to specify a communicator, you set the `communicator` key within a -build. Multiple builds can have different communicators. Example: +## Using The SSH Communicator + +To specify a communicator, you set the `communicator` key within a +build. If your template contains multiple builds, you can have a different +communicator configured for each. Here's an extremely basic example of +configuring the SSH communicator for an Amazon builder: ``` json { @@ -48,10 +67,10 @@ build. Multiple builds can have different communicators. Example: } ``` -After specifying the `communicator`, you can specify a number of other +After specifying the `communicator` type, you can specify a number of other configuration parameters for that communicator. These are documented below. -## SSH Communicator +## SSH Communicator Options The SSH communicator connects to the host via SSH. If you have an SSH agent configured on the host running Packer, and SSH agent authentication is enabled @@ -176,58 +195,4 @@ And the following MACs: - hmac-sha2-256 - `hmac-sha2-256-etm@openssh.com` -## WinRM Communicator - -The WinRM communicator has the following options. - -- `winrm_host` (string) - The address for WinRM to connect to. - - NOTE: If using an Amazon EBS builder, you can specify the interface WinRM - connects to via - [`ssh_interface`](https://www.packer.io/docs/builders/amazon-ebs.html#ssh_interface) - -- `winrm_insecure` (boolean) - If `true`, do not check server certificate - chain and host name. - -- `winrm_password` (string) - The password to use to connect to WinRM. - -- `winrm_port` (number) - The WinRM port to connect to. This defaults to - `5985` for plain unencrypted connection and `5986` for SSL when - `winrm_use_ssl` is set to true. - -- `winrm_timeout` (string) - The amount of time to wait for WinRM to become - available. This defaults to `30m` since setting up a Windows machine - generally takes a long time. - -- `winrm_use_ntlm` (boolean) - If `true`, NTLMv2 authentication (with session - security) will be used for WinRM, rather than default (basic - authentication), removing the requirement for basic authentication to be - enabled within the target guest. Further reading for remote connection - authentication can be found - [here](https://msdn.microsoft.com/en-us/library/aa384295(v=vs.85).aspx). - -- `winrm_use_ssl` (boolean) - If `true`, use HTTPS for WinRM. - -- `winrm_username` (string) - The username to use to connect to WinRM. - -## Pausing Before Connecting -We recommend that you enable SSH or WinRM as the very last step in your -guest's bootstrap script, but sometimes you may have a race condition where -you need Packer to wait before attempting to connect to your guest. - -If you end up in this situation, you can use the template option -`pause_before_connecting`. By default, there is no pause. For example: - -``` -{ - "communicator": "ssh", - "ssh_username": "myuser", - "pause_before_connecting": "10m" -} -``` - -In this example, Packer will check whether it can connect, as normal. But once -a connection attempt is successful, it will disconnect and then wait 10 minutes -before connecting to the guest and beginning provisioning. - diff --git a/website/source/docs/communicators/ssh.html.md.erb b/website/source/docs/communicators/ssh.html.md.erb new file mode 100644 index 000000000..988870816 --- /dev/null +++ b/website/source/docs/communicators/ssh.html.md.erb @@ -0,0 +1,87 @@ +--- +description: | + The SSH communicator uses SSH to upload files, execute scripts, etc. on + the machine being created. +layout: docs +page_title: 'Communicators - SSH' +sidebar_current: 'docs-communicators-ssh' +--- + +# SSH Communicator + +Communicators are the mechanism Packer uses to upload files, execute scripts, +etc. on the machine being created, and ar configured within the +[builder](/docs/templates/builders.html) section. + +The SSH communicator does this by using the SSH protocol. It is the default +communicator for a majority of builders. + +If you have an SSH agent configured on the host running Packer, and SSH agent +authentication is enabled in the communicator config, Packer will automatically +forward the SSH agent to the remote host. + +## Getting Ready to Use the SSH Communicator + +The SSH communicator is the default communicator for a majority of builders, but +depending on your builder it may not work "out of the box". + +If you are building from a cloud image (for example, building on Amazon), there +is a good chance that your cloud provider has already preconfigured SSH on the +image for you, meaning that all you have to do is configure the communicator in +the Packer template. + +However, if you are building from a brand-new and unconfigured operating system +image, you will almost always have to perform some extra work to configure SSH +on the guest machine. For most operating system distributions, this work will +be performed by a [boot command](/docs/builders/vmware-iso.html#boot-configuration) +that references a file which provides answers to the normally-interactive +questions you get asked when installing an operating system. The name of this +file varies by operating system; some common examples are the "preseed" file +required by Debian, the "kickstart" file required by CentOS or the +"answer file", also known as the Autounattend.xml file, required by Windows. +For simplicity's sake, we'll refer to this file as the "preseed" file in the +rest of the documentation. + +If you are unfamiliar with how to use a preseed file for automatic +bootstrapping of an image, please either take a look at our +[quick guides](/guides/automatic-operating-system-installs/index.html) to +image bootstrapping, or research automatic configuration for your specific +guest operating system. Knowing how to automatically initalize your operating +system is critical for being able to successfully use Packer. + +## SSH Communicator + +The SSH communicator connects to the host via SSH. If you have an SSH agent +configured on the host running Packer, and SSH agent authentication is enabled +in the communicator config, Packer will automatically forward the SSH agent to +the remote host. + +The SSH communicator has the following options: + +<%= partial "partials/helper/communicator/SSH-not-required" %> + +### SSH Communicator Details + +Packer will only use one authentication method, either `publickey` or if +`ssh_password` is used packer will offer `password` and `keyboard-interactive` +both sending the password. In other words Packer will not work with *sshd* +configured with more than one configured authentication method using +`AuthenticationMethods`. + +Packer supports the following ciphers: + +- aes128-ctr +- aes192-ctr +- aes256-ctr +- arcfour128 +- arcfour256 +- arcfour +- `es128-gcm@openssh.com` +- `acha20-poly1305@openssh.com` + +And the following MACs: + +- hmac-sha1 +- hmac-sha1-96 +- hmac-sha2-256 +- `hmac-sha2-256-etm@openssh.com` \ No newline at end of file diff --git a/website/source/docs/communicators/winrm.html.md b/website/source/docs/communicators/winrm.html.md new file mode 100644 index 000000000..6918b4115 --- /dev/null +++ b/website/source/docs/communicators/winrm.html.md @@ -0,0 +1,160 @@ +--- +description: | + Communicators are the mechanism Packer uses to upload files, execute scripts, + etc. with the machine being created. +layout: docs +page_title: 'Communicators - Templates' +sidebar_current: 'docs-templates-communicators' +--- + +# Template Communicators + +Communicators are the mechanism Packer uses to upload files, execute scripts, +etc. with the machine being created. + +Communicators are configured within the +[builder](/docs/templates/builders.html) section. Packer currently supports +three kinds of communicators: + +- `none` - No communicator will be used. If this is set, most provisioners + also can't be used. + +- `ssh` - An SSH connection will be established to the machine. This is + usually the default. + +- `winrm` - A WinRM connection will be established. + +In addition to the above, some builders have custom communicators they can use. +For example, the Docker builder has a "docker" communicator that uses +`docker exec` and `docker cp` to execute scripts and copy files. + +## Using a Communicator + +By default, the SSH communicator is usually used. Additional configuration may +not even be necessary, since some builders such as Amazon automatically +configure everything. + +However, to specify a communicator, you set the `communicator` key within a +build. Multiple builds can have different communicators. Example: + +``` json +{ + "builders": [ + { + "type": "amazon-ebs", + "communicator": "ssh" + } + ] +} +``` + +After specifying the `communicator`, you can specify a number of other +configuration parameters for that communicator. These are documented below. + +## WinRM Communicator + +The WinRM communicator has the following options. + +- `winrm_host` (string) - The address for WinRM to connect to. + + NOTE: If using an Amazon EBS builder, you can specify the interface WinRM + connects to via + [`ssh_interface`](https://www.packer.io/docs/builders/amazon-ebs.html#ssh_interface) + +- `winrm_insecure` (boolean) - If `true`, do not check server certificate + chain and host name. + +- `winrm_password` (string) - The password to use to connect to WinRM. + +- `winrm_port` (number) - The WinRM port to connect to. This defaults to + `5985` for plain unencrypted connection and `5986` for SSL when + `winrm_use_ssl` is set to true. + +- `winrm_timeout` (string) - The amount of time to wait for WinRM to become + available. This defaults to `30m` since setting up a Windows machine + generally takes a long time. + +- `winrm_use_ntlm` (boolean) - If `true`, NTLMv2 authentication (with session + security) will be used for WinRM, rather than default (basic + authentication), removing the requirement for basic authentication to be + enabled within the target guest. Further reading for remote connection + authentication can be found + [here](https://msdn.microsoft.com/en-us/library/aa384295(v=vs.85).aspx). + +- `winrm_use_ssl` (boolean) - If `true`, use HTTPS for WinRM. + +- `winrm_username` (string) - The username to use to connect to WinRM. + +## Pausing Before Connecting +We recommend that you enable SSH or WinRM as the very last step in your +guest's bootstrap script, but sometimes you may have a race condition where +you need Packer to wait before attempting to connect to your guest. + +If you end up in this situation, you can use the template option +`pause_before_connecting`. By default, there is no pause. For example: + +``` +{ + "communicator": "ssh", + "ssh_username": "myuser", + "pause_before_connecting": "10m" +} +``` + +In this example, Packer will check whether it can connect, as normal. But once +a connection attempt is successful, it will disconnect and then wait 10 minutes +before connecting to the guest and beginning provisioning. + + +## Configuring WinRM as part of an Autounattend File + +You can add a batch file to your autounattend that contains the commands for +configuring winrm. Depending on your winrm setup, this could be a complex batch +file, or a very simple one. + +``` xml + + ... + + cmd.exe /c a:\winrmConfig.bat + Configure WinRM + 3 + true + + ... + +``` + +The winrmConfig.bat referenced above can be as simple as + +``` +rem basic config for winrm +cmd.exe /c winrm quickconfig -q + +rem allow unencrypted traffic, and configure auth to use basic username/password auth +cmd.exe /c winrm set winrm/config/service @{AllowUnencrypted="true"} +cmd.exe /c winrm set winrm/config/service/auth @{Basic="true"} + +rem update firewall rules to open the right port and to allow remote administration +cmd.exe /c netsh advfirewall firewall set rule group="remote administration" new enable=yes + +rem restart winrm +cmd.exe /c net stop winrm +cmd.exe /c net start winrm +``` + +This batch file will only work for http connections, not https, but will enable +you to connect using only the username and password created earlier in the +Autounattend file. The above batchfile will allow you to connect using a very +simple Packer config: + +```json + ... + "communicator": "winrm", + "winrm_username": "packeruser", + "winrm_password": "SecretPassword" + ... +``` + +If you want to set winRM up for https, things will be a bit more complicated. +We'll explore \ No newline at end of file diff --git a/website/source/docs/communicators/winrm.html.md.erb b/website/source/docs/communicators/winrm.html.md.erb new file mode 100644 index 000000000..af32caedd --- /dev/null +++ b/website/source/docs/communicators/winrm.html.md.erb @@ -0,0 +1,198 @@ +--- +description: | + Communicators are the mechanism Packer uses to upload files, execute scripts, + etc. with the machine being created. +layout: docs +page_title: 'Communicators - Templates' +sidebar_current: 'docs-communicators-winrm' +--- + +# WinRM Communicator + +Communicators are the mechanism Packer uses to upload files, execute scripts, +etc. with the machine being created. The WinRM communicator uses the +Windows Remote Management protocol to do this. + +## Getting Ready to Use the WinRM Communicator + +The WinRM communicator is not the default communicator, so you will always have +to set the `"communicator": "winrm",` template option explicitly. In addition, +you will almost always have to provide a pre-run script that enables and +configures WinRM on the guest machine. This will generally be in the form of a +powershell script or a batch file. + +If you are building from a brand-new and unconfigured operating system +image, you will need to provide this pre-run script as part of your +Autounattend.xml file, required by Windows for automatic operating system +installation. If you are building in a cloud or from a pre-installed image, your +method for providing this pre-run script will vary based on the builder. Please +refer to each builder's documentation for more information on how to supply the +winrm configuration script. + +If you are unfamiliar with how to use an autounattend file, take a look at our +[quick guides](/guides/automatic-operating-system-installs/index.html); knowing +how to automatically initalize your operating system is critical for being able +to successfully use Packer to build from an iso. + +## WinRM Communicator Options + +<%= partial "partials/helper/communicator/WinRM-not-required" %> + +## Examples + +### Basics of WinRM Connection + +Please note that WinRM is not a Packer-specific protocol. Microsoft has a great +deal of documentation about WinRM. If you find after reading this guide that +you are still not able to connect via WinRM, check the +[Microsoft documentation](https://docs.microsoft.com/en-us/windows/win32/winrm/installation-and-configuration-for-windows-remote-management) +to make sure there isn't anything you're missing. + +There are some steps that you will normally need to take in order for Packer +to be able to connect via WinRM + +1. Set up a username and password that Packer to connect with. +2. Make any necesary registry edits to enable remote execution + (and remote execution with elevated privileges, if needed) +3. Start WinRM, setting any config needed for allowing basic auth +4. Open ports 5985 and/or 5986 depending on how you're connecting +5. launch WinRM and set it to automatically launch when the computer restarts +6. If necessary, generate a self-signed certificate or provide a real certificate + to the WinRM listener. + +#### Configuring WinRM in VMWare + +If you are configuring WinRM using an Autounattend.xml, the simplest way to set +up WinRM is to put the configuration commands directly into the Autounattend +file as shown [here](https://github.com/StefanScherer/packer-windows/blob/6e603e904e9b280eeb97f7eb542940a043954112/answer_files/2008_r2_core/Autounattend.xml#L157-L234) + +Instead of entering each line individually, you can also add a batch file to +your autounattend that contains the commands for configuring winrm. Depending +on your winrm setup, this could be a complex batch file, or a very simple one. + +Below is an example of how we would call a batch file from inside the +Autounattend file. + +``` xml + + ... + + cmd.exe /c a:\winrmConfig.bat + Configure WinRM + 3 + true + + ... + +``` +It is also possible to call powershell scripts in a similar manner. + +The winrmConfig.bat referenced above can be as simple as + +``` +rem basic config for winrm +cmd.exe /c winrm quickconfig -q + +rem allow unencrypted traffic, and configure auth to use basic username/password auth +cmd.exe /c winrm set winrm/config/service @{AllowUnencrypted="true"} +cmd.exe /c winrm set winrm/config/service/auth @{Basic="true"} + +rem update firewall rules to open the right port and to allow remote administration +cmd.exe /c netsh advfirewall firewall set rule group="remote administration" new enable=yes + +rem restart winrm +cmd.exe /c net stop winrm +cmd.exe /c net start winrm +``` + +Please note that the above batch file is _extremely_ simplistic, and not secure. +It is intended to be an example of the bare minimum configuration. Below, you'll +find a more complicated example of a more secure WinRM configuration process. + +This batch file will only work for http connections, not https, but will enable +you to connect using only the username and password created earlier in the +Autounattend file. The above batchfile will allow you to connect using a very +simple Packer config: + +```json + "communicator": "winrm", + "winrm_username": "packeruser", + "winrm_password": "SecretPassword" +``` + +A more complex example of a powershell script used for configuration can be seen +below. + +```powershell +# A Packer config that works with this example would be: +# +# +# "winrm_username": "Administrator", +# "winrm_password": "SuperS3cr3t!!!", +# "winrm_insecure": true, +# "winrm_use_ssl": true +# +# + +# Create username and password +net user Administrator SuperS3cr3t!!! +wmic useraccount where "name='Administrator'" set PasswordExpires=FALSE + +Set-ExecutionPolicy Unrestricted -Scope LocalMachine -Force -ErrorAction Ignore + +# Don't set this before Set-ExecutionPolicy as it throws an error +$ErrorActionPreference = "stop" + +# Remove HTTP listener +Remove-Item -Path WSMan:\Localhost\listener\listener* -Recurse + +# Create a self-signed certificate to let ssl work +$Cert = New-SelfSignedCertificate -CertstoreLocation Cert:\LocalMachine\My -DnsName "packer" +New-Item -Path WSMan:\LocalHost\Listener -Transport HTTPS -Address * -CertificateThumbPrint $Cert.Thumbprint -Force + +# WinRM +write-output "Setting up WinRM" +write-host "(host) setting up WinRM" + +# Configure WinRM to allow unencrypted communication, and provide the +# self-signed cert to the WinRM listener. +cmd.exe /c winrm quickconfig -q +cmd.exe /c winrm set "winrm/config/service" '@{AllowUnencrypted="true"}' +cmd.exe /c winrm set "winrm/config/client" '@{AllowUnencrypted="true"}' +cmd.exe /c winrm set "winrm/config/service/auth" '@{Basic="true"}' +cmd.exe /c winrm set "winrm/config/client/auth" '@{Basic="true"}' +cmd.exe /c winrm set "winrm/config/service/auth" '@{CredSSP="true"}' +cmd.exe /c winrm set "winrm/config/listener?Address=*+Transport=HTTPS" "@{Port=`"5986`";Hostname=`"packer`";CertificateThumbprint=`"$($Cert.Thumbprint)`"}" + +# Make sure appropriate firewall port openings exist +cmd.exe /c netsh advfirewall firewall set rule group="remote administration" new enable=yes +cmd.exe /c netsh firewall add portopening TCP 5986 "Port 5986" + +# Restart WinRM, and set it so that it auto-launches on startup. +cmd.exe /c net stop winrm +cmd.exe /c sc config winrm start= auto +cmd.exe /c net start winrm +``` + +Please note that having WinRM auto-launch on all start ups may not be the right +choice for you, if you don't need the server to recieve WinRM connections in the +future. Clean up after yourself and close unnecesary firewall ports at a final +provisioning step to make sure your image is secure. + +#### Configuring WinRM in the Cloud + +Most clouds allow you to provide a configuration script that runs when the +instance is launched. In AWS, this is the +[user_data_file](/docs/builders/amazon-ebs.html#user_data_file). In Google +Cloud, this is provided using the `windows-startup-script-cmd` +[metadata](/docs/builders/googlecompute.html#metadata) tag. +[Example](/docs/builders/googlecompute.html#windows-example) + +Essentially, these files are powershell or cmd scripts that configure winrm, +without having to be wrapped in an Autounattend. Provide the script in the +format requested by each cloud, and make sure you manually configure any +firewall rules that the cloud doesn't allow you to manage internally. More +specific details for each cloud can be found in the builder sections. + +The above examples will work in cloud prep too, but may be overkill depending on +how much preconfiguration the cloud has done for you. \ No newline at end of file diff --git a/website/source/docs/templates/communicator.html.md.erb b/website/source/docs/templates/communicator.html.md.erb index 6d801e467..8e7fefc40 100644 --- a/website/source/docs/templates/communicator.html.md.erb +++ b/website/source/docs/templates/communicator.html.md.erb @@ -13,73 +13,40 @@ Communicators are the mechanism Packer uses to upload files, execute scripts, etc. with the machine being created. Communicators are configured within the -[builder](/docs/templates/builders.html) section. +[builder](/docs/templates/builders.html) section. All communicators have the following options: <%= partial "partials/helper/communicator/Config-not-required" %> -## Using a Communicator +## Getting Ready to Use the Communicator -By default, the SSH communicator is usually used. Additional configuration may -not even be necessary, since some builders such as Amazon automatically -configure everything. +Depending on your builder, your communicator may not have all it needs in order +to work "out of the box". -However, to specify a communicator, you set the `communicator` key within a -build. Multiple builds can have different communicators. Example: +If you are building from a cloud image (for example, building on Amazon), there +is a good chance that your cloud provider has already preconfigured SSH on the +image for you, meaning that all you have to do is configure the communicator in +the Packer template. -``` json -{ - "builders": [ - { - "type": "amazon-ebs", - "communicator": "ssh" - } - ] -} -``` +However, if you are building from a brand-new and unconfigured operating system +image, you will almost always have to perform some extra work to configure SSH +on the guest machine. For most operating system distributions, this work will +be performed by a [boot_command](/docs/builders/vmware-iso.html#boot-command) that references a file which +provides answers to the normally-interactive questions you get asked when +installing an operating system. The name of this file varies by operating +system; some common examples are the "preseed" file required by Debian, the +"kickstart" file required by CentOS or the "answer file", also known as the +Autounattend.xml file, required by Windows. For simplicity's sake, we'll refer +to this file as the "preseed" file in the rest of the documentation. -After specifying the `communicator`, you can specify a number of other -configuration parameters for that communicator. These are documented below. +If you are unfamiliar with how to use a preseed file for automatic +bootstrapping of an image, please either take a look at our quick guides to +image bootstrapping, or research automatic configuration for your specific +guest operating system. Knowing how to automatically initalize your operating +system is critical for being able to successfully use Packer. +## Communicator-Specific Options -## SSH Communicator - -The SSH communicator connects to the host via SSH. If you have an SSH agent -configured on the host running Packer, and SSH agent authentication is enabled -in the communicator config, Packer will automatically forward the SSH agent to -the remote host. - -The SSH communicator has the following options: - -<%= partial "partials/helper/communicator/SSH-not-required" %> - -### SSH Communicator Details - -Packer will only use one authentication method, either `publickey` or if -`ssh_password` is used packer will offer `password` and `keyboard-interactive` -both sending the password. In other words Packer will not work with *sshd* -configured with more than one configured authentication method using -`AuthenticationMethods`. - -Packer supports the following ciphers: - -- aes128-ctr -- aes192-ctr -- aes256-ctr -- arcfour128 -- arcfour256 -- arcfour -- `es128-gcm@openssh.com` -- `acha20-poly1305@openssh.com` - -And the following MACs: - -- hmac-sha1 -- hmac-sha1-96 -- hmac-sha2-256 -- `hmac-sha2-256-etm@openssh.com` - -## WinRM Communicator - -<%= partial "partials/helper/communicator/WinRM-not-required" %> +For more details on how to use each communicator, visit the +[communicators](/docs/communicators/index.html) page. \ No newline at end of file diff --git a/website/source/guides/automatic-operating-system-installs/autounattend_windows.html.md b/website/source/guides/automatic-operating-system-installs/autounattend_windows.html.md new file mode 100644 index 000000000..0f6404ff8 --- /dev/null +++ b/website/source/guides/automatic-operating-system-installs/autounattend_windows.html.md @@ -0,0 +1,97 @@ +--- +layout: guides +sidebar_current: automatic-operating-system-installs-unattended-installation-windows +page_title: Unattended Windows Installation +description: |- + Learn how to use an autounattend file to automatically answer installation + questions and enable Packer to connect to your windows instnace. +--- + +# Unattended Installation for Windows + +Unattended Windows installation is done via "Answer Files", or "Unattend files". + +These files are generally named "autounattend.xml". They are not +Packer-specific tools, though we do make use of them. + +If, after following this guide, you're still having issues getting an answer +file working, We recommend you read the official documentation on +[answer files](https://docs.microsoft.com/en-us/windows-hardware/manufacture/desktop/update-windows-settings-and-scripts-create-your-own-answer-file-sxs). + +The guide here is hopefully enough to get you started, but isn't a replacement +for the official documentation. + +## When To Use an Answer File + +If you are installing the Windows Operating System from a mounted iso as part of +your Packer build, you will need to use an Answer file. For example, you're +building an image from scratch using the [vmware-iso](/docs/builders/vmware-iso.html), +[virtualbox-iso](/docs/builders/virtualbox-iso.html), or +[hyperv-iso](/docs/builders/hyperv-iso.html) builders. + +If you are not installing the operating system, you won't need to provide an +answer file. If you are using a pre-built image +in a cloud, you don't need to worry about Answer files. + +## How to make an Answer File + +You can either start from an example answer file from a known repo (take a look +at the examples links below), or you can generate one using an answer file +wizard by selecting New File > New Answer file on a Windows machine. +A comprehensive list of all the options you can set in an answer file can be +found [here](https://docs.microsoft.com/en-us/windows-hardware/customize/desktop/unattend/components-b-unattend) + +## Where to put the Answer File + +Windows will automatically look for an autounattend.xml file on mounted drives. +Many users use the `floppy_files` option or a secondary mounted iso for +providing the answer file to their iso builders. + +You can also specify an unattend file to use by using the /unattend: option when +running Windows Setup (setup.exe) in your `boot_command`. + +## What does Packer _need_ the Answer File to do? + +Packer needs the Answer File to handle any questions that would normally be +answered interactively during a Windows installation. + +If you want to be able to use provisioners, the Answer file must also contain +a script that sets up SSH or WinRM so that Packer can connect to the instance. + +Finally, your Packer build will be much smoother if the Answer File handles or +disables windows updates rather than you tyring to run them using a Packer +provisioner. This is because the winrm communicator does not handle the +disconnects caused by automatic reboots in Windows updates well, and the +disconnections can fail a build. + +## Examples + +The chef-maintained bento boxes are a great example of a windows build that +sets up openssh as part of the unattended installation so that Packer can +connect using the ssh communicator. They functioning answer files for every +modern Windows version. +https://github.com/chef/bento/tree/master/packer_templates/windows/answer_files + +Stefan Scherer's packer-windows repo is a great example of windows builds that +set up WinRM as part of the unattended installation so that Packer can connect +using the winrm communicator: +https://github.com/StefanScherer/packer-windows + +``` json + { + "type": "virtualbox-iso", + "guest_os_type": "Windows2008_64", + "iso_url": "https://download.microsoft.com/download/7/5/E/75EC4E54-5B02-42D6-8879-D8D3A25FBEF7/7601.17514.101119-1850_x64fre_server_eval_en-us-GRMSXEVAL_EN_DVD.iso", + "iso_checksum": "30832AD76CCFA4CE48CCB936EDEFE02079D42FB1DA32201BF9E3A880C8ED6312", + "iso_checksum_type": "sha256", + "shutdown_command": "shutdown /s /t 10 /f /d p:4:1 /c Packer_Provisioning_Shutdown", + "guest_additions_mode": "attach", + "floppy_files": [ + "./scripts/Autounattend.xml", + "./scripts/openssh.ps1" + ], + "communicator": "winrm", + "winrm_username": "vagrant", + "winrm_password": "vagrant" + } +``` \ No newline at end of file diff --git a/website/source/guides/automatic-operating-system-installs/index.html.md b/website/source/guides/automatic-operating-system-installs/index.html.md new file mode 100644 index 000000000..b5f711e2e --- /dev/null +++ b/website/source/guides/automatic-operating-system-installs/index.html.md @@ -0,0 +1,26 @@ +--- +layout: guides +sidebar_current: automatic-operating-system-installs +page_title: Automatic OS Installs +description: |- + Learn how to use preseed, kickstart, and autounattend files to automatically + answer installation questions and enable Packer to connect to your instnace. +--- + +# Automatic OS Installs + +If you are building from a brand-new and unconfigured operating system +image, Packer will need you to perform the operating system install before it +can connect to and configure your image using its provisioners. Most operating +system distributions have a mechanism for performing the normally-interactive +installation in an automated way. For Debian operating systems, this is done +using a preseed file; for Windows, it's done using an Autounattend.xml. We have +compiled some simple guides here for common operating system distributions. + +These guides are meant to give you a quick introduction to how to use automated +installation answer files in order to perfom those installs; we don't mean to +be a comprehensive guide on each operating system, but we hope to give you +enough context to be able to more easily find any further information you need. + +Please use the left-hand navigation to find instructions for the operating +system that is relevant to you. \ No newline at end of file diff --git a/website/source/guides/automatic-operating-system-installs/preseed_ubuntu.html.md b/website/source/guides/automatic-operating-system-installs/preseed_ubuntu.html.md new file mode 100644 index 000000000..3c55c4162 --- /dev/null +++ b/website/source/guides/automatic-operating-system-installs/preseed_ubuntu.html.md @@ -0,0 +1,179 @@ +--- +layout: guides +sidebar_current: automatic-operating-system-installs-unattended-installation-debian +page_title: Unattended Debian/Ubuntu Installation +description: |- + Learn how to use a preseed file to automatically answer installation + questions and enable Packer to connect to your Debian instnace. +--- + +# Unattended Installation for Debian + +Unattended Debian/Ubuntu installation is done via "preseed" files + +These files are generally named "preseed.cfg". They are not +Packer-specific tools, though we do make use of them. + +If, after following this guide, you're still having issues getting a preseed +file working, We recommend you read the official documentation on +[preseed files](https://wiki.debian.org/DebianInstaller/Preseed). + +The guide here is hopefully enough to get you started, but isn't a replacement +for the official documentation. + +## When To Use a Preseed File + +If you are installing the operating system from a mounted iso as part of +your Packer build, you will need to use a preseed file. For example, you're +building an image from scratch using the [vmware-iso](/docs/builders/vmware-iso.html), +[virtualbox-iso](/docs/builders/virtualbox-iso.html), or +[hyperv-iso](/docs/builders/hyperv-iso.html) builders. + +If you are not installing the operating system, you won't need to provide a +preseed file. If you are using a pre-built image in a cloud, you don't need to +worry about preseed files. + +## How to make a Preseed File + +You can either start from an example preseed file from a known repo (take a look +at the examples links below), or you can start with the official [example +preseed](https://www.debian.org/releases/stable/example-preseed.txt), and +comment or uncomment the options as you need them. + +## Where to put the preseed file + +The `-iso` builders mentioned above all have an `http_dir` option. Any file +inside of your `http_dir` will be served on a local fileserver for your virtual +machine to be able to access. One very common use for this directory is to use +it to provide your preseed file. + +You then reference the file using a `boot_command` to kick off the installation. +In the example below, see how the `preseed/url` command line option is being +used in the `/install/vmlinuz command`. The `{{ .HTTPIP }}` and +`{{ .HTTPPort }}` options are special Packer template options that will get set +by Packer to point to the http server we create, so that your boot command can +access it. For an example of a working boot_command, see the Examples section +below. For more information on how boot_command works, see the +boot_command section of the docs for whatever builder you are using. + +## What does Packer _need_ the preseed file to do? + +Packer needs the preseed file to handle any questions that would normally be +answered interactively during a Debian installation. + +If you want to be able to use provisioners, the preseed file must also install +SSH so that Packer can connect to the instance. + +## Examples + +A very minimal example of a preseed file can be found below. Much of this was +copied from the official example-preseed shared above. Notice that we are +installing ssh via `d-i pkgsel/include string openssh-server` and configuring +a username so that Packer will be able to connect. + +You need to make sure that your mirror settings are properly configured for your +specific distribution of Debian. + +``` +# Preseeding only locale sets language, country and locale. +d-i debian-installer/locale string en_US + +# Keyboard selection. +d-i console-setup/ask_detect boolean false +d-i keyboard-configuration/xkb-keymap select us + +choose-mirror-bin mirror/http/proxy string + +### Clock and time zone setup +d-i clock-setup/utc boolean true +d-i time/zone string UTC + +# Avoid that last message about the install being complete. +d-i finish-install/reboot_in_progress note + +# This is fairly safe to set, it makes grub install automatically to the MBR +# if no other operating system is detected on the machine. +d-i grub-installer/only_debian boolean true + +# This one makes grub-installer install to the MBR if it also finds some other +# OS, which is less safe as it might not be able to boot that other OS. +d-i grub-installer/with_other_os boolean true + +### Mirror settings +# If you select ftp, the mirror/country string does not need to be set. +d-i mirror/country string manual +d-i mirror/http/directory string /ubuntu/ +d-i mirror/http/hostname string archive.ubuntu.com +d-i mirror/http/proxy string + +### Partitioning +d-i partman-auto/method string lvm + +# This makes partman automatically partition without confirmation. +d-i partman-md/confirm boolean true +d-i partman-partitioning/confirm_write_new_label boolean true +d-i partman/choose_partition select finish +d-i partman/confirm boolean true +d-i partman/confirm_nooverwrite boolean true + +### Account setup +d-i passwd/user-fullname string vagrant +d-i passwd/user-uid string 1000 +d-i passwd/user-password password vagrant +d-i passwd/user-password-again password vagrant +d-i passwd/username string vagrant + +# The installer will warn about weak passwords. If you are sure you know +# what you're doing and want to override it, uncomment this. +d-i user-setup/allow-password-weak boolean true +d-i user-setup/encrypt-home boolean false + +### Package selection +tasksel tasksel/first standard +d-i pkgsel/include string openssh-server build-essential +d-i pkgsel/install-language-support boolean false + +# disable automatic package updates +d-i pkgsel/update-policy select none +d-i pkgsel/upgrade select full-upgrade +``` + +Here's an example of the vmware-iso builder being used to call this preseed. +In this case, it is assumed that the file is saved as preseed.cfg inside of a +directory called "http", and Packer is being called from the directory +containing the "http" directory. + +``` + "builders": [ + { + "boot_command": [ + "", + "", + "", + "/install/vmlinuz", + " initrd=/install/initrd.gz", + " auto-install/enable=true", + " debconf/priority=critical", + " preseed/url=http://{{ .HTTPIP }}:{{ .HTTPPort }}/preseed_2.cfg", + " -- ", + "" + ], + "boot_wait": "10s", + "guest_os_type": "ubuntu-64", + "http_directory": "http", + "iso_checksum_type": "sha256", + "iso_checksum_url": "file:///Users/mmarsh/dev/repro_cases/packer_cache/shasums.txt", + "iso_url": "http://old-releases.ubuntu.com/releases/14.04.1/ubuntu-14.04.1-server-amd64.iso", + "shutdown_command": "echo 'vagrant' | sudo -S shutdown -P now", + "ssh_password": "vagrant", + "ssh_username": "vagrant", + "ssh_wait_timeout": "10000s", + "tools_upload_flavor": "linux", + "type": "vmware-iso" + } + ], +``` + +For more functional examples of a debian preseeded installation, you can see the +Chef-maintained bento boxes for [Debian](https://github.com/chef/bento/tree/master/packer_templates/debian) +and [Ubuntu](https://github.com/chef/bento/tree/master/packer_templates/ubuntu) \ No newline at end of file diff --git a/website/source/guides/workflow-tips-and-tricks/index.html.md b/website/source/guides/workflow-tips-and-tricks/index.html.md new file mode 100644 index 000000000..6a513ea28 --- /dev/null +++ b/website/source/guides/workflow-tips-and-tricks/index.html.md @@ -0,0 +1,13 @@ +--- +layout: guides +sidebar_current: workflow-tips-and-tricks +page_title: Tips and Tricks +description: |- + The guides stored in this section are miscellanious tips and tricks that might + make your experience of using Packer easier +--- + +# Tips and Tricks + +Click the sidebar navigation to check out the miscellaneous guides we have for +making your life with Packer just a bit easier. diff --git a/website/source/guides/isotime-template-function.html.md b/website/source/guides/workflow-tips-and-tricks/isotime-template-function.html.md similarity index 96% rename from website/source/guides/isotime-template-function.html.md rename to website/source/guides/workflow-tips-and-tricks/isotime-template-function.html.md index 48c084704..7eacf521e 100644 --- a/website/source/guides/isotime-template-function.html.md +++ b/website/source/guides/workflow-tips-and-tricks/isotime-template-function.html.md @@ -1,6 +1,6 @@ --- layout: guides -sidebar_current: isotime-template-function +sidebar_current: workflow-tips-and-tricks-isotime-template-function page_title: Using the isotime template function - Guides description: |- It can be a bit confusing to figure out how to format your isotime using the diff --git a/website/source/guides/use-packer-with-comment.html.md b/website/source/guides/workflow-tips-and-tricks/use-packer-with-comment.html.md similarity index 96% rename from website/source/guides/use-packer-with-comment.html.md rename to website/source/guides/workflow-tips-and-tricks/use-packer-with-comment.html.md index 52fbaa7dc..e3176653e 100644 --- a/website/source/guides/use-packer-with-comment.html.md +++ b/website/source/guides/workflow-tips-and-tricks/use-packer-with-comment.html.md @@ -1,6 +1,6 @@ --- layout: guides -sidebar_current: use-packer-with-comment +sidebar_current: workflow-tips-and-tricks-use-packer-with-comment page_title: Use jq and Packer to comment your templates - Guides description: |- You can add detailed comments beyond the root-level underscore-prefixed field diff --git a/website/source/guides/veewee-to-packer.html.md b/website/source/guides/workflow-tips-and-tricks/veewee-to-packer.html.md similarity index 97% rename from website/source/guides/veewee-to-packer.html.md rename to website/source/guides/workflow-tips-and-tricks/veewee-to-packer.html.md index 710cbae72..5c4c7a3d7 100644 --- a/website/source/guides/veewee-to-packer.html.md +++ b/website/source/guides/workflow-tips-and-tricks/veewee-to-packer.html.md @@ -1,6 +1,6 @@ --- layout: guides -sidebar_current: guides-veewee-to-packer +sidebar_current: workflow-tips-and-tricks-guides-veewee-to-packer page_title: Convert Veewee Definitions to Packer Templates - Guides description: |- If you are or were a user of Veewee, then there is an official tool called diff --git a/website/source/layouts/docs.erb b/website/source/layouts/docs.erb index 11c9f8a49..6593ae9f9 100644 --- a/website/source/layouts/docs.erb +++ b/website/source/layouts/docs.erb @@ -53,6 +53,18 @@
+ > + Communicators + + + > Builders