Skip to content

Commit

Permalink
Rework deprecations
Browse files Browse the repository at this point in the history
We're independent from Salt releases now, so act like it.
  • Loading branch information
lkubb committed Dec 11, 2023
1 parent bae0335 commit 984a8d2
Show file tree
Hide file tree
Showing 8 changed files with 165 additions and 8 deletions.
6 changes: 6 additions & 0 deletions docs/all.rst
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,9 @@ Complete List of saltext-vault
:maxdepth: 2

ref/states/index


.. toctree::
:maxdepth: 2

ref/utils/index
12 changes: 12 additions & 0 deletions docs/ref/utils/index.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
.. all-saltext.vault.utils:
____________
Util Modules
____________

.. currentmodule:: saltext.vault.utils

.. autosummary::
:toctree:

versions
5 changes: 5 additions & 0 deletions docs/ref/utils/saltext.vault.utils.versions.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
saltext.vault.utils.versions
============================

.. automodule:: saltext.vault.utils.versions
:members:
20 changes: 18 additions & 2 deletions src/saltext/vault/modules/vault.py
Original file line number Diff line number Diff line change
Expand Up @@ -698,6 +698,7 @@
from salt.exceptions import CommandExecutionError
from salt.exceptions import SaltException
from salt.exceptions import SaltInvocationError
from saltext.vault.utils.versions import warn_until

log = logging.getLogger(__name__)

Expand Down Expand Up @@ -972,7 +973,7 @@ def destroy_secret(path, *args):
return False


def list_secrets(path, default=NOT_SET, keys_only=False):
def list_secrets(path, default=NOT_SET, keys_only=None):
"""
List secret keys at <path>. The vault policy used must allow this.
The path should end with a trailing slash.
Expand Down Expand Up @@ -1008,10 +1009,25 @@ def list_secrets(path, default=NOT_SET, keys_only=False):
This function used to return a dictionary like ``{"keys": ["some/", "some/key"]}``.
Setting this to True will only return the list of keys.
For backwards-compatibility reasons, this defaults to False.
For backwards-compatibility reasons, this currently defaults to False.
Beginning with version 2 of this extension, the default will change to True.
"""
if default == NOT_SET:
default = CommandExecutionError
if keys_only is None:
try:
warn_until(
2,
(
"In version {version}, this function will return the list of "
"secret keys only. You can switch to the new behavior explicitly "
"by specifying keys_only=True."
),
)
keys_only = False
except RuntimeError:
keys_only = True

log.debug("Listing vault secret keys for %s in %s", __grains__.get("id"), path)
try:
keys = vault.list_kv(path, __opts__, __context__)
Expand Down
11 changes: 8 additions & 3 deletions src/saltext/vault/runners/vault.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
from salt.defaults import NOT_SET
from salt.exceptions import SaltInvocationError
from salt.exceptions import SaltRunnerError
from saltext.vault.utils.versions import warn_until

log = logging.getLogger(__name__)

Expand Down Expand Up @@ -156,9 +157,13 @@ def generate_token(
)
_validate_signature(minion_id, signature, impersonated_by_master)
try:
salt.utils.versions.warn_until(
"Argon",
"vault.generate_token endpoint is deprecated. Please update your minions.",
warn_until(
2,
(
"The vault.generate_token endpoint is deprecated and will be removed "
"in version {version}. Please ensure your minions are running the "
"Vault Salt extension as well."
),
)

if _config("issue:type") != "token":
Expand Down
22 changes: 20 additions & 2 deletions src/saltext/vault/sdb/vault.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,14 +45,16 @@
When writing data, partially update the secret instead of overwriting it completely.
This is usually the expected behavior, since without this option,
each secret path can only contain a single mapping key safely.
Defaults to ``False`` for backwards-compatibility reasons.
Currently defaults to ``False`` for backwards-compatibility reasons.
Beginning with version 2 of this extension, will default to ``True``.
.. versionadded:: 1.0.0
"""
import logging

import salt.exceptions
import saltext.vault.utils.vault as vault
from saltext.vault.utils.versions import warn_until

log = logging.getLogger(__name__)

Expand All @@ -70,8 +72,24 @@ def set_(key, value, profile=None): # pylint: disable=unused-argument
data = {key: value}
curr_data = {}
profile = profile or {}
patch = profile.get("patch")

if profile.get("patch"):
if patch is None:
try:
warn_until(
2,
(
"Beginning with version {version}, the Vault SDB module will "
"partially update secrets instead of overwriting it completely. "
"You can switch to the new behavior explicitly by specifying "
"patch: true in your Vault SDB configuration."
),
)
patch = False
except RuntimeError:
patch = True

if patch:
try:
# Patching only works on existing secrets.
# Save the current data if patching is enabled
Expand Down
95 changes: 95 additions & 0 deletions src/saltext/vault/utils/versions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import inspect
import os
import sys
import warnings

import packaging.version
from saltext.vault import __version__


def warn_until(
version,
message,
category=DeprecationWarning,
):
"""
Warn about deprecations until the specified version is reached, after which
raise a RuntimeError to remind developers about removal.
Loosely based on ``salt.utils.versions.warn_until``.
version
The version at which the warning turns into an error. Can be specified
as a string, float, int or iterable with items castable to integers.
message
The warning message to show.
category
The warning class to be thrown, by default ``DeprecationWarning``.
"""
version = _parse_version(version)
saltext_version = _parse_version(__version__)
# Attribute the warning to the calling function, not to warn_until()
stacklevel = 2

if saltext_version >= version:
caller = inspect.getframeinfo(sys._getframe(stacklevel - 1))
raise RuntimeError(
f"The warning triggered on filename '{caller.filename}', line number "
f"{caller.lineno}, is supposed to be shown until version "
f"{version} is released. Current version is now "
f"{saltext_version}. Please remove the warning."
)

if os.environ.get("PYTHONWARNINGS") != "ignore":
warnings.warn(
message.format(version=version),
category,
stacklevel=stacklevel,
)


class Version(packaging.version.Version):
def __lt__(self, other):
if isinstance(other, str):
other = Version(other)
return super().__lt__(other)

def __le__(self, other):
if isinstance(other, str):
other = Version(other)
return super().__le__(other)

def __eq__(self, other):
if isinstance(other, str):
other = Version(other)
return super().__eq__(other)

def __ge__(self, other):
if isinstance(other, str):
other = Version(other)
return super().__ge__(other)

def __gt__(self, other):
if isinstance(other, str):
other = Version(other)
return super().__gt__(other)

def __ne__(self, other):
if isinstance(other, str):
other = Version(other)
return super().__ne__(other)


def _parse_version(version):
if isinstance(version, str):
pass
elif isinstance(version, (float, int)):
version = str(version)
else:
try:
version = ".".join(str(x) for x in version)
except TypeError as err:
raise RuntimeError("`version` must be a string, integer, float or an iterable") from err
return Version(version)
2 changes: 1 addition & 1 deletion tests/unit/runners/vault/test_token_auth_deprecated.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
Unit tests for the Vault runner
This module only tests a deprecated function, see
tests/pytests/unit/runners/test_vault.py for the current tests.
tests/unit/runners/test_vault.py for the current tests.
"""
import logging
from unittest.mock import ANY
Expand Down

0 comments on commit 984a8d2

Please sign in to comment.