Skip to content

Commit 12cc329

Browse files
committed
cleanup
Signed-off-by: Pavel Boldyrev <[email protected]>
1 parent bf19edb commit 12cc329

18 files changed

+853
-1386
lines changed

.golangci.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ linters:
4444
gosec:
4545
excludes:
4646
- G115
47+
lll:
48+
line-length: 150
4749
revive:
4850
rules:
4951
- name: "package-comments"

fwprovider/cluster/sdn/zone/resource_evpn.go

Lines changed: 113 additions & 146 deletions
Original file line numberDiff line numberDiff line change
@@ -8,184 +8,151 @@ package zone
88

99
import (
1010
"context"
11-
"errors"
12-
"fmt"
11+
"regexp"
1312

13+
"github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
14+
"github.com/hashicorp/terraform-plugin-framework/diag"
1415
"github.com/hashicorp/terraform-plugin-framework/resource"
16+
"github.com/hashicorp/terraform-plugin-framework/resource/schema"
17+
"github.com/hashicorp/terraform-plugin-framework/schema/validator"
18+
"github.com/hashicorp/terraform-plugin-framework/types"
1519

16-
"github.com/bpg/terraform-provider-proxmox/fwprovider/config"
17-
"github.com/bpg/terraform-provider-proxmox/proxmox/api"
20+
"github.com/bpg/terraform-provider-proxmox/fwprovider/types/stringset"
1821
"github.com/bpg/terraform-provider-proxmox/proxmox/cluster/sdn/zones"
19-
"github.com/bpg/terraform-provider-proxmox/proxmox/helpers/ptr"
22+
23+
proxmoxtypes "github.com/bpg/terraform-provider-proxmox/proxmox/types"
2024
)
2125

2226
var (
2327
_ resource.ResourceWithConfigure = &EVPNResource{}
2428
_ resource.ResourceWithImportState = &EVPNResource{}
2529
)
2630

27-
type EVPNResource struct {
28-
client *zones.Client
31+
type evpnModel struct {
32+
genericModel
33+
34+
AdvertiseSubnets types.Bool `tfsdk:"advertise_subnets"`
35+
Controller types.String `tfsdk:"controller"`
36+
DisableARPNDSuppression types.Bool `tfsdk:"disable_arp_nd_suppression"`
37+
ExitNodes stringset.Value `tfsdk:"exit_nodes"`
38+
ExitNodesLocalRouting types.Bool `tfsdk:"exit_nodes_local_routing"`
39+
PrimaryExitNode types.String `tfsdk:"primary_exit_node"`
40+
RouteTargetImport types.String `tfsdk:"rt_import"`
41+
VRFVXLANID types.Int64 `tfsdk:"vrf_vxlan"`
2942
}
3043

31-
func NewEVPNResource() resource.Resource {
32-
return &EVPNResource{}
44+
func (m *evpnModel) importFromAPI(name string, data *zones.ZoneData, diags *diag.Diagnostics) {
45+
m.genericModel.importFromAPI(name, data, diags)
46+
47+
m.AdvertiseSubnets = types.BoolPointerValue(data.AdvertiseSubnets.PointerBool())
48+
m.Controller = types.StringPointerValue(data.Controller)
49+
m.DisableARPNDSuppression = types.BoolPointerValue(data.DisableARPNDSuppression.PointerBool())
50+
m.ExitNodes = stringset.NewValueString(data.ExitNodes, diags, stringset.WithSeparator(","))
51+
m.ExitNodesLocalRouting = types.BoolPointerValue(data.ExitNodesLocalRouting.PointerBool())
52+
m.PrimaryExitNode = types.StringPointerValue(data.ExitNodesPrimary)
53+
m.RouteTargetImport = types.StringPointerValue(data.RouteTargetImport)
54+
m.VRFVXLANID = types.Int64PointerValue(data.VRFVXLANID)
3355
}
3456

35-
func (r *EVPNResource) Metadata(
36-
_ context.Context,
37-
req resource.MetadataRequest,
38-
resp *resource.MetadataResponse,
39-
) {
40-
resp.TypeName = req.ProviderTypeName + "_sdn_zone_evpn"
41-
}
57+
func (m *evpnModel) toAPIRequestBody(ctx context.Context, diags *diag.Diagnostics) *zones.ZoneRequestData {
58+
data := m.genericModel.toAPIRequestBody(ctx, diags)
4259

43-
func (r *EVPNResource) Configure(
44-
_ context.Context,
45-
req resource.ConfigureRequest,
46-
resp *resource.ConfigureResponse,
47-
) {
48-
if req.ProviderData == nil {
49-
return
50-
}
60+
data.AdvertiseSubnets = proxmoxtypes.CustomBoolPtr(m.AdvertiseSubnets.ValueBoolPointer())
61+
data.Controller = m.Controller.ValueStringPointer()
62+
data.DisableARPNDSuppression = proxmoxtypes.CustomBoolPtr(m.DisableARPNDSuppression.ValueBoolPointer())
63+
data.ExitNodes = m.ExitNodes.ValueStringPointer(ctx, diags, stringset.WithSeparator(","))
64+
data.ExitNodesLocalRouting = proxmoxtypes.CustomBoolPtr(m.ExitNodesLocalRouting.ValueBoolPointer())
65+
data.ExitNodesPrimary = m.PrimaryExitNode.ValueStringPointer()
66+
data.RouteTargetImport = m.RouteTargetImport.ValueStringPointer()
67+
data.VRFVXLANID = m.VRFVXLANID.ValueInt64Pointer()
5168

52-
cfg, ok := req.ProviderData.(config.Resource)
53-
if !ok {
54-
resp.Diagnostics.AddError(
55-
"Unexpected Resource Configure Type",
56-
fmt.Sprintf(
57-
"Expected config.Resource, got: %T",
58-
req.ProviderData,
59-
),
60-
)
61-
return
62-
}
63-
64-
r.client = cfg.Client.Cluster().SDNZones()
69+
return data
6570
}
6671

67-
func (r *EVPNResource) Create(
68-
ctx context.Context,
69-
req resource.CreateRequest,
70-
resp *resource.CreateResponse,
71-
) {
72-
var plan evpnModel
73-
74-
resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
75-
76-
if resp.Diagnostics.HasError() {
77-
return
78-
}
79-
80-
reqData := plan.toAPIRequestBody(ctx, &resp.Diagnostics)
81-
reqData.Type = ptr.Ptr(zones.TypeEVPN)
82-
83-
if err := r.client.CreateZone(ctx, reqData); err != nil {
84-
resp.Diagnostics.AddError(
85-
"Unable to Create SDN EVPN Zone",
86-
err.Error(),
87-
)
88-
return
89-
}
90-
91-
resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
72+
type EVPNResource struct {
73+
generic *genericZoneResource
9274
}
9375

94-
func (r *EVPNResource) Read(
95-
ctx context.Context,
96-
req resource.ReadRequest,
97-
resp *resource.ReadResponse,
98-
) {
99-
var state evpnModel
100-
101-
resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
102-
103-
if resp.Diagnostics.HasError() {
104-
return
105-
}
106-
107-
zone, err := r.client.GetZone(ctx, state.ID.ValueString())
108-
if err != nil {
109-
if errors.Is(err, api.ErrResourceDoesNotExist) {
110-
resp.State.RemoveResource(ctx)
111-
return
112-
}
113-
114-
resp.Diagnostics.AddError(
115-
"Unable to Read SDN EVPN Zone",
116-
err.Error(),
117-
)
118-
return
76+
func NewEVPNResource() resource.Resource {
77+
return &EVPNResource{
78+
generic: newGenericZoneResource(zoneResourceConfig{
79+
typeNameSuffix: "_sdn_zone_evpn",
80+
zoneType: zones.TypeEVPN,
81+
modelFunc: func() zoneModel { return &evpnModel{} },
82+
}).(*genericZoneResource),
11983
}
120-
121-
readModel := &evpnModel{}
122-
readModel.importFromAPI(zone.ID, zone, &resp.Diagnostics)
123-
resp.Diagnostics.Append(resp.State.Set(ctx, readModel)...)
12484
}
12585

126-
func (r *EVPNResource) Update(
127-
ctx context.Context,
128-
req resource.UpdateRequest,
129-
resp *resource.UpdateResponse,
130-
) {
131-
var plan evpnModel
132-
133-
resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
134-
135-
if resp.Diagnostics.HasError() {
136-
return
86+
func (r *EVPNResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) {
87+
resp.Schema = schema.Schema{
88+
Description: "EVPN Zone in Proxmox SDN.",
89+
MarkdownDescription: "EVPN Zone in Proxmox SDN. The EVPN zone creates a routable Layer 3 network, capable of " +
90+
"spanning across multiple clusters.",
91+
Attributes: genericAttributesWith(map[string]schema.Attribute{
92+
"advertise_subnets": schema.BoolAttribute{
93+
Optional: true,
94+
Description: "Enable subnet advertisement for EVPN.",
95+
},
96+
"controller": schema.StringAttribute{
97+
Optional: true,
98+
Description: "EVPN controller address.",
99+
},
100+
"disable_arp_nd_suppression": schema.BoolAttribute{
101+
Optional: true,
102+
Description: "Disable ARP/ND suppression for EVPN.",
103+
},
104+
"exit_nodes": stringset.ResourceAttribute("List of exit nodes for EVPN.", ""),
105+
"exit_nodes_local_routing": schema.BoolAttribute{
106+
Optional: true,
107+
Description: "Enable local routing for EVPN exit nodes.",
108+
},
109+
"primary_exit_node": schema.StringAttribute{
110+
Optional: true,
111+
Description: "Primary exit node for EVPN.",
112+
},
113+
"rt_import": schema.StringAttribute{
114+
Optional: true,
115+
Description: "Route target import for EVPN.",
116+
Validators: []validator.String{
117+
stringvalidator.RegexMatches(
118+
regexp.MustCompile(`^(\d+):(\d+)$`),
119+
"must be in the format '<ASN>:<number>' (e.g., '65000:65000')",
120+
),
121+
},
122+
},
123+
"vrf_vxlan": schema.Int64Attribute{
124+
Optional: true,
125+
Description: "VRF VXLAN-ID used for dedicated routing interconnect between VNets. It must be different " +
126+
"than the VXLAN-ID of the VNets.",
127+
},
128+
}),
137129
}
130+
}
138131

139-
reqData := plan.toAPIRequestBody(ctx, &resp.Diagnostics)
140-
141-
if err := r.client.UpdateZone(ctx, reqData); err != nil {
142-
resp.Diagnostics.AddError(
143-
"Unable to Update SDN EVPN Zone",
144-
err.Error(),
145-
)
146-
return
147-
}
132+
func (r *EVPNResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
133+
r.generic.Metadata(ctx, req, resp)
134+
}
148135

149-
resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
136+
func (r *EVPNResource) Configure(ctx context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
137+
r.generic.Configure(ctx, req, resp)
150138
}
151139

152-
func (r *EVPNResource) Delete(
153-
ctx context.Context,
154-
req resource.DeleteRequest,
155-
resp *resource.DeleteResponse,
156-
) {
157-
var state evpnModel
140+
func (r *EVPNResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
141+
r.generic.Create(ctx, req, resp)
142+
}
158143

159-
resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
144+
func (r *EVPNResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
145+
r.generic.Read(ctx, req, resp)
146+
}
160147

161-
if resp.Diagnostics.HasError() {
162-
return
163-
}
148+
func (r *EVPNResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
149+
r.generic.Update(ctx, req, resp)
150+
}
164151

165-
if err := r.client.DeleteZone(ctx, state.ID.ValueString()); err != nil &&
166-
!errors.Is(err, api.ErrResourceDoesNotExist) {
167-
resp.Diagnostics.AddError(
168-
"Unable to Delete SDN EVPN Zone",
169-
err.Error(),
170-
)
171-
}
152+
func (r *EVPNResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
153+
r.generic.Delete(ctx, req, resp)
172154
}
173155

174-
func (r *EVPNResource) ImportState(
175-
ctx context.Context,
176-
req resource.ImportStateRequest,
177-
resp *resource.ImportStateResponse,
178-
) {
179-
zone, err := r.client.GetZone(ctx, req.ID)
180-
if err != nil {
181-
if errors.Is(err, api.ErrResourceDoesNotExist) {
182-
resp.Diagnostics.AddError(fmt.Sprintf("Zone %s does not exist", req.ID), err.Error())
183-
return
184-
}
185-
resp.Diagnostics.AddError(fmt.Sprintf("Unable to Import SDN EVPN Zone %s", req.ID), err.Error())
186-
return
187-
}
188-
readModel := &evpnModel{}
189-
readModel.importFromAPI(zone.ID, zone, &resp.Diagnostics)
190-
resp.Diagnostics.Append(resp.State.Set(ctx, readModel)...)
156+
func (r *EVPNResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
157+
r.generic.ImportState(ctx, req, resp)
191158
}

0 commit comments

Comments
 (0)