diff --git a/.github/workflows/gotest-cloud.yml b/.github/workflows/gotest-cloud.yml
index 07e98fa..b60f6b4 100644
--- a/.github/workflows/gotest-cloud.yml
+++ b/.github/workflows/gotest-cloud.yml
@@ -147,4 +147,5 @@ jobs:
# Sweep
- name: Sweep
+ if: always()
run: go test -v ./internal/test -run "^TestAzureMcs$" -timeout 1h -sweep-run "citrix_zone,citrix_zone,citrix_admin_folder,citrix_admin_role,citrix_admin_scope" -sweep="azure"
\ No newline at end of file
diff --git a/.github/workflows/gotest-onprem.yml b/.github/workflows/gotest-onprem.yml
index 0a0a1af..b19c93c 100644
--- a/.github/workflows/gotest-onprem.yml
+++ b/.github/workflows/gotest-onprem.yml
@@ -141,4 +141,5 @@ jobs:
# Sweep
- name: Sweep
+ if: always()
run: go test -v ./internal/test -run "^TestAzureMcs$" -timeout 1h -sweep-run "citrix_zone,citrix_zone,citrix_admin_folder,citrix_admin_role,citrix_admin_scope" -sweep="azure"
\ No newline at end of file
diff --git a/docs/data-sources/cloud_resource_location.md b/docs/data-sources/cloud_resource_location.md
new file mode 100644
index 0000000..2f468f2
--- /dev/null
+++ b/docs/data-sources/cloud_resource_location.md
@@ -0,0 +1,31 @@
+---
+# generated by https://github.com/hashicorp/terraform-plugin-docs
+page_title: "citrix_cloud_resource_location Data Source - citrix"
+subcategory: "Citrix Cloud"
+description: |-
+ Read data of an existing resource location.
+---
+
+# citrix_cloud_resource_location (Data Source)
+
+Read data of an existing resource location.
+
+## Example Usage
+
+```terraform
+# Get Resource Location resource by name
+data "citrix_cloud_resource_location" "example-resource-location" {
+ name = "example-resource-location"
+}
+```
+
+
+## Schema
+
+### Required
+
+- `name` (String) Name of the resource location.
+
+### Read-Only
+
+- `id` (String) ID of the resource location.
\ No newline at end of file
diff --git a/docs/index.md b/docs/index.md
index 4d8e2c1..cce790b 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -10,6 +10,43 @@ description: |-
Manage and deploy Citrix resources easily using the Citrix Terraform provider. The provider currently supports both Citrix Virtual Apps & Desktops(CVAD) and Citrix Desktop as a Service (DaaS) solutions. You can automate creation of site setup including host connections, machine catalogs and delivery groups etc for both CVAD and Citrix DaaS. You can deploy resources in Citrix supported hypervisors and public clouds. Currently, we support deployments in Nutanix, VMware vSphere, XenServer, Microsoft Azure, AWS EC2 and Google Cloud Compute. Additionally, you can also use Manual provisioning or RemotePC to add workloads. The provider is developed and maintained by Citrix.
+Documentation regarding the [Data Sources](https://developer.hashicorp.com/terraform/language/data-sources) and [Resources](https://developer.hashicorp.com/terraform/language/resources) supported by the Citrix Provider can be found in the navigation to the left.
+
+Check out the [release notes](https://github.com/citrix/terraform-provider-citrix/releases) to find out more about the provider's latest features and version information.
+
+## Getting Started
+
+New to Terraform? Click [here](https://developer.hashicorp.com/terraform) to learn more.
+
+### Importing existing Citrix resources into Terraform
+
+Experience the immediate benefits of Terraform by importing your Citrix resources (CVAD or DaaS) using our [Onboarding Script](https://github.com/citrix/terraform-provider-citrix/blob/main/scripts/onboarding-helper/terraform-onboarding.ps1). This allows you to quickly adopt infrastructure as code and streamline your infrastructure management. A comprehensive [ReadMe](https://github.com/citrix/terraform-provider-citrix/blob/main/scripts/onboarding-helper/README.md) is available to guide you through the process.
+
+### Creating Citrix resources via Terraform
+
+Please refer to [Citrix Tech Zone](https://community.citrix.com/tech-zone/automation/) to find detailed guides on how to deploy and manage resources using the Citrix provider:
+- [Installing and configuring the Citrix provider](https://community.citrix.com/tech-zone/automation/terraform-install-and-config/)
+- [AWS EC2](https://community.citrix.com/tech-zone/build/deployment-guides/terraform-daas-aws/) via MCS
+- [Azure](https://community.citrix.com/tech-zone/build/deployment-guides/citrix-daas-terraform-azure/) via MCS
+- [GCP](https://community.citrix.com/tech-zone/build/deployment-guides/terraform-daas-gcp/) via MCS
+- [vSphere](https://community.citrix.com/tech-zone/build/deployment-guides/terraform-daas-vsphere8/) via MCS
+- [XenServer](https://community.citrix.com/tech-zone/automation/citrix-terraform-xenserver) via MCS
+- [Citrix policies](https://community.citrix.com/tech-zone/automation/cvad-terraform-policies/)
+
+## Frequently Asked Questions
+
+### What resource is supported for different connection types?
+
+| Connection Type | Hypervisor | Resource Pool | MCS Power Managed | MCS Provisioning | PVS | Manual/Remote PC |
+|------------------|--------------------|--------------------|----------------------|----------------------|--------------------------|----------------------|
+| AzureRM |:heavy_check_mark: |:heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |:heavy_check_mark: | :heavy_check_mark: |
+| AWS EC2 |:heavy_check_mark: |:heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |:heavy_multiplication_x: | :heavy_check_mark: |
+| GCP |:heavy_check_mark: |:heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |:heavy_multiplication_x: | :heavy_check_mark: |
+| vSphere |:heavy_check_mark: |:heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |:heavy_multiplication_x: | :heavy_check_mark: |
+| XenServer |:heavy_check_mark: |:heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |:heavy_multiplication_x: | :heavy_check_mark: |
+| Nutanix |:heavy_check_mark: |:heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |:heavy_multiplication_x: | :heavy_check_mark: |
+| SCVMM |:heavy_check_mark: |:heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |:heavy_multiplication_x: | :heavy_check_mark: |
+
## Example Usage
```terraform
@@ -74,6 +111,10 @@ For Citrix Cloud customers: Use this to specify Cloud API Key Client Secret.
-> **Note** Can be set via Environment Variable **CITRIX_CUSTOMER_ID**.
~> **Please Note** This parameter is required for Citrix Cloud customers to be specified in the provider configuration or via environment variable.
+- `disable_daas_client` (Boolean) Disable Citrix DaaS client setup.
+Set to true to skip Citrix DaaS client setup.
+
+-> **Note** Can be set via Environment Variable **CITRIX_DISABLE_DAAS_CLIENT**.
- `disable_ssl_verification` (Boolean) Disable SSL verification against the target DDC.
Set to true to skip SSL verification only when the target DDC does not have a valid SSL certificate issued by a trusted CA.
When set to true, please make sure that your provider config is set for a known DDC hostname.
@@ -103,4 +144,4 @@ Optional:
- `ad_admin_password` (String) Active Directory Admin Password to connect to storefront server
Use this to specify AD admin password
Can be set via Environment Variable **SF_AD_ADMIN_PASSWORD**.
This parameter is **required** to be specified in the provider configuration or via environment variable.
- `ad_admin_username` (String) Active Directory Admin Username to connect to storefront server
Use this to specify AD admin username
Can be set via Environment Variable **SF_AD_ADMIN_USERNAME**.
This parameter is **required** to be specified in the provider configuration or via environment variable.
- `computer_name` (String) StoreFront server computer Name
Use this to specify StoreFront server computer name
Can be set via Environment Variable **SF_COMPUTER_NAME**.
This parameter is **required** to be specified in the provider configuration or via environment variable.
-- `disable_ssl_verification` (Boolean) Disable SSL verification against the target storefront server.
Only applicable to customers connecting to storefront server remotely. Customers should omit this option when running storefront provider locally. Set to true to skip SSL verification only when the target DDC does not have a valid SSL certificate issued by a trusted CA.
When set to true, please make sure that your provider storefront_remote_host is set for a known storefront hostname.
Can be set via Environment Variable **SF_DISABLE_SSL_VERIFICATION**.
\ No newline at end of file
+- `disable_ssl_verification` (Boolean) Disable SSL verification against the target storefront server.
Only applicable to customers connecting to storefront server remotely. Customers should omit this option when running storefront provider locally. Set to true to skip SSL verification only when the target DDC does not have a valid SSL certificate issued by a trusted CA.
When set to true, please make sure that your provider storefront_remote_host is set for a known storefront hostname.
Can be set via Environment Variable **SF_DISABLE_SSL_VERIFICATION**.
diff --git a/docs/resources/application.md b/docs/resources/application.md
index fb7dd96..fae2cdf 100644
--- a/docs/resources/application.md
+++ b/docs/resources/application.md
@@ -79,9 +79,7 @@ resource "citrix_application" "example-application" {
- `limit_visibility_to_users` (Set of String) By default, the application is visible to all users within a delivery group. However, you can restrict its visibility to only certain users by specifying them in the `limit_visibility_to_users` list.
-> **Note** Users must be in `DOMAIN\UserOrGroupName` or `user@domain.com` format
-- `metadata` (Attributes List) Metadata for the Application.
-
-~> **Please Note** Metadata once set cannot be removed. Use this field to add new metadata or update the value for an existing metadata. Subsequently, removing any metadata from config will have no effect on the existing metadata of the resource. (see [below for nested schema](#nestedatt--metadata))
+- `metadata` (Attributes List) Metadata for the Application. (see [below for nested schema](#nestedatt--metadata))
- `tags` (Set of String) A set of identifiers of tags to associate with the application.
### Read-Only
diff --git a/docs/resources/application_group.md b/docs/resources/application_group.md
index 71df8f3..f4f71a9 100644
--- a/docs/resources/application_group.md
+++ b/docs/resources/application_group.md
@@ -36,9 +36,7 @@ resource "citrix_application_group" "example-application-group" {
- `included_users` (Set of String) Users who can use this application group.
-> **Note** User must be in `Domain\UserOrGroupName` or `user@domain.com` format
-- `metadata` (Attributes List) Metadata for the Application Group.
-
-~> **Please Note** Metadata once set cannot be removed. Use this field to add new metadata or update the value for an existing metadata. Subsequently, removing any metadata from config will have no effect on the existing metadata of the resource. (see [below for nested schema](#nestedatt--metadata))
+- `metadata` (Attributes List) Metadata for the Application Group. (see [below for nested schema](#nestedatt--metadata))
- `restrict_to_tag` (String) The tag to restrict the application group to.
- `scopes` (Set of String) The IDs of the scopes for the application group to be a part of.
- `tags` (Set of String) A set of identifiers of tags to associate with the application group.
diff --git a/docs/resources/aws_hypervisor.md b/docs/resources/aws_hypervisor.md
index 733418f..6563a5a 100644
--- a/docs/resources/aws_hypervisor.md
+++ b/docs/resources/aws_hypervisor.md
@@ -36,9 +36,7 @@ resource "citrix_aws_hypervisor" "example-aws-hypervisor" {
### Optional
-- `metadata` (Attributes List) Metadata for the Hypervisor.
-
-~> **Please Note** Metadata once set cannot be removed. Use this field to add new metadata or update the value for an existing metadata. Subsequently, removing any metadata from config will have no effect on the existing metadata of the resource. (see [below for nested schema](#nestedatt--metadata))
+- `metadata` (Attributes List) Metadata for the Hypervisor. (see [below for nested schema](#nestedatt--metadata))
- `scopes` (Set of String) The IDs of the scopes for the hypervisor to be a part of.
### Read-Only
diff --git a/docs/resources/aws_hypervisor_resource_pool.md b/docs/resources/aws_hypervisor_resource_pool.md
index 0108514..fa0315b 100644
--- a/docs/resources/aws_hypervisor_resource_pool.md
+++ b/docs/resources/aws_hypervisor_resource_pool.md
@@ -37,9 +37,7 @@ resource "citrix_aws_hypervisor_resource_pool" "example-aws-hypervisor-resource-
### Optional
-- `metadata` (Attributes List) Metadata for the Hypervosor Resource Pool.
-
-~> **Please Note** Metadata once set cannot be removed. Use this field to add new metadata or update the value for an existing metadata. Subsequently, removing any metadata from config will have no effect on the existing metadata of the resource. (see [below for nested schema](#nestedatt--metadata))
+- `metadata` (Attributes List) Metadata for the Hypervosor Resource Pool. (see [below for nested schema](#nestedatt--metadata))
### Read-Only
diff --git a/docs/resources/azure_hypervisor.md b/docs/resources/azure_hypervisor.md
index 06dc1f8..097c6b1 100644
--- a/docs/resources/azure_hypervisor.md
+++ b/docs/resources/azure_hypervisor.md
@@ -42,14 +42,13 @@ resource "citrix_azure_hypervisor" "example-azure-hypervisor" {
-> **Note** Expiration date format is `YYYY-MM-DD`.
- `enable_azure_ad_device_management` (Boolean) Enable Azure AD device management. Default is false.
-- `metadata` (Attributes List) Metadata for the Hypervisor.
-
-~> **Please Note** Metadata once set cannot be removed. Use this field to add new metadata or update the value for an existing metadata. Subsequently, removing any metadata from config will have no effect on the existing metadata of the resource. (see [below for nested schema](#nestedatt--metadata))
+- `metadata` (Attributes List) Metadata for the Hypervisor. (see [below for nested schema](#nestedatt--metadata))
- `scopes` (Set of String) The IDs of the scopes for the hypervisor to be a part of.
### Read-Only
- `id` (String) GUID identifier of the hypervisor.
+- `tenants` (Set of String) A set of identifiers of tenants to associate with the hypervisor connection.
### Nested Schema for `metadata`
diff --git a/docs/resources/azure_hypervisor_resource_pool.md b/docs/resources/azure_hypervisor_resource_pool.md
index e000b4a..8eace1b 100644
--- a/docs/resources/azure_hypervisor_resource_pool.md
+++ b/docs/resources/azure_hypervisor_resource_pool.md
@@ -40,9 +40,7 @@ resource "citrix_azure_hypervisor_resource_pool" "example-azure-hypervisor-resou
### Optional
-- `metadata` (Attributes List) Metadata for the Hypervisor Resource Pool.
-
-~> **Please Note** Metadata once set cannot be removed. Use this field to add new metadata or update the value for an existing metadata. Subsequently, removing any metadata from config will have no effect on the existing metadata of the resource. (see [below for nested schema](#nestedatt--metadata))
+- `metadata` (Attributes List) Metadata for the Hypervisor Resource Pool. (see [below for nested schema](#nestedatt--metadata))
### Read-Only
diff --git a/docs/resources/delivery_group.md b/docs/resources/delivery_group.md
index a65ec18..572d001 100644
--- a/docs/resources/delivery_group.md
+++ b/docs/resources/delivery_group.md
@@ -204,9 +204,7 @@ resource "citrix_delivery_group" "example-delivery-group" {
~> **Please Note** This setting only impacts Single Session OS Random (pooled) desktops which are power managed. LHC is always enabled for Single Session OS static and Multi Session OS desktops.
-> **Note** When set to `true`, machines will remain available and allow new connections and changes to the machine caused by a user might be present in subsequent sessions. When set to `false`, machines in the delivery group will be unavailable for new connections during a Local Host Cache event.
-- `metadata` (Attributes List) Metadata for the Delivery Group.
-
-~> **Please Note** Metadata once set cannot be removed. Use this field to add new metadata or update the value for an existing metadata. Subsequently, removing any metadata from config will have no effect on the existing metadata of the resource. (see [below for nested schema](#nestedatt--metadata))
+- `metadata` (Attributes List) Metadata for the Delivery Group. (see [below for nested schema](#nestedatt--metadata))
- `minimum_functional_level` (String) Specifies the minimum functional level for the VDA machines in the delivery group. Defaults to `L7_20`.
- `policy_set_id` (String) GUID identifier of the policy set.
- `reboot_schedules` (Attributes List) The reboot schedule for the delivery group. (see [below for nested schema](#nestedatt--reboot_schedules))
@@ -426,6 +424,7 @@ Optional:
- `description` (String) A description for the published desktop. The name and description are shown in Citrix Workspace app.
- `enabled` (Boolean) Specify whether to enable the delivery of this desktop. Default is `true`.
+- `restrict_to_tag` (String) Restrict session launch to machines with tag specified in GUID.
- `restricted_access_users` (Attributes) Restrict access to this Desktop by specifying users and groups in the allow and block list. If no value is specified, all users that have access to this Delivery Group will have access to the Desktop.
~> **Please Note** For Remote PC Delivery Groups desktops, `restricted_access_users` has to be set. (see [below for nested schema](#nestedatt--desktops--restricted_access_users))
@@ -480,7 +479,7 @@ Optional:
- `reboot_notification_to_users` (Attributes) The reboot notification for the reboot schedule.
~> **Please Note** Not available for natural reboot. (see [below for nested schema](#nestedatt--reboot_schedules--reboot_notification_to_users))
-- `restrict_to_tag` (String) The tag to which the reboot schedule is restricted.
+- `restrict_to_tag` (String) Restrict reboot schedule to machines with tag specified in Guid.
- `week_in_month` (String) The week in the month on which the reboot schedule runs monthly. Can only be set to `First`, `Second`, `Third`, `Fourth`, or `Last`.
diff --git a/docs/resources/gac_settings.md b/docs/resources/gac_settings.md
index b4d61be..b407c20 100644
--- a/docs/resources/gac_settings.md
+++ b/docs/resources/gac_settings.md
@@ -58,7 +58,28 @@ resource "citrix_gac_settings" "test_settings_configuration" {
value_string = "3600000"
}
]
- }
+ },
+ {
+ user_override = false,
+ category = "dazzle",
+ settings = [
+ {
+ name = "Local App Whitelist",
+ local_app_allow_list = [
+ {
+ arguments = "www.citrix.com",
+ name = "Google Chrome",
+ path = "C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe"
+ },
+ {
+ arguments = "www.citrix2.com",
+ name = "Google Chrome2",
+ path = "C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe"
+ },
+ ]
+ }
+ ]
+ },
],
html5 = [
{
@@ -97,6 +118,37 @@ resource "citrix_gac_settings" "test_settings_configuration" {
]
}
]
+ },
+ {
+ user_override = false,
+ category = "Browser",
+ settings = [
+ {
+ name = "managed bookmarks",
+ managed_bookmarks = [
+ {
+ name = "Citrix",
+ url = "https://www.citrix.com/"
+ },
+ {
+ name = "Citrix Workspace app",
+ url = "https://www.citrix.com/products/receiver.html"
+ }
+ ]
+ }
+ ]
+ }
+ ],
+ linux = [
+ {
+ category = "root",
+ user_override = false,
+ settings = [
+ {
+ name = "enable fido2",
+ value_string = "true"
+ }
+ ]
}
]
}
@@ -122,12 +174,13 @@ resource "citrix_gac_settings" "test_settings_configuration" {
Optional:
-- `android` (Attributes List) Settings to be applied for users using android platform. (see [below for nested schema](#nestedatt--app_settings--android))
-- `chromeos` (Attributes List) Settings to be applied for users using chrome os platform. (see [below for nested schema](#nestedatt--app_settings--chromeos))
-- `html5` (Attributes List) Settings to be applied for users using html5. (see [below for nested schema](#nestedatt--app_settings--html5))
-- `ios` (Attributes List) Settings to be applied for users using ios platform. (see [below for nested schema](#nestedatt--app_settings--ios))
-- `macos` (Attributes List) Settings to be applied for users using mac os platform. (see [below for nested schema](#nestedatt--app_settings--macos))
-- `windows` (Attributes List) Settings to be applied for users using windows platform. (see [below for nested schema](#nestedatt--app_settings--windows))
+- `android` (Attributes Set) Settings to be applied for users using android platform. (see [below for nested schema](#nestedatt--app_settings--android))
+- `chromeos` (Attributes Set) Settings to be applied for users using chrome os platform. (see [below for nested schema](#nestedatt--app_settings--chromeos))
+- `html5` (Attributes Set) Settings to be applied for users using html5. (see [below for nested schema](#nestedatt--app_settings--html5))
+- `ios` (Attributes Set) Settings to be applied for users using ios platform. (see [below for nested schema](#nestedatt--app_settings--ios))
+- `linux` (Attributes Set) Settings to be applied for users using linux platform. (see [below for nested schema](#nestedatt--app_settings--linux))
+- `macos` (Attributes Set) Settings to be applied for users using mac os platform. (see [below for nested schema](#nestedatt--app_settings--macos))
+- `windows` (Attributes Set) Settings to be applied for users using windows platform. (see [below for nested schema](#nestedatt--app_settings--windows))
### Nested Schema for `app_settings.android`
@@ -220,6 +273,63 @@ Optional:
+
+### Nested Schema for `app_settings.linux`
+
+Required:
+
+- `category` (String) Defines the category of the setting.
+- `settings` (Attributes List) A list of name value pairs for the settings. Please refer to the following [table](https://developer-docs.citrix.com/en-us/server-integration/global-app-configuration-service/getting-started#supported-settings-and-their-values-per-platform) for the supported settings name and their values per platform. (see [below for nested schema](#nestedatt--app_settings--linux--settings))
+- `user_override` (Boolean) Defines if users can modify or change the value of as obtained settings from the Global App Citrix Workspace configuration service.
+
+
+### Nested Schema for `app_settings.linux.settings`
+
+Required:
+
+- `name` (String) Name of the setting.
+
+Optional:
+
+- `auto_launch_protocols_from_origins` (Attributes List) A list of protocols that can launch an external application from the listed origins without prompting the user. (see [below for nested schema](#nestedatt--app_settings--linux--settings--auto_launch_protocols_from_origins))
+- `extension_install_allow_list` (Attributes List) An allowed list of extensions that users can add to the Citrix Enterprise Browser. This list uses the Chrome Web Store. (see [below for nested schema](#nestedatt--app_settings--linux--settings--extension_install_allow_list))
+- `managed_bookmarks` (Attributes List) A list of bookmarks to push to the Citrix Enterprise Browser. (see [below for nested schema](#nestedatt--app_settings--linux--settings--managed_bookmarks))
+- `value_list` (List of String) List value (if any) associated with the setting.
+- `value_string` (String) String value (if any) associated with the setting.
+
+
+### Nested Schema for `app_settings.linux.settings.value_string`
+
+Required:
+
+- `protocol` (String) Auto launch protocol
+
+Optional:
+
+- `allowed_origins` (List of String) List of origins urls
+
+
+
+### Nested Schema for `app_settings.linux.settings.value_string`
+
+Required:
+
+- `id` (String) Id of the allowed extensions.
+- `install_link` (String) Install link for the allowed extensions.
+- `name` (String) Name of the allowed extensions.
+
+
+
+### Nested Schema for `app_settings.linux.settings.value_string`
+
+Required:
+
+- `name` (String) Name for the bookmark
+- `url` (String) URL for the bookmark
+
+
+
+
### Nested Schema for `app_settings.macos`
diff --git a/docs/resources/gcp_hypervisor.md b/docs/resources/gcp_hypervisor.md
index bf667f8..cc3d78f 100644
--- a/docs/resources/gcp_hypervisor.md
+++ b/docs/resources/gcp_hypervisor.md
@@ -34,14 +34,13 @@ resource "citrix_gcp_hypervisor" "example-gcp-hypervisor" {
### Optional
-- `metadata` (Attributes List) Metadata for the Hypervisor.
-
-~> **Please Note** Metadata once set cannot be removed. Use this field to add new metadata or update the value for an existing metadata. Subsequently, removing any metadata from config will have no effect on the existing metadata of the resource. (see [below for nested schema](#nestedatt--metadata))
+- `metadata` (Attributes List) Metadata for the Hypervisor. (see [below for nested schema](#nestedatt--metadata))
- `scopes` (Set of String) The IDs of the scopes for the hypervisor to be a part of.
### Read-Only
- `id` (String) GUID identifier of the hypervisor.
+- `tenants` (Set of String) A set of identifiers of tenants to associate with the hypervisor connection.
### Nested Schema for `metadata`
diff --git a/docs/resources/gcp_hypervisor_resource_pool.md b/docs/resources/gcp_hypervisor_resource_pool.md
index 99b1b7e..c03ef9d 100644
--- a/docs/resources/gcp_hypervisor_resource_pool.md
+++ b/docs/resources/gcp_hypervisor_resource_pool.md
@@ -39,9 +39,7 @@ resource "citrix_gcp_hypervisor_resource_pool" "example-gcp-hypervisor-resource-
### Optional
-- `metadata` (Attributes List) Metadata for the Hypervisor Resource Pool.
-
-~> **Please Note** Metadata once set cannot be removed. Use this field to add new metadata or update the value for an existing metadata. Subsequently, removing any metadata from config will have no effect on the existing metadata of the resource. (see [below for nested schema](#nestedatt--metadata))
+- `metadata` (Attributes List) Metadata for the Hypervisor Resource Pool. (see [below for nested schema](#nestedatt--metadata))
- `shared_vpc` (Boolean) Indicate whether the GCP Virtual Private Cloud is a shared VPC.
### Read-Only
diff --git a/docs/resources/machine_catalog.md b/docs/resources/machine_catalog.md
index bff311c..fb781cd 100644
--- a/docs/resources/machine_catalog.md
+++ b/docs/resources/machine_catalog.md
@@ -445,9 +445,7 @@ resource "citrix_machine_catalog" "example-non-domain-joined-azure-mcs" {
- `is_remote_pc` (Boolean) Specify if this catalog is for Remote PC access.
- `machine_accounts` (Attributes List) Machine accounts to add to the catalog. Only to be used when using `provisioning_type = MANUAL` (see [below for nested schema](#nestedatt--machine_accounts))
- `machine_catalog_folder_path` (String) The path to the folder in which the machine catalog is located.
-- `metadata` (Attributes List) Metadata for the Machine Catalog.
-
-~> **Please Note** Metadata once set cannot be removed. Use this field to add new metadata or update the value for an existing metadata. Subsequently, removing any metadata from config will have no effect on the existing metadata of the resource. (see [below for nested schema](#nestedatt--metadata))
+- `metadata` (Attributes List) Metadata for the Machine Catalog. (see [below for nested schema](#nestedatt--metadata))
- `minimum_functional_level` (String) Specifies the minimum functional level for the VDA machines in the catalog. Defaults to `L7_20`.
- `provisioning_scheme` (Attributes) Machine catalog provisioning scheme. Required when `provisioning_type = MCS` or `provisioning_type = PVS_STREAMING`. (see [below for nested schema](#nestedatt--provisioning_scheme))
- `remote_pc_ous` (Attributes List) Organizational Units to be included in the Remote PC machine catalog. Only to be used when `is_remote_pc = true`. For adding machines, use `machine_accounts`. (see [below for nested schema](#nestedatt--remote_pc_ous))
@@ -867,6 +865,7 @@ Optional:
- `image_update_reboot_options` (Attributes) The options for how rebooting is performed for image update. When omitted, image update on the VDAs will be performed on next shutdown. (see [below for nested schema](#nestedatt--provisioning_scheme--vsphere_machine_config--image_update_reboot_options))
- `machine_profile` (String) The name of the virtual machine template that will be used to identify the default value for the tags, virtual machine size, boot diagnostics and host cache property of OS disk.
- `master_image_note` (String) The note for the master image.
+- `resource_pool_path` (String) The Resource Pool path under which the `master_image_vm` is located. This property is case sensitive.
- `writeback_cache` (Attributes) Write-back Cache config. Leave this empty to disable Write-back Cache. (see [below for nested schema](#nestedatt--provisioning_scheme--vsphere_machine_config--writeback_cache))
diff --git a/docs/resources/nutanix_hypervisor.md b/docs/resources/nutanix_hypervisor.md
index d753101..140cf81 100644
--- a/docs/resources/nutanix_hypervisor.md
+++ b/docs/resources/nutanix_hypervisor.md
@@ -42,9 +42,7 @@ resource "citrix_nutanix_hypervisor" "example-nutanix-hypervisor" {
- `max_absolute_active_actions` (Number) Maximum number of actions that can execute in parallel on the hypervisor. Default is 100.
- `max_absolute_new_actions_per_minute` (Number) Maximum number of actions that can be started on the hypervisor per-minute. Default is 10.
- `max_power_actions_percentage_of_machines` (Number) Maximum percentage of machines on the hypervisor which can have their power state changed simultaneously. Default is 20.
-- `metadata` (Attributes List) Metadata for the Hypervisor.
-
-~> **Please Note** Metadata once set cannot be removed. Use this field to add new metadata or update the value for an existing metadata. Subsequently, removing any metadata from config will have no effect on the existing metadata of the resource. (see [below for nested schema](#nestedatt--metadata))
+- `metadata` (Attributes List) Metadata for the Hypervisor. (see [below for nested schema](#nestedatt--metadata))
- `scopes` (Set of String) The IDs of the scopes for the hypervisor to be a part of.
### Read-Only
diff --git a/docs/resources/nutanix_hypervisor_resource_pool.md b/docs/resources/nutanix_hypervisor_resource_pool.md
index fee493b..742a0d0 100644
--- a/docs/resources/nutanix_hypervisor_resource_pool.md
+++ b/docs/resources/nutanix_hypervisor_resource_pool.md
@@ -34,9 +34,7 @@ resource "citrix_nutanix_hypervisor_resource_pool" "example-nutanix-hypervisor-r
### Optional
-- `metadata` (Attributes List) Metadata for the Hypervisor Resource Pool.
-
-~> **Please Note** Metadata once set cannot be removed. Use this field to add new metadata or update the value for an existing metadata. Subsequently, removing any metadata from config will have no effect on the existing metadata of the resource. (see [below for nested schema](#nestedatt--metadata))
+- `metadata` (Attributes List) Metadata for the Hypervisor Resource Pool. (see [below for nested schema](#nestedatt--metadata))
### Read-Only
diff --git a/docs/resources/policy_set.md b/docs/resources/policy_set.md
index 980f64c..b11573d 100644
--- a/docs/resources/policy_set.md
+++ b/docs/resources/policy_set.md
@@ -12,7 +12,7 @@ Manages a policy set and the policies within it. The order of the policies speci
-> **Note** For detailed information about policy settings and filters, please refer to [this document](https://github.com/citrix/terraform-provider-citrix/blob/main/internal/daas/policies/policy_set_resource.md).
-~> **Disclaimer** This feature is supported for On-Premises with DDC version `2402` and above and will be made available for Cloud soon.
+~> **Disclaimer** This feature is supported for Citrix Cloud customers, and for Citrix On-Premises customers with DDC version `2402` and above.
## Example Usage
diff --git a/docs/resources/scvmm_hypervisor.md b/docs/resources/scvmm_hypervisor.md
index 900f08f..92ca56f 100644
--- a/docs/resources/scvmm_hypervisor.md
+++ b/docs/resources/scvmm_hypervisor.md
@@ -42,9 +42,7 @@ resource "citrix_scvmm_hypervisor" "example-scvmm-hypervisor" {
- `max_absolute_active_actions` (Number) Maximum number of actions that can execute in parallel on the hypervisor. Default is 50.
- `max_absolute_new_actions_per_minute` (Number) Maximum number of actions that can be started on the hypervisor per-minute. Default is 10.
- `max_power_actions_percentage_of_machines` (Number) Maximum percentage of machines on the hypervisor which can have their power state changed simultaneously. Default is 10.
-- `metadata` (Attributes List) Metadata for the Hypervisor.
-
-~> **Please Note** Metadata once set cannot be removed. Use this field to add new metadata or update the value for an existing metadata. Subsequently, removing any metadata from config will have no effect on the existing metadata of the resource. (see [below for nested schema](#nestedatt--metadata))
+- `metadata` (Attributes List) Metadata for the Hypervisor. (see [below for nested schema](#nestedatt--metadata))
- `scopes` (Set of String) The IDs of the scopes for the hypervisor to be a part of.
### Read-Only
diff --git a/docs/resources/scvmm_hypervisor_resource_pool.md b/docs/resources/scvmm_hypervisor_resource_pool.md
index 5eb1c3a..b0a22aa 100644
--- a/docs/resources/scvmm_hypervisor_resource_pool.md
+++ b/docs/resources/scvmm_hypervisor_resource_pool.md
@@ -51,9 +51,7 @@ resource "citrix_scvmm_hypervisor_resource_pool" "example-scvmm-hypervisor-resou
### Optional
-- `metadata` (Attributes List) Metadata for the Hypervisor Resource Pool.
-
-~> **Please Note** Metadata once set cannot be removed. Use this field to add new metadata or update the value for an existing metadata. Subsequently, removing any metadata from config will have no effect on the existing metadata of the resource. (see [below for nested schema](#nestedatt--metadata))
+- `metadata` (Attributes List) Metadata for the Hypervisor Resource Pool. (see [below for nested schema](#nestedatt--metadata))
- `use_local_storage_caching` (Boolean) Indicates whether intellicache is enabled to reduce load on the shared storage device. Will only be effective when shared storage is used. Default value is `false`.
### Read-Only
diff --git a/docs/resources/vsphere_hypervisor.md b/docs/resources/vsphere_hypervisor.md
index 13e6cc6..37aaba0 100644
--- a/docs/resources/vsphere_hypervisor.md
+++ b/docs/resources/vsphere_hypervisor.md
@@ -42,9 +42,7 @@ resource "citrix_vsphere_hypervisor" "example-vsphere-hypervisor" {
- `max_absolute_active_actions` (Number) Maximum number of actions that can execute in parallel on the hypervisor. Default is 40.
- `max_absolute_new_actions_per_minute` (Number) Maximum number of actions that can be started on the hypervisor per-minute. Default is 10.
- `max_power_actions_percentage_of_machines` (Number) Maximum percentage of machines on the hypervisor which can have their power state changed simultaneously. Default is 20.
-- `metadata` (Attributes List) Metadata for the Hypervisor.
-
-~> **Please Note** Metadata once set cannot be removed. Use this field to add new metadata or update the value for an existing metadata. Subsequently, removing any metadata from config will have no effect on the existing metadata of the resource. (see [below for nested schema](#nestedatt--metadata))
+- `metadata` (Attributes List) Metadata for the Hypervisor. (see [below for nested schema](#nestedatt--metadata))
- `scopes` (Set of String) The IDs of the scopes for the hypervisor to be a part of.
- `ssl_thumbprints` (List of String) SSL certificate thumbprints to consider acceptable for this connection. If not specified, and the hypervisor uses SSL for its connection, the SSL certificate's root certification authority and any intermediate certificates must be trusted.
diff --git a/docs/resources/vsphere_hypervisor_resource_pool.md b/docs/resources/vsphere_hypervisor_resource_pool.md
index 2d8f5a8..cab053a 100644
--- a/docs/resources/vsphere_hypervisor_resource_pool.md
+++ b/docs/resources/vsphere_hypervisor_resource_pool.md
@@ -55,9 +55,7 @@ resource "citrix_vsphere_hypervisor_resource_pool" "example-vsphere-hypervisor-r
### Optional
-- `metadata` (Attributes List) Metadata for the Hypervisor Resource Pool.
-
-~> **Please Note** Metadata once set cannot be removed. Use this field to add new metadata or update the value for an existing metadata. Subsequently, removing any metadata from config will have no effect on the existing metadata of the resource. (see [below for nested schema](#nestedatt--metadata))
+- `metadata` (Attributes List) Metadata for the Hypervisor Resource Pool. (see [below for nested schema](#nestedatt--metadata))
- `use_local_storage_caching` (Boolean) Indicates whether intellicache is enabled to reduce load on the shared storage device. Will only be effective when shared storage is used. Default value is `false`.
### Read-Only
diff --git a/docs/resources/xenserver_hypervisor.md b/docs/resources/xenserver_hypervisor.md
index 43f861a..78c6558 100644
--- a/docs/resources/xenserver_hypervisor.md
+++ b/docs/resources/xenserver_hypervisor.md
@@ -46,9 +46,7 @@ resource "citrix_xenserver_hypervisor" "example-xenserver-hypervisor" {
- `max_absolute_active_actions` (Number) Maximum number of actions that can execute in parallel on the hypervisor. Default is 40.
- `max_absolute_new_actions_per_minute` (Number) Maximum number of actions that can be started on the hypervisor per-minute. Default is 10.
- `max_power_actions_percentage_of_machines` (Number) Maximum percentage of machines on the hypervisor which can have their power state changed simultaneously. Default is 20.
-- `metadata` (Attributes List) Metadata for the Hypervisor.
-
-~> **Please Note** Metadata once set cannot be removed. Use this field to add new metadata or update the value for an existing metadata. Subsequently, removing any metadata from config will have no effect on the existing metadata of the resource. (see [below for nested schema](#nestedatt--metadata))
+- `metadata` (Attributes List) Metadata for the Hypervisor. (see [below for nested schema](#nestedatt--metadata))
- `scopes` (Set of String) The IDs of the scopes for the hypervisor to be a part of.
- `ssl_thumbprints` (List of String) SSL certificate thumbprints to consider acceptable for this connection. If not specified, and the hypervisor uses SSL for its connection, the SSL certificate's root certification authority and any intermediate certificates must be trusted.
diff --git a/docs/resources/xenserver_hypervisor_resource_pool.md b/docs/resources/xenserver_hypervisor_resource_pool.md
index 3b99bd8..922d607 100644
--- a/docs/resources/xenserver_hypervisor_resource_pool.md
+++ b/docs/resources/xenserver_hypervisor_resource_pool.md
@@ -49,9 +49,7 @@ resource "citrix_xenserver_hypervisor_resource_pool" "example-xenserver-hypervis
### Optional
-- `metadata` (Attributes List) Metadata for the Hypervisor Resource Pool.
-
-~> **Please Note** Metadata once set cannot be removed. Use this field to add new metadata or update the value for an existing metadata. Subsequently, removing any metadata from config will have no effect on the existing metadata of the resource. (see [below for nested schema](#nestedatt--metadata))
+- `metadata` (Attributes List) Metadata for the Hypervisor Resource Pool. (see [below for nested schema](#nestedatt--metadata))
- `use_local_storage_caching` (Boolean) Indicates whether intellicache is enabled to reduce load on the shared storage device. Will only be effective when shared storage is used. Default value is `false`.
### Read-Only
diff --git a/docs/resources/zone.md b/docs/resources/zone.md
index 3b9b56b..319b2ce 100644
--- a/docs/resources/zone.md
+++ b/docs/resources/zone.md
@@ -51,9 +51,7 @@ resource "citrix_zone" "example-cloud-zone" {
- `description` (String) Description of the zone.
-> **Note** For Citrix Cloud customer, ensure this matches the description of the existing zone behind the `resource_location_id` that needs to be used.
-- `metadata` (Attributes List) Metadata for the Zone.
-
-~> **Please Note** Metadata once set cannot be removed. Use this field to add new metadata or update the value for an existing metadata. Subsequently, removing any metadata from config will have no effect on the existing metadata of the resource. (see [below for nested schema](#nestedatt--metadata))
+- `metadata` (Attributes List) Metadata for the Zone. (see [below for nested schema](#nestedatt--metadata))
- `name` (String) Name of the zone.
-> **Note** For Citrix Cloud Customer, `name` is not allowed to be used for creating zone and is computed only. Use `resource_location_id` to create zone Instead.
diff --git a/go.mod b/go.mod
index 18d288b..d1f65ea 100644
--- a/go.mod
+++ b/go.mod
@@ -5,7 +5,7 @@ go 1.22.0
toolchain go1.23.1
require (
- github.com/citrix/citrix-daas-rest-go v1.0.5
+ github.com/citrix/citrix-daas-rest-go v1.0.6
github.com/google/uuid v1.6.0
github.com/hashicorp/go-azure-helpers v0.71.0
github.com/hashicorp/go-multierror v1.1.1
@@ -15,7 +15,7 @@ require (
github.com/hashicorp/terraform-plugin-go v0.24.0
github.com/hashicorp/terraform-plugin-log v0.9.0
github.com/hashicorp/terraform-plugin-testing v1.8.0
- golang.org/x/exp v0.0.0-20240909161429-701f63a606c0
+ golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c
golang.org/x/mod v0.21.0
)
@@ -68,16 +68,16 @@ require (
github.com/vmihailenco/msgpack/v5 v5.4.1 // indirect
github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect
github.com/zclconf/go-cty v1.15.0 // indirect
- golang.org/x/crypto v0.27.0 // indirect
- golang.org/x/net v0.29.0 // indirect
+ golang.org/x/crypto v0.28.0 // indirect
+ golang.org/x/net v0.30.0 // indirect
golang.org/x/sync v0.8.0 // indirect
- golang.org/x/sys v0.25.0 // indirect
- golang.org/x/text v0.18.0 // indirect
- golang.org/x/tools v0.25.0 // indirect
+ golang.org/x/sys v0.26.0 // indirect
+ golang.org/x/text v0.19.0 // indirect
+ golang.org/x/tools v0.26.0 // indirect
google.golang.org/appengine v1.6.8 // indirect
- google.golang.org/genproto/googleapis/rpc v0.0.0-20240924160255-9d4c2d233b61 // indirect
- google.golang.org/grpc v1.67.0 // indirect
- google.golang.org/protobuf v1.34.2 // indirect
+ google.golang.org/genproto/googleapis/rpc v0.0.0-20241007155032-5fefd90f89a9 // indirect
+ google.golang.org/grpc v1.67.1 // indirect
+ google.golang.org/protobuf v1.35.1 // indirect
)
// replace github.com/citrix/citrix-daas-rest-go => ../citrix-daas-rest-go
diff --git a/go.sum b/go.sum
index 00556b1..a14bc8c 100644
--- a/go.sum
+++ b/go.sum
@@ -24,8 +24,8 @@ github.com/bgentry/speakeasy v0.1.0 h1:ByYyxL9InA1OWqxJqqp2A5pYHUrCiAL6K3J+LKSsQ
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
github.com/bufbuild/protocompile v0.4.0 h1:LbFKd2XowZvQ/kajzguUp2DC9UEIQhIq77fZZlaQsNA=
github.com/bufbuild/protocompile v0.4.0/go.mod h1:3v93+mbWn/v3xzN+31nwkJfrEpAUwp+BagBSZWx+TP8=
-github.com/citrix/citrix-daas-rest-go v1.0.5 h1:zDOoydXQq4jQ3fObZypsBG6ZJxyHIcHrS4eg6kJzlZ0=
-github.com/citrix/citrix-daas-rest-go v1.0.5/go.mod h1:4Me0VHpyxMYfPwpU2XWV0jOE2Jdz8MHNpge3MLD5B2E=
+github.com/citrix/citrix-daas-rest-go v1.0.6 h1:yUHs6jWmlOB0DReJyvAoxG7oKPi2TYXAituxBbOOBLE=
+github.com/citrix/citrix-daas-rest-go v1.0.6/go.mod h1:4Me0VHpyxMYfPwpU2XWV0jOE2Jdz8MHNpge3MLD5B2E=
github.com/cloudflare/circl v1.3.7 h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vcU=
github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBSc8r4zxgA=
github.com/cyphar/filepath-securejoin v0.2.4 h1:Ugdm7cg7i6ZK6x3xDF1oEu1nfkyfH53EtKeQYTC3kyg=
@@ -213,10 +213,10 @@ golang.org/x/crypto v0.0.0-20200414173820-0848c9571904/go.mod h1:LzIPMQfyMNhhGPh
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
-golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A=
-golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70=
-golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 h1:e66Fs6Z+fZTbFBAxKfP3PALWBtpfqks2bwGcexMxgtk=
-golang.org/x/exp v0.0.0-20240909161429-701f63a606c0/go.mod h1:2TbTHSBQa924w8M6Xs1QcRcFwyucIwBGpK1p2f1YFFY=
+golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw=
+golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U=
+golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c h1:7dEasQXItcW1xKJ2+gg5VOiBnqWrJc+rq0DPKyvvdbY=
+golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c/go.mod h1:NQtJDoLvd6faHhE7m4T/1IY708gDefGGjR/iUW8yQQ8=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0=
golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
@@ -225,8 +225,8 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
-golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo=
-golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0=
+golang.org/x/net v0.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4=
+golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -246,8 +246,8 @@ golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34=
-golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo=
+golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
@@ -257,26 +257,26 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
-golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224=
-golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
+golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM=
+golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
-golang.org/x/tools v0.25.0 h1:oFU9pkj/iJgs+0DT+VMHrx+oBKs/LJMV+Uvg78sl+fE=
-golang.org/x/tools v0.25.0/go.mod h1:/vtpO8WL1N9cQC3FN5zPqb//fRXskFHbLKk4OW1Q7rg=
+golang.org/x/tools v0.26.0 h1:v/60pFQmzmT9ExmjDv2gGIfi3OqfKoEP6I5+umXlbnQ=
+golang.org/x/tools v0.26.0/go.mod h1:TPVVj70c7JJ3WCazhD8OdXcZg/og+b9+tH/KxylGwH0=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM=
google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20240924160255-9d4c2d233b61 h1:N9BgCIAUvn/M+p4NJccWPWb3BWh88+zyL0ll9HgbEeM=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20240924160255-9d4c2d233b61/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU=
-google.golang.org/grpc v1.67.0 h1:IdH9y6PF5MPSdAntIcpjQ+tXO41pcQsfZV2RxtQgVcw=
-google.golang.org/grpc v1.67.0/go.mod h1:1gLDyUQU7CTLJI90u3nXZ9ekeghjeM7pTDZlqFNg2AA=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20241007155032-5fefd90f89a9 h1:QCqS/PdaHTSWGvupk2F/ehwHtGc0/GYkT+3GAcR1CCc=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20241007155032-5fefd90f89a9/go.mod h1:GX3210XPVPUjJbTUbvwI8f2IpZDMZuPJWDzDuebbviI=
+google.golang.org/grpc v1.67.1 h1:zWnc1Vrcno+lHZCOofnIMvycFcc0QRGIzm9dhnDX68E=
+google.golang.org/grpc v1.67.1/go.mod h1:1gLDyUQU7CTLJI90u3nXZ9ekeghjeM7pTDZlqFNg2AA=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
-google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
-google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
+google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA=
+google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
diff --git a/internal/citrixcloud/admin_user/admin_user_resource.go b/internal/citrixcloud/admin_user/admin_user_resource.go
index 5f0bbfc..5be869d 100644
--- a/internal/citrixcloud/admin_user/admin_user_resource.go
+++ b/internal/citrixcloud/admin_user/admin_user_resource.go
@@ -15,7 +15,6 @@ import (
"github.com/hashicorp/terraform-plugin-framework/path"
"github.com/hashicorp/terraform-plugin-framework/resource"
- "github.com/hashicorp/terraform-plugin-framework/types"
"github.com/hashicorp/terraform-plugin-log/tflog"
)
@@ -133,28 +132,9 @@ func (r *ccAdminUserResource) Create(ctx context.Context, req resource.CreateReq
return
}
- // Try getting the new admin user from remote
- adminUser, err := getAdminUser(ctx, r.client, plan)
+ plan, err = fetchAndUpdateAdminUser(ctx, r.client, plan, &resp.Diagnostics)
if err != nil {
- resp.Diagnostics.AddError(
- "Error fetching admin user",
- util.ReadClientError(err),
- )
- return
- }
-
- // Update the plan with the fetched admin user details
- plan = plan.RefreshPropertyValues(ctx, &resp.Diagnostics, adminUser)
-
- if !plan.Policies.IsNull() {
- var filteredPolicies []CCAdminPolicyResourceModel
- policies := util.ObjectListToTypedArray[CCAdminPolicyResourceModel](ctx, &resp.Diagnostics, plan.Policies)
- for _, policy := range policies {
- // Set the service name to empty string as it is not returned by the API
- policy.ServiceName = types.StringValue("")
- filteredPolicies = append(filteredPolicies, policy)
- }
- plan.Policies = util.TypedArrayToObjectList[CCAdminPolicyResourceModel](ctx, &resp.Diagnostics, filteredPolicies)
+ return // Error already added to diagnostics
}
// Set state to fully populated data
diff --git a/internal/citrixcloud/admin_user/admin_user_resource_model.go b/internal/citrixcloud/admin_user/admin_user_resource_model.go
index 9537ec1..6d2e074 100644
--- a/internal/citrixcloud/admin_user/admin_user_resource_model.go
+++ b/internal/citrixcloud/admin_user/admin_user_resource_model.go
@@ -286,8 +286,11 @@ func filterPolicies(remotePolicies []ccadmins.AdministratorAccessPolicyModel, po
checkable := remotePolicy.GetCheckable()
if checkable.GetValue() {
// Check if the remote policy name exists in the policies
+ trimmedRemotePolicyDisplayName := strings.TrimSuffix(remotePolicy.GetDisplayName(), util.AdminUserMonitorAccessPolicySuffix)
if configPolicyName, exists := policyNameMap[strings.ToLower(remotePolicy.GetDisplayName())]; exists {
remotePolicy.SetDisplayName(configPolicyName)
+ } else if configPolicyName, exists := policyNameMap[strings.ToLower(trimmedRemotePolicyDisplayName)]; exists {
+ remotePolicy.SetDisplayName(configPolicyName)
}
filteredPolicies = append(filteredPolicies, remotePolicy)
}
diff --git a/internal/citrixcloud/admin_user/admin_user_utils.go b/internal/citrixcloud/admin_user/admin_user_utils.go
index b402da8..d45518e 100644
--- a/internal/citrixcloud/admin_user/admin_user_utils.go
+++ b/internal/citrixcloud/admin_user/admin_user_utils.go
@@ -13,6 +13,7 @@ import (
citrixdaasclient "github.com/citrix/citrix-daas-rest-go/client"
"github.com/citrix/terraform-provider-citrix/internal/util"
"github.com/hashicorp/terraform-plugin-framework/diag"
+ "github.com/hashicorp/terraform-plugin-framework/types"
)
// List of AdministratorServiceNames
@@ -142,8 +143,8 @@ func getAdminAccessPolicy(ctx context.Context, diagnostics *diag.Diagnostics, ad
createAdminPolicyModel := ccadmins.AdministratorAccessPolicyModel{}
var serviceNameList []string
for _, remotePolicy := range remoteAdminPolicies {
-
- if strings.EqualFold(remotePolicy.GetDisplayName(), policyDisplayName) {
+ trimmedRemotePolicyDisplayName := strings.TrimSuffix(remotePolicy.GetDisplayName(), util.AdminUserMonitorAccessPolicySuffix)
+ if strings.EqualFold(remotePolicy.GetDisplayName(), policyDisplayName) || strings.EqualFold(trimmedRemotePolicyDisplayName, policyDisplayName) {
// If service name is specified, check if the policy is associated with the service
if serviceName != "" && !strings.EqualFold(remotePolicy.GetServiceName(), serviceName) {
continue
@@ -275,22 +276,34 @@ func fetchAndUpdateAdminUser(ctx context.Context, client *citrixdaasclient.Citri
// Update the plan with the fetched admin user details
plan = plan.RefreshPropertyValues(ctx, diagnostics, adminUser)
- // Check if the invitation is accepted and if custom access type with policies is required
- if isInvitationAccepted(plan) && isCustomAccessTypeWithPolicies(plan) {
- adminId := plan.AdminId.ValueString()
-
- // Fetch access policies for the admin user
- accessPolicies, err := getAccessPolicies(ctx, client, adminId)
- if err != nil {
- diagnostics.AddError(
- "Error getting access policies for user "+plan.Email.ValueString(),
- "Error message: "+util.ReadClientError(err),
- )
- return plan, err
+ // Check if custom access type with policies is required
+ if isCustomAccessTypeWithPolicies(plan) {
+ if isInvitationAccepted(plan) {
+ adminId := plan.AdminId.ValueString()
+ // Fetch access policies for the admin user
+ accessPolicies, err := getAccessPolicies(ctx, client, adminId)
+ if err != nil {
+ diagnostics.AddError(
+ "Error getting access policies for user "+plan.Email.ValueString(),
+ "Error message: "+util.ReadClientError(err),
+ )
+ return plan, err
+ }
+ // Update the plan with the fetched access policies
+ plan = plan.RefreshPropertyValuesForPolicies(ctx, diagnostics, accessPolicies)
+ } else {
+ // If the invitation is not accepted
+ var filteredPolicies []CCAdminPolicyResourceModel
+ policies := util.ObjectListToTypedArray[CCAdminPolicyResourceModel](ctx, diagnostics, plan.Policies)
+ for _, policy := range policies {
+ // Set the service name to empty string if it is not set as its a computed field
+ if policy.ServiceName.IsNull() || policy.ServiceName.ValueString() == "" {
+ policy.ServiceName = types.StringValue("")
+ }
+ filteredPolicies = append(filteredPolicies, policy)
+ }
+ plan.Policies = util.TypedArrayToObjectList[CCAdminPolicyResourceModel](ctx, diagnostics, filteredPolicies)
}
-
- // Update the plan with the fetched access policies
- plan = plan.RefreshPropertyValuesForPolicies(ctx, diagnostics, accessPolicies)
}
return plan, nil
}
diff --git a/internal/citrixcloud/gac_settings/gac_settings_resource.go b/internal/citrixcloud/gac_settings/gac_settings_resource.go
index f637388..820253f 100644
--- a/internal/citrixcloud/gac_settings/gac_settings_resource.go
+++ b/internal/citrixcloud/gac_settings/gac_settings_resource.go
@@ -77,6 +77,7 @@ func (r *gacSettingsResource) Create(ctx context.Context, req resource.CreateReq
appSettings.SetHtml5(GetAppSettingsForHtml5(ctx, &resp.Diagnostics, planAppSettings.Html5))
appSettings.SetIos(GetAppSettingsForIos(ctx, &resp.Diagnostics, planAppSettings.Ios))
appSettings.SetMacos(GetAppSettingsForMacos(ctx, &resp.Diagnostics, planAppSettings.Macos))
+ appSettings.SetLinux(GetAppSettingsForLinux(ctx, &resp.Diagnostics, planAppSettings.Linux))
appSettings.SetWindows(GetAppSettingsForWindows(ctx, &resp.Diagnostics, planAppSettings.Windows))
var settings globalappconfiguration.Settings
@@ -173,6 +174,7 @@ func (r *gacSettingsResource) Update(ctx context.Context, req resource.UpdateReq
appSettings.SetIos(GetAppSettingsForIos(ctx, &resp.Diagnostics, planAppSettings.Ios))
appSettings.SetMacos(GetAppSettingsForMacos(ctx, &resp.Diagnostics, planAppSettings.Macos))
appSettings.SetWindows(GetAppSettingsForWindows(ctx, &resp.Diagnostics, planAppSettings.Windows))
+ appSettings.SetLinux(GetAppSettingsForLinux(ctx, &resp.Diagnostics, planAppSettings.Linux))
var settings globalappconfiguration.Settings
settings.SetName(plan.Name.ValueString())
@@ -269,9 +271,9 @@ func readSettingsConfiguration(ctx context.Context, client *citrixdaasclient.Cit
return getSettingsResponse, err
}
-func GetAppSettingsForWindows(ctx context.Context, diagnostics *diag.Diagnostics, windowsList types.List) []globalappconfiguration.PlatformSettings {
+func GetAppSettingsForWindows(ctx context.Context, diagnostics *diag.Diagnostics, windowsList types.Set) []globalappconfiguration.PlatformSettings {
var platformSettings []globalappconfiguration.PlatformSettings
- windows := util.ObjectListToTypedArray[Windows](ctx, diagnostics, windowsList)
+ windows := util.ObjectSetToTypedArray[Windows](ctx, diagnostics, windowsList)
for _, windowsInstance := range windows {
var platformSetting globalappconfiguration.PlatformSettings
@@ -285,9 +287,25 @@ func GetAppSettingsForWindows(ctx context.Context, diagnostics *diag.Diagnostics
return platformSettings
}
-func GetAppSettingsForIos(ctx context.Context, diagnostics *diag.Diagnostics, iosList types.List) []globalappconfiguration.PlatformSettings {
+func GetAppSettingsForLinux(ctx context.Context, diagnostics *diag.Diagnostics, linuxList types.Set) []globalappconfiguration.PlatformSettings {
var platformSettings []globalappconfiguration.PlatformSettings
- ios := util.ObjectListToTypedArray[Ios](ctx, diagnostics, iosList)
+ linux := util.ObjectSetToTypedArray[Linux](ctx, diagnostics, linuxList)
+
+ for _, linuxInstance := range linux {
+ var platformSetting globalappconfiguration.PlatformSettings
+ platformSetting.SetCategory(linuxInstance.Category.ValueString())
+ platformSetting.SetUserOverride(linuxInstance.UserOverride.ValueBool())
+ platformSetting.SetAssignmentPriority(util.AssignmentPriority)
+ platformSetting.SetAssignedTo(util.PlatformSettingsAssignedTo)
+ platformSetting.SetSettings(CreateCategorySettingsForLinux(ctx, diagnostics, linuxInstance.Settings))
+ platformSettings = append(platformSettings, platformSetting)
+ }
+ return platformSettings
+}
+
+func GetAppSettingsForIos(ctx context.Context, diagnostics *diag.Diagnostics, iosList types.Set) []globalappconfiguration.PlatformSettings {
+ var platformSettings []globalappconfiguration.PlatformSettings
+ ios := util.ObjectSetToTypedArray[Ios](ctx, diagnostics, iosList)
for _, iosInstance := range ios {
var platformSetting globalappconfiguration.PlatformSettings
@@ -301,9 +319,9 @@ func GetAppSettingsForIos(ctx context.Context, diagnostics *diag.Diagnostics, io
return platformSettings
}
-func GetAppSettingsForAndroid(ctx context.Context, diagnostics *diag.Diagnostics, androidList types.List) []globalappconfiguration.PlatformSettings {
+func GetAppSettingsForAndroid(ctx context.Context, diagnostics *diag.Diagnostics, androidList types.Set) []globalappconfiguration.PlatformSettings {
var platformSettings []globalappconfiguration.PlatformSettings
- android := util.ObjectListToTypedArray[Android](ctx, diagnostics, androidList)
+ android := util.ObjectSetToTypedArray[Android](ctx, diagnostics, androidList)
for _, androidInstance := range android {
var platformSetting globalappconfiguration.PlatformSettings
@@ -317,9 +335,9 @@ func GetAppSettingsForAndroid(ctx context.Context, diagnostics *diag.Diagnostics
return platformSettings
}
-func GetAppSettingsForChromeos(ctx context.Context, diagnostics *diag.Diagnostics, chromeosList types.List) []globalappconfiguration.PlatformSettings {
+func GetAppSettingsForChromeos(ctx context.Context, diagnostics *diag.Diagnostics, chromeosList types.Set) []globalappconfiguration.PlatformSettings {
var platformSettings []globalappconfiguration.PlatformSettings
- chromeos := util.ObjectListToTypedArray[Chromeos](ctx, diagnostics, chromeosList)
+ chromeos := util.ObjectSetToTypedArray[Chromeos](ctx, diagnostics, chromeosList)
for _, chromeosInstance := range chromeos {
var platformSetting globalappconfiguration.PlatformSettings
@@ -333,9 +351,9 @@ func GetAppSettingsForChromeos(ctx context.Context, diagnostics *diag.Diagnostic
return platformSettings
}
-func GetAppSettingsForHtml5(ctx context.Context, diagnostics *diag.Diagnostics, html5List types.List) []globalappconfiguration.PlatformSettings {
+func GetAppSettingsForHtml5(ctx context.Context, diagnostics *diag.Diagnostics, html5List types.Set) []globalappconfiguration.PlatformSettings {
var platformSettings []globalappconfiguration.PlatformSettings
- html5 := util.ObjectListToTypedArray[Html5](ctx, diagnostics, html5List)
+ html5 := util.ObjectSetToTypedArray[Html5](ctx, diagnostics, html5List)
for _, html5Instance := range html5 {
var platformSetting globalappconfiguration.PlatformSettings
@@ -349,9 +367,9 @@ func GetAppSettingsForHtml5(ctx context.Context, diagnostics *diag.Diagnostics,
return platformSettings
}
-func GetAppSettingsForMacos(ctx context.Context, diagnostics *diag.Diagnostics, macosList types.List) []globalappconfiguration.PlatformSettings {
+func GetAppSettingsForMacos(ctx context.Context, diagnostics *diag.Diagnostics, macosList types.Set) []globalappconfiguration.PlatformSettings {
var platformSettings []globalappconfiguration.PlatformSettings
- macos := util.ObjectListToTypedArray[Macos](ctx, diagnostics, macosList)
+ macos := util.ObjectSetToTypedArray[Macos](ctx, diagnostics, macosList)
for _, macosInstance := range macos {
var platformSetting globalappconfiguration.PlatformSettings
@@ -430,6 +448,55 @@ func CreateCategorySettingsForWindows(ctx context.Context, diagnostics *diag.Dia
return categorySettings
}
+func CreateCategorySettingsForLinux(ctx context.Context, diagnostics *diag.Diagnostics, linuxSettingsList types.List) []globalappconfiguration.CategorySettings {
+ var categorySettings []globalappconfiguration.CategorySettings
+ linuxSettings := util.ObjectListToTypedArray[LinuxSettings](ctx, diagnostics, linuxSettingsList)
+
+ for _, linuxSetting := range linuxSettings {
+ var categorySetting globalappconfiguration.CategorySettings
+
+ categorySetting.SetName(linuxSetting.Name.ValueString())
+ if !linuxSetting.ValueString.IsNull() {
+ categorySetting.SetValue(linuxSetting.ValueString.ValueString())
+ } else if len(linuxSetting.ValueList.Elements()) > 0 {
+ categorySetting.SetValue(util.StringListToStringArray(ctx, diagnostics, linuxSetting.ValueList))
+ } else if !linuxSetting.ExtensionInstallAllowList.IsNull() {
+ var extensionInstallAllowListGo []ExtensionInstallAllowListModel_Go
+ extensionInstallAllowList := util.ObjectListToTypedArray[ExtensionInstallAllowListModel](ctx, diagnostics, linuxSetting.ExtensionInstallAllowList)
+ for _, extensionInstall := range extensionInstallAllowList {
+ var extensionInstallAllowListGoItem ExtensionInstallAllowListModel_Go
+ ConvertStruct(extensionInstall, &extensionInstallAllowListGoItem)
+ extensionInstallAllowListGo = append(extensionInstallAllowListGo, extensionInstallAllowListGoItem)
+ }
+ categorySetting.SetValue(extensionInstallAllowListGo)
+ } else if !linuxSetting.AutoLaunchProtocolsFromOrigins.IsNull() {
+ var autoLaunchProtocolsFromOriginsGo []AutoLaunchProtocolsFromOriginsModel_Go
+ autoLaunchProtocolsFromOriginsList := util.ObjectListToTypedArray[AutoLaunchProtocolsFromOriginsModel](ctx, diagnostics, linuxSetting.AutoLaunchProtocolsFromOrigins)
+ for _, autoLaunchProtocolsFromOrigins := range autoLaunchProtocolsFromOriginsList {
+ var autoLaunchProtocolItem AutoLaunchProtocolsFromOriginsModel_Go
+ autoLaunchProtocolItem.Protocol = autoLaunchProtocolsFromOrigins.Protocol.ValueString()
+ if !autoLaunchProtocolsFromOrigins.AllowedOrigins.IsNull() {
+ autoLaunchProtocolItem.AllowedOrigins = util.StringListToStringArray(ctx, diagnostics, autoLaunchProtocolsFromOrigins.AllowedOrigins)
+ }
+ autoLaunchProtocolsFromOriginsGo = append(autoLaunchProtocolsFromOriginsGo, autoLaunchProtocolItem)
+ }
+ categorySetting.SetValue(autoLaunchProtocolsFromOriginsGo)
+ } else if !linuxSetting.ManagedBookmarks.IsNull() {
+ var managedBookmarksGo []BookMarkValueModel_Go
+ managedBookmarksList := util.ObjectListToTypedArray[BookMarkValueModel](ctx, diagnostics, linuxSetting.ManagedBookmarks)
+ for _, managedBookmark := range managedBookmarksList {
+ var managedBookmarkItem BookMarkValueModel_Go
+ managedBookmarkItem.Name = managedBookmark.Name.ValueString()
+ managedBookmarkItem.Url = managedBookmark.Url.ValueString()
+ managedBookmarksGo = append(managedBookmarksGo, managedBookmarkItem)
+ }
+ categorySetting.SetValue(managedBookmarksGo)
+ }
+ categorySettings = append(categorySettings, categorySetting)
+ }
+ return categorySettings
+}
+
func CreateCategorySettingsForIos(ctx context.Context, diagnostics *diag.Diagnostics, iosSettingsList types.List) []globalappconfiguration.CategorySettings {
var categorySettings []globalappconfiguration.CategorySettings
iosSettings := util.ObjectListToTypedArray[IosSettings](ctx, diagnostics, iosSettingsList)
@@ -576,9 +643,10 @@ func (r *gacSettingsResource) ValidateConfig(ctx context.Context, req resource.V
return
}
+ // Validate the configuration for windows
appSettings := util.ObjectValueToTypedObject[AppSettings](ctx, &resp.Diagnostics, data.AppSettings)
if !appSettings.Windows.IsNull() && !appSettings.Windows.IsUnknown() {
- windowsList := util.ObjectListToTypedArray[Windows](ctx, &resp.Diagnostics, appSettings.Windows)
+ windowsList := util.ObjectSetToTypedArray[Windows](ctx, &resp.Diagnostics, appSettings.Windows)
for _, windowsInstance := range windowsList {
appSettings := util.ObjectListToTypedArray[WindowsSettings](ctx, &resp.Diagnostics, windowsInstance.Settings)
for _, appSetting := range appSettings {
@@ -587,21 +655,34 @@ func (r *gacSettingsResource) ValidateConfig(ctx context.Context, req resource.V
}
}
}
+ }
- if !appSettings.Macos.IsNull() && !appSettings.Macos.IsUnknown() {
- macosList := util.ObjectListToTypedArray[Macos](ctx, &resp.Diagnostics, appSettings.Macos)
- for _, macosInstance := range macosList {
- appSettings := util.ObjectListToTypedArray[MacosSettings](ctx, &resp.Diagnostics, macosInstance.Settings)
- for _, appSetting := range appSettings {
- if appSetting.EnterpriseBroswerSSO.IsNull() && appSetting.ExtensionInstallAllowList.IsNull() && appSetting.ValueList.IsNull() && appSetting.ValueString.IsNull() && appSetting.AutoLaunchProtocolsFromOrigins.IsNull() && appSetting.ManagedBookmarks.IsNull() {
- resp.Diagnostics.AddError("Error in MacOs Settings", "At least one value should be specified for Windows Settings")
- }
+ // Validate the configuration for macOs
+ if !appSettings.Macos.IsNull() && !appSettings.Macos.IsUnknown() {
+ macosList := util.ObjectSetToTypedArray[Macos](ctx, &resp.Diagnostics, appSettings.Macos)
+ for _, macosInstance := range macosList {
+ appSettings := util.ObjectListToTypedArray[MacosSettings](ctx, &resp.Diagnostics, macosInstance.Settings)
+ for _, appSetting := range appSettings {
+ if appSetting.EnterpriseBroswerSSO.IsNull() && appSetting.ExtensionInstallAllowList.IsNull() && appSetting.ValueList.IsNull() && appSetting.ValueString.IsNull() && appSetting.AutoLaunchProtocolsFromOrigins.IsNull() && appSetting.ManagedBookmarks.IsNull() {
+ resp.Diagnostics.AddError("Error in MacOs Settings", "At least one value should be specified for MacOs Settings")
}
}
-
- schemaType, configValuesForSchema := util.GetConfigValuesForSchema(ctx, &resp.Diagnostics, &data)
- tflog.Debug(ctx, "Validate Config - "+schemaType, configValuesForSchema)
}
+ }
+ // Validate the configuration for Linux
+ if !appSettings.Linux.IsNull() && !appSettings.Linux.IsUnknown() {
+ htmls5List := util.ObjectSetToTypedArray[Linux](ctx, &resp.Diagnostics, appSettings.Linux)
+ for _, LinuxInstance := range htmls5List {
+ appSettings := util.ObjectListToTypedArray[LinuxSettings](ctx, &resp.Diagnostics, LinuxInstance.Settings)
+ for _, appSetting := range appSettings {
+ if appSetting.ValueString.IsNull() && appSetting.ValueList.IsNull() && appSetting.AutoLaunchProtocolsFromOrigins.IsNull() && appSetting.ManagedBookmarks.IsNull() && appSetting.ExtensionInstallAllowList.IsNull() {
+ resp.Diagnostics.AddError("Error in Linux Settings", "At least one value should be specified for Linux Settings")
+ }
+ }
+ }
}
+
+ schemaType, configValuesForSchema := util.GetConfigValuesForSchema(ctx, &resp.Diagnostics, &data)
+ tflog.Debug(ctx, "Validate Config - "+schemaType, configValuesForSchema)
}
diff --git a/internal/citrixcloud/gac_settings/gac_settings_resource_model.go b/internal/citrixcloud/gac_settings/gac_settings_resource_model.go
index 99dde7c..e3accfb 100644
--- a/internal/citrixcloud/gac_settings/gac_settings_resource_model.go
+++ b/internal/citrixcloud/gac_settings/gac_settings_resource_model.go
@@ -7,10 +7,12 @@ import (
"encoding/json"
"fmt"
"reflect"
+ "regexp"
globalappconfiguration "github.com/citrix/citrix-daas-rest-go/globalappconfiguration"
"github.com/citrix/terraform-provider-citrix/internal/util"
"github.com/hashicorp/terraform-plugin-framework-validators/listvalidator"
+ "github.com/hashicorp/terraform-plugin-framework-validators/setvalidator"
"github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
"github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/hashicorp/terraform-plugin-framework/path"
@@ -35,12 +37,13 @@ func (GACSettingsResourceModel) GetAttributes() map[string]schema.Attribute {
}
type AppSettings struct {
- Windows types.List `tfsdk:"windows"` //[]Windows
- Ios types.List `tfsdk:"ios"` //[]Ios
- Android types.List `tfsdk:"android"` //[]Android
- Chromeos types.List `tfsdk:"chromeos"` //[]Chromeos
- Html5 types.List `tfsdk:"html5"` //[]Html5
- Macos types.List `tfsdk:"macos"` //[]Macos
+ Windows types.Set `tfsdk:"windows"` //[]Windows
+ Ios types.Set `tfsdk:"ios"` //[]Ios
+ Android types.Set `tfsdk:"android"` //[]Android
+ Chromeos types.Set `tfsdk:"chromeos"` //[]Chromeos
+ Html5 types.Set `tfsdk:"html5"` //[]Html5
+ Macos types.Set `tfsdk:"macos"` //[]Macos
+ Linux types.Set `tfsdk:"linux"` //[]Linux
}
func (AppSettings) GetSchema() schema.SingleNestedAttribute {
@@ -48,52 +51,60 @@ func (AppSettings) GetSchema() schema.SingleNestedAttribute {
Description: "Defines the device platform and the associated settings. Currently, only settings objects with value type of integer, boolean, strings and list of strings is supported.",
Required: true,
Attributes: map[string]schema.Attribute{
- "windows": schema.ListNestedAttribute{
+ "windows": schema.SetNestedAttribute{
Description: "Settings to be applied for users using windows platform.",
Optional: true,
NestedObject: Windows{}.GetSchema(),
- Validators: []validator.List{
- listvalidator.SizeAtLeast(1),
+ Validators: []validator.Set{
+ setvalidator.SizeAtLeast(1),
},
},
- "ios": schema.ListNestedAttribute{
+ "ios": schema.SetNestedAttribute{
Description: "Settings to be applied for users using ios platform.",
Optional: true,
NestedObject: Ios{}.GetSchema(),
- Validators: []validator.List{
- listvalidator.SizeAtLeast(1),
+ Validators: []validator.Set{
+ setvalidator.SizeAtLeast(1),
},
},
- "android": schema.ListNestedAttribute{
+ "android": schema.SetNestedAttribute{
Description: "Settings to be applied for users using android platform.",
Optional: true,
NestedObject: Android{}.GetSchema(),
- Validators: []validator.List{
- listvalidator.SizeAtLeast(1),
+ Validators: []validator.Set{
+ setvalidator.SizeAtLeast(1),
},
},
- "html5": schema.ListNestedAttribute{
+ "html5": schema.SetNestedAttribute{
Description: "Settings to be applied for users using html5.",
Optional: true,
NestedObject: Html5{}.GetSchema(),
- Validators: []validator.List{
- listvalidator.SizeAtLeast(1),
+ Validators: []validator.Set{
+ setvalidator.SizeAtLeast(1),
},
},
- "chromeos": schema.ListNestedAttribute{
+ "chromeos": schema.SetNestedAttribute{
Description: "Settings to be applied for users using chrome os platform.",
Optional: true,
NestedObject: Chromeos{}.GetSchema(),
- Validators: []validator.List{
- listvalidator.SizeAtLeast(1),
+ Validators: []validator.Set{
+ setvalidator.SizeAtLeast(1),
},
},
- "macos": schema.ListNestedAttribute{
+ "macos": schema.SetNestedAttribute{
Description: "Settings to be applied for users using mac os platform.",
Optional: true,
NestedObject: Macos{}.GetSchema(),
- Validators: []validator.List{
- listvalidator.SizeAtLeast(1),
+ Validators: []validator.Set{
+ setvalidator.SizeAtLeast(1),
+ },
+ },
+ "linux": schema.SetNestedAttribute{
+ Description: "Settings to be applied for users using linux platform.",
+ Optional: true,
+ NestedObject: Linux{}.GetSchema(),
+ Validators: []validator.Set{
+ setvalidator.SizeAtLeast(1),
},
},
},
@@ -116,6 +127,9 @@ func (Windows) GetSchema() schema.NestedAttributeObject {
"category": schema.StringAttribute{
Description: "Defines the category of the setting.",
Required: true,
+ Validators: []validator.String{
+ stringvalidator.RegexMatches(regexp.MustCompile(util.GacCategoryNameRegex), "\nCategory name must start with a single uppercase letter followed by zero or more lowercase letters "),
+ },
},
"user_override": schema.BoolAttribute{
Description: "Defines if users can modify or change the value of as obtained settings from the Global App Citrix Workspace configuration service.",
@@ -149,6 +163,9 @@ func (Ios) GetSchema() schema.NestedAttributeObject {
"category": schema.StringAttribute{
Description: "Defines the category of the setting",
Required: true,
+ Validators: []validator.String{
+ stringvalidator.RegexMatches(regexp.MustCompile(util.GacCategoryNameRegex), "\nCategory name must start with a single uppercase letter followed by zero or more lowercase letters "),
+ },
},
"user_override": schema.BoolAttribute{
Description: "Defines if users can modify or change the value of as obtained settings from the Global App Citrix Workspace configuration service.",
@@ -182,6 +199,9 @@ func (Android) GetSchema() schema.NestedAttributeObject {
"category": schema.StringAttribute{
Description: "Defines the category of the setting.",
Required: true,
+ Validators: []validator.String{
+ stringvalidator.RegexMatches(regexp.MustCompile(util.GacCategoryNameRegex), "\nCategory name must start with a single uppercase letter followed by zero or more lowercase letters "),
+ },
},
"user_override": schema.BoolAttribute{
Description: "Defines if users can modify or change the value of as obtained settings from the Global App Citrix Workspace configuration service.",
@@ -215,6 +235,9 @@ func (Chromeos) GetSchema() schema.NestedAttributeObject {
"category": schema.StringAttribute{
Description: "Defines the category of the setting.",
Required: true,
+ Validators: []validator.String{
+ stringvalidator.RegexMatches(regexp.MustCompile(util.GacCategoryNameRegex), "\nCategory name must start with a single uppercase letter followed by zero or more lowercase letters "),
+ },
},
"user_override": schema.BoolAttribute{
Description: "Defines if users can modify or change the value of as obtained settings from the Global App Citrix Workspace configuration service.",
@@ -248,6 +271,9 @@ func (Html5) GetSchema() schema.NestedAttributeObject {
"category": schema.StringAttribute{
Description: "Defines the category of the setting.",
Required: true,
+ Validators: []validator.String{
+ stringvalidator.RegexMatches(regexp.MustCompile(util.GacCategoryNameRegex), "\nCategory name must start with a single uppercase letter followed by zero or more lowercase letters "),
+ },
},
"user_override": schema.BoolAttribute{
Description: "Defines if users can modify or change the value of as obtained settings from the Global App Citrix Workspace configuration service.",
@@ -281,6 +307,9 @@ func (Macos) GetSchema() schema.NestedAttributeObject {
"category": schema.StringAttribute{
Description: "Defines the category of the setting.",
Required: true,
+ Validators: []validator.String{
+ stringvalidator.RegexMatches(regexp.MustCompile(util.GacCategoryNameRegex), "\nCategory name must start with a single uppercase letter followed by zero or more lowercase letters "),
+ },
},
"user_override": schema.BoolAttribute{
Description: "Defines if users can modify or change the value of as obtained settings from the Global App Citrix Workspace configuration service.",
@@ -302,6 +331,42 @@ func (Macos) GetAttributes() map[string]schema.Attribute {
return Macos{}.GetSchema().Attributes
}
+type Linux struct {
+ Category types.String `tfsdk:"category"`
+ UserOverride types.Bool `tfsdk:"user_override"`
+ Settings types.List `tfsdk:"settings"` //[]LinuxSettings
+}
+
+func (Linux) GetSchema() schema.NestedAttributeObject {
+ return schema.NestedAttributeObject{
+ Attributes: map[string]schema.Attribute{
+ "category": schema.StringAttribute{
+ Description: "Defines the category of the setting.",
+ Required: true,
+ Validators: []validator.String{
+ stringvalidator.RegexMatches(regexp.MustCompile(util.GacCategoryNameRegex), "\nCategory name must start with a single uppercase letter followed by zero or more lowercase letters "),
+ },
+ },
+ "user_override": schema.BoolAttribute{
+ Description: "Defines if users can modify or change the value of as obtained settings from the Global App Citrix Workspace configuration service.",
+ Required: true,
+ },
+ "settings": schema.ListNestedAttribute{
+ Description: "A list of name value pairs for the settings. Please refer to the following [table](https://developer-docs.citrix.com/en-us/server-integration/global-app-configuration-service/getting-started#supported-settings-and-their-values-per-platform) for the supported settings name and their values per platform.",
+ Required: true,
+ Validators: []validator.List{
+ listvalidator.SizeAtLeast(1),
+ },
+ NestedObject: LinuxSettings{}.GetSchema(),
+ },
+ },
+ }
+}
+
+func (Linux) GetAttributes() map[string]schema.Attribute {
+ return Linux{}.GetSchema().Attributes
+}
+
type WindowsSettings struct {
Name types.String `tfsdk:"name"`
ValueString types.String `tfsdk:"value_string"`
@@ -514,6 +579,69 @@ func (Html5Settings) GetAttributes() map[string]schema.Attribute {
return Html5Settings{}.GetSchema().Attributes
}
+type LinuxSettings struct {
+ Name types.String `tfsdk:"name"`
+ ValueString types.String `tfsdk:"value_string"`
+ ValueList types.List `tfsdk:"value_list"`
+ ExtensionInstallAllowList types.List `tfsdk:"extension_install_allow_list"` //list[ExtensionInstallAllowListModel]
+ AutoLaunchProtocolsFromOrigins types.List `tfsdk:"auto_launch_protocols_from_origins"` //List[AutoLaunchProtocolsFromOriginsModel]
+ ManagedBookmarks types.List `tfsdk:"managed_bookmarks"` //List[BookMarkValueModel]
+}
+
+func (LinuxSettings) GetSchema() schema.NestedAttributeObject {
+ return schema.NestedAttributeObject{
+ Attributes: map[string]schema.Attribute{
+ "name": schema.StringAttribute{
+ Description: "Name of the setting.",
+ Required: true,
+ },
+ "value_string": schema.StringAttribute{
+ Description: "String value (if any) associated with the setting.",
+ Optional: true,
+ Validators: []validator.String{
+ stringvalidator.LengthAtLeast(1),
+ },
+ },
+ "value_list": schema.ListAttribute{
+ ElementType: types.StringType,
+ Description: "List value (if any) associated with the setting.",
+ Optional: true,
+ Validators: []validator.List{
+ listvalidator.SizeAtLeast(1),
+ },
+ },
+ "extension_install_allow_list": schema.ListNestedAttribute{
+ Optional: true,
+ Description: "An allowed list of extensions that users can add to the Citrix Enterprise Browser. This list uses the Chrome Web Store.",
+ NestedObject: ExtensionInstallAllowListModel{}.GetSchema(),
+ Validators: []validator.List{
+ listvalidator.SizeAtLeast(1),
+ },
+ },
+ "auto_launch_protocols_from_origins": schema.ListNestedAttribute{
+ Optional: true,
+ Description: "A list of protocols that can launch an external application from the listed origins without prompting the user.",
+ NestedObject: AutoLaunchProtocolsFromOriginsModel{}.GetSchema(),
+ Validators: []validator.List{
+ listvalidator.SizeAtLeast(1),
+ },
+ },
+ "managed_bookmarks": schema.ListNestedAttribute{
+ Optional: true,
+ Description: "A list of bookmarks to push to the Citrix Enterprise Browser.",
+ NestedObject: BookMarkValueModel{}.GetSchema(),
+ Validators: []validator.List{
+ listvalidator.SizeAtLeast(1),
+ },
+ },
+ },
+ }
+}
+
+func (LinuxSettings) GetAttributes() map[string]schema.Attribute {
+ return LinuxSettings{}.GetSchema().Attributes
+}
+
type MacosSettings struct {
Name types.String `tfsdk:"name"`
ValueString types.String `tfsdk:"value_string"`
@@ -596,6 +724,7 @@ func (r GACSettingsResourceModel) RefreshPropertyValues(ctx context.Context, dia
var chromeosSettings = appSettings.GetChromeos()
var html5Settings = appSettings.GetHtml5()
var macosSettings = appSettings.GetMacos()
+ var linuxSettings = appSettings.GetLinux()
planAppSettings := util.ObjectValueToTypedObject[AppSettings](ctx, diagnostics, r.AppSettings)
@@ -605,18 +734,19 @@ func (r GACSettingsResourceModel) RefreshPropertyValues(ctx context.Context, dia
planAppSettings.Chromeos = r.getChromeosSettings(ctx, diagnostics, chromeosSettings)
planAppSettings.Html5 = r.getHtml5Settings(ctx, diagnostics, html5Settings)
planAppSettings.Macos = r.getMacosSettings(ctx, diagnostics, macosSettings)
+ planAppSettings.Linux = r.getLinuxSettings(ctx, diagnostics, linuxSettings)
r.AppSettings = util.TypedObjectToObjectValue(ctx, diagnostics, planAppSettings)
return r
}
-func (r GACSettingsResourceModel) getWindowsSettings(ctx context.Context, diagnostics *diag.Diagnostics, remoteWindowsSettings []globalappconfiguration.PlatformSettings) types.List {
+func (r GACSettingsResourceModel) getWindowsSettings(ctx context.Context, diagnostics *diag.Diagnostics, remoteWindowsSettings []globalappconfiguration.PlatformSettings) types.Set {
var stateWindowsSettings []Windows
if !r.AppSettings.IsNull() {
appSettings := util.ObjectValueToTypedObject[AppSettings](ctx, diagnostics, r.AppSettings)
if !appSettings.Windows.IsNull() {
- stateWindowsSettings = util.ObjectListToTypedArray[Windows](ctx, diagnostics, appSettings.Windows)
+ stateWindowsSettings = util.ObjectSetToTypedArray[Windows](ctx, diagnostics, appSettings.Windows)
}
}
@@ -664,15 +794,71 @@ func (r GACSettingsResourceModel) getWindowsSettings(ctx context.Context, diagno
}
}
- return util.TypedArrayToObjectList[Windows](ctx, diagnostics, windowsSettingsForState)
+ return util.TypedArrayToObjectSet[Windows](ctx, diagnostics, windowsSettingsForState)
}
-func (r GACSettingsResourceModel) getIosSettings(ctx context.Context, diagnostics *diag.Diagnostics, remoteIosSettings []globalappconfiguration.PlatformSettings) types.List {
+func (r GACSettingsResourceModel) getLinuxSettings(ctx context.Context, diagnostics *diag.Diagnostics, remoteLinuxSettings []globalappconfiguration.PlatformSettings) types.Set {
+ var stateLinuxSettings []Linux
+ if !r.AppSettings.IsNull() {
+ appSettings := util.ObjectValueToTypedObject[AppSettings](ctx, diagnostics, r.AppSettings)
+ if !appSettings.Linux.IsNull() {
+ stateLinuxSettings = util.ObjectSetToTypedArray[Linux](ctx, diagnostics, appSettings.Linux)
+ }
+ }
+
+ type RemoteLinuxSettingsTracker struct {
+ platformSetting globalappconfiguration.PlatformSettings
+ IsVisited bool
+ }
+
+ // Create a map of category -> RemoteLinuxSettingsTracker for remote
+ remoteLinuxSettingsMap := map[string]*RemoteLinuxSettingsTracker{}
+ for _, remoteLinuxSetting := range remoteLinuxSettings {
+ remoteLinuxSettingsMap[remoteLinuxSetting.GetCategory()] = &RemoteLinuxSettingsTracker{
+ platformSetting: remoteLinuxSetting,
+ IsVisited: false,
+ }
+ }
+
+ // Prepare the linux settings list to be stored in the state
+ var linuxSettingsForState []Linux
+ for _, stateLinuxSetting := range stateLinuxSettings {
+ remoteLinuxSetting, exists := remoteLinuxSettingsMap[stateLinuxSetting.Category.ValueString()]
+ if !exists {
+ // If linux setting is not present in the remote, then don't add it to the state
+ continue
+ }
+
+ linuxSettingsForState = append(linuxSettingsForState, Linux{
+ Category: types.StringValue(remoteLinuxSetting.platformSetting.GetCategory()),
+ UserOverride: types.BoolValue(remoteLinuxSetting.platformSetting.GetUserOverride()),
+ Settings: getLinuxCategorySettings(ctx, diagnostics, stateLinuxSetting.Settings, remoteLinuxSetting.platformSetting.GetSettings()),
+ })
+
+ remoteLinuxSetting.IsVisited = true
+
+ }
+
+ // Add the linux settings from remote which are not present in the state
+ for _, remoteLinuxSetting := range remoteLinuxSettingsMap {
+ if !remoteLinuxSetting.IsVisited {
+ linuxSettingsForState = append(linuxSettingsForState, Linux{
+ Category: types.StringValue(remoteLinuxSetting.platformSetting.GetCategory()),
+ UserOverride: types.BoolValue(remoteLinuxSetting.platformSetting.GetUserOverride()),
+ Settings: parseLinuxSettings(ctx, diagnostics, remoteLinuxSetting.platformSetting.GetSettings()),
+ })
+ }
+ }
+
+ return util.TypedArrayToObjectSet[Linux](ctx, diagnostics, linuxSettingsForState)
+}
+
+func (r GACSettingsResourceModel) getIosSettings(ctx context.Context, diagnostics *diag.Diagnostics, remoteIosSettings []globalappconfiguration.PlatformSettings) types.Set {
var stateIosSettings []Ios
if !r.AppSettings.IsNull() {
appSettings := util.ObjectValueToTypedObject[AppSettings](ctx, diagnostics, r.AppSettings)
if !appSettings.Ios.IsNull() {
- stateIosSettings = util.ObjectListToTypedArray[Ios](ctx, diagnostics, appSettings.Ios)
+ stateIosSettings = util.ObjectSetToTypedArray[Ios](ctx, diagnostics, appSettings.Ios)
}
}
@@ -720,15 +906,15 @@ func (r GACSettingsResourceModel) getIosSettings(ctx context.Context, diagnostic
}
}
- return util.TypedArrayToObjectList[Ios](ctx, diagnostics, iosSettingsForState)
+ return util.TypedArrayToObjectSet[Ios](ctx, diagnostics, iosSettingsForState)
}
-func (r GACSettingsResourceModel) getAndroidSettings(ctx context.Context, diagnostics *diag.Diagnostics, remoteAndroidSettings []globalappconfiguration.PlatformSettings) types.List {
+func (r GACSettingsResourceModel) getAndroidSettings(ctx context.Context, diagnostics *diag.Diagnostics, remoteAndroidSettings []globalappconfiguration.PlatformSettings) types.Set {
var stateAndroidSettings []Android
if !r.AppSettings.IsNull() {
appSettings := util.ObjectValueToTypedObject[AppSettings](ctx, diagnostics, r.AppSettings)
if !appSettings.Android.IsNull() {
- stateAndroidSettings = util.ObjectListToTypedArray[Android](ctx, diagnostics, appSettings.Android)
+ stateAndroidSettings = util.ObjectSetToTypedArray[Android](ctx, diagnostics, appSettings.Android)
}
}
@@ -776,15 +962,15 @@ func (r GACSettingsResourceModel) getAndroidSettings(ctx context.Context, diagno
}
}
- return util.TypedArrayToObjectList[Android](ctx, diagnostics, androidSettingsForState)
+ return util.TypedArrayToObjectSet[Android](ctx, diagnostics, androidSettingsForState)
}
-func (r GACSettingsResourceModel) getHtml5Settings(ctx context.Context, diagnostics *diag.Diagnostics, remoteHtml5Settings []globalappconfiguration.PlatformSettings) types.List {
+func (r GACSettingsResourceModel) getHtml5Settings(ctx context.Context, diagnostics *diag.Diagnostics, remoteHtml5Settings []globalappconfiguration.PlatformSettings) types.Set {
var stateHtml5Settings []Html5
if !r.AppSettings.IsNull() {
appSettings := util.ObjectValueToTypedObject[AppSettings](ctx, diagnostics, r.AppSettings)
if !appSettings.Html5.IsNull() {
- stateHtml5Settings = util.ObjectListToTypedArray[Html5](ctx, diagnostics, appSettings.Html5)
+ stateHtml5Settings = util.ObjectSetToTypedArray[Html5](ctx, diagnostics, appSettings.Html5)
}
}
@@ -832,15 +1018,15 @@ func (r GACSettingsResourceModel) getHtml5Settings(ctx context.Context, diagnost
}
}
- return util.TypedArrayToObjectList[Html5](ctx, diagnostics, html5SettingsForState)
+ return util.TypedArrayToObjectSet[Html5](ctx, diagnostics, html5SettingsForState)
}
-func (r GACSettingsResourceModel) getChromeosSettings(ctx context.Context, diagnostics *diag.Diagnostics, remoteChromeosSettings []globalappconfiguration.PlatformSettings) types.List {
+func (r GACSettingsResourceModel) getChromeosSettings(ctx context.Context, diagnostics *diag.Diagnostics, remoteChromeosSettings []globalappconfiguration.PlatformSettings) types.Set {
var stateChromeosSettings []Chromeos
if !r.AppSettings.IsNull() {
appSettings := util.ObjectValueToTypedObject[AppSettings](ctx, diagnostics, r.AppSettings)
if !appSettings.Chromeos.IsNull() {
- stateChromeosSettings = util.ObjectListToTypedArray[Chromeos](ctx, diagnostics, appSettings.Chromeos)
+ stateChromeosSettings = util.ObjectSetToTypedArray[Chromeos](ctx, diagnostics, appSettings.Chromeos)
}
}
@@ -888,15 +1074,15 @@ func (r GACSettingsResourceModel) getChromeosSettings(ctx context.Context, diagn
}
}
- return util.TypedArrayToObjectList[Chromeos](ctx, diagnostics, chromeosSettingsForState)
+ return util.TypedArrayToObjectSet[Chromeos](ctx, diagnostics, chromeosSettingsForState)
}
-func (r GACSettingsResourceModel) getMacosSettings(ctx context.Context, diagnostics *diag.Diagnostics, remoteMacosSettings []globalappconfiguration.PlatformSettings) types.List {
+func (r GACSettingsResourceModel) getMacosSettings(ctx context.Context, diagnostics *diag.Diagnostics, remoteMacosSettings []globalappconfiguration.PlatformSettings) types.Set {
var stateMacosSettings []Macos
if !r.AppSettings.IsNull() {
appSettings := util.ObjectValueToTypedObject[AppSettings](ctx, diagnostics, r.AppSettings)
if !appSettings.Macos.IsNull() {
- stateMacosSettings = util.ObjectListToTypedArray[Macos](ctx, diagnostics, appSettings.Macos)
+ stateMacosSettings = util.ObjectSetToTypedArray[Macos](ctx, diagnostics, appSettings.Macos)
}
}
@@ -944,7 +1130,7 @@ func (r GACSettingsResourceModel) getMacosSettings(ctx context.Context, diagnost
}
}
- return util.TypedArrayToObjectList[Macos](ctx, diagnostics, macosSettingsForState)
+ return util.TypedArrayToObjectSet[Macos](ctx, diagnostics, macosSettingsForState)
}
func parseWindowsSettings(ctx context.Context, diagnostics *diag.Diagnostics, remoteWindowsSettings []globalappconfiguration.CategorySettings) types.List {
@@ -1017,6 +1203,54 @@ func parseWindowsSettings(ctx context.Context, diagnostics *diag.Diagnostics, re
return util.TypedArrayToObjectList[WindowsSettings](ctx, diagnostics, windowsSettings)
}
+func parseLinuxSettings(ctx context.Context, diagnostics *diag.Diagnostics, remoteLinuxSettings []globalappconfiguration.CategorySettings) types.List {
+ var linuxSettings []LinuxSettings
+ var errMsg string
+
+ for _, remoteLinuxSetting := range remoteLinuxSettings {
+ var linuxSetting LinuxSettings
+ LinuxSettingsDefaultValues(ctx, diagnostics, &linuxSetting)
+ linuxSetting.Name = types.StringValue(remoteLinuxSetting.GetName())
+ valueType := reflect.TypeOf(remoteLinuxSetting.GetValue())
+ switch valueType.Kind() {
+ case reflect.String:
+ linuxSetting.ValueString = types.StringValue(remoteLinuxSetting.GetValue().(string))
+ case reflect.Slice:
+ extentionInstallAllowList := GACSettingsUpdate[ExtensionInstallAllowListModel, ExtensionInstallAllowListModel_Go](ctx, diagnostics, remoteLinuxSetting.Value)
+ if extentionInstallAllowList != nil {
+ linuxSetting.ExtensionInstallAllowList = util.TypedArrayToObjectList(ctx, diagnostics, extentionInstallAllowList)
+ break
+ }
+
+ autoLaunchProtocolsList := GACSettingsUpdate[AutoLaunchProtocolsFromOriginsModel, AutoLaunchProtocolsFromOriginsModel_Go](ctx, diagnostics, remoteLinuxSetting.Value)
+ if autoLaunchProtocolsList != nil {
+ linuxSetting.AutoLaunchProtocolsFromOrigins = util.TypedArrayToObjectList(ctx, diagnostics, autoLaunchProtocolsList)
+ break
+ }
+
+ managedBookmarkList := GACSettingsUpdate[BookMarkValueModel, BookMarkValueModel_Go](ctx, diagnostics, remoteLinuxSetting.Value)
+ if managedBookmarkList != nil {
+ linuxSetting.ManagedBookmarks = util.TypedArrayToObjectList(ctx, diagnostics, managedBookmarkList)
+ break
+ }
+
+ linuxSetting.ValueList, errMsg = util.ConvertPrimitiveInterfaceArrayToStringList(ctx, diagnostics, remoteLinuxSetting.Value.([]interface{}))
+ default:
+ errMsg = fmt.Sprintf("Unsupported type for linux setting value: %v", valueType.Kind())
+ }
+ if errMsg != "" {
+ diagnostics.AddError(
+ "Could not parse value for the setting:"+linuxSetting.Name.ValueString(),
+ errMsg,
+ )
+ }
+
+ linuxSettings = append(linuxSettings, linuxSetting)
+ }
+
+ return util.TypedArrayToObjectList[LinuxSettings](ctx, diagnostics, linuxSettings)
+}
+
func parseIosSettings(ctx context.Context, diagnostics *diag.Diagnostics, remoteIosSettings []globalappconfiguration.CategorySettings) types.List {
var iosSettings []IosSettings
var errMsg string
@@ -1368,6 +1602,125 @@ func getWindowsCategorySettings(ctx context.Context, diagnostics *diag.Diagnosti
return util.TypedArrayToObjectList[WindowsSettings](ctx, diagnostics, windowsSettingsForState)
}
+func getLinuxCategorySettings(ctx context.Context, diagnostics *diag.Diagnostics, linuxSettings types.List, remoteLinuxSettings []globalappconfiguration.CategorySettings) types.List {
+
+ var linuxSettingsForState []LinuxSettings
+ var errMsg string
+
+ stateLinuxSettings := util.ObjectListToTypedArray[LinuxSettings](ctx, diagnostics, linuxSettings)
+
+ type RemoteSettingsTracker struct {
+ Value interface{}
+ IsVisited bool
+ }
+
+ // Create a map of name -> RemoteSettingsTracker for remote
+ remoteLinuxCategorySettingsMap := map[string]*RemoteSettingsTracker{}
+ for _, remoteLinuxSetting := range remoteLinuxSettings {
+ remoteLinuxCategorySettingsMap[remoteLinuxSetting.GetName()] = &RemoteSettingsTracker{
+ Value: remoteLinuxSetting.GetValue(),
+ IsVisited: false,
+ }
+ }
+
+ // Prepare the linux settings list to be stored in the state
+ for _, stateLinuxSetting := range stateLinuxSettings {
+ remoteLinuxSetting, exists := remoteLinuxCategorySettingsMap[stateLinuxSetting.Name.ValueString()]
+ if !exists {
+ // If linux setting is not present in the remote, then don't add it to the state
+ continue
+ }
+
+ var linuxSetting LinuxSettings
+ errMsg = ""
+ linuxSetting.Name = stateLinuxSetting.Name
+ LinuxSettingsDefaultValues(ctx, diagnostics, &linuxSetting)
+ valueType := reflect.TypeOf(remoteLinuxSetting.Value)
+ switch valueType.Kind() {
+ case reflect.String:
+ linuxSetting.ValueString = types.StringValue(remoteLinuxSetting.Value.(string))
+ case reflect.Slice:
+ extentionInstallAllowList := GACSettingsUpdate[ExtensionInstallAllowListModel, ExtensionInstallAllowListModel_Go](ctx, diagnostics, remoteLinuxSetting.Value)
+ if extentionInstallAllowList != nil {
+ linuxSetting.ExtensionInstallAllowList = util.TypedArrayToObjectList(ctx, diagnostics, extentionInstallAllowList)
+ break
+ }
+
+ autoLaunchProtocolsList := GACSettingsUpdate[AutoLaunchProtocolsFromOriginsModel, AutoLaunchProtocolsFromOriginsModel_Go](ctx, diagnostics, remoteLinuxSetting.Value)
+ if autoLaunchProtocolsList != nil {
+ linuxSetting.AutoLaunchProtocolsFromOrigins = util.TypedArrayToObjectList(ctx, diagnostics, autoLaunchProtocolsList)
+ break
+ }
+
+ managedBookmarkList := GACSettingsUpdate[BookMarkValueModel, BookMarkValueModel_Go](ctx, diagnostics, remoteLinuxSetting.Value)
+ if managedBookmarkList != nil {
+ linuxSetting.ManagedBookmarks = util.TypedArrayToObjectList(ctx, diagnostics, managedBookmarkList)
+ break
+ }
+
+ linuxSetting.ValueList, errMsg = util.ConvertPrimitiveInterfaceArrayToStringList(ctx, diagnostics, remoteLinuxSetting.Value.([]interface{}))
+ default:
+ errMsg = fmt.Sprintf("Unsupported type for linux setting value: %v", valueType.Kind())
+ }
+ if errMsg != "" {
+ diagnostics.AddError(
+ "Could not parse value for the setting:"+linuxSetting.Name.ValueString(),
+ errMsg,
+ )
+ }
+
+ linuxSettingsForState = append(linuxSettingsForState, linuxSetting)
+ remoteLinuxSetting.IsVisited = true
+ }
+ // Add the linux settings from remote which are not present in the state
+ for settingName, remoteLinuxSetting := range remoteLinuxCategorySettingsMap {
+ if !remoteLinuxSetting.IsVisited {
+ var linuxSetting LinuxSettings
+ errMsg = ""
+
+ linuxSetting.Name = types.StringValue(settingName)
+ LinuxSettingsDefaultValues(ctx, diagnostics, &linuxSetting)
+ valueType := reflect.TypeOf(remoteLinuxSetting.Value)
+ switch valueType.Kind() {
+ case reflect.String:
+ linuxSetting.ValueString = types.StringValue(remoteLinuxSetting.Value.(string))
+ case reflect.Slice:
+ extentionInstallAllowList := GACSettingsUpdate[ExtensionInstallAllowListModel, ExtensionInstallAllowListModel_Go](ctx, diagnostics, remoteLinuxSetting.Value)
+ if extentionInstallAllowList != nil {
+ linuxSetting.ExtensionInstallAllowList = util.TypedArrayToObjectList(ctx, diagnostics, extentionInstallAllowList)
+ break
+ }
+
+ autoLaunchProtocolsList := GACSettingsUpdate[AutoLaunchProtocolsFromOriginsModel, AutoLaunchProtocolsFromOriginsModel_Go](ctx, diagnostics, remoteLinuxSetting.Value)
+ if autoLaunchProtocolsList != nil {
+ linuxSetting.AutoLaunchProtocolsFromOrigins = util.TypedArrayToObjectList(ctx, diagnostics, autoLaunchProtocolsList)
+ break
+ }
+
+ managedBookmarkList := GACSettingsUpdate[BookMarkValueModel, BookMarkValueModel_Go](ctx, diagnostics, remoteLinuxSetting.Value)
+ if managedBookmarkList != nil {
+ linuxSetting.ManagedBookmarks = util.TypedArrayToObjectList(ctx, diagnostics, managedBookmarkList)
+ break
+ }
+
+ linuxSetting.ValueList, errMsg = util.ConvertPrimitiveInterfaceArrayToStringList(ctx, diagnostics, remoteLinuxSetting.Value.([]interface{}))
+ default:
+ errMsg = fmt.Sprintf("Unsupported type for linux setting value: %v", valueType.Kind())
+ }
+ if errMsg != "" {
+ diagnostics.AddError(
+ "Could not parse value for the setting:"+linuxSetting.Name.ValueString(),
+ errMsg,
+ )
+ }
+
+ linuxSettingsForState = append(linuxSettingsForState, linuxSetting)
+ }
+ }
+
+ return util.TypedArrayToObjectList[LinuxSettings](ctx, diagnostics, linuxSettingsForState)
+}
+
func getIosCategorySettings(ctx context.Context, diagnostics *diag.Diagnostics, iosSettings types.List, remoteIosSettings []globalappconfiguration.CategorySettings) types.List {
var iosSettingsForState []IosSettings
diff --git a/internal/citrixcloud/gac_settings/gac_settings_util.go b/internal/citrixcloud/gac_settings/gac_settings_util.go
index 6297dcd..1c46801 100644
--- a/internal/citrixcloud/gac_settings/gac_settings_util.go
+++ b/internal/citrixcloud/gac_settings/gac_settings_util.go
@@ -419,3 +419,31 @@ func MacosSettingsDefaultValues(ctx context.Context, diagnostics *diag.Diagnosti
}
macosSetting.EnterpriseBroswerSSO = types.ObjectNull(enterpriseBrowserAttributesMap)
}
+
+func LinuxSettingsDefaultValues(ctx context.Context, diagnostics *diag.Diagnostics, linuxSetting *LinuxSettings) {
+ linuxSetting.ValueList = types.ListNull(types.StringType)
+ //setting null for AutoLaunchProtocolsFromOrigins
+ autoLaunchProtocolAttributesMap, err := util.AttributeMapFromObject(AutoLaunchProtocolsFromOriginsModel{AllowedOrigins: types.ListNull(types.StringType)})
+ if err != nil {
+ diagnostics.AddWarning("Error converting schema to attribute map. Error: ", err.Error())
+ return
+ }
+ linuxSetting.AutoLaunchProtocolsFromOrigins = types.ListNull(types.ObjectType{AttrTypes: autoLaunchProtocolAttributesMap})
+
+ //setting null for ManagedBookmarks
+ bookMarkAttributesMap, err := util.AttributeMapFromObject(BookMarkValueModel{})
+ if err != nil {
+ diagnostics.AddWarning("Error converting schema to attribute map. Error: ", err.Error())
+ return
+ }
+ linuxSetting.ManagedBookmarks = types.ListNull(types.ObjectType{AttrTypes: bookMarkAttributesMap})
+
+ //setting null for ExtensionInstallAllowList
+ installAllowListAttributesMap, err := util.AttributeMapFromObject(ExtensionInstallAllowListModel{})
+ if err != nil {
+ diagnostics.AddWarning("Error converting schema to attribute map. Error: ", err.Error())
+ return
+ }
+ linuxSetting.ExtensionInstallAllowList = types.ListNull(types.ObjectType{AttrTypes: installAllowListAttributesMap})
+
+}
diff --git a/internal/citrixcloud/identity_providers/google_identity_provider_resource_model.go b/internal/citrixcloud/identity_providers/google_identity_provider_resource_model.go
index 0666c4d..bdedc78 100644
--- a/internal/citrixcloud/identity_providers/google_identity_provider_resource_model.go
+++ b/internal/citrixcloud/identity_providers/google_identity_provider_resource_model.go
@@ -75,10 +75,16 @@ func (GoogleIdentityProviderResourceModel) GetSchema() schema.Schema {
"google_customer_id": schema.StringAttribute{
Description: "Customer ID of the configured Google Cloud Identity Provider.",
Computed: true,
+ PlanModifiers: []planmodifier.String{
+ stringplanmodifier.UseStateForUnknown(),
+ },
},
"google_domain": schema.StringAttribute{
Description: "Domain of the configured Google Cloud Identity Provider.",
Computed: true,
+ PlanModifiers: []planmodifier.String{
+ stringplanmodifier.UseStateForUnknown(),
+ },
},
},
}
diff --git a/internal/citrixcloud/identity_providers/saml_identity_provider_resource_model.go b/internal/citrixcloud/identity_providers/saml_identity_provider_resource_model.go
index 55ff8cd..1fd9ee5 100644
--- a/internal/citrixcloud/identity_providers/saml_identity_provider_resource_model.go
+++ b/internal/citrixcloud/identity_providers/saml_identity_provider_resource_model.go
@@ -300,14 +300,23 @@ func (SamlIdentityProviderResourceModel) GetSchema() schema.Schema {
"cert_common_name": schema.StringAttribute{
Description: "The common name of the SAML certificate.",
Computed: true,
+ PlanModifiers: []planmodifier.String{
+ stringplanmodifier.UseStateForUnknown(),
+ },
},
"cert_expiration": schema.StringAttribute{
Description: "The expiration date time of the SAML certificate.",
Computed: true,
+ PlanModifiers: []planmodifier.String{
+ stringplanmodifier.UseStateForUnknown(),
+ },
},
"scoped_entity_id_suffix": schema.StringAttribute{
Description: "The Scoped Entity Id Suffix for the SAML 2.0 Identity Provider.",
Computed: true,
+ PlanModifiers: []planmodifier.String{
+ stringplanmodifier.UseStateForUnknown(),
+ },
},
},
}
diff --git a/internal/citrixcloud/resource_locations/resource_locations_data_source.go b/internal/citrixcloud/resource_locations/resource_locations_data_source.go
new file mode 100644
index 0000000..3ab2be1
--- /dev/null
+++ b/internal/citrixcloud/resource_locations/resource_locations_data_source.go
@@ -0,0 +1,96 @@
+// Copyright © 2024. Citrix Systems, Inc.
+
+package resource_locations
+
+import (
+ "context"
+ "strings"
+
+ ccresourcelocations "github.com/citrix/citrix-daas-rest-go/ccresourcelocations"
+ resourcelocations "github.com/citrix/citrix-daas-rest-go/ccresourcelocations"
+ citrixdaasclient "github.com/citrix/citrix-daas-rest-go/client"
+ "github.com/citrix/terraform-provider-citrix/internal/util"
+
+ "github.com/hashicorp/terraform-plugin-framework/datasource"
+)
+
+// Ensure provider defined types fully satisfy framework interfaces.
+var (
+ _ datasource.DataSource = &ResourceLocationsDataSource{}
+)
+
+func NewResourceLocationsDataSource() datasource.DataSource {
+ return &ResourceLocationsDataSource{}
+}
+
+// ResourceLocationsDataSource defines the data source implementation.
+type ResourceLocationsDataSource struct {
+ client *citrixdaasclient.CitrixDaasClient
+}
+
+func (d *ResourceLocationsDataSource) Metadata(ctx context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) {
+ resp.TypeName = req.ProviderTypeName + "_cloud_resource_location"
+}
+
+func (d *ResourceLocationsDataSource) Schema(ctx context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) {
+ resp.Schema = ResourceLocationsDataSourceModel{}.GetSchema()
+}
+
+func (d *ResourceLocationsDataSource) Configure(ctx context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) {
+ // Prevent panic if the provider has not been configured.
+ if req.ProviderData == nil {
+ return
+ }
+
+ d.client = req.ProviderData.(*citrixdaasclient.CitrixDaasClient)
+}
+
+func (d *ResourceLocationsDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) {
+ defer util.PanicHandler(&resp.Diagnostics)
+
+ if d.client != nil && d.client.ApiClient == nil {
+ resp.Diagnostics.AddError(util.ProviderInitializationErrorMsg, util.MissingProviderClientIdAndSecretErrorMsg)
+ return
+ }
+
+ var data ResourceLocationsDataSourceModel
+
+ // Read Terraform configuration data into the model
+ resp.Diagnostics.Append(req.Config.Get(ctx, &data)...)
+
+ if resp.Diagnostics.HasError() {
+ return
+ }
+
+ // Get resource location
+ getResourceLocationRequest := d.client.ResourceLocationsClient.LocationsDAAS.LocationsGetAll(ctx)
+ resourceLocation, httpResp, err := citrixdaasclient.ExecuteWithRetry[*resourcelocations.CitrixCloudServicesRegistryApiModelsLocationsResourceLocationsResultsModel](getResourceLocationRequest, d.client)
+ if err != nil {
+ resp.Diagnostics.AddError(
+ "Failed to get resource location."+err.Error(),
+ "TransactionId: "+citrixdaasclient.GetTransactionIdFromHttpResponse(httpResp)+
+ "\nError message: "+util.ReadClientError(err),
+ )
+ }
+
+ var matchedResourceLocation *ccresourcelocations.CitrixCloudServicesRegistryApiModelsLocationsResourceLocationModel
+ // Refresh data with the latest state
+ for _, rl := range resourceLocation.Items {
+ if strings.EqualFold(rl.GetName(), data.Name.ValueString()) {
+ matchedResourceLocation = &rl
+ break
+ }
+ }
+
+ if matchedResourceLocation == nil {
+ resp.Diagnostics.AddError(
+ "Error reading Resource Location",
+ "Resource location with name "+data.Name.ValueString()+" was not found",
+ )
+ return
+ }
+
+ data = data.RefreshPropertyValues(matchedResourceLocation)
+ // Save data into Terraform state
+ resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
+}
diff --git a/internal/citrixcloud/resource_locations/resource_locations_data_source_model.go b/internal/citrixcloud/resource_locations/resource_locations_data_source_model.go
new file mode 100644
index 0000000..542340f
--- /dev/null
+++ b/internal/citrixcloud/resource_locations/resource_locations_data_source_model.go
@@ -0,0 +1,39 @@
+// Copyright © 2024. Citrix Systems, Inc.
+
+package resource_locations
+
+import (
+ ccresourcelocations "github.com/citrix/citrix-daas-rest-go/ccresourcelocations"
+ "github.com/hashicorp/terraform-plugin-framework/datasource/schema"
+ "github.com/hashicorp/terraform-plugin-framework/types"
+)
+
+type ResourceLocationsDataSourceModel struct {
+ Id types.String `tfsdk:"id"`
+ Name types.String `tfsdk:"name"`
+}
+
+func (ResourceLocationsDataSourceModel) GetSchema() schema.Schema {
+ return schema.Schema{
+ Description: "Citrix Cloud --- Read data of an existing resource location.",
+
+ Attributes: map[string]schema.Attribute{
+ "id": schema.StringAttribute{
+ Description: "ID of the resource location.",
+ Computed: true,
+ },
+ "name": schema.StringAttribute{
+ Description: "Name of the resource location.",
+ Required: true,
+ },
+ },
+ }
+}
+
+func (r ResourceLocationsDataSourceModel) RefreshPropertyValues(ccResourceLocation *ccresourcelocations.CitrixCloudServicesRegistryApiModelsLocationsResourceLocationModel) ResourceLocationsDataSourceModel {
+ // Overwrite resource location with refreshed state
+ r.Id = types.StringValue(ccResourceLocation.GetId())
+ r.Name = types.StringValue(ccResourceLocation.GetName())
+
+ return r
+}
diff --git a/internal/daas/admin_folder/admin_folder_data_source.go b/internal/daas/admin_folder/admin_folder_data_source.go
index c7f1f8d..d9e81e0 100644
--- a/internal/daas/admin_folder/admin_folder_data_source.go
+++ b/internal/daas/admin_folder/admin_folder_data_source.go
@@ -63,7 +63,7 @@ func (d *AdminFolderDataSource) Read(ctx context.Context, req datasource.ReadReq
adminFolderIdOrPath = data.Id.ValueString()
}
if data.Path.ValueString() != "" {
- adminFolderIdOrPath = data.Path.ValueString()
+ adminFolderIdOrPath = data.Path.ValueString() + "\\"
adminFolderIdOrPath = strings.ReplaceAll(adminFolderIdOrPath, "\\", "|")
}
diff --git a/internal/daas/admin_folder/admin_folder_data_source_model.go b/internal/daas/admin_folder/admin_folder_data_source_model.go
index 9fddb91..77ff99e 100644
--- a/internal/daas/admin_folder/admin_folder_data_source_model.go
+++ b/internal/daas/admin_folder/admin_folder_data_source_model.go
@@ -3,6 +3,7 @@ package admin_folder
import (
"context"
+ "regexp"
"strings"
citrixorchestration "github.com/citrix/citrix-daas-rest-go/citrixorchestration"
@@ -43,6 +44,10 @@ func (AdminFolderDataSourceModel) GetSchema() schema.Schema {
"path": schema.StringAttribute{
Description: "Path to the admin folder.",
Optional: true,
+ Validators: []validator.String{
+ stringvalidator.RegexMatches(regexp.MustCompile(util.AdminFolderPathWithBackslashRegex), "Admin Folder Path must not start or end with a backslash"),
+ stringvalidator.RegexMatches(regexp.MustCompile(util.AdminFolderPathSpecialCharactersRegex), "Admin Folder Path must not contain any of the following special characters: / ; : # . * ? = < > | [ ] ( ) { } \" ' ` ~ "),
+ },
},
"name": schema.StringAttribute{
Description: "Name of the admin folder.",
@@ -82,7 +87,7 @@ func (r AdminFolderDataSourceModel) RefreshPropertyValues(ctx context.Context, d
r.Id = types.StringValue(adminFolder.GetId())
r.Name = types.StringValue(adminFolder.GetName())
- r.Path = types.StringValue(adminFolder.GetPath())
+ r.Path = types.StringValue(strings.TrimSuffix(adminFolder.GetPath(), "\\"))
adminFolderTypes := []string{}
adminFolderMetadata := adminFolder.GetMetadata()
@@ -94,6 +99,7 @@ func (r AdminFolderDataSourceModel) RefreshPropertyValues(ctx context.Context, d
r.Type = adminFolderTypeSet
var parentPath = strings.TrimSuffix(adminFolder.GetPath(), adminFolder.GetName()+"\\")
+ parentPath = strings.TrimSuffix(parentPath, "\\")
if parentPath != "" {
r.ParentPath = types.StringValue(parentPath)
} else {
diff --git a/internal/daas/admin_folder/admin_folder_resource.go b/internal/daas/admin_folder/admin_folder_resource.go
index dbd964f..2e59b4a 100644
--- a/internal/daas/admin_folder/admin_folder_resource.go
+++ b/internal/daas/admin_folder/admin_folder_resource.go
@@ -70,7 +70,11 @@ func (r *adminFolderResource) Create(ctx context.Context, req resource.CreateReq
// Generate API request body from plan
var createAdminFolderRequest citrixorchestration.CreateAdminFolderRequestModel
createAdminFolderRequest.SetName(plan.Name.ValueString())
- createAdminFolderRequest.SetPath(plan.ParentPath.ValueString())
+ parentPath := plan.ParentPath.ValueString()
+ if parentPath != "" {
+ parentPath = parentPath + "\\"
+ }
+ createAdminFolderRequest.SetPath(parentPath)
adminFolderTypesArray, err := getAdminFolderObjectIdentifierArrayFromTypeSet(ctx, &resp.Diagnostics, plan.Name.ValueString(), plan.Type)
if err != nil {
@@ -155,7 +159,7 @@ func (r *adminFolderResource) Update(ctx context.Context, req resource.UpdateReq
editAdminFolderRequestBody.SetName(plan.Name.ValueString())
var parentPath = strings.TrimSuffix(adminFolderResource.GetPath(), adminFolderResource.GetName()+"\\")
- if plan.ParentPath.ValueString() != parentPath {
+ if plan.ParentPath.ValueString() != strings.TrimSuffix(parentPath, "\\") {
editAdminFolderRequestBody.SetParent(plan.ParentPath.ValueString())
}
diff --git a/internal/daas/admin_folder/admin_folder_resource_model.go b/internal/daas/admin_folder/admin_folder_resource_model.go
index 260fcc3..e26ee4a 100644
--- a/internal/daas/admin_folder/admin_folder_resource_model.go
+++ b/internal/daas/admin_folder/admin_folder_resource_model.go
@@ -3,6 +3,7 @@ package admin_folder
import (
"context"
+ "regexp"
"strings"
citrixorchestration "github.com/citrix/citrix-daas-rest-go/citrixorchestration"
@@ -43,6 +44,10 @@ func (AdminFolderResourceModel) GetSchema() schema.Schema {
"parent_path": schema.StringAttribute{
Description: "Path of the parent admin folder.",
Optional: true,
+ Validators: []validator.String{
+ stringvalidator.RegexMatches(regexp.MustCompile(util.AdminFolderPathWithBackslashRegex), "Admin Folder Path must not start or end with a backslash"),
+ stringvalidator.RegexMatches(regexp.MustCompile(util.AdminFolderPathSpecialCharactersRegex), "Admin Folder Path must not contain any of the following special characters: / ; : # . * ? = < > | [ ] ( ) { } \" ' ` ~ "),
+ },
},
"type": schema.SetAttribute{
ElementType: types.StringType,
@@ -65,6 +70,9 @@ func (AdminFolderResourceModel) GetSchema() schema.Schema {
"path": schema.StringAttribute{
Description: "Path to the admin folder.",
Computed: true,
+ PlanModifiers: []planmodifier.String{
+ stringplanmodifier.UseStateForUnknown(),
+ },
},
},
}
@@ -80,7 +88,7 @@ func (r AdminFolderResourceModel) RefreshPropertyValues(ctx context.Context, dia
r.Name = types.StringValue(adminFolder.GetName())
// Set optional values
- r.Path = types.StringValue(adminFolder.GetPath())
+ r.Path = types.StringValue(strings.TrimSuffix(adminFolder.GetPath(), "\\"))
adminFolderTypes := []string{}
adminFolderMetadata := adminFolder.GetMetadata()
@@ -92,6 +100,7 @@ func (r AdminFolderResourceModel) RefreshPropertyValues(ctx context.Context, dia
r.Type = adminFolderTypeSet
var parentPath = strings.TrimSuffix(adminFolder.GetPath(), adminFolder.GetName()+"\\")
+ parentPath = strings.TrimSuffix(parentPath, "\\")
if parentPath != "" {
r.ParentPath = types.StringValue(parentPath)
} else {
diff --git a/internal/daas/admin_role/admin_role_resource_model.go b/internal/daas/admin_role/admin_role_resource_model.go
index b09bb38..082c1fa 100644
--- a/internal/daas/admin_role/admin_role_resource_model.go
+++ b/internal/daas/admin_role/admin_role_resource_model.go
@@ -12,6 +12,7 @@ import (
"github.com/hashicorp/terraform-plugin-framework/diag"
"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/planmodifier"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
@@ -75,6 +76,9 @@ func (AdminRoleResourceModel) GetSchema() schema.Schema {
"is_built_in": schema.BoolAttribute{
Description: "Flag to determine if the role was built-in or user defined",
Computed: true,
+ PlanModifiers: []planmodifier.Bool{
+ boolplanmodifier.UseStateForUnknown(),
+ },
},
"can_launch_manage": schema.BoolAttribute{
Description: "Flag to determine if the user will have access to the Manage tab on the console. Defaults to `true`. " +
diff --git a/internal/daas/application/application_group_resource.go b/internal/daas/application/application_group_resource.go
index 00b8840..df90124 100644
--- a/internal/daas/application/application_group_resource.go
+++ b/internal/daas/application/application_group_resource.go
@@ -197,6 +197,14 @@ func (r *applicationGroupResource) Update(ctx context.Context, req resource.Upda
return
}
+ // Get current state
+ var state ApplicationGroupResourceModel
+ diags = req.State.Get(ctx, &state)
+ resp.Diagnostics.Append(diags...)
+ if resp.Diagnostics.HasError() {
+ return
+ }
+
applicationGroupId := plan.Id.ValueString()
applicationGroupName := plan.Name.ValueString()
@@ -239,7 +247,7 @@ func (r *applicationGroupResource) Update(ctx context.Context, req resource.Upda
editApplicationGroupRequestBody.SetAdminFolder(plan.ApplicationGroupFolderPath.ValueString())
- metadata := util.GetMetadataRequestModel(ctx, &resp.Diagnostics, util.ObjectListToTypedArray[util.NameValueStringPairModel](ctx, &resp.Diagnostics, plan.Metadata))
+ metadata := util.GetUpdatedMetadataRequestModel(ctx, &resp.Diagnostics, util.ObjectListToTypedArray[util.NameValueStringPairModel](ctx, &resp.Diagnostics, state.Metadata), util.ObjectListToTypedArray[util.NameValueStringPairModel](ctx, &resp.Diagnostics, plan.Metadata))
editApplicationGroupRequestBody.SetMetadata(metadata)
// Update Application
@@ -397,6 +405,7 @@ func setApplicationGroupTags(ctx context.Context, diagnostics *diag.Diagnostics,
func getApplicationGroupTags(ctx context.Context, diagnostics *diag.Diagnostics, client *citrixdaasclient.CitrixDaasClient, applicationGroupId string) []string {
getTagsRequest := client.ApiClient.ApplicationGroupsAPIsDAAS.ApplicationGroupsGetApplicationGroupTags(ctx, applicationGroupId)
+ getTagsRequest = getTagsRequest.Fields("Id,Name,Description")
tagsResp, httpResp, err := citrixdaasclient.AddRequestData(getTagsRequest, client).Execute()
return util.ProcessTagsResponseCollection(diagnostics, tagsResp, httpResp, err, "Application Group", applicationGroupId)
}
diff --git a/internal/daas/application/application_group_resource_model.go b/internal/daas/application/application_group_resource_model.go
index 4fa6538..64e8799 100644
--- a/internal/daas/application/application_group_resource_model.go
+++ b/internal/daas/application/application_group_resource_model.go
@@ -5,6 +5,7 @@ package application
import (
"context"
"regexp"
+ "strings"
citrixorchestration "github.com/citrix/citrix-daas-rest-go/citrixorchestration"
citrixdaasclient "github.com/citrix/citrix-daas-rest-go/client"
@@ -19,6 +20,7 @@ import (
"github.com/hashicorp/terraform-plugin-framework/resource/schema"
"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/setplanmodifier"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
)
@@ -108,6 +110,9 @@ func (ApplicationGroupResourceModel) GetSchema() schema.Schema {
ElementType: types.StringType,
Description: "The IDs of the built-in scopes of the application group.",
Computed: true,
+ PlanModifiers: []planmodifier.Set{
+ setplanmodifier.UseStateForUnknown(),
+ },
},
"inherited_scopes": schema.SetAttribute{
ElementType: types.StringType,
@@ -117,6 +122,10 @@ func (ApplicationGroupResourceModel) GetSchema() schema.Schema {
"application_group_folder_path": schema.StringAttribute{
Description: "The path of the folder in which the application group is located.",
Optional: true,
+ Validators: []validator.String{
+ stringvalidator.RegexMatches(regexp.MustCompile(util.AdminFolderPathWithBackslashRegex), "Admin Folder Path must not start or end with a backslash"),
+ stringvalidator.RegexMatches(regexp.MustCompile(util.AdminFolderPathSpecialCharactersRegex), "Admin Folder Path must not contain any of the following special characters: / ; : # . * ? = < > | [ ] ( ) { } \" ' ` ~ "),
+ },
},
"tenants": schema.SetAttribute{
ElementType: types.StringType,
@@ -185,7 +194,7 @@ func (r ApplicationGroupResourceModel) RefreshPropertyValues(ctx context.Context
r.InheritedScopes = util.StringArrayToStringSet(ctx, diagnostics, inheritedScopeIds)
adminFolder := applicationGroup.GetAdminFolder()
- adminFolderPath := adminFolder.GetName()
+ adminFolderPath := strings.TrimSuffix(adminFolder.GetName(), "\\")
if adminFolderPath != "" {
r.ApplicationGroupFolderPath = types.StringValue(adminFolderPath)
} else {
diff --git a/internal/daas/application/application_resource.go b/internal/daas/application/application_resource.go
index 6d7cdd1..71ad1a1 100644
--- a/internal/daas/application/application_resource.go
+++ b/internal/daas/application/application_resource.go
@@ -138,7 +138,7 @@ func (r *applicationResource) Create(ctx context.Context, req resource.CreateReq
// If the application is present in an application folder, we specify the name in this format: {application folder path plus application name}.For example, FolderName1|FolderName2|ApplicationName.
if plan.ApplicationFolderPath.ValueString() != "" {
- applicationName = strings.ReplaceAll(plan.ApplicationFolderPath.ValueString(), "\\", "|") + applicationName
+ applicationName = strings.ReplaceAll(plan.ApplicationFolderPath.ValueString(), "\\", "|") + "|" + applicationName
}
application, err := getApplication(ctx, r.client, &resp.Diagnostics, applicationName)
@@ -211,6 +211,14 @@ func (r *applicationResource) Update(ctx context.Context, req resource.UpdateReq
return
}
+ // Get current state
+ var state ApplicationResourceModel
+ diags = req.State.Get(ctx, &state)
+ resp.Diagnostics.Append(diags...)
+ if resp.Diagnostics.HasError() {
+ return
+ }
+
applicationId := plan.Id.ValueString()
applicationName := plan.Name.ValueString()
@@ -256,7 +264,7 @@ func (r *applicationResource) Update(ctx context.Context, req resource.UpdateReq
return
}
- metadata := util.GetMetadataRequestModel(ctx, &resp.Diagnostics, util.ObjectListToTypedArray[util.NameValueStringPairModel](ctx, &resp.Diagnostics, plan.Metadata))
+ metadata := util.GetUpdatedMetadataRequestModel(ctx, &resp.Diagnostics, util.ObjectListToTypedArray[util.NameValueStringPairModel](ctx, &resp.Diagnostics, state.Metadata), util.ObjectListToTypedArray[util.NameValueStringPairModel](ctx, &resp.Diagnostics, plan.Metadata))
editApplicationRequestBody.SetMetadata(metadata)
// Update Application
@@ -399,7 +407,7 @@ func checkIfApplicationFolderPathExist(ctx context.Context, client *citrixdaascl
return true
}
- tempFolderPath := strings.ReplaceAll(applicationFolderPath, "\\", "|")
+ tempFolderPath := strings.ReplaceAll(applicationFolderPath, "\\", "|") + "|"
appFolderExistRequest := client.ApiClient.ApplicationFoldersAPIsDAAS.ApplicationFoldersCheckApplicationFolderPathExists(ctx, tempFolderPath)
httpResp, err := citrixdaasclient.AddRequestData(appFolderExistRequest, client).Execute()
if err != nil {
@@ -474,6 +482,7 @@ func validateDeliveryGroupsPriority(ctx context.Context, diagnostics *diag.Diagn
func getApplicationTags(ctx context.Context, diagnostics *diag.Diagnostics, client *citrixdaasclient.CitrixDaasClient, applicationId string) []string {
getTagsRequest := client.ApiClient.ApplicationsAPIsDAAS.ApplicationsGetApplicationTags(ctx, applicationId)
+ getTagsRequest = getTagsRequest.Fields("Id,Name,Description")
tagsResp, httpResp, err := citrixdaasclient.AddRequestData(getTagsRequest, client).Execute()
return util.ProcessTagsResponseCollection(diagnostics, tagsResp, httpResp, err, "Application", applicationId)
}
diff --git a/internal/daas/application/application_resource_model.go b/internal/daas/application/application_resource_model.go
index 5c947ae..c7961e4 100644
--- a/internal/daas/application/application_resource_model.go
+++ b/internal/daas/application/application_resource_model.go
@@ -6,6 +6,7 @@ import (
"context"
"regexp"
"sort"
+ "strings"
citrixorchestration "github.com/citrix/citrix-daas-rest-go/citrixorchestration"
"github.com/citrix/terraform-provider-citrix/internal/util"
@@ -166,6 +167,10 @@ func (ApplicationResourceModel) GetSchema() schema.Schema {
"application_folder_path": schema.StringAttribute{
Description: "The application folder path in which the application should be created.",
Optional: true,
+ Validators: []validator.String{
+ stringvalidator.RegexMatches(regexp.MustCompile(util.AdminFolderPathWithBackslashRegex), "Admin Folder Path must not start or end with a backslash"),
+ stringvalidator.RegexMatches(regexp.MustCompile(util.AdminFolderPathSpecialCharactersRegex), "Admin Folder Path must not contain any of the following special characters: / ; : # . * ? = < > | [ ] ( ) { } \" ' ` ~ "),
+ },
},
"icon": schema.StringAttribute{
Description: "The Id of the icon to be associated with the application.",
@@ -229,8 +234,10 @@ func (r ApplicationResourceModel) RefreshPropertyValues(ctx context.Context, dia
r.ApplicationCategoryPath = types.StringValue(application.GetClientFolder())
// Set optional values
- if *application.GetApplicationFolder().Name.Get() != "" {
- r.ApplicationFolderPath = types.StringValue(*application.GetApplicationFolder().Name.Get())
+ adminFolder := application.GetApplicationFolder()
+ adminFolderPath := strings.TrimSuffix(adminFolder.GetName(), "\\")
+ if adminFolderPath != "" {
+ r.ApplicationFolderPath = types.StringValue(adminFolderPath)
} else {
r.ApplicationFolderPath = types.StringNull()
}
diff --git a/internal/daas/delivery_group/delivery_group_data_source.go b/internal/daas/delivery_group/delivery_group_data_source.go
index 7051ad3..4061788 100644
--- a/internal/daas/delivery_group/delivery_group_data_source.go
+++ b/internal/daas/delivery_group/delivery_group_data_source.go
@@ -4,6 +4,7 @@ package delivery_group
import (
"context"
+ "strings"
citrixdaasclient "github.com/citrix/citrix-daas-rest-go/client"
"github.com/citrix/terraform-provider-citrix/internal/util"
@@ -61,7 +62,13 @@ func (d *DeliveryGroupDataSource) Read(ctx context.Context, req datasource.ReadR
// Get refreshed delivery group state from Orchestration
deliveryGroupName := data.Name.ValueString()
- getDeliveryGroupRequest := d.client.ApiClient.DeliveryGroupsAPIsDAAS.DeliveryGroupsGetDeliveryGroup(ctx, deliveryGroupName)
+ deliveryGroupPath := strings.ReplaceAll(data.DeliveryGroupFolderPath.ValueString(), "\\", "|")
+ if deliveryGroupPath != "" {
+ deliveryGroupPath = deliveryGroupPath + "|" + deliveryGroupName
+ } else {
+ deliveryGroupPath = deliveryGroupName
+ }
+ getDeliveryGroupRequest := d.client.ApiClient.DeliveryGroupsAPIsDAAS.DeliveryGroupsGetDeliveryGroup(ctx, deliveryGroupPath)
deliveryGroup, httpResp, err := citrixdaasclient.AddRequestData(getDeliveryGroupRequest, d.client).Execute()
if err != nil {
resp.Diagnostics.AddError(
diff --git a/internal/daas/delivery_group/delivery_group_data_source_model.go b/internal/daas/delivery_group/delivery_group_data_source_model.go
index 4577ccd..d6b2ab4 100644
--- a/internal/daas/delivery_group/delivery_group_data_source_model.go
+++ b/internal/daas/delivery_group/delivery_group_data_source_model.go
@@ -4,12 +4,16 @@ package delivery_group
import (
"context"
+ "regexp"
+ "strings"
"github.com/citrix/citrix-daas-rest-go/citrixorchestration"
"github.com/citrix/terraform-provider-citrix/internal/daas/vda"
"github.com/citrix/terraform-provider-citrix/internal/util"
+ "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
"github.com/hashicorp/terraform-plugin-framework/datasource/schema"
"github.com/hashicorp/terraform-plugin-framework/diag"
+ "github.com/hashicorp/terraform-plugin-framework/schema/validator"
"github.com/hashicorp/terraform-plugin-framework/types"
)
@@ -38,6 +42,10 @@ func (DeliveryGroupDataSourceModel) GetSchema() schema.Schema {
"delivery_group_folder_path": schema.StringAttribute{
Description: "The path to the folder in which the delivery group is located.",
Optional: true,
+ Validators: []validator.String{
+ stringvalidator.RegexMatches(regexp.MustCompile(util.AdminFolderPathWithBackslashRegex), "Admin Folder Path must not start or end with a backslash"),
+ stringvalidator.RegexMatches(regexp.MustCompile(util.AdminFolderPathSpecialCharactersRegex), "Admin Folder Path must not contain any of the following special characters: / ; : # . * ? = < > | [ ] ( ) { } \" ' ` ~ "),
+ },
},
"vdas": schema.ListNestedAttribute{
Description: "The VDAs associated with the delivery group.",
@@ -63,7 +71,7 @@ func (r DeliveryGroupDataSourceModel) RefreshPropertyValues(ctx context.Context,
r.Name = types.StringValue(deliveryGroup.GetName())
adminFolder := deliveryGroup.GetAdminFolder()
- adminFolderPath := adminFolder.GetName()
+ adminFolderPath := strings.TrimSuffix(adminFolder.GetName(), "\\")
if adminFolderPath != "" {
r.DeliveryGroupFolderPath = types.StringValue(adminFolderPath)
} else {
diff --git a/internal/daas/delivery_group/delivery_group_resource.go b/internal/daas/delivery_group/delivery_group_resource.go
index 2e28d03..f13b674 100644
--- a/internal/daas/delivery_group/delivery_group_resource.go
+++ b/internal/daas/delivery_group/delivery_group_resource.go
@@ -349,6 +349,14 @@ func (r *deliveryGroupResource) Update(ctx context.Context, req resource.UpdateR
return
}
+ // Get State to check the diff for metadata
+ var state DeliveryGroupResourceModel
+ diags = req.State.Get(ctx, &state)
+ resp.Diagnostics.Append(diags...)
+ if resp.Diagnostics.HasError() {
+ return
+ }
+
// Get refreshed delivery group properties from Orchestration
deliveryGroupId := plan.Id.ValueString()
deliveryGroupName := plan.Name.ValueString()
@@ -357,7 +365,7 @@ func (r *deliveryGroupResource) Update(ctx context.Context, req resource.UpdateR
return
}
- editDeliveryGroupRequestBody, err := getRequestModelForDeliveryGroupUpdate(ctx, &resp.Diagnostics, r.client, plan, currentDeliveryGroup)
+ editDeliveryGroupRequestBody, err := getRequestModelForDeliveryGroupUpdate(ctx, &resp.Diagnostics, r.client, plan, state, currentDeliveryGroup)
if err != nil {
return
}
diff --git a/internal/daas/delivery_group/delivery_group_resource_model.go b/internal/daas/delivery_group/delivery_group_resource_model.go
index 190e957..358ab04 100644
--- a/internal/daas/delivery_group/delivery_group_resource_model.go
+++ b/internal/daas/delivery_group/delivery_group_resource_model.go
@@ -26,6 +26,7 @@ import (
"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/setdefault"
+ "github.com/hashicorp/terraform-plugin-framework/resource/schema/setplanmodifier"
"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"
@@ -239,8 +240,11 @@ func (DeliveryGroupRebootSchedule) GetSchema() schema.NestedAttributeObject {
Required: true,
},
"restrict_to_tag": schema.StringAttribute{
- Description: "The tag to which the reboot schedule is restricted.",
+ Description: "Restrict reboot schedule to machines with tag specified in Guid.",
Optional: true,
+ Validators: []validator.String{
+ stringvalidator.RegexMatches(regexp.MustCompile(util.GuidRegex), "must be specified with ID in GUID format"),
+ },
},
"ignore_maintenance_mode": schema.BoolAttribute{
Description: "Whether the reboot schedule ignores machines in the maintenance mode.",
@@ -624,6 +628,7 @@ var _ util.RefreshableListItemWithAttributes[citrixorchestration.DesktopResponse
type DeliveryGroupDesktop struct {
PublishedName types.String `tfsdk:"published_name"`
DesktopDescription types.String `tfsdk:"description"`
+ RestrictToTag types.String `tfsdk:"restrict_to_tag"`
Enabled types.Bool `tfsdk:"enabled"`
EnableSessionRoaming types.Bool `tfsdk:"enable_session_roaming"`
RestrictedAccessUsers types.Object `tfsdk:"restricted_access_users"` //RestrictedAccessUsers
@@ -647,6 +652,13 @@ func (DeliveryGroupDesktop) GetSchema() schema.NestedAttributeObject {
Computed: true,
Default: stringdefault.StaticString(""),
},
+ "restrict_to_tag": schema.StringAttribute{
+ Description: "Restrict session launch to machines with tag specified in GUID.",
+ Optional: true,
+ Validators: []validator.String{
+ stringvalidator.RegexMatches(regexp.MustCompile(util.GuidRegex), "must be specified with ID in GUID format"),
+ },
+ },
"enabled": schema.BoolAttribute{
Description: "Specify whether to enable the delivery of this desktop. Default is `true`.",
Optional: true,
@@ -1043,6 +1055,9 @@ func (DeliveryGroupResourceModel) GetSchema() schema.Schema {
ElementType: types.StringType,
Description: "The IDs of the built-in scopes of the delivery group.",
Computed: true,
+ PlanModifiers: []planmodifier.Set{
+ setplanmodifier.UseStateForUnknown(),
+ },
},
"inherited_scopes": schema.SetAttribute{
ElementType: types.StringType,
@@ -1095,6 +1110,10 @@ func (DeliveryGroupResourceModel) GetSchema() schema.Schema {
"delivery_group_folder_path": schema.StringAttribute{
Description: "The path of the folder in which the delivery group is located.",
Optional: true,
+ Validators: []validator.String{
+ stringvalidator.RegexMatches(regexp.MustCompile(util.AdminFolderPathWithBackslashRegex), "Admin Folder Path must not start or end with a backslash"),
+ stringvalidator.RegexMatches(regexp.MustCompile(util.AdminFolderPathSpecialCharactersRegex), "Admin Folder Path must not contain any of the following special characters: / ; : # . * ? = < > | [ ] ( ) { } \" ' ` ~ "),
+ },
},
"tenants": schema.SetAttribute{
ElementType: types.StringType,
@@ -1186,7 +1205,7 @@ func (r DeliveryGroupResourceModel) RefreshPropertyValues(ctx context.Context, d
}
adminFolder := deliveryGroup.GetAdminFolder()
- adminFolderPath := adminFolder.GetName()
+ adminFolderPath := strings.TrimSuffix(adminFolder.GetName(), "\\")
if adminFolderPath != "" {
r.DeliveryGroupFolderPath = types.StringValue(adminFolderPath)
} else {
diff --git a/internal/daas/delivery_group/delivery_group_utils.go b/internal/daas/delivery_group/delivery_group_utils.go
index 1238f6a..1770386 100644
--- a/internal/daas/delivery_group/delivery_group_utils.go
+++ b/internal/daas/delivery_group/delivery_group_utils.go
@@ -778,7 +778,7 @@ func getRequestModelForDeliveryGroupCreate(ctx context.Context, diagnostics *dia
return body, nil
}
-func getRequestModelForDeliveryGroupUpdate(ctx context.Context, diagnostics *diag.Diagnostics, client *citrixdaasclient.CitrixDaasClient, plan DeliveryGroupResourceModel, currentDeliveryGroup *citrixorchestration.DeliveryGroupDetailResponseModel) (citrixorchestration.EditDeliveryGroupRequestModel, error) {
+func getRequestModelForDeliveryGroupUpdate(ctx context.Context, diagnostics *diag.Diagnostics, client *citrixdaasclient.CitrixDaasClient, plan DeliveryGroupResourceModel, state DeliveryGroupResourceModel, currentDeliveryGroup *citrixorchestration.DeliveryGroupDetailResponseModel) (citrixorchestration.EditDeliveryGroupRequestModel, error) {
desktops := util.ObjectListToTypedArray[DeliveryGroupDesktop](ctx, diagnostics, plan.Desktops)
deliveryGroupDesktopsArray, err := verifyUsersAndParseDeliveryGroupDesktopsToClientModel(ctx, diagnostics, client, desktops)
if err != nil {
@@ -992,7 +992,7 @@ func getRequestModelForDeliveryGroupUpdate(ctx context.Context, diagnostics *dia
editDeliveryGroupRequestBody.SetAdminFolder(plan.DeliveryGroupFolderPath.ValueString())
- metadata := util.GetMetadataRequestModel(ctx, diagnostics, util.ObjectListToTypedArray[util.NameValueStringPairModel](ctx, diagnostics, plan.Metadata))
+ metadata := util.GetUpdatedMetadataRequestModel(ctx, diagnostics, util.ObjectListToTypedArray[util.NameValueStringPairModel](ctx, diagnostics, state.Metadata), util.ObjectListToTypedArray[util.NameValueStringPairModel](ctx, diagnostics, plan.Metadata))
editDeliveryGroupRequestBody.SetMetadata(metadata)
return editDeliveryGroupRequestBody, nil
@@ -1173,6 +1173,13 @@ func (dgDesktop DeliveryGroupDesktop) RefreshListItem(ctx context.Context, diagn
dgDesktop.PublishedName = types.StringValue(desktop.GetPublishedName())
dgDesktop.DesktopDescription = types.StringValue(desktop.GetDescription())
+ if desktop.RestrictToTag != nil {
+ restrictToTag := desktop.GetRestrictToTag()
+ dgDesktop.RestrictToTag = types.StringValue(restrictToTag.GetId())
+ } else {
+ dgDesktop.RestrictToTag = types.StringNull()
+ }
+
dgDesktop.Enabled = types.BoolValue(desktop.GetEnabled())
sessionReconnection := desktop.GetSessionReconnection()
if sessionReconnection == citrixorchestration.SESSIONRECONNECTION_ALWAYS {
@@ -1380,6 +1387,21 @@ func verifyUsersAndParseDeliveryGroupDesktopsToClientModel(ctx context.Context,
}
}
+ if !deliveryGroupDesktop.RestrictToTag.IsNull() {
+ tagId := deliveryGroupDesktop.RestrictToTag.ValueString()
+ getTagRequest := client.ApiClient.TagsAPIsDAAS.TagsGetTag(ctx, tagId)
+ tag, httpResp, err := citrixdaasclient.AddRequestData(getTagRequest, client).Execute()
+ if err != nil {
+ diagnostics.AddError(
+ "Error fetching tag for delivery group desktop",
+ "TransactionId: "+citrixdaasclient.GetTransactionIdFromHttpResponse(httpResp)+
+ "\nError message: "+util.ReadClientError(err),
+ )
+ return desktopRequests, err
+ }
+
+ desktopRequest.SetRestrictToTag(tag.GetName())
+ }
desktopRequest.SetIncludedUserFilterEnabled(includedUsersFilterEnabled)
desktopRequest.SetExcludedUserFilterEnabled(excludedUsersFilterEnabled)
desktopRequest.SetIncludedUsers(includedUserIds)
@@ -2027,6 +2049,7 @@ func setDeliveryGroupTags(ctx context.Context, diagnostics *diag.Diagnostics, cl
func getDeliveryGroupTags(ctx context.Context, diagnostics *diag.Diagnostics, client *citrixdaasclient.CitrixDaasClient, deliveryGroupId string) []string {
getTagsRequest := client.ApiClient.DeliveryGroupsAPIsDAAS.DeliveryGroupsGetDeliveryGroupTags(ctx, deliveryGroupId)
+ getTagsRequest = getTagsRequest.Fields("Id,Name,Description")
tagsResp, httpResp, err := citrixdaasclient.AddRequestData(getTagsRequest, client).Execute()
return util.ProcessTagsResponseCollection(diagnostics, tagsResp, httpResp, err, "Delivery Group", deliveryGroupId)
}
diff --git a/internal/daas/hypervisor/aws_hypervisor_resource.go b/internal/daas/hypervisor/aws_hypervisor_resource.go
index a2c1d9f..7925c85 100644
--- a/internal/daas/hypervisor/aws_hypervisor_resource.go
+++ b/internal/daas/hypervisor/aws_hypervisor_resource.go
@@ -159,6 +159,14 @@ func (r *awsHypervisorResource) Update(ctx context.Context, req resource.UpdateR
return
}
+ // Get current state
+ var state AwsHypervisorResourceModel
+ diags = req.State.Get(ctx, &state)
+ resp.Diagnostics.Append(diags...)
+ if resp.Diagnostics.HasError() {
+ return
+ }
+
// Construct the update model
var editHypervisorRequestBody citrixorchestration.EditHypervisorConnectionRequestModel
editHypervisorRequestBody.SetName(plan.Name.ValueString())
@@ -169,7 +177,7 @@ func (r *awsHypervisorResource) Update(ctx context.Context, req resource.UpdateR
editHypervisorRequestBody.SetScopes(util.StringSetToStringArray(ctx, &resp.Diagnostics, plan.Scopes))
}
- metadata := util.GetMetadataRequestModel(ctx, &resp.Diagnostics, util.ObjectListToTypedArray[util.NameValueStringPairModel](ctx, &resp.Diagnostics, plan.Metadata))
+ metadata := util.GetUpdatedMetadataRequestModel(ctx, &resp.Diagnostics, util.ObjectListToTypedArray[util.NameValueStringPairModel](ctx, &resp.Diagnostics, state.Metadata), util.ObjectListToTypedArray[util.NameValueStringPairModel](ctx, &resp.Diagnostics, plan.Metadata))
editHypervisorRequestBody.SetMetadata(metadata)
// Patch hypervisor
diff --git a/internal/daas/hypervisor/azure_hypervisor_resource.go b/internal/daas/hypervisor/azure_hypervisor_resource.go
index 6eeb723..260a790 100644
--- a/internal/daas/hypervisor/azure_hypervisor_resource.go
+++ b/internal/daas/hypervisor/azure_hypervisor_resource.go
@@ -175,6 +175,14 @@ func (r *azureHypervisorResource) Update(ctx context.Context, req resource.Updat
return
}
+ // Get current state
+ var state AzureHypervisorResourceModel
+ diags = req.State.Get(ctx, &state)
+ resp.Diagnostics.Append(diags...)
+ if resp.Diagnostics.HasError() {
+ return
+ }
+
// Construct the update model
var editHypervisorRequestBody citrixorchestration.EditHypervisorConnectionRequestModel
editHypervisorRequestBody.SetName(plan.Name.ValueString())
@@ -182,7 +190,7 @@ func (r *azureHypervisorResource) Update(ctx context.Context, req resource.Updat
editHypervisorRequestBody.SetApplicationId(plan.ApplicationId.ValueString())
editHypervisorRequestBody.SetApplicationSecret(plan.ApplicationSecret.ValueString())
metadata := getMetadataForAzureRmHypervisor(plan)
- additionalMetadata := util.GetMetadataRequestModel(ctx, &resp.Diagnostics, util.ObjectListToTypedArray[util.NameValueStringPairModel](ctx, &resp.Diagnostics, plan.Metadata))
+ additionalMetadata := util.GetUpdatedMetadataRequestModel(ctx, &resp.Diagnostics, util.ObjectListToTypedArray[util.NameValueStringPairModel](ctx, &resp.Diagnostics, state.Metadata), util.ObjectListToTypedArray[util.NameValueStringPairModel](ctx, &resp.Diagnostics, plan.Metadata))
metadata = append(metadata, additionalMetadata...)
editHypervisorRequestBody.SetMetadata(metadata)
if !plan.Scopes.IsNull() {
diff --git a/internal/daas/hypervisor/azure_hypervisor_resource_model.go b/internal/daas/hypervisor/azure_hypervisor_resource_model.go
index a9ca200..4443a2d 100644
--- a/internal/daas/hypervisor/azure_hypervisor_resource_model.go
+++ b/internal/daas/hypervisor/azure_hypervisor_resource_model.go
@@ -32,6 +32,7 @@ type AzureHypervisorResourceModel struct {
Zone types.String `tfsdk:"zone"`
Scopes types.Set `tfsdk:"scopes"` // Set[string]
Metadata types.List `tfsdk:"metadata"` // List[NameValueStringPairModel]
+ Tenants types.Set `tfsdk:"tenants"` // Set[string]
/** Azure Connection **/
ApplicationId types.String `tfsdk:"application_id"`
ApplicationSecret types.String `tfsdk:"application_secret"`
@@ -118,6 +119,11 @@ func (AzureHypervisorResourceModel) GetSchema() schema.Schema {
},
},
"metadata": util.GetMetadataListSchema("Hypervisor"),
+ "tenants": schema.SetAttribute{
+ ElementType: types.StringType,
+ Description: "A set of identifiers of tenants to associate with the hypervisor connection.",
+ Computed: true,
+ },
},
}
}
@@ -146,6 +152,8 @@ func (r AzureHypervisorResourceModel) RefreshPropertyValues(ctx context.Context,
r.Metadata = util.TypedArrayToObjectList[util.NameValueStringPairModel](ctx, diagnostics, nil)
}
+ r.Tenants = util.RefreshTenantSet(ctx, diagnostics, hypervisor.GetTenants())
+
customPropertiesString := hypervisor.GetCustomProperties()
var customProperties []citrixorchestration.NameValueStringPairModel
err := json.Unmarshal([]byte(customPropertiesString), &customProperties)
diff --git a/internal/daas/hypervisor/gcp_hypervisor_resource.go b/internal/daas/hypervisor/gcp_hypervisor_resource.go
index 75dca40..6262c14 100644
--- a/internal/daas/hypervisor/gcp_hypervisor_resource.go
+++ b/internal/daas/hypervisor/gcp_hypervisor_resource.go
@@ -159,6 +159,14 @@ func (r *gcpHypervisorResource) Update(ctx context.Context, req resource.UpdateR
return
}
+ // Get current state
+ var state GcpHypervisorResourceModel
+ diags = req.State.Get(ctx, &state)
+ resp.Diagnostics.Append(diags...)
+ if resp.Diagnostics.HasError() {
+ return
+ }
+
// Construct the update model
var editHypervisorRequestBody citrixorchestration.EditHypervisorConnectionRequestModel
editHypervisorRequestBody.SetName(plan.Name.ValueString())
@@ -169,7 +177,7 @@ func (r *gcpHypervisorResource) Update(ctx context.Context, req resource.UpdateR
editHypervisorRequestBody.SetScopes(util.StringSetToStringArray(ctx, &resp.Diagnostics, plan.Scopes))
}
- metadata := util.GetMetadataRequestModel(ctx, &resp.Diagnostics, util.ObjectListToTypedArray[util.NameValueStringPairModel](ctx, &resp.Diagnostics, plan.Metadata))
+ metadata := util.GetUpdatedMetadataRequestModel(ctx, &resp.Diagnostics, util.ObjectListToTypedArray[util.NameValueStringPairModel](ctx, &resp.Diagnostics, state.Metadata), util.ObjectListToTypedArray[util.NameValueStringPairModel](ctx, &resp.Diagnostics, plan.Metadata))
editHypervisorRequestBody.SetMetadata(metadata)
// Patch hypervisor
diff --git a/internal/daas/hypervisor/gcp_hypervisor_resource_model.go b/internal/daas/hypervisor/gcp_hypervisor_resource_model.go
index adf81a1..b16d85d 100644
--- a/internal/daas/hypervisor/gcp_hypervisor_resource_model.go
+++ b/internal/daas/hypervisor/gcp_hypervisor_resource_model.go
@@ -29,6 +29,7 @@ type GcpHypervisorResourceModel struct {
Zone types.String `tfsdk:"zone"`
Scopes types.Set `tfsdk:"scopes"` // Set[string]
Metadata types.List `tfsdk:"metadata"` // List[NameValueStringPairModel]
+ Tenants types.Set `tfsdk:"tenants"` // Set[string]
/** GCP Connection **/
ServiceAccountId types.String `tfsdk:"service_account_id"`
ServiceAccountCredentials types.String `tfsdk:"service_account_credentials"`
@@ -83,6 +84,11 @@ func (GcpHypervisorResourceModel) GetSchema() schema.Schema {
},
},
"metadata": util.GetMetadataListSchema("Hypervisor"),
+ "tenants": schema.SetAttribute{
+ ElementType: types.StringType,
+ Description: "A set of identifiers of tenants to associate with the hypervisor connection.",
+ Computed: true,
+ },
},
}
}
@@ -109,5 +115,7 @@ func (r GcpHypervisorResourceModel) RefreshPropertyValues(ctx context.Context, d
r.Metadata = util.TypedArrayToObjectList[util.NameValueStringPairModel](ctx, diagnostics, nil)
}
+ r.Tenants = util.RefreshTenantSet(ctx, diagnostics, hypervisor.GetTenants())
+
return r
}
diff --git a/internal/daas/hypervisor/nutanix_hypervisor_resource.go b/internal/daas/hypervisor/nutanix_hypervisor_resource.go
index 49c09f2..1112012 100644
--- a/internal/daas/hypervisor/nutanix_hypervisor_resource.go
+++ b/internal/daas/hypervisor/nutanix_hypervisor_resource.go
@@ -167,6 +167,15 @@ func (r *nutanixHypervisorResource) Update(ctx context.Context, req resource.Upd
if resp.Diagnostics.HasError() {
return
}
+
+ // Get current state
+ var state NutanixHypervisorResourceModel
+ diags = req.State.Get(ctx, &state)
+ resp.Diagnostics.Append(diags...)
+ if resp.Diagnostics.HasError() {
+ return
+ }
+
// Construct the update model
var editHypervisorRequestBody citrixorchestration.EditHypervisorConnectionRequestModel
editHypervisorRequestBody.SetName(plan.Name.ValueString())
@@ -192,7 +201,7 @@ func (r *nutanixHypervisorResource) Update(ctx context.Context, req resource.Upd
editHypervisorRequestBody.SetScopes(util.StringSetToStringArray(ctx, &resp.Diagnostics, plan.Scopes))
}
- metadata := util.GetMetadataRequestModel(ctx, &resp.Diagnostics, util.ObjectListToTypedArray[util.NameValueStringPairModel](ctx, &resp.Diagnostics, plan.Metadata))
+ metadata := util.GetUpdatedMetadataRequestModel(ctx, &resp.Diagnostics, util.ObjectListToTypedArray[util.NameValueStringPairModel](ctx, &resp.Diagnostics, state.Metadata), util.ObjectListToTypedArray[util.NameValueStringPairModel](ctx, &resp.Diagnostics, plan.Metadata))
editHypervisorRequestBody.SetMetadata(metadata)
// Patch hypervisor
diff --git a/internal/daas/hypervisor/scvmm_hypervisor_resource.go b/internal/daas/hypervisor/scvmm_hypervisor_resource.go
index 10587de..a35eaff 100644
--- a/internal/daas/hypervisor/scvmm_hypervisor_resource.go
+++ b/internal/daas/hypervisor/scvmm_hypervisor_resource.go
@@ -188,6 +188,14 @@ func (r *scvmmHypervisorResource) Update(ctx context.Context, req resource.Updat
return
}
+ // Get current state
+ var state SCVMMMHypervisorResourceModel
+ diags = req.State.Get(ctx, &state)
+ resp.Diagnostics.Append(diags...)
+ if resp.Diagnostics.HasError() {
+ return
+ }
+
// Construct the update model
var editHypervisorRequestBody citrixorchestration.EditHypervisorConnectionRequestModel
editHypervisorRequestBody.SetName(plan.Name.ValueString())
@@ -213,7 +221,7 @@ func (r *scvmmHypervisorResource) Update(ctx context.Context, req resource.Updat
editHypervisorRequestBody.SetScopes(util.StringSetToStringArray(ctx, &resp.Diagnostics, plan.Scopes))
}
- metadata := util.GetMetadataRequestModel(ctx, &resp.Diagnostics, util.ObjectListToTypedArray[util.NameValueStringPairModel](ctx, &resp.Diagnostics, plan.Metadata))
+ metadata := util.GetUpdatedMetadataRequestModel(ctx, &resp.Diagnostics, util.ObjectListToTypedArray[util.NameValueStringPairModel](ctx, &resp.Diagnostics, state.Metadata), util.ObjectListToTypedArray[util.NameValueStringPairModel](ctx, &resp.Diagnostics, plan.Metadata))
editHypervisorRequestBody.SetMetadata(metadata)
// Patch hypervisor
diff --git a/internal/daas/hypervisor/vsphere_hypervisor_resource.go b/internal/daas/hypervisor/vsphere_hypervisor_resource.go
index d0ea206..9cb5938 100644
--- a/internal/daas/hypervisor/vsphere_hypervisor_resource.go
+++ b/internal/daas/hypervisor/vsphere_hypervisor_resource.go
@@ -172,6 +172,14 @@ func (r *vsphereHypervisorResource) Update(ctx context.Context, req resource.Upd
return
}
+ // Get current state
+ var state VsphereHypervisorResourceModel
+ diags = req.State.Get(ctx, &state)
+ resp.Diagnostics.Append(diags...)
+ if resp.Diagnostics.HasError() {
+ return
+ }
+
// Construct the update model
var editHypervisorRequestBody citrixorchestration.EditHypervisorConnectionRequestModel
editHypervisorRequestBody.SetName(plan.Name.ValueString())
@@ -199,7 +207,7 @@ func (r *vsphereHypervisorResource) Update(ctx context.Context, req resource.Upd
if !plan.Scopes.IsNull() {
editHypervisorRequestBody.SetScopes(util.StringSetToStringArray(ctx, &resp.Diagnostics, plan.Scopes))
}
- metadata := util.GetMetadataRequestModel(ctx, &resp.Diagnostics, util.ObjectListToTypedArray[util.NameValueStringPairModel](ctx, &resp.Diagnostics, plan.Metadata))
+ metadata := util.GetUpdatedMetadataRequestModel(ctx, &resp.Diagnostics, util.ObjectListToTypedArray[util.NameValueStringPairModel](ctx, &resp.Diagnostics, state.Metadata), util.ObjectListToTypedArray[util.NameValueStringPairModel](ctx, &resp.Diagnostics, plan.Metadata))
editHypervisorRequestBody.SetMetadata(metadata)
// Patch hypervisor
diff --git a/internal/daas/hypervisor/xenserver_hypervisor_resource.go b/internal/daas/hypervisor/xenserver_hypervisor_resource.go
index adb0831..2f82c47 100644
--- a/internal/daas/hypervisor/xenserver_hypervisor_resource.go
+++ b/internal/daas/hypervisor/xenserver_hypervisor_resource.go
@@ -173,6 +173,14 @@ func (r *xenserverHypervisorResource) Update(ctx context.Context, req resource.U
return
}
+ // Get current state
+ var state XenserverHypervisorResourceModel
+ diags = req.State.Get(ctx, &state)
+ resp.Diagnostics.Append(diags...)
+ if resp.Diagnostics.HasError() {
+ return
+ }
+
// Construct the update model
var editHypervisorRequestBody citrixorchestration.EditHypervisorConnectionRequestModel
editHypervisorRequestBody.SetName(plan.Name.ValueString())
@@ -201,7 +209,7 @@ func (r *xenserverHypervisorResource) Update(ctx context.Context, req resource.U
editHypervisorRequestBody.SetScopes(util.StringSetToStringArray(ctx, &resp.Diagnostics, plan.Scopes))
}
- metadata := util.GetMetadataRequestModel(ctx, &resp.Diagnostics, util.ObjectListToTypedArray[util.NameValueStringPairModel](ctx, &resp.Diagnostics, plan.Metadata))
+ metadata := util.GetUpdatedMetadataRequestModel(ctx, &resp.Diagnostics, util.ObjectListToTypedArray[util.NameValueStringPairModel](ctx, &resp.Diagnostics, state.Metadata), util.ObjectListToTypedArray[util.NameValueStringPairModel](ctx, &resp.Diagnostics, plan.Metadata))
editHypervisorRequestBody.SetMetadata(metadata)
// Patch hypervisor
diff --git a/internal/daas/hypervisor_resource_pool/aws_hypervisor_resource_pool_resource.go b/internal/daas/hypervisor_resource_pool/aws_hypervisor_resource_pool_resource.go
index 7e3d92e..dde76bc 100644
--- a/internal/daas/hypervisor_resource_pool/aws_hypervisor_resource_pool_resource.go
+++ b/internal/daas/hypervisor_resource_pool/aws_hypervisor_resource_pool_resource.go
@@ -164,6 +164,13 @@ func (r *awsHypervisorResourcePoolResource) Update(ctx context.Context, req reso
return
}
+ var state AwsHypervisorResourcePoolResourceModel
+ diags = req.State.Get(ctx, &state)
+ resp.Diagnostics.Append(diags...)
+ if resp.Diagnostics.HasError() {
+ return
+ }
+
var editHypervisorResourcePool citrixorchestration.EditHypervisorResourcePoolRequestModel
editHypervisorResourcePool.SetName(plan.Name.ValueString())
editHypervisorResourcePool.SetConnectionType(citrixorchestration.HYPERVISORCONNECTIONTYPE_AWS)
@@ -177,7 +184,7 @@ func (r *awsHypervisorResourcePoolResource) Update(ctx context.Context, req reso
}
editHypervisorResourcePool.SetNetworks(subnets)
- metadata := util.GetMetadataRequestModel(ctx, &resp.Diagnostics, util.ObjectListToTypedArray[util.NameValueStringPairModel](ctx, &resp.Diagnostics, plan.Metadata))
+ metadata := util.GetUpdatedMetadataRequestModel(ctx, &resp.Diagnostics, util.ObjectListToTypedArray[util.NameValueStringPairModel](ctx, &resp.Diagnostics, state.Metadata), util.ObjectListToTypedArray[util.NameValueStringPairModel](ctx, &resp.Diagnostics, plan.Metadata))
editHypervisorResourcePool.SetMetadata(metadata)
updatedResourcePool, err := UpdateHypervisorResourcePool(ctx, r.client, &resp.Diagnostics, plan.Hypervisor.ValueString(), plan.Id.ValueString(), editHypervisorResourcePool)
diff --git a/internal/daas/hypervisor_resource_pool/azure_hypervisor_resource_pool_resource.go b/internal/daas/hypervisor_resource_pool/azure_hypervisor_resource_pool_resource.go
index 7261ce5..652c8b7 100644
--- a/internal/daas/hypervisor_resource_pool/azure_hypervisor_resource_pool_resource.go
+++ b/internal/daas/hypervisor_resource_pool/azure_hypervisor_resource_pool_resource.go
@@ -91,7 +91,7 @@ func (r *azureHypervisorResourcePoolResource) Create(ctx context.Context, req re
return
}
region, httpResp, err := util.GetSingleHypervisorResource(ctx, r.client, &resp.Diagnostics, hypervisorId, "", plan.Region.ValueString(), "Region", "", hypervisor)
- regionPath := region.GetXDPath()
+ regionPath := region.GetRelativePath()
if err != nil {
resp.Diagnostics.AddError(
"Error creating Hypervisor Resource Pool for Azure",
@@ -102,7 +102,7 @@ func (r *azureHypervisorResourcePoolResource) Create(ctx context.Context, req re
}
resourcePoolDetails.SetRegion(regionPath)
vnet, httpResp, err := util.GetSingleHypervisorResource(ctx, r.client, &resp.Diagnostics, hypervisorId, fmt.Sprintf("%s/virtualprivatecloud.folder", regionPath), plan.VirtualNetwork.ValueString(), util.VirtualPrivateCloudResourceType, plan.VirtualNetworkResourceGroup.ValueString(), hypervisor)
- vnetPath := vnet.GetXDPath()
+ vnetPath := vnet.GetRelativePath()
if err != nil {
resp.Diagnostics.AddError(
"Error creating Hypervisor Resource Pool for Azure",
@@ -190,6 +190,13 @@ func (r *azureHypervisorResourcePoolResource) Update(ctx context.Context, req re
return
}
+ var state AzureHypervisorResourcePoolResourceModel
+ diags = req.State.Get(ctx, &state)
+ resp.Diagnostics.Append(diags...)
+ if resp.Diagnostics.HasError() {
+ return
+ }
+
var editHypervisorResourcePool citrixorchestration.EditHypervisorResourcePoolRequestModel
editHypervisorResourcePool.SetName(plan.Name.ValueString())
editHypervisorResourcePool.SetConnectionType(citrixorchestration.HYPERVISORCONNECTIONTYPE_AZURE_RM)
@@ -206,7 +213,7 @@ func (r *azureHypervisorResourcePoolResource) Update(ctx context.Context, req re
}
editHypervisorResourcePool.SetSubnets(subnets)
- metadata := util.GetMetadataRequestModel(ctx, &resp.Diagnostics, util.ObjectListToTypedArray[util.NameValueStringPairModel](ctx, &resp.Diagnostics, plan.Metadata))
+ metadata := util.GetUpdatedMetadataRequestModel(ctx, &resp.Diagnostics, util.ObjectListToTypedArray[util.NameValueStringPairModel](ctx, &resp.Diagnostics, state.Metadata), util.ObjectListToTypedArray[util.NameValueStringPairModel](ctx, &resp.Diagnostics, plan.Metadata))
editHypervisorResourcePool.SetMetadata(metadata)
updatedResourcePool, err := UpdateHypervisorResourcePool(ctx, r.client, &resp.Diagnostics, plan.Hypervisor.ValueString(), plan.Id.ValueString(), editHypervisorResourcePool)
diff --git a/internal/daas/hypervisor_resource_pool/gcp_hypervisor_resource_pool_resource.go b/internal/daas/hypervisor_resource_pool/gcp_hypervisor_resource_pool_resource.go
index 0052d67..c3b751f 100644
--- a/internal/daas/hypervisor_resource_pool/gcp_hypervisor_resource_pool_resource.go
+++ b/internal/daas/hypervisor_resource_pool/gcp_hypervisor_resource_pool_resource.go
@@ -175,6 +175,13 @@ func (r *gcpHypervisorResourcePoolResource) Update(ctx context.Context, req reso
return
}
+ var state GcpHypervisorResourcePoolResourceModel
+ diags = req.State.Get(ctx, &state)
+ resp.Diagnostics.Append(diags...)
+ if resp.Diagnostics.HasError() {
+ return
+ }
+
var editHypervisorResourcePool citrixorchestration.EditHypervisorResourcePoolRequestModel
editHypervisorResourcePool.SetName(plan.Name.ValueString())
editHypervisorResourcePool.SetConnectionType(citrixorchestration.HYPERVISORCONNECTIONTYPE_GOOGLE_CLOUD_PLATFORM)
@@ -192,7 +199,7 @@ func (r *gcpHypervisorResourcePoolResource) Update(ctx context.Context, req reso
return
}
editHypervisorResourcePool.SetNetworks(subnets)
- metadata := util.GetMetadataRequestModel(ctx, &resp.Diagnostics, util.ObjectListToTypedArray[util.NameValueStringPairModel](ctx, &resp.Diagnostics, plan.Metadata))
+ metadata := util.GetUpdatedMetadataRequestModel(ctx, &resp.Diagnostics, util.ObjectListToTypedArray[util.NameValueStringPairModel](ctx, &resp.Diagnostics, state.Metadata), util.ObjectListToTypedArray[util.NameValueStringPairModel](ctx, &resp.Diagnostics, plan.Metadata))
editHypervisorResourcePool.SetMetadata(metadata)
updatedResourcePool, err := UpdateHypervisorResourcePool(ctx, r.client, &resp.Diagnostics, plan.Hypervisor.ValueString(), plan.Id.ValueString(), editHypervisorResourcePool)
diff --git a/internal/daas/hypervisor_resource_pool/nutanix_hypervisor_resource_pool_resource.go b/internal/daas/hypervisor_resource_pool/nutanix_hypervisor_resource_pool_resource.go
index 3d86031..c8236d3 100644
--- a/internal/daas/hypervisor_resource_pool/nutanix_hypervisor_resource_pool_resource.go
+++ b/internal/daas/hypervisor_resource_pool/nutanix_hypervisor_resource_pool_resource.go
@@ -150,6 +150,13 @@ func (r *nutanixHypervisorResourcePoolResource) Update(ctx context.Context, req
return
}
+ var state NutanixHypervisorResourcePoolResourceModel
+ diags = req.State.Get(ctx, &state)
+ resp.Diagnostics.Append(diags...)
+ if resp.Diagnostics.HasError() {
+ return
+ }
+
hypervisorId := plan.Hypervisor.ValueString()
hypervisor, err := util.GetHypervisor(ctx, r.client, &resp.Diagnostics, hypervisorId)
@@ -175,7 +182,7 @@ func (r *nutanixHypervisorResourcePoolResource) Update(ctx context.Context, req
networks := plan.GetNetworksList(ctx, r.client, &resp.Diagnostics, hypervisor, false)
editHypervisorResourcePool.SetNetworks(networks)
- metadata := util.GetMetadataRequestModel(ctx, &resp.Diagnostics, util.ObjectListToTypedArray[util.NameValueStringPairModel](ctx, &resp.Diagnostics, plan.Metadata))
+ metadata := util.GetUpdatedMetadataRequestModel(ctx, &resp.Diagnostics, util.ObjectListToTypedArray[util.NameValueStringPairModel](ctx, &resp.Diagnostics, state.Metadata), util.ObjectListToTypedArray[util.NameValueStringPairModel](ctx, &resp.Diagnostics, plan.Metadata))
editHypervisorResourcePool.SetMetadata(metadata)
_, err = UpdateHypervisorResourcePool(ctx, r.client, &resp.Diagnostics, plan.Hypervisor.ValueString(), plan.Id.ValueString(), editHypervisorResourcePool)
diff --git a/internal/daas/hypervisor_resource_pool/scvmm_hypervisor_resource_pool_resource.go b/internal/daas/hypervisor_resource_pool/scvmm_hypervisor_resource_pool_resource.go
index 0f2d0c3..d6ff380 100644
--- a/internal/daas/hypervisor_resource_pool/scvmm_hypervisor_resource_pool_resource.go
+++ b/internal/daas/hypervisor_resource_pool/scvmm_hypervisor_resource_pool_resource.go
@@ -260,6 +260,13 @@ func (r *scvmmHypervisorResourcePoolResource) Update(ctx context.Context, req re
return
}
+ var state SCVMMHypervisorResourcePoolResourceModel
+ diags = req.State.Get(ctx, &state)
+ resp.Diagnostics.Append(diags...)
+ if resp.Diagnostics.HasError() {
+ return
+ }
+
hypervisorId := plan.Hypervisor.ValueString()
hypervisor, err := util.GetHypervisor(ctx, r.client, &resp.Diagnostics, hypervisorId)
@@ -330,7 +337,7 @@ func (r *scvmmHypervisorResourcePoolResource) Update(ctx context.Context, req re
editHypervisorResourcePool.SetUseLocalStorageCaching(plan.UseLocalStorageCaching.ValueBool())
- metadata := util.GetMetadataRequestModel(ctx, &resp.Diagnostics, util.ObjectListToTypedArray[util.NameValueStringPairModel](ctx, &resp.Diagnostics, plan.Metadata))
+ metadata := util.GetUpdatedMetadataRequestModel(ctx, &resp.Diagnostics, util.ObjectListToTypedArray[util.NameValueStringPairModel](ctx, &resp.Diagnostics, state.Metadata), util.ObjectListToTypedArray[util.NameValueStringPairModel](ctx, &resp.Diagnostics, plan.Metadata))
editHypervisorResourcePool.SetMetadata(metadata)
updatedResourcePool, err := UpdateHypervisorResourcePool(ctx, r.client, &resp.Diagnostics, plan.Hypervisor.ValueString(), plan.Id.ValueString(), editHypervisorResourcePool)
diff --git a/internal/daas/hypervisor_resource_pool/vsphere_hypervisor_resource_pool_resource.go b/internal/daas/hypervisor_resource_pool/vsphere_hypervisor_resource_pool_resource.go
index 85af12b..1e45a96 100644
--- a/internal/daas/hypervisor_resource_pool/vsphere_hypervisor_resource_pool_resource.go
+++ b/internal/daas/hypervisor_resource_pool/vsphere_hypervisor_resource_pool_resource.go
@@ -249,6 +249,13 @@ func (r *vsphereHypervisorResourcePoolResource) Update(ctx context.Context, req
return
}
+ var state VsphereHypervisorResourcePoolResourceModel
+ diags = req.State.Get(ctx, &state)
+ resp.Diagnostics.Append(diags...)
+ if resp.Diagnostics.HasError() {
+ return
+ }
+
hypervisorId := plan.Hypervisor.ValueString()
hypervisor, err := util.GetHypervisor(ctx, r.client, &resp.Diagnostics, hypervisorId)
@@ -309,7 +316,7 @@ func (r *vsphereHypervisorResourcePoolResource) Update(ctx context.Context, req
editHypervisorResourcePool.SetUseLocalStorageCaching(plan.UseLocalStorageCaching.ValueBool())
- metadata := util.GetMetadataRequestModel(ctx, &resp.Diagnostics, util.ObjectListToTypedArray[util.NameValueStringPairModel](ctx, &resp.Diagnostics, plan.Metadata))
+ metadata := util.GetUpdatedMetadataRequestModel(ctx, &resp.Diagnostics, util.ObjectListToTypedArray[util.NameValueStringPairModel](ctx, &resp.Diagnostics, state.Metadata), util.ObjectListToTypedArray[util.NameValueStringPairModel](ctx, &resp.Diagnostics, plan.Metadata))
editHypervisorResourcePool.SetMetadata(metadata)
updatedResourcePool, err := UpdateHypervisorResourcePool(ctx, r.client, &resp.Diagnostics, plan.Hypervisor.ValueString(), plan.Id.ValueString(), editHypervisorResourcePool)
diff --git a/internal/daas/hypervisor_resource_pool/xenserver_hypervisor_resource_pool_resource.go b/internal/daas/hypervisor_resource_pool/xenserver_hypervisor_resource_pool_resource.go
index 2ef6dcc..f6b9e3b 100644
--- a/internal/daas/hypervisor_resource_pool/xenserver_hypervisor_resource_pool_resource.go
+++ b/internal/daas/hypervisor_resource_pool/xenserver_hypervisor_resource_pool_resource.go
@@ -161,6 +161,13 @@ func (r *xenserverHypervisorResourcePoolResource) Update(ctx context.Context, re
return
}
+ var state XenserverHypervisorResourcePoolResourceModel
+ diags = req.State.Get(ctx, &state)
+ resp.Diagnostics.Append(diags...)
+ if resp.Diagnostics.HasError() {
+ return
+ }
+
hypervisorId := plan.Hypervisor.ValueString()
hypervisor, err := util.GetHypervisor(ctx, r.client, &resp.Diagnostics, hypervisorId)
@@ -221,7 +228,7 @@ func (r *xenserverHypervisorResourcePoolResource) Update(ctx context.Context, re
editHypervisorResourcePool.SetUseLocalStorageCaching(plan.UseLocalStorageCaching.ValueBool())
- metadata := util.GetMetadataRequestModel(ctx, &resp.Diagnostics, util.ObjectListToTypedArray[util.NameValueStringPairModel](ctx, &resp.Diagnostics, plan.Metadata))
+ metadata := util.GetUpdatedMetadataRequestModel(ctx, &resp.Diagnostics, util.ObjectListToTypedArray[util.NameValueStringPairModel](ctx, &resp.Diagnostics, state.Metadata), util.ObjectListToTypedArray[util.NameValueStringPairModel](ctx, &resp.Diagnostics, plan.Metadata))
editHypervisorResourcePool.SetMetadata(metadata)
updatedResourcePool, err := UpdateHypervisorResourcePool(ctx, r.client, &resp.Diagnostics, plan.Hypervisor.ValueString(), plan.Id.ValueString(), editHypervisorResourcePool)
diff --git a/internal/daas/machine_catalog/machine_catalog_common_utils.go b/internal/daas/machine_catalog/machine_catalog_common_utils.go
index b48f20b..c3aba70 100644
--- a/internal/daas/machine_catalog/machine_catalog_common_utils.go
+++ b/internal/daas/machine_catalog/machine_catalog_common_utils.go
@@ -132,7 +132,7 @@ func getRequestModelForCreateMachineCatalog(plan MachineCatalogResourceModel, ct
return &body, nil
}
-func getRequestModelForUpdateMachineCatalog(plan MachineCatalogResourceModel, ctx context.Context, client *citrixdaasclient.CitrixDaasClient, resp *resource.UpdateResponse, isOnPremises bool) (*citrixorchestration.UpdateMachineCatalogRequestModel, error) {
+func getRequestModelForUpdateMachineCatalog(plan MachineCatalogResourceModel, state MachineCatalogResourceModel, ctx context.Context, client *citrixdaasclient.CitrixDaasClient, resp *resource.UpdateResponse, isOnPremises bool) (*citrixorchestration.UpdateMachineCatalogRequestModel, error) {
// Generate API request body from plan
var body citrixorchestration.UpdateMachineCatalogRequestModel
body.SetName(plan.Name.ValueString())
@@ -194,7 +194,7 @@ func getRequestModelForUpdateMachineCatalog(plan MachineCatalogResourceModel, ct
return nil, err
}
- metadata := util.GetMetadataRequestModel(ctx, &resp.Diagnostics, util.ObjectListToTypedArray[util.NameValueStringPairModel](ctx, &resp.Diagnostics, plan.Metadata))
+ metadata := util.GetUpdatedMetadataRequestModel(ctx, &resp.Diagnostics, util.ObjectListToTypedArray[util.NameValueStringPairModel](ctx, &resp.Diagnostics, state.Metadata), util.ObjectListToTypedArray[util.NameValueStringPairModel](ctx, &resp.Diagnostics, plan.Metadata))
body.SetMetadata(metadata)
return &body, nil
@@ -245,7 +245,7 @@ func generateBatchApiHeaders(ctx context.Context, diagnostics *diag.Diagnostics,
}
func readMachineCatalog(ctx context.Context, client *citrixdaasclient.CitrixDaasClient, resp *resource.ReadResponse, machineCatalogId string) (*citrixorchestration.MachineCatalogDetailResponseModel, *http.Response, error) {
- getMachineCatalogRequest := client.ApiClient.MachineCatalogsAPIsDAAS.MachineCatalogsGetMachineCatalog(ctx, machineCatalogId).Fields("Id,Name,Description,ProvisioningType,Zone,AllocationType,SessionSupport,TotalCount,HypervisorConnection,ProvisioningScheme,RemotePCEnrollmentScopes,IsPowerManaged,MinimumFunctionalLevel,IsRemotePC,Metadata,Scopes")
+ getMachineCatalogRequest := client.ApiClient.MachineCatalogsAPIsDAAS.MachineCatalogsGetMachineCatalog(ctx, machineCatalogId).Fields("Id,Name,Description,ProvisioningType,Zone,AllocationType,SessionSupport,TotalCount,HypervisorConnection,ProvisioningScheme,RemotePCEnrollmentScopes,IsPowerManaged,MinimumFunctionalLevel,IsRemotePC,Metadata,Scopes,UpgradeInfo,AdminFolder")
catalog, httpResp, err := util.ReadResource[*citrixorchestration.MachineCatalogDetailResponseModel](getMachineCatalogRequest, ctx, client, resp, "Machine Catalog", machineCatalogId)
return catalog, httpResp, err
@@ -284,7 +284,7 @@ func deleteMachinesFromCatalog(ctx context.Context, client *citrixdaasclient.Cit
)
return err
}
- relativeUrl := fmt.Sprintf("/Machines/%s?async=true", machineToDelete.GetId())
+ relativeUrl := fmt.Sprintf("/Machines/%s", machineToDelete.GetId())
var batchRequestItem citrixorchestration.BatchRequestItemModel
batchRequestItem.SetReference(strconv.Itoa(index))
@@ -341,7 +341,7 @@ func deleteMachinesFromCatalog(ctx context.Context, client *citrixdaasclient.Cit
batchRequestItems = []citrixorchestration.BatchRequestItemModel{}
for index, machineToDelete := range machinesToDelete {
var batchRequestItem citrixorchestration.BatchRequestItemModel
- relativeUrl := fmt.Sprintf("/Machines/%s?deleteVm=%t&purgeDBOnly=false&deleteAccount=%s&async=true", machineToDelete.GetId(), isMcsOrPvsCatalog, deleteAccountOpion)
+ relativeUrl := fmt.Sprintf("/Machines/%s?deleteVm=%t&purgeDBOnly=false&deleteAccount=%s", machineToDelete.GetId(), isMcsOrPvsCatalog, deleteAccountOpion)
batchRequestItem.SetReference(strconv.Itoa(index))
batchRequestItem.SetMethod(http.MethodDelete)
batchRequestItem.SetHeaders(batchApiHeaders)
@@ -478,6 +478,7 @@ func setMachineCatalogTags(ctx context.Context, diagnostics *diag.Diagnostics, c
func getMachineCatalogTags(ctx context.Context, diagnostics *diag.Diagnostics, client *citrixdaasclient.CitrixDaasClient, machineCatalogId string) []string {
getTagsRequest := client.ApiClient.MachineCatalogsAPIsDAAS.MachineCatalogsGetMachineCatalogTags(ctx, machineCatalogId)
+ getTagsRequest = getTagsRequest.Fields("Id,Name,Description")
tagsResp, httpResp, err := citrixdaasclient.AddRequestData(getTagsRequest, client).Execute()
return util.ProcessTagsResponseCollection(diagnostics, tagsResp, httpResp, err, "Machine Catalog", machineCatalogId)
}
diff --git a/internal/daas/machine_catalog/machine_catalog_data_source.go b/internal/daas/machine_catalog/machine_catalog_data_source.go
index 0121fdc..d54ed97 100644
--- a/internal/daas/machine_catalog/machine_catalog_data_source.go
+++ b/internal/daas/machine_catalog/machine_catalog_data_source.go
@@ -61,12 +61,18 @@ func (d *MachineCatalogDataSource) Read(ctx context.Context, req datasource.Read
}
// Get refreshed machine catalog state from Orchestration
- machineCatalogPath := strings.ReplaceAll(data.MachineCatalogFolderPath.ValueString(), "\\", "|") + data.Name.ValueString()
+ machineCatalogName := data.Name.ValueString()
+ machineCatalogPath := strings.ReplaceAll(data.MachineCatalogFolderPath.ValueString(), "\\", "|")
+ if machineCatalogPath != "" {
+ machineCatalogPath = machineCatalogPath + "|" + machineCatalogName
+ } else {
+ machineCatalogPath += machineCatalogName
+ }
getMachineCatalogRequest := d.client.ApiClient.MachineCatalogsAPIsDAAS.MachineCatalogsGetMachineCatalog(ctx, machineCatalogPath).Fields("Id,Name,Description,ProvisioningType,Zone,AllocationType,SessionSupport,TotalCount,HypervisorConnection,ProvisioningScheme,RemotePCEnrollmentScopes,IsPowerManaged,MinimumFunctionalLevel,IsRemotePC")
machineCatalog, httpResp, err := citrixdaasclient.AddRequestData(getMachineCatalogRequest, d.client).Execute()
if err != nil {
resp.Diagnostics.AddError(
- "Error reading Machine Catalog "+data.Name.ValueString(),
+ "Error reading Machine Catalog "+machineCatalogName,
"TransactionId: "+citrixdaasclient.GetTransactionIdFromHttpResponse(httpResp)+
"\nError message: "+util.ReadClientError(err),
)
@@ -78,7 +84,7 @@ func (d *MachineCatalogDataSource) Read(ctx context.Context, req datasource.Read
if err != nil {
resp.Diagnostics.AddError(
- "Error listing VDAs in Machine Catalog "+data.Name.ValueString(),
+ "Error listing VDAs in Machine Catalog "+machineCatalogName,
"TransactionId: "+citrixdaasclient.GetTransactionIdFromHttpResponse(httpResp)+
"\nError message: "+util.ReadClientError(err),
)
diff --git a/internal/daas/machine_catalog/machine_catalog_data_source_model.go b/internal/daas/machine_catalog/machine_catalog_data_source_model.go
index 0625565..5497a0d 100644
--- a/internal/daas/machine_catalog/machine_catalog_data_source_model.go
+++ b/internal/daas/machine_catalog/machine_catalog_data_source_model.go
@@ -4,12 +4,16 @@ package machine_catalog
import (
"context"
+ "regexp"
+ "strings"
"github.com/citrix/citrix-daas-rest-go/citrixorchestration"
"github.com/citrix/terraform-provider-citrix/internal/daas/vda"
"github.com/citrix/terraform-provider-citrix/internal/util"
+ "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
"github.com/hashicorp/terraform-plugin-framework/datasource/schema"
"github.com/hashicorp/terraform-plugin-framework/diag"
+ "github.com/hashicorp/terraform-plugin-framework/schema/validator"
"github.com/hashicorp/terraform-plugin-framework/types"
)
@@ -38,6 +42,10 @@ func (MachineCatalogDataSourceModel) GetSchema() schema.Schema {
"machine_catalog_folder_path": schema.StringAttribute{
Description: "The path to the folder in which the machine catalog is located.",
Optional: true,
+ Validators: []validator.String{
+ stringvalidator.RegexMatches(regexp.MustCompile(util.AdminFolderPathWithBackslashRegex), "Admin Folder Path must not start or end with a backslash"),
+ stringvalidator.RegexMatches(regexp.MustCompile(util.AdminFolderPathSpecialCharactersRegex), "Admin Folder Path must not contain any of the following special characters: / ; : # . * ? = < > | [ ] ( ) { } \" ' ` ~ "),
+ },
},
"vdas": schema.ListNestedAttribute{
Description: "The VDAs associated with the machine catalog.",
@@ -63,7 +71,7 @@ func (r MachineCatalogDataSourceModel) RefreshPropertyValues(ctx context.Context
r.Name = types.StringValue(catalog.GetName())
adminFolder := catalog.GetAdminFolder()
- adminFolderPath := adminFolder.GetName()
+ adminFolderPath := strings.TrimSuffix(adminFolder.GetName(), "\\")
if adminFolderPath != "" {
r.MachineCatalogFolderPath = types.StringValue(adminFolderPath)
} else {
diff --git a/internal/daas/machine_catalog/machine_catalog_manual_utils.go b/internal/daas/machine_catalog/machine_catalog_manual_utils.go
index 492fc86..ffb047a 100644
--- a/internal/daas/machine_catalog/machine_catalog_manual_utils.go
+++ b/internal/daas/machine_catalog/machine_catalog_manual_utils.go
@@ -219,7 +219,7 @@ func addMachinesToManualCatalog(ctx context.Context, diagnostics *diag.Diagnosti
}
batchRequestItems := []citrixorchestration.BatchRequestItemModel{}
- relativeUrl := fmt.Sprintf("/MachineCatalogs/%s/Machines?async=true", catalogIdOrName)
+ relativeUrl := fmt.Sprintf("/MachineCatalogs/%s/Machines", catalogIdOrName)
for i := 0; i < len(addMachinesRequest); i++ {
addMachineRequestStringBody, err := util.ConvertToString(addMachinesRequest[i])
if err != nil {
diff --git a/internal/daas/machine_catalog/machine_catalog_mcs_pvs_utils.go b/internal/daas/machine_catalog/machine_catalog_mcs_pvs_utils.go
index b481270..8005512 100644
--- a/internal/daas/machine_catalog/machine_catalog_mcs_pvs_utils.go
+++ b/internal/daas/machine_catalog/machine_catalog_mcs_pvs_utils.go
@@ -284,7 +284,8 @@ func buildProvSchemeForCatalog(ctx context.Context, client *citrixdaasclient.Cit
image := vSphereMachineConfig.MasterImageVm.ValueString()
snapshot := vSphereMachineConfig.ImageSnapshot.ValueString()
- imagePath, err := getOnPremImagePath(ctx, client, diag, hypervisor.GetName(), hypervisorResourcePool.GetName(), image, snapshot, "creating")
+ resourcePoolPath := vSphereMachineConfig.ResourcePoolPath.ValueString()
+ imagePath, err := getOnPremImagePath(ctx, client, diag, hypervisor.GetName(), hypervisorResourcePool.GetName(), image, snapshot, resourcePoolPath, "creating")
if err != nil {
return nil, err
}
@@ -325,7 +326,7 @@ func buildProvSchemeForCatalog(ctx context.Context, client *citrixdaasclient.Cit
image := xenserverMachineConfig.MasterImageVm.ValueString()
snapshot := xenserverMachineConfig.ImageSnapshot.ValueString()
- imagePath, err := getOnPremImagePath(ctx, client, diag, hypervisor.GetName(), hypervisorResourcePool.GetName(), image, snapshot, "creating")
+ imagePath, err := getOnPremImagePath(ctx, client, diag, hypervisor.GetName(), hypervisorResourcePool.GetName(), image, snapshot, "", "creating")
if err != nil {
return nil, err
}
@@ -349,7 +350,7 @@ func buildProvSchemeForCatalog(ctx context.Context, client *citrixdaasclient.Cit
image := scvmmMachineConfig.MasterImage.ValueString()
snapshot := scvmmMachineConfig.ImageSnapshot.ValueString()
- imageResource, err := getOnPremImage(ctx, client, diag, hypervisor.GetName(), hypervisorResourcePool.GetName(), image, snapshot, "creating")
+ imageResource, err := getOnPremImage(ctx, client, diag, hypervisor.GetName(), hypervisorResourcePool.GetName(), image, snapshot, "", "creating")
if err != nil {
return nil, err
}
@@ -611,7 +612,7 @@ func setProvSchemePropertiesForUpdateCatalog(provisioningSchemePlan Provisioning
image := scvmmMachineConfig.MasterImage.ValueString()
snapshot := scvmmMachineConfig.ImageSnapshot.ValueString()
- imageResource, err := getOnPremImage(ctx, client, diagnostics, hypervisor.GetName(), hypervisorResourcePool.GetName(), image, snapshot, "updating")
+ imageResource, err := getOnPremImage(ctx, client, diagnostics, hypervisor.GetName(), hypervisorResourcePool.GetName(), image, snapshot, "", "updating")
if err != nil {
return body, err
}
@@ -744,7 +745,7 @@ func addMachinesToMcsPvsCatalog(ctx context.Context, client *citrixdaasclient.Ci
}
batchRequestItems := []citrixorchestration.BatchRequestItemModel{}
- relativeUrl := fmt.Sprintf("/MachineCatalogs/%s/Machines?async=true", catalogId)
+ relativeUrl := fmt.Sprintf("/MachineCatalogs/%s/Machines", catalogId)
for i := 0; i < int(addMachinesCount); i++ {
var batchRequestItem citrixorchestration.BatchRequestItemModel
batchRequestItem.SetMethod(http.MethodPost)
@@ -1040,7 +1041,8 @@ func updateCatalogImageAndMachineProfile(ctx context.Context, client *citrixdaas
vSphereMachineConfig := util.ObjectValueToTypedObject[VsphereMachineConfigModel](ctx, &resp.Diagnostics, provisioningSchemePlan.VsphereMachineConfig)
newImage := vSphereMachineConfig.MasterImageVm.ValueString()
snapshot := vSphereMachineConfig.ImageSnapshot.ValueString()
- imagePath, err = getOnPremImagePath(ctx, client, &resp.Diagnostics, hypervisor.GetName(), hypervisorResourcePool.GetName(), newImage, snapshot, "updating")
+ resourcePoolPath := vSphereMachineConfig.ResourcePoolPath.ValueString()
+ imagePath, err = getOnPremImagePath(ctx, client, &resp.Diagnostics, hypervisor.GetName(), hypervisorResourcePool.GetName(), newImage, snapshot, resourcePoolPath, "updating")
if err != nil {
return err
}
@@ -1065,7 +1067,7 @@ func updateCatalogImageAndMachineProfile(ctx context.Context, client *citrixdaas
xenserverMachineConfig := util.ObjectValueToTypedObject[XenserverMachineConfigModel](ctx, &resp.Diagnostics, provisioningSchemePlan.XenserverMachineConfig)
newImage := xenserverMachineConfig.MasterImageVm.ValueString()
snapshot := xenserverMachineConfig.ImageSnapshot.ValueString()
- imagePath, err = getOnPremImagePath(ctx, client, &resp.Diagnostics, hypervisor.GetName(), hypervisorResourcePool.GetName(), newImage, snapshot, "updating")
+ imagePath, err = getOnPremImagePath(ctx, client, &resp.Diagnostics, hypervisor.GetName(), hypervisorResourcePool.GetName(), newImage, snapshot, "", "updating")
if err != nil {
return err
}
@@ -1090,7 +1092,7 @@ func updateCatalogImageAndMachineProfile(ctx context.Context, client *citrixdaas
scvmmMachineConfig := util.ObjectValueToTypedObject[SCVMMMachineConfigModel](ctx, &resp.Diagnostics, provisioningSchemePlan.SCVMMMachineConfigModel)
newImage := scvmmMachineConfig.MasterImage.ValueString()
snapshot := scvmmMachineConfig.ImageSnapshot.ValueString()
- imagePath, err = getOnPremImagePath(ctx, client, &resp.Diagnostics, hypervisor.GetName(), hypervisorResourcePool.GetName(), newImage, snapshot, "updating")
+ imagePath, err = getOnPremImagePath(ctx, client, &resp.Diagnostics, hypervisor.GetName(), hypervisorResourcePool.GetName(), newImage, snapshot, "", "updating")
if err != nil {
return err
}
@@ -1503,13 +1505,19 @@ func parseNetworkMappingToClientModel(networkMappings []NetworkMappingModel, res
return res, nil
}
-func getOnPremImage(ctx context.Context, client *citrixdaasclient.CitrixDaasClient, diags *diag.Diagnostics, hypervisorName, resourcePoolName, image, snapshot, action string) (*citrixorchestration.HypervisorResourceResponseModel, error) {
+func getOnPremImage(ctx context.Context, client *citrixdaasclient.CitrixDaasClient, diags *diag.Diagnostics, hypervisorName, resourcePoolName, image, snapshot, resourcePoolPath, action string) (*citrixorchestration.HypervisorResourceResponseModel, error) {
queryPath := ""
+ if resourcePoolPath != "" {
+ resourcePoolSegments := strings.Split(resourcePoolPath, "/")
+ for _, resourcePool := range resourcePoolSegments {
+ queryPath = queryPath + resourcePool + ".resourcepool" + "\\"
+ }
+ }
resourceType := util.VirtualMachineResourceType
resourceName := image
errTemplate := fmt.Sprintf("Failed to locate master image machine %s", image)
if snapshot != "" {
- queryPath = fmt.Sprintf("%s.vm", image)
+ queryPath = queryPath + fmt.Sprintf("%s.vm", image)
snapshotSegments := strings.Split(snapshot, "/")
snapshotName := snapshotSegments[len(snapshotSegments)-1]
for i := 0; i < len(snapshotSegments)-1; i++ {
@@ -1534,8 +1542,8 @@ func getOnPremImage(ctx context.Context, client *citrixdaasclient.CitrixDaasClie
return imageResource, nil
}
-func getOnPremImagePath(ctx context.Context, client *citrixdaasclient.CitrixDaasClient, diags *diag.Diagnostics, hypervisorName, resourcePoolName, image, snapshot, action string) (string, error) {
- imageResource, err := getOnPremImage(ctx, client, diags, hypervisorName, resourcePoolName, image, snapshot, action)
+func getOnPremImagePath(ctx context.Context, client *citrixdaasclient.CitrixDaasClient, diags *diag.Diagnostics, hypervisorName, resourcePoolName, image, snapshot, resourcePoolPath, action string) (string, error) {
+ imageResource, err := getOnPremImage(ctx, client, diags, hypervisorName, resourcePoolName, image, snapshot, resourcePoolPath, action)
if err != nil {
return "", err
}
diff --git a/internal/daas/machine_catalog/machine_catalog_resource.go b/internal/daas/machine_catalog/machine_catalog_resource.go
index a4569ed..74ca78e 100644
--- a/internal/daas/machine_catalog/machine_catalog_resource.go
+++ b/internal/daas/machine_catalog/machine_catalog_resource.go
@@ -104,7 +104,13 @@ func (r *machineCatalogResource) Create(ctx context.Context, req resource.Create
if err != nil {
return
}
- machineCatalogPath := strings.ReplaceAll(plan.MachineCatalogFolderPath.ValueString(), "\\", "|") + plan.Name.ValueString()
+ machineCatalogName := plan.Name.ValueString()
+ machineCatalogPath := strings.ReplaceAll(plan.MachineCatalogFolderPath.ValueString(), "\\", "|")
+ if machineCatalogPath != "" {
+ machineCatalogPath = machineCatalogPath + "|" + machineCatalogName
+ } else {
+ machineCatalogPath += machineCatalogName
+ }
setMachineCatalogTags(ctx, &resp.Diagnostics, r.client, machineCatalogPath, plan.Tags)
@@ -231,7 +237,7 @@ func (r *machineCatalogResource) Update(ctx context.Context, req resource.Update
return
}
- body, err := getRequestModelForUpdateMachineCatalog(plan, ctx, r.client, resp, r.client.AuthConfig.OnPremises)
+ body, err := getRequestModelForUpdateMachineCatalog(plan, state, ctx, r.client, resp, r.client.AuthConfig.OnPremises)
if err != nil {
return
}
diff --git a/internal/daas/machine_catalog/machine_catalog_resource_model.go b/internal/daas/machine_catalog/machine_catalog_resource_model.go
index f9e7d8b..be7fc18 100644
--- a/internal/daas/machine_catalog/machine_catalog_resource_model.go
+++ b/internal/daas/machine_catalog/machine_catalog_resource_model.go
@@ -24,6 +24,7 @@ import (
"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/setdefault"
+ "github.com/hashicorp/terraform-plugin-framework/resource/schema/setplanmodifier"
"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"
@@ -579,6 +580,9 @@ func (MachineCatalogResourceModel) GetSchema() schema.Schema {
ElementType: types.StringType,
Description: "The IDs of the built_in scopes of the machine catalog.",
Computed: true,
+ PlanModifiers: []planmodifier.Set{
+ setplanmodifier.UseStateForUnknown(),
+ },
},
"inherited_scopes": schema.SetAttribute{
ElementType: types.StringType,
@@ -589,6 +593,10 @@ func (MachineCatalogResourceModel) GetSchema() schema.Schema {
"machine_catalog_folder_path": schema.StringAttribute{
Description: "The path to the folder in which the machine catalog is located.",
Optional: true,
+ Validators: []validator.String{
+ stringvalidator.RegexMatches(regexp.MustCompile(util.AdminFolderPathWithBackslashRegex), "Admin Folder Path must not start or end with a backslash"),
+ stringvalidator.RegexMatches(regexp.MustCompile(util.AdminFolderPathSpecialCharactersRegex), "Admin Folder Path must not contain any of the following special characters: / ; : # . * ? = < > | [ ] ( ) { } \" ' ` ~ "),
+ },
},
"tenants": schema.SetAttribute{
ElementType: types.StringType,
@@ -633,12 +641,12 @@ func (r MachineCatalogResourceModel) RefreshPropertyValues(ctx context.Context,
catalogZone := catalog.GetZone()
r.Zone = types.StringValue(catalogZone.GetId())
- if catalog.UpgradeInfo != nil {
- if *catalog.UpgradeInfo.UpgradeType != citrixorchestration.VDAUPGRADETYPE_NOT_SET || !r.VdaUpgradeType.IsNull() {
- r.VdaUpgradeType = types.StringValue(string(*catalog.UpgradeInfo.UpgradeType))
- }
- } else {
+ upgradeInfo := catalog.GetUpgradeInfo()
+ upgradeType := upgradeInfo.GetUpgradeType()
+ if upgradeType == "" || upgradeType == citrixorchestration.VDAUPGRADETYPE_NOT_SET {
r.VdaUpgradeType = types.StringNull()
+ } else {
+ r.VdaUpgradeType = types.StringValue(string(upgradeType))
}
provtype := catalog.GetProvisioningType()
@@ -679,20 +687,8 @@ func (r MachineCatalogResourceModel) RefreshPropertyValues(ctx context.Context,
r.Tenants = util.RefreshTenantSet(ctx, diagnostics, catalog.GetTenants())
- if catalog.ProvisioningScheme == nil {
- if attributesMap, err := util.AttributeMapFromObject(ProvisioningSchemeModel{}); err == nil {
- r.ProvisioningScheme = types.ObjectNull(attributesMap)
- } else {
- diagnostics.AddWarning("Error when creating null ProvisioningSchemeModel", err.Error())
- }
- return r
- }
-
- // Provisioning Scheme Properties
- r = r.updateCatalogWithProvScheme(ctx, diagnostics, client, catalog, connectionType, pluginId, provScheme)
-
adminFolder := catalog.GetAdminFolder()
- adminFolderPath := adminFolder.GetName()
+ adminFolderPath := strings.TrimSuffix(adminFolder.GetName(), "\\")
if adminFolderPath != "" {
r.MachineCatalogFolderPath = types.StringValue(adminFolderPath)
} else {
@@ -709,6 +705,18 @@ func (r MachineCatalogResourceModel) RefreshPropertyValues(ctx context.Context,
r.Tags = util.RefreshTagSet(ctx, diagnostics, tags)
+ if catalog.ProvisioningScheme == nil {
+ if attributesMap, err := util.AttributeMapFromObject(ProvisioningSchemeModel{}); err == nil {
+ r.ProvisioningScheme = types.ObjectNull(attributesMap)
+ } else {
+ diagnostics.AddWarning("Error when creating null ProvisioningSchemeModel", err.Error())
+ }
+ return r
+ }
+
+ // Provisioning Scheme Properties
+ r = r.updateCatalogWithProvScheme(ctx, diagnostics, client, catalog, connectionType, pluginId, provScheme)
+
return r
}
diff --git a/internal/daas/machine_catalog/machine_config.go b/internal/daas/machine_catalog/machine_config.go
index edd3c80..fe41758 100644
--- a/internal/daas/machine_catalog/machine_config.go
+++ b/internal/daas/machine_catalog/machine_config.go
@@ -278,6 +278,7 @@ func (GcpMachineConfigModel) GetAttributes() map[string]schema.Attribute {
type VsphereMachineConfigModel struct {
/** vSphere Hypervisor **/
MasterImageVm types.String `tfsdk:"master_image_vm"`
+ ResourcePoolPath types.String `tfsdk:"resource_pool_path"`
ImageSnapshot types.String `tfsdk:"image_snapshot"`
MasterImageNote types.String `tfsdk:"master_image_note"`
ImageUpdateRebootOptions types.Object `tfsdk:"image_update_reboot_options"`
@@ -295,6 +296,18 @@ func (VsphereMachineConfigModel) GetSchema() schema.SingleNestedAttribute {
"master_image_vm": schema.StringAttribute{
Description: "The name of the virtual machine that will be used as master image. This property is case sensitive.",
Required: true,
+ Validators: []validator.String{
+ stringvalidator.RegexMatches(
+ regexp.MustCompile(util.NoPathRegex),
+ "must not contain any path.",
+ ),
+ },
+ },
+ "resource_pool_path": schema.StringAttribute{
+ Description: "The Resource Pool path under which the `master_image_vm` is located. This property is case sensitive.",
+ Optional: true,
+ Computed: true,
+ Default: stringdefault.StaticString(""),
},
"image_snapshot": schema.StringAttribute{
Description: "The Snapshot of the virtual machine specified in `master_image_vm`. Specify the relative path of the snapshot. Eg: snaphost-1/snapshot-2/snapshot-3. This property is case sensitive.",
@@ -360,6 +373,12 @@ func (XenserverMachineConfigModel) GetSchema() schema.SingleNestedAttribute {
"master_image_vm": schema.StringAttribute{
Description: "The name of the virtual machine that will be used as master image. This property is case sensitive.",
Required: true,
+ Validators: []validator.String{
+ stringvalidator.RegexMatches(
+ regexp.MustCompile(util.NoPathRegex),
+ "must not contain any path.",
+ ),
+ },
},
"image_snapshot": schema.StringAttribute{
Description: "The Snapshot of the virtual machine specified in `master_image_vm`. Specify the relative path of the snapshot. Eg: snaphost-1/snapshot-2/snapshot-3. This property is case sensitive.",
@@ -576,6 +595,9 @@ func (AzureMasterImageModel) GetSchema() schema.SingleNestedAttribute {
"shared_subscription": schema.StringAttribute{
Description: "The Azure Subscription ID where the image VHD / managed disk / snapshot for creating machines is located. Only required if the image is not in the same subscription of the hypervisor.",
Optional: true,
+ Validators: []validator.String{
+ stringvalidator.LengthAtLeast(1),
+ },
},
"master_image": schema.StringAttribute{
Description: "The name of the virtual machine snapshot or VM template that will be used. This identifies the hard disk to be used and the default values for the memory and processors. Omit this field if you want to use gallery_image.",
@@ -1430,9 +1452,10 @@ func (mc *VsphereMachineConfigModel) RefreshProperties(ctx context.Context, diag
provScheme := catalog.GetProvisioningScheme()
// Refresh Master Image
- masterImage, imageSnapshot := parseOnPremImagePath(catalog)
+ masterImage, imageSnapshot, resourcePoolPath := parseOnPremImagePath(catalog)
mc.MasterImageVm = types.StringValue(masterImage)
mc.ImageSnapshot = types.StringValue(imageSnapshot)
+ mc.ResourcePoolPath = types.StringValue(resourcePoolPath)
// Refresh Master Image Note
currentDiskImage := provScheme.GetCurrentDiskImage()
@@ -1473,7 +1496,7 @@ func (mc *XenserverMachineConfigModel) RefreshProperties(ctx context.Context, di
mc.CpuCount = types.Int64Value(int64(provScheme.GetCpuCount()))
mc.MemoryMB = types.Int64Value(int64(provScheme.GetMemoryMB()))
- masterImage, imageSnapshot := parseOnPremImagePath(catalog)
+ masterImage, imageSnapshot, _ := parseOnPremImagePath(catalog)
mc.MasterImageVm = types.StringValue(masterImage)
mc.ImageSnapshot = types.StringValue(imageSnapshot)
@@ -1516,7 +1539,7 @@ func (mc *SCVMMMachineConfigModel) RefreshProperties(ctx context.Context, diagno
provScheme := catalog.GetProvisioningScheme()
// Refresh Master Image
- masterImage, imageSnapshot := parseOnPremImagePath(catalog)
+ masterImage, imageSnapshot, _ := parseOnPremImagePath(catalog)
mc.MasterImage = types.StringValue(masterImage)
mc.ImageSnapshot = types.StringValue(imageSnapshot)
@@ -1581,7 +1604,7 @@ func parseAzureMachineProfileResponseToModel(machineProfileResponse citrixorches
return &machineProfileModel
}
-func parseOnPremImagePath(catalog citrixorchestration.MachineCatalogDetailResponseModel) (masterImage, imageSnapshot string) {
+func parseOnPremImagePath(catalog citrixorchestration.MachineCatalogDetailResponseModel) (masterImage, imageSnapshot string, resourcePoolPath string) {
provScheme := catalog.GetProvisioningScheme()
currentDiskImage := provScheme.GetCurrentDiskImage()
currentImage := currentDiskImage.GetImage()
@@ -1589,17 +1612,36 @@ func parseOnPremImagePath(catalog citrixorchestration.MachineCatalogDetailRespon
// Refresh Master Image
/*
- * For On-Premise snapshot image, the RelativePath looks like:
- * {VM name}.vm/{VM snapshot name}.snapshot(/{VM snapshot name}.snapshot)*
- * A new snapshot will be created if it was not specified. There will always be at least one snapshot in the path.
- */
- imageSegments := strings.Split(relativePath, "/")
- masterImage = strings.TrimSuffix(imageSegments[0], ".vm")
+ * For On-Premise snapshot image, the RelativePath looks like:
+ * {VM name}.vm/{VM snapshot name}.snapshot(/{VM snapshot name}.snapshot)*
+ * A new snapshot will be created if it was not specified. There will always be at least one snapshot in the path.
+
+ * For Vsphere image, the RelativePath can also include resource pool and look like:
+ * {Resource Pool Name}.resourcepool/{Resource Pool Name}.resourcepool/{VM name}.vm/{VM snapshot name}.snapshot(/{VM snapshot name}.snapshot)*
+ */
+
+ // Find the last index of ".resourcepool"
+ lastResourcePoolIndex := strings.LastIndex(relativePath, ".resourcepool")
+ if lastResourcePoolIndex != -1 {
+ // Extract the resource pool path
+ resourcePoolVal := relativePath[:lastResourcePoolIndex+len(".resourcepool")]
+ // Remove all occurrences of ".resourcepool" from the extracted path
+ resourcePoolPath = strings.ReplaceAll(resourcePoolVal, ".resourcepool", "")
+ // Trim the resource pool path from the relative path
+ relativePath = relativePath[lastResourcePoolIndex+len(".resourcepool/"):]
+ }
- snapshot := strings.TrimSuffix(imageSegments[1], ".snapshot")
- for i := 2; i < len(imageSegments); i++ {
- snapshot = snapshot + "/" + strings.TrimSuffix(imageSegments[i], ".snapshot")
+ // Find the index of ".vm"
+ vmIndex := strings.Index(relativePath, ".vm")
+ if vmIndex == -1 {
+ return "", "", ""
}
+ // Extract the master image name and trim the ".vm"
+ masterImage = relativePath[:vmIndex]
+
+ // Extract the snapshot part of the path
+ snapshotPath := relativePath[vmIndex+len(".vm/"):]
+ imageSnapshot = strings.ReplaceAll(snapshotPath, ".snapshot", "")
- return masterImage, snapshot
+ return masterImage, imageSnapshot, resourcePoolPath
}
diff --git a/internal/daas/policies/policy_set_resource_model.go b/internal/daas/policies/policy_set_resource_model.go
index ee8b41d..84ffaa4 100644
--- a/internal/daas/policies/policy_set_resource_model.go
+++ b/internal/daas/policies/policy_set_resource_model.go
@@ -18,6 +18,7 @@ import (
"github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/hashicorp/terraform-plugin-framework/path"
"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/planmodifier"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/setdefault"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault"
@@ -556,6 +557,9 @@ func (PolicySetResourceModel) GetSchema() schema.Schema {
"assigned": schema.BoolAttribute{
Description: "Indicate whether the policy set is being assigned to delivery groups.",
Computed: true,
+ PlanModifiers: []planmodifier.Bool{
+ boolplanmodifier.UseStateForUnknown(),
+ },
},
},
}
diff --git a/internal/daas/tags/tag_resource.go b/internal/daas/tags/tag_resource.go
index c5b09d8..e2630e6 100644
--- a/internal/daas/tags/tag_resource.go
+++ b/internal/daas/tags/tag_resource.go
@@ -5,6 +5,7 @@ import (
"context"
"fmt"
"net/http"
+ "strings"
"github.com/citrix/citrix-daas-rest-go/citrixorchestration"
citrixdaasclient "github.com/citrix/citrix-daas-rest-go/client"
@@ -256,11 +257,17 @@ func (r *TagResource) ModifyPlan(ctx context.Context, req resource.ModifyPlanReq
operation = "creating"
}
- isTagNameAvailable, err := checkTagNameAvailability(ctx, r.client, &resp.Diagnostics, plan.Name.ValueString())
+ // Only validate tag name availability against tag ID during update operation.
+ tagId := ""
+ if !create {
+ tagId = plan.Id.ValueString()
+ }
+
+ isTagNameAvailable, err := checkTagNameAvailability(ctx, r.client, &resp.Diagnostics, tagId, plan.Name.ValueString())
if err != nil {
return
}
- if !isTagNameAvailable {
+ if !isTagNameAvailable && create {
resp.Diagnostics.AddError(
fmt.Sprintf("Error %s Tag: %s", operation, plan.Name.ValueString()),
fmt.Sprintf("Tag with name %s already exist", plan.Name.ValueString()),
@@ -269,9 +276,9 @@ func (r *TagResource) ModifyPlan(ctx context.Context, req resource.ModifyPlanReq
}
}
-func checkTagNameAvailability(ctx context.Context, client *citrixdaasclient.CitrixDaasClient, diagnostics *diag.Diagnostics, tagName string) (bool, error) {
- checkTagNameAvailabilityRequest := client.ApiClient.TagsAPIsDAAS.TagsCheckTagExists(ctx, tagName)
- httpResp, err := citrixdaasclient.AddRequestData(checkTagNameAvailabilityRequest, client).Execute()
+func checkTagNameAvailability(ctx context.Context, client *citrixdaasclient.CitrixDaasClient, diagnostics *diag.Diagnostics, tagId string, tagName string) (bool, error) {
+ getTagRequest := client.ApiClient.TagsAPIsDAAS.TagsGetTag(ctx, tagName)
+ tag, httpResp, err := citrixdaasclient.AddRequestData(getTagRequest, client).Execute()
if err != nil {
if httpResp.StatusCode == http.StatusNotFound {
return true, nil
@@ -283,7 +290,13 @@ func checkTagNameAvailability(ctx context.Context, client *citrixdaasclient.Citr
)
return false, err
}
- return false, nil
+
+ // Only fail availability check if the tag name is already in used by another tag
+ if !strings.EqualFold(tagId, tag.GetId()) {
+ return false, nil
+ }
+
+ return true, nil
}
func getTag(ctx context.Context, client *citrixdaasclient.CitrixDaasClient, diagnostics *diag.Diagnostics, tagNameOrId string) (*citrixorchestration.TagDetailResponseModel, error) {
diff --git a/internal/daas/zone/zone_resource.go b/internal/daas/zone/zone_resource.go
index 1c0f5bc..9d0c61d 100644
--- a/internal/daas/zone/zone_resource.go
+++ b/internal/daas/zone/zone_resource.go
@@ -229,7 +229,7 @@ func (r *zoneResource) Update(ctx context.Context, req resource.UpdateRequest, r
}
editZoneRequestBody.SetName(zoneName)
editZoneRequestBody.SetDescription(plan.Description.ValueString())
- metadata := util.GetMetadataRequestModel(ctx, &resp.Diagnostics, util.ObjectListToTypedArray[util.NameValueStringPairModel](ctx, &resp.Diagnostics, plan.Metadata))
+ metadata := util.GetUpdatedMetadataRequestModel(ctx, &resp.Diagnostics, util.ObjectListToTypedArray[util.NameValueStringPairModel](ctx, &resp.Diagnostics, state.Metadata), util.ObjectListToTypedArray[util.NameValueStringPairModel](ctx, &resp.Diagnostics, plan.Metadata))
editZoneRequestBody.SetMetadata(metadata)
// Update zone
diff --git a/internal/examples/data-sources/citrix_cloud_resource_location/data-source.tf b/internal/examples/data-sources/citrix_cloud_resource_location/data-source.tf
new file mode 100644
index 0000000..5f44776
--- /dev/null
+++ b/internal/examples/data-sources/citrix_cloud_resource_location/data-source.tf
@@ -0,0 +1,4 @@
+# Get Resource Location resource by name
+data "citrix_cloud_resource_location" "example-resource-location" {
+ name = "example-resource-location"
+}
\ No newline at end of file
diff --git a/internal/examples/resources/citrix_gac_settings/resource.tf b/internal/examples/resources/citrix_gac_settings/resource.tf
index d5dab69..e6e18f0 100644
--- a/internal/examples/resources/citrix_gac_settings/resource.tf
+++ b/internal/examples/resources/citrix_gac_settings/resource.tf
@@ -30,7 +30,28 @@ resource "citrix_gac_settings" "test_settings_configuration" {
value_string = "3600000"
}
]
- }
+ },
+ {
+ user_override = false,
+ category = "dazzle",
+ settings = [
+ {
+ name = "Local App Whitelist",
+ local_app_allow_list = [
+ {
+ arguments = "www.citrix.com",
+ name = "Google Chrome",
+ path = "C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe"
+ },
+ {
+ arguments = "www.citrix2.com",
+ name = "Google Chrome2",
+ path = "C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe"
+ },
+ ]
+ }
+ ]
+ },
],
html5 = [
{
@@ -69,6 +90,37 @@ resource "citrix_gac_settings" "test_settings_configuration" {
]
}
]
+ },
+ {
+ user_override = false,
+ category = "Browser",
+ settings = [
+ {
+ name = "managed bookmarks",
+ managed_bookmarks = [
+ {
+ name = "Citrix",
+ url = "https://www.citrix.com/"
+ },
+ {
+ name = "Citrix Workspace app",
+ url = "https://www.citrix.com/products/receiver.html"
+ }
+ ]
+ }
+ ]
+ }
+ ],
+ linux = [
+ {
+ category = "root",
+ user_override = false,
+ settings = [
+ {
+ name = "enable fido2",
+ value_string = "true"
+ }
+ ]
}
]
}
diff --git a/internal/provider/provider.go b/internal/provider/provider.go
index 1ff2a00..e2e8c6e 100644
--- a/internal/provider/provider.go
+++ b/internal/provider/provider.go
@@ -102,6 +102,7 @@ type cvadConfig struct {
ClientId types.String `tfsdk:"client_id"`
ClientSecret types.String `tfsdk:"client_secret"`
DisableSslVerification types.Bool `tfsdk:"disable_ssl_verification"`
+ DisableDaaSClient types.Bool `tfsdk:"disable_daas_client"`
}
type storefrontConfig struct {
@@ -181,6 +182,12 @@ func (p *citrixProvider) Schema(_ context.Context, _ provider.SchemaRequest, res
"\n\n~> **Please Note** [It is recommended to configure a valid certificate for the target DDC](https://docs.citrix.com/en-us/citrix-virtual-apps-desktops/install-configure/install-core/secure-web-studio-deployment) ",
Optional: true,
},
+ "disable_daas_client": schema.BoolAttribute{
+ Description: "Disable Citrix DaaS client setup. " +
+ "\nSet to true to skip Citrix DaaS client setup. " +
+ "\n\n-> **Note** Can be set via Environment Variable **CITRIX_DISABLE_DAAS_CLIENT**.",
+ Optional: true,
+ },
},
},
"storefront_remote_host": schema.SingleNestedAttribute{
@@ -358,6 +365,7 @@ func (p *citrixProvider) Configure(ctx context.Context, req provider.ConfigureRe
environment := os.Getenv("CITRIX_ENVIRONMENT")
customerId := os.Getenv("CITRIX_CUSTOMER_ID")
disableSslVerification := strings.EqualFold(os.Getenv("CITRIX_DISABLE_SSL_VERIFICATION"), "true")
+ disableDaasClient := strings.EqualFold(os.Getenv("CITRIX_DISABLE_DAAS_CLIENT"), "true")
quick_create_host_name := os.Getenv("CITRIX_QUICK_CREATE_HOST_NAME")
if cvadConfig := config.CvadConfig; cvadConfig != nil || (clientId != "" && clientSecret != "") {
@@ -385,9 +393,14 @@ func (p *citrixProvider) Configure(ctx context.Context, req provider.ConfigureRe
if !cvadConfig.DisableSslVerification.IsNull() {
disableSslVerification = cvadConfig.DisableSslVerification.ValueBool()
}
+
+ if !cvadConfig.DisableDaaSClient.IsNull() {
+ disableDaasClient = cvadConfig.DisableDaaSClient.ValueBool()
+ }
+
}
- validateAndInitializeDaaSClient(ctx, resp, client, clientId, clientSecret, hostname, environment, customerId, quick_create_host_name, p.version, disableSslVerification)
+ validateAndInitializeDaaSClient(ctx, resp, client, clientId, clientSecret, hostname, environment, customerId, quick_create_host_name, p.version, disableSslVerification, disableDaasClient)
if resp.Diagnostics.HasError() {
return
}
@@ -441,7 +454,7 @@ func validateAndInitializeStorefrontClient(ctx context.Context, resp *provider.C
client.InitializeStoreFrontClient(ctx, storefront_computer_name, storefront_ad_admin_username, storefront_ad_admin_password, storefront_disable_ssl_verification)
}
-func validateAndInitializeDaaSClient(ctx context.Context, resp *provider.ConfigureResponse, client *citrixclient.CitrixDaasClient, clientId, clientSecret, hostname, environment, customerId, quick_create_host_name, version string, disableSslVerification bool) {
+func validateAndInitializeDaaSClient(ctx context.Context, resp *provider.ConfigureResponse, client *citrixclient.CitrixDaasClient, clientId, clientSecret, hostname, environment, customerId, quick_create_host_name, version string, disableSslVerification bool, disableDaasClient bool) {
if clientId == "" {
resp.Diagnostics.AddAttributeError(
path.Root("cvad_config").AtName("client_id"),
@@ -626,81 +639,63 @@ func validateAndInitializeDaaSClient(ctx context.Context, resp *provider.Configu
tflog.Debug(ctx, "Creating Citrix API client")
userAgent := "citrix-terraform-provider/" + version + " (https://github.com/citrix/terraform-provider-citrix)"
- // Create a new Citrix API client using the configuration values
- httpResp, err := client.InitializeCitrixDaasClient(ctx, authUrl, ccUrl, hostname, customerId, clientId, clientSecret, onPremises, apiGateway, isGov, disableSslVerification, &userAgent, middleware.MiddlewareAuthFunc, middleware.MiddlewareAuthWithCustomerIdHeaderFunc)
+
+ // Setup the Citrix API Client
+ token, httpResp, err := client.SetupCitrixClientsContext(ctx, authUrl, ccUrl, hostname, customerId, clientId, clientSecret, onPremises, apiGateway, isGov, disableSslVerification, &userAgent, middleware.MiddlewareAuthFunc, middleware.MiddlewareAuthWithCustomerIdHeaderFunc)
if err != nil {
- if httpResp != nil {
- if httpResp.StatusCode == 401 {
- resp.Diagnostics.AddError(
- "Invalid credential in provider config",
- "Make sure client_id and client_secret is correct in provider config. ",
- )
- } else if httpResp.StatusCode >= 500 {
- if onPremises {
- resp.Diagnostics.AddError(
- "Citrix DaaS service unavailable",
- "Please check if you can access Web Studio. \n\n"+
- "Please ensure that Citrix Orchestration Service on the target DDC(s) are running reachable from this Machine.",
- )
- } else {
- resp.Diagnostics.AddError(
- "Citrix DaaS service unavailable",
- "The DDC(s) for the customer cannot be reached. Please check if you can access DaaS UI.",
- )
- }
- } else {
- resp.Diagnostics.AddError(
- "Unable to Create Citrix API Client",
- "An unexpected error occurred when creating the Citrix API client. \n\n"+
- "Error: "+err.Error(),
- )
- }
+ if httpResp != nil && httpResp.StatusCode == 401 {
+ resp.Diagnostics.AddError(
+ "Invalid credential in provider config",
+ "Make sure client_id and client_secret are correct in provider config.",
+ )
} else {
- // Case 1: DDC off
- urlErr := new(url.Error)
- opErr := new(net.OpError)
- syscallErr := new(os.SyscallError)
- if errors.As(err, &urlErr) && errors.As(urlErr.Err, &opErr) && errors.As(opErr.Err, &syscallErr) && syscallErr.Err == syscall.Errno(10060) {
- resp.Diagnostics.AddError(
- "DDC(s) cannot be reached",
- "Ensure that the DDC(s) are running. Make sure this machine has proper network routing to reach the DDC(s) and is not blocked by any firewall rules.",
- )
-
- return
- }
-
- // Case 2: Invalid certificate
- cryptoErr := new(tls.CertificateVerificationError)
- errors.As(urlErr.Err, &cryptoErr)
- if len(cryptoErr.UnverifiedCertificates) > 0 {
- resp.Diagnostics.AddError(
- "DDC(s) does not have a valid SSL certificate issued by a trusted Certificate Authority",
- "If you are running against on-premises DDC(s) that does not have an SSL certificate issue by a trusted CA, consider setting \"disable_ssl_verification\" to \"true\" in provider config.",
- )
-
- return
- }
-
- // Case 3: Malformed hostname
- if urlErr != nil && opErr.Err == nil {
- resp.Diagnostics.AddError(
- "Invalid DDC(s) hostname",
- "Please revise the hostname in provider config and make sure it is a valid hostname or IP address.",
- )
-
- return
- }
-
- // Case 4: Catch all other errors
resp.Diagnostics.AddError(
"Unable to Create Citrix API Client",
- "An unexpected error occurred when creating the Citrix API client. \n\n"+
+ "An unexpected error occurred when creating the Citrix API client.\n\n"+
"Error: "+err.Error(),
)
}
-
return
}
+
+ // Initialize the Cloud Clients if not on-premises
+ if !onPremises {
+ client.InitializeCitrixCloudClients(ctx, ccUrl, hostname, middleware.MiddlewareAuthFunc, middleware.MiddlewareAuthWithCustomerIdHeaderFunc)
+ }
+
+ if !disableDaasClient {
+ // Setup the DAAS Client
+ httpResp, err = client.InitializeCitrixDaasClient(ctx, customerId, token, onPremises, apiGateway, disableSslVerification, &userAgent)
+ if err != nil {
+ if httpResp != nil {
+ if httpResp.StatusCode >= 500 {
+ if onPremises {
+ resp.Diagnostics.AddError(
+ "Citrix DaaS service unavailable",
+ "Please check if you can access Web Studio. \n\n"+
+ "Please ensure that Citrix Orchestration Service on the target DDC(s) are running reachable from this Machine.",
+ )
+ } else {
+ resp.Diagnostics.AddError(
+ "Citrix DaaS service unavailable",
+ "The DDC(s) for the customer cannot be reached. Please check if you can access DaaS UI.\n\n"+
+ "Note: If you are running resources that do not require DaaS/CVAD entitlement, you can set `disable_daas_client` to `true` in the provider configuration to skip the DaaS client setup.",
+ )
+ }
+ } else {
+ resp.Diagnostics.AddError(
+ "Unable to Create Citrix API Client",
+ "An unexpected error occurred when creating the Citrix API client.\n\n"+
+ "Error: "+err.Error(),
+ )
+ }
+
+ } else {
+ handleNetworkError(err, resp)
+ }
+ }
+ }
+
// Set Quick Create Client
if quickCreateHostname != "" {
client.InitializeQuickCreateClient(ctx, quickCreateHostname, middleware.MiddlewareAuthFunc)
@@ -711,6 +706,49 @@ func validateAndInitializeDaaSClient(ctx context.Context, resp *provider.Configu
}
}
+func handleNetworkError(err error, resp *provider.ConfigureResponse) {
+ urlErr := new(url.Error)
+ opErr := new(net.OpError)
+ syscallErr := new(os.SyscallError)
+
+ // Case 1: DDC off
+ if errors.As(err, &urlErr) && errors.As(urlErr.Err, &opErr) && errors.As(opErr.Err, &syscallErr) && syscallErr.Err == syscall.Errno(10060) {
+ resp.Diagnostics.AddError(
+ "DDC(s) cannot be reached",
+ "Ensure that the DDC(s) are running. Make sure this machine has proper network routing to reach the DDC(s) and is not blocked by any firewall rules.",
+ )
+ return
+ }
+
+ // Case 2: Invalid certificate
+ cryptoErr := new(tls.CertificateVerificationError)
+ errors.As(urlErr.Err, &cryptoErr)
+ if len(cryptoErr.UnverifiedCertificates) > 0 {
+ resp.Diagnostics.AddError(
+ "DDC(s) does not have a valid SSL certificate issued by a trusted Certificate Authority",
+ "If you are running against on-premises DDC(s) that does not have an SSL certificate issue by a trusted CA, consider setting \"disable_ssl_verification\" to \"true\" in provider config.",
+ )
+ return
+ }
+
+ // Case 3: Malformed hostname
+ if urlErr != nil && opErr.Err == nil {
+ resp.Diagnostics.AddError(
+ "Invalid DDC(s) hostname",
+ "Please revise the hostname in provider config and make sure it is a valid hostname or IP address.",
+ )
+ return
+ }
+
+ // Case 4: Catch all other errors
+ resp.Diagnostics.AddError(
+ "Unable to Create Citrix API Client",
+ "An unexpected error occurred when creating the Citrix API client. \n\n"+
+ "Error: "+err.Error(),
+ )
+ return
+}
+
// DataSources defines the data sources implemented in the provider.
func (p *citrixProvider) DataSources(_ context.Context) []func() datasource.DataSource {
return []func() datasource.DataSource{
@@ -739,6 +777,8 @@ func (p *citrixProvider) DataSources(_ context.Context) []func() datasource.Data
cc_identity_providers.NewOktaIdentityProviderDataSource,
cc_identity_providers.NewGoogleIdentityProviderDataSource,
cc_identity_providers.NewSamlIdentityProviderDataSource,
+ // CC Resource Locations
+ resource_locations.NewResourceLocationsDataSource,
}
}
diff --git a/internal/quickcreate/qcs_account/aws_workspaces_account_resource_model.go b/internal/quickcreate/qcs_account/aws_workspaces_account_resource_model.go
index 4644ca2..cc0d4f8 100644
--- a/internal/quickcreate/qcs_account/aws_workspaces_account_resource_model.go
+++ b/internal/quickcreate/qcs_account/aws_workspaces_account_resource_model.go
@@ -46,6 +46,9 @@ func (AwsWorkspacesAccountResourceModel) GetSchema() schema.Schema {
"aws_account": schema.StringAttribute{
Description: "AWS account number associated with the account.",
Computed: true,
+ PlanModifiers: []planmodifier.String{
+ stringplanmodifier.UseStateForUnknown(),
+ },
},
"aws_region": schema.StringAttribute{
Description: "AWS region the account is associated with.",
diff --git a/internal/quickcreate/qcs_deployment/aws_workspaces_deployment_resource.go b/internal/quickcreate/qcs_deployment/aws_workspaces_deployment_resource.go
index 1a80702..11d064e 100644
--- a/internal/quickcreate/qcs_deployment/aws_workspaces_deployment_resource.go
+++ b/internal/quickcreate/qcs_deployment/aws_workspaces_deployment_resource.go
@@ -608,7 +608,7 @@ func updateMachinesMaintenceMode(ctx context.Context, diagnostics *diag.Diagnost
)
return err
}
- relativeUrl := fmt.Sprintf("/Machines/%s?async=true", brokerMachineId)
+ relativeUrl := fmt.Sprintf("/Machines/%s", brokerMachineId)
var batchRequestItem citrixorchestration.BatchRequestItemModel
batchRequestItem.SetReference(fmt.Sprintf("maintenanceMode%s", strconv.Itoa(index)))
diff --git a/internal/quickcreate/qcs_deployment/aws_workspaces_deployment_resource_model.go b/internal/quickcreate/qcs_deployment/aws_workspaces_deployment_resource_model.go
index 799c3d0..f3c55aa 100644
--- a/internal/quickcreate/qcs_deployment/aws_workspaces_deployment_resource_model.go
+++ b/internal/quickcreate/qcs_deployment/aws_workspaces_deployment_resource_model.go
@@ -133,18 +133,30 @@ func (AwsWorkspacesDeploymentWorkspaceModel) GetSchema() schema.NestedAttributeO
"workspace_id": schema.StringAttribute{
Description: "Id of the AWS WorkSpaces machine.",
Computed: true,
+ PlanModifiers: []planmodifier.String{
+ stringplanmodifier.UseStateForUnknown(),
+ },
},
"machine_id": schema.StringAttribute{
Description: "Id of the machine.",
Computed: true,
+ PlanModifiers: []planmodifier.String{
+ stringplanmodifier.UseStateForUnknown(),
+ },
},
"machine_name": schema.StringAttribute{
Description: "Name of the machine.",
Computed: true,
+ PlanModifiers: []planmodifier.String{
+ stringplanmodifier.UseStateForUnknown(),
+ },
},
"broker_machine_id": schema.StringAttribute{
Description: "GUID identifier of the machine.",
Computed: true,
+ PlanModifiers: []planmodifier.String{
+ stringplanmodifier.UseStateForUnknown(),
+ },
},
},
}
diff --git a/internal/quickcreate/qcs_image/aws_workspaces_image_resource_model.go b/internal/quickcreate/qcs_image/aws_workspaces_image_resource_model.go
index e26b5d5..35de721 100644
--- a/internal/quickcreate/qcs_image/aws_workspaces_image_resource_model.go
+++ b/internal/quickcreate/qcs_image/aws_workspaces_image_resource_model.go
@@ -113,10 +113,16 @@ func (AwsWorkspacesImageResourceModel) GetSchema() schema.Schema {
"tenancy": schema.StringAttribute{
Description: "The type of tenancy of the image.",
Computed: true,
+ PlanModifiers: []planmodifier.String{
+ stringplanmodifier.UseStateForUnknown(),
+ },
},
"state": schema.StringAttribute{
Description: "The state of ingestion process of the image.",
Computed: true,
+ PlanModifiers: []planmodifier.String{
+ stringplanmodifier.UseStateForUnknown(),
+ },
},
},
}
diff --git a/internal/storefront/stf_store/stf_store_service_resource.go b/internal/storefront/stf_store/stf_store_service_resource.go
index a9cbeeb..6904953 100644
--- a/internal/storefront/stf_store/stf_store_service_resource.go
+++ b/internal/storefront/stf_store/stf_store_service_resource.go
@@ -135,8 +135,10 @@ func (r *stfStoreServiceResource) Create(ctx context.Context, req resource.Creat
}
//Create Store Farms
- plan.createStoreFarms(ctx, r.client, &resp.Diagnostics)
- farms, err := plan.getStoreFarms(ctx, r.client, &resp.Diagnostics)
+ var farms []citrixstorefront.StoreFarmModel
+ storeFarm := util.ObjectListToTypedArray[StoreFarm](ctx, &resp.Diagnostics, plan.StoreFarm)
+ createAndUpdateStoreFarms(ctx, r.client, &resp.Diagnostics, farms, siteIdInt, plan.VirtualPath.ValueString(), storeFarm)
+ farms, err = plan.getStoreFarms(ctx, r.client, &resp.Diagnostics)
if err != nil {
return
}
@@ -145,15 +147,15 @@ func (r *stfStoreServiceResource) Create(ctx context.Context, req resource.Creat
plan.RefreshPropertyValues(ctx, &resp.Diagnostics, &StoreServiceDetail, farms)
// Create StoreFarmConfiguration
if !plan.FarmSettings.IsNull() {
-
- err := plan.setFarmSettingsSetRequest(ctx, r.client, &resp.Diagnostics)
+ plannedFarmSettings := util.ObjectValueToTypedObject[FarmSettings](ctx, &resp.Diagnostics, plan.FarmSettings)
+ err := setFarmSettingsSetRequest(ctx, r.client, &resp.Diagnostics, siteIdInt, plan.VirtualPath.ValueString(), plannedFarmSettings)
if err != nil {
return
}
// Get updated STFStoreFarmConfiguration Settings
- getResponse, err := plan.getFarmSettingsGetRequest(ctx, r.client, &resp.Diagnostics)
+ getResponse, err := getFarmSettingsGetRequest(ctx, r.client, siteIdInt, plan.VirtualPath.ValueString())
if err != nil {
resp.Diagnostics.AddError(
"Error fetching STF StoreFarmConfigurations in Create",
@@ -166,12 +168,12 @@ func (r *stfStoreServiceResource) Create(ctx context.Context, req resource.Creat
// Create StoreFront Store Enumeration Options
if !plan.EnumerationOptions.IsNull() {
-
+ enumerationOptions := util.ObjectValueToTypedObject[EnumerationOptions](ctx, &resp.Diagnostics, plan.EnumerationOptions)
// Update Storefront Store Enumeration Options
- plan.setSTFStoreEnumerationOptions(ctx, r.client, &resp.Diagnostics)
+ setSTFStoreEnumerationOptions(ctx, r.client, &resp.Diagnostics, siteIdInt, plan.VirtualPath.ValueString(), enumerationOptions)
// Get updated STFStoreService Enumeration Options
- getResponse, err := plan.getSTFStoreEnumerationOptions(ctx, r.client, &resp.Diagnostics)
+ getResponse, err := getSTFStoreEnumerationOptions(ctx, r.client, siteIdInt, plan.VirtualPath.ValueString())
if err != nil {
resp.Diagnostics.AddError(
"Error fetching StoreFront Store Enumeration Options",
@@ -186,9 +188,10 @@ func (r *stfStoreServiceResource) Create(ctx context.Context, req resource.Creat
// Set PNA properties
if !plan.PNA.IsNull() {
- plan.setSTFStorePNA(ctx, r.client, &resp.Diagnostics)
+ pna := util.ObjectValueToTypedObject[PNA](ctx, &resp.Diagnostics, plan.PNA)
+ setSTFStorePNA(ctx, r.client, &resp.Diagnostics, siteIdInt, plan.VirtualPath.ValueString(), pna)
- updatedPna, err := plan.getSTFStorePNA(ctx, r.client, &resp.Diagnostics)
+ updatedPna, err := getSTFStorePNA(ctx, r.client, &resp.Diagnostics, siteIdInt, plan.VirtualPath.ValueString())
if err != nil {
resp.Diagnostics.AddError(
"Error fetching updated PNA for StoreFront StoreService",
@@ -200,12 +203,13 @@ func (r *stfStoreServiceResource) Create(ctx context.Context, req resource.Creat
// Create StoreFront Store Launch Options
if !plan.LaunchOptions.IsNull() {
+ launchOptions := util.ObjectValueToTypedObject[LaunchOptions](ctx, &resp.Diagnostics, plan.LaunchOptions)
// Update Storefront Store Launch Options
- plan.setSTFStoreLaunchOptions(ctx, r.client, &resp.Diagnostics)
+ setSTFStoreLaunchOptions(ctx, r.client, &resp.Diagnostics, siteIdInt, plan.VirtualPath.ValueString(), launchOptions)
// Get updated STFStoreService Launch Options
- getResponse, err := plan.getSTFStoreLaunchOptions(ctx, r.client)
+ getResponse, err := getSTFStoreLaunchOptions(ctx, r.client, siteIdInt, plan.VirtualPath.ValueString())
if err != nil {
resp.Diagnostics.AddError(
"Error fetching StoreFront Store Launch Options",
@@ -221,13 +225,14 @@ func (r *stfStoreServiceResource) Create(ctx context.Context, req resource.Creat
// Create StoreFront Roaming Account
if !plan.RoamingAccount.IsNull() {
+ roamingAccount := util.ObjectValueToTypedObject[RoamingAccount](ctx, &resp.Diagnostics, plan.RoamingAccount)
// Update Storefront Roaming Account
- err := plan.setSTFRoamingAccount(ctx, r.client, &resp.Diagnostics)
+ err := setSTFRoamingAccount(ctx, r.client, &resp.Diagnostics, siteIdInt, plan.VirtualPath.ValueString(), roamingAccount)
if err != nil {
return
}
// Get updated Roaming Account
- getResponse, err := plan.getSTFRoamingAccount(ctx, r.client, &resp.Diagnostics)
+ getResponse, err := getSTFRoamingAccount(ctx, r.client, siteIdInt, plan.VirtualPath.ValueString())
if err != nil {
resp.Diagnostics.AddError(
"Error fetching STF StoreFront Roaming Account",
@@ -261,7 +266,16 @@ func (r *stfStoreServiceResource) Read(ctx context.Context, req resource.ReadReq
return
}
- STFStoreService, err := state.getSTFStoreService(ctx, r.client, &resp.Diagnostics)
+ siteIdInt, err := strconv.ParseInt(state.SiteId.ValueString(), 10, 64)
+ if err != nil {
+ resp.Diagnostics.AddError(
+ "Error deleting StoreFront Store Service ",
+ "Error message: "+err.Error(),
+ )
+ return
+ }
+
+ STFStoreService, err := getSTFStoreService(ctx, r.client, siteIdInt, state.VirtualPath.ValueString())
if err != nil {
return
}
@@ -282,7 +296,7 @@ func (r *stfStoreServiceResource) Read(ctx context.Context, req resource.ReadReq
// Refresh StoreFarmConfiguration
if !state.FarmSettings.IsNull() {
// Get updated STFStoreFarmConfiguration Settings
- getResponse, err := state.getFarmSettingsGetRequest(ctx, r.client, &resp.Diagnostics)
+ getResponse, err := getFarmSettingsGetRequest(ctx, r.client, siteIdInt, state.VirtualPath.ValueString())
if err != nil {
resp.Diagnostics.AddError(
"Error fetching STF StoreFarmConfigurations in Read",
@@ -295,7 +309,7 @@ func (r *stfStoreServiceResource) Read(ctx context.Context, req resource.ReadReq
//Refresh Storefront StoreService Enumerations
if !state.EnumerationOptions.IsNull() {
// Get STFStoreService Enumeration Options
- getResponse, err := state.getSTFStoreEnumerationOptions(ctx, r.client, &resp.Diagnostics)
+ getResponse, err := getSTFStoreEnumerationOptions(ctx, r.client, siteIdInt, state.VirtualPath.ValueString())
if err != nil {
resp.Diagnostics.AddError(
"Error fetching StoreFront Store Enumeration Options",
@@ -309,7 +323,7 @@ func (r *stfStoreServiceResource) Read(ctx context.Context, req resource.ReadReq
//Refresh Storefront StoreService Launch Options
if !state.LaunchOptions.IsNull() {
// Get STFStoreService Launch Options
- getResponse, err := state.getSTFStoreLaunchOptions(ctx, r.client)
+ getResponse, err := getSTFStoreLaunchOptions(ctx, r.client, siteIdInt, state.VirtualPath.ValueString())
if err != nil {
resp.Diagnostics.AddError(
"Error fetching StoreFront Store Launch Options",
@@ -322,7 +336,7 @@ func (r *stfStoreServiceResource) Read(ctx context.Context, req resource.ReadReq
// Fetch Pna
if !state.PNA.IsNull() {
- updatedPna, err := state.getSTFStorePNA(ctx, r.client, &resp.Diagnostics)
+ updatedPna, err := getSTFStorePNA(ctx, r.client, &resp.Diagnostics, siteIdInt, state.VirtualPath.ValueString())
if err != nil {
resp.Diagnostics.AddError(
"Error fetching PNA for StoreFront StoreService",
@@ -335,7 +349,7 @@ func (r *stfStoreServiceResource) Read(ctx context.Context, req resource.ReadReq
// Fetch Roaming Account
if !state.RoamingAccount.IsNull() {
// Get updated STFStoreFarmConfiguration Settings
- getResponse, err := state.getSTFRoamingAccount(ctx, r.client, &resp.Diagnostics)
+ getResponse, err := getSTFRoamingAccount(ctx, r.client, siteIdInt, state.VirtualPath.ValueString())
if err != nil {
resp.Diagnostics.AddError(
"Error fetching STF Roaming Account",
@@ -376,7 +390,7 @@ func (r *stfStoreServiceResource) Update(ctx context.Context, req resource.Updat
return
}
// Get refreshed STFStoreService
- _, err = plan.getSTFStoreService(ctx, r.client, &resp.Diagnostics)
+ _, err = getSTFStoreService(ctx, r.client, siteIdInt, plan.VirtualPath.ValueString())
if err != nil {
return
}
@@ -397,19 +411,21 @@ func (r *stfStoreServiceResource) Update(ctx context.Context, req resource.Updat
}
// Fetch updated STFStoreService
- updatedSTFStoreService, err := plan.getSTFStoreService(ctx, r.client, &resp.Diagnostics)
+ updatedSTFStoreService, err := getSTFStoreService(ctx, r.client, siteIdInt, plan.VirtualPath.ValueString())
if err != nil {
return
}
var state STFStoreServiceResourceModel
req.State.Get(ctx, &state)
+
existingFarms, err := state.getStoreFarms(ctx, r.client, &resp.Diagnostics)
if err != nil {
return
}
//Update farms
- plan.updateStoreFarms(ctx, r.client, &resp.Diagnostics, existingFarms)
+ storeFarms := util.ObjectListToTypedArray[StoreFarm](ctx, &resp.Diagnostics, plan.StoreFarm)
+ createAndUpdateStoreFarms(ctx, r.client, &resp.Diagnostics, existingFarms, siteIdInt, plan.VirtualPath.ValueString(), storeFarms)
farms, err := plan.getStoreFarms(ctx, r.client, &resp.Diagnostics)
if err != nil {
return
@@ -420,15 +436,15 @@ func (r *stfStoreServiceResource) Update(ctx context.Context, req resource.Updat
// Update StoreFarmConfiguration
if !plan.FarmSettings.IsNull() {
-
- err := plan.setFarmSettingsSetRequest(ctx, r.client, &resp.Diagnostics)
+ plannedFarmSettings := util.ObjectValueToTypedObject[FarmSettings](ctx, &resp.Diagnostics, plan.FarmSettings)
+ err := setFarmSettingsSetRequest(ctx, r.client, &resp.Diagnostics, siteIdInt, plan.VirtualPath.ValueString(), plannedFarmSettings)
if err != nil {
return
}
// Get updated STFStoreFarmConfiguration Settings
- getResponse, err := plan.getFarmSettingsGetRequest(ctx, r.client, &resp.Diagnostics)
+ getResponse, err := getFarmSettingsGetRequest(ctx, r.client, siteIdInt, plan.VirtualPath.ValueString())
if err != nil {
resp.Diagnostics.AddError(
"Error fetching STF StoreFarmConfigurations in Update",
@@ -441,12 +457,12 @@ func (r *stfStoreServiceResource) Update(ctx context.Context, req resource.Updat
// updated STFStoreService Enumeration Options
if !plan.EnumerationOptions.IsNull() {
-
+ enumerationOptions := util.ObjectValueToTypedObject[EnumerationOptions](ctx, &resp.Diagnostics, plan.EnumerationOptions)
// Update Storefront Store Enumeration Options
- plan.setSTFStoreEnumerationOptions(ctx, r.client, &resp.Diagnostics)
+ setSTFStoreEnumerationOptions(ctx, r.client, &resp.Diagnostics, siteIdInt, plan.VirtualPath.ValueString(), enumerationOptions)
// Get updated STFStoreService Enumeration Options
- getResponse, err := plan.getSTFStoreEnumerationOptions(ctx, r.client, &resp.Diagnostics)
+ getResponse, err := getSTFStoreEnumerationOptions(ctx, r.client, siteIdInt, plan.VirtualPath.ValueString())
if err != nil {
resp.Diagnostics.AddError(
"Error fetching StoreFront Store Enumeration Options",
@@ -459,9 +475,10 @@ func (r *stfStoreServiceResource) Update(ctx context.Context, req resource.Updat
// Set PNA properties
if !plan.PNA.IsNull() {
- plan.setSTFStorePNA(ctx, r.client, &resp.Diagnostics)
+ pna := util.ObjectValueToTypedObject[PNA](ctx, &resp.Diagnostics, plan.PNA)
+ setSTFStorePNA(ctx, r.client, &resp.Diagnostics, siteIdInt, plan.VirtualPath.ValueString(), pna)
- updatedPna, err := plan.getSTFStorePNA(ctx, r.client, &resp.Diagnostics)
+ updatedPna, err := getSTFStorePNA(ctx, r.client, &resp.Diagnostics, siteIdInt, plan.VirtualPath.ValueString())
if err != nil {
resp.Diagnostics.AddError(
"Error fetching updated PNA for StoreFront StoreService",
@@ -473,12 +490,12 @@ func (r *stfStoreServiceResource) Update(ctx context.Context, req resource.Updat
// Update StoreFront Store Launch Options
if !plan.LaunchOptions.IsNull() {
-
+ launchOptions := util.ObjectValueToTypedObject[LaunchOptions](ctx, &resp.Diagnostics, plan.LaunchOptions)
// Update Storefront Store Launch Options
- plan.setSTFStoreLaunchOptions(ctx, r.client, &resp.Diagnostics)
+ setSTFStoreLaunchOptions(ctx, r.client, &resp.Diagnostics, siteIdInt, plan.VirtualPath.ValueString(), launchOptions)
// Get updated STFStoreService Launch Options
- getResponse, err := plan.getSTFStoreLaunchOptions(ctx, r.client)
+ getResponse, err := getSTFStoreLaunchOptions(ctx, r.client, siteIdInt, plan.VirtualPath.ValueString())
if err != nil {
resp.Diagnostics.AddError(
"Error fetching StoreFront Store Launch Options",
@@ -494,15 +511,16 @@ func (r *stfStoreServiceResource) Update(ctx context.Context, req resource.Updat
// Update StoreFront Roaming Account
if !plan.RoamingAccount.IsNull() {
+ roamingAccount := util.ObjectValueToTypedObject[RoamingAccount](ctx, &resp.Diagnostics, plan.RoamingAccount)
// Update Storefront Roaming Account
- update_err := plan.setSTFRoamingAccount(ctx, r.client, &resp.Diagnostics)
+ update_err := setSTFRoamingAccount(ctx, r.client, &resp.Diagnostics, siteIdInt, plan.VirtualPath.ValueString(), roamingAccount)
if update_err != nil {
return
}
// Get updated Roaming Account
- getResponse, err := plan.getSTFRoamingAccount(ctx, r.client, &resp.Diagnostics)
+ getResponse, err := getSTFRoamingAccount(ctx, r.client, siteIdInt, plan.VirtualPath.ValueString())
if err != nil {
resp.Diagnostics.AddError(
"Error fetching STF StoreFront Roaming Account",
@@ -594,20 +612,12 @@ func (r *stfStoreServiceResource) ImportState(ctx context.Context, req resource.
}
// Gets the STFStoreService and logs any errors
-func (plan STFStoreServiceResourceModel) getSTFStoreService(ctx context.Context, client *citrixdaasclient.CitrixDaasClient, diagnostics *diag.Diagnostics) (*citrixstorefront.STFStoreDetailModel, error) {
+func getSTFStoreService(ctx context.Context, client *citrixdaasclient.CitrixDaasClient, siteIdInt int64, VirtualPath string) (*citrixstorefront.STFStoreDetailModel, error) {
var body citrixstorefront.GetSTFStoreRequestModel
- if !plan.SiteId.IsNull() {
- siteIdInt, err := strconv.ParseInt(plan.SiteId.ValueString(), 10, 64)
- if err != nil {
- diagnostics.AddError(
- "Error fetching state of StoreFront StoreService ",
- "Error message: "+err.Error(),
- )
- return nil, err
- }
- body.SetSiteId(siteIdInt)
- }
- body.SetVirtualPath(plan.VirtualPath.ValueString())
+
+ body.SetSiteId(siteIdInt)
+
+ body.SetVirtualPath(VirtualPath)
getSTFStoreServiceRequest := client.StorefrontClient.StoreSF.STFStoreGetSTFStore(ctx, body)
// Get refreshed STFStoreService properties from Orchestration
@@ -621,18 +631,9 @@ func (plan STFStoreServiceResourceModel) getSTFStoreService(ctx context.Context,
return &STFStoreService, nil
}
-func (plan STFStoreServiceResourceModel) setFarmSettingsSetRequest(ctx context.Context, client *citrixdaasclient.CitrixDaasClient, diagnostics *diag.Diagnostics) error {
+func setFarmSettingsSetRequest(ctx context.Context, client *citrixdaasclient.CitrixDaasClient, diagnostics *diag.Diagnostics, siteId int64, VirtualPath string, plannedFarmSettings FarmSettings) error {
var farmSettingBody citrixstorefront.SetStoreFarmConfigurationRequestModel
- siteIdInt, err := strconv.ParseInt(plan.SiteId.ValueString(), 10, 64)
- if err != nil {
- diagnostics.AddError(
- "Error setting farm_settings for StoreFront StoreService ",
- "Error message: "+err.Error(),
- )
- return err
- }
- plannedFarmSettings := util.ObjectValueToTypedObject[FarmSettings](ctx, diagnostics, plan.FarmSettings)
farmSettingBody.SetEnableFileTypeAssociation(plannedFarmSettings.EnableFileTypeAssociation.ValueBool())
farmSettingBody.SetCommunicationTimeout(plannedFarmSettings.CommunicationTimeout.ValueString())
farmSettingBody.SetConnectionTimeout(plannedFarmSettings.ConnectionTimeout.ValueString())
@@ -647,14 +648,14 @@ func (plan STFStoreServiceResourceModel) setFarmSettingsSetRequest(ctx context.C
// Generate STFStoreFarmConfig body
getSTFStoreServiceBody := citrixstorefront.GetSTFStoreRequestModel{}
- getSTFStoreServiceBody.SetSiteId(siteIdInt)
- getSTFStoreServiceBody.SetVirtualPath(plan.VirtualPath.ValueString())
+ getSTFStoreServiceBody.SetSiteId(siteId)
+ getSTFStoreServiceBody.SetVirtualPath(VirtualPath)
// Create the client request to Set StoreFront Enumeration Options
farmSettingsRequest := client.StorefrontClient.StoreSF.STFStoreFarmSetSTFStoreConfiguration(ctx, farmSettingBody, getSTFStoreServiceBody)
// Execute the request
- _, err = farmSettingsRequest.Execute()
+ _, err := farmSettingsRequest.Execute()
if err != nil {
diagnostics.AddError(
"Error creating StoreFront Store Farm Configurations",
@@ -667,19 +668,12 @@ func (plan STFStoreServiceResourceModel) setFarmSettingsSetRequest(ctx context.C
}
// Get STF-StoreFarm Config
-func (plan STFStoreServiceResourceModel) getFarmSettingsGetRequest(ctx context.Context, client *citrixdaasclient.CitrixDaasClient, diagnostics *diag.Diagnostics) (*citrixstorefront.StoreFarmConfigurationResponseModel, error) {
+func getFarmSettingsGetRequest(ctx context.Context, client *citrixdaasclient.CitrixDaasClient, siteId int64, VirtualPath string) (*citrixstorefront.StoreFarmConfigurationResponseModel, error) {
// Generate farmSetting body
- siteIdInt, err := strconv.ParseInt(plan.SiteId.ValueString(), 10, 64)
- if err != nil {
- diagnostics.AddError(
- "Error setting farm_settings for StoreFront StoreService ",
- "Error message: "+err.Error(),
- )
- return nil, err
- }
+
getFarmSettingsBody := citrixstorefront.GetSTFStoreRequestModel{}
- getFarmSettingsBody.SetSiteId(siteIdInt)
- getFarmSettingsBody.SetVirtualPath(plan.VirtualPath.ValueString())
+ getFarmSettingsBody.SetSiteId(siteId)
+ getFarmSettingsBody.SetVirtualPath(VirtualPath)
// Get Request for STF StoreFarm Configurations
farmSettingsRequest := client.StorefrontClient.StoreSF.STFStoreFarmGetStoreConfiguration(ctx, getFarmSettingsBody)
@@ -689,20 +683,11 @@ func (plan STFStoreServiceResourceModel) getFarmSettingsGetRequest(ctx context.C
return &getResponse, err
}
-func (plan STFStoreServiceResourceModel) getSTFStorePNA(ctx context.Context, client *citrixdaasclient.CitrixDaasClient, diagnostics *diag.Diagnostics) (*citrixstorefront.STFPna, error) {
+func getSTFStorePNA(ctx context.Context, client *citrixdaasclient.CitrixDaasClient, diagnostics *diag.Diagnostics, siteIdInt int64, VirtualPath string) (*citrixstorefront.STFPna, error) {
var storeBody citrixstorefront.GetSTFStoreRequestModel
- siteIdInt, err := strconv.ParseInt(plan.SiteId.ValueString(), 10, 64)
- if err != nil {
- diagnostics.AddError(
- "Error fetching PNA for Store Service ",
- "Error message: "+err.Error(),
- )
- return nil, err
- }
-
storeBody.SetSiteId(siteIdInt)
- storeBody.SetVirtualPath(plan.VirtualPath.ValueString())
+ storeBody.SetVirtualPath(VirtualPath)
// Fetch updated PNA
updatedPna, err := client.StorefrontClient.StoreSF.STFStoreGetStorePna(ctx, storeBody).Execute()
if err != nil {
@@ -715,20 +700,12 @@ func (plan STFStoreServiceResourceModel) getSTFStorePNA(ctx context.Context, cli
}
// Set STF Store PNA
-func (plan STFStoreServiceResourceModel) setSTFStorePNA(ctx context.Context, client *citrixdaasclient.CitrixDaasClient, diagnostics *diag.Diagnostics) error {
- siteIdInt, err := strconv.ParseInt(plan.SiteId.ValueString(), 10, 64)
- if err != nil {
- diagnostics.AddError(
- "Error setting PNA for Store Service ",
- "Error message: "+err.Error(),
- )
- return err
- }
+func setSTFStorePNA(ctx context.Context, client *citrixdaasclient.CitrixDaasClient, diagnostics *diag.Diagnostics, siteIdInt int64, VirtualPath string, pna PNA) error {
+
var storeBody citrixstorefront.GetSTFStoreRequestModel
storeBody.SetSiteId(siteIdInt)
- storeBody.SetVirtualPath(plan.VirtualPath.ValueString())
+ storeBody.SetVirtualPath(VirtualPath)
- pna := util.ObjectValueToTypedObject[PNA](ctx, diagnostics, plan.PNA)
if pna.Enable.ValueBool() {
// Disable PNA first because of the existing problem from PNA cmdlet
disablePnaRequest := client.StorefrontClient.StoreSF.STFStoreDisableStorePna(ctx, storeBody)
@@ -765,18 +742,11 @@ func (plan STFStoreServiceResourceModel) setSTFStorePNA(ctx context.Context, cli
}
// Set Storefront Store Enumeration Options
-func (plan STFStoreServiceResourceModel) setSTFStoreEnumerationOptions(ctx context.Context, client *citrixdaasclient.CitrixDaasClient, diagnostics *diag.Diagnostics) error {
- siteIdInt, err := strconv.ParseInt(plan.SiteId.ValueString(), 10, 64)
- if err != nil {
- diagnostics.AddError(
- "Error setting StoreFront Store Enumeration Options",
- "Error message: "+err.Error(),
- )
- return err
- }
+func setSTFStoreEnumerationOptions(ctx context.Context, client *citrixdaasclient.CitrixDaasClient, diagnostics *diag.Diagnostics, siteId int64, VirtualPath string, enumerationOptions EnumerationOptions) error {
+
// Generate API request body
var enumerationOptionsBody citrixstorefront.SetSTFStoreEnumerationOptionsRequestModel
- enumerationOptions := util.ObjectValueToTypedObject[EnumerationOptions](ctx, diagnostics, plan.EnumerationOptions)
+
if !enumerationOptions.EnhancedEnumeration.IsNull() {
enumerationOptionsBody.SetEnhancedEnumeration(enumerationOptions.EnhancedEnumeration.ValueBool())
}
@@ -795,14 +765,14 @@ func (plan STFStoreServiceResourceModel) setSTFStoreEnumerationOptions(ctx conte
// Generate getSTFStoreService body
getSTFStoreServiceBody := citrixstorefront.GetSTFStoreRequestModel{}
- getSTFStoreServiceBody.SetSiteId(siteIdInt)
- getSTFStoreServiceBody.SetVirtualPath(plan.VirtualPath.ValueString())
+ getSTFStoreServiceBody.SetSiteId(siteId)
+ getSTFStoreServiceBody.SetVirtualPath(VirtualPath)
// Create the client request to Set StoreFront Enumeration Options
enumerationOptionsRequest := client.StorefrontClient.StoreSF.STFStoreSetSTFStoreEnumerationOptions(ctx, enumerationOptionsBody, getSTFStoreServiceBody)
// Execute the request
- _, err = enumerationOptionsRequest.Execute()
+ _, err := enumerationOptionsRequest.Execute()
if err != nil {
diagnostics.AddError(
"Error setting StoreFront Store Enumeration Options",
@@ -814,19 +784,12 @@ func (plan STFStoreServiceResourceModel) setSTFStoreEnumerationOptions(ctx conte
}
// Get Storefront store Enumeration Options
-func (plan STFStoreServiceResourceModel) getSTFStoreEnumerationOptions(ctx context.Context, client *citrixdaasclient.CitrixDaasClient, diagnostics *diag.Diagnostics) (*citrixstorefront.GetSTFStoreEnumerationOptionsResponseModel, error) {
- siteIdInt, err := strconv.ParseInt(plan.SiteId.ValueString(), 10, 64)
- if err != nil {
- diagnostics.AddError(
- "Error setting StoreFront Store Enumeration Options",
- "Error message: "+err.Error(),
- )
- return nil, err
- }
+func getSTFStoreEnumerationOptions(ctx context.Context, client *citrixdaasclient.CitrixDaasClient, siteId int64, VirtualPath string) (*citrixstorefront.GetSTFStoreEnumerationOptionsResponseModel, error) {
+
// Generate getSTFStoreService body
getSTFStoreServiceBody := citrixstorefront.GetSTFStoreRequestModel{}
- getSTFStoreServiceBody.SetSiteId(siteIdInt)
- getSTFStoreServiceBody.SetVirtualPath(plan.VirtualPath.ValueString())
+ getSTFStoreServiceBody.SetSiteId(siteId)
+ getSTFStoreServiceBody.SetVirtualPath(VirtualPath)
// Create the client request to Get StoreFront Enumeration Options
enumerationOptionsRequest := client.StorefrontClient.StoreSF.STFStoreGetSTFStoreEnumerationOptions(ctx, getSTFStoreServiceBody)
@@ -837,18 +800,10 @@ func (plan STFStoreServiceResourceModel) getSTFStoreEnumerationOptions(ctx conte
}
// Set Storefront Store Launch Options
-func (plan STFStoreServiceResourceModel) setSTFStoreLaunchOptions(ctx context.Context, client *citrixdaasclient.CitrixDaasClient, diagnostics *diag.Diagnostics) error {
- siteIdInt, err := strconv.ParseInt(plan.SiteId.ValueString(), 10, 64)
- if err != nil {
- diagnostics.AddError(
- "Error setting StoreFront Store Launch Options",
- "Error message: "+err.Error(),
- )
- return err
- }
+func setSTFStoreLaunchOptions(ctx context.Context, client *citrixdaasclient.CitrixDaasClient, diagnostics *diag.Diagnostics, siteId int64, VirtualPath string, launchOptions LaunchOptions) error {
+
// Generate API request body
var launchOptionsBody citrixstorefront.SetSTFStoreLaunchOptionsRequestModel
- launchOptions := util.ObjectValueToTypedObject[LaunchOptions](ctx, diagnostics, plan.LaunchOptions)
if !launchOptions.AddressResolutionType.IsNull() {
launchOptionsBody.SetAddressResolutionType(launchOptions.AddressResolutionType.ValueString())
@@ -892,14 +847,14 @@ func (plan STFStoreServiceResourceModel) setSTFStoreLaunchOptions(ctx context.Co
// Generate getSTFStoreService body
getSTFStoreServiceBody := citrixstorefront.GetSTFStoreRequestModel{}
- getSTFStoreServiceBody.SetSiteId(siteIdInt)
- getSTFStoreServiceBody.SetVirtualPath(plan.VirtualPath.ValueString())
+ getSTFStoreServiceBody.SetSiteId(siteId)
+ getSTFStoreServiceBody.SetVirtualPath(VirtualPath)
// Create the client request to Set StoreFront Enumeration Options
launchOptionsRequest := client.StorefrontClient.StoreSF.STFStoreSetSTFStoreLaunchOptions(ctx, launchOptionsBody, getSTFStoreServiceBody)
// Execute the request
- err = launchOptionsRequest.Execute()
+ err := launchOptionsRequest.Execute()
if err != nil {
diagnostics.AddError(
"Error setting StoreFront Store Launch Options",
@@ -911,11 +866,11 @@ func (plan STFStoreServiceResourceModel) setSTFStoreLaunchOptions(ctx context.Co
}
// Get Storefront store Launch Options
-func (plan *STFStoreServiceResourceModel) getSTFStoreLaunchOptions(ctx context.Context, client *citrixdaasclient.CitrixDaasClient) (*citrixstorefront.GetSTFStoreLaunchOptionsResponseModel, error) {
+func getSTFStoreLaunchOptions(ctx context.Context, client *citrixdaasclient.CitrixDaasClient, siteId int64, VirtualPath string) (*citrixstorefront.GetSTFStoreLaunchOptionsResponseModel, error) {
// Generate getSTFStoreService body
getSTFStoreServiceBody := citrixstorefront.GetSTFStoreRequestModel{}
-
- getSTFStoreServiceBody.SetVirtualPath(plan.VirtualPath.ValueString())
+ getSTFStoreServiceBody.SetSiteId(siteId)
+ getSTFStoreServiceBody.SetVirtualPath(VirtualPath)
// Create the client request to Get StoreFront Launch Options
launchOptionsRequest := client.StorefrontClient.StoreSF.STFStoreGetSTFStoreLaunchOptions(ctx, getSTFStoreServiceBody)
@@ -926,17 +881,9 @@ func (plan *STFStoreServiceResourceModel) getSTFStoreLaunchOptions(ctx context.C
return &getResponse, err
}
-func (plan STFStoreServiceResourceModel) setSTFRoamingAccount(ctx context.Context, client *citrixdaasclient.CitrixDaasClient, diagnostics *diag.Diagnostics) error {
- siteIdInt, err := strconv.ParseInt(plan.SiteId.ValueString(), 10, 64)
- if err != nil {
- diagnostics.AddError(
- "Error creating StoreFront StoreService ",
- "Error message: "+err.Error(),
- )
- return err
- }
+func setSTFRoamingAccount(ctx context.Context, client *citrixdaasclient.CitrixDaasClient, diagnostics *diag.Diagnostics, siteId int64, VirtualPath string, roamingAccountSettings RoamingAccount) error {
+
var roamingAccountSettingsBody citrixstorefront.SetSTFRoamingAccountRequestModel
- roamingAccountSettings := util.ObjectValueToTypedObject[RoamingAccount](ctx, diagnostics, plan.RoamingAccount)
if !roamingAccountSettings.Published.IsNull() {
roamingAccountSettingsBody.SetPublished(roamingAccountSettings.Published.ValueBool())
@@ -944,14 +891,14 @@ func (plan STFStoreServiceResourceModel) setSTFRoamingAccount(ctx context.Contex
// Generate getSTFStoreService body
getSTFStoreServiceBody := citrixstorefront.GetSTFStoreRequestModel{}
- getSTFStoreServiceBody.SetSiteId(siteIdInt)
- getSTFStoreServiceBody.SetVirtualPath(plan.VirtualPath.ValueString())
+ getSTFStoreServiceBody.SetSiteId(siteId)
+ getSTFStoreServiceBody.SetVirtualPath(VirtualPath)
// Create the client request to Set Storefront Gateway Settings
gatewaySerivceRequest := client.StorefrontClient.StoreSF.STFRoamingAccountSet(ctx, roamingAccountSettingsBody, getSTFStoreServiceBody)
// Execute the request
- err = gatewaySerivceRequest.Execute()
+ err := gatewaySerivceRequest.Execute()
if err != nil {
diagnostics.AddError(
"Error setting StoreFront Store Gateway Settings",
@@ -963,19 +910,12 @@ func (plan STFStoreServiceResourceModel) setSTFRoamingAccount(ctx context.Contex
}
-func (plan STFStoreServiceResourceModel) getSTFRoamingAccount(ctx context.Context, client *citrixdaasclient.CitrixDaasClient, diagnostics *diag.Diagnostics) (*citrixstorefront.GetSTFRoamingAccountResponseModel, error) {
- siteIdInt, err := strconv.ParseInt(plan.SiteId.ValueString(), 10, 64)
- if err != nil {
- diagnostics.AddError(
- "Error creating StoreFront StoreService ",
- "Error message: "+err.Error(),
- )
- return nil, err
- }
+func getSTFRoamingAccount(ctx context.Context, client *citrixdaasclient.CitrixDaasClient, siteId int64, VirtualPath string) (*citrixstorefront.GetSTFRoamingAccountResponseModel, error) {
+
// Generate getSTFStoreService body
getSTFStoreServiceBody := citrixstorefront.GetSTFStoreRequestModel{}
- getSTFStoreServiceBody.SetSiteId(siteIdInt)
- getSTFStoreServiceBody.SetVirtualPath(plan.VirtualPath.ValueString())
+ getSTFStoreServiceBody.SetSiteId(siteId)
+ getSTFStoreServiceBody.SetVirtualPath(VirtualPath)
// Create the client request to Get StoreFront Gateway Settings
roamingAccRequest := client.StorefrontClient.StoreSF.STFRoamingAccountGet(ctx, getSTFStoreServiceBody)
@@ -986,62 +926,32 @@ func (plan STFStoreServiceResourceModel) getSTFRoamingAccount(ctx context.Contex
return &getResponse, err
}
-func (plan STFStoreServiceResourceModel) createStoreFarms(ctx context.Context, client *citrixdaasclient.CitrixDaasClient, diagnostics *diag.Diagnostics) error {
- siteIdInt, err := strconv.ParseInt(plan.SiteId.ValueString(), 10, 64)
- if err != nil {
- diagnostics.AddError(
- "Error getting StoreFront StoreService SiteId",
- "Error message: "+err.Error(),
- )
- return err
- }
+func createAndUpdateStoreFarms(ctx context.Context, client *citrixdaasclient.CitrixDaasClient, diagnostics *diag.Diagnostics, existingFarms []citrixstorefront.StoreFarmModel, siteId int64, VirtualPath string, farms []StoreFarm) error {
- farms := util.ObjectListToTypedArray[StoreFarm](ctx, diagnostics, plan.StoreFarm)
+ //set Store for StoreFarm Set Request
+ getStoreBody := citrixstorefront.GetSTFStoreRequestModel{}
+ getStoreBody.SetSiteId(siteId)
+ getStoreBody.SetVirtualPath(VirtualPath)
+
+ planFarmArray := []string{}
+ existingFarmArray := []string{}
for _, farm := range farms {
- var storeFarmSetBody = farm.buildStoreFarmBody(ctx, client, diagnostics)
- //set Store for StoreFarm Create Request
- getStoreBody := citrixstorefront.GetSTFStoreRequestModel{}
- getStoreBody.SetSiteId(siteIdInt)
- getStoreBody.SetVirtualPath(plan.VirtualPath.ValueString())
-
- createStoreFarmRequest := client.StorefrontClient.StoreSF.STFStoreNewStoreFarm(ctx, storeFarmSetBody, getStoreBody)
- _, err := createStoreFarmRequest.Execute()
- if err != nil {
- diagnostics.AddError(
- "Error creating Store Farm",
- "Error message: "+err.Error(),
- )
- return err
- }
+ planFarmArray = append(planFarmArray, farm.FarmName.ValueString())
}
- return nil
-}
-func (plan STFStoreServiceResourceModel) updateStoreFarms(ctx context.Context, client *citrixdaasclient.CitrixDaasClient, diagnostics *diag.Diagnostics, existingFarms []citrixstorefront.StoreFarmModel) error {
- siteIdInt, err := strconv.ParseInt(plan.SiteId.ValueString(), 10, 64)
- if err != nil {
- diagnostics.AddError(
- "Error getting StoreFront StoreService SiteId",
- "Error message: "+err.Error(),
- )
- return err
- }
- //set Store for StoreFarm Set Request
- getStoreBody := citrixstorefront.GetSTFStoreRequestModel{}
- getStoreBody.SetSiteId(siteIdInt)
- getStoreBody.SetVirtualPath(plan.VirtualPath.ValueString())
- farms := util.ObjectListToTypedArray[StoreFarm](ctx, diagnostics, plan.StoreFarm)
- //remove farms that are not in the plan
+ // Delete Roaming Farms that are in not in the plan but are in the existing farms
for _, existingFarm := range existingFarms {
+ var existingFarmName string
found := false
if existingFarm.FarmName.Get() == nil || *existingFarm.FarmName.Get() == "" {
continue
}
- existingFarmName := *existingFarm.FarmName.Get()
+ existingFarmArray = append(existingFarmArray, *existingFarm.FarmName.Get())
+ existingFarmName = *existingFarm.FarmName.Get()
- for _, farm := range farms {
- if existingFarmName == farm.FarmName.ValueString() {
+ for _, planFarm := range planFarmArray {
+ if existingFarmName == planFarm {
found = true
break
}
@@ -1061,15 +971,22 @@ func (plan STFStoreServiceResourceModel) updateStoreFarms(ctx context.Context, c
}
}
}
+
//update or create farms
for _, farm := range farms {
- var storeFarmSetBody = farm.buildStoreFarmBody(ctx, client, diagnostics)
+ found := false
+ var storeFarmSetBody = farm.buildStoreFarmBody(ctx, diagnostics)
//fetch existing StoreFarm to see if a new farm need to be created
- var storeFarmGetBody citrixstorefront.GetSTFStoreFarmRequestModel
- storeFarmGetBody.SetFarmName(farm.FarmName.ValueString())
- getStoreFarmRequest := client.StorefrontClient.StoreSF.STFStoreGetStoreFarm(ctx, storeFarmGetBody, getStoreBody)
- _, err := getStoreFarmRequest.Execute()
- if err != nil && strings.EqualFold(err.Error(), util.NOT_EXIST) { //if farm does not exist, create a new farm
+
+ // Check if the farm is already present in the existing farms
+ for _, existingFarm := range existingFarmArray {
+ if existingFarm == farm.FarmName.ValueString() {
+ found = true
+ break
+ }
+ }
+
+ if !found { //create new farm
createStoreFarmRequest := client.StorefrontClient.StoreSF.STFStoreNewStoreFarm(ctx, storeFarmSetBody, getStoreBody)
_, err := createStoreFarmRequest.Execute()
if err != nil {
@@ -1081,7 +998,7 @@ func (plan STFStoreServiceResourceModel) updateStoreFarms(ctx context.Context, c
}
} else { //otherwise update the existing farm
setStoreFarmRequest := client.StorefrontClient.StoreSF.STFStoreSetStoreFarm(ctx, storeFarmSetBody, getStoreBody)
- _, err = setStoreFarmRequest.Execute()
+ _, err := setStoreFarmRequest.Execute()
if err != nil {
diagnostics.AddError(
"Error updating Store Farm during Update",
@@ -1094,7 +1011,7 @@ func (plan STFStoreServiceResourceModel) updateStoreFarms(ctx context.Context, c
return nil
}
-func (farm StoreFarm) buildStoreFarmBody(ctx context.Context, client *citrixdaasclient.CitrixDaasClient, diagnostics *diag.Diagnostics) citrixstorefront.AddSTFStoreFarmRequestModel {
+func (farm StoreFarm) buildStoreFarmBody(ctx context.Context, diagnostics *diag.Diagnostics) citrixstorefront.AddSTFStoreFarmRequestModel {
var storeFarmSetBody citrixstorefront.AddSTFStoreFarmRequestModel
if !farm.AllFailedBypassDuration.IsNull() {
storeFarmSetBody.SetAllFailedBypassDuration(farm.AllFailedBypassDuration.ValueInt64())
@@ -1164,7 +1081,7 @@ func (farm StoreFarm) buildStoreFarmBody(ctx context.Context, client *citrixdaas
}
func (plan STFStoreServiceResourceModel) getStoreFarms(ctx context.Context, client *citrixdaasclient.CitrixDaasClient, diagnostics *diag.Diagnostics) ([]citrixstorefront.StoreFarmModel, error) {
- siteIdInt, err := strconv.ParseInt(plan.SiteId.ValueString(), 10, 64)
+ siteId, err := strconv.ParseInt(plan.SiteId.ValueString(), 10, 64)
if err != nil {
diagnostics.AddError(
"Error getting StoreFront StoreService SiteId",
@@ -1173,9 +1090,8 @@ func (plan STFStoreServiceResourceModel) getStoreFarms(ctx context.Context, clie
return nil, err
}
farms := util.ObjectListToTypedArray[StoreFarm](ctx, diagnostics, plan.StoreFarm)
-
getStoreBody := citrixstorefront.GetSTFStoreRequestModel{}
- getStoreBody.SetSiteId(siteIdInt)
+ getStoreBody.SetSiteId(siteId)
getStoreBody.SetVirtualPath(plan.VirtualPath.ValueString())
var storeFarms []citrixstorefront.StoreFarmModel
diff --git a/internal/storefront/stf_webreceiver/stf_webreceiver_resource_model.go b/internal/storefront/stf_webreceiver/stf_webreceiver_resource_model.go
index bb7e1d6..4e54012 100644
--- a/internal/storefront/stf_webreceiver/stf_webreceiver_resource_model.go
+++ b/internal/storefront/stf_webreceiver/stf_webreceiver_resource_model.go
@@ -484,6 +484,9 @@ func (ReceiverConfiguration) GetSchema() schema.SingleNestedAttribute {
"download_url": schema.StringAttribute{
Description: "The URL to download the Receiver Configuration .cr file.",
Computed: true,
+ PlanModifiers: []planmodifier.String{
+ stringplanmodifier.UseStateForUnknown(),
+ },
},
},
}
@@ -584,14 +587,23 @@ func (AuthenticationManager) GetSchema() schema.SingleNestedAttribute {
"get_user_name_url": schema.StringAttribute{
Description: "The URL to obtain the full username. Defaults to `Authentication/GetUserName`.",
Computed: true,
+ PlanModifiers: []planmodifier.String{
+ stringplanmodifier.UseStateForUnknown(),
+ },
},
"logoff_url": schema.StringAttribute{
Description: "The URL to log off the Citrix Receiver for Web session. Defaults to `Authentication/Logoff`.",
Computed: true,
+ PlanModifiers: []planmodifier.String{
+ stringplanmodifier.UseStateForUnknown(),
+ },
},
"change_credentials_url": schema.StringAttribute{
Description: "The URL to initiate a change password operation. Defaults to `ExplicitAuth/GetChangeCredentialForm`.",
Computed: true,
+ PlanModifiers: []planmodifier.String{
+ stringplanmodifier.UseStateForUnknown(),
+ },
},
},
}
diff --git a/internal/test/gac_settings_resource_test.go b/internal/test/gac_settings_resource_test.go
index acae609..75edac5 100644
--- a/internal/test/gac_settings_resource_test.go
+++ b/internal/test/gac_settings_resource_test.go
@@ -127,6 +127,12 @@ func TestGacSettingsResource(t *testing.T) {
resource.TestCheckResourceAttr("citrix_gac_settings.test_settings_configuration", "app_settings.macos.0.settings.0.value_list.#", "2"),
resource.TestCheckResourceAttr("citrix_gac_settings.test_settings_configuration", "app_settings.macos.0.settings.0.value_list.0", "startWorkspace"),
resource.TestCheckResourceAttr("citrix_gac_settings.test_settings_configuration", "app_settings.macos.0.settings.0.value_list.1", "refreshApps"),
+ // Check permissions for Linux
+ resource.TestCheckResourceAttr("citrix_gac_settings.test_settings_configuration", "app_settings.linux.#", "1"),
+ resource.TestCheckResourceAttr("citrix_gac_settings.test_settings_configuration", "app_settings.linux.0.category", "root"),
+ resource.TestCheckResourceAttr("citrix_gac_settings.test_settings_configuration", "app_settings.linux.0.user_override", "false"),
+ resource.TestCheckResourceAttr("citrix_gac_settings.test_settings_configuration", "app_settings.linux.0.settings.#", "1"),
+ resource.TestCheckResourceAttr("citrix_gac_settings.test_settings_configuration", "app_settings.linux.0.settings.0.name", "enable fido2"),
),
},
// Delete testing automatically occurs in TestCase
@@ -265,6 +271,18 @@ var (
}
]
}
+ ],
+ linux = [
+ {
+ category = "root",
+ user_override = false,
+ settings = [
+ {
+ name = "enable fido2",
+ value_string = "true"
+ }
+ ]
+ }
]
}
}
diff --git a/internal/test/resource_locations_data_resource_test.go b/internal/test/resource_locations_data_resource_test.go
new file mode 100644
index 0000000..ad22f8e
--- /dev/null
+++ b/internal/test/resource_locations_data_resource_test.go
@@ -0,0 +1,57 @@
+// Copyright © 2024. Citrix Systems, Inc.
+
+package test
+
+import (
+ "fmt"
+ "os"
+ "testing"
+
+ "github.com/hashicorp/terraform-plugin-testing/helper/resource"
+)
+
+func TestResourceLocationDataResourcePreCheck(t *testing.T) {
+ if v := os.Getenv("TEST_RESOURCE_LOCATION_NAME"); v == "" {
+ t.Fatal("TEST_RESOURCE_LOCATION_DATASOURCE_NAME must be set for acceptance tests")
+ }
+
+ if v := os.Getenv("TEST_RESOURCE_LOCATION_ID"); v == "" {
+ t.Fatal("TEST_RESOURCE_LOCATION_ID must be set for acceptance tests")
+ }
+}
+
+func TestResourceLocationDataResource(t *testing.T) {
+ name := os.Getenv("TEST_RESOURCE_LOCATION_NAME")
+ id := os.Getenv("TEST_RESOURCE_LOCATION_DATASOURCE_NAME")
+
+ resource.Test(t, resource.TestCase{
+ ProtoV6ProviderFactories: testAccProtoV6ProviderFactories,
+ PreCheck: func() {
+ TestProviderPreCheck(t)
+ TestResourceLocationDataResourcePreCheck(t)
+ },
+ Steps: []resource.TestStep{
+ // Create and Read testing
+ {
+ Config: BuildResourceLocationDataResource(t, resourceLocationTestDataResource, name),
+ Check: resource.ComposeAggregateTestCheckFunc(
+ // Verify the id of the resource location data source
+ resource.TestCheckResourceAttr("citrix_cloud_resource_location.test_resource_location", "id", id),
+ ),
+ },
+ },
+ })
+}
+
+var (
+ resourceLocationTestDataResource = `
+resource "citrix_cloud_resource_location" "test_resource_location" {
+ name = "%s"
+}
+`
+)
+
+func BuildResourceLocationDataResource(t *testing.T, resourceLocation string, resourceLocationName string) string {
+ tfbody := fmt.Sprintf(resourceLocation, resourceLocationName)
+ return tfbody
+}
diff --git a/internal/test/sweeper_test.go b/internal/test/sweeper_test.go
index 4387104..db5aed4 100644
--- a/internal/test/sweeper_test.go
+++ b/internal/test/sweeper_test.go
@@ -99,7 +99,11 @@ func sharedClientForSweepers(ctx context.Context) *citrixclient.CitrixDaasClient
// Initialize CVAD client
client := &citrixclient.CitrixDaasClient{}
- client.InitializeCitrixDaasClient(ctx, authUrl, ccUrl, hostname, customerId, clientId, clientSecret, onPremises, apiGateway, isGov, disableSslVerification, &userAgent, middleware.MiddlewareAuthFunc, middleware.MiddlewareAuthWithCustomerIdHeaderFunc)
+ token, _, _ := client.SetupCitrixClientsContext(ctx, authUrl, ccUrl, hostname, customerId, clientId, clientSecret, onPremises, apiGateway, isGov, disableSslVerification, &userAgent, middleware.MiddlewareAuthFunc, middleware.MiddlewareAuthWithCustomerIdHeaderFunc)
+ if !onPremises {
+ client.InitializeCitrixCloudClients(ctx, ccUrl, hostname, middleware.MiddlewareAuthFunc, middleware.MiddlewareAuthWithCustomerIdHeaderFunc)
+ }
+ client.InitializeCitrixDaasClient(ctx, customerId, token, onPremises, apiGateway, disableSslVerification, &userAgent)
return client
}
diff --git a/internal/util/common.go b/internal/util/common.go
index 097d528..d96e599 100644
--- a/internal/util/common.go
+++ b/internal/util/common.go
@@ -104,7 +104,7 @@ const SslThumbprintRegex string = `^([0-9a-fA-F]{40}|[0-9a-fA-F]{64})$`
const AwsEc2InstanceTypeRegex string = `^[a-z0-9]{1,15}\.[a-z0-9]{1,15}$`
// Active Directory Sid
-const ActiveDirectorySidRegex string = `^S-1-[0-59]-\d{2}-\d{8,10}-\d{8,10}-\d{8,10}-[1-9]\d{3}$`
+const ActiveDirectorySidRegex string = `^S-1-[0-59]-\d{2}-\d{8,10}-\d{8,10}-\d{8,10}-[1-9]\d{2,}$`
// AWS Machine Image ID REGEX
const AwsAmiRegex string = `^ami-[0-9a-f]{8,17}$`
@@ -129,6 +129,16 @@ const AppCategoryPathRegex string = `^([a-zA-Z0-9 ]+\\)*[a-zA-Z0-9 ]+\\?$`
// SAML 2.0 Identity Provider Certificate REGEX
const SamlIdpCertRegex string = `\.[Pp][Ee][Mm]$|\.[Cc][Rr][Tt]$|\.[Cc][Ee][Rr]$`
+// Admin Folder Path
+const AdminFolderPathWithBackslashRegex string = `^[^\\].*[^\\]$`
+const AdminFolderPathSpecialCharactersRegex string = `^[^/;:#.*?=<>|[\](){}"'\` + "`~]+$"
+
+// Check if it does not contain path separator
+const NoPathRegex = `^[^\\/]*$`
+
+// GAC Category Name
+const GacCategoryNameRegex string = `^(root|[A-Z][a-z ]*)$`
+
// NOT_EXIST error code
const NOT_EXIST string = "NOT_EXIST"
@@ -192,6 +202,9 @@ const MetadataImageManagementPrepPrefix = "imagemanagementprep_"
const MetadataTaskDataPrefix = "taskdata_"
const MetadataTaskStatePrefix = "taskstate_"
+// CC Admin User
+const AdminUserMonitorAccessPolicySuffix = " - Access to 'Monitor' tab only"
+
var PlatformSettingsAssignedTo = []string{"AllUsersNoAuthentication"}
//
diff --git a/internal/util/name-value-string-pair.go b/internal/util/name-value-string-pair.go
index d5f4241..d49ba1b 100644
--- a/internal/util/name-value-string-pair.go
+++ b/internal/util/name-value-string-pair.go
@@ -107,8 +107,7 @@ func ValidateMetadataConfig(ctx context.Context, diagnostics *diag.Diagnostics,
func GetMetadataListSchema(resource string) schema.ListNestedAttribute {
return schema.ListNestedAttribute{
- Description: fmt.Sprintf("Metadata for the %s.", resource) +
- "\n\n~> **Please Note** Metadata once set cannot be removed. Use this field to add new metadata or update the value for an existing metadata. Subsequently, removing any metadata from config will have no effect on the existing metadata of the resource.",
+ Description: fmt.Sprintf("Metadata for the %s.", resource),
Optional: true,
NestedObject: NameValueStringPairModel{}.GetSchema(),
Validators: []validator.List{
@@ -180,6 +179,25 @@ func GetMetadataRequestModel(ctx context.Context, diagnostics *diag.Diagnostics,
return metadata
}
+//
+// Helper function to delete metadata that is not a part of the plan. The value of the metadata is set to empty string to delete the KVP from the remote. (STUD-31858)
+//
+func GetUpdatedMetadataRequestModel(ctx context.Context, diagnostics *diag.Diagnostics, stateMetadata []NameValueStringPairModel, planMetadata []NameValueStringPairModel) []citrixorchestration.NameValueStringPairModel {
+ metadata := GetMetadataRequestModel(ctx, diagnostics, planMetadata)
+ metadataMap := make(map[string]bool)
+ for _, item := range metadata {
+ metadataMap[item.GetName()] = true
+ }
+
+ // Add metadata Name from state with empty value to delete them from the remote
+ for _, pair := range stateMetadata {
+ if _, exists := metadataMap[pair.Name.ValueString()]; !exists {
+ AppendNameValueStringPair(&metadata, pair.Name.ValueString(), "")
+ }
+ }
+ return metadata
+}
+
// /
// / Helper function to include only metadata that are a part of the state
// /
diff --git a/internal/util/resource.go b/internal/util/resource.go
index 77fb531..b16f06d 100644
--- a/internal/util/resource.go
+++ b/internal/util/resource.go
@@ -47,7 +47,7 @@ func GetHypervisorResourcePool(ctx context.Context, client *citrixdaasclient.Cit
}
func GetMachineCatalog(ctx context.Context, client *citrixdaasclient.CitrixDaasClient, diagnostics *diag.Diagnostics, machineCatalogId string, addErrorToDiagnostics bool) (*citrixorchestration.MachineCatalogDetailResponseModel, error) {
- getMachineCatalogRequest := client.ApiClient.MachineCatalogsAPIsDAAS.MachineCatalogsGetMachineCatalog(ctx, machineCatalogId).Fields("Id,Name,Description,ProvisioningType,Zone,AllocationType,SessionSupport,TotalCount,HypervisorConnection,ProvisioningScheme,RemotePCEnrollmentScopes,IsPowerManaged,MinimumFunctionalLevel,IsRemotePC,Metadata,Scopes")
+ getMachineCatalogRequest := client.ApiClient.MachineCatalogsAPIsDAAS.MachineCatalogsGetMachineCatalog(ctx, machineCatalogId).Fields("Id,Name,Description,ProvisioningType,Zone,AllocationType,SessionSupport,TotalCount,HypervisorConnection,ProvisioningScheme,RemotePCEnrollmentScopes,IsPowerManaged,MinimumFunctionalLevel,IsRemotePC,Metadata,Scopes,UpgradeInfo,AdminFolder")
catalog, httpResp, err := citrixdaasclient.ExecuteWithRetry[*citrixorchestration.MachineCatalogDetailResponseModel](getMachineCatalogRequest, client)
if err != nil && addErrorToDiagnostics {
diagnostics.AddError(
@@ -315,7 +315,7 @@ func GetFilteredResourcePathList(ctx context.Context, client *citrixdaasclient.C
name = strings.Split(name, " ")[0]
}
if _, exists := filterMap[strings.ToLower(name)]; exists {
- if connectionType == citrixorchestration.HYPERVISORCONNECTIONTYPE_V_CENTER && strings.EqualFold(resourceType, NetworkResourceType) {
+ if (connectionType == citrixorchestration.HYPERVISORCONNECTIONTYPE_AZURE_RM || connectionType == citrixorchestration.HYPERVISORCONNECTIONTYPE_V_CENTER) && strings.EqualFold(resourceType, NetworkResourceType) {
result = append(result, child.GetRelativePath())
} else if connectionType == citrixorchestration.HYPERVISORCONNECTIONTYPE_CUSTOM && strings.EqualFold(pluginId, NUTANIX_PLUGIN_ID) && strings.EqualFold(resourceType, NetworkResourceType) {
result = append(result, child.GetFullName())
diff --git a/settings.cloud.example.json b/settings.cloud.example.json
index e6111a2..5396a62 100644
--- a/settings.cloud.example.json
+++ b/settings.cloud.example.json
@@ -261,7 +261,7 @@
// Resource Location Go Tests
"TEST_RESOURCE_LOCATION_NAME": "ctx-test-resource-location",
-
+
// StoreFront env variable
"SF_COMPUTER_NAME" : "{storefront_computer_name}",
"SF_AD_ADMIN_USERNAME" : "{storefront_admin_username}",
@@ -301,6 +301,10 @@
"TEST_HYPERVISOR_DATASOURCE_NAME" :"azure",
"TEST_HYPERVISOR_DATASOURCE_ID": "{Existing hypervisor ID for verification}",
+ // Resource Location Data Source Go Tests
+ "TEST_RESOURCE_LOCATION_DATASOURCE_NAME": "ctx-test-resource-location",
+ "TEST_RESOURCE_LOCATION_ID": "{Existing resource location ID for verification}",
+
// Hypervisor Resource Pool Data Source Go Tests
"TEST_HYPERVISOR_RP_DATASOURCE_NAME" :"zl-rp",
"TEST_HYPERVISOR_RP_DATASOURCE_ID": "{Existing hypervisor resource pool ID for verification}",
diff --git a/templates/index.md.tmpl b/templates/index.md.tmpl
index 9073de8..7492a1e 100644
--- a/templates/index.md.tmpl
+++ b/templates/index.md.tmpl
@@ -10,10 +10,47 @@ description: |-
{{ .Description | trimspace }}
+Documentation regarding the [Data Sources](https://developer.hashicorp.com/terraform/language/data-sources) and [Resources](https://developer.hashicorp.com/terraform/language/resources) supported by the Citrix Provider can be found in the navigation to the left.
+
+Check out the [release notes](https://github.com/citrix/terraform-provider-citrix/releases) to find out more about the provider's latest features and version information.
+
+## Getting Started
+
+New to Terraform? Click [here](https://developer.hashicorp.com/terraform) to learn more.
+
+### Importing existing Citrix resources into Terraform
+
+Experience the immediate benefits of Terraform by importing your Citrix resources (CVAD or DaaS) using our [Onboarding Script](https://github.com/citrix/terraform-provider-citrix/blob/main/scripts/onboarding-helper/terraform-onboarding.ps1). This allows you to quickly adopt infrastructure as code and streamline your infrastructure management. A comprehensive [ReadMe](https://github.com/citrix/terraform-provider-citrix/blob/main/scripts/onboarding-helper/README.md) is available to guide you through the process.
+
+### Creating Citrix resources via Terraform
+
+Please refer to [Citrix Tech Zone](https://community.citrix.com/tech-zone/automation/) to find detailed guides on how to deploy and manage resources using the Citrix provider:
+- [Installing and configuring the Citrix provider](https://community.citrix.com/tech-zone/automation/terraform-install-and-config/)
+- [AWS EC2](https://community.citrix.com/tech-zone/build/deployment-guides/terraform-daas-aws/) via MCS
+- [Azure](https://community.citrix.com/tech-zone/build/deployment-guides/citrix-daas-terraform-azure/) via MCS
+- [GCP](https://community.citrix.com/tech-zone/build/deployment-guides/terraform-daas-gcp/) via MCS
+- [vSphere](https://community.citrix.com/tech-zone/build/deployment-guides/terraform-daas-vsphere8/) via MCS
+- [XenServer](https://community.citrix.com/tech-zone/automation/citrix-terraform-xenserver) via MCS
+- [Citrix policies](https://community.citrix.com/tech-zone/automation/cvad-terraform-policies/)
+
+## Frequently Asked Questions
+
+### What resource is supported for different connection types?
+
+| Connection Type | Hypervisor | Resource Pool | MCS Power Managed | MCS Provisioning | PVS | Manual/Remote PC |
+|------------------|--------------------|--------------------|----------------------|----------------------|--------------------------|----------------------|
+| AzureRM |:heavy_check_mark: |:heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |:heavy_check_mark: | :heavy_check_mark: |
+| AWS EC2 |:heavy_check_mark: |:heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |:heavy_multiplication_x: | :heavy_check_mark: |
+| GCP |:heavy_check_mark: |:heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |:heavy_multiplication_x: | :heavy_check_mark: |
+| vSphere |:heavy_check_mark: |:heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |:heavy_multiplication_x: | :heavy_check_mark: |
+| XenServer |:heavy_check_mark: |:heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |:heavy_multiplication_x: | :heavy_check_mark: |
+| Nutanix |:heavy_check_mark: |:heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |:heavy_multiplication_x: | :heavy_check_mark: |
+| SCVMM |:heavy_check_mark: |:heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |:heavy_multiplication_x: | :heavy_check_mark: |
+
{{ if .HasExample -}}
## Example Usage
{{ tffile "internal/examples/provider/provider.tf" }}
{{- end }}
-{{ .SchemaMarkdown | trimspace }}
\ No newline at end of file
+{{ .SchemaMarkdown | trimspace }}
diff --git a/templates/resources/policy_set.md.tmpl b/templates/resources/policy_set.md.tmpl
index e324ae8..7a3303e 100644
--- a/templates/resources/policy_set.md.tmpl
+++ b/templates/resources/policy_set.md.tmpl
@@ -25,7 +25,7 @@ description: |-
-> **Note** For detailed information about policy settings and filters, please refer to [this document](https://github.com/citrix/terraform-provider-citrix/blob/main/internal/daas/policies/policy_set_resource.md).
-~> **Disclaimer** This feature is supported for On-Premises with DDC version `2402` and above and will be made available for Cloud soon.
+~> **Disclaimer** This feature is supported for Citrix Cloud customers, and for Citrix On-Premises customers with DDC version `2402` and above.
## Example Usage