mirror of https://github.com/apache/cloudstack.git
Merge branch '4.19' into 4.20.merge
This commit is contained in:
commit
da54234585
|
|
@ -19,6 +19,9 @@ package com.cloud.agent.api.to;
|
||||||
import com.cloud.network.rules.FirewallRule;
|
import com.cloud.network.rules.FirewallRule;
|
||||||
import com.cloud.network.rules.PortForwardingRule;
|
import com.cloud.network.rules.PortForwardingRule;
|
||||||
import com.cloud.utils.net.NetUtils;
|
import com.cloud.utils.net.NetUtils;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* PortForwardingRuleTO specifies one port forwarding rule.
|
* PortForwardingRuleTO specifies one port forwarding rule.
|
||||||
|
|
@ -29,6 +32,8 @@ public class PortForwardingRuleTO extends FirewallRuleTO {
|
||||||
String dstIp;
|
String dstIp;
|
||||||
int[] dstPortRange;
|
int[] dstPortRange;
|
||||||
|
|
||||||
|
List<String> sourceCidrList;
|
||||||
|
|
||||||
protected PortForwardingRuleTO() {
|
protected PortForwardingRuleTO() {
|
||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
|
|
@ -37,6 +42,7 @@ public class PortForwardingRuleTO extends FirewallRuleTO {
|
||||||
super(rule, srcVlanTag, srcIp);
|
super(rule, srcVlanTag, srcIp);
|
||||||
this.dstIp = rule.getDestinationIpAddress().addr();
|
this.dstIp = rule.getDestinationIpAddress().addr();
|
||||||
this.dstPortRange = new int[] {rule.getDestinationPortStart(), rule.getDestinationPortEnd()};
|
this.dstPortRange = new int[] {rule.getDestinationPortStart(), rule.getDestinationPortEnd()};
|
||||||
|
this.sourceCidrList = rule.getSourceCidrList();
|
||||||
}
|
}
|
||||||
|
|
||||||
public PortForwardingRuleTO(long id, String srcIp, int srcPortStart, int srcPortEnd, String dstIp, int dstPortStart, int dstPortEnd, String protocol,
|
public PortForwardingRuleTO(long id, String srcIp, int srcPortStart, int srcPortEnd, String dstIp, int dstPortStart, int dstPortEnd, String protocol,
|
||||||
|
|
@ -58,4 +64,11 @@ public class PortForwardingRuleTO extends FirewallRuleTO {
|
||||||
return NetUtils.portRangeToString(dstPortRange);
|
return NetUtils.portRangeToString(dstPortRange);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getSourceCidrListAsString() {
|
||||||
|
if (sourceCidrList != null) {
|
||||||
|
return StringUtils.join(sourceCidrList, ",");
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@ import com.cloud.exception.ResourceUnavailableException;
|
||||||
import com.cloud.user.Account;
|
import com.cloud.user.Account;
|
||||||
import com.cloud.utils.Pair;
|
import com.cloud.utils.Pair;
|
||||||
import com.cloud.utils.net.Ip;
|
import com.cloud.utils.net.Ip;
|
||||||
|
import org.apache.cloudstack.api.command.user.firewall.UpdatePortForwardingRuleCmd;
|
||||||
|
|
||||||
public interface RulesService {
|
public interface RulesService {
|
||||||
Pair<List<? extends FirewallRule>, Integer> searchStaticNatRules(Long ipId, Long id, Long vmId, Long start, Long size, String accountName, Long domainId,
|
Pair<List<? extends FirewallRule>, Integer> searchStaticNatRules(Long ipId, Long id, Long vmId, Long start, Long size, String accountName, Long domainId,
|
||||||
|
|
@ -81,6 +82,8 @@ public interface RulesService {
|
||||||
|
|
||||||
boolean disableStaticNat(long ipId) throws ResourceUnavailableException, NetworkRuleConflictException, InsufficientAddressCapacityException;
|
boolean disableStaticNat(long ipId) throws ResourceUnavailableException, NetworkRuleConflictException, InsufficientAddressCapacityException;
|
||||||
|
|
||||||
PortForwardingRule updatePortForwardingRule(long id, Integer privatePort, Integer privateEndPort, Long virtualMachineId, Ip vmGuestIp, String customId, Boolean forDisplay);
|
PortForwardingRule updatePortForwardingRule(UpdatePortForwardingRuleCmd cmd);
|
||||||
|
|
||||||
|
void validatePortForwardingSourceCidrList(List<String> sourceCidrList);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -244,6 +244,7 @@ public class ApiConstants {
|
||||||
public static final String ICMP_TYPE = "icmptype";
|
public static final String ICMP_TYPE = "icmptype";
|
||||||
public static final String ID = "id";
|
public static final String ID = "id";
|
||||||
public static final String IDS = "ids";
|
public static final String IDS = "ids";
|
||||||
|
public static final String IMPORT_INSTANCE_HOST_ID = "importinstancehostid";
|
||||||
public static final String INDEX = "index";
|
public static final String INDEX = "index";
|
||||||
public static final String INSTANCES_DISKS_STATS_RETENTION_ENABLED = "instancesdisksstatsretentionenabled";
|
public static final String INSTANCES_DISKS_STATS_RETENTION_ENABLED = "instancesdisksstatsretentionenabled";
|
||||||
public static final String INSTANCES_DISKS_STATS_RETENTION_TIME = "instancesdisksstatsretentiontime";
|
public static final String INSTANCES_DISKS_STATS_RETENTION_TIME = "instancesdisksstatsretentiontime";
|
||||||
|
|
@ -464,6 +465,7 @@ public class ApiConstants {
|
||||||
public static final String SNAPSHOT_POLICY_ID = "snapshotpolicyid";
|
public static final String SNAPSHOT_POLICY_ID = "snapshotpolicyid";
|
||||||
public static final String SNAPSHOT_TYPE = "snapshottype";
|
public static final String SNAPSHOT_TYPE = "snapshottype";
|
||||||
public static final String SNAPSHOT_QUIESCEVM = "quiescevm";
|
public static final String SNAPSHOT_QUIESCEVM = "quiescevm";
|
||||||
|
public static final String SOURCE_CIDR_LIST = "sourcecidrlist";
|
||||||
public static final String SOURCE_ZONE_ID = "sourcezoneid";
|
public static final String SOURCE_ZONE_ID = "sourcezoneid";
|
||||||
public static final String SSL_VERIFICATION = "sslverification";
|
public static final String SSL_VERIFICATION = "sslverification";
|
||||||
public static final String START_ASN = "startasn";
|
public static final String START_ASN = "startasn";
|
||||||
|
|
|
||||||
|
|
@ -144,15 +144,19 @@ public class ImportVmCmd extends ImportUnmanagedInstanceCmd {
|
||||||
private String clusterName;
|
private String clusterName;
|
||||||
|
|
||||||
@Parameter(name = ApiConstants.CONVERT_INSTANCE_HOST_ID, type = CommandType.UUID, entityType = HostResponse.class,
|
@Parameter(name = ApiConstants.CONVERT_INSTANCE_HOST_ID, type = CommandType.UUID, entityType = HostResponse.class,
|
||||||
description = "(only for importing VMs from VMware to KVM) optional - the host to perform the virt-v2v migration from VMware to KVM.")
|
description = "(only for importing VMs from VMware to KVM) optional - the host to perform the virt-v2v conversion from VMware to KVM.")
|
||||||
private Long convertInstanceHostId;
|
private Long convertInstanceHostId;
|
||||||
|
|
||||||
|
@Parameter(name = ApiConstants.IMPORT_INSTANCE_HOST_ID, type = CommandType.UUID, entityType = HostResponse.class, since = "4.19.2",
|
||||||
|
description = "(only for importing VMs from VMware to KVM) optional - the host to import the converted instance from VMware to KVM.")
|
||||||
|
private Long importInstanceHostId;
|
||||||
|
|
||||||
@Parameter(name = ApiConstants.CONVERT_INSTANCE_STORAGE_POOL_ID, type = CommandType.UUID, entityType = StoragePoolResponse.class,
|
@Parameter(name = ApiConstants.CONVERT_INSTANCE_STORAGE_POOL_ID, type = CommandType.UUID, entityType = StoragePoolResponse.class,
|
||||||
description = "(only for importing VMs from VMware to KVM) optional - the temporary storage pool to perform the virt-v2v migration from VMware to KVM.")
|
description = "(only for importing VMs from VMware to KVM) optional - the temporary storage pool to perform the virt-v2v migration from VMware to KVM.")
|
||||||
private Long convertStoragePoolId;
|
private Long convertStoragePoolId;
|
||||||
|
|
||||||
@Parameter(name = ApiConstants.FORCE_MS_TO_IMPORT_VM_FILES, type = CommandType.BOOLEAN,
|
@Parameter(name = ApiConstants.FORCE_MS_TO_IMPORT_VM_FILES, type = CommandType.BOOLEAN,
|
||||||
description = "(only for importing VMs from VMware to KVM) optional - if true, forces MS to import VM file(s) to temporary storage, else uses KVM Host if ovftool is available, falls back to MS if not.")
|
description = "(only for importing VMs from VMware to KVM) optional - if true, forces MS to export OVF from VMware to temporary storage, else uses KVM Host if ovftool is available, falls back to MS if not.")
|
||||||
private Boolean forceMsToImportVmFiles;
|
private Boolean forceMsToImportVmFiles;
|
||||||
|
|
||||||
/////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////
|
||||||
|
|
@ -199,6 +203,10 @@ public class ImportVmCmd extends ImportUnmanagedInstanceCmd {
|
||||||
return convertInstanceHostId;
|
return convertInstanceHostId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Long getImportInstanceHostId() {
|
||||||
|
return importInstanceHostId;
|
||||||
|
}
|
||||||
|
|
||||||
public Long getConvertStoragePoolId() {
|
public Long getConvertStoragePoolId() {
|
||||||
return convertStoragePoolId;
|
return convertStoragePoolId;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -105,8 +105,12 @@ public class CreatePortForwardingRuleCmd extends BaseAsyncCreateCmd implements P
|
||||||
description = "the ID of the virtual machine for the port forwarding rule")
|
description = "the ID of the virtual machine for the port forwarding rule")
|
||||||
private Long virtualMachineId;
|
private Long virtualMachineId;
|
||||||
|
|
||||||
@Parameter(name = ApiConstants.CIDR_LIST, type = CommandType.LIST, collectionType = CommandType.STRING, description = "the cidr list to forward traffic from. Multiple entries must be separated by a single comma character (,). This parameter is deprecated. Do not use.")
|
@Parameter(name = ApiConstants.CIDR_LIST,
|
||||||
private List<String> cidrlist;
|
type = CommandType.LIST,
|
||||||
|
collectionType = CommandType.STRING,
|
||||||
|
description = " the source CIDR list to allow traffic from; all other CIDRs will be blocked. " +
|
||||||
|
"Multiple entries must be separated by a single comma character (,). This param will be used only for VPC tiers. By default, all CIDRs are allowed.")
|
||||||
|
private List<String> sourceCidrList;
|
||||||
|
|
||||||
@Parameter(name = ApiConstants.OPEN_FIREWALL, type = CommandType.BOOLEAN, description = "if true, firewall rule for source/end public port is automatically created; "
|
@Parameter(name = ApiConstants.OPEN_FIREWALL, type = CommandType.BOOLEAN, description = "if true, firewall rule for source/end public port is automatically created; "
|
||||||
+ "if false - firewall rule has to be created explicitly. If not specified 1) defaulted to false when PF"
|
+ "if false - firewall rule has to be created explicitly. If not specified 1) defaulted to false when PF"
|
||||||
|
|
@ -155,11 +159,7 @@ public class CreatePortForwardingRuleCmd extends BaseAsyncCreateCmd implements P
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<String> getSourceCidrList() {
|
public List<String> getSourceCidrList() {
|
||||||
if (cidrlist != null) {
|
return sourceCidrList;
|
||||||
throw new InvalidParameterValueException("Parameter cidrList is deprecated; if you need to open firewall "
|
|
||||||
+ "rule for the specific cidr, please refer to createFirewallRule command");
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Boolean getOpenFirewall() {
|
public Boolean getOpenFirewall() {
|
||||||
|
|
@ -332,12 +332,6 @@ public class CreatePortForwardingRuleCmd extends BaseAsyncCreateCmd implements P
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void create() {
|
public void create() {
|
||||||
// cidr list parameter is deprecated
|
|
||||||
if (cidrlist != null) {
|
|
||||||
throw new InvalidParameterValueException(
|
|
||||||
"Parameter cidrList is deprecated; if you need to open firewall rule for the specific cidr, please refer to createFirewallRule command");
|
|
||||||
}
|
|
||||||
|
|
||||||
Ip privateIp = getVmSecondaryIp();
|
Ip privateIp = getVmSecondaryIp();
|
||||||
if (privateIp != null) {
|
if (privateIp != null) {
|
||||||
if (!NetUtils.isValidIp4(privateIp.toString())) {
|
if (!NetUtils.isValidIp4(privateIp.toString())) {
|
||||||
|
|
@ -345,6 +339,8 @@ public class CreatePortForwardingRuleCmd extends BaseAsyncCreateCmd implements P
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_rulesService.validatePortForwardingSourceCidrList(sourceCidrList);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
PortForwardingRule result = _rulesService.createPortForwardingRule(this, virtualMachineId, privateIp, getOpenFirewall(), isDisplay());
|
PortForwardingRule result = _rulesService.createPortForwardingRule(this, virtualMachineId, privateIp, getOpenFirewall(), isDisplay());
|
||||||
setEntityId(result.getId());
|
setEntityId(result.getId());
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,8 @@ import com.cloud.network.rules.PortForwardingRule;
|
||||||
import com.cloud.user.Account;
|
import com.cloud.user.Account;
|
||||||
import com.cloud.utils.net.Ip;
|
import com.cloud.utils.net.Ip;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
@APICommand(name = "updatePortForwardingRule",
|
@APICommand(name = "updatePortForwardingRule",
|
||||||
responseObject = FirewallRuleResponse.class,
|
responseObject = FirewallRuleResponse.class,
|
||||||
description = "Updates a port forwarding rule. Only the private port and the virtual machine can be updated.", entityType = {PortForwardingRule.class},
|
description = "Updates a port forwarding rule. Only the private port and the virtual machine can be updated.", entityType = {PortForwardingRule.class},
|
||||||
|
|
@ -63,6 +65,13 @@ public class UpdatePortForwardingRuleCmd extends BaseAsyncCustomIdCmd {
|
||||||
@Parameter(name = ApiConstants.FOR_DISPLAY, type = CommandType.BOOLEAN, description = "an optional field, whether to the display the rule to the end user or not", since = "4.4", authorized = {RoleType.Admin})
|
@Parameter(name = ApiConstants.FOR_DISPLAY, type = CommandType.BOOLEAN, description = "an optional field, whether to the display the rule to the end user or not", since = "4.4", authorized = {RoleType.Admin})
|
||||||
private Boolean display;
|
private Boolean display;
|
||||||
|
|
||||||
|
@Parameter(name = ApiConstants.CIDR_LIST,
|
||||||
|
type = CommandType.LIST,
|
||||||
|
collectionType = CommandType.STRING,
|
||||||
|
description = " the source CIDR list to allow traffic from; all other CIDRs will be blocked. " +
|
||||||
|
"Multiple entries must be separated by a single comma character (,). This param will be used only for VPC tiers. By default, all CIDRs are allowed.")
|
||||||
|
private List<String> sourceCidrList;
|
||||||
|
|
||||||
/////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////
|
||||||
/////////////////// Accessors ///////////////////////
|
/////////////////// Accessors ///////////////////////
|
||||||
/////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////
|
||||||
|
|
@ -94,6 +103,10 @@ public class UpdatePortForwardingRuleCmd extends BaseAsyncCustomIdCmd {
|
||||||
return display;
|
return display;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<String> getSourceCidrList() {
|
||||||
|
return sourceCidrList;
|
||||||
|
}
|
||||||
|
|
||||||
/////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////
|
||||||
/////////////// API Implementation///////////////////
|
/////////////// API Implementation///////////////////
|
||||||
/////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////
|
||||||
|
|
@ -130,7 +143,7 @@ public class UpdatePortForwardingRuleCmd extends BaseAsyncCustomIdCmd {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void execute() {
|
public void execute() {
|
||||||
PortForwardingRule rule = _rulesService.updatePortForwardingRule(getId(), getPrivatePort(), getPrivateEndPort(), getVirtualMachineId(), getVmGuestIp(), getCustomId(), getDisplay());
|
PortForwardingRule rule = _rulesService.updatePortForwardingRule(this);
|
||||||
FirewallRuleResponse fwResponse = new FirewallRuleResponse();
|
FirewallRuleResponse fwResponse = new FirewallRuleResponse();
|
||||||
if (rule != null) {
|
if (rule != null) {
|
||||||
fwResponse = _responseGenerator.createPortForwardingRuleResponse(rule);
|
fwResponse = _responseGenerator.createPortForwardingRuleResponse(rule);
|
||||||
|
|
|
||||||
|
|
@ -104,7 +104,7 @@ public class CreateLoadBalancerRuleCmd extends BaseAsyncCreateCmd /*implements L
|
||||||
@Parameter(name = ApiConstants.DOMAIN_ID, type = CommandType.UUID, entityType = DomainResponse.class, description = "the domain ID associated with the load balancer")
|
@Parameter(name = ApiConstants.DOMAIN_ID, type = CommandType.UUID, entityType = DomainResponse.class, description = "the domain ID associated with the load balancer")
|
||||||
private Long domainId;
|
private Long domainId;
|
||||||
|
|
||||||
@Parameter(name = ApiConstants.CIDR_LIST, type = CommandType.LIST, collectionType = CommandType.STRING, since = "4.18.0.0", description = "the CIDR list to allow traffic, "
|
@Parameter(name = ApiConstants.CIDR_LIST, type = CommandType.LIST, collectionType = CommandType.STRING, since = "4.18.0.0", description = "the source CIDR list to allow traffic from; "
|
||||||
+ "all other CIDRs will be blocked. Multiple entries must be separated by a single comma character (,). By default, all CIDRs are allowed.")
|
+ "all other CIDRs will be blocked. Multiple entries must be separated by a single comma character (,). By default, all CIDRs are allowed.")
|
||||||
private List<String> cidrlist;
|
private List<String> cidrlist;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,8 @@ import org.apache.cloudstack.vm.UnmanagedInstanceTO;
|
||||||
|
|
||||||
public class ConvertInstanceAnswer extends Answer {
|
public class ConvertInstanceAnswer extends Answer {
|
||||||
|
|
||||||
|
private String temporaryConvertUuid;
|
||||||
|
|
||||||
public ConvertInstanceAnswer() {
|
public ConvertInstanceAnswer() {
|
||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
|
|
@ -34,6 +36,15 @@ public class ConvertInstanceAnswer extends Answer {
|
||||||
this.convertedInstance = convertedInstance;
|
this.convertedInstance = convertedInstance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ConvertInstanceAnswer(Command command, String temporaryConvertUuid) {
|
||||||
|
super(command, true, "");
|
||||||
|
this.temporaryConvertUuid = temporaryConvertUuid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTemporaryConvertUuid() {
|
||||||
|
return temporaryConvertUuid;
|
||||||
|
}
|
||||||
|
|
||||||
public UnmanagedInstanceTO getConvertedInstance() {
|
public UnmanagedInstanceTO getConvertedInstance() {
|
||||||
return convertedInstance;
|
return convertedInstance;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,40 @@
|
||||||
|
// 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.agent.api;
|
||||||
|
|
||||||
|
import org.apache.cloudstack.vm.UnmanagedInstanceTO;
|
||||||
|
|
||||||
|
public class ImportConvertedInstanceAnswer extends Answer {
|
||||||
|
|
||||||
|
public ImportConvertedInstanceAnswer() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
private UnmanagedInstanceTO convertedInstance;
|
||||||
|
|
||||||
|
public ImportConvertedInstanceAnswer(Command command, boolean success, String details) {
|
||||||
|
super(command, success, details);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ImportConvertedInstanceAnswer(Command command, UnmanagedInstanceTO convertedInstance) {
|
||||||
|
super(command, true, "");
|
||||||
|
this.convertedInstance = convertedInstance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UnmanagedInstanceTO getConvertedInstance() {
|
||||||
|
return convertedInstance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,63 @@
|
||||||
|
// 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.agent.api;
|
||||||
|
|
||||||
|
import com.cloud.agent.api.to.DataStoreTO;
|
||||||
|
import com.cloud.agent.api.to.RemoteInstanceTO;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class ImportConvertedInstanceCommand extends Command {
|
||||||
|
|
||||||
|
private RemoteInstanceTO sourceInstance;
|
||||||
|
private List<String> destinationStoragePools;
|
||||||
|
private DataStoreTO conversionTemporaryLocation;
|
||||||
|
private String temporaryConvertUuid;
|
||||||
|
|
||||||
|
public ImportConvertedInstanceCommand() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public ImportConvertedInstanceCommand(RemoteInstanceTO sourceInstance,
|
||||||
|
List<String> destinationStoragePools,
|
||||||
|
DataStoreTO conversionTemporaryLocation, String temporaryConvertUuid) {
|
||||||
|
this.sourceInstance = sourceInstance;
|
||||||
|
this.destinationStoragePools = destinationStoragePools;
|
||||||
|
this.conversionTemporaryLocation = conversionTemporaryLocation;
|
||||||
|
this.temporaryConvertUuid = temporaryConvertUuid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public RemoteInstanceTO getSourceInstance() {
|
||||||
|
return sourceInstance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getDestinationStoragePools() {
|
||||||
|
return destinationStoragePools;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DataStoreTO getConversionTemporaryLocation() {
|
||||||
|
return conversionTemporaryLocation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTemporaryConvertUuid() {
|
||||||
|
return temporaryConvertUuid;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean executeInSequence() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -41,7 +41,7 @@ public class SetPortForwardingRulesConfigItem extends AbstractConfigItemFacade {
|
||||||
|
|
||||||
for (final PortForwardingRuleTO rule : command.getRules()) {
|
for (final PortForwardingRuleTO rule : command.getRules()) {
|
||||||
final ForwardingRule fwdRule = new ForwardingRule(rule.revoked(), rule.getProtocol().toLowerCase(), rule.getSrcIp(), rule.getStringSrcPortRange(), rule.getDstIp(),
|
final ForwardingRule fwdRule = new ForwardingRule(rule.revoked(), rule.getProtocol().toLowerCase(), rule.getSrcIp(), rule.getStringSrcPortRange(), rule.getDstIp(),
|
||||||
rule.getStringDstPortRange());
|
rule.getStringDstPortRange(), rule.getSourceCidrListAsString());
|
||||||
rules.add(fwdRule);
|
rules.add(fwdRule);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -26,18 +26,21 @@ public class ForwardingRule {
|
||||||
private String sourcePortRange;
|
private String sourcePortRange;
|
||||||
private String destinationIpAddress;
|
private String destinationIpAddress;
|
||||||
private String destinationPortRange;
|
private String destinationPortRange;
|
||||||
|
private String sourceCidrList;
|
||||||
|
|
||||||
public ForwardingRule() {
|
public ForwardingRule() {
|
||||||
// Empty constructor for (de)serialization
|
// Empty constructor for (de)serialization
|
||||||
}
|
}
|
||||||
|
|
||||||
public ForwardingRule(boolean revoke, String protocol, String sourceIpAddress, String sourcePortRange, String destinationIpAddress, String destinationPortRange) {
|
public ForwardingRule(boolean revoke, String protocol, String sourceIpAddress, String sourcePortRange, String destinationIpAddress, String destinationPortRange,
|
||||||
|
String sourceCidrList) {
|
||||||
this.revoke = revoke;
|
this.revoke = revoke;
|
||||||
this.protocol = protocol;
|
this.protocol = protocol;
|
||||||
this.sourceIpAddress = sourceIpAddress;
|
this.sourceIpAddress = sourceIpAddress;
|
||||||
this.sourcePortRange = sourcePortRange;
|
this.sourcePortRange = sourcePortRange;
|
||||||
this.destinationIpAddress = destinationIpAddress;
|
this.destinationIpAddress = destinationIpAddress;
|
||||||
this.destinationPortRange = destinationPortRange;
|
this.destinationPortRange = destinationPortRange;
|
||||||
|
this.sourceCidrList = sourceCidrList;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isRevoke() {
|
public boolean isRevoke() {
|
||||||
|
|
@ -88,4 +91,8 @@ public class ForwardingRule {
|
||||||
this.destinationPortRange = destinationPortRange;
|
this.destinationPortRange = destinationPortRange;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getSourceCidrList() {
|
||||||
|
return sourceCidrList;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -29,4 +29,6 @@ public interface FirewallRulesCidrsDao extends GenericDao<FirewallRulesCidrsVO,
|
||||||
|
|
||||||
@DB
|
@DB
|
||||||
List<FirewallRulesCidrsVO> listByFirewallRuleId(long firewallRuleId);
|
List<FirewallRulesCidrsVO> listByFirewallRuleId(long firewallRuleId);
|
||||||
|
|
||||||
|
void updateSourceCidrsForRule(Long firewallRuleId, List<String> sourceCidrList);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@ import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
|
||||||
|
import org.apache.commons.collections4.CollectionUtils;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import com.cloud.utils.db.DB;
|
import com.cloud.utils.db.DB;
|
||||||
|
|
@ -45,7 +46,7 @@ public class FirewallRulesCidrsDaoImpl extends GenericDaoBase<FirewallRulesCidrs
|
||||||
sc.setParameters("firewallRuleId", firewallRuleId);
|
sc.setParameters("firewallRuleId", firewallRuleId);
|
||||||
|
|
||||||
List<FirewallRulesCidrsVO> results = search(sc, null);
|
List<FirewallRulesCidrsVO> results = search(sc, null);
|
||||||
List<String> cidrs = new ArrayList<String>(results.size());
|
List<String> cidrs = new ArrayList<>(results.size());
|
||||||
for (FirewallRulesCidrsVO result : results) {
|
for (FirewallRulesCidrsVO result : results) {
|
||||||
cidrs.add(result.getCidr());
|
cidrs.add(result.getCidr());
|
||||||
}
|
}
|
||||||
|
|
@ -63,9 +64,27 @@ public class FirewallRulesCidrsDaoImpl extends GenericDaoBase<FirewallRulesCidrs
|
||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateSourceCidrsForRule(Long firewallRuleId, List<String> sourceCidrList) {
|
||||||
|
TransactionLegacy txn = TransactionLegacy.currentTxn();
|
||||||
|
txn.start();
|
||||||
|
|
||||||
|
SearchCriteria<FirewallRulesCidrsVO> sc = CidrsSearch.create();
|
||||||
|
sc.setParameters("firewallRuleId", firewallRuleId);
|
||||||
|
remove(sc);
|
||||||
|
|
||||||
|
persist(firewallRuleId, sourceCidrList);
|
||||||
|
|
||||||
|
txn.commit();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@DB
|
@DB
|
||||||
public void persist(long firewallRuleId, List<String> sourceCidrs) {
|
public void persist(long firewallRuleId, List<String> sourceCidrs) {
|
||||||
|
if (CollectionUtils.isEmpty(sourceCidrs)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
TransactionLegacy txn = TransactionLegacy.currentTxn();
|
TransactionLegacy txn = TransactionLegacy.currentTxn();
|
||||||
|
|
||||||
txn.start();
|
txn.start();
|
||||||
|
|
|
||||||
|
|
@ -251,9 +251,6 @@ public class FirewallRulesDaoImpl extends GenericDaoBase<FirewallRuleVO, Long> i
|
||||||
}
|
}
|
||||||
|
|
||||||
public void saveSourceCidrs(FirewallRuleVO firewallRule, List<String> cidrList) {
|
public void saveSourceCidrs(FirewallRuleVO firewallRule, List<String> cidrList) {
|
||||||
if (cidrList == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
_firewallRulesCidrsDao.persist(firewallRule.getId(), cidrList);
|
_firewallRulesCidrsDao.persist(firewallRule.getId(), cidrList);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@ import javax.persistence.EnumType;
|
||||||
import javax.persistence.Enumerated;
|
import javax.persistence.Enumerated;
|
||||||
import javax.persistence.PrimaryKeyJoinColumn;
|
import javax.persistence.PrimaryKeyJoinColumn;
|
||||||
import javax.persistence.Table;
|
import javax.persistence.Table;
|
||||||
|
import javax.persistence.Transient;
|
||||||
|
|
||||||
import com.cloud.utils.net.Ip;
|
import com.cloud.utils.net.Ip;
|
||||||
|
|
||||||
|
|
@ -47,21 +48,30 @@ public class PortForwardingRuleVO extends FirewallRuleVO implements PortForwardi
|
||||||
@Column(name = "instance_id")
|
@Column(name = "instance_id")
|
||||||
private long virtualMachineId;
|
private long virtualMachineId;
|
||||||
|
|
||||||
|
@Transient
|
||||||
|
List<String> sourceCidrs;
|
||||||
|
|
||||||
public PortForwardingRuleVO() {
|
public PortForwardingRuleVO() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public PortForwardingRuleVO(String xId, long srcIpId, int srcPortStart, int srcPortEnd, Ip dstIp, int dstPortStart, int dstPortEnd, String protocol, long networkId,
|
public PortForwardingRuleVO(String xId, long srcIpId, int srcPortStart, int srcPortEnd, Ip dstIp, int dstPortStart, int dstPortEnd, String protocol, long networkId,
|
||||||
long accountId, long domainId, long instanceId) {
|
long accountId, long domainId, long instanceId, List<String> sourceCidrs) {
|
||||||
super(xId, srcIpId, srcPortStart, srcPortEnd, protocol, networkId, accountId, domainId, Purpose.PortForwarding, null, null, null, null, null);
|
super(xId, srcIpId, srcPortStart, srcPortEnd, protocol, networkId, accountId, domainId, Purpose.PortForwarding, sourceCidrs, null, null, null, null);
|
||||||
this.destinationIpAddress = dstIp;
|
this.destinationIpAddress = dstIp;
|
||||||
this.virtualMachineId = instanceId;
|
this.virtualMachineId = instanceId;
|
||||||
this.destinationPortStart = dstPortStart;
|
this.destinationPortStart = dstPortStart;
|
||||||
this.destinationPortEnd = dstPortEnd;
|
this.destinationPortEnd = dstPortEnd;
|
||||||
|
this.sourceCidrs = sourceCidrs;
|
||||||
}
|
}
|
||||||
|
|
||||||
public PortForwardingRuleVO(String xId, long srcIpId, int srcPort, Ip dstIp, int dstPort, String protocol, List<String> sourceCidrs, long networkId, long accountId,
|
public PortForwardingRuleVO(String xId, long srcIpId, int srcPortStart, int srcPortEnd, Ip dstIp, int dstPortStart, int dstPortEnd, String protocol, long networkId,
|
||||||
long domainId, long instanceId) {
|
long accountId, long domainId, long instanceId) {
|
||||||
this(xId, srcIpId, srcPort, srcPort, dstIp, dstPort, dstPort, protocol.toLowerCase(), networkId, accountId, domainId, instanceId);
|
this(xId, srcIpId, srcPortStart, srcPortEnd, dstIp, dstPortStart, dstPortEnd, protocol.toLowerCase(), networkId, accountId, domainId, instanceId, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public PortForwardingRuleVO(String xId, long srcIpId, int srcPort, Ip dstIp, int dstPort, String protocol, long networkId, long accountId,
|
||||||
|
long domainId, long instanceId) {
|
||||||
|
this(xId, srcIpId, srcPort, srcPort, dstIp, dstPort, dstPort, protocol.toLowerCase(), networkId, accountId, domainId, instanceId, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -106,4 +116,13 @@ public class PortForwardingRuleVO extends FirewallRuleVO implements PortForwardi
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setSourceCidrList(List<String> sourceCidrs) {
|
||||||
|
this.sourceCidrs = sourceCidrs;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> getSourceCidrList() {
|
||||||
|
return sourceCidrs;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,9 @@ import com.cloud.utils.db.GenericDaoBase;
|
||||||
import com.cloud.utils.db.SearchBuilder;
|
import com.cloud.utils.db.SearchBuilder;
|
||||||
import com.cloud.utils.db.SearchCriteria;
|
import com.cloud.utils.db.SearchCriteria;
|
||||||
import com.cloud.utils.db.SearchCriteria.Op;
|
import com.cloud.utils.db.SearchCriteria.Op;
|
||||||
|
import com.cloud.utils.db.Transaction;
|
||||||
|
import com.cloud.utils.db.TransactionCallback;
|
||||||
|
import com.cloud.utils.db.TransactionLegacy;
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
public class PortForwardingRulesDaoImpl extends GenericDaoBase<PortForwardingRuleVO, Long> implements PortForwardingRulesDao {
|
public class PortForwardingRulesDaoImpl extends GenericDaoBase<PortForwardingRuleVO, Long> implements PortForwardingRulesDao {
|
||||||
|
|
@ -42,7 +45,7 @@ public class PortForwardingRulesDaoImpl extends GenericDaoBase<PortForwardingRul
|
||||||
protected final SearchBuilder<PortForwardingRuleVO> ActiveRulesSearchByAccount;
|
protected final SearchBuilder<PortForwardingRuleVO> ActiveRulesSearchByAccount;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
protected FirewallRulesCidrsDao _portForwardingRulesCidrsDao;
|
protected FirewallRulesCidrsDao portForwardingRulesCidrsDao;
|
||||||
|
|
||||||
protected PortForwardingRulesDaoImpl() {
|
protected PortForwardingRulesDaoImpl() {
|
||||||
super();
|
super();
|
||||||
|
|
@ -183,4 +186,43 @@ public class PortForwardingRulesDaoImpl extends GenericDaoBase<PortForwardingRul
|
||||||
sc.setParameters("vmIds", vmIds.toArray());
|
sc.setParameters("vmIds", vmIds.toArray());
|
||||||
return batchExpunge(sc, batchSize);
|
return batchExpunge(sc, batchSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public PortForwardingRuleVO persist(PortForwardingRuleVO portForwardingRule) {
|
||||||
|
return Transaction.execute((TransactionCallback<PortForwardingRuleVO>) transactionStatus -> {
|
||||||
|
PortForwardingRuleVO dbPfRule = super.persist(portForwardingRule);
|
||||||
|
|
||||||
|
portForwardingRulesCidrsDao.persist(portForwardingRule.getId(), portForwardingRule.getSourceCidrList());
|
||||||
|
List<String> cidrList = portForwardingRulesCidrsDao.getSourceCidrs(portForwardingRule.getId());
|
||||||
|
portForwardingRule.setSourceCidrList(cidrList);
|
||||||
|
|
||||||
|
return dbPfRule;
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean update(Long id, PortForwardingRuleVO entity) {
|
||||||
|
TransactionLegacy txn = TransactionLegacy.currentTxn();
|
||||||
|
txn.start();
|
||||||
|
|
||||||
|
boolean success = super.update(id, entity);
|
||||||
|
if (!success) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
portForwardingRulesCidrsDao.updateSourceCidrsForRule(entity.getId(), entity.getSourceCidrList());
|
||||||
|
txn.commit();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PortForwardingRuleVO findById(Long id) {
|
||||||
|
PortForwardingRuleVO rule = super.findById(id);
|
||||||
|
|
||||||
|
List<String> sourceCidrList = portForwardingRulesCidrsDao.getSourceCidrs(id);
|
||||||
|
rule.setSourceCidrList(sourceCidrList);
|
||||||
|
|
||||||
|
return rule;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -50,6 +50,9 @@ public class VolumeVO implements Volume {
|
||||||
@Column(name = "id")
|
@Column(name = "id")
|
||||||
long id;
|
long id;
|
||||||
|
|
||||||
|
@Column(name = "last_id")
|
||||||
|
private long lastId;
|
||||||
|
|
||||||
@Column(name = "name")
|
@Column(name = "name")
|
||||||
String name;
|
String name;
|
||||||
|
|
||||||
|
|
@ -690,4 +693,12 @@ public class VolumeVO implements Volume {
|
||||||
public void setDeleteProtection(boolean deleteProtection) {
|
public void setDeleteProtection(boolean deleteProtection) {
|
||||||
this.deleteProtection = deleteProtection;
|
this.deleteProtection = deleteProtection;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public long getLastId() {
|
||||||
|
return lastId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLastId(long lastId) {
|
||||||
|
this.lastId = lastId;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -70,3 +70,6 @@ CALL `cloud`.`IDEMPOTENT_ADD_COLUMN`('cloud.user_data', 'removed', 'datetime COM
|
||||||
UPDATE `cloud`.`configuration` SET
|
UPDATE `cloud`.`configuration` SET
|
||||||
`options` = 'FirstFitRouting,RandomAllocator,TestingAllocator,FirstFitAllocator,RecreateHostAllocator'
|
`options` = 'FirstFitRouting,RandomAllocator,TestingAllocator,FirstFitAllocator,RecreateHostAllocator'
|
||||||
WHERE `name` = 'host.allocators.order';
|
WHERE `name` = 'host.allocators.order';
|
||||||
|
|
||||||
|
-- Add last_id to the volumes table
|
||||||
|
CALL `cloud`.`IDEMPOTENT_ADD_COLUMN`('volumes','last_id', 'bigint(20) unsigned DEFAULT NULL');
|
||||||
|
|
|
||||||
|
|
@ -2293,6 +2293,8 @@ public class StorageSystemDataMotionStrategy implements DataMotionStrategy {
|
||||||
if (success) {
|
if (success) {
|
||||||
VolumeVO volumeVO = _volumeDao.findById(destVolumeInfo.getId());
|
VolumeVO volumeVO = _volumeDao.findById(destVolumeInfo.getId());
|
||||||
volumeVO.setFormat(ImageFormat.QCOW2);
|
volumeVO.setFormat(ImageFormat.QCOW2);
|
||||||
|
volumeVO.setLastId(srcVolumeInfo.getId());
|
||||||
|
|
||||||
_volumeDao.update(volumeVO.getId(), volumeVO);
|
_volumeDao.update(volumeVO.getId(), volumeVO);
|
||||||
|
|
||||||
_volumeService.copyPoliciesBetweenVolumesAndDestroySourceVolumeAfterMigration(Event.OperationSuccessed, null, srcVolumeInfo, destVolumeInfo, false);
|
_volumeService.copyPoliciesBetweenVolumesAndDestroySourceVolumeAfterMigration(Event.OperationSuccessed, null, srcVolumeInfo, destVolumeInfo, false);
|
||||||
|
|
|
||||||
|
|
@ -1720,6 +1720,7 @@ public class VolumeServiceImpl implements VolumeService {
|
||||||
newVol.setPassphraseId(volume.getPassphraseId());
|
newVol.setPassphraseId(volume.getPassphraseId());
|
||||||
newVol.setEncryptFormat(volume.getEncryptFormat());
|
newVol.setEncryptFormat(volume.getEncryptFormat());
|
||||||
}
|
}
|
||||||
|
newVol.setLastId(volume.getId());
|
||||||
return volDao.persist(newVol);
|
return volDao.persist(newVol);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3000,6 +3000,17 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv
|
||||||
return dataPath;
|
return dataPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean useBLOCKDiskType(KVMPhysicalDisk physicalDisk) {
|
||||||
|
return physicalDisk != null &&
|
||||||
|
physicalDisk.getPool().getType() == StoragePoolType.Linstor &&
|
||||||
|
physicalDisk.getFormat() != null &&
|
||||||
|
physicalDisk.getFormat()== PhysicalDiskFormat.RAW;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static DiskDef.DiskType getDiskType(KVMPhysicalDisk physicalDisk) {
|
||||||
|
return useBLOCKDiskType(physicalDisk) ? DiskDef.DiskType.BLOCK : DiskDef.DiskType.FILE;
|
||||||
|
}
|
||||||
|
|
||||||
public void createVbd(final Connect conn, final VirtualMachineTO vmSpec, final String vmName, final LibvirtVMDef vm) throws InternalErrorException, LibvirtException, URISyntaxException {
|
public void createVbd(final Connect conn, final VirtualMachineTO vmSpec, final String vmName, final LibvirtVMDef vm) throws InternalErrorException, LibvirtException, URISyntaxException {
|
||||||
final Map<String, String> details = vmSpec.getDetails();
|
final Map<String, String> details = vmSpec.getDetails();
|
||||||
final List<DiskTO> disks = Arrays.asList(vmSpec.getDisks());
|
final List<DiskTO> disks = Arrays.asList(vmSpec.getDisks());
|
||||||
|
|
@ -3045,7 +3056,8 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv
|
||||||
physicalDisk = getPhysicalDiskFromNfsStore(dataStoreUrl, data);
|
physicalDisk = getPhysicalDiskFromNfsStore(dataStoreUrl, data);
|
||||||
} else if (primaryDataStoreTO.getPoolType().equals(StoragePoolType.SharedMountPoint) ||
|
} else if (primaryDataStoreTO.getPoolType().equals(StoragePoolType.SharedMountPoint) ||
|
||||||
primaryDataStoreTO.getPoolType().equals(StoragePoolType.Filesystem) ||
|
primaryDataStoreTO.getPoolType().equals(StoragePoolType.Filesystem) ||
|
||||||
primaryDataStoreTO.getPoolType().equals(StoragePoolType.StorPool)) {
|
primaryDataStoreTO.getPoolType().equals(StoragePoolType.StorPool) ||
|
||||||
|
primaryDataStoreTO.getPoolType().equals(StoragePoolType.Linstor)) {
|
||||||
physicalDisk = getPhysicalDiskPrimaryStore(primaryDataStoreTO, data);
|
physicalDisk = getPhysicalDiskPrimaryStore(primaryDataStoreTO, data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -3095,8 +3107,8 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv
|
||||||
final DiskDef disk = new DiskDef();
|
final DiskDef disk = new DiskDef();
|
||||||
int devId = volume.getDiskSeq().intValue();
|
int devId = volume.getDiskSeq().intValue();
|
||||||
if (volume.getType() == Volume.Type.ISO) {
|
if (volume.getType() == Volume.Type.ISO) {
|
||||||
|
final DiskDef.DiskType diskType = getDiskType(physicalDisk);
|
||||||
disk.defISODisk(volPath, devId, isUefiEnabled);
|
disk.defISODisk(volPath, devId, isUefiEnabled, diskType);
|
||||||
|
|
||||||
if (guestCpuArch != null && guestCpuArch.equals("aarch64")) {
|
if (guestCpuArch != null && guestCpuArch.equals("aarch64")) {
|
||||||
disk.setBusType(DiskDef.DiskBus.SCSI);
|
disk.setBusType(DiskDef.DiskBus.SCSI);
|
||||||
|
|
@ -3195,7 +3207,7 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv
|
||||||
|
|
||||||
if (vmSpec.getType() != VirtualMachine.Type.User) {
|
if (vmSpec.getType() != VirtualMachine.Type.User) {
|
||||||
final DiskDef iso = new DiskDef();
|
final DiskDef iso = new DiskDef();
|
||||||
iso.defISODisk(sysvmISOPath);
|
iso.defISODisk(sysvmISOPath, DiskDef.DiskType.FILE);
|
||||||
if (guestCpuArch != null && guestCpuArch.equals("aarch64")) {
|
if (guestCpuArch != null && guestCpuArch.equals("aarch64")) {
|
||||||
iso.setBusType(DiskDef.DiskBus.SCSI);
|
iso.setBusType(DiskDef.DiskBus.SCSI);
|
||||||
}
|
}
|
||||||
|
|
@ -3408,7 +3420,7 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv
|
||||||
List<DiskDef> disks = getDisks(conn, vmName);
|
List<DiskDef> disks = getDisks(conn, vmName);
|
||||||
DiskDef configdrive = null;
|
DiskDef configdrive = null;
|
||||||
for (DiskDef disk : disks) {
|
for (DiskDef disk : disks) {
|
||||||
if (disk.getDeviceType() == DiskDef.DeviceType.CDROM && disk.getDiskLabel() == CONFIG_DRIVE_ISO_DISK_LABEL) {
|
if (disk.getDeviceType() == DiskDef.DeviceType.CDROM && CONFIG_DRIVE_ISO_DISK_LABEL.equals(disk.getDiskLabel())) {
|
||||||
configdrive = disk;
|
configdrive = disk;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -3438,11 +3450,12 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv
|
||||||
final String name = isoPath.substring(index + 1);
|
final String name = isoPath.substring(index + 1);
|
||||||
final KVMStoragePool secondaryPool = storagePoolManager.getStoragePoolByURI(path);
|
final KVMStoragePool secondaryPool = storagePoolManager.getStoragePoolByURI(path);
|
||||||
final KVMPhysicalDisk isoVol = secondaryPool.getPhysicalDisk(name);
|
final KVMPhysicalDisk isoVol = secondaryPool.getPhysicalDisk(name);
|
||||||
|
final DiskDef.DiskType diskType = getDiskType(isoVol);
|
||||||
isoPath = isoVol.getPath();
|
isoPath = isoVol.getPath();
|
||||||
|
|
||||||
iso.defISODisk(isoPath, diskSeq);
|
iso.defISODisk(isoPath, diskSeq, diskType);
|
||||||
} else {
|
} else {
|
||||||
iso.defISODisk(null, diskSeq);
|
iso.defISODisk(null, diskSeq, DiskDef.DiskType.FILE);
|
||||||
}
|
}
|
||||||
|
|
||||||
final String result = attachOrDetachDevice(conn, true, vmName, iso.toString());
|
final String result = attachOrDetachDevice(conn, true, vmName, iso.toString());
|
||||||
|
|
@ -3450,7 +3463,7 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv
|
||||||
final List<DiskDef> disks = getDisks(conn, vmName);
|
final List<DiskDef> disks = getDisks(conn, vmName);
|
||||||
for (final DiskDef disk : disks) {
|
for (final DiskDef disk : disks) {
|
||||||
if (disk.getDeviceType() == DiskDef.DeviceType.CDROM
|
if (disk.getDeviceType() == DiskDef.DeviceType.CDROM
|
||||||
&& (diskSeq == null || disk.getDiskLabel() == iso.getDiskLabel())) {
|
&& (diskSeq == null || disk.getDiskLabel().equals(iso.getDiskLabel()))) {
|
||||||
cleanupDisk(disk);
|
cleanupDisk(disk);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -4046,7 +4059,7 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv
|
||||||
return stopVMInternal(conn, vmName, true);
|
return stopVMInternal(conn, vmName, true);
|
||||||
}
|
}
|
||||||
String ret = stopVMInternal(conn, vmName, false);
|
String ret = stopVMInternal(conn, vmName, false);
|
||||||
if (ret == Script.ERR_TIMEOUT) {
|
if (Script.ERR_TIMEOUT.equals(ret)) {
|
||||||
ret = stopVMInternal(conn, vmName, true);
|
ret = stopVMInternal(conn, vmName, true);
|
||||||
} else if (ret != null) {
|
} else if (ret != null) {
|
||||||
/*
|
/*
|
||||||
|
|
|
||||||
|
|
@ -127,11 +127,10 @@ public class LibvirtDomainXMLParser {
|
||||||
}
|
}
|
||||||
def.defFileBasedDisk(diskFile, diskLabel, DiskDef.DiskBus.valueOf(bus.toUpperCase()), fmt);
|
def.defFileBasedDisk(diskFile, diskLabel, DiskDef.DiskBus.valueOf(bus.toUpperCase()), fmt);
|
||||||
} else if (device.equalsIgnoreCase("cdrom")) {
|
} else if (device.equalsIgnoreCase("cdrom")) {
|
||||||
def.defISODisk(diskFile, i+1, diskLabel);
|
def.defISODisk(diskFile, i+1, diskLabel, DiskDef.DiskType.FILE);
|
||||||
}
|
}
|
||||||
} else if (type.equalsIgnoreCase("block")) {
|
} else if (type.equalsIgnoreCase("block")) {
|
||||||
def.defBlockBasedDisk(diskDev, diskLabel,
|
parseDiskBlock(def, device, diskDev, diskLabel, bus, diskFile, i);
|
||||||
DiskDef.DiskBus.valueOf(bus.toUpperCase()));
|
|
||||||
}
|
}
|
||||||
if (StringUtils.isNotBlank(diskCacheMode)) {
|
if (StringUtils.isNotBlank(diskCacheMode)) {
|
||||||
def.setCacheMode(DiskDef.DiskCacheMode.valueOf(diskCacheMode.toUpperCase()));
|
def.setCacheMode(DiskDef.DiskCacheMode.valueOf(diskCacheMode.toUpperCase()));
|
||||||
|
|
@ -450,6 +449,25 @@ public class LibvirtDomainXMLParser {
|
||||||
return node.getAttribute(attr);
|
return node.getAttribute(attr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse the disk block part of the libvirt XML.
|
||||||
|
* @param def
|
||||||
|
* @param device
|
||||||
|
* @param diskDev
|
||||||
|
* @param diskLabel
|
||||||
|
* @param bus
|
||||||
|
* @param diskFile
|
||||||
|
* @param curDiskIndex
|
||||||
|
*/
|
||||||
|
private void parseDiskBlock(DiskDef def, String device, String diskDev, String diskLabel, String bus,
|
||||||
|
String diskFile, int curDiskIndex) {
|
||||||
|
if (device.equalsIgnoreCase("disk")) {
|
||||||
|
def.defBlockBasedDisk(diskDev, diskLabel, DiskDef.DiskBus.valueOf(bus.toUpperCase()));
|
||||||
|
} else if (device.equalsIgnoreCase("cdrom")) {
|
||||||
|
def.defISODisk(diskFile, curDiskIndex+1, diskLabel, DiskDef.DiskType.BLOCK);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public Integer getVncPort() {
|
public Integer getVncPort() {
|
||||||
return vncPort;
|
return vncPort;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -894,8 +894,8 @@ public class LibvirtVMDef {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void defISODisk(String volPath) {
|
public void defISODisk(String volPath, DiskType diskType) {
|
||||||
_diskType = DiskType.FILE;
|
_diskType = diskType;
|
||||||
_deviceType = DeviceType.CDROM;
|
_deviceType = DeviceType.CDROM;
|
||||||
_sourcePath = volPath;
|
_sourcePath = volPath;
|
||||||
_diskLabel = getDevLabel(3, DiskBus.IDE, true);
|
_diskLabel = getDevLabel(3, DiskBus.IDE, true);
|
||||||
|
|
@ -904,8 +904,8 @@ public class LibvirtVMDef {
|
||||||
_bus = DiskBus.IDE;
|
_bus = DiskBus.IDE;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void defISODisk(String volPath, boolean isUefiEnabled) {
|
public void defISODisk(String volPath, boolean isUefiEnabled, DiskType diskType) {
|
||||||
_diskType = DiskType.FILE;
|
_diskType = diskType;
|
||||||
_deviceType = DeviceType.CDROM;
|
_deviceType = DeviceType.CDROM;
|
||||||
_sourcePath = volPath;
|
_sourcePath = volPath;
|
||||||
_bus = isUefiEnabled ? DiskBus.SATA : DiskBus.IDE;
|
_bus = isUefiEnabled ? DiskBus.SATA : DiskBus.IDE;
|
||||||
|
|
@ -914,18 +914,18 @@ public class LibvirtVMDef {
|
||||||
_diskCacheMode = DiskCacheMode.NONE;
|
_diskCacheMode = DiskCacheMode.NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void defISODisk(String volPath, Integer devId) {
|
public void defISODisk(String volPath, Integer devId, DiskType diskType) {
|
||||||
defISODisk(volPath, devId, null);
|
defISODisk(volPath, devId, null, diskType);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void defISODisk(String volPath, Integer devId, String diskLabel) {
|
public void defISODisk(String volPath, Integer devId, String diskLabel, DiskType diskType) {
|
||||||
if (devId == null && StringUtils.isBlank(diskLabel)) {
|
if (devId == null && StringUtils.isBlank(diskLabel)) {
|
||||||
LOGGER.debug(String.format("No ID or label informed for volume [%s].", volPath));
|
LOGGER.debug(String.format("No ID or label informed for volume [%s].", volPath));
|
||||||
defISODisk(volPath);
|
defISODisk(volPath, diskType);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_diskType = DiskType.FILE;
|
_diskType = diskType;
|
||||||
_deviceType = DeviceType.CDROM;
|
_deviceType = DeviceType.CDROM;
|
||||||
_sourcePath = volPath;
|
_sourcePath = volPath;
|
||||||
|
|
||||||
|
|
@ -942,11 +942,11 @@ public class LibvirtVMDef {
|
||||||
_bus = DiskBus.IDE;
|
_bus = DiskBus.IDE;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void defISODisk(String volPath, Integer devId,boolean isSecure) {
|
public void defISODisk(String volPath, Integer devId, boolean isSecure, DiskType diskType) {
|
||||||
if (!isSecure) {
|
if (!isSecure) {
|
||||||
defISODisk(volPath, devId);
|
defISODisk(volPath, devId, diskType);
|
||||||
} else {
|
} else {
|
||||||
_diskType = DiskType.FILE;
|
_diskType = diskType;
|
||||||
_deviceType = DeviceType.CDROM;
|
_deviceType = DeviceType.CDROM;
|
||||||
_sourcePath = volPath;
|
_sourcePath = volPath;
|
||||||
_diskLabel = getDevLabel(devId, DiskBus.SATA, true);
|
_diskLabel = getDevLabel(devId, DiskBus.SATA, true);
|
||||||
|
|
|
||||||
|
|
@ -130,34 +130,25 @@ public class LibvirtConvertInstanceCommandWrapper extends CommandWrapper<Convert
|
||||||
final String temporaryConvertUuid = UUID.randomUUID().toString();
|
final String temporaryConvertUuid = UUID.randomUUID().toString();
|
||||||
boolean verboseModeEnabled = serverResource.isConvertInstanceVerboseModeEnabled();
|
boolean verboseModeEnabled = serverResource.isConvertInstanceVerboseModeEnabled();
|
||||||
|
|
||||||
|
boolean cleanupSecondaryStorage = false;
|
||||||
try {
|
try {
|
||||||
boolean result = performInstanceConversion(sourceOVFDirPath, temporaryConvertPath, temporaryConvertUuid,
|
boolean result = performInstanceConversion(sourceOVFDirPath, temporaryConvertPath, temporaryConvertUuid,
|
||||||
timeout, verboseModeEnabled);
|
timeout, verboseModeEnabled);
|
||||||
if (!result) {
|
if (!result) {
|
||||||
String err = String.format("The virt-v2v conversion for the OVF %s failed. " +
|
String err = String.format(
|
||||||
"Please check the agent logs for the virt-v2v output", ovfTemplateDirOnConversionLocation);
|
"The virt-v2v conversion for the OVF %s failed. Please check the agent logs " +
|
||||||
|
"for the virt-v2v output. Please try on a different kvm host which " +
|
||||||
|
"has a different virt-v2v version.",
|
||||||
|
ovfTemplateDirOnConversionLocation);
|
||||||
logger.error(err);
|
logger.error(err);
|
||||||
return new ConvertInstanceAnswer(cmd, false, err);
|
return new ConvertInstanceAnswer(cmd, false, err);
|
||||||
}
|
}
|
||||||
String convertedBasePath = String.format("%s/%s", temporaryConvertPath, temporaryConvertUuid);
|
return new ConvertInstanceAnswer(cmd, temporaryConvertUuid);
|
||||||
LibvirtDomainXMLParser xmlParser = parseMigratedVMXmlDomain(convertedBasePath);
|
|
||||||
|
|
||||||
List<KVMPhysicalDisk> temporaryDisks = xmlParser == null ?
|
|
||||||
getTemporaryDisksWithPrefixFromTemporaryPool(temporaryStoragePool, temporaryConvertPath, temporaryConvertUuid) :
|
|
||||||
getTemporaryDisksFromParsedXml(temporaryStoragePool, xmlParser, convertedBasePath);
|
|
||||||
|
|
||||||
List<KVMPhysicalDisk> destinationDisks = moveTemporaryDisksToDestination(temporaryDisks,
|
|
||||||
destinationStoragePools, storagePoolMgr);
|
|
||||||
|
|
||||||
cleanupDisksAndDomainFromTemporaryLocation(temporaryDisks, temporaryStoragePool, temporaryConvertUuid);
|
|
||||||
|
|
||||||
UnmanagedInstanceTO convertedInstanceTO = getConvertedUnmanagedInstance(temporaryConvertUuid,
|
|
||||||
destinationDisks, xmlParser);
|
|
||||||
return new ConvertInstanceAnswer(cmd, convertedInstanceTO);
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
String error = String.format("Error converting instance %s from %s, due to: %s",
|
String error = String.format("Error converting instance %s from %s, due to: %s",
|
||||||
sourceInstanceName, sourceHypervisorType, e.getMessage());
|
sourceInstanceName, sourceHypervisorType, e.getMessage());
|
||||||
logger.error(error, e);
|
logger.error(error, e);
|
||||||
|
cleanupSecondaryStorage = true;
|
||||||
return new ConvertInstanceAnswer(cmd, false, error);
|
return new ConvertInstanceAnswer(cmd, false, error);
|
||||||
} finally {
|
} finally {
|
||||||
if (ovfExported && StringUtils.isNotBlank(ovfTemplateDirOnConversionLocation)) {
|
if (ovfExported && StringUtils.isNotBlank(ovfTemplateDirOnConversionLocation)) {
|
||||||
|
|
@ -165,7 +156,7 @@ public class LibvirtConvertInstanceCommandWrapper extends CommandWrapper<Convert
|
||||||
logger.debug("Cleaning up exported OVA at dir " + sourceOVFDir);
|
logger.debug("Cleaning up exported OVA at dir " + sourceOVFDir);
|
||||||
FileUtil.deletePath(sourceOVFDir);
|
FileUtil.deletePath(sourceOVFDir);
|
||||||
}
|
}
|
||||||
if (conversionTemporaryLocation instanceof NfsTO) {
|
if (cleanupSecondaryStorage && conversionTemporaryLocation instanceof NfsTO) {
|
||||||
logger.debug("Cleaning up secondary storage temporary location");
|
logger.debug("Cleaning up secondary storage temporary location");
|
||||||
storagePoolMgr.deleteStoragePool(temporaryStoragePool.getType(), temporaryStoragePool.getUuid());
|
storagePoolMgr.deleteStoragePool(temporaryStoragePool.getType(), temporaryStoragePool.getUuid());
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,299 @@
|
||||||
|
//
|
||||||
|
// 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.hypervisor.kvm.resource.wrapper;
|
||||||
|
|
||||||
|
import java.io.BufferedInputStream;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import org.apache.cloudstack.storage.to.PrimaryDataStoreTO;
|
||||||
|
import org.apache.cloudstack.vm.UnmanagedInstanceTO;
|
||||||
|
import org.apache.commons.collections.CollectionUtils;
|
||||||
|
import org.apache.commons.io.IOUtils;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
|
import com.cloud.agent.api.Answer;
|
||||||
|
import com.cloud.agent.api.ImportConvertedInstanceAnswer;
|
||||||
|
import com.cloud.agent.api.ImportConvertedInstanceCommand;
|
||||||
|
import com.cloud.agent.api.to.DataStoreTO;
|
||||||
|
import com.cloud.agent.api.to.NfsTO;
|
||||||
|
import com.cloud.agent.api.to.RemoteInstanceTO;
|
||||||
|
import com.cloud.hypervisor.Hypervisor;
|
||||||
|
import com.cloud.hypervisor.kvm.resource.LibvirtComputingResource;
|
||||||
|
import com.cloud.hypervisor.kvm.resource.LibvirtDomainXMLParser;
|
||||||
|
import com.cloud.hypervisor.kvm.resource.LibvirtVMDef;
|
||||||
|
import com.cloud.hypervisor.kvm.storage.KVMPhysicalDisk;
|
||||||
|
import com.cloud.hypervisor.kvm.storage.KVMStoragePool;
|
||||||
|
import com.cloud.hypervisor.kvm.storage.KVMStoragePoolManager;
|
||||||
|
import com.cloud.resource.CommandWrapper;
|
||||||
|
import com.cloud.resource.ResourceWrapper;
|
||||||
|
import com.cloud.storage.Storage;
|
||||||
|
import com.cloud.utils.FileUtil;
|
||||||
|
import com.cloud.utils.Pair;
|
||||||
|
import com.cloud.utils.exception.CloudRuntimeException;
|
||||||
|
import com.cloud.utils.script.Script;
|
||||||
|
|
||||||
|
@ResourceWrapper(handles = ImportConvertedInstanceCommand.class)
|
||||||
|
public class LibvirtImportConvertedInstanceCommandWrapper extends CommandWrapper<ImportConvertedInstanceCommand, Answer, LibvirtComputingResource> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Answer execute(ImportConvertedInstanceCommand cmd, LibvirtComputingResource serverResource) {
|
||||||
|
RemoteInstanceTO sourceInstance = cmd.getSourceInstance();
|
||||||
|
Hypervisor.HypervisorType sourceHypervisorType = sourceInstance.getHypervisorType();
|
||||||
|
String sourceInstanceName = sourceInstance.getInstanceName();
|
||||||
|
List<String> destinationStoragePools = cmd.getDestinationStoragePools();
|
||||||
|
DataStoreTO conversionTemporaryLocation = cmd.getConversionTemporaryLocation();
|
||||||
|
final String temporaryConvertUuid = cmd.getTemporaryConvertUuid();
|
||||||
|
|
||||||
|
final KVMStoragePoolManager storagePoolMgr = serverResource.getStoragePoolMgr();
|
||||||
|
KVMStoragePool temporaryStoragePool = getTemporaryStoragePool(conversionTemporaryLocation, storagePoolMgr);
|
||||||
|
final String temporaryConvertPath = temporaryStoragePool.getLocalPath();
|
||||||
|
|
||||||
|
try {
|
||||||
|
String convertedBasePath = String.format("%s/%s", temporaryConvertPath, temporaryConvertUuid);
|
||||||
|
LibvirtDomainXMLParser xmlParser = parseMigratedVMXmlDomain(convertedBasePath);
|
||||||
|
|
||||||
|
List<KVMPhysicalDisk> temporaryDisks = xmlParser == null ?
|
||||||
|
getTemporaryDisksWithPrefixFromTemporaryPool(temporaryStoragePool, temporaryConvertPath, temporaryConvertUuid) :
|
||||||
|
getTemporaryDisksFromParsedXml(temporaryStoragePool, xmlParser, convertedBasePath);
|
||||||
|
|
||||||
|
List<KVMPhysicalDisk> destinationDisks = moveTemporaryDisksToDestination(temporaryDisks,
|
||||||
|
destinationStoragePools, storagePoolMgr);
|
||||||
|
|
||||||
|
cleanupDisksAndDomainFromTemporaryLocation(temporaryDisks, temporaryStoragePool, temporaryConvertUuid);
|
||||||
|
|
||||||
|
UnmanagedInstanceTO convertedInstanceTO = getConvertedUnmanagedInstance(temporaryConvertUuid,
|
||||||
|
destinationDisks, xmlParser);
|
||||||
|
return new ImportConvertedInstanceAnswer(cmd, convertedInstanceTO);
|
||||||
|
} catch (Exception e) {
|
||||||
|
String error = String.format("Error converting instance %s from %s, due to: %s",
|
||||||
|
sourceInstanceName, sourceHypervisorType, e.getMessage());
|
||||||
|
logger.error(error, e);
|
||||||
|
return new ImportConvertedInstanceAnswer(cmd, false, error);
|
||||||
|
} finally {
|
||||||
|
if (conversionTemporaryLocation instanceof NfsTO) {
|
||||||
|
logger.debug("Cleaning up secondary storage temporary location");
|
||||||
|
storagePoolMgr.deleteStoragePool(temporaryStoragePool.getType(), temporaryStoragePool.getUuid());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected KVMStoragePool getTemporaryStoragePool(DataStoreTO conversionTemporaryLocation, KVMStoragePoolManager storagePoolMgr) {
|
||||||
|
if (conversionTemporaryLocation instanceof NfsTO) {
|
||||||
|
NfsTO nfsTO = (NfsTO) conversionTemporaryLocation;
|
||||||
|
return storagePoolMgr.getStoragePoolByURI(nfsTO.getUrl());
|
||||||
|
} else {
|
||||||
|
PrimaryDataStoreTO primaryDataStoreTO = (PrimaryDataStoreTO) conversionTemporaryLocation;
|
||||||
|
return storagePoolMgr.getStoragePool(primaryDataStoreTO.getPoolType(), primaryDataStoreTO.getUuid());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected List<KVMPhysicalDisk> getTemporaryDisksFromParsedXml(KVMStoragePool pool, LibvirtDomainXMLParser xmlParser, String convertedBasePath) {
|
||||||
|
List<LibvirtVMDef.DiskDef> disksDefs = xmlParser.getDisks();
|
||||||
|
disksDefs = disksDefs.stream().filter(x -> x.getDiskType() == LibvirtVMDef.DiskDef.DiskType.FILE &&
|
||||||
|
x.getDeviceType() == LibvirtVMDef.DiskDef.DeviceType.DISK).collect(Collectors.toList());
|
||||||
|
if (CollectionUtils.isEmpty(disksDefs)) {
|
||||||
|
String err = String.format("Cannot find any disk defined on the converted XML domain %s.xml", convertedBasePath);
|
||||||
|
logger.error(err);
|
||||||
|
throw new CloudRuntimeException(err);
|
||||||
|
}
|
||||||
|
sanitizeDisksPath(disksDefs);
|
||||||
|
return getPhysicalDisksFromDefPaths(disksDefs, pool);
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<KVMPhysicalDisk> getPhysicalDisksFromDefPaths(List<LibvirtVMDef.DiskDef> disksDefs, KVMStoragePool pool) {
|
||||||
|
List<KVMPhysicalDisk> disks = new ArrayList<>();
|
||||||
|
for (LibvirtVMDef.DiskDef diskDef : disksDefs) {
|
||||||
|
KVMPhysicalDisk physicalDisk = pool.getPhysicalDisk(diskDef.getDiskPath());
|
||||||
|
disks.add(physicalDisk);
|
||||||
|
}
|
||||||
|
return disks;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected List<KVMPhysicalDisk> getTemporaryDisksWithPrefixFromTemporaryPool(KVMStoragePool pool, String path, String prefix) {
|
||||||
|
String msg = String.format("Could not parse correctly the converted XML domain, checking for disks on %s with prefix %s", path, prefix);
|
||||||
|
logger.info(msg);
|
||||||
|
pool.refresh();
|
||||||
|
List<KVMPhysicalDisk> disksWithPrefix = pool.listPhysicalDisks()
|
||||||
|
.stream()
|
||||||
|
.filter(x -> x.getName().startsWith(prefix) && !x.getName().endsWith(".xml"))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
if (CollectionUtils.isEmpty(disksWithPrefix)) {
|
||||||
|
msg = String.format("Could not find any converted disk with prefix %s on temporary location %s", prefix, path);
|
||||||
|
logger.error(msg);
|
||||||
|
throw new CloudRuntimeException(msg);
|
||||||
|
}
|
||||||
|
return disksWithPrefix;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void cleanupDisksAndDomainFromTemporaryLocation(List<KVMPhysicalDisk> disks,
|
||||||
|
KVMStoragePool temporaryStoragePool,
|
||||||
|
String temporaryConvertUuid) {
|
||||||
|
for (KVMPhysicalDisk disk : disks) {
|
||||||
|
logger.info(String.format("Cleaning up temporary disk %s after conversion from temporary location", disk.getName()));
|
||||||
|
temporaryStoragePool.deletePhysicalDisk(disk.getName(), Storage.ImageFormat.QCOW2);
|
||||||
|
}
|
||||||
|
logger.info(String.format("Cleaning up temporary domain %s after conversion from temporary location", temporaryConvertUuid));
|
||||||
|
FileUtil.deleteFiles(temporaryStoragePool.getLocalPath(), temporaryConvertUuid, ".xml");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void sanitizeDisksPath(List<LibvirtVMDef.DiskDef> disks) {
|
||||||
|
for (LibvirtVMDef.DiskDef disk : disks) {
|
||||||
|
String[] diskPathParts = disk.getDiskPath().split("/");
|
||||||
|
String relativePath = diskPathParts[diskPathParts.length - 1];
|
||||||
|
disk.setDiskPath(relativePath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected List<KVMPhysicalDisk> moveTemporaryDisksToDestination(List<KVMPhysicalDisk> temporaryDisks,
|
||||||
|
List<String> destinationStoragePools,
|
||||||
|
KVMStoragePoolManager storagePoolMgr) {
|
||||||
|
List<KVMPhysicalDisk> targetDisks = new ArrayList<>();
|
||||||
|
if (temporaryDisks.size() != destinationStoragePools.size()) {
|
||||||
|
String warn = String.format("Discrepancy between the converted instance disks (%s) " +
|
||||||
|
"and the expected number of disks (%s)", temporaryDisks.size(), destinationStoragePools.size());
|
||||||
|
logger.warn(warn);
|
||||||
|
}
|
||||||
|
for (int i = 0; i < temporaryDisks.size(); i++) {
|
||||||
|
String poolPath = destinationStoragePools.get(i);
|
||||||
|
KVMStoragePool destinationPool = storagePoolMgr.getStoragePool(Storage.StoragePoolType.NetworkFilesystem, poolPath);
|
||||||
|
if (destinationPool == null) {
|
||||||
|
String err = String.format("Could not find a storage pool by URI: %s", poolPath);
|
||||||
|
logger.error(err);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (destinationPool.getType() != Storage.StoragePoolType.NetworkFilesystem) {
|
||||||
|
String err = String.format("Storage pool by URI: %s is not an NFS storage", poolPath);
|
||||||
|
logger.error(err);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
KVMPhysicalDisk sourceDisk = temporaryDisks.get(i);
|
||||||
|
if (logger.isDebugEnabled()) {
|
||||||
|
String msg = String.format("Trying to copy converted instance disk number %s from the temporary location %s" +
|
||||||
|
" to destination storage pool %s", i, sourceDisk.getPool().getLocalPath(), destinationPool.getUuid());
|
||||||
|
logger.debug(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
String destinationName = UUID.randomUUID().toString();
|
||||||
|
|
||||||
|
KVMPhysicalDisk destinationDisk = storagePoolMgr.copyPhysicalDisk(sourceDisk, destinationName, destinationPool, 7200 * 1000);
|
||||||
|
targetDisks.add(destinationDisk);
|
||||||
|
}
|
||||||
|
return targetDisks;
|
||||||
|
}
|
||||||
|
|
||||||
|
private UnmanagedInstanceTO getConvertedUnmanagedInstance(String baseName,
|
||||||
|
List<KVMPhysicalDisk> vmDisks,
|
||||||
|
LibvirtDomainXMLParser xmlParser) {
|
||||||
|
UnmanagedInstanceTO instanceTO = new UnmanagedInstanceTO();
|
||||||
|
instanceTO.setName(baseName);
|
||||||
|
instanceTO.setDisks(getUnmanagedInstanceDisks(vmDisks, xmlParser));
|
||||||
|
instanceTO.setNics(getUnmanagedInstanceNics(xmlParser));
|
||||||
|
return instanceTO;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<UnmanagedInstanceTO.Nic> getUnmanagedInstanceNics(LibvirtDomainXMLParser xmlParser) {
|
||||||
|
List<UnmanagedInstanceTO.Nic> nics = new ArrayList<>();
|
||||||
|
if (xmlParser != null) {
|
||||||
|
List<LibvirtVMDef.InterfaceDef> interfaces = xmlParser.getInterfaces();
|
||||||
|
for (LibvirtVMDef.InterfaceDef interfaceDef : interfaces) {
|
||||||
|
UnmanagedInstanceTO.Nic nic = new UnmanagedInstanceTO.Nic();
|
||||||
|
nic.setMacAddress(interfaceDef.getMacAddress());
|
||||||
|
nic.setNicId(interfaceDef.getBrName());
|
||||||
|
nic.setAdapterType(interfaceDef.getModel().toString());
|
||||||
|
nics.add(nic);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nics;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected List<UnmanagedInstanceTO.Disk> getUnmanagedInstanceDisks(List<KVMPhysicalDisk> vmDisks, LibvirtDomainXMLParser xmlParser) {
|
||||||
|
List<UnmanagedInstanceTO.Disk> instanceDisks = new ArrayList<>();
|
||||||
|
List<LibvirtVMDef.DiskDef> diskDefs = xmlParser != null ? xmlParser.getDisks() : null;
|
||||||
|
for (int i = 0; i< vmDisks.size(); i++) {
|
||||||
|
KVMPhysicalDisk physicalDisk = vmDisks.get(i);
|
||||||
|
KVMStoragePool storagePool = physicalDisk.getPool();
|
||||||
|
UnmanagedInstanceTO.Disk disk = new UnmanagedInstanceTO.Disk();
|
||||||
|
disk.setPosition(i);
|
||||||
|
Pair<String, String> storagePoolHostAndPath = getNfsStoragePoolHostAndPath(storagePool);
|
||||||
|
disk.setDatastoreHost(storagePoolHostAndPath.first());
|
||||||
|
disk.setDatastorePath(storagePoolHostAndPath.second());
|
||||||
|
disk.setDatastoreName(storagePool.getUuid());
|
||||||
|
disk.setDatastoreType(storagePool.getType().name());
|
||||||
|
disk.setCapacity(physicalDisk.getVirtualSize());
|
||||||
|
disk.setFileBaseName(physicalDisk.getName());
|
||||||
|
if (CollectionUtils.isNotEmpty(diskDefs)) {
|
||||||
|
LibvirtVMDef.DiskDef diskDef = diskDefs.get(i);
|
||||||
|
disk.setController(diskDef.getBusType() != null ? diskDef.getBusType().toString() : LibvirtVMDef.DiskDef.DiskBus.VIRTIO.toString());
|
||||||
|
} else {
|
||||||
|
// If the job is finished but we cannot parse the XML, the guest VM can use the virtio driver
|
||||||
|
disk.setController(LibvirtVMDef.DiskDef.DiskBus.VIRTIO.toString());
|
||||||
|
}
|
||||||
|
instanceDisks.add(disk);
|
||||||
|
}
|
||||||
|
return instanceDisks;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Pair<String, String> getNfsStoragePoolHostAndPath(KVMStoragePool storagePool) {
|
||||||
|
String sourceHostIp = null;
|
||||||
|
String sourcePath = null;
|
||||||
|
List<String[]> commands = new ArrayList<>();
|
||||||
|
commands.add(new String[]{Script.getExecutableAbsolutePath("mount")});
|
||||||
|
commands.add(new String[]{Script.getExecutableAbsolutePath("grep"), storagePool.getLocalPath()});
|
||||||
|
String storagePoolMountPoint = Script.executePipedCommands(commands, 0).second();
|
||||||
|
logger.debug(String.format("NFS Storage pool: %s - local path: %s, mount point: %s", storagePool.getUuid(), storagePool.getLocalPath(), storagePoolMountPoint));
|
||||||
|
if (StringUtils.isNotEmpty(storagePoolMountPoint)) {
|
||||||
|
String[] res = storagePoolMountPoint.strip().split(" ");
|
||||||
|
res = res[0].split(":");
|
||||||
|
if (res.length > 1) {
|
||||||
|
sourceHostIp = res[0].strip();
|
||||||
|
sourcePath = res[1].strip();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new Pair<>(sourceHostIp, sourcePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected LibvirtDomainXMLParser parseMigratedVMXmlDomain(String installPath) throws IOException {
|
||||||
|
String xmlPath = String.format("%s.xml", installPath);
|
||||||
|
if (!new File(xmlPath).exists()) {
|
||||||
|
String err = String.format("Conversion failed. Unable to find the converted XML domain, expected %s", xmlPath);
|
||||||
|
logger.error(err);
|
||||||
|
throw new CloudRuntimeException(err);
|
||||||
|
}
|
||||||
|
InputStream is = new BufferedInputStream(new FileInputStream(xmlPath));
|
||||||
|
String xml = IOUtils.toString(is, Charset.defaultCharset());
|
||||||
|
final LibvirtDomainXMLParser parser = new LibvirtDomainXMLParser();
|
||||||
|
try {
|
||||||
|
parser.parseDomainXML(xml);
|
||||||
|
return parser;
|
||||||
|
} catch (RuntimeException e) {
|
||||||
|
String err = String.format("Error parsing the converted instance XML domain at %s: %s", xmlPath, e.getMessage());
|
||||||
|
logger.error(err, e);
|
||||||
|
logger.debug(xml);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1119,11 +1119,12 @@ public class KVMStorageProcessor implements StorageProcessor {
|
||||||
storagePool = storagePoolMgr.getStoragePoolByURI(path);
|
storagePool = storagePoolMgr.getStoragePoolByURI(path);
|
||||||
}
|
}
|
||||||
final KVMPhysicalDisk isoVol = storagePool.getPhysicalDisk(name);
|
final KVMPhysicalDisk isoVol = storagePool.getPhysicalDisk(name);
|
||||||
|
final DiskDef.DiskType isoDiskType = LibvirtComputingResource.getDiskType(isoVol);
|
||||||
isoPath = isoVol.getPath();
|
isoPath = isoVol.getPath();
|
||||||
|
|
||||||
iso.defISODisk(isoPath, isUefiEnabled);
|
iso.defISODisk(isoPath, isUefiEnabled, isoDiskType);
|
||||||
} else {
|
} else {
|
||||||
iso.defISODisk(null, isUefiEnabled);
|
iso.defISODisk(null, isUefiEnabled, DiskDef.DiskType.FILE);
|
||||||
}
|
}
|
||||||
|
|
||||||
final List<DiskDef> disks = resource.getDisks(conn, vmName);
|
final List<DiskDef> disks = resource.getDisks(conn, vmName);
|
||||||
|
|
|
||||||
|
|
@ -173,7 +173,7 @@ public class LibvirtStorageAdaptor implements StorageAdaptor {
|
||||||
* Checks if downloaded template is extractable
|
* Checks if downloaded template is extractable
|
||||||
* @return true if it should be extracted, false if not
|
* @return true if it should be extracted, false if not
|
||||||
*/
|
*/
|
||||||
private boolean isTemplateExtractable(String templatePath) {
|
public static boolean isTemplateExtractable(String templatePath) {
|
||||||
String type = Script.runSimpleBashScript("file " + templatePath + " | awk -F' ' '{print $2}'");
|
String type = Script.runSimpleBashScript("file " + templatePath + " | awk -F' ' '{print $2}'");
|
||||||
return type.equalsIgnoreCase("bzip2") || type.equalsIgnoreCase("gzip") || type.equalsIgnoreCase("zip");
|
return type.equalsIgnoreCase("bzip2") || type.equalsIgnoreCase("gzip") || type.equalsIgnoreCase("zip");
|
||||||
}
|
}
|
||||||
|
|
@ -183,7 +183,7 @@ public class LibvirtStorageAdaptor implements StorageAdaptor {
|
||||||
* @param downloadedTemplateFile
|
* @param downloadedTemplateFile
|
||||||
* @param templateUuid
|
* @param templateUuid
|
||||||
*/
|
*/
|
||||||
private String getExtractCommandForDownloadedFile(String downloadedTemplateFile, String templateUuid) {
|
public static String getExtractCommandForDownloadedFile(String downloadedTemplateFile, String templateUuid) {
|
||||||
if (downloadedTemplateFile.endsWith(".zip")) {
|
if (downloadedTemplateFile.endsWith(".zip")) {
|
||||||
return "unzip -p " + downloadedTemplateFile + " | cat > " + templateUuid;
|
return "unzip -p " + downloadedTemplateFile + " | cat > " + templateUuid;
|
||||||
} else if (downloadedTemplateFile.endsWith(".bz2")) {
|
} else if (downloadedTemplateFile.endsWith(".bz2")) {
|
||||||
|
|
@ -198,7 +198,7 @@ public class LibvirtStorageAdaptor implements StorageAdaptor {
|
||||||
/**
|
/**
|
||||||
* Extract downloaded template into installPath, remove compressed file
|
* Extract downloaded template into installPath, remove compressed file
|
||||||
*/
|
*/
|
||||||
private void extractDownloadedTemplate(String downloadedTemplateFile, KVMStoragePool destPool, String destinationFile) {
|
public static void extractDownloadedTemplate(String downloadedTemplateFile, KVMStoragePool destPool, String destinationFile) {
|
||||||
String extractCommand = getExtractCommandForDownloadedFile(downloadedTemplateFile, destinationFile);
|
String extractCommand = getExtractCommandForDownloadedFile(downloadedTemplateFile, destinationFile);
|
||||||
Script.runSimpleBashScript(extractCommand);
|
Script.runSimpleBashScript(extractCommand);
|
||||||
Script.runSimpleBashScript("rm -f " + downloadedTemplateFile);
|
Script.runSimpleBashScript("rm -f " + downloadedTemplateFile);
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,6 @@
|
||||||
//
|
//
|
||||||
package com.cloud.hypervisor.kvm.resource.wrapper;
|
package com.cloud.hypervisor.kvm.resource.wrapper;
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
|
|
@ -80,7 +79,6 @@ public class LibvirtConvertInstanceCommandWrapperTest {
|
||||||
Mockito.when(storagePoolManager.getStoragePoolByURI(secondaryPoolUrl)).thenReturn(temporaryPool);
|
Mockito.when(storagePoolManager.getStoragePoolByURI(secondaryPoolUrl)).thenReturn(temporaryPool);
|
||||||
KVMPhysicalDisk physicalDisk1 = Mockito.mock(KVMPhysicalDisk.class);
|
KVMPhysicalDisk physicalDisk1 = Mockito.mock(KVMPhysicalDisk.class);
|
||||||
KVMPhysicalDisk physicalDisk2 = Mockito.mock(KVMPhysicalDisk.class);
|
KVMPhysicalDisk physicalDisk2 = Mockito.mock(KVMPhysicalDisk.class);
|
||||||
Mockito.when(temporaryPool.listPhysicalDisks()).thenReturn(Arrays.asList(physicalDisk1, physicalDisk2));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -107,51 +105,6 @@ public class LibvirtConvertInstanceCommandWrapperTest {
|
||||||
Assert.assertNotNull(temporaryStoragePool);
|
Assert.assertNotNull(temporaryStoragePool);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testGetTemporaryDisksWithPrefixFromTemporaryPool() {
|
|
||||||
String convertPath = "/xyz";
|
|
||||||
String convertPrefix = UUID.randomUUID().toString();
|
|
||||||
KVMPhysicalDisk physicalDisk1 = Mockito.mock(KVMPhysicalDisk.class);
|
|
||||||
Mockito.when(physicalDisk1.getName()).thenReturn("disk1");
|
|
||||||
KVMPhysicalDisk physicalDisk2 = Mockito.mock(KVMPhysicalDisk.class);
|
|
||||||
Mockito.when(physicalDisk2.getName()).thenReturn("disk2");
|
|
||||||
|
|
||||||
KVMPhysicalDisk convertedDisk1 = Mockito.mock(KVMPhysicalDisk.class);
|
|
||||||
Mockito.when(convertedDisk1.getName()).thenReturn(String.format("%s-sda", convertPrefix));
|
|
||||||
KVMPhysicalDisk convertedDisk2 = Mockito.mock(KVMPhysicalDisk.class);
|
|
||||||
Mockito.when(convertedDisk2.getName()).thenReturn(String.format("%s-sdb", convertPrefix));
|
|
||||||
KVMPhysicalDisk convertedXml = Mockito.mock(KVMPhysicalDisk.class);
|
|
||||||
Mockito.when(convertedXml.getName()).thenReturn(String.format("%s.xml", convertPrefix));
|
|
||||||
Mockito.when(temporaryPool.listPhysicalDisks()).thenReturn(Arrays.asList(physicalDisk1, physicalDisk2,
|
|
||||||
convertedDisk1, convertedDisk2, convertedXml));
|
|
||||||
|
|
||||||
List<KVMPhysicalDisk> convertedDisks = convertInstanceCommandWrapper.getTemporaryDisksWithPrefixFromTemporaryPool(temporaryPool, convertPath, convertPrefix);
|
|
||||||
Assert.assertEquals(2, convertedDisks.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testGetTemporaryDisksFromParsedXml() {
|
|
||||||
String relativePath = UUID.randomUUID().toString();
|
|
||||||
String fullPath = String.format("/mnt/xyz/%s", relativePath);
|
|
||||||
|
|
||||||
LibvirtVMDef.DiskDef diskDef = new LibvirtVMDef.DiskDef();
|
|
||||||
LibvirtVMDef.DiskDef.DiskBus bus = LibvirtVMDef.DiskDef.DiskBus.VIRTIO;
|
|
||||||
LibvirtVMDef.DiskDef.DiskFmtType type = LibvirtVMDef.DiskDef.DiskFmtType.QCOW2;
|
|
||||||
diskDef.defFileBasedDisk(fullPath, "test", bus, type);
|
|
||||||
|
|
||||||
LibvirtDomainXMLParser parser = Mockito.mock(LibvirtDomainXMLParser.class);
|
|
||||||
Mockito.when(parser.getDisks()).thenReturn(List.of(diskDef));
|
|
||||||
|
|
||||||
KVMPhysicalDisk convertedDisk1 = Mockito.mock(KVMPhysicalDisk.class);
|
|
||||||
Mockito.when(convertedDisk1.getName()).thenReturn("disk1");
|
|
||||||
Mockito.when(temporaryPool.getPhysicalDisk(relativePath)).thenReturn(convertedDisk1);
|
|
||||||
|
|
||||||
List<KVMPhysicalDisk> disks = convertInstanceCommandWrapper.getTemporaryDisksFromParsedXml(temporaryPool, parser, "");
|
|
||||||
Mockito.verify(convertInstanceCommandWrapper).sanitizeDisksPath(List.of(diskDef));
|
|
||||||
Assert.assertEquals(1, disks.size());
|
|
||||||
Assert.assertEquals("disk1", disks.get(0).getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSanitizeDisksPath() {
|
public void testSanitizeDisksPath() {
|
||||||
String relativePath = UUID.randomUUID().toString();
|
String relativePath = UUID.randomUUID().toString();
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,245 @@
|
||||||
|
//
|
||||||
|
// 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.hypervisor.kvm.resource.wrapper;
|
||||||
|
|
||||||
|
import com.cloud.agent.api.Answer;
|
||||||
|
import com.cloud.agent.api.ImportConvertedInstanceCommand;
|
||||||
|
import com.cloud.agent.api.to.NfsTO;
|
||||||
|
import com.cloud.agent.api.to.RemoteInstanceTO;
|
||||||
|
import com.cloud.hypervisor.Hypervisor;
|
||||||
|
import com.cloud.hypervisor.kvm.resource.LibvirtComputingResource;
|
||||||
|
import com.cloud.hypervisor.kvm.resource.LibvirtDomainXMLParser;
|
||||||
|
import com.cloud.hypervisor.kvm.resource.LibvirtVMDef;
|
||||||
|
import com.cloud.hypervisor.kvm.storage.KVMPhysicalDisk;
|
||||||
|
import com.cloud.hypervisor.kvm.storage.KVMStoragePool;
|
||||||
|
import com.cloud.hypervisor.kvm.storage.KVMStoragePoolManager;
|
||||||
|
import com.cloud.storage.Storage;
|
||||||
|
import com.cloud.utils.Pair;
|
||||||
|
import com.cloud.utils.script.Script;
|
||||||
|
import org.apache.cloudstack.storage.to.PrimaryDataStoreTO;
|
||||||
|
import org.apache.cloudstack.vm.UnmanagedInstanceTO;
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.MockedStatic;
|
||||||
|
import org.mockito.Mockito;
|
||||||
|
import org.mockito.Spy;
|
||||||
|
import org.mockito.junit.MockitoJUnitRunner;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
@RunWith(MockitoJUnitRunner.class)
|
||||||
|
public class LibvirtImportConvertedInstanceCommandWrapperTest {
|
||||||
|
|
||||||
|
@Spy
|
||||||
|
private LibvirtImportConvertedInstanceCommandWrapper importInstanceCommandWrapper =
|
||||||
|
Mockito.spy(LibvirtImportConvertedInstanceCommandWrapper.class);
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private LibvirtComputingResource libvirtComputingResourceMock;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private KVMStoragePool temporaryPool;
|
||||||
|
@Mock
|
||||||
|
private KVMStoragePool destinationPool;
|
||||||
|
@Mock
|
||||||
|
private PrimaryDataStoreTO primaryDataStore;
|
||||||
|
@Mock
|
||||||
|
private NfsTO secondaryDataStore;
|
||||||
|
@Mock
|
||||||
|
private KVMStoragePoolManager storagePoolManager;
|
||||||
|
|
||||||
|
private static final String secondaryPoolUrl = "nfs://192.168.1.1/secondary";
|
||||||
|
private static final String vmName = "VmToImport";
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() {
|
||||||
|
Mockito.when(secondaryDataStore.getUrl()).thenReturn(secondaryPoolUrl);
|
||||||
|
Mockito.when(libvirtComputingResourceMock.getStoragePoolMgr()).thenReturn(storagePoolManager);
|
||||||
|
Mockito.when(storagePoolManager.getStoragePoolByURI(secondaryPoolUrl)).thenReturn(temporaryPool);
|
||||||
|
KVMPhysicalDisk physicalDisk1 = Mockito.mock(KVMPhysicalDisk.class);
|
||||||
|
KVMPhysicalDisk physicalDisk2 = Mockito.mock(KVMPhysicalDisk.class);
|
||||||
|
Mockito.when(temporaryPool.listPhysicalDisks()).thenReturn(Arrays.asList(physicalDisk1, physicalDisk2));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetTemporaryStoragePool() {
|
||||||
|
KVMStoragePool temporaryStoragePool = importInstanceCommandWrapper.getTemporaryStoragePool(secondaryDataStore, libvirtComputingResourceMock.getStoragePoolMgr());
|
||||||
|
Assert.assertNotNull(temporaryStoragePool);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetTemporaryDisksWithPrefixFromTemporaryPool() {
|
||||||
|
String convertPath = "/xyz";
|
||||||
|
String convertPrefix = UUID.randomUUID().toString();
|
||||||
|
KVMPhysicalDisk physicalDisk1 = Mockito.mock(KVMPhysicalDisk.class);
|
||||||
|
Mockito.when(physicalDisk1.getName()).thenReturn("disk1");
|
||||||
|
KVMPhysicalDisk physicalDisk2 = Mockito.mock(KVMPhysicalDisk.class);
|
||||||
|
Mockito.when(physicalDisk2.getName()).thenReturn("disk2");
|
||||||
|
|
||||||
|
KVMPhysicalDisk convertedDisk1 = Mockito.mock(KVMPhysicalDisk.class);
|
||||||
|
Mockito.when(convertedDisk1.getName()).thenReturn(String.format("%s-sda", convertPrefix));
|
||||||
|
KVMPhysicalDisk convertedDisk2 = Mockito.mock(KVMPhysicalDisk.class);
|
||||||
|
Mockito.when(convertedDisk2.getName()).thenReturn(String.format("%s-sdb", convertPrefix));
|
||||||
|
KVMPhysicalDisk convertedXml = Mockito.mock(KVMPhysicalDisk.class);
|
||||||
|
Mockito.when(convertedXml.getName()).thenReturn(String.format("%s.xml", convertPrefix));
|
||||||
|
Mockito.when(temporaryPool.listPhysicalDisks()).thenReturn(Arrays.asList(physicalDisk1, physicalDisk2,
|
||||||
|
convertedDisk1, convertedDisk2, convertedXml));
|
||||||
|
|
||||||
|
List<KVMPhysicalDisk> convertedDisks = importInstanceCommandWrapper.getTemporaryDisksWithPrefixFromTemporaryPool(temporaryPool, convertPath, convertPrefix);
|
||||||
|
Assert.assertEquals(2, convertedDisks.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetTemporaryDisksFromParsedXml() {
|
||||||
|
String relativePath = UUID.randomUUID().toString();
|
||||||
|
String fullPath = String.format("/mnt/xyz/%s", relativePath);
|
||||||
|
|
||||||
|
LibvirtVMDef.DiskDef diskDef = new LibvirtVMDef.DiskDef();
|
||||||
|
LibvirtVMDef.DiskDef.DiskBus bus = LibvirtVMDef.DiskDef.DiskBus.VIRTIO;
|
||||||
|
LibvirtVMDef.DiskDef.DiskFmtType type = LibvirtVMDef.DiskDef.DiskFmtType.QCOW2;
|
||||||
|
diskDef.defFileBasedDisk(fullPath, "test", bus, type);
|
||||||
|
|
||||||
|
LibvirtDomainXMLParser parser = Mockito.mock(LibvirtDomainXMLParser.class);
|
||||||
|
Mockito.when(parser.getDisks()).thenReturn(List.of(diskDef));
|
||||||
|
|
||||||
|
KVMPhysicalDisk convertedDisk1 = Mockito.mock(KVMPhysicalDisk.class);
|
||||||
|
Mockito.when(convertedDisk1.getName()).thenReturn("disk1");
|
||||||
|
Mockito.when(temporaryPool.getPhysicalDisk(relativePath)).thenReturn(convertedDisk1);
|
||||||
|
|
||||||
|
List<KVMPhysicalDisk> disks = importInstanceCommandWrapper.getTemporaryDisksFromParsedXml(temporaryPool, parser, "");
|
||||||
|
Mockito.verify(importInstanceCommandWrapper).sanitizeDisksPath(List.of(diskDef));
|
||||||
|
Assert.assertEquals(1, disks.size());
|
||||||
|
Assert.assertEquals("disk1", disks.get(0).getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSanitizeDisksPath() {
|
||||||
|
String relativePath = UUID.randomUUID().toString();
|
||||||
|
String fullPath = String.format("/mnt/xyz/%s", relativePath);
|
||||||
|
LibvirtVMDef.DiskDef diskDef = new LibvirtVMDef.DiskDef();
|
||||||
|
LibvirtVMDef.DiskDef.DiskBus bus = LibvirtVMDef.DiskDef.DiskBus.VIRTIO;
|
||||||
|
LibvirtVMDef.DiskDef.DiskFmtType type = LibvirtVMDef.DiskDef.DiskFmtType.QCOW2;
|
||||||
|
diskDef.defFileBasedDisk(fullPath, "test", bus, type);
|
||||||
|
|
||||||
|
importInstanceCommandWrapper.sanitizeDisksPath(List.of(diskDef));
|
||||||
|
Assert.assertEquals(relativePath, diskDef.getDiskPath());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMoveTemporaryDisksToDestination() {
|
||||||
|
KVMPhysicalDisk sourceDisk = Mockito.mock(KVMPhysicalDisk.class);
|
||||||
|
Mockito.lenient().when(sourceDisk.getPool()).thenReturn(temporaryPool);
|
||||||
|
List<KVMPhysicalDisk> disks = List.of(sourceDisk);
|
||||||
|
String destinationPoolUuid = UUID.randomUUID().toString();
|
||||||
|
List<String> destinationPools = List.of(destinationPoolUuid);
|
||||||
|
|
||||||
|
KVMPhysicalDisk destDisk = Mockito.mock(KVMPhysicalDisk.class);
|
||||||
|
Mockito.when(destDisk.getPath()).thenReturn("xyz");
|
||||||
|
Mockito.when(storagePoolManager.getStoragePool(Storage.StoragePoolType.NetworkFilesystem, destinationPoolUuid))
|
||||||
|
.thenReturn(destinationPool);
|
||||||
|
Mockito.when(destinationPool.getType()).thenReturn(Storage.StoragePoolType.NetworkFilesystem);
|
||||||
|
Mockito.when(storagePoolManager.copyPhysicalDisk(Mockito.eq(sourceDisk), Mockito.anyString(), Mockito.eq(destinationPool), Mockito.anyInt()))
|
||||||
|
.thenReturn(destDisk);
|
||||||
|
|
||||||
|
List<KVMPhysicalDisk> movedDisks = importInstanceCommandWrapper.moveTemporaryDisksToDestination(disks, destinationPools, storagePoolManager);
|
||||||
|
Assert.assertEquals(1, movedDisks.size());
|
||||||
|
Assert.assertEquals("xyz", movedDisks.get(0).getPath());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetUnmanagedInstanceDisks() {
|
||||||
|
try (MockedStatic<Script> ignored = Mockito.mockStatic(Script.class)) {
|
||||||
|
String relativePath = UUID.randomUUID().toString();
|
||||||
|
LibvirtVMDef.DiskDef diskDef = new LibvirtVMDef.DiskDef();
|
||||||
|
LibvirtVMDef.DiskDef.DiskBus bus = LibvirtVMDef.DiskDef.DiskBus.IDE;
|
||||||
|
LibvirtVMDef.DiskDef.DiskFmtType type = LibvirtVMDef.DiskDef.DiskFmtType.QCOW2;
|
||||||
|
diskDef.defFileBasedDisk(relativePath, relativePath, bus, type);
|
||||||
|
|
||||||
|
KVMPhysicalDisk sourceDisk = Mockito.mock(KVMPhysicalDisk.class);
|
||||||
|
Mockito.when(sourceDisk.getName()).thenReturn(UUID.randomUUID().toString());
|
||||||
|
Mockito.when(sourceDisk.getPool()).thenReturn(destinationPool);
|
||||||
|
Mockito.when(destinationPool.getType()).thenReturn(Storage.StoragePoolType.NetworkFilesystem);
|
||||||
|
List<KVMPhysicalDisk> disks = List.of(sourceDisk);
|
||||||
|
|
||||||
|
LibvirtDomainXMLParser parser = Mockito.mock(LibvirtDomainXMLParser.class);
|
||||||
|
Mockito.when(parser.getDisks()).thenReturn(List.of(diskDef));
|
||||||
|
Mockito.doReturn(new Pair<String, String>(null, null)).when(importInstanceCommandWrapper).getNfsStoragePoolHostAndPath(destinationPool);
|
||||||
|
|
||||||
|
Mockito.when(Script.executePipedCommands(Mockito.anyList(), Mockito.anyLong()))
|
||||||
|
.thenReturn(new Pair<>(0, null));
|
||||||
|
|
||||||
|
List<UnmanagedInstanceTO.Disk> unmanagedInstanceDisks = importInstanceCommandWrapper.getUnmanagedInstanceDisks(disks, parser);
|
||||||
|
Assert.assertEquals(1, unmanagedInstanceDisks.size());
|
||||||
|
UnmanagedInstanceTO.Disk disk = unmanagedInstanceDisks.get(0);
|
||||||
|
Assert.assertEquals(LibvirtVMDef.DiskDef.DiskBus.IDE.toString(), disk.getController());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetNfsStoragePoolHostAndPath() {
|
||||||
|
try (MockedStatic<Script> ignored = Mockito.mockStatic(Script.class)) {
|
||||||
|
String localMountPoint = "/mnt/xyz";
|
||||||
|
String host = "192.168.1.2";
|
||||||
|
String path = "/secondary";
|
||||||
|
String mountOutput = String.format("%s:%s on %s type nfs (...)", host, path, localMountPoint);
|
||||||
|
Mockito.when(temporaryPool.getLocalPath()).thenReturn(localMountPoint);
|
||||||
|
Mockito.when(Script.executePipedCommands(Mockito.anyList(), Mockito.anyLong()))
|
||||||
|
.thenReturn(new Pair<>(0, mountOutput));
|
||||||
|
|
||||||
|
Pair<String, String> pair = importInstanceCommandWrapper.getNfsStoragePoolHostAndPath(temporaryPool);
|
||||||
|
Assert.assertEquals(host, pair.first());
|
||||||
|
Assert.assertEquals(path, pair.second());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private RemoteInstanceTO getRemoteInstanceTO(Hypervisor.HypervisorType hypervisorType) {
|
||||||
|
RemoteInstanceTO remoteInstanceTO = Mockito.mock(RemoteInstanceTO.class);
|
||||||
|
Mockito.when(remoteInstanceTO.getHypervisorType()).thenReturn(hypervisorType);
|
||||||
|
Mockito.when(remoteInstanceTO.getInstanceName()).thenReturn(vmName);
|
||||||
|
return remoteInstanceTO;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ImportConvertedInstanceCommand getImportConvertedInstanceCommand(RemoteInstanceTO remoteInstanceTO) {
|
||||||
|
ImportConvertedInstanceCommand cmd = Mockito.mock(ImportConvertedInstanceCommand.class);
|
||||||
|
Mockito.when(cmd.getSourceInstance()).thenReturn(remoteInstanceTO);
|
||||||
|
Mockito.when(cmd.getConversionTemporaryLocation()).thenReturn(secondaryDataStore);
|
||||||
|
return cmd;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testExecuteConvertUnsupportedOnTheHost() {
|
||||||
|
RemoteInstanceTO remoteInstanceTO = getRemoteInstanceTO(Hypervisor.HypervisorType.VMware);
|
||||||
|
ImportConvertedInstanceCommand cmd = getImportConvertedInstanceCommand(remoteInstanceTO);
|
||||||
|
Answer answer = importInstanceCommandWrapper.execute(cmd, libvirtComputingResourceMock);
|
||||||
|
Assert.assertFalse(answer.getResult());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testExecuteConvertUnsupportedHypervisors() {
|
||||||
|
RemoteInstanceTO remoteInstanceTO = getRemoteInstanceTO(Hypervisor.HypervisorType.XenServer);
|
||||||
|
ImportConvertedInstanceCommand cmd = getImportConvertedInstanceCommand(remoteInstanceTO);
|
||||||
|
Answer answer = importInstanceCommandWrapper.execute(cmd, libvirtComputingResourceMock);
|
||||||
|
Assert.assertFalse(answer.getResult());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -461,7 +461,7 @@ public class KubernetesClusterResourceModifierActionWorker extends KubernetesClu
|
||||||
sourcePort, sourcePort,
|
sourcePort, sourcePort,
|
||||||
vmIp,
|
vmIp,
|
||||||
destPort, destPort,
|
destPort, destPort,
|
||||||
"tcp", networkId, accountId, domainId, vmId);
|
"tcp", networkId, accountId, domainId, vmId, null);
|
||||||
newRule.setDisplay(true);
|
newRule.setDisplay(true);
|
||||||
newRule.setState(FirewallRule.State.Add);
|
newRule.setState(FirewallRule.State.Add);
|
||||||
newRule = portForwardingRulesDao.persist(newRule);
|
newRule = portForwardingRulesDao.persist(newRule);
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||||
- Disable discard="unmap" for ide devices and qemu < 7.0
|
- Disable discard="unmap" for ide devices and qemu < 7.0
|
||||||
https://bugzilla.redhat.com/show_bug.cgi?id=2029980
|
https://bugzilla.redhat.com/show_bug.cgi?id=2029980
|
||||||
|
|
||||||
|
## [2024-10-14]
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- Support for ISO direct download to primary storage
|
||||||
|
|
||||||
## [2024-10-04]
|
## [2024-10-04]
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
|
||||||
|
|
@ -23,11 +23,13 @@ import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
|
|
||||||
import com.cloud.storage.Storage;
|
import com.cloud.storage.Storage;
|
||||||
import com.cloud.utils.exception.CloudRuntimeException;
|
import com.cloud.utils.exception.CloudRuntimeException;
|
||||||
|
import com.cloud.utils.script.Script;
|
||||||
|
|
||||||
import org.apache.cloudstack.storage.datastore.util.LinstorUtil;
|
import org.apache.cloudstack.storage.datastore.util.LinstorUtil;
|
||||||
import org.apache.cloudstack.utils.qemu.QemuImg;
|
import org.apache.cloudstack.utils.qemu.QemuImg;
|
||||||
|
|
@ -57,6 +59,8 @@ import com.linbit.linstor.api.model.StoragePool;
|
||||||
import com.linbit.linstor.api.model.Volume;
|
import com.linbit.linstor.api.model.Volume;
|
||||||
import com.linbit.linstor.api.model.VolumeDefinition;
|
import com.linbit.linstor.api.model.VolumeDefinition;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
public class LinstorStorageAdaptor implements StorageAdaptor {
|
public class LinstorStorageAdaptor implements StorageAdaptor {
|
||||||
protected Logger logger = LogManager.getLogger(getClass());
|
protected Logger logger = LogManager.getLogger(getClass());
|
||||||
private static final Map<String, KVMStoragePool> MapStorageUuidToStoragePool = new HashMap<>();
|
private static final Map<String, KVMStoragePool> MapStorageUuidToStoragePool = new HashMap<>();
|
||||||
|
|
@ -566,13 +570,7 @@ public class LinstorStorageAdaptor implements StorageAdaptor {
|
||||||
name, QemuImg.PhysicalDiskFormat.RAW, provisioningType, disk.getVirtualSize(), null);
|
name, QemuImg.PhysicalDiskFormat.RAW, provisioningType, disk.getVirtualSize(), null);
|
||||||
|
|
||||||
final DevelopersApi api = getLinstorAPI(destPools);
|
final DevelopersApi api = getLinstorAPI(destPools);
|
||||||
final String rscName = LinstorUtil.RSC_PREFIX + name;
|
applyAuxProps(api, name, disk.getDispName(), disk.getVmName());
|
||||||
try {
|
|
||||||
LinstorUtil.applyAuxProps(api, rscName, disk.getDispName(), disk.getVmName());
|
|
||||||
} catch (ApiException apiExc) {
|
|
||||||
logger.error("Error setting aux properties for {}", rscName);
|
|
||||||
logLinstorAnswers(apiExc.getApiCallRcList());
|
|
||||||
}
|
|
||||||
|
|
||||||
logger.debug("Linstor.copyPhysicalDisk: dstPath: {}", dstDisk.getPath());
|
logger.debug("Linstor.copyPhysicalDisk: dstPath: {}", dstDisk.getPath());
|
||||||
final QemuImgFile destFile = new QemuImgFile(dstDisk.getPath());
|
final QemuImgFile destFile = new QemuImgFile(dstDisk.getPath());
|
||||||
|
|
@ -623,13 +621,58 @@ public class LinstorStorageAdaptor implements StorageAdaptor {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void fileExistsOrThrow(String templateFilePath) {
|
||||||
|
File sourceFile = new File(templateFilePath);
|
||||||
|
if (!sourceFile.exists()) {
|
||||||
|
throw new CloudRuntimeException("Direct download template file " + sourceFile +
|
||||||
|
" does not exist on this host");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getFinalDirectDownloadPath(String templateFilePath, KVMStoragePool destPool) {
|
||||||
|
String finalSourcePath = templateFilePath;
|
||||||
|
if (LibvirtStorageAdaptor.isTemplateExtractable(templateFilePath)) {
|
||||||
|
finalSourcePath = templateFilePath.substring(0, templateFilePath.lastIndexOf('.'));
|
||||||
|
LibvirtStorageAdaptor.extractDownloadedTemplate(templateFilePath, destPool, finalSourcePath);
|
||||||
|
}
|
||||||
|
return finalSourcePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void applyAuxProps(DevelopersApi api, String csPath, String csName, String csVMName) {
|
||||||
|
final String rscName = getLinstorRscName(csPath);
|
||||||
|
try {
|
||||||
|
LinstorUtil.applyAuxProps(api, rscName, csName, csVMName);
|
||||||
|
} catch (ApiException apiExc) {
|
||||||
|
logger.error(String.format("Error setting aux properties for %s", rscName));
|
||||||
|
logLinstorAnswers(apiExc.getApiCallRcList());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public KVMPhysicalDisk createTemplateFromDirectDownloadFile(String templateFilePath, String destTemplatePath,
|
public KVMPhysicalDisk createTemplateFromDirectDownloadFile(String templateFilePath, String destTemplatePath,
|
||||||
KVMStoragePool destPool, Storage.ImageFormat format,
|
KVMStoragePool destPool, Storage.ImageFormat format,
|
||||||
int timeout)
|
int timeout)
|
||||||
{
|
{
|
||||||
logger.debug("Linstor: createTemplateFromDirectDownloadFile");
|
logger.debug("Linstor: createTemplateFromDirectDownloadFile");
|
||||||
return null;
|
|
||||||
|
fileExistsOrThrow(templateFilePath);
|
||||||
|
String name = UUID.randomUUID().toString();
|
||||||
|
|
||||||
|
String finalSourcePath = getFinalDirectDownloadPath(templateFilePath, destPool);
|
||||||
|
|
||||||
|
File finalSourceFile = new File(finalSourcePath);
|
||||||
|
final KVMPhysicalDisk dstDisk = destPool.createPhysicalDisk(
|
||||||
|
name, QemuImg.PhysicalDiskFormat.RAW, Storage.ProvisioningType.THIN, finalSourceFile.length(), null);
|
||||||
|
|
||||||
|
final DevelopersApi api = getLinstorAPI(destPool);
|
||||||
|
applyAuxProps(api, name, finalSourceFile.getName(), null);
|
||||||
|
|
||||||
|
Script.runSimpleBashScript(
|
||||||
|
String.format("dd if=\"%s\" of=\"%s\" bs=64k conv=nocreat,sparse oflag=direct",
|
||||||
|
finalSourcePath, dstDisk.getPath()));
|
||||||
|
|
||||||
|
Script.runSimpleBashScript("rm " + finalSourcePath);
|
||||||
|
return dstDisk;
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getCapacity(LinstorStoragePool pool) {
|
public long getCapacity(LinstorStoragePool pool) {
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,9 @@ import java.util.Set;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import javax.naming.ConfigurationException;
|
import javax.naming.ConfigurationException;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.ObjectUtils;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import com.cloud.dc.DataCenter;
|
import com.cloud.dc.DataCenter;
|
||||||
import com.cloud.network.dao.NsxProviderDao;
|
import com.cloud.network.dao.NsxProviderDao;
|
||||||
import com.cloud.network.element.NsxProviderVO;
|
import com.cloud.network.element.NsxProviderVO;
|
||||||
|
|
@ -40,7 +43,6 @@ import org.apache.cloudstack.context.CallContext;
|
||||||
import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService;
|
import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService;
|
||||||
import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
|
import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
|
||||||
import org.apache.cloudstack.network.RoutedIpv4Manager;
|
import org.apache.cloudstack.network.RoutedIpv4Manager;
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
|
|
||||||
import com.cloud.configuration.Config;
|
import com.cloud.configuration.Config;
|
||||||
import com.cloud.domain.dao.DomainDao;
|
import com.cloud.domain.dao.DomainDao;
|
||||||
|
|
@ -402,20 +404,34 @@ public class FirewallManagerImpl extends ManagerBase implements FirewallService,
|
||||||
((rule.getPurpose() == Purpose.Firewall || newRule.getPurpose() == Purpose.Firewall) && ((newRule.getPurpose() != rule.getPurpose()) || (!newRule.getProtocol()
|
((rule.getPurpose() == Purpose.Firewall || newRule.getPurpose() == Purpose.Firewall) && ((newRule.getPurpose() != rule.getPurpose()) || (!newRule.getProtocol()
|
||||||
.equalsIgnoreCase(rule.getProtocol()))));
|
.equalsIgnoreCase(rule.getProtocol()))));
|
||||||
|
|
||||||
// if both rules are firewall and their cidrs are different, we can skip port ranges verification
|
// if both rules are firewall/port forwarding and their cidrs are different, we can skip port ranges verification
|
||||||
boolean bothRulesFirewall = (rule.getPurpose() == newRule.getPurpose() && rule.getPurpose() == Purpose.Firewall);
|
|
||||||
boolean duplicatedCidrs = false;
|
boolean duplicatedCidrs = false;
|
||||||
|
|
||||||
|
boolean bothRulesFirewall = (rule.getPurpose() == newRule.getPurpose() && rule.getPurpose() == Purpose.Firewall);
|
||||||
if (bothRulesFirewall) {
|
if (bothRulesFirewall) {
|
||||||
_firewallDao.loadSourceCidrs(rule);
|
_firewallDao.loadSourceCidrs(rule);
|
||||||
_firewallDao.loadSourceCidrs((FirewallRuleVO)newRule);
|
_firewallDao.loadSourceCidrs((FirewallRuleVO)newRule);
|
||||||
|
|
||||||
|
if (ObjectUtils.anyNull(rule.getSourceCidrList(), newRule.getSourceCidrList())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
_firewallDao.loadDestinationCidrs(rule);
|
_firewallDao.loadDestinationCidrs(rule);
|
||||||
_firewallDao.loadDestinationCidrs((FirewallRuleVO) newRule);
|
_firewallDao.loadDestinationCidrs((FirewallRuleVO) newRule);
|
||||||
|
|
||||||
if (rule.getSourceCidrList() == null || newRule.getSourceCidrList() == null) {
|
duplicatedCidrs = detectConflictingCidrs(rule.getSourceCidrList(), newRule.getSourceCidrList()) && detectConflictingCidrs(rule.getDestinationCidrList(), newRule.getDestinationCidrList());
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean bothRulesPortForwarding = rule.getPurpose() == newRule.getPurpose() && rule.getPurpose() == Purpose.PortForwarding;
|
||||||
|
if (bothRulesPortForwarding) {
|
||||||
|
_firewallDao.loadSourceCidrs(rule);
|
||||||
|
_firewallDao.loadSourceCidrs((FirewallRuleVO) newRule);
|
||||||
|
|
||||||
|
if (ObjectUtils.anyNull(rule.getSourceCidrList(), newRule.getSourceCidrList())) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
duplicatedCidrs = (detectConflictingCidrs(rule.getSourceCidrList(), newRule.getSourceCidrList()) && detectConflictingCidrs(rule.getDestinationCidrList(), newRule.getDestinationCidrList()));
|
|
||||||
|
duplicatedCidrs = detectConflictingCidrs(rule.getSourceCidrList(), newRule.getSourceCidrList());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!oneOfRulesIsFirewall) {
|
if (!oneOfRulesIsFirewall) {
|
||||||
|
|
@ -451,18 +467,7 @@ public class FirewallManagerImpl extends ManagerBase implements FirewallService,
|
||||||
|
|
||||||
if (!notNullPorts) {
|
if (!notNullPorts) {
|
||||||
continue;
|
continue;
|
||||||
} else if (!oneOfRulesIsFirewall &&
|
} else if (checkIfRulesHaveConflictingPortRanges(newRule, rule, oneOfRulesIsFirewall, bothRulesFirewall, bothRulesPortForwarding, duplicatedCidrs)) {
|
||||||
!(bothRulesFirewall && !duplicatedCidrs) &&
|
|
||||||
((rule.getSourcePortStart().intValue() <= newRule.getSourcePortStart().intValue() &&
|
|
||||||
rule.getSourcePortEnd().intValue() >= newRule.getSourcePortStart().intValue()) ||
|
|
||||||
(rule.getSourcePortStart().intValue() <= newRule.getSourcePortEnd().intValue() &&
|
|
||||||
rule.getSourcePortEnd().intValue() >= newRule.getSourcePortEnd().intValue()) ||
|
|
||||||
(newRule.getSourcePortStart().intValue() <= rule.getSourcePortStart().intValue() &&
|
|
||||||
newRule.getSourcePortEnd().intValue() >= rule.getSourcePortStart().intValue()) ||
|
|
||||||
(newRule.getSourcePortStart().intValue() <= rule.getSourcePortEnd().intValue() &&
|
|
||||||
newRule.getSourcePortEnd().intValue() >= rule.getSourcePortEnd().intValue()))) {
|
|
||||||
//Above else if conditions checks for the conflicting port ranges.
|
|
||||||
|
|
||||||
// we allow port forwarding rules with the same parameters but different protocols
|
// we allow port forwarding rules with the same parameters but different protocols
|
||||||
boolean allowPf =
|
boolean allowPf =
|
||||||
(rule.getPurpose() == Purpose.PortForwarding && newRule.getPurpose() == Purpose.PortForwarding && !newRule.getProtocol().equalsIgnoreCase(
|
(rule.getPurpose() == Purpose.PortForwarding && newRule.getPurpose() == Purpose.PortForwarding && !newRule.getProtocol().equalsIgnoreCase(
|
||||||
|
|
@ -489,6 +494,45 @@ public class FirewallManagerImpl extends ManagerBase implements FirewallService,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected boolean checkIfRulesHaveConflictingPortRanges(FirewallRule newRule, FirewallRule rule, boolean oneOfRulesIsFirewall, boolean bothRulesFirewall, boolean bothRulesPortForwarding, boolean duplicatedCidrs) {
|
||||||
|
String rulesAsString = String.format("[%s] and [%s]", rule, newRule);
|
||||||
|
|
||||||
|
if (oneOfRulesIsFirewall) {
|
||||||
|
logger.debug(String.format("Only one of the rules (%s) is firewall; therefore, their port ranges will not conflict.",
|
||||||
|
rulesAsString));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((bothRulesFirewall || bothRulesPortForwarding) && !duplicatedCidrs) {
|
||||||
|
logger.debug(String.format("Both rules (%s) are firewall/port forwarding, but they do not have duplicated CIDRs; therefore, their port ranges will not conflict.",
|
||||||
|
rulesAsString));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rule.getSourcePortStart() <= newRule.getSourcePortStart() && rule.getSourcePortEnd() >= newRule.getSourcePortStart()) {
|
||||||
|
logger.debug(String.format("Rules (%s) have conflicting port ranges.", rulesAsString));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rule.getSourcePortStart() <= newRule.getSourcePortEnd() && rule.getSourcePortEnd() >= newRule.getSourcePortEnd()) {
|
||||||
|
logger.debug(String.format("Rules (%s) have conflicting port ranges.", rulesAsString));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newRule.getSourcePortStart() <= rule.getSourcePortStart() && newRule.getSourcePortEnd() >= rule.getSourcePortStart()) {
|
||||||
|
logger.debug(String.format("Rules (%s) have conflicting port ranges.", rulesAsString));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newRule.getSourcePortStart() <= rule.getSourcePortEnd() && newRule.getSourcePortEnd() >= rule.getSourcePortEnd()) {
|
||||||
|
logger.debug(String.format("Rules (%s) have conflicting port ranges.", rulesAsString));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.debug(String.format("Rules (%s) do not have conflicting port ranges.", rulesAsString));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void validateFirewallRule(Account caller, IPAddressVO ipAddress, Integer portStart, Integer portEnd, String proto, Purpose purpose, FirewallRuleType type,
|
public void validateFirewallRule(Account caller, IPAddressVO ipAddress, Integer portStart, Integer portEnd, String proto, Purpose purpose, FirewallRuleType type,
|
||||||
Long networkId, FirewallRule.TrafficType trafficType) {
|
Long networkId, FirewallRule.TrafficType trafficType) {
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,7 @@ import java.util.Set;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
import com.cloud.network.rules.PortForwardingRuleVO;
|
||||||
import org.apache.cloudstack.api.ApiConstants;
|
import org.apache.cloudstack.api.ApiConstants;
|
||||||
import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService;
|
import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService;
|
||||||
import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
|
import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
|
||||||
|
|
@ -408,6 +409,7 @@ public class CommandSetupHelper {
|
||||||
final List<PortForwardingRuleTO> rulesTO = new ArrayList<PortForwardingRuleTO>();
|
final List<PortForwardingRuleTO> rulesTO = new ArrayList<PortForwardingRuleTO>();
|
||||||
if (rules != null) {
|
if (rules != null) {
|
||||||
for (final PortForwardingRule rule : rules) {
|
for (final PortForwardingRule rule : rules) {
|
||||||
|
_rulesDao.loadSourceCidrs((PortForwardingRuleVO) rule);
|
||||||
final IpAddress sourceIp = _networkModel.getIp(rule.getSourceIpAddressId());
|
final IpAddress sourceIp = _networkModel.getIp(rule.getSourceIpAddressId());
|
||||||
final PortForwardingRuleTO ruleTO = new PortForwardingRuleTO(rule, null, sourceIp.getAddress().addr());
|
final PortForwardingRuleTO ruleTO = new PortForwardingRuleTO(rule, null, sourceIp.getAddress().addr());
|
||||||
rulesTO.add(ruleTO);
|
rulesTO.add(ruleTO);
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,7 @@ import com.cloud.vm.VirtualMachineProfile;
|
||||||
import com.cloud.vm.VirtualMachineProfileImpl;
|
import com.cloud.vm.VirtualMachineProfileImpl;
|
||||||
import org.apache.cloudstack.acl.SecurityChecker;
|
import org.apache.cloudstack.acl.SecurityChecker;
|
||||||
import org.apache.cloudstack.api.command.user.firewall.ListPortForwardingRulesCmd;
|
import org.apache.cloudstack.api.command.user.firewall.ListPortForwardingRulesCmd;
|
||||||
|
import org.apache.cloudstack.api.command.user.firewall.UpdatePortForwardingRuleCmd;
|
||||||
import org.apache.cloudstack.context.CallContext;
|
import org.apache.cloudstack.context.CallContext;
|
||||||
import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService;
|
import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService;
|
||||||
|
|
||||||
|
|
@ -102,6 +103,7 @@ import com.cloud.vm.dao.NicSecondaryIpDao;
|
||||||
import com.cloud.vm.dao.NicSecondaryIpVO;
|
import com.cloud.vm.dao.NicSecondaryIpVO;
|
||||||
import com.cloud.vm.dao.UserVmDao;
|
import com.cloud.vm.dao.UserVmDao;
|
||||||
import com.cloud.vm.dao.VMInstanceDao;
|
import com.cloud.vm.dao.VMInstanceDao;
|
||||||
|
import org.apache.commons.collections.CollectionUtils;
|
||||||
|
|
||||||
public class RulesManagerImpl extends ManagerBase implements RulesManager, RulesService {
|
public class RulesManagerImpl extends ManagerBase implements RulesManager, RulesService {
|
||||||
|
|
||||||
|
|
@ -112,7 +114,7 @@ public class RulesManagerImpl extends ManagerBase implements RulesManager, Rules
|
||||||
@Inject
|
@Inject
|
||||||
PortForwardingRulesDao _portForwardingDao;
|
PortForwardingRulesDao _portForwardingDao;
|
||||||
@Inject
|
@Inject
|
||||||
FirewallRulesCidrsDao _firewallCidrsDao;
|
FirewallRulesCidrsDao firewallCidrsDao;
|
||||||
@Inject
|
@Inject
|
||||||
FirewallRulesDao _firewallDao;
|
FirewallRulesDao _firewallDao;
|
||||||
@Inject
|
@Inject
|
||||||
|
|
@ -247,6 +249,7 @@ public class RulesManagerImpl extends ManagerBase implements RulesManager, Rules
|
||||||
|
|
||||||
final Long accountId = ipAddress.getAllocatedToAccountId();
|
final Long accountId = ipAddress.getAllocatedToAccountId();
|
||||||
final Long domainId = ipAddress.getAllocatedInDomainId();
|
final Long domainId = ipAddress.getAllocatedInDomainId();
|
||||||
|
List<String> sourceCidrList = rule.getSourceCidrList();
|
||||||
|
|
||||||
// start port can't be bigger than end port
|
// start port can't be bigger than end port
|
||||||
if (rule.getDestinationPortStart() > rule.getDestinationPortEnd()) {
|
if (rule.getDestinationPortStart() > rule.getDestinationPortEnd()) {
|
||||||
|
|
@ -310,9 +313,8 @@ public class RulesManagerImpl extends ManagerBase implements RulesManager, Rules
|
||||||
final IPAddressVO ipAddressFinal = ipAddress;
|
final IPAddressVO ipAddressFinal = ipAddress;
|
||||||
return Transaction.execute((TransactionCallbackWithException<PortForwardingRuleVO, NetworkRuleConflictException>) status -> {
|
return Transaction.execute((TransactionCallbackWithException<PortForwardingRuleVO, NetworkRuleConflictException>) status -> {
|
||||||
PortForwardingRuleVO newRule =
|
PortForwardingRuleVO newRule =
|
||||||
new PortForwardingRuleVO(rule.getXid(), rule.getSourceIpAddressId(), rule.getSourcePortStart(), rule.getSourcePortEnd(), dstIpFinal,
|
new PortForwardingRuleVO(rule.getXid(), rule.getSourceIpAddressId(), rule.getSourcePortStart(), rule.getSourcePortEnd(), dstIpFinal,
|
||||||
rule.getDestinationPortStart(), rule.getDestinationPortEnd(), rule.getProtocol().toLowerCase(), networkId, accountId, domainId, vmId);
|
rule.getDestinationPortStart(), rule.getDestinationPortEnd(), rule.getProtocol().toLowerCase(), networkId, accountId, domainId, vmId, sourceCidrList);
|
||||||
|
|
||||||
if (forDisplay != null) {
|
if (forDisplay != null) {
|
||||||
newRule.setDisplay(forDisplay);
|
newRule.setDisplay(forDisplay);
|
||||||
}
|
}
|
||||||
|
|
@ -896,6 +898,10 @@ public class RulesManagerImpl extends ManagerBase implements RulesManager, Rules
|
||||||
_accountMgr.checkAccess(caller, null, true, rules.toArray(new PortForwardingRuleVO[rules.size()]));
|
_accountMgr.checkAccess(caller, null, true, rules.toArray(new PortForwardingRuleVO[rules.size()]));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (PortForwardingRuleVO rule : rules) {
|
||||||
|
rule.setSourceCidrList(firewallCidrsDao.getSourceCidrs(rule.getId()));
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (!_firewallMgr.applyRules(rules, continueOnError, true)) {
|
if (!_firewallMgr.applyRules(rules, continueOnError, true)) {
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -949,6 +955,10 @@ public class RulesManagerImpl extends ManagerBase implements RulesManager, Rules
|
||||||
_accountMgr.checkAccess(caller, null, true, rules.toArray(new PortForwardingRuleVO[rules.size()]));
|
_accountMgr.checkAccess(caller, null, true, rules.toArray(new PortForwardingRuleVO[rules.size()]));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (PortForwardingRuleVO rule: rules) {
|
||||||
|
rule.setSourceCidrList(firewallCidrsDao.getSourceCidrs(rule.getId()));
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (!_firewallMgr.applyRules(rules, continueOnError, true)) {
|
if (!_firewallMgr.applyRules(rules, continueOnError, true)) {
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -1568,12 +1578,22 @@ public class RulesManagerImpl extends ManagerBase implements RulesManager, Rules
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ActionEvent(eventType = EventTypes.EVENT_NET_RULE_MODIFY, eventDescription = "updating forwarding rule", async = true)
|
@ActionEvent(eventType = EventTypes.EVENT_NET_RULE_MODIFY, eventDescription = "updating forwarding rule", async = true)
|
||||||
public PortForwardingRule updatePortForwardingRule(long id, Integer privatePort, Integer privateEndPort, Long virtualMachineId, Ip vmGuestIp, String customId, Boolean forDisplay) {
|
public PortForwardingRule updatePortForwardingRule(UpdatePortForwardingRuleCmd cmd) {
|
||||||
Account caller = CallContext.current().getCallingAccount();
|
long id = cmd.getId();
|
||||||
|
Integer privatePort = cmd.getPrivatePort();
|
||||||
|
Integer privateEndPort = cmd.getPrivateEndPort();
|
||||||
|
Long virtualMachineId = cmd.getVirtualMachineId();
|
||||||
|
Ip vmGuestIp = cmd.getVmGuestIp();
|
||||||
|
String customId = cmd.getCustomId();
|
||||||
|
Boolean forDisplay = cmd.getDisplay();
|
||||||
|
List<String> sourceCidrList = cmd.getSourceCidrList();
|
||||||
|
|
||||||
PortForwardingRuleVO rule = _portForwardingDao.findById(id);
|
PortForwardingRuleVO rule = _portForwardingDao.findById(id);
|
||||||
if (rule == null) {
|
if (rule == null) {
|
||||||
throw new InvalidParameterValueException("Unable to find " + id);
|
throw new InvalidParameterValueException("Unable to find " + id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Account caller = CallContext.current().getCallingAccount();
|
||||||
_accountMgr.checkAccess(caller, null, true, rule);
|
_accountMgr.checkAccess(caller, null, true, rule);
|
||||||
|
|
||||||
if (customId != null) {
|
if (customId != null) {
|
||||||
|
|
@ -1634,6 +1654,8 @@ public class RulesManagerImpl extends ManagerBase implements RulesManager, Rules
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
validatePortForwardingSourceCidrList(sourceCidrList);
|
||||||
|
|
||||||
// revoke old rules at first
|
// revoke old rules at first
|
||||||
List<PortForwardingRuleVO> rules = new ArrayList<PortForwardingRuleVO>();
|
List<PortForwardingRuleVO> rules = new ArrayList<PortForwardingRuleVO>();
|
||||||
rule.setState(State.Revoke);
|
rule.setState(State.Revoke);
|
||||||
|
|
@ -1661,6 +1683,11 @@ public class RulesManagerImpl extends ManagerBase implements RulesManager, Rules
|
||||||
rule.setVirtualMachineId(virtualMachineId);
|
rule.setVirtualMachineId(virtualMachineId);
|
||||||
rule.setDestinationIpAddress(dstIp);
|
rule.setDestinationIpAddress(dstIp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (sourceCidrList != null) {
|
||||||
|
rule.setSourceCidrList(sourceCidrList);
|
||||||
|
}
|
||||||
|
|
||||||
_portForwardingDao.update(id, rule);
|
_portForwardingDao.update(id, rule);
|
||||||
|
|
||||||
//apply new rules
|
//apply new rules
|
||||||
|
|
@ -1670,4 +1697,17 @@ public class RulesManagerImpl extends ManagerBase implements RulesManager, Rules
|
||||||
|
|
||||||
return _portForwardingDao.findById(id);
|
return _portForwardingDao.findById(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void validatePortForwardingSourceCidrList(List<String> sourceCidrList) {
|
||||||
|
if (CollectionUtils.isEmpty(sourceCidrList)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (String cidr : sourceCidrList) {
|
||||||
|
if (!NetUtils.isValidCidrList(cidr) && !NetUtils.isValidIp6Cidr(cidr)) {
|
||||||
|
throw new InvalidParameterValueException(String.format("The given source CIDR [%s] is invalid.", cidr));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,8 @@ import com.cloud.agent.api.GetRemoteVmsAnswer;
|
||||||
import com.cloud.agent.api.GetRemoteVmsCommand;
|
import com.cloud.agent.api.GetRemoteVmsCommand;
|
||||||
import com.cloud.agent.api.GetUnmanagedInstancesAnswer;
|
import com.cloud.agent.api.GetUnmanagedInstancesAnswer;
|
||||||
import com.cloud.agent.api.GetUnmanagedInstancesCommand;
|
import com.cloud.agent.api.GetUnmanagedInstancesCommand;
|
||||||
|
import com.cloud.agent.api.ImportConvertedInstanceAnswer;
|
||||||
|
import com.cloud.agent.api.ImportConvertedInstanceCommand;
|
||||||
import com.cloud.agent.api.PrepareUnmanageVMInstanceAnswer;
|
import com.cloud.agent.api.PrepareUnmanageVMInstanceAnswer;
|
||||||
import com.cloud.agent.api.PrepareUnmanageVMInstanceCommand;
|
import com.cloud.agent.api.PrepareUnmanageVMInstanceCommand;
|
||||||
import com.cloud.agent.api.to.DataStoreTO;
|
import com.cloud.agent.api.to.DataStoreTO;
|
||||||
|
|
@ -1338,6 +1340,10 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager {
|
||||||
Long clusterId = cmd.getClusterId();
|
Long clusterId = cmd.getClusterId();
|
||||||
Cluster cluster = basicAccessChecks(clusterId);
|
Cluster cluster = basicAccessChecks(clusterId);
|
||||||
|
|
||||||
|
if (!cluster.getAllocationState().equals(Cluster.AllocationState.Enabled)) {
|
||||||
|
throw new InvalidParameterValueException(String.format("Cluster [%s] is not enabled.", cluster));
|
||||||
|
}
|
||||||
|
|
||||||
final Account caller = CallContext.current().getCallingAccount();
|
final Account caller = CallContext.current().getCallingAccount();
|
||||||
final DataCenter zone = dataCenterDao.findById(cluster.getDataCenterId());
|
final DataCenter zone = dataCenterDao.findById(cluster.getDataCenterId());
|
||||||
final Account owner = accountService.getActiveAccountById(cmd.getEntityOwnerId());
|
final Account owner = accountService.getActiveAccountById(cmd.getEntityOwnerId());
|
||||||
|
|
@ -1601,6 +1607,7 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager {
|
||||||
String clusterName = cmd.getClusterName();
|
String clusterName = cmd.getClusterName();
|
||||||
String sourceHostName = cmd.getHostIp();
|
String sourceHostName = cmd.getHostIp();
|
||||||
Long convertInstanceHostId = cmd.getConvertInstanceHostId();
|
Long convertInstanceHostId = cmd.getConvertInstanceHostId();
|
||||||
|
Long importInstanceHostId = cmd.getImportInstanceHostId();
|
||||||
Long convertStoragePoolId = cmd.getConvertStoragePoolId();
|
Long convertStoragePoolId = cmd.getConvertStoragePoolId();
|
||||||
|
|
||||||
if ((existingVcenterId == null && vcenter == null) || (existingVcenterId != null && vcenter != null)) {
|
if ((existingVcenterId == null && vcenter == null) || (existingVcenterId != null && vcenter != null)) {
|
||||||
|
|
@ -1630,12 +1637,14 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager {
|
||||||
DataStoreTO temporaryConvertLocation = null;
|
DataStoreTO temporaryConvertLocation = null;
|
||||||
String ovfTemplateOnConvertLocation = null;
|
String ovfTemplateOnConvertLocation = null;
|
||||||
try {
|
try {
|
||||||
HostVO convertHost = selectInstanceConversionKVMHostInCluster(destinationCluster, convertInstanceHostId);
|
HostVO convertHost = selectKVMHostForConversionInCluster(destinationCluster, convertInstanceHostId);
|
||||||
|
HostVO importHost = selectKVMHostForImportingInCluster(destinationCluster, importInstanceHostId);
|
||||||
CheckConvertInstanceAnswer conversionSupportAnswer = checkConversionSupportOnHost(convertHost, sourceVMName, false);
|
CheckConvertInstanceAnswer conversionSupportAnswer = checkConversionSupportOnHost(convertHost, sourceVMName, false);
|
||||||
logger.debug(String.format("The host %s (%s) is selected to execute the conversion of the instance %s" +
|
logger.debug(String.format("The host %s (%s) is selected to execute the conversion of the instance %s" +
|
||||||
" from VMware to KVM ", convertHost.getId(), convertHost.getName(), sourceVMName));
|
" from VMware to KVM ", convertHost.getId(), convertHost.getName(), sourceVMName));
|
||||||
|
|
||||||
temporaryConvertLocation = selectInstanceConversionTemporaryLocation(destinationCluster, convertStoragePoolId);
|
temporaryConvertLocation = selectInstanceConversionTemporaryLocation(
|
||||||
|
destinationCluster, convertHost, convertStoragePoolId);
|
||||||
List<StoragePoolVO> convertStoragePools = findInstanceConversionStoragePoolsInCluster(destinationCluster);
|
List<StoragePoolVO> convertStoragePools = findInstanceConversionStoragePoolsInCluster(destinationCluster);
|
||||||
long importStartTime = System.currentTimeMillis();
|
long importStartTime = System.currentTimeMillis();
|
||||||
Pair<UnmanagedInstanceTO, Boolean> sourceInstanceDetails = getSourceVmwareUnmanagedInstance(vcenter, datacenterName, username, password, clusterName, sourceHostName, sourceVMName);
|
Pair<UnmanagedInstanceTO, Boolean> sourceInstanceDetails = getSourceVmwareUnmanagedInstance(vcenter, datacenterName, username, password, clusterName, sourceHostName, sourceVMName);
|
||||||
|
|
@ -1654,11 +1663,13 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager {
|
||||||
int noOfThreads = UnmanagedVMsManager.ThreadsOnMSToImportVMwareVMFiles.value();
|
int noOfThreads = UnmanagedVMsManager.ThreadsOnMSToImportVMwareVMFiles.value();
|
||||||
ovfTemplateOnConvertLocation = createOvfTemplateOfSourceVmwareUnmanagedInstance(vcenter, datacenterName, username, password,
|
ovfTemplateOnConvertLocation = createOvfTemplateOfSourceVmwareUnmanagedInstance(vcenter, datacenterName, username, password,
|
||||||
clusterName, sourceHostName, sourceVMwareInstance.getName(), temporaryConvertLocation, noOfThreads);
|
clusterName, sourceHostName, sourceVMwareInstance.getName(), temporaryConvertLocation, noOfThreads);
|
||||||
convertedInstance = convertVmwareInstanceToKVMWithOVFOnConvertLocation(sourceVMName, sourceVMwareInstance, convertHost, convertStoragePools,
|
convertedInstance = convertVmwareInstanceToKVMWithOVFOnConvertLocation(sourceVMName,
|
||||||
|
sourceVMwareInstance, convertHost, importHost, convertStoragePools,
|
||||||
temporaryConvertLocation, ovfTemplateOnConvertLocation);
|
temporaryConvertLocation, ovfTemplateOnConvertLocation);
|
||||||
} else {
|
} else {
|
||||||
// Uses KVM Host for OVF export to temporary conversion location, through ovftool
|
// Uses KVM Host for OVF export to temporary conversion location, through ovftool
|
||||||
convertedInstance = convertVmwareInstanceToKVMAfterExportingOVFToConvertLocation(sourceVMName, sourceVMwareInstance, convertHost, convertStoragePools,
|
convertedInstance = convertVmwareInstanceToKVMAfterExportingOVFToConvertLocation(
|
||||||
|
sourceVMName, sourceVMwareInstance, convertHost, importHost, convertStoragePools,
|
||||||
temporaryConvertLocation, vcenter, username, password, datacenterName);
|
temporaryConvertLocation, vcenter, username, password, datacenterName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1814,23 +1825,81 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager {
|
||||||
return params;
|
return params;
|
||||||
}
|
}
|
||||||
|
|
||||||
private HostVO selectInstanceConversionKVMHostInCluster(Cluster destinationCluster, Long convertInstanceHostId) {
|
HostVO selectKVMHostForImportingInCluster(Cluster destinationCluster, Long importInstanceHostId) {
|
||||||
if (convertInstanceHostId != null) {
|
if (importInstanceHostId != null) {
|
||||||
HostVO selectedHost = hostDao.findById(convertInstanceHostId);
|
String err = null;
|
||||||
|
HostVO selectedHost = hostDao.findById(importInstanceHostId);
|
||||||
if (selectedHost == null) {
|
if (selectedHost == null) {
|
||||||
String msg = String.format("Cannot find host with ID %s", convertInstanceHostId);
|
err = String.format("Cannot find host with ID %s to import the instance",
|
||||||
logger.error(msg);
|
importInstanceHostId);
|
||||||
throw new CloudRuntimeException(msg);
|
} else if (selectedHost.getResourceState() != ResourceState.Enabled) {
|
||||||
|
err = String.format(
|
||||||
|
"Cannot import the converted instance on the host %s as it is not in Enabled state",
|
||||||
|
selectedHost.getName());
|
||||||
|
} else if (selectedHost.getStatus() != Status.Up) {
|
||||||
|
err = String.format(
|
||||||
|
"Cannot import the converted instance on the host %s as it is not running",
|
||||||
|
selectedHost.getName());
|
||||||
|
} else if (selectedHost.getType() != Host.Type.Routing) {
|
||||||
|
err = String.format(
|
||||||
|
"Cannot import the converted instance on the host %s as it is not a routing host",
|
||||||
|
selectedHost.getName());
|
||||||
|
} else if (destinationCluster.getId() != selectedHost.getClusterId()) {
|
||||||
|
err = String.format(
|
||||||
|
"Cannot import the converted instance on the host %s as it is not in the same cluster as the destination cluster",
|
||||||
|
selectedHost.getName());
|
||||||
}
|
}
|
||||||
if (selectedHost.getResourceState() != ResourceState.Enabled ||
|
|
||||||
selectedHost.getStatus() != Status.Up || selectedHost.getType() != Host.Type.Routing ||
|
if (err != null) {
|
||||||
selectedHost.getClusterId() != destinationCluster.getId()) {
|
logger.error(err);
|
||||||
String msg = String.format("Cannot perform the conversion on the host %s as it is not a running and Enabled host", selectedHost.getName());
|
throw new CloudRuntimeException(err);
|
||||||
logger.error(msg);
|
|
||||||
throw new CloudRuntimeException(msg);
|
|
||||||
}
|
}
|
||||||
return selectedHost;
|
return selectedHost;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
List<HostVO> hosts = hostDao.listByClusterAndHypervisorType(destinationCluster.getId(), destinationCluster.getHypervisorType());
|
||||||
|
if (CollectionUtils.isNotEmpty(hosts)) {
|
||||||
|
return hosts.get(new Random().nextInt(hosts.size()));
|
||||||
|
}
|
||||||
|
|
||||||
|
String err = String.format(
|
||||||
|
"Could not find any suitable %s host in cluster %s to import the converted instance",
|
||||||
|
destinationCluster.getHypervisorType(), destinationCluster.getName());
|
||||||
|
logger.error(err);
|
||||||
|
throw new CloudRuntimeException(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
HostVO selectKVMHostForConversionInCluster(Cluster destinationCluster, Long convertInstanceHostId) {
|
||||||
|
if (convertInstanceHostId != null) {
|
||||||
|
HostVO selectedHost = hostDao.findById(convertInstanceHostId);
|
||||||
|
String err = null;
|
||||||
|
if (selectedHost == null) {
|
||||||
|
err = String.format("Cannot find host with ID %s for conversion",
|
||||||
|
convertInstanceHostId);
|
||||||
|
} else if (!List.of(ResourceState.Enabled, ResourceState.Disabled).contains(selectedHost.getResourceState())) {
|
||||||
|
err = String.format(
|
||||||
|
"Cannot perform the conversion on the host %s as the host is in %s state",
|
||||||
|
selectedHost.getName(), selectedHost.getResourceState());
|
||||||
|
} else if (selectedHost.getStatus() != Status.Up) {
|
||||||
|
err = String.format(
|
||||||
|
"Cannot perform the conversion on the host %s as it is not running",
|
||||||
|
selectedHost.getName());
|
||||||
|
} else if (selectedHost.getType() != Host.Type.Routing) {
|
||||||
|
err = String.format(
|
||||||
|
"Cannot perform the conversion on the host %s as it is not a routing host",
|
||||||
|
selectedHost.getName());
|
||||||
|
} else if (destinationCluster.getDataCenterId() != selectedHost.getDataCenterId()) {
|
||||||
|
err = String.format(
|
||||||
|
"Cannot perform the conversion on the host %s as it is not in the same zone as the destination cluster",
|
||||||
|
selectedHost.getName());
|
||||||
|
}
|
||||||
|
if (err != null) {
|
||||||
|
logger.error(err);
|
||||||
|
throw new CloudRuntimeException(err);
|
||||||
|
}
|
||||||
|
return selectedHost;
|
||||||
|
}
|
||||||
|
|
||||||
// Auto select host with conversion capability
|
// Auto select host with conversion capability
|
||||||
List<HostVO> hosts = hostDao.listByClusterHypervisorTypeAndHostCapability(destinationCluster.getId(), destinationCluster.getHypervisorType(), Host.HOST_INSTANCE_CONVERSION);
|
List<HostVO> hosts = hostDao.listByClusterHypervisorTypeAndHostCapability(destinationCluster.getId(), destinationCluster.getHypervisorType(), Host.HOST_INSTANCE_CONVERSION);
|
||||||
if (CollectionUtils.isNotEmpty(hosts)) {
|
if (CollectionUtils.isNotEmpty(hosts)) {
|
||||||
|
|
@ -1875,10 +1944,13 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager {
|
||||||
return checkConvertInstanceAnswer;
|
return checkConvertInstanceAnswer;
|
||||||
}
|
}
|
||||||
|
|
||||||
private UnmanagedInstanceTO convertVmwareInstanceToKVMWithOVFOnConvertLocation(String sourceVM, UnmanagedInstanceTO sourceVMwareInstance, HostVO convertHost,
|
private UnmanagedInstanceTO convertVmwareInstanceToKVMWithOVFOnConvertLocation(
|
||||||
List<StoragePoolVO> convertStoragePools, DataStoreTO temporaryConvertLocation,
|
String sourceVM, UnmanagedInstanceTO sourceVMwareInstance,
|
||||||
String ovfTemplateDirConvertLocation) {
|
HostVO convertHost, HostVO importHost,
|
||||||
logger.debug(String.format("Delegating the conversion of instance %s from VMware to KVM to the host %s (%s) using OVF %s on conversion datastore",
|
List<StoragePoolVO> convertStoragePools, DataStoreTO temporaryConvertLocation,
|
||||||
|
String ovfTemplateDirConvertLocation
|
||||||
|
) {
|
||||||
|
logger.debug(String.format("Delegating the conversion of instance %s from VMware to KVM to the host %s (%s) using OVF %s on conversion datastore",
|
||||||
sourceVM, convertHost.getId(), convertHost.getName(), ovfTemplateDirConvertLocation));
|
sourceVM, convertHost.getId(), convertHost.getName(), ovfTemplateDirConvertLocation));
|
||||||
|
|
||||||
RemoteInstanceTO remoteInstanceTO = new RemoteInstanceTO(sourceVM);
|
RemoteInstanceTO remoteInstanceTO = new RemoteInstanceTO(sourceVM);
|
||||||
|
|
@ -1907,9 +1979,12 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager {
|
||||||
return ((ConvertInstanceAnswer) convertAnswer).getConvertedInstance();
|
return ((ConvertInstanceAnswer) convertAnswer).getConvertedInstance();
|
||||||
}
|
}
|
||||||
|
|
||||||
private UnmanagedInstanceTO convertVmwareInstanceToKVMAfterExportingOVFToConvertLocation(String sourceVM, UnmanagedInstanceTO sourceVMwareInstance, HostVO convertHost,
|
private UnmanagedInstanceTO convertVmwareInstanceToKVMAfterExportingOVFToConvertLocation(
|
||||||
List<StoragePoolVO> convertStoragePools, DataStoreTO temporaryConvertLocation,
|
String sourceVM, UnmanagedInstanceTO sourceVMwareInstance,
|
||||||
String vcenterHost, String vcenterUsername, String vcenterPassword, String datacenterName) {
|
HostVO convertHost, HostVO importHost, List<StoragePoolVO> convertStoragePools,
|
||||||
|
DataStoreTO temporaryConvertLocation, String vcenterHost,
|
||||||
|
String vcenterUsername, String vcenterPassword, String datacenterName
|
||||||
|
) {
|
||||||
logger.debug(String.format("Delegating the conversion of instance %s from VMware to KVM to the host %s (%s) after OVF export through ovftool",
|
logger.debug(String.format("Delegating the conversion of instance %s from VMware to KVM to the host %s (%s) after OVF export through ovftool",
|
||||||
sourceVM, convertHost.getId(), convertHost.getName()));
|
sourceVM, convertHost.getId(), convertHost.getName()));
|
||||||
|
|
||||||
|
|
@ -1926,9 +2001,18 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager {
|
||||||
}
|
}
|
||||||
cmd.setThreadsCountToExportOvf(noOfThreads);
|
cmd.setThreadsCountToExportOvf(noOfThreads);
|
||||||
|
|
||||||
|
return convertAndImportToKVM(cmd, convertHost, importHost, sourceVM,
|
||||||
|
remoteInstanceTO, destinationStoragePools, temporaryConvertLocation);
|
||||||
|
}
|
||||||
|
|
||||||
|
private UnmanagedInstanceTO convertAndImportToKVM(ConvertInstanceCommand convertInstanceCommand, HostVO convertHost, HostVO importHost,
|
||||||
|
String sourceVM,
|
||||||
|
RemoteInstanceTO remoteInstanceTO,
|
||||||
|
List<String> destinationStoragePools,
|
||||||
|
DataStoreTO temporaryConvertLocation) {
|
||||||
Answer convertAnswer;
|
Answer convertAnswer;
|
||||||
try {
|
try {
|
||||||
convertAnswer = agentManager.send(convertHost.getId(), cmd);
|
convertAnswer = agentManager.send(convertHost.getId(), convertInstanceCommand);
|
||||||
} catch (AgentUnavailableException | OperationTimedoutException e) {
|
} catch (AgentUnavailableException | OperationTimedoutException e) {
|
||||||
String err = String.format("Could not send the convert instance command to host %s (%s) due to: %s",
|
String err = String.format("Could not send the convert instance command to host %s (%s) due to: %s",
|
||||||
convertHost.getId(), convertHost.getName(), e.getMessage());
|
convertHost.getId(), convertHost.getName(), e.getMessage());
|
||||||
|
|
@ -1942,7 +2026,30 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager {
|
||||||
logger.error(err);
|
logger.error(err);
|
||||||
throw new CloudRuntimeException(err);
|
throw new CloudRuntimeException(err);
|
||||||
}
|
}
|
||||||
return ((ConvertInstanceAnswer) convertAnswer).getConvertedInstance();
|
|
||||||
|
Answer importAnswer;
|
||||||
|
try {
|
||||||
|
ImportConvertedInstanceCommand importCmd = new ImportConvertedInstanceCommand(
|
||||||
|
remoteInstanceTO, destinationStoragePools, temporaryConvertLocation,
|
||||||
|
((ConvertInstanceAnswer)convertAnswer).getTemporaryConvertUuid());
|
||||||
|
importAnswer = agentManager.send(importHost.getId(), importCmd);
|
||||||
|
} catch (AgentUnavailableException | OperationTimedoutException e) {
|
||||||
|
String err = String.format(
|
||||||
|
"Could not send the import converted instance command to host %d (%s) due to: %s",
|
||||||
|
importHost.getId(), importHost.getName(), e.getMessage());
|
||||||
|
logger.error(err, e);
|
||||||
|
throw new CloudRuntimeException(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!importAnswer.getResult()) {
|
||||||
|
String err = String.format(
|
||||||
|
"The import process failed for instance %s from VMware to KVM on host %s: %s",
|
||||||
|
sourceVM, importHost.getName(), importAnswer.getDetails());
|
||||||
|
logger.error(err);
|
||||||
|
throw new CloudRuntimeException(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ((ImportConvertedInstanceAnswer) importAnswer).getConvertedInstance();
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<StoragePoolVO> findInstanceConversionStoragePoolsInCluster(Cluster destinationCluster) {
|
private List<StoragePoolVO> findInstanceConversionStoragePoolsInCluster(Cluster destinationCluster) {
|
||||||
|
|
@ -1974,7 +2081,9 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager {
|
||||||
throw new CloudRuntimeException(msg);
|
throw new CloudRuntimeException(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected DataStoreTO selectInstanceConversionTemporaryLocation(Cluster destinationCluster, Long convertStoragePoolId) {
|
protected DataStoreTO selectInstanceConversionTemporaryLocation(Cluster destinationCluster,
|
||||||
|
HostVO convertHost,
|
||||||
|
Long convertStoragePoolId) {
|
||||||
if (convertStoragePoolId != null) {
|
if (convertStoragePoolId != null) {
|
||||||
StoragePoolVO selectedStoragePool = primaryDataStoreDao.findById(convertStoragePoolId);
|
StoragePoolVO selectedStoragePool = primaryDataStoreDao.findById(convertStoragePoolId);
|
||||||
if (selectedStoragePool == null) {
|
if (selectedStoragePool == null) {
|
||||||
|
|
@ -1985,6 +2094,10 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager {
|
||||||
logFailureAndThrowException(String.format("Cannot use the storage pool %s for the instance conversion as " +
|
logFailureAndThrowException(String.format("Cannot use the storage pool %s for the instance conversion as " +
|
||||||
"it is not in the scope of the cluster %s", selectedStoragePool.getName(), destinationCluster.getName()));
|
"it is not in the scope of the cluster %s", selectedStoragePool.getName(), destinationCluster.getName()));
|
||||||
}
|
}
|
||||||
|
if (convertHost != null && selectedStoragePool.getScope() == ScopeType.CLUSTER && !selectedStoragePool.getClusterId().equals(convertHost.getClusterId())) {
|
||||||
|
logFailureAndThrowException(String.format("Cannot use the storage pool %s for the instance conversion as " +
|
||||||
|
"the host %s for conversion is in a different cluster", selectedStoragePool.getName(), convertHost.getName()));
|
||||||
|
}
|
||||||
if (selectedStoragePool.getScope() == ScopeType.HOST) {
|
if (selectedStoragePool.getScope() == ScopeType.HOST) {
|
||||||
logFailureAndThrowException(String.format("The storage pool %s is a local storage pool and not supported for temporary conversion location, cluster and zone wide NFS storage pools are supported", selectedStoragePool.getName()));
|
logFailureAndThrowException(String.format("The storage pool %s is a local storage pool and not supported for temporary conversion location, cluster and zone wide NFS storage pools are supported", selectedStoragePool.getName()));
|
||||||
} else if (selectedStoragePool.getPoolType() != Storage.StoragePoolType.NetworkFilesystem) {
|
} else if (selectedStoragePool.getPoolType() != Storage.StoragePoolType.NetworkFilesystem) {
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,6 @@ import com.cloud.network.dao.FirewallRulesDao;
|
||||||
import com.cloud.network.element.FirewallServiceProvider;
|
import com.cloud.network.element.FirewallServiceProvider;
|
||||||
import com.cloud.network.element.VirtualRouterElement;
|
import com.cloud.network.element.VirtualRouterElement;
|
||||||
import com.cloud.network.element.VpcVirtualRouterElement;
|
import com.cloud.network.element.VpcVirtualRouterElement;
|
||||||
import com.cloud.network.rules.FirewallManager;
|
|
||||||
import com.cloud.network.rules.FirewallRule;
|
import com.cloud.network.rules.FirewallRule;
|
||||||
import com.cloud.network.rules.FirewallRule.Purpose;
|
import com.cloud.network.rules.FirewallRule.Purpose;
|
||||||
import com.cloud.network.rules.FirewallRuleVO;
|
import com.cloud.network.rules.FirewallRuleVO;
|
||||||
|
|
@ -35,11 +34,9 @@ import com.cloud.network.vpc.VpcManager;
|
||||||
import com.cloud.user.AccountManager;
|
import com.cloud.user.AccountManager;
|
||||||
import com.cloud.user.DomainManager;
|
import com.cloud.user.DomainManager;
|
||||||
import com.cloud.utils.component.ComponentContext;
|
import com.cloud.utils.component.ComponentContext;
|
||||||
import junit.framework.Assert;
|
|
||||||
import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService;
|
import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService;
|
||||||
import org.apache.logging.log4j.Logger;
|
|
||||||
import org.apache.logging.log4j.LogManager;
|
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
|
import org.junit.Assert;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Ignore;
|
import org.junit.Ignore;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
@ -47,6 +44,7 @@ import org.junit.runner.RunWith;
|
||||||
import org.mockito.InjectMocks;
|
import org.mockito.InjectMocks;
|
||||||
import org.mockito.Mock;
|
import org.mockito.Mock;
|
||||||
import org.mockito.MockitoAnnotations;
|
import org.mockito.MockitoAnnotations;
|
||||||
|
import org.mockito.Spy;
|
||||||
import org.mockito.junit.MockitoJUnitRunner;
|
import org.mockito.junit.MockitoJUnitRunner;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
@ -62,40 +60,8 @@ import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
@RunWith(MockitoJUnitRunner.class)
|
@RunWith(MockitoJUnitRunner.class)
|
||||||
public class FirewallManagerTest {
|
public class FirewallManagerTest {
|
||||||
private Logger logger = LogManager.getLogger(FirewallManagerTest.class);
|
|
||||||
private AutoCloseable closeable;
|
private AutoCloseable closeable;
|
||||||
|
|
||||||
|
|
||||||
@Ignore("Requires database to be set up")
|
|
||||||
@Test
|
|
||||||
public void testInjected() {
|
|
||||||
|
|
||||||
// FirewallManagerImpl firewallMgr = (FirewallManagerImpl)ComponentLocator.getCurrentLocator().getManager(FirewallManager.class);
|
|
||||||
// Assert.assertTrue(firewallMgr._firewallElements.enumeration().hasMoreElements());
|
|
||||||
// Assert.assertTrue(firewallMgr._pfElements.enumeration().hasMoreElements());
|
|
||||||
// Assert.assertTrue(firewallMgr._staticNatElements.enumeration().hasMoreElements());
|
|
||||||
// Assert.assertTrue(firewallMgr._networkAclElements.enumeration().hasMoreElements());
|
|
||||||
// Assert.assertNotNull(firewallMgr._networkModel);
|
|
||||||
//
|
|
||||||
// Assert.assertNotNull(firewallMgr._firewallElements.get("VirtualRouter"));
|
|
||||||
// Assert.assertNotNull(firewallMgr._firewallElements.get("VpcVirtualRouter"));
|
|
||||||
// Assert.assertNotNull(firewallMgr._pfElements.get("VirtualRouter"));
|
|
||||||
// Assert.assertNotNull(firewallMgr._pfElements.get("VpcVirtualRouter"));
|
|
||||||
// Assert.assertNotNull(firewallMgr._staticNatElements.get("VirtualRouter"));
|
|
||||||
// Assert.assertNotNull(firewallMgr._staticNatElements.get("VpcVirtualRouter"));
|
|
||||||
// Assert.assertNotNull(firewallMgr._networkAclElements.get("VpcVirtualRouter"));
|
|
||||||
// Assert.assertNull(firewallMgr._networkAclElements.get("VirtualRouter"));
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// Assert.assertTrue(firewallMgr._firewallElements.get("VirtualRouter") instanceof FirewallServiceProvider);
|
|
||||||
// Assert.assertTrue(firewallMgr._pfElements.get("VirtualRouter") instanceof PortForwardingServiceProvider);
|
|
||||||
// Assert.assertTrue(firewallMgr._staticNatElements.get("VirtualRouter") instanceof StaticNatServiceProvider);
|
|
||||||
// Assert.assertTrue(firewallMgr._networkAclElements.get("VpcVirtualRouter") instanceof NetworkACLServiceProvider);
|
|
||||||
|
|
||||||
logger.info("Done testing injection of service elements into firewall manager");
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Mock
|
@Mock
|
||||||
AccountManager _accountMgr;
|
AccountManager _accountMgr;
|
||||||
@Mock
|
@Mock
|
||||||
|
|
@ -111,12 +77,30 @@ public class FirewallManagerTest {
|
||||||
@Mock
|
@Mock
|
||||||
FirewallRulesDao _firewallDao;
|
FirewallRulesDao _firewallDao;
|
||||||
|
|
||||||
|
@Spy
|
||||||
@InjectMocks
|
@InjectMocks
|
||||||
FirewallManager _firewallMgr = new FirewallManagerImpl();
|
FirewallManagerImpl _firewallMgr;
|
||||||
|
|
||||||
|
FirewallRule fwRule50to150;
|
||||||
|
FirewallRule fwRule100to200;
|
||||||
|
FirewallRule fwRule151to200;
|
||||||
|
|
||||||
|
FirewallRule pfRule50to150;
|
||||||
|
FirewallRule pfRule100to200;
|
||||||
|
FirewallRule pfRule151to200;
|
||||||
|
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void initMocks() {
|
public void initMocks() {
|
||||||
closeable = MockitoAnnotations.openMocks(this);
|
closeable = MockitoAnnotations.openMocks(this);
|
||||||
|
|
||||||
|
fwRule50to150 = createFirewallRule(50, 150, Purpose.Firewall);
|
||||||
|
fwRule100to200 = createFirewallRule(100, 150, Purpose.Firewall);
|
||||||
|
fwRule151to200 = createFirewallRule(151, 200, Purpose.Firewall);
|
||||||
|
|
||||||
|
pfRule50to150 = createFirewallRule(50, 150, Purpose.PortForwarding);
|
||||||
|
pfRule100to200 = createFirewallRule(100, 150, Purpose.PortForwarding);
|
||||||
|
pfRule151to200 = createFirewallRule(151, 200, Purpose.PortForwarding);
|
||||||
}
|
}
|
||||||
|
|
||||||
@After
|
@After
|
||||||
|
|
@ -124,6 +108,11 @@ public class FirewallManagerTest {
|
||||||
closeable.close();
|
closeable.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private FirewallRule createFirewallRule(int startPort, int endPort, Purpose purpose) {
|
||||||
|
return new FirewallRuleVO("xid", 1L, startPort, endPort, "TCP", 2, 3, 4, purpose, new ArrayList<>(),
|
||||||
|
new ArrayList<>(), 5, 6, null, FirewallRule.TrafficType.Ingress);
|
||||||
|
}
|
||||||
|
|
||||||
@Ignore("Requires database to be set up")
|
@Ignore("Requires database to be set up")
|
||||||
@Test
|
@Test
|
||||||
public void testApplyRules() {
|
public void testApplyRules() {
|
||||||
|
|
@ -218,6 +207,75 @@ public class FirewallManagerTest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void checkIfRulesHaveConflictingPortRangesTestOnlyOneRuleIsFirewallReturnsFalse()
|
||||||
|
{
|
||||||
|
boolean result = _firewallMgr.checkIfRulesHaveConflictingPortRanges(fwRule50to150, pfRule50to150, true, false, false, true);
|
||||||
|
|
||||||
|
Assert.assertFalse(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void checkIfRulesHaveConflictingPortRangesTestBothRulesAreFirewallButNoDuplicateCidrsReturnsFalse()
|
||||||
|
{
|
||||||
|
boolean result = _firewallMgr.checkIfRulesHaveConflictingPortRanges(fwRule50to150, fwRule50to150, false, true, false, false);
|
||||||
|
|
||||||
|
Assert.assertFalse(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void checkIfRulesHaveConflictingPortRangesTestBothRulesArePortForwardingButNoDuplicateCidrsReturnsFalse()
|
||||||
|
{
|
||||||
|
boolean result = _firewallMgr.checkIfRulesHaveConflictingPortRanges(pfRule50to150, pfRule50to150, false, false, true, false);
|
||||||
|
|
||||||
|
Assert.assertFalse(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void checkIfRulesHaveConflictingPortRangesTestBothRulesAreFirewallAndDuplicatedCidrsAndNewRuleSourceStartPortIsInsideExistingRangeReturnsTrue()
|
||||||
|
{
|
||||||
|
boolean result = _firewallMgr.checkIfRulesHaveConflictingPortRanges(fwRule100to200, fwRule50to150, false, true, false, true);
|
||||||
|
|
||||||
|
Assert.assertTrue(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void checkIfRulesHaveConflictingPortRangesTestBothRulesAreFirewallAndDuplicatedCidrsAndNewRuleSourceEndPortIsInsideExistingRangeReturnsTrue()
|
||||||
|
{
|
||||||
|
boolean result = _firewallMgr.checkIfRulesHaveConflictingPortRanges(fwRule50to150, fwRule100to200, false, true, false, true);
|
||||||
|
|
||||||
|
Assert.assertTrue(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void checkIfRulesHaveConflictingPortRangesTestBothRulesArePortForwardingAndDuplicatedCidrsAndNewRuleSourceStartPortIsInsideExistingRangeReturnsTrue()
|
||||||
|
{
|
||||||
|
boolean result = _firewallMgr.checkIfRulesHaveConflictingPortRanges(pfRule50to150, pfRule100to200, false, false, true, true);
|
||||||
|
|
||||||
|
Assert.assertTrue(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void checkIfRulesHaveConflictingPortRangesTestBothRulesArePortForwardingAndDuplicatedCidrsAndNewRuleSourceEndPortIsInsideExistingRangeReturnsTrue()
|
||||||
|
{
|
||||||
|
boolean result = _firewallMgr.checkIfRulesHaveConflictingPortRanges(pfRule50to150, pfRule100to200, false, false, true, true);
|
||||||
|
|
||||||
|
Assert.assertTrue(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void checkIfRulesHaveConflictingPortRangesTestBothRulesAreFirewallAndDuplicatedCidrsAndNoRangeConflictReturnsFalse()
|
||||||
|
{
|
||||||
|
boolean result = _firewallMgr.checkIfRulesHaveConflictingPortRanges(fwRule50to150, fwRule151to200, false, true, false, true);
|
||||||
|
|
||||||
|
Assert.assertFalse(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void checkIfRulesHaveConflictingPortRangesTestBothRulesArePortForwardingAndDuplicatedCidrsAndNoRangeConflictReturnsFalse()
|
||||||
|
{
|
||||||
|
boolean result = _firewallMgr.checkIfRulesHaveConflictingPortRanges(pfRule50to150, pfRule151to200, false, false, true, true);
|
||||||
|
|
||||||
|
Assert.assertFalse(result);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -83,6 +83,8 @@ import com.cloud.agent.api.GetRemoteVmsAnswer;
|
||||||
import com.cloud.agent.api.GetRemoteVmsCommand;
|
import com.cloud.agent.api.GetRemoteVmsCommand;
|
||||||
import com.cloud.agent.api.GetUnmanagedInstancesAnswer;
|
import com.cloud.agent.api.GetUnmanagedInstancesAnswer;
|
||||||
import com.cloud.agent.api.GetUnmanagedInstancesCommand;
|
import com.cloud.agent.api.GetUnmanagedInstancesCommand;
|
||||||
|
import com.cloud.agent.api.ImportConvertedInstanceAnswer;
|
||||||
|
import com.cloud.agent.api.ImportConvertedInstanceCommand;
|
||||||
import com.cloud.agent.api.to.DataStoreTO;
|
import com.cloud.agent.api.to.DataStoreTO;
|
||||||
import com.cloud.configuration.Resource;
|
import com.cloud.configuration.Resource;
|
||||||
import com.cloud.dc.ClusterVO;
|
import com.cloud.dc.ClusterVO;
|
||||||
|
|
@ -116,6 +118,7 @@ import com.cloud.network.dao.NetworkDao;
|
||||||
import com.cloud.network.dao.NetworkVO;
|
import com.cloud.network.dao.NetworkVO;
|
||||||
import com.cloud.offering.NetworkOffering;
|
import com.cloud.offering.NetworkOffering;
|
||||||
import com.cloud.offering.ServiceOffering;
|
import com.cloud.offering.ServiceOffering;
|
||||||
|
import com.cloud.org.Grouping;
|
||||||
import com.cloud.resource.ResourceManager;
|
import com.cloud.resource.ResourceManager;
|
||||||
import com.cloud.resource.ResourceState;
|
import com.cloud.resource.ResourceState;
|
||||||
import com.cloud.service.ServiceOfferingVO;
|
import com.cloud.service.ServiceOfferingVO;
|
||||||
|
|
@ -371,9 +374,9 @@ public class UnmanagedVMsManagerImplTest {
|
||||||
doNothing().when(networkModel).checkNetworkPermissions(any(Account.class), any(Network.class));
|
doNothing().when(networkModel).checkNetworkPermissions(any(Account.class), any(Network.class));
|
||||||
NicProfile profile = Mockito.mock(NicProfile.class);
|
NicProfile profile = Mockito.mock(NicProfile.class);
|
||||||
Integer deviceId = 100;
|
Integer deviceId = 100;
|
||||||
Pair<NicProfile, Integer> pair = new Pair<NicProfile, Integer>(profile, deviceId);
|
Pair<NicProfile, Integer> pair = new Pair<>(profile, deviceId);
|
||||||
when(networkOrchestrationService.importNic(nullable(String.class), nullable(Integer.class), nullable(Network.class), nullable(Boolean.class), nullable(VirtualMachine.class), nullable(Network.IpAddresses.class), nullable(DataCenter.class), anyBoolean())).thenReturn(pair);
|
when(networkOrchestrationService.importNic(nullable(String.class), nullable(Integer.class), nullable(Network.class), nullable(Boolean.class), nullable(VirtualMachine.class), nullable(Network.IpAddresses.class), nullable(DataCenter.class), Mockito.anyBoolean())).thenReturn(pair);
|
||||||
when(volumeDao.findByInstance(anyLong())).thenReturn(volumes);
|
when(volumeDao.findByInstance(Mockito.anyLong())).thenReturn(volumes);
|
||||||
List<UserVmResponse> userVmResponses = new ArrayList<>();
|
List<UserVmResponse> userVmResponses = new ArrayList<>();
|
||||||
UserVmResponse userVmResponse = new UserVmResponse();
|
UserVmResponse userVmResponse = new UserVmResponse();
|
||||||
userVmResponse.setInstanceName(instance.getName());
|
userVmResponse.setInstanceName(instance.getName());
|
||||||
|
|
@ -597,6 +600,7 @@ public class UnmanagedVMsManagerImplTest {
|
||||||
|
|
||||||
ClusterVO cluster = mock(ClusterVO.class);
|
ClusterVO cluster = mock(ClusterVO.class);
|
||||||
when(cluster.getId()).thenReturn(clusterId);
|
when(cluster.getId()).thenReturn(clusterId);
|
||||||
|
when(cluster.getAllocationState()).thenReturn(Grouping.AllocationState.Enabled);
|
||||||
when(cluster.getHypervisorType()).thenReturn(Hypervisor.HypervisorType.KVM);
|
when(cluster.getHypervisorType()).thenReturn(Hypervisor.HypervisorType.KVM);
|
||||||
when(cluster.getDataCenterId()).thenReturn(zoneId);
|
when(cluster.getDataCenterId()).thenReturn(zoneId);
|
||||||
when(clusterDao.findById(clusterId)).thenReturn(cluster);
|
when(clusterDao.findById(clusterId)).thenReturn(cluster);
|
||||||
|
|
@ -610,6 +614,7 @@ public class UnmanagedVMsManagerImplTest {
|
||||||
when(importVmCmd.getHostIp()).thenReturn(host);
|
when(importVmCmd.getHostIp()).thenReturn(host);
|
||||||
when(importVmCmd.getNicNetworkList()).thenReturn(Map.of("NIC 1", networkId));
|
when(importVmCmd.getNicNetworkList()).thenReturn(Map.of("NIC 1", networkId));
|
||||||
when(importVmCmd.getConvertInstanceHostId()).thenReturn(null);
|
when(importVmCmd.getConvertInstanceHostId()).thenReturn(null);
|
||||||
|
when(importVmCmd.getImportInstanceHostId()).thenReturn(null);
|
||||||
when(importVmCmd.getConvertStoragePoolId()).thenReturn(null);
|
when(importVmCmd.getConvertStoragePoolId()).thenReturn(null);
|
||||||
|
|
||||||
NetworkVO networkVO = Mockito.mock(NetworkVO.class);
|
NetworkVO networkVO = Mockito.mock(NetworkVO.class);
|
||||||
|
|
@ -631,10 +636,14 @@ public class UnmanagedVMsManagerImplTest {
|
||||||
when(convertHost.getId()).thenReturn(convertHostId);
|
when(convertHost.getId()).thenReturn(convertHostId);
|
||||||
when(convertHost.getName()).thenReturn("KVM-Convert-Host");
|
when(convertHost.getName()).thenReturn("KVM-Convert-Host");
|
||||||
when(convertHost.getType()).thenReturn(Host.Type.Routing);
|
when(convertHost.getType()).thenReturn(Host.Type.Routing);
|
||||||
|
when(convertHost.getDataCenterId()).thenReturn(zoneId);
|
||||||
when(convertHost.getClusterId()).thenReturn(clusterId);
|
when(convertHost.getClusterId()).thenReturn(clusterId);
|
||||||
if (selectConvertHost) {
|
if (selectConvertHost) {
|
||||||
when(importVmCmd.getConvertInstanceHostId()).thenReturn(convertHostId);
|
when(importVmCmd.getConvertInstanceHostId()).thenReturn(convertHostId);
|
||||||
|
when(importVmCmd.getImportInstanceHostId()).thenReturn(convertHostId);
|
||||||
when(hostDao.findById(convertHostId)).thenReturn(convertHost);
|
when(hostDao.findById(convertHostId)).thenReturn(convertHost);
|
||||||
|
} else {
|
||||||
|
when(hostDao.listByClusterAndHypervisorType(clusterId, Hypervisor.HypervisorType.KVM)).thenReturn(List.of(convertHost));
|
||||||
}
|
}
|
||||||
|
|
||||||
DataStoreTO dataStoreTO = mock(DataStoreTO.class);
|
DataStoreTO dataStoreTO = mock(DataStoreTO.class);
|
||||||
|
|
@ -695,10 +704,14 @@ public class UnmanagedVMsManagerImplTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
ConvertInstanceAnswer convertInstanceAnswer = mock(ConvertInstanceAnswer.class);
|
ConvertInstanceAnswer convertInstanceAnswer = mock(ConvertInstanceAnswer.class);
|
||||||
when(convertInstanceAnswer.getResult()).thenReturn(vcenterParameter != VcenterParameter.CONVERT_FAILURE);
|
ImportConvertedInstanceAnswer convertImportedInstanceAnswer = mock(ImportConvertedInstanceAnswer.class);
|
||||||
when(convertInstanceAnswer.getConvertedInstance()).thenReturn(instance);
|
when(convertInstanceAnswer.getConvertedInstance()).thenReturn(instance);
|
||||||
|
when(convertInstanceAnswer.getResult()).thenReturn(vcenterParameter != VcenterParameter.CONVERT_FAILURE);
|
||||||
|
Mockito.lenient().when(convertImportedInstanceAnswer.getConvertedInstance()).thenReturn(instance);
|
||||||
|
Mockito.lenient().when(convertImportedInstanceAnswer.getResult()).thenReturn(vcenterParameter != VcenterParameter.CONVERT_FAILURE);
|
||||||
if (VcenterParameter.AGENT_UNAVAILABLE != vcenterParameter) {
|
if (VcenterParameter.AGENT_UNAVAILABLE != vcenterParameter) {
|
||||||
when(agentManager.send(Mockito.eq(convertHostId), Mockito.any(ConvertInstanceCommand.class))).thenReturn(convertInstanceAnswer);
|
when(agentManager.send(Mockito.eq(convertHostId), Mockito.any(ConvertInstanceCommand.class))).thenReturn(convertInstanceAnswer);
|
||||||
|
Mockito.lenient().when(agentManager.send(Mockito.eq(convertHostId), Mockito.any(ImportConvertedInstanceCommand.class))).thenReturn(convertImportedInstanceAnswer);
|
||||||
}
|
}
|
||||||
|
|
||||||
try (MockedStatic<UsageEventUtils> ignored = Mockito.mockStatic(UsageEventUtils.class)) {
|
try (MockedStatic<UsageEventUtils> ignored = Mockito.mockStatic(UsageEventUtils.class)) {
|
||||||
|
|
@ -762,6 +775,7 @@ public class UnmanagedVMsManagerImplTest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
public void testImportVmFromVmwareToKvmExistingVcenter() throws OperationTimedoutException, AgentUnavailableException {
|
public void testImportVmFromVmwareToKvmExistingVcenter() throws OperationTimedoutException, AgentUnavailableException {
|
||||||
baseTestImportVmFromVmwareToKvm(VcenterParameter.EXISTING, false, false);
|
baseTestImportVmFromVmwareToKvm(VcenterParameter.EXISTING, false, false);
|
||||||
}
|
}
|
||||||
|
|
@ -814,7 +828,7 @@ public class UnmanagedVMsManagerImplTest {
|
||||||
|
|
||||||
long poolId = 1L;
|
long poolId = 1L;
|
||||||
when(primaryDataStoreDao.findById(poolId)).thenReturn(null);
|
when(primaryDataStoreDao.findById(poolId)).thenReturn(null);
|
||||||
unmanagedVMsManager.selectInstanceConversionTemporaryLocation(cluster, poolId);
|
unmanagedVMsManager.selectInstanceConversionTemporaryLocation(cluster, null, poolId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = CloudRuntimeException.class)
|
@Test(expected = CloudRuntimeException.class)
|
||||||
|
|
@ -822,20 +836,35 @@ public class UnmanagedVMsManagerImplTest {
|
||||||
ClusterVO cluster = getClusterForTests();
|
ClusterVO cluster = getClusterForTests();
|
||||||
long poolId = 1L;
|
long poolId = 1L;
|
||||||
StoragePoolVO pool = mock(StoragePoolVO.class);
|
StoragePoolVO pool = mock(StoragePoolVO.class);
|
||||||
Mockito.when(pool.getScope()).thenReturn(ScopeType.CLUSTER);
|
when(pool.getScope()).thenReturn(ScopeType.CLUSTER);
|
||||||
Mockito.when(pool.getClusterId()).thenReturn(100L);
|
when(pool.getClusterId()).thenReturn(100L);
|
||||||
when(primaryDataStoreDao.findById(poolId)).thenReturn(pool);
|
when(primaryDataStoreDao.findById(poolId)).thenReturn(pool);
|
||||||
unmanagedVMsManager.selectInstanceConversionTemporaryLocation(cluster, poolId);
|
unmanagedVMsManager.selectInstanceConversionTemporaryLocation(cluster, null, poolId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test(expected = CloudRuntimeException.class)
|
||||||
|
public void testSelectInstanceConversionTemporaryLocationPoolConvertHostDifferentCluster() {
|
||||||
|
ClusterVO cluster = getClusterForTests();
|
||||||
|
long poolId = 1L;
|
||||||
|
StoragePoolVO pool = mock(StoragePoolVO.class);
|
||||||
|
when(pool.getScope()).thenReturn(ScopeType.CLUSTER);
|
||||||
|
when(pool.getClusterId()).thenReturn(1L);
|
||||||
|
HostVO host = mock(HostVO.class);
|
||||||
|
when(primaryDataStoreDao.findById(poolId)).thenReturn(pool);
|
||||||
|
when(host.getClusterId()).thenReturn(2L);
|
||||||
|
unmanagedVMsManager.selectInstanceConversionTemporaryLocation(cluster, host, poolId);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Test(expected = CloudRuntimeException.class)
|
@Test(expected = CloudRuntimeException.class)
|
||||||
public void testSelectInstanceConversionTemporaryLocationLocalStoragePoolInvalid() {
|
public void testSelectInstanceConversionTemporaryLocationLocalStoragePoolInvalid() {
|
||||||
ClusterVO cluster = getClusterForTests();
|
ClusterVO cluster = getClusterForTests();
|
||||||
long poolId = 1L;
|
long poolId = 1L;
|
||||||
StoragePoolVO pool = mock(StoragePoolVO.class);
|
StoragePoolVO pool = mock(StoragePoolVO.class);
|
||||||
Mockito.when(pool.getScope()).thenReturn(ScopeType.HOST);
|
when(pool.getScope()).thenReturn(ScopeType.HOST);
|
||||||
when(primaryDataStoreDao.findById(poolId)).thenReturn(pool);
|
when(primaryDataStoreDao.findById(poolId)).thenReturn(pool);
|
||||||
unmanagedVMsManager.selectInstanceConversionTemporaryLocation(cluster, poolId);
|
unmanagedVMsManager.selectInstanceConversionTemporaryLocation(cluster, null, poolId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = CloudRuntimeException.class)
|
@Test(expected = CloudRuntimeException.class)
|
||||||
|
|
@ -843,18 +872,250 @@ public class UnmanagedVMsManagerImplTest {
|
||||||
ClusterVO cluster = getClusterForTests();
|
ClusterVO cluster = getClusterForTests();
|
||||||
long poolId = 1L;
|
long poolId = 1L;
|
||||||
StoragePoolVO pool = mock(StoragePoolVO.class);
|
StoragePoolVO pool = mock(StoragePoolVO.class);
|
||||||
Mockito.when(pool.getScope()).thenReturn(ScopeType.CLUSTER);
|
when(pool.getScope()).thenReturn(ScopeType.CLUSTER);
|
||||||
Mockito.when(pool.getClusterId()).thenReturn(1L);
|
when(pool.getClusterId()).thenReturn(1L);
|
||||||
when(primaryDataStoreDao.findById(poolId)).thenReturn(pool);
|
when(primaryDataStoreDao.findById(poolId)).thenReturn(pool);
|
||||||
Mockito.when(pool.getPoolType()).thenReturn(Storage.StoragePoolType.RBD);
|
when(pool.getPoolType()).thenReturn(Storage.StoragePoolType.RBD);
|
||||||
unmanagedVMsManager.selectInstanceConversionTemporaryLocation(cluster, poolId);
|
unmanagedVMsManager.selectInstanceConversionTemporaryLocation(cluster, null, poolId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = CloudRuntimeException.class)
|
@Test(expected = CloudRuntimeException.class)
|
||||||
public void testSelectInstanceConversionTemporaryLocationNoPoolAvailable() {
|
public void testSelectInstanceConversionTemporaryLocationNoPoolAvailable() {
|
||||||
ClusterVO cluster = getClusterForTests();
|
ClusterVO cluster = getClusterForTests();
|
||||||
Mockito.when(imageStoreDao.findOneByZoneAndProtocol(anyLong(), anyString())).thenReturn(null);
|
when(imageStoreDao.findOneByZoneAndProtocol(anyLong(), anyString())).thenReturn(null);
|
||||||
unmanagedVMsManager.selectInstanceConversionTemporaryLocation(cluster, null);
|
unmanagedVMsManager.selectInstanceConversionTemporaryLocation(cluster, null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSelectKVMHostForImportingInClusterWithImportInstanceIdSuccess() {
|
||||||
|
Long hostId = 1L;
|
||||||
|
ClusterVO cluster = getClusterForTests();
|
||||||
|
HostVO host = Mockito.mock(HostVO.class);
|
||||||
|
when(host.getResourceState()).thenReturn(ResourceState.Enabled);
|
||||||
|
when(host.getStatus()).thenReturn(Status.Up);
|
||||||
|
when(host.getType()).thenReturn(Host.Type.Routing);
|
||||||
|
when(host.getClusterId()).thenReturn(1L);
|
||||||
|
|
||||||
|
when(hostDao.findById(hostId)).thenReturn(host);
|
||||||
|
|
||||||
|
HostVO returnedHost = unmanagedVMsManager.selectKVMHostForImportingInCluster(cluster, hostId);
|
||||||
|
Assert.assertEquals(host, returnedHost);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSelectKVMHostForImportingInClusterWithNullImportInstanceIdSuccess() {
|
||||||
|
ClusterVO cluster = getClusterForTests();
|
||||||
|
HostVO host = Mockito.mock(HostVO.class);
|
||||||
|
when(hostDao.listByClusterAndHypervisorType(cluster.getId(), cluster.getHypervisorType())).thenReturn(List.of(host));
|
||||||
|
|
||||||
|
HostVO returnedHost = unmanagedVMsManager.selectKVMHostForImportingInCluster(cluster, null);
|
||||||
|
Assert.assertEquals(host, returnedHost);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = CloudRuntimeException.class)
|
||||||
|
public void testSelectKVMHostForImportingInClusterFailure() {
|
||||||
|
ClusterVO cluster = getClusterForTests();
|
||||||
|
when(hostDao.listByClusterAndHypervisorType(cluster.getId(), cluster.getHypervisorType())).thenReturn(List.of());
|
||||||
|
|
||||||
|
unmanagedVMsManager.selectKVMHostForImportingInCluster(cluster, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = CloudRuntimeException.class)
|
||||||
|
public void testSelectKVMHostForImportingInClusterWithImportInstanceIdInvalidCluster() {
|
||||||
|
Long hostId = 1L;
|
||||||
|
ClusterVO cluster = getClusterForTests();
|
||||||
|
HostVO host = Mockito.mock(HostVO.class);
|
||||||
|
when(host.getResourceState()).thenReturn(ResourceState.Enabled);
|
||||||
|
when(host.getStatus()).thenReturn(Status.Up);
|
||||||
|
when(host.getType()).thenReturn(Host.Type.Routing);
|
||||||
|
when(host.getClusterId()).thenReturn(2L);
|
||||||
|
|
||||||
|
when(hostDao.findById(hostId)).thenReturn(host);
|
||||||
|
|
||||||
|
unmanagedVMsManager.selectKVMHostForImportingInCluster(cluster, hostId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = CloudRuntimeException.class)
|
||||||
|
public void testSelectKVMHostForImportingInClusterWithImportInstanceIdInvalidType() {
|
||||||
|
Long hostId = 1L;
|
||||||
|
ClusterVO cluster = getClusterForTests();
|
||||||
|
HostVO host = Mockito.mock(HostVO.class);
|
||||||
|
when(host.getResourceState()).thenReturn(ResourceState.Enabled);
|
||||||
|
when(host.getStatus()).thenReturn(Status.Up);
|
||||||
|
when(host.getType()).thenReturn(Host.Type.Storage);
|
||||||
|
|
||||||
|
when(hostDao.findById(hostId)).thenReturn(host);
|
||||||
|
|
||||||
|
unmanagedVMsManager.selectKVMHostForImportingInCluster(cluster, hostId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = CloudRuntimeException.class)
|
||||||
|
public void testSelectKVMHostForImportingInClusterWithImportInstanceIdInvalidStatus() {
|
||||||
|
Long hostId = 1L;
|
||||||
|
ClusterVO cluster = getClusterForTests();
|
||||||
|
HostVO host = Mockito.mock(HostVO.class);
|
||||||
|
when(host.getResourceState()).thenReturn(ResourceState.Enabled);
|
||||||
|
when(host.getStatus()).thenReturn(Status.Alert);
|
||||||
|
|
||||||
|
when(hostDao.findById(hostId)).thenReturn(host);
|
||||||
|
|
||||||
|
unmanagedVMsManager.selectKVMHostForImportingInCluster(cluster, hostId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = CloudRuntimeException.class)
|
||||||
|
public void testSelectKVMHostForImportingInClusterWithImportInstanceIdInvalidResourceState() {
|
||||||
|
Long hostId = 1L;
|
||||||
|
ClusterVO cluster = getClusterForTests();
|
||||||
|
HostVO host = Mockito.mock(HostVO.class);
|
||||||
|
when(host.getResourceState()).thenReturn(ResourceState.Disabled);
|
||||||
|
|
||||||
|
when(hostDao.findById(hostId)).thenReturn(host);
|
||||||
|
|
||||||
|
unmanagedVMsManager.selectKVMHostForImportingInCluster(cluster, hostId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = CloudRuntimeException.class)
|
||||||
|
public void testSelectKVMHostForImportingInClusterWithImportInstanceIdInvalidHostId() {
|
||||||
|
Long hostId = 1L;
|
||||||
|
ClusterVO cluster = getClusterForTests();
|
||||||
|
|
||||||
|
when(hostDao.findById(hostId)).thenReturn(null);
|
||||||
|
|
||||||
|
unmanagedVMsManager.selectKVMHostForImportingInCluster(cluster, hostId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSelectKVMHostForConversionInClusterWithImportInstanceIdEnabledHost() {
|
||||||
|
Long hostId = 1L;
|
||||||
|
ClusterVO cluster = getClusterForTests();
|
||||||
|
HostVO host = Mockito.mock(HostVO.class);
|
||||||
|
when(host.getResourceState()).thenReturn(ResourceState.Enabled);
|
||||||
|
when(host.getStatus()).thenReturn(Status.Up);
|
||||||
|
when(host.getType()).thenReturn(Host.Type.Routing);
|
||||||
|
when(host.getDataCenterId()).thenReturn(1L);
|
||||||
|
|
||||||
|
when(hostDao.findById(hostId)).thenReturn(host);
|
||||||
|
|
||||||
|
HostVO returnedHost = unmanagedVMsManager.selectKVMHostForConversionInCluster(cluster, hostId);
|
||||||
|
Assert.assertEquals(host, returnedHost);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSelectKVMHostForConversionInClusterWithImportInstanceIdDisabledHost() {
|
||||||
|
Long hostId = 1L;
|
||||||
|
ClusterVO cluster = getClusterForTests();
|
||||||
|
HostVO host = Mockito.mock(HostVO.class);
|
||||||
|
when(host.getResourceState()).thenReturn(ResourceState.Disabled);
|
||||||
|
when(host.getStatus()).thenReturn(Status.Up);
|
||||||
|
when(host.getType()).thenReturn(Host.Type.Routing);
|
||||||
|
when(host.getDataCenterId()).thenReturn(1L);
|
||||||
|
|
||||||
|
when(hostDao.findById(hostId)).thenReturn(host);
|
||||||
|
|
||||||
|
HostVO returnedHost = unmanagedVMsManager.selectKVMHostForConversionInCluster(cluster, hostId);
|
||||||
|
Assert.assertEquals(host, returnedHost);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSelectKVMHostForConversionInClusterWithImportInstanceIdSuccessCompatible() {
|
||||||
|
ClusterVO cluster = getClusterForTests();
|
||||||
|
HostVO host = Mockito.mock(HostVO.class);
|
||||||
|
|
||||||
|
when(hostDao.listByClusterHypervisorTypeAndHostCapability(cluster.getId(),
|
||||||
|
cluster.getHypervisorType(), Host.HOST_INSTANCE_CONVERSION)).thenReturn(List.of(host));
|
||||||
|
|
||||||
|
HostVO returnedHost = unmanagedVMsManager.selectKVMHostForConversionInCluster(cluster, null);
|
||||||
|
Assert.assertEquals(host, returnedHost);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSelectKVMHostForConversionInClusterWithImportInstanceIdSuccessNonCompatible() {
|
||||||
|
ClusterVO cluster = getClusterForTests();
|
||||||
|
HostVO host = Mockito.mock(HostVO.class);
|
||||||
|
|
||||||
|
when(hostDao.listByClusterHypervisorTypeAndHostCapability(cluster.getId(),
|
||||||
|
cluster.getHypervisorType(), Host.HOST_INSTANCE_CONVERSION)).thenReturn(List.of());
|
||||||
|
|
||||||
|
when(hostDao.listByClusterAndHypervisorType(cluster.getId(), cluster.getHypervisorType())).thenReturn(List.of(host));
|
||||||
|
|
||||||
|
HostVO returnedHost = unmanagedVMsManager.selectKVMHostForConversionInCluster(cluster, null);
|
||||||
|
Assert.assertEquals(host, returnedHost);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = CloudRuntimeException.class)
|
||||||
|
public void testSelectKVMHostForConversionInClusterWithImportInstanceIdFailure() {
|
||||||
|
ClusterVO cluster = getClusterForTests();
|
||||||
|
|
||||||
|
when(hostDao.listByClusterHypervisorTypeAndHostCapability(cluster.getId(),
|
||||||
|
cluster.getHypervisorType(), Host.HOST_INSTANCE_CONVERSION)).thenReturn(List.of());
|
||||||
|
|
||||||
|
when(hostDao.listByClusterAndHypervisorType(cluster.getId(), cluster.getHypervisorType())).thenReturn(List.of());
|
||||||
|
|
||||||
|
unmanagedVMsManager.selectKVMHostForConversionInCluster(cluster, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = CloudRuntimeException.class)
|
||||||
|
public void testSelectKVMHostForConversionInClusterWithImportInstanceIdInvalidZone() {
|
||||||
|
Long hostId = 1L;
|
||||||
|
ClusterVO cluster = getClusterForTests();
|
||||||
|
HostVO host = Mockito.mock(HostVO.class);
|
||||||
|
when(host.getResourceState()).thenReturn(ResourceState.Enabled);
|
||||||
|
when(host.getStatus()).thenReturn(Status.Up);
|
||||||
|
when(host.getType()).thenReturn(Host.Type.Routing);
|
||||||
|
when(host.getDataCenterId()).thenReturn(2L);
|
||||||
|
|
||||||
|
when(hostDao.findById(hostId)).thenReturn(host);
|
||||||
|
|
||||||
|
unmanagedVMsManager.selectKVMHostForConversionInCluster(cluster, hostId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = CloudRuntimeException.class)
|
||||||
|
public void testSelectKVMHostForConversionInClusterWithImportInstanceIdInvalidType() {
|
||||||
|
Long hostId = 1L;
|
||||||
|
ClusterVO cluster = getClusterForTests();
|
||||||
|
HostVO host = Mockito.mock(HostVO.class);
|
||||||
|
when(host.getResourceState()).thenReturn(ResourceState.Enabled);
|
||||||
|
when(host.getStatus()).thenReturn(Status.Up);
|
||||||
|
when(host.getType()).thenReturn(Host.Type.SecondaryStorage);
|
||||||
|
|
||||||
|
when(hostDao.findById(hostId)).thenReturn(host);
|
||||||
|
|
||||||
|
unmanagedVMsManager.selectKVMHostForConversionInCluster(cluster, hostId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = CloudRuntimeException.class)
|
||||||
|
public void testSelectKVMHostForConversionInClusterWithImportInstanceIdInvalidStatus() {
|
||||||
|
Long hostId = 1L;
|
||||||
|
ClusterVO cluster = getClusterForTests();
|
||||||
|
HostVO host = Mockito.mock(HostVO.class);
|
||||||
|
when(host.getResourceState()).thenReturn(ResourceState.Enabled);
|
||||||
|
when(host.getStatus()).thenReturn(Status.Down);
|
||||||
|
|
||||||
|
when(hostDao.findById(hostId)).thenReturn(host);
|
||||||
|
|
||||||
|
unmanagedVMsManager.selectKVMHostForConversionInCluster(cluster, hostId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = CloudRuntimeException.class)
|
||||||
|
public void testSelectKVMHostForConversionInClusterWithImportInstanceIdInvalidResourceState() {
|
||||||
|
Long hostId = 1L;
|
||||||
|
ClusterVO cluster = getClusterForTests();
|
||||||
|
HostVO host = Mockito.mock(HostVO.class);
|
||||||
|
when(host.getResourceState()).thenReturn(ResourceState.Maintenance);
|
||||||
|
|
||||||
|
when(hostDao.findById(hostId)).thenReturn(host);
|
||||||
|
|
||||||
|
unmanagedVMsManager.selectKVMHostForConversionInCluster(cluster, hostId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = CloudRuntimeException.class)
|
||||||
|
public void testSelectKVMHostForConversionInClusterWithImportInstanceIdInvalidHostId() {
|
||||||
|
Long hostId = 1L;
|
||||||
|
ClusterVO cluster = getClusterForTests();
|
||||||
|
|
||||||
|
when(hostDao.findById(hostId)).thenReturn(null);
|
||||||
|
|
||||||
|
unmanagedVMsManager.selectKVMHostForConversionInCluster(cluster, hostId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
|
||||||
|
|
@ -1467,7 +1467,10 @@ class CsForwardingRules(CsDataBag):
|
||||||
self.fw.append(["filter", "", fw7])
|
self.fw.append(["filter", "", fw7])
|
||||||
|
|
||||||
def forward_vpc(self, rule):
|
def forward_vpc(self, rule):
|
||||||
fw_prerout_rule = "-A PREROUTING -d %s/32 " % (rule["public_ip"])
|
fw_prerout_rule = "-A PREROUTING"
|
||||||
|
if "source_cidr_list" in rule and rule["source_cidr_list"]:
|
||||||
|
fw_prerout_rule += " -s %s" % rule["source_cidr_list"]
|
||||||
|
fw_prerout_rule += " -d %s/32" % rule["public_ip"]
|
||||||
if not rule["protocol"] == "any":
|
if not rule["protocol"] == "any":
|
||||||
fw_prerout_rule += " -m %s -p %s" % (rule["protocol"], rule["protocol"])
|
fw_prerout_rule += " -m %s -p %s" % (rule["protocol"], rule["protocol"])
|
||||||
if not rule["public_ports"] == "any":
|
if not rule["public_ports"] == "any":
|
||||||
|
|
@ -1476,7 +1479,10 @@ class CsForwardingRules(CsDataBag):
|
||||||
if not rule["internal_ports"] == "any":
|
if not rule["internal_ports"] == "any":
|
||||||
fw_prerout_rule += ":" + self.portsToString(rule["internal_ports"], "-")
|
fw_prerout_rule += ":" + self.portsToString(rule["internal_ports"], "-")
|
||||||
|
|
||||||
fw_output_rule = "-A OUTPUT -d %s/32" % rule["public_ip"]
|
fw_output_rule = "-A OUTPUT"
|
||||||
|
if "source_cidr_list" in rule and rule["source_cidr_list"]:
|
||||||
|
fw_output_rule += " -s %s" % rule["source_cidr_list"]
|
||||||
|
fw_output_rule += " -d %s/32" % rule["public_ip"]
|
||||||
if not rule["protocol"] == "any":
|
if not rule["protocol"] == "any":
|
||||||
fw_output_rule += " -m %s -p %s" % (rule["protocol"], rule["protocol"])
|
fw_output_rule += " -m %s -p %s" % (rule["protocol"], rule["protocol"])
|
||||||
if not rule["public_ports"] == "any":
|
if not rule["public_ports"] == "any":
|
||||||
|
|
|
||||||
|
|
@ -379,7 +379,7 @@ class CsNetfilter(object):
|
||||||
return self.rule
|
return self.rule
|
||||||
|
|
||||||
def to_str(self, delete=False):
|
def to_str(self, delete=False):
|
||||||
""" Convert the rule back into aynactically correct iptables command """
|
""" Convert the rule back into syntactically correct iptables command """
|
||||||
# Order is important
|
# Order is important
|
||||||
order = ['-A', '-s', '-d', '!_-d', '-i', '!_-i', '-p', '-m', '-m2', '--icmp-type', '--state',
|
order = ['-A', '-s', '-d', '!_-d', '-i', '!_-i', '-p', '-m', '-m2', '--icmp-type', '--state',
|
||||||
'--dport', '--destination-port', '-o', '!_-o', '-j', '--set-xmark', '--checksum',
|
'--dport', '--destination-port', '-o', '!_-o', '-j', '--set-xmark', '--checksum',
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,8 @@
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
|
|
||||||
|
import logging
|
||||||
|
|
||||||
def merge(dbag, rules):
|
def merge(dbag, rules):
|
||||||
for rule in rules["rules"]:
|
for rule in rules["rules"]:
|
||||||
source_ip = rule["source_ip_address"]
|
source_ip = rule["source_ip_address"]
|
||||||
|
|
@ -33,6 +35,8 @@ def merge(dbag, rules):
|
||||||
newrule["public_ports"] = rule["source_port_range"]
|
newrule["public_ports"] = rule["source_port_range"]
|
||||||
newrule["internal_ports"] = rule["destination_port_range"]
|
newrule["internal_ports"] = rule["destination_port_range"]
|
||||||
newrule["protocol"] = rule["protocol"]
|
newrule["protocol"] = rule["protocol"]
|
||||||
|
if "source_cidr_list" in rule:
|
||||||
|
newrule["source_cidr_list"] = rule["source_cidr_list"]
|
||||||
|
|
||||||
if not revoke:
|
if not revoke:
|
||||||
if rules["type"] == "staticnatrules":
|
if rules["type"] == "staticnatrules":
|
||||||
|
|
@ -59,7 +63,7 @@ def merge(dbag, rules):
|
||||||
for forward in dbag[source_ip]:
|
for forward in dbag[source_ip]:
|
||||||
if ruleCompare(forward, newrule):
|
if ruleCompare(forward, newrule):
|
||||||
index = dbag[source_ip].index(forward)
|
index = dbag[source_ip].index(forward)
|
||||||
print("removing index %s" % str(index))
|
logging.info("Removing forwarding rule [%s] at index [%s].", forward, index)
|
||||||
if not index == -1:
|
if not index == -1:
|
||||||
del dbag[source_ip][index]
|
del dbag[source_ip][index]
|
||||||
|
|
||||||
|
|
@ -74,4 +78,18 @@ def ruleCompare(ruleA, ruleB):
|
||||||
return ruleA["public_ip"] == ruleB["public_ip"]
|
return ruleA["public_ip"] == ruleB["public_ip"]
|
||||||
elif ruleA["type"] == "forward":
|
elif ruleA["type"] == "forward":
|
||||||
return ruleA["public_ip"] == ruleB["public_ip"] and ruleA["public_ports"] == ruleB["public_ports"] \
|
return ruleA["public_ip"] == ruleB["public_ip"] and ruleA["public_ports"] == ruleB["public_ports"] \
|
||||||
and ruleA["protocol"] == ruleB["protocol"]
|
and ruleA["protocol"] == ruleB["protocol"] and cidrsConflict(ruleA.get("source_cidr_list"), ruleB.get("source_cidr_list"))
|
||||||
|
|
||||||
|
# Same validation as in com.cloud.network.firewall.FirewallManagerImpl.detectConflictingCidrs
|
||||||
|
def cidrsConflict(cidrListA, cidrListB):
|
||||||
|
if not cidrListA and not cidrListB:
|
||||||
|
return True
|
||||||
|
if not cidrListA:
|
||||||
|
return False
|
||||||
|
if not cidrListB:
|
||||||
|
return False
|
||||||
|
|
||||||
|
cidrListA = set(cidrListA.split(","))
|
||||||
|
cidrListB = set(cidrListB.split(","))
|
||||||
|
|
||||||
|
return len(cidrListA.intersection(cidrListB)) > 0
|
||||||
|
|
|
||||||
|
|
@ -1000,7 +1000,7 @@
|
||||||
"label.for": "for",
|
"label.for": "for",
|
||||||
"label.forbidden": "Forbidden",
|
"label.forbidden": "Forbidden",
|
||||||
"label.forced": "Force",
|
"label.forced": "Force",
|
||||||
"label.force.ms.to.import.vm.files": "Force MS to import VM file(s) to temporary storage",
|
"label.force.ms.to.import.vm.files": "Force MS to export OVF from VMware to temporary storage",
|
||||||
"label.force.stop": "Force stop",
|
"label.force.stop": "Force stop",
|
||||||
"label.force.reboot": "Force reboot",
|
"label.force.reboot": "Force reboot",
|
||||||
"label.forceencap": "Force UDP encapsulation of ESP packets",
|
"label.forceencap": "Force UDP encapsulation of ESP packets",
|
||||||
|
|
@ -1564,6 +1564,7 @@
|
||||||
"label.noselect": "No thanks",
|
"label.noselect": "No thanks",
|
||||||
"label.not.found": "Not found",
|
"label.not.found": "Not found",
|
||||||
"label.not.suitable": "Not suitable",
|
"label.not.suitable": "Not suitable",
|
||||||
|
"label.not.supported": "Not supported",
|
||||||
"label.notifications": "Notifications",
|
"label.notifications": "Notifications",
|
||||||
"label.nsx": "NSX",
|
"label.nsx": "NSX",
|
||||||
"label.nsx.provider": "NSX Provider",
|
"label.nsx.provider": "NSX Provider",
|
||||||
|
|
@ -2102,6 +2103,7 @@
|
||||||
"label.source": "Select Import-Export Source Hypervisor",
|
"label.source": "Select Import-Export Source Hypervisor",
|
||||||
"label.source.based": "SourceBased",
|
"label.source.based": "SourceBased",
|
||||||
"label.sourcecidr": "Source CIDR",
|
"label.sourcecidr": "Source CIDR",
|
||||||
|
"label.sourcecidrlist": "Source CIDR list",
|
||||||
"label.sourcehost": "Source host",
|
"label.sourcehost": "Source host",
|
||||||
"label.sourceipaddress": "Source IP address",
|
"label.sourceipaddress": "Source IP address",
|
||||||
"label.sourceipaddressnetworkid": "Network ID of source IP address",
|
"label.sourceipaddressnetworkid": "Network ID of source IP address",
|
||||||
|
|
@ -3399,8 +3401,9 @@
|
||||||
"message.select.destination.image.stores": "Please select Image Store(s) to which data is to be migrated to",
|
"message.select.destination.image.stores": "Please select Image Store(s) to which data is to be migrated to",
|
||||||
"message.select.disk.offering": "Please select a disk offering for disk",
|
"message.select.disk.offering": "Please select a disk offering for disk",
|
||||||
"message.select.end.date.and.time": "Select an end date & time.",
|
"message.select.end.date.and.time": "Select an end date & time.",
|
||||||
"message.select.kvm.host.instance.conversion": "(Optional) Select a KVM host in the cluster to perform the instance conversion through virt-v2v",
|
"message.select.kvm.host.instance.conversion": "(Optional) Select a KVM host in the zone to perform the instance conversion through virt-v2v",
|
||||||
"message.select.load.balancer.rule": "Please select a load balancer rule for your AutoScale Group.",
|
"message.select.kvm.host.instance.import": "(Optional) Select a KVM host in the cluster to perform the importing of the converted instance",
|
||||||
|
"message.select.load.balancer.rule": "Please select a load balancer rule for your AutoScale Instance group.",
|
||||||
"message.select.migration.policy": "Please select a migration policy.",
|
"message.select.migration.policy": "Please select a migration policy.",
|
||||||
"message.select.nic.network": "Please select a Network for NIC",
|
"message.select.nic.network": "Please select a Network for NIC",
|
||||||
"message.select.security.groups": "Please select security group(s) for your new Instance.",
|
"message.select.security.groups": "Please select security group(s) for your new Instance.",
|
||||||
|
|
|
||||||
|
|
@ -352,7 +352,7 @@
|
||||||
"label.choose.saml.identity": "Escolha um provedor de identidade SAML",
|
"label.choose.saml.identity": "Escolha um provedor de identidade SAML",
|
||||||
"label.cidr": "CIDR",
|
"label.cidr": "CIDR",
|
||||||
"label.cidr.destination.network": "CIDR da rede de destino",
|
"label.cidr.destination.network": "CIDR da rede de destino",
|
||||||
"label.cidrlist": "Lista de CIDR ",
|
"label.cidrlist": "Lista de CIDRs",
|
||||||
"label.cisco.nexus1000v.ip.address": "Endere\u00e7o IP do Nexus 1000v",
|
"label.cisco.nexus1000v.ip.address": "Endere\u00e7o IP do Nexus 1000v",
|
||||||
"label.cisco.nexus1000v.password": "Senha do Nexus 1000v",
|
"label.cisco.nexus1000v.password": "Senha do Nexus 1000v",
|
||||||
"label.cisco.nexus1000v.username": "Usu\u00e1rio do Nexus 1000v",
|
"label.cisco.nexus1000v.username": "Usu\u00e1rio do Nexus 1000v",
|
||||||
|
|
@ -1510,6 +1510,7 @@
|
||||||
"label.sockettimeout": "Tempo limite no socket",
|
"label.sockettimeout": "Tempo limite no socket",
|
||||||
"label.source.based": "SourceBased",
|
"label.source.based": "SourceBased",
|
||||||
"label.sourcecidr": "CIDR de origem",
|
"label.sourcecidr": "CIDR de origem",
|
||||||
|
"label.sourcecidrlist": "Lista de CIDRs de origem",
|
||||||
"label.sourceipaddress": "Endere\u00e7o IP de origem",
|
"label.sourceipaddress": "Endere\u00e7o IP de origem",
|
||||||
"label.sourcenat": "Source NAT",
|
"label.sourcenat": "Source NAT",
|
||||||
"label.sourcenatsupported": "Suporte \u00e0 source NAT",
|
"label.sourcenatsupported": "Suporte \u00e0 source NAT",
|
||||||
|
|
|
||||||
|
|
@ -186,7 +186,14 @@
|
||||||
<div class="resource-detail-item__label">{{ $t('label.cpu') }}</div>
|
<div class="resource-detail-item__label">{{ $t('label.cpu') }}</div>
|
||||||
<div class="resource-detail-item__details">
|
<div class="resource-detail-item__details">
|
||||||
<appstore-outlined />
|
<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-if="'cpunumber' in resource && 'cpuspeed' in resource">{{ resource.cpunumber }} CPU x {{ (resource.cpuspeed / 1000.0).toFixed(2) }} GHz
|
||||||
|
<a-tooltip placement="top">
|
||||||
|
<template #title>
|
||||||
|
{{ resource.cpuspeed }} MHz
|
||||||
|
</template>
|
||||||
|
<QuestionCircleOutlined />
|
||||||
|
</a-tooltip>
|
||||||
|
</span>
|
||||||
<span v-else>{{ resource.cputotal }}</span>
|
<span v-else>{{ resource.cputotal }}</span>
|
||||||
<a-tag v-if="resource.arch" style="margin-left: 10px">
|
<a-tag v-if="resource.arch" style="margin-left: 10px">
|
||||||
{{ resource.arch }}
|
{{ resource.arch }}
|
||||||
|
|
@ -233,7 +240,16 @@
|
||||||
<div class="resource-detail-item" v-else-if="resource.memorytotalgb">
|
<div class="resource-detail-item" v-else-if="resource.memorytotalgb">
|
||||||
<div class="resource-detail-item__label">{{ $t('label.memory') }}</div>
|
<div class="resource-detail-item__label">{{ $t('label.memory') }}</div>
|
||||||
<div class="resource-detail-item__details">
|
<div class="resource-detail-item__details">
|
||||||
<bulb-outlined />{{ resource.memorytotalgb + ' ' + $t('label.memory') }}
|
<bulb-outlined />
|
||||||
|
<span>
|
||||||
|
{{ resource.memorytotalgb + ' ' + $t('label.memory') }}
|
||||||
|
<a-tooltip placement="top">
|
||||||
|
<template #title>
|
||||||
|
{{ (resource.memorytotal/(1024**2)).toFixed(3) }} MB
|
||||||
|
</template>
|
||||||
|
<QuestionCircleOutlined />
|
||||||
|
</a-tooltip>
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<span v-if="resource.memoryusedgb">
|
<span v-if="resource.memoryusedgb">
|
||||||
|
|
|
||||||
|
|
@ -299,7 +299,6 @@ export default {
|
||||||
if (response) {
|
if (response) {
|
||||||
const oauthproviders = response.listoauthproviderresponse.oauthprovider || []
|
const oauthproviders = response.listoauthproviderresponse.oauthprovider || []
|
||||||
oauthproviders.forEach(item => {
|
oauthproviders.forEach(item => {
|
||||||
this.socialLogin = true
|
|
||||||
if (item.provider === 'google') {
|
if (item.provider === 'google') {
|
||||||
this.googleprovider = item.enabled
|
this.googleprovider = item.enabled
|
||||||
this.googleclientid = item.clientid
|
this.googleclientid = item.clientid
|
||||||
|
|
@ -311,6 +310,7 @@ export default {
|
||||||
this.githubredirecturi = item.redirecturi
|
this.githubredirecturi = item.redirecturi
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
this.socialLogin = this.googleprovider || this.githubprovider
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
api('forgotPassword', {}).then(response => {
|
api('forgotPassword', {}).then(response => {
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,7 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="form">
|
<div class="form">
|
||||||
<div class="form__item" ref="newCidrList">
|
<div class="form__item" ref="newCidrList">
|
||||||
<tooltip-label :title="$t('label.cidrlist')" bold :tooltip="createLoadBalancerRuleParams.cidrlist.description" :tooltip-placement="'right'"/>
|
<tooltip-label :title="$t('label.sourcecidrlist')" bold :tooltip="createLoadBalancerRuleParams.cidrlist.description" :tooltip-placement="'right'"/>
|
||||||
<a-input v-model:value="newRule.cidrlist"></a-input>
|
<a-input v-model:value="newRule.cidrlist"></a-input>
|
||||||
</div>
|
</div>
|
||||||
<div class="form__item">
|
<div class="form__item">
|
||||||
|
|
@ -126,7 +126,7 @@
|
||||||
:rowKey="record => record.id">
|
:rowKey="record => record.id">
|
||||||
<template #bodyCell="{ column, record }">
|
<template #bodyCell="{ column, record }">
|
||||||
<template v-if="column.key === 'cidrlist'">
|
<template v-if="column.key === 'cidrlist'">
|
||||||
<span style="white-space: pre-line"> {{ record.cidrlist?.replaceAll(" ", "\n") }}</span>
|
<span style="white-space: pre-line"> {{ record.cidrlist?.replaceAll(",", "\n") }}</span>
|
||||||
</template>
|
</template>
|
||||||
<template v-if="column.key === 'algorithm'">
|
<template v-if="column.key === 'algorithm'">
|
||||||
{{ returnAlgorithmName(record.algorithm) }}
|
{{ returnAlgorithmName(record.algorithm) }}
|
||||||
|
|
@ -808,7 +808,7 @@ export default {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'cidrlist',
|
key: 'cidrlist',
|
||||||
title: this.$t('label.cidrlist')
|
title: this.$t('label.sourcecidrlist')
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'protocol',
|
key: 'protocol',
|
||||||
|
|
|
||||||
|
|
@ -72,6 +72,12 @@
|
||||||
<a-select-option value="udp" :label="$t('label.udp')">{{ $t('label.udp') }}</a-select-option>
|
<a-select-option value="udp" :label="$t('label.udp')">{{ $t('label.udp') }}</a-select-option>
|
||||||
</a-select>
|
</a-select>
|
||||||
</div>
|
</div>
|
||||||
|
<div v-if="isVPC()">
|
||||||
|
<div class="form__item" ref="newCidrList">
|
||||||
|
<tooltip-label :title="$t('label.sourcecidrlist')" bold :tooltip="apiParams.cidrlist.description" :tooltip-placement="'right'"/>
|
||||||
|
<a-input v-model:value="newRule.cidrlist"></a-input>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="form__item" style="margin-left: auto;">
|
<div class="form__item" style="margin-left: auto;">
|
||||||
<div class="form__label">{{ $t('label.add.vm') }}</div>
|
<div class="form__label">{{ $t('label.add.vm') }}</div>
|
||||||
<a-button :disabled="!('createPortForwardingRule' in $store.getters.apis)" type="primary" @click="openAddVMModal">{{ $t('label.add') }}</a-button>
|
<a-button :disabled="!('createPortForwardingRule' in $store.getters.apis)" type="primary" @click="openAddVMModal">{{ $t('label.add') }}</a-button>
|
||||||
|
|
@ -108,6 +114,9 @@
|
||||||
<template v-if="column.key === 'protocol'">
|
<template v-if="column.key === 'protocol'">
|
||||||
{{ getCapitalise(record.protocol) }}
|
{{ getCapitalise(record.protocol) }}
|
||||||
</template>
|
</template>
|
||||||
|
<template v-if="column.key === 'cidrlist'">
|
||||||
|
<span style="white-space: pre-line"> {{ record.cidrlist?.replaceAll(",", "\n") }}</span>
|
||||||
|
</template>
|
||||||
<template v-if="column.key === 'vm'">
|
<template v-if="column.key === 'vm'">
|
||||||
<div><desktop-outlined/>
|
<div><desktop-outlined/>
|
||||||
<router-link
|
<router-link
|
||||||
|
|
@ -334,9 +343,11 @@ import Status from '@/components/widgets/Status'
|
||||||
import TooltipButton from '@/components/widgets/TooltipButton'
|
import TooltipButton from '@/components/widgets/TooltipButton'
|
||||||
import BulkActionView from '@/components/view/BulkActionView'
|
import BulkActionView from '@/components/view/BulkActionView'
|
||||||
import eventBus from '@/config/eventBus'
|
import eventBus from '@/config/eventBus'
|
||||||
|
import TooltipLabel from '@/components/widgets/TooltipLabel.vue'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
|
TooltipLabel,
|
||||||
Status,
|
Status,
|
||||||
TooltipButton,
|
TooltipButton,
|
||||||
BulkActionView
|
BulkActionView
|
||||||
|
|
@ -399,6 +410,11 @@ export default {
|
||||||
key: 'protocol',
|
key: 'protocol',
|
||||||
title: this.$t('label.protocol')
|
title: this.$t('label.protocol')
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
key: 'cidrlist',
|
||||||
|
title: this.$t('label.sourcecidrlist'),
|
||||||
|
hidden: !this.isVPC()
|
||||||
|
},
|
||||||
{
|
{
|
||||||
title: this.$t('label.state'),
|
title: this.$t('label.state'),
|
||||||
dataIndex: 'state'
|
dataIndex: 'state'
|
||||||
|
|
@ -411,7 +427,7 @@ export default {
|
||||||
key: 'actions',
|
key: 'actions',
|
||||||
title: this.$t('label.actions')
|
title: this.$t('label.actions')
|
||||||
}
|
}
|
||||||
],
|
].filter(item => !item.hidden),
|
||||||
tiers: {
|
tiers: {
|
||||||
loading: false,
|
loading: false,
|
||||||
data: []
|
data: []
|
||||||
|
|
@ -450,7 +466,8 @@ export default {
|
||||||
vmPage: 1,
|
vmPage: 1,
|
||||||
vmPageSize: 10,
|
vmPageSize: 10,
|
||||||
vmCount: 0,
|
vmCount: 0,
|
||||||
searchQuery: null
|
searchQuery: null,
|
||||||
|
cidrlist: ''
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
|
@ -458,6 +475,9 @@ export default {
|
||||||
return this.selectedRowKeys.length > 0
|
return this.selectedRowKeys.length > 0
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
beforeCreate () {
|
||||||
|
this.apiParams = this.$getApiParams('createPortForwardingRule')
|
||||||
|
},
|
||||||
created () {
|
created () {
|
||||||
console.log(this.resource)
|
console.log(this.resource)
|
||||||
this.initForm()
|
this.initForm()
|
||||||
|
|
@ -830,6 +850,9 @@ export default {
|
||||||
onSearch (value) {
|
onSearch (value) {
|
||||||
this.searchQuery = value
|
this.searchQuery = value
|
||||||
this.fetchVirtualMachines()
|
this.fetchVirtualMachines()
|
||||||
|
},
|
||||||
|
isVPC () {
|
||||||
|
return 'vpcid' in this.resource
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -31,27 +31,23 @@
|
||||||
<template #label>
|
<template #label>
|
||||||
<tooltip-label :title="$t('label.account')" :tooltip="apiParams.addAccountToProject.account.description"/>
|
<tooltip-label :title="$t('label.account')" :tooltip="apiParams.addAccountToProject.account.description"/>
|
||||||
</template>
|
</template>
|
||||||
<a-select
|
<a-auto-complete
|
||||||
show-search
|
|
||||||
v-model:value="form.account"
|
v-model:value="form.account"
|
||||||
:placeholder="apiParams.addAccountToProject.account.description"
|
:placeholder="apiParams.addAccountToProject.account.description"
|
||||||
v-focus="true"
|
:filterOption="filterOption"
|
||||||
:filterOption="false"
|
:options="accounts"
|
||||||
@search="fetchAccounts"
|
>
|
||||||
>
|
<template v-if="load.accounts" #notFoundContent>
|
||||||
<template v-if="load.accounts" #notFoundContent>
|
<a-spin size="small" />
|
||||||
<a-spin size="small" />
|
</template>
|
||||||
</template>
|
<template v-if="!load.accounts" #option="account">
|
||||||
<template v-if="!load.accounts">
|
<span v-if="account.icon">
|
||||||
<a-select-option v-for="account in accounts" :key="account.name" :value="account.name">
|
<resource-icon :image="account.icon.base64image" size="1x" style="margin-right: 5px"/>
|
||||||
<span v-if="account.icon">
|
</span>
|
||||||
<resource-icon :image="account.icon.base64image" size="1x" style="margin-right: 5px"/>
|
<block-outlined v-else style="margin-right: 5px" />
|
||||||
</span>
|
{{ account.name }}
|
||||||
<block-outlined v-else style="margin-right: 5px" />
|
</template>
|
||||||
{{ account.name }}
|
</a-auto-complete>
|
||||||
</a-select-option>
|
|
||||||
</template>
|
|
||||||
</a-select>
|
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item name="email" ref="email">
|
<a-form-item name="email" ref="email">
|
||||||
<template #label>
|
<template #label>
|
||||||
|
|
@ -121,27 +117,23 @@
|
||||||
<template #label>
|
<template #label>
|
||||||
<tooltip-label :title="$t('label.name')" :tooltip="apiParams.addUserToProject.username.description"/>
|
<tooltip-label :title="$t('label.name')" :tooltip="apiParams.addUserToProject.username.description"/>
|
||||||
</template>
|
</template>
|
||||||
<a-select
|
<a-auto-complete
|
||||||
show-search
|
|
||||||
v-model:value="form.username"
|
v-model:value="form.username"
|
||||||
:placeholder="apiParams.addUserToProject.username.description"
|
:placeholder="apiParams.addUserToProject.username.description"
|
||||||
v-focus="true"
|
:filterOption="filterOption"
|
||||||
:filterOption="false"
|
:options="users"
|
||||||
@search="fetchUsers"
|
|
||||||
>
|
>
|
||||||
<template v-if="load.users" #notFoundContent>
|
<template v-if="load.users" #notFoundContent>
|
||||||
<a-spin size="small" />
|
<a-spin size="small" />
|
||||||
</template>
|
</template>
|
||||||
<template v-if="!load.users">
|
<template v-if="!load.users" #option="user">
|
||||||
<a-select-option v-for="user in users" :key="user.username" :value="user.username">
|
<span v-if="user.icon">
|
||||||
<span v-if="user.icon">
|
<resource-icon :image="user.icon.base64image" size="1x" style="margin-right: 5px"/>
|
||||||
<resource-icon :image="user.icon.base64image" size="1x" style="margin-right: 5px"/>
|
</span>
|
||||||
</span>
|
<block-outlined v-else style="margin-right: 5px" />
|
||||||
<block-outlined v-else style="margin-right: 5px" />
|
{{ user.firstName + ' ' + user.lastName + " (" + user.username + ")" }}
|
||||||
{{ user.firstname + ' ' + user.lastname + " (" + user.username + ")" }}
|
|
||||||
</a-select-option>
|
|
||||||
</template>
|
</template>
|
||||||
</a-select>
|
</a-auto-complete>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item name="email" ref="email">
|
<a-form-item name="email" ref="email">
|
||||||
<template #label>
|
<template #label>
|
||||||
|
|
@ -254,6 +246,11 @@ export default {
|
||||||
this.fetchProjectRoles()
|
this.fetchProjectRoles()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
filterOption (input, option) {
|
||||||
|
return (
|
||||||
|
option.value.toUpperCase().indexOf(input.toUpperCase()) >= 0
|
||||||
|
)
|
||||||
|
},
|
||||||
fetchUsers (keyword) {
|
fetchUsers (keyword) {
|
||||||
this.load.users = true
|
this.load.users = true
|
||||||
const params = { listall: true, showicon: true }
|
const params = { listall: true, showicon: true }
|
||||||
|
|
@ -261,13 +258,28 @@ export default {
|
||||||
params.keyword = keyword
|
params.keyword = keyword
|
||||||
}
|
}
|
||||||
api('listUsers', params).then(response => {
|
api('listUsers', params).then(response => {
|
||||||
this.users = response.listusersresponse.user ? response.listusersresponse.user : []
|
this.users = this.parseUsers(response?.listusersresponse?.user)
|
||||||
}).catch(error => {
|
}).catch(error => {
|
||||||
this.$notifyError(error)
|
this.$notifyError(error)
|
||||||
}).finally(() => {
|
}).finally(() => {
|
||||||
this.load.users = false
|
this.load.users = false
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
parseUsers (users) {
|
||||||
|
if (!users) {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
|
||||||
|
return users.map(user => {
|
||||||
|
return {
|
||||||
|
value: user.username,
|
||||||
|
username: user.username,
|
||||||
|
firstName: user.firstname,
|
||||||
|
lastName: user.lastname,
|
||||||
|
icon: user.icon
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
fetchAccounts (keyword) {
|
fetchAccounts (keyword) {
|
||||||
this.load.accounts = true
|
this.load.accounts = true
|
||||||
const params = { domainid: this.resource.domainid, showicon: true }
|
const params = { domainid: this.resource.domainid, showicon: true }
|
||||||
|
|
@ -275,13 +287,26 @@ export default {
|
||||||
params.keyword = keyword
|
params.keyword = keyword
|
||||||
}
|
}
|
||||||
api('listAccounts', params).then(response => {
|
api('listAccounts', params).then(response => {
|
||||||
this.accounts = response.listaccountsresponse.account || []
|
this.accounts = this.parseAccounts(response?.listaccountsresponse?.account)
|
||||||
}).catch(error => {
|
}).catch(error => {
|
||||||
this.$notifyError(error)
|
this.$notifyError(error)
|
||||||
}).finally(() => {
|
}).finally(() => {
|
||||||
this.load.accounts = false
|
this.load.accounts = false
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
parseAccounts (accounts) {
|
||||||
|
if (!accounts) {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
|
||||||
|
return accounts.map(account => {
|
||||||
|
return {
|
||||||
|
value: account.name,
|
||||||
|
name: account.name,
|
||||||
|
icon: account.icon
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
fetchProjectRoles () {
|
fetchProjectRoles () {
|
||||||
this.load.projectRoles = true
|
this.load.projectRoles = true
|
||||||
api('listProjectRoles', {
|
api('listProjectRoles', {
|
||||||
|
|
|
||||||
|
|
@ -164,6 +164,18 @@
|
||||||
@handle-checkselectpair-change="updateSelectedKvmHostForConversion"
|
@handle-checkselectpair-change="updateSelectedKvmHostForConversion"
|
||||||
/>
|
/>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
|
<a-form-item name="importhostid" ref="importhostid">
|
||||||
|
<check-box-select-pair
|
||||||
|
layout="vertical"
|
||||||
|
v-if="cluster.hypervisortype === 'KVM' && selectedVmwareVcenter"
|
||||||
|
:resourceKey="cluster.id"
|
||||||
|
:selectOptions="kvmHostsForImporting"
|
||||||
|
:checkBoxLabel="$t('message.select.kvm.host.instance.import')"
|
||||||
|
:defaultCheckBoxValue="false"
|
||||||
|
:reversed="false"
|
||||||
|
@handle-checkselectpair-change="updateSelectedKvmHostForImporting"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
<a-form-item name="convertstorageoption" ref="convertstorageoption">
|
<a-form-item name="convertstorageoption" ref="convertstorageoption">
|
||||||
<check-box-select-pair
|
<check-box-select-pair
|
||||||
layout="vertical"
|
layout="vertical"
|
||||||
|
|
@ -494,7 +506,9 @@ export default {
|
||||||
switches: {},
|
switches: {},
|
||||||
loading: false,
|
loading: false,
|
||||||
kvmHostsForConversion: [],
|
kvmHostsForConversion: [],
|
||||||
|
kvmHostsForImporting: [],
|
||||||
selectedKvmHostForConversion: null,
|
selectedKvmHostForConversion: null,
|
||||||
|
selectedKvmHostForImporting: null,
|
||||||
storageOptionsForConversion: [
|
storageOptionsForConversion: [
|
||||||
{
|
{
|
||||||
id: 'secondary',
|
id: 'secondary',
|
||||||
|
|
@ -730,6 +744,7 @@ export default {
|
||||||
page: 1
|
page: 1
|
||||||
})
|
})
|
||||||
this.fetchKvmHostsForConversion()
|
this.fetchKvmHostsForConversion()
|
||||||
|
this.fetchKvmHostsForImporting()
|
||||||
if (this.resource?.disk?.length > 1) {
|
if (this.resource?.disk?.length > 1) {
|
||||||
this.updateSelectedRootDisk()
|
this.updateSelectedRootDisk()
|
||||||
}
|
}
|
||||||
|
|
@ -914,6 +929,25 @@ export default {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
fetchKvmHostsForConversion () {
|
fetchKvmHostsForConversion () {
|
||||||
|
api('listHosts', {
|
||||||
|
zoneid: this.zoneid,
|
||||||
|
hypervisor: this.cluster.hypervisortype,
|
||||||
|
type: 'Routing',
|
||||||
|
state: 'Up'
|
||||||
|
}).then(json => {
|
||||||
|
this.kvmHostsForConversion = json.listhostsresponse.host || []
|
||||||
|
this.kvmHostsForConversion = this.kvmHostsForConversion.filter(host => ['Enabled', 'Disabled'].includes(host.resourcestate))
|
||||||
|
this.kvmHostsForConversion.map(host => {
|
||||||
|
host.name = host.name + ' [Pod=' + host.podname + '] [Cluster=' + host.clustername + ']'
|
||||||
|
if (host.instanceconversionsupported !== null && host.instanceconversionsupported !== undefined && host.instanceconversionsupported) {
|
||||||
|
host.name = host.name + ' (' + this.$t('label.supported') + ')'
|
||||||
|
} else {
|
||||||
|
host.name = host.name + ' (' + this.$t('label.not.supported') + ')'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
fetchKvmHostsForImporting () {
|
||||||
api('listHosts', {
|
api('listHosts', {
|
||||||
clusterid: this.cluster.id,
|
clusterid: this.cluster.id,
|
||||||
hypervisor: this.cluster.hypervisortype,
|
hypervisor: this.cluster.hypervisortype,
|
||||||
|
|
@ -921,20 +955,22 @@ export default {
|
||||||
state: 'Up',
|
state: 'Up',
|
||||||
resourcestate: 'Enabled'
|
resourcestate: 'Enabled'
|
||||||
}).then(json => {
|
}).then(json => {
|
||||||
this.kvmHostsForConversion = json.listhostsresponse.host || []
|
this.kvmHostsForImporting = json.listhostsresponse.host || []
|
||||||
this.kvmHostsForConversion.map(host => {
|
|
||||||
if (host.instanceconversionsupported !== null && host.instanceconversionsupported !== undefined && host.instanceconversionsupported) {
|
|
||||||
host.name = host.name + ' (' + this.$t('label.supported') + ')'
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
fetchStoragePoolsForConversion () {
|
fetchStoragePoolsForConversion () {
|
||||||
if (this.selectedStorageOptionForConversion === 'primary') {
|
if (this.selectedStorageOptionForConversion === 'primary') {
|
||||||
api('listStoragePools', {
|
const params = {
|
||||||
zoneid: this.cluster.zoneid,
|
clusterid: this.cluster.id,
|
||||||
status: 'Up'
|
status: 'Up'
|
||||||
}).then(json => {
|
}
|
||||||
|
if (this.selectedKvmHostForConversion) {
|
||||||
|
const kvmHost = this.kvmHostsForConversion.filter(x => x.id === this.selectedKvmHostForConversion)[0]
|
||||||
|
if (kvmHost.clusterid !== this.cluster.id) {
|
||||||
|
params.scope = 'ZONE'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
api('listStoragePools', params).then(json => {
|
||||||
this.storagePoolsForConversion = json.liststoragepoolsresponse.storagepool || []
|
this.storagePoolsForConversion = json.liststoragepoolsresponse.storagepool || []
|
||||||
})
|
})
|
||||||
} else if (this.selectedStorageOptionForConversion === 'local') {
|
} else if (this.selectedStorageOptionForConversion === 'local') {
|
||||||
|
|
@ -948,6 +984,14 @@ export default {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
updateSelectedKvmHostForImporting (clusterid, checked, value) {
|
||||||
|
if (checked) {
|
||||||
|
this.selectedKvmHostForImporting = value
|
||||||
|
} else {
|
||||||
|
this.selectedKvmHostForImporting = null
|
||||||
|
this.resetStorageOptionsForConversion()
|
||||||
|
}
|
||||||
|
},
|
||||||
updateSelectedKvmHostForConversion (clusterid, checked, value) {
|
updateSelectedKvmHostForConversion (clusterid, checked, value) {
|
||||||
if (checked) {
|
if (checked) {
|
||||||
this.selectedKvmHostForConversion = value
|
this.selectedKvmHostForConversion = value
|
||||||
|
|
@ -1099,6 +1143,9 @@ export default {
|
||||||
if (this.selectedKvmHostForConversion) {
|
if (this.selectedKvmHostForConversion) {
|
||||||
params.convertinstancehostid = this.selectedKvmHostForConversion
|
params.convertinstancehostid = this.selectedKvmHostForConversion
|
||||||
}
|
}
|
||||||
|
if (this.selectedKvmHostForImporting) {
|
||||||
|
params.importinstancehostid = this.selectedKvmHostForImporting
|
||||||
|
}
|
||||||
if (this.selectedStoragePoolForConversion) {
|
if (this.selectedStoragePoolForConversion) {
|
||||||
params.convertinstancepoolid = this.selectedStoragePoolForConversion
|
params.convertinstancepoolid = this.selectedStoragePoolForConversion
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -840,7 +840,8 @@ export default {
|
||||||
options: {
|
options: {
|
||||||
zoneid: _.get(this.zone, 'id'),
|
zoneid: _.get(this.zone, 'id'),
|
||||||
podid: this.podId,
|
podid: this.podId,
|
||||||
hypervisor: this.destinationHypervisor
|
hypervisor: this.destinationHypervisor,
|
||||||
|
allocationstate: 'Enabled'
|
||||||
},
|
},
|
||||||
field: 'clusterid'
|
field: 'clusterid'
|
||||||
},
|
},
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue