Is it possible to manage a device instead of a connection with Ansible 'nmcli' module? - ansible

I have to apply the following configuration on several hosts via Ansible:
nmcli device modify "device_name" ens192 ipv6.method "disabled"
I wanted to use the nmcli module instead of a command as it is cleaner. But from what I found on the documentation and forums the nmcli module manage only connections.
Apart from recovering all connections associated to an interface and modifying each one using Ansible nmcli module I could not find a way to do it. This solution beeing, in my opinion, uglier than using command module I will stick with command.
Any informed comment or suggestion would be appreciated.
For the sake of precision the current code used to disable ipv6 if networkmanager is used:
- name: get service facts
service_facts:
- name: Disable ipv6 with network manager
become: yes
command: "/bin/nmcli device modify {{ ansible_default_ipv4.interface }} ipv6.method 'disabled'"
when: ansible_facts.services["NetworkManager.service"] is defined
changed_when: false

I am not sure if I understand your question fully since there is no example what you have tried, problem description, description of your system, used versions, confguration or error messages.
Regarding
I wanted to use the nmcli module instead of a command as it is cleaner
and according the documentation of the module nmcli there is a parameter ifname
The interface to bind the connection to.
The connection will only be applicable to this interface name.
A special value of '*' can be used for interface-independent connections.
The ifname argument is mandatory for all connection types except bond, team, bridge, vlan and vpn.
This parameter defaults to conn_name when left unset for all connection types except vpn that removes it.
So looking at the CLI output of nmcli device show
GENERAL.DEVICE: eth0
GENERAL.TYPE: ethernet
GENERAL.HWADDR: AB:CD:EF:01:02:03
GENERAL.MTU: 1500
GENERAL.STATE: 100 (connected)
GENERAL.CONNECTION: eth0
...
and since conn_name obviously points to GENERAL.CONNECTION, wouldn't that parameter
ifname for GENERAL.DEVICE not be that one which you are looking for?
The Examples are showing also the usage of ifname together with conn_name.
Furthermore ipv6.method disabled isn't available in example in RHEL 7, but as of 8.
- name: Make sure IPv6 is disabled
shell:
cmd: nmcli conn mod eth0 ipv6.method disabled
when: ansible_distribution == 'RedHat' and ansible_distribution_major_version == '8'

Related

What's the "best" way to add an ip route using ansible?

I am unable to find an ansible module that adds ip routes.
Basically the command I'm looking for should allow something like:
sudo ip route add 12.3.4.0/24 via 123.456.78.90
I found net_static_route_module which seems related, but is deprecated since 2022-06-01.
A simple solution would be:
- name: Add a route
ansible.builtin.shell:
cmd: sudo ip route add 12.3.4.0/24 via 123.456.78.90
of course, but inbuilt modules are usually better.
Additional information
This task will be executed on a subset of all nodes (ubuntu 22.04 machines that are all part of a cloud cluster using openstack) (specified by groups). Concrete subnets and IPs will be defined using variables.
An example hostfile could look like this:
master:
hosts:
localhost:
ansible_connection: local
ansible_python_interpreter: /usr/bin/python3
ansible_user: ubuntu
ip: localhost
workers:
children:
ephemeral:
hosts: {}
hosts:
someworker:
ansible_connection: ssh
ansible_python_interpreter: /usr/bin/python3
ansible_user: ubuntu
This playbook will be used to setup wireguard. Every vpn-node (those nodes will be connected with each other via wireguard) is connected in its own subnet with multiple worker nodes. Those workers need to add the ip route to get back to the master node which is in a different subnet, but in the same virtual subnet created by wireguard and the vpn nodes). I do not think that this is related to my question, but I might overlook how this can affect the right answer.
From your description I understand that you like to configure the network route settings on a Linux based operating system (Debian/GNU Linux, Ubuntu 22.04) and not on a dedicated router or switch.
Whereby the mentioned module net_static_route was for providing
... declarative management of static IP routes on network appliances (routers, switches et. al.).
and became deprecated
Removed in: major release after 2022-06-01
Why: Updated modules released with more functionality
Alternative: Use platform-specific [netos]_static_route module
it further recommends to use the vendor and platform specific modules instead.
Certain Linux Distributions tend to integrate and use NetworkManager for creating and managing network connections.
Documentation
RHEL7 - Getting Started with NetworkManager
ArchLinux - NetworkManager
Ubuntu - NetworkManager
...
So the respective Ansible module for this is nmcli module – Manage Networking. You may have a look into the Parameters and Examples, especially into the parameters for route*.
Further Readings
For more examples have a look at
How to configure network settings with Ansible system roles
Linux System Roles

