mirror of
https://github.com/bpg/terraform-provider-proxmox.git
synced 2025-08-26 13:25:43 +00:00
add simple zone resource
Signed-off-by: Pavel Boldyrev <627562+bpg@users.noreply.github.com>
This commit is contained in:
parent
c1016a96eb
commit
21059a6aa4
30
docs/resources/virtual_environment_sdn_zone_simple.md
Normal file
30
docs/resources/virtual_environment_sdn_zone_simple.md
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
---
|
||||||
|
layout: page
|
||||||
|
title: proxmox_virtual_environment_sdn_zone_simple
|
||||||
|
parent: Resources
|
||||||
|
subcategory: Virtual Environment
|
||||||
|
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.
|
||||||
|
---
|
||||||
|
|
||||||
|
# Resource: proxmox_virtual_environment_sdn_zone_simple
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!-- schema generated by tfplugindocs -->
|
||||||
|
## Schema
|
||||||
|
|
||||||
|
### Required
|
||||||
|
|
||||||
|
- `id` (String) The unique identifier of the SDN zone.
|
||||||
|
|
||||||
|
### Optional
|
||||||
|
|
||||||
|
- `dns` (String) DNS API server address.
|
||||||
|
- `dns_zone` (String) DNS domain name. Used to register hostnames, such as `<hostname>.<domain>`. 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.
|
93
fwprovider/cluster/sdn/zone/resource_model.go
Normal file
93
fwprovider/cluster/sdn/zone/resource_model.go
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
/*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package zone
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform-plugin-framework/diag"
|
||||||
|
"github.com/hashicorp/terraform-plugin-framework/types"
|
||||||
|
|
||||||
|
"github.com/bpg/terraform-provider-proxmox/fwprovider/types/stringset"
|
||||||
|
"github.com/bpg/terraform-provider-proxmox/proxmox/cluster/sdn/zones"
|
||||||
|
)
|
||||||
|
|
||||||
|
type baseModel struct {
|
||||||
|
ID types.String `tfsdk:"id"`
|
||||||
|
IPAM types.String `tfsdk:"ipam"`
|
||||||
|
DNS types.String `tfsdk:"dns"`
|
||||||
|
ReverseDNS types.String `tfsdk:"reverse_dns"`
|
||||||
|
DNSZone types.String `tfsdk:"dns_zone"`
|
||||||
|
Nodes stringset.Value `tfsdk:"nodes"`
|
||||||
|
MTU types.Int64 `tfsdk:"mtu"`
|
||||||
|
// // VLAN.
|
||||||
|
// Bridge types.String `tfsdk:"bridge"`
|
||||||
|
// // QinQ.
|
||||||
|
// ServiceVLAN types.Int64 `tfsdk:"service_vlan"`
|
||||||
|
// ServiceVLANProtocol types.String `tfsdk:"service_vlan_protocol"`
|
||||||
|
// // VXLAN.
|
||||||
|
// Peers stringset.Value `tfsdk:"peers"`
|
||||||
|
// // EVPN.
|
||||||
|
// Controller types.String `tfsdk:"controller"`
|
||||||
|
// ExitNodes stringset.Value `tfsdk:"exit_nodes"`
|
||||||
|
// PrimaryExitNode types.String `tfsdk:"primary_exit_node"`
|
||||||
|
// RouteTargetImport types.String `tfsdk:"rt_import"`
|
||||||
|
// VRFVXLANID types.Int64 `tfsdk:"vrf_vxlan"`
|
||||||
|
// ExitNodesLocalRouting types.Bool `tfsdk:"exit_nodes_local_routing"`
|
||||||
|
// AdvertiseSubnets types.Bool `tfsdk:"advertise_subnets"`
|
||||||
|
// DisableARPNDSuppression types.Bool `tfsdk:"disable_arp_nd_suppression"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *baseModel) importFromAPI(name string, data *zones.ZoneData, diags *diag.Diagnostics) {
|
||||||
|
m.ID = types.StringValue(name)
|
||||||
|
|
||||||
|
m.DNS = types.StringPointerValue(data.DNS)
|
||||||
|
m.DNSZone = types.StringPointerValue(data.DNSZone)
|
||||||
|
m.IPAM = types.StringPointerValue(data.IPAM)
|
||||||
|
m.MTU = types.Int64PointerValue(data.MTU)
|
||||||
|
m.Nodes = stringset.NewValueString(data.Nodes, diags, stringset.WithSeparator(","))
|
||||||
|
m.ReverseDNS = types.StringPointerValue(data.ReverseDNS)
|
||||||
|
// m.Bridge = types.StringPointerValue(data.Bridge)
|
||||||
|
// m.ServiceVLAN = types.Int64PointerValue(data.ServiceVLAN)
|
||||||
|
// m.ServiceVLANProtocol = types.StringPointerValue(data.ServiceVLANProtocol)
|
||||||
|
// m.Peers = stringset.NewValueString(data.Peers, diags, comaSeparated)
|
||||||
|
// m.Controller = types.StringPointerValue(data.Controller)
|
||||||
|
// m.ExitNodes = stringset.NewValueString(data.ExitNodes, diags, comaSeparated)
|
||||||
|
// m.PrimaryExitNode = types.StringPointerValue(data.ExitNodesPrimary)
|
||||||
|
// m.RouteTargetImport = types.StringPointerValue(data.RouteTargetImport)
|
||||||
|
// m.VRFVXLANID = types.Int64PointerValue(data.VRFVXLANID)
|
||||||
|
// m.ExitNodesLocalRouting = types.BoolPointerValue(ptrConversion.Int64ToBoolPtr(data.ExitNodesLocalRouting))
|
||||||
|
// m.AdvertiseSubnets = types.BoolPointerValue(ptrConversion.Int64ToBoolPtr(data.AdvertiseSubnets))
|
||||||
|
// m.DisableARPNDSuppression = types.BoolPointerValue(ptrConversion.Int64ToBoolPtr(data.DisableARPNDSuppression))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *baseModel) toAPIRequestBody(ctx context.Context, diags *diag.Diagnostics) *zones.ZoneRequestData {
|
||||||
|
data := &zones.ZoneRequestData{}
|
||||||
|
|
||||||
|
data.ID = m.ID.ValueString()
|
||||||
|
|
||||||
|
data.IPAM = m.IPAM.ValueStringPointer()
|
||||||
|
data.DNS = m.DNS.ValueStringPointer()
|
||||||
|
data.ReverseDNS = m.ReverseDNS.ValueStringPointer()
|
||||||
|
data.DNSZone = m.DNSZone.ValueStringPointer()
|
||||||
|
data.Nodes = m.Nodes.ValueStringPointer(ctx, diags, stringset.WithSeparator(","))
|
||||||
|
data.MTU = m.MTU.ValueInt64Pointer()
|
||||||
|
// data.Bridge = m.Bridge.ValueStringPointer()
|
||||||
|
// data.ServiceVLAN = m.ServiceVLAN.ValueInt64Pointer()
|
||||||
|
// data.ServiceVLANProtocol = m.ServiceVLANProtocol.ValueStringPointer()
|
||||||
|
// data.Peers = m.Peers.ValueStringPointer(ctx, diags, comaSeparated)
|
||||||
|
// data.Controller = m.Controller.ValueStringPointer()
|
||||||
|
// data.ExitNodes = m.ExitNodes.ValueStringPointer(ctx, diags, comaSeparated)
|
||||||
|
// data.ExitNodesPrimary = m.PrimaryExitNode.ValueStringPointer()
|
||||||
|
// data.RouteTargetImport = m.RouteTargetImport.ValueStringPointer()
|
||||||
|
// data.VRFVXLANID = m.VRFVXLANID.ValueInt64Pointer()
|
||||||
|
// data.ExitNodesLocalRouting = ptrConversion.BoolToInt64Ptr(m.ExitNodesLocalRouting.ValueBoolPointer())
|
||||||
|
// data.AdvertiseSubnets = ptrConversion.BoolToInt64Ptr(m.AdvertiseSubnets.ValueBoolPointer())
|
||||||
|
// data.DisableARPNDSuppression = ptrConversion.BoolToInt64Ptr(m.DisableARPNDSuppression.ValueBoolPointer())
|
||||||
|
|
||||||
|
return data
|
||||||
|
}
|
213
fwprovider/cluster/sdn/zone/resource_schema.go
Normal file
213
fwprovider/cluster/sdn/zone/resource_schema.go
Normal file
@ -0,0 +1,213 @@
|
|||||||
|
/*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package zone
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"maps"
|
||||||
|
"regexp"
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform-plugin-framework-validators/int64validator"
|
||||||
|
"github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
|
||||||
|
"github.com/hashicorp/terraform-plugin-framework/resource"
|
||||||
|
"github.com/hashicorp/terraform-plugin-framework/resource/schema"
|
||||||
|
"github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
|
||||||
|
"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
|
||||||
|
"github.com/hashicorp/terraform-plugin-framework/schema/validator"
|
||||||
|
|
||||||
|
"github.com/bpg/terraform-provider-proxmox/fwprovider/types/stringset"
|
||||||
|
)
|
||||||
|
|
||||||
|
func commonAttributes(base ...map[string]schema.Attribute) map[string]schema.Attribute {
|
||||||
|
if len(base) > 1 {
|
||||||
|
panic("commonAttributes expects at most one base map")
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(base) == 0 {
|
||||||
|
base = append(base, make(map[string]schema.Attribute))
|
||||||
|
}
|
||||||
|
|
||||||
|
maps.Copy(base[0], map[string]schema.Attribute{
|
||||||
|
"dns": schema.StringAttribute{
|
||||||
|
Optional: true,
|
||||||
|
Description: "DNS API server address.",
|
||||||
|
},
|
||||||
|
"dns_zone": schema.StringAttribute{
|
||||||
|
Optional: true,
|
||||||
|
Description: "DNS domain name. The DNS zone must already exist on the DNS server.",
|
||||||
|
MarkdownDescription: "DNS domain name. Used to register hostnames, such as `<hostname>.<domain>`. " +
|
||||||
|
"The DNS zone must already exist on the DNS server.",
|
||||||
|
},
|
||||||
|
"id": schema.StringAttribute{
|
||||||
|
Description: "The unique identifier of the SDN zone.",
|
||||||
|
Required: true,
|
||||||
|
PlanModifiers: []planmodifier.String{
|
||||||
|
stringplanmodifier.RequiresReplace(),
|
||||||
|
},
|
||||||
|
Validators: []validator.String{
|
||||||
|
// https://github.com/proxmox/pve-network/blob/faaf96a8378a3e41065018562c09c3de0aa434f5/src/PVE/Network/SDN/Zones/Plugin.pm#L34
|
||||||
|
stringvalidator.RegexMatches(
|
||||||
|
regexp.MustCompile(`^[A-Za-z][A-Za-z0-9]*[A-Za-z0-9]$`),
|
||||||
|
"must be a valid zone identifier",
|
||||||
|
),
|
||||||
|
stringvalidator.LengthAtMost(8),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"ipam": schema.StringAttribute{
|
||||||
|
Optional: true,
|
||||||
|
Description: "IP Address Management system.",
|
||||||
|
},
|
||||||
|
"mtu": schema.Int64Attribute{
|
||||||
|
Optional: true,
|
||||||
|
Description: "MTU value for the zone.",
|
||||||
|
},
|
||||||
|
"nodes": stringset.ResourceAttribute("Proxmox node names.", ""),
|
||||||
|
"reverse_dns": schema.StringAttribute{
|
||||||
|
Optional: true,
|
||||||
|
Description: "Reverse DNS API server address.",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
return base[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *SimpleResource) Schema(
|
||||||
|
_ context.Context,
|
||||||
|
_ resource.SchemaRequest,
|
||||||
|
resp *resource.SchemaResponse,
|
||||||
|
) {
|
||||||
|
resp.Schema = schema.Schema{
|
||||||
|
Description: "Simple Zone in Proxmox SDN.",
|
||||||
|
MarkdownDescription: "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.",
|
||||||
|
Attributes: commonAttributes(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *VLAN) Schema(
|
||||||
|
_ context.Context,
|
||||||
|
_ resource.SchemaRequest,
|
||||||
|
resp *resource.SchemaResponse,
|
||||||
|
) {
|
||||||
|
resp.Schema = schema.Schema{
|
||||||
|
Description: "VLAN Zone in Proxmox SDN.",
|
||||||
|
MarkdownDescription: "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.",
|
||||||
|
Attributes: commonAttributes(map[string]schema.Attribute{
|
||||||
|
"bridge": schema.StringAttribute{
|
||||||
|
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,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *QinQ) Schema(
|
||||||
|
_ context.Context,
|
||||||
|
_ resource.SchemaRequest,
|
||||||
|
resp *resource.SchemaResponse,
|
||||||
|
) {
|
||||||
|
resp.Schema = schema.Schema{
|
||||||
|
Description: "QinQ Zone in Proxmox SDN.",
|
||||||
|
MarkdownDescription: "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.",
|
||||||
|
Attributes: commonAttributes(map[string]schema.Attribute{
|
||||||
|
"bridge": schema.StringAttribute{
|
||||||
|
Description: "A local, VLAN-aware bridge that is already configured on each local node",
|
||||||
|
Optional: true,
|
||||||
|
},
|
||||||
|
"service_vlan": schema.Int64Attribute{
|
||||||
|
Optional: true,
|
||||||
|
Description: "Service VLAN tag for QinQ.",
|
||||||
|
Validators: []validator.Int64{
|
||||||
|
int64validator.Between(int64(1), int64(4094)),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"service_vlan_protocol": schema.StringAttribute{
|
||||||
|
Optional: true,
|
||||||
|
Description: "Service VLAN protocol for QinQ.",
|
||||||
|
Validators: []validator.String{
|
||||||
|
stringvalidator.OneOf("802.1ad", "802.1q"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *VXLAN) Schema(
|
||||||
|
_ context.Context,
|
||||||
|
_ resource.SchemaRequest,
|
||||||
|
resp *resource.SchemaResponse,
|
||||||
|
) {
|
||||||
|
resp.Schema = schema.Schema{
|
||||||
|
Description: "VXLAN Zone in Proxmox SDN.",
|
||||||
|
MarkdownDescription: "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.",
|
||||||
|
Attributes: commonAttributes(map[string]schema.Attribute{
|
||||||
|
"peers": stringset.ResourceAttribute(
|
||||||
|
"A list of IP addresses of each node in the VXLAN zone.",
|
||||||
|
"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",
|
||||||
|
),
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *EVPN) Schema(
|
||||||
|
_ context.Context,
|
||||||
|
_ resource.SchemaRequest,
|
||||||
|
resp *resource.SchemaResponse,
|
||||||
|
) {
|
||||||
|
resp.Schema = schema.Schema{
|
||||||
|
Description: "EVPN Zone in Proxmox SDN.",
|
||||||
|
MarkdownDescription: "EVPN Zone in Proxmox SDN. The EVPN zone creates a routable Layer 3 network, capable of " +
|
||||||
|
"spanning across multiple clusters.",
|
||||||
|
Attributes: commonAttributes(map[string]schema.Attribute{
|
||||||
|
"advertise_subnets": schema.BoolAttribute{
|
||||||
|
Optional: true,
|
||||||
|
Description: "Enable subnet advertisement for EVPN.",
|
||||||
|
},
|
||||||
|
"controller": schema.StringAttribute{
|
||||||
|
Optional: true,
|
||||||
|
Description: "EVPN controller address.",
|
||||||
|
},
|
||||||
|
"disable_arp_nd_suppression": schema.BoolAttribute{
|
||||||
|
Optional: true,
|
||||||
|
Description: "Disable ARP/ND suppression for EVPN.",
|
||||||
|
},
|
||||||
|
"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.",
|
||||||
|
},
|
||||||
|
"primary_exit_node": schema.StringAttribute{
|
||||||
|
Optional: true,
|
||||||
|
Description: "Primary exit node for EVPN.",
|
||||||
|
},
|
||||||
|
"rt_import": schema.StringAttribute{
|
||||||
|
Optional: true,
|
||||||
|
Description: "Route target import for EVPN.",
|
||||||
|
},
|
||||||
|
"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.",
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
}
|
185
fwprovider/cluster/sdn/zone/resource_simple.go
Normal file
185
fwprovider/cluster/sdn/zone/resource_simple.go
Normal file
@ -0,0 +1,185 @@
|
|||||||
|
/*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package zone
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform-plugin-framework/resource"
|
||||||
|
|
||||||
|
"github.com/bpg/terraform-provider-proxmox/fwprovider/config"
|
||||||
|
"github.com/bpg/terraform-provider-proxmox/proxmox/api"
|
||||||
|
"github.com/bpg/terraform-provider-proxmox/proxmox/cluster/sdn/zones"
|
||||||
|
"github.com/bpg/terraform-provider-proxmox/proxmox/helpers/ptr"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
_ resource.ResourceWithConfigure = &SimpleResource{}
|
||||||
|
_ resource.ResourceWithImportState = &SimpleResource{}
|
||||||
|
)
|
||||||
|
|
||||||
|
type SimpleResource struct {
|
||||||
|
client *zones.Client
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewSimpleResource creates a new instance of the Simple resource.
|
||||||
|
func NewSimpleResource() resource.Resource {
|
||||||
|
return &SimpleResource{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Metadata defines the name of the resource.
|
||||||
|
func (r *SimpleResource) Metadata(
|
||||||
|
_ context.Context,
|
||||||
|
req resource.MetadataRequest,
|
||||||
|
resp *resource.MetadataResponse,
|
||||||
|
) {
|
||||||
|
resp.TypeName = req.ProviderTypeName + "_sdn_zone_simple"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *SimpleResource) Configure(
|
||||||
|
_ context.Context,
|
||||||
|
req resource.ConfigureRequest,
|
||||||
|
resp *resource.ConfigureResponse,
|
||||||
|
) {
|
||||||
|
if req.ProviderData == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
cfg, ok := req.ProviderData.(config.Resource)
|
||||||
|
if !ok {
|
||||||
|
resp.Diagnostics.AddError(
|
||||||
|
"Unexpected Resource Configure Type",
|
||||||
|
fmt.Sprintf(
|
||||||
|
"Expected config.Resource, got: %T",
|
||||||
|
req.ProviderData,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
r.client = cfg.Client.Cluster().SDNZones()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *SimpleResource) Create(
|
||||||
|
ctx context.Context,
|
||||||
|
req resource.CreateRequest,
|
||||||
|
resp *resource.CreateResponse,
|
||||||
|
) {
|
||||||
|
var plan baseModel
|
||||||
|
|
||||||
|
resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
|
||||||
|
|
||||||
|
if resp.Diagnostics.HasError() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
reqData := plan.toAPIRequestBody(ctx, &resp.Diagnostics)
|
||||||
|
reqData.Type = ptr.Ptr(zones.TypeSimple)
|
||||||
|
|
||||||
|
if err := r.client.CreateZone(ctx, reqData); err != nil {
|
||||||
|
resp.Diagnostics.AddError(
|
||||||
|
"Unable to Create SDN Zone",
|
||||||
|
err.Error(),
|
||||||
|
)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *SimpleResource) Read(
|
||||||
|
ctx context.Context,
|
||||||
|
req resource.ReadRequest,
|
||||||
|
resp *resource.ReadResponse,
|
||||||
|
) {
|
||||||
|
var state baseModel
|
||||||
|
|
||||||
|
resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
|
||||||
|
|
||||||
|
if resp.Diagnostics.HasError() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
zone, err := r.client.GetZone(ctx, state.ID.ValueString())
|
||||||
|
if err != nil {
|
||||||
|
if errors.Is(err, api.ErrResourceDoesNotExist) {
|
||||||
|
resp.State.RemoveResource(ctx)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
resp.Diagnostics.AddError(
|
||||||
|
"Unable to Read SDN Zone",
|
||||||
|
err.Error(),
|
||||||
|
)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
readModel := &baseModel{}
|
||||||
|
readModel.importFromAPI(zone.ID, zone, &resp.Diagnostics)
|
||||||
|
resp.Diagnostics.Append(resp.State.Set(ctx, readModel)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *SimpleResource) Update(
|
||||||
|
ctx context.Context,
|
||||||
|
req resource.UpdateRequest,
|
||||||
|
resp *resource.UpdateResponse,
|
||||||
|
) {
|
||||||
|
var plan baseModel
|
||||||
|
|
||||||
|
resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
|
||||||
|
|
||||||
|
if resp.Diagnostics.HasError() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
reqData := plan.toAPIRequestBody(ctx, &resp.Diagnostics)
|
||||||
|
|
||||||
|
if err := r.client.UpdateZone(ctx, reqData); err != nil {
|
||||||
|
resp.Diagnostics.AddError(
|
||||||
|
"Unable to Update SDN Zone",
|
||||||
|
err.Error(),
|
||||||
|
)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *SimpleResource) Delete(
|
||||||
|
ctx context.Context,
|
||||||
|
req resource.DeleteRequest,
|
||||||
|
resp *resource.DeleteResponse,
|
||||||
|
) {
|
||||||
|
var state baseModel
|
||||||
|
|
||||||
|
resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
|
||||||
|
|
||||||
|
if resp.Diagnostics.HasError() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := r.client.DeleteZone(ctx, state.ID.ValueString()); err != nil &&
|
||||||
|
!errors.Is(err, api.ErrResourceDoesNotExist) {
|
||||||
|
resp.Diagnostics.AddError(
|
||||||
|
"Unable to Delete SDN Zone",
|
||||||
|
err.Error(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *SimpleResource) ImportState(
|
||||||
|
ctx context.Context,
|
||||||
|
req resource.ImportStateRequest,
|
||||||
|
resp *resource.ImportStateResponse,
|
||||||
|
) {
|
||||||
|
}
|
53
fwprovider/cluster/sdn/zone/resource_simple_test.go
Normal file
53
fwprovider/cluster/sdn/zone/resource_simple_test.go
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
//go:build acceptance || all
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package zone_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
|
||||||
|
|
||||||
|
"github.com/bpg/terraform-provider-proxmox/fwprovider/test"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestAccResourceSDNZoneSimple(t *testing.T) {
|
||||||
|
te := test.InitEnvironment(t)
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
steps []resource.TestStep
|
||||||
|
}{
|
||||||
|
{"create and update zones", []resource.TestStep{{
|
||||||
|
Config: te.RenderConfig(`
|
||||||
|
resource "proxmox_virtual_environment_sdn_zone_simple" "zone_simple" {
|
||||||
|
id = "zoneS"
|
||||||
|
nodes = ["pve"]
|
||||||
|
mtu = 1496
|
||||||
|
}
|
||||||
|
`),
|
||||||
|
}, {
|
||||||
|
Config: te.RenderConfig(`
|
||||||
|
resource "proxmox_virtual_environment_sdn_zone_simple" "zone_simple" {
|
||||||
|
id = "zoneS"
|
||||||
|
nodes = ["pve"]
|
||||||
|
mtu = 1495
|
||||||
|
}
|
||||||
|
`),
|
||||||
|
}}},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
resource.ParallelTest(t, resource.TestCase{
|
||||||
|
ProtoV6ProviderFactories: te.AccProviders,
|
||||||
|
Steps: tt.steps,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
@ -30,6 +30,7 @@ import (
|
|||||||
"github.com/bpg/terraform-provider-proxmox/fwprovider/cluster/hardwaremapping"
|
"github.com/bpg/terraform-provider-proxmox/fwprovider/cluster/hardwaremapping"
|
||||||
"github.com/bpg/terraform-provider-proxmox/fwprovider/cluster/metrics"
|
"github.com/bpg/terraform-provider-proxmox/fwprovider/cluster/metrics"
|
||||||
"github.com/bpg/terraform-provider-proxmox/fwprovider/cluster/options"
|
"github.com/bpg/terraform-provider-proxmox/fwprovider/cluster/options"
|
||||||
|
sdnzone "github.com/bpg/terraform-provider-proxmox/fwprovider/cluster/sdn/zone"
|
||||||
"github.com/bpg/terraform-provider-proxmox/fwprovider/config"
|
"github.com/bpg/terraform-provider-proxmox/fwprovider/config"
|
||||||
"github.com/bpg/terraform-provider-proxmox/fwprovider/nodes"
|
"github.com/bpg/terraform-provider-proxmox/fwprovider/nodes"
|
||||||
"github.com/bpg/terraform-provider-proxmox/fwprovider/nodes/apt"
|
"github.com/bpg/terraform-provider-proxmox/fwprovider/nodes/apt"
|
||||||
@ -527,6 +528,11 @@ func (p *proxmoxProvider) Resources(_ context.Context) []func() resource.Resourc
|
|||||||
nodes.NewDownloadFileResource,
|
nodes.NewDownloadFileResource,
|
||||||
options.NewClusterOptionsResource,
|
options.NewClusterOptionsResource,
|
||||||
vm.NewResource,
|
vm.NewResource,
|
||||||
|
sdnzone.NewSimpleResource,
|
||||||
|
//
|
||||||
|
// sdn.NewSDNZoneResource,
|
||||||
|
// sdn.NewSDNVnetResource,
|
||||||
|
//sdn.NewSDNSubnetResource,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -550,6 +556,9 @@ func (p *proxmoxProvider) DataSources(_ context.Context) []func() datasource.Dat
|
|||||||
hardwaremapping.NewUSBDataSource,
|
hardwaremapping.NewUSBDataSource,
|
||||||
metrics.NewMetricsServerDatasource,
|
metrics.NewMetricsServerDatasource,
|
||||||
vm.NewDataSource,
|
vm.NewDataSource,
|
||||||
|
// sdn.NewSDNZoneDataSource,
|
||||||
|
// sdn.NewSDNVnetDataSource,
|
||||||
|
// sdn.NewSDNSubnetDataSource,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
1
main.go
1
main.go
@ -65,6 +65,7 @@ import (
|
|||||||
//go:generate cp ./build/docs-gen/resources/virtual_environment_haresource.md ./docs/resources/
|
//go:generate cp ./build/docs-gen/resources/virtual_environment_haresource.md ./docs/resources/
|
||||||
//go:generate cp ./build/docs-gen/resources/virtual_environment_network_linux_bridge.md ./docs/resources/
|
//go:generate cp ./build/docs-gen/resources/virtual_environment_network_linux_bridge.md ./docs/resources/
|
||||||
//go:generate cp ./build/docs-gen/resources/virtual_environment_network_linux_vlan.md ./docs/resources/
|
//go:generate cp ./build/docs-gen/resources/virtual_environment_network_linux_vlan.md ./docs/resources/
|
||||||
|
//go:generate cp ./build/docs-gen/resources/virtual_environment_sdn_zone_simple.md ./docs/resources/
|
||||||
//go:generate cp ./build/docs-gen/resources/virtual_environment_user_token.md ./docs/resources/
|
//go:generate cp ./build/docs-gen/resources/virtual_environment_user_token.md ./docs/resources/
|
||||||
//go:generate cp ./build/docs-gen/resources/virtual_environment_vm2.md ./docs/resources/
|
//go:generate cp ./build/docs-gen/resources/virtual_environment_vm2.md ./docs/resources/
|
||||||
//go:generate cp ./build/docs-gen/resources/virtual_environment_metrics_server.md ./docs/resources/
|
//go:generate cp ./build/docs-gen/resources/virtual_environment_metrics_server.md ./docs/resources/
|
||||||
|
@ -15,6 +15,7 @@ import (
|
|||||||
"github.com/bpg/terraform-provider-proxmox/proxmox/cluster/ha"
|
"github.com/bpg/terraform-provider-proxmox/proxmox/cluster/ha"
|
||||||
"github.com/bpg/terraform-provider-proxmox/proxmox/cluster/mapping"
|
"github.com/bpg/terraform-provider-proxmox/proxmox/cluster/mapping"
|
||||||
"github.com/bpg/terraform-provider-proxmox/proxmox/cluster/metrics"
|
"github.com/bpg/terraform-provider-proxmox/proxmox/cluster/metrics"
|
||||||
|
"github.com/bpg/terraform-provider-proxmox/proxmox/cluster/sdn/zones"
|
||||||
"github.com/bpg/terraform-provider-proxmox/proxmox/firewall"
|
"github.com/bpg/terraform-provider-proxmox/proxmox/firewall"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -54,3 +55,18 @@ func (c *Client) ACME() *acme.Client {
|
|||||||
func (c *Client) Metrics() *metrics.Client {
|
func (c *Client) Metrics() *metrics.Client {
|
||||||
return &metrics.Client{Client: c}
|
return &metrics.Client{Client: c}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SDNZones returns a client for managing the cluster's SDN zones.
|
||||||
|
func (c *Client) SDNZones() *zones.Client {
|
||||||
|
return &zones.Client{Client: c}
|
||||||
|
}
|
||||||
|
|
||||||
|
// // SDNVnets returns a client for managing the cluster's SDN Vnets.
|
||||||
|
// func (c *Client) SDNVnets() *vnets.Client {
|
||||||
|
// return &vnets.Client{Client: c}
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // SDNSubnets returns a client for managing the cluster's SDN Subnets.
|
||||||
|
// func (c *Client) SDNSubnets() *subnets.Client {
|
||||||
|
// return &subnets.Client{Client: c}
|
||||||
|
// }
|
||||||
|
@ -6,8 +6,16 @@
|
|||||||
|
|
||||||
package zones
|
package zones
|
||||||
|
|
||||||
|
const (
|
||||||
|
TypeSimple = "simple"
|
||||||
|
TypeVLAN = "vlan"
|
||||||
|
TypeQinQ = "qinq"
|
||||||
|
TypeVXLAN = "vxlan"
|
||||||
|
TypeEVPN = "evpn"
|
||||||
|
)
|
||||||
|
|
||||||
type ZoneData struct {
|
type ZoneData struct {
|
||||||
ID string `json:"zone,omitempty" url:"zone,omitempty"`
|
ID string `json:"zone" url:"zone"`
|
||||||
Type *string `json:"type,omitempty" url:"type,omitempty"`
|
Type *string `json:"type,omitempty" url:"type,omitempty"`
|
||||||
IPAM *string `json:"ipam,omitempty" url:"ipam,omitempty"`
|
IPAM *string `json:"ipam,omitempty" url:"ipam,omitempty"`
|
||||||
DNS *string `json:"dns,omitempty" url:"dns,omitempty"`
|
DNS *string `json:"dns,omitempty" url:"dns,omitempty"`
|
||||||
@ -40,6 +48,7 @@ type ZoneData struct {
|
|||||||
// ZoneRequestData wraps a ZoneData struct with optional delete instructions.
|
// ZoneRequestData wraps a ZoneData struct with optional delete instructions.
|
||||||
type ZoneRequestData struct {
|
type ZoneRequestData struct {
|
||||||
ZoneData
|
ZoneData
|
||||||
|
|
||||||
Delete []string `url:"delete,omitempty"`
|
Delete []string `url:"delete,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
20
testacc
20
testacc
@ -6,5 +6,21 @@
|
|||||||
# file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
# file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
#
|
#
|
||||||
|
|
||||||
# shellcheck disable=SC2046
|
BASE_PKG="github.com/bpg/terraform-provider-proxmox"
|
||||||
TF_ACC=1 env $(xargs < testacc.env) go test -count 1 --tags=acceptance -timeout 360s -run "$1" github.com/bpg/terraform-provider-proxmox/fwprovider/... $2
|
|
||||||
|
find_test_package() {
|
||||||
|
test_name="$1"
|
||||||
|
[ -z "$test_name" ] && echo "${BASE_PKG}/fwprovider/..." && return
|
||||||
|
|
||||||
|
test_file=$(find . -name "*.go" -type f -exec grep -l "func ${test_name}(" {} \; | head -1)
|
||||||
|
[ -z "$test_file" ] && echo "${BASE_PKG}/fwprovider/..." && return
|
||||||
|
|
||||||
|
package_dir=$(dirname "$test_file")
|
||||||
|
package_path=$(echo "$package_dir" | sed 's|^\./||')
|
||||||
|
echo "${BASE_PKG}/${package_path}"
|
||||||
|
}
|
||||||
|
|
||||||
|
PACKAGE_PATH=$(find_test_package "$1")
|
||||||
|
|
||||||
|
# shellcheck disable=SC2046,SC2086
|
||||||
|
TF_ACC=1 env $(xargs < testacc.env) go test -count 1 --tags=acceptance -timeout 360s -run "$1" "$PACKAGE_PATH" $2
|
||||||
|
Loading…
Reference in New Issue
Block a user