From cfba8354b93aacbda55d134c07de8b217cf0e1c3 Mon Sep 17 00:00:00 2001 From: IBM-Deeksha Date: Tue, 17 Sep 2024 16:40:18 +0530 Subject: [PATCH 1/4] Add test bucket endpoints (#5636) * add changes for test bucket endpoints * update code --------- Co-authored-by: Deeksha Sharma --- ibm/service/cos/data_source_ibm_cos_bucket.go | 3 +- ibm/service/cos/resource_ibm_cos_bucket.go | 28 ++++++++++--------- .../cos/resource_ibm_cos_bucket_object.go | 17 ++++++----- .../cos/resource_ibm_cos_bucket_test.go | 2 +- ...ource_ibm_cos_replication_configuration.go | 19 ++++++++----- 5 files changed, 40 insertions(+), 29 deletions(-) diff --git a/ibm/service/cos/data_source_ibm_cos_bucket.go b/ibm/service/cos/data_source_ibm_cos_bucket.go index 24e7c74ad9b..1e8316b38ea 100644 --- a/ibm/service/cos/data_source_ibm_cos_bucket.go +++ b/ibm/service/cos/data_source_ibm_cos_bucket.go @@ -621,7 +621,7 @@ func dataSourceIBMCosBucketRead(d *schema.ResourceData, meta interface{}) error apiEndpoint = SelectSatlocCosApi(bucketType, serviceID, satlc_id) } else { - apiEndpoint, apiEndpointPrivate, directApiEndpoint = SelectCosApi(bucketLocationConvert(bucketType), bucketRegion) + apiEndpoint, apiEndpointPrivate, directApiEndpoint = SelectCosApi(bucketLocationConvert(bucketType), bucketRegion, false) visibility = endpointType if endpointType == "private" { apiEndpoint = apiEndpointPrivate @@ -718,6 +718,7 @@ func dataSourceIBMCosBucketRead(d *schema.ResourceData, meta interface{}) error bucketCRN := fmt.Sprintf("%s:%s:%s", strings.Replace(serviceID, "::", "", -1), "bucket", bucketName) d.Set("crn", bucketCRN) d.Set("resource_instance_id", serviceID) + apiEndpoint, apiEndpointPrivate, directApiEndpoint = SelectCosApi(bucketLocationConvert(bucketType), bucketRegion, strings.Contains(apiEndpoint, "test")) d.Set("s3_endpoint_public", apiEndpoint) d.Set("s3_endpoint_private", apiEndpointPrivate) d.Set("s3_endpoint_direct", directApiEndpoint) diff --git a/ibm/service/cos/resource_ibm_cos_bucket.go b/ibm/service/cos/resource_ibm_cos_bucket.go index 32850cd514a..96373743832 100644 --- a/ibm/service/cos/resource_ibm_cos_bucket.go +++ b/ibm/service/cos/resource_ibm_cos_bucket.go @@ -759,7 +759,7 @@ func resourceIBMCOSBucketUpdate(d *schema.ResourceData, meta interface{}) error if apiType == "sl" { apiEndpoint = SelectSatlocCosApi(apiType, serviceID, bLocation) } else { - apiEndpoint, apiEndpointPrivate, directApiEndpoint = SelectCosApi(apiType, bLocation) + apiEndpoint, apiEndpointPrivate, directApiEndpoint = SelectCosApi(apiType, bLocation, false) visibility = endpointType if endpointType == "private" { apiEndpoint = apiEndpointPrivate @@ -1108,13 +1108,12 @@ func resourceIBMCOSBucketRead(d *schema.ResourceData, meta interface{}) error { bucketsatcrn := satloc_guid[0] serviceID = bucketsatcrn } - var apiEndpoint, apiEndpointPublic, apiEndpointPrivate, directApiEndpoint, visibility string visibility = endpointType if apiType == "sl" { apiEndpoint = SelectSatlocCosApi(apiType, serviceID, bLocation) } else { - apiEndpointPublic, apiEndpointPrivate, directApiEndpoint = SelectCosApi(apiType, bLocation) + apiEndpointPublic, apiEndpointPrivate, directApiEndpoint = SelectCosApi(apiType, bLocation, false) apiEndpoint = apiEndpointPublic if endpointType == "private" { apiEndpoint = apiEndpointPrivate @@ -1202,6 +1201,8 @@ func resourceIBMCOSBucketRead(d *schema.ResourceData, meta interface{}) error { d.Set("crn", bucketCRN) d.Set("resource_instance_id", serviceID) d.Set("bucket_name", bucketName) + + apiEndpointPublic, apiEndpointPrivate, directApiEndpoint = SelectCosApi(apiType, bLocation, strings.Contains(apiEndpoint, "test")) d.Set("s3_endpoint_public", apiEndpointPublic) d.Set("s3_endpoint_private", apiEndpointPrivate) d.Set("s3_endpoint_direct", directApiEndpoint) @@ -1401,13 +1402,12 @@ func resourceIBMCOSBucketCreate(d *schema.ResourceData, meta interface{}) error lConstraint := fmt.Sprintf("%s-%s", bLocation, storageClass) var endpointType = d.Get("endpoint_type").(string) - var apiEndpoint, privateApiEndpoint, directApiEndpoint, visibility string if apiType == "sl" { apiEndpoint = SelectSatlocCosApi(apiType, serviceID, bLocation) } else { - apiEndpoint, privateApiEndpoint, directApiEndpoint = SelectCosApi(apiType, bLocation) + apiEndpoint, privateApiEndpoint, directApiEndpoint = SelectCosApi(apiType, bLocation, false) visibility = endpointType if endpointType == "private" { apiEndpoint = privateApiEndpoint @@ -1527,13 +1527,12 @@ func resourceIBMCOSBucketDelete(d *schema.ResourceData, meta interface{}) error endpointType = d.Get("endpoint_type").(string) } var apiEndpoint, apiEndpointPrivate, directApiEndpoint, visibility string - if apiType == "sl" { apiEndpoint = SelectSatlocCosApi(apiType, serviceID, bLocation) } else { - apiEndpoint, apiEndpointPrivate, directApiEndpoint = SelectCosApi(apiType, bLocation) + apiEndpoint, apiEndpointPrivate, directApiEndpoint = SelectCosApi(apiType, bLocation, false) visibility = endpointType if endpointType == "private" { apiEndpoint = apiEndpointPrivate @@ -1662,13 +1661,12 @@ func resourceIBMCOSBucketExists(d *schema.ResourceData, meta interface{}) (bool, } var apiEndpoint, apiEndpointPrivate, directApiEndpoint string - if apiType == "sl" { apiEndpoint = SelectSatlocCosApi(apiType, serviceID, bLocation) } else { - apiEndpoint, apiEndpointPrivate, directApiEndpoint = SelectCosApi(apiType, bLocation) + apiEndpoint, apiEndpointPrivate, directApiEndpoint = SelectCosApi(apiType, bLocation, false) if endpointType == "private" { apiEndpoint = apiEndpointPrivate } @@ -1722,15 +1720,19 @@ func resourceIBMCOSBucketExists(d *schema.ResourceData, meta interface{}) (bool, return false, nil } -func SelectCosApi(apiType string, bLocation string) (string, string, string) { +func SelectCosApi(apiType string, bLocation string, test bool) (string, string, string) { + hostUrl := "cloud-object-storage.appdomain.cloud" + if test { + hostUrl = "cloud-object-storage.test.appdomain.cloud" + } if apiType == "crl" { - return fmt.Sprintf("s3.%s.cloud-object-storage.appdomain.cloud", bLocation), fmt.Sprintf("s3.private.%s.cloud-object-storage.appdomain.cloud", bLocation), fmt.Sprintf("s3.direct.%s.cloud-object-storage.appdomain.cloud", bLocation) + return fmt.Sprintf("s3.%s.%s", bLocation, hostUrl), fmt.Sprintf("s3.private.%s.%s", bLocation, hostUrl), fmt.Sprintf("s3.direct.%s.%s", bLocation, hostUrl) } if apiType == "rl" { - return fmt.Sprintf("s3.%s.cloud-object-storage.appdomain.cloud", bLocation), fmt.Sprintf("s3.private.%s.cloud-object-storage.appdomain.cloud", bLocation), fmt.Sprintf("s3.direct.%s.cloud-object-storage.appdomain.cloud", bLocation) + return fmt.Sprintf("s3.%s.%s", bLocation, hostUrl), fmt.Sprintf("s3.private.%s.%s", bLocation, hostUrl), fmt.Sprintf("s3.direct.%s.%s", bLocation, hostUrl) } if apiType == "ssl" { - return fmt.Sprintf("s3.%s.cloud-object-storage.appdomain.cloud", bLocation), fmt.Sprintf("s3.private.%s.cloud-object-storage.appdomain.cloud", bLocation), fmt.Sprintf("s3.direct.%s.cloud-object-storage.appdomain.cloud", bLocation) + return fmt.Sprintf("s3.%s.%s", bLocation, hostUrl), fmt.Sprintf("s3.private.%s.%s", bLocation, hostUrl), fmt.Sprintf("s3.direct.%s.%s", bLocation, hostUrl) } return "", "", "" } diff --git a/ibm/service/cos/resource_ibm_cos_bucket_object.go b/ibm/service/cos/resource_ibm_cos_bucket_object.go index e907534138f..4868e740645 100644 --- a/ibm/service/cos/resource_ibm_cos_bucket_object.go +++ b/ibm/service/cos/resource_ibm_cos_bucket_object.go @@ -476,17 +476,21 @@ func resourceIBMCOSBucketObjectDelete(ctx context.Context, d *schema.ResourceDat return nil } -func getCosEndpoint(bucketLocation string, endpointType string) string { +func getCosEndpoint(bucketLocation string, endpointType string, test bool) string { if bucketLocation != "" { + hostUrl := "cloud-object-storage.appdomain.cloud" + if test { + hostUrl = "cloud-object-storage.test.appdomain.cloud" + } switch endpointType { case "public": - return fmt.Sprintf("s3.%s.cloud-object-storage.appdomain.cloud", bucketLocation) + return fmt.Sprintf("s3.%s.%s", bucketLocation, hostUrl) case "private": - return fmt.Sprintf("s3.private.%s.cloud-object-storage.appdomain.cloud", bucketLocation) + return fmt.Sprintf("s3.private.%s.%s", bucketLocation, hostUrl) case "direct": - return fmt.Sprintf("s3.direct.%s.cloud-object-storage.appdomain.cloud", bucketLocation) + return fmt.Sprintf("s3.direct.%s.%s", bucketLocation, hostUrl) default: - return fmt.Sprintf("s3.%s.cloud-object-storage.appdomain.cloud", bucketLocation) + return fmt.Sprintf("s3.%s.%s", bucketLocation, hostUrl) } } return "" @@ -498,8 +502,7 @@ func getS3Client(bxSession *bxsession.Session, bucketLocation string, endpointTy if endpointType == "direct" { visibility = "private" } - - apiEndpoint := getCosEndpoint(bucketLocation, endpointType) + apiEndpoint := getCosEndpoint(bucketLocation, endpointType, false) apiEndpoint = conns.FileFallBack(bxSession.Config.EndpointsFile, visibility, "IBMCLOUD_COS_ENDPOINT", bucketLocation, apiEndpoint) apiEndpoint = conns.EnvFallBack([]string{"IBMCLOUD_COS_ENDPOINT"}, apiEndpoint) if apiEndpoint == "" { diff --git a/ibm/service/cos/resource_ibm_cos_bucket_test.go b/ibm/service/cos/resource_ibm_cos_bucket_test.go index 8cc51802de5..1a27c0ba497 100644 --- a/ibm/service/cos/resource_ibm_cos_bucket_test.go +++ b/ibm/service/cos/resource_ibm_cos_bucket_test.go @@ -2242,7 +2242,7 @@ func testAccCheckIBMCosBucketExists(resource string, bucket string, regiontype s rt = "crl" } - apiEndpoint, _, _ := cos.SelectCosApi(rt, region) + apiEndpoint, _, _ := cos.SelectCosApi(rt, region, false) rsContClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).BluemixSession() if err != nil { diff --git a/ibm/service/cos/resource_ibm_cos_replication_configuration.go b/ibm/service/cos/resource_ibm_cos_replication_configuration.go index f805ace41f6..fbd461d899d 100644 --- a/ibm/service/cos/resource_ibm_cos_replication_configuration.go +++ b/ibm/service/cos/resource_ibm_cos_replication_configuration.go @@ -334,19 +334,25 @@ func parseBucketReplId(id string, info string) string { return parseBucketId(bucketCRN, info) } -func getCosEndpointType(bucketLocation string, endpointType string) string { +func getCosEndpointType(bucketLocation string, endpointType string, test bool) string { + if bucketLocation != "" { + hostUrl := "cloud-object-storage.appdomain.cloud" + if test { + hostUrl = "cloud-object-storage.test.appdomain.cloud" + } switch endpointType { case "public": - return fmt.Sprintf("s3.%s.cloud-object-storage.appdomain.cloud", bucketLocation) + return fmt.Sprintf("s3.%s.%s", bucketLocation, hostUrl) case "private": - return fmt.Sprintf("s3.private.%s.cloud-object-storage.appdomain.cloud", bucketLocation) + return fmt.Sprintf("s3.private.%s.%s", bucketLocation, hostUrl) case "direct": - return fmt.Sprintf("s3.direct.%s.cloud-object-storage.appdomain.cloud", bucketLocation) + return fmt.Sprintf("s3.direct.%s.%s", bucketLocation, hostUrl) default: - return fmt.Sprintf("s3.%s.cloud-object-storage.appdomain.cloud", bucketLocation) + return fmt.Sprintf("s3.%s.%s", bucketLocation, hostUrl) } } + return "" } @@ -357,8 +363,7 @@ func getS3ClientSession(bxSession *bxsession.Session, bucketLocation string, end if endpointType == "direct" { visibility = "private" } - - apiEndpoint := getCosEndpointType(bucketLocation, endpointType) + apiEndpoint := getCosEndpointType(bucketLocation, endpointType, false) apiEndpoint = conns.FileFallBack(bxSession.Config.EndpointsFile, visibility, "IBMCLOUD_COS_ENDPOINT", bucketLocation, apiEndpoint) apiEndpoint = conns.EnvFallBack([]string{"IBMCLOUD_COS_ENDPOINT"}, apiEndpoint) if apiEndpoint == "" { From 1e82c333f062737a4ae756a41810910e140b3d0a Mon Sep 17 00:00:00 2001 From: Jason Peterson Date: Tue, 17 Sep 2024 07:11:14 -0400 Subject: [PATCH 2/4] Add support for Code Engine functions (#5596) * Add support for Code Engine functions * update .secrets.baseline * remove unnecessary check --- .secrets.baseline | 44 +- examples/ibm-code-engine/README.md | 726 ++++++++++++--- examples/ibm-code-engine/main.tf | 40 +- examples/ibm-code-engine/outputs.tf | 6 + examples/ibm-code-engine/variables.tf | 33 +- go.mod | 4 +- go.sum | 26 +- ibm/provider/provider.go | 3 + .../data_source_ibm_code_engine_function.go | 373 ++++++++ ...ta_source_ibm_code_engine_function_test.go | 147 +++ .../resource_ibm_code_engine_function.go | 839 ++++++++++++++++++ .../resource_ibm_code_engine_function_test.go | 251 ++++++ .../docs/d/code_engine_function.html.markdown | 114 +++ .../docs/r/code_engine_function.html.markdown | 117 +++ 14 files changed, 2567 insertions(+), 156 deletions(-) create mode 100644 ibm/service/codeengine/data_source_ibm_code_engine_function.go create mode 100644 ibm/service/codeengine/data_source_ibm_code_engine_function_test.go create mode 100644 ibm/service/codeengine/resource_ibm_code_engine_function.go create mode 100644 ibm/service/codeengine/resource_ibm_code_engine_function_test.go create mode 100644 website/docs/d/code_engine_function.html.markdown create mode 100644 website/docs/r/code_engine_function.html.markdown diff --git a/.secrets.baseline b/.secrets.baseline index 1332509cd91..5eb22bef301 100644 --- a/.secrets.baseline +++ b/.secrets.baseline @@ -3,7 +3,7 @@ "files": "go.mod|go.sum|.*.map|^.secrets.baseline$", "lines": null }, - "generated_at": "2024-09-10T13:43:43Z", + "generated_at": "2024-09-12T14:29:18Z", "plugins_used": [ { "name": "AWSKeyDetector" @@ -444,15 +444,15 @@ "hashed_secret": "dc61ac50e6f36d09340d8ca062da1f0d4215004f", "is_secret": false, "is_verified": false, - "line_number": 62, + "line_number": 170, "type": "Secret Keyword", "verified_result": null }, { - "hashed_secret": "f4adb76dda1dc36da0e225b8477887a30e7346c9", + "hashed_secret": "470851178a9e3a16c35bc88232c21d04c555e5ca", "is_secret": false, "is_verified": false, - "line_number": 131, + "line_number": 242, "type": "Secret Keyword", "verified_result": null } @@ -1789,6 +1789,16 @@ "verified_result": null } ], + "ibm/service/codeengine/data_source_ibm_code_engine_function.go": [ + { + "hashed_secret": "b732fb611fd46a38e8667f9972e0cde777fbe37f", + "is_secret": false, + "is_verified": false, + "line_number": 229, + "type": "Secret Keyword", + "verified_result": null + } + ], "ibm/service/codeengine/data_source_ibm_code_engine_job.go": [ { "hashed_secret": "b732fb611fd46a38e8667f9972e0cde777fbe37f", @@ -1871,6 +1881,32 @@ "verified_result": null } ], + "ibm/service/codeengine/resource_ibm_code_engine_function.go": [ + { + "hashed_secret": "b732fb611fd46a38e8667f9972e0cde777fbe37f", + "is_secret": false, + "is_verified": false, + "line_number": 503, + "type": "Secret Keyword", + "verified_result": null + }, + { + "hashed_secret": "a99bf28e18370eb20e9cc79a1e7f8c379075f69c", + "is_secret": false, + "is_verified": false, + "line_number": 658, + "type": "Secret Keyword", + "verified_result": null + }, + { + "hashed_secret": "b5366a2d2ac98dae978423083f8b09e5cddc705d", + "is_secret": false, + "is_verified": false, + "line_number": 726, + "type": "Secret Keyword", + "verified_result": null + } + ], "ibm/service/codeengine/resource_ibm_code_engine_job.go": [ { "hashed_secret": "b732fb611fd46a38e8667f9972e0cde777fbe37f", diff --git a/examples/ibm-code-engine/README.md b/examples/ibm-code-engine/README.md index 33ac34cd9b3..931a6b8fff0 100644 --- a/examples/ibm-code-engine/README.md +++ b/examples/ibm-code-engine/README.md @@ -1,17 +1,28 @@ -# Example for CodeEngineV2 - -This example illustrates how to use the CodeEngineV2 - -The following types of resources are supported: - -* code_engine_app -* code_engine_binding -* code_engine_build -* code_engine_config_map -* code_engine_domain_mapping -* code_engine_job -* code_engine_project -* code_engine_secret +# Examples for Code Engine + +These examples illustrate how to use the resources and data sources associated with Code Engine. + +The following resources are supported: +* ibm_code_engine_app +* ibm_code_engine_binding +* ibm_code_engine_build +* ibm_code_engine_config_map +* ibm_code_engine_domain_mapping +* ibm_code_engine_function +* ibm_code_engine_job +* ibm_code_engine_project +* ibm_code_engine_secret + +The following data sources are supported: +* ibm_code_engine_app +* ibm_code_engine_binding +* ibm_code_engine_build +* ibm_code_engine_config_map +* ibm_code_engine_domain_mapping +* ibm_code_engine_function +* ibm_code_engine_job +* ibm_code_engine_project +* ibm_code_engine_secret ## Usage @@ -25,19 +36,37 @@ $ terraform apply Run `terraform destroy` when you don't need these resources. +## Code Engine resources -## CodeEngineV2 resources - -code_engine_project resource: +### Resource: ibm_code_engine_project ```hcl -resource "code_engine_project" "code_engine_project_instance" { +resource "ibm_code_engine_project" "code_engine_project_instance" { name = var.code_engine_project_name resource_group_id = var.code_engine_project_resource_group_id } ``` -code_engine_app resource: +#### Inputs + +| Name | Description | Type | Required | +|------|-------------|------|---------| +| name | The name of the project. | `string` | true | +| resource_group_id | The ID of the resource group. | `string` | false | + +#### Outputs + +| Name | Description | +|------|-------------| +| account_id | An alphanumeric value identifying the account ID. | +| created_at | The timestamp when the project was created. | +| crn | The CRN of the project. | +| href | When you provision a new resource, a URL is created identifying the location of the instance. | +| region | The region for your project deployment. Possible values: `au-syd`, `br-sao`, `ca-tor`, `eu-de`, `eu-es`, `eu-gb`, `jp-osa`, `jp-tok`, `us-east`, `us-south`. | +| resource_type | The type of the project. | +| status | The current state of the project. For example, when the project is created and is ready for use, the status of the project is `active`. | + +### Resource: ibm_code_engine_app ```hcl resource "ibm_code_engine_app" "code_engine_app_instance" { @@ -52,7 +81,86 @@ resource "ibm_code_engine_app" "code_engine_app_instance" { } ``` -code_engine_build resource: +#### Inputs + +| Name | Description | Type | Required | +|------|-------------|------|---------| +| project_id | The ID of the project. | `string` | true | +| image_port | Optional port the app listens on. While the app will always be exposed via port `443` for end users, this port is used to connect to the port that is exposed by the container image. | `number` | false | +| image_reference | The name of the image that is used for this app. The format is `REGISTRY/NAMESPACE/REPOSITORY:TAG` where `REGISTRY` and `TAG` are optional. If `REGISTRY` is not specified, the default is `docker.io`. If `TAG` is not specified, the default is `latest`. If the image reference points to a registry that requires authentication, make sure to also specify the property `image_secret`. | `string` | true | +| image_secret | Optional name of the image registry access secret. The image registry access secret is used to authenticate with a private registry when you download the container image. If the image reference points to a registry that requires authentication, the app will be created but cannot reach the ready status, until this property is provided, too. | `string` | false | +| managed_domain_mappings | Optional value controlling which of the system managed domain mappings will be setup for the application. Valid values are 'local_public', 'local_private' and 'local'. Visibility can only be 'local_private' if the project supports application private visibility. | `string` | false | +| name | The name of the app. | `string` | true | +| probe_liveness | Response model for probes. | `` | false | +| probe_readiness | Response model for probes. | `` | false | +| run_arguments | Optional arguments for the app that are passed to start the container. If not specified an empty string array will be applied and the arguments specified by the container image, will be used to start the container. | `list(string)` | false | +| run_as_user | Optional user ID (UID) to run the app. | `number` | false | +| run_commands | Optional commands for the app that are passed to start the container. If not specified an empty string array will be applied and the command specified by the container image, will be used to start the container. | `list(string)` | false | +| run_env_variables | References to config maps, secrets or literal values, which are exposed as environment variables in the application. | `list()` | false | +| run_service_account | Optional name of the service account. For built-in service accounts, you can use the shortened names `manager` , `none`, `reader`, and `writer`. | `string` | false | +| run_volume_mounts | Mounts of config maps or secrets. | `list()` | false | +| scale_concurrency | Optional maximum number of requests that can be processed concurrently per instance. | `number` | false | +| scale_concurrency_target | Optional threshold of concurrent requests per instance at which one or more additional instances are created. Use this value to scale up instances based on concurrent number of requests. This option defaults to the value of the `scale_concurrency` option, if not specified. | `number` | false | +| scale_cpu_limit | Optional number of CPU set for the instance of the app. For valid values see [Supported memory and CPU combinations](https://cloud.ibm.com/docs/codeengine?topic=codeengine-mem-cpu-combo). | `string` | false | +| scale_down_delay | Optional amount of time in seconds that delays the scale-down behavior for an app instance. | `number` | false | +| scale_ephemeral_storage_limit | Optional amount of ephemeral storage to set for the instance of the app. The amount specified as ephemeral storage, must not exceed the amount of `scale_memory_limit`. The units for specifying ephemeral storage are Megabyte (M) or Gigabyte (G), whereas G and M are the shorthand expressions for GB and MB. For more information see [Units of measurement](https://cloud.ibm.com/docs/codeengine?topic=codeengine-mem-cpu-combo#unit-measurements). | `string` | false | +| scale_initial_instances | Optional initial number of instances that are created upon app creation or app update. | `number` | false | +| scale_max_instances | Optional maximum number of instances for this app. If you set this value to `0`, this property does not set a upper scaling limit. However, the app scaling is still limited by the project quota for instances. See [Limits and quotas for Code Engine](https://cloud.ibm.com/docs/codeengine?topic=codeengine-limits). | `number` | false | +| scale_memory_limit | Optional amount of memory set for the instance of the app. For valid values see [Supported memory and CPU combinations](https://cloud.ibm.com/docs/codeengine?topic=codeengine-mem-cpu-combo). The units for specifying memory are Megabyte (M) or Gigabyte (G), whereas G and M are the shorthand expressions for GB and MB. For more information see [Units of measurement](https://cloud.ibm.com/docs/codeengine?topic=codeengine-mem-cpu-combo#unit-measurements). | `string` | false | +| scale_min_instances | Optional minimum number of instances for this app. If you set this value to `0`, the app will scale down to zero, if not hit by any request for some time. | `number` | false | +| scale_request_timeout | Optional amount of time in seconds that is allowed for a running app to respond to a request. | `number` | false | + +#### Outputs + +| Name | Description | +|------|-------------| +| build | Reference to a build that is associated with the application. | +| build_run | Reference to a build run that is associated with the application. | +| created_at | The timestamp when the resource was created. | +| endpoint | Optional URL to invoke the app. Depending on visibility, this is accessible publicly or in the private network only. Empty in case 'managed_domain_mappings' is set to 'local'. | +| endpoint_internal | The URL to the app that is only visible within the project. | +| entity_tag | The version of the app instance, which is used to achieve optimistic locking. | +| href | When you provision a new app, a URL is created identifying the location of the instance. | +| app_id | The identifier of the resource. | +| region | The region of the project the resource is located in. Possible values: 'au-syd', 'br-sao', 'ca-tor', 'eu-de', 'eu-gb', 'jp-osa', 'jp-tok', 'us-east', 'us-south'. | +| resource_type | The type of the app. | +| status | The current status of the app. | +| status_details | The detailed status of the application. | + +### Resource: ibm_code_engine_binding + +```hcl +resource "ibm_code_engine_binding" "code_engine_binding_instance" { + project_id = var.code_engine_project_id + prefix = var.code_engine_binding_prefix + secret_name = "my-service-access-secret" + component { + name = var.code_engine_binding_component_name + resource_type = var.code_engine_binding_component_resource_type + } +} + +``` + +#### Inputs + +| Name | Description | Type | Required | +|------|-------------|------|---------| +| project_id | The ID of the project. | `string` | true | +| component | A reference to another component. | `` | true | +| prefix | The value that is set as a prefix in the component that is bound. | `string` | true | +| secret_name | The service access secret that is bound to a component. | `string` | true | + +#### Outputs + +| Name | Description | +|------|-------------| +| href | When you provision a new binding, a URL is created identifying the location of the instance. | +| resource_type | The type of the binding. | +| status | The current status of the binding. | +| code_engine_binding_id | The ID of the binding. | + +### Resource: ibm_code_engine_build ```hcl resource "ibm_code_engine_build" "code_engine_build_instance" { @@ -65,34 +173,201 @@ resource "ibm_code_engine_build" "code_engine_build_instance" { } ``` -code_engine_config_map resource: +#### Inputs + +| Name | Description | Type | Required | +|------|-------------|------|---------| +| project_id | The ID of the project. | `string` | true | +| name | The name of the build. | `string` | true | +| output_image | The name of the image. | `string` | true | +| output_secret | The secret that is required to access the image registry. Make sure that the secret is granted with push permissions towards the specified container registry namespace. | `string` | true | +| source_context_dir | Optional directory in the repository that contains the buildpacks file or the Dockerfile. | `string` | false | +| source_revision | Commit, tag, or branch in the source repository to pull. This field is optional if the `source_type` is `git` and uses the HEAD of default branch if not specified. If the `source_type` value is `local`, this field must be omitted. | `string` | false | +| source_secret | Name of the secret that is used access the repository source. This field is optional if the `source_type` is `git`. Additionally, if the `source_url` points to a repository that requires authentication, the build will be created but cannot access any source code, until this property is provided, too. If the `source_type` value is `local`, this field must be omitted. | `string` | false | +| source_type | Specifies the type of source to determine if your build source is in a repository or based on local source code.* local - For builds from local source code.* git - For builds from git version controlled source code. | `string` | false | +| source_url | The URL of the code repository. This field is required if the `source_type` is `git`. If the `source_type` value is `local`, this field must be omitted. If the repository is publicly available you can provide a 'https' URL like `https://github.com/IBM/CodeEngine`. If the repository requires authentication, you need to provide a 'ssh' URL like `git@github.com:IBM/CodeEngine.git` along with a `source_secret` that points to a secret of format `ssh_auth`. | `string` | false | +| strategy_size | Optional size for the build, which determines the amount of resources used. Build sizes are `small`, `medium`, `large`, `xlarge`, `xxlarge`. | `string` | false | +| strategy_spec_file | Optional path to the specification file that is used for build strategies for building an image. | `string` | false | +| strategy_type | The strategy to use for building the image. | `string` | true | +| timeout | The maximum amount of time, in seconds, that can pass before the build must succeed or fail. | `number` | false | + +#### Outputs + +| Name | Description | +|------|-------------| +| created_at | The timestamp when the resource was created. | +| entity_tag | The version of the build instance, which is used to achieve optimistic locking. | +| href | When you provision a new build, a URL is created identifying the location of the instance. | +| build_id | The identifier of the resource. | +| region | The region of the project the resource is located in. Possible values: 'au-syd', 'br-sao', 'ca-tor', 'eu-de', 'eu-gb', 'jp-osa', 'jp-tok', 'us-east', 'us-south'. | +| resource_type | The type of the build. | +| status | The current status of the build. | +| status_details | The detailed status of the build. | + +### Resource: ibm_code_engine_config_map ```hcl -resource "code_engine_config_map" "code_engine_config_map_instance" { +resource "ibm_code_engine_config_map" "code_engine_config_map_instance" { project_id = var.code_engine_project_id name = var.code_engine_config_map_name data = var.code_engine_config_map_data } ``` -code_engine_job resource: +#### Inputs + +| Name | Description | Type | Required | +|------|-------------|------|---------| +| project_id | The ID of the project. | `string` | true | +| data | The key-value pair for the config map. Values must be specified in `KEY=VALUE` format. | `map(string)` | false | +| name | The name of the config map. | `string` | true | + +#### Outputs + +| Name | Description | +|------|-------------| +| created_at | The timestamp when the resource was created. | +| entity_tag | The version of the config map instance, which is used to achieve optimistic locking. | +| href | When you provision a new config map, a URL is created identifying the location of the instance. | +| config_map_id | The identifier of the resource. | +| region | The region of the project the resource is located in. Possible values: 'au-syd', 'br-sao', 'ca-tor', 'eu-de', 'eu-gb', 'jp-osa', 'jp-tok', 'us-east', 'us-south'. | +| resource_type | The type of the config map. | + +### Resource: ibm_code_engine_domain_mapping + +```hcl +resource "ibm_code_engine_domain_mapping" "code_engine_domain_mapping_instance" { + project_id = var.code_engine_domain_mapping_project_id + name = var.code_engine_domain_mapping_name + tls_secret = var.code_engine_domain_mapping_tls_secret + component { + name = var.code_engine_domain_mapping_component_name + resource_type = var.code_engine_domain_mapping_component_resource_type + } +} +``` + +#### Inputs + +| Name | Description | Type | Required | +|------|-------------|------|---------| +| project_id | The ID of the project. | `string` | true | +| component | A reference to another component. | `` | true | +| name | The name of the domain mapping. | `string` | true | +| tls_secret | The name of the TLS secret that includes the certificate and private key of this domain mapping. | `string` | true | + +#### Outputs + +| Name | Description | +|------|-------------| +| cname_target | The value of the CNAME record that must be configured in the DNS settings of the domain, to route traffic properly to the target Code Engine region. | +| created_at | The timestamp when the resource was created. | +| entity_tag | The version of the domain mapping instance, which is used to achieve optimistic locking. | +| href | When you provision a new domain mapping, a URL is created identifying the location of the instance. | +| domain_mapping_id | The identifier of the resource. | +| region | The region of the project the resource is located in. Possible values: 'au-syd', 'br-sao', 'ca-tor', 'eu-de', 'eu-gb', 'jp-osa', 'jp-tok', 'us-east', 'us-south'. | +| resource_type | The type of the Code Engine resource. | +| status | The current status of the domain mapping. | +| status_details | The detailed status of the domain mapping. | +| user_managed | Specifies whether the domain mapping is managed by the user or by Code Engine. | +| visibility | Specifies whether the domain mapping is reachable through the public internet, or private IBM network, or only through other components within the same Code Engine project. | + +### Resource: ibm_code_engine_function + +```hcl +resource "ibm_code_engine_function" "code_engine_function_instance" { + project_id = var.code_engine_function_project_id + name = var.code_engine_function_name + runtime = var.code_engine_function_runtime + code_reference = var.code_engine_function_code_reference +} +``` + +#### Inputs + +| Name | Description | Type | Required | +|------|-------------|------|---------| +| project_id | The ID of the project. | `string` | true | +| code_binary | Specifies whether the code is binary or not. Defaults to false when `code_reference` is set to a data URL. When `code_reference` is set to a code bundle URL, this field is always true. | `bool` | false | +| code_main | Specifies the name of the function that should be invoked. | `string` | false | +| code_reference | Specifies either a reference to a code bundle or the source code itself. To specify the source code, use the data URL scheme and include the source code as base64 encoded. The data URL scheme is defined in [RFC 2397](https://tools.ietf.org/html/rfc2397). | `string` | true | +| code_secret | The name of the secret that is used to access the specified `code_reference`. The secret is used to authenticate with a non-public endpoint that is specified as`code_reference`. | `string` | false | +| managed_domain_mappings | Optional value controlling which of the system managed domain mappings will be setup for the function. Valid values are 'local_public', 'local_private' and 'local'. Visibility can only be 'local_private' if the project supports function private visibility. | `string` | false | +| name | The name of the function. | `string` | true | +| run_env_variables | References to config maps, secrets or literal values, which are defined by the function owner and are exposed as environment variables in the function. | `list()` | false | +| runtime | The managed runtime used to execute the injected code. | `string` | true | +| scale_concurrency | Number of parallel requests handled by a single instance, supported only by Node.js, default is `1`. | `number` | false | +| scale_cpu_limit | Optional amount of CPU set for the instance of the function. For valid values see [Supported memory and CPU combinations](https://cloud.ibm.com/docs/codeengine?topic=codeengine-mem-cpu-combo). | `string` | false | +| scale_down_delay | Optional amount of time in seconds that delays the scale down behavior for a function. | `number` | false | +| scale_max_execution_time | Timeout in secs after which the function is terminated. | `number` | false | +| scale_memory_limit | Optional amount of memory set for the instance of the function. For valid values see [Supported memory and CPU combinations](https://cloud.ibm.com/docs/codeengine?topic=codeengine-mem-cpu-combo). The units for specifying memory are Megabyte (M) or Gigabyte (G), whereas G and M are the shorthand expressions for GB and MB. For more information see [Units of measurement](https://cloud.ibm.com/docs/codeengine?topic=codeengine-mem-cpu-combo#unit-measurements). | `string` | false | + +#### Outputs + +| Name | Description | +|------|-------------| +| created_at | The timestamp when the resource was created. | +| endpoint | URL to invoke the function. | +| endpoint_internal | URL to function that is only visible within the project. | +| entity_tag | The version of the function instance, which is used to achieve optimistic locking. | +| href | When you provision a new function, a relative URL path is created identifying the location of the instance. | +| function_id | The identifier of the resource. | +| region | The region of the project the resource is located in. Possible values: 'au-syd', 'br-sao', 'ca-tor', 'eu-de', 'eu-gb', 'jp-osa', 'jp-tok', 'us-east', 'us-south'. | +| resource_type | The type of the function. | +| status | The current status of the function. | +| status_details | The detailed status of the function. | + +### Resource: ibm_code_engine_job ```hcl resource "ibm_code_engine_job" "code_engine_job_instance" { project_id = var.code_engine_project_id image_reference = var.code_engine_job_image_reference name = var.code_engine_job_name - run_env_variables { type = "literal" name = "name" value = "value" } } - ``` -code_engine_secret resource: +#### Inputs + +| Name | Description | Type | Required | +|------|-------------|------|---------| +| project_id | The ID of the project. | `string` | true | +| image_reference | The name of the image that is used for this job. The format is `REGISTRY/NAMESPACE/REPOSITORY:TAG` where `REGISTRY` and `TAG` are optional. If `REGISTRY` is not specified, the default is `docker.io`. If `TAG` is not specified, the default is `latest`. If the image reference points to a registry that requires authentication, make sure to also specify the property `image_secret`. | `string` | true | +| image_secret | The name of the image registry access secret. The image registry access secret is used to authenticate with a private registry when you download the container image. If the image reference points to a registry that requires authentication, the job / job runs will be created but submitted job runs will fail, until this property is provided, too. This property must not be set on a job run, which references a job template. | `string` | false | +| name | The name of the job. | `string` | true | +| run_arguments | Set arguments for the job that are passed to start job run containers. If not specified an empty string array will be applied and the arguments specified by the container image, will be used to start the container. | `list(string)` | false | +| run_as_user | The user ID (UID) to run the job. | `number` | false | +| run_commands | Set commands for the job that are passed to start job run containers. If not specified an empty string array will be applied and the command specified by the container image, will be used to start the container. | `list(string)` | false | +| run_env_variables | References to config maps, secrets or literal values, which are exposed as environment variables in the job run. | `list()` | false | +| run_mode | The mode for runs of the job. Valid values are `task` and `daemon`. In `task` mode, the `max_execution_time` and `retry_limit` properties apply. In `daemon` mode, since there is no timeout and failed instances are restarted indefinitely, the `max_execution_time` and `retry_limit` properties are not allowed. | `string` | false | +| run_service_account | The name of the service account. For built-in service accounts, you can use the shortened names `manager`, `none`, `reader`, and `writer`. This property must not be set on a job run, which references a job template. | `string` | false | +| run_volume_mounts | Optional mounts of config maps or secrets. | `list()` | false | +| scale_array_spec | Define a custom set of array indices as a comma-separated list containing single values and hyphen-separated ranges, such as 5,12-14,23,27. Each instance gets its array index value from the environment variable JOB_INDEX. The number of unique array indices that you specify with this parameter determines the number of job instances to run. | `string` | false | +| scale_cpu_limit | Optional amount of CPU set for the instance of the job. For valid values see [Supported memory and CPU combinations](https://cloud.ibm.com/docs/codeengine?topic=codeengine-mem-cpu-combo). | `string` | false | +| scale_ephemeral_storage_limit | Optional amount of ephemeral storage to set for the instance of the job. The amount specified as ephemeral storage, must not exceed the amount of `scale_memory_limit`. The units for specifying ephemeral storage are Megabyte (M) or Gigabyte (G), whereas G and M are the shorthand expressions for GB and MB. For more information see [Units of measurement](https://cloud.ibm.com/docs/codeengine?topic=codeengine-mem-cpu-combo#unit-measurements). | `string` | false | +| scale_max_execution_time | The maximum execution time in seconds for runs of the job. This property can only be specified if `run_mode` is `task`. | `number` | false | +| scale_memory_limit | Optional amount of memory set for the instance of the job. For valid values see [Supported memory and CPU combinations](https://cloud.ibm.com/docs/codeengine?topic=codeengine-mem-cpu-combo). The units for specifying memory are Megabyte (M) or Gigabyte (G), whereas G and M are the shorthand expressions for GB and MB. For more information see [Units of measurement](https://cloud.ibm.com/docs/codeengine?topic=codeengine-mem-cpu-combo#unit-measurements). | `string` | false | +| scale_retry_limit | The number of times to rerun an instance of the job before the job is marked as failed. This property can only be specified if `run_mode` is `task`. | `number` | false | + +#### Outputs + +| Name | Description | +|------|-------------| +| build | Reference to a build that is associated with the job. | +| build_run | Reference to a build run that is associated with the job. | +| created_at | The timestamp when the resource was created. | +| entity_tag | The version of the job instance, which is used to achieve optimistic locking. | +| href | When you provision a new job, a URL is created identifying the location of the instance. | +| job_id | The identifier of the resource. | +| region | The region of the project the resource is located in. Possible values: 'au-syd', 'br-sao', 'ca-tor', 'eu-de', 'eu-gb', 'jp-osa', 'jp-tok', 'us-east', 'us-south'. | +| resource_type | The type of the job. | + +### Resource: ibm_code_engine_secret ```hcl resource "ibm_code_engine_secret" "code_engine_secret_instance" { @@ -103,172 +378,349 @@ resource "ibm_code_engine_secret" "code_engine_secret_instance" { } ``` -code_engine_binding resource: +#### Inputs -```hcl -resource "ibm_code_engine_binding" "code_engine_secret_instance" { - project_id = var.code_engine_project_id - component { - name = var.code_engine_binding_component_name - resource_type = var.code_engine_binding_component_resource_type - } +| Name | Description | Type | Required | +|------|-------------|------|---------| +| project_id | The ID of the project. | `string` | true | +| data | Data container that allows to specify config parameters and their values as a key-value map. Each key field must consist of alphanumeric characters, `-`, `_` or `.` and must not exceed a max length of 253 characters. Each value field can consists of any character and must not exceed a max length of 1048576 characters. | `map(string)` | false | +| format | Specify the format of the secret. | `string` | true | +| name | The name of the secret. | `string` | true | +| service_access | Properties for Service Access Secrets. | `` | false | +| service_operator | Properties for the IBM Cloud Operator Secret. | `` | false | - prefix = var.code_engine_binding_prefix - secret_name = var.code_engine_binding_secret_name -} -``` +#### Outputs -code_engine_domain_mapping resource: +| Name | Description | +|------|-------------| +| created_at | The timestamp when the resource was created. | +| entity_tag | The version of the secret instance, which is used to achieve optimistic locking. | +| href | When you provision a new secret, a URL is created identifying the location of the instance. | +| secret_id | The identifier of the resource. | +| region | The region of the project the resource is located in. Possible values: 'au-syd', 'br-sao', 'ca-tor', 'eu-de', 'eu-gb', 'jp-osa', 'jp-tok', 'us-east', 'us-south'. | +| resource_type | The type of the secret. | + +## Code Engine data sources + +### Data source: ibm_code_engine_project ```hcl -resource "ibm_code_engine_domain_mapping" "code_engine_domain_mapping_instance" { - project_id = var.code_engine_project_id - name = var.code_engine_domain_mapping_name - component { - name = var.code_engine_domain_mapping_component_name - resource_type = var.code_engine_domain_mapping_component_resource_type - } - tls_secret = var.code_engine_binding_secret_name +data "ibm_code_engine_project" "code_engine_project_instance" { + project_id = var.data_code_engine_project_code_engine_project_id } ``` -## CodeEngineV2 Data sources +#### Inputs + +| Name | Description | Type | Required | +|------|-------------|------|---------| +| project_id | The ID of the project. | `string` | true | -code_engine_project data source: +#### Outputs + +| Name | Description | +|------|-------------| +| account_id | An alphanumeric value identifying the account ID. | +| created_at | The timestamp when the project was created. | +| crn | The CRN of the project. | +| href | When you provision a new resource, a URL is created identifying the location of the instance. | +| name | The name of the project. | +| region | The region for your project deployment. Possible values: 'au-syd', 'br-sao', 'ca-tor', 'eu-de', 'eu-gb', 'jp-osa', 'jp-tok', 'us-east', 'us-south'. | +| resource_group_id | The ID of the resource group. | +| resource_type | The type of the project. | +| status | The current state of the project. For example, when the project is created and is ready for use, the status of the project is active. | + +### Data source: ibm_code_engine_app ```hcl -data "code_engine_project" "code_engine_project_instance" { - project_id = var.code_engine_project_id +data "ibm_code_engine_app" "code_engine_app_instance" { + project_id = var.data_code_engine_app_project_id + name = var.data_code_engine_app_name } ``` -code_engine_app data source: +#### Inputs + +| Name | Description | Type | Required | +|------|-------------|------|---------| +| project_id | The ID of the project. | `string` | true | +| name | The name of your application. | `string` | true | + +#### Outputs + +| Name | Description | +|------|-------------| +| build | Reference to a build that is associated with the application. | +| build_run | Reference to a build run that is associated with the application. | +| created_at | The timestamp when the resource was created. | +| endpoint | Optional URL to invoke the app. Depending on visibility, this is accessible publicly or in the private network only. Empty in case 'managed_domain_mappings' is set to 'local'. | +| endpoint_internal | The URL to the app that is only visible within the project. | +| entity_tag | The version of the app instance, which is used to achieve optimistic locking. | +| href | When you provision a new app, a URL is created identifying the location of the instance. | +| image_port | Optional port the app listens on. While the app will always be exposed via port `443` for end users, this port is used to connect to the port that is exposed by the container image. | +| image_reference | The name of the image that is used for this app. The format is `REGISTRY/NAMESPACE/REPOSITORY:TAG` where `REGISTRY` and `TAG` are optional. If `REGISTRY` is not specified, the default is `docker.io`. If `TAG` is not specified, the default is `latest`. If the image reference points to a registry that requires authentication, make sure to also specify the property `image_secret`. | +| image_secret | Optional name of the image registry access secret. The image registry access secret is used to authenticate with a private registry when you download the container image. If the image reference points to a registry that requires authentication, the app will be created but cannot reach the ready status, until this property is provided, too. | +| managed_domain_mappings | Optional value controlling which of the system managed domain mappings will be setup for the application. Valid values are 'local_public', 'local_private' and 'local'. Visibility can only be 'local_private' if the project supports application private visibility. | +| probe_liveness | Response model for probes. | +| probe_readiness | Response model for probes. | +| region | The region of the project the resource is located in. Possible values: 'au-syd', 'br-sao', 'ca-tor', 'eu-de', 'eu-gb', 'jp-osa', 'jp-tok', 'us-east', 'us-south'. | +| resource_type | The type of the app. | +| run_arguments | Optional arguments for the app that are passed to start the container. If not specified an empty string array will be applied and the arguments specified by the container image, will be used to start the container. | +| run_as_user | Optional user ID (UID) to run the app. | +| run_commands | Optional commands for the app that are passed to start the container. If not specified an empty string array will be applied and the command specified by the container image, will be used to start the container. | +| run_env_variables | References to config maps, secrets or literal values, which are exposed as environment variables in the application. | +| run_service_account | Optional name of the service account. For built-in service accounts, you can use the shortened names `manager` , `none`, `reader`, and `writer`. | +| run_volume_mounts | Mounts of config maps or secrets. | +| scale_concurrency | Optional maximum number of requests that can be processed concurrently per instance. | +| scale_concurrency_target | Optional threshold of concurrent requests per instance at which one or more additional instances are created. Use this value to scale up instances based on concurrent number of requests. This option defaults to the value of the `scale_concurrency` option, if not specified. | +| scale_cpu_limit | Optional number of CPU set for the instance of the app. For valid values see [Supported memory and CPU combinations](https://cloud.ibm.com/docs/codeengine?topic=codeengine-mem-cpu-combo). | +| scale_down_delay | Optional amount of time in seconds that delays the scale-down behavior for an app instance. | +| scale_ephemeral_storage_limit | Optional amount of ephemeral storage to set for the instance of the app. The amount specified as ephemeral storage, must not exceed the amount of `scale_memory_limit`. The units for specifying ephemeral storage are Megabyte (M) or Gigabyte (G), whereas G and M are the shorthand expressions for GB and MB. For more information see [Units of measurement](https://cloud.ibm.com/docs/codeengine?topic=codeengine-mem-cpu-combo#unit-measurements). | +| scale_initial_instances | Optional initial number of instances that are created upon app creation or app update. | +| scale_max_instances | Optional maximum number of instances for this app. If you set this value to `0`, this property does not set a upper scaling limit. However, the app scaling is still limited by the project quota for instances. See [Limits and quotas for Code Engine](https://cloud.ibm.com/docs/codeengine?topic=codeengine-limits). | +| scale_memory_limit | Optional amount of memory set for the instance of the app. For valid values see [Supported memory and CPU combinations](https://cloud.ibm.com/docs/codeengine?topic=codeengine-mem-cpu-combo). The units for specifying memory are Megabyte (M) or Gigabyte (G), whereas G and M are the shorthand expressions for GB and MB. For more information see [Units of measurement](https://cloud.ibm.com/docs/codeengine?topic=codeengine-mem-cpu-combo#unit-measurements). | +| scale_min_instances | Optional minimum number of instances for this app. If you set this value to `0`, the app will scale down to zero, if not hit by any request for some time. | +| scale_request_timeout | Optional amount of time in seconds that is allowed for a running app to respond to a request. | +| status | The current status of the app. | +| status_details | The detailed status of the application. | + +### Data source: ibm_code_engine_binding ```hcl -data "ibm_code_engine_app" "code_engine_app_instance" { - project_id = var.code_engine_project_id - name = var.code_engine_app_name +data "ibm_code_engine_binding" "code_engine_binding_instance" { + project_id = var.data_code_engine_binding_project_id + code_engine_binding_id = var.data_code_engine_binding_code_engine_binding_id } ``` -code_engine_build data source: +#### Inputs + +| Name | Description | Type | Required | +|------|-------------|------|---------| +| project_id | The ID of the project. | `string` | true | +| code_engine_binding_id | The id of your binding. | `string` | true | + +#### Outputs + +| Name | Description | +|------|-------------| +| component | A reference to another component. | +| href | When you provision a new binding, a URL is created identifying the location of the instance. | +| prefix | The value that is set as a prefix in the component that is bound. | +| resource_type | The type of the binding. | +| secret_name | The service access secret that is bound to a component. | +| status | The current status of the binding. | + +### Data source: ibm_code_engine_build ```hcl data "ibm_code_engine_build" "code_engine_build_instance" { - project_id = var.code_engine_project_id - name = var.code_engine_build_name + project_id = var.data_code_engine_build_project_id + name = var.data_code_engine_build_name } ``` -code_engine_config_map data source: +#### Inputs + +| Name | Description | Type | Required | +|------|-------------|------|---------| +| project_id | The ID of the project. | `string` | true | +| name | The name of your build. | `string` | true | + +#### Outputs + +| Name | Description | +|------|-------------| +| created_at | The timestamp when the resource was created. | +| entity_tag | The version of the build instance, which is used to achieve optimistic locking. | +| href | When you provision a new build, a URL is created identifying the location of the instance. | +| output_image | The name of the image. | +| output_secret | The secret that is required to access the image registry. Make sure that the secret is granted with push permissions towards the specified container registry namespace. | +| region | The region of the project the resource is located in. Possible values: 'au-syd', 'br-sao', 'ca-tor', 'eu-de', 'eu-gb', 'jp-osa', 'jp-tok', 'us-east', 'us-south'. | +| resource_type | The type of the build. | +| source_context_dir | Optional directory in the repository that contains the buildpacks file or the Dockerfile. | +| source_revision | Commit, tag, or branch in the source repository to pull. This field is optional if the `source_type` is `git` and uses the HEAD of default branch if not specified. If the `source_type` value is `local`, this field must be omitted. | +| source_secret | Name of the secret that is used access the repository source. This field is optional if the `source_type` is `git`. Additionally, if the `source_url` points to a repository that requires authentication, the build will be created but cannot access any source code, until this property is provided, too. If the `source_type` value is `local`, this field must be omitted. | +| source_type | Specifies the type of source to determine if your build source is in a repository or based on local source code.* local - For builds from local source code.* git - For builds from git version controlled source code. | +| source_url | The URL of the code repository. This field is required if the `source_type` is `git`. If the `source_type` value is `local`, this field must be omitted. If the repository is publicly available you can provide a 'https' URL like `https://github.com/IBM/CodeEngine`. If the repository requires authentication, you need to provide a 'ssh' URL like `git@github.com:IBM/CodeEngine.git` along with a `source_secret` that points to a secret of format `ssh_auth`. | +| status | The current status of the build. | +| status_details | The detailed status of the build. | +| strategy_size | Optional size for the build, which determines the amount of resources used. Build sizes are `small`, `medium`, `large`, `xlarge`, `xxlarge`. | +| strategy_spec_file | Optional path to the specification file that is used for build strategies for building an image. | +| strategy_type | The strategy to use for building the image. | +| timeout | The maximum amount of time, in seconds, that can pass before the build must succeed or fail. | + +### Data source: ibm_code_engine_config_map ```hcl -data "code_engine_config_map" "code_engine_config_map_instance" { - project_id = var.code_engine_project_id - name = var.code_engine_config_map_name +data "ibm_code_engine_config_map" "code_engine_config_map_instance" { + project_id = var.data_code_engine_config_map_project_id + name = var.data_code_engine_config_map_name } ``` -code_engine_job data source: +#### Inputs + +| Name | Description | Type | Required | +|------|-------------|------|---------| +| project_id | The ID of the project. | `string` | true | +| name | The name of your configmap. | `string` | true | + +#### Outputs + +| Name | Description | +|------|-------------| +| created_at | The timestamp when the resource was created. | +| data | The key-value pair for the config map. Values must be specified in `KEY=VALUE` format. | +| entity_tag | The version of the config map instance, which is used to achieve optimistic locking. | +| href | When you provision a new config map, a URL is created identifying the location of the instance. | +| region | The region of the project the resource is located in. Possible values: 'au-syd', 'br-sao', 'ca-tor', 'eu-de', 'eu-gb', 'jp-osa', 'jp-tok', 'us-east', 'us-south'. | +| resource_type | The type of the config map. | + +### Data source: ibm_code_engine_domain_mapping ```hcl -data "ibm_code_engine_job" "code_engine_job_instance" { - project_id = var.code_engine_project_id - name = var.code_engine_job_name +data "ibm_code_engine_domain_mapping" "code_engine_domain_mapping_instance" { + project_id = var.data_code_engine_domain_mapping_project_id + name = var.data_code_engine_domain_mapping_name } - ``` -code_engine_secret data source: +#### Inputs + +| Name | Description | Type | Required | +|------|-------------|------|---------| +| project_id | The ID of the project. | `string` | true | +| name | The name of your domain mapping. | `string` | true | + +#### Outputs + +| Name | Description | +|------|-------------| +| cname_target | The value of the CNAME record that must be configured in the DNS settings of the domain, to route traffic properly to the target Code Engine region. | +| component | A reference to another component. | +| created_at | The timestamp when the resource was created. | +| entity_tag | The version of the domain mapping instance, which is used to achieve optimistic locking. | +| href | When you provision a new domain mapping, a URL is created identifying the location of the instance. | +| region | The region of the project the resource is located in. Possible values: 'au-syd', 'br-sao', 'ca-tor', 'eu-de', 'eu-gb', 'jp-osa', 'jp-tok', 'us-east', 'us-south'. | +| resource_type | The type of the Code Engine resource. | +| status | The current status of the domain mapping. | +| status_details | The detailed status of the domain mapping. | +| tls_secret | The name of the TLS secret that includes the certificate and private key of this domain mapping. | +| user_managed | Specifies whether the domain mapping is managed by the user or by Code Engine. | +| visibility | Specifies whether the domain mapping is reachable through the public internet, or private IBM network, or only through other components within the same Code Engine project. | + +### Data source: ibm_code_engine_function ```hcl -data "ibm_code_engine_secret" "code_engine_secret_instance" { - project_id = var.code_engine_project_id - name = var.code_engine_secret_name +data "ibm_code_engine_function" "code_engine_function_instance" { + project_id = var.data_code_engine_function_project_id + name = var.data_code_engine_function_name } ``` -code_engine_binding data source: +#### Inputs + +| Name | Description | Type | Required | +|------|-------------|------|---------| +| project_id | The ID of the project. | `string` | true | +| name | The name of your function. | `string` | true | + +#### Outputs + +| Name | Description | +|------|-------------| +| code_binary | Specifies whether the code is binary or not. Defaults to false when `code_reference` is set to a data URL. When `code_reference` is set to a code bundle URL, this field is always true. | +| code_main | Specifies the name of the function that should be invoked. | +| code_reference | Specifies either a reference to a code bundle or the source code itself. To specify the source code, use the data URL scheme and include the source code as base64 encoded. The data URL scheme is defined in [RFC 2397](https://tools.ietf.org/html/rfc2397). | +| code_secret | The name of the secret that is used to access the specified `code_reference`. The secret is used to authenticate with a non-public endpoint that is specified as`code_reference`. | +| created_at | The timestamp when the resource was created. | +| endpoint | URL to invoke the function. | +| endpoint_internal | URL to function that is only visible within the project. | +| entity_tag | The version of the function instance, which is used to achieve optimistic locking. | +| href | When you provision a new function, a relative URL path is created identifying the location of the instance. | +| managed_domain_mappings | Optional value controlling which of the system managed domain mappings will be setup for the function. Valid values are 'local_public', 'local_private' and 'local'. Visibility can only be 'local_private' if the project supports function private visibility. | +| region | The region of the project the resource is located in. Possible values: 'au-syd', 'br-sao', 'ca-tor', 'eu-de', 'eu-gb', 'jp-osa', 'jp-tok', 'us-east', 'us-south'. | +| resource_type | The type of the function. | +| run_env_variables | References to config maps, secrets or literal values, which are defined by the function owner and are exposed as environment variables in the function. | +| runtime | The managed runtime used to execute the injected code. | +| scale_concurrency | Number of parallel requests handled by a single instance, supported only by Node.js, default is `1`. | +| scale_cpu_limit | Optional amount of CPU set for the instance of the function. For valid values see [Supported memory and CPU combinations](https://cloud.ibm.com/docs/codeengine?topic=codeengine-mem-cpu-combo). | +| scale_down_delay | Optional amount of time in seconds that delays the scale down behavior for a function. | +| scale_max_execution_time | Timeout in secs after which the function is terminated. | +| scale_memory_limit | Optional amount of memory set for the instance of the function. For valid values see [Supported memory and CPU combinations](https://cloud.ibm.com/docs/codeengine?topic=codeengine-mem-cpu-combo). The units for specifying memory are Megabyte (M) or Gigabyte (G), whereas G and M are the shorthand expressions for GB and MB. For more information see [Units of measurement](https://cloud.ibm.com/docs/codeengine?topic=codeengine-mem-cpu-combo#unit-measurements). | +| status | The current status of the function. | +| status_details | The detailed status of the function. | + +### Data source: ibm_code_engine_job ```hcl -data "ibm_code_engine_binding" "code_engine_binding_instance" { - project_id = var.code_engine_project_id - binding_id = var.code_engine_binding_id +data "ibm_code_engine_job" "code_engine_job_instance" { + project_id = var.data_code_engine_job_project_id + name = var.data_code_engine_job_name } ``` -code_engine_domain_mapping data source: +#### Inputs + +| Name | Description | Type | Required | +|------|-------------|------|---------| +| project_id | The ID of the project. | `string` | true | +| name | The name of your job. | `string` | true | + +#### Outputs + +| Name | Description | +|------|-------------| +| build | Reference to a build that is associated with the job. | +| build_run | Reference to a build run that is associated with the job. | +| created_at | The timestamp when the resource was created. | +| entity_tag | The version of the job instance, which is used to achieve optimistic locking. | +| href | When you provision a new job, a URL is created identifying the location of the instance. | +| image_reference | The name of the image that is used for this job. The format is `REGISTRY/NAMESPACE/REPOSITORY:TAG` where `REGISTRY` and `TAG` are optional. If `REGISTRY` is not specified, the default is `docker.io`. If `TAG` is not specified, the default is `latest`. If the image reference points to a registry that requires authentication, make sure to also specify the property `image_secret`. | +| image_secret | The name of the image registry access secret. The image registry access secret is used to authenticate with a private registry when you download the container image. If the image reference points to a registry that requires authentication, the job / job runs will be created but submitted job runs will fail, until this property is provided, too. This property must not be set on a job run, which references a job template. | +| region | The region of the project the resource is located in. Possible values: 'au-syd', 'br-sao', 'ca-tor', 'eu-de', 'eu-gb', 'jp-osa', 'jp-tok', 'us-east', 'us-south'. | +| resource_type | The type of the job. | +| run_arguments | Set arguments for the job that are passed to start job run containers. If not specified an empty string array will be applied and the arguments specified by the container image, will be used to start the container. | +| run_as_user | The user ID (UID) to run the job. | +| run_commands | Set commands for the job that are passed to start job run containers. If not specified an empty string array will be applied and the command specified by the container image, will be used to start the container. | +| run_env_variables | References to config maps, secrets or literal values, which are exposed as environment variables in the job run. | +| run_mode | The mode for runs of the job. Valid values are `task` and `daemon`. In `task` mode, the `max_execution_time` and `retry_limit` properties apply. In `daemon` mode, since there is no timeout and failed instances are restarted indefinitely, the `max_execution_time` and `retry_limit` properties are not allowed. | +| run_service_account | The name of the service account. For built-in service accounts, you can use the shortened names `manager`, `none`, `reader`, and `writer`. This property must not be set on a job run, which references a job template. | +| run_volume_mounts | Optional mounts of config maps or secrets. | +| scale_array_spec | Define a custom set of array indices as a comma-separated list containing single values and hyphen-separated ranges, such as 5,12-14,23,27. Each instance gets its array index value from the environment variable JOB_INDEX. The number of unique array indices that you specify with this parameter determines the number of job instances to run. | +| scale_cpu_limit | Optional amount of CPU set for the instance of the job. For valid values see [Supported memory and CPU combinations](https://cloud.ibm.com/docs/codeengine?topic=codeengine-mem-cpu-combo). | +| scale_ephemeral_storage_limit | Optional amount of ephemeral storage to set for the instance of the job. The amount specified as ephemeral storage, must not exceed the amount of `scale_memory_limit`. The units for specifying ephemeral storage are Megabyte (M) or Gigabyte (G), whereas G and M are the shorthand expressions for GB and MB. For more information see [Units of measurement](https://cloud.ibm.com/docs/codeengine?topic=codeengine-mem-cpu-combo#unit-measurements). | +| scale_max_execution_time | The maximum execution time in seconds for runs of the job. This property can only be specified if `run_mode` is `task`. | +| scale_memory_limit | Optional amount of memory set for the instance of the job. For valid values see [Supported memory and CPU combinations](https://cloud.ibm.com/docs/codeengine?topic=codeengine-mem-cpu-combo). The units for specifying memory are Megabyte (M) or Gigabyte (G), whereas G and M are the shorthand expressions for GB and MB. For more information see [Units of measurement](https://cloud.ibm.com/docs/codeengine?topic=codeengine-mem-cpu-combo#unit-measurements). | +| scale_retry_limit | The number of times to rerun an instance of the job before the job is marked as failed. This property can only be specified if `run_mode` is `task`. | + +### Data source: ibm_code_engine_secret ```hcl -data "ibm_code_engine_domain_mapping" "code_engine_domain_mapping_instance" { - project_id = var.code_engine_project_id - name = var.code_engine_domain_mapping_name +data "ibm_code_engine_secret" "code_engine_secret_instance" { + project_id = var.data_code_engine_secret_project_id + name = var.data_code_engine_secret_name } ``` -## Inputs +#### Inputs | Name | Description | Type | Required | |------|-------------|------|---------| -| ibmcloud\_api\_key | IBM Cloud API key | `string` | true | | project_id | The ID of the project. | `string` | true | -| image_reference | The name of the image that is used for this app or job. The format is `REGISTRY/NAMESPACE/REPOSITORY:TAG` where `REGISTRY` and `TAG` are optional. If `REGISTRY` is not specified, the default is `docker.io`. If `TAG` is not specified, the default is `latest`. If the image reference points to a registry that requires authentication, make sure to also specify the property `image_secret`. | `string` | true | -| name | The name of the resource. | `string` | true | -| image_port | Optional port the app listens on. While the app will always be exposed via port `443` for end users, this port is used to connect to the port that is exposed by the container image. | `number` | false | -| image_secret | Optional name of the image registry access secret. The image registry access secret is used to authenticate with a private registry when you download the container image. If the image reference points to a registry that requires authentication, the app will be created but cannot reach the ready status, until this property is provided, too. | `string` | false | -| managed_domain_mappings | Optional value controlling which of the system managed domain mappings will be setup for the application. Valid values are 'local_public', 'local_private' and 'local'. Visibility can only be 'local_private' if the project supports application private visibility. | `string` | false | -| run_arguments | Optional arguments for the app that are passed to start the container. If not specified an empty string array will be applied and the arguments specified by the container image, will be used to start the container. | `list(string)` | false | -| run_as_user | Optional user ID (UID) to run the app/job (e.g., `1001`). | `number` | false | -| run_commands | Optional commands for the app/job that are passed to start the container. If not specified an empty string array will be applied and the command specified by the container image, will be used to start the container. | `list(string)` | false | -| run_env_variables | Optional references to config maps, secrets or literal values that are exposed as environment variables within the running application. | `list()` | false | -| run_service_account | Optional name of the service account. For built-in service accounts, you can use the shortened names `manager` , `none`, `reader`, and `writer`. | `string` | false | -| run_volume_mounts | Optional mounts of config maps or a secrets. | `list()` | false | -| scale_concurrency | Optional maximum number of requests that can be processed concurrently per instance. | `number` | false | -| scale_concurrency_target | Optional threshold of concurrent requests per instance at which one or more additional instances are created. Use this value to scale up instances based on concurrent number of requests. This option defaults to the value of the `scale_concurrency` option, if not specified. | `number` | false | -| scale_cpu_limit | Optional number of CPU set for the instance of the app/job. For valid values see [Supported memory and CPU combinations](https://cloud.ibm.com/docs/codeengine?topic=codeengine-mem-cpu-combo). | `string` | false | -| scale_down_delay | Optional amount of time in seconds that delays the scale down behavior for an app instance. | `number` | false | -| scale_ephemeral_storage_limit | Optional amount of ephemeral storage to set for the instance of the app. The amount specified as ephemeral storage, must not exceed the amount of `scale_memory_limit`. The units for specifying ephemeral storage are Megabyte (M) or Gigabyte (G), whereas G and M are the shorthand expressions for GB and MB. For more information see [Units of measurement](https://cloud.ibm.com/docs/codeengine?topic=codeengine-mem-cpu-combo#unit-measurements). | `string` | false | -| scale_initial_instances | Optional initial number of instances that are created upon app creation or app update. | `number` | false | -| scale_max_instances | Optional maximum number of instances for this app. If you set this value to `0`, this property does not set a upper scaling limit. However, the app scaling is still limited by the project quota for instances. See [Limits and quotas for Code Engine](https://cloud.ibm.com/docs/codeengine?topic=codeengine-limits). | `number` | false | -| scale_memory_limit | Optional amount of memory set for the instance of the app. For valid values see [Supported memory and CPU combinations](https://cloud.ibm.com/docs/codeengine?topic=codeengine-mem-cpu-combo). The units for specifying memory are Megabyte (M) or Gigabyte (G), whereas G and M are the shorthand expressions for GB and MB. For more information see [Units of measurement](https://cloud.ibm.com/docs/codeengine?topic=codeengine-mem-cpu-combo#unit-measurements). | `string` | false | -| scale_min_instances | Optional minimum number of instances for this app. If you set this value to `0`, the app will scale down to zero, if not hit by any request for some time. | `number` | false | -| scale_request_timeout | Optional amount of time in seconds that is allowed for a running app to respond to a request. | `number` | false | -| component | A reference to another component. | `` | true | -| prefix | Optional value that is set as prefix in the component that is bound. Will be generated if not provided. | `string` | true | -| secret_name | The service access secret that is binding to a component. | `string` | true | -| output_image | The name of the image. | `string` | true | -| output_secret | The secret that is required to access the image registry. Make sure that the secret is granted with push permissions towards the specified container registry namespace. | `string` | true | -| strategy_type | The strategy to use for building the image. | `string` | true | -| source_context_dir | Option directory in the repository that contains the buildpacks file or the Dockerfile. | `string` | false | -| source_revision | Commit, tag, or branch in the source repository to pull. This field is optional if the `source_type` is `git` and uses the HEAD of default branch if not specified. If the `source_type` value is `local`, this field must be omitted. | `string` | false | -| source_secret | Name of the secret that is used access the repository source. This field is optional if the `source_type` is `git`. Additionally, if the `source_url` points to a repository that requires authentication, the build will be created but cannot access any source code, until this property is provided, too. If the `source_type` value is `local`, this field must be omitted. | `string` | false | -| source_type | Specifies the type of source to determine if your build source is in a repository or based on local source code.* local - For builds from local source code.* git - For builds from git version controlled source code. | `string` | false | -| source_url | The URL of the code repository. This field is required if the `source_type` is `git`. If the `source_type` value is `local`, this field must be omitted. If the repository is publicly available you can provide a 'https' URL like `https://github.com/IBM/CodeEngine`. If the repository requires authentication, you need to provide a 'ssh' URL like `git@github.com:IBM/CodeEngine.git` along with a `source_secret` that points to a secret of format `ssh_auth`. | `string` | false | -| strategy_size | Optional size for the build, which determines the amount of resources used. Build sizes are `small`, `medium`, `large`, `xlarge`. | `string` | false | -| strategy_spec_file | Optional path to the specification file that is used for build strategies for building an image. | `string` | false | -| timeout | The maximum amount of time, in seconds, that can pass before the build must succeed or fail. | `number` | false | -| data | The key-value pair for the config map. Values must be specified in `KEY=VALUE` format. Each `KEY` field must consist of alphanumeric characters, `-`, `_` or `.` and must not be exceed a max length of 253 characters. Each `VALUE` field can consists of any character and must not be exceed a max length of 1048576 characters. | `map(string)` | false | -| image_reference | The name of the image that is used for this job. The format is `REGISTRY/NAMESPACE/REPOSITORY:TAG` where `REGISTRY` and `TAG` are optional. If `REGISTRY` is not specified, the default is `docker.io`. If `TAG` is not specified, the default is `latest`. If the image reference points to a registry that requires authentication, make sure to also specify the property `image_secret`. | `string` | true | -| image_secret | The name of the image registry access secret. The image registry access secret is used to authenticate with a private registry when you download the container image. If the image reference points to a registry that requires authentication, the job / job runs will be created but submitted job runs will fail, until this property is provided, too. This property must not be set on a job run, which references a job template. | `string` | false | -| run_mode | The mode for runs of the job. Valid values are `task` and `daemon`. In `task` mode, the `scale_max_execution_time` and `scale_retry_limit` properties apply. In `daemon` mode, since there is no timeout and failed instances are restarted indefinitely, the `scale_max_execution_time` and `scale_retry_limit` properties are not allowed. | `string` | false | -| scale_array_spec | Define a custom set of array indices as comma-separated list containing single values and hyphen-separated ranges like `5,12-14,23,27`. Each instance can pick up its array index via environment variable `JOB_INDEX`. The number of unique array indices specified here determines the number of job instances to run. | `string` | false | -| scale_max_execution_time | The maximum execution time in seconds for runs of the job. This property can only be specified if `run_mode` is `task`. | `number` | false | -| scale_memory_limit | Optional amount of memory set for the instance of the job. For valid values see [Supported memory and CPU combinations](https://cloud.ibm.com/docs/codeengine?topic=codeengine-mem-cpu-combo). The units for specifying memory are Megabyte (M) or Gigabyte (G), whereas G and M are the shorthand expressions for GB and MB. For more information see [Units of measurement](https://cloud.ibm.com/docs/codeengine?topic=codeengine-mem-cpu-combo#unit-measurements). | `string` | false | -| scale_retry_limit | The number of times to rerun an instance of the job before the job is marked as failed. This property can only be specified if `run_mode` is `task`. | `number` | false | -| resource_group_id | Optional ID of the resource group for your project deployment. If this field is not defined, the default resource group of the account will be used. | `string` | false | -| format | Specify the format of the secret. | `string` | true | -| service_access | Properties for Service Access Secret Prototypes. | `` | false | -| tls_secret | The name of the TLS secret that holds the certificate and private key of the domain mapping. | `string` | true | +| name | The name of your secret. | `string` | true | -## Outputs +#### Outputs | Name | Description | |------|-------------| -| code_engine_project | code_engine_project object | -| code_engine_app | code_engine_app object | -| code_engine_binding | code_engine_binding object | -| code_engine_build | code_engine_build object | -| code_engine_config_map | code_engine_config_map object | -| code_engine_domain_mapping | code_engine_domain_mapping object | -| code_engine_job | code_engine_job object | -| code_engine_secret | code_engine_secret object | +| created_at | The timestamp when the resource was created. | +| data | Data container that allows to specify config parameters and their values as a key-value map. Each key field must consist of alphanumeric characters, `-`, `_` or `.` and must not exceed a max length of 253 characters. Each value field can consists of any character and must not exceed a max length of 1048576 characters. | +| entity_tag | The version of the secret instance, which is used to achieve optimistic locking. | +| format | Specify the format of the secret. | +| href | When you provision a new secret, a URL is created identifying the location of the instance. | +| region | The region of the project the resource is located in. Possible values: 'au-syd', 'br-sao', 'ca-tor', 'eu-de', 'eu-gb', 'jp-osa', 'jp-tok', 'us-east', 'us-south'. | +| resource_type | The type of the secret. | +| service_access | Properties for Service Access Secrets. | +| service_operator | Properties for the IBM Cloud Operator Secret. | diff --git a/examples/ibm-code-engine/main.tf b/examples/ibm-code-engine/main.tf index e196dbfd810..bbb3ecb3e2f 100644 --- a/examples/ibm-code-engine/main.tf +++ b/examples/ibm-code-engine/main.tf @@ -28,7 +28,7 @@ resource "ibm_code_engine_config_map" "code_engine_config_map_instance" { } // Provision code_engine_secret resource instance -resource "ibm_code_engine_secret" "code_engine_secret_generic" { +resource "ibm_code_engine_secret" "code_engine_secret_instance" { project_id = ibm_code_engine_project.code_engine_project_instance.project_id name = var.code_engine_secret_name format = var.code_engine_secret_format @@ -83,6 +83,14 @@ resource "ibm_code_engine_secret" "code_engine_secret_service_access" { } } +// Provision code_engine_secret resource instance for format tls +resource "ibm_code_engine_secret" "code_engine_secret_tls_instance" { + project_id = ibm_code_engine_project.code_engine_project_instance.project_id + name = var.code_engine_secret_tls_name + format = "tls" + data = local.tls_secret_data +} + // Provision code_engine_binding resource instance resource "ibm_code_engine_binding" "code_engine_binding_instance" { project_id = ibm_code_engine_project.code_engine_project_instance.project_id @@ -102,7 +110,19 @@ resource "ibm_code_engine_domain_mapping" "code_engine_domain_mapping_instance" name = ibm_code_engine_app.code_engine_app_instance.name resource_type = ibm_code_engine_app.code_engine_app_instance.resource_type } - tls_secret = ibm_code_engine_secret.code_engine_secret_instance.name + tls_secret = ibm_code_engine_secret.code_engine_secret_tls_instance.name + + depends_on = [ + ibm_code_engine_app.code_engine_app_instance, + ] +} + +// Provision code_engine_function resource instance +resource "ibm_code_engine_function" "code_engine_function_instance" { + project_id = ibm_code_engine_project.code_engine_project_instance.project_id + name = var.code_engine_function_name + runtime = var.code_engine_function_runtime + code_reference = local.function_code_reference } ////////////////// @@ -154,3 +174,19 @@ data "ibm_code_engine_domain_mapping" "code_engine_domain_mapping_data" { project_id = data.ibm_code_engine_project.code_engine_project_data.project_id name = var.code_engine_domain_mapping_name } + +// Create code_engine_function data source +data "ibm_code_engine_function" "code_engine_function_data" { + project_id = data.ibm_code_engine_project.code_engine_project_data.project_id + name = var.code_engine_function_name +} + +////////////////// +// Locals +locals { + tls_secret_data = { + tls_key = file(var.code_engine_secret_tls_key_file_path) + tls_cert = file(var.code_engine_secret_tls_crt_file_path) + } + function_code_reference = format("data:text/plain;base64,%s", filebase64(var.code_engine_function_code_reference_file_path)) +} diff --git a/examples/ibm-code-engine/outputs.tf b/examples/ibm-code-engine/outputs.tf index 71264826557..ebc5c0e1800 100644 --- a/examples/ibm-code-engine/outputs.tf +++ b/examples/ibm-code-engine/outputs.tf @@ -48,3 +48,9 @@ output "ibm_code_engine_domain_mapping" { value = ibm_code_engine_domain_mapping.code_engine_domain_mapping_instance description = "code_engine_domain_mapping resource instance" } +// This allows code_engine_function data to be referenced by other resources and the terraform CLI +// Modify this if only certain data should be exposed +output "ibm_code_engine_function" { + value = ibm_code_engine_function.code_engine_function_instance + description = "code_engine_function resource instance" +} diff --git a/examples/ibm-code-engine/variables.tf b/examples/ibm-code-engine/variables.tf index 86f1b0a770f..0c7734109bd 100644 --- a/examples/ibm-code-engine/variables.tf +++ b/examples/ibm-code-engine/variables.tf @@ -17,7 +17,7 @@ variable "code_engine_project_name" { // Resource arguments for code_engine_app variable "code_engine_app_image_reference" { - description = "The name of the image that is used for this job. The format is `REGISTRY/NAMESPACE/REPOSITORY:TAG` where `REGISTRY` and `TAG` are optional. If `REGISTRY` is not specified, the default is `docker.io`. If `TAG` is not specified, the default is `latest`. If the image reference points to a registry that requires authentication, make sure to also specify the property `image_secret`." + description = "The name of the image that is used for this app. The format is `REGISTRY/NAMESPACE/REPOSITORY:TAG` where `REGISTRY` and `TAG` are optional. If `REGISTRY` is not specified, the default is `docker.io`. If `TAG` is not specified, the default is `latest`. If the image reference points to a registry that requires authentication, make sure to also specify the property `image_secret`." type = string default = "icr.io/codeengine/helloworld" } @@ -125,6 +125,37 @@ variable "code_engine_domain_mapping_name" { type = string } +// Resource arguments for code_engine_function +variable "code_engine_function_name" { + description = "The name of the function." + type = string + default = "my-function" +} +variable "code_engine_function_runtime" { + description = "The runtime of the function." + type = string + default = "nodejs-20" +} +variable "code_engine_function_code_reference_file_path" { + description = "The path to a file containing the source code." + type = string +} + +// Resource arguments for code_engine_secret with format tls +variable "code_engine_secret_tls_name" { + description = "The name of the tls secret." + type = string + default = "my-tls-secret" +} +variable "code_engine_secret_tls_key_file_path" { + description = "The path to the .key file containing the private key of the TLS certificate." + type = string +} +variable "code_engine_secret_tls_crt_file_path" { + description = "The path to the .crt file containing the signed TLS certificate." + type = string +} + // Data source arguments for code_engine_project variable "code_engine_project_id" { description = "The ID of the project." diff --git a/go.mod b/go.mod index dd37ef341f7..de81d322f14 100644 --- a/go.mod +++ b/go.mod @@ -13,7 +13,7 @@ require ( github.com/IBM/appid-management-go-sdk v0.0.0-20210908164609-dd0e0eaf732f github.com/IBM/cloud-databases-go-sdk v0.7.0 github.com/IBM/cloudant-go-sdk v0.8.0 - github.com/IBM/code-engine-go-sdk v0.0.0-20240126185534-a6e054aa01ed + github.com/IBM/code-engine-go-sdk v0.0.0-20240808131715-b9d168602dac github.com/IBM/container-registry-go-sdk v1.1.0 github.com/IBM/continuous-delivery-go-sdk v1.6.0 github.com/IBM/event-notifications-go-admin-sdk v0.9.0 @@ -104,7 +104,7 @@ require ( github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/gabriel-vasile/mimetype v1.4.3 // indirect github.com/go-jose/go-jose/v3 v3.0.3 // indirect - github.com/go-logr/logr v1.3.0 // indirect + github.com/go-logr/logr v1.4.1 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-openapi/analysis v0.21.5 // indirect github.com/go-openapi/errors v0.22.0 // indirect diff --git a/go.sum b/go.sum index 3b78929a98f..4b4ae2f1f92 100644 --- a/go.sum +++ b/go.sum @@ -132,8 +132,8 @@ github.com/IBM/cloud-databases-go-sdk v0.7.0 h1:prvLebKD1kcIk81D6yRhOr/TWp1VQJGL github.com/IBM/cloud-databases-go-sdk v0.7.0/go.mod h1:JYucI1PdwqbAd8XGdDAchxzxRP7bxOh1zUnseovHKsc= github.com/IBM/cloudant-go-sdk v0.8.0 h1:XzaqZFy5fm1Q9+iK52X5zRW39SHaahT9pf5SRgVTsTY= github.com/IBM/cloudant-go-sdk v0.8.0/go.mod h1:zDGBs8ideVtn9MehXbIQNI3852B68BsMtKJvq3iPn/Q= -github.com/IBM/code-engine-go-sdk v0.0.0-20240126185534-a6e054aa01ed h1:X0VrZW5ulbqxbOmy5JoZcH0A+tw80k0/ZmRZz1NqogM= -github.com/IBM/code-engine-go-sdk v0.0.0-20240126185534-a6e054aa01ed/go.mod h1:m4pD/58c6NVzlAFkN3XCYXpmDFmUyTG31ivLy/loyHQ= +github.com/IBM/code-engine-go-sdk v0.0.0-20240808131715-b9d168602dac h1:9Y5TB9Ar2SM6JPr2kM6c9pHSdSuHMDCIcbvTa/hNTj4= +github.com/IBM/code-engine-go-sdk v0.0.0-20240808131715-b9d168602dac/go.mod h1:sy4CocPPaCiS+T1znqVdw83dkoyxSMUFxkksqahUhbY= github.com/IBM/container-registry-go-sdk v1.1.0 h1:sYyknIod8R4RJZQqAheiduP6wbSTphE9Ag8ho28yXjc= github.com/IBM/container-registry-go-sdk v1.1.0/go.mod h1:4TwsCnQtVfZ4Vkapy/KPvQBKFc3VOyUZYkwRU4FTPrs= github.com/IBM/continuous-delivery-go-sdk v1.6.0 h1:eAL/jIWHrDFlWDF+Qd9Y5UN99Pr5Mjd/H/bvTbXUbz4= @@ -529,8 +529,9 @@ github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbV github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.3.0 h1:2y3SDp0ZXuc6/cjLSZ+Q3ir+QB9T/iG5yYRXqsagWSY= github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= +github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-logr/zapr v0.1.0/go.mod h1:tabnROwaDl0UNxkVeFRbY8bwB37GwRv0P8lg6aAiEnk= @@ -644,6 +645,8 @@ github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/me github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= +github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= +github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= github.com/go-test/deep v1.0.1/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= github.com/go-test/deep v1.0.2-0.20181118220953-042da051cf31/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= github.com/go-test/deep v1.0.2/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= @@ -779,8 +782,8 @@ github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLe github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20230510103437-eeec1cb781c3 h1:2XF1Vzq06X+inNqgJ9tRnGuw+ZVCB3FazXODD6JE1R8= -github.com/google/pprof v0.0.0-20230510103437-eeec1cb781c3/go.mod h1:79YE0hCXdHag9sBkw2o+N/YnZtTkXi0UT9Nnixa5eYk= +github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6 h1:k7nVchz72niMH6YLQNvHSdIE7iqsQxK1P41mySCvssg= +github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6/go.mod h1:kf6iHlnVGwgKolg33glAes7Yg/8iWP8ukqeldJSO7jw= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -1347,8 +1350,9 @@ github.com/onsi/ginkgo/v2 v2.9.5/go.mod h1:tvAoo1QUJwNEU2ITftXTpR7R1RbCzoZUOs3Ro github.com/onsi/ginkgo/v2 v2.9.7/go.mod h1:cxrmXWykAwTwhQsJOPfdIDiJ+l2RYq7U8hFU+M/1uw0= github.com/onsi/ginkgo/v2 v2.11.0/go.mod h1:ZhrRA5XmEE3x3rhlzamx/JJvujdZoJ2uvgI7kR0iZvM= github.com/onsi/ginkgo/v2 v2.13.0/go.mod h1:TE309ZR8s5FsKKpuB1YAQYBzCaAfUgatB/xlT/ETL/o= -github.com/onsi/ginkgo/v2 v2.15.0 h1:79HwNRBAZHOEwrczrgSOPy+eFTTlIGELKy5as+ClttY= github.com/onsi/ginkgo/v2 v2.15.0/go.mod h1:HlxMHtYF57y6Dpf+mc5529KKmSq9h2FpCF+/ZkwUxKM= +github.com/onsi/ginkgo/v2 v2.19.0 h1:9Cnnf7UHo57Hy3k6/m5k3dRfGTMXGvxhHFvkDTCTpvA= +github.com/onsi/ginkgo/v2 v2.19.0/go.mod h1:rlwLi9PilAFJ8jCg9UE1QP6VBpd6/xj3SRC0d6TU0To= github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v0.0.0-20190113212917-5533ce8a0da3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.4.2/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= @@ -1380,8 +1384,8 @@ github.com/onsi/gomega v1.27.8/go.mod h1:2J8vzI/s+2shY9XHRApDkdgPo1TKT7P2u6fXeJK github.com/onsi/gomega v1.27.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3evPbQ0M= github.com/onsi/gomega v1.30.0/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ= github.com/onsi/gomega v1.31.1/go.mod h1:y40C95dwAD1Nz36SsEnxvfFe8FFfNxzI5eJ0EYGyAy0= -github.com/onsi/gomega v1.33.1 h1:dsYjIxxSR755MDmKVsaFQTE22ChNBcuuTWgkUDSubOk= -github.com/onsi/gomega v1.33.1/go.mod h1:U4R44UsT+9eLIaYRB2a5qajjtQYn0hauxvRm16AVYg0= +github.com/onsi/gomega v1.34.1 h1:EUMJIKUjM8sKjYbtxQI9A4z2o+rruxnzNvpknOXie6k= +github.com/onsi/gomega v1.34.1/go.mod h1:kU1QgUvBDLXBJq618Xvm2LUX6rSAfRaFRTcdOeDLwwY= github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= @@ -1786,6 +1790,8 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0 golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= +golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8= +golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -2191,8 +2197,8 @@ golang.org/x/tools v0.9.3/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc= golang.org/x/tools v0.12.0/go.mod h1:Sc0INKfu04TlqNoRA1hgpFZbhYXHPr4V5DzpSBTPqQM= golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= golang.org/x/tools v0.16.1/go.mod h1:kYVVN6I1mBNoB1OX+noeBjbRk4IUEPa7JJ+TJMEooJ0= -golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg= -golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= +golang.org/x/tools v0.23.0 h1:SGsXPZ+2l4JsgaCKkx+FQ9YZ5XEtA1GZYuoDjenLjvg= +golang.org/x/tools v0.23.0/go.mod h1:pnu6ufv6vQkll6szChhK3C3L/ruaIv5eBeztNG8wtsI= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/ibm/provider/provider.go b/ibm/provider/provider.go index 00b107e2790..2d94cf08f04 100644 --- a/ibm/provider/provider.go +++ b/ibm/provider/provider.go @@ -932,6 +932,7 @@ func Provider() *schema.Provider { "ibm_code_engine_build": codeengine.DataSourceIbmCodeEngineBuild(), "ibm_code_engine_config_map": codeengine.DataSourceIbmCodeEngineConfigMap(), "ibm_code_engine_domain_mapping": codeengine.DataSourceIbmCodeEngineDomainMapping(), + "ibm_code_engine_function": codeengine.DataSourceIbmCodeEngineFunction(), "ibm_code_engine_job": codeengine.DataSourceIbmCodeEngineJob(), "ibm_code_engine_project": codeengine.DataSourceIbmCodeEngineProject(), "ibm_code_engine_secret": codeengine.DataSourceIbmCodeEngineSecret(), @@ -1534,6 +1535,7 @@ func Provider() *schema.Provider { "ibm_code_engine_build": codeengine.ResourceIbmCodeEngineBuild(), "ibm_code_engine_config_map": codeengine.ResourceIbmCodeEngineConfigMap(), "ibm_code_engine_domain_mapping": codeengine.ResourceIbmCodeEngineDomainMapping(), + "ibm_code_engine_function": codeengine.ResourceIbmCodeEngineFunction(), "ibm_code_engine_job": codeengine.ResourceIbmCodeEngineJob(), "ibm_code_engine_project": codeengine.ResourceIbmCodeEngineProject(), "ibm_code_engine_secret": codeengine.ResourceIbmCodeEngineSecret(), @@ -1990,6 +1992,7 @@ func Validator() validate.ValidatorDict { "ibm_code_engine_build": codeengine.ResourceIbmCodeEngineBuildValidator(), "ibm_code_engine_config_map": codeengine.ResourceIbmCodeEngineConfigMapValidator(), "ibm_code_engine_domain_mapping": codeengine.ResourceIbmCodeEngineDomainMappingValidator(), + "ibm_code_engine_function": codeengine.ResourceIbmCodeEngineFunctionValidator(), "ibm_code_engine_job": codeengine.ResourceIbmCodeEngineJobValidator(), "ibm_code_engine_project": codeengine.ResourceIbmCodeEngineProjectValidator(), "ibm_code_engine_secret": codeengine.ResourceIbmCodeEngineSecretValidator(), diff --git a/ibm/service/codeengine/data_source_ibm_code_engine_function.go b/ibm/service/codeengine/data_source_ibm_code_engine_function.go new file mode 100644 index 00000000000..5fc67cd134f --- /dev/null +++ b/ibm/service/codeengine/data_source_ibm_code_engine_function.go @@ -0,0 +1,373 @@ +// Copyright IBM Corp. 2024 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package codeengine + +import ( + "context" + "fmt" + "log" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM/code-engine-go-sdk/codeenginev2" +) + +func DataSourceIbmCodeEngineFunction() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIbmCodeEngineFunctionRead, + + Schema: map[string]*schema.Schema{ + "project_id": { + Type: schema.TypeString, + Required: true, + Description: "The ID of the project.", + }, + "name": { + Type: schema.TypeString, + Required: true, + Description: "The name of your function.", + }, + "code_binary": { + Type: schema.TypeBool, + Computed: true, + Description: "Specifies whether the code is binary or not. Defaults to false when `code_reference` is set to a data URL. When `code_reference` is set to a code bundle URL, this field is always true.", + }, + "code_main": { + Type: schema.TypeString, + Computed: true, + Description: "Specifies the name of the function that should be invoked.", + }, + "code_reference": { + Type: schema.TypeString, + Computed: true, + Description: "Specifies either a reference to a code bundle or the source code itself. To specify the source code, use the data URL scheme and include the source code as base64 encoded. The data URL scheme is defined in [RFC 2397](https://tools.ietf.org/html/rfc2397).", + }, + "code_secret": { + Type: schema.TypeString, + Computed: true, + Description: "The name of the secret that is used to access the specified `code_reference`. The secret is used to authenticate with a non-public endpoint that is specified as`code_reference`.", + }, + "created_at": { + Type: schema.TypeString, + Computed: true, + Description: "The timestamp when the resource was created.", + }, + "endpoint": { + Type: schema.TypeString, + Computed: true, + Description: "URL to invoke the function.", + }, + "endpoint_internal": { + Type: schema.TypeString, + Computed: true, + Description: "URL to function that is only visible within the project.", + }, + "entity_tag": { + Type: schema.TypeString, + Computed: true, + Description: "The version of the function instance, which is used to achieve optimistic locking.", + }, + "href": { + Type: schema.TypeString, + Computed: true, + Description: "When you provision a new function, a relative URL path is created identifying the location of the instance.", + }, + "function_id": { + Type: schema.TypeString, + Computed: true, + Description: "The identifier of the resource.", + }, + "managed_domain_mappings": { + Type: schema.TypeString, + Computed: true, + Description: "Optional value controlling which of the system managed domain mappings will be setup for the function. Valid values are 'local_public', 'local_private' and 'local'. Visibility can only be 'local_private' if the project supports function private visibility.", + }, + "region": { + Type: schema.TypeString, + Computed: true, + Description: "The region of the project the resource is located in. Possible values: 'au-syd', 'br-sao', 'ca-tor', 'eu-de', 'eu-gb', 'jp-osa', 'jp-tok', 'us-east', 'us-south'.", + }, + "resource_type": { + Type: schema.TypeString, + Computed: true, + Description: "The type of the function.", + }, + "run_env_variables": { + Type: schema.TypeList, + Computed: true, + Description: "References to config maps, secrets or literal values, which are defined by the function owner and are exposed as environment variables in the function.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "key": { + Type: schema.TypeString, + Computed: true, + Description: "The key to reference as environment variable.", + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: "The name of the environment variable.", + }, + "prefix": { + Type: schema.TypeString, + Computed: true, + Description: "A prefix that can be added to all keys of a full secret or config map reference.", + }, + "reference": { + Type: schema.TypeString, + Computed: true, + Description: "The name of the secret or config map.", + }, + "type": { + Type: schema.TypeString, + Computed: true, + Description: "Specify the type of the environment variable.", + }, + "value": { + Type: schema.TypeString, + Computed: true, + Description: "The literal value of the environment variable.", + }, + }, + }, + }, + "runtime": { + Type: schema.TypeString, + Computed: true, + Description: "The managed runtime used to execute the injected code.", + }, + "scale_concurrency": { + Type: schema.TypeInt, + Computed: true, + Description: "Number of parallel requests handled by a single instance, supported only by Node.js, default is `1`.", + }, + "scale_cpu_limit": { + Type: schema.TypeString, + Computed: true, + Description: "Optional amount of CPU set for the instance of the function. For valid values see [Supported memory and CPU combinations](https://cloud.ibm.com/docs/codeengine?topic=codeengine-mem-cpu-combo).", + }, + "scale_down_delay": { + Type: schema.TypeInt, + Computed: true, + Description: "Optional amount of time in seconds that delays the scale down behavior for a function.", + }, + "scale_max_execution_time": { + Type: schema.TypeInt, + Computed: true, + Description: "Timeout in secs after which the function is terminated.", + }, + "scale_memory_limit": { + Type: schema.TypeString, + Computed: true, + Description: "Optional amount of memory set for the instance of the function. For valid values see [Supported memory and CPU combinations](https://cloud.ibm.com/docs/codeengine?topic=codeengine-mem-cpu-combo). The units for specifying memory are Megabyte (M) or Gigabyte (G), whereas G and M are the shorthand expressions for GB and MB. For more information see [Units of measurement](https://cloud.ibm.com/docs/codeengine?topic=codeengine-mem-cpu-combo#unit-measurements).", + }, + "status": { + Type: schema.TypeString, + Computed: true, + Description: "The current status of the function.", + }, + "status_details": { + Type: schema.TypeList, + Computed: true, + Description: "The detailed status of the function.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "reason": { + Type: schema.TypeString, + Computed: true, + Description: "Provides additional information about the status of the function.", + }, + }, + }, + }, + }, + } +} + +func dataSourceIbmCodeEngineFunctionRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + codeEngineClient, err := meta.(conns.ClientSession).CodeEngineV2() + if err != nil { + tfErr := flex.TerraformErrorf(err, err.Error(), "(Data) ibm_code_engine_function", "read") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } + + getFunctionOptions := &codeenginev2.GetFunctionOptions{} + + getFunctionOptions.SetProjectID(d.Get("project_id").(string)) + getFunctionOptions.SetName(d.Get("name").(string)) + + function, _, err := codeEngineClient.GetFunctionWithContext(context, getFunctionOptions) + if err != nil { + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("GetFunctionWithContext failed: %s", err.Error()), "(Data) ibm_code_engine_function", "read") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } + + d.SetId(fmt.Sprintf("%s/%s", *getFunctionOptions.ProjectID, *getFunctionOptions.Name)) + + if err = d.Set("code_binary", function.CodeBinary); err != nil { + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("Error setting code_binary: %s", err), "(Data) ibm_code_engine_function", "read") + return tfErr.GetDiag() + } + + if err = d.Set("code_main", function.CodeMain); err != nil { + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("Error setting code_main: %s", err), "(Data) ibm_code_engine_function", "read") + return tfErr.GetDiag() + } + + if err = d.Set("code_reference", function.CodeReference); err != nil { + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("Error setting code_reference: %s", err), "(Data) ibm_code_engine_function", "read") + return tfErr.GetDiag() + } + + if err = d.Set("code_secret", function.CodeSecret); err != nil { + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("Error setting code_secret: %s", err), "(Data) ibm_code_engine_function", "read") + return tfErr.GetDiag() + } + + if err = d.Set("created_at", function.CreatedAt); err != nil { + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("Error setting created_at: %s", err), "(Data) ibm_code_engine_function", "read") + return tfErr.GetDiag() + } + + if err = d.Set("endpoint", function.Endpoint); err != nil { + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("Error setting endpoint: %s", err), "(Data) ibm_code_engine_function", "read") + return tfErr.GetDiag() + } + + if err = d.Set("endpoint_internal", function.EndpointInternal); err != nil { + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("Error setting endpoint_internal: %s", err), "(Data) ibm_code_engine_function", "read") + return tfErr.GetDiag() + } + + if err = d.Set("entity_tag", function.EntityTag); err != nil { + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("Error setting entity_tag: %s", err), "(Data) ibm_code_engine_function", "read") + return tfErr.GetDiag() + } + + if err = d.Set("href", function.Href); err != nil { + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("Error setting href: %s", err), "(Data) ibm_code_engine_function", "read") + return tfErr.GetDiag() + } + + if err = d.Set("function_id", function.ID); err != nil { + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("Error setting function_id: %s", err), "(Data) ibm_code_engine_function", "read") + return tfErr.GetDiag() + } + + if err = d.Set("managed_domain_mappings", function.ManagedDomainMappings); err != nil { + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("Error setting managed_domain_mappings: %s", err), "(Data) ibm_code_engine_function", "read") + return tfErr.GetDiag() + } + + if err = d.Set("region", function.Region); err != nil { + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("Error setting region: %s", err), "(Data) ibm_code_engine_function", "read") + return tfErr.GetDiag() + } + + if err = d.Set("resource_type", function.ResourceType); err != nil { + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("Error setting resource_type: %s", err), "(Data) ibm_code_engine_function", "read") + return tfErr.GetDiag() + } + + runEnvVariables := []map[string]interface{}{} + if function.RunEnvVariables != nil { + for _, modelItem := range function.RunEnvVariables { + modelMap, err := dataSourceIbmCodeEngineFunctionEnvVarToMap(&modelItem) /* #nosec G601 */ + if err != nil { + tfErr := flex.TerraformErrorf(err, err.Error(), "(Data) ibm_code_engine_function", "read") + return tfErr.GetDiag() + } + runEnvVariables = append(runEnvVariables, modelMap) + } + } + if err = d.Set("run_env_variables", runEnvVariables); err != nil { + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("Error setting run_env_variables: %s", err), "(Data) ibm_code_engine_function", "read") + return tfErr.GetDiag() + } + + if err = d.Set("runtime", function.Runtime); err != nil { + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("Error setting runtime: %s", err), "(Data) ibm_code_engine_function", "read") + return tfErr.GetDiag() + } + + if err = d.Set("scale_concurrency", flex.IntValue(function.ScaleConcurrency)); err != nil { + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("Error setting scale_concurrency: %s", err), "(Data) ibm_code_engine_function", "read") + return tfErr.GetDiag() + } + + if err = d.Set("scale_cpu_limit", function.ScaleCpuLimit); err != nil { + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("Error setting scale_cpu_limit: %s", err), "(Data) ibm_code_engine_function", "read") + return tfErr.GetDiag() + } + + if err = d.Set("scale_down_delay", flex.IntValue(function.ScaleDownDelay)); err != nil { + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("Error setting scale_down_delay: %s", err), "(Data) ibm_code_engine_function", "read") + return tfErr.GetDiag() + } + + if err = d.Set("scale_max_execution_time", flex.IntValue(function.ScaleMaxExecutionTime)); err != nil { + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("Error setting scale_max_execution_time: %s", err), "(Data) ibm_code_engine_function", "read") + return tfErr.GetDiag() + } + + if err = d.Set("scale_memory_limit", function.ScaleMemoryLimit); err != nil { + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("Error setting scale_memory_limit: %s", err), "(Data) ibm_code_engine_function", "read") + return tfErr.GetDiag() + } + + if err = d.Set("status", function.Status); err != nil { + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("Error setting status: %s", err), "(Data) ibm_code_engine_function", "read") + return tfErr.GetDiag() + } + + statusDetails := []map[string]interface{}{} + if function.StatusDetails != nil { + modelMap, err := dataSourceIbmCodeEngineFunctionFunctionStatusToMap(function.StatusDetails) + if err != nil { + tfErr := flex.TerraformErrorf(err, err.Error(), "(Data) ibm_code_engine_function", "read") + return tfErr.GetDiag() + } + statusDetails = append(statusDetails, modelMap) + } + if err = d.Set("status_details", statusDetails); err != nil { + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("Error setting status_details: %s", err), "(Data) ibm_code_engine_function", "read") + return tfErr.GetDiag() + } + + return nil +} + +func dataSourceIbmCodeEngineFunctionEnvVarToMap(model *codeenginev2.EnvVar) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Key != nil { + modelMap["key"] = *model.Key + } + if model.Name != nil { + modelMap["name"] = *model.Name + } + if model.Prefix != nil { + modelMap["prefix"] = *model.Prefix + } + if model.Reference != nil { + modelMap["reference"] = *model.Reference + } + modelMap["type"] = *model.Type + if model.Value != nil { + modelMap["value"] = *model.Value + } + return modelMap, nil +} + +func dataSourceIbmCodeEngineFunctionFunctionStatusToMap(model *codeenginev2.FunctionStatus) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Reason != nil { + modelMap["reason"] = *model.Reason + } + return modelMap, nil +} diff --git a/ibm/service/codeengine/data_source_ibm_code_engine_function_test.go b/ibm/service/codeengine/data_source_ibm_code_engine_function_test.go new file mode 100644 index 00000000000..9700e13223a --- /dev/null +++ b/ibm/service/codeengine/data_source_ibm_code_engine_function_test.go @@ -0,0 +1,147 @@ +// Copyright IBM Corp. 2024 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package codeengine_test + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + + acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" +) + +func TestAccIbmCodeEngineFunctionDataSourceBasic(t *testing.T) { + functionName := fmt.Sprintf("%s", acctest.RandStringFromCharSet(10, acctest.CharSetAlpha)) + functionRuntime := "nodejs-20" + functionCodeReference := "data:text/plain;base64,foo" + + projectID := acc.CeProjectId + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIbmCodeEngineFunctionDataSourceConfigBasic(projectID, functionCodeReference, functionName, functionRuntime), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.ibm_code_engine_function.code_engine_function_instance", "function_id"), + resource.TestCheckResourceAttr("data.ibm_code_engine_function.code_engine_function_instance", "project_id", projectID), + resource.TestCheckResourceAttr("data.ibm_code_engine_function.code_engine_function_instance", "resource_type", "function_v2"), + resource.TestCheckResourceAttr("data.ibm_code_engine_function.code_engine_function_instance", "name", functionName), + resource.TestCheckResourceAttr("data.ibm_code_engine_function.code_engine_function_instance", "code_binary", "false"), + resource.TestCheckResourceAttr("data.ibm_code_engine_function.code_engine_function_instance", "code_reference", functionCodeReference), + resource.TestCheckResourceAttr("data.ibm_code_engine_function.code_engine_function_instance", "managed_domain_mappings", "local_public"), + resource.TestCheckResourceAttr("data.ibm_code_engine_function.code_engine_function_instance", "runtime", functionRuntime), + resource.TestCheckResourceAttr("data.ibm_code_engine_function.code_engine_function_instance", "scale_concurrency", "1"), + resource.TestCheckResourceAttr("data.ibm_code_engine_function.code_engine_function_instance", "scale_cpu_limit", "1"), + resource.TestCheckResourceAttr("data.ibm_code_engine_function.code_engine_function_instance", "scale_down_delay", "1"), + resource.TestCheckResourceAttr("data.ibm_code_engine_function.code_engine_function_instance", "scale_max_execution_time", "60"), + resource.TestCheckResourceAttr("data.ibm_code_engine_function.code_engine_function_instance", "scale_memory_limit", "4G"), + ), + }, + }, + }) +} + +func TestAccIbmCodeEngineFunctionDataSourceExtended(t *testing.T) { + functionName := fmt.Sprintf("%s", acctest.RandStringFromCharSet(10, acctest.CharSetAlpha)) + functionRuntime := "nodejs-20" + functionCodeReference := "data:text/plain;base64,foo" + functionManagedDomainMappings := "local_private" + functionScaleCpuLimit := "0.5" + functionScaleDownDelay := "20" + functionScaleMaxExecutionTime := "30" + functionScaleMemoryLimit := "2G" + + projectID := acc.CeProjectId + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIbmCodeEngineFunctionDataSourceConfig(projectID, functionCodeReference, functionManagedDomainMappings, functionName, functionRuntime, functionScaleCpuLimit, functionScaleDownDelay, functionScaleMaxExecutionTime, functionScaleMemoryLimit), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("data.ibm_code_engine_function.code_engine_function_instance", "project_id", projectID), + resource.TestCheckResourceAttr("data.ibm_code_engine_function.code_engine_function_instance", "resource_type", "function_v2"), + resource.TestCheckResourceAttr("data.ibm_code_engine_function.code_engine_function_instance", "name", functionName), + resource.TestCheckResourceAttr("data.ibm_code_engine_function.code_engine_function_instance", "code_binary", "false"), + resource.TestCheckResourceAttr("data.ibm_code_engine_function.code_engine_function_instance", "code_reference", functionCodeReference), + resource.TestCheckResourceAttr("data.ibm_code_engine_function.code_engine_function_instance", "managed_domain_mappings", functionManagedDomainMappings), + resource.TestCheckResourceAttr("data.ibm_code_engine_function.code_engine_function_instance", "runtime", functionRuntime), + resource.TestCheckResourceAttr("data.ibm_code_engine_function.code_engine_function_instance", "scale_concurrency", "1"), + resource.TestCheckResourceAttr("data.ibm_code_engine_function.code_engine_function_instance", "scale_cpu_limit", functionScaleCpuLimit), + resource.TestCheckResourceAttr("data.ibm_code_engine_function.code_engine_function_instance", "scale_down_delay", functionScaleDownDelay), + resource.TestCheckResourceAttr("data.ibm_code_engine_function.code_engine_function_instance", "scale_max_execution_time", functionScaleMaxExecutionTime), + resource.TestCheckResourceAttr("data.ibm_code_engine_function.code_engine_function_instance", "scale_memory_limit", functionScaleMemoryLimit), + ), + }, + }, + }) +} + +func testAccCheckIbmCodeEngineFunctionDataSourceConfigBasic(projectID string, functionCodeReference string, functionName string, functionRuntime string) string { + return fmt.Sprintf(` + data "ibm_code_engine_project" "code_engine_project_instance" { + project_id = "%s" + } + + resource "ibm_code_engine_function" "code_engine_function_instance" { + project_id = data.ibm_code_engine_project.code_engine_project_instance.project_id + code_reference = "%s" + name = "%s" + runtime = "%s" + + lifecycle { + ignore_changes = [ + run_env_variables + ] + } + } + + data "ibm_code_engine_function" "code_engine_function_instance" { + project_id = ibm_code_engine_function.code_engine_function_instance.project_id + name = ibm_code_engine_function.code_engine_function_instance.name + } + `, projectID, functionCodeReference, functionName, functionRuntime) +} + +func testAccCheckIbmCodeEngineFunctionDataSourceConfig(projectID string, functionCodeReference string, functionManagedDomainMappings string, functionName string, functionRuntime string, functionScaleCpuLimit string, functionScaleDownDelay string, functionScaleMaxExecutionTime string, functionScaleMemoryLimit string) string { + return fmt.Sprintf(` + data "ibm_code_engine_project" "code_engine_project_instance" { + project_id = "%s" + } + + resource "ibm_code_engine_function" "code_engine_function_instance" { + project_id = data.ibm_code_engine_project.code_engine_project_instance.project_id + code_reference = "%s" + managed_domain_mappings = "%s" + name = "%s" + runtime = "%s" + scale_cpu_limit = "%s" + scale_down_delay = %s + scale_max_execution_time = %s + scale_memory_limit = "%s" + + run_env_variables { + type = "literal" + name = "name" + value = "value" + } + + lifecycle { + ignore_changes = [ + run_env_variables + ] + } + } + + data "ibm_code_engine_function" "code_engine_function_instance" { + project_id = ibm_code_engine_function.code_engine_function_instance.project_id + name = ibm_code_engine_function.code_engine_function_instance.name + } + `, projectID, functionCodeReference, functionManagedDomainMappings, functionName, functionRuntime, functionScaleCpuLimit, functionScaleDownDelay, functionScaleMaxExecutionTime, functionScaleMemoryLimit) +} diff --git a/ibm/service/codeengine/resource_ibm_code_engine_function.go b/ibm/service/codeengine/resource_ibm_code_engine_function.go new file mode 100644 index 00000000000..981aecdf1c3 --- /dev/null +++ b/ibm/service/codeengine/resource_ibm_code_engine_function.go @@ -0,0 +1,839 @@ +// Copyright IBM Corp. 2024 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package codeengine + +import ( + "context" + "fmt" + "log" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" + "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/IBM/code-engine-go-sdk/codeenginev2" + "github.com/IBM/go-sdk-core/v5/core" +) + +func ResourceIbmCodeEngineFunction() *schema.Resource { + return &schema.Resource{ + CreateContext: resourceIbmCodeEngineFunctionCreate, + ReadContext: resourceIbmCodeEngineFunctionRead, + UpdateContext: resourceIbmCodeEngineFunctionUpdate, + DeleteContext: resourceIbmCodeEngineFunctionDelete, + Importer: &schema.ResourceImporter{}, + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(10 * time.Minute), + Update: schema.DefaultTimeout(10 * time.Minute), + }, + + Schema: map[string]*schema.Schema{ + "project_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.InvokeValidator("ibm_code_engine_function", "project_id"), + Description: "The ID of the project.", + }, + "code_binary": { + Type: schema.TypeBool, + Optional: true, + Description: "Specifies whether the code is binary or not. Defaults to false when `code_reference` is set to a data URL. When `code_reference` is set to a code bundle URL, this field is always true.", + }, + "code_main": { + Type: schema.TypeString, + Optional: true, + Default: "main", + ValidateFunc: validate.InvokeValidator("ibm_code_engine_function", "code_main"), + Description: "Specifies the name of the function that should be invoked.", + }, + "code_reference": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validate.InvokeValidator("ibm_code_engine_function", "code_reference"), + Description: "Specifies either a reference to a code bundle or the source code itself. To specify the source code, use the data URL scheme and include the source code as base64 encoded. The data URL scheme is defined in [RFC 2397](https://tools.ietf.org/html/rfc2397).", + }, + "code_secret": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validate.InvokeValidator("ibm_code_engine_function", "code_secret"), + Description: "The name of the secret that is used to access the specified `code_reference`. The secret is used to authenticate with a non-public endpoint that is specified as`code_reference`.", + }, + "managed_domain_mappings": { + Type: schema.TypeString, + Optional: true, + Default: "local_public", + ValidateFunc: validate.InvokeValidator("ibm_code_engine_function", "managed_domain_mappings"), + Description: "Optional value controlling which of the system managed domain mappings will be setup for the function. Valid values are 'local_public', 'local_private' and 'local'. Visibility can only be 'local_private' if the project supports function private visibility.", + }, + "name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.InvokeValidator("ibm_code_engine_function", "name"), + Description: "The name of the function.", + }, + "run_env_variables": { + Type: schema.TypeList, + Optional: true, + Description: "References to config maps, secrets or literal values, which are defined by the function owner and are exposed as environment variables in the function.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "key": { + Type: schema.TypeString, + Optional: true, + Description: "The key to reference as environment variable.", + }, + "name": { + Type: schema.TypeString, + Optional: true, + Description: "The name of the environment variable.", + }, + "prefix": { + Type: schema.TypeString, + Optional: true, + Description: "A prefix that can be added to all keys of a full secret or config map reference.", + }, + "reference": { + Type: schema.TypeString, + Optional: true, + Description: "The name of the secret or config map.", + }, + "type": { + Type: schema.TypeString, + Optional: true, + Default: "literal", + Description: "Specify the type of the environment variable.", + }, + "value": { + Type: schema.TypeString, + Optional: true, + Description: "The literal value of the environment variable.", + }, + }, + }, + }, + "runtime": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validate.InvokeValidator("ibm_code_engine_function", "runtime"), + Description: "The managed runtime used to execute the injected code.", + }, + "scale_concurrency": { + Type: schema.TypeInt, + Optional: true, + Default: 1, + ValidateFunc: validate.InvokeValidator("ibm_code_engine_function", "scale_concurrency"), + Description: "Number of parallel requests handled by a single instance, supported only by Node.js, default is `1`.", + }, + "scale_cpu_limit": { + Type: schema.TypeString, + Optional: true, + Default: "1", + ValidateFunc: validate.InvokeValidator("ibm_code_engine_function", "scale_cpu_limit"), + Description: "Optional amount of CPU set for the instance of the function. For valid values see [Supported memory and CPU combinations](https://cloud.ibm.com/docs/codeengine?topic=codeengine-mem-cpu-combo).", + }, + "scale_down_delay": { + Type: schema.TypeInt, + Optional: true, + Default: 1, + ValidateFunc: validate.InvokeValidator("ibm_code_engine_function", "scale_down_delay"), + Description: "Optional amount of time in seconds that delays the scale down behavior for a function.", + }, + "scale_max_execution_time": { + Type: schema.TypeInt, + Optional: true, + Default: 60, + ValidateFunc: validate.InvokeValidator("ibm_code_engine_function", "scale_max_execution_time"), + Description: "Timeout in secs after which the function is terminated.", + }, + "scale_memory_limit": { + Type: schema.TypeString, + Optional: true, + Default: "4G", + ValidateFunc: validate.InvokeValidator("ibm_code_engine_function", "scale_memory_limit"), + Description: "Optional amount of memory set for the instance of the function. For valid values see [Supported memory and CPU combinations](https://cloud.ibm.com/docs/codeengine?topic=codeengine-mem-cpu-combo). The units for specifying memory are Megabyte (M) or Gigabyte (G), whereas G and M are the shorthand expressions for GB and MB. For more information see [Units of measurement](https://cloud.ibm.com/docs/codeengine?topic=codeengine-mem-cpu-combo#unit-measurements).", + }, + "created_at": { + Type: schema.TypeString, + Computed: true, + Description: "The timestamp when the resource was created.", + }, + "endpoint": { + Type: schema.TypeString, + Computed: true, + Description: "URL to invoke the function.", + }, + "endpoint_internal": { + Type: schema.TypeString, + Computed: true, + Description: "URL to function that is only visible within the project.", + }, + "entity_tag": { + Type: schema.TypeString, + Computed: true, + Description: "The version of the function instance, which is used to achieve optimistic locking.", + }, + "href": { + Type: schema.TypeString, + Computed: true, + Description: "When you provision a new function, a relative URL path is created identifying the location of the instance.", + }, + "function_id": { + Type: schema.TypeString, + Computed: true, + Description: "The identifier of the resource.", + }, + "region": { + Type: schema.TypeString, + Computed: true, + Description: "The region of the project the resource is located in. Possible values: 'au-syd', 'br-sao', 'ca-tor', 'eu-de', 'eu-gb', 'jp-osa', 'jp-tok', 'us-east', 'us-south'.", + }, + "resource_type": { + Type: schema.TypeString, + Computed: true, + Description: "The type of the function.", + }, + "status": { + Type: schema.TypeString, + Computed: true, + Description: "The current status of the function.", + }, + "status_details": { + Type: schema.TypeList, + Computed: true, + Description: "The detailed status of the function.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "reason": { + Type: schema.TypeString, + Computed: true, + Description: "Provides additional information about the status of the function.", + }, + }, + }, + }, + "etag": { + Type: schema.TypeString, + Computed: true, + }, + }, + } +} + +func ResourceIbmCodeEngineFunctionValidator() *validate.ResourceValidator { + validateSchema := make([]validate.ValidateSchema, 0) + validateSchema = append(validateSchema, + validate.ValidateSchema{ + Identifier: "project_id", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Required: true, + Regexp: `^[0-9a-z]{8}-[0-9a-z]{4}-[0-9a-z]{4}-[0-9a-z]{4}-[0-9a-z]{12}$`, + MinValueLength: 36, + MaxValueLength: 36, + }, + validate.ValidateSchema{ + Identifier: "code_main", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Optional: true, + Regexp: `^[a-zA-Z_][a-zA-Z0-9_]*$`, + MinValueLength: 1, + MaxValueLength: 63, + }, + validate.ValidateSchema{ + Identifier: "code_reference", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Required: true, + Regexp: `^([a-z0-9][a-z0-9\-_.]+[a-z0-9][\/])?([a-z0-9][a-z0-9\-_]+[a-z0-9][\/])?[a-z0-9][a-z0-9\-_.\/]+[a-z0-9](:[\w][\w.\-]{0,127})?(@sha256:[a-fA-F0-9]{64})?$|data:([-\w]+\/[-+\w.]+)?(;?\w+=[-\w]+)*;base64,.*`, + MinValueLength: 1, + MaxValueLength: 1048576, + }, + validate.ValidateSchema{ + Identifier: "code_secret", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Optional: true, + Regexp: `^[a-z0-9]([\-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([\-a-z0-9]*[a-z0-9])?)*$`, + MinValueLength: 1, + MaxValueLength: 253, + }, + validate.ValidateSchema{ + Identifier: "managed_domain_mappings", + ValidateFunctionIdentifier: validate.ValidateAllowedStringValue, + Type: validate.TypeString, + Optional: true, + AllowedValues: "local, local_private, local_public", + }, + validate.ValidateSchema{ + Identifier: "name", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Required: true, + Regexp: `^[a-z]([-a-z0-9]*[a-z0-9])?$`, + MinValueLength: 1, + MaxValueLength: 63, + }, + validate.ValidateSchema{ + Identifier: "runtime", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Required: true, + Regexp: `^[a-z]*\-[0-9]*(\.[0-9]*)?$`, + MinValueLength: 1, + MaxValueLength: 63, + }, + validate.ValidateSchema{ + Identifier: "scale_concurrency", + ValidateFunctionIdentifier: validate.IntBetween, + Type: validate.TypeInt, + Optional: true, + MinValue: "1", + MaxValue: "100", + }, + validate.ValidateSchema{ + Identifier: "scale_cpu_limit", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Optional: true, + Regexp: `^([0-9.]+)([eEinumkKMGTPB]*)$`, + MinValueLength: 0, + MaxValueLength: 10, + }, + validate.ValidateSchema{ + Identifier: "scale_down_delay", + ValidateFunctionIdentifier: validate.IntBetween, + Type: validate.TypeInt, + Optional: true, + MinValue: "0", + MaxValue: "600", + }, + validate.ValidateSchema{ + Identifier: "scale_max_execution_time", + ValidateFunctionIdentifier: validate.IntBetween, + Type: validate.TypeInt, + Optional: true, + MinValue: "1", + MaxValue: "120", + }, + validate.ValidateSchema{ + Identifier: "scale_memory_limit", + ValidateFunctionIdentifier: validate.ValidateRegexpLen, + Type: validate.TypeString, + Optional: true, + Regexp: `^([0-9.]+)([eEinumkKMGTPB]*)$`, + MinValueLength: 0, + MaxValueLength: 10, + }, + ) + + resourceValidator := validate.ResourceValidator{ResourceName: "ibm_code_engine_function", Schema: validateSchema} + return &resourceValidator +} + +func resourceIbmCodeEngineFunctionCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + codeEngineClient, err := meta.(conns.ClientSession).CodeEngineV2() + if err != nil { + tfErr := flex.TerraformErrorf(err, err.Error(), "ibm_code_engine_function", "create") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } + + createFunctionOptions := &codeenginev2.CreateFunctionOptions{} + + createFunctionOptions.SetProjectID(d.Get("project_id").(string)) + createFunctionOptions.SetCodeReference(d.Get("code_reference").(string)) + createFunctionOptions.SetName(d.Get("name").(string)) + createFunctionOptions.SetRuntime(d.Get("runtime").(string)) + if _, ok := d.GetOk("code_binary"); ok { + createFunctionOptions.SetCodeBinary(d.Get("code_binary").(bool)) + } + if _, ok := d.GetOk("code_main"); ok { + createFunctionOptions.SetCodeMain(d.Get("code_main").(string)) + } + if _, ok := d.GetOk("code_secret"); ok { + createFunctionOptions.SetCodeSecret(d.Get("code_secret").(string)) + } + if _, ok := d.GetOk("managed_domain_mappings"); ok { + createFunctionOptions.SetManagedDomainMappings(d.Get("managed_domain_mappings").(string)) + } + if _, ok := d.GetOk("run_env_variables"); ok { + var runEnvVariables []codeenginev2.EnvVarPrototype + for _, v := range d.Get("run_env_variables").([]interface{}) { + value := v.(map[string]interface{}) + runEnvVariablesItem, err := resourceIbmCodeEngineFunctionMapToEnvVarPrototype(value) + if err != nil { + return diag.FromErr(err) + } + runEnvVariables = append(runEnvVariables, *runEnvVariablesItem) + } + createFunctionOptions.SetRunEnvVariables(runEnvVariables) + } + if _, ok := d.GetOk("scale_concurrency"); ok { + createFunctionOptions.SetScaleConcurrency(int64(d.Get("scale_concurrency").(int))) + } + if _, ok := d.GetOk("scale_cpu_limit"); ok { + createFunctionOptions.SetScaleCpuLimit(d.Get("scale_cpu_limit").(string)) + } + if _, ok := d.GetOk("scale_down_delay"); ok { + createFunctionOptions.SetScaleDownDelay(int64(d.Get("scale_down_delay").(int))) + } + if _, ok := d.GetOk("scale_max_execution_time"); ok { + createFunctionOptions.SetScaleMaxExecutionTime(int64(d.Get("scale_max_execution_time").(int))) + } + if _, ok := d.GetOk("scale_memory_limit"); ok { + createFunctionOptions.SetScaleMemoryLimit(d.Get("scale_memory_limit").(string)) + } + + function, _, err := codeEngineClient.CreateFunctionWithContext(context, createFunctionOptions) + if err != nil { + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("CreateFunctionWithContext failed: %s", err.Error()), "ibm_code_engine_function", "create") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } + + d.SetId(fmt.Sprintf("%s/%s", *createFunctionOptions.ProjectID, *function.Name)) + + _, err = waitForIbmCodeEngineFunctionCreate(d, meta) + if err != nil { + errMsg := fmt.Sprintf("Error waiting for resource IbmCodeEngineFunction (%s) to be created: %s", d.Id(), err) + tfErr := flex.TerraformErrorf(err, errMsg, "ibm_code_engine_function", "create") + return tfErr.GetDiag() + } + + return resourceIbmCodeEngineFunctionRead(context, d, meta) +} + +func waitForIbmCodeEngineFunctionCreate(d *schema.ResourceData, meta interface{}) (interface{}, error) { + codeEngineClient, err := meta.(conns.ClientSession).CodeEngineV2() + if err != nil { + return false, err + } + getFunctionOptions := &codeenginev2.GetFunctionOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + return false, err + } + + getFunctionOptions.SetProjectID(parts[0]) + getFunctionOptions.SetName(parts[1]) + + stateConf := &resource.StateChangeConf{ + Pending: []string{"deploying"}, + Target: []string{"ready", "failed", "offline"}, + Refresh: func() (interface{}, string, error) { + stateObj, response, err := codeEngineClient.GetFunction(getFunctionOptions) + if err != nil { + if sdkErr, ok := err.(*core.SDKProblem); ok && response.GetStatusCode() == 404 { + sdkErr.Summary = fmt.Sprintf("The instance %s does not exist anymore: %s", "getFunctionOptions", err) + return nil, "", sdkErr + } + return nil, "", err + } + failStates := map[string]bool{"failure": true, "failed": true} + if failStates[*stateObj.Status] { + return stateObj, *stateObj.Status, fmt.Errorf("the instance %s failed: %s", "getFunctionOptions", err) + } + return stateObj, *stateObj.Status, nil + }, + Timeout: d.Timeout(schema.TimeoutCreate), + Delay: 60 * time.Second, + MinTimeout: 60 * time.Second, + } + + return stateConf.WaitForState() +} + +func resourceIbmCodeEngineFunctionRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + codeEngineClient, err := meta.(conns.ClientSession).CodeEngineV2() + if err != nil { + tfErr := flex.TerraformErrorf(err, err.Error(), "ibm_code_engine_function", "read") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } + + getFunctionOptions := &codeenginev2.GetFunctionOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + tfErr := flex.TerraformErrorf(err, err.Error(), "ibm_code_engine_function", "read") + return tfErr.GetDiag() + } + + getFunctionOptions.SetProjectID(parts[0]) + getFunctionOptions.SetName(parts[1]) + + function, response, err := codeEngineClient.GetFunctionWithContext(context, getFunctionOptions) + if err != nil { + if response != nil && response.StatusCode == 404 { + d.SetId("") + return nil + } + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("GetFunctionWithContext failed: %s", err.Error()), "ibm_code_engine_function", "read") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } + + if err = d.Set("project_id", function.ProjectID); err != nil { + return diag.FromErr(fmt.Errorf("error setting project_id: %s", err)) + } + if !core.IsNil(function.CodeBinary) { + if err = d.Set("code_binary", function.CodeBinary); err != nil { + return diag.FromErr(fmt.Errorf("error setting code_binary: %s", err)) + } + } + if !core.IsNil(function.CodeMain) { + if err = d.Set("code_main", function.CodeMain); err != nil { + return diag.FromErr(fmt.Errorf("error setting code_main: %s", err)) + } + } + if err = d.Set("code_reference", function.CodeReference); err != nil { + return diag.FromErr(fmt.Errorf("error setting code_reference: %s", err)) + } + if !core.IsNil(function.CodeSecret) { + if err = d.Set("code_secret", function.CodeSecret); err != nil { + return diag.FromErr(fmt.Errorf("error setting code_secret: %s", err)) + } + } + if !core.IsNil(function.ManagedDomainMappings) { + if err = d.Set("managed_domain_mappings", function.ManagedDomainMappings); err != nil { + return diag.FromErr(fmt.Errorf("error setting managed_domain_mappings: %s", err)) + } + } + if err = d.Set("name", function.Name); err != nil { + return diag.FromErr(fmt.Errorf("error setting name: %s", err)) + } + if !core.IsNil(function.RunEnvVariables) { + runEnvVariables := []map[string]interface{}{} + for _, runEnvVariablesItem := range function.RunEnvVariables { + runEnvVariablesItemMap, err := resourceIbmCodeEngineFunctionEnvVarToMap(&runEnvVariablesItem) /* #nosec G601 */ + if err != nil { + return diag.FromErr(err) + } + runEnvVariables = append(runEnvVariables, runEnvVariablesItemMap) + } + if err = d.Set("run_env_variables", runEnvVariables); err != nil { + return diag.FromErr(fmt.Errorf("error setting run_env_variables: %s", err)) + } + } + if err = d.Set("runtime", function.Runtime); err != nil { + return diag.FromErr(fmt.Errorf("error setting runtime: %s", err)) + } + if !core.IsNil(function.ScaleConcurrency) { + if err = d.Set("scale_concurrency", flex.IntValue(function.ScaleConcurrency)); err != nil { + return diag.FromErr(fmt.Errorf("error setting scale_concurrency: %s", err)) + } + } + if !core.IsNil(function.ScaleCpuLimit) { + if err = d.Set("scale_cpu_limit", function.ScaleCpuLimit); err != nil { + return diag.FromErr(fmt.Errorf("error setting scale_cpu_limit: %s", err)) + } + } + if !core.IsNil(function.ScaleDownDelay) { + if err = d.Set("scale_down_delay", flex.IntValue(function.ScaleDownDelay)); err != nil { + return diag.FromErr(fmt.Errorf("error setting scale_down_delay: %s", err)) + } + } + if !core.IsNil(function.ScaleMaxExecutionTime) { + if err = d.Set("scale_max_execution_time", flex.IntValue(function.ScaleMaxExecutionTime)); err != nil { + return diag.FromErr(fmt.Errorf("error setting scale_max_execution_time: %s", err)) + } + } + if !core.IsNil(function.ScaleMemoryLimit) { + if err = d.Set("scale_memory_limit", function.ScaleMemoryLimit); err != nil { + return diag.FromErr(fmt.Errorf("error setting scale_memory_limit: %s", err)) + } + } + if !core.IsNil(function.CreatedAt) { + if err = d.Set("created_at", function.CreatedAt); err != nil { + return diag.FromErr(fmt.Errorf("error setting created_at: %s", err)) + } + } + if !core.IsNil(function.Endpoint) { + if err = d.Set("endpoint", function.Endpoint); err != nil { + return diag.FromErr(fmt.Errorf("error setting endpoint: %s", err)) + } + } + if !core.IsNil(function.EndpointInternal) { + if err = d.Set("endpoint_internal", function.EndpointInternal); err != nil { + return diag.FromErr(fmt.Errorf("error setting endpoint_internal: %s", err)) + } + } + if err = d.Set("entity_tag", function.EntityTag); err != nil { + return diag.FromErr(fmt.Errorf("error setting entity_tag: %s", err)) + } + if !core.IsNil(function.Href) { + if err = d.Set("href", function.Href); err != nil { + return diag.FromErr(fmt.Errorf("error setting href: %s", err)) + } + } + if !core.IsNil(function.ID) { + if err = d.Set("function_id", function.ID); err != nil { + return diag.FromErr(fmt.Errorf("error setting function_id: %s", err)) + } + } + if !core.IsNil(function.Region) { + if err = d.Set("region", function.Region); err != nil { + return diag.FromErr(fmt.Errorf("error setting region: %s", err)) + } + } + if !core.IsNil(function.ResourceType) { + if err = d.Set("resource_type", function.ResourceType); err != nil { + return diag.FromErr(fmt.Errorf("error setting resource_type: %s", err)) + } + } + if !core.IsNil(function.Status) { + if err = d.Set("status", function.Status); err != nil { + return diag.FromErr(fmt.Errorf("error setting status: %s", err)) + } + } + statusDetailsMap, err := resourceIbmCodeEngineFunctionFunctionStatusToMap(function.StatusDetails) + if err != nil { + return diag.FromErr(err) + } + if err = d.Set("status_details", []map[string]interface{}{statusDetailsMap}); err != nil { + return diag.FromErr(fmt.Errorf("error setting status_details: %s", err)) + } + if err = d.Set("etag", response.Headers.Get("Etag")); err != nil { + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("Error setting etag: %s", err), "ibm_code_engine_function", "read") + return tfErr.GetDiag() + } + + return nil +} + +func resourceIbmCodeEngineFunctionUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + codeEngineClient, err := meta.(conns.ClientSession).CodeEngineV2() + if err != nil { + tfErr := flex.TerraformErrorf(err, err.Error(), "ibm_code_engine_function", "update") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } + + updateFunctionOptions := &codeenginev2.UpdateFunctionOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + tfErr := flex.TerraformErrorf(err, err.Error(), "ibm_code_engine_function", "update") + return tfErr.GetDiag() + } + + updateFunctionOptions.SetProjectID(parts[0]) + updateFunctionOptions.SetName(parts[1]) + + hasChange := false + + patchVals := &codeenginev2.FunctionPatch{} + if d.HasChange("code_binary") { + newCodeBinary := d.Get("code_binary").(bool) + patchVals.CodeBinary = &newCodeBinary + hasChange = true + } + if d.HasChange("code_main") { + newCodeMain := d.Get("code_main").(string) + patchVals.CodeMain = &newCodeMain + hasChange = true + } + if d.HasChange("code_reference") { + newCodeReference := d.Get("code_reference").(string) + patchVals.CodeReference = &newCodeReference + hasChange = true + } + if d.HasChange("code_secret") { + newCodeSecret := d.Get("code_secret").(string) + patchVals.CodeSecret = &newCodeSecret + hasChange = true + } + if d.HasChange("managed_domain_mappings") { + newManagedDomainMappings := d.Get("managed_domain_mappings").(string) + patchVals.ManagedDomainMappings = &newManagedDomainMappings + hasChange = true + } + if d.HasChange("run_env_variables") { + var runEnvVariables []codeenginev2.EnvVarPrototype + for _, v := range d.Get("run_env_variables").([]interface{}) { + value := v.(map[string]interface{}) + runEnvVariablesItem, err := resourceIbmCodeEngineFunctionMapToEnvVarPrototype(value) + if err != nil { + return diag.FromErr(err) + } + runEnvVariables = append(runEnvVariables, *runEnvVariablesItem) + } + patchVals.RunEnvVariables = runEnvVariables + hasChange = true + } + if d.HasChange("runtime") { + newRuntime := d.Get("runtime").(string) + patchVals.Runtime = &newRuntime + hasChange = true + } + if d.HasChange("scale_concurrency") { + newScaleConcurrency := int64(d.Get("scale_concurrency").(int)) + patchVals.ScaleConcurrency = &newScaleConcurrency + hasChange = true + } + if d.HasChange("scale_cpu_limit") { + newScaleCpuLimit := d.Get("scale_cpu_limit").(string) + patchVals.ScaleCpuLimit = &newScaleCpuLimit + hasChange = true + } + if d.HasChange("scale_down_delay") { + newScaleDownDelay := int64(d.Get("scale_down_delay").(int)) + patchVals.ScaleDownDelay = &newScaleDownDelay + hasChange = true + } + if d.HasChange("scale_max_execution_time") { + newScaleMaxExecutionTime := int64(d.Get("scale_max_execution_time").(int)) + patchVals.ScaleMaxExecutionTime = &newScaleMaxExecutionTime + hasChange = true + } + if d.HasChange("scale_memory_limit") { + newScaleMemoryLimit := d.Get("scale_memory_limit").(string) + patchVals.ScaleMemoryLimit = &newScaleMemoryLimit + hasChange = true + } + updateFunctionOptions.SetIfMatch(d.Get("etag").(string)) + + if hasChange { + updateFunctionOptions.Function, _ = patchVals.AsPatch() + + // Fields with `nil` values are omitted from the generic map, + // so we need to re-add them to support removing arguments. + if _, exists := d.GetOk("code_binary"); d.HasChange("code_binary") && !exists { + updateFunctionOptions.Function["code_binary"] = nil + } + if _, exists := d.GetOk("code_main"); d.HasChange("code_main") && !exists { + updateFunctionOptions.Function["code_main"] = nil + } + if _, exists := d.GetOk("code_reference"); d.HasChange("code_reference") && !exists { + updateFunctionOptions.Function["code_reference"] = nil + } + if _, exists := d.GetOk("code_secret"); d.HasChange("code_secret") && !exists { + updateFunctionOptions.Function["code_secret"] = nil + } + if _, exists := d.GetOk("managed_domain_mappings"); d.HasChange("managed_domain_mappings") && !exists { + updateFunctionOptions.Function["managed_domain_mappings"] = nil + } + if _, exists := d.GetOk("run_env_variables"); d.HasChange("run_env_variables") && !exists { + updateFunctionOptions.Function["run_env_variables"] = nil + } + if _, exists := d.GetOk("runtime"); d.HasChange("runtime") && !exists { + updateFunctionOptions.Function["runtime"] = nil + } + if _, exists := d.GetOk("scale_concurrency"); d.HasChange("scale_concurrency") && !exists { + updateFunctionOptions.Function["scale_concurrency"] = nil + } + if _, exists := d.GetOk("scale_cpu_limit"); d.HasChange("scale_cpu_limit") && !exists { + updateFunctionOptions.Function["scale_cpu_limit"] = nil + } + if _, exists := d.GetOk("scale_down_delay"); d.HasChange("scale_down_delay") && !exists { + updateFunctionOptions.Function["scale_down_delay"] = nil + } + if _, exists := d.GetOk("scale_max_execution_time"); d.HasChange("scale_max_execution_time") && !exists { + updateFunctionOptions.Function["scale_max_execution_time"] = nil + } + if _, exists := d.GetOk("scale_memory_limit"); d.HasChange("scale_memory_limit") && !exists { + updateFunctionOptions.Function["scale_memory_limit"] = nil + } + + _, _, err = codeEngineClient.UpdateFunctionWithContext(context, updateFunctionOptions) + if err != nil { + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("UpdateFunctionWithContext failed: %s", err.Error()), "ibm_code_engine_function", "update") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } + } + + return resourceIbmCodeEngineFunctionRead(context, d, meta) +} + +func resourceIbmCodeEngineFunctionDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + codeEngineClient, err := meta.(conns.ClientSession).CodeEngineV2() + if err != nil { + tfErr := flex.TerraformErrorf(err, err.Error(), "ibm_code_engine_function", "delete") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } + + deleteFunctionOptions := &codeenginev2.DeleteFunctionOptions{} + + parts, err := flex.SepIdParts(d.Id(), "/") + if err != nil { + tfErr := flex.TerraformErrorf(err, err.Error(), "ibm_code_engine_function", "delete") + return tfErr.GetDiag() + } + + deleteFunctionOptions.SetProjectID(parts[0]) + deleteFunctionOptions.SetName(parts[1]) + + _, err = codeEngineClient.DeleteFunctionWithContext(context, deleteFunctionOptions) + if err != nil { + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("DeleteFunctionWithContext failed: %s", err.Error()), "ibm_code_engine_function", "delete") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } + + d.SetId("") + + return nil +} + +func resourceIbmCodeEngineFunctionMapToEnvVarPrototype(modelMap map[string]interface{}) (*codeenginev2.EnvVarPrototype, error) { + model := &codeenginev2.EnvVarPrototype{} + if modelMap["key"] != nil && modelMap["key"].(string) != "" { + model.Key = core.StringPtr(modelMap["key"].(string)) + } + if modelMap["name"] != nil && modelMap["name"].(string) != "" { + model.Name = core.StringPtr(modelMap["name"].(string)) + } + if modelMap["prefix"] != nil && modelMap["prefix"].(string) != "" { + model.Prefix = core.StringPtr(modelMap["prefix"].(string)) + } + if modelMap["reference"] != nil && modelMap["reference"].(string) != "" { + model.Reference = core.StringPtr(modelMap["reference"].(string)) + } + if modelMap["type"] != nil && modelMap["type"].(string) != "" { + model.Type = core.StringPtr(modelMap["type"].(string)) + } + if modelMap["value"] != nil && modelMap["value"].(string) != "" { + model.Value = core.StringPtr(modelMap["value"].(string)) + } + return model, nil +} + +func resourceIbmCodeEngineFunctionEnvVarToMap(model *codeenginev2.EnvVar) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Key != nil { + modelMap["key"] = *model.Key + } + if model.Name != nil { + modelMap["name"] = *model.Name + } + if model.Prefix != nil { + modelMap["prefix"] = *model.Prefix + } + if model.Reference != nil { + modelMap["reference"] = *model.Reference + } + modelMap["type"] = *model.Type + if model.Value != nil { + modelMap["value"] = *model.Value + } + return modelMap, nil +} + +func resourceIbmCodeEngineFunctionFunctionStatusToMap(model *codeenginev2.FunctionStatus) (map[string]interface{}, error) { + modelMap := make(map[string]interface{}) + if model.Reason != nil { + modelMap["reason"] = *model.Reason + } + return modelMap, nil +} diff --git a/ibm/service/codeengine/resource_ibm_code_engine_function_test.go b/ibm/service/codeengine/resource_ibm_code_engine_function_test.go new file mode 100644 index 00000000000..71101397077 --- /dev/null +++ b/ibm/service/codeengine/resource_ibm_code_engine_function_test.go @@ -0,0 +1,251 @@ +// Copyright IBM Corp. 2024 All Rights Reserved. +// Licensed under the Mozilla Public License v2.0 + +package codeengine_test + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + + 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/code-engine-go-sdk/codeenginev2" +) + +func TestAccIbmCodeEngineFunctionBasic(t *testing.T) { + var conf codeenginev2.Function + functionName := fmt.Sprintf("%s", acctest.RandStringFromCharSet(10, acctest.CharSetAlpha)) + functionRuntime := "nodejs-20" + functionCodeReference := "data:text/plain;base64,foo" + + projectID := acc.CeProjectId + + functionCodeReferenceUpdate := "data:text/plain;base64,bar" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIbmCodeEngineFunctionDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIbmCodeEngineFunctionConfigBasic(projectID, functionCodeReference, functionName, functionRuntime), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIbmCodeEngineFunctionExists("ibm_code_engine_function.code_engine_function_instance", conf), + resource.TestCheckResourceAttr("ibm_code_engine_function.code_engine_function_instance", "project_id", projectID), + resource.TestCheckResourceAttr("ibm_code_engine_function.code_engine_function_instance", "name", functionName), + resource.TestCheckResourceAttr("ibm_code_engine_function.code_engine_function_instance", "runtime", functionRuntime), + resource.TestCheckResourceAttr("ibm_code_engine_function.code_engine_function_instance", "code_binary", "false"), + resource.TestCheckResourceAttr("ibm_code_engine_function.code_engine_function_instance", "code_reference", functionCodeReference), + resource.TestCheckResourceAttr("ibm_code_engine_function.code_engine_function_instance", "managed_domain_mappings", "local_public"), + resource.TestCheckResourceAttr("ibm_code_engine_function.code_engine_function_instance", "scale_concurrency", "1"), + resource.TestCheckResourceAttr("ibm_code_engine_function.code_engine_function_instance", "scale_cpu_limit", "1"), + resource.TestCheckResourceAttr("ibm_code_engine_function.code_engine_function_instance", "scale_down_delay", "1"), + resource.TestCheckResourceAttr("ibm_code_engine_function.code_engine_function_instance", "scale_max_execution_time", "60"), + resource.TestCheckResourceAttr("ibm_code_engine_function.code_engine_function_instance", "scale_memory_limit", "4G"), + ), + }, + resource.TestStep{ + Config: testAccCheckIbmCodeEngineFunctionConfigBasic(projectID, functionCodeReferenceUpdate, functionName, functionRuntime), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("ibm_code_engine_function.code_engine_function_instance", "project_id", projectID), + resource.TestCheckResourceAttr("ibm_code_engine_function.code_engine_function_instance", "name", functionName), + resource.TestCheckResourceAttr("ibm_code_engine_function.code_engine_function_instance", "runtime", functionRuntime), + resource.TestCheckResourceAttr("ibm_code_engine_function.code_engine_function_instance", "code_binary", "false"), + resource.TestCheckResourceAttr("ibm_code_engine_function.code_engine_function_instance", "code_reference", functionCodeReferenceUpdate), + resource.TestCheckResourceAttr("ibm_code_engine_function.code_engine_function_instance", "managed_domain_mappings", "local_public"), + resource.TestCheckResourceAttr("ibm_code_engine_function.code_engine_function_instance", "scale_concurrency", "1"), + resource.TestCheckResourceAttr("ibm_code_engine_function.code_engine_function_instance", "scale_cpu_limit", "1"), + resource.TestCheckResourceAttr("ibm_code_engine_function.code_engine_function_instance", "scale_down_delay", "1"), + resource.TestCheckResourceAttr("ibm_code_engine_function.code_engine_function_instance", "scale_max_execution_time", "60"), + resource.TestCheckResourceAttr("ibm_code_engine_function.code_engine_function_instance", "scale_memory_limit", "4G"), + ), + }, + }, + }) +} + +func TestAccIbmCodeEngineFunctionExtended(t *testing.T) { + var conf codeenginev2.Function + + functionName := fmt.Sprintf("%s", acctest.RandStringFromCharSet(10, acctest.CharSetAlpha)) + functionRuntime := "nodejs-20" + functionCodeReference := "data:text/plain;base64,foo" + functionManagedDomainMappings := "local_public" + functionScaleCpuLimit := "1" + functionScaleDownDelay := "1" + functionScaleMaxExecutionTime := "60" + functionScaleMemoryLimit := "4G" + + projectID := acc.CeProjectId + + functionCodeReferenceUpdate := "data:text/plain;base64,bar" + functionManagedDomainMappingsUpdate := "local_private" + functionScaleCpuLimitUpdate := "0.5" + functionScaleDownDelayUpdate := "20" + functionScaleMaxExecutionTimeUpdate := "30" + functionScaleMemoryLimitUpdate := "2G" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIbmCodeEngineFunctionDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckIbmCodeEngineFunctionConfig(projectID, functionCodeReference, functionManagedDomainMappings, functionName, functionRuntime, functionScaleCpuLimit, functionScaleDownDelay, functionScaleMaxExecutionTime, functionScaleMemoryLimit), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIbmCodeEngineFunctionExists("ibm_code_engine_function.code_engine_function_instance", conf), + resource.TestCheckResourceAttr("ibm_code_engine_function.code_engine_function_instance", "project_id", projectID), + resource.TestCheckResourceAttr("ibm_code_engine_function.code_engine_function_instance", "name", functionName), + resource.TestCheckResourceAttr("ibm_code_engine_function.code_engine_function_instance", "runtime", functionRuntime), + resource.TestCheckResourceAttr("ibm_code_engine_function.code_engine_function_instance", "code_binary", "false"), + resource.TestCheckResourceAttr("ibm_code_engine_function.code_engine_function_instance", "code_reference", functionCodeReference), + resource.TestCheckResourceAttr("ibm_code_engine_function.code_engine_function_instance", "managed_domain_mappings", functionManagedDomainMappings), + resource.TestCheckResourceAttr("ibm_code_engine_function.code_engine_function_instance", "scale_concurrency", "1"), + resource.TestCheckResourceAttr("ibm_code_engine_function.code_engine_function_instance", "scale_cpu_limit", functionScaleCpuLimit), + resource.TestCheckResourceAttr("ibm_code_engine_function.code_engine_function_instance", "scale_down_delay", functionScaleDownDelay), + resource.TestCheckResourceAttr("ibm_code_engine_function.code_engine_function_instance", "scale_max_execution_time", functionScaleMaxExecutionTime), + resource.TestCheckResourceAttr("ibm_code_engine_function.code_engine_function_instance", "scale_memory_limit", functionScaleMemoryLimit), + ), + }, + resource.TestStep{ + Config: testAccCheckIbmCodeEngineFunctionConfig(projectID, functionCodeReferenceUpdate, functionManagedDomainMappingsUpdate, functionName, functionRuntime, functionScaleCpuLimitUpdate, functionScaleDownDelayUpdate, functionScaleMaxExecutionTimeUpdate, functionScaleMemoryLimitUpdate), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("ibm_code_engine_function.code_engine_function_instance", "project_id", projectID), + resource.TestCheckResourceAttr("ibm_code_engine_function.code_engine_function_instance", "name", functionName), + resource.TestCheckResourceAttr("ibm_code_engine_function.code_engine_function_instance", "runtime", functionRuntime), + resource.TestCheckResourceAttr("ibm_code_engine_function.code_engine_function_instance", "code_binary", "false"), + resource.TestCheckResourceAttr("ibm_code_engine_function.code_engine_function_instance", "code_reference", functionCodeReferenceUpdate), + resource.TestCheckResourceAttr("ibm_code_engine_function.code_engine_function_instance", "managed_domain_mappings", functionManagedDomainMappingsUpdate), + resource.TestCheckResourceAttr("ibm_code_engine_function.code_engine_function_instance", "scale_concurrency", "1"), + resource.TestCheckResourceAttr("ibm_code_engine_function.code_engine_function_instance", "scale_cpu_limit", functionScaleCpuLimitUpdate), + resource.TestCheckResourceAttr("ibm_code_engine_function.code_engine_function_instance", "scale_down_delay", functionScaleDownDelayUpdate), + resource.TestCheckResourceAttr("ibm_code_engine_function.code_engine_function_instance", "scale_max_execution_time", functionScaleMaxExecutionTimeUpdate), + resource.TestCheckResourceAttr("ibm_code_engine_function.code_engine_function_instance", "scale_memory_limit", functionScaleMemoryLimitUpdate), + ), + }, + }, + }) +} + +func testAccCheckIbmCodeEngineFunctionConfigBasic(projectID string, codeReference string, name string, runtime string) string { + return fmt.Sprintf(` + data "ibm_code_engine_project" "code_engine_project_instance" { + project_id = "%s" + } + + resource "ibm_code_engine_function" "code_engine_function_instance" { + project_id = data.ibm_code_engine_project.code_engine_project_instance.project_id + code_reference = "%s" + name = "%s" + runtime = "%s" + + lifecycle { + ignore_changes = [ + run_env_variables + ] + } + } + `, projectID, codeReference, name, runtime) +} + +func testAccCheckIbmCodeEngineFunctionConfig(projectID string, codeReference string, managedDomainMappings string, name string, runtime string, scaleCpuLimit string, scaleDownDelay string, scaleMaxExecutionTime string, scaleMemoryLimit string) string { + return fmt.Sprintf(` + data "ibm_code_engine_project" "code_engine_project_instance" { + project_id = "%s" + } + + resource "ibm_code_engine_function" "code_engine_function_instance" { + project_id = data.ibm_code_engine_project.code_engine_project_instance.project_id + code_reference = "%s" + managed_domain_mappings = "%s" + name = "%s" + runtime = "%s" + scale_cpu_limit = "%s" + scale_down_delay = %s + scale_max_execution_time = %s + scale_memory_limit = "%s" + run_env_variables { + type = "literal" + name = "name" + value = "value" + } + + lifecycle { + ignore_changes = [ + run_env_variables + ] + } + } + `, projectID, codeReference, managedDomainMappings, name, runtime, scaleCpuLimit, scaleDownDelay, scaleMaxExecutionTime, scaleMemoryLimit) +} + +func testAccCheckIbmCodeEngineFunctionExists(n string, obj codeenginev2.Function) resource.TestCheckFunc { + + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + codeEngineClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).CodeEngineV2() + if err != nil { + return err + } + + getFunctionOptions := &codeenginev2.GetFunctionOptions{} + + parts, err := flex.SepIdParts(rs.Primary.ID, "/") + if err != nil { + return err + } + + getFunctionOptions.SetProjectID(parts[0]) + getFunctionOptions.SetName(parts[1]) + + function, _, err := codeEngineClient.GetFunction(getFunctionOptions) + if err != nil { + return err + } + + obj = *function + return nil + } +} + +func testAccCheckIbmCodeEngineFunctionDestroy(s *terraform.State) error { + codeEngineClient, err := acc.TestAccProvider.Meta().(conns.ClientSession).CodeEngineV2() + if err != nil { + return err + } + for _, rs := range s.RootModule().Resources { + if rs.Type != "ibm_code_engine_function" { + continue + } + + getFunctionOptions := &codeenginev2.GetFunctionOptions{} + + parts, err := flex.SepIdParts(rs.Primary.ID, "/") + if err != nil { + return err + } + + getFunctionOptions.SetProjectID(parts[0]) + getFunctionOptions.SetName(parts[1]) + + // Try to find the key + _, response, err := codeEngineClient.GetFunction(getFunctionOptions) + + if err == nil { + return fmt.Errorf("code_engine_function still exists: %s", rs.Primary.ID) + } else if response.StatusCode != 404 { + return fmt.Errorf("Error checking for code_engine_function (%s) has been destroyed: %s", rs.Primary.ID, err) + } + } + + return nil +} diff --git a/website/docs/d/code_engine_function.html.markdown b/website/docs/d/code_engine_function.html.markdown new file mode 100644 index 00000000000..350dbb3fdd1 --- /dev/null +++ b/website/docs/d/code_engine_function.html.markdown @@ -0,0 +1,114 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_code_engine_function" +description: |- + Get information about code_engine_function +subcategory: "Code Engine" +--- + +# ibm_code_engine_function + +Provides a read-only data source to retrieve information about a code_engine_function. You can then reference the fields of the data source in other resources within the same configuration by using interpolation syntax. + +## Example Usage + +```hcl +data "ibm_code_engine_function" "code_engine_function" { + name = ibm_code_engine_function.code_engine_function_instance.name + project_id = ibm_code_engine_function.code_engine_function_instance.project_id +} +``` + +## Argument Reference + +You can specify the following arguments for this data source. + +* `name` - (Required, Forces new resource, String) The name of your function. + * Constraints: The maximum length is `63` characters. The minimum length is `1` character. The value must match regular expression `/^[a-z]([-a-z0-9]*[a-z0-9])?$/`. +* `project_id` - (Required, Forces new resource, String) The ID of the project. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[0-9a-z]{8}-[0-9a-z]{4}-[0-9a-z]{4}-[0-9a-z]{4}-[0-9a-z]{12}$/`. + +## Attribute Reference + +After your data source is created, you can read values from the following attributes. + +* `id` - The unique identifier of the code_engine_function. + +* `function_id` - (String) The identifier of the resource. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[0-9a-z]{8}-[0-9a-z]{4}-[0-9a-z]{4}-[0-9a-z]{4}-[0-9a-z]{12}$/`. + +* `code_binary` - (Boolean) Specifies whether the code is binary or not. Defaults to false when `code_reference` is set to a data URL. When `code_reference` is set to a code bundle URL, this field is always true. + +* `code_main` - (String) Specifies the name of the function that should be invoked. + * Constraints: The default value is `main`. The maximum length is `63` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z_][a-zA-Z0-9_]*$/`. + +* `code_reference` - (String) Specifies either a reference to a code bundle or the source code itself. To specify the source code, use the data URL scheme and include the source code as base64 encoded. The data URL scheme is defined in [RFC 2397](https://tools.ietf.org/html/rfc2397). + * Constraints: The maximum length is `1048576` characters. The minimum length is `1` character. The value must match regular expression `/^([a-z0-9][a-z0-9\\-_.]+[a-z0-9][\/])?([a-z0-9][a-z0-9\\-_]+[a-z0-9][\/])?[a-z0-9][a-z0-9\\-_.\/]+[a-z0-9](:[\\w][\\w.\\-]{0,127})?(@sha256:[a-fA-F0-9]{64})?$|data:([-\\w]+\/[-+\\w.]+)?(;?\\w+=[-\\w]+)*;base64,.*/`. + +* `code_secret` - (String) The name of the secret that is used to access the specified `code_reference`. The secret is used to authenticate with a non-public endpoint that is specified as`code_reference`. + * Constraints: The maximum length is `253` characters. The minimum length is `1` character. The value must match regular expression `/^[a-z0-9]([\\-a-z0-9]*[a-z0-9])?(\\.[a-z0-9]([\\-a-z0-9]*[a-z0-9])?)*$/`. + +* `created_at` - (String) The timestamp when the resource was created. + +* `endpoint` - (String) URL to invoke the function. + * Constraints: The maximum length is `2048` characters. The minimum length is `0` characters. The value must match regular expression `/(([^:\/?#]+):)?(\/\/([^\/?#]*))?([^?#]*)(\\?([^#]*))?(#(.*))?$/`. + +* `endpoint_internal` - (String) URL to function that is only visible within the project. + * Constraints: The maximum length is `2048` characters. The minimum length is `0` characters. The value must match regular expression `/(([^:\/?#]+):)?(\/\/([^\/?#]*))?([^?#]*)(\\?([^#]*))?(#(.*))?$/`. + +* `entity_tag` - (String) The version of the function instance, which is used to achieve optimistic locking. + * Constraints: The maximum length is `63` characters. The minimum length is `1` character. The value must match regular expression `/^[\\*\\-a-z0-9]+$/`. + +* `href` - (String) When you provision a new function, a relative URL path is created identifying the location of the instance. + * Constraints: The maximum length is `2048` characters. The minimum length is `0` characters. The value must match regular expression `/(([^:\/?#]+):)?(\/\/([^\/?#]*))?([^?#]*)(\\?([^#]*))?(#(.*))?$/`. + +* `managed_domain_mappings` - (String) Optional value controlling which of the system managed domain mappings will be setup for the function. Valid values are 'local_public', 'local_private' and 'local'. Visibility can only be 'local_private' if the project supports function private visibility. + * Constraints: The default value is `local_public`. Allowable values are: `local`, `local_private`, `local_public`. + +* `region` - (String) The region of the project the resource is located in. Possible values: 'au-syd', 'br-sao', 'ca-tor', 'eu-de', 'eu-gb', 'jp-osa', 'jp-tok', 'us-east', 'us-south'. + +* `resource_type` - (String) The type of the function. + * Constraints: Allowable values are: `function_v2`. + +* `run_env_variables` - (List) References to config maps, secrets or literal values, which are defined by the function owner and are exposed as environment variables in the function. + * Constraints: The maximum length is `100` items. The minimum length is `0` items. +Nested schema for **run_env_variables**: + * `key` - (String) The key to reference as environment variable. + * Constraints: The maximum length is `253` characters. The minimum length is `1` character. The value must match regular expression `/^[\\-._a-zA-Z0-9]+$/`. + * `name` - (String) The name of the environment variable. + * Constraints: The maximum length is `253` characters. The minimum length is `1` character. The value must match regular expression `/^[\\-._a-zA-Z0-9]+$/`. + * `prefix` - (String) A prefix that can be added to all keys of a full secret or config map reference. + * Constraints: The maximum length is `253` characters. The minimum length is `0` characters. The value must match regular expression `/^[a-zA-Z_][a-zA-Z0-9_]*$/`. + * `reference` - (String) The name of the secret or config map. + * Constraints: The maximum length is `253` characters. The minimum length is `1` character. The value must match regular expression `/^[a-z0-9]([\\-a-z0-9]*[a-z0-9])?(\\.[a-z0-9]([\\-a-z0-9]*[a-z0-9])?)*$/`. + * `type` - (String) Specify the type of the environment variable. + * Constraints: The default value is `literal`. Allowable values are: `literal`, `config_map_full_reference`, `secret_full_reference`, `config_map_key_reference`, `secret_key_reference`. The value must match regular expression `/^(literal|config_map_full_reference|secret_full_reference|config_map_key_reference|secret_key_reference)$/`. + * `value` - (String) The literal value of the environment variable. + * Constraints: The maximum length is `253` characters. The minimum length is `1` character. The value must match regular expression `/^[\\-._a-zA-Z0-9]+$/`. + +* `runtime` - (String) The managed runtime used to execute the injected code. + * Constraints: The maximum length is `63` characters. The minimum length is `1` character. The value must match regular expression `/^[a-z]*\\-[0-9]*(\\.[0-9]*)?$/`. + +* `scale_concurrency` - (Integer) Number of parallel requests handled by a single instance, supported only by Node.js, default is `1`. + * Constraints: The default value is `1`. The maximum value is `100`. The minimum value is `1`. + +* `scale_cpu_limit` - (String) Optional amount of CPU set for the instance of the function. For valid values see [Supported memory and CPU combinations](https://cloud.ibm.com/docs/codeengine?topic=codeengine-mem-cpu-combo). + * Constraints: The default value is `1`. The maximum length is `10` characters. The minimum length is `0` characters. The value must match regular expression `/^([0-9.]+)([eEinumkKMGTPB]*)$/`. + +* `scale_down_delay` - (Integer) Optional amount of time in seconds that delays the scale down behavior for a function. + * Constraints: The default value is `1`. The maximum value is `600`. The minimum value is `0`. + +* `scale_max_execution_time` - (Integer) Timeout in secs after which the function is terminated. + * Constraints: The default value is `60`. The maximum value is `120`. The minimum value is `1`. + +* `scale_memory_limit` - (String) Optional amount of memory set for the instance of the function. For valid values see [Supported memory and CPU combinations](https://cloud.ibm.com/docs/codeengine?topic=codeengine-mem-cpu-combo). The units for specifying memory are Megabyte (M) or Gigabyte (G), whereas G and M are the shorthand expressions for GB and MB. For more information see [Units of measurement](https://cloud.ibm.com/docs/codeengine?topic=codeengine-mem-cpu-combo#unit-measurements). + * Constraints: The default value is `4G`. The maximum length is `10` characters. The minimum length is `0` characters. The value must match regular expression `/^([0-9.]+)([eEinumkKMGTPB]*)$/`. + +* `status` - (String) The current status of the function. + * Constraints: Allowable values are: `offline`, `deploying`, `ready`, `failed`. + +* `status_details` - (List) The detailed status of the function. +Nested schema for **status_details**: + * `reason` - (String) Provides additional information about the status of the function. + * Constraints: Allowable values are: `offline`, `deploying_configuring_routes`, `ready_update_in_progress`, `deploying`, `ready_last_update_failed`, `ready`, `unknown_reason`, `no_code_bundle`. + diff --git a/website/docs/r/code_engine_function.html.markdown b/website/docs/r/code_engine_function.html.markdown new file mode 100644 index 00000000000..91ec7863500 --- /dev/null +++ b/website/docs/r/code_engine_function.html.markdown @@ -0,0 +1,117 @@ +--- +layout: "ibm" +page_title: "IBM : ibm_code_engine_function" +description: |- + Manages code_engine_function. +subcategory: "Code Engine" +--- + +# ibm_code_engine_function + +Create, update, and delete code_engine_functions with this resource. + +## Example Usage + +```hcl +resource "ibm_code_engine_function" "code_engine_function_instance" { + project_id = ibm_code_engine_project.code_engine_project_instance.project_id + name = "my-function" + runtime = "nodejs-20" + code_reference = "icr.io/codeengine/samples/function-nodejs-codebundle" +} +``` + +## Timeouts + +code_engine_function provides the following [Timeouts](https://www.terraform.io/docs/configuration/resources.html#timeouts) configuration options: + +* `create` - (Default 10 minutes) Used for creating a code_engine_function. +* `update` - (Default 10 minutes) Used for updating a code_engine_function. + +## Argument Reference + +You can specify the following arguments for this resource. + +* `code_binary` - (Optional, Boolean) Specifies whether the code is binary or not. Defaults to false when `code_reference` is set to a data URL. When `code_reference` is set to a code bundle URL, this field is always true. +* `code_main` - (Optional, String) Specifies the name of the function that should be invoked. + * Constraints: The default value is `main`. The maximum length is `63` characters. The minimum length is `1` character. The value must match regular expression `/^[a-zA-Z_][a-zA-Z0-9_]*$/`. +* `code_reference` - (Required, String) Specifies either a reference to a code bundle or the source code itself. To specify the source code, use the data URL scheme and include the source code as base64 encoded. The data URL scheme is defined in [RFC 2397](https://tools.ietf.org/html/rfc2397). + * Constraints: The maximum length is `1048576` characters. The minimum length is `1` character. The value must match regular expression `/^([a-z0-9][a-z0-9\\-_.]+[a-z0-9][\/])?([a-z0-9][a-z0-9\\-_]+[a-z0-9][\/])?[a-z0-9][a-z0-9\\-_.\/]+[a-z0-9](:[\\w][\\w.\\-]{0,127})?(@sha256:[a-fA-F0-9]{64})?$|data:([-\\w]+\/[-+\\w.]+)?(;?\\w+=[-\\w]+)*;base64,.*/`. +* `code_secret` - (Optional, String) The name of the secret that is used to access the specified `code_reference`. The secret is used to authenticate with a non-public endpoint that is specified as`code_reference`. + * Constraints: The maximum length is `253` characters. The minimum length is `1` character. The value must match regular expression `/^[a-z0-9]([\\-a-z0-9]*[a-z0-9])?(\\.[a-z0-9]([\\-a-z0-9]*[a-z0-9])?)*$/`. +* `managed_domain_mappings` - (Optional, String) Optional value controlling which of the system managed domain mappings will be setup for the function. Valid values are 'local_public', 'local_private' and 'local'. Visibility can only be 'local_private' if the project supports function private visibility. + * Constraints: The default value is `local_public`. Allowable values are: `local`, `local_private`, `local_public`. +* `name` - (Required, Forces new resource, String) The name of the function. + * Constraints: The maximum length is `63` characters. The minimum length is `1` character. The value must match regular expression `/^[a-z]([-a-z0-9]*[a-z0-9])?$/`. +* `project_id` - (Required, Forces new resource, String) The ID of the project. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[0-9a-z]{8}-[0-9a-z]{4}-[0-9a-z]{4}-[0-9a-z]{4}-[0-9a-z]{12}$/`. +* `run_env_variables` - (Optional, List) References to config maps, secrets or literal values, which are defined by the function owner and are exposed as environment variables in the function. + * Constraints: The maximum length is `100` items. The minimum length is `0` items. +Nested schema for **run_env_variables**: + * `key` - (Optional, String) The key to reference as environment variable. + * Constraints: The maximum length is `253` characters. The minimum length is `1` character. The value must match regular expression `/^[\\-._a-zA-Z0-9]+$/`. + * `name` - (Optional, String) The name of the environment variable. + * Constraints: The maximum length is `253` characters. The minimum length is `1` character. The value must match regular expression `/^[\\-._a-zA-Z0-9]+$/`. + * `prefix` - (Optional, String) A prefix that can be added to all keys of a full secret or config map reference. + * Constraints: The maximum length is `253` characters. The minimum length is `0` characters. The value must match regular expression `/^[a-zA-Z_][a-zA-Z0-9_]*$/`. + * `reference` - (Optional, String) The name of the secret or config map. + * Constraints: The maximum length is `253` characters. The minimum length is `1` character. The value must match regular expression `/^[a-z0-9]([\\-a-z0-9]*[a-z0-9])?(\\.[a-z0-9]([\\-a-z0-9]*[a-z0-9])?)*$/`. + * `type` - (Optional, String) Specify the type of the environment variable. + * Constraints: The default value is `literal`. Allowable values are: `literal`, `config_map_full_reference`, `secret_full_reference`, `config_map_key_reference`, `secret_key_reference`. The value must match regular expression `/^(literal|config_map_full_reference|secret_full_reference|config_map_key_reference|secret_key_reference)$/`. When referencing a secret or configmap, the `reference` must be specified. When referencing a secret or configmap key, a `key` must also be specified. + * `value` - (Optional, String) The literal value of the environment variable. + * Constraints: The maximum length is `253` characters. The minimum length is `1` character. The value must match regular expression `/^[\\-._a-zA-Z0-9]+$/`. +* `runtime` - (Required, String) The managed runtime used to execute the injected code. + * Constraints: The maximum length is `63` characters. The minimum length is `1` character. The value must match regular expression `/^[a-z]*\\-[0-9]*(\\.[0-9]*)?$/`. +* `scale_concurrency` - (Optional, Integer) Number of parallel requests handled by a single instance, supported only by Node.js, default is `1`. + * Constraints: The default value is `1`. The maximum value is `100`. The minimum value is `1`. +* `scale_cpu_limit` - (Optional, String) Optional amount of CPU set for the instance of the function. For valid values see [Supported memory and CPU combinations](https://cloud.ibm.com/docs/codeengine?topic=codeengine-mem-cpu-combo). + * Constraints: The default value is `1`. The maximum length is `10` characters. The minimum length is `0` characters. The value must match regular expression `/^([0-9.]+)([eEinumkKMGTPB]*)$/`. +* `scale_down_delay` - (Optional, Integer) Optional amount of time in seconds that delays the scale down behavior for a function. + * Constraints: The default value is `1`. The maximum value is `600`. The minimum value is `0`. +* `scale_max_execution_time` - (Optional, Integer) Timeout in secs after which the function is terminated. + * Constraints: The default value is `60`. The maximum value is `120`. The minimum value is `1`. +* `scale_memory_limit` - (Optional, String) Optional amount of memory set for the instance of the function. For valid values see [Supported memory and CPU combinations](https://cloud.ibm.com/docs/codeengine?topic=codeengine-mem-cpu-combo). The units for specifying memory are Megabyte (M) or Gigabyte (G), whereas G and M are the shorthand expressions for GB and MB. For more information see [Units of measurement](https://cloud.ibm.com/docs/codeengine?topic=codeengine-mem-cpu-combo#unit-measurements). + * Constraints: The default value is `4G`. The maximum length is `10` characters. The minimum length is `0` characters. The value must match regular expression `/^([0-9.]+)([eEinumkKMGTPB]*)$/`. + +## Attribute Reference + +After your resource is created, you can read values from the listed arguments and the following attributes. + +* `id` - The unique identifier of the code_engine_function. +* `function_id` - (String) The identifier of the resource. + * Constraints: The maximum length is `36` characters. The minimum length is `36` characters. The value must match regular expression `/^[0-9a-z]{8}-[0-9a-z]{4}-[0-9a-z]{4}-[0-9a-z]{4}-[0-9a-z]{12}$/`. +* `created_at` - (String) The timestamp when the resource was created. +* `endpoint` - (String) URL to invoke the function. + * Constraints: The maximum length is `2048` characters. The minimum length is `0` characters. The value must match regular expression `/(([^:\/?#]+):)?(\/\/([^\/?#]*))?([^?#]*)(\\?([^#]*))?(#(.*))?$/`. +* `endpoint_internal` - (String) URL to function that is only visible within the project. + * Constraints: The maximum length is `2048` characters. The minimum length is `0` characters. The value must match regular expression `/(([^:\/?#]+):)?(\/\/([^\/?#]*))?([^?#]*)(\\?([^#]*))?(#(.*))?$/`. +* `entity_tag` - (String) The version of the function instance, which is used to achieve optimistic locking. + * Constraints: The maximum length is `63` characters. The minimum length is `1` character. The value must match regular expression `/^[\\*\\-a-z0-9]+$/`. +* `href` - (String) When you provision a new function, a relative URL path is created identifying the location of the instance. + * Constraints: The maximum length is `2048` characters. The minimum length is `0` characters. The value must match regular expression `/(([^:\/?#]+):)?(\/\/([^\/?#]*))?([^?#]*)(\\?([^#]*))?(#(.*))?$/`. +* `region` - (String) The region of the project the resource is located in. Possible values: 'au-syd', 'br-sao', 'ca-tor', 'eu-de', 'eu-gb', 'jp-osa', 'jp-tok', 'us-east', 'us-south'. +* `resource_type` - (String) The type of the function. + * Constraints: Allowable values are: `function_v2`. +* `status` - (String) The current status of the function. + * Constraints: Allowable values are: `offline`, `deploying`, `ready`, `failed`. +* `status_details` - (List) The detailed status of the function. +Nested schema for **status_details**: + * `reason` - (String) Provides additional information about the status of the function. + * Constraints: Allowable values are: `offline`, `deploying_configuring_routes`, `ready_update_in_progress`, `deploying`, `ready_last_update_failed`, `ready`, `unknown_reason`, `no_code_bundle`. +* `etag` - ETag identifier for code_engine_function. + +## Import + +You can import the `ibm_code_engine_function` resource by using `name`. +The `name` property can be formed from `project_id`, and `name` in the following format: + +
+<project_id>/<name>
+
+* `project_id`: A string in the format `15314cc3-85b4-4338-903f-c28cdee6d005`. The ID of the project. +* `name`: A string in the format `my-function`. The name of the function. + +# Syntax +
+$ terraform import ibm_code_engine_function.code_engine_function <project_id>/<name>
+
From 54c8962aada4e0e01d8b01d0aed7f6fd98340005 Mon Sep 17 00:00:00 2001 From: luiof <69894130+luiof@users.noreply.github.com> Date: Tue, 17 Sep 2024 15:44:28 +0200 Subject: [PATCH 3/4] Fix the 5635 - The ibm_resource_tag now checks the response in the api tags calls (#5641) * Deprecated ibm_resource_access_tag in favor of ibm_iam_access_tag * changes * Fix * Changed resource to speed up tests * fix * PR changes * PR changes * Added new context functions. Now the code handles the error in the response on resource tags calls. * Fixed 5635 * Fix * Fixed * Removed logs line --- ibm/flex/structures.go | 111 +++++++++++--- .../resource_ibm_iam_access_tag.go | 4 +- .../resource_ibm_iam_access_tag_test.go | 24 +-- .../resource_ibm_resource_tag.go | 111 +++++++------- .../resource_ibm_resource_tag_test.go | 141 +++++++++++++++--- 5 files changed, 276 insertions(+), 115 deletions(-) diff --git a/ibm/flex/structures.go b/ibm/flex/structures.go index da354497e63..147a0d6bba3 100644 --- a/ibm/flex/structures.go +++ b/ibm/flex/structures.go @@ -2401,34 +2401,46 @@ func GetTags(d *schema.ResourceData, meta interface{}) error { // } func GetGlobalTagsUsingCRN(meta interface{}, resourceID, resourceType, tagType string) (*schema.Set, error) { + taggingResult, err := GetGlobalTagsUsingSearchAPI(meta, resourceID, resourceType, tagType) + if err != nil { + return nil, err + } + return taggingResult, nil +} + +func GetTagsUsingResourceCRNFromTaggingApi(meta interface{}, resourceID, resourceType, tagType string) (*schema.Set, error) { + gtClient, err := meta.(conns.ClientSession).GlobalTaggingAPIv1() + if err != nil { + return nil, fmt.Errorf("[ERROR] Error getting global tagging client settings: %s", err) + } userDetails, err := meta.(conns.ClientSession).BluemixUserDetails() if err != nil { return nil, err } accountID := userDetails.UserAccount ListTagsOptions := &globaltaggingv1.ListTagsOptions{} - if resourceID != "" { - ListTagsOptions.AttachedTo = &resourceID - } + ListTagsOptions.AttachedTo = &resourceID if strings.HasPrefix(resourceType, "Softlayer_") { ListTagsOptions.Providers = []string{"ims"} } if len(tagType) > 0 { ListTagsOptions.TagType = PtrToString(tagType) - if tagType == "service" { ListTagsOptions.AccountID = PtrToString(accountID) } } - taggingResult, err := GetGlobalTagsUsingSearchAPI(meta, resourceID, resourceType, tagType) + taggingResult, _, err := gtClient.ListTags(ListTagsOptions) if err != nil { return nil, err } - return taggingResult, nil + var taglist []string + for _, item := range taggingResult.Items { + taglist = append(taglist, *item.Name) + } + return NewStringSet(ResourceIBMVPCHash, taglist), nil } func GetGlobalTagsUsingSearchAPI(meta interface{}, resourceID, resourceType, tagType string) (*schema.Set, error) { - gsClient, err := meta.(conns.ClientSession).GlobalSearchAPIV2() if err != nil { return nil, fmt.Errorf("[ERROR] Error getting global search client settings: %s", err) @@ -2531,18 +2543,20 @@ func UpdateGlobalTagsUsingCRN(oldList, newList interface{}, meta interface{}, re detachTagOptions.AccountID = PtrToString(acctID) } } - - _, resp, err := gtClient.DetachTag(detachTagOptions) + results, fullResponse, err := gtClient.DetachTag(detachTagOptions) if err != nil { - return fmt.Errorf("[ERROR] Error detaching database tags %v: %s\n%s", remove, err, resp) + return fmt.Errorf("[ERROR] Error detaching tags calling api %v: %s\n%s", remove, err, fullResponse) } - for _, v := range remove { - delTagOptions := &globaltaggingv1.DeleteTagOptions{ - TagName: PtrToString(v), + if results != nil { + errMap := make([]globaltaggingv1.TagResultsItem, 0) + for _, res := range results.Results { + if res.IsError != nil && *res.IsError { + errMap = append(errMap, res) + } } - _, resp, err := gtClient.DeleteTag(delTagOptions) - if err != nil { - return fmt.Errorf("[ERROR] Error deleting database tag %v: %s\n%s", v, err, resp) + if len(errMap) > 0 { + output, _ := json.MarshalIndent(errMap, "", " ") + return fmt.Errorf("[ERROR] Error detaching tag in results %v: %s\n%s", remove, string(output), fullResponse) } } } @@ -2624,7 +2638,7 @@ func GetTagsUsingCRN(meta interface{}, resourceCRN string) (*schema.Set, error) } func UpdateTagsUsingCRN(oldList, newList interface{}, meta interface{}, resourceCRN string) error { - gtClient, err := meta.(conns.ClientSession).GlobalTaggingAPI() + gtClient, err := meta.(conns.ClientSession).GlobalTaggingAPIv1() if err != nil { return fmt.Errorf("[ERROR] Error getting global tagging client settings: %s", err) } @@ -2654,23 +2668,74 @@ func UpdateTagsUsingCRN(oldList, newList interface{}, meta interface{}, resource add = append(add, envTags...) } + resources := []globaltaggingv1.Resource{} + r := globaltaggingv1.Resource{ResourceID: &resourceCRN} + resources = append(resources, r) + if len(remove) > 0 { - _, err := gtClient.Tags().DetachTags(resourceCRN, remove) + detachTagOptions := &globaltaggingv1.DetachTagOptions{} + detachTagOptions.Resources = resources + detachTagOptions.TagNames = remove + + results, fullResponse, err := gtClient.DetachTag(detachTagOptions) if err != nil { - return fmt.Errorf("[ERROR] Error detaching database tags %v: %s", remove, err) + return fmt.Errorf("[ERROR] Error detaching tags %v: %s", remove, err) + } + if results != nil { + errMap := make([]globaltaggingv1.TagResultsItem, 0) + for _, res := range results.Results { + if res.IsError != nil && *res.IsError { + errMap = append(errMap, res) + } + } + if len(errMap) > 0 { + output, _ := json.MarshalIndent(errMap, "", " ") + return fmt.Errorf("[ERROR] Error detaching tag %v: %s\n%s", remove, string(output), fullResponse) + } } for _, v := range remove { - _, err := gtClient.Tags().DeleteTag(v) + delTagOptions := &globaltaggingv1.DeleteTagOptions{ + TagName: PtrToString(v), + } + results, fullResponse, err := gtClient.DeleteTag(delTagOptions) if err != nil { - return fmt.Errorf("[ERROR] Error deleting database tag %v: %s", v, err) + return fmt.Errorf("[ERROR] Error deleting tag %v: %s\n%s", v, err, fullResponse) + } + + if results != nil { + errMap := make([]globaltaggingv1.DeleteTagResultsItem, 0) + for _, res := range results.Results { + if res.IsError != nil && *res.IsError { + errMap = append(errMap, res) + } + } + if len(errMap) > 0 { + output, _ := json.MarshalIndent(errMap, "", " ") + return fmt.Errorf("[ERROR] Error deleting tag %s: %s\n%s", v, string(output), fullResponse) + } } } } if len(add) > 0 { - _, err := gtClient.Tags().AttachTags(resourceCRN, add) + AttachTagOptions := &globaltaggingv1.AttachTagOptions{} + AttachTagOptions.Resources = resources + AttachTagOptions.TagNames = add + results, fullResponse, err := gtClient.AttachTag(AttachTagOptions) if err != nil { - return fmt.Errorf("[ERROR] Error updating database tags %v : %s", add, err) + return fmt.Errorf("[ERROR] Error updating tags %v : %s", add, err) + } + if results != nil { + errMap := make([]globaltaggingv1.TagResultsItem, 0) + for _, res := range results.Results { + if res.IsError != nil && *res.IsError { + errMap = append(errMap, res) + } + } + if len(errMap) > 0 { + output, _ := json.MarshalIndent(errMap, "", " ") + return fmt.Errorf("Error while updating tag: %s - Full response: %s", string(output), fullResponse) + } } } diff --git a/ibm/service/globaltagging/resource_ibm_iam_access_tag.go b/ibm/service/globaltagging/resource_ibm_iam_access_tag.go index fa7874bef76..a1844c8fc39 100644 --- a/ibm/service/globaltagging/resource_ibm_iam_access_tag.go +++ b/ibm/service/globaltagging/resource_ibm_iam_access_tag.go @@ -153,7 +153,7 @@ func resourceIBMIamAccessTagDelete(context context.Context, d *schema.ResourceDa results, resp, err := gtClient.DeleteTagWithContext(context, deleteTagOptions) if err != nil { - return diag.FromErr(fmt.Errorf("Error while deleting access tag(%s) : %v\n%v", tagName, err, resp)) + return diag.FromErr(fmt.Errorf("Error while deleting access tag calling api (%s) : %v\n%v", tagName, err, resp)) } if results != nil { errMap := make([]globaltaggingv1.DeleteTagResultsItem, 0) @@ -164,7 +164,7 @@ func resourceIBMIamAccessTagDelete(context context.Context, d *schema.ResourceDa } if len(errMap) > 0 { output, _ := json.MarshalIndent(errMap, "", " ") - return diag.FromErr(fmt.Errorf("Error while deleting access tag(%s) : %s", tagName, string(output))) + return diag.FromErr(fmt.Errorf("Error while deleting access tag in results (%s) : %s", tagName, string(output))) } } diff --git a/ibm/service/globaltagging/resource_ibm_iam_access_tag_test.go b/ibm/service/globaltagging/resource_ibm_iam_access_tag_test.go index a6d973def4a..e4a4f2362c1 100644 --- a/ibm/service/globaltagging/resource_ibm_iam_access_tag_test.go +++ b/ibm/service/globaltagging/resource_ibm_iam_access_tag_test.go @@ -6,7 +6,6 @@ package globaltagging_test import ( "fmt" "regexp" - "strings" "testing" acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" @@ -44,10 +43,6 @@ func TestAccIamAccessTag_Basic(t *testing.T) { } func TestAccIamAccessTag_Usage(t *testing.T) { name := fmt.Sprintf("tf%d:iam-access%d", acctest.RandIntRange(10, 100), acctest.RandIntRange(10, 100)) - publicKey := strings.TrimSpace(` -ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVERRN7/9484SOBJ3HSKxxNG5JN8owAjy5f9yYwcUg+JaUVuytn5Pv3aeYROHGGg+5G346xaq3DAwX6Y5ykr2fvjObgncQBnuU5KHWCECO/4h8uWuwh/kfniXPVjFToc+gnkqA+3RKpAecZhFXwfalQ9mMuYGFxn+fwn8cYEApsJbsEmb0iJwPiZ5hjFC8wREuiTlhPHDgkBLOiycd20op2nXzDbHfCHInquEe/gYxEitALONxm0swBOwJZwlTDOB7C6y2dzlrtxr1L59m7pCkWI4EtTRLvleehBoj3u7jB4usR -`) - sshkeyname := fmt.Sprintf("tfssh-createname-%d", acctest.RandIntRange(10, 100)) resource.Test(t, resource.TestCase{ PreCheck: func() { acc.TestAccPreCheck(t) }, Providers: acc.TestAccProviders, @@ -63,7 +58,7 @@ ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCKVmnMOlHKcZK8tpt3MP1lqOLAcqcJzhsvJcjscgVE ), }, resource.TestStep{ - Config: testAccCheckIamAccessTagUsage(name, sshkeyname, publicKey), + Config: testAccCheckIamAccessTagUsage(name), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckIamAccessTagExists("ibm_iam_access_tag.tag"), resource.TestCheckResourceAttr("ibm_iam_access_tag.tag", "id", name), @@ -129,19 +124,24 @@ func testAccCheckIamAccessTagCreate(name string) string { } `, name) } -func testAccCheckIamAccessTagUsage(name, sshkeyname, publicKey string) string { +func testAccCheckIamAccessTagUsage(name string) string { + resource_group_name := fmt.Sprintf("tf%d-iam-access%d", acctest.RandIntRange(10, 100), acctest.RandIntRange(10, 100)) return fmt.Sprintf(` + data "ibm_resource_group" "group" { + name = "Default" + } resource "ibm_iam_access_tag" "tag" { name = "%s" } - resource "ibm_is_ssh_key" "key" { - name = "%s" - public_key = "%s" + resource "ibm_cd_toolchain" "cd_toolchain_instance" { + description = "Terraform test" + name = "%s-toolchain" + resource_group_id = data.ibm_resource_group.group.id } resource "ibm_resource_tag" "tag" { - resource_id = ibm_is_ssh_key.key.crn + resource_id = ibm_cd_toolchain.cd_toolchain_instance.crn tags = [ibm_iam_access_tag.tag.name] tag_type = "access" } -`, name, sshkeyname, publicKey) +`, name, resource_group_name) } diff --git a/ibm/service/globaltagging/resource_ibm_resource_tag.go b/ibm/service/globaltagging/resource_ibm_resource_tag.go index 34df86fc29e..aa23bd1f730 100644 --- a/ibm/service/globaltagging/resource_ibm_resource_tag.go +++ b/ibm/service/globaltagging/resource_ibm_resource_tag.go @@ -5,6 +5,7 @@ package globaltagging import ( "context" + "encoding/json" "fmt" "log" "os" @@ -18,6 +19,7 @@ import ( "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" "github.com/IBM-Cloud/terraform-provider-ibm/ibm/flex" "github.com/IBM-Cloud/terraform-provider-ibm/ibm/validate" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" ) const ( @@ -32,11 +34,11 @@ const ( func ResourceIBMResourceTag() *schema.Resource { return &schema.Resource{ - Create: resourceIBMResourceTagCreate, - Read: resourceIBMResourceTagRead, - Update: resourceIBMResourceTagUpdate, - Delete: resourceIBMResourceTagDelete, - Importer: &schema.ResourceImporter{}, + CreateContext: resourceIBMResourceTagCreate, + ReadContext: resourceIBMResourceTagRead, + UpdateContext: resourceIBMResourceTagUpdate, + DeleteContext: resourceIBMResourceTagDelete, + Importer: &schema.ResourceImporter{}, CustomizeDiff: customdiff.Sequence( func(_ context.Context, diff *schema.ResourceDiff, v interface{}) error { @@ -125,19 +127,23 @@ func ResourceIBMResourceTagValidator() *validate.ResourceValidator { return &ibmResourceTagValidator } -func resourceIBMResourceTagCreate(d *schema.ResourceData, meta interface{}) error { +func resourceIBMResourceTagCreate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { var rType, tType string resources := []globaltaggingv1.Resource{} userDetails, err := meta.(conns.ClientSession).BluemixUserDetails() if err != nil { - return err + tfErr := flex.TerraformErrorf(err, err.Error(), "ibm_resource_tag", "create") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() } accountID := userDetails.UserAccount gtClient, err := meta.(conns.ClientSession).GlobalTaggingAPIv1() if err != nil { - return fmt.Errorf("[ERROR] Error getting global tagging client settings: %s", err) + tfErr := flex.TerraformErrorf(err, err.Error(), "ibm_resource_tag", "create") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() } resourceID := d.Get(resourceID).(string) @@ -187,9 +193,24 @@ func resourceIBMResourceTagCreate(d *schema.ResourceData, meta interface{}) erro } if len(add) > 0 { - _, resp, err := gtClient.AttachTag(AttachTagOptions) + results, fullResponse, err := gtClient.AttachTagWithContext(context, AttachTagOptions) if err != nil { - return fmt.Errorf("[ERROR] Error attaching resource tags : %v\n%s", resp, err) + tfErr := flex.TerraformErrorf(err, err.Error(), "ibm_resource_tag", "create") + return tfErr.GetDiag() + } + + // Check if there are errors on the attach internal response + if results != nil { + errMap := make([]globaltaggingv1.TagResultsItem, 0) + for _, res := range results.Results { + if res.IsError != nil && *res.IsError { + errMap = append(errMap, res) + } + } + if len(errMap) > 0 { + output, _ := json.MarshalIndent(errMap, "", " ") + return diag.FromErr(fmt.Errorf("Error while creating tag: %s - Full response: %s", string(output), fullResponse)) + } } response, errored := flex.WaitForTagsAvailable(meta, resourceID, resourceType, tagType, news, d.Timeout(schema.TimeoutCreate)) if errored != nil { @@ -204,15 +225,17 @@ func resourceIBMResourceTagCreate(d *schema.ResourceData, meta interface{}) erro d.SetId(fmt.Sprintf("%s/%s", resourceID, rType)) } - return resourceIBMResourceTagRead(d, meta) + return resourceIBMResourceTagRead(context, d, meta) } -func resourceIBMResourceTagRead(d *schema.ResourceData, meta interface{}) error { +func resourceIBMResourceTagRead(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { var rID, rType, tType string userDetails, err := meta.(conns.ClientSession).BluemixUserDetails() if err != nil { - return err + tfErr := flex.TerraformErrorf(err, err.Error(), "ibm_resource_tag", "read") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() } acctID := userDetails.UserAccount @@ -221,10 +244,12 @@ func resourceIBMResourceTagRead(d *schema.ResourceData, meta interface{}) error } else { parts, err := flex.VmIdParts(d.Id()) if err != nil { - return err + tfErr := flex.TerraformErrorf(err, err.Error(), "ibm_resource_tag", "read") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() } if len(parts) < 2 { - return fmt.Errorf("[ERROR] Incorrect ID %s: Id should be a combination of resourceID/resourceType", d.Id()) + return diag.FromErr(fmt.Errorf("Incorrect ID %s: Id should be a combination of resourceID/resourceType", d.Id())) } rID = parts[0] rType = parts[1] @@ -240,7 +265,7 @@ func resourceIBMResourceTagRead(d *schema.ResourceData, meta interface{}) error tagList, err := flex.GetGlobalTagsUsingSearchAPI(meta, rID, rType, tType) if err != nil { - return fmt.Errorf("[ERROR] Error getting resource tags for: %s with error : %s", rID, err) + return diag.FromErr(fmt.Errorf("Error getting resource tags for: %s with error : %s", rID, err)) } d.Set(resourceID, rID) @@ -250,7 +275,7 @@ func resourceIBMResourceTagRead(d *schema.ResourceData, meta interface{}) error return nil } -func resourceIBMResourceTagUpdate(d *schema.ResourceData, meta interface{}) error { +func resourceIBMResourceTagUpdate(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { var rID, rType, tType string if strings.HasPrefix(d.Id(), "crn:") { @@ -258,7 +283,9 @@ func resourceIBMResourceTagUpdate(d *schema.ResourceData, meta interface{}) erro } else { parts, err := flex.VmIdParts(d.Id()) if err != nil { - return err + tfErr := flex.TerraformErrorf(err, err.Error(), "ibm_resource_tag", "update") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() } rID = parts[0] rType = parts[1] @@ -272,68 +299,38 @@ func resourceIBMResourceTagUpdate(d *schema.ResourceData, meta interface{}) erro oldList, newList := d.GetChange(tags) err := flex.UpdateGlobalTagsUsingCRN(oldList, newList, meta, rID, rType, tType) if err != nil { - return fmt.Errorf("[ERROR] Error on create of resource tags: %s", err) + return diag.FromErr(fmt.Errorf("Error on create of resource tags: %s", err)) } } - return resourceIBMResourceTagRead(d, meta) + return resourceIBMResourceTagRead(context, d, meta) } -func resourceIBMResourceTagDelete(d *schema.ResourceData, meta interface{}) error { +func resourceIBMResourceTagDelete(context context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { var rID, rType string - if strings.HasPrefix(d.Id(), "crn:") { rID = d.Id() } else { parts, err := flex.VmIdParts(d.Id()) if err != nil { - return err + tfErr := flex.TerraformErrorf(err, err.Error(), "ibm_resource_tag", "delete") + log.Printf("[ERROR] Error in deleting.\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() } rID = parts[0] rType = parts[1] } - - gtClient, err := meta.(conns.ClientSession).GlobalTaggingAPIv1() - if err != nil { - return fmt.Errorf("[ERROR] Error getting global tagging client settings: %s", err) - } - - var remove []string removeTags := d.Get(tags).(*schema.Set) - remove = make([]string, len(removeTags.List())) - for i, v := range removeTags.List() { - remove[i] = fmt.Sprint(v) - } var tType string if v, ok := d.GetOk(tagType); ok && v != nil { tType = v.(string) } else { tType = "user" } - - if len(remove) > 0 { - resources := []globaltaggingv1.Resource{} - r := globaltaggingv1.Resource{ResourceID: flex.PtrToString(rID), ResourceType: flex.PtrToString(rType)} - resources = append(resources, r) - - detachTagOptions := &globaltaggingv1.DetachTagOptions{ - Resources: resources, - TagNames: remove, - TagType: &tType, - } - - _, resp, err := gtClient.DetachTag(detachTagOptions) + if len(removeTags.List()) > 0 { + err := flex.UpdateGlobalTagsUsingCRN(removeTags, nil, meta, rID, rType, tType) if err != nil { - return fmt.Errorf("[ERROR] Error detaching resource tags %v: %s\n%s", remove, err, resp) - } - for _, v := range remove { - delTagOptions := &globaltaggingv1.DeleteTagOptions{ - TagName: flex.PtrToString(v), - } - _, resp, err := gtClient.DeleteTag(delTagOptions) - if err != nil { - return fmt.Errorf("[ERROR] Error deleting resource tag %v: %s\n%s", v, err, resp) - } + return diag.FromErr(fmt.Errorf("Error on deleting tags: %s", err)) } } return nil diff --git a/ibm/service/globaltagging/resource_ibm_resource_tag_test.go b/ibm/service/globaltagging/resource_ibm_resource_tag_test.go index b7dca8d395c..414a1a2d4bd 100644 --- a/ibm/service/globaltagging/resource_ibm_resource_tag_test.go +++ b/ibm/service/globaltagging/resource_ibm_resource_tag_test.go @@ -7,6 +7,7 @@ import ( "fmt" "log" "regexp" + "strings" "testing" acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest" @@ -18,14 +19,17 @@ import ( func TestAccResourceTag_Basic(t *testing.T) { name := fmt.Sprintf("tf-cos-%d", acctest.RandIntRange(10, 100)) + var tags []string + tags = append(tags, "env:dev") + tags = append(tags, "cpu:4") resource.Test(t, resource.TestCase{ - PreCheck: func() { acc.TestAccPreCheck(t) }, - Providers: acc.TestAccProviders, + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckTagDestroy("ibm_resource_tag.tag", "user", tags), Steps: []resource.TestStep{ - { - Config: testAccCheckResourceTagCreate(name), + Config: testAccCheckResourceTagCreate(name, tags), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckResourceTagExists("ibm_resource_tag.tag"), resource.TestCheckResourceAttr("ibm_resource_tag.tag", "tags.#", "2"), @@ -41,26 +45,45 @@ func TestAccResourceTag_Basic(t *testing.T) { }, }) } -func TestAccResourceTag_Wait(t *testing.T) { - name := fmt.Sprintf("tf-cos-%d", acctest.RandIntRange(10, 100)) +func TestAccResourceTag_FakeCrnExpectingError(t *testing.T) { + var tags []string + tags = append(tags, "env:dev") + tags = append(tags, "cpu:4") resource.Test(t, resource.TestCase{ PreCheck: func() { acc.TestAccPreCheck(t) }, Providers: acc.TestAccProviders, Steps: []resource.TestStep{ + { + Config: testAccCheckResourceTagCreateFakeCrnExpectingError(tags), + ExpectError: regexp.MustCompile("\"is_error\": true"), + }, + }, + }) +} +func TestAccResourceTag_AttachOnExistingResource(t *testing.T) { + crn := "crn:v1:bluemix:public:toolchain:eu-gb:a/970f5cb4bbc04119ab0a0f399e4b776c:8784b8c3-1c7f-476a-ac30-50ae07e3cce3::" + var tags []string + tags = append(tags, "env:dev") + tags = append(tags, "cpu:4") + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckTagOnExistingResourceDestroy(crn, "ibm_resource_tag.tag", "user", tags), + Steps: []resource.TestStep{ { - Config: testAccCheckResourceTagWaitCreate(name), + Config: testAccCheckResourceAttachOnExistingResource(crn, tags), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckResourceTagExists("ibm_resource_tag.tag"), - resource.TestCheckResourceAttr("ibm_resource_tag.tag", "tags.#", "3"), + resource.TestCheckResourceAttr("ibm_resource_tag.tag", "tags.#", "2"), ), }, }, }) } -func testAccCheckResourceTagExists(n string) resource.TestCheckFunc { +func testAccCheckTagDestroy(n, tagType string, tagNames []string) resource.TestCheckFunc { return func(s *terraform.State) error { var resourceID string rs, ok := s.RootModule().Resources[n] @@ -72,7 +95,80 @@ func testAccCheckResourceTagExists(n string) resource.TestCheckFunc { if err != nil { return err } + if crn.MatchString(rs.Primary.ID) { + resourceID = rs.Primary.ID + } else { + parts, err := flex.VmIdParts(rs.Primary.ID) + if err != nil { + return err + } + resourceID = parts[0] + } + results, errorGet := flex.GetTagsUsingResourceCRNFromTaggingApi(acc.TestAccProvider.Meta(), resourceID, "", tagType) + if errorGet != nil { + return fmt.Errorf("Error on get of resource tags (%s) : %s", resourceID, errorGet) + } + var taglist []string + for _, v := range results.List() { + taglist = append(taglist, fmt.Sprint(v)) + } + existingAccessTags := flex.NewStringSet(flex.ResourceIBMVPCHash, taglist) + for _, tagName := range tagNames { + if existingAccessTags.Contains(tagName) { + return fmt.Errorf("Tag still exists") + } + } + return nil + } +} +func testAccCheckTagOnExistingResourceDestroy(resourceCrn, n, tagType string, tagNames []string) resource.TestCheckFunc { + return func(s *terraform.State) error { + var resourceID string + _, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + crnRegex := "^crn:v1(:[a-zA-Z0-9 \\-\\._~\\*\\+,;=!$&'\\(\\)\\/\\?#\\[\\]@]*){8}$|^[0-9]+$" + crn, err := regexp.Compile(crnRegex) + if err != nil { + return err + } + if crn.MatchString(resourceCrn) { + resourceID = resourceCrn + } else { + return fmt.Errorf("CRN not correct: %s", resourceCrn) + } + results, errorGet := flex.GetTagsUsingResourceCRNFromTaggingApi(acc.TestAccProvider.Meta(), resourceID, "", tagType) + if errorGet != nil { + return fmt.Errorf("Error on get of resource tags (%s) : %s", resourceID, errorGet) + } + var taglist []string + for _, v := range results.List() { + taglist = append(taglist, fmt.Sprint(v)) + } + existingAccessTags := flex.NewStringSet(flex.ResourceIBMVPCHash, taglist) + for _, tagName := range tagNames { + if existingAccessTags.Contains(tagName) { + return fmt.Errorf("Tag still exists") + } + } + return nil + } +} + +func testAccCheckResourceTagExists(n string) resource.TestCheckFunc { + return func(s *terraform.State) error { + var resourceID string + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + crnRegex := "^crn:v1(:[a-zA-Z0-9 \\-\\._~\\*\\+,;=!$&'\\(\\)\\/\\?#\\[\\]@]*){8}$|^[0-9]+$" + crn, err := regexp.Compile(crnRegex) + if err != nil { + return err + } if crn.MatchString(rs.Primary.ID) { resourceID = rs.Primary.ID } else { @@ -91,7 +187,7 @@ func testAccCheckResourceTagExists(n string) resource.TestCheckFunc { } } -func testAccCheckResourceTagWaitCreate(name string) string { +func testAccCheckResourceTagCreate(name string, tagNames []string) string { return fmt.Sprintf(` resource "ibm_resource_instance" "resource_1" { name = "%s" @@ -102,24 +198,27 @@ func testAccCheckResourceTagWaitCreate(name string) string { resource "ibm_resource_tag" "tag" { resource_id = ibm_resource_instance.resource_1.crn - tags = ["env:dev", "cpu:4", "user:8"] + tags = ["%s"] } -`, name) +`, name, strings.Join(tagNames[:], "\",\"")) } -func testAccCheckResourceTagCreate(name string) string { + +func testAccCheckResourceTagCreateFakeCrnExpectingError(tagNames []string) string { return fmt.Sprintf(` - resource "ibm_resource_instance" "resource_1" { - name = "%s" - service = "cloud-object-storage" - plan = "lite" - location = "global" + resource "ibm_resource_tag" "tag" { + resource_id = "crn:v1:staging:public:cloud-object-storage:global:a/d99e99999dfe99ee999999f99bddd099:ab99d9be-9e9c-99dd-ad99-9bced9999999::" + tags = ["%s"] } +`, strings.Join(tagNames[:], "\",\"")) +} +func testAccCheckResourceAttachOnExistingResource(crn string, tagNames []string) string { + return fmt.Sprintf(` resource "ibm_resource_tag" "tag" { - resource_id = ibm_resource_instance.resource_1.crn - tags = ["env:dev", "cpu:4"] + resource_id = "%s" + tags = ["%s"] } -`, name) +`, crn, strings.Join(tagNames[:], "\",\"")) } func TestAccResourceTag_replace_Basic(t *testing.T) { From 2aa217615d259531c1ad886be77286507a602b1d Mon Sep 17 00:00:00 2001 From: siddhuvarma1997 <49102413+siddhuvarma1997@users.noreply.github.com> Date: Wed, 18 Sep 2024 08:55:41 +0530 Subject: [PATCH 4/4] IAM Policy Assignment: S2S Policy Assignments ET and AG (#5624) * IAM Policy Assignment: S2S Policy Assignments ET and AG Signed-off-by: Alluri-Varma * resolving CVE's for EPAP * IAM Policy Assignment: S2S Policy Assignments ET and AG * IAM Policy Assignment: S2S Policy Assignments ET and AG * IAM Policy Assignment: S2S Policy Assignments ET and AG * IAM Policy Assignment: S2S Policy Assignments ET and AG * IAM Policy Assignment: S2S Policy Assignments ET and AG * IAM Policy Assignment: S2S Policy Assignments ET and AG * IAM Policy Assignment: S2S Policy Assignments ET and AG --------- Signed-off-by: Alluri-Varma Co-authored-by: Alluri-Varma --- ibm/acctest/acctest.go | 7 + ...a_source_ibm_iam_policy_assignment_test.go | 6 - .../resource_ibm_iam_policy_assignment.go | 194 +++++++++++++++++- ...resource_ibm_iam_policy_assignment_test.go | 64 +++++- .../d/iam_policy_assignment.html.markdown | 8 + .../docs/r/policy_assignment.html.markdown | 38 +++- 6 files changed, 300 insertions(+), 17 deletions(-) diff --git a/ibm/acctest/acctest.go b/ibm/acctest/acctest.go index 410539545ef..f04f3474190 100644 --- a/ibm/acctest/acctest.go +++ b/ibm/acctest/acctest.go @@ -394,6 +394,7 @@ var ( // For IAM Access Management var ( TargetAccountId string + TargetEnterpriseId string ) // For Partner Center Sell @@ -1870,6 +1871,12 @@ func init() { fmt.Println("[INFO] Set the environment variable IBM_POLICY_ASSIGNMENT_TARGET_ACCOUNT_ID for testing ibm_iam_policy_assignment resource else tests will fail if this is not set correctly") } + + TargetEnterpriseId = os.Getenv("IBM_POLICY_ASSIGNMENT_TARGET_ENTERPRISE_ID") + if TargetEnterpriseId == "" { + fmt.Println("[INFO] Set the environment variable IBM_POLICY_ASSIGNMENT_TARGET_ENTERPRISE_ID for testing ibm_iam_policy_assignment resource else tests will fail if this is not set correctly") + } + PcsRegistrationAccountId = os.Getenv("PCS_REGISTRATION_ACCOUNT_ID") if PcsRegistrationAccountId == "" { fmt.Println("[WARN] Set the environment variable PCS_REGISTRATION_ACCOUNT_ID for testing iam_onboarding resource else tests will fail if this is not set correctly") diff --git a/ibm/service/iampolicy/data_source_ibm_iam_policy_assignment_test.go b/ibm/service/iampolicy/data_source_ibm_iam_policy_assignment_test.go index 4bcc33195aa..96e7647359a 100644 --- a/ibm/service/iampolicy/data_source_ibm_iam_policy_assignment_test.go +++ b/ibm/service/iampolicy/data_source_ibm_iam_policy_assignment_test.go @@ -64,12 +64,6 @@ resource "ibm_iam_policy_assignment" "policy_assignment" { id = "%s" } - options { - root { - requester_id = "orchestrator" - assignment_id = "test" - } - } templates{ id = ibm_iam_policy_template.policy_s2s_template.template_id version = ibm_iam_policy_template.policy_s2s_template.version diff --git a/ibm/service/iampolicy/resource_ibm_iam_policy_assignment.go b/ibm/service/iampolicy/resource_ibm_iam_policy_assignment.go index 9072c9f76d9..766c1545051 100644 --- a/ibm/service/iampolicy/resource_ibm_iam_policy_assignment.go +++ b/ibm/service/iampolicy/resource_ibm_iam_policy_assignment.go @@ -7,8 +7,11 @@ import ( "context" "fmt" "log" + "strings" + "time" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/IBM-Cloud/terraform-provider-ibm/ibm/conns" @@ -17,6 +20,12 @@ import ( "github.com/IBM/platform-services-go-sdk/iampolicymanagementv1" ) +const ( + InProgress = "in_progress" + complete = "complete" + failed = "failed" +) + func ResourceIBMIAMPolicyAssignment() *schema.Resource { return &schema.Resource{ CreateContext: resourceIBMPolicyAssignmentCreate, @@ -24,7 +33,11 @@ func ResourceIBMIAMPolicyAssignment() *schema.Resource { UpdateContext: resourceIBMPolicyAssignmentUpdate, DeleteContext: resourceIBMPolicyAssignmentDelete, Importer: &schema.ResourceImporter{}, - + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(30 * time.Minute), + Update: schema.DefaultTimeout(30 * time.Minute), + Delete: schema.DefaultTimeout(30 * time.Minute), + }, Schema: map[string]*schema.Schema{ "version": { Type: schema.TypeString, @@ -251,9 +264,9 @@ func resourceIBMPolicyAssignmentCreate(context context.Context, d *schema.Resour createPolicyTemplateAssignmentOptions := &iampolicymanagementv1.CreatePolicyTemplateAssignmentOptions{} createPolicyTemplateAssignmentOptions.SetVersion(d.Get("version").(string)) - targetModel, err := ResourceIBMPolicyAssignmentMapToAssignmentTargetDetails(d.Get("target").(map[string]interface{})) - if err != nil { - return diag.FromErr(err) + targetModel, diags := GetTargetModel(d) + if diags.HasError() { + return diags } createPolicyTemplateAssignmentOptions.SetTarget(targetModel) var templates []iampolicymanagementv1.AssignmentTemplateDetails @@ -278,6 +291,14 @@ func resourceIBMPolicyAssignmentCreate(context context.Context, d *schema.Resour d.SetId(*policyAssignmentV1Collection.Assignments[0].ID) + if targetModel.Type != nil && (*targetModel.Type == "Account") { + log.Printf("[DEBUG] Skipping waitForAssignment for target type: %s", *targetModel.Type) + } else { + _, err = waitForAssignment(d.Timeout(schema.TimeoutCreate), meta, d, isAccessPolicyAssigned) + if err != nil { + return diag.FromErr(fmt.Errorf("error assigning: %s", err)) + } + } return resourceIBMPolicyAssignmentRead(context, d, meta) } @@ -385,6 +406,12 @@ func resourceIBMPolicyAssignmentUpdate(context context.Context, d *schema.Resour updatePolicyAssignmentOptions.SetAssignmentID(d.Id()) + targetModel, diags := GetTargetModel(d) + + if diags.HasError() { + return diags + } + hasChange := false if d.HasChange("template_version") { @@ -416,6 +443,16 @@ func resourceIBMPolicyAssignmentUpdate(context context.Context, d *schema.Resour log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) return tfErr.GetDiag() } + + if targetModel.Type != nil && (*targetModel.Type == "Account") { + log.Printf("[DEBUG] Skipping waitForAssignment for target type: %s", *targetModel.Type) + } else { + _, err = waitForAssignment(d.Timeout(schema.TimeoutUpdate), meta, d, isAccessPolicyAssigned) + if err != nil { + return diag.FromErr(fmt.Errorf("error assigning: %s", err)) + } + } + } return resourceIBMPolicyAssignmentRead(context, d, meta) @@ -433,11 +470,34 @@ func resourceIBMPolicyAssignmentDelete(context context.Context, d *schema.Resour deletePolicyAssignmentOptions.SetAssignmentID(d.Id()) - _, err = iamPolicyManagementClient.DeletePolicyAssignmentWithContext(context, deletePolicyAssignmentOptions) + + response, err := iamPolicyManagementClient.DeletePolicyAssignmentWithContext(context, deletePolicyAssignmentOptions) if err != nil { - tfErr := flex.TerraformErrorf(err, fmt.Sprintf("DeletePolicyAssignmentWithContext failed: %s", err.Error()), "ibm_policy_assignment", "delete") - log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) - return tfErr.GetDiag() + if response != nil && response.StatusCode == 404 { + return nil + } else { + tfErr := flex.TerraformErrorf(err, fmt.Sprintf("DeletePolicyAssignmentWithContext failed: %s", err.Error()), "ibm_policy_assignment", "delete") + log.Printf("[DEBUG]\n%s", tfErr.GetDebugMessage()) + return tfErr.GetDiag() + } + } + + targetModel, diags := GetTargetModel(d) + if diags.HasError() { + return diags + } + + if targetModel.Type != nil && (*targetModel.Type == "Account") { + log.Printf("[DEBUG] Skipping waitForAssignment for target type: %s", *targetModel.Type) + } else { + _, err = waitForAssignment(d.Timeout(schema.TimeoutDelete), meta, d, isAccessPolicyAssignedDeleted) + if err != nil { + if strings.Contains(err.Error(), "not found") { + return nil + } else { + return diag.FromErr(fmt.Errorf("error assigning: %s", err)) + } + } } d.SetId("") @@ -477,3 +537,121 @@ func ResourceIBMPolicyAssignmentAssignmentTemplateDetailsToMap(model *iampolicym } return modelMap, nil } + +func GetTargetModel(d *schema.ResourceData) (*iampolicymanagementv1.AssignmentTargetDetails, diag.Diagnostics) { + targetModel, err := ResourceIBMPolicyAssignmentMapToAssignmentTargetDetails(d.Get("target").(map[string]interface{})) + + if err != nil { + return targetModel, diag.FromErr(err) + } + + return targetModel, nil +} + + +func waitForAssignment(timeout time.Duration, meta interface{}, d *schema.ResourceData, refreshFn func(string, interface{}) resource.StateRefreshFunc) (interface{}, error) { + + stateConf := &resource.StateChangeConf{ + Pending: []string{InProgress}, + Target: []string{complete}, + Refresh: refreshFn(d.Id(), meta), + Delay: 30 * time.Second, + PollInterval: time.Minute, + Timeout: timeout, + } + + return stateConf.WaitForState() +} + +func isAccessPolicyAssigned(id string, meta interface{}) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + iamPolicyManagementClient, err := meta.(conns.ClientSession).IAMPolicyManagementV1API() + if err != nil { + return nil, failed, err + } + + getAssignmentPolicyOptions := &iampolicymanagementv1.GetPolicyAssignmentOptions{ + AssignmentID: core.StringPtr(id), + Version: core.StringPtr("1.0"), + } + + getAssignmentPolicyOptions.SetAssignmentID(id) + + assignmentDetails, response, err := iamPolicyManagementClient.GetPolicyAssignment(getAssignmentPolicyOptions) + + if err != nil { + if response != nil && response.StatusCode == 404 { + return nil, failed, err + } + return nil, failed, err + } + + assignment, ok := assignmentDetails.(*iampolicymanagementv1.GetPolicyAssignmentResponse) + + if !ok { + return nil, failed, fmt.Errorf("[ERROR] Type assertion failed for assignment details : %s", id) + } + + if assignment != nil { + if *assignment.Status == "accepted" || *assignment.Status == "in_progress" { + log.Printf("Assignment still in progress\n") + return assignment, InProgress, nil + } + + if *assignment.Status == "succeeded" { + return assignment, complete, nil + } + + if *assignment.Status == "failed" { + return assignment, failed, fmt.Errorf("[ERROR] The assignment %s did not complete successfully and has a 'failed' status. Please check assignment resource for detailed errors: %s\n", id, response) + } + } + + return assignment, failed, fmt.Errorf("[ERROR] Unexpected status reached for assignment %s.: %s\n", id, response) + } +} + +func isAccessPolicyAssignedDeleted(id string, meta interface{}) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + iamPolicyManagementClient, err := meta.(conns.ClientSession).IAMPolicyManagementV1API() + if err != nil { + return nil, failed, err + } + + getAssignmentPolicyOptions := &iampolicymanagementv1.GetPolicyAssignmentOptions{ + AssignmentID: core.StringPtr(id), + Version: core.StringPtr("1.0"), + } + + getAssignmentPolicyOptions.SetAssignmentID(id) + + assignmentDetails, response, err := iamPolicyManagementClient.GetPolicyAssignment(getAssignmentPolicyOptions) + + if err != nil { + if response != nil && response.StatusCode == 404 { + return nil, failed, err + } + return nil, failed, err + } + + assignment, ok := assignmentDetails.(*iampolicymanagementv1.GetPolicyAssignmentResponse) + + if !ok { + return nil, failed, fmt.Errorf("[ERROR] Type assertion failed for assignment details : %s", id) + } + + + if assignment != nil { + if *assignment.Status == "accepted" || *assignment.Status == "in_progress" { + log.Printf("Assignment still in progress\n") + return assignment, InProgress, nil + } + + if *assignment.Status == "failed" { + return assignment, failed, fmt.Errorf("[ERROR] The assignment %s did not complete successfully and has a 'failed' status. Please check assignment resource for detailed errors: %s\n", id, response) + } + } + + return assignment, failed, fmt.Errorf("[ERROR] Unexpected status reached for assignment %s.: %s\n", id, response) + } +} diff --git a/ibm/service/iampolicy/resource_ibm_iam_policy_assignment_test.go b/ibm/service/iampolicy/resource_ibm_iam_policy_assignment_test.go index 925fe756b10..d6da6ad589f 100644 --- a/ibm/service/iampolicy/resource_ibm_iam_policy_assignment_test.go +++ b/ibm/service/iampolicy/resource_ibm_iam_policy_assignment_test.go @@ -46,6 +46,7 @@ func TestAccIBMPolicyAssignmentBasic(t *testing.T) { }) } + func TestAccIBMPolicyAssignmentS2SBasic(t *testing.T) { var conf iampolicymanagementv1.GetPolicyAssignmentResponse var name string = fmt.Sprintf("TerraformTemplateTest%d", acctest.RandIntRange(10, 100)) @@ -70,6 +71,27 @@ func TestAccIBMPolicyAssignmentS2SBasic(t *testing.T) { }) } +func TestAccIBMPolicyAssignmentEnterprise(t *testing.T) { + var conf iampolicymanagementv1.GetPolicyAssignmentResponse + var name string = fmt.Sprintf("TerraformTemplateTest%d", acctest.RandIntRange(10, 100)) + resource.Test(t, resource.TestCase{ + PreCheck: func() { acc.TestAccPreCheck(t) }, + Providers: acc.TestAccProviders, + CheckDestroy: testAccCheckIBMPolicyAssignmentDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckIBMPolicyAssignmentConfigEnterprise(name, acc.TargetEnterpriseId), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckIBMPolicyAssignmentExists("ibm_iam_policy_assignment.policy_assignment", conf), + resource.TestCheckResourceAttr("ibm_iam_policy_template.policy_s2s_template", "name", name), + resource.TestCheckResourceAttr("ibm_iam_policy_template.policy_s2s_template", "policy.0.resource.0.attributes.0.value", resourceServiceName), + resource.TestCheckResourceAttr("ibm_iam_policy_template.policy_s2s_template", "policy.0.subject.0.attributes.0.value", "compliance"), + ), + }, + }, + }) +} + func testAccCheckIBMPolicyAssignmentConfigBasic(name string, targetId string) string { return fmt.Sprintf(` resource "ibm_iam_policy_template" "policy_s2s_template" { @@ -215,8 +237,46 @@ func testAccCheckIBMPolicyAssignmentConfigUpdate(name string, targetId string) s } templates{ - id = ibm_iam_policy_template.policy_s2stemplate.template_id - version = ibm_iam_policy_template.policy_s2stemplate.version + id = ibm_iam_policy_template_version.template_version.template_id + version = ibm_iam_policy_template_version.template_version.version + } + }`, name, targetId) +} + +func testAccCheckIBMPolicyAssignmentConfigEnterprise(name string, targetId string) string { + return fmt.Sprintf(` + resource "ibm_iam_policy_template" "policy_s2s_template" { + name = "%s" + policy { + type = "authorization" + description = "description" + resource { + attributes { + key = "serviceName" + operator = "stringEquals" + value = "kms" + } + } + subject { + attributes { + key = "serviceName" + operator = "stringEquals" + value = "compliance" + } + } + roles = ["Reader"] + } + committed=true + } + resource "ibm_iam_policy_assignment" "policy_assignment" { + version = "1.0" + target ={ + type = "Enterprise" + id = "%s" + } + templates{ + id = ibm_iam_policy_template.policy_s2s_template.template_id + version = ibm_iam_policy_template.policy_s2s_template.version } }`, name, targetId) } diff --git a/website/docs/d/iam_policy_assignment.html.markdown b/website/docs/d/iam_policy_assignment.html.markdown index a309ddb4cf0..19bfcbce60d 100644 --- a/website/docs/d/iam_policy_assignment.html.markdown +++ b/website/docs/d/iam_policy_assignment.html.markdown @@ -19,6 +19,14 @@ data "ibm_iam_policy_assignments" "policy_assignment" { ## Argument Reference +## Timeouts section + +The resource includes default timeout settings for the following operations: + +* `create` - (Timeout) Defaults to 30 minutes. +* `update` - (Timeout) Defaults to 30 minutes. +* `delete` - (Timeout) Defaults to 30 minutes. + ## Attribute Reference diff --git a/website/docs/r/policy_assignment.html.markdown b/website/docs/r/policy_assignment.html.markdown index cea35cb8bc6..f65e3c172bd 100644 --- a/website/docs/r/policy_assignment.html.markdown +++ b/website/docs/r/policy_assignment.html.markdown @@ -73,6 +73,34 @@ resource "ibm_iam_policy_assignment" "policy_assignment" { } template_version=ibm_iam_policy_template_version.template_version.version } + +resource "ibm_iam_policy_assignment" "policy_assignment" { + version ="1.0" + target ={ + type = "Account Group" + id = "" + } + + templates{ + id = ibm_iam_policy_template.policy_s2s_template.template_id + version = ibm_iam_policy_template.policy_s2s_template.version + } + template_version=ibm_iam_policy_template_version.template_version.version +} + +resource "ibm_iam_policy_assignment" "policy_assignment" { + version ="1.0" + target ={ + type = "Enterprise" + id = "" + } + + templates{ + id = ibm_iam_policy_template.policy_s2s_template.template_id + version = ibm_iam_policy_template.policy_s2s_template.version + } + template_version=ibm_iam_policy_template_version.template_version.version +} ``` **Note**: Above configuration is to create policy template versions and assign to a target enterprise account. Update this parameter(***template_version***) and terraform apply again to update the assignment @@ -94,10 +122,18 @@ Nested schema for **target**: * `id` - (Required, String) ID of the target account. * Constraints: The maximum length is `32` characters. The minimum length is `1` character. The value must match regular expression `/^[A-Za-z0-9-]*$/`. * `type` - (Required, String) Assignment target type. - * Constraints: Allowable values are: `Account`. The maximum length is `30` characters. The minimum length is `1` character. + * Constraints: Allowable values are: `Account`, `Account Group` and `Enterprise`. The maximum length is `30` characters. The minimum length is `1` character. * `version` - (Required, String) specify version of response body format. * Constraints: Allowable values are: `1.0`. The minimum length is `1` character. +## Timeouts section + +The resource includes default timeout settings for the following operations: + +* `create` - (Timeout) Defaults to 30 minutes. +* `update` - (Timeout) Defaults to 30 minutes. +* `delete` - (Timeout) Defaults to 30 minutes. + ## Attribute Reference After your resource is created, you can read values from the listed arguments and the following attributes.