The code below is working. I would like the template content to be in a separate file and not within main.tf. I tried using the templatefile method but without success. At the end I show what I tried. Maybe it's the way I set up the metric_info variable, or it's necessary to reformulate the template after I implement the templatefile function.
main.tf:
locals {
# Base variables
base_vars = yamldecode(file("env/${var.working_env}/vars.yaml")) # TF_VAR_working_env
# Metrics subfolder names
metrics = distinct([
for dir_path in fileset("../metrics-table/", "*/*/") :
basename(dirname(dir_path))
])
# Metrics configuration
metrics_config = flatten([
for subfolder in local.metrics :
[
for file in fileset("../metrics-table/${subfolder}", "metrics.yaml") :
merge(yamldecode(file("../metrics-table/${subfolder}/${file}")), { subfolder = subfolder })
]
])
# Metrics info
metric_info = [
{
metrics = merge([
for metric_config in local.metrics_config :
{
for metric_name, metric_data in metric_config.metrics :
metric_name => {
name = metric_data.name
metric_table = metric_config.metric_table
numerator = metric_data.numerator
denominator = metric_data.denominator
}
}
]...)
}
]
}
# TEMPLATE ALL_METRICS.SQL
data "template_file" "all_metrics_sql" {
template = <<EOT
# Parte 1 do arquivo SQL
-- BEGIN Parte 1 do arquivo SQL
WITH
%{ for metric_info in local.metric_info }
%{ for metric_name, metric_data in metric_info.metrics }
${metric_name} AS (
SELECT
date,
'${metric_name}' AS metric_name,
experiment,
alternative,
context_id,
control,
CASE
WHEN version IS NULL THEN 'v1'
ELSE version
END AS version,
device_group,
platform,
SUM(${metric_data.denominator}) AS denominator,
SUM(${metric_data.numerator}) AS numerator,
SAFE_DIVIDE(SUM(${metric_data.numerator}), SUM(${metric_data.denominator})) AS metric_value
FROM `${local.base_vars.project}.ab_experiment_metrics.${metric_data.metric_table}`
WHERE outlier = FALSE
GROUP BY
date,
experiment,
alternative,
context_id,
control,
version,
device_group,
platform,
metric_name
),
%{ endfor }
%{ endfor }
-- END Parte 1 do arquivo SQL
# Parte 2 do arquivo SQL
-- BEGIN Parte 2 do arquivo SQL
all_metrics AS (
SELECT * FROM conversion_rate
%{ for metric_info in local.metric_info }
%{ for metric_name, _ in metric_info.metrics }
UNION ALL
SELECT * FROM ${metric_name}
%{ endfor }
%{ endfor }
),
all_metrics_final as
(
SELECT
date,
metric_name,
all_metrics.experiment,
alternative,
control,
version,
device_group,
platform,
denominator,
SUM(denominator) OVER (PARTITION BY metric_name, all_metrics.experiment, alternative, version, device_group, platform ORDER BY date ASC ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS denominator_cumsum,
numerator,
SUM(numerator) OVER (PARTITION BY metric_name, all_metrics.experiment, alternative, version, device_group, platform ORDER BY date ASC ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS numerator_cumsum,
metric_value
FROM all_metrics
)
SELECT *
FROM all_metrics_final
-- END Parte 2 do arquivo SQL
EOT
}
# CREATE ALL_METRICS.SQL
resource "local_file" "all_metrics_sql" {
filename = "all_metrics.sql"
content = data.template_file.all_metrics_sql.rendered
}
# OUTPUTS
output "metrics_config" {
value = local.metrics_config
}
output "metric_info" {
value = local.metric_info
}
output "all_metrics_sql_content" {
value = data.template_file.all_metrics_sql.rendered
}
Changes to Outputs:
+ metric_info = [
+ {
+ metrics = {
+ time_to_first_play_per_login = {
+ denominator = "experiment_login_count"
+ metric_table = "time_to_first_play"
+ name = "time_to_first_play_per_login"
+ numerator = "total_time_to_first_play"
}
+ time_to_first_play_per_session = {
+ denominator = "experiment_session_count"
+ metric_table = "time_to_first_play"
+ name = "time_to_first_play_per_session"
+ numerator = "total_time_to_first_play"
}
+ time_to_first_play_per_user = {
+ denominator = "experiment_user_count"
+ metric_table = "time_to_first_play"
+ name = "time_to_first_play_per_user"
+ numerator = "total_time_to_first_play"
}
+ time_to_second_play_per_creator = {
+ denominator = "experiment_user_count"
+ metric_table = "time_to_second_play"
+ name = "time_to_second_play_per_user"
+ numerator = "total_time_to_second_play"
}
+ time_to_second_play_per_login = {
+ denominator = "experiment_user_count"
+ metric_table = "time_to_second_play"
+ name = "time_to_second_play_per_user"
+ numerator = "total_time_to_second_play"
}
+ time_to_second_play_per_name = {
+ denominator = "experiment_session_count"
+ metric_table = "time_to_second_play"
+ name = "time_to_second_play_per_session"
+ numerator = "total_time_to_second_play"
}
}
},
]
+ metrics_config = [
+ {
+ metric_table = "time_to_first_play"
+ metrics = {
+ time_to_first_play_per_login = {
+ active = 1
+ category = "Métrica de vídeo"
+ denominator = "experiment_login_count"
+ description = "Tempo médio que cada usuário leva para dar o primeiro play em algum vídeo"
+ metric_title = "Tempo para o Primeiro Play por Usuário"
+ metric_type_id = 2
+ name = "time_to_first_play_per_login"
+ numerator = "total_time_to_first_play"
}
+ time_to_first_play_per_session = {
+ active = 1
+ category = "Métrica de vídeo"
+ denominator = "experiment_session_count"
+ description = "Tempo médio que cada sessão leva para dar o primeiro play em algum vídeo"
+ metric_title = "Tempo para o Primeiro Play por Sessão"
+ metric_type_id = 2
+ name = "time_to_first_play_per_session"
+ numerator = "total_time_to_first_play"
}
+ time_to_first_play_per_user = {
+ active = 1
+ category = "Métrica de vídeo"
+ denominator = "experiment_user_count"
+ description = "Tempo médio que cada usuário leva para dar o primeiro play em algum vídeo"
+ metric_title = "Tempo para o Primeiro Play por Usuário"
+ metric_type_id = 2
+ name = "time_to_first_play_per_user"
+ numerator = "total_time_to_first_play"
}
}
+ subfolder = "time_to_first_play"
},
+ {
+ metric_table = "time_to_second_play"
+ metrics = {
+ time_to_second_play_per_creator = {
+ active = 1
+ category = "Métrica de vídeo"
+ denominator = "experiment_user_count"
+ description = "Tempo médio que cada usuário leva para dar o primeiro play em algum vídeo"
+ metric_title = "Tempo para o Primeiro Play por Usuário"
+ metric_type_id = 2
+ name = "time_to_second_play_per_user"
+ numerator = "total_time_to_second_play"
}
+ time_to_second_play_per_login = {
+ active = 1
+ category = "Métrica de vídeo"
+ denominator = "experiment_user_count"
+ description = "Tempo médio que cada usuário leva para dar o primeiro play em algum vídeo"
+ metric_title = "Tempo para o Primeiro Play por Usuário"
+ metric_type_id = 2
+ name = "time_to_second_play_per_user"
+ numerator = "total_time_to_second_play"
}
+ time_to_second_play_per_name = {
+ active = 1
+ category = "Métrica de vídeo"
+ denominator = "experiment_session_count"
+ description = "Tempo médio que cada sessão leva para dar o primeiro play em algum vídeo"
+ metric_title = "Tempo para o Primeiro Play por Sessão"
+ metric_type_id = 2
+ name = "time_to_second_play_per_session"
+ numerator = "total_time_to_second_play"
}
}
+ subfolder = "time_to_second_play"
},
]
I tried to use the method below but return erros.
data "template_file" "all_metrics_sql" {
template = templatefile("${path.module}/template.tftpl", {
metric_info = local.metric_info.metrics
})
}
╷
│ Error: Not enough function arguments
│
│ on main.tf line 69, in data "template_file" "all_metrics_sql":
│ 69: template = templatefile("arquivo_template.tpl")
│
│ Function "templatefile" expects 2 argument(s). Missing value for
│ "vars".
╵
╷
│ Error: Unsupported attribute
│
│ on main.tf line 72, in data "template_file" "all_metrics_sql":
│ 72: metric_info = local.metric_info.metrics
│ ├────────────────
│ │ local.metric_info is tuple with 1 element
│
│ This value does not have any attributes.
You are using both the deprecated
template_file
data source and thetemplatefile
function at the same time. These both perform the same operation, so it is incorrect to use them together.You can use the
templatefile
function alone. You should never need to use thetemplate_file
data source in modern Terraform; it exists to support very old versions of Terraform that didn't have thetemplatefile
function yet.The above assigns the result of template rendering directly to a resource argument, which is a concise way to write it when you only need the template result in one part of your configuration. If you want to reuse that template result in multiple locations then you can optionally assign its result to a local value: