Compare commits

...

No commits in common. "c8" and "c8-beta" have entirely different histories.
c8 ... c8-beta

11 changed files with 19 additions and 1294 deletions

View File

@ -1,62 +1,37 @@
3297473a9d57e93ff378eab173990c1b64673c01 SOURCES/Jinja2-3.0.2.tar.gz
e1b766b2b1601fde67b3b19ed2f13b9746bb1cca SOURCES/MarkupSafe-2.0.1.tar.gz
3880207fdf0db1eeadf976092c8fbf80a7335c24 SOURCES/PyJWT-2.4.0.tar.gz
a8c40a3ae9d4c159382a58db3153d83e5521c51e SOURCES/PyYAML-6.0.tar.gz
0c47ce98be5a519023c16e10027ed1268c489fcc SOURCES/adal-1.2.7.tar.gz
0a56f6d9ed2014a363486d33b63eca094379be06 SOURCES/aliyun-python-sdk-core-2.13.1.tar.gz
c2a98b9a1562d223a76514f05028488ca000c395 SOURCES/aliyun-python-sdk-ecs-4.9.3.tar.gz
f14647a4d37a9a254c4e711b95a7654fc418e41e SOURCES/aliyun-python-sdk-vpc-3.0.2.tar.gz
1f493a02d15374027ae2bcb2ea4daf5b907c528b SOURCES/azure-common-1.1.28.zip
acfa532a6e6acc7311d697b3835a6190796ab5b4 SOURCES/azure-core-1.24.2.zip
46d2d17d958ae305ced32fdd6aa847b0cdf31989 SOURCES/azure-identity-1.10.0.zip
2a2e61ec1805165b19c4652b316225ced9b1ca28 SOURCES/azure-mgmt-compute-27.2.0.zip
f73acf29dd33e65a37b13dc8048832cbdd9e8306 SOURCES/azure-mgmt-core-1.3.2.zip
d4672e130177a9b330cf40c5bded8ed3aa4b1143 SOURCES/azure-mgmt-network-20.0.0.zip
2512ff4ef016cad0b916006f6acf2a309f908c4d SOURCES/botocore-1.23.46.tar.gz
0d12f48faa727f0979e9ad5c4c80dfa32b73caff SOURCES/cachetools-4.2.4.tar.gz
ec7e8dd8ef95edfdb83a1ea040b8b88507b47615 SOURCES/certifi-2023.7.22.tar.gz
c42a46cd11f6153f299cf10e9c236e8b2a143c21 SOURCES/cffi-1.15.1.tar.gz
2384f6cfba4685d901262e073a4455d4cf76d102 SOURCES/chardet-4.0.0.tar.gz
865df92e66e5dc7b940144cbad8115c07dc8784f SOURCES/charset-normalizer-2.0.7.tar.gz
eb8be696115458f9368432525e9cae11d0f6bebf SOURCES/cryptography-3.3.2.tar.gz
e2561df8e7ff9113dab118a651371dd88dab0142 SOURCES/fence-agents-4.2.1.tar.gz
81c165cd2a388d5a6cd415308edaf11ee5bf42cd SOURCES/flit_core-3.10.1.tar.gz
f4e578dc0ed68d6667d7b36cdfc2647d55e9858f SOURCES/google-auth-2.3.0.tar.gz
74ec77d2e2ef6b2ef8503e6e398faa6f3ba298ae SOURCES/httplib2-0.19.1-py3-none-any.whl
08c0449533fc94462f78652dea209099754d9ee4 SOURCES/idna-3.3.tar.gz
ea36ce1c780dd44f01225dca7f9995a6685a60cc SOURCES/isodate-0.6.1.tar.gz
356c48dfea2214dd9e7e2b222a99dddfe9c0d05c SOURCES/jmespath-0.10.0.tar.gz
d06a9547b1a87e9c51b0a7c708189d993f2e3d89 SOURCES/kubernetes-12.0.1.tar.gz
373683b6adda29af3b1334a69bf149b85deb7899 SOURCES/msal-1.27.0.tar.gz
04e016bd1fa4ed6ddb852095a45d4f8c81a5b54a SOURCES/msal-extensions-1.0.0.tar.gz
00c5509205e59ebae09e5d3fe068ab61588e9b4a SOURCES/msrest-0.7.1.zip
bcedc87fc73e9738cbc8b0435513c01b6eb0b5c2 SOURCES/msrestazure-0.6.4.tar.gz
f6efa66f6106b069b5c0e0cf8cc677e4e96c91ca SOURCES/oauthlib-3.1.1.tar.gz
7e2f8f4cebf309ef6aaf740ee9073276d6937802 SOURCES/oauthlib-3.2.2.tar.gz
570d69d8c108ebb8aee562389d13b07dfb61ce25 SOURCES/openshift-0.12.1.tar.gz
bccbc1bf76a9db46998eb8e1ffa2f2a2baf9237a SOURCES/packaging-21.2-py3-none-any.whl
a243525070cf70f22a185447ebd3e1435dabb218 SOURCES/pip-21.3.1.tar.gz
67c8e65065f751c87cadf973a0a2d7b2cfad3bfa SOURCES/poetry-core-1.0.8.tar.gz
4f099f76d500f4ca500a17a3a647f84b7a796e54 SOURCES/portalocker-2.7.0.tar.gz
e0fa19f8fda46a1fa2253477499b116b33f67175 SOURCES/pyasn1-0.4.8.tar.gz
43b89feb6864fe359aae89120627165219de313b SOURCES/pyasn1-modules-0.2.8.tar.gz
0ae93d89b69fab48af3a407a2f8663bcea270c3d SOURCES/pycparser-2.20.tar.gz
c55d177e9484d974c95078d4ae945f89ba2c7251 SOURCES/pycryptodome-3.20.0.tar.gz
c8307f47e3b75a2d02af72982a2dfefa3f56e407 SOURCES/pyparsing-2.4.7-py2.py3-none-any.whl
c2ba10c775b7a52a4b57cac4d4110a0c0f812a82 SOURCES/python-dateutil-2.8.2.tar.gz
1dc2fa004aa6517f1620e55d8a7b8e68a9cf2a47 SOURCES/python-string-utils-1.0.0.tar.gz
8c7a89d183d3e9b70bf91ba5b75eccf7111b9d8d SOURCES/requests-2.26.0.tar.gz
96c46fc47e75d06fa7ead4d7fb1ae7d58d68989f SOURCES/requests-2.27.1.tar.gz
f139aed770519b6a095b8fdc888d03955cbe9d8e SOURCES/requests-oauthlib-1.3.0.tar.gz
024bb67bc625557fd15b70e1c8e7d6abf5aa75dd SOURCES/requests-oauthlib-2.0.0.tar.gz
e8a53067e03fe1b6682fd99a40a7359396a06daa SOURCES/rsa-4.7.2.tar.gz
d1011ff44cd5a045de0460c1b79ec65592e86860 SOURCES/ruamel.yaml-0.17.16.tar.gz
27de97227bbbde5a9f571f9fad223578d7bdf7cc SOURCES/ruamel.yaml.clib-0.2.6.tar.gz
d5354718cb8c9330d3abc27445467ce8a5ed9d70 SOURCES/setuptools-58.3.0.tar.gz
0f34eba670121f9c41939ca8d805687de359f71c SOURCES/setuptools_scm-6.4.2.tar.gz
a4f02fddae697614e356cadfddb6241cc7737f38 SOURCES/setuptools_scm-6.3.2.tar.gz
06fa0bb50f2a4e2917fd14c21e9d2d5508ce0163 SOURCES/six-1.16.0.tar.gz
2a2b9fb5137976719423b1bb8241b83eb32bb7b0 SOURCES/tomli-1.1.0.tar.gz
0fab53e2ff16ae6370cfcf72e3e251535a5ebe74 SOURCES/typing_extensions-4.1.1.tar.gz
b42b7960047441db7dc021cc20e14279bd836f8d SOURCES/tomli-1.0.1.tar.gz
84e2852d8da1655373f7ce5e7d5d3e256b62b4e4 SOURCES/urllib3-1.26.18.tar.gz
540f083782c584989c1a0f69ffd69ba7aae07db6 SOURCES/websocket-client-1.2.1.tar.gz
f9f3d980579b88baaacdb6c4a3cc4466b9353030 SOURCES/wheel-0.37.1.tar.gz

29
.gitignore vendored
View File

