How to create an aws sagemaker project using terraform? - amazon-web-services

This is the terraform shown in the docs:
resource "aws_sagemaker_project" "example" {
project_name = "example"
service_catalog_provisioning_details {
product_id = aws_servicecatalog_product.example.id
}
}
I created a service catalog product with id: "prod-xxxxxxxxxxxxx".
When I substitute the service catalog product id into the above template,
to get the following:
resource "aws_sagemaker_project" "example" {
project_name = "example"
service_catalog_provisioning_details {
product_id = aws_servicecatalog_product.prod-xxxxxxxxxxxxx
}
}
I run terraform plan, but the following error occurs:
A managed resource "aws_servicecatalog_product" "prod-xxxxxxxxxxxxx" has not been declared in the root module.
What do I need to do to fix this error?

Since the documentation is lacking a bit of clarity, in order to have this work as in the example, you would first have to create the Service Catalog product in Terraform as well, e.g.:
resource "aws_servicecatalog_product" "example" {
name = "example"
owner = [aws_security_group.example.id] # <---- This would need to be created first
type = aws_subnet.main.id # <---- This would need to be created first
provisioning_artifact_parameters {
template_url = "https://s3.amazonaws.com/cf-templates-ozkq9d3hgiq2-us-east-1/temp1.json"
}
tags = {
foo = "bar"
}
}
You can reference it then in the SageMaker project the same way as in the example:
resource "aws_sagemaker_project" "example" {
project_name = "example"
service_catalog_provisioning_details {
product_id = aws_servicecatalog_product.example.id
}
}
Each of the resources that gets created has a set of attributes that can be accessed as needed by other resources, data sources or outputs. In order to understand how this works, I strongly suggest reading the documentation about referencing values [1]. Since you already created the Service Catalog product, the only thing you need to do is provide the string value for the product ID:
resource "aws_sagemaker_project" "example" {
project_name = "example"
service_catalog_provisioning_details {
product_id = "prod-xxxxxxxxxxxxx"
}
}
When I can't understand what value is expected by an argument (e.g., product_id in this case), I usually read the docs and look for examples like in [2]. Note: That example is CloudFormation, but it can help you understand what type of a value is expected (e.g., string, number, bool).
You could also import the created Service Catalog product into Terraform so you can manage it with IaC [3]. You should understand all the implications of terraform import though before trying it [4].
[1] https://www.terraform.io/language/expressions/references
[2] https://docs.amazonaws.cn/en_us/AWSCloudFormation/latest/UserGuide/aws-resource-sagemaker-project.html#aws-resource-sagemaker-project--examples--SageMaker_Project_Example
[3] https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/servicecatalog_product#import
[4] https://www.terraform.io/cli/commands/import

Related

Terraform recreates BQ Dataset access resource every time there are changes in the plan

