mirror of
https://github.com/linux-system-roles/network.git
synced 2026-01-23 10:25:28 +00:00
library: let the module handle all connections at once
Instead, of having the tasks call the "network_connections.py" library for each connection profile individually (using with_items), pass all profiles at once. The advantage is: - the module can validate the input arguments better as it has access to all profiles. For example, when a slave connection refers to another master profile from the same play. Previously, each invocation of the module only sees the current profile and cannot verify whether the reference is valid. - while configuring the network, the play might need to shortly disconnect the control connection. In the previous way, after tearing down the network the target host becomes unreachable for ansible and the following steps cannot be executed anymore. Now, all steps are done as a whole on the target host, via one connection. If the host becomes unreachable for a short time, that is not a problem as long as the connectivty is restored at the end. Ansible also supports to switch the host IP (or SSH port). With this new way, the ansible play can apply a bunch of profiles autonomously and the ansible play can potentially handle a changing IP configuration.
This commit is contained in:
parent
407e3b81af
commit
edcb4a2850
4 changed files with 1267 additions and 715 deletions
|
|
@ -9,6 +9,7 @@
|
|||
type: ethernet
|
||||
- name: p-3-auto
|
||||
|
||||
- wait: 10
|
||||
|
||||
- name: p-3-manual
|
||||
autoconnect: no
|
||||
|
|
@ -22,6 +23,7 @@
|
|||
- "192.168.122.{{ network_iphost }}/24"
|
||||
- name: p-3-manual
|
||||
|
||||
- wait: 10
|
||||
|
||||
- name: p-3-br0
|
||||
autoconnect: no
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
250
library/test_network_connections.py
Executable file
250
library/test_network_connections.py
Executable file
|
|
@ -0,0 +1,250 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
import sys
|
||||
import os
|
||||
import unittest
|
||||
|
||||
sys.path.insert(1, os.path.dirname(os.path.abspath(__file__)))
|
||||
|
||||
import network_connections as n
|
||||
|
||||
class TestValidator(unittest.TestCase):
|
||||
|
||||
def test_validate_str(self):
|
||||
|
||||
v = n.ArgValidatorStr('state')
|
||||
self.assertEqual('a', v.validate('a'))
|
||||
with self.assertRaises(n.ValidationError):
|
||||
v.validate(1)
|
||||
with self.assertRaises(n.ValidationError):
|
||||
v.validate(None)
|
||||
|
||||
v = n.ArgValidatorStr('state', required = True)
|
||||
with self.assertRaises(n.ValidationError):
|
||||
v.validate(None)
|
||||
|
||||
def test_validate_int(self):
|
||||
|
||||
v = n.ArgValidatorInt('state', default_value = None)
|
||||
self.assertEqual(1, v.validate(1))
|
||||
self.assertEqual(1, v.validate("1"))
|
||||
with self.assertRaises(n.ValidationError):
|
||||
v.validate(None)
|
||||
with self.assertRaises(n.ValidationError):
|
||||
v.validate("1a")
|
||||
|
||||
v = n.ArgValidatorInt('state', required = True)
|
||||
with self.assertRaises(n.ValidationError):
|
||||
v.validate(None)
|
||||
|
||||
def test_validate_bool(self):
|
||||
|
||||
v = n.ArgValidatorBool('state')
|
||||
self.assertEqual(True, v.validate(True))
|
||||
self.assertEqual(True, v.validate("True"))
|
||||
self.assertEqual(True, v.validate(1))
|
||||
self.assertEqual(False, v.validate(False))
|
||||
self.assertEqual(False, v.validate("False"))
|
||||
self.assertEqual(False, v.validate(0))
|
||||
with self.assertRaises(n.ValidationError):
|
||||
v.validate(2)
|
||||
|
||||
with self.assertRaises(n.ValidationError):
|
||||
v.validate(None)
|
||||
v = n.ArgValidatorBool('state', required = True)
|
||||
with self.assertRaises(n.ValidationError):
|
||||
v.validate(None)
|
||||
|
||||
def test_validate_dict(self):
|
||||
|
||||
v = n.ArgValidatorDict(
|
||||
'dict',
|
||||
nested = [
|
||||
n.ArgValidatorInt('i', required = True),
|
||||
n.ArgValidatorStr('s', required = False, default_value = 's_default'),
|
||||
n.ArgValidatorStr('l', required = False, default_value = n.ArgValidator.MISSING),
|
||||
])
|
||||
|
||||
self.assertEqual(
|
||||
{
|
||||
'i': 5,
|
||||
's': 's_default',
|
||||
},
|
||||
v.validate({
|
||||
'i': '5',
|
||||
})
|
||||
)
|
||||
self.assertEqual(
|
||||
{
|
||||
'i': 5,
|
||||
's': 's_default',
|
||||
'l': '6',
|
||||
},
|
||||
v.validate({
|
||||
'i': '5',
|
||||
'l': '6',
|
||||
})
|
||||
)
|
||||
with self.assertRaises(n.ValidationError):
|
||||
v.validate({ 'k': 1 })
|
||||
|
||||
def test_validate_list(self):
|
||||
|
||||
v = n.ArgValidatorList(
|
||||
'list',
|
||||
nested = n.ArgValidatorInt('i')
|
||||
)
|
||||
self.assertEqual(
|
||||
[ 1, 5 ],
|
||||
v.validate([ '1', 5 ])
|
||||
)
|
||||
with self.assertRaises(n.ValidationError):
|
||||
v.validate([1, 's'])
|
||||
|
||||
def test_1(self):
|
||||
|
||||
self.assertEqual(
|
||||
[],
|
||||
n.AnsibleUtil.ARGS_CONNECTIONS.validate([]),
|
||||
)
|
||||
|
||||
self.assertEqual(
|
||||
[
|
||||
{
|
||||
'name': '5',
|
||||
'state': 'present',
|
||||
'type': 'ethernet',
|
||||
'autoconnect': True,
|
||||
'parent': None,
|
||||
'ip': {
|
||||
'gateway6': None,
|
||||
'gateway4': None,
|
||||
'route_metric4': None,
|
||||
'auto6': True,
|
||||
'dhcp4': True,
|
||||
'address': [],
|
||||
'route_metric6': None,
|
||||
'ip_is_present': False,
|
||||
'dhcp4_send_hostname': None,
|
||||
},
|
||||
'mac': None,
|
||||
'master': None,
|
||||
'vlan_id': None,
|
||||
'on_error':
|
||||
'fail',
|
||||
'interface_name': None,
|
||||
'slave_type': None,
|
||||
},
|
||||
{
|
||||
'name': '5',
|
||||
'state': 'up',
|
||||
'wait': 90,
|
||||
'on_error': 'fail',
|
||||
}
|
||||
],
|
||||
n.AnsibleUtil.ARGS_CONNECTIONS.validate([
|
||||
{ 'name': '5',
|
||||
'type': 'ethernet',
|
||||
},
|
||||
{ 'name': '5' }
|
||||
]),
|
||||
)
|
||||
self.assertEqual(
|
||||
[
|
||||
{
|
||||
'name': '5',
|
||||
'state': 'up',
|
||||
'type': 'ethernet',
|
||||
'autoconnect': True,
|
||||
'parent': None,
|
||||
'ip': {
|
||||
'gateway6': None,
|
||||
'gateway4': None,
|
||||
'route_metric4': None,
|
||||
'auto6': True,
|
||||
'dhcp4': True,
|
||||
'address': [],
|
||||
'route_metric6': None,
|
||||
'ip_is_present': False,
|
||||
'dhcp4_send_hostname': None,
|
||||
},
|
||||
'mac': None,
|
||||
'master': None,
|
||||
'vlan_id': None,
|
||||
'on_error':
|
||||
'fail',
|
||||
'interface_name': None,
|
||||
'slave_type': None,
|
||||
'wait': 90,
|
||||
},
|
||||
],
|
||||
n.AnsibleUtil.ARGS_CONNECTIONS.validate([
|
||||
{ 'name': '5',
|
||||
'state': 'up',
|
||||
'type': 'ethernet',
|
||||
},
|
||||
]),
|
||||
)
|
||||
|
||||
with self.assertRaises(n.ValidationError):
|
||||
n.AnsibleUtil.ARGS_CONNECTIONS.validate([ { 'name': 'a', 'autoconnect': True }])
|
||||
|
||||
self.assertEqual(
|
||||
[
|
||||
{
|
||||
'name': '5',
|
||||
'state': 'absent',
|
||||
'on_error': 'fail',
|
||||
}
|
||||
],
|
||||
n.AnsibleUtil.ARGS_CONNECTIONS.validate([
|
||||
{
|
||||
'name': '5',
|
||||
'state': 'absent',
|
||||
}
|
||||
]),
|
||||
)
|
||||
|
||||
with self.assertRaises(n.ValidationError):
|
||||
n.AnsibleUtil.ARGS_CONNECTIONS.validate([ { } ])
|
||||
with self.assertRaises(n.ValidationError):
|
||||
n.AnsibleUtil.ARGS_CONNECTIONS.validate([ { 'name': 'b', 'xxx': 5 } ])
|
||||
|
||||
self.assertEqual(
|
||||
[
|
||||
{
|
||||
'autoconnect': True,
|
||||
'interface_name': None,
|
||||
'ip': {
|
||||
'address': [],
|
||||
'auto6': True,
|
||||
'dhcp4': True,
|
||||
'dhcp4_send_hostname': None,
|
||||
'gateway4': None,
|
||||
'gateway6': None,
|
||||
'ip_is_present': False,
|
||||
'route_metric4': None,
|
||||
'route_metric6': None,
|
||||
},
|
||||
'mac': None,
|
||||
'master': None,
|
||||
'name': '5',
|
||||
'parent': None,
|
||||
'on_error': 'fail',
|
||||
'slave_type': None,
|
||||
'state': 'present',
|
||||
'type': 'ethernet',
|
||||
'vlan_id': None,
|
||||
},
|
||||
],
|
||||
n.AnsibleUtil.ARGS_CONNECTIONS.validate([
|
||||
{
|
||||
'name': '5',
|
||||
'type': 'ethernet',
|
||||
}
|
||||
]),
|
||||
)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
|
@ -15,19 +15,7 @@
|
|||
- name: Configure networking connection profiles
|
||||
network_connections:
|
||||
provider: "{{ network.provider | default(network_provider) | mandatory }}"
|
||||
name: "{{ item.name | mandatory }}"
|
||||
state: "{{ item.state | default(omit) }}"
|
||||
wait: "{{ item.wait | default(omit) }}"
|
||||
type: "{{ item.type | default(omit) }}"
|
||||
autoconnect: "{{ item.autoconnect | default(omit) }}"
|
||||
slave_type: "{{ item.slave_type | default(omit) }}"
|
||||
master: "{{ item.master | default(omit) }}"
|
||||
interface_name: "{{ item.interface_name | default(omit) }}"
|
||||
mac: "{{ item.mac | default(omit) }}"
|
||||
parent: "{{ item.parent | default(omit) }}"
|
||||
vlan_id: "{{ item.vlan_id | default(omit) }}"
|
||||
ip: "{{ item.ip | default(omit) }}"
|
||||
with_items: "{{ network.connections | default([]) }}"
|
||||
connections: "{{ network.connections | default([]) }}"
|
||||
|
||||
- name: Re-test connectivity
|
||||
ping:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue