Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TM Edge Clusters and QoS #1375

Merged
merged 17 commits into from
Dec 20, 2024
3 changes: 3 additions & 0 deletions .changes/v4.0.0/1375-features.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
* **New Data Source:** `vcd_tm_edge_cluster` to read and sync TM Edge Clusters [GH-1375]
* **New Resource:** `vcd_tm_edge_cluster_qos` to manage QoS settings for TM Edge Clusters [GH-1375]
* **New Data Source:** `vcd_tm_edge_cluster_qos` to read QoS settings for TM Edge Clusters [GH-1375]
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -69,3 +69,5 @@ require (
google.golang.org/grpc v1.63.2 // indirect
google.golang.org/protobuf v1.34.0 // indirect
)

replace github.com/vmware/go-vcloud-director/v3 => github.com/Didainius/go-vcloud-director/v3 v3.0.0-alpha.4.0.20241220083848-a052e17ab2fb
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk=
dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
github.com/Didainius/go-vcloud-director/v3 v3.0.0-alpha.4.0.20241220083848-a052e17ab2fb h1:mn7zJvagS0s6FU3RtCRWLH1cQHqcFBAbQ3k8I3BYgLc=
github.com/Didainius/go-vcloud-director/v3 v3.0.0-alpha.4.0.20241220083848-a052e17ab2fb/go.mod h1:68KHsVns52dsq/w5JQYzauaU/+NAi1FmCxhBrFc/VoQ=
github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow=
github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM=
github.com/ProtonMail/go-crypto v1.1.0-alpha.2 h1:bkyFVUP+ROOARdgCiJzNQo2V2kiB97LyUpzH9P6Hrlg=
Expand Down Expand Up @@ -149,8 +151,6 @@ github.com/vmihailenco/msgpack/v5 v5.4.1 h1:cQriyiUvjTwOHg8QZaPihLWeRAAVoCpE00IU
github.com/vmihailenco/msgpack/v5 v5.4.1/go.mod h1:GaZTsDaehaPpQVyxrf5mtQlH+pc21PIudVV/E3rRQok=
github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g=
github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds=
github.com/vmware/go-vcloud-director/v3 v3.0.0-alpha.12 h1:WLMb6TygvaQasOcw32yomqb0FODvqjlAtpA1QONec4k=
github.com/vmware/go-vcloud-director/v3 v3.0.0-alpha.12/go.mod h1:68KHsVns52dsq/w5JQYzauaU/+NAi1FmCxhBrFc/VoQ=
github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM=
github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
Expand Down
1 change: 1 addition & 0 deletions vcd/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ type TestConfig struct {
NsxtManagerUsername string `json:"nsxtManagerUsername"`
NsxtManagerPassword string `json:"nsxtManagerPassword"`
NsxtManagerUrl string `json:"nsxtManagerUrl"`
NsxtEdgeCluster string `json:"nsxtEdgeCluster"`
NsxtTier0Gateway string `json:"nsxtTier0Gateway"`

CreateVcenter bool `json:"createVcenter"`
Expand Down
129 changes: 129 additions & 0 deletions vcd/datasource_vcd_tm_edge_cluster.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
package vcd

import (
"context"
"fmt"

"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/vmware/go-vcloud-director/v3/govcd"
"github.com/vmware/go-vcloud-director/v3/types/v56"
)

const labelTmEdgeCluster = "TM Edge Cluster"
const labelTmEdgeClusterSync = "TM Edge Cluster Sync"

func datasourceVcdTmEdgeCluster() *schema.Resource {
return &schema.Resource{
ReadContext: datasourceVcdTmEdgeClusterRead,

Schema: map[string]*schema.Schema{
"name": {
Type: schema.TypeString,
Required: true,
Description: fmt.Sprintf("Name %s", labelTmEdgeCluster),
},
"region_id": {
Type: schema.TypeString,
Required: true,
Description: fmt.Sprintf("Region ID of %s", labelTmEdgeCluster),
},
"sync_before_read": {
Type: schema.TypeBool,
Optional: true,
Default: false,
Description: fmt.Sprintf("Will trigger SYNC operation before looking for a given %s", labelTmEdgeCluster),
},
"node_count": {
Type: schema.TypeInt,
Computed: true,
Description: fmt.Sprintf("Node count in %s", labelTmEdgeCluster),
},
"org_count": {
Type: schema.TypeInt,
Computed: true,
Description: fmt.Sprintf("Org count %s", labelTmEdgeCluster),
},
"vpc_count": {
Type: schema.TypeInt,
Computed: true,
Description: fmt.Sprintf("VPC count %s", labelTmEdgeCluster),
},
"average_cpu_usage_percentage": {
Type: schema.TypeFloat,
Computed: true,
Description: fmt.Sprintf("Average CPU Usage percentage of %s ", labelTmEdgeCluster),
},
"average_memory_usage_percentage": {
Type: schema.TypeFloat,
Computed: true,
Description: fmt.Sprintf("Average Memory Usage percentage of %s ", labelTmEdgeCluster),
},
"health_status": {
Type: schema.TypeString,
Computed: true,
Description: fmt.Sprintf("Health status of %s", labelTmEdgeCluster),
},
"status": {
Type: schema.TypeString,
Computed: true,
Description: fmt.Sprintf("Status of %s", labelTmEdgeCluster),
},
"deployment_type": {
Type: schema.TypeString,
Computed: true,
Description: fmt.Sprintf("Deployment type of %s", labelTmEdgeCluster),
},
},
}
}

func datasourceVcdTmEdgeClusterRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
vcdClient := meta.(*VCDClient)

regionId := d.Get("region_id").(string)
getByName := func(name string) (*govcd.TmEdgeCluster, error) {
return vcdClient.GetTmEdgeClusterByNameAndRegionId(name, regionId)
}

c := dsReadConfig[*govcd.TmEdgeCluster, types.TmEdgeCluster]{
entityLabel: labelTmEdgeCluster,
getEntityFunc: getByName,
stateStoreFunc: setTmEdgeClusterData,
preReadHooks: []schemaHook{syncTmEdgeClustersBeforeReadHook},
}
return readDatasource(ctx, d, meta, c)
}