@ -1,62 +1,37 @@
SOURCES/Jinja2-3.0.2.tar.gz
SOURCES/MarkupSafe-2.0.1.tar.gz
SOURCES/PyJWT-2.4.0.tar.gz
SOURCES/PyYAML-6.0.tar.gz
SOURCES/adal-1.2.7.tar.gz
SOURCES/aliyun-python-sdk-core-2.13.1.tar.gz
SOURCES/aliyun-python-sdk-ecs-4.9.3.tar.gz
SOURCES/aliyun-python-sdk-vpc-3.0.2.tar.gz
SOURCES/azure-common-1.1.28.zip
SOURCES/azure-core-1.24.2.zip
SOURCES/azure-identity-1.10.0.zip
SOURCES/azure-mgmt-compute-27.2.0.zip
SOURCES/azure-mgmt-core-1.3.2.zip
SOURCES/azure-mgmt-network-20.0.0.zip
SOURCES/botocore-1.23.46.tar.gz
SOURCES/cachetools-4.2.4.tar.gz
SOURCES/certifi-2023.7.22.tar.gz
SOURCES/cffi-1.15.1.tar.gz
SOURCES/chardet-4.0.0.tar.gz
SOURCES/charset-normalizer-2.0.7.tar.gz
SOURCES/cryptography-3.3.2.tar.gz
SOURCES/fence-agents-4.2.1.tar.gz
SOURCES/flit_core-3.10.1.tar.gz
SOURCES/google-auth-2.3.0.tar.gz
SOURCES/httplib2-0.19.1-py3-none-any.whl
SOURCES/idna-3.3.tar.gz
SOURCES/isodate-0.6.1.tar.gz
SOURCES/jmespath-0.10.0.tar.gz
SOURCES/kubernetes-12.0.1.tar.gz
SOURCES/msal-1.27.0.tar.gz
SOURCES/msal-extensions-1.0.0.tar.gz
SOURCES/msrest-0.7.1.zip
SOURCES/msrestazure-0.6.4.tar.gz
SOURCES/oauthlib-3.1.1.tar.gz
SOURCES/oauthlib-3.2.2.tar.gz
SOURCES/openshift-0.12.1.tar.gz
SOURCES/packaging-21.2-py3-none-any.whl
SOURCES/pip-21.3.1.tar.gz
SOURCES/poetry-core-1.0.8.tar.gz
SOURCES/portalocker-2.7.0.tar.gz
SOURCES/pyasn1-0.4.8.tar.gz
SOURCES/pyasn1-modules-0.2.8.tar.gz
SOURCES/pycparser-2.20.tar.gz
SOURCES/pycryptodome-3.20.0.tar.gz
SOURCES/pyparsing-2.4.7-py2.py3-none-any.whl
SOURCES/python-dateutil-2.8.2.tar.gz
SOURCES/python-string-utils-1.0.0.tar.gz
SOURCES/requests-2.26.0.tar.gz
SOURCES/requests-2.27.1.tar.gz
SOURCES/requests-oauthlib-1.3.0.tar.gz
SOURCES/requests-oauthlib-2.0.0.tar.gz
SOURCES/rsa-4.7.2.tar.gz
SOURCES/ruamel.yaml-0.17.16.tar.gz
SOURCES/ruamel.yaml.clib-0.2.6.tar.gz
SOURCES/setuptools-58.3.0.tar.gz
SOURCES/setuptools_scm-6.4.2.tar.gz
SOURCES/setuptools_scm-6.3.2.tar.gz
SOURCES/six-1.16.0.tar.gz
SOURCES/tomli-1.1.0.tar.gz
SOURCES/typing_extensions-4.1.1.tar.gz
SOURCES/tomli-1.0.1.tar.gz
SOURCES/urllib3-1.26.18.tar.gz
SOURCES/websocket-client-1.2.1.tar.gz
SOURCES/wheel-0.37.1.tar.gz

View File

