class ClientWrapper(): EventFeedListeners = [] def __init__(self): self.SaltClient = APIClient() def auth(self, username, password, eauth='pam'): '''Authenticates a user against external auth and returns a token.''' try: token = self.SaltClient.create_token({ 'username': username, 'password': password, 'eauth': eauth }) except: token = { 'error': 'Invalid credentials', 'details': 'Authentication failed with provided credentials.' } return token def get_event(self, tag=''): self.SaltClient.get_event(tag) def cmd(self, cmdmesg): cdict = { 'mode': 'async' } # TODO: async? cdict['fun'] = cmdmesg['method'] cdict['tgt'] = cmdmesg['pattern'] cdict['expr_form'] = cmdmesg.get('pattern_type', 'glob') cdict['kwarg'] = cmdmesg.get('kwargs', {}) cdict['arg'] = cmdmesg.get('args', []) cdict['token'] = cmdmesg['token'] retval = self.SaltClient.run(cdict) return retval
def runner_manage_present_async(self): ''' Make a call to runner.manage.present and test against returned SSE data ''' self.app.post_json('/run', dict(client='master', fun='runner.manage.present', kwarg={}), headers=self.headers) keep_looping = True client = APIClient() sse = None while keep_looping: sse = client.get_event(wait=5, tag='salt/', full=True) keep_looping = False self.assertNotEqual(sse, None)
def runner_manage_present_datastructure(self): ''' Make a call to runner.manage.present and test data structure integrity ''' resp = self.app.post_json('/run', dict(client='master', fun='runner.manage.present', kwarg={}), headers=self.headers) tag = resp.json_body['return'][0]['tag'] client = APIClient() data = None while not data: sse = client.get_event(wait=0.01, tag='salt/', full=True) if sse['tag'] == '%s/ret' % tag: data = sse['data']['return'] self.assertNotEqual(data, None)
class MultiJob(object): def __init__(self): """ MultiJob constructor """ self._jobs = {} self.client = APIClient(opts=MASTER_OPTIONS) self.handler = Handler() def add(self, job): """ Adds a job to be tracked. The job is published with the salt apiclient. The resulting dict containing the job id and the minions associated with the job id are stored for later use. @param salt_job - SaltCommand object containing a dictionary defining parameters of the salt job to be published @return - Boolean True for successful publish, Boolean False otherwise """ pub_data = self.client.run(job.kwargs) job.set_pub_data(pub_data) self._jobs[job.jid] = job def is_finished(self): """ Checks to see if all jobs are finished. @return - Boolean true for finished, Boolean false otherwise """ return all([job.is_finished() for job in self._jobs.itervalues()]) def should_process_event(self, event): """ Checks whether or not we need to process an event. Events should have a jid and a return. The jid should be a job belonging to this MultiJob The job should not be finished yet. @param event - Dictionary representing an event. @return Boolean True for yes, False otherwise. """ jid = event.get('jid') ret = event.get('return') if jid is None or ret is None: return False if jid not in self._jobs: return False job = self._jobs[jid] if job.is_finished(): return False return True def wait(self, timeout): """ Waits for all jobs so far to be finished. If a job finishes that is part of a sequence of jobs, the next job in the sequenced is published. @param timeout - Float or int describing number of seconds to wait in total before returning. @return dict - Dictionary of responses """ start = time.time() timeout_at = start + timeout while True: # Break on timeout if time.time() > timeout_at: break # Listen for all events with tag set to ''. # Need to be able to listen for multiple jobs. event = self.client.get_event(tag='', wait=0.25) # Check for no event received if event is None: continue if self.should_process_event(event): job = self._jobs[event.get('jid')] job.add_minion_return(event) if job.is_finished(): self.handler.handle_finish(job) if job.chain: self.add(job.chain) # Break on all jobs finished if self.is_finished(): break errors = [] # Validate our jobs for jid, job in self._jobs.iteritems(): try: job.validate() except (UnfinishedException, UnsuccessfulException, RetcodeException, FailedStateSlsException) as e: errors.append(e) if errors: raise MultiJobException(errors) resp = {jid: job.ret for jid, job in self._jobs.iteritems()} return resp