mirror of https://github.com/apache/cloudstack.git
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>
This commit is contained in:
parent
52b06962bc
commit
8c8d115a1e
|
|
@ -504,6 +504,13 @@ public class Agent implements HandlerFactory, IAgentControl, AgentStatusUpdater
|
|||
startup.setGuid(getResourceGuid());
|
||||
startup.setResourceName(getResourceName());
|
||||
startup.setVersion(getVersion());
|
||||
startup.setArch(getAgentArch());
|
||||
}
|
||||
|
||||
protected String getAgentArch() {
|
||||
final Script command = new Script("/usr/bin/arch", 500, logger);
|
||||
final OutputInterpreter.OneLineParser parser = new OutputInterpreter.OneLineParser();
|
||||
return command.execute(parser);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -858,11 +865,21 @@ public class Agent implements HandlerFactory, IAgentControl, AgentStatusUpdater
|
|||
setId(ready.getHostId());
|
||||
}
|
||||
|
||||
verifyAgentArch(ready.getArch());
|
||||
processManagementServerList(ready.getMsHostList(), ready.getLbAlgorithm(), ready.getLbCheckInterval());
|
||||
|
||||
logger.info("Ready command is processed for agent id = {}", getId());
|
||||
}
|
||||
|
||||
private void verifyAgentArch(String arch) {
|
||||
if (StringUtils.isNotBlank(arch)) {
|
||||
String agentArch = getAgentArch();
|
||||
if (!arch.equals(agentArch)) {
|
||||
logger.error("Unexpected arch {}, expected {}", agentArch, arch);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void processOtherTask(final Task task) {
|
||||
final Object obj = task.get();
|
||||
if (obj instanceof Response) {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,67 @@
|
|||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
package com.cloud.cpu;
|
||||
|
||||
import com.cloud.utils.exception.CloudRuntimeException;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class CPU {
|
||||
|
||||
public static final String archX86Identifier = "i686";
|
||||
public static final String archX86_64Identifier = "x86_64";
|
||||
public static final String archARM64Identifier = "aarch64";
|
||||
|
||||
public static class CPUArch {
|
||||
private static final Map<String, CPUArch> cpuArchMap = new LinkedHashMap<>();
|
||||
|
||||
public static final CPUArch archX86 = new CPUArch(archX86Identifier, 32);
|
||||
public static final CPUArch amd64 = new CPUArch(archX86_64Identifier, 64);
|
||||
public static final CPUArch arm64 = new CPUArch(archARM64Identifier, 64);
|
||||
|
||||
private String type;
|
||||
private int bits;
|
||||
|
||||
public CPUArch(String type, int bits) {
|
||||
this.type = type;
|
||||
this.bits = bits;
|
||||
cpuArchMap.put(type, this);
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return this.type;
|
||||
}
|
||||
|
||||
public int getBits() {
|
||||
return this.bits;
|
||||
}
|
||||
|
||||
public static CPUArch fromType(String type) {
|
||||
if (StringUtils.isBlank(type)) {
|
||||
return amd64;
|
||||
}
|
||||
switch (type) {
|
||||
case archX86Identifier: return archX86;
|
||||
case archX86_64Identifier: return amd64;
|
||||
case archARM64Identifier: return arm64;
|
||||
default: throw new CloudRuntimeException(String.format("Unsupported arch type: %s", type));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -16,6 +16,7 @@
|
|||
// under the License.
|
||||
package com.cloud.host;
|
||||
|
||||
import com.cloud.cpu.CPU;
|
||||
import com.cloud.hypervisor.Hypervisor.HypervisorType;
|
||||
import com.cloud.resource.ResourceState;
|
||||
import com.cloud.utils.fsm.StateObject;
|
||||
|
|
@ -208,4 +209,6 @@ public interface Host extends StateObject<Status>, Identity, Partition, HAResour
|
|||
boolean isDisabled();
|
||||
|
||||
ResourceState getResourceState();
|
||||
|
||||
CPU.CPUArch getArch();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
// under the License.
|
||||
package com.cloud.org;
|
||||
|
||||
import com.cloud.cpu.CPU;
|
||||
import com.cloud.hypervisor.Hypervisor.HypervisorType;
|
||||
import com.cloud.org.Managed.ManagedState;
|
||||
import org.apache.cloudstack.kernel.Partition;
|
||||
|
|
@ -38,4 +39,6 @@ public interface Cluster extends Grouping, Partition {
|
|||
AllocationState getAllocationState();
|
||||
|
||||
ManagedState getManagedState();
|
||||
|
||||
CPU.CPUArch getArch();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ package com.cloud.template;
|
|||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
|
||||
import com.cloud.cpu.CPU;
|
||||
import com.cloud.user.UserData;
|
||||
import org.apache.cloudstack.acl.ControlledEntity;
|
||||
import org.apache.cloudstack.api.Identity;
|
||||
|
|
@ -148,4 +149,6 @@ public interface VirtualMachineTemplate extends ControlledEntity, Identity, Inte
|
|||
|
||||
UserData.UserDataOverridePolicy getUserDataOverridePolicy();
|
||||
|
||||
CPU.CPUArch getArch();
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ public class ApiConstants {
|
|||
public static final String ANNOTATION = "annotation";
|
||||
public static final String API_KEY = "apikey";
|
||||
public static final String ARCHIVED = "archived";
|
||||
public static final String ARCH = "arch";
|
||||
public static final String AS_NUMBER = "asnumber";
|
||||
public static final String AS_NUMBER_ID = "asnumberid";
|
||||
public static final String ASN_RANGE = "asnrange";
|
||||
|
|
@ -326,6 +327,8 @@ public class ApiConstants {
|
|||
public static final String MIGRATIONS = "migrations";
|
||||
public static final String MEMORY = "memory";
|
||||
public static final String MODE = "mode";
|
||||
public static final String MULTI_ARCH = "ismultiarch";
|
||||
public static final String NSX_MODE = "nsxmode";
|
||||
public static final String NETWORK_MODE = "networkmode";
|
||||
public static final String NSX_ENABLED = "isnsxenabled";
|
||||
public static final String NAME = "name";
|
||||
|
|
|
|||
|
|
@ -16,8 +16,10 @@
|
|||
// under the License.
|
||||
package org.apache.cloudstack.api;
|
||||
|
||||
import com.cloud.cpu.CPU;
|
||||
import org.apache.cloudstack.api.response.GuestOSResponse;
|
||||
import org.apache.cloudstack.api.response.TemplateResponse;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
|
|
@ -77,6 +79,11 @@ public abstract class BaseUpdateTemplateOrIsoCmd extends BaseCmd {
|
|||
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)")
|
||||
private Boolean cleanupDetails;
|
||||
|
||||
@Parameter(name = ApiConstants.ARCH, type = CommandType.STRING,
|
||||
description = "the CPU arch of the template/ISO. Valid options are: x86_64, aarch64",
|
||||
since = "4.20")
|
||||
private String arch;
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
/////////////////// Accessors ///////////////////////
|
||||
/////////////////////////////////////////////////////
|
||||
|
|
@ -141,4 +148,11 @@ public abstract class BaseUpdateTemplateOrIsoCmd extends BaseCmd {
|
|||
public boolean isCleanupDetails(){
|
||||
return cleanupDetails == null ? false : cleanupDetails.booleanValue();
|
||||
}
|
||||
|
||||
public CPU.CPUArch getCPUArch() {
|
||||
if (StringUtils.isBlank(arch)) {
|
||||
return null;
|
||||
}
|
||||
return CPU.CPUArch.fromType(arch);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ package org.apache.cloudstack.api.command.admin.cluster;
|
|||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.cloud.cpu.CPU;
|
||||
import org.apache.cloudstack.api.ApiCommandResourceType;
|
||||
|
||||
import org.apache.cloudstack.api.APICommand;
|
||||
|
|
@ -67,6 +68,11 @@ public class AddClusterCmd extends BaseCmd {
|
|||
description = "hypervisor type of the cluster: XenServer,KVM,VMware,Hyperv,BareMetal,Simulator,Ovm3")
|
||||
private String hypervisor;
|
||||
|
||||
@Parameter(name = ApiConstants.ARCH, type = CommandType.STRING,
|
||||
description = "the CPU arch of the cluster. Valid options are: x86_64, aarch64",
|
||||
since = "4.20")
|
||||
private String arch;
|
||||
|
||||
@Parameter(name = ApiConstants.CLUSTER_TYPE, type = CommandType.STRING, required = true, description = "type of the cluster: CloudManaged, ExternalManaged")
|
||||
private String clusterType;
|
||||
|
||||
|
|
@ -204,6 +210,10 @@ public class AddClusterCmd extends BaseCmd {
|
|||
return ApiCommandResourceType.Cluster;
|
||||
}
|
||||
|
||||
public CPU.CPUArch getArch() {
|
||||
return CPU.CPUArch.fromType(arch);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute() {
|
||||
try {
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
// under the License.
|
||||
package org.apache.cloudstack.api.command.admin.cluster;
|
||||
|
||||
import com.cloud.cpu.CPU;
|
||||
import org.apache.cloudstack.api.ApiCommandResourceType;
|
||||
|
||||
import org.apache.cloudstack.api.APICommand;
|
||||
|
|
@ -29,6 +30,7 @@ import org.apache.cloudstack.api.response.ClusterResponse;
|
|||
import com.cloud.exception.InvalidParameterValueException;
|
||||
import com.cloud.org.Cluster;
|
||||
import com.cloud.user.Account;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
@APICommand(name = "updateCluster", description = "Updates an existing cluster", responseObject = ClusterResponse.class,
|
||||
requestHasSensitiveInfo = false, responseHasSensitiveInfo = false)
|
||||
|
|
@ -53,6 +55,11 @@ public class UpdateClusterCmd extends BaseCmd {
|
|||
@Parameter(name = ApiConstants.MANAGED_STATE, type = CommandType.STRING, description = "whether this cluster is managed by cloudstack")
|
||||
private String managedState;
|
||||
|
||||
@Parameter(name = ApiConstants.ARCH, type = CommandType.STRING,
|
||||
description = "the CPU arch of the cluster. Valid options are: x86_64, aarch64",
|
||||
since = "4.20")
|
||||
private String arch;
|
||||
|
||||
public String getClusterName() {
|
||||
return clusterName;
|
||||
}
|
||||
|
|
@ -108,6 +115,13 @@ public class UpdateClusterCmd extends BaseCmd {
|
|||
return ApiCommandResourceType.Cluster;
|
||||
}
|
||||
|
||||
public CPU.CPUArch getArch() {
|
||||
if (StringUtils.isBlank(arch)) {
|
||||
return null;
|
||||
}
|
||||
return CPU.CPUArch.fromType(arch);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute() {
|
||||
Cluster cluster = _resourceService.getCluster(getId());
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
// under the License.
|
||||
package org.apache.cloudstack.api.command.user.iso;
|
||||
|
||||
import com.cloud.cpu.CPU;
|
||||
import com.cloud.server.ResourceIcon;
|
||||
import com.cloud.server.ResourceTag;
|
||||
import org.apache.cloudstack.api.response.ResourceIconResponse;
|
||||
|
|
@ -34,6 +35,7 @@ import org.apache.cloudstack.context.CallContext;
|
|||
|
||||
import com.cloud.template.VirtualMachineTemplate.TemplateFilter;
|
||||
import com.cloud.user.Account;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
|
@ -88,6 +90,11 @@ public class ListIsosCmd extends BaseListTaggedResourcesCmd implements UserCmd {
|
|||
@Parameter(name = ApiConstants.SHOW_RESOURCE_ICON, type = CommandType.BOOLEAN, description = "flag to display the resource image for the isos")
|
||||
private Boolean showIcon;
|
||||
|
||||
@Parameter(name = ApiConstants.ARCH, type = CommandType.STRING,
|
||||
description = "the CPU arch of the ISO. Valid options are: x86_64, aarch64",
|
||||
since = "4.20")
|
||||
private String arch;
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
/////////////////// Accessors ///////////////////////
|
||||
/////////////////////////////////////////////////////
|
||||
|
|
@ -159,6 +166,13 @@ public class ListIsosCmd extends BaseListTaggedResourcesCmd implements UserCmd {
|
|||
return onlyReady;
|
||||
}
|
||||
|
||||
public CPU.CPUArch getArch() {
|
||||
if (StringUtils.isBlank(arch)) {
|
||||
return null;
|
||||
}
|
||||
return CPU.CPUArch.fromType(arch);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
/////////////// API Implementation///////////////////
|
||||
/////////////////////////////////////////////////////
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ package org.apache.cloudstack.api.command.user.iso;
|
|||
|
||||
import java.util.List;
|
||||
|
||||
import com.cloud.cpu.CPU;
|
||||
import org.apache.cloudstack.api.APICommand;
|
||||
import org.apache.cloudstack.api.ApiCommandResourceType;
|
||||
import org.apache.cloudstack.api.ApiConstants;
|
||||
|
|
@ -118,6 +119,11 @@ public class RegisterIsoCmd extends BaseCmd implements UserCmd {
|
|||
description = "true if password reset feature is supported; default is false")
|
||||
private Boolean passwordEnabled;
|
||||
|
||||
@Parameter(name = ApiConstants.ARCH, type = CommandType.STRING,
|
||||
description = "the CPU arch of the ISO. Valid options are: x86_64, aarch64",
|
||||
since = "4.20")
|
||||
private String arch;
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
/////////////////// Accessors ///////////////////////
|
||||
/////////////////////////////////////////////////////
|
||||
|
|
@ -229,6 +235,14 @@ public class RegisterIsoCmd extends BaseCmd implements UserCmd {
|
|||
return passwordEnabled == null ? false : passwordEnabled;
|
||||
}
|
||||
|
||||
public void setArch(String arch) {
|
||||
this.arch = arch;
|
||||
}
|
||||
|
||||
public CPU.CPUArch getArch() {
|
||||
return CPU.CPUArch.fromType(arch);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
/////////////// API Implementation///////////////////
|
||||
/////////////////////////////////////////////////////
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ import java.net.MalformedURLException;
|
|||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
|
||||
import com.cloud.cpu.CPU;
|
||||
import com.cloud.hypervisor.Hypervisor;
|
||||
import org.apache.cloudstack.acl.RoleType;
|
||||
import org.apache.cloudstack.api.APICommand;
|
||||
|
|
@ -55,6 +56,11 @@ public class GetUploadParamsForTemplateCmd extends AbstractGetUploadParamsCmd {
|
|||
description = "the ID of the OS Type that best represents the OS of this template. Not required for VMware as the guest OS is obtained from the OVF file.")
|
||||
private Long osTypeId;
|
||||
|
||||
@Parameter(name = ApiConstants.ARCH, type = CommandType.STRING,
|
||||
description = "the CPU arch of the template. Valid options are: x86_64, aarch64",
|
||||
since = "4.20")
|
||||
private String arch;
|
||||
|
||||
@Parameter(name = ApiConstants.BITS, type = CommandType.INTEGER, description = "32 or 64 bits support. 64 by default")
|
||||
private Integer bits;
|
||||
|
||||
|
|
@ -162,6 +168,10 @@ public class GetUploadParamsForTemplateCmd extends AbstractGetUploadParamsCmd {
|
|||
Boolean.TRUE.equals(deployAsIs);
|
||||
}
|
||||
|
||||
public CPU.CPUArch getArch() {
|
||||
return CPU.CPUArch.fromType(arch);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute() throws ServerApiException {
|
||||
validateRequest();
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
// under the License.
|
||||
package org.apache.cloudstack.api.command.user.template;
|
||||
|
||||
import com.cloud.cpu.CPU;
|
||||
import com.cloud.exception.InvalidParameterValueException;
|
||||
import com.cloud.server.ResourceIcon;
|
||||
import com.cloud.server.ResourceTag;
|
||||
|
|
@ -41,6 +42,7 @@ import org.apache.cloudstack.context.CallContext;
|
|||
import com.cloud.template.VirtualMachineTemplate;
|
||||
import com.cloud.template.VirtualMachineTemplate.TemplateFilter;
|
||||
import com.cloud.user.Account;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
@APICommand(name = "listTemplates", description = "List all public, private, and privileged templates.", responseObject = TemplateResponse.class, entityType = {VirtualMachineTemplate.class}, responseView = ResponseView.Restricted,
|
||||
requestHasSensitiveInfo = false, responseHasSensitiveInfo = false)
|
||||
|
|
@ -104,6 +106,11 @@ public class ListTemplatesCmd extends BaseListTaggedResourcesCmd implements User
|
|||
since = "4.19.0")
|
||||
private Boolean isVnf;
|
||||
|
||||
@Parameter(name = ApiConstants.ARCH, type = CommandType.STRING,
|
||||
description = "the CPU arch of the template. Valid options are: x86_64, aarch64",
|
||||
since = "4.20")
|
||||
private String arch;
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
/////////////////// Accessors ///////////////////////
|
||||
/////////////////////////////////////////////////////
|
||||
|
|
@ -191,6 +198,13 @@ public class ListTemplatesCmd extends BaseListTaggedResourcesCmd implements User
|
|||
return isVnf;
|
||||
}
|
||||
|
||||
public CPU.CPUArch getArch() {
|
||||
if (StringUtils.isBlank(arch)) {
|
||||
return null;
|
||||
}
|
||||
return CPU.CPUArch.fromType(arch);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCommandName() {
|
||||
return s_name;
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
// under the License.
|
||||
package org.apache.cloudstack.api.command.user.template;
|
||||
|
||||
import com.cloud.cpu.CPU;
|
||||
import com.cloud.hypervisor.Hypervisor;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.ArrayList;
|
||||
|
|
@ -172,6 +173,11 @@ public class RegisterTemplateCmd extends BaseCmd implements UserCmd {
|
|||
since = "4.19.0")
|
||||
private String templateType;
|
||||
|
||||
@Parameter(name = ApiConstants.ARCH, type = CommandType.STRING,
|
||||
description = "the CPU arch of the template. Valid options are: x86_64, aarch64",
|
||||
since = "4.20")
|
||||
private String arch;
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
/////////////////// Accessors ///////////////////////
|
||||
/////////////////////////////////////////////////////
|
||||
|
|
@ -293,6 +299,10 @@ public class RegisterTemplateCmd extends BaseCmd implements UserCmd {
|
|||
return templateType;
|
||||
}
|
||||
|
||||
public CPU.CPUArch getArch() {
|
||||
return CPU.CPUArch.fromType(arch);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
/////////////// API Implementation///////////////////
|
||||
/////////////////////////////////////////////////////
|
||||
|
|
|
|||
|
|
@ -91,6 +91,10 @@ public class ClusterResponse extends BaseResponseWithAnnotations {
|
|||
@Param(description = "Meta data associated with the zone (key/value pairs)")
|
||||
private Map<String, String> resourceDetails;
|
||||
|
||||
@SerializedName(ApiConstants.ARCH)
|
||||
@Param(description = "CPU Arch of the hosts in the cluster", since = "4.20")
|
||||
private String arch;
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
|
@ -247,4 +251,12 @@ public class ClusterResponse extends BaseResponseWithAnnotations {
|
|||
public void setCapacities(List<CapacityResponse> capacities) {
|
||||
this.capacities = capacities;
|
||||
}
|
||||
|
||||
public void setArch(String arch) {
|
||||
this.arch = arch;
|
||||
}
|
||||
|
||||
public String getArch() {
|
||||
return arch;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -290,6 +290,10 @@ public class HostResponse extends BaseResponseWithAnnotations {
|
|||
@Param(description = "true if the host supports instance conversion (using virt-v2v)", since = "4.19.1")
|
||||
private Boolean instanceConversionSupported;
|
||||
|
||||
@SerializedName(ApiConstants.ARCH)
|
||||
@Param(description = "CPU Arch of the host", since = "4.20")
|
||||
private String arch;
|
||||
|
||||
@Override
|
||||
public String getObjectId() {
|
||||
return this.getId();
|
||||
|
|
@ -787,6 +791,14 @@ public class HostResponse extends BaseResponseWithAnnotations {
|
|||
isTagARule = tagARule;
|
||||
}
|
||||
|
||||
public void setArch(String arch) {
|
||||
this.arch = arch;
|
||||
}
|
||||
|
||||
public String getArch() {
|
||||
return arch;
|
||||
}
|
||||
|
||||
public Long getCpuAllocatedValue() {
|
||||
return cpuAllocatedValue;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -183,6 +183,10 @@ public class TemplateResponse extends BaseResponseWithTagInformation implements
|
|||
@Param(description = "Lists the download progress of a template across all secondary storages")
|
||||
private List<Map<String, String>> downloadDetails;
|
||||
|
||||
@SerializedName(ApiConstants.ARCH)
|
||||
@Param(description = "CPU Arch of the template", since = "4.20")
|
||||
private String arch;
|
||||
|
||||
@SerializedName(ApiConstants.BITS)
|
||||
@Param(description = "the processor bit size", since = "4.10")
|
||||
private int bits;
|
||||
|
|
@ -520,4 +524,8 @@ public class TemplateResponse extends BaseResponseWithTagInformation implements
|
|||
public void setUserDataParams(String userDataParams) {
|
||||
this.userDataParams = userDataParams;
|
||||
}
|
||||
|
||||
public void setArch(String arch) {
|
||||
this.arch = arch;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -149,6 +149,10 @@ public class ZoneResponse extends BaseResponseWithAnnotations implements SetReso
|
|||
@Param(description = "true, if zone is NSX enabled", since = "4.20.0")
|
||||
private boolean nsxEnabled = false;
|
||||
|
||||
@SerializedName(ApiConstants.MULTI_ARCH)
|
||||
@Param(description = "true, if zone contains clusters and hosts from different CPU architectures", since = "4.20")
|
||||
private boolean multiArch;
|
||||
|
||||
@SerializedName(ApiConstants.ASN_RANGE)
|
||||
@Param(description = "AS Number Range")
|
||||
private String asnRange;
|
||||
|
|
@ -397,6 +401,10 @@ public class ZoneResponse extends BaseResponseWithAnnotations implements SetReso
|
|||
this.nsxEnabled = nsxEnabled;
|
||||
}
|
||||
|
||||
public void setMultiArch(boolean multiArch) {
|
||||
this.multiArch = multiArch;
|
||||
}
|
||||
|
||||
public void setAsnRange(String asnRange) {
|
||||
this.asnRange = asnRange;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ public class ReadyCommand extends Command {
|
|||
private String lbAlgorithm;
|
||||
private Long lbCheckInterval;
|
||||
private Boolean enableHumanReadableSizes;
|
||||
private String arch;
|
||||
|
||||
public ReadyCommand(Long dcId) {
|
||||
super();
|
||||
|
|
@ -94,4 +95,12 @@ public class ReadyCommand extends Command {
|
|||
public Boolean getEnableHumanReadableSizes() {
|
||||
return enableHumanReadableSizes;
|
||||
}
|
||||
|
||||
public String getArch() {
|
||||
return arch;
|
||||
}
|
||||
|
||||
public void setArch(String arch) {
|
||||
this.arch = arch;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@ public class StartupCommand extends Command {
|
|||
String resourceName;
|
||||
String gatewayIpAddress;
|
||||
String msHostList;
|
||||
String arch;
|
||||
|
||||
public StartupCommand(Host.Type type) {
|
||||
this.type = type;
|
||||
|
|
@ -290,6 +291,14 @@ public class StartupCommand extends Command {
|
|||
this.msHostList = msHostList;
|
||||
}
|
||||
|
||||
public String getArch() {
|
||||
return arch;
|
||||
}
|
||||
|
||||
public void setArch(String arch) {
|
||||
this.arch = arch;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean executeInSequence() {
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ public class StartupRoutingCommand extends StartupCommand {
|
|||
Integer cpuSockets;
|
||||
int cpus;
|
||||
long speed;
|
||||
String cpuArch;
|
||||
long memory;
|
||||
long dom0MinMemory;
|
||||
boolean poolSync;
|
||||
|
|
@ -201,4 +202,12 @@ public class StartupRoutingCommand extends StartupCommand {
|
|||
public void setHostHealthCheckResult(Boolean hostHealthCheckResult) {
|
||||
this.hostHealthCheckResult = hostHealthCheckResult;
|
||||
}
|
||||
|
||||
public String getCpuArch() {
|
||||
return cpuArch;
|
||||
}
|
||||
|
||||
public void setCpuArch(String cpuArch) {
|
||||
this.cpuArch = cpuArch;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ import java.text.ParseException;
|
|||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
|
||||
import com.cloud.cpu.CPU;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.cloud.agent.api.CheckOnHostCommand;
|
||||
|
|
@ -272,7 +273,12 @@ public class CheckOnHostCommandTest {
|
|||
@Override
|
||||
public ResourceState getResourceState() {
|
||||
return ResourceState.Enabled;
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public CPU.CPUArch getArch() {
|
||||
return CPU.CPUArch.amd64;
|
||||
}
|
||||
};
|
||||
|
||||
CheckOnHostCommand cohc = new CheckOnHostCommand(host);
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@ import javax.inject.Inject;
|
|||
import javax.naming.ConfigurationException;
|
||||
|
||||
import com.cloud.configuration.Config;
|
||||
import com.cloud.org.Cluster;
|
||||
import com.cloud.utils.NumbersUtil;
|
||||
import com.cloud.utils.db.GlobalLock;
|
||||
import org.apache.cloudstack.agent.lb.IndirectAgentLB;
|
||||
|
|
@ -1097,6 +1098,7 @@ public class AgentManagerImpl extends ManagerBase implements AgentManager, Handl
|
|||
agentMSHostList.addAll(Arrays.asList(msHosts[0].split(",")));
|
||||
}
|
||||
}
|
||||
ready.setArch(host.getArch().getType());
|
||||
AgentAttache attache = null;
|
||||
GlobalLock joinLock = getHostJoinLock(host.getId());
|
||||
if (joinLock.lock(60)) {
|
||||
|
|
@ -1128,6 +1130,7 @@ public class AgentManagerImpl extends ManagerBase implements AgentManager, Handl
|
|||
try {
|
||||
final HostVO host = _resourceMgr.createHostVOForConnectedAgent(startup);
|
||||
if (host != null) {
|
||||
checkHostArchOnCluster(host);
|
||||
ready = new ReadyCommand(host.getDataCenterId(), host.getId(), NumbersUtil.enableHumanReadableSizes);
|
||||
attache = sendReadyAndGetAttache(host, ready, link, startup);
|
||||
}
|
||||
|
|
@ -1154,6 +1157,16 @@ public class AgentManagerImpl extends ManagerBase implements AgentManager, Handl
|
|||
return attache;
|
||||
}
|
||||
|
||||
private void checkHostArchOnCluster(HostVO host) {
|
||||
Cluster cluster = _resourceMgr.getCluster(host.getClusterId());
|
||||
if (cluster != null && !cluster.getArch().equals(host.getArch())) {
|
||||
String msg = String.format("The host %s has arch %s and cannot be added to the %s cluster %s",
|
||||
host.getName(), host.getArch().getType(), cluster.getArch().getType(), cluster.getName());
|
||||
logger.error(msg);
|
||||
throw new CloudRuntimeException(msg);
|
||||
}
|
||||
}
|
||||
|
||||
protected class SimulateStartTask extends ManagedContextRunnable {
|
||||
ServerResource resource;
|
||||
Map<String, String> details;
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
// under the License.
|
||||
package org.apache.cloudstack.engine.datacenter.entity.api.db;
|
||||
|
||||
import com.cloud.cpu.CPU;
|
||||
import com.cloud.hypervisor.Hypervisor.HypervisorType;
|
||||
import com.cloud.org.Cluster;
|
||||
import com.cloud.org.Grouping;
|
||||
|
|
@ -26,6 +27,7 @@ import com.cloud.utils.db.StateMachine;
|
|||
import org.apache.cloudstack.api.Identity;
|
||||
import org.apache.cloudstack.engine.datacenter.entity.api.DataCenterResourceEntity.State;
|
||||
import org.apache.cloudstack.engine.datacenter.entity.api.DataCenterResourceEntity.State.Event;
|
||||
import org.apache.cloudstack.util.CPUArchConverter;
|
||||
import org.apache.cloudstack.util.HypervisorTypeConverter;
|
||||
|
||||
import javax.persistence.Column;
|
||||
|
|
@ -75,6 +77,10 @@ public class EngineClusterVO implements EngineCluster, Identity {
|
|||
@Enumerated(value = EnumType.STRING)
|
||||
AllocationState allocationState;
|
||||
|
||||
@Column(name = "arch")
|
||||
@Convert(converter = CPUArchConverter.class)
|
||||
private CPU.CPUArch arch;
|
||||
|
||||
@Column(name = "managed_state")
|
||||
@Enumerated(value = EnumType.STRING)
|
||||
ManagedState managedState;
|
||||
|
|
@ -245,6 +251,15 @@ public class EngineClusterVO implements EngineCluster, Identity {
|
|||
return state;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CPU.CPUArch getArch() {
|
||||
return arch;
|
||||
}
|
||||
|
||||
public void setArch(CPU.CPUArch arch) {
|
||||
this.arch = arch;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PartitionType partitionType() {
|
||||
return PartitionType.Cluster;
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ import javax.persistence.Temporal;
|
|||
import javax.persistence.TemporalType;
|
||||
import javax.persistence.Transient;
|
||||
|
||||
import com.cloud.cpu.CPU;
|
||||
import org.apache.cloudstack.api.Identity;
|
||||
import org.apache.cloudstack.engine.datacenter.entity.api.DataCenterResourceEntity.State;
|
||||
import org.apache.cloudstack.engine.datacenter.entity.api.DataCenterResourceEntity.State.Event;
|
||||
|
|
@ -50,6 +51,7 @@ import com.cloud.util.StoragePoolTypeConverter;
|
|||
import com.cloud.utils.NumbersUtil;
|
||||
import com.cloud.utils.db.GenericDao;
|
||||
import com.cloud.utils.db.StateMachine;
|
||||
import org.apache.cloudstack.util.CPUArchConverter;
|
||||
import org.apache.cloudstack.util.HypervisorTypeConverter;
|
||||
|
||||
@Entity
|
||||
|
|
@ -122,6 +124,10 @@ public class EngineHostVO implements EngineHost, Identity {
|
|||
@Convert(converter = HypervisorTypeConverter.class)
|
||||
private HypervisorType hypervisorType;
|
||||
|
||||
@Column(name = "arch")
|
||||
@Convert(converter = CPUArchConverter.class)
|
||||
private CPU.CPUArch arch;
|
||||
|
||||
@Column(name = "proxy_port")
|
||||
private Integer proxyPort;
|
||||
|
||||
|
|
@ -725,6 +731,15 @@ public class EngineHostVO implements EngineHost, Identity {
|
|||
return resourceState;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CPU.CPUArch getArch() {
|
||||
return arch;
|
||||
}
|
||||
|
||||
public void setArch(CPU.CPUArch arch) {
|
||||
this.arch = arch;
|
||||
}
|
||||
|
||||
public void setResourceState(ResourceState state) {
|
||||
resourceState = state;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,12 +16,14 @@
|
|||
// under the License.
|
||||
package com.cloud.dc;
|
||||
|
||||
import com.cloud.cpu.CPU;
|
||||
import com.cloud.hypervisor.Hypervisor.HypervisorType;
|
||||
import com.cloud.org.Cluster;
|
||||
import com.cloud.org.Grouping;
|
||||
import com.cloud.org.Managed.ManagedState;
|
||||
import com.cloud.utils.NumbersUtil;
|
||||
import com.cloud.utils.db.GenericDao;
|
||||
import org.apache.cloudstack.util.CPUArchConverter;
|
||||
import org.apache.cloudstack.util.HypervisorTypeConverter;
|
||||
|
||||
import javax.persistence.Column;
|
||||
|
|
@ -69,6 +71,10 @@ public class ClusterVO implements Cluster {
|
|||
@Enumerated(value = EnumType.STRING)
|
||||
AllocationState allocationState;
|
||||
|
||||
@Column(name = "arch")
|
||||
@Convert(converter = CPUArchConverter.class)
|
||||
private String arch;
|
||||
|
||||
@Column(name = "managed_state")
|
||||
@Enumerated(value = EnumType.STRING)
|
||||
ManagedState managedState;
|
||||
|
|
@ -200,6 +206,15 @@ public class ClusterVO implements Cluster {
|
|||
return PartitionType.Cluster;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CPU.CPUArch getArch() {
|
||||
return CPU.CPUArch.fromType(arch);
|
||||
}
|
||||
|
||||
public void setArch(String arch) {
|
||||
this.arch = arch;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("Cluster {id: \"%s\", name: \"%s\", uuid: \"%s\"}", id, name, uuid);
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
// under the License.
|
||||
package com.cloud.dc.dao;
|
||||
|
||||
import com.cloud.cpu.CPU;
|
||||
import com.cloud.dc.ClusterVO;
|
||||
import com.cloud.hypervisor.Hypervisor.HypervisorType;
|
||||
import com.cloud.utils.db.GenericDao;
|
||||
|
|
@ -50,4 +51,8 @@ public interface ClusterDao extends GenericDao<ClusterVO, Long> {
|
|||
List<Long> listAllClusters(Long zoneId);
|
||||
|
||||
boolean getSupportsResigning(long clusterId);
|
||||
|
||||
List<CPU.CPUArch> getClustersArchsByZone(long zoneId);
|
||||
|
||||
List<ClusterVO> listClustersByArchAndZoneId(long zoneId, CPU.CPUArch arch);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
// under the License.
|
||||
package com.cloud.dc.dao;
|
||||
|
||||
import com.cloud.cpu.CPU;
|
||||
import com.cloud.dc.ClusterDetailsDao;
|
||||
import com.cloud.dc.ClusterDetailsVO;
|
||||
import com.cloud.dc.ClusterVO;
|
||||
|
|
@ -43,6 +44,7 @@ import java.util.HashSet;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Component
|
||||
public class ClusterDaoImpl extends GenericDaoBase<ClusterVO, Long> implements ClusterDao {
|
||||
|
|
@ -54,6 +56,8 @@ public class ClusterDaoImpl extends GenericDaoBase<ClusterVO, Long> implements C
|
|||
protected final SearchBuilder<ClusterVO> ZoneHyTypeSearch;
|
||||
protected final SearchBuilder<ClusterVO> ZoneClusterSearch;
|
||||
protected final SearchBuilder<ClusterVO> ClusterSearch;
|
||||
protected final SearchBuilder<ClusterVO> ClusterDistinctArchSearch;
|
||||
protected final SearchBuilder<ClusterVO> ClusterArchSearch;
|
||||
|
||||
protected GenericSearchBuilder<ClusterVO, Long> ClusterIdSearch;
|
||||
|
||||
|
|
@ -104,6 +108,16 @@ public class ClusterDaoImpl extends GenericDaoBase<ClusterVO, Long> implements C
|
|||
ClusterSearch = createSearchBuilder();
|
||||
ClusterSearch.select(null, Func.DISTINCT, ClusterSearch.entity().getHypervisorType());
|
||||
ClusterIdSearch.done();
|
||||
|
||||
ClusterDistinctArchSearch = createSearchBuilder();
|
||||
ClusterDistinctArchSearch.and("dataCenterId", ClusterDistinctArchSearch.entity().getDataCenterId(), SearchCriteria.Op.EQ);
|
||||
ClusterDistinctArchSearch.select(null, Func.DISTINCT, ClusterDistinctArchSearch.entity().getArch());
|
||||
ClusterDistinctArchSearch.done();
|
||||
|
||||
ClusterArchSearch = createSearchBuilder();
|
||||
ClusterArchSearch.and("dataCenterId", ClusterArchSearch.entity().getDataCenterId(), SearchCriteria.Op.EQ);
|
||||
ClusterArchSearch.and("arch", ClusterArchSearch.entity().getArch(), SearchCriteria.Op.EQ);
|
||||
ClusterArchSearch.done();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -301,4 +315,20 @@ public class ClusterDaoImpl extends GenericDaoBase<ClusterVO, Long> implements C
|
|||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<CPU.CPUArch> getClustersArchsByZone(long zoneId) {
|
||||
SearchCriteria<ClusterVO> sc = ClusterDistinctArchSearch.create();
|
||||
sc.setParameters("dataCenterId", zoneId);
|
||||
List<ClusterVO> clusters = listBy(sc);
|
||||
return clusters.stream().map(ClusterVO::getArch).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ClusterVO> listClustersByArchAndZoneId(long zoneId, CPU.CPUArch arch) {
|
||||
SearchCriteria<ClusterVO> sc = ClusterArchSearch.create();
|
||||
sc.setParameters("dataCenterId", zoneId);
|
||||
sc.setParameters("arch", arch);
|
||||
return listBy(sc);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,6 +42,8 @@ import javax.persistence.Temporal;
|
|||
import javax.persistence.TemporalType;
|
||||
import javax.persistence.Transient;
|
||||
|
||||
import com.cloud.cpu.CPU;
|
||||
import org.apache.cloudstack.util.CPUArchConverter;
|
||||
import org.apache.cloudstack.util.HypervisorTypeConverter;
|
||||
import org.apache.cloudstack.utils.jsinterpreter.TagAsRuleHelper;
|
||||
import org.apache.cloudstack.utils.reflectiontostringbuilderutils.ReflectionToStringBuilderUtils;
|
||||
|
|
@ -153,6 +155,10 @@ public class HostVO implements Host {
|
|||
@Column(name = "hypervisor_version")
|
||||
private String hypervisorVersion;
|
||||
|
||||
@Column(name = "arch")
|
||||
@Convert(converter = CPUArchConverter.class)
|
||||
private CPU.CPUArch arch;
|
||||
|
||||
@Column(name = "update_count", updatable = true, nullable = false)
|
||||
protected long updated; // This field should be updated everytime the state is updated. There's no set method in the vo object because it is done with in the dao code.
|
||||
|
||||
|
|
@ -738,6 +744,15 @@ public class HostVO implements Host {
|
|||
return resourceState;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CPU.CPUArch getArch() {
|
||||
return arch;
|
||||
}
|
||||
|
||||
public void setArch(CPU.CPUArch arch) {
|
||||
this.arch = arch;
|
||||
}
|
||||
|
||||
public void setResourceState(ResourceState state) {
|
||||
resourceState = state;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,7 +32,9 @@ import javax.persistence.Temporal;
|
|||
import javax.persistence.TemporalType;
|
||||
import javax.persistence.Transient;
|
||||
|
||||
import com.cloud.cpu.CPU;
|
||||
import com.cloud.user.UserData;
|
||||
import org.apache.cloudstack.util.CPUArchConverter;
|
||||
import org.apache.cloudstack.util.HypervisorTypeConverter;
|
||||
import org.apache.cloudstack.utils.reflectiontostringbuilderutils.ReflectionToStringBuilderUtils;
|
||||
|
||||
|
|
@ -167,6 +169,10 @@ public class VMTemplateVO implements VirtualMachineTemplate {
|
|||
@Enumerated(value = EnumType.STRING)
|
||||
UserData.UserDataOverridePolicy userDataLinkPolicy;
|
||||
|
||||
@Column(name = "arch")
|
||||
@Convert(converter = CPUArchConverter.class)
|
||||
private CPU.CPUArch arch;
|
||||
|
||||
@Override
|
||||
public String getUniqueName() {
|
||||
return uniqueName;
|
||||
|
|
@ -209,7 +215,7 @@ public class VMTemplateVO implements VirtualMachineTemplate {
|
|||
|
||||
public VMTemplateVO(long id, String name, ImageFormat format, boolean isPublic, boolean featured, boolean isExtractable, TemplateType type, String url, boolean requiresHvm, int bits, long accountId, String cksum, String displayText, boolean enablePassword, long guestOSId, boolean bootable,
|
||||
HypervisorType hyperType, String templateTag, Map<String, String> details, boolean sshKeyEnabled, boolean isDynamicallyScalable, boolean directDownload,
|
||||
boolean deployAsIs) {
|
||||
boolean deployAsIs, CPU.CPUArch arch) {
|
||||
this(id,
|
||||
name,
|
||||
format,
|
||||
|
|
@ -235,6 +241,7 @@ public class VMTemplateVO implements VirtualMachineTemplate {
|
|||
state = State.Active;
|
||||
this.directDownload = directDownload;
|
||||
this.deployAsIs = deployAsIs;
|
||||
this.arch = arch;
|
||||
}
|
||||
|
||||
public static VMTemplateVO createPreHostIso(Long id, String uniqueName, String name, ImageFormat format, boolean isPublic, boolean featured, TemplateType type,
|
||||
|
|
@ -673,4 +680,13 @@ public class VMTemplateVO implements VirtualMachineTemplate {
|
|||
this.userDataLinkPolicy = userDataLinkPolicy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CPU.CPUArch getArch() {
|
||||
return arch;
|
||||
}
|
||||
|
||||
public void setArch(CPU.CPUArch arch) {
|
||||
this.arch = arch;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,36 @@
|
|||
// 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.util;
|
||||
|
||||
import com.cloud.cpu.CPU;
|
||||
|
||||
import javax.persistence.AttributeConverter;
|
||||
import javax.persistence.Converter;
|
||||
|
||||
@Converter
|
||||
public class CPUArchConverter implements AttributeConverter<CPU.CPUArch, String> {
|
||||
|
||||
@Override
|
||||
public String convertToDatabaseColumn(CPU.CPUArch cpuArch) {
|
||||
return cpuArch == null ? CPU.CPUArch.amd64.getType() : cpuArch.getType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CPU.CPUArch convertToEntityAttribute(String attribute) {
|
||||
return CPU.CPUArch.fromType(attribute);
|
||||
}
|
||||
}
|
||||
|
|
@ -581,6 +581,11 @@ CALL `cloud`.`IDEMPOTENT_MODIFY_COLUMN_CHAR_SET`('vpc_offerings', 'display_text'
|
|||
|
||||
CALL `cloud`.`IDEMPOTENT_ADD_COLUMN`('cloud.roles','state', 'varchar(10) NOT NULL default "enabled" COMMENT "role state"');
|
||||
|
||||
-- Multi-Arch Zones
|
||||
CALL `cloud`.`IDEMPOTENT_ADD_COLUMN`('cloud.cluster', 'arch', 'varchar(8) DEFAULT "x86_64" COMMENT "the CPU architecture of the hosts in the cluster"');
|
||||
CALL `cloud`.`IDEMPOTENT_ADD_COLUMN`('cloud.host', 'arch', 'varchar(8) DEFAULT "x86_64" COMMENT "the CPU architecture of the host"');
|
||||
CALL `cloud`.`IDEMPOTENT_ADD_COLUMN`('cloud.vm_template', 'arch', 'varchar(8) DEFAULT "x86_64" COMMENT "the CPU architecture of the template/ISO"');
|
||||
|
||||
-- NAS B&R Plugin Backup Repository
|
||||
DROP TABLE IF EXISTS `cloud`.`backup_repository`;
|
||||
CREATE TABLE `cloud`.`backup_repository` (
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ SELECT
|
|||
host.cpus,
|
||||
host.speed,
|
||||
host.ram,
|
||||
host.arch,
|
||||
cluster.id cluster_id,
|
||||
cluster.uuid cluster_uuid,
|
||||
cluster.name cluster_name,
|
||||
|
|
|
|||
|
|
@ -50,6 +50,7 @@ SELECT
|
|||
`vm_template`.`sort_key` AS `sort_key`,
|
||||
`vm_template`.`removed` AS `removed`,
|
||||
`vm_template`.`enable_sshkey` AS `enable_sshkey`,
|
||||
`vm_template`.`arch` AS `arch`,
|
||||
`parent_template`.`id` AS `parent_template_id`,
|
||||
`parent_template`.`uuid` AS `parent_template_uuid`,
|
||||
`source_template`.`id` AS `source_template_id`,
|
||||
|
|
|
|||
|
|
@ -814,7 +814,7 @@ public class TemplateServiceImpl implements TemplateService {
|
|||
String templateName = dataDiskTemplate.isIso() ? dataDiskTemplate.getPath().substring(dataDiskTemplate.getPath().lastIndexOf(File.separator) + 1) : template.getName() + suffix + diskCount;
|
||||
VMTemplateVO templateVO = new VMTemplateVO(templateId, templateName, format, false, false, false, ttype, template.getUrl(),
|
||||
template.requiresHvm(), template.getBits(), template.getAccountId(), null, templateName, false, guestOsId, false, template.getHypervisorType(), null,
|
||||
null, false, false, false, false);
|
||||
null, false, false, false, false, template.getArch());
|
||||
if (dataDiskTemplate.isIso()){
|
||||
templateVO.setUniqueName(templateName);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ import java.util.Map;
|
|||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import com.cloud.cpu.CPU;
|
||||
import com.cloud.storage.StorageManager;
|
||||
import com.cloud.user.UserData;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
|
@ -350,6 +351,11 @@ public class TemplateObject implements TemplateInfo {
|
|||
return imageVO.getUserDataOverridePolicy();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CPU.CPUArch getArch() {
|
||||
return imageVO.getArch();
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataTO getTO() {
|
||||
DataTO to = null;
|
||||
|
|
|
|||
|
|
@ -3655,7 +3655,6 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv
|
|||
if (dpdkSupport) {
|
||||
capabilities += ",dpdk";
|
||||
}
|
||||
|
||||
final StartupRoutingCommand cmd =
|
||||
new StartupRoutingCommand(info.getAllocatableCpus(), info.getCpuSpeed(), info.getTotalMemory(), info.getReservedMemory(), capabilities, hypervisorType,
|
||||
RouterPrivateIpStrategy.HostLocal);
|
||||
|
|
@ -3675,6 +3674,9 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv
|
|||
if (healthCheckResult != HealthCheckResult.IGNORE) {
|
||||
cmd.setHostHealthCheckResult(healthCheckResult == HealthCheckResult.SUCCESS);
|
||||
}
|
||||
if (StringUtils.isNotBlank(info.getCpuArch())) {
|
||||
cmd.setCpuArch(info.getCpuArch());
|
||||
}
|
||||
|
||||
if (cmd.getHostDetails().containsKey("Host.OS")) {
|
||||
hostDistro = cmd.getHostDetails().get("Host.OS");
|
||||
|
|
|
|||
|
|
@ -53,12 +53,14 @@ public class KVMHostInfo {
|
|||
private int allocatableCpus;
|
||||
private int cpusockets;
|
||||
private long cpuSpeed;
|
||||
private String cpuArch;
|
||||
private long totalMemory;
|
||||
private long reservedMemory;
|
||||
private long overCommitMemory;
|
||||
private List<String> capabilities = new ArrayList<>();
|
||||
|
||||
private static String cpuInfoFreqFileName = "/sys/devices/system/cpu/cpu0/cpufreq/base_frequency";
|
||||
private static String cpuArchCommand = "/usr/bin/arch";
|
||||
|
||||
public KVMHostInfo(long reservedMemory, long overCommitMemory, long manualSpeed, int reservedCpus) {
|
||||
this.cpuSpeed = manualSpeed;
|
||||
|
|
@ -105,6 +107,10 @@ public class KVMHostInfo {
|
|||
return this.capabilities;
|
||||
}
|
||||
|
||||
public String getCpuArch() {
|
||||
return cpuArch;
|
||||
}
|
||||
|
||||
protected static long getCpuSpeed(final String cpabilities, final NodeInfo nodeInfo) {
|
||||
long speed = 0L;
|
||||
speed = getCpuSpeedFromCommandLscpu();
|
||||
|
|
@ -201,6 +207,7 @@ public class KVMHostInfo {
|
|||
this.cpusockets = hosts.sockets * hosts.nodes;
|
||||
}
|
||||
this.totalCpus = hosts.cpus;
|
||||
this.cpuArch = getCPUArchFromCommand();
|
||||
|
||||
final LibvirtCapXMLParser parser = new LibvirtCapXMLParser();
|
||||
parser.parseCapabilitiesXML(capabilities);
|
||||
|
|
@ -227,4 +234,9 @@ public class KVMHostInfo {
|
|||
LOGGER.error("Caught libvirt exception while fetching host information", e);
|
||||
}
|
||||
}
|
||||
|
||||
private String getCPUArchFromCommand() {
|
||||
LOGGER.info("Fetching host CPU arch");
|
||||
return Script.runSimpleBashScript(cpuArchCommand);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ import java.util.UUID;
|
|||
import javax.inject.Inject;
|
||||
|
||||
import com.cloud.agent.api.to.NfsTO;
|
||||
import com.cloud.cpu.CPU;
|
||||
import com.cloud.hypervisor.vmware.mo.DatastoreMO;
|
||||
import com.cloud.hypervisor.vmware.mo.HostMO;
|
||||
import com.cloud.hypervisor.vmware.util.VmwareClient;
|
||||
|
|
@ -642,7 +643,7 @@ public class VMwareGuru extends HypervisorGuruBase implements HypervisorGuru, Co
|
|||
private VMTemplateVO createVMTemplateRecord(String vmInternalName, long guestOsId, long accountId) {
|
||||
Long nextTemplateId = vmTemplateDao.getNextInSequence(Long.class, "id");
|
||||
VMTemplateVO templateVO = new VMTemplateVO(nextTemplateId, "Imported-from-" + vmInternalName, Storage.ImageFormat.OVA, false, false, false, Storage.TemplateType.USER, null,
|
||||
false, 64, accountId, null, "Template imported from VM " + vmInternalName, false, guestOsId, false, HypervisorType.VMware, null, null, false, false, false, false);
|
||||
false, 64, accountId, null, "Template imported from VM " + vmInternalName, false, guestOsId, false, HypervisorType.VMware, null, null, false, false, false, false, CPU.CPUArch.amd64);
|
||||
return vmTemplateDao.persist(templateVO);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ import java.util.List;
|
|||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import com.cloud.cpu.CPU;
|
||||
import org.apache.cloudstack.api.ApiCommandResourceType;
|
||||
import org.apache.cloudstack.api.ApiConstants;
|
||||
import org.apache.cloudstack.api.command.admin.kubernetes.version.AddKubernetesSupportedVersionCmd;
|
||||
|
|
@ -159,7 +160,7 @@ public class KubernetesVersionManagerImpl extends ManagerBase implements Kuberne
|
|||
return versions;
|
||||
}
|
||||
|
||||
private VirtualMachineTemplate registerKubernetesVersionIso(final Long zoneId, final String versionName, final String isoUrl, final String isoChecksum, final boolean directDownload) throws IllegalAccessException, NoSuchFieldException,
|
||||
private VirtualMachineTemplate registerKubernetesVersionIso(final Long zoneId, final String versionName, final String isoUrl, final String isoChecksum, final boolean directDownload, CPU.CPUArch arch) throws IllegalAccessException, NoSuchFieldException,
|
||||
IllegalArgumentException, ResourceAllocationException {
|
||||
CallContext.register(CallContext.current(), ApiCommandResourceType.Iso);
|
||||
String isoName = String.format("%s-Kubernetes-Binaries-ISO", versionName);
|
||||
|
|
@ -177,6 +178,7 @@ public class KubernetesVersionManagerImpl extends ManagerBase implements Kuberne
|
|||
registerIsoCmd.setChecksum(isoChecksum);
|
||||
}
|
||||
registerIsoCmd.setDirectDownload(directDownload);
|
||||
registerIsoCmd.setArch(arch.getType());
|
||||
registerIsoCmd.setAccountName(accountManager.getSystemAccount().getAccountName());
|
||||
registerIsoCmd.setDomainId(accountManager.getSystemAccount().getDomainId());
|
||||
try {
|
||||
|
|
@ -316,6 +318,8 @@ public class KubernetesVersionManagerImpl extends ManagerBase implements Kuberne
|
|||
final Integer minimumCpu = cmd.getMinimumCpu();
|
||||
final Integer minimumRamSize = cmd.getMinimumRamSize();
|
||||
final boolean isDirectDownload = cmd.isDirectDownload();
|
||||
CPU.CPUArch arch = cmd.getArch();
|
||||
|
||||
if (minimumCpu == null || minimumCpu < KubernetesClusterService.MIN_KUBERNETES_CLUSTER_NODE_CPU) {
|
||||
throw new InvalidParameterValueException(String.format("Invalid value for %s parameter. Minimum %d vCPUs required.", ApiConstants.MIN_CPU_NUMBER, KubernetesClusterService.MIN_KUBERNETES_CLUSTER_NODE_CPU));
|
||||
}
|
||||
|
|
@ -346,7 +350,7 @@ public class KubernetesVersionManagerImpl extends ManagerBase implements Kuberne
|
|||
|
||||
VMTemplateVO template = null;
|
||||
try {
|
||||
VirtualMachineTemplate vmTemplate = registerKubernetesVersionIso(zoneId, name, isoUrl, isoChecksum, isDirectDownload);
|
||||
VirtualMachineTemplate vmTemplate = registerKubernetesVersionIso(zoneId, name, isoUrl, isoChecksum, isDirectDownload, arch);
|
||||
template = templateDao.findById(vmTemplate.getId());
|
||||
} catch (IllegalAccessException | NoSuchFieldException | IllegalArgumentException | ResourceAllocationException ex) {
|
||||
logger.error(String.format("Unable to register binaries ISO for supported kubernetes version, %s, with url: %s", name, isoUrl), ex);
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ package org.apache.cloudstack.api.command.admin.kubernetes.version;
|
|||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import com.cloud.cpu.CPU;
|
||||
import org.apache.cloudstack.acl.RoleType;
|
||||
import org.apache.cloudstack.api.APICommand;
|
||||
import org.apache.cloudstack.api.ApiCommandResourceType;
|
||||
|
|
@ -87,6 +88,11 @@ public class AddKubernetesSupportedVersionCmd extends BaseCmd implements AdminCm
|
|||
description = "If set to true the Kubernetes supported version ISO will bypass Secondary Storage and be downloaded to Primary Storage on deployment. Default is false")
|
||||
private Boolean directDownload;
|
||||
|
||||
@Parameter(name = ApiConstants.ARCH, type = CommandType.STRING,
|
||||
description = "the CPU arch of the Kubernetes ISO. Valid options are: x86_64, aarch64",
|
||||
since = "4.20")
|
||||
private String arch;
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
/////////////////// Accessors ///////////////////////
|
||||
/////////////////////////////////////////////////////
|
||||
|
|
@ -130,6 +136,10 @@ public class AddKubernetesSupportedVersionCmd extends BaseCmd implements AdminCm
|
|||
return (directDownload != null) ? directDownload : false;
|
||||
}
|
||||
|
||||
public CPU.CPUArch getArch() {
|
||||
return CPU.CPUArch.fromType(arch);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getEntityOwnerId() {
|
||||
return CallContext.current().getCallingAccountId();
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ import java.util.ArrayList;
|
|||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
import com.cloud.cpu.CPU;
|
||||
import org.apache.cloudstack.api.command.admin.kubernetes.version.AddKubernetesSupportedVersionCmd;
|
||||
import org.apache.cloudstack.api.command.admin.kubernetes.version.DeleteKubernetesSupportedVersionCmd;
|
||||
import org.apache.cloudstack.api.command.admin.kubernetes.version.UpdateKubernetesSupportedVersionCmd;
|
||||
|
|
@ -213,6 +214,7 @@ public class KubernetesVersionServiceTest {
|
|||
when(cmd.getChecksum()).thenReturn(null);
|
||||
when(cmd.getMinimumCpu()).thenReturn(KubernetesClusterService.MIN_KUBERNETES_CLUSTER_NODE_CPU);
|
||||
when(cmd.getMinimumRamSize()).thenReturn(KubernetesClusterService.MIN_KUBERNETES_CLUSTER_NODE_RAM_SIZE);
|
||||
when(cmd.getArch()).thenReturn(CPU.CPUArch.amd64);
|
||||
Account systemAccount = new AccountVO("system", 1L, "", Account.Type.ADMIN, "uuid");
|
||||
when(accountManager.getSystemAccount()).thenReturn(systemAccount);
|
||||
CallContext callContext = Mockito.mock(CallContext.class);
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ import java.util.stream.Collectors;
|
|||
import javax.annotation.PostConstruct;
|
||||
import javax.inject.Inject;
|
||||
|
||||
import com.cloud.cpu.CPU;
|
||||
import org.apache.cloudstack.acl.Role;
|
||||
import org.apache.cloudstack.acl.RoleService;
|
||||
import org.apache.cloudstack.affinity.AffinityGroup;
|
||||
|
|
@ -2286,4 +2287,8 @@ public class ApiDBUtils {
|
|||
public static SharedFSJoinVO newSharedFSView(SharedFS sharedFS) {
|
||||
return s_sharedFSJoinDao.newSharedFSView(sharedFS);
|
||||
}
|
||||
|
||||
public static List<CPU.CPUArch> listZoneClustersArchs(long zoneId) {
|
||||
return s_clusterDao.getClustersArchsByZone(zoneId);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1530,6 +1530,9 @@ public class ApiResponseHelper implements ResponseGenerator {
|
|||
clusterResponse.setCpuOvercommitRatio(cpuOvercommitRatio);
|
||||
clusterResponse.setMemoryOvercommitRatio(memoryOvercommitRatio);
|
||||
clusterResponse.setResourceDetails(_clusterDetailsDao.findDetails(cluster.getId()));
|
||||
if (cluster.getArch() != null) {
|
||||
clusterResponse.setArch(cluster.getArch().getType());
|
||||
}
|
||||
|
||||
if (showCapacities != null && showCapacities) {
|
||||
List<SummedCapacity> capacities = ApiDBUtils.getCapacityByClusterPodZone(null, null, cluster.getId());
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ import java.util.stream.Stream;
|
|||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import com.cloud.cpu.CPU;
|
||||
import org.apache.cloudstack.acl.ControlledEntity;
|
||||
import org.apache.cloudstack.acl.ControlledEntity.ACLType;
|
||||
import org.apache.cloudstack.acl.SecurityChecker;
|
||||
|
|
@ -4476,7 +4477,7 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
|
|||
null, cmd.getPageSizeVal(), cmd.getStartIndex(), cmd.getZoneId(), cmd.getStoragePoolId(),
|
||||
cmd.getImageStoreId(), hypervisorType, showDomr, cmd.listInReadyState(), permittedAccounts, caller,
|
||||
listProjectResourcesCriteria, tags, showRemovedTmpl, cmd.getIds(), parentTemplateId, cmd.getShowUnique(),
|
||||
templateType, isVnf);
|
||||
templateType, isVnf, cmd.getArch());
|
||||
}
|
||||
|
||||
private Pair<List<TemplateJoinVO>, Integer> searchForTemplatesInternal(Long templateId, String name, String keyword,
|
||||
|
|
@ -4485,7 +4486,7 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
|
|||
boolean showDomr, boolean onlyReady, List<Account> permittedAccounts, Account caller,
|
||||
ListProjectResourcesCriteria listProjectResourcesCriteria, Map<String, String> tags,
|
||||
boolean showRemovedTmpl, List<Long> ids, Long parentTemplateId, Boolean showUnique, String templateType,
|
||||
Boolean isVnf) {
|
||||
Boolean isVnf, CPU.CPUArch arch) {
|
||||
|
||||
// check if zone is configured, if not, just return empty list
|
||||
List<HypervisorType> hypers = null;
|
||||
|
|
@ -4523,6 +4524,10 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
|
|||
sc.addAnd("dataStoreId", SearchCriteria.Op.EQ, imageStoreId);
|
||||
}
|
||||
|
||||
if (arch != null) {
|
||||
sc.addAnd("arch", SearchCriteria.Op.EQ, arch);
|
||||
}
|
||||
|
||||
if (storagePoolId != null) {
|
||||
sc.setJoinParameters("storagePool", "pool_id", storagePoolId);
|
||||
}
|
||||
|
|
@ -4912,7 +4917,7 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
|
|||
return searchForTemplatesInternal(cmd.getId(), cmd.getIsoName(), cmd.getKeyword(), isoFilter, true, cmd.isBootable(),
|
||||
cmd.getPageSizeVal(), cmd.getStartIndex(), cmd.getZoneId(), cmd.getStoragePoolId(), cmd.getImageStoreId(),
|
||||
hypervisorType, true, cmd.listInReadyState(), permittedAccounts, caller, listProjectResourcesCriteria,
|
||||
tags, showRemovedISO, null, null, cmd.getShowUnique(), null, null);
|
||||
tags, showRemovedISO, null, null, cmd.getShowUnique(), null, null, cmd.getArch());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ import java.util.stream.Collectors;
|
|||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import com.cloud.cpu.CPU;
|
||||
import com.cloud.dc.ASNumberRangeVO;
|
||||
import com.cloud.dc.dao.ASNumberRangeDao;
|
||||
import com.cloud.network.dao.NsxProviderDao;
|
||||
|
|
@ -33,6 +34,7 @@ import org.apache.cloudstack.api.response.ResourceIconResponse;
|
|||
import org.apache.cloudstack.api.response.ResourceTagResponse;
|
||||
import org.apache.cloudstack.api.response.ZoneResponse;
|
||||
import org.apache.cloudstack.context.CallContext;
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
import org.apache.commons.lang3.ObjectUtils;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
|
|
@ -132,6 +134,9 @@ public class DataCenterJoinDaoImpl extends GenericDaoBase<DataCenterJoinVO, Long
|
|||
zoneResponse.setNsxEnabled(true);
|
||||
}
|
||||
|
||||
List<CPU.CPUArch> clusterArchs = ApiDBUtils.listZoneClustersArchs(dataCenter.getId());
|
||||
zoneResponse.setMultiArch(CollectionUtils.isNotEmpty(clusterArchs) && clusterArchs.size() > 1);
|
||||
|
||||
List<ASNumberRangeVO> asNumberRange = asNumberRangeDao.listByZoneId(dataCenter.getId());
|
||||
String asRange = asNumberRange.stream().map(range -> range.getStartASNumber() + "-" + range.getEndASNumber()).collect(Collectors.joining(", "));
|
||||
zoneResponse.setAsnRange(asRange);
|
||||
|
|
|
|||
|
|
@ -209,6 +209,9 @@ public class HostJoinDaoImpl extends GenericDaoBase<HostJoinVO, Long> implements
|
|||
hostResponse.setImplicitHostTags(host.getImplicitTag());
|
||||
|
||||
hostResponse.setHypervisorVersion(host.getHypervisorVersion());
|
||||
if (host.getArch() != null) {
|
||||
hostResponse.setArch(host.getArch().getType());
|
||||
}
|
||||
|
||||
float cpuWithOverprovisioning = host.getCpus() * host.getSpeed() * cpuOverprovisioningFactor;
|
||||
hostResponse.setCpuAllocatedValue(cpu);
|
||||
|
|
|
|||
|
|
@ -332,6 +332,9 @@ public class TemplateJoinDaoImpl extends GenericDaoBaseWithTagInformation<Templa
|
|||
templateResponse.setDirectDownload(template.isDirectDownload());
|
||||
templateResponse.setDeployAsIs(template.isDeployAsIs());
|
||||
templateResponse.setRequiresHvm(template.isRequiresHvm());
|
||||
if (template.getArch() != null) {
|
||||
templateResponse.setArch(template.getArch().getType());
|
||||
}
|
||||
|
||||
//set template children disks
|
||||
Set<ChildTemplateResponse> childTemplatesSet = new HashSet<ChildTemplateResponse>();
|
||||
|
|
@ -600,6 +603,9 @@ public class TemplateJoinDaoImpl extends GenericDaoBaseWithTagInformation<Templa
|
|||
_accountService.isRootAdmin(CallContext.current().getCallingAccount().getId())));
|
||||
|
||||
isoResponse.setDirectDownload(iso.isDirectDownload());
|
||||
if (iso.getArch() != null) {
|
||||
isoResponse.setArch(iso.getArch().getType());
|
||||
}
|
||||
|
||||
isoResponse.setObjectName("iso");
|
||||
return isoResponse;
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ import javax.persistence.Table;
|
|||
import javax.persistence.Temporal;
|
||||
import javax.persistence.TemporalType;
|
||||
|
||||
import com.cloud.cpu.CPU;
|
||||
import com.cloud.host.Host.Type;
|
||||
import com.cloud.host.Status;
|
||||
import com.cloud.hypervisor.Hypervisor.HypervisorType;
|
||||
|
|
@ -39,6 +40,7 @@ import org.apache.cloudstack.api.Identity;
|
|||
import org.apache.cloudstack.api.InternalIdentity;
|
||||
import org.apache.cloudstack.ha.HAConfig;
|
||||
import org.apache.cloudstack.outofbandmanagement.OutOfBandManagement;
|
||||
import org.apache.cloudstack.util.CPUArchConverter;
|
||||
import org.apache.cloudstack.util.HypervisorTypeConverter;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
|
|
@ -213,6 +215,10 @@ public class HostJoinVO extends BaseViewVO implements InternalIdentity, Identity
|
|||
@Column(name = "username")
|
||||
private String username;
|
||||
|
||||
@Column(name = "arch")
|
||||
@Convert(converter = CPUArchConverter.class)
|
||||
private CPU.CPUArch arch;
|
||||
|
||||
@Override
|
||||
public long getId() {
|
||||
return this.id;
|
||||
|
|
@ -432,4 +438,8 @@ public class HostJoinVO extends BaseViewVO implements InternalIdentity, Identity
|
|||
ResourceState.Maintenance, ResourceState.ErrorInMaintenance, ResourceState.PrepareForMaintenance)
|
||||
.contains(getResourceState());
|
||||
}
|
||||
|
||||
public CPU.CPUArch getArch() {
|
||||
return arch;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ import javax.persistence.Table;
|
|||
import javax.persistence.Temporal;
|
||||
import javax.persistence.TemporalType;
|
||||
|
||||
import com.cloud.cpu.CPU;
|
||||
import com.cloud.user.Account;
|
||||
import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine;
|
||||
|
||||
|
|
@ -37,6 +38,7 @@ import com.cloud.storage.VMTemplateStorageResourceAssoc.Status;
|
|||
import com.cloud.template.VirtualMachineTemplate;
|
||||
import com.cloud.template.VirtualMachineTemplate.State;
|
||||
import com.cloud.utils.db.GenericDao;
|
||||
import org.apache.cloudstack.util.CPUArchConverter;
|
||||
import org.apache.cloudstack.util.HypervisorTypeConverter;
|
||||
|
||||
@Entity
|
||||
|
|
@ -70,6 +72,10 @@ public class TemplateJoinVO extends BaseViewWithTagInformationVO implements Cont
|
|||
@Column(name = "hvm")
|
||||
private boolean requiresHvm;
|
||||
|
||||
@Column(name = "arch")
|
||||
@Convert(converter = CPUArchConverter.class)
|
||||
private CPU.CPUArch arch;
|
||||
|
||||
@Column(name = "bits")
|
||||
private int bits;
|
||||
|
||||
|
|
@ -543,4 +549,8 @@ public class TemplateJoinVO extends BaseViewWithTagInformationVO implements Cont
|
|||
public String getUserDataParams() {
|
||||
return userDataParams;
|
||||
}
|
||||
|
||||
public CPU.CPUArch getArch() {
|
||||
return arch;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ package com.cloud.deploy;
|
|||
import static com.cloud.utils.NumbersUtil.toHumanReadableSize;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
|
|
@ -35,6 +36,7 @@ import java.util.stream.Collectors;
|
|||
import javax.inject.Inject;
|
||||
import javax.naming.ConfigurationException;
|
||||
|
||||
import com.cloud.cpu.CPU;
|
||||
import com.cloud.vm.UserVmManager;
|
||||
import org.apache.cloudstack.affinity.AffinityGroupDomainMapVO;
|
||||
import com.cloud.storage.VMTemplateVO;
|
||||
|
|
@ -271,6 +273,8 @@ StateListener<State, VirtualMachine.Event, VirtualMachine>, Configurable {
|
|||
_affinityProcessors = affinityProcessors;
|
||||
}
|
||||
|
||||
private static final List<CPU.CPUArch> clusterArchTypes = Arrays.asList(CPU.CPUArch.amd64, CPU.CPUArch.arm64);
|
||||
|
||||
protected void avoidOtherClustersForDeploymentIfMigrationDisabled(VirtualMachine vm, Host lastHost, ExcludeList avoids) {
|
||||
if (lastHost == null || lastHost.getClusterId() == null ||
|
||||
ConfigurationManagerImpl.MIGRATE_VM_ACROSS_CLUSTERS.valueIn(vm.getDataCenterId())) {
|
||||
|
|
@ -329,6 +333,7 @@ StateListener<State, VirtualMachine.Event, VirtualMachine>, Configurable {
|
|||
logger.debug("ROOT volume [{}] {} to deploy VM [{}].", () -> getRootVolumeUuid(_volsDao.findByInstance(vm.getId())), () -> plan.getPoolId() != null ? "is ready" : "is not ready", vm::getUuid);
|
||||
|
||||
avoidDisabledResources(vmProfile, dc, avoids);
|
||||
avoidDifferentArchResources(vmProfile, dc, avoids);
|
||||
|
||||
String haVmTag = (String)vmProfile.getParameter(VirtualMachineProfile.Param.HaTag);
|
||||
String uefiFlag = (String)vmProfile.getParameter(VirtualMachineProfile.Param.UefiFlag);
|
||||
|
|
@ -455,6 +460,22 @@ StateListener<State, VirtualMachine.Event, VirtualMachine>, Configurable {
|
|||
return dest;
|
||||
}
|
||||
|
||||
private void avoidDifferentArchResources(VirtualMachineProfile vmProfile, DataCenter dc, ExcludeList avoids) {
|
||||
VirtualMachineTemplate template = vmProfile.getTemplate();
|
||||
for (CPU.CPUArch arch : clusterArchTypes) {
|
||||
if (arch.equals(template.getArch())) {
|
||||
continue;
|
||||
}
|
||||
List<ClusterVO> avoidClusters = _clusterDao.listClustersByArchAndZoneId(dc.getId(), arch);
|
||||
if (CollectionUtils.isNotEmpty(avoidClusters)) {
|
||||
logger.debug("Excluding {} clusters as they are {} arch, conflicting with the requested arch {}",
|
||||
avoidClusters.size(), arch.getType(), template.getArch().getType());
|
||||
List<Long> clusterIds = avoidClusters.stream().map(x -> x.getId()).collect(Collectors.toList());
|
||||
avoids.addClusterList(clusterIds);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private DeployDestination deployInVmLastHost(VirtualMachineProfile vmProfile, DeploymentPlan plan, ExcludeList avoids,
|
||||
DeploymentPlanner planner, VirtualMachine vm, DataCenter dc, ServiceOffering offering, int cpuRequested, long ramRequested,
|
||||
boolean volumesRequireEncryption) throws InsufficientServerCapacityException {
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ import javax.inject.Inject;
|
|||
import javax.naming.ConfigurationException;
|
||||
|
||||
import com.cloud.alert.AlertManager;
|
||||
import com.cloud.cpu.CPU;
|
||||
import com.cloud.exception.StorageConflictException;
|
||||
import com.cloud.exception.StorageUnavailableException;
|
||||
import com.cloud.host.HostTagVO;
|
||||
|
|
@ -426,6 +427,7 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager,
|
|||
String url = cmd.getUrl();
|
||||
final String username = cmd.getUsername();
|
||||
final String password = cmd.getPassword();
|
||||
CPU.CPUArch arch = cmd.getArch();
|
||||
|
||||
if (url != null) {
|
||||
url = URLDecoder.decode(url);
|
||||
|
|
@ -525,6 +527,7 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager,
|
|||
|
||||
cluster.setClusterType(clusterType);
|
||||
cluster.setAllocationState(allocationState);
|
||||
cluster.setArch(arch.getType());
|
||||
try {
|
||||
cluster = _clusterDao.persist(cluster);
|
||||
} catch (final Exception e) {
|
||||
|
|
@ -1141,6 +1144,7 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager,
|
|||
String allocationState = cmd.getAllocationState();
|
||||
String managedstate = cmd.getManagedstate();
|
||||
String name = cmd.getClusterName();
|
||||
CPU.CPUArch arch = cmd.getArch();
|
||||
|
||||
// Verify cluster information and update the cluster if needed
|
||||
boolean doUpdate = false;
|
||||
|
|
@ -1213,6 +1217,11 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager,
|
|||
}
|
||||
}
|
||||
|
||||
if (arch != null) {
|
||||
cluster.setArch(arch.getType());
|
||||
doUpdate = true;
|
||||
}
|
||||
|
||||
if (doUpdate) {
|
||||
_clusterDao.update(cluster.getId(), cluster);
|
||||
}
|
||||
|
|
@ -2353,6 +2362,7 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager,
|
|||
host.setLastPinged(System.currentTimeMillis() >> 10);
|
||||
host.setHostTags(hostTags, false);
|
||||
host.setDetails(details);
|
||||
host.setArch(CPU.CPUArch.fromType(startup.getArch()));
|
||||
if (startup.getStorageIpAddressDeux() != null) {
|
||||
host.setStorageIpAddressDeux(startup.getStorageIpAddressDeux());
|
||||
host.setStorageMacAddressDeux(startup.getStorageMacAddressDeux());
|
||||
|
|
@ -2746,6 +2756,13 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager,
|
|||
throw new IllegalArgumentException("Can't add host whose hypervisor type is: " + hyType + " into cluster: " + clusterVO.getId() +
|
||||
" whose hypervisor type is: " + clusterVO.getHypervisorType());
|
||||
}
|
||||
CPU.CPUArch hostCpuArch = CPU.CPUArch.fromType(ssCmd.getCpuArch());
|
||||
if (hostCpuArch != null && clusterVO.getArch() != null && hostCpuArch != clusterVO.getArch()) {
|
||||
String msg = String.format("Can't add a host whose arch is: %s into cluster of arch type: %s",
|
||||
hostCpuArch.getType(), clusterVO.getArch().getType());
|
||||
logger.error(msg);
|
||||
throw new IllegalArgumentException(msg);
|
||||
}
|
||||
|
||||
final Map<String, String> hostDetails = ssCmd.getHostDetails();
|
||||
if (hostDetails != null) {
|
||||
|
|
@ -2764,6 +2781,7 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager,
|
|||
host.setCaps(ssCmd.getCapabilities());
|
||||
host.setCpuSockets(ssCmd.getCpuSockets());
|
||||
host.setCpus(ssCmd.getCpus());
|
||||
host.setArch(hostCpuArch);
|
||||
host.setTotalMemory(ssCmd.getMemory());
|
||||
host.setSpeed(ssCmd.getSpeed());
|
||||
host.setHypervisorType(hyType);
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ import java.util.ArrayList;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.cloud.cpu.CPU;
|
||||
import com.cloud.hypervisor.Hypervisor.HypervisorType;
|
||||
import com.cloud.storage.Storage.ImageFormat;
|
||||
import com.cloud.storage.Storage.TemplateType;
|
||||
|
|
@ -28,6 +29,7 @@ public class TemplateProfile {
|
|||
Long userId;
|
||||
String name;
|
||||
String displayText;
|
||||
CPU.CPUArch arch;
|
||||
Integer bits;
|
||||
Boolean passwordEnabled;
|
||||
Boolean sshKeyEnbaled;
|
||||
|
|
@ -55,13 +57,14 @@ public class TemplateProfile {
|
|||
Boolean deployAsIs;
|
||||
Long size;
|
||||
|
||||
public TemplateProfile(Long templateId, Long userId, String name, String displayText, Integer bits, Boolean passwordEnabled, Boolean requiresHvm, String url,
|
||||
public TemplateProfile(Long templateId, Long userId, String name, String displayText, CPU.CPUArch arch, Integer bits, Boolean passwordEnabled, Boolean requiresHvm, String url,
|
||||
Boolean isPublic, Boolean featured, Boolean isExtractable, ImageFormat format, Long guestOsId, List<Long> zoneIdList, HypervisorType hypervisorType,
|
||||
String accountName, Long domainId, Long accountId, String chksum, Boolean bootable, Map details, Boolean sshKeyEnabled) {
|
||||
this.templateId = templateId;
|
||||
this.userId = userId;
|
||||
this.name = name;
|
||||
this.displayText = displayText;
|
||||
this.arch = arch;
|
||||
this.bits = bits;
|
||||
this.passwordEnabled = passwordEnabled;
|
||||
this.requiresHvm = requiresHvm;
|
||||
|
|
@ -92,15 +95,16 @@ public class TemplateProfile {
|
|||
else this.zoneIdList = null;
|
||||
}
|
||||
|
||||
public TemplateProfile(Long templateId, Long userId, String name, String displayText, Integer bits, Boolean passwordEnabled, Boolean requiresHvm, String url,
|
||||
Boolean isPublic, Boolean featured, Boolean isExtractable, ImageFormat format, Long guestOsId, List<Long> zoneId,
|
||||
public TemplateProfile(Long templateId, Long userId, String name, String displayText, CPU.CPUArch arch, Integer bits, Boolean passwordEnabled, Boolean requiresHvm, String url,
|
||||
Boolean isPublic, Boolean featured, Boolean isExtractable, ImageFormat format, Long guestOsId, List<Long> zoneId,
|
||||
|
||||
HypervisorType hypervisorType, String accountName, Long domainId, Long accountId, String chksum, Boolean bootable, String templateTag, Map details,
|
||||
Boolean sshKeyEnabled, Long imageStoreId, Boolean isDynamicallyScalable, TemplateType templateType, Boolean directDownload, Boolean deployAsIs) {
|
||||
HypervisorType hypervisorType, String accountName, Long domainId, Long accountId, String chksum, Boolean bootable, String templateTag, Map details,
|
||||
Boolean sshKeyEnabled, Long imageStoreId, Boolean isDynamicallyScalable, TemplateType templateType, Boolean directDownload, Boolean deployAsIs) {
|
||||
this(templateId,
|
||||
userId,
|
||||
name,
|
||||
displayText,
|
||||
arch,
|
||||
bits,
|
||||
passwordEnabled,
|
||||
requiresHvm,
|
||||
|
|
@ -337,4 +341,8 @@ public class TemplateProfile {
|
|||
public boolean isDeployAsIs() {
|
||||
return this.deployAsIs;
|
||||
}
|
||||
|
||||
public CPU.CPUArch getArch() {
|
||||
return arch;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,13 +16,14 @@
|
|||
// under the License.
|
||||
package com.cloud.storage.upload.params;
|
||||
|
||||
import com.cloud.cpu.CPU;
|
||||
import com.cloud.hypervisor.Hypervisor;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class TemplateUploadParams extends UploadParamsBase {
|
||||
|
||||
public TemplateUploadParams(long userId, String name, String displayText,
|
||||
public TemplateUploadParams(long userId, String name, String displayText, CPU.CPUArch arch,
|
||||
Integer bits, Boolean passwordEnabled, Boolean requiresHVM,
|
||||
Boolean isPublic, Boolean featured,
|
||||
Boolean isExtractable, String format, Long guestOSId,
|
||||
|
|
@ -30,7 +31,7 @@ public class TemplateUploadParams extends UploadParamsBase {
|
|||
String templateTag, long templateOwnerId,
|
||||
Map details, Boolean sshkeyEnabled,
|
||||
Boolean isDynamicallyScalable, Boolean isRoutingType, boolean deployAsIs) {
|
||||
super(userId, name, displayText, bits, passwordEnabled, requiresHVM, isPublic, featured, isExtractable,
|
||||
super(userId, name, displayText, arch, bits, passwordEnabled, requiresHVM, isPublic, featured, isExtractable,
|
||||
format, guestOSId, zoneId, hypervisorType, chksum, templateTag, templateOwnerId, details,
|
||||
sshkeyEnabled, isDynamicallyScalable, isRoutingType, deployAsIs);
|
||||
setBootable(true);
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
// under the License.
|
||||
package com.cloud.storage.upload.params;
|
||||
|
||||
import com.cloud.cpu.CPU;
|
||||
import com.cloud.hypervisor.Hypervisor;
|
||||
|
||||
import java.util.Map;
|
||||
|
|
@ -47,4 +48,5 @@ public interface UploadParams {
|
|||
boolean isRoutingType();
|
||||
boolean isDirectDownload();
|
||||
boolean isDeployAsIs();
|
||||
CPU.CPUArch getArch();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
// under the License.
|
||||
package com.cloud.storage.upload.params;
|
||||
|
||||
import com.cloud.cpu.CPU;
|
||||
import com.cloud.hypervisor.Hypervisor;
|
||||
|
||||
import java.util.Map;
|
||||
|
|
@ -45,8 +46,9 @@ public abstract class UploadParamsBase implements UploadParams {
|
|||
private boolean isDynamicallyScalable;
|
||||
private boolean isRoutingType;
|
||||
private boolean deployAsIs;
|
||||
private CPU.CPUArch arch;
|
||||
|
||||
UploadParamsBase(long userId, String name, String displayText,
|
||||
UploadParamsBase(long userId, String name, String displayText, CPU.CPUArch arch,
|
||||
Integer bits, boolean passwordEnabled, boolean requiresHVM,
|
||||
boolean isPublic, boolean featured,
|
||||
boolean isExtractable, String format, Long guestOSId,
|
||||
|
|
@ -57,6 +59,7 @@ public abstract class UploadParamsBase implements UploadParams {
|
|||
this.userId = userId;
|
||||
this.name = name;
|
||||
this.displayText = displayText;
|
||||
this.arch = arch;
|
||||
this.bits = bits;
|
||||
this.passwordEnabled = passwordEnabled;
|
||||
this.requiresHVM = requiresHVM;
|
||||
|
|
@ -244,4 +247,13 @@ public abstract class UploadParamsBase implements UploadParams {
|
|||
void setHypervisorType(Hypervisor.HypervisorType hypervisorType) {
|
||||
this.hypervisorType = hypervisorType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CPU.CPUArch getArch() {
|
||||
return arch;
|
||||
}
|
||||
|
||||
public void setArch(CPU.CPUArch arch) {
|
||||
this.arch = arch;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ package com.cloud.template;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.cloud.cpu.CPU;
|
||||
import org.apache.cloudstack.api.command.user.iso.DeleteIsoCmd;
|
||||
import org.apache.cloudstack.api.command.user.iso.GetUploadParamsForIsoCmd;
|
||||
import org.apache.cloudstack.api.command.user.iso.RegisterIsoCmd;
|
||||
|
|
@ -72,11 +73,11 @@ public interface TemplateAdapter extends Adapter {
|
|||
|
||||
boolean delete(TemplateProfile profile);
|
||||
|
||||
TemplateProfile prepare(boolean isIso, Long userId, String name, String displayText, Integer bits, Boolean passwordEnabled, Boolean requiresHVM, String url, Boolean isPublic,
|
||||
TemplateProfile prepare(boolean isIso, Long userId, String name, String displayText, CPU.CPUArch arch, Integer bits, Boolean passwordEnabled, Boolean requiresHVM, String url, Boolean isPublic,
|
||||
Boolean featured, Boolean isExtractable, String format, Long guestOSId, List<Long> zoneId, HypervisorType hypervisorType, String accountName, Long domainId, String chksum, Boolean bootable, Map details, boolean directDownload,
|
||||
boolean deployAsIs) throws ResourceAllocationException;
|
||||
|
||||
TemplateProfile prepare(boolean isIso, long userId, String name, String displayText, Integer bits, Boolean passwordEnabled, Boolean requiresHVM, String url, Boolean isPublic,
|
||||
TemplateProfile prepare(boolean isIso, long userId, String name, String displayText, CPU.CPUArch arch, Integer bits, Boolean passwordEnabled, Boolean requiresHVM, String url, Boolean isPublic,
|
||||
Boolean featured, Boolean isExtractable, String format, Long guestOSId, List<Long> zoneId, HypervisorType hypervisorType, String chksum, Boolean bootable, String templateTag, Account templateOwner, Map details, Boolean sshKeyEnabled, String imageStoreUuid, Boolean isDynamicallyScalable,
|
||||
TemplateType templateType, boolean directDownload, boolean deployAsIs) throws ResourceAllocationException;
|
||||
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ import java.util.Map;
|
|||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import com.cloud.cpu.CPU;
|
||||
import com.cloud.deployasis.DeployAsIsConstants;
|
||||
import com.cloud.storage.upload.params.IsoUploadParams;
|
||||
import com.cloud.storage.upload.params.TemplateUploadParams;
|
||||
|
|
@ -130,18 +131,18 @@ public abstract class TemplateAdapterBase extends AdapterBase implements Templat
|
|||
}
|
||||
|
||||
@Override
|
||||
public TemplateProfile prepare(boolean isIso, Long userId, String name, String displayText, Integer bits, Boolean passwordEnabled, Boolean requiresHVM, String url,
|
||||
Boolean isPublic, Boolean featured, Boolean isExtractable, String format, Long guestOSId, List<Long> zoneId, HypervisorType hypervisorType, String accountName,
|
||||
Long domainId, String chksum, Boolean bootable, Map details, boolean directDownload, boolean deployAsIs) throws ResourceAllocationException {
|
||||
return prepare(isIso, userId, name, displayText, bits, passwordEnabled, requiresHVM, url, isPublic, featured, isExtractable, format, guestOSId, zoneId,
|
||||
public TemplateProfile prepare(boolean isIso, Long userId, String name, String displayText, CPU.CPUArch arch, Integer bits, Boolean passwordEnabled, Boolean requiresHVM, String url,
|
||||
Boolean isPublic, Boolean featured, Boolean isExtractable, String format, Long guestOSId, List<Long> zoneId, HypervisorType hypervisorType, String accountName,
|
||||
Long domainId, String chksum, Boolean bootable, Map details, boolean directDownload, boolean deployAsIs) throws ResourceAllocationException {
|
||||
return prepare(isIso, userId, name, displayText, arch, bits, passwordEnabled, requiresHVM, url, isPublic, featured, isExtractable, format, guestOSId, zoneId,
|
||||
hypervisorType, chksum, bootable, null, null, details, false, null, false, TemplateType.USER, directDownload, deployAsIs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TemplateProfile prepare(boolean isIso, long userId, String name, String displayText, Integer bits, Boolean passwordEnabled, Boolean requiresHVM, String url,
|
||||
Boolean isPublic, Boolean featured, Boolean isExtractable, String format, Long guestOSId, List<Long> zoneIdList, HypervisorType hypervisorType, String chksum,
|
||||
Boolean bootable, String templateTag, Account templateOwner, Map details, Boolean sshkeyEnabled, String imageStoreUuid, Boolean isDynamicallyScalable,
|
||||
TemplateType templateType, boolean directDownload, boolean deployAsIs) throws ResourceAllocationException {
|
||||
public TemplateProfile prepare(boolean isIso, long userId, String name, String displayText, CPU.CPUArch arch, Integer bits, Boolean passwordEnabled, Boolean requiresHVM, String url,
|
||||
Boolean isPublic, Boolean featured, Boolean isExtractable, String format, Long guestOSId, List<Long> zoneIdList, HypervisorType hypervisorType, String chksum,
|
||||
Boolean bootable, String templateTag, Account templateOwner, Map details, Boolean sshkeyEnabled, String imageStoreUuid, Boolean isDynamicallyScalable,
|
||||
TemplateType templateType, boolean directDownload, boolean deployAsIs) throws ResourceAllocationException {
|
||||
//Long accountId = null;
|
||||
// parameters verification
|
||||
|
||||
|
|
@ -262,7 +263,7 @@ public abstract class TemplateAdapterBase extends AdapterBase implements Templat
|
|||
|
||||
Long id = _tmpltDao.getNextInSequence(Long.class, "id");
|
||||
CallContext.current().setEventDetails("Id: " + id + " name: " + name);
|
||||
return new TemplateProfile(id, userId, name, displayText, bits, passwordEnabled, requiresHVM, url, isPublic, featured, isExtractable, imgfmt, guestOSId, zoneIdList,
|
||||
return new TemplateProfile(id, userId, name, displayText, arch, bits, passwordEnabled, requiresHVM, url, isPublic, featured, isExtractable, imgfmt, guestOSId, zoneIdList,
|
||||
hypervisorType, templateOwner.getAccountName(), templateOwner.getDomainId(), templateOwner.getAccountId(), chksum, bootable, templateTag, details,
|
||||
sshkeyEnabled, null, isDynamicallyScalable, templateType, directDownload, deployAsIs);
|
||||
|
||||
|
|
@ -306,7 +307,7 @@ public abstract class TemplateAdapterBase extends AdapterBase implements Templat
|
|||
}
|
||||
}
|
||||
}
|
||||
return prepare(false, CallContext.current().getCallingUserId(), cmd.getTemplateName(), cmd.getDisplayText(), cmd.getBits(), cmd.isPasswordEnabled(), cmd.getRequiresHvm(),
|
||||
return prepare(false, CallContext.current().getCallingUserId(), cmd.getTemplateName(), cmd.getDisplayText(), cmd.getArch(), cmd.getBits(), cmd.isPasswordEnabled(), cmd.getRequiresHvm(),
|
||||
cmd.getUrl(), cmd.isPublic(), cmd.isFeatured(), cmd.isExtractable(), cmd.getFormat(), cmd.getOsTypeId(), zoneId, hypervisorType, cmd.getChecksum(), true,
|
||||
cmd.getTemplateTag(), owner, details, cmd.isSshKeyEnabled(), null, cmd.isDynamicallyScalable(), templateType,
|
||||
cmd.isDirectDownload(), cmd.isDeployAsIs());
|
||||
|
|
@ -337,7 +338,7 @@ public abstract class TemplateAdapterBase extends AdapterBase implements Templat
|
|||
StringUtils.join(Arrays.stream(HypervisorType.values()).filter(h -> h != HypervisorType.None).map(HypervisorType::name).toArray(), ", ")));
|
||||
}
|
||||
|
||||
return prepare(params.isIso(), params.getUserId(), params.getName(), params.getDisplayText(), params.getBits(),
|
||||
return prepare(params.isIso(), params.getUserId(), params.getName(), params.getDisplayText(), params.getArch(), params.getBits(),
|
||||
params.isPasswordEnabled(), params.requiresHVM(), params.getUrl(), params.isPublic(), params.isFeatured(),
|
||||
params.isExtractable(), params.getFormat(), params.getGuestOSId(), zoneList,
|
||||
params.getHypervisorType(), params.getChecksum(), params.isBootable(), params.getTemplateTag(), owner,
|
||||
|
|
@ -358,7 +359,7 @@ public abstract class TemplateAdapterBase extends AdapterBase implements Templat
|
|||
osTypeId = getDefaultDeployAsIsGuestOsId();
|
||||
}
|
||||
UploadParams params = new TemplateUploadParams(CallContext.current().getCallingUserId(), cmd.getName(),
|
||||
cmd.getDisplayText(), cmd.getBits(), BooleanUtils.toBoolean(cmd.isPasswordEnabled()),
|
||||
cmd.getDisplayText(), cmd.getArch(), cmd.getBits(), BooleanUtils.toBoolean(cmd.isPasswordEnabled()),
|
||||
BooleanUtils.toBoolean(cmd.getRequiresHvm()), BooleanUtils.toBoolean(cmd.isPublic()),
|
||||
BooleanUtils.toBoolean(cmd.isFeatured()), BooleanUtils.toBoolean(cmd.isExtractable()), cmd.getFormat(), osTypeId,
|
||||
cmd.getZoneId(), HypervisorType.getType(cmd.getHypervisor()), cmd.getChecksum(),
|
||||
|
|
@ -392,7 +393,7 @@ public abstract class TemplateAdapterBase extends AdapterBase implements Templat
|
|||
zoneList.add(zoneId);
|
||||
}
|
||||
|
||||
return prepare(true, CallContext.current().getCallingUserId(), cmd.getIsoName(), cmd.getDisplayText(), 64, cmd.isPasswordEnabled(), true, cmd.getUrl(), cmd.isPublic(),
|
||||
return prepare(true, CallContext.current().getCallingUserId(), cmd.getIsoName(), cmd.getDisplayText(), cmd.getArch(), 64, cmd.isPasswordEnabled(), true, cmd.getUrl(), cmd.isPublic(),
|
||||
cmd.isFeatured(), cmd.isExtractable(), ImageFormat.ISO.toString(), cmd.getOsTypeId(), zoneList, HypervisorType.None, cmd.getChecksum(), cmd.isBootable(), null,
|
||||
owner, null, false, cmd.getImageStoreUuid(), cmd.isDynamicallyScalable(), TemplateType.USER, cmd.isDirectDownload(), false);
|
||||
}
|
||||
|
|
@ -403,7 +404,7 @@ public abstract class TemplateAdapterBase extends AdapterBase implements Templat
|
|||
new VMTemplateVO(profile.getTemplateId(), profile.getName(), profile.getFormat(), profile.isPublic(), profile.isFeatured(), profile.isExtractable(),
|
||||
profile.getTemplateType(), profile.getUrl(), profile.isRequiresHVM(), profile.getBits(), profile.getAccountId(), profile.getCheckSum(),
|
||||
profile.getDisplayText(), profile.isPasswordEnabled(), profile.getGuestOsId(), profile.isBootable(), profile.getHypervisorType(),
|
||||
profile.getTemplateTag(), profile.getDetails(), profile.isSshKeyEnabled(), profile.IsDynamicallyScalable(), profile.isDirectDownload(), profile.isDeployAsIs());
|
||||
profile.getTemplateTag(), profile.getDetails(), profile.isSshKeyEnabled(), profile.IsDynamicallyScalable(), profile.isDirectDownload(), profile.isDeployAsIs(), profile.getArch());
|
||||
template.setState(initialState);
|
||||
|
||||
if (profile.isDirectDownload()) {
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ import java.util.stream.Collectors;
|
|||
import javax.inject.Inject;
|
||||
import javax.naming.ConfigurationException;
|
||||
|
||||
import com.cloud.cpu.CPU;
|
||||
import org.apache.cloudstack.acl.SecurityChecker.AccessType;
|
||||
import org.apache.cloudstack.api.ApiConstants;
|
||||
import org.apache.cloudstack.api.BaseCmd;
|
||||
|
|
@ -1918,9 +1919,13 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager,
|
|||
String description = cmd.getDisplayText();
|
||||
boolean isExtractable = false;
|
||||
Long sourceTemplateId = null;
|
||||
CPU.CPUArch arch = CPU.CPUArch.amd64;
|
||||
if (volume != null) {
|
||||
VMTemplateVO template = ApiDBUtils.findTemplateById(volume.getTemplateId());
|
||||
isExtractable = template != null && template.isExtractable() && template.getTemplateType() != Storage.TemplateType.SYSTEM;
|
||||
if (template != null) {
|
||||
arch = template.getArch();
|
||||
}
|
||||
if (volume.getIsoId() != null && volume.getIsoId() != 0) {
|
||||
sourceTemplateId = volume.getIsoId();
|
||||
} else if (volume.getTemplateId() != null) {
|
||||
|
|
@ -1935,7 +1940,7 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager,
|
|||
}
|
||||
privateTemplate = new VMTemplateVO(nextTemplateId, name, ImageFormat.RAW, isPublic, featured, isExtractable,
|
||||
TemplateType.USER, null, requiresHvmValue, bitsValue, templateOwner.getId(), null, description,
|
||||
passwordEnabledValue, guestOS.getId(), true, hyperType, templateTag, cmd.getDetails(), sshKeyEnabledValue, isDynamicScalingEnabled, false, false);
|
||||
passwordEnabledValue, guestOS.getId(), true, hyperType, templateTag, cmd.getDetails(), sshKeyEnabledValue, isDynamicScalingEnabled, false, false, arch);
|
||||
|
||||
if (sourceTemplateId != null) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
|
|
@ -2113,6 +2118,7 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager,
|
|||
Map details = cmd.getDetails();
|
||||
Account account = CallContext.current().getCallingAccount();
|
||||
boolean cleanupDetails = cmd.isCleanupDetails();
|
||||
CPU.CPUArch arch = cmd.getCPUArch();
|
||||
|
||||
// verify that template exists
|
||||
VMTemplateVO template = _tmpltDao.findById(id);
|
||||
|
|
@ -2161,6 +2167,7 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager,
|
|||
isRoutingTemplate == null &&
|
||||
templateType == null &&
|
||||
templateTag == null &&
|
||||
arch == null &&
|
||||
(! cleanupDetails && details == null) //update details in every case except this one
|
||||
);
|
||||
if (!updateNeeded) {
|
||||
|
|
@ -2235,6 +2242,10 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager,
|
|||
template.setDynamicallyScalable(isDynamicallyScalable);
|
||||
}
|
||||
|
||||
if (arch != null) {
|
||||
template.setArch(arch);
|
||||
}
|
||||
|
||||
if (isRoutingTemplate != null) {
|
||||
if (isRoutingTemplate) {
|
||||
template.setTemplateType(TemplateType.ROUTING);
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ import com.cloud.agent.AgentManager;
|
|||
import com.cloud.capacity.CapacityManager;
|
||||
import com.cloud.capacity.dao.CapacityDao;
|
||||
import com.cloud.configuration.ConfigurationManagerImpl;
|
||||
import com.cloud.cpu.CPU;
|
||||
import com.cloud.dc.ClusterDetailsDao;
|
||||
import com.cloud.dc.ClusterDetailsVO;
|
||||
import com.cloud.dc.ClusterVO;
|
||||
|
|
@ -295,6 +296,10 @@ public class DeploymentPlanningManagerImplTest {
|
|||
DataCenterDeployment plan = new DataCenterDeployment(dataCenterId);
|
||||
|
||||
Mockito.when(avoids.shouldAvoid((DataCenterVO) ArgumentMatchers.any())).thenReturn(true);
|
||||
VirtualMachineTemplate template = Mockito.mock(VirtualMachineTemplate.class);
|
||||
Mockito.when(template.getArch()).thenReturn(CPU.CPUArch.amd64);
|
||||
Mockito.when(vmProfile.getTemplate()).thenReturn(template);
|
||||
Mockito.when(_clusterDao.listClustersByArchAndZoneId(dataCenterId, CPU.CPUArch.arm64)).thenReturn(null);
|
||||
DeployDestination dest = _dpm.planDeployment(vmProfile, plan, avoids, null);
|
||||
assertNull("DataCenter is in avoid set, destination should be null! ", dest);
|
||||
}
|
||||
|
|
@ -310,6 +315,10 @@ public class DeploymentPlanningManagerImplTest {
|
|||
Mockito.when(avoids.shouldAvoid((DataCenterVO) ArgumentMatchers.any())).thenReturn(false);
|
||||
|
||||
Mockito.when(_planner.canHandle(vmProfile, plan, avoids)).thenReturn(false);
|
||||
VirtualMachineTemplate template = Mockito.mock(VirtualMachineTemplate.class);
|
||||
Mockito.when(template.getArch()).thenReturn(CPU.CPUArch.amd64);
|
||||
Mockito.when(vmProfile.getTemplate()).thenReturn(template);
|
||||
Mockito.when(_clusterDao.listClustersByArchAndZoneId(dataCenterId, CPU.CPUArch.arm64)).thenReturn(null);
|
||||
DeployDestination dest = _dpm.planDeployment(vmProfile, plan, avoids, null);
|
||||
assertNull("Planner cannot handle, destination should be null! ", dest);
|
||||
}
|
||||
|
|
@ -326,6 +335,10 @@ public class DeploymentPlanningManagerImplTest {
|
|||
Mockito.when(_planner.canHandle(vmProfile, plan, avoids)).thenReturn(true);
|
||||
|
||||
Mockito.when(((DeploymentClusterPlanner) _planner).orderClusters(vmProfile, plan, avoids)).thenReturn(null);
|
||||
VirtualMachineTemplate template = Mockito.mock(VirtualMachineTemplate.class);
|
||||
Mockito.when(template.getArch()).thenReturn(CPU.CPUArch.amd64);
|
||||
Mockito.when(vmProfile.getTemplate()).thenReturn(template);
|
||||
Mockito.when(_clusterDao.listClustersByArchAndZoneId(dataCenterId, CPU.CPUArch.arm64)).thenReturn(null);
|
||||
DeployDestination dest = _dpm.planDeployment(vmProfile, plan, avoids, null);
|
||||
assertNull("Planner cannot handle, destination should be null! ", dest);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -381,6 +381,7 @@
|
|||
"label.apply.tungsten.firewall.policy": "Apply Firewall Policy",
|
||||
"label.apply.tungsten.network.policy": "Apply Network Policy",
|
||||
"label.apply.tungsten.tag": "Apply tag",
|
||||
"label.arch": "Arch",
|
||||
"label.archive": "Archive",
|
||||
"label.archived": "Archived",
|
||||
"label.archive.alerts": "Archive alerts",
|
||||
|
|
@ -3220,6 +3221,7 @@
|
|||
"message.ip.address": "IP address : ",
|
||||
"message.ip.address.changes.effect.after.vm.restart": "IP address changes takes effect only after Instance restart.",
|
||||
"message.ip.v6.prefix.delete": "IPv6 prefix deleted",
|
||||
"message.iso.arch": "Please select an ISO architecture",
|
||||
"message.iso.desc": "Disc image containing data or bootable media for OS.",
|
||||
"message.kubeconfig.cluster.not.available": "Kubernetes cluster kubeconfig not available currently.",
|
||||
"message.kubernetes.cluster.delete": "Please confirm that you want to destroy the cluster.",
|
||||
|
|
@ -3551,6 +3553,7 @@
|
|||
"message.suspend.project": "Are you sure you want to suspend this project?",
|
||||
"message.sussess.discovering.feature": "Discovered all available features!",
|
||||
"message.switch.to": "Switched to",
|
||||
"message.template.arch": "Please select a Template architecture.",
|
||||
"message.template.desc": "OS image that can be used to boot Instances.",
|
||||
"message.template.import.vm.temporary": "If a temporary Template is used, the reset Instance operation will not work after importing it.",
|
||||
"message.template.iso": "Please select a Template or ISO to continue.",
|
||||
|
|
|
|||
|
|
@ -188,6 +188,9 @@
|
|||
<appstore-outlined />
|
||||
<span v-if="'cpunumber' in resource && 'cpuspeed' in resource">{{ resource.cpunumber }} CPU x {{ parseFloat(resource.cpuspeed / 1000.0).toFixed(2) }} Ghz</span>
|
||||
<span v-else>{{ resource.cputotal }}</span>
|
||||
<a-tag v-if="resource.arch" style="margin-left: 10px">
|
||||
{{ resource.arch }}
|
||||
</a-tag>
|
||||
</div>
|
||||
<div>
|
||||
<span v-if="resource.cpuused">
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ export default {
|
|||
return fields
|
||||
},
|
||||
details: () => {
|
||||
var fields = ['name', 'id', 'displaytext', 'checksum', 'hypervisor', 'format', 'ostypename', 'size', 'physicalsize', 'isready', 'passwordenabled',
|
||||
var fields = ['name', 'id', 'displaytext', 'checksum', 'hypervisor', 'arch', 'format', 'ostypename', 'size', 'physicalsize', 'isready', 'passwordenabled',
|
||||
'crossZones', 'templatetype', 'directdownload', 'deployasis', 'ispublic', 'isfeatured', 'isextractable', 'isdynamicallyscalable', 'crosszones', 'type',
|
||||
'account', 'domain', 'created', 'userdatadetails', 'userdatapolicy']
|
||||
if (['Admin'].includes(store.getters.userInfo.roletype)) {
|
||||
|
|
@ -231,7 +231,7 @@ export default {
|
|||
}
|
||||
return fields
|
||||
},
|
||||
details: ['name', 'id', 'displaytext', 'checksum', 'ostypename', 'size', 'bootable', 'isready', 'passwordenabled', 'directdownload', 'isextractable', 'ispublic', 'isfeatured', 'isdynamicallyscalable', 'crosszones', 'account', 'domain', 'created', 'userdatadetails', 'userdatapolicy', 'url'],
|
||||
details: ['name', 'id', 'displaytext', 'checksum', 'ostypename', 'size', 'arch', 'bootable', 'isready', 'passwordenabled', 'directdownload', 'isextractable', 'ispublic', 'isfeatured', 'isdynamicallyscalable', 'crosszones', 'account', 'domain', 'created', 'userdatadetails', 'userdatapolicy', 'url'],
|
||||
searchFilters: () => {
|
||||
var filters = ['name', 'zoneid', 'tags']
|
||||
if (['Admin', 'DomainAdmin'].includes(store.getters.userInfo.roletype)) {
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ export default {
|
|||
fields.push('zonename')
|
||||
return fields
|
||||
},
|
||||
details: ['name', 'id', 'allocationstate', 'clustertype', 'managedstate', 'hypervisortype', 'podname', 'zonename', 'drsimbalance'],
|
||||
details: ['name', 'id', 'allocationstate', 'clustertype', 'managedstate', 'arch', 'hypervisortype', 'podname', 'zonename', 'drsimbalance'],
|
||||
related: [{
|
||||
name: 'host',
|
||||
title: 'label.hosts',
|
||||
|
|
@ -83,7 +83,12 @@ export default {
|
|||
icon: 'edit-outlined',
|
||||
label: 'label.edit',
|
||||
dataView: true,
|
||||
args: ['clustername']
|
||||
args: ['clustername', 'arch'],
|
||||
mapping: {
|
||||
arch: {
|
||||
options: ['x86_64', 'aarch64']
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
api: 'updateCluster',
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ export default {
|
|||
fields.push('zonename')
|
||||
return fields
|
||||
},
|
||||
details: ['name', 'id', 'resourcestate', 'ipaddress', 'hypervisor', 'type', 'clustername', 'podname', 'zonename', 'disconnected', 'created'],
|
||||
details: ['name', 'id', 'resourcestate', 'ipaddress', 'hypervisor', 'arch', 'type', 'clustername', 'podname', 'zonename', 'disconnected', 'created'],
|
||||
tabs: [{
|
||||
name: 'details',
|
||||
component: shallowRef(defineAsyncComponent(() => import('@/components/view/DetailsTab.vue')))
|
||||
|
|
|
|||
|
|
@ -152,6 +152,18 @@
|
|||
@tabChange="key => onTabChange(key, 'tabKey')">
|
||||
<div v-if="tabKey === 'templateid'">
|
||||
{{ $t('message.template.desc') }}
|
||||
<div v-if="isZoneSelectedMultiArch" style="width: 100%; margin-top: 5px">
|
||||
{{ $t('message.template.arch') }}
|
||||
<a-select
|
||||
style="width: 100%"
|
||||
v-model:value="selectedArchitecture"
|
||||
:defaultValue="architectureTypes.opts[0].id"
|
||||
@change="arch => changeArchitecture(arch, true)">
|
||||
<a-select-option v-for="opt in architectureTypes.opts" :key="opt.id">
|
||||
{{ opt.name || opt.description }}
|
||||
</a-select-option>
|
||||
</a-select>
|
||||
</div>
|
||||
<template-iso-selection
|
||||
input-decorator="templateid"
|
||||
:items="options.templates"
|
||||
|
|
@ -181,6 +193,18 @@
|
|||
</div>
|
||||
<div v-else>
|
||||
{{ $t('message.iso.desc') }}
|
||||
<div v-if="isZoneSelectedMultiArch" style="width: 100%; margin-top: 5px">
|
||||
{{ $t('message.iso.arch') }}
|
||||
<a-select
|
||||
style="width: 100%"
|
||||
v-model:value="selectedArchitecture"
|
||||
:defaultValue="architectureTypes.opts[0].id"
|
||||
@change="arch => changeArchitecture(arch, false)">
|
||||
<a-select-option v-for="opt in architectureTypes.opts" :key="opt.id">
|
||||
{{ opt.name || opt.description }}
|
||||
</a-select-option>
|
||||
</a-select>
|
||||
</div>
|
||||
<template-iso-selection
|
||||
input-decorator="isoid"
|
||||
:items="options.isos"
|
||||
|
|
@ -914,6 +938,7 @@ export default {
|
|||
podId: null,
|
||||
clusterId: null,
|
||||
zoneSelected: false,
|
||||
isZoneSelectedMultiArch: false,
|
||||
dynamicscalingenabled: true,
|
||||
templateKey: 0,
|
||||
showRegisteredUserdata: true,
|
||||
|
|
@ -1064,7 +1089,19 @@ export default {
|
|||
zones: [],
|
||||
selectedZone: '',
|
||||
formModel: {},
|
||||
nicToNetworkSelection: []
|
||||
nicToNetworkSelection: [],
|
||||
selectedArchitecture: null,
|
||||
architectureTypes: {
|
||||
opts: [
|
||||
{
|
||||
id: 'x86_64',
|
||||
description: 'AMD 64 bits (x86_64)'
|
||||
}, {
|
||||
id: 'aarch64',
|
||||
description: 'ARM 64 bits (aarch64)'
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
|
|
@ -1957,6 +1994,14 @@ export default {
|
|||
getText (option) {
|
||||
return _.get(option, 'displaytext', _.get(option, 'name'))
|
||||
},
|
||||
changeArchitecture (arch, isTemplate) {
|
||||
this.selectedArchitecture = arch
|
||||
if (isTemplate) {
|
||||
this.fetchAllTemplates()
|
||||
} else {
|
||||
this.fetchAllIsos()
|
||||
}
|
||||
},
|
||||
handleSubmitAndStay (e) {
|
||||
this.form.stayonpage = true
|
||||
this.handleSubmit(e.domEvent)
|
||||
|
|
@ -2383,6 +2428,9 @@ export default {
|
|||
args.pageSize = args.pageSize || 10
|
||||
}
|
||||
args.zoneid = _.get(this.zone, 'id')
|
||||
if (this.isZoneSelectedMultiArch) {
|
||||
args.arch = this.selectedArchitecture
|
||||
}
|
||||
args.account = store.getters.project?.id ? null : this.owner.account
|
||||
args.domainid = store.getters.project?.id ? null : this.owner.domainid
|
||||
args.projectid = store.getters.project?.id || this.owner.projectid
|
||||
|
|
@ -2408,6 +2456,9 @@ export default {
|
|||
args.pageSize = args.pageSize || 10
|
||||
}
|
||||
args.zoneid = _.get(this.zone, 'id')
|
||||
if (this.isZoneSelectedMultiArch) {
|
||||
args.arch = this.selectedArchitecture
|
||||
}
|
||||
args.isoFilter = isoFilter
|
||||
args.bootable = true
|
||||
args.showicon = 'true'
|
||||
|
|
@ -2471,6 +2522,10 @@ export default {
|
|||
this.podId = null
|
||||
this.clusterId = null
|
||||
this.zone = _.find(this.options.zones, (option) => option.id === value)
|
||||
this.isZoneSelectedMultiArch = this.zone.ismultiarch
|
||||
if (this.isZoneSelectedMultiArch) {
|
||||
this.selectedArchitecture = this.architectureTypes.opts[0].id
|
||||
}
|
||||
this.zoneSelected = true
|
||||
this.form.startvm = true
|
||||
this.selectedZone = this.zoneId
|
||||
|
|
|
|||
|
|
@ -106,6 +106,25 @@
|
|||
v-model:checked="form.directdownload"
|
||||
:placeholder="apiParams.directdownload.description"/>
|
||||
</a-form-item>
|
||||
<a-form-item
|
||||
name="arch"
|
||||
ref="arch">
|
||||
<template #label>
|
||||
<tooltip-label :title="$t('label.arch')" :tooltip="apiParams.arch.description"/>
|
||||
</template>
|
||||
<a-select
|
||||
showSearch
|
||||
optionFilterProp="label"
|
||||
:filterOption="(input, option) => {
|
||||
return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
|
||||
}"
|
||||
v-model:value="form.arch"
|
||||
:placeholder="apiParams.arch.description">
|
||||
<a-select-option v-for="opt in architectureTypes.opts" :key="opt.id">
|
||||
{{ opt.name || opt.description }}
|
||||
</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
|
||||
<div :span="24" class="action-button">
|
||||
<a-button @click="closeAction">{{ $t('label.cancel') }}</a-button>
|
||||
|
|
@ -135,7 +154,8 @@ export default {
|
|||
loading: false,
|
||||
selectedZone: {},
|
||||
directDownloadDisabled: false,
|
||||
lastNonEdgeDirectDownloadUserSelection: false
|
||||
lastNonEdgeDirectDownloadUserSelection: false,
|
||||
architectureTypes: {}
|
||||
}
|
||||
},
|
||||
beforeCreate () {
|
||||
|
|
@ -196,6 +216,7 @@ export default {
|
|||
})
|
||||
},
|
||||
fetchData () {
|
||||
this.fetchArchitectureTypes()
|
||||
this.fetchZoneData()
|
||||
},
|
||||
isValidValueForKey (obj, key) {
|
||||
|
|
@ -204,6 +225,19 @@ export default {
|
|||
arrayHasItems (array) {
|
||||
return array !== null && array !== undefined && Array.isArray(array) && array.length > 0
|
||||
},
|
||||
fetchArchitectureTypes () {
|
||||
this.architectureTypes.opts = []
|
||||
const typesList = []
|
||||
typesList.push({
|
||||
id: 'x86_64',
|
||||
description: 'AMD 64 bits (x86_64)'
|
||||
})
|
||||
typesList.push({
|
||||
id: 'aarch64',
|
||||
description: 'ARM 64 bits (aarch64)'
|
||||
})
|
||||
this.architectureTypes.opts = typesList
|
||||
},
|
||||
fetchZoneData () {
|
||||
const params = {}
|
||||
params.showicon = true
|
||||
|
|
|
|||
|
|
@ -183,6 +183,26 @@
|
|||
</a-select>
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item
|
||||
name="arch"
|
||||
ref="arch">
|
||||
<template #label>
|
||||
<tooltip-label :title="$t('label.arch')" :tooltip="apiParams.arch.description"/>
|
||||
</template>
|
||||
<a-select
|
||||
showSearch
|
||||
optionFilterProp="label"
|
||||
:filterOption="(input, option) => {
|
||||
return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
|
||||
}"
|
||||
v-model:value="form.arch"
|
||||
:placeholder="apiParams.arch.description">
|
||||
<a-select-option v-for="opt in architectureTypes.opts" :key="opt.id">
|
||||
{{ opt.name || opt.description }}
|
||||
</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
|
||||
<a-row :gutter="12">
|
||||
<a-col :md="24" :lg="12">
|
||||
<a-form-item
|
||||
|
|
@ -322,7 +342,8 @@ export default {
|
|||
accounts: [],
|
||||
domainLoading: false,
|
||||
domainid: null,
|
||||
account: null
|
||||
account: null,
|
||||
architectureTypes: {}
|
||||
}
|
||||
},
|
||||
beforeCreate () {
|
||||
|
|
@ -363,6 +384,7 @@ export default {
|
|||
fetchData () {
|
||||
this.fetchZoneData()
|
||||
this.fetchOsType()
|
||||
this.fetchArchitectureTypes()
|
||||
this.fetchUserData()
|
||||
this.fetchUserdataPolicy()
|
||||
if ('listDomains' in this.$store.getters.apis) {
|
||||
|
|
@ -388,6 +410,19 @@ export default {
|
|||
this.form.zoneid = (this.zones[0].id ? this.zones[0].id : '')
|
||||
})
|
||||
},
|
||||
fetchArchitectureTypes () {
|
||||
this.architectureTypes.opts = []
|
||||
const typesList = []
|
||||
typesList.push({
|
||||
id: 'x86_64',
|
||||
description: 'AMD 64 bits (x86_64)'
|
||||
})
|
||||
typesList.push({
|
||||
id: 'aarch64',
|
||||
description: 'ARM 64 bits (aarch64)'
|
||||
})
|
||||
this.architectureTypes.opts = typesList
|
||||
},
|
||||
fetchOsType () {
|
||||
this.osTypeLoading = true
|
||||
|
||||
|
|
|
|||
|
|
@ -343,6 +343,25 @@
|
|||
</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
<a-form-item
|
||||
name="arch"
|
||||
ref="arch">
|
||||
<template #label>
|
||||
<tooltip-label :title="$t('label.arch')" :tooltip="apiParams.arch.description"/>
|
||||
</template>
|
||||
<a-select
|
||||
showSearch
|
||||
optionFilterProp="label"
|
||||
:filterOption="(input, option) => {
|
||||
return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
|
||||
}"
|
||||
v-model:value="form.arch"
|
||||
:placeholder="apiParams.arch.description">
|
||||
<a-select-option v-for="opt in architectureTypes.opts" :key="opt.id">
|
||||
{{ opt.name || opt.description }}
|
||||
</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
<a-form-item ref="templatetag" name="templatetag" v-if="isAdminRole">
|
||||
<template #label>
|
||||
<tooltip-label :title="$t('label.templatetag')" :tooltip="apiParams.templatetag.description"/>
|
||||
|
|
@ -511,7 +530,8 @@ export default {
|
|||
domainLoading: false,
|
||||
domainid: null,
|
||||
account: null,
|
||||
customHypervisorName: 'Custom'
|
||||
customHypervisorName: 'Custom',
|
||||
architectureTypes: {}
|
||||
}
|
||||
},
|
||||
beforeCreate () {
|
||||
|
|
@ -563,6 +583,7 @@ export default {
|
|||
this.fetchZone()
|
||||
this.fetchOsTypes()
|
||||
this.fetchTemplateTypes()
|
||||
this.fetchArchitectureTypes()
|
||||
this.fetchUserData()
|
||||
this.fetchUserdataPolicy()
|
||||
if ('listDomains' in this.$store.getters.apis) {
|
||||
|
|
@ -732,6 +753,19 @@ export default {
|
|||
}
|
||||
this.templateTypes.opts = templatetypes
|
||||
},
|
||||
fetchArchitectureTypes () {
|
||||
this.architectureTypes.opts = []
|
||||
const typesList = []
|
||||
typesList.push({
|
||||
id: 'x86_64',
|
||||
description: 'AMD 64 bits (x86_64)'
|
||||
})
|
||||
typesList.push({
|
||||
id: 'aarch64',
|
||||
description: 'ARM 64 bits (aarch64)'
|
||||
})
|
||||
this.architectureTypes.opts = typesList
|
||||
},
|
||||
fetchUserData () {
|
||||
const params = {}
|
||||
params.listAll = true
|
||||
|
|
|
|||
|
|
@ -119,6 +119,26 @@
|
|||
</a-col>
|
||||
</a-row>
|
||||
|
||||
<a-form-item
|
||||
name="arch"
|
||||
ref="arch">
|
||||
<template #label>
|
||||
<tooltip-label :title="$t('label.arch')" :tooltip="apiParams.arch.description"/>
|
||||
</template>
|
||||
<a-select
|
||||
showSearch
|
||||
optionFilterProp="label"
|
||||
:filterOption="(input, option) => {
|
||||
return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
|
||||
}"
|
||||
v-model:value="form.arch"
|
||||
:placeholder="apiParams.arch.description">
|
||||
<a-select-option v-for="opt in architectureTypes.opts" :key="opt.id">
|
||||
{{ opt.name || opt.description }}
|
||||
</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
|
||||
<div :span="24" class="action-button">
|
||||
<a-button @click="closeAction">{{ $t('label.cancel') }}</a-button>
|
||||
<a-button :loading="loading" ref="submit" type="primary" @click="handleSubmit">{{ $t('label.ok') }}</a-button>
|
||||
|
|
@ -151,7 +171,8 @@ export default {
|
|||
userdata: {},
|
||||
userdataid: null,
|
||||
userdatapolicy: null,
|
||||
userdatapolicylist: {}
|
||||
userdatapolicylist: {},
|
||||
architectureTypes: {}
|
||||
}
|
||||
},
|
||||
beforeCreate () {
|
||||
|
|
@ -195,6 +216,7 @@ export default {
|
|||
},
|
||||
fetchData () {
|
||||
this.fetchOsTypes()
|
||||
this.fetchArchitectureTypes()
|
||||
this.fetchUserdata()
|
||||
this.fetchUserdataPolicy()
|
||||
},
|
||||
|
|
@ -213,6 +235,19 @@ export default {
|
|||
this.osTypes.loading = false
|
||||
})
|
||||
},
|
||||
fetchArchitectureTypes () {
|
||||
this.architectureTypes.opts = []
|
||||
const typesList = []
|
||||
typesList.push({
|
||||
id: 'x86_64',
|
||||
description: 'AMD 64 bits (x86_64)'
|
||||
})
|
||||
typesList.push({
|
||||
id: 'aarch64',
|
||||
description: 'ARM 64 bits (aarch64)'
|
||||
})
|
||||
this.architectureTypes.opts = typesList
|
||||
},
|
||||
fetchUserdataPolicy () {
|
||||
const userdataPolicy = []
|
||||
userdataPolicy.push({
|
||||
|
|
|
|||
|
|
@ -186,6 +186,25 @@
|
|||
:placeholder="apiParams.templatetag.description"
|
||||
v-focus="currentForm !== 'Create'"/>
|
||||
</a-form-item>
|
||||
<a-form-item
|
||||
name="arch"
|
||||
ref="arch">
|
||||
<template #label>
|
||||
<tooltip-label :title="$t('label.arch')" :tooltip="apiParams.arch.description"/>
|
||||
</template>
|
||||
<a-select
|
||||
showSearch
|
||||
optionFilterProp="label"
|
||||
:filterOption="(input, option) => {
|
||||
return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
|
||||
}"
|
||||
v-model:value="form.arch"
|
||||
:placeholder="apiParams.arch.description">
|
||||
<a-select-option v-for="opt in architectureTypes.opts" :key="opt.id">
|
||||
{{ opt.name || opt.description }}
|
||||
</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
|
||||
<div :span="24" class="action-button">
|
||||
<a-button @click="closeAction">{{ $t('label.cancel') }}</a-button>
|
||||
|
|
@ -225,7 +244,8 @@ export default {
|
|||
userdata: {},
|
||||
userdataid: null,
|
||||
userdatapolicy: null,
|
||||
userdatapolicylist: {}
|
||||
userdatapolicylist: {},
|
||||
architectureTypes: {}
|
||||
}
|
||||
},
|
||||
beforeCreate () {
|
||||
|
|
@ -254,7 +274,7 @@ export default {
|
|||
displaytext: [{ required: true, message: this.$t('message.error.required.input') }],
|
||||
ostypeid: [{ required: true, message: this.$t('message.error.select') }]
|
||||
})
|
||||
const resourceFields = ['name', 'displaytext', 'passwordenabled', 'ostypeid', 'isdynamicallyscalable', 'userdataid', 'userdatapolicy']
|
||||
const resourceFields = ['name', 'displaytext', 'architecture', 'passwordenabled', 'ostypeid', 'isdynamicallyscalable', 'userdataid', 'userdatapolicy']
|
||||
if (this.isAdmin) {
|
||||
resourceFields.push('templatetype')
|
||||
resourceFields.push('templatetag')
|
||||
|
|
@ -290,6 +310,7 @@ export default {
|
|||
},
|
||||
fetchData () {
|
||||
this.fetchOsTypes()
|
||||
this.fetchArchitectureTypes()
|
||||
this.fetchRootDiskControllerTypes(this.resource.hypervisor)
|
||||
this.fetchNicAdapterTypes()
|
||||
this.fetchKeyboardTypes()
|
||||
|
|
@ -314,6 +335,19 @@ export default {
|
|||
this.osTypes.loading = false
|
||||
})
|
||||
},
|
||||
fetchArchitectureTypes () {
|
||||
this.architectureTypes.opts = []
|
||||
const typesList = []
|
||||
typesList.push({
|
||||
id: 'x86_64',
|
||||
description: 'AMD 64 bits (x86_64)'
|
||||
})
|
||||
typesList.push({
|
||||
id: 'aarch64',
|
||||
description: 'ARM 64 bits (aarch64)'
|
||||
})
|
||||
this.architectureTypes.opts = typesList
|
||||
},
|
||||
fetchRootDiskControllerTypes (hyperVisor) {
|
||||
const controller = []
|
||||
this.rootDisk.opts = []
|
||||
|
|
|
|||
|
|
@ -62,6 +62,21 @@
|
|||
</a-select>
|
||||
</div>
|
||||
|
||||
<div class="form__item">
|
||||
<div class="form__label">{{ $t('label.arch') }}</div>
|
||||
<a-select
|
||||
showSearch
|
||||
optionFilterProp="label"
|
||||
:filterOption="(input, option) => {
|
||||
return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
|
||||
}"
|
||||
v-model:value="selectedArchitecture">
|
||||
<a-select-option v-for="opt in architectureTypes.opts" :key="opt.id">
|
||||
{{ opt.name || opt.description }}
|
||||
</a-select-option>
|
||||
</a-select>
|
||||
</div>
|
||||
|
||||
<div class="form__item">
|
||||
<div class="form__label">{{ $t('label.podname') }}</div>
|
||||
<a-select
|
||||
|
|
@ -174,6 +189,8 @@ export default {
|
|||
dedicatedAccount: null,
|
||||
domainError: false,
|
||||
params: [],
|
||||
architectureTypes: {},
|
||||
selectedArchitecture: null,
|
||||
placeholder: {
|
||||
clustername: null
|
||||
}
|
||||
|
|
@ -186,6 +203,7 @@ export default {
|
|||
fetchData () {
|
||||
this.fetchZones()
|
||||
this.fetchHypervisors()
|
||||
this.fetchArchitectureTypes()
|
||||
this.params = this.$store.getters.apis.addCluster.params
|
||||
Object.keys(this.placeholder).forEach(item => { this.returnPlaceholder(item) })
|
||||
},
|
||||
|
|
@ -212,6 +230,20 @@ export default {
|
|||
this.loading = false
|
||||
})
|
||||
},
|
||||
fetchArchitectureTypes () {
|
||||
this.architectureTypes.opts = []
|
||||
const typesList = []
|
||||
typesList.push({
|
||||
id: 'x86_64',
|
||||
description: 'AMD 64 bits (x86_64)'
|
||||
})
|
||||
typesList.push({
|
||||
id: 'aarch64',
|
||||
description: 'ARM 64 bits (aarch64)'
|
||||
})
|
||||
this.architectureTypes.opts = typesList
|
||||
this.selectedArchitecture = this.architectureTypes.opts[0].id
|
||||
},
|
||||
fetchPods () {
|
||||
this.loading = true
|
||||
api('listPods', {
|
||||
|
|
@ -285,6 +317,7 @@ export default {
|
|||
clustertype: this.clustertype,
|
||||
podId: this.podId,
|
||||
clustername: clustername,
|
||||
arch: this.selectedArchitecture,
|
||||
url: this.url
|
||||
}
|
||||
if (this.ovm3pool) {
|
||||
|
|
|
|||
Loading…
Reference in New Issue