Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ARTESCA-11245 repair metalk8s monitoring salt module #4238

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,18 @@
Workload Plane/Control Plane CIDRs.
(PR[#4217](https://github.com/scality/metalk8s/pull/4217))

### Bug fixes

- Salt module metalk8s_monitoring fixed and improved
(PR[#4238](https://github.com/scality/metalk8s/pull/4238))

## Release 126.0.2

### Bug fixes

- [2137](https://github.com/scality/metalk8s/issues/2137) - Fix a bug
that prevents re-run of the bootstrap script if it fails at a specific point
(PR[4196](https://github.com/scality/metalk8s/pull/4196))
(PR[#4196](https://github.com/scality/metalk8s/pull/4196))

- Bump the attempts to wait for the Operator and ClusterConfig
to be Ready
Expand Down
59 changes: 57 additions & 2 deletions salt/_modules/metalk8s_kubernetes_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ def read_and_render_yaml_file(source, template, context=None, saltenv="base"):
return salt.utils.yaml.safe_load(contents)


def get_service_endpoints(service, namespace, kubeconfig):
def get_service_endpoints(service, namespace, **kwargs):
error_tpl = "Unable to get kubernetes endpoints for {} in namespace {}"

try:
Expand All @@ -159,7 +159,7 @@ def get_service_endpoints(service, namespace, kubeconfig):
kind="Endpoints",
apiVersion="v1",
namespace=namespace,
kubeconfig=kubeconfig,
**kwargs,
)
if not endpoint:
raise CommandExecutionError("Endpoint not found")
Expand All @@ -184,3 +184,58 @@ def get_service_endpoints(service, namespace, kubeconfig):
raise CommandExecutionError(error_tpl.format(service, namespace)) from exc

return result


def get_service_ips_and_ports(service, namespace, **kwargs):
try:
service_object = __salt__["metalk8s_kubernetes.get_object"](
name=service,
kind="Service",
apiVersion="v1",
namespace=namespace,
**kwargs,
)
if not service_object:
raise CommandExecutionError("Service not found")
except CommandExecutionError as exc:
raise CommandExecutionError(
f"Unable to get kubernetes service {service} in namespace {namespace}"
) from exc

cip = service_object["spec"].get("clusterIP")
cips = [cip] if cip else []
cips.extend(
[ip for ip in service_object["spec"].get("clusterIPs", []) if ip != cip]
)

try:
unamed = 0
ports = {}
service_ports = service_object["spec"]["ports"]

for port in service_ports:
if port.get("name"):
ports[port["name"]] = port["port"]
else:
ports[f"unnamed-{unamed}"] = port["port"]
unamed += 1

if not ports:
raise CommandExecutionError("No ports")
except (
AttributeError,
IndexError,
KeyError,
TypeError,
CommandExecutionError,
) as exc:
raise CommandExecutionError(
f"No ports for service {service} in namespace {namespace}",
) from exc

result = {}
if cips:
result["ips"] = cips
result["ports"] = ports

return result
40 changes: 21 additions & 19 deletions salt/_modules/metalk8s_monitoring.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

def __virtual__():
if MISSING_DEPS:
error_msg = "Missing dependencies: {}".format(", ".join(MISSING_DEPS))
error_msg = f"Missing dependencies: {', '.join(MISSING_DEPS)}"
return False, error_msg

return __virtualname__
Expand All @@ -33,7 +33,7 @@ def add_silence(
time_format="%Y-%m-%dT%H:%M:%S",
author="",
comment="",
**kwargs
**kwargs,
):
"""Add a new silence in Alertmanager.

Expand Down Expand Up @@ -106,9 +106,7 @@ def delete_silence(silence_id, **kwargs):
salt-call metalk8s_monitoring.delete_silence \
64d84a9e-cc6e-41ce-83ff-e84771ff6872
"""
_requests_alertmanager_api(
"api/v1/silence/{}".format(silence_id), "DELETE", **kwargs
)
_requests_alertmanager_api(f"api/v1/silence/{silence_id}", "DELETE", **kwargs)


def get_silences(state=None, **kwargs):
Expand Down Expand Up @@ -164,42 +162,46 @@ def get_alerts(state=None, **kwargs):


def _requests_alertmanager_api(route, method="GET", **kwargs):
endpoint = __salt__["metalk8s_kubernetes.get_service_endpoints"](
endpoints = __salt__["metalk8s_kubernetes.get_service_ips_and_ports"](
"prometheus-operator-alertmanager",
"metalk8s-monitoring",
kwargs.pop("kubeconfig", None),
**kwargs,
)

url = "http://{}:{}/{}".format(
endpoint["ip"],
endpoint["ports"]["web"],
route,
)
try:
ip = endpoints["ips"][0]
port = endpoints["ports"]["http-web"]
url = f"http://{ip}:{port}/{route}"
except (IndexError, KeyError) as exc:
raise CommandExecutionError(
"Unable to get proper Alertmanager API endpoint: "
f"Available endpoints: {endpoints}"
) from exc

try:
session = __utils__["metalk8s.requests_retry_session"]()
response = session.request(method, url, **kwargs)
except Exception as exc:
raise CommandExecutionError(
"Unable to query Alertmanager API on {}".format(url)
f"Unable to query Alertmanager API on {url}"
) from exc

try:
json = response.json()
except ValueError as exc:
if response.status_code != requests.codes.ok:
error = "Received HTTP code {} when querying Alertmanager API on {}".format(
response.status_code, url
error = (
f"Received HTTP code {response.status_code} when "
f"querying Alertmanager API on {url}"
)
else:
error = (
"Malformed response returned from Alertmanager API: {!s}: {}".format(
exc, response.text
)
"Malformed response returned from Alertmanager API: "
f"{exc}: {response.text}"
)
raise CommandExecutionError(error) from exc

if json["status"] == "error":
raise CommandExecutionError("{}: {}".format(json["errorType"], json["error"]))
raise CommandExecutionError(f"{json['errorType']}: {json['error']}")

return json.get("data")
2 changes: 1 addition & 1 deletion salt/_pillar/metalk8s_endpoints.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ def ext_pillar(minion_id, pillar, kubeconfig): # pylint: disable=unused-argumen
try:
service_endpoints = __salt__[
"metalk8s_kubernetes.get_service_endpoints"
](service, namespace, kubeconfig)
](service, namespace, kubeconfig=kubeconfig)
except CommandExecutionError as exc:
errors.append(str(exc))

Expand Down
129 changes: 129 additions & 0 deletions salt/tests/unit/modules/files/test_metalk8s_kubernetes_utils.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -278,3 +278,132 @@ get_service_endpoints:
subsets: null
raises: True
result: "Unable to get kubernetes endpoints for my_service in namespace my_namespace"

get_service_ips_and_ports:
# Multiples IPs and multiple ports
- obj:
spec:
clusterIPs:
- 10.0.0.1
- 10.0.0.2
clusterIP: 10.0.0.1
ports:
- name: http-web
port: 1234
- name: reloader-web
port: 1235
result:
ips:
- 10.0.0.1
- 10.0.0.2
ports:
http-web: 1234
reloader-web: 1235
TeddyAndrieux marked this conversation as resolved.
Show resolved Hide resolved
# ClusterIP not in clusterIPs and multiple ports
- obj:
spec:
clusterIPs:
- 10.0.0.2
- 10.0.0.3
clusterIP: 10.0.0.1
ports:
- name: http-web
port: 1234
- name: reloader-web
port: 1235
result:
ips:
- 10.0.0.1
- 10.0.0.2
- 10.0.0.3
ports:
http-web: 1234
reloader-web: 1235
# Single IP and multiple ports
- obj:
spec:
clusterIPs:
- 10.0.0.1
clusterIP: 10.0.0.1
ports:
- name: http-web
port: 2345
- name: reloader-web
port: 2346
result:
ips:
- 10.0.0.1
ports:
http-web: 2345
reloader-web: 2346
# Only clusterIP and multiple ports
- obj:
spec:
clusterIP: 10.0.0.1
ports:
- name: http-web
port: 2345
- name: reloader-web
port: 2346
result:
ips:
- 10.0.0.1
ports:
http-web: 2345
reloader-web: 2346
# No IPs and multiple ports
- obj:
spec:
ports:
- name: http-web
port: 1234
- name: reloader-web
port: 1235
result:
ports:
http-web: 1234
reloader-web: 1235
# Named and unnamed ports
- obj:
spec:
ports:
- name: http-web
port: 1234
- port: 1235
result:
ports:
http-web: 1234
unnamed-0: 1235
# Unnamed ports
- obj:
spec:
ports:
- port: 1234
- port: 1235
result:
ports:
unnamed-0: 1234
unnamed-1: 1235
# No ports
- obj:
spec:
ports: []
result: "No ports for service my_service in namespace my_namespace"
raises: True
# Empty spec
- obj:
spec: {}
result: "No ports for service my_service in namespace my_namespace"
raises: True
# Empty object returned
- obj: {}
result: "Unable to get kubernetes service my_service in namespace my_namespace"
raises: True
# Object is False
- obj: False
result: "Unable to get kubernetes service my_service in namespace my_namespace"
raises: True
# No object returned
- obj: null
result: "Unable to get kubernetes service my_service in namespace my_namespace"
raises: True
Loading
Loading