diff --git a/.secrets.baseline b/.secrets.baseline index 70af282b73..bc905bc42e 100644 --- a/.secrets.baseline +++ b/.secrets.baseline @@ -3,7 +3,7 @@ "files": "go.mod|go.sum|.*.map|^.secrets.baseline$", "lines": null }, - "generated_at": "2023-09-14T05:19:33Z", + "generated_at": "2023-09-14T15:01:09Z", "plugins_used": [ { "name": "AWSKeyDetector" @@ -552,7 +552,7 @@ "hashed_secret": "91199272d5d6a574a51722ca6f3d1148edb1a0e7", "is_secret": false, "is_verified": false, - "line_number": 94, + "line_number": 95, "type": "Secret Keyword", "verified_result": null }, @@ -560,7 +560,7 @@ "hashed_secret": "a8d42722d33725b90f8e5ca1ae8aed3edaac55bd", "is_secret": false, "is_verified": false, - "line_number": 109, + "line_number": 110, "type": "Secret Keyword", "verified_result": null }, @@ -568,7 +568,7 @@ "hashed_secret": "5f28e11957b762c5558d22b7ad9b15d822cb856a", "is_secret": false, "is_verified": false, - "line_number": 111, + "line_number": 112, "type": "Secret Keyword", "verified_result": null }, @@ -576,7 +576,17 @@ "hashed_secret": "c88488e962fe2062632f389e755794fc3c29ff0d", "is_secret": false, "is_verified": false, - "line_number": 112, + "line_number": 113, + "type": "Secret Keyword", + "verified_result": null + } + ], + "examples/ibm-satellite/modules/configuration/README.md": [ + { + "hashed_secret": "bf10dae7b89461df3fd3c48f86ec23543710e8cd", + "is_secret": false, + "is_verified": false, + "line_number": 67, "type": "Secret Keyword", "verified_result": null } @@ -2904,6 +2914,16 @@ "type": "Hex High Entropy String", "verified_result": null } + ] + "ibm/service/satellite/resource_ibm_satellite_storage_configuration_test.go": [ + { + "hashed_secret": "f32b67c7e26342af42efabc674d441dca0a281c5", + "is_secret": false, + "is_verified": false, + "line_number": 118, + "type": "Secret Keyword", + "verified_result": null + } ], "ibm/service/schematics/data_source_ibm_schematics_action.go": [ { @@ -3626,7 +3646,7 @@ "hashed_secret": "f855f5027fd8fdb2df3f6a6f1cf858fffcbedb0c", "is_secret": false, "is_verified": false, - "line_number": 89160, + "line_number": 89080, "type": "Secret Keyword", "verified_result": null }, @@ -3634,7 +3654,7 @@ "hashed_secret": "5fb0fa884132a8724a8d7cba55853737e442adbd", "is_secret": false, "is_verified": false, - "line_number": 111481, + "line_number": 111658, "type": "Secret Keyword", "verified_result": null }, @@ -3642,7 +3662,7 @@ "hashed_secret": "1e5c2f367f02e47a8c160cda1cd9d91decbac441", "is_secret": false, "is_verified": false, - "line_number": 141026, + "line_number": 141194, "type": "Secret Keyword", "verified_result": null } @@ -4779,6 +4799,16 @@ "verified_result": null } ], + "website/docs/r/satellite_storage_configuration.html.markdown": [ + { + "hashed_secret": "d4c3d66fd0c38547a3c7a4c6bdc29c36911bc030", + "is_secret": false, + "is_verified": false, + "line_number": 42, + "type": "Secret Keyword", + "verified_result": null + } + ], "website/docs/r/sm_arbitrary_secret.html.markdown": [ { "hashed_secret": "d47dcacc720a39e236679ac3e311a0d58bb6519e", diff --git a/examples/ibm-satellite/README.md b/examples/ibm-satellite/README.md index 5ce3ca6a3a..5a4c4ba3df 100644 --- a/examples/ibm-satellite/README.md +++ b/examples/ibm-satellite/README.md @@ -11,7 +11,8 @@ This example uses below modules to set up the satellite location with IBM enviro 5. [satellite-route](modules/route) This module will create openshift route. 6. [satellite-endpoint](modules/endpoint) This module will create satellite endpoint. 7. [satellite-dns](modules/dns) This module will register public IPs to control plane & open-shit cluster subdomain DNS records. - +8. [satellite-storage-configuration](modules/configuration) This module will create and manage storage configurations in your satellite location. +9. [satellite-storage-assignment](modules/assignment) This module will assign your storage configurations to clusters or cluster groups. ## Usage @@ -115,6 +116,26 @@ module "satellite-endpoint" { client_certificate = var.client_certificate } +module "satellite-storage-configuration" { + source = "./modules/configuration" + + location = var.location + config_name = var.config_name + storage_template_name = var.storage_template_name + storage_template_version = var.storage_template_version + user_config_parameters = var.user_config_parameters + user_secret_parameters = var.user_secret_parameters + storage_class_parameters = var.storage_class_parameters +} + +module "satellite-storage-assignment"{ + source = "./modules/assignment" + + assignment_name = var.assignment_name + cluster = var.cluster + config = var.config + controller = var.controller +} ``` ## Note diff --git a/examples/ibm-satellite/assignment.tf b/examples/ibm-satellite/assignment.tf new file mode 100644 index 0000000000..f25ba3ef58 --- /dev/null +++ b/examples/ibm-satellite/assignment.tf @@ -0,0 +1,8 @@ +module "satellite-storage-assignment"{ + source = "./modules/assignment" + + assignment_name = var.assignment_name + cluster = var.cluster + config = var.config + controller = var.controller +} \ No newline at end of file diff --git a/examples/ibm-satellite/configuration.tf b/examples/ibm-satellite/configuration.tf new file mode 100644 index 0000000000..1c451388de --- /dev/null +++ b/examples/ibm-satellite/configuration.tf @@ -0,0 +1,11 @@ +module "satellite-storage-configuration" { + source = "./modules/configuration" + + location = var.location + config_name = var.config_name + storage_template_name = var.storage_template_name + storage_template_version = var.storage_template_version + user_config_parameters = var.user_config_parameters + user_secret_parameters = var.user_secret_parameters + storage_class_parameters = var.storage_class_parameters +} \ No newline at end of file diff --git a/examples/ibm-satellite/modules/assignment/README.md b/examples/ibm-satellite/modules/assignment/README.md new file mode 100644 index 0000000000..15beb8f4c0 --- /dev/null +++ b/examples/ibm-satellite/modules/assignment/README.md @@ -0,0 +1,85 @@ +# This Module is used to create satellite storage assignment + +This module creates a `satellite storage assignment` based on a storage template of your choice. For more information on storage templates and their parameters refer -> https://cloud.ibm.com/docs/satellite?topic=satellite-storage-template-ov&interface=ui + +## Prerequisite + +* Set up the IBM Cloud command line interface (CLI), the Satellite plug-in, and other related CLIs. +* Install cli and plugin package +```console + ibmcloud plugin install container-service +``` +## Usage + +``` +terraform init +``` +``` +terraform plan +``` +``` +terraform apply +``` +``` +terraform destroy +``` +## Example Usage + +``` hcl +module "satellite-storage-assignment" { + assignment_name = var.assignment_name + cluster = var.cluster + config = var.config + controller = var.controller +} +``` + +### Assigning a Configuration to a cluster +```hcl +resource "ibm_satellite_storage_assignment" "odf_assignment" { + assignment_name = var.assignment_name + config = var.config + cluster = var.cluster + controller = var.controller +} +``` + +### Assigning a Configuration to Cluster Groups +```hcl +resource "ibm_satellite_storage_assignment" "odf_assignment" { + assignment_name = var.assignment_name + config = var.config + groups = var.groups +} +``` + +### Updating the Configuration Revision to a cluster +```hcl +resource "ibm_satellite_storage_assignment" "odf_assignment" { + assignment_name = var.assignment_name + config = var.config + cluster = var.cluster + controller = var.controller + update_config_revision = true +} +``` + + +## Inputs + +| Name | Description | Type | Required | +|------|-------------|------|---------| +| ibmcloud\_api\_key | IBM Cloud API key | `string` | true | +| assignment_name | Name of the Assignment. | `string` | true | +| groups | One or more cluster groups on which you want to apply the configuration. Note that at least one cluster group is required. | `list[string]` | true | +| cluster | ID of the Satellite cluster or Service Cluster that you want to apply the configuration to. | `string` | true | +| config | Storage Configuration Name or ID. | `string` | true | +| controller | The Name or ID of the Satellite Location. | `string` | true | +| update_config_revision | Update an assignment to the latest available storage configuration version. | `bool` | false | + +## Note + * You cannot use the `groups` argument with `cluster` & `controller`, this is applicable when creating assignments to cluster groups. + * Similarly `cluster` & `controller` are to be used together and cannot be used with `groups`, this is applicable when creating assignments to clusters. + + + \ No newline at end of file diff --git a/examples/ibm-satellite/modules/assignment/main.tf b/examples/ibm-satellite/modules/assignment/main.tf new file mode 100644 index 0000000000..8747d49159 --- /dev/null +++ b/examples/ibm-satellite/modules/assignment/main.tf @@ -0,0 +1,7 @@ +// Provision satellite_storage_assignment resource instance +resource "ibm_satellite_storage_assignment" "instance" { + assignment_name = var.assignment_name + cluster = var.cluster + config = var.config + controller = var.controller +} \ No newline at end of file diff --git a/examples/ibm-satellite/modules/assignment/provider.tf b/examples/ibm-satellite/modules/assignment/provider.tf new file mode 100644 index 0000000000..01feea38b4 --- /dev/null +++ b/examples/ibm-satellite/modules/assignment/provider.tf @@ -0,0 +1,7 @@ +terraform { + required_providers { + ibm = { + source = "ibm-cloud/ibm" + } + } +} \ No newline at end of file diff --git a/examples/ibm-satellite/modules/assignment/variables.tf b/examples/ibm-satellite/modules/assignment/variables.tf new file mode 100644 index 0000000000..1c6c2221fd --- /dev/null +++ b/examples/ibm-satellite/modules/assignment/variables.tf @@ -0,0 +1,29 @@ +variable "assignment_name" { + type = string + description = "Name of the Assignment." +} + +variable "groups" { + type = list(string) + description = "One or more cluster groups on which you want to apply the configuration. Note that at least one cluster group is required." +} + +variable "cluster" { + type = string + description = "ID of the Satellite cluster or Service Cluster that you want to apply the configuration to." +} + +variable "config" { + type = string + description = "Storage Configuration Name or ID." +} + +variable "controller" { + type = string + description = "The Name or ID of the Satellite Location." +} + +variable "update_config_revision" { + type = bool + description = "Update an assignment to the latest available storage configuration version." +} \ No newline at end of file diff --git a/examples/ibm-satellite/modules/configuration/README.md b/examples/ibm-satellite/modules/configuration/README.md new file mode 100644 index 0000000000..6910630ce1 --- /dev/null +++ b/examples/ibm-satellite/modules/configuration/README.md @@ -0,0 +1,85 @@ +# This Module is used to create satellite storage configuration + +This module creates a `satellite storage configuration` based on a storage template of your choice. For more information on storage templates and their parameters refer -> https://cloud.ibm.com/docs/satellite?topic=satellite-storage-template-ov&interface=ui + +## Prerequisite + +* Set up the IBM Cloud command line interface (CLI), the Satellite plug-in, and other related CLIs. +* Install cli and plugin package +```console + ibmcloud plugin install container-service +``` +## Usage + +``` +terraform init +``` +``` +terraform plan +``` +``` +terraform apply +``` +``` +terraform destroy +``` +## Example Usage + +``` hcl +module "satellite-storage-configuration" { + source = "./modules/configuration" + location = var.location + config_name = var.config_name + storage_template_name = var.storage_template_name + storage_template_version = var.storage_template_version + user_config_parameters = var.user_config_parameters + user_secret_parameters = var.user_secret_parameters + storage_class_parameters = var.storage_class_parameters +} +``` + +### Example using the `odf-remote` storage template +``` hcl +resource "ibm_satellite_storage_configuration" "odf_storage_configuration" { + location = var.location + config_name = var.config_name + storage_template_name = "odf-remote" + storage_template_version = "4.12" + user_config_parameters = { + osd-size = "100Gi" + osd-storage-class = "ibmc-vpc-block-metro-5iops-tier" + billing-type = "advanced" + cluster-encryption = "false" + ibm-cos-endpoint = "" + ibm-cos-location = "" + ignore-noobaa = "false" + kms-base-url = "" + kms-encryption = "false" + kms-instance-id = "" + kms-instance-name = "" + kms-token-url = "" + num-of-osd = "1" + odf-upgrade = "false" + perform-cleanup = "false" + worker-nodes = "" + } + user_secret_parameters = { + iam-api-key = "api-key-value" + } +} +``` + + +## Inputs + +| Name | Description | Type | Required | +|------|-------------|------|---------| +| ibmcloud\_api\_key | IBM Cloud API key | `string` | true | +| config_name | The Storage Configuration Name. | `string` | true | +| storage_template_name | The Name of the Storage Template to create the configuration. | `string` | true | +| storage_template_version | The Version of the Storage Template. | `string` | true | +| user_config_parameters | The different configuration parameters available based on the selected storage template | `map` | true | +| user_secret_parameters | The different secrets required based on the selected storage template | `map` | true | +| storage_class_parameters | Define your own storage classes if supported by the storage template | `list[map]` | true | + + \ No newline at end of file diff --git a/examples/ibm-satellite/modules/configuration/main.tf b/examples/ibm-satellite/modules/configuration/main.tf new file mode 100644 index 0000000000..843773ead8 --- /dev/null +++ b/examples/ibm-satellite/modules/configuration/main.tf @@ -0,0 +1,10 @@ +// Provision satellite_storage_configuration_resource instance +resource "ibm_satellite_storage_configuration" "instance" { + location = var.location + config_name = var.config_name + storage_template_name = var.storage_template_name + storage_template_version = var.storage_template_version + user_config_parameters = var.user_config_parameters + user_secret_parameters = var.user_secret_parameters + storage_class_parameters = var.storage_class_parameters +} \ No newline at end of file diff --git a/examples/ibm-satellite/modules/configuration/provider.tf b/examples/ibm-satellite/modules/configuration/provider.tf new file mode 100644 index 0000000000..01feea38b4 --- /dev/null +++ b/examples/ibm-satellite/modules/configuration/provider.tf @@ -0,0 +1,7 @@ +terraform { + required_providers { + ibm = { + source = "ibm-cloud/ibm" + } + } +} \ No newline at end of file diff --git a/examples/ibm-satellite/modules/configuration/variables.tf b/examples/ibm-satellite/modules/configuration/variables.tf new file mode 100644 index 0000000000..06bc175910 --- /dev/null +++ b/examples/ibm-satellite/modules/configuration/variables.tf @@ -0,0 +1,34 @@ +variable "location" { + description = "The name of the location." + type = string +} + +variable "config_name" { + description = "The name of the storage configuration you are creating." + type = string +} + +variable "storage_template_name" { + description = "The storage template name you are using to create the configuration." + type = string +} + +variable "storage_template_version" { + description = "The storage template version." + type = string +} + +variable "user_config_parameters" { + description = "The user configuration parameters based on the current storage template." + type = map(string) +} + +variable "user_secret_parameters" { + description = "The user secret parameters based on the current storage template." + type = map(string) +} + +variable "storage_class_parameters" { + description = "List of storage class parameters if supported by the storage template" + type = list(map(string)) +} \ No newline at end of file diff --git a/go.mod b/go.mod index d60f2a3b44..78a3403ee3 100644 --- a/go.mod +++ b/go.mod @@ -4,8 +4,8 @@ go 1.18 require ( github.com/IBM-Cloud/bluemix-go v0.0.0-20230601050310-eecebfbff63e - github.com/IBM-Cloud/container-services-go-sdk v0.0.0-20230118060037-101bda076037 - github.com/IBM-Cloud/power-go-client v1.2.4 + github.com/IBM-Cloud/container-services-go-sdk v0.0.0-20230822142550-30562e113de9 + github.com/IBM-Cloud/power-go-client v1.2.2 github.com/IBM/apigateway-go-sdk v0.0.0-20210714141226-a5d5d49caaca github.com/IBM/appconfiguration-go-admin-sdk v0.3.0 github.com/IBM/appid-management-go-sdk v0.0.0-20210908164609-dd0e0eaf732f @@ -60,6 +60,17 @@ require ( k8s.io/api v0.26.3 k8s.io/apimachinery v0.26.3 k8s.io/client-go v0.26.1 +) + +require ( + github.com/IBM/go-sdk-core/v3 v3.2.4 + github.com/IBM/project-go-sdk v0.0.10 + github.com/akamai/AkamaiOPEN-edgegrid-golang v1.2.2 + github.com/akamai/AkamaiOPEN-edgegrid-golang/v5 v5.0.0 + github.com/pkg/errors v0.9.1 + github.com/rook/rook v1.11.4 + gopkg.in/yaml.v3 v3.0.1 + k8s.io/utils v0.0.0-20230313181309-38a27ef9d749 sigs.k8s.io/controller-runtime v0.14.1 ) @@ -209,7 +220,6 @@ require ( gopkg.in/yaml.v2 v2.4.0 // indirect k8s.io/klog/v2 v2.90.1 // indirect k8s.io/kube-openapi v0.0.0-20221110221610-a28e98eb7c70 // indirect - k8s.io/utils v0.0.0-20230313181309-38a27ef9d749 // indirect sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect sigs.k8s.io/yaml v1.3.0 // indirect diff --git a/go.sum b/go.sum index 5f051d8e9c..12d71481a0 100644 --- a/go.sum +++ b/go.sum @@ -100,8 +100,8 @@ github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3 github.com/DataDog/zstd v1.4.4/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= github.com/IBM-Cloud/bluemix-go v0.0.0-20230601050310-eecebfbff63e h1:0GNM+YmWoFcq8/cih+oZAv+cdvNt8ZdFO807QbBzm1Y= github.com/IBM-Cloud/bluemix-go v0.0.0-20230601050310-eecebfbff63e/go.mod h1:cO5KCpiop9eP/pM/5W07TprYUkv/kHtajW1FiZgE59k= -github.com/IBM-Cloud/container-services-go-sdk v0.0.0-20230118060037-101bda076037 h1:C1gOsj2A5ouRUXrmKHebXjs4FXRE8ApMUC3GBUpd9Co= -github.com/IBM-Cloud/container-services-go-sdk v0.0.0-20230118060037-101bda076037/go.mod h1:xUQL9SGAjoZFd4GNjrjjtEpjpkgU7RFXRyHesbKTjiY= +github.com/IBM-Cloud/container-services-go-sdk v0.0.0-20230822142550-30562e113de9 h1:sXRzCK3Glxpyu66Tu2NjztLdT5sDwj4qly+MJKRhdWY= +github.com/IBM-Cloud/container-services-go-sdk v0.0.0-20230822142550-30562e113de9/go.mod h1:xUQL9SGAjoZFd4GNjrjjtEpjpkgU7RFXRyHesbKTjiY= github.com/IBM-Cloud/ibm-cloud-cli-sdk v0.5.3/go.mod h1:RiUvKuHKTBmBApDMUQzBL14pQUGKcx/IioKQPIcRQjs= github.com/IBM-Cloud/power-go-client v1.2.2 h1:VNlzizoG2x06c3nL1ZBILF701QcvXcu6nEH3hmEKCkw= github.com/IBM-Cloud/power-go-client v1.2.2/go.mod h1:Qfx0fNi+9hms+xu9Z6Euhu9088ByW6C/TCMLECTRWNE= diff --git a/ibm/provider/provider.go b/ibm/provider/provider.go index 887ca918c9..77364e1991 100644 --- a/ibm/provider/provider.go +++ b/ibm/provider/provider.go @@ -704,6 +704,8 @@ func Provider() *schema.Provider { "ibm_satellite_link": satellite.DataSourceIBMSatelliteLink(), "ibm_satellite_endpoint": satellite.DataSourceIBMSatelliteEndpoint(), "ibm_satellite_cluster_worker_pool_zone_attachment": satellite.DataSourceIBMSatelliteClusterWorkerPoolAttachment(), + "ibm_satellite_storage_configuration": satellite.DataSourceIBMSatelliteStorageConfiguration(), + "ibm_satellite_storage_assignment": satellite.DataSourceIBMSatelliteStorageAssignment(), // Catalog related resources "ibm_cm_catalog": catalogmanagement.DataSourceIBMCmCatalog(), @@ -1221,6 +1223,8 @@ func Provider() *schema.Provider { "ibm_satellite_cluster": satellite.ResourceIBMSatelliteCluster(), "ibm_satellite_cluster_worker_pool": satellite.ResourceIBMSatelliteClusterWorkerPool(), "ibm_satellite_link": satellite.ResourceIBMSatelliteLink(), + "ibm_satellite_storage_configuration": satellite.ResourceIBMSatelliteStorageConfiguration(), + "ibm_satellite_storage_assignment": satellite.ResourceIBMSatelliteStorageAssignment(), "ibm_satellite_endpoint": satellite.ResourceIBMSatelliteEndpoint(), "ibm_satellite_location_nlb_dns": satellite.ResourceIBMSatelliteLocationNlbDns(), "ibm_satellite_cluster_worker_pool_zone_attachment": satellite.ResourceIbmSatelliteClusterWorkerPoolZoneAttachment(), diff --git a/ibm/service/satellite/data_source_ibm_satellite_storage_assignment.go b/ibm/service/satellite/data_source_ibm_satellite_storage_assignment.go new file mode 100644 index 0000000000..cf4c478cec --- /dev/null +++ b/ibm/service/satellite/data_source_ibm_satellite_storage_assignment.go @@ -0,0 +1,163 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package satellite + +import ( + "fmt" + + "github.com/IBM-Cloud/container-services-go-sdk/kubernetesserviceapiv1" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func DataSourceIBMSatelliteStorageAssignment() *schema.Resource { + return &schema.Resource{ + Read: dataSourceIBMSatelliteStorageAssignmentRead, + + Schema: map[string]*schema.Schema{ + "assignment_name": { + Type: schema.TypeString, + Computed: true, + Description: "Name of the Assignment.", + }, + "uuid": { + Type: schema.TypeString, + Required: true, + Description: "The Universally Unique IDentifier (UUID) of the Assignment.", + }, + "owner": { + Type: schema.TypeString, + Computed: true, + Description: "The Owner of the Assignment.", + }, + "groups": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Description: "One or more cluster groups on which you want to apply the configuration. Note that at least one cluster group is required. ", + }, + "cluster": { + Type: schema.TypeString, + Computed: true, + Description: "ID of the Satellite cluster or Service Cluster that you want to apply the configuration to.", + }, + "svc_cluster": { + Type: schema.TypeString, + Computed: true, + Description: "ID of the Service Cluster that you applied the configuration to.", + }, + "sat_cluster": { + Type: schema.TypeString, + Computed: true, + Description: "ID of the Satellite cluster that you applied the configuration to.", + }, + "config": { + Type: schema.TypeString, + Computed: true, + Description: "Storage Configuration Name or ID.", + }, + "config_uuid": { + Type: schema.TypeString, + Computed: true, + Description: "The Universally Unique IDentifier (UUID) of the Storage Configuration.", + }, + "config_version": { + Type: schema.TypeString, + Computed: true, + Description: "The Storage Configuration Version.", + }, + "config_version_uuid": { + Type: schema.TypeString, + Computed: true, + Description: "The Universally Unique IDentifier (UUID) of the Storage Configuration Version.", + }, + "assignment_type": { + Type: schema.TypeString, + Computed: true, + Description: "The Type of Assignment.", + }, + "created": { + Type: schema.TypeString, + Computed: true, + Description: "The Time of Creation of the Assignment.", + }, + "rollout_success_count": { + Type: schema.TypeInt, + Computed: true, + Description: "The Rollout Success Count of the Assignment.", + }, + "rollout_error_count": { + Type: schema.TypeInt, + Computed: true, + Description: "The Rollout Error Count of the Assignment.", + }, + "is_assignment_upgrade_available": { + Type: schema.TypeBool, + Computed: true, + Description: "Whether an Upgrade is Available for the Assignment.", + }, + }, + } +} + +func dataSourceIBMSatelliteStorageAssignmentRead(d *schema.ResourceData, meta interface{}) error { + + satClient, err := meta.(conns.ClientSession).SatelliteClientSession() + if err != nil { + return err + } + + uuid := d.Get("uuid").(string) + getAssignmentOptions := &kubernetesserviceapiv1.GetAssignmentOptions{ + UUID: &uuid, + } + + result, _, err := satClient.GetAssignment(getAssignmentOptions) + if err != nil { + return fmt.Errorf("[ERROR] Error getting Assignment of UUID %s - %v", uuid, err) + } + + d.SetId(uuid + "/" + *result.Name) + d.Set("assignment_name", *result.Name) + d.Set("uuid", *result.UUID) + d.Set("owner", *result.Owner.Name) + if result.Groups != nil { + d.Set("groups", result.Groups) + } + if result.Cluster != nil { + d.Set("cluster", *result.Cluster) + } + if result.SatSvcClusterID != nil { + d.Set("svc_cluster", *result.SatSvcClusterID) + } + if result.Satcluster != nil { + d.Set("sat_cluster", *result.Satcluster) + } + if result.ChannelName != nil { + d.Set("config", *result.ChannelName) + } + if result.ChannelUUID != nil { + d.Set("config_uuid", *result.ChannelUUID) + } + if result.Version != nil { + d.Set("config_version", *result.Version) + } + if result.VersionUUID != nil { + d.Set("config_version_uuid", *result.VersionUUID) + } + if result.SubscriptionType != nil { + d.Set("assignment_type", *result.SubscriptionType) + } + if result.Created != nil { + d.Set("created", *result.Created) + } + if result.IsAssignmentUpgradeAvailable != nil { + d.Set("is_assignment_upgrade_available", *result.IsAssignmentUpgradeAvailable) + } + if result.RolloutStatus != nil { + d.Set("rollout_success_count", *result.RolloutStatus.SuccessCount) + d.Set("rollout_error_count", *result.RolloutStatus.ErrorCount) + } + return nil +} diff --git a/ibm/service/satellite/data_source_ibm_satellite_storage_assignment_test.go b/ibm/service/satellite/data_source_ibm_satellite_storage_assignment_test.go new file mode 100644 index 0000000000..8483791a38 --- /dev/null +++ b/ibm/service/satellite/data_source_ibm_satellite_storage_assignment_test.go @@ -0,0 +1,54 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package satellite_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIbmSatelliteStorageAssignmentDataSourceBasic(t *testing.T) { + uuid := fmt.Sprintf("tf-uuid-%d", acctest.RandIntRange(10, 100)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIbmSatelliteStorageAssignmentDataSourceConfigBasic(uuid), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_satellite_storage_assignment.satellite_storage_assignment", "uuid"), + resource.TestCheckResourceAttrSet("data.ibm_satellite_storage_assignment.satellite_storage_assignment", "assignment_name"), + resource.TestCheckResourceAttrSet("data.ibm_satellite_storage_assignment.satellite_storage_assignment", "owner"), + resource.TestCheckResourceAttrSet("data.ibm_satellite_storage_assignment.satellite_storage_assignment", "groups"), + resource.TestCheckResourceAttrSet("data.ibm_satellite_storage_assignment.satellite_storage_assignment", "cluster"), + resource.TestCheckResourceAttrSet("data.ibm_satellite_storage_assignment.satellite_storage_assignment", "svc_cluster"), + resource.TestCheckResourceAttrSet("data.ibm_satellite_storage_assignment.satellite_storage_assignment", "sat_cluster"), + resource.TestCheckResourceAttrSet("data.ibm_satellite_storage_assignment.satellite_storage_assignment", "config"), + resource.TestCheckResourceAttrSet("data.ibm_satellite_storage_assignment.satellite_storage_assignment", "config_uuid"), + resource.TestCheckResourceAttrSet("data.ibm_satellite_storage_assignment.satellite_storage_assignment", "config_version"), + resource.TestCheckResourceAttrSet("data.ibm_satellite_storage_assignment.satellite_storage_assignment", "config_version_uuid"), + resource.TestCheckResourceAttrSet("data.ibm_satellite_storage_assignment.satellite_storage_assignment", "assignment_type"), + resource.TestCheckResourceAttrSet("data.ibm_satellite_storage_assignment.satellite_storage_assignment", "created"), + resource.TestCheckResourceAttrSet("data.ibm_satellite_storage_assignment.satellite_storage_assignment", "rollout_success_count"), + resource.TestCheckResourceAttrSet("data.ibm_satellite_storage_assignment.satellite_storage_assignment", "rollout_error_count"), + resource.TestCheckResourceAttrSet("data.ibm_satellite_storage_assignment.satellite_storage_assignment", "is_assignment_upgrade_available"), + ), + }, + }, + }) +} + +func testAccCheckIbmSatelliteStorageAssignmentDataSourceConfigBasic(uuid string) string { + return fmt.Sprintf(` + data "ibm_satellite_storage_assignment" "satellite_storage_assignment" { + uuid = "%s" + } + `, uuid) +} diff --git a/ibm/service/satellite/data_source_ibm_satellite_storage_configuration.go b/ibm/service/satellite/data_source_ibm_satellite_storage_configuration.go new file mode 100644 index 0000000000..8133b41ab6 --- /dev/null +++ b/ibm/service/satellite/data_source_ibm_satellite_storage_configuration.go @@ -0,0 +1,104 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package satellite + +import ( + "fmt" + + "github.com/IBM-Cloud/container-services-go-sdk/kubernetesserviceapiv1" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func DataSourceIBMSatelliteStorageConfiguration() *schema.Resource { + return &schema.Resource{ + Read: dataSourceIBMSatelliteStorageConfigurationRead, + + Schema: map[string]*schema.Schema{ + "location": { + Type: schema.TypeString, + Required: true, + Description: "The Location Name.", + }, + "config_name": { + Type: schema.TypeString, + Required: true, + Description: "Name of the Storage Configuration.", + }, + "config_version": { + Type: schema.TypeString, + Computed: true, + Description: "Version of the Storage Configuration.", + }, + "storage_template_name": { + Type: schema.TypeString, + Computed: true, + Description: "The Storage Template Name.", + }, + "storage_template_version": { + Type: schema.TypeString, + Computed: true, + Description: "The Storage Template Version.", + }, + "user_config_parameters": { + Type: schema.TypeMap, + Computed: true, + Description: "The storage configuration parameters depending on the storage template.", + }, + "storage_class_parameters": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{ + Type: schema.TypeMap, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + Description: "The List of Storage Class Parameters as a list of a Map of string key-value.", + }, + }, + "uuid": { + Type: schema.TypeString, + Computed: true, + Description: "The Universally Unique IDentifier (UUID) of the Storage Configuration.", + }, + }, + } +} + +func dataSourceIBMSatelliteStorageConfigurationRead(d *schema.ResourceData, meta interface{}) error { + satClient, err := meta.(conns.ClientSession).SatelliteClientSession() + if err != nil { + return err + } + + satLocation := d.Get("location").(string) + d.Set("location", satLocation) + getSatelliteLocation := &kubernetesserviceapiv1.GetSatelliteLocationOptions{ + Controller: &satLocation, + } + _, _, err = satClient.GetSatelliteLocation(getSatelliteLocation) + if err != nil { + return fmt.Errorf("[ERROR] Location not found! - %v", err) + } + + storageConfigName := d.Get("config_name").(string) + getStorageConfigurationOptions := &kubernetesserviceapiv1.GetStorageConfigurationOptions{ + Name: &storageConfigName, + } + result, _, err := satClient.GetStorageConfiguration(getStorageConfigurationOptions) + if err != nil { + return err + } + + d.Set("config_name", *result.ConfigName) + d.Set("config_version", *result.ConfigVersion) + d.Set("storage_template_name", *result.StorageTemplateName) + d.Set("storage_template_version", *result.StorageTemplateVersion) + d.Set("user_config_parameters", result.UserConfigParameters) + d.Set("storage_class_parameters", result.StorageClassParameters) + d.Set("uuid", *result.UUID) + d.SetId(*result.UUID + "/" + satLocation) + + return nil +} diff --git a/ibm/service/satellite/data_source_ibm_satellite_storage_configuration_test.go b/ibm/service/satellite/data_source_ibm_satellite_storage_configuration_test.go new file mode 100644 index 0000000000..9265a54957 --- /dev/null +++ b/ibm/service/satellite/data_source_ibm_satellite_storage_configuration_test.go @@ -0,0 +1,54 @@ +// Copyright IBM Corp. 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package satellite_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIbmSatelliteStorageConfigurationDataSourceBasic(t *testing.T) { + configName := fmt.Sprintf("tf-config-name-%d", acctest.RandIntRange(10, 100)) + location := "satellite-location" + secretKey := "apikey" + secretValue := "apikey - value" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckIbmSatelliteStorageConfigurationDataSourceConfigBasic(location, configName, secretKey, secretValue), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_satellite_storage_configuration.satellite_storage_configuration", "uuid"), + resource.TestCheckResourceAttrSet("data.ibm_satellite_storage_configuration.satellite_storage_configuration", "location"), + resource.TestCheckResourceAttrSet("data.ibm_satellite_storage_configuration.satellite_storage_configuration", "config_name"), + resource.TestCheckResourceAttrSet("data.ibm_satellite_storage_configuration.satellite_storage_configuration", "config_version"), + resource.TestCheckResourceAttrSet("data.ibm_satellite_storage_configuration.satellite_storage_configuration", "storage_template_name"), + resource.TestCheckResourceAttrSet("data.ibm_satellite_storage_configuration.satellite_storage_configuration", "storage_template_version"), + resource.TestCheckResourceAttrSet("data.ibm_satellite_storage_configuration.satellite_storage_configuration", "user_config_parameters"), + resource.TestCheckResourceAttrSet("data.ibm_satellite_storage_configuration.satellite_storage_configuration", "user_secret_parameters"), + resource.TestCheckResourceAttrSet("data.ibm_satellite_storage_configuration.satellite_storage_configuration", "storage_class_parameters"), + ), + }, + }, + }) +} + +func testAccCheckIbmSatelliteStorageConfigurationDataSourceConfigBasic(location string, configName string, secretKey string, secretValue string) string { + return fmt.Sprintf(` + data "ibm_satellite_storage_configuration" "satellite_storage_configuration" { + location = "%s" + config_name = "%s" + user_secret_parameters = { + %s : "%s" + } + } + `, location, configName, secretKey, secretValue) +} diff --git a/ibm/service/satellite/resource_ibm_satellite_storage_assignment.go b/ibm/service/satellite/resource_ibm_satellite_storage_assignment.go new file mode 100644 index 0000000000..07b5d1bc51 --- /dev/null +++ b/ibm/service/satellite/resource_ibm_satellite_storage_assignment.go @@ -0,0 +1,383 @@ +package satellite + +import ( + "fmt" + "time" + + "github.com/IBM-Cloud/container-services-go-sdk/kubernetesserviceapiv1" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func ResourceIBMSatelliteStorageAssignment() *schema.Resource { + return &schema.Resource{ + Create: resourceIBMContainerStorageAssignmentCreate, + Read: resourceIBMContainerStorageAssignmentRead, + Update: resourceIBMContainerStorageAssignmentUpdate, + Delete: resourceIBMContainerStorageAssignmentDelete, + Importer: &schema.ResourceImporter{}, + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(20 * time.Minute), + Update: schema.DefaultTimeout(20 * time.Minute), + Delete: schema.DefaultTimeout(20 * time.Minute), + }, + + Schema: map[string]*schema.Schema{ + "assignment_name": { + Type: schema.TypeString, + Required: true, + Description: "Name of the Assignment.", + }, + "uuid": { + Type: schema.TypeString, + Computed: true, + ForceNew: true, + Description: "The Universally Unique IDentifier (UUID) of the Assignment.", + }, + "owner": { + Type: schema.TypeString, + Computed: true, + Description: "The Owner of the Assignment.", + }, + "groups": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeString}, + ConflictsWith: []string{"cluster", "controller"}, + Description: "One or more cluster groups on which you want to apply the configuration. Note that at least one cluster group is required. ", + }, + "cluster": { + Type: schema.TypeString, + Optional: true, + Description: "ID of the Satellite cluster or Service Cluster that you want to apply the configuration to.", + DiffSuppressFunc: flex.ApplyOnce, + RequiredWith: []string{"controller"}, + }, + "svc_cluster": { + Type: schema.TypeString, + Computed: true, + Description: "ID of the Service Cluster that you applied the configuration to.", + }, + "sat_cluster": { + Type: schema.TypeString, + Computed: true, + Description: "ID of the Satellite cluster that you applied the configuration to.", + }, + "config": { + Type: schema.TypeString, + Required: true, + DiffSuppressFunc: flex.ApplyOnce, + Description: "Storage Configuration Name or ID.", + }, + "config_uuid": { + Type: schema.TypeString, + Computed: true, + Description: "The Universally Unique IDentifier (UUID) of the Storage Configuration.", + }, + "config_version": { + Type: schema.TypeString, + Computed: true, + Description: "The Storage Configuration Version.", + }, + "config_version_uuid": { + Type: schema.TypeString, + Computed: true, + Description: "The Universally Unique IDentifier (UUID) of the Storage Configuration Version.", + }, + "assignment_type": { + Type: schema.TypeString, + Computed: true, + Description: "The Type of Assignment.", + }, + "created": { + Type: schema.TypeString, + Computed: true, + Description: "The Time of Creation of the Assignment.", + }, + "rollout_success_count": { + Type: schema.TypeInt, + Computed: true, + Description: "The Rollout Success Count of the Assignment.", + }, + "rollout_error_count": { + Type: schema.TypeInt, + Computed: true, + Description: "The Rollout Error Count of the Assignment.", + }, + "is_assignment_upgrade_available": { + Type: schema.TypeBool, + Computed: true, + ForceNew: false, + Description: "Whether an Upgrade is Available for the Assignment.", + }, + "update_config_revision": { + Type: schema.TypeBool, + Default: false, + Optional: true, + Description: "Updating an assignment to the latest available storage configuration version.", + }, + "controller": { + Type: schema.TypeString, + Optional: true, + Description: "The Name or ID of the Satellite Location.", + ConflictsWith: []string{"groups"}, + RequiredWith: []string{"cluster"}, + }, + }, + } +} + +func resourceIBMContainerStorageAssignmentCreate(d *schema.ResourceData, meta interface{}) error { + + satClient, err := meta.(conns.ClientSession).SatelliteClientSession() + if err != nil { + return err + } + + var result *kubernetesserviceapiv1.CreateSubscriptionData + + assignmentOptions := &kubernetesserviceapiv1.CreateAssignmentOptions{} + + if v, ok := d.GetOk("assignment_name"); ok { + name := v.(string) + assignmentOptions.Name = &name + } + + if v, ok := d.GetOk("config"); ok { + config := v.(string) + assignmentOptions.Config = &config + } + + if v, ok := d.GetOk("cluster"); ok { + cluster := v.(string) + assignmentOptions.Cluster = &cluster + } + + if v, ok := d.GetOk("controller"); ok { + controller := v.(string) + assignmentOptions.Controller = &controller + } + // If Groups are defined, create assignment to group function is called or else an assignment is made to a cluster + if v, groupsOk := d.GetOk("groups"); groupsOk { + groups := v.([]interface{}) + assignmentOptions.Groups = flex.ExpandStringList(groups) + result, _, err = satClient.CreateAssignment(assignmentOptions) + if err != nil { + return fmt.Errorf("[ERROR] Error Creating Assignment - %v", err) + } + } else { + result, _, err = satClient.CreateAssignmentByCluster(assignmentOptions) + if err != nil { + return fmt.Errorf("[ERROR] Error Creating Assignment by Cluster - %v", err) + } + } + + d.Set("uuid", *result.AddSubscription.UUID) + + getAssignmentOptions := &kubernetesserviceapiv1.GetAssignmentOptions{ + UUID: result.AddSubscription.UUID, + } + _, err = waitForAssignmentCreationStatus(getAssignmentOptions, meta, d) + if err != nil { + return err + } + d.SetId(*result.AddSubscription.UUID) + + return resourceIBMContainerStorageAssignmentRead(d, meta) +} + +func resourceIBMContainerStorageAssignmentRead(d *schema.ResourceData, meta interface{}) error { + + satClient, err := meta.(conns.ClientSession).SatelliteClientSession() + if err != nil { + return err + } + + uuid := d.Get("uuid").(string) + controller := d.Get("controller").(string) + d.Set("controller", controller) + + getAssignmentOptions := &kubernetesserviceapiv1.GetAssignmentOptions{ + UUID: &uuid, + } + + result, _, err := satClient.GetAssignment(getAssignmentOptions) + if err != nil { + return fmt.Errorf("[ERROR] Error getting Assignment of UUID %s - %v", uuid, err) + } + d.Set("assignment_name", *result.Name) + d.Set("uuid", *result.UUID) + d.Set("owner", *result.Owner.Name) + if result.Groups != nil { + d.Set("groups", result.Groups) + } + if result.Cluster != nil { + d.Set("cluster", *result.Cluster) + } + if result.SatSvcClusterID != nil { + d.Set("svc_cluster", *result.SatSvcClusterID) + } + if result.Satcluster != nil { + d.Set("sat_cluster", *result.Satcluster) + } + if result.ChannelName != nil { + d.Set("config", *result.ChannelName) + } + if result.ChannelUUID != nil { + d.Set("config_uuid", *result.ChannelUUID) + } + if result.Version != nil { + d.Set("config_version", *result.Version) + } + if result.VersionUUID != nil { + d.Set("config_version_uuid", *result.VersionUUID) + } + if result.SubscriptionType != nil { + d.Set("assignment_type", *result.SubscriptionType) + } + if result.Created != nil { + d.Set("created", *result.Created) + } + if result.IsAssignmentUpgradeAvailable != nil { + d.Set("is_assignment_upgrade_available", *result.IsAssignmentUpgradeAvailable) + } + if result.RolloutStatus != nil { + d.Set("rollout_success_count", *result.RolloutStatus.SuccessCount) + d.Set("rollout_error_count", *result.RolloutStatus.ErrorCount) + } + d.Set("update_config_revision", false) + return nil +} + +func resourceIBMContainerStorageAssignmentUpdate(d *schema.ResourceData, meta interface{}) error { + uuid := d.Get("uuid").(string) + updateAssignmentOptions := &kubernetesserviceapiv1.UpdateAssignmentOptions{} + updateAssignmentOptions.UUID = &uuid + + if d.HasChange("assignment_name") || d.HasChange("groups") || d.HasChange("update_config_revision") && !d.IsNewResource() { + assignmentName := d.Get("assignment_name").(string) + updateAssignmentOptions.Name = &assignmentName + + groups := flex.ExpandStringList(d.Get("groups").([]interface{})) + updateAssignmentOptions.Groups = groups + + updateConfigRevision := d.Get("update_config_revision").(bool) + updateAssignmentOptions.UpdateConfigVersion = &updateConfigRevision + + _, err := waitForAssignmentUpdateStatus(updateAssignmentOptions, meta, d) + if err != nil { + return fmt.Errorf("[ERROR] Error Updating Assignment with UUID %s - %v", uuid, err) + } + } + return resourceIBMContainerStorageAssignmentRead(d, meta) +} + +func resourceIBMContainerStorageAssignmentDelete(d *schema.ResourceData, meta interface{}) error { + uuid := d.Get("uuid").(string) + removeAssignmentOptions := &kubernetesserviceapiv1.RemoveAssignmentOptions{} + removeAssignmentOptions.UUID = &uuid + + _, err := waitForAssignmentDeletionStatus(removeAssignmentOptions, meta, d) + if err != nil { + return fmt.Errorf("[ERROR] Error Removing Assignment with UUID %s - %v", uuid, err) + } + + d.SetId("") + return nil +} + +func waitForAssignmentCreationStatus(getAssignmentOptions *kubernetesserviceapiv1.GetAssignmentOptions, meta interface{}, d *schema.ResourceData) (interface{}, error) { + stateConf := &resource.StateChangeConf{ + Pending: []string{"NotReady"}, + Target: []string{"Ready"}, + Refresh: assignmentCreationStatusRefreshFunc(getAssignmentOptions, meta), + Timeout: d.Timeout(schema.TimeoutCreate), + Delay: 10 * time.Second, + MinTimeout: 10 * time.Second, + NotFoundChecks: 100, + } + return stateConf.WaitForState() +} + +func assignmentCreationStatusRefreshFunc(getAssignmentOptions *kubernetesserviceapiv1.GetAssignmentOptions, meta interface{}) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + + satClient, err := meta.(conns.ClientSession).SatelliteClientSession() + + if err != nil { + return nil, "NotReady", err + } + _, response, err := satClient.GetAssignment(getAssignmentOptions) + + if response.GetStatusCode() == 200 { + return true, "Ready", nil + } + + return nil, "NotReady", nil + } +} + +func waitForAssignmentUpdateStatus(updateAssignmentOptions *kubernetesserviceapiv1.UpdateAssignmentOptions, meta interface{}, d *schema.ResourceData) (interface{}, error) { + stateConf := &resource.StateChangeConf{ + Pending: []string{"NotReady"}, + Target: []string{"Ready"}, + Refresh: assignmentUpdateStatusRefreshFunc(updateAssignmentOptions, meta), + Timeout: d.Timeout(schema.TimeoutUpdate), + Delay: 10 * time.Second, + MinTimeout: 10 * time.Second, + NotFoundChecks: 100, + } + return stateConf.WaitForState() +} + +func assignmentUpdateStatusRefreshFunc(updateAssignmentOptions *kubernetesserviceapiv1.UpdateAssignmentOptions, meta interface{}) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + + satClient, err := meta.(conns.ClientSession).SatelliteClientSession() + + if err != nil { + return nil, "NotReady", err + } + + result, _, err := satClient.UpdateAssignment(updateAssignmentOptions) + + if *result.EditSubscription.Success == true && err == nil { + return true, "Ready", nil + } + + return nil, "NotReady", nil + } +} + +func waitForAssignmentDeletionStatus(removeAssignmentOptions *kubernetesserviceapiv1.RemoveAssignmentOptions, meta interface{}, d *schema.ResourceData) (interface{}, error) { + stateConf := &resource.StateChangeConf{ + Pending: []string{"NotReady"}, + Target: []string{"Ready"}, + Refresh: assignmentDeletionStatusRefreshFunc(removeAssignmentOptions, meta), + Timeout: d.Timeout(schema.TimeoutDelete), + Delay: 10 * time.Second, + MinTimeout: 10 * time.Second, + NotFoundChecks: 100, + } + return stateConf.WaitForState() +} + +func assignmentDeletionStatusRefreshFunc(removeAssignmentOptions *kubernetesserviceapiv1.RemoveAssignmentOptions, meta interface{}) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + + satClient, err := meta.(conns.ClientSession).SatelliteClientSession() + + if err != nil { + return nil, "NotReady", err + } + + response, _, err := satClient.RemoveAssignment(removeAssignmentOptions) + if *response.RemoveSubscription.Success == true && err == nil { + return true, "Ready", nil + } + + return nil, "NotReady", nil + } +} diff --git a/ibm/service/satellite/resource_ibm_satellite_storage_assignment_test.go b/ibm/service/satellite/resource_ibm_satellite_storage_assignment_test.go new file mode 100644 index 0000000000..a41e35fee7 --- /dev/null +++ b/ibm/service/satellite/resource_ibm_satellite_storage_assignment_test.go @@ -0,0 +1,113 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package satellite_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + + "github.com/IBM-Cloud/container-services-go-sdk/kubernetesserviceapiv1" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" +) + +func TestAccSatelliteStorageAssignment_Basic(t *testing.T) { + assignment_name := fmt.Sprintf("tf_assignment_%d", acctest.RandIntRange(10, 100)) + controller := "test-controller" + config := "test-odf-remote" + cluster := "test-cluster" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckSatelliteStorageConfigurationDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckSatelliteStorageAssignmentCreate(controller, assignment_name, config, cluster), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr( + "ibm_satellite_storage_assignment", "assignment.#", "1"), + ), + }, + { + Config: testAccCheckSatelliteStorageAssignmentUpdate(controller, assignment_name, config, cluster), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr( + "ibm_satellite_storage_assignment", "assignment.#", "2"), + ), + }, + { + ResourceName: "ibm_satellite_storage_assignment.assignment", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccCheckSatelliteStorageAssignmentDestroy(s *terraform.State) error { + satClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).SatelliteClientSession() + if err != nil { + return err + } + + for _, rs := range s.RootModule().Resources { + if rs.Type != "ibm_satellite_storage_assignment" { + continue + } + + ID := rs.Primary.ID + getAssignmentOptions := &kubernetesserviceapiv1.GetAssignmentOptions{ + UUID: &ID, + } + + _, _, err = satClient.GetAssignment(getAssignmentOptions) + if err == nil { + return fmt.Errorf("Storage Assignment still exists: %s", rs.Primary.ID) + } + + } + return nil +} + +func testAccCheckSatelliteStorageAssignmentUpdate(controller string, assignment_name string, config string, cluster string) string { + return fmt.Sprintf(` + + data "ibm_resource_group" "res_group" { + is_default = true + } + + resource "ibm_satellite_storage_assignment" "assignment" { + assignment_name = %s + cluster = %s + config = %s + controller = %s + update_config_revision = true + } + + +`, assignment_name, cluster, config, controller) +} + +func testAccCheckSatelliteStorageAssignmentCreate(controller string, assignment_name string, config string, cluster string) string { + return fmt.Sprintf(` + + data "ibm_resource_group" "res_group" { + is_default = true + } + + resource "ibm_satellite_storage_assignment" "assignment" { + assignment_name = %s + cluster = %s + config = %s + controller = %s + } + + +`, assignment_name, cluster, config, controller) +} diff --git a/ibm/service/satellite/resource_ibm_satellite_storage_configuration.go b/ibm/service/satellite/resource_ibm_satellite_storage_configuration.go new file mode 100644 index 0000000000..acb74fcf77 --- /dev/null +++ b/ibm/service/satellite/resource_ibm_satellite_storage_configuration.go @@ -0,0 +1,542 @@ +package satellite + +import ( + "encoding/json" + "fmt" + "reflect" + "time" + + "github.com/IBM-Cloud/container-services-go-sdk/kubernetesserviceapiv1" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "k8s.io/utils/strings/slices" +) + +func ResourceIBMSatelliteStorageConfiguration() *schema.Resource { + return &schema.Resource{ + Create: resourceIBMContainerStorageConfigurationCreate, + Read: resourceIBMContainerStorageConfigurationRead, + Update: resourceIBMContainerStorageConfigurationUpdate, + Delete: resourceIBMContainerStorageConfigurationDelete, + Importer: &schema.ResourceImporter{}, + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(20 * time.Minute), + Delete: schema.DefaultTimeout(20 * time.Minute), + }, + + Schema: map[string]*schema.Schema{ + "location": { + Type: schema.TypeString, + Required: true, + Description: "Location ID.", + }, + "config_name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "Name of the Storage Configuration.", + }, + "config_version": { + Type: schema.TypeString, + Computed: true, + Description: "Version of the Storage Configuration.", + }, + "storage_template_name": { + Type: schema.TypeString, + Required: true, + Description: "The Storage Template Name.", + }, + "storage_template_version": { + Type: schema.TypeString, + Required: true, + Description: "The Storage Template Version.", + }, + "user_config_parameters": { + Type: schema.TypeMap, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + Required: true, + Description: "User Config Parameters to pass as a Map of string key-value.", + }, + "user_secret_parameters": { + Type: schema.TypeMap, + Sensitive: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + Required: true, + Description: "User Secret Parameters to pass as a Map of string key-value.", + }, + "storage_class_parameters": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Schema{ + Type: schema.TypeMap, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + Description: "The List of Storage Class Parameters as a list of a Map of string key-value.", + }, + }, + "uuid": { + Type: schema.TypeString, + Computed: true, + ForceNew: true, + Description: "The Universally Unique IDentifier (UUID) of the Storage Configuration.", + }, + "update_assignments": { + Type: schema.TypeBool, + Optional: true, + Default: false, + Description: "Set to update all assignments during a configuration update.", + }, + "delete_assignments": { + Type: schema.TypeBool, + Optional: true, + Default: false, + Description: "Set to delete all assignments during a configuration destroy.", + }, + }, + } +} + +// Helper Function to convert map[string]interface to map[string]string +func convertToMapStringString(mapInterface map[string]interface{}) map[string]string { + data := make(map[string]string) + for k, v := range mapInterface { + data[k] = v.(string) + } + return data +} + +// Function to validate the keys of user_config_parameters and user_secrets_parameters +func validateStorageConfig(d *schema.ResourceData, meta interface{}) error { + satClient, err := meta.(conns.ClientSession).SatelliteClientSession() + if err != nil { + return err + } + + userconfigParams := convertToMapStringString(d.Get("user_config_parameters").(map[string]interface{})) + usersecretParams := convertToMapStringString(d.Get("user_secret_parameters").(map[string]interface{})) + storageTemplateName := d.Get("storage_template_name").(string) + storageTemplateVersion := d.Get("storage_template_version").(string) + storageresult := &kubernetesserviceapiv1.GetStorageTemplateOptions{ + Name: &storageTemplateName, + Version: &storageTemplateVersion, + } + // We get the details of the storage template i.e we get the parameter list for that specific template. + result, _, err := satClient.GetStorageTemplate(storageresult) + if err != nil { + return err + } + + var customparamList []string + for _, v := range result.CustomParameters { + var parameterOptions map[string]string + inrec, _ := json.Marshal(v) + json.Unmarshal(inrec, ¶meterOptions) + if parameterOptions["required"] == "true" { + _, foundConfig := userconfigParams[parameterOptions["name"]] + _, foundSecret := usersecretParams[parameterOptions["name"]] + // if "required" key parameters are not present in the terraform schema + if !(foundConfig || foundSecret) { + // if they have default values, set it with those or else throw an error + if len(parameterOptions["default"]) > 0 { + userconfigParams[parameterOptions["name"]] = parameterOptions["default"] + } else { + return fmt.Errorf("%s Parameter missing - Required", parameterOptions["name"]) + } + } + } + customparamList = append(customparamList, parameterOptions["name"]) + } + // checks if the user has entered correct parameteric keys, if the key is not found an error is thrown + for k, _ := range userconfigParams { + if !slices.Contains(customparamList, k) { + return fmt.Errorf("Config Parameter %s not found", k) + } + } + + // checks if the user has entered correct secret keys, if the key is not found an error is thrown + for k, _ := range usersecretParams { + if !slices.Contains(customparamList, k) { + return fmt.Errorf("Secret Parameter %s not found", k) + } + } + + return nil +} + +func resourceIBMContainerStorageConfigurationCreate(d *schema.ResourceData, meta interface{}) error { + satClient, err := meta.(conns.ClientSession).SatelliteClientSession() + if err != nil { + return err + } + createStorageConfigurationOptions := &kubernetesserviceapiv1.CreateStorageConfigurationOptions{} + satLocation := d.Get("location").(string) + createStorageConfigurationOptions.Controller = &satLocation + + err = validateStorageConfig(d, meta) + if err != nil { + return err + } + + var configName string + if v, ok := d.GetOk("config_name"); ok { + configName = v.(string) + createStorageConfigurationOptions.SetConfigName(v.(string)) + } + + if v, ok := d.GetOk("storage_template_name"); ok { + createStorageConfigurationOptions.SetStorageTemplateName(v.(string)) + } + + if v, ok := d.GetOk("storage_template_version"); ok { + createStorageConfigurationOptions.SetStorageTemplateVersion(v.(string)) + } + + if v, ok := d.GetOk("user_config_parameters"); ok { + userConfigParameters := convertToMapStringString(v.(map[string]interface{})) + createStorageConfigurationOptions.SetUserConfigParameters(userConfigParameters) + } + + if v, ok := d.GetOk("user_secret_parameters"); ok { + userSecretParams := convertToMapStringString(v.(map[string]interface{})) + createStorageConfigurationOptions.SetUserSecretParameters(userSecretParams) + } + // convert the storage class parameters into a list[map[string]string] + if storageClassParamsList, ok := d.GetOk("storage_class_parameters"); ok { + var scpList []map[string]string + for _, value := range storageClassParamsList.([]interface{}) { + storageclassParams := convertToMapStringString(value.(map[string]interface{})) + scpList = append(scpList, storageclassParams) + } + createStorageConfigurationOptions.SetStorageClassParameters(scpList) + } + + result, _, err := satClient.CreateStorageConfiguration(createStorageConfigurationOptions) + if err != nil { + return fmt.Errorf("Unable to Create Storage Configuration - %v", err) + } + getStorageConfigurationOptions := &kubernetesserviceapiv1.GetStorageConfigurationOptions{ + Name: createStorageConfigurationOptions.ConfigName, + } + // If we are able to successful get the configuration, then create is assumed to be a success + _, err = waitForStorageConfigurationStatus(getStorageConfigurationOptions, meta, d) + if err != nil { + return err + } + + d.SetId(*result.AddChannel.UUID + "/" + configName) + return resourceIBMContainerStorageConfigurationRead(d, meta) +} + +func resourceIBMContainerStorageConfigurationRead(d *schema.ResourceData, meta interface{}) error { + satClient, err := meta.(conns.ClientSession).SatelliteClientSession() + if err != nil { + return err + } + + satLocation := d.Get("location").(string) + d.Set("location", satLocation) + // We will only set the user defined storage classes in the terraform state file + var scDefinedList []map[string]string + if storageClassParamsList, ok := d.GetOk("storage_class_parameters"); ok { + for _, value := range storageClassParamsList.([]interface{}) { + storageclassParams := convertToMapStringString(value.(map[string]interface{})) + scDefinedList = append(scDefinedList, storageclassParams) + } + } + + storageConfigName := d.Get("config_name").(string) + getStorageConfigurationOptions := &kubernetesserviceapiv1.GetStorageConfigurationOptions{ + Name: &storageConfigName, + } + + result, _, err := satClient.GetStorageConfiguration(getStorageConfigurationOptions) + if err != nil { + return err + } + + d.Set("config_name", *result.ConfigName) + d.Set("config_version", *result.ConfigVersion) + d.Set("storage_template_name", *result.StorageTemplateName) + d.Set("storage_template_version", *result.StorageTemplateVersion) + d.Set("user_config_parameters", result.UserConfigParameters) + // The secret parameters from terraform are set directly in the state file, they cannot be retreived from the server. A local copy is kept for secret parameter refresh. + userSecretParams := convertToMapStringString(d.Get("user_secret_parameters").(map[string]interface{})) + for k, _ := range result.UserSecretParameters { + result.UserSecretParameters[k] = userSecretParams[k] + } + d.Set("user_secret_parameters", result.UserSecretParameters) + var storageClassList []map[string]string + for _, v := range result.StorageClassParameters { + if getDefinedStorageClasses(scDefinedList, v) { + storageClassList = append(storageClassList, v) + } + } + // Set terraform defined storage classes + d.Set("storage_class_parameters", storageClassList) + d.Set("uuid", *result.UUID) + d.Set("update_assignments", false) + delete_assignments := d.Get("delete_assignments").(bool) + d.Set("delete_assignments", delete_assignments) + + return nil +} + +func resourceIBMContainerStorageConfigurationUpdate(d *schema.ResourceData, meta interface{}) error { + satClient, err := meta.(conns.ClientSession).SatelliteClientSession() + if err != nil { + return err + } + updateStorageConfigurationOptions := &kubernetesserviceapiv1.UpdateStorageConfigurationOptions{} + updateAssignments := d.Get("update_assignments").(bool) + configName := d.Get("config_name").(string) + satLocation := d.Get("location").(string) + updateStorageConfigurationOptions.Controller = &satLocation + + err = validateStorageConfig(d, meta) + if err != nil { + return err + } + + if d.HasChange("user_config_parameters") || d.HasChange("user_secret_parameters") || d.HasChange("storage_class_parameters") && !d.IsNewResource() { + + if v, ok := d.GetOk("config_name"); ok { + updateStorageConfigurationOptions.SetConfigName(v.(string)) + } + + if v, ok := d.GetOk("storage_template_name"); ok { + updateStorageConfigurationOptions.SetStorageTemplateName(v.(string)) + } + + if v, ok := d.GetOk("storage_template_version"); ok { + updateStorageConfigurationOptions.SetStorageTemplateVersion(v.(string)) + } + + if v, ok := d.GetOk("user_config_parameters"); ok { + userConfigParameters := convertToMapStringString(v.(map[string]interface{})) + updateStorageConfigurationOptions.SetUserConfigParameters(userConfigParameters) + } + + if v, ok := d.GetOk("user_secret_parameters"); ok { + userSecretParams := convertToMapStringString(v.(map[string]interface{})) + updateStorageConfigurationOptions.SetUserSecretParameters(userSecretParams) + } + + if storageClassParamsList, ok := d.GetOk("storage_class_parameters"); ok { + var scpList []map[string]string + for _, value := range storageClassParamsList.([]interface{}) { + storageclassParams := convertToMapStringString(value.(map[string]interface{})) + scpList = append(scpList, storageclassParams) + } + updateStorageConfigurationOptions.SetStorageClassParameters(scpList) + } + + _, _, err := satClient.UpdateStorageConfiguration(updateStorageConfigurationOptions) + if err != nil { + return fmt.Errorf("[ERROR] Unable to Update Storage Configuration %s - %v", *updateStorageConfigurationOptions.ConfigName, err) + } + + getStorageConfigurationOptions := &kubernetesserviceapiv1.GetStorageConfigurationOptions{ + Name: updateStorageConfigurationOptions.ConfigName, + } + // If we are able to successful get the configuration, then update is assumed to be a success + _, err = waitForStorageConfigurationStatus(getStorageConfigurationOptions, meta, d) + if err != nil { + return err + } + + // if the user has set the updateAssignments parameter to true, then all the assignments are auto updated with the latest configuration revision + if updateAssignments { + getAssignmentsByConfigOptions := &kubernetesserviceapiv1.GetAssignmentsByConfigOptions{ + Config: updateStorageConfigurationOptions.ConfigName, + } + + result, _, err := satClient.GetAssignmentsByConfig(getAssignmentsByConfigOptions) + if err != nil { + return err + } + + for _, v := range result { + updateStorageAssignment := &kubernetesserviceapiv1.UpdateAssignmentOptions{ + Name: v.Name, + UpdateConfigVersion: &updateAssignments, + UUID: v.UUID, + } + _, _, err := satClient.UpdateAssignment(updateStorageAssignment) + if err != nil { + return err + } + } + } + } + + // Version Upgrade Scenario, the existing configuration is deleted along with its assignments, + // a new configuration with the new template version is created and assigned back to the previously assigned clusters and groups + if d.HasChange("storage_template_version") { + getAssignmentsByConfigOptions := &kubernetesserviceapiv1.GetAssignmentsByConfigOptions{ + Config: &configName, + } + result, _, err := satClient.GetAssignmentsByConfig(getAssignmentsByConfigOptions) + if err != nil { + return err + } + err = resourceIBMContainerStorageConfigurationDelete(d, meta) + if err != nil { + return err + } + err = resourceIBMContainerStorageConfigurationCreate(d, meta) + if err != nil { + return err + } + for _, v := range result { + if len(v.Groups) != 0 { + createAssignmentGroupOptions := &kubernetesserviceapiv1.CreateAssignmentOptions{ + Name: v.Name, + Groups: v.Groups, + Config: v.ChannelName, + } + _, _, err = satClient.CreateAssignment(createAssignmentGroupOptions) + if err != nil { + return fmt.Errorf("[ERROR] Creating Assignment during Storage Configuration Upgrade - %v", err) + } + } else { + createAssignmentConfigOptions := &kubernetesserviceapiv1.CreateAssignmentOptions{ + Name: v.Name, + Config: v.ChannelName, + Cluster: v.Cluster, + Controller: &satLocation, + } + _, _, err = satClient.CreateAssignmentByCluster(createAssignmentConfigOptions) + if err != nil { + return fmt.Errorf("[ERROR] Creating Assignment during Storage Configuration Upgrade - %v", err) + } + } + } + } + + return resourceIBMContainerStorageConfigurationRead(d, meta) +} + +func resourceIBMContainerStorageConfigurationDelete(d *schema.ResourceData, meta interface{}) error { + uuid := d.Get("uuid").(string) + name := d.Get("config_name").(string) + delete_assignments := d.Get("delete_assignments").(bool) + + satClient, err := meta.(conns.ClientSession).SatelliteClientSession() + if err != nil { + return err + } + // If delete assignments = true, then all the configuration's assignments are deleted before it is destroyed. + if delete_assignments || d.HasChange("storage_template_version") { + getAssignmentsByConfigOptions := &kubernetesserviceapiv1.GetAssignmentsByConfigOptions{ + Config: &name, + } + result, _, err := satClient.GetAssignmentsByConfig(getAssignmentsByConfigOptions) + if err != nil { + return err + } + for _, v := range result { + removeAssignmentsByConfigOptions := &kubernetesserviceapiv1.RemoveAssignmentOptions{ + UUID: v.UUID, + } + _, _, err := satClient.RemoveAssignment(removeAssignmentsByConfigOptions) + if err != nil { + return fmt.Errorf("[ERROR] Failed to Delete Assignments for Storage Configuration %s - %v", name, err) + } + } + } + + _, _, err = satClient.RemoveStorageConfiguration(&kubernetesserviceapiv1.RemoveStorageConfigurationOptions{ + UUID: &uuid, + }) + if err != nil { + return fmt.Errorf("[ERROR] Error Deleting Storage Configuration %s - %v", name, err) + } + getStorageConfigurationOptions := &kubernetesserviceapiv1.GetStorageConfigurationOptions{ + Name: &name, + } + // If we cannot Get the storage configuration, it is assumed to be successfully deleted. + _, err = waitForStorageConfigurationDeletionStatus(getStorageConfigurationOptions, meta, d) + if err != nil { + return err + } + d.SetId("") + return nil +} + +// Helper function to extract only the terraform defined storage classes from the server equivalent +func getDefinedStorageClasses(definedMaps []map[string]string, getMaps map[string]string) bool { + for _, v := range definedMaps { + eq := reflect.DeepEqual(v, getMaps) + if eq { + return true + } + } + return false +} + +func waitForStorageConfigurationStatus(getStorageConfigurationOptions *kubernetesserviceapiv1.GetStorageConfigurationOptions, meta interface{}, d *schema.ResourceData) (interface{}, error) { + stateConf := &resource.StateChangeConf{ + Pending: []string{"NotReady"}, + Target: []string{"Ready"}, + Refresh: storageConfigurationStatusRefreshFunc(getStorageConfigurationOptions, meta), + Timeout: d.Timeout(schema.TimeoutCreate), + Delay: 10 * time.Second, + MinTimeout: 10 * time.Second, + NotFoundChecks: 100, + } + return stateConf.WaitForState() +} + +func storageConfigurationStatusRefreshFunc(getStorageConfigurationOptions *kubernetesserviceapiv1.GetStorageConfigurationOptions, meta interface{}) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + + satClient, err := meta.(conns.ClientSession).SatelliteClientSession() + + if err != nil { + return nil, "NotReady", err + } + _, response, err := satClient.GetStorageConfiguration(getStorageConfigurationOptions) + + if response.GetStatusCode() == 200 { + return true, "Ready", nil + } + + return nil, "NotReady", nil + } +} + +func waitForStorageConfigurationDeletionStatus(getStorageConfigurationOptions *kubernetesserviceapiv1.GetStorageConfigurationOptions, meta interface{}, d *schema.ResourceData) (interface{}, error) { + stateConf := &resource.StateChangeConf{ + Pending: []string{"NotReady"}, + Target: []string{"Ready"}, + Refresh: storageConfigurationDeletionStatusRefreshFunc(getStorageConfigurationOptions, meta), + Timeout: d.Timeout(schema.TimeoutDelete), + Delay: 10 * time.Second, + MinTimeout: 10 * time.Second, + NotFoundChecks: 100, + } + return stateConf.WaitForState() +} + +func storageConfigurationDeletionStatusRefreshFunc(getStorageConfigurationOptions *kubernetesserviceapiv1.GetStorageConfigurationOptions, meta interface{}) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + + satClient, err := meta.(conns.ClientSession).SatelliteClientSession() + + if err != nil { + return nil, "NotReady", err + } + _, response, err := satClient.GetStorageConfiguration(getStorageConfigurationOptions) + if response.GetStatusCode() == 500 { + return true, "Ready", nil + } + + return nil, "NotReady", nil + } +} diff --git a/ibm/service/satellite/resource_ibm_satellite_storage_configuration_test.go b/ibm/service/satellite/resource_ibm_satellite_storage_configuration_test.go new file mode 100644 index 0000000000..394baec68a --- /dev/null +++ b/ibm/service/satellite/resource_ibm_satellite_storage_configuration_test.go @@ -0,0 +1,123 @@ +// Copyright IBM Corp. 2017, 2021 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package satellite_test + +import ( + "fmt" + "testing" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + + "github.com/IBM-Cloud/container-services-go-sdk/kubernetesserviceapiv1" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" +) + +func TestAccSatelliteStorageConfiguration_Basic(t *testing.T) { + config_name := fmt.Sprintf("tf_config_name_%d", acctest.RandIntRange(10, 100)) + location := "satellite-location" + storage_template_name := "template-name" + storage_template_version := "template-version" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckSatelliteStorageConfigurationDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckSatelliteStorageConfigurationCreate(location, config_name, storage_template_name, storage_template_version), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr( + "ibm_satellite_storage_configuration.storage_configuration", "sc.#", "1"), + ), + }, + { + Config: testAccCheckSatelliteStorageConfigurationUpdate(location, config_name, storage_template_name, storage_template_version), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr( + "ibm_satellite_storage_configuration.storage_configuration", "sc.#", "2"), + ), + }, + { + ResourceName: "ibm_satellite_storage_configuration.storage_configuration", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccCheckSatelliteStorageConfigurationDestroy(s *terraform.State) error { + satClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).SatelliteClientSession() + if err != nil { + return err + } + + for _, rs := range s.RootModule().Resources { + if rs.Type != "ibm_satellite_storage_configuration" { + continue + } + + parts, _ := flex.IdParts(rs.Primary.ID) + getStorageConfigurationOptions := &kubernetesserviceapiv1.GetStorageConfigurationOptions{ + Name: &parts[1], + } + + _, _, err = satClient.GetStorageConfiguration(getStorageConfigurationOptions) + if err == nil { + return fmt.Errorf("Storage Configuration still exists: %s", rs.Primary.ID) + } + + } + return nil +} + +func testAccCheckSatelliteStorageConfigurationUpdate(location string, config_name string, storage_template_name string, storage_template_version string) string { + return fmt.Sprintf(` + + data "ibm_resource_group" "res_group" { + is_default = true + } + + resource "ibm_satellite_storage_configuration" "storage_configuration" { + location = %s + config_name = %s + storage_template_name = %s + storage_template_version = %s + user_config_parameters = { + numOfOsd = "2" + } + user_secret_parameters = { + ibm-api-key = "value" + } + } + +`, location, config_name, storage_template_name, storage_template_version) +} + +func testAccCheckSatelliteStorageConfigurationCreate(location string, config_name string, storage_template_name string, storage_template_version string) string { + return fmt.Sprintf(` + + data "ibm_resource_group" "res_group" { + is_default = true + } + + resource "ibm_satellite_storage_configuration" "storage_configuration" { + location = %s + config_name = %s + storage_template_name = %s + storage_template_version = %s + user_config_parameters = { + numOfOsd = "1" + } + user_secret_parameters = { + ibm-api-key = "value" + } + } + +`, location, config_name, storage_template_name, storage_template_version) +} diff --git a/website/docs/d/satellite_storage_assignment.html.markdown b/website/docs/d/satellite_storage_assignment.html.markdown new file mode 100644 index 0000000000..bda934fe1e --- /dev/null +++ b/website/docs/d/satellite_storage_assignment.html.markdown @@ -0,0 +1,45 @@ +--- +subcategory: "Satellite" +layout: "ibm" +page_title: "IBM : satellite_storage_assignment" +description: |- + Get information about an IBM Cloud Satellite Storage Assignment. +--- + +# ibm_satellite_storage_assignment +Retrieve information of an existing Satellite Storage Assignment. You can then reference the fields of the data source in other resources within the same configuration by using interpolation syntax. For more information, about IBM Cloud Satellite Storage Configurations see [Satellite Storage](https://cloud.ibm.com/docs/satellite?topic=satellite-storage-template-ov&interface=ui). + + +## Example usage + +```terraform +data "ibm_satellite_storage_assignment" "assignment" { + uuid = var.uuid +} +``` + +## Argument reference +Review the argument references that you can specify for your resource. + +- `uuid` - (String) The Universally Unique IDentifier (UUID) of the Assignment. + +## Attribute reference +In addition to all argument reference list, you can access the following attribute reference after your resource is created. + +- `assignment_name` - (String) The name of the assignment +- `config` - (String) The name of the storage configuration assigned. +- `groups` - (List(String)) A list of strings of cluster groups assigned to the defined configuration. +- `cluster` - (Required, String) The id of the cluster assigned to the defined configuration. + * Constraints: Required with `controller` and Conflicts with `groups` +- `owner` - (String) The Owner of the Assignment. +- `svc_cluster` - (String) ID of the Service Cluster that you have assigned the configuration to. +- `sat_cluster` - (String) ID of the Satellite cluster that you have assigned the configuration to. +- `config_uuid` - (String) The Universally Unique IDentifier (UUID) of the Storage Configuration. +- `config_version` - (String) The Current Storage Configuration Version. +- `config_version_uuid` - (String) The Universally Unique IDentifier (UUID) of the Storage Configuration Version. +- `assignment_type` - (String) The Type of Assignment. +- `created` - (String) The Time of Creation of the Assignment. +- `rollout_success_count` - (String) The Rollout Success Count of the Assignment. +- `rollout_error_count` - (String) The Rollout Error Count of the Assignment. +- `is_assignment_upgrade_available` - (Bool) Whether a Configuration Revision Update is Available for the Assignment. +- `id` - (String) ID of the Storage Assignment Resource diff --git a/website/docs/d/satellite_storage_configuration.html.markdown b/website/docs/d/satellite_storage_configuration.html.markdown new file mode 100644 index 0000000000..cc12c1db84 --- /dev/null +++ b/website/docs/d/satellite_storage_configuration.html.markdown @@ -0,0 +1,37 @@ +--- +subcategory: "Satellite" +layout: "ibm" +page_title: "IBM : satellite_storage_configuration" +description: |- + Get information about an IBM Cloud Satellite Storage Configuration. +--- + +# ibm_satellite_storage_configuration +Retrieve information of an existing Satellite Storage Configuration. You can then reference the fields of the data source in other resources within the same configuration by using interpolation syntax. For more information, about IBM Cloud Satellite Storage Configurations see [Satellite Storage](https://cloud.ibm.com/docs/satellite?topic=satellite-storage-template-ov&interface=ui). + + +## Example usage + +```terraform +data "ibm_satellite_storage_configuration" "storage_configuration" { + config_name = var.config_name + location = var.location +} +``` + +## Argument reference +Review the argument references that you can specify for your resource. + +- `location` - (Required, String) The name of the location where the storage configuration is created. +- `config_name` - (Required, String) The name of the storage configuration. + +## Attribute reference +In addition to all argument reference list, you can access the following attribute reference after your resource is created. + +- `storage_template_name` - (String) The storage template name used by the storage configuration. +- `storage_template_version` - (String) The version of the storage template. +- `user_config_parameters` - (Map) The Storage Configuration parameters of a particular storage template in the form of a Map. +- `storage_class_parameters` - (List(Map)) A list of the different storage classes available to the storage configuration, each in the form of a map. +- `uuid` - (String) The Universally Unique IDentifier (UUID) of the Storage Configuration. +- `config_version` - (String) The current version of the storage configuration. +- `id` - (String) The ID of the storage configuration data source. \ No newline at end of file diff --git a/website/docs/r/satellite_storage_assignment.html.markdown b/website/docs/r/satellite_storage_assignment.html.markdown new file mode 100644 index 0000000000..a4236d9023 --- /dev/null +++ b/website/docs/r/satellite_storage_assignment.html.markdown @@ -0,0 +1,79 @@ +--- +subcategory: "Satellite" +layout: "ibm" +page_title: "IBM : satellite_storage_assignment" +description: |- + Manages IBM Cloud Satellite Storage Assignment. +--- + +# ibm_satellite_storage_assignment + +Create, update, or delete [IBM Cloud Storage Assignment](https://cloud.ibm.com/docs/satellite?topic=satellite-storage-template-ov&interface=ui). With Storage Assignments, you can assign your storage configuration to clusters, service clusters, and cluster groups in your location. + +## Example usage + +### Sample to create a storage assignment to a cluster + +```terraform +resource "ibm_satellite_storage_assignment" "assignment" { + assignment_name = "assignment-name" + cluster = "cluster-id" + config = "storage-config-name" + controller = "satellite-location" +} +``` + +### Sample to create a storage assignment to a group +```terraform +resource "ibm_satellite_storage_assignment" "assignment" { + assignment_name = "assignment-name" + config = "storage-config-name" + groups = ["cluster-group-1","cluster-group-2"] +} +``` + +### Sample to update the storage configuration revision to a cluster/group +```terraform +resource "ibm_satellite_storage_assignment" "assignment" { + assignment_name = "assignment-name" + config = "storage-config-name" + groups = ["cluster-group-1","cluster-group-2"] + update_config_revision = true +} +``` +## Timeouts +The `ibm_satellite_storage_assignment` provides the following [Timeouts](https://www.terraform.io/docs/language/resources/syntax.html) configuration options: + +- **create** - (Default 20 minutes) Used for creating Instance. +- **update** - (Default 20 minutes) Used for creating Instance. +- **delete** - (Default 20 minutes) Used for deleting Instance. + +## Argument reference +Review the argument references that you can specify for your resource. + +- `assignment_name` - (Required, String) The name of the assignment +- `controller` - (Required, String) The name of the location where the storage configuration is created. + * Constraints: Required with `cluster` and Conflicts with `groups` +- `config` - (Required, String) The name of the storage configuration to be assigned. +- `groups` - (Required, List(String)) A list of strings of cluster groups you want to assign the defined configuration too. + * Constraints: Conflicts with `cluster` and `controller` +- `cluster` - (Required, String) The id of the cluster you wish to assign the defined configuration too. + * Constraints: Required with `controller` and Conflicts with `groups` +- `update_config_revision` - (Optional, Bool) Set to true to update the assignment with the latest revision of the storage configuration. + +## Attribute reference +In addition to all argument reference list, you can access the following attribute reference after your resource is created. + +- `uuid` - (String) The Universally Unique IDentifier (UUID) of the Assignment. +- `owner` - (String) The Owner of the Assignment. +- `svc_cluster` - (String) ID of the Service Cluster that you have assigned the configuration to. +- `sat_cluster` - (String) ID of the Satellite cluster that you have assigned the configuration to. +- `config_uuid` - (String) The Universally Unique IDentifier (UUID) of the Storage Configuration. +- `config_version` - (String) The Current Storage Configuration Version. +- `config_version_uuid` - (String) The Universally Unique IDentifier (UUID) of the Storage Configuration Version. +- `assignment_type` - (String) The Type of Assignment. +- `created` - (String) The Time of Creation of the Assignment. +- `rollout_success_count` - (String) The Rollout Success Count of the Assignment. +- `rollout_error_count` - (String) The Rollout Error Count of the Assignment. +- `is_assignment_upgrade_available` - (Bool) Whether a Configuration Revision Update is Available for the Assignment. +- `id` - (String) ID of the Storage Assignment Resource \ No newline at end of file diff --git a/website/docs/r/satellite_storage_configuration.html.markdown b/website/docs/r/satellite_storage_configuration.html.markdown new file mode 100644 index 0000000000..d39b66d867 --- /dev/null +++ b/website/docs/r/satellite_storage_configuration.html.markdown @@ -0,0 +1,73 @@ +--- +subcategory: "Satellite" +layout: "ibm" +page_title: "IBM : satellite_storage_configuration" +description: |- + Manages IBM Cloud Satellite Storage Configuration. +--- + +# ibm_satellite_storage_configuration + +Create, update, or delete [IBM Cloud Storage Configuration](https://cloud.ibm.com/docs/satellite?topic=satellite-storage-template-ov&interface=ui). By using storage templates, you can create storage configurations that can be consistently assigned, updated, and managed across the clusters, service clusters, and cluster groups in your location. + +## Example usage + +### Sample to create a storage configuration by using the odf-remote storage template + +```terraform +resource "ibm_satellite_storage_configuration" "storage_configuration" { + location = "location-name" + config_name = "config-name" + storage_template_name = "odf-remote" + storage_template_version = "4.12" + user_config_parameters = { + osd-size = "100Gi" + osd-storage-class = "ibmc-vpc-block-metro-5iops-tier" + billing-type = "advanced" + cluster-encryption = "false" + ibm-cos-endpoint = "" + ibm-cos-location = "" + ignore-noobaa = "false" + kms-base-url = "" + kms-encryption = "false" + kms-instance-id = "" + kms-instance-name = "" + kms-token-url = "" + num-of-osd = "1" + odf-upgrade = "true" + perform-cleanup = "false" + worker-nodes = "" + } + user_secret_parameters = { + iam-api-key = "apikey" + } +} +``` +## Timeouts +The `ibm_satellite_storage_configuration` provides the following [Timeouts](https://www.terraform.io/docs/language/resources/syntax.html) configuration options: + +- **create** - (Default 20 minutes) Used for creating Instance. +- **delete** - (Default 20 minutes) Used for deleting Instance. + +## Argument reference +Review the argument references that you can specify for your resource. + +- `location` - (Required, String) The name of the location where the storage configuration is created. +- `config_name` - (Required, String) The name of the storage configuration to be created. +- `storage_template_name` - (Required, String) The storage template name to create the storage configuration such as `odf-remote`. +- `storage_template_version` - (Required, String) The version of the storage template you'd like to use. +- `user_config_parameters` - (Required, Map) The Storage Configuration parameters of a particular storage template to be passed to be passed as a Map of string key-value. Both the key-value i.e the configuration parameter name and the respective value must be entered based on the chosen storage template. +- `user_secret_parameters` - (Required, Map) The Storage Configuration secret parameters of a particular storage template to be passed as a Map of string key-value. Both the key-value i.e the secret parameter name and the respective value must be entered based on the chosen storage template. +- `storage_class_parameters` - (Optional, List(Map)) A list of Maps, users can enter custom storage classes if the storage template supports it. Each Map will require a key-value of type string. +- `update_assignments` - (Optional, String) If set to `true` it will auto-update all the configuration's assignments with the latest revision after a configuration update. +- `delete_assignments` - (Optional, String) If set to `true` it will auto-delete all the configuration's assignments before the configuration's deletion. + +* To find out more about the different parameters and storage classes check the [available storage templates](https://cloud.ibm.com/docs/satellite?topic=satellite-storage-template-ov&interface=ui#storage-template-ov-providers) to know more. + + +## Attribute reference +In addition to all argument reference list, you can access the following attribute reference after your resource is created. + +- `uuid` - (String) The Universally Unique IDentifier (UUID) of the Storage Configuration. +- `config_version` - (String) The current version of the storage configuration. +- `id` - (String) The ID of the storage configuration resource. \ No newline at end of file