def delete_expired_files(self): """delete expired toml/tmpl files in remote confd client """ cfg_names = [x['name'] for x in self._files] for host in self._hosts: aapi = Ansible2API(hosts=[host], **self._ansible_kwargs) # 1. delete expired toml file tomls = self.get_tomls(host=host) for x in tomls: config = x.split(self._file_pre)[1].split('toml')[0].strip('.') if config not in cfg_names: state, state_sum, results = ansible_safe_run( aapi=aapi, module='file', args=dict(path=os.path.join(self._r_toml, x), state='absent')) msg = 'Toml File Deleted: %s' % state_sum app.logger.debug(logmsg(msg)) msg = 'Toml File Deleted: %s' % results app.logger.info(logmsg(msg)) # 2. delete expired tmpl file tmpls = self.get_tmpls(host=host) for x in tmpls: config = x.split('.tmpl')[0] if config not in cfg_names: state, state_sum, results = ansible_safe_run( aapi=aapi, module='file', args=dict(path=os.path.join(self._r_tmpl, self._folder_pre, x), state='absent')) msg = 'Tmpl File Deleted: %s' % state_sum app.logger.debug(logmsg(msg)) msg = 'Tmpl File Deleted: %s' % results app.logger.info(logmsg(msg))
def confd_cmd(self, action): """ confd client startup cmd """ aapi = Ansible2API(hosts=self._hosts, **self._ansible_kwargs) state, state_sum, results = ansible_safe_run( aapi=aapi, module='shell', args=self._confd_startup_cmd[action]) msg = 'Confd %s: %s' % (action.upper(), state_sum) app.logger.debug(logmsg(msg)) msg = 'Confd %s: %s' % (action.upper(), results) app.logger.info(logmsg(msg))
def get_tmpl_content(self, cfg_name, host): """get template file content from remote confd client """ aapi = Ansible2API(hosts=[host], **self._ansible_kwargs) state, state_sum, results = ansible_safe_run( aapi=aapi, module='shell', args='cat %s.tmpl' % os.path.join(self._folder_pre, cfg_name)) msg = 'Tmpl File Get: %s' % state_sum app.logger.debug(logmsg(msg)) msg = 'Tmpl File Get: %s' % results app.logger.info(logmsg(msg)) return '%s\r\n' % results[host]['stdout']
def get_tmpls(self, host): """get template files from remote confd client """ aapi = Ansible2API(hosts=[host], **self._ansible_kwargs) state, state_sum, results = ansible_safe_run( aapi=aapi, module='shell', args='ls %s | awk 1' % os.path.join(self._r_tmpl, self._folder_pre)) msg = 'Tmpl File Check: %s' % state_sum app.logger.debug(logmsg(msg)) msg = 'Tmpl File Check: %s' % results app.logger.info(logmsg(msg)) return results[host]['stdout_lines']
def get_tomls(self, host): """get toml files from remote confd client """ aapi = Ansible2API(hosts=[host], **self._ansible_kwargs) state, state_sum, results = ansible_safe_run( aapi=aapi, module='shell', args='ls %s | grep "^%s\..*\.toml$" | awk 1' % (self._r_toml, self._file_pre)) msg = 'Toml File Check: %s' % state_sum app.logger.debug(logmsg(msg)) msg = 'Toml File Check: %s' % results app.logger.info(logmsg(msg)) return results[host]['stdout_lines']
def get_toml_content(self, cfg_name, host): """get toml file content from remote confd client """ aapi = Ansible2API(hosts=[host], **self._ansible_kwargs) state, state_sum, results = ansible_safe_run( aapi=aapi, module='shell', args='cat %s.%s.toml' % (self._file_pre, cfg_name)) msg = 'Toml File Get: %s' % state_sum app.logger.debug(logmsg(msg)) msg = 'Toml File Get: %s' % results app.logger.info(logmsg(msg)) results = results[host]['stdout_lines'][1:] ret = dict() for x in results: key, value = x.split(' = ') ret[key] = value.strip('\"') return ret
def setUp(self): ''' create ansible api object and mock attr ''' self._hosts = ['127.0.0.1', '10.0.0.1'] self._args = 'cat helloworld.txt' self._state = 0 self._stat = { 'unreachable': 0, 'skipped': 0, 'ok': 1, 'changed': 1, 'failures': 0 } self._hostvars = { self._hosts[0]: { 'out': { u'changed': True, u'end': u'2018-01-01 10:57:08.144560', u'stdout': u'Hello World!', u'cmd': self._args, u'rc': 0, u'start': u'2018-01-01 10:57:08.137068', u'stderr': u'', u'delta': u'0:00:00.007492', 'stdout_lines': [u'Hello World!'], u'warnings': [] } }, self._hosts[1]: { 'out': { u'changed': True, u'end': u'2018-01-01 10:57:08.144560', u'stdout': u'Hello Leann!', u'cmd': self._args, u'rc': 0, u'start': u'2018-01-01 10:57:08.137068', u'stderr': u'', u'delta': u'0:00:00.007492', 'stdout_lines': [u'Hello Leann!'], u'warnings': [] } } } TaskQueueManager.hostvars = self._hostvars self.aapi = Ansible2API(hosts=self._hosts)
def delete_files(self): """ delete old toml/tmpl files in remote confd client ps: make sure that all these files have been backup already """ for host in self._hosts: aapi = Ansible2API(hosts=[host], **self._ansible_kwargs) # 1. delete toml tomls = self.get_tomls(host=host) for x in tomls: state, state_sum, results = ansible_safe_run( aapi=aapi, module='file', args=dict(path=os.path.join(self._r_toml, x), state='absent')) msg = 'Toml File Deleted: %s' % state_sum app.logger.debug(logmsg(msg)) msg = 'Toml File Deleted: %s' % results app.logger.info(logmsg(msg)) # 2. delete tmpl state, state_sum, results = ansible_safe_run( aapi=aapi, module='file', args=dict(path='%s/' % os.path.join(self._r_tmpl, self._folder_pre), state='absent')) msg = 'Tmpl File Deleted: %s' % state_sum app.logger.debug(logmsg(msg)) msg = 'Tmpl File Deleted: %s' % results app.logger.info(logmsg(msg)) # 3. delete conf for x in self._files: state, state_sum, results = ansible_safe_run( aapi=aapi, module='file', args=dict(path=os.path.join(x['dir'], x['name']), state='absent')) msg = 'Conf File Deleted: %s' % state_sum app.logger.debug(logmsg(msg)) msg = 'Conf File Deleted: %s' % results app.logger.info(logmsg(msg))
def get_uids(self, name, group): """fetch owner's uid and gid via name """ aapi = Ansible2API(hosts=self._hosts, **self._ansible_kwargs) state, state_sum, results = ansible_safe_run( aapi=aapi, module='shell', args="cat /etc/passwd | grep ^%s: | awk -F ':' '{print $3}';" "cat /etc/passwd | grep ^%s: | awk -F ':' '{print $3}';" % (name, group)) msg = 'Uid and Gid Get: %s' % state_sum app.logger.debug(logmsg(msg)) msg = 'Uid and Gid Get: %s' % results app.logger.info(logmsg(msg)) ret = {} for k, v in results.items(): if len(v['stdout_lines']) == 2: ret[k] = dict(uid=v['stdout_lines'][0], gid=v['stdout_lines'][1]) else: raise Exception('{0}: No such user or group ({1}, {2})'.format( k, name, group)) return ret
def check_files(self): ret = {} template_regex = r'{{getv\s+"/%s"}}' mode_dict = {'-': 0, 'x': 1, 'w': 2, 'r': 4} aapi = Ansible2API(hosts=self._hosts, **self._ansible_kwargs) for x in self._files: abs_path = os.path.join(x['dir'], x['name']) ret[x['name']] = {host: {} for host in self._hosts} # 1. check md5 # use tmpl to generate expected configuration file content content = x['template'] for k, v in x['items'].items(): content = re.sub(pattern=template_regex % k, repl=v, string=content) # cuz ansible shell 'stdout' will ignore terminal '\r\n' expected_raw = content.rstrip('\r\n') expected_md5 = md5hex(expected_raw) # use ansible to fetch file content state, state_sum, results = ansible_safe_run( aapi=aapi, module='shell', args='cat {0}'.format(abs_path)) # compare the online to the expected using md5 for host in self._hosts: if results[host]['stderr']: ret[x['name']][host] = dict( error='{0}: No such file or directory'.format( abs_path)) else: actual_raw = results[host]['stdout'].rstrip('\r\n') actual_md5 = md5hex(actual_raw) if actual_md5 != expected_md5: ret[x['name']][host]['content'] = '{0} != {1}'.format( actual_md5, expected_md5) ret[x['name']][host]['content_expected'] = expected_raw ret[x['name']][host]['content_actual'] = actual_raw else: ret[x['name']][host]['content'] = "OK" # 2. check mode state, state_sum, results = ansible_safe_run( aapi=aapi, module='shell', args="ls -al %s|awk '{print $1}'" % abs_path) for host in self._hosts: if 'error' in ret[x['name']][host]: continue mode = '0{0}{1}{2}'.format( sum([mode_dict[y] for y in results[host]['stdout'][1:4]]), sum([mode_dict[y] for y in results[host]['stdout'][4:7]]), sum([mode_dict[y] for y in results[host]['stdout'][7:]])) ret[x['name']][host]['mode'] = ('{0} != {1}'.format( mode, x['mode']) if mode != x['mode'] else 'OK') # 3. check owner state, state_sum, results = ansible_safe_run( aapi=aapi, module='shell', args="ls -al %s|awk '{print $3,$4}'" % abs_path) for host in self._hosts: if 'error' in ret[x['name']][host]: continue owner = results[host]['stdout'].split() ret[x['name']][host]['owner'] = ( '{0} != {1}'.format(tuple(owner), (x['owner']['name'], x['owner']['group'])) if owner[0] != x['owner']['name'] and owner[1] != x['owner']['group'] else 'OK') # 4. check modify time state, state_sum, results = ansible_safe_run( aapi=aapi, module='shell', args="ls --full-time %s|awk '{print $6,$7,$8}'" % abs_path) for host in self._hosts: if 'error' in ret[x['name']][host]: continue ret[x['name']][host]['last_modify_time'] = results[host][ 'stdout'] return ret
def push_files(self, rollback=False): """ update toml/tmpl/(conf) files to remote/local confd client """ for host in self._hosts: aapi = Ansible2API(hosts=[host], **self._ansible_kwargs) toml_folder = '%s/' % (os.path.join(self._l_toml_bak, host) if rollback else os.path.join( self._l_toml, host)) tmpl_folder = '{}/'.format( os.path.join(self._l_tmpl_bak, host) if rollback else self. _l_tmpl) if rollback: conf_folder = '%s/' % os.path.join(self._l_conf_bak, host) # clear folders remove_folder(toml_folder) remove_folder(tmpl_folder) remove_folder(conf_folder) get_folder(toml_folder) get_folder(tmpl_folder) get_folder(conf_folder) # download latest tomls/tmpls from minio toml_pre = '%s/' % os.path.join('toml', self._folder_pre, host) objs = self.minio.list_objects(bucket_name=self._minio_bucket, prefix=toml_pre, recursive=False) for x in objs: object_name = x.object_name.encode('utf-8') self.minio.fget_object(bucket_name=self._minio_bucket, object_name=object_name, file_path=os.path.join( toml_folder, os.path.basename(object_name))) tmpl_pre = '%s/' % os.path.join('tmpl', self._folder_pre, host) objs = self.minio.list_objects(bucket_name=self._minio_bucket, prefix=tmpl_pre, recursive=False) for x in objs: object_name = x.object_name.encode('utf-8') self.minio.fget_object(bucket_name=self._minio_bucket, object_name=object_name, file_path=os.path.join( tmpl_folder, os.path.basename(object_name))) conf_pre = '%s/' % os.path.join('conf', self._folder_pre, host) objs = self.minio.list_objects(bucket_name=self._minio_bucket, prefix=conf_pre, recursive=False) for x in objs: object_name = x.object_name.encode('utf-8') self.minio.fget_object(bucket_name=self._minio_bucket, object_name=object_name, file_path=os.path.join( conf_folder, os.path.basename(object_name))) # push conf files to remote/local confd client for x in os.listdir(conf_folder): config = x.split(self._broken_word_2) file_path = config[1].replace(self._broken_word_1, '/') info = config[0].split('@@') state, state_sum, results = ansible_safe_run( aapi=aapi, module='copy', args=dict(mode=info[0], src=os.path.join(conf_folder, x), dest=file_path, group=info[2], owner=info[1])) msg = 'Conf File Updated: %s' % state_sum app.logger.debug(logmsg(msg)) msg = 'Conf File Updated: %s' % results app.logger.info(logmsg(msg)) # 1. push toml files to remote/local confd client state, state_sum, results = ansible_safe_run( aapi=aapi, module='copy', args=dict(mode=self._confd_file_mode, src=toml_folder, dest=self._r_toml, group=self._confd_owner[1], owner=self._confd_owner[0])) msg = 'Toml File Updated: %s' % state_sum app.logger.debug(logmsg(msg)) msg = 'Toml File Updated: %s' % results app.logger.info(logmsg(msg)) # 2. push tmpl files to remote/local confd client r_tmpl_folder = os.path.join(self._r_tmpl, self._folder_pre) state, state_sum, results = ansible_safe_run( aapi=aapi, module='copy', args=dict(mode=self._confd_file_mode, src=tmpl_folder, dest=r_tmpl_folder, group=self._confd_owner[1], owner=self._confd_owner[0])) msg = 'Tmpl File Updated: %s' % state_sum app.logger.debug(logmsg(msg)) msg = 'Tmpl File Updated: %s' % results app.logger.info(logmsg(msg))
def backup_files(self): """backup old toml/tmpl/cfg files from remote confd client to server """ for host in self._hosts: # local filesystem toml_bak = os.path.join(self._l_toml_bak, host) tmpl_bak = os.path.join(self._l_tmpl_bak, host) conf_bak = os.path.join(self._l_conf_bak, host) remove_folder(toml_bak) remove_folder(tmpl_bak) remove_folder(conf_bak) get_folder(toml_bak) get_folder(tmpl_bak) get_folder(conf_bak) # minio server toml_pre = '%s/' % os.path.join('toml', self._folder_pre, host) tmpl_pre = '%s/' % os.path.join('tmpl', self._folder_pre, host) conf_pre = '%s/' % os.path.join('conf', self._folder_pre, host) objs = self.minio.list_objects(bucket_name=self._minio_bucket, prefix=toml_pre, recursive=False) for x in objs: self.minio.remove_object( bucket_name=self._minio_bucket, object_name=x.object_name.encode('utf-8')) objs = self.minio.list_objects(bucket_name=self._minio_bucket, prefix=tmpl_pre, recursive=False) for x in objs: self.minio.remove_object( bucket_name=self._minio_bucket, object_name=x.object_name.encode('utf-8')) objs = self.minio.list_objects(bucket_name=self._minio_bucket, prefix=conf_pre, recursive=False) for x in objs: self.minio.remove_object( bucket_name=self._minio_bucket, object_name=x.object_name.encode('utf-8')) aapi = Ansible2API(hosts=[host], **self._ansible_kwargs) # 1. backup toml to minio server tomls = self.get_tomls(host=host) for x in tomls: state, state_sum, results = ansible_safe_run( aapi=aapi, module='fetch', args=dict(dest='%s/' % toml_bak, src=os.path.join(self._r_toml, x), flat='yes')) msg = 'Toml File Backup: %s' % state_sum app.logger.debug(logmsg(msg)) msg = 'Toml File Backup: %s' % results app.logger.info(logmsg(msg)) self.minio.fput_object(bucket_name=self._minio_bucket, object_name=os.path.join(toml_pre, x), file_path=os.path.join(toml_bak, x)) # 2. backup tmpl to minio server tmpls = self.get_tmpls(host=host) for x in tmpls: state, state_sum, results = ansible_safe_run( aapi=aapi, module='fetch', args=dict(dest='%s/' % tmpl_bak, src=os.path.join(self._r_tmpl, self._folder_pre, x), flat='yes')) msg = 'Tmpl File Backup: %s' % state_sum app.logger.debug(logmsg(msg)) msg = 'Tmpl File Backup: %s' % results app.logger.info(logmsg(msg)) self.minio.fput_object(bucket_name=self._minio_bucket, object_name=os.path.join(tmpl_pre, x), file_path=os.path.join(tmpl_bak, x)) # 3. backup conf to minio server # files should include (name, dir, mode, owner) for x in self._files: src = os.path.join(x['dir'], x['name']) file_name = '%s%s%s' % ('@@'.join([ x['mode'], x['owner']['name'], x['owner']['group'] ]), self._broken_word_2, src.replace('/', self._broken_word_1)) state, state_sum, results = ansible_safe_run( aapi=aapi, module='fetch', args=dict(dest=os.path.join(conf_bak, file_name), src=src, flat='yes')) msg = 'Conf File Backup: %s' % state_sum app.logger.debug(logmsg(msg)) msg = 'Conf File Backup: %s' % results app.logger.info(logmsg(msg)) file_path = os.path.join(conf_bak, file_name) if os.path.isfile(file_path): self.minio.fput_object(bucket_name=self._minio_bucket, object_name=os.path.join( conf_pre, file_name), file_path=file_path) # 4. check if toml/tmpl/conf have been backuped to minio server objs = [ os.path.basename(x.object_name.encode('utf-8')) for x in self.minio.list_objects(bucket_name=self._minio_bucket, prefix=toml_pre, recursive=False) ] for x in tomls: if x not in objs: raise Exception('Toml Backup Failed: %s.' % x) objs = [ os.path.basename(x.object_name.encode('utf-8')) for x in self.minio.list_objects(bucket_name=self._minio_bucket, prefix=tmpl_pre, recursive=False) ] for x in tmpls: if x not in objs: raise Exception('Tmpl Backup Failed: %s.' % x)