terraform console: Extra characters after expression - terraform

I installed terraform and trying to do eval basic expression.
I am getting weird errors.
e.g what's wrong with this expression?
variable "BN" { default = "X" }
or
x = 3
for loops works but it needs to be wrapped into square brackets.
[ for bn in [1, 2, 3] : "%{if bn == 2} ok %{else} bad ${bn} %{endif}" ]
terraform console makes impression that you made a syntax error, but I think at most it could be semantic one.
As for now this utility looks very limited.
Is there any other place I can play with terraform where?

Of the three examples you shared, only the third one is actually a Terraform language expression. An expression is something that generates a value which you can then assign to a resource type argument.
Your first example is a variable declaration. The string you assigned to its default argument is an example of an expression - a literal string expression - but that overall block declares a new variable in a configuration, so it's not something you can evaluate to produce a value.
Your second example seems to assigning the value 3 to an argument called x, but that doesn't mean anything without some additional context: x would need to be an argument inside a block in order to be meaningful, and even then it wouldn't be an expression, but rather the definition of an argument called x using the expression 3.
If you want to experiment with the Terraform language then the best way to do it is to make a file whose name has the suffix .tf in a new directory, and then run the main Terraform commands terraform init, terraform plan, etc in that directory. The terraform console command is for evaluating hypothetical expressions against your configuration, but until you've actually written a configuration you'll have nothing other than literal values to refer to.

Related

Using Groovy 3 YamlBuilder with Yaml that contains a hyphen

I'm trying to write a Groovy 3 script that uses yamlbuilder to write a yaml file. I have it working on almost everything apart from;
execution:
set-props:
url:http://myhouse.net
port:8000
How do I write a map that allows the use of a hyphen in the name? Following my previous work I foolishly tried;
def setprops=[:]
setprops=(["url":"http://myhouse.net","port":"8000"])
execution.set-props=setprops
Which gives me an error 'The LHS of an assignment should be a variable or a field'.
If I just use execution.setprops then it works fine, but of course the resulting yaml from yaml(execution) is invalid.
I think if the set-props was a a key/value pair then it could go into quote and everything would be good. But because it is part of the structure I don't know what needs to be done.
You can use strings as "methods" and the builder will create your
intermediate structures from them:
import groovy.yaml.YamlBuilder
def b = new YamlBuilder()
b.execution {
"set-props"(
url: "..."
)
}
println b
Or to continue on your example: You can create the whole map and use is as argument, where you want to have that content.
def setprops=["set-props": [url:"..."]]
b.execution(setprops)
Both result in:
---
execution:
set-props:
url: "..."
Note that the first version nests via passed closures and then passes in the map. The second bit just passes a nested map.

How to interpolate expressions in Terraform?

I'm trying to use the keys expression in Terraform to grab a list of keys (from a map variable) and assign it to a local variable. Here is the code snippet:
locals {
project_name_list = keys(${var.project_map})
}
However, I'm getting the following error:
Unknown token: 29:22 IDENT keys
Am I missing something here. Nowhere can I find an example of this expression. As bad as it is, even the official documentation does not help -https://www.terraform.io/docs/configuration/functions/keys.html
HashiCorp has really done a bad job of elaborating the nuances of Terraform for beginners on their website.
Terraform functions need to be wrapped in expression syntax to show that it's not a literal value: "${}"
So try this: project_name_list = "${keys(var.project_map)}"
The example in the documentation is written as though being run from the terraform command line, which already assumes the command is a HCL expression and doesn't require that syntax.
UPDATE
I said above that the expression syntax is to show that it's not a literal value. It's probably more accurate to speak of it as expression syntax vs. configuration syntax. Configuration syntax is the first level of interpolation, which forms the basic structure of your terraform file with resource blocks, data blocks, etc. The second interpolation level is expression syntax which is used to generate values used by your configuration.
Thinking of it in these terms makes better sense of the error message, Unknown token, because terraform is attempting to read it as a configuration key word.
I had compared it to a literal value because it's in the same position as where a literal value would be.

How to test if a string variable in Robot Framework is empty?

How to test if a string variable in Robot Framework is empty?
My first naïve attempt looked like this:
Run Keyword If ${myVar}!=${EMPTY}
but it failed:
Evaluating expression '!=' failed: SyntaxError: unexpected EOF while parsing (, line 1)
I then found this issue at Github but it didn't suggest a solution, just that the error message was unclear. An alternative solution was presented here:
${length}= Get Length ${Portfolio_ste}
Run Keyword If ${length} Go To Edit Portfolio
but is this really the best practice?
(The context is that I use a variable argument list and if a certain variable contains a value something should be done, otherwise just ignore it)
The expression needs to be a valid python expression after variable substitution. Assuming for the moment that myVar might be something like the number 42, your expression would end up looking like this after substitution:
Run Keyword if 42!=
When comparing against the empty string you need to add quotes to guarantee that the expression is a proper python expression after substitution. For example:
Run Keyword If "${myVar}"!="${EMPTY}"
Try Get Variable Value. It solved my problem.

difference between variable definition in a Haskell source file and in GHCi?

