def test_multiple_response_job(self): out = run_client(['bkr', 'job-modify', self.job.t_id, self.job_for_rs.t_id, '--response', 'ack']) self.assert_(out == 'Successfully modified jobs %s %s\n' % (self.job.t_id, self.job_for_rs.t_id)) j = TaskBase.get_by_t_id(self.job.t_id) for rs in j.recipesets: self.assert_('%s' % rs.nacked.response == 'ack') j2 = TaskBase.get_by_t_id(self.job_for_rs.t_id) for rs in j2.recipesets: self.assert_('%s' % rs.nacked.response == 'ack')
def test_multiple_response_recipeset(self): out = run_client(['bkr', 'job-modify', self.job.recipesets[0].t_id, self.job_for_rs.recipesets[0].t_id, '--response', 'ack']) self.assert_('Successfully modified jobs' in out and \ self.job_for_rs.recipesets[0].t_id in out and \ self.job.recipesets[0].t_id in out,) rs = TaskBase.get_by_t_id(self.job.recipesets[0].t_id) self.assert_('%s' % rs.nacked.response == 'ack') rs = TaskBase.get_by_t_id(self.job_for_rs.recipesets[0].t_id) self.assert_('%s' % rs.nacked.response == 'ack')
def test_multiple_response_job(self): out = run_client(['bkr', 'job-modify', self.job.t_id, self.job_for_rs.t_id, '--response', 'ack']) self.assert_('Successfully modified jobs' in out and self.job.t_id in out and self.job_for_rs.t_id in out) j = TaskBase.get_by_t_id(self.job.t_id) for rs in j.recipesets: self.assert_('%s' % rs.nacked.response == 'ack') j2 = TaskBase.get_by_t_id(self.job_for_rs.t_id) for rs in j2.recipesets: self.assert_('%s' % rs.nacked.response == 'ack')
def test_can_reserve_manual_system(self): with session.begin(): broken_system = data_setup.create_system(arch=u'i386', shared=True, status=SystemStatus.broken, lab_controller=self.lc) manual_system = data_setup.create_system(arch=u'i386', shared=True, status=SystemStatus.manual, lab_controller=self.lc) b = self.browser login(b) # broken system should not be present go_to_reserve_systems(b, distro_tree=self.distro_tree_i386) search_for_system(b, broken_system) check_system_search_results(b, absent=[broken_system]) # provision manual system go_to_reserve_systems(b, distro_tree=self.distro_tree_i386) search_for_system(b, manual_system) row = b.find_element_by_xpath('//tr[normalize-space(string(td))="%s"]' % manual_system.fqdn) row.find_element_by_link_text('Reserve Now').click() b.find_element_by_xpath('//button[normalize-space(text())="Submit job"]').click() # should end up on the job page job_id = b.find_element_by_xpath('//td[preceding-sibling::th/text()="Job ID"]/a').text with session.begin(): job = TaskBase.get_by_t_id(job_id) cloned_job_xml = job.to_xml(clone=True).toxml() # cloning re-parses hostRequires self.assertIn( u'<hostRequires force="%s"/>' % manual_system.fqdn, cloned_job_xml)
def update_recipeset_by_taskspec(taskspec): """ Updates the attributes of a recipe set identified by a taskspec. The valid type of a taskspec is either J(job) or RS(recipe-set). If a taskspec format is J:<id>, all the recipe sets in this job will be updated. The request must be :mimetype:`application/json`. :param taskspec: A taskspec argument that identifies a job or recipe set. :jsonparam string priority: Priority for the recipe set. Must be one of 'Low', 'Medium', 'Normal', 'High', or 'Urgent'. This can only be changed while a recipe set is still queued. Job owners can generally only *decrease* the priority of their recipe set, queue admins can increase it. :jsonparam boolean waived: If true, the recipe set will be waived, regardless of its result. """ if not taskspec.startswith(('J', 'RS')): raise BadRequest400('Taskspec type must be one of [J, RS]') try: obj = TaskBase.get_by_t_id(taskspec) except BeakerException as exc: raise NotFound404(unicode(exc)) data = read_json_request(request) if isinstance(obj, Job): for rs in obj.recipesets: _update_recipeset(rs, data) elif isinstance(obj, RecipeSet): _update_recipeset(obj, data) return jsonify(obj.__json__())
def set_retention_product(self, job_t_id, retention_tag_name, product_name): """ XML-RPC method to update a job's retention tag, product, or both. There is an important distinction between product_name of None, which means do not change the existing value, vs. empty string, which means clear the existing product. """ job = TaskBase.get_by_t_id(job_t_id) if job.can_change_product(identity.current.user) and \ job.can_change_retention_tag(identity.current.user): if retention_tag_name and product_name: retention_tag = RetentionTag.by_name(retention_tag_name) product = Product.by_name(product_name) result = Utility.update_retention_tag_and_product(job, retention_tag, product) elif retention_tag_name and product_name == '': retention_tag = RetentionTag.by_name(retention_tag_name) result = Utility.update_retention_tag_and_product(job, retention_tag, None) elif retention_tag_name: retention_tag = RetentionTag.by_name(retention_tag_name) result = Utility.update_retention_tag(job, retention_tag) elif product_name: product = Product.by_name(product_name) result = Utility.update_product(job, product) elif product_name == '': result = Utility.update_product(job, None) else: result = {'success': False, 'msg': 'Nothing to do'} if not result['success'] is True: raise BeakerException('Job %s not updated: %s' % (job.id, result.get('msg', 'Unknown reason'))) else: raise BeakerException('No permission to modify %s' % job)
def test_preserves_lab_requirement(self): login(self.browser) b = self.browser b.get(get_server_base() + 'reserveworkflow') Select(b.find_element_by_name('osmajor'))\ .select_by_visible_text(self.distro.osversion.osmajor.osmajor) Select(b.find_element_by_name('distro')).select_by_visible_text( self.distro.name) Select(b.find_element_by_name('distro_tree_id'))\ .select_by_visible_text('%s Server i386' % self.distro.name) b.find_element_by_xpath( '//label[contains(string(.), "Any system from lab:")]' '/input[@type="radio"]').click() Select(b.find_element_by_name('lab')).select_by_visible_text( self.lc.fqdn) b.find_element_by_xpath( '//button[normalize-space(text())="Submit job"]').click() # should end up on the job page job_id = b.find_element_by_xpath('//h1//span[@class="job-id"]').text wb_descr = (WORKFLOW_DESCR % (self.distro.name, "any lab system", "86400")) wboard = b.find_element_by_class_name('job-whiteboard') self.assertIn(wb_descr, wboard.text, msg="Fail to match default whiteboard") with session.begin(): job = TaskBase.get_by_t_id(job_id) cloned_job_xml = lxml.etree.tostring( job.to_xml(clone=True), encoding=unicode) # cloning re-parses hostRequires self.assertIn( u'<hostRequires><labcontroller op="=" value="%s"/>' u'<system_type op="=" value="Machine"/></hostRequires>' % self.lc.fqdn, cloned_job_xml)
def test_reserve_time(self): login(self.browser) b = self.browser b.get(get_server_base() + 'reserveworkflow/') Select(b.find_element_by_name('osmajor'))\ .select_by_visible_text(self.distro.osversion.osmajor.osmajor) Select(b.find_element_by_name('distro')).select_by_visible_text( self.distro.name) Select(b.find_element_by_name('distro_tree_id'))\ .select_by_visible_text('%s Server i386' % self.distro.name) b.find_element_by_name('reserve_duration').clear() b.find_element_by_name('reserve_duration').send_keys('96') b.find_element_by_xpath('.//button[text()="Hours"]').click() b.find_element_by_xpath( '//button[normalize-space(text())="Submit job"]').click() # should end up on the job page jid = b.find_element_by_xpath('//h1//span[@class="job-id"]').text with session.begin(): job = TaskBase.get_by_t_id(jid) reserve_task = job.recipesets[0].recipes[0].tasks[1] self.assertEquals(reserve_task.task.name, '/distribution/reservesys') self.assertEquals(reserve_task.params[0].name, 'RESERVETIME') self.assertEquals(reserve_task.params[0].value, '345600') # 4 days in seconds
def test_can_reserve_manual_system(self): with session.begin(): broken_system = data_setup.create_system( arch=u"i386", shared=True, status=SystemStatus.broken, lab_controller=self.lc ) manual_system = data_setup.create_system( arch=u"i386", shared=True, status=SystemStatus.manual, lab_controller=self.lc ) b = self.browser login(b) # broken system should not be present go_to_reserve_systems(b, distro_tree=self.distro_tree_i386) search_for_system(b, broken_system) check_system_search_results(b, absent=[broken_system]) # provision manual system go_to_reserve_systems(b, distro_tree=self.distro_tree_i386) search_for_system(b, manual_system) row = b.find_element_by_xpath('//tr[normalize-space(string(td))="%s"]' % manual_system.fqdn) row.find_element_by_link_text("Reserve Now").click() b.find_element_by_xpath('//button[normalize-space(text())="Submit job"]').click() # should end up on the job page job_id = b.find_element_by_xpath('//td[preceding-sibling::th/text()="Job ID"]/a').text with session.begin(): job = TaskBase.get_by_t_id(job_id) cloned_job_xml = job.to_xml(clone=True).toxml() # cloning re-parses hostRequires self.assertIn(u'<hostRequires force="%s"/>' % manual_system.fqdn, cloned_job_xml)
def set_retention_product(self, job_t_id, retention_tag_name, product_name): """ XML-RPC method to update a job's retention tag, product, or both. There is an important distinction between product_name of None, which means do not change the existing value, vs. empty string, which means clear the existing product. """ job = TaskBase.get_by_t_id(job_t_id) if job.can_change_product(identity.current.user) and \ job.can_change_retention_tag(identity.current.user): if retention_tag_name and product_name: retention_tag = RetentionTag.by_name(retention_tag_name) product = Product.by_name(product_name) old_tag = job.retention_tag if job.retention_tag else None result = Utility.update_retention_tag_and_product( job, retention_tag, product) job.record_activity(user=identity.current.user, service=u'XMLRPC', field=u'Retention Tag', action='Changed', old=old_tag.tag, new=retention_tag.tag) elif retention_tag_name and product_name == '': retention_tag = RetentionTag.by_name(retention_tag_name) old_tag = job.retention_tag if job.retention_tag else None result = Utility.update_retention_tag_and_product( job, retention_tag, None) job.record_activity(user=identity.current.user, service=u'XMLRPC', field=u'Retention Tag', action='Changed', old=old_tag.tag, new=retention_tag.tag) elif retention_tag_name: retention_tag = RetentionTag.by_name(retention_tag_name) old_tag = job.retention_tag if job.retention_tag else None result = Utility.update_retention_tag(job, retention_tag) job.record_activity(user=identity.current.user, service=u'XMLRPC', field=u'Retention Tag', action='Changed', old=old_tag.tag, new=retention_tag.tag) elif product_name: product = Product.by_name(product_name) result = Utility.update_product(job, product) elif product_name == '': result = Utility.update_product(job, None) else: result = {'success': False, 'msg': 'Nothing to do'} if not result['success'] is True: raise BeakerException( 'Job %s not updated: %s' % (job.id, result.get('msg', 'Unknown reason'))) else: raise BeakerException('No permission to modify %s' % job)
def test_external_tasks(self): job_tid = self.server.jobs.upload(''' <job> <whiteboard>job with external task</whiteboard> <recipeSet> <recipe> <distroRequires> <distro_name op="=" value="BlueShoeLinux5-5" /> </distroRequires> <hostRequires/> <task name="/distribution/install" /> <task name="/distribution/example"> <fetch url="git://example.com/externaltasks/example#master"/> </task> <task> <fetch url="git://example.com/externaltasks/example2#master"/> </task> <task name="/distribution/example3"> <fetch url="git://example.com/externaltasks#master" subdir="examples/3" /> </task> <task> <fetch url="git://example.com/externaltasks#master" subdir="examples/4" /> </task> </recipe> </recipeSet> </job> ''') self.assert_(job_tid.startswith('J:')) with session.begin(): job = TaskBase.get_by_t_id(job_tid) recipe = job.recipesets[0].recipes[0] self.assertEquals(len(recipe.tasks), 5) self.assertEquals(recipe.tasks[0].name, u'/distribution/install') self.assertEquals(recipe.tasks[0].task.name, u'/distribution/install') self.assertEquals(recipe.tasks[0].fetch_url, None) self.assertEquals(recipe.tasks[1].name, u'/distribution/example') self.assertEquals(recipe.tasks[1].task, None) self.assertEquals(recipe.tasks[1].fetch_url, 'git://example.com/externaltasks/example#master') self.assertEquals(recipe.tasks[2].name, u'git://example.com/externaltasks/example2#master') self.assertEquals(recipe.tasks[2].task, None) self.assertEquals(recipe.tasks[2].fetch_url, u'git://example.com/externaltasks/example2#master') self.assertEquals(recipe.tasks[3].name, u'/distribution/example3') self.assertEquals(recipe.tasks[3].task, None) self.assertEquals(recipe.tasks[3].fetch_url, u'git://example.com/externaltasks#master') self.assertEquals(recipe.tasks[3].fetch_subdir, u'examples/3') self.assertEquals(recipe.tasks[4].name, u'git://example.com/externaltasks#master examples/4') self.assertEquals(recipe.tasks[4].task, None) self.assertEquals(recipe.tasks[4].fetch_url, u'git://example.com/externaltasks#master') self.assertEquals(recipe.tasks[4].fetch_subdir, u'examples/4')
def files(self, taskid): """ Returns an array of XML-RPC structures (dicts) describing each of the result files for the given job component and its descendants. :param taskid: see above :type taskid: string """ return [l.dict for l in TaskBase.get_by_t_id(taskid).all_logs()]
def task_info(self, taskid,flat=True): """ Returns an XML-RPC structure (dict) describing the current state of the given job component. :param taskid: see above :type taskid: string """ return TaskBase.get_by_t_id(taskid).task_info()
def delete_jobs(self, jobs=None, tag=None, complete_days=None, family=None, dryrun=False, product=None): """ delete_jobs will mark the job to be deleted To select jobs by id, pass an array for the *jobs* argument. Elements of the array must be strings of the form ``'J:123'``. Alternatively, pass some combination of the *tag*, *complete_days*, or *family* arguments to select jobs for deletion. These arguments behave as per the :meth:`jobs.list` method. If *dryrun* is True, deletions will be reported but nothing will be modified. Admins are not be able to delete jobs which are not owned by themselves by using the tag, complete_days etc kwargs, instead, they should do that via the *jobs* argument. """ if jobs: #Turn them into job objects if not isinstance(jobs, list): jobs = [jobs] jobs_to_try_to_del = [] for j_id in jobs: job = TaskBase.get_by_t_id(j_id) if not isinstance(job, Job): raise BeakerException('Incorrect task type passed %s' % j_id) if not job.can_delete(identity.current.user): raise BeakerException( "You don't have permission to delete job %s" % j_id) jobs_to_try_to_del.append(job) delete_jobs_kw = dict(jobs=jobs_to_try_to_del) else: # only allow people to delete their own jobs while using these kwargs delete_jobs_kw = dict( query=Job.find_jobs(tag=tag, complete_days=complete_days, family=family, product=product, owner=identity.current.user.user_name)) deleted_jobs = Job.delete_jobs(**delete_jobs_kw) msg = 'Jobs deleted' if dryrun: session.rollback() msg = 'Dryrun only. %s' % (msg) return '%s: %s' % (msg, [j.t_id for j in deleted_jobs])
def test_retention_tag_product(self): with session.begin(): rt1 = data_setup.create_retention_tag() rt2 = data_setup.create_retention_tag(needs_product=True) p1 = data_setup.create_product() out = run_client(['bkr', 'job-modify', self.job.t_id, '--retention-tag', '%s' % rt1.tag]) self.assert_(out == 'Successfully modified jobs %s\n' % self.job.t_id) session.expunge_all() j = TaskBase.get_by_t_id(self.job.t_id) self.assert_(j.retention_tag.tag == rt1.tag) out = run_client(['bkr', 'job-modify', self.job.t_id, '--retention-tag', '%s' % rt2.tag, '--product', '%s' % p1.name]) self.assert_(out == 'Successfully modified jobs %s\n' % self.job.t_id) session.expunge_all() j = TaskBase.get_by_t_id(self.job.t_id) self.assert_(j.retention_tag.tag == rt2.tag) self.assert_(j.product.name == p1.name) out = run_client(['bkr', 'job-modify', self.job.t_id, '--retention-tag', '%s' % rt1.tag, '--product=']) self.assert_(out == 'Successfully modified jobs %s\n' % self.job.t_id) session.expunge_all() j = TaskBase.get_by_t_id(self.job.t_id) self.assert_(j.retention_tag.tag == rt1.tag) self.assert_(j.product is None)
def set_response(self, taskid, response): """ Updates the response (ack/nak) for a recipe set, or for all recipe sets in a job. This is part of the results reviewing system. :param taskid: see above :type taskid: string :param response: new response, either ``'ack'`` or ``'nak'`` :type response: string """ job = TaskBase.get_by_t_id(taskid) if job.can_set_response(identity.current.user): job.set_response(response) else: raise BeakerException('No permission to modify %s' % job)
def test_only_reserves_machines(self): login(self.browser) b = self.browser b.get(get_server_base() + "reserveworkflow") Select(b.find_element_by_name("tag")).select_by_visible_text("None selected") Select(b.find_element_by_name("osmajor")).select_by_visible_text(self.distro.osversion.osmajor.osmajor) Select(b.find_element_by_name("distro")).select_by_visible_text(self.distro.name) Select(b.find_element_by_name("distro_tree_id")).select_by_visible_text("%s Server i386" % self.distro.name) b.find_element_by_xpath('//button[normalize-space(text())="Submit job"]').click() # should end up on the job page job_id = b.find_element_by_xpath('//td[preceding-sibling::th/text()="Job ID"]/a').text with session.begin(): job = TaskBase.get_by_t_id(job_id) recipe = job.recipesets[0].recipes[0] self.assertEquals(recipe.host_requires, u'<hostRequires><system_type value="Machine"/></hostRequires>')
def test_uses_new_check_install_task(self): login(self.browser) b = self.browser b.get(get_server_base() + 'reserveworkflow/') Select(b.find_element_by_name('osmajor'))\ .select_by_visible_text(self.distro.osversion.osmajor.osmajor) Select(b.find_element_by_name('distro')).select_by_visible_text(self.distro.name) Select(b.find_element_by_name('distro_tree_id'))\ .select_by_visible_text('%s Server i386' % self.distro.name) b.find_element_by_xpath('//button[normalize-space(text())="Submit job"]').click() # should end up on the job page jid = b.find_element_by_xpath('//h1//span[@class="job-id"]').text with session.begin(): job = TaskBase.get_by_t_id(jid) # first task in the recipe should be our new check-install task first_task = job.recipesets[0].recipes[0].tasks[0] self.assertEquals(first_task.task.name, '/distribution/check-install')
def test_only_reserves_machines(self): login(self.browser) b = self.browser b.get(get_server_base() + 'reserveworkflow') Select(b.find_element_by_name('tag')).select_by_visible_text('None selected') Select(b.find_element_by_name('osmajor'))\ .select_by_visible_text(self.distro.osversion.osmajor.osmajor) Select(b.find_element_by_name('distro')).select_by_visible_text(self.distro.name) Select(b.find_element_by_name('distro_tree_id'))\ .select_by_visible_text('%s Server i386' % self.distro.name) b.find_element_by_xpath('//button[normalize-space(text())="Submit job"]').click() # should end up on the job page job_id = b.find_element_by_xpath('//td[preceding-sibling::th/text()="Job ID"]/a').text with session.begin(): job = TaskBase.get_by_t_id(job_id) recipe = job.recipesets[0].recipes[0] self.assertEquals(recipe.host_requires, u'<hostRequires><system_type value="Machine"/></hostRequires>')
def test_reserve_time(self): login(self.browser) b = self.browser b.get(get_server_base() + "reserveworkflow/") Select(b.find_element_by_name("osmajor")).select_by_visible_text(self.distro.osversion.osmajor.osmajor) Select(b.find_element_by_name("distro")).select_by_visible_text(self.distro.name) Select(b.find_element_by_name("distro_tree_id")).select_by_visible_text("%s Server i386" % self.distro.name) b.find_element_by_name("reserve_days").clear() b.find_element_by_name("reserve_days").send_keys("4") b.find_element_by_xpath('//button[normalize-space(text())="Submit job"]').click() # should end up on the job page jid = b.find_element_by_xpath('//td[preceding-sibling::th/text()="Job ID"]/a').text with session.begin(): job = TaskBase.get_by_t_id(jid) reserve_task = job.recipesets[0].recipes[0].tasks[1] self.assertEquals(reserve_task.task.name, "/distribution/reservesys") self.assertEquals(reserve_task.params[0].name, "RESERVETIME") self.assertEquals(reserve_task.params[0].value, "345600") # 4 days in seconds
def test_only_reserves_machines(self): login(self.browser) b = self.browser b.get(get_server_base() + 'reserveworkflow') Select(b.find_element_by_name('tag')).select_by_visible_text('None selected') Select(b.find_element_by_name('osmajor'))\ .select_by_visible_text(self.distro.osversion.osmajor.osmajor) Select(b.find_element_by_name('distro')).select_by_visible_text(self.distro.name) Select(b.find_element_by_name('distro_tree_id'))\ .select_by_visible_text('%s Server i386' % self.distro.name) b.find_element_by_xpath('//button[normalize-space(text())="Submit job"]').click() # should end up on the job page job_id = b.find_element_by_xpath('//h1//span[@class="job-id"]').text with session.begin(): job = TaskBase.get_by_t_id(job_id) recipe = job.recipesets[0].recipes[0] self.assertEquals(recipe.host_requires, u'<hostRequires><system_type value="Machine"/></hostRequires>')
def delete_jobs(self, jobs=None, tag=None, complete_days=None, family=None, dryrun=False, product=None): """ delete_jobs will mark the job to be deleted To select jobs by id, pass an array for the *jobs* argument. Elements of the array must be strings of the form ``'J:123'``. Alternatively, pass some combination of the *tag*, *complete_days*, or *family* arguments to select jobs for deletion. These arguments behave as per the :meth:`jobs.list` method. If *dryrun* is True, deletions will be reported but nothing will be modified. Admins are not be able to delete jobs which are not owned by themselves by using the tag, complete_days etc kwargs, instead, they should do that via the *jobs* argument. """ if jobs: #Turn them into job objects if not isinstance(jobs,list): jobs = [jobs] jobs_to_try_to_del = [] for j_id in jobs: job = TaskBase.get_by_t_id(j_id) if not isinstance(job,Job): raise BeakerException('Incorrect task type passed %s' % j_id ) if not job.can_delete(identity.current.user): raise BeakerException("You don't have permission to delete job %s" % j_id) jobs_to_try_to_del.append(job) delete_jobs_kw = dict(jobs=jobs_to_try_to_del) else: # only allow people to delete their own jobs while using these kwargs delete_jobs_kw = dict(query=Job.find_jobs(tag=tag, complete_days=complete_days, family=family, product=product, owner=identity.current.user.user_name)) deleted_jobs = Job.delete_jobs(**delete_jobs_kw) msg = 'Jobs deleted' if dryrun: session.rollback() msg = 'Dryrun only. %s' % (msg) return '%s: %s' % (msg, [j.t_id for j in deleted_jobs])
def test_preserves_lab_requirement(self): login(self.browser) b = self.browser b.get(get_server_base() + "reserveworkflow") Select(b.find_element_by_name("osmajor")).select_by_visible_text(self.distro.osversion.osmajor.osmajor) Select(b.find_element_by_name("distro")).select_by_visible_text(self.distro.name) Select(b.find_element_by_name("distro_tree_id")).select_by_visible_text("%s Server i386" % self.distro.name) b.find_element_by_xpath('//label[contains(string(.), "Any system from lab:")]' '/input[@type="radio"]').click() Select(b.find_element_by_name("lab")).select_by_visible_text(self.lc.fqdn) b.find_element_by_xpath('//button[normalize-space(text())="Submit job"]').click() # should end up on the job page job_id = b.find_element_by_xpath('//td[preceding-sibling::th/text()="Job ID"]/a').text with session.begin(): job = TaskBase.get_by_t_id(job_id) cloned_job_xml = job.to_xml(clone=True).toxml() # cloning re-parses hostRequires self.assertIn( u'<hostRequires><labcontroller op="=" value="%s"/>' u'<system_type op="=" value="Machine"/></hostRequires>' % self.lc.fqdn, cloned_job_xml, )
def test_uses_new_check_install_task(self): login(self.browser) b = self.browser b.get(get_server_base() + 'reserveworkflow/') Select(b.find_element_by_name('osmajor'))\ .select_by_visible_text(self.distro.osversion.osmajor.osmajor) Select(b.find_element_by_name('distro')).select_by_visible_text( self.distro.name) Select(b.find_element_by_name('distro_tree_id'))\ .select_by_visible_text('%s Server i386' % self.distro.name) b.find_element_by_xpath( '//button[normalize-space(text())="Submit job"]').click() # should end up on the job page jid = b.find_element_by_xpath('//h1//span[@class="job-id"]').text with session.begin(): job = TaskBase.get_by_t_id(jid) # first task in the recipe should be our new check-install task first_task = job.recipesets[0].recipes[0].tasks[0] self.assertEquals(first_task.task.name, '/distribution/check-install')
def test_reserve_time(self): login(self.browser) b = self.browser b.get(get_server_base() + 'reserveworkflow/') Select(b.find_element_by_name('osmajor'))\ .select_by_visible_text(self.distro.osversion.osmajor.osmajor) Select(b.find_element_by_name('distro')).select_by_visible_text(self.distro.name) Select(b.find_element_by_name('distro_tree_id'))\ .select_by_visible_text('%s Server i386' % self.distro.name) b.find_element_by_name('reserve_duration').clear() b.find_element_by_name('reserve_duration').send_keys('96') b.find_element_by_xpath('.//button[text()="Hours"]').click() b.find_element_by_xpath('//button[normalize-space(text())="Submit job"]').click() # should end up on the job page jid = b.find_element_by_xpath('//h1//span[@class="job-id"]').text with session.begin(): job = TaskBase.get_by_t_id(jid) reserve_task = job.recipesets[0].recipes[0].tasks[1] self.assertEquals(reserve_task.task.name, '/distribution/reservesys') self.assertEquals(reserve_task.params[0].name, 'RESERVETIME') self.assertEquals(reserve_task.params[0].value, '345600') # 4 days in seconds
def test_can_reserve_manual_system(self): with session.begin(): broken_system = data_setup.create_system( arch=u'i386', shared=True, status=SystemStatus.broken, lab_controller=self.lc) manual_system = data_setup.create_system( arch=u'i386', shared=True, status=SystemStatus.manual, lab_controller=self.lc) b = self.browser login(b) # broken system should not be present go_to_reserve_systems(b, distro_tree=self.distro_tree_i386) search_for_system(b, broken_system) check_system_search_results(b, absent=[broken_system]) # provision manual system go_to_reserve_systems(b, distro_tree=self.distro_tree_i386) search_for_system(b, manual_system) row = b.find_element_by_xpath( '//tr[normalize-space(string(td))="%s"]' % manual_system.fqdn) row.find_element_by_link_text('Reserve Now').click() b.find_element_by_xpath( '//button[normalize-space(text())="Submit job"]').click() # should end up on the job page job_id = b.find_element_by_xpath('//h1//span[@class="job-id"]').text wb_descr = (WORKFLOW_DESCR % ("None", "a specific system", "86400")) wboard = b.find_element_by_class_name('job-whiteboard') self.assertIn(wb_descr, wboard.text, msg="Fail to match default whiteboard") with session.begin(): job = TaskBase.get_by_t_id(job_id) cloned_job_xml = lxml.etree.tostring( job.to_xml(clone=True), encoding=unicode) # cloning re-parses hostRequires self.assertIn(u'<hostRequires force="%s"/>' % manual_system.fqdn, cloned_job_xml)
def extend_watchdog_by_taskspec(taskspec): """ Extend the watchdog for a recipe identified by a taskspec. The valid type of a taskspec is either R(recipe) or T(recipe-task). See :ref:`Specifying tasks <taskspec>` in :manpage:`bkr(1)`. :param taskspec: A taskspec argument that identifies a recipe or recipe task. :jsonparam string kill_time: Time in seconds to extend the watchdog by. """ if not taskspec.startswith(('R', 'T')): raise BadRequest400('Taskspec type must be one of [R, T]') try: obj = TaskBase.get_by_t_id(taskspec) except BeakerException as exc: raise NotFound404(unicode(exc)) if isinstance(obj, Recipe): recipe = obj else: recipe = obj.recipe data = read_json_request(request) return _extend_watchdog(recipe.id, data)
def test_preserves_lab_requirement(self): login(self.browser) b = self.browser b.get(get_server_base() + 'reserveworkflow') Select(b.find_element_by_name('osmajor'))\ .select_by_visible_text(self.distro.osversion.osmajor.osmajor) Select(b.find_element_by_name('distro')).select_by_visible_text(self.distro.name) Select(b.find_element_by_name('distro_tree_id'))\ .select_by_visible_text('%s Server i386' % self.distro.name) b.find_element_by_xpath( '//label[contains(string(.), "Any system from lab:")]' '/input[@type="radio"]').click() Select(b.find_element_by_name('lab')).select_by_visible_text(self.lc.fqdn) b.find_element_by_xpath('//button[normalize-space(text())="Submit job"]').click() # should end up on the job page job_id = b.find_element_by_xpath('//h1//span[@class="job-id"]').text with session.begin(): job = TaskBase.get_by_t_id(job_id) cloned_job_xml = lxml.etree.tostring(job.to_xml(clone=True), encoding=unicode) # cloning re-parses hostRequires self.assertIn( u'<hostRequires><labcontroller op="=" value="%s"/>' u'<system_type op="=" value="Machine"/></hostRequires>' % self.lc.fqdn, cloned_job_xml)
def test_preserves_lab_requirement(self): login(self.browser) b = self.browser b.get(get_server_base() + 'reserveworkflow') Select(b.find_element_by_name('osmajor'))\ .select_by_visible_text(self.distro.osversion.osmajor.osmajor) Select(b.find_element_by_name('distro')).select_by_visible_text(self.distro.name) Select(b.find_element_by_name('distro_tree_id'))\ .select_by_visible_text('%s Server i386' % self.distro.name) b.find_element_by_xpath( '//label[contains(string(.), "Any system from lab:")]' '/input[@type="radio"]').click() Select(b.find_element_by_name('lab')).select_by_visible_text(self.lc.fqdn) b.find_element_by_xpath('//button[normalize-space(text())="Submit job"]').click() # should end up on the job page job_id = b.find_element_by_xpath('//td[preceding-sibling::th/text()="Job ID"]/a').text with session.begin(): job = TaskBase.get_by_t_id(job_id) cloned_job_xml = job.to_xml(clone=True).toxml() # cloning re-parses hostRequires self.assertIn( u'<hostRequires><labcontroller op="=" value="%s"/>' u'<system_type op="=" value="Machine"/></hostRequires>' % self.lc.fqdn, cloned_job_xml)
def files(self, taskid): """ Returns an array of XML-RPC structures (dicts) describing each of the result files for the given job component and its descendants. """ return TaskBase.get_by_t_id(taskid).all_logs
def _delete_job(self, t_id): job = TaskBase.get_by_t_id(t_id) self._check_job_deletability(t_id, job) Job.delete_jobs([job]) return [t_id]
def set_response(self, job_t_id, response): job = TaskBase.get_by_t_id(job_t_id) if job.can_set_response(identity.current.user): job.set_response(response) else: raise BeakerException('No permission to modify %s' % job)
def test_ack_job(self): out = run_client(['bkr', 'job-modify', self.job.t_id, '--response', 'ack']) self.assert_(out == 'Successfully modified jobs %s\n' % self.job.t_id) j = TaskBase.get_by_t_id(self.job.t_id) for rs in j.recipesets: self.assert_('%s' % rs.nacked.response == 'ack')
def test_nak_rs(self): out = run_client(['bkr', 'job-modify', self.job.recipesets[0].t_id, '--response', 'nak']) self.assert_(out == 'Successfully modified jobs %s\n' % self.job.recipesets[0].t_id) rs = TaskBase.get_by_t_id(self.job.recipesets[0].t_id) self.assert_('%s' % rs.nacked.response == 'nak')