diff --git a/WHATSNEW.md b/WHATSNEW.md index 6b5dca8..87783bf 100644 --- a/WHATSNEW.md +++ b/WHATSNEW.md @@ -1,5 +1,8 @@ ### Added +- Add more examples on how to use imported fotoobo +- Add typing information for fotoobo so that mypy is able to check types when importing fotoobo + ### Changed ### Removed diff --git a/docs/source/usage/configuration.rst b/docs/source/usage/configuration.rst index b3c56a2..d6d7c50 100644 --- a/docs/source/usage/configuration.rst +++ b/docs/source/usage/configuration.rst @@ -74,7 +74,7 @@ Logging NOTE: The settings here apply the same to normal logging and audit logging. -If you configure a logging setting it is automatically enabled. Otherwise defaut logging will be +If you configure a logging setting it is automatically enabled. Otherwise default logging will be used. Default logging is set to log to **console** with log-level **WARNING**. .. _logging_level: diff --git a/docs/source/usage/import_fotoobo.rst b/docs/source/usage/import_fotoobo.rst index 5ad2bd6..a8d8ca3 100644 --- a/docs/source/usage/import_fotoobo.rst +++ b/docs/source/usage/import_fotoobo.rst @@ -62,3 +62,67 @@ FortiClient EMS print(ems.get_version()) ems.logout() +Using an inventory file +^^^^^^^^^^^^^^^^^^^^^^^ + +You can maintain an :ref:`inventory file` to load the assets from. This helps not having API tokens or username/passwords directly in the source code. + +Imagine you created the inventory file ``~/.config/inventory.yaml``: + +.. code-block:: yaml + + fmg-test: + hostname: myfortimanager.local + username: the_fortimanager_username + password: the_fortimanager_password + type: fortimanager + +With this inventory file you can use the asset ```fmg-test`` in your code: + +.. code-block:: python + + from fotoobo.inventory import Inventory + inventory = Inventory(Path("~/.config/inventory.yaml")) + fmg = inventory.get_item("fmg-test") + print(fmg.get_version()) + + +Using a configuration file +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +You can read your fotoobo :ref:`configuration file`. This is useful if you wish to load and change settings like :ref:`inventory file`, :ref:`logging options` or a :ref:`vault configuration`. + +Use the inventory file ``~/.config/inventory.yaml`` with the string ``VAULT`` as the token or password for your assets. + +.. code-block:: yaml + + fmg-test: + hostname: myfortimanager.local + username: the_fortimanager_username + password: VAULT + type: fortimanager + +Then you have to specify this inventory file and the vault configuration in the fotoobo configuration file ``~/.config/fotoobo.yaml``. + +.. code-block:: yaml + + inventory: ~/.config/inventory.yaml + vault: + url: https://vault.local + namespace: vault_namespace + data_path: /v1/kv/data/fotoobo + role_id: ... + secret_id: ... + token_file: ~/.cache/token.key + +With these preparations you can use the fotoobo configuration to access your assets. + +.. code-block:: python + + from fotoobo.helpers.config import config + from fotoobo.inventory import Inventory + config.load_configuration() + config.vault["ssl_verify"] = False + inventory = Inventory(config.inventory_file) + fmg = inventory.get_item("fmg-test") + print(fmg.get_version()) diff --git a/fotoobo/fortinet/forticlientems.py b/fotoobo/fortinet/forticlientems.py index 4944834..f5c1c1a 100644 --- a/fotoobo/fortinet/forticlientems.py +++ b/fotoobo/fortinet/forticlientems.py @@ -57,7 +57,7 @@ def api( # pylint: disable=too-many-arguments, too-many-positional-arguments params: dict[str, str] | None = None, payload: dict[str, Any] | None = None, timeout: float | None = None, - ) -> requests.models.Response: + ) -> requests.Response: """ API request to a FortiClientEMS device. diff --git a/fotoobo/fortinet/forticloudasset.py b/fotoobo/fortinet/forticloudasset.py index 4b84ed1..eed48be 100644 --- a/fotoobo/fortinet/forticloudasset.py +++ b/fotoobo/fortinet/forticloudasset.py @@ -54,7 +54,7 @@ def api( # pylint: disable=too-many-arguments, too-many-positional-arguments params: dict[str, str] | None = None, payload: dict[str, Any] | None = None, timeout: float | None = None, - ) -> requests.models.Response: + ) -> requests.Response: """ API request to a FortiManager device. diff --git a/fotoobo/fortinet/fortigate.py b/fotoobo/fortinet/fortigate.py index 5771246..c4547be 100644 --- a/fotoobo/fortinet/fortigate.py +++ b/fotoobo/fortinet/fortigate.py @@ -49,7 +49,7 @@ def api( # pylint: disable=too-many-arguments, too-many-positional-arguments params: dict[str, str] | None = None, payload: dict[str, Any] | None = None, timeout: float | None = None, - ) -> requests.models.Response: + ) -> requests.Response: """Native API request to a FortiGate. It uses the super.api method but it has to enrich the payload in post requests with the diff --git a/fotoobo/fortinet/fortimanager.py b/fotoobo/fortinet/fortimanager.py index 8d65c2f..ab11874 100644 --- a/fotoobo/fortinet/fortimanager.py +++ b/fotoobo/fortinet/fortimanager.py @@ -68,7 +68,7 @@ def __init__(self, hostname: str, username: str, password: str, **kwargs: Any) - "rootp", ] - def api_delete(self, url: str) -> requests.models.Response: + def api_delete(self, url: str) -> requests.Response: """DELETE method for API requests Args: @@ -85,7 +85,7 @@ def api_delete(self, url: str) -> requests.models.Response: def api_get( self, url: str, params: dict[str, Any] | None = None, timeout: float | None = None - ) -> requests.models.Response: + ) -> requests.Response: """GET method for API requests Args: @@ -114,7 +114,7 @@ def api( # pylint: disable=too-many-arguments, too-many-positional-arguments params: dict[str, str] | None = None, payload: dict[str, Any] | None = None, timeout: float | None = None, - ) -> requests.models.Response: + ) -> requests.Response: """ API request to a FortiManager device. @@ -818,7 +818,6 @@ def login(self) -> int: response = super().api("post", payload=payload) if response.status_code == 200: if "session" in response.json(): - log.debug("Storing session key") self.session_key = response.json()["session"] if self.session_path: diff --git a/fotoobo/fortinet/fortinet.py b/fotoobo/fortinet/fortinet.py index 3805c4f..d53749b 100644 --- a/fotoobo/fortinet/fortinet.py +++ b/fotoobo/fortinet/fortinet.py @@ -78,7 +78,7 @@ def api( # pylint: disable=too-many-arguments, too-many-positional-arguments params: dict[str, str] | None = None, payload: dict[str, Any] | None = None, timeout: float | None = None, - ) -> requests.models.Response: + ) -> requests.Response: """ API request to a Fortinet device. diff --git a/fotoobo/py.typed b/fotoobo/py.typed new file mode 100644 index 0000000..e69de29 diff --git a/poetry.lock b/poetry.lock index 9fecfb8..9f02510 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 2.1.4 and should not be changed by hand. +# This file is automatically @generated by Poetry 2.3.2 and should not be changed by hand. [[package]] name = "alabaster" @@ -1126,15 +1126,15 @@ testing = ["covdefaults (>=2.3)", "pytest (>=8.4.2)", "pytest-cov (>=7)", "pytes [[package]] name = "pytest" -version = "9.0.2" +version = "9.0.3" description = "pytest: simple powerful testing with Python" optional = true python-versions = ">=3.10" groups = ["main"] markers = "extra == \"dev\"" files = [ - {file = "pytest-9.0.2-py3-none-any.whl", hash = "sha256:711ffd45bf766d5264d487b917733b453d917afd2b0ad65223959f59089f875b"}, - {file = "pytest-9.0.2.tar.gz", hash = "sha256:75186651a92bd89611d1d9fc20f0b4345fd827c41ccd5c299a868a05d70edf11"}, + {file = "pytest-9.0.3-py3-none-any.whl", hash = "sha256:2c5efc453d45394fdd706ade797c0a81091eccd1d6e4bccfcd476e2b8e0ab5d9"}, + {file = "pytest-9.0.3.tar.gz", hash = "sha256:b86ada508af81d19edeb213c681b1d48246c1a91d304c6c81a427674c17eb91c"}, ] [package.dependencies] diff --git a/pyproject.toml b/pyproject.toml index 05de8aa..e3f7d0c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -91,7 +91,6 @@ disallow_untyped_decorators=false [tool.pytest.ini_options] addopts = "--basetemp=tests/temp/" - # here we define the tox settings # we do it inline because we don't want to have another tox.ini in the project root # package management is done as described in option 3 on the following FAQ