Twitter

Showing posts with label ansible. Show all posts
Showing posts with label ansible. Show all posts

Ansible: prevent executing a playbook if no limit is specified

Ansible is a very good tool, no doubt about this but there is something which has always been annoying me. Indeed, if you run a playbook with no limit specified as shown below:
$ ansible-playbook patch-vm.yml
then this playbook will be executed against all the hosts of your inventory and depending on the playbook, a simple "oops, I forgot to set up a limit" human error can be devastating for your system. And this is same if you use a tool like Ansible Tower (great tool as well) where you can prompt for a limit and put a dummy one per default but you cannot prevent someone to run a playbook with an empty limit -- then against all the host from your inventory.

Hopefully, ansible is a very complete tool and it is then easy to code a task preventing a playbook to run if no limit is specified using the special variable ansible_limit, we basically want to say no to "no limit" !

Here is what this task looks like:
$ cat exit-if-no-limit.yml
---
  - name: Verifying that a limit is set
    fail:
      msg: 'This playbook cannot be run with no limit'
    run_once: true
    when: ansible_limit is not defined
  - debug:
      msg: Limit is {{ ansible_limit }}, let's continue
    run_once: true
    when: ansible_limit is defined
You can then use this task in your playbooks as below:
- include_role:
    name: myrole
    tasks_from: "{{ item }}.yml"
  loop:
  - exit-if-no-limit
  - something
  - something_else
Easy to use, easy to reuse when needed, below an example of the output produced when no limit is specified:
TASK [myrole: Verifying that a limit is set]
fatal: [ahost]: FAILED! => {"changed": false, "msg": "This playbook cannot be run with no limit"}
And an output with a limit specified:
TASK [myrole: debug]
ok: [anotherhost] => {
    "msg": "Limit is anotherhost, let's continue"
}
I never had to go further like testing how many hosts are specified, if the limit contains groups, how many groups, etc ... but it would be easy to do with a bit of regexp against the ansible_limit variable.

Stay safe with ansible thanks to exit-if-no-limit.yml !

Ansible: Error opening terminal: unknown

When ansible does not have the module you want, you can still use the shell module to run any shell command you want which is very cool.

I made my own playbook to be able to run any command / script on a target host from Ansible Tower which is very useful to run rac-status.sh, asmdu.sh, etc ... once on each cluster with one click, or an uptime command on each node of a cluster, and yes, also patching Exadata (:)), etc ... and I recently faced a weird error when running some Exadata pre-requisites:
Error opening terminal: unknown
This was not obvious to me at first and I then discovered that it was coming from the exa-versions.sh script and more precisely this line of code:
NB_PER_LINE=$(bc <<< "`tput cols`/22")          # Number of element to print per line
This command line uses tput to get the size of the user terminal to make a nice a dynamic output not exceeding the border of the user terminal which is cool but ansible does not run with a terminal (nor any environment) thus the error I got ! and you can reproduce it easily from a shell environement:
$ echo $TERM
xterm          
$ tput cols
346                                               <== Number of columns of my terminal
$ unset TERM
$ tput cols
tput: No value for $TERM and no -T specified      <== makes sense, there is no terminal any more as I have unset TERM
$

This is where you (re)discover that ansible runs with no environment and also no terminal. To fix this, you have just have to set the TERM environment variable to the shell ansible module as shown below:
  - name: Run command | Execute {{ l_command }}
    environment:
      PATH: "/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:{{ scripts_dir }}"
      TERM: xterm                                 <== set the TERM to xterm
    shell: "{{ l_command }}"
    register: out
    args:
      executable: /bin/bash
    when: l_command is defined
And you are done ! Also note that depending on what you want to run, you may also need to set a PATH; here, I also add to my path a variable where all my scripts are on the local system: scripts_dir.

OCI: Datapump between 23ai ADB and 19c ADB using database link

Now that we know how to manually create a 23ai ADB in OCI , that we also know how to create a database link between a 23ai ADB and a 19C AD...