Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Migrate win route #734

Merged
merged 12 commits into from
Jan 19, 2025
65 changes: 65 additions & 0 deletions plugins/modules/win_route.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
#!powershell

# Copyright: (c) 2025, Red Hat, Inc.
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)


#AnsibleRequires -CSharpUtil Ansible.Basic
$spec = @{
options = @{
destination = @{ type = 'str' ; required = $true }
gateway = @{ type = 'str' ; default = "0.0.0.0" }
state = @{ type = 'str' ; default = "present" ; choices = @( "present", "absent") }
metric = @{ type = 'int' ; default = 1 }
}
supports_check_mode = $true
}

$module = [Ansible.Basic.AnsibleModule]::Create($args, $spec)
$Destination = $module.Params.destination
$Gateway = $module.Params.gateway
$State = $module.Params.state
$Metric = $module.metric
$check_mode = $module.Checkmode

$IpAddress = $Destination.split('/')[0]
$Route = Get-CimInstance win32_ip4PersistedrouteTable -Filter "Destination = '$($IpAddress)'"

if ($State -eq "present") {
if (!($Route)) {
try {
# Find Interface Index
$InterfaceIndex = Find-NetRoute -RemoteIPAddress $Gateway | Select-Object -First 1 -ExpandProperty InterfaceIndex

# Add network route
$routeParams = @{
DestinationPrefix = $Destination
NextHop = $Gateway
InterfaceIndex = $InterfaceIndex
RouteMetric = $Metric
ErrorAction = "Stop"
WhatIf = $check_mode
}
New-NetRoute @routeParams | Out-Null
$module.result.changed = $true
$module.result.msg = "Route added"

}
catch { $module.FailJson("Failed to create a new route", $_) }
amitosw15 marked this conversation as resolved.
Show resolved Hide resolved
}
else { $module.result.msg = "Static route already exists" }
}
else {
if ($Route) {
try {

Remove-NetRoute -DestinationPrefix $Destination -Confirm:$false -ErrorAction Stop -WhatIf:$check_mode
$module.result.changed = $true
$module.result.msg = "Route removed"
}
catch { $module.FailJson("Failed to remove the requested route", $_) }
amitosw15 marked this conversation as resolved.
Show resolved Hide resolved
}
else { $module.result.msg = "No route to remove" }
}

$module.ExitJson()
63 changes: 63 additions & 0 deletions plugins/modules/win_route.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-

# Copyright: (c) 2025, Red Hat, Inc.
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)

DOCUMENTATION = r'''
---
module: win_route
short_description: Add or remove a static route
description:
amitosw15 marked this conversation as resolved.
Show resolved Hide resolved
- Add or remove a static route.
options:
destination:
description:
- Destination IP address in CIDR format (ip address/prefix length).
type: str
required: yes
gateway:
description:
- The gateway used by the static route.
- If C(gateway) is not provided it will be set to C(0.0.0.0).
type: str
default: 0.0.0.0
metric:
description:
- Metric used by the static route.
type: int
default: 1
state:
description:
- If C(absent), it removes a network static route.
- If C(present), it adds a network static route.
type: str
choices: [ absent, present ]
default: present
notes:
- Works only with Windows 2012 R2 and newer.
author:
- Amit Weinstock (@amitosw15)
'''

EXAMPLES = r'''
---
- name: Add a network static route
ansible.windows.win_route:
destination: 192.168.2.10/32
gateway: 192.168.1.1
metric: 1
state: present

- name: Remove a network static route
ansible.windows.win_route:
destination: 192.168.2.10/32
state: absent
'''
RETURN = r'''
msg:
description: A message describing the task result.
returned: always
type: str
sample: "Route added"
'''
1 change: 1 addition & 0 deletions tests/integration/targets/win_route/aliases
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
shippable/windows/group5
3 changes: 3 additions & 0 deletions tests/integration/targets/win_route/defaults/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
---
default_gateway: 192.168.1.1
destination_ip_address: 192.168.2.10
34 changes: 34 additions & 0 deletions tests/integration/targets/win_route/tasks/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
---
# test code for the win_psmodule module when using winrm connection
# (c) 2017, Daniele Lazzari <[email protected]>

# This file is part of Ansible
#
# Ansible is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Ansible is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.

- block:
- name: get os info
ansible.windows.win_shell: '[Environment]::OSVersion.Version -ge [Version]"6.3"'
register: os

- name: run all tasks
include_tasks: tests.yml
when: os.stdout_lines[0] == "True"
amitosw15 marked this conversation as resolved.
Show resolved Hide resolved

always:
- name: remove test routes
win_route:
destination: "{{ destination_ip_address }}/32"
state: absent
register: route_removed
105 changes: 105 additions & 0 deletions tests/integration/targets/win_route/tasks/tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
---
- name: add a static route check mode
win_route:
destination: "{{ destination_ip_address }}/32"
gateway: "{{ default_gateway }}"
metric: 1
state: present
register: route_checkmode
check_mode: yes

- name: test if route successfully added check mode
assert:
that:
- route_checkmode is changed

- name: add a static route
win_route:
destination: "{{ destination_ip_address }}/32"
gateway: "{{ default_gateway }}"
metric: 1
state: present
register: route

- name: check if route successfully added
ansible.windows.win_shell: (Get-CimInstance win32_ip4PersistedrouteTable -Filter "Destination = '{{ destination_ip_address }}'").Caption
register: route_added

- name: check route default gateway
ansible.windows.win_shell: (Get-CimInstance win32_ip4PersistedrouteTable -Filter "Destination = '{{ destination_ip_address }}'").NextHop
register: route_gateway

- name: test if route successfully added
assert:
that:
- route is changed
- route_added.stdout_lines[0] == "{{ destination_ip_address }}"
- route_gateway.stdout_lines[0] == "{{ default_gateway }}"

- name: add a static route to test idempotency
win_route:
destination: "{{ destination_ip_address }}/32"
gateway: "{{ default_gateway }}"
metric: 1
state: present
register: idempotent_route

- name: test idempotency
assert:
that:
- idempotent_route is not changed
- idempotent_route.msg == "Static route already exists"

- name: remove route check mode
win_route:
destination: "{{ destination_ip_address }}/32"
state: absent
register: route_removed_checkmode
check_mode: yes

- name: test route is removed
assert:
that:
- route_removed_checkmode is changed

- name: remove route
win_route:
destination: "{{ destination_ip_address }}/32"
state: absent
register: route_removed

- name: check route is removed
ansible.windows.win_shell: Get-CimInstance win32_ip4PersistedrouteTable -Filter "Destination = '{{ destination_ip_address }}'"
register: check_route_removed

- name: test route is removed
assert:
that:
- route_removed is changed
- check_route_removed.stdout == ''

- name: remove static route to test idempotency
win_route:
destination: "{{ destination_ip_address }}/32"
state: absent
register: idempotent_route_removed

- name: test idempotency
assert:
that:
- idempotent_route_removed is not changed
- idempotent_route_removed.msg == "No route to remove"

- name: add route to wrong ip address
win_route:
destination: "715.18.0.0/32"
gateway: "{{ default_gateway }}"
metric: 1
state: present
ignore_errors: yes
register: wrong_ip

- name: test route to wrong ip address
assert:
that:
- wrong_ip is failed
Loading