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

feat: global refactoring #54

Open
wants to merge 34 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
cebc733
feat: first refactoring
djerfy Jan 10, 2024
1a456a0
feat: improve logging
djerfy Jan 10, 2024
f249b36
feat: use enable/disable functions
djerfy Jan 10, 2024
ceda038
misc: remove useless comments
djerfy Jan 10, 2024
7c72a5c
fix: match include/exclude labels from list
djerfy Jan 10, 2024
3895da8
misc: remove empty line
djerfy Jan 10, 2024
eeb7e24
feat: use threading for parallels execution
djerfy Jan 10, 2024
32fb86d
feat: upgrade dependencies
djerfy Jan 10, 2024
f353a0e
feat: set final values of schedule
djerfy Jan 10, 2024
ffb7ec6
feat: prepare modules integration
djerfy Jan 10, 2024
eb398ef
fix: openebs syntax
djerfy Jan 10, 2024
c7cfcc0
fix: openebs syntax
djerfy Jan 10, 2024
709c349
fix: syntax if not labels founds
djerfy Jan 10, 2024
038ae86
misc: return empty list if engine isn't cstor
djerfy Jan 10, 2024
9939798
feat(openebs): cstorpoolinstances integration
djerfy Jan 10, 2024
e50380d
feat(openebs): fix names of files
djerfy Jan 10, 2024
f635595
feat(openebs): fix syntax
djerfy Jan 10, 2024
972a77e
feat: review threading and fix memory leak
djerfy Jan 11, 2024
9af31bc
fix: job queue execution
djerfy Jan 11, 2024
4755b8b
feat: improve logging and add logger
djerfy Jan 11, 2024
47a4263
feat: cleanup config
djerfy Jan 11, 2024
3831a54
feat: improve memory overview
djerfy Jan 11, 2024
a6e4447
feat: improve loglevel config
djerfy Jan 11, 2024
1c78b65
feat: replace py-zabbix by zappix and global review
djerfy Jan 11, 2024
8793871
fix: labels parsing
djerfy Jan 11, 2024
da922b2
fix: sender list
djerfy Jan 11, 2024
d959832
fix: zabbix sender from list
djerfy Jan 11, 2024
f8f9881
misc: improve sender configuration
djerfy Jan 11, 2024
51ccf6c
fix: labels items parser
djerfy Jan 11, 2024
35837b3
fix: openebs match labels
djerfy Jan 11, 2024
f3576da
fix: discovery list syntax
djerfy Jan 11, 2024
a3003af
fix: discovery list syntax
djerfy Jan 11, 2024
d7c5e31
misc: rename zabbix objects
djerfy Jan 12, 2024
c3ed0cc
fix: objects exception if not exists
djerfy Jan 13, 2024
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
14 changes: 1 addition & 13 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,6 @@ LABEL description="Zabbix Kubernetes Discovery" \

WORKDIR /app

ENV ZABBIX_ENDPOINT=""
ENV KUBERNETES_NAME=""

ARG CONTAINER_USER="zabbix"
ARG CONTAINER_GROUP="zabbix"

Expand All @@ -17,18 +14,9 @@ RUN apt-get update && \
apt-get install -y --no-install-recommends curl iputils-ping python3 python3-pip && \
rm -rf /var/lib/apt/lists && \
mkdir -p /app /root/.kube && \
touch /app/crontab && \
groupadd -g 2000 ${CONTAINER_GROUP} && \
useradd -u 2000 -d /app -s /bin/bash -M -g ${CONTAINER_GROUP} ${CONTAINER_USER}

ARG SUPERCRONIC_VER="0.2.28"
ARG SUPERCRONIC_SHA="fe1a81a8a5809deebebbd7a209a3b97e542e2bcd"

RUN curl -fsSLO "https://github.com/aptible/supercronic/releases/download/v${SUPERCRONIC_VER}/supercronic-linux-amd64" && \
echo "${SUPERCRONIC_SHA} supercronic-linux-amd64" | sha1sum -c - && \
chmod +x supercronic-linux-amd64 && \
mv supercronic-linux-amd64 /usr/local/bin/supercronic

COPY ./src/ /app/

RUN chown ${CONTAINER_USER}:${CONTAINER_GROUP} -R /app && \
Expand All @@ -37,4 +25,4 @@ RUN chown ${CONTAINER_USER}:${CONTAINER_GROUP} -R /app && \

USER ${CONTAINER_USER}:${CONTAINER_GROUP}

CMD ["/usr/local/bin/supercronic", "-split-logs", "-json", "/app/crontab"]
CMD ["/usr/bin/python3", "/app/zabbix-kubernetes-discovery.py"]
75 changes: 75 additions & 0 deletions src/config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
output:
level: INFO

kubernetes:
name: localhost

zabbix:
endpoint: localhost
timeout: 10
schedule:
discovery: 3600
items: 3

monitoring:
# base
nodes:
enabled: True
labels:
include: []
exclude: []
daemonsets:
enabled: False
labels:
include: []
exclude: []
volumes:
enabled: False
labels:
include: []
exclude: []
deployments:
enabled: False
labels:
include: []
exclude: []
statefulsets:
enabled: False
labels:
include: []
exclude: []
cronjobs:
enabled: False
labels:
include: []
exclude: []
ingresses:
enabled: False
labels:
include: []
exclude: []
# openebs
openebs:
enabled: False
engine: cstor
labels:
include: []
exclude: []
# velero
velero:
enabled: False
labels:
include: []
exclude: []
# trivy
trivy:
enabled: False
labels:
include: []
exclude: []
# certificates
certs:
enabled: False
labels:
include: []
exclude: []
55 changes: 20 additions & 35 deletions src/modules/common/functions.py
Original file line number Diff line number Diff line change
@@ -1,48 +1,33 @@
import re
import json

def ifObjectMatch(object_list=None, object_name=None):
def matchLabels(match_labels=None, object_labels=None):
"""
description: check if the object is in list
description: check if the object match labels
return: bool
"""
if object_list is None or object_list == "" or object_list == "*":
return False
for i in [match_labels, object_labels]:
if i is None or i == [] or i == "" or i == "*":
return False

if object_name is None or object_name == "" or object_name == "*":
return False

if type(object_list) == str:
object_list = object_list.split(",")

if type(object_list) != list:
return False

reg_list = map(re.compile, object_list)
object_labels = str(object_labels).replace("{", "").replace("}", "").replace("'", "").replace(" ", "").split(",")

if any(reg.match(object_name) for reg in reg_list):
return True
for object_label in object_labels:
key, value = object_label.split(":")[0], object_label.split(":")[1]
for match_label in match_labels:
for separator in ["=", ":"]:
if match_label.split(separator)[0] == key and match_label.split(separator)[1] == value:
return True

return False

def ifLabelMatch(match_label=None, object_labels=None):
def rawObjects(data=[]):
"""
description: check if the object match a label
return: bool
description: get objects from raw api, convert items and return only objects
return: list
"""
if match_label is None or match_label == "" or match_label == "*":
return False

if object_labels is None or object_labels == "" or object_labels == "*":
return False

object_labels = str(object_labels).replace("{", "").replace("}", "").replace("'", "").replace(" ", "").split(",")

for label in object_labels:
k, v = label.split(":")[0], label.split(":")[1]

for separator in ["=", ":"]:
if match_label.split(separator)[0] == k and match_label.split(separator)[1] == v:
return True

return False
for key, value in data.items():
if key == "items":
return value

return []
Empty file.
6 changes: 6 additions & 0 deletions src/modules/kubernetes/base/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from modules.kubernetes.base.cronjobs import zabbixDiscoveryCronjobs, zabbixItemsCronjobs
from modules.kubernetes.base.daemonsets import zabbixDiscoveryDaemonsets, zabbixItemsDaemonsets
from modules.kubernetes.base.deployments import zabbixDiscoveryDeployments, zabbixItemsDeployments
from modules.kubernetes.base.nodes import zabbixDiscoveryNodes, zabbixItemsNodes
from modules.kubernetes.base.statefulsets import zabbixDiscoveryStatefulsets, zabbixItemsStatefulsets
from modules.kubernetes.base.volumes import zabbixDiscoveryVolumes, zabbixItemsVolumes
109 changes: 109 additions & 0 deletions src/modules/kubernetes/base/cronjobs.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
from kubernetes import client
from datetime import datetime
from modules.common.functions import *
import json, urllib3, logging

urllib3.disable_warnings()
logging = logging.getLogger("kubernetes.base.cronjobs")

def kubernetesGetCronjobs(config):
"""
description: get cronjobs data
return: list
"""
kubernetes = client.BatchV1Api()

cronjobs = []

for cronjob in kubernetes.list_cron_job_for_all_namespaces().items:
related_jobs, job_latest = [], {}

for job in kubernetes.list_job_for_all_namespaces().items:
if not job:
continue

if not job.metadata.owner_references:
continue

if not "CronJob" in job.metadata.owner_references[0].kind:
continue

if job.metadata.owner_references[0].name != cronjob.metadata.name:
continue

if job.status.active is not None:
continue

related_jobs.append(job)

for related_job in related_jobs:
if not bool(job_latest):
job_latest = related_job
continue

related_job_dt = datetime.timestamp(related_job.status.conditions[0].last_probe_time)
job_latest_dt = datetime.timestamp(job_latest.status.conditions[0].last_probe_time)

if related_job_dt > job_latest_dt:
job_latest = related_job

if type(job_latest) is dict:
continue

if job_latest.status.conditions[0].type == "Complete":
cronjob_status = "0"
else:
cronjob_status = "1"

