OSSIM开源安全信息管理系统(八)

2021SC@SDUSC



上周开始对 framework.py 的相关联的其他类进行了分析,并且上周主要分析的是 logger.py ,这周开始对另一个重要的源代码文件 backupmanager.py 进行分析,也就是对 backupmanager 这个类进行分析

1、BackupManager.py

1.1 简介

BackupManager 该类继承自 python 自带线程类 threading.Thread,该类主要功能为管理备份

  • threading.Thread简介:

    Python3 通过两个标准库 _thread 和 threading 提供对线程的支持。其中 _thread 提供了低级别的、原始的线程以及一个简单的锁,它相比于 threading 模块的功能还是比较有限的。而 threading 模块除了包含 _thread 模块中的所有方法外,还提供的其他方法:

    • threading.currentThread() : 返回当前的线程变量。
    • threading.enumerate() : 返回一个包含正在运行的线程的list。正在运行指线程启动后、结束前,不包括启动前和终止后的线程。
    • threading.activeCount() : 返回正在运行的线程数量,与 len(threading.enumerate()) 有相同的结果。

    除了使用方法外,线程模块同样提供了 Thread 类来处理线程,Thread 类提供了以下方法:

    • run() : 用以表示线程活动的方法。
    • start() : 启动线程活动。
    • join([time]) : 等待至线程终止。这阻塞调用线程直至线程的 join() 方法被调用中止-正常退出或者抛出未处理的异常-或者是可选的超时发生。
    • isAlive() : 返回线程是否活动的。
    • getName() : 返回线程名。
    • setName(): 设置线程名。

1.2 类分析

首先继承自 python 的 threading.Thread

然后定义了两个变量:

  • UPDATE_BACKUP_FILE:备份配置文件
  • LISTEN_SOCK:这个变量虽然在这里定义了,并赋值为 /etc/ossim/framework/bksock.sock ,但是看了一下这个类后面的各个方法的代码,并没有发现任何有使用这个变量的代码片段,可能是在其他类中使用了该变量,等到后续遇到了再仔细看一下吧。这个文件就是以 .sock 为后缀的文件而已。UNIX 系统不以后缀区分文件类型,但为了方便,通常使用后缀来标识一下。.sock 文件极有可能是 UNIX 域套接字(UNIX domain socket),即通过文件系统(而非网络地址)进行寻址和访问的套接字
class BackupManager(threading.Thread):
    UPDATE_BACKUP_FILE = '/etc/ossim/framework/lastbkday.fkm'
    LISTEN_SOCK = '/etc/ossim/framework/bksock.sock'

__inin__(self)

一个默认的构造器,用于声明一些类属性,并初始化类的属性,以及调用 threading.Thread.__init__(self) 初始化父类 threading.Thread

def __init__(self):
    threading.Thread.__init__(self)
    self.__myDB = OssimDB(_CONF[VAR_DB_HOST],
                          _CONF[VAR_DB_SCHEMA],
                          _CONF[VAR_DB_USER],
                          _CONF[VAR_DB_PASSWORD])
    self.__myDB_connected = False
    self.__keepWorking = True
    self.__bkConfig = {
     }    #存储备份配置信息
    self.__loadConfiguration()
    self.__stopE = threading.Event()
    self.__stopE.clear()

__loadConfiguration(self)

主要功能为加载备份管理器的相关配置,并使用数据库中的值进行更新。

def __loadConfiguration(self):
    #从文件中读取备份的配置信息,存储在self.__bkConfig中
    self.__loadBackupConfig()

连接数据库

if not self.__myDB_connected:
    if self.__myDB.connect():
        self.__myDB_connected = True
    else:
        logger.error("Can't connect to database")
        return

从数据库中查询相关配置信息,判断配置信息,并更新相关配置信息

query = 'select * from config where conf like "%backup%"'
data = None
data = self.__myDB.exec_query(query)

tmpConfig = {
     }
        
if data is not None:
	for row in data:
		if row['conf'] in ['backup_base', 'backup_day', 'backup_dir', 'backup_events', 'backup_store','frameworkd_backup_storage_days_lifetime', 'backup_hour']:
			tmpConfig [row['conf']] = row['value']

for key, value in tmpConfig.iteritems():
    if key == 'last_run':
        continue
    if key not in self.__bkConfig:
        logger.info("Backup new config key: '%s' '%s'" % (key, value))
        self.__bkConfig[key] = tmpConfig[key]
    elif value != self.__bkConfig[key]:
        logger.info('Backup Config value has changed %s=%s and old value %s=%s' % (key, value, key, self.__bkConfig[key]))
        self.__bkConfig[key] = tmpConfig[key]

if not self.__bkConfig.has_key('last_run'):
    self.__bkConfig['last_run'] = date(year=1,month=1,day=1)
if not self.__bkConfig.has_key('backup_day'):
    self.__bkConfig['backup_day'] = 30
if not self.__bkConfig.has_key('frameworkd_backup_storage_days_lifetime'):
    self.__bkConfig['frameworkd_backup_storage_days_lifetime'] = 5

self.__updateBackupConfigFile()        

__updateBackupConfigFile(self)

主要实现功能为更新备份配置文件

