How to set Cargo configurable-env setting for specific profile? - rust

I'm trying to find out if it is possible to use configurable-env Cargo feature to set environment variables specific to a certain profile.
# Instead of global version:
# [env]
# FOO_QTY = "10"
# Something similar to the following(pseudocode):
[profile.test.env]
FOO_QTY = "2"
[profile.release.env]
FOO_QTY = "1000"

Not exactly your question, but you can create a static or const that's set based on the profile.
pub const FOO_QTY: usize = if cfg!(build = "release") {
1000
} else {
2
};
Presumably you're trying to conditionally configure some value or behavior (at least that's how I found this question). The cfg! macro is a more flexible way to do that.

Related

Using alias for referenced variables in capture list of lambda?

With a lambda, is it not possible to use an alias for a variable that is in the capture list (by reference)?
auto AddSlip = [rFile = &fileCSV](COleDateTime datMeeting)
{
}
That won't work.
With a lambda, is it not possible to use an alias for a variable that is in the capture list (by reference)?
Yes: it's possible. Starting from C++14.
Not in your way
auto AddSlip = [rFile = &fileCSV](COleDateTime datMeeting)
because rFile become the copy of the pointer to fileCSV; the syntax you're looking for is the following
auto AddSlip = [&rFile = fileCSV](COleDateTime datMeeting)
or, if you want a const reference,
auto AddSlip = [&rFile = std::as_const(fileCSV)](COleDateTime datMeeting)

TF: Loop through map with lookup and set variable accordingly

I have a map with some environment ID's as the key, then keywords as the values in a list.
variable "environments" {
type = map(list(string))
default = {
"env-one" = ["dev", "test", "stage", "staging"],
"env-two" = ["prod", "production", "live"]
}
}
I'm looking to use this to set the environment name based on the value of var.context["stage"].
So, if var.context["stage"] is equal to staging the value of environment will be dev
I was initially thinking to use lookup(), something like;
environment = "${lookup(var.environments, var.context["stage"])}"
However, I realise that's looking up the wrong way (finding the value as opposed to the key), and also it won't work as part of a map. So presumably I need to look through the map and run the lookup (albeit) backwards(?) on each iteration?
You would want to restructure the type into map(string). Then it would follow that the value would be:
{
"dev" = "env-one",
"test" = "env-one",
"stage" = "env-one",
"staging" = "env-one",
"prod" = "env-two",
"production" = "env-two",
"live" = "env-two"
}
You could also modify this to be map(object) to contain more information. Based on the usage described in the question, this would actually make more sense to be a local. If you were to place this data into a locals block named environments, then the key-value pair could be accessed (according to the question) like local.environments[var.context["stage"]].

Pattern for templating arguments for existing Terraform resources