json = {
"name": cronjob.metadata.name,
"namespace": cronjob.metadata.namespace,
"status": cronjob_status,
"last_job": {
"name": job_latest.metadata.name,
"reason": job_latest.status.conditions[0].reason,
"message": job_latest.status.conditions[0].message,
"status": job_latest.status.conditions[0].type
}
}

if hasattr(cronjob, 'metadata'):
if hasattr(cronjob.metadata, 'labels'):
if matchLabels(config['monitoring']['cronjobs']['labels']['exclude'], cronjob.metadata.labels):
continue
if config['monitoring']['cronjobs']['labels']['include'] != []:
if not matchLabels(config['monitoring']['cronjobs']['labels']['include'], cronjob.metadata.labels):
continue

cronjobs.append(json)

return cronjobs

def zabbixDiscoveryCronjobs(config):
"""
description: create a discovery for cronjob, per namespace
return: dict
"""
discovery = {"data":[]}

for cronjob in kubernetesGetCronjobs(config):
output = {
"{#KUBERNETES_BASE_CRONJOBS_NAMESPACE}": cronjob['namespace'],
"{#KUBERNETES_BASE_CRONJOBS_NAME}": cronjob['name']}
discovery['data'].append(output)

return [[config['kubernetes']['name'], "kubernetes.base.cronjobs.discovery", json.dumps(discovery)]]

def zabbixItemsCronjobs(config):
"""
description: create a item for cronjob, per namespace
return: list
"""
items = []

for cronjob in kubernetesGetCronjobs(config):
items.append([config['kubernetes']['name'], f"kubernetes.base.cronjobs.status[{cronjob['namespace']},{cronjob['name']}]", cronjob['status']])
items.append([config['kubernetes']['name'], f"kubernetes.base.cronjobs.reason[{cronjob['namespace']},{cronjob['name']}]", cronjob['last_job']['reason']])
items.append([config['kubernetes']['name'], f"kubernetes.base.cronjobs.message[{cronjob['namespace']},{cronjob['name']}]", cronjob['last_job']['message']])

return items
77 changes: 77 additions & 0 deletions src/modules/kubernetes/base/daemonsets.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
from kubernetes import client
from modules.common.functions import *
import json, urllib3, logging

urllib3.disable_warnings()
logging = logging.getLogger("kubernetes.base.daemonsets")

def kubernetesGetDaemonsets(config):
"""
description: get daemonsets data
return: list
"""
kubernetes = client.AppsV1Api()

daemonsets = []

for daemonset in kubernetes.list_daemon_set_for_all_namespaces().items:

json = {
"name": daemonset.metadata.name,
"namespace": daemonset.metadata.namespace,
"replicas": {
"desired": daemonset.status.desired_number_scheduled,
"current": daemonset.status.current_number_scheduled,
"available": daemonset.status.number_available,
"ready": daemonset.status.number_ready
}
}

for i in ["desired", "current", "available", "ready"]:
if json['replicas'][i] is None:
json['replicas'][i] = 0

if hasattr(daemonset, 'metadata'):
if hasattr(daemonset.metadata, 'labels'):
if matchLabels(config['monitoring']['daemonsets']['labels']['exclude'], daemonset.metadata.labels):
continue
if config['monitoring']['daemonsets']['labels']['include'] != []:
if not matchLabels(config['monitoring']['daemonsets']['labels']['include'], daemonset.metadata.labels):
continue

if any(d['name'] == json['name'] and d['namespace'] == json['namespace'] for d in daemonsets):
continue

daemonsets.append(json)

return daemonsets

def zabbixDiscoveryDaemonsets(config):
"""
description: create a discovery for daemonset, per namespace
return: dict
"""
discovery = {"data":[]}

for daemonset in kubernetesGetDaemonsets(config):
output = {
"{#KUBERNETES_BASE_DAEMONSETS_NAMESPACE}": daemonset['namespace'],
"{#KUBERNETES_BASE_DAEMONSETS_NAME}": daemonset['name']}
discovery['data'].append(output)

return [[config['kubernetes']['name'], "kubernetes.base.daemonsets.discovery", json.dumps(discovery)]]

def zabbixItemsDaemonsets(config):
"""
description: create a item for daemonset, per namespace
return: list
"""
items = []

for daemonset in kubernetesGetDaemonsets(config):
items.append([config['kubernetes']['name'], f"kubernetes.base.daemonsets.desiredReplicas[{daemonset['namespace']},{daemonset['name']}]", daemonset['replicas']['desired']])
items.append([config['kubernetes']['name'], f"kubernetes.base.daemonsets.currentReplicas[{daemonset['namespace']},{daemonset['name']}]", daemonset['replicas']['current']])
items.append([config['kubernetes']['name'], f"kubernetes.base.daemonsets.availableReplicas[{daemonset['namespace']},{daemonset['name']}]", daemonset['replicas']['available']])
items.append([config['kubernetes']['name'], f"kubernetes.base.daemonsets.readyReplicas[{daemonset['namespace']},{daemonset['name']}]", daemonset['replicas']['ready']])

return items
Loading