Skip to content

Commit

Permalink
Added Static Route module
Browse files Browse the repository at this point in the history
  • Loading branch information
Arkadiy Shinkarev committed Dec 1, 2022
1 parent 6a42832 commit 19f72d4
Show file tree
Hide file tree
Showing 5 changed files with 648 additions and 0 deletions.
121 changes: 121 additions & 0 deletions plugins/module_utils/static_route.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
# -*- coding: utf-8 -*-
# Copyright: (c) 2022, Arkadiy Shinkarev | Tinkoff <[email protected]>
#
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)


from __future__ import absolute_import, division, print_function

__metaclass__ = type

from .utils import (
get_query,
MaasValueMapper,
)
from . import errors
from .rest_client import RestClient
from .client import Client


MAAS_RESOURCE = "/api/2.0/static-routes"


class StaticRoute(MaasValueMapper):
def __init__(
self,
source=None,
destination=None,
gateway_ip=None,
metric=None,
id=None,
resource_uri=None,
):
self.source = source
self.destination = destination
self.gateway_ip = gateway_ip
self.metric = metric
self.id = id
self.resource_uri = resource_uri

@classmethod
def get_by_spec(cls, module, client: Client, must_exist=False):
rest_client = RestClient(client=client)
fields = {"source", "destination"}
ansible_maas_map_dict = {k: k for k in fields}
query = get_query(
module,
*fields,
ansible_maas_map=ansible_maas_map_dict,
)
maas_dict = rest_client.get_record(
f"{MAAS_RESOURCE}/", query, must_exist=must_exist
)
if maas_dict:
static_route = cls.from_maas(maas_dict)
return static_route

@classmethod
def from_ansible(cls, module):
return

@classmethod
def from_maas(cls, maas_dict):
obj = cls()
try:
obj.source = maas_dict["source"]
obj.destination = maas_dict["destination"]
obj.gateway_ip = maas_dict["gateway_ip"]
obj.metric = maas_dict["metric"]
obj.id = maas_dict["id"]
obj.resource_uri = maas_dict["resource_uri"]
except KeyError as e:
raise errors.MissingValueMAAS(e)
return obj

def to_maas(self):
return

def to_ansible(self):
return dict(
source=self.source,
destination=self.destination,
gateway_ip=self.gateway_ip,
metric=self.metric,
id=self.id,
resource_uri=self.resource_uri,
)

def delete(self, module, client):
rest_client = RestClient(client=client)
rest_client.delete_record(f"{MAAS_RESOURCE}/{self.id}/", module.check_mode)

def update(self, module, client, payload):
rest_client = RestClient(client=client)
return rest_client.put_record(
f"{MAAS_RESOURCE}/{self.id}/",
payload=payload,
check_mode=module.check_mode,
).json

@classmethod
def create(cls, client, payload):
static_route_maas_dict = client.post(
f"{MAAS_RESOURCE}/",
data=payload,
timeout=60, # Sometimes we get timeout error thus changing timeout from 20s to 60s
).json
static_route = cls.from_maas(static_route_maas_dict)
return static_route

def __eq__(self, other):
"""One DHCP Snippet is equal to another if it has all attributes exactly the same"""
return all(
(
self.source == other.source,
self.destination == other.destination,
self.gateway_ip == other.gateway_ip,
self.metric == other.metric,
self.id == other.id,
self.resource_uri == other.resource_uri,
)
)
210 changes: 210 additions & 0 deletions plugins/modules/static_route.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,210 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Copyright: (c) 2022, Arkadiy Shinkarev | Tinkoff <[email protected]>
#
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)

from __future__ import absolute_import, division, print_function

__metaclass__ = type

DOCUMENTATION = r"""
module: static_route
author:
- Arkadiy Shinkarev (@k3nny0ne)
short_description: Creates, updates or deletes Static Routes.
description:
- If I(state) is C(present) and all required options is provided but not found,
new Static Route with specified configuration is created.
- If I(state) is C(present) and static route is found based on specified options, updates an existing Static Route.
- If I(state) is C(absent) Static Route selected by I(name) is deleted.
version_added: 1.0.0
extends_documentation_fragment:
- canonical.maas.cluster_instance
seealso: []
options:
state:
description:
- Desired state of the Static Route.
choices: [ present, absent ]
type: str
required: True
source:
description:
- Source subnet name for the route.
type: str
required: True
destination:
description:
- Destination subnet name for the route.
type: str
required: True
gateway_ip:
description:
- IP address of the gateway on the source subnet.
type: str
required: True
metric:
description:
- Weight of the route on a deployed machine.
type: int
required: False
"""

