When I launch a command ansible-config list, some configuration entries had a yaml field, for example :
DEFAULT_VAULT_PASSWORD_FILE:
default: null
description: The vault password file to use. Equivalent to --vault-password-file or --vault-id
env:
- {name: ANSIBLE_VAULT_PASSWORD_FILE}
ini:
- {key: vault_password_file, section: defaults}
name: Vault password file
type: path
yaml: {key: defaults.vault_password_file}
I know how to use field env: {name: ANSIBLE_VAULT_PASSWORD_FILE} and field ini: {key: vault_password_file, section: defaults}.
How can I use yaml: {key: defaults.vault_password_file} ?
It's evidently designed to make people ask questions after carefully reading the output from ansible-config :-D
But, seriously, it is apparently part of an aspirational world in which config/manager.py reads YAML but in practice it is just one fat FIXME
Reasonable people can certainly differ about whether that stuff should be removed until it works for real, if for no other reason than this question right here. Feel free to file an issue if you think it would be ideally removed.
Related
The Bolt docs on Writing plans in YAML gives an code snippet that is not supposed to work:
steps:
- targets: $targets
description: Apply a file resource
resources:
- type: file
title: '/tmp/foo'
parameters:
content: $facts['os']['family']
ensure: present
- name: file_contents
description: Read contents of file managed with file resource
eval: >
file::read('/tmp/foo')
return: $file_contents
This snippet could be vastly improved with a GIANT RED "THIS DOES NOT WORK" right next to it.
I want to do exactly that: use a values from facts in a step. I understand I could use the puppet language to do so, but I'd like to use YAML.
EDIT: How can you write the above in YAML?
I would use the facts function instead to be safe, and functions are possible in YAML plans.
${facts(<target>)['os']['family']}
Since the step in the question already supplies a target type, it does not need to be converted from a TargetSpec type with get_target like in Puppet language plans.
Note that you may need to gather the facts with another plan before referencing them:
steps:
- plan: facts
description: 'Gather facts for the servers using the built-in facts plan'
parameters:
targets:
- foo.example.com
- bar.example.com
- baz.example.com
I'm trying to download multiple artifacts into different servers(like web, db) using environments. Currently i have added the task DownloadPipelineArtifact#2 in a file and using template to add that task in azure-pipelines.yml. As i'm having multiple artifacts, im trying to use for loop where i'm getting issues.
#azure-pipelines.yml
- template: artifacts-download.yml
parameters:
pipeline:
- pipeline1
- pipeline2
- pipeline3
path:
- path1
- path2
- path3
I need to write loop in yaml so that it should download the pipeline1 artifacts to path1 and so on. Can someone please help??
Object-type parameters are your friend. They are incredibly powerful. As qBasicBoy answered, you'll want to make sure that you group the multiple properties together. If you're finding that you have a high number of properties per object, though, you can do a multi-line equivalent.
The following is an equivalent parameter structure to what qBasicBoy posted:
parameters:
- name: pipelines
type: object
default:
- Name: pipeline1
Path: path1
- Name: pipeline2
Path: path2
- Name: pipeline3
Path: path3
An example where you can stack many properties to a single object is as follows:
parameters:
- name: big_honkin_object
type: object
default:
config:
- appA: this
appB: is
appC: a
appD: really
appE: long
appF: set
appG: of
appH: properties
- appA: and
appB: here
appC: we
appD: go
appE: again
appF: making
appG: more
appH: properties
settings:
startuptype: service
recovery: no
You can, in essence, create an entire dumping ground for everything that you want to do by sticking it in one single object structure and properly segmenting everything. Sure, you could have had "startuptype" and "recovery" as separate string parameters with defaults of "service" and "no" respectively, but this way, we can pass a single large parameter from a high level pipeline to a called template, rather than passing a huge list of parameters AND defining said parameters in the template yaml scripts (remember, that's necessary!).
If you then want to access JUST a single setting, you can do something along the lines of:
- task: PowerShell#2
inputs:
targetType: 'inline'
script: |
# Write your PowerShell commands here.
Write-Host "Apps start as a "${{ parameters.settings.startuptype }}
Write-Host "Do the applications recover? "${{ parameters.settings.recovery }}
This will give you the following output:
Apps start as a service
Do the applications recover? no
YAML and Azure Pipelines are incredibly powerful tools. I can't recommend enough going through the entire contents of learn.microsoft.com on the subject. You'll spend a couple hours there, but you'll come out the other end with an incredibly knowledge of how these pipelines can be tailored to do everything you could ever NOT want to do yourself!
Notable links that helped me a TON (only learned this a couple months ago):
How to work with the YAML language in Pipelines
https://learn.microsoft.com/en-us/azure/devops/pipelines/yaml-schema?view=azure-devops&tabs=schema%2Cparameter-schema
How to compose expressions (also contains useful functions like convertToJSON for your object parameters!)
https://learn.microsoft.com/en-us/azure/devops/pipelines/process/expressions?view=azure-devops
How to create variables (separate from parameters, still useful)
https://learn.microsoft.com/en-us/azure/devops/pipelines/build/variables?view=azure-devops&tabs=yaml
SLEEPER ALERT!!! Templates are HUGELY helpful!!!
https://learn.microsoft.com/en-us/azure/devops/pipelines/process/templates?view=azure-devops
You could use an object with multiple properties
parameters:
- name: pipelines
type: object
default:
- { Name: pipeline1, Path: path1 }
- { Name: pipeline2, Path: path2 }
- { Name: pipeline3, Path: path3 }
steps:
- ${{each pipeline in parameters.pipelines}}:
# use pipeline.Name or pipeline.Path
I'm getting the following error in a yaml file
Error : end of the stream or a document separator is expected at line 2, column 11:
apiVersion: v1
^
Line : undefined undefined
This is the entire contents of the file
<<EOT
apiVersion: v1
clusters:
- cluster:
server: https://3F46DDD9022BD149B88DA7ED4AFB2B30.gr7.eu-west-1.eks.amazonaws.com
certificate-authority-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUN5RENDQWJDZ0F3SUJBZ0lCQURBTkJna3Foa2lHOXcwQkFRc0ZBREFWTVJNd0VRWURWUVFERXdwcmRXSmwKY201bGRHVnpNQjR> name: kubernetes
contexts:
- context:
cluster: kubernetes
user: aws
name: aws
current-context: aws
kind: Config
preferences: {}
users:
- name: aws
user:
exec:
apiVersion: client.authentication.k8s.io/v1alpha1
command: aws-iam-authenticator
args:
- "token"
- "-i"
- "terraform-eks-demo"
EOT
I've been googling this for hours but I'm getting nowhere tried . I've tried every YAML linter I can find, can anybody point me in the right direction? I am new to this, if that wasn't obvious
You need to remove <<EOT and EOT. You probably copied them from some code that injected YAML into a command line utility via a heredoc but they should not part of the YAML content.
What happens is that when the YAML processor sees <<EOT (which parses as part of a YAML scalar because < is not a special character) and then a new line. A multiline scalar at root level must be the single root node of a document. When the second line is read, the YAML processor sees a : which is not allowed here. At this point, both lines have been read as multiline scalar, and a multiline scalar cannot be used as mapping key. Therefore, the processor complains that after the single root node of the YAML document, the document must end, but instead you try to start a mapping.
I think you should keep a space before 'v1' at line2.
I'm pretty new to ruby and all the documentation on this subject has confused me a bit. So here goes.
I'm using inspec to test my infrastructure, but I want it to consume some variables from the YAML file used by ansible. This effectively means I can share vars from ansible code and use them in ruby.
The YAML file looks like this:
- name: Converge
hosts: all
vars:
elasticsearch_config:
cluster.name: "{{ elasticsearch_cluster_name }}"
node.name: "es-test-node"
path.data: "/var/lib/elasticsearch"
path.logs: "/var/log/elasticsearch"
elasticsearch_cluster_name: test
pre_tasks:
roles:
- elasticsearch
post_tasks:
At this point, I'm just playing around with ruby code to extract that, and have:
require 'yaml'
parsed = begin
YAML.load(File.open("../../playbook.yml"))
rescue ArgumentError => e
puts "Could not parse YAML: #{e.message}"
end
puts parsed
Which outputs the hash:
{"name"=>"Converge", "hosts"=>"all", "vars"=>{"elasticsearch_config"=>{"cluster.name"=>"{{ elasticsearch_cluster_name }}", "node.name"=>"es-test-node", "path.data"=>"/var/lib/elasticsearch", "path.logs"=>"/var/log/elasticsearch"}, "elasticsearch_cluster_name"=>"test"}, "pre_tasks"=>nil, "roles"=>["elasticsearch"], "post_tasks"=>nil}
So far so good. This all makes sense to me. Now, I would like to pull values out of this data and use them in the ruby code, referencing them by the keys. So, if I wanted to get the value of vars.elasticsearch_config.node.name, how would I go about doing this?
YAML.load reads the document into an array, so you must get the first element in your example:
loaded_yaml[0]["vars"]["elasticsearch_config"]["node.name"]
The reason for this is that the document you are parsing begins with a single dash, indicating a list item. Even though there is only one item in the list, Psych (thy YAML engine) is still placing it into an array representing a list. This is also why you got a no implicit conversion of String to Integer error. Note that the response you get is enclosed by square brackets:
=> [{"name"=>"Converge", "hosts"=>"all", "vars"=>{"elasticsearch_config"=>{"cluster.name"=>"{{ elasticsearch_cluster_name }}", "node.name"=>"es-test-node", "path.data"=>"/var/lib/elasticsearch", "path.logs"=>"/var/log/elasticsearch"}, "elasticsearch_cluster_name"=>"test"}, "pre_tasks"=>nil, "roles"=>["elasticsearch"], "post_tasks"=>nil}]
How can I check if / else in yaml file.
like:
if %{attribute}
attributes:
shipping_comment: Shipping comment / Instructions
else
attributes:
shipping_date: Date
YAML is a data serialisation language, so it's not meant to contain if/else style executable statements: that's the responsibility of the programming language you're using.
A simple example in Ruby to determine which config string from a YAML file to output could be defining your YAML config file as follows:
data.yml
attributes:
shipping_comment: Shipping comment / Instructions
shipping_date: Date
Then, in your program, read the file in and run the conditional there:
shipping.rb
#!/usr/bin/env ruby
require 'yaml'
config = YAML.load_file('data.yml')
attribute = true # your attribute to check here
if attribute
puts config['attributes']['shipping_comment']
else
puts config['attributes']['shipping_date']
end
Out of the box .yaml files won't include any conditional logic, as Paul Fioravanti says:
YAML is a data serialisation language, so it's not meant to contain if/else style executable statements: that's the responsibility of the programming language you're using.
However, there are some cases, such as Infrastructure as Code where you might not have the luxury of Paul's solution. In these cases, most decent Infrastructure tools provide an inbuilt way of achieving conditional logic.
Since it appears that infra is not the area you're looking in, I won't go into detail on how to write each tools solution, but for anyone that end's up here like I did, docs such as these helped me and may prove useful for you:
Ansible
CloudFormation
This is a little late for the original poster, but may be of use to others: The Azure implementation of the YAML parser does support conditional checks. For example, the following YAML in an azure-pipeline.yml:
#azure-pipeline.yml
parameters:
- name: testCondition
displayName: 'Use experimental build process?'
type: boolean
default: true
steps:
- ${{ if eq(parameters.testCondition, true) }}:
- bash: echo 'true'
- ${{ if not(eq(parameters.testCondition, true)) }}:
- bash: echo 'false'
will evaluate the value of the testCondition parameter. When run, the bash task will echo "true", something like this: