Ansible json_query'd json to yaml inventory with variables - ansible

I have an ansible json_query'd result that I'm trying to use as the inventory for another playbook and my noob skills at manipulating data are lacking.
The json_query is:
community.general.json_query('device_info.value[].{ hostname: DeviceName, serial: DeviceServiceTag, model: Model, connected: ConnectionState, networkaddress: DeviceManagement[0].NetworkAddress }')
With the results being something like this (100+ hosts in real world):
[
{
"hostname": "thingy1.company.org",
"serial": "serial1",
"model": "modelA",
"connected": true,
"networkaddress": "1.2.3.4"
},
{
"hostname": "thingy2.company.org",
"serial": "serial2",
"model": "modelB",
"connected": true,
"networkaddress": "1.2.3.5"
}
]
I'm trying to convert this result into a usable yaml inventory file. Here is what I'm trying to get to.
groupname:
hosts:
thingy1.company.org:
connected: true
model: modelA
networkaddress: 1.2.3.4
serial: serial1
thingy2.company.org:
connected: true
model: modelB
networkaddress: 1.2.3.5
serial: serial2
Any tips to help a noob out?

Given the list
result_list:
- connected: true
hostname: thingy1.company.org
model: modelA
networkaddress: 1.2.3.4
serial: serial1
- connected: true
hostname: thingy2.company.org
model: modelB
networkaddress: 1.2.3.5
serial: serial2
Declare the dictionary
result_dict: "{{ dict(result_list|map(attribute='hostname')|
zip(result_list)) }}"
gives
result_dict:
thingy1.company.org:
connected: true
hostname: thingy1.company.org
model: modelA
networkaddress: 1.2.3.4
serial: serial1
thingy2.company.org:
connected: true
hostname: thingy2.company.org
model: modelB
networkaddress: 1.2.3.5
serial: serial2
You can remove the attribute hostname
result_dict: "{{ dict(result_list|map(attribute='hostname')|
zip(result_list|
ansible.utils.remove_keys(target=['hostname']))) }}"
gives
result_dict:
thingy1.company.org:
connected: true
model: modelA
networkaddress: 1.2.3.4
serial: serial1
thingy2.company.org:
connected: true
model: modelB
networkaddress: 1.2.3.5
serial: serial2
Write the dictionary to the file
- copy:
dest: /tmp/my_hosts.yaml
content: |
groupname:
hosts:
{{ result_dict|to_nice_yaml(indent=2)|indent(4, first=true) }}
gives
shell> cat /tmp/my_hosts.yaml
groupname:
hosts:
thingy1.company.org:
connected: true
model: modelA
networkaddress: 1.2.3.4
serial: serial1
thingy2.company.org:
connected: true
model: modelB
networkaddress: 1.2.3.5
serial: serial2
You can change the query
result_list: "{{ device_info.value|community.general.json_query(my_query) }}"
my_query: '[].{key: DeviceName, value: {serial: DeviceServiceTag, model: Model, connected: ConnectionState, networkaddress: DeviceManagement[0].NetworkAddress}}'
and get the list
result_list:
- key: thingy1.company.org
value:
connected: true
model: modelA
networkaddress: 1.2.3.4
serial: serial1
- key: thingy2.company.org
value:
connected: true
model: modelB
networkaddress: 1.2.3.5
serial: serial2
It's trivial to change this list to the dictionary
result_dict: "{{ result_list|items2dict }}"
gives
result_dict:
thingy1.company.org:
connected: true
model: modelA
networkaddress: 1.2.3.4
serial: serial1
thingy2.company.org:
connected: true
model: modelB
networkaddress: 1.2.3.5
serial: serial2

Related

Ansible playbook not looping through device_list

