-
Notifications
You must be signed in to change notification settings - Fork 15
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Arkadiy Shinkarev
committed
Dec 1, 2022
1 parent
6a42832
commit 19f72d4
Showing
5 changed files
with
648 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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, | ||
) | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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() |
Oops, something went wrong.