diff --git a/CHANGELOG.md b/CHANGELOG.md index 03377fba3..96fa26170 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -430,10 +430,12 @@ - [v0.2.0](services/telemetryrouter/CHANGELOG.md#v020) - **Feature:** Added `_UNKNOWN_DEFAULT_OPEN_API` fallback value to all enums to handle unknown API values gracefully. - [v0.2.1](services/telemetryrouter/CHANGELOG.md#v021) - - **Improvement**: Use new `WaiterHandler` struct in the DNS WaitHandler + - **Improvement**: Use new `WaiterHandler` struct in the TelemetryRouter WaitHandler - `telemetrylink`: - [v0.1.0](services/telemetrylink/CHANGELOG.md#v010) - **New**: API for STACKIT Telemetry Link + - [v0.1.1](services/telemetrylink/CHANGELOG.md#v011) + - **Improvement**: Use new `WaiterHandler` struct in the TelemetryLink WaitHandler - `vpn`: - [v0.4.2](services/vpn/CHANGELOG.md#v042) - **Dependencies:** Bump STACKIT SDK core module from `v0.24.0` to `v0.24.1` diff --git a/examples/telemetrylink/go.mod b/examples/telemetrylink/go.mod new file mode 100644 index 000000000..27e137e5d --- /dev/null +++ b/examples/telemetrylink/go.mod @@ -0,0 +1,16 @@ +module github.com/stackitcloud/stackit-sdk-go/examples/telemetrylink + +go 1.25 + +// This is not needed in production. This is only here to point the golangci linter to the local version instead of the last release on GitHub. +replace github.com/stackitcloud/stackit-sdk-go/services/telemetrylink => ../../services/telemetrylink + +require ( + github.com/stackitcloud/stackit-sdk-go/core v0.26.0 + github.com/stackitcloud/stackit-sdk-go/services/telemetrylink v0.1.1 +) + +require ( + github.com/golang-jwt/jwt/v5 v5.3.1 // indirect + github.com/google/uuid v1.6.0 // indirect +) diff --git a/examples/telemetrylink/go.sum b/examples/telemetrylink/go.sum new file mode 100644 index 000000000..3712a0c87 --- /dev/null +++ b/examples/telemetrylink/go.sum @@ -0,0 +1,8 @@ +github.com/golang-jwt/jwt/v5 v5.3.1 h1:kYf81DTWFe7t+1VvL7eS+jKFVWaUnK9cB1qbwn63YCY= +github.com/golang-jwt/jwt/v5 v5.3.1/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE= +github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/stackitcloud/stackit-sdk-go/core v0.26.0 h1:jQEb9gkehfp6VCP6TcYk7BI10cz4l0KM2L6hqYBH2QA= +github.com/stackitcloud/stackit-sdk-go/core v0.26.0/go.mod h1:WU1hhxnjXw2EV7CYa1nlEvNpMiRY6CvmIOaHuL3pOaA= diff --git a/examples/telemetrylink/telemetrylink.go b/examples/telemetrylink/telemetrylink.go new file mode 100644 index 000000000..2ccaa8e7c --- /dev/null +++ b/examples/telemetrylink/telemetrylink.go @@ -0,0 +1,299 @@ +package main + +import ( + "context" + "log" + + "github.com/stackitcloud/stackit-sdk-go/core/utils" + telemetrylink "github.com/stackitcloud/stackit-sdk-go/services/telemetrylink/v1betaapi" + "github.com/stackitcloud/stackit-sdk-go/services/telemetrylink/v1betaapi/wait" +) + +func main() { + ctx := context.Background() + + organizationId := "ORGANIZATION_ID" // the uuid of your STACKIT organization + folderId := "FOLDER_ID" // the uuid of your STACKIT folder + projectId := "PROJECT_ID" // the uuid of your STACKIT project + regionId := "eu01" + telemetryRouterId := "TELEMETRY_ROUTER_ID" // the uuid of your STACKIT TelemetryRouter + telemetryRouterAccessToken := "TELEMETRY_ROUTER_ACCESS_TOKEN" // the access token of your TelemetryRouter + + client, err := telemetrylink.NewAPIClient() + if err != nil { + log.Fatalf("[TelemetryLink API] Creating API client: %v\n", err) + } + + // --- Organization TelemetryLink Examples --- + + // Create an organization TelemetryLink + log.Printf("[TelemetryLink API] Creating Organization TelemetryLink.\n") + var createdOrgLink string + createOrgLinkPayload := telemetrylink.CreateOrUpdateOrganizationTelemetryLinkPayload{ + DisplayName: "my-org-telemetry-link", + TelemetryRouterId: telemetryRouterId, + AccessToken: telemetryRouterAccessToken, + } + createResp, err := client.DefaultAPI.CreateOrUpdateOrganizationTelemetryLink(ctx, organizationId, regionId). + CreateOrUpdateOrganizationTelemetryLinkPayload(createOrgLinkPayload). + Execute() + if err != nil { + log.Fatalf("[TelemetryLink API] Error when calling `CreateOrUpdateOrganizationTelemetryLink`: %v\n", err) + } + createdOrgLink = createResp.Id + + // Wait for the TelemetryLink to be ready + log.Printf("[TelemetryLink API] Waiting for organization TelemetryLink to be created.\n") + _, err = wait.CreateOrUpdateOrganizationTelemetryLinkWaitHandler(ctx, client.DefaultAPI, organizationId, regionId).WaitWithContext(context.Background()) + if err != nil { + log.Fatalf("[TelemetryLink API] Error when waiting for creation: %v\n", err) + } + log.Printf("[TelemetryLink API] Organization TelemetryLink \"%s\" has been successfully created.\n", createdOrgLink) + + // Get the created organization TelemetryLink Instance + log.Printf("[TelemetryLink API] Retrieving organization TelemetryLink.\n") + getResp, err := client.DefaultAPI.GetOrganizationTelemetryLink(ctx, organizationId, regionId).Execute() + if err != nil { + log.Fatalf("[TelemetryLink API] Error when calling `GetOrganizationTelemetryLink`: %v\n", err) + } + log.Printf("[TelemetryLink API] Retrieved organization TelemetryLink with ID \"%s\" and Display Name \"%s\".\n", getResp.Id, getResp.DisplayName) + + // Update the created organization TelemetryLink + log.Printf("[TelemetryLink API] Updating organization TelemetryLink.\n") + updatePayload := telemetrylink.CreateOrUpdateOrganizationTelemetryLinkPayload{ + DisplayName: "my-upd-org-telemetry-link", + TelemetryRouterId: telemetryRouterId, + AccessToken: telemetryRouterAccessToken, + } + updateResp, err := client.DefaultAPI.CreateOrUpdateOrganizationTelemetryLink(ctx, organizationId, regionId). + CreateOrUpdateOrganizationTelemetryLinkPayload(updatePayload). + Execute() + if err != nil { + log.Fatalf("[TelemetryLink API] Error when calling `CreateOrUpdateOrganizationTelemetryLink`: %v\n", err) + } + + // Wait for the organization TelemetryLink to be updated + log.Printf("[TelemetryLink API] Waiting for organization TelemetryLink to be updated.\n") + _, err = wait.CreateOrUpdateOrganizationTelemetryLinkWaitHandler(ctx, client.DefaultAPI, organizationId, regionId).WaitWithContext(context.Background()) + if err != nil { + log.Fatalf("[TelemetryLink API] Error when waiting for update: %v\n", err) + } + log.Printf("[TelemetryLink API] Organization TelemetryLink \"%s\" has been successfully updated.\n", updateResp.Id) + + // Partially update organization TelemetryLink + log.Printf("[TelemetryLink API] Partially updating organization TelemetryLink.\n") + partialUpdatePayload := telemetrylink.PartialUpdateOrganizationTelemetryLinkPayload{ + Description: utils.Ptr("description"), + } + partialUpdateResp, err := client.DefaultAPI.PartialUpdateOrganizationTelemetryLink(ctx, organizationId, regionId). + PartialUpdateOrganizationTelemetryLinkPayload(partialUpdatePayload). + Execute() + if err != nil { + log.Fatalf("[TelemetryLink API] Error when calling `PartialUpdateOrganizationTelemetryLink`: %v\n", err) + } + + // Wait for the organization TelemetryLink to be partiallyupdated + log.Printf("[TelemetryLink API] Waiting for organization TelemetryLink to be partially updated.\n") + _, err = wait.PartialUpdateOrganizationTelemetryLinkWaitHandler(ctx, client.DefaultAPI, organizationId, regionId).WaitWithContext(context.Background()) + if err != nil { + log.Fatalf("[TelemetryLink API] Error when waiting for partial update: %v\n", err) + } + log.Printf("[TelemetryLink API] Organization TelemetryLink \"%s\" has been successfully partially updated.\n", partialUpdateResp.Id) + + // Delete the organization TelemetryLink + log.Printf("[TelemetryLink API] Deleting organization TelemetryLink.\n") + err = client.DefaultAPI.DeleteOrganizationTelemetryLink(ctx, organizationId, regionId).Execute() + if err != nil { + log.Fatalf("[TelemetryLink API] Error when calling `DeleteOrganizationTelemetryLink`: %v\n", err) + } + + // Wait for the organization TelemetryLink to be deleted + log.Printf("[TelemetryLink API] Waiting for organization TelemetryLink to be deleted.\n") + _, err = wait.DeleteOrganizationTelemetryLinkWaitHandler(ctx, client.DefaultAPI, organizationId, regionId).WaitWithContext(context.Background()) + if err != nil { + log.Fatalf("[TelemetryLink API] Error when waiting for deletion: %v\n", err) + } + log.Printf("[TelemetryLink API] Organization TelemetryLink \"%s\" has been successfully deleted.\n", createdOrgLink) + + // --- Folder TelemetryLink Examples --- + + // Create a folder TelemetryLink + log.Printf("[TelemetryLink API] Creating Folder TelemetryLink.\n") + var createdFolderLink string + createFolderLinkPayload := telemetrylink.CreateOrUpdateFolderTelemetryLinkPayload{ + DisplayName: "my-folder-telemetry-link", + TelemetryRouterId: telemetryRouterId, + AccessToken: telemetryRouterAccessToken, + } + createFolderResp, err := client.DefaultAPI.CreateOrUpdateFolderTelemetryLink(ctx, folderId, regionId). + CreateOrUpdateFolderTelemetryLinkPayload(createFolderLinkPayload). + Execute() + if err != nil { + log.Fatalf("[TelemetryLink API] Error when calling `CreateOrUpdateFolderTelemetryLink`: %v\n", err) + } + createdFolderLink = createFolderResp.Id + + // Wait for the Folder TelemetryLink to be ready + log.Printf("[TelemetryLink API] Waiting for folder TelemetryLink to be created.\n") + _, err = wait.CreateOrUpdateFolderTelemetryLinkWaitHandler(ctx, client.DefaultAPI, folderId, regionId).WaitWithContext(context.Background()) + if err != nil { + log.Fatalf("[TelemetryLink API] Error when waiting for creation: %v\n", err) + } + log.Printf("[TelemetryLink API] Folder TelemetryLink \"%s\" has been successfully created.\n", createdFolderLink) + + // Get the created folder TelemetryLink Instance + log.Printf("[TelemetryLink API] Retrieving folder TelemetryLink.\n") + getFolderResp, err := client.DefaultAPI.GetFolderTelemetryLink(ctx, folderId, regionId).Execute() + if err != nil { + log.Fatalf("[TelemetryLink API] Error when calling `GetFolderTelemetryLink`: %v\n", err) + } + log.Printf("[TelemetryLink API] Retrieved folder TelemetryLink with ID \"%s\" and Display Name \"%s\".\n", getFolderResp.Id, getFolderResp.DisplayName) + + // Update the created folder TelemetryLink + log.Printf("[TelemetryLink API] Updating folder TelemetryLink.\n") + updateFolderPayload := telemetrylink.CreateOrUpdateFolderTelemetryLinkPayload{ + DisplayName: "my-upd-folder-telemetry-link", + TelemetryRouterId: telemetryRouterId, + AccessToken: telemetryRouterAccessToken, + } + updateFolderResp, err := client.DefaultAPI.CreateOrUpdateFolderTelemetryLink(ctx, folderId, regionId). + CreateOrUpdateFolderTelemetryLinkPayload(updateFolderPayload). + Execute() + if err != nil { + log.Fatalf("[TelemetryLink API] Error when calling `CreateOrUpdateFolderTelemetryLink`: %v\n", err) + } + + // Wait for the folder TelemetryLink to be updated + log.Printf("[TelemetryLink API] Waiting for folder TelemetryLink to be updated.\n") + _, err = wait.CreateOrUpdateFolderTelemetryLinkWaitHandler(ctx, client.DefaultAPI, folderId, regionId).WaitWithContext(context.Background()) + if err != nil { + log.Fatalf("[TelemetryLink API] Error when waiting for update: %v\n", err) + } + log.Printf("[TelemetryLink API] Folder TelemetryLink \"%s\" has been successfully updated.\n", updateFolderResp.Id) + + // Partially update folder TelemetryLink + log.Printf("[TelemetryLink API] Partially updating folder TelemetryLink.\n") + partialUpdateFolderPayload := telemetrylink.PartialUpdateFolderTelemetryLinkPayload{ + Description: utils.Ptr("folder description"), + } + partialUpdateFolderResp, err := client.DefaultAPI.PartialUpdateFolderTelemetryLink(ctx, folderId, regionId). + PartialUpdateFolderTelemetryLinkPayload(partialUpdateFolderPayload). + Execute() + if err != nil { + log.Fatalf("[TelemetryLink API] Error when calling `PartialUpdateFolderTelemetryLink`: %v\n", err) + } + + // Wait for the folder TelemetryLink to be partially updated + log.Printf("[TelemetryLink API] Waiting for folder TelemetryLink to be partially updated.\n") + _, err = wait.PartialUpdateFolderTelemetryLinkWaitHandler(ctx, client.DefaultAPI, folderId, regionId).WaitWithContext(context.Background()) + if err != nil { + log.Fatalf("[TelemetryLink API] Error when waiting for partial update: %v\n", err) + } + log.Printf("[TelemetryLink API] Folder TelemetryLink \"%s\" has been successfully partially updated.\n", partialUpdateFolderResp.Id) + + // Delete the folder TelemetryLink + log.Printf("[TelemetryLink API] Deleting folder TelemetryLink.\n") + err = client.DefaultAPI.DeleteFolderTelemetryLink(ctx, folderId, regionId).Execute() + if err != nil { + log.Fatalf("[TelemetryLink API] Error when calling `DeleteFolderTelemetryLink`: %v\n", err) + } + + // Wait for the folder TelemetryLink to be deleted + log.Printf("[TelemetryLink API] Waiting for folder TelemetryLink to be deleted.\n") + _, err = wait.DeleteFolderTelemetryLinkWaitHandler(ctx, client.DefaultAPI, folderId, regionId).WaitWithContext(context.Background()) + if err != nil { + log.Fatalf("[TelemetryLink API] Error when waiting for deletion: %v\n", err) + } + log.Printf("[TelemetryLink API] Folder TelemetryLink \"%s\" has been successfully deleted.\n", createdFolderLink) + + // --- Project TelemetryLink Examples --- + + // Create a project TelemetryLink + log.Printf("[TelemetryLink API] Creating Project TelemetryLink.\n") + var createdProjectLink string + createProjectLinkPayload := telemetrylink.CreateOrUpdateProjectTelemetryLinkPayload{ + DisplayName: "my-project-telemetry-link", + TelemetryRouterId: telemetryRouterId, + AccessToken: telemetryRouterAccessToken, + } + createProjectResp, err := client.DefaultAPI.CreateOrUpdateProjectTelemetryLink(ctx, projectId, regionId). + CreateOrUpdateProjectTelemetryLinkPayload(createProjectLinkPayload). + Execute() + if err != nil { + log.Fatalf("[TelemetryLink API] Error when calling `CreateOrUpdateProjectTelemetryLink`: %v\n", err) + } + createdProjectLink = createProjectResp.Id + + // Wait for the Project TelemetryLink to be ready + log.Printf("[TelemetryLink API] Waiting for project TelemetryLink to be created.\n") + _, err = wait.CreateOrUpdateProjectTelemetryLinkWaitHandler(ctx, client.DefaultAPI, projectId, regionId).WaitWithContext(context.Background()) + if err != nil { + log.Fatalf("[TelemetryLink API] Error when waiting for creation: %v\n", err) + } + log.Printf("[TelemetryLink API] Project TelemetryLink \"%s\" has been successfully created.\n", createdProjectLink) + + // Get the created project TelemetryLink Instance + log.Printf("[TelemetryLink API] Retrieving project TelemetryLink.\n") + getProjectResp, err := client.DefaultAPI.GetProjectTelemetryLink(ctx, projectId, regionId).Execute() + if err != nil { + log.Fatalf("[TelemetryLink API] Error when calling `GetProjectTelemetryLink`: %v\n", err) + } + log.Printf("[TelemetryLink API] Retrieved project TelemetryLink with ID \"%s\" and Display Name \"%s\".\n", getProjectResp.Id, getProjectResp.DisplayName) + + // Update the created project TelemetryLink + log.Printf("[TelemetryLink API] Updating project TelemetryLink.\n") + updateProjectPayload := telemetrylink.CreateOrUpdateProjectTelemetryLinkPayload{ + DisplayName: "my-upd-project-telemetry-link", + TelemetryRouterId: telemetryRouterId, + AccessToken: telemetryRouterAccessToken, + } + updateProjectResp, err := client.DefaultAPI.CreateOrUpdateProjectTelemetryLink(ctx, projectId, regionId). + CreateOrUpdateProjectTelemetryLinkPayload(updateProjectPayload). + Execute() + if err != nil { + log.Fatalf("[TelemetryLink API] Error when calling `CreateOrUpdateProjectTelemetryLink`: %v\n", err) + } + + // Wait for the project TelemetryLink to be updated + log.Printf("[TelemetryLink API] Waiting for project TelemetryLink to be updated.\n") + _, err = wait.CreateOrUpdateProjectTelemetryLinkWaitHandler(ctx, client.DefaultAPI, projectId, regionId).WaitWithContext(context.Background()) + if err != nil { + log.Fatalf("[TelemetryLink API] Error when waiting for update: %v\n", err) + } + log.Printf("[TelemetryLink API] Project TelemetryLink \"%s\" has been successfully updated.\n", updateProjectResp.Id) + + // Partially update project TelemetryLink + log.Printf("[TelemetryLink API] Partially updating project TelemetryLink.\n") + partialUpdateProjectPayload := telemetrylink.PartialUpdateProjectTelemetryLinkPayload{ + Description: utils.Ptr("project description"), + } + partialUpdateProjectResp, err := client.DefaultAPI.PartialUpdateProjectTelemetryLink(ctx, projectId, regionId). + PartialUpdateProjectTelemetryLinkPayload(partialUpdateProjectPayload). + Execute() + if err != nil { + log.Fatalf("[TelemetryLink API] Error when calling `PartialUpdateProjectTelemetryLink`: %v\n", err) + } + + // Wait for the project TelemetryLink to be partially updated + log.Printf("[TelemetryLink API] Waiting for project TelemetryLink to be partially updated.\n") + _, err = wait.PartialUpdateProjectTelemetryLinkWaitHandler(ctx, client.DefaultAPI, projectId, regionId).WaitWithContext(context.Background()) + if err != nil { + log.Fatalf("[TelemetryLink API] Error when waiting for partial update: %v\n", err) + } + log.Printf("[TelemetryLink API] Project TelemetryLink \"%s\" has been successfully partially updated.\n", partialUpdateProjectResp.Id) + + // Delete the project TelemetryLink + log.Printf("[TelemetryLink API] Deleting project TelemetryLink.\n") + err = client.DefaultAPI.DeleteProjectTelemetryLink(ctx, projectId, regionId).Execute() + if err != nil { + log.Fatalf("[TelemetryLink API] Error when calling `DeleteProjectTelemetryLink`: %v\n", err) + } + + // Wait for the project TelemetryLink to be deleted + log.Printf("[TelemetryLink API] Waiting for project TelemetryLink to be deleted.\n") + _, err = wait.DeleteProjectTelemetryLinkWaitHandler(ctx, client.DefaultAPI, projectId, regionId).WaitWithContext(context.Background()) + if err != nil { + log.Fatalf("[TelemetryLink API] Error when waiting for deletion: %v\n", err) + } + log.Printf("[TelemetryLink API] Project TelemetryLink \"%s\" has been successfully deleted.\n", createdProjectLink) +} diff --git a/go.work b/go.work index 8fc1a8c1e..b82330bef 100644 --- a/go.work +++ b/go.work @@ -34,6 +34,7 @@ use ( ./examples/sfs ./examples/ske ./examples/sqlserverflex + ./examples/telemetrylink ./examples/telemetryrouter ./examples/waiter ./services/alb diff --git a/services/telemetrylink/CHANGELOG.md b/services/telemetrylink/CHANGELOG.md index a5de4843d..645bee64f 100644 --- a/services/telemetrylink/CHANGELOG.md +++ b/services/telemetrylink/CHANGELOG.md @@ -1,2 +1,5 @@ +## v0.1.1 +- **Improvement**: Use new `WaiterHandler` struct in the TelemetryLink WaitHandler + ## v0.1.0 - **New**: API for STACKIT Telemetry Link \ No newline at end of file diff --git a/services/telemetrylink/VERSION b/services/telemetrylink/VERSION index 9ff151c5b..a1c2c6a9f 100644 --- a/services/telemetrylink/VERSION +++ b/services/telemetrylink/VERSION @@ -1 +1 @@ -v0.1.0 \ No newline at end of file +v0.1.1 \ No newline at end of file diff --git a/services/telemetrylink/go.mod b/services/telemetrylink/go.mod index a4bc8ff75..b28722936 100644 --- a/services/telemetrylink/go.mod +++ b/services/telemetrylink/go.mod @@ -2,7 +2,10 @@ module github.com/stackitcloud/stackit-sdk-go/services/telemetrylink go 1.25 -require github.com/stackitcloud/stackit-sdk-go/core v0.26.0 +require ( + github.com/google/go-cmp v0.7.0 + github.com/stackitcloud/stackit-sdk-go/core v0.26.0 +) require ( github.com/golang-jwt/jwt/v5 v5.3.1 // indirect diff --git a/services/telemetrylink/v1betaapi/wait/wait.go b/services/telemetrylink/v1betaapi/wait/wait.go new file mode 100644 index 000000000..09ade4047 --- /dev/null +++ b/services/telemetrylink/v1betaapi/wait/wait.go @@ -0,0 +1,177 @@ +package wait + +import ( + "context" + "errors" + "net/http" + "time" + + "github.com/stackitcloud/stackit-sdk-go/core/wait" + telemetrylink "github.com/stackitcloud/stackit-sdk-go/services/telemetrylink/v1betaapi" +) + +const ( + TELEMETRYLINK_ACTIVE = "active" +) + +// CreateOrUpdateOrganizationTelemetryLinkWaitHandler will wait for organization TelemetryLink creation or update +func CreateOrUpdateOrganizationTelemetryLinkWaitHandler(ctx context.Context, a telemetrylink.DefaultAPI, organizationId, region string) *wait.AsyncActionHandler[telemetrylink.TelemetryLinkResponse] { + waitConfig := wait.WaiterHelper[telemetrylink.TelemetryLinkResponse, string]{ + FetchInstance: a.GetOrganizationTelemetryLink(ctx, organizationId, region).Execute, + GetState: func(d *telemetrylink.TelemetryLinkResponse) (string, error) { + if d == nil { + return "", errors.New("empty response") + } + return d.Status, nil + }, + ActiveState: []string{TELEMETRYLINK_ACTIVE}, + } + + handler := wait.New(waitConfig.Wait()) + handler.SetTimeout(10 * time.Minute) + return handler +} + +// PartialUpdateOrganizationTelemetryLinkWaitHandler will wait for organization TelemetryLink partial update +func PartialUpdateOrganizationTelemetryLinkWaitHandler(ctx context.Context, a telemetrylink.DefaultAPI, organizationId, region string) *wait.AsyncActionHandler[telemetrylink.TelemetryLinkResponse] { + waitConfig := wait.WaiterHelper[telemetrylink.TelemetryLinkResponse, string]{ + FetchInstance: a.GetOrganizationTelemetryLink(ctx, organizationId, region).Execute, + GetState: func(d *telemetrylink.TelemetryLinkResponse) (string, error) { + if d == nil { + return "", errors.New("empty response") + } + return d.Status, nil + }, + ActiveState: []string{TELEMETRYLINK_ACTIVE}, + } + + handler := wait.New(waitConfig.Wait()) + handler.SetTimeout(10 * time.Minute) + return handler +} + +// DeleteOrganizationTelemetryLinkWaitHandler will wait for organization TelemetryLink deletion +func DeleteOrganizationTelemetryLinkWaitHandler(ctx context.Context, a telemetrylink.DefaultAPI, organizationId, region string) *wait.AsyncActionHandler[telemetrylink.TelemetryLinkResponse] { + waitConfig := wait.WaiterHelper[telemetrylink.TelemetryLinkResponse, string]{ + FetchInstance: a.GetOrganizationTelemetryLink(ctx, organizationId, region).Execute, + GetState: func(d *telemetrylink.TelemetryLinkResponse) (string, error) { + if d == nil { + return "", errors.New("empty response") + } + return d.Status, nil + }, + DeleteHttpErrorStatusCodes: []int{http.StatusNotFound}, + } + + handler := wait.New(waitConfig.Wait()) + handler.SetTimeout(10 * time.Minute) + return handler +} + +// CreateOrUpdateFolderTelemetryLinkWaitHandler will wait for folder TelemetryLink creation or update +func CreateOrUpdateFolderTelemetryLinkWaitHandler(ctx context.Context, a telemetrylink.DefaultAPI, folderId, region string) *wait.AsyncActionHandler[telemetrylink.TelemetryLinkResponse] { + waitConfig := wait.WaiterHelper[telemetrylink.TelemetryLinkResponse, string]{ + FetchInstance: a.GetFolderTelemetryLink(ctx, folderId, region).Execute, + GetState: func(d *telemetrylink.TelemetryLinkResponse) (string, error) { + if d == nil { + return "", errors.New("empty response") + } + return d.Status, nil + }, + ActiveState: []string{TELEMETRYLINK_ACTIVE}, + } + + handler := wait.New(waitConfig.Wait()) + handler.SetTimeout(10 * time.Minute) + return handler +} + +// PartialUpdateFolderTelemetryLinkWaitHandler will wait for folder TelemetryLink partial update +func PartialUpdateFolderTelemetryLinkWaitHandler(ctx context.Context, a telemetrylink.DefaultAPI, folderId, region string) *wait.AsyncActionHandler[telemetrylink.TelemetryLinkResponse] { + waitConfig := wait.WaiterHelper[telemetrylink.TelemetryLinkResponse, string]{ + FetchInstance: a.GetFolderTelemetryLink(ctx, folderId, region).Execute, + GetState: func(d *telemetrylink.TelemetryLinkResponse) (string, error) { + if d == nil { + return "", errors.New("empty response") + } + return d.Status, nil + }, + ActiveState: []string{TELEMETRYLINK_ACTIVE}, + } + + handler := wait.New(waitConfig.Wait()) + handler.SetTimeout(10 * time.Minute) + return handler +} + +// DeleteFolderTelemetryLinkWaitHandler will wait for folder TelemetryLink deletion +func DeleteFolderTelemetryLinkWaitHandler(ctx context.Context, a telemetrylink.DefaultAPI, folderId, region string) *wait.AsyncActionHandler[telemetrylink.TelemetryLinkResponse] { + waitConfig := wait.WaiterHelper[telemetrylink.TelemetryLinkResponse, string]{ + FetchInstance: a.GetFolderTelemetryLink(ctx, folderId, region).Execute, + GetState: func(d *telemetrylink.TelemetryLinkResponse) (string, error) { + if d == nil { + return "", errors.New("empty response") + } + return d.Status, nil + }, + DeleteHttpErrorStatusCodes: []int{http.StatusNotFound}, + } + + handler := wait.New(waitConfig.Wait()) + handler.SetTimeout(10 * time.Minute) + return handler +} + +// CreateOrUpdateProjectTelemetryLinkWaitHandler will wait for project TelemetryLink creation or update +func CreateOrUpdateProjectTelemetryLinkWaitHandler(ctx context.Context, a telemetrylink.DefaultAPI, projectId, region string) *wait.AsyncActionHandler[telemetrylink.TelemetryLinkResponse] { + waitConfig := wait.WaiterHelper[telemetrylink.TelemetryLinkResponse, string]{ + FetchInstance: a.GetProjectTelemetryLink(ctx, projectId, region).Execute, + GetState: func(d *telemetrylink.TelemetryLinkResponse) (string, error) { + if d == nil { + return "", errors.New("empty response") + } + return d.Status, nil + }, + ActiveState: []string{TELEMETRYLINK_ACTIVE}, + } + + handler := wait.New(waitConfig.Wait()) + handler.SetTimeout(10 * time.Minute) + return handler +} + +// PartialUpdateProjectTelemetryLinkWaitHandler will wait for project TelemetryLink partial update +func PartialUpdateProjectTelemetryLinkWaitHandler(ctx context.Context, a telemetrylink.DefaultAPI, projectId, region string) *wait.AsyncActionHandler[telemetrylink.TelemetryLinkResponse] { + waitConfig := wait.WaiterHelper[telemetrylink.TelemetryLinkResponse, string]{ + FetchInstance: a.GetProjectTelemetryLink(ctx, projectId, region).Execute, + GetState: func(d *telemetrylink.TelemetryLinkResponse) (string, error) { + if d == nil { + return "", errors.New("empty response") + } + return d.Status, nil + }, + ActiveState: []string{TELEMETRYLINK_ACTIVE}, + } + + handler := wait.New(waitConfig.Wait()) + handler.SetTimeout(10 * time.Minute) + return handler +} + +// DeleteProjectTelemetryLinkWaitHandler will wait for project TelemetryLink deletion +func DeleteProjectTelemetryLinkWaitHandler(ctx context.Context, a telemetrylink.DefaultAPI, projectId, region string) *wait.AsyncActionHandler[telemetrylink.TelemetryLinkResponse] { + waitConfig := wait.WaiterHelper[telemetrylink.TelemetryLinkResponse, string]{ + FetchInstance: a.GetProjectTelemetryLink(ctx, projectId, region).Execute, + GetState: func(d *telemetrylink.TelemetryLinkResponse) (string, error) { + if d == nil { + return "", errors.New("empty response") + } + return d.Status, nil + }, + DeleteHttpErrorStatusCodes: []int{http.StatusNotFound}, + } + + handler := wait.New(waitConfig.Wait()) + handler.SetTimeout(10 * time.Minute) + return handler +} diff --git a/services/telemetrylink/v1betaapi/wait/wait_test.go b/services/telemetrylink/v1betaapi/wait/wait_test.go new file mode 100644 index 000000000..f57c0692c --- /dev/null +++ b/services/telemetrylink/v1betaapi/wait/wait_test.go @@ -0,0 +1,637 @@ +package wait + +import ( + "context" + "testing" + "testing/synctest" + "time" + + "github.com/google/go-cmp/cmp" + + "github.com/stackitcloud/stackit-sdk-go/core/oapierror" + "github.com/stackitcloud/stackit-sdk-go/core/utils" + telemetrylink "github.com/stackitcloud/stackit-sdk-go/services/telemetrylink/v1betaapi" +) + +type mockSettings struct { + getFails bool + notFound bool + resourceState string +} + +func newAPIMock(settings mockSettings) telemetrylink.DefaultAPI { + return &telemetrylink.DefaultAPIServiceMock{ + GetOrganizationTelemetryLinkExecuteMock: utils.Ptr(func(_ telemetrylink.ApiGetOrganizationTelemetryLinkRequest) (*telemetrylink.TelemetryLinkResponse, error) { + if settings.getFails { + return nil, &oapierror.GenericOpenAPIError{ + StatusCode: 500, + } + } + + if settings.notFound { + return nil, &oapierror.GenericOpenAPIError{ + StatusCode: 404, + } + } + + return &telemetrylink.TelemetryLinkResponse{ + Status: settings.resourceState, + }, nil + }), + GetFolderTelemetryLinkExecuteMock: utils.Ptr(func(_ telemetrylink.ApiGetFolderTelemetryLinkRequest) (*telemetrylink.TelemetryLinkResponse, error) { + if settings.getFails { + return nil, &oapierror.GenericOpenAPIError{ + StatusCode: 500, + } + } + + if settings.notFound { + return nil, &oapierror.GenericOpenAPIError{ + StatusCode: 404, + } + } + + return &telemetrylink.TelemetryLinkResponse{ + Status: settings.resourceState, + }, nil + }), + GetProjectTelemetryLinkExecuteMock: utils.Ptr(func(_ telemetrylink.ApiGetProjectTelemetryLinkRequest) (*telemetrylink.TelemetryLinkResponse, error) { + if settings.getFails { + return nil, &oapierror.GenericOpenAPIError{ + StatusCode: 500, + } + } + + if settings.notFound { + return nil, &oapierror.GenericOpenAPIError{ + StatusCode: 404, + } + } + + return &telemetrylink.TelemetryLinkResponse{ + Status: settings.resourceState, + }, nil + }), + } +} + +func TestCreateOrUpdateOrganizationTelemetryLinkWaitHandler(t *testing.T) { + tests := []struct { + desc string + getFails bool + resourceState string + wantErr bool + wantResp bool + }{ + { + desc: "create_or_update_succeeded", + getFails: false, + resourceState: TELEMETRYLINK_ACTIVE, + wantErr: false, + wantResp: true, + }, + { + desc: "get_fails", + getFails: true, + resourceState: "", + wantErr: true, + wantResp: false, + }, + { + desc: "timeout", + getFails: false, + resourceState: "ANOTHER STATE", + wantErr: true, + wantResp: false, + }, + } + for _, tt := range tests { + t.Run(tt.desc, func(t *testing.T) { + synctest.Test(t, func(t *testing.T) { + apiClient := newAPIMock(mockSettings{ + getFails: tt.getFails, + resourceState: tt.resourceState, + }) + + var wantRes *telemetrylink.TelemetryLinkResponse + if tt.wantResp { + wantRes = &telemetrylink.TelemetryLinkResponse{ + Status: tt.resourceState, + } + } + + handler := CreateOrUpdateOrganizationTelemetryLinkWaitHandler(context.Background(), apiClient, "pid", "eu01") + + gotRes, err := handler.SetTimeout(10 * time.Millisecond).WaitWithContext(context.Background()) + + if (err != nil) != tt.wantErr { + t.Fatalf("handler error = %v, wantErr %v", err, tt.wantErr) + } + if !cmp.Equal(gotRes, wantRes) { + t.Fatalf("handler gotRes = %v, want %v", gotRes, wantRes) + } + }) + }) + } +} + +func TestPartialUpdateOrganizationTelemetryLinkWaitHandler(t *testing.T) { + tests := []struct { + desc string + getFails bool + resourceState string + wantErr bool + wantResp bool + }{ + { + desc: "create_or_update_succeeded", + getFails: false, + resourceState: TELEMETRYLINK_ACTIVE, + wantErr: false, + wantResp: true, + }, + { + desc: "get_fails", + getFails: true, + resourceState: "", + wantErr: true, + wantResp: false, + }, + { + desc: "timeout", + getFails: false, + resourceState: "ANOTHER STATE", + wantErr: true, + wantResp: false, + }, + } + for _, tt := range tests { + t.Run(tt.desc, func(t *testing.T) { + synctest.Test(t, func(t *testing.T) { + apiClient := newAPIMock(mockSettings{ + getFails: tt.getFails, + resourceState: tt.resourceState, + }) + + var wantRes *telemetrylink.TelemetryLinkResponse + if tt.wantResp { + wantRes = &telemetrylink.TelemetryLinkResponse{ + Status: tt.resourceState, + } + } + + handler := PartialUpdateOrganizationTelemetryLinkWaitHandler(context.Background(), apiClient, "pid", "eu01") + + gotRes, err := handler.SetTimeout(10 * time.Millisecond).WaitWithContext(context.Background()) + + if (err != nil) != tt.wantErr { + t.Fatalf("handler error = %v, wantErr %v", err, tt.wantErr) + } + if !cmp.Equal(gotRes, wantRes) { + t.Fatalf("handler gotRes = %v, want %v", gotRes, wantRes) + } + }) + }) + } +} + +func TestDeleteOrganizationTelemetryLinkWaitHandler(t *testing.T) { + tests := []struct { + desc string + getFails bool + notFound bool + resourceState string + wantErr bool + wantResp bool + }{ + { + desc: "not_found", + getFails: false, + resourceState: "", + wantErr: true, + wantResp: false, + }, + { + desc: "get_fails", + getFails: true, + resourceState: "", + wantErr: true, + wantResp: false, + }, + { + desc: "timeout", + getFails: false, + resourceState: "ANOTHER STATE", + wantErr: true, + wantResp: false, + }, + } + for _, tt := range tests { + t.Run(tt.desc, func(t *testing.T) { + synctest.Test(t, func(t *testing.T) { + apiClient := newAPIMock(mockSettings{ + notFound: tt.notFound, + getFails: tt.getFails, + resourceState: tt.resourceState, + }) + + var wantRes *telemetrylink.TelemetryLinkResponse + if tt.wantResp { + wantRes = &telemetrylink.TelemetryLinkResponse{ + Status: tt.resourceState, + } + } else { + wantRes = nil + } + + handler := DeleteOrganizationTelemetryLinkWaitHandler(context.Background(), apiClient, "pid", "eu01") + + gotRes, err := handler.SetTimeout(10 * time.Millisecond).WaitWithContext(context.Background()) + + if (err != nil) != tt.wantErr { + t.Fatalf("handler error = %v, wantErr %v", err, tt.wantErr) + } + if wantRes == nil && gotRes != nil { + t.Fatalf("handler gotRes = %v, want %v", gotRes, wantRes) + } + if wantRes != nil && !cmp.Equal(gotRes, wantRes) { + t.Fatalf("handler gotRes = %v, want %v", gotRes, wantRes) + } + }) + }) + } +} + +func TestCreateOrUpdateFolderTelemetryLinkWaitHandler(t *testing.T) { + tests := []struct { + desc string + getFails bool + resourceState string + wantErr bool + wantResp bool + }{ + { + desc: "create_or_update_succeeded", + getFails: false, + resourceState: TELEMETRYLINK_ACTIVE, + wantErr: false, + wantResp: true, + }, + { + desc: "get_fails", + getFails: true, + resourceState: "", + wantErr: true, + wantResp: false, + }, + { + desc: "timeout", + getFails: false, + resourceState: "ANOTHER STATE", + wantErr: true, + wantResp: false, + }, + } + for _, tt := range tests { + t.Run(tt.desc, func(t *testing.T) { + synctest.Test(t, func(t *testing.T) { + apiClient := newAPIMock(mockSettings{ + getFails: tt.getFails, + resourceState: tt.resourceState, + }) + + var wantRes *telemetrylink.TelemetryLinkResponse + if tt.wantResp { + wantRes = &telemetrylink.TelemetryLinkResponse{ + Status: tt.resourceState, + } + } + + handler := CreateOrUpdateFolderTelemetryLinkWaitHandler(context.Background(), apiClient, "pid", "eu01") + + gotRes, err := handler.SetTimeout(10 * time.Millisecond).WaitWithContext(context.Background()) + + if (err != nil) != tt.wantErr { + t.Fatalf("handler error = %v, wantErr %v", err, tt.wantErr) + } + if !cmp.Equal(gotRes, wantRes) { + t.Fatalf("handler gotRes = %v, want %v", gotRes, wantRes) + } + }) + }) + } +} + +func TestPartialUpdateFolderTelemetryLinkWaitHandler(t *testing.T) { + tests := []struct { + desc string + getFails bool + resourceState string + wantErr bool + wantResp bool + }{ + { + desc: "create_or_update_succeeded", + getFails: false, + resourceState: TELEMETRYLINK_ACTIVE, + wantErr: false, + wantResp: true, + }, + { + desc: "get_fails", + getFails: true, + resourceState: "", + wantErr: true, + wantResp: false, + }, + { + desc: "timeout", + getFails: false, + resourceState: "ANOTHER STATE", + wantErr: true, + wantResp: false, + }, + } + for _, tt := range tests { + t.Run(tt.desc, func(t *testing.T) { + synctest.Test(t, func(t *testing.T) { + apiClient := newAPIMock(mockSettings{ + getFails: tt.getFails, + resourceState: tt.resourceState, + }) + + var wantRes *telemetrylink.TelemetryLinkResponse + if tt.wantResp { + wantRes = &telemetrylink.TelemetryLinkResponse{ + Status: tt.resourceState, + } + } + + handler := PartialUpdateFolderTelemetryLinkWaitHandler(context.Background(), apiClient, "pid", "eu01") + + gotRes, err := handler.SetTimeout(10 * time.Millisecond).WaitWithContext(context.Background()) + + if (err != nil) != tt.wantErr { + t.Fatalf("handler error = %v, wantErr %v", err, tt.wantErr) + } + if !cmp.Equal(gotRes, wantRes) { + t.Fatalf("handler gotRes = %v, want %v", gotRes, wantRes) + } + }) + }) + } +} + +func TestDeleteFolderTelemetryLinkWaitHandler(t *testing.T) { + tests := []struct { + desc string + getFails bool + notFound bool + resourceState string + wantErr bool + wantResp bool + }{ + { + desc: "not_found", + getFails: false, + resourceState: "", + wantErr: true, + wantResp: false, + }, + { + desc: "get_fails", + getFails: true, + resourceState: "", + wantErr: true, + wantResp: false, + }, + { + desc: "timeout", + getFails: false, + resourceState: "ANOTHER STATE", + wantErr: true, + wantResp: false, + }, + } + for _, tt := range tests { + t.Run(tt.desc, func(t *testing.T) { + synctest.Test(t, func(t *testing.T) { + apiClient := newAPIMock(mockSettings{ + notFound: tt.notFound, + getFails: tt.getFails, + resourceState: tt.resourceState, + }) + + var wantRes *telemetrylink.TelemetryLinkResponse + if tt.wantResp { + wantRes = &telemetrylink.TelemetryLinkResponse{ + Status: tt.resourceState, + } + } else { + wantRes = nil + } + + handler := DeleteFolderTelemetryLinkWaitHandler(context.Background(), apiClient, "pid", "eu01") + + gotRes, err := handler.SetTimeout(10 * time.Millisecond).WaitWithContext(context.Background()) + + if (err != nil) != tt.wantErr { + t.Fatalf("handler error = %v, wantErr %v", err, tt.wantErr) + } + if wantRes == nil && gotRes != nil { + t.Fatalf("handler gotRes = %v, want %v", gotRes, wantRes) + } + if wantRes != nil && !cmp.Equal(gotRes, wantRes) { + t.Fatalf("handler gotRes = %v, want %v", gotRes, wantRes) + } + }) + }) + } +} + +func TestCreateOrUpdateProjectTelemetryLinkWaitHandler(t *testing.T) { + tests := []struct { + desc string + getFails bool + resourceState string + wantErr bool + wantResp bool + }{ + { + desc: "create_or_update_succeeded", + getFails: false, + resourceState: TELEMETRYLINK_ACTIVE, + wantErr: false, + wantResp: true, + }, + { + desc: "get_fails", + getFails: true, + resourceState: "", + wantErr: true, + wantResp: false, + }, + { + desc: "timeout", + getFails: false, + resourceState: "ANOTHER STATE", + wantErr: true, + wantResp: false, + }, + } + for _, tt := range tests { + t.Run(tt.desc, func(t *testing.T) { + synctest.Test(t, func(t *testing.T) { + apiClient := newAPIMock(mockSettings{ + getFails: tt.getFails, + resourceState: tt.resourceState, + }) + + var wantRes *telemetrylink.TelemetryLinkResponse + if tt.wantResp { + wantRes = &telemetrylink.TelemetryLinkResponse{ + Status: tt.resourceState, + } + } + + handler := CreateOrUpdateProjectTelemetryLinkWaitHandler(context.Background(), apiClient, "pid", "eu01") + + gotRes, err := handler.SetTimeout(10 * time.Millisecond).WaitWithContext(context.Background()) + + if (err != nil) != tt.wantErr { + t.Fatalf("handler error = %v, wantErr %v", err, tt.wantErr) + } + if !cmp.Equal(gotRes, wantRes) { + t.Fatalf("handler gotRes = %v, want %v", gotRes, wantRes) + } + }) + }) + } +} + +func TestPartialUpdateProjectTelemetryLinkWaitHandler(t *testing.T) { + tests := []struct { + desc string + getFails bool + resourceState string + wantErr bool + wantResp bool + }{ + { + desc: "create_or_update_succeeded", + getFails: false, + resourceState: TELEMETRYLINK_ACTIVE, + wantErr: false, + wantResp: true, + }, + { + desc: "get_fails", + getFails: true, + resourceState: "", + wantErr: true, + wantResp: false, + }, + { + desc: "timeout", + getFails: false, + resourceState: "ANOTHER STATE", + wantErr: true, + wantResp: false, + }, + } + for _, tt := range tests { + t.Run(tt.desc, func(t *testing.T) { + synctest.Test(t, func(t *testing.T) { + apiClient := newAPIMock(mockSettings{ + getFails: tt.getFails, + resourceState: tt.resourceState, + }) + + var wantRes *telemetrylink.TelemetryLinkResponse + if tt.wantResp { + wantRes = &telemetrylink.TelemetryLinkResponse{ + Status: tt.resourceState, + } + } + + handler := PartialUpdateProjectTelemetryLinkWaitHandler(context.Background(), apiClient, "pid", "eu01") + + gotRes, err := handler.SetTimeout(10 * time.Millisecond).WaitWithContext(context.Background()) + + if (err != nil) != tt.wantErr { + t.Fatalf("handler error = %v, wantErr %v", err, tt.wantErr) + } + if !cmp.Equal(gotRes, wantRes) { + t.Fatalf("handler gotRes = %v, want %v", gotRes, wantRes) + } + }) + }) + } +} + +func TestDeleteProjectTelemetryLinkWaitHandler(t *testing.T) { + tests := []struct { + desc string + getFails bool + notFound bool + resourceState string + wantErr bool + wantResp bool + }{ + { + desc: "not_found", + getFails: false, + resourceState: "", + wantErr: true, + wantResp: false, + }, + { + desc: "get_fails", + getFails: true, + resourceState: "", + wantErr: true, + wantResp: false, + }, + { + desc: "timeout", + getFails: false, + resourceState: "ANOTHER STATE", + wantErr: true, + wantResp: false, + }, + } + for _, tt := range tests { + t.Run(tt.desc, func(t *testing.T) { + synctest.Test(t, func(t *testing.T) { + apiClient := newAPIMock(mockSettings{ + notFound: tt.notFound, + getFails: tt.getFails, + resourceState: tt.resourceState, + }) + + var wantRes *telemetrylink.TelemetryLinkResponse + if tt.wantResp { + wantRes = &telemetrylink.TelemetryLinkResponse{ + Status: tt.resourceState, + } + } else { + wantRes = nil + } + + handler := DeleteProjectTelemetryLinkWaitHandler(context.Background(), apiClient, "pid", "eu01") + + gotRes, err := handler.SetTimeout(10 * time.Millisecond).WaitWithContext(context.Background()) + + if (err != nil) != tt.wantErr { + t.Fatalf("handler error = %v, wantErr %v", err, tt.wantErr) + } + if wantRes == nil && gotRes != nil { + t.Fatalf("handler gotRes = %v, want %v", gotRes, wantRes) + } + if wantRes != nil && !cmp.Equal(gotRes, wantRes) { + t.Fatalf("handler gotRes = %v, want %v", gotRes, wantRes) + } + }) + }) + } +} diff --git a/services/telemetryrouter/CHANGELOG.md b/services/telemetryrouter/CHANGELOG.md index 2d0d23697..979e84f8f 100644 --- a/services/telemetryrouter/CHANGELOG.md +++ b/services/telemetryrouter/CHANGELOG.md @@ -1,5 +1,5 @@ ## v0.2.1 -- **Improvement**: Use new `WaiterHandler` struct in the DNS WaitHandler +- **Improvement**: Use new `WaiterHandler` struct in the TelemetryRouter WaitHandler ## v0.2.0 - **Feature:** Added `_UNKNOWN_DEFAULT_OPEN_API` fallback value to all enums to handle unknown API values gracefully.