I am trying to loop variables into a playbook, but I keep getting the following error
TASK [Add policy package to model device] ********************************************************************************************************************************************************************
failed: [fmg01] (item={'device_name': 'FGT1', 'device_ip': '192.168.0.103', 'group_name': 'Branch_Office', 'policy_package': 'default', 'device_serial': 'FGVM01TM12345678'}) => {"ansible_loop_var": "item", "changed": false, "item": {"device_ip": "192.168.0.103", "device_name": "FGT1", "device_serial": "FGVM01TM12345678", "group_name": "Branch_Office", "policy_package": "default"}, "meta": {"status": {"code": -10, "message": "The data is invalid for selected url"}, "url": "/pm/pkg/adom/root"}, "unreachable": false}
Below is my YML playbook. It works just fine when I use static variables (write out a single IP address and serial number as a string)
---
- name: Add model device to FMG and install Policy Package
hosts: fmg01
# gather_facts: no
connection: httpapi
collections:
- fortinet.fortimanager
vars_files:
- inventory.yml
tasks:
- name: Add model device
fmgr_dvm_cmd_add_device:
loose_validation: true
method: exec
params:
- data:
adom: root
device:
# device action: add_model
mgmt_mode: 'fmg'
#os_ver: 6
#mr: 4
sn: '{{item.device_serial}}'
adm_pass: 'password'
adm_usr: 'admin'
ip: '{{item.device_ip}}'
loop: '{{device_list}}'
- name: Add policy package to model device
fmgr_pm_pkg_adom_obj:
loose_validation: true
method: set
url_params:
adom: root
params:
- data:
name: default
scope member:
- name: '{{item.device_serial}}'
vdom: root
type: pkg
loop: '{{device_list}}'
- name: Install policy package to model device
fmgr_securityconsole_install_package:
loose_validation: true
method: exec
params:
- data:
adom: root
pkg: default
scope:
- name: '{{item.device_serial}}'
vdom: root
loop: '{{device_list}}'
Here is my inventory.yml file. I tested this ok with the first task. It passed in the IP address in ok. I tested the other tasks with the device_serial parameter, but that did not work.
#feeds into playbook
#add_device / add_device_group
device_list:
- device_name: FGT1
device_ip: '192.168.0.103'
group_name: Branch_Office
policy_package: default
device_serial: 'FGVM01TM12345678'
Problem turned out to be an indention problem with the params portion
- name: Add policy package to model device
fmgr_pm_pkg_adom_obj:
loose_validation: true
method: set
url_params:
adom: root
params:
- data:
name: default
scope member:
- name: '{{item.device_serial}}'
vdom: root
type: pkg
loop: '{{device_list}}'

Ansible loop built from variable sets

