diff --git a/docs/resources/fabric_service_token.md b/docs/resources/fabric_service_token.md index 92c1a36da..437523ab9 100644 --- a/docs/resources/fabric_service_token.md +++ b/docs/resources/fabric_service_token.md @@ -15,8 +15,8 @@ Additional documentation: Aside Port Service Token ```terraform resource "equinix_fabric_service_token" "test" { - type = "VC_TOKEN" - description = "Aside COLO Service Token" + type = "VC_TOKEN" + description = "Aside COLO Service Token" expiration_date_time = "2025-01-18T06:43:49.981Z" service_token_connection { type = "EVPL_VC" @@ -44,8 +44,8 @@ resource "equinix_fabric_service_token" "test" { Zside Port Service Token ```terraform resource "equinix_fabric_service_token" "test"{ - type = "VC_TOKEN" - description = "Zside COLO Service Token" + type = "VC_TOKEN" + description = "Zside COLO Service Token" expiration_date_time = "2025-01-18T06:43:49.981Z" service_token_connection { type = "EVPL_VC" @@ -70,11 +70,36 @@ resource "equinix_fabric_service_token" "test"{ } ``` +Zside Network Service Token +```terraform +resource "equinix_fabric_service_token" "test" { + type = "VC_TOKEN" + description = "Zside Network Service Token" + expiration_date_time = "2025-01-18T06:43:49.986Z" + service_token_connection { + type = "EVPL_VC" + supported_bandwidths = [50, 200, 10000] + z_side { + access_point_selectors { + type = "NETWORK" + network { + uuid = "" + } + } + } + } + notifications { + type = "ALL" + emails = ["example@equinix.com"] + } +} +``` + Zside Virtual Device Service Token ```terraform resource "equinix_fabric_service_token" "test" { type = "VC_TOKEN" - description = "Zside VD Service Token" + description = "Zside VD Service Token" expiration_date_time = "2025-01-18T06:43:49.986Z" service_token_connection { type = "EVPL_VC" @@ -206,27 +231,27 @@ Optional: ### Nested Schema for `service_token_connection.a_side.access_point_selectors.network` -Optional: +Required: -- `location` (Block Set) Location (see [below for nested schema](#nestedblock--service_token_connection--a_side--access_point_selectors--network--location)) -- `name` (String) Network Name -- `scope` (String) Scope of Network -- `type` (String) Type of Network - `uuid` (String) Equinix-assigned Network identifier Read-Only: - `href` (String) Unique Resource Identifier +- `location` (Set of Object) Location (see [below for nested schema](#nestedatt--service_token_connection--a_side--access_point_selectors--network--location)) +- `name` (String) Network Name +- `scope` (String) Scope of Network +- `type` (String) Type of Network - + ### Nested Schema for `service_token_connection.a_side.access_point_selectors.network.location` -Optional: +Read-Only: -- `ibx` (String) IBX Code -- `metro_code` (String) Access point metro code -- `metro_name` (String) Access point metro name -- `region` (String) Access point region +- `ibx` (String) +- `metro_code` (String) +- `metro_name` (String) +- `region` (String) @@ -330,27 +355,27 @@ Optional: ### Nested Schema for `service_token_connection.z_side.access_point_selectors.network` -Optional: +Required: -- `location` (Block Set) Location (see [below for nested schema](#nestedblock--service_token_connection--z_side--access_point_selectors--network--location)) -- `name` (String) Network Name -- `scope` (String) Scope of Network -- `type` (String) Type of Network - `uuid` (String) Equinix-assigned Network identifier Read-Only: - `href` (String) Unique Resource Identifier +- `location` (Set of Object) Location (see [below for nested schema](#nestedatt--service_token_connection--z_side--access_point_selectors--network--location)) +- `name` (String) Network Name +- `scope` (String) Scope of Network +- `type` (String) Type of Network - + ### Nested Schema for `service_token_connection.z_side.access_point_selectors.network.location` -Optional: +Read-Only: -- `ibx` (String) IBX Code -- `metro_code` (String) Access point metro code -- `metro_name` (String) Access point metro name -- `region` (String) Access point region +- `ibx` (String) +- `metro_code` (String) +- `metro_name` (String) +- `region` (String) diff --git a/examples/resources/equinix_fabric_service_token/aside_colo_service_token.tf b/examples/resources/equinix_fabric_service_token/aside_colo_service_token.tf index b65b98be7..53f68d352 100644 --- a/examples/resources/equinix_fabric_service_token/aside_colo_service_token.tf +++ b/examples/resources/equinix_fabric_service_token/aside_colo_service_token.tf @@ -1,6 +1,6 @@ resource "equinix_fabric_service_token" "test" { - type = "VC_TOKEN" - description = "Aside COLO Service Token" + type = "VC_TOKEN" + description = "Aside COLO Service Token" expiration_date_time = "2025-01-18T06:43:49.981Z" service_token_connection { type = "EVPL_VC" diff --git a/examples/resources/equinix_fabric_service_token/zside_colo_service_token.tf b/examples/resources/equinix_fabric_service_token/zside_colo_service_token.tf index f4394340f..73eb49bff 100644 --- a/examples/resources/equinix_fabric_service_token/zside_colo_service_token.tf +++ b/examples/resources/equinix_fabric_service_token/zside_colo_service_token.tf @@ -1,6 +1,6 @@ resource "equinix_fabric_service_token" "test"{ - type = "VC_TOKEN" - description = "Zside COLO Service Token" + type = "VC_TOKEN" + description = "Zside COLO Service Token" expiration_date_time = "2025-01-18T06:43:49.981Z" service_token_connection { type = "EVPL_VC" diff --git a/examples/resources/equinix_fabric_service_token/zside_network_service_token.tf b/examples/resources/equinix_fabric_service_token/zside_network_service_token.tf new file mode 100644 index 000000000..f9cba0a53 --- /dev/null +++ b/examples/resources/equinix_fabric_service_token/zside_network_service_token.tf @@ -0,0 +1,21 @@ +resource "equinix_fabric_service_token" "test" { + type = "VC_TOKEN" + description = "Zside Network Service Token" + expiration_date_time = "2025-01-18T06:43:49.986Z" + service_token_connection { + type = "EVPL_VC" + supported_bandwidths = [50, 200, 10000] + z_side { + access_point_selectors { + type = "NETWORK" + network { + uuid = "" + } + } + } + } + notifications { + type = "ALL" + emails = ["example@equinix.com"] + } +} diff --git a/examples/resources/equinix_fabric_service_token/zside_vd_service_token.tf b/examples/resources/equinix_fabric_service_token/zside_vd_service_token.tf index f3f0b8b36..39ef02bf4 100644 --- a/examples/resources/equinix_fabric_service_token/zside_vd_service_token.tf +++ b/examples/resources/equinix_fabric_service_token/zside_vd_service_token.tf @@ -1,6 +1,6 @@ resource "equinix_fabric_service_token" "test" { type = "VC_TOKEN" - description = "Zside VD Service Token" + description = "Zside VD Service Token" expiration_date_time = "2025-01-18T06:43:49.986Z" service_token_connection { type = "EVPL_VC" diff --git a/internal/resources/fabric/service_token/models.go b/internal/resources/fabric/service_token/models.go index 2e37c57b5..821d7c2f6 100644 --- a/internal/resources/fabric/service_token/models.go +++ b/internal/resources/fabric/service_token/models.go @@ -28,6 +28,11 @@ func buildCreateRequest(d *schema.ResourceData) fabricv4.ServiceToken { } serviceTokenRequest.SetExpirationDateTime(expirationTime) + descriptionConfig := d.Get("description").(string) + if descriptionConfig != "" { + serviceTokenRequest.SetDescription(descriptionConfig) + } + connectionConfig := d.Get("service_token_connection").(*schema.Set).List() connection := connectionTerraformToGo(connectionConfig) serviceTokenRequest.SetConnection(connection) @@ -40,33 +45,33 @@ func buildCreateRequest(d *schema.ResourceData) fabricv4.ServiceToken { } -func buildUpdateRequest(d *schema.ResourceData) []fabricv4.ServiceTokenChangeOperation { - patches := make([]fabricv4.ServiceTokenChangeOperation, 0) +func buildUpdateRequest(d *schema.ResourceData) ([][]fabricv4.ServiceTokenChangeOperation, error) { + patches := make([][]fabricv4.ServiceTokenChangeOperation, 0) oldName, newName := d.GetChange("name") if oldName.(string) != newName.(string) { - patches = append(patches, fabricv4.ServiceTokenChangeOperation{ + patches = append(patches, []fabricv4.ServiceTokenChangeOperation{{ Op: "replace", Path: "/name", Value: newName.(string), - }) + }}) } oldDescription, newDescription := d.GetChange("description") if oldDescription.(string) != newDescription.(string) { - patches = append(patches, fabricv4.ServiceTokenChangeOperation{ + patches = append(patches, []fabricv4.ServiceTokenChangeOperation{{ Op: "replace", Path: "/description", Value: newDescription.(string), - }) + }}) } oldExpirationDate, newExpirationDate := d.GetChange("expiration_date_time") if oldExpirationDate.(string) != newExpirationDate.(string) { - patches = append(patches, fabricv4.ServiceTokenChangeOperation{ + patches = append(patches, []fabricv4.ServiceTokenChangeOperation{{ Op: "replace", Path: "/expirationDateTime", Value: newExpirationDate.(string), - }) + }}) } oldNotifications, newNotifications := d.GetChange("notifications") @@ -99,11 +104,11 @@ func buildUpdateRequest(d *schema.ResourceData) []fabricv4.ServiceTokenChangeOpe } if !reflect.DeepEqual(oldNotificationEmails, newNotificationEmails) { - patches = append(patches, fabricv4.ServiceTokenChangeOperation{ + patches = append(patches, []fabricv4.ServiceTokenChangeOperation{{ Op: "replace", Path: "/notifications/emails", Value: newNotificationEmails, - }) + }}) } oldServiceTokenConnection, newServiceTokenConnection := d.GetChange("service_token_connection") @@ -114,11 +119,9 @@ func buildUpdateRequest(d *schema.ResourceData) []fabricv4.ServiceTokenChangeOpe for _, connection := range oldServiceTokenConnection.(*schema.Set).List() { oldBandwidthLimitMap := connection.(map[string]interface{}) - if bandwidth, ok := oldBandwidthLimitMap["bandwidthLimit"]; ok { - oldBandwidthLimit := bandwidth.([]interface{}) - if len(oldBandwidthLimit) > 0 { - oldAsideBandwidthLimits := converters.IfArrToIntArr(oldBandwidthLimit) - oldAsideBandwidthLimit = oldAsideBandwidthLimits[0] + if bandwidth, ok := oldBandwidthLimitMap["bandwidth_limit"]; ok { + if bandwidthLimitValue, ok := bandwidth.(int); ok { + oldAsideBandwidthLimit = bandwidthLimitValue } } } @@ -128,22 +131,20 @@ func buildUpdateRequest(d *schema.ResourceData) []fabricv4.ServiceTokenChangeOpe for _, connection := range newServiceTokenConnection.(*schema.Set).List() { newBandwidthLimitMap := connection.(map[string]interface{}) - if bandwidth, ok := newBandwidthLimitMap["bandwidthLimit"]; ok { - newBandwidthLimit := bandwidth.([]interface{}) - if len(newBandwidthLimit) > 0 { - newAsideBandwidthLimits := converters.IfArrToIntArr(newBandwidthLimit) - newAsideBandwidthLimit = newAsideBandwidthLimits[0] + if bandwidth, ok := newBandwidthLimitMap["bandwidth_limit"]; ok { + if bandwidthLimitValue, ok := bandwidth.(int); ok { + newAsideBandwidthLimit = bandwidthLimitValue } } } } if oldAsideBandwidthLimit != newAsideBandwidthLimit { - patches = append(patches, fabricv4.ServiceTokenChangeOperation{ + patches = append(patches, []fabricv4.ServiceTokenChangeOperation{{ Op: "replace", Path: "/connection/bandwidthLimit", Value: newAsideBandwidthLimit, - }) + }}) } var oldZsideBandwidth, newZsideBandwidth []int @@ -176,14 +177,14 @@ func buildUpdateRequest(d *schema.ResourceData) []fabricv4.ServiceTokenChangeOpe } if !areSlicesEqual(oldZsideBandwidth, newZsideBandwidth) { - patches = append(patches, fabricv4.ServiceTokenChangeOperation{ + patches = append(patches, []fabricv4.ServiceTokenChangeOperation{{ Op: "replace", Path: "/connection/supportedBandwidths", Value: newZsideBandwidth, - }) + }}) } - return patches + return patches, nil } func areSlicesEqual(a, b []int) bool { @@ -251,16 +252,35 @@ func setServiceTokensData(d *schema.ResourceData, routeFilters *fabricv4.Service func serviceTokenResponseMap(token *fabricv4.ServiceToken) map[string]interface{} { serviceToken := make(map[string]interface{}) serviceToken["type"] = string(token.GetType()) - serviceToken["href"] = token.GetHref() - serviceToken["uuid"] = token.GetUuid() expirationDateTime := token.GetExpirationDateTime() const TimeFormat = "2006-01-02T15:04:05.000Z" serviceToken["expiration_date_time"] = expirationDateTime.Format(TimeFormat) - serviceToken["state"] = token.GetState() + if token.Href != nil { + serviceToken["href"] = token.GetHref() + } + if token.Uuid != nil { + serviceToken["uuid"] = token.GetUuid() + } + if token.State != nil { + serviceToken["state"] = token.GetState() + } + if token.IssuerSide != nil { + serviceToken["issuer_side"] = token.GetIssuerSide() + } + if token.Name != nil { + serviceToken["name"] = token.GetName() + } + if token.Description != nil { + serviceToken["description"] = token.GetDescription() + } if token.Connection != nil { connection := token.GetConnection() serviceToken["service_token_connection"] = connectionGoToTerraform(&connection) } + if token.Notifications != nil { + notifications := token.GetNotifications() + serviceToken["notifications"] = equinix_fabric_schema.NotificationsGoToTerraform(notifications) + } if token.Account != nil { account := token.GetAccount() serviceToken["account"] = equinix_fabric_schema.AccountGoToTerraform(&account) @@ -290,7 +310,9 @@ func connectionTerraformToGo(connectionTerraform []interface{}) fabricv4.Service connection.SetType(fabricv4.ServiceTokenConnectionType(typeVal)) uuid := connectionMap["uuid"].(string) - connection.SetUuid(uuid) + if uuid != "" { + connection.SetUuid(uuid) + } allowRemoteConnection := connectionMap["allow_remote_connection"].(bool) connection.SetAllowRemoteConnection(allowRemoteConnection) @@ -299,10 +321,12 @@ func connectionTerraformToGo(connectionTerraform []interface{}) fabricv4.Service connection.SetAllowCustomBandwidth(allowCustomBandwidth) bandwidthLimit := connectionMap["bandwidth_limit"].(int) - connection.SetBandwidthLimit(int32(bandwidthLimit)) + if bandwidthLimit > 0 { + connection.SetBandwidthLimit(int32(bandwidthLimit)) + } supportedBandwidths := connectionMap["supported_bandwidths"].([]interface{}) - if supportedBandwidths != nil { + if len(supportedBandwidths) > 0 { int32Bandwidths := make([]int32, len(supportedBandwidths)) for i, v := range supportedBandwidths { int32Bandwidths[i] = int32(v.(int)) @@ -403,9 +427,7 @@ func portTerraformToGo(portList []interface{}) fabricv4.SimplifiedMetadataEntity priority := portListMap["priority"].(string) locationList := portListMap["location"].(*schema.Set).List() - if uuid != "" { - port.SetUuid(uuid) - } + port.SetUuid(uuid) if href != "" { port.SetHref(href) } @@ -475,11 +497,20 @@ func virtualDeviceTerraformToGo(virtualDeviceList []interface{}) fabricv4.Simpli uuid := virtualDeviceMap["uuid"].(string) name := virtualDeviceMap["name"].(string) cluster := virtualDeviceMap["cluster"].(string) - virtualDevice.SetHref(href) - virtualDevice.SetType(fabricv4.SimplifiedVirtualDeviceType(type_)) + + if href != "" { + virtualDevice.SetHref(href) + } + if type_ != "" { + virtualDevice.SetType(fabricv4.SimplifiedVirtualDeviceType(type_)) + } virtualDevice.SetUuid(uuid) - virtualDevice.SetName(name) - virtualDevice.SetCluster(cluster) + if name != "" { + virtualDevice.SetName(name) + } + if cluster != "" { + virtualDevice.SetCluster(cluster) + } return virtualDevice } @@ -494,9 +525,14 @@ func interfaceTerraformToGo(interfaceList []interface{}) fabricv4.VirtualDeviceI uuid := interfaceMap["uuid"].(string) type_ := interfaceMap["type"].(string) id := interfaceMap["id"].(int) - interface_.SetUuid(uuid) + + if uuid != "" { + interface_.SetUuid(uuid) + } interface_.SetType(fabricv4.VirtualDeviceInterfaceType(type_)) - interface_.SetId(int32(id)) + if id >= 0 { + interface_.SetId(int32(id)) + } return interface_ } @@ -508,9 +544,29 @@ func networkTerraformToGo(networkList []interface{}) fabricv4.SimplifiedTokenNet var network fabricv4.SimplifiedTokenNetwork networkListMap := networkList[0].(map[string]interface{}) uuid := networkListMap["uuid"].(string) + href := networkListMap["href"].(string) type_ := networkListMap["type"].(string) + name := networkListMap["name"].(string) + scope := networkListMap["scope"].(string) + locationList := networkListMap["location"].(*schema.Set).List() + network.SetUuid(uuid) - network.SetType(fabricv4.SimplifiedTokenNetworkType(type_)) + if href != "" { + network.SetHref(href) + } + if type_ != "" { + network.SetType(fabricv4.SimplifiedTokenNetworkType(type_)) + } + if name != "" { + network.SetName(name) + } + if scope != "" { + network.SetScope(fabricv4.SimplifiedTokenNetworkScope(scope)) + } + if len(locationList) != 0 { + location := equinix_fabric_schema.LocationTerraformToGo(locationList) + network.SetLocation(location) + } return network } @@ -748,10 +804,25 @@ func networkGoToTerraform(network *fabricv4.SimplifiedTokenNetwork) *schema.Set } mappedNetwork := make(map[string]interface{}) - mappedNetwork["uuid"] = network.GetUuid() - mappedNetwork["href"] = network.GetHref() - mappedNetwork["type"] = string(network.GetType()) - + if uuid := network.GetUuid(); uuid != "" { + mappedNetwork["uuid"] = uuid + } + if href := network.GetHref(); href != "" { + mappedNetwork["href"] = href + } + if type_ := network.GetType(); type_ != "" { + mappedNetwork["type"] = string(type_) + } + if name := network.GetName(); name != "" { + mappedNetwork["name"] = name + } + if scope := network.GetName(); scope != "" { + mappedNetwork["scope"] = string(network.GetScope()) + } + if network.Location != nil { + location := network.GetLocation() + mappedNetwork["location"] = equinix_fabric_schema.LocationGoToTerraform(&location) + } return schema.NewSet( schema.HashResource(networkSch()), []interface{}{mappedNetwork}, diff --git a/internal/resources/fabric/service_token/resource.go b/internal/resources/fabric/service_token/resource.go index ec8f57cff..7bfc90b28 100644 --- a/internal/resources/fabric/service_token/resource.go +++ b/internal/resources/fabric/service_token/resource.go @@ -2,6 +2,7 @@ package service_token import ( "context" + "fmt" "log" "strings" "time" @@ -65,7 +66,7 @@ func resourceCreate(ctx context.Context, d *schema.ResourceData, meta interface{ } createTimeout := d.Timeout(schema.TimeoutCreate) - 30*time.Second - time.Since(start) - if err = waitForStability(d.Id(), meta, d, ctx, createTimeout); err != nil { + if _, err = waitForStability(d.Id(), meta, d, ctx, createTimeout); err != nil { return diag.Errorf("error waiting for service token (%s) to be created: %s", d.Id(), err) } @@ -74,20 +75,35 @@ func resourceCreate(ctx context.Context, d *schema.ResourceData, meta interface{ func resourceUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { client := meta.(*config.Config).NewFabricClientForSDK(d) - updateRequest := buildUpdateRequest(d) - start := time.Now() - serviceToken, _, err := client.ServiceTokensApi.UpdateServiceTokenByUuid(ctx, d.Id()).ServiceTokenChangeOperation(updateRequest).Execute() + updateTimeout := d.Timeout(schema.TimeoutUpdate) - 30*time.Second - time.Since(start) + dbToken, err := waitForStability(d.Id(), meta, d, ctx, updateTimeout) if err != nil { - return diag.FromErr(equinix_errors.FormatFabricError(err)) + return diag.Errorf("either timed out or errored out while fetching Fabric Service Token for uuid %s and error %v", d.Id(), err) } - - updateTimeout := d.Timeout(schema.TimeoutUpdate) - 30*time.Second - time.Since(start) - if err = waitForStability(d.Id(), meta, d, ctx, updateTimeout); err != nil { - return diag.Errorf("error waiting for service token (%s) to be updated: %s", d.Id(), err) + diags := diag.Diagnostics{} + updates, err := buildUpdateRequest(d) + if err != nil { + diags = append(diags, diag.Diagnostic{Severity: 1, Summary: err.Error()}) + return diags } + for _, update := range updates { + _, _, err = client.ServiceTokensApi.UpdateServiceTokenByUuid(ctx, d.Id()).ServiceTokenChangeOperation(update).Execute() + if err != nil { + diags = append(diags, diag.Diagnostic{Severity: 0, Summary: fmt.Sprintf("service token property update request error: %v [update payload: %v] (other updates will be successful if the payload is not shown)", equinix_errors.FormatFabricError(err), update)}) + continue + } + updateTimeout := d.Timeout(schema.TimeoutUpdate) - 30*time.Second - time.Since(start) + updateServiceToken, err := waitForStability(d.Id(), meta, d, ctx, updateTimeout) + if err != nil { + diags = append(diags, diag.Diagnostic{Severity: 0, Summary: fmt.Sprintf("service token property update completion timeout error: %v [update payload: %v] (other updates will be successful if the payload is not shown)", equinix_errors.FormatFabricError(err), update)}) + } else { + dbToken = updateServiceToken + } - return setServiceTokenMap(d, serviceToken) + } + d.SetId(dbToken.GetUuid()) + return append(diags, setServiceTokenMap(d, dbToken)...) } func resourceDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { @@ -115,7 +131,7 @@ func resourceDelete(ctx context.Context, d *schema.ResourceData, meta interface{ return diags } -func waitForStability(uuid string, meta interface{}, d *schema.ResourceData, ctx context.Context, tieout time.Duration) error { +func waitForStability(uuid string, meta interface{}, d *schema.ResourceData, ctx context.Context, timeout time.Duration) (*fabricv4.ServiceToken, error) { log.Printf("Waiting for service token to be created, uuid %s", uuid) stateConf := &retry.StateChangeConf{ Target: []string{ @@ -127,16 +143,27 @@ func waitForStability(uuid string, meta interface{}, d *schema.ResourceData, ctx if err != nil { return "", "", equinix_errors.FormatFabricError(err) } - return serviceToken, string(serviceToken.GetState()), nil + currentState := string(serviceToken.GetState()) + return serviceToken, currentState, nil }, - Timeout: tieout, + Timeout: timeout, Delay: 30 * time.Second, MinTimeout: 30 * time.Second, } - _, err := stateConf.WaitForStateContext(ctx) + inter, err := stateConf.WaitForStateContext(ctx) + var serviceToken *fabricv4.ServiceToken - return err + if err != nil { + log.Printf("[ERROR] Error while waiting for service token to go to INACTIVE state: %v", err) + return nil, err + } + + serviceToken, ok := inter.(*fabricv4.ServiceToken) + if !ok { + return nil, fmt.Errorf("expected *fabricv4.ServiceToken, but got %T", inter) + } + return serviceToken, err } func WaitForDeletion(uuid string, meta interface{}, d *schema.ResourceData, ctx context.Context, timeout time.Duration) error { diff --git a/internal/resources/fabric/service_token/resource_schema.go b/internal/resources/fabric/service_token/resource_schema.go index fe4bf0b02..66ba28192 100644 --- a/internal/resources/fabric/service_token/resource_schema.go +++ b/internal/resources/fabric/service_token/resource_schema.go @@ -181,7 +181,6 @@ func accessPointSelectorsSch() *schema.Resource { "port": { Type: schema.TypeSet, Optional: true, - Computed: true, Description: "Port Configuration", MaxItems: 1, Elem: portSch(), @@ -189,7 +188,6 @@ func accessPointSelectorsSch() *schema.Resource { "link_protocol": { Type: schema.TypeSet, Optional: true, - Computed: true, Description: "Link protocol Configuration", MaxItems: 1, Elem: linkProtocolSch(), @@ -204,7 +202,6 @@ func accessPointSelectorsSch() *schema.Resource { "interface": { Type: schema.TypeSet, Optional: true, - Computed: true, Description: "Virtual Device Interface Configuration", MaxItems: 1, Elem: interfaceSch(), @@ -374,8 +371,7 @@ func networkSch() *schema.Resource { Schema: map[string]*schema.Schema{ "uuid": { Type: schema.TypeString, - Optional: true, - Computed: true, + Required: true, Description: "Equinix-assigned Network identifier", }, "href": { @@ -385,25 +381,21 @@ func networkSch() *schema.Resource { }, "type": { Type: schema.TypeString, - Optional: true, Computed: true, Description: "Type of Network", }, "name": { Type: schema.TypeString, - Optional: true, Computed: true, Description: "Network Name", }, "scope": { Type: schema.TypeString, - Optional: true, Computed: true, Description: "Scope of Network", }, "location": { Type: schema.TypeSet, - Optional: true, Computed: true, Description: "Location", Elem: &schema.Resource{ diff --git a/internal/resources/fabric/service_token/resource_test.go b/internal/resources/fabric/service_token/resource_test.go index 09a7f4128..c00ca3129 100644 --- a/internal/resources/fabric/service_token/resource_test.go +++ b/internal/resources/fabric/service_token/resource_test.go @@ -157,7 +157,48 @@ func TestAccFabricZsidePortServiceToken_PNFV(t *testing.T) { }) } -func testAccFabricZsideVirtualDeviceServiceTokenConfig(serviceTokenName string, serviceTokenDescription string, virtualDeviceUuid string) string { +func TestAccFabricZsideNetworkServiceToken_PNFV(t *testing.T) { + connectionTestData := testing_helpers.GetFabricEnvConnectionTestData(t) + var networkUuid string + if len(connectionTestData) > 0 { + networkUuid = connectionTestData["pfcr"]["network"] + } + serviceTokenName, serviceTokenUpdatedName := "token_zwan_PNFV", "UP_Token_zwan_PNFV" + serviceTokenDescription, serviceTokenUpdatedDescription := "zside network token", "Updated zside network token" + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acceptance.TestAccPreCheck(t) }, + Providers: acceptance.TestAccProviders, + CheckDestroy: CheckServiceTokenDelete, + Steps: []resource.TestStep{ + { + Config: testAccFabricZsideNetworkServiceTokenConfig(serviceTokenName, serviceTokenDescription, networkUuid), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("equinix_fabric_service_token.test", "uuid"), + resource.TestCheckResourceAttr("equinix_fabric_service_token.test", "name", serviceTokenName), + resource.TestCheckResourceAttr("equinix_fabric_service_token.test", "type", "VC_TOKEN"), + resource.TestCheckResourceAttr("equinix_fabric_service_token.test", "description", serviceTokenDescription), + resource.TestCheckResourceAttr("equinix_fabric_service_token.test", "expiration_date_time", "2025-02-18T06:43:49.981Z"), + resource.TestCheckResourceAttr("equinix_fabric_service_token.test", "service_token_connection.0.z_side.0.access_point_selectors.0.network.0.uuid", networkUuid), + ), + ExpectNonEmptyPlan: true, + }, + { + Config: testAccFabricZsideNetworkServiceTokenConfig(serviceTokenUpdatedName, serviceTokenUpdatedDescription, networkUuid), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("equinix_fabric_service_token.test", "uuid"), + resource.TestCheckResourceAttr("equinix_fabric_service_token.test", "name", serviceTokenUpdatedName), + resource.TestCheckResourceAttr("equinix_fabric_service_token.test", "type", "VC_TOKEN"), + resource.TestCheckResourceAttr("equinix_fabric_service_token.test", "description", serviceTokenUpdatedDescription), + resource.TestCheckResourceAttr("equinix_fabric_service_token.test", "expiration_date_time", "2025-02-18T06:43:49.981Z"), + resource.TestCheckResourceAttr("equinix_fabric_service_token.test", "service_token_connection.0.z_side.0.access_point_selectors.0.network.0.uuid", networkUuid), + ), + ExpectNonEmptyPlan: true, + }, + }, + }) +} + +func testAccFabricAsidePortServiceTokenConfig(serviceTokenName string, serviceTokenDescription string, portUuid string) string { return fmt.Sprintf( `resource "equinix_fabric_service_token" "test"{ type = "VC_TOKEN" @@ -166,16 +207,16 @@ func testAccFabricZsideVirtualDeviceServiceTokenConfig(serviceTokenName string, expiration_date_time = "2025-01-18T06:43:49.981Z" service_token_connection { type = "EVPL_VC" - supported_bandwidths = [50, 200, 10000] - z_side { + bandwidth_limit = 1000 + a_side { access_point_selectors{ - type = "VD" - virtual_device{ - type = "EDGE" + type = "COLO" + port { uuid = "%s" } - interface{ - type = "NETWORK" + link_protocol { + type = "DOT1Q" + vlan_tag = "2987" } } } @@ -186,10 +227,10 @@ func testAccFabricZsideVirtualDeviceServiceTokenConfig(serviceTokenName string, } } - `, serviceTokenName, serviceTokenDescription, virtualDeviceUuid) + `, serviceTokenName, serviceTokenDescription, portUuid) } -func testAccFabricAsidePortServiceTokenConfig(serviceTokenName string, serviceTokenDescription string, portUuid string) string { +func testAccFabricZsidePortServiceTokenConfig(serviceTokenName string, serviceTokenDescription string, portUuid string) string { return fmt.Sprintf( `resource "equinix_fabric_service_token" "test"{ type = "VC_TOKEN" @@ -198,8 +239,8 @@ func testAccFabricAsidePortServiceTokenConfig(serviceTokenName string, serviceTo expiration_date_time = "2025-01-18T06:43:49.981Z" service_token_connection { type = "EVPL_VC" - bandwidth_limit = 1000 - a_side { + supported_bandwidths = [50, 200, 10000] + z_side { access_point_selectors{ type = "COLO" port { @@ -207,7 +248,7 @@ func testAccFabricAsidePortServiceTokenConfig(serviceTokenName string, serviceTo } link_protocol { type = "DOT1Q" - vlan_tag = "2987" + vlan_tag = "2087" } } } @@ -221,7 +262,7 @@ func testAccFabricAsidePortServiceTokenConfig(serviceTokenName string, serviceTo `, serviceTokenName, serviceTokenDescription, portUuid) } -func testAccFabricZsidePortServiceTokenConfig(serviceTokenName string, serviceTokenDescription string, portUuid string) string { +func testAccFabricZsideVirtualDeviceServiceTokenConfig(serviceTokenName string, serviceTokenDescription string, virtualDeviceUuid string) string { return fmt.Sprintf( `resource "equinix_fabric_service_token" "test"{ type = "VC_TOKEN" @@ -233,13 +274,13 @@ func testAccFabricZsidePortServiceTokenConfig(serviceTokenName string, serviceTo supported_bandwidths = [50, 200, 10000] z_side { access_point_selectors{ - type = "COLO" - port { + type = "VD" + virtual_device{ + type = "EDGE" uuid = "%s" } - link_protocol { - type = "DOT1Q" - vlan_tag = "2087" + interface{ + type = "NETWORK" } } } @@ -250,7 +291,34 @@ func testAccFabricZsidePortServiceTokenConfig(serviceTokenName string, serviceTo } } - `, serviceTokenName, serviceTokenDescription, portUuid) + `, serviceTokenName, serviceTokenDescription, virtualDeviceUuid) +} + +func testAccFabricZsideNetworkServiceTokenConfig(serviceTokenName string, serviceTokenDescription string, networkUuid string) string { + return fmt.Sprintf( + `resource "equinix_fabric_service_token" "test" { + type = "VC_TOKEN" + name = "%s" + description = "%s" + expiration_date_time = "2025-02-18T06:43:49.981Z" + service_token_connection { + type = "EVPLAN_VC" + supported_bandwidths = [50, 200, 10000] + z_side { + access_point_selectors{ + type = "NETWORK" + network { + uuid = "%s" + } + } + } + } + notifications { + type = "ALL" + emails = ["example@equinix.com", "test1@equinix.com"] + } + } + `, serviceTokenName, serviceTokenDescription, networkUuid) } func CheckServiceTokenDelete(s *terraform.State) error { diff --git a/templates/resources/fabric_service_token.md.tmpl b/templates/resources/fabric_service_token.md.tmpl index 6df858e27..3dd70bc8f 100644 --- a/templates/resources/fabric_service_token.md.tmpl +++ b/templates/resources/fabric_service_token.md.tmpl @@ -22,6 +22,9 @@ Aside Port Service Token Zside Port Service Token {{tffile "examples/resources/equinix_fabric_service_token/zside_colo_service_token.tf"}} +Zside Network Service Token +{{tffile "examples/resources/equinix_fabric_service_token/zside_network_service_token.tf"}} + Zside Virtual Device Service Token {{tffile "examples/resources/equinix_fabric_service_token/zside_vd_service_token.tf"}}