I manage my BQ infrastructure through Terraform.
I recently found out about the google_bigquery_dataset_access resource, which can be used to either grant access to a dataset to every resource of a specific type, or individually grant access for views.
So I implemented this in my foo dataset module
dataset.tf:
resource "google_bigquery_dataset_access" "dataset_authorization" {
dataset_id = "foo"
dataset {
dataset {
project_id = "some-project"
dataset_id = "bar"
}
target_types = ["VIEWS"]
}
}
module "foo_dataset" {
source = <path to google provider google_bigquery_dataset>
version = "some_version"
dataset_id = "foo"
description = "lorem ipsum"
location = "some_location"
project = "some-project"
}
But every single time there is a change anywhere in my configuration (not even just in this foo module), TF plan says there's been changes to the access resource and it will try to recreate it:
Terraform apply output
# module.foo.module.foo_dataset.google_bigquery_dataset.dataset has changed
~ resource "google_bigquery_dataset" "dataset" {
~ etag = "VH7HJLt5Avl4zcT1spXxtA==" -> "ZQFENhnM/wOpJrgaccOfgQ=="
id = "some-project:foo"
~ last_modified_time = 1667311213019 -> 1667312336825
The etag and last_modified_time change even if no changes were done on the module.
Does anyone know what might be going on here?

error creating SageMaker project in terraform because service catalog product "does not exist or access was denied"

I have a product with id: prod-xxxxxxxxxxxx. I have checked that it exists in aws service catalog. However, when I try to create an aws_sagemaker_project using terraform:
resource "aws_sagemaker_project" "test-project" {
project_name = "test-project"
service_catalog_provisioning_details {
product_id = "prod-xxxxxxxxxxxx"
}
}
I get the error: "error creating SageMaker project: ValidationException: Product prod-xxxxxxxxxxxx does not exist or access was denied". How do I ensure that I can access this product?
Do I need a launch constraint for this product, and to grant access to the portfolio to end users as described here: https://docs.aws.amazon.com/sagemaker/latest/dg/sagemaker-projects-templates-custom.html?
You need to aws_servicecatalog_product terraform state to refer to product_id.
resource "aws_servicecatalog_product" "example" {
name = "example"
owner = [aws_security_group.example.id]
type = aws_subnet.main.id
provisioning_artifact_parameters {
template_url = "https://s3.amazonaws.com/cf-templates-ozkq9d3hgiq2-us-east-1/temp1.json"
}
tags = {
foo = "bar"
}
}
resource "aws_sagemaker_project" "example" {
project_name = "example"
service_catalog_provisioning_details {
product_id = aws_servicecatalog_product.example.id
}
}
This error means that you haven't granted access to the service catalog's portfolio to your terraform IAM principal/user/role. Basically you are unable to "see" the product based on the end user section of the service catalog portfolio.
You can fix this by adding the following Servicecatalog resources
resource "aws_servicecatalog_principal_portfolio_association" "project" {
portfolio_id = aws_servicecatalog_portfolio.portfolio.id
principal_arn = "${ROLE_ARN}"
}
resource "aws_servicecatalog_portfolio" "portfolio" {
name = "My App Portfolio"
description = "List of my organizations apps"
provider_name = "Brett"
}
resource "aws_servicecatalog_product_portfolio_association" "example" {
portfolio_id = aws_servicecatalog_portfolio.portfolio.id
product_id = "prod-xxxxxxxxxxxx"
}

build resources based on variable count

may I ask if there is a way to build an aws resource using Terraform v0.14.10 base from the count of the defined variables and use the name of the variable as part of the name of the created ECR resource. Its like I want to build ECR repo and it should be 3 of them coz of the variables I used has 3 and use the name as the repo name like as below:
Results of ECR build creation
app1.repo
pogi2.repo
panget3.repo
Terraform Code:
MY.TF
variable RESOURCE_NAME { type = map }
locals {
RESOURCE_NAME = "${var.app-name}-repo"
}
resource "aws_ecr_repository" "myrepo" {
name = local.RESOURCE_NAME
}
VAR.tfvars
app-name = [ "app1", "pogi2", "panget3" ]
You can do that as follows:
resource "aws_ecr_repository" "myrepo" {
for_each = toset(var.app-name)
name = "${each.key}.repo"
}

How can I use var in resource calling

I'm importing roles which already have been created in AWS console and unfortunately the names are strange. So in order to use those roles I am trying like this
I've two IAM roles as follows
data "aws_iam_role" "reithera-rtcov201" {
name = "exomcloudrosareitherartcov-YRX1M2GJKD6H"
}
data "aws_iam_role" "dompe-rlx0120" {
name = "exomcloudrosadomperlx0120p-1SCGY0RG5JXFF"
}
In this file I have 2 variables as follows:
sponsor = ["reithera", "dompe"]
study = ["rtcov201", "rlx0120"]
I'm trying in the following way, but terraform doesn't allow to use $.
data.aws_iam_role.${var.sponsor}-${var.study}.arn
Do you know any solution for this.
Its not possible. You can dynamically create references to resources.
Instead of two separate data sources you should create one:
variable "iam_roles"
default = ["exomcloudrosareitherartcov-YRX1M2GJKD6H", "exomcloudrosadomperlx0120p-1SCGY0RG5JXFF"]
}
and then
data "aws_iam_role" "role" {
for_each = toset(var.iam_roles)
name = each.key
}
and you can refer to them using role name:
data.aws_iam_role["exomcloudrosareitherartcov-YRX1M2GJKD6H"].arn

how to refer GCP resources in terraform?

I would like to understand about the resources reference in terraform.
Example:
In my project, pubsub topic has been referred with .name as well as .id
resource "google_pubsub_topic" "topic" {
name = "my_topic"
}
resource "google_pubsub_subscription" "subscription" {
name = "my_subscription"
topic = google_pubsub_topic.topic.name
}
resource "google_cloudiot_registry" "cloudiot" {
name = "my_iot_registry"
region = "us-central1"
log_level = "ERROR"
event_notification_configs {
pubsub_topic_name = google_pubsub_topic.topic.id
}
mqtt_config = {
mqtt_enabled_state = "MQTT_ENABLED"
}
}
I could not get the information the difference in referring by .name/.id from many online forums.
For which resources using terraform we need to refer by .name and .id?
There is no such hard referring notion, it appears to be an anomaly with usage specific to this resource.
I guess it needs to be
event_notification_configs {
pubsub_topic_id = google_pubsub_topic.topic.id
}
From google_cloudiot_registry, I see id being returned by the resource which contains the resource name & the same is being passed to pubsub_topic_name part of event_notification_configs block.
If you wish to change pubsub_topic_name to pubsub_topic_id, you could create PR on the provider code base.
To conclude, if you would like to refer output of some resource/data source, you would need to fetch the attributes returned in the response & assign it to appropriate field in the next resource.