I am pretty new to Ansible as a network engineer and have found it breaking my brain. I've used basic loops in some Ansible playbooks. Now I'm trying something a bit more complex and I'm sure I'm missing something because it feels like it should be simple.
I want to take these variables in a playbook:
vars:
smb_tcp_ports:
- '139'
- '445'
smb_udp_ports:
- '137'
- '138'
smb_ips:
- '172.16.13.130'
- '172.16.13.0/26'
- '200X:8X0:fX4a:X053::/64'
- '200X:8X0:fX4a:X050::130'
and loop through them so I build a new variable like this:
vars:
smb_allowed_ips_tcp:
- { ip: "172.16.13.130", port: ['139','445'] }
- { ip: "172.16.13.0/26", port: ['139','445'] }
- { ip: "X001:8X0:fX4a:X053::/64", port: ['139','445'] }
- { ip: "X001:8X0:fX4a:X050::130", port: ['139','445'] }
smb_allowed_ips_udp:
- { ip: "172.16.13.130", port: ['137','138'] }
- { ip: "172.16.13.0/26", port: ['137','138'] }
- { ip: "200X:8X0:fX4a:X053::/64", port: ['137','138'] }
- { ip: "200X:8X0:fX4a:X050::130", port: ['137','138'] }
^^^ the above bit that I want to generate is the bit that I'm struggling with ^^^
Then I can send it to this:
- name: Allow SMB TCP
ufw:
rule: allow
src: '{{ item.0.ip }}'
port: '{{ item.1 }}'
proto: tcp
with_subelements:
- "{{ smb_allowed_ips_tcp }}"
- port
when: "'smbserver' in group_names"
- name: Allow SMB UDP
ufw:
rule: allow
src: '{{ item.0.ip }}'
port: '{{ item.1 }}'
proto: udp
with_subelements:
- "{{ smb_allowed_ips_udp }}"
- port
when: "'smbserver' in group_names"
The question used to have a lot of words here. I deleted it. Thanks Larsks. I hope this is clearer?
I tried set_facts, but there is loads of stuff I don't understand in examples i see, like adding | symbols and writing list, product etc, and I always end up breaking. It also doesnt seem to add as an array, it overwrites.
Answered here: using https://ansibledaily.com/process-complex-variables-with-set_fact-and-with_items/
---
- hosts: myhosts
gather_facts: true
become: true
vars:
smb_tcp_ports:
- '139'
- '445'
smb_udp_ports:
- '137'
- '138'
smb_ips:
- '172.16.13.130'
- '172.16.13.0/26'
- '200X:8X0:fX4a:X053::/64'
- '200X:8X0:fX4a:X050::130'
smb_ips_tcp: {}
tasks:
- name: Populate IPs in dict
set_fact:
smb_ips_tcp: "{{ smb_ips_tcp | combine({'ip': item}) }}"
with_items:
- "{{ smb_ips }}"
register: smbout
- name: Populate ports in dict
set_fact:
smb_ips_tcp: "{{ item | combine({'port': smb_tcp_ports}) }}"
with_items:
- "{{ smbout.results | map(attribute='ansible_facts.smb_ips_tcp') | list }}"
register: smbout
- name: smbout results
set_fact:
smb_ips_tcp: "{{ smbout.results | map(attribute='ansible_facts.smb_ips_tcp') | list }}"
- name: Allow SMB TCP
ufw:
rule: allow
src: '{{ item.0.ip }}'
port: '{{ item.1 }}'
proto: tcp
with_subelements:
- "{{ smb_ips_tcp }}"
- port
I think I had missed the register bit. So when I tried the register facts bit before it kept leaving me with one key value pair. Which was useless. The register though is allowing me to keep all the key values and use them again.
Unsure if this is a duplicate question now.
It sounds like you may have resolved your question, but I thought you might be interested in an alternative implementation. I would probably solve this using the product filter, which produces the cartesian product of two lists. For example, to produce smb_allowed_ips_tcp, I would write:
- name: create smb_allowed_ips_tcp
set_fact:
smb_allowed_ips_tcp: "{{ smb_allowed_ips_tcp + [{'ip': item.0, 'port': item.1}] }}"
loop: "{{ smb_ips|product(smb_tcp_ports)|list }}"
vars:
smb_allowed_ips_tcp: []
This produces a data structure that looks like:
TASK [debug] ******************************************************************************************
ok: [localhost] => {
"smb_allowed_ips_tcp": [
{
"ip": "172.16.13.130",
"port": "139"
},
{
"ip": "172.16.13.130",
"port": "445"
},
{
"ip": "172.16.13.0/26",
"port": "139"
},
{
"ip": "172.16.13.0/26",
"port": "445"
},
{
"ip": "200X:8X0:fX4a:X053::/64",
"port": "139"
},
{
"ip": "200X:8X0:fX4a:X053::/64",
"port": "445"
},
{
"ip": "200X:8X0:fX4a:X050::130",
"port": "139"
},
{
"ip": "200X:8X0:fX4a:X050::130",
"port": "445"
}
]
}
We can feed that to the ufw module like this:
- name: Allow SMB TCP
ufw:
rule: allow
src: '{{ item.ip }}'
port: '{{ item.port }}'
proto: tcp
loop: "{{ smb_allowed_ips_tcp }}"
There are fewer tasks required for this solution, and I think the logic is a little easier to follow.

Ansible - Use when condition in a playbook for roles

