From f909d494a01b209c71b49fc5d9240e3d2d86fe6d Mon Sep 17 00:00:00 2001 From: vishesh92 Date: Fri, 8 May 2026 13:42:30 +0530 Subject: [PATCH] fixup --- .../schedule/CreateResourceScheduleCmd.java | 34 +++--- .../schedule/DeleteResourceScheduleCmd.java | 25 ++-- .../schedule/ListResourceScheduleCmd.java | 31 +++-- .../schedule/UpdateResourceScheduleCmd.java | 16 +-- .../command/user/vm/CreateVMScheduleCmd.java | 27 ++--- .../command/user/vm/DeleteVMScheduleCmd.java | 16 +-- .../command/user/vm/ListVMScheduleCmd.java | 31 ++--- .../command/user/vm/UpdateVMScheduleCmd.java | 17 +-- .../api/response/VMScheduleResponse.java | 4 +- .../cloudstack/schedule/ResourceSchedule.java | 3 - .../schedule/ResourceScheduleManager.java | 22 ++-- .../user/vm/CreateVMScheduleCmdTest.java | 2 + .../user/vm/DeleteVMScheduleCmdTest.java | 1 + .../user/vm/ListVMScheduleCmdTest.java | 1 + .../user/vm/UpdateVMScheduleCmdTest.java | 4 +- .../schedule/ResourceScheduleDetailVO.java | 4 +- .../schedule/ResourceScheduleVO.java | 2 +- .../schedule/dao/ResourceScheduleDao.java | 2 +- .../schedule/dao/ResourceScheduleDaoImpl.java | 46 +++----- .../dao/ResourceScheduleDetailsDao.java | 3 +- .../dao/ResourceScheduledJobDaoImpl.java | 4 +- .../vm/schedule/dao/VMScheduleDao.java | 28 ----- .../vm/schedule/dao/VMScheduledJobDao.java | 28 ----- .../META-INF/db/schema-42210to42300.sql | 3 + .../schedule/BaseScheduleWorker.java | 25 ++-- .../schedule/ResourceScheduleManagerImpl.java | 111 ++++++++---------- .../schedule/vm/VMScheduleWorker.java | 26 ++-- .../ResourceScheduleManagerImplTest.java | 11 ++ .../schedule/vm/VMScheduleWorkerTest.java | 6 +- tools/apidoc/gen_toc.py | 1 + 30 files changed, 226 insertions(+), 308 deletions(-) delete mode 100644 engine/schema/src/main/java/org/apache/cloudstack/vm/schedule/dao/VMScheduleDao.java delete mode 100644 engine/schema/src/main/java/org/apache/cloudstack/vm/schedule/dao/VMScheduledJobDao.java diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/schedule/CreateResourceScheduleCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/schedule/CreateResourceScheduleCmd.java index 44a48115270..0dceb4d0b77 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/user/schedule/CreateResourceScheduleCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/user/schedule/CreateResourceScheduleCmd.java @@ -16,23 +16,21 @@ // under the License. package org.apache.cloudstack.api.command.user.schedule; -import java.util.Date; -import java.util.Map; - -import javax.inject.Inject; - +import com.cloud.exception.InvalidParameterValueException; import org.apache.cloudstack.acl.RoleType; import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.ApiCommandResourceType; -import org.apache.commons.lang3.EnumUtils; -import com.cloud.exception.InvalidParameterValueException; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.BaseCmd; import org.apache.cloudstack.api.Parameter; -import org.apache.cloudstack.api.TaggedResources; import org.apache.cloudstack.api.response.ResourceScheduleResponse; import org.apache.cloudstack.context.CallContext; import org.apache.cloudstack.schedule.ResourceScheduleManager; +import org.apache.commons.lang3.EnumUtils; + +import javax.inject.Inject; +import java.util.Date; +import java.util.Map; @APICommand(name = "createResourceSchedule", description = "Create Resource Schedule", responseObject = ResourceScheduleResponse.class, requestHasSensitiveInfo = false, responseHasSensitiveInfo = false, since = "4.23.0", @@ -72,8 +70,12 @@ public class CreateResourceScheduleCmd extends BaseCmd { @Parameter(name = ApiConstants.DETAILS, type = CommandType.MAP, required = false, description = "Map of (key/value pairs) details for the schedule.") private Map details; - public String getResourceType() { - return resourceType; + public ApiCommandResourceType getResourceType() { + ApiCommandResourceType type = EnumUtils.getEnumIgnoreCase(ApiCommandResourceType.class, resourceType); + if (type == null) { + throw new InvalidParameterValueException("Unknown resource type: " + resourceType); + } + return type; } public String getResourceId() { @@ -112,20 +114,12 @@ public class CreateResourceScheduleCmd extends BaseCmd { } public Map getDetails() { - Map detailsMap = null; - if (details != null && !details.isEmpty()) { - detailsMap = TaggedResources.parseKeyValueMap(details, true); - } - return detailsMap; + return convertDetailsToMap(details); } @Override public void execute() { - ApiCommandResourceType type = EnumUtils.getEnumIgnoreCase(ApiCommandResourceType.class, getResourceType()); - if (type == null) { - throw new InvalidParameterValueException("Unknown resource type: " + getResourceType()); - } - ResourceScheduleResponse response = resourceScheduleManager.createSchedule(type, getResourceId(), + ResourceScheduleResponse response = resourceScheduleManager.createSchedule(getResourceType(), getResourceId(), getDescription(), getSchedule(), getTimeZone(), getAction(), getStartDate(), getEndDate(), getEnabled(), getDetails()); response.setResponseName(getCommandName()); setResponseObject(response); diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/schedule/DeleteResourceScheduleCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/schedule/DeleteResourceScheduleCmd.java index c4d760d46a5..ce64c82e680 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/user/schedule/DeleteResourceScheduleCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/user/schedule/DeleteResourceScheduleCmd.java @@ -16,15 +16,10 @@ // under the License. package org.apache.cloudstack.api.command.user.schedule; -import java.util.List; - -import javax.inject.Inject; - +import com.cloud.exception.InvalidParameterValueException; import org.apache.cloudstack.acl.RoleType; import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.ApiCommandResourceType; -import org.apache.commons.lang3.EnumUtils; -import com.cloud.exception.InvalidParameterValueException; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.BaseCmd; import org.apache.cloudstack.api.Parameter; @@ -32,6 +27,10 @@ import org.apache.cloudstack.api.response.ResourceScheduleResponse; import org.apache.cloudstack.api.response.SuccessResponse; import org.apache.cloudstack.context.CallContext; import org.apache.cloudstack.schedule.ResourceScheduleManager; +import org.apache.commons.lang3.EnumUtils; + +import javax.inject.Inject; +import java.util.List; @APICommand(name = "deleteResourceSchedule", description = "Delete Resource Schedule", responseObject = SuccessResponse.class, requestHasSensitiveInfo = false, responseHasSensitiveInfo = false, since = "4.23.0", @@ -53,8 +52,12 @@ public class DeleteResourceScheduleCmd extends BaseCmd { @Parameter(name = ApiConstants.IDS, type = CommandType.LIST, collectionType = CommandType.UUID, entityType = ResourceScheduleResponse.class, required = false, description = "comma separated list of schedule ids to be deleted") private List ids; - public String getResourceType() { - return resourceType; + public ApiCommandResourceType getResourceType() { + ApiCommandResourceType type = EnumUtils.getEnumIgnoreCase(ApiCommandResourceType.class, resourceType); + if (type == null) { + throw new InvalidParameterValueException("Unknown resource type: " + resourceType); + } + return type; } public String getResourceId() { @@ -71,11 +74,7 @@ public class DeleteResourceScheduleCmd extends BaseCmd { @Override public void execute() { - ApiCommandResourceType type = EnumUtils.getEnumIgnoreCase(ApiCommandResourceType.class, getResourceType()); - if (type == null) { - throw new InvalidParameterValueException("Unknown resource type: " + getResourceType()); - } - resourceScheduleManager.removeSchedule(type, getResourceId(), getId(), getIds()); + resourceScheduleManager.removeSchedule(getResourceType(), getResourceId(), getId(), getIds()); SuccessResponse response = new SuccessResponse(getCommandName()); setResponseObject(response); } diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/schedule/ListResourceScheduleCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/schedule/ListResourceScheduleCmd.java index acb8c55c6d0..e2c702ac61c 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/user/schedule/ListResourceScheduleCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/user/schedule/ListResourceScheduleCmd.java @@ -16,21 +16,20 @@ // under the License. package org.apache.cloudstack.api.command.user.schedule; -import java.util.List; - -import javax.inject.Inject; - +import com.cloud.exception.InvalidParameterValueException; import org.apache.cloudstack.acl.RoleType; import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.ApiCommandResourceType; -import org.apache.commons.lang3.EnumUtils; -import com.cloud.exception.InvalidParameterValueException; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.BaseListCmd; import org.apache.cloudstack.api.Parameter; import org.apache.cloudstack.api.response.ListResponse; import org.apache.cloudstack.api.response.ResourceScheduleResponse; import org.apache.cloudstack.schedule.ResourceScheduleManager; +import org.apache.commons.lang3.EnumUtils; + +import javax.inject.Inject; +import java.util.List; @APICommand(name = "listResourceSchedule", description = "List Resource Schedules", responseObject = ResourceScheduleResponse.class, requestHasSensitiveInfo = false, responseHasSensitiveInfo = false, since = "4.23.0", @@ -66,8 +65,12 @@ public class ListResourceScheduleCmd extends BaseListCmd { return ids; } - public String getResourceType() { - return resourceType; + public ApiCommandResourceType getResourceType() { + ApiCommandResourceType type = EnumUtils.getEnumIgnoreCase(ApiCommandResourceType.class, resourceType); + if (type == null) { + throw new InvalidParameterValueException("Unknown resource type: " + resourceType); + } + return type; } public String getResourceId() { @@ -84,14 +87,10 @@ public class ListResourceScheduleCmd extends BaseListCmd { @Override public void execute() { - ApiCommandResourceType type = null; - if (getResourceType() != null) { - type = EnumUtils.getEnumIgnoreCase(ApiCommandResourceType.class, getResourceType()); - if (type == null) { - throw new InvalidParameterValueException("Unknown resource type: " + getResourceType()); - } - } - ListResponse response = resourceScheduleManager.listSchedule(getId(), getIds(), type, getResourceId(), getAction(), getEnabled(), getStartIndex(), getPageSizeVal()); + ListResponse response = resourceScheduleManager.listSchedule( + getId(), getIds(), getResourceType(), getResourceId(), getAction(), getEnabled(), + getStartIndex(), getPageSizeVal() + ); response.setResponseName(getCommandName()); setResponseObject(response); } diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/schedule/UpdateResourceScheduleCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/schedule/UpdateResourceScheduleCmd.java index 9005e9ce43a..5422588853e 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/user/schedule/UpdateResourceScheduleCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/user/schedule/UpdateResourceScheduleCmd.java @@ -16,21 +16,19 @@ // under the License. package org.apache.cloudstack.api.command.user.schedule; -import java.util.Date; -import java.util.Map; - -import javax.inject.Inject; - import org.apache.cloudstack.acl.RoleType; import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.BaseCmd; import org.apache.cloudstack.api.Parameter; -import org.apache.cloudstack.api.TaggedResources; import org.apache.cloudstack.api.response.ResourceScheduleResponse; import org.apache.cloudstack.context.CallContext; import org.apache.cloudstack.schedule.ResourceScheduleManager; +import javax.inject.Inject; +import java.util.Date; +import java.util.Map; + @APICommand(name = "updateResourceSchedule", description = "Update Resource Schedule", responseObject = ResourceScheduleResponse.class, requestHasSensitiveInfo = false, responseHasSensitiveInfo = false, since = "4.23.0", authorized = {RoleType.Admin, RoleType.ResourceAdmin, RoleType.DomainAdmin, RoleType.User}) @@ -92,11 +90,7 @@ public class UpdateResourceScheduleCmd extends BaseCmd { } public Map getDetails() { - Map detailsMap = null; - if (details != null && !details.isEmpty()) { - detailsMap = TaggedResources.parseKeyValueMap(details, true); - } - return detailsMap; + return convertDetailsToMap(details); } @Override diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/vm/CreateVMScheduleCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/vm/CreateVMScheduleCmd.java index dece0cbda85..512d5f4f40d 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/user/vm/CreateVMScheduleCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/user/vm/CreateVMScheduleCmd.java @@ -22,6 +22,7 @@ import com.cloud.exception.InvalidParameterValueException; import com.cloud.vm.VirtualMachine; import org.apache.cloudstack.acl.RoleType; import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.ApiCommandResourceType; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.BaseCmd; import org.apache.cloudstack.api.Parameter; @@ -29,9 +30,6 @@ import org.apache.cloudstack.api.response.ResourceScheduleResponse; import org.apache.cloudstack.api.response.UserVmResponse; import org.apache.cloudstack.api.response.VMScheduleResponse; import org.apache.cloudstack.schedule.ResourceScheduleManager; -import org.apache.cloudstack.schedule.vm.VMScheduleAction; -import org.apache.cloudstack.api.ApiCommandResourceType; -import org.apache.commons.lang3.EnumUtils; import javax.inject.Inject; import java.util.Date; @@ -95,9 +93,9 @@ public class CreateVMScheduleCmd extends BaseCmd { description = "Enable Instance schedule. Defaults to true") private Boolean enabled; - ///////////////////////////////////////////////////// - /////////////////// Accessors /////////////////////// - ///////////////////////////////////////////////////// + /// ////////////////////////////////////////////////// + /// //////////////// Accessors /////////////////////// + /// ////////////////////////////////////////////////// public Long getVmId() { return vmId; @@ -134,26 +132,17 @@ public class CreateVMScheduleCmd extends BaseCmd { return enabled; } - ///////////////////////////////////////////////////// - /////////////// API Implementation/////////////////// - ///////////////////////////////////////////////////// + /// ////////////////////////////////////////////////// + /// //////////// API Implementation/////////////////// + /// ////////////////////////////////////////////////// @Override public void execute() { - String actionStr = null; - if (getAction() != null) { - VMScheduleAction vmAction = EnumUtils.getEnumIgnoreCase(VMScheduleAction.class, getAction()); - if (vmAction == null) { - throw new InvalidParameterValueException(String.format("Invalid value for action: %s", getAction())); - } - actionStr = vmAction.name(); - } - String resourceIdStr = getVmId() != null ? String.valueOf(getVmId()) : null; ResourceScheduleResponse scheduleResponse = resourceScheduleManager.createSchedule( ApiCommandResourceType.VirtualMachine, - resourceIdStr, getDescription(), getSchedule(), getTimeZone(), actionStr, + resourceIdStr, getDescription(), getSchedule(), getTimeZone(), getAction(), getStartDate(), getEndDate(), getEnabled(), null); VMScheduleResponse response = new VMScheduleResponse(scheduleResponse); response.setResponseName(getCommandName()); diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/vm/DeleteVMScheduleCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/vm/DeleteVMScheduleCmd.java index 78ea07b647b..8269c7a26d0 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/user/vm/DeleteVMScheduleCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/user/vm/DeleteVMScheduleCmd.java @@ -22,6 +22,7 @@ import com.cloud.exception.InvalidParameterValueException; import com.cloud.vm.VirtualMachine; import org.apache.cloudstack.acl.RoleType; import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.ApiCommandResourceType; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.ApiErrorCode; import org.apache.cloudstack.api.BaseCmd; @@ -31,7 +32,6 @@ import org.apache.cloudstack.api.response.SuccessResponse; import org.apache.cloudstack.api.response.UserVmResponse; import org.apache.cloudstack.api.response.VMScheduleResponse; import org.apache.cloudstack.schedule.ResourceScheduleManager; -import org.apache.cloudstack.api.ApiCommandResourceType; import javax.inject.Inject; import java.util.Collections; @@ -50,12 +50,14 @@ public class DeleteVMScheduleCmd extends BaseCmd { required = true, description = "ID of Instance") private Long vmId; + @Parameter(name = ApiConstants.ID, type = CommandType.UUID, entityType = VMScheduleResponse.class, required = false, description = "ID of Instance schedule") private Long id; + @Parameter(name = ApiConstants.IDS, type = CommandType.LIST, collectionType = CommandType.UUID, @@ -64,9 +66,9 @@ public class DeleteVMScheduleCmd extends BaseCmd { description = "IDs of Instance schedule") private List ids; - ///////////////////////////////////////////////////// - /////////////////// Accessors /////////////////////// - ///////////////////////////////////////////////////// + /// ////////////////////////////////////////////////// + /// //////////////// Accessors /////////////////////// + /// ////////////////////////////////////////////////// public Long getId() { return id; @@ -83,9 +85,9 @@ public class DeleteVMScheduleCmd extends BaseCmd { return vmId; } - ///////////////////////////////////////////////////// - /////////////// API Implementation/////////////////// - ///////////////////////////////////////////////////// + /// ////////////////////////////////////////////////// + /// //////////// API Implementation/////////////////// + /// ////////////////////////////////////////////////// @Override public void execute() { diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/vm/ListVMScheduleCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/vm/ListVMScheduleCmd.java index e032566f2a9..e8df429ec09 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/user/vm/ListVMScheduleCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/user/vm/ListVMScheduleCmd.java @@ -20,6 +20,7 @@ package org.apache.cloudstack.api.command.user.vm; import org.apache.cloudstack.acl.RoleType; import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.ApiCommandResourceType; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.BaseListCmd; import org.apache.cloudstack.api.Parameter; @@ -28,10 +29,6 @@ import org.apache.cloudstack.api.response.ResourceScheduleResponse; import org.apache.cloudstack.api.response.UserVmResponse; import org.apache.cloudstack.api.response.VMScheduleResponse; import org.apache.cloudstack.schedule.ResourceScheduleManager; -import org.apache.cloudstack.schedule.vm.VMScheduleAction; -import org.apache.cloudstack.api.ApiCommandResourceType; -import org.apache.commons.lang3.EnumUtils; -import com.cloud.exception.InvalidParameterValueException; import javax.inject.Inject; import java.util.ArrayList; @@ -70,9 +67,9 @@ public class ListVMScheduleCmd extends BaseListCmd { description = "ID of Instance schedule") private Boolean enabled; - ///////////////////////////////////////////////////// - /////////////////// Accessors /////////////////////// - ///////////////////////////////////////////////////// + /// ////////////////////////////////////////////////// + /// //////////////// Accessors /////////////////////// + /// ////////////////////////////////////////////////// public Long getVmId() { return vmId; @@ -90,24 +87,18 @@ public class ListVMScheduleCmd extends BaseListCmd { return enabled; } - ///////////////////////////////////////////////////// - /////////////// API Implementation/////////////////// - ///////////////////////////////////////////////////// + /// ////////////////////////////////////////////////// + /// //////////// API Implementation/////////////////// + /// ////////////////////////////////////////////////// @Override public void execute() { - String actionStr = null; - if (getAction() != null) { - VMScheduleAction vmAction = EnumUtils.getEnumIgnoreCase(VMScheduleAction.class, getAction()); - if (vmAction == null) { - throw new InvalidParameterValueException("Invalid value for action: " + getAction()); - } - actionStr = vmAction.name(); - } - String resourceIdStr = getVmId() != null ? String.valueOf(getVmId()) : null; ListResponse scheduleResponse = resourceScheduleManager.listSchedule( - getId(), null, ApiCommandResourceType.VirtualMachine, resourceIdStr, actionStr, getEnabled(), getStartIndex(), getPageSizeVal()); + getId(), null, ApiCommandResourceType.VirtualMachine, resourceIdStr, getAction(), getEnabled(), + getStartIndex(), getPageSizeVal() + ); + List vmScheduleResponses = new ArrayList<>(); for (ResourceScheduleResponse resourceScheduleResponse : scheduleResponse.getResponses()) { vmScheduleResponses.add(new VMScheduleResponse(resourceScheduleResponse)); diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/vm/UpdateVMScheduleCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/vm/UpdateVMScheduleCmd.java index 033a8ae7147..93a010923c0 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/user/vm/UpdateVMScheduleCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/user/vm/UpdateVMScheduleCmd.java @@ -22,12 +22,12 @@ import com.cloud.exception.InvalidParameterValueException; import com.cloud.vm.VirtualMachine; import org.apache.cloudstack.acl.RoleType; import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.ApiCommandResourceType; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.BaseCmd; import org.apache.cloudstack.api.Parameter; import org.apache.cloudstack.api.response.ResourceScheduleResponse; import org.apache.cloudstack.api.response.VMScheduleResponse; -import org.apache.cloudstack.api.ApiCommandResourceType; import org.apache.cloudstack.schedule.ResourceSchedule; import org.apache.cloudstack.schedule.ResourceScheduleManager; @@ -86,9 +86,9 @@ public class UpdateVMScheduleCmd extends BaseCmd { description = "Enable Instance schedule") private Boolean enabled; - ///////////////////////////////////////////////////// - /////////////////// Accessors /////////////////////// - ///////////////////////////////////////////////////// + /// ////////////////////////////////////////////////// + /// //////////////// Accessors /////////////////////// + /// ////////////////////////////////////////////////// public Long getId() { return id; @@ -118,9 +118,9 @@ public class UpdateVMScheduleCmd extends BaseCmd { return enabled; } - ///////////////////////////////////////////////////// - /////////////// API Implementation/////////////////// - ///////////////////////////////////////////////////// + /// ////////////////////////////////////////////////// + /// //////////// API Implementation/////////////////// + /// ////////////////////////////////////////////////// @Override public void execute() { @@ -138,6 +138,9 @@ public class UpdateVMScheduleCmd extends BaseCmd { throw new InvalidParameterValueException(String.format("Unable to find VM schedule by id=%d", getId())); } VirtualMachine vm = _entityMgr.findById(VirtualMachine.class, schedule.getResourceId()); + if (vm == null) { + throw new InvalidParameterValueException(String.format("Unable to find VM schedule by id=%d", getId())); + } return vm.getAccountId(); } } diff --git a/api/src/main/java/org/apache/cloudstack/api/response/VMScheduleResponse.java b/api/src/main/java/org/apache/cloudstack/api/response/VMScheduleResponse.java index 63947468cb8..34455b3a0bf 100644 --- a/api/src/main/java/org/apache/cloudstack/api/response/VMScheduleResponse.java +++ b/api/src/main/java/org/apache/cloudstack/api/response/VMScheduleResponse.java @@ -119,5 +119,7 @@ public class VMScheduleResponse extends BaseResponse { this.endDate = endDate; } - public void setCreated(Date created) { this.created = created; } + public void setCreated(Date created) { + this.created = created; + } } diff --git a/api/src/main/java/org/apache/cloudstack/schedule/ResourceSchedule.java b/api/src/main/java/org/apache/cloudstack/schedule/ResourceSchedule.java index a6cdaafc86e..4bd39211a27 100644 --- a/api/src/main/java/org/apache/cloudstack/schedule/ResourceSchedule.java +++ b/api/src/main/java/org/apache/cloudstack/schedule/ResourceSchedule.java @@ -33,10 +33,8 @@ public interface ResourceSchedule extends Identity, InternalIdentity { * and {@link #getEventType()} without knowing the concrete type. */ interface Action { - /** Enum constant name (START, STOP, SCALE_UP, …). */ String name(); - /** CloudStack event type string used for audit / quota attribution. */ String getEventType(); } @@ -50,7 +48,6 @@ public interface ResourceSchedule extends Identity, InternalIdentity { String getTimeZone(); - /** Returns the raw action name stored in the DB (e.g. "START", "SCALE_UP"). */ String getActionName(); boolean getEnabled(); diff --git a/api/src/main/java/org/apache/cloudstack/schedule/ResourceScheduleManager.java b/api/src/main/java/org/apache/cloudstack/schedule/ResourceScheduleManager.java index b1792cadbd8..fb650a6cf68 100644 --- a/api/src/main/java/org/apache/cloudstack/schedule/ResourceScheduleManager.java +++ b/api/src/main/java/org/apache/cloudstack/schedule/ResourceScheduleManager.java @@ -18,26 +18,26 @@ */ package org.apache.cloudstack.schedule; +import org.apache.cloudstack.api.ApiCommandResourceType; +import org.apache.cloudstack.api.response.ListResponse; +import org.apache.cloudstack.api.response.ResourceScheduleResponse; + import java.util.Date; import java.util.List; import java.util.Map; -import org.apache.cloudstack.api.ApiCommandResourceType; - -import org.apache.cloudstack.api.response.ListResponse; -import org.apache.cloudstack.api.response.ResourceScheduleResponse; - public interface ResourceScheduleManager { - ResourceScheduleResponse createSchedule(ApiCommandResourceType resourceType, String resourceUuid, String description, - String schedule, String timeZone, String action, Date startDate, Date endDate, - boolean enabled, Map details); + ResourceScheduleResponse createSchedule(ApiCommandResourceType resourceType, String resourceUuid, + String description, String schedule, String timeZone, String action, + Date startDate, Date endDate, boolean enabled, Map details); - ResourceScheduleResponse updateSchedule(Long id, String description, String schedule, - String timeZone, Date startDate, Date endDate, Boolean enabled, Map details); + ResourceScheduleResponse updateSchedule(Long id, String description, String schedule, String timeZone, + Date startDate, Date endDate, Boolean enabled, Map details); ListResponse listSchedule(Long id, List ids, ApiCommandResourceType resourceType, - String resourceUuid, String action, Boolean enabled, Long startIndex, Long pageSize); + String resourceUuid, String action, Boolean enabled, + Long startIndex, Long pageSize); Long removeSchedule(ApiCommandResourceType resourceType, String resourceUuid, Long id, List ids); diff --git a/api/src/test/java/org/apache/cloudstack/api/command/user/vm/CreateVMScheduleCmdTest.java b/api/src/test/java/org/apache/cloudstack/api/command/user/vm/CreateVMScheduleCmdTest.java index 3a9b8548ca5..ae848b2712b 100644 --- a/api/src/test/java/org/apache/cloudstack/api/command/user/vm/CreateVMScheduleCmdTest.java +++ b/api/src/test/java/org/apache/cloudstack/api/command/user/vm/CreateVMScheduleCmdTest.java @@ -36,8 +36,10 @@ import org.mockito.MockitoAnnotations; public class CreateVMScheduleCmdTest { @Mock public ResourceScheduleManager resourceScheduleManager; + @Mock public EntityManager entityManager; + @InjectMocks private CreateVMScheduleCmd createVMScheduleCmd = new CreateVMScheduleCmd(); diff --git a/api/src/test/java/org/apache/cloudstack/api/command/user/vm/DeleteVMScheduleCmdTest.java b/api/src/test/java/org/apache/cloudstack/api/command/user/vm/DeleteVMScheduleCmdTest.java index 89ab14ac877..cec7503bd52 100644 --- a/api/src/test/java/org/apache/cloudstack/api/command/user/vm/DeleteVMScheduleCmdTest.java +++ b/api/src/test/java/org/apache/cloudstack/api/command/user/vm/DeleteVMScheduleCmdTest.java @@ -36,6 +36,7 @@ import org.mockito.MockitoAnnotations; public class DeleteVMScheduleCmdTest { @Mock public ResourceScheduleManager resourceScheduleManager; + @Mock public EntityManager entityManager; diff --git a/api/src/test/java/org/apache/cloudstack/api/command/user/vm/ListVMScheduleCmdTest.java b/api/src/test/java/org/apache/cloudstack/api/command/user/vm/ListVMScheduleCmdTest.java index 52e88191cae..5449be17a57 100644 --- a/api/src/test/java/org/apache/cloudstack/api/command/user/vm/ListVMScheduleCmdTest.java +++ b/api/src/test/java/org/apache/cloudstack/api/command/user/vm/ListVMScheduleCmdTest.java @@ -38,6 +38,7 @@ import java.util.Collections; public class ListVMScheduleCmdTest { @Mock public ResourceScheduleManager resourceScheduleManager; + @InjectMocks private ListVMScheduleCmd listVMScheduleCmd = new ListVMScheduleCmd(); private AutoCloseable closeable; diff --git a/api/src/test/java/org/apache/cloudstack/api/command/user/vm/UpdateVMScheduleCmdTest.java b/api/src/test/java/org/apache/cloudstack/api/command/user/vm/UpdateVMScheduleCmdTest.java index 85a884f96d2..a24252f4a1d 100644 --- a/api/src/test/java/org/apache/cloudstack/api/command/user/vm/UpdateVMScheduleCmdTest.java +++ b/api/src/test/java/org/apache/cloudstack/api/command/user/vm/UpdateVMScheduleCmdTest.java @@ -21,9 +21,9 @@ package org.apache.cloudstack.api.command.user.vm; import com.cloud.exception.InvalidParameterValueException; import com.cloud.utils.db.EntityManager; import com.cloud.vm.VirtualMachine; +import org.apache.cloudstack.api.ApiCommandResourceType; import org.apache.cloudstack.api.response.ResourceScheduleResponse; import org.apache.cloudstack.api.response.VMScheduleResponse; -import org.apache.cloudstack.api.ApiCommandResourceType; import org.apache.cloudstack.schedule.ResourceSchedule; import org.apache.cloudstack.schedule.ResourceScheduleManager; import org.junit.After; @@ -38,8 +38,10 @@ import org.mockito.MockitoAnnotations; public class UpdateVMScheduleCmdTest { @Mock public ResourceScheduleManager resourceScheduleManager; + @Mock public EntityManager entityManager; + @InjectMocks private UpdateVMScheduleCmd updateVMScheduleCmd = new UpdateVMScheduleCmd(); diff --git a/engine/schema/src/main/java/org/apache/cloudstack/schedule/ResourceScheduleDetailVO.java b/engine/schema/src/main/java/org/apache/cloudstack/schedule/ResourceScheduleDetailVO.java index 14076b61697..16985e6bac3 100644 --- a/engine/schema/src/main/java/org/apache/cloudstack/schedule/ResourceScheduleDetailVO.java +++ b/engine/schema/src/main/java/org/apache/cloudstack/schedule/ResourceScheduleDetailVO.java @@ -16,6 +16,8 @@ // under the License. package org.apache.cloudstack.schedule; +import org.apache.cloudstack.api.ResourceDetail; + import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; @@ -23,8 +25,6 @@ import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.Table; -import org.apache.cloudstack.api.ResourceDetail; - @Entity @Table(name = "resource_schedule_details") public class ResourceScheduleDetailVO implements ResourceDetail { diff --git a/engine/schema/src/main/java/org/apache/cloudstack/schedule/ResourceScheduleVO.java b/engine/schema/src/main/java/org/apache/cloudstack/schedule/ResourceScheduleVO.java index 5c3df12a0dc..e323b8cc449 100644 --- a/engine/schema/src/main/java/org/apache/cloudstack/schedule/ResourceScheduleVO.java +++ b/engine/schema/src/main/java/org/apache/cloudstack/schedule/ResourceScheduleVO.java @@ -89,7 +89,7 @@ public class ResourceScheduleVO implements ResourceSchedule { } public ResourceScheduleVO(ApiCommandResourceType resourceType, long resourceId, String description, String schedule, - String timeZone, String action, Date startDate, Date endDate, boolean enabled) { + String timeZone, String action, Date startDate, Date endDate, boolean enabled) { uuid = UUID.randomUUID().toString(); this.resourceType = resourceType; this.resourceId = resourceId; diff --git a/engine/schema/src/main/java/org/apache/cloudstack/schedule/dao/ResourceScheduleDao.java b/engine/schema/src/main/java/org/apache/cloudstack/schedule/dao/ResourceScheduleDao.java index 5e1beccf1f2..ee56991fb9a 100644 --- a/engine/schema/src/main/java/org/apache/cloudstack/schedule/dao/ResourceScheduleDao.java +++ b/engine/schema/src/main/java/org/apache/cloudstack/schedule/dao/ResourceScheduleDao.java @@ -34,7 +34,7 @@ public interface ResourceScheduleDao extends GenericDao, Integer> searchAndCount(List ids, ApiCommandResourceType resourceType, Long resourceId, - String action, Boolean enabled, Long offset, Long limit); + String action, Boolean enabled, Long offset, Long limit); SearchCriteria getSearchCriteriaForResource(ApiCommandResourceType resourceType, long resourceId); } diff --git a/engine/schema/src/main/java/org/apache/cloudstack/schedule/dao/ResourceScheduleDaoImpl.java b/engine/schema/src/main/java/org/apache/cloudstack/schedule/dao/ResourceScheduleDaoImpl.java index 80fcc8bdf68..ace249cab62 100644 --- a/engine/schema/src/main/java/org/apache/cloudstack/schedule/dao/ResourceScheduleDaoImpl.java +++ b/engine/schema/src/main/java/org/apache/cloudstack/schedule/dao/ResourceScheduleDaoImpl.java @@ -26,6 +26,7 @@ import com.cloud.utils.db.SearchCriteria; import org.apache.cloudstack.api.ApiCommandResourceType; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.schedule.ResourceScheduleVO; +import org.apache.commons.collections4.CollectionUtils; import org.springframework.stereotype.Component; import java.util.Date; @@ -35,9 +36,7 @@ import java.util.List; public class ResourceScheduleDaoImpl extends GenericDaoBase implements ResourceScheduleDao { private final SearchBuilder activeScheduleSearch; - private final SearchBuilder scheduleSearchByResourceAndIds; - private final SearchBuilder scheduleSearchByResource; - private final SearchBuilder scheduleSearch; + private final SearchBuilder allSearch; static final String RESOURCE_TYPE = "resourceType"; static final String RESOURCE_ID = "resourceId"; @@ -53,24 +52,13 @@ public class ResourceScheduleDaoImpl extends GenericDaoBase ids) { - SearchCriteria sc = scheduleSearchByResourceAndIds.create(); - sc.setParameters(ApiConstants.ID, ids.toArray()); + SearchCriteria sc = allSearch.create(); + if (CollectionUtils.isNotEmpty(ids)) { + sc.setParameters(ApiConstants.ID, ids.toArray()); + } sc.setParameters(RESOURCE_TYPE, resourceType); sc.setParameters(RESOURCE_ID, resourceId); return remove(sc); @@ -93,7 +83,7 @@ public class ResourceScheduleDaoImpl extends GenericDaoBase sc = scheduleSearchByResource.create(); + SearchCriteria sc = allSearch.create(); sc.setParameters(RESOURCE_TYPE, resourceType); sc.setParameters(RESOURCE_ID, resourceId); return remove(sc); @@ -101,9 +91,9 @@ public class ResourceScheduleDaoImpl extends GenericDaoBase, Integer> searchAndCount(List ids, ApiCommandResourceType resourceType, Long resourceId, - String action, Boolean enabled, Long offset, Long limit) { - SearchCriteria sc = scheduleSearch.create(); - if (ids != null && !ids.isEmpty()) { + String action, Boolean enabled, Long offset, Long limit) { + SearchCriteria sc = allSearch.create(); + if (CollectionUtils.isNotEmpty(ids)) { sc.setParameters(ApiConstants.ID, ids.toArray()); } sc.setParametersIfNotNull(ApiConstants.ENABLED, enabled); @@ -116,7 +106,7 @@ public class ResourceScheduleDaoImpl extends GenericDaoBase getSearchCriteriaForResource(ApiCommandResourceType resourceType, long resourceId) { - SearchCriteria sc = scheduleSearchByResource.create(); + SearchCriteria sc = allSearch.create(); sc.setParameters(RESOURCE_TYPE, resourceType); sc.setParameters(RESOURCE_ID, resourceId); return sc; diff --git a/engine/schema/src/main/java/org/apache/cloudstack/schedule/dao/ResourceScheduleDetailsDao.java b/engine/schema/src/main/java/org/apache/cloudstack/schedule/dao/ResourceScheduleDetailsDao.java index d07204ff6ac..f36ce8d0879 100644 --- a/engine/schema/src/main/java/org/apache/cloudstack/schedule/dao/ResourceScheduleDetailsDao.java +++ b/engine/schema/src/main/java/org/apache/cloudstack/schedule/dao/ResourceScheduleDetailsDao.java @@ -16,10 +16,9 @@ // under the License. package org.apache.cloudstack.schedule.dao; +import com.cloud.utils.db.GenericDao; import org.apache.cloudstack.resourcedetail.ResourceDetailsDao; import org.apache.cloudstack.schedule.ResourceScheduleDetailVO; -import com.cloud.utils.db.GenericDao; - public interface ResourceScheduleDetailsDao extends GenericDao, ResourceDetailsDao { } diff --git a/engine/schema/src/main/java/org/apache/cloudstack/schedule/dao/ResourceScheduledJobDaoImpl.java b/engine/schema/src/main/java/org/apache/cloudstack/schedule/dao/ResourceScheduledJobDaoImpl.java index bc64dbc96e4..02c1acb6c71 100644 --- a/engine/schema/src/main/java/org/apache/cloudstack/schedule/dao/ResourceScheduledJobDaoImpl.java +++ b/engine/schema/src/main/java/org/apache/cloudstack/schedule/dao/ResourceScheduledJobDaoImpl.java @@ -39,8 +39,8 @@ public class ResourceScheduledJobDaoImpl extends GenericDaoBase expungeJobForScheduleSearch; private final SearchBuilder scheduleAndTimestampSearch; - static final String SCHEDULED_TIMESTAMP = "scheduled_timestamp"; - static final String SCHEDULE_ID = "schedule_id"; + static final String SCHEDULED_TIMESTAMP = "scheduledTimestamp"; + static final String SCHEDULE_ID = "scheduleId"; static final String RESOURCE_TYPE = "resourceType"; public ResourceScheduledJobDaoImpl() { diff --git a/engine/schema/src/main/java/org/apache/cloudstack/vm/schedule/dao/VMScheduleDao.java b/engine/schema/src/main/java/org/apache/cloudstack/vm/schedule/dao/VMScheduleDao.java deleted file mode 100644 index 5d2c883cc26..00000000000 --- a/engine/schema/src/main/java/org/apache/cloudstack/vm/schedule/dao/VMScheduleDao.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * 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 org.apache.cloudstack.vm.schedule.dao; - -import org.apache.cloudstack.schedule.dao.ResourceScheduleDao; - -/** - * @deprecated Use {@link ResourceScheduleDao} directly. - */ -@Deprecated -public interface VMScheduleDao extends ResourceScheduleDao { -} diff --git a/engine/schema/src/main/java/org/apache/cloudstack/vm/schedule/dao/VMScheduledJobDao.java b/engine/schema/src/main/java/org/apache/cloudstack/vm/schedule/dao/VMScheduledJobDao.java deleted file mode 100644 index 9053286d681..00000000000 --- a/engine/schema/src/main/java/org/apache/cloudstack/vm/schedule/dao/VMScheduledJobDao.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * 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 org.apache.cloudstack.vm.schedule.dao; - -import org.apache.cloudstack.schedule.dao.ResourceScheduledJobDao; - -/** - * @deprecated Use {@link ResourceScheduledJobDao} directly. - */ -@Deprecated -public interface VMScheduledJobDao extends ResourceScheduledJobDao { -} diff --git a/engine/schema/src/main/resources/META-INF/db/schema-42210to42300.sql b/engine/schema/src/main/resources/META-INF/db/schema-42210to42300.sql index d5ecac1d18b..070667092f7 100644 --- a/engine/schema/src/main/resources/META-INF/db/schema-42210to42300.sql +++ b/engine/schema/src/main/resources/META-INF/db/schema-42210to42300.sql @@ -183,3 +183,6 @@ CREATE TABLE IF NOT EXISTS `cloud`.`resource_schedule_details` ( UPDATE `cloud`.`event` SET `type` = 'SCHEDULE.CREATE' WHERE `type` = 'VM.SCHEDULE.CREATE'; UPDATE `cloud`.`event` SET `type` = 'SCHEDULE.UPDATE' WHERE `type` = 'VM.SCHEDULE.UPDATE'; UPDATE `cloud`.`event` SET `type` = 'SCHEDULE.DELETE' WHERE `type` = 'VM.SCHEDULE.DELETE'; + +-- Step 5: Rename the global configuration key for the scheduler +UPDATE `cloud`.`configuration` SET name='scheduler.jobs.expire.interval' WHERE name='vmscheduler.jobs.expire.interval'; diff --git a/server/src/main/java/org/apache/cloudstack/schedule/BaseScheduleWorker.java b/server/src/main/java/org/apache/cloudstack/schedule/BaseScheduleWorker.java index c2471c7b425..6fd33fcd949 100644 --- a/server/src/main/java/org/apache/cloudstack/schedule/BaseScheduleWorker.java +++ b/server/src/main/java/org/apache/cloudstack/schedule/BaseScheduleWorker.java @@ -36,6 +36,7 @@ import org.apache.cloudstack.framework.jobs.impl.AsyncJobVO; import org.apache.cloudstack.managed.context.ManagedContextTimerTask; import org.apache.cloudstack.schedule.dao.ResourceScheduleDao; import org.apache.cloudstack.schedule.dao.ResourceScheduledJobDao; +import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang.time.DateUtils; import org.springframework.scheduling.support.CronExpression; @@ -66,8 +67,10 @@ public abstract class BaseScheduleWorker extends ManagerBase { @Inject protected ResourceScheduleDao resourceScheduleDao; + @Inject protected ResourceScheduledJobDao resourceScheduledJobDao; + @Inject protected AsyncJobManager asyncJobManager; @@ -83,10 +86,14 @@ public abstract class BaseScheduleWorker extends ManagerBase { asyncJobDispatcher = dispatcher; } - /** The API resource type this worker handles (e.g. {@code ApiCommandResourceType.VirtualMachine}). */ + /** + * The API resource type this worker handles (e.g. {@code ApiCommandResourceType.VirtualMachine}). + */ public abstract ApiCommandResourceType getApiResourceType(); - /** Convenience method returning {@code getApiResourceType().name()} for use in DAO queries, locks, and logging. */ + /** + * Convenience method returning {@code getApiResourceType().name()} for use in DAO queries, locks, and logging. + */ protected final String getResourceTypeName() { return getApiResourceType().name(); } @@ -258,7 +265,7 @@ public abstract class BaseScheduleWorker extends ManagerBase { } public void removeScheduledJobs(List scheduleIds) { - if (scheduleIds == null || scheduleIds.isEmpty()) { + if (CollectionUtils.isEmpty(scheduleIds)) { return; } int removed = resourceScheduledJobDao.expungeJobsForSchedules(scheduleIds, new Date()); @@ -312,7 +319,7 @@ public abstract class BaseScheduleWorker extends ManagerBase { } private void logSkippedJobs(Map executed, - Map> skipped) { + Map> skipped) { for (Map.Entry> entry : skipped.entrySet()) { long resourceId = entry.getKey(); ResourceScheduledJobVO running = executed.get(resourceId); @@ -333,16 +340,18 @@ public abstract class BaseScheduleWorker extends ManagerBase { // Subclass helpers // ------------------------------------------------------------------------- - /** Returns true when the given resource ID is valid and eligible for scheduling. */ public abstract boolean isResourceValid(long resourceId); - /** Returns the account that owns the given resource (for ACL / event attribution). */ public abstract long getEntityOwnerId(long resourceId); - /** Parses an action string into the resource-type-specific typed action constant. Throws InvalidParameterValueException for unknown values. */ + /** + * Parses an action string into the resource-type-specific typed action constant. Throws InvalidParameterValueException for unknown values. + */ public abstract ResourceSchedule.Action parseAction(String action); - /** Validates action-specific detail parameters. Throws InvalidParameterValueException on failure. */ + /** + * Validates action-specific detail parameters. Throws InvalidParameterValueException on failure. + */ public abstract void validateDetails(ResourceSchedule.Action action, Map details); /** diff --git a/server/src/main/java/org/apache/cloudstack/schedule/ResourceScheduleManagerImpl.java b/server/src/main/java/org/apache/cloudstack/schedule/ResourceScheduleManagerImpl.java index e8b11becf4c..0e4d58ba421 100644 --- a/server/src/main/java/org/apache/cloudstack/schedule/ResourceScheduleManagerImpl.java +++ b/server/src/main/java/org/apache/cloudstack/schedule/ResourceScheduleManagerImpl.java @@ -16,19 +16,21 @@ // under the License. package org.apache.cloudstack.schedule; -import java.time.ZonedDateTime; -import java.util.ArrayList; -import java.util.Date; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.TimeZone; - -import javax.inject.Inject; -import javax.naming.ConfigurationException; - +import com.cloud.api.query.MutualExclusiveIdsManagerBase; +import com.cloud.event.ActionEvent; +import com.cloud.event.EventTypes; +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.user.AccountManager; +import com.cloud.utils.DateUtil; +import com.cloud.utils.Pair; +import com.cloud.utils.component.PluggableService; +import com.cloud.utils.db.EntityManager; +import com.cloud.utils.db.Transaction; +import com.cloud.utils.db.TransactionCallback; +import com.cloud.utils.exception.CloudRuntimeException; import org.apache.cloudstack.api.ApiCommandResourceType; +import org.apache.cloudstack.api.Identity; +import org.apache.cloudstack.api.InternalIdentity; import org.apache.cloudstack.api.command.user.schedule.CreateResourceScheduleCmd; import org.apache.cloudstack.api.command.user.schedule.DeleteResourceScheduleCmd; import org.apache.cloudstack.api.command.user.schedule.ListResourceScheduleCmd; @@ -42,36 +44,36 @@ import org.apache.cloudstack.api.response.ResourceScheduleResponse; import org.apache.cloudstack.context.CallContext; import org.apache.cloudstack.framework.config.ConfigKey; import org.apache.cloudstack.framework.config.Configurable; -import org.apache.cloudstack.schedule.dao.ResourceScheduleDetailsDao; import org.apache.cloudstack.schedule.dao.ResourceScheduleDao; +import org.apache.cloudstack.schedule.dao.ResourceScheduleDetailsDao; import org.apache.commons.lang.time.DateUtils; import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; import org.springframework.scheduling.support.CronExpression; -import com.cloud.api.query.MutualExclusiveIdsManagerBase; -import com.cloud.event.ActionEvent; -import com.cloud.event.EventTypes; -import com.cloud.exception.InvalidParameterValueException; -import com.cloud.user.AccountManager; -import com.cloud.utils.DateUtil; -import com.cloud.utils.Pair; -import com.cloud.utils.component.PluggableService; -import com.cloud.utils.db.EntityManager; -import com.cloud.utils.db.Transaction; -import com.cloud.utils.db.TransactionCallback; -import com.cloud.utils.exception.CloudRuntimeException; -import org.apache.cloudstack.api.InternalIdentity; -import org.apache.cloudstack.api.Identity; +import javax.inject.Inject; +import javax.naming.ConfigurationException; +import java.time.ZonedDateTime; +import java.util.ArrayList; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.TimeZone; +import java.util.stream.Collectors; public class ResourceScheduleManagerImpl extends MutualExclusiveIdsManagerBase implements ResourceScheduleManager, PluggableService, Configurable { @Inject private ResourceScheduleDao resourceScheduleDao; + @Inject private ResourceScheduleDetailsDao resourceScheduleDetailsDao; + @Inject private AccountManager accountManager; + @Inject private EntityManager entityManager; @@ -120,7 +122,7 @@ public class ResourceScheduleManagerImpl extends MutualExclusiveIdsManagerBase i @Override public ConfigKey[] getConfigKeys() { - return new ConfigKey[] { + return new ConfigKey[]{ BaseScheduleWorker.ScheduledJobExpireInterval }; } @@ -254,33 +256,19 @@ public class ResourceScheduleManagerImpl extends MutualExclusiveIdsManagerBase i public ListResponse listSchedule(Long id, List ids, ApiCommandResourceType resourceType, String resourceUuid, String action, Boolean enabled, Long startIndex, Long pageSize) { - List scheduleIds = getIdsListFromCmd(id, ids); - if (!scheduleIds.isEmpty() && resourceType == null) { - throw new InvalidParameterValueException("resourcetype is required when filtering by id or ids"); + Long internalResourceId = null; + BaseScheduleWorker worker = getWorker(resourceType); + if (StringUtils.isBlank(resourceUuid)) { + throw new InvalidParameterValueException("Resource ID must be specified"); + } else { + internalResourceId = resolveResourceId(resourceUuid, worker.getApiResourceType().getAssociatedClass()); + long ownerId = worker.getEntityOwnerId(internalResourceId); + accountManager.checkAccess(CallContext.current().getCallingAccount(), null, false, accountManager.getAccount(ownerId)); } - Long internalResourceId = null; - if (resourceType != null) { - BaseScheduleWorker worker = getWorker(resourceType); - if (StringUtils.isNotBlank(resourceUuid)) { - internalResourceId = resolveResourceId(resourceUuid, worker.getApiResourceType().getAssociatedClass()); - long ownerId = worker.getEntityOwnerId(internalResourceId); - accountManager.checkAccess(CallContext.current().getCallingAccount(), null, false, accountManager.getAccount(ownerId)); - } - for (Long schedId : scheduleIds) { - ResourceScheduleVO scheduleVO = resourceScheduleDao.findById(schedId); - if (scheduleVO == null) { - throw new InvalidParameterValueException("Schedule " + schedId + " not found"); - } - if (!resourceType.equals(scheduleVO.getResourceType())) { - throw new InvalidParameterValueException("Schedule " + schedId + " is not of resource type " + resourceType); - } - long ownerId = worker.getEntityOwnerId(scheduleVO.getResourceId()); - accountManager.checkAccess(CallContext.current().getCallingAccount(), null, false, accountManager.getAccount(ownerId)); - } - if (action != null) { - action = worker.parseAction(action).name(); - } + List scheduleIds = getIdsListFromCmd(id, ids); + if (action != null) { + action = worker.parseAction(action).name(); } Pair, Integer> result = resourceScheduleDao.searchAndCount( @@ -442,22 +430,15 @@ public class ResourceScheduleManagerImpl extends MutualExclusiveIdsManagerBase i accountManager.checkAccess(CallContext.current().getCallingAccount(), null, false, accountManager.getAccount(ownerId)); List ids = getIdsListFromCmd(id, idsList); - - if (ids.isEmpty()) { - throw new InvalidParameterValueException("Either id or ids parameter must be specified"); - } - + Pair, Integer> result = resourceScheduleDao.searchAndCount(ids, resourceType, internalResourceId, null, null, null, null); + List schedulesToRemove = result.first(); + List scheduleIdsToRemove = schedulesToRemove.stream().map(ResourceScheduleVO::getId).collect(Collectors.toList()); return Transaction.execute((TransactionCallback) status -> { - worker.removeScheduledJobs(ids); - - for (Long schedId : ids) { - resourceScheduleDetailsDao.removeDetails(schedId); - } + worker.removeScheduledJobs(scheduleIdsToRemove); CallContext.current().setEventResourceId(internalResourceId); CallContext.current().setEventResourceType(worker.getApiResourceType()); - return resourceScheduleDao.removeSchedulesForResourceAndIds( - resourceType, internalResourceId, ids); + return resourceScheduleDao.removeSchedulesForResourceAndIds(resourceType, internalResourceId, scheduleIdsToRemove); }); } } diff --git a/server/src/main/java/org/apache/cloudstack/schedule/vm/VMScheduleWorker.java b/server/src/main/java/org/apache/cloudstack/schedule/vm/VMScheduleWorker.java index a21c1752f5b..398a80844bb 100644 --- a/server/src/main/java/org/apache/cloudstack/schedule/vm/VMScheduleWorker.java +++ b/server/src/main/java/org/apache/cloudstack/schedule/vm/VMScheduleWorker.java @@ -63,16 +63,15 @@ public class VMScheduleWorker extends BaseScheduleWorker { public VMScheduleAction parseAction(String actionName) { VMScheduleAction action = EnumUtils.getEnumIgnoreCase(VMScheduleAction.class, actionName); if (action == null) { - throw new InvalidParameterValueException("Invalid action for VirtualMachine schedule: " + actionName + - ". Supported actions: " + Arrays.toString(VMScheduleAction.values())); + throw new InvalidParameterValueException(String.format( + "Invalid action for VirtualMachine schedule: %s. Supported actions: %s", + actionName, Arrays.toString(VMScheduleAction.values()))); } return action; } @Override - public void validateDetails(ResourceSchedule.Action action, Map details) { - // No special details required/validated for VM schedules right now. - } + public void validateDetails(ResourceSchedule.Action action, Map details) {} @Override protected Long processJob(ResourceScheduledJobVO job) { @@ -88,7 +87,7 @@ public class VMScheduleWorker extends BaseScheduleWorker { return null; } - VMScheduleAction action = VMScheduleAction.valueOf(job.getActionName()); + VMScheduleAction action = parseAction(job.getActionName()); final long eventId = ActionEventUtils.onCompletedActionEvent( User.UID_SYSTEM, vm.getAccountId(), null, action.getEventType(), true, @@ -97,11 +96,16 @@ public class VMScheduleWorker extends BaseScheduleWorker { if (vm.getState() == VirtualMachine.State.Running) { switch (action) { - case STOP: return submitStopVMJob(vm, false, eventId); - case FORCE_STOP: return submitStopVMJob(vm, true, eventId); - case REBOOT: return submitRebootVMJob(vm, false, eventId); - case FORCE_REBOOT: return submitRebootVMJob(vm, true, eventId); - default: break; + case STOP: + return submitStopVMJob(vm, false, eventId); + case FORCE_STOP: + return submitStopVMJob(vm, true, eventId); + case REBOOT: + return submitRebootVMJob(vm, false, eventId); + case FORCE_REBOOT: + return submitRebootVMJob(vm, true, eventId); + default: + break; } } else if (vm.getState() == VirtualMachine.State.Stopped && action == VMScheduleAction.START) { return submitStartVMJob(vm, eventId); diff --git a/server/src/test/java/org/apache/cloudstack/schedule/ResourceScheduleManagerImplTest.java b/server/src/test/java/org/apache/cloudstack/schedule/ResourceScheduleManagerImplTest.java index 42ce0c300fd..e87459c2482 100644 --- a/server/src/test/java/org/apache/cloudstack/schedule/ResourceScheduleManagerImplTest.java +++ b/server/src/test/java/org/apache/cloudstack/schedule/ResourceScheduleManagerImplTest.java @@ -260,6 +260,17 @@ public class ResourceScheduleManagerImplTest { Mockito.when(resourceScheduleDao.removeSchedulesForResourceAndIds( Mockito.any(), Mockito.anyLong(), Mockito.anyList())).thenReturn(1L); + ResourceScheduleVO schedule1 = Mockito.mock(ResourceScheduleVO.class); + ResourceScheduleVO schedule2 = Mockito.mock(ResourceScheduleVO.class); + List scheduleList = new ArrayList<>(); + scheduleList.add(schedule1); + scheduleList.add(schedule2); + + Mockito.when(resourceScheduleDao.searchAndCount( + Mockito.any(), Mockito.any(), Mockito.any(), Mockito.any(), + Mockito.any(), Mockito.any(), Mockito.any()) + ).thenReturn(new Pair<>(scheduleList, scheduleList.size())); + Long rowsRemoved = resourceScheduleManager.removeSchedule( ApiCommandResourceType.VirtualMachine, "1", 10L, null); diff --git a/server/src/test/java/org/apache/cloudstack/schedule/vm/VMScheduleWorkerTest.java b/server/src/test/java/org/apache/cloudstack/schedule/vm/VMScheduleWorkerTest.java index 7040b1318f3..e2b435d76c7 100644 --- a/server/src/test/java/org/apache/cloudstack/schedule/vm/VMScheduleWorkerTest.java +++ b/server/src/test/java/org/apache/cloudstack/schedule/vm/VMScheduleWorkerTest.java @@ -89,9 +89,9 @@ public class VMScheduleWorkerTest { closeable = MockitoAnnotations.openMocks(this); actionEventUtilsMocked = Mockito.mockStatic(ActionEventUtils.class); Mockito.when(ActionEventUtils.onScheduledActionEvent(Mockito.anyLong(), Mockito.anyLong(), Mockito.anyString(), - Mockito.anyString(), Mockito.anyLong(), Mockito.anyString(), Mockito.anyBoolean(), - Mockito.anyLong())) - .thenReturn(1L); + Mockito.anyString(), Mockito.anyLong(), Mockito.anyString(), Mockito.anyBoolean(), + Mockito.anyLong())) + .thenReturn(1L); Mockito.when(ActionEventUtils.onCompletedActionEvent(Mockito.anyLong(), Mockito.anyLong(), Mockito.any(), Mockito.anyString(), Mockito.anyBoolean(), Mockito.anyString(), diff --git a/tools/apidoc/gen_toc.py b/tools/apidoc/gen_toc.py index 292f52d809b..95db9cdbc19 100644 --- a/tools/apidoc/gen_toc.py +++ b/tools/apidoc/gen_toc.py @@ -238,6 +238,7 @@ known_categories = { 'removeQuarantinedIp': 'IP Quarantine', 'Shutdown': 'Maintenance', 'Maintenance': 'Maintenance', + 'ResourceSchedule': 'Resource Schedule', 'addObjectStoragePool': 'Object Store', 'listObjectStoragePools': 'Object Store', 'deleteObjectStoragePool': 'Object Store',