#!/usr/bin/env python3 # NodeInstance.py - Class implementing a PVC node in pvchealthd # Part of the Parallel Virtual Cluster (PVC) system # # Copyright (C) 2018-2024 Joshua M. Boniface # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # ############################################################################### class NodeInstance(object): # Initialization function def __init__( self, name, zkhandler, config, logger, ): # Passed-in variables on creation self.name = name self.zkhandler = zkhandler self.config = config self.logger = logger # States self.daemon_state = "stop" self.coordinator_state = "client" self.domain_state = "flushed" # Node resources self.health = 100 self.active_domains_count = 0 self.provisioned_domains_count = 0 self.memused = 0 self.memfree = 0 self.memalloc = 0 self.vcpualloc = 0 # Zookeeper handlers for changed states @self.zkhandler.zk_conn.DataWatch( self.zkhandler.schema.path("node.state.daemon", self.name) ) def watch_node_daemonstate(data, stat, event=""): if event and event.type == "DELETED": # The key has been deleted after existing before; terminate this watcher # because this class instance is about to be reaped in Daemon.py return False try: data = data.decode("ascii") except AttributeError: data = "stop" if data != self.daemon_state: self.daemon_state = data @self.zkhandler.zk_conn.DataWatch( self.zkhandler.schema.path("node.state.router", self.name) ) def watch_node_routerstate(data, stat, event=""): if event and event.type == "DELETED": # The key has been deleted after existing before; terminate this watcher # because this class instance is about to be reaped in Daemon.py return False try: data = data.decode("ascii") except AttributeError: data = "client" if data != self.coordinator_state: self.coordinator_state = data @self.zkhandler.zk_conn.DataWatch( self.zkhandler.schema.path("node.state.domain", self.name) ) def watch_node_domainstate(data, stat, event=""): if event and event.type == "DELETED": # The key has been deleted after existing before; terminate this watcher # because this class instance is about to be reaped in Daemon.py return False try: data = data.decode("ascii") except AttributeError: data = "unknown" if data != self.domain_state: self.domain_state = data @self.zkhandler.zk_conn.DataWatch( self.zkhandler.schema.path("node.monitoring.health", self.name) ) def watch_node_health(data, stat, event=""): if event and event.type == "DELETED": # The key has been deleted after existing before; terminate this watcher # because this class instance is about to be reaped in Daemon.py return False try: data = data.decode("ascii") except AttributeError: data = 100 try: data = int(data) except ValueError: pass if data != self.health: self.health = data @self.zkhandler.zk_conn.DataWatch( self.zkhandler.schema.path("node.memory.free", self.name) ) def watch_node_memfree(data, stat, event=""): if event and event.type == "DELETED": # The key has been deleted after existing before; terminate this watcher # because this class instance is about to be reaped in Daemon.py return False try: data = data.decode("ascii") except AttributeError: data = 0 if data != self.memfree: self.memfree = data @self.zkhandler.zk_conn.DataWatch( self.zkhandler.schema.path("node.memory.used", self.name) ) def watch_node_memused(data, stat, event=""): if event and event.type == "DELETED": # The key has been deleted after existing before; terminate this watcher # because this class instance is about to be reaped in Daemon.py return False try: data = data.decode("ascii") except AttributeError: data = 0 if data != self.memused: self.memused = data @self.zkhandler.zk_conn.DataWatch( self.zkhandler.schema.path("node.memory.allocated", self.name) ) def watch_node_memalloc(data, stat, event=""): if event and event.type == "DELETED": # The key has been deleted after existing before; terminate this watcher # because this class instance is about to be reaped in Daemon.py return False try: data = data.decode("ascii") except AttributeError: data = 0 if data != self.memalloc: self.memalloc = data @self.zkhandler.zk_conn.DataWatch( self.zkhandler.schema.path("node.vcpu.allocated", self.name) ) def watch_node_vcpualloc(data, stat, event=""): if event and event.type == "DELETED": # The key has been deleted after existing before; terminate this watcher # because this class instance is about to be reaped in Daemon.py return False try: data = data.decode("ascii") except AttributeError: data = 0 if data != self.vcpualloc: self.vcpualloc = data @self.zkhandler.zk_conn.DataWatch( self.zkhandler.schema.path("node.running_domains", self.name) ) def watch_node_runningdomains(data, stat, event=""): if event and event.type == "DELETED": # The key has been deleted after existing before; terminate this watcher # because this class instance is about to be reaped in Daemon.py return False try: data = data.decode("ascii").split() except AttributeError: data = [] if len(data) != self.active_domains_count: self.active_domains_count = len(data) @self.zkhandler.zk_conn.DataWatch( self.zkhandler.schema.path("node.count.provisioned_domains", self.name) ) def watch_node_domainscount(data, stat, event=""): if event and event.type == "DELETED": # The key has been deleted after existing before; terminate this watcher # because this class instance is about to be reaped in Daemon.py return False try: data = data.decode("ascii") except AttributeError: data = 0 if data != self.provisioned_domains_count: self.provisioned_domains_count = data