How to properly use expression results as booleans on Azure Devops pipelines? - azure-devops

I'm trying to use an or expression to define a boolean on a template as follows:
parameters:
- name: A
default: true
- name: B
default: false
stages:
- template: bacon.yml#template
parameters:
booleanParameter: or(eq(${{ parameters.A }}, true), eq(${{ parameters.B}}, true))
In my head, it should work just fine, yet I keep getting this same error:
The 'booleanParameter' parameter value 'or(eq(True, true), eq(False, true))' is not a valid Boolean.
I've tried some small variations of syntax, all of them resulting in the same error.
What am I missing here?

You should use template expression to wrap whole expression:
booleanParameter: ${{ or(eq(parameters.A, true), eq(parameters.B, true)) }}

Related

Deploy only certain resources into Azure using DevOps Pipeline

I have a main.bicep template with multiple resources that I deploy to Azure via my DevOps pipeline. My template is currently configured to either deploy all modules to Azure or none. However, I would like to customize this in my pipeline so that only certain resources show up in my resource group so that it acts like a selection catalog.
However, I need advice and help on how to solve the problem as I can’t find the right approach. Attached you can see a snippet from my bicep template below.
– main.bicep–
param deployAppInsights bool = true param deployNetworkWatcher bool = true param deploySentinel bool = true
Example for a module
// Deploy App Insights resource
module appInsights 'AzureMonitor/AppInsights/appInsights-temp.bicep' = if(deployAppInsights) { name: 'appInsightsDeployment' params: { appName: appInsightsName regionId: regionId // tagsArray: tagsArray requestSource: requestSource workspaceResourceId: workspace.outputs.resourceWorkspaceIdOutput } }
This snippet is in my pipeline - yml
(I would like to shorten the parameters block by using override parameters.)
parameters:
- name: appInsights
type: boolean
default: True
values:
- True
- False
inputs: overrideParameters: -deployAppInsights false -deployNetworkWatcher true -deploySentinel true
Currently, my override parameters are hardcoded, but I’d like to keep it in a general way, like for example:
overrideParameters: -deployAppInsights ${{appInsights}} -deployNetworkWatcher ${{networkWatcher}} -deploySentinel ${{sentinel}}
However, this does not unfortunately work. Could anyone please help me in this regard, how I can solve this or how the variables need to look like?
Thank you very much!
Best regards
Jennifer
As far as I understand, the syntax you are using is wrong in the below code
overrideParameters: -deployAppInsights ${{appInsights}} -deployNetworkWatcher ${{networkWatcher}} -deploySentinel ${{sentinel}}
Since you have already defined parameters section in the Yml file. The correct syntax is
overrideParameters: -deployAppInsights ${{parameters.appInsights}} -deployNetworkWatcher ${{parameters.networkWatcher}} -deploySentinel ${{parameters.sentinel}}
A sample code snippet for your reference
parameters:
- name: var1
type: string
- name: var2
type: string
- name: bool1
type: bool
...
omitted
...
- task: AzureResourceManagerTemplateDeployment#3
inputs:
deploymentScope: 'Resource Group'
azureResourceManagerConnection: ''
subscriptionId: ''
action: 'Create Or Update Resource Group'
resourceGroupName: rg-${{parameters.var1}}-${{parameters.var2}}
location: ''
templateLocation: 'Linked artifact'
csmFile: $(System.DefaultWorkingDirectory)/arm.json
csmParametersFile: $(System.DefaultWorkingDirectory)/arm.parameters.json
deploymentMode: 'Incremental'
overrideParameters:
-string1 ${{parameters.var1}}
-string2 ${{parameters.var2}}
-flag ${{parameters.bool1}}
For more, please refer to the link from Microsoft. Azure Devops Template
Edit: After the first comment
Please update your 'appInsights' parameter as follows
parameters:
- name: appInsights
type: boolean
default: true

Boolean input not passed correctly to reusable workflow

I have an invoking and a called (reusable) workflow.
Here is the input of the reusable one:
stg_image_build:
description: whether to build the staging image
required: true
type: boolean
default: false
Here is the relevant part of the calling workflow
push_to_stg:
description: "Build and push image to staging registry"
type: boolean
default: false
required: true
...
build-and-push-image:
uses: path/to/reusable/workflow.yaml#master
with:
stg_image_build: ${{ inputs.push_to_stg }}
This fails as follows:
The template is not valid. .github/workflows/calling.yaml (Line: 72, Col: 24): Unexpected type of value '', expected type: Boolean.
The error refers to this line:
stg_image_build: ${{ inputs.push_to_stg }}
Why?

Referencing json list value created in Rundeck Data Workflow step

Rundeck job: When I create data in data workflow step as json list
{
"repo": ["repo1","repo2","repo3"],
"myrepo": "repo4"
}
how can I access the elements in the list from inline script in next step?
#stub.repo[1]#
doesn't work
#stub.myrepo#
works fine
Data Workflow step executed
Script:
echo "value: #stub.repo[1]]#"
echo "value2: #stub.myrepo#"
Result:
value:
value2: repo4
The easiest way to catch that array is to use the jq-JSON mapper log filter plugin in any step like the command step or script step (here are the releases, here is how to install the plugin, and here how Log filters works).
Using this plugin you can use the array positions directly, e.g: ${data.data.0}, ${data.data.1}, etc.
Job definition example with your JSON output for testing.
- defaultTab: summary
description: ''
executionEnabled: true
group: JSON
id: f0d2843f-8de3-4984-a9ae-2fd7ab3963ae
loglevel: INFO
name: test-json-array
nodeFilterEditable: false
plugins:
ExecutionLifecycle: null
scheduleEnabled: true
sequence:
commands:
- plugins:
LogFilter:
- config:
filter: .[]
logData: 'true'
prefix: data
type: json-mapper
script: |-
cat <<-END
{
"repo": ["repo1","repo2","repo3"],
"myrepo": "repo4"
}
END
- exec: echo ${data.data.0}
keepgoing: false
strategy: node-first
uuid: f0d2843f-8de3-4984-a9ae-2fd7ab3963ae
Result.
More info about the plugin here.

AZP: Is there a best practice to be able to "namespace" script tasks in yaml templates for usage of variables?

In Azure Pipelines: my main problem is, if I create a yml template and have some logic inside that template in a script task where I want to set a variable, i need the
name: "pseudonamespace" to reference that variable further down in that template via
$(pseudonamespace.variablename)
An example, where the script part does nothing overtly useful, but should demonstrate my problem:
mytemplate.yml:
parameters:
- name: isWindowsOnTarget
type: boolean
default: true
steps:
- script: |
if [ "${{lower(parameters.isWindowsOnTarget)}}" == "true" ]; then
delimiter="\\"
else
delimiter="/"
fi
echo "##vso[task.setvariable variable=myCoolVariable;isOutput=true]$delimiter"
name: MyFakeNameSpace
...
- task: SomeTask#0
inputs:
myInput: $(MyFakeNameSpace.myCoolVariable)
This codeblock works; but only, if, in a job, I only instanciate it once:
- template: mytemplate.yml#templates
parameters:
isWindowsOnTarget: true
If I would need that template twice, differently parameterized, I get the error that the name of the script block needs to be unique.
Is there any useful possibility I'm not currently thinking about other than to have an extra parameter for the template that I could basically just call "UniqueNamespace"?
There is no much space to move. Your task needs a unique name as later as you mention for output parameters it works like a namespace. So the best and the only way you have is to provide another parameter which would be task name.
parameters:
- name: isWindowsOnTarget
type: boolean
default: true
- name: taskName
type: string
steps:
- script: |
if [ "${{lower(parameters.isWindowsOnTarget)}}" == "true" ]; then
delimiter="\\"
else
delimiter="/"
fi
echo "##vso[task.setvariable variable=myCoolVariable;isOutput=true]$delimiter"
name: ${{ parameters.taskName }}
...
- task: SomeTask#0
inputs:
myInput: $(MyFakeNameSpace.myCoolVariable)
and then:
- template: mytemplate.yml#templates
parameters:
isWindowsOnTarget: true
taskName: MyFakeNameSpace
- template: mytemplate.yml#templates
parameters:
isWindowsOnTarget: true
taskName: MyFakeNameSpace2
In fact when you do not provide a name Azure DevOps assign a unique name. However, in this way you don't know the name till runtime.

How to round trip ruamel.yaml strings like "on"

When using ruamel.yaml to round-trip some YAML I see the following issue. Given this input:
root:
matchers:
- select: "response.body#state"
test: all
expected: "on"
I see this output:
root:
matchers:
- select: response.body#state
test: all
expected: on
Note that in YAML, on parses as a boolean true value while off parses as false.
The following code is used to read/write:
# Use the default (round-trip) settings.
yaml = YAML()
if args.source == '-':
src = sys.stdin
else:
src = open(args.source)
doc = yaml.load(src)
process(args.tag, set(args.keep.split(',')), doc)
if args.destination == '-':
dest = sys.stdout
else:
dest = open(args.destination, 'w')
yaml.dump(doc, dest)
The process function is not modifying values. It only removes things with a special tag in the input after crawling the structure.
How can I get the output to be a string rather than a boolean?
You write that:
Note that in YAML, on parses as a boolean true value while off parses as false.
That statement is not true (or better:
has not been true for ten years). If you have an unquoted on in your
YAML, like in your output, that is obviously not the case when using ruamel.yaml:
import sys
import ruamel.yaml
yaml_str = """\
root:
matchers:
- select: response.body#state
test: all
expected: on
"""
yaml = ruamel.yaml.YAML()
data = yaml.load(yaml_str)
expected = data['root']['matchers'][0]['expected']
print(type(expected), repr(expected))
which gives:
<class 'str'> 'on'
This is because in the YAML 1.2 spec on/off/yes/no are no
longer mentioned as having the same meaning as true
resp. false. They are mentioned in the YAML 1.1 spec, but that was
superseded in 2009. Unfortunately there are YAML libraries out in the
wild, that have not been updated since then.
What is actually happening is that the suprefluous quotes in your
input are automatically discarded by the round-trip process. You can
also see that happen for the value "response.body#state". Although
there the character that starts comments (#) is included, to
actually start a comment that character has to be proceded by
white-space, and since it is isn't, the quotes are not necessary.
So your output is fine, but if you are in the unfortunate
situation where you have to deal with other programs relying on
outdated YAML 1.1, then you can e.g. specify that you want to preserve
your quotes on round-trip:
yaml_str = """\
root:
matchers:
- select: "response.body#state"
test: all
expected: "on"
"""
yaml = ruamel.yaml.YAML()
yaml.indent(sequence=4, offset=2)
yaml.preserve_quotes = True
data = yaml.load(yaml_str)
yaml.dump(data, sys.stdout)
as this gives your exact input:
root:
matchers:
- select: "response.body#state"
test: all
expected: "on"
However maybe the better option would be that you actually specify that your
YAML is and has to conforming to the YAML 1.1 specification by making
your intensions, and the output document, explicit:
yaml_str = """\
root:
matchers:
- select: response.body#state
test: all
expected: on
"""
yaml_in = ruamel.yaml.YAML()
yaml_out = ruamel.yaml.YAML()
yaml_out.indent(sequence=4, offset=2)
yaml_out.version = (1, 1)
data = yaml_in.load(yaml_str)
yaml_out.dump(data, sys.stdout)
Notice that the "unquoted" YAML 1.2 input, gives output where on is quoted:
%YAML 1.1
---
root:
matchers:
- select: response.body#state
test: all
expected: 'on'