Ansible - Power of 2 loop on a variable - loops

I need:
vars_prompt:
- name: loopvar
prompt: Enter the loop variable
private: False
default: 16
- hosts: epcs
serial:1
gather_facts: no
tasks:
- name: Do some mathematics divide multiply
#insert logic here
register: my_content # save logic in register
with_sequence: count={{loopvar}} #I need a loop sequence here
when: inventory_hostname == "vm1"
ignore_errors: yes
A simple loop in c++ would be sth like:
int x=0;
for (int i=1; i<loopvar; i+=pow(2,x)) //pow is a math function with pow(2,x)= 2^x
{
cout<<hi;
x++;
}
One more thing, how can I store the results of each iteration in a register, so that I have it available, when the playbook runs serially the 2nd, 3rd or 4th time etc.
Update:
Jinja2 allows the following:
Raise the left operand to the power of the right operand.
{{ 2**3 }} would return 8.
Now keeping this new information in mind, can we do a power of 2 loop?

The type of loop you want is not going to be possible in Ansible. The tool is limited to looping over a list, dictionary, or a sequence but the counter cannot be modified. See the ansible docs on loops.
For something like this you may want to look into writing a custom module.
One more thing, how can I store the results of each iteration in a register, so that I have it available, when the playbook runs serially the 2nd, 3rd or 4th time etc.
See the section in the Ansible docs on how to use register in a loop.
If you register a var named my_content you can access the individual results in my_content.results.

Related

Power Automate overwrites array in for each loop

While building a for each loop which connects to outlook and searches for specific subject line(s) I encountered the iterator working correctly upon entry of the loop (i.e. emails were found and stored in the flow variable) for the 2nd searchterm it empties the entire array and starts anew. Upon not finding the specified the flow stops and reports back not having found anything.
I've tried looking at making the storage append in stead of overwrite but can not find anything to do so.
Also have tried to move the data off to a file for a short while but this gets overwritten as well.
Is there a way to make the array append in stead of getting overwritten?
Outlook.Launch Instance=> OutlookInstance
ON ERROR REPEAT 1 TIMES WAIT 2
END
LOOP FOREACH QM_loop IN Query_mails
Outlook.RetrieveEmailMessages.RetrieveEmails Instance: OutlookInstance Account: Support_Account_2_O365 MailFolder: $'''Postvak In''' EmailsToRetrieve: Outlook.RetrieveMessagesMode.All MarkAsRead: False SubjectContains: QM_loop Messages=> RetrievedEmails
END
Display.ShowMessageDialog.ShowMessageWithTimeout Title: $'''Berichten tellen''' Message: $'''%RetrievedEmails.Count% berichten gevonden met de term: \"%QM_loop%\".''' Icon: Display.Icon.Information Buttons: Display.Buttons.OK DefaultButton: Display.DefaultButton.Button1 IsTopMost: True Timeout: 3 ButtonPressed=> ButtonPressed

Loop over a do file with regression model in Stata

I am estimating several regressions in Stata with the same functional form. I'd like to perform my estimations by looping over a .do file that contains the "program" for my regression. The (simplified) code I have attempted is as follows:
local vars waz haz whz cough fever diar
foreach depvar of local vars {
forvalues i = 10(5)15 {
do "Regression.do"
}
}
Where "Regression.do" is this code:
reg `depvar' distance_`i'
est store `depvar'_`i'
Stata returns an error message: "Error: last estimates not found." How can I amend my code so that I can execute the .do file in a loop?
Simplifying your code as suggested by #Nick Cox is best, however, to answer your question the solution is below:
main do-file
local vars waz haz whz cough fever diar
foreach depvar of local vars {
forvalues i = 10(5)15 {
do "Regression.do" "`i'"
}
}
regression.do
reg `depvar' distance_`1'
est store `depvar'_`1'
The do-file is hardly needed in this example. Using its contents directly avoids the problem that local macros are ... local ... meaning only visible within the same program space.
foreach depvar in waz haz whz cough fever diar {
foreach num in 10 15 {
reg `depvar' distance_`num'
est store `depvar'_`num'
}
}
is one way to simplify your code. although that is partly a matter of taste.
See also https://journals.sagepub.com/doi/pdf/10.1177/1536867X20931028 for more on what bit you.
I see a lot of Stata code which puts content into a local macro only to take it out again just once and immediately. This is like "I have a pen. I put it in a box. I take it out of the box. I now have my pen again." Sometimes the box (meaning, local macro) is a good idea; but other times there is no gain to writing the code that way.
You do flag that you have fuller code, which is fair enough, and at some point having a do-file and passing arguments to it may appear to be better style.
As partly explained in the answer of #24thDan, you can pass arguments to a do-file, which is how a local macro's contents can become visible to and within a do-file.
You can rewrite your do-file this way
* regression.do
args depvar num
regress `depvar' distance_`num'
est store `depvar'_`num'
and within your loops call it with
do regression.do `depvar' `num'
As in the other answer, you can within the do-file refer to the first, second, ... arguments numbering them as 1, 2, and so on, but I recommend the use of args to map those local macros to other macros with intelligible names.

