From fdcf66c8ed14ec4394d8889c1b820caa89648fe8 Mon Sep 17 00:00:00 2001
From: Isaac Calligeros <101079287+IsaacCalligeros95@users.noreply.github.com>
Date: Wed, 7 Aug 2024 14:34:53 +0930
Subject: [PATCH 01/12] Chore!: Migrate docker container registry (#702)
* Migrate docker container registry
* Tidy up
* Rename APIVersion
* Fix descriptions
---
docs/data-sources/feeds.md | 35 ++--
docs/data-sources/library_variable_sets.md | 4 +-
docs/resources/artifactory_generic_feed.md | 4 +-
.../aws_elastic_container_registry.md | 6 +-
docs/resources/docker_container_registry.md | 6 +-
docs/resources/github_repository_feed.md | 4 +-
docs/resources/helm_feed.md | 8 +-
docs/resources/library_variable_set.md | 4 +-
docs/resources/maven_feed.md | 4 +-
docs/resources/nuget_feed.md | 6 +-
octopusdeploy/provider.go | 1 -
.../resource_docker_container_registry.go | 104 ----------
.../schema_docker_container_registry.go | 104 ----------
octopusdeploy_framework/framework_provider.go | 3 +-
.../resource_artifactory_generic_feed.go | 3 +-
...resource_aws_elastic_container_registry.go | 3 +-
.../resource_docker_container_registry.go | 183 ++++++++++++++++++
...resource_docker_container_registry_test.go | 11 +-
.../resource_github_repository_feed.go | 3 +-
octopusdeploy_framework/resource_helm_feed.go | 3 +-
.../resource_maven_feed.go | 3 +-
.../resource_nuget_feed.go | 3 +-
.../schemas/docker_container_registry_feed.go | 39 ++++
.../schemas/library_variable_set.go | 4 +-
24 files changed, 286 insertions(+), 262 deletions(-)
delete mode 100644 octopusdeploy/resource_docker_container_registry.go
delete mode 100644 octopusdeploy/schema_docker_container_registry.go
create mode 100644 octopusdeploy_framework/resource_docker_container_registry.go
rename {octopusdeploy => octopusdeploy_framework}/resource_docker_container_registry_test.go (94%)
create mode 100644 octopusdeploy_framework/schemas/docker_container_registry_feed.go
diff --git a/docs/data-sources/feeds.md b/docs/data-sources/feeds.md
index 623ec5593..91fde3c96 100644
--- a/docs/data-sources/feeds.md
+++ b/docs/data-sources/feeds.md
@@ -27,37 +27,40 @@ data "octopusdeploy_feeds" "example" {
### Optional
- `feed_type` (String) A filter to search by feed type. Valid feed types are `AwsElasticContainerRegistry`, `BuiltIn`, `Docker`, `GitHub`, `Helm`, `Maven`, `NuGet`, or `OctopusProject`.
+- `feeds` (Block List) (see [below for nested schema](#nestedblock--feeds))
+- `id` (String) The unique ID for this resource.
- `ids` (List of String) A filter to search by a list of IDs.
-- `name` (String) A filter to search by name.
-- `partial_name` (String) A filter to search by the partial match of a name.
+- `name` (String) The name of this resource.
+- `partial_name` (String) A filter to search by a partial name.
- `skip` (Number) A filter to specify the number of items to skip in the response.
-- `space_id` (String) The space ID associated with this resource.
+- `space_id` (String) The space ID associated with this feeds.
- `take` (Number) A filter to specify the number of items to take (or return) in the response.
-### Read-Only
-
-- `feeds` (Block List) A list of feeds that match the filter(s). (see [below for nested schema](#nestedblock--feeds))
-- `id` (String) The ID of this resource.
-
### Nested Schema for `feeds`
-Read-Only:
+Required:
+
+- `access_key` (String) The AWS access key to use when authenticating against Amazon Web Services.
+- `feed_uri` (String)
+- `name` (String) The name of this resource.
+
+Optional:
-- `access_key` (String)
- `api_version` (String)
- `delete_unreleased_packages_after_days` (Number)
- `download_attempts` (Number) The number of times a deployment should attempt to download a package from this feed before failing.
- `download_retry_backoff_seconds` (Number) The number of seconds to apply as a linear back off between download attempts.
-- `feed_type` (String)
-- `feed_uri` (String)
+- `feed_type` (String) A filter to search by feed type. Valid feed types are `AwsElasticContainerRegistry`, `BuiltIn`, `Docker`, `GitHub`, `Helm`, `Maven`, `NuGet`, or `OctopusProject`.
- `id` (String) The unique ID for this resource.
- `is_enhanced_mode` (Boolean)
-- `name` (String) A short, memorable, unique name for this feed. Example: ACME Builds.
- `package_acquisition_location_options` (List of String)
- `password` (String, Sensitive) The password associated with this resource.
-- `region` (String)
- `registry_path` (String)
- `secret_key` (String, Sensitive)
-- `space_id` (String) The space ID associated with this resource.
-- `username` (String, Sensitive) The username associated with this resource.
\ No newline at end of file
+- `space_id` (String) The space ID associated with this feeds.
+- `username` (String, Sensitive) The username associated with this resource.
+
+Read-Only:
+
+- `region` (String)
\ No newline at end of file
diff --git a/docs/data-sources/library_variable_sets.md b/docs/data-sources/library_variable_sets.md
index da636ab68..8b6eeb19f 100644
--- a/docs/data-sources/library_variable_sets.md
+++ b/docs/data-sources/library_variable_sets.md
@@ -3,12 +3,12 @@
page_title: "octopusdeploy_library_variable_sets Data Source - terraform-provider-octopusdeploy"
subcategory: ""
description: |-
-
+ Provides information about existing library variable sets.
---
# octopusdeploy_library_variable_sets (Data Source)
-
+Provides information about existing library variable sets.
diff --git a/docs/resources/artifactory_generic_feed.md b/docs/resources/artifactory_generic_feed.md
index 3d46c6eec..07ea676ce 100644
--- a/docs/resources/artifactory_generic_feed.md
+++ b/docs/resources/artifactory_generic_feed.md
@@ -29,7 +29,7 @@ resource "octopusdeploy_artifactory_generic_feed" "example" {
### Required
- `feed_uri` (String)
-- `name` (String) A short, memorable, unique name for this feed. Example: ACME Builds.
+- `name` (String) The name of this resource.
- `repository` (String)
### Optional
@@ -38,7 +38,7 @@ resource "octopusdeploy_artifactory_generic_feed" "example" {
- `layout_regex` (String)
- `package_acquisition_location_options` (List of String)
- `password` (String, Sensitive) The password associated with this resource.
-- `space_id` (String) The space ID associated with this resource.
+- `space_id` (String) The space ID associated with this helm feed.
- `username` (String, Sensitive) The username associated with this resource.
## Import
diff --git a/docs/resources/aws_elastic_container_registry.md b/docs/resources/aws_elastic_container_registry.md
index 5549897ea..e0b4f802f 100644
--- a/docs/resources/aws_elastic_container_registry.md
+++ b/docs/resources/aws_elastic_container_registry.md
@@ -25,15 +25,15 @@ resource "octopusdeploy_aws_elastic_container_registry" "example" {
### Required
- `access_key` (String) The AWS access key to use when authenticating against Amazon Web Services.
-- `name` (String) A short, memorable, unique name for this feed. Example: ACME Builds.
+- `name` (String) The name of this resource.
- `region` (String) The AWS region where the registry resides.
- `secret_key` (String, Sensitive) The AWS secret key to use when authenticating against Amazon Web Services.
### Optional
-- `id` (String) The unique ID for this feed.
+- `id` (String) The unique ID for this resource.
- `package_acquisition_location_options` (List of String)
-- `space_id` (String) The space ID associated with this feed.
+- `space_id` (String) The space ID associated with this aws elastic container registry.
## Import
diff --git a/docs/resources/docker_container_registry.md b/docs/resources/docker_container_registry.md
index ebc6b68cb..8a59fe071 100644
--- a/docs/resources/docker_container_registry.md
+++ b/docs/resources/docker_container_registry.md
@@ -25,8 +25,8 @@ resource "octopusdeploy_docker_container_registry" "example" {
### Required
-- `feed_uri` (String) The URL to a Docker repository.
-- `name` (String) A short, memorable, unique name for this feed. Example: ACME Builds.
+- `feed_uri` (String)
+- `name` (String) The name of this resource.
### Optional
@@ -35,7 +35,7 @@ resource "octopusdeploy_docker_container_registry" "example" {
- `package_acquisition_location_options` (List of String)
- `password` (String, Sensitive) The password associated with this resource.
- `registry_path` (String)
-- `space_id` (String) The space ID associated with this resource.
+- `space_id` (String) The space ID associated with this docker container registry feed.
- `username` (String, Sensitive) The username associated with this resource.
## Import
diff --git a/docs/resources/github_repository_feed.md b/docs/resources/github_repository_feed.md
index c743a47dd..37e9601c1 100644
--- a/docs/resources/github_repository_feed.md
+++ b/docs/resources/github_repository_feed.md
@@ -27,7 +27,7 @@ resource "octopusdeploy_github_repository_feed" "example" {
### Required
- `feed_uri` (String)
-- `name` (String) A short, memorable, unique name for this feed. Example: ACME Builds.
+- `name` (String) The name of this resource.
### Optional
@@ -36,7 +36,7 @@ resource "octopusdeploy_github_repository_feed" "example" {
- `id` (String) The unique ID for this resource.
- `package_acquisition_location_options` (List of String)
- `password` (String, Sensitive) The password associated with this resource.
-- `space_id` (String) The space ID associated with this resource.
+- `space_id` (String) The space ID associated with this github repository feed.
- `username` (String, Sensitive) The username associated with this resource.
## Import
diff --git a/docs/resources/helm_feed.md b/docs/resources/helm_feed.md
index 037bc5888..5eed44882 100644
--- a/docs/resources/helm_feed.md
+++ b/docs/resources/helm_feed.md
@@ -2,12 +2,12 @@
page_title: "octopusdeploy_helm_feed Resource - terraform-provider-octopusdeploy"
subcategory: "Feeds"
description: |-
- This resource manages a Helm feed in Octopus Deploy.
+ This resource manages a Helm Feed in Octopus Deploy.
---
# octopusdeploy_helm_feed (Resource)
-This resource manages a Helm feed in Octopus Deploy.
+This resource manages a Helm Feed in Octopus Deploy.
## Example Usage
@@ -25,14 +25,14 @@ resource "octopusdeploy_helm_feed" "example" {
### Required
- `feed_uri` (String)
-- `name` (String) A short, memorable, unique name for this feed. Example: ACME Builds.
+- `name` (String) The name of this resource.
### Optional
- `id` (String) The unique ID for this resource.
- `package_acquisition_location_options` (List of String)
- `password` (String, Sensitive) The password associated with this resource.
-- `space_id` (String) The space ID associated with this resource.
+- `space_id` (String) The space ID associated with this helm feed.
- `username` (String, Sensitive) The username associated with this resource.
## Import
diff --git a/docs/resources/library_variable_set.md b/docs/resources/library_variable_set.md
index b30fd3f1f..9bff4bf78 100644
--- a/docs/resources/library_variable_set.md
+++ b/docs/resources/library_variable_set.md
@@ -3,12 +3,12 @@
page_title: "octopusdeploy_library_variable_set Resource - terraform-provider-octopusdeploy"
subcategory: ""
description: |-
-
+ This resource manages library variable sets in Octopus Deploy.
---
# octopusdeploy_library_variable_set (Resource)
-
+This resource manages library variable sets in Octopus Deploy.
diff --git a/docs/resources/maven_feed.md b/docs/resources/maven_feed.md
index a589dc13f..1c01d16e8 100644
--- a/docs/resources/maven_feed.md
+++ b/docs/resources/maven_feed.md
@@ -27,7 +27,7 @@ resource "octopusdeploy_maven_feed" "example" {
### Required
- `feed_uri` (String)
-- `name` (String) A short, memorable, unique name for this feed. Example: ACME Builds.
+- `name` (String) The name of this resource.
### Optional
@@ -36,7 +36,7 @@ resource "octopusdeploy_maven_feed" "example" {
- `id` (String) The unique ID for this resource.
- `package_acquisition_location_options` (List of String)
- `password` (String, Sensitive) The password associated with this resource.
-- `space_id` (String) The space ID associated with this resource.
+- `space_id` (String) The space ID associated with this maven feed.
- `username` (String, Sensitive) The username associated with this resource.
## Import
diff --git a/docs/resources/nuget_feed.md b/docs/resources/nuget_feed.md
index 0444d55ba..b5758af66 100644
--- a/docs/resources/nuget_feed.md
+++ b/docs/resources/nuget_feed.md
@@ -27,8 +27,8 @@ resource "octopusdeploy_nuget_feed" "example" {
### Required
-- `feed_uri` (String) The feed URI can be a URL or a folder path.
-- `name` (String) A short, memorable, unique name for this feed. Example: ACME Builds.
+- `feed_uri` (String)
+- `name` (String) The name of this resource.
### Optional
@@ -38,7 +38,7 @@ resource "octopusdeploy_nuget_feed" "example" {
- `is_enhanced_mode` (Boolean) This will improve performance of the NuGet feed but may not be supported by some older feeds. Disable if the operation, Create Release does not return the latest version for a package.
- `package_acquisition_location_options` (List of String)
- `password` (String, Sensitive) The password associated with this resource.
-- `space_id` (String) The space ID associated with this resource.
+- `space_id` (String) The space ID associated with this nuget feed.
- `username` (String, Sensitive) The username associated with this resource.
## Import
diff --git a/octopusdeploy/provider.go b/octopusdeploy/provider.go
index cd51d9521..07f503374 100644
--- a/octopusdeploy/provider.go
+++ b/octopusdeploy/provider.go
@@ -48,7 +48,6 @@ func Provider() *schema.Provider {
"octopusdeploy_channel": resourceChannel(),
"octopusdeploy_cloud_region_deployment_target": resourceCloudRegionDeploymentTarget(),
"octopusdeploy_deployment_process": resourceDeploymentProcess(),
- "octopusdeploy_docker_container_registry": resourceDockerContainerRegistry(),
"octopusdeploy_dynamic_worker_pool": resourceDynamicWorkerPool(),
"octopusdeploy_gcp_account": resourceGoogleCloudPlatformAccount(),
"octopusdeploy_kubernetes_agent_deployment_target": resourceKubernetesAgentDeploymentTarget(),
diff --git a/octopusdeploy/resource_docker_container_registry.go b/octopusdeploy/resource_docker_container_registry.go
deleted file mode 100644
index bf5d1edd8..000000000
--- a/octopusdeploy/resource_docker_container_registry.go
+++ /dev/null
@@ -1,104 +0,0 @@
-package octopusdeploy
-
-import (
- "context"
- "fmt"
-
- "github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/client"
- "github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/feeds"
- "github.com/OctopusDeploy/terraform-provider-octopusdeploy/internal/errors"
- "github.com/hashicorp/terraform-plugin-log/tflog"
- "github.com/hashicorp/terraform-plugin-sdk/v2/diag"
- "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
-)
-
-func resourceDockerContainerRegistry() *schema.Resource {
- return &schema.Resource{
- CreateContext: resourceDockerContainerRegistryCreate,
- DeleteContext: resourceDockerContainerRegistryDelete,
- Description: "This resource manages a Docker Container Registry in Octopus Deploy.",
- Importer: getImporter(),
- ReadContext: resourceDockerContainerRegistryRead,
- Schema: getDockerContainerRegistrySchema(),
- UpdateContext: resourceDockerContainerRegistryUpdate,
- }
-}
-
-func resourceDockerContainerRegistryCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
- dockerContainerRegistry, err := expandDockerContainerRegistry(d)
- if err != nil {
- return diag.FromErr(err)
- }
-
- tflog.Info(ctx, fmt.Sprintf("creating Docker container registry, %s", dockerContainerRegistry.GetName()))
-
- client := m.(*client.Client)
- createdDockerContainerRegistry, err := feeds.Add(client, dockerContainerRegistry)
- if err != nil {
- return diag.FromErr(err)
- }
-
- if err := setDockerContainerRegistry(ctx, d, createdDockerContainerRegistry.(*feeds.DockerContainerRegistry)); err != nil {
- return diag.FromErr(err)
- }
-
- d.SetId(createdDockerContainerRegistry.GetID())
-
- tflog.Info(ctx, fmt.Sprintf("Docker container registry created (%s)", d.Id()))
- return nil
-}
-
-func resourceDockerContainerRegistryDelete(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
- tflog.Info(ctx, fmt.Sprintf("deleting Docker container registry (%s)", d.Id()))
-
- client := m.(*client.Client)
- err := client.Feeds.DeleteByID(d.Id())
- if err != nil {
- return diag.FromErr(err)
- }
-
- d.SetId("")
-
- tflog.Info(ctx, "Docker container registry deleted")
- return nil
-}
-
-func resourceDockerContainerRegistryRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
- tflog.Info(ctx, fmt.Sprintf("reading Docker container registry (%s)", d.Id()))
-
- client := m.(*client.Client)
- feed, err := feeds.GetByID(client, d.Get("space_id").(string), d.Id())
- if err != nil {
- return errors.ProcessApiError(ctx, d, err, "Docker container registry")
- }
-
- dockerContainerRegistry := feed.(*feeds.DockerContainerRegistry)
- if err := setDockerContainerRegistry(ctx, d, dockerContainerRegistry); err != nil {
- return diag.FromErr(err)
- }
-
- tflog.Info(ctx, fmt.Sprintf("Docker container registry read (%s)", dockerContainerRegistry.GetID()))
- return nil
-}
-
-func resourceDockerContainerRegistryUpdate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
- feed, err := expandDockerContainerRegistry(d)
- if err != nil {
- return diag.FromErr(err)
- }
-
- tflog.Info(ctx, fmt.Sprintf("updating Docker container registry (%s)", feed.GetID()))
-
- client := m.(*client.Client)
- updatedFeed, err := feeds.Update(client, feed)
- if err != nil {
- return diag.FromErr(err)
- }
-
- if err := setDockerContainerRegistry(ctx, d, updatedFeed.(*feeds.DockerContainerRegistry)); err != nil {
- return diag.FromErr(err)
- }
-
- tflog.Info(ctx, fmt.Sprintf("Docker container registry updated (%s)", d.Id()))
- return nil
-}
diff --git a/octopusdeploy/schema_docker_container_registry.go b/octopusdeploy/schema_docker_container_registry.go
deleted file mode 100644
index a28f565cd..000000000
--- a/octopusdeploy/schema_docker_container_registry.go
+++ /dev/null
@@ -1,104 +0,0 @@
-package octopusdeploy
-
-import (
- "context"
- "fmt"
-
- "github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/core"
- "github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/feeds"
- "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
- "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
-)
-
-func expandDockerContainerRegistry(d *schema.ResourceData) (*feeds.DockerContainerRegistry, error) {
- name := d.Get("name").(string)
-
- feed, err := feeds.NewDockerContainerRegistry(name)
- if err != nil {
- return nil, err
- }
-
- feed.ID = d.Id()
-
- if v, ok := d.GetOk("api_version"); ok {
- feed.APIVersion = v.(string)
- }
-
- if v, ok := d.GetOk("feed_uri"); ok {
- feed.FeedURI = v.(string)
- }
-
- if v, ok := d.GetOk("registry_path"); ok {
- feed.RegistryPath = v.(string)
- }
-
- if v, ok := d.GetOk("space_id"); ok {
- feed.SpaceID = v.(string)
- }
-
- if v, ok := d.GetOk("package_acquisition_location_options"); ok {
- feed.PackageAcquisitionLocationOptions = getSliceFromTerraformTypeList(v)
- }
-
- if v, ok := d.GetOk("password"); ok {
- feed.Password = core.NewSensitiveValue(v.(string))
- }
-
- if v, ok := d.GetOk("username"); ok {
- feed.Username = v.(string)
- }
-
- return feed, nil
-}
-
-func getDockerContainerRegistrySchema() map[string]*schema.Schema {
- return map[string]*schema.Schema{
- "api_version": {
- Optional: true,
- Type: schema.TypeString,
- },
- "feed_uri": {
- Description: "The URL to a Docker repository.",
- Required: true,
- Type: schema.TypeString,
- ValidateDiagFunc: validation.ToDiagFunc(validation.IsURLWithHTTPorHTTPS),
- },
- "id": getIDSchema(),
- "name": {
- Description: "A short, memorable, unique name for this feed. Example: ACME Builds.",
- Required: true,
- Type: schema.TypeString,
- ValidateDiagFunc: validation.ToDiagFunc(validation.StringIsNotEmpty),
- },
- "password": getPasswordSchema(false),
- "package_acquisition_location_options": {
- Computed: true,
- Elem: &schema.Schema{Type: schema.TypeString},
- Optional: true,
- Type: schema.TypeList,
- },
- "registry_path": {
- Optional: true,
- Type: schema.TypeString,
- },
- "space_id": getSpaceIDSchema(),
- "username": getUsernameSchema(false),
- }
-}
-
-func setDockerContainerRegistry(ctx context.Context, d *schema.ResourceData, feed *feeds.DockerContainerRegistry) error {
- d.Set("api_version", feed.APIVersion)
- d.Set("feed_uri", feed.FeedURI)
- d.Set("name", feed.Name)
- d.Set("registry_path", feed.RegistryPath)
- d.Set("space_id", feed.SpaceID)
- d.Set("username", feed.Username)
-
- if err := d.Set("package_acquisition_location_options", feed.PackageAcquisitionLocationOptions); err != nil {
- return fmt.Errorf("error setting package_acquisition_location_options: %s", err)
- }
-
- d.SetId(feed.GetID())
-
- return nil
-}
diff --git a/octopusdeploy_framework/framework_provider.go b/octopusdeploy_framework/framework_provider.go
index 816b8f774..447f66237 100644
--- a/octopusdeploy_framework/framework_provider.go
+++ b/octopusdeploy_framework/framework_provider.go
@@ -2,9 +2,9 @@ package octopusdeploy_framework
import (
"context"
+ "github.com/OctopusDeploy/terraform-provider-octopusdeploy/octopusdeploy_framework/util"
"os"
- "github.com/OctopusDeploy/terraform-provider-octopusdeploy/octopusdeploy_framework/util"
"github.com/hashicorp/terraform-plugin-framework/datasource"
"github.com/hashicorp/terraform-plugin-framework/provider"
"github.com/hashicorp/terraform-plugin-framework/provider/schema"
@@ -92,6 +92,7 @@ func (p *octopusDeployFrameworkProvider) Resources(ctx context.Context) []func()
NewLibraryVariableSetFeedResource,
NewVariableResource,
NewProjectResource,
+ NewDockerContainerRegistryFeedResource,
}
}
diff --git a/octopusdeploy_framework/resource_artifactory_generic_feed.go b/octopusdeploy_framework/resource_artifactory_generic_feed.go
index e70900061..a1eb7ab58 100644
--- a/octopusdeploy_framework/resource_artifactory_generic_feed.go
+++ b/octopusdeploy_framework/resource_artifactory_generic_feed.go
@@ -29,7 +29,8 @@ func (r *artifactoryGenericFeedTypeResource) Metadata(ctx context.Context, req r
func (r *artifactoryGenericFeedTypeResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
resp.Schema = schema.Schema{
- Attributes: schemas.GetArtifactoryGenericFeedResourceSchema(),
+ Attributes: schemas.GetArtifactoryGenericFeedResourceSchema(),
+ Description: "This resource manages a Artifactory Generic feed in Octopus Deploy.",
}
}
diff --git a/octopusdeploy_framework/resource_aws_elastic_container_registry.go b/octopusdeploy_framework/resource_aws_elastic_container_registry.go
index 96f089a83..72cef3b51 100644
--- a/octopusdeploy_framework/resource_aws_elastic_container_registry.go
+++ b/octopusdeploy_framework/resource_aws_elastic_container_registry.go
@@ -28,7 +28,8 @@ func (r *awsElasticContainerRegistryFeedTypeResource) Metadata(ctx context.Conte
func (r *awsElasticContainerRegistryFeedTypeResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
resp.Schema = schema.Schema{
- Attributes: schemas.GetAwsElasticContainerRegistryFeedResourceSchema(),
+ Attributes: schemas.GetAwsElasticContainerRegistryFeedResourceSchema(),
+ Description: "This resource manages an AWS Elastic Container Registry in Octopus Deploy.",
}
}
diff --git a/octopusdeploy_framework/resource_docker_container_registry.go b/octopusdeploy_framework/resource_docker_container_registry.go
new file mode 100644
index 000000000..fa73ef902
--- /dev/null
+++ b/octopusdeploy_framework/resource_docker_container_registry.go
@@ -0,0 +1,183 @@
+package octopusdeploy_framework
+
+import (
+ "context"
+ "fmt"
+ "github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/core"
+ "github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/feeds"
+ "github.com/OctopusDeploy/terraform-provider-octopusdeploy/octopusdeploy_framework/schemas"
+ "github.com/OctopusDeploy/terraform-provider-octopusdeploy/octopusdeploy_framework/util"
+ "github.com/hashicorp/terraform-plugin-framework/attr"
+ "github.com/hashicorp/terraform-plugin-framework/resource"
+ "github.com/hashicorp/terraform-plugin-framework/resource/schema"
+ "github.com/hashicorp/terraform-plugin-framework/types"
+ "github.com/hashicorp/terraform-plugin-log/tflog"
+)
+
+type dockerContainerRegistryFeedTypeResource struct {
+ *Config
+}
+
+func NewDockerContainerRegistryFeedResource() resource.Resource {
+ return &dockerContainerRegistryFeedTypeResource{}
+}
+
+func (r *dockerContainerRegistryFeedTypeResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
+ resp.TypeName = util.GetTypeName("docker_container_registry")
+}
+
+func (r *dockerContainerRegistryFeedTypeResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
+ resp.Schema = schema.Schema{
+ Attributes: schemas.GetDockerContainerRegistryFeedResourceSchema(),
+ Description: "This resource manages a Docker Container Registry in Octopus Deploy.",
+ }
+}
+
+func (r *dockerContainerRegistryFeedTypeResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
+ r.Config = ResourceConfiguration(req, resp)
+}
+
+func (r *dockerContainerRegistryFeedTypeResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
+ var data *schemas.DockerContainerRegistryFeedTypeResourceModel
+ resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...)
+ if resp.Diagnostics.HasError() {
+ return
+ }
+
+ dockerContainerRegistryFeed, err := createDockerContainerRegistryFeedResourceFromData(data)
+ if err != nil {
+ return
+ }
+
+ tflog.Info(ctx, fmt.Sprintf("creating Docker Container Registry feed: %s", dockerContainerRegistryFeed.GetName()))
+
+ client := r.Config.Client
+ createdFeed, err := feeds.Add(client, dockerContainerRegistryFeed)
+ if err != nil {
+ resp.Diagnostics.AddError("unable to create docker container registry feed", err.Error())
+ return
+ }
+
+ updateDataFromDockerContainerRegistryFeed(data, data.SpaceID.ValueString(), createdFeed.(*feeds.DockerContainerRegistry))
+
+ tflog.Info(ctx, fmt.Sprintf("Docker Container Registry feed created (%s)", data.ID))
+ resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
+}
+
+func (r *dockerContainerRegistryFeedTypeResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
+ var data *schemas.DockerContainerRegistryFeedTypeResourceModel
+ resp.Diagnostics.Append(req.State.Get(ctx, &data)...)
+ if resp.Diagnostics.HasError() {
+ return
+ }
+
+ tflog.Info(ctx, fmt.Sprintf("reading Docker Container Registry feed (%s)", data.ID))
+
+ client := r.Config.Client
+ feed, err := feeds.GetByID(client, data.SpaceID.ValueString(), data.ID.ValueString())
+ if err != nil {
+ resp.Diagnostics.AddError("unable to load docker container registry feed", err.Error())
+ return
+ }
+
+ dockerContainerRegistry := feed.(*feeds.DockerContainerRegistry)
+ updateDataFromDockerContainerRegistryFeed(data, data.SpaceID.ValueString(), dockerContainerRegistry)
+
+ tflog.Info(ctx, fmt.Sprintf("Docker Container Registry feed read (%s)", dockerContainerRegistry.GetID()))
+ resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
+}
+
+func (r *dockerContainerRegistryFeedTypeResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
+ var data, state *schemas.DockerContainerRegistryFeedTypeResourceModel
+ resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...)
+ resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
+ if resp.Diagnostics.HasError() {
+ return
+ }
+
+ tflog.Debug(ctx, fmt.Sprintf("updating docker container registry feed '%s'", data.ID.ValueString()))
+
+ feed, err := createDockerContainerRegistryFeedResourceFromData(data)
+ feed.ID = state.ID.ValueString()
+ if err != nil {
+ resp.Diagnostics.AddError("unable to load docker container registry feed", err.Error())
+ return
+ }
+
+ tflog.Info(ctx, fmt.Sprintf("updating Docker Container Registry feed (%s)", data.ID))
+
+ client := r.Config.Client
+ updatedFeed, err := feeds.Update(client, feed)
+ if err != nil {
+ resp.Diagnostics.AddError("unable to update docker container registry feed", err.Error())
+ return
+ }
+
+ updateDataFromDockerContainerRegistryFeed(data, state.SpaceID.ValueString(), updatedFeed.(*feeds.DockerContainerRegistry))
+
+ tflog.Info(ctx, fmt.Sprintf("Docker Container Registry feed updated (%s)", data.ID))
+
+ resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
+}
+
+func (r *dockerContainerRegistryFeedTypeResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
+ var data schemas.DockerContainerRegistryFeedTypeResourceModel
+
+ resp.Diagnostics.Append(req.State.Get(ctx, &data)...)
+ if resp.Diagnostics.HasError() {
+ return
+ }
+
+ if err := feeds.DeleteByID(r.Config.Client, data.SpaceID.ValueString(), data.ID.ValueString()); err != nil {
+ resp.Diagnostics.AddError("unable to delete docker container registry feed", err.Error())
+ return
+ }
+}
+
+func createDockerContainerRegistryFeedResourceFromData(data *schemas.DockerContainerRegistryFeedTypeResourceModel) (*feeds.DockerContainerRegistry, error) {
+ feed, err := feeds.NewDockerContainerRegistry(data.Name.ValueString())
+ if err != nil {
+ return nil, err
+ }
+
+ feed.ID = data.ID.ValueString()
+ feed.FeedURI = data.FeedUri.ValueString()
+
+ var packageAcquisitionLocationOptions []string
+ for _, element := range data.PackageAcquisitionLocationOptions.Elements() {
+ packageAcquisitionLocationOptions = append(packageAcquisitionLocationOptions, element.(types.String).ValueString())
+ }
+
+ feed.PackageAcquisitionLocationOptions = packageAcquisitionLocationOptions
+ feed.Password = core.NewSensitiveValue(data.Password.ValueString())
+ feed.SpaceID = data.SpaceID.ValueString()
+ feed.Username = data.Username.ValueString()
+ feed.APIVersion = data.APIVersion.ValueString()
+ feed.RegistryPath = data.RegistryPath.ValueString()
+
+ return feed, nil
+}
+
+func updateDataFromDockerContainerRegistryFeed(data *schemas.DockerContainerRegistryFeedTypeResourceModel, spaceId string, feed *feeds.DockerContainerRegistry) {
+ data.FeedUri = types.StringValue(feed.FeedURI)
+ data.Name = types.StringValue(feed.Name)
+ data.SpaceID = types.StringValue(spaceId)
+ if feed.APIVersion != "" {
+ data.APIVersion = types.StringValue(feed.APIVersion)
+ }
+ if feed.RegistryPath != "" {
+ data.RegistryPath = types.StringValue(feed.RegistryPath)
+ }
+ if feed.Username != "" {
+ data.Username = types.StringValue(feed.Username)
+ }
+
+ packageAcquisitionLocationOptionsList := make([]attr.Value, len(feed.PackageAcquisitionLocationOptions))
+ for i, option := range feed.PackageAcquisitionLocationOptions {
+ packageAcquisitionLocationOptionsList[i] = types.StringValue(option)
+ }
+
+ var packageAcquisitionLocationOptionsListValue, _ = types.ListValue(types.StringType, packageAcquisitionLocationOptionsList)
+ data.PackageAcquisitionLocationOptions = packageAcquisitionLocationOptionsListValue
+ data.ID = types.StringValue(feed.ID)
+}
diff --git a/octopusdeploy/resource_docker_container_registry_test.go b/octopusdeploy_framework/resource_docker_container_registry_test.go
similarity index 94%
rename from octopusdeploy/resource_docker_container_registry_test.go
rename to octopusdeploy_framework/resource_docker_container_registry_test.go
index 377ced443..9e2c893fa 100644
--- a/octopusdeploy/resource_docker_container_registry_test.go
+++ b/octopusdeploy_framework/resource_docker_container_registry_test.go
@@ -1,16 +1,15 @@
-package octopusdeploy
+package octopusdeploy_framework
import (
"fmt"
"github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/feeds"
"github.com/OctopusSolutionsEngineering/OctopusTerraformTestFramework/octoclient"
"github.com/OctopusSolutionsEngineering/OctopusTerraformTestFramework/test"
+ "github.com/hashicorp/terraform-plugin-testing/helper/acctest"
+ "github.com/hashicorp/terraform-plugin-testing/helper/resource"
+ "github.com/hashicorp/terraform-plugin-testing/terraform"
"path/filepath"
"testing"
-
- "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest"
- "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
- "github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
)
func TestAccOctopusDeployDockerContainerRegistry(t *testing.T) {
@@ -26,7 +25,7 @@ func TestAccOctopusDeployDockerContainerRegistry(t *testing.T) {
resource.Test(t, resource.TestCase{
CheckDestroy: testDockerContainerRegistryCheckDestroy,
- PreCheck: func() { testAccPreCheck(t) },
+ PreCheck: func() { TestAccPreCheck(t) },
ProtoV6ProviderFactories: ProtoV6ProviderFactories(),
Steps: []resource.TestStep{
{
diff --git a/octopusdeploy_framework/resource_github_repository_feed.go b/octopusdeploy_framework/resource_github_repository_feed.go
index 7a198daaa..30f7bdb28 100644
--- a/octopusdeploy_framework/resource_github_repository_feed.go
+++ b/octopusdeploy_framework/resource_github_repository_feed.go
@@ -28,7 +28,8 @@ func (r *githubRepositoryFeedTypeResource) Metadata(ctx context.Context, req res
func (r *githubRepositoryFeedTypeResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
resp.Schema = schema.Schema{
- Attributes: schemas.GetGitHubRepositoryFeedResourceSchema(),
+ Attributes: schemas.GetGitHubRepositoryFeedResourceSchema(),
+ Description: "This resource manages a GitHub repository feed in Octopus Deploy.",
}
}
diff --git a/octopusdeploy_framework/resource_helm_feed.go b/octopusdeploy_framework/resource_helm_feed.go
index 4fc1c9d3c..64ec52677 100644
--- a/octopusdeploy_framework/resource_helm_feed.go
+++ b/octopusdeploy_framework/resource_helm_feed.go
@@ -29,7 +29,8 @@ func (r *helmFeedTypeResource) Metadata(ctx context.Context, req resource.Metada
func (r *helmFeedTypeResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
resp.Schema = schema.Schema{
- Attributes: schemas.GetHelmFeedResourceSchema(),
+ Attributes: schemas.GetHelmFeedResourceSchema(),
+ Description: "This resource manages a Helm Feed in Octopus Deploy.",
}
}
diff --git a/octopusdeploy_framework/resource_maven_feed.go b/octopusdeploy_framework/resource_maven_feed.go
index c6f6ddd19..722081e81 100644
--- a/octopusdeploy_framework/resource_maven_feed.go
+++ b/octopusdeploy_framework/resource_maven_feed.go
@@ -28,7 +28,8 @@ func (r *mavenFeedTypeResource) Metadata(ctx context.Context, req resource.Metad
func (r *mavenFeedTypeResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
resp.Schema = schema.Schema{
- Attributes: schemas.GetMavenFeedResourceSchema(),
+ Attributes: schemas.GetMavenFeedResourceSchema(),
+ Description: "This resource manages a Maven feed in Octopus Deploy.",
}
}
diff --git a/octopusdeploy_framework/resource_nuget_feed.go b/octopusdeploy_framework/resource_nuget_feed.go
index 306e16f14..f053ea450 100644
--- a/octopusdeploy_framework/resource_nuget_feed.go
+++ b/octopusdeploy_framework/resource_nuget_feed.go
@@ -28,7 +28,8 @@ func (r *nugetFeedTypeResource) Metadata(ctx context.Context, req resource.Metad
func (r *nugetFeedTypeResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
resp.Schema = schema.Schema{
- Attributes: schemas.GetNugetFeedResourceSchema(),
+ Attributes: schemas.GetNugetFeedResourceSchema(),
+ Description: "This resource manages a Nuget feed in Octopus Deploy.",
}
}
diff --git a/octopusdeploy_framework/schemas/docker_container_registry_feed.go b/octopusdeploy_framework/schemas/docker_container_registry_feed.go
new file mode 100644
index 000000000..d7ff550c4
--- /dev/null
+++ b/octopusdeploy_framework/schemas/docker_container_registry_feed.go
@@ -0,0 +1,39 @@
+package schemas
+
+import (
+ "github.com/OctopusDeploy/terraform-provider-octopusdeploy/octopusdeploy_framework/util"
+ resourceSchema "github.com/hashicorp/terraform-plugin-framework/resource/schema"
+ "github.com/hashicorp/terraform-plugin-framework/types"
+)
+
+const dockerContainerRegistryFeedDescription = "docker container registry feed"
+
+func GetDockerContainerRegistryFeedResourceSchema() map[string]resourceSchema.Attribute {
+ return map[string]resourceSchema.Attribute{
+ "api_version": resourceSchema.StringAttribute{
+ Optional: true,
+ },
+ "feed_uri": util.GetFeedUriResourceSchema(),
+ "id": util.GetIdResourceSchema(),
+ "name": util.GetNameResourceSchema(true),
+ "package_acquisition_location_options": util.GetPackageAcquisitionLocationOptionsResourceSchema(),
+ "password": util.GetPasswordResourceSchema(false),
+ "space_id": util.GetSpaceIdResourceSchema(dockerContainerRegistryFeedDescription),
+ "username": util.GetUsernameResourceSchema(false),
+ "registry_path": resourceSchema.StringAttribute{
+ Optional: true,
+ },
+ }
+}
+
+type DockerContainerRegistryFeedTypeResourceModel struct {
+ APIVersion types.String `tfsdk:"api_version"`
+ FeedUri types.String `tfsdk:"feed_uri"`
+ ID types.String `tfsdk:"id"`
+ Name types.String `tfsdk:"name"`
+ PackageAcquisitionLocationOptions types.List `tfsdk:"package_acquisition_location_options"`
+ Password types.String `tfsdk:"password"`
+ SpaceID types.String `tfsdk:"space_id"`
+ Username types.String `tfsdk:"username"`
+ RegistryPath types.String `tfsdk:"registry_path"`
+}
diff --git a/octopusdeploy_framework/schemas/library_variable_set.go b/octopusdeploy_framework/schemas/library_variable_set.go
index f3355768f..5fab75d02 100644
--- a/octopusdeploy_framework/schemas/library_variable_set.go
+++ b/octopusdeploy_framework/schemas/library_variable_set.go
@@ -22,7 +22,8 @@ type LibraryVariableSetResourceModel struct {
func GetLibraryVariableSetDataSourceSchema() datasourceSchema.Schema {
return datasourceSchema.Schema{
- Attributes: getLibraryVariableSetDataSchema(),
+ Attributes: getLibraryVariableSetDataSchema(),
+ Description: "Provides information about existing library variable sets.",
Blocks: map[string]datasourceSchema.Block{
"library_variable_sets": datasourceSchema.ListNestedBlock{
Description: "A list of library variable sets that match the filter(s).",
@@ -97,6 +98,7 @@ func GetLibraryVariableSetResourceSchema() resourceSchema.Schema {
Computed: true,
},
},
+ Description: "This resource manages library variable sets in Octopus Deploy.",
Blocks: map[string]resourceSchema.Block{
"template": resourceSchema.ListNestedBlock{
NestedObject: resourceSchema.NestedBlockObject{
From 7c81ce944a04db0272c2a4aab8adac7d3b56a1b1 Mon Sep 17 00:00:00 2001
From: Huy Nguyen <162080607+HuyPhanNguyen@users.noreply.github.com>
Date: Wed, 7 Aug 2024 18:37:14 +1000
Subject: [PATCH 02/12] Fix bug datasource spaces (#710)
* Fix query.Ids convert and add basic test
* Update the test
* Fix the util method instead
* just ignore if cant convert to string
* try to fix flaky test
* second try
* Add lifecycle datasource test
* Last try to avoid race condition
* Test why not 7 variables create
* switch the order
---
octopusdeploy/testing_container_test.go | 5 ++
.../datasource_lifecycle_test.go | 63 +++++++++++++++++
.../datasource_spaces_test.go | 58 ++++++++++++++++
.../resource_variable_test.go | 15 +++-
octopusdeploy_framework/schemas/schema.go | 7 +-
terraform/49-variables/variables.tf | 68 ++++++++++++++++---
6 files changed, 203 insertions(+), 13 deletions(-)
create mode 100644 octopusdeploy_framework/datasource_lifecycle_test.go
create mode 100644 octopusdeploy_framework/datasource_spaces_test.go
diff --git a/octopusdeploy/testing_container_test.go b/octopusdeploy/testing_container_test.go
index 8c1bd6397..6fd5dfba7 100644
--- a/octopusdeploy/testing_container_test.go
+++ b/octopusdeploy/testing_container_test.go
@@ -57,6 +57,11 @@ func TestMain(m *testing.M) {
log.Printf("Failed to create client: (%s)", err.Error())
panic(m)
}
+
+ octoContainer = &test.OctopusContainer{
+ Container: nil,
+ URI: url,
+ }
}
code := m.Run()
os.Exit(code)
diff --git a/octopusdeploy_framework/datasource_lifecycle_test.go b/octopusdeploy_framework/datasource_lifecycle_test.go
new file mode 100644
index 000000000..c7febe404
--- /dev/null
+++ b/octopusdeploy_framework/datasource_lifecycle_test.go
@@ -0,0 +1,63 @@
+package octopusdeploy_framework
+
+import (
+ "fmt"
+ "github.com/hashicorp/terraform-plugin-testing/helper/acctest"
+ "testing"
+
+ "github.com/hashicorp/terraform-plugin-testing/helper/resource"
+)
+
+func TestAccDataSourceLifecycles(t *testing.T) {
+ spaceName := acctest.RandStringFromCharSet(20, acctest.CharSetAlpha)
+ lifecycleName := "Default Lifecycle"
+ resourceName := "data.octopusdeploy_lifecycles.lifecycle_default_lifecycle"
+
+ resource.Test(t, resource.TestCase{
+ PreCheck: func() { TestAccPreCheck(t) },
+ ProtoV6ProviderFactories: ProtoV6ProviderFactories(),
+ Steps: []resource.TestStep{
+ {
+ Config: testAccDataSourceLifecyclesConfig(spaceName, lifecycleName),
+ Check: resource.ComposeTestCheckFunc(
+ resource.TestCheckResourceAttrSet(resourceName, "space_id"),
+ resource.TestCheckResourceAttr(resourceName, "partial_name", lifecycleName),
+ resource.TestCheckResourceAttr(resourceName, "lifecycles.#", "1"),
+ resource.TestCheckResourceAttrSet(resourceName, "lifecycles.0.id"),
+ resource.TestCheckResourceAttr(resourceName, "lifecycles.0.name", lifecycleName),
+ testAccCheckOutputExists("octopus_space_id"),
+ testAccCheckOutputExists("octopus_lifecycle_id"),
+ ),
+ },
+ },
+ })
+}
+
+func testAccDataSourceLifecyclesConfig(spaceName, lifecycleName string) string {
+ return fmt.Sprintf(`
+resource "octopusdeploy_space" "octopus_project_space_test" {
+ name = "%s"
+ is_default = false
+ is_task_queue_stopped = false
+ description = "Test space for lifecycles datasource"
+ space_managers_teams = ["teams-administrators"]
+}
+
+data "octopusdeploy_lifecycles" "lifecycle_default_lifecycle" {
+ ids = null
+ partial_name = "%s"
+ space_id = octopusdeploy_space.octopus_project_space_test.id
+ skip = 0
+ take = 1
+ depends_on = [octopusdeploy_space.octopus_project_space_test]
+}
+
+output "octopus_space_id" {
+ value = octopusdeploy_space.octopus_project_space_test.id
+}
+
+output "octopus_lifecycle_id" {
+ value = data.octopusdeploy_lifecycles.lifecycle_default_lifecycle.lifecycles[0].id
+}
+`, spaceName, lifecycleName)
+}
diff --git a/octopusdeploy_framework/datasource_spaces_test.go b/octopusdeploy_framework/datasource_spaces_test.go
new file mode 100644
index 000000000..dc48f1108
--- /dev/null
+++ b/octopusdeploy_framework/datasource_spaces_test.go
@@ -0,0 +1,58 @@
+package octopusdeploy_framework
+
+import (
+ "fmt"
+ "testing"
+
+ "github.com/hashicorp/terraform-plugin-testing/helper/resource"
+ "github.com/hashicorp/terraform-plugin-testing/terraform"
+)
+
+func TestAccDataSourceSpaces(t *testing.T) {
+ spaceID := "Spaces-1"
+ resourceName := "data.octopusdeploy_spaces.test"
+
+ resource.Test(t, resource.TestCase{
+ PreCheck: func() { TestAccPreCheck(t) },
+ ProtoV6ProviderFactories: ProtoV6ProviderFactories(),
+ Steps: []resource.TestStep{
+ {
+ Config: testAccDataSourceSpacesConfig(spaceID),
+ Check: resource.ComposeTestCheckFunc(
+ resource.TestCheckResourceAttr(resourceName, "ids.#", "1"),
+ resource.TestCheckResourceAttr(resourceName, "ids.0", spaceID),
+ resource.TestCheckResourceAttr(resourceName, "skip", "0"),
+ resource.TestCheckResourceAttr(resourceName, "take", "1"),
+ resource.TestCheckResourceAttrSet(resourceName, "spaces.0.id"),
+ testAccCheckOutputExists("octopus_space_id"),
+ resource.TestCheckOutput("octopus_space_id", spaceID),
+ ),
+ },
+ },
+ })
+}
+
+func testAccDataSourceSpacesConfig(spaceID string) string {
+ tfConfig := fmt.Sprintf(`
+ data "octopusdeploy_spaces" "test" {
+ ids = ["%s"]
+ skip = 0
+ take = 1
+ }
+
+ output "octopus_space_id" {
+ value = data.octopusdeploy_spaces.test.spaces[0].id
+ }
+ `, spaceID)
+ return tfConfig
+}
+
+func testAccCheckOutputExists(name string) resource.TestCheckFunc {
+ return func(s *terraform.State) error {
+ _, ok := s.RootModule().Outputs[name]
+ if !ok {
+ return fmt.Errorf("output %s not found", name)
+ }
+ return nil
+ }
+}
diff --git a/octopusdeploy_framework/resource_variable_test.go b/octopusdeploy_framework/resource_variable_test.go
index 055d796d4..d71cc6dd8 100644
--- a/octopusdeploy_framework/resource_variable_test.go
+++ b/octopusdeploy_framework/resource_variable_test.go
@@ -3,7 +3,9 @@ package octopusdeploy_framework
import (
"fmt"
"path/filepath"
+ "strings"
"testing"
+ "time"
"github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/variables"
internalTest "github.com/OctopusDeploy/terraform-provider-octopusdeploy/internal/test"
@@ -320,6 +322,9 @@ func TestVariableResource(t *testing.T) {
// Assert
client, err := octoclient.CreateClient(octoContainer.URI, newSpaceId, test.ApiKey)
project, err := client.Projects.GetByName("Test")
+
+ // Add a short delay before querying the API
+ time.Sleep(5 * time.Second)
variableSet, err := client.Variables.GetAll(project.ID)
if err != nil {
@@ -327,7 +332,15 @@ func TestVariableResource(t *testing.T) {
}
if len(variableSet.Variables) != 7 {
- t.Fatalf("Expected 7 variables to be created.")
+ var report strings.Builder
+ report.WriteString(fmt.Sprintf("Expected 7 variables, but found %d.\nReturned variables:\n", len(variableSet.Variables)))
+
+ for _, v := range variableSet.Variables {
+ report.WriteString(fmt.Sprintf("- Name: %s\n Type: %s\n Value: %s\n Scope: %+v\n\n",
+ v.Name, v.Type, v.Value, v.Scope))
+ }
+
+ t.Fatalf(report.String())
}
for _, variable := range variableSet.Variables {
diff --git a/octopusdeploy_framework/schemas/schema.go b/octopusdeploy_framework/schemas/schema.go
index 5c786144b..395aefc7f 100644
--- a/octopusdeploy_framework/schemas/schema.go
+++ b/octopusdeploy_framework/schemas/schema.go
@@ -191,7 +191,12 @@ func GetBooleanResourceAttribute(description string, defaultValue bool, isOption
func GetIds(ids types.List) []string {
var result = make([]string, 0, len(ids.Elements()))
for _, id := range ids.Elements() {
- result = append(result, id.String())
+ strVal, ok := id.(types.String)
+
+ if !ok || strVal.IsNull() || strVal.IsUnknown() {
+ continue
+ }
+ result = append(result, strVal.ValueString())
}
return result
}
diff --git a/terraform/49-variables/variables.tf b/terraform/49-variables/variables.tf
index 9ebdc692c..0e2f15da7 100644
--- a/terraform/49-variables/variables.tf
+++ b/terraform/49-variables/variables.tf
@@ -1,21 +1,35 @@
+
+
+resource "octopusdeploy_variable" "scoped_project_variable_action" {
+ depends_on = [
+ octopusdeploy_project.test_project,
+ ]
+ owner_id = octopusdeploy_project.test_project.id
+ type = "String"
+ name = "ActionScopedVariable"
+ value = "unscoped variable"
+ scope {
+ actions = [octopusdeploy_deployment_process.test_deployment_process.step[0].run_script_action[0].id]
+ }
+}
+
resource "octopusdeploy_variable" "unscoped_project_variable" {
+ depends_on = [
+ octopusdeploy_project.test_project,
+ octopusdeploy_variable.scoped_project_variable_action,
+ ]
owner_id = octopusdeploy_project.test_project.id
type = "String"
name = "UnscopedVariable"
value = "UnscopedVariable"
}
-resource "octopusdeploy_variable" "scoped_project_variable_action" {
- owner_id = octopusdeploy_project.test_project.id
- type = "String"
- name = "ActionScopedVariable"
- value = "unscoped variable"
- scope {
- actions = [octopusdeploy_deployment_process.test_deployment_process.step[0].run_script_action[0].id]
- }
-}
-
resource "octopusdeploy_variable" "scoped_project_variable_channel" {
+ depends_on = [
+ octopusdeploy_project.test_project,
+ octopusdeploy_variable.unscoped_project_variable,
+ octopusdeploy_variable.scoped_project_variable_action,
+ ]
owner_id = octopusdeploy_project.test_project.id
type = "String"
name = "ChannelScopedVariable"
@@ -26,6 +40,12 @@ resource "octopusdeploy_variable" "scoped_project_variable_channel" {
}
resource "octopusdeploy_variable" "scoped_project_variable_environment" {
+ depends_on = [
+ octopusdeploy_project.test_project,
+ octopusdeploy_variable.unscoped_project_variable,
+ octopusdeploy_variable.scoped_project_variable_action,
+ octopusdeploy_variable.scoped_project_variable_channel,
+ ]
owner_id = octopusdeploy_project.test_project.id
type = "String"
name = "EnvironmentScopedVariable"
@@ -36,6 +56,14 @@ resource "octopusdeploy_variable" "scoped_project_variable_environment" {
}
resource "octopusdeploy_variable" "scoped_project_variable_machine" {
+ depends_on = [
+ octopusdeploy_project.test_project,
+ octopusdeploy_variable.unscoped_project_variable,
+ octopusdeploy_variable.scoped_project_variable_action,
+ octopusdeploy_variable.scoped_project_variable_channel,
+ octopusdeploy_variable.scoped_project_variable_environment
+ ]
+
owner_id = octopusdeploy_project.test_project.id
type = "String"
name = "MachineScopedVariable"
@@ -46,6 +74,14 @@ resource "octopusdeploy_variable" "scoped_project_variable_machine" {
}
resource "octopusdeploy_variable" "scoped_project_variable_process" {
+ depends_on = [
+ octopusdeploy_project.test_project,
+ octopusdeploy_variable.unscoped_project_variable,
+ octopusdeploy_variable.scoped_project_variable_action,
+ octopusdeploy_variable.scoped_project_variable_channel,
+ octopusdeploy_variable.scoped_project_variable_environment,
+ octopusdeploy_variable.scoped_project_variable_machine,
+ ]
owner_id = octopusdeploy_project.test_project.id
type = "String"
name = "ProcessScopedVariable"
@@ -56,6 +92,16 @@ resource "octopusdeploy_variable" "scoped_project_variable_process" {
}
resource "octopusdeploy_variable" "scoped_project_variable_role" {
+ depends_on = [
+ octopusdeploy_project.test_project,
+ octopusdeploy_variable.unscoped_project_variable,
+ octopusdeploy_variable.scoped_project_variable_action,
+ octopusdeploy_variable.scoped_project_variable_channel,
+ octopusdeploy_variable.scoped_project_variable_environment,
+ octopusdeploy_variable.scoped_project_variable_machine,
+ octopusdeploy_variable.scoped_project_variable_process,
+ ]
+
owner_id = octopusdeploy_project.test_project.id
type = "String"
name = "RoleScopedVariable"
@@ -63,4 +109,4 @@ resource "octopusdeploy_variable" "scoped_project_variable_role" {
scope {
roles = ["role"]
}
-}
+}
\ No newline at end of file
From 3a8a027a764cda034b8840bbba6df254e5f0d6b4 Mon Sep 17 00:00:00 2001
From: Isaac Calligeros <101079287+IsaacCalligeros95@users.noreply.github.com>
Date: Thu, 8 Aug 2024 10:23:22 +0930
Subject: [PATCH 03/12] Isaac/mc schema fixes (#715)
* propagate an error
* The collection returned by data sources must not be optional
* Add more optionals
---------
Co-authored-by: Matthew Casperson
---
octopusdeploy/data_source_tenants.go | 5 ++++-
octopusdeploy/schema_account_resource.go | 1 +
.../schema_azure_cloud_service_deployment_target.go | 2 +-
.../schema_azure_service_fabric_cluster_deployment_target.go | 2 +-
octopusdeploy/schema_azure_web_app_deployment_target.go | 2 +-
octopusdeploy/schema_certificate.go | 2 +-
octopusdeploy/schema_channel.go | 2 +-
octopusdeploy/schema_cloud_region_deployment_target.go | 2 +-
octopusdeploy/schema_deployment_target.go | 2 +-
octopusdeploy/schema_kubernetes_agent_deployment_target.go | 2 +-
octopusdeploy/schema_kubernetes_cluster_deployment_target.go | 2 +-
octopusdeploy/schema_listening_tentacle_deployment_target.go | 2 +-
octopusdeploy/schema_machine_policy.go | 2 +-
.../schema_offline_package_drop_deployment_target.go | 2 +-
octopusdeploy/schema_polling_tentacle_deployment_target.go | 2 +-
octopusdeploy/schema_script_modules.go | 2 +-
octopusdeploy/schema_ssh_connection_deployment_target.go | 2 +-
octopusdeploy/schema_tag_set.go | 2 +-
octopusdeploy/schema_team.go | 2 +-
octopusdeploy/schema_tenant.go | 2 +-
octopusdeploy/schema_user.go | 2 +-
octopusdeploy/schema_user_role.go | 2 +-
octopusdeploy/schema_worker_pool.go | 2 +-
octopusdeploy_framework/schemas/gitCredential.go | 1 +
octopusdeploy_framework/schemas/lifecycle.go | 1 +
octopusdeploy_framework/schemas/project.go | 1 +
26 files changed, 29 insertions(+), 22 deletions(-)
diff --git a/octopusdeploy/data_source_tenants.go b/octopusdeploy/data_source_tenants.go
index fcbdceae8..4c9cfa569 100644
--- a/octopusdeploy/data_source_tenants.go
+++ b/octopusdeploy/data_source_tenants.go
@@ -44,7 +44,10 @@ func dataSourceTenantsRead(ctx context.Context, d *schema.ResourceData, meta int
flattenedTenants = append(flattenedTenants, flattenTenant(tenant))
}
- d.Set("tenants", flattenedTenants)
+ if err := d.Set("tenants", flattenedTenants); err != nil {
+ return diag.FromErr(err)
+ }
+
d.SetId("Tenants " + time.Now().UTC().String())
return nil
diff --git a/octopusdeploy/schema_account_resource.go b/octopusdeploy/schema_account_resource.go
index 5dbee9361..4a31f5017 100644
--- a/octopusdeploy/schema_account_resource.go
+++ b/octopusdeploy/schema_account_resource.go
@@ -50,6 +50,7 @@ func getAccountResourceDataSchema() map[string]*schema.Schema {
Description: "A list of accounts that match the filter(s).",
Elem: &schema.Resource{Schema: dataSchema},
Type: schema.TypeList,
+ Optional: false,
},
"id": getDataSchemaID(),
"space_id": getQuerySpaceID(),
diff --git a/octopusdeploy/schema_azure_cloud_service_deployment_target.go b/octopusdeploy/schema_azure_cloud_service_deployment_target.go
index 46488a934..45e00de20 100644
--- a/octopusdeploy/schema_azure_cloud_service_deployment_target.go
+++ b/octopusdeploy/schema_azure_cloud_service_deployment_target.go
@@ -70,7 +70,7 @@ func getAzureCloudServiceDeploymentTargetDataSchema() map[string]*schema.Schema
Computed: true,
Description: "A list of Azure cloud service deployment targets that match the filter(s).",
Elem: &schema.Resource{Schema: dataSchema},
- Optional: true,
+ Optional: false,
Type: schema.TypeList,
}
diff --git a/octopusdeploy/schema_azure_service_fabric_cluster_deployment_target.go b/octopusdeploy/schema_azure_service_fabric_cluster_deployment_target.go
index 3f8af8905..639d08553 100644
--- a/octopusdeploy/schema_azure_service_fabric_cluster_deployment_target.go
+++ b/octopusdeploy/schema_azure_service_fabric_cluster_deployment_target.go
@@ -85,7 +85,7 @@ func getAzureServiceFabricClusterDeploymentTargetDataSchema() map[string]*schema
Computed: true,
Description: "A list of Azure service fabric cluster deployment targets that match the filter(s).",
Elem: &schema.Resource{Schema: dataSchema},
- Optional: true,
+ Optional: false,
Type: schema.TypeList,
}
diff --git a/octopusdeploy/schema_azure_web_app_deployment_target.go b/octopusdeploy/schema_azure_web_app_deployment_target.go
index 8478378b6..f8b2cfe25 100644
--- a/octopusdeploy/schema_azure_web_app_deployment_target.go
+++ b/octopusdeploy/schema_azure_web_app_deployment_target.go
@@ -55,7 +55,7 @@ func getAzureWebAppDeploymentTargetDataSchema() map[string]*schema.Schema {
Computed: true,
Description: "A list of Azure web app deployment targets that match the filter(s).",
Elem: &schema.Resource{Schema: dataSchema},
- Optional: true,
+ Optional: false,
Type: schema.TypeList,
}
diff --git a/octopusdeploy/schema_certificate.go b/octopusdeploy/schema_certificate.go
index 4252f9899..2d35164c9 100644
--- a/octopusdeploy/schema_certificate.go
+++ b/octopusdeploy/schema_certificate.go
@@ -170,7 +170,7 @@ func getCertificateDataSchema() map[string]*schema.Schema {
Computed: true,
Description: "A list of certificates that match the filter(s).",
Elem: &schema.Resource{Schema: dataSchema},
- Optional: true,
+ Optional: false,
Type: schema.TypeList,
},
"first_result": getQueryFirstResult(),
diff --git a/octopusdeploy/schema_channel.go b/octopusdeploy/schema_channel.go
index 88aa0bda9..eed2eead6 100644
--- a/octopusdeploy/schema_channel.go
+++ b/octopusdeploy/schema_channel.go
@@ -73,7 +73,7 @@ func getChannelDataSchema() map[string]*schema.Schema {
Computed: true,
Description: "A channel that matches the specified filter(s).",
Elem: &schema.Resource{Schema: dataSchema},
- Optional: true,
+ Optional: false,
Type: schema.TypeList,
},
"ids": getQueryIDs(),
diff --git a/octopusdeploy/schema_cloud_region_deployment_target.go b/octopusdeploy/schema_cloud_region_deployment_target.go
index bce3dd18e..8e2375e07 100644
--- a/octopusdeploy/schema_cloud_region_deployment_target.go
+++ b/octopusdeploy/schema_cloud_region_deployment_target.go
@@ -40,7 +40,7 @@ func getCloudRegionDeploymentTargetDataSchema() map[string]*schema.Schema {
Computed: true,
Description: "A list of cloud region deployment targets that match the filter(s).",
Elem: &schema.Resource{Schema: dataSchema},
- Optional: true,
+ Optional: false,
Type: schema.TypeList,
}
diff --git a/octopusdeploy/schema_deployment_target.go b/octopusdeploy/schema_deployment_target.go
index 456265859..9649a7bec 100644
--- a/octopusdeploy/schema_deployment_target.go
+++ b/octopusdeploy/schema_deployment_target.go
@@ -90,7 +90,7 @@ func getDeploymentTargetDataSchema() map[string]*schema.Schema {
Computed: true,
Description: "A list of deployment targets that match the filter(s).",
Elem: &schema.Resource{Schema: dataSchema},
- Optional: true,
+ Optional: false,
Type: schema.TypeList,
},
"environments": getQueryEnvironments(),
diff --git a/octopusdeploy/schema_kubernetes_agent_deployment_target.go b/octopusdeploy/schema_kubernetes_agent_deployment_target.go
index 822e7dce8..2323f311b 100644
--- a/octopusdeploy/schema_kubernetes_agent_deployment_target.go
+++ b/octopusdeploy/schema_kubernetes_agent_deployment_target.go
@@ -173,7 +173,7 @@ func getKubernetesAgentDeploymentTargetDataSchema() map[string]*schema.Schema {
Computed: true,
Description: "A list of kubernetes agent deployment targets that match the filter(s).",
Elem: &schema.Resource{Schema: dataSchema},
- Optional: true,
+ Optional: false,
Type: schema.TypeList,
}
diff --git a/octopusdeploy/schema_kubernetes_cluster_deployment_target.go b/octopusdeploy/schema_kubernetes_cluster_deployment_target.go
index 6dcbd6a35..4704688ff 100644
--- a/octopusdeploy/schema_kubernetes_cluster_deployment_target.go
+++ b/octopusdeploy/schema_kubernetes_cluster_deployment_target.go
@@ -131,7 +131,7 @@ func getKubernetesClusterDeploymentTargetDataSchema() map[string]*schema.Schema
Computed: true,
Description: "A list of Kubernetes cluster deployment targets that match the filter(s).",
Elem: &schema.Resource{Schema: dataSchema},
- Optional: true,
+ Optional: false,
Type: schema.TypeList,
}
diff --git a/octopusdeploy/schema_listening_tentacle_deployment_target.go b/octopusdeploy/schema_listening_tentacle_deployment_target.go
index 32d2b3481..a35cdb8af 100644
--- a/octopusdeploy/schema_listening_tentacle_deployment_target.go
+++ b/octopusdeploy/schema_listening_tentacle_deployment_target.go
@@ -57,7 +57,7 @@ func getListeningTentacleDeploymentTargetDataSchema() map[string]*schema.Schema
Computed: true,
Description: "A list of listening tentacle deployment targets that match the filter(s).",
Elem: &schema.Resource{Schema: dataSchema},
- Optional: true,
+ Optional: false,
Type: schema.TypeList,
}
diff --git a/octopusdeploy/schema_machine_policy.go b/octopusdeploy/schema_machine_policy.go
index 537da34df..0d24b2f6c 100644
--- a/octopusdeploy/schema_machine_policy.go
+++ b/octopusdeploy/schema_machine_policy.go
@@ -112,7 +112,7 @@ func getMachinePolicyDataSchema() map[string]*schema.Schema {
Computed: true,
Description: "A list of machine policies that match the filter(s).",
Elem: &schema.Resource{Schema: dataSchema},
- Optional: true,
+ Optional: false,
Type: schema.TypeList,
},
"partial_name": getQueryPartialName(),
diff --git a/octopusdeploy/schema_offline_package_drop_deployment_target.go b/octopusdeploy/schema_offline_package_drop_deployment_target.go
index f8b88f704..371a08b01 100644
--- a/octopusdeploy/schema_offline_package_drop_deployment_target.go
+++ b/octopusdeploy/schema_offline_package_drop_deployment_target.go
@@ -51,7 +51,7 @@ func getOfflinePackageDropDeploymentTargetDataSchema() map[string]*schema.Schema
Computed: true,
Description: "A list of offline package drop deployment targets that match the filter(s).",
Elem: &schema.Resource{Schema: dataSchema},
- Optional: true,
+ Optional: false,
Type: schema.TypeList,
}
diff --git a/octopusdeploy/schema_polling_tentacle_deployment_target.go b/octopusdeploy/schema_polling_tentacle_deployment_target.go
index ab6472663..ee73b0cfb 100644
--- a/octopusdeploy/schema_polling_tentacle_deployment_target.go
+++ b/octopusdeploy/schema_polling_tentacle_deployment_target.go
@@ -51,7 +51,7 @@ func getPollingTentacleDeploymentTargetDataSchema() map[string]*schema.Schema {
Computed: true,
Description: "A list of polling tentacle deployment targets that match the filter(s).",
Elem: &schema.Resource{Schema: dataSchema},
- Optional: true,
+ Optional: false,
Type: schema.TypeList,
}
diff --git a/octopusdeploy/schema_script_modules.go b/octopusdeploy/schema_script_modules.go
index c4a24d1f8..906d2ea54 100644
--- a/octopusdeploy/schema_script_modules.go
+++ b/octopusdeploy/schema_script_modules.go
@@ -86,7 +86,7 @@ func getScriptModuleDataSchema() map[string]*schema.Schema {
Computed: true,
Description: "A list of script modules that match the filter(s).",
Elem: &schema.Resource{Schema: dataSchema},
- Optional: true,
+ Optional: false,
Type: schema.TypeList,
},
"partial_name": getQueryPartialName(),
diff --git a/octopusdeploy/schema_ssh_connection_deployment_target.go b/octopusdeploy/schema_ssh_connection_deployment_target.go
index 90934132f..df977c19d 100644
--- a/octopusdeploy/schema_ssh_connection_deployment_target.go
+++ b/octopusdeploy/schema_ssh_connection_deployment_target.go
@@ -57,7 +57,7 @@ func getSSHConnectionDeploymentTargetDataSchema() map[string]*schema.Schema {
Computed: true,
Description: "A list of SSH connection deployment targets that match the filter(s).",
Elem: &schema.Resource{Schema: dataSchema},
- Optional: true,
+ Optional: false,
Type: schema.TypeList,
}
diff --git a/octopusdeploy/schema_tag_set.go b/octopusdeploy/schema_tag_set.go
index db5c31a23..953b5c40c 100644
--- a/octopusdeploy/schema_tag_set.go
+++ b/octopusdeploy/schema_tag_set.go
@@ -54,7 +54,7 @@ func getTagSetDataSchema() map[string]*schema.Schema {
Computed: true,
Description: "A list of tag sets that match the filter(s).",
Elem: &schema.Resource{Schema: dataSchema},
- Optional: true,
+ Optional: false,
Type: schema.TypeList,
},
"take": getQueryTake(),
diff --git a/octopusdeploy/schema_team.go b/octopusdeploy/schema_team.go
index 3f782a1c9..d0656662e 100644
--- a/octopusdeploy/schema_team.go
+++ b/octopusdeploy/schema_team.go
@@ -85,7 +85,7 @@ func getTeamDataSchema() map[string]*schema.Schema {
Computed: true,
Description: "A list of teams that match the filter(s).",
Elem: &schema.Resource{Schema: dataSchema},
- Optional: true,
+ Optional: false,
Type: schema.TypeList,
},
}
diff --git a/octopusdeploy/schema_tenant.go b/octopusdeploy/schema_tenant.go
index 6045f5981..260ba93f8 100644
--- a/octopusdeploy/schema_tenant.go
+++ b/octopusdeploy/schema_tenant.go
@@ -67,7 +67,7 @@ func getTenantDataSchema() map[string]*schema.Schema {
Computed: true,
Description: "A list of tenants that match the filter(s).",
Elem: &schema.Resource{Schema: dataSchema},
- Optional: true,
+ Optional: false,
Type: schema.TypeList,
},
"take": getQueryTake(),
diff --git a/octopusdeploy/schema_user.go b/octopusdeploy/schema_user.go
index 5ef089c67..620c3db37 100644
--- a/octopusdeploy/schema_user.go
+++ b/octopusdeploy/schema_user.go
@@ -74,7 +74,7 @@ func getUserDataSchema() map[string]*schema.Schema {
Computed: true,
Description: "A list of users that match the filter(s).",
Elem: &schema.Resource{Schema: dataSchema},
- Optional: true,
+ Optional: false,
Type: schema.TypeList,
},
}
diff --git a/octopusdeploy/schema_user_role.go b/octopusdeploy/schema_user_role.go
index 9258402e5..4487a9170 100644
--- a/octopusdeploy/schema_user_role.go
+++ b/octopusdeploy/schema_user_role.go
@@ -84,7 +84,7 @@ func getUserRoleDataSchema() map[string]*schema.Schema {
Computed: true,
Description: "A list of user roles that match the filter(s).",
Elem: &schema.Resource{Schema: dataSchema},
- Optional: true,
+ Optional: false,
Type: schema.TypeList,
},
}
diff --git a/octopusdeploy/schema_worker_pool.go b/octopusdeploy/schema_worker_pool.go
index 9207124c2..036e2a04a 100644
--- a/octopusdeploy/schema_worker_pool.go
+++ b/octopusdeploy/schema_worker_pool.go
@@ -39,7 +39,7 @@ func getWorkerPoolDataSchema() map[string]*schema.Schema {
Computed: true,
Description: "A list of worker pools that match the filter(s).",
Elem: &schema.Resource{Schema: dataSchema},
- Optional: true,
+ Optional: false,
Type: schema.TypeList,
},
}
diff --git a/octopusdeploy_framework/schemas/gitCredential.go b/octopusdeploy_framework/schemas/gitCredential.go
index 2a29f1b4d..594f927b1 100644
--- a/octopusdeploy_framework/schemas/gitCredential.go
+++ b/octopusdeploy_framework/schemas/gitCredential.go
@@ -54,6 +54,7 @@ func GetGitCredentialDataSourceSchema() map[string]datasourceSchema.Attribute {
"take": util.GetQueryTakeDatasourceSchema(),
"git_credentials": datasourceSchema.ListNestedAttribute{
Computed: true,
+ Optional: false,
Description: "A list of Git Credentials that match the filter(s).",
NestedObject: datasourceSchema.NestedAttributeObject{
Attributes: GetGitCredentialAttributes(),
diff --git a/octopusdeploy_framework/schemas/lifecycle.go b/octopusdeploy_framework/schemas/lifecycle.go
index 092d48ab6..04f7f493a 100644
--- a/octopusdeploy_framework/schemas/lifecycle.go
+++ b/octopusdeploy_framework/schemas/lifecycle.go
@@ -97,6 +97,7 @@ func GetDatasourceLifecycleSchema() datasourceSchema.Schema {
"take": util.GetQueryTakeDatasourceSchema(),
"lifecycles": datasourceSchema.ListNestedAttribute{
Computed: true,
+ Optional: false,
NestedObject: datasourceSchema.NestedAttributeObject{
Attributes: map[string]datasourceSchema.Attribute{
"id": util.GetIdDatasourceSchema(),
diff --git a/octopusdeploy_framework/schemas/project.go b/octopusdeploy_framework/schemas/project.go
index fc4fee3b7..814710bda 100644
--- a/octopusdeploy_framework/schemas/project.go
+++ b/octopusdeploy_framework/schemas/project.go
@@ -193,6 +193,7 @@ func getProjectsDataSourceAttribute() datasourceSchema.ListNestedAttribute {
return datasourceSchema.ListNestedAttribute{
Description: "A list of projects that match the filter(s).",
Computed: true,
+ Optional: false,
NestedObject: datasourceSchema.NestedAttributeObject{
Attributes: map[string]datasourceSchema.Attribute{
"allow_deployments_to_no_targets": util.DataSourceBool().Computed().Deprecated("Allow deployments to be created when there are no targets.").Build(),
From 7fade0508fa4f3279c9ef91caa3e97bb6c781464 Mon Sep 17 00:00:00 2001
From: Huy Nguyen <162080607+HuyPhanNguyen@users.noreply.github.com>
Date: Thu, 8 Aug 2024 14:25:25 +1000
Subject: [PATCH 04/12] Update schema and doc GitCredential, Lifecycles and
TenantProjectVariable (#717)
* Update lifecycles schema and doc
* Fix lifecyle schema
* Update git credential resource
* Refactor tenant project variable
* Make it consistent
* Update datasource GitCredentialModel
* fix test fail
* Add username_password_account resource
* Revert "Add username_password_account resource"
This reverts commit 7a20ecb5c8698d7f341c2437d5f841aa2cf179ae.
* Update doc example
* small change on lifecycle example
---
docs/data-sources/lifecycles.md | 70 ++++----
docs/resources/git_credential.md | 10 +-
docs/resources/lifecycle.md | 38 ++---
docs/resources/tenant_project_variable.md | 18 +-
.../datasource_git_credentials.go | 8 +-
.../schemas/gitCredential.go | 95 +++++------
octopusdeploy_framework/schemas/lifecycle.go | 155 +++++++++---------
.../schemas/tenant_project_variable.go | 44 +++--
.../util/resource_attribute_builder.go | 80 +++++++++
9 files changed, 307 insertions(+), 211 deletions(-)
diff --git a/docs/data-sources/lifecycles.md b/docs/data-sources/lifecycles.md
index 2d6ce478e..d7fb232f4 100644
--- a/docs/data-sources/lifecycles.md
+++ b/docs/data-sources/lifecycles.md
@@ -26,62 +26,62 @@ data "octopusdeploy_lifecycles" "example" {
### Optional
-- `ids` (List of String) A filter to search by a list of IDs.
-- `partial_name` (String) A filter to search by the partial match of a name.
+- `ids` (List of String) A list of lifecycle IDs to filter by.
+- `partial_name` (String) A partial name to filter lifecycles by.
- `skip` (Number) A filter to specify the number of items to skip in the response.
-- `space_id` (String) The space ID associated with this resource.
+- `space_id` (String) The space ID associated with this lifecycle.
- `take` (Number) A filter to specify the number of items to take (or return) in the response.
### Read-Only
-- `id` (String) The ID of this resource.
-- `lifecycles` (Block List) A list of lifecycles that match the filter(s). (see [below for nested schema](#nestedblock--lifecycles))
+- `id` (String) The ID of the lifecycle.
+- `lifecycles` (Attributes List) (see [below for nested schema](#nestedatt--lifecycles))
-
+
### Nested Schema for `lifecycles`
Read-Only:
-- `description` (String) The description of this lifecycle.
-- `id` (String) The unique ID for this resource.
-- `name` (String) The name of this resource.
-- `phase` (List of Object) (see [below for nested schema](#nestedatt--lifecycles--phase))
-- `release_retention_policy` (List of Object) (see [below for nested schema](#nestedatt--lifecycles--release_retention_policy))
-- `space_id` (String) The space ID associated with this resource.
-- `tentacle_retention_policy` (List of Object) (see [below for nested schema](#nestedatt--lifecycles--tentacle_retention_policy))
+- `description` (String) The description of the lifecycle.
+- `id` (String) The ID of the lifecycle.
+- `name` (String) The name of the lifecycle.
+- `phase` (Attributes List) (see [below for nested schema](#nestedatt--lifecycles--phase))
+- `release_retention_policy` (Attributes List) (see [below for nested schema](#nestedatt--lifecycles--release_retention_policy))
+- `space_id` (String) The space ID associated with this lifecycle.
+- `tentacle_retention_policy` (Attributes List) (see [below for nested schema](#nestedatt--lifecycles--tentacle_retention_policy))
### Nested Schema for `lifecycles.phase`
Read-Only:
-- `automatic_deployment_targets` (List of String)
-- `id` (String)
-- `is_optional_phase` (Boolean)
-- `minimum_environments_before_promotion` (Number)
-- `name` (String)
-- `optional_deployment_targets` (List of String)
-- `release_retention_policy` (List of Object) (see [below for nested schema](#nestedobjatt--lifecycles--phase--release_retention_policy))
-- `tentacle_retention_policy` (List of Object) (see [below for nested schema](#nestedobjatt--lifecycles--phase--tentacle_retention_policy))
+- `automatic_deployment_targets` (List of String) The automatic deployment targets for this phase.
+- `id` (String) The ID of the phase.
+- `is_optional_phase` (Boolean) Whether this phase is optional.
+- `minimum_environments_before_promotion` (Number) The minimum number of environments before promotion.
+- `name` (String) The name of the phase.
+- `optional_deployment_targets` (List of String) The optional deployment targets for this phase.
+- `release_retention_policy` (Attributes List) (see [below for nested schema](#nestedatt--lifecycles--phase--release_retention_policy))
+- `tentacle_retention_policy` (Attributes List) (see [below for nested schema](#nestedatt--lifecycles--phase--tentacle_retention_policy))
-
+
### Nested Schema for `lifecycles.phase.release_retention_policy`
Read-Only:
-- `quantity_to_keep` (Number)
-- `should_keep_forever` (Boolean)
-- `unit` (String)
+- `quantity_to_keep` (Number) The quantity of releases to keep.
+- `should_keep_forever` (Boolean) Whether releases should be kept forever.
+- `unit` (String) The unit of time for the retention policy.
-
+
### Nested Schema for `lifecycles.phase.tentacle_retention_policy`
Read-Only:
-- `quantity_to_keep` (Number)
-- `should_keep_forever` (Boolean)
-- `unit` (String)
+- `quantity_to_keep` (Number) The quantity of releases to keep.
+- `should_keep_forever` (Boolean) Whether releases should be kept forever.
+- `unit` (String) The unit of time for the retention policy.
@@ -90,9 +90,9 @@ Read-Only:
Read-Only:
-- `quantity_to_keep` (Number)
-- `should_keep_forever` (Boolean)
-- `unit` (String)
+- `quantity_to_keep` (Number) The quantity of releases to keep.
+- `should_keep_forever` (Boolean) Whether releases should be kept forever.
+- `unit` (String) The unit of time for the retention policy.
@@ -100,8 +100,8 @@ Read-Only:
Read-Only:
-- `quantity_to_keep` (Number)
-- `should_keep_forever` (Boolean)
-- `unit` (String)
+- `quantity_to_keep` (Number) The quantity of releases to keep.
+- `should_keep_forever` (Boolean) Whether releases should be kept forever.
+- `unit` (String) The unit of time for the retention policy.
diff --git a/docs/resources/git_credential.md b/docs/resources/git_credential.md
index e47402fa1..ad9aa4392 100644
--- a/docs/resources/git_credential.md
+++ b/docs/resources/git_credential.md
@@ -3,12 +3,12 @@
page_title: "octopusdeploy_git_credential Resource - terraform-provider-octopusdeploy"
subcategory: ""
description: |-
- This resource manages Git credentials in Octopus Deploy.
+ Manages a Git credential in Octopus Deploy.
---
# octopusdeploy_git_credential (Resource)
-This resource manages Git credentials in Octopus Deploy.
+Manages a Git credential in Octopus Deploy.
@@ -17,15 +17,15 @@ This resource manages Git credentials in Octopus Deploy.
### Required
-- `name` (String) The name of the Git credential. This name must be unique.
+- `name` (String) The name of this Git Credential.
- `password` (String, Sensitive) The password for the Git credential.
- `username` (String) The username for the Git credential.
### Optional
-- `description` (String) The description of this Git credential.
+- `description` (String) The description of this Git Credential.
- `id` (String) The unique ID for this resource.
-- `space_id` (String) The space ID associated with this resource.
+- `space_id` (String) The space ID associated with this Git Credential.
- `type` (String) The Git credential authentication type.
diff --git a/docs/resources/lifecycle.md b/docs/resources/lifecycle.md
index a367cce62..8714ab06e 100644
--- a/docs/resources/lifecycle.md
+++ b/docs/resources/lifecycle.md
@@ -33,8 +33,8 @@ resource "octopusdeploy_lifecycle" "example" {
name = "foo"
release_retention_policy {
- quantity_to_keep = 0
- should_keep_forever = true
+ quantity_to_keep = 0
+ should_keep_forever = true // true only if quantity_to_keep = 0
unit = "Days"
}
@@ -64,10 +64,10 @@ resource "octopusdeploy_lifecycle" "example" {
- `description` (String) The description of this lifecycle.
- `id` (String) The unique ID for this resource.
-- `phase` (Block List) (see [below for nested schema](#nestedblock--phase))
-- `release_retention_policy` (Block List, Max: 1) (see [below for nested schema](#nestedblock--release_retention_policy))
+- `phase` (Block List) Defines a phase in the lifecycle. (see [below for nested schema](#nestedblock--phase))
+- `release_retention_policy` (Block List) Defines the retention policy for releases or tentacles. (see [below for nested schema](#nestedblock--release_retention_policy))
- `space_id` (String) The space ID associated with this resource.
-- `tentacle_retention_policy` (Block List, Max: 1) (see [below for nested schema](#nestedblock--tentacle_retention_policy))
+- `tentacle_retention_policy` (Block List) Defines the retention policy for releases or tentacles. (see [below for nested schema](#nestedblock--tentacle_retention_policy))
### Nested Schema for `phase`
@@ -83,17 +83,17 @@ Optional:
- `is_optional_phase` (Boolean) If false a release must be deployed to this phase before it can be deployed to the next phase.
- `minimum_environments_before_promotion` (Number) The number of units required before a release can enter the next phase. If 0, all environments are required.
- `optional_deployment_targets` (List of String) Environment IDs in this phase that a release can be deployed to, but is not automatically deployed to
-- `release_retention_policy` (Block List, Max: 1) (see [below for nested schema](#nestedblock--phase--release_retention_policy))
-- `tentacle_retention_policy` (Block List, Max: 1) (see [below for nested schema](#nestedblock--phase--tentacle_retention_policy))
+- `release_retention_policy` (Block List) Defines the retention policy for releases or tentacles. (see [below for nested schema](#nestedblock--phase--release_retention_policy))
+- `tentacle_retention_policy` (Block List) Defines the retention policy for releases or tentacles. (see [below for nested schema](#nestedblock--phase--tentacle_retention_policy))
### Nested Schema for `phase.release_retention_policy`
Optional:
-- `quantity_to_keep` (Number) The number of days/releases to keep. The default value is `30`. If `0` then all are kept.
-- `should_keep_forever` (Boolean) Indicates if items should never be deleted. The default value is `false`.
-- `unit` (String) The unit of quantity to keep. Valid units are `Days` or `Items`. The default value is `Days`.
+- `quantity_to_keep` (Number) The number of days/releases to keep. The default value is 30. If 0 then all are kept.
+- `should_keep_forever` (Boolean) Indicates if items should never be deleted. The default value is false.
+- `unit` (String) The unit of quantity to keep. Valid units are Days or Items. The default value is Days.
@@ -101,9 +101,9 @@ Optional:
Optional:
-- `quantity_to_keep` (Number) The number of days/releases to keep. The default value is `30`. If `0` then all are kept.
-- `should_keep_forever` (Boolean) Indicates if items should never be deleted. The default value is `false`.
-- `unit` (String) The unit of quantity to keep. Valid units are `Days` or `Items`. The default value is `Days`.
+- `quantity_to_keep` (Number) The number of days/releases to keep. The default value is 30. If 0 then all are kept.
+- `should_keep_forever` (Boolean) Indicates if items should never be deleted. The default value is false.
+- `unit` (String) The unit of quantity to keep. Valid units are Days or Items. The default value is Days.
@@ -112,9 +112,9 @@ Optional:
Optional:
-- `quantity_to_keep` (Number) The number of days/releases to keep. The default value is `30`. If `0` then all are kept.
-- `should_keep_forever` (Boolean) Indicates if items should never be deleted. The default value is `false`.
-- `unit` (String) The unit of quantity to keep. Valid units are `Days` or `Items`. The default value is `Days`.
+- `quantity_to_keep` (Number) The number of days/releases to keep. The default value is 30. If 0 then all are kept.
+- `should_keep_forever` (Boolean) Indicates if items should never be deleted. The default value is false.
+- `unit` (String) The unit of quantity to keep. Valid units are Days or Items. The default value is Days.
@@ -122,9 +122,9 @@ Optional:
Optional:
-- `quantity_to_keep` (Number) The number of days/releases to keep. The default value is `30`. If `0` then all are kept.
-- `should_keep_forever` (Boolean) Indicates if items should never be deleted. The default value is `false`.
-- `unit` (String) The unit of quantity to keep. Valid units are `Days` or `Items`. The default value is `Days`.
+- `quantity_to_keep` (Number) The number of days/releases to keep. The default value is 30. If 0 then all are kept.
+- `should_keep_forever` (Boolean) Indicates if items should never be deleted. The default value is false.
+- `unit` (String) The unit of quantity to keep. Valid units are Days or Items. The default value is Days.
## Import
diff --git a/docs/resources/tenant_project_variable.md b/docs/resources/tenant_project_variable.md
index c27b1afae..053b6739a 100644
--- a/docs/resources/tenant_project_variable.md
+++ b/docs/resources/tenant_project_variable.md
@@ -3,12 +3,12 @@
page_title: "octopusdeploy_tenant_project_variable Resource - terraform-provider-octopusdeploy"
subcategory: ""
description: |-
- This resource manages tenant project variables in Octopus Deploy.
+ Manages a tenant project variable in Octopus Deploy.
---
# octopusdeploy_tenant_project_variable (Resource)
-This resource manages tenant project variables in Octopus Deploy.
+Manages a tenant project variable in Octopus Deploy.
@@ -17,18 +17,18 @@ This resource manages tenant project variables in Octopus Deploy.
### Required
-- `environment_id` (String)
-- `project_id` (String)
-- `template_id` (String)
-- `tenant_id` (String)
+- `environment_id` (String) The ID of the environment.
+- `project_id` (String) The ID of the project.
+- `template_id` (String) The ID of the variable template.
+- `tenant_id` (String) The ID of the tenant.
### Optional
-- `space_id` (String)
-- `value` (String, Sensitive)
+- `space_id` (String) The space ID associated with this Tenant Project Variable.
+- `value` (String, Sensitive) The value of the variable.
### Read-Only
-- `id` (String) The ID of this resource.
+- `id` (String) The unique ID for this resource.
diff --git a/octopusdeploy_framework/datasource_git_credentials.go b/octopusdeploy_framework/datasource_git_credentials.go
index 210c7d83b..5dc1592c3 100644
--- a/octopusdeploy_framework/datasource_git_credentials.go
+++ b/octopusdeploy_framework/datasource_git_credentials.go
@@ -8,7 +8,6 @@ import (
"github.com/OctopusDeploy/terraform-provider-octopusdeploy/octopusdeploy_framework/util"
"github.com/hashicorp/terraform-plugin-framework/attr"
"github.com/hashicorp/terraform-plugin-framework/datasource"
- "github.com/hashicorp/terraform-plugin-framework/datasource/schema"
"github.com/hashicorp/terraform-plugin-framework/types"
"time"
)
@@ -35,6 +34,7 @@ type GitCredentialModel struct {
Description types.String `tfsdk:"description"`
Type types.String `tfsdk:"type"`
Username types.String `tfsdk:"username"`
+ Password types.String `tfsdk:"password"`
}
func NewGitCredentialsDataSource() datasource.DataSource {
@@ -46,10 +46,7 @@ func (g *gitCredentialsDataSource) Metadata(_ context.Context, req datasource.Me
}
func (g *gitCredentialsDataSource) Schema(_ context.Context, _ datasource.SchemaRequest, resp *datasource.SchemaResponse) {
- resp.Schema = schema.Schema{
- Description: "A list of Git Credentials that match the filter(s).",
- Attributes: schemas.GetGitCredentialDataSourceSchema(),
- }
+ resp.Schema = schemas.GetGitCredentialDataSourceSchema()
}
func (g *gitCredentialsDataSource) Configure(_ context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) {
@@ -102,6 +99,7 @@ func GetGitCredentialAttrTypes() map[string]attr.Type {
"description": types.StringType,
"type": types.StringType,
"username": types.StringType,
+ "password": types.StringType,
}
}
diff --git a/octopusdeploy_framework/schemas/gitCredential.go b/octopusdeploy_framework/schemas/gitCredential.go
index 594f927b1..c4b0b4d6f 100644
--- a/octopusdeploy_framework/schemas/gitCredential.go
+++ b/octopusdeploy_framework/schemas/gitCredential.go
@@ -5,59 +5,55 @@ import (
"github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
datasourceSchema "github.com/hashicorp/terraform-plugin-framework/datasource/schema"
resourceSchema "github.com/hashicorp/terraform-plugin-framework/resource/schema"
- "github.com/hashicorp/terraform-plugin-framework/schema/validator"
)
const (
- GitCredentialResourceDescription = "Git Credential"
- GitCredentialResourceName = "git_credential"
- GitCredentialDatasourceName = "git_credentials"
+ GitCredentialResourceName = "git_credential"
+ GitCredentialDatasourceName = "git_credentials"
)
func GetGitCredentialResourceSchema() resourceSchema.Schema {
return resourceSchema.Schema{
Description: "Manages a Git credential in Octopus Deploy.",
Attributes: map[string]resourceSchema.Attribute{
- "id": util.GetIdResourceSchema(),
- "space_id": util.GetSpaceIdResourceSchema(GitCredentialResourceDescription),
- "name": util.GetNameResourceSchema(true),
- "description": util.GetDescriptionResourceSchema(GitCredentialResourceDescription),
- "type": resourceSchema.StringAttribute{
- Optional: true,
- Description: "The Git credential authentication type.",
- },
- "username": resourceSchema.StringAttribute{
- Required: true,
- Description: "The username for the Git credential.",
- Validators: []validator.String{
- stringvalidator.LengthAtLeast(1),
- },
- },
- "password": resourceSchema.StringAttribute{
- Required: true,
- Sensitive: true,
- Description: "The password for the Git credential.",
- Validators: []validator.String{
- stringvalidator.LengthAtLeast(1),
- },
- },
+ "id": util.ResourceString().Optional().Computed().Description("The unique ID for this resource.").Build(),
+ "space_id": util.ResourceString().Optional().Computed().Description("The space ID associated with this Git Credential.").Build(),
+ "name": util.ResourceString().Required().Description("The name of this Git Credential.").Build(),
+ "description": util.ResourceString().Optional().Description("The description of this Git Credential.").Build(),
+ "type": util.ResourceString().
+ Optional().
+ Description("The Git credential authentication type.").
+ Build(),
+ "username": util.ResourceString().
+ Required().
+ Description("The username for the Git credential.").
+ Validators(stringvalidator.LengthAtLeast(1)).
+ Build(),
+ "password": util.ResourceString().
+ Required().
+ Sensitive().
+ Description("The password for the Git credential.").
+ Validators(stringvalidator.LengthAtLeast(1)).
+ Build(),
},
}
}
-func GetGitCredentialDataSourceSchema() map[string]datasourceSchema.Attribute {
- return map[string]datasourceSchema.Attribute{
- "id": util.GetIdDatasourceSchema(),
- "space_id": util.GetSpaceIdDatasourceSchema(GitCredentialResourceDescription),
- "name": util.GetQueryNameDatasourceSchema(),
- "skip": util.GetQuerySkipDatasourceSchema(),
- "take": util.GetQueryTakeDatasourceSchema(),
- "git_credentials": datasourceSchema.ListNestedAttribute{
- Computed: true,
- Optional: false,
- Description: "A list of Git Credentials that match the filter(s).",
- NestedObject: datasourceSchema.NestedAttributeObject{
- Attributes: GetGitCredentialAttributes(),
+func GetGitCredentialDataSourceSchema() datasourceSchema.Schema {
+ return datasourceSchema.Schema{
+ Description: "Use this data source to retrieve information about Git credentials in Octopus Deploy.",
+ Attributes: map[string]datasourceSchema.Attribute{
+ "id": util.DataSourceString().Computed().Description("The unique ID for this resource.").Build(),
+ "space_id": util.DataSourceString().Optional().Description("The space ID associated with this Git Credential.").Build(),
+ "name": util.DataSourceString().Optional().Description("The name of the Git Credential to filter by.").Build(),
+ "skip": util.DataSourceInt64().Optional().Description("The number of records to skip.").Build(),
+ "take": util.DataSourceInt64().Optional().Description("The number of records to take.").Build(),
+ "git_credentials": datasourceSchema.ListNestedAttribute{
+ Computed: true,
+ Description: "Provides information about existing GitCredentials.",
+ NestedObject: datasourceSchema.NestedAttributeObject{
+ Attributes: GetGitCredentialAttributes(),
+ },
},
},
}
@@ -65,17 +61,12 @@ func GetGitCredentialDataSourceSchema() map[string]datasourceSchema.Attribute {
func GetGitCredentialAttributes() map[string]datasourceSchema.Attribute {
return map[string]datasourceSchema.Attribute{
- "id": util.GetIdDatasourceSchema(),
- "space_id": util.GetSpaceIdDatasourceSchema(GitCredentialResourceDescription),
- "name": util.GetQueryNameDatasourceSchema(),
- "description": util.GetDescriptionDatasourceSchema(GitCredentialResourceDescription),
- "type": datasourceSchema.StringAttribute{
- Computed: true,
- Description: "The Git credential authentication type.",
- },
- "username": datasourceSchema.StringAttribute{
- Computed: true,
- Description: "The username for the Git credential.",
- },
+ "id": util.DataSourceString().Computed().Description("The unique ID for this resource.").Build(),
+ "space_id": util.DataSourceString().Computed().Description("The space ID associated with this Git Credential.").Build(),
+ "name": util.DataSourceString().Computed().Description("The name of this Git Credential.").Build(),
+ "description": util.DataSourceString().Computed().Description("The description of this Git Credential.").Build(),
+ "type": util.DataSourceString().Computed().Description("The Git credential authentication type.").Build(),
+ "username": util.DataSourceString().Computed().Description("The username for the Git credential.").Build(),
+ "password": util.DataSourceString().Computed().Sensitive().Description("The password for the Git credential.").Build(),
}
}
diff --git a/octopusdeploy_framework/schemas/lifecycle.go b/octopusdeploy_framework/schemas/lifecycle.go
index 04f7f493a..ba28f35b9 100644
--- a/octopusdeploy_framework/schemas/lifecycle.go
+++ b/octopusdeploy_framework/schemas/lifecycle.go
@@ -7,16 +7,18 @@ import (
"github.com/hashicorp/terraform-plugin-framework/resource/schema/booldefault"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/int64default"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault"
+ "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
"github.com/hashicorp/terraform-plugin-framework/types"
)
func GetResourceLifecycleSchema() resourceSchema.Schema {
return resourceSchema.Schema{
+ Description: "This resource manages lifecycles in Octopus Deploy.",
Attributes: map[string]resourceSchema.Attribute{
- "id": util.GetIdResourceSchema(),
- "space_id": util.GetSpaceIdResourceSchema("lifecycle"),
- "name": util.GetNameResourceSchema(true),
- "description": util.GetDescriptionResourceSchema("lifecycle"),
+ "id": util.ResourceString().Optional().Computed().Description("The unique ID for this resource.").PlanModifiers(stringplanmodifier.UseStateForUnknown()).Build(),
+ "space_id": util.ResourceString().Optional().Computed().Description("The space ID associated with this resource.").PlanModifiers(stringplanmodifier.UseStateForUnknown()).Build(),
+ "name": util.ResourceString().Required().Description("The name of this resource.").Build(),
+ "description": util.ResourceString().Optional().Computed().Default("").Description("The description of this lifecycle.").Build(),
},
Blocks: map[string]resourceSchema.Block{
"phase": getResourcePhaseBlockSchema(),
@@ -28,30 +30,29 @@ func GetResourceLifecycleSchema() resourceSchema.Schema {
func getResourcePhaseBlockSchema() resourceSchema.ListNestedBlock {
return resourceSchema.ListNestedBlock{
+ Description: "Defines a phase in the lifecycle.",
NestedObject: resourceSchema.NestedBlockObject{
Attributes: map[string]resourceSchema.Attribute{
- "id": util.GetIdResourceSchema(),
- "name": util.GetNameResourceSchema(true),
- "automatic_deployment_targets": resourceSchema.ListAttribute{
- ElementType: types.StringType,
- Optional: true,
- Computed: true,
- },
- "optional_deployment_targets": resourceSchema.ListAttribute{
- ElementType: types.StringType,
- Optional: true,
- Computed: true,
- },
- "minimum_environments_before_promotion": resourceSchema.Int64Attribute{
- Optional: true,
- Computed: true,
- Default: int64default.StaticInt64(0),
- },
- "is_optional_phase": resourceSchema.BoolAttribute{
- Optional: true,
- Computed: true,
- Default: booldefault.StaticBool(false),
- },
+ "id": util.ResourceString().Optional().Computed().Description("The unique ID for this resource.").Build(),
+ "name": util.ResourceString().Required().Description("The name of this resource.").Build(),
+ "automatic_deployment_targets": util.ResourceList(types.StringType).
+ Optional().Computed().
+ Description("Environment IDs in this phase that a release is automatically deployed to when it is eligible for this phase").
+ Build(),
+ "optional_deployment_targets": util.ResourceList(types.StringType).
+ Optional().Computed().
+ Description("Environment IDs in this phase that a release can be deployed to, but is not automatically deployed to").
+ Build(),
+ "minimum_environments_before_promotion": util.ResourceInt64().
+ Optional().Computed().
+ Default(int64default.StaticInt64(0)).
+ Description("The number of units required before a release can enter the next phase. If 0, all environments are required.").
+ Build(),
+ "is_optional_phase": util.ResourceBool().
+ Optional().Computed().
+ Default(booldefault.StaticBool(false)).
+ Description("If false a release must be deployed to this phase before it can be deployed to the next phase.").
+ Build(),
},
Blocks: map[string]resourceSchema.Block{
"release_retention_policy": getResourceRetentionPolicyBlockSchema(),
@@ -63,83 +64,87 @@ func getResourcePhaseBlockSchema() resourceSchema.ListNestedBlock {
func getResourceRetentionPolicyBlockSchema() resourceSchema.ListNestedBlock {
return resourceSchema.ListNestedBlock{
+ Description: "Defines the retention policy for releases or tentacles.",
NestedObject: resourceSchema.NestedBlockObject{
Attributes: map[string]resourceSchema.Attribute{
- "quantity_to_keep": resourceSchema.Int64Attribute{
- Optional: true,
- Computed: true,
- Default: int64default.StaticInt64(30),
- },
- "should_keep_forever": resourceSchema.BoolAttribute{
- Optional: true,
- Computed: true,
- Default: booldefault.StaticBool(false),
- },
- "unit": resourceSchema.StringAttribute{
- Optional: true,
- Computed: true,
- Default: stringdefault.StaticString("Days"),
- },
+ "quantity_to_keep": util.ResourceInt64().
+ Optional().Computed().
+ Default(int64default.StaticInt64(30)).
+ Description("The number of days/releases to keep. The default value is 30. If 0 then all are kept.").
+ Build(),
+ "should_keep_forever": util.ResourceBool().
+ Optional().Computed().
+ Default(booldefault.StaticBool(false)).
+ Description("Indicates if items should never be deleted. The default value is false.").
+ Build(),
+ "unit": util.ResourceString().
+ Optional().Computed().
+ Default(stringdefault.StaticString("Days")).
+ Description("The unit of quantity to keep. Valid units are Days or Items. The default value is Days.").
+ Build(),
},
},
}
}
func GetDatasourceLifecycleSchema() datasourceSchema.Schema {
- description := "lifecycle"
return datasourceSchema.Schema{
+ Description: "Provides information about existing lifecycles.",
Attributes: map[string]datasourceSchema.Attribute{
- "id": util.GetIdDatasourceSchema(),
- "space_id": util.GetSpaceIdDatasourceSchema(description),
- "ids": util.GetQueryIDsDatasourceSchema(),
- "partial_name": util.GetQueryPartialNameDatasourceSchema(),
- "skip": util.GetQuerySkipDatasourceSchema(),
- "take": util.GetQueryTakeDatasourceSchema(),
- "lifecycles": datasourceSchema.ListNestedAttribute{
- Computed: true,
- Optional: false,
- NestedObject: datasourceSchema.NestedAttributeObject{
- Attributes: map[string]datasourceSchema.Attribute{
- "id": util.GetIdDatasourceSchema(),
- "space_id": util.GetSpaceIdDatasourceSchema(description),
- "name": util.GetNameDatasourceSchema(true),
- "description": util.GetDescriptionDatasourceSchema(description),
- "phase": getDatasourcePhasesSchema(),
- "release_retention_policy": getDatasourceRetentionPolicySchema(),
- "tentacle_retention_policy": getDatasourceRetentionPolicySchema(),
- },
- },
+ "id": util.DataSourceString().Computed().Description("The ID of the lifecycle.").Build(),
+ "space_id": util.DataSourceString().Optional().Description("The space ID associated with this lifecycle.").Build(),
+ "ids": util.DataSourceList(types.StringType).Optional().Description("A list of lifecycle IDs to filter by.").Build(),
+ "partial_name": util.DataSourceString().Optional().Description("A partial name to filter lifecycles by.").Build(),
+ "skip": util.DataSourceInt64().Optional().Description("A filter to specify the number of items to skip in the response.").Build(),
+ "take": util.DataSourceInt64().Optional().Description("A filter to specify the number of items to take (or return) in the response.").Build(),
+ "lifecycles": getLifecyclesAttribute(),
+ },
+ }
+}
+
+func getLifecyclesAttribute() datasourceSchema.ListNestedAttribute {
+ return datasourceSchema.ListNestedAttribute{
+ Computed: true,
+ NestedObject: datasourceSchema.NestedAttributeObject{
+ Attributes: map[string]datasourceSchema.Attribute{
+ "id": util.DataSourceString().Computed().Description("The ID of the lifecycle.").Build(),
+ "space_id": util.DataSourceString().Computed().Description("The space ID associated with this lifecycle.").Build(),
+ "name": util.DataSourceString().Computed().Description("The name of the lifecycle.").Build(),
+ "description": util.DataSourceString().Computed().Description("The description of the lifecycle.").Build(),
+ "phase": getPhasesAttribute(),
+ "release_retention_policy": getRetentionPolicyAttribute(),
+ "tentacle_retention_policy": getRetentionPolicyAttribute(),
},
},
}
}
-func getDatasourcePhasesSchema() datasourceSchema.ListNestedAttribute {
+func getPhasesAttribute() datasourceSchema.ListNestedAttribute {
return datasourceSchema.ListNestedAttribute{
Computed: true,
NestedObject: datasourceSchema.NestedAttributeObject{
Attributes: map[string]datasourceSchema.Attribute{
- "id": util.GetIdDatasourceSchema(),
- "name": util.GetNameDatasourceSchema(true),
- "automatic_deployment_targets": datasourceSchema.ListAttribute{ElementType: types.StringType, Computed: true},
- "optional_deployment_targets": datasourceSchema.ListAttribute{ElementType: types.StringType, Computed: true},
- "minimum_environments_before_promotion": datasourceSchema.Int64Attribute{Computed: true},
- "is_optional_phase": datasourceSchema.BoolAttribute{Computed: true},
- "release_retention_policy": getDatasourceRetentionPolicySchema(),
- "tentacle_retention_policy": getDatasourceRetentionPolicySchema(),
+ "id": util.DataSourceString().Computed().Description("The ID of the phase.").Build(),
+ "name": util.DataSourceString().Computed().Description("The name of the phase.").Build(),
+ "automatic_deployment_targets": util.DataSourceList(types.StringType).Computed().Description("The automatic deployment targets for this phase.").Build(),
+ "optional_deployment_targets": util.DataSourceList(types.StringType).Computed().Description("The optional deployment targets for this phase.").Build(),
+ "minimum_environments_before_promotion": util.DataSourceInt64().Computed().Description("The minimum number of environments before promotion.").Build(),
+ "is_optional_phase": util.DataSourceBool().Computed().Description("Whether this phase is optional.").Build(),
+ "release_retention_policy": getRetentionPolicyAttribute(),
+ "tentacle_retention_policy": getRetentionPolicyAttribute(),
},
},
}
}
-func getDatasourceRetentionPolicySchema() datasourceSchema.ListNestedAttribute {
+func getRetentionPolicyAttribute() datasourceSchema.ListNestedAttribute {
return datasourceSchema.ListNestedAttribute{
Computed: true,
NestedObject: datasourceSchema.NestedAttributeObject{
Attributes: map[string]datasourceSchema.Attribute{
- "quantity_to_keep": datasourceSchema.Int64Attribute{Computed: true},
- "should_keep_forever": datasourceSchema.BoolAttribute{Computed: true},
- "unit": datasourceSchema.StringAttribute{Computed: true},
+ "quantity_to_keep": util.DataSourceInt64().Computed().Description("The quantity of releases to keep.").Build(),
+ "should_keep_forever": util.DataSourceBool().Computed().Description("Whether releases should be kept forever.").Build(),
+ "unit": util.DataSourceString().Computed().Description("The unit of time for the retention policy.").Build(),
},
},
}
diff --git a/octopusdeploy_framework/schemas/tenant_project_variable.go b/octopusdeploy_framework/schemas/tenant_project_variable.go
index 99553e7c6..4e681a99e 100644
--- a/octopusdeploy_framework/schemas/tenant_project_variable.go
+++ b/octopusdeploy_framework/schemas/tenant_project_variable.go
@@ -3,6 +3,7 @@ package schemas
import (
"github.com/OctopusDeploy/terraform-provider-octopusdeploy/octopusdeploy_framework/util"
"github.com/hashicorp/terraform-plugin-framework/resource/schema"
+ "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
)
const (
@@ -14,17 +15,38 @@ func GetTenantProjectVariableResourceSchema() schema.Schema {
return schema.Schema{
Description: "Manages a tenant project variable in Octopus Deploy.",
Attributes: map[string]schema.Attribute{
- "id": util.GetIdResourceSchema(),
- "space_id": util.GetSpaceIdResourceSchema(TenantProjectVariableResourceDescription),
- "tenant_id": util.GetRequiredStringResourceSchema("The ID of the tenant."),
- "project_id": util.GetRequiredStringResourceSchema("The ID of the project."),
- "environment_id": util.GetRequiredStringResourceSchema("The ID of the environment."),
- "template_id": util.GetRequiredStringResourceSchema("The ID of the variable template."),
- "value": schema.StringAttribute{
- Required: true,
- Description: "The value of the variable.",
- Sensitive: true,
- },
+ "id": util.ResourceString().
+ Computed().
+ Description("The unique ID for this resource.").
+ PlanModifiers(stringplanmodifier.UseStateForUnknown()).
+ Build(),
+ "space_id": util.ResourceString().
+ Optional().
+ Computed().
+ Description("The space ID associated with this Tenant Project Variable.").
+ PlanModifiers(stringplanmodifier.UseStateForUnknown()).
+ Build(),
+ "tenant_id": util.ResourceString().
+ Required().
+ Description("The ID of the tenant.").
+ Build(),
+ "project_id": util.ResourceString().
+ Required().
+ Description("The ID of the project.").
+ Build(),
+ "environment_id": util.ResourceString().
+ Required().
+ Description("The ID of the environment.").
+ Build(),
+ "template_id": util.ResourceString().
+ Required().
+ Description("The ID of the variable template.").
+ Build(),
+ "value": util.ResourceString().
+ Optional().
+ Sensitive().
+ Description("The value of the variable.").
+ Build(),
},
}
}
diff --git a/octopusdeploy_framework/util/resource_attribute_builder.go b/octopusdeploy_framework/util/resource_attribute_builder.go
index 153cafbf7..908f07929 100644
--- a/octopusdeploy_framework/util/resource_attribute_builder.go
+++ b/octopusdeploy_framework/util/resource_attribute_builder.go
@@ -8,8 +8,10 @@ import (
"github.com/hashicorp/terraform-plugin-framework/resource/schema/int64default"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/listdefault"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/mapdefault"
+ "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/setdefault"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault"
+ "github.com/hashicorp/terraform-plugin-framework/schema/validator"
"github.com/hashicorp/terraform-plugin-framework/types"
)
@@ -217,6 +219,84 @@ func (b *AttributeBuilder[T]) Build() T {
return b.attr
}
+func (b *AttributeBuilder[T]) PlanModifiers(modifiers ...any) *AttributeBuilder[T] {
+ switch a := any(&b.attr).(type) {
+ case *schema.StringAttribute:
+ if stringModifiers, ok := convertToTypedSlice[planmodifier.String](modifiers); ok {
+ a.PlanModifiers = append(a.PlanModifiers, stringModifiers...)
+ }
+ case *schema.BoolAttribute:
+ if boolModifiers, ok := convertToTypedSlice[planmodifier.Bool](modifiers); ok {
+ a.PlanModifiers = append(a.PlanModifiers, boolModifiers...)
+ }
+ case *schema.Int64Attribute:
+ if int64Modifiers, ok := convertToTypedSlice[planmodifier.Int64](modifiers); ok {
+ a.PlanModifiers = append(a.PlanModifiers, int64Modifiers...)
+ }
+ case *schema.Float64Attribute:
+ if float64Modifiers, ok := convertToTypedSlice[planmodifier.Float64](modifiers); ok {
+ a.PlanModifiers = append(a.PlanModifiers, float64Modifiers...)
+ }
+ case *schema.ListAttribute:
+ if listModifiers, ok := convertToTypedSlice[planmodifier.List](modifiers); ok {
+ a.PlanModifiers = append(a.PlanModifiers, listModifiers...)
+ }
+ case *schema.SetAttribute:
+ if setModifiers, ok := convertToTypedSlice[planmodifier.Set](modifiers); ok {
+ a.PlanModifiers = append(a.PlanModifiers, setModifiers...)
+ }
+ case *schema.MapAttribute:
+ if mapModifiers, ok := convertToTypedSlice[planmodifier.Map](modifiers); ok {
+ a.PlanModifiers = append(a.PlanModifiers, mapModifiers...)
+ }
+ }
+ return b
+}
+func (b *AttributeBuilder[T]) Validators(validators ...any) *AttributeBuilder[T] {
+ switch a := any(&b.attr).(type) {
+ case *schema.StringAttribute:
+ if stringValidators, ok := convertToTypedSlice[validator.String](validators); ok {
+ a.Validators = append(a.Validators, stringValidators...)
+ }
+ case *schema.BoolAttribute:
+ if boolValidators, ok := convertToTypedSlice[validator.Bool](validators); ok {
+ a.Validators = append(a.Validators, boolValidators...)
+ }
+ case *schema.Int64Attribute:
+ if int64Validators, ok := convertToTypedSlice[validator.Int64](validators); ok {
+ a.Validators = append(a.Validators, int64Validators...)
+ }
+ case *schema.Float64Attribute:
+ if float64Validators, ok := convertToTypedSlice[validator.Float64](validators); ok {
+ a.Validators = append(a.Validators, float64Validators...)
+ }
+ case *schema.ListAttribute:
+ if listValidators, ok := convertToTypedSlice[validator.List](validators); ok {
+ a.Validators = append(a.Validators, listValidators...)
+ }
+ case *schema.SetAttribute:
+ if setValidators, ok := convertToTypedSlice[validator.Set](validators); ok {
+ a.Validators = append(a.Validators, setValidators...)
+ }
+ case *schema.MapAttribute:
+ if mapValidators, ok := convertToTypedSlice[validator.Map](validators); ok {
+ a.Validators = append(a.Validators, mapValidators...)
+ }
+ }
+ return b
+}
+
+func convertToTypedSlice[T any](slice []any) ([]T, bool) {
+ typedSlice := make([]T, 0, len(slice))
+ for _, item := range slice {
+ if typed, ok := item.(T); ok {
+ typedSlice = append(typedSlice, typed)
+ } else {
+ return nil, false
+ }
+ }
+ return typedSlice, true
+}
func ResourceString() *AttributeBuilder[schema.StringAttribute] {
return NewAttributeBuilder[schema.StringAttribute]()
}
From b1a1cd2f7f0d7638e05cd8b54a1bb76f6d8ae6cb Mon Sep 17 00:00:00 2001
From: Henrik Andersson
Date: Wed, 7 Aug 2024 22:38:06 -0700
Subject: [PATCH 05/12] chore: ensure resources deleted from Octopus are
removed from state (#720)
---
go.mod | 2 +-
go.sum | 2 ++
internal/errors/error.go | 22 +++++++++++++++++++
.../resource_artifactory_generic_feed.go | 6 ++++-
...resource_aws_elastic_container_registry.go | 6 ++++-
.../resource_docker_container_registry.go | 6 ++++-
.../resource_environment.go | 6 ++++-
.../resource_git_credential.go | 9 ++++++--
.../resource_github_repository_feed.go | 6 ++++-
octopusdeploy_framework/resource_helm_feed.go | 6 ++++-
.../resource_library_variable_set.go | 8 +++++--
octopusdeploy_framework/resource_lifecycle.go | 17 +++++++++-----
.../resource_lifecycle_test.go | 7 +++---
.../resource_maven_feed.go | 6 ++++-
.../resource_nuget_feed.go | 6 ++++-
octopusdeploy_framework/resource_project.go | 6 ++++-
.../resource_project_flatten.go | 4 +++-
.../resource_project_group.go | 6 ++++-
.../resource_project_model.go | 4 +++-
octopusdeploy_framework/resource_space.go | 8 +++++--
.../resource_tenant_common_variable.go | 3 ++-
.../resource_tenant_project.go | 3 ++-
.../resource_tenant_project_variable.go | 6 +++--
octopusdeploy_framework/resource_variable.go | 5 ++++-
.../schemas/artifactory_generic_feed.go | 3 ++-
.../schemas/aws_elastic_container_registry.go | 3 ++-
.../schemas/docker_container_registry_feed.go | 3 ++-
.../schemas/environment.go | 3 ++-
.../schemas/github_repository_feed.go | 3 ++-
octopusdeploy_framework/schemas/helm_feed.go | 3 ++-
.../schemas/library_variable_set.go | 3 ++-
octopusdeploy_framework/schemas/maven_feed.go | 3 ++-
octopusdeploy_framework/schemas/nuget_feed.go | 3 ++-
.../schemas/project_group.go | 3 ++-
octopusdeploy_framework/schemas/resource.go | 19 ++++++++++++++++
octopusdeploy_framework/schemas/space.go | 3 ++-
octopusdeploy_framework/schemas/variable.go | 6 +++--
37 files changed, 173 insertions(+), 45 deletions(-)
create mode 100644 octopusdeploy_framework/schemas/resource.go
diff --git a/go.mod b/go.mod
index 2cad3a7e8..4cc35d04a 100644
--- a/go.mod
+++ b/go.mod
@@ -8,7 +8,7 @@ require (
github.com/google/uuid v1.6.0
github.com/hashicorp/go-cty v1.4.1-0.20200723130312-85980079f637
github.com/hashicorp/terraform-plugin-docs v0.13.0
- github.com/hashicorp/terraform-plugin-framework v1.9.0
+ github.com/hashicorp/terraform-plugin-framework v1.11.0
github.com/hashicorp/terraform-plugin-framework-validators v0.12.0
github.com/hashicorp/terraform-plugin-go v0.23.0
github.com/hashicorp/terraform-plugin-log v0.9.0
diff --git a/go.sum b/go.sum
index fd5a915a5..c917536b0 100644
--- a/go.sum
+++ b/go.sum
@@ -166,6 +166,8 @@ github.com/hashicorp/terraform-plugin-docs v0.13.0 h1:6e+VIWsVGb6jYJewfzq2ok2smP
github.com/hashicorp/terraform-plugin-docs v0.13.0/go.mod h1:W0oCmHAjIlTHBbvtppWHe8fLfZ2BznQbuv8+UD8OucQ=
github.com/hashicorp/terraform-plugin-framework v1.9.0 h1:caLcDoxiRucNi2hk8+j3kJwkKfvHznubyFsJMWfZqKU=
github.com/hashicorp/terraform-plugin-framework v1.9.0/go.mod h1:qBXLDn69kM97NNVi/MQ9qgd1uWWsVftGSnygYG1tImM=
+github.com/hashicorp/terraform-plugin-framework v1.11.0 h1:M7+9zBArexHFXDx/pKTxjE6n/2UCXY6b8FIq9ZYhwfE=
+github.com/hashicorp/terraform-plugin-framework v1.11.0/go.mod h1:qBXLDn69kM97NNVi/MQ9qgd1uWWsVftGSnygYG1tImM=
github.com/hashicorp/terraform-plugin-framework-validators v0.12.0 h1:HOjBuMbOEzl7snOdOoUfE2Jgeto6JOjLVQ39Ls2nksc=
github.com/hashicorp/terraform-plugin-framework-validators v0.12.0/go.mod h1:jfHGE/gzjxYz6XoUwi/aYiiKrJDeutQNUtGQXkaHklg=
github.com/hashicorp/terraform-plugin-go v0.23.0 h1:AALVuU1gD1kPb48aPQUjug9Ir/125t+AAurhqphJ2Co=
diff --git a/internal/errors/error.go b/internal/errors/error.go
index 21c2d4f74..733b46675 100644
--- a/internal/errors/error.go
+++ b/internal/errors/error.go
@@ -6,6 +6,8 @@ import (
"net/http"
"github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/core"
+ "github.com/OctopusDeploy/terraform-provider-octopusdeploy/octopusdeploy_framework/schemas"
+ "github.com/hashicorp/terraform-plugin-framework/resource"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)
@@ -29,3 +31,23 @@ func ProcessApiError(ctx context.Context, d *schema.ResourceData, err error, res
return diag.FromErr(err)
}
+
+func DeleteFromStateV2(ctx context.Context, resp *resource.ReadResponse, resource schemas.IResourceModel, resourceDescription string) error {
+ log.Printf("[INFO] %s (%s) not found; deleting from state", resourceDescription, resource.GetID())
+ resp.State.RemoveResource(ctx)
+ return nil
+}
+
+func ProcessApiErrorV2(ctx context.Context, resp *resource.ReadResponse, resource schemas.IResourceModel, err error, resourceDescription string) error {
+ if err == nil {
+ return nil
+ }
+
+ if apiError, ok := err.(*core.APIError); ok {
+ if apiError.StatusCode == http.StatusNotFound {
+ return DeleteFromStateV2(ctx, resp, resource, resourceDescription)
+ }
+ }
+
+ return nil
+}
diff --git a/octopusdeploy_framework/resource_artifactory_generic_feed.go b/octopusdeploy_framework/resource_artifactory_generic_feed.go
index a1eb7ab58..b6c765d51 100644
--- a/octopusdeploy_framework/resource_artifactory_generic_feed.go
+++ b/octopusdeploy_framework/resource_artifactory_generic_feed.go
@@ -3,7 +3,9 @@ package octopusdeploy_framework
import (
"context"
"fmt"
+
"github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/core"
+ "github.com/OctopusDeploy/terraform-provider-octopusdeploy/internal/errors"
"github.com/OctopusDeploy/terraform-provider-octopusdeploy/octopusdeploy_framework/schemas"
"github.com/OctopusDeploy/terraform-provider-octopusdeploy/octopusdeploy_framework/util"
"github.com/hashicorp/terraform-plugin-framework/attr"
@@ -77,7 +79,9 @@ func (r *artifactoryGenericFeedTypeResource) Read(ctx context.Context, req resou
client := r.Config.Client
feed, err := feeds.GetByID(client, data.SpaceID.ValueString(), data.ID.ValueString())
if err != nil {
- resp.Diagnostics.AddError("unable to load artifactoryGeneric feed", err.Error())
+ if err := errors.ProcessApiErrorV2(ctx, resp, data, err, "artifactory generic feed"); err != nil {
+ resp.Diagnostics.AddError("unable to load artifactoryGeneric feed", err.Error())
+ }
return
}
diff --git a/octopusdeploy_framework/resource_aws_elastic_container_registry.go b/octopusdeploy_framework/resource_aws_elastic_container_registry.go
index 72cef3b51..daeb36f31 100644
--- a/octopusdeploy_framework/resource_aws_elastic_container_registry.go
+++ b/octopusdeploy_framework/resource_aws_elastic_container_registry.go
@@ -3,8 +3,10 @@ package octopusdeploy_framework
import (
"context"
"fmt"
+
"github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/core"
"github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/feeds"
+ "github.com/OctopusDeploy/terraform-provider-octopusdeploy/internal/errors"
"github.com/OctopusDeploy/terraform-provider-octopusdeploy/octopusdeploy_framework/schemas"
"github.com/OctopusDeploy/terraform-provider-octopusdeploy/octopusdeploy_framework/util"
"github.com/hashicorp/terraform-plugin-framework/attr"
@@ -78,7 +80,9 @@ func (r *awsElasticContainerRegistryFeedTypeResource) Read(ctx context.Context,
client := r.Config.Client
feed, err := feeds.GetByID(client, data.SpaceID.ValueString(), data.ID.ValueString())
if err != nil {
- resp.Diagnostics.AddError("unable to load aws elastic container registry", err.Error())
+ if err := errors.ProcessApiErrorV2(ctx, resp, data, err, "aws elastic container registry"); err != nil {
+ resp.Diagnostics.AddError("unable to load aws elastic container registry", err.Error())
+ }
return
}
diff --git a/octopusdeploy_framework/resource_docker_container_registry.go b/octopusdeploy_framework/resource_docker_container_registry.go
index fa73ef902..0b246633e 100644
--- a/octopusdeploy_framework/resource_docker_container_registry.go
+++ b/octopusdeploy_framework/resource_docker_container_registry.go
@@ -3,8 +3,10 @@ package octopusdeploy_framework
import (
"context"
"fmt"
+
"github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/core"
"github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/feeds"
+ "github.com/OctopusDeploy/terraform-provider-octopusdeploy/internal/errors"
"github.com/OctopusDeploy/terraform-provider-octopusdeploy/octopusdeploy_framework/schemas"
"github.com/OctopusDeploy/terraform-provider-octopusdeploy/octopusdeploy_framework/util"
"github.com/hashicorp/terraform-plugin-framework/attr"
@@ -76,7 +78,9 @@ func (r *dockerContainerRegistryFeedTypeResource) Read(ctx context.Context, req
client := r.Config.Client
feed, err := feeds.GetByID(client, data.SpaceID.ValueString(), data.ID.ValueString())
if err != nil {
- resp.Diagnostics.AddError("unable to load docker container registry feed", err.Error())
+ if err := errors.ProcessApiErrorV2(ctx, resp, data, err, "docker container registry feed"); err != nil {
+ resp.Diagnostics.AddError("unable to load docker container registry feed", err.Error())
+ }
return
}
diff --git a/octopusdeploy_framework/resource_environment.go b/octopusdeploy_framework/resource_environment.go
index a393279ad..281639f6d 100644
--- a/octopusdeploy_framework/resource_environment.go
+++ b/octopusdeploy_framework/resource_environment.go
@@ -5,6 +5,7 @@ import (
"github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/environments"
"github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/extensions"
+ "github.com/OctopusDeploy/terraform-provider-octopusdeploy/internal/errors"
"github.com/OctopusDeploy/terraform-provider-octopusdeploy/octopusdeploy_framework/schemas"
"github.com/OctopusDeploy/terraform-provider-octopusdeploy/octopusdeploy_framework/util"
"github.com/hashicorp/terraform-plugin-framework/resource"
@@ -82,7 +83,10 @@ func (r *environmentTypeResource) Read(ctx context.Context, req resource.ReadReq
environment, err := environments.GetByID(r.Config.Client, data.SpaceID.ValueString(), data.ID.ValueString())
if err != nil {
- resp.Diagnostics.AddError("unable to load environment", err.Error())
+ if err := errors.ProcessApiErrorV2(ctx, resp, data, err, "environment"); err != nil {
+ resp.Diagnostics.AddError("unable to load environment", err.Error())
+ }
+ return
}
updateEnvironment(ctx, &data, environment)
diff --git a/octopusdeploy_framework/resource_git_credential.go b/octopusdeploy_framework/resource_git_credential.go
index 478b4f8b4..8a5baeec1 100644
--- a/octopusdeploy_framework/resource_git_credential.go
+++ b/octopusdeploy_framework/resource_git_credential.go
@@ -2,8 +2,10 @@ package octopusdeploy_framework
import (
"context"
+
"github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/core"
"github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/credentials"
+ "github.com/OctopusDeploy/terraform-provider-octopusdeploy/internal/errors"
"github.com/OctopusDeploy/terraform-provider-octopusdeploy/octopusdeploy_framework/schemas"
"github.com/OctopusDeploy/terraform-provider-octopusdeploy/octopusdeploy_framework/util"
"github.com/hashicorp/terraform-plugin-framework/resource"
@@ -18,13 +20,14 @@ type gitCredentialResource struct {
}
type gitCredentialResourceModel struct {
- ID types.String `tfsdk:"id"`
SpaceID types.String `tfsdk:"space_id"`
Name types.String `tfsdk:"name"`
Description types.String `tfsdk:"description"`
Type types.String `tfsdk:"type"`
Username types.String `tfsdk:"username"`
Password types.String `tfsdk:"password"`
+
+ schemas.ResourceModel
}
func NewGitCredentialResource() resource.Resource {
@@ -92,7 +95,9 @@ func (g *gitCredentialResource) Read(ctx context.Context, req resource.ReadReque
gitCredential, err := credentials.GetByID(g.Client, state.SpaceID.ValueString(), state.ID.ValueString())
if err != nil {
- resp.Diagnostics.AddError("Error reading Git credential", err.Error())
+ if err := errors.ProcessApiErrorV2(ctx, resp, state, err, "git credential"); err != nil {
+ resp.Diagnostics.AddError("Error reading Git credential", err.Error())
+ }
return
}
diff --git a/octopusdeploy_framework/resource_github_repository_feed.go b/octopusdeploy_framework/resource_github_repository_feed.go
index 30f7bdb28..6b6aabb63 100644
--- a/octopusdeploy_framework/resource_github_repository_feed.go
+++ b/octopusdeploy_framework/resource_github_repository_feed.go
@@ -3,8 +3,10 @@ package octopusdeploy_framework
import (
"context"
"fmt"
+
"github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/core"
"github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/feeds"
+ "github.com/OctopusDeploy/terraform-provider-octopusdeploy/internal/errors"
"github.com/OctopusDeploy/terraform-provider-octopusdeploy/octopusdeploy_framework/schemas"
"github.com/OctopusDeploy/terraform-provider-octopusdeploy/octopusdeploy_framework/util"
"github.com/hashicorp/terraform-plugin-framework/attr"
@@ -78,7 +80,9 @@ func (r *githubRepositoryFeedTypeResource) Read(ctx context.Context, req resourc
client := r.Config.Client
feed, err := feeds.GetByID(client, data.SpaceID.ValueString(), data.ID.ValueString())
if err != nil {
- resp.Diagnostics.AddError("unable to load github repository feed", err.Error())
+ if err := errors.ProcessApiErrorV2(ctx, resp, data, err, "github repository feed"); err != nil {
+ resp.Diagnostics.AddError("unable to load github repository feed", err.Error())
+ }
return
}
diff --git a/octopusdeploy_framework/resource_helm_feed.go b/octopusdeploy_framework/resource_helm_feed.go
index 64ec52677..dd7667eff 100644
--- a/octopusdeploy_framework/resource_helm_feed.go
+++ b/octopusdeploy_framework/resource_helm_feed.go
@@ -3,7 +3,9 @@ package octopusdeploy_framework
import (
"context"
"fmt"
+
"github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/core"
+ "github.com/OctopusDeploy/terraform-provider-octopusdeploy/internal/errors"
"github.com/OctopusDeploy/terraform-provider-octopusdeploy/octopusdeploy_framework/schemas"
"github.com/OctopusDeploy/terraform-provider-octopusdeploy/octopusdeploy_framework/util"
"github.com/hashicorp/terraform-plugin-framework/attr"
@@ -77,7 +79,9 @@ func (r *helmFeedTypeResource) Read(ctx context.Context, req resource.ReadReques
client := r.Config.Client
feed, err := feeds.GetByID(client, data.SpaceID.ValueString(), data.ID.ValueString())
if err != nil {
- resp.Diagnostics.AddError("unable to load helm feed", err.Error())
+ if err := errors.ProcessApiErrorV2(ctx, resp, data, err, "helm feed"); err != nil {
+ resp.Diagnostics.AddError("unable to load helm feed", err.Error())
+ }
return
}
diff --git a/octopusdeploy_framework/resource_library_variable_set.go b/octopusdeploy_framework/resource_library_variable_set.go
index 733b88664..cdf616aa0 100644
--- a/octopusdeploy_framework/resource_library_variable_set.go
+++ b/octopusdeploy_framework/resource_library_variable_set.go
@@ -3,12 +3,14 @@ package octopusdeploy_framework
import (
"context"
"fmt"
+ "log"
+
"github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/libraryvariablesets"
+ "github.com/OctopusDeploy/terraform-provider-octopusdeploy/internal/errors"
"github.com/OctopusDeploy/terraform-provider-octopusdeploy/octopusdeploy_framework/schemas"
"github.com/OctopusDeploy/terraform-provider-octopusdeploy/octopusdeploy_framework/util"
"github.com/hashicorp/terraform-plugin-framework/resource"
"github.com/hashicorp/terraform-plugin-log/tflog"
- "log"
)
type libraryVariableSetFeedTypeResource struct {
@@ -61,7 +63,9 @@ func (r *libraryVariableSetFeedTypeResource) Read(ctx context.Context, req resou
libraryVariableSet, err := libraryvariablesets.GetByID(r.Config.Client, data.SpaceID.ValueString(), data.ID.ValueString())
if err != nil {
- resp.Diagnostics.AddError("unable to load library variable set", err.Error())
+ if err := errors.ProcessApiErrorV2(ctx, resp, data, err, "library variable set"); err != nil {
+ resp.Diagnostics.AddError("unable to load library variable set", err.Error())
+ }
return
}
diff --git a/octopusdeploy_framework/resource_lifecycle.go b/octopusdeploy_framework/resource_lifecycle.go
index afdea2ef6..a4c863f8c 100644
--- a/octopusdeploy_framework/resource_lifecycle.go
+++ b/octopusdeploy_framework/resource_lifecycle.go
@@ -3,8 +3,11 @@ package octopusdeploy_framework
import (
"context"
"fmt"
+ "strings"
+
"github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/core"
"github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/lifecycles"
+ "github.com/OctopusDeploy/terraform-provider-octopusdeploy/internal/errors"
"github.com/OctopusDeploy/terraform-provider-octopusdeploy/octopusdeploy_framework/schemas"
"github.com/OctopusDeploy/terraform-provider-octopusdeploy/octopusdeploy_framework/util"
"github.com/hashicorp/terraform-plugin-framework/attr"
@@ -12,7 +15,6 @@ import (
"github.com/hashicorp/terraform-plugin-framework/resource"
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/hashicorp/terraform-plugin-log/tflog"
- "strings"
)
type lifecycleTypeResource struct {
@@ -23,13 +25,14 @@ var _ resource.Resource = &lifecycleTypeResource{}
var _ resource.ResourceWithImportState = &lifecycleTypeResource{}
type lifecycleTypeResourceModel struct {
- ID types.String `tfsdk:"id"`
SpaceID types.String `tfsdk:"space_id"`
Name types.String `tfsdk:"name"`
Description types.String `tfsdk:"description"`
Phase types.List `tfsdk:"phase"`
ReleaseRetentionPolicy types.List `tfsdk:"release_retention_policy"`
TentacleRetentionPolicy types.List `tfsdk:"tentacle_retention_policy"`
+
+ schemas.ResourceModel
}
func NewLifecycleResource() resource.Resource {
@@ -88,7 +91,9 @@ func (r *lifecycleTypeResource) Read(ctx context.Context, req resource.ReadReque
lifecycle, err := lifecycles.GetByID(r.Config.Client, data.SpaceID.ValueString(), data.ID.ValueString())
if err != nil {
- resp.Diagnostics.AddError("unable to load lifecycle", err.Error())
+ if err := errors.ProcessApiErrorV2(ctx, resp, data, err, "lifecycle"); err != nil {
+ resp.Diagnostics.AddError("unable to load lifecycle", err.Error())
+ }
return
}
data = flattenLifecycleResource(lifecycle)
@@ -195,8 +200,7 @@ func setDefaultRetentionPolicies(data *lifecycleTypeResourceModel) {
}
func flattenLifecycleResource(lifecycle *lifecycles.Lifecycle) *lifecycleTypeResourceModel {
- return &lifecycleTypeResourceModel{
- ID: types.StringValue(lifecycle.ID),
+ flattenedLifecycle := &lifecycleTypeResourceModel{
SpaceID: types.StringValue(lifecycle.SpaceID),
Name: types.StringValue(lifecycle.Name),
Description: types.StringValue(lifecycle.Description),
@@ -204,6 +208,9 @@ func flattenLifecycleResource(lifecycle *lifecycles.Lifecycle) *lifecycleTypeRes
ReleaseRetentionPolicy: flattenRetentionPeriod(lifecycle.ReleaseRetentionPolicy),
TentacleRetentionPolicy: flattenRetentionPeriod(lifecycle.TentacleRetentionPolicy),
}
+ flattenedLifecycle.ID = types.StringValue(lifecycle.GetID())
+
+ return flattenedLifecycle
}
func flattenPhases(phases []*lifecycles.Phase) types.List {
diff --git a/octopusdeploy_framework/resource_lifecycle_test.go b/octopusdeploy_framework/resource_lifecycle_test.go
index 639fc6a93..bbcc08030 100644
--- a/octopusdeploy_framework/resource_lifecycle_test.go
+++ b/octopusdeploy_framework/resource_lifecycle_test.go
@@ -2,6 +2,9 @@ package octopusdeploy_framework
import (
"fmt"
+ "path/filepath"
+ "testing"
+
"github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/client"
"github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/core"
"github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/lifecycles"
@@ -13,8 +16,6 @@ import (
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
"github.com/hashicorp/terraform-plugin-testing/terraform"
"github.com/stretchr/testify/require"
- "path/filepath"
- "testing"
)
func TestExpandLifecycleWithNil(t *testing.T) {
@@ -31,7 +32,6 @@ func TestExpandLifecycle(t *testing.T) {
tentacleRetention := core.NewRetentionPeriod(2, "Items", false)
data := &lifecycleTypeResourceModel{
- ID: types.StringValue(Id),
Description: types.StringValue(description),
Name: types.StringValue(name),
SpaceID: types.StringValue(spaceID),
@@ -62,6 +62,7 @@ func TestExpandLifecycle(t *testing.T) {
},
),
}
+ data.ID = types.StringValue(Id)
lifecycle := expandLifecycle(data)
diff --git a/octopusdeploy_framework/resource_maven_feed.go b/octopusdeploy_framework/resource_maven_feed.go
index 722081e81..55346da60 100644
--- a/octopusdeploy_framework/resource_maven_feed.go
+++ b/octopusdeploy_framework/resource_maven_feed.go
@@ -3,8 +3,10 @@ package octopusdeploy_framework
import (
"context"
"fmt"
+
"github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/core"
"github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/feeds"
+ "github.com/OctopusDeploy/terraform-provider-octopusdeploy/internal/errors"
"github.com/OctopusDeploy/terraform-provider-octopusdeploy/octopusdeploy_framework/schemas"
"github.com/OctopusDeploy/terraform-provider-octopusdeploy/octopusdeploy_framework/util"
"github.com/hashicorp/terraform-plugin-framework/attr"
@@ -76,7 +78,9 @@ func (r *mavenFeedTypeResource) Read(ctx context.Context, req resource.ReadReque
client := r.Config.Client
feed, err := feeds.GetByID(client, data.SpaceID.ValueString(), data.ID.ValueString())
if err != nil {
- resp.Diagnostics.AddError("unable to load maven feed", err.Error())
+ if err := errors.ProcessApiErrorV2(ctx, resp, data, err, "maven feed"); err != nil {
+ resp.Diagnostics.AddError("unable to load maven feed", err.Error())
+ }
return
}
diff --git a/octopusdeploy_framework/resource_nuget_feed.go b/octopusdeploy_framework/resource_nuget_feed.go
index f053ea450..bf0576248 100644
--- a/octopusdeploy_framework/resource_nuget_feed.go
+++ b/octopusdeploy_framework/resource_nuget_feed.go
@@ -3,8 +3,10 @@ package octopusdeploy_framework
import (
"context"
"fmt"
+
"github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/core"
"github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/feeds"
+ "github.com/OctopusDeploy/terraform-provider-octopusdeploy/internal/errors"
"github.com/OctopusDeploy/terraform-provider-octopusdeploy/octopusdeploy_framework/schemas"
"github.com/OctopusDeploy/terraform-provider-octopusdeploy/octopusdeploy_framework/util"
"github.com/hashicorp/terraform-plugin-framework/attr"
@@ -78,7 +80,9 @@ func (r *nugetFeedTypeResource) Read(ctx context.Context, req resource.ReadReque
client := r.Config.Client
feed, err := feeds.GetByID(client, data.SpaceID.ValueString(), data.ID.ValueString())
if err != nil {
- resp.Diagnostics.AddError("unable to load nuget feed", err.Error())
+ if err := errors.ProcessApiErrorV2(ctx, resp, data, err, "nuget feed"); err != nil {
+ resp.Diagnostics.AddError("unable to load nuget feed", err.Error())
+ }
return
}
diff --git a/octopusdeploy_framework/resource_project.go b/octopusdeploy_framework/resource_project.go
index 6b73a6d7a..bcefbbf69 100644
--- a/octopusdeploy_framework/resource_project.go
+++ b/octopusdeploy_framework/resource_project.go
@@ -3,7 +3,9 @@ package octopusdeploy_framework
import (
"context"
"fmt"
+
"github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/projects"
+ "github.com/OctopusDeploy/terraform-provider-octopusdeploy/internal/errors"
"github.com/OctopusDeploy/terraform-provider-octopusdeploy/octopusdeploy_framework/schemas"
"github.com/OctopusDeploy/terraform-provider-octopusdeploy/octopusdeploy_framework/util"
"github.com/hashicorp/terraform-plugin-framework/resource"
@@ -92,7 +94,9 @@ func (r *projectResource) Read(ctx context.Context, req resource.ReadRequest, re
project, err := projects.GetByID(r.Client, state.SpaceID.ValueString(), state.ID.ValueString())
if err != nil {
- resp.Diagnostics.AddError("Error reading project", err.Error())
+ if err := errors.ProcessApiErrorV2(ctx, resp, state, err, "lifecycle"); err != nil {
+ resp.Diagnostics.AddError("Error reading project", err.Error())
+ }
return
}
if persistenceSettings != nil {
diff --git a/octopusdeploy_framework/resource_project_flatten.go b/octopusdeploy_framework/resource_project_flatten.go
index 39b4c3e80..6e411b08d 100644
--- a/octopusdeploy_framework/resource_project_flatten.go
+++ b/octopusdeploy_framework/resource_project_flatten.go
@@ -3,6 +3,7 @@ package octopusdeploy_framework
import (
"context"
"fmt"
+
"github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/actiontemplates"
"github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/core"
"github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/credentials"
@@ -26,7 +27,6 @@ func flattenProject(ctx context.Context, project *projects.Project, state *proje
}
model := &projectResourceModel{
- ID: types.StringValue(project.GetID()),
SpaceID: types.StringValue(project.SpaceID),
Name: types.StringValue(project.Name),
Description: types.StringValue(project.Description),
@@ -48,6 +48,8 @@ func flattenProject(ctx context.Context, project *projects.Project, state *proje
ClonedFromProjectID: util.StringOrNull(project.ClonedFromProjectID),
}
+ model.ID = types.StringValue(project.GetID())
+
model.IncludedLibraryVariableSets = util.FlattenStringList(project.IncludedLibraryVariableSets)
model.AutoDeployReleaseOverrides = flattenAutoDeployReleaseOverrides(project.AutoDeployReleaseOverrides)
diff --git a/octopusdeploy_framework/resource_project_group.go b/octopusdeploy_framework/resource_project_group.go
index e78f49cef..8d7a628de 100644
--- a/octopusdeploy_framework/resource_project_group.go
+++ b/octopusdeploy_framework/resource_project_group.go
@@ -3,7 +3,9 @@ package octopusdeploy_framework
import (
"context"
"fmt"
+
"github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/projectgroups"
+ "github.com/OctopusDeploy/terraform-provider-octopusdeploy/internal/errors"
"github.com/OctopusDeploy/terraform-provider-octopusdeploy/octopusdeploy_framework/schemas"
"github.com/OctopusDeploy/terraform-provider-octopusdeploy/octopusdeploy_framework/util"
"github.com/hashicorp/terraform-plugin-framework/resource"
@@ -67,7 +69,9 @@ func (r *projectGroupTypeResource) Read(ctx context.Context, req resource.ReadRe
group, err := projectgroups.GetByID(r.Config.Client, data.SpaceID.ValueString(), data.ID.ValueString())
if err != nil {
- resp.Diagnostics.AddError("unable to load project group", err.Error())
+ if err := errors.ProcessApiErrorV2(ctx, resp, data, err, "project group"); err != nil {
+ resp.Diagnostics.AddError("unable to load project group", err.Error())
+ }
return
}
diff --git a/octopusdeploy_framework/resource_project_model.go b/octopusdeploy_framework/resource_project_model.go
index 7e7386079..d58409893 100644
--- a/octopusdeploy_framework/resource_project_model.go
+++ b/octopusdeploy_framework/resource_project_model.go
@@ -1,11 +1,11 @@
package octopusdeploy_framework
import (
+ "github.com/OctopusDeploy/terraform-provider-octopusdeploy/octopusdeploy_framework/schemas"
"github.com/hashicorp/terraform-plugin-framework/types"
)
type projectResourceModel struct {
- ID types.String `tfsdk:"id"`
SpaceID types.String `tfsdk:"space_id"`
Name types.String `tfsdk:"name"`
Description types.String `tfsdk:"description"`
@@ -37,6 +37,8 @@ type projectResourceModel struct {
ServiceNowExtensionSettings types.List `tfsdk:"servicenow_extension_settings"`
IncludedLibraryVariableSets types.List `tfsdk:"included_library_variable_sets"`
AutoDeployReleaseOverrides types.List `tfsdk:"auto_deploy_release_overrides"`
+
+ schemas.ResourceModel
}
type connectivityPolicyModel struct {
diff --git a/octopusdeploy_framework/resource_space.go b/octopusdeploy_framework/resource_space.go
index 01cf13cdb..42470551a 100644
--- a/octopusdeploy_framework/resource_space.go
+++ b/octopusdeploy_framework/resource_space.go
@@ -3,7 +3,10 @@ package octopusdeploy_framework
import (
"context"
"fmt"
+ "strings"
+
"github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/spaces"
+ "github.com/OctopusDeploy/terraform-provider-octopusdeploy/internal/errors"
"github.com/OctopusDeploy/terraform-provider-octopusdeploy/octopusdeploy_framework/schemas"
"github.com/OctopusDeploy/terraform-provider-octopusdeploy/octopusdeploy_framework/util"
"github.com/hashicorp/terraform-plugin-framework/path"
@@ -11,7 +14,6 @@ import (
"github.com/hashicorp/terraform-plugin-framework/resource/schema"
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/hashicorp/terraform-plugin-log/tflog"
- "strings"
)
const spaceManagersTeamIDPrefix = "teams-spacemanagers-"
@@ -129,7 +131,9 @@ func (s *spaceResource) Read(ctx context.Context, req resource.ReadRequest, resp
spaceResult, err := spaces.GetByID(s.Client, data.ID.ValueString())
if err != nil {
- resp.Diagnostics.AddError("unable to query spaces", err.Error())
+ if err := errors.ProcessApiErrorV2(ctx, resp, data, err, "space"); err != nil {
+ resp.Diagnostics.AddError("unable to query spaces", err.Error())
+ }
return
}
diff --git a/octopusdeploy_framework/resource_tenant_common_variable.go b/octopusdeploy_framework/resource_tenant_common_variable.go
index 5ce0bd4a3..715f306bb 100644
--- a/octopusdeploy_framework/resource_tenant_common_variable.go
+++ b/octopusdeploy_framework/resource_tenant_common_variable.go
@@ -24,12 +24,13 @@ type tenantCommonVariableResource struct {
}
type tenantCommonVariableResourceModel struct {
- ID types.String `tfsdk:"id"`
SpaceID types.String `tfsdk:"space_id"`
TenantID types.String `tfsdk:"tenant_id"`
LibraryVariableSetID types.String `tfsdk:"library_variable_set_id"`
TemplateID types.String `tfsdk:"template_id"`
Value types.String `tfsdk:"value"`
+
+ schemas.ResourceModel
}
func NewTenantCommonVariableResource() resource.Resource {
diff --git a/octopusdeploy_framework/resource_tenant_project.go b/octopusdeploy_framework/resource_tenant_project.go
index f860af3e3..37a6879c9 100644
--- a/octopusdeploy_framework/resource_tenant_project.go
+++ b/octopusdeploy_framework/resource_tenant_project.go
@@ -21,11 +21,12 @@ import (
)
type TenantProjectModel struct {
- ID types.String `tfsdk:"id"`
SpaceID types.String `tfsdk:"space_id"`
TenantID types.String `tfsdk:"tenant_id"`
ProjectID types.String `tfsdk:"project_id"`
EnvironmentIDs types.List `tfsdk:"environment_ids"`
+
+ schemas.ResourceModel
}
type tenantProjectResource struct {
diff --git a/octopusdeploy_framework/resource_tenant_project_variable.go b/octopusdeploy_framework/resource_tenant_project_variable.go
index 7c7fb8191..7718f658e 100644
--- a/octopusdeploy_framework/resource_tenant_project_variable.go
+++ b/octopusdeploy_framework/resource_tenant_project_variable.go
@@ -3,6 +3,8 @@ package octopusdeploy_framework
import (
"context"
"fmt"
+ "strings"
+
"github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/core"
"github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/tenants"
"github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/variables"
@@ -12,7 +14,6 @@ import (
"github.com/hashicorp/terraform-plugin-framework/resource"
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/hashicorp/terraform-plugin-log/tflog"
- "strings"
)
var _ resource.Resource = &tenantProjectVariableResource{}
@@ -23,13 +24,14 @@ type tenantProjectVariableResource struct {
}
type tenantProjectVariableResourceModel struct {
- ID types.String `tfsdk:"id"`
SpaceID types.String `tfsdk:"space_id"`
TenantID types.String `tfsdk:"tenant_id"`
ProjectID types.String `tfsdk:"project_id"`
EnvironmentID types.String `tfsdk:"environment_id"`
TemplateID types.String `tfsdk:"template_id"`
Value types.String `tfsdk:"value"`
+
+ schemas.ResourceModel
}
func NewTenantProjectVariableResource() resource.Resource {
diff --git a/octopusdeploy_framework/resource_variable.go b/octopusdeploy_framework/resource_variable.go
index 2b411f50c..78d48b5a2 100644
--- a/octopusdeploy_framework/resource_variable.go
+++ b/octopusdeploy_framework/resource_variable.go
@@ -7,6 +7,7 @@ import (
"github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/variables"
"github.com/OctopusDeploy/terraform-provider-octopusdeploy/internal"
+ "github.com/OctopusDeploy/terraform-provider-octopusdeploy/internal/errors"
"github.com/OctopusDeploy/terraform-provider-octopusdeploy/octopusdeploy_framework/schemas"
"github.com/OctopusDeploy/terraform-provider-octopusdeploy/octopusdeploy_framework/util"
"github.com/hashicorp/terraform-plugin-framework/attr"
@@ -125,7 +126,9 @@ func (r *variableTypeResource) Read(ctx context.Context, req resource.ReadReques
variable, err := variables.GetByID(r.Config.Client, data.SpaceID.ValueString(), variableOwnerID.ValueString(), data.ID.ValueString())
if err != nil {
- resp.Diagnostics.AddError("unable to load variable", err.Error())
+ if err := errors.ProcessApiErrorV2(ctx, resp, data, err, schemas.VariableResourceDescription); err != nil {
+ resp.Diagnostics.AddError("unable to load variable", err.Error())
+ }
return
}
diff --git a/octopusdeploy_framework/schemas/artifactory_generic_feed.go b/octopusdeploy_framework/schemas/artifactory_generic_feed.go
index 9ee7623f8..aecde79de 100644
--- a/octopusdeploy_framework/schemas/artifactory_generic_feed.go
+++ b/octopusdeploy_framework/schemas/artifactory_generic_feed.go
@@ -33,7 +33,6 @@ func GetArtifactoryGenericFeedResourceSchema() map[string]resourceSchema.Attribu
type ArtifactoryGenericFeedTypeResourceModel struct {
FeedUri types.String `tfsdk:"feed_uri"`
- ID types.String `tfsdk:"id"`
Name types.String `tfsdk:"name"`
PackageAcquisitionLocationOptions types.List `tfsdk:"package_acquisition_location_options"`
Password types.String `tfsdk:"password"`
@@ -41,4 +40,6 @@ type ArtifactoryGenericFeedTypeResourceModel struct {
Username types.String `tfsdk:"username"`
Repository types.String `tfsdk:"repository"`
LayoutRegex types.String `tfsdk:"layout_regex"`
+
+ ResourceModel
}
diff --git a/octopusdeploy_framework/schemas/aws_elastic_container_registry.go b/octopusdeploy_framework/schemas/aws_elastic_container_registry.go
index 92c3c847b..fbc321f9e 100644
--- a/octopusdeploy_framework/schemas/aws_elastic_container_registry.go
+++ b/octopusdeploy_framework/schemas/aws_elastic_container_registry.go
@@ -32,10 +32,11 @@ func GetAwsElasticContainerRegistryFeedResourceSchema() map[string]resourceSchem
type AwsElasticContainerRegistryFeedTypeResourceModel struct {
AccessKey types.String `tfsdk:"access_key"`
- ID types.String `tfsdk:"id"`
Name types.String `tfsdk:"name"`
PackageAcquisitionLocationOptions types.List `tfsdk:"package_acquisition_location_options"`
Region types.String `tfsdk:"region"`
SecretKey types.String `tfsdk:"secret_key"`
SpaceID types.String `tfsdk:"space_id"`
+
+ ResourceModel
}
diff --git a/octopusdeploy_framework/schemas/docker_container_registry_feed.go b/octopusdeploy_framework/schemas/docker_container_registry_feed.go
index d7ff550c4..346eee869 100644
--- a/octopusdeploy_framework/schemas/docker_container_registry_feed.go
+++ b/octopusdeploy_framework/schemas/docker_container_registry_feed.go
@@ -29,11 +29,12 @@ func GetDockerContainerRegistryFeedResourceSchema() map[string]resourceSchema.At
type DockerContainerRegistryFeedTypeResourceModel struct {
APIVersion types.String `tfsdk:"api_version"`
FeedUri types.String `tfsdk:"feed_uri"`
- ID types.String `tfsdk:"id"`
Name types.String `tfsdk:"name"`
PackageAcquisitionLocationOptions types.List `tfsdk:"package_acquisition_location_options"`
Password types.String `tfsdk:"password"`
SpaceID types.String `tfsdk:"space_id"`
Username types.String `tfsdk:"username"`
RegistryPath types.String `tfsdk:"registry_path"`
+
+ ResourceModel
}
diff --git a/octopusdeploy_framework/schemas/environment.go b/octopusdeploy_framework/schemas/environment.go
index af4a31e20..964532446 100644
--- a/octopusdeploy_framework/schemas/environment.go
+++ b/octopusdeploy_framework/schemas/environment.go
@@ -180,7 +180,6 @@ func MapServiceNowExtensionSettings(serviceNowExtensionSettings *environments.Se
}
type EnvironmentTypeResourceModel struct {
- ID types.String `tfsdk:"id"`
Slug types.String `tfsdk:"slug"`
Name types.String `tfsdk:"name"`
Description types.String `tfsdk:"description"`
@@ -191,4 +190,6 @@ type EnvironmentTypeResourceModel struct {
JiraExtensionSettings types.List `tfsdk:"jira_extension_settings"`
JiraServiceManagementExtensionSettings types.List `tfsdk:"jira_service_management_extension_settings"`
ServiceNowExtensionSettings types.List `tfsdk:"servicenow_extension_settings"`
+
+ ResourceModel
}
diff --git a/octopusdeploy_framework/schemas/github_repository_feed.go b/octopusdeploy_framework/schemas/github_repository_feed.go
index 12cda7b7e..71049f464 100644
--- a/octopusdeploy_framework/schemas/github_repository_feed.go
+++ b/octopusdeploy_framework/schemas/github_repository_feed.go
@@ -26,10 +26,11 @@ type GitHubRepositoryFeedTypeResourceModel struct {
DownloadAttempts types.Int64 `tfsdk:"download_attempts"`
DownloadRetryBackoffSeconds types.Int64 `tfsdk:"download_retry_backoff_seconds"`
FeedUri types.String `tfsdk:"feed_uri"`
- ID types.String `tfsdk:"id"`
Name types.String `tfsdk:"name"`
PackageAcquisitionLocationOptions types.List `tfsdk:"package_acquisition_location_options"`
Password types.String `tfsdk:"password"`
SpaceID types.String `tfsdk:"space_id"`
Username types.String `tfsdk:"username"`
+
+ ResourceModel
}
diff --git a/octopusdeploy_framework/schemas/helm_feed.go b/octopusdeploy_framework/schemas/helm_feed.go
index 62b567b60..7e3072fee 100644
--- a/octopusdeploy_framework/schemas/helm_feed.go
+++ b/octopusdeploy_framework/schemas/helm_feed.go
@@ -22,10 +22,11 @@ func GetHelmFeedResourceSchema() map[string]resourceSchema.Attribute {
type HelmFeedTypeResourceModel struct {
FeedUri types.String `tfsdk:"feed_uri"`
- ID types.String `tfsdk:"id"`
Name types.String `tfsdk:"name"`
PackageAcquisitionLocationOptions types.List `tfsdk:"package_acquisition_location_options"`
Password types.String `tfsdk:"password"`
SpaceID types.String `tfsdk:"space_id"`
Username types.String `tfsdk:"username"`
+
+ ResourceModel
}
diff --git a/octopusdeploy_framework/schemas/library_variable_set.go b/octopusdeploy_framework/schemas/library_variable_set.go
index 5fab75d02..3ca65b627 100644
--- a/octopusdeploy_framework/schemas/library_variable_set.go
+++ b/octopusdeploy_framework/schemas/library_variable_set.go
@@ -12,12 +12,13 @@ import (
type LibraryVariableSetResourceModel struct {
Description types.String `tfsdk:"description"`
- ID types.String `tfsdk:"id"`
Name types.String `tfsdk:"name"`
SpaceID types.String `tfsdk:"space_id"`
Template types.List `tfsdk:"template"`
TemplateIds types.Map `tfsdk:"template_ids"`
VariableSetId types.String `tfsdk:"variable_set_id"`
+
+ ResourceModel
}
func GetLibraryVariableSetDataSourceSchema() datasourceSchema.Schema {
diff --git a/octopusdeploy_framework/schemas/maven_feed.go b/octopusdeploy_framework/schemas/maven_feed.go
index 096d7b4f4..9c01debc3 100644
--- a/octopusdeploy_framework/schemas/maven_feed.go
+++ b/octopusdeploy_framework/schemas/maven_feed.go
@@ -26,10 +26,11 @@ type MavenFeedTypeResourceModel struct {
DownloadAttempts types.Int64 `tfsdk:"download_attempts"`
DownloadRetryBackoffSeconds types.Int64 `tfsdk:"download_retry_backoff_seconds"`
FeedUri types.String `tfsdk:"feed_uri"`
- ID types.String `tfsdk:"id"`
Name types.String `tfsdk:"name"`
PackageAcquisitionLocationOptions types.List `tfsdk:"package_acquisition_location_options"`
Password types.String `tfsdk:"password"`
SpaceID types.String `tfsdk:"space_id"`
Username types.String `tfsdk:"username"`
+
+ ResourceModel
}
diff --git a/octopusdeploy_framework/schemas/nuget_feed.go b/octopusdeploy_framework/schemas/nuget_feed.go
index a9d5567fb..a744dafb1 100644
--- a/octopusdeploy_framework/schemas/nuget_feed.go
+++ b/octopusdeploy_framework/schemas/nuget_feed.go
@@ -33,11 +33,12 @@ type NugetFeedTypeResourceModel struct {
DownloadAttempts types.Int64 `tfsdk:"download_attempts"`
DownloadRetryBackoffSeconds types.Int64 `tfsdk:"download_retry_backoff_seconds"`
FeedUri types.String `tfsdk:"feed_uri"`
- ID types.String `tfsdk:"id"`
IsEnhancedMode types.Bool `tfsdk:"is_enhanced_mode"`
Name types.String `tfsdk:"name"`
PackageAcquisitionLocationOptions types.List `tfsdk:"package_acquisition_location_options"`
Password types.String `tfsdk:"password"`
SpaceID types.String `tfsdk:"space_id"`
Username types.String `tfsdk:"username"`
+
+ ResourceModel
}
diff --git a/octopusdeploy_framework/schemas/project_group.go b/octopusdeploy_framework/schemas/project_group.go
index 1aaf65d18..bafc5ea42 100644
--- a/octopusdeploy_framework/schemas/project_group.go
+++ b/octopusdeploy_framework/schemas/project_group.go
@@ -43,9 +43,10 @@ func GetProjectGroupResourceSchema() map[string]resourceSchema.Attribute {
}
type ProjectGroupTypeResourceModel struct {
- ID types.String `tfsdk:"id"`
Name types.String `tfsdk:"name"`
SpaceID types.String `tfsdk:"space_id"`
Description types.String `tfsdk:"description"`
RetentionPolicyID types.String `tfsdk:"retention_policy_id"`
+
+ ResourceModel
}
diff --git a/octopusdeploy_framework/schemas/resource.go b/octopusdeploy_framework/schemas/resource.go
new file mode 100644
index 000000000..b97eb5efc
--- /dev/null
+++ b/octopusdeploy_framework/schemas/resource.go
@@ -0,0 +1,19 @@
+package schemas
+
+import (
+ "github.com/hashicorp/terraform-plugin-framework/types"
+)
+
+type IResourceModel interface {
+ GetID() string
+}
+
+type ResourceModel struct {
+ ID types.String `tfsdk:"id"`
+
+ IResourceModel `tfsdk:"-"` // Ignore resource model interface in object conversion
+}
+
+func (r ResourceModel) GetID() string {
+ return r.ID.ValueString()
+}
diff --git a/octopusdeploy_framework/schemas/space.go b/octopusdeploy_framework/schemas/space.go
index c14354752..662a95c96 100644
--- a/octopusdeploy_framework/schemas/space.go
+++ b/octopusdeploy_framework/schemas/space.go
@@ -11,7 +11,6 @@ import (
const spaceDescription = "space"
type SpaceModel struct {
- ID types.String `tfsdk:"id"`
Name types.String `tfsdk:"name"`
Slug types.String `tfsdk:"slug"`
Description types.String `tfsdk:"description"`
@@ -19,6 +18,8 @@ type SpaceModel struct {
SpaceManagersTeams types.Set `tfsdk:"space_managers_teams"`
SpaceManagersTeamMembers types.Set `tfsdk:"space_managers_team_members"`
IsTaskQueueStopped types.Bool `tfsdk:"is_task_queue_stopped"`
+
+ ResourceModel
}
func GetSpaceResourceSchema() map[string]resourceSchema.Attribute {
diff --git a/octopusdeploy_framework/schemas/variable.go b/octopusdeploy_framework/schemas/variable.go
index b3195028b..5d9836e99 100644
--- a/octopusdeploy_framework/schemas/variable.go
+++ b/octopusdeploy_framework/schemas/variable.go
@@ -218,7 +218,6 @@ func GetVariableResourceSchema() resourceSchema.Schema {
}
type VariableTypeResourceModel struct {
- ID types.String `tfsdk:"id"`
Name types.String `tfsdk:"name"`
Description types.String `tfsdk:"description"`
OwnerID types.String `tfsdk:"owner_id"`
@@ -234,6 +233,8 @@ type VariableTypeResourceModel struct {
Prompt types.List `tfsdk:"prompt"`
Scope types.List `tfsdk:"scope"`
SpaceID types.String `tfsdk:"space_id"`
+
+ ResourceModel
}
type VariablesDataSourceModel struct {
@@ -242,11 +243,12 @@ type VariablesDataSourceModel struct {
Scope types.List `tfsdk:"scope"`
SpaceID types.String `tfsdk:"space_id"`
Description types.String `tfsdk:"description"`
- ID types.String `tfsdk:"id"`
IsEditable types.Bool `tfsdk:"is_editable"`
IsSensitive types.Bool `tfsdk:"is_sensitive"`
Prompt types.List `tfsdk:"prompt"`
SensitiveValue types.String `tfsdk:"sensitive_value"`
Type types.String `tfsdk:"type"`
Value types.String `tfsdk:"value"`
+
+ ResourceModel
}
From 7ac25f7e821378b13a78088411332565f665a8d8 Mon Sep 17 00:00:00 2001
From: Isaac Calligeros <101079287+IsaacCalligeros95@users.noreply.github.com>
Date: Fri, 9 Aug 2024 13:29:25 +0930
Subject: [PATCH 06/12] Chore!: Migrate tenant datasource (#699)
* Migrate tenants datasource
* Update previously migrated data source schemas to be read only
---
.../azure_cloud_service_deployment_targets.md | 28 ++---
...rvice_fabric_cluster_deployment_targets.md | 30 ++---
.../azure_web_app_deployment_targets.md | 28 ++---
docs/data-sources/certificates.md | 26 ++---
docs/data-sources/channels.md | 26 ++---
.../cloud_region_deployment_targets.md | 28 ++---
docs/data-sources/deployment_targets.md | 28 ++---
docs/data-sources/environments.md | 20 ++--
docs/data-sources/feeds.md | 23 ++--
docs/data-sources/git_credentials.md | 24 ++--
.../kubernetes_agent_deployment_targets.md | 44 +++----
.../kubernetes_cluster_deployment_targets.md | 56 ++++-----
docs/data-sources/library_variable_sets.md | 14 +--
.../listening_tentacle_deployment_targets.md | 52 ++++-----
docs/data-sources/machine_policies.md | 38 +++----
...offline_package_drop_deployment_targets.md | 32 +++---
.../polling_tentacle_deployment_targets.md | 32 +++---
docs/data-sources/project_groups.md | 19 ++--
docs/data-sources/script_modules | 18 +--
docs/data-sources/script_modules.md | 18 +--
docs/data-sources/space.md | 2 +-
docs/data-sources/spaces.md | 17 +--
.../ssh_connection_deployment_targets.md | 28 ++---
docs/data-sources/tag_sets.md | 14 +--
docs/data-sources/teams.md | 20 ++--
docs/data-sources/tenants.md | 10 +-
docs/data-sources/user_roles.md | 10 +-
docs/data-sources/users.md | 18 +--
docs/data-sources/worker_pools.md | 14 +--
docs/index.md | 5 +-
docs/resources/azure_subscription_account.md | 4 +-
docs/resources/environment.md | 29 +++--
docs/resources/lifecycle.md | 4 +-
docs/resources/nuget_feed.md | 4 +-
docs/resources/space.md | 4 +-
docs/resources/tenant_common_variable.md | 19 ++--
docs/resources/tenant_project.md | 13 +--
go.mod | 2 +-
go.sum | 4 +-
octopusdeploy/data_source_tenants.go | 54 ---------
octopusdeploy/provider.go | 2 -
.../resource_deployment_process_test.go | 1 -
octopusdeploy/testing_container_test.go | 2 +-
.../datasource_environments.go | 4 +-
.../datasource_project_groups.go | 4 +-
octopusdeploy_framework/datasource_spaces.go | 2 +-
octopusdeploy_framework/datasource_tenants.go | 80 +++++++++++++
.../datasource_tenants_test.go | 11 +-
octopusdeploy_framework/framework_provider.go | 3 +-
.../schemas/environment.go | 15 +--
octopusdeploy_framework/schemas/feed.go | 33 +++---
.../schemas/library_variable_set.go | 14 +--
.../schemas/project_group.go | 2 +-
octopusdeploy_framework/schemas/schema.go | 58 ++++++++--
octopusdeploy_framework/schemas/space.go | 23 ++--
octopusdeploy_framework/schemas/tenant.go | 107 ++++++++++++++++++
.../testing_container_test.go | 2 +-
octopusdeploy_framework/util/schema.go | 40 ++++---
58 files changed, 708 insertions(+), 554 deletions(-)
delete mode 100644 octopusdeploy/data_source_tenants.go
create mode 100644 octopusdeploy_framework/datasource_tenants.go
rename octopusdeploy/data_source_tenants_test.go => octopusdeploy_framework/datasource_tenants_test.go (82%)
create mode 100644 octopusdeploy_framework/schemas/tenant.go
diff --git a/docs/data-sources/azure_cloud_service_deployment_targets.md b/docs/data-sources/azure_cloud_service_deployment_targets.md
index 5bd56afb8..c202843d6 100644
--- a/docs/data-sources/azure_cloud_service_deployment_targets.md
+++ b/docs/data-sources/azure_cloud_service_deployment_targets.md
@@ -45,10 +45,10 @@ data "octopusdeploy_azure_cloud_service_deployment_targets" "example" {
### Read-Only
-- `azure_cloud_service_deployment_targets` (Block List) A list of Azure cloud service deployment targets that match the filter(s). (see [below for nested schema](#nestedblock--azure_cloud_service_deployment_targets))
+- `azure_cloud_service_deployment_targets` (List of Object) A list of Azure cloud service deployment targets that match the filter(s). (see [below for nested schema](#nestedatt--azure_cloud_service_deployment_targets))
- `id` (String) An auto-generated identifier that includes the timestamp when this data source was last modified.
-
+
### Nested Schema for `azure_cloud_service_deployment_targets`
Read-Only:
@@ -56,33 +56,33 @@ Read-Only:
- `account_id` (String)
- `cloud_service_name` (String)
- `default_worker_pool_id` (String)
-- `endpoint` (List of Object) (see [below for nested schema](#nestedatt--azure_cloud_service_deployment_targets--endpoint))
-- `environments` (List of String) A list of environment IDs associated with this resource.
+- `endpoint` (List of Object) (see [below for nested schema](#nestedobjatt--azure_cloud_service_deployment_targets--endpoint))
+- `environments` (List of String)
- `has_latest_calamari` (Boolean)
-- `health_status` (String) Represents the health status of this deployment target. Valid health statuses are `HasWarnings`, `Healthy`, `Unavailable`, `Unhealthy`, or `Unknown`.
-- `id` (String) The unique ID for this resource.
+- `health_status` (String)
+- `id` (String)
- `is_disabled` (Boolean)
- `is_in_process` (Boolean)
- `machine_policy_id` (String)
-- `name` (String) The name of this resource.
+- `name` (String)
- `operating_system` (String)
- `roles` (List of String)
- `shell_name` (String)
- `shell_version` (String)
- `slot` (String)
-- `space_id` (String) The space ID associated with this resource.
-- `status` (String) The status of this resource. Valid statuses are `CalamariNeedsUpgrade`, `Disabled`, `NeedsUpgrade`, `Offline`, `Online`, or `Unknown`.
-- `status_summary` (String) A summary elaborating on the status of this resource.
+- `space_id` (String)
+- `status` (String)
+- `status_summary` (String)
- `storage_account_name` (String)
- `swap_if_possible` (Boolean)
-- `tenant_tags` (List of String) A list of tenant tags associated with this resource.
-- `tenanted_deployment_participation` (String) The tenanted deployment mode of the resource. Valid account types are `Untenanted`, `TenantedOrUntenanted`, or `Tenanted`.
-- `tenants` (List of String) A list of tenant IDs associated with this resource.
+- `tenant_tags` (List of String)
+- `tenanted_deployment_participation` (String)
+- `tenants` (List of String)
- `thumbprint` (String)
- `uri` (String)
- `use_current_instance_count` (Boolean)
-
+
### Nested Schema for `azure_cloud_service_deployment_targets.endpoint`
Read-Only:
diff --git a/docs/data-sources/azure_service_fabric_cluster_deployment_targets.md b/docs/data-sources/azure_service_fabric_cluster_deployment_targets.md
index f6aedf261..13a82ca92 100644
--- a/docs/data-sources/azure_service_fabric_cluster_deployment_targets.md
+++ b/docs/data-sources/azure_service_fabric_cluster_deployment_targets.md
@@ -45,47 +45,47 @@ data "octopusdeploy_azure_service_fabric_cluster_deployment_targets" "example" {
### Read-Only
-- `azure_service_fabric_cluster_deployment_targets` (Block List) A list of Azure service fabric cluster deployment targets that match the filter(s). (see [below for nested schema](#nestedblock--azure_service_fabric_cluster_deployment_targets))
+- `azure_service_fabric_cluster_deployment_targets` (List of Object) A list of Azure service fabric cluster deployment targets that match the filter(s). (see [below for nested schema](#nestedatt--azure_service_fabric_cluster_deployment_targets))
- `id` (String) An auto-generated identifier that includes the timestamp when this data source was last modified.
-
+
### Nested Schema for `azure_service_fabric_cluster_deployment_targets`
Read-Only:
- `aad_client_credential_secret` (String)
- `aad_credential_type` (String)
-- `aad_user_credential_password` (String, Sensitive)
+- `aad_user_credential_password` (String)
- `aad_user_credential_username` (String)
- `certificate_store_location` (String)
- `certificate_store_name` (String)
- `client_certificate_variable` (String)
- `connection_endpoint` (String)
-- `endpoint` (List of Object) (see [below for nested schema](#nestedatt--azure_service_fabric_cluster_deployment_targets--endpoint))
-- `environments` (List of String) A list of environment IDs associated with this resource.
+- `endpoint` (List of Object) (see [below for nested schema](#nestedobjatt--azure_service_fabric_cluster_deployment_targets--endpoint))
+- `environments` (List of String)
- `has_latest_calamari` (Boolean)
-- `health_status` (String) Represents the health status of this deployment target. Valid health statuses are `HasWarnings`, `Healthy`, `Unavailable`, `Unhealthy`, or `Unknown`.
-- `id` (String) The unique ID for this resource.
+- `health_status` (String)
+- `id` (String)
- `is_disabled` (Boolean)
- `is_in_process` (Boolean)
- `machine_policy_id` (String)
-- `name` (String) The name of this resource.
+- `name` (String)
- `operating_system` (String)
- `roles` (List of String)
- `security_mode` (String)
- `server_certificate_thumbprint` (String)
- `shell_name` (String)
- `shell_version` (String)
-- `space_id` (String) The space ID associated with this resource.
-- `status` (String) The status of this resource. Valid statuses are `CalamariNeedsUpgrade`, `Disabled`, `NeedsUpgrade`, `Offline`, `Online`, or `Unknown`.
-- `status_summary` (String) A summary elaborating on the status of this resource.
-- `tenant_tags` (List of String) A list of tenant tags associated with this resource.
-- `tenanted_deployment_participation` (String) The tenanted deployment mode of the resource. Valid account types are `Untenanted`, `TenantedOrUntenanted`, or `Tenanted`.
-- `tenants` (List of String) A list of tenant IDs associated with this resource.
+- `space_id` (String)
+- `status` (String)
+- `status_summary` (String)
+- `tenant_tags` (List of String)
+- `tenanted_deployment_participation` (String)
+- `tenants` (List of String)
- `thumbprint` (String)
- `uri` (String)
-
+
### Nested Schema for `azure_service_fabric_cluster_deployment_targets.endpoint`
Read-Only:
diff --git a/docs/data-sources/azure_web_app_deployment_targets.md b/docs/data-sources/azure_web_app_deployment_targets.md
index 26a8b8a06..a5f00dd3d 100644
--- a/docs/data-sources/azure_web_app_deployment_targets.md
+++ b/docs/data-sources/azure_web_app_deployment_targets.md
@@ -45,41 +45,41 @@ data "octopusdeploy_azure_web_app_deployment_targets" "example" {
### Read-Only
-- `azure_web_app_deployment_targets` (Block List) A list of Azure web app deployment targets that match the filter(s). (see [below for nested schema](#nestedblock--azure_web_app_deployment_targets))
+- `azure_web_app_deployment_targets` (List of Object) A list of Azure web app deployment targets that match the filter(s). (see [below for nested schema](#nestedatt--azure_web_app_deployment_targets))
- `id` (String) An auto-generated identifier that includes the timestamp when this data source was last modified.
-
+
### Nested Schema for `azure_web_app_deployment_targets`
Read-Only:
- `account_id` (String)
-- `endpoint` (List of Object) (see [below for nested schema](#nestedatt--azure_web_app_deployment_targets--endpoint))
-- `environments` (List of String) A list of environment IDs associated with this resource.
+- `endpoint` (List of Object) (see [below for nested schema](#nestedobjatt--azure_web_app_deployment_targets--endpoint))
+- `environments` (List of String)
- `has_latest_calamari` (Boolean)
-- `health_status` (String) Represents the health status of this deployment target. Valid health statuses are `HasWarnings`, `Healthy`, `Unavailable`, `Unhealthy`, or `Unknown`.
-- `id` (String) The unique ID for this resource.
+- `health_status` (String)
+- `id` (String)
- `is_disabled` (Boolean)
- `is_in_process` (Boolean)
- `machine_policy_id` (String)
-- `name` (String) The name of this resource.
+- `name` (String)
- `operating_system` (String)
- `resource_group_name` (String)
- `roles` (List of String)
- `shell_name` (String)
- `shell_version` (String)
-- `space_id` (String) The space ID associated with this resource.
-- `status` (String) The status of this resource. Valid statuses are `CalamariNeedsUpgrade`, `Disabled`, `NeedsUpgrade`, `Offline`, `Online`, or `Unknown`.
-- `status_summary` (String) A summary elaborating on the status of this resource.
-- `tenant_tags` (List of String) A list of tenant tags associated with this resource.
-- `tenanted_deployment_participation` (String) The tenanted deployment mode of the resource. Valid account types are `Untenanted`, `TenantedOrUntenanted`, or `Tenanted`.
-- `tenants` (List of String) A list of tenant IDs associated with this resource.
+- `space_id` (String)
+- `status` (String)
+- `status_summary` (String)
+- `tenant_tags` (List of String)
+- `tenanted_deployment_participation` (String)
+- `tenants` (List of String)
- `thumbprint` (String)
- `uri` (String)
- `web_app_name` (String)
- `web_app_slot_name` (String)
-
+
### Nested Schema for `azure_web_app_deployment_targets.endpoint`
Read-Only:
diff --git a/docs/data-sources/certificates.md b/docs/data-sources/certificates.md
index 9ba533b85..a62462d0b 100644
--- a/docs/data-sources/certificates.md
+++ b/docs/data-sources/certificates.md
@@ -40,29 +40,29 @@ data "octopusdeploy_certificates" "example" {
### Read-Only
-- `certificates` (Block List) A list of certificates that match the filter(s). (see [below for nested schema](#nestedblock--certificates))
+- `certificates` (List of Object) A list of certificates that match the filter(s). (see [below for nested schema](#nestedatt--certificates))
- `id` (String) An auto-generated identifier that includes the timestamp when this data source was last modified.
-
+
### Nested Schema for `certificates`
Read-Only:
- `archived` (String)
-- `certificate_data` (String, Sensitive) The encoded data of the certificate.
-- `certificate_data_format` (String) Specifies the archive file format used for storing cryptography objects in the certificate. Valid formats are `Der`, `Pem`, `Pkcs12`, or `Unknown`.
-- `environments` (List of String) A list of environment IDs associated with this resource.
-- `has_private_key` (Boolean) Indicates if the certificate has a private key.
-- `id` (String) The unique ID for this resource.
-- `is_expired` (Boolean) Indicates if the certificate has expired.
+- `certificate_data` (String)
+- `certificate_data_format` (String)
+- `environments` (List of String)
+- `has_private_key` (Boolean)
+- `id` (String)
+- `is_expired` (Boolean)
- `issuer_common_name` (String)
- `issuer_distinguished_name` (String)
- `issuer_organization` (String)
-- `name` (String) The name of this resource.
+- `name` (String)
- `not_after` (String)
- `not_before` (String)
- `notes` (String)
-- `password` (String, Sensitive) The password associated with this resource.
+- `password` (String)
- `replaced_by` (String)
- `self_signed` (Boolean)
- `serial_number` (String)
@@ -72,9 +72,9 @@ Read-Only:
- `subject_common_name` (String)
- `subject_distinguished_name` (String)
- `subject_organization` (String)
-- `tenant_tags` (List of String) A list of tenant tags associated with this resource.
-- `tenanted_deployment_participation` (String) The tenanted deployment mode of the resource. Valid account types are `Untenanted`, `TenantedOrUntenanted`, or `Tenanted`.
-- `tenants` (List of String) A list of tenant IDs associated with this resource.
+- `tenant_tags` (List of String)
+- `tenanted_deployment_participation` (String)
+- `tenants` (List of String)
- `thumbprint` (String)
- `version` (Number)
diff --git a/docs/data-sources/channels.md b/docs/data-sources/channels.md
index bf1546f4f..b19b11d00 100644
--- a/docs/data-sources/channels.md
+++ b/docs/data-sources/channels.md
@@ -34,25 +34,25 @@ data "octopusdeploy_channels" "example" {
### Read-Only
-- `channels` (Block List) A channel that matches the specified filter(s). (see [below for nested schema](#nestedblock--channels))
+- `channels` (List of Object) A channel that matches the specified filter(s). (see [below for nested schema](#nestedatt--channels))
- `id` (String) The ID of this resource.
-
+
### Nested Schema for `channels`
Read-Only:
-- `description` (String) The description of this channel.
-- `id` (String) The unique ID for this resource.
-- `is_default` (Boolean) Indicates if this is the default channel for the associated project.
-- `lifecycle_id` (String) The lifecycle ID associated with this channel.
-- `name` (String) The name of this resource.
-- `project_id` (String) The project ID associated with this channel.
-- `rule` (List of Object) A list of rules associated with this channel. (see [below for nested schema](#nestedatt--channels--rule))
-- `space_id` (String) The space ID associated with this resource.
-- `tenant_tags` (List of String) A list of tenant tags associated with this resource.
-
-
+- `description` (String)
+- `id` (String)
+- `is_default` (Boolean)
+- `lifecycle_id` (String)
+- `name` (String)
+- `project_id` (String)
+- `rule` (List of Object) (see [below for nested schema](#nestedobjatt--channels--rule))
+- `space_id` (String)
+- `tenant_tags` (List of String)
+
+
### Nested Schema for `channels.rule`
Read-Only:
diff --git a/docs/data-sources/cloud_region_deployment_targets.md b/docs/data-sources/cloud_region_deployment_targets.md
index 79adef44b..8818118d5 100644
--- a/docs/data-sources/cloud_region_deployment_targets.md
+++ b/docs/data-sources/cloud_region_deployment_targets.md
@@ -46,38 +46,38 @@ data "octopusdeploy_cloud_region_deployment_targets" "example" {
### Read-Only
-- `cloud_region_deployment_targets` (Block List) A list of cloud region deployment targets that match the filter(s). (see [below for nested schema](#nestedblock--cloud_region_deployment_targets))
+- `cloud_region_deployment_targets` (List of Object) A list of cloud region deployment targets that match the filter(s). (see [below for nested schema](#nestedatt--cloud_region_deployment_targets))
- `id` (String) An auto-generated identifier that includes the timestamp when this data source was last modified.
-
+
### Nested Schema for `cloud_region_deployment_targets`
Read-Only:
- `default_worker_pool_id` (String)
-- `endpoint` (List of Object) (see [below for nested schema](#nestedatt--cloud_region_deployment_targets--endpoint))
-- `environments` (List of String) A list of environment IDs associated with this resource.
+- `endpoint` (List of Object) (see [below for nested schema](#nestedobjatt--cloud_region_deployment_targets--endpoint))
+- `environments` (List of String)
- `has_latest_calamari` (Boolean)
-- `health_status` (String) Represents the health status of this deployment target. Valid health statuses are `HasWarnings`, `Healthy`, `Unavailable`, `Unhealthy`, or `Unknown`.
-- `id` (String) The unique ID for this resource.
+- `health_status` (String)
+- `id` (String)
- `is_disabled` (Boolean)
- `is_in_process` (Boolean)
- `machine_policy_id` (String)
-- `name` (String) The name of this resource.
+- `name` (String)
- `operating_system` (String)
- `roles` (List of String)
- `shell_name` (String)
- `shell_version` (String)
-- `space_id` (String) The space ID associated with this resource.
-- `status` (String) The status of this resource. Valid statuses are `CalamariNeedsUpgrade`, `Disabled`, `NeedsUpgrade`, `Offline`, `Online`, or `Unknown`.
-- `status_summary` (String) A summary elaborating on the status of this resource.
-- `tenant_tags` (List of String) A list of tenant tags associated with this resource.
-- `tenanted_deployment_participation` (String) The tenanted deployment mode of the resource. Valid account types are `Untenanted`, `TenantedOrUntenanted`, or `Tenanted`.
-- `tenants` (List of String) A list of tenant IDs associated with this resource.
+- `space_id` (String)
+- `status` (String)
+- `status_summary` (String)
+- `tenant_tags` (List of String)
+- `tenanted_deployment_participation` (String)
+- `tenants` (List of String)
- `thumbprint` (String)
- `uri` (String)
-
+
### Nested Schema for `cloud_region_deployment_targets.endpoint`
Read-Only:
diff --git a/docs/data-sources/deployment_targets.md b/docs/data-sources/deployment_targets.md
index 4677decd0..50a12ed38 100644
--- a/docs/data-sources/deployment_targets.md
+++ b/docs/data-sources/deployment_targets.md
@@ -36,37 +36,37 @@ Provides information about existing deployment targets.
### Read-Only
-- `deployment_targets` (Block List) A list of deployment targets that match the filter(s). (see [below for nested schema](#nestedblock--deployment_targets))
+- `deployment_targets` (List of Object) A list of deployment targets that match the filter(s). (see [below for nested schema](#nestedatt--deployment_targets))
- `id` (String) The ID of this resource.
-
+
### Nested Schema for `deployment_targets`
Read-Only:
-- `endpoint` (List of Object) (see [below for nested schema](#nestedatt--deployment_targets--endpoint))
-- `environments` (List of String) A list of environment IDs associated with this resource.
+- `endpoint` (List of Object) (see [below for nested schema](#nestedobjatt--deployment_targets--endpoint))
+- `environments` (List of String)
- `has_latest_calamari` (Boolean)
-- `health_status` (String) Represents the health status of this deployment target. Valid health statuses are `HasWarnings`, `Healthy`, `Unavailable`, `Unhealthy`, or `Unknown`.
-- `id` (String) The unique ID for this resource.
+- `health_status` (String)
+- `id` (String)
- `is_disabled` (Boolean)
- `is_in_process` (Boolean)
- `machine_policy_id` (String)
-- `name` (String) The name of this resource.
+- `name` (String)
- `operating_system` (String)
- `roles` (List of String)
- `shell_name` (String)
- `shell_version` (String)
-- `space_id` (String) The space ID associated with this resource.
-- `status` (String) The status of this resource. Valid statuses are `CalamariNeedsUpgrade`, `Disabled`, `NeedsUpgrade`, `Offline`, `Online`, or `Unknown`.
-- `status_summary` (String) A summary elaborating on the status of this resource.
-- `tenant_tags` (List of String) A list of tenant tags associated with this resource.
-- `tenanted_deployment_participation` (String) The tenanted deployment mode of the resource. Valid account types are `Untenanted`, `TenantedOrUntenanted`, or `Tenanted`.
-- `tenants` (List of String) A list of tenant IDs associated with this resource.
+- `space_id` (String)
+- `status` (String)
+- `status_summary` (String)
+- `tenant_tags` (List of String)
+- `tenanted_deployment_participation` (String)
+- `tenants` (List of String)
- `thumbprint` (String)
- `uri` (String)
-
+
### Nested Schema for `deployment_targets.endpoint`
Read-Only:
diff --git a/docs/data-sources/environments.md b/docs/data-sources/environments.md
index 69bc1ab23..d67c25219 100644
--- a/docs/data-sources/environments.md
+++ b/docs/data-sources/environments.md
@@ -28,16 +28,16 @@ data "octopusdeploy_environments" "example" {
### Optional
- `ids` (List of String) A filter to search by a list of IDs.
-- `name` (String) A filter to search by name.
-- `partial_name` (String) A filter to search by the partial match of a name.
+- `name` (String) A filter search by exact name
+- `partial_name` (String) A filter to search by a partial name.
- `skip` (Number) A filter to specify the number of items to skip in the response.
-- `space_id` (String) The space ID associated with this resource.
+- `space_id` (String) The space ID associated with this environment.
- `take` (Number) A filter to specify the number of items to take (or return) in the response.
### Read-Only
-- `environments` (Block List) A list of environments that match the filter(s). (see [below for nested schema](#nestedblock--environments))
-- `id` (String) An auto-generated identifier that includes the timestamp when this data source was last modified.
+- `environments` (Block List) Provides information about existing environments. (see [below for nested schema](#nestedblock--environments))
+- `id` (String) The unique ID for this resource.
### Nested Schema for `environments`
@@ -47,12 +47,12 @@ Read-Only:
- `allow_dynamic_infrastructure` (Boolean)
- `description` (String) The description of this environment.
- `id` (String) The unique ID for this resource.
-- `jira_extension_settings` (List of Object) Provides extension settings for the Jira integration for this environment. (see [below for nested schema](#nestedatt--environments--jira_extension_settings))
-- `jira_service_management_extension_settings` (List of Object) Provides extension settings for the Jira Service Management (JSM) integration for this environment. (see [below for nested schema](#nestedatt--environments--jira_service_management_extension_settings))
+- `jira_extension_settings` (Attributes List) Provides extension settings for the Jira integration for this environment. (see [below for nested schema](#nestedatt--environments--jira_extension_settings))
+- `jira_service_management_extension_settings` (Attributes List) Provides extension settings for the Jira Service Management (JSM) integration for this environment. (see [below for nested schema](#nestedatt--environments--jira_service_management_extension_settings))
- `name` (String) The name of this resource.
-- `servicenow_extension_settings` (List of Object) Provides extension settings for the ServiceNow integration for this environment. (see [below for nested schema](#nestedatt--environments--servicenow_extension_settings))
-- `slug` (String)
-- `sort_order` (Number) The order number to sort an environment.
+- `servicenow_extension_settings` (Attributes List) Provides extension settings for the ServiceNow integration for this environment. (see [below for nested schema](#nestedatt--environments--servicenow_extension_settings))
+- `slug` (String) The unique slug of this environment
+- `sort_order` (Number) The order number to sort an environment
- `space_id` (String) The space ID associated with this environment.
- `use_guided_failure` (Boolean)
diff --git a/docs/data-sources/feeds.md b/docs/data-sources/feeds.md
index 91fde3c96..7afdb726d 100644
--- a/docs/data-sources/feeds.md
+++ b/docs/data-sources/feeds.md
@@ -27,8 +27,6 @@ data "octopusdeploy_feeds" "example" {
### Optional
- `feed_type` (String) A filter to search by feed type. Valid feed types are `AwsElasticContainerRegistry`, `BuiltIn`, `Docker`, `GitHub`, `Helm`, `Maven`, `NuGet`, or `OctopusProject`.
-- `feeds` (Block List) (see [below for nested schema](#nestedblock--feeds))
-- `id` (String) The unique ID for this resource.
- `ids` (List of String) A filter to search by a list of IDs.
- `name` (String) The name of this resource.
- `partial_name` (String) A filter to search by a partial name.
@@ -36,31 +34,30 @@ data "octopusdeploy_feeds" "example" {
- `space_id` (String) The space ID associated with this feeds.
- `take` (Number) A filter to specify the number of items to take (or return) in the response.
+### Read-Only
+
+- `feeds` (Block List) (see [below for nested schema](#nestedblock--feeds))
+- `id` (String) The unique ID for this resource.
+
### Nested Schema for `feeds`
-Required:
+Read-Only:
- `access_key` (String) The AWS access key to use when authenticating against Amazon Web Services.
-- `feed_uri` (String)
-- `name` (String) The name of this resource.
-
-Optional:
-
- `api_version` (String)
- `delete_unreleased_packages_after_days` (Number)
- `download_attempts` (Number) The number of times a deployment should attempt to download a package from this feed before failing.
- `download_retry_backoff_seconds` (Number) The number of seconds to apply as a linear back off between download attempts.
- `feed_type` (String) A filter to search by feed type. Valid feed types are `AwsElasticContainerRegistry`, `BuiltIn`, `Docker`, `GitHub`, `Helm`, `Maven`, `NuGet`, or `OctopusProject`.
+- `feed_uri` (String)
- `id` (String) The unique ID for this resource.
- `is_enhanced_mode` (Boolean)
+- `name` (String) The name of this resource.
- `package_acquisition_location_options` (List of String)
- `password` (String, Sensitive) The password associated with this resource.
+- `region` (String)
- `registry_path` (String)
- `secret_key` (String, Sensitive)
- `space_id` (String) The space ID associated with this feeds.
-- `username` (String, Sensitive) The username associated with this resource.
-
-Read-Only:
-
-- `region` (String)
\ No newline at end of file
+- `username` (String, Sensitive) The username associated with this resource.
\ No newline at end of file
diff --git a/docs/data-sources/git_credentials.md b/docs/data-sources/git_credentials.md
index d5e0820a4..e7a4a3c4d 100644
--- a/docs/data-sources/git_credentials.md
+++ b/docs/data-sources/git_credentials.md
@@ -3,12 +3,12 @@
page_title: "octopusdeploy_git_credentials Data Source - terraform-provider-octopusdeploy"
subcategory: ""
description: |-
- Provides information about existing GitCredentials.
+ Use this data source to retrieve information about Git credentials in Octopus Deploy.
---
# octopusdeploy_git_credentials (Data Source)
-Provides information about existing GitCredentials.
+Use this data source to retrieve information about Git credentials in Octopus Deploy.
@@ -17,26 +17,26 @@ Provides information about existing GitCredentials.
### Optional
-- `name` (String) A filter to search by name.
-- `skip` (Number) A filter to specify the number of items to skip in the response.
-- `space_id` (String) The space ID associated with this resource.
-- `take` (Number) A filter to specify the number of items to take (or return) in the response.
+- `name` (String) The name of the Git Credential to filter by.
+- `skip` (Number) The number of records to skip.
+- `space_id` (String) The space ID associated with this Git Credential.
+- `take` (Number) The number of records to take.
### Read-Only
-- `git_credentials` (Block List) A list of Git Credentials that match the filter(s). (see [below for nested schema](#nestedblock--git_credentials))
-- `id` (String) The ID of this resource.
+- `git_credentials` (Attributes List) Provides information about existing GitCredentials. (see [below for nested schema](#nestedatt--git_credentials))
+- `id` (String) The unique ID for this resource.
-
+
### Nested Schema for `git_credentials`
Read-Only:
-- `description` (String) The description of this Git credential.
+- `description` (String) The description of this Git Credential.
- `id` (String) The unique ID for this resource.
-- `name` (String) The name of the Git credential. This name must be unique.
+- `name` (String) The name of this Git Credential.
- `password` (String, Sensitive) The password for the Git credential.
-- `space_id` (String) The space ID associated with this resource.
+- `space_id` (String) The space ID associated with this Git Credential.
- `type` (String) The Git credential authentication type.
- `username` (String) The username for the Git credential.
diff --git a/docs/data-sources/kubernetes_agent_deployment_targets.md b/docs/data-sources/kubernetes_agent_deployment_targets.md
index 527adad4a..dd4c61884 100644
--- a/docs/data-sources/kubernetes_agent_deployment_targets.md
+++ b/docs/data-sources/kubernetes_agent_deployment_targets.md
@@ -55,32 +55,32 @@ data "octopusdeploy_kubernetes_agent_deployment_targets" "kubernetes_agent_deplo
### Read-Only
- `id` (String) An auto-generated identifier that includes the timestamp when this data source was last modified.
-- `kubernetes_agent_deployment_targets` (Block List) A list of kubernetes agent deployment targets that match the filter(s). (see [below for nested schema](#nestedblock--kubernetes_agent_deployment_targets))
+- `kubernetes_agent_deployment_targets` (List of Object) A list of kubernetes agent deployment targets that match the filter(s). (see [below for nested schema](#nestedatt--kubernetes_agent_deployment_targets))
-
+
### Nested Schema for `kubernetes_agent_deployment_targets`
Read-Only:
-- `agent_helm_release_name` (String) Name of the Helm release that the agent belongs to.
-- `agent_kubernetes_namespace` (String) Name of the Kubernetes namespace where the agent is installed.
-- `agent_tentacle_version` (String) Current Tentacle version of the agent
-- `agent_upgrade_status` (String) Current upgrade availability status of the agent. One of 'NoUpgrades', 'UpgradeAvailable', 'UpgradeSuggested', 'UpgradeRequired'
-- `agent_version` (String) Current Helm chart version of the agent.
-- `communication_mode` (String) The communication mode used by the Kubernetes agent to communicate with Octopus Server. Currently, the only supported value is 'Polling'.
-- `default_namespace` (String) Optional default namespace that will be used when using Kubernetes deployment steps, can be overrides within step configurations.
-- `environments` (List of String) A list of environment IDs this Kubernetes agent can deploy to.
-- `id` (String) The unique ID for this resource.
-- `is_disabled` (Boolean) Whether the Kubernetes agent is disabled. If the agent is disabled, it will not be included in any deployments.
-- `machine_policy_id` (String) Optional ID of the machine policy that the Kubernetes agent will use. If not provided the default machine policy will be used.
-- `name` (String) The name of this resource.
-- `roles` (List of String) A list of target roles that are associated to this Kubernetes agent.
-- `space_id` (String) The space ID associated with this resource.
-- `tenant_tags` (List of String) A list of tenant tags associated with this resource.
-- `tenanted_deployment_participation` (String) The tenanted deployment mode of the resource. Valid account types are `Untenanted`, `TenantedOrUntenanted`, or `Tenanted`.
-- `tenants` (List of String) A list of tenant IDs associated with this resource.
-- `thumbprint` (String) The thumbprint of the Kubernetes agent's certificate used by server to verify the identity of the agent. This is the same thumbprint that was used when installing the agent.
-- `upgrade_locked` (Boolean) If enabled the Kubernetes agent will not automatically upgrade and will stay on the currently installed version, even if the associated machine policy is configured to automatically upgrade.
-- `uri` (String) The URI of the Kubernetes agent's used by the server to queue messages. This is the same subscription uri that was used when installing the agent.
+- `agent_helm_release_name` (String)
+- `agent_kubernetes_namespace` (String)
+- `agent_tentacle_version` (String)
+- `agent_upgrade_status` (String)
+- `agent_version` (String)
+- `communication_mode` (String)
+- `default_namespace` (String)
+- `environments` (List of String)
+- `id` (String)
+- `is_disabled` (Boolean)
+- `machine_policy_id` (String)
+- `name` (String)
+- `roles` (List of String)
+- `space_id` (String)
+- `tenant_tags` (List of String)
+- `tenanted_deployment_participation` (String)
+- `tenants` (List of String)
+- `thumbprint` (String)
+- `upgrade_locked` (Boolean)
+- `uri` (String)
diff --git a/docs/data-sources/kubernetes_cluster_deployment_targets.md b/docs/data-sources/kubernetes_cluster_deployment_targets.md
index 4bf178018..7b7da7741 100644
--- a/docs/data-sources/kubernetes_cluster_deployment_targets.md
+++ b/docs/data-sources/kubernetes_cluster_deployment_targets.md
@@ -36,52 +36,52 @@ Provides information about existing Kubernetes cluster deployment targets.
### Read-Only
- `id` (String) An auto-generated identifier that includes the timestamp when this data source was last modified.
-- `kubernetes_cluster_deployment_targets` (Block List) A list of Kubernetes cluster deployment targets that match the filter(s). (see [below for nested schema](#nestedblock--kubernetes_cluster_deployment_targets))
+- `kubernetes_cluster_deployment_targets` (List of Object) A list of Kubernetes cluster deployment targets that match the filter(s). (see [below for nested schema](#nestedatt--kubernetes_cluster_deployment_targets))
-
+
### Nested Schema for `kubernetes_cluster_deployment_targets`
Read-Only:
-- `authentication` (List of Object) (see [below for nested schema](#nestedatt--kubernetes_cluster_deployment_targets--authentication))
-- `aws_account_authentication` (List of Object) (see [below for nested schema](#nestedatt--kubernetes_cluster_deployment_targets--aws_account_authentication))
-- `azure_service_principal_authentication` (List of Object) (see [below for nested schema](#nestedatt--kubernetes_cluster_deployment_targets--azure_service_principal_authentication))
-- `certificate_authentication` (List of Object) (see [below for nested schema](#nestedatt--kubernetes_cluster_deployment_targets--certificate_authentication))
+- `authentication` (List of Object) (see [below for nested schema](#nestedobjatt--kubernetes_cluster_deployment_targets--authentication))
+- `aws_account_authentication` (List of Object) (see [below for nested schema](#nestedobjatt--kubernetes_cluster_deployment_targets--aws_account_authentication))
+- `azure_service_principal_authentication` (List of Object) (see [below for nested schema](#nestedobjatt--kubernetes_cluster_deployment_targets--azure_service_principal_authentication))
+- `certificate_authentication` (List of Object) (see [below for nested schema](#nestedobjatt--kubernetes_cluster_deployment_targets--certificate_authentication))
- `cluster_certificate` (String)
- `cluster_certificate_path` (String)
- `cluster_url` (String)
-- `container` (List of Object) (see [below for nested schema](#nestedatt--kubernetes_cluster_deployment_targets--container))
+- `container` (List of Object) (see [below for nested schema](#nestedobjatt--kubernetes_cluster_deployment_targets--container))
- `container_options` (String)
- `default_worker_pool_id` (String)
-- `endpoint` (List of Object) (see [below for nested schema](#nestedatt--kubernetes_cluster_deployment_targets--endpoint))
-- `environments` (List of String) A list of environment IDs associated with this resource.
-- `gcp_account_authentication` (List of Object) (see [below for nested schema](#nestedatt--kubernetes_cluster_deployment_targets--gcp_account_authentication))
+- `endpoint` (List of Object) (see [below for nested schema](#nestedobjatt--kubernetes_cluster_deployment_targets--endpoint))
+- `environments` (List of String)
+- `gcp_account_authentication` (List of Object) (see [below for nested schema](#nestedobjatt--kubernetes_cluster_deployment_targets--gcp_account_authentication))
- `has_latest_calamari` (Boolean)
-- `health_status` (String) Represents the health status of this deployment target. Valid health statuses are `HasWarnings`, `Healthy`, `Unavailable`, `Unhealthy`, or `Unknown`.
-- `id` (String) The unique ID for this resource.
+- `health_status` (String)
+- `id` (String)
- `is_disabled` (Boolean)
- `is_in_process` (Boolean)
- `machine_policy_id` (String)
-- `name` (String) The name of this resource.
+- `name` (String)
- `namespace` (String)
- `operating_system` (String)
-- `pod_authentication` (List of Object) (see [below for nested schema](#nestedatt--kubernetes_cluster_deployment_targets--pod_authentication))
+- `pod_authentication` (List of Object) (see [below for nested schema](#nestedobjatt--kubernetes_cluster_deployment_targets--pod_authentication))
- `proxy_id` (String)
- `roles` (List of String)
- `running_in_container` (Boolean)
- `shell_name` (String)
- `shell_version` (String)
- `skip_tls_verification` (Boolean)
-- `space_id` (String) The space ID associated with this resource.
-- `status` (String) The status of this resource. Valid statuses are `CalamariNeedsUpgrade`, `Disabled`, `NeedsUpgrade`, `Offline`, `Online`, or `Unknown`.
-- `status_summary` (String) A summary elaborating on the status of this resource.
-- `tenant_tags` (List of String) A list of tenant tags associated with this resource.
-- `tenanted_deployment_participation` (String) The tenanted deployment mode of the resource. Valid account types are `Untenanted`, `TenantedOrUntenanted`, or `Tenanted`.
-- `tenants` (List of String) A list of tenant IDs associated with this resource.
+- `space_id` (String)
+- `status` (String)
+- `status_summary` (String)
+- `tenant_tags` (List of String)
+- `tenanted_deployment_participation` (String)
+- `tenants` (List of String)
- `thumbprint` (String)
- `uri` (String)
-
+
### Nested Schema for `kubernetes_cluster_deployment_targets.authentication`
Read-Only:
@@ -89,7 +89,7 @@ Read-Only:
- `account_id` (String)
-
+
### Nested Schema for `kubernetes_cluster_deployment_targets.aws_account_authentication`
Read-Only:
@@ -104,7 +104,7 @@ Read-Only:
- `use_instance_role` (Boolean)
-
+
### Nested Schema for `kubernetes_cluster_deployment_targets.azure_service_principal_authentication`
Read-Only:
@@ -114,7 +114,7 @@ Read-Only:
- `cluster_resource_group` (String)
-
+
### Nested Schema for `kubernetes_cluster_deployment_targets.certificate_authentication`
Read-Only:
@@ -122,7 +122,7 @@ Read-Only:
- `client_certificate` (String)
-
+
### Nested Schema for `kubernetes_cluster_deployment_targets.container`
Read-Only:
@@ -131,7 +131,7 @@ Read-Only:
- `image` (String)
-
+
### Nested Schema for `kubernetes_cluster_deployment_targets.endpoint`
Read-Only:
@@ -235,7 +235,7 @@ Read-Only:
-
+
### Nested Schema for `kubernetes_cluster_deployment_targets.gcp_account_authentication`
Read-Only:
@@ -250,7 +250,7 @@ Read-Only:
- `zone` (String)
-
+
### Nested Schema for `kubernetes_cluster_deployment_targets.pod_authentication`
Read-Only:
diff --git a/docs/data-sources/library_variable_sets.md b/docs/data-sources/library_variable_sets.md
index 8b6eeb19f..9b10353eb 100644
--- a/docs/data-sources/library_variable_sets.md
+++ b/docs/data-sources/library_variable_sets.md
@@ -18,34 +18,34 @@ Provides information about existing library variable sets.
### Optional
- `content_type` (String) A filter to search by content type.
-- `id` (String) The unique ID for this resource.
- `ids` (List of String) A filter to search by a list of IDs.
-- `library_variable_sets` (Block List) A list of library variable sets that match the filter(s). (see [below for nested schema](#nestedblock--library_variable_sets))
- `partial_name` (String) A filter to search by a partial name.
- `skip` (Number) A filter to specify the number of items to skip in the response.
- `space_id` (String) The space ID associated with this library variable set.
- `take` (Number) A filter to specify the number of items to take (or return) in the response.
+### Read-Only
+
+- `id` (String) The unique ID for this resource.
+- `library_variable_sets` (Block List) A list of library variable sets that match the filter(s). (see [below for nested schema](#nestedblock--library_variable_sets))
+
### Nested Schema for `library_variable_sets`
-Optional:
+Read-Only:
- `description` (String) The description of this library variable set.
- `id` (String) The unique ID for this resource.
- `name` (String) The name of this resource.
- `space_id` (String) The space ID associated with this library variable set.
- `template` (List of Object) (see [below for nested schema](#nestedatt--library_variable_sets--template))
-
-Read-Only:
-
- `template_ids` (Map of String)
- `variable_set_id` (String)
### Nested Schema for `library_variable_sets.template`
-Optional:
+Read-Only:
- `default_value` (String)
- `display_settings` (Map of String)
diff --git a/docs/data-sources/listening_tentacle_deployment_targets.md b/docs/data-sources/listening_tentacle_deployment_targets.md
index e8f7ccb8f..c90c679f0 100644
--- a/docs/data-sources/listening_tentacle_deployment_targets.md
+++ b/docs/data-sources/listening_tentacle_deployment_targets.md
@@ -55,39 +55,39 @@ data "octopusdeploy_listening_tentacle_deployment_targets" "listening_tentacle_d
### Read-Only
- `id` (String) An auto-generated identifier that includes the timestamp when this data source was last modified.
-- `listening_tentacle_deployment_targets` (Block List) A list of listening tentacle deployment targets that match the filter(s). (see [below for nested schema](#nestedblock--listening_tentacle_deployment_targets))
+- `listening_tentacle_deployment_targets` (List of Object) A list of listening tentacle deployment targets that match the filter(s). (see [below for nested schema](#nestedatt--listening_tentacle_deployment_targets))
-
+
### Nested Schema for `listening_tentacle_deployment_targets`
Read-Only:
- `certificate_signature_algorithm` (String)
-- `environments` (List of String) A list of environment IDs associated with this listening tentacle.
+- `environments` (List of String)
- `has_latest_calamari` (Boolean)
-- `health_status` (String) Represents the health status of this deployment target. Valid health statuses are `HasWarnings`, `Healthy`, `Unavailable`, `Unhealthy`, or `Unknown`.
-- `id` (String) The unique ID for this resource.
-- `is_disabled` (Boolean) Represents the disabled status of this deployment target.
-- `is_in_process` (Boolean) Represents the in-process status of this deployment target.
-- `machine_policy_id` (String) The machine policy ID that is associated with this deployment target.
-- `name` (String) The name of this resource.
-- `operating_system` (String) The operating system that is associated with this deployment target.
-- `proxy_id` (String) The proxy ID that is associated with this deployment target.
-- `roles` (List of String) A list of role IDs that are associated with this deployment target.
-- `shell_name` (String) The shell name associated with this deployment target.
-- `shell_version` (String) The shell version associated with this deployment target.
-- `space_id` (String) The space ID associated with this resource.
-- `status` (String) The status of this resource. Valid statuses are `CalamariNeedsUpgrade`, `Disabled`, `NeedsUpgrade`, `Offline`, `Online`, or `Unknown`.
-- `status_summary` (String) A summary elaborating on the status of this resource.
-- `tenant_tags` (List of String) A list of tenant tags associated with this resource.
-- `tenanted_deployment_participation` (String) The tenanted deployment mode of the resource. Valid account types are `Untenanted`, `TenantedOrUntenanted`, or `Tenanted`.
-- `tenants` (List of String) A list of tenant IDs associated with this resource.
-- `tentacle_url` (String) The tenant URL of this deployment target.
-- `tentacle_version_details` (List of Object) (see [below for nested schema](#nestedatt--listening_tentacle_deployment_targets--tentacle_version_details))
-- `thumbprint` (String) The thumbprint of this deployment target.
-- `uri` (String) The URI of this deployment target.
-
-
+- `health_status` (String)
+- `id` (String)
+- `is_disabled` (Boolean)
+- `is_in_process` (Boolean)
+- `machine_policy_id` (String)
+- `name` (String)
+- `operating_system` (String)
+- `proxy_id` (String)
+- `roles` (List of String)
+- `shell_name` (String)
+- `shell_version` (String)
+- `space_id` (String)
+- `status` (String)
+- `status_summary` (String)
+- `tenant_tags` (List of String)
+- `tenanted_deployment_participation` (String)
+- `tenants` (List of String)
+- `tentacle_url` (String)
+- `tentacle_version_details` (List of Object) (see [below for nested schema](#nestedobjatt--listening_tentacle_deployment_targets--tentacle_version_details))
+- `thumbprint` (String)
+- `uri` (String)
+
+
### Nested Schema for `listening_tentacle_deployment_targets.tentacle_version_details`
Read-Only:
diff --git a/docs/data-sources/machine_policies.md b/docs/data-sources/machine_policies.md
index 68e70b324..614a9a02e 100644
--- a/docs/data-sources/machine_policies.md
+++ b/docs/data-sources/machine_policies.md
@@ -26,29 +26,29 @@ Provides information about existing machine policies.
### Read-Only
- `id` (String) The ID of this resource.
-- `machine_policies` (Block List) A list of machine policies that match the filter(s). (see [below for nested schema](#nestedblock--machine_policies))
+- `machine_policies` (List of Object) A list of machine policies that match the filter(s). (see [below for nested schema](#nestedatt--machine_policies))
-
+
### Nested Schema for `machine_policies`
Read-Only:
-- `connection_connect_timeout` (Number) In nanoseconds. Minimum value: 10000000000 (10 seconds).
+- `connection_connect_timeout` (Number)
- `connection_retry_count_limit` (Number)
-- `connection_retry_sleep_interval` (Number) In nanoseconds.
-- `connection_retry_time_limit` (Number) In nanoseconds.
-- `description` (String) The description of this machine policy.
-- `id` (String) The unique ID for this resource.
+- `connection_retry_sleep_interval` (Number)
+- `connection_retry_time_limit` (Number)
+- `description` (String)
+- `id` (String)
- `is_default` (Boolean)
-- `machine_cleanup_policy` (Set of Object) (see [below for nested schema](#nestedatt--machine_policies--machine_cleanup_policy))
-- `machine_connectivity_policy` (Set of Object) (see [below for nested schema](#nestedatt--machine_policies--machine_connectivity_policy))
-- `machine_health_check_policy` (Set of Object) (see [below for nested schema](#nestedatt--machine_policies--machine_health_check_policy))
-- `machine_update_policy` (Set of Object) (see [below for nested schema](#nestedatt--machine_policies--machine_update_policy))
-- `name` (String) The name of this resource.
-- `polling_request_queue_timeout` (Number) In nanoseconds.
-- `space_id` (String) The space ID associated with this resource.
-
-
+- `machine_cleanup_policy` (Set of Object) (see [below for nested schema](#nestedobjatt--machine_policies--machine_cleanup_policy))
+- `machine_connectivity_policy` (Set of Object) (see [below for nested schema](#nestedobjatt--machine_policies--machine_connectivity_policy))
+- `machine_health_check_policy` (Set of Object) (see [below for nested schema](#nestedobjatt--machine_policies--machine_health_check_policy))
+- `machine_update_policy` (Set of Object) (see [below for nested schema](#nestedobjatt--machine_policies--machine_update_policy))
+- `name` (String)
+- `polling_request_queue_timeout` (Number)
+- `space_id` (String)
+
+
### Nested Schema for `machine_policies.machine_cleanup_policy`
Read-Only:
@@ -57,7 +57,7 @@ Read-Only:
- `delete_machines_elapsed_timespan` (Number)
-
+
### Nested Schema for `machine_policies.machine_connectivity_policy`
Read-Only:
@@ -65,7 +65,7 @@ Read-Only:
- `machine_connectivity_behavior` (String)
-
+
### Nested Schema for `machine_policies.machine_health_check_policy`
Read-Only:
@@ -96,7 +96,7 @@ Read-Only:
-
+
### Nested Schema for `machine_policies.machine_update_policy`
Read-Only:
diff --git a/docs/data-sources/offline_package_drop_deployment_targets.md b/docs/data-sources/offline_package_drop_deployment_targets.md
index fc01cb4ad..193982d1e 100644
--- a/docs/data-sources/offline_package_drop_deployment_targets.md
+++ b/docs/data-sources/offline_package_drop_deployment_targets.md
@@ -36,39 +36,39 @@ Provides information about existing offline package drop deployment targets.
### Read-Only
- `id` (String) An auto-generated identifier that includes the timestamp when this data source was last modified.
-- `offline_package_drop_deployment_targets` (Block List) A list of offline package drop deployment targets that match the filter(s). (see [below for nested schema](#nestedblock--offline_package_drop_deployment_targets))
+- `offline_package_drop_deployment_targets` (List of Object) A list of offline package drop deployment targets that match the filter(s). (see [below for nested schema](#nestedatt--offline_package_drop_deployment_targets))
-
+
### Nested Schema for `offline_package_drop_deployment_targets`
Read-Only:
- `applications_directory` (String)
-- `destination` (List of Object) (see [below for nested schema](#nestedatt--offline_package_drop_deployment_targets--destination))
-- `endpoint` (List of Object) (see [below for nested schema](#nestedatt--offline_package_drop_deployment_targets--endpoint))
-- `environments` (List of String) A list of environment IDs associated with this resource.
+- `destination` (List of Object) (see [below for nested schema](#nestedobjatt--offline_package_drop_deployment_targets--destination))
+- `endpoint` (List of Object) (see [below for nested schema](#nestedobjatt--offline_package_drop_deployment_targets--endpoint))
+- `environments` (List of String)
- `has_latest_calamari` (Boolean)
-- `health_status` (String) Represents the health status of this deployment target. Valid health statuses are `HasWarnings`, `Healthy`, `Unavailable`, `Unhealthy`, or `Unknown`.
-- `id` (String) The unique ID for this resource.
+- `health_status` (String)
+- `id` (String)
- `is_disabled` (Boolean)
- `is_in_process` (Boolean)
- `machine_policy_id` (String)
-- `name` (String) The name of this resource.
+- `name` (String)
- `operating_system` (String)
- `roles` (List of String)
- `shell_name` (String)
- `shell_version` (String)
-- `space_id` (String) The space ID associated with this resource.
-- `status` (String) The status of this resource. Valid statuses are `CalamariNeedsUpgrade`, `Disabled`, `NeedsUpgrade`, `Offline`, `Online`, or `Unknown`.
-- `status_summary` (String) A summary elaborating on the status of this resource.
-- `tenant_tags` (List of String) A list of tenant tags associated with this resource.
-- `tenanted_deployment_participation` (String) The tenanted deployment mode of the resource. Valid account types are `Untenanted`, `TenantedOrUntenanted`, or `Tenanted`.
-- `tenants` (List of String) A list of tenant IDs associated with this resource.
+- `space_id` (String)
+- `status` (String)
+- `status_summary` (String)
+- `tenant_tags` (List of String)
+- `tenanted_deployment_participation` (String)
+- `tenants` (List of String)
- `thumbprint` (String)
- `uri` (String)
- `working_directory` (String)
-
+
### Nested Schema for `offline_package_drop_deployment_targets.destination`
Read-Only:
@@ -77,7 +77,7 @@ Read-Only:
- `drop_folder_path` (String)
-
+
### Nested Schema for `offline_package_drop_deployment_targets.endpoint`
Read-Only:
diff --git a/docs/data-sources/polling_tentacle_deployment_targets.md b/docs/data-sources/polling_tentacle_deployment_targets.md
index 5124fddfc..b28cdfddf 100644
--- a/docs/data-sources/polling_tentacle_deployment_targets.md
+++ b/docs/data-sources/polling_tentacle_deployment_targets.md
@@ -36,39 +36,39 @@ Provides information about existing polling tentacle deployment targets.
### Read-Only
- `id` (String) An auto-generated identifier that includes the timestamp when this data source was last modified.
-- `polling_tentacle_deployment_targets` (Block List) A list of polling tentacle deployment targets that match the filter(s). (see [below for nested schema](#nestedblock--polling_tentacle_deployment_targets))
+- `polling_tentacle_deployment_targets` (List of Object) A list of polling tentacle deployment targets that match the filter(s). (see [below for nested schema](#nestedatt--polling_tentacle_deployment_targets))
-
+
### Nested Schema for `polling_tentacle_deployment_targets`
Read-Only:
- `certificate_signature_algorithm` (String)
-- `endpoint` (List of Object) (see [below for nested schema](#nestedatt--polling_tentacle_deployment_targets--endpoint))
-- `environments` (List of String) A list of environment IDs associated with this resource.
+- `endpoint` (List of Object) (see [below for nested schema](#nestedobjatt--polling_tentacle_deployment_targets--endpoint))
+- `environments` (List of String)
- `has_latest_calamari` (Boolean)
-- `health_status` (String) Represents the health status of this deployment target. Valid health statuses are `HasWarnings`, `Healthy`, `Unavailable`, `Unhealthy`, or `Unknown`.
-- `id` (String) The unique ID for this resource.
+- `health_status` (String)
+- `id` (String)
- `is_disabled` (Boolean)
- `is_in_process` (Boolean)
- `machine_policy_id` (String)
-- `name` (String) The name of this resource.
+- `name` (String)
- `operating_system` (String)
- `roles` (List of String)
- `shell_name` (String)
- `shell_version` (String)
-- `space_id` (String) The space ID associated with this resource.
-- `status` (String) The status of this resource. Valid statuses are `CalamariNeedsUpgrade`, `Disabled`, `NeedsUpgrade`, `Offline`, `Online`, or `Unknown`.
-- `status_summary` (String) A summary elaborating on the status of this resource.
-- `tenant_tags` (List of String) A list of tenant tags associated with this resource.
-- `tenanted_deployment_participation` (String) The tenanted deployment mode of the resource. Valid account types are `Untenanted`, `TenantedOrUntenanted`, or `Tenanted`.
-- `tenants` (List of String) A list of tenant IDs associated with this resource.
+- `space_id` (String)
+- `status` (String)
+- `status_summary` (String)
+- `tenant_tags` (List of String)
+- `tenanted_deployment_participation` (String)
+- `tenants` (List of String)
- `tentacle_url` (String)
-- `tentacle_version_details` (List of Object) (see [below for nested schema](#nestedatt--polling_tentacle_deployment_targets--tentacle_version_details))
+- `tentacle_version_details` (List of Object) (see [below for nested schema](#nestedobjatt--polling_tentacle_deployment_targets--tentacle_version_details))
- `thumbprint` (String)
- `uri` (String)
-
+
### Nested Schema for `polling_tentacle_deployment_targets.endpoint`
Read-Only:
@@ -172,7 +172,7 @@ Read-Only:
-
+
### Nested Schema for `polling_tentacle_deployment_targets.tentacle_version_details`
Read-Only:
diff --git a/docs/data-sources/project_groups.md b/docs/data-sources/project_groups.md
index ed88f743a..ab1d0f4eb 100644
--- a/docs/data-sources/project_groups.md
+++ b/docs/data-sources/project_groups.md
@@ -3,12 +3,12 @@
page_title: "octopusdeploy_project_groups Data Source - terraform-provider-octopusdeploy"
subcategory: ""
description: |-
- Provides information about existing project groups.
+
---
# octopusdeploy_project_groups (Data Source)
-Provides information about existing project groups.
+
## Example Usage
@@ -27,25 +27,28 @@ data "octopusdeploy_project_groups" "example" {
### Optional
- `ids` (List of String) A filter to search by a list of IDs.
-- `partial_name` (String) A filter to search by the partial match of a name.
+- `partial_name` (String) A filter to search by a partial name.
+- `project_groups` (Block List) A list of project groups that match the filter(s). (see [below for nested schema](#nestedblock--project_groups))
- `skip` (Number) A filter to specify the number of items to skip in the response.
-- `space_id` (String) A Space ID to filter by. Will revert what is specified on the provider if not set.
+- `space_id` (String) The space ID associated with this project group.
- `take` (Number) A filter to specify the number of items to take (or return) in the response.
### Read-Only
-- `id` (String) An auto-generated identifier that includes the timestamp when this data source was last modified.
-- `project_groups` (Block List) A list of project groups that match the filter(s). (see [below for nested schema](#nestedblock--project_groups))
+- `id` (String) The unique ID for this resource.
### Nested Schema for `project_groups`
-Read-Only:
+Optional:
- `description` (String) The description of this project group.
- `id` (String) The unique ID for this resource.
-- `name` (String) The name of this resource.
- `retention_policy_id` (String) The ID of the retention policy associated with this project group.
- `space_id` (String) The space ID associated with this project group.
+Read-Only:
+
+- `name` (String) The name of this resource.
+
diff --git a/docs/data-sources/script_modules b/docs/data-sources/script_modules
index 6625186eb..6a12509e7 100644
--- a/docs/data-sources/script_modules
+++ b/docs/data-sources/script_modules
@@ -34,21 +34,21 @@ data "octopusdeploy_script_modules" "example" {
### Read-Only
- `id` (String) An auto-generated identifier that includes the timestamp when this data source was last modified.
-- `script_modules` (Block List) A list of script modules that match the filter(s). (see [below for nested schema](#nestedblock--script_modules))
+- `script_modules` (List of Object) A list of script modules that match the filter(s). (see [below for nested schema](#nestedatt--script_modules))
-
+
### Nested Schema for `script_modules`
Read-Only:
-- `description` (String) The description of this script module.
-- `id` (String) The unique ID for this resource.
-- `name` (String) The name of this resource.
-- `script` (Set of Object) The script associated with this script module. (see [below for nested schema](#nestedatt--script_modules--script))
-- `space_id` (String) The space ID associated with this resource.
-- `variable_set_id` (String) The variable set ID for this script module.
+- `description` (String)
+- `id` (String)
+- `name` (String)
+- `script` (Set of Object) (see [below for nested schema](#nestedobjatt--script_modules--script))
+- `space_id` (String)
+- `variable_set_id` (String)
-
+
### Nested Schema for `script_modules.script`
Read-Only:
diff --git a/docs/data-sources/script_modules.md b/docs/data-sources/script_modules.md
index 283f804cc..35d7e16a8 100644
--- a/docs/data-sources/script_modules.md
+++ b/docs/data-sources/script_modules.md
@@ -35,21 +35,21 @@ data "octopusdeploy_script_modules" "example" {
### Read-Only
- `id` (String) An auto-generated identifier that includes the timestamp when this data source was last modified.
-- `script_modules` (Block List) A list of script modules that match the filter(s). (see [below for nested schema](#nestedblock--script_modules))
+- `script_modules` (List of Object) A list of script modules that match the filter(s). (see [below for nested schema](#nestedatt--script_modules))
-
+
### Nested Schema for `script_modules`
Read-Only:
-- `description` (String) The description of this script module.
-- `id` (String) The unique ID for this resource.
-- `name` (String) The name of this resource.
-- `script` (Set of Object) The script associated with this script module. (see [below for nested schema](#nestedatt--script_modules--script))
-- `space_id` (String) The space ID associated with this resource.
-- `variable_set_id` (String) The variable set ID for this script module.
+- `description` (String)
+- `id` (String)
+- `name` (String)
+- `script` (Set of Object) (see [below for nested schema](#nestedobjatt--script_modules--script))
+- `space_id` (String)
+- `variable_set_id` (String)
-
+
### Nested Schema for `script_modules.script`
Read-Only:
diff --git a/docs/data-sources/space.md b/docs/data-sources/space.md
index 36bcc4c81..2ec59a7f5 100644
--- a/docs/data-sources/space.md
+++ b/docs/data-sources/space.md
@@ -25,7 +25,7 @@ Provides information about an existing space.
- `id` (String) The unique ID for this resource.
- `is_default` (Boolean) Specifies if this space is the default space in Octopus.
- `is_task_queue_stopped` (Boolean) Specifies the status of the task queue for this space.
-- `slug` (String) The unique slug of this space.
+- `slug` (String) The unique slug of this space
- `space_managers_team_members` (Set of String) A list of user IDs designated to be managers of this space.
- `space_managers_teams` (Set of String) A list of team IDs designated to be managers of this space.
diff --git a/docs/data-sources/spaces.md b/docs/data-sources/spaces.md
index 36485b0a1..ff5ae2193 100644
--- a/docs/data-sources/spaces.md
+++ b/docs/data-sources/spaces.md
@@ -3,12 +3,12 @@
page_title: "octopusdeploy_spaces Data Source - terraform-provider-octopusdeploy"
subcategory: ""
description: |-
- Provides information about existing spaces.
+
---
# octopusdeploy_spaces (Data Source)
-Provides information about existing spaces.
+
## Example Usage
@@ -27,26 +27,29 @@ data "octopusdeploy_spaces" "spaces" {
### Optional
- `ids` (List of String) A filter to search by a list of IDs.
-- `partial_name` (String) A filter to search by the partial match of a name.
+- `partial_name` (String) A filter to search by a partial name.
- `skip` (Number) A filter to specify the number of items to skip in the response.
+- `spaces` (Block List) Provides information about existing spaces. (see [below for nested schema](#nestedblock--spaces))
- `take` (Number) A filter to specify the number of items to take (or return) in the response.
### Read-Only
-- `id` (String) An auto-generated identifier that includes the timestamp when this data source was last modified.
-- `spaces` (Block List) A list of spaces that match the filter(s). (see [below for nested schema](#nestedblock--spaces))
+- `id` (String) The unique ID for this resource.
### Nested Schema for `spaces`
+Required:
+
+- `name` (String) The name of this resource, no more than 20 characters long
+
Read-Only:
- `description` (String) The description of this space.
- `id` (String) The unique ID for this resource.
- `is_default` (Boolean) Specifies if this space is the default space in Octopus.
- `is_task_queue_stopped` (Boolean) Specifies the status of the task queue for this space.
-- `name` (String) The name of this resource, no more than 20 characters long
-- `slug` (String) The unique slug of this space.
+- `slug` (String) The unique slug of this space
- `space_managers_team_members` (Set of String) A list of user IDs designated to be managers of this space.
- `space_managers_teams` (Set of String) A list of team IDs designated to be managers of this space.
diff --git a/docs/data-sources/ssh_connection_deployment_targets.md b/docs/data-sources/ssh_connection_deployment_targets.md
index 43e054adb..4c0d32f1c 100644
--- a/docs/data-sources/ssh_connection_deployment_targets.md
+++ b/docs/data-sources/ssh_connection_deployment_targets.md
@@ -36,42 +36,42 @@ Provides information about existing SSH connection deployment targets.
### Read-Only
- `id` (String) An auto-generated identifier that includes the timestamp when this data source was last modified.
-- `ssh_connection_deployment_targets` (Block List) A list of SSH connection deployment targets that match the filter(s). (see [below for nested schema](#nestedblock--ssh_connection_deployment_targets))
+- `ssh_connection_deployment_targets` (List of Object) A list of SSH connection deployment targets that match the filter(s). (see [below for nested schema](#nestedatt--ssh_connection_deployment_targets))
-
+
### Nested Schema for `ssh_connection_deployment_targets`
Read-Only:
- `account_id` (String)
- `dot_net_core_platform` (String)
-- `endpoint` (List of Object) (see [below for nested schema](#nestedatt--ssh_connection_deployment_targets--endpoint))
-- `environments` (List of String) A list of environment IDs associated with this resource.
+- `endpoint` (List of Object) (see [below for nested schema](#nestedobjatt--ssh_connection_deployment_targets--endpoint))
+- `environments` (List of String)
- `fingerprint` (String)
- `has_latest_calamari` (Boolean)
-- `health_status` (String) Represents the health status of this deployment target. Valid health statuses are `HasWarnings`, `Healthy`, `Unavailable`, `Unhealthy`, or `Unknown`.
+- `health_status` (String)
- `host` (String)
-- `id` (String) The unique ID for this resource.
+- `id` (String)
- `is_disabled` (Boolean)
- `is_in_process` (Boolean)
- `machine_policy_id` (String)
-- `name` (String) The name of this resource.
+- `name` (String)
- `operating_system` (String)
- `port` (Number)
- `proxy_id` (String)
- `roles` (List of String)
- `shell_name` (String)
- `shell_version` (String)
-- `space_id` (String) The space ID associated with this resource.
-- `status` (String) The status of this resource. Valid statuses are `CalamariNeedsUpgrade`, `Disabled`, `NeedsUpgrade`, `Offline`, `Online`, or `Unknown`.
-- `status_summary` (String) A summary elaborating on the status of this resource.
-- `tenant_tags` (List of String) A list of tenant tags associated with this resource.
-- `tenanted_deployment_participation` (String) The tenanted deployment mode of the resource. Valid account types are `Untenanted`, `TenantedOrUntenanted`, or `Tenanted`.
-- `tenants` (List of String) A list of tenant IDs associated with this resource.
+- `space_id` (String)
+- `status` (String)
+- `status_summary` (String)
+- `tenant_tags` (List of String)
+- `tenanted_deployment_participation` (String)
+- `tenants` (List of String)
- `thumbprint` (String)
- `uri` (String)
-
+
### Nested Schema for `ssh_connection_deployment_targets.endpoint`
Read-Only:
diff --git a/docs/data-sources/tag_sets.md b/docs/data-sources/tag_sets.md
index fb8fffe78..56b41b61b 100644
--- a/docs/data-sources/tag_sets.md
+++ b/docs/data-sources/tag_sets.md
@@ -26,17 +26,17 @@ Provides information about existing tag sets.
### Read-Only
- `id` (String) The ID of this resource.
-- `tag_sets` (Block List) A list of tag sets that match the filter(s). (see [below for nested schema](#nestedblock--tag_sets))
+- `tag_sets` (List of Object) A list of tag sets that match the filter(s). (see [below for nested schema](#nestedatt--tag_sets))
-
+
### Nested Schema for `tag_sets`
Read-Only:
-- `description` (String) The description of this tag set.
-- `id` (String) The unique ID for this resource.
-- `name` (String) The name of this resource.
-- `sort_order` (Number) The sort order associated with this resource.
-- `space_id` (String) The space ID associated with this resource.
+- `description` (String)
+- `id` (String)
+- `name` (String)
+- `sort_order` (Number)
+- `space_id` (String)
diff --git a/docs/data-sources/teams.md b/docs/data-sources/teams.md
index ba635c2e0..1075d7295 100644
--- a/docs/data-sources/teams.md
+++ b/docs/data-sources/teams.md
@@ -27,9 +27,9 @@ Provides information about existing users.
### Read-Only
- `id` (String) An auto-generated identifier that includes the timestamp when this data source was last modified.
-- `teams` (Block List) A list of teams that match the filter(s). (see [below for nested schema](#nestedblock--teams))
+- `teams` (List of Object) A list of teams that match the filter(s). (see [below for nested schema](#nestedatt--teams))
-
+
### Nested Schema for `teams`
Read-Only:
@@ -38,14 +38,14 @@ Read-Only:
- `can_be_renamed` (Boolean)
- `can_change_members` (Boolean)
- `can_change_roles` (Boolean)
-- `description` (String) The user-friendly description of this team.
-- `external_security_group` (List of Object) (see [below for nested schema](#nestedatt--teams--external_security_group))
-- `id` (String) The unique ID for this resource.
-- `name` (String) The name of this team.
-- `space_id` (String) The space associated with this team.
-- `users` (Set of String) A list of user IDs designated to be members of this team.
-
-
+- `description` (String)
+- `external_security_group` (List of Object) (see [below for nested schema](#nestedobjatt--teams--external_security_group))
+- `id` (String)
+- `name` (String)
+- `space_id` (String)
+- `users` (Set of String)
+
+
### Nested Schema for `teams.external_security_group`
Read-Only:
diff --git a/docs/data-sources/tenants.md b/docs/data-sources/tenants.md
index 28d093d17..7b6486318 100644
--- a/docs/data-sources/tenants.md
+++ b/docs/data-sources/tenants.md
@@ -21,16 +21,16 @@ Provides information about existing tenants.
- `ids` (List of String) A filter to search by a list of IDs.
- `is_clone` (Boolean) A filter to search for cloned resources.
- `name` (String) A filter to search by name.
-- `partial_name` (String) A filter to search by the partial match of a name.
+- `partial_name` (String) A filter to search by a partial name.
- `project_id` (String) A filter to search by a project ID.
- `skip` (Number) A filter to specify the number of items to skip in the response.
-- `space_id` (String) A Space ID to filter by. Will revert what is specified on the provider if not set.
+- `space_id` (String) The space ID associated with this tenants.
- `tags` (List of String) A filter to search by a list of tags.
- `take` (Number) A filter to specify the number of items to take (or return) in the response.
### Read-Only
-- `id` (String) An auto-generated identifier that includes the timestamp when this data source was last modified.
+- `id` (String) The unique ID for this resource.
- `tenants` (Block List) A list of tenants that match the filter(s). (see [below for nested schema](#nestedblock--tenants))
@@ -39,10 +39,10 @@ Provides information about existing tenants.
Read-Only:
- `cloned_from_tenant_id` (String) The ID of the tenant from which this tenant was cloned.
-- `description` (String) The description of this tenant.
+- `description` (String) The description of this tenants.
- `id` (String) The unique ID for this resource.
- `name` (String) The name of this resource.
-- `space_id` (String) The space ID associated with this resource.
+- `space_id` (String) The space ID associated with this tenant.
- `tenant_tags` (List of String) A list of tenant tags associated with this resource.
diff --git a/docs/data-sources/user_roles.md b/docs/data-sources/user_roles.md
index 19010c518..8c6bc4544 100644
--- a/docs/data-sources/user_roles.md
+++ b/docs/data-sources/user_roles.md
@@ -35,19 +35,19 @@ data "octopusdeploy_user_roles" "example" {
### Read-Only
- `id` (String) An auto-generated identifier that includes the timestamp when this data source was last modified.
-- `user_roles` (Block List) A list of user roles that match the filter(s). (see [below for nested schema](#nestedblock--user_roles))
+- `user_roles` (List of Object) A list of user roles that match the filter(s). (see [below for nested schema](#nestedatt--user_roles))
-
+
### Nested Schema for `user_roles`
Read-Only:
- `can_be_deleted` (Boolean)
-- `description` (String) The description of this user role.
+- `description` (String)
- `granted_space_permissions` (List of String)
- `granted_system_permissions` (List of String)
-- `id` (String) The unique ID for this resource.
-- `name` (String) The name of this resource.
+- `id` (String)
+- `name` (String)
- `space_permission_descriptions` (List of String)
- `supported_restrictions` (List of String)
- `system_permission_descriptions` (List of String)
diff --git a/docs/data-sources/users.md b/docs/data-sources/users.md
index dd1a19994..ca9f963dd 100644
--- a/docs/data-sources/users.md
+++ b/docs/data-sources/users.md
@@ -34,25 +34,25 @@ data "octopusdeploy_users" "example" {
### Read-Only
- `id` (String) An auto-generated identifier that includes the timestamp when this data source was last modified.
-- `users` (Block List) A list of users that match the filter(s). (see [below for nested schema](#nestedblock--users))
+- `users` (List of Object) A list of users that match the filter(s). (see [below for nested schema](#nestedatt--users))
-
+
### Nested Schema for `users`
Read-Only:
- `can_password_be_edited` (Boolean)
-- `display_name` (String) The display name of this resource.
-- `email_address` (String) The email address of this resource.
-- `id` (String) The unique ID for this resource.
-- `identity` (Set of Object) (see [below for nested schema](#nestedatt--users--identity))
+- `display_name` (String)
+- `email_address` (String)
+- `id` (String)
+- `identity` (Set of Object) (see [below for nested schema](#nestedobjatt--users--identity))
- `is_active` (Boolean)
- `is_requestor` (Boolean)
- `is_service` (Boolean)
-- `password` (String, Sensitive) The password associated with this resource.
-- `username` (String, Sensitive) The username associated with this resource.
+- `password` (String)
+- `username` (String)
-
+
### Nested Schema for `users.identity`
Read-Only:
diff --git a/docs/data-sources/worker_pools.md b/docs/data-sources/worker_pools.md
index 7c6636313..95c0cdf35 100644
--- a/docs/data-sources/worker_pools.md
+++ b/docs/data-sources/worker_pools.md
@@ -27,20 +27,20 @@ Provides information about existing worker pools.
### Read-Only
- `id` (String) The ID of this resource.
-- `worker_pools` (Block List) A list of worker pools that match the filter(s). (see [below for nested schema](#nestedblock--worker_pools))
+- `worker_pools` (List of Object) A list of worker pools that match the filter(s). (see [below for nested schema](#nestedatt--worker_pools))
-
+
### Nested Schema for `worker_pools`
Read-Only:
- `can_add_workers` (Boolean)
-- `description` (String) The description of this worker pool.
-- `id` (String) The unique ID for this resource.
+- `description` (String)
+- `id` (String)
- `is_default` (Boolean)
-- `name` (String) The name of this resource.
-- `sort_order` (Number) The order number to sort a dynamic worker pool.
-- `space_id` (String) The space ID associated with this resource.
+- `name` (String)
+- `sort_order` (Number)
+- `space_id` (String)
- `worker_pool_type` (String)
- `worker_type` (String)
diff --git a/docs/index.md b/docs/index.md
index 9787f53dc..e0fadfb5f 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -79,11 +79,8 @@ resource "octopusdeploy_environment" "Env3" {
## Schema
-### Required
+### Optional
- `address` (String) The endpoint of the Octopus REST API
- `api_key` (String) The API key to use with the Octopus REST API
-
-### Optional
-
- `space_id` (String) The space ID to target
\ No newline at end of file
diff --git a/docs/resources/azure_subscription_account.md b/docs/resources/azure_subscription_account.md
index a7025e91a..7f11a8822 100644
--- a/docs/resources/azure_subscription_account.md
+++ b/docs/resources/azure_subscription_account.md
@@ -22,9 +22,7 @@ resource "octopusdeploy_azure_subscription_account" "example" {
### Required
-- `management_endpoint` (String)
- `name` (String) The name of this resource.
-- `storage_endpoint_suffix` (String) The storage endpoint suffix associated with this Azure subscription account.
- `subscription_id` (String) The subscription ID of this resource.
### Optional
@@ -34,7 +32,9 @@ resource "octopusdeploy_azure_subscription_account" "example" {
- `certificate_thumbprint` (String, Sensitive)
- `description` (String) The description of this Azure subscription account.
- `environments` (List of String) A list of environment IDs associated with this resource.
+- `management_endpoint` (String)
- `space_id` (String) The space ID associated with this resource.
+- `storage_endpoint_suffix` (String) The storage endpoint suffix associated with this Azure subscription account.
- `tenant_tags` (List of String) A list of tenant tags associated with this resource.
- `tenanted_deployment_participation` (String) The tenanted deployment mode of the resource. Valid account types are `Untenanted`, `TenantedOrUntenanted`, or `Tenanted`.
- `tenants` (List of String) A list of tenant IDs associated with this resource.
diff --git a/docs/resources/environment.md b/docs/resources/environment.md
index e8a5c7438..c9f9c5d1e 100644
--- a/docs/resources/environment.md
+++ b/docs/resources/environment.md
@@ -3,12 +3,12 @@
page_title: "octopusdeploy_environment Resource - terraform-provider-octopusdeploy"
subcategory: ""
description: |-
- This resource manages environments in Octopus Deploy.
+
---
# octopusdeploy_environment (Resource)
-This resource manages environments in Octopus Deploy.
+
## Example Usage
@@ -45,39 +45,36 @@ resource "octopusdeploy_environment" "example" {
- `allow_dynamic_infrastructure` (Boolean)
- `description` (String) The description of this environment.
- `id` (String) The unique ID for this resource.
-- `jira_extension_settings` (Block List, Max: 1) Provides extension settings for the Jira integration for this environment. (see [below for nested schema](#nestedblock--jira_extension_settings))
-- `jira_service_management_extension_settings` (Block List, Max: 1) Provides extension settings for the Jira Service Management (JSM) integration for this environment. (see [below for nested schema](#nestedblock--jira_service_management_extension_settings))
-- `servicenow_extension_settings` (Block List, Max: 1) Provides extension settings for the ServiceNow integration for this environment. (see [below for nested schema](#nestedblock--servicenow_extension_settings))
-- `sort_order` (Number) The order number to sort an environment.
+- `jira_extension_settings` (Block List) Provides extension settings for the Jira integration for this environment. (see [below for nested schema](#nestedblock--jira_extension_settings))
+- `jira_service_management_extension_settings` (Block List) Provides extension settings for the Jira Service Management (JSM) integration for this environment. (see [below for nested schema](#nestedblock--jira_service_management_extension_settings))
+- `servicenow_extension_settings` (Block List) Provides extension settings for the ServiceNow integration for this environment. (see [below for nested schema](#nestedblock--servicenow_extension_settings))
+- `slug` (String) The unique slug of this environment
+- `sort_order` (Number) The order number to sort an environment
- `space_id` (String) The space ID associated with this environment.
- `use_guided_failure` (Boolean)
-### Read-Only
-
-- `slug` (String)
-
### Nested Schema for `jira_extension_settings`
-Required:
+Optional:
-- `environment_type` (String) The Jira environment type of this Octopus deployment environment. Valid values are `"development"`, `"production"`, `"staging"`, `"testing"`, or `"unmapped"`.
+- `environment_type` (String)
### Nested Schema for `jira_service_management_extension_settings`
-Required:
+Optional:
-- `is_enabled` (Boolean) Specifies whether or not this extension is enabled for this project.
+- `is_enabled` (Boolean)
### Nested Schema for `servicenow_extension_settings`
-Required:
+Optional:
-- `is_enabled` (Boolean) Specifies whether or not this extension is enabled for this project.
+- `is_enabled` (Boolean)
## Import
diff --git a/docs/resources/lifecycle.md b/docs/resources/lifecycle.md
index 8714ab06e..e5178b91e 100644
--- a/docs/resources/lifecycle.md
+++ b/docs/resources/lifecycle.md
@@ -33,8 +33,8 @@ resource "octopusdeploy_lifecycle" "example" {
name = "foo"
release_retention_policy {
- quantity_to_keep = 0
- should_keep_forever = true // true only if quantity_to_keep = 0
+ quantity_to_keep = 1
+ should_keep_forever = true
unit = "Days"
}
diff --git a/docs/resources/nuget_feed.md b/docs/resources/nuget_feed.md
index b5758af66..4a736c70a 100644
--- a/docs/resources/nuget_feed.md
+++ b/docs/resources/nuget_feed.md
@@ -2,12 +2,12 @@
page_title: "octopusdeploy_nuget_feed Resource - terraform-provider-octopusdeploy"
subcategory: "Feeds"
description: |-
- This resource manages a NuGet feed in Octopus Deploy.
+ This resource manages a Nuget feed in Octopus Deploy.
---
# octopusdeploy_nuget_feed (Resource)
-This resource manages a NuGet feed in Octopus Deploy.
+This resource manages a Nuget feed in Octopus Deploy.
## Example Usage
diff --git a/docs/resources/space.md b/docs/resources/space.md
index 6ab45052e..f2b0f3084 100644
--- a/docs/resources/space.md
+++ b/docs/resources/space.md
@@ -28,7 +28,7 @@ resource "octopusdeploy_space" "example" {
### Required
-- `name` (String) The name of this resource, no more than 20 characters long
+- `name` (String) The name of this resource.
### Optional
@@ -36,7 +36,7 @@ resource "octopusdeploy_space" "example" {
- `id` (String) The unique ID for this resource.
- `is_default` (Boolean) Specifies if this space is the default space in Octopus.
- `is_task_queue_stopped` (Boolean) Specifies the status of the task queue for this space.
-- `slug` (String) The unique slug of this space.
+- `slug` (String) The unique slug of this space
- `space_managers_team_members` (Set of String) A list of user IDs designated to be managers of this space.
- `space_managers_teams` (Set of String) A list of team IDs designated to be managers of this space.
diff --git a/docs/resources/tenant_common_variable.md b/docs/resources/tenant_common_variable.md
index 4c1c54054..c306e3c59 100644
--- a/docs/resources/tenant_common_variable.md
+++ b/docs/resources/tenant_common_variable.md
@@ -3,12 +3,12 @@
page_title: "octopusdeploy_tenant_common_variable Resource - terraform-provider-octopusdeploy"
subcategory: ""
description: |-
- This resource manages tenant common variables in Octopus Deploy.
+ Manages a tenant common variable in Octopus Deploy.
---
# octopusdeploy_tenant_common_variable (Resource)
-This resource manages tenant common variables in Octopus Deploy.
+Manages a tenant common variable in Octopus Deploy.
@@ -17,17 +17,14 @@ This resource manages tenant common variables in Octopus Deploy.
### Required
-- `library_variable_set_id` (String)
-- `template_id` (String)
-- `tenant_id` (String)
+- `library_variable_set_id` (String) The ID of the library variable set.
+- `template_id` (String) The ID of the variable template.
+- `tenant_id` (String) The ID of the tenant.
### Optional
-- `space_id` (String)
-- `value` (String, Sensitive)
-
-### Read-Only
-
-- `id` (String) The ID of this resource.
+- `id` (String) The unique ID for this resource.
+- `space_id` (String) The space ID associated with this Tenant Common Variable.
+- `value` (String, Sensitive) The value of the variable.
diff --git a/docs/resources/tenant_project.md b/docs/resources/tenant_project.md
index f537e8fcc..2558f847b 100644
--- a/docs/resources/tenant_project.md
+++ b/docs/resources/tenant_project.md
@@ -3,12 +3,12 @@
page_title: "octopusdeploy_tenant_project Resource - terraform-provider-octopusdeploy"
subcategory: ""
description: |-
- This resource represents the connection between tenants and projects.
+
---
# octopusdeploy_tenant_project (Resource)
-This resource represents the connection between tenants and projects.
+
@@ -22,11 +22,8 @@ This resource represents the connection between tenants and projects.
### Optional
-- `environment_ids` (List of String) The environment ID associated with this tenant.
-- `space_id` (String) The space ID associated with this resource.
-
-### Read-Only
-
-- `id` (String) The ID of this resource.
+- `environment_ids` (List of String) The environment IDs associated with this tenant.
+- `id` (String) The unique ID for this resource.
+- `space_id` (String) The space ID associated with this project tenant.
diff --git a/go.mod b/go.mod
index 4cc35d04a..f3ed22597 100644
--- a/go.mod
+++ b/go.mod
@@ -4,7 +4,7 @@ go 1.21
require (
github.com/OctopusDeploy/go-octopusdeploy/v2 v2.49.1
- github.com/OctopusSolutionsEngineering/OctopusTerraformTestFramework v0.0.0-20240725054341-2848f54d101e
+ github.com/OctopusSolutionsEngineering/OctopusTerraformTestFramework v0.0.0-20240729041805-46db6fb717b4
github.com/google/uuid v1.6.0
github.com/hashicorp/go-cty v1.4.1-0.20200723130312-85980079f637
github.com/hashicorp/terraform-plugin-docs v0.13.0
diff --git a/go.sum b/go.sum
index c917536b0..c0bdd145e 100644
--- a/go.sum
+++ b/go.sum
@@ -22,8 +22,8 @@ github.com/OctopusDeploy/go-octodiff v1.0.0 h1:U+ORg6azniwwYo+O44giOw6TiD5USk8S4
github.com/OctopusDeploy/go-octodiff v1.0.0/go.mod h1:Mze0+EkOWTgTmi8++fyUc6r0aLZT7qD9gX+31t8MmIU=
github.com/OctopusDeploy/go-octopusdeploy/v2 v2.49.1 h1:lzC3tcnfvC07Ilqn5J51qhOnW79kGD6nTIxCBOdmAe8=
github.com/OctopusDeploy/go-octopusdeploy/v2 v2.49.1/go.mod h1:ggvOXzMnq+w0pLg6C9zdjz6YBaHfO3B3tqmmB7JQdaw=
-github.com/OctopusSolutionsEngineering/OctopusTerraformTestFramework v0.0.0-20240725054341-2848f54d101e h1:FIvWa8wNg8IBG5uVhqkKvcBhaxx4TgN7T8/5Ed4VQUE=
-github.com/OctopusSolutionsEngineering/OctopusTerraformTestFramework v0.0.0-20240725054341-2848f54d101e/go.mod h1:Oq9KbiRNDBB5jFmrwnrgLX0urIqR/1ptY18TzkqXm7M=
+github.com/OctopusSolutionsEngineering/OctopusTerraformTestFramework v0.0.0-20240729041805-46db6fb717b4 h1:QfbVf0bOIRMp/WHAWsuVDB7KHoWnRsGbvDuOf2ua7k4=
+github.com/OctopusSolutionsEngineering/OctopusTerraformTestFramework v0.0.0-20240729041805-46db6fb717b4/go.mod h1:Oq9KbiRNDBB5jFmrwnrgLX0urIqR/1ptY18TzkqXm7M=
github.com/ProtonMail/go-crypto v1.1.0-alpha.2 h1:bkyFVUP+ROOARdgCiJzNQo2V2kiB97LyUpzH9P6Hrlg=
github.com/ProtonMail/go-crypto v1.1.0-alpha.2/go.mod h1:rA3QumHc/FZ8pAHreoekgiAbzpNsfQAosU5td4SnOrE=
github.com/agext/levenshtein v1.2.3 h1:YB2fHEn0UJagG8T1rrWknE3ZQzWM06O8AMAatNn7lmo=
diff --git a/octopusdeploy/data_source_tenants.go b/octopusdeploy/data_source_tenants.go
deleted file mode 100644
index 4c9cfa569..000000000
--- a/octopusdeploy/data_source_tenants.go
+++ /dev/null
@@ -1,54 +0,0 @@
-package octopusdeploy
-
-import (
- "context"
- "time"
-
- "github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/client"
- "github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/tenants"
- "github.com/hashicorp/terraform-plugin-sdk/v2/diag"
- "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
-)
-
-func dataSourceTenants() *schema.Resource {
- return &schema.Resource{
- Description: "Provides information about existing tenants.",
- ReadContext: dataSourceTenantsRead,
- Schema: getTenantDataSchema(),
- }
-}
-
-func dataSourceTenantsRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
- query := tenants.TenantsQuery{
- ClonedFromTenantID: d.Get("cloned_from_tenant_id").(string),
- IDs: expandArray(d.Get("ids").([]interface{})),
- IsClone: d.Get("is_clone").(bool),
- Name: d.Get("name").(string),
- PartialName: d.Get("partial_name").(string),
- ProjectID: d.Get("project_id").(string),
- Skip: d.Get("skip").(int),
- Tags: expandArray(d.Get("tags").([]interface{})),
- Take: d.Get("take").(int),
- }
-
- spaceID := d.Get("space_id").(string)
-
- client := meta.(*client.Client)
- existingTenants, err := tenants.Get(client, spaceID, query)
- if err != nil {
- return diag.FromErr(err)
- }
-
- flattenedTenants := []interface{}{}
- for _, tenant := range existingTenants.Items {
- flattenedTenants = append(flattenedTenants, flattenTenant(tenant))
- }
-
- if err := d.Set("tenants", flattenedTenants); err != nil {
- return diag.FromErr(err)
- }
-
- d.SetId("Tenants " + time.Now().UTC().String())
-
- return nil
-}
diff --git a/octopusdeploy/provider.go b/octopusdeploy/provider.go
index 07f503374..6de5657b1 100644
--- a/octopusdeploy/provider.go
+++ b/octopusdeploy/provider.go
@@ -2,7 +2,6 @@ package octopusdeploy
import (
"context"
-
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)
@@ -30,7 +29,6 @@ func Provider() *schema.Provider {
"octopusdeploy_ssh_connection_deployment_targets": dataSourceSSHConnectionDeploymentTargets(),
"octopusdeploy_tag_sets": dataSourceTagSets(),
"octopusdeploy_teams": dataSourceTeams(),
- "octopusdeploy_tenants": dataSourceTenants(),
"octopusdeploy_users": dataSourceUsers(),
"octopusdeploy_user_roles": dataSourceUserRoles(),
"octopusdeploy_worker_pools": dataSourceWorkerPools(),
diff --git a/octopusdeploy/resource_deployment_process_test.go b/octopusdeploy/resource_deployment_process_test.go
index d800b81da..10bdefef0 100644
--- a/octopusdeploy/resource_deployment_process_test.go
+++ b/octopusdeploy/resource_deployment_process_test.go
@@ -436,7 +436,6 @@ func testAccDeploymentProcessCheckDestroy(s *terraform.State) error {
func TestDeploymentProcessWithGitDependency(t *testing.T) {
testFramework := test.OctopusContainerTest{}
-
newSpaceId, err := testFramework.Act(t, octoContainer, "../terraform", "51-deploymentprocesswithgitdependency", []string{})
if err != nil {
diff --git a/octopusdeploy/testing_container_test.go b/octopusdeploy/testing_container_test.go
index 6fd5dfba7..1f37ad0a3 100644
--- a/octopusdeploy/testing_container_test.go
+++ b/octopusdeploy/testing_container_test.go
@@ -27,7 +27,7 @@ func TestMain(m *testing.M) {
if *createSharedContainer {
testFramework := test.OctopusContainerTest{}
- octoContainer, octoClient, sqlServerContainer, network, err = testFramework.ArrangeContainer(m)
+ octoContainer, octoClient, sqlServerContainer, network, err = testFramework.ArrangeContainer()
if err != nil {
log.Printf("Failed to arrange containers: (%s)", err.Error())
}
diff --git a/octopusdeploy_framework/datasource_environments.go b/octopusdeploy_framework/datasource_environments.go
index b788107d5..06b52a527 100644
--- a/octopusdeploy_framework/datasource_environments.go
+++ b/octopusdeploy_framework/datasource_environments.go
@@ -45,14 +45,14 @@ func (*environmentDataSource) Schema(_ context.Context, req datasource.SchemaReq
Attributes: map[string]schema.Attribute{
//request
"ids": util.GetQueryIDsDatasourceSchema(),
- "space_id": util.GetSpaceIdDatasourceSchema(schemas.EnvironmentResourceDescription),
+ "space_id": schemas.GetSpaceIdDatasourceSchema(schemas.EnvironmentResourceDescription, false),
"name": util.GetQueryNameDatasourceSchema(),
"partial_name": util.GetQueryPartialNameDatasourceSchema(),
"skip": util.GetQuerySkipDatasourceSchema(),
"take": util.GetQueryTakeDatasourceSchema(),
//response
- "id": util.GetIdDatasourceSchema(),
+ "id": schemas.GetIdDatasourceSchema(true),
},
Blocks: map[string]schema.Block{
"environments": schema.ListNestedBlock{
diff --git a/octopusdeploy_framework/datasource_project_groups.go b/octopusdeploy_framework/datasource_project_groups.go
index 01713abbc..bca82cd2a 100644
--- a/octopusdeploy_framework/datasource_project_groups.go
+++ b/octopusdeploy_framework/datasource_project_groups.go
@@ -50,14 +50,14 @@ func (p *projectGroupsDataSource) Schema(_ context.Context, _ datasource.SchemaR
resp.Schema = schema.Schema{
Attributes: map[string]schema.Attribute{
// request
- "space_id": util.GetSpaceIdDatasourceSchema(description),
+ "space_id": schemas.GetSpaceIdDatasourceSchema(description, false),
"ids": util.GetQueryIDsDatasourceSchema(),
"partial_name": util.GetQueryPartialNameDatasourceSchema(),
"skip": util.GetQuerySkipDatasourceSchema(),
"take": util.GetQueryTakeDatasourceSchema(),
// response
- "id": util.GetIdDatasourceSchema(),
+ "id": schemas.GetIdDatasourceSchema(true),
},
Blocks: map[string]schema.Block{
"project_groups": schema.ListNestedBlock{
diff --git a/octopusdeploy_framework/datasource_spaces.go b/octopusdeploy_framework/datasource_spaces.go
index c7ec6414c..00ba2352c 100644
--- a/octopusdeploy_framework/datasource_spaces.go
+++ b/octopusdeploy_framework/datasource_spaces.go
@@ -42,7 +42,7 @@ func (*spacesDataSource) Schema(_ context.Context, _ datasource.SchemaRequest, r
"take": schemas.GetQueryTakeDatasourceSchema(),
// response
- "id": schemas.GetIdDatasourceSchema(),
+ "id": schemas.GetIdDatasourceSchema(true),
},
Blocks: map[string]schema.Block{
"spaces": schema.ListNestedBlock{
diff --git a/octopusdeploy_framework/datasource_tenants.go b/octopusdeploy_framework/datasource_tenants.go
new file mode 100644
index 000000000..bf8b2867a
--- /dev/null
+++ b/octopusdeploy_framework/datasource_tenants.go
@@ -0,0 +1,80 @@
+package octopusdeploy_framework
+
+import (
+ "context"
+ "github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/tenants"
+ "github.com/OctopusDeploy/terraform-provider-octopusdeploy/octopusdeploy_framework/schemas"
+ "github.com/OctopusDeploy/terraform-provider-octopusdeploy/octopusdeploy_framework/util"
+ "github.com/hashicorp/terraform-plugin-framework/datasource"
+ datasourceSchema "github.com/hashicorp/terraform-plugin-framework/datasource/schema"
+ "github.com/hashicorp/terraform-plugin-framework/types"
+ "time"
+)
+
+type tenantsDataSource struct {
+ *Config
+}
+
+func NewTenantsDataSource() datasource.DataSource {
+ return &tenantsDataSource{}
+}
+
+func (*tenantsDataSource) Metadata(_ context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) {
+ resp.TypeName = util.GetTypeName("tenants")
+}
+
+func (e *tenantsDataSource) Configure(_ context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) {
+ e.Config = DataSourceConfiguration(req, resp)
+}
+
+func (*tenantsDataSource) Schema(_ context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) {
+ resp.Schema = datasourceSchema.Schema{
+ Description: "Provides information about existing tenants.",
+ Attributes: schemas.GetTenantsDataSourceSchema(),
+ Blocks: map[string]datasourceSchema.Block{
+ "tenants": datasourceSchema.ListNestedBlock{
+ Description: "A list of tenants that match the filter(s).",
+ NestedObject: datasourceSchema.NestedBlockObject{
+ Attributes: schemas.GetTenantDataSourceSchema(),
+ },
+ },
+ },
+ }
+}
+
+func (b *tenantsDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) {
+ var err error
+ var data schemas.TenantsModel
+ resp.Diagnostics.Append(req.Config.Get(ctx, &data)...)
+ if resp.Diagnostics.HasError() {
+ return
+ }
+
+ query := tenants.TenantsQuery{
+ ClonedFromTenantID: data.ClonedFromTenantId.ValueString(),
+ IDs: util.ExpandStringList(data.IDs),
+ IsClone: data.IsClone.ValueBool(),
+ Name: data.Name.ValueString(),
+ PartialName: data.PartialName.ValueString(),
+ ProjectID: data.ProjectId.ValueString(),
+ Skip: int(data.Skip.ValueInt64()),
+ Tags: util.ExpandStringList(data.Tags),
+ Take: int(data.Take.ValueInt64()),
+ }
+
+ existingTenants, err := tenants.Get(b.Client, data.SpaceID.ValueString(), query)
+ if err != nil {
+ resp.Diagnostics.AddError("unable to load tenants", err.Error())
+ return
+ }
+
+ flattenedTenants := []interface{}{}
+ for _, tenant := range existingTenants.Items {
+ flattenedTenants = append(flattenedTenants, schemas.FlattenTenant(tenant))
+ }
+
+ data.ID = types.StringValue("Tenants " + time.Now().UTC().String())
+ data.Tenants, _ = types.ListValueFrom(ctx, types.ObjectType{AttrTypes: schemas.TenantObjectType()}, flattenedTenants)
+
+ resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
+}
diff --git a/octopusdeploy/data_source_tenants_test.go b/octopusdeploy_framework/datasource_tenants_test.go
similarity index 82%
rename from octopusdeploy/data_source_tenants_test.go
rename to octopusdeploy_framework/datasource_tenants_test.go
index b7baa57c8..95907b087 100644
--- a/octopusdeploy/data_source_tenants_test.go
+++ b/octopusdeploy_framework/datasource_tenants_test.go
@@ -1,13 +1,12 @@
-package octopusdeploy
+package octopusdeploy_framework
import (
"fmt"
+ "github.com/hashicorp/terraform-plugin-testing/helper/acctest"
+ "github.com/hashicorp/terraform-plugin-testing/helper/resource"
+ "github.com/hashicorp/terraform-plugin-testing/terraform"
"strconv"
"testing"
-
- "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest"
- "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
- "github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
)
func TestAccDataSourceTenants(t *testing.T) {
@@ -17,7 +16,7 @@ func TestAccDataSourceTenants(t *testing.T) {
take := acctest.RandIntRange(0, 100)
resource.Test(t, resource.TestCase{
- PreCheck: func() { testAccPreCheck(t) },
+ PreCheck: func() { TestAccPreCheck(t) },
ProtoV6ProviderFactories: ProtoV6ProviderFactories(),
Steps: []resource.TestStep{
{
diff --git a/octopusdeploy_framework/framework_provider.go b/octopusdeploy_framework/framework_provider.go
index 447f66237..95bf6c0a1 100644
--- a/octopusdeploy_framework/framework_provider.go
+++ b/octopusdeploy_framework/framework_provider.go
@@ -2,9 +2,9 @@ package octopusdeploy_framework
import (
"context"
- "github.com/OctopusDeploy/terraform-provider-octopusdeploy/octopusdeploy_framework/util"
"os"
+ "github.com/OctopusDeploy/terraform-provider-octopusdeploy/octopusdeploy_framework/util"
"github.com/hashicorp/terraform-plugin-framework/datasource"
"github.com/hashicorp/terraform-plugin-framework/provider"
"github.com/hashicorp/terraform-plugin-framework/provider/schema"
@@ -70,6 +70,7 @@ func (p *octopusDeployFrameworkProvider) DataSources(ctx context.Context) []func
NewLibraryVariableSetDataSource,
NewVariablesDataSource,
NewProjectsDataSource,
+ NewTenantsDataSource,
}
}
diff --git a/octopusdeploy_framework/schemas/environment.go b/octopusdeploy_framework/schemas/environment.go
index 964532446..6ab91f49d 100644
--- a/octopusdeploy_framework/schemas/environment.go
+++ b/octopusdeploy_framework/schemas/environment.go
@@ -27,21 +27,20 @@ const (
func GetEnvironmentDatasourceSchema() map[string]datasourceSchema.Attribute {
return map[string]datasourceSchema.Attribute{
- "id": util.GetIdDatasourceSchema(),
- "slug": util.GetSlugDatasourceSchema(EnvironmentResourceDescription),
- "name": util.GetNameDatasourceWithMaxLengthSchema(true, 50),
+ "id": GetIdDatasourceSchema(true),
+ "slug": util.GetSlugDatasourceSchema(EnvironmentResourceDescription, true),
+ "name": GetReadonlyNameDatasourceSchema(),
"description": util.GetDescriptionDatasourceSchema(EnvironmentResourceDescription),
EnvironmentSortOrder: util.GetSortOrderDataSourceSchema(EnvironmentResourceDescription),
EnvironmentAllowDynamicInfrastructure: datasourceSchema.BoolAttribute{
- Optional: true,
+ Computed: true,
},
EnvironmentUseGuidedFailure: datasourceSchema.BoolAttribute{
- Optional: true,
+ Computed: true,
},
- "space_id": util.GetSpaceIdDatasourceSchema(EnvironmentResourceDescription),
+ "space_id": GetSpaceIdDatasourceSchema(EnvironmentResourceDescription, true),
EnvironmentJiraExtensionSettings: datasourceSchema.ListNestedAttribute{
Description: "Provides extension settings for the Jira integration for this environment.",
- Optional: true,
Computed: true,
NestedObject: datasourceSchema.NestedAttributeObject{
Attributes: map[string]datasourceSchema.Attribute{
@@ -62,7 +61,6 @@ func GetEnvironmentDatasourceSchema() map[string]datasourceSchema.Attribute {
},
EnvironmentJiraServiceManagementExtensionSettings: datasourceSchema.ListNestedAttribute{
Description: "Provides extension settings for the Jira Service Management (JSM) integration for this environment.",
- Optional: true,
Computed: true,
NestedObject: datasourceSchema.NestedAttributeObject{
Attributes: map[string]datasourceSchema.Attribute{
@@ -72,7 +70,6 @@ func GetEnvironmentDatasourceSchema() map[string]datasourceSchema.Attribute {
},
EnvironmentServiceNowExtensionSettings: datasourceSchema.ListNestedAttribute{
Description: "Provides extension settings for the ServiceNow integration for this environment.",
- Optional: true,
Computed: true,
NestedObject: datasourceSchema.NestedAttributeObject{
Attributes: map[string]datasourceSchema.Attribute{
diff --git a/octopusdeploy_framework/schemas/feed.go b/octopusdeploy_framework/schemas/feed.go
index 60a084e64..61b01ae23 100644
--- a/octopusdeploy_framework/schemas/feed.go
+++ b/octopusdeploy_framework/schemas/feed.go
@@ -78,10 +78,10 @@ func GetFeedsDataSourceSchema() map[string]datasourceSchema.Attribute {
"partial_name": util.GetQueryPartialNameDatasourceSchema(),
"skip": util.GetQuerySkipDatasourceSchema(),
"take": util.GetQueryTakeDatasourceSchema(),
- "space_id": util.GetSpaceIdDatasourceSchema("feeds"),
+ "space_id": GetSpaceIdDatasourceSchema("feeds", false),
// response
- "id": util.GetIdDatasourceSchema(),
+ "id": GetIdDatasourceSchema(true),
}
}
@@ -89,7 +89,7 @@ func GetFeedDataSourceSchema() map[string]datasourceSchema.Attribute {
return map[string]datasourceSchema.Attribute{
"feed_type": datasourceSchema.StringAttribute{
Description: "A filter to search by feed type. Valid feed types are `AwsElasticContainerRegistry`, `BuiltIn`, `Docker`, `GitHub`, `Helm`, `Maven`, `NuGet`, or `OctopusProject`.",
- Optional: true,
+ Computed: true,
Validators: []validator.String{
stringvalidator.OneOf(
"AwsElasticContainerRegistry",
@@ -103,17 +103,17 @@ func GetFeedDataSourceSchema() map[string]datasourceSchema.Attribute {
},
},
"feed_uri": datasourceSchema.StringAttribute{
- Required: true,
+ Computed: true,
},
- "id": util.GetIdDatasourceSchema(),
+ "id": GetIdDatasourceSchema(true),
"is_enhanced_mode": datasourceSchema.BoolAttribute{
- Optional: true,
+ Computed: true,
},
- "name": util.GetNameDatasourceSchema(true),
+ "name": GetReadonlyNameDatasourceSchema(),
"password": datasourceSchema.StringAttribute{
Description: "The password associated with this resource.",
Sensitive: true,
- Optional: true,
+ Computed: true,
Validators: []validator.String{
stringvalidator.LengthAtLeast(1),
},
@@ -121,45 +121,42 @@ func GetFeedDataSourceSchema() map[string]datasourceSchema.Attribute {
"package_acquisition_location_options": datasourceSchema.ListAttribute{
Computed: true,
ElementType: types.StringType,
- Optional: true,
},
"region": datasourceSchema.StringAttribute{
Computed: true,
},
"registry_path": datasourceSchema.StringAttribute{
- Optional: true,
+ Computed: true,
},
"secret_key": datasourceSchema.StringAttribute{
- Optional: true,
+ Computed: true,
Sensitive: true,
},
- "space_id": util.GetSpaceIdDatasourceSchema("feeds"),
+ "space_id": GetSpaceIdDatasourceSchema("feeds", true),
"username": datasourceSchema.StringAttribute{
Description: "The username associated with this resource.",
Sensitive: true,
- Optional: true,
+ Computed: true,
Validators: []validator.String{
stringvalidator.LengthAtLeast(1),
},
},
"delete_unreleased_packages_after_days": datasourceSchema.Int64Attribute{
- Optional: true,
+ Computed: true,
},
"access_key": datasourceSchema.StringAttribute{
- Required: true,
+ Computed: true,
Description: "The AWS access key to use when authenticating against Amazon Web Services.",
},
"api_version": datasourceSchema.StringAttribute{
- Optional: true,
+ Computed: true,
},
"download_attempts": datasourceSchema.Int64Attribute{
Description: "The number of times a deployment should attempt to download a package from this feed before failing.",
- Optional: true,
Computed: true,
},
"download_retry_backoff_seconds": datasourceSchema.Int64Attribute{
Description: "The number of seconds to apply as a linear back off between download attempts.",
- Optional: true,
Computed: true,
},
}
diff --git a/octopusdeploy_framework/schemas/library_variable_set.go b/octopusdeploy_framework/schemas/library_variable_set.go
index 3ca65b627..76ba84d14 100644
--- a/octopusdeploy_framework/schemas/library_variable_set.go
+++ b/octopusdeploy_framework/schemas/library_variable_set.go
@@ -42,8 +42,8 @@ func getLibraryVariableSetDataSchema() map[string]datasourceSchema.Attribute {
Description: "A filter to search by content type.",
Optional: true,
},
- "id": util.GetIdDatasourceSchema(),
- "space_id": util.GetSpaceIdDatasourceSchema("library variable set"),
+ "id": GetIdDatasourceSchema(true),
+ "space_id": GetSpaceIdDatasourceSchema("library variable set", false),
"ids": util.GetQueryIDsDatasourceSchema(),
"partial_name": util.GetQueryPartialNameDatasourceSchema(),
"skip": util.GetQuerySkipDatasourceSchema(),
@@ -53,16 +53,16 @@ func getLibraryVariableSetDataSchema() map[string]datasourceSchema.Attribute {
func GetLibraryVariableSetObjectDatasourceSchema() map[string]datasourceSchema.Attribute {
return map[string]datasourceSchema.Attribute{
- "description": GetDescriptionDatasourceSchema("library variable set"),
- "id": GetIdDatasourceSchema(),
- "name": GetNameDatasourceSchema(false),
- "space_id": GetSpaceIdDatasourceSchema("library variable set"),
+ "description": GetReadonlyDescriptionDatasourceSchema("library variable set"),
+ "id": GetIdDatasourceSchema(true),
+ "name": GetReadonlyNameDatasourceSchema(),
+ "space_id": GetSpaceIdDatasourceSchema("library variable set", true),
"template_ids": datasourceSchema.MapAttribute{
ElementType: types.StringType,
Computed: true,
},
"template": datasourceSchema.ListAttribute{
- Optional: true,
+ Computed: true,
ElementType: types.ObjectType{AttrTypes: TemplateObjectType()},
},
"variable_set_id": datasourceSchema.StringAttribute{
diff --git a/octopusdeploy_framework/schemas/project_group.go b/octopusdeploy_framework/schemas/project_group.go
index bafc5ea42..27b42acfd 100644
--- a/octopusdeploy_framework/schemas/project_group.go
+++ b/octopusdeploy_framework/schemas/project_group.go
@@ -15,7 +15,7 @@ func GetProjectGroupDatasourceSchema() map[string]datasourceSchema.Attribute {
return map[string]datasourceSchema.Attribute{
"id": util.GetIdResourceSchema(),
"space_id": util.GetSpaceIdResourceSchema(projectGroupDescription),
- "name": util.GetNameResourceSchema(true),
+ "name": GetReadonlyNameDatasourceSchema(),
"retention_policy_id": datasourceSchema.StringAttribute{
Computed: true,
Optional: true,
diff --git a/octopusdeploy_framework/schemas/schema.go b/octopusdeploy_framework/schemas/schema.go
index 395aefc7f..496dbc913 100644
--- a/octopusdeploy_framework/schemas/schema.go
+++ b/octopusdeploy_framework/schemas/schema.go
@@ -5,7 +5,6 @@ import (
"github.com/hashicorp/terraform-plugin-framework/resource/schema/booldefault"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault"
-
//"github.com/OctopusDeploy/terraform-provider-octopusdeploy/octopusdeploy_framework"
"github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
@@ -56,20 +55,41 @@ func GetQueryTakeDatasourceSchema() datasourceSchema.Attribute {
}
}
-func GetIdDatasourceSchema() datasourceSchema.Attribute {
+func GetReadonlyNameDatasourceSchema() datasourceSchema.Attribute {
return datasourceSchema.StringAttribute{
- Description: "The unique ID for this resource.",
+ Description: "The name of this resource.",
Computed: true,
- Optional: true,
}
}
-func GetSpaceIdDatasourceSchema(resourceDescription string) datasourceSchema.Attribute {
- return datasourceSchema.StringAttribute{
+func GetIdDatasourceSchema(isReadOnly bool) datasourceSchema.Attribute {
+ s := datasourceSchema.StringAttribute{
+ Description: "The unique ID for this resource.",
+ }
+
+ if isReadOnly {
+ s.Computed = true
+ } else {
+ s.Computed = true
+ s.Optional = true
+ }
+
+ return s
+}
+
+func GetSpaceIdDatasourceSchema(resourceDescription string, isReadOnly bool) datasourceSchema.Attribute {
+ s := datasourceSchema.StringAttribute{
Description: "The space ID associated with this " + resourceDescription + ".",
- Computed: true,
- Optional: true,
}
+
+ if isReadOnly {
+ s.Computed = true
+ } else {
+ s.Computed = true
+ s.Optional = true
+ }
+
+ return s
}
func GetNameDatasourceWithMaxLengthSchema(isRequired bool, maxLength int) datasourceSchema.Attribute {
@@ -113,6 +133,13 @@ func GetDescriptionDatasourceSchema(resourceDescription string) datasourceSchema
}
}
+func GetReadonlyDescriptionDatasourceSchema(resourceDescription string) datasourceSchema.Attribute {
+ return datasourceSchema.StringAttribute{
+ Description: "The description of this " + resourceDescription + ".",
+ Computed: true,
+ }
+}
+
func GetIdResourceSchema() resourceSchema.Attribute {
return resourceSchema.StringAttribute{
Description: "The unique ID for this resource.",
@@ -155,12 +182,19 @@ func GetDescriptionResourceSchema(resourceDescription string) resourceSchema.Att
}
}
-func GetSlugDatasourceSchema(resourceDescription string) datasourceSchema.Attribute {
- return datasourceSchema.StringAttribute{
+func GetSlugDatasourceSchema(resourceDescription string, isReadOnly bool) datasourceSchema.Attribute {
+ s := datasourceSchema.StringAttribute{
Description: fmt.Sprintf("The unique slug of this %s", resourceDescription),
- Optional: true,
- Computed: true,
}
+
+ if isReadOnly {
+ s.Computed = true
+ } else {
+ s.Optional = true
+ s.Computed = true
+ }
+
+ return s
}
func GetSlugResourceSchema(resourceDescription string) resourceSchema.Attribute {
diff --git a/octopusdeploy_framework/schemas/space.go b/octopusdeploy_framework/schemas/space.go
index 662a95c96..0c1159553 100644
--- a/octopusdeploy_framework/schemas/space.go
+++ b/octopusdeploy_framework/schemas/space.go
@@ -1,10 +1,13 @@
package schemas
import (
+ "fmt"
+ "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
"github.com/hashicorp/terraform-plugin-framework/attr"
datasourceSchema "github.com/hashicorp/terraform-plugin-framework/datasource/schema"
resourceSchema "github.com/hashicorp/terraform-plugin-framework/resource/schema"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/booldefault"
+ "github.com/hashicorp/terraform-plugin-framework/schema/validator"
"github.com/hashicorp/terraform-plugin-framework/types"
)
@@ -57,29 +60,33 @@ func GetSpaceResourceSchema() map[string]resourceSchema.Attribute {
func GetSpaceDatasourceSchema() map[string]datasourceSchema.Attribute {
return map[string]datasourceSchema.Attribute{
- "id": GetIdDatasourceSchema(),
- "description": GetDescriptionDatasourceSchema(spaceDescription),
- "name": GetNameDatasourceWithMaxLengthSchema(true, 20),
- "slug": GetSlugDatasourceSchema(spaceDescription),
+ "id": GetIdDatasourceSchema(true),
+ "description": GetReadonlyDescriptionDatasourceSchema(spaceDescription),
+ "name": datasourceSchema.StringAttribute{
+ Description: fmt.Sprintf("The name of this resource, no more than %d characters long", 20),
+ Validators: []validator.String{
+ stringvalidator.LengthBetween(1, 20),
+ },
+ Required: true,
+ },
+ "slug": GetSlugDatasourceSchema(spaceDescription, true),
"space_managers_teams": datasourceSchema.SetAttribute{
ElementType: types.StringType,
Description: "A list of team IDs designated to be managers of this space.",
- Optional: true,
Computed: true,
},
"space_managers_team_members": datasourceSchema.SetAttribute{
ElementType: types.StringType,
Description: "A list of user IDs designated to be managers of this space.",
- Optional: true,
Computed: true,
},
"is_task_queue_stopped": datasourceSchema.BoolAttribute{
Description: "Specifies the status of the task queue for this space.",
- Optional: true,
+ Computed: true,
},
"is_default": datasourceSchema.BoolAttribute{
Description: "Specifies if this space is the default space in Octopus.",
- Optional: true,
+ Computed: true,
},
}
}
diff --git a/octopusdeploy_framework/schemas/tenant.go b/octopusdeploy_framework/schemas/tenant.go
new file mode 100644
index 000000000..41d55b7d1
--- /dev/null
+++ b/octopusdeploy_framework/schemas/tenant.go
@@ -0,0 +1,107 @@
+package schemas
+
+import (
+ "github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/tenants"
+ "github.com/OctopusDeploy/terraform-provider-octopusdeploy/octopusdeploy_framework/util"
+ "github.com/hashicorp/terraform-plugin-framework/attr"
+ datasourceSchema "github.com/hashicorp/terraform-plugin-framework/datasource/schema"
+ "github.com/hashicorp/terraform-plugin-framework/types"
+)
+
+type TenantModel struct {
+ ClonedFromTenantId types.String `tfsdk:"cloned_from_tenant_id"`
+ Description types.String `tfsdk:"description"`
+ ID types.String `tfsdk:"id"`
+ Name types.String `tfsdk:"name"`
+ SpaceID types.String `tfsdk:"space_id"`
+ TenantTags types.List `tfsdk:"tenant_tags"`
+}
+
+type TenantsModel struct {
+ ClonedFromTenantId types.String `tfsdk:"cloned_from_tenant_id"`
+ ID types.String `tfsdk:"id"`
+ IDs types.List `tfsdk:"ids"`
+ IsClone types.Bool `tfsdk:"is_clone"`
+ Name types.String `tfsdk:"name"`
+ PartialName types.String `tfsdk:"partial_name"`
+ ProjectId types.String `tfsdk:"project_id"`
+ Skip types.Int64 `tfsdk:"skip"`
+ Tags types.List `tfsdk:"tags"`
+ SpaceID types.String `tfsdk:"space_id"`
+ Tenants types.List `tfsdk:"tenants"`
+ Take types.Int64 `tfsdk:"take"`
+}
+
+func TenantObjectType() map[string]attr.Type {
+ return map[string]attr.Type{
+ "cloned_from_tenant_id": types.StringType,
+ "description": types.StringType,
+ "id": types.StringType,
+ "name": types.StringType,
+ "space_id": types.StringType,
+ "tenant_tags": types.ListType{ElemType: types.StringType},
+ }
+}
+
+func FlattenTenant(tenant *tenants.Tenant) attr.Value {
+ tenantTags := make([]attr.Value, len(tenant.TenantTags))
+ for i, value := range tenant.TenantTags {
+ tenantTags[i] = types.StringValue(value)
+ }
+ var tenantTagsList, _ = types.ListValue(types.StringType, tenantTags)
+
+ return types.ObjectValueMust(TenantObjectType(), map[string]attr.Value{
+ "cloned_from_tenant_id": types.StringValue(tenant.ClonedFromTenantID),
+ "description": types.StringValue(tenant.Description),
+ "id": types.StringValue(tenant.GetID()),
+ "name": types.StringValue(tenant.Name),
+ "space_id": types.StringValue(tenant.SpaceID),
+ "tenant_tags": tenantTagsList,
+ })
+}
+
+func GetTenantsDataSourceSchema() map[string]datasourceSchema.Attribute {
+ return map[string]datasourceSchema.Attribute{
+ "cloned_from_tenant_id": datasourceSchema.StringAttribute{
+ Description: "A filter to search for a cloned tenant by its ID.",
+ Optional: true,
+ },
+ "id": GetIdDatasourceSchema(true),
+ "ids": util.GetQueryIDsDatasourceSchema(),
+ "is_clone": datasourceSchema.BoolAttribute{
+ Description: "A filter to search for cloned resources.",
+ Optional: true,
+ },
+ "name": datasourceSchema.StringAttribute{
+ Description: "A filter to search by name.",
+ Optional: true,
+ },
+ "partial_name": util.GetQueryPartialNameDatasourceSchema(),
+ "project_id": datasourceSchema.StringAttribute{
+ Description: "A filter to search by a project ID.",
+ Optional: true,
+ },
+ "skip": util.GetQuerySkipDatasourceSchema(),
+ "tags": util.GetQueryDatasourceTags(),
+ "space_id": GetSpaceIdDatasourceSchema("tenants", false),
+ "take": util.GetQueryTakeDatasourceSchema(),
+ }
+}
+
+func GetTenantDataSourceSchema() map[string]datasourceSchema.Attribute {
+ return map[string]datasourceSchema.Attribute{
+ "cloned_from_tenant_id": datasourceSchema.StringAttribute{
+ Description: "The ID of the tenant from which this tenant was cloned.",
+ Computed: true,
+ },
+ "description": util.GetDescriptionDatasourceSchema("tenants"),
+ "id": GetIdDatasourceSchema(true),
+ "name": GetReadonlyNameDatasourceSchema(),
+ "space_id": GetSpaceIdDatasourceSchema("tenant", true),
+ "tenant_tags": datasourceSchema.ListAttribute{
+ Computed: true,
+ Description: "A list of tenant tags associated with this resource.",
+ ElementType: types.StringType,
+ },
+ }
+}
diff --git a/octopusdeploy_framework/testing_container_test.go b/octopusdeploy_framework/testing_container_test.go
index a876440fd..49319d02e 100644
--- a/octopusdeploy_framework/testing_container_test.go
+++ b/octopusdeploy_framework/testing_container_test.go
@@ -28,7 +28,7 @@ func TestMain(m *testing.M) {
if *createSharedContainer {
testFramework := test.OctopusContainerTest{}
- octoContainer, octoClient, sqlServerContainer, network, err = testFramework.ArrangeContainer(m)
+ octoContainer, octoClient, sqlServerContainer, network, err = testFramework.ArrangeContainer()
if err != nil {
log.Printf("Failed to arrange containers: (%s)", err.Error())
}
diff --git a/octopusdeploy_framework/util/schema.go b/octopusdeploy_framework/util/schema.go
index 433892367..d8108b803 100644
--- a/octopusdeploy_framework/util/schema.go
+++ b/octopusdeploy_framework/util/schema.go
@@ -60,22 +60,6 @@ func GetQueryTakeDatasourceSchema() datasourceSchema.Attribute {
}
}
-func GetIdDatasourceSchema() datasourceSchema.Attribute {
- return datasourceSchema.StringAttribute{
- Description: "The unique ID for this resource.",
- Computed: true,
- Optional: true,
- }
-}
-
-func GetSpaceIdDatasourceSchema(resourceDescription string) datasourceSchema.Attribute {
- return datasourceSchema.StringAttribute{
- Description: "The space ID associated with this " + resourceDescription + ".",
- Computed: true,
- Optional: true,
- }
-}
-
func GetNameDatasourceWithMaxLengthSchema(isRequired bool, maxLength int) datasourceSchema.Attribute {
s := datasourceSchema.StringAttribute{
Description: fmt.Sprintf("The name of this resource, no more than %d characters long", maxLength),
@@ -117,6 +101,14 @@ func GetDescriptionDatasourceSchema(resourceDescription string) datasourceSchema
}
}
+func GetQueryDatasourceTags() datasourceSchema.Attribute {
+ return datasourceSchema.ListAttribute{
+ Description: "A filter to search by a list of tags.",
+ ElementType: types.StringType,
+ Optional: true,
+ }
+}
+
func GetIdResourceSchema() resourceSchema.Attribute {
return resourceSchema.StringAttribute{
Description: "The unique ID for this resource.",
@@ -165,12 +157,19 @@ func GetDescriptionResourceSchema(resourceDescription string) resourceSchema.Att
}
}
-func GetSlugDatasourceSchema(resourceDescription string) resourceSchema.Attribute {
- return resourceSchema.StringAttribute{
+func GetSlugDatasourceSchema(resourceDescription string, isReadOnly bool) datasourceSchema.Attribute {
+ s := datasourceSchema.StringAttribute{
Description: fmt.Sprintf("The unique slug of this %s", resourceDescription),
- Optional: true,
- Computed: true,
}
+
+ if isReadOnly {
+ s.Computed = true
+ } else {
+ s.Optional = true
+ s.Computed = true
+ }
+
+ return s
}
func GetSlugResourceSchema(resourceDescription string) resourceSchema.Attribute {
@@ -184,7 +183,6 @@ func GetSlugResourceSchema(resourceDescription string) resourceSchema.Attribute
func GetSortOrderDataSourceSchema(resourceDescription string) resourceSchema.Attribute {
return resourceSchema.Int64Attribute{
Description: fmt.Sprintf("The order number to sort an %s", resourceDescription),
- Optional: true,
Computed: true,
}
}
From e5533e062c96133ee8e1c084bf7a77cea5cea18e Mon Sep 17 00:00:00 2001
From: Henrik Andersson
Date: Fri, 9 Aug 2024 00:55:57 -0700
Subject: [PATCH 07/12] chore: update environment resource and datasource docs
(#708)
---
docs/resources/environment.md | 17 ++++---
.../schemas/environment.go | 51 ++++++++++++++-----
octopusdeploy_framework/util/schema.go | 3 +-
3 files changed, 49 insertions(+), 22 deletions(-)
diff --git a/docs/resources/environment.md b/docs/resources/environment.md
index c9f9c5d1e..22b847d57 100644
--- a/docs/resources/environment.md
+++ b/docs/resources/environment.md
@@ -3,12 +3,12 @@
page_title: "octopusdeploy_environment Resource - terraform-provider-octopusdeploy"
subcategory: ""
description: |-
-
+ This resource manages environments in Octopus Deploy.
---
# octopusdeploy_environment (Resource)
-
+This resource manages environments in Octopus Deploy.
## Example Usage
@@ -48,17 +48,20 @@ resource "octopusdeploy_environment" "example" {
- `jira_extension_settings` (Block List) Provides extension settings for the Jira integration for this environment. (see [below for nested schema](#nestedblock--jira_extension_settings))
- `jira_service_management_extension_settings` (Block List) Provides extension settings for the Jira Service Management (JSM) integration for this environment. (see [below for nested schema](#nestedblock--jira_service_management_extension_settings))
- `servicenow_extension_settings` (Block List) Provides extension settings for the ServiceNow integration for this environment. (see [below for nested schema](#nestedblock--servicenow_extension_settings))
-- `slug` (String) The unique slug of this environment
-- `sort_order` (Number) The order number to sort an environment
+- `sort_order` (Number) The order number to sort an environment.
- `space_id` (String) The space ID associated with this environment.
- `use_guided_failure` (Boolean)
+### Read-Only
+
+- `slug` (String) The unique slug of this environment
+
### Nested Schema for `jira_extension_settings`
Optional:
-- `environment_type` (String)
+- `environment_type` (String) The Jira environment type of this Octopus deployment environment. Valid values are `"development"`, `"production"`, `"staging"`, `"testing"`, `"unmapped"`.
@@ -66,7 +69,7 @@ Optional:
Optional:
-- `is_enabled` (Boolean)
+- `is_enabled` (Boolean) Specifies whether or not this extension is enabled for this project.
@@ -74,7 +77,7 @@ Optional:
Optional:
-- `is_enabled` (Boolean)
+- `is_enabled` (Boolean) Specifies whether or not this extension is enabled for this project.
## Import
diff --git a/octopusdeploy_framework/schemas/environment.go b/octopusdeploy_framework/schemas/environment.go
index 6ab91f49d..ed57bba65 100644
--- a/octopusdeploy_framework/schemas/environment.go
+++ b/octopusdeploy_framework/schemas/environment.go
@@ -1,6 +1,9 @@
package schemas
import (
+ "fmt"
+ "strings"
+
"github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/environments"
"github.com/OctopusDeploy/terraform-provider-octopusdeploy/octopusdeploy_framework/util"
"github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
@@ -25,6 +28,28 @@ const (
EnvironmentServiceNowExtensionSettingsIsEnabled = "is_enabled"
)
+var jiraEnvironmentTypeNames = struct {
+ Development string
+ Production string
+ Testing string
+ Staging string
+ Unmapped string
+}{
+ Development: "development",
+ Production: "production",
+ Testing: "testing",
+ Staging: "staging",
+ Unmapped: "unmapped",
+}
+
+var jiraEnvironmentTypes = []string{
+ jiraEnvironmentTypeNames.Development,
+ jiraEnvironmentTypeNames.Production,
+ jiraEnvironmentTypeNames.Staging,
+ jiraEnvironmentTypeNames.Testing,
+ jiraEnvironmentTypeNames.Unmapped,
+}
+
func GetEnvironmentDatasourceSchema() map[string]datasourceSchema.Attribute {
return map[string]datasourceSchema.Attribute{
"id": GetIdDatasourceSchema(true),
@@ -48,11 +73,7 @@ func GetEnvironmentDatasourceSchema() map[string]datasourceSchema.Attribute {
Computed: true,
Validators: []validator.String{
stringvalidator.OneOfCaseInsensitive(
- "development",
- "production",
- "testing",
- "staging",
- "unmapped",
+ jiraEnvironmentTypes...,
),
},
},
@@ -82,6 +103,7 @@ func GetEnvironmentDatasourceSchema() map[string]datasourceSchema.Attribute {
func GetEnvironmentResourceSchema() resourceSchema.Schema {
return resourceSchema.Schema{
+ Description: util.GetResourceSchemaDescription(EnvironmentResourceDescription),
Attributes: map[string]resourceSchema.Attribute{
"id": util.GetIdResourceSchema(),
"slug": util.GetSlugResourceSchema(EnvironmentResourceDescription),
@@ -106,14 +128,11 @@ func GetEnvironmentResourceSchema() resourceSchema.Schema {
NestedObject: resourceSchema.NestedBlockObject{
Attributes: map[string]resourceSchema.Attribute{
"environment_type": resourceSchema.StringAttribute{
- Optional: true,
+ Description: fmt.Sprintf("The Jira environment type of this Octopus deployment environment. Valid values are %s.", strings.Join(util.Map(jiraEnvironmentTypes, func(item string) string { return fmt.Sprintf("`\"%s\"`", item) }), ", ")),
+ Optional: true,
Validators: []validator.String{
stringvalidator.OneOfCaseInsensitive(
- "development",
- "production",
- "staging",
- "testing",
- "unmapped",
+ jiraEnvironmentTypes...,
),
},
},
@@ -124,7 +143,10 @@ func GetEnvironmentResourceSchema() resourceSchema.Schema {
Description: "Provides extension settings for the Jira Service Management (JSM) integration for this environment.",
NestedObject: resourceSchema.NestedBlockObject{
Attributes: map[string]resourceSchema.Attribute{
- "is_enabled": resourceSchema.BoolAttribute{Optional: true},
+ "is_enabled": resourceSchema.BoolAttribute{
+ Description: "Specifies whether or not this extension is enabled for this project.",
+ Optional: true,
+ },
},
},
},
@@ -132,7 +154,10 @@ func GetEnvironmentResourceSchema() resourceSchema.Schema {
Description: "Provides extension settings for the ServiceNow integration for this environment.",
NestedObject: resourceSchema.NestedBlockObject{
Attributes: map[string]resourceSchema.Attribute{
- "is_enabled": resourceSchema.BoolAttribute{Optional: true},
+ "is_enabled": resourceSchema.BoolAttribute{
+ Description: "Specifies whether or not this extension is enabled for this project.",
+ Optional: true,
+ },
},
},
},
diff --git a/octopusdeploy_framework/util/schema.go b/octopusdeploy_framework/util/schema.go
index d8108b803..26856a9da 100644
--- a/octopusdeploy_framework/util/schema.go
+++ b/octopusdeploy_framework/util/schema.go
@@ -175,7 +175,6 @@ func GetSlugDatasourceSchema(resourceDescription string, isReadOnly bool) dataso
func GetSlugResourceSchema(resourceDescription string) resourceSchema.Attribute {
return resourceSchema.StringAttribute{
Description: fmt.Sprintf("The unique slug of this %s", resourceDescription),
- Optional: true,
Computed: true,
}
}
@@ -189,7 +188,7 @@ func GetSortOrderDataSourceSchema(resourceDescription string) resourceSchema.Att
func GetSortOrderResourceSchema(resourceDescription string) resourceSchema.Attribute {
return resourceSchema.Int64Attribute{
- Description: fmt.Sprintf("The order number to sort an %s", resourceDescription),
+ Description: fmt.Sprintf("The order number to sort an %s.", resourceDescription),
Optional: true,
Computed: true,
}
From 04b191762f5773a3b62386be37391d58dc51021b Mon Sep 17 00:00:00 2001
From: Isaac Calligeros <101079287+IsaacCalligeros95@users.noreply.github.com>
Date: Mon, 12 Aug 2024 10:35:34 +0930
Subject: [PATCH 08/12] Chore!: Require updated docs (#697)
* Adds a GHA to require no docs differences between generated and checked in
---
.github/workflows/docs.yml | 19 +++++++++++++++++++
1 file changed, 19 insertions(+)
create mode 100644 .github/workflows/docs.yml
diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml
new file mode 100644
index 000000000..2e2328067
--- /dev/null
+++ b/.github/workflows/docs.yml
@@ -0,0 +1,19 @@
+name: Validate Docs
+on:
+ push:
+ branches:
+ - '**'
+ workflow_dispatch:
+jobs:
+ build:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v3
+ with:
+ fetch-depth: 0
+ - uses: actions/setup-go@v3
+ with:
+ go-version: '1.22'
+ - run: go generate main.go
+ - name: Check for file changes
+ run: git diff --exit-code
From c595415a729f483b16006da13967325bdc5fc900 Mon Sep 17 00:00:00 2001
From: Henrik Andersson
Date: Sun, 11 Aug 2024 20:38:43 -0700
Subject: [PATCH 09/12] chore!: migrate runbook resource to tf framework (#709)
---
docs/resources/runbook.md | 10 +-
octopusdeploy/provider.go | 1 -
octopusdeploy/resource_runbook.go | 104 -------
octopusdeploy/resource_runbook_process.go | 3 +-
octopusdeploy/schema_runbook.go | 176 -----------
.../schema_runbook_retention_period.go | 50 ---
octopusdeploy_framework/framework_provider.go | 1 +
octopusdeploy_framework/resource_project.go | 2 +-
octopusdeploy_framework/resource_runbook.go | 179 +++++++++++
.../resource_runbook_migration_test.go | 121 ++++++++
.../resource_runbook_test.go | 7 +-
.../schemas/connectivity_policy.go | 142 +++++++++
octopusdeploy_framework/schemas/runbook.go | 288 ++++++++++++++++++
.../schemas/runbook_retention_period.go | 99 ++++++
octopusdeploy_framework/util/logging.go | 25 ++
15 files changed, 867 insertions(+), 341 deletions(-)
delete mode 100644 octopusdeploy/resource_runbook.go
delete mode 100644 octopusdeploy/schema_runbook.go
delete mode 100644 octopusdeploy/schema_runbook_retention_period.go
create mode 100644 octopusdeploy_framework/resource_runbook.go
create mode 100644 octopusdeploy_framework/resource_runbook_migration_test.go
rename octopusdeploy/resource_runbook_process_test.go => octopusdeploy_framework/resource_runbook_test.go (99%)
create mode 100644 octopusdeploy_framework/schemas/connectivity_policy.go
create mode 100644 octopusdeploy_framework/schemas/runbook.go
create mode 100644 octopusdeploy_framework/schemas/runbook_retention_period.go
diff --git a/docs/resources/runbook.md b/docs/resources/runbook.md
index b540fd6e7..09b12e7b3 100644
--- a/docs/resources/runbook.md
+++ b/docs/resources/runbook.md
@@ -22,16 +22,16 @@ This resource manages runbooks in Octopus Deploy.
### Optional
-- `connectivity_policy` (Block List, Max: 1) (see [below for nested schema](#nestedblock--connectivity_policy))
+- `connectivity_policy` (Block List) (see [below for nested schema](#nestedblock--connectivity_policy))
- `default_guided_failure_mode` (String) Sets the runbook guided failure mode.
- `description` (String) The description of this runbook.
- `environment_scope` (String) Determines how the runbook is scoped to environments.
- `environments` (List of String) When environment_scope is set to "Specified", this is the list of environments the runbook can be run against.
-- `force_package_download` (Boolean) Whether to force packages to be re-downloaded or not
+- `force_package_download` (Boolean) Whether to force packages to be re-downloaded or not.
- `id` (String) The unique ID for this resource.
-- `multi_tenancy_mode` (String) The tenanted deployment mode of the resource. Valid account types are `Untenanted`, `TenantedOrUntenanted`, or `Tenanted`.
-- `retention_policy` (Block List, Max: 1) Sets the runbook retention policy (see [below for nested schema](#nestedblock--retention_policy))
-- `space_id` (String) The space ID associated with this resource.
+- `multi_tenancy_mode` (String) The tenanted deployment mode of the runbook. Valid modes are `Untenanted`, `TenantedOrUntenanted`, `Tenanted`
+- `retention_policy` (Block List) Sets the runbook retention policy. (see [below for nested schema](#nestedblock--retention_policy))
+- `space_id` (String) The space ID associated with this runbook.
### Read-Only
diff --git a/octopusdeploy/provider.go b/octopusdeploy/provider.go
index 6de5657b1..794853fff 100644
--- a/octopusdeploy/provider.go
+++ b/octopusdeploy/provider.go
@@ -58,7 +58,6 @@ func Provider() *schema.Provider {
"octopusdeploy_project_deployment_target_trigger": resourceProjectDeploymentTargetTrigger(),
"octopusdeploy_external_feed_create_release_trigger": resourceExternalFeedCreateReleaseTrigger(),
"octopusdeploy_project_scheduled_trigger": resourceProjectScheduledTrigger(),
- "octopusdeploy_runbook": resourceRunbook(),
"octopusdeploy_runbook_process": resourceRunbookProcess(),
"octopusdeploy_scoped_user_role": resourceScopedUserRole(),
"octopusdeploy_script_module": resourceScriptModule(),
diff --git a/octopusdeploy/resource_runbook.go b/octopusdeploy/resource_runbook.go
deleted file mode 100644
index 7497a1a04..000000000
--- a/octopusdeploy/resource_runbook.go
+++ /dev/null
@@ -1,104 +0,0 @@
-package octopusdeploy
-
-import (
- "context"
- "fmt"
- "github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/runbooks"
-
- "github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/client"
- "github.com/OctopusDeploy/terraform-provider-octopusdeploy/internal/errors"
- "github.com/hashicorp/terraform-plugin-log/tflog"
- "github.com/hashicorp/terraform-plugin-sdk/v2/diag"
- "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
-)
-
-func resourceRunbook() *schema.Resource {
- return &schema.Resource{
- CreateContext: resourceRunbookCreate,
- DeleteContext: resourceRunbookDelete,
- Description: "This resource manages runbooks in Octopus Deploy.",
- Importer: getImporter(),
- ReadContext: resourceRunbookRead,
- Schema: getRunbookSchema(),
- UpdateContext: resourceRunbookUpdate,
- }
-}
-
-func resourceRunbookCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
- runbook := expandRunbook(ctx, d)
-
- tflog.Info(ctx, fmt.Sprintf("creating runbook (%s)", runbook.Name))
-
- client := m.(*client.Client)
- createdRunbook, err := runbooks.Add(client, runbook)
- if err != nil {
- return diag.FromErr(err)
- }
-
- if err := setRunbook(ctx, d, createdRunbook); err != nil {
- return diag.FromErr(err)
- }
-
- d.SetId(createdRunbook.GetID())
-
- tflog.Info(ctx, fmt.Sprintf("runbook created (%s)", d.Id()))
- return nil
-}
-
-func resourceRunbookDelete(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
- tflog.Info(ctx, fmt.Sprintf("deleting runbook (%s)", d.Id()))
-
- client := m.(*client.Client)
- if err := runbooks.DeleteByID(client, d.Get("space_id").(string), d.Id()); err != nil {
- return diag.FromErr(err)
- }
-
- tflog.Info(ctx, fmt.Sprintf("runbook deleted (%s)", d.Id()))
- d.SetId("")
- return nil
-}
-
-func resourceRunbookRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
- tflog.Info(ctx, fmt.Sprintf("reading runbook (%s)", d.Id()))
-
- client := m.(*client.Client)
- runbook, err := runbooks.GetByID(client, d.Get("space_id").(string), d.Id())
- if err != nil {
- return errors.ProcessApiError(ctx, d, err, "runbook")
- }
-
- if err := setRunbook(ctx, d, runbook); err != nil {
- return diag.FromErr(err)
- }
-
- tflog.Info(ctx, fmt.Sprintf("runbook read (%s)", d.Id()))
- return nil
-}
-
-func resourceRunbookUpdate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
- tflog.Info(ctx, fmt.Sprintf("updating runbook (%s)", d.Id()))
-
- client := m.(*client.Client)
- runbook := expandRunbook(ctx, d)
- var updatedRunbook *runbooks.Runbook
- var err error
-
- runbookLinks, err := runbooks.GetByID(client, d.Get("space_id").(string), d.Id())
- if err != nil {
- return diag.FromErr(err)
- }
-
- runbook.Links = runbookLinks.Links
-
- updatedRunbook, err = runbooks.Update(client, runbook)
- if err != nil {
- return diag.FromErr(err)
- }
-
- if err := setRunbook(ctx, d, updatedRunbook); err != nil {
- return diag.FromErr(err)
- }
-
- tflog.Info(ctx, fmt.Sprintf("runbook updated (%s)", d.Id()))
- return nil
-}
diff --git a/octopusdeploy/resource_runbook_process.go b/octopusdeploy/resource_runbook_process.go
index 5ff0fb3ac..8019bd4b5 100644
--- a/octopusdeploy/resource_runbook_process.go
+++ b/octopusdeploy/resource_runbook_process.go
@@ -105,7 +105,8 @@ func resourceRunbookProcessDelete(ctx context.Context, d *schema.ResourceData, m
}
runbookProcess := &runbookprocess.RunbookProcess{
- Version: current.Version,
+ ProjectID: current.ProjectID,
+ Version: current.Version,
}
runbookProcess.Links = current.Links
runbookProcess.ID = d.Id()
diff --git a/octopusdeploy/schema_runbook.go b/octopusdeploy/schema_runbook.go
deleted file mode 100644
index 47ffebba4..000000000
--- a/octopusdeploy/schema_runbook.go
+++ /dev/null
@@ -1,176 +0,0 @@
-package octopusdeploy
-
-import (
- "context"
- "fmt"
- "github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/runbooks"
-
- "github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/core"
- "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
- "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
-)
-
-func expandRunbook(ctx context.Context, d *schema.ResourceData) *runbooks.Runbook {
- name := d.Get("name").(string)
- projectId := d.Get("project_id").(string)
-
- runbook := runbooks.NewRunbook(name, projectId)
- runbook.ID = d.Id()
-
- if v, ok := d.GetOk("description"); ok {
- runbook.Description = v.(string)
- }
-
- if v, ok := d.GetOk("runbook_process_id"); ok {
- runbook.RunbookProcessID = v.(string)
- }
-
- if v, ok := d.GetOk("published_runbook_snapshot_id"); ok {
- runbook.PublishedRunbookSnapshotID = v.(string)
- }
-
- if v, ok := d.GetOk("space_id"); ok {
- runbook.SpaceID = v.(string)
- }
-
- if v, ok := d.GetOk("multi_tenancy_mode"); ok {
- runbook.MultiTenancyMode = core.TenantedDeploymentMode(v.(string))
- }
-
- if v, ok := d.GetOk("connectivity_policy"); ok {
- runbook.ConnectivityPolicy = expandConnectivityPolicy(v.([]interface{}))
- }
-
- if v, ok := d.GetOk("environment_scope"); ok {
- runbook.EnvironmentScope = v.(string)
- }
-
- if v, ok := d.GetOk("environments"); ok {
- runbook.Environments = getSliceFromTerraformTypeList(v)
- }
-
- if v, ok := d.GetOk("default_guided_failure_mode"); ok {
- runbook.DefaultGuidedFailureMode = v.(string)
- }
-
- if v, ok := d.GetOk("retention_policy"); ok {
- runbook.RunRetentionPolicy = expandRunbookRetentionPolicy(v.([]interface{}))
- }
-
- if v, ok := d.GetOk("force_package_download"); ok {
- runbook.ForcePackageDownload = v.(bool)
- }
-
- return runbook
-}
-
-func getRunbookSchema() map[string]*schema.Schema {
- return map[string]*schema.Schema{
- "id": getIDSchema(),
- "name": {
- Description: "The name of the runbook in Octopus Deploy. This name must be unique.",
- Required: true,
- Type: schema.TypeString,
- ValidateDiagFunc: validation.ToDiagFunc(validation.StringIsNotWhiteSpace),
- },
- "description": {
- Computed: true,
- Description: "The description of this runbook.",
- Optional: true,
- Type: schema.TypeString,
- },
- "project_id": {
- Description: "The project that this runbook belongs to.",
- Required: true,
- Type: schema.TypeString,
- },
- "runbook_process_id": {
- Description: "The runbook process ID.",
- Computed: true,
- Type: schema.TypeString,
- },
- "published_runbook_snapshot_id": {
- Description: "The published snapshot ID.",
- Computed: true,
- Type: schema.TypeString,
- },
- "space_id": getSpaceIDSchema(),
- "multi_tenancy_mode": getTenantedDeploymentSchema(),
- "connectivity_policy": {
- Computed: true,
- Elem: &schema.Resource{Schema: getConnectivityPolicySchema()},
- MaxItems: 1,
- Optional: true,
- Type: schema.TypeList,
- },
- "environment_scope": {
- Description: "Determines how the runbook is scoped to environments.",
- Computed: true,
- Optional: true,
- Type: schema.TypeString,
- ValidateDiagFunc: validation.ToDiagFunc(validation.StringInSlice([]string{
- "All",
- "Specified",
- "FromProjectLifecycles",
- }, false)),
- },
- "environments": {
- Description: "When environment_scope is set to \"Specified\", this is the list of environments the runbook can be run against.",
- Computed: true,
- Optional: true,
- Elem: &schema.Schema{Type: schema.TypeString},
- Type: schema.TypeList,
- },
- "default_guided_failure_mode": {
- Description: "Sets the runbook guided failure mode.",
- Computed: true,
- Optional: true,
- Type: schema.TypeString,
- ValidateDiagFunc: validation.ToDiagFunc(validation.StringInSlice([]string{
- "EnvironmentDefault",
- "Off",
- "On",
- }, false)),
- },
- "retention_policy": {
- Description: "Sets the runbook retention policy",
- Computed: true,
- DefaultFunc: func() (interface{}, error) {
- return flattenRunbookRetentionPeriod(&runbooks.RunbookRetentionPeriod{
- QuantityToKeep: 100,
- ShouldKeepForever: false,
- }), nil
- },
- Elem: &schema.Resource{Schema: getRunbookRetentionPeriodSchema()},
- MaxItems: 1,
- Optional: true,
- Type: schema.TypeList,
- },
- "force_package_download": {
- Description: "Whether to force packages to be re-downloaded or not",
- Computed: true,
- Optional: true,
- Type: schema.TypeBool,
- },
- }
-}
-
-func setRunbook(ctx context.Context, d *schema.ResourceData, runbook *runbooks.Runbook) error {
- d.Set("id", runbook.GetID())
- d.Set("name", runbook.Name)
- d.Set("project_id", runbook.ProjectID)
- d.Set("description", runbook.Description)
- d.Set("runbook_process_id", runbook.RunbookProcessID)
- d.Set("published_runbook_snapshot_id", runbook.PublishedRunbookSnapshotID)
- d.Set("space_id", runbook.SpaceID)
- d.Set("multi_tenancy_mode", runbook.MultiTenancyMode)
- if err := d.Set("connectivity_policy", flattenConnectivityPolicy(runbook.ConnectivityPolicy)); err != nil {
- return fmt.Errorf("error setting connectivity_policy: %s", err)
- }
- d.Set("environment_scope", runbook.EnvironmentScope)
- d.Set("environments", runbook.Environments)
- d.Set("default_guided_failure_mode", runbook.DefaultGuidedFailureMode)
- d.Set("force_package_download", runbook.ForcePackageDownload)
-
- return nil
-}
diff --git a/octopusdeploy/schema_runbook_retention_period.go b/octopusdeploy/schema_runbook_retention_period.go
deleted file mode 100644
index 516cada68..000000000
--- a/octopusdeploy/schema_runbook_retention_period.go
+++ /dev/null
@@ -1,50 +0,0 @@
-package octopusdeploy
-
-import (
- "github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/runbooks"
- "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
- "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
-)
-
-func expandRunbookRetentionPolicy(flattenedRetentionPeriod interface{}) *runbooks.RunbookRetentionPeriod {
- if flattenedRetentionPeriod == nil {
- return nil
- }
-
- retentionPeriodProperties := flattenedRetentionPeriod.([]interface{})
- if len(retentionPeriodProperties) == 1 {
- retentionPeriodMap := retentionPeriodProperties[0].(map[string]interface{})
- return &runbooks.RunbookRetentionPeriod{
- QuantityToKeep: int32(retentionPeriodMap["quantity_to_keep"].(int)),
- ShouldKeepForever: retentionPeriodMap["should_keep_forever"].(bool),
- }
- }
-
- return nil
-}
-
-func flattenRunbookRetentionPeriod(r *runbooks.RunbookRetentionPeriod) []interface{} {
- retentionPeriod := make(map[string]interface{})
- retentionPeriod["quantity_to_keep"] = int(r.QuantityToKeep)
- retentionPeriod["should_keep_forever"] = r.ShouldKeepForever
- return []interface{}{retentionPeriod}
-}
-
-func getRunbookRetentionPeriodSchema() map[string]*schema.Schema {
- return map[string]*schema.Schema{
- "quantity_to_keep": {
- Default: 100,
- Description: "How many runs to keep per environment.",
- Optional: true,
- Type: schema.TypeInt,
- ValidateDiagFunc: validation.ToDiagFunc(validation.IntAtLeast(0)),
- },
- "should_keep_forever": {
- Default: false,
- Description: "Indicates if items should never be deleted. The default value is `false`.",
- Optional: true,
- Type: schema.TypeBool,
- ConflictsWith: []string{"retention_policy.quantity_to_keep"},
- },
- }
-}
diff --git a/octopusdeploy_framework/framework_provider.go b/octopusdeploy_framework/framework_provider.go
index 95bf6c0a1..fc1128666 100644
--- a/octopusdeploy_framework/framework_provider.go
+++ b/octopusdeploy_framework/framework_provider.go
@@ -94,6 +94,7 @@ func (p *octopusDeployFrameworkProvider) Resources(ctx context.Context) []func()
NewVariableResource,
NewProjectResource,
NewDockerContainerRegistryFeedResource,
+ NewRunbookResource,
}
}
diff --git a/octopusdeploy_framework/resource_project.go b/octopusdeploy_framework/resource_project.go
index bcefbbf69..7a8ece169 100644
--- a/octopusdeploy_framework/resource_project.go
+++ b/octopusdeploy_framework/resource_project.go
@@ -94,7 +94,7 @@ func (r *projectResource) Read(ctx context.Context, req resource.ReadRequest, re
project, err := projects.GetByID(r.Client, state.SpaceID.ValueString(), state.ID.ValueString())
if err != nil {
- if err := errors.ProcessApiErrorV2(ctx, resp, state, err, "lifecycle"); err != nil {
+ if err := errors.ProcessApiErrorV2(ctx, resp, state, err, "project"); err != nil {
resp.Diagnostics.AddError("Error reading project", err.Error())
}
return
diff --git a/octopusdeploy_framework/resource_runbook.go b/octopusdeploy_framework/resource_runbook.go
new file mode 100644
index 000000000..066f32b13
--- /dev/null
+++ b/octopusdeploy_framework/resource_runbook.go
@@ -0,0 +1,179 @@
+package octopusdeploy_framework
+
+import (
+ "context"
+ "fmt"
+
+ "github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/core"
+ "github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/runbooks"
+ "github.com/OctopusDeploy/terraform-provider-octopusdeploy/internal/errors"
+ "github.com/OctopusDeploy/terraform-provider-octopusdeploy/octopusdeploy_framework/schemas"
+ "github.com/OctopusDeploy/terraform-provider-octopusdeploy/octopusdeploy_framework/util"
+ "github.com/hashicorp/terraform-plugin-framework/path"
+ "github.com/hashicorp/terraform-plugin-framework/resource"
+)
+
+var _ resource.ResourceWithImportState = &runbookTypeResource{}
+
+type runbookTypeResource struct {
+ *Config
+}
+
+func NewRunbookResource() resource.Resource {
+ return &runbookTypeResource{}
+}
+
+func (*runbookTypeResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
+ resp.TypeName = util.GetTypeName(schemas.RunbookResourceDescription)
+}
+
+func (*runbookTypeResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
+ resp.Schema = schemas.GetRunbookResourceSchema()
+}
+
+func (r *runbookTypeResource) Configure(ctx context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
+ r.Config = ResourceConfiguration(req, resp)
+}
+
+func (r *runbookTypeResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
+ var plan schemas.RunbookTypeResourceModel
+ resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
+ if resp.Diagnostics.HasError() {
+ return
+ }
+
+ name := plan.Name.ValueString()
+ projectId := plan.ProjectID.ValueString()
+
+ runbook := runbooks.NewRunbook(name, projectId)
+ if !plan.ID.IsNull() {
+ runbook.ID = plan.ID.ValueString()
+ }
+
+ runbook.Description = plan.Description.ValueString()
+ runbook.RunbookProcessID = plan.RunbookProcessID.ValueString()
+ runbook.PublishedRunbookSnapshotID = plan.PublishedRunbookSnapshotID.ValueString()
+ runbook.SpaceID = plan.SpaceID.ValueString()
+ if !plan.MultiTenancyMode.IsNull() {
+ runbook.MultiTenancyMode = core.TenantedDeploymentMode(plan.MultiTenancyMode.ValueString())
+ }
+ runbook.ConnectivityPolicy = schemas.MapToConnectivityPolicy(plan.ConnectivityPolicy)
+ runbook.EnvironmentScope = plan.EnvironmentScope.ValueString()
+ runbook.Environments = util.ExpandStringList(plan.Environments)
+ runbook.DefaultGuidedFailureMode = plan.DefaultGuidedFailureMode.ValueString()
+ runbook.RunRetentionPolicy = schemas.MapToRunbookRetentionPeriod(plan.RunRetentionPolicy)
+ runbook.ForcePackageDownload = plan.ForcePackageDownload.ValueBool()
+
+ util.Create(ctx, schemas.RunbookResourceDescription, plan)
+
+ createdRunbook, err := runbooks.Add(r.Config.Client, runbook)
+ if err != nil {
+ resp.Diagnostics.AddError(fmt.Sprintf("failed to create runbook (%s)", runbook.Name), err.Error())
+ return
+ }
+
+ resp.Diagnostics.Append(plan.RefreshFromApiResponse(ctx, createdRunbook)...)
+ if resp.Diagnostics.HasError() {
+ return
+ }
+
+ resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
+
+ util.Created(ctx, schemas.RunbookResourceDescription, createdRunbook)
+}
+
+func (r *runbookTypeResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
+ var state schemas.RunbookTypeResourceModel
+ resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
+ if resp.Diagnostics.HasError() {
+ return
+ }
+
+ util.Reading(ctx, schemas.RunbookResourceDescription, state)
+
+ runbook, err := runbooks.GetByID(r.Config.Client, state.SpaceID.ValueString(), state.ID.ValueString())
+ if err != nil {
+ if err := errors.ProcessApiErrorV2(ctx, resp, state, err, schemas.RunbookResourceDescription); err != nil {
+ resp.Diagnostics.AddError("failed to load runbook", err.Error())
+ }
+ return
+ }
+
+ resp.Diagnostics.Append(state.RefreshFromApiResponse(ctx, runbook)...)
+ if resp.Diagnostics.HasError() {
+ return
+ }
+
+ resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
+
+ util.Read(ctx, schemas.RunbookResourceDescription, runbook)
+}
+
+func (r *runbookTypeResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
+ var plan, state schemas.RunbookTypeResourceModel
+ resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
+ resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
+ if resp.Diagnostics.HasError() {
+ return
+ }
+
+ util.Update(ctx, schemas.RunbookResourceDescription, plan)
+
+ runbook, err := runbooks.GetByID(r.Config.Client, state.SpaceID.ValueString(), state.ID.ValueString())
+ if err != nil {
+ resp.Diagnostics.AddError("unable to load runbook", err.Error())
+ return
+ }
+
+ updatedRunbook := runbooks.NewRunbook(plan.Name.ValueString(), plan.ProjectID.ValueString())
+ updatedRunbook.ID = runbook.GetID()
+ updatedRunbook.SpaceID = runbook.SpaceID
+ updatedRunbook.Description = plan.Description.ValueString()
+ updatedRunbook.RunbookProcessID = plan.RunbookProcessID.ValueString()
+ updatedRunbook.PublishedRunbookSnapshotID = plan.PublishedRunbookSnapshotID.ValueString()
+ if !plan.MultiTenancyMode.IsNull() {
+ updatedRunbook.MultiTenancyMode = core.TenantedDeploymentMode(plan.MultiTenancyMode.ValueString())
+ }
+ updatedRunbook.ConnectivityPolicy = schemas.MapToConnectivityPolicy(plan.ConnectivityPolicy)
+ updatedRunbook.EnvironmentScope = plan.EnvironmentScope.ValueString()
+ updatedRunbook.Environments = util.ExpandStringList(plan.Environments)
+ updatedRunbook.DefaultGuidedFailureMode = plan.DefaultGuidedFailureMode.ValueString()
+ updatedRunbook.RunRetentionPolicy = schemas.MapToRunbookRetentionPeriod(plan.RunRetentionPolicy)
+ updatedRunbook.ForcePackageDownload = plan.ForcePackageDownload.ValueBool()
+
+ updatedRunbook, err = runbooks.Update(r.Config.Client, updatedRunbook)
+ if err != nil {
+ resp.Diagnostics.AddError("failed to update runbook", err.Error())
+ }
+
+ resp.Diagnostics.Append(plan.RefreshFromApiResponse(ctx, updatedRunbook)...)
+ if resp.Diagnostics.HasError() {
+ return
+ }
+
+ resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
+
+ util.Updated(ctx, schemas.RunbookResourceDescription, updatedRunbook)
+}
+
+func (*runbookTypeResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
+ resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp)
+}
+
+func (r *runbookTypeResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
+ var state schemas.RunbookTypeResourceModel
+ resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
+ if resp.Diagnostics.HasError() {
+ return
+ }
+
+ util.Delete(ctx, schemas.RunbookResourceDescription, state)
+
+ if err := runbooks.DeleteByID(r.Config.Client, state.SpaceID.ValueString(), state.ID.ValueString()); err != nil {
+ resp.Diagnostics.AddError("failed to delete runbook", err.Error())
+ return
+ }
+
+ util.Deleted(ctx, schemas.RunbookResourceDescription, state)
+ resp.State.RemoveResource(ctx)
+}
diff --git a/octopusdeploy_framework/resource_runbook_migration_test.go b/octopusdeploy_framework/resource_runbook_migration_test.go
new file mode 100644
index 000000000..3eb66928a
--- /dev/null
+++ b/octopusdeploy_framework/resource_runbook_migration_test.go
@@ -0,0 +1,121 @@
+package octopusdeploy_framework
+
+import (
+ "fmt"
+ "os"
+ "testing"
+
+ "github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/runbooks"
+ internaltest "github.com/OctopusDeploy/terraform-provider-octopusdeploy/internal/test"
+ "github.com/hashicorp/terraform-plugin-testing/helper/acctest"
+ "github.com/hashicorp/terraform-plugin-testing/helper/resource"
+ "github.com/hashicorp/terraform-plugin-testing/plancheck"
+ "github.com/hashicorp/terraform-plugin-testing/terraform"
+ "github.com/stretchr/testify/assert"
+)
+
+func TestRunbookResource_UpgradeFromSDK_ToPluginFramework(t *testing.T) {
+ internaltest.SkipCI(t, "'octopusdeploy_runbook.runbook1' - expected NoOp, got action(s): [update]")
+ os.Setenv("TF_CLI_CONFIG_FILE=", "")
+
+ name := acctest.RandStringFromCharSet(20, acctest.CharSetAlpha)
+ resource.Test(t, resource.TestCase{
+ CheckDestroy: testRunbookDestroyed,
+ Steps: []resource.TestStep{
+ {
+ ExternalProviders: map[string]resource.ExternalProvider{
+ "octopusdeploy": {
+ VersionConstraint: "0.22.0",
+ Source: "OctopusDeployLabs/octopusdeploy",
+ },
+ },
+ Config: runbookConfig(name),
+ },
+ {
+ ProtoV6ProviderFactories: ProtoV6ProviderFactories(),
+ Config: runbookConfig(name),
+ ConfigPlanChecks: resource.ConfigPlanChecks{
+ PreApply: []plancheck.PlanCheck{
+ plancheck.ExpectResourceAction("octopusdeploy_runbook.runbook1", "NoOp"),
+ },
+ },
+ },
+ {
+ ProtoV6ProviderFactories: ProtoV6ProviderFactories(),
+ Config: updatedRunbookConfig(name),
+ Check: resource.ComposeTestCheckFunc(
+ testRunbookUpdated(t, name),
+ ),
+ },
+ },
+ })
+}
+
+func runbookConfig(name string) string {
+ return fmt.Sprintf(`
+ resource "octopusdeploy_project" "project1" {
+ name = "project %[1]s"
+ lifecycle_id = "Lifecycles-1"
+ project_group_id = "ProjectGroups-1"
+ }
+ resource "octopusdeploy_runbook" "runbook1" {
+ project_id = octopusdeploy_project.project1.id
+ name = "runbook %[1]s"
+ }
+ `, name)
+}
+
+func updatedRunbookConfig(name string) string {
+ return fmt.Sprintf(`
+ resource "octopusdeploy_project" "project1" {
+ name = "project %[1]s"
+ lifecycle_id = "Lifecycles-1"
+ project_group_id = "ProjectGroups-1"
+ }
+ resource "octopusdeploy_runbook" "runbook1" {
+ project_id = octopusdeploy_project.project1.id
+ name = "runbook %[1]s"
+ description = "description %[1]s"
+ connectivity_policy {
+ allow_deployments_to_no_targets = true
+ exclude_unhealthy_targets = true
+ }
+ retention_policy {
+ quantity_to_keep = 10
+ }
+ }
+ `, name)
+}
+
+func testRunbookDestroyed(s *terraform.State) error {
+ for _, rs := range s.RootModule().Resources {
+ if rs.Type != "octopusdeploy_runbook" {
+ runbook, err := runbooks.GetByID(octoClient, octoClient.GetSpaceID(), rs.Primary.ID)
+ if err == nil && runbook != nil {
+ return fmt.Errorf("runbook (%s) still exists", rs.Primary.ID)
+ }
+ }
+ }
+
+ return nil
+}
+
+func testRunbookUpdated(t *testing.T, name string) resource.TestCheckFunc {
+ return func(s *terraform.State) error {
+ projectId := s.RootModule().Resources["octopusdeploy_project.project1"].Primary.ID
+ runbookId := s.RootModule().Resources["octopusdeploy_runbook.runbook1"].Primary.ID
+ runbook, err := runbooks.GetByID(octoClient, octoClient.GetSpaceID(), runbookId)
+ if err != nil {
+ return fmt.Errorf("failed to retrieve runbook by ID: %s", err)
+ }
+
+ assert.NotEmpty(t, runbook.ID, "Runbook ID did not match expected value")
+ assert.Equal(t, runbook.ProjectID, projectId)
+ assert.Equal(t, runbook.Description, fmt.Sprintf("description %s", name))
+ assert.True(t, runbook.ConnectivityPolicy.AllowDeploymentsToNoTargets, "allow_deployments_to_no_targets should be true")
+ assert.True(t, runbook.ConnectivityPolicy.ExcludeUnhealthyTargets, "exclude_unhealthy_targets should be true")
+ assert.Equal(t, runbook.RunRetentionPolicy.QuantityToKeep, 10)
+
+ return nil
+ }
+}
diff --git a/octopusdeploy/resource_runbook_process_test.go b/octopusdeploy_framework/resource_runbook_test.go
similarity index 99%
rename from octopusdeploy/resource_runbook_process_test.go
rename to octopusdeploy_framework/resource_runbook_test.go
index 0f1de80d0..992b38238 100644
--- a/octopusdeploy/resource_runbook_process_test.go
+++ b/octopusdeploy_framework/resource_runbook_test.go
@@ -1,11 +1,12 @@
-package octopusdeploy
+package octopusdeploy_framework
import (
"fmt"
- "github.com/OctopusSolutionsEngineering/OctopusTerraformTestFramework/octoclient"
- "github.com/OctopusSolutionsEngineering/OctopusTerraformTestFramework/test"
"strings"
"testing"
+
+ "github.com/OctopusSolutionsEngineering/OctopusTerraformTestFramework/octoclient"
+ "github.com/OctopusSolutionsEngineering/OctopusTerraformTestFramework/test"
)
// TestRunbookResource verifies that a runbook can be reimported with the correct settings
diff --git a/octopusdeploy_framework/schemas/connectivity_policy.go b/octopusdeploy_framework/schemas/connectivity_policy.go
new file mode 100644
index 000000000..508718f3b
--- /dev/null
+++ b/octopusdeploy_framework/schemas/connectivity_policy.go
@@ -0,0 +1,142 @@
+package schemas
+
+import (
+ "github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/core"
+ "github.com/OctopusDeploy/terraform-provider-octopusdeploy/octopusdeploy_framework/util"
+ "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
+ "github.com/hashicorp/terraform-plugin-framework/attr"
+ resourceSchema "github.com/hashicorp/terraform-plugin-framework/resource/schema"
+ "github.com/hashicorp/terraform-plugin-framework/resource/schema/booldefault"
+ "github.com/hashicorp/terraform-plugin-framework/resource/schema/boolplanmodifier"
+ "github.com/hashicorp/terraform-plugin-framework/resource/schema/listplanmodifier"
+ "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
+ "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault"
+ "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
+ "github.com/hashicorp/terraform-plugin-framework/schema/validator"
+ "github.com/hashicorp/terraform-plugin-framework/types"
+)
+
+var runbookConnectivityPolicySchemeAttributeNames = struct {
+ AllowDeploymentsToNoTargets string
+ ExcludeUnhealthyTargets string
+ SkipMachineBehavior string
+ TargetRoles string
+}{
+ AllowDeploymentsToNoTargets: "allow_deployments_to_no_targets",
+ ExcludeUnhealthyTargets: "exclude_unhealthy_targets",
+ SkipMachineBehavior: "skip_machine_behavior",
+ TargetRoles: "target_roles",
+}
+
+var skipMachineBehaviorNames = struct {
+ SkipUnavailableMachines string
+ None string
+}{
+ SkipUnavailableMachines: "SkipUnavailableMachines",
+ None: "None",
+}
+
+var skipMachineBehaviors = []string{
+ skipMachineBehaviorNames.SkipUnavailableMachines,
+ skipMachineBehaviorNames.None,
+}
+
+func GetConnectivityPolicyObjectType() map[string]attr.Type {
+ return map[string]attr.Type{
+ runbookConnectivityPolicySchemeAttributeNames.AllowDeploymentsToNoTargets: types.BoolType,
+ runbookConnectivityPolicySchemeAttributeNames.ExcludeUnhealthyTargets: types.BoolType,
+ runbookConnectivityPolicySchemeAttributeNames.SkipMachineBehavior: types.StringType,
+ runbookConnectivityPolicySchemeAttributeNames.TargetRoles: types.ListType{ElemType: types.StringType},
+ }
+}
+
+func getConnectivityPolicySchema() map[string]resourceSchema.Attribute {
+ return map[string]resourceSchema.Attribute{
+ runbookConnectivityPolicySchemeAttributeNames.AllowDeploymentsToNoTargets: resourceSchema.BoolAttribute{
+ Computed: true,
+ Optional: true,
+ Default: booldefault.StaticBool(true),
+ PlanModifiers: []planmodifier.Bool{
+ boolplanmodifier.UseStateForUnknown(),
+ },
+ },
+ runbookConnectivityPolicySchemeAttributeNames.ExcludeUnhealthyTargets: resourceSchema.BoolAttribute{
+ Computed: true,
+ Optional: true,
+ Default: booldefault.StaticBool(false),
+ PlanModifiers: []planmodifier.Bool{
+ boolplanmodifier.UseStateForUnknown(),
+ },
+ },
+ runbookConnectivityPolicySchemeAttributeNames.SkipMachineBehavior: resourceSchema.StringAttribute{
+ Computed: true,
+ Optional: true,
+ Default: stringdefault.StaticString(skipMachineBehaviorNames.None),
+ Validators: []validator.String{
+ stringvalidator.OneOf(
+ skipMachineBehaviors...,
+ ),
+ },
+ PlanModifiers: []planmodifier.String{
+ stringplanmodifier.UseStateForUnknown(),
+ },
+ },
+ runbookConnectivityPolicySchemeAttributeNames.TargetRoles: resourceSchema.ListAttribute{
+ Computed: true,
+ Optional: true,
+ ElementType: types.StringType,
+ PlanModifiers: []planmodifier.List{
+ listplanmodifier.UseStateForUnknown(),
+ },
+ },
+ }
+}
+
+func GetDefaultConnectivityPolicy() *core.ConnectivityPolicy {
+ return &core.ConnectivityPolicy{
+ AllowDeploymentsToNoTargets: true,
+ ExcludeUnhealthyTargets: false,
+ SkipMachineBehavior: core.SkipMachineBehaviorNone,
+ TargetRoles: []string{},
+ }
+}
+
+func MapFromConnectivityPolicy(connectivityPolicy *core.ConnectivityPolicy) attr.Value {
+ if connectivityPolicy == nil {
+ return MapFromConnectivityPolicy(GetDefaultConnectivityPolicy())
+ }
+
+ attrs := map[string]attr.Value{
+ runbookConnectivityPolicySchemeAttributeNames.AllowDeploymentsToNoTargets: types.BoolValue(connectivityPolicy.AllowDeploymentsToNoTargets),
+ runbookConnectivityPolicySchemeAttributeNames.ExcludeUnhealthyTargets: types.BoolValue(connectivityPolicy.ExcludeUnhealthyTargets),
+ runbookConnectivityPolicySchemeAttributeNames.SkipMachineBehavior: types.StringValue(string(connectivityPolicy.SkipMachineBehavior)),
+ runbookConnectivityPolicySchemeAttributeNames.TargetRoles: util.FlattenStringList(connectivityPolicy.TargetRoles),
+ }
+
+ return types.ObjectValueMust(GetConnectivityPolicyObjectType(), attrs)
+}
+
+func MapToConnectivityPolicy(flattenedConnectivityPolicy types.List) *core.ConnectivityPolicy {
+ if flattenedConnectivityPolicy.IsNull() || len(flattenedConnectivityPolicy.Elements()) == 0 {
+ return GetDefaultConnectivityPolicy()
+ }
+
+ obj := flattenedConnectivityPolicy.Elements()[0].(types.Object)
+ attrs := obj.Attributes()
+
+ var connectivityPolicy core.ConnectivityPolicy
+ if allowDeploymentsToNoTargets, ok := attrs[runbookConnectivityPolicySchemeAttributeNames.AllowDeploymentsToNoTargets].(types.Bool); ok && !allowDeploymentsToNoTargets.IsNull() {
+ connectivityPolicy.AllowDeploymentsToNoTargets = allowDeploymentsToNoTargets.ValueBool()
+ }
+ if excludeUnhealthyTargets, ok := attrs[runbookConnectivityPolicySchemeAttributeNames.ExcludeUnhealthyTargets].(types.Bool); ok && !excludeUnhealthyTargets.IsNull() {
+ connectivityPolicy.ExcludeUnhealthyTargets = excludeUnhealthyTargets.ValueBool()
+ }
+ if skipMachineBehavior, ok := attrs[runbookConnectivityPolicySchemeAttributeNames.SkipMachineBehavior].(types.String); ok && !skipMachineBehavior.IsNull() {
+ connectivityPolicy.SkipMachineBehavior = core.SkipMachineBehavior(skipMachineBehavior.ValueString())
+ }
+ if targetRoles, ok := attrs[runbookConnectivityPolicySchemeAttributeNames.TargetRoles].(types.List); ok && !targetRoles.IsNull() {
+ connectivityPolicy.TargetRoles = util.ExpandStringList(targetRoles)
+ }
+
+ return &connectivityPolicy
+}
diff --git a/octopusdeploy_framework/schemas/runbook.go b/octopusdeploy_framework/schemas/runbook.go
new file mode 100644
index 000000000..2bc493d94
--- /dev/null
+++ b/octopusdeploy_framework/schemas/runbook.go
@@ -0,0 +1,288 @@
+package schemas
+
+import (
+ "context"
+ "fmt"
+ "regexp"
+ "strings"
+
+ "github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/runbooks"
+ "github.com/OctopusDeploy/terraform-provider-octopusdeploy/octopusdeploy_framework/util"
+ "github.com/hashicorp/terraform-plugin-framework-validators/listvalidator"
+ "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
+ "github.com/hashicorp/terraform-plugin-framework/attr"
+ "github.com/hashicorp/terraform-plugin-framework/diag"
+ resourceSchema "github.com/hashicorp/terraform-plugin-framework/resource/schema"
+ "github.com/hashicorp/terraform-plugin-framework/resource/schema/boolplanmodifier"
+ "github.com/hashicorp/terraform-plugin-framework/resource/schema/listplanmodifier"
+ "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
+ "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
+ "github.com/hashicorp/terraform-plugin-framework/schema/validator"
+ "github.com/hashicorp/terraform-plugin-framework/types"
+)
+
+const RunbookResourceDescription = "runbook"
+
+var RunbookSchemaAttributeNames = struct {
+ ID string
+ Name string
+ Description string
+ ProjectID string
+ RunbookProcessID string
+ PublishedRunbookSnapshotID string
+ SpaceID string
+ MultiTenancyMode string
+ ConnectivityPolicy string
+ EnvironmentScope string
+ Environments string
+ DefaultGuidedFailureMode string
+ RetentionPolicy string
+ ForcePackageDownload string
+}{
+ ID: "id",
+ Name: "name",
+ Description: "description",
+ ProjectID: "project_id",
+ RunbookProcessID: "runbook_process_id",
+ PublishedRunbookSnapshotID: "published_runbook_snapshot_id",
+ SpaceID: "space_id",
+ MultiTenancyMode: "multi_tenancy_mode",
+ ConnectivityPolicy: "connectivity_policy",
+ EnvironmentScope: "environment_scope",
+ Environments: "environments",
+ DefaultGuidedFailureMode: "default_guided_failure_mode",
+ RetentionPolicy: "retention_policy",
+ ForcePackageDownload: "force_package_download",
+}
+
+var tenantedDeploymentModeNames = struct {
+ Untenanted string
+ TenantedOrUntenanted string
+ Tenanted string
+}{
+ Untenanted: "Untenanted",
+ TenantedOrUntenanted: "TenantedOrUntenanted",
+ Tenanted: "Tenanted",
+}
+
+var tenantedDeploymentModes = []string{
+ tenantedDeploymentModeNames.Untenanted,
+ tenantedDeploymentModeNames.TenantedOrUntenanted,
+ tenantedDeploymentModeNames.Tenanted,
+}
+
+var environmentScopeNames = struct {
+ All string
+ Specified string
+ FromProjectLifecycles string
+}{
+ All: "All",
+ Specified: "Specified",
+ FromProjectLifecycles: "FromProjectLifecycles",
+}
+
+var environmentScopeTypes = []string{
+ environmentScopeNames.All,
+ environmentScopeNames.Specified,
+ environmentScopeNames.FromProjectLifecycles,
+}
+
+var defaultGuidedFailureModeNames = struct {
+ EnvironmentDefault string
+ Off string
+ On string
+}{
+ EnvironmentDefault: "EnvironmentDefault",
+ Off: "Off",
+ On: "On",
+}
+
+var defaultGuidedFailureModes = []string{
+ defaultGuidedFailureModeNames.EnvironmentDefault,
+ defaultGuidedFailureModeNames.Off,
+ defaultGuidedFailureModeNames.On,
+}
+
+type RunbookTypeResourceModel struct {
+ Name types.String `tfsdk:"name"`
+ ProjectID types.String `tfsdk:"project_id"`
+ Description types.String `tfsdk:"description"`
+ RunbookProcessID types.String `tfsdk:"runbook_process_id"`
+ PublishedRunbookSnapshotID types.String `tfsdk:"published_runbook_snapshot_id"`
+ SpaceID types.String `tfsdk:"space_id"`
+ MultiTenancyMode types.String `tfsdk:"multi_tenancy_mode"`
+ ConnectivityPolicy types.List `tfsdk:"connectivity_policy"`
+ EnvironmentScope types.String `tfsdk:"environment_scope"`
+ Environments types.List `tfsdk:"environments"`
+ DefaultGuidedFailureMode types.String `tfsdk:"default_guided_failure_mode"`
+ RunRetentionPolicy types.List `tfsdk:"retention_policy"`
+ ForcePackageDownload types.Bool `tfsdk:"force_package_download"`
+
+ ResourceModel
+}
+
+type RunbookRetentionPeriodModel struct {
+ QuantityToKeep types.String `tfsdk:"quantity_to_keep"`
+ ShouldKeepForever types.Bool `tfsdk:"should_keep_forever"`
+}
+
+type RunbookConnectivityPolicyModel struct {
+ AllowDeploymentsToNoTargets types.Bool `tfsdk:"allow_deployments_to_no_targets"`
+ ExcludeUnhealthyTargets types.Bool `tfsdk:"exclude_unhealthy_targets"`
+ SkipMachineBehavior types.String `tfsdk:"skip_machine_behaviour"`
+ TargetRoles types.List `tfsdk:"target_roles"`
+}
+
+func GetRunbookResourceSchema() resourceSchema.Schema {
+ return resourceSchema.Schema{
+ Description: util.GetResourceSchemaDescription(RunbookResourceDescription),
+ Attributes: map[string]resourceSchema.Attribute{
+ RunbookSchemaAttributeNames.ID: util.GetIdResourceSchema(),
+ RunbookSchemaAttributeNames.Name: resourceSchema.StringAttribute{
+ Description: "The name of the runbook in Octopus Deploy. This name must be unique.",
+ Required: true,
+ Validators: []validator.String{
+ stringvalidator.RegexMatches(
+ regexp.MustCompile(`\S+`),
+ "expected value to not be an empty string or whitespace",
+ ),
+ },
+ },
+ RunbookSchemaAttributeNames.Description: util.GetDescriptionResourceSchema(RunbookResourceDescription),
+ RunbookSchemaAttributeNames.ProjectID: resourceSchema.StringAttribute{
+ Description: "The project that this runbook belongs to.",
+ Required: true,
+ },
+ RunbookSchemaAttributeNames.RunbookProcessID: resourceSchema.StringAttribute{
+ Description: "The runbook process ID.",
+ Computed: true,
+ PlanModifiers: []planmodifier.String{
+ stringplanmodifier.UseStateForUnknown(),
+ },
+ },
+ RunbookSchemaAttributeNames.PublishedRunbookSnapshotID: resourceSchema.StringAttribute{
+ Description: "The published snapshot ID.",
+ Computed: true,
+ PlanModifiers: []planmodifier.String{
+ stringplanmodifier.UseStateForUnknown(),
+ },
+ },
+ RunbookSchemaAttributeNames.SpaceID: util.GetSpaceIdResourceSchema(RunbookResourceDescription),
+ RunbookSchemaAttributeNames.MultiTenancyMode: resourceSchema.StringAttribute{
+ Description: fmt.Sprintf("The tenanted deployment mode of the runbook. Valid modes are %s", strings.Join(util.Map(tenantedDeploymentModes, func(item string) string { return fmt.Sprintf("`%s`", item) }), ", ")),
+ Computed: true,
+ Optional: true,
+ Validators: []validator.String{
+ stringvalidator.OneOf(tenantedDeploymentModes...),
+ },
+ PlanModifiers: []planmodifier.String{
+ stringplanmodifier.UseStateForUnknown(),
+ },
+ },
+ RunbookSchemaAttributeNames.EnvironmentScope: resourceSchema.StringAttribute{
+ Description: "Determines how the runbook is scoped to environments.",
+ Computed: true,
+ Optional: true,
+ Validators: []validator.String{
+ stringvalidator.OneOf(environmentScopeTypes...),
+ },
+ PlanModifiers: []planmodifier.String{
+ stringplanmodifier.UseStateForUnknown(),
+ },
+ },
+ RunbookSchemaAttributeNames.Environments: resourceSchema.ListAttribute{
+ Description: fmt.Sprintf("When %s is set to \"%s\", this is the list of environments the runbook can be run against.", RunbookSchemaAttributeNames.EnvironmentScope, environmentScopeNames.Specified),
+ Optional: true,
+ Computed: true,
+ ElementType: types.StringType,
+ PlanModifiers: []planmodifier.List{
+ listplanmodifier.UseStateForUnknown(),
+ },
+ },
+ RunbookSchemaAttributeNames.DefaultGuidedFailureMode: resourceSchema.StringAttribute{
+ Description: "Sets the runbook guided failure mode.",
+ Optional: true,
+ Computed: true,
+ Validators: []validator.String{
+ stringvalidator.OneOf(defaultGuidedFailureModes...),
+ },
+ PlanModifiers: []planmodifier.String{
+ stringplanmodifier.UseStateForUnknown(),
+ },
+ },
+ RunbookSchemaAttributeNames.ForcePackageDownload: resourceSchema.BoolAttribute{
+ Description: "Whether to force packages to be re-downloaded or not.",
+ Computed: true,
+ Optional: true,
+ PlanModifiers: []planmodifier.Bool{
+ boolplanmodifier.UseStateForUnknown(),
+ },
+ },
+ },
+ Blocks: map[string]resourceSchema.Block{
+ RunbookSchemaAttributeNames.ConnectivityPolicy: resourceSchema.ListNestedBlock{
+ NestedObject: resourceSchema.NestedBlockObject{
+ Attributes: getConnectivityPolicySchema(),
+ },
+ Validators: []validator.List{
+ listvalidator.SizeAtMost(1),
+ },
+ },
+ RunbookSchemaAttributeNames.RetentionPolicy: resourceSchema.ListNestedBlock{
+ Description: "Sets the runbook retention policy.",
+ NestedObject: resourceSchema.NestedBlockObject{
+ Attributes: getRunbookRetentionPeriodSchema(),
+ },
+ Validators: []validator.List{
+ listvalidator.SizeAtMost(1),
+ },
+ },
+ },
+ }
+}
+
+func (data *RunbookTypeResourceModel) RefreshFromApiResponse(ctx context.Context, runbook *runbooks.Runbook) diag.Diagnostics {
+ var diags diag.Diagnostics
+
+ if runbook == nil {
+ return diags
+ }
+
+ data.ID = types.StringValue(runbook.ID)
+ data.Name = types.StringValue(runbook.Name)
+ data.ProjectID = types.StringValue(runbook.ProjectID)
+ data.Description = types.StringValue(runbook.Description)
+ data.RunbookProcessID = types.StringValue(runbook.RunbookProcessID)
+ data.PublishedRunbookSnapshotID = types.StringValue(runbook.PublishedRunbookSnapshotID)
+ data.SpaceID = types.StringValue(runbook.SpaceID)
+ data.MultiTenancyMode = types.StringValue(string(runbook.MultiTenancyMode))
+ data.EnvironmentScope = types.StringValue(runbook.EnvironmentScope)
+ data.Environments = util.FlattenStringList(runbook.Environments)
+ data.DefaultGuidedFailureMode = types.StringValue(runbook.DefaultGuidedFailureMode)
+ data.ForcePackageDownload = types.BoolValue(runbook.ForcePackageDownload)
+ if !data.ConnectivityPolicy.IsNull() {
+ result, d := types.ListValueFrom(
+ ctx,
+ types.ObjectType{AttrTypes: GetConnectivityPolicyObjectType()},
+ []attr.Value{MapFromConnectivityPolicy(runbook.ConnectivityPolicy)},
+ )
+ diags.Append(d...)
+ data.ConnectivityPolicy = result
+ } /*else {
+ data.ConnectivityPolicy = types.ListValueMust(
+ types.ObjectType{AttrTypes: GetConnectivityPolicyObjectType()},
+ []attr.Value{MapFromConnectivityPolicy(GetDefaultConnectivityPolicy())},
+ )
+ }*/
+ if !data.RunRetentionPolicy.IsNull() {
+ result, d := types.ListValueFrom(
+ ctx,
+ types.ObjectType{AttrTypes: GetRunbookRetentionPeriodObjectType()},
+ []attr.Value{MapFromRunbookRetentionPeriod(runbook.RunRetentionPolicy)},
+ )
+ diags.Append(d...)
+ data.RunRetentionPolicy = result
+ }
+
+ return diags
+}
diff --git a/octopusdeploy_framework/schemas/runbook_retention_period.go b/octopusdeploy_framework/schemas/runbook_retention_period.go
new file mode 100644
index 000000000..d8bbdc8b6
--- /dev/null
+++ b/octopusdeploy_framework/schemas/runbook_retention_period.go
@@ -0,0 +1,99 @@
+package schemas
+
+import (
+ "fmt"
+
+ "github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/runbooks"
+ "github.com/hashicorp/terraform-plugin-framework-validators/boolvalidator"
+ "github.com/hashicorp/terraform-plugin-framework-validators/int64validator"
+ "github.com/hashicorp/terraform-plugin-framework/attr"
+ "github.com/hashicorp/terraform-plugin-framework/path"
+ resourceSchema "github.com/hashicorp/terraform-plugin-framework/resource/schema"
+ "github.com/hashicorp/terraform-plugin-framework/resource/schema/booldefault"
+ "github.com/hashicorp/terraform-plugin-framework/resource/schema/boolplanmodifier"
+ "github.com/hashicorp/terraform-plugin-framework/resource/schema/int64planmodifier"
+ "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
+ "github.com/hashicorp/terraform-plugin-framework/schema/validator"
+ "github.com/hashicorp/terraform-plugin-framework/types"
+)
+
+var runbookRetentionPeriodSchemeAttributeNames = struct {
+ QuantityToKeep string
+ ShouldKeepForever string
+}{
+ QuantityToKeep: "quantity_to_keep",
+ ShouldKeepForever: "should_keep_forever",
+}
+
+func GetRunbookRetentionPeriodObjectType() map[string]attr.Type {
+ return map[string]attr.Type{
+ runbookRetentionPeriodSchemeAttributeNames.QuantityToKeep: types.Int64Type,
+ runbookRetentionPeriodSchemeAttributeNames.ShouldKeepForever: types.BoolType,
+ }
+}
+
+func getRunbookRetentionPeriodSchema() map[string]resourceSchema.Attribute {
+ return map[string]resourceSchema.Attribute{
+ runbookRetentionPeriodSchemeAttributeNames.QuantityToKeep: resourceSchema.Int64Attribute{
+ Description: "How many runs to keep per environment.",
+ Computed: true,
+ Optional: true,
+ Validators: []validator.Int64{
+ int64validator.AtLeast(0),
+ },
+ PlanModifiers: []planmodifier.Int64{
+ int64planmodifier.UseStateForUnknown(),
+ },
+ },
+ runbookRetentionPeriodSchemeAttributeNames.ShouldKeepForever: resourceSchema.BoolAttribute{
+ Description: "Indicates if items should never be deleted. The default value is `false`.",
+ Computed: true,
+ Optional: true,
+ Default: booldefault.StaticBool(false),
+ Validators: []validator.Bool{
+ boolvalidator.ConflictsWith(path.MatchRelative().AtParent().AtName(runbookRetentionPeriodSchemeAttributeNames.QuantityToKeep)),
+ },
+ PlanModifiers: []planmodifier.Bool{
+ boolplanmodifier.UseStateForUnknown(),
+ },
+ },
+ }
+}
+
+func GetDefaultRunbookRetentionPeriod() *runbooks.RunbookRetentionPeriod {
+ return &runbooks.RunbookRetentionPeriod{
+ QuantityToKeep: 100,
+ ShouldKeepForever: false,
+ }
+}
+
+func MapFromRunbookRetentionPeriod(retentionPeriod *runbooks.RunbookRetentionPeriod) attr.Value {
+ if retentionPeriod == nil {
+ return MapFromRunbookRetentionPeriod(GetDefaultRunbookRetentionPeriod())
+ }
+
+ attrs := map[string]attr.Value{
+ runbookRetentionPeriodSchemeAttributeNames.QuantityToKeep: types.Int64Value(int64(retentionPeriod.QuantityToKeep)),
+ runbookRetentionPeriodSchemeAttributeNames.ShouldKeepForever: types.BoolValue(retentionPeriod.ShouldKeepForever),
+ }
+
+ return types.ObjectValueMust(GetRunbookRetentionPeriodObjectType(), attrs)
+}
+
+func MapToRunbookRetentionPeriod(flattenedRunbookRetentionPeriod types.List) *runbooks.RunbookRetentionPeriod {
+ if flattenedRunbookRetentionPeriod.IsNull() || len(flattenedRunbookRetentionPeriod.Elements()) == 0 {
+ return GetDefaultRunbookRetentionPeriod()
+ }
+ obj := flattenedRunbookRetentionPeriod.Elements()[0].(types.Object)
+ attrs := obj.Attributes()
+
+ var runbookRetentionPeriod runbooks.RunbookRetentionPeriod
+ if quantityToKeep, ok := attrs[runbookRetentionPeriodSchemeAttributeNames.QuantityToKeep].(types.Int64); ok && !quantityToKeep.IsNull() {
+ runbookRetentionPeriod.QuantityToKeep = int32(quantityToKeep.ValueInt64())
+ }
+ if shouldKeepForever, ok := attrs[runbookRetentionPeriodSchemeAttributeNames.ShouldKeepForever].(types.Bool); ok && !shouldKeepForever.IsNull() {
+ runbookRetentionPeriod.ShouldKeepForever = shouldKeepForever.ValueBool()
+ }
+ fmt.Printf("runbook retention period: %#v", runbookRetentionPeriod)
+ return &runbookRetentionPeriod
+}
diff --git a/octopusdeploy_framework/util/logging.go b/octopusdeploy_framework/util/logging.go
index 139d7932d..66b3ca311 100644
--- a/octopusdeploy_framework/util/logging.go
+++ b/octopusdeploy_framework/util/logging.go
@@ -3,6 +3,7 @@ package util
import (
"context"
"fmt"
+
"github.com/hashicorp/terraform-plugin-log/tflog"
)
@@ -13,3 +14,27 @@ func Create(ctx context.Context, resource string, v ...any) {
func Created(ctx context.Context, resource string, v ...any) {
tflog.Info(ctx, fmt.Sprintf("created %s: %#v", resource, v))
}
+
+func Delete(ctx context.Context, resource string, v ...any) {
+ tflog.Info(ctx, fmt.Sprintf("deleting %s: %#v", resource, v))
+}
+
+func Deleted(ctx context.Context, resource string, v ...any) {
+ tflog.Info(ctx, fmt.Sprintf("deleted %s: %#v", resource, v))
+}
+
+func Reading(ctx context.Context, resource string, v ...any) {
+ tflog.Info(ctx, fmt.Sprintf("reading %s: %#v", resource, v))
+}
+
+func Read(ctx context.Context, resource string, v ...any) {
+ tflog.Info(ctx, fmt.Sprintf("read %s: %#v", resource, v))
+}
+
+func Update(ctx context.Context, resource string, v ...any) {
+ tflog.Info(ctx, fmt.Sprintf("updating %s: %#v", resource, v))
+}
+
+func Updated(ctx context.Context, resource string, v ...any) {
+ tflog.Info(ctx, fmt.Sprintf("updated %s: %#v", resource, v))
+}
From be6e0ecbc40204f589722263e49e681a6984f160 Mon Sep 17 00:00:00 2001
From: Isaac Calligeros <101079287+IsaacCalligeros95@users.noreply.github.com>
Date: Mon, 12 Aug 2024 13:27:53 +0930
Subject: [PATCH 10/12] Chore!: migrate tenant resource and datasource (#707)
* Migrate tenants resource
---
docs/resources/tenant.md | 2 +-
octopusdeploy/provider.go | 1 -
octopusdeploy/resource_tenant.go | 108 -----------
octopusdeploy/schema_tenant.go | 104 -----------
octopusdeploy/schema_tenant_test.go | 40 ----
octopusdeploy_framework/framework_provider.go | 1 +
octopusdeploy_framework/resource_tenant.go | 174 ++++++++++++++++++
.../resource_tenant_migration_test.go | 109 +++++++++++
.../resource_tenant_test.go | 11 +-
octopusdeploy_framework/schemas/tenant.go | 31 +++-
10 files changed, 320 insertions(+), 261 deletions(-)
delete mode 100644 octopusdeploy/resource_tenant.go
delete mode 100644 octopusdeploy/schema_tenant.go
delete mode 100644 octopusdeploy/schema_tenant_test.go
create mode 100644 octopusdeploy_framework/resource_tenant.go
create mode 100644 octopusdeploy_framework/resource_tenant_migration_test.go
rename {octopusdeploy => octopusdeploy_framework}/resource_tenant_test.go (95%)
diff --git a/docs/resources/tenant.md b/docs/resources/tenant.md
index ba3ce6aa6..16851becb 100644
--- a/docs/resources/tenant.md
+++ b/docs/resources/tenant.md
@@ -21,7 +21,7 @@ This resource manages tenants in Octopus Deploy.
- `cloned_from_tenant_id` (String) The ID of the tenant from which this tenant was cloned.
- `description` (String) The description of this tenant.
- `id` (String) The unique ID for this resource.
-- `space_id` (String) The space ID associated with this resource.
+- `space_id` (String) The space ID associated with this tenant.
- `tenant_tags` (List of String) A list of tenant tags associated with this resource.
~> **NOTE property `project_environment` deprecated:** The `project_environment` property has been replaced by the `octopusdeploy_tenant_project` resource to allow more advanced provisioning scenarioes.
\ No newline at end of file
diff --git a/octopusdeploy/provider.go b/octopusdeploy/provider.go
index 794853fff..ebdaf0b94 100644
--- a/octopusdeploy/provider.go
+++ b/octopusdeploy/provider.go
@@ -67,7 +67,6 @@ func Provider() *schema.Provider {
"octopusdeploy_tag": resourceTag(),
"octopusdeploy_tag_set": resourceTagSet(),
"octopusdeploy_team": resourceTeam(),
- "octopusdeploy_tenant": resourceTenant(),
"octopusdeploy_tentacle_certificate": resourceTentacleCertificate(),
"octopusdeploy_token_account": resourceTokenAccount(),
"octopusdeploy_user": resourceUser(),
diff --git a/octopusdeploy/resource_tenant.go b/octopusdeploy/resource_tenant.go
deleted file mode 100644
index 899cf6f48..000000000
--- a/octopusdeploy/resource_tenant.go
+++ /dev/null
@@ -1,108 +0,0 @@
-package octopusdeploy
-
-import (
- "context"
- "log"
-
- "github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/client"
- "github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/tenants"
- "github.com/OctopusDeploy/terraform-provider-octopusdeploy/internal"
- "github.com/OctopusDeploy/terraform-provider-octopusdeploy/internal/errors"
- "github.com/hashicorp/terraform-plugin-sdk/v2/diag"
- "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
-)
-
-func resourceTenant() *schema.Resource {
- return &schema.Resource{
- CreateContext: resourceTenantCreate,
- DeleteContext: resourceTenantDelete,
- Description: "This resource manages tenants in Octopus Deploy.",
- Importer: getImporter(),
- ReadContext: resourceTenantRead,
- Schema: getTenantSchema(),
- UpdateContext: resourceTenantUpdate,
- }
-}
-
-func resourceTenantCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
- internal.Mutex.Lock()
- defer internal.Mutex.Unlock()
-
- tenant := expandTenant(d)
-
- log.Printf("[INFO] creating tenant: %#v", tenant)
-
- client := m.(*client.Client)
- createdTenant, err := tenants.Add(client, tenant)
- if err != nil {
- return diag.FromErr(err)
- }
-
- if err := setTenant(ctx, d, createdTenant); err != nil {
- return diag.FromErr(err)
- }
-
- d.SetId(createdTenant.GetID())
-
- log.Printf("[INFO] tenant created (%s)", d.Id())
- return nil
-}
-
-func resourceTenantDelete(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
- internal.Mutex.Lock()
- defer internal.Mutex.Unlock()
-
- log.Printf("[INFO] deleting tenant (%s)", d.Id())
-
- client := m.(*client.Client)
- if err := tenants.DeleteByID(client, d.Get("space_id").(string), d.Id()); err != nil {
- return diag.FromErr(err)
- }
-
- log.Printf("[INFO] tenant deleted (%s)", d.Id())
- d.SetId("")
- return nil
-}
-
-func resourceTenantRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
- log.Printf("[INFO] reading tenant (%s)", d.Id())
-
- client := m.(*client.Client)
- tenant, err := tenants.GetByID(client, d.Get("space_id").(string), d.Id())
- if err != nil {
- return errors.ProcessApiError(ctx, d, err, "tenant")
- }
-
- if err := setTenant(ctx, d, tenant); err != nil {
- return diag.FromErr(err)
- }
-
- log.Printf("[INFO] tenant read (%s)", d.Id())
- return nil
-}
-
-func resourceTenantUpdate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
- internal.Mutex.Lock()
- defer internal.Mutex.Unlock()
-
- log.Printf("[INFO] updating tenant (%s)", d.Id())
-
- client := m.(*client.Client)
- tenantFromApi, err := tenants.GetByID(client, d.Get("space_id").(string), d.Id())
-
- tenant := expandTenant(d)
-
- // the project environments are not managed here, so we need to maintain the collection when updating
- tenant.ProjectEnvironments = tenantFromApi.ProjectEnvironments
- updatedTenant, err := tenants.Update(client, tenant)
- if err != nil {
- return diag.FromErr(err)
- }
-
- if err := setTenant(ctx, d, updatedTenant); err != nil {
- return diag.FromErr(err)
- }
-
- log.Printf("[INFO] tenant updated (%s)", d.Id())
- return nil
-}
diff --git a/octopusdeploy/schema_tenant.go b/octopusdeploy/schema_tenant.go
deleted file mode 100644
index 260ba93f8..000000000
--- a/octopusdeploy/schema_tenant.go
+++ /dev/null
@@ -1,104 +0,0 @@
-package octopusdeploy
-
-import (
- "context"
- "fmt"
-
- "github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/tenants"
- "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
-)
-
-func expandTenant(d *schema.ResourceData) *tenants.Tenant {
- name := d.Get("name").(string)
-
- tenant := tenants.NewTenant(name)
- tenant.ID = d.Id()
-
- if v, ok := d.GetOk("cloned_from_tenant_id"); ok {
- tenant.ClonedFromTenantID = v.(string)
- }
-
- if v, ok := d.GetOk("description"); ok {
- tenant.Description = v.(string)
- }
-
- if v, ok := d.GetOk("space_id"); ok {
- tenant.SpaceID = v.(string)
- }
-
- if v, ok := d.GetOk("tenant_tags"); ok {
- tenant.TenantTags = getSliceFromTerraformTypeList(v)
- }
-
- return tenant
-}
-
-func flattenTenant(tenant *tenants.Tenant) map[string]interface{} {
- if tenant == nil {
- return nil
- }
-
- return map[string]interface{}{
- "cloned_from_tenant_id": tenant.ClonedFromTenantID,
- "description": tenant.Description,
- "id": tenant.GetID(),
- "name": tenant.Name,
- "space_id": tenant.SpaceID,
- "tenant_tags": tenant.TenantTags,
- }
-}
-
-func getTenantDataSchema() map[string]*schema.Schema {
- dataSchema := getTenantSchema()
- setDataSchema(&dataSchema)
-
- return map[string]*schema.Schema{
- "cloned_from_tenant_id": getQueryClonedFromTenantID(),
- "id": getDataSchemaID(),
- "ids": getQueryIDs(),
- "is_clone": getQueryIsClone(),
- "name": getQueryName(),
- "partial_name": getQueryPartialName(),
- "project_id": getQueryProjectID(),
- "skip": getQuerySkip(),
- "tags": getQueryTags(),
- "space_id": getQuerySpaceID(),
- "tenants": {
- Computed: true,
- Description: "A list of tenants that match the filter(s).",
- Elem: &schema.Resource{Schema: dataSchema},
- Optional: false,
- Type: schema.TypeList,
- },
- "take": getQueryTake(),
- }
-}
-
-func getTenantSchema() map[string]*schema.Schema {
- return map[string]*schema.Schema{
- "cloned_from_tenant_id": {
- Description: "The ID of the tenant from which this tenant was cloned.",
- Optional: true,
- Type: schema.TypeString,
- },
- "description": getDescriptionSchema("tenant"),
- "id": getIDSchema(),
- "name": getNameSchema(true),
- "space_id": getSpaceIDSchema(),
- "tenant_tags": getTenantTagsSchema(),
- }
-}
-
-func setTenant(ctx context.Context, d *schema.ResourceData, tenant *tenants.Tenant) error {
- d.Set("cloned_from_tenant_id", tenant.ClonedFromTenantID)
- d.Set("description", tenant.Description)
- d.Set("id", tenant.GetID())
- d.Set("name", tenant.Name)
- d.Set("space_id", tenant.SpaceID)
-
- if err := d.Set("tenant_tags", tenant.TenantTags); err != nil {
- return fmt.Errorf("error setting tenant_tags: %s", err)
- }
-
- return nil
-}
diff --git a/octopusdeploy/schema_tenant_test.go b/octopusdeploy/schema_tenant_test.go
deleted file mode 100644
index 0a1d00d18..000000000
--- a/octopusdeploy/schema_tenant_test.go
+++ /dev/null
@@ -1,40 +0,0 @@
-package octopusdeploy
-
-import (
- "reflect"
- "testing"
-
- "github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/tenants"
- "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest"
- "github.com/stretchr/testify/require"
-)
-
-func TestFlattenTenant(t *testing.T) {
- clonedFromTenantID := acctest.RandStringFromCharSet(20, acctest.CharSetAlpha)
- description := acctest.RandStringFromCharSet(20, acctest.CharSetAlpha)
- id := acctest.RandStringFromCharSet(20, acctest.CharSetAlpha)
- name := acctest.RandStringFromCharSet(20, acctest.CharSetAlpha)
- projectEnvironments := map[string][]string{}
- spaceID := acctest.RandStringFromCharSet(20, acctest.CharSetAlpha)
- tenantTags := []string{acctest.RandStringFromCharSet(20, acctest.CharSetAlpha), acctest.RandStringFromCharSet(20, acctest.CharSetAlpha)}
-
- expectedExpanded := tenants.NewTenant(name)
- expectedExpanded.ClonedFromTenantID = clonedFromTenantID
- expectedExpanded.Description = description
- expectedExpanded.ID = id
- expectedExpanded.ProjectEnvironments = projectEnvironments
- expectedExpanded.SpaceID = spaceID
- expectedExpanded.TenantTags = tenantTags
-
- expectedFlattened := map[string]interface{}{
- "cloned_from_tenant_id": clonedFromTenantID,
- "description": description,
- "id": id,
- "name": name,
- "space_id": spaceID,
- "tenant_tags": tenantTags,
- }
-
- actualFlattened := flattenTenant(expectedExpanded)
- require.True(t, reflect.DeepEqual(expectedFlattened, actualFlattened))
-}
diff --git a/octopusdeploy_framework/framework_provider.go b/octopusdeploy_framework/framework_provider.go
index fc1128666..68686d521 100644
--- a/octopusdeploy_framework/framework_provider.go
+++ b/octopusdeploy_framework/framework_provider.go
@@ -95,6 +95,7 @@ func (p *octopusDeployFrameworkProvider) Resources(ctx context.Context) []func()
NewProjectResource,
NewDockerContainerRegistryFeedResource,
NewRunbookResource,
+ NewTenantResource,
}
}
diff --git a/octopusdeploy_framework/resource_tenant.go b/octopusdeploy_framework/resource_tenant.go
new file mode 100644
index 000000000..3fcde55b3
--- /dev/null
+++ b/octopusdeploy_framework/resource_tenant.go
@@ -0,0 +1,174 @@
+package octopusdeploy_framework
+
+import (
+ "context"
+ "fmt"
+ "github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/tenants"
+ "github.com/OctopusDeploy/terraform-provider-octopusdeploy/internal"
+ "github.com/OctopusDeploy/terraform-provider-octopusdeploy/internal/errors"
+ "github.com/OctopusDeploy/terraform-provider-octopusdeploy/octopusdeploy_framework/schemas"
+ "github.com/OctopusDeploy/terraform-provider-octopusdeploy/octopusdeploy_framework/util"
+ "github.com/hashicorp/terraform-plugin-framework/attr"
+ "github.com/hashicorp/terraform-plugin-framework/resource"
+ "github.com/hashicorp/terraform-plugin-framework/resource/schema"
+ "github.com/hashicorp/terraform-plugin-framework/types"
+ "github.com/hashicorp/terraform-plugin-log/tflog"
+ "sort"
+)
+
+type tenantTypeResource struct {
+ *Config
+}
+
+func NewTenantResource() resource.Resource {
+ return &tenantTypeResource{}
+}
+
+func (r *tenantTypeResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
+ resp.TypeName = util.GetTypeName("tenant")
+}
+
+func (r *tenantTypeResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
+ resp.Schema = schema.Schema{
+ Attributes: schemas.GetTenantResourceSchema(),
+ Description: "This resource manages tenants in Octopus Deploy.",
+ }
+}
+
+func (r *tenantTypeResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
+ r.Config = ResourceConfiguration(req, resp)
+}
+
+func (r *tenantTypeResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
+ internal.Mutex.Lock()
+ defer internal.Mutex.Unlock()
+
+ var data *schemas.TenantModel
+ resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...)
+ if resp.Diagnostics.HasError() {
+ return
+ }
+
+ tenant, err := mapStateToTenant(data)
+ if err != nil {
+ return
+ }
+
+ tflog.Info(ctx, fmt.Sprintf("creating Tenant: %s", tenant.Name))
+
+ createdTenant, err := tenants.Add(r.Config.Client, tenant)
+ if err != nil {
+ resp.Diagnostics.AddError("unable to create tenant", err.Error())
+ return
+ }
+
+ mapTenantToState(data, createdTenant)
+
+ tflog.Info(ctx, fmt.Sprintf("Tenant created (%s)", data.ID))
+ resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
+}
+
+func (r *tenantTypeResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
+ var data *schemas.TenantModel
+ resp.Diagnostics.Append(req.State.Get(ctx, &data)...)
+ if resp.Diagnostics.HasError() {
+ return
+ }
+
+ tflog.Info(ctx, fmt.Sprintf("reading Tenant (%s)", data.ID))
+
+ client := r.Config.Client
+ tenant, err := tenants.GetByID(client, data.SpaceID.ValueString(), data.ID.ValueString())
+ if err != nil {
+ if err := errors.ProcessApiErrorV2(ctx, resp, data, err, "tenant"); err != nil {
+ resp.Diagnostics.AddError("unable to load tenant", err.Error())
+ }
+ return
+ }
+
+ mapTenantToState(data, tenant)
+
+ tflog.Info(ctx, fmt.Sprintf("Tenant read (%s)", tenant.GetID()))
+ resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
+}
+
+func (r *tenantTypeResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
+ internal.Mutex.Lock()
+ defer internal.Mutex.Unlock()
+
+ var data, state *schemas.TenantModel
+ resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...)
+ resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
+ if resp.Diagnostics.HasError() {
+ return
+ }
+
+ tflog.Debug(ctx, fmt.Sprintf("updating tenant '%s'", data.ID.ValueString()))
+
+ tenantFromApi, err := tenants.GetByID(r.Config.Client, data.SpaceID.ValueString(), data.ID.ValueString())
+
+ tenant, err := mapStateToTenant(data)
+ tenant.ID = state.ID.ValueString()
+ if err != nil {
+ resp.Diagnostics.AddError("unable to map to tenant", err.Error())
+ return
+ }
+
+ tflog.Info(ctx, fmt.Sprintf("updating Tenant (%s)", data.ID))
+
+ tenant.ProjectEnvironments = tenantFromApi.ProjectEnvironments
+ updatedTenant, err := tenants.Update(r.Config.Client, tenant)
+ if err != nil {
+ resp.Diagnostics.AddError("unable to update tenant", err.Error())
+ return
+ }
+
+ mapTenantToState(data, updatedTenant)
+
+ tflog.Info(ctx, fmt.Sprintf("Tenant updated (%s)", data.ID))
+
+ resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
+}
+
+func (r *tenantTypeResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
+ internal.Mutex.Lock()
+ defer internal.Mutex.Unlock()
+
+ var data schemas.TenantModel
+
+ resp.Diagnostics.Append(req.State.Get(ctx, &data)...)
+ if resp.Diagnostics.HasError() {
+ return
+ }
+
+ if err := tenants.DeleteByID(r.Config.Client, data.SpaceID.ValueString(), data.ID.ValueString()); err != nil {
+ resp.Diagnostics.AddError("unable to delete tenant", err.Error())
+ return
+ }
+}
+
+func mapStateToTenant(data *schemas.TenantModel) (*tenants.Tenant, error) {
+ tenant := tenants.NewTenant(data.Name.ValueString())
+ tenant.ID = data.ID.ValueString()
+ tenant.ClonedFromTenantID = data.ClonedFromTenantId.ValueString()
+ tenant.Description = data.Description.ValueString()
+ tenant.SpaceID = data.SpaceID.ValueString()
+ if len(data.TenantTags.Elements()) > 0 {
+ tenant.TenantTags = util.ExpandStringList(data.TenantTags)
+ } else {
+ tenant.TenantTags = []string{}
+ }
+ sort.Strings(tenant.TenantTags)
+
+ return tenant, nil
+}
+
+func mapTenantToState(data *schemas.TenantModel, tenant *tenants.Tenant) {
+ data.ID = types.StringValue(tenant.ID)
+ data.ClonedFromTenantId = types.StringValue(tenant.ClonedFromTenantID)
+ data.Description = types.StringValue(tenant.Description)
+ data.SpaceID = types.StringValue(tenant.SpaceID)
+ data.Name = types.StringValue(tenant.Name)
+ sort.Strings(tenant.TenantTags)
+ data.TenantTags = util.Ternary(tenant.TenantTags != nil && len(tenant.TenantTags) > 0, util.FlattenStringList(tenant.TenantTags), types.ListValueMust(types.StringType, make([]attr.Value, 0)))
+}
diff --git a/octopusdeploy_framework/resource_tenant_migration_test.go b/octopusdeploy_framework/resource_tenant_migration_test.go
new file mode 100644
index 000000000..0ca7404e7
--- /dev/null
+++ b/octopusdeploy_framework/resource_tenant_migration_test.go
@@ -0,0 +1,109 @@
+package octopusdeploy_framework
+
+import (
+ "fmt"
+ "github.com/hashicorp/terraform-plugin-testing/helper/acctest"
+ "github.com/hashicorp/terraform-plugin-testing/helper/resource"
+ "github.com/hashicorp/terraform-plugin-testing/plancheck"
+ "github.com/hashicorp/terraform-plugin-testing/terraform"
+ "github.com/stretchr/testify/assert"
+ "os"
+ "sort"
+ "testing"
+)
+
+func TestTenantResource_UpgradeFromSDK_ToPluginFramework(t *testing.T) {
+ // override the path to check for terraformrc file and test against the real 0.21.1 version
+ os.Setenv("TF_CLI_CONFIG_FILE=", "")
+
+ name := acctest.RandStringFromCharSet(20, acctest.CharSetAlpha)
+ resource.Test(t, resource.TestCase{
+ CheckDestroy: testTenantProjectDestroyed,
+ Steps: []resource.TestStep{
+ {
+ ExternalProviders: map[string]resource.ExternalProvider{
+ "octopusdeploy": {
+ VersionConstraint: "0.22.0",
+ Source: "OctopusDeployLabs/octopusdeploy",
+ },
+ },
+ Config: tenantConfig(),
+ },
+ {
+ ProtoV6ProviderFactories: ProtoV6ProviderFactories(),
+ Config: tenantConfig(),
+ ConfigPlanChecks: resource.ConfigPlanChecks{
+ PreApply: []plancheck.PlanCheck{
+ plancheck.ExpectEmptyPlan(),
+ },
+ },
+ },
+ {
+ ProtoV6ProviderFactories: ProtoV6ProviderFactories(),
+ Config: updatedTenantResourceConfig(),
+ Check: resource.ComposeTestCheckFunc(
+ testTenantResourceUpdated(t, name),
+ ),
+ },
+ },
+ })
+}
+
+func tenantConfig() string {
+ return fmt.Sprintf(`
+ resource "octopusdeploy_tenant" "tenant1" {
+ name = "tenant test"
+ }`)
+}
+
+func updatedTenantResourceConfig() string {
+ return fmt.Sprintf(`
+resource "octopusdeploy_tag_set" "tagset_tag1" {
+ name = "tag1"
+ description = "Test tagset"
+ sort_order = 0
+}
+
+resource "octopusdeploy_tag" "tag_a" {
+ name = "a"
+ color = "#333333"
+ description = "tag a"
+ sort_order = 2
+ tag_set_id = octopusdeploy_tag_set.tagset_tag1.id
+}
+
+resource "octopusdeploy_tag" "tag_b" {
+ name = "b"
+ color = "#333333"
+ description = "tag b"
+ sort_order = 3
+ tag_set_id = octopusdeploy_tag_set.tagset_tag1.id
+}
+
+resource "octopusdeploy_tenant" "tenant1" {
+ name = "Updated tenant"
+ description = "Updated description"
+ tenant_tags = ["tag1/a", "tag1/b"]
+ depends_on = [octopusdeploy_tag.tag_a, octopusdeploy_tag.tag_b]
+}`)
+}
+
+func testTenantResourceUpdated(t *testing.T, name string) resource.TestCheckFunc {
+ return func(s *terraform.State) error {
+ tenantId := s.RootModule().Resources["octopusdeploy_tenant.tenant1"].Primary.ID
+ tenant, err := octoClient.Tenants.GetByID(tenantId)
+ if err != nil {
+ return fmt.Errorf("failed to retrieve tenant by ID: %s", err)
+ }
+ sort.Strings(tenant.TenantTags)
+
+ assert.NotEmpty(t, "Tenant ID did not match expected value", tenant.ID)
+ assert.Equal(t, fmt.Sprintf("Updated description"), tenant.Description)
+ assert.Equal(t, "", tenant.ClonedFromTenantID)
+ assert.Equal(t, "Updated tenant", tenant.Name)
+ assert.Equal(t, "Spaces-1", tenant.SpaceID)
+ assert.Equal(t, []string{"tag1/a", "tag1/b"}, tenant.TenantTags)
+
+ return nil
+ }
+}
diff --git a/octopusdeploy/resource_tenant_test.go b/octopusdeploy_framework/resource_tenant_test.go
similarity index 95%
rename from octopusdeploy/resource_tenant_test.go
rename to octopusdeploy_framework/resource_tenant_test.go
index 22b03b365..cd5a28b72 100644
--- a/octopusdeploy/resource_tenant_test.go
+++ b/octopusdeploy_framework/resource_tenant_test.go
@@ -1,17 +1,16 @@
-package octopusdeploy
+package octopusdeploy_framework
import (
"fmt"
+ "github.com/hashicorp/terraform-plugin-testing/helper/acctest"
+ "github.com/hashicorp/terraform-plugin-testing/helper/resource"
+ "github.com/hashicorp/terraform-plugin-testing/terraform"
"path/filepath"
"testing"
"github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/tenants"
"github.com/OctopusSolutionsEngineering/OctopusTerraformTestFramework/octoclient"
"github.com/OctopusSolutionsEngineering/OctopusTerraformTestFramework/test"
-
- "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest"
- "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
- "github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
)
func TestAccTenantBasic(t *testing.T) {
@@ -34,7 +33,7 @@ func TestAccTenantBasic(t *testing.T) {
resource.Test(t, resource.TestCase{
CheckDestroy: testAccTenantCheckDestroy,
- PreCheck: func() { testAccPreCheck(t) },
+ PreCheck: func() { TestAccPreCheck(t) },
ProtoV6ProviderFactories: ProtoV6ProviderFactories(),
Steps: []resource.TestStep{
{
diff --git a/octopusdeploy_framework/schemas/tenant.go b/octopusdeploy_framework/schemas/tenant.go
index 41d55b7d1..497540621 100644
--- a/octopusdeploy_framework/schemas/tenant.go
+++ b/octopusdeploy_framework/schemas/tenant.go
@@ -5,16 +5,21 @@ import (
"github.com/OctopusDeploy/terraform-provider-octopusdeploy/octopusdeploy_framework/util"
"github.com/hashicorp/terraform-plugin-framework/attr"
datasourceSchema "github.com/hashicorp/terraform-plugin-framework/datasource/schema"
+ resourceSchema "github.com/hashicorp/terraform-plugin-framework/resource/schema"
+ "github.com/hashicorp/terraform-plugin-framework/resource/schema/listplanmodifier"
+ "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
+ "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault"
"github.com/hashicorp/terraform-plugin-framework/types"
)
type TenantModel struct {
ClonedFromTenantId types.String `tfsdk:"cloned_from_tenant_id"`
Description types.String `tfsdk:"description"`
- ID types.String `tfsdk:"id"`
Name types.String `tfsdk:"name"`
SpaceID types.String `tfsdk:"space_id"`
TenantTags types.List `tfsdk:"tenant_tags"`
+
+ ResourceModel
}
type TenantsModel struct {
@@ -105,3 +110,27 @@ func GetTenantDataSourceSchema() map[string]datasourceSchema.Attribute {
},
}
}
+
+func GetTenantResourceSchema() map[string]resourceSchema.Attribute {
+ return map[string]resourceSchema.Attribute{
+ "cloned_from_tenant_id": resourceSchema.StringAttribute{
+ Description: "The ID of the tenant from which this tenant was cloned.",
+ Optional: true,
+ Computed: true,
+ Default: stringdefault.StaticString(""),
+ },
+ "description": util.GetDescriptionResourceSchema("tenant"),
+ "id": util.GetIdResourceSchema(),
+ "name": util.GetNameResourceSchema(true),
+ "space_id": util.GetSpaceIdResourceSchema("tenant"),
+ "tenant_tags": resourceSchema.ListAttribute{
+ Description: "A list of tenant tags associated with this resource.",
+ ElementType: types.StringType,
+ Optional: true,
+ Computed: true,
+ PlanModifiers: []planmodifier.List{
+ listplanmodifier.UseStateForUnknown(),
+ },
+ },
+ }
+}
From d10c46797e4914498e46dff5ab571661a83cf8dd Mon Sep 17 00:00:00 2001
From: Huy Nguyen <162080607+HuyPhanNguyen@users.noreply.github.com>
Date: Mon, 12 Aug 2024 15:00:47 +1000
Subject: [PATCH 11/12] chore!: Migrate username_password_account resource
(#721)
* Add username_password_account resource
* Fix test fail
* Add import and import test
* Update octopusdeploy_framework/schemas/username_password_account.go
Co-authored-by: Henrik Andersson
* Update follow new way to handle a missing resource in the Read function
* fix the document
* fix issue list set to state as null
* tidy
---------
Co-authored-by: Henrik Andersson
---
docs/resources/username_password_account.md | 2 +-
octopusdeploy/provider.go | 1 -
...bernetes_cluster_deployment_target_test.go | 7 +
.../resource_username_password_account.go | 95 --------
.../schema_username_password_account.go | 90 --------
octopusdeploy_framework/framework_provider.go | 1 +
.../resource_username_password_account.go | 210 ++++++++++++++++++
...rname_password_account_integration_test.go | 2 +-
...resource_username_password_account_test.go | 87 ++++++--
.../schemas/username_password_account.go | 40 ++++
10 files changed, 333 insertions(+), 202 deletions(-)
delete mode 100644 octopusdeploy/resource_username_password_account.go
delete mode 100644 octopusdeploy/schema_username_password_account.go
create mode 100644 octopusdeploy_framework/resource_username_password_account.go
rename {octopusdeploy => octopusdeploy_framework}/resource_username_password_account_integration_test.go (98%)
rename {octopusdeploy => octopusdeploy_framework}/resource_username_password_account_test.go (56%)
create mode 100644 octopusdeploy_framework/schemas/username_password_account.go
diff --git a/docs/resources/username_password_account.md b/docs/resources/username_password_account.md
index cd949fa53..f00bd5ad6 100644
--- a/docs/resources/username_password_account.md
+++ b/docs/resources/username_password_account.md
@@ -23,7 +23,7 @@ resource "octopusdeploy_username_password_account" "example" {
### Required
-- `name` (String) The name of this resource.
+- `name` (String) The name of the username-password account.
- `username` (String, Sensitive) The username associated with this resource.
### Optional
diff --git a/octopusdeploy/provider.go b/octopusdeploy/provider.go
index ebdaf0b94..ed362eb12 100644
--- a/octopusdeploy/provider.go
+++ b/octopusdeploy/provider.go
@@ -71,7 +71,6 @@ func Provider() *schema.Provider {
"octopusdeploy_token_account": resourceTokenAccount(),
"octopusdeploy_user": resourceUser(),
"octopusdeploy_user_role": resourceUserRole(),
- "octopusdeploy_username_password_account": resourceUsernamePasswordAccount(),
},
Schema: map[string]*schema.Schema{
"address": {
diff --git a/octopusdeploy/resource_kubernetes_cluster_deployment_target_test.go b/octopusdeploy/resource_kubernetes_cluster_deployment_target_test.go
index 0b92199bd..e1973adc0 100644
--- a/octopusdeploy/resource_kubernetes_cluster_deployment_target_test.go
+++ b/octopusdeploy/resource_kubernetes_cluster_deployment_target_test.go
@@ -149,6 +149,13 @@ func testAccKubernetesClusterDeploymentTargetBasic(accountLocalName string, acco
}`, localName, clusterURL, environmentID, name, userRoleID, usernamePasswordAccountID)
}
+func testUsernamePasswordMinimum(localName string, name string, username string) string {
+ return fmt.Sprintf(`resource "octopusdeploy_username_password_account" "%s" {
+ name = "%s"
+ username = "%s"
+ }`, localName, name, username)
+}
+
func testAccKubernetesClusterDeploymentTargetGcp(
accountLocalName string,
accountName string,
diff --git a/octopusdeploy/resource_username_password_account.go b/octopusdeploy/resource_username_password_account.go
deleted file mode 100644
index 4d6ba8b79..000000000
--- a/octopusdeploy/resource_username_password_account.go
+++ /dev/null
@@ -1,95 +0,0 @@
-package octopusdeploy
-
-import (
- "context"
- "log"
-
- "github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/accounts"
- "github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/client"
- "github.com/OctopusDeploy/terraform-provider-octopusdeploy/internal/errors"
- "github.com/hashicorp/terraform-plugin-sdk/v2/diag"
- "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
-)
-
-func resourceUsernamePasswordAccount() *schema.Resource {
- return &schema.Resource{
- CreateContext: resourceUsernamePasswordAccountCreate,
- DeleteContext: resourceUsernamePasswordAccountDelete,
- Description: "This resource manages username-password accounts in Octopus Deploy.",
- Importer: getImporter(),
- ReadContext: resourceUsernamePasswordAccountRead,
- Schema: getUsernamePasswordAccountSchema(),
- UpdateContext: resourceUsernamePasswordAccountUpdate,
- }
-}
-
-func resourceUsernamePasswordAccountCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
- account := expandUsernamePasswordAccount(d)
-
- log.Printf("[INFO] creating username-password account: %#v", account)
-
- client := m.(*client.Client)
- createdAccount, err := accounts.Add(client, account)
- if err != nil {
- return diag.FromErr(err)
- }
-
- if err := setUsernamePasswordAccount(ctx, d, createdAccount.(*accounts.UsernamePasswordAccount)); err != nil {
- return diag.FromErr(err)
- }
-
- d.SetId(createdAccount.GetID())
-
- log.Printf("[INFO] username-password account created (%s)", d.Id())
- return nil
-}
-
-func resourceUsernamePasswordAccountDelete(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
- log.Printf("[INFO] deleting username-password account (%s)", d.Id())
-
- client := m.(*client.Client)
- if err := accounts.DeleteByID(client, d.Get("space_id").(string), d.Id()); err != nil {
- return diag.FromErr(err)
- }
-
- d.SetId("")
-
- log.Printf("[INFO] username-password account deleted")
- return nil
-}
-
-func resourceUsernamePasswordAccountRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
- log.Printf("[INFO] reading username-password account (%s)", d.Id())
-
- client := m.(*client.Client)
- accountResource, err := accounts.GetByID(client, d.Get("space_id").(string), d.Id())
- if err != nil {
- return errors.ProcessApiError(ctx, d, err, "username-password account")
- }
-
- if err := setUsernamePasswordAccount(ctx, d, accountResource.(*accounts.UsernamePasswordAccount)); err != nil {
- return diag.FromErr(err)
- }
-
- log.Printf("[INFO] username-password account read: (%s)", d.Id())
- return nil
-}
-
-func resourceUsernamePasswordAccountUpdate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
- account := expandUsernamePasswordAccount(d)
-
- log.Printf("[INFO] updating username-password account: %#v", account)
-
- client := m.(*client.Client)
- updatedAccount, err := accounts.Update(client, account)
- if err != nil {
- return diag.FromErr(err)
- }
-
- if err := setUsernamePasswordAccount(ctx, d, updatedAccount.(*accounts.UsernamePasswordAccount)); err != nil {
- return diag.FromErr(err)
- }
-
- log.Printf("[INFO] username-password account updated (%s)", d.Id())
- return nil
-}
diff --git a/octopusdeploy/schema_username_password_account.go b/octopusdeploy/schema_username_password_account.go
deleted file mode 100644
index 4e0c50b65..000000000
--- a/octopusdeploy/schema_username_password_account.go
+++ /dev/null
@@ -1,90 +0,0 @@
-package octopusdeploy
-
-import (
- "context"
- "fmt"
-
- "github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/accounts"
- "github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/core"
- "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
-)
-
-func expandUsernamePasswordAccount(d *schema.ResourceData) accounts.IUsernamePasswordAccount {
- name := d.Get("name").(string)
-
- account, _ := accounts.NewUsernamePasswordAccount(name)
- account.SetID(d.Id())
- account.SetPassword(core.NewSensitiveValue(d.Get("password").(string)))
-
- if v, ok := d.GetOk("description"); ok {
- account.SetDescription(v.(string))
- }
-
- if v, ok := d.GetOk("environments"); ok {
- account.SetEnvironmentIDs(getSliceFromTerraformTypeList(v))
- }
-
- if v, ok := d.GetOk("space_id"); ok {
- account.SetSpaceID(v.(string))
- }
-
- if v, ok := d.GetOk("tenanted_deployment_participation"); ok {
- account.SetTenantedDeploymentMode(core.TenantedDeploymentMode(v.(string)))
- }
-
- if v, ok := d.GetOk("tenants"); ok {
- account.SetTenantIDs(getSliceFromTerraformTypeList(v))
- }
-
- if v, ok := d.GetOk("tenant_tags"); ok {
- account.SetTenantTags(getSliceFromTerraformTypeList(v))
- }
-
- if v, ok := d.GetOk("username"); ok {
- account.SetUsername(v.(string))
- }
-
- return account
-}
-
-func setUsernamePasswordAccount(ctx context.Context, d *schema.ResourceData, account *accounts.UsernamePasswordAccount) error {
- d.Set("description", account.GetDescription())
-
- if err := d.Set("environments", account.GetEnvironmentIDs()); err != nil {
- return fmt.Errorf("error setting environments: %s", err)
- }
-
- d.Set("id", account.GetID())
- d.Set("name", account.GetName())
- d.Set("space_id", account.GetSpaceID())
- d.Set("tenanted_deployment_participation", account.GetTenantedDeploymentMode())
-
- if err := d.Set("tenants", account.GetTenantIDs()); err != nil {
- return fmt.Errorf("error setting tenants: %s", err)
- }
-
- if err := d.Set("tenant_tags", account.TenantTags); err != nil {
- return fmt.Errorf("error setting tenant_tags: %s", err)
- }
-
- d.Set("username", account.Username)
-
- d.SetId(account.GetID())
-
- return nil
-}
-
-func getUsernamePasswordAccountSchema() map[string]*schema.Schema {
- return map[string]*schema.Schema{
- "description": getDescriptionSchema("username/password account"),
- "environments": getEnvironmentsSchema(),
- "id": getIDSchema(),
- "name": getNameSchema(true),
- "password": getPasswordSchema(false),
- "space_id": getSpaceIDSchema(),
- "tenanted_deployment_participation": getTenantedDeploymentSchema(),
- "tenants": getTenantsSchema(),
- "tenant_tags": getTenantTagsSchema(),
- "username": getUsernameSchema(true),
- }
-}
diff --git a/octopusdeploy_framework/framework_provider.go b/octopusdeploy_framework/framework_provider.go
index 68686d521..0e1ac1453 100644
--- a/octopusdeploy_framework/framework_provider.go
+++ b/octopusdeploy_framework/framework_provider.go
@@ -94,6 +94,7 @@ func (p *octopusDeployFrameworkProvider) Resources(ctx context.Context) []func()
NewVariableResource,
NewProjectResource,
NewDockerContainerRegistryFeedResource,
+ NewUsernamePasswordAccountResource,
NewRunbookResource,
NewTenantResource,
}
diff --git a/octopusdeploy_framework/resource_username_password_account.go b/octopusdeploy_framework/resource_username_password_account.go
new file mode 100644
index 000000000..307ffe3fd
--- /dev/null
+++ b/octopusdeploy_framework/resource_username_password_account.go
@@ -0,0 +1,210 @@
+package octopusdeploy_framework
+
+import (
+ "context"
+ "fmt"
+ "github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/accounts"
+ "github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/core"
+ "github.com/OctopusDeploy/terraform-provider-octopusdeploy/internal/errors"
+ "github.com/OctopusDeploy/terraform-provider-octopusdeploy/octopusdeploy_framework/schemas"
+ "github.com/OctopusDeploy/terraform-provider-octopusdeploy/octopusdeploy_framework/util"
+ "github.com/hashicorp/terraform-plugin-framework/attr"
+ "github.com/hashicorp/terraform-plugin-framework/resource"
+ "github.com/hashicorp/terraform-plugin-framework/types"
+ "github.com/hashicorp/terraform-plugin-log/tflog"
+)
+
+var _ resource.Resource = &usernamePasswordAccountResource{}
+var _ resource.ResourceWithImportState = &usernamePasswordAccountResource{}
+
+type usernamePasswordAccountResource struct {
+ *Config
+}
+
+func NewUsernamePasswordAccountResource() resource.Resource {
+ return &usernamePasswordAccountResource{}
+}
+
+func (r *usernamePasswordAccountResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
+ resp.TypeName = util.GetTypeName("username_password_account")
+}
+
+func (r *usernamePasswordAccountResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) {
+ resp.Schema = schemas.GetUsernamePasswordAccountResourceSchema()
+}
+
+func (r *usernamePasswordAccountResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
+ r.Config = ResourceConfiguration(req, resp)
+}
+func (r *usernamePasswordAccountResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
+ var plan schemas.UsernamePasswordAccountResourceModel
+ resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
+ if resp.Diagnostics.HasError() {
+ return
+ }
+
+ tflog.Debug(ctx, "Creating username password account", map[string]interface{}{
+ "name": plan.Name.ValueString(),
+ })
+
+ account := expandUsernamePasswordAccount(ctx, plan)
+ createdAccount, err := accounts.Add(r.Client, account)
+ if err != nil {
+ resp.Diagnostics.AddError("Error creating username password account", err.Error())
+ return
+ }
+
+ state := flattenUsernamePasswordAccount(ctx, createdAccount.(*accounts.UsernamePasswordAccount), plan)
+ resp.Diagnostics.Append(resp.State.Set(ctx, state)...)
+}
+
+func (r *usernamePasswordAccountResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
+ var state schemas.UsernamePasswordAccountResourceModel
+ resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
+ if resp.Diagnostics.HasError() {
+ return
+ }
+
+ account, err := accounts.GetByID(r.Client, state.SpaceID.ValueString(), state.ID.ValueString())
+ if err != nil {
+ if err := errors.ProcessApiErrorV2(ctx, resp, state, err, "usernamePasswordAccountResource"); err != nil {
+ resp.Diagnostics.AddError("unable to load username password account", err.Error())
+ }
+ return
+ }
+
+ newState := flattenUsernamePasswordAccount(ctx, account.(*accounts.UsernamePasswordAccount), state)
+ resp.Diagnostics.Append(resp.State.Set(ctx, newState)...)
+}
+
+func (r *usernamePasswordAccountResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
+ var plan schemas.UsernamePasswordAccountResourceModel
+ resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
+ if resp.Diagnostics.HasError() {
+ return
+ }
+
+ account := expandUsernamePasswordAccount(ctx, plan)
+ updatedAccount, err := accounts.Update(r.Client, account)
+ if err != nil {
+ resp.Diagnostics.AddError("Error updating username password account", err.Error())
+ return
+ }
+
+ state := flattenUsernamePasswordAccount(ctx, updatedAccount.(*accounts.UsernamePasswordAccount), plan)
+ resp.Diagnostics.Append(resp.State.Set(ctx, state)...)
+}
+
+func (r *usernamePasswordAccountResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
+ var state schemas.UsernamePasswordAccountResourceModel
+ resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
+ if resp.Diagnostics.HasError() {
+ return
+ }
+
+ err := accounts.DeleteByID(r.Client, state.SpaceID.ValueString(), state.ID.ValueString())
+ if err != nil {
+ resp.Diagnostics.AddError("Error deleting username password account", err.Error())
+ return
+ }
+}
+
+func (r *usernamePasswordAccountResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
+ accountID := req.ID
+
+ account, err := accounts.GetByID(r.Client, r.Client.GetSpaceID(), accountID)
+ if err != nil {
+ resp.Diagnostics.AddError(
+ "Error reading username password account",
+ fmt.Sprintf("Unable to read username password account with ID %s: %s", accountID, err.Error()),
+ )
+ return
+ }
+
+ usernamePasswordAccount, ok := account.(*accounts.UsernamePasswordAccount)
+ if !ok {
+ resp.Diagnostics.AddError(
+ "Unexpected account type",
+ fmt.Sprintf("Expected username password account, got: %T", account),
+ )
+ return
+ }
+
+ state := schemas.UsernamePasswordAccountResourceModel{
+ SpaceID: types.StringValue(usernamePasswordAccount.GetSpaceID()),
+ Name: types.StringValue(usernamePasswordAccount.GetName()),
+ Description: types.StringValue(usernamePasswordAccount.GetDescription()),
+ Username: types.StringValue(usernamePasswordAccount.GetUsername()),
+ TenantedDeploymentParticipation: types.StringValue(string(usernamePasswordAccount.GetTenantedDeploymentMode())),
+ Environments: flattenStringList(usernamePasswordAccount.GetEnvironmentIDs(), types.ListNull(types.StringType)),
+ Tenants: flattenStringList(usernamePasswordAccount.GetTenantIDs(), types.ListNull(types.StringType)),
+ TenantTags: flattenStringList(usernamePasswordAccount.TenantTags, types.ListNull(types.StringType)),
+ Password: types.StringNull(),
+ }
+ state.ID = types.StringValue(usernamePasswordAccount.ID)
+
+ resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
+}
+
+func expandUsernamePasswordAccount(ctx context.Context, model schemas.UsernamePasswordAccountResourceModel) *accounts.UsernamePasswordAccount {
+ account, _ := accounts.NewUsernamePasswordAccount(model.Name.ValueString())
+
+ account.SetID(model.ID.ValueString())
+ account.SetDescription(model.Description.ValueString())
+ account.SetSpaceID(model.SpaceID.ValueString())
+ account.SetUsername(model.Username.ValueString())
+ account.SetPassword(core.NewSensitiveValue(model.Password.ValueString()))
+ account.SetEnvironmentIDs(expandStringList(model.Environments))
+ account.SetTenantedDeploymentMode(core.TenantedDeploymentMode(model.TenantedDeploymentParticipation.ValueString()))
+ account.SetTenantIDs(expandStringList(model.Tenants))
+ account.SetTenantTags(expandStringList(model.TenantTags))
+
+ return account
+}
+
+func flattenUsernamePasswordAccount(ctx context.Context, account *accounts.UsernamePasswordAccount, model schemas.UsernamePasswordAccountResourceModel) schemas.UsernamePasswordAccountResourceModel {
+ model.ID = types.StringValue(account.GetID())
+ model.SpaceID = types.StringValue(account.GetSpaceID())
+ model.Name = types.StringValue(account.GetName())
+ model.Description = types.StringValue(account.GetDescription())
+ model.Username = types.StringValue(account.GetUsername())
+ model.TenantedDeploymentParticipation = types.StringValue(string(account.GetTenantedDeploymentMode()))
+
+ model.Environments = flattenStringList(account.GetEnvironmentIDs(), model.Environments)
+ model.Tenants = flattenStringList(account.GetTenantIDs(), model.Tenants)
+ model.TenantTags = flattenStringList(account.TenantTags, model.TenantTags)
+
+ // Note: We don't flatten the password as it's sensitive and not returned by the API
+
+ return model
+}
+
+func expandStringList(list types.List) []string {
+ if list.IsNull() || list.IsUnknown() {
+ return nil
+ }
+
+ var result []string
+ list.ElementsAs(context.Background(), &result, false)
+ if len(result) == 0 {
+ return nil
+ }
+
+ return result
+}
+
+func flattenStringList(slice []string, currentList types.List) types.List {
+ if len(slice) == 0 && currentList.IsNull() {
+ return types.ListNull(types.StringType)
+ }
+ if slice == nil {
+ return types.ListNull(types.StringType)
+ }
+
+ valueSlice := make([]attr.Value, len(slice))
+ for i, s := range slice {
+ valueSlice[i] = types.StringValue(s)
+ }
+
+ return types.ListValueMust(types.StringType, valueSlice)
+}
diff --git a/octopusdeploy/resource_username_password_account_integration_test.go b/octopusdeploy_framework/resource_username_password_account_integration_test.go
similarity index 98%
rename from octopusdeploy/resource_username_password_account_integration_test.go
rename to octopusdeploy_framework/resource_username_password_account_integration_test.go
index b5ea00af4..a730246f1 100644
--- a/octopusdeploy/resource_username_password_account_integration_test.go
+++ b/octopusdeploy_framework/resource_username_password_account_integration_test.go
@@ -1,4 +1,4 @@
-package octopusdeploy
+package octopusdeploy_framework
import (
"github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/accounts"
diff --git a/octopusdeploy/resource_username_password_account_test.go b/octopusdeploy_framework/resource_username_password_account_test.go
similarity index 56%
rename from octopusdeploy/resource_username_password_account_test.go
rename to octopusdeploy_framework/resource_username_password_account_test.go
index e1a29bd9f..25977a673 100644
--- a/octopusdeploy/resource_username_password_account_test.go
+++ b/octopusdeploy_framework/resource_username_password_account_test.go
@@ -1,16 +1,16 @@
-package octopusdeploy
+package octopusdeploy_framework
import (
"fmt"
+ "github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/core"
"github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/projects"
"github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/variables"
"github.com/OctopusSolutionsEngineering/OctopusTerraformTestFramework/octoclient"
"github.com/OctopusSolutionsEngineering/OctopusTerraformTestFramework/test"
+ "github.com/hashicorp/terraform-plugin-testing/helper/acctest"
+ "github.com/hashicorp/terraform-plugin-testing/helper/resource"
+ "github.com/hashicorp/terraform-plugin-testing/terraform"
"testing"
-
- "github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/core"
- "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest"
- "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
)
func TestAccUsernamePasswordBasic(t *testing.T) {
@@ -26,8 +26,7 @@ func TestAccUsernamePasswordBasic(t *testing.T) {
config := testUsernamePasswordBasic(localName, description, name, username, password, tenantedDeploymentParticipation)
resource.Test(t, resource.TestCase{
- CheckDestroy: testAccountCheckDestroy,
- PreCheck: func() { testAccPreCheck(t) },
+ PreCheck: func() { TestAccPreCheck(t) },
ProtoV6ProviderFactories: ProtoV6ProviderFactories(),
Steps: []resource.TestStep{
{
@@ -48,6 +47,17 @@ func TestAccUsernamePasswordBasic(t *testing.T) {
})
}
+func testAccountExists(prefix string) resource.TestCheckFunc {
+ return func(s *terraform.State) error {
+ accountID := s.RootModule().Resources[prefix].Primary.ID
+ if _, err := octoClient.Accounts.GetByID(accountID); err != nil {
+ return err
+ }
+
+ return nil
+ }
+}
+
func testUsernamePasswordBasic(localName string, description string, name string, username string, password string, tenantedDeploymentParticipation core.TenantedDeploymentMode) string {
return fmt.Sprintf(`resource "octopusdeploy_username_password_account" "%s" {
description = "%s"
@@ -58,13 +68,6 @@ func testUsernamePasswordBasic(localName string, description string, name string
}`, localName, description, name, password, tenantedDeploymentParticipation, username)
}
-func testUsernamePasswordMinimum(localName string, name string, username string) string {
- return fmt.Sprintf(`resource "octopusdeploy_username_password_account" "%s" {
- name = "%s"
- username = "%s"
- }`, localName, name, username)
-}
-
// TestUsernamePasswordVariableResource verifies that a project variable referencing a username/password account
// can be created
func TestUsernamePasswordVariableResource(t *testing.T) {
@@ -111,3 +114,59 @@ func TestUsernamePasswordVariableResource(t *testing.T) {
t.Fatalf("The variable must have type of UsernamePasswordAccount.")
}
}
+
+func TestAccUsernamePasswordAccountImport(t *testing.T) {
+ localName := acctest.RandStringFromCharSet(20, acctest.CharSetAlpha)
+ resourceName := "octopusdeploy_username_password_account." + localName
+
+ description := acctest.RandStringFromCharSet(20, acctest.CharSetAlpha)
+ name := acctest.RandStringFromCharSet(20, acctest.CharSetAlpha)
+ password := acctest.RandStringFromCharSet(20, acctest.CharSetAlpha)
+ tenantedDeploymentParticipation := core.TenantedDeploymentModeTenantedOrUntenanted
+ username := acctest.RandStringFromCharSet(20, acctest.CharSetAlpha)
+
+ resource.Test(t, resource.TestCase{
+ PreCheck: func() { TestAccPreCheck(t) },
+ ProtoV6ProviderFactories: ProtoV6ProviderFactories(),
+ Steps: []resource.TestStep{
+ // Create and test the resource
+ {
+ Config: testAccUsernamePasswordAccountBasic(localName, description, name, username, password, tenantedDeploymentParticipation),
+ Check: resource.ComposeTestCheckFunc(
+ testAccountExists(resourceName),
+ resource.TestCheckResourceAttr(resourceName, "name", name),
+ resource.TestCheckResourceAttr(resourceName, "description", description),
+ resource.TestCheckResourceAttr(resourceName, "username", username),
+ resource.TestCheckResourceAttr(resourceName, "tenanted_deployment_participation", string(tenantedDeploymentParticipation)),
+ ),
+ },
+ {
+ ResourceName: resourceName,
+ ImportState: true,
+ ImportStateVerify: true,
+ ImportStateVerifyIgnore: []string{"password"},
+ ImportStateIdFunc: testAccUsernamePasswordAccountImportStateIdFunc(resourceName),
+ },
+ },
+ })
+}
+
+func testAccUsernamePasswordAccountImportStateIdFunc(resourceName string) resource.ImportStateIdFunc {
+ return func(s *terraform.State) (string, error) {
+ rs, ok := s.RootModule().Resources[resourceName]
+ if !ok {
+ return "", fmt.Errorf("Not found: %s", resourceName)
+ }
+
+ return rs.Primary.ID, nil
+ }
+}
+func testAccUsernamePasswordAccountBasic(localName, description, name, username, password string, tenantedDeploymentParticipation core.TenantedDeploymentMode) string {
+ return fmt.Sprintf(`resource "octopusdeploy_username_password_account" "%s" {
+ name = "%s"
+ description = "%s"
+ username = "%s"
+ password = "%s"
+ tenanted_deployment_participation = "%s"
+ }`, localName, name, description, username, password, tenantedDeploymentParticipation)
+}
diff --git a/octopusdeploy_framework/schemas/username_password_account.go b/octopusdeploy_framework/schemas/username_password_account.go
new file mode 100644
index 000000000..c5bff07fc
--- /dev/null
+++ b/octopusdeploy_framework/schemas/username_password_account.go
@@ -0,0 +1,40 @@
+package schemas
+
+import (
+ "github.com/OctopusDeploy/terraform-provider-octopusdeploy/octopusdeploy_framework/util"
+ "github.com/hashicorp/terraform-plugin-framework/resource/schema"
+ "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
+ "github.com/hashicorp/terraform-plugin-framework/types"
+)
+
+func GetUsernamePasswordAccountResourceSchema() schema.Schema {
+ return schema.Schema{
+ Description: "This resource manages username-password accounts in Octopus Deploy.",
+ Attributes: map[string]schema.Attribute{
+ "id": util.ResourceString().Optional().Computed().PlanModifiers(stringplanmodifier.UseStateForUnknown()).Description("The unique ID for this resource.").Build(),
+ "space_id": util.ResourceString().Optional().Computed().PlanModifiers(stringplanmodifier.UseStateForUnknown()).Description("The space ID associated with this resource.").Build(),
+ "name": util.ResourceString().Required().Description("The name of the username-password account.").Build(),
+ "description": util.ResourceString().Optional().Computed().PlanModifiers(stringplanmodifier.UseStateForUnknown()).Default("").Description("The description of this username/password account.").Build(),
+ "environments": util.ResourceList(types.StringType).Optional().Computed().Description("A list of environment IDs associated with this resource.").Build(),
+ "password": util.ResourceString().Optional().Sensitive().Description("The password associated with this resource.").Build(),
+ "tenanted_deployment_participation": util.ResourceString().Optional().Optional().Computed().PlanModifiers(stringplanmodifier.UseStateForUnknown()).Description("The tenanted deployment mode of the resource. Valid account types are `Untenanted`, `TenantedOrUntenanted`, or `Tenanted`.").Build(),
+ "tenants": util.ResourceList(types.StringType).Optional().Computed().Description("A list of tenant IDs associated with this resource.").Build(),
+ "tenant_tags": util.ResourceList(types.StringType).Optional().Computed().Description("A list of tenant tags associated with this resource.").Build(),
+ "username": util.ResourceString().Required().Sensitive().Description("The username associated with this resource.").Build(),
+ },
+ }
+}
+
+type UsernamePasswordAccountResourceModel struct {
+ SpaceID types.String `tfsdk:"space_id"`
+ Name types.String `tfsdk:"name"`
+ Description types.String `tfsdk:"description"`
+ Environments types.List `tfsdk:"environments"`
+ Password types.String `tfsdk:"password"`
+ TenantedDeploymentParticipation types.String `tfsdk:"tenanted_deployment_participation"`
+ Tenants types.List `tfsdk:"tenants"`
+ TenantTags types.List `tfsdk:"tenant_tags"`
+ Username types.String `tfsdk:"username"`
+
+ ResourceModel
+}
From 44acc60e960ed19d524bcd26852fd3267b4ccf5d Mon Sep 17 00:00:00 2001
From: Isaac Calligeros <101079287+IsaacCalligeros95@users.noreply.github.com>
Date: Mon, 12 Aug 2024 14:55:32 +0930
Subject: [PATCH 12/12] Chore!: Migrate script module resource (#712)
---
docs/data-sources/script_modules | 26 +--
docs/data-sources/script_modules.md | 26 +--
docs/resources/script_module.md | 8 +-
octopusdeploy/data_source_script_modules.go | 48 ----
octopusdeploy/provider.go | 2 -
octopusdeploy/resource_script_module.go | 106 ---------
octopusdeploy/schema_script_modules.go | 155 -------------
.../data_source_script_modules.go | 74 ++++++
.../data_source_script_modules_test.go | 11 +-
octopusdeploy_framework/framework_provider.go | 2 +
.../resource_script_module.go | 130 +++++++++++
.../resource_script_module_test.go | 11 +-
.../schemas/script_modules.go | 213 ++++++++++++++++++
13 files changed, 459 insertions(+), 353 deletions(-)
delete mode 100644 octopusdeploy/data_source_script_modules.go
delete mode 100644 octopusdeploy/resource_script_module.go
delete mode 100644 octopusdeploy/schema_script_modules.go
create mode 100644 octopusdeploy_framework/data_source_script_modules.go
rename {octopusdeploy => octopusdeploy_framework}/data_source_script_modules_test.go (79%)
create mode 100644 octopusdeploy_framework/resource_script_module.go
rename {octopusdeploy => octopusdeploy_framework}/resource_script_module_test.go (95%)
create mode 100644 octopusdeploy_framework/schemas/script_modules.go
diff --git a/docs/data-sources/script_modules b/docs/data-sources/script_modules
index 6a12509e7..848de86dc 100644
--- a/docs/data-sources/script_modules
+++ b/docs/data-sources/script_modules
@@ -26,32 +26,32 @@ data "octopusdeploy_script_modules" "example" {
### Optional
- `ids` (List of String) A filter to search by a list of IDs.
-- `partial_name` (String) A filter to search by the partial match of a name.
+- `partial_name` (String) A filter to search by a partial name.
- `skip` (Number) A filter to specify the number of items to skip in the response.
-- `space_id` (String) A Space ID to filter by. Will revert what is specified on the provider if not set.
+- `space_id` (String) The space ID associated with this script module.
- `take` (Number) A filter to specify the number of items to take (or return) in the response.
### Read-Only
-- `id` (String) An auto-generated identifier that includes the timestamp when this data source was last modified.
-- `script_modules` (List of Object) A list of script modules that match the filter(s). (see [below for nested schema](#nestedatt--script_modules))
+- `id` (String) The unique ID for this resource.
+- `script_modules` (Attributes List) (see [below for nested schema](#nestedatt--script_modules))
### Nested Schema for `script_modules`
Read-Only:
-- `description` (String)
-- `id` (String)
-- `name` (String)
-- `script` (Set of Object) (see [below for nested schema](#nestedobjatt--script_modules--script))
-- `space_id` (String)
-- `variable_set_id` (String)
+- `description` (String) The description of this script module.
+- `id` (String) The unique ID for this resource.
+- `name` (String) The name of this resource.
+- `script` (Attributes List) The script associated with this script module. (see [below for nested schema](#nestedatt--script_modules--script))
+- `space_id` (String) The space ID associated with this Script Module.
+- `variable_set_id` (String) The variable set ID for this script module.
-
+
### Nested Schema for `script_modules.script`
Read-Only:
-- `body` (String)
-- `syntax` (String)
\ No newline at end of file
+- `body` (String) The body of this script module.
+- `syntax` (String) The syntax of the script. Valid types are `Bash`, `CSharp`, `FSharp`, `PowerShell`, or `Python`.
\ No newline at end of file
diff --git a/docs/data-sources/script_modules.md b/docs/data-sources/script_modules.md
index 35d7e16a8..2149ce0ca 100644
--- a/docs/data-sources/script_modules.md
+++ b/docs/data-sources/script_modules.md
@@ -27,34 +27,34 @@ data "octopusdeploy_script_modules" "example" {
### Optional
- `ids` (List of String) A filter to search by a list of IDs.
-- `partial_name` (String) A filter to search by the partial match of a name.
+- `partial_name` (String) A filter to search by a partial name.
- `skip` (Number) A filter to specify the number of items to skip in the response.
-- `space_id` (String) A Space ID to filter by. Will revert what is specified on the provider if not set.
+- `space_id` (String) The space ID associated with this script module.
- `take` (Number) A filter to specify the number of items to take (or return) in the response.
### Read-Only
-- `id` (String) An auto-generated identifier that includes the timestamp when this data source was last modified.
-- `script_modules` (List of Object) A list of script modules that match the filter(s). (see [below for nested schema](#nestedatt--script_modules))
+- `id` (String) The unique ID for this resource.
+- `script_modules` (Attributes List) (see [below for nested schema](#nestedatt--script_modules))
### Nested Schema for `script_modules`
Read-Only:
-- `description` (String)
-- `id` (String)
-- `name` (String)
-- `script` (Set of Object) (see [below for nested schema](#nestedobjatt--script_modules--script))
-- `space_id` (String)
-- `variable_set_id` (String)
+- `description` (String) The description of this script module.
+- `id` (String) The unique ID for this resource.
+- `name` (String) The name of this resource.
+- `script` (Attributes List) The script associated with this script module. (see [below for nested schema](#nestedatt--script_modules--script))
+- `space_id` (String) The space ID associated with this Script Module.
+- `variable_set_id` (String) The variable set ID for this script module.
-
+
### Nested Schema for `script_modules.script`
Read-Only:
-- `body` (String)
-- `syntax` (String)
+- `body` (String) The body of this script module.
+- `syntax` (String) The syntax of the script. Valid types are `Bash`, `CSharp`, `FSharp`, `PowerShell`, or `Python`.
diff --git a/docs/resources/script_module.md b/docs/resources/script_module.md
index 15d81fb84..bb484cf04 100644
--- a/docs/resources/script_module.md
+++ b/docs/resources/script_module.md
@@ -3,12 +3,12 @@
page_title: "octopusdeploy_script_module Resource - terraform-provider-octopusdeploy"
subcategory: ""
description: |-
- This resource manages script modules in Octopus Deploy.
+
---
# octopusdeploy_script_module (Resource)
-This resource manages script modules in Octopus Deploy.
+
## Example Usage
@@ -30,13 +30,13 @@ resource "octopusdeploy_script_module" "example" {
### Required
- `name` (String) The name of this resource.
-- `script` (Block Set, Min: 1, Max: 1) The script associated with this script module. (see [below for nested schema](#nestedblock--script))
### Optional
- `description` (String) The description of this script module.
- `id` (String) The unique ID for this resource.
-- `space_id` (String) The space ID associated with this resource.
+- `script` (Block List) The script associated with this script module. (see [below for nested schema](#nestedblock--script))
+- `space_id` (String) The space ID associated with this Script Module.
- `variable_set_id` (String) The variable set ID for this script module.
diff --git a/octopusdeploy/data_source_script_modules.go b/octopusdeploy/data_source_script_modules.go
deleted file mode 100644
index f782e1410..000000000
--- a/octopusdeploy/data_source_script_modules.go
+++ /dev/null
@@ -1,48 +0,0 @@
-package octopusdeploy
-
-import (
- "context"
- "time"
-
- "github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/client"
- "github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/scriptmodules"
- "github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/variables"
- "github.com/hashicorp/terraform-plugin-sdk/v2/diag"
- "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
-)
-
-func dataSourceScriptModules() *schema.Resource {
- return &schema.Resource{
- Description: "Provides information about existing script modules.",
- ReadContext: dataSourceScriptModulesRead,
- Schema: getScriptModuleDataSchema(),
- }
-}
-
-func dataSourceScriptModulesRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
- query := variables.LibraryVariablesQuery{
- ContentType: "ScriptModule",
- IDs: expandArray(d.Get("ids").([]interface{})),
- PartialName: d.Get("partial_name").(string),
- Skip: d.Get("skip").(int),
- Take: d.Get("take").(int),
- }
-
- spaceID := d.Get("space_id").(string)
-
- client := m.(*client.Client)
- existingScriptModules, err := scriptmodules.Get(client, spaceID, query)
- if err != nil {
- return diag.FromErr(err)
- }
-
- flattenedScriptModules := []interface{}{}
- for _, scriptModule := range existingScriptModules.Items {
- flattenedScriptModules = append(flattenedScriptModules, flattenScriptModule(scriptModule))
- }
-
- d.Set("script_modules", flattenedScriptModules)
- d.SetId("Script Modules " + time.Now().UTC().String())
-
- return nil
-}
diff --git a/octopusdeploy/provider.go b/octopusdeploy/provider.go
index ed362eb12..1c8ff40e9 100644
--- a/octopusdeploy/provider.go
+++ b/octopusdeploy/provider.go
@@ -25,7 +25,6 @@ func Provider() *schema.Provider {
"octopusdeploy_machine_policies": dataSourceMachinePolicies(),
"octopusdeploy_offline_package_drop_deployment_targets": dataSourceOfflinePackageDropDeploymentTargets(),
"octopusdeploy_polling_tentacle_deployment_targets": dataSourcePollingTentacleDeploymentTargets(),
- "octopusdeploy_script_modules": dataSourceScriptModules(),
"octopusdeploy_ssh_connection_deployment_targets": dataSourceSSHConnectionDeploymentTargets(),
"octopusdeploy_tag_sets": dataSourceTagSets(),
"octopusdeploy_teams": dataSourceTeams(),
@@ -60,7 +59,6 @@ func Provider() *schema.Provider {
"octopusdeploy_project_scheduled_trigger": resourceProjectScheduledTrigger(),
"octopusdeploy_runbook_process": resourceRunbookProcess(),
"octopusdeploy_scoped_user_role": resourceScopedUserRole(),
- "octopusdeploy_script_module": resourceScriptModule(),
"octopusdeploy_ssh_connection_deployment_target": resourceSSHConnectionDeploymentTarget(),
"octopusdeploy_ssh_key_account": resourceSSHKeyAccount(),
"octopusdeploy_static_worker_pool": resourceStaticWorkerPool(),
diff --git a/octopusdeploy/resource_script_module.go b/octopusdeploy/resource_script_module.go
deleted file mode 100644
index faf0f5232..000000000
--- a/octopusdeploy/resource_script_module.go
+++ /dev/null
@@ -1,106 +0,0 @@
-package octopusdeploy
-
-import (
- "context"
- "log"
-
- "github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/client"
- "github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/scriptmodules"
- "github.com/OctopusDeploy/terraform-provider-octopusdeploy/internal/errors"
- "github.com/hashicorp/terraform-plugin-sdk/v2/diag"
- "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
-)
-
-func resourceScriptModule() *schema.Resource {
- return &schema.Resource{
- CreateContext: resourceScriptModuleCreate,
- DeleteContext: resourceScriptModuleDelete,
- Description: "This resource manages script modules in Octopus Deploy.",
- Importer: getImporter(),
- ReadContext: resourceScriptModuleRead,
- Schema: getScriptModuleSchema(),
- UpdateContext: resourceScriptModuleUpdate,
- }
-}
-
-func resourceScriptModuleCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
- scriptModule := expandScriptModule(d)
-
- log.Printf("[INFO] creating script module: %#v", scriptModule)
-
- client := m.(*client.Client)
- createdScriptModule, err := scriptmodules.Add(client, scriptModule)
- if err != nil {
- return diag.FromErr(err)
- }
-
- if err := setScriptModule(ctx, d, createdScriptModule); err != nil {
- return diag.FromErr(err)
- }
-
- d.SetId(createdScriptModule.GetID())
-
- log.Printf("[INFO] script module created (%s)", d.Id())
- return nil
-}
-
-func resourceScriptModuleDelete(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
- log.Printf("[INFO] deleting script module (%s)", d.Id())
-
- var spaceID string
- if v, ok := d.GetOk("space_id"); ok {
- spaceID = v.(string)
- }
-
- client := m.(*client.Client)
- err := scriptmodules.DeleteByID(client, spaceID, d.Id())
- if err != nil {
- return diag.FromErr(err)
- }
-
- log.Printf("[INFO] script module deleted (%s)", d.Id())
- d.SetId("")
- return nil
-}
-
-func resourceScriptModuleRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
- log.Printf("[INFO] reading script module (%s)", d.Id())
-
- var spaceID string
- if v, ok := d.GetOk("space_id"); ok {
- spaceID = v.(string)
- }
-
- client := m.(*client.Client)
-
- scriptModule, err := scriptmodules.GetByID(client, spaceID, d.Id())
- if err != nil {
- return errors.ProcessApiError(ctx, d, err, "script module")
- }
-
- if err := setScriptModule(ctx, d, scriptModule); err != nil {
- return diag.FromErr(err)
- }
-
- log.Printf("[INFO] script module read (%s)", d.Id())
- return nil
-}
-
-func resourceScriptModuleUpdate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
- log.Printf("[INFO] updating script module (%s)", d.Id())
-
- scriptModule := expandScriptModule(d)
-
- client := m.(*client.Client)
- updatedScriptModule, err := scriptmodules.Update(client, scriptModule)
- if err != nil {
- return diag.FromErr(err)
- }
-
- if err := setScriptModule(ctx, d, updatedScriptModule); err != nil {
- return diag.FromErr(err)
- }
-
- log.Printf("[INFO] script module updated (%s)", d.Id())
- return nil
-}
diff --git a/octopusdeploy/schema_script_modules.go b/octopusdeploy/schema_script_modules.go
deleted file mode 100644
index 906d2ea54..000000000
--- a/octopusdeploy/schema_script_modules.go
+++ /dev/null
@@ -1,155 +0,0 @@
-package octopusdeploy
-
-import (
- "context"
- "fmt"
-
- "github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/variables"
- "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
- "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
-)
-
-func expandScriptModule(d *schema.ResourceData) *variables.ScriptModule {
- name := d.Get("name").(string)
-
- scriptModule := variables.NewScriptModule(name)
- scriptModule.ID = d.Id()
-
- if v, ok := d.GetOk("description"); ok {
- scriptModule.Description = v.(string)
- }
-
- if v, ok := d.GetOk("script"); ok {
- scripts := v.(*schema.Set).List()
- for _, script := range scripts {
- rawScript := script.(map[string]interface{})
-
- if rawScript["body"] != nil {
- scriptModule.ScriptBody = rawScript["body"].(string)
- }
-
- if rawScript["syntax"] != nil {
- scriptModule.Syntax = rawScript["syntax"].(string)
- }
- }
- }
-
- if v, ok := d.GetOk("space_id"); ok {
- scriptModule.SpaceID = v.(string)
- }
-
- if v, ok := d.GetOk("variable_set_id"); ok {
- scriptModule.VariableSetID = v.(string)
- }
-
- return scriptModule
-}
-
-func flattenScript(scriptModule *variables.ScriptModule) []interface{} {
- if scriptModule == nil {
- return nil
- }
-
- flattenedScriptModules := make([]interface{}, 1)
- flattenedScriptModules[0] = map[string]interface{}{
- "body": scriptModule.ScriptBody,
- "syntax": scriptModule.Syntax,
- }
-
- return flattenedScriptModules
-}
-
-func flattenScriptModule(scriptModule *variables.ScriptModule) map[string]interface{} {
- if scriptModule == nil {
- return nil
- }
-
- return map[string]interface{}{
- "description": scriptModule.Description,
- "id": scriptModule.GetID(),
- "name": scriptModule.Name,
- "script": flattenScript(scriptModule),
- "space_id": scriptModule.SpaceID,
- "variable_set_id": scriptModule.VariableSetID,
- }
-}
-
-func getScriptModuleDataSchema() map[string]*schema.Schema {
- dataSchema := getScriptModuleSchema()
- setDataSchema(&dataSchema)
-
- return map[string]*schema.Schema{
- "id": getDataSchemaID(),
- "space_id": getQuerySpaceID(),
- "ids": getQueryIDs(),
- "script_modules": {
- Computed: true,
- Description: "A list of script modules that match the filter(s).",
- Elem: &schema.Resource{Schema: dataSchema},
- Optional: false,
- Type: schema.TypeList,
- },
- "partial_name": getQueryPartialName(),
- "skip": getQuerySkip(),
- "take": getQueryTake(),
- }
-}
-
-func getScriptModuleSchema() map[string]*schema.Schema {
- return map[string]*schema.Schema{
- "description": getDescriptionSchema("script module"),
- "id": getIDSchema(),
- "name": getNameSchema(true),
- "script": {
- Description: "The script associated with this script module.",
- Required: true,
- Elem: &schema.Resource{
- Schema: map[string]*schema.Schema{
- "body": {
- Description: "The body of this script module.",
- Required: true,
- Type: schema.TypeString,
- },
- "syntax": {
- Description: "The syntax of the script. Valid types are `Bash`, `CSharp`, `FSharp`, `PowerShell`, or `Python`.",
- Required: true,
- Type: schema.TypeString,
- ValidateDiagFunc: validation.ToDiagFunc(validation.StringInSlice([]string{
- "Bash",
- "CSharp",
- "FSharp",
- "PowerShell",
- "Python",
- }, false)),
- },
- },
- },
- MaxItems: 1,
- MinItems: 1,
- Type: schema.TypeSet,
- },
- "space_id": getSpaceIDSchema(),
- "variable_set_id": {
- Computed: true,
- Description: "The variable set ID for this script module.",
- Optional: true,
- Type: schema.TypeString,
- },
- }
-}
-
-func setScriptModule(ctx context.Context, d *schema.ResourceData, scriptModule *variables.ScriptModule) error {
- d.Set("description", scriptModule.Description)
- d.Set("name", scriptModule.Name)
-
- if err := d.Set("script", flattenScript(scriptModule)); err != nil {
- return fmt.Errorf("error setting script: %s", err)
- }
-
- d.Set("space_id", scriptModule.SpaceID)
- d.Set("variable_set_id", scriptModule.VariableSetID)
-
- d.SetId(scriptModule.GetID())
-
- return nil
-}
diff --git a/octopusdeploy_framework/data_source_script_modules.go b/octopusdeploy_framework/data_source_script_modules.go
new file mode 100644
index 000000000..8374402de
--- /dev/null
+++ b/octopusdeploy_framework/data_source_script_modules.go
@@ -0,0 +1,74 @@
+package octopusdeploy_framework
+
+import (
+ "context"
+ "fmt"
+ "github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/scriptmodules"
+ "github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/variables"
+ "github.com/hashicorp/terraform-plugin-framework/attr"
+ "time"
+
+ "github.com/OctopusDeploy/terraform-provider-octopusdeploy/octopusdeploy_framework/schemas"
+ "github.com/OctopusDeploy/terraform-provider-octopusdeploy/octopusdeploy_framework/util"
+ "github.com/hashicorp/terraform-plugin-framework/datasource"
+ "github.com/hashicorp/terraform-plugin-framework/types"
+ "github.com/hashicorp/terraform-plugin-log/tflog"
+)
+
+type scriptModulesDataSource struct {
+ *Config
+}
+
+func NewScriptModuleDataSource() datasource.DataSource {
+ return &scriptModulesDataSource{}
+}
+
+func (l *scriptModulesDataSource) Metadata(ctx context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) {
+ tflog.Debug(ctx, "script modules datasource Metadata")
+ resp.TypeName = util.GetTypeName("script_modules")
+}
+
+func (l *scriptModulesDataSource) Schema(ctx context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) {
+ tflog.Debug(ctx, "script modules datasource Schema")
+ resp.Schema = schemas.GetDatasourceScriptModuleSchema()
+}
+
+func (l *scriptModulesDataSource) Configure(ctx context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) {
+ tflog.Debug(ctx, "script modules datasource Configure")
+ l.Config = DataSourceConfiguration(req, resp)
+}
+
+func (l *scriptModulesDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) {
+ tflog.Debug(ctx, "script modules datasource Read")
+ var data schemas.ScriptModuleDataSourceModel
+ resp.Diagnostics.Append(req.Config.Get(ctx, &data)...)
+ if resp.Diagnostics.HasError() {
+ return
+ }
+
+ query := variables.LibraryVariablesQuery{
+ ContentType: "ScriptModule",
+ IDs: util.ExpandStringList(data.IDs),
+ PartialName: data.PartialName.ValueString(),
+ Skip: int(data.Skip.ValueInt64()),
+ Take: int(data.Take.ValueInt64()),
+ }
+
+ spaceID := data.SpaceID.ValueString()
+ existingScriptModules, err := scriptmodules.Get(l.Config.Client, spaceID, query)
+ if err != nil {
+ resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Unable to read script modules, got error: %s", err))
+ return
+ }
+
+ flattenedScriptModules := []attr.Value{}
+ for _, scriptModule := range existingScriptModules.Items {
+ flattenedScriptModules = append(flattenedScriptModules, schemas.FlattenScriptModule(scriptModule))
+ }
+
+ data.ScriptModules = types.ListValueMust(types.ObjectType{AttrTypes: schemas.ScriptModuleObjectType()},
+ flattenedScriptModules)
+ data.ID = types.StringValue("Script Modules " + time.Now().UTC().String())
+
+ resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
+}
diff --git a/octopusdeploy/data_source_script_modules_test.go b/octopusdeploy_framework/data_source_script_modules_test.go
similarity index 79%
rename from octopusdeploy/data_source_script_modules_test.go
rename to octopusdeploy_framework/data_source_script_modules_test.go
index f5fa0450e..286a8ec5b 100644
--- a/octopusdeploy/data_source_script_modules_test.go
+++ b/octopusdeploy_framework/data_source_script_modules_test.go
@@ -1,12 +1,11 @@
-package octopusdeploy
+package octopusdeploy_framework
import (
"fmt"
+ "github.com/hashicorp/terraform-plugin-testing/helper/acctest"
+ "github.com/hashicorp/terraform-plugin-testing/helper/resource"
+ "github.com/hashicorp/terraform-plugin-testing/terraform"
"testing"
-
- "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest"
- "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
- "github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
)
func TestAccDataSourceScriptModules(t *testing.T) {
@@ -15,7 +14,7 @@ func TestAccDataSourceScriptModules(t *testing.T) {
take := 10
resource.Test(t, resource.TestCase{
- PreCheck: func() { testAccPreCheck(t) },
+ PreCheck: func() { TestAccPreCheck(t) },
ProtoV6ProviderFactories: ProtoV6ProviderFactories(),
Steps: []resource.TestStep{
{
diff --git a/octopusdeploy_framework/framework_provider.go b/octopusdeploy_framework/framework_provider.go
index 0e1ac1453..894f15e82 100644
--- a/octopusdeploy_framework/framework_provider.go
+++ b/octopusdeploy_framework/framework_provider.go
@@ -71,6 +71,7 @@ func (p *octopusDeployFrameworkProvider) DataSources(ctx context.Context) []func
NewVariablesDataSource,
NewProjectsDataSource,
NewTenantsDataSource,
+ NewScriptModuleDataSource,
}
}
@@ -97,6 +98,7 @@ func (p *octopusDeployFrameworkProvider) Resources(ctx context.Context) []func()
NewUsernamePasswordAccountResource,
NewRunbookResource,
NewTenantResource,
+ NewScriptModuleResource,
}
}
diff --git a/octopusdeploy_framework/resource_script_module.go b/octopusdeploy_framework/resource_script_module.go
new file mode 100644
index 000000000..8e0a1294f
--- /dev/null
+++ b/octopusdeploy_framework/resource_script_module.go
@@ -0,0 +1,130 @@
+package octopusdeploy_framework
+
+import (
+ "context"
+ "fmt"
+ "github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/scriptmodules"
+ "github.com/OctopusDeploy/terraform-provider-octopusdeploy/internal"
+ "github.com/OctopusDeploy/terraform-provider-octopusdeploy/internal/errors"
+ "github.com/OctopusDeploy/terraform-provider-octopusdeploy/octopusdeploy_framework/schemas"
+ "github.com/OctopusDeploy/terraform-provider-octopusdeploy/octopusdeploy_framework/util"
+ "github.com/hashicorp/terraform-plugin-framework/resource"
+ "github.com/hashicorp/terraform-plugin-framework/resource/schema"
+ "github.com/hashicorp/terraform-plugin-log/tflog"
+)
+
+type scriptModuleTypeResource struct {
+ *Config
+}
+
+func NewScriptModuleResource() resource.Resource {
+ return &scriptModuleTypeResource{}
+}
+
+func (r *scriptModuleTypeResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
+ resp.TypeName = util.GetTypeName("script_module")
+}
+
+func (r *scriptModuleTypeResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
+ resp.Schema = schema.Schema{
+ Attributes: schemas.GetScriptModuleResourceSchema(),
+ Blocks: schemas.GetScriptModuleSchemaBlock(),
+ }
+}
+
+func (r *scriptModuleTypeResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
+ r.Config = ResourceConfiguration(req, resp)
+}
+
+func (r *scriptModuleTypeResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
+ internal.Mutex.Lock()
+ defer internal.Mutex.Unlock()
+
+ var data *schemas.ScriptModuleResourceModel
+ resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...)
+ if resp.Diagnostics.HasError() {
+ return
+ }
+
+ scriptModule := schemas.MapFromScriptModuleToState(data)
+
+ tflog.Info(ctx, fmt.Sprintf("creating Script Module: %s", scriptModule.Name))
+
+ createdScriptModule, err := scriptmodules.Add(r.Config.Client, scriptModule)
+ if err != nil {
+ resp.Diagnostics.AddError("unable to create script module", err.Error())
+ return
+ }
+
+ schemas.MapToScriptModuleFromState(data, createdScriptModule)
+
+ tflog.Info(ctx, fmt.Sprintf("Script Module created (%s)", data.ID))
+ resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
+}
+
+func (r *scriptModuleTypeResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
+ var data *schemas.ScriptModuleResourceModel
+ resp.Diagnostics.Append(req.State.Get(ctx, &data)...)
+ if resp.Diagnostics.HasError() {
+ return
+ }
+
+ tflog.Info(ctx, fmt.Sprintf("reading Script Module (%s)", data.ID))
+
+ client := r.Config.Client
+ scriptModule, err := scriptmodules.GetByID(client, data.SpaceID.ValueString(), data.ID.ValueString())
+ if err != nil {
+ if err := errors.ProcessApiErrorV2(ctx, resp, data, err, "Script Module"); err != nil {
+ resp.Diagnostics.AddError("unable to load script module", err.Error())
+ }
+ return
+ }
+
+ schemas.MapToScriptModuleFromState(data, scriptModule)
+
+ tflog.Info(ctx, fmt.Sprintf("Script Module read (%s)", scriptModule.GetID()))
+ resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
+}
+
+func (r *scriptModuleTypeResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
+ var data, state *schemas.ScriptModuleResourceModel
+ resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...)
+ resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
+ if resp.Diagnostics.HasError() {
+ return
+ }
+
+ tflog.Debug(ctx, fmt.Sprintf("updating script module '%s'", data.ID.ValueString()))
+
+ scriptModule := schemas.MapFromScriptModuleToState(data)
+ scriptModule.ID = state.ID.ValueString()
+
+ updatedScriptModule, err := scriptmodules.Update(r.Config.Client, scriptModule)
+ if err != nil {
+ resp.Diagnostics.AddError("unable to update script module", err.Error())
+ return
+ }
+
+ schemas.MapToScriptModuleFromState(data, updatedScriptModule)
+
+ tflog.Info(ctx, fmt.Sprintf("Script Module updated (%s)", data.ID))
+
+ resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
+}
+
+func (r *scriptModuleTypeResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
+ internal.Mutex.Lock()
+ defer internal.Mutex.Unlock()
+
+ var data schemas.ScriptModuleResourceModel
+
+ resp.Diagnostics.Append(req.State.Get(ctx, &data)...)
+ if resp.Diagnostics.HasError() {
+ return
+ }
+
+ if err := scriptmodules.DeleteByID(r.Config.Client, data.SpaceID.ValueString(), data.ID.ValueString()); err != nil {
+ resp.Diagnostics.AddError("unable to delete script module", err.Error())
+ return
+ }
+}
diff --git a/octopusdeploy/resource_script_module_test.go b/octopusdeploy_framework/resource_script_module_test.go
similarity index 95%
rename from octopusdeploy/resource_script_module_test.go
rename to octopusdeploy_framework/resource_script_module_test.go
index 3893ad972..c7828d6a3 100644
--- a/octopusdeploy/resource_script_module_test.go
+++ b/octopusdeploy_framework/resource_script_module_test.go
@@ -1,16 +1,15 @@
-package octopusdeploy
+package octopusdeploy_framework
import (
"fmt"
"github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/variables"
"github.com/OctopusSolutionsEngineering/OctopusTerraformTestFramework/octoclient"
"github.com/OctopusSolutionsEngineering/OctopusTerraformTestFramework/test"
+ "github.com/hashicorp/terraform-plugin-testing/helper/acctest"
+ "github.com/hashicorp/terraform-plugin-testing/helper/resource"
+ "github.com/hashicorp/terraform-plugin-testing/terraform"
"path/filepath"
"testing"
-
- "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest"
- "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
- "github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
)
func TestAccOctopusDeployScriptModuleBasic(t *testing.T) {
@@ -24,7 +23,7 @@ func TestAccOctopusDeployScriptModuleBasic(t *testing.T) {
resource.Test(t, resource.TestCase{
CheckDestroy: testScriptModuleCheckDestroy,
- PreCheck: func() { testAccPreCheck(t) },
+ PreCheck: func() { TestAccPreCheck(t) },
ProtoV6ProviderFactories: ProtoV6ProviderFactories(),
Steps: []resource.TestStep{
{
diff --git a/octopusdeploy_framework/schemas/script_modules.go b/octopusdeploy_framework/schemas/script_modules.go
new file mode 100644
index 000000000..f74ab893b
--- /dev/null
+++ b/octopusdeploy_framework/schemas/script_modules.go
@@ -0,0 +1,213 @@
+package schemas
+
+import (
+ "github.com/OctopusDeploy/terraform-provider-octopusdeploy/octopusdeploy_framework/util"
+ "github.com/hashicorp/terraform-plugin-framework-validators/listvalidator"
+ "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
+ "github.com/hashicorp/terraform-plugin-framework/attr"
+ datasourceSchema "github.com/hashicorp/terraform-plugin-framework/datasource/schema"
+ resourceSchema "github.com/hashicorp/terraform-plugin-framework/resource/schema"
+ "github.com/hashicorp/terraform-plugin-framework/schema/validator"
+ "github.com/hashicorp/terraform-plugin-framework/types"
+
+ "github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/variables"
+)
+
+type ScriptModuleResourceModel struct {
+ Description types.String `tfsdk:"description"`
+ Name types.String `tfsdk:"name"`
+ SpaceID types.String `tfsdk:"space_id"`
+ VariableSetId types.String `tfsdk:"variable_set_id"`
+ Script types.List `tfsdk:"script"`
+
+ ResourceModel
+}
+
+type ScriptModuleDataSourceModel struct {
+ ID types.String `tfsdk:"id"`
+ SpaceID types.String `tfsdk:"space_id"`
+ IDs types.List `tfsdk:"ids"`
+ PartialName types.String `tfsdk:"partial_name"`
+ Skip types.Int64 `tfsdk:"skip"`
+ Take types.Int64 `tfsdk:"take"`
+ ScriptModules types.List `tfsdk:"script_modules"`
+}
+
+func GetDatasourceScriptModuleSchema() datasourceSchema.Schema {
+ description := "script module"
+ return datasourceSchema.Schema{
+ Description: "Provides information about existing script modules.",
+ Attributes: map[string]datasourceSchema.Attribute{
+ "id": GetIdDatasourceSchema(true),
+ "space_id": GetSpaceIdDatasourceSchema(description, false),
+ "ids": util.GetQueryIDsDatasourceSchema(),
+ "partial_name": util.GetQueryPartialNameDatasourceSchema(),
+ "skip": util.GetQuerySkipDatasourceSchema(),
+ "take": util.GetQueryTakeDatasourceSchema(),
+ "script_modules": datasourceSchema.ListNestedAttribute{
+ Computed: true,
+ NestedObject: datasourceSchema.NestedAttributeObject{
+ Attributes: GetScriptModuleDatasourceSchema(),
+ },
+ },
+ },
+ }
+}
+
+func GetScriptModuleDatasourceSchema() map[string]datasourceSchema.Attribute {
+ return map[string]datasourceSchema.Attribute{
+ "description": GetReadonlyDescriptionDatasourceSchema("script module"),
+ "id": GetIdDatasourceSchema(true),
+ "name": GetReadonlyNameDatasourceSchema(),
+ "space_id": GetSpaceIdDatasourceSchema("Script Module", true),
+ "variable_set_id": datasourceSchema.StringAttribute{
+ Computed: true,
+ Description: "The variable set ID for this script module.",
+ },
+ "script": datasourceSchema.ListNestedAttribute{
+ Description: "The script associated with this script module.",
+ Computed: true,
+ NestedObject: datasourceSchema.NestedAttributeObject{
+ Attributes: map[string]datasourceSchema.Attribute{
+ "body": datasourceSchema.StringAttribute{
+ Description: "The body of this script module.",
+ Computed: true,
+ },
+ "syntax": datasourceSchema.StringAttribute{
+ Description: "The syntax of the script. Valid types are `Bash`, `CSharp`, `FSharp`, `PowerShell`, or `Python`.",
+ Computed: true,
+ Validators: []validator.String{
+ stringvalidator.OneOfCaseInsensitive(
+ "Bash",
+ "CSharp",
+ "FSharp",
+ "PowerShell",
+ "Python"),
+ },
+ },
+ },
+ },
+ Validators: []validator.List{
+ listvalidator.SizeAtMost(1),
+ listvalidator.SizeAtLeast(1),
+ },
+ },
+ }
+}
+
+func FlattenScriptModule(scriptModule *variables.ScriptModule) attr.Value {
+ attrs := map[string]attr.Value{
+ "description": types.StringValue(scriptModule.Description),
+ "id": types.StringValue(scriptModule.GetID()),
+ "name": types.StringValue(scriptModule.Name),
+ "script": types.ListValueMust(ScriptObjectType(), flattenScript(scriptModule)),
+ "space_id": types.StringValue(scriptModule.SpaceID),
+ "variable_set_id": types.StringValue(scriptModule.VariableSetID),
+ }
+
+ return types.ObjectValueMust(ScriptModuleObjectType(), attrs)
+}
+
+func ScriptObjectType() types.ObjectType {
+ return types.ObjectType{AttrTypes: map[string]attr.Type{
+ "body": types.StringType,
+ "syntax": types.StringType,
+ }}
+}
+
+func ScriptModuleObjectType() map[string]attr.Type {
+ return map[string]attr.Type{
+ "description": types.StringType,
+ "id": types.StringType,
+ "name": types.StringType,
+ "space_id": types.StringType,
+ "variable_set_id": types.StringType,
+ "script": types.ListType{ElemType: ScriptObjectType()},
+ }
+}
+
+func GetScriptModuleSchemaBlock() map[string]resourceSchema.Block {
+ return map[string]resourceSchema.Block{
+ "script": resourceSchema.ListNestedBlock{
+ Description: "The script associated with this script module.",
+ NestedObject: resourceSchema.NestedBlockObject{
+ Attributes: map[string]resourceSchema.Attribute{
+ "body": resourceSchema.StringAttribute{
+ Description: "The body of this script module.",
+ Required: true,
+ },
+ "syntax": resourceSchema.StringAttribute{
+ Description: "The syntax of the script. Valid types are `Bash`, `CSharp`, `FSharp`, `PowerShell`, or `Python`.",
+ Required: true,
+ Validators: []validator.String{
+ stringvalidator.OneOfCaseInsensitive(
+ "Bash",
+ "CSharp",
+ "FSharp",
+ "PowerShell",
+ "Python"),
+ },
+ },
+ },
+ },
+ Validators: []validator.List{
+ listvalidator.SizeAtMost(1),
+ listvalidator.SizeAtLeast(1),
+ },
+ },
+ }
+}
+
+func GetScriptModuleResourceSchema() map[string]resourceSchema.Attribute {
+ return map[string]resourceSchema.Attribute{
+ "description": GetDescriptionResourceSchema("script module"),
+ "id": GetIdResourceSchema(),
+ "name": GetNameResourceSchema(true),
+ "space_id": GetSpaceIdResourceSchema("Script Module"),
+ "variable_set_id": resourceSchema.StringAttribute{
+ Computed: true,
+ Description: "The variable set ID for this script module.",
+ Optional: true,
+ },
+ }
+}
+
+func MapFromScriptModuleToState(data *ScriptModuleResourceModel) *variables.ScriptModule {
+ name := data.Name.ValueString()
+ scriptModule := variables.NewScriptModule(name)
+ scriptModule.ID = data.ID.ValueString()
+ scriptModule.Description = data.Description.ValueString()
+ // We enforce on the schema a single required script
+ scriptDetails := data.Script.Elements()[0].(types.Object).Attributes()
+ scriptModule.Syntax = scriptDetails["syntax"].(types.String).ValueString()
+ scriptModule.ScriptBody = scriptDetails["body"].(types.String).ValueString()
+ scriptModule.SpaceID = data.SpaceID.ValueString()
+ scriptModule.VariableSetID = data.VariableSetId.ValueString()
+
+ return scriptModule
+}
+
+func flattenScript(scriptModule *variables.ScriptModule) []attr.Value {
+ return []attr.Value{
+ types.ObjectValueMust(map[string]attr.Type{
+ "body": types.StringType,
+ "syntax": types.StringType,
+ }, map[string]attr.Value{
+ "body": types.StringValue(scriptModule.ScriptBody),
+ "syntax": types.StringValue(scriptModule.Syntax),
+ }),
+ }
+}
+
+func MapToScriptModuleFromState(data *ScriptModuleResourceModel, scriptModule *variables.ScriptModule) {
+ data.Description = types.StringValue(scriptModule.Description)
+ data.Name = types.StringValue(scriptModule.Name)
+ data.SpaceID = types.StringValue(scriptModule.SpaceID)
+ data.VariableSetId = types.StringValue(scriptModule.VariableSetID)
+ data.ID = types.StringValue(scriptModule.ID)
+
+ flattenScript(scriptModule)
+
+ var script, _ = types.ListValue(ScriptObjectType(), flattenScript(scriptModule))
+ data.Script = script
+}