refactor: move BaseSettingResource to reusable in broader scope GenericResource (#51)

This commit is contained in:
Mateusz Filipowicz
2025-03-14 00:34:29 +01:00
committed by GitHub
parent 9f2573d72c
commit 5d1643ed80
17 changed files with 304 additions and 238 deletions

View File

@@ -10,6 +10,18 @@ import (
"github.com/hashicorp/terraform-plugin-framework/types"
)
type SiteAware interface {
GetSite() string
SetSite(string)
GetRawSite() types.String
}
type Identifiable interface {
GetID() string
SetID(string)
GetRawID() types.String
}
type Resource interface {
SetClient(client *Client)
SetVersionValidator(validator ControllerVersionValidator)
@@ -17,14 +29,10 @@ type Resource interface {
// ResourceModel defines the interface that all setting models must implement
type ResourceModel interface {
GetSite() string
GetRawSite() types.String
SetSite(string)
GetID() string
GetRawID() types.String
SetID(string)
AsUnifiModel(context.Context) (interface{}, diag.Diagnostics)
Identifiable
SiteAware
Merge(context.Context, interface{}) diag.Diagnostics
AsUnifiModel(context.Context) (interface{}, diag.Diagnostics)
}
type Model struct {

View File

@@ -2,38 +2,16 @@ package base
import (
"crypto/tls"
"errors"
"fmt"
"github.com/filipowm/go-unifi/unifi"
"github.com/hashicorp/go-version"
"github.com/hashicorp/terraform-plugin-framework/diag"
"log"
"net"
"net/http"
"strings"
"time"
)
func IsServerErrorContains(err error, messageContains string) bool {
if err == nil {
return false
}
var se *unifi.ServerError
if errors.As(err, &se) {
if strings.Contains(se.Message, messageContains) {
return true
}
// check details
if se.Details != nil {
for _, m := range se.Details {
if strings.Contains(m.Message, messageContains) {
return true
}
}
}
}
return false
}
type ClientConfig struct {
Username string
Password string
@@ -80,7 +58,7 @@ type Client struct {
Version *version.Version
}
func (c *Client) ResolveSite(res ResourceModel) string {
func (c *Client) ResolveSite(res SiteAware) string {
if res == nil || IsEmptyString(res.GetRawSite()) {
return c.Site
}
@@ -104,3 +82,14 @@ func CreateHttpTransport(insecure bool) http.RoundTripper {
},
}
}
func checkClientConfigured(client *Client) diag.Diagnostics {
diags := diag.Diagnostics{}
if client == nil {
diags.AddError(
"Client Not Configured",
"Expected configured client. Please report this issue to the provider developers.",
)
}
return diags
}

View File

@@ -1,8 +1,11 @@
package base
import (
"errors"
"github.com/filipowm/go-unifi/unifi"
"github.com/hashicorp/terraform-plugin-framework/diag"
"reflect"
"strings"
)
func ErrorInvalidModelMergeTarget(expectedType, actualType interface{}) diag.Diagnostic {
@@ -10,3 +13,24 @@ func ErrorInvalidModelMergeTarget(expectedType, actualType interface{}) diag.Dia
a := reflect.TypeOf(&actualType).Elem().String()
return diag.NewErrorDiagnostic("Invalid model merge target", "Expected target type to be the same a receiver: "+e+". Was : "+a)
}
func IsServerErrorContains(err error, messageContains string) bool {
if err == nil {
return false
}
var se *unifi.ServerError
if errors.As(err, &se) {
if strings.Contains(se.Message, messageContains) {
return true
}
// check details
if se.Details != nil {
for _, m := range se.Details {
if strings.Contains(m.Message, messageContains) {
return true
}
}
}
}
return false
}

View File

@@ -0,0 +1,215 @@
package base
import (
"context"
"errors"
"fmt"
"github.com/filipowm/go-unifi/unifi"
"github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/hashicorp/terraform-plugin-framework/resource"
)
type ResourceFunctions struct {
Read func(ctx context.Context, client *Client, site string, id string) (interface{}, error)
Create func(ctx context.Context, client *Client, site string, body interface{}) (interface{}, error)
Update func(ctx context.Context, client *Client, site string, body interface{}) (interface{}, error)
Delete func(ctx context.Context, client *Client, site string, id string) error
}
// GenericResource provides common functionality for all resources
type GenericResource[T ResourceModel] struct {
ControllerVersionValidator
client *Client
typeName string
modelFactory func() T
Handlers ResourceFunctions
}
// NewGenericResource creates a new base resource
func NewGenericResource[T ResourceModel](
typeName string,
modelFactory func() T,
handlers ResourceFunctions,
) *GenericResource[T] {
return &GenericResource[T]{
typeName: typeName,
modelFactory: modelFactory,
Handlers: handlers,
}
}
// GetClient returns the UniFi client
func (b *GenericResource[T]) GetClient() *Client {
return b.client
}
// SetClient sets the UniFi client
func (b *GenericResource[T]) SetClient(client *Client) {
b.client = client
}
func (b *GenericResource[T]) SetVersionValidator(validator ControllerVersionValidator) {
b.ControllerVersionValidator = validator
}
func (b *GenericResource[T]) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
ConfigureResource(b, req, resp)
}
func (b *GenericResource[T]) Metadata(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) {
resp.TypeName = b.typeName
}
func (b *GenericResource[T]) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
resp.Diagnostics.Append(checkClientConfigured(b.client)...)
if resp.Diagnostics.HasError() {
return
}
id, site := ImportIDWithSite(req, resp)
if resp.Diagnostics.HasError() {
return
}
state := b.modelFactory()
state.SetID(id)
state.SetSite(site)
b.read(ctx, site, state, &resp.Diagnostics)
if resp.Diagnostics.HasError() {
return
}
resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
}
func (b *GenericResource[T]) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
if b.Handlers.Create == nil {
// Create is not supported
return
}
resp.Diagnostics.Append(checkClientConfigured(b.client)...)
if resp.Diagnostics.HasError() {
return
}
var plan T
resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
if resp.Diagnostics.HasError() {
return
}
site := b.client.ResolveSite(plan)
body, diags := plan.AsUnifiModel(ctx)
if diags.HasError() {
resp.Diagnostics.Append(diags...)
return
}
res, err := b.Handlers.Create(ctx, b.client, site, body)
if err != nil {
resp.Diagnostics.AddError("Error creating resource", err.Error())
return
}
if res == nil {
resp.Diagnostics.AddError("Error creating resource", fmt.Sprintf("No %[1]s resource returned from the UniFi controller. %[1]s might not be supported on this controller", b.typeName))
return
}
plan.Merge(ctx, res)
plan.SetSite(site)
resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
}
func (b *GenericResource[T]) read(ctx context.Context, site string, state T, diag *diag.Diagnostics) {
res, err := b.Handlers.Read(ctx, b.client, site, state.GetID())
if err != nil {
if errors.Is(err, unifi.ErrNotFound) {
diag.AddError("Resource not found", "The resource was not found in the UniFi controller")
} else {
diag.AddError("Error reading resource", err.Error())
}
return
}
if res != nil {
state.Merge(ctx, res)
}
}
func (b *GenericResource[T]) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
if b.Handlers.Read == nil {
resp.Diagnostics.AddError("Read Not Supported", "Read operation is not supported for this resource. Please report this issue to the provider developers cause this is unexpected issue.")
return
}
resp.Diagnostics.Append(checkClientConfigured(b.client)...)
if resp.Diagnostics.HasError() {
return
}
var state T
resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
if resp.Diagnostics.HasError() {
return
}
site := b.client.ResolveSite(state)
b.read(ctx, site, state, &resp.Diagnostics)
if resp.Diagnostics.HasError() {
return
}
state.SetSite(site)
resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
}
func (b *GenericResource[T]) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
if b.Handlers.Update == nil {
// Update is not supported
return
}
resp.Diagnostics.Append(checkClientConfigured(b.client)...)
if resp.Diagnostics.HasError() {
return
}
var plan, state T
resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
if resp.Diagnostics.HasError() {
return
}
body, diags := plan.AsUnifiModel(ctx)
if diags.HasError() {
resp.Diagnostics.Append(diags...)
return
}
site := b.client.ResolveSite(plan)
res, err := b.Handlers.Update(ctx, b.client, site, body)
if err != nil {
resp.Diagnostics.AddError("Error updating resource", err.Error())
return
}
state.Merge(ctx, res)
state.SetSite(site)
resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
}
func (b *GenericResource[T]) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
if b.Handlers.Delete == nil {
// Delete is not supported
return
}
resp.Diagnostics.Append(checkClientConfigured(b.client)...)
if resp.Diagnostics.HasError() {
return
}
var state T
resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
if resp.Diagnostics.HasError() {
return
}
site := b.client.ResolveSite(state)
err := b.Handlers.Delete(ctx, b.client, site, state.GetID())
if err != nil {
resp.Diagnostics.AddError("Error deleting resource", err.Error())
return
}
}

View File

@@ -2,194 +2,24 @@ package settings
import (
"context"
"errors"
"fmt"
"github.com/filipowm/go-unifi/unifi"
"github.com/filipowm/terraform-provider-unifi/internal/provider/base"
"github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/hashicorp/terraform-plugin-framework/resource"
)
// BaseSettingResource provides common functionality for all setting resources
type BaseSettingResource[T base.ResourceModel] struct {
base.ControllerVersionValidator
client *base.Client
typeName string
modelFactory func() T
getter func(context.Context, *base.Client, string) (interface{}, error)
updater func(context.Context, *base.Client, string, interface{}) (interface{}, error)
}
// NewBaseSettingResource creates a new base setting resource
func NewBaseSettingResource[T base.ResourceModel](
// NewSettingResource creates a new base setting resource
func NewSettingResource[T base.ResourceModel](
typeName string,
modelFactory func() T,
getter func(context.Context, *base.Client, string) (interface{}, error),
updater func(context.Context, *base.Client, string, interface{}) (interface{}, error),
) *BaseSettingResource[T] {
return &BaseSettingResource[T]{
typeName: typeName,
modelFactory: modelFactory,
getter: getter,
updater: updater,
}
}
// GetClient returns the UniFi client
func (b *BaseSettingResource[T]) GetClient() *base.Client {
return b.client
}
// SetClient sets the UniFi client
func (b *BaseSettingResource[T]) SetClient(client *base.Client) {
b.client = client
}
func (b *BaseSettingResource[T]) SetVersionValidator(validator base.ControllerVersionValidator) {
b.ControllerVersionValidator = validator
}
func (b *BaseSettingResource[T]) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
base.ConfigureResource(b, req, resp)
}
func (b *BaseSettingResource[T]) Metadata(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) {
resp.TypeName = b.typeName
}
func (b *BaseSettingResource[T]) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
id, site := base.ImportIDWithSite(req, resp)
if resp.Diagnostics.HasError() {
return
}
state := b.modelFactory()
state.SetID(id)
state.SetSite(site)
b.read(ctx, site, state, &resp.Diagnostics)
if resp.Diagnostics.HasError() {
return
}
resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
}
func (b *BaseSettingResource[T]) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
if b.client == nil {
resp.Diagnostics.AddError(
"Client Not Configured",
"Expected configured client. Please report this issue to the provider developers.",
)
return
}
var plan T
resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
if resp.Diagnostics.HasError() {
return
}
site := b.client.ResolveSite(plan)
body, diags := plan.AsUnifiModel(ctx)
if diags.HasError() {
resp.Diagnostics.Append(diags...)
return
}
res, err := b.updater(ctx, b.client, site, body)
if err != nil {
resp.Diagnostics.AddError("Error creating settings", err.Error())
return
}
if res == nil {
resp.Diagnostics.AddError("Error creating settings", fmt.Sprintf("No %[1]s settings returned from the UniFi controller. %[1]s might not be supported on this controller", b.typeName))
return
}
plan.Merge(ctx, res)
plan.SetSite(site)
resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
}
func (b *BaseSettingResource[T]) read(ctx context.Context, site string, state T, diag *diag.Diagnostics) {
if b.client == nil {
diag.AddError(
"Client Not Configured",
"Expected configured client. Please report this issue to the provider developers.",
)
return
}
res, err := b.getter(ctx, b.client, site)
if err != nil {
if errors.Is(err, unifi.ErrNotFound) {
diag.AddError("Settings not found", "The settings were not found in the UniFi controller")
} else {
diag.AddError("Error reading settings", err.Error())
}
return
}
if res != nil {
state.Merge(ctx, res)
}
}
func (b *BaseSettingResource[T]) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
if b.client == nil {
resp.Diagnostics.AddError(
"Client Not Configured",
"Expected configured client. Please report this issue to the provider developers.",
)
return
}
var state T
resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
if resp.Diagnostics.HasError() {
return
}
site := b.client.ResolveSite(state)
b.read(ctx, site, state, &resp.Diagnostics)
if resp.Diagnostics.HasError() {
return
}
state.SetSite(site)
resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
}
func (b *BaseSettingResource[T]) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
if b.client == nil {
resp.Diagnostics.AddError(
"Client Not Configured",
"Expected configured client. Please report this issue to the provider developers.",
)
return
}
var plan, state T
resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
if resp.Diagnostics.HasError() {
return
}
body, diags := plan.AsUnifiModel(ctx)
if diags.HasError() {
resp.Diagnostics.Append(diags...)
return
}
site := b.client.ResolveSite(plan)
res, err := b.updater(ctx, b.client, site, body)
if err != nil {
resp.Diagnostics.AddError("Error updating settings", err.Error())
return
}
state.Merge(ctx, res)
state.SetSite(site)
resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
}
func (b *BaseSettingResource[T]) Delete(_ context.Context, _ resource.DeleteRequest, _ *resource.DeleteResponse) {
// Not supported
) *base.GenericResource[T] {
return base.NewGenericResource(
typeName,
modelFactory,
base.ResourceFunctions{
Read: func(ctx context.Context, client *base.Client, site, _ string) (interface{}, error) {
return getter(ctx, client, site)
},
Create: updater,
Update: updater,
})
}

