9 Commits

Author SHA1 Message Date
patrick 856fa7eb4c check-snapshot-age aktualisiert 2026-02-12 20:38:17 +01:00
patrick d50d3e02ed check-snapshot-age aktualisiert 2026-02-12 14:15:00 +01:00
patrick 0016fb8e3b Dateien nach "/" hochladen 2025-11-06 22:51:29 +01:00
patrick 324b19ff09 4.13 2025-07-20 21:58:16 +02:00
patrick 6a1b6a27cf check-snapshot-age aktualisiert
fix which zfs
2025-07-01 01:41:25 +02:00
patrick a09317b44a check-snapshot-age aktualisiert 2025-05-15 11:15:15 +02:00
patrick 412a576ccd check-snapshot-age aktualisiert
Erweiterung Filter nach Dataset oder Volums
2025-05-15 11:12:29 +02:00
Chriz bf46208c4d 4.11
Individual Exlude
2024-03-26 14:06:51 +01:00
Thorsten Spille ae5a89a21b Merge pull request #6 from bashclub/testing
v4.09
2023-05-26 21:38:36 +02:00
2 changed files with 56 additions and 20 deletions
+44 -11
View File
@@ -3,35 +3,68 @@
import subprocess import subprocess
import re import re
import time import time
import argparse
#_snapshots = open("zfs.txt","r").read() # Argumente verarbeiten
_snapshots = subprocess.check_output("/usr/sbin/zfs list -t snapshot -Hpo name,creation".split()) parser = argparse.ArgumentParser(description="ZFS Snapshot Übersicht")
parser.add_argument("--filter", help="Nur bestimmte Datasets anzeigen (Regex möglich, z.B. 'rpool/ROOT')", type=str)
args = parser.parse_args()
# Snapshots abrufen
_snapshots = subprocess.check_output(["zfs", "list", "-t", "snapshot", "-Hpo", "name,creation"],encoding="utf-8")
LABELS=("frequent","hourly","daily","weekly","monthly","yearly","backup-zfs","bashclub-zfs")
RE_LABELSEARCH = re.compile("|".join(LABELS))
_datasets = {} _datasets = {}
for _datastore,_snapshot,_creation in re.findall("^([\w_./-]+)@([\w_.-]+)\t(\d+)",_snapshots.decode('utf-8'),re.M):
# Snapshots parsen
for _datastore, _snapshot, _creation in re.findall(
r"^([\w_./-]+)@([\w_.:-]+)\t(\d+)",
_snapshots,
re.M):
if args.filter and not re.search(args.filter, _datastore):
continue
if _datastore not in _datasets: if _datastore not in _datasets:
_datasets[_datastore] = {} _datasets[_datastore] = {}
_label = RE_LABELSEARCH.search(_snapshot)
if _label: # -------------------------------------------------
_label = _label.group(0) # Snapshot-Typ automatisch erkennen
# -------------------------------------------------
if _snapshot.startswith("zfs-auto-snap_"):
m = re.match(r"zfs-auto-snap_([^-\s]+)-", _snapshot)
_label = m.group(1) if m else "zfs-auto-snap"
elif re.match(r"^[^_]+_\d{4}-\d{2}-\d{2}", _snapshot):
# Beispiel: bashclub-zfs_2025-09-05_06:25:24
_label = _snapshot.split("_")[0]
else: else:
_label = "other" # Fallback → alles vor erstem Datum abschneiden
_label = re.sub(r'[-_]\d{4}-\d{2}-\d{2}.*$', '', _snapshot)
# -------------------------------------------------
if _label not in _datasets[_datastore]: if _label not in _datasets[_datastore]:
_datasets[_datastore][_label] = [] _datasets[_datastore][_label] = []
_datasets[_datastore][_label].append((_snapshot, int(_creation))) _datasets[_datastore][_label].append((_snapshot, int(_creation)))
for _datastore in _datasets.keys(): # Ergebnisse anzeigen
for _datastore in _datasets:
print(_datastore) print(_datastore)
print("-" * 40) print("-" * 40)
for _label in _datasets[_datastore].keys():
for _label in sorted(_datasets[_datastore]):
_data = _datasets[_datastore][_label] _data = _datasets[_datastore][_label]
_data.sort(key=lambda x: x[1])
_first = time.strftime("%d.%m.%Y %H:%M:%S", time.localtime(_data[0][1])) _first = time.strftime("%d.%m.%Y %H:%M:%S", time.localtime(_data[0][1]))
_last = time.strftime("%d.%m.%Y %H:%M:%S", time.localtime(_data[-1][1])) _last = time.strftime("%d.%m.%Y %H:%M:%S", time.localtime(_data[-1][1]))
_count = len(_data) _count = len(_data)
print(f" {_label} {_count}") print(f" {_label} {_count}")
print(f" {_first} {_data[0][0]}") print(f" {_first} {_data[0][0]}")
if _count > 1: if _count > 1:
print(f" {_last} {_data[-1][0]}") print(f" {_last} {_data[-1][0]}")
print("") print("")
+8 -5
View File
@@ -16,7 +16,7 @@
## GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ## GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
## LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ## LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
VERSION = "4.12" VERSION = 4.14
### for check_mk usage link or copy binary to check_mk_agent/local/checkzfs ### for check_mk usage link or copy binary to check_mk_agent/local/checkzfs
### create /etc/check_mk/checkzfs ## the config file name matches the filename in check_mk_agent/local/ ### create /etc/check_mk/checkzfs ## the config file name matches the filename in check_mk_agent/local/
@@ -227,7 +227,7 @@ class negative_regex_class(object):
return not self.regex.search(text) return not self.regex.search(text)
class zfscheck(object): class zfscheck(object):
ZFSLIST_REGEX = re.compile("^(?P<dataset>.*?)(?:|@(?P<snapshot>.*?))\t(?P<type>\w*)\t(?P<creation>\d+)\t(?P<guid>\d+)\t(?P<used>\d+|-)\t(?P<available>\d+|-)\t(?P<written>\d+|-)\t(?P<origin>.*?)\t(?P<autosnapshot>[-\w]+)\t(?P<checkzfs>[-\w]+)$",re.M) ZFSLIST_REGEX = re.compile(r"^(?P<dataset>.*?)(?:|@(?P<snapshot>.*?))\t(?P<type>\w*)\t(?P<creation>\d+)\t(?P<guid>\d+)\t(?P<used>\d+|-)\t(?P<available>\d+|-)\t(?P<written>\d+|-)\t(?P<origin>.*?)\t(?P<autosnapshot>[-\w]+)\t(?P<checkzfs>[-\w]+)$",re.M)
ZFS_DATASETS = {} ZFS_DATASETS = {}
ZFS_SNAPSHOTS = {} ZFS_SNAPSHOTS = {}
#VALIDCOLUMNS = ["source","replica","type","autosnap","snapshot","creation","guid","used","referenced","size","age","status","message"] ## valid columns #VALIDCOLUMNS = ["source","replica","type","autosnap","snapshot","creation","guid","used","referenced","size","age","status","message"] ## valid columns
@@ -708,7 +708,7 @@ class zfscheck(object):
if not _email: if not _email:
_users = open("/etc/pve/user.cfg","rt").read() _users = open("/etc/pve/user.cfg","rt").read()
_email = "root@{0}".format(_hostname) _email = "root@{0}".format(_hostname)
_emailmatch = re.search("^user:root@pam:.*?:(?P<mail>[\w.]+@[\w.]+):.*?$",_users,re.M) _emailmatch = re.search(r"^user:root@pam:.*?:(?P<mail>[\w.]+@[\w.]+):.*?$",_users,re.M)
if _emailmatch: if _emailmatch:
_email = _emailmatch.group(1) _email = _emailmatch.group(1)
#raise Exception("No PVE User Email found") #raise Exception("No PVE User Email found")
@@ -798,7 +798,7 @@ if __name__ == "__main__":
args = _parser.parse_args() args = _parser.parse_args()
CONFIG_KEYS="disabled|source|sourceonly|piggyback|remote|legacyhosts|prefix|filter|replicafilter|threshold|ignoreattr|maxsnapshots|snapshotfilter|ssh-identity|ssh-extra-options" CONFIG_KEYS="disabled|source|sourceonly|piggyback|remote|legacyhosts|prefix|filter|replicafilter|threshold|ignoreattr|maxsnapshots|snapshotfilter|ssh-identity|ssh-extra-options"
_config_regex = re.compile(f"^({CONFIG_KEYS}):\s*(.*?)(?:\s+#|$)",re.M) _config_regex = re.compile(rf"^({CONFIG_KEYS}):\s*(.*?)(?:\s+#|$)",re.M)
_basename = os.path.basename(__file__).split(".")[0] ## name für config ermitteln aufgrund des script namens _basename = os.path.basename(__file__).split(".")[0] ## name für config ermitteln aufgrund des script namens
#_is_checkmk_plugin = os.path.dirname(os.path.abspath(__file__)).find("/check_mk_agent/local") > -1 ## wenn im check_mk ordner #_is_checkmk_plugin = os.path.dirname(os.path.abspath(__file__)).find("/check_mk_agent/local") > -1 ## wenn im check_mk ordner
#if _is_checkmk_plugin: #if _is_checkmk_plugin:
@@ -863,7 +863,7 @@ if __name__ == "__main__":
_github_version = _github_req.json() _github_version = _github_req.json()
_github_last_modified = datetime.strptime(_github_req.headers.get("last-modified"),"%a, %d %b %Y %X %Z") _github_last_modified = datetime.strptime(_github_req.headers.get("last-modified"),"%a, %d %b %Y %X %Z")
_new_script = base64.b64decode(_github_version.get("content")).decode("utf-8") _new_script = base64.b64decode(_github_version.get("content")).decode("utf-8")
_new_version = re.findall("^VERSION\s*=\s*([0-9.]*)",_new_script,re.M) _new_version = re.findall(r"^VERSION\s*=[\s\x22]*([0-9.]*)",_new_script,re.M)
_new_version = _new_version[0] if _new_version else "0.0.0" _new_version = _new_version[0] if _new_version else "0.0.0"
_script_location = os.path.realpath(__file__) _script_location = os.path.realpath(__file__)
_current_last_modified = datetime.fromtimestamp(int(os.path.getmtime(_script_location))) _current_last_modified = datetime.fromtimestamp(int(os.path.getmtime(_script_location)))
@@ -871,6 +871,8 @@ if __name__ == "__main__":
_content = _f.read() _content = _f.read()
_current_sha = hashlib.sha1(f"blob {len(_content)}\0".encode("utf-8") + _content).hexdigest() _current_sha = hashlib.sha1(f"blob {len(_content)}\0".encode("utf-8") + _content).hexdigest()
_content = _content.decode("utf-8") _content = _content.decode("utf-8")
if type(VERSION) != str:
VERSION = str(VERSION)
if _current_sha == _github_version.get("sha"): if _current_sha == _github_version.get("sha"):
print(f"allready up to date {_current_sha}") print(f"allready up to date {_current_sha}")
sys.exit(0) sys.exit(0)
@@ -915,3 +917,4 @@ if __name__ == "__main__":
if args.debug: if args.debug:
raise raise
sys.exit(1) sys.exit(1)