def __updateBackupConfigFile(self):
    try:
        bk_configfile = open(BackupManager.UPDATE_BACKUP_FILE, "wb")
        pickle.dump(self.__bkConfig, bk_configfile)
        bk_configfile.close()
        os.chmod(BackupManager.UPDATE_BACKUP_FILE,0644)
    except Exception, e:
        logger.error("Error dumping backup config update_file...:%s" % str(e))

__loadBackupConfig(self) :

该函数主要功能为从文件中加载备份配置信息,并将备份配置内容信息存储到 __bkConfig

def __loadBackupConfig(self):
    self.__bkConfig = {
     }

首先判断 UPDATE_BACKUP_FILE = '/etc/ossim/framework/lastbkday.fkm' 文件是否存在

存在的话使用 pickle.load(bk_configfile) 反序列化读取文件中存储的对象

if os.path.isfile(BackupManager.UPDATE_BACKUP_FILE):
	try:
		bk_configfile = open(BackupManager.UPDATE_BACKUP_FILE)

该函数对文件中存储的对象进行反序列化,使用的模块为 pickle,是 python 的一个重要模块。

pickle 提供了一个简单的持久化功能。可以将对象以文件的形式存放在磁盘上。

pickle 模块只能在 Python 中使用,python 中几乎所有的数据类型(列表,字典,集合,类等)都可以用 pickle来序列化,
因为这里用到了 python 的序列化与反序列化的相关知识,所以对这方面内容进行了简单的查询学习和了解。关于 python 序列化函数的简单介绍:

  • pickle.dump(obj, file[, protocol])
    • 功能:序列化对象,并将结果数据流写入到文件对象中。
    • 参数:参数 protocol 是序列化模式,默认值为 0,表示以文本的形式序列化。protocol 的值还可以是1或2,表示以二进制的形式序列化。
  • pickle.load(file)
    • 功能:反序列化对象。并将文件中的数据解析为一个 Python 对象。
self.__bkConfig = pickle.load(bk_configfile)
bk_configfile.close()     

isinstance() 函数用来判断一个对象是否是一个已知的类型,类似于 type()。

下面部分代码主要就是判断反序列化得到的对象是否为一个字典类型(dict)

if not isinstance(self.__bkConfig, dict):

if 判断如果不是字典类型数据,则报告相应警告提示信息,然后从数据库加载配置信息

	logger.warning("Error loading backup configuration file.")
    logger.info("New configuration will be loaded from database")
    self.__bkConfig = {
     }
except Exception, e:
    logger.warning("Error loading backup configuration file...:%s" % str(e))
    logger.info("New configuration will be loaded from database")
    self.__bkConfig = {
     }           

purgeOldBackupfiles(self)

该方法主要功能为清除旧备份文件。

def purgeOldBackupfiles(self):
	backup_files = []
    bkdays = 5
    try:
        #从配置信息中读取backup_day
        bkdays = int(_CONF[VAR_BACKUP_DAYS_LIFETIME])
	except ValueError,e:
        logger.warning("Invalid value for backup_day in config table")

timedelta :该函数表示两个时间的间隔
参数可选、默认值都为0:
datetime.timedelta(days=0, seconds=0, microseconds=0, milliseconds=0, minutes=0, hours=0, weeks=0)

通过 while 循环,分别对每天的备份进行处理,在相应目录下,创建 /insert-[经过格式化的时间字符串 today].sql.gz

today = datetime.now() - timedelta(days=1)
while bkdays>0:
    dt = today.date().isoformat()
    dtstr = "%s" % dt
    dtstr = dtstr.replace('-','')
    str_insert = '%s/insert-%s.sql.gz' % (self.__bkConfig['backup_dir'], dtstr)
    str_delete = '%s/delete-%s.sql.gz' % (self.__bkConfig['backup_dir'], dtstr)
    backup_files.append(str_insert)
    backup_files.append(str_delete)
    bkdays = bkdays - 1
    today = today -timedelta(days=1)

glob 是 python 自带的一个操作文件的相关模块,用它可以查找符合特定规则的文件路径名。模块功能不是很多,还是比较容易掌握的。
使用该模块查找文件,只需要用到: “*”, “?”, “[]”这三个匹配符;

  • ”*”匹配0个或多个字符;
  • ”?”匹配单个字符;
  • ”[]”匹配指定范围内的字符,如:[0-9]匹配数字。

因为这里用到了这个模块里面的方法,来实现文件路径名的查找,所以先简单学习介绍一下这个模块。

这里主要实现通过 os.unlink() 方法来删除一些过时的备份文件,如果文件是一个目录则返回一个错误。 os.unlink() 是 python 用来删除指定路径文件的一个函数。

for bkfile in glob.glob(os.path.join(self.__bkConfig['backup_dir'], '[insert|delete]*.sql.gz')):
	bkfilep=os.path.join(self.__bkConfig['backup_dir'], bkfile)
	if bkfilep not in backup_files:
    	logger.info("Removing outdated backfile :%s" % bkfilep)
        try:
        	os.unlink(bkfilep)
        except Exception,e:
            logger.error("Error removing outdated files: %s" % bkfilep)



上一篇:
下一篇:

你可能感兴趣的:(2021SC@SDUSC,安全,运维)