Terraform iterate over nested map from module - foreach

I'm fairly new to Terraform, and I'm struggling trying to design a module to create Monitor Alerts in Azure.
I've essentially created a module that will generate alerts based on a nested map passed in from my storage-account-alerts.tf file. However I'm receiving errors saying all of the required arguments are missing. I've tried a few different things, but from my understanding this should work? I've declared the variables in the variables.tf file as well.
module "storage-account-alerts" {
source = "../modules/az-monitor-alerts"
alerts = local.alerts
}
locals {
alerts = {
SA_average_availability = {
name = "Test Name"
scope = var.sa_avg_availability_tp2_scope
description = "Test description"
action_group_id = azurerm_monitor_action_group.ag["Test-ag-1"].id
severity = 1
frequency = "PT5M"
window_size = "PT15M"
criteria = [{
metric_namespace = "Microsoft.Storage/storageAccounts"
metric_name = "Availability"
aggregation = "Average"
operator = "LessThan"
threshold = 100
}]
target_resource_type = "Microsoft.Storage/storageAccounts"
target_resource_location = "canadacentral"
}
}
}
And the module itself looks like this:
resource "azurerm_monitor_metric_alert" "alert" {
for_each = var.alerts
name = each.value.name
resource_group_name = var.resource_group_name
scopes = each.value.scope
description = each.value.description
severity = each.value.severity
frequency = each.value.frequency
window_size = each.value.window_size
target_resource_type = try(each.value.target_resource_type, "")
target_resource_location = try(each.value.target_resource_location, "")
dynamic "criteria" {
for_each = each.value.criteria
content {
metric_namespace = criteria.value.metric_namespace
metric_name = criteria.value.metric_name
aggregation = criteria.value.aggregation
operator = criteria.value.operator
threshold = criteria.value.threshold
skip_metric_validation = true
dynamic "dimension" {
for_each = try(criteria.value.dimensions, [])
content {
name = dimension.value.name
operator = dimension.value.operator
values = dimension.value.values
}
}
}
}
action {
action_group_id = each.value.action_group_id
}
}
Edit: Added errors
│ Error: Missing required argument
│
│ on storage-account-alerts.tf line 1, in module "storage-account-alerts":
│ 1: module "storage-account-alerts" {
│
│ The argument "action_group_id" is required, but no definition was found.
╵
╷
│ Error: Missing required argument
│
│ on storage-account-alerts.tf line 1, in module "storage-account-alerts":
│ 1: module "storage-account-alerts" {
│
│ The argument "name" is required, but no definition was found.
╵
╷
│ Error: Missing required argument
│
│ on storage-account-alerts.tf line 1, in module "storage-account-alerts":
│ 1: module "storage-account-alerts" {
│
│ The argument "target_resource_location" is required, but no definition was found.
╵
╷
│ Error: Missing required argument
│
│ on storage-account-alerts.tf line 1, in module "storage-account-alerts":
│ 1: module "storage-account-alerts" {
│
│ The argument "frequency" is required, but no definition was found.
╵
╷
│ Error: Missing required argument
│
│ on storage-account-alerts.tf line 1, in module "storage-account-alerts":
│ 1: module "storage-account-alerts" {
│
│ The argument "window_size" is required, but no definition was found.
╵
╷
│ Error: Missing required argument
│
│ on storage-account-alerts.tf line 1, in module "storage-account-alerts":
│ 1: module "storage-account-alerts" {
│
│ The argument "target_resource_type" is required, but no definition was found.
╵
╷
│ Error: Missing required argument
│
│ on storage-account-alerts.tf line 1, in module "storage-account-alerts":
│ 1: module "storage-account-alerts" {
│
│ The argument "resource_group_name" is required, but no definition was found.
╵
╷
│ Error: Missing required argument
│
│ on storage-account-alerts.tf line 1, in module "storage-account-alerts":
│ 1: module "storage-account-alerts" {
│
│ The argument "scopes" is required, but no definition was found.
╵
╷
│ Error: Missing required argument
│
│ on storage-account-alerts.tf line 1, in module "storage-account-alerts":
│ 1: module "storage-account-alerts" {
│
│ The argument "description" is required, but no definition was found.
╵
╷
│ Error: Missing required argument
│
│ on storage-account-alerts.tf line 1, in module "storage-account-alerts":
│ 1: module "storage-account-alerts" {
│
│ The argument "severity" is required, but no definition was found.
Any help is appreciated!

Related

Jenkins shared library loading dynamically with groovy file under `src/**`

I'm constructing a Jenkins pipeline to verify the shared-libs (from Gerrit) automatically, by reuse whatever pipelines we have right now.
the original thoughts should be very simple, which :
#Library( 'shared-libs#master' ) _
// |
// |
// variable instead of hard code
// |
// v
#Library( "shared-libs#${refs_params}" ) _
the libraries structure :
(root)
+- src # Groovy source files
| +- org
| +- jenkins
| +- FooDefinition.groovy # for org.jenkins.FooDefinition
| +- BarDefinition.groovy # for org.jenkins.BarDefinition
| +- ... # for org.jenkins....
| +- virtualization
| +- PodDefinition.groovy # for org.virtualization.PodDefinition
| +- ... # for org.virtualization....
+- vars
| +- foo.groovy # for global 'foo' variable
| +- logger.groovy # for global 'logger' variable
For regular pipeline, I'm using the groovy shared library (pre-setup in Manage Jenkins -> Configure System -> Global Pipeline Libraries) by:
#Library( 'shared-libs#master' ) _
import org.virtualization.PodDefinition
// generate pod
PodDefinition.runWith( ... ) {
// pipeline content
}
make sure the refs/changes/x works in Specify ref specs : +refs/changes/*:refs/remotes/#{remote}/changes/*:
// works by using hard code `refs/changes/x/x/123`
#Library( 'shared-libs#refs/changes/x/x/123' ) _
import org.virtualization.PodDefinition
However, when I using GERRIT_REFSPEC, it dosen't work due to WorkflowScript: #Library value ‘shared-libs#$GERRIT_REFSPEC’ was not a constant either way as below:
#Library( 'shared-libs#${GERRIT_REFSPEC}' ) _
#Library( 'shared-libs#${env.GERRIT_REFSPEC}' ) _
#Library( 'shared-libs#${params.GERRIT_REFSPEC}' ) _
So, I've modified the library usage according from the official document Extending with Shared Libraries to library( "shared-libs#${GERRIT_REFSPEC}" ), the libs clone works, but import org.virtualization.PodDefinition failed :
library( "shared-libs#${GERRIT_REFSPEC}" )
// or
this._ = library( "shared-libs#${GERRIT_REFSPEC}" )
// or
this = library( "shared-libs#${GERRIT_REFSPEC}" )
// or
library( "shared-libs#${GERRIT_REFSPEC}" ) _
import org.virtualization.PodDefinition
// WorkflowScript: 5: unable to resolve class org.virtualization.PodDefinition
// # line 3, column 1.
// import org.virtualization.PodDefinition
// ^
//
// 1 error
So, I've tried:
load path/to/x.grovy
library( "shared-libs#${GERRIT_REFSPEC}" )
node( 'built-in' ) {
load "../${env.JOB_BASE_NAME}#libs/<reivsion>/src/org/jenkins/FooDefinition.groovy"
load "../${env.JOB_BASE_NAME}#libs/<reivsion>/src/org/jenkins/BarDefinition.groovy"
load "../${env.JOB_BASE_NAME}#libs/<reivsion>/src/org/virtualization/PodDefinition.groovy"
}
// --- shows thrid party libs import failure ---
// org.jenkinsci.plugins.workflow.cps.CpsCompilationErrorsException: startup failed:
// Script7.groovy: 3: unable to resolve class com.cwctravel.hudson.plugins.extended_choice_parameter.ExtendedChoiceParameterDefinition
// # line 3, column 1.
// import com.cwctravel.hudson.plugins.extended_choice_parameter.ExtendedChoiceParameterDefinition
// ^
//
// 1 error
def x = library() org.x.x ( get hints from Importing class from git - unable to resolve class ) : it will not exact reuse current pipeline any more, and also dozens of groovy file make difficult of naming
def a = library( "shared-libs#${GERRIT_REFSPEC}" ) org.jenkins.FooDefinition.groovy
def b = library( "shared-libs#${GERRIT_REFSPEC}" ) org.jenkins.BarDefinition.groovy
def c = library( "shared-libs#${GERRIT_REFSPEC}" ) org.jenkins.xxx.groovy
def d = library( "shared-libs#${GERRIT_REFSPEC}" ) org.virtualization.PodDefinition.groovy
def e = library( "shared-libs#${GERRIT_REFSPEC}" ) org.virtualization.xxx.groovy
#Grab :
library( "shared-libs#${GERRIT_REFSPEC}" )
#Grab( 'org.virtualization.PodDefinition' )
#Grab( group='org.virtualization', module='PodDefinition' )
// WorkflowScript: 3: The missing attribute "version" is required in #Grab annotations
// # line 3, column 1.
// #Grab( group='org.virtualization', module='PodType' )
// ^
//
// 1 error
#Grab( group='org.virtualization', module='PodDefinition', version='latset' )
// org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed:
// General error during conversion: Error grabbing Grapes -- [unresolved dependency: org.virtualization#PodDefinition;latest: not found]
#Grab( group='org.virtualization', module='PodDefinition', version='default' )
// org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed:
// General error during conversion: Error grabbing Grapes -- [unresolved dependency: org.virtualization#PodDefinition;default: not found]
So, I don't know what I should do next, either "change" "shared-libs#${GERRIT_REFSPEC}" to constant to use #Library(...) _, or using library(...) to import all libs under src/**
BTW, here the way I've tried to "convert" variable to constant:
Object.metaclass.SHARED_LIBS = "shared-libs#${GERRIT_REFSPEC}"
#Library( SHARED_LIBS ) _
// or
class SHARED_LIBS {
final String REFSPEC = "shared-libs#${GERRIT_REFSPEC}"
}
#Library( SHARED_LIBS.REFSPEC ) _
// or
import groovy.transform.Field
#Field final String SHARED_LIBS = "shared-libs#${GERRIT_REFSPEC}"
#Library( SHARED_LIBS ) _
// or
def bindings = new Binding()
bindings.setVariable("SHARED_LIBS", "shared-libs#${GERRIT_REFSPEC}")
#Library( SHARED_LIBS ) _
// or
withEnv([ 'SHARED_LIBS=shared-libs#${GERRIT_REFSPEC}' ]) {
#Library( SHARED_LIBS ) _
}
You can dynamically load the library at any point of your groovy file and use the full class name to use the function. Maybe this is something that could help you.
def myLib = dsl.library 'my-shared-lib#<SHA>'
myLib.net.vy.a.v1.Sonarqube.call(dsl, parameters)
Here net.vy.a.v1.Sonarqube is the actual package. dsl is an object of Script

Pattern Matching does not allow me to change values

so I am currently working on a new programming language tr-lang
and I am currently in the process of writing the parser of the language
this piece of code is where the bug lies
BlockToken::İse(bip) => {
let ise = &mut parsed[bip]; // Access method 1
match ise.typ {
TokenType::İse ( mut yoksa ) => {
yoksa = Some(ip);
},
TokenType::Yoksa ( mut tp ) => {
tp = Some(ip);
},
_ => unreachable!(),
}
ip + 1
},
BlockToken::İken(bip) => {
let iken = parsed.get_mut(bip).unwrap(); // Trying other access methods
match iken.typ {
TokenType::İken ( mut yoksa ) => {
yoksa = Some(ip + 1);
},
_ => unreachable!(),
}
bip
},
_ => unimplemented!(),
};
and this is part of the code that parses and produces an executable program
and it gives a few warnings but i think the problem lies in these ones:
warning: variable `yoksa` is assigned to, but never used
--> src/parser/parser.rs:121:54
|
121 | ... TokenType::İse ( mut yoksa ) => {
| ^^^^^
|
= note: consider using `_yoksa` instead
warning: value assigned to `yoksa` is never read
--> src/parser/parser.rs:122:37
|
122 | ... yoksa = Some(ip);
| ^^^^^
|
= help: maybe it is overwritten before being read?
warning: variable `tp` is assigned to, but never used
--> src/parser/parser.rs:124:56
|
124 | ... TokenType::Yoksa ( mut tp ) => {
| ^^
|
= note: consider using `_tp` instead
warning: value assigned to `tp` is never read
--> src/parser/parser.rs:125:37
|
125 | ... tp = Some(ip);
| ^^
|
= help: maybe it is overwritten before being read?
warning: variable `yoksa` is assigned to, but never used
--> src/parser/parser.rs:134:55
|
134 | ... TokenType::İken ( mut yoksa ) => {
| ^^^^^
|
= note: consider using `_yoksa` instead
warning: value assigned to `yoksa` is never read
--> src/parser/parser.rs:135:37
|
135 | ... yoksa = Some(ip + 1);
| ^^^^^
|
= help: maybe it is overwritten before being read?
as you can see for some reason even though i pattern-match like usual when i try to set the value to something else it treats the variables as different
and instead of changing the value of yoksa/tp the end result just does not change anything
i tried changing the way i access ise/iken however it didn't change anything
i also tried using if let instead of match
it doesn't change the value of ise.typ.yoksa or ise.typ.tp
for extra info BlockToken is this enum
enum BlockToken {
İse(usize),
İken(usize),
İkiNoktaNokta(usize),
}
Token is this struct
struct Token {
pub typ: TokenType,
pub line: usize,
pub col: usize,
}
what i want from here is the ability to change the contents of the enum structs İse, İken and Yoksa
it can be unsafe although a safe method is preferred
Use Option::replace to fit the new value into the mutable option:
yoksa.replace(ip + 1);
Also you probably want a mutable reference:
TokenType::İken(ref mut yoksa)
I think you need to match on a mutable reference when matching otherwise you are just creating a local variable and mutating that.
For example this code:
#[derive(Debug)]
enum Blah {
A(u64),
}
mod test {
use super::Blah;
#[test]
fn test_match() {
let mut a = Blah::A(23);
println!("{:?}", a);
match a {
Blah::A(ref mut x) => *x = 5,
}
println!("{:?}", a);
}
}
will output:
running 1 test
A(23)
A(5)
If you run it with cargo test -- --nocapture.

How to name infix operators?

I have the following code:
[<AutoOpen>]
module OptionOperators =
let private mapOption func arg =
match arg with
| None -> Ok None
| Some arg -> func arg |> Result.map Some
let ( ^> ) arg func =
mapOption func arg
[<AutoOpen>]
module Model =
// Constrained to be no more than 35 chars, not null or empty, used for tag
type String35 = private String35 of string
module String35 =
let create field str =
ConstrainedType.createString field String35 35 str
type UnvalidatedAddress = { Name: string option }
type Address = { Name: String35 option }
let validate dto =
result {
let! name = dto.Name ^> String35.create "Name"
}
Is ^> the reasonable infix operator for the combine of Result and Option?
And is there a list of infix operators?
You're losing readability by using that obscure operator. I suggest you look for something more meaningful that anyone reading your code can understand:
let private validateField validator arg =
match arg with
| None -> Ok None
| Some arg -> validator arg |> Result.map Some
which you can use as:
let validate dto =
result {
let! name = dto.Name
|>validateField (String35.create "Name")
}

Spock does not execute when clause

One of my spock tests is skipping the when clause and moving right to the then clause.
#Unroll
void "test refresh metadata with #consumerNames"() {
setup:
consumerNames.each {
new CredentialConsumer(name: it).save(validate: false)
}
when:
service.refreshMetadata()
then:
consumerNames.each { consumerName ->
Metadata metadata = new Metadata(content: "Metadata for $consumerName")
ConsumerDefinition consumerDefinition = new ConsumerDefinition(name: consumerName, metadata: metadata)
1 * mockApplicationLibraryService.fetchConsumerDefinition(consumerName) >> consumerDefinition
assert CredentialConsumer.findByName(consumerName)?.metadata?.content == metadata.content
}
where:
consumerNames | _
["bacon"] | _
["bacon", "eggs"] | _
}
I get the following results...
Condition not satisfied:
CredentialConsumer.findByName(consumerName)?.metadata?.content == metadata.content
| | | | | | |
| bacon null null | | Metadata for bacon
| | com.datapriviasoftware.completesso.configuration.Metadata#487cd177
| false
com.datapriviasoftware.completesso.CredentialConsumer : 1
Expected :Metadata for bacon
Actual :null
When I step through it with the debugger, it executes the setup clause, skips the when clause, and immediately executes the then clause.
So, I knew that Spock uses AST transformations to process mocks in the then clause before it executes the when clause. When I thought through it, I realized that processing the mocks in the then clause required the entire each loop to execute, so I needed to separate the explicit assertion from the mock definition.
This works...
#Unroll
void "test refresh metadata with #consumerNames"() {
setup:
consumerNames.each {
new CredentialConsumer(name: it).save(validate: false)
}
when:
service.refreshMetadata()
then:
consumerNames.each { consumerName ->
Metadata metadata = new Metadata(content: "Metadata for $consumerName")
ConsumerDefinition consumerDefinition = new ConsumerDefinition(name: consumerName, metadata: metadata)
1 * mockApplicationLibraryService.fetchConsumerDefinition(consumerName) >> consumerDefinition
}
and:
consumerNames.each { consumerName ->
assert CredentialConsumer.findByName(consumerName)?.metadata?.content == "Metadata for $consumerName"
}
where:
consumerNames | _
["bacon"] | _
["bacon", "eggs"] | _
}

Get modifiers from class

I'm trying to get all the modifiers from a class in Rascal.
m = createM3FromEclipseProject(projectLocation);
for(cl <- classes(m)){
set[Modifier] modi = { f | f <- m#modifiers[cl], f.scheme == "java+class"};
println(modi);
}
This gives me an empty set of modifiers for all classes, but if I check m#modifiers, it is not empty.
So m#modifiers[cl] won't give me the modifiers that belong to that the class with location cl. How do I get these modifiers?
Something's wrong with the code you presented. If you try to do it step by step on the REPL you will see why:
For an example project with Fruit and such extracted into the M3 model m I have this:
rascal>classes(m)
set[loc]: {
|java+class:///Fruit|,
|java+class:///Apple|,
|java+class:///HelloWorld|
}
rascal>m#modifiers
rel[loc definition,Modifier modifier]: {
<|java+interface:///IFruit|,public()>,
<|java+method:///HelloWorld/main(java.lang.String%5B%5D)|,static()>,
<|java+class:///Fruit|,abstract()>,
<|java+method:///Apple/edible()|,public()>,
<|java+method:///Fruit/edible()|,public()>,
<|java+class:///Apple|,public()>,
<|java+method:///HelloWorld/main(java.lang.String%5B%5D)|,public()>,
<|java+class:///HelloWorld|,public()>,
<|java+method:///Fruit/edible()|,abstract()>,
<|java+class:///Fruit|,public()>
}
So m#modifiers[someClass] returns a set of modifiers:
rascal>m#modifiers[|java+class:///Fruit|]
set[Modifier]: {
abstract(),
public()
}
In your code f <- m#modifiers[cl] the f thus binds to a modifier and not to a source location. Somehow the code does not throw an exception but rather lets the condition fail for you? Because I get this result instead:
rascal>{ f | cl <- classes(m), f <- m#modifiers[cl], f.scheme == "java+class"};
|prompt:///|(46,1,<1,46>,<1,47>): Undeclared field: scheme for Modifier
Advice: |http://tutor.rascal-mpl.org/Errors/Static/UndeclaredField/UndeclaredField.html|
If you want to print the modifiers for each class, then this code should do it:
for (cl <- classes(m)) {
println("modifiers for <cl> are <m#modifiers[cl]>");
}

Resources