EXAMPLES = r"""
- name: Create Static Route
canonical.maas.static_route:
state: present
source: "subnet-1"
destination: "subnet-2"
gateway_ip: "192.168.1.1"
metric: 100
- name: Update Static Route
canonical.maas.static_route:
state: present
source: "subnet-1"
destination: "subnet-2"
gateway_ip: "192.168.1.1"
metric: 0
- name: Remove Static Route using specification
canonical.maas.static_route:
state: absent
source: "subnet-1"
destination: "subnet-2"
gateway_ip: "192.168.1.1"
metric: 0
"""

RETURN = r"""
record:
description:
- Created or updated Static Route.
returned: success
type: dict
sample:
source: "subnet-1"
destination: "subnet-2"
gateway_ip: "192.168.1.1"
metric: 0
id: 4
resource_uri: /MAAS/api/2.0/static-routes/4/
"""


from ansible.module_utils.basic import AnsibleModule

from ..module_utils import arguments, errors
from ..module_utils.client import Client
from ..module_utils.static_route import StaticRoute
from ..module_utils.cluster_instance import get_oauth1_client


def data_for_create_static_route(module):
data = {}
data["source"] = module.params["source"] # required
data["destination"] = module.params["destination"] # required
data["gateway_ip"] = module.params["gateway_ip"] # required

if "metric" in module.params and module.params["metric"]:
data["metric"] = module.params["metric"]
return data


def create_static_route(module, client: Client):
data = data_for_create_static_route(module)
static_route = StaticRoute.create(client, data)
return (
True,
static_route.to_ansible(),
dict(before={}, after=static_route.to_ansible()),
)


def data_for_update_static_route(module, static_route):
data = {}

if module.params["metric"]:
if static_route.metric != module.params["metric"]:
data["metric"] = module.params["metric"]
if module.params["gateway_ip"]:
if static_route.gateway_ip != module.params["gateway_ip"]:
data["gateway_ip"] = module.params["gateway_ip"]

if (
static_route.source
and isinstance(static_route.source, dict)
and static_route.source["name"] != module.params["source"]
):
data["source"] = module.params["source"]

if (
static_route.destination
and isinstance(static_route.destination, dict)
and static_route.destination["name"] != module.params["destination"]
):
data["destination"] = module.params["destination"]

return data


def update_static_route(module, client: Client, static_route: StaticRoute):
data = data_for_update_static_route(module, static_route)
if data:
updated = static_route.update(module, client, data)
after = StaticRoute.from_maas(updated)
return (
True,
after.to_ansible(),
dict(before=static_route.to_ansible(), after=after.to_ansible()),
)
return (
False,
static_route.to_ansible(),
dict(before=static_route.to_ansible(), after=static_route.to_ansible()),
)


def delete_static_route(module, client: Client):
static_route = StaticRoute.get_by_spec(module, client, must_exist=False)
if static_route:
static_route.delete(module, client)
return True, dict(), dict(before=static_route.to_ansible(), after={})
return False, dict(), dict(before={}, after={})


def run(module, client: Client):
if module.params["state"] == "present":
static_route = StaticRoute.get_by_spec(module, client, must_exist=False)
if static_route:
return update_static_route(module, client, static_route)
return create_static_route(module, client)
if module.params["state"] == "absent":
return delete_static_route(module, client)


def main():
module = AnsibleModule(
supports_check_mode=True,
argument_spec=dict(
arguments.get_spec("cluster_instance"),
state=dict(type="str", choices=["present", "absent"], required=True),
source=dict(type="str", required=True),
destination=dict(type="str", required=True),
gateway_ip=dict(type="str", required=True),
metric=dict(type="int"),
),
)

try:
client = get_oauth1_client(module.params)
changed, record, diff = run(module, client)
module.exit_json(changed=changed, record=record, diff=diff)
except errors.MaasError as e:
module.fail_json(msg=str(e))


if __name__ == "__main__":
main()
Loading

0 comments on commit 19f72d4

Please sign in to comment.