def _gen_bot_info(key_id, last_seen_ts, **kwargs): args = { 'key': ndb.Key('BotRoot', key_id, 'BotInfo', 'info'), 'last_seen_ts': last_seen_ts, 'dimensions': { 'os': ['Linux', 'Ubuntu'], 'bot_id': [key_id], }, } args.update(**kwargs) args['dimensions_flat'] = bot_management.dimensions_to_flat( args.pop('dimensions')) return bot_management.BotInfo(**args)
def get(self, bot_id): # pagination is currently for tasks, not events. limit = int(self.request.get('limit', 100)) cursor = datastore_query.Cursor(urlsafe=self.request.get('cursor')) run_results_future = task_result.TaskRunResult.query( task_result.TaskRunResult.bot_id == bot_id).order( -task_result.TaskRunResult.started_ts).fetch_page_async( limit, start_cursor=cursor) bot_future = bot_management.get_info_key(bot_id).get_async() events_future = bot_management.get_events_query( bot_id, True).fetch_async(100) now = utils.utcnow() # Calculate the time this bot was idle. idle_time = datetime.timedelta() run_time = datetime.timedelta() run_results, cursor, more = run_results_future.get_result() if run_results: run_time = run_results[0].duration_now(now) or datetime.timedelta() if not cursor and run_results[0].state != task_result.State.RUNNING: # Add idle time since last task completed. Do not do this when a cursor # is used since it's not representative. idle_time = now - run_results[0].ended_ts for index in xrange(1, len(run_results)): # .started_ts will always be set by definition but .ended_ts may be None # if the task was abandoned. We can't count idle time since the bot may # have been busy running *another task*. # TODO(maruel): One option is to add a third value "broken_time". # Looking at timestamps specifically could help too, e.g. comparing # ended_ts of this task vs the next one to see if the bot was assigned # two tasks simultaneously. if run_results[index].ended_ts: idle_time += ( run_results[index-1].started_ts - run_results[index].ended_ts) # We are taking the whole time the bot was doing work, not just the # duration associated with the task. duration = run_results[index].duration_as_seen_by_server if duration: run_time += duration events = events_future.get_result() bot = bot_future.get_result() if not bot and events: # If there is not BotInfo, look if there are BotEvent child of this # entity. If this is the case, it means the bot was deleted but it's # useful to show information about it to the user even if the bot was # deleted. For example, it could be an auto-scaled bot. bot = bot_management.BotInfo( key=bot_management.get_info_key(bot_id), dimensions_flat=bot_management.dimensions_to_flat( events[0].dimensions), state=events[0].state, external_ip=events[0].external_ip, authenticated_as=events[0].authenticated_as, version=events[0].version, quarantined=events[0].quarantined, task_id=events[0].task_id, last_seen_ts=events[0].ts) params = { 'bot': bot, 'bot_id': bot_id, 'current_version': bot_code.get_bot_version(self.request.host_url), 'cursor': cursor.urlsafe() if cursor and more else None, 'events': events, 'idle_time': idle_time, 'is_admin': acl.is_admin(), 'limit': limit, 'now': now, 'run_results': run_results, 'run_time': run_time, 'try_link': '/bot?id=%s' % bot_id, 'xsrf_token': self.generate_xsrf_token(), } self.response.write( template.render('swarming/restricted_bot.html', params))
def test_dimensions_to_flat(self): self.assertEqual(['a:b', 'c:d'], bot_management.dimensions_to_flat({ 'a': 'b', 'c': 'd' }))