Skip to content

Commit fa3f2a7

Browse files
authored
feature: VM Scheduler (apache#7397)
This PR adds a feature to setup schedules to stop/start/restart your VMs. Documentation PR: apache/cloudstack-documentation#313 Related issue: apache#3387
1 parent 409e320 commit fa3f2a7

41 files changed

Lines changed: 4560 additions & 73 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

api/src/main/java/com/cloud/event/EventTypes.java

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@
8484
import com.cloud.vm.Nic;
8585
import com.cloud.vm.NicSecondaryIp;
8686
import com.cloud.vm.VirtualMachine;
87+
import org.apache.cloudstack.vm.schedule.VMSchedule;
8788

8889
public class EventTypes {
8990

@@ -111,6 +112,17 @@ public class EventTypes {
111112
public static final String EVENT_VM_UNMANAGE = "VM.UNMANAGE";
112113
public static final String EVENT_VM_RECOVER = "VM.RECOVER";
113114

115+
// VM Schedule
116+
public static final String EVENT_VM_SCHEDULE_CREATE = "VM.SCHEDULE.CREATE";
117+
public static final String EVENT_VM_SCHEDULE_UPDATE = "VM.SCHEDULE.UPDATE";
118+
public static final String EVENT_VM_SCHEDULE_DELETE = "VM.SCHEDULE.DELETE";
119+
120+
public static final String EVENT_VM_SCHEDULE_START = "VM.SCHEDULE.START";
121+
public static final String EVENT_VM_SCHEDULE_STOP = "VM.SCHEDULE.STOP";
122+
public static final String EVENT_VM_SCHEDULE_REBOOT = "VM.SCHEDULE.REBOOT";
123+
public static final String EVENT_VM_SCHEDULE_FORCE_STOP = "VM.SCHEDULE.FORCE.STOP";
124+
public static final String EVENT_VM_SCHEDULE_FORCE_REBOOT = "VM.SCHEDULE.FORCE.REBOOT";
125+
114126
// Domain Router
115127
public static final String EVENT_ROUTER_CREATE = "ROUTER.CREATE";
116128
public static final String EVENT_ROUTER_DESTROY = "ROUTER.DESTROY";
@@ -716,6 +728,16 @@ public class EventTypes {
716728
entityEventDetails.put(EVENT_VM_IMPORT, VirtualMachine.class);
717729
entityEventDetails.put(EVENT_VM_UNMANAGE, VirtualMachine.class);
718730

731+
// VMSchedule
732+
entityEventDetails.put(EVENT_VM_SCHEDULE_CREATE, VMSchedule.class);
733+
entityEventDetails.put(EVENT_VM_SCHEDULE_DELETE, VMSchedule.class);
734+
entityEventDetails.put(EVENT_VM_SCHEDULE_UPDATE, VMSchedule.class);
735+
entityEventDetails.put(EVENT_VM_SCHEDULE_START, VMSchedule.class);
736+
entityEventDetails.put(EVENT_VM_SCHEDULE_STOP, VMSchedule.class);
737+
entityEventDetails.put(EVENT_VM_SCHEDULE_REBOOT, VMSchedule.class);
738+
entityEventDetails.put(EVENT_VM_SCHEDULE_FORCE_STOP, VMSchedule.class);
739+
entityEventDetails.put(EVENT_VM_SCHEDULE_FORCE_REBOOT, VMSchedule.class);
740+
719741
entityEventDetails.put(EVENT_ROUTER_CREATE, VirtualRouter.class);
720742
entityEventDetails.put(EVENT_ROUTER_DESTROY, VirtualRouter.class);
721743
entityEventDetails.put(EVENT_ROUTER_START, VirtualRouter.class);
Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
package org.apache.cloudstack.api.command.user.vm;
20+
21+
import com.cloud.exception.InvalidParameterValueException;
22+
import com.cloud.vm.VirtualMachine;
23+
import org.apache.cloudstack.acl.RoleType;
24+
import org.apache.cloudstack.api.APICommand;
25+
import org.apache.cloudstack.api.ApiConstants;
26+
import org.apache.cloudstack.api.BaseCmd;
27+
import org.apache.cloudstack.api.Parameter;
28+
import org.apache.cloudstack.api.response.UserVmResponse;
29+
import org.apache.cloudstack.api.response.VMScheduleResponse;
30+
import org.apache.cloudstack.vm.schedule.VMScheduleManager;
31+
32+
import javax.inject.Inject;
33+
import java.util.Date;
34+
35+
@APICommand(name = "createVMSchedule", description = "Create VM Schedule", responseObject = VMScheduleResponse.class,
36+
requestHasSensitiveInfo = false, responseHasSensitiveInfo = false, since = "4.19.0",
37+
authorized = {RoleType.Admin, RoleType.ResourceAdmin, RoleType.DomainAdmin, RoleType.User})
38+
public class CreateVMScheduleCmd extends BaseCmd {
39+
40+
@Inject
41+
VMScheduleManager vmScheduleManager;
42+
43+
@Parameter(name = ApiConstants.VIRTUAL_MACHINE_ID,
44+
type = CommandType.UUID,
45+
entityType = UserVmResponse.class,
46+
required = true,
47+
description = "ID of the VM for which schedule is to be defined")
48+
private Long vmId;
49+
50+
@Parameter(name = ApiConstants.DESCRIPTION,
51+
type = CommandType.STRING,
52+
required = false,
53+
description = "Description of the schedule")
54+
private String description;
55+
56+
@Parameter(name = ApiConstants.SCHEDULE,
57+
type = CommandType.STRING,
58+
required = true,
59+
description = "Schedule for action on VM in cron format. e.g. '0 15 10 * *' for 'at 15:00 on 10th day of every month'")
60+
private String schedule;
61+
62+
@Parameter(name = ApiConstants.TIMEZONE,
63+
type = CommandType.STRING,
64+
required = true,
65+
description = "Specifies a timezone for this command. For more information on the timezone parameter, see TimeZone Format.")
66+
private String timeZone;
67+
68+
@Parameter(name = ApiConstants.ACTION,
69+
type = CommandType.STRING,
70+
required = true,
71+
description = "Action to take on the VM (start/stop/restart/force_stop/force_reboot).")
72+
private String action;
73+
74+
@Parameter(name = ApiConstants.START_DATE,
75+
type = CommandType.DATE,
76+
required = false,
77+
description = "start date from which the schedule becomes active. Defaults to current date plus 1 minute."
78+
+ "Use format \"yyyy-MM-dd hh:mm:ss\")")
79+
private Date startDate;
80+
81+
@Parameter(name = ApiConstants.END_DATE,
82+
type = CommandType.DATE,
83+
required = false,
84+
description = "end date after which the schedule becomes inactive"
85+
+ "Use format \"yyyy-MM-dd hh:mm:ss\")")
86+
private Date endDate;
87+
88+
@Parameter(name = ApiConstants.ENABLED,
89+
type = CommandType.BOOLEAN,
90+
required = false,
91+
description = "Enable VM schedule. Defaults to true")
92+
private Boolean enabled;
93+
94+
/////////////////////////////////////////////////////
95+
/////////////////// Accessors ///////////////////////
96+
/////////////////////////////////////////////////////
97+
98+
public Long getVmId() {
99+
return vmId;
100+
}
101+
102+
public String getDescription() {
103+
return description;
104+
}
105+
106+
public String getSchedule() {
107+
return schedule;
108+
}
109+
110+
public String getTimeZone() {
111+
return timeZone;
112+
}
113+
114+
public String getAction() {
115+
return action;
116+
}
117+
118+
public Date getStartDate() {
119+
return startDate;
120+
}
121+
122+
public Date getEndDate() {
123+
return endDate;
124+
}
125+
126+
public Boolean getEnabled() {
127+
if (enabled == null) {
128+
enabled = true;
129+
}
130+
return enabled;
131+
}
132+
133+
/////////////////////////////////////////////////////
134+
/////////////// API Implementation///////////////////
135+
/////////////////////////////////////////////////////
136+
137+
@Override
138+
public void execute() {
139+
VMScheduleResponse response = vmScheduleManager.createSchedule(this);
140+
response.setResponseName(getCommandName());
141+
setResponseObject(response);
142+
}
143+
144+
@Override
145+
public long getEntityOwnerId() {
146+
VirtualMachine vm = _entityMgr.findById(VirtualMachine.class, getVmId());
147+
if (vm == null) {
148+
throw new InvalidParameterValueException(String.format("Unable to find VM by id=%d", getVmId()));
149+
}
150+
return vm.getAccountId();
151+
}
152+
}
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
package org.apache.cloudstack.api.command.user.vm;
20+
21+
import com.cloud.exception.InvalidParameterValueException;
22+
import com.cloud.vm.VirtualMachine;
23+
import org.apache.cloudstack.acl.RoleType;
24+
import org.apache.cloudstack.api.APICommand;
25+
import org.apache.cloudstack.api.ApiConstants;
26+
import org.apache.cloudstack.api.ApiErrorCode;
27+
import org.apache.cloudstack.api.BaseCmd;
28+
import org.apache.cloudstack.api.Parameter;
29+
import org.apache.cloudstack.api.ServerApiException;
30+
import org.apache.cloudstack.api.response.SuccessResponse;
31+
import org.apache.cloudstack.api.response.UserVmResponse;
32+
import org.apache.cloudstack.api.response.VMScheduleResponse;
33+
import org.apache.cloudstack.vm.schedule.VMSchedule;
34+
import org.apache.cloudstack.vm.schedule.VMScheduleManager;
35+
36+
import javax.inject.Inject;
37+
import java.util.Collections;
38+
import java.util.List;
39+
40+
@APICommand(name = "deleteVMSchedule", description = "Delete VM Schedule.", responseObject = SuccessResponse.class,
41+
requestHasSensitiveInfo = false, responseHasSensitiveInfo = false, since = "4.19.0",
42+
authorized = {RoleType.Admin, RoleType.ResourceAdmin, RoleType.DomainAdmin, RoleType.User})
43+
public class DeleteVMScheduleCmd extends BaseCmd {
44+
@Inject
45+
VMScheduleManager vmScheduleManager;
46+
47+
@Parameter(name = ApiConstants.VIRTUAL_MACHINE_ID,
48+
type = CommandType.UUID,
49+
entityType = UserVmResponse.class,
50+
required = true,
51+
description = "ID of VM")
52+
private Long vmId;
53+
@Parameter(name = ApiConstants.ID,
54+
type = CommandType.UUID,
55+
entityType = VMScheduleResponse.class,
56+
required = false,
57+
description = "ID of VM schedule")
58+
private Long id;
59+
@Parameter(name = ApiConstants.IDS,
60+
type = CommandType.LIST,
61+
collectionType = CommandType.UUID,
62+
entityType = VMScheduleResponse.class,
63+
required = false,
64+
description = "IDs of VM schedule")
65+
private List<Long> ids;
66+
67+
/////////////////////////////////////////////////////
68+
/////////////////// Accessors ///////////////////////
69+
/////////////////////////////////////////////////////
70+
71+
public Long getId() {
72+
return id;
73+
}
74+
75+
public List<Long> getIds() {
76+
if (ids == null) {
77+
return Collections.emptyList();
78+
}
79+
return ids;
80+
}
81+
82+
public Long getVmId() {
83+
return vmId;
84+
}
85+
86+
/////////////////////////////////////////////////////
87+
/////////////// API Implementation///////////////////
88+
/////////////////////////////////////////////////////
89+
90+
@Override
91+
public void execute() {
92+
long rowsRemoved = vmScheduleManager.removeSchedule(this);
93+
94+
if (rowsRemoved > 0) {
95+
final SuccessResponse response = new SuccessResponse();
96+
response.setResponseName(getCommandName());
97+
response.setObjectName(VMSchedule.class.getSimpleName().toLowerCase());
98+
setResponseObject(response);
99+
} else {
100+
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to delete VM Schedules");
101+
}
102+
}
103+
104+
@Override
105+
public long getEntityOwnerId() {
106+
VirtualMachine vm = _entityMgr.findById(VirtualMachine.class, getVmId());
107+
if (vm == null) {
108+
throw new InvalidParameterValueException(String.format("Unable to find VM by id=%d", getVmId()));
109+
}
110+
return vm.getAccountId();
111+
}
112+
}

0 commit comments

Comments
 (0)