@ -1,65 +0,0 @@
From d655030770081e2dfe46f90e27620472a502289d Mon Sep 17 00:00:00 2001
From: David Lord <davidism@gmail.com>
Date: Thu, 2 May 2024 09:14:00 -0700
Subject: [PATCH] disallow invalid characters in keys to xmlattr filter
---
CHANGES.rst | 6 ++++++
src/jinja2/filters.py | 22 +++++++++++++++++-----
tests/test_filters.py | 11 ++++++-----
3 files changed, 29 insertions(+), 10 deletions(-)
diff --git a/kubevirt/jinja2/filters.py b/kubevirt/jinja2/filters.py
index 4cf3c11fb..acd11976e 100644
--- a/kubevirt/jinja2/filters.py
+++ b/kubevirt/jinja2/filters.py
@@ -250,7 +250,9 @@ def do_items(value: t.Union[t.Mapping[K, V], Undefined]) -> t.Iterator[t.Tuple[K
yield from value.items()
-_space_re = re.compile(r"\s", flags=re.ASCII)
+# Check for characters that would move the parser state from key to value.
+# https://html.spec.whatwg.org/#attribute-name-state
+_attr_key_re = re.compile(r"[\s/>=]", flags=re.ASCII)
@pass_eval_context
@@ -259,8 +261,14 @@ def do_xmlattr(
) -> str:
"""Create an SGML/XML attribute string based on the items in a dict.
- If any key contains a space, this fails with a ``ValueError``. Values that
- are neither ``none`` nor ``undefined`` are automatically escaped.
+ **Values** that are neither ``none`` nor ``undefined`` are automatically
+ escaped, safely allowing untrusted user input.
+
+ User input should not be used as **keys** to this filter. If any key
+ contains a space, ``/`` solidus, ``>`` greater-than sign, or ``=`` equals
+ sign, this fails with a ``ValueError``. Regardless of this, user input
+ should never be used as keys to this filter, or must be separately validated
+ first.
.. sourcecode:: html+jinja
@@ -280,6 +288,10 @@ def do_xmlattr(
As you can see it automatically prepends a space in front of the item
if the filter returned something unless the second parameter is false.
+ .. versionchanged:: 3.1.4
+ Keys with ``/`` solidus, ``>`` greater-than sign, or ``=`` equals sign
+ are not allowed.
+
.. versionchanged:: 3.1.3
Keys with spaces are not allowed.
"""
@@ -289,8 +301,8 @@ def do_xmlattr(
if value is None or isinstance(value, Undefined):
continue
- if _space_re.search(key) is not None:
- raise ValueError(f"Spaces are not allowed in attributes: '{key}'")
+ if _attr_key_re.search(key) is not None:
+ raise ValueError(f"Invalid character in attribute name: {key!r}")
items.append(f'{escape(key)}="{escape(value)}"')

View File

@ -1,32 +0,0 @@
From accff72ecc2f6cf5a76d9570198a93ac7c90270e Mon Sep 17 00:00:00 2001
From: Quentin Pradet <quentin.pradet@gmail.com>
Date: Mon, 17 Jun 2024 11:09:06 +0400
Subject: [PATCH] Merge pull request from GHSA-34jh-p97f-mpxf
* Strip Proxy-Authorization header on redirects
* Fix test_retry_default_remove_headers_on_redirect
* Set release date
---
CHANGES.rst | 5 +++++
src/urllib3/util/retry.py | 4 +++-
test/test_retry.py | 6 ++++-
test/with_dummyserver/test_poolmanager.py | 27 ++++++++++++++++++++---
4 files changed, 37 insertions(+), 5 deletions(-)
diff --git a/kubevirt/urllib3/util/retry.py b/kubevirt/urllib3/util/retry.py
index 7a76a4a6ad..0456cceba4 100644
--- a/kubevirt/urllib3/util/retry.py
+++ b/kubevirt/urllib3/util/retry.py
@@ -189,7 +189,9 @@ class Retry:
RETRY_AFTER_STATUS_CODES = frozenset([413, 429, 503])
#: Default headers to be used for ``remove_headers_on_redirect``
- DEFAULT_REMOVE_HEADERS_ON_REDIRECT = frozenset(["Cookie", "Authorization"])
+ DEFAULT_REMOVE_HEADERS_ON_REDIRECT = frozenset(
+ ["Cookie", "Authorization", "Proxy-Authorization"]
+ )
#: Default maximum backoff time.
DEFAULT_BACKOFF_MAX = 120

View File

@ -1,32 +0,0 @@
From accff72ecc2f6cf5a76d9570198a93ac7c90270e Mon Sep 17 00:00:00 2001
From: Quentin Pradet <quentin.pradet@gmail.com>
Date: Mon, 17 Jun 2024 11:09:06 +0400
Subject: [PATCH] Merge pull request from GHSA-34jh-p97f-mpxf
* Strip Proxy-Authorization header on redirects
* Fix test_retry_default_remove_headers_on_redirect
* Set release date
---
CHANGES.rst | 5 +++++
src/urllib3/util/retry.py | 4 +++-
test/test_retry.py | 6 ++++-
test/with_dummyserver/test_poolmanager.py | 27 ++++++++++++++++++++---
4 files changed, 37 insertions(+), 5 deletions(-)
diff --git a/aws/urllib3/util/retry.py b/aws/urllib3/util/retry.py
index 7a76a4a6ad..0456cceba4 100644
--- a/aws/urllib3/util/retry.py
+++ b/aws/urllib3/util/retry.py
@@ -189,7 +189,9 @@ class Retry:
RETRY_AFTER_STATUS_CODES = frozenset([413, 429, 503])
#: Default headers to be used for ``remove_headers_on_redirect``
- DEFAULT_REMOVE_HEADERS_ON_REDIRECT = frozenset(["Cookie", "Authorization"])
+ DEFAULT_REMOVE_HEADERS_ON_REDIRECT = frozenset(
+ ["Cookie", "Authorization", "Proxy-Authorization"]
+ )
#: Default maximum backoff time.
DEFAULT_BACKOFF_MAX = 120

View File

@ -1,203 +0,0 @@
diff --color -uNr a/kubevirt/setuptools/package_index.py b/kubevirt/setuptools/package_index.py
--- a/kubevirt/setuptools/package_index.py 2021-10-22 22:55:51.000000000 +0200
+++ b/kubevirt/setuptools/package_index.py 2024-07-24 14:06:14.833852463 +0200
@@ -1,5 +1,6 @@
"""PyPI and direct package downloading"""
import sys
+import subprocess
import os
import re
import io
@@ -558,7 +559,7 @@
scheme = URL_SCHEME(spec)
if scheme:
# It's a url, download it to tmpdir
- found = self._download_url(scheme.group(1), spec, tmpdir)
+ found = self._download_url(spec, tmpdir)
base, fragment = egg_info_for_url(spec)
if base.endswith('.py'):
found = self.gen_setup(found, fragment, tmpdir)
@@ -777,7 +778,7 @@
raise DistutilsError("Download error for %s: %s"
% (url, v)) from v
- def _download_url(self, scheme, url, tmpdir):
+ def _download_url(self, url, tmpdir):
# Determine download filename
#
name, fragment = egg_info_for_url(url)
@@ -792,19 +793,59 @@
filename = os.path.join(tmpdir, name)
- # Download the file
- #
- if scheme == 'svn' or scheme.startswith('svn+'):
- return self._download_svn(url, filename)
- elif scheme == 'git' or scheme.startswith('git+'):
- return self._download_git(url, filename)
- elif scheme.startswith('hg+'):
- return self._download_hg(url, filename)
- elif scheme == 'file':
- return urllib.request.url2pathname(urllib.parse.urlparse(url)[2])
- else:
- self.url_ok(url, True) # raises error if not allowed
- return self._attempt_download(url, filename)
+ return self._download_vcs(url, filename) or self._download_other(url, filename)
+
+ @staticmethod
+ def _resolve_vcs(url):
+ """
+ >>> rvcs = PackageIndex._resolve_vcs
+ >>> rvcs('git+http://foo/bar')
+ 'git'
+ >>> rvcs('hg+https://foo/bar')
+ 'hg'
+ >>> rvcs('git:myhost')
+ 'git'
+ >>> rvcs('hg:myhost')
+ >>> rvcs('http://foo/bar')
+ """
+ scheme = urllib.parse.urlsplit(url).scheme
+ pre, sep, post = scheme.partition('+')
+ # svn and git have their own protocol; hg does not
+ allowed = set(['svn', 'git'] + ['hg'] * bool(sep))
+ return next(iter({pre} & allowed), None)
+
+ def _download_vcs(self, url, spec_filename):
+ vcs = self._resolve_vcs(url)
+ if not vcs:
+ return
+ if vcs == 'svn':
+ raise DistutilsError(
+ f"Invalid config, SVN download is not supported: {url}"
+ )
+
+ filename, _, _ = spec_filename.partition('#')
+ url, rev = self._vcs_split_rev_from_url(url)
+
+ self.info(f"Doing {vcs} clone from {url} to {filename}")
+ subprocess.check_call([vcs, 'clone', '--quiet', url, filename])
+
+ co_commands = dict(
+ git=[vcs, '-C', filename, 'checkout', '--quiet', rev],
+ hg=[vcs, '--cwd', filename, 'up', '-C', '-r', rev, '-q'],
+ )
+ if rev is not None:
+ self.info(f"Checking out {rev}")
+ subprocess.check_call(co_commands[vcs])
+
+ return filename
+
+ def _download_other(self, url, filename):
+ scheme = urllib.parse.urlsplit(url).scheme
+ if scheme == 'file': # pragma: no cover
+ return urllib.request.url2pathname(urllib.parse.urlparse(url).path)
+ # raise error if not allowed
+ self.url_ok(url, True)
+ return self._attempt_download(url, filename)
def scan_url(self, url):
self.process_url(url, True)
@@ -831,77 +872,37 @@
os.unlink(filename)
raise DistutilsError("Unexpected HTML page found at " + url)
- def _download_svn(self, url, filename):
- warnings.warn("SVN download support is deprecated", UserWarning)
- url = url.split('#', 1)[0] # remove any fragment for svn's sake
- creds = ''
- if url.lower().startswith('svn:') and '@' in url:
- scheme, netloc, path, p, q, f = urllib.parse.urlparse(url)
- if not netloc and path.startswith('//') and '/' in path[2:]:
- netloc, path = path[2:].split('/', 1)
- auth, host = _splituser(netloc)
- if auth:
- if ':' in auth:
- user, pw = auth.split(':', 1)
- creds = " --username=%s --password=%s" % (user, pw)
- else:
- creds = " --username=" + auth
- netloc = host
- parts = scheme, netloc, url, p, q, f
- url = urllib.parse.urlunparse(parts)
- self.info("Doing subversion checkout from %s to %s", url, filename)
- os.system("svn checkout%s -q %s %s" % (creds, url, filename))
- return filename
-
@staticmethod
- def _vcs_split_rev_from_url(url, pop_prefix=False):
- scheme, netloc, path, query, frag = urllib.parse.urlsplit(url)
-
- scheme = scheme.split('+', 1)[-1]
-
- # Some fragment identification fails
- path = path.split('#', 1)[0]
-
- rev = None
- if '@' in path:
- path, rev = path.rsplit('@', 1)
-
- # Also, discard fragment
- url = urllib.parse.urlunsplit((scheme, netloc, path, query, ''))
-
- return url, rev
-
- def _download_git(self, url, filename):
- filename = filename.split('#', 1)[0]
- url, rev = self._vcs_split_rev_from_url(url, pop_prefix=True)
-
- self.info("Doing git clone from %s to %s", url, filename)
- os.system("git clone --quiet %s %s" % (url, filename))
+ def _vcs_split_rev_from_url(url):
+ """
+ Given a possible VCS URL, return a clean URL and resolved revision if any.
- if rev is not None:
- self.info("Checking out %s", rev)
- os.system("git -C %s checkout --quiet %s" % (
- filename,
- rev,
- ))
+ >>> vsrfu = PackageIndex._vcs_split_rev_from_url
+ >>> vsrfu('git+https://github.com/pypa/setuptools@v69.0.0#egg-info=setuptools')
+ ('https://github.com/pypa/setuptools', 'v69.0.0')
+ >>> vsrfu('git+https://github.com/pypa/setuptools#egg-info=setuptools')
+ ('https://github.com/pypa/setuptools', None)
+ >>> vsrfu('http://foo/bar')
+ ('http://foo/bar', None)
+ """
+ parts = urllib.parse.urlsplit(url)
- return filename
+ clean_scheme = parts.scheme.split('+', 1)[-1]
- def _download_hg(self, url, filename):
- filename = filename.split('#', 1)[0]
- url, rev = self._vcs_split_rev_from_url(url, pop_prefix=True)
+ # Some fragment identification fails
+ no_fragment_path, _, _ = parts.path.partition('#')
- self.info("Doing hg clone from %s to %s", url, filename)
- os.system("hg clone --quiet %s %s" % (url, filename))
+ pre, sep, post = no_fragment_path.rpartition('@')
+ clean_path, rev = (pre, post) if sep else (post, None)
- if rev is not None:
- self.info("Updating to %s", rev)
- os.system("hg --cwd %s up -C -r %s -q" % (
- filename,
- rev,
- ))
+ resolved = parts._replace(
+ scheme=clean_scheme,
+ path=clean_path,
+ # discard the fragment
+ fragment='',
+ ).geturl()
- return filename
+ return resolved, rev
def debug(self, msg, *args):
log.debug(msg, *args)

View File

@ -1,40 +0,0 @@
From cb57f1c2ee734a40d01249305965ea4ecdf02039 Mon Sep 17 00:00:00 2001
From: Oyvind Albrigtsen <oalbrigt@redhat.com>
Date: Thu, 5 Sep 2024 09:06:34 +0200
Subject: [PATCH] fence_scsi: preempt clears all devices on the mpath device,
so only run it for the first device
---
agents/scsi/fence_scsi.py | 10 ++++++----
1 file changed, 6 insertions(+), 4 deletions(-)
diff --git a/agents/scsi/fence_scsi.py b/agents/scsi/fence_scsi.py
index a1598411c..12f7fb49b 100644
--- a/agents/scsi/fence_scsi.py
+++ b/agents/scsi/fence_scsi.py
@@ -131,11 +131,13 @@ def reset_dev(options, dev):
return run_cmd(options, options["--sg_turs-path"] + " " + dev)["rc"]
-def register_dev(options, dev, key):
+def register_dev(options, dev, key, do_preempt=True):
dev = os.path.realpath(dev)
if re.search(r"^dm", dev[5:]):
- for slave in get_mpath_slaves(dev):
- register_dev(options, slave, key)
+ devices = get_mpath_slaves(dev)
+ register_dev(options, devices[0], key)
+ for device in devices[1:]:
+ register_dev(options, device, key, False)
return True
# Check if any registration exists for the key already. We track this in
@@ -153,7 +155,7 @@ def register_dev(options, dev, key):
# If key matches, make sure it matches with the connection that
# exists right now. To do this, we can issue a preempt with same key
# which should replace the old invalid entries from the target.
- if not preempt(options, key, dev, key):
+ if do_preempt and not preempt(options, key, dev, key):
return False
# If there was no reservation, we need to issue another registration

View File

@ -1,381 +0,0 @@
--- a/lib/azure_fence.py.py 2025-01-30 14:47:16.047999700 +0100
+++ b/lib/azure_fence.py.py 2025-01-30 12:06:10.847889534 +0100
@@ -14,6 +14,9 @@
IP_TYPE_DYNAMIC = "Dynamic"
MAX_RETRY = 10
RETRY_WAIT = 5
+NETWORK_MGMT_CLIENT_API_VERSION = "2021-05-01"
+AZURE_RHEL8_COMPUTE_VERSION = "27.2.0"
+AZURE_COMPUTE_VERSION_5 = "5.0.0"
class AzureSubResource:
Type = None
@@ -49,7 +52,7 @@
return None
def get_azure_resource(id):
- match = re.match('(/subscriptions/([^/]*)/resourceGroups/([^/]*))(/providers/([^/]*/[^/]*)/([^/]*))?((/([^/]*)/([^/]*))*)', id)
+ match = re.match(r'(/subscriptions/([^/]*)/resourceGroups/([^/]*))(/providers/([^/]*/[^/]*)/([^/]*))?((/([^/]*)/([^/]*))*)', id)
if not match:
fail_usage("{get_azure_resource} cannot parse resource id %s" % id)
@@ -86,6 +89,59 @@
return resource
+def azure_dep_versions(v):
+ return tuple(map(int, (v.split("."))))
+
+# Do azure API call to list all virtual machines in a resource group
+def get_vm_list(compute_client,rgName):
+ return compute_client.virtual_machines.list(rgName)
+
+# Do azue API call to shutdown a virtual machine
+def do_vm_power_off(compute_client,rgName,vmName, skipShutdown):
+ try:
+ # Version is not available in azure-mgmt-compute version 14.0.0 until 27.2.0
+ from azure.mgmt.compute import __version__
+ except ImportError:
+ __version__ = "0.0.0"
+
+ # use different implementation call based on used version
+ if (azure_dep_versions(__version__) == azure_dep_versions(AZURE_COMPUTE_VERSION_5)):
+ logging.debug("{do_vm_power_off} azure.mgtm.compute version is to old to use 'begin_power_off' use 'power_off' function")
+ compute_client.virtual_machines.power_off(rgName, vmName, skip_shutdown=skipShutdown)
+ return
+
+ compute_client.virtual_machines.begin_power_off(rgName, vmName, skip_shutdown=skipShutdown)
+
+# Do azure API call to start a virtual machine
+def do_vm_start(compute_client,rgName,vmName):
+ try:
+ # Version is not available in azure-mgmt-compute version 14.0.0 until 27.2.0
+ from azure.mgmt.compute import __version__
+ except ImportError:
+ __version__ = "0.0.0"
+
+ # use different implementation call based on used version
+ if (azure_dep_versions(__version__) == azure_dep_versions(AZURE_COMPUTE_VERSION_5)):
+ logging.debug("{do_vm_start} azure.mgtm.compute version is to old to use 'begin_start' use 'start' function")
+ compute_client.virtual_machines.start(rgName, vmName)
+ return
+
+ compute_client.virtual_machines.begin_start(rgName, vmName)
+
+def get_vm_resource(compute_client, rgName, vmName):
+ try:
+ # Version is not available in azure-mgmt-compute version 14.0.0 until 27.2.0
+ from azure.mgmt.compute import __version__
+ except ImportError:
+ __version__ = "0.0.0"
+
+ # use different implementation call based on used version
+ if (azure_dep_versions(__version__) <= azure_dep_versions(AZURE_RHEL8_COMPUTE_VERSION)):
+ return compute_client.virtual_machines.get(rgName, vmName, "instanceView")
+
+ return compute_client.virtual_machines.get(resource_group_name=rgName, vm_name=vmName,expand="instanceView")
+
+
def get_fence_subnet_for_config(ipConfig, network_client):
subnetResource = get_azure_resource(ipConfig.subnet.id)
logging.debug("{get_fence_subnet_for_config} testing virtual network %s in resource group %s for a fence subnet" %(subnetResource.ResourceName, subnetResource.ResourceGroupName))
@@ -152,7 +208,7 @@
result = FENCE_STATE_ON
try:
- vm = compute_client.virtual_machines.get(rgName, vmName, "instanceView")
+ vm = get_vm_resource(compute_client, rgName, vmName)
allNICOK = True
for nicRef in vm.network_profile.network_interfaces:
@@ -179,7 +235,7 @@
import msrestazure.azure_exceptions
logging.info("{set_network_state} Setting state %s for %s in resource group %s" % (operation, vmName, rgName))
- vm = compute_client.virtual_machines.get(rgName, vmName, "instanceView")
+ vm = get_vm_resource(compute_client,rgName, vmName)
operations = []
for nicRef in vm.network_profile.network_interfaces:
@@ -268,10 +324,72 @@
return config
+# Function to fetch endpoints from metadata endpoint for azure_stack
+def get_cloud_from_arm_metadata_endpoint(arm_endpoint):
+ try:
+ import requests
+ session = requests.Session()
+ metadata_endpoint = arm_endpoint + "/metadata/endpoints?api-version=2015-01-01"
+ response = session.get(metadata_endpoint)
+ if response.status_code == 200:
+ metadata = response.json()
+ return {
+ "resource_manager": arm_endpoint,
+ "credential_scopes": [metadata.get("graphEndpoint") + "/.default"],
+ "authority_hosts": metadata['authentication'].get('loginEndpoint').replace("https://","")
+ }
+ else:
+ fail_usage("Failed to get cloud from metadata endpoint: %s - %s" % arm_endpoint, e)
+ except Exception as e:
+ fail_usage("Failed to get cloud from metadata endpoint: %s - %s" % arm_endpoint, e)
+
+def get_azure_arm_endpoints(cloudName, authority):
+ cloudEnvironment = {
+ "authority_hosts": authority
+ }
+
+ if cloudName == "AZURE_CHINA_CLOUD":
+ cloudEnvironment["resource_manager"] = "https://management.chinacloudapi.cn/"
+ cloudEnvironment["credential_scopes"] = ["https://management.chinacloudapi.cn/.default"]
+ return cloudEnvironment
+
+ if cloudName == "AZURE_US_GOV_CLOUD":
+ cloudEnvironment["resource_manager"] = "https://management.usgovcloudapi.net/"
+ cloudEnvironment["credential_scopes"] = ["https://management.core.usgovcloudapi.net/.default"]
+ return cloudEnvironment
+
+ if cloudName == "AZURE_PUBLIC_CLOUD":
+ cloudEnvironment["resource_manager"] = "https://management.azure.com/"
+ cloudEnvironment["credential_scopes"] = ["https://management.azure.com/.default"]
+ return cloudEnvironment
+
+
def get_azure_cloud_environment(config):
- cloud_environment = None
- if config.Cloud:
+ if (config.Cloud is None):
+ config.Cloud = "public"
+
+ try:
+ from azure.identity import AzureAuthorityHosts
+
+ azureCloudName = "AZURE_PUBLIC_CLOUD"
+ authorityHosts = AzureAuthorityHosts.AZURE_PUBLIC_CLOUD
if (config.Cloud.lower() == "china"):
+ azureCloudName = "AZURE_CHINA_CLOUD"
+ authorityHosts = AzureAuthorityHosts.AZURE_CHINA
+ elif (config.Cloud.lower() == "usgov"):
+ azureCloudName = "AZURE_US_GOV_CLOUD"
+ authorityHosts = AzureAuthorityHosts.AZURE_GOVERNMENT
+ elif (config.Cloud.lower() == "stack"):
+ # use custom function to call the azuer stack metadata endpoint to get required configuration.
+ return get_cloud_from_arm_metadata_endpoint(config.MetadataEndpoint)
+
+ return get_azure_arm_endpoints(azureCloudName, authorityHosts)
+
+ except ImportError:
+ if (config.Cloud.lower() == "public"):
+ from msrestazure.azure_cloud import AZURE_PUBLIC_CLOUD
+ cloud_environment = AZURE_PUBLIC_CLOUD
+ elif (config.Cloud.lower() == "china"):
from msrestazure.azure_cloud import AZURE_CHINA_CLOUD
cloud_environment = AZURE_CHINA_CLOUD
elif (config.Cloud.lower() == "germany"):
@@ -284,31 +402,43 @@
from msrestazure.azure_cloud import get_cloud_from_metadata_endpoint
cloud_environment = get_cloud_from_metadata_endpoint(config.MetadataEndpoint)
- return cloud_environment
+ authority_hosts = cloud_environment.endpoints.active_directory.replace("http://","")
+ return {
+ "resource_manager": cloud_environment.endpoints.resource_manager,
+ "credential_scopes": [cloud_environment.endpoints.active_directory_resource_id + "/.default"],
+ "authority_hosts": authority_hosts,
+ "cloud_environment": cloud_environment,
+ }
def get_azure_credentials(config):
credentials = None
cloud_environment = get_azure_cloud_environment(config)
- if config.UseMSI and cloud_environment:
- from msrestazure.azure_active_directory import MSIAuthentication
- credentials = MSIAuthentication(cloud_environment=cloud_environment)
- elif config.UseMSI:
- from msrestazure.azure_active_directory import MSIAuthentication
- credentials = MSIAuthentication()
- elif cloud_environment:
- from azure.common.credentials import ServicePrincipalCredentials
- credentials = ServicePrincipalCredentials(
+ if config.UseMSI:
+ try:
+ from azure.identity import ManagedIdentityCredential
+ credentials = ManagedIdentityCredential(authority=cloud_environment["authority_hosts"])
+ except ImportError:
+ from msrestazure.azure_active_directory import MSIAuthentication
+ credentials = MSIAuthentication(cloud_environment=cloud_environment["cloud_environment"])
+ return credentials
+
+ try:
+ # try to use new libraries ClientSecretCredential (azure.identity, based on azure.core)
+ from azure.identity import ClientSecretCredential
+ credentials = ClientSecretCredential(
client_id = config.ApplicationId,
- secret = config.ApplicationKey,
- tenant = config.Tenantid,
- cloud_environment=cloud_environment
+ client_secret = config.ApplicationKey,
+ tenant_id = config.Tenantid,
+ authority=cloud_environment["authority_hosts"]
)
- else:
+ except ImportError:
+ # use old libraries ServicePrincipalCredentials (azure.common) if new one is not available
from azure.common.credentials import ServicePrincipalCredentials
credentials = ServicePrincipalCredentials(
client_id = config.ApplicationId,
secret = config.ApplicationKey,
- tenant = config.Tenantid
+ tenant = config.Tenantid,
+ cloud_environment=cloud_environment["cloud_environment"]
)
return credentials
@@ -317,40 +447,75 @@
from azure.mgmt.compute import ComputeManagementClient
cloud_environment = get_azure_cloud_environment(config)
- if cloud_environment and config.Cloud.lower() == "stack" and not config.MetadataEndpoint:
- fail_usage("metadata-endpoint not specified")
credentials = get_azure_credentials(config)
- if cloud_environment:
+ # Try to read the default used api version from the installed package.
+ try:
+ compute_api_version = ComputeManagementClient.LATEST_PROFILE.get_profile_dict()["azure.mgmt.compute.ComputeManagementClient"]["virtual_machines"]
+ except Exception as e:
+ compute_api_version = ComputeManagementClient.DEFAULT_API_VERSION
+ logging.debug("{get_azure_compute_client} Failed to get the latest profile: %s using the default api version %s" % (e, compute_api_version))
+
+ logging.debug("{get_azure_compute_client} use virtual_machine api version: %s" %(compute_api_version))
+
+ if (config.Cloud.lower() == "stack") and not config.MetadataEndpoint:
+ fail_usage("metadata-endpoint not specified")
+
+ try:
+ from azure.profiles import KnownProfiles
+ if (config.Cloud.lower() == "stack"):
+ client_profile = KnownProfiles.v2020_09_01_hybrid
+ else:
+ client_profile = KnownProfiles.default
compute_client = ComputeManagementClient(
credentials,
config.SubscriptionId,
- base_url=cloud_environment.endpoints.resource_manager
+ base_url=cloud_environment["resource_manager"],
+ profile=client_profile,
+ credential_scopes=cloud_environment["credential_scopes"],
+ api_version=compute_api_version
)
- else:
+ except TypeError:
compute_client = ComputeManagementClient(
credentials,
- config.SubscriptionId
+ config.SubscriptionId,
+ base_url=cloud_environment["resource_manager"],
+ api_version=compute_api_version
)
+
return compute_client
def get_azure_network_client(config):
from azure.mgmt.network import NetworkManagementClient
cloud_environment = get_azure_cloud_environment(config)
- if cloud_environment and config.Cloud.lower() == "stack" and not config.MetadataEndpoint:
- fail_usage("metadata-endpoint not specified")
credentials = get_azure_credentials(config)
- if cloud_environment:
+ if (config.Cloud.lower() == "stack") and not config.MetadataEndpoint:
+ fail_usage("metadata-endpoint not specified")
+
+
+ from azure.profiles import KnownProfiles
+
+ if (config.Cloud.lower() == "stack"):
+ client_profile = KnownProfiles.v2020_09_01_hybrid
+ else:
+ client_profile = KnownProfiles.default
+
+ try:
network_client = NetworkManagementClient(
credentials,
config.SubscriptionId,
- base_url=cloud_environment.endpoints.resource_manager
+ base_url=cloud_environment["resource_manager"],
+ profile=client_profile,
+ credential_scopes=cloud_environment["credential_scopes"],
+ api_version=NETWORK_MGMT_CLIENT_API_VERSION
)
- else:
+ except TypeError:
network_client = NetworkManagementClient(
credentials,
- config.SubscriptionId
+ config.SubscriptionId,
+ base_url=cloud_environment["resource_manager"],
+ api_version=NETWORK_MGMT_CLIENT_API_VERSION
)
return network_client
--- a/agents/azure_arm/fence_azure_arm.py 2025-01-30 15:28:35.889163377 +0100
+++ b/agents/azure_arm/fence_azure_arm.py 2025-01-30 15:28:52.190553135 +0100
@@ -7,7 +7,6 @@
sys.path.append("@FENCEAGENTSLIBDIR@")
from fencing import *
from fencing import fail_usage, run_command, run_delay
-
sys.path.insert(0, '/usr/lib/fence-agents/bundled/azure')
import azure_fence
@@ -17,7 +16,7 @@
if clients:
compute_client = clients[0]
rgName = options["--resourceGroup"]
- vms = compute_client.virtual_machines.list(rgName)
+ vms = azure_fence.get_vm_list(compute_client,rgName)
try:
for vm in vms:
result[vm.name] = ("", None)
@@ -33,7 +32,7 @@
rgName = options["--resourceGroup"]
try:
- vms = compute_client.virtual_machines.list(rgName)
+ vms = azure_fence.get_vm_list(compute_client,rgName)
except Exception as e:
fail_usage("Failed: %s" % e)
@@ -74,7 +73,7 @@
powerState = "unknown"
try:
- vmStatus = compute_client.virtual_machines.get(rgName, vmName, "instanceView")
+ vmStatus = azure_fence.get_vm_resource(compute_client, rgName, vmName)
except Exception as e:
fail_usage("Failed: %s" % e)
@@ -117,11 +116,10 @@
if (options["--action"]=="off"):
logging.info("Poweroff " + vmName + " in resource group " + rgName)
- compute_client.virtual_machines.power_off(rgName, vmName, skip_shutdown=True)
+ azure_fence.do_vm_power_off(compute_client, rgName, vmName, True)
elif (options["--action"]=="on"):
logging.info("Starting " + vmName + " in resource group " + rgName)
- compute_client.virtual_machines.start(rgName, vmName)
-
+ azure_fence.do_vm_start(compute_client, rgName, vmName)
def define_new_opts():
all_opt["resourceGroup"] = {
@@ -241,7 +239,7 @@
except ImportError:
fail_usage("Azure Resource Manager Python SDK not found or not accessible")
except Exception as e:
- fail_usage("Failed: %s" % re.sub("^, ", "", str(e)))
+ fail_usage("Failed: %s" % re.sub(r"^, ", r"", str(e)))
if "--network-fencing" in options:
# use off-action to quickly return off once network is fenced instead of

View File

@ -1,365 +0,0 @@
From 55451b6fd007e6f9a6d6860e95304b7c5c27cc1b Mon Sep 17 00:00:00 2001
From: Oyvind Albrigtsen <oalbrigt@redhat.com>
Date: Thu, 2 May 2024 15:10:16 +0200
Subject: [PATCH 1/2] fencing: add support for docs["agent_name"] to use the
main agent name when generating manpages
---
lib/fencing.py.py | 12 +++++++++---
tests/data/metadata/fence_eps.xml | 9 ++++++---
2 files changed, 15 insertions(+), 6 deletions(-)
diff --git a/lib/fencing.py.py b/lib/fencing.py.py
index 511eb2689..66e2ff156 100644
--- a/lib/fencing.py.py
+++ b/lib/fencing.py.py
@@ -603,7 +603,7 @@ def usage(avail_opt):
if len(value["help"]) != 0:
print(" " + _join_wrap([value["help"]], first_indent=3))
-def metadata(options, avail_opt, docs):
+def metadata(options, avail_opt, docs, agent_name=os.path.basename(sys.argv[0])):
# avail_opt has to be unique, if there are duplicities then they should be removed
sorted_list = [(key, all_opt[key]) for key in list(set(avail_opt)) if "longopt" in all_opt[key]]
# Find keys that are going to replace inconsistent names
@@ -617,7 +617,7 @@ def metadata(options, avail_opt, docs):
docs["longdesc"] = re.sub(r"\\f[BPIR]|\.P|\.TP|\.br\n", r"", docs["longdesc"])
print("<?xml version=\"1.0\" ?>")
- print("<resource-agent name=\"" + os.path.basename(sys.argv[0]) + \
+ print("<resource-agent name=\"" + agent_name + \
"\" shortdesc=\"" + docs["shortdesc"] + "\" >")
for (symlink, desc) in docs.get("symlink", []):
print("<symlink name=\"" + symlink + "\" shortdesc=\"" + desc + "\"/>")
@@ -928,9 +928,15 @@ def show_docs(options, docs=None):
sys.exit(0)
if options.get("--action", "") in ["metadata", "manpage"]:
+ if options["--action"] == "metadata" or "agent_name" not in docs:
+ agent_name=os.path.basename(sys.argv[0])
+ else:
+ agent_name=docs["agent_name"]
+
+
if "port_as_ip" in device_opt:
device_opt.remove("separator")
- metadata(options, device_opt, docs)
+ metadata(options, device_opt, docs, agent_name)
sys.exit(0)
if "--version" in options:
diff --git a/tests/data/metadata/fence_eps.xml b/tests/data/metadata/fence_eps.xml
index 3f9ebdc22..a3aeb1aea 100644
--- a/tests/data/metadata/fence_eps.xml
+++ b/tests/data/metadata/fence_eps.xml
@@ -1,9 +1,12 @@
<?xml version="1.0" ?>
<resource-agent name="fence_eps" shortdesc="Fence agent for ePowerSwitch" >
-<longdesc>fence_eps is a Power Fencing agent which can be used with the ePowerSwitch 8M+ power switch to fence connected machines. Fence agent works ONLY on 8M+ device, because this is only one, which has support for hidden page feature.
+<symlink name="fence_epsr2" shortdesc="Fence agent for ePowerSwitch R2 and newer"/>
+<longdesc>fence_eps is a Power Fencing agent which can be used with the ePowerSwitch 8M+ power switch to fence connected machines. It ONLY works on 8M+ devices, as they support the hidden page feature.
-Agent basically works by connecting to hidden page and pass appropriate arguments to GET request. This means, that hidden page feature must be enabled and properly configured.</longdesc>
-<vendor-url>http://www.epowerswitch.com</vendor-url>
+The agent works by connecting to the hidden page and pass the appropriate arguments to GET request. This means, that the hidden page feature must be enabled and properly configured.
+
+NOTE: In most cases you want to use fence_epsr2, as fence_eps only works with older hardware.</longdesc>
+<vendor-url>https://www.neol.com</vendor-url>
<parameters>
<parameter name="action" unique="0" required="1">
<getopt mixed="-o, --action=[action]" />
From 639f5293e0b2c0153ea01bf37534b74f436dd630 Mon Sep 17 00:00:00 2001
From: Oyvind Albrigtsen <oalbrigt@redhat.com>
Date: Tue, 13 Feb 2024 11:11:25 +0100
Subject: [PATCH 2/2] fence_eps: add fence_epsr2 for ePowerSwitch R2 and newer
---
agents/eps/fence_eps.py | 46 ++++---
fence-agents.spec.in | 4 +-
tests/data/metadata/fence_epsr2.xml | 178 ++++++++++++++++++++++++++++
3 files changed, 211 insertions(+), 17 deletions(-)
create mode 100644 tests/data/metadata/fence_epsr2.xml
diff --git a/agents/eps/fence_eps.py b/agents/eps/fence_eps.py
index 81e439533..1e6bda099 100644
--- a/agents/eps/fence_eps.py
+++ b/agents/eps/fence_eps.py
@@ -3,8 +3,8 @@
# The Following Agent Has Been Tested On:
# ePowerSwitch 8M+ version 1.0.0.4
-import sys, re
-import base64, string, socket
+import sys, os, re
+import base64, socket
import logging
import atexit
sys.path.append("@FENCEAGENTSLIBDIR@")
@@ -37,7 +37,7 @@ def eps_run_command(options, params):
options["--password"] = "" # Default is empty password
# String for Authorization header
- auth_str = 'Basic ' + string.strip(base64.encodestring(options["--username"]+':'+options["--password"]))
+ auth_str = 'Basic ' + str(base64.encodebytes(bytes(options["--username"]+':'+options["--password"], "utf-8")).decode("utf-8").strip())
logging.debug("Authorization: %s\n", auth_str)
conn.putheader('Authorization', auth_str)
@@ -60,16 +60,22 @@ def eps_run_command(options, params):
logging.error("Failed: {}".format(str(e)))
fail(EC_LOGIN_DENIED)
- return result
+ return result.decode("utf-8", "ignore")
def get_power_status(conn, options):
del conn
ret_val = eps_run_command(options, "")
result = {}
- status = re.findall(r"p(\d{2})=(0|1)\s*\<br\>", ret_val.lower())
+ if os.path.basename(sys.argv[0]) == "fence_eps":
+ status = re.findall(r"p(\d{2})=(0|1)\s*\<br\>", ret_val.lower())
+ elif os.path.basename(sys.argv[0]) == "fence_epsr2":
+ status = re.findall(r"m0:o(\d)=(on|off)\s*", ret_val.lower())
for out_num, out_stat in status:
- result[out_num] = ("", (out_stat == "1" and "on" or "off"))
+ if os.path.basename(sys.argv[0]) == "fence_eps":
+ result[out_num] = ("", (out_stat == "1" and "on" or "off"))
+ elif os.path.basename(sys.argv[0]) == "fence_epsr2":
+ result[out_num] = ("", out_stat)
if not options["--action"] in ['monitor', 'list']:
if not options["--plug"] in result:
@@ -81,7 +87,12 @@ def get_power_status(conn, options):
def set_power_status(conn, options):
del conn
- eps_run_command(options, "P%s=%s"%(options["--plug"], (options["--action"] == "on" and "1" or "0")))
+ if os.path.basename(sys.argv[0]) == "fence_eps":
+ eps_run_command(options, "P%s=%s"%(options["--plug"], (options["--action"] == "on" and "1" or "0")))
+ elif os.path.basename(sys.argv[0]) == "fence_epsr2":
+ if options["--action"] == "reboot":
+ options["--action"] = "off"
+ eps_run_command(options, "M0:O%s=%s"%(options["--plug"], options["--action"]))
# Define new option
def eps_define_new_opts():
@@ -107,20 +118,25 @@ def main():
options = check_input(device_opt, process_input(device_opt))
docs = {}
+ docs["agent_name"] = "fence_eps"
docs["shortdesc"] = "Fence agent for ePowerSwitch"
- docs["longdesc"] = "fence_eps is a Power Fencing agent \
+ docs["longdesc"] = os.path.basename(sys.argv[0]) + " is a Power Fencing agent \
which can be used with the ePowerSwitch 8M+ power switch to fence \
-connected machines. Fence agent works ONLY on 8M+ device, because \
-this is only one, which has support for hidden page feature. \
+connected machines. It ONLY works on 8M+ devices, as \
+they support the hidden page feature. \
\n.TP\n\
-Agent basically works by connecting to hidden page and pass \
-appropriate arguments to GET request. This means, that hidden \
-page feature must be enabled and properly configured."
- docs["vendorurl"] = "http://www.epowerswitch.com"
+The agent works by connecting to the hidden page and pass \
+the appropriate arguments to GET request. This means, that the hidden \
+page feature must be enabled and properly configured. \
+\n.TP\n\
+NOTE: In most cases you want to use fence_epsr2, as fence_eps \
+only works with older hardware."
+ docs["vendorurl"] = "https://www.neol.com"
+ docs["symlink"] = [("fence_epsr2", "Fence agent for ePowerSwitch R2 and newer")]
show_docs(options, docs)
run_delay(options)
- #Run fence action. Conn is None, beacause we always need open new http connection
+ #Run fence action. Conn is None, because we always need open new http connection
result = fence_action(None, options, set_power_status, get_power_status, get_power_status)
sys.exit(result)
diff --git a/tests/data/metadata/fence_epsr2.xml b/tests/data/metadata/fence_epsr2.xml
new file mode 100644
index 000000000..37074e052
--- /dev/null
+++ b/tests/data/metadata/fence_epsr2.xml
@@ -0,0 +1,178 @@
+<?xml version="1.0" ?>
+<resource-agent name="fence_epsr2" shortdesc="Fence agent for ePowerSwitch" >
+<symlink name="fence_epsr2" shortdesc="Fence agent for ePowerSwitch R2 and newer"/>
+<longdesc>fence_epsr2 is a Power Fencing agent which can be used with the ePowerSwitch 8M+ power switch to fence connected machines. It ONLY works on 8M+ devices, as they support the hidden page feature.
+
+The agent works by connecting to the hidden page and pass the appropriate arguments to GET request. This means, that the hidden page feature must be enabled and properly configured.
+
+NOTE: In most cases you want to use fence_epsr2, as fence_eps only works with older hardware.</longdesc>
+<vendor-url>https://www.neol.com</vendor-url>
+<parameters>
+ <parameter name="action" unique="0" required="1">
+ <getopt mixed="-o, --action=[action]" />
+ <content type="string" default="reboot" />
+ <shortdesc lang="en">Fencing action</shortdesc>
+ </parameter>
+ <parameter name="hidden_page" unique="0" required="0" deprecated="1">
+ <getopt mixed="-c, --page=[page]" />
+ <content type="string" default="hidden.htm" />
+ <shortdesc lang="en">Name of hidden page</shortdesc>
+ </parameter>
+ <parameter name="ip" unique="0" required="1" obsoletes="ipaddr">
+ <getopt mixed="-a, --ip=[ip]" />
+ <content type="string" />
+ <shortdesc lang="en">IP address or hostname of fencing device</shortdesc>
+ </parameter>
+ <parameter name="ipaddr" unique="0" required="1" deprecated="1">
+ <getopt mixed="-a, --ip=[ip]" />
+ <content type="string" />
+ <shortdesc lang="en">IP address or hostname of fencing device</shortdesc>
+ </parameter>
+ <parameter name="ipport" unique="0" required="0">
+ <getopt mixed="-u, --ipport=[port]" />
+ <content type="integer" default="80" />
+ <shortdesc lang="en">TCP/UDP port to use for connection with device</shortdesc>
+ </parameter>
+ <parameter name="login" unique="0" required="0" deprecated="1">
+ <getopt mixed="-l, --username=[name]" />
+ <content type="string" />
+ <shortdesc lang="en">Login name</shortdesc>
+ </parameter>
+ <parameter name="page" unique="0" required="0" obsoletes="hidden_page">
+ <getopt mixed="-c, --page=[page]" />
+ <content type="string" default="hidden.htm" />
+ <shortdesc lang="en">Name of hidden page</shortdesc>
+ </parameter>
+ <parameter name="passwd" unique="0" required="0" deprecated="1">
+ <getopt mixed="-p, --password=[password]" />
+ <content type="string" />
+ <shortdesc lang="en">Login password or passphrase</shortdesc>
+ </parameter>
+ <parameter name="passwd_script" unique="0" required="0" deprecated="1">
+ <getopt mixed="-S, --password-script=[script]" />
+ <content type="string" />
+ <shortdesc lang="en">Script to run to retrieve password</shortdesc>
+ </parameter>
+ <parameter name="password" unique="0" required="0" obsoletes="passwd">
+ <getopt mixed="-p, --password=[password]" />
+ <content type="string" />
+ <shortdesc lang="en">Login password or passphrase</shortdesc>
+ </parameter>
+ <parameter name="password_script" unique="0" required="0" obsoletes="passwd_script">
+ <getopt mixed="-S, --password-script=[script]" />
+ <content type="string" />
+ <shortdesc lang="en">Script to run to retrieve password</shortdesc>
+ </parameter>
+ <parameter name="plug" unique="0" required="1" obsoletes="port">
+ <getopt mixed="-n, --plug=[id]" />
+ <content type="string" />
+ <shortdesc lang="en">Physical plug number on device, UUID or identification of machine</shortdesc>
+ </parameter>
+ <parameter name="port" unique="0" required="1" deprecated="1">
+ <getopt mixed="-n, --plug=[id]" />
+ <content type="string" />
+ <shortdesc lang="en">Physical plug number on device, UUID or identification of machine</shortdesc>
+ </parameter>
+ <parameter name="username" unique="0" required="0" obsoletes="login">
+ <getopt mixed="-l, --username=[name]" />
+ <content type="string" />
+ <shortdesc lang="en">Login name</shortdesc>
+ </parameter>
+ <parameter name="quiet" unique="0" required="0">
+ <getopt mixed="-q, --quiet" />
+ <content type="boolean" />
+ <shortdesc lang="en">Disable logging to stderr. Does not affect --verbose or --debug-file or logging to syslog.</shortdesc>
+ </parameter>
+ <parameter name="verbose" unique="0" required="0">
+ <getopt mixed="-v, --verbose" />
+ <content type="boolean" />
+ <shortdesc lang="en">Verbose mode. Multiple -v flags can be stacked on the command line (e.g., -vvv) to increase verbosity.</shortdesc>
+ </parameter>
+ <parameter name="verbose_level" unique="0" required="0">
+ <getopt mixed="--verbose-level" />
+ <content type="integer" />
+ <shortdesc lang="en">Level of debugging detail in output. Defaults to the number of --verbose flags specified on the command line, or to 1 if verbose=1 in a stonith device configuration (i.e., on stdin).</shortdesc>
+ </parameter>
+ <parameter name="debug" unique="0" required="0" deprecated="1">
+ <getopt mixed="-D, --debug-file=[debugfile]" />
+ <content type="string" />
+ <shortdesc lang="en">Write debug information to given file</shortdesc>
+ </parameter>
+ <parameter name="debug_file" unique="0" required="0" obsoletes="debug">
+ <getopt mixed="-D, --debug-file=[debugfile]" />
+ <shortdesc lang="en">Write debug information to given file</shortdesc>
+ </parameter>
+ <parameter name="version" unique="0" required="0">
+ <getopt mixed="-V, --version" />
+ <content type="boolean" />
+ <shortdesc lang="en">Display version information and exit</shortdesc>
+ </parameter>
+ <parameter name="help" unique="0" required="0">
+ <getopt mixed="-h, --help" />
+ <content type="boolean" />
+ <shortdesc lang="en">Display help and exit</shortdesc>
+ </parameter>
+ <parameter name="plug_separator" unique="0" required="0">
+ <getopt mixed="--plug-separator=[char]" />
+ <content type="string" default="," />
+ <shortdesc lang="en">Separator for plug parameter when specifying more than 1 plug</shortdesc>
+ </parameter>
+ <parameter name="separator" unique="0" required="0">
+ <getopt mixed="-C, --separator=[char]" />
+ <content type="string" default="," />
+ <shortdesc lang="en">Separator for CSV created by 'list' operation</shortdesc>
+ </parameter>
+ <parameter name="delay" unique="0" required="0">
+ <getopt mixed="--delay=[seconds]" />
+ <content type="second" default="0" />
+ <shortdesc lang="en">Wait X seconds before fencing is started</shortdesc>
+ </parameter>
+ <parameter name="disable_timeout" unique="0" required="0">
+ <getopt mixed="--disable-timeout=[true/false]" />
+ <content type="string" />
+ <shortdesc lang="en">Disable timeout (true/false) (default: true when run from Pacemaker 2.0+)</shortdesc>
+ </parameter>
+ <parameter name="login_timeout" unique="0" required="0">
+ <getopt mixed="--login-timeout=[seconds]" />
+ <content type="second" default="5" />
+ <shortdesc lang="en">Wait X seconds for cmd prompt after login</shortdesc>
+ </parameter>
+ <parameter name="power_timeout" unique="0" required="0">
+ <getopt mixed="--power-timeout=[seconds]" />
+ <content type="second" default="20" />
+ <shortdesc lang="en">Test X seconds for status change after ON/OFF</shortdesc>
+ </parameter>
+ <parameter name="power_wait" unique="0" required="0">
+ <getopt mixed="--power-wait=[seconds]" />
+ <content type="second" default="0" />
+ <shortdesc lang="en">Wait X seconds after issuing ON/OFF</shortdesc>
+ </parameter>
+ <parameter name="shell_timeout" unique="0" required="0">
+ <getopt mixed="--shell-timeout=[seconds]" />
+ <content type="second" default="3" />
+ <shortdesc lang="en">Wait X seconds for cmd prompt after issuing command</shortdesc>
+ </parameter>
+ <parameter name="stonith_status_sleep" unique="0" required="0">
+ <getopt mixed="--stonith-status-sleep=[seconds]" />
+ <content type="second" default="1" />
+ <shortdesc lang="en">Sleep X seconds between status calls during a STONITH action</shortdesc>
+ </parameter>
+ <parameter name="retry_on" unique="0" required="0">
+ <getopt mixed="--retry-on=[attempts]" />
+ <content type="integer" default="1" />
+ <shortdesc lang="en">Count of attempts to retry power on</shortdesc>
+ </parameter>
+</parameters>
+<actions>
+ <action name="on" automatic="0"/>
+ <action name="off" />
+ <action name="reboot" />
+ <action name="status" />
+ <action name="list" />
+ <action name="list-status" />
+ <action name="monitor" />
+ <action name="metadata" />
+ <action name="manpage" />
+ <action name="validate-all" />
+</actions>
+</resource-agent>

View File

@ -1,4 +0,0 @@
azure-mgmt-compute
azure-mgmt-network
azure-identity
msrestazure

View File

@ -87,7 +87,7 @@
Name: fence-agents
Summary: Set of unified programs capable of host isolation ("fencing")
Version: 4.2.1
Release: 129%{?alphatag:.%{alphatag}}%{?dist}.7
Release: 129%{?alphatag:.%{alphatag}}%{?dist}
License: GPLv2+ and LGPLv2+
Group: System Environment/Base
URL: https://github.com/ClusterLabs/fence-agents
@ -133,40 +133,10 @@ Source30: %{reqstsoauthlib}-%{reqstsoauthlib_version}.tar.gz
Source31: %{oauthlib}-%{oauthlib_version}.tar.gz
Source32: %{ruamelyaml}-%{ruamelyaml_version}.tar.gz
Source33: %{setuptools}-%{setuptools_version}.tar.gz
# azure
Source34: requirements-azure.txt
Source35: azure-common-1.1.28.zip
Source36: azure-core-1.24.2.zip
Source37: azure-mgmt-compute-27.2.0.zip
Source38: azure-mgmt-core-1.3.2.zip
Source39: azure-mgmt-network-20.0.0.zip
Source40: azure-identity-1.10.0.zip
Source41: isodate-0.6.1.tar.gz
Source42: msrest-0.7.1.zip
Source43: oauthlib-3.2.2.tar.gz
Source44: PyJWT-2.4.0.tar.gz
Source45: requests-2.27.1.tar.gz
Source46: requests-oauthlib-2.0.0.tar.gz
Source47: msal-1.27.0.tar.gz
Source48: msal-extensions-1.0.0.tar.gz
Source49: portalocker-2.7.0.tar.gz
Source50: cryptography-3.3.2.tar.gz
Source51: cffi-1.15.1.tar.gz
Source52: typing_extensions-4.1.1.tar.gz
## msrestazure specific
Source54: msrestazure-0.6.4.tar.gz
Source55: adal-1.2.7.tar.gz
## required for installation
Source100: setuptools_scm-6.4.2.tar.gz
Source101: packaging-21.2-py3-none-any.whl
Source102: tomli-1.1.0.tar.gz
Source103: pycparser-2.20.tar.gz
Source104: wheel-0.37.1.tar.gz
Source105: pip-21.3.1.tar.gz
## azure
Source106: flit_core-3.10.1.tar.gz
## msrestazure
Source107: poetry-core-1.0.8.tar.gz
Source34: setuptools_scm-6.3.2.tar.gz
Source35: packaging-21.2-py3-none-any.whl
Source36: tomli-1.0.1.tar.gz
### END
Patch0: fence_impilan-fence_ilo_ssh-add-ilo5-support.patch
@ -312,20 +282,13 @@ Patch139: RHEL-5397-fence_scsi-2-fix-ISID-reg-handling-off.patch
Patch140: RHEL-5397-fence_scsi-3-fix-run_cmd.patch
Patch141: RHEL-5397-4-fence_scsi-log-err.patch
Patch142: RHEL-14343-fence_zvmip-2-fix-manpage-formatting.patch
Patch143: RHEL-7734-fence_eps-add-fence_epsr2-for-ePowerSwitch-R2-and-newer.patch
Patch144: RHEL-56840-fence_scsi-only-preempt-once-for-mpath-devices.patch
Patch145: RHEL-76492-fence_azure_arm-use-azure-identity.patch
### HA support libs/utils ###
# all archs
Patch1000: bz2218234-1-kubevirt-fix-bundled-dateutil-CVE-2007-4559.patch
Patch1001: RHEL-22174-kubevirt-fix-bundled-jinja2-CVE-2024-22195.patch
Patch1002: RHEL-35655-kubevirt-fix-bundled-jinja2-CVE-2024-34064.patch
Patch1003: RHEL-43568-1-kubevirt-fix-bundled-urllib3-CVE-2024-37891.patch
Patch1004: RHEL-50223-setuptools-fix-CVE-2024-6345.patch
# cloud (x86_64 only)
Patch2000: bz2218234-2-aws-fix-bundled-dateutil-CVE-2007-4559.patch
Patch2001: RHEL-43568-2-aws-fix-bundled-urllib3-CVE-2024-37891.patch
%if 0%{?fedora} || 0%{?rhel} > 7
%global supportedagents amt_ws apc apc_snmp bladecenter brocade cisco_mds cisco_ucs compute drac5 eaton_snmp emerson eps evacuate hds_cb hpblade ibmblade ibm_powervs ibm_vpc ifmib ilo ilo_moonshot ilo_mp ilo_ssh intelmodular ipdu ipmilan kdump kubevirt lpar mpath redfish rhevm rsa rsb sbd scsi vmware_rest vmware_soap wti
@ -391,7 +354,7 @@ BuildRequires: libxslt
## establishing proper paths to particular programs
BuildRequires: gnutls-utils
## Python dependencies
BuildRequires: python3-devel python3-pycparser libffi-devel openssl-devel
BuildRequires: python3-devel
BuildRequires: python3-pexpect python3-pycurl python3-requests
BuildRequires: python3-suds openwsman-python3 python3-boto3
BuildRequires: python3-google-api-client python3-pip python3-wheel python3-jinja2
@ -546,9 +509,6 @@ BuildRequires: python3-google-api-client python3-pip python3-wheel python3-jinja
%patch -p1 -P 140
%patch -p1 -P 141
%patch -p1 -P 142
%patch -p1 -P 143 -F1
%patch -p1 -P 144
%patch -p1 -P 145
# prevent compilation of something that won't get used anyway
sed -i.orig 's|FENCE_ZVM=1|FENCE_ZVM=0|' configure.ac
@ -648,33 +608,24 @@ popd
# aws/kubevirt
%{__python3} -m pip install --user --no-index --find-links %{_sourcedir} setuptools-scm
# kubevirt
%{__python3} -m pip install --target %{buildroot}/usr/lib/fence-agents/%{bundled_lib_dir}/kubevirt --no-index --find-links %{_sourcedir} openshift
rm -rf %{buildroot}/usr/lib/fence-agents/%{bundled_lib_dir}/kubevirt/rsa*
%ifarch x86_64
# aws
%ifarch x86_64
%{__python3} -m pip install --user --no-index --find-links %{_sourcedir} jmespath
%{__python3} -m pip install --target %{buildroot}/usr/lib/fence-agents/%{bundled_lib_dir}/aws --no-index --find-links %{_sourcedir} botocore
%{__python3} -m pip install --target %{buildroot}/usr/lib/fence-agents/%{bundled_lib_dir}/aws --no-index --find-links %{_sourcedir} requests
# azure
%{__python3} -m pip install --user --upgrade --no-index --find-links %{_sourcedir} pip setuptools
%{__python3} -m pip install --target %{buildroot}/usr/lib/fence-agents/%{bundled_lib_dir}/azure --no-index --find-links %{_sourcedir} -r %{_sourcedir}/requirements-azure.txt
%endif
# kubevirt
%{__python3} -m pip install --target %{buildroot}/usr/lib/fence-agents/%{bundled_lib_dir}/kubevirt --no-index --find-links %{_sourcedir} openshift
rm -rf %{buildroot}/usr/lib/fence-agents/%{bundled_lib_dir}/kubevirt/rsa*
# regular patch doesnt work in build-section
pushd %{buildroot}/usr/lib/fence-agents/%{bundled_lib_dir}
/usr/bin/patch --no-backup-if-mismatch -p1 --fuzz=0 < %{PATCH1000}
/usr/bin/patch --no-backup-if-mismatch -p1 --fuzz=1 < %{PATCH1001}
/usr/bin/patch --no-backup-if-mismatch -p1 --fuzz=1 < %{PATCH1002}
/usr/bin/patch --no-backup-if-mismatch -p1 --fuzz=2 < %{PATCH1003}
/usr/bin/patch --no-backup-if-mismatch -p1 --fuzz=0 < %{PATCH1004}
%ifarch x86_64
/usr/bin/patch --no-backup-if-mismatch -p1 --fuzz=0 < %{PATCH2000}
/usr/bin/patch --no-backup-if-mismatch -p1 --fuzz=2 < %{PATCH2001}
%endif
popd
@ -859,41 +810,13 @@ Fence agent for Amazon AWS instances.
%ifarch x86_64
%package azure-arm
License: GPLv2+ and LGPLv2+ and MIT and MPL-2.0 and Apache-2.0 and BSD and PSF-2.0 and BSD-3-Clause and ISC
License: GPLv2+ and LGPLv2+
Group: System Environment/Base
Summary: Fence agent for Azure Resource Manager
Requires: fence-agents-common >= %{version}-%{release}
# azure
Provides: bundled(python3-adal) = 1.2.7
Provides: bundled(python3-azure-common) = 1.1.28
Provides: bundled(python3-azure-core) = 1.24.2
Provides: bundled(python3-azure-identity) = 1.10.0
Provides: bundled(python3-azure-mgmt-compute) = 27.2.0
Provides: bundled(python3-azure-mgmt-core) = 1.3.2
Provides: bundled(python3-azure-mgmt-network) = 20.0.0
Provides: bundled(python3-certifi) = 2023.7.22
Provides: bundled(python3-cffi) = 1.15.1
Provides: bundled(python3-charset-normalizer) = 2.0.7
Provides: bundled(python3-cryptography) = 3.3.2
Provides: bundled(python3-%{dateutil}) = %{dateutil_version}
Provides: bundled(python3-%{idna}) = %{idna_version}
Provides: bundled(python3-isodate) = 0.6.1
Provides: bundled(python3-msal) = 1.27.0
Provides: bundled(python3-msal-extensions) = 1.0.0
Provides: bundled(python3-msrest) = 0.7.1
Provides: bundled(python3-msrestazure) = 0.6.4
Provides: bundled(python3-oauthlib) = 3.2.2
Provides: bundled(python3-portalocker) = 2.7.0
Provides: bundled(python3-pycparser) = 2.20
Provides: bundled(python3-PyJWT) = 2.4.0
Provides: bundled(python3-requests) = 2.27.1
Provides: bundled(python3-requests-oauthlib) = 2.0.0
Provides: bundled(python3-six) = 1.16.0
Provides: bundled(python3-typing-extensions) = 4.1.1
Provides: bundled(python3-urllib3) = 1.26.18
Requires: python3-azure-sdk >= 4.0.0-9
Obsoletes: %{name} < %{version}-%{release}
Provides: python3-azure-sdk = 4.0.0-10
Obsoletes: python3-azure-sdk < 4.0.0-10
BuildArch: noarch
%description azure-arm
Fence agent for Azure Resource Manager instances.
%files azure-arm
@ -901,8 +824,6 @@ Fence agent for Azure Resource Manager instances.
%{_datadir}/fence/azure_fence.py*
%{_datadir}/fence/__pycache__/azure_fence.*
%{_mandir}/man8/fence_azure_arm.8*
# bundled libraries
/usr/lib/fence-agents/%{bundled_lib_dir}/azure
%endif
%package bladecenter
@ -1056,8 +977,8 @@ BuildArch: noarch
Fence agent for ePowerSwitch 8M+ power switches that are accessed
via the HTTP(s) protocol.
%files eps
%{_sbindir}/fence_eps*
%{_mandir}/man8/fence_eps*.8*
%{_sbindir}/fence_eps
%{_mandir}/man8/fence_eps.8*
%ifarch x86_64
%package gce
@ -1595,30 +1516,6 @@ Fence agent for IBM z/VM over IP.
%endif
%changelog
* Thu Jan 30 2025 Oyvind Albrigtsen <oalbrigt@redhat.com> - 4.2.1-129.7
- fence_azure_arm: use azure-identity instead of msrestazure, which has
been deprecated
Resolves: RHEL-76492
* Tue Sep 24 2024 Oyvind Albrigtsen <oalbrigt@redhat.com> - 4.2.1-129.5
- fence_scsi: preempt clears all devices on the mpath device, so only
run it for the first device
Resolves: RHEL-56840
* Wed Jul 24 2024 Oyvind Albrigtsen <oalbrigt@redhat.com> - 4.2.1-129.4
- bundled setuptools: fix CVE-2024-6345
Resolves: RHEL-50223
* Tue Jun 25 2024 Oyvind Albrigtsen <oalbrigt@redhat.com> - 4.2.1-129.3
- bundled urllib3: fix CVE-2024-37891
Resolves: RHEL-43568
* Thu May 30 2024 Oyvind Albrigtsen <oalbrigt@redhat.com> - 4.2.1-129.2
- fence_eps: add fence_epsr2 for ePowerSwitch R2 and newer
Resolves: RHEL-7734
- bundled jinja2: fix CVE-2024-34064
Resolves: RHEL-35655
* Fri Jan 19 2024 Oyvind Albrigtsen <oalbrigt@redhat.com> - 4.2.1-129
- bundled urllib3: fix CVE-2023-45803
Resolves: RHEL-18132