Skip to content

Commit

Permalink
vCenter and NSX-T Manager resources (#1343)
Browse files Browse the repository at this point in the history
  • Loading branch information
Didainius authored Oct 25, 2024
1 parent b9c52c7 commit 050cad3
Show file tree
Hide file tree
Showing 20 changed files with 1,190 additions and 102 deletions.
2 changes: 2 additions & 0 deletions .changes/v4.0.0/1343-features.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
* **New Resource:** `vcd_vcenter` to manage vCenter servers [GH-1343]
* **New Resource:** `vcd_nsxt_manager` to manage NSX-T Managers [GH-1343]
4 changes: 4 additions & 0 deletions .changes/v4.0.0/1343-improvements.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
* **Data Source:** `vcd_vcenter` improved with new fields that match the ones for new resource
[GH-1343]
* **Data Source:** `vcd_nsxt_manager` improved with new fields that match the ones for new resource
[GH-1343]
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ require (
github.com/hashicorp/go-version v1.6.0
github.com/hashicorp/terraform-plugin-sdk/v2 v2.34.0
github.com/kr/pretty v0.3.1
github.com/vmware/go-vcloud-director/v3 v3.0.0-alpha.2
github.com/vmware/go-vcloud-director/v3 v3.0.0-alpha.3
)

require (
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -149,8 +149,8 @@ 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.2 h1:5bpxq1V0I4G50FWwi+COnbNcPUD/T747BmrkZaiN7G0=
github.com/vmware/go-vcloud-director/v3 v3.0.0-alpha.2/go.mod h1:68KHsVns52dsq/w5JQYzauaU/+NAi1FmCxhBrFc/VoQ=
github.com/vmware/go-vcloud-director/v3 v3.0.0-alpha.3 h1:MYdFcDIKbIw4W09iK4e73/VMgom8hl/3fM9d18gwAkI=
github.com/vmware/go-vcloud-director/v3 v3.0.0-alpha.3/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
18 changes: 14 additions & 4 deletions vcd/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,10 +108,20 @@ type TestConfig struct {
MaxRetryTimeout int `json:"maxRetryTimeout"`
} `json:"provider"`
Tm struct {
Org string `json:"org"` // temporary field to make skipIfNotTm work
Region string `json:"region"`
RegionStoragePolicy string `json:"regionStoragePolicy"`
Vdc string `json:"vdc"`
Org string `json:"org"` // temporary field to make skipIfNotTm work
Region string `json:"region"` //
RegionStoragePolicy string `json:"regionStoragePolicy"` //
Vdc string `json:"vdc"` //

CreateNsxtManager bool `json:"createNsxtManager"`
NsxtManagerUsername string `json:"nsxtManagerUsername"`
NsxtManagerPassword string `json:"nsxtManagerPassword"`
NsxtManagerUrl string `json:"nsxtManagerUrl"`

CreateVcenter bool `json:"createVcenter"`
VcenterUsername string `json:"vcenterUsername"`
VcenterPassword string `json:"vcenterPassword"`
VcenterUrl string `json:"vcenterUrl"`
} `json:"tm,omitempty"`
VCD struct {
Org string `json:"org"`
Expand Down
71 changes: 40 additions & 31 deletions vcd/datasource_vcd_nsxt_manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,57 +2,66 @@ package vcd

import (
"context"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"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"
)

// TODO: TM: validate compatibility with old data source

func datasourceVcdNsxtManager() *schema.Resource {
return &schema.Resource{
ReadContext: datasourceNsxtManagerRead,
ReadContext: datasourceVcdNsxtManagerRead,

Schema: map[string]*schema.Schema{
"name": {
Type: schema.TypeString,
Required: true,
Description: "Name of NSX-T manager.",
Description: fmt.Sprintf("Name of %s", labelNsxtManager),
},
"description": {
Type: schema.TypeString,
Computed: true,
Description: fmt.Sprintf("Description of %s", labelNsxtManager),
},
"username": {
Type: schema.TypeString,
Computed: true,
Description: fmt.Sprintf("Username for authenticating to %s", labelNsxtManager),
},
"url": {
Type: schema.TypeString,
Computed: true,
Description: fmt.Sprintf("URL of %s", labelNsxtManager),
},
"network_provider_scope": {
Type: schema.TypeString,
Computed: true,
Description: fmt.Sprintf("Network Provider Scope for %s", labelNsxtManager),
},
"status": {
Type: schema.TypeString,
Computed: true,
Description: fmt.Sprintf("Status of %s", labelNsxtManager),
},
"href": {
Type: schema.TypeString,
Computed: true,
Description: "HREF of NSX-T manager.",
Description: fmt.Sprintf("HREF of %s", labelNsxtManager),
},
},
}
}

func datasourceNsxtManagerRead(_ context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
func datasourceVcdNsxtManagerRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
vcdClient := meta.(*VCDClient)
nsxtManagerName := d.Get("name").(string)

nsxtManagers, err := vcdClient.QueryNsxtManagerByName(nsxtManagerName)
if err != nil {
return diag.Errorf("could not find NSX-T manager by name '%s': %s", nsxtManagerName, err)
c := crudConfig[*govcd.NsxtManagerOpenApi, types.NsxtManagerOpenApi]{
entityLabel: labelNsxtManager,
getEntityFunc: vcdClient.GetNsxtManagerOpenApiByName,
stateStoreFunc: setNsxtManagerData,
}

if len(nsxtManagers) == 0 {
return diag.Errorf("%s found %d NSX-T managers with name '%s'",
govcd.ErrorEntityNotFound, len(nsxtManagers), nsxtManagerName)
}

if len(nsxtManagers) > 1 {
return diag.Errorf("found %d NSX-T managers with name '%s'", len(nsxtManagers), nsxtManagerName)
}

// We try to keep IDs clean
id := extractUuid(nsxtManagers[0].HREF)
urn, err := govcd.BuildUrnWithUuid("urn:vcloud:nsxtmanager:", id)
if err != nil {
return diag.Errorf("could not construct URN from id '%s': %s", id, err)
}
dSet(d, "name", nsxtManagers[0].Name)
dSet(d, "href", nsxtManagers[0].HREF)
d.SetId(urn)

return nil
return readDatasource(ctx, d, meta, c)
}
111 changes: 53 additions & 58 deletions vcd/datasource_vcd_vcenter.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,96 +2,91 @@ package vcd

import (
"context"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"log"
"net/url"
"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"
)

// TODO: TM: validate compatibility with old data source

func datasourceVcdVcenter() *schema.Resource {
return &schema.Resource{
ReadContext: datasourceVcenterRead,
ReadContext: datasourceVcdVcenterRead,

Schema: map[string]*schema.Schema{
"name": {
Type: schema.TypeString,
Required: true,
Description: "Name of vCenter.",
Description: fmt.Sprintf("Name of %s", labelVirtualCenter),
},
"vcenter_version": {
"url": {
Type: schema.TypeString,
Computed: true,
Description: "vCenter version",
Description: fmt.Sprintf("URL of %s", labelVirtualCenter),
},
"vcenter_host": {
"username": {
Type: schema.TypeString,
Computed: true,
Description: "vCenter hostname",
Description: fmt.Sprintf("Username of %s", labelVirtualCenter),
},
"is_enabled": {
Type: schema.TypeBool,
Computed: true,
Description: fmt.Sprintf("Should the %s be enabled", labelVirtualCenter),
},
"status": {
"description": {
Type: schema.TypeString,
Computed: true,
Description: "vCenter status",
Description: fmt.Sprintf("Description of %s", labelVirtualCenter),
},
"is_enabled": {
"has_proxy": {
Type: schema.TypeBool,
Computed: true,
Description: "vCenter version",
Description: fmt.Sprintf("A flag that shows if %s has proxy defined", labelVirtualCenter),
},
// In UI this field is called `connection`, but it is a reserved field in Terrraform
"connection_status": {
"is_connected": {
Type: schema.TypeBool,
Computed: true,
Description: fmt.Sprintf("A flag that shows if %s is connected", labelVirtualCenter),
},
"mode": {
Type: schema.TypeString,
Computed: true,
Description: fmt.Sprintf("Mode of %s", labelVirtualCenter),
},
"listener_state": {
Type: schema.TypeString,
Computed: true,
Description: "vCenter connection state",
Description: fmt.Sprintf("Listener state of %s", labelVirtualCenter),
},
"cluster_health_status": {
Type: schema.TypeString,
Computed: true,
Description: fmt.Sprintf("Mode of %s", labelVirtualCenter),
},
"version": {
Type: schema.TypeString,
Computed: true,
Description: fmt.Sprintf("Version of %s", labelVirtualCenter),
},
"uuid": {
Type: schema.TypeString,
Computed: true,
Description: fmt.Sprintf("%s UUID", labelVirtualCenter),
},
},
}
}

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

vCenterName := d.Get("name").(string)

vcs, err := govcd.QueryVirtualCenters(vcdClient.VCDClient, "name=="+url.QueryEscape(vCenterName))
if err != nil {
return diag.Errorf("error occured while querying vCenters: %s", err)
}

if len(vcs) == 0 {
return diag.Errorf("%s: could not identify single vCenter. Got %d with name '%s'",
govcd.ErrorEntityNotFound, len(vcs), vCenterName)
}

if len(vcs) > 1 {
return diag.Errorf("could not identify single vCenter. Got %d with name '%s'",
len(vcs), vCenterName)
}

uuid := extractUuid(vcs[0].HREF)
urn, err := govcd.BuildUrnWithUuid("urn:vcloud:vimserver:", uuid)
if err != nil {
return diag.Errorf("could not build URN for ID '%s': %s", uuid, err)
}

d.SetId(urn)
setVcenterData(d, vcs[0])

return nil
}

func setVcenterData(d *schema.ResourceData, vc *types.QueryResultVirtualCenterRecordType) {
dSet(d, "vcenter_version", vc.VcVersion)
// vc.Url is in format `https://XXXX.com/sdk` while UI shows hostname only so we extract it
// The error should not be a reason to fail datasource if it is invalid so it is just logged
host, err := url.Parse(vc.Url)
if err != nil {
log.Printf("[DEBUG] [vCenter read] - could not parse vCenter URL '%s': %s", vc.Url, err)
c := crudConfig[*govcd.VCenter, types.VSphereVirtualCenter]{
entityLabel: labelVirtualCenter,
getEntityFunc: vcdClient.GetVCenterByName,
stateStoreFunc: setTmVcenterData,
}
dSet(d, "vcenter_host", host.Host)
dSet(d, "status", vc.Status)
dSet(d, "is_enabled", vc.IsEnabled)
dSet(d, "connection_status", vc.ListenerState)
return readDatasource(ctx, d, meta, c)
}
2 changes: 1 addition & 1 deletion vcd/datasource_vcd_vcenter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import (
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
)

func TestAccVcdVcenter(t *testing.T) {
func TestAccVcdVcenterDS(t *testing.T) {
preTestChecks(t)
skipIfNotSysAdmin(t)

Expand Down
2 changes: 2 additions & 0 deletions vcd/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,8 @@ var globalResourceMap = map[string]*schema.Resource{
"vcd_nsxt_alb_virtual_service_http_sec_rules": resourceVcdAlbVirtualServiceSecRules(), // 3.14

"vcd_tm_content_library": resourceVcdTmContentLibrary(), // 4.0
"vcd_nsxt_manager": resourceVcdNsxtManager(), // 4.0
"vcd_vcenter": resourceVcdVcenter(), // 4.0
}

// Provider returns a terraform.ResourceProvider.
Expand Down
Loading

0 comments on commit 050cad3

Please sign in to comment.