def start(self): """Start the daemon. Args: None Returns: """ # Check for a pidfile to see if the daemon already runs try: with open(self.pidfile, 'r') as pf_handle: pid = int(pf_handle.read().strip()) except IOError: pid = None if pid: log_message = ( 'PID file: {} already exists. Daemon already running?' ''.format(self.pidfile)) log.log2die(1062, log_message) # Start the daemon self.daemonize() # Log success log_message = ('Daemon {} started - PID file: {}' ''.format(self.name, self.pidfile)) log.log2info(1070, log_message) # Run code for daemon self.run()
def populate(self, data_in): """Populate data for agent to eventually send to server. Args: data_in: dict of datapoint values from agent timeseries: TimeSeries data if True Returns: None """ # Initialize data data = deepcopy(data_in) # Validate base_type if len(data) != 1 or isinstance(data, defaultdict) is False: log_message = 'Agent data "{}" is invalid'.format(data) log.log2die(1025, log_message) # Get a description to use for label value for label in data.keys(): description = self._lang.label_description(label) data[label]['description'] = description break # Add data to appropriate self._data key if data[label]['base_type'] is not None: self._data['devices'][self._devicename]['timeseries'].update(data) else: self._data['devices'][self._devicename]['timefixed'].update(data)
def _ip_binding(): """Create IPv4 / IPv6 binding for Gunicorn. Args: None Returns: result: bind """ # Initialize key variables config = CONFIG ipv4 = False ip_address = config.listen_address() # Check IP address type try: ip_object = ipaddress.ip_address(ip_address) except: log_message = ( 'The {} IP address in the configuration file is incorrectly ' 'formatted'.format(ip_address)) log.log2die(1234, log_message) # Is this an IPv4 address? ipv4 = isinstance(ip_object, ipaddress.IPv4Address) if ipv4 is True: result = '{}:{}'.format(ip_address, config.bind_port()) else: result = '[{}]:{}'.format(ip_address, config.bind_port()) return result
def agent_cache_directory(self): """Determine the agent_cache_directory. Args: None Returns: value: configured agent_cache_directory """ # Initialize key variables key = 'main' sub_key = 'agent_cache_directory' # Get result _value = _key_sub_key(key, sub_key, self._config_dict) # Expand linux ~ notation for home directories if provided. value = os.path.expanduser(_value) # Check if value exists if os.path.isdir(value) is False: log_message = ('agent_cache_directory: "{}" ' 'in configuration doesn\'t exist!'.format(value)) log.log2die(1031, log_message) # Return return value
def log_directory(self): """Get log_directory. Args: None Returns: result: result """ # Get result sub_key = 'log_directory' result = None key = 'main' # Get new result _result = _key_sub_key(key, sub_key, self._config_dict) # Expand linux ~ notation for home directories if provided. result = os.path.expanduser(_result) # Check if value exists if os.path.isdir(result) is False: log_message = ('log_directory: "{}" ' 'in configuration doesn\'t exist!'.format(result)) log.log2die(1010, log_message) # Return return result
def stop(self): """Stop the daemon. Args: None Returns: """ # Get the pid from the pidfile try: with open(self.pidfile, 'r') as pf_handle: pid = int(pf_handle.read().strip()) except IOError: pid = None if not pid: log_message = ('PID file: {} does not exist. Daemon not running?' ''.format(self.pidfile)) log.log2warning(1063, log_message) # Not an error in a restart return # Try killing the daemon process try: while 1: if self.lockfile is None: os.kill(pid, signal.SIGTERM) else: time.sleep(0.3) if os.path.exists(self.lockfile) is True: continue else: os.kill(pid, signal.SIGTERM) time.sleep(0.3) except OSError as err: error = str(err.args) if error.find("No such process") > 0: self.delpid() self.dellock() else: log_message = (str(err.args)) log_message = ('{} - PID file: {}'.format( log_message, self.pidfile)) log.log2die(1068, log_message) except: log_message = ('Unknown daemon "stop" error for PID file: {}' ''.format(self.pidfile)) log.log2die(1066, log_message) # Log success self.delpid() self.dellock() log_message = ('Daemon {} stopped - PID file: {}' ''.format(self.name, self.pidfile)) log.log2info(1071, log_message)
def daemonize(self): """Deamonize class. UNIX double fork mechanism. Args: None Returns: None """ # Create a parent process that will manage the child # when the code using this class is done. try: pid = os.fork() if pid > 0: # Exit first parent sys.exit(0) except OSError as err: log_message = 'Daemon fork #1 failed: {}'.format(err) log_message = '{} - PID file: {}'.format(log_message, self.pidfile) log.log2die(1060, log_message) # Decouple from parent environment os.chdir('/') os.setsid() os.umask(0) # Do second fork try: pid = os.fork() if pid > 0: # exit from second parent sys.exit(0) except OSError as err: log_message = 'Daemon fork #2 failed: {}'.format(err) log_message = '{} - PID file: {}'.format(log_message, self.pidfile) log.log2die(1061, log_message) # Redirect standard file descriptors sys.stdout.flush() sys.stderr.flush() f_handle_si = open(os.devnull, 'r') f_handle_so = open(os.devnull, 'a+') f_handle_se = open(os.devnull, 'a+') os.dup2(f_handle_si.fileno(), sys.stdin.fileno()) os.dup2(f_handle_so.fileno(), sys.stdout.fileno()) os.dup2(f_handle_se.fileno(), sys.stderr.fileno()) # write pidfile atexit.register(self.delpid) pid = str(os.getpid()) with open(self.pidfile, 'w+') as f_handle: f_handle.write(pid + '\n')
def purge(self): """Purge data from cache by posting to central server. Args: None Returns: success: "True: if successful """ # Initialize key variables agent_id = self._data['agent_id'] # Add files in cache directory to list only if they match the # cache suffix all_filenames = [ filename for filename in os.listdir(self._cache_dir) if os.path.isfile(os.path.join(self._cache_dir, filename)) ] filenames = [ filename for filename in all_filenames if filename.endswith(self._cache_filename_suffix) ] # Read cache file for filename in filenames: # Only post files for our own UID value if agent_id not in filename: continue # Get the full filepath for the cache file and post filepath = os.path.join(self._cache_dir, filename) with open(filepath, 'r') as f_handle: try: data = json.load(f_handle) except: # Log removal log_message = ( 'Error reading previously cached agent data file {} ' 'for agent {}. May be corrupted.' ''.format(filepath, self._agent_name)) log.log2die(1064, log_message) # Post file success = self.post(save=False, data=data) # Delete file if successful if success is True: os.remove(filepath) # Log removal log_message = ('Purging cache file {} after successfully ' 'contacting server {}' ''.format(filepath, self._url)) log.log2info(1029, log_message)
def read_yaml_files(config_directory): """Read the contents of all yaml files in a directory. Args: config_directory: Directory with configuration files Returns: config_dict: Dict of yaml read """ # Initialize key variables yaml_found = False yaml_from_file = '' all_yaml_read = '' if os.path.isdir(config_directory) is False: log_message = ('Configuration directory "{}" ' 'doesn\'t exist!'.format(config_directory)) log.log2die(1009, log_message) # Cycle through list of files in directory for filename in os.listdir(config_directory): # Examine all the '.yaml' files in directory if filename.endswith('.yaml'): # YAML files found yaml_found = True # Read file and add to string file_path = '{}/{}'.format(config_directory, filename) try: with open(file_path, 'r') as file_handle: yaml_from_file = file_handle.read() except: log_message = ('Error reading file {}. Check permissions, ' 'existence and file syntax.' ''.format(file_path)) log.log2die(1065, log_message) # Append yaml from file to all yaml previously read all_yaml_read = '{}\n{}'.format(all_yaml_read, yaml_from_file) # Verify YAML files found in directory. We cannot use logging as it # requires a logfile location from the configuration directory to work # properly if yaml_found is False: log_message = ( 'No configuration files found in directory "{}" with ".yaml" ' 'extension.'.format(config_directory)) print(log_message) sys.exit(1) # Return config_dict = yaml.safe_load(all_yaml_read) return config_dict
def _mkdir(directory): """Create a directory if it doesn't already exist. Args: directory: Directory name Returns: None """ # Do work if os.path.exists(directory) is False: os.makedirs(directory, mode=0o775) else: if os.path.isfile(directory) is True: log_message = ('{} is not a directory.' ''.format(directory)) log.log2die(1043, log_message)
def agents(self): """Get agents. Args: None Returns: result: list of agents """ # Initialize key variables key = 'agents' result = None # Verify data if key not in self._config_dict: log_message = ('No agents configured') log.log2die(1100, log_message) # Process agents result = self._config_dict[key] # Return return result