I am trying to add a when condition in my ansible-playbook. However, I am not able to figure out the exact syntax/method to do it because my roles are using additional parameters. Below mentioned is my playbook
---
- name: Deploying application code
hosts: uat-aegis
roles:
- { role: roles/send_slack, slack_message_text: "*`Started : Deploying code for {{ module_name }} on {{ inventory_hostname }}`*"}
- { role: roles/application_code_backup, backup_directory_name: "NAME", repo_directory: "/path/to/repo" }
- { role: roles/application_copy_config, repo_directory: "/path/to/repo"}
- { role: roles/application_git_pull, repo_url: "git#code.git", repo_directory: "/path/to/repo", branch_name: "BRANCH_NAME"}
- { role: roles/application_pm2_restart, process_name: "NAME" }
- { role: roles/send_slack, slack_message_text: "*`=== Completed : Deploying code for {{ module_name }} on {{ inventory_hostname }} ===`*"}
Here I need to execute roles/application_copy_config only when a certain variable value is true. This variable value is passed as --extra-vars while executing the ansible-playbook from Jenkins(Boolean value parameter in Execute Script). I have tried using the below piece of code but it does not work.
---
- name: Deploying application code
hosts: uat-aegis
roles:
- { role: roles/send_slack, slack_message_text: "*`Started : Deploying code for {{ module_name }} on {{ inventory_hostname }}`*"}
- { role: roles/application_code_backup, backup_directory_name: "NAME", repo_directory: "/path/to/repo" }
- { role: roles/application_copy_config
when: "copy_config=true", repo_directory: "/path/to/repo"}
- { role: roles/application_git_pull, repo_url: "git#code.git", repo_directory: "/path/to/repo", branch_name: "BRANCH_NAME"}
- { role: roles/application_pm2_restart, process_name: "NAME" }
- { role: roles/send_slack, slack_message_text: "*`=== Completed : Deploying code for {{ module_name }} on {{ inventory_hostname }} ===`*"}
ansible-playbook command is as follows
ansible-playbook plays/deploy_application/code.yml --extra-vars "module_name=$MODULE_NAME config_copy_path=$CURRENT_PATH/ env=$ENVIRONMENT copy_config=$COPY_CONFIG"
Please help me to use the when condition in the ansible-playbook. This is required becuase I need to execute the role: roles/application_copy_config only when the variable value is true. I have used this reference for adding when condition in the role
Was able to apply the when condition for boolean values using bool filter as mentioned below
---
- name: Deploying application code
hosts: uat-aegis
roles:
- { role: roles/send_slack, slack_message_text: "*`Started : Deploying code for {{ module_name }} on {{ inventory_hostname }}`*"}
- { role: roles/application_code_backup, backup_directory_name: "NAME", repo_directory: "/path/to/repo", when: var1 | bool }
- { role: roles/application_copy_config, repo_directory: "/path/to/repo"}
- { role: roles/application_git_pull, repo_url: "git#code.git", repo_directory: "/path/to/repo", branch_name: "BRANCH_NAME", when: var2 | bool}
- { role: roles/application_pm2_restart, process_name: "NAME", when: not var3 | bool }
- { role: roles/send_slack, slack_message_text: "*`=== Completed : Deploying code for {{ module_name }} on {{ inventory_hostname }} ===`*"}
Use the below code to check true and false
when: var1 | bool ----> true
when: not var2 | bool ----> false
You can specify conditionals with different style:
- name: Deploying application code
hosts: uat-aegis
roles:
- role: roles/application_code_backup
vars:
backup_directory_name: "NAME"
repo_directory: "/path/to/repo"
when: var1 | bool

Role duplication and execution, passing multiple variable structure for arguments that can have multiple entries

I am trying come up with a way to pass multiple variables to the same field in a role but not having any luck getting it to work using the Role duplication and execution method I've been using. As an example I want an SLB Server to have multiple ports assigned to it using the port_number variable. I'm new to Ansible so making some rookie mistakes like the code below (port_number: "80", port_number: "8080" returns duplicate entry so only uses the first) but I have tried just about every syntax I have found examples for and nothing is working right. The end result is basically having test3 with both of the port_number: entries assigned to it but at this point I'm not even sure it's possible doing it this way or if I have to run a separate module after the fact to add the entries. Any help is greatly appreciated. Thanks.
---
- name: Deploy A10 config
connection: local
hosts: all
roles:
- role: server
vars:
name: "test1"
fqdn_name: "test1.test.domain.net"
health_check: "TCP-8080-HALFOPEN"
port_number: "80"
- { role: server, vars: { name: "test2", fqdn_name: "test2.test.domain.net", port_number: "8080" }}
- { role: server, vars: { name: "test3", fqdn_name: "test3.test.domain.net", port_number: "80", port_number: "8080" }}
---
- name: Test server create
a10_slb_server:
a10_host: "10.1.1.1"
a10_username: "admin"
a10_password: "admin"
a10_port: "443"
a10_protocol: "https"
state: present
name: "{{ name }}"
fqdn_name: "{{ fqdn_name }}"
port_list:
- port_number: "{{ port_number }}"
In your code vars is dictionary. The keys in a dictionary must be unique.
vars:
name: "test1"
fqdn_name: "test1.test.domain.net"
health_check: "TCP-8080-HALFOPEN"
port_number: "80"
YAML resolves the duplication of the keys simply by overriding the value. This expression
vars: { name: "test3", fqdn_name: "test3.test.domain.net", port_number: "80", port_number: "8080" }
would give
"vars": {
"fqdn_name": "test3.test.domain.net",
"name": "test3",
"port_number": "8080"
}
In your code port_list is list. It's a list of dictionaries. This seems to be the proper way to declare multiple port numbers.
port_list:
- port_number: "80"
- port_number: "8080"
In serialized format
port_list: [{port_number: "80"}, {port_number: "8080"}]
But, in your code role: server it's not clear how these variables are used in the role. It is necessary to review the role to learn how to submit the data.
For example:
- role: server
vars:
name: "test1"
fqdn_name: "test1.test.domain.net"
health_check: "TCP-8080-HALFOPEN"
port_number1: "80"
port_number2: "8080"
--
- name: Test server create
a10_slb_server:
a10_host: "10.1.1.1"
a10_username: "admin"
a10_password: "admin"
a10_port: "443"
a10_protocol: "https"
state: present
name: "{{ name }}"
fqdn_name: "{{ fqdn_name }}"
port_list:
- port_number: "{{ port_number1 }}"
- port_number: "{{ port_number2 }}"