Port forward with Ansible and firewalld

I am experimenting with Ansible and want to set a port forward rule in firewalld.
I've tried the following:
- name: Port forward for 443
become: true
ansible.posix.firewalld:
port_forward:
- port: 443
proto: tcp
toport: 2443
state: enabled
This resulted in:
ERROR: Exception caught: queryForwardPort() got an unexpected keyword argument ''to_port''
If I format it as a list it says
Only one port forward supported at a time
and if I format it as a dict I get:
argument port_forward is of type <class ''dict''> and we were unable to convert to list: <class ''dict''> cannot be converted to a list'
I'm using a Debian 11 VM with Ansible 2.10.8. I've installed the latest ansible.posix (1.3.0) as the included version was older (1.1.1). I can manually create the rule on the target machine (OEL 8).
This is as far as I got using the documentation.
Any idea how to get this working?
Thank you in advance!
At a short glance there seems to be syntax errors. The first error message says
ERROR: Exception caught: queryForwardPort() got an unexpected keyword argument ''to_port''
to_port, whereby it should be toport according the linked documentation of the firewalld_module. Since your are on ansible.posix.collections v1.3.0 and there is bug report open according Ansible Collections Ansible Posix Issue #247, were downgrading to v1.2.0 fix the issue, another approach might be according Ansible Issue #28349 using the parameter rich_rule. That would work for v1.1.1 too.
- name: Redirect port 443 to 8443
firewalld:
rich_rule: rule family={{ item }} forward-port port=443 protocol=tcp to-port=8443
zone: public
permanent: true
immediate: true
state: enabled
with_items:
- ipv4
- ipv6
To get the older version you could use
ansible-galaxy collection install ansible.posix:1.2.0
The syntax error is in the file ansible.posix/plugins/modules/firewalld.py and seems to be simple enough that one can fix it on hisself locally on behalf.

Can we create a playbook to install a package in our own system?

I'm using Ubuntu Linux
I have created an inventory file and I have put my own system IP address there.
I have written a playbook to install the nginx package.
I'm getting the following error:
false, msg" : Failed to connect to the host via ssh: connect to host myip : Connection refused, unreachable=true
How can I solve this?
You could use the hosts keyword with the value localhost
- name: Install nginx package
hosts: localhost
tasks:
- name: Install nginx package
apt:
name: nginx
state: latest
Putting your host IP directly in your inventory treats your local machine as any other remote target. Although this can work, ansible will use the ssh connection plugin by default to reach your IP. If an ssh server is not installed/configured/running on your host it will fail (as you have experienced), as well as if you did not configure the needed credentials (ssh keys, etc.).
You don't need to (and in most common situations you don't want to) declare localhost in your inventory to use it as it is implicit by default. The implicit localhost uses the local connection plugin which does not need ssh at all and will use the same user to run the tasks as the one running the playbook.
For more information on connection plugins, see the current list
See #gary lopez answer for an example playbook to use localhost as target.

Set static IP on Centos7

I have a CentOS7 box that I need to change from DHCP to Static IP. I am using the ansible code below and I keep getting message. I have installed the required packages for this to work, so I dont think that is the issue.
"FAILED! => {"changed": false, "msg": "Error: Failed to modify connection 'System ens192': No such method 'Update2'\n", "name": "System ens192", "rc": 1}"
I know the ifname is "ens192" not sure about the conn_name. I did a "nmcli connection show" and a "nmcli device show" but none of them seem to work.
I have tried for the conn_name "ens192, System ens192, my-en192" and I get the same error message just with the different conn_names.
I would ultimately like to have these values set by the gathering facts procedure, but not sure how to do this?
- name: Add an Ethernet connection with static IP configuration
nmcli:
conn_name: ens192
ifname: ens192
type: ethernet
ip4: 192.0.2.100/24
gw4: 192.0.2.1
state: present
"nmcli connection show" and a "nmcli device show" but none of them seem to work
It should work.
Did you install dependancies for this module?
If not you can install them with ansible this way:
- name: install needed network manager libs
package:
name:
- NetworkManager-glib
- nm-connection-editor
- libsemanage-python
- policycoreutils-python
state: present
Or just yum install them.
When I run the nmcli commands, this is the output I get. I have tried to use on the conn_name: ens192 and System ens192 and both give me the same error message.
nmcli device show
GENERAL.DEVICE: ens192
GENERAL.TYPE: ethernet
GENERAL.HWADDR: 00:50:56:87:FB:F1
GENERAL.MTU: 1500
GENERAL.STATE: 100 (connected)
GENERAL.CONNECTION: System ens192
GENERAL.CON-PATH: /org/freedesktop/NetworkManager/ActiveConnection/0
WIRED-PROPERTIES.CARRIER: on
IP4.ADDRESS[1]: 10.21.10.100/24
IP4.GATEWAY: 10.21.10.254
IP4.DNS[1]: 8.8.8.8
IP4.DNS[2]: 4.2.2.2
IP6.ADDRESS[1]:
IP6.GATEWAY: --
GENERAL.DEVICE: lo
GENERAL.TYPE: loopback
GENERAL.HWADDR: 00:00:00:00:00:00
GENERAL.MTU: 65536
GENERAL.STATE: 10 (unmanaged)
GENERAL.CONNECTION: --
GENERAL.CON-PATH: --
IP4.ADDRESS[1]: 127.0.0.1/8
IP4.GATEWAY: --
IP6.ADDRESS[1]: ::1/128
IP6.GATEWAY: --
[root#kamailio01 ~]# nmcli connection show
NAME UUID TYPE DEVICE
System ens192 2df1f002-52f2-4d9c-b7dd-7af061eceb34 ethernet ens192
In my work, I've just had a Jinja2 template and used the template module to overwrite the /etc/sysconfig/network-scripts/ifcfg-whatever file.

Ansible connect to jump machine through VPN?

I was wondering if it were possible to tell Ansible to set up a VPN connection before executing the rest of the playbook. I've googled around, but haven't seen much on this.
You could combine a local playbook to setup a VPN and a playbook to run your tasks against a server.
Depending on whats the job you can use ansible or a shell script to connect the VPN. Maybe there should be another playbook to disconnect afterwards.
As result you will have three playbooks and one to combine them via include:
- include: connect_vpn.yml
- include: do_stuff.yml
- include: disconnect_vpn.yml
Check How To Use Ansible and Tinc VPN to Secure Your Server Infrastructure.
Basically, you need to install thisismitch/ansible-tinc playbook and create a hosts inventory file with the nodes that you want to include in the VPN, for example:
[vpn]
prod01 vpn_ip=10.0.0.1 ansible_host=162.243.125.98
prod02 vpn_ip=10.0.0.2 ansible_host=162.243.243.235
prod03 vpn_ip=10.0.0.3 ansible_host=162.243.249.86
prod04 vpn_ip=10.0.0.4 ansible_host=162.243.252.151
[removevpn]
Then you should review the contents of the /group_vars/all file such as:
---
netname: nyc3
physical_ip: "{{ ansible_eth1.ipv4.address }}"
vpn_interface: tun0
vpn_netmask: 255.255.255.0
vpn_subnet_cidr_netmask: 32
where:
physical_ip is IP address which you want tinc to bind to;
vpn_netmask is the netmask that the will be applied to the VPN interface.
If you're using Amazon Web Services, check out the ec2_vpc_vpn module which can create, modify, and delete VPN connections. It uses boto3/botocore library.
For example:
- name: create a VPN connection
ec2_vpc_vpn:
state: present
vpn_gateway_id: vgw-XXXXXXXX
customer_gateway_id: cgw-XXXXXXXX
- name: delete a connection
ec2_vpc_vpn:
vpn_connection_id: vpn-XXXXXXXX
state: absent
For other cloud services, check the list of Ansible Cloud Modules.

Resources