class TSExperimentSvcAgent(TSLocalAgent): agentId = expsvcAgentId uuid = expsvcAgentUUID agentType = expsvcAgentType def __init__(self, server, connString): TSLocalAgent.__init__(self, server) self.rootAgent = server.localAgents[0] self.userAgent = server.localAgents[1] self.database = create_database(connString) self.dbStore = Store(self.database) self.server.listenerAgents.append(AgentListener('load', self.onAgentRegister, self.onAgentDisconnect)) self.loadAgents = {} self.resourceManager = ResourceManager(self.dbStore) @inlineCallbacks def registerNewAgent(self, client, agent): hostInfo = yield agent.getHostInfo() agentObj = Agent() agentObj.uuid = uuid.UUID(client.agentUuid) agentObj.agentType = 'load' # FIXME: Sometimes domainname passed with hostname agentObj.hostname = unicode(hostInfo.hostname) agentObj.domainname = unicode(hostInfo.domainname) agentObj.osname = hostInfo.osname agentObj.release = hostInfo.release agentObj.machineArch = hostInfo.machineArch agentObj.numCPUs = hostInfo.numCPUs agentObj.numCores = hostInfo.numCores agentObj.memTotal = hostInfo.memTotal agentObj.lastOnline = datetime.now() yield self.dbStore.add(agentObj) yield self.dbStore.commit() returnValue(agentObj) @inlineCallbacks def onAgentRegister(self, client): if client.agentType == 'load': if client.agentUuid in self.loadAgents: raise JSONTS.Error(JSONTS.AE_INVALID_STATE, "Loader agent with uuid '%s' already registered" % client.agentUuid) agentId = client.getId() agent = self.createRemoteAgent(agentId, LoadAgent) agentSet = yield self.dbStore.find(Agent, Agent.uuid == uuid.UUID(client.agentUuid)) agentObj = yield agentSet.one() if agentObj is None: agentObj = yield self.registerNewAgent(client, agent) else: # Update last online timestamp agentObj.lastOnline = datetime.now() yield self.dbStore.add(agentObj) yield self.dbStore.commit() agentInfo = LoadAgentInfo(agent, agentObj) self.loadAgents[client.agentUuid] = agentInfo print "Registered agent %s with uuid '%s'" % (agentObj.hostname, client.agentUuid) reactor.callLater(0.0, self.fetchWorkloadTypes, agent, agentObj) reactor.callLater(0.1, self.resourceManager.registerLoadAgent, agent, agentObj) def onAgentDisconnect(self, client): if client.agentType == 'load': yield self.resourceManager.unregisterLoadAgent(agentInfo.agentObj) agentInfo = self.loadAgents[client.agentUuid] print 'Disconnected agent %s' % agentInfo.agentObj.hostname del self.loadAgents[client.agentUuid] @inlineCallbacks def fetchWorkloadTypes(self, agent, agentObj): wltypeList = yield agent.getWorkloadTypes() wltSet = yield self.dbStore.find(WorkloadType, WorkloadType.agent == agentObj) for wltypeName, wltype in wltypeList.iteritems(): wltObj = wltSet.find(WorkloadType.name == wltypeName) wltObj = wltObj.any() if wltObj is None: wltObj = WorkloadType() wltObj.agent = agentObj wltObj.name = wltypeName wltObj.module = wltype.module wltObj.modulePath = wltype.path wltObj.classList = ','.join(wltype.wlclass) yield self.dbStore.add(wltObj) paramSet = yield self.dbStore.find(WorkloadParam, WorkloadParam.workloadType == wltObj) # Update parameter list for paramObj in paramSet: if paramObj.name not in wltype.params: paramObj.remove() continue paramObj.data = wltype.params.serialize() # Remove serialized object from params array del wltype.params[paramObj.name] yield self.dbStore.add(paramObj) for paramName, param in wltype.params.iteritems(): paramObj = WorkloadParam() paramObj.name = paramName paramObj.workloadType = wltObj paramObj.paramData = TSWorkloadParameter.serialize(param) yield self.dbStore.add(paramObj) yield self.dbStore.commit() @TSMethodImpl(ExpSvcAgent.listAgents) @inlineCallbacks def listAgents(self, context): agentsList = {} agentSet = yield self.dbStore.find(Agent) for agentObj in agentSet: # TODO: should filter agents according to users ACL agentUuid = str(agentObj.uuid) descriptor = TSExpSvcAgentDescriptor() descriptor.agentId = agentObj.id descriptor.lastOnline = datetimeToTSTime(agentObj.lastOnline) descriptor.isOnline = agentUuid in self.loadAgents for field in ('hostname', 'domainname', 'osname', 'release', 'machineArch', 'numCPUs', 'numCores', 'memTotal'): setattr(descriptor, field, getattr(agentObj, field)) agentsList[agentUuid] = descriptor returnValue(agentsList) @TSMethodImpl(ExpSvcAgent.getWorkloadTypes) @inlineCallbacks def getWorkloadTypes(self, context, agentId): wltSet = yield self.dbStore.find(WorkloadType, WorkloadType.aid == agentId) paramsQuery = (WorkloadParam, Join(WorkloadType, And(WorkloadType.aid == agentId, WorkloadParam.wltid == WorkloadType.id))) paramsGlobalSet = yield self.dbStore.using(*paramsQuery).find(WorkloadParam) wltypeList = {} for wltObj in wltSet: paramsSet = yield paramsGlobalSet.find(WorkloadParam.workloadType == wltObj) wltype = TSWorkloadType() wltype.module = wltObj.module wltype.path = wltObj.modulePath wltype.wlclass = wltObj.classList.split(',') wltype.params = {} for paramObj in paramsSet: param = TSWorkloadParameter.deserialize(paramObj.paramData) wltype.params[paramObj.name] = param wltypeList[wltObj.name] = wltype returnValue(wltypeList) @TSMethodImpl(ExpSvcAgent.getAgentResources) @inlineCallbacks def getAgentResources(self, context, agentId): resourceInfo = yield self.resourceManager.getAgentResources(agentId) returnValue(resourceInfo) @inlineCallbacks def _getProfileObj(self, context, profileName, profile): client = context.client if client.auth == TSServerClient.AUTH_MASTER or \ client.auth == TSServerClient.AUTH_ADMIN: userId = profile.userId if profile.userId is not None else 0 else: agentId = client.getId() userId = self.userAgent.agentUsers[agentId] profileSet = yield self.dbStore.find(ExperimentProfile, And(ExperimentProfile.name == unicode(profileName), ExperimentProfile.userId == userId)) returnValue((profileSet.one(), userId)) @TSMethodImpl(ExpSvcAgent.listProfiles) @inlineCallbacks def listProfiles(self, context): '''If context is of administrative rights (master.key or admin), list all experiments, or select only owned experiment''' client = context.client # TODO: Support for experiment sharing profiles = {} if client.auth == TSServerClient.AUTH_MASTER or \ client.auth == TSServerClient.AUTH_ADMIN: profileSet = yield self.dbStore.find(ExperimentProfile) else: agentId = client.getId() userId = self.userAgent.agentUsers[agentId] profileSet = yield self.dbStore.find(ExperimentProfile, ExperimentProfile.userId == userId) for profileObj in profileSet: profiles[profileObj.name] = _profileObjToTSO(profileObj, TSExperimentProfileInfo) returnValue(profiles) @TSMethodImpl(ExpSvcAgent.getProfile) @inlineCallbacks def getProfile(self, context, profileName, profile): profileObj, _ = yield self._getProfileObj(context, profileName, profile) fullProfile = _profileObjToTSO(profileObj, TSExperimentProfile) fullProfile.threadpools = {} fullProfile.workloads = {} threadpoolSet = yield self.dbStore.find(ExperimentThreadPool, ExperimentThreadPool.profile == profileObj) for threadpoolObj in threadpoolSet: threadpool = TSExperimentThreadPool() threadpool.agentId = threadpoolObj.aid threadpool.numWorkers = threadpoolObj.numWorkers fullProfile.threadpools[threadpoolObj.name] = threadpool workloadSet = yield self.dbStore.find(ExperimentWorkload, ExperimentWorkload.profile == profileObj) for workloadObj in workloadSet: workload = TSExperimentWorkload() workload.agentId = workloadObj.threadpool.aid if workloadObj.threadpool is not None else -1 workload.workloadType = workloadObj.workloadType.name if workloadObj.workloadType is not None else '' workload.threadpool = workloadObj.threadpool.name if workloadObj.threadpool is not None else '' workload.params = workloadObj.params fullProfile.workloads[workloadObj.name] = workload returnValue(fullProfile) @TSMethodImpl(ExpSvcAgent.configureProfile) @inlineCallbacks def configureProfile(self, context, profileName, profile): profileObj, userId = yield self._getProfileObj(context, profileName, profile) newProfile = False threadpools = {} if profileObj is None: profileObj = ExperimentProfile() profileObj.name = unicode(profileName) profileObj.userId = userId profileObj.creationDate = datetime.now() newProfile = True profileObj.description = unicode(profile.description) yield self.dbStore.add(profileObj) if not newProfile: threadpoolSet = yield self.dbStore.find(ExperimentThreadPool, ExperimentThreadPool.profile == profileObj) # Update or remove existing threadpools for threadpoolObj in threadpoolSet: if threadpoolObj.name in profile.threadpools: threadpool = profile.threadpools[threadpoolObj.name] threadpoolObj.aid = threadpool.agentId threadpoolObj.numWorkers = threadpool.numWorkers del profile.threadpools[threadpoolObj.name] yield self.dbStore.add(threadpoolObj) threadpools[threadpoolObj.name] = threadpoolObj else: yield self.dbStore.remove(threadpoolObj) # Add new threadpools for threadpoolName, threadpool in profile.threadpools.iteritems(): threadpoolObj = ExperimentThreadPool() threadpoolObj.name = unicode(threadpoolName) threadpoolObj.aid = threadpool.agentId threadpoolObj.profile = profileObj threadpoolObj.numWorkers = threadpool.numWorkers threadpools[threadpoolName] = threadpoolObj yield self.dbStore.add(threadpoolObj) @inlineCallbacks def _setWorkloadType(workload, workloadObj): if workload.workloadType is not None and workload.agentId is not None: workloadTypeSet = yield self.dbStore.find(WorkloadType, And(WorkloadType.aid == workload.agentId, WorkloadType.name == unicode(workload.workloadType))) workloadTypeObj = workloadTypeSet.one() workloadObj.wltid = workloadTypeObj.id else: workloadObj.wltid = None def _setThreadpool(workload, workloadObj): workloadObj.tpid = threadpools[workloadObj.name].id \ if workload.threadpool is not None \ else None if not newProfile: workloadSet = yield self.dbStore.find(ExperimentWorkload, ExperimentWorkload.profile == profileObj) for workloadObj in workloadSet: if workloadObj.name in profile.workloads: workload = profile.workloads[workloadObj.name] _setThreadpool(workload, workloadObj) yield _setWorkloadType(workload, workloadObj) workloadObj.params = workload.params del profile.workloads[workloadObj.name] yield self.dbStore.add(workloadObj) else: yield self.dbStore.remove(workloadObj) for workloadName, workload in profile.workloads.iteritems(): workloadObj = ExperimentWorkload() workloadObj.name = unicode(workloadName) workloadObj.profile = profileObj _setThreadpool(workload, workloadObj) yield _setWorkloadType(workload, workloadObj) workloadObj.params = workload.params # TODO: implement workload steps workloadObj.stepsId = None yield self.dbStore.add(workloadObj) yield self.dbStore.commit()
class Form(GladeDelegate): widgets = ['name', 'number', 'category'] race_widgets = ['start_hour', 'time_elapsed'] def __init__(self): GladeDelegate.__init__(self, gladefile="interface.ui", delete_handler=self.quit_if_last) self.proxy = None self.db = create_database("sqlite:laps.sqlite") self.store = Store(self.db) self.race = self._check_race() self.race_proxy = self.add_proxy(self.race, self.race_widgets) self.register_validate_function(self._validation_changed) self._check_categories() self.setup_widgets() def _validation_changed(self, valid): self.save_button.set_sensitive(valid) def _check_race(self): race = self.store.find(Race).one() if race: return race race = Race() race.name = u'First race ever' self.store.add(race) self.store.commit() return race def _check_categories(self): categories = self.race.get_categories() if not categories.is_empty(): return for short, name in CATEGORIES.items(): cat = Category() cat.race = self.race cat.short_name = short cat.name = name cat.total_laps = CATEGORIES_LAPS[short] self.store.add(cat) #for i in range(200): # racer = Racer() # racer.name = unicode(i) # racer.number = i # racer.race = self.race # racer.category = cat # self.store.add(racer) self.store.commit() def setup_widgets(self): self.save_button.set_sensitive(False) self.racer_field.set_sensitive(False) if not self.race.start_time: self.lap_number.set_sensitive(False) else: self.start_button.set_sensitive(False) large = pango.FontDescription('Lucida Sans 32') self.lap_number.modify_font(large) self.time_elapsed.modify_font(large) self.start_hour.modify_font(large) self.hpaned1.set_position(550) # Categores options = sorted([(c.name, c.id) for c in self.race.get_categories()]) self.category.prefill(options) # Lists self.racers.set_columns([ Column('name', title="Nome", data_type=str, sorted=True), Column('number', title='Número', data_type=int), Column('completed_laps', title='Completas', data_type=int), Column('total_time', title='Tempo', data_type=str), Column('category_str', title="Categoria", data_type=str) ]) self.categories.set_columns([ Column('short_name', title="Cat", data_type=str, sorted=True), Column('name', title="Category", data_type=str, expand=True), Column('total_racers', title="Corredores", data_type=str), Column('completed_laps', title="Comp", data_type=int), Column('total_laps', title="Total", data_type=int)]) self.log.set_columns([Column('id', data_type=int, visible=False), Column('number', title="#", data_type=int), Column('name', title="Nome", expand=True, data_type=str), Column('event_time', title="Hora", data_type=datetime.time), Column('lap_time', title="Tempo Volta", data_type=str), Column('lap_number', title="Volta N", data_type=int), Column('category', title="Cat", data_type=str), Column('remaining_laps', title="Falta", data_type=int), ]) for racer in self.store.find(Racer): self.racers.append(racer) self.log.extend(self.store.find(RacerLap)) self.categories.extend(self.store.find(Category)) # timer gobject.timeout_add(1000, self._update_timer) # Always show bottom of the log list. self.log.get_treeview().connect('size-allocate', self._treeview_changed) # Show finishing categories in bold self.categories.set_cell_data_func(self._on_categories__cell_data_func) self.log.set_cell_data_func(self._on_log__cell_data_func) self.racers.set_cell_data_func(self._on_racers__cell_data_func) def _on_categories__cell_data_func(self, column, renderer, category, text): if not isinstance(renderer, gtk.CellRendererText): return text completed_laps = category.completed_laps last_lap = completed_laps == (category.total_laps - 1) finished = completed_laps == category.total_laps renderer.set_property('weight-set', last_lap or finished) renderer.set_property('background-set', last_lap or finished) if last_lap or finished: renderer.set_property('weight', pango.WEIGHT_BOLD) if last_lap: renderer.set_property('background', 'yellow') elif finished: renderer.set_property('background', 'green') return text def _on_log__cell_data_func(self, column, renderer, racer_lap, text): if not isinstance(renderer, gtk.CellRendererText): return text remaining_laps = racer_lap.remaining_laps last_lap = remaining_laps == 1 finished = remaining_laps == 0 renderer.set_property('weight-set', last_lap or finished) renderer.set_property('background-set', last_lap or finished) if last_lap or finished: renderer.set_property('weight', pango.WEIGHT_BOLD) if last_lap: renderer.set_property('background', 'yellow') elif finished: renderer.set_property('background', 'green') return text def _on_racers__cell_data_func(self, column, renderer, racer, text): if not isinstance(renderer, gtk.CellRendererText): return text renderer.set_property('weight-set', False) renderer.set_property('background-set', False) if not isinstance(racer, Racer): return text racer_lap = racer.last_lap if not racer_lap: return text remaining_laps = racer_lap.remaining_laps last_lap = remaining_laps == 1 finished = remaining_laps == 0 renderer.set_property('weight-set', last_lap or finished) renderer.set_property('background-set', last_lap or finished) if last_lap or finished: renderer.set_property('weight', pango.WEIGHT_BOLD) if last_lap: renderer.set_property('background', 'yellow') elif finished: renderer.set_property('background', 'green') return text def _treeview_changed(self, widget, event): adj = self.log.get_scrolled_window().get_vadjustment() adj.set_value(adj.upper - adj.page_size) def _update_timer(self): self.race_proxy.update('time_elapsed') return True # # Public API # def add_lap(self, number): racer = self.store.find(Racer, number=number).one() if not racer: print 'recer not found', number return if racer.is_finished: print 'racer finished', number return print 'add_lap', number lap = racer.add_lap() self.log.append(lap) # We need to recalculate the number of laps racer.category.update() racer.update() # Update the categories list. self.categories.refresh(racer.category) self.store.flush() self.store._connection.commit() def edit_racer(self, racer): self._current_model = racer if not self.proxy: self.proxy = self.add_proxy(racer, self.widgets) self.proxy.set_model(racer) self.save_button.set_sensitive(True) self.new_button.set_sensitive(False) self.racer_field.set_sensitive(True) self.name.grab_focus() def save_racer(self): racer = self._current_model self.store.add(racer) if self._is_new: self.racers.append(racer, select=True) self.proxy.set_model(None) self.racer_field.set_sensitive(False) self.save_button.set_sensitive(False) self.new_button.set_sensitive(True) self.racers.refresh() self.store.commit() self._current_model = None # # Callbacks # def on_start_button__clicked(self, button): if self.race.start_time: return self.race.start() self.race_proxy.update('start_hour') self.lap_number.set_sensitive(True) self.start_button.set_sensitive(False) self.store.commit() def on_lap_number__activate(self, widget): try: number = int(widget.get_text()) except: return self.add_lap(number) widget.set_text('') def on_racers__row_activated(self, widget, row): self._is_new = False if isinstance(row, Racer): self.edit_racer(row) def on_new_button__clicked(self, button): self._is_new = True racer = Racer() racer.category = self.category.get_selected() racer.race = self.race self.edit_racer(racer) def on_save_button__clicked(self, button): self.save_racer() def on_number__validate(self, widget, value): query = And(Racer.race == self.race, Racer.id != self._current_model.id, Racer.number == value) if self.store.find(Racer, query).any(): return ValidationError('Número já utilizado') def on_remove_log_button__clicked(self, button): parent = self.get_toplevel().get_toplevel() response = yesno('Deseja remover?', parent=parent, default=False, buttons=((gtk.STOCK_YES, True), (gtk.STOCK_NO, False))) if not response: return log = self.log.get_selected() racer = log.racer self.log.remove(log) self.store.remove(log) self.store.commit() # We need to recalculate the number of laps racer.category.update() racer.update() self.categories.refresh(racer.category) self.lap_number.grab_focus()
class Form(GladeDelegate): widgets = ['name', 'number', 'category'] race_widgets = ['start_hour', 'time_elapsed'] def __init__(self): GladeDelegate.__init__(self, gladefile="interface.ui", delete_handler=self.quit_if_last) self.proxy = None self.db = create_database("sqlite:laps.sqlite") self.store = Store(self.db) self.race = self._check_race() self.race_proxy = self.add_proxy(self.race, self.race_widgets) self.register_validate_function(self._validation_changed) self._check_categories() self.setup_widgets() def _validation_changed(self, valid): self.save_button.set_sensitive(valid) def _check_race(self): race = self.store.find(Race).one() if race: return race race = Race() race.name = u'First race ever' self.store.add(race) self.store.commit() return race def _check_categories(self): categories = self.race.get_categories() if not categories.is_empty(): return for short, name in CATEGORIES.items(): cat = Category() cat.race = self.race cat.short_name = short cat.name = name cat.total_laps = CATEGORIES_LAPS[short] self.store.add(cat) #for i in range(200): # racer = Racer() # racer.name = unicode(i) # racer.number = i # racer.race = self.race # racer.category = cat # self.store.add(racer) self.store.commit() def setup_widgets(self): self.save_button.set_sensitive(False) self.racer_field.set_sensitive(False) if not self.race.start_time: self.lap_number.set_sensitive(False) else: self.start_button.set_sensitive(False) large = pango.FontDescription('Lucida Sans 32') self.lap_number.modify_font(large) self.time_elapsed.modify_font(large) self.start_hour.modify_font(large) self.hpaned1.set_position(550) # Categores options = sorted([(c.name, c.id) for c in self.race.get_categories()]) self.category.prefill(options) # Lists self.racers.set_columns([ Column('name', title="Nome", data_type=str, sorted=True), Column('number', title='Número', data_type=int), Column('completed_laps', title='Completas', data_type=int), Column('total_time', title='Tempo', data_type=str), Column('category_str', title="Categoria", data_type=str) ]) self.categories.set_columns([ Column('short_name', title="Cat", data_type=str, sorted=True), Column('name', title="Category", data_type=str, expand=True), Column('total_racers', title="Corredores", data_type=str), Column('completed_laps', title="Comp", data_type=int), Column('total_laps', title="Total", data_type=int) ]) self.log.set_columns([ Column('id', data_type=int, visible=False), Column('number', title="#", data_type=int), Column('name', title="Nome", expand=True, data_type=str), Column('event_time', title="Hora", data_type=datetime.time), Column('lap_time', title="Tempo Volta", data_type=str), Column('lap_number', title="Volta N", data_type=int), Column('category', title="Cat", data_type=str), Column('remaining_laps', title="Falta", data_type=int), ]) for racer in self.store.find(Racer): self.racers.append(racer) self.log.extend(self.store.find(RacerLap)) self.categories.extend(self.store.find(Category)) # timer gobject.timeout_add(1000, self._update_timer) # Always show bottom of the log list. self.log.get_treeview().connect('size-allocate', self._treeview_changed) # Show finishing categories in bold self.categories.set_cell_data_func(self._on_categories__cell_data_func) self.log.set_cell_data_func(self._on_log__cell_data_func) self.racers.set_cell_data_func(self._on_racers__cell_data_func) def _on_categories__cell_data_func(self, column, renderer, category, text): if not isinstance(renderer, gtk.CellRendererText): return text completed_laps = category.completed_laps last_lap = completed_laps == (category.total_laps - 1) finished = completed_laps == category.total_laps renderer.set_property('weight-set', last_lap or finished) renderer.set_property('background-set', last_lap or finished) if last_lap or finished: renderer.set_property('weight', pango.WEIGHT_BOLD) if last_lap: renderer.set_property('background', 'yellow') elif finished: renderer.set_property('background', 'green') return text def _on_log__cell_data_func(self, column, renderer, racer_lap, text): if not isinstance(renderer, gtk.CellRendererText): return text remaining_laps = racer_lap.remaining_laps last_lap = remaining_laps == 1 finished = remaining_laps == 0 renderer.set_property('weight-set', last_lap or finished) renderer.set_property('background-set', last_lap or finished) if last_lap or finished: renderer.set_property('weight', pango.WEIGHT_BOLD) if last_lap: renderer.set_property('background', 'yellow') elif finished: renderer.set_property('background', 'green') return text def _on_racers__cell_data_func(self, column, renderer, racer, text): if not isinstance(renderer, gtk.CellRendererText): return text renderer.set_property('weight-set', False) renderer.set_property('background-set', False) if not isinstance(racer, Racer): return text racer_lap = racer.last_lap if not racer_lap: return text remaining_laps = racer_lap.remaining_laps last_lap = remaining_laps == 1 finished = remaining_laps == 0 renderer.set_property('weight-set', last_lap or finished) renderer.set_property('background-set', last_lap or finished) if last_lap or finished: renderer.set_property('weight', pango.WEIGHT_BOLD) if last_lap: renderer.set_property('background', 'yellow') elif finished: renderer.set_property('background', 'green') return text def _treeview_changed(self, widget, event): adj = self.log.get_scrolled_window().get_vadjustment() adj.set_value(adj.upper - adj.page_size) def _update_timer(self): self.race_proxy.update('time_elapsed') return True # # Public API # def add_lap(self, number): racer = self.store.find(Racer, number=number).one() if not racer: print 'recer not found', number return if racer.is_finished: print 'racer finished', number return print 'add_lap', number lap = racer.add_lap() self.log.append(lap) # We need to recalculate the number of laps racer.category.update() racer.update() # Update the categories list. self.categories.refresh(racer.category) self.store.flush() self.store._connection.commit() def edit_racer(self, racer): self._current_model = racer if not self.proxy: self.proxy = self.add_proxy(racer, self.widgets) self.proxy.set_model(racer) self.save_button.set_sensitive(True) self.new_button.set_sensitive(False) self.racer_field.set_sensitive(True) self.name.grab_focus() def save_racer(self): racer = self._current_model self.store.add(racer) if self._is_new: self.racers.append(racer, select=True) self.proxy.set_model(None) self.racer_field.set_sensitive(False) self.save_button.set_sensitive(False) self.new_button.set_sensitive(True) self.racers.refresh() self.store.commit() self._current_model = None # # Callbacks # def on_start_button__clicked(self, button): if self.race.start_time: return self.race.start() self.race_proxy.update('start_hour') self.lap_number.set_sensitive(True) self.start_button.set_sensitive(False) self.store.commit() def on_lap_number__activate(self, widget): try: number = int(widget.get_text()) except: return self.add_lap(number) widget.set_text('') def on_racers__row_activated(self, widget, row): self._is_new = False if isinstance(row, Racer): self.edit_racer(row) def on_new_button__clicked(self, button): self._is_new = True racer = Racer() racer.category = self.category.get_selected() racer.race = self.race self.edit_racer(racer) def on_save_button__clicked(self, button): self.save_racer() def on_number__validate(self, widget, value): query = And(Racer.race == self.race, Racer.id != self._current_model.id, Racer.number == value) if self.store.find(Racer, query).any(): return ValidationError('Número já utilizado') def on_remove_log_button__clicked(self, button): parent = self.get_toplevel().get_toplevel() response = yesno('Deseja remover?', parent=parent, default=False, buttons=((gtk.STOCK_YES, True), (gtk.STOCK_NO, False))) if not response: return log = self.log.get_selected() racer = log.racer self.log.remove(log) self.store.remove(log) self.store.commit() # We need to recalculate the number of laps racer.category.update() racer.update() self.categories.refresh(racer.category) self.lap_number.grab_focus()
class TSExperimentSvcAgent(TSLocalAgent): agentId = expsvcAgentId uuid = expsvcAgentUUID agentType = expsvcAgentType def __init__(self, server, connString): TSLocalAgent.__init__(self, server) self.rootAgent = server.localAgents[0] self.userAgent = server.localAgents[1] self.database = create_database(connString) self.dbStore = Store(self.database) self.server.listenerAgents.append( AgentListener('load', self.onAgentRegister, self.onAgentDisconnect)) self.loadAgents = {} self.resourceManager = ResourceManager(self.dbStore) @inlineCallbacks def registerNewAgent(self, client, agent): hostInfo = yield agent.getHostInfo() agentObj = Agent() agentObj.uuid = uuid.UUID(client.agentUuid) agentObj.agentType = 'load' # FIXME: Sometimes domainname passed with hostname agentObj.hostname = unicode(hostInfo.hostname) agentObj.domainname = unicode(hostInfo.domainname) agentObj.osname = hostInfo.osname agentObj.release = hostInfo.release agentObj.machineArch = hostInfo.machineArch agentObj.numCPUs = hostInfo.numCPUs agentObj.numCores = hostInfo.numCores agentObj.memTotal = hostInfo.memTotal agentObj.lastOnline = datetime.now() yield self.dbStore.add(agentObj) yield self.dbStore.commit() returnValue(agentObj) @inlineCallbacks def onAgentRegister(self, client): if client.agentType == 'load': if client.agentUuid in self.loadAgents: raise JSONTS.Error( JSONTS.AE_INVALID_STATE, "Loader agent with uuid '%s' already registered" % client.agentUuid) agentId = client.getId() agent = self.createRemoteAgent(agentId, LoadAgent) agentSet = yield self.dbStore.find( Agent, Agent.uuid == uuid.UUID(client.agentUuid)) agentObj = yield agentSet.one() if agentObj is None: agentObj = yield self.registerNewAgent(client, agent) else: # Update last online timestamp agentObj.lastOnline = datetime.now() yield self.dbStore.add(agentObj) yield self.dbStore.commit() agentInfo = LoadAgentInfo(agent, agentObj) self.loadAgents[client.agentUuid] = agentInfo print "Registered agent %s with uuid '%s'" % (agentObj.hostname, client.agentUuid) reactor.callLater(0.0, self.fetchWorkloadTypes, agent, agentObj) reactor.callLater(0.1, self.resourceManager.registerLoadAgent, agent, agentObj) def onAgentDisconnect(self, client): if client.agentType == 'load': yield self.resourceManager.unregisterLoadAgent(agentInfo.agentObj) agentInfo = self.loadAgents[client.agentUuid] print 'Disconnected agent %s' % agentInfo.agentObj.hostname del self.loadAgents[client.agentUuid] @inlineCallbacks def fetchWorkloadTypes(self, agent, agentObj): wltypeList = yield agent.getWorkloadTypes() wltSet = yield self.dbStore.find(WorkloadType, WorkloadType.agent == agentObj) for wltypeName, wltype in wltypeList.iteritems(): wltObj = wltSet.find(WorkloadType.name == wltypeName) wltObj = wltObj.any() if wltObj is None: wltObj = WorkloadType() wltObj.agent = agentObj wltObj.name = wltypeName wltObj.module = wltype.module wltObj.modulePath = wltype.path wltObj.classList = ','.join(wltype.wlclass) yield self.dbStore.add(wltObj) paramSet = yield self.dbStore.find( WorkloadParam, WorkloadParam.workloadType == wltObj) # Update parameter list for paramObj in paramSet: if paramObj.name not in wltype.params: paramObj.remove() continue paramObj.data = wltype.params.serialize() # Remove serialized object from params array del wltype.params[paramObj.name] yield self.dbStore.add(paramObj) for paramName, param in wltype.params.iteritems(): paramObj = WorkloadParam() paramObj.name = paramName paramObj.workloadType = wltObj paramObj.paramData = TSWorkloadParameter.serialize(param) yield self.dbStore.add(paramObj) yield self.dbStore.commit() @TSMethodImpl(ExpSvcAgent.listAgents) @inlineCallbacks def listAgents(self, context): agentsList = {} agentSet = yield self.dbStore.find(Agent) for agentObj in agentSet: # TODO: should filter agents according to users ACL agentUuid = str(agentObj.uuid) descriptor = TSExpSvcAgentDescriptor() descriptor.agentId = agentObj.id descriptor.lastOnline = datetimeToTSTime(agentObj.lastOnline) descriptor.isOnline = agentUuid in self.loadAgents for field in ('hostname', 'domainname', 'osname', 'release', 'machineArch', 'numCPUs', 'numCores', 'memTotal'): setattr(descriptor, field, getattr(agentObj, field)) agentsList[agentUuid] = descriptor returnValue(agentsList) @TSMethodImpl(ExpSvcAgent.getWorkloadTypes) @inlineCallbacks def getWorkloadTypes(self, context, agentId): wltSet = yield self.dbStore.find(WorkloadType, WorkloadType.aid == agentId) paramsQuery = (WorkloadParam, Join( WorkloadType, And(WorkloadType.aid == agentId, WorkloadParam.wltid == WorkloadType.id))) paramsGlobalSet = yield self.dbStore.using( *paramsQuery).find(WorkloadParam) wltypeList = {} for wltObj in wltSet: paramsSet = yield paramsGlobalSet.find( WorkloadParam.workloadType == wltObj) wltype = TSWorkloadType() wltype.module = wltObj.module wltype.path = wltObj.modulePath wltype.wlclass = wltObj.classList.split(',') wltype.params = {} for paramObj in paramsSet: param = TSWorkloadParameter.deserialize(paramObj.paramData) wltype.params[paramObj.name] = param wltypeList[wltObj.name] = wltype returnValue(wltypeList) @TSMethodImpl(ExpSvcAgent.getAgentResources) @inlineCallbacks def getAgentResources(self, context, agentId): resourceInfo = yield self.resourceManager.getAgentResources(agentId) returnValue(resourceInfo) @inlineCallbacks def _getProfileObj(self, context, profileName, profile): client = context.client if client.auth == TSServerClient.AUTH_MASTER or \ client.auth == TSServerClient.AUTH_ADMIN: userId = profile.userId if profile.userId is not None else 0 else: agentId = client.getId() userId = self.userAgent.agentUsers[agentId] profileSet = yield self.dbStore.find( ExperimentProfile, And(ExperimentProfile.name == unicode(profileName), ExperimentProfile.userId == userId)) returnValue((profileSet.one(), userId)) @TSMethodImpl(ExpSvcAgent.listProfiles) @inlineCallbacks def listProfiles(self, context): '''If context is of administrative rights (master.key or admin), list all experiments, or select only owned experiment''' client = context.client # TODO: Support for experiment sharing profiles = {} if client.auth == TSServerClient.AUTH_MASTER or \ client.auth == TSServerClient.AUTH_ADMIN: profileSet = yield self.dbStore.find(ExperimentProfile) else: agentId = client.getId() userId = self.userAgent.agentUsers[agentId] profileSet = yield self.dbStore.find( ExperimentProfile, ExperimentProfile.userId == userId) for profileObj in profileSet: profiles[profileObj.name] = _profileObjToTSO( profileObj, TSExperimentProfileInfo) returnValue(profiles) @TSMethodImpl(ExpSvcAgent.getProfile) @inlineCallbacks def getProfile(self, context, profileName, profile): profileObj, _ = yield self._getProfileObj(context, profileName, profile) fullProfile = _profileObjToTSO(profileObj, TSExperimentProfile) fullProfile.threadpools = {} fullProfile.workloads = {} threadpoolSet = yield self.dbStore.find( ExperimentThreadPool, ExperimentThreadPool.profile == profileObj) for threadpoolObj in threadpoolSet: threadpool = TSExperimentThreadPool() threadpool.agentId = threadpoolObj.aid threadpool.numWorkers = threadpoolObj.numWorkers fullProfile.threadpools[threadpoolObj.name] = threadpool workloadSet = yield self.dbStore.find( ExperimentWorkload, ExperimentWorkload.profile == profileObj) for workloadObj in workloadSet: workload = TSExperimentWorkload() workload.agentId = workloadObj.threadpool.aid if workloadObj.threadpool is not None else -1 workload.workloadType = workloadObj.workloadType.name if workloadObj.workloadType is not None else '' workload.threadpool = workloadObj.threadpool.name if workloadObj.threadpool is not None else '' workload.params = workloadObj.params fullProfile.workloads[workloadObj.name] = workload returnValue(fullProfile) @TSMethodImpl(ExpSvcAgent.configureProfile) @inlineCallbacks def configureProfile(self, context, profileName, profile): profileObj, userId = yield self._getProfileObj(context, profileName, profile) newProfile = False threadpools = {} if profileObj is None: profileObj = ExperimentProfile() profileObj.name = unicode(profileName) profileObj.userId = userId profileObj.creationDate = datetime.now() newProfile = True profileObj.description = unicode(profile.description) yield self.dbStore.add(profileObj) if not newProfile: threadpoolSet = yield self.dbStore.find( ExperimentThreadPool, ExperimentThreadPool.profile == profileObj) # Update or remove existing threadpools for threadpoolObj in threadpoolSet: if threadpoolObj.name in profile.threadpools: threadpool = profile.threadpools[threadpoolObj.name] threadpoolObj.aid = threadpool.agentId threadpoolObj.numWorkers = threadpool.numWorkers del profile.threadpools[threadpoolObj.name] yield self.dbStore.add(threadpoolObj) threadpools[threadpoolObj.name] = threadpoolObj else: yield self.dbStore.remove(threadpoolObj) # Add new threadpools for threadpoolName, threadpool in profile.threadpools.iteritems(): threadpoolObj = ExperimentThreadPool() threadpoolObj.name = unicode(threadpoolName) threadpoolObj.aid = threadpool.agentId threadpoolObj.profile = profileObj threadpoolObj.numWorkers = threadpool.numWorkers threadpools[threadpoolName] = threadpoolObj yield self.dbStore.add(threadpoolObj) @inlineCallbacks def _setWorkloadType(workload, workloadObj): if workload.workloadType is not None and workload.agentId is not None: workloadTypeSet = yield self.dbStore.find( WorkloadType, And(WorkloadType.aid == workload.agentId, WorkloadType.name == unicode(workload.workloadType))) workloadTypeObj = workloadTypeSet.one() workloadObj.wltid = workloadTypeObj.id else: workloadObj.wltid = None def _setThreadpool(workload, workloadObj): workloadObj.tpid = threadpools[workloadObj.name].id \ if workload.threadpool is not None \ else None if not newProfile: workloadSet = yield self.dbStore.find( ExperimentWorkload, ExperimentWorkload.profile == profileObj) for workloadObj in workloadSet: if workloadObj.name in profile.workloads: workload = profile.workloads[workloadObj.name] _setThreadpool(workload, workloadObj) yield _setWorkloadType(workload, workloadObj) workloadObj.params = workload.params del profile.workloads[workloadObj.name] yield self.dbStore.add(workloadObj) else: yield self.dbStore.remove(workloadObj) for workloadName, workload in profile.workloads.iteritems(): workloadObj = ExperimentWorkload() workloadObj.name = unicode(workloadName) workloadObj.profile = profileObj _setThreadpool(workload, workloadObj) yield _setWorkloadType(workload, workloadObj) workloadObj.params = workload.params # TODO: implement workload steps workloadObj.stepsId = None yield self.dbStore.add(workloadObj) yield self.dbStore.commit()