mirror of
https://github.com/apache/cloudstack.git
synced 2025-10-26 08:42:29 +01:00
asyncjobs: add endtime to async jobs (#2739)
There is currently no functional mechanism that captures or persists the end time of when an asynchronous job has finished. As a result, users are not able to do any reporting about the duration of various asynchronous jobs in Cloudstack. Link to FS: https://cwiki.apache.org/confluence/display/CLOUDSTACK/Add+End+Time+To+Asynchronous+Jobs
This commit is contained in:
parent
443490179c
commit
542d4da16c
@ -42,6 +42,7 @@ env:
|
||||
- TESTS="smoke/test_accounts
|
||||
smoke/test_affinity_groups
|
||||
smoke/test_affinity_groups_projects
|
||||
smoke/test_async_job
|
||||
smoke/test_deploy_vgpu_enabled_vm
|
||||
smoke/test_deploy_vm_iso
|
||||
smoke/test_deploy_vm_root_resize
|
||||
|
||||
@ -549,6 +549,7 @@ public class ApiConstants {
|
||||
public static final String IPSEC_PSK = "ipsecpsk";
|
||||
public static final String GUEST_IP = "guestip";
|
||||
public static final String REMOVED = "removed";
|
||||
public static final String COMPLETED = "completed";
|
||||
public static final String IKE_POLICY = "ikepolicy";
|
||||
public static final String ESP_POLICY = "esppolicy";
|
||||
public static final String IKE_LIFETIME = "ikelifetime";
|
||||
|
||||
@ -75,6 +75,10 @@ public class AsyncJobResponse extends BaseResponse {
|
||||
@Param(description = " the created date of the job")
|
||||
private Date created;
|
||||
|
||||
@SerializedName(ApiConstants.COMPLETED)
|
||||
@Param(description = " the completed date of the job")
|
||||
private Date removed;
|
||||
|
||||
public void setAccountId(String accountId) {
|
||||
this.accountId = accountId;
|
||||
}
|
||||
@ -119,4 +123,8 @@ public class AsyncJobResponse extends BaseResponse {
|
||||
public void setCreated(Date created) {
|
||||
this.created = created;
|
||||
}
|
||||
|
||||
public void setRemoved(final Date removed) {
|
||||
this.removed = removed;
|
||||
}
|
||||
}
|
||||
|
||||
@ -68,6 +68,8 @@ public interface JobInfo extends Identity, InternalIdentity {
|
||||
|
||||
Date getCreated();
|
||||
|
||||
Date getRemoved();
|
||||
|
||||
Date getLastUpdated();
|
||||
|
||||
Date getLastPolled();
|
||||
|
||||
@ -32,4 +32,6 @@ ALTER TABLE `vlan` CHANGE `description` `ip4_range` varchar(255);
|
||||
-- We are only adding the permission to the default rules. Any custom rule must be configured by the root admin.
|
||||
INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 2, 'moveNetworkAclItem', 'ALLOW', 100) ON DUPLICATE KEY UPDATE rule=rule;
|
||||
INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'moveNetworkAclItem', 'ALLOW', 302) ON DUPLICATE KEY UPDATE rule=rule;
|
||||
INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'moveNetworkAclItem', 'ALLOW', 260) ON DUPLICATE KEY UPDATE rule=rule;
|
||||
INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 4, 'moveNetworkAclItem', 'ALLOW', 260) ON DUPLICATE KEY UPDATE rule=rule;
|
||||
|
||||
UPDATE `cloud`.`async_job` SET `removed` = now() WHERE `removed` IS NULL;
|
||||
@ -24,6 +24,7 @@ import org.apache.cloudstack.framework.jobs.impl.AsyncJobVO;
|
||||
import com.cloud.utils.db.GenericDao;
|
||||
|
||||
public interface AsyncJobDao extends GenericDao<AsyncJobVO, Long> {
|
||||
|
||||
AsyncJobVO findInstancePendingAsyncJob(String instanceType, long instanceId);
|
||||
|
||||
List<AsyncJobVO> findInstancePendingAsyncJobs(String instanceType, Long accountId);
|
||||
|
||||
@ -21,6 +21,7 @@ import java.sql.SQLException;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.cloudstack.api.ApiConstants;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
import org.apache.cloudstack.framework.jobs.impl.AsyncJobVO;
|
||||
@ -71,7 +72,7 @@ public class AsyncJobDaoImpl extends GenericDaoBase<AsyncJobVO, Long> implements
|
||||
expiringUnfinishedAsyncJobSearch.done();
|
||||
|
||||
expiringCompletedAsyncJobSearch = createSearchBuilder();
|
||||
expiringCompletedAsyncJobSearch.and("created", expiringCompletedAsyncJobSearch.entity().getCreated(), SearchCriteria.Op.LTEQ);
|
||||
expiringCompletedAsyncJobSearch.and(ApiConstants.REMOVED, expiringCompletedAsyncJobSearch.entity().getRemoved(), SearchCriteria.Op.LTEQ);
|
||||
expiringCompletedAsyncJobSearch.and("completeMsId", expiringCompletedAsyncJobSearch.entity().getCompleteMsid(), SearchCriteria.Op.NNULL);
|
||||
expiringCompletedAsyncJobSearch.and("jobStatus", expiringCompletedAsyncJobSearch.entity().getStatus(), SearchCriteria.Op.NEQ);
|
||||
expiringCompletedAsyncJobSearch.done();
|
||||
@ -168,11 +169,11 @@ public class AsyncJobDaoImpl extends GenericDaoBase<AsyncJobVO, Long> implements
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<AsyncJobVO> getExpiredCompletedJobs(Date cutTime, int limit) {
|
||||
SearchCriteria<AsyncJobVO> sc = expiringCompletedAsyncJobSearch.create();
|
||||
sc.setParameters("created", cutTime);
|
||||
public List<AsyncJobVO> getExpiredCompletedJobs(final Date cutTime, final int limit) {
|
||||
final SearchCriteria<AsyncJobVO> sc = expiringCompletedAsyncJobSearch.create();
|
||||
sc.setParameters(ApiConstants.REMOVED, cutTime);
|
||||
sc.setParameters("jobStatus", JobInfo.Status.IN_PROGRESS);
|
||||
Filter filter = new Filter(AsyncJobVO.class, "created", true, 0L, (long)limit);
|
||||
final Filter filter = new Filter(AsyncJobVO.class, ApiConstants.REMOVED, true, 0L, (long)limit);
|
||||
return listIncludingRemovedBy(sc, filter);
|
||||
}
|
||||
|
||||
|
||||
@ -161,7 +161,7 @@ public class AsyncJobManagerImpl extends ManagerBase implements AsyncJobManager,
|
||||
|
||||
@Override
|
||||
public AsyncJobVO getAsyncJob(long jobId) {
|
||||
return _jobDao.findById(jobId);
|
||||
return _jobDao.findByIdIncludingRemoved(jobId);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -286,9 +286,9 @@ public class AsyncJobManagerImpl extends ManagerBase implements AsyncJobManager,
|
||||
if (s_logger.isDebugEnabled()) {
|
||||
s_logger.debug("Wake up jobs related to job-" + jobId);
|
||||
}
|
||||
List<Long> wakeupList = Transaction.execute(new TransactionCallback<List<Long>>() {
|
||||
final List<Long> wakeupList = Transaction.execute(new TransactionCallback<List<Long>>() {
|
||||
@Override
|
||||
public List<Long> doInTransaction(TransactionStatus status) {
|
||||
public List<Long> doInTransaction(final TransactionStatus status) {
|
||||
if (s_logger.isDebugEnabled()) {
|
||||
s_logger.debug("Update db status for job-" + jobId);
|
||||
}
|
||||
@ -302,14 +302,16 @@ public class AsyncJobManagerImpl extends ManagerBase implements AsyncJobManager,
|
||||
job.setResult(null);
|
||||
}
|
||||
|
||||
job.setLastUpdated(DateUtil.currentGMTTime());
|
||||
final Date currentGMTTime = DateUtil.currentGMTTime();
|
||||
job.setLastUpdated(currentGMTTime);
|
||||
job.setRemoved(currentGMTTime);
|
||||
job.setExecutingMsid(null);
|
||||
_jobDao.update(jobId, job);
|
||||
|
||||
if (s_logger.isDebugEnabled()) {
|
||||
s_logger.debug("Wake up jobs joined with job-" + jobId + " and disjoin all subjobs created from job- " + jobId);
|
||||
}
|
||||
List<Long> wakeupList = wakeupByJoinedJobCompletion(jobId);
|
||||
final List<Long> wakeupList = wakeupByJoinedJobCompletion(jobId);
|
||||
_joinMapDao.disjoinAllJobs(jobId);
|
||||
|
||||
// purge the job sync item from queue
|
||||
@ -445,8 +447,8 @@ public class AsyncJobManagerImpl extends ManagerBase implements AsyncJobManager,
|
||||
}
|
||||
|
||||
@Override
|
||||
public AsyncJob queryJob(long jobId, boolean updatePollTime) {
|
||||
AsyncJobVO job = _jobDao.findById(jobId);
|
||||
public AsyncJob queryJob(final long jobId, final boolean updatePollTime) {
|
||||
final AsyncJobVO job = _jobDao.findByIdIncludingRemoved(jobId);
|
||||
|
||||
if (updatePollTime) {
|
||||
job.setLastPolled(DateUtil.currentGMTTime());
|
||||
@ -1025,8 +1027,8 @@ public class AsyncJobManagerImpl extends ManagerBase implements AsyncJobManager,
|
||||
// purge sync queue item running on this ms node
|
||||
_queueMgr.cleanupActiveQueueItems(msid, true);
|
||||
// reset job status for all jobs running on this ms node
|
||||
List<AsyncJobVO> jobs = _jobDao.getResetJobs(msid);
|
||||
for (AsyncJobVO job : jobs) {
|
||||
final List<AsyncJobVO> jobs = _jobDao.getResetJobs(msid);
|
||||
for (final AsyncJobVO job : jobs) {
|
||||
if (s_logger.isDebugEnabled()) {
|
||||
s_logger.debug("Cancel left-over job-" + job.getId());
|
||||
}
|
||||
@ -1034,12 +1036,15 @@ public class AsyncJobManagerImpl extends ManagerBase implements AsyncJobManager,
|
||||
job.setResultCode(ApiErrorCode.INTERNAL_ERROR.getHttpCode());
|
||||
job.setResult("job cancelled because of management server restart or shutdown");
|
||||
job.setCompleteMsid(msid);
|
||||
final Date currentGMTTime = DateUtil.currentGMTTime();
|
||||
job.setLastUpdated(currentGMTTime);
|
||||
job.setRemoved(currentGMTTime);
|
||||
_jobDao.update(job.getId(), job);
|
||||
if (s_logger.isDebugEnabled()) {
|
||||
s_logger.debug("Purge queue item for cancelled job-" + job.getId());
|
||||
}
|
||||
_queueMgr.purgeAsyncJobQueueItemId(job.getId());
|
||||
if (job.getInstanceType().equals(ApiCommandJobType.Volume.toString())) {
|
||||
if (ApiCommandJobType.Volume.toString().equals(job.getInstanceType())) {
|
||||
|
||||
try {
|
||||
_volumeDetailsDao.removeDetail(job.getInstanceId(), "SNAPSHOT_ID");
|
||||
@ -1049,8 +1054,8 @@ public class AsyncJobManagerImpl extends ManagerBase implements AsyncJobManager,
|
||||
}
|
||||
}
|
||||
}
|
||||
List<SnapshotDetailsVO> snapshotList = _snapshotDetailsDao.findDetails(AsyncJob.Constants.MS_ID, Long.toString(msid), false);
|
||||
for (SnapshotDetailsVO snapshotDetailsVO : snapshotList) {
|
||||
final List<SnapshotDetailsVO> snapshotList = _snapshotDetailsDao.findDetails(AsyncJob.Constants.MS_ID, Long.toString(msid), false);
|
||||
for (final SnapshotDetailsVO snapshotDetailsVO : snapshotList) {
|
||||
SnapshotInfo snapshot = snapshotFactory.getSnapshot(snapshotDetailsVO.getResourceId(), DataStoreRole.Primary);
|
||||
snapshotSrv.processEventOnSnapshotObject(snapshot, Snapshot.Event.OperationFailed);
|
||||
_snapshotDetailsDao.removeDetail(snapshotDetailsVO.getResourceId(), AsyncJob.Constants.MS_ID);
|
||||
|
||||
@ -372,6 +372,15 @@ public class AsyncJobVO implements AsyncJob, JobInfo {
|
||||
this.uuid = uuid;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Date getRemoved() {
|
||||
return removed;
|
||||
}
|
||||
|
||||
public void setRemoved(final Date removed) {
|
||||
this.removed = removed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuffer sb = new StringBuffer();
|
||||
@ -392,6 +401,7 @@ public class AsyncJobVO implements AsyncJob, JobInfo {
|
||||
sb.append(", lastUpdated: ").append(getLastUpdated());
|
||||
sb.append(", lastPolled: ").append(getLastPolled());
|
||||
sb.append(", created: ").append(getCreated());
|
||||
sb.append(", removed: ").append(getRemoved());
|
||||
sb.append("}");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@ -1808,16 +1808,16 @@ public class ApiResponseHelper implements ResponseGenerator {
|
||||
}
|
||||
|
||||
@Override
|
||||
public AsyncJobResponse queryJobResult(QueryAsyncJobResultCmd cmd) {
|
||||
Account caller = CallContext.current().getCallingAccount();
|
||||
public AsyncJobResponse queryJobResult(final QueryAsyncJobResultCmd cmd) {
|
||||
final Account caller = CallContext.current().getCallingAccount();
|
||||
|
||||
AsyncJob job = _entityMgr.findById(AsyncJob.class, cmd.getId());
|
||||
final AsyncJob job = _entityMgr.findByIdIncludingRemoved(AsyncJob.class, cmd.getId());
|
||||
if (job == null) {
|
||||
throw new InvalidParameterValueException("Unable to find a job by id " + cmd.getId());
|
||||
}
|
||||
|
||||
User userJobOwner = _accountMgr.getUserIncludingRemoved(job.getUserId());
|
||||
Account jobOwner = _accountMgr.getAccount(userJobOwner.getAccountId());
|
||||
final User userJobOwner = _accountMgr.getUserIncludingRemoved(job.getUserId());
|
||||
final Account jobOwner = _accountMgr.getAccount(userJobOwner.getAccountId());
|
||||
|
||||
//check permissions
|
||||
if (_accountMgr.isNormalUser(caller.getId())) {
|
||||
|
||||
@ -50,12 +50,13 @@ public class AsyncJobJoinDaoImpl extends GenericDaoBase<AsyncJobJoinVO, Long> im
|
||||
}
|
||||
|
||||
@Override
|
||||
public AsyncJobResponse newAsyncJobResponse(AsyncJobJoinVO job) {
|
||||
AsyncJobResponse jobResponse = new AsyncJobResponse();
|
||||
public AsyncJobResponse newAsyncJobResponse(final AsyncJobJoinVO job) {
|
||||
final AsyncJobResponse jobResponse = new AsyncJobResponse();
|
||||
jobResponse.setAccountId(job.getAccountUuid());
|
||||
jobResponse.setUserId(job.getUserUuid());
|
||||
jobResponse.setCmd(job.getCmd());
|
||||
jobResponse.setCreated(job.getCreated());
|
||||
jobResponse.setRemoved(job.getRemoved());
|
||||
jobResponse.setJobId(job.getUuid());
|
||||
jobResponse.setJobStatus(job.getStatus());
|
||||
jobResponse.setJobProcStatus(job.getProcessStatus());
|
||||
@ -68,15 +69,15 @@ public class AsyncJobJoinDaoImpl extends GenericDaoBase<AsyncJobJoinVO, Long> im
|
||||
}
|
||||
jobResponse.setJobResultCode(job.getResultCode());
|
||||
|
||||
boolean savedValue = SerializationContext.current().getUuidTranslation();
|
||||
final boolean savedValue = SerializationContext.current().getUuidTranslation();
|
||||
SerializationContext.current().setUuidTranslation(false);
|
||||
|
||||
Object resultObject = ApiSerializerHelper.fromSerializedString(job.getResult());
|
||||
final Object resultObject = ApiSerializerHelper.fromSerializedString(job.getResult());
|
||||
jobResponse.setJobResult((ResponseObject)resultObject);
|
||||
SerializationContext.current().setUuidTranslation(savedValue);
|
||||
|
||||
if (resultObject != null) {
|
||||
Class<?> clz = resultObject.getClass();
|
||||
final Class<?> clz = resultObject.getClass();
|
||||
if (clz.isPrimitive() || clz.getSuperclass() == Number.class || clz == String.class || clz == Date.class) {
|
||||
jobResponse.setJobResultType("text");
|
||||
} else {
|
||||
|
||||
@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package com.cloud.storage.dao;
|
||||
|
||||
import com.cloud.api.query.dao.AsyncJobJoinDaoImpl;
|
||||
import com.cloud.api.query.vo.AsyncJobJoinVO;
|
||||
import org.apache.cloudstack.api.ApiCommandJobType;
|
||||
import org.apache.cloudstack.api.response.AsyncJobResponse;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class AsyncJobJoinDaoTest {
|
||||
|
||||
@InjectMocks
|
||||
AsyncJobJoinDaoImpl dao;
|
||||
|
||||
@Test
|
||||
public void testNewAsyncJobResponseValidValues() {
|
||||
final AsyncJobJoinVO job = new AsyncJobJoinVO();
|
||||
ReflectionTestUtils.setField(job,"uuid","a2b22932-1b61-4406-8e89-4ae19968e8d3");
|
||||
ReflectionTestUtils.setField(job,"accountUuid","4dea2836-72cc-11e8-b2de-107b4429825a");
|
||||
ReflectionTestUtils.setField(job,"domainUuid","4dea136b-72cc-11e8-b2de-107b4429825a");
|
||||
ReflectionTestUtils.setField(job,"userUuid","4decc724-72cc-11e8-b2de-107b4429825a");
|
||||
ReflectionTestUtils.setField(job,"cmd","org.apache.cloudstack.api.command.admin.vm.StartVMCmdByAdmin");
|
||||
ReflectionTestUtils.setField(job,"status",0);
|
||||
ReflectionTestUtils.setField(job,"resultCode",0);
|
||||
ReflectionTestUtils.setField(job,"result",null);
|
||||
ReflectionTestUtils.setField(job,"created",new Date());
|
||||
ReflectionTestUtils.setField(job,"removed",new Date());
|
||||
ReflectionTestUtils.setField(job,"instanceType",ApiCommandJobType.VirtualMachine);
|
||||
ReflectionTestUtils.setField(job,"instanceId",3L);
|
||||
final AsyncJobResponse response = dao.newAsyncJobResponse(job);
|
||||
Assert.assertEquals(job.getUuid(),response.getJobId());
|
||||
Assert.assertEquals(job.getAccountUuid(), ReflectionTestUtils.getField(response, "accountId"));
|
||||
Assert.assertEquals(job.getUserUuid(), ReflectionTestUtils.getField(response, "userId"));
|
||||
Assert.assertEquals(job.getCmd(), ReflectionTestUtils.getField(response, "cmd"));
|
||||
Assert.assertEquals(job.getStatus(), ReflectionTestUtils.getField(response, "jobStatus"));
|
||||
Assert.assertEquals(job.getStatus(), ReflectionTestUtils.getField(response, "jobProcStatus"));
|
||||
Assert.assertEquals(job.getResultCode(), ReflectionTestUtils.getField(response, "jobResultCode"));
|
||||
Assert.assertEquals(null, ReflectionTestUtils.getField(response, "jobResultType"));
|
||||
Assert.assertEquals(job.getResult(), ReflectionTestUtils.getField(response, "jobResult"));
|
||||
Assert.assertEquals(job.getInstanceType().toString(), ReflectionTestUtils.getField(response, "jobInstanceType"));
|
||||
Assert.assertEquals(job.getInstanceUuid(), ReflectionTestUtils.getField(response, "jobInstanceId"));
|
||||
Assert.assertEquals(job.getCreated(), ReflectionTestUtils.getField(response, "created"));
|
||||
Assert.assertEquals(job.getRemoved(), ReflectionTestUtils.getField(response, "removed"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNewAsyncJobResponseNullValues() {
|
||||
final AsyncJobJoinVO job = new AsyncJobJoinVO();
|
||||
final AsyncJobResponse response = dao.newAsyncJobResponse(job);
|
||||
Assert.assertEquals(job.getUuid(),response.getJobId());
|
||||
Assert.assertEquals(job.getAccountUuid(), ReflectionTestUtils.getField(response, "accountId"));
|
||||
Assert.assertEquals(job.getUserUuid(), ReflectionTestUtils.getField(response, "userId"));
|
||||
Assert.assertEquals(job.getCmd(), ReflectionTestUtils.getField(response, "cmd"));
|
||||
Assert.assertEquals(job.getStatus(), ReflectionTestUtils.getField(response, "jobStatus"));
|
||||
Assert.assertEquals(job.getStatus(), ReflectionTestUtils.getField(response, "jobProcStatus"));
|
||||
Assert.assertEquals(job.getResultCode(), ReflectionTestUtils.getField(response, "jobResultCode"));
|
||||
Assert.assertEquals(null, ReflectionTestUtils.getField(response, "jobResultType"));
|
||||
Assert.assertEquals(job.getResult(), ReflectionTestUtils.getField(response, "jobResult"));
|
||||
Assert.assertEquals(job.getInstanceType(), ReflectionTestUtils.getField(response, "jobInstanceType"));
|
||||
Assert.assertEquals(job.getInstanceUuid(), ReflectionTestUtils.getField(response, "jobInstanceId"));
|
||||
Assert.assertEquals(job.getCreated(), ReflectionTestUtils.getField(response, "created"));
|
||||
Assert.assertEquals(job.getRemoved(), ReflectionTestUtils.getField(response, "removed"));
|
||||
}
|
||||
}
|
||||
135
test/integration/smoke/test_async_job.py
Normal file
135
test/integration/smoke/test_async_job.py
Normal file
@ -0,0 +1,135 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from nose.plugins.attrib import attr
|
||||
from marvin.cloudstackTestCase import cloudstackTestCase
|
||||
from marvin.lib.utils import cleanup_resources
|
||||
from marvin.lib.base import ServiceOffering, DiskOffering, Account, VirtualMachine,\
|
||||
queryAsyncJobResult, PASS
|
||||
from marvin.lib.common import get_domain, get_zone, get_test_template
|
||||
from pytz import timezone
|
||||
|
||||
|
||||
class TestAsyncJob(cloudstackTestCase):
|
||||
"""
|
||||
Test queryAsyncJobResult
|
||||
"""
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
cls.testClient = super(TestAsyncJob, cls).getClsTestClient()
|
||||
cls.api_client = cls.testClient.getApiClient()
|
||||
|
||||
cls.testdata = cls.testClient.getParsedTestDataConfig()
|
||||
# Get Zone, Domain and templates
|
||||
cls.domain = get_domain(cls.api_client)
|
||||
cls.zone = get_zone(cls.api_client, cls.testClient.getZoneForTests())
|
||||
cls.hypervisor = cls.testClient.getHypervisorInfo()
|
||||
|
||||
cls.template = get_test_template(
|
||||
cls.api_client,
|
||||
cls.zone.id,
|
||||
cls.hypervisor
|
||||
)
|
||||
|
||||
# Create service, disk offerings etc
|
||||
cls.service_offering = ServiceOffering.create(
|
||||
cls.api_client,
|
||||
cls.testdata["service_offering"]
|
||||
)
|
||||
|
||||
cls.disk_offering = DiskOffering.create(
|
||||
cls.api_client,
|
||||
cls.testdata["disk_offering"]
|
||||
)
|
||||
|
||||
cls._cleanup = [
|
||||
cls.service_offering,
|
||||
cls.disk_offering
|
||||
]
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
try:
|
||||
cleanup_resources(cls.api_client, cls._cleanup)
|
||||
except Exception as exception:
|
||||
raise Exception("Warning: Exception during cleanup : %s" % exception)
|
||||
|
||||
def setUp(self):
|
||||
self.apiclient = self.testClient.getApiClient()
|
||||
self.dbclient = self.testClient.getDbConnection()
|
||||
self.hypervisor = self.testClient.getHypervisorInfo()
|
||||
self.testdata["virtual_machine"]["zoneid"] = self.zone.id
|
||||
self.testdata["virtual_machine"]["template"] = self.template.id
|
||||
self.testdata["iso"]["zoneid"] = self.zone.id
|
||||
self.account = Account.create(
|
||||
self.apiclient,
|
||||
self.testdata["account"],
|
||||
domainid=self.domain.id
|
||||
)
|
||||
self.cleanup = [self.account]
|
||||
|
||||
def tearDown(self):
|
||||
try:
|
||||
self.debug("Cleaning up the resources")
|
||||
cleanup_resources(self.apiclient, self.cleanup)
|
||||
self.debug("Cleanup complete!")
|
||||
except Exception as exception:
|
||||
self.debug("Warning! Exception in tearDown: %s" % exception)
|
||||
|
||||
@attr(tags=["advanced", "eip", "advancedns", "basic", "sg"], required_hardware="false")
|
||||
def test_query_async_job_result(self):
|
||||
"""
|
||||
Test queryAsyncJobResult API for expected values
|
||||
"""
|
||||
self.debug("Deploying instance in the account: %s" %
|
||||
self.account.name)
|
||||
virtual_machine = VirtualMachine.create(
|
||||
self.apiclient,
|
||||
self.testdata["virtual_machine"],
|
||||
accountid=self.account.name,
|
||||
domainid=self.account.domainid,
|
||||
serviceofferingid=self.service_offering.id,
|
||||
diskofferingid=self.disk_offering.id,
|
||||
hypervisor=self.hypervisor
|
||||
)
|
||||
|
||||
response = virtual_machine.getState(
|
||||
self.apiclient,
|
||||
VirtualMachine.RUNNING)
|
||||
self.assertEqual(response[0], PASS, response[1])
|
||||
|
||||
cmd = queryAsyncJobResult.queryAsyncJobResultCmd()
|
||||
cmd.jobid = virtual_machine.jobid
|
||||
cmd_response = self.apiclient.queryAsyncJobResult(cmd)
|
||||
|
||||
db_result = self.dbclient.execute("select * from async_job where uuid='%s'" %
|
||||
virtual_machine.jobid)
|
||||
|
||||
# verify that 'completed' value from api equals 'removed' db column value
|
||||
completed = cmd_response.completed
|
||||
removed = timezone('UTC').localize(db_result[0][17])
|
||||
removed = removed.strftime("%Y-%m-%dT%H:%M:%S%z")
|
||||
self.assertEqual(completed, removed,
|
||||
"Expected 'completed' timestamp value %s to be equal to "
|
||||
"'removed' db column value %s." % (completed, removed))
|
||||
|
||||
# verify that api job_status value equals db job_status value
|
||||
jobstatus_db = db_result[0][8]
|
||||
jobstatus_api = cmd_response.jobstatus
|
||||
self.assertEqual(jobstatus_api, jobstatus_db,
|
||||
"Expected 'jobstatus' api value %s to be equal to "
|
||||
"'job_status' db column value %s." % (jobstatus_api, jobstatus_db))
|
||||
@ -54,7 +54,8 @@ setup(name="Marvin",
|
||||
"pyvmomi >= 5.5.0",
|
||||
"netaddr >= 0.7.14",
|
||||
"dnspython",
|
||||
"ipmisim >= 0.7"
|
||||
"ipmisim >= 0.7",
|
||||
"pytz"
|
||||
],
|
||||
extras_require={
|
||||
"nuagevsp": ["vspk", "PyYAML", "futures", "netaddr", "retries", "jpype1"]
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user