Skip to content

Commit 8c8d115

Browse files
feature: Support Multi-arch Zones (#9619)
This introduces the multi-arch zones, allowing users to select the VM arch upon deployment. Multi-arch zone support in CloudStack can allow admins to mix x86_64 & arm64 hosts within the same zone with the following changes proposed: - All hosts in a clusters need to be homogenous, wrt host CPU type (amd64 vs arm64) and hypevisor - Arch-aware templates & ISOs: - Add support for a new arch field (default set of: amd64 and arm64), when unspecified defaults to amd64 and for existing templates & iso - Allow admins to edit the arch type of the registered template & iso - Arch-aware clusters and host: - Add new attribute field for cluster and hosts (kvm host agents can automatically report this, arch of the first host of the cluster is cluster's architecture), defaults to amd64 when not specified - Allow admins to edit the arch of an existing cluster - VM deployment form (UI): - In a multi-arch zone/env, the VM deployment form can allow some kind of template/iso filtration in the UI - Users should be able to select arch: amd64 & arm64; but this is shown only in a multi-arch zone (env) - VM orchestration and lifecycle operations: - Use of VM/template's arch to correctly decide where to provision the VM (on the correct strictly arch-matching host/clusters) & other lifecycle operations (such as migration from/to arch-matching hosts) Co-authored-by: Rohit Yadav <rohit.yadav@shapeblue.com>
1 parent 52b0696 commit 8c8d115

File tree

72 files changed

+926
-47
lines changed

Some content is hidden

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

72 files changed

+926
-47
lines changed

agent/src/main/java/com/cloud/agent/Agent.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -504,6 +504,13 @@ protected void setupStartupCommand(final StartupCommand startup) {
504504
startup.setGuid(getResourceGuid());
505505
startup.setResourceName(getResourceName());
506506
startup.setVersion(getVersion());
507+
startup.setArch(getAgentArch());
508+
}
509+
510+
protected String getAgentArch() {
511+
final Script command = new Script("/usr/bin/arch", 500, logger);
512+
final OutputInterpreter.OneLineParser parser = new OutputInterpreter.OneLineParser();
513+
return command.execute(parser);
507514
}
508515

509516
@Override
@@ -858,11 +865,21 @@ public void processReadyCommand(final Command cmd) {
858865
setId(ready.getHostId());
859866
}
860867

868+
verifyAgentArch(ready.getArch());
861869
processManagementServerList(ready.getMsHostList(), ready.getLbAlgorithm(), ready.getLbCheckInterval());
862870

863871
logger.info("Ready command is processed for agent id = {}", getId());
864872
}
865873

874+
private void verifyAgentArch(String arch) {
875+
if (StringUtils.isNotBlank(arch)) {
876+
String agentArch = getAgentArch();
877+
if (!arch.equals(agentArch)) {
878+
logger.error("Unexpected arch {}, expected {}", agentArch, arch);
879+
}
880+
}
881+
}
882+
866883
public void processOtherTask(final Task task) {
867884
final Object obj = task.get();
868885
if (obj instanceof Response) {
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
// Licensed to the Apache Software Foundation (ASF) under one
2+
// or more contributor license agreements. See the NOTICE file
3+
// distributed with this work for additional information
4+
// regarding copyright ownership. The ASF licenses this file
5+
// to you under the Apache License, Version 2.0 (the
6+
// "License"); you may not use this file except in compliance
7+
// with the License. You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing,
12+
// software distributed under the License is distributed on an
13+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
// KIND, either express or implied. See the License for the
15+
// specific language governing permissions and limitations
16+
// under the License.
17+
package com.cloud.cpu;
18+
19+
import com.cloud.utils.exception.CloudRuntimeException;
20+
import org.apache.commons.lang3.StringUtils;
21+
22+
import java.util.LinkedHashMap;
23+
import java.util.Map;
24+
25+
public class CPU {
26+
27+
public static final String archX86Identifier = "i686";
28+
public static final String archX86_64Identifier = "x86_64";
29+
public static final String archARM64Identifier = "aarch64";
30+
31+
public static class CPUArch {
32+
private static final Map<String, CPUArch> cpuArchMap = new LinkedHashMap<>();
33+
34+
public static final CPUArch archX86 = new CPUArch(archX86Identifier, 32);
35+
public static final CPUArch amd64 = new CPUArch(archX86_64Identifier, 64);
36+
public static final CPUArch arm64 = new CPUArch(archARM64Identifier, 64);
37+
38+
private String type;
39+
private int bits;
40+
41+
public CPUArch(String type, int bits) {
42+
this.type = type;
43+
this.bits = bits;
44+
cpuArchMap.put(type, this);
45+
}
46+
47+
public String getType() {
48+
return this.type;
49+
}
50+
51+
public int getBits() {
52+
return this.bits;
53+
}
54+
55+
public static CPUArch fromType(String type) {
56+
if (StringUtils.isBlank(type)) {
57+
return amd64;
58+
}
59+
switch (type) {
60+
case archX86Identifier: return archX86;
61+
case archX86_64Identifier: return amd64;
62+
case archARM64Identifier: return arm64;
63+
default: throw new CloudRuntimeException(String.format("Unsupported arch type: %s", type));
64+
}
65+
}
66+
}
67+
}

api/src/main/java/com/cloud/host/Host.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
// under the License.
1717
package com.cloud.host;
1818

19+
import com.cloud.cpu.CPU;
1920
import com.cloud.hypervisor.Hypervisor.HypervisorType;
2021
import com.cloud.resource.ResourceState;
2122
import com.cloud.utils.fsm.StateObject;
@@ -208,4 +209,6 @@ public static String[] toStrings(Host.Type... types) {
208209
boolean isDisabled();
209210

210211
ResourceState getResourceState();
212+
213+
CPU.CPUArch getArch();
211214
}

api/src/main/java/com/cloud/org/Cluster.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
// under the License.
1717
package com.cloud.org;
1818

19+
import com.cloud.cpu.CPU;
1920
import com.cloud.hypervisor.Hypervisor.HypervisorType;
2021
import com.cloud.org.Managed.ManagedState;
2122
import org.apache.cloudstack.kernel.Partition;
@@ -38,4 +39,6 @@ public static enum ClusterType {
3839
AllocationState getAllocationState();
3940

4041
ManagedState getManagedState();
42+
43+
CPU.CPUArch getArch();
4144
}

api/src/main/java/com/cloud/template/VirtualMachineTemplate.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import java.util.Date;
2020
import java.util.Map;
2121

22+
import com.cloud.cpu.CPU;
2223
import com.cloud.user.UserData;
2324
import org.apache.cloudstack.acl.ControlledEntity;
2425
import org.apache.cloudstack.api.Identity;
@@ -148,4 +149,6 @@ public enum TemplateFilter {
148149

149150
UserData.UserDataOverridePolicy getUserDataOverridePolicy();
150151

152+
CPU.CPUArch getArch();
153+
151154
}

api/src/main/java/org/apache/cloudstack/api/ApiConstants.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ public class ApiConstants {
3636
public static final String ANNOTATION = "annotation";
3737
public static final String API_KEY = "apikey";
3838
public static final String ARCHIVED = "archived";
39+
public static final String ARCH = "arch";
3940
public static final String AS_NUMBER = "asnumber";
4041
public static final String AS_NUMBER_ID = "asnumberid";
4142
public static final String ASN_RANGE = "asnrange";
@@ -326,6 +327,8 @@ public class ApiConstants {
326327
public static final String MIGRATIONS = "migrations";
327328
public static final String MEMORY = "memory";
328329
public static final String MODE = "mode";
330+
public static final String MULTI_ARCH = "ismultiarch";
331+
public static final String NSX_MODE = "nsxmode";
329332
public static final String NETWORK_MODE = "networkmode";
330333
public static final String NSX_ENABLED = "isnsxenabled";
331334
public static final String NAME = "name";

api/src/main/java/org/apache/cloudstack/api/BaseUpdateTemplateOrIsoCmd.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,10 @@
1616
// under the License.
1717
package org.apache.cloudstack.api;
1818

19+
import com.cloud.cpu.CPU;
1920
import org.apache.cloudstack.api.response.GuestOSResponse;
2021
import org.apache.cloudstack.api.response.TemplateResponse;
22+
import org.apache.commons.lang3.StringUtils;
2123

2224
import java.util.Collection;
2325
import java.util.Map;
@@ -77,6 +79,11 @@ public abstract class BaseUpdateTemplateOrIsoCmd extends BaseCmd {
7779
description = "optional boolean field, which indicates if details should be cleaned up or not (if set to true, details removed for this resource, details field ignored; if false or not set, no action)")
7880
private Boolean cleanupDetails;
7981

82+
@Parameter(name = ApiConstants.ARCH, type = CommandType.STRING,
83+
description = "the CPU arch of the template/ISO. Valid options are: x86_64, aarch64",
84+
since = "4.20")
85+
private String arch;
86+
8087
/////////////////////////////////////////////////////
8188
/////////////////// Accessors ///////////////////////
8289
/////////////////////////////////////////////////////
@@ -141,4 +148,11 @@ public Map getDetails() {
141148
public boolean isCleanupDetails(){
142149
return cleanupDetails == null ? false : cleanupDetails.booleanValue();
143150
}
151+
152+
public CPU.CPUArch getCPUArch() {
153+
if (StringUtils.isBlank(arch)) {
154+
return null;
155+
}
156+
return CPU.CPUArch.fromType(arch);
157+
}
144158
}

api/src/main/java/org/apache/cloudstack/api/command/admin/cluster/AddClusterCmd.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import java.util.ArrayList;
2121
import java.util.List;
2222

23+
import com.cloud.cpu.CPU;
2324
import org.apache.cloudstack.api.ApiCommandResourceType;
2425

2526
import org.apache.cloudstack.api.APICommand;
@@ -67,6 +68,11 @@ public class AddClusterCmd extends BaseCmd {
6768
description = "hypervisor type of the cluster: XenServer,KVM,VMware,Hyperv,BareMetal,Simulator,Ovm3")
6869
private String hypervisor;
6970

71+
@Parameter(name = ApiConstants.ARCH, type = CommandType.STRING,
72+
description = "the CPU arch of the cluster. Valid options are: x86_64, aarch64",
73+
since = "4.20")
74+
private String arch;
75+
7076
@Parameter(name = ApiConstants.CLUSTER_TYPE, type = CommandType.STRING, required = true, description = "type of the cluster: CloudManaged, ExternalManaged")
7177
private String clusterType;
7278

@@ -204,6 +210,10 @@ public ApiCommandResourceType getApiResourceType() {
204210
return ApiCommandResourceType.Cluster;
205211
}
206212

213+
public CPU.CPUArch getArch() {
214+
return CPU.CPUArch.fromType(arch);
215+
}
216+
207217
@Override
208218
public void execute() {
209219
try {

api/src/main/java/org/apache/cloudstack/api/command/admin/cluster/UpdateClusterCmd.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
// under the License.
1717
package org.apache.cloudstack.api.command.admin.cluster;
1818

19+
import com.cloud.cpu.CPU;
1920
import org.apache.cloudstack.api.ApiCommandResourceType;
2021

2122
import org.apache.cloudstack.api.APICommand;
@@ -29,6 +30,7 @@
2930
import com.cloud.exception.InvalidParameterValueException;
3031
import com.cloud.org.Cluster;
3132
import com.cloud.user.Account;
33+
import org.apache.commons.lang3.StringUtils;
3234

3335
@APICommand(name = "updateCluster", description = "Updates an existing cluster", responseObject = ClusterResponse.class,
3436
requestHasSensitiveInfo = false, responseHasSensitiveInfo = false)
@@ -53,6 +55,11 @@ public class UpdateClusterCmd extends BaseCmd {
5355
@Parameter(name = ApiConstants.MANAGED_STATE, type = CommandType.STRING, description = "whether this cluster is managed by cloudstack")
5456
private String managedState;
5557

58+
@Parameter(name = ApiConstants.ARCH, type = CommandType.STRING,
59+
description = "the CPU arch of the cluster. Valid options are: x86_64, aarch64",
60+
since = "4.20")
61+
private String arch;
62+
5663
public String getClusterName() {
5764
return clusterName;
5865
}
@@ -108,6 +115,13 @@ public ApiCommandResourceType getApiResourceType() {
108115
return ApiCommandResourceType.Cluster;
109116
}
110117

118+
public CPU.CPUArch getArch() {
119+
if (StringUtils.isBlank(arch)) {
120+
return null;
121+
}
122+
return CPU.CPUArch.fromType(arch);
123+
}
124+
111125
@Override
112126
public void execute() {
113127
Cluster cluster = _resourceService.getCluster(getId());

api/src/main/java/org/apache/cloudstack/api/command/user/iso/ListIsosCmd.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
// under the License.
1717
package org.apache.cloudstack.api.command.user.iso;
1818

19+
import com.cloud.cpu.CPU;
1920
import com.cloud.server.ResourceIcon;
2021
import com.cloud.server.ResourceTag;
2122
import org.apache.cloudstack.api.response.ResourceIconResponse;
@@ -34,6 +35,7 @@
3435

3536
import com.cloud.template.VirtualMachineTemplate.TemplateFilter;
3637
import com.cloud.user.Account;
38+
import org.apache.commons.lang3.StringUtils;
3739

3840
import java.util.List;
3941

@@ -88,6 +90,11 @@ public class ListIsosCmd extends BaseListTaggedResourcesCmd implements UserCmd {
8890
@Parameter(name = ApiConstants.SHOW_RESOURCE_ICON, type = CommandType.BOOLEAN, description = "flag to display the resource image for the isos")
8991
private Boolean showIcon;
9092

93+
@Parameter(name = ApiConstants.ARCH, type = CommandType.STRING,
94+
description = "the CPU arch of the ISO. Valid options are: x86_64, aarch64",
95+
since = "4.20")
96+
private String arch;
97+
9198
/////////////////////////////////////////////////////
9299
/////////////////// Accessors ///////////////////////
93100
/////////////////////////////////////////////////////
@@ -159,6 +166,13 @@ public boolean listInReadyState() {
159166
return onlyReady;
160167
}
161168

169+
public CPU.CPUArch getArch() {
170+
if (StringUtils.isBlank(arch)) {
171+
return null;
172+
}
173+
return CPU.CPUArch.fromType(arch);
174+
}
175+
162176
/////////////////////////////////////////////////////
163177
/////////////// API Implementation///////////////////
164178
/////////////////////////////////////////////////////

0 commit comments

Comments
 (0)