func setTmEdgeClusterData(_ *VCDClient, d *schema.ResourceData, t *govcd.TmEdgeCluster) error {
if t == nil || t.TmEdgeCluster == nil {
return fmt.Errorf("empty %s received", labelTmEdgeCluster)
}

d.SetId(t.TmEdgeCluster.ID)
dSet(d, "status", t.TmEdgeCluster.Status)
dSet(d, "health_status", t.TmEdgeCluster.HealthStatus)

dSet(d, "region_id", "")
if t.TmEdgeCluster.RegionRef != nil {
dSet(d, "region_id", t.TmEdgeCluster.RegionRef.ID)
}
dSet(d, "deployment_type", t.TmEdgeCluster.DeploymentType)
dSet(d, "node_count", t.TmEdgeCluster.NodeCount)
dSet(d, "org_count", t.TmEdgeCluster.OrgCount)
dSet(d, "vpc_count", t.TmEdgeCluster.VpcCount)
dSet(d, "average_cpu_usage_percentage", t.TmEdgeCluster.AvgCPUUsagePercentage)
dSet(d, "average_memory_usage_percentage", t.TmEdgeCluster.AvgMemoryUsagePercentage)

return nil
}

func syncTmEdgeClustersBeforeReadHook(vcdClient *VCDClient, d *schema.ResourceData) error {
if d.Get("sync_before_read").(bool) {
err := vcdClient.TmSyncEdgeClusters()
if err != nil {
return fmt.Errorf("error syncing %s before lookup: %s", labelTmEdgeClusterSync, err)
}
}
return nil
}
62 changes: 62 additions & 0 deletions vcd/datasource_vcd_tm_edge_cluster_qos.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package vcd

import (
"context"
"fmt"

"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/vmware/go-vcloud-director/v3/govcd"
"github.com/vmware/go-vcloud-director/v3/types/v56"
)

func datasourceVcdTmEdgeClusterQos() *schema.Resource {
return &schema.Resource{
ReadContext: datasourceVcdTmEdgeClusterQosRead,

Schema: map[string]*schema.Schema{
"edge_cluster_id": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
Description: fmt.Sprintf("ID of %s", labelTmEdgeCluster),
},
"region_id": {
Type: schema.TypeString,
Computed: true,
Description: fmt.Sprintf("Region ID of %s", labelTmEdgeCluster),
},
"ingress_committed_bandwidth_mbps": {
Type: schema.TypeString,
Computed: true,
Description: fmt.Sprintf("Ingress committed bandwidth in Mbps for %s", labelTmEdgeCluster),
},
"ingress_burst_size_bytes": {
Type: schema.TypeString,
Computed: true,
Description: fmt.Sprintf("Ingress burst size bytes for %s", labelTmEdgeCluster),
},
"egress_committed_bandwidth_mbps": {
Type: schema.TypeString,
Computed: true,
Description: fmt.Sprintf("Egress committed bandwidth in Mbps for %s", labelTmEdgeCluster),
},
"egress_burst_size_bytes": {
Type: schema.TypeString,
Computed: true,
Description: fmt.Sprintf("Egress burst size bytes for %s", labelTmEdgeCluster),
},
},
}
}

func datasourceVcdTmEdgeClusterQosRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
vcdClient := meta.(*VCDClient)
c := dsReadConfig[*govcd.TmEdgeCluster, types.TmEdgeCluster]{
entityLabel: labelTmEdgeClusterQos,
stateStoreFunc: setTmEdgeClusterQosData,
overrideDefaultNameField: "edge_cluster_id", // pass the value of this field to getEntityFunc
getEntityFunc: vcdClient.GetTmEdgeClusterById,
}
return readDatasource(ctx, d, meta, c)
}
3 changes: 3 additions & 0 deletions vcd/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,8 @@ var globalDataSourceMap = map[string]*schema.Resource{
"vcd_tm_ip_space": datasourceVcdTmIpSpace(), // 4.0
"vcd_tm_tier0_gateway": datasourceVcdTmTier0Gateway(), // 4.0
"vcd_tm_provider_gateway": datasourceVcdTmProviderGateway(), // 4.0
"vcd_tm_edge_cluster": datasourceVcdTmEdgeCluster(), // 4.0
"vcd_tm_edge_cluster_qos": datasourceVcdTmEdgeClusterQos(), // 4.0
}

var globalResourceMap = map[string]*schema.Resource{
Expand Down Expand Up @@ -324,6 +326,7 @@ var globalResourceMap = map[string]*schema.Resource{
"vcd_tm_org_vdc": resourceTmOrgVdc(), // 4.0
"vcd_tm_ip_space": resourceVcdTmIpSpace(), // 4.0
"vcd_tm_provider_gateway": resourceVcdTmProviderGateway(), // 4.0
"vcd_tm_edge_cluster_qos": resourceVcdTmEdgeClusterQos(), // 4.0
}

// Provider returns a terraform.ResourceProvider.
Expand Down
25 changes: 23 additions & 2 deletions vcd/resource_generic_crud.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,10 @@ func updateResource[O updateDeleter[O, I], I any](ctx context.Context, d *schema
return diag.Errorf("error getting %s type on update: %s", c.entityLabel, err)
}

if d.Id() == "" {
return diag.Errorf("empty id for updating %s", c.entityLabel)
}

retrievedEntity, err := c.getEntityFunc(d.Id())
if err != nil {
return diag.Errorf("error getting %s for update: %s", c.entityLabel, err)
Expand Down Expand Up @@ -225,17 +229,34 @@ type dsReadConfig[O any, I any] struct {
// getEntityFunc is a function that retrieves the entity
// It will use ID for resources and Name for data sources
getEntityFunc func(idOrName string) (O, error)

// preReadHooks will be executed before the entity is created
preReadHooks []schemaHook

// overrideDefaultNameField permits to override default field ('name') that passed to
// getEntityFunc. The field must be a string (schema.TypeString)
overrideDefaultNameField string
}

// readDatasource will read a data source by a 'name' field in Terraform schema
func readDatasource[O any, I any](_ context.Context, d *schema.ResourceData, meta interface{}, c dsReadConfig[O, I]) diag.Diagnostics {
entityName := d.Get("name").(string)
vcdClient := meta.(*VCDClient)
err := execSchemaHook(vcdClient, d, c.preReadHooks)
if err != nil {
return diag.Errorf("error executing pre-read %s hooks: %s", c.entityLabel, err)
}

fieldName := "name"
if c.overrideDefaultNameField != "" {
fieldName = c.overrideDefaultNameField
util.Logger.Printf("[DEBUG] Overriding %s field 'name' to '%s' for datasource lookup", c.entityLabel, c.overrideDefaultNameField)
}
entityName := d.Get(fieldName).(string)
retrievedEntity, err := c.getEntityFunc(entityName)
if err != nil {
return diag.Errorf("error getting %s by Name '%s': %s", c.entityLabel, entityName, err)
}

vcdClient := meta.(*VCDClient)
err = c.stateStoreFunc(vcdClient, d, retrievedEntity)
if err != nil {
return diag.Errorf("error storing %s to state during data source read: %s", c.entityLabel, err)
Expand Down
Loading
Loading