View File

@@ -42,7 +42,7 @@ func (d *autoSpeedtestModel) Merge(_ context.Context, other interface{}) diag.Di
}
type autoSpeedtestResource struct {
*BaseSettingResource[*autoSpeedtestModel]
*base.GenericResource[*autoSpeedtestModel]
}
func checkAutoSpeedtestUnsupportedError(err error) error {
@@ -54,7 +54,7 @@ func checkAutoSpeedtestUnsupportedError(err error) error {
func NewAutoSpeedtestResource() resource.Resource {
r := &autoSpeedtestResource{}
r.BaseSettingResource = NewBaseSettingResource(
r.GenericResource = NewSettingResource(
"unifi_setting_auto_speedtest",
func() *autoSpeedtestModel { return &autoSpeedtestModel{} },
func(ctx context.Context, client *base.Client, site string) (interface{}, error) {

View File

@@ -45,12 +45,12 @@ func (d *countryModel) Merge(_ context.Context, other interface{}) diag.Diagnost
}
type countryResource struct {
*BaseSettingResource[*countryModel]
*base.GenericResource[*countryModel]
}
func NewCountryResource() resource.Resource {
r := &countryResource{}
r.BaseSettingResource = NewBaseSettingResource(
r.GenericResource = NewSettingResource(
"unifi_setting_country",
func() *countryModel { return &countryModel{} },
func(ctx context.Context, client *base.Client, site string) (interface{}, error) {

View File

@@ -53,7 +53,7 @@ var (
)
type dpiResource struct {
*BaseSettingResource[*dpiModel]
*base.GenericResource[*dpiModel]
}
func (r *dpiResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) {
@@ -76,7 +76,7 @@ func (r *dpiResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *
func NewDpiResource() resource.Resource {
r := &dpiResource{}
r.BaseSettingResource = NewBaseSettingResource(
r.GenericResource = NewSettingResource(
"unifi_setting_dpi",
func() *dpiModel { return &dpiModel{} },
func(ctx context.Context, client *base.Client, site string) (interface{}, error) {

View File

@@ -89,7 +89,7 @@ var (
)
type lcmResource struct {
*BaseSettingResource[*lcmModel]
*base.GenericResource[*lcmModel]
}
func (r *lcmResource) ConfigValidators(_ context.Context) []resource.ConfigValidator {
@@ -136,7 +136,7 @@ func (r *lcmResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *
func NewLcmResource() resource.Resource {
r := &lcmResource{}
r.BaseSettingResource = NewBaseSettingResource(
r.GenericResource = NewSettingResource(
"unifi_setting_lcd_monitor",
func() *lcmModel { return &lcmModel{} },
func(ctx context.Context, client *base.Client, site string) (interface{}, error) {

View File

@@ -52,7 +52,7 @@ var (
)
type localeResource struct {
*BaseSettingResource[*localeModel]
*base.GenericResource[*localeModel]
}
func (r *localeResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) {
@@ -74,7 +74,7 @@ func (r *localeResource) Schema(_ context.Context, _ resource.SchemaRequest, res
func NewLocaleResource() resource.Resource {
r := &localeResource{}
r.BaseSettingResource = NewBaseSettingResource(
r.GenericResource = NewSettingResource(
"unifi_setting_locale",
func() *localeModel { return &localeModel{} },
func(ctx context.Context, client *base.Client, site string) (interface{}, error) {

View File

@@ -50,7 +50,7 @@ var (
)
type magicSiteToSiteVpnResource struct {
*BaseSettingResource[*magicSiteToSiteVpnModel]
*base.GenericResource[*magicSiteToSiteVpnModel]
}
func (r *magicSiteToSiteVpnResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) {
@@ -69,7 +69,7 @@ func (r *magicSiteToSiteVpnResource) Schema(_ context.Context, _ resource.Schema
func NewMagicSiteToSiteVpnResource() resource.Resource {
r := &magicSiteToSiteVpnResource{}
r.BaseSettingResource = NewBaseSettingResource(
r.GenericResource = NewSettingResource(
"unifi_setting_magic_site_to_site_vpn",
func() *magicSiteToSiteVpnModel { return &magicSiteToSiteVpnModel{} },
func(ctx context.Context, client *base.Client, site string) (interface{}, error) {

View File

@@ -50,7 +50,7 @@ var (
)
type networkOptimizationResource struct {
*BaseSettingResource[*networkOptimizationModel]
*base.GenericResource[*networkOptimizationModel]
}
func (r *networkOptimizationResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) {
@@ -70,7 +70,7 @@ func (r *networkOptimizationResource) Schema(_ context.Context, _ resource.Schem
func NewNetworkOptimizationResource() resource.Resource {
r := &networkOptimizationResource{}
r.BaseSettingResource = NewBaseSettingResource(
r.GenericResource = NewSettingResource(
"unifi_setting_network_optimization",
func() *networkOptimizationModel { return &networkOptimizationModel{} },
func(ctx context.Context, client *base.Client, site string) (interface{}, error) {

View File

@@ -92,7 +92,7 @@ var (
)
type ntpResource struct {
*BaseSettingResource[*ntpModel]
*base.GenericResource[*ntpModel]
}
func (r *ntpResource) ConfigValidators(_ context.Context) []resource.ConfigValidator {
@@ -164,7 +164,7 @@ func (r *ntpResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *
// NewNtpResource creates a new instance of the NTP resource.
func NewNtpResource() resource.Resource {
r := &ntpResource{}
r.BaseSettingResource = NewBaseSettingResource(
r.GenericResource = NewSettingResource(
"unifi_setting_ntp",
func() *ntpModel { return &ntpModel{} },
func(ctx context.Context, client *base.Client, site string) (interface{}, error) {

View File

@@ -149,7 +149,7 @@ var (
)
type rsyslogdResource struct {
*BaseSettingResource[*rsyslogdModel]
*base.GenericResource[*rsyslogdModel]
}
func (r *rsyslogdResource) ModifyPlan(_ context.Context, _ resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) {
@@ -260,7 +260,7 @@ func (r *rsyslogdResource) Schema(_ context.Context, _ resource.SchemaRequest, r
func NewRsyslogdResource() resource.Resource {
r := &rsyslogdResource{}
r.BaseSettingResource = NewBaseSettingResource(
r.GenericResource = NewSettingResource(
"unifi_setting_rsyslogd",
func() *rsyslogdModel { return &rsyslogdModel{} },
func(ctx context.Context, client *base.Client, site string) (interface{}, error) {

View File

@@ -52,7 +52,7 @@ var (
)
type sslInspectionResource struct {
*BaseSettingResource[*sslInspectionModel]
*base.GenericResource[*sslInspectionModel]
}
func (r *sslInspectionResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) {
@@ -74,7 +74,7 @@ func (r *sslInspectionResource) Schema(_ context.Context, _ resource.SchemaReque
func NewSslInspectionResource() resource.Resource {
r := &sslInspectionResource{}
r.BaseSettingResource = NewBaseSettingResource(
r.GenericResource = NewSettingResource(
"unifi_setting_ssl_inspection",
func() *sslInspectionModel { return &sslInspectionModel{} },
func(ctx context.Context, client *base.Client, site string) (interface{}, error) {

View File

@@ -56,7 +56,7 @@ var (
)
type teleportResource struct {
*BaseSettingResource[*teleportModel]
*base.GenericResource[*teleportModel]
}
func (r *teleportResource) ModifyPlan(_ context.Context, _ resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) {
@@ -87,7 +87,7 @@ func (r *teleportResource) Schema(_ context.Context, _ resource.SchemaRequest, r
func NewTeleportResource() resource.Resource {
r := &teleportResource{}
r.BaseSettingResource = NewBaseSettingResource(
r.GenericResource = NewSettingResource(
"unifi_setting_teleport",
func() *teleportModel { return &teleportModel{} },
func(ctx context.Context, client *base.Client, site string) (interface{}, error) {

View File

@@ -1220,7 +1220,7 @@ func (r *usgResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *
// NewUsgResource creates a new instance of the USG resource.
func NewUsgResource() resource.Resource {
r := &usgResource{}
r.BaseSettingResource = NewBaseSettingResource(
r.GenericResource = NewSettingResource(
"unifi_setting_usg",
func() *usgModel { return &usgModel{} },
func(ctx context.Context, client *base.Client, site string) (interface{}, error) {
@@ -1243,7 +1243,7 @@ var (
)
type usgResource struct {
*BaseSettingResource[*usgModel]
*base.GenericResource[*usgModel]
}
func (r *usgResource) ConfigValidators(ctx context.Context) []resource.ConfigValidator {