I'm using the Terraform GitHub provider to define GitHub repositories for an internal GitHub Enterprise instance (although the question isn't provider-specific).
The existing github_repository resource works fine, but I'd like to be able to set non-standard defaults for some of its arguments, and easily group other arguments under a single new argument.
e.g.
github_repository's private value defaults to false but I'd like to default to true
Many repos will only want to allow squash merges, so having a squash_merge_only parameter which sets allow_squash_merge = true, allow_rebase_merge = false, allow_merge_commit = false
There are more cases but these illustrate the point. The intention is to make it simple for people to configure new repos correctly and to avoid having large amounts of config repeated across every repo.
I can achieve this by passing variables into a custom module, e.g. something along the lines of:
Foo/custom_repo/main.tf:
resource "github_repository" "custom_repo" {
name = ${var.repo_name}
private = true
allow_squash_merge = true
allow_merge_commit = ${var.squash_merge_only ? false : true}
allow_rebase_merge = ${var.squash_merge_only ? false : true}
}
Foo/main.tf:
provider "github" {
...
}
module "MyRepo_module" {
source = "./custom_repo"
repo_name = "MyRepo"
squash_merge_only = true
}
This is a bit rubbish though, as I have to add a variable for every other argument on github_repository that people using the custom_repo module might want to set (which is basically all of them - I'm not trying to restrict what people are allowed to do) - see name and repo_name on the example. This all then needs documenting separately, which is also a shame given that there are good docs for the existing provider.
Is there a better pattern for reusing existing resources like this but having some control over how arguments get passed to them?
We created an opinionated module (terraform 0.12+) for this at https://github.com/mineiros-io/terraform-github-repository
We set all the defaults to values we think fit best, but basically you can create a set of local defaults and reuse them when calling the module multiple times.
fun fact... your desired defaults are already the module's default right away, but to be clear how to set those explicitly here is an example (untested):
locals {
my_defaults = {
# actually already the modules default to create private repositories
private = true
# also the modules default already and
# all other strategies are disabled by default
allow_squash_merge = true
}
}
module "repository" {
source = "mineiros-io/repository/github"
version = "0.4.0"
name = "my_new_repository"
defaults = local.my_defaults
}
not all arguments are supported as defaults yet, buts most are: https://github.com/mineiros-io/terraform-github-repository#defaults-object-attributes

How do you create scalar arrays/lists in Terraform?

myvar should be a list of security groups.
variable "myvar" {
default = null
}
If users specify it that list is concatenated with the default security group (pulled in from the data source).
If it's not specified just use the default security group.
This is not working:
local {
test = var.myvar != null ? concat(tolist(data.aws_security_group.data.id), var.myvar) : tolist(data.aws_security_group.data.id)
}
But this does work:
aaa = var.myvar != null ? concat(["aaaa"], ["bbbbb","ccccccc"]) : ["aaaa"]
So how to I convert a string to a scalar array/list? It seems like that's what Terraform needs and tolist() is not working.
Based on the given requirements, I think the most straightforward solution would be to set the default for the variable to [] and avoid the need for conditionals at all:
variable "additional_security_group_ids" {
type = list(string)
default = []
}
locals {
security_group_ids = concat(
[data.aws_security_group.default.id],
var.additional_security_group_ids,
)
}
Concatenating an empty list just produces the same list, so leaving the variable unset in the above would cause local.security_group_ids to contain only the default security group id.
Setting the default to null is useful when the absence of a value for that variable disables some feature entirely, or if the logic you need can't be conveniently expressed via defaults, but I'd always recommend using specific default values where possible because the result will tend to be easier to read and understand for future maintainers.
Is this what you're looking for?
value = var.myvar != null ? concat([data.aws_security_group.data.id], var.myvar) : [data.aws_security_group.data.id]
Proposing this as answer, but hoping there is a less crazy way
local {
test = var.myvar != null ? flatten(concat(tolist([data.aws_security_group.data.id]), [var.myvar])) : tolist([data.aws_security_group.data.id])
}

Is it possible to generate a variable name in terraform

So i want to get the variable in the terraform remote state, however we have a number of different one per environment on the shared route53
So for a given environement, we want to pull the zone id out as such;
zone_id = data.terraform_remote_state.route_53.route53_zone_${var.environment}_id
How would I do this please.
In general, it is not possible to use arbitrary dynamic strings as variable names.
However, in this particular case the outputs from terraform_remote_state are collection values and so you can use the index syntax to access a dynamically-built key from your map value:
data.terraform_remote_state.outputs.route53["route53_zone_${var.environment}_id"]
With that said, if possible I would recommend structuring the output values better so that the Route53 zone ids are given as a map by environment, so that this can be obtained in a more intuitive way.
For example, you could make your route53 output be a map of objects whose keys are the environment names:
data.terraform_remote_state.outputs.route53[var.environment].zone_id
output "route53" {
value = tomap({
production = {
zone_id = aws_route53_zone.production.id
}
staging = {
zone_id = aws_route53_zone.staging.id
}
})
}
Or, if you have a variety of different per-environment settings you could structure it as a single output value that is a map of all of those per environment settings keyed by environment name:
data.terraform_remote_state.outputs.environments[var.environment].route53_zone_id
output "environments" {
value = tomap({
production = {
ec2_vpc_id = aws_vpc.production.id
route53_zone_id = aws_route53_zone.production.id
}
staging = {
ec2_vpc_id = aws_vpc.staging.id
route53_zone_id = aws_route53_zone.staging.id
}
})
}
This doesn't change anything about the ultimate result, but grouping things by your environment keys in your outputs is likely to make your intent clearer to future maintainers of these configurations.
(You might also consider whether it'd be better to have a separate configuration/state per environment rather than managing them altogether, but that is a big topic in itself.)

Resources