diff --git a/docs/resources/virtual_environment_sdn_zone_evpn.md b/docs/resources/virtual_environment_sdn_zone_evpn.md index fc2b9efc..1b94d637 100644 --- a/docs/resources/virtual_environment_sdn_zone_evpn.md +++ b/docs/resources/virtual_environment_sdn_zone_evpn.md @@ -11,19 +11,45 @@ description: |- EVPN Zone in Proxmox SDN. The EVPN zone creates a routable Layer 3 network, capable of spanning across multiple clusters. +## Example Usage +```terraform +resource "proxmox_virtual_environment_sdn_zone_evpn" "example" { + id = "evpn1" + nodes = ["pve"] + controller = "evpn-controller1" + vrf_vxlan = 4000 + + # Optional attributes + advertise_subnets = true + disable_arp_nd_suppression = false + exit_nodes = ["pve-exit1", "pve-exit2"] + exit_nodes_local_routing = true + primary_exit_node = "pve-exit1" + rt_import = "65000:65000" + mtu = 1450 + + # Generic optional attributes + dns = "1.1.1.1" + dns_zone = "example.com" + ipam = "pve" + reverse_dns = "1.1.1.1" +} +``` ## Schema ### Required +- `controller` (String) EVPN controller address. - `id` (String) The unique identifier of the SDN zone. +- `nodes` (Set of String) The Proxmox nodes which the zone and associated VNets should be deployed on +- `vrf_vxlan` (Number) VRF VXLAN-ID used for dedicated routing interconnect between VNets. It must be different than the VXLAN-ID of the VNets. ### Optional - `advertise_subnets` (Boolean) Enable subnet advertisement for EVPN. -- `controller` (String) EVPN controller address. - `disable_arp_nd_suppression` (Boolean) Disable ARP/ND suppression for EVPN. - `dns` (String) DNS API server address. - `dns_zone` (String) DNS domain name. Used to register hostnames, such as `.`. The DNS zone must already exist on the DNS server. @@ -31,8 +57,16 @@ EVPN Zone in Proxmox SDN. The EVPN zone creates a routable Layer 3 network, capa - `exit_nodes_local_routing` (Boolean) Enable local routing for EVPN exit nodes. - `ipam` (String) IP Address Management system. - `mtu` (Number) MTU value for the zone. -- `nodes` (Set of String) Proxmox node names. - `primary_exit_node` (String) Primary exit node for EVPN. - `reverse_dns` (String) Reverse DNS API server address. - `rt_import` (String) Route target import for EVPN. -- `vrf_vxlan` (Number) VRF VXLAN-ID used for dedicated routing interconnect between VNets. It must be different than the VXLAN-ID of the VNets. + +## Import + +Import is supported using the following syntax: + +```shell +#!/usr/bin/env sh +# EVPN SDN zone can be imported using its unique identifier (zone ID) +terraform import proxmox_virtual_environment_sdn_zone_evpn.example evpn1 +``` diff --git a/docs/resources/virtual_environment_sdn_zone_qinq.md b/docs/resources/virtual_environment_sdn_zone_qinq.md index 7cad37b5..7b72b785 100644 --- a/docs/resources/virtual_environment_sdn_zone_qinq.md +++ b/docs/resources/virtual_environment_sdn_zone_qinq.md @@ -11,23 +11,50 @@ description: |- QinQ Zone in Proxmox SDN. QinQ also known as VLAN stacking, that uses multiple layers of VLAN tags for isolation. The QinQ zone defines the outer VLAN tag (the Service VLAN) whereas the inner VLAN tag is defined by the VNet. Your physical network switches must support stacked VLANs for this configuration. Due to the double stacking of tags, you need 4 more bytes for QinQ VLANs. For example, you must reduce the MTU to 1496 if you physical interface MTU is 1500. +## Example Usage +```terraform +resource "proxmox_virtual_environment_sdn_zone_qinq" "example" { + id = "qinq1" + nodes = ["pve"] + bridge = "vmbr0" + service_vlan = 100 + service_vlan_protocol = "802.1ad" + mtu = 1496 + + # Optional attributes + dns = "1.1.1.1" + dns_zone = "example.com" + ipam = "pve" + reverse_dns = "1.1.1.1" +} +``` ## Schema ### Required +- `bridge` (String) A local, VLAN-aware bridge that is already configured on each local node - `id` (String) The unique identifier of the SDN zone. +- `nodes` (Set of String) The Proxmox nodes which the zone and associated VNets should be deployed on +- `service_vlan` (Number) Service VLAN tag for QinQ. The tag must be between `1` and `4094`. ### Optional -- `bridge` (String) A local, VLAN-aware bridge that is already configured on each local node - `dns` (String) DNS API server address. - `dns_zone` (String) DNS domain name. Used to register hostnames, such as `.`. The DNS zone must already exist on the DNS server. - `ipam` (String) IP Address Management system. - `mtu` (Number) MTU value for the zone. -- `nodes` (Set of String) Proxmox node names. - `reverse_dns` (String) Reverse DNS API server address. -- `service_vlan` (Number) Service VLAN tag for QinQ. -- `service_vlan_protocol` (String) Service VLAN protocol for QinQ. +- `service_vlan_protocol` (String) Service VLAN protocol for QinQ. The protocol must be `802.1ad` or `802.1q`. + +## Import + +Import is supported using the following syntax: + +```shell +#!/usr/bin/env sh +# QinQ SDN zone can be imported using its unique identifier (zone ID) +terraform import proxmox_virtual_environment_sdn_zone_qinq.example qinq1 +``` diff --git a/docs/resources/virtual_environment_sdn_zone_simple.md b/docs/resources/virtual_environment_sdn_zone_simple.md index ab922e64..92600448 100644 --- a/docs/resources/virtual_environment_sdn_zone_simple.md +++ b/docs/resources/virtual_environment_sdn_zone_simple.md @@ -11,7 +11,21 @@ description: |- Simple Zone in Proxmox SDN. It will create an isolated VNet bridge. This bridge is not linked to a physical interface, and VM traffic is only local on each the node. It can be used in NAT or routed setups. +## Example Usage +```terraform +resource "proxmox_virtual_environment_sdn_zone_simple" "example" { + id = "simple1" + nodes = ["pve"] + mtu = 1500 + + # Optional attributes + dns = "1.1.1.1" + dns_zone = "example.com" + ipam = "pve" + reverse_dns = "1.1.1.1" +} +``` ## Schema @@ -19,6 +33,7 @@ Simple Zone in Proxmox SDN. It will create an isolated VNet bridge. This bridge ### Required - `id` (String) The unique identifier of the SDN zone. +- `nodes` (Set of String) The Proxmox nodes which the zone and associated VNets should be deployed on ### Optional @@ -26,5 +41,14 @@ Simple Zone in Proxmox SDN. It will create an isolated VNet bridge. This bridge - `dns_zone` (String) DNS domain name. Used to register hostnames, such as `.`. The DNS zone must already exist on the DNS server. - `ipam` (String) IP Address Management system. - `mtu` (Number) MTU value for the zone. -- `nodes` (Set of String) Proxmox node names. - `reverse_dns` (String) Reverse DNS API server address. + +## Import + +Import is supported using the following syntax: + +```shell +#!/usr/bin/env sh +# Simple SDN zone can be imported using its unique identifier (zone ID) +terraform import proxmox_virtual_environment_sdn_zone_simple.example simple1 +``` diff --git a/docs/resources/virtual_environment_sdn_zone_vlan.md b/docs/resources/virtual_environment_sdn_zone_vlan.md index 921f4187..3cb0b5eb 100644 --- a/docs/resources/virtual_environment_sdn_zone_vlan.md +++ b/docs/resources/virtual_environment_sdn_zone_vlan.md @@ -11,21 +11,46 @@ description: |- VLAN Zone in Proxmox SDN. It uses an existing local Linux or OVS bridge to connect to the node's physical interface. It uses VLAN tagging defined in the VNet to isolate the network segments. This allows connectivity of VMs between different nodes. +## Example Usage +```terraform +resource "proxmox_virtual_environment_sdn_zone_vlan" "example" { + id = "vlan1" + nodes = ["pve"] + bridge = "vmbr0" + mtu = 1500 + + # Optional attributes + dns = "1.1.1.1" + dns_zone = "example.com" + ipam = "pve" + reverse_dns = "1.1.1.1" +} +``` ## Schema ### Required +- `bridge` (String) The local bridge or OVS switch, already configured on _each_ node that allows node-to-node connection. - `id` (String) The unique identifier of the SDN zone. +- `nodes` (Set of String) The Proxmox nodes which the zone and associated VNets should be deployed on ### Optional -- `bridge` (String) The local bridge or OVS switch, already configured on _each_ node that allows node-to-node connection. - `dns` (String) DNS API server address. - `dns_zone` (String) DNS domain name. Used to register hostnames, such as `.`. The DNS zone must already exist on the DNS server. - `ipam` (String) IP Address Management system. - `mtu` (Number) MTU value for the zone. -- `nodes` (Set of String) Proxmox node names. - `reverse_dns` (String) Reverse DNS API server address. + +## Import + +Import is supported using the following syntax: + +```shell +#!/usr/bin/env sh +# VLAN SDN zone can be imported using its unique identifier (zone ID) +terraform import proxmox_virtual_environment_sdn_zone_vlan.example vlan1 +``` diff --git a/docs/resources/virtual_environment_sdn_zone_vxlan.md b/docs/resources/virtual_environment_sdn_zone_vxlan.md index 9879f5c3..630f2a3a 100644 --- a/docs/resources/virtual_environment_sdn_zone_vxlan.md +++ b/docs/resources/virtual_environment_sdn_zone_vxlan.md @@ -11,7 +11,22 @@ description: |- VXLAN Zone in Proxmox SDN. It establishes a tunnel (overlay) on top of an existing network (underlay). This encapsulates layer 2 Ethernet frames within layer 4 UDP datagrams using the default destination port 4789. You have to configure the underlay network yourself to enable UDP connectivity between all peers. Because VXLAN encapsulation uses 50 bytes, the MTU needs to be 50 bytes lower than the outgoing physical interface. +## Example Usage +```terraform +resource "proxmox_virtual_environment_sdn_zone_vxlan" "example" { + id = "vxlan1" + nodes = ["pve"] + peers = ["10.0.0.1", "10.0.0.2", "10.0.0.3"] + mtu = 1450 + + # Optional attributes + dns = "1.1.1.1" + dns_zone = "example.com" + ipam = "pve" + reverse_dns = "1.1.1.1" +} +``` ## Schema @@ -19,6 +34,8 @@ VXLAN Zone in Proxmox SDN. It establishes a tunnel (overlay) on top of an existi ### Required - `id` (String) The unique identifier of the SDN zone. +- `nodes` (Set of String) The Proxmox nodes which the zone and associated VNets should be deployed on +- `peers` (Set of String) A list of IP addresses of each node in the VXLAN zone. This can be external nodes reachable at this IP address. All nodes in the cluster need to be mentioned here ### Optional @@ -26,6 +43,14 @@ VXLAN Zone in Proxmox SDN. It establishes a tunnel (overlay) on top of an existi - `dns_zone` (String) DNS domain name. Used to register hostnames, such as `.`. The DNS zone must already exist on the DNS server. - `ipam` (String) IP Address Management system. - `mtu` (Number) MTU value for the zone. -- `nodes` (Set of String) Proxmox node names. -- `peers` (Set of String) A list of IP addresses of each node in the VXLAN zone. This can be external nodes reachable at this IP address. All nodes in the cluster need to be mentioned here - `reverse_dns` (String) Reverse DNS API server address. + +## Import + +Import is supported using the following syntax: + +```shell +#!/usr/bin/env sh +# VXLAN SDN zone can be imported using its unique identifier (zone ID) +terraform import proxmox_virtual_environment_sdn_zone_vxlan.example vxlan1 +``` diff --git a/examples/resources/proxmox_virtual_environment_sdn_zone_evpn/import.sh b/examples/resources/proxmox_virtual_environment_sdn_zone_evpn/import.sh new file mode 100644 index 00000000..77ec54de --- /dev/null +++ b/examples/resources/proxmox_virtual_environment_sdn_zone_evpn/import.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env sh +# EVPN SDN zone can be imported using its unique identifier (zone ID) +terraform import proxmox_virtual_environment_sdn_zone_evpn.example evpn1 diff --git a/examples/resources/proxmox_virtual_environment_sdn_zone_evpn/resource.tf b/examples/resources/proxmox_virtual_environment_sdn_zone_evpn/resource.tf new file mode 100644 index 00000000..1993be2b --- /dev/null +++ b/examples/resources/proxmox_virtual_environment_sdn_zone_evpn/resource.tf @@ -0,0 +1,21 @@ +resource "proxmox_virtual_environment_sdn_zone_evpn" "example" { + id = "evpn1" + nodes = ["pve"] + controller = "evpn-controller1" + vrf_vxlan = 4000 + + # Optional attributes + advertise_subnets = true + disable_arp_nd_suppression = false + exit_nodes = ["pve-exit1", "pve-exit2"] + exit_nodes_local_routing = true + primary_exit_node = "pve-exit1" + rt_import = "65000:65000" + mtu = 1450 + + # Generic optional attributes + dns = "1.1.1.1" + dns_zone = "example.com" + ipam = "pve" + reverse_dns = "1.1.1.1" +} diff --git a/examples/resources/proxmox_virtual_environment_sdn_zone_qinq/import.sh b/examples/resources/proxmox_virtual_environment_sdn_zone_qinq/import.sh new file mode 100644 index 00000000..ee146ff5 --- /dev/null +++ b/examples/resources/proxmox_virtual_environment_sdn_zone_qinq/import.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env sh +# QinQ SDN zone can be imported using its unique identifier (zone ID) +terraform import proxmox_virtual_environment_sdn_zone_qinq.example qinq1 diff --git a/examples/resources/proxmox_virtual_environment_sdn_zone_qinq/resource.tf b/examples/resources/proxmox_virtual_environment_sdn_zone_qinq/resource.tf new file mode 100644 index 00000000..3b5f1998 --- /dev/null +++ b/examples/resources/proxmox_virtual_environment_sdn_zone_qinq/resource.tf @@ -0,0 +1,14 @@ +resource "proxmox_virtual_environment_sdn_zone_qinq" "example" { + id = "qinq1" + nodes = ["pve"] + bridge = "vmbr0" + service_vlan = 100 + service_vlan_protocol = "802.1ad" + mtu = 1496 + + # Optional attributes + dns = "1.1.1.1" + dns_zone = "example.com" + ipam = "pve" + reverse_dns = "1.1.1.1" +} diff --git a/examples/resources/proxmox_virtual_environment_sdn_zone_simple/import.sh b/examples/resources/proxmox_virtual_environment_sdn_zone_simple/import.sh new file mode 100644 index 00000000..72b735c0 --- /dev/null +++ b/examples/resources/proxmox_virtual_environment_sdn_zone_simple/import.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env sh +# Simple SDN zone can be imported using its unique identifier (zone ID) +terraform import proxmox_virtual_environment_sdn_zone_simple.example simple1 diff --git a/examples/resources/proxmox_virtual_environment_sdn_zone_simple/resource.tf b/examples/resources/proxmox_virtual_environment_sdn_zone_simple/resource.tf new file mode 100644 index 00000000..ebe019e2 --- /dev/null +++ b/examples/resources/proxmox_virtual_environment_sdn_zone_simple/resource.tf @@ -0,0 +1,11 @@ +resource "proxmox_virtual_environment_sdn_zone_simple" "example" { + id = "simple1" + nodes = ["pve"] + mtu = 1500 + + # Optional attributes + dns = "1.1.1.1" + dns_zone = "example.com" + ipam = "pve" + reverse_dns = "1.1.1.1" +} diff --git a/examples/resources/proxmox_virtual_environment_sdn_zone_vlan/import.sh b/examples/resources/proxmox_virtual_environment_sdn_zone_vlan/import.sh new file mode 100644 index 00000000..72dd74cd --- /dev/null +++ b/examples/resources/proxmox_virtual_environment_sdn_zone_vlan/import.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env sh +# VLAN SDN zone can be imported using its unique identifier (zone ID) +terraform import proxmox_virtual_environment_sdn_zone_vlan.example vlan1 diff --git a/examples/resources/proxmox_virtual_environment_sdn_zone_vlan/resource.tf b/examples/resources/proxmox_virtual_environment_sdn_zone_vlan/resource.tf new file mode 100644 index 00000000..1cd733da --- /dev/null +++ b/examples/resources/proxmox_virtual_environment_sdn_zone_vlan/resource.tf @@ -0,0 +1,12 @@ +resource "proxmox_virtual_environment_sdn_zone_vlan" "example" { + id = "vlan1" + nodes = ["pve"] + bridge = "vmbr0" + mtu = 1500 + + # Optional attributes + dns = "1.1.1.1" + dns_zone = "example.com" + ipam = "pve" + reverse_dns = "1.1.1.1" +} diff --git a/examples/resources/proxmox_virtual_environment_sdn_zone_vxlan/import.sh b/examples/resources/proxmox_virtual_environment_sdn_zone_vxlan/import.sh new file mode 100644 index 00000000..fb9cad68 --- /dev/null +++ b/examples/resources/proxmox_virtual_environment_sdn_zone_vxlan/import.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env sh +# VXLAN SDN zone can be imported using its unique identifier (zone ID) +terraform import proxmox_virtual_environment_sdn_zone_vxlan.example vxlan1 diff --git a/examples/resources/proxmox_virtual_environment_sdn_zone_vxlan/resource.tf b/examples/resources/proxmox_virtual_environment_sdn_zone_vxlan/resource.tf new file mode 100644 index 00000000..833397bb --- /dev/null +++ b/examples/resources/proxmox_virtual_environment_sdn_zone_vxlan/resource.tf @@ -0,0 +1,12 @@ +resource "proxmox_virtual_environment_sdn_zone_vxlan" "example" { + id = "vxlan1" + nodes = ["pve"] + peers = ["10.0.0.1", "10.0.0.2", "10.0.0.3"] + mtu = 1450 + + # Optional attributes + dns = "1.1.1.1" + dns_zone = "example.com" + ipam = "pve" + reverse_dns = "1.1.1.1" +} diff --git a/fwprovider/cluster/sdn/zone/resource_evpn.go b/fwprovider/cluster/sdn/zone/resource_evpn.go index f753bae3..fff5f8e9 100644 --- a/fwprovider/cluster/sdn/zone/resource_evpn.go +++ b/fwprovider/cluster/sdn/zone/resource_evpn.go @@ -90,28 +90,27 @@ func (r *EVPNResource) Schema(_ context.Context, _ resource.SchemaRequest, resp "spanning across multiple clusters.", Attributes: genericAttributesWith(map[string]schema.Attribute{ "advertise_subnets": schema.BoolAttribute{ - Optional: true, Description: "Enable subnet advertisement for EVPN.", + Optional: true, }, "controller": schema.StringAttribute{ - Optional: true, Description: "EVPN controller address.", + Required: true, }, "disable_arp_nd_suppression": schema.BoolAttribute{ - Optional: true, Description: "Disable ARP/ND suppression for EVPN.", + Optional: true, }, "exit_nodes": stringset.ResourceAttribute("List of exit nodes for EVPN.", ""), "exit_nodes_local_routing": schema.BoolAttribute{ - Optional: true, Description: "Enable local routing for EVPN exit nodes.", + Optional: true, }, "primary_exit_node": schema.StringAttribute{ - Optional: true, Description: "Primary exit node for EVPN.", + Optional: true, }, "rt_import": schema.StringAttribute{ - Optional: true, Description: "Route target import for EVPN.", Validators: []validator.String{ stringvalidator.RegexMatches( @@ -119,11 +118,12 @@ func (r *EVPNResource) Schema(_ context.Context, _ resource.SchemaRequest, resp "must be in the format ':' (e.g., '65000:65000')", ), }, + Optional: true, }, "vrf_vxlan": schema.Int64Attribute{ - Optional: true, Description: "VRF VXLAN-ID used for dedicated routing interconnect between VNets. It must be different " + "than the VXLAN-ID of the VNets.", + Required: true, }, }), } diff --git a/fwprovider/cluster/sdn/zone/resource_generic.go b/fwprovider/cluster/sdn/zone/resource_generic.go index 94efe910..3ade630a 100644 --- a/fwprovider/cluster/sdn/zone/resource_generic.go +++ b/fwprovider/cluster/sdn/zone/resource_generic.go @@ -104,7 +104,7 @@ func genericAttributesWith(extraAttributes map[string]schema.Attribute) map[stri Optional: true, Description: "MTU value for the zone.", }, - "nodes": stringset.ResourceAttribute("Proxmox node names.", ""), + "nodes": stringset.ResourceAttribute("The Proxmox nodes which the zone and associated VNets should be deployed on", "", stringset.WithRequired()), "reverse_dns": schema.StringAttribute{ Optional: true, Description: "Reverse DNS API server address.", diff --git a/fwprovider/cluster/sdn/zone/resource_qinq.go b/fwprovider/cluster/sdn/zone/resource_qinq.go index 04e083d6..ca89398d 100644 --- a/fwprovider/cluster/sdn/zone/resource_qinq.go +++ b/fwprovider/cluster/sdn/zone/resource_qinq.go @@ -73,21 +73,23 @@ func (r *QinQResource) Schema(_ context.Context, _ resource.SchemaRequest, resp Attributes: genericAttributesWith(map[string]schema.Attribute{ "bridge": schema.StringAttribute{ Description: "A local, VLAN-aware bridge that is already configured on each local node", - Optional: true, + Required: true, }, "service_vlan": schema.Int64Attribute{ - Optional: true, - Description: "Service VLAN tag for QinQ.", + Description: "Service VLAN tag for QinQ.", + MarkdownDescription: "Service VLAN tag for QinQ. The tag must be between `1` and `4094`.", Validators: []validator.Int64{ int64validator.Between(int64(1), int64(4094)), }, + Required: true, }, "service_vlan_protocol": schema.StringAttribute{ - Optional: true, - Description: "Service VLAN protocol for QinQ.", + Description: "Service VLAN protocol for QinQ.", + MarkdownDescription: "Service VLAN protocol for QinQ. The protocol must be `802.1ad` or `802.1q`.", Validators: []validator.String{ stringvalidator.OneOf("802.1ad", "802.1q"), }, + Optional: true, }, }), } diff --git a/fwprovider/cluster/sdn/zone/resource_vlan.go b/fwprovider/cluster/sdn/zone/resource_vlan.go index 31c10c90..c3f61312 100644 --- a/fwprovider/cluster/sdn/zone/resource_vlan.go +++ b/fwprovider/cluster/sdn/zone/resource_vlan.go @@ -67,7 +67,7 @@ func (r *VLANResource) Schema(_ context.Context, _ resource.SchemaRequest, resp Description: "Bridge interface for VLAN.", MarkdownDescription: "The local bridge or OVS switch, already configured on _each_ node that allows " + "node-to-node connection.", - Optional: true, + Required: true, }, }), } diff --git a/fwprovider/cluster/sdn/zone/resource_vxlan.go b/fwprovider/cluster/sdn/zone/resource_vxlan.go index b0b0abdc..824d4383 100644 --- a/fwprovider/cluster/sdn/zone/resource_vxlan.go +++ b/fwprovider/cluster/sdn/zone/resource_vxlan.go @@ -69,6 +69,7 @@ func (r *VXLANResource) Schema(_ context.Context, _ resource.SchemaRequest, resp "A list of IP addresses of each node in the VXLAN zone. "+ "This can be external nodes reachable at this IP address. All nodes in the cluster need to be "+ "mentioned here", + stringset.WithRequired(), ), }), } diff --git a/fwprovider/types/stringset/attribute.go b/fwprovider/types/stringset/attribute.go index ca7f89d7..2b5a2ba6 100644 --- a/fwprovider/types/stringset/attribute.go +++ b/fwprovider/types/stringset/attribute.go @@ -16,9 +16,27 @@ import ( "github.com/hashicorp/terraform-plugin-framework/types" ) +type ResourceAttributeOption func(*schema.SetAttribute) + +func WithRequired() ResourceAttributeOption { + return func(attribute *schema.SetAttribute) { + attribute.Required = true + attribute.Optional = false + attribute.Computed = false + } +} + +func WithOptional() ResourceAttributeOption { + return func(attribute *schema.SetAttribute) { + attribute.Optional = true + attribute.Required = false + attribute.Computed = true + } +} + // ResourceAttribute returns a resource schema attribute for string set. -func ResourceAttribute(desc, markdownDesc string) schema.SetAttribute { - return schema.SetAttribute{ +func ResourceAttribute(desc, markdownDesc string, options ...ResourceAttributeOption) schema.SetAttribute { + attribute := schema.SetAttribute{ CustomType: Type{ SetType: types.SetType{ ElemType: types.StringType, @@ -30,7 +48,6 @@ func ResourceAttribute(desc, markdownDesc string) schema.SetAttribute { Computed: true, ElementType: types.StringType, Validators: []validator.Set{ - // NOTE: we allow empty list to remove all previously set values setvalidator.ValueStringsAre( stringvalidator.RegexMatches( regexp.MustCompile(`(.|\s)*\S(.|\s)*`), @@ -40,6 +57,12 @@ func ResourceAttribute(desc, markdownDesc string) schema.SetAttribute { ), }, } + + for _, option := range options { + option(&attribute) + } + + return attribute } // DataSourceAttribute returns a data source schema attribute for string set.