In a Haskell source file, I can write
a = 1
and I had the impression that I have to write the same in GHCi as
let a = 1
, for a = 1 in GHCi gives a parse error on =.
Now, if I write
a = 1
a = 2
in a source file, I will get an error about Multiple declaration of a, but it is OK to write in GHCi:
let a = 1
let a = 2
Can someone help clarify the difference between the two styles?
Successive let "statements" in the interactive interpreter are really the equivalent of nested let expressions. They behave as if there is an implied in following the assignment, and the rest of the interpreter session comprises the body of the let. That is
>>> let a = 1
>>> let a = 1
>>> print a
is the same as
let a = 1 in
let a = 1 in
print a
There is a key difference in Haskell in having two definitions of the same name and identical scopes, and having two definitions of the same name in nested scopes. GHCi vs modules in a file isn't really related to the underlying concept here, but those situations do lead you to encounter problems if you're not familiar with it.
A let-expression (and a let-statement in a do block) creates a set of bindings with the same scope, not just a single binding. For example, as an expression:
let a = True
a = False
in a
Or with braces and semicolons (more convenient to paste into GHCi without turning on multi-line mode):
let { a = True; a = False} in a
This will fail, whether in a module or in GHCi. There cannot be a single variable a that is both True and False, and there can't be two separate variables named a in the same scope (or it would be impossible to know which one was being referred to by the source text a).
The variables in a single binding set are all defined "at once"; the order they're written in is not relevant at all. You can see this because it's possible to define mututally-recursive bindings that all refer to each other, and couldn't possibly be defined one-at-a-time in any order:
λ let a = True : b
| b = False : a
| in take 10 a
[True,False,True,False,True,False,True,False,True,False]
it :: [Bool]
Here I've defined an infinite list of alternating True and False, and used it to come up with a finite result.
A Haskell module is a single scope, containing all the definitions in the file. Exactly as in a let-expression with multiple bindings, all the definitions "happen at once"1; they're only in a particular order because writing them down in a file inevitably introduces an order. So in a module this:
a = True
a = False
gives you an error, as you've seen.
In a do-block you have let-statements rather than let-expressions.2 These don't have an in part since they just scope over the entire rest of the do-block.3 GHCi commands are very like entering statements in an IO do-block, so you have the same option there, and that's what you're using in your example.
However your example has two let-bindings, not one. So there are two separate variables named a defined in two separate scopes.
Haskell doesn't care (almost ever) about the written order of different definitions, but it does care about the "nesting order" of nested scopes; the rule is that when you refer to a variable a, you get the inner-most definition of a whose scope contains the reference.4
As an aside, hiding an outer-scope name by reusing a name in an inner scope is known as shadowing (we say the inner definition shadows the outer one). It's a useful general programming term to know, since the concept comes up in many languages.
So it's not that the rules about when you can define a name twice are different in GHCi vs a module, its just that the different context makes different things easier.
If you want to put a bunch of definitions in a module, the easy thing to do is make them all top-level definitions, which all have the same scope (the whole module) and so you get an error if you use the same name twice. You have to work a bit more to nest the definitions.
In GHCi you're entering commands one-at-a-time, and it's more work to use multi-line commands or braces-and-semicolon style, so the easy thing when you want to enter several definitions is to use several let statements, and so you end up shadowing earlier definitions if you reuse names.5 You have to more deliberately try to actually enter multiple names in the same scope.
1 Or more accurately the bindings "just are" without any notion of "the time at which they happen" at all.
2 Or rather: you have let-statements as well as let-expressions, since statements are mostly made up of expressions and a let-expression is always valid as an expression.
3 You can see this as a general rule that later statements in a do-block are conceptually nested inside all earlier statements, since that's what they mean when you translate them to monadic operations; indeed let-statements are actually translated to let-expressions with the rest of the do-block inside the in part.
4 It's not ambiguous like two variables with the same name in the same scope would be, though it is impossible to refer to any further-out definitions.
5 And note that anything you've previously defined referring to the name before the shadowing will still behave exactly as it did before, referring to the previous name. This includes functions that return the value of the variable. It's easiest to understand shadowing as introducing a different variable that happens to have the same name as an earlier one, rather than trying to understand it as actually changing what the earlier variable name refers to.

Prolog List of Constants to String

i have a list in input: [asd,qweqwe,fsdf,lkasd]
As un can see from the code i want connect each constant of the list to output a single variable list.
i m using yap prolog, i consult this code and i write :- run.
the write function print out _G1233 and not 'asd,asd2,asd3,asd4'
why ? how i have to change the code for output me 'asd,asd2,asd3,asd4' ?
run :- toAtomicVars([asd,asd2,asd3,asd4],',',Out),
write(Out),nl.
toAtomicVars([],In,Out).
toAtomicVars([A|B],In,Out) :-
atomic_concat(A,In,Out1),
atomic_concat(',',Out1,Out2),
toAtomicVars(B,Out2,Out2).
you (should) get a warning like
Singleton variables: [In,Out]
Singleton variables: [Out]
that means that you dont really do anything with those variables:
toAtomicVars([],In,Out).
In and Out can be anything, so prolog just prints a dummy value, _Gsomething that means that the variable is not instantiated.
same thing happens in the second clause:
toAtomicVars([A|B],In,Out) :-
atomic_concat(A,In,Out1),
atomic_concat(',',Out1,Out2),
toAtomicVars(B,Out2,Out2).
you dont say anywhere what is that Out.
personally i think that it would be easier if you just printed each variable recursively and then print a comma, something like:
print_list([X]):-
write(X).
print_list([H|T]):-
write(H),
write(', '),
print_list(T).
but if you want to put commas in the list you should add a rule that defines Out.

Resources