diff --git a/docs/resources/dhcp_relay.md b/docs/resources/dhcp_relay.md new file mode 100644 index 00000000..c436654d --- /dev/null +++ b/docs/resources/dhcp_relay.md @@ -0,0 +1,52 @@ +--- +page_title: "panos: panos_dhcp_relay" +subcategory: "Network" +--- + +# panos_bgp + +This resource allows you to add/update/delete a dhcp relay. + + +## PAN-OS + +NGFW + + +## Import Name + +``` + +``` + + +## Example Usage + +```hcl +resource "panos_dhcp_relay" "relay" { + name = "ethernet1/3" + ipv4_enabled = true + ipv4_servers = [ + "203.0.113.1", + "203.0.113.254", + ] + ipv6_enabled = true + ipv6_servers = [ + { + server = "2001:db8::1", + interface = "ethernet1/3", + } + ] +} +``` + +## Argument Reference + +The following arguments are supported: + +* `name` - (Required, string) The name of the interface to add the dhcp relay to. +* `ipv4_enabled` - (Optional, bool) Enable IPv4 DHCP relay. +* `ipv4_servers` - (Optional, list(string)) List of IPv4 DHCP servers. +* `ipv6_enabled` - (Optional, bool) Enable IPv6 DHCP relay. +* `ipv6_servers` - (Optional, list(object)) List of IPv6 DHCP servers. +* `vsys` - (Optional) The vsys location (default: `vsys1`). diff --git a/panos/provider.go b/panos/provider.go index bed7f3d9..78f7a303 100644 --- a/panos/provider.go +++ b/panos/provider.go @@ -185,6 +185,7 @@ func Provider() terraform.ResourceProvider { "panos_custom_url_category_entry": resourceCustomUrlCategoryEntry(), "panos_data_filtering_security_profile": resourceDataFilteringSecurityProfile(), "panos_decryption_rule_group": resourceDecryptionRuleGroup(), + "panos_dhcp_relay": resourceDhcpRelay(), "panos_dos_protection_profile": resourceDosProtectionProfile(), "panos_dynamic_user_group": resourceDynamicUserGroup(), "panos_file_blocking_security_profile": resourceFileBlockingSecurityProfile(), diff --git a/panos/resource_dhcp_relay.go b/panos/resource_dhcp_relay.go new file mode 100644 index 00000000..60e05930 --- /dev/null +++ b/panos/resource_dhcp_relay.go @@ -0,0 +1,203 @@ +package panos + +import ( + "fmt" + + "github.com/PaloAltoNetworks/pango" + "github.com/PaloAltoNetworks/pango/netw/dhcp" + + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" +) + +func resourceDhcpRelay() *schema.Resource { + return &schema.Resource{ + Create: createDhcpRelay, + Read: readDhcpRelay, + Update: updateDhcpRelay, + Delete: deleteDhcpRelay, + + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "Interface to enable dhcp relay on", + }, + "vsys": { + Type: schema.TypeString, + Optional: true, + Default: "vsys1", + ForceNew: true, + Description: "Vsys to put interface in", + }, + "ipv4_enabled": { + Type: schema.TypeBool, + Optional: true, + Description: "Enables dhcp relay for ipv4", + }, + "ipv6_enabled": { + Type: schema.TypeBool, + Optional: true, + Description: "Enables dhcp relay for ipv6", + }, + "ipv4_servers": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + Description: "List of ipv4 dhcp servers", + }, + "ipv6_servers": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "server": { + Type: schema.TypeString, + Optional: true, + }, + "interface": { + Type: schema.TypeString, + Optional: true, + }, + }, + Description: "List of ipv6 dhcp servers", + }, + }, + }, + } +} + +func parseDhcpRelay(d *schema.ResourceData) (string, dhcp.Entry) { + vsys := d.Get("vsys").(string) + + if !castIntoBool(d.Get("ipv4_enabled")) && !castIntoBool(d.Get("ipv6_enabled")) { + return "", dhcp.Entry{} + } + + o := dhcp.Entry{ + Name: d.Get("name").(string), + + Relay: &dhcp.Relay{ + Ipv4Enabled: castIntoBool(d.Get("ipv4_enabled")), + Ipv4Servers: flattenIPv4DhcpServers(d.Get("ipv4_servers")), + Ipv6Enabled: castIntoBool(d.Get("ipv6_enabled")), + Ipv6Servers: flattenIPv6DhcpServers(d.Get("ipv6_servers")), + }, + } + + return vsys, o +} + +func castIntoBool(v interface{}) bool { + return v.(bool) +} + +func flattenIPv4DhcpServers(o interface{}) []string { + var d []string + for _, v := range o.([]interface{}) { + d = append(d, v.(string)) + } + return d +} + +func flattenIPv6DhcpServers(d interface{}) []dhcp.Ipv6Server { + var o []dhcp.Ipv6Server + for _, v := range d.([]interface{}) { + m := v.(map[string]interface{}) + o = append(o, dhcp.Ipv6Server{ + Server: m["server"].(string), + Interface: m["interface"].(string), + }) + } + return o +} + +func isEmpty(o dhcp.Entry) bool { + return !o.Relay.Ipv4Enabled && !o.Relay.Ipv6Enabled && len(o.Relay.Ipv4Servers) ==0 && len(o.Relay.Ipv6Servers) == 0 +} + +func readDhcpRelay(d *schema.ResourceData, meta interface{}) error { + var err error + + fw := meta.(*pango.Firewall) + name := d.Get("name").(string) + + o, err := fw.Network.Dhcp.Get(name) + if err != nil { + if isObjectNotFound(err) { + d.SetId("") + return nil + } + return err + } + + d.Set("name", o.Name) + d.Set("ipv4_enabled", o.Relay.Ipv4Enabled) + d.Set("ipv6_enabled", o.Relay.Ipv6Enabled) + d.Set("ipv4_servers", o.Relay.Ipv6Enabled) + d.Set("ipv6_servers", o.Relay.Ipv6Servers) + + return nil +} + +func createDhcpRelay(d *schema.ResourceData, meta interface{}) error { + fw := meta.(*pango.Firewall) + vsys, o := parseDhcpRelay(d) + + if vsys == "" && isEmpty(o) { + return fmt.Errorf("[ERROR] Error in creating DHCP relay: no valid configuration provided") + } + + if err := fw.Network.Dhcp.Set(o); err != nil { + return err + } + + d.SetId(resource.UniqueId()) + return d.Set("vsys", vsys) +} + +func updateDhcpRelay(d *schema.ResourceData, meta interface{}) error { + var err error + + fw := meta.(*pango.Firewall) + name := d.Get("name").(string) + + dg, err := fw.Network.Dhcp.Get(name) + if err != nil { + return err + } + + vsys, o := parseDhcpRelay(d) + + if vsys == "" && isEmpty(o) { + return fmt.Errorf("[ERROR] Error in updating DHCP relay: no valid configuration provided") + } + + dg.Copy(o) + if err = fw.Network.Dhcp.Edit(o); err != nil { + return err + } + + return readDhcpRelay(d, meta) +} + +func deleteDhcpRelay(d *schema.ResourceData, meta interface{}) error { + fw := meta.(*pango.Firewall) + name := d.Get("name").(string) + + err := fw.Network.Dhcp.Delete(name) + if err != nil { + if isObjectNotFound(err) { + return err + } + } + d.SetId("") + return nil +} diff --git a/panos/resource_dhcp_relay_test.go b/panos/resource_dhcp_relay_test.go new file mode 100644 index 00000000..677eea35 --- /dev/null +++ b/panos/resource_dhcp_relay_test.go @@ -0,0 +1,39 @@ +package panos + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" +) + +func TestAccPanosDhcpRelay_basic(t *testing.T) { + if !testAccIsFirewall { + t.Skip(SkipFirewallAccTest) + } + + resource.Test(t, resource.TestCase{ + PreCheck: func() { + testAccPreCheck(t) + }, + Providers: testAccProviders, + + Steps: []resource.TestStep{ + { + Config: fmt.Sprintf(` + resource "panos_dhcp_relay" "test" { + name = "test-eth0" + ipv4_enabled = true + ipv4_servers = [ + "10.1.0.1", + "10.2.0.1", + ] + }`), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("panos_dhcp_relay.test", "name", "test-eth0"), + resource.TestCheckResourceAttr("panos_dhcp_relay.ipv4_servers", "#", "2"), + ), + }, + }, + }) +}