Search in sources :

Example 36 with Task

use of cz.metacentrum.perun.taskslib.model.Task in project perun by CESNET.

the class SendCollector method run.

@Override
public void run() {
    while (!shouldStop()) {
        SendTask sendTask = null;
        Task task = null;
        Service service = null;
        Destination destination = null;
        String stderr;
        String stdout;
        int returnCode;
        // FIXME - doesn't provide nice output and clog the log
        log.debug(schedulingPool.getReport());
        try {
            sendTask = sendCompletionService.blockingTake();
            task = sendTask.getTask();
            /*
				 Set Task "sendEndTime" immediately for each done SendTask, so it's not considered as stuck
				 by PropagationMaintainer#endStuckTasks().
				 Like this we can maximally propagate for "rescheduleTime" for each Destination and not
				 all Destinations (whole Task). Default rescheduleTime is 3 hours * no.of destinations.
				 */
            task.setSendEndTime(LocalDateTime.now());
            // XXX: why is this necessary? Rewriting status with every completed destination?
            if (!Objects.equals(task.getStatus(), Task.TaskStatus.SENDERROR) && !Objects.equals(task.getStatus(), Task.TaskStatus.WARNING) && !Objects.equals(sendTask.getStatus(), SendTaskStatus.WARNING)) {
                // keep SENDING status only if task previously hasn't failed
                task.setStatus(Task.TaskStatus.SENDING);
            } else if (!Objects.equals(task.getStatus(), Task.TaskStatus.SENDERROR) && sendTask.getStatus() == SendTaskStatus.WARNING) {
                task.setStatus(Task.TaskStatus.WARNING);
            }
            destination = sendTask.getDestination();
            stderr = sendTask.getStderr();
            stdout = sendTask.getStdout();
            returnCode = sendTask.getReturnCode();
            service = sendTask.getTask().getService();
        } catch (InterruptedException e) {
            String errorStr = "Thread collecting sent SendTasks was interrupted.";
            log.error("{}: {}", errorStr, e);
            throw new RuntimeException(errorStr, e);
        } catch (TaskExecutionException e) {
            task = e.getTask();
            /*
				 Set Task "sendEndTime" immediately for each done SendTask, so it's not considered as stuck
				 by PropagationMaintainer#endStuckTasks().
				 Like this we can maximally propagate for "rescheduleTime" for each Destination and not
				 all Destinations (whole Task). Default rescheduleTime is 3 hours * no.of destinations.
				 */
            task.setSendEndTime(LocalDateTime.now());
            // set SENDERROR status immediately as first SendTask (Destination) fails
            task.setStatus(Task.TaskStatus.SENDERROR);
            destination = e.getDestination();
            stderr = e.getStderr();
            stdout = e.getStdout();
            returnCode = e.getReturnCode();
            service = task.getService();
            log.error("[{}] Error occurred while sending Task to destination {}", task.getId(), e.getDestination());
        } catch (Throwable ex) {
            log.error("Unexpected exception in SendCollector thread. Stuck Tasks will be cleaned by PropagationMaintainer#endStuckTasks() later.", ex);
            continue;
        }
        // this is just interesting cross-check
        if (schedulingPool.getTask(task.getId()) == null) {
            log.warn("[{}] Task retrieved from SendTask is no longer in SchedulingPool. Probably cleaning thread removed it before completion. " + "This might create possibility of running GEN and SEND of same Task together!", task.getId());
        }
        try {
            // report TaskResult to Dispatcher for this SendTask (Destination)
            jmsQueueManager.reportTaskResult(schedulingPool.createTaskResult(task.getId(), destination.getId(), stderr, stdout, returnCode, service));
        } catch (JMSException | InterruptedException e1) {
            log.error("[{}] Error trying to reportTaskResult for Destination: {} to Dispatcher: {}", task.getId(), destination, e1);
        }
        try {
            // Decrease SendTasks count for Task
            // Consequently, if count is <=1, Task is reported to Dispatcher
            // as DONE/SENDERROR and removed from SchedulingPool (Engine).
            schedulingPool.decreaseSendTaskCount(task, 1);
        } catch (TaskStoreException e) {
            log.error("[{}] Task {} could not be removed from SchedulingPool: {}", task.getId(), task, e);
        }
    }
}
Also used : Destination(cz.metacentrum.perun.core.api.Destination) Task(cz.metacentrum.perun.taskslib.model.Task) SendTask(cz.metacentrum.perun.taskslib.model.SendTask) BlockingSendExecutorCompletionService(cz.metacentrum.perun.engine.scheduling.impl.BlockingSendExecutorCompletionService) Service(cz.metacentrum.perun.core.api.Service) JMSException(javax.jms.JMSException) TaskStoreException(cz.metacentrum.perun.taskslib.exceptions.TaskStoreException) TaskExecutionException(cz.metacentrum.perun.engine.exceptions.TaskExecutionException) SendTask(cz.metacentrum.perun.taskslib.model.SendTask)