Advice on improving my playbooks efficiency?

Started to experiment with Ansible and using playbooks to automate some routine tasks on network devices. I was able to get some basic stuff working and learn in the process but I know my knowledge is limited so when I see this playbook and how much stuff seems redundant I have to assume there are better ways to eliminate some of the redundancy and make things cleaner and more efficient.
Example I want to try to use and explain in order to get some ideas on is around configuring a new vlan on a group of devices.
Typically a new vlan first needs to be configured on the two distribution switches and then there are specific interfaces on those two switches that we have to add the vlan to.
So, for this first part I have the two hosts in a group called "dist" in my hosts file:
[dist]
DIST01 ansible_host=10.10.1.1
DIST02 ansible_host=10.10.1.2
Then I created the following in my playbook:
- name: Add Heartbeat VLAN to DIST
hosts: dist
connection: local
gather_facts: no
tasks:
- name: Include Login Credentials
include_vars: secrets.yml
- name: Define Provider
set_fact:
provider:
host: "{{ ansible_host }}"
username: "{{ creds['username'] }}"
password: "{{ creds['password'] }}"
tasks:
- name: Ensure VLAN Exists
provider: "{{ provider }}"
nxos_vlan: vlan_id="2600" state=present host={{ ansible_host }}
- name: Ensure VLAN Name Configured
provider: "{{ provider }}"
nxos_vlan: vlan_id={{ item.vid }} name={{ item.name }} host={{ ansible_host }} state=present
with_items:
- { vid: 2600, name: Ansible Heartbeat VLAN }
- name: ASSIGN VLAN TO TRUNK PORTS
nxos_switchport:
interface: "{{ item.interface }}"
mode: trunk
trunk_vlans: "{{ item.vlan }}"
provider: "{{ provider }}"
with_items:
- { interface: po850, vlan: 2600 }
- { interface: po860, vlan: 2600 }
- { interface: po865, vlan: 2600 }
- { interface: po868, vlan: 2600 }
- { interface: po871, vlan: 2600 }
- { interface: po872, vlan: 2600 }
- { interface: po875, vlan: 2600 }
- { interface: po877, vlan: 2600 }
- { interface: po884, vlan: 2600 }
So, for each host in that group it iterates through a list of interfaces / ports and adds the vlan specified.
Question #1.
First thing that stands out as being "inefficient" in my mind is I don't believe its very wise to have to specify the "vlan: 2600" every where.
I would think I should just set the vlan as a variable some where (in the playbook? in some other file that gets called?) to be used in each case where it is needed.
Next set of tasks:
After the previous task the next requires us to connect to each access switch that needs the vlan to be deployed on and configure the new vlan there.
The issue I run into here is that the port-channel on each of these switches is a different interface #. So I can't apply the same config by just iterating through a list of devices.
For instance what I have to do is something like this:
host: ACCESS01 interface: po850 vlan: 2600
host: ACCESS02 interface: po860 vlan: 2600
host: ACCESS03 interface: po870 vlan: 2600
So for each host/switch you add the vlan to the interface associated with that switch.
I just created a new task for each device that specifies the interface to configure for that switch.
Example:
- name: Add Heartbeat VLAN to ACCESS01
hosts: ACCESS01
connection: local
gather_facts: no
tasks:
- name: Include Login Credentials
include_vars: secrets.yml
- name: Define Provider
set_fact:
provider:
host: "{{ ansible_host }}"
username: "{{ creds['username'] }}"
password: "{{ creds['password'] }}"
tasks:
- name: Ensure VLAN Exists
provider: "{{ provider }}"
nxos_vlan: vlan_id="2600" state=present host={{ ansible_host }}
- name: Ensure VLAN Name Configured
provider: "{{ provider }}"
nxos_vlan: vlan_id={{ item.vid }} name={{ item.name }} host={{ ansible_host }} state=present
with_items:
- { vid: 2600, name: Ansible Heartbeat VLAN }
- name: ASSIGN VLAN TO PORTS
nxos_switchport:
interface: "{{ item.interface }}"
mode: trunk
trunk_vlans: "{{ item.vlan }}"
provider: "{{ provider }}"
with_items:
- { interface: po850, vlan: 2600 }
- name: Add Heartbeat VLAN to ACCESS02
hosts: ACCESS02
connection: local
gather_facts: no
tasks:
- name: Include Login Credentials
include_vars: secrets.yml
- name: Define Provider
set_fact:
provider:
host: "{{ ansible_host }}"
username: "{{ creds['username'] }}"
password: "{{ creds['password'] }}"
tasks:
- name: Ensure VLAN Exists
provider: "{{ provider }}"
nxos_vlan: vlan_id="2600" state=present host={{ ansible_host }}
- name: Ensure VLAN Name Configured
provider: "{{ provider }}"
nxos_vlan: vlan_id={{ item.vid }} name={{ item.name }} host={{ ansible_host }} state=present
with_items:
- { vid: 2600, name: Ansible Heartbeat VLAN }
- name: ASSIGN VLAN TO PORTS
nxos_switchport:
interface: "{{ item.interface }}"
mode: trunk
trunk_vlans: "{{ item.vlan }}"
provider: "{{ provider }}"
with_items:
- { interface: po860, vlan: 2600 }
- name: Add Heartbeat VLAN to ACCESS03
hosts: ACCESS03
connection: local
gather_facts: no
tasks:
- name: Include Login Credentials
include_vars: secrets.yml
- name: Define Provider
set_fact:
provider:
host: "{{ ansible_host }}"
username: "{{ creds['username'] }}"
password: "{{ creds['password'] }}"
tasks:
- name: Ensure VLAN Exists
provider: "{{ provider }}"
nxos_vlan: vlan_id="2600" state=present host={{ ansible_host }}
- name: Ensure VLAN Name Configured
provider: "{{ provider }}"
nxos_vlan: vlan_id={{ item.vid }} name={{ item.name }} host={{ ansible_host }} state=present
with_items:
- { vid: 2600, name: Ansible Heartbeat VLAN }
- name: ASSIGN VLAN TO PORTS
nxos_switchport:
interface: "{{ item.interface }}"
mode: trunk
trunk_vlans: "{{ item.vlan }}"
provider: "{{ provider }}"
with_items:
- { interface: po870, vlan: 2600 }
And so you see... I know when I see things almost identical repeated over and over again I have to assume there is a better way and I just don't know enough yet to solve on my own.
Question #2. I suspect there is a better way to handle repeating the following for each task in the playbook:
tasks:
- name: Include Login Credentials
include_vars: secrets.yml
- name: Define Provider
set_fact:
provider:
host: "{{ ansible_host }}"
username: "{{ creds['username'] }}"
password: "{{ creds['password'] }}"
Question #3, Could I possibly just list this data some where, either in the playbook or another file maybe and then create a task that could iterate through the data to determine what port needs to be configured?
host: ACCESS01 interface: po850 vlan: 2600
host: ACCESS02 interface: po860 vlan: 2600
host: ACCESS03 interface: po870 vlan: 2600
Some sort of logic to this in my mind would be something like, if "host" equals "ACCESS01" then interface equals po850.
So the task could just be referencing variables that are populated depending on the host its currently working on?
Any thoughts and advice on improving both the playbook and my knowledge of things is greatly appreciated. I guess I'm look for the most "ansiblistic" way to accomplish this. That's not a word huh?
For Question#1, you can use like this:
- name: ASSIGN VLAN TO TRUNK PORTS
nxos_switchport:
interface: "{{ item.interface }}"
mode: trunk
trunk_vlans: "{{ item.vlan | default('2600') }}"
provider: "{{ provider }}"
with_items:
- interface: po850
- interface: po860
- interface: po865
- interface: po868
- interface: po871
- interface: po872
- interface: po875
- interface: po884
If you want to assign different vlan to one or more interface(s), then you can use like this:
- { interface: po850, vlan: 2700 }
Hope that help you.

Resources