def fetch(self, princ, addresses): """fetch keytabs of the address from locker returns: list -- encoded keytab contents belonging to addresses """ if not princ or not princ.startswith('host/'): raise keytabs2.KeytabLockerError( 'princ "{}" not accepted'.format(princ)) hostname = princ[len('host/'):princ.rfind('@')] if not self.zkclient.exists(z.path.server(hostname)): _LOGGER.error('Invalid server: %s', hostname) return {} try: for hostname in addresses: keytab_files = glob.glob( os.path.join(self._kt_spool_dir, '*#{}@*'.format(hostname))) kts = { os.path.basename(keytab_file): keytabs2.read_keytab(keytab_file) for keytab_file in keytab_files } except OSError as err: raise keytabs2.KeytabLockerError(err) return kts
def validate_as_file(encoded_keytabs, basedir): """ validate keytab by given encoded data return keytab files validated """ temp_dir = tempfile.mkdtemp(dir=basedir) try: for encoded in encoded_keytabs: test_file = os.path.join(temp_dir, _NAME) keytabs2.write_keytab( test_file, encoded, ) try: subproc.check_call( ['kt_split', '--dir={}'.format(basedir), test_file]) except subproc.CalledProcessError: raise keytabs2.KeytabLockerError( 'wrong keytab data: {}'.format(encoded)) for kt_file in os.listdir(basedir): full_path = os.path.join(basedir, kt_file) # we ignore temp_dir in basedir if os.path.isdir(full_path): continue yield full_path finally: fs.rmtree_safe(temp_dir)
def _get(self, req): """get keytabs from appname """ try: app_name = req['app'] except KeyError: raise keytabs2.KeytabLockerError('No "app" in request') keytabs = locker.get(self.peer(), app_name) return _response(success=True, keytabs=keytabs)
def _query(self, req): """query keytabs from appname """ try: app_name = req['app'] except KeyError: raise keytabs2.KeytabLockerError('No "app" in request') locker.query(self.peer(), app_name) return _response(success=True)
def _put(self, req): """Store encoded keytab. """ try: keytabs = req['keytabs'] except KeyError: raise keytabs2.KeytabLockerError('No "keytabs" in request') _LOGGER.debug('put keytabs: %s', keytabs) receiver.add(self.peer(), keytabs) return _response(success=True)
def _get(self, req): """get keytabs from appname """ if 'app' in req: app_name = req['app'] kts = locker.get(self.peer(), app_name) elif 'addresses' in req: addresses = req['addresses'] kts = locker.fetch(self.peer(), addresses) else: raise keytabs2.KeytabLockerError( '"app" or "addresses" must be in request') return _response(success=True, keytabs=kts)
def _translate_vip(keytab): """Get ip address from hostname inside keytab string """ match = _KEYTAB_RE_OBJ.match(keytab) if match: hostname = match.group(1) else: raise keytabs2.KeytabLockerError( 'Keytab {} in wrong format'.format(keytab)) _LOGGER.debug('Trying to get vip of %s', hostname) ipaddress = socket.gethostbyname(hostname) _LOGGER.info('keytab => vip: %s => %s', keytab, ipaddress) return ipaddress
def _sync(self, req): """sync proid keytab relationship """ try: mapping = req['mapping'] except KeyError: raise keytabs2.KeytabLockerError('No "mapping" in request') # we convert into a tuple list mapping = [(item[0], item[1]) for item in mapping] _LOGGER.debug('sync mapping: %r', mapping) receiver.sync(self.peer(), mapping) return _response(success=True)
def query(self, princ, app_name): """query if keytabs are valid in manifest returns: list -- keytab names required by app """ vips = self._query_proid_vips(app_name) keytabs = self._get_app_keytabs(princ, app_name) for keytab in keytabs: vip = _translate_vip(keytab) if vip not in vips: raise keytabs2.KeytabLockerError( '{} of keytab {} does not exist or of wrong proid'.format( vip, keytab)) return keytabs
def get(self, princ, app_name): """Get keytabs defined in manifest from locker. returns: list -- encoded keytab contents required by app """ keytab_names = self.query(princ, app_name) try: keytabs = { keytab: keytabs2.read_keytab(os.path.join(self._kt_spool_dir, keytab)) for keytab in keytab_names } except OSError as err: raise keytabs2.KeytabLockerError(err) return keytabs
def _get_app_keytabs(self, princ, appname): """Get keytabs required for the given app.""" # TODO: the logic is duplicated with ticket locker # we need to refactor to implement generic locker in the future if not princ or not princ.startswith('host/'): raise keytabs2.KeytabLockerError( 'princ "{}" not accepted'.format(princ)) hostname = princ[len('host/'):princ.rfind('@')] if not self.zkclient.exists(z.path.placement(hostname, appname)): _LOGGER.error('App %s not scheduled on node %s', appname, hostname) return [] try: appnode = z.path.scheduled(appname) app = zkutils.with_retry(zkutils.get, self.zkclient, appnode) return app.get('keytabs', []) except kazoo.client.NoNodeError: _LOGGER.info('App does not exist: %s', appname) return []
def _query_proid_vips(self, appname): """query proid vips relationship """ proid = appname.split('.')[0] res = set() if not os.path.exists(self._database): _LOGGER.error('DB %s not exist', self._database) raise keytabs2.KeytabLockerError('DB not exist') conn = sqlite3.connect(self._database) cur = conn.cursor() try: query = 'SELECT vip FROM {} where proid = ?'.format(keytabs2.TABLE) store_virtuals = cur.execute(query, (proid, )).fetchall() res = {virtual[0] for virtual in store_virtuals} except sqlite3.OperationalError as err: # table may not exist yet, try sync in the next execution _LOGGER.warning('wait for keytab locker starting.') finally: conn.close() return res
def _check_principal_user(self, princ): """Validate keytab principal.""" if not princ or princ.split('/')[0] != self._owner: raise keytabs2.KeytabLockerError('expect user {}, got: {}'.format( self._owner, princ))