Run a command with different args everytime in Ansible playbook

I am trying to run a command in Ansible so as to find the neighbors in my network:
- name: Get neighbors
junos_rpc:
rpc: "get-lldp-interface-neighbors"
output: 'xml'
args:
interface_device: A
register: net_topology
So my problem comes when in this task I need to loop over a list and give another arg for the interface_device and register the result also in another variable 'net_topology' every time.
- name: Get neighbors
junos_rpc:
rpc: "get-lldp-interface-neighbors"
output: 'xml'
args:
interface_device: "{{ item }}"
loop:
- A
- B
- C
register: net_topology
Once you modify your task like this, it will play three times: once for each element in my example loop. The variable item will get the value of the current element in the list.
You do not need to change your register variable: it will automatically be modified as explained in the ansible documentation:
When you use register with a loop, the data structure placed in the variable will contain a results attribute that is a list of all responses from the module. This differs from the data structure returned when using register without a loop
So you can inspect all your results in a subsequent task by looping over net_topology.results which contains the list of individual results.
Actually i did something similar with the above, but i just passed my list with a different way:
- name: building network topology
junos_rpc:
rpc: "get-lldp-interface-neighbors"
output: 'xml'
args:
interface_device: "{{item}}"
loop:
"{{my_list}}"
register: net_topology
And this is actually the same as doing this also:
- name: building network topology
junos_rpc:
rpc: "get-lldp-interface-neighbors"
output: 'xml'
args:
interface_device: "{{item}}"
with_items:
"{{my_list}}"
register: net_topology
I must say that my initial mistake was the identation of the loop, because it was placed inside the junos_rpc and by doing this I could not get any result !!!

Ansible loops and conditionals

Ansible docs states that:
Combining when with with_items (see Loops), be aware that the when statement is processed separately for each item.
However when I try to skip one item in task, it doesn't work that way:
value_var: [1, 5]
- name: register variable
command: echo "4"
register: var
- name: conditional check
command: nevermind
when: var.stdout > item
By my understanding, that I would get changed on first item within conditional check task, and skipped on second item. But I get:
changed: [guest] => (item=5)
changed: [guest] => (item=1)
What am I doing wrong?
It has nothing to do with loops. You are comparing a string (the result of echo command) with an integer.
You should first cast the value:
when: var.stdout|int > item

Ansible custom nested looping

I have to process output from CloudFormation Outputs that is:
Ansible code that produces this output:
- debug:
var: stack.stack_outputs
Output:
ok: [localhost] => {
"stack.stack_outputs": {
"Roles": "webserver balancer dbserver",
"dbserver": "54.0.1.1 54.0.1.2",
"balancer": "54.0.2.3",
"webserver": "54.0.2.5 54.0.2.7 54.0.3.1"
}}
With that, I want to create 3 (dynamic number!) groups named accordingly filled with appropriate IPs.
Ansible code that I want to HELP WITH:
- name: fill roles with proper hosts
local_action: add_host hostname={{item}} groupname={{role}}
with_whatever: ?...?
In pseudo ansible python it would look like this:
for role in stack.stack_outputs.Roles.split(): # Python
for ip in stack.stack_outputs[role].split(): # Python
local_action: add_host hostname={{ip}} groupname={{role}} # Ansible
Note:
The way to do it for these three roles statically is obviously:
- name: fill role WEBSERVER
local_action: add_host hostname={{item}} groupname=webserver
with_items: stack.stack_outputs.webserver.split()
- name: fill role DBSERVER
local_action: add_host hostname={{item}} groupname=dbserver
with_items: stack.stack_outputs.dbserver.split()
- name: fill role BALANCER
local_action: add_host hostname={{item}} groupname=balancer
with_items: stack.stack_outputs.balancer.split()
I want to do it dynamically, is it even possible in Ansible?
Yes, I can use shell module to hack it putting everything in temporary file and then looping over that; but is there a better solution?
Thanks for any suggestions.
I understand you want the answer to fit a very specific framework. Within that, a custom lookup_plugin is your best bet. Otherwise it'll be an ugly sequence of set_fact and add_host. Sophisticated control structures are the antithesis of Ansible.
You don't explicitly rule out the following, so even if it's too out of the box for you, consider it because I've been reconciling cfn and ansible for a good long while:
Don't use stack outputs to fill your inventory. Use a dynamic inventory script for that (e.g. one that goes over stack outputs or tags set in the templates).
I'm aware of the implications like, you can't have this in a single playbook, but if that's paramount, use group_by.
Hope this helps.
For anyone that comes asking without reading the documentation first. Ansible has been updated to support nested indexing:
http://docs.ansible.com/ansible/playbooks_loops.html#nested-loops
Cheers!

Resources