Example 37 with Task

use of cz.metacentrum.perun.taskslib.model.Task in project perun by CESNET.

the class EventProcessorImpl method receiveEvent.

@Override
public void receiveEvent(String event) {
    log.debug("Event {} is going to be resolved.", event);
    Task task = null;
    try {
        task = eventParser.parseEvent(event);
    } catch (InvalidEventMessageException | InternalErrorException e) {
        log.error(e.toString());
    }
    if (task == null) {
        log.debug("Task not found in event {}", event);
        return;
    }
    task.setStatus(Task.TaskStatus.PLANNED);
    log.info("Current pool size BEFORE event processing: {}", schedulingPool.getSize());
    log.debug("\t Resolved Facility[{}]", task.getFacility());
    log.debug("\t Resolved Service[{}]", task.getService());
    if (task.getFacility() != null && task.getService() != null) {
        log.debug("[{}] Check if Task exist in SchedulingPool: {}", task.getId(), task);
        Task currentTask = schedulingPool.getTask(task.getId());
        if (currentTask == null) {
            log.debug("[{}] Task not found in SchedulingPool.", task.getId());
            try {
                schedulingPool.addTask(task);
            } catch (TaskStoreException e) {
                log.error("Could not save Task {} into Engine SchedulingPool because of {}, it will be ignored", task, e);
            // FIXME - should probably report ERROR back to dispatcher...
            }
        } else {
            // since we always remove Task from pool at the end and Dispatcher doesn't send partial Destinations,
            // we don't need to update existing Task object !! Let engine finish the processing.
            log.debug("[{}] Task found in SchedulingPool, message skipped.", task.getId(), currentTask);
        }
    }
    log.debug("[{}] POOL SIZE: {}", task.getId(), schedulingPool.getSize());
    log.info("[{}] Current pool size AFTER event processing: {}", task.getId(), schedulingPool.getSize());
}
Also used : Task(cz.metacentrum.perun.taskslib.model.Task) InternalErrorException(cz.metacentrum.perun.core.api.exceptions.InternalErrorException) TaskStoreException(cz.metacentrum.perun.taskslib.exceptions.TaskStoreException) InvalidEventMessageException(cz.metacentrum.perun.engine.exceptions.InvalidEventMessageException)

Example 38 with Task

use of cz.metacentrum.perun.taskslib.model.Task in project perun by CESNET.

the class GenPlanner method run.

@Override
public void run() {
    BlockingDeque<Task> newTasks = schedulingPool.getNewTasksQueue();
    while (!shouldStop()) {
        try {
            log.debug("Getting new Task in the newTasks BlockingDeque");
            Task task = newTasks.take();
            /*
				!! Change status immediately, so it won't be picked by PropagationMaintainer#endStuckTasks()
				because we might be waiting on blockingSubmit() here !!
				*/
            task.setStatus(GENERATING);
            GenWorker worker = new GenWorkerImpl(task, directory);
            genCompletionService.blockingSubmit(worker);
            try {
                jmsQueueManager.reportTaskStatus(task.getId(), task.getStatus(), task.getGenStartTime().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli());
            } catch (JMSException e) {
                log.warn("[{}] Could not send Tasks {} GEN status update: {}", task.getId(), task, e);
            }
        } catch (InterruptedException e) {
            String errorStr = "Thread executing GEN tasks was interrupted.";
            log.error(errorStr, e);
            throw new RuntimeException(errorStr, e);
        } catch (Throwable ex) {
            log.error("Unexpected exception in GenPlanner thread. Stuck Tasks will be cleaned by PropagationMaintainer#endStuckTasks() later.", ex);
        }
    }
}
Also used : Task(cz.metacentrum.perun.taskslib.model.Task) GenWorker(cz.metacentrum.perun.engine.scheduling.GenWorker) GenWorkerImpl(cz.metacentrum.perun.engine.scheduling.impl.GenWorkerImpl) JMSException(javax.jms.JMSException)

Example 39 with Task

use of cz.metacentrum.perun.taskslib.model.Task in project perun by CESNET.

the class PropagationStatsReaderImpl method getFacilityState.

@Override
public FacilityState getFacilityState(PerunSession session, Facility facility) throws PrivilegeException, FacilityNotExistsException, InternalErrorException {
    // get all tasks
    List<Task> tasks = taskDao.listAllTasksForFacility(facility.getId());
    // define state
    FacilityState state = new FacilityState();
    state.setFacility(facility);
    // if no tasks we can't determine facility state
    if (tasks.isEmpty() || tasks == null) {
        state.setState(FacilityPropagationState.NOT_DETERMINED);
        return state;
    } else {
        // OK if no change
        state.setState(FacilityPropagationState.OK);
    }
    // fill all available destinations
    List<RichDestination> destinations = perun.getServicesManager().getAllRichDestinations(session, facility);
    for (RichDestination rd : destinations) {
        state.getResults().put(rd.getDestination(), FacilityPropagationState.NOT_DETERMINED);
    }
    // magic with tasks :-)
    for (Task task : tasks) {
        // save previous facility state
        FacilityPropagationState facState = state.getState();
        // PROCESSING and not ERROR before
        if (TaskStatus.PROCESSING.equals(task.getStatus()) && (facState != FacilityPropagationState.ERROR)) {
            state.setState(FacilityPropagationState.PROCESSING);
        } else // ERROR - set ERROR
        if (TaskStatus.ERROR.equals(task.getStatus())) {
            state.setState(FacilityPropagationState.ERROR);
        }
        // get destination status
        if (task.getExecService().getExecServiceType().equals(ExecService.ExecServiceType.SEND)) {
            List<TaskResult> results = taskResultDao.getTaskResultsByTask(task.getId());
            Map<Service, Map<Destination, TaskResult>> latestResults = new HashMap<Service, Map<Destination, TaskResult>>();
            for (TaskResult res : results) {
                if (latestResults.get(res.getService()) == null) {
                    // put in map since result for service exists
                    Map<Destination, TaskResult> value = new HashMap<>();
                    value.put(res.getDestination(), res);
                    latestResults.put(res.getService(), value);
                } else if (latestResults.get(res.getService()) != null && latestResults.get(res.getService()).get(res.getDestination()) == null) {
                    // put in inner map, since destination for service not yet exists
                    latestResults.get(res.getService()).put(res.getDestination(), res);
                } else {
                    // update in inner map since this is later task result
                    if (latestResults.get(res.getService()).get(res.getDestination()).getId() < res.getId()) {
                        // put in map
                        latestResults.get(res.getService()).put(res.getDestination(), res);
                    }
                }
            }
            for (Map<Destination, TaskResult> res : latestResults.values()) {
                for (TaskResult result : res.values()) {
                    // iterate over all latest tasks results
                    String destination = result.getDestination().getDestination();
                    FacilityPropagationState propState = state.getResults().get(destination);
                    // if any error => state is error
                    if (TaskResult.TaskResultStatus.ERROR.equals(result.getStatus())) {
                        state.getResults().put(destination, FacilityPropagationState.ERROR);
                        continue;
                    }
                    // if result ok and previous was not bad
                    if (TaskResult.TaskResultStatus.DONE.equals(result.getStatus())) {
                        if (FacilityPropagationState.NOT_DETERMINED.equals(propState)) {
                            state.getResults().put(destination, FacilityPropagationState.OK);
                        }
                    }
                }
            }
        }
    }
    return state;
}
Also used : Task(cz.metacentrum.perun.taskslib.model.Task) ExecService(cz.metacentrum.perun.taskslib.model.ExecService) FacilityState(cz.metacentrum.perun.controller.model.FacilityState) TaskResult(cz.metacentrum.perun.taskslib.model.TaskResult) FacilityPropagationState(cz.metacentrum.perun.controller.model.FacilityState.FacilityPropagationState)

Example 40 with Task

use of cz.metacentrum.perun.taskslib.model.Task in project perun by CESNET.

the class TaskResultDaoTest method testClearOldTaskResult.

@Test
public void testClearOldTaskResult() throws InternalErrorException, PrivilegeException, ServiceExistsException, OwnerNotExistsException, FacilityExistsException, ServiceNotExistsException, FacilityNotExistsException, DestinationAlreadyAssignedException, WrongPatternException {
    System.out.println("TaskResultDao.clearOld");
    Owner testOwner = new Owner();
    testOwner.setContact("Call me");
    testOwner.setName("Tester-" + Long.toHexString(System.currentTimeMillis()));
    testOwner.setType(OwnerType.technical);
    testOwner = ownersManager.createOwner(perunSession, testOwner);
    Service testService = new Service();
    testService.setName("Test_service_1_" + Long.toHexString(System.currentTimeMillis()));
    testService = servicesManager.createService(perunSession, testService);
    Service testService2 = new Service();
    testService2.setName("Test_service_2_" + Long.toHexString(System.currentTimeMillis()));
    testService2 = servicesManager.createService(perunSession, testService2);
    Facility facility = new Facility();
    facility.setName("Facility 1-" + Long.toHexString(System.currentTimeMillis()));
    facility.setDescription("Description");
    facility = facilitiesManager.createFacility(perunSession, facility);
    Facility facility2 = new Facility();
    facility2.setName("Facility 2-" + Long.toHexString(System.currentTimeMillis()));
    facility2.setDescription("Description");
    facility2 = facilitiesManager.createFacility(perunSession, facility2);
    ExecService testExecService = new ExecService();
    testExecService.setDefaultDelay(1);
    testExecService.setDefaultRecurrence(1);
    testExecService.setEnabled(true);
    testExecService.setService(testService);
    testExecService.setScript("serviceGenerate.bash");
    testExecService.setExecServiceType(ExecService.ExecServiceType.GENERATE);
    testExecService.setId(execServiceDao.insertExecService(testExecService));
    ExecService testExecService2 = new ExecService();
    testExecService2.setDefaultDelay(1);
    testExecService2.setDefaultRecurrence(1);
    testExecService2.setEnabled(true);
    testExecService2.setService(testService2);
    testExecService2.setScript("serviceGenerate.bash");
    testExecService2.setExecServiceType(ExecService.ExecServiceType.GENERATE);
    testExecService2.setId(execServiceDao.insertExecService(testExecService2));
    Destination destination1 = new Destination();
    destination1.setDestination("Destination-1-" + Long.toHexString(System.currentTimeMillis()));
    destination1.setType(Destination.DESTINATIONEMAILTYPE);
    destination1 = servicesManager.addDestination(perunSession, testService, facility, destination1);
    Destination destination2 = new Destination();
    destination2.setDestination("Destination-2-" + Long.toHexString(System.currentTimeMillis()));
    destination2.setType(Destination.DESTINATIONEMAILTYPE);
    destination2 = servicesManager.addDestination(perunSession, testService, facility, destination2);
    Destination destination3 = new Destination();
    destination3.setDestination("Destination-3-" + Long.toHexString(System.currentTimeMillis()));
    destination3.setType(Destination.DESTINATIONEMAILTYPE);
    destination3 = servicesManager.addDestination(perunSession, testService2, facility2, destination3);
    Task testTask1 = new Task();
    testTask1.setDelay(10);
    testTask1.setExecService(testExecService);
    testTask1.setFacility(facility);
    testTask1.setRecurrence(10);
    testTask1.setSchedule(new Date());
    testTask1.setStatus(Task.TaskStatus.PROCESSING);
    testTask1.setId(taskDao.scheduleNewTask(testTask1, virtualEngineID));
    Task testTask2 = new Task();
    testTask2.setDelay(10);
    testTask2.setExecService(testExecService2);
    testTask2.setFacility(facility2);
    testTask2.setRecurrence(10);
    testTask2.setSchedule(new Date());
    testTask2.setStatus(Task.TaskStatus.PROCESSING);
    testTask2.setId(taskDao.scheduleNewTask(testTask2, virtualEngineID));
    Calendar cal = Calendar.getInstance();
    cal.add(Calendar.DATE, -2);
    TaskResult taskResult = new TaskResult();
    taskResult.setDestinationId(destination1.getId());
    taskResult.setErrorMessage("error message");
    taskResult.setReturnCode(0);
    taskResult.setStandardMessage("std message");
    taskResult.setStatus(TaskResult.TaskResultStatus.DONE);
    taskResult.setTaskId(testTask1.getId());
    taskResult.setTimestamp(cal.getTime());
    taskResult.setService(testService);
    taskResult.setId(taskResultDao.insertNewTaskResult(taskResult, virtualEngineID));
    TaskResult taskResult2 = new TaskResult();
    taskResult2.setDestinationId(destination3.getId());
    taskResult2.setErrorMessage("error message");
    taskResult2.setReturnCode(0);
    taskResult2.setStandardMessage("std message");
    taskResult2.setStatus(TaskResult.TaskResultStatus.DONE);
    taskResult2.setTaskId(testTask2.getId());
    taskResult2.setTimestamp(cal.getTime());
    taskResult2.setService(testService2);
    taskResult2.setId(taskResultDao.insertNewTaskResult(taskResult2, virtualEngineID));
    cal.add(Calendar.DATE, -5);
    TaskResult oldTaskResult = new TaskResult();
    oldTaskResult.setDestinationId(destination1.getId());
    oldTaskResult.setErrorMessage("error message");
    oldTaskResult.setReturnCode(0);
    oldTaskResult.setStandardMessage("std message");
    oldTaskResult.setStatus(TaskResult.TaskResultStatus.DONE);
    oldTaskResult.setTaskId(testTask1.getId());
    oldTaskResult.setTimestamp(cal.getTime());
    oldTaskResult.setService(testService);
    oldTaskResult.setId(taskResultDao.insertNewTaskResult(oldTaskResult, virtualEngineID));
    TaskResult oldTaskResult2 = new TaskResult();
    oldTaskResult2.setDestinationId(destination3.getId());
    oldTaskResult2.setErrorMessage("error message");
    oldTaskResult2.setReturnCode(0);
    oldTaskResult2.setStandardMessage("std message");
    oldTaskResult2.setStatus(TaskResult.TaskResultStatus.DONE);
    oldTaskResult2.setTaskId(testTask2.getId());
    oldTaskResult2.setTimestamp(cal.getTime());
    oldTaskResult2.setService(testService2);
    oldTaskResult2.setId(taskResultDao.insertNewTaskResult(oldTaskResult2, virtualEngineID));
    TaskResult uniqueTaskResult = new TaskResult();
    uniqueTaskResult.setDestinationId(destination2.getId());
    uniqueTaskResult.setErrorMessage("error message");
    uniqueTaskResult.setReturnCode(0);
    uniqueTaskResult.setStandardMessage("std message");
    uniqueTaskResult.setStatus(TaskResult.TaskResultStatus.DONE);
    uniqueTaskResult.setTaskId(testTask1.getId());
    uniqueTaskResult.setTimestamp(cal.getTime());
    uniqueTaskResult.setService(testService);
    uniqueTaskResult.setId(taskResultDao.insertNewTaskResult(uniqueTaskResult, virtualEngineID));
    TaskResult uniqueTaskResult2 = new TaskResult();
    uniqueTaskResult2.setDestinationId(destination2.getId());
    uniqueTaskResult2.setErrorMessage("error message");
    uniqueTaskResult2.setReturnCode(0);
    uniqueTaskResult2.setStandardMessage("std message");
    uniqueTaskResult2.setStatus(TaskResult.TaskResultStatus.DONE);
    uniqueTaskResult2.setTaskId(testTask2.getId());
    uniqueTaskResult2.setTimestamp(cal.getTime());
    uniqueTaskResult2.setService(testService2);
    uniqueTaskResult2.setId(taskResultDao.insertNewTaskResult(uniqueTaskResult2, virtualEngineID));
    TaskResult foundTaskResult1 = taskResultDao.getTaskResultById(taskResult.getId());
    TaskResult foundTaskResult2 = taskResultDao.getTaskResultById(oldTaskResult.getId());
    TaskResult foundTaskResult3 = taskResultDao.getTaskResultById(uniqueTaskResult.getId());
    TaskResult foundTaskResult4 = taskResultDao.getTaskResultById(taskResult2.getId());
    TaskResult foundTaskResult5 = taskResultDao.getTaskResultById(oldTaskResult2.getId());
    TaskResult foundTaskResult6 = taskResultDao.getTaskResultById(uniqueTaskResult2.getId());
    assertEquals(taskResult, foundTaskResult1);
    assertEquals(oldTaskResult, foundTaskResult2);
    assertEquals(uniqueTaskResult, foundTaskResult3);
    assertEquals(taskResult2, foundTaskResult4);
    assertEquals(oldTaskResult2, foundTaskResult5);
    assertEquals(uniqueTaskResult2, foundTaskResult6);
    taskResultDao.clearOld(virtualEngineID, 6);
    foundTaskResult1 = taskResultDao.getTaskResultById(taskResult.getId());
    foundTaskResult3 = taskResultDao.getTaskResultById(uniqueTaskResult.getId());
    foundTaskResult4 = taskResultDao.getTaskResultById(taskResult2.getId());
    foundTaskResult6 = taskResultDao.getTaskResultById(uniqueTaskResult2.getId());
    assertEquals(taskResult, foundTaskResult1);
    assertEquals(uniqueTaskResult, foundTaskResult3);
    assertEquals(taskResult2, foundTaskResult4);
    assertEquals(uniqueTaskResult2, foundTaskResult6);
    try {
        taskResultDao.getTaskResultById(oldTaskResult.getId());
        fail("TaskResult " + taskResult + " should not have been found");
    } catch (EmptyResultDataAccessException e) {
    }
    try {
        taskResultDao.getTaskResultById(oldTaskResult2.getId());
        fail("TaskResult " + taskResult2 + " should not have been found");
    } catch (EmptyResultDataAccessException e) {
    }
    taskResultDao.clearOld(virtualEngineID, 1);
    foundTaskResult1 = taskResultDao.getTaskResultById(taskResult.getId());
    foundTaskResult3 = taskResultDao.getTaskResultById(uniqueTaskResult.getId());
    foundTaskResult4 = taskResultDao.getTaskResultById(taskResult2.getId());
    foundTaskResult6 = taskResultDao.getTaskResultById(uniqueTaskResult2.getId());
    assertEquals(taskResult, foundTaskResult1);
    assertEquals(uniqueTaskResult, foundTaskResult3);
    assertEquals(taskResult2, foundTaskResult4);
    assertEquals(uniqueTaskResult2, foundTaskResult6);
}
Also used : Task(cz.metacentrum.perun.taskslib.model.Task) ExecService(cz.metacentrum.perun.taskslib.model.ExecService) Calendar(java.util.Calendar) ExecService(cz.metacentrum.perun.taskslib.model.ExecService) TaskResult(cz.metacentrum.perun.taskslib.model.TaskResult) EmptyResultDataAccessException(org.springframework.dao.EmptyResultDataAccessException) Date(java.util.Date) Test(org.junit.Test)

Aggregations

Task (cz.metacentrum.perun.taskslib.model.Task)77 InternalErrorException (cz.metacentrum.perun.core.api.exceptions.InternalErrorException)16 Date (java.util.Date)16 Test (org.junit.Test)15 Facility (cz.metacentrum.perun.core.api.Facility)14 Destination (cz.metacentrum.perun.core.api.Destination)11 Service (cz.metacentrum.perun.core.api.Service)10 TaskStoreException (cz.metacentrum.perun.taskslib.exceptions.TaskStoreException)10 PrivilegeException (cz.metacentrum.perun.core.api.exceptions.PrivilegeException)9 ExecService (cz.metacentrum.perun.taskslib.model.ExecService)9 ArrayList (java.util.ArrayList)9 AbstractDispatcherTest (cz.metacentrum.perun.dispatcher.AbstractDispatcherTest)6 SendTask (cz.metacentrum.perun.taskslib.model.SendTask)6 TaskResult (cz.metacentrum.perun.taskslib.model.TaskResult)6 JMSException (javax.jms.JMSException)6 Pair (cz.metacentrum.perun.core.api.Pair)5 AbstractEngineTest (cz.metacentrum.perun.engine.AbstractEngineTest)5 TaskExecutionException (cz.metacentrum.perun.engine.exceptions.TaskExecutionException)5 LocalDateTime (java.time.LocalDateTime)5 Resource (cz.metacentrum.perun.core.api.Resource)4