Skip to content

Commit ae5031c

Browse files
committed
1.2.4 (2023-05-02)
------------------ * [fix] Fortigate._valid_url()
1 parent b19f7bd commit ae5031c

File tree

9 files changed

+140
-42
lines changed

9 files changed

+140
-42
lines changed

CHANGELOG.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,11 @@
44
CHANGELOG
55
=========
66

7+
1.2.4 (2023-05-02)
8+
------------------
9+
* [fix] Fortigate._valid_url()
10+
11+
712
1.2.3 (2023-04-27)
813
------------------
914
* [feat] poetry

README.rst

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ or install the package from github.com release
4949

5050
.. code:: bash
5151
52-
pip install https://github.com/vladimirs-git/fortigate-api/archive/refs/tags/1.2.3.tar.gz
52+
pip install https://github.com/vladimirs-git/fortigate-api/archive/refs/tags/1.2.4.tar.gz
5353
5454
or install the package from github.com repository
5555

@@ -866,6 +866,8 @@ Python examples `./examples/fortigate.py`_
866866

867867
Python examples `./examples/fortigate_token.py`_
868868

869+
Python examples `./examples/monitor.py`_
870+
869871
.. code:: python
870872

871873
from fortigate_api import Fortigate
@@ -1084,14 +1086,15 @@ Return
10841086
.. _`./examples/yml/zone.yml`: ./examples/yml/zone.yml
10851087

10861088
.. _`./examples/address.py`: ./examples/address.py
1087-
.. _`./examples/address_token.py`: ./examples/address_token.py
10881089
.. _`./examples/address_group.py`: ./examples/address_group.py
1090+
.. _`./examples/address_token.py`: ./examples/address_token.py
10891091
.. _`./examples/dhcp_server.py`: ./examples/dhcp_server.py
10901092
.. _`./examples/external_resource.py`: ./examples/external_resource.py
10911093
.. _`./examples/fortigate.py`: ./examples/fortigate.py
10921094
.. _`./examples/fortigate_token.py`: ./examples/fortigate_token.py
10931095
.. _`./examples/interface.py`: ./examples/interface.py
10941096
.. _`./examples/ip_pool.py`: ./examples/ip_pool.py
1097+
.. _`./examples/monitor.py`: ./examples/monitor.py
10951098
.. _`./examples/policy.py`: ./examples/policy.py
10961099
.. _`./examples/policy_extended_filter.py`: ./examples/policy_extended_filter.py
10971100
.. _`./examples/snmp_community.py`: ./examples/snmp_community.py

examples/address.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,12 @@
2929
fgt.login()
3030

3131
# Create Address
32-
data = {"name": "ADDRESS",
33-
"obj-type": "ip",
34-
"subnet": "127.0.0.100 255.255.255.252",
35-
"type": "ipmask"}
32+
data = {
33+
"name": "ADDRESS",
34+
"obj-type": "ip",
35+
"subnet": "127.0.0.100 255.255.255.252",
36+
"type": "ipmask",
37+
}
3638
response = fgt.address.create(data=data)
3739
print("address.create", response) # address.create <Response [200]>
3840

examples/interface.py

Lines changed: 24 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@
88
- Filter interface by multiple conditions
99
- Update interface data in the Fortigate
1010
- Check for presence of interface in the Fortigate
11-
- Get all interfaces in vdom "VDOM"
11+
- Change virtual domain to VDOM and get all interfaces of this virtual domain
12+
- Change virtual domain to root and get all interfaces of this virtual domain
13+
- Get all interfaces in all virtual domains (root and VDOM)
1214
"""
1315

1416
import logging
@@ -25,53 +27,61 @@
2527
fgt = FortigateAPI(host=HOST, username=USERNAME, password=PASSWORD)
2628
fgt.login()
2729

28-
print("\nGets all interfaces in vdom \"root\" from the Fortigate")
30+
print("\nGet all interfaces in vdom \"root\" from the Fortigate")
2931
interfaces = fgt.interface.get()
3032
print(f"interfaces count={len(interfaces)}") # interfaces count=21
3133

32-
print("\nGets filtered interface by name (unique identifier)")
34+
print("\nGet filtered interface by name (unique identifier)")
3335
interfaces = fgt.interface.get(uid="dmz")
3436
pprint(interfaces)
3537
# [{"name": "dmz",
3638
# "ip": "0.0.0.0 0.0.0.0",
3739
# ...
3840
# }]
3941

40-
print("\nFilters interface by operator equals \"==\"")
42+
print("\nFilter interface by operator equals \"==\"")
4143
interfaces = fgt.interface.get(filter="name==dmz")
4244
print(f"interfaces count={len(interfaces)}") # interfaces count=1
4345

44-
print("\nFilters interface by operator contains \"=@\"")
46+
print("\nFilter interface by operator contains \"=@\"")
4547
interfaces = fgt.interface.get(filter="name=@wan")
4648
print(f"interfaces count={len(interfaces)}") # interfaces count=2
4749

48-
print("\nFilters interface by operator not equals \"!=\"")
50+
print("\nFilter interface by operator not equals \"!=\"")
4951
interfaces = fgt.interface.get(filter="name!=dmz")
5052
print(f"interfaces count={len(interfaces)}") # interfaces count=20
5153

52-
print("\nFilters interface by multiple conditions")
54+
print("\nFilter interface by multiple conditions")
5355
interfaces = fgt.interface.get(filter=["allowaccess=@ping", "detectprotocol==ping"])
5456
print(f"interfaces count={len(interfaces)}") # interfaces count=8
5557

56-
print("\nUpdates interface data in the Fortigate")
58+
print("\nUpdate interface data in the Fortigate")
5759
data = dict(name="dmz", description="dmz")
5860
response = fgt.interface.update(uid="dmz", data=data)
5961
print("interface.update", response) # interface.update <Response [200]>
6062

61-
print("\nChecks for presence of interface in the Fortigate")
63+
print("\nCheck for presence of interface in the Fortigate")
6264
response = fgt.interface.is_exist(uid="dmz")
6365
print("interface.is_exist", response) # interface.is_exist True
6466

65-
print("\nChanges virtual domain to \"VDOM\" and gets all interfaces inside this vdom")
67+
# Interfaces in virtual domains
68+
69+
print("\nChange virtual domain to VDOM and get all interfaces of this virtual domain")
6670
fgt.rest.vdom = "VDOM"
67-
print(f"{fgt!r}") # Fortigate(host='host', username='username', password='********', vdom='VDOM')
71+
print(f"{fgt!r}") # Fortigate(host='host', username='username', vdom='VDOM')
6872
print(fgt.vdom) # VDOM
6973
interfaces = fgt.interface.get()
70-
print(f"interfaces count={len(interfaces)}") # interfaces count=0
74+
print(f"interfaces count={len(interfaces)}") # interfaces count=12
7175

72-
print("\nChanges virtual domain to \"root\"")
76+
print("\nChange virtual domain to root and get all interfaces of this virtual domain")
7377
fgt.vdom = "root"
74-
print(f"{fgt!r}") # Fortigate(host='host', username='username', password='********')
78+
print(f"{fgt!r}") # Fortigate(host='host', username='username')
7579
print(fgt.vdom) # root
80+
interfaces = fgt.interface.get()
81+
print(f"interfaces count={len(interfaces)}") # interfaces count=31
82+
83+
print("\nGet all interfaces in all virtual domains (root and VDOM)")
84+
interfaces = fgt.interface.get(all=True)
85+
print(f"interfaces count={len(interfaces)}") # interfaces count=43
7686

7787
fgt.logout()

examples/monitor.py

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
"""Monitor examples.
2+
3+
- Get directory of monitor options (schema)
4+
- Get all ipv4 routes
5+
- Get static ipv4 routes
6+
- Get route to interested ip address
7+
"""
8+
import logging
9+
from pprint import pprint
10+
11+
from fortigate_api import Fortigate
12+
13+
logging.getLogger().setLevel(logging.DEBUG)
14+
15+
HOST = "host"
16+
USERNAME = "username"
17+
PASSWORD = "password"
18+
19+
fgt = Fortigate(host=HOST, username=USERNAME, password=PASSWORD)
20+
21+
# Get directory of monitor options (schema)
22+
directory = fgt.directory("api/v2/monitor")
23+
pprint(directory)
24+
# [{"access_group": "sysgrp.cfg",
25+
# "action": "select",
26+
# "name": "health",
27+
# "path": "firewall",
28+
# "request": {"http_method": "GET"},
29+
# "response": {"type": "array"},
30+
# "summary": "List configured load balance server health monitors.",
31+
# "supported": True},
32+
# ...
33+
34+
# Get all ipv4 routes
35+
routes = fgt.get(url="api/v2/monitor/router/ipv4")
36+
pprint(routes)
37+
# [{"distance": 20,
38+
# "gateway": "10.0.0.1",
39+
# "install_date": 1681965487,
40+
# "interface": "tunnel1",
41+
# "ip_mask": "10.0.0.0/8",
42+
# "ip_version": 4,
43+
# "is_tunnel_route": True,
44+
# "metric": 100,
45+
# "priority": 1,
46+
# "tunnel_parent": "tunnel1",
47+
# "type": "bgp",
48+
# "vrf": 0},
49+
# ...
50+
# ]
51+
52+
# Get static ipv4 routes
53+
routes = fgt.get(url="api/v2/monitor/router/ipv4?type=static")
54+
pprint(routes)
55+
# [{"distance": 10,
56+
# "gateway": "10.0.1.1",
57+
# "interface": "wan1",
58+
# "ip_mask": "0.0.0.0/0",
59+
# "ip_version": 4,
60+
# "metric": 0,
61+
# "priority": 1,
62+
# "type": "static",
63+
# "vrf": 0},
64+
# ...
65+
# ]
66+
67+
# Get route to interested ip address
68+
routes = fgt.get(url="api/v2/monitor/router/lookup?destination=10.1.1.1")
69+
pprint(routes)
70+
# {"gateway": "10.0.0.1",
71+
# "interface": "tunnel1",
72+
# "network": "10.0.0.0/10",
73+
# "success": True}

fortigate_api/fortigate.py

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
import logging
1111
import re
1212
from typing import Callable, Iterable, Optional
13-
from urllib.parse import urlencode
13+
from urllib.parse import urlencode, urljoin
1414

1515
import requests
1616
from requests import Session, Response
@@ -423,8 +423,11 @@ def _response(self, method: Method, url: str, data: ODAny = None) -> Response:
423423
return response
424424

425425
def _valid_url(self, url: str) -> str:
426-
"""Add "https://" to `url` if absent."""
426+
"""Return a valid URL string.
427+
428+
Add "https://" to `url` if it is absent and remove any trailing "/" character.
429+
"""
427430
if re.match("http(s)?://", url):
428-
return url
429-
url = url.strip("/")
430-
return f"{self.url}/{url}/"
431+
return url.rstrip("/")
432+
path = url.strip("/")
433+
return urljoin(self.url, path)

pyproject.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[tool.poetry]
22
name = "fortigate_api"
3-
version = "1.2.3"
3+
version = "1.2.4"
44
description = "Python package to configure Fortigate (Fortios) devices using REST API and SSH"
55
authors = ["Vladimir Prusakov <[email protected]>"]
66
license = "MIT"
@@ -44,4 +44,4 @@ test = ["pytest"]
4444

4545
[tool.poetry.urls]
4646
"Bug Tracker" = "https://github.com/vladimirs-git/fortigate-api/issues"
47-
"Download URL" = "https://github.com/vladimirs-git/fortigate-api/archive/refs/tags/1.2.3.tar.gz"
47+
"Download URL" = "https://github.com/vladimirs-git/fortigate-api/archive/refs/tags/1.2.4.tar.gz"

tests/helper__tst.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -111,13 +111,13 @@ class MockResponse(Response):
111111
f"api/v2/cmdb/antivirus/profile/{NAME1}": [D_NAME1],
112112
f"api/v2/cmdb/application/list/{NAME1}": [D_NAME1],
113113

114-
"api/v2/cmdb/firewall/address/": [D_ADDR1, D_ADDR2, D_ADDR3, D_ADDR4, D_ADDR5],
114+
"api/v2/cmdb/firewall/address": [D_ADDR1, D_ADDR2, D_ADDR3, D_ADDR4, D_ADDR5],
115115
f"api/v2/cmdb/firewall/address/?filter=name{EQ}{ADDR1}": [D_ADDR1],
116116
f"api/v2/cmdb/firewall/address/{ADDR1}": [D_ADDR1],
117117
f"api/v2/cmdb/firewall/address/{ADDR1}?filter=name{EQ}{ADDR1}": [D_ADDR1],
118118
f"api/v2/cmdb/firewall/address/{SLASH_}": [D_SLASH],
119119

120-
"api/v2/cmdb/firewall/addrgrp/": [D_ADDGR1],
120+
"api/v2/cmdb/firewall/addrgrp": [D_ADDGR1],
121121
f"api/v2/cmdb/firewall/addrgrp/?filter=name{EQ}{ADDGR1}": [D_ADDGR1],
122122
f"api/v2/cmdb/firewall/addrgrp/{ADDGR1}": [D_ADDGR1],
123123
f"api/v2/cmdb/firewall/addrgrp/{ADDGR1}?filter=name{EQ}{ADDGR1}": [D_ADDGR1],
@@ -126,7 +126,7 @@ class MockResponse(Response):
126126
f"api/v2/cmdb/firewall/ippool/{NAME1}": [D_NAME1],
127127
f"api/v2/cmdb/firewall/vip/{NAME1}": [D_NAME1],
128128

129-
"api/v2/cmdb/firewall/policy/": [D_POL1, D_POL3],
129+
"api/v2/cmdb/firewall/policy": [D_POL1, D_POL3],
130130
"api/v2/cmdb/firewall/policy/1": [D_POL1],
131131
"api/v2/cmdb/firewall/policy/3": [D_POL3],
132132
f"api/v2/cmdb/firewall/policy/1?filter=name{EQ}{POL1}": [D_POL1],
@@ -141,7 +141,7 @@ class MockResponse(Response):
141141
f"api/v2/cmdb/firewall.service/custom/{NAME1}": [D_NAME1],
142142
f"api/v2/cmdb/firewall.service/group/{NAME1}": [D_NAME1],
143143

144-
"api/v2/cmdb/system.snmp/community/": [D_SNMP1, D_SNMP3],
144+
"api/v2/cmdb/system.snmp/community": [D_SNMP1, D_SNMP3],
145145
"api/v2/cmdb/system.snmp/community/1": [D_SNMP1],
146146
"api/v2/cmdb/system.snmp/community/3": [D_SNMP3],
147147
f"api/v2/cmdb/system.snmp/community/1?filter=name{EQ}{NAME1}": [D_SNMP1],
@@ -154,7 +154,7 @@ class MockResponse(Response):
154154
f"api/v2/cmdb/system/external-resource/{NAME1}": [D_NAME1],
155155
f"api/v2/cmdb/system/external-resource/?filter=name{EQ}{NAME1}": [D_NAME1],
156156

157-
"api/v2/cmdb/system/interface/": [D_INTF1, D_INTF3],
157+
"api/v2/cmdb/system/interface": [D_INTF1, D_INTF3],
158158
f"api/v2/cmdb/system/interface/?filter=name{EQ}{NAME1}": [D_INTF1],
159159
f"api/v2/cmdb/system/interface/?filter=name{EQ}{NAME3}": [D_INTF3],
160160
f"api/v2/cmdb/system/interface/{NAME1}": [D_INTF1],

tests/test__fortigate.py

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -231,17 +231,19 @@ def test_valid__hide_secret(self):
231231
def test_valid__valid_url(self):
232232
"""Fortigate._valid_url()"""
233233
default = dict(host="host", username="username", password="", port=443)
234-
query = "api/v2/cmdb/firewall/address/"
235-
url_ = f"https://host/{query}"
234+
query = "api/v2/cmdb/firewall/address"
235+
full_url = f"https://host/{query}"
236+
https_80 = "https://host:80/"
237+
http_80 = "http://host:80/"
236238
for kwargs, url, req in [
237-
({}, query, url_),
238-
({}, f"/{query}", url_),
239-
({}, "api/v2/cmdb/firewall/address", url_),
240-
({}, url_, url_),
241-
(dict(port=80), query, f"https://host:80/{query}"),
242-
(dict(port=80), f"https://host:80/{query}", f"https://host:80/{query}"),
243-
(dict(scheme="http", port=80), query, f"http://host:80/{query}"),
244-
(dict(scheme="http", port=80), f"http://host:80/{query}", f"http://host:80/{query}"),
239+
({}, query, full_url),
240+
({}, f"/{query}/", full_url),
241+
({}, full_url, full_url),
242+
({}, f"{full_url}/", full_url),
243+
(dict(port=80), query, f"{https_80}{query}"),
244+
(dict(port=80), f"{https_80}{query}", f"{https_80}{query}"),
245+
(dict(scheme="http", port=80), query, f"{http_80}{query}"),
246+
(dict(scheme="http", port=80), f"{http_80}{query}", f"{http_80}{query}"),
245247
]:
246248
kwargs_ = {**default, **kwargs}
247249
fgt = Fortigate(**kwargs_)

0 commit comments

Comments
 (0)