From 087abf56ff898e38169779a1e7482fe45df565a3 Mon Sep 17 00:00:00 2001 From: Tim Hogarty Date: Mon, 13 Jan 2025 12:04:58 -0800 Subject: [PATCH 01/13] Update Fabric Client config and update sdkv2 calls to it --- equinix/data_source_fabric_cloud_routers.go | 2 +- equinix/resource_fabric_cloud_router.go | 14 +++++----- equinix/resource_fabric_port.go | 4 +-- equinix/resource_fabric_routing_protocol.go | 14 +++++----- equinix/resource_fabric_service_profile.go | 16 +++++------ internal/config/config.go | 28 +++++++++++++++---- .../resources/fabric/cloud_router/sweeper.go | 2 +- .../fabric/connection/datasources.go | 2 +- .../resources/fabric/connection/resource.go | 18 ++++++------ .../resources/fabric/connection/sweeper.go | 2 +- .../connection_route_filter/datasources.go | 2 +- .../connection_route_filter/resource.go | 12 ++++---- .../fabric/marketplace/datasources.go | 2 +- .../resources/fabric/network/datasources.go | 2 +- internal/resources/fabric/network/resource.go | 14 +++++----- .../fabric/route_filter/datasources.go | 2 +- .../resources/fabric/route_filter/resource.go | 12 ++++---- .../resources/fabric/route_filter/sweeper.go | 2 +- .../fabric/route_filter_rule/datasources.go | 2 +- .../fabric/route_filter_rule/resource.go | 12 ++++---- .../fabric/service_token/datasources.go | 2 +- .../fabric/service_token/resource.go | 12 ++++---- 22 files changed, 97 insertions(+), 81 deletions(-) diff --git a/equinix/data_source_fabric_cloud_routers.go b/equinix/data_source_fabric_cloud_routers.go index d9d4a5fc9..bcaec2b7c 100644 --- a/equinix/data_source_fabric_cloud_routers.go +++ b/equinix/data_source_fabric_cloud_routers.go @@ -132,7 +132,7 @@ func dataSourceFabricGetCloudRoutersRead(ctx context.Context, d *schema.Resource } func resourceFabricCloudRoutersSearch(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - client := meta.(*config.Config).NewFabricClientForSDK(d) + client := meta.(*config.Config).NewFabricClientForSDK(ctx, d) cloudRouterSearchRequest := fabricv4.CloudRouterSearchRequest{} schemaFilters := d.Get("filter").([]interface{}) diff --git a/equinix/resource_fabric_cloud_router.go b/equinix/resource_fabric_cloud_router.go index de31c9774..9a621f0ef 100644 --- a/equinix/resource_fabric_cloud_router.go +++ b/equinix/resource_fabric_cloud_router.go @@ -274,7 +274,7 @@ func marketplaceSubscriptionCloudRouterTerraformToGo(marketplaceSubscriptionTerr return marketplaceSubscription } func resourceFabricCloudRouterCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - client := meta.(*config.Config).NewFabricClientForSDK(d) + client := meta.(*config.Config).NewFabricClientForSDK(ctx, d) createCloudRouterRequest := fabricv4.CloudRouterPostRequest{} @@ -329,7 +329,7 @@ func resourceFabricCloudRouterCreate(ctx context.Context, d *schema.ResourceData } func resourceFabricCloudRouterRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - client := meta.(*config.Config).NewFabricClientForSDK(d) + client := meta.(*config.Config).NewFabricClientForSDK(ctx, d) cloudRouter, _, err := client.CloudRoutersApi.GetCloudRouterByUuid(ctx, d.Id()).Execute() if err != nil { log.Printf("[WARN] Fabric Cloud Router %s not found , error %s", d.Id(), err) @@ -465,7 +465,7 @@ func getCloudRouterUpdateRequests(cr *fabricv4.CloudRouter, d *schema.ResourceDa } func resourceFabricCloudRouterUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - client := meta.(*config.Config).NewFabricClientForSDK(d) + client := meta.(*config.Config).NewFabricClientForSDK(ctx, d) start := time.Now() updateTimeout := d.Timeout(schema.TimeoutUpdate) - 30*time.Second - time.Since(start) dbCR, err := waitUntilCloudRouterIsProvisioned(d.Id(), meta, d, ctx, updateTimeout) @@ -505,7 +505,7 @@ func waitForCloudRouterUpdateCompletion(uuid string, meta interface{}, d *schema stateConf := &retry.StateChangeConf{ Target: []string{string(fabricv4.CLOUDROUTERACCESSPOINTSTATE_PROVISIONED)}, Refresh: func() (interface{}, string, error) { - client := meta.(*config.Config).NewFabricClientForSDK(d) + client := meta.(*config.Config).NewFabricClientForSDK(ctx, d) dbCR, _, err := client.CloudRoutersApi.GetCloudRouterByUuid(ctx, uuid).Execute() if err != nil { return "", "", equinix_errors.FormatFabricError(err) @@ -536,7 +536,7 @@ func waitUntilCloudRouterIsProvisioned(uuid string, meta interface{}, d *schema. string(fabricv4.CLOUDROUTERACCESSPOINTSTATE_PROVISIONED), }, Refresh: func() (interface{}, string, error) { - client := meta.(*config.Config).NewFabricClientForSDK(d) + client := meta.(*config.Config).NewFabricClientForSDK(ctx, d) dbCR, _, err := client.CloudRoutersApi.GetCloudRouterByUuid(ctx, uuid).Execute() if err != nil { return "", "", equinix_errors.FormatFabricError(err) @@ -559,7 +559,7 @@ func waitUntilCloudRouterIsProvisioned(uuid string, meta interface{}, d *schema. func resourceFabricCloudRouterDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { diags := diag.Diagnostics{} - client := meta.(*config.Config).NewFabricClientForSDK(d) + client := meta.(*config.Config).NewFabricClientForSDK(ctx, d) start := time.Now() _, err := client.CloudRoutersApi.DeleteCloudRouterByUuid(ctx, d.Id()).Execute() if err != nil { @@ -592,7 +592,7 @@ func WaitUntilCloudRouterDeprovisioned(uuid string, meta interface{}, d *schema. string(fabricv4.CLOUDROUTERACCESSPOINTSTATE_DEPROVISIONED), }, Refresh: func() (interface{}, string, error) { - client := meta.(*config.Config).NewFabricClientForSDK(d) + client := meta.(*config.Config).NewFabricClientForSDK(ctx, d) dbCR, _, err := client.CloudRoutersApi.GetCloudRouterByUuid(ctx, uuid).Execute() if err != nil { return "", "", equinix_errors.FormatFabricError(err) diff --git a/equinix/resource_fabric_port.go b/equinix/resource_fabric_port.go index 85146f93f..988d1e2b3 100644 --- a/equinix/resource_fabric_port.go +++ b/equinix/resource_fabric_port.go @@ -355,7 +355,7 @@ func portEncapsulationGoToTerraform(portEncapsulation *fabricv4.PortEncapsulatio } func resourceFabricPortRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - client := meta.(*config.Config).NewFabricClientForSDK(d) + client := meta.(*config.Config).NewFabricClientForSDK(ctx, d) port, _, err := client.PortsApi.GetPortByUuid(ctx, d.Id()).Execute() if err != nil { log.Printf("[WARN] Port %s not found , error %s", d.Id(), err) @@ -443,7 +443,7 @@ func resourceFabricPortGetByPortName(ctx context.Context, d *schema.ResourceData } }() - client := meta.(*config.Config).NewFabricClientForSDK(d) + client := meta.(*config.Config).NewFabricClientForSDK(ctx, d) portNameParam := d.Get("filters").(*schema.Set).List() portName := portName(portNameParam) ports, _, err := client.PortsApi.GetPorts(ctx).Name(portName).Execute() diff --git a/equinix/resource_fabric_routing_protocol.go b/equinix/resource_fabric_routing_protocol.go index 08b0ea36c..678faa3b3 100644 --- a/equinix/resource_fabric_routing_protocol.go +++ b/equinix/resource_fabric_routing_protocol.go @@ -340,7 +340,7 @@ func resourceFabricRoutingProtocol() *schema.Resource { } func resourceFabricRoutingProtocolRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - client := meta.(*config.Config).NewFabricClientForSDK(d) + client := meta.(*config.Config).NewFabricClientForSDK(ctx, d) log.Printf("[WARN] Routing Protocol Connection uuid: %s", d.Get("connection_uuid").(string)) fabricRoutingProtocolData, _, err := client.RoutingProtocolsApi.GetConnectionRoutingProtocolByUuid(ctx, d.Id(), d.Get("connection_uuid").(string)).Execute() if err != nil { @@ -357,7 +357,7 @@ func resourceFabricRoutingProtocolRead(ctx context.Context, d *schema.ResourceDa } func resourceFabricRoutingProtocolCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - client := meta.(*config.Config).NewFabricClientForSDK(d) + client := meta.(*config.Config).NewFabricClientForSDK(ctx, d) start := time.Now() type_ := d.Get("type").(string) @@ -384,7 +384,7 @@ func resourceFabricRoutingProtocolCreate(ctx context.Context, d *schema.Resource } func resourceFabricRoutingProtocolUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - client := meta.(*config.Config).NewFabricClientForSDK(d) + client := meta.(*config.Config).NewFabricClientForSDK(ctx, d) type_ := d.Get("type").(string) @@ -422,7 +422,7 @@ func resourceFabricRoutingProtocolUpdate(ctx context.Context, d *schema.Resource func resourceFabricRoutingProtocolDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { diags := diag.Diagnostics{} start := time.Now() - client := meta.(*config.Config).NewFabricClientForSDK(d) + client := meta.(*config.Config).NewFabricClientForSDK(ctx, d) _, _, err := client.RoutingProtocolsApi.DeleteConnectionRoutingProtocolByUuid(ctx, d.Id(), d.Get("connection_uuid").(string)).Execute() if err != nil { if genericError, ok := err.(*fabricv4.GenericOpenAPIError); ok { @@ -642,7 +642,7 @@ func waitUntilRoutingProtocolIsProvisioned(uuid string, connUuid string, meta in string(fabricv4.CONNECTIONSTATE_PROVISIONED), }, Refresh: func() (interface{}, string, error) { - client := meta.(*config.Config).NewFabricClientForSDK(d) + client := meta.(*config.Config).NewFabricClientForSDK(ctx, d) dbConn, _, err := client.RoutingProtocolsApi.GetConnectionRoutingProtocolByUuid(ctx, uuid, connUuid).Execute() if err != nil { return "", "", equinix_errors.FormatFabricError(err) @@ -680,7 +680,7 @@ func WaitUntilRoutingProtocolIsDeprovisioned(uuid string, connUuid string, meta strconv.Itoa(404), }, Refresh: func() (interface{}, string, error) { - client := meta.(*config.Config).NewFabricClientForSDK(d) + client := meta.(*config.Config).NewFabricClientForSDK(ctx, d) dbConn, resp, _ := client.RoutingProtocolsApi.GetConnectionRoutingProtocolByUuid(ctx, uuid, connUuid).Execute() // fixme: check for error code instead? // ignore error for Target @@ -701,7 +701,7 @@ func waitForRoutingProtocolUpdateCompletion(rpChangeUuid string, uuid string, co stateConf := &retry.StateChangeConf{ Target: []string{"COMPLETED"}, Refresh: func() (interface{}, string, error) { - client := meta.(*config.Config).NewFabricClientForSDK(d) + client := meta.(*config.Config).NewFabricClientForSDK(ctx, d) dbConn, _, err := client.RoutingProtocolsApi.GetConnectionRoutingProtocolsChangeByUuid(ctx, connUuid, uuid, rpChangeUuid).Execute() if err != nil { return "", "", equinix_errors.FormatFabricError(err) diff --git a/equinix/resource_fabric_service_profile.go b/equinix/resource_fabric_service_profile.go index 288b8c147..1806b4c8e 100644 --- a/equinix/resource_fabric_service_profile.go +++ b/equinix/resource_fabric_service_profile.go @@ -554,7 +554,7 @@ Additional documentation: } func resourceFabricServiceProfileRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - client := meta.(*config.Config).NewFabricClientForSDK(d) + client := meta.(*config.Config).NewFabricClientForSDK(ctx, d) serviceProfile, _, err := client.ServiceProfilesApi.GetServiceProfileByUuid(ctx, d.Id()).Execute() if err != nil { if !strings.Contains(err.Error(), "500") { @@ -567,7 +567,7 @@ func resourceFabricServiceProfileRead(ctx context.Context, d *schema.ResourceDat } func resourceFabricServiceProfileCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - client := meta.(*config.Config).NewFabricClientForSDK(d) + client := meta.(*config.Config).NewFabricClientForSDK(ctx, d) createRequest := getServiceProfileRequestPayload(d) sp, _, err := client.ServiceProfilesApi.CreateServiceProfile(ctx).ServiceProfileRequest(createRequest).Execute() @@ -647,7 +647,7 @@ func getServiceProfileRequestPayload(d *schema.ResourceData) fabricv4.ServicePro } func resourceFabricServiceProfileUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - client := meta.(*config.Config).NewFabricClientForSDK(d) + client := meta.(*config.Config).NewFabricClientForSDK(ctx, d) uuid := d.Id() updateRequest := getServiceProfileRequestPayload(d) @@ -685,7 +685,7 @@ func waitForServiceProfileUpdateCompletion(uuid string, meta interface{}, d *sch stateConf := &retry.StateChangeConf{ Target: []string{"COMPLETED"}, Refresh: func() (interface{}, string, error) { - client := meta.(*config.Config).NewFabricClientForSDK(d) + client := meta.(*config.Config).NewFabricClientForSDK(ctx, d) dbServiceProfile, _, err := client.ServiceProfilesApi.GetServiceProfileByUuid(ctx, uuid).Execute() if err != nil { return "", "", equinix_errors.FormatFabricError(err) @@ -713,7 +713,7 @@ func waitForActiveServiceProfileAndPopulateETag(uuid string, meta interface{}, d stateConf := &retry.StateChangeConf{ Target: []string{string(fabricv4.SERVICEPROFILESTATEENUM_ACTIVE)}, Refresh: func() (interface{}, string, error) { - client := meta.(*config.Config).NewFabricClientForSDK(d) + client := meta.(*config.Config).NewFabricClientForSDK(ctx, d) dbServiceProfile, res, err := client.ServiceProfilesApi.GetServiceProfileByUuid(ctx, uuid).Execute() if err != nil { return nil, "", equinix_errors.FormatFabricError(err) @@ -745,7 +745,7 @@ func waitForActiveServiceProfileAndPopulateETag(uuid string, meta interface{}, d func resourceFabricServiceProfileDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { diags := diag.Diagnostics{} - client := meta.(*config.Config).NewFabricClientForSDK(d) + client := meta.(*config.Config).NewFabricClientForSDK(ctx, d) uuid := d.Id() if uuid == "" { return diag.Errorf("No uuid found for Service Profile Deletion %v ", uuid) @@ -771,7 +771,7 @@ func WaitAndCheckServiceProfileDeleted(uuid string, meta interface{}, d *schema. stateConf := &retry.StateChangeConf{ Target: []string{string(fabricv4.SERVICEPROFILESTATEENUM_DELETED)}, Refresh: func() (interface{}, string, error) { - client := meta.(*config.Config).NewFabricClientForSDK(d) + client := meta.(*config.Config).NewFabricClientForSDK(ctx, d) dbConn, _, err := client.ServiceProfilesApi.GetServiceProfileByUuid(ctx, uuid).Execute() if err != nil { return "", "", equinix_errors.FormatFabricError(err) @@ -851,7 +851,7 @@ func fabricServiceProfileMap(serviceProfile *fabricv4.ServiceProfile) map[string } func resourceServiceProfilesSearchRequest(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - client := meta.(*config.Config).NewFabricClientForSDK(d) + client := meta.(*config.Config).NewFabricClientForSDK(ctx, d) serviceProfilesSearchRequest := fabricv4.ServiceProfileSearchRequest{} andFilters := false diff --git a/internal/config/config.go b/internal/config/config.go index 59d002bf9..29ee7e6ca 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -119,8 +119,8 @@ func (c *Config) Load(ctx context.Context) error { // NewFabricClientForSDK returns a terraform sdkv2 plugin compatible // equinix-sdk-go/fabricv4 client to be used to access Fabric's V4 APIs -func (c *Config) NewFabricClientForSDK(d *schema.ResourceData) *fabricv4.APIClient { - client := c.newFabricClient() +func (c *Config) NewFabricClientForSDK(ctx context.Context, d *schema.ResourceData) *fabricv4.APIClient { + client := c.newFabricClient(ctx) baseUserAgent := c.tfSdkUserAgent(client.GetConfig().UserAgent) client.GetConfig().UserAgent = generateModuleUserAgentString(d, baseUserAgent) @@ -130,19 +130,35 @@ func (c *Config) NewFabricClientForSDK(d *schema.ResourceData) *fabricv4.APIClie // Shim for Fabric tests. // Deprecated: when the acceptance package starts to contain API clients for testing/cleanup this will move with them -func (c *Config) NewFabricClientForTesting() *fabricv4.APIClient { - client := c.newFabricClient() +func (c *Config) NewFabricClientForTesting(ctx context.Context) *fabricv4.APIClient { + client := c.newFabricClient(ctx) client.GetConfig().UserAgent = fmt.Sprintf("tf-acceptance-tests %v", client.GetConfig().UserAgent) return client } +func (c *Config) NewFabricClientForFramework(ctx context.Context, meta tfsdk.Config) *fabricv4.APIClient { + client := c.newFabricClient(ctx) + + baseUserAgent := c.tfFrameworkUserAgent(client.GetConfig().UserAgent) + client.GetConfig().UserAgent = generateFwModuleUserAgentString(ctx, meta, baseUserAgent) + + return client +} + // newFabricClient returns the base fabricv4 client that is then used for either the sdkv2 or framework // implementations of the Terraform Provider with exported Methods -func (c *Config) newFabricClient() *fabricv4.APIClient { +func (c *Config) newFabricClient(ctx context.Context) *fabricv4.APIClient { + //nolint:staticcheck // We should move to subsystem loggers, but that is a much bigger change + authConfig := oauth2.Config{ + ClientID: c.ClientID, + ClientSecret: c.ClientSecret, + BaseURL: c.BaseURL, + } + authClient := authConfig.New(ctx) //nolint:staticcheck // We should move to subsystem loggers, but that is a much bigger change - transport := logging.NewTransport("Equinix Fabric (fabricv4)", c.authClient.Transport) + transport := logging.NewTransport("Equinix Fabric (fabricv4)", authClient.Transport) retryClient := retryablehttp.NewClient() retryClient.HTTPClient.Transport = transport diff --git a/internal/resources/fabric/cloud_router/sweeper.go b/internal/resources/fabric/cloud_router/sweeper.go index c97f238d1..a96648259 100644 --- a/internal/resources/fabric/cloud_router/sweeper.go +++ b/internal/resources/fabric/cloud_router/sweeper.go @@ -34,7 +34,7 @@ func testSweepCloudRouters(region string) error { log.Printf("Error loading meta: %v", err) return err } - fabric := meta.NewFabricClientForTesting() + fabric := meta.NewFabricClientForTesting(ctx) equinixStatus := "/state" equalOperator := string(fabricv4.EXPRESSIONOPERATOR_EQUAL) diff --git a/internal/resources/fabric/connection/datasources.go b/internal/resources/fabric/connection/datasources.go index 914b104cc..790e18225 100644 --- a/internal/resources/fabric/connection/datasources.go +++ b/internal/resources/fabric/connection/datasources.go @@ -49,7 +49,7 @@ func dataSourceFabricConnectionSearch(ctx context.Context, d *schema.ResourceDat } func resourceFabricConnectionSearch(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - client := meta.(*config.Config).NewFabricClientForSDK(d) + client := meta.(*config.Config).NewFabricClientForSDK(ctx, d) connectionSearchRequest := fabricv4.SearchRequest{} schemaFilters := d.Get("filter").([]interface{}) diff --git a/internal/resources/fabric/connection/resource.go b/internal/resources/fabric/connection/resource.go index 7a1d46c6b..2f094a5b4 100644 --- a/internal/resources/fabric/connection/resource.go +++ b/internal/resources/fabric/connection/resource.go @@ -39,7 +39,7 @@ func Resource() *schema.Resource { } func resourceFabricConnectionCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - client := meta.(*config.Config).NewFabricClientForSDK(d) + client := meta.(*config.Config).NewFabricClientForSDK(ctx, d) createConnectionRequest := fabricv4.ConnectionPostRequest{} @@ -129,7 +129,7 @@ func resourceFabricConnectionCreate(ctx context.Context, d *schema.ResourceData, } func resourceFabricConnectionRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - client := meta.(*config.Config).NewFabricClientForSDK(d) + client := meta.(*config.Config).NewFabricClientForSDK(ctx, d) conn, _, err := client.ConnectionsApi.GetConnectionByUuid(ctx, d.Id()).Execute() if err != nil { log.Printf("[WARN] Connection %s not found , error %s", d.Id(), err) @@ -143,7 +143,7 @@ func resourceFabricConnectionRead(ctx context.Context, d *schema.ResourceData, m } func resourceFabricConnectionUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - client := meta.(*config.Config).NewFabricClientForSDK(d) + client := meta.(*config.Config).NewFabricClientForSDK(ctx, d) start := time.Now() updateTimeout := d.Timeout(schema.TimeoutUpdate) - 30*time.Second - time.Since(start) dbConn, err := verifyConnectionCreated(d.Id(), meta, d, ctx, updateTimeout) @@ -197,7 +197,7 @@ func waitForConnectionUpdateCompletion(uuid string, meta interface{}, d *schema. stateConf := &retry.StateChangeConf{ Target: []string{"COMPLETED", "SUBMITTED_FOR_APPROVAL"}, Refresh: func() (interface{}, string, error) { - client := meta.(*config.Config).NewFabricClientForSDK(d) + client := meta.(*config.Config).NewFabricClientForSDK(ctx, d) dbConn, _, err := client.ConnectionsApi.GetConnectionByUuid(ctx, uuid).Execute() if err != nil { return "", "", equinix_errors.FormatFabricError(err) @@ -236,7 +236,7 @@ func waitUntilConnectionIsCreated(uuid string, meta interface{}, d *schema.Resou string(fabricv4.CONNECTIONSTATE_ACTIVE), }, Refresh: func() (interface{}, string, error) { - client := meta.(*config.Config).NewFabricClientForSDK(d) + client := meta.(*config.Config).NewFabricClientForSDK(ctx, d) dbConn, _, err := client.ConnectionsApi.GetConnectionByUuid(ctx, uuid).Execute() if err != nil { return "", "", equinix_errors.FormatFabricError(err) @@ -264,7 +264,7 @@ func waitForConnectionProviderStatusChange(uuid string, meta interface{}, d *sch string(fabricv4.PROVIDERSTATUS_PROVISIONED), }, Refresh: func() (interface{}, string, error) { - client := meta.(*config.Config).NewFabricClientForSDK(d) + client := meta.(*config.Config).NewFabricClientForSDK(ctx, d) dbConn, _, err := client.ConnectionsApi.GetConnectionByUuid(ctx, uuid).Execute() if err != nil { return "", "", equinix_errors.FormatFabricError(err) @@ -296,7 +296,7 @@ func verifyConnectionCreated(uuid string, meta interface{}, d *schema.ResourceDa string(fabricv4.CONNECTIONSTATE_PENDING), }, Refresh: func() (interface{}, string, error) { - client := meta.(*config.Config).NewFabricClientForSDK(d) + client := meta.(*config.Config).NewFabricClientForSDK(ctx, d) dbConn, _, err := client.ConnectionsApi.GetConnectionByUuid(ctx, uuid).Execute() if err != nil { return "", "", equinix_errors.FormatFabricError(err) @@ -319,7 +319,7 @@ func verifyConnectionCreated(uuid string, meta interface{}, d *schema.ResourceDa func resourceFabricConnectionDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { diags := diag.Diagnostics{} - client := meta.(*config.Config).NewFabricClientForSDK(d) + client := meta.(*config.Config).NewFabricClientForSDK(ctx, d) start := time.Now() _, _, err := client.ConnectionsApi.DeleteConnectionByUuid(ctx, d.Id()).Execute() if err != nil { @@ -354,7 +354,7 @@ func WaitUntilConnectionDeprovisioned(uuid string, meta interface{}, d *schema.R string(fabricv4.CONNECTIONSTATE_DEPROVISIONED), }, Refresh: func() (interface{}, string, error) { - client := meta.(*config.Config).NewFabricClientForSDK(d) + client := meta.(*config.Config).NewFabricClientForSDK(ctx, d) dbConn, _, err := client.ConnectionsApi.GetConnectionByUuid(ctx, uuid).Execute() if err != nil { return "", "", equinix_errors.FormatFabricError(err) diff --git a/internal/resources/fabric/connection/sweeper.go b/internal/resources/fabric/connection/sweeper.go index 8757e66bd..e0d4648bc 100644 --- a/internal/resources/fabric/connection/sweeper.go +++ b/internal/resources/fabric/connection/sweeper.go @@ -34,7 +34,7 @@ func testSweepConnections(region string) error { log.Printf("Error loading meta: %v", err) return err } - fabric := meta.NewFabricClientForTesting() + fabric := meta.NewFabricClientForTesting(ctx) name := fabricv4.SEARCHFIELDNAME_NAME equinixStatus := fabricv4.SEARCHFIELDNAME_OPERATION_EQUINIX_STATUS diff --git a/internal/resources/fabric/connection_route_filter/datasources.go b/internal/resources/fabric/connection_route_filter/datasources.go index e8eaeb309..c0914e5db 100644 --- a/internal/resources/fabric/connection_route_filter/datasources.go +++ b/internal/resources/fabric/connection_route_filter/datasources.go @@ -42,7 +42,7 @@ Additional Documentation: } func dataSourceGetAllFilters(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - client := meta.(*config.Config).NewFabricClientForSDK(d) + client := meta.(*config.Config).NewFabricClientForSDK(ctx, d) connectionId := d.Get("connection_id").(string) connectionRouteFilters, _, err := client.RouteFiltersApi.GetConnectionRouteFilters(ctx, connectionId).Execute() if err != nil { diff --git a/internal/resources/fabric/connection_route_filter/resource.go b/internal/resources/fabric/connection_route_filter/resource.go index b3a0d9800..c0e12c788 100644 --- a/internal/resources/fabric/connection_route_filter/resource.go +++ b/internal/resources/fabric/connection_route_filter/resource.go @@ -41,7 +41,7 @@ Additional Documentation: } func resourceRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - client := meta.(*config.Config).NewFabricClientForSDK(d) + client := meta.(*config.Config).NewFabricClientForSDK(ctx, d) connectionId := d.Get("connection_id").(string) connectionRouteFilter, _, err := client.RouteFiltersApi.GetConnectionRouteFilterByUuid(ctx, d.Id(), connectionId).Execute() if err != nil { @@ -56,7 +56,7 @@ func resourceRead(ctx context.Context, d *schema.ResourceData, meta interface{}) } func resourceCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - client := meta.(*config.Config).NewFabricClientForSDK(d) + client := meta.(*config.Config).NewFabricClientForSDK(ctx, d) connectionId := d.Get("connection_id").(string) routeFilterId := d.Get("route_filter_id").(string) direction := d.Get("direction").(string) @@ -87,7 +87,7 @@ 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) + client := meta.(*config.Config).NewFabricClientForSDK(ctx, d) connectionId := d.Get("connection_id").(string) routeFilterId := d.Get("route_filter_id").(string) oldDirection, newDirection := d.GetChange("direction") @@ -117,7 +117,7 @@ func resourceUpdate(ctx context.Context, d *schema.ResourceData, meta interface{ func resourceDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { diags := diag.Diagnostics{} - client := meta.(*config.Config).NewFabricClientForSDK(d) + client := meta.(*config.Config).NewFabricClientForSDK(ctx, d) connectionId := d.Get("connection_id").(string) start := time.Now() @@ -152,7 +152,7 @@ func waitForStability(connectionId, routeFilterId string, meta interface{}, d *s string(fabricv4.CONNECTIONROUTEAGGREGATIONDATAATTACHMENTSTATUS_PENDING_BGP_CONFIGURATION), }, Refresh: func() (interface{}, string, error) { - client := meta.(*config.Config).NewFabricClientForSDK(d) + client := meta.(*config.Config).NewFabricClientForSDK(ctx, d) connectionRouteFilter, _, err := client.RouteFiltersApi.GetConnectionRouteFilterByUuid(ctx, routeFilterId, connectionId).Execute() if err != nil { return "", "", equinix_errors.FormatFabricError(err) @@ -181,7 +181,7 @@ func WaitForDeletion(connectionId, routeFilterId string, meta interface{}, d *sc string(fabricv4.CONNECTIONROUTEAGGREGATIONDATAATTACHMENTSTATUS_DETACHED), }, Refresh: func() (interface{}, string, error) { - client := meta.(*config.Config).NewFabricClientForSDK(d) + client := meta.(*config.Config).NewFabricClientForSDK(ctx, d) connectionRouteFilter, body, err := client.RouteFiltersApi.GetConnectionRouteFilterByUuid(ctx, routeFilterId, connectionId).Execute() if err != nil { if body.StatusCode >= 400 && body.StatusCode <= 499 { diff --git a/internal/resources/fabric/marketplace/datasources.go b/internal/resources/fabric/marketplace/datasources.go index 820de733d..5e4a41ed0 100644 --- a/internal/resources/fabric/marketplace/datasources.go +++ b/internal/resources/fabric/marketplace/datasources.go @@ -26,7 +26,7 @@ func dataSourceFabricMarketplaceSubscriptionRead(ctx context.Context, d *schema. } func fabricMarketplaceSubscriptionRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - client := meta.(*config.Config).NewFabricClientForSDK(d) + client := meta.(*config.Config).NewFabricClientForSDK(ctx, d) subscription, _, err := client.MarketplaceSubscriptionsApi.GetSubscriptionById(ctx, d.Id()).Execute() if err != nil { log.Printf("[WARN] Subscription %s not found , error %s", d.Id(), err) diff --git a/internal/resources/fabric/network/datasources.go b/internal/resources/fabric/network/datasources.go index 28f6e4fd7..28c967174 100644 --- a/internal/resources/fabric/network/datasources.go +++ b/internal/resources/fabric/network/datasources.go @@ -51,7 +51,7 @@ func dataSourceFabricNetworkSearch(ctx context.Context, d *schema.ResourceData, } func resourceFabricNetworkSearch(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - client := meta.(*config.Config).NewFabricClientForSDK(d) + client := meta.(*config.Config).NewFabricClientForSDK(ctx, d) networkSearchRequest := fabricv4.NetworkSearchRequest{} schemaFilters := d.Get("filter").([]interface{}) diff --git a/internal/resources/fabric/network/resource.go b/internal/resources/fabric/network/resource.go index de13788ac..de9811d9d 100644 --- a/internal/resources/fabric/network/resource.go +++ b/internal/resources/fabric/network/resource.go @@ -42,7 +42,7 @@ Additional documentation: } func resourceFabricNetworkCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - client := meta.(*config.Config).NewFabricClientForSDK(d) + client := meta.(*config.Config).NewFabricClientForSDK(ctx, d) createRequest := fabricv4.NetworkPostRequest{} createRequest.SetName(d.Get("name").(string)) @@ -81,7 +81,7 @@ func resourceFabricNetworkCreate(ctx context.Context, d *schema.ResourceData, me } func resourceFabricNetworkRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - client := meta.(*config.Config).NewFabricClientForSDK(d) + client := meta.(*config.Config).NewFabricClientForSDK(ctx, d) fabricNetwork, _, err := client.NetworksApi.GetNetworkByUuid(ctx, d.Id()).Execute() if err != nil { return diag.FromErr(equinix_errors.FormatFabricError(err)) @@ -91,7 +91,7 @@ func resourceFabricNetworkRead(ctx context.Context, d *schema.ResourceData, meta } func resourceFabricNetworkUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - client := meta.(*config.Config).NewFabricClientForSDK(d) + client := meta.(*config.Config).NewFabricClientForSDK(ctx, d) start := time.Now() updateTimeout := d.Timeout(schema.TimeoutUpdate) - 30*time.Second - time.Since(start) dbConn, waitUntilNetworkProvisionedErr := waitUntilFabricNetworkIsProvisioned(d.Id(), meta, d, ctx, updateTimeout) @@ -124,7 +124,7 @@ func waitForFabricNetworkUpdateCompletion(uuid string, meta interface{}, d *sche stateConf := &retry.StateChangeConf{ Target: []string{string(fabricv4.NETWORKEQUINIXSTATUS_PROVISIONED)}, Refresh: func() (interface{}, string, error) { - client := meta.(*config.Config).NewFabricClientForSDK(d) + client := meta.(*config.Config).NewFabricClientForSDK(ctx, d) dbConn, _, err := client.NetworksApi.GetNetworkByUuid(ctx, uuid).Execute() if err != nil { return "", "", equinix_errors.FormatFabricError(err) @@ -155,7 +155,7 @@ func waitUntilFabricNetworkIsProvisioned(uuid string, meta interface{}, d *schem string(fabricv4.NETWORKEQUINIXSTATUS_PROVISIONED), }, Refresh: func() (interface{}, string, error) { - client := meta.(*config.Config).NewFabricClientForSDK(d) + client := meta.(*config.Config).NewFabricClientForSDK(ctx, d) dbConn, _, err := client.NetworksApi.GetNetworkByUuid(ctx, uuid).Execute() if err != nil { return "", "", equinix_errors.FormatFabricError(err) @@ -178,7 +178,7 @@ func waitUntilFabricNetworkIsProvisioned(uuid string, meta interface{}, d *schem func resourceFabricNetworkDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { diags := diag.Diagnostics{} - client := meta.(*config.Config).NewFabricClientForSDK(d) + client := meta.(*config.Config).NewFabricClientForSDK(ctx, d) start := time.Now() _, _, err := client.NetworksApi.DeleteNetworkByUuid(ctx, d.Id()).Execute() if err != nil { @@ -211,7 +211,7 @@ func WaitUntilFabricNetworkDeprovisioned(uuid string, meta interface{}, d *schem string(fabricv4.NETWORKEQUINIXSTATUS_DEPROVISIONED), }, Refresh: func() (interface{}, string, error) { - client := meta.(*config.Config).NewFabricClientForSDK(d) + client := meta.(*config.Config).NewFabricClientForSDK(ctx, d) dbConn, _, err := client.NetworksApi.GetNetworkByUuid(ctx, uuid).Execute() if err != nil { return "", "", equinix_errors.FormatFabricError(err) diff --git a/internal/resources/fabric/route_filter/datasources.go b/internal/resources/fabric/route_filter/datasources.go index b0602fdb2..66dbf27a0 100644 --- a/internal/resources/fabric/route_filter/datasources.go +++ b/internal/resources/fabric/route_filter/datasources.go @@ -42,7 +42,7 @@ Additional Documentation: } func dataSourceSearch(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - client := meta.(*config.Config).NewFabricClientForSDK(d) + client := meta.(*config.Config).NewFabricClientForSDK(ctx, d) searchRequest := buildSearchRequest(d) routeFilters, _, err := client.RouteFiltersApi.SearchRouteFilters(ctx).RouteFiltersSearchBase(searchRequest).Execute() diff --git a/internal/resources/fabric/route_filter/resource.go b/internal/resources/fabric/route_filter/resource.go index 60e3f291f..d662280c8 100644 --- a/internal/resources/fabric/route_filter/resource.go +++ b/internal/resources/fabric/route_filter/resource.go @@ -41,7 +41,7 @@ Additional Documentation: } func resourceRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - client := meta.(*config.Config).NewFabricClientForSDK(d) + client := meta.(*config.Config).NewFabricClientForSDK(ctx, d) routeFilter, _, err := client.RouteFiltersApi.GetRouteFilterByUuid(ctx, d.Id()).Execute() if err != nil { log.Printf("[WARN] Route Filter %s not found , error %s", d.Id(), err) @@ -55,7 +55,7 @@ func resourceRead(ctx context.Context, d *schema.ResourceData, meta interface{}) } func resourceCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - client := meta.(*config.Config).NewFabricClientForSDK(d) + client := meta.(*config.Config).NewFabricClientForSDK(ctx, d) createRequest := buildCreateRequest(d) start := time.Now() @@ -74,7 +74,7 @@ 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) + client := meta.(*config.Config).NewFabricClientForSDK(ctx, d) updateRequest := buildUpdateRequest(d) start := time.Now() @@ -93,7 +93,7 @@ func resourceUpdate(ctx context.Context, d *schema.ResourceData, meta interface{ func resourceDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { diags := diag.Diagnostics{} - client := meta.(*config.Config).NewFabricClientForSDK(d) + client := meta.(*config.Config).NewFabricClientForSDK(ctx, d) start := time.Now() _, _, err := client.RouteFiltersApi.DeleteRouteFilterByUuid(ctx, d.Id()).Execute() @@ -127,7 +127,7 @@ func waitForStability(uuid string, meta interface{}, d *schema.ResourceData, ctx string(fabricv4.ROUTEFILTERSTATE_PROVISIONED), }, Refresh: func() (interface{}, string, error) { - client := meta.(*config.Config).NewFabricClientForSDK(d) + client := meta.(*config.Config).NewFabricClientForSDK(ctx, d) routeFilter, _, err := client.RouteFiltersApi.GetRouteFilterByUuid(ctx, uuid).Execute() if err != nil { return "", "", equinix_errors.FormatFabricError(err) @@ -155,7 +155,7 @@ func WaitForDeletion(uuid string, meta interface{}, d *schema.ResourceData, ctx string(fabricv4.ROUTEFILTERSTATE_DEPROVISIONED), }, Refresh: func() (interface{}, string, error) { - client := meta.(*config.Config).NewFabricClientForSDK(d) + client := meta.(*config.Config).NewFabricClientForSDK(ctx, d) routeFilter, body, err := client.RouteFiltersApi.GetRouteFilterByUuid(ctx, uuid).Execute() if err != nil { if body.StatusCode >= 400 && body.StatusCode <= 499 { diff --git a/internal/resources/fabric/route_filter/sweeper.go b/internal/resources/fabric/route_filter/sweeper.go index 26ab887f5..c88773b02 100644 --- a/internal/resources/fabric/route_filter/sweeper.go +++ b/internal/resources/fabric/route_filter/sweeper.go @@ -35,7 +35,7 @@ func testSweepRouteFilters(region string) error { if configLoadErr != nil { return fmt.Errorf("error loading configuration for sweeping Route Filters: %s", err) } - fabric := meta.NewFabricClientForTesting() + fabric := meta.NewFabricClientForTesting(ctx) name := fabricv4.ROUTEFILTERSSEARCHFILTERITEMPROPERTY_NAME equinixState := fabricv4.ROUTEFILTERSSEARCHFILTERITEMPROPERTY_STATE diff --git a/internal/resources/fabric/route_filter_rule/datasources.go b/internal/resources/fabric/route_filter_rule/datasources.go index 2e03110c9..9b7ba2eac 100644 --- a/internal/resources/fabric/route_filter_rule/datasources.go +++ b/internal/resources/fabric/route_filter_rule/datasources.go @@ -42,7 +42,7 @@ Additional Documentation: } func dataSourceGetAllRules(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - client := meta.(*config.Config).NewFabricClientForSDK(d) + client := meta.(*config.Config).NewFabricClientForSDK(ctx, d) routeFilterId := d.Get("route_filter_id").(string) getRouteFilterRulesRequest := client.RouteFilterRulesApi.GetRouteFilterRules(ctx, routeFilterId) diff --git a/internal/resources/fabric/route_filter_rule/resource.go b/internal/resources/fabric/route_filter_rule/resource.go index d87c6cc77..fa3e6a3ac 100644 --- a/internal/resources/fabric/route_filter_rule/resource.go +++ b/internal/resources/fabric/route_filter_rule/resource.go @@ -41,7 +41,7 @@ Additional Documentation: } func resourceRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - client := meta.(*config.Config).NewFabricClientForSDK(d) + client := meta.(*config.Config).NewFabricClientForSDK(ctx, d) routeFilterId := d.Get("route_filter_id").(string) routeFilterRule, _, err := client.RouteFilterRulesApi.GetRouteFilterRuleByUuid(ctx, routeFilterId, d.Id()).Execute() if err != nil { @@ -56,7 +56,7 @@ func resourceRead(ctx context.Context, d *schema.ResourceData, meta interface{}) } func resourceCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - client := meta.(*config.Config).NewFabricClientForSDK(d) + client := meta.(*config.Config).NewFabricClientForSDK(ctx, d) routeFilterId := d.Get("route_filter_id").(string) createRequest := buildCreateRequest(d) @@ -80,7 +80,7 @@ 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) + client := meta.(*config.Config).NewFabricClientForSDK(ctx, d) routeFilterId := d.Get("route_filter_id").(string) updateRequest := buildUpdateRequest(d) @@ -100,7 +100,7 @@ func resourceUpdate(ctx context.Context, d *schema.ResourceData, meta interface{ func resourceDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { diags := diag.Diagnostics{} - client := meta.(*config.Config).NewFabricClientForSDK(d) + client := meta.(*config.Config).NewFabricClientForSDK(ctx, d) routeFilterId := d.Get("route_filter_id").(string) start := time.Now() @@ -135,7 +135,7 @@ func waitForStability(routeFilterId, ruleId string, meta interface{}, d *schema. string(fabricv4.ROUTEFILTERRULESTATE_PROVISIONED), }, Refresh: func() (interface{}, string, error) { - client := meta.(*config.Config).NewFabricClientForSDK(d) + client := meta.(*config.Config).NewFabricClientForSDK(ctx, d) routeFilterRule, _, err := client.RouteFilterRulesApi.GetRouteFilterRuleByUuid(ctx, routeFilterId, ruleId).Execute() if err != nil { return "", "", equinix_errors.FormatFabricError(err) @@ -163,7 +163,7 @@ func WaitForDeletion(routeFilterId, ruleId string, meta interface{}, d *schema.R string(fabricv4.ROUTEFILTERRULESTATE_DEPROVISIONED), }, Refresh: func() (interface{}, string, error) { - client := meta.(*config.Config).NewFabricClientForSDK(d) + client := meta.(*config.Config).NewFabricClientForSDK(ctx, d) routeFilterRule, body, err := client.RouteFilterRulesApi.GetRouteFilterRuleByUuid(ctx, routeFilterId, ruleId).Execute() if err != nil { if body != nil && body.StatusCode >= 400 && body.StatusCode <= 499 { diff --git a/internal/resources/fabric/service_token/datasources.go b/internal/resources/fabric/service_token/datasources.go index 92241fcd5..8932035b4 100644 --- a/internal/resources/fabric/service_token/datasources.go +++ b/internal/resources/fabric/service_token/datasources.go @@ -41,7 +41,7 @@ Additional documentation: } func dataSourceSearch(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - client := meta.(*config.Config).NewFabricClientForSDK(d) + client := meta.(*config.Config).NewFabricClientForSDK(ctx, d) searchRequest := buildSearchRequest(d) serviceTokens, _, err := client.ServiceTokensApi.SearchServiceTokens(ctx).ServiceTokenSearchRequest(searchRequest).Execute() diff --git a/internal/resources/fabric/service_token/resource.go b/internal/resources/fabric/service_token/resource.go index 7bfc90b28..9c509c840 100644 --- a/internal/resources/fabric/service_token/resource.go +++ b/internal/resources/fabric/service_token/resource.go @@ -37,7 +37,7 @@ func Resource() *schema.Resource { } func resourceRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - client := meta.(*config.Config).NewFabricClientForSDK(d) + client := meta.(*config.Config).NewFabricClientForSDK(ctx, d) serviceToken, _, err := client.ServiceTokensApi.GetServiceTokenByUuid(ctx, d.Id()).Execute() if err != nil { log.Printf("[WARN] Service Token %s not found , error %s", d.Id(), err) @@ -51,7 +51,7 @@ func resourceRead(ctx context.Context, d *schema.ResourceData, meta interface{}) } func resourceCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - client := meta.(*config.Config).NewFabricClientForSDK(d) + client := meta.(*config.Config).NewFabricClientForSDK(ctx, d) createRequest := buildCreateRequest(d) start := time.Now() @@ -74,7 +74,7 @@ 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) + client := meta.(*config.Config).NewFabricClientForSDK(ctx, d) start := time.Now() updateTimeout := d.Timeout(schema.TimeoutUpdate) - 30*time.Second - time.Since(start) dbToken, err := waitForStability(d.Id(), meta, d, ctx, updateTimeout) @@ -108,7 +108,7 @@ func resourceUpdate(ctx context.Context, d *schema.ResourceData, meta interface{ func resourceDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { diags := diag.Diagnostics{} - client := meta.(*config.Config).NewFabricClientForSDK(d) + client := meta.(*config.Config).NewFabricClientForSDK(ctx, d) start := time.Now() _, _, err := client.ServiceTokensApi.DeleteServiceTokenByUuid(ctx, d.Id()).Execute() @@ -138,7 +138,7 @@ func waitForStability(uuid string, meta interface{}, d *schema.ResourceData, ctx string(fabricv4.SERVICETOKENSTATE_INACTIVE), }, Refresh: func() (interface{}, string, error) { - client := meta.(*config.Config).NewFabricClientForSDK(d) + client := meta.(*config.Config).NewFabricClientForSDK(ctx, d) serviceToken, _, err := client.ServiceTokensApi.GetServiceTokenByUuid(ctx, uuid).Execute() if err != nil { return "", "", equinix_errors.FormatFabricError(err) @@ -176,7 +176,7 @@ func WaitForDeletion(uuid string, meta interface{}, d *schema.ResourceData, ctx string(fabricv4.SERVICETOKENSTATE_DELETED), }, Refresh: func() (interface{}, string, error) { - client := meta.(*config.Config).NewFabricClientForSDK(d) + client := meta.(*config.Config).NewFabricClientForSDK(ctx, d) serviceToken, body, err := client.ServiceTokensApi.GetServiceTokenByUuid(ctx, uuid).Execute() if err != nil { if body.StatusCode >= 400 && body.StatusCode <= 499 { From eaf92247f8543f8fa2ea5325a7d9d56e952e80f7 Mon Sep 17 00:00:00 2001 From: Tim Hogarty Date: Thu, 16 Jan 2025 19:16:03 -0800 Subject: [PATCH 02/13] Add equinix_fabric_stream resource and data sources --- .../fabric/stream/datasource_all_streams.go | 67 ++++ .../fabric/stream/datasource_by_streamid.go | 62 ++++ .../fabric/stream/datasources_schema.go | 160 +++++++++ internal/resources/fabric/stream/models.go | 247 +++++++++++++ internal/resources/fabric/stream/resource.go | 324 ++++++++++++++++++ .../fabric/stream/resource_schema.go | 122 +++++++ 6 files changed, 982 insertions(+) create mode 100644 internal/resources/fabric/stream/datasource_all_streams.go create mode 100644 internal/resources/fabric/stream/datasource_by_streamid.go create mode 100644 internal/resources/fabric/stream/datasources_schema.go create mode 100644 internal/resources/fabric/stream/models.go create mode 100644 internal/resources/fabric/stream/resource.go create mode 100644 internal/resources/fabric/stream/resource_schema.go diff --git a/internal/resources/fabric/stream/datasource_all_streams.go b/internal/resources/fabric/stream/datasource_all_streams.go new file mode 100644 index 000000000..9947d3bc4 --- /dev/null +++ b/internal/resources/fabric/stream/datasource_all_streams.go @@ -0,0 +1,67 @@ +package stream + +import ( + "context" + equinix_errors "github.com/equinix/terraform-provider-equinix/internal/errors" + "github.com/equinix/terraform-provider-equinix/internal/framework" + "github.com/hashicorp/terraform-plugin-framework/datasource" + "github.com/hashicorp/terraform-plugin-framework/types/basetypes" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" +) + +func NewDataSourceAllStreams() datasource.DataSource { + return &DataSourceAllStreams{ + BaseDataSource: framework.NewBaseDataSource( + framework.BaseDataSourceConfig{ + Name: "equinix_fabric_streams", + }, + ), + } +} + +type DataSourceAllStreams struct { + framework.BaseDataSource +} + +func (r *DataSourceAllStreams) Schema( + ctx context.Context, + req datasource.SchemaRequest, + resp *datasource.SchemaResponse, +) { + resp.Schema = dataSourceSingleStreamSchema(ctx) +} + +func (r *DataSourceAllStreams) Read(ctx context.Context, request datasource.ReadRequest, response *datasource.ReadResponse) { + client := r.Meta.NewFabricClientForFramework(ctx, request.ProviderMeta) + + // Retrieve values from plan + var data DataSourceAllStreamsModel + response.Diagnostics.Append(request.Config.Get(ctx, &data)...) + if response.Diagnostics.HasError() { + return + } + + var pagination PaginationModel + diags := data.Pagination.As(ctx, &pagination, basetypes.ObjectAsOptions{}) + if diags.HasError() { + return + } + + // Use API client to get the current state of the resource + streams, _, err := client.StreamsApi.GetStreams(ctx).Execute() + + if err != nil { + response.State.RemoveResource(ctx) + diag.FromErr(equinix_errors.FormatFabricError(err)) + return + } + + // Set state to fully populated data + response.Diagnostics.Append(data.parse(ctx, streams)...) + if response.Diagnostics.HasError() { + return + } + + // Update the Terraform state + response.Diagnostics.Append(response.State.Set(ctx, &data)...) +} diff --git a/internal/resources/fabric/stream/datasource_by_streamid.go b/internal/resources/fabric/stream/datasource_by_streamid.go new file mode 100644 index 000000000..508db8a05 --- /dev/null +++ b/internal/resources/fabric/stream/datasource_by_streamid.go @@ -0,0 +1,62 @@ +package stream + +import ( + "context" + equinix_errors "github.com/equinix/terraform-provider-equinix/internal/errors" + "github.com/equinix/terraform-provider-equinix/internal/framework" + "github.com/hashicorp/terraform-plugin-framework/datasource" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" +) + +func NewDataSourceByStreamID() datasource.DataSource { + return &DataSourceByStreamID{ + BaseDataSource: framework.NewBaseDataSource( + framework.BaseDataSourceConfig{ + Name: "equinix_fabric_stream", + }, + ), + } +} + +type DataSourceByStreamID struct { + framework.BaseDataSource +} + +func (r *DataSourceByStreamID) Schema( + ctx context.Context, + req datasource.SchemaRequest, + resp *datasource.SchemaResponse, +) { + resp.Schema = dataSourceSingleStreamSchema(ctx) +} + +func (r *DataSourceByStreamID) Read(ctx context.Context, request datasource.ReadRequest, response *datasource.ReadResponse) { + client := r.Meta.NewFabricClientForFramework(ctx, request.ProviderMeta) + + // Retrieve values from plan + var data DataSourceByIdModel + response.Diagnostics.Append(request.Config.Get(ctx, &data)...) + if response.Diagnostics.HasError() { + return + } + + streamID := data.StreamID.ValueString() + + // Use API client to get the current state of the resource + stream, _, err := client.StreamsApi.GetStreamByUuid(ctx, streamID).Execute() + + if err != nil { + response.State.RemoveResource(ctx) + diag.FromErr(equinix_errors.FormatFabricError(err)) + return + } + + // Set state to fully populated data + response.Diagnostics.Append(data.parse(ctx, stream)...) + if response.Diagnostics.HasError() { + return + } + + // Update the Terraform state + response.Diagnostics.Append(response.State.Set(ctx, &data)...) +} diff --git a/internal/resources/fabric/stream/datasources_schema.go b/internal/resources/fabric/stream/datasources_schema.go new file mode 100644 index 000000000..139766aab --- /dev/null +++ b/internal/resources/fabric/stream/datasources_schema.go @@ -0,0 +1,160 @@ +package stream + +import ( + "context" + "github.com/equinix/terraform-provider-equinix/internal/framework" + "github.com/hashicorp/terraform-plugin-framework/datasource/schema" +) + +func dataSourceAllStreamsSchema(ctx context.Context) schema.Schema { + return schema.Schema{ + Attributes: map[string]schema.Attribute{ + "id": framework.IDAttributeDefaultDescription(), + "pagination": schema.SingleNestedAttribute{ + Description: "Pagination details for the returned streams list", + Optional: true, + Computed: true, + Attributes: map[string]schema.Attribute{ + "offset": schema.Int32Attribute{ + Description: "The page offset for the returned streams list", + Optional: true, + Computed: true, + }, + "limit": schema.Int32Attribute{ + Description: "The page size for the returned streams list", + Optional: true, + Computed: true, + }, + "total": schema.Int32Attribute{ + Description: "The total number of streams available to the user making the request", + Computed: true, + }, + }, + }, + "data": schema.ListNestedAttribute{ + Description: "Returned list of stream objects", + Computed: true, + NestedObject: schema.NestedAttributeObject{ + Attributes: getStreamSchema(), + }, + }, + }, + } +} + +func dataSourceSingleStreamSchema(ctx context.Context) schema.Schema { + baseStreamSchema := getStreamSchema() + baseStreamSchema["id"] = framework.IDAttributeDefaultDescription() + baseStreamSchema["stream_id"] = schema.StringAttribute{ + Description: "The uuid of the stream this data source should retrieve", + Required: true, + } + return schema.Schema{ + Attributes: baseStreamSchema, + } +} + +func getStreamSchema() map[string]schema.Attribute { + return map[string]schema.Attribute{ + "type": schema.StringAttribute{ + Description: "Equinix defined Streaming Type", + Computed: true, + }, + "name": schema.StringAttribute{ + Description: "Customer-provided name of the stream resource", + Computed: true, + }, + "description": schema.StringAttribute{ + Description: "Customer-provided description of the stream resource", + Computed: true, + }, + "enabled": schema.BoolAttribute{ + Description: "Boolean switch enabling streaming data for the stream resource", + Computed: true, + }, + "project": schema.SingleNestedAttribute{ + Description: "Equinix Project attribute object", + Computed: true, + Attributes: map[string]schema.Attribute{ + "project_id": schema.StringAttribute{ + Description: "Equinix Subscriber-assigned project ID", + Computed: true, + }, + }, + }, + "href": schema.StringAttribute{ + Description: "Equinix auto generated URI to the stream resource in Equinix Portal", + Computed: true, + }, + "uuid": schema.StringAttribute{ + Description: "Equinix-assigned unique id for the stream resource", + Computed: true, + }, + "state": schema.StringAttribute{ + Description: "Value representing provisioning status for the stream resource", + Computed: true, + }, + "assets_count": schema.Int32Attribute{ + Description: "Count of the streaming assets attached to the stream resource", + Computed: true, + }, + "stream_subscriptions_count": schema.Int32Attribute{ + Description: "Count of the client subscriptions on the stream resource", + Computed: true, + }, + "change_log": schema.SingleNestedAttribute{ + Description: "Details of the last change on the stream resource", + Computed: true, + Attributes: map[string]schema.Attribute{ + "created_by": schema.StringAttribute{ + Description: "User name of creator of the stream resource", + Computed: true, + }, + "created_by_full_name": schema.StringAttribute{ + Description: "Legal name of creator of the stream resource", + Computed: true, + }, + "created_by_email": schema.StringAttribute{ + Description: "Email of creator of the stream resource", + Computed: true, + }, + "created_date_time": schema.StringAttribute{ + Description: "Creation time of the stream resource", + Computed: true, + }, + "updated_by": schema.StringAttribute{ + Description: "User name of last updater of the stream resource", + Computed: true, + }, + "updated_by_full_name": schema.StringAttribute{ + Description: "Legal name of last updater of the stream resource", + Computed: true, + }, + "updated_by_email": schema.StringAttribute{ + Description: "Email of last updater of the stream resource", + Computed: true, + }, + "updated_date_time": schema.StringAttribute{ + Description: "Last update time of the stream resource", + Computed: true, + }, + "deleted_by": schema.StringAttribute{ + Description: "User name of deleter of the stream resource", + Computed: true, + }, + "deleted_by_full_name": schema.StringAttribute{ + Description: "Legal name of deleter of the stream resource", + Computed: true, + }, + "deleted_by_email": schema.StringAttribute{ + Description: "Email of deleter of the stream resource", + Computed: true, + }, + "deleted_date_time": schema.StringAttribute{ + Description: "Deletion time of the stream resource", + Computed: true, + }, + }, + }, + } +} diff --git a/internal/resources/fabric/stream/models.go b/internal/resources/fabric/stream/models.go new file mode 100644 index 000000000..ca645a47e --- /dev/null +++ b/internal/resources/fabric/stream/models.go @@ -0,0 +1,247 @@ +package stream + +import ( + "context" + + "github.com/equinix/equinix-sdk-go/services/fabricv4" + fwtypes "github.com/equinix/terraform-provider-equinix/internal/framework/types" + "github.com/hashicorp/terraform-plugin-framework-timeouts/resource/timeouts" + "github.com/hashicorp/terraform-plugin-framework/attr" + "github.com/hashicorp/terraform-plugin-framework/diag" + "github.com/hashicorp/terraform-plugin-framework/types" + "github.com/hashicorp/terraform-plugin-framework/types/basetypes" +) + +type DataSourceByIdModel struct { + StreamID types.String `tfsdk:"stream_id"` + ID types.String `tfsdk:"id"` + BaseStreamModel +} + +type DataSourceAllStreamsModel struct { + ID types.String `tfsdk:"id"` + Pagination fwtypes.ObjectValueOf[PaginationModel] `tfsdk:"pagination"` + Data fwtypes.ListNestedObjectValueOf[BaseStreamModel] `tfsdk:"data"` +} + +type PaginationModel struct { + Offset types.Int32 `tfsdk:"offset"` + Limit types.Int32 `tfsdk:"limit"` + Total types.Int32 `tfsdk:"total"` + Next types.String `tfsdk:"next"` + Previous types.String `tfsdk:"previous"` +} + +type ResourceModel struct { + ID types.String `tfsdk:"id"` + Timeouts timeouts.Value `tfsdk:"timeouts"` + BaseStreamModel +} + +type BaseStreamModel struct { + Type types.String `tfsdk:"type"` + Name types.String `tfsdk:"name"` + Description types.String `tfsdk:"description"` + Href types.String `tfsdk:"href"` + Uuid types.String `tfsdk:"uuid"` + State types.String `tfsdk:"state"` + Enabled types.Bool `tfsdk:"enabled"` + AssetsCount types.Int32 `tfsdk:"assets_count"` + StreamSubscriptionsCount types.Int32 `tfsdk:"stream_subscriptions_count"` + Project types.Object `tfsdk:"project"` // Object of ProjectModel + ChangeLog types.Object `tfsdk:"change_log"` // Object of ChangeLogModel +} + +type ProjectModel struct { + ProjectID types.String `tfsdk:"project_id"` +} + +func (m ProjectModel) AttributeTypes() map[string]attr.Type { + return map[string]attr.Type{ + "project_id": types.StringType, + } +} + +type ChangeLogModel struct { + CreatedBy types.String `tfsdk:"created_by"` + CreatedByFullName types.String `tfsdk:"created_by_full_name"` + CreatedByEmail types.String `tfsdk:"created_by_email"` + CreatedDateTime types.String `tfsdk:"created_date_time"` + UpdatedBy types.String `tfsdk:"updated_by"` + UpdatedByFullName types.String `tfsdk:"updated_by_full_name"` + UpdatedByEmail types.String `tfsdk:"updated_by_email"` + UpdatedDateTime types.String `tfsdk:"updated_date_time"` + DeletedBy types.String `tfsdk:"deleted_by"` + DeletedByFullName types.String `tfsdk:"deleted_by_full_name"` + DeletedByEmail types.String `tfsdk:"deleted_by_email"` + DeletedDateTime types.String `tfsdk:"deleted_date_time"` +} + +func (m ChangeLogModel) AttributeTypes() map[string]attr.Type { + return map[string]attr.Type{ + "created_by": types.StringType, + "created_by_full_name": types.StringType, + "created_by_email": types.StringType, + "created_date_time": types.StringType, + "updated_by": types.StringType, + "updated_by_full_name": types.StringType, + "updated_by_email": types.StringType, + "updated_date_time": types.StringType, + "deleted_by": types.StringType, + "deleted_by_full_name": types.StringType, + "deleted_by_email": types.StringType, + "deleted_date_time": types.StringType, + } +} + +func (m *DataSourceByIdModel) parse(ctx context.Context, stream *fabricv4.Stream) diag.Diagnostics { + var diags diag.Diagnostics + + m.StreamID = types.StringValue(stream.GetUuid()) + m.ID = types.StringValue(stream.GetUuid()) + + diags = parseStream(ctx, stream, + &m.Type, + &m.Name, + &m.Description, + &m.Href, + &m.Uuid, + &m.State, + &m.Enabled, + &m.AssetsCount, + &m.StreamSubscriptionsCount, + &m.Project, + &m.ChangeLog) + if diags.HasError() { + return diags + } + + return diags +} + +func (m *DataSourceAllStreamsModel) parse(ctx context.Context, streamsResponse *fabricv4.GetAllStreamResponse) diag.Diagnostics { + var diags diag.Diagnostics + + data := make([]BaseStreamModel, len(streamsResponse.GetData())) + streams := streamsResponse.GetData() + for _, stream := range streams { + var streamModel BaseStreamModel + diags = streamModel.parse(ctx, &stream) + if diags.HasError() { + return diags + } + data = append(data, streamModel) + } + responsePagination := streamsResponse.GetPagination() + pagination := PaginationModel{ + Offset: types.Int32Value(responsePagination.GetOffset()), + Limit: types.Int32Value(responsePagination.GetLimit()), + Total: types.Int32Value(responsePagination.GetTotal()), + Next: types.StringValue(responsePagination.GetNext()), + Previous: types.StringValue(responsePagination.GetPrevious()), + } + + m.ID = types.StringValue(data[0].Uuid.ValueString()) + m.Pagination = fwtypes.NewObjectValueOf[PaginationModel](ctx, &pagination) + m.Data = fwtypes.NewListNestedObjectValueOfValueSlice[BaseStreamModel](ctx, data) + + return diags +} + +func (m *ResourceModel) parse(ctx context.Context, stream *fabricv4.Stream) diag.Diagnostics { + var diags diag.Diagnostics + + m.ID = types.StringValue(stream.GetUuid()) + + diags = parseStream(ctx, stream, + &m.Type, + &m.Name, + &m.Description, + &m.Href, + &m.Uuid, + &m.State, + &m.Enabled, + &m.AssetsCount, + &m.StreamSubscriptionsCount, + &m.Project, + &m.ChangeLog) + if diags.HasError() { + return diags + } + + return diags +} + +func (m *BaseStreamModel) parse(ctx context.Context, stream *fabricv4.Stream) diag.Diagnostics { + var diags diag.Diagnostics + + diags = parseStream(ctx, stream, + &m.Type, + &m.Name, + &m.Description, + &m.Href, + &m.Uuid, + &m.State, + &m.Enabled, + &m.AssetsCount, + &m.StreamSubscriptionsCount, + &m.Project, + &m.ChangeLog) + if diags.HasError() { + return diags + } + + return diags +} + +func parseStream(ctx context.Context, stream *fabricv4.Stream, + type_, name, description, href, uuid, state *basetypes.StringValue, + enabled *basetypes.BoolValue, + assetsCount, streamSubscriptionCount *basetypes.Int32Value, + project, changeLog *basetypes.ObjectValue) diag.Diagnostics { + + var diag diag.Diagnostics + + *type_ = types.StringValue(string(stream.GetType())) + *name = types.StringValue(stream.GetName()) + *description = types.StringValue(stream.GetDescription()) + *href = types.StringValue(stream.GetHref()) + *uuid = types.StringValue(stream.GetUuid()) + *state = types.StringValue(stream.GetState()) + *enabled = types.BoolValue(stream.GetEnabled()) + *assetsCount = types.Int32Value(stream.GetAssetsCount()) + *streamSubscriptionCount = types.Int32Value(stream.GetStreamSubscriptionsCount()) + + streamProject := stream.GetProject() + projectModel := ProjectModel{ + ProjectID: types.StringValue(streamProject.GetProjectId()), + } + terraformProject, diags := types.ObjectValueFrom(ctx, projectModel.AttributeTypes(), projectModel) + if diags.HasError() { + return diags + } + *project = terraformProject + + const TIMEFORMAT = "2006-01-02T15:04:05.000Z" + streamChangeLog := stream.GetChangelog() + changeLogModel := ChangeLogModel{ + CreatedBy: types.StringValue(streamChangeLog.GetCreatedBy()), + CreatedByFullName: types.StringValue(streamChangeLog.GetCreatedByFullName()), + CreatedByEmail: types.StringValue(streamChangeLog.GetCreatedByEmail()), + CreatedDateTime: types.StringValue(streamChangeLog.GetCreatedDateTime().Format(TIMEFORMAT)), + UpdatedBy: types.StringValue(streamChangeLog.GetUpdatedBy()), + UpdatedByFullName: types.StringValue(streamChangeLog.GetUpdatedByFullName()), + UpdatedByEmail: types.StringValue(streamChangeLog.GetUpdatedByEmail()), + UpdatedDateTime: types.StringValue(streamChangeLog.GetUpdatedDateTime().Format(TIMEFORMAT)), + DeletedBy: types.StringValue(streamChangeLog.GetDeletedBy()), + DeletedByFullName: types.StringValue(streamChangeLog.GetDeletedByFullName()), + DeletedByEmail: types.StringValue(streamChangeLog.GetDeletedByEmail()), + DeletedDateTime: types.StringValue(streamChangeLog.GetDeletedDateTime().Format(TIMEFORMAT)), + } + terraformChangeLog, diags := types.ObjectValueFrom(ctx, changeLogModel.AttributeTypes(), changeLogModel) + if diags.HasError() { + return diags + } + *changeLog = terraformChangeLog + return diag +} diff --git a/internal/resources/fabric/stream/resource.go b/internal/resources/fabric/stream/resource.go new file mode 100644 index 000000000..00d3b45ee --- /dev/null +++ b/internal/resources/fabric/stream/resource.go @@ -0,0 +1,324 @@ +package stream + +import ( + "context" + "fmt" + equinix_errors "github.com/equinix/terraform-provider-equinix/internal/errors" + "net/http" + "reflect" + "slices" + "time" + + "github.com/equinix/equinix-sdk-go/services/fabricv4" + "github.com/equinix/terraform-provider-equinix/internal/framework" + "github.com/hashicorp/terraform-plugin-framework/diag" + "github.com/hashicorp/terraform-plugin-framework/resource" + "github.com/hashicorp/terraform-plugin-framework/types/basetypes" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/retry" +) + +func NewResource() resource.Resource { + return &Resource{ + BaseResource: framework.NewBaseResource( + framework.BaseResourceConfig{ + Name: "equinix_fabric_stream", + }, + ), + } +} + +type Resource struct { + framework.BaseResource +} + +func (r *Resource) Schema( + ctx context.Context, + req resource.SchemaRequest, + resp *resource.SchemaResponse, +) { + resp.Schema = resourceSchema(ctx) +} + +func (r *Resource) Create( + ctx context.Context, + req resource.CreateRequest, + resp *resource.CreateResponse, +) { + + var plan ResourceModel + diags := req.Plan.Get(ctx, &plan) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + // Retrieve the API client from the provider metadata + client := r.Meta.NewFabricClientForFramework(ctx, req.ProviderMeta) + var project ProjectModel + diags = plan.Project.As(ctx, &project, basetypes.ObjectAsOptions{}) + if diags.HasError() { + return + } + + createRequest, diags := buildCreateRequest(ctx, plan) + if diags.HasError() { + return + } + + stream, _, err := client.StreamsApi.CreateStreams(ctx).StreamPostRequest(createRequest).Execute() + if err != nil { + resp.Diagnostics.AddError( + fmt.Sprintf("Failed creating Stream"), equinix_errors.FormatFabricError(err).Error()) + return + } + + createTimeout, diags := plan.Timeouts.Create(ctx, 10*time.Minute) + if diags.HasError() { + resp.Diagnostics.Append(diags...) + return + } + createWaiter := getCreateUpdateWaiter(ctx, client, stream.GetUuid(), createTimeout) + streamChecked, err := createWaiter.WaitForStateContext(ctx) + if err != nil { + resp.Diagnostics.AddError( + fmt.Sprintf("Failed creating Stream %s", stream.GetUuid()), err.Error()) + return + } + + resp.Diagnostics.Append(diags...) + if diags.HasError() { + return + } + + // Parse API response into the Terraform state + resp.Diagnostics.Append(plan.parse(ctx, streamChecked.(*fabricv4.Stream))...) + if resp.Diagnostics.HasError() { + return + } + + // Set state to fully populated data + resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...) +} + +func (r *Resource) Read( + ctx context.Context, + req resource.ReadRequest, + resp *resource.ReadResponse, +) { + var state ResourceModel + diags := req.State.Get(ctx, &state) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + // Retrieve the API client from the provider metadata + client := r.Meta.NewFabricClientForFramework(ctx, req.ProviderMeta) + + // Extract the ID of the resource from the state + id := state.ID.ValueString() + + stream, _, err := client.StreamsApi.GetStreamByUuid(ctx, id).Execute() + if err != nil { + resp.Diagnostics.AddError( + fmt.Sprintf("Failed retrieving Stream %s", id), equinix_errors.FormatFabricError(err).Error()) + return + } + + // Set state to fully populated data + resp.Diagnostics.Append(state.parse(ctx, stream)...) + if resp.Diagnostics.HasError() { + return + } + + // Update the Terraform state + resp.Diagnostics.Append(resp.State.Set(ctx, &state)...) +} + +func (r *Resource) Update( + ctx context.Context, + req resource.UpdateRequest, + resp *resource.UpdateResponse, +) { + client := r.Meta.NewFabricClientForFramework(ctx, req.ProviderMeta) + + // Retrieve values from plan + var state, plan ResourceModel + resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...) + resp.Diagnostics.Append(req.State.Get(ctx, &state)...) + if resp.Diagnostics.HasError() { + return + } + + id := state.ID.ValueString() + + updateRequest := fabricv4.StreamPutRequest{} + + if !plan.Name.IsNull() { + if plan.Name.ValueString() != state.Name.ValueString() { + updateRequest.SetName(plan.Name.ValueString()) + } + } + + if !plan.Description.IsNull() { + if plan.Description.ValueString() != state.Description.ValueString() { + updateRequest.SetDescription(plan.Description.ValueString()) + } + } + + if !plan.Enabled.IsNull() { + if plan.Enabled.ValueBool() != state.Enabled.ValueBool() { + updateRequest.SetEnabled(plan.Enabled.ValueBool()) + } + } + + if reflect.ValueOf(updateRequest).IsZero() { + resp.Diagnostics.AddWarning("No updatable fields have changed", + "Terraform detected a config change, but it is for a field that isn't updatable for the stream resource. Please revert to prior config") + return + } + + stream, _, err := client.StreamsApi.UpdateStreamByUuid(ctx, id).StreamPutRequest(updateRequest).Execute() + if err != nil { + resp.Diagnostics.AddError( + fmt.Sprintf("Failed updating Stream %s", id), equinix_errors.FormatFabricError(err).Error()) + return + } + + updateTimeout, diags := plan.Timeouts.Update(ctx, 10*time.Minute) + if diags.HasError() { + resp.Diagnostics.Append(diags...) + return + } + + updateWaiter := getCreateUpdateWaiter(ctx, client, id, updateTimeout) + streamChecked, err := updateWaiter.WaitForStateContext(ctx) + if err != nil { + resp.Diagnostics.AddError( + fmt.Sprintf("Failed updating Stream %s", id), err.Error()) + return + } + + // Set state to fully populated data + resp.Diagnostics.Append(plan.parse(ctx, streamChecked.(*fabricv4.Stream))...) + if resp.Diagnostics.HasError() { + return + } + + // Set the updated state back into Terraform state + resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...) +} + +func (r *Resource) Delete( + ctx context.Context, + req resource.DeleteRequest, + resp *resource.DeleteResponse, +) { + // Retrieve the API client + client := r.Meta.NewFabricClientForFramework(ctx, req.ProviderMeta) + + // Retrieve the current state + var state ResourceModel + resp.Diagnostics.Append(req.State.Get(ctx, &state)...) + if resp.Diagnostics.HasError() { + return + } + + id := state.ID.ValueString() + + _, deleteResp, err := client.StreamsApi.DeleteStreamByUuid(ctx, id).Execute() + if err != nil { + if deleteResp == nil || !slices.Contains([]int{http.StatusForbidden, http.StatusNotFound}, deleteResp.StatusCode) { + resp.Diagnostics.AddError( + fmt.Sprintf("Failed deleting Stream %s", id), equinix_errors.FormatFabricError(err).Error()) + return + } + } + + deleteTimeout, diags := state.Timeouts.Delete(ctx, 10*time.Minute) + if diags.HasError() { + resp.Diagnostics.Append(diags...) + return + } + deleteWaiter := getDeleteWaiter(ctx, client, id, deleteTimeout) + _, err = deleteWaiter.WaitForStateContext(ctx) + + if err != nil { + resp.Diagnostics.AddError( + fmt.Sprintf("Failed deleting Stream %s", id), err.Error()) + return + } + +} + +func buildCreateRequest(ctx context.Context, plan ResourceModel) (fabricv4.StreamPostRequest, diag.Diagnostics) { + var diags diag.Diagnostics + request := fabricv4.StreamPostRequest{} + + request.SetName(plan.Name.ValueString()) + request.SetType(fabricv4.StreamPostRequestType(plan.Type.ValueString())) + request.SetDescription(plan.Description.ValueString()) + if !plan.Enabled.IsNull() { + request.SetEnabled(plan.Enabled.ValueBool()) + } + var project ProjectModel + if !plan.Project.IsNull() { + diags = plan.Project.As(ctx, &project, basetypes.ObjectAsOptions{}) + if diags.HasError() { + return fabricv4.StreamPostRequest{}, diags + } + request.SetProject(fabricv4.Project{ProjectId: project.ProjectID.ValueString()}) + } + + return request, diags +} + +func getCreateUpdateWaiter(ctx context.Context, client *fabricv4.APIClient, id string, timeout time.Duration) *retry.StateChangeConf { + return &retry.StateChangeConf{ + Pending: []string{ + string(fabricv4.STREAMSUBSCRIPTIONSTATE_PROVISIONING), + }, + Target: []string{ + string(fabricv4.STREAMSUBSCRIPTIONSTATE_PROVISIONED), + }, + Refresh: func() (interface{}, string, error) { + stream, _, err := client.StreamsApi.GetStreamByUuid(ctx, id).Execute() + if err != nil { + return 0, "", err + } + return stream, stream.GetState(), nil + }, + Timeout: timeout, + Delay: 10 * time.Second, + MinTimeout: 5 * time.Second, + } +} + +func getDeleteWaiter(ctx context.Context, client *fabricv4.APIClient, id string, timeout time.Duration) *retry.StateChangeConf { + // deletedMarker is a terraform-provider-only value that is used by the waiter + // to indicate that the connection appears to be deleted successfully based on + // status code + deletedMarker := "tf-marker-for-deleted-connection" + return &retry.StateChangeConf{ + Pending: []string{ + string(fabricv4.STREAMSUBSCRIPTIONSTATE_DEPROVISIONING), + }, + Target: []string{ + deletedMarker, + string(fabricv4.STREAMSUBSCRIPTIONSTATE_DEPROVISIONED), + }, + Refresh: func() (interface{}, string, error) { + stream, resp, err := client.StreamsApi.GetStreamByUuid(ctx, id).Execute() + if err != nil { + if resp != nil && slices.Contains([]int{http.StatusForbidden, http.StatusNotFound}, resp.StatusCode) { + return stream, deletedMarker, nil + } + return 0, "", err + } + return stream, stream.GetState(), nil + }, + Timeout: timeout, + Delay: 10 * time.Second, + MinTimeout: 5 * time.Second, + } +} diff --git a/internal/resources/fabric/stream/resource_schema.go b/internal/resources/fabric/stream/resource_schema.go new file mode 100644 index 000000000..f7ba2638d --- /dev/null +++ b/internal/resources/fabric/stream/resource_schema.go @@ -0,0 +1,122 @@ +package stream + +import ( + "context" + "github.com/equinix/terraform-provider-equinix/internal/framework" + "github.com/hashicorp/terraform-plugin-framework-timeouts/resource/timeouts" + "github.com/hashicorp/terraform-plugin-framework/resource/schema" +) + +func resourceSchema(ctx context.Context) schema.Schema { + return schema.Schema{ + Attributes: map[string]schema.Attribute{ + "id": framework.IDAttributeDefaultDescription(), + "timeouts": timeouts.Attributes(ctx, timeouts.Opts{ + Create: true, + Read: true, + Update: true, + Delete: true, + }), + "type": schema.StringAttribute{ + Description: "Equinix defined Streaming Type", + Required: true, + }, + "name": schema.StringAttribute{ + Description: "Customer-provided name of the stream resource", + Required: true, + }, + "description": schema.StringAttribute{ + Description: "Customer-provided description of the stream resource", + Required: true, + }, + "enabled": schema.BoolAttribute{ + Description: "Boolean switch enabling streaming data for the stream resource", + Required: true, + }, + "project": schema.SingleNestedAttribute{ + Description: "Equinix Project attribute object", + Required: true, + Attributes: map[string]schema.Attribute{ + "project_id": schema.StringAttribute{ + Description: "Equinix Subscriber-assigned project ID", + Required: true, + }, + }, + }, + "href": schema.StringAttribute{ + Description: "Equinix auto generated URI to the stream resource in Equinix Portal", + Computed: true, + }, + "uuid": schema.StringAttribute{ + Description: "Equinix-assigned unique id for the stream resource", + Computed: true, + }, + "state": schema.StringAttribute{ + Description: "Value representing provisioning status for the stream resource", + Computed: true, + }, + "assets_count": schema.Int32Attribute{ + Description: "Count of the streaming assets attached to the stream resource", + Computed: true, + }, + "stream_subscriptions_count": schema.Int32Attribute{ + Description: "Count of the client subscriptions on the stream resource", + Computed: true, + }, + "change_log": schema.SingleNestedAttribute{ + Description: "Details of the last change on the stream resource", + Computed: true, + Attributes: map[string]schema.Attribute{ + "created_by": schema.StringAttribute{ + Description: "User name of creator of the stream resource", + Computed: true, + }, + "created_by_full_name": schema.StringAttribute{ + Description: "Legal name of creator of the stream resource", + Computed: true, + }, + "created_by_email": schema.StringAttribute{ + Description: "Email of creator of the stream resource", + Computed: true, + }, + "created_date_time": schema.StringAttribute{ + Description: "Creation time of the stream resource", + Computed: true, + }, + "updated_by": schema.StringAttribute{ + Description: "User name of last updater of the stream resource", + Computed: true, + }, + "updated_by_full_name": schema.StringAttribute{ + Description: "Legal name of last updater of the stream resource", + Computed: true, + }, + "updated_by_email": schema.StringAttribute{ + Description: "Email of last updater of the stream resource", + Computed: true, + }, + "updated_date_time": schema.StringAttribute{ + Description: "Last update time of the stream resource", + Computed: true, + }, + "deleted_by": schema.StringAttribute{ + Description: "User name of deleter of the stream resource", + Computed: true, + }, + "deleted_by_full_name": schema.StringAttribute{ + Description: "Legal name of deleter of the stream resource", + Computed: true, + }, + "deleted_by_email": schema.StringAttribute{ + Description: "Email of deleter of the stream resource", + Computed: true, + }, + "deleted_date_time": schema.StringAttribute{ + Description: "Deletion time of the stream resource", + Computed: true, + }, + }, + }, + }, + } +} From ccd6c8d88e79a6166859948ff4d27b9d892a87c3 Mon Sep 17 00:00:00 2001 From: Tim Hogarty Date: Wed, 22 Jan 2025 11:12:12 -0800 Subject: [PATCH 03/13] Add Equinix Fabric Stream Resource and Data Sources --- internal/config/config.go | 1 - internal/provider/services/fabric.go | 10 ++- .../fabric/stream/datasource_all_streams.go | 9 ++- .../fabric/stream/datasources_schema.go | 26 ++++++-- internal/resources/fabric/stream/models.go | 66 +++++-------------- internal/resources/fabric/stream/resource.go | 29 +++----- .../fabric/stream/resource_schema.go | 3 + 7 files changed, 63 insertions(+), 81 deletions(-) diff --git a/internal/config/config.go b/internal/config/config.go index 29ee7e6ca..90c00b911 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -150,7 +150,6 @@ func (c *Config) NewFabricClientForFramework(ctx context.Context, meta tfsdk.Con // newFabricClient returns the base fabricv4 client that is then used for either the sdkv2 or framework // implementations of the Terraform Provider with exported Methods func (c *Config) newFabricClient(ctx context.Context) *fabricv4.APIClient { - //nolint:staticcheck // We should move to subsystem loggers, but that is a much bigger change authConfig := oauth2.Config{ ClientID: c.ClientID, ClientSecret: c.ClientSecret, diff --git a/internal/provider/services/fabric.go b/internal/provider/services/fabric.go index f545396bf..d89eadf6c 100644 --- a/internal/provider/services/fabric.go +++ b/internal/provider/services/fabric.go @@ -1,14 +1,20 @@ package services import ( + "github.com/equinix/terraform-provider-equinix/internal/resources/fabric/stream" "github.com/hashicorp/terraform-plugin-framework/datasource" "github.com/hashicorp/terraform-plugin-framework/resource" ) func FabricResources() []func() resource.Resource { - return []func() resource.Resource{} + return []func() resource.Resource{ + stream.NewResource, + } } func FabricDatasources() []func() datasource.DataSource { - return []func() datasource.DataSource{} + return []func() datasource.DataSource{ + stream.NewDataSourceByStreamID, + stream.NewDataSourceAllStreams, + } } diff --git a/internal/resources/fabric/stream/datasource_all_streams.go b/internal/resources/fabric/stream/datasource_all_streams.go index 9947d3bc4..9c9deaf08 100644 --- a/internal/resources/fabric/stream/datasource_all_streams.go +++ b/internal/resources/fabric/stream/datasource_all_streams.go @@ -28,7 +28,7 @@ func (r *DataSourceAllStreams) Schema( req datasource.SchemaRequest, resp *datasource.SchemaResponse, ) { - resp.Schema = dataSourceSingleStreamSchema(ctx) + resp.Schema = dataSourceAllStreamsSchema(ctx) } func (r *DataSourceAllStreams) Read(ctx context.Context, request datasource.ReadRequest, response *datasource.ReadResponse) { @@ -46,9 +46,14 @@ func (r *DataSourceAllStreams) Read(ctx context.Context, request datasource.Read if diags.HasError() { return } + offset := pagination.Offset.ValueInt32() + limit := pagination.Limit.ValueInt32() + if limit == 0 { + limit = 20 + } // Use API client to get the current state of the resource - streams, _, err := client.StreamsApi.GetStreams(ctx).Execute() + streams, _, err := client.StreamsApi.GetStreams(ctx).Limit(limit).Offset(offset).Execute() if err != nil { response.State.RemoveResource(ctx) diff --git a/internal/resources/fabric/stream/datasources_schema.go b/internal/resources/fabric/stream/datasources_schema.go index 139766aab..3160b2063 100644 --- a/internal/resources/fabric/stream/datasources_schema.go +++ b/internal/resources/fabric/stream/datasources_schema.go @@ -3,6 +3,7 @@ package stream import ( "context" "github.com/equinix/terraform-provider-equinix/internal/framework" + fwtypes "github.com/equinix/terraform-provider-equinix/internal/framework/types" "github.com/hashicorp/terraform-plugin-framework/datasource/schema" ) @@ -12,16 +13,16 @@ func dataSourceAllStreamsSchema(ctx context.Context) schema.Schema { "id": framework.IDAttributeDefaultDescription(), "pagination": schema.SingleNestedAttribute{ Description: "Pagination details for the returned streams list", - Optional: true, - Computed: true, + Required: true, + CustomType: fwtypes.NewObjectTypeOf[PaginationModel](ctx), Attributes: map[string]schema.Attribute{ "offset": schema.Int32Attribute{ - Description: "The page offset for the returned streams list", + Description: "Index of the first item returned in the response. The default is 0", Optional: true, Computed: true, }, "limit": schema.Int32Attribute{ - Description: "The page size for the returned streams list", + Description: "Maximum number of search results returned per page. Number must be between 1 and 100, and the default is 20", Optional: true, Computed: true, }, @@ -29,13 +30,22 @@ func dataSourceAllStreamsSchema(ctx context.Context) schema.Schema { Description: "The total number of streams available to the user making the request", Computed: true, }, + "next": schema.StringAttribute{ + Description: "The URL relative to the next item in the response", + Computed: true, + }, + "previous": schema.StringAttribute{ + Description: "The URL relative to the previous item in the response", + Computed: true, + }, }, }, "data": schema.ListNestedAttribute{ Description: "Returned list of stream objects", Computed: true, + CustomType: fwtypes.NewListNestedObjectTypeOf[BaseStreamModel](ctx), NestedObject: schema.NestedAttributeObject{ - Attributes: getStreamSchema(), + Attributes: getStreamSchema(ctx), }, }, }, @@ -43,7 +53,7 @@ func dataSourceAllStreamsSchema(ctx context.Context) schema.Schema { } func dataSourceSingleStreamSchema(ctx context.Context) schema.Schema { - baseStreamSchema := getStreamSchema() + baseStreamSchema := getStreamSchema(ctx) baseStreamSchema["id"] = framework.IDAttributeDefaultDescription() baseStreamSchema["stream_id"] = schema.StringAttribute{ Description: "The uuid of the stream this data source should retrieve", @@ -54,7 +64,7 @@ func dataSourceSingleStreamSchema(ctx context.Context) schema.Schema { } } -func getStreamSchema() map[string]schema.Attribute { +func getStreamSchema(ctx context.Context) map[string]schema.Attribute { return map[string]schema.Attribute{ "type": schema.StringAttribute{ Description: "Equinix defined Streaming Type", @@ -75,6 +85,7 @@ func getStreamSchema() map[string]schema.Attribute { "project": schema.SingleNestedAttribute{ Description: "Equinix Project attribute object", Computed: true, + CustomType: fwtypes.NewObjectTypeOf[ProjectModel](ctx), Attributes: map[string]schema.Attribute{ "project_id": schema.StringAttribute{ Description: "Equinix Subscriber-assigned project ID", @@ -105,6 +116,7 @@ func getStreamSchema() map[string]schema.Attribute { "change_log": schema.SingleNestedAttribute{ Description: "Details of the last change on the stream resource", Computed: true, + CustomType: fwtypes.NewObjectTypeOf[ChangeLogModel](ctx), Attributes: map[string]schema.Attribute{ "created_by": schema.StringAttribute{ Description: "User name of creator of the stream resource", diff --git a/internal/resources/fabric/stream/models.go b/internal/resources/fabric/stream/models.go index ca645a47e..2882e2531 100644 --- a/internal/resources/fabric/stream/models.go +++ b/internal/resources/fabric/stream/models.go @@ -2,11 +2,9 @@ package stream import ( "context" - "github.com/equinix/equinix-sdk-go/services/fabricv4" fwtypes "github.com/equinix/terraform-provider-equinix/internal/framework/types" "github.com/hashicorp/terraform-plugin-framework-timeouts/resource/timeouts" - "github.com/hashicorp/terraform-plugin-framework/attr" "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-framework/types/basetypes" @@ -39,29 +37,23 @@ type ResourceModel struct { } type BaseStreamModel struct { - Type types.String `tfsdk:"type"` - Name types.String `tfsdk:"name"` - Description types.String `tfsdk:"description"` - Href types.String `tfsdk:"href"` - Uuid types.String `tfsdk:"uuid"` - State types.String `tfsdk:"state"` - Enabled types.Bool `tfsdk:"enabled"` - AssetsCount types.Int32 `tfsdk:"assets_count"` - StreamSubscriptionsCount types.Int32 `tfsdk:"stream_subscriptions_count"` - Project types.Object `tfsdk:"project"` // Object of ProjectModel - ChangeLog types.Object `tfsdk:"change_log"` // Object of ChangeLogModel + Type types.String `tfsdk:"type"` + Name types.String `tfsdk:"name"` + Description types.String `tfsdk:"description"` + Href types.String `tfsdk:"href"` + Uuid types.String `tfsdk:"uuid"` + State types.String `tfsdk:"state"` + Enabled types.Bool `tfsdk:"enabled"` + AssetsCount types.Int32 `tfsdk:"assets_count"` + StreamSubscriptionsCount types.Int32 `tfsdk:"stream_subscriptions_count"` + Project fwtypes.ObjectValueOf[ProjectModel] `tfsdk:"project"` // Object of ProjectModel + ChangeLog fwtypes.ObjectValueOf[ChangeLogModel] `tfsdk:"change_log"` // Object of ChangeLogModel } type ProjectModel struct { ProjectID types.String `tfsdk:"project_id"` } -func (m ProjectModel) AttributeTypes() map[string]attr.Type { - return map[string]attr.Type{ - "project_id": types.StringType, - } -} - type ChangeLogModel struct { CreatedBy types.String `tfsdk:"created_by"` CreatedByFullName types.String `tfsdk:"created_by_full_name"` @@ -77,23 +69,6 @@ type ChangeLogModel struct { DeletedDateTime types.String `tfsdk:"deleted_date_time"` } -func (m ChangeLogModel) AttributeTypes() map[string]attr.Type { - return map[string]attr.Type{ - "created_by": types.StringType, - "created_by_full_name": types.StringType, - "created_by_email": types.StringType, - "created_date_time": types.StringType, - "updated_by": types.StringType, - "updated_by_full_name": types.StringType, - "updated_by_email": types.StringType, - "updated_date_time": types.StringType, - "deleted_by": types.StringType, - "deleted_by_full_name": types.StringType, - "deleted_by_email": types.StringType, - "deleted_date_time": types.StringType, - } -} - func (m *DataSourceByIdModel) parse(ctx context.Context, stream *fabricv4.Stream) diag.Diagnostics { var diags diag.Diagnostics @@ -124,13 +99,13 @@ func (m *DataSourceAllStreamsModel) parse(ctx context.Context, streamsResponse * data := make([]BaseStreamModel, len(streamsResponse.GetData())) streams := streamsResponse.GetData() - for _, stream := range streams { + for index, stream := range streams { var streamModel BaseStreamModel diags = streamModel.parse(ctx, &stream) if diags.HasError() { return diags } - data = append(data, streamModel) + data[index] = streamModel } responsePagination := streamsResponse.GetPagination() pagination := PaginationModel{ @@ -198,7 +173,8 @@ func parseStream(ctx context.Context, stream *fabricv4.Stream, type_, name, description, href, uuid, state *basetypes.StringValue, enabled *basetypes.BoolValue, assetsCount, streamSubscriptionCount *basetypes.Int32Value, - project, changeLog *basetypes.ObjectValue) diag.Diagnostics { + project *fwtypes.ObjectValueOf[ProjectModel], + changeLog *fwtypes.ObjectValueOf[ChangeLogModel]) diag.Diagnostics { var diag diag.Diagnostics @@ -216,11 +192,7 @@ func parseStream(ctx context.Context, stream *fabricv4.Stream, projectModel := ProjectModel{ ProjectID: types.StringValue(streamProject.GetProjectId()), } - terraformProject, diags := types.ObjectValueFrom(ctx, projectModel.AttributeTypes(), projectModel) - if diags.HasError() { - return diags - } - *project = terraformProject + *project = fwtypes.NewObjectValueOf[ProjectModel](ctx, &projectModel) const TIMEFORMAT = "2006-01-02T15:04:05.000Z" streamChangeLog := stream.GetChangelog() @@ -238,10 +210,6 @@ func parseStream(ctx context.Context, stream *fabricv4.Stream, DeletedByEmail: types.StringValue(streamChangeLog.GetDeletedByEmail()), DeletedDateTime: types.StringValue(streamChangeLog.GetDeletedDateTime().Format(TIMEFORMAT)), } - terraformChangeLog, diags := types.ObjectValueFrom(ctx, changeLogModel.AttributeTypes(), changeLogModel) - if diags.HasError() { - return diags - } - *changeLog = terraformChangeLog + *changeLog = fwtypes.NewObjectValueOf[ChangeLogModel](ctx, &changeLogModel) return diag } diff --git a/internal/resources/fabric/stream/resource.go b/internal/resources/fabric/stream/resource.go index 00d3b45ee..9b46e064b 100644 --- a/internal/resources/fabric/stream/resource.go +++ b/internal/resources/fabric/stream/resource.go @@ -5,7 +5,6 @@ import ( "fmt" equinix_errors "github.com/equinix/terraform-provider-equinix/internal/errors" "net/http" - "reflect" "slices" "time" @@ -154,31 +153,21 @@ func (r *Resource) Update( updateRequest := fabricv4.StreamPutRequest{} - if !plan.Name.IsNull() { - if plan.Name.ValueString() != state.Name.ValueString() { - updateRequest.SetName(plan.Name.ValueString()) - } - } - - if !plan.Description.IsNull() { - if plan.Description.ValueString() != state.Description.ValueString() { - updateRequest.SetDescription(plan.Description.ValueString()) - } - } + needsUpdate := plan.Name.ValueString() != state.Name.ValueString() || + plan.Description.ValueString() != state.Description.ValueString() || + plan.Enabled.ValueBool() != state.Enabled.ValueBool() - if !plan.Enabled.IsNull() { - if plan.Enabled.ValueBool() != state.Enabled.ValueBool() { - updateRequest.SetEnabled(plan.Enabled.ValueBool()) - } - } - - if reflect.ValueOf(updateRequest).IsZero() { + if !needsUpdate { resp.Diagnostics.AddWarning("No updatable fields have changed", "Terraform detected a config change, but it is for a field that isn't updatable for the stream resource. Please revert to prior config") return } - stream, _, err := client.StreamsApi.UpdateStreamByUuid(ctx, id).StreamPutRequest(updateRequest).Execute() + updateRequest.SetName(plan.Name.ValueString()) + updateRequest.SetDescription(plan.Description.ValueString()) + updateRequest.SetEnabled(plan.Enabled.ValueBool()) + + _, _, err := client.StreamsApi.UpdateStreamByUuid(ctx, id).StreamPutRequest(updateRequest).Execute() if err != nil { resp.Diagnostics.AddError( fmt.Sprintf("Failed updating Stream %s", id), equinix_errors.FormatFabricError(err).Error()) diff --git a/internal/resources/fabric/stream/resource_schema.go b/internal/resources/fabric/stream/resource_schema.go index f7ba2638d..609714314 100644 --- a/internal/resources/fabric/stream/resource_schema.go +++ b/internal/resources/fabric/stream/resource_schema.go @@ -3,6 +3,7 @@ package stream import ( "context" "github.com/equinix/terraform-provider-equinix/internal/framework" + fwtypes "github.com/equinix/terraform-provider-equinix/internal/framework/types" "github.com/hashicorp/terraform-plugin-framework-timeouts/resource/timeouts" "github.com/hashicorp/terraform-plugin-framework/resource/schema" ) @@ -36,6 +37,7 @@ func resourceSchema(ctx context.Context) schema.Schema { "project": schema.SingleNestedAttribute{ Description: "Equinix Project attribute object", Required: true, + CustomType: fwtypes.NewObjectTypeOf[ProjectModel](ctx), Attributes: map[string]schema.Attribute{ "project_id": schema.StringAttribute{ Description: "Equinix Subscriber-assigned project ID", @@ -66,6 +68,7 @@ func resourceSchema(ctx context.Context) schema.Schema { "change_log": schema.SingleNestedAttribute{ Description: "Details of the last change on the stream resource", Computed: true, + CustomType: fwtypes.NewObjectTypeOf[ChangeLogModel](ctx), Attributes: map[string]schema.Attribute{ "created_by": schema.StringAttribute{ Description: "User name of creator of the stream resource", From f1cca20324e2212b0ac29ed9a2fe40b8c1d8a9cb Mon Sep 17 00:00:00 2001 From: Tim Hogarty Date: Thu, 23 Jan 2025 17:47:41 -0800 Subject: [PATCH 04/13] Add acceptance tests to streams resource and data source --- .../fabric/stream/datasources_schema.go | 4 - .../fabric/stream/datasources_test.go | 96 ++++++++++++++++++ internal/resources/fabric/stream/models.go | 6 -- internal/resources/fabric/stream/resource.go | 15 +-- .../fabric/stream/resource_schema.go | 7 +- .../resources/fabric/stream/resource_test.go | 97 +++++++++++++++++++ 6 files changed, 198 insertions(+), 27 deletions(-) create mode 100644 internal/resources/fabric/stream/datasources_test.go create mode 100644 internal/resources/fabric/stream/resource_test.go diff --git a/internal/resources/fabric/stream/datasources_schema.go b/internal/resources/fabric/stream/datasources_schema.go index 3160b2063..55fffd8ae 100644 --- a/internal/resources/fabric/stream/datasources_schema.go +++ b/internal/resources/fabric/stream/datasources_schema.go @@ -78,10 +78,6 @@ func getStreamSchema(ctx context.Context) map[string]schema.Attribute { Description: "Customer-provided description of the stream resource", Computed: true, }, - "enabled": schema.BoolAttribute{ - Description: "Boolean switch enabling streaming data for the stream resource", - Computed: true, - }, "project": schema.SingleNestedAttribute{ Description: "Equinix Project attribute object", Computed: true, diff --git a/internal/resources/fabric/stream/datasources_test.go b/internal/resources/fabric/stream/datasources_test.go new file mode 100644 index 000000000..c9d3666ef --- /dev/null +++ b/internal/resources/fabric/stream/datasources_test.go @@ -0,0 +1,96 @@ +package stream_test + +import ( + "fmt" + "testing" + + "github.com/equinix/terraform-provider-equinix/internal/acceptance" + "github.com/hashicorp/terraform-plugin-testing/helper/resource" +) + +func testAccFabricStreamDataSourcesConfig(name, description string) string { + return fmt.Sprintf(` + + resource "equinix_fabric_stream" "new_stream_1" { + type = "TELEMETRY_STREAM" + name = "%[1]s" + description = "%[2]s" + } + + resource "equinix_fabric_stream" "new_stream_2" { + type = "TELEMETRY_STREAM" + name = "%[1]s" + description = "%[2]s" + } + + resource "equinix_fabric_stream" "new_stream_3" { + type = "TELEMETRY_STREAM" + name = "%[1]s" + description = "%[2]s" + project = { + project_id = "291639000636552" + } + } + + data "equinix_fabric_stream" "data_stream" { + stream_id = equinix_fabric_stream.new_stream_3.id + } + + data "equinix_fabric_streams" "data_streams" { + depends_on = [equinix_fabric_stream.new_stream_1, equinix_fabric_stream.new_stream_2, equinix_fabric_stream.new_stream_3] + pagination = { + limit = 2 + offset = 1 + } + } + `, name, description) +} + +func TestAccFabricStreamDataSources_PFCR(t *testing.T) { + streamName := "stream_PFCR" + streamDescription := "stream acceptance test PFCR" + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acceptance.TestAccPreCheck(t); acceptance.TestAccPreCheckProviderConfigured(t) }, + ExternalProviders: acceptance.TestExternalProviders, + ProtoV6ProviderFactories: acceptance.ProtoV6ProviderFactories, + CheckDestroy: CheckStreamDelete, + Steps: []resource.TestStep{ + { + Config: testAccFabricStreamDataSourcesConfig(streamName, streamDescription), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr( + "data.equinix_fabric_stream.data_stream", "name", streamName), + resource.TestCheckResourceAttr( + "data.equinix_fabric_stream.data_stream", "type", "TELEMETRY_STREAM"), + resource.TestCheckResourceAttr( + "data.equinix_fabric_stream.data_stream", "project.project_id", "291639000636552"), + resource.TestCheckResourceAttr( + "data.equinix_fabric_stream.data_stream", "description", streamDescription), + resource.TestCheckResourceAttrSet("data.equinix_fabric_stream.data_stream", "id"), + resource.TestCheckResourceAttrSet("data.equinix_fabric_stream.data_stream", "href"), + resource.TestCheckResourceAttrSet("data.equinix_fabric_stream.data_stream", "assets_count"), + resource.TestCheckResourceAttrSet("data.equinix_fabric_stream.data_stream", "stream_subscriptions_count"), + resource.TestCheckResourceAttrSet("data.equinix_fabric_stream.data_stream", "uuid"), + resource.TestCheckResourceAttrSet("data.equinix_fabric_stream.data_stream", "change_log.created_by"), + resource.TestCheckResourceAttrSet("data.equinix_fabric_streams.data_streams", "id"), + resource.TestCheckResourceAttrSet("data.equinix_fabric_streams.data_streams", "data.0.name"), + resource.TestCheckResourceAttrSet("data.equinix_fabric_streams.data_streams", "data.0.type"), + resource.TestCheckResourceAttrSet("data.equinix_fabric_streams.data_streams", "data.0.project.project_id"), + resource.TestCheckResourceAttrSet("data.equinix_fabric_streams.data_streams", "data.0.description"), + resource.TestCheckResourceAttrSet("data.equinix_fabric_streams.data_streams", "data.0.project.project_id"), + resource.TestCheckResourceAttrSet("data.equinix_fabric_streams.data_streams", "data.0.href"), + resource.TestCheckResourceAttrSet("data.equinix_fabric_streams.data_streams", "data.0.assets_count"), + resource.TestCheckResourceAttrSet("data.equinix_fabric_streams.data_streams", "data.0.stream_subscriptions_count"), + resource.TestCheckResourceAttrSet("data.equinix_fabric_streams.data_streams", "data.0.uuid"), + resource.TestCheckResourceAttrSet("data.equinix_fabric_streams.data_streams", "data.0.change_log.created_by"), + resource.TestCheckResourceAttr("data.equinix_fabric_streams.data_streams", "data.#", "2"), + resource.TestCheckResourceAttr("data.equinix_fabric_streams.data_streams", "pagination.%", "5"), + resource.TestCheckResourceAttr("data.equinix_fabric_streams.data_streams", "pagination.limit", "2"), + resource.TestCheckResourceAttr("data.equinix_fabric_streams.data_streams", "pagination.offset", "1"), + ), + ExpectNonEmptyPlan: true, + }, + }, + }) + +} diff --git a/internal/resources/fabric/stream/models.go b/internal/resources/fabric/stream/models.go index 2882e2531..fa42b74ae 100644 --- a/internal/resources/fabric/stream/models.go +++ b/internal/resources/fabric/stream/models.go @@ -43,7 +43,6 @@ type BaseStreamModel struct { Href types.String `tfsdk:"href"` Uuid types.String `tfsdk:"uuid"` State types.String `tfsdk:"state"` - Enabled types.Bool `tfsdk:"enabled"` AssetsCount types.Int32 `tfsdk:"assets_count"` StreamSubscriptionsCount types.Int32 `tfsdk:"stream_subscriptions_count"` Project fwtypes.ObjectValueOf[ProjectModel] `tfsdk:"project"` // Object of ProjectModel @@ -82,7 +81,6 @@ func (m *DataSourceByIdModel) parse(ctx context.Context, stream *fabricv4.Stream &m.Href, &m.Uuid, &m.State, - &m.Enabled, &m.AssetsCount, &m.StreamSubscriptionsCount, &m.Project, @@ -135,7 +133,6 @@ func (m *ResourceModel) parse(ctx context.Context, stream *fabricv4.Stream) diag &m.Href, &m.Uuid, &m.State, - &m.Enabled, &m.AssetsCount, &m.StreamSubscriptionsCount, &m.Project, @@ -157,7 +154,6 @@ func (m *BaseStreamModel) parse(ctx context.Context, stream *fabricv4.Stream) di &m.Href, &m.Uuid, &m.State, - &m.Enabled, &m.AssetsCount, &m.StreamSubscriptionsCount, &m.Project, @@ -171,7 +167,6 @@ func (m *BaseStreamModel) parse(ctx context.Context, stream *fabricv4.Stream) di func parseStream(ctx context.Context, stream *fabricv4.Stream, type_, name, description, href, uuid, state *basetypes.StringValue, - enabled *basetypes.BoolValue, assetsCount, streamSubscriptionCount *basetypes.Int32Value, project *fwtypes.ObjectValueOf[ProjectModel], changeLog *fwtypes.ObjectValueOf[ChangeLogModel]) diag.Diagnostics { @@ -184,7 +179,6 @@ func parseStream(ctx context.Context, stream *fabricv4.Stream, *href = types.StringValue(stream.GetHref()) *uuid = types.StringValue(stream.GetUuid()) *state = types.StringValue(stream.GetState()) - *enabled = types.BoolValue(stream.GetEnabled()) *assetsCount = types.Int32Value(stream.GetAssetsCount()) *streamSubscriptionCount = types.Int32Value(stream.GetStreamSubscriptionsCount()) diff --git a/internal/resources/fabric/stream/resource.go b/internal/resources/fabric/stream/resource.go index 9b46e064b..e08af5001 100644 --- a/internal/resources/fabric/stream/resource.go +++ b/internal/resources/fabric/stream/resource.go @@ -53,11 +53,6 @@ func (r *Resource) Create( // Retrieve the API client from the provider metadata client := r.Meta.NewFabricClientForFramework(ctx, req.ProviderMeta) - var project ProjectModel - diags = plan.Project.As(ctx, &project, basetypes.ObjectAsOptions{}) - if diags.HasError() { - return - } createRequest, diags := buildCreateRequest(ctx, plan) if diags.HasError() { @@ -154,8 +149,7 @@ func (r *Resource) Update( updateRequest := fabricv4.StreamPutRequest{} needsUpdate := plan.Name.ValueString() != state.Name.ValueString() || - plan.Description.ValueString() != state.Description.ValueString() || - plan.Enabled.ValueBool() != state.Enabled.ValueBool() + plan.Description.ValueString() != state.Description.ValueString() if !needsUpdate { resp.Diagnostics.AddWarning("No updatable fields have changed", @@ -165,7 +159,6 @@ func (r *Resource) Update( updateRequest.SetName(plan.Name.ValueString()) updateRequest.SetDescription(plan.Description.ValueString()) - updateRequest.SetEnabled(plan.Enabled.ValueBool()) _, _, err := client.StreamsApi.UpdateStreamByUuid(ctx, id).StreamPutRequest(updateRequest).Execute() if err != nil { @@ -247,11 +240,9 @@ func buildCreateRequest(ctx context.Context, plan ResourceModel) (fabricv4.Strea request.SetName(plan.Name.ValueString()) request.SetType(fabricv4.StreamPostRequestType(plan.Type.ValueString())) request.SetDescription(plan.Description.ValueString()) - if !plan.Enabled.IsNull() { - request.SetEnabled(plan.Enabled.ValueBool()) - } + var project ProjectModel - if !plan.Project.IsNull() { + if !plan.Project.IsNull() && !plan.Project.IsUnknown() { diags = plan.Project.As(ctx, &project, basetypes.ObjectAsOptions{}) if diags.HasError() { return fabricv4.StreamPostRequest{}, diags diff --git a/internal/resources/fabric/stream/resource_schema.go b/internal/resources/fabric/stream/resource_schema.go index 609714314..d4cbcb0c1 100644 --- a/internal/resources/fabric/stream/resource_schema.go +++ b/internal/resources/fabric/stream/resource_schema.go @@ -30,13 +30,10 @@ func resourceSchema(ctx context.Context) schema.Schema { Description: "Customer-provided description of the stream resource", Required: true, }, - "enabled": schema.BoolAttribute{ - Description: "Boolean switch enabling streaming data for the stream resource", - Required: true, - }, "project": schema.SingleNestedAttribute{ Description: "Equinix Project attribute object", - Required: true, + Optional: true, + Computed: true, CustomType: fwtypes.NewObjectTypeOf[ProjectModel](ctx), Attributes: map[string]schema.Attribute{ "project_id": schema.StringAttribute{ diff --git a/internal/resources/fabric/stream/resource_test.go b/internal/resources/fabric/stream/resource_test.go new file mode 100644 index 000000000..9208ac431 --- /dev/null +++ b/internal/resources/fabric/stream/resource_test.go @@ -0,0 +1,97 @@ +package stream_test + +import ( + "context" + "fmt" + "github.com/equinix/equinix-sdk-go/services/fabricv4" + "testing" + + "github.com/equinix/terraform-provider-equinix/internal/acceptance" + "github.com/equinix/terraform-provider-equinix/internal/config" + + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-plugin-testing/terraform" +) + +func CheckStreamDelete(s *terraform.State) error { + ctx := context.Background() + client := acceptance.TestAccProvider.Meta().(*config.Config).NewFabricClientForTesting(ctx) + + for _, rs := range s.RootModule().Resources { + if rs.Type != "equinix_fabric_stream" { + continue + } + + if stream, _, err := client.StreamsApi.GetStreamByUuid(ctx, rs.Primary.ID).Execute(); err == nil && + stream.GetState() == string(fabricv4.STREAMSUBSCRIPTIONSTATE_PROVISIONED) { + return fmt.Errorf("fabric stream %s still exists and is %s", + rs.Primary.ID, string(fabricv4.STREAMSUBSCRIPTIONSTATE_PROVISIONED)) + } + } + return nil +} + +func testAccFabricStreamConfig(name, description string) string { + return fmt.Sprintf(` + resource "equinix_fabric_stream" "new_stream" { + type = "TELEMETRY_STREAM" + name = "%s" + description = "%s" + project = { + project_id = "291639000636552" + } + } + `, name, description) +} + +func TestAccFabricStream_PFCR(t *testing.T) { + streamName, updatedStreamName := "stream_PFCR", "stream_up_PFCR" + streamDescription, updatedStreamDescription := "stream acceptance test PFCR", "updated stream acceptance test PFCR" + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acceptance.TestAccPreCheck(t); acceptance.TestAccPreCheckProviderConfigured(t) }, + ExternalProviders: acceptance.TestExternalProviders, + ProtoV6ProviderFactories: acceptance.ProtoV6ProviderFactories, + CheckDestroy: CheckStreamDelete, + Steps: []resource.TestStep{ + { + Config: testAccFabricStreamConfig(streamName, streamDescription), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr( + "equinix_fabric_stream.new_stream", "name", streamName), + resource.TestCheckResourceAttr( + "equinix_fabric_stream.new_stream", "type", "TELEMETRY_STREAM"), + resource.TestCheckResourceAttr( + "equinix_fabric_stream.new_stream", "project.project_id", "291639000636552"), + resource.TestCheckResourceAttr( + "equinix_fabric_stream.new_stream", "description", streamDescription), + resource.TestCheckResourceAttrSet("equinix_fabric_stream.new_stream", "id"), + resource.TestCheckResourceAttrSet("equinix_fabric_stream.new_stream", "href"), + resource.TestCheckResourceAttrSet("equinix_fabric_stream.new_stream", "assets_count"), + resource.TestCheckResourceAttrSet("equinix_fabric_stream.new_stream", "stream_subscriptions_count"), + resource.TestCheckResourceAttrSet("equinix_fabric_stream.new_stream", "uuid"), + resource.TestCheckResourceAttrSet("equinix_fabric_stream.new_stream", "change_log.created_by"), + ), + ExpectNonEmptyPlan: false, + }, + { + Config: testAccFabricStreamConfig(updatedStreamName, updatedStreamDescription), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr( + "equinix_fabric_stream.new_stream", "name", updatedStreamName), + resource.TestCheckResourceAttr( + "equinix_fabric_stream.new_stream", "project.project_id", "291639000636552"), + resource.TestCheckResourceAttr( + "equinix_fabric_stream.new_stream", "description", updatedStreamDescription), + resource.TestCheckResourceAttrSet("equinix_fabric_stream.new_stream", "id"), + resource.TestCheckResourceAttrSet("equinix_fabric_stream.new_stream", "href"), + resource.TestCheckResourceAttrSet("equinix_fabric_stream.new_stream", "assets_count"), + resource.TestCheckResourceAttrSet("equinix_fabric_stream.new_stream", "stream_subscriptions_count"), + resource.TestCheckResourceAttrSet("equinix_fabric_stream.new_stream", "uuid"), + resource.TestCheckResourceAttrSet("equinix_fabric_stream.new_stream", "change_log.created_by"), + ), + ExpectNonEmptyPlan: false, + }, + }, + }) + +} From 2f8b5ae02a714d3b3ecfe131b3667d91b56622dd Mon Sep 17 00:00:00 2001 From: Tim Hogarty Date: Thu, 23 Jan 2025 21:59:38 -0800 Subject: [PATCH 05/13] Add docs for fabric stream resource and data sources --- docs/data-sources/fabric_stream.md | 70 ++++++++++++++ docs/data-sources/fabric_streams.md | 95 +++++++++++++++++++ docs/resources/fabric_stream.md | 89 +++++++++++++++++ .../equinix_fabric_stream/data-source.tf | 7 ++ .../equinix_fabric_streams/data-source.tf | 10 ++ .../equinix_fabric_stream/resource.tf | 12 +++ .../fabric/stream/datasources_schema.go | 10 ++ .../fabric/stream/resource_schema.go | 5 + 8 files changed, 298 insertions(+) create mode 100644 docs/data-sources/fabric_stream.md create mode 100644 docs/data-sources/fabric_streams.md create mode 100644 docs/resources/fabric_stream.md create mode 100644 examples/data-sources/equinix_fabric_stream/data-source.tf create mode 100644 examples/data-sources/equinix_fabric_streams/data-source.tf create mode 100644 examples/resources/equinix_fabric_stream/resource.tf diff --git a/docs/data-sources/fabric_stream.md b/docs/data-sources/fabric_stream.md new file mode 100644 index 000000000..cdc965c74 --- /dev/null +++ b/docs/data-sources/fabric_stream.md @@ -0,0 +1,70 @@ +--- +subcategory: "Fabric" +--- + +# equinix_fabric_stream (Data Source) + +Fabric V4 API compatible data resource that allow user to fetch Equinix Fabric Stream by UUID + +Additional Documentation: +* Getting Started: TODO +* API: TODO + +## Example Usage + +```terraform +data "equinix_fabric_stream" "data_stream" { + stream_id = "" +} + +output "stream_state" { + value = data.equinix_fabric_stream.data_stream.state +} +``` + + +## Schema + +### Required + +- `stream_id` (String) The uuid of the stream this data source should retrieve + +### Read-Only + +- `assets_count` (Number) Count of the streaming assets attached to the stream resource +- `change_log` (Attributes) Details of the last change on the stream resource (see [below for nested schema](#nestedatt--change_log)) +- `description` (String) Customer-provided description of the stream resource +- `href` (String) Equinix auto generated URI to the stream resource in Equinix Portal +- `id` (String) The unique identifier of the resource +- `name` (String) Customer-provided name of the stream resource +- `project` (Attributes) Equinix Project attribute object (see [below for nested schema](#nestedatt--project)) +- `state` (String) Value representing provisioning status for the stream resource +- `stream_subscriptions_count` (Number) Count of the client subscriptions on the stream resource +- `type` (String) Equinix defined Streaming Type +- `uuid` (String) Equinix-assigned unique id for the stream resource + + +### Nested Schema for `change_log` + +Read-Only: + +- `created_by` (String) User name of creator of the stream resource +- `created_by_email` (String) Email of creator of the stream resource +- `created_by_full_name` (String) Legal name of creator of the stream resource +- `created_date_time` (String) Creation time of the stream resource +- `deleted_by` (String) User name of deleter of the stream resource +- `deleted_by_email` (String) Email of deleter of the stream resource +- `deleted_by_full_name` (String) Legal name of deleter of the stream resource +- `deleted_date_time` (String) Deletion time of the stream resource +- `updated_by` (String) User name of last updater of the stream resource +- `updated_by_email` (String) Email of last updater of the stream resource +- `updated_by_full_name` (String) Legal name of last updater of the stream resource +- `updated_date_time` (String) Last update time of the stream resource + + + +### Nested Schema for `project` + +Read-Only: + +- `project_id` (String) Equinix Subscriber-assigned project ID diff --git a/docs/data-sources/fabric_streams.md b/docs/data-sources/fabric_streams.md new file mode 100644 index 000000000..9166fd51a --- /dev/null +++ b/docs/data-sources/fabric_streams.md @@ -0,0 +1,95 @@ +--- +subcategory: "Fabric" +--- + +# equinix_fabric_streams (Data Source) + +Fabric V4 API compatible data resource that allow user to fetch Equinix Fabric Streams with pagination details + +Additional Documentation: +* Getting Started: TODO +* API: TODO + +## Example Usage + +```terraform +data "equinix_fabric_streams" "data_streams" { + pagination = { + limit = 2 + offset = 1 + } +} + +output "number_of_returned_streams" { + value = length(data.equinix_fabric_streams.data_streams.data) +} +``` + + +## Schema + +### Required + +- `pagination` (Attributes) Pagination details for the returned streams list (see [below for nested schema](#nestedatt--pagination)) + +### Read-Only + +- `data` (Attributes List) Returned list of stream objects (see [below for nested schema](#nestedatt--data)) +- `id` (String) The unique identifier of the resource + + +### Nested Schema for `pagination` + +Optional: + +- `limit` (Number) Maximum number of search results returned per page. Number must be between 1 and 100, and the default is 20 +- `offset` (Number) Index of the first item returned in the response. The default is 0 + +Read-Only: + +- `next` (String) The URL relative to the next item in the response +- `previous` (String) The URL relative to the previous item in the response +- `total` (Number) The total number of streams available to the user making the request + + + +### Nested Schema for `data` + +Read-Only: + +- `assets_count` (Number) Count of the streaming assets attached to the stream resource +- `change_log` (Attributes) Details of the last change on the stream resource (see [below for nested schema](#nestedatt--data--change_log)) +- `description` (String) Customer-provided description of the stream resource +- `href` (String) Equinix auto generated URI to the stream resource in Equinix Portal +- `name` (String) Customer-provided name of the stream resource +- `project` (Attributes) Equinix Project attribute object (see [below for nested schema](#nestedatt--data--project)) +- `state` (String) Value representing provisioning status for the stream resource +- `stream_subscriptions_count` (Number) Count of the client subscriptions on the stream resource +- `type` (String) Equinix defined Streaming Type +- `uuid` (String) Equinix-assigned unique id for the stream resource + + +### Nested Schema for `data.change_log` + +Read-Only: + +- `created_by` (String) User name of creator of the stream resource +- `created_by_email` (String) Email of creator of the stream resource +- `created_by_full_name` (String) Legal name of creator of the stream resource +- `created_date_time` (String) Creation time of the stream resource +- `deleted_by` (String) User name of deleter of the stream resource +- `deleted_by_email` (String) Email of deleter of the stream resource +- `deleted_by_full_name` (String) Legal name of deleter of the stream resource +- `deleted_date_time` (String) Deletion time of the stream resource +- `updated_by` (String) User name of last updater of the stream resource +- `updated_by_email` (String) Email of last updater of the stream resource +- `updated_by_full_name` (String) Legal name of last updater of the stream resource +- `updated_date_time` (String) Last update time of the stream resource + + + +### Nested Schema for `data.project` + +Read-Only: + +- `project_id` (String) Equinix Subscriber-assigned project ID diff --git a/docs/resources/fabric_stream.md b/docs/resources/fabric_stream.md new file mode 100644 index 000000000..a8d0f96a2 --- /dev/null +++ b/docs/resources/fabric_stream.md @@ -0,0 +1,89 @@ +--- +subcategory: "Fabric" +--- + +# equinix_fabric_stream (Resource) + +Fabric V4 API compatible resource allows creation and management of Equinix Fabric Stream + +Additional Documentation: +* Getting Started: TODO +* API: TODO + +## Example Usage + +```terraform +resource "equinix_fabric_stream" "new_stream" { + type = "TELEMETRY_STREAM" + name = "" + description = "" + project = { + project_id = " +## Schema + +### Required + +- `description` (String) Customer-provided description of the stream resource +- `name` (String) Customer-provided name of the stream resource +- `type` (String) Equinix defined Streaming Type + +### Optional + +- `project` (Attributes) Equinix Project attribute object (see [below for nested schema](#nestedatt--project)) +- `timeouts` (Attributes) (see [below for nested schema](#nestedatt--timeouts)) + +### Read-Only + +- `assets_count` (Number) Count of the streaming assets attached to the stream resource +- `change_log` (Attributes) Details of the last change on the stream resource (see [below for nested schema](#nestedatt--change_log)) +- `href` (String) Equinix auto generated URI to the stream resource in Equinix Portal +- `id` (String) The unique identifier of the resource +- `state` (String) Value representing provisioning status for the stream resource +- `stream_subscriptions_count` (Number) Count of the client subscriptions on the stream resource +- `uuid` (String) Equinix-assigned unique id for the stream resource + + +### Nested Schema for `project` + +Required: + +- `project_id` (String) Equinix Subscriber-assigned project ID + + + +### Nested Schema for `timeouts` + +Optional: + +- `create` (String) A string that can be [parsed as a duration](https://pkg.go.dev/time#ParseDuration) consisting of numbers and unit suffixes, such as "30s" or "2h45m". Valid time units are "s" (seconds), "m" (minutes), "h" (hours). +- `delete` (String) A string that can be [parsed as a duration](https://pkg.go.dev/time#ParseDuration) consisting of numbers and unit suffixes, such as "30s" or "2h45m". Valid time units are "s" (seconds), "m" (minutes), "h" (hours). Setting a timeout for a Delete operation is only applicable if changes are saved into state before the destroy operation occurs. +- `read` (String) A string that can be [parsed as a duration](https://pkg.go.dev/time#ParseDuration) consisting of numbers and unit suffixes, such as "30s" or "2h45m". Valid time units are "s" (seconds), "m" (minutes), "h" (hours). Read operations occur during any refresh or planning operation when refresh is enabled. +- `update` (String) A string that can be [parsed as a duration](https://pkg.go.dev/time#ParseDuration) consisting of numbers and unit suffixes, such as "30s" or "2h45m". Valid time units are "s" (seconds), "m" (minutes), "h" (hours). + + + +### Nested Schema for `change_log` + +Read-Only: + +- `created_by` (String) User name of creator of the stream resource +- `created_by_email` (String) Email of creator of the stream resource +- `created_by_full_name` (String) Legal name of creator of the stream resource +- `created_date_time` (String) Creation time of the stream resource +- `deleted_by` (String) User name of deleter of the stream resource +- `deleted_by_email` (String) Email of deleter of the stream resource +- `deleted_by_full_name` (String) Legal name of deleter of the stream resource +- `deleted_date_time` (String) Deletion time of the stream resource +- `updated_by` (String) User name of last updater of the stream resource +- `updated_by_email` (String) Email of last updater of the stream resource +- `updated_by_full_name` (String) Legal name of last updater of the stream resource +- `updated_date_time` (String) Last update time of the stream resource diff --git a/examples/data-sources/equinix_fabric_stream/data-source.tf b/examples/data-sources/equinix_fabric_stream/data-source.tf new file mode 100644 index 000000000..1342b3dbf --- /dev/null +++ b/examples/data-sources/equinix_fabric_stream/data-source.tf @@ -0,0 +1,7 @@ +data "equinix_fabric_stream" "data_stream" { + stream_id = "" +} + +output "stream_state" { + value = data.equinix_fabric_stream.data_stream.state +} diff --git a/examples/data-sources/equinix_fabric_streams/data-source.tf b/examples/data-sources/equinix_fabric_streams/data-source.tf new file mode 100644 index 000000000..7ffb5623b --- /dev/null +++ b/examples/data-sources/equinix_fabric_streams/data-source.tf @@ -0,0 +1,10 @@ +data "equinix_fabric_streams" "data_streams" { + pagination = { + limit = 2 + offset = 1 + } +} + +output "number_of_returned_streams" { + value = length(data.equinix_fabric_streams.data_streams.data) +} diff --git a/examples/resources/equinix_fabric_stream/resource.tf b/examples/resources/equinix_fabric_stream/resource.tf new file mode 100644 index 000000000..54351db23 --- /dev/null +++ b/examples/resources/equinix_fabric_stream/resource.tf @@ -0,0 +1,12 @@ +resource "equinix_fabric_stream" "new_stream" { + type = "TELEMETRY_STREAM" + name = "" + description = "" + project = { + project_id = " Date: Fri, 24 Jan 2025 15:29:18 -0800 Subject: [PATCH 06/13] Finish stream resource and data source dev --- docs/data-sources/fabric_stream.md | 4 +-- docs/data-sources/fabric_streams.md | 4 +-- docs/resources/fabric_stream.md | 4 +-- .../fabric/stream/datasource_all_streams.go | 5 +-- .../fabric/stream/datasource_by_streamid.go | 5 +-- .../fabric/stream/datasources_schema.go | 10 +++--- internal/resources/fabric/stream/models.go | 11 +++++- internal/resources/fabric/stream/resource.go | 6 ++-- .../fabric/stream/resource_schema.go | 35 ++++++++++++++++--- .../resources/fabric/stream/resource_test.go | 3 +- 10 files changed, 65 insertions(+), 22 deletions(-) diff --git a/docs/data-sources/fabric_stream.md b/docs/data-sources/fabric_stream.md index cdc965c74..627b5adad 100644 --- a/docs/data-sources/fabric_stream.md +++ b/docs/data-sources/fabric_stream.md @@ -7,8 +7,8 @@ subcategory: "Fabric" Fabric V4 API compatible data resource that allow user to fetch Equinix Fabric Stream by UUID Additional Documentation: -* Getting Started: TODO -* API: TODO +* Getting Started: https://docs.equinix.com/en-us/Content/KnowledgeCenter/Fabric/GettingStarted/Integrating-with-Fabric-V4-APIs/IntegrateWithSink.htm +* API: https://developer.equinix.com/catalog/fabricv4#tag/Streams ## Example Usage diff --git a/docs/data-sources/fabric_streams.md b/docs/data-sources/fabric_streams.md index 9166fd51a..744e8be29 100644 --- a/docs/data-sources/fabric_streams.md +++ b/docs/data-sources/fabric_streams.md @@ -7,8 +7,8 @@ subcategory: "Fabric" Fabric V4 API compatible data resource that allow user to fetch Equinix Fabric Streams with pagination details Additional Documentation: -* Getting Started: TODO -* API: TODO +* Getting Started: https://docs.equinix.com/en-us/Content/KnowledgeCenter/Fabric/GettingStarted/Integrating-with-Fabric-V4-APIs/IntegrateWithSink.htm +* API: https://developer.equinix.com/catalog/fabricv4#tag/Streams ## Example Usage diff --git a/docs/resources/fabric_stream.md b/docs/resources/fabric_stream.md index a8d0f96a2..4fcf9bf7a 100644 --- a/docs/resources/fabric_stream.md +++ b/docs/resources/fabric_stream.md @@ -7,8 +7,8 @@ subcategory: "Fabric" Fabric V4 API compatible resource allows creation and management of Equinix Fabric Stream Additional Documentation: -* Getting Started: TODO -* API: TODO +* Getting Started: https://docs.equinix.com/en-us/Content/KnowledgeCenter/Fabric/GettingStarted/Integrating-with-Fabric-V4-APIs/IntegrateWithSink.htm +* API: https://developer.equinix.com/catalog/fabricv4#tag/Streams ## Example Usage diff --git a/internal/resources/fabric/stream/datasource_all_streams.go b/internal/resources/fabric/stream/datasource_all_streams.go index 9c9deaf08..08c689111 100644 --- a/internal/resources/fabric/stream/datasource_all_streams.go +++ b/internal/resources/fabric/stream/datasource_all_streams.go @@ -2,11 +2,12 @@ package stream import ( "context" + equinix_errors "github.com/equinix/terraform-provider-equinix/internal/errors" "github.com/equinix/terraform-provider-equinix/internal/framework" + "github.com/hashicorp/terraform-plugin-framework/datasource" "github.com/hashicorp/terraform-plugin-framework/types/basetypes" - "github.com/hashicorp/terraform-plugin-sdk/v2/diag" ) func NewDataSourceAllStreams() datasource.DataSource { @@ -57,7 +58,7 @@ func (r *DataSourceAllStreams) Read(ctx context.Context, request datasource.Read if err != nil { response.State.RemoveResource(ctx) - diag.FromErr(equinix_errors.FormatFabricError(err)) + response.Diagnostics.AddError("api error retrieving streams data", equinix_errors.FormatFabricError(err).Error()) return } diff --git a/internal/resources/fabric/stream/datasource_by_streamid.go b/internal/resources/fabric/stream/datasource_by_streamid.go index 508db8a05..1e4a09c64 100644 --- a/internal/resources/fabric/stream/datasource_by_streamid.go +++ b/internal/resources/fabric/stream/datasource_by_streamid.go @@ -2,10 +2,11 @@ package stream import ( "context" + equinix_errors "github.com/equinix/terraform-provider-equinix/internal/errors" "github.com/equinix/terraform-provider-equinix/internal/framework" + "github.com/hashicorp/terraform-plugin-framework/datasource" - "github.com/hashicorp/terraform-plugin-sdk/v2/diag" ) func NewDataSourceByStreamID() datasource.DataSource { @@ -47,7 +48,7 @@ func (r *DataSourceByStreamID) Read(ctx context.Context, request datasource.Read if err != nil { response.State.RemoveResource(ctx) - diag.FromErr(equinix_errors.FormatFabricError(err)) + response.Diagnostics.AddError("api error retrieving stream data", equinix_errors.FormatFabricError(err).Error()) return } diff --git a/internal/resources/fabric/stream/datasources_schema.go b/internal/resources/fabric/stream/datasources_schema.go index b4323b4fa..9362a0522 100644 --- a/internal/resources/fabric/stream/datasources_schema.go +++ b/internal/resources/fabric/stream/datasources_schema.go @@ -2,8 +2,10 @@ package stream import ( "context" + "github.com/equinix/terraform-provider-equinix/internal/framework" fwtypes "github.com/equinix/terraform-provider-equinix/internal/framework/types" + "github.com/hashicorp/terraform-plugin-framework/datasource/schema" ) @@ -12,8 +14,8 @@ func dataSourceAllStreamsSchema(ctx context.Context) schema.Schema { Description: `Fabric V4 API compatible data resource that allow user to fetch Equinix Fabric Streams with pagination details Additional Documentation: -* Getting Started: TODO -* API: TODO`, +* Getting Started: https://docs.equinix.com/en-us/Content/KnowledgeCenter/Fabric/GettingStarted/Integrating-with-Fabric-V4-APIs/IntegrateWithSink.htm +* API: https://developer.equinix.com/catalog/fabricv4#tag/Streams`, Attributes: map[string]schema.Attribute{ "id": framework.IDAttributeDefaultDescription(), "pagination": schema.SingleNestedAttribute{ @@ -68,8 +70,8 @@ func dataSourceSingleStreamSchema(ctx context.Context) schema.Schema { Description: `Fabric V4 API compatible data resource that allow user to fetch Equinix Fabric Stream by UUID Additional Documentation: -* Getting Started: TODO -* API: TODO`, +* Getting Started: https://docs.equinix.com/en-us/Content/KnowledgeCenter/Fabric/GettingStarted/Integrating-with-Fabric-V4-APIs/IntegrateWithSink.htm +* API: https://developer.equinix.com/catalog/fabricv4#tag/Streams`, Attributes: baseStreamSchema, } } diff --git a/internal/resources/fabric/stream/models.go b/internal/resources/fabric/stream/models.go index fa42b74ae..d754d74e8 100644 --- a/internal/resources/fabric/stream/models.go +++ b/internal/resources/fabric/stream/models.go @@ -2,8 +2,11 @@ package stream import ( "context" - "github.com/equinix/equinix-sdk-go/services/fabricv4" + fwtypes "github.com/equinix/terraform-provider-equinix/internal/framework/types" + + "github.com/equinix/equinix-sdk-go/services/fabricv4" + "github.com/hashicorp/terraform-plugin-framework-timeouts/resource/timeouts" "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/types" @@ -95,6 +98,12 @@ func (m *DataSourceByIdModel) parse(ctx context.Context, stream *fabricv4.Stream func (m *DataSourceAllStreamsModel) parse(ctx context.Context, streamsResponse *fabricv4.GetAllStreamResponse) diag.Diagnostics { var diags diag.Diagnostics + if len(streamsResponse.GetData()) < 1 { + diags.AddError("no data retrieved by streams data source", + "either the account does not have any streams data to pull or the combination of limit and offset needs to be updated") + return diags + } + data := make([]BaseStreamModel, len(streamsResponse.GetData())) streams := streamsResponse.GetData() for index, stream := range streams { diff --git a/internal/resources/fabric/stream/resource.go b/internal/resources/fabric/stream/resource.go index e08af5001..f2133931b 100644 --- a/internal/resources/fabric/stream/resource.go +++ b/internal/resources/fabric/stream/resource.go @@ -3,13 +3,15 @@ package stream import ( "context" "fmt" - equinix_errors "github.com/equinix/terraform-provider-equinix/internal/errors" "net/http" "slices" "time" - "github.com/equinix/equinix-sdk-go/services/fabricv4" + equinix_errors "github.com/equinix/terraform-provider-equinix/internal/errors" "github.com/equinix/terraform-provider-equinix/internal/framework" + + "github.com/equinix/equinix-sdk-go/services/fabricv4" + "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/resource" "github.com/hashicorp/terraform-plugin-framework/types/basetypes" diff --git a/internal/resources/fabric/stream/resource_schema.go b/internal/resources/fabric/stream/resource_schema.go index 3d1e1ec25..5e5018886 100644 --- a/internal/resources/fabric/stream/resource_schema.go +++ b/internal/resources/fabric/stream/resource_schema.go @@ -2,10 +2,16 @@ package stream import ( "context" + "github.com/equinix/terraform-provider-equinix/internal/framework" fwtypes "github.com/equinix/terraform-provider-equinix/internal/framework/types" + "github.com/hashicorp/terraform-plugin-framework-timeouts/resource/timeouts" "github.com/hashicorp/terraform-plugin-framework/resource/schema" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/int32planmodifier" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/objectplanmodifier" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier" ) func resourceSchema(ctx context.Context) schema.Schema { @@ -13,8 +19,8 @@ func resourceSchema(ctx context.Context) schema.Schema { Description: `Fabric V4 API compatible resource allows creation and management of Equinix Fabric Stream Additional Documentation: -* Getting Started: TODO -* API: TODO`, +* Getting Started: https://docs.equinix.com/en-us/Content/KnowledgeCenter/Fabric/GettingStarted/Integrating-with-Fabric-V4-APIs/IntegrateWithSink.htm +* API: https://developer.equinix.com/catalog/fabricv4#tag/Streams`, Attributes: map[string]schema.Attribute{ "id": framework.IDAttributeDefaultDescription(), "timeouts": timeouts.Attributes(ctx, timeouts.Opts{ @@ -39,7 +45,10 @@ Additional Documentation: Description: "Equinix Project attribute object", Optional: true, Computed: true, - CustomType: fwtypes.NewObjectTypeOf[ProjectModel](ctx), + PlanModifiers: []planmodifier.Object{ + objectplanmodifier.UseStateForUnknown(), + }, + CustomType: fwtypes.NewObjectTypeOf[ProjectModel](ctx), Attributes: map[string]schema.Attribute{ "project_id": schema.StringAttribute{ Description: "Equinix Subscriber-assigned project ID", @@ -50,27 +59,45 @@ Additional Documentation: "href": schema.StringAttribute{ Description: "Equinix auto generated URI to the stream resource in Equinix Portal", Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, }, "uuid": schema.StringAttribute{ Description: "Equinix-assigned unique id for the stream resource", Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, }, "state": schema.StringAttribute{ Description: "Value representing provisioning status for the stream resource", Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, }, "assets_count": schema.Int32Attribute{ Description: "Count of the streaming assets attached to the stream resource", Computed: true, + PlanModifiers: []planmodifier.Int32{ + int32planmodifier.UseStateForUnknown(), + }, }, "stream_subscriptions_count": schema.Int32Attribute{ Description: "Count of the client subscriptions on the stream resource", Computed: true, + PlanModifiers: []planmodifier.Int32{ + int32planmodifier.UseStateForUnknown(), + }, }, "change_log": schema.SingleNestedAttribute{ Description: "Details of the last change on the stream resource", Computed: true, - CustomType: fwtypes.NewObjectTypeOf[ChangeLogModel](ctx), + PlanModifiers: []planmodifier.Object{ + objectplanmodifier.UseStateForUnknown(), + }, + CustomType: fwtypes.NewObjectTypeOf[ChangeLogModel](ctx), Attributes: map[string]schema.Attribute{ "created_by": schema.StringAttribute{ Description: "User name of creator of the stream resource", diff --git a/internal/resources/fabric/stream/resource_test.go b/internal/resources/fabric/stream/resource_test.go index 9208ac431..7dbf3cc8a 100644 --- a/internal/resources/fabric/stream/resource_test.go +++ b/internal/resources/fabric/stream/resource_test.go @@ -3,12 +3,13 @@ package stream_test import ( "context" "fmt" - "github.com/equinix/equinix-sdk-go/services/fabricv4" "testing" "github.com/equinix/terraform-provider-equinix/internal/acceptance" "github.com/equinix/terraform-provider-equinix/internal/config" + "github.com/equinix/equinix-sdk-go/services/fabricv4" + "github.com/hashicorp/terraform-plugin-testing/helper/resource" "github.com/hashicorp/terraform-plugin-testing/terraform" ) From d1646bd330c62ae36e92a7ef4cb74b4cfa4457ec Mon Sep 17 00:00:00 2001 From: Tim Hogarty Date: Fri, 24 Jan 2025 15:34:48 -0800 Subject: [PATCH 07/13] Fix linter error; remove fmt.Sprintf --- internal/resources/fabric/stream/resource.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/internal/resources/fabric/stream/resource.go b/internal/resources/fabric/stream/resource.go index f2133931b..b8f82fcd0 100644 --- a/internal/resources/fabric/stream/resource.go +++ b/internal/resources/fabric/stream/resource.go @@ -63,8 +63,7 @@ func (r *Resource) Create( stream, _, err := client.StreamsApi.CreateStreams(ctx).StreamPostRequest(createRequest).Execute() if err != nil { - resp.Diagnostics.AddError( - fmt.Sprintf("Failed creating Stream"), equinix_errors.FormatFabricError(err).Error()) + resp.Diagnostics.AddError("Failed creating Stream", equinix_errors.FormatFabricError(err).Error()) return } From 28e84c84015391b89c3864b94f531568b2d31e62 Mon Sep 17 00:00:00 2001 From: Tim Hogarty Date: Fri, 24 Jan 2025 15:38:15 -0800 Subject: [PATCH 08/13] Fix variable declaration and assignment linting errors --- internal/resources/fabric/stream/models.go | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/internal/resources/fabric/stream/models.go b/internal/resources/fabric/stream/models.go index d754d74e8..f8093c2da 100644 --- a/internal/resources/fabric/stream/models.go +++ b/internal/resources/fabric/stream/models.go @@ -72,12 +72,11 @@ type ChangeLogModel struct { } func (m *DataSourceByIdModel) parse(ctx context.Context, stream *fabricv4.Stream) diag.Diagnostics { - var diags diag.Diagnostics m.StreamID = types.StringValue(stream.GetUuid()) m.ID = types.StringValue(stream.GetUuid()) - diags = parseStream(ctx, stream, + diags := parseStream(ctx, stream, &m.Type, &m.Name, &m.Description, @@ -131,11 +130,9 @@ func (m *DataSourceAllStreamsModel) parse(ctx context.Context, streamsResponse * } func (m *ResourceModel) parse(ctx context.Context, stream *fabricv4.Stream) diag.Diagnostics { - var diags diag.Diagnostics - m.ID = types.StringValue(stream.GetUuid()) - diags = parseStream(ctx, stream, + diags := parseStream(ctx, stream, &m.Type, &m.Name, &m.Description, @@ -154,9 +151,7 @@ func (m *ResourceModel) parse(ctx context.Context, stream *fabricv4.Stream) diag } func (m *BaseStreamModel) parse(ctx context.Context, stream *fabricv4.Stream) diag.Diagnostics { - var diags diag.Diagnostics - - diags = parseStream(ctx, stream, + diags := parseStream(ctx, stream, &m.Type, &m.Name, &m.Description, From 955f9c00dc7c430e8587c120b185209e42485939 Mon Sep 17 00:00:00 2001 From: Tim Hogarty Date: Fri, 24 Jan 2025 17:09:51 -0800 Subject: [PATCH 09/13] Add test sweeper for stream resource --- internal/resources/fabric/stream/sweeper.go | 55 +++++++++++++++++++++ internal/sweep/sweep_test.go | 2 + 2 files changed, 57 insertions(+) create mode 100644 internal/resources/fabric/stream/sweeper.go diff --git a/internal/resources/fabric/stream/sweeper.go b/internal/resources/fabric/stream/sweeper.go new file mode 100644 index 000000000..6c855c737 --- /dev/null +++ b/internal/resources/fabric/stream/sweeper.go @@ -0,0 +1,55 @@ +package stream + +import ( + "context" + "errors" + "fmt" + "log" + "net/http" + + equinix_errors "github.com/equinix/terraform-provider-equinix/internal/errors" + "github.com/equinix/terraform-provider-equinix/internal/sweep" + + "github.com/hashicorp/terraform-plugin-testing/helper/resource" +) + +func AddTestSweeper() { + resource.AddTestSweepers("equinix_fabric_stream", &resource.Sweeper{ + Name: "equinix_fabric_stream", + Dependencies: []string{}, + F: testSweepStreams, + }) +} + +func testSweepStreams(region string) error { + var errs []error + log.Printf("[DEBUG] Sweeping Fabric Streams") + ctx := context.Background() + meta, err := sweep.GetConfigForFabric() + if err != nil { + return fmt.Errorf("error getting configuration for sweeping Streams: %s", err) + } + configLoadErr := meta.Load(ctx) + if configLoadErr != nil { + return fmt.Errorf("error loading configuration for sweeping Streams: %s", err) + } + fabric := meta.NewFabricClientForTesting(ctx) + limit := int32(100) + + streams, _, err := fabric.StreamsApi.GetStreams(ctx).Limit(limit).Execute() + if err != nil { + return fmt.Errorf("error getting streams list for sweeping fabric streams: %s", err) + } + + for _, stream := range streams.GetData() { + if sweep.IsSweepableFabricTestResource(stream.GetName()) { + log.Printf("[DEBUG] Deleting stream: %s", stream.GetName()) + _, resp, err := fabric.StreamsApi.DeleteStreamByUuid(ctx, stream.GetUuid()).Execute() + if equinix_errors.IgnoreHttpResponseErrors(http.StatusForbidden, http.StatusNotFound)(resp, err) != nil { + errs = append(errs, fmt.Errorf("error deleting fabric stream: %s", err)) + } + } + } + + return errors.Join(errs...) +} diff --git a/internal/sweep/sweep_test.go b/internal/sweep/sweep_test.go index b71b5cc8e..411ff764c 100644 --- a/internal/sweep/sweep_test.go +++ b/internal/sweep/sweep_test.go @@ -6,6 +6,7 @@ import ( fabric_cloud_router "github.com/equinix/terraform-provider-equinix/internal/resources/fabric/cloud_router" fabric_connection "github.com/equinix/terraform-provider-equinix/internal/resources/fabric/connection" fabric_route_filter "github.com/equinix/terraform-provider-equinix/internal/resources/fabric/route_filter" + fabric_stream "github.com/equinix/terraform-provider-equinix/internal/resources/fabric/stream" "github.com/equinix/terraform-provider-equinix/internal/resources/metal/connection" "github.com/equinix/terraform-provider-equinix/internal/resources/metal/device" @@ -33,6 +34,7 @@ func addTestSweepers() { fabric_cloud_router.AddTestSweeper() fabric_connection.AddTestSweeper() fabric_route_filter.AddTestSweeper() + fabric_stream.AddTestSweeper() organization.AddTestSweeper() project.AddTestSweeper() ssh_key.AddTestSweeper() From f485a2b767619bf7e38fa2be1274a04822c2079c Mon Sep 17 00:00:00 2001 From: Tim Hogarty Date: Wed, 29 Jan 2025 14:48:50 -0800 Subject: [PATCH 10/13] Update const to match Go styling guide and update tests for plan modifications --- internal/resources/fabric/stream/models.go | 10 +++++----- .../resources/fabric/stream/resource_schema.go | 15 +-------------- internal/resources/fabric/stream/resource_test.go | 2 -- 3 files changed, 6 insertions(+), 21 deletions(-) diff --git a/internal/resources/fabric/stream/models.go b/internal/resources/fabric/stream/models.go index f8093c2da..2b4232059 100644 --- a/internal/resources/fabric/stream/models.go +++ b/internal/resources/fabric/stream/models.go @@ -192,21 +192,21 @@ func parseStream(ctx context.Context, stream *fabricv4.Stream, } *project = fwtypes.NewObjectValueOf[ProjectModel](ctx, &projectModel) - const TIMEFORMAT = "2006-01-02T15:04:05.000Z" - streamChangeLog := stream.GetChangelog() + const TimeFormat = "2006-01-02T15:04:05.000Z" + streamChangeLog := stream.GetChangeLog() changeLogModel := ChangeLogModel{ CreatedBy: types.StringValue(streamChangeLog.GetCreatedBy()), CreatedByFullName: types.StringValue(streamChangeLog.GetCreatedByFullName()), CreatedByEmail: types.StringValue(streamChangeLog.GetCreatedByEmail()), - CreatedDateTime: types.StringValue(streamChangeLog.GetCreatedDateTime().Format(TIMEFORMAT)), + CreatedDateTime: types.StringValue(streamChangeLog.GetCreatedDateTime().Format(TimeFormat)), UpdatedBy: types.StringValue(streamChangeLog.GetUpdatedBy()), UpdatedByFullName: types.StringValue(streamChangeLog.GetUpdatedByFullName()), UpdatedByEmail: types.StringValue(streamChangeLog.GetUpdatedByEmail()), - UpdatedDateTime: types.StringValue(streamChangeLog.GetUpdatedDateTime().Format(TIMEFORMAT)), + UpdatedDateTime: types.StringValue(streamChangeLog.GetUpdatedDateTime().Format(TimeFormat)), DeletedBy: types.StringValue(streamChangeLog.GetDeletedBy()), DeletedByFullName: types.StringValue(streamChangeLog.GetDeletedByFullName()), DeletedByEmail: types.StringValue(streamChangeLog.GetDeletedByEmail()), - DeletedDateTime: types.StringValue(streamChangeLog.GetDeletedDateTime().Format(TIMEFORMAT)), + DeletedDateTime: types.StringValue(streamChangeLog.GetDeletedDateTime().Format(TimeFormat)), } *changeLog = fwtypes.NewObjectValueOf[ChangeLogModel](ctx, &changeLogModel) return diag diff --git a/internal/resources/fabric/stream/resource_schema.go b/internal/resources/fabric/stream/resource_schema.go index 5e5018886..6cc6a0a9d 100644 --- a/internal/resources/fabric/stream/resource_schema.go +++ b/internal/resources/fabric/stream/resource_schema.go @@ -8,7 +8,6 @@ import ( "github.com/hashicorp/terraform-plugin-framework-timeouts/resource/timeouts" "github.com/hashicorp/terraform-plugin-framework/resource/schema" - "github.com/hashicorp/terraform-plugin-framework/resource/schema/int32planmodifier" "github.com/hashicorp/terraform-plugin-framework/resource/schema/objectplanmodifier" "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier" @@ -73,31 +72,19 @@ Additional Documentation: "state": schema.StringAttribute{ Description: "Value representing provisioning status for the stream resource", Computed: true, - PlanModifiers: []planmodifier.String{ - stringplanmodifier.UseStateForUnknown(), - }, }, "assets_count": schema.Int32Attribute{ Description: "Count of the streaming assets attached to the stream resource", Computed: true, - PlanModifiers: []planmodifier.Int32{ - int32planmodifier.UseStateForUnknown(), - }, }, "stream_subscriptions_count": schema.Int32Attribute{ Description: "Count of the client subscriptions on the stream resource", Computed: true, - PlanModifiers: []planmodifier.Int32{ - int32planmodifier.UseStateForUnknown(), - }, }, "change_log": schema.SingleNestedAttribute{ Description: "Details of the last change on the stream resource", Computed: true, - PlanModifiers: []planmodifier.Object{ - objectplanmodifier.UseStateForUnknown(), - }, - CustomType: fwtypes.NewObjectTypeOf[ChangeLogModel](ctx), + CustomType: fwtypes.NewObjectTypeOf[ChangeLogModel](ctx), Attributes: map[string]schema.Attribute{ "created_by": schema.StringAttribute{ Description: "User name of creator of the stream resource", diff --git a/internal/resources/fabric/stream/resource_test.go b/internal/resources/fabric/stream/resource_test.go index 7dbf3cc8a..c3c817b53 100644 --- a/internal/resources/fabric/stream/resource_test.go +++ b/internal/resources/fabric/stream/resource_test.go @@ -72,7 +72,6 @@ func TestAccFabricStream_PFCR(t *testing.T) { resource.TestCheckResourceAttrSet("equinix_fabric_stream.new_stream", "uuid"), resource.TestCheckResourceAttrSet("equinix_fabric_stream.new_stream", "change_log.created_by"), ), - ExpectNonEmptyPlan: false, }, { Config: testAccFabricStreamConfig(updatedStreamName, updatedStreamDescription), @@ -90,7 +89,6 @@ func TestAccFabricStream_PFCR(t *testing.T) { resource.TestCheckResourceAttrSet("equinix_fabric_stream.new_stream", "uuid"), resource.TestCheckResourceAttrSet("equinix_fabric_stream.new_stream", "change_log.created_by"), ), - ExpectNonEmptyPlan: false, }, }, }) From 2f03c65dc1c7c641053ed708deb83ae05e7dc583 Mon Sep 17 00:00:00 2001 From: Tim Hogarty Date: Thu, 30 Jan 2025 17:34:28 -0800 Subject: [PATCH 11/13] Update reference to const timeout format --- internal/fabric/constants.go | 5 +++++ internal/resources/fabric/stream/models.go | 8 ++++---- 2 files changed, 9 insertions(+), 4 deletions(-) create mode 100644 internal/fabric/constants.go diff --git a/internal/fabric/constants.go b/internal/fabric/constants.go new file mode 100644 index 000000000..b481dd017 --- /dev/null +++ b/internal/fabric/constants.go @@ -0,0 +1,5 @@ +package fabric + +const ( + TimeFormat = "2006-01-02T15:04:05.000Z" +) diff --git a/internal/resources/fabric/stream/models.go b/internal/resources/fabric/stream/models.go index 2b4232059..3bdccdde5 100644 --- a/internal/resources/fabric/stream/models.go +++ b/internal/resources/fabric/stream/models.go @@ -3,6 +3,7 @@ package stream import ( "context" + "github.com/equinix/terraform-provider-equinix/internal/fabric" fwtypes "github.com/equinix/terraform-provider-equinix/internal/framework/types" "github.com/equinix/equinix-sdk-go/services/fabricv4" @@ -192,21 +193,20 @@ func parseStream(ctx context.Context, stream *fabricv4.Stream, } *project = fwtypes.NewObjectValueOf[ProjectModel](ctx, &projectModel) - const TimeFormat = "2006-01-02T15:04:05.000Z" streamChangeLog := stream.GetChangeLog() changeLogModel := ChangeLogModel{ CreatedBy: types.StringValue(streamChangeLog.GetCreatedBy()), CreatedByFullName: types.StringValue(streamChangeLog.GetCreatedByFullName()), CreatedByEmail: types.StringValue(streamChangeLog.GetCreatedByEmail()), - CreatedDateTime: types.StringValue(streamChangeLog.GetCreatedDateTime().Format(TimeFormat)), + CreatedDateTime: types.StringValue(streamChangeLog.GetCreatedDateTime().Format(fabric.TimeFormat)), UpdatedBy: types.StringValue(streamChangeLog.GetUpdatedBy()), UpdatedByFullName: types.StringValue(streamChangeLog.GetUpdatedByFullName()), UpdatedByEmail: types.StringValue(streamChangeLog.GetUpdatedByEmail()), - UpdatedDateTime: types.StringValue(streamChangeLog.GetUpdatedDateTime().Format(TimeFormat)), + UpdatedDateTime: types.StringValue(streamChangeLog.GetUpdatedDateTime().Format(fabric.TimeFormat)), DeletedBy: types.StringValue(streamChangeLog.GetDeletedBy()), DeletedByFullName: types.StringValue(streamChangeLog.GetDeletedByFullName()), DeletedByEmail: types.StringValue(streamChangeLog.GetDeletedByEmail()), - DeletedDateTime: types.StringValue(streamChangeLog.GetDeletedDateTime().Format(TimeFormat)), + DeletedDateTime: types.StringValue(streamChangeLog.GetDeletedDateTime().Format(fabric.TimeFormat)), } *changeLog = fwtypes.NewObjectValueOf[ChangeLogModel](ctx, &changeLogModel) return diag From a8f8962aaa7b42fdb0a700cb4c9660ff7da7a63c Mon Sep 17 00:00:00 2001 From: Tim Hogarty Date: Fri, 31 Jan 2025 14:38:46 -0800 Subject: [PATCH 12/13] Add revive and stylecheck linters + update linting errors --- .golangci.yaml | 4 +++- .../fabric/stream/datasource_all_streams.go | 2 +- .../fabric/stream/datasource_by_streamid.go | 4 ++-- internal/resources/fabric/stream/models.go | 18 +++++++++--------- internal/resources/fabric/stream/resource.go | 2 +- internal/resources/fabric/stream/sweeper.go | 2 +- 6 files changed, 17 insertions(+), 15 deletions(-) diff --git a/.golangci.yaml b/.golangci.yaml index 674ed5dad..db3f2fa63 100644 --- a/.golangci.yaml +++ b/.golangci.yaml @@ -10,6 +10,8 @@ linters: - ineffassign - staticcheck - unused + - revive + - stylecheck issues: max-issues-per-linter: 0 - max-same-issues: 0 \ No newline at end of file + max-same-issues: 0 diff --git a/internal/resources/fabric/stream/datasource_all_streams.go b/internal/resources/fabric/stream/datasource_all_streams.go index 08c689111..044bb00f9 100644 --- a/internal/resources/fabric/stream/datasource_all_streams.go +++ b/internal/resources/fabric/stream/datasource_all_streams.go @@ -26,7 +26,7 @@ type DataSourceAllStreams struct { func (r *DataSourceAllStreams) Schema( ctx context.Context, - req datasource.SchemaRequest, + _ datasource.SchemaRequest, resp *datasource.SchemaResponse, ) { resp.Schema = dataSourceAllStreamsSchema(ctx) diff --git a/internal/resources/fabric/stream/datasource_by_streamid.go b/internal/resources/fabric/stream/datasource_by_streamid.go index 1e4a09c64..0ba6e2c6b 100644 --- a/internal/resources/fabric/stream/datasource_by_streamid.go +++ b/internal/resources/fabric/stream/datasource_by_streamid.go @@ -25,7 +25,7 @@ type DataSourceByStreamID struct { func (r *DataSourceByStreamID) Schema( ctx context.Context, - req datasource.SchemaRequest, + _ datasource.SchemaRequest, resp *datasource.SchemaResponse, ) { resp.Schema = dataSourceSingleStreamSchema(ctx) @@ -35,7 +35,7 @@ func (r *DataSourceByStreamID) Read(ctx context.Context, request datasource.Read client := r.Meta.NewFabricClientForFramework(ctx, request.ProviderMeta) // Retrieve values from plan - var data DataSourceByIdModel + var data DataSourceByIDModel response.Diagnostics.Append(request.Config.Get(ctx, &data)...) if response.Diagnostics.HasError() { return diff --git a/internal/resources/fabric/stream/models.go b/internal/resources/fabric/stream/models.go index 3bdccdde5..6c9e2b806 100644 --- a/internal/resources/fabric/stream/models.go +++ b/internal/resources/fabric/stream/models.go @@ -14,7 +14,7 @@ import ( "github.com/hashicorp/terraform-plugin-framework/types/basetypes" ) -type DataSourceByIdModel struct { +type DataSourceByIDModel struct { StreamID types.String `tfsdk:"stream_id"` ID types.String `tfsdk:"id"` BaseStreamModel @@ -45,7 +45,7 @@ type BaseStreamModel struct { Name types.String `tfsdk:"name"` Description types.String `tfsdk:"description"` Href types.String `tfsdk:"href"` - Uuid types.String `tfsdk:"uuid"` + UUID types.String `tfsdk:"uuid"` State types.String `tfsdk:"state"` AssetsCount types.Int32 `tfsdk:"assets_count"` StreamSubscriptionsCount types.Int32 `tfsdk:"stream_subscriptions_count"` @@ -72,7 +72,7 @@ type ChangeLogModel struct { DeletedDateTime types.String `tfsdk:"deleted_date_time"` } -func (m *DataSourceByIdModel) parse(ctx context.Context, stream *fabricv4.Stream) diag.Diagnostics { +func (m *DataSourceByIDModel) parse(ctx context.Context, stream *fabricv4.Stream) diag.Diagnostics { m.StreamID = types.StringValue(stream.GetUuid()) m.ID = types.StringValue(stream.GetUuid()) @@ -82,7 +82,7 @@ func (m *DataSourceByIdModel) parse(ctx context.Context, stream *fabricv4.Stream &m.Name, &m.Description, &m.Href, - &m.Uuid, + &m.UUID, &m.State, &m.AssetsCount, &m.StreamSubscriptionsCount, @@ -123,7 +123,7 @@ func (m *DataSourceAllStreamsModel) parse(ctx context.Context, streamsResponse * Previous: types.StringValue(responsePagination.GetPrevious()), } - m.ID = types.StringValue(data[0].Uuid.ValueString()) + m.ID = types.StringValue(data[0].UUID.ValueString()) m.Pagination = fwtypes.NewObjectValueOf[PaginationModel](ctx, &pagination) m.Data = fwtypes.NewListNestedObjectValueOfValueSlice[BaseStreamModel](ctx, data) @@ -138,7 +138,7 @@ func (m *ResourceModel) parse(ctx context.Context, stream *fabricv4.Stream) diag &m.Name, &m.Description, &m.Href, - &m.Uuid, + &m.UUID, &m.State, &m.AssetsCount, &m.StreamSubscriptionsCount, @@ -157,7 +157,7 @@ func (m *BaseStreamModel) parse(ctx context.Context, stream *fabricv4.Stream) di &m.Name, &m.Description, &m.Href, - &m.Uuid, + &m.UUID, &m.State, &m.AssetsCount, &m.StreamSubscriptionsCount, @@ -171,14 +171,14 @@ func (m *BaseStreamModel) parse(ctx context.Context, stream *fabricv4.Stream) di } func parseStream(ctx context.Context, stream *fabricv4.Stream, - type_, name, description, href, uuid, state *basetypes.StringValue, + streamType, name, description, href, uuid, state *basetypes.StringValue, assetsCount, streamSubscriptionCount *basetypes.Int32Value, project *fwtypes.ObjectValueOf[ProjectModel], changeLog *fwtypes.ObjectValueOf[ChangeLogModel]) diag.Diagnostics { var diag diag.Diagnostics - *type_ = types.StringValue(string(stream.GetType())) + *streamType = types.StringValue(string(stream.GetType())) *name = types.StringValue(stream.GetName()) *description = types.StringValue(stream.GetDescription()) *href = types.StringValue(stream.GetHref()) diff --git a/internal/resources/fabric/stream/resource.go b/internal/resources/fabric/stream/resource.go index b8f82fcd0..7f9d9beba 100644 --- a/internal/resources/fabric/stream/resource.go +++ b/internal/resources/fabric/stream/resource.go @@ -34,7 +34,7 @@ type Resource struct { func (r *Resource) Schema( ctx context.Context, - req resource.SchemaRequest, + _ resource.SchemaRequest, resp *resource.SchemaResponse, ) { resp.Schema = resourceSchema(ctx) diff --git a/internal/resources/fabric/stream/sweeper.go b/internal/resources/fabric/stream/sweeper.go index 6c855c737..de2e40de6 100644 --- a/internal/resources/fabric/stream/sweeper.go +++ b/internal/resources/fabric/stream/sweeper.go @@ -21,7 +21,7 @@ func AddTestSweeper() { }) } -func testSweepStreams(region string) error { +func testSweepStreams(_ string) error { var errs []error log.Printf("[DEBUG] Sweeping Fabric Streams") ctx := context.Background() From 36a88c835a346e9dd9ef0d37386193b52fb4334f Mon Sep 17 00:00:00 2001 From: Tim Hogarty Date: Fri, 31 Jan 2025 14:53:01 -0800 Subject: [PATCH 13/13] Remove styling additions to move it to a separate PR to avoid modifications in as many files as this change is touching --- .golangci.yaml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.golangci.yaml b/.golangci.yaml index db3f2fa63..bd812ea3f 100644 --- a/.golangci.yaml +++ b/.golangci.yaml @@ -10,8 +10,6 @@ linters: - ineffassign - staticcheck - unused - - revive - - stylecheck issues: max-issues-per-linter: 0 max-same-issues: 0