I have created the following simple schema:
insert
name sub resource datatype string;
id sub resource datatype string;
person sub entity has name has id;
and data:
insert
$x isa person has name "Bob" has id bob;
How can I get all the resources I have attached to an entity? Do I have to iterate over all of them?
You can get all the resources by querying the root resource like so:
match $x has resource $y;
Related
I have a bunch of files that are published to an S3 bucket managed using the terraform script below. To make file tracking easy, I used a combination of for_each when declaring an aws_s3_object and fileset() to grab the list of files from my local volume.
I want to create an SSM Parameter that contains a common separated string of the list of files that I have published to S3 using the aws_s3_object (ie: "scripts/app/script1.py, scripts/app/script2.py, scripts/app/script3.py")
My approach to this problem is to use a combination of locals block and for statement to iterate over each key of aws_s3_object.app_files map
and construct the string, but I can't figure out how to write this for statement as the examples from the documentation seem to suggest that the results of the for statement will result in a list or object and not a string.
Is it even possible to do this? And if so, how can this be achieved?
resource "aws_s3_object" "app_files" {
for_each = fileset("scripts/", "**.py")
bucket = "myBucket"
key = "dev/app/${each.value}"
server_side_encryption = "aws:kms"
bucket_key_enabled = true
source = "scripts/${each.value}"
source_hash = filemd5("scripts/${each.value}")
tags = {
Name = each.value
}
}
The easiest would be to use join:
locals {
joined_keys = join(",", keys(aws_s3_object.app_files))
}
Sometimes, json string may be more useful:
locals {
joined_keys_json = jsonencode(keys(aws_s3_object.app_files))
}
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
I want to create a resource group in AWS inspector with terraform, that has few tags with key "Name" and different values. I can do this with AWS GUI, but I Want to do it in terraform also. If I do it like in the example below, it will just override the name..
resource "aws_inspector_resource_group" "bar" {
tags = {
Name = "Master"
Name = "UF"
}
}
Could you please try the following:
resource "aws_inspector_resource_group" "bar" {
tags = {
Name = ["Master", "UF"]
}
}
If that doesn't work you could just use the aws_ec2_tag resource:
https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ec2_tag
Should do the job
I want access to my AWS Account ID in terraform. I am able to get at it with aws_caller_identity per the documentation. How do I then use the variable I created? In the below case I am trying to use it in an S3 bucket name:
data "aws_caller_identity" "current" {}
output "account_id" {
value = data.aws_caller_identity.current.account_id
}
resource "aws_s3_bucket" "test-bucket" {
bucket = "test-bucket-${account_id}"
}
Trying to use the account_id variable in this way gives me the error A reference to a resource type must be followed by at least one attribute access, specifying the resource name. I expect I'm not calling it correctly?
If you have a
data "aws_caller_identity" "current" {}
then you need to define a local for that value:
locals {
account_id = data.aws_caller_identity.current.account_id
}
and then use it like
output "account_id" {
value = local.account_id
}
resource "aws_s3_bucket" "test-bucket" {
bucket = "test-bucket-${local.account_id}"
}
Terraform resolves the locals based on their dependencies so you can create locals that depend on other locals, on resources, on data blocks, etc.
Any time you create a datasource in terraform , it will export some attributes related to that datasource so that you can reference it somewhere else in your configuration and interpolate it with various ways.
In your case, you are already referencing the value of your account id in output block
So that same way, you can construct the string for the bucket name as follows.
resource "aws_s3_bucket" "test-bucket" {
bucket = "test-bucket-${data.aws_caller_identity.current.account_id}"
}
I would highly recommend you go through the terrraform syntax which can help you better understand the resource, datasource and expressions
https://www.terraform.io/docs/language/expressions/references.html
We want to get away from using incremental numbers for the host names of our instances. These machines are not in an auto-scaling group, hence we could keep the prod-webserver-001, prod-webserver-002 etc convention if we wanted but it just doesn't make sense with tags being available.
What we've been doing with auto-scaling groups, we want to utilize parts of the instance id. I'm able to accomplish this with a post script with our ASG servers but unlike that, I want Terraform to keep track of the DNS record so that they get destroyed when I issue a terraform destroy.
Ideally we want the first six characters after the hyphen in the instance_id. For example if the instance_id is i-0876cr2456 we want to use 0876cr within the name.
prod-webserver-0876cr
prod-webserver-09a24i
Terraform code:
resource "aws_instance" "instance" {
...
...
}
resource "aws_route53_record" "instance_dns_a" {
count = "${var.num_instances}"
zone_id = "${var.internal_zone_id}"
# New line but we want the parsed version
name = "${aws_instance.instance.id}"
# old that works
name = "${format(prod-${service_name}-%03d", count.index + 1)}"
}
You could extract the first 6 characters from the instance id by using substr:
$ terraform console
> substr("i-123456adgcgabsadh", 2, 6)
123456
So to use it in your Route53 record you'd want to use something like:
resource "aws_instance" "instance" {
...
...
}
resource "aws_route53_record" "instance_dns_a" {
count = "${var.num_instances}"
zone_id = "${var.internal_zone_id}"
name = "prod-${var.service_name}-${substr(aws_instance.instance.*.id[count.index], 2, 6}"
}
I would be worried about truncating the instance ID for something that needs to be unique though because you will then inevitably end up with instances with ids of i-123456a... and i-123456b and then you'll end up overwriting the prod-webserver-123456 record with the IP address of the second instance and losing the first record. Any reason you need to truncate here? You have 63 characters to play with for the first label in DNS which should be enough to leave this untruncated no?