Skip to content

Commit 941cc83

Browse files
Feature: Safely shutdown cloudstack (#6755)
Co-authored-by: dahn <daan.hoogland@gmail.com>
1 parent 62b332e commit 941cc83

48 files changed

Lines changed: 1926 additions & 145 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/org/apache/cloudstack/api/ApiConstants.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -523,6 +523,7 @@ public class ApiConstants {
523523
public static final String PRIVATE_NETWORK_ID = "privatenetworkid";
524524
public static final String ALLOCATION_STATE = "allocationstate";
525525
public static final String MANAGED_STATE = "managedstate";
526+
public static final String MANAGEMENT_SERVER_ID = "managementserverid";
526527
public static final String STORAGE_ID = "storageid";
527528
public static final String PING_STORAGE_SERVER_IP = "pingstorageserverip";
528529
public static final String PING_DIR = "pingdir";
@@ -1018,6 +1019,10 @@ public class ApiConstants {
10181019
public static final String LOGOUT = "logout";
10191020
public static final String LIST_IDPS = "listIdps";
10201021

1022+
public static final String READY_FOR_SHUTDOWN = "readyforshutdown";
1023+
public static final String SHUTDOWN_TRIGGERED = "shutdowntriggered";
1024+
public static final String PENDING_JOBS_COUNT = "pendingjobscount";
1025+
10211026
public static final String PUBLIC_MTU = "publicmtu";
10221027
public static final String PRIVATE_MTU = "privatemtu";
10231028
public static final String MTU = "mtu";

api/src/main/java/org/apache/cloudstack/api/command/user/job/ListAsyncJobsCmd.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import org.apache.cloudstack.api.Parameter;
2525
import org.apache.cloudstack.api.response.AsyncJobResponse;
2626
import org.apache.cloudstack.api.response.ListResponse;
27+
import org.apache.cloudstack.api.response.ManagementServerResponse;
2728

2829
@APICommand(name = "listAsyncJobs", description = "Lists all pending asynchronous jobs for the account.", responseObject = AsyncJobResponse.class,
2930
requestHasSensitiveInfo = false, responseHasSensitiveInfo = false)
@@ -36,6 +37,9 @@ public class ListAsyncJobsCmd extends BaseListAccountResourcesCmd {
3637
@Parameter(name = ApiConstants.START_DATE, type = CommandType.DATE, description = "The start date of the async job (use format \"yyyy-MM-dd'T'HH:mm:ss'+'SSSS\")")
3738
private Date startDate;
3839

40+
@Parameter(name = ApiConstants.MANAGEMENT_SERVER_ID, type = CommandType.UUID, entityType = ManagementServerResponse.class, description = "The id of the management server", since="4.19")
41+
private Long managementServerId;
42+
3943
/////////////////////////////////////////////////////
4044
/////////////////// Accessors ///////////////////////
4145
/////////////////////////////////////////////////////
@@ -44,6 +48,10 @@ public Date getStartDate() {
4448
return startDate;
4549
}
4650

51+
public Long getManagementServerId() {
52+
return managementServerId;
53+
}
54+
4755
/////////////////////////////////////////////////////
4856
/////////////// API Implementation///////////////////
4957
/////////////////////////////////////////////////////

api/src/main/java/org/apache/cloudstack/api/response/AsyncJobResponse.java

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,21 @@
3232
public class AsyncJobResponse extends BaseResponse {
3333

3434
@SerializedName("accountid")
35-
@Param(description = "the account that executed the async command")
35+
@Param(description = "the account id that executed the async command")
3636
private String accountId;
3737

38+
@SerializedName("account")
39+
@Param(description = "the account that executed the async command")
40+
private String account;
41+
42+
@SerializedName("domainid")
43+
@Param(description = "the domain id that executed the async command")
44+
private String domainid;
45+
46+
@SerializedName("domainpath")
47+
@Param(description = "the domain that executed the async command")
48+
private String domainPath;
49+
3850
@SerializedName(ApiConstants.USER_ID)
3951
@Param(description = "the user that executed the async command")
4052
private String userId;
@@ -71,6 +83,10 @@ public class AsyncJobResponse extends BaseResponse {
7183
@Param(description = "the unique ID of the instance/entity object related to the job")
7284
private String jobInstanceId;
7385

86+
@SerializedName("managementserverid")
87+
@Param(description = "the msid of the management server on which the job is running", since = "4.19")
88+
private Long msid;
89+
7490
@SerializedName(ApiConstants.CREATED)
7591
@Param(description = " the created date of the job")
7692
private Date created;
@@ -83,6 +99,18 @@ public void setAccountId(String accountId) {
8399
this.accountId = accountId;
84100
}
85101

102+
public void setAccount(String account) {
103+
this.account = account;
104+
}
105+
106+
public void setDomainId(String domainid) {
107+
this.domainid = domainid;
108+
}
109+
110+
public void setDomainPath(String domainPath) {
111+
this.domainPath = domainPath;
112+
}
113+
86114
public void setUserId(String userId) {
87115
this.userId = userId;
88116
}
@@ -127,4 +155,8 @@ public void setCreated(Date created) {
127155
public void setRemoved(final Date removed) {
128156
this.removed = removed;
129157
}
158+
159+
public void setMsid(Long msid) {
160+
this.msid = msid;
161+
}
130162
}

api/src/main/java/org/apache/cloudstack/management/ManagementServerHost.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121

2222
public interface ManagementServerHost extends InternalIdentity, Identity {
2323
enum State {
24-
Up, Down
24+
Up, Down, PreparingToShutDown, ReadyToShutDown, ShuttingDown
2525
}
2626

2727
long getMsid();

client/pom.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -552,6 +552,11 @@
552552
<artifactId>cloud-plugin-integrations-kubernetes-service</artifactId>
553553
<version>${project.version}</version>
554554
</dependency>
555+
<dependency>
556+
<groupId>org.apache.cloudstack</groupId>
557+
<artifactId>cloud-plugin-shutdown</artifactId>
558+
<version>${project.version}</version>
559+
</dependency>
555560
</dependencies>
556561
<build>
557562
<plugins>

engine/orchestration/pom.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,11 @@
6868
<artifactId>cloud-server</artifactId>
6969
<version>${project.version}</version>
7070
</dependency>
71+
<dependency>
72+
<groupId>org.apache.cloudstack</groupId>
73+
<artifactId>cloud-plugin-shutdown</artifactId>
74+
<version>${project.version}</version>
75+
</dependency>
7176
</dependencies>
7277
<build>
7378
<plugins>

engine/orchestration/src/main/java/com/cloud/agent/manager/ClusteredAgentManagerImpl.java

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,11 @@
5050
import org.apache.cloudstack.managed.context.ManagedContextRunnable;
5151
import org.apache.cloudstack.managed.context.ManagedContextTimerTask;
5252
import org.apache.cloudstack.outofbandmanagement.dao.OutOfBandManagementDao;
53+
import org.apache.cloudstack.shutdown.ShutdownManager;
54+
import org.apache.cloudstack.shutdown.command.CancelShutdownManagementServerHostCommand;
55+
import org.apache.cloudstack.shutdown.command.PrepareForShutdownManagementServerHostCommand;
56+
import org.apache.cloudstack.shutdown.command.BaseShutdownManagementServerHostCommand;
57+
import org.apache.cloudstack.shutdown.command.TriggerShutdownManagementServerHostCommand;
5358
import org.apache.cloudstack.utils.identity.ManagementServerNode;
5459
import org.apache.cloudstack.utils.security.SSLUtils;
5560
import org.apache.log4j.Logger;
@@ -129,6 +134,8 @@ public class ClusteredAgentManagerImpl extends AgentManagerImpl implements Clust
129134
private HAConfigDao haConfigDao;
130135
@Inject
131136
private CAManager caService;
137+
@Inject
138+
private ShutdownManager shutdownManager;
132139

133140
protected ClusteredAgentManagerImpl() {
134141
super();
@@ -1341,8 +1348,10 @@ public String dispatch(final ClusterServicePdu pdu) {
13411348
return _gson.toJson(answers);
13421349
} else if (cmds.length == 1 && cmds[0] instanceof ScheduleHostScanTaskCommand) {
13431350
final ScheduleHostScanTaskCommand cmd = (ScheduleHostScanTaskCommand)cmds[0];
1344-
final String response = handleScheduleHostScanTaskCommand(cmd);
1345-
return response;
1351+
return handleScheduleHostScanTaskCommand(cmd);
1352+
} else if (cmds.length == 1 && cmds[0] instanceof BaseShutdownManagementServerHostCommand) {
1353+
final BaseShutdownManagementServerHostCommand cmd = (BaseShutdownManagementServerHostCommand)cmds[0];
1354+
return handleShutdownManagementServerHostCommand(cmd);
13461355
}
13471356

13481357
try {
@@ -1376,6 +1385,36 @@ public String dispatch(final ClusterServicePdu pdu) {
13761385
return null;
13771386
}
13781387

1388+
private String handleShutdownManagementServerHostCommand(BaseShutdownManagementServerHostCommand cmd) {
1389+
if (cmd instanceof PrepareForShutdownManagementServerHostCommand) {
1390+
s_logger.debug("Received BaseShutdownManagementServerHostCommand - preparing to shut down");
1391+
try {
1392+
shutdownManager.prepareForShutdown();
1393+
return "Successfully prepared for shutdown";
1394+
} catch(CloudRuntimeException e) {
1395+
return e.getMessage();
1396+
}
1397+
}
1398+
if (cmd instanceof TriggerShutdownManagementServerHostCommand) {
1399+
s_logger.debug("Received TriggerShutdownManagementServerHostCommand - triggering a shut down");
1400+
try {
1401+
shutdownManager.triggerShutdown();
1402+
return "Successfully triggered shutdown";
1403+
} catch(CloudRuntimeException e) {
1404+
return e.getMessage();
1405+
}
1406+
}
1407+
if (cmd instanceof CancelShutdownManagementServerHostCommand) {
1408+
s_logger.debug("Received CancelShutdownManagementServerHostCommand - cancelling shut down");
1409+
try {
1410+
shutdownManager.cancelShutdown();
1411+
return "Successfully prepared for shutdown";
1412+
} catch(CloudRuntimeException e) {
1413+
return e.getMessage();
1414+
}
1415+
}
1416+
throw new CloudRuntimeException("Unknown BaseShutdownManagementServerHostCommand command received : " + cmd);
1417+
}
13791418
}
13801419

13811420
public boolean executeAgentUserRequest(final long agentId, final Event event) throws AgentUnavailableException {

engine/schema/src/main/resources/META-INF/db/schema-41720to41800.sql

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1582,4 +1582,4 @@ UPDATE
15821582
SET
15831583
usage_type = 22
15841584
WHERE
1585-
usage_type = 24 AND usage_display like '% io write';
1585+
usage_type = 24 AND usage_display like '% io write';

engine/schema/src/main/resources/META-INF/db/schema-41810to41900.sql

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,115 @@
1919
-- Schema upgrade from 4.18.1.0 to 4.19.0.0
2020
--;
2121

22+
ALTER TABLE `cloud`.`mshost` MODIFY COLUMN `state` varchar(25);
23+
24+
DROP VIEW IF EXISTS `cloud`.`async_job_view`;
25+
CREATE VIEW `cloud`.`async_job_view` AS
26+
select
27+
account.id account_id,
28+
account.uuid account_uuid,
29+
account.account_name account_name,
30+
account.type account_type,
31+
domain.id domain_id,
32+
domain.uuid domain_uuid,
33+
domain.name domain_name,
34+
domain.path domain_path,
35+
user.id user_id,
36+
user.uuid user_uuid,
37+
async_job.id,
38+
async_job.uuid,
39+
async_job.job_cmd,
40+
async_job.job_status,
41+
async_job.job_process_status,
42+
async_job.job_result_code,
43+
async_job.job_result,
44+
async_job.created,
45+
async_job.removed,
46+
async_job.instance_type,
47+
async_job.instance_id,
48+
async_job.job_executing_msid,
49+
CASE
50+
WHEN async_job.instance_type = 'Volume' THEN volumes.uuid
51+
WHEN
52+
async_job.instance_type = 'Template'
53+
or async_job.instance_type = 'Iso'
54+
THEN
55+
vm_template.uuid
56+
WHEN
57+
async_job.instance_type = 'VirtualMachine'
58+
or async_job.instance_type = 'ConsoleProxy'
59+
or async_job.instance_type = 'SystemVm'
60+
or async_job.instance_type = 'DomainRouter'
61+
THEN
62+
vm_instance.uuid
63+
WHEN async_job.instance_type = 'Snapshot' THEN snapshots.uuid
64+
WHEN async_job.instance_type = 'Host' THEN host.uuid
65+
WHEN async_job.instance_type = 'StoragePool' THEN storage_pool.uuid
66+
WHEN async_job.instance_type = 'IpAddress' THEN user_ip_address.uuid
67+
WHEN async_job.instance_type = 'SecurityGroup' THEN security_group.uuid
68+
WHEN async_job.instance_type = 'PhysicalNetwork' THEN physical_network.uuid
69+
WHEN async_job.instance_type = 'TrafficType' THEN physical_network_traffic_types.uuid
70+
WHEN async_job.instance_type = 'PhysicalNetworkServiceProvider' THEN physical_network_service_providers.uuid
71+
WHEN async_job.instance_type = 'FirewallRule' THEN firewall_rules.uuid
72+
WHEN async_job.instance_type = 'Account' THEN acct.uuid
73+
WHEN async_job.instance_type = 'User' THEN us.uuid
74+
WHEN async_job.instance_type = 'StaticRoute' THEN static_routes.uuid
75+
WHEN async_job.instance_type = 'PrivateGateway' THEN vpc_gateways.uuid
76+
WHEN async_job.instance_type = 'Counter' THEN counter.uuid
77+
WHEN async_job.instance_type = 'Condition' THEN conditions.uuid
78+
WHEN async_job.instance_type = 'AutoScalePolicy' THEN autoscale_policies.uuid
79+
WHEN async_job.instance_type = 'AutoScaleVmProfile' THEN autoscale_vmprofiles.uuid
80+
WHEN async_job.instance_type = 'AutoScaleVmGroup' THEN autoscale_vmgroups.uuid
81+
ELSE null
82+
END instance_uuid
83+
from
84+
`cloud`.`async_job`
85+
left join
86+
`cloud`.`account` ON async_job.account_id = account.id
87+
left join
88+
`cloud`.`domain` ON domain.id = account.domain_id
89+
left join
90+
`cloud`.`user` ON async_job.user_id = user.id
91+
left join
92+
`cloud`.`volumes` ON async_job.instance_id = volumes.id
93+
left join
94+
`cloud`.`vm_template` ON async_job.instance_id = vm_template.id
95+
left join
96+
`cloud`.`vm_instance` ON async_job.instance_id = vm_instance.id
97+
left join
98+
`cloud`.`snapshots` ON async_job.instance_id = snapshots.id
99+
left join
100+
`cloud`.`host` ON async_job.instance_id = host.id
101+
left join
102+
`cloud`.`storage_pool` ON async_job.instance_id = storage_pool.id
103+
left join
104+
`cloud`.`user_ip_address` ON async_job.instance_id = user_ip_address.id
105+
left join
106+
`cloud`.`security_group` ON async_job.instance_id = security_group.id
107+
left join
108+
`cloud`.`physical_network` ON async_job.instance_id = physical_network.id
109+
left join
110+
`cloud`.`physical_network_traffic_types` ON async_job.instance_id = physical_network_traffic_types.id
111+
left join
112+
`cloud`.`physical_network_service_providers` ON async_job.instance_id = physical_network_service_providers.id
113+
left join
114+
`cloud`.`firewall_rules` ON async_job.instance_id = firewall_rules.id
115+
left join
116+
`cloud`.`account` acct ON async_job.instance_id = acct.id
117+
left join
118+
`cloud`.`user` us ON async_job.instance_id = us.id
119+
left join
120+
`cloud`.`static_routes` ON async_job.instance_id = static_routes.id
121+
left join
122+
`cloud`.`vpc_gateways` ON async_job.instance_id = vpc_gateways.id
123+
left join
124+
`cloud`.`counter` ON async_job.instance_id = counter.id
125+
left join
126+
`cloud`.`conditions` ON async_job.instance_id = conditions.id
127+
left join
128+
`cloud`.`autoscale_policies` ON async_job.instance_id = autoscale_policies.id
129+
left join
130+
`cloud`.`autoscale_vmprofiles` ON async_job.instance_id = autoscale_vmprofiles.id
131+
left join
132+
`cloud`.`autoscale_vmgroups` ON async_job.instance_id = autoscale_vmgroups.id;
133+

framework/jobs/src/main/java/org/apache/cloudstack/framework/jobs/AsyncJob.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,8 @@ public static interface Constants {
9090
@Override
9191
Long getExecutingMsid();
9292

93+
void setExecutingMsid(Long msid);
94+
9395
@Override
9496
Long getCompleteMsid();
9597

0 commit comments

Comments
 (0)