resolve conflict with main

This commit is contained in:
Manoj Kumar 2026-04-01 09:59:16 +05:30
commit f524bbe0e2
No known key found for this signature in database
GPG Key ID: E952B7234D2C6F88
123 changed files with 2221 additions and 509 deletions

20
.codespellrc Normal file
View File

@ -0,0 +1,20 @@
# 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.
[codespell]
ignore-words = .github/linters/codespell.txt
skip = systemvm/agent/noVNC/*,ui/package.json,ui/package-lock.json,ui/public/js/less.min.js,ui/public/locales/*.json,server/src/test/java/org/apache/cloudstack/network/ssl/CertServiceTest.java,test/integration/smoke/test_ssl_offloading.py

View File

@ -22,8 +22,19 @@
version: 2
updates:
- package-ecosystem: "maven" # See documentation for possible values
directory: "/" # Location of package manifests
- package-ecosystem: "github-actions"
directory: "/"
open-pull-requests-limit: 2
schedule:
interval: "weekly"
groups:
github-actions-dependencies:
patterns:
- "*"
cooldown:
default-days: 7
- package-ecosystem: "maven"
directory: "/"
schedule:
interval: "daily"
cooldown:

View File

@ -30,7 +30,7 @@ jobs:
build:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v6
- name: Set up JDK 17
uses: actions/setup-java@v5

View File

@ -217,7 +217,7 @@ jobs:
smoke/test_list_volumes"]
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v6
with:
fetch-depth: 0

View File

@ -32,7 +32,7 @@ jobs:
name: codecov
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v6
with:
fetch-depth: 0

View File

@ -35,7 +35,7 @@ jobs:
language: ["actions"]
steps:
- name: Checkout repository
uses: actions/checkout@v5
uses: actions/checkout@v6
- name: Initialize CodeQL
uses: github/codeql-action/init@v3
with:

View File

@ -47,7 +47,7 @@ jobs:
- name: Set Docker repository name
run: echo "DOCKER_REPOSITORY=apache" >> $GITHUB_ENV
- uses: actions/checkout@v5
- uses: actions/checkout@v6
- name: Set ACS version
run: echo "ACS_VERSION=$(grep '<version>' pom.xml | head -2 | tail -1 | cut -d'>' -f2 |cut -d'<' -f1)" >> $GITHUB_ENV

View File

@ -32,7 +32,7 @@ jobs:
name: Main Sonar JaCoCo Build
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v6
with:
fetch-depth: 0

View File

@ -32,7 +32,7 @@ jobs:
runs-on: ubuntu-22.04
steps:
- name: Check Out
uses: actions/checkout@v5
uses: actions/checkout@v6
- name: Install
run: |
python -m pip install --upgrade pip

View File

@ -30,7 +30,7 @@ jobs:
build:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v6
- name: Set up JDK 17
uses: actions/setup-java@v5
with:

View File

@ -33,7 +33,7 @@ jobs:
name: Sonar JaCoCo Coverage
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v6
with:
ref: "refs/pull/${{ github.event.number }}/merge"
fetch-depth: 0

View File

@ -31,7 +31,7 @@ jobs:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v6
- name: Set up Node
uses: actions/setup-node@v5

View File

@ -162,17 +162,15 @@ repos:
- id: forbid-submodules
- id: mixed-line-ending
- id: trailing-whitespace
files: ^(LICENSE|NOTICE)$|\.(bat|cfg|cs|css|gitignore|header|in|install|java|md|properties|py|rb|rc|sh|sql|te|template|txt|ucls|vue|xml|xsl|yaml|yml)$|^cloud-cli/bindir/cloud-tool$|^debian/changelog$
files: ^(LICENSE|NOTICE)$|README$|\.(bat|cfg|config|cs|css|erb|gitignore|header|in|install|java|md|properties|py|rb|rc|sh|sql|svg|te|template|txt|ucls|vue|xml|xsl|yaml|yml)$|^cloud-cli/bindir/cloud-tool$|^debian/changelog$
args: [--markdown-linebreak-ext=md]
exclude: ^services/console-proxy/rdpconsole/src/test/doc/freerdp-debug-log\.txt$
- repo: https://github.com/codespell-project/codespell
rev: v2.4.1
rev: v2.4.2
hooks:
- id: codespell
name: run codespell
description: Check spelling with codespell
args: [--ignore-words=.github/linters/codespell.txt]
exclude: ^systemvm/agent/noVNC/|^ui/package\.json$|^ui/package-lock\.json$|^ui/public/js/less\.min\.js$|^ui/public/locales/.*[^n].*\.json$|^server/src/test/java/org/apache/cloudstack/network/ssl/CertServiceTest.java$|^test/integration/smoke/test_ssl_offloading.py$
- repo: https://github.com/pycqa/flake8
rev: 7.0.0
hooks:
@ -186,7 +184,7 @@ repos:
description: check Markdown files with markdownlint
args: [--config=.github/linters/.markdown-lint.yml]
types: [markdown]
files: \.(md|mdown|markdown)$
files: \.md$
- repo: https://github.com/adrienverge/yamllint
rev: v1.37.1
hooks:

View File

@ -33,6 +33,7 @@ public class NicTO extends NetworkTO {
boolean dpdkEnabled;
Integer mtu;
Long networkId;
boolean enabled;
String networkSegmentName;
@ -154,4 +155,12 @@ public class NicTO extends NetworkTO {
public void setNetworkSegmentName(String networkSegmentName) {
this.networkSegmentName = networkSegmentName;
}
public boolean isEnabled() {
return enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
}

View File

@ -138,6 +138,8 @@ public interface AccountService {
Long finalizeAccountId(String accountName, Long domainId, Long projectId, boolean enabledOnly);
Long finalizeAccountId(Long accountId, String accountName, Long domainId, Long projectId);
/**
* returns the user account object for a given user id
* @param userId user id

View File

@ -167,4 +167,6 @@ public interface Nic extends Identity, InternalIdentity {
String getIPv6Address();
Integer getMtu();
boolean isEnabled();
}

View File

@ -52,6 +52,7 @@ public class NicProfile implements InternalIdentity, Serializable {
boolean defaultNic;
Integer networkRate;
boolean isSecurityGroupEnabled;
boolean enabled;
Integer orderIndex;
@ -87,6 +88,7 @@ public class NicProfile implements InternalIdentity, Serializable {
broadcastType = network.getBroadcastDomainType();
trafficType = network.getTrafficType();
format = nic.getAddressFormat();
enabled = nic.isEnabled();
iPv4Address = nic.getIPv4Address();
iPv4Netmask = nic.getIPv4Netmask();
@ -414,6 +416,14 @@ public class NicProfile implements InternalIdentity, Serializable {
this.ipv4AllocationRaceCheck = ipv4AllocationRaceCheck;
}
public boolean isEnabled() {
return enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
//
// OTHER METHODS
//

View File

@ -40,6 +40,7 @@ import org.apache.cloudstack.api.command.user.vm.ScaleVMCmd;
import org.apache.cloudstack.api.command.user.vm.StartVMCmd;
import org.apache.cloudstack.api.command.user.vm.UpdateDefaultNicForVMCmd;
import org.apache.cloudstack.api.command.user.vm.UpdateVMCmd;
import org.apache.cloudstack.api.command.user.vm.UpdateVmNicCmd;
import org.apache.cloudstack.api.command.user.vm.UpdateVmNicIpCmd;
import org.apache.cloudstack.api.command.user.vm.UpgradeVMCmd;
import org.apache.cloudstack.api.command.user.vmgroup.CreateVMGroupCmd;
@ -152,6 +153,8 @@ public interface UserVmService {
*/
UserVm updateNicIpForVirtualMachine(UpdateVmNicIpCmd cmd);
UserVm updateVirtualMachineNic(UpdateVmNicCmd cmd);
UserVm recoverVirtualMachine(RecoverVMCmd cmd) throws ResourceAllocationException;
/**
@ -524,6 +527,7 @@ public interface UserVmService {
* @param userId user ID
* @param serviceOffering service offering for the imported VM
* @param sshPublicKey ssh key for the imported VM
* @param guestOsId guest OS ID for the imported VM (if not passed, then the guest OS of the template will be used)
* @param hostName the name for the imported VM
* @param hypervisorType hypervisor type for the imported VM
* @param customParameters details for the imported VM
@ -533,7 +537,7 @@ public interface UserVmService {
* @throws InsufficientCapacityException in case of errors
*/
UserVm importVM(final DataCenter zone, final Host host, final VirtualMachineTemplate template, final String instanceNameInternal, final String displayName, final Account owner, final String userData, final Account caller, final Boolean isDisplayVm, final String keyboard,
final long accountId, final long userId, final ServiceOffering serviceOffering, final String sshPublicKey,
final long accountId, final long userId, final ServiceOffering serviceOffering, final String sshPublicKey, final Long guestOsId,
final String hostName, final HypervisorType hypervisorType, final Map<String, String> customParameters,
final VirtualMachine.PowerState powerState, final LinkedHashMap<String, List<NicProfile>> networkNicMap) throws InsufficientCapacityException;

View File

@ -124,6 +124,9 @@ public interface VirtualMachine extends RunningOn, ControlledEntity, Partition,
s_fsm.addTransition(new Transition<State, Event>(State.Stopping, VirtualMachine.Event.StopRequested, State.Stopping, null));
s_fsm.addTransition(new Transition<State, Event>(State.Stopping, VirtualMachine.Event.AgentReportShutdowned, State.Stopped, Arrays.asList(new Impact[]{Impact.USAGE})));
s_fsm.addTransition(new Transition<State, Event>(State.Expunging, VirtualMachine.Event.OperationFailed, State.Expunging,null));
// Note: In addition to the Stopped -> Error transition for failed VM creation,
// a VM can also transition from Expunging to Error on OperationFailedToError.
s_fsm.addTransition(new Transition<State, Event>(State.Expunging, VirtualMachine.Event.OperationFailedToError, State.Error, null));
s_fsm.addTransition(new Transition<State, Event>(State.Expunging, VirtualMachine.Event.ExpungeOperation, State.Expunging,null));
s_fsm.addTransition(new Transition<State, Event>(State.Error, VirtualMachine.Event.DestroyRequested, State.Expunging, null));
s_fsm.addTransition(new Transition<State, Event>(State.Error, VirtualMachine.Event.ExpungeOperation, State.Expunging, null));

View File

@ -20,6 +20,7 @@ public class ApiConstants {
public static final String ACCOUNT = "account";
public static final String ACCOUNTS = "accounts";
public static final String ACCOUNT_NAME = "accountname";
public static final String ACCOUNT_STATE_TO_SHOW = "accountstatetoshow";
public static final String ACCOUNT_TYPE = "accounttype";
public static final String ACCOUNT_ID = "accountid";
public static final String ACCOUNT_IDS = "accountids";

View File

@ -343,6 +343,8 @@ public interface ResponseGenerator {
UserVm findUserVmById(Long vmId);
UserVm findUserVmByNicId(Long nicId);
Volume findVolumeById(Long volumeId);
Account findAccountByNameDomain(String accountName, Long domainId);

View File

@ -30,6 +30,7 @@ import org.apache.cloudstack.api.BaseCmd;
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.ResponseObject;
import org.apache.cloudstack.api.ServerApiException;
import org.apache.cloudstack.api.response.GuestOSResponse;
import org.apache.cloudstack.api.response.HostResponse;
import org.apache.cloudstack.api.response.NetworkResponse;
import org.apache.cloudstack.api.response.StoragePoolResponse;
@ -171,6 +172,13 @@ public class ImportVmCmd extends ImportUnmanagedInstanceCmd {
description = "(only for importing VMs from VMware to KVM) optional - if true, forces virt-v2v conversions to write directly on the provided storage pool (avoid using temporary conversion pool).")
private Boolean forceConvertToPool;
@Parameter(name = ApiConstants.OS_ID,
type = CommandType.UUID,
entityType = GuestOSResponse.class,
since = "4.22.1",
description = "(only for importing VMs from VMware to KVM) optional - the ID of the guest OS for the imported VM.")
private Long guestOsId;
/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
@ -268,6 +276,10 @@ public class ImportVmCmd extends ImportUnmanagedInstanceCmd {
return BooleanUtils.toBooleanDefaultIfNull(forceConvertToPool, false);
}
public Long getGuestOsId() {
return guestOsId;
}
@Override
public String getEventDescription() {
String vmName = getName();

View File

@ -45,6 +45,11 @@ public class ListGuestOsCmd extends BaseListCmd {
@Parameter(name = ApiConstants.ID, type = CommandType.UUID, entityType = GuestOSResponse.class, description = "List by OS type ID")
private Long id;
@Parameter(name = ApiConstants.IDS, type = CommandType.LIST, collectionType = CommandType.UUID,
entityType = GuestOSResponse.class, since = "4.22.1",
description = "Comma separated list of OS types")
private List<Long> ids;
@Parameter(name = ApiConstants.OS_CATEGORY_ID, type = CommandType.UUID, entityType = GuestOSCategoryResponse.class, description = "List by OS Category ID")
private Long osCategoryId;
@ -63,6 +68,10 @@ public class ListGuestOsCmd extends BaseListCmd {
return id;
}
public List<Long> getIds() {
return ids;
}
public Long getOsCategoryId() {
return osCategoryId;
}

View File

@ -0,0 +1,95 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package org.apache.cloudstack.api.command.user.vm;
import org.apache.cloudstack.acl.RoleType;
import org.apache.cloudstack.api.ACL;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.ApiErrorCode;
import org.apache.cloudstack.api.BaseAsyncCmd;
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.ResponseObject;
import org.apache.cloudstack.api.ServerApiException;
import org.apache.cloudstack.api.response.NicResponse;
import org.apache.cloudstack.api.response.UserVmResponse;
import org.apache.cloudstack.context.CallContext;
import com.cloud.event.EventTypes;
import com.cloud.user.Account;
import com.cloud.uservm.UserVm;
import java.util.ArrayList;
import java.util.EnumSet;
@APICommand(name = "updateVmNic", description = "Updates the specified VM NIC", responseObject = NicResponse.class, requestHasSensitiveInfo = false, responseHasSensitiveInfo = false,
authorized = { RoleType.Admin, RoleType.ResourceAdmin, RoleType.DomainAdmin, RoleType.User })
public class UpdateVmNicCmd extends BaseAsyncCmd {
@ACL
@Parameter(name = ApiConstants.NIC_ID, type = CommandType.UUID, entityType = NicResponse.class, required = true, description = "NIC ID")
private Long nicId;
@Parameter(name = ApiConstants.ENABLED, type = CommandType.BOOLEAN, description = "If true, sets the NIC state to UP; otherwise, sets the NIC state to DOWN")
private Boolean enabled;
public Long getNicId() {
return nicId;
}
public Boolean isEnabled() {
return enabled;
}
@Override
public String getEventType() {
return EventTypes.EVENT_NIC_UPDATE;
}
@Override
public String getEventDescription() {
return String.format("Updating NIC %s.", getResourceUuid(ApiConstants.NIC_ID));
}
@Override
public long getEntityOwnerId() {
UserVm vm = _responseGenerator.findUserVmByNicId(nicId);
if (vm == null) {
return Account.ACCOUNT_ID_SYSTEM;
}
return vm.getAccountId();
}
@Override
public void execute() {
CallContext.current().setEventDetails(String.format("NIC ID: %s", getResourceUuid(ApiConstants.NIC_ID)));
UserVm result = _userVmService.updateVirtualMachineNic(this);
ArrayList<ApiConstants.VMDetails> dc = new ArrayList<>();
dc.add(ApiConstants.VMDetails.valueOf("nics"));
EnumSet<ApiConstants.VMDetails> details = EnumSet.copyOf(dc);
if (result != null){
UserVmResponse response = _responseGenerator.createUserVmResponse(ResponseObject.ResponseView.Restricted, "virtualmachine", details, result).get(0);
response.setResponseName(getCommandName());
this.setResponseObject(response);
} else {
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to update NIC from VM.");
}
}
}

View File

@ -46,7 +46,6 @@ public class CreateStaticRouteCmd extends BaseAsyncCreateCmd {
@Parameter(name = ApiConstants.GATEWAY_ID,
type = CommandType.UUID,
entityType = PrivateGatewayResponse.class,
required = true,
description = "The gateway ID we are creating static route for. Mutually exclusive with the nexthop parameter")
private Long gatewayId;

View File

@ -146,6 +146,10 @@ public class NicResponse extends BaseResponse {
@Param(description = "Public IP address associated with this NIC via Static NAT rule")
private String publicIp;
@SerializedName(ApiConstants.ENABLED)
@Param(description = "whether the NIC is enabled or not")
private Boolean isEnabled;
@SerializedName("dnsrecordurl")
@Param(description = "Public IP address associated with this NIC via Static NAT rule")
private String dnsRecordUrl;
@ -421,6 +425,14 @@ public class NicResponse extends BaseResponse {
this.publicIp = publicIp;
}
public Boolean getEnabled() {
return isEnabled;
}
public void setEnabled(Boolean enabled) {
isEnabled = enabled;
}
public void setDnsRecordUrl(String dnsRecordUrl) {
this.dnsRecordUrl = dnsRecordUrl;
}

View File

@ -51,6 +51,14 @@ public class UnmanagedInstanceResponse extends BaseResponse {
@Param(description = "The name of the host to which Instance belongs")
private String hostName;
@SerializedName(ApiConstants.HYPERVISOR)
@Param(description = "The hypervisor to which Instance belongs")
private String hypervisor;
@SerializedName(ApiConstants.HYPERVISOR_VERSION)
@Param(description = "The hypervisor version of the host to which Instance belongs")
private String hypervisorVersion;
@SerializedName(ApiConstants.POWER_STATE)
@Param(description = "The power state of the Instance")
private String powerState;
@ -140,6 +148,22 @@ public class UnmanagedInstanceResponse extends BaseResponse {
this.hostName = hostName;
}
public String getHypervisor() {
return hypervisor;
}
public void setHypervisor(String hypervisor) {
this.hypervisor = hypervisor;
}
public String getHypervisorVersion() {
return hypervisorVersion;
}
public void setHypervisorVersion(String hypervisorVersion) {
this.hypervisorVersion = hypervisorVersion;
}
public String getPowerState() {
return powerState;
}

View File

@ -25,11 +25,13 @@ import org.apache.cloudstack.api.command.admin.volume.ImportVolumeCmd;
import org.apache.cloudstack.api.response.ListResponse;
import org.apache.cloudstack.api.response.VolumeForImportResponse;
import org.apache.cloudstack.api.response.VolumeResponse;
import org.apache.cloudstack.framework.config.ConfigKey;
import org.apache.cloudstack.framework.config.Configurable;
import java.util.Arrays;
import java.util.List;
public interface VolumeImportUnmanageService extends PluggableService {
public interface VolumeImportUnmanageService extends PluggableService, Configurable {
List<Hypervisor.HypervisorType> SUPPORTED_HYPERVISORS =
Arrays.asList(Hypervisor.HypervisorType.KVM, Hypervisor.HypervisorType.VMware);
@ -37,6 +39,15 @@ public interface VolumeImportUnmanageService extends PluggableService {
List<Storage.StoragePoolType> SUPPORTED_STORAGE_POOL_TYPES_FOR_KVM = Arrays.asList(Storage.StoragePoolType.NetworkFilesystem,
Storage.StoragePoolType.Filesystem, Storage.StoragePoolType.RBD);
ConfigKey<Boolean> AllowImportVolumeWithBackingFile = new ConfigKey<>(Boolean.class,
"allow.import.volume.with.backing.file",
"Advanced",
"false",
"If enabled, allows QCOW2 volumes with backing files to be imported or unmanaged",
true,
ConfigKey.Scope.Global,
null);
ListResponse<VolumeForImportResponse> listVolumesForImport(ListVolumesForImportCmd cmd);
VolumeResponse importVolume(ImportVolumeCmd cmd);

View File

@ -55,6 +55,9 @@ public class UnmanagedInstanceTO {
private String hostName;
private String hypervisorType;
private String hostHypervisorVersion;
private List<Disk> disks;
private List<Nic> nics;
@ -168,6 +171,22 @@ public class UnmanagedInstanceTO {
this.hostName = hostName;
}
public String getHypervisorType() {
return hypervisorType;
}
public void setHypervisorType(String hypervisorType) {
this.hypervisorType = hypervisorType;
}
public String getHostHypervisorVersion() {
return hostHypervisorVersion;
}
public void setHostHypervisorVersion(String hostHypervisorVersion) {
this.hostHypervisorVersion = hostHypervisorVersion;
}
public List<Disk> getDisks() {
return disks;
}

View File

@ -26,6 +26,8 @@ import static com.cloud.hypervisor.Hypervisor.HypervisorType.VMware;
public interface UnmanagedVMsManager extends VmImportService, UnmanageVMService, PluggableService, Configurable {
String VM_IMPORT_DEFAULT_TEMPLATE_NAME = "system-default-vm-import-dummy-template.iso";
String KVM_VM_IMPORT_DEFAULT_TEMPLATE_NAME = "kvm-default-vm-import-dummy-template";
ConfigKey<Boolean> UnmanageVMPreserveNic = new ConfigKey<>("Advanced", Boolean.class, "unmanage.vm.preserve.nics", "false",
"If set to true, do not remove VM nics (and its MAC addresses) when unmanaging a VM, leaving them allocated but not reserved. " +
"If set to false, nics are removed and MAC addresses can be reassigned", true, ConfigKey.Scope.Zone);

View File

@ -0,0 +1,27 @@
// 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;
public class UpdateVmNicAnswer extends Answer {
public UpdateVmNicAnswer() {
}
public UpdateVmNicAnswer(UpdateVmNicCommand cmd, boolean success, String result) {
super(cmd, success, result);
}
}

View File

@ -0,0 +1,51 @@
// 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;
public class UpdateVmNicCommand extends Command {
String nicMacAddress;
String instanceName;
Boolean enabled;
@Override
public boolean executeInSequence() {
return true;
}
protected UpdateVmNicCommand() {
}
public UpdateVmNicCommand(String nicMacAdderss, String instanceName, Boolean enabled) {
this.nicMacAddress = nicMacAdderss;
this.instanceName = instanceName;
this.enabled = enabled;
}
public String getNicMacAddress() {
return nicMacAddress;
}
public String getVmName() {
return instanceName;
}
public Boolean isEnabled() {
return enabled;
}
}

View File

@ -231,6 +231,8 @@ public interface VirtualMachineManager extends Manager {
Boolean updateDefaultNicForVM(VirtualMachine vm, Nic nic, Nic defaultNic);
boolean updateVmNic(VirtualMachine vm, Nic nic, Boolean enabled) throws ResourceUnavailableException;
/**
* @param vm
* @param network

View File

@ -153,6 +153,8 @@ import com.cloud.agent.api.UnPlugNicAnswer;
import com.cloud.agent.api.UnPlugNicCommand;
import com.cloud.agent.api.UnmanageInstanceCommand;
import com.cloud.agent.api.UnregisterVMCommand;
import com.cloud.agent.api.UpdateVmNicAnswer;
import com.cloud.agent.api.UpdateVmNicCommand;
import com.cloud.agent.api.VmDiskStatsEntry;
import com.cloud.agent.api.VmNetworkStatsEntry;
import com.cloud.agent.api.VmStatsEntry;
@ -6270,6 +6272,80 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
_jobMgr.marshallResultObject(result));
}
@Override
public boolean updateVmNic(VirtualMachine vm, Nic nic, Boolean enabled) {
Outcome<VirtualMachine> outcome = updateVmNicThroughJobQueue(vm, nic, enabled);
retrieveVmFromJobOutcome(outcome, vm.getUuid(), "updateVmNic");
try {
Object jobResult = retrieveResultFromJobOutcomeAndThrowExceptionIfNeeded(outcome);
if (jobResult instanceof Boolean) {
return BooleanUtils.isTrue((Boolean) jobResult);
}
} catch (ResourceUnavailableException | InsufficientCapacityException ex) {
throw new CloudRuntimeException(String.format("Exception while updating VM [%s] NIC. Check the logs for more information.", vm.getUuid()));
}
throw new CloudRuntimeException("Unexpected job execution result.");
}
private boolean orchestrateUpdateVmNic(final VirtualMachine vm, final Nic nic, final Boolean enabled) throws ResourceUnavailableException {
if (vm.getState() == State.Running) {
try {
UpdateVmNicCommand updateVmNicCmd = new UpdateVmNicCommand(nic.getMacAddress(), vm.getName(), enabled);
Commands cmds = new Commands(Command.OnError.Stop);
cmds.addCommand("updatevmnic", updateVmNicCmd);
_agentMgr.send(vm.getHostId(), cmds);
UpdateVmNicAnswer updateVmNicAnswer = cmds.getAnswer(UpdateVmNicAnswer.class);
if (updateVmNicAnswer == null || !updateVmNicAnswer.getResult()) {
logger.warn("Unable to update VM %s NIC [{}].", vm.getName(), nic.getUuid());
return false;
}
} catch (final OperationTimedoutException e) {
throw new AgentUnavailableException(String.format("Unable to update NIC %s for VM %s.", nic.getUuid(), vm.getUuid()), vm.getHostId(), e);
}
}
NicVO nicVo = _nicsDao.findById(nic.getId());
nicVo.setEnabled(enabled);
_nicsDao.persist(nicVo);
return true;
}
public Outcome<VirtualMachine> updateVmNicThroughJobQueue(final VirtualMachine vm, final Nic nic, final Boolean isNicEnabled) {
Long vmId = vm.getId();
String commandName = VmWorkUpdateNic.class.getName();
Pair<VmWorkJobVO, Long> pendingWorkJob = retrievePendingWorkJob(vmId, commandName);
VmWorkJobVO workJob = pendingWorkJob.first();
if (workJob == null) {
Pair<VmWorkJobVO, VmWork> newVmWorkJobAndInfo = createWorkJobAndWorkInfo(commandName, vmId);
workJob = newVmWorkJobAndInfo.first();
VmWorkUpdateNic workInfo = new VmWorkUpdateNic(newVmWorkJobAndInfo.second(), nic.getId(), isNicEnabled);
setCmdInfoAndSubmitAsyncJob(workJob, workInfo, vmId);
}
AsyncJobExecutionContext.getCurrentExecutionContext().joinJob(workJob.getId());
return new VmJobVirtualMachineOutcome(workJob, vmId);
}
@ReflectionUse
private Pair<JobInfo.Status, String> orchestrateUpdateVmNic(final VmWorkUpdateNic work) throws Exception {
VMInstanceVO vm = findVmById(work.getVmId());
final NicVO nic = _entityMgr.findById(NicVO.class, work.getNicId());
if (nic == null) {
throw new CloudRuntimeException(String.format("Unable to find NIC with ID %s.", work.getNicId()));
}
final boolean result = orchestrateUpdateVmNic(vm, nic, work.isEnabled());
return new Pair<>(JobInfo.Status.SUCCEEDED, _jobMgr.marshallResultObject(result));
}
private Pair<Long, Long> findClusterAndHostIdForVmFromVolumes(long vmId) {
Long clusterId = null;
Long hostId = null;

View File

@ -0,0 +1,38 @@
// 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.vm;
public class VmWorkUpdateNic extends VmWork {
private static final long serialVersionUID = -8957066627929113278L;
Long nicId;
Boolean enabled;
public VmWorkUpdateNic(VmWork vmWork, Long nicId, Boolean enabled) {
super(vmWork);
this.nicId = nicId;
this.enabled = enabled;
}
public Long getNicId() {
return nicId;
}
public Boolean isEnabled() {
return enabled;
}
}

View File

@ -2326,7 +2326,8 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra
for (final NetworkElement element : networkElements) {
if (providersToImplement.contains(element.getProvider())) {
if (!_networkModel.isProviderEnabledInPhysicalNetwork(_networkModel.getPhysicalNetworkId(network), element.getProvider().getName())) {
throw new CloudRuntimeException(String.format("Service provider %s either doesn't exist or is not enabled in physical network: %s", element.getProvider().getName(), _physicalNetworkDao.findById(network.getPhysicalNetworkId())));
throw new CloudRuntimeException(String.format("Service provider %s either doesn't exist or is not enabled in physical network: %s",
element.getProvider().getName(), _physicalNetworkDao.findById(network.getPhysicalNetworkId())));
}
if (element instanceof NetworkMigrationResponder) {
if (!((NetworkMigrationResponder) element).prepareMigration(profile, network, vm, dest, context)) {
@ -2633,6 +2634,10 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra
final NetworkGuru guru = AdapterBase.getAdapterByName(networkGurus, network.getGuruName());
guru.deallocate(network, profile, vm);
if (nic.getReservationStrategy() == Nic.ReservationStrategy.Create) {
applyProfileToNicForRelease(nic, profile);
_nicDao.update(nic.getId(), nic);
}
if (BooleanUtils.isNotTrue(preserveNics)) {
_nicDao.remove(nic.getId());
}

View File

@ -262,7 +262,7 @@ public class DomainDaoImpl extends GenericDaoBase<DomainVO, Long> implements Dom
SearchCriteria<DomainVO> sc = DomainPairSearch.create();
sc.setParameters("id", parentId, childId);
List<DomainVO> domainPair = listBy(sc);
List<DomainVO> domainPair = listIncludingRemovedBy(sc);
if ((domainPair != null) && (domainPair.size() == 2)) {
DomainVO d1 = domainPair.get(0);

View File

@ -35,7 +35,7 @@ public interface GuestOSDao extends GenericDao<GuestOSVO, Long> {
List<GuestOSVO> listByDisplayName(String displayName);
Pair<List<? extends GuestOS>, Integer> listGuestOSByCriteria(Long startIndex, Long pageSize, Long id, Long osCategoryId, String description, String keyword, Boolean forDisplay);
Pair<List<? extends GuestOS>, Integer> listGuestOSByCriteria(Long startIndex, Long pageSize, List<Long> ids, Long osCategoryId, String description, String keyword, Boolean forDisplay);
List<Long> listIdsByCategoryId(final long categoryId);
}

View File

@ -125,12 +125,12 @@ public class GuestOSDaoImpl extends GenericDaoBase<GuestOSVO, Long> implements G
return listBy(sc);
}
public Pair<List<? extends GuestOS>, Integer> listGuestOSByCriteria(Long startIndex, Long pageSize, Long id, Long osCategoryId, String description, String keyword, Boolean forDisplay) {
public Pair<List<? extends GuestOS>, Integer> listGuestOSByCriteria(Long startIndex, Long pageSize, List<Long> ids, Long osCategoryId, String description, String keyword, Boolean forDisplay) {
final Filter searchFilter = new Filter(GuestOSVO.class, "displayName", true, startIndex, pageSize);
final SearchCriteria<GuestOSVO> sc = createSearchCriteria();
if (id != null) {
sc.addAnd("id", SearchCriteria.Op.EQ, id);
if (CollectionUtils.isNotEmpty(ids)) {
sc.addAnd("id", SearchCriteria.Op.IN, ids.toArray());
}
if (osCategoryId != null) {

View File

@ -166,4 +166,12 @@ public interface VolumeDao extends GenericDao<VolumeVO, Long>, StateDao<Volume.S
int getVolumeCountByOfferingId(long diskOfferingId);
VolumeVO findByLastIdAndState(long lastVolumeId, Volume.State...states);
/**
* Retrieves volume by its externalId
*
* @param externalUuid
* @return Volume Object of matching search criteria
*/
VolumeVO findByExternalUuid(String externalUuid);
}

View File

@ -74,6 +74,7 @@ public class VolumeDaoImpl extends GenericDaoBase<VolumeVO, Long> implements Vol
private final SearchBuilder<VolumeVO> storeAndInstallPathSearch;
private final SearchBuilder<VolumeVO> volumeIdSearch;
protected GenericSearchBuilder<VolumeVO, Long> CountByAccount;
protected final SearchBuilder<VolumeVO> ExternalUuidSearch;
protected GenericSearchBuilder<VolumeVO, SumCount> primaryStorageSearch;
protected GenericSearchBuilder<VolumeVO, SumCount> primaryStorageSearch2;
protected GenericSearchBuilder<VolumeVO, SumCount> secondaryStorageSearch;
@ -459,6 +460,10 @@ public class VolumeDaoImpl extends GenericDaoBase<VolumeVO, Long> implements Vol
CountByAccount.and("idNIN", CountByAccount.entity().getId(), Op.NIN);
CountByAccount.done();
ExternalUuidSearch = createSearchBuilder();
ExternalUuidSearch.and("externalUuid", ExternalUuidSearch.entity().getExternalUuid(), Op.EQ);
ExternalUuidSearch.done();
primaryStorageSearch = createSearchBuilder(SumCount.class);
primaryStorageSearch.select("sum", Func.SUM, primaryStorageSearch.entity().getSize());
primaryStorageSearch.and("accountId", primaryStorageSearch.entity().getAccountId(), Op.EQ);
@ -934,4 +939,11 @@ public class VolumeDaoImpl extends GenericDaoBase<VolumeVO, Long> implements Vol
sc.and(sc.entity().getState(), SearchCriteria.Op.IN, (Object[]) states);
return sc.find();
}
@Override
public VolumeVO findByExternalUuid(String externalUuid) {
SearchCriteria<VolumeVO> sc = ExternalUuidSearch.create();
sc.setParameters("externalUuid", externalUuid);
return findOneBy(sc);
}
}

View File

@ -16,6 +16,14 @@
// under the License.
package com.cloud.upgrade.dao;
import org.apache.cloudstack.vm.UnmanagedVMsManager;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;
public class Upgrade42200to42210 extends DbUpgradeAbstractImpl implements DbUpgrade, DbUpgradeSystemVmTemplate {
@Override
@ -27,4 +35,47 @@ public class Upgrade42200to42210 extends DbUpgradeAbstractImpl implements DbUpgr
public String getUpgradedVersion() {
return "4.22.1.0";
}
@Override
public void performDataMigration(Connection conn) {
removeDuplicateKVMImportTemplates(conn);
}
private void removeDuplicateKVMImportTemplates(Connection conn) {
List<Long> templateIds = new ArrayList<>();
try (PreparedStatement selectStmt = conn.prepareStatement(String.format("SELECT id FROM cloud.vm_template WHERE name='%s' ORDER BY id ASC", UnmanagedVMsManager.KVM_VM_IMPORT_DEFAULT_TEMPLATE_NAME))) {
ResultSet rs = selectStmt.executeQuery();
while (rs.next()) {
templateIds.add(rs.getLong(1));
}
if (templateIds.size() <= 1) {
return;
}
logger.info("Removing duplicate template " + UnmanagedVMsManager.KVM_VM_IMPORT_DEFAULT_TEMPLATE_NAME + " entries");
Long firstTemplateId = templateIds.get(0);
String updateTemplateSql = "UPDATE cloud.vm_instance SET vm_template_id = ? WHERE vm_template_id = ?";
String deleteTemplateSql = "DELETE FROM cloud.vm_template WHERE id = ?";
try (PreparedStatement updateTemplateStmt = conn.prepareStatement(updateTemplateSql);
PreparedStatement deleteTemplateStmt = conn.prepareStatement(deleteTemplateSql)) {
for (int i = 1; i < templateIds.size(); i++) {
Long duplicateTemplateId = templateIds.get(i);
// Update VM references
updateTemplateStmt.setLong(1, firstTemplateId);
updateTemplateStmt.setLong(2, duplicateTemplateId);
updateTemplateStmt.executeUpdate();
// Delete duplicate dummy template
deleteTemplateStmt.setLong(1, duplicateTemplateId);
deleteTemplateStmt.executeUpdate();
}
}
} catch (Exception e) {
logger.warn("Failed to remove duplicate template " + UnmanagedVMsManager.KVM_VM_IMPORT_DEFAULT_TEMPLATE_NAME + " entries", e);
}
}
}

View File

@ -131,6 +131,9 @@ public class NicVO implements Nic {
@Column(name = "mtu")
Integer mtu;
@Column(name = "enabled")
boolean enabled;
@Transient
transient String nsxLogicalSwitchUuid;
@ -143,6 +146,7 @@ public class NicVO implements Nic {
this.networkId = configurationId;
this.state = State.Allocated;
this.vmType = vmType;
this.enabled = true;
}
@Override
@ -397,6 +401,14 @@ public class NicVO implements Nic {
this.nsxLogicalSwitchPortUuid = nsxLogicalSwitchPortUuid;
}
public boolean isEnabled() {
return enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
@Override
public int hashCode() {
return new HashCodeBuilder(17, 31).append(id).toHashCode();

View File

@ -67,7 +67,7 @@ public class SnapshotDataStoreDaoImpl extends GenericDaoBase<SnapshotDataStoreVO
private SearchBuilder<SnapshotDataStoreVO> searchFilteringStoreIdEqStoreRoleEqStateNeqRefCntNeq;
protected SearchBuilder<SnapshotDataStoreVO> searchFilteringStoreIdEqStateEqStoreRoleEqIdEqUpdateCountEqSnapshotIdEqVolumeIdEq;
private SearchBuilder<SnapshotDataStoreVO> stateSearch;
private SearchBuilder<SnapshotDataStoreVO> idStateNeqSearch;
private SearchBuilder<SnapshotDataStoreVO> idStateNinSearch;
protected SearchBuilder<SnapshotVO> snapshotVOSearch;
private SearchBuilder<SnapshotDataStoreVO> snapshotCreatedSearch;
private SearchBuilder<SnapshotDataStoreVO> dataStoreAndInstallPathSearch;
@ -146,10 +146,10 @@ public class SnapshotDataStoreDaoImpl extends GenericDaoBase<SnapshotDataStoreVO
stateSearch.done();
idStateNeqSearch = createSearchBuilder();
idStateNeqSearch.and(SNAPSHOT_ID, idStateNeqSearch.entity().getSnapshotId(), SearchCriteria.Op.EQ);
idStateNeqSearch.and(STATE, idStateNeqSearch.entity().getState(), SearchCriteria.Op.NEQ);
idStateNeqSearch.done();
idStateNinSearch = createSearchBuilder();
idStateNinSearch.and(SNAPSHOT_ID, idStateNinSearch.entity().getSnapshotId(), SearchCriteria.Op.EQ);
idStateNinSearch.and(STATE, idStateNinSearch.entity().getState(), SearchCriteria.Op.NOTIN);
idStateNinSearch.done();
snapshotVOSearch = snapshotDao.createSearchBuilder();
snapshotVOSearch.and(VOLUME_ID, snapshotVOSearch.entity().getVolumeId(), SearchCriteria.Op.EQ);
@ -480,7 +480,7 @@ public class SnapshotDataStoreDaoImpl extends GenericDaoBase<SnapshotDataStoreVO
@Override
public List<SnapshotDataStoreVO> findBySnapshotIdWithNonDestroyedState(long snapshotId) {
SearchCriteria<SnapshotDataStoreVO> sc = idStateNeqSearch.create();
SearchCriteria<SnapshotDataStoreVO> sc = idStateNinSearch.create();
sc.setParameters(SNAPSHOT_ID, snapshotId);
sc.setParameters(STATE, State.Destroyed.name());
return listBy(sc);
@ -488,7 +488,7 @@ public class SnapshotDataStoreDaoImpl extends GenericDaoBase<SnapshotDataStoreVO
@Override
public List<SnapshotDataStoreVO> findBySnapshotIdAndNotInDestroyedHiddenState(long snapshotId) {
SearchCriteria<SnapshotDataStoreVO> sc = idStateNeqSearch.create();
SearchCriteria<SnapshotDataStoreVO> sc = idStateNinSearch.create();
sc.setParameters(SNAPSHOT_ID, snapshotId);
sc.setParameters(STATE, State.Destroyed.name(), State.Hidden.name());
return listBy(sc);

View File

@ -18,3 +18,5 @@
--;
-- Schema upgrade cleanup from 4.22.0.0 to 4.22.1.0
--;
DROP VIEW IF EXISTS `cloud`.`account_netstats_view`;

View File

@ -33,3 +33,5 @@ UPDATE `cloud`.`alert` SET type = 34 WHERE name = 'ALERT.VR.PRIVATE.IFACE.MTU';
-- Update configuration 'kvm.ssh.to.agent' description and is_dynamic fields
UPDATE `cloud`.`configuration` SET description = 'True if the management server will restart the agent service via SSH into the KVM hosts after or during maintenance operations', is_dynamic = 1 WHERE name = 'kvm.ssh.to.agent';
UPDATE `cloud`.`vm_template` SET guest_os_id = 99 WHERE name = 'kvm-default-vm-import-dummy-template';

View File

@ -115,6 +115,9 @@ CALL `cloud`.`IDEMPOTENT_UPDATE_API_PERMISSION`('Resource Admin', 'deleteUserKey
-- Add conserve mode for VPC offerings
CALL `cloud`.`IDEMPOTENT_ADD_COLUMN`('cloud.vpc_offerings','conserve_mode', 'tinyint(1) unsigned NULL DEFAULT 0 COMMENT ''True if the VPC offering is IP conserve mode enabled, allowing public IP services to be used across multiple VPC tiers'' ');
--- Disable/enable NICs
CALL `cloud`.`IDEMPOTENT_ADD_COLUMN`('cloud.nics','enabled', 'TINYINT(1) NOT NULL DEFAULT 1 COMMENT ''Indicates whether the NIC is enabled or not'' ');
-- ======================================================================
-- DNS Framework Schema

View File

@ -1,31 +0,0 @@
-- 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.
-- cloud.account_netstats_view source
DROP VIEW IF EXISTS `cloud`.`account_netstats_view`;
CREATE VIEW `cloud`.`account_netstats_view` AS
select
`user_statistics`.`account_id` AS `account_id`,
(sum(`user_statistics`.`net_bytes_received`) + sum(`user_statistics`.`current_bytes_received`)) AS `bytesReceived`,
(sum(`user_statistics`.`net_bytes_sent`) + sum(`user_statistics`.`current_bytes_sent`)) AS `bytesSent`
from
`user_statistics`
group by
`user_statistics`.`account_id`;

View File

@ -39,8 +39,8 @@ select
`data_center`.`id` AS `data_center_id`,
`data_center`.`uuid` AS `data_center_uuid`,
`data_center`.`name` AS `data_center_name`,
`account_netstats_view`.`bytesReceived` AS `bytesReceived`,
`account_netstats_view`.`bytesSent` AS `bytesSent`,
`account_netstats`.`bytesReceived` AS `bytesReceived`,
`account_netstats`.`bytesSent` AS `bytesSent`,
`vmlimit`.`max` AS `vmLimit`,
`vmcount`.`count` AS `vmTotal`,
`runningvm`.`vmcount` AS `runningVms`,
@ -89,8 +89,15 @@ from
`cloud`.`domain` ON account.domain_id = domain.id
left join
`cloud`.`data_center` ON account.default_zone_id = data_center.id
left join
`cloud`.`account_netstats_view` ON account.id = account_netstats_view.account_id
left join lateral (
select
coalesce(sum(`user_statistics`.`net_bytes_received` + `user_statistics`.`current_bytes_received`), 0) AS `bytesReceived`,
coalesce(sum(`user_statistics`.`net_bytes_sent` + `user_statistics`.`current_bytes_sent`), 0) AS `bytesSent`
from
`cloud`.`user_statistics`
where
`user_statistics`.`account_id` = `account`.`id`
) AS `account_netstats` ON TRUE
left join
`cloud`.`resource_limit` vmlimit ON account.id = vmlimit.account_id
and vmlimit.type = 'user_vm' and vmlimit.tag IS NULL

View File

@ -76,6 +76,7 @@ select
nics.broadcast_uri broadcast_uri,
nics.isolation_uri isolation_uri,
nics.mtu mtu,
nics.enabled is_nic_enabled,
vpc.id vpc_id,
vpc.uuid vpc_uuid,
vpc.name vpc_name,

View File

@ -141,6 +141,7 @@ SELECT
`nics`.`mac_address` AS `mac_address`,
`nics`.`broadcast_uri` AS `broadcast_uri`,
`nics`.`isolation_uri` AS `isolation_uri`,
`nics`.`enabled` AS `is_nic_enabled`,
`nic_details`.`value` AS `dns_record_url`,
`vpc`.`id` AS `vpc_id`,
`vpc`.`uuid` AS `vpc_uuid`,

View File

@ -0,0 +1,48 @@
-- 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.
-- cloud_usage.quota_summary_view source
-- Create view for quota summary
DROP VIEW IF EXISTS `cloud_usage`.`quota_summary_view`;
CREATE VIEW `cloud_usage`.`quota_summary_view` AS
SELECT
cloud_usage.quota_account.account_id AS account_id,
cloud_usage.quota_account.quota_balance AS quota_balance,
cloud_usage.quota_account.quota_balance_date AS quota_balance_date,
cloud_usage.quota_account.quota_enforce AS quota_enforce,
cloud_usage.quota_account.quota_min_balance AS quota_min_balance,
cloud_usage.quota_account.quota_alert_date AS quota_alert_date,
cloud_usage.quota_account.quota_alert_type AS quota_alert_type,
cloud_usage.quota_account.last_statement_date AS last_statement_date,
cloud.account.uuid AS account_uuid,
cloud.account.account_name AS account_name,
cloud.account.state AS account_state,
cloud.account.removed AS account_removed,
cloud.domain.id AS domain_id,
cloud.domain.uuid AS domain_uuid,
cloud.domain.name AS domain_name,
cloud.domain.path AS domain_path,
cloud.domain.removed AS domain_removed,
cloud.projects.uuid AS project_uuid,
cloud.projects.name AS project_name,
cloud.projects.removed AS project_removed
FROM
cloud_usage.quota_account
INNER JOIN cloud.account ON (cloud.account.id = cloud_usage.quota_account.account_id)
INNER JOIN cloud.domain ON (cloud.domain.id = cloud.account.domain_id)
LEFT JOIN cloud.projects ON (cloud.account.type = 5 AND cloud.account.id = cloud.projects.project_account_id);

View File

@ -148,8 +148,8 @@ import java.util.HashSet;
import java.util.stream.Collectors;
import org.apache.commons.collections.CollectionUtils;
import static org.apache.cloudstack.vm.UnmanagedVMsManagerImpl.KVM_VM_IMPORT_DEFAULT_TEMPLATE_NAME;
import static org.apache.cloudstack.vm.UnmanagedVMsManagerImpl.VM_IMPORT_DEFAULT_TEMPLATE_NAME;
import static org.apache.cloudstack.vm.UnmanagedVMsManager.KVM_VM_IMPORT_DEFAULT_TEMPLATE_NAME;
import static org.apache.cloudstack.vm.UnmanagedVMsManager.VM_IMPORT_DEFAULT_TEMPLATE_NAME;
public class StorageSystemDataMotionStrategy implements DataMotionStrategy {
protected Logger logger = LogManager.getLogger(getClass());

View File

@ -64,7 +64,7 @@ public class SequenceFetcher {
try {
return future.get();
} catch (Exception e) {
logger.warn("Unable to get sequeunce for " + tg.table() + ":" + tg.pkColumnValue(), e);
logger.warn("Unable to get sequence for " + tg.table() + ":" + tg.pkColumnValue(), e);
return null;
}
}

View File

@ -0,0 +1,35 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package org.apache.cloudstack.quota;
import org.apache.commons.lang3.StringUtils;
public enum QuotaAccountStateFilter {
ALL, ACTIVE, REMOVED;
public static QuotaAccountStateFilter getValue(String value) {
if (StringUtils.isBlank(value)) {
return null;
}
for (QuotaAccountStateFilter state : values()) {
if (state.name().equalsIgnoreCase(value)) {
return state;
}
}
return null;
}
}

View File

@ -0,0 +1,32 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package org.apache.cloudstack.quota.dao;
import java.util.List;
import org.apache.cloudstack.quota.QuotaAccountStateFilter;
import org.apache.cloudstack.quota.vo.QuotaSummaryVO;
import com.cloud.utils.Pair;
import com.cloud.utils.db.GenericDao;
public interface QuotaSummaryDao extends GenericDao<QuotaSummaryVO, Long> {
Pair<List<QuotaSummaryVO>, Integer> listQuotaSummariesForAccountAndOrDomain(Long accountId, String accountName, Long domainId, String domainPath,
QuotaAccountStateFilter accountStateFilter, Long startIndex, Long pageSize);
}

View File

@ -0,0 +1,80 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package org.apache.cloudstack.quota.dao;
import java.util.List;
import org.apache.cloudstack.quota.QuotaAccountStateFilter;
import org.apache.cloudstack.quota.vo.QuotaSummaryVO;
import com.cloud.utils.Pair;
import com.cloud.utils.db.Filter;
import com.cloud.utils.db.GenericDaoBase;
import com.cloud.utils.db.SearchBuilder;
import com.cloud.utils.db.SearchCriteria;
import com.cloud.utils.db.Transaction;
import com.cloud.utils.db.TransactionCallback;
import com.cloud.utils.db.TransactionLegacy;
public class QuotaSummaryDaoImpl extends GenericDaoBase<QuotaSummaryVO, Long> implements QuotaSummaryDao {
@Override
public Pair<List<QuotaSummaryVO>, Integer> listQuotaSummariesForAccountAndOrDomain(Long accountId, String accountName, Long domainId, String domainPath,
QuotaAccountStateFilter accountStateFilter, Long startIndex, Long pageSize) {
SearchCriteria<QuotaSummaryVO> searchCriteria = createListQuotaSummariesSearchCriteria(accountId, accountName, domainId, domainPath, accountStateFilter);
Filter filter = new Filter(QuotaSummaryVO.class, "accountName", true, startIndex, pageSize);
return Transaction.execute(TransactionLegacy.USAGE_DB, (TransactionCallback<Pair<List<QuotaSummaryVO>, Integer>>) status -> searchAndCount(searchCriteria, filter));
}
protected SearchCriteria<QuotaSummaryVO> createListQuotaSummariesSearchCriteria(Long accountId, String accountName, Long domainId, String domainPath,
QuotaAccountStateFilter accountStateFilter) {
SearchCriteria<QuotaSummaryVO> searchCriteria = createListQuotaSummariesSearchBuilder(accountStateFilter).create();
searchCriteria.setParametersIfNotNull("accountId", accountId);
searchCriteria.setParametersIfNotNull("domainId", domainId);
if (accountName != null) {
searchCriteria.setParameters("accountName", "%" + accountName + "%");
}
if (domainPath != null) {
searchCriteria.setParameters("domainPath", domainPath + "%");
}
return searchCriteria;
}
protected SearchBuilder<QuotaSummaryVO> createListQuotaSummariesSearchBuilder(QuotaAccountStateFilter accountStateFilter) {
SearchBuilder<QuotaSummaryVO> searchBuilder = createSearchBuilder();
searchBuilder.and("accountId", searchBuilder.entity().getAccountId(), SearchCriteria.Op.EQ);
searchBuilder.and("accountName", searchBuilder.entity().getAccountName(), SearchCriteria.Op.LIKE);
searchBuilder.and("domainId", searchBuilder.entity().getDomainId(), SearchCriteria.Op.EQ);
searchBuilder.and("domainPath", searchBuilder.entity().getDomainPath(), SearchCriteria.Op.LIKE);
if (QuotaAccountStateFilter.REMOVED.equals(accountStateFilter)) {
searchBuilder.and("accountRemoved", searchBuilder.entity().getAccountRemoved(), SearchCriteria.Op.NNULL);
} else if (QuotaAccountStateFilter.ACTIVE.equals(accountStateFilter)) {
searchBuilder.and("accountRemoved", searchBuilder.entity().getAccountRemoved(), SearchCriteria.Op.NULL);
}
return searchBuilder;
}
}

View File

@ -0,0 +1,154 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package org.apache.cloudstack.quota.vo;
import java.math.BigDecimal;
import java.util.Date;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import com.cloud.user.Account;
@Entity
@Table(name = "quota_summary_view")
public class QuotaSummaryVO {
@Id
@Column(name = "account_id")
private Long accountId = null;
@Column(name = "quota_enforce")
private Integer quotaEnforce = 0;
@Column(name = "quota_balance")
private BigDecimal quotaBalance;
@Column(name = "quota_balance_date")
@Temporal(value = TemporalType.TIMESTAMP)
private Date quotaBalanceDate = null;
@Column(name = "quota_min_balance")
private BigDecimal quotaMinBalance;
@Column(name = "quota_alert_type")
private Integer quotaAlertType = null;
@Column(name = "quota_alert_date")
@Temporal(value = TemporalType.TIMESTAMP)
private Date quotaAlertDate = null;
@Column(name = "last_statement_date")
@Temporal(value = TemporalType.TIMESTAMP)
private Date lastStatementDate = null;
@Column(name = "account_uuid")
private String accountUuid;
@Column(name = "account_name")
private String accountName;
@Column(name = "account_state")
@Enumerated(EnumType.STRING)
private Account.State accountState;
@Column(name = "account_removed")
private Date accountRemoved;
@Column(name = "domain_id")
private Long domainId;
@Column(name = "domain_uuid")
private String domainUuid;
@Column(name = "domain_name")
private String domainName;
@Column(name = "domain_path")
private String domainPath;
@Column(name = "domain_removed")
private Date domainRemoved;
@Column(name = "project_uuid")
private String projectUuid;
@Column(name = "project_name")
private String projectName;
@Column(name = "project_removed")
private Date projectRemoved;
public Long getAccountId() {
return accountId;
}
public BigDecimal getQuotaBalance() {
return quotaBalance;
}
public String getAccountUuid() {
return accountUuid;
}
public String getAccountName() {
return accountName;
}
public Date getAccountRemoved() {
return accountRemoved;
}
public Account.State getAccountState() {
return accountState;
}
public Long getDomainId() {
return domainId;
}
public String getDomainUuid() {
return domainUuid;
}
public String getDomainPath() {
return domainPath;
}
public Date getDomainRemoved() {
return domainRemoved;
}
public String getProjectUuid() {
return projectUuid;
}
public String getProjectName() {
return projectName;
}
public Date getProjectRemoved() {
return projectRemoved;
}
}

View File

@ -19,7 +19,8 @@
<bean id="presetVariableHelper" class="org.apache.cloudstack.quota.activationrule.presetvariables.PresetVariableHelper" />
<bean id="QuotaTariffDao" class="org.apache.cloudstack.quota.dao.QuotaTariffDaoImpl" />
<bean id="QuotaAccountDao" class="org.apache.cloudstack.quota.dao.QuotaAccountDaoImpl" />
<bean id="QuotaSummaryDao" class="org.apache.cloudstack.quota.dao.QuotaSummaryDaoImpl" />
<bean id="QuotaAccountDao" class="org.apache.cloudstack.quota.dao.QuotaAccountDaoImpl" />
<bean id="QuotaBalanceDao" class="org.apache.cloudstack.quota.dao.QuotaBalanceDaoImpl" />
<bean id="QuotaCreditsDao" class="org.apache.cloudstack.quota.dao.QuotaCreditsDaoImpl" />
<bean id="QuotaEmailTemplatesDao"

View File

@ -16,61 +16,80 @@
//under the License.
package org.apache.cloudstack.api.command;
import com.cloud.user.Account;
import com.cloud.utils.Pair;
import org.apache.cloudstack.api.ACL;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.BaseListCmd;
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.response.AccountResponse;
import org.apache.cloudstack.api.response.DomainResponse;
import org.apache.cloudstack.api.response.ListResponse;
import org.apache.cloudstack.api.response.QuotaResponseBuilder;
import org.apache.cloudstack.api.response.QuotaSummaryResponse;
import org.apache.cloudstack.context.CallContext;
import org.apache.cloudstack.api.response.ProjectResponse;
import org.apache.cloudstack.api.response.ListResponse;
import org.apache.cloudstack.quota.QuotaAccountStateFilter;
import org.apache.cloudstack.quota.QuotaService;
import org.apache.commons.lang3.ObjectUtils;
import java.util.List;
import javax.inject.Inject;
@APICommand(name = "quotaSummary", responseObject = QuotaSummaryResponse.class, description = "Lists balance and quota usage for all Accounts", since = "4.7.0", requestHasSensitiveInfo = false, responseHasSensitiveInfo = false,
httpMethod = "GET")
@APICommand(name = "quotaSummary", responseObject = QuotaSummaryResponse.class, description = "Lists Quota balance summary of Accounts and Projects.", since = "4.7.0",
requestHasSensitiveInfo = false, responseHasSensitiveInfo = false, httpMethod = "GET")
public class QuotaSummaryCmd extends BaseListCmd {
@Parameter(name = ApiConstants.ACCOUNT, type = CommandType.STRING, required = false, description = "Optional, Account Id for which statement needs to be generated")
private String accountName;
@Parameter(name = ApiConstants.DOMAIN_ID, type = CommandType.UUID, required = false, entityType = DomainResponse.class, description = "Optional, If domain Id is given and the caller is domain admin then the statement is generated for domain.")
private Long domainId;
@Parameter(name = ApiConstants.LIST_ALL, type = CommandType.BOOLEAN, required = false, description = "Optional, to list all Accounts irrespective of the quota activity")
private Boolean listAll;
@Inject
QuotaResponseBuilder quotaResponseBuilder;
@Inject
QuotaResponseBuilder _responseBuilder;
QuotaService quotaService;
public QuotaSummaryCmd() {
super();
}
@ACL
@Parameter(name = ApiConstants.ACCOUNT_ID, type = CommandType.UUID, entityType = AccountResponse.class, description = "ID of the Account for which balance will be listed. Can not be specified with projectid.", since = "4.23.0")
private Long accountId;
@ACL
@Parameter(name = ApiConstants.ACCOUNT, type = CommandType.STRING, required = false, description = "Name of the Account for which balance will be listed.")
private String accountName;
@ACL
@Parameter(name = ApiConstants.DOMAIN_ID, type = CommandType.UUID, required = false, entityType = DomainResponse.class, description = "ID of the Domain for which balance will be listed. May be used individually or with accountname.")
private Long domainId;
@Parameter(name = ApiConstants.LIST_ALL, type = CommandType.BOOLEAN, description = "False (default) lists the Quota balance summary for calling Account. True lists balance summary for " +
"Accounts which the caller has access. If domain ID is informed, this parameter is considered as true.")
private Boolean listAll;
@Parameter(name = ApiConstants.ACCOUNT_STATE_TO_SHOW, type = CommandType.STRING, description = "Possible values are [ALL, ACTIVE, REMOVED]. ALL will list summaries for " +
"active and removed accounts; ACTIVE will list summaries only for active accounts; REMOVED will list summaries only for removed accounts. The default value is ACTIVE.",
since = "4.23.0")
private String accountStateToShow;
@ACL
@Parameter(name = ApiConstants.PROJECT_ID, type = CommandType.UUID, entityType = ProjectResponse.class, description = "ID of the Project for which balance will be listed. Can not be specified with accountId.", since = "4.23.0")
private Long projectId;
@Override
public void execute() {
Account caller = CallContext.current().getCallingAccount();
Pair<List<QuotaSummaryResponse>, Integer> responses;
if (caller.getType() == Account.Type.ADMIN) {
if (getAccountName() != null && getDomainId() != null)
responses = _responseBuilder.createQuotaSummaryResponse(getAccountName(), getDomainId());
else
responses = _responseBuilder.createQuotaSummaryResponse(isListAll(), getKeyword(), getStartIndex(), getPageSizeVal());
} else {
responses = _responseBuilder.createQuotaSummaryResponse(caller.getAccountName(), caller.getDomainId());
}
final ListResponse<QuotaSummaryResponse> response = new ListResponse<QuotaSummaryResponse>();
Pair<List<QuotaSummaryResponse>, Integer> responses = quotaResponseBuilder.createQuotaSummaryResponse(this);
ListResponse<QuotaSummaryResponse> response = new ListResponse<>();
response.setResponses(responses.first(), responses.second());
response.setResponseName(getCommandName());
setResponseObject(response);
}
public Long getAccountId() {
return accountId;
}
public void setAccountId(Long accountId) {
this.accountId = accountId;
}
public String getAccountName() {
return accountName;
}
@ -88,16 +107,31 @@ public class QuotaSummaryCmd extends BaseListCmd {
}
public Boolean isListAll() {
return listAll == null ? false: listAll;
// If a domain ID was specified, then allow listing all summaries of domain
return ObjectUtils.defaultIfNull(listAll, Boolean.FALSE) || domainId != null;
}
public void setListAll(Boolean listAll) {
this.listAll = listAll;
}
@Override
public long getEntityOwnerId() {
return Account.ACCOUNT_ID_SYSTEM;
public Long getProjectId() {
return projectId;
}
public QuotaAccountStateFilter getAccountStateToShow() {
QuotaAccountStateFilter state = QuotaAccountStateFilter.getValue(accountStateToShow);
if (state != null) {
return state;
}
return QuotaAccountStateFilter.ACTIVE;
}
@Override
public long getEntityOwnerId() {
if (ObjectUtils.allNull(accountId, accountName, projectId)) {
return -1;
}
return _accountService.finalizeAccountId(accountId, accountName, domainId, projectId);
}
}

View File

@ -24,6 +24,7 @@ import org.apache.cloudstack.api.command.QuotaEmailTemplateListCmd;
import org.apache.cloudstack.api.command.QuotaEmailTemplateUpdateCmd;
import org.apache.cloudstack.api.command.QuotaPresetVariablesListCmd;
import org.apache.cloudstack.api.command.QuotaStatementCmd;
import org.apache.cloudstack.api.command.QuotaSummaryCmd;
import org.apache.cloudstack.api.command.QuotaTariffCreateCmd;
import org.apache.cloudstack.api.command.QuotaTariffListCmd;
import org.apache.cloudstack.api.command.QuotaTariffUpdateCmd;
@ -52,11 +53,7 @@ public interface QuotaResponseBuilder {
QuotaBalanceResponse createQuotaBalanceResponse(List<QuotaBalanceVO> quotaUsage, Date startDate, Date endDate);
Pair<List<QuotaSummaryResponse>, Integer> createQuotaSummaryResponse(Boolean listAll);
Pair<List<QuotaSummaryResponse>, Integer> createQuotaSummaryResponse(Boolean listAll, String keyword, Long startIndex, Long pageSize);
Pair<List<QuotaSummaryResponse>, Integer> createQuotaSummaryResponse(String accountName, Long domainId);
Pair<List<QuotaSummaryResponse>, Integer> createQuotaSummaryResponse(QuotaSummaryCmd cmd);
QuotaBalanceResponse createQuotaLastBalanceResponse(List<QuotaBalanceVO> quotaBalance, Date startDate);

View File

@ -42,7 +42,9 @@ import java.util.stream.Collectors;
import javax.inject.Inject;
import com.cloud.domain.Domain;
import com.cloud.exception.PermissionDeniedException;
import com.cloud.projects.dao.ProjectDao;
import com.cloud.user.User;
import com.cloud.user.UserVO;
import com.cloud.utils.DateUtil;
@ -56,6 +58,7 @@ import org.apache.cloudstack.api.command.QuotaEmailTemplateListCmd;
import org.apache.cloudstack.api.command.QuotaEmailTemplateUpdateCmd;
import org.apache.cloudstack.api.command.QuotaPresetVariablesListCmd;
import org.apache.cloudstack.api.command.QuotaStatementCmd;
import org.apache.cloudstack.api.command.QuotaSummaryCmd;
import org.apache.cloudstack.api.command.QuotaTariffCreateCmd;
import org.apache.cloudstack.api.command.QuotaTariffListCmd;
import org.apache.cloudstack.api.command.QuotaTariffUpdateCmd;
@ -74,11 +77,13 @@ import org.apache.cloudstack.quota.activationrule.presetvariables.PresetVariable
import org.apache.cloudstack.quota.activationrule.presetvariables.Value;
import org.apache.cloudstack.quota.constant.QuotaConfig;
import org.apache.cloudstack.quota.constant.QuotaTypes;
import org.apache.cloudstack.quota.dao.QuotaAccountDao;
import org.apache.cloudstack.quota.dao.QuotaBalanceDao;
import org.apache.cloudstack.quota.dao.QuotaCreditsDao;
import org.apache.cloudstack.quota.dao.QuotaEmailConfigurationDao;
import org.apache.cloudstack.quota.dao.QuotaEmailTemplatesDao;
import org.apache.cloudstack.quota.dao.QuotaSummaryDao;
import org.apache.cloudstack.quota.dao.QuotaTariffDao;
import org.apache.cloudstack.quota.dao.QuotaUsageDao;
import org.apache.cloudstack.quota.vo.QuotaAccountVO;
@ -86,10 +91,13 @@ import org.apache.cloudstack.quota.vo.QuotaBalanceVO;
import org.apache.cloudstack.quota.vo.QuotaCreditsVO;
import org.apache.cloudstack.quota.vo.QuotaEmailConfigurationVO;
import org.apache.cloudstack.quota.vo.QuotaEmailTemplatesVO;
import org.apache.cloudstack.quota.vo.QuotaSummaryVO;
import org.apache.cloudstack.quota.vo.QuotaTariffVO;
import org.apache.cloudstack.quota.vo.QuotaUsageVO;
import org.apache.cloudstack.utils.jsinterpreter.JsInterpreter;
import org.apache.cloudstack.utils.reflectiontostringbuilderutils.ReflectionToStringBuilderUtils;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.compress.utils.Sets;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.reflect.FieldUtils;
@ -108,7 +116,6 @@ import com.cloud.user.AccountVO;
import com.cloud.user.dao.AccountDao;
import com.cloud.user.dao.UserDao;
import com.cloud.utils.Pair;
import com.cloud.utils.db.Filter;
@Component
public class QuotaResponseBuilderImpl implements QuotaResponseBuilder {
@ -121,7 +128,7 @@ public class QuotaResponseBuilderImpl implements QuotaResponseBuilder {
@Inject
private QuotaCreditsDao quotaCreditsDao;
@Inject
private QuotaUsageDao _quotaUsageDao;
private QuotaUsageDao quotaUsageDao;
@Inject
private QuotaEmailTemplatesDao _quotaEmailTemplateDao;
@ -132,24 +139,30 @@ public class QuotaResponseBuilderImpl implements QuotaResponseBuilder {
@Inject
private AccountDao _accountDao;
@Inject
private ProjectDao projectDao;
@Inject
private QuotaAccountDao quotaAccountDao;
@Inject
private DomainDao _domainDao;
private DomainDao domainDao;
@Inject
private AccountManager _accountMgr;
@Inject
private QuotaStatement _statement;
private QuotaStatement quotaStatement;
@Inject
private QuotaManager _quotaManager;
@Inject
private QuotaEmailConfigurationDao quotaEmailConfigurationDao;
@Inject
private QuotaSummaryDao quotaSummaryDao;
@Inject
private JsInterpreterHelper jsInterpreterHelper;
@Inject
private ApiDiscoveryService apiDiscoveryService;
private final Class<?>[] assignableClasses = {GenericPresetVariable.class, ComputingResources.class};
private Set<Account.Type> accountTypesThatCanListAllQuotaSummaries = Sets.newHashSet(Account.Type.ADMIN, Account.Type.DOMAIN_ADMIN);
protected void checkActivationRulesAllowed(String activationRule) {
if (!_quotaService.isJsInterpretationEnabled() && StringUtils.isNotEmpty(activationRule)) {
throw new PermissionDeniedException("Quota Tariff Activation Rule cannot be set, as Javascript interpretation is disabled in the configuration.");
@ -180,75 +193,113 @@ public class QuotaResponseBuilderImpl implements QuotaResponseBuilder {
}
@Override
public Pair<List<QuotaSummaryResponse>, Integer> createQuotaSummaryResponse(final String accountName, final Long domainId) {
List<QuotaSummaryResponse> result = new ArrayList<QuotaSummaryResponse>();
public Pair<List<QuotaSummaryResponse>, Integer> createQuotaSummaryResponse(QuotaSummaryCmd cmd) {
Account caller = CallContext.current().getCallingAccount();
if (accountName != null && domainId != null) {
Account account = _accountDao.findActiveAccount(accountName, domainId);
QuotaSummaryResponse qr = getQuotaSummaryResponse(account);
result.add(qr);
if (!accountTypesThatCanListAllQuotaSummaries.contains(caller.getType()) || !cmd.isListAll()) {
return getQuotaSummaryResponse(cmd.getEntityOwnerId(), null, null, cmd);
}
return new Pair<>(result, result.size());
return getQuotaSummaryResponseWithListAll(cmd, caller);
}
@Override
public Pair<List<QuotaSummaryResponse>, Integer> createQuotaSummaryResponse(Boolean listAll) {
return createQuotaSummaryResponse(listAll, null, null, null);
}
@Override
public Pair<List<QuotaSummaryResponse>, Integer> createQuotaSummaryResponse(Boolean listAll, final String keyword, final Long startIndex, final Long pageSize) {
List<QuotaSummaryResponse> result = new ArrayList<QuotaSummaryResponse>();
Integer count = 0;
if (listAll) {
Filter filter = new Filter(AccountVO.class, "accountName", true, startIndex, pageSize);
Pair<List<AccountVO>, Integer> data = _accountDao.findAccountsLike(keyword, filter);
count = data.second();
for (final AccountVO account : data.first()) {
QuotaSummaryResponse qr = getQuotaSummaryResponse(account);
result.add(qr);
}
} else {
Pair<List<QuotaAccountVO>, Integer> data = quotaAccountDao.listAllQuotaAccount(startIndex, pageSize);
count = data.second();
for (final QuotaAccountVO quotaAccount : data.first()) {
AccountVO account = _accountDao.findById(quotaAccount.getId());
if (account == null) {
continue;
}
QuotaSummaryResponse qr = getQuotaSummaryResponse(account);
result.add(qr);
protected Pair<List<QuotaSummaryResponse>, Integer> getQuotaSummaryResponseWithListAll(QuotaSummaryCmd cmd, Account caller) {
Long domainId = cmd.getDomainId();
if (domainId != null) {
DomainVO domain = domainDao.findByIdIncludingRemoved(domainId);
if (domain == null) {
throw new InvalidParameterValueException(String.format("Domain [%s] does not exist.", domainId));
}
}
return new Pair<>(result, count);
String domainPath = getDomainPathByDomainIdForDomainAdmin(caller);
Long accountId = cmd.getEntityOwnerId();
if (accountId == -1) {
accountId = cmd.isListAll() ? null : caller.getAccountId();
}
return getQuotaSummaryResponse(accountId, domainId, domainPath, cmd);
}
protected QuotaSummaryResponse getQuotaSummaryResponse(final Account account) {
Calendar[] period = _statement.getCurrentStatementTime();
if (account != null) {
QuotaSummaryResponse qr = new QuotaSummaryResponse();
DomainVO domain = _domainDao.findById(account.getDomainId());
BigDecimal curBalance = _quotaBalanceDao.lastQuotaBalance(account.getAccountId(), account.getDomainId(), period[1].getTime());
BigDecimal quotaUsage = _quotaUsageDao.findTotalQuotaUsage(account.getAccountId(), account.getDomainId(), null, period[0].getTime(), period[1].getTime());
qr.setAccountId(account.getUuid());
qr.setAccountName(account.getAccountName());
qr.setDomainId(domain.getUuid());
qr.setDomainName(domain.getName());
qr.setBalance(curBalance);
qr.setQuotaUsage(quotaUsage);
qr.setState(account.getState());
qr.setStartDate(period[0].getTime());
qr.setEndDate(period[1].getTime());
qr.setCurrency(QuotaConfig.QuotaCurrencySymbol.value());
qr.setQuotaEnabled(QuotaConfig.QuotaAccountEnabled.valueIn(account.getId()));
qr.setObjectName("summary");
return qr;
} else {
return new QuotaSummaryResponse();
/**
* Retrieves the domain path of the caller's domain (if the caller is Domain Admin) for filtering in the quota summary query.
* @return null if the caller is an Admin or the domain path of the caller's domain if the caller is a Domain Admin.
* @throws InvalidParameterValueException if it cannot find the domain.
*/
protected String getDomainPathByDomainIdForDomainAdmin(Account caller) {
if (caller.getType() != Account.Type.DOMAIN_ADMIN) {
return null;
}
Long domainId = caller.getDomainId();
Domain domain = domainDao.findById(domainId);
_accountMgr.checkAccess(caller, domain);
if (domain == null) {
throw new InvalidParameterValueException(String.format("Domain ID [%s] is invalid.", domainId));
}
return domain.getPath();
}
/**
* Returns a <code>List</code> of <code>QuotaSummaryResponse</code> based on the provided parameters.
* @param accountId ID of the Account to return the summaries for. If <code>-1</code>, either because no specific
* Account was provided, or list all is disabled, then the summary is generated for the calling Account.
* @param domainId ID of the Domain to return the summaries for.
* @param domainPath path of the Domain to return the summaries for.
*/
protected Pair<List<QuotaSummaryResponse>, Integer> getQuotaSummaryResponse(Long accountId, Long domainId, String domainPath, QuotaSummaryCmd cmd) {
if (accountId != null && accountId == -1) {
accountId = CallContext.current().getCallingAccountId();
}
Pair<List<QuotaSummaryVO>, Integer> pairSummaries = quotaSummaryDao.listQuotaSummariesForAccountAndOrDomain(accountId, cmd.getKeyword(), domainId, domainPath,
cmd.getAccountStateToShow(), cmd.getStartIndex(), cmd.getPageSizeVal());
List<QuotaSummaryVO> summaries = pairSummaries.first();
if (CollectionUtils.isEmpty(summaries)) {
logger.info("There are no summaries to list for parameters [{}].", ReflectionToStringBuilderUtils.reflectOnlySelectedFields(cmd, "accountName", "domainId", "listAll", "page", "pageSize"));
return new Pair<>(new ArrayList<>(), 0);
}
List<QuotaSummaryResponse> responses = summaries.stream().map(this::getQuotaSummaryResponse).collect(Collectors.toList());
return new Pair<>(responses, pairSummaries.second());
}
protected QuotaSummaryResponse getQuotaSummaryResponse(QuotaSummaryVO summary) {
QuotaSummaryResponse response = new QuotaSummaryResponse();
Account account = _accountDao.findByUuidIncludingRemoved(summary.getAccountUuid());
Calendar[] period = quotaStatement.getCurrentStatementTime();
Date startDate = period[0].getTime();
Date endDate = period[1].getTime();
BigDecimal quotaUsage = quotaUsageDao.findTotalQuotaUsage(account.getAccountId(), account.getDomainId(), null, startDate, endDate);
response.setQuotaUsage(quotaUsage);
response.setStartDate(startDate);
response.setEndDate(endDate);
response.setAccountId(summary.getAccountUuid());
response.setAccountName(summary.getAccountName());
response.setDomainId(summary.getDomainUuid());
response.setDomainPath(summary.getDomainPath());
response.setBalance(summary.getQuotaBalance());
response.setState(summary.getAccountState());
response.setCurrency(QuotaConfig.QuotaCurrencySymbol.value());
response.setQuotaEnabled(QuotaConfig.QuotaAccountEnabled.valueIn(account.getId()));
response.setDomainRemoved(summary.getDomainRemoved() != null);
response.setAccountRemoved(summary.getAccountRemoved() != null);
response.setObjectName("summary");
if (summary.getProjectUuid() != null) {
response.setProjectId(summary.getProjectUuid());
response.setProjectName(summary.getProjectName());
response.setProjectRemoved(summary.getProjectRemoved() != null);
}
return response;
}
public boolean isUserAllowedToSeeActivationRules(User user) {

View File

@ -17,7 +17,6 @@
package org.apache.cloudstack.api.response;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Date;
import com.google.gson.annotations.SerializedName;
@ -30,40 +29,48 @@ import com.cloud.user.Account.State;
public class QuotaSummaryResponse extends BaseResponse {
@SerializedName("accountid")
@Param(description = "Account ID")
@Param(description = "Account's ID")
private String accountId;
@SerializedName("account")
@Param(description = "Account name")
@Param(description = "Account's name")
private String accountName;
@SerializedName("domainid")
@Param(description = "Domain ID")
@Param(description = "Domain's ID")
private String domainId;
@SerializedName("domain")
@Param(description = "Domain name")
private String domainName;
@Param(description = "Domain's path")
private String domainPath;
@SerializedName("balance")
@Param(description = "Account balance")
@Param(description = "Account's balance")
private BigDecimal balance;
@SerializedName("state")
@Param(description = "Account state")
@Param(description = "Account's state")
private State state;
@SerializedName("domainremoved")
@Param(description = "If the domain is removed or not", since = "4.23.0")
private boolean domainRemoved;
@SerializedName("accountremoved")
@Param(description = "If the account is removed or not", since = "4.23.0")
private boolean accountRemoved;
@SerializedName("quota")
@Param(description = "Quota usage of this period")
@Param(description = "Quota consumed between the startdate and enddate")
private BigDecimal quotaUsage;
@SerializedName("startdate")
@Param(description = "Start date")
private Date startDate = null;
@Param(description = "Start date of the quota consumption")
private Date startDate;
@SerializedName("enddate")
@Param(description = "End date")
private Date endDate = null;
@Param(description = "End date of the quota consumption")
private Date endDate;
@SerializedName("currency")
@Param(description = "Currency")
@ -73,9 +80,17 @@ public class QuotaSummaryResponse extends BaseResponse {
@Param(description = "If the account has the quota config enabled")
private boolean quotaEnabled;
public QuotaSummaryResponse() {
super();
}
@SerializedName("projectname")
@Param(description = "Name of the project", since = "4.23.0")
private String projectName;
@SerializedName("projectid")
@Param(description = "Project's id", since = "4.23.0")
private String projectId;
@SerializedName("projectremoved")
@Param(description = "Whether the project is removed or not", since = "4.23.0")
private Boolean projectRemoved;
public String getAccountId() {
return accountId;
@ -101,28 +116,16 @@ public class QuotaSummaryResponse extends BaseResponse {
this.domainId = domainId;
}
public String getDomainName() {
return domainName;
}
public void setDomainName(String domainName) {
this.domainName = domainName;
}
public BigDecimal getQuotaUsage() {
return quotaUsage;
}
public State getState() {
return state;
public void setDomainPath(String domainPath) {
this.domainPath = domainPath;
}
public void setState(State state) {
this.state = state;
}
public void setQuotaUsage(BigDecimal startQuota) {
this.quotaUsage = startQuota.setScale(2, RoundingMode.HALF_EVEN);
public void setQuotaUsage(BigDecimal quotaUsage) {
this.quotaUsage = quotaUsage;
}
public BigDecimal getBalance() {
@ -130,38 +133,42 @@ public class QuotaSummaryResponse extends BaseResponse {
}
public void setBalance(BigDecimal balance) {
this.balance = balance.setScale(2, RoundingMode.HALF_EVEN);
}
public Date getStartDate() {
return startDate == null ? null : new Date(startDate.getTime());
this.balance = balance;
}
public void setStartDate(Date startDate) {
this.startDate = startDate == null ? null : new Date(startDate.getTime());
}
public Date getEndDate() {
return endDate == null ? null : new Date(endDate.getTime());
this.startDate = startDate;
}
public void setEndDate(Date endDate) {
this.endDate = endDate == null ? null : new Date(endDate.getTime());
}
public String getCurrency() {
return currency;
this.endDate = endDate;
}
public void setCurrency(String currency) {
this.currency = currency;
}
public boolean getQuotaEnabled() {
return quotaEnabled;
}
public void setQuotaEnabled(boolean quotaEnabled) {
this.quotaEnabled = quotaEnabled;
}
public void setProjectName(String projectName) {
this.projectName = projectName;
}
public void setProjectId(String projectId) {
this.projectId = projectId;
}
public void setProjectRemoved(Boolean projectRemoved) {
this.projectRemoved = projectRemoved;
}
public void setDomainRemoved(boolean domainRemoved) {
this.domainRemoved = domainRemoved;
}
public void setAccountRemoved(boolean accountRemoved) {
this.accountRemoved = accountRemoved;
}
}

View File

@ -26,6 +26,8 @@ import java.util.TimeZone;
import javax.inject.Inject;
import javax.naming.ConfigurationException;
import com.cloud.projects.ProjectManager;
import com.cloud.user.AccountService;
import org.apache.cloudstack.api.command.QuotaBalanceCmd;
import org.apache.cloudstack.api.command.QuotaConfigureEmailCmd;
import org.apache.cloudstack.api.command.QuotaCreditsCmd;
@ -75,6 +77,8 @@ public class QuotaServiceImpl extends ManagerBase implements QuotaService, Confi
@Inject
private AccountDao _accountDao;
@Inject
private AccountService accountService;
@Inject
private QuotaAccountDao _quotaAcc;
@Inject
private QuotaUsageDao _quotaUsageDao;
@ -86,6 +90,8 @@ public class QuotaServiceImpl extends ManagerBase implements QuotaService, Confi
private QuotaBalanceDao _quotaBalanceDao;
@Inject
private QuotaResponseBuilder _respBldr;
@Inject
private ProjectManager projectMgr;
private TimeZone _usageTimezone;

View File

@ -16,13 +16,11 @@
// under the License.
package org.apache.cloudstack.api.response;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
@ -31,6 +29,7 @@ import java.util.Set;
import java.util.HashSet;
import java.util.function.Consumer;
import com.cloud.domain.Domain;
import com.cloud.domain.DomainVO;
import com.cloud.domain.dao.DomainDao;
import com.cloud.exception.PermissionDeniedException;
@ -43,10 +42,10 @@ import org.apache.cloudstack.api.command.QuotaConfigureEmailCmd;
import org.apache.cloudstack.api.command.QuotaCreditsListCmd;
import org.apache.cloudstack.api.command.QuotaEmailTemplateListCmd;
import org.apache.cloudstack.api.command.QuotaEmailTemplateUpdateCmd;
import org.apache.cloudstack.api.command.QuotaSummaryCmd;
import org.apache.cloudstack.api.command.QuotaValidateActivationRuleCmd;
import org.apache.cloudstack.context.CallContext;
import org.apache.cloudstack.discovery.ApiDiscoveryService;
import org.apache.cloudstack.framework.config.ConfigKey;
import org.apache.cloudstack.jsinterpreter.JsInterpreterHelper;
import org.apache.cloudstack.quota.QuotaService;
import org.apache.cloudstack.quota.QuotaStatement;
@ -79,7 +78,10 @@ import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockedConstruction;
import org.mockito.MockedStatic;
import org.mockito.Mockito;
import org.mockito.Spy;
import org.mockito.junit.MockitoJUnitRunner;
import com.cloud.exception.InvalidParameterValueException;
import com.cloud.user.Account;
@ -89,8 +91,7 @@ import com.cloud.user.dao.UserDao;
import com.cloud.user.User;
import junit.framework.TestCase;
import org.mockito.Spy;
import org.mockito.junit.MockitoJUnitRunner;
@RunWith(MockitoJUnitRunner.class)
public class QuotaResponseBuilderImplTest extends TestCase {
@ -153,7 +154,7 @@ public class QuotaResponseBuilderImplTest extends TestCase {
Account accountMock;
@Mock
DomainVO domainVOMock;
DomainVO domainVoMock;
@Mock
QuotaConfigureEmailCmd quotaConfigureEmailCmdMock;
@ -161,6 +162,9 @@ public class QuotaResponseBuilderImplTest extends TestCase {
@Mock
QuotaAccountVO quotaAccountVOMock;
@Mock
CallContext callContextMock;
@Mock
QuotaEmailTemplatesVO quotaEmailTemplatesVoMock;
@ -184,17 +188,8 @@ public class QuotaResponseBuilderImplTest extends TestCase {
CallContext.register(callerUserMock, callerAccountMock);
}
private void overrideDefaultQuotaEnabledConfigValue(final Object value) throws IllegalAccessException, NoSuchFieldException {
Field f = ConfigKey.class.getDeclaredField("_defaultValue");
f.setAccessible(true);
f.set(QuotaConfig.QuotaAccountEnabled, value);
}
private Calendar[] createPeriodForQuotaSummary() {
final Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.HOUR, 0);
return new Calendar[] {calendar, calendar};
}
@Mock
Pair<List<QuotaSummaryResponse>, Integer> quotaSummaryResponseMock1, quotaSummaryResponseMock2;
@Mock
QuotaValidateActivationRuleCmd quotaValidateActivationRuleCmdMock = Mockito.mock(QuotaValidateActivationRuleCmd.class);
@ -466,36 +461,6 @@ public class QuotaResponseBuilderImplTest extends TestCase {
Mockito.verify(quotaTariffVoMock).setRemoved(Mockito.any(Date.class));
}
@Test
public void getQuotaSummaryResponseTestAccountIsNotNullQuotaIsDisabledShouldReturnFalse() throws NoSuchFieldException, IllegalAccessException {
Calendar[] period = createPeriodForQuotaSummary();
overrideDefaultQuotaEnabledConfigValue("false");
Mockito.doReturn(period).when(quotaStatementMock).getCurrentStatementTime();
Mockito.doReturn(domainVOMock).when(domainDaoMock).findById(Mockito.anyLong());
Mockito.doReturn(BigDecimal.ZERO).when(quotaBalanceDaoMock).lastQuotaBalance(Mockito.anyLong(), Mockito.anyLong(), Mockito.any(Date.class));
Mockito.doReturn(BigDecimal.ZERO).when(quotaUsageDaoMock).findTotalQuotaUsage(Mockito.anyLong(), Mockito.anyLong(), Mockito.isNull(), Mockito.any(Date.class), Mockito.any(Date.class));
QuotaSummaryResponse quotaSummaryResponse = quotaResponseBuilderSpy.getQuotaSummaryResponse(accountMock);
assertFalse(quotaSummaryResponse.getQuotaEnabled());
}
@Test
public void getQuotaSummaryResponseTestAccountIsNotNullQuotaIsEnabledShouldReturnTrue() throws NoSuchFieldException, IllegalAccessException {
Calendar[] period = createPeriodForQuotaSummary();
overrideDefaultQuotaEnabledConfigValue("true");
Mockito.doReturn(period).when(quotaStatementMock).getCurrentStatementTime();
Mockito.doReturn(domainVOMock).when(domainDaoMock).findById(Mockito.anyLong());
Mockito.doReturn(BigDecimal.ZERO).when(quotaBalanceDaoMock).lastQuotaBalance(Mockito.anyLong(), Mockito.anyLong(), Mockito.any(Date.class));
Mockito.doReturn(BigDecimal.ZERO).when(quotaUsageDaoMock).findTotalQuotaUsage(Mockito.anyLong(), Mockito.anyLong(), Mockito.isNull(), Mockito.any(Date.class), Mockito.any(Date.class));
QuotaSummaryResponse quotaSummaryResponse = quotaResponseBuilderSpy.getQuotaSummaryResponse(accountMock);
assertTrue(quotaSummaryResponse.getQuotaEnabled());
}
@Test
public void filterSupportedTypesTestReturnWhenQuotaTypeDoesNotMatch() throws NoSuchFieldException {
List<Pair<String, String>> variables = new ArrayList<>();
@ -576,6 +541,63 @@ public class QuotaResponseBuilderImplTest extends TestCase {
quotaResponseBuilderSpy.validateQuotaConfigureEmailCmdParameters(quotaConfigureEmailCmdMock);
}
@Test
public void createQuotaSummaryResponseTestNotListAllAndAllAccountTypesReturnsSingleRecord() {
QuotaSummaryCmd cmd = new QuotaSummaryCmd();
try(MockedStatic<CallContext> callContextMocked = Mockito.mockStatic(CallContext.class)) {
callContextMocked.when(CallContext::current).thenReturn(callContextMock);
Mockito.doReturn(accountMock).when(callContextMock).getCallingAccount();
Mockito.doReturn(quotaSummaryResponseMock1).when(quotaResponseBuilderSpy).getQuotaSummaryResponse(Mockito.any(), Mockito.any(), Mockito.any(), Mockito.any());
for (Account.Type type : Account.Type.values()) {
Mockito.doReturn(type).when(accountMock).getType();
Pair<List<QuotaSummaryResponse>, Integer> result = quotaResponseBuilderSpy.createQuotaSummaryResponse(cmd);
Assert.assertEquals(quotaSummaryResponseMock1, result);
}
Mockito.verify(quotaResponseBuilderSpy, Mockito.times(Account.Type.values().length)).getQuotaSummaryResponse(Mockito.any(), Mockito.any(), Mockito.any(),
Mockito.any());
};
}
@Test
public void getDomainPathByDomainIdForDomainAdminTestAccountNotDomainAdminReturnsNull() {
for (Account.Type type : Account.Type.values()) {
if (Account.Type.DOMAIN_ADMIN.equals(type)) {
continue;
}
Mockito.doReturn(type).when(accountMock).getType();
Assert.assertNull(quotaResponseBuilderSpy.getDomainPathByDomainIdForDomainAdmin(accountMock));
}
}
@Test(expected = InvalidParameterValueException.class)
public void getDomainPathByDomainIdForDomainAdminTestDomainFromCallerIsNullThrowsInvalidParameterValueException() {
Mockito.doReturn(Account.Type.DOMAIN_ADMIN).when(accountMock).getType();
Mockito.doReturn(null).when(domainDaoMock).findById(Mockito.anyLong());
Mockito.lenient().doNothing().when(accountManagerMock).checkAccess(Mockito.any(Account.class), Mockito.any(Domain.class));
quotaResponseBuilderSpy.getDomainPathByDomainIdForDomainAdmin(accountMock);
}
@Test
public void getDomainPathByDomainIdForDomainAdminTestDomainFromCallerIsNotNullReturnsPath() {
String expected = "/test/";
Mockito.doReturn(Account.Type.DOMAIN_ADMIN).when(accountMock).getType();
Mockito.doReturn(domainVoMock).when(domainDaoMock).findById(Mockito.anyLong());
Mockito.doNothing().when(accountManagerMock).checkAccess(Mockito.any(Account.class), Mockito.any(Domain.class));
Mockito.doReturn(expected).when(domainVoMock).getPath();
String result = quotaResponseBuilderSpy.getDomainPathByDomainIdForDomainAdmin(accountMock);
Assert.assertEquals(expected, result);
}
@Test
public void getQuotaEmailConfigurationVoTestTemplateNameIsNull() {
Mockito.doReturn(null).when(quotaConfigureEmailCmdMock).getTemplateName();

View File

@ -18,6 +18,7 @@ package org.apache.cloudstack.quota;
import com.cloud.configuration.Config;
import com.cloud.domain.dao.DomainDao;
import com.cloud.user.AccountVO;
import com.cloud.user.dao.AccountDao;
import com.cloud.utils.db.TransactionLegacy;
import junit.framework.TestCase;
@ -33,8 +34,10 @@ import org.joda.time.DateTime;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.Spy;
import org.mockito.junit.MockitoJUnitRunner;
import javax.naming.ConfigurationException;
@ -48,7 +51,7 @@ import java.util.List;
public class QuotaServiceImplTest extends TestCase {
@Mock
AccountDao accountDao;
AccountDao accountDaoMock;
@Mock
QuotaAccountDao quotaAcc;
@Mock
@ -61,8 +64,13 @@ public class QuotaServiceImplTest extends TestCase {
QuotaBalanceDao quotaBalanceDao;
@Mock
QuotaResponseBuilder respBldr;
@Mock
private AccountVO accountVoMock;
@Spy
@InjectMocks
QuotaServiceImpl quotaServiceImplSpy;
QuotaServiceImpl quotaService = new QuotaServiceImpl();
@Before
public void setup() throws IllegalAccessException, NoSuchFieldException, ConfigurationException {
@ -71,34 +79,34 @@ public class QuotaServiceImplTest extends TestCase {
Field accountDaoField = QuotaServiceImpl.class.getDeclaredField("_accountDao");
accountDaoField.setAccessible(true);
accountDaoField.set(quotaService, accountDao);
accountDaoField.set(quotaServiceImplSpy, accountDaoMock);
Field quotaAccountDaoField = QuotaServiceImpl.class.getDeclaredField("_quotaAcc");
quotaAccountDaoField.setAccessible(true);
quotaAccountDaoField.set(quotaService, quotaAcc);
quotaAccountDaoField.set(quotaServiceImplSpy, quotaAcc);
Field quotaUsageDaoField = QuotaServiceImpl.class.getDeclaredField("_quotaUsageDao");
quotaUsageDaoField.setAccessible(true);
quotaUsageDaoField.set(quotaService, quotaUsageDao);
quotaUsageDaoField.set(quotaServiceImplSpy, quotaUsageDao);
Field domainDaoField = QuotaServiceImpl.class.getDeclaredField("_domainDao");
domainDaoField.setAccessible(true);
domainDaoField.set(quotaService, domainDao);
domainDaoField.set(quotaServiceImplSpy, domainDao);
Field configDaoField = QuotaServiceImpl.class.getDeclaredField("_configDao");
configDaoField.setAccessible(true);
configDaoField.set(quotaService, configDao);
configDaoField.set(quotaServiceImplSpy, configDao);
Field balanceDaoField = QuotaServiceImpl.class.getDeclaredField("_quotaBalanceDao");
balanceDaoField.setAccessible(true);
balanceDaoField.set(quotaService, quotaBalanceDao);
balanceDaoField.set(quotaServiceImplSpy, quotaBalanceDao);
Field QuotaResponseBuilderField = QuotaServiceImpl.class.getDeclaredField("_respBldr");
QuotaResponseBuilderField.setAccessible(true);
QuotaResponseBuilderField.set(quotaService, respBldr);
QuotaResponseBuilderField.set(quotaServiceImplSpy, respBldr);
Mockito.when(configDao.getValue(Mockito.eq(Config.UsageAggregationTimezone.toString()))).thenReturn("IST");
quotaService.configure("randomName", null);
quotaServiceImplSpy.configure("randomName", null);
}
@Test
@ -120,9 +128,9 @@ public class QuotaServiceImplTest extends TestCase {
Mockito.when(quotaBalanceDao.lastQuotaBalanceVO(Mockito.eq(accountId), Mockito.eq(domainId), Mockito.any(Date.class))).thenReturn(records);
// with enddate
assertTrue(quotaService.findQuotaBalanceVO(accountId, accountName, domainId, startDate, endDate).get(0).equals(qb));
assertTrue(quotaServiceImplSpy.findQuotaBalanceVO(accountId, accountName, domainId, startDate, endDate).get(0).equals(qb));
// without enddate
assertTrue(quotaService.findQuotaBalanceVO(accountId, accountName, domainId, startDate, null).get(0).equals(qb));
assertTrue(quotaServiceImplSpy.findQuotaBalanceVO(accountId, accountName, domainId, startDate, null).get(0).equals(qb));
}
@Test
@ -133,7 +141,7 @@ public class QuotaServiceImplTest extends TestCase {
final Date startDate = new DateTime().minusDays(2).toDate();
final Date endDate = new Date();
quotaService.getQuotaUsage(accountId, accountName, domainId, QuotaTypes.IP_ADDRESS, startDate, endDate);
quotaServiceImplSpy.getQuotaUsage(accountId, accountName, domainId, QuotaTypes.IP_ADDRESS, startDate, endDate);
Mockito.verify(quotaUsageDao, Mockito.times(1)).findQuotaUsage(Mockito.eq(accountId), Mockito.eq(domainId), Mockito.eq(QuotaTypes.IP_ADDRESS), Mockito.any(Date.class), Mockito.any(Date.class));
}
@ -142,13 +150,13 @@ public class QuotaServiceImplTest extends TestCase {
// existing account
QuotaAccountVO quotaAccountVO = new QuotaAccountVO();
Mockito.when(quotaAcc.findByIdQuotaAccount(Mockito.anyLong())).thenReturn(quotaAccountVO);
quotaService.setLockAccount(2L, true);
quotaServiceImplSpy.setLockAccount(2L, true);
Mockito.verify(quotaAcc, Mockito.times(0)).persistQuotaAccount(Mockito.any(QuotaAccountVO.class));
Mockito.verify(quotaAcc, Mockito.times(1)).updateQuotaAccount(Mockito.anyLong(), Mockito.any(QuotaAccountVO.class));
// new account
Mockito.when(quotaAcc.findByIdQuotaAccount(Mockito.anyLong())).thenReturn(null);
quotaService.setLockAccount(2L, true);
quotaServiceImplSpy.setLockAccount(2L, true);
Mockito.verify(quotaAcc, Mockito.times(1)).persistQuotaAccount(Mockito.any(QuotaAccountVO.class));
}
@ -160,13 +168,14 @@ public class QuotaServiceImplTest extends TestCase {
// existing account setting
QuotaAccountVO quotaAccountVO = new QuotaAccountVO();
Mockito.when(quotaAcc.findByIdQuotaAccount(Mockito.anyLong())).thenReturn(quotaAccountVO);
quotaService.setMinBalance(accountId, balance);
quotaServiceImplSpy.setMinBalance(accountId, balance);
Mockito.verify(quotaAcc, Mockito.times(0)).persistQuotaAccount(Mockito.any(QuotaAccountVO.class));
Mockito.verify(quotaAcc, Mockito.times(1)).updateQuotaAccount(Mockito.anyLong(), Mockito.any(QuotaAccountVO.class));
// no account with limit set
Mockito.when(quotaAcc.findByIdQuotaAccount(Mockito.anyLong())).thenReturn(null);
quotaService.setMinBalance(accountId, balance);
quotaServiceImplSpy.setMinBalance(accountId, balance);
Mockito.verify(quotaAcc, Mockito.times(1)).persistQuotaAccount(Mockito.any(QuotaAccountVO.class));
}
}

View File

@ -35,7 +35,7 @@
<appender-ref ref="EventLogAppender"/>
</root>
</log4net>
<applicationSettings>
<CloudStack.Plugin.AgentShell.AgentSettings>
<setting name="cpus" serializeAs="String">

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8" ?>
<!--
<!--
Note: Add entries to the App.config file for configuration settings
that apply only to the Test project.
-->

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
<!--
Note: Add entries to the App.config file for configuration settings
that apply only to the Test project.
-->

View File

@ -275,6 +275,7 @@ public class BridgeVifDriver extends VifDriverBase {
if (nic.getPxeDisable()) {
intf.setPxeDisable(true);
}
intf.setLinkStateUp(nic.isEnabled());
return intf;
}

View File

@ -4851,6 +4851,12 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv
}
}
public InterfaceDef getInterface(final Connect conn, final String vmName, final String macAddress) {
List<InterfaceDef> interfaces = getInterfaces(conn, vmName);
return interfaces.stream().filter(interfaceDef -> interfaceDef.getMacAddress().equals(macAddress))
.findFirst().orElseThrow(() -> new CloudRuntimeException(String.format("Unable to find NIC with MAC address %s.", macAddress)));
}
public List<DiskDef> getDisks(final Connect conn, final String vmName) {
final LibvirtDomainXMLParser parser = new LibvirtDomainXMLParser();
Domain dm = null;

View File

@ -22,6 +22,7 @@ package com.cloud.hypervisor.kvm.resource.wrapper;
import com.cloud.agent.api.Answer;
import com.cloud.agent.api.GetRemoteVmsAnswer;
import com.cloud.agent.api.GetRemoteVmsCommand;
import com.cloud.hypervisor.Hypervisor;
import com.cloud.hypervisor.kvm.resource.LibvirtComputingResource;
import com.cloud.hypervisor.kvm.resource.LibvirtConnection;
import com.cloud.hypervisor.kvm.resource.LibvirtDomainXMLParser;
@ -97,6 +98,7 @@ public final class LibvirtGetRemoteVmsCommandWrapper extends CommandWrapper<GetR
if (parser.getCpuTuneDef() !=null) {
instance.setCpuSpeed(parser.getCpuTuneDef().getShares());
}
instance.setHypervisorType(Hypervisor.HypervisorType.KVM.name());
instance.setPowerState(getPowerState(libvirtComputingResource.getVmState(conn,domain.getName())));
instance.setNics(getUnmanagedInstanceNics(parser.getInterfaces()));
instance.setDisks(getUnmanagedInstanceDisks(parser.getDisks(),libvirtComputingResource, domain));

View File

@ -19,6 +19,7 @@ package com.cloud.hypervisor.kvm.resource.wrapper;
import com.cloud.agent.api.GetUnmanagedInstancesAnswer;
import com.cloud.agent.api.GetUnmanagedInstancesCommand;
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;
@ -130,6 +131,7 @@ public final class LibvirtGetUnmanagedInstancesCommandWrapper extends CommandWra
if (parser.getCpuModeDef() != null) {
instance.setCpuCoresPerSocket(parser.getCpuModeDef().getCoresPerSocket());
}
instance.setHypervisorType(Hypervisor.HypervisorType.KVM.name());
instance.setPowerState(getPowerState(libvirtComputingResource.getVmState(conn,domain.getName())));
instance.setMemory((int) LibvirtComputingResource.getDomainMemory(domain) / 1024);
instance.setNics(getUnmanagedInstanceNics(libvirtComputingResource, parser.getInterfaces()));

View File

@ -0,0 +1,67 @@
//
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
//
package com.cloud.hypervisor.kvm.resource.wrapper;
import com.cloud.agent.api.Answer;
import com.cloud.agent.api.UpdateVmNicAnswer;
import com.cloud.agent.api.UpdateVmNicCommand;
import com.cloud.hypervisor.kvm.resource.LibvirtComputingResource;
import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.InterfaceDef;
import com.cloud.resource.CommandWrapper;
import com.cloud.resource.ResourceWrapper;
import org.libvirt.Connect;
import org.libvirt.Domain;
import org.libvirt.LibvirtException;
@ResourceWrapper(handles = UpdateVmNicCommand.class)
public final class LibvirtUpdateVmNicCommandWrapper extends CommandWrapper<UpdateVmNicCommand, Answer, LibvirtComputingResource> {
@Override
public Answer execute(UpdateVmNicCommand command, LibvirtComputingResource libvirtComputingResource) {
String nicMacAddress = command.getNicMacAddress();
String vmName = command.getVmName();
boolean isEnabled = command.isEnabled();
Domain vm = null;
try {
final LibvirtUtilitiesHelper libvirtUtilitiesHelper = libvirtComputingResource.getLibvirtUtilitiesHelper();
final Connect conn = libvirtUtilitiesHelper.getConnectionByVmName(vmName);
vm = libvirtComputingResource.getDomain(conn, vmName);
final InterfaceDef nic = libvirtComputingResource.getInterface(conn, vmName, nicMacAddress);
nic.setLinkStateUp(isEnabled);
vm.updateDeviceFlags(nic.toString(), Domain.DeviceModifyFlags.LIVE);
return new UpdateVmNicAnswer(command, true, "success");
} catch (final LibvirtException e) {
final String msg = String.format(" Update NIC failed due to %s.", e);
logger.warn(msg, e);
return new UpdateVmNicAnswer(command, false, msg);
} finally {
if (vm != null) {
try {
vm.free();
} catch (final LibvirtException l) {
logger.trace("Ignoring libvirt error.", l);
}
}
}
}
}

View File

@ -7203,4 +7203,35 @@ public class LibvirtComputingResourceTest {
libvirtComputingResourceSpy.defineDiskForDefaultPoolType(diskDef, volume, false, false, false, physicalDisk, DEV_ID, DISK_BUS_TYPE, DISK_BUS_TYPE_DATA, null);
Mockito.verify(diskDef).defFileBasedDisk(PHYSICAL_DISK_PATH, DEV_ID, DISK_BUS_TYPE_DATA, DiskDef.DiskFmtType.QCOW2);
}
@Test
public void getInterfaceTestValidMacAddressReturnInterface() {
String macAddress = "a0:90:27:a9:9e:62";
final String vmName = "Test";
final InterfaceDef interfaceDef = Mockito.mock(InterfaceDef.class);
final List<InterfaceDef> interfaces = new ArrayList<>();
interfaces.add(interfaceDef);
Mockito.doReturn(macAddress).when(interfaceDef).getMacAddress();
Mockito.doReturn(interfaces).when(libvirtComputingResourceSpy).getInterfaces(Mockito.any(), Mockito.anyString());
InterfaceDef result = libvirtComputingResourceSpy.getInterface(connMock, vmName, macAddress);
Assert.assertNotNull(result);
}
@Test(expected = CloudRuntimeException.class)
public void getInterfaceTestInvalidMacAddressThrowCloudRuntimeException() {
String invalidMacAddress = "ea:57:5d:f1:64:05";
String macAddress = "a0:90:27:a9:9e:62";
final String vmName = "Test";
final InterfaceDef interfaceDef = Mockito.mock(InterfaceDef.class);
final List<InterfaceDef> interfaces = new ArrayList<>();
interfaces.add(interfaceDef);
Mockito.doReturn(macAddress).when(interfaceDef).getMacAddress();
Mockito.doReturn(interfaces).when(libvirtComputingResourceSpy).getInterfaces(Mockito.any(), Mockito.anyString());
libvirtComputingResourceSpy.getInterface(connMock, vmName, invalidMacAddress);
}
}

View File

@ -171,11 +171,20 @@ public class KubernetesClusterUtil {
// Check if dashboard service is up running.
while (System.currentTimeMillis() < timeoutTime) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug(String.format("Checking dashboard service for the Kubernetes cluster: %s to come up", kubernetesCluster));
LOGGER.debug(String.format("Checking dashboard service (Kubernetes Dashboard or Headlamp) for the Kubernetes cluster: %s to come up", kubernetesCluster));
}
// Check for Headlamp (new dashboard) in kube-system namespace
if (isKubernetesClusterAddOnServiceRunning(kubernetesCluster, ipAddress, port, user, sshKeyFile, "kube-system", "headlamp")) {
if (LOGGER.isInfoEnabled()) {
LOGGER.info(String.format("Headlamp dashboard service for the Kubernetes cluster %s is in running state", kubernetesCluster));
}
running = true;
break;
}
// For backward compatibility, check for Kubernetes Dashboard in kubernetes-dashboard namespace
if (isKubernetesClusterAddOnServiceRunning(kubernetesCluster, ipAddress, port, user, sshKeyFile, "kubernetes-dashboard", "kubernetes-dashboard")) {
if (LOGGER.isInfoEnabled()) {
LOGGER.info(String.format("Dashboard service for the Kubernetes cluster %s is in running state", kubernetesCluster));
LOGGER.info(String.format("Kubernetes Dashboard service for the Kubernetes cluster %s is in running state", kubernetesCluster));
}
running = true;
break;

View File

@ -331,16 +331,29 @@ write_files:
if [[ ${EXTERNAL_CNI_PLUGIN} == false ]]; then
/opt/bin/kubectl apply -f ${K8S_CONFIG_SCRIPTS_COPY_DIR}/network.yaml
fi
/opt/bin/kubectl apply -f ${K8S_CONFIG_SCRIPTS_COPY_DIR}/dashboard.yaml
if [ -f "${K8S_CONFIG_SCRIPTS_COPY_DIR}/headlamp.yaml" ]; then
echo "Installing Headlamp dashboard from ISO"
/opt/bin/kubectl apply -f ${K8S_CONFIG_SCRIPTS_COPY_DIR}/headlamp.yaml
elif [ -f "${K8S_CONFIG_SCRIPTS_COPY_DIR}/dashboard.yaml" ]; then
echo "Installing Kubernetes Dashboard from ISO"
/opt/bin/kubectl apply -f ${K8S_CONFIG_SCRIPTS_COPY_DIR}/dashboard.yaml
/opt/bin/kubectl create rolebinding admin-binding --role=admin --user=admin || true
/opt/bin/kubectl create clusterrolebinding cluster-admin-binding --clusterrole=cluster-admin --user=admin || true
/opt/bin/kubectl create clusterrolebinding kubernetes-dashboard-ui --clusterrole=cluster-admin --serviceaccount=kubernetes-dashboard:kubernetes-dashboard || true
else
echo "Warning: No dashboard YAML found in ISO (neither headlamp.yaml nor dashboard.yaml)"
fi
rm -rf "${K8S_CONFIG_SCRIPTS_COPY_DIR}"
else
### Online installation - use Headlamp by default ###
/opt/bin/kubectl apply -f "https://cloud.weave.works/k8s/net?k8s-version=$(/opt/bin/kubectl version | base64 | tr -d '\n')"
/opt/bin/kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/v2.0.0-beta6/aio/deploy/recommended.yaml
/opt/bin/kubectl apply -f https://raw.githubusercontent.com/kubernetes-sigs/headlamp/v0.40.1/kubernetes-headlamp.yaml
/opt/bin/kubectl create serviceaccount headlamp-admin -n kube-system || true
/opt/bin/kubectl create clusterrolebinding headlamp-admin --clusterrole=cluster-admin --serviceaccount=kube-system:headlamp-admin || true
fi
/opt/bin/kubectl create rolebinding admin-binding --role=admin --user=admin || true
/opt/bin/kubectl create clusterrolebinding cluster-admin-binding --clusterrole=cluster-admin --user=admin || true
/opt/bin/kubectl create clusterrolebinding kubernetes-dashboard-ui --clusterrole=cluster-admin --serviceaccount=kubernetes-dashboard:kubernetes-dashboard || true
sudo touch /home/cloud/success
echo "true" > /home/cloud/success

View File

@ -485,6 +485,12 @@ public class MockAccountManager extends ManagerBase implements AccountManager {
return null;
}
@Override
public Long finalizeAccountId(Long accountId, String accountName, Long domainId, Long projectId) {
// TODO Auto-generated method stub
return null;
}
@Override
public void checkAccess(Account account, ServiceOffering so, DataCenter zone) throws PermissionDeniedException {
// TODO Auto-generated method stub

View File

@ -335,6 +335,9 @@ public class SAMLUtils {
resp.addCookie(newCookie(domain, path,"isSAML", URLEncoder.encode("true", HttpUtils.UTF_8)));
resp.addCookie(newCookie(domain, path,"twoFaEnabled", URLEncoder.encode(loginResponse.is2FAenabled(), HttpUtils.UTF_8)));
resp.addCookie(newCookie(domain, path,"userfullname", URLEncoder.encode(loginResponse.getFirstName() + " " + loginResponse.getLastName(), HttpUtils.UTF_8).replace("+", "%20")));
if (StringUtils.isNotBlank(loginResponse.getManagementServerId())) {
resp.addCookie(new Cookie(ApiConstants.MANAGEMENT_SERVER_ID, URLEncoder.encode(loginResponse.getManagementServerId(), HttpUtils.UTF_8)));
}
}
private static Cookie newCookie(final String domain, final String path, final String name, final String value) {

View File

@ -19,8 +19,8 @@
set -e
if [ $# -lt 6 ]; then
echo "Invalid input. Valid usage: ./create-kubernetes-binaries-iso.sh OUTPUT_PATH KUBERNETES_VERSION CNI_VERSION CRICTL_VERSION WEAVENET_NETWORK_YAML_CONFIG DASHBOARD_YAML_CONFIG BUILD_NAME [ARCH] [ETCD_VERSION]"
echo "eg: ./create-kubernetes-binaries-iso.sh ./ 1.11.4 0.7.1 1.11.1 https://github.com/weaveworks/weave/releases/download/latest_release/weave-daemonset-k8s-1.11.yaml https://raw.githubusercontent.com/kubernetes/dashboard/v1.10.0/src/deploy/recommended/kubernetes-dashboard.yaml setup-v1.11.4 amd64"
echo "Invalid input. Valid usage: ./create-kubernetes-binaries-iso.sh OUTPUT_PATH KUBERNETES_VERSION CNI_VERSION CRICTL_VERSION WEAVENET_NETWORK_YAML_CONFIG HEADLAMP_DASHBOARD_VERSION BUILD_NAME [ARCH] [ETCD_VERSION]"
echo "eg: ./create-kubernetes-binaries-iso.sh ./ 1.11.4 0.7.1 1.11.1 https://github.com/weaveworks/weave/releases/download/latest_release/weave-daemonset-k8s-1.11.yaml 0.40.1 setup-v1.11.4 amd64"
exit 1
fi
@ -96,10 +96,11 @@ echo "Downloading network config ${NETWORK_CONFIG_URL}"
network_conf_file="${working_dir}/network.yaml"
curl -sSL ${NETWORK_CONFIG_URL} -o ${network_conf_file}
DASHBORAD_CONFIG_URL="${6}"
echo "Downloading dashboard config ${DASHBORAD_CONFIG_URL}"
dashboard_conf_file="${working_dir}/dashboard.yaml"
curl -sSL ${DASHBORAD_CONFIG_URL} -o ${dashboard_conf_file}
HEADLAMP_DASHBOARD_VERSION="${6}"
HEADLAMP_DASHBOARD_URL="https://raw.githubusercontent.com/kubernetes-sigs/headlamp/v${HEADLAMP_DASHBOARD_VERSION}/kubernetes-headlamp.yaml"
echo "Downloading Headlamp manifest from ${HEADLAMP_DASHBOARD_URL}"
headlamp_conf_file="${working_dir}/headlamp.yaml"
curl -sSL ${HEADLAMP_DASHBOARD_URL} -o ${headlamp_conf_file}
# TODO : Change the url once merged
AUTOSCALER_URL="https://raw.githubusercontent.com/kubernetes/autoscaler/master/cluster-autoscaler/cloudprovider/cloudstack/examples/cluster-autoscaler-standard.yaml"
@ -135,7 +136,7 @@ mkdir -p "${working_dir}/docker"
output=`${k8s_dir}/kubeadm config images list --kubernetes-version=${RELEASE}`
# Don't forget about the yaml images !
for i in ${network_conf_file} ${dashboard_conf_file}
for i in ${network_conf_file} ${headlamp_conf_file}
do
images=`grep "image:" $i | cut -d ':' -f2- | tr -d ' ' | tr -d "'"`
output=`printf "%s\n" ${output} ${images}`

View File

@ -2243,6 +2243,10 @@ public class ApiDBUtils {
return s_nicSecondaryIpDao.listByNicId(nicId);
}
public static NicVO findNicById(long nicId) {
return s_nicDao.findById(nicId);
}
public static TemplateResponse newTemplateUpdateResponse(TemplateJoinVO vr) {
return s_templateJoinDao.newUpdateResponse(vr);
}

View File

@ -1930,6 +1930,12 @@ public class ApiResponseHelper implements ResponseGenerator {
}
@Override
public UserVm findUserVmByNicId(Long nicId) {
NicVO nic = ApiDBUtils.findNicById(nicId);
return ApiDBUtils.findUserVmById(nic.getInstanceId());
}
@Override
public VolumeVO findVolumeById(Long volumeId) {
return ApiDBUtils.findVolumeById(volumeId);
@ -4853,6 +4859,8 @@ public class ApiResponseHelper implements ResponseGenerator {
VpcVO vpc = _entityMgr.findByUuidIncludingRemoved(VpcVO.class, userVm.getVpcUuid());
response.setVpcName(vpc.getName());
}
response.setEnabled(result.isEnabled());
return response;
}
@ -5402,8 +5410,21 @@ public class ApiResponseHelper implements ResponseGenerator {
if (host != null) {
response.setHostId(host.getUuid());
response.setHostName(host.getName());
} else if (instance.getHostName() != null) {
response.setHostName(instance.getHostName());
if (host.getHypervisorType() != null) {
response.setHypervisor(host.getHypervisorType().name());
}
response.setHypervisorVersion(host.getHypervisorVersion());
} else {
// In case the unmanaged instance is on an external host
if (instance.getHostName() != null) {
response.setHostName(instance.getHostName());
}
if (instance.getHypervisorType() != null) {
response.setHypervisor(instance.getHypervisorType());
}
if (instance.getHostHypervisorVersion() != null) {
response.setHypervisorVersion(instance.getHostHypervisorVersion());
}
}
response.setPowerState((instance.getPowerState() != null)? instance.getPowerState().toString() : UnmanagedInstanceTO.PowerState.PowerUnknown.toString());
response.setCpuCores(instance.getCpuCores());

View File

@ -314,20 +314,7 @@ public class ParamProcessWorker implements DispatchWorker {
protected void doAccessChecks(BaseCmd cmd, Map<Object, AccessType> entitiesToAccess) {
Account caller = CallContext.current().getCallingAccount();
List<Long> entityOwners = cmd.getEntityOwnerIds();
Account[] owners = null;
if (entityOwners != null) {
owners = entityOwners.stream().map(id -> _accountMgr.getAccount(id)).toArray(Account[]::new);
} else {
if (cmd.getEntityOwnerId() == Account.ACCOUNT_ID_SYSTEM && cmd instanceof BaseAsyncCmd && ((BaseAsyncCmd)cmd).getApiResourceType() == ApiCommandResourceType.Network) {
if (logger.isDebugEnabled()) {
logger.debug("Skipping access check on the network owner if the owner is ROOT/system.");
}
owners = new Account[]{};
} else {
owners = new Account[]{_accountMgr.getAccount(cmd.getEntityOwnerId())};
}
}
Account[] owners = getEntityOwners(cmd);
if (cmd instanceof BaseAsyncCreateCmd) {
// check that caller can access the owner account.

View File

@ -196,6 +196,7 @@ public class DomainRouterJoinDaoImpl extends GenericDaoBase<DomainRouterJoinVO,
nicResponse.setMtu(router.getMtu());
}
nicResponse.setIsDefault(router.isDefaultNic());
nicResponse.setEnabled(router.isNicEnabled());
nicResponse.setObjectName("nic");
routerResponse.addNic(nicResponse);
}
@ -289,6 +290,7 @@ public class DomainRouterJoinDaoImpl extends GenericDaoBase<DomainRouterJoinVO,
nicResponse.setMtu(vr.getMtu());
}
nicResponse.setIsDefault(vr.isDefaultNic());
nicResponse.setEnabled(vr.isNicEnabled());
nicResponse.setObjectName("nic");
vrData.addNic(nicResponse);
}

View File

@ -359,6 +359,7 @@ public class UserVmJoinDaoImpl extends GenericDaoBaseWithTagInformation<UserVmJo
nicResponse.setIp6Address(userVm.getIp6Address());
nicResponse.setIp6Gateway(userVm.getIp6Gateway());
nicResponse.setIp6Cidr(userVm.getIp6Cidr());
nicResponse.setEnabled(userVm.isNicEnabled());
nicResponse.setDnsRecordUrl(userVm.getDnsRecordUrl());
if (userVm.getBroadcastUri() != null) {
nicResponse.setBroadcastUri(userVm.getBroadcastUri().toString());
@ -630,6 +631,7 @@ public class UserVmJoinDaoImpl extends GenericDaoBaseWithTagInformation<UserVmJo
/*17: default*/
nicResponse.setIsDefault(uvo.isDefaultNic());
nicResponse.setDeviceId(String.valueOf(uvo.getNicDeviceId()));
nicResponse.setEnabled(uvo.isNicEnabled());
List<NicSecondaryIpVO> secondaryIps = ApiDBUtils.findNicSecondaryIps(uvo.getNicId());
if (secondaryIps != null) {
List<NicSecondaryIpResponse> ipList = new ArrayList<NicSecondaryIpResponse>();

View File

@ -274,6 +274,9 @@ public class DomainRouterJoinVO extends BaseViewVO implements ControlledViewEnti
@Column(name = "mtu")
private Integer mtu;
@Column(name = "is_nic_enabled")
private boolean isNicEnabled;
public DomainRouterJoinVO() {
}
@ -577,4 +580,8 @@ public class DomainRouterJoinVO extends BaseViewVO implements ControlledViewEnti
public Integer getMtu() {
return mtu;
}
public boolean isNicEnabled() {
return isNicEnabled;
}
}

View File

@ -346,6 +346,9 @@ public class UserVmJoinVO extends BaseViewWithTagInformationVO implements Contro
@Column(name = "is_default_nic")
private boolean isDefaultNic;
@Column(name = "is_nic_enabled")
private boolean isNicEnabled;
@Column(name = "ip_address")
private String ipAddress;
@ -1094,6 +1097,10 @@ public class UserVmJoinVO extends BaseViewWithTagInformationVO implements Contro
return leaseActionExecution;
}
public boolean isNicEnabled() {
return isNicEnabled;
}
public String getDnsRecordUrl() {
return dnsRecordUrl;
}

View File

@ -1714,7 +1714,7 @@ StateListener<State, VirtualMachine.Event, VirtualMachine>, Configurable {
@Override
public void reorderHostsByPriority(Map<Long, Integer> priorities, List<Host> hosts) {
logger.info("Re-ordering hosts {} by priorities {}", hosts, priorities);
logger.debug("Re-ordering hosts {} by priorities {}", hosts, priorities);
hosts.removeIf(host -> DataCenterDeployment.PROHIBITED_HOST_PRIORITY.equals(getHostPriority(priorities, host.getId())));
@ -1727,7 +1727,7 @@ StateListener<State, VirtualMachine.Event, VirtualMachine>, Configurable {
}
);
logger.info("Hosts after re-ordering are: {}", hosts);
logger.debug("Hosts after re-ordering are: {}", hosts);
}
private Integer getHostPriority(Map<Long, Integer> priorities, Long hostId) {

View File

@ -205,6 +205,7 @@ public abstract class HypervisorGuruBase extends AdapterBase implements Hypervis
to.setIp6Dns1(profile.getIPv6Dns1());
to.setIp6Dns2(profile.getIPv6Dns2());
to.setNetworkId(profile.getNetworkId());
to.setEnabled(profile.isEnabled());
NetworkVO network = networkDao.findById(profile.getNetworkId());
to.setNetworkUuid(network.getUuid());

View File

@ -44,6 +44,7 @@ import javax.inject.Inject;
import javax.naming.ConfigurationException;
import org.apache.cloudstack.acl.ApiKeyPairVO;
import com.cloud.api.query.MutualExclusiveIdsManagerBase;
import com.cloud.network.vpc.VpcVO;
import org.apache.cloudstack.acl.ControlledEntity;
import org.apache.cloudstack.acl.SecurityChecker;
@ -566,6 +567,7 @@ import org.apache.cloudstack.api.command.user.vm.StartVMCmd;
import org.apache.cloudstack.api.command.user.vm.StopVMCmd;
import org.apache.cloudstack.api.command.user.vm.UpdateDefaultNicForVMCmd;
import org.apache.cloudstack.api.command.user.vm.UpdateVMCmd;
import org.apache.cloudstack.api.command.user.vm.UpdateVmNicCmd;
import org.apache.cloudstack.api.command.user.vm.UpdateVmNicIpCmd;
import org.apache.cloudstack.api.command.user.vm.UpgradeVMCmd;
import org.apache.cloudstack.api.command.user.vmgroup.CreateVMGroupCmd;
@ -842,7 +844,6 @@ import com.cloud.utils.Pair;
import com.cloud.utils.PasswordGenerator;
import com.cloud.utils.Ternary;
import com.cloud.utils.component.ComponentLifecycle;
import com.cloud.utils.component.ManagerBase;
import com.cloud.utils.concurrency.NamedThreadFactory;
import com.cloud.utils.crypt.DBEncryptionUtil;
import com.cloud.utils.db.DB;
@ -885,7 +886,7 @@ import com.cloud.vm.dao.UserVmDao;
import com.cloud.vm.dao.VMInstanceDao;
import com.cloud.vm.dao.VMInstanceDetailsDao;
public class ManagementServerImpl extends ManagerBase implements ManagementServer, Configurable {
public class ManagementServerImpl extends MutualExclusiveIdsManagerBase implements ManagementServer, Configurable {
protected StateMachine2<State, VirtualMachine.Event, VirtualMachine> _stateMachine;
static final String FOR_SYSTEMVMS = "forsystemvms";
@ -2908,7 +2909,7 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe
@Override
public Pair<List<? extends GuestOS>, Integer> listGuestOSByCriteria(final ListGuestOsCmd cmd) {
final Long id = cmd.getId();
List<Long> ids = getIdsListFromCmd(cmd.getId(), cmd.getIds());
final Long osCategoryId = cmd.getOsCategoryId();
final String description = cmd.getDescription();
final String keyword = cmd.getKeyword();
@ -2916,7 +2917,7 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe
final Long pageSize = cmd.getPageSizeVal();
Boolean forDisplay = cmd.getDisplay();
return _guestOSDao.listGuestOSByCriteria(startIndex, pageSize, id, osCategoryId, description, keyword, forDisplay);
return _guestOSDao.listGuestOSByCriteria(startIndex, pageSize, ids, osCategoryId, description, keyword, forDisplay);
}
@Override
@ -3048,28 +3049,41 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe
throw new InvalidParameterValueException("Hypervisor version parameter cannot be used without specifying a hypervisor : XenServer, KVM or VMware");
}
final SearchCriteria<GuestOSHypervisorVO> sc = _guestOSHypervisorDao.createSearchCriteria();
SearchBuilder<GuestOSHypervisorVO> sb = _guestOSHypervisorDao.createSearchBuilder();
sb.and("id", sb.entity().getId(), SearchCriteria.Op.EQ);
sb.and("guestOsName", sb.entity().getGuestOsName(), SearchCriteria.Op.LIKE);
sb.and("hypervisorType", sb.entity().getHypervisorType(), SearchCriteria.Op.LIKE);
sb.and("hypervisorVersion", sb.entity().getHypervisorVersion(), SearchCriteria.Op.LIKE);
sb.and(guestOsId, sb.entity().getGuestOsId(), SearchCriteria.Op.EQ);
SearchBuilder<GuestOSVO> guestOSSearch = _guestOSDao.createSearchBuilder();
guestOSSearch.and("display", guestOSSearch.entity().isDisplay(), SearchCriteria.Op.LIKE);
sb.join("guestOSSearch", guestOSSearch, sb.entity().getGuestOsId(), guestOSSearch.entity().getId(), JoinBuilder.JoinType.INNER);
final SearchCriteria<GuestOSHypervisorVO> sc = sb.create();
if (id != null) {
sc.addAnd("id", SearchCriteria.Op.EQ, id);
sc.setParameters("id", SearchCriteria.Op.EQ, id);
}
if (osTypeId != null) {
sc.addAnd(guestOsId, SearchCriteria.Op.EQ, osTypeId);
sc.setParameters(guestOsId, osTypeId);
}
if (osNameForHypervisor != null) {
sc.addAnd("guestOsName", SearchCriteria.Op.LIKE, "%" + osNameForHypervisor + "%");
sc.setParameters("guestOsName", "%" + osNameForHypervisor + "%");
}
if (hypervisor != null) {
sc.addAnd("hypervisorType", SearchCriteria.Op.LIKE, "%" + hypervisor + "%");
sc.setParameters("hypervisorType", "%" + hypervisor + "%");
}
if (hypervisorVersion != null) {
sc.addAnd("hypervisorVersion", SearchCriteria.Op.LIKE, "%" + hypervisorVersion + "%");
sc.setParameters("hypervisorVersion", "%" + hypervisorVersion + "%");
}
// Exclude the mappings for guest OS marked as display = false
sc.setJoinParameters("guestOSSearch", "display", true);
if (osDisplayName != null) {
List<GuestOSVO> guestOSVOS = _guestOSDao.listLikeDisplayName(osDisplayName);
if (CollectionUtils.isNotEmpty(guestOSVOS)) {
@ -4152,6 +4166,7 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe
cmdList.add(StopVMCmd.class);
cmdList.add(UpdateDefaultNicForVMCmd.class);
cmdList.add(UpdateVMCmd.class);
cmdList.add(UpdateVmNicCmd.class);
cmdList.add(UpgradeVMCmd.class);
cmdList.add(CreateVMGroupCmd.class);
cmdList.add(DeleteVMGroupCmd.class);

View File

@ -2381,6 +2381,9 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager,
@Override
public TemplateType validateTemplateType(BaseCmd cmd, boolean isAdmin, boolean isCrossZones, HypervisorType hypervisorType) {
if (cmd instanceof GetUploadParamsForIsoCmd) {
return TemplateType.USER;
}
if (!(cmd instanceof UpdateTemplateCmd) && !(cmd instanceof RegisterTemplateCmd) && !(cmd instanceof GetUploadParamsForTemplateCmd)) {
return null;
}

View File

@ -73,7 +73,9 @@ import org.apache.cloudstack.affinity.dao.AffinityGroupDao;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiCommandResourceType;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.ApiErrorCode;
import org.apache.cloudstack.api.BaseAsyncCmd;
import org.apache.cloudstack.api.ServerApiException;
import org.apache.cloudstack.api.command.admin.account.CreateAccountCmd;
import org.apache.cloudstack.api.command.admin.account.UpdateAccountCmd;
import org.apache.cloudstack.api.command.admin.user.DeleteUserCmd;
@ -3889,6 +3891,48 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M
return null;
}
@Override
public Long finalizeAccountId(Long accountId, String accountName, Long domainId, Long projectId) {
if (projectId != null) {
if (ObjectUtils.anyNotNull(accountId, accountName)) {
throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Project and account can not be specified together.");
}
return getActiveProjectAccountByProjectId(projectId);
}
if (accountId != null) {
if (getActiveAccountById(accountId) != null) {
return accountId;
}
throw new InvalidParameterValueException(String.format("Unable to find account with ID [%s].", accountId));
}
if (accountName == null && domainId == null) {
throw new ServerApiException(ApiErrorCode.PARAM_ERROR, String.format("Either %s or %s must be informed.", ApiConstants.ACCOUNT_ID, ApiConstants.PROJECT_ID));
}
try {
Account activeAccount = getActiveAccountByName(accountName, domainId);
if (activeAccount != null) {
return activeAccount.getId();
}
} catch (InvalidParameterValueException exception) {
throw new ServerApiException(ApiErrorCode.PARAM_ERROR, String.format("Both %s and %s are needed if using either. Consider using %s instead.",
ApiConstants.ACCOUNT, ApiConstants.DOMAIN_ID, ApiConstants.ACCOUNT_ID));
}
throw new InvalidParameterValueException(String.format("Unable to find account by name [%s] on domain [%s].", accountName, domainId));
}
protected long getActiveProjectAccountByProjectId(long projectId) {
Project project = _projectMgr.getProject(projectId);
if (project == null) {
throw new ServerApiException(ApiErrorCode.PARAM_ERROR, String.format("Unable to find project with ID [%s].", projectId));
}
if (project.getState() != Project.State.Active) {
throw new ServerApiException(ApiErrorCode.PARAM_ERROR, String.format("Project with ID [%s] is not active.", projectId));
}
return project.getProjectAccountId();
}
@Override
public UserAccount getUserAccountById(Long userId) {
UserAccount userAccount = userAccountDao.findById(userId);

View File

@ -199,4 +199,9 @@ public interface UserVmManager extends UserVmService {
Boolean getDestroyRootVolumeOnVmDestruction(Long domainId);
/**
* @return true if the VM is part of a CKS cluster, false otherwise.
*/
boolean isVMPartOfAnyCKSCluster(VMInstanceVO vm);
}

View File

@ -102,6 +102,7 @@ import org.apache.cloudstack.api.command.user.vm.SecurityGroupAction;
import org.apache.cloudstack.api.command.user.vm.StartVMCmd;
import org.apache.cloudstack.api.command.user.vm.UpdateDefaultNicForVMCmd;
import org.apache.cloudstack.api.command.user.vm.UpdateVMCmd;
import org.apache.cloudstack.api.command.user.vm.UpdateVmNicCmd;
import org.apache.cloudstack.api.command.user.vm.UpdateVmNicIpCmd;
import org.apache.cloudstack.api.command.user.vm.UpgradeVMCmd;
import org.apache.cloudstack.api.command.user.vmgroup.CreateVMGroupCmd;
@ -1177,21 +1178,21 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
List<Long> vmNetworks = _vmNetworkMapDao.getNetworks(vmId);
List<DomainRouterVO> routers = new ArrayList<>();
//List the stopped routers
for(long vmNetworkId : vmNetworks) {
for (long vmNetworkId : vmNetworks) {
List<DomainRouterVO> router = _routerDao.listStopped(vmNetworkId);
routers.addAll(router);
}
//A vm may not have many nics attached and even fewer routers might be stopped (only in exceptional cases)
//Safe to start the stopped router serially, this is consistent with the way how multiple networks are added to vm during deploy
//and routers are started serially ,may revisit to make this process parallel
for(DomainRouterVO routerToStart : routers) {
for (DomainRouterVO routerToStart : routers) {
logger.warn("Trying to start router {} as part of vm: {} reboot", routerToStart, vm);
_virtualNetAppliance.startRouter(routerToStart.getId(),true);
}
}
} catch (ConcurrentOperationException e) {
throw new CloudRuntimeException("Concurrent operations on starting router. " + e);
} catch (Exception ex){
} catch (Exception ex) {
throw new CloudRuntimeException("Router start failed due to" + ex);
} finally {
if (logger.isInfoEnabled()) {
@ -1476,7 +1477,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
macAddress = validateOrReplaceMacAddress(macAddress, network);
if(_nicDao.findByNetworkIdAndMacAddress(networkId, macAddress) != null) {
if (_nicDao.findByNetworkIdAndMacAddress(networkId, macAddress) != null) {
throw new CloudRuntimeException("A NIC with this MAC address exists for network: " + network.getUuid());
}
@ -1502,7 +1503,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
vmInstance, dc, network, dataCenterDao.findById(network.getDataCenterId())));
}
if(_networkModel.getNicInNetwork(vmInstance.getId(),network.getId()) != null){
if (_networkModel.getNicInNetwork(vmInstance.getId(),network.getId()) != null) {
logger.debug("Instance {} already in network {} going to add another NIC", vmInstance, network);
} else {
//* get all vms hostNames in the network
@ -1530,7 +1531,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
} catch (ConcurrentOperationException e) {
throw new CloudRuntimeException("Concurrent operations on adding NIC to " + vmInstance + ": " + e);
} finally {
if(cleanUp) {
if (cleanUp) {
try {
_itMgr.removeVmFromNetwork(vmInstance, network, null);
} catch (ResourceUnavailableException e) {
@ -1935,6 +1936,54 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
return vm;
}
@Override
public UserVm updateVirtualMachineNic(UpdateVmNicCmd cmd) {
Long nicId = cmd.getNicId();
Boolean isNicEnabled = cmd.isEnabled();
Account caller = CallContext.current().getCallingAccount();
NicVO nic = _nicDao.findById(nicId);
if (nic == null) {
throw new InvalidParameterValueException("Unable to find the specified NIC.");
}
UserVmVO vmInstance = _vmDao.findById(nic.getInstanceId());
if (vmInstance == null) {
throw new InvalidParameterValueException("Unable to find a virtual machine associated with the specified NIC.");
}
if (vmInstance.getHypervisorType() != HypervisorType.KVM) {
throw new InvalidParameterValueException("Updating the VM NIC is only supported by the KVM hypervisor.");
}
NetworkVO network = _networkDao.findById(nic.getNetworkId());
if (network == null) {
throw new InvalidParameterValueException("Unable to find NIC's network.");
}
_accountMgr.checkAccess(caller, null, true, vmInstance);
if (isNicEnabled == null) {
return vmInstance;
}
boolean success = false;
try {
success = _itMgr.updateVmNic(vmInstance, nic, isNicEnabled);
} catch (ResourceUnavailableException e) {
throw new CloudRuntimeException(String.format("Unable to update NIC %s of VM %s in network %s due to: %s.", nic, vmInstance, network.getUuid(), e.getMessage()));
} catch (ConcurrentOperationException e) {
throw new CloudRuntimeException(String.format("Concurrent operations while updating NIC %s for VM %s: %s.", nic, vmInstance, e.getMessage()));
}
if (!success) {
throw new CloudRuntimeException(String.format("Failed to update NIC %s of VM %s in network %s.", nic, vmInstance, network.getUuid()));
}
logger.debug("Successfully updated NIC {} in network {} for VM {}.", nic, network.getUuid(), vmInstance);
return vmInstance;
}
private void updatePublicIpDnatVmIp(long vmId, long networkId, String oldIp, String newIp) {
if (!_networkModel.areServicesSupportedInNetwork(networkId, Service.StaticNat)) {
return;
@ -2311,7 +2360,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
answer = _agentMgr.easySend(neighbor.getId(), cmd);
}
if (answer != null && answer instanceof GetVolumeStatsAnswer){
if (answer != null && answer instanceof GetVolumeStatsAnswer) {
GetVolumeStatsAnswer volstats = (GetVolumeStatsAnswer)answer;
if (volstats.getVolumeStats() != null) {
volumeStatsByUuid.putAll(volstats.getVolumeStats());
@ -2322,7 +2371,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
return volumeStatsByUuid.size() > 0 ? volumeStatsByUuid : null;
}
private List<String> getVolumesByHost(HostVO host, StoragePool pool){
private List<String> getVolumesByHost(HostVO host, StoragePool pool) {
List<VMInstanceVO> vmsPerHost = _vmInstanceDao.listByHostId(host.getId());
return vmsPerHost.stream()
.flatMap(vm -> _volsDao.findNonDestroyedVolumesByInstanceIdAndPoolId(vm.getId(),pool.getId()).stream().map(vol ->
@ -2594,6 +2643,22 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
}
}
private void transitionExpungingToError(long vmId) {
UserVmVO vm = _vmDao.findById(vmId);
if (vm != null && vm.getState() == State.Expunging) {
try {
boolean transitioned = _itMgr.stateTransitTo(vm, VirtualMachine.Event.OperationFailedToError, null);
if (transitioned) {
logger.info("Transitioned VM [{}] from Expunging to Error after failed expunge", vm.getUuid());
} else {
logger.warn("Failed to persist transition of VM [{}] from Expunging to Error after failed expunge, possibly due to concurrent update", vm.getUuid());
}
} catch (NoTransitionException e) {
logger.warn("Failed to transition VM {} to Error state: {}", vm, e.getMessage());
}
}
}
/**
* Release network resources, it was done on vm stop previously.
* @param id vm id
@ -2602,7 +2667,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
*/
private void releaseNetworkResourcesOnExpunge(long id) throws ConcurrentOperationException, ResourceUnavailableException {
final VMInstanceVO vmInstance = _vmDao.findById(id);
if (vmInstance != null){
if (vmInstance != null) {
final VirtualMachineProfile profile = new VirtualMachineProfileImpl(vmInstance);
_networkMgr.release(profile, false);
}
@ -2867,17 +2932,17 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
) {
if (newCpu > currentCpu) {
_resourceLimitMgr.incrementVmCpuResourceCount(owner.getAccountId(), vmInstance.isDisplay(), svcOffering, template, newCpu - currentCpu);
} else if (newCpu > 0 && currentCpu > newCpu){
} else if (newCpu > 0 && currentCpu > newCpu) {
_resourceLimitMgr.decrementVmCpuResourceCount(owner.getAccountId(), vmInstance.isDisplay(), svcOffering, template, currentCpu - newCpu);
}
if (newMemory > currentMemory) {
_resourceLimitMgr.incrementVmMemoryResourceCount(owner.getAccountId(), vmInstance.isDisplay(), svcOffering, template, newMemory - currentMemory);
} else if (newMemory > 0 && currentMemory > newMemory){
} else if (newMemory > 0 && currentMemory > newMemory) {
_resourceLimitMgr.decrementVmMemoryResourceCount(owner.getAccountId(), vmInstance.isDisplay(), svcOffering, template, currentMemory - newMemory);
}
if (newGpu > currentGpu) {
_resourceLimitMgr.incrementVmGpuResourceCount(owner.getAccountId(), vmInstance.isDisplay(), svcOffering, template, newGpu - currentGpu);
} else if (newGpu > 0 && currentGpu > newGpu){
} else if (newGpu > 0 && currentGpu > newGpu) {
_resourceLimitMgr.decrementVmGpuResourceCount(owner.getAccountId(), vmInstance.isDisplay(), svcOffering, template, currentGpu - newGpu);
}
}
@ -3008,7 +3073,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
if (userReadOnlySettings.contains(detailName)) {
throw new InvalidParameterValueException("You're not allowed to add or edit the read-only setting: " + detailName);
}
if (existingDetails.stream().anyMatch(d -> Objects.equals(d.getName(), detailName) && !d.isDisplay())){
if (existingDetails.stream().anyMatch(d -> Objects.equals(d.getName(), detailName) && !d.isDisplay())) {
throw new InvalidParameterValueException("You're not allowed to add or edit the non-displayable setting: " + detailName);
}
}
@ -3100,25 +3165,24 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
private void saveUsageEvent(UserVmVO vm) {
// If vm not destroyed
if( vm.getState() != State.Destroyed && vm.getState() != State.Expunging && vm.getState() != State.Error){
if (vm.getState() != State.Destroyed && vm.getState() != State.Expunging && vm.getState() != State.Error) {
if(vm.isDisplayVm()){
if (vm.isDisplayVm()) {
//1. Allocated VM Usage Event
generateUsageEvent(vm, true, EventTypes.EVENT_VM_CREATE);
if(vm.getState() == State.Running || vm.getState() == State.Stopping){
if (vm.getState() == State.Running || vm.getState() == State.Stopping) {
//2. Running VM Usage Event
generateUsageEvent(vm, true, EventTypes.EVENT_VM_START);
// 3. Network offering usage
generateNetworkUsageForVm(vm, true, EventTypes.EVENT_NETWORK_OFFERING_ASSIGN);
}
}else {
} else {
//1. Allocated VM Usage Event
generateUsageEvent(vm, true, EventTypes.EVENT_VM_DESTROY);
if(vm.getState() == State.Running || vm.getState() == State.Stopping){
if (vm.getState() == State.Running || vm.getState() == State.Stopping) {
//2. Running VM Usage Event
generateUsageEvent(vm, true, EventTypes.EVENT_VM_STOP);
@ -3130,8 +3194,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
}
private void generateNetworkUsageForVm(VirtualMachine vm, boolean isDisplay, String eventType){
private void generateNetworkUsageForVm(VirtualMachine vm, boolean isDisplay, String eventType) {
List<NicVO> nics = _nicDao.listByVmId(vm.getId());
for (NicVO nic : nics) {
NetworkVO network = _networkDao.findById(nic.getNetworkId());
@ -3156,9 +3219,9 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
throw new CloudRuntimeException("Unable to find virtual machine with id " + id);
}
if(instanceName != null){
if (instanceName != null) {
VMInstanceVO vmInstance = _vmInstanceDao.findVMByInstanceName(instanceName);
if(vmInstance != null && vmInstance.getId() != id){
if (vmInstance != null && vmInstance.getId() != id) {
throw new CloudRuntimeException("Instance name : " + instanceName + " is not unique");
}
}
@ -3300,7 +3363,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
networkIds = networks.stream().map(Network::getId).collect(Collectors.toList());
}
} catch (InvalidParameterValueException e) {
if(logger.isDebugEnabled()) {
if (logger.isDebugEnabled()) {
logger.debug(e.getMessage(),e);
}
}
@ -3592,8 +3655,19 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
detachVolumesFromVm(vm, dataVols);
UserVm destroyedVm = destroyVm(vmId, expunge);
if (expunge && !expunge(vm)) {
throw new CloudRuntimeException("Failed to expunge vm " + destroyedVm);
if (expunge) {
boolean expunged = false;
String errorMsg = "";
try {
expunged = expunge(vm);
} catch (RuntimeException e) {
logger.error("Failed to expunge VM [{}] due to: {}", vm, e.getMessage(), e);
errorMsg = e.getMessage();
}
if (!expunged) {
transitionExpungingToError(vm.getId());
throw new CloudRuntimeException("Failed to expunge VM " + vm.getUuid() + (StringUtils.isNotBlank(errorMsg) ? " due to: " + errorMsg : ""));
}
}
autoScaleManager.removeVmFromVmGroup(vmId);
@ -4439,7 +4513,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
}
}
if (template.getTemplateType().equals(TemplateType.SYSTEM) && !CKS_NODE.equals(vmType) && !SHAREDFSVM.equals(vmType)) {
if (TemplateType.SYSTEM.equals(template.getTemplateType()) && !CKS_NODE.equals(vmType) && !SHAREDFSVM.equals(vmType)) {
throw new InvalidParameterValueException(String.format("Unable to use system template %s to deploy a user vm", template));
}
@ -4834,12 +4908,13 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
private UserVmVO commitUserVm(final boolean isImport, final DataCenter zone, final Host host, final Host lastHost, final VirtualMachineTemplate template, final String hostName, final String displayName, final Account owner,
final Long diskOfferingId, final Long diskSize, final String userData, Long userDataId, String userDataDetails, final Boolean isDisplayVm, final String keyboard,
final long accountId, final long userId, final ServiceOffering offering, final boolean isIso, final String sshPublicKeys, final LinkedHashMap<String, List<NicProfile>> networkNicMap,
final long accountId, final long userId, final ServiceOffering offering, final boolean isIso, final Long guestOsId, final String sshPublicKeys, final LinkedHashMap<String, List<NicProfile>> networkNicMap,
final long id, final String instanceName, final String uuidName, final HypervisorType hypervisorType, final Map<String, String> customParameters,
final Map<String, Map<Integer, String>> extraDhcpOptionMap, final Map<Long, DiskOffering> dataDiskTemplateToDiskOfferingMap,
final Map<String, String> userVmOVFPropertiesMap, final VirtualMachine.PowerState powerState, final boolean dynamicScalingEnabled, String vmType, final Long rootDiskOfferingId, String sshkeypairs,
List<VmDiskInfo> dataDiskInfoList, Volume volume, Snapshot snapshot) throws InsufficientCapacityException {
UserVmVO vm = new UserVmVO(id, instanceName, displayName, template.getId(), hypervisorType, template.getGuestOSId(), offering.isOfferHA(),
Long selectedGuestOsId = guestOsId != null ? guestOsId : template.getGuestOSId();
UserVmVO vm = new UserVmVO(id, instanceName, displayName, template.getId(), hypervisorType, selectedGuestOsId, offering.isOfferHA(),
offering.getLimitCpuUse(), owner.getDomainId(), owner.getId(), userId, offering.getId(), userData, userDataId, userDataDetails, hostName);
vm.setUuid(uuidName);
vm.setDynamicallyScalable(dynamicScalingEnabled);
@ -4865,8 +4940,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
vm.setIsoId(template.getId());
}
long guestOSId = template.getGuestOSId();
GuestOSVO guestOS = _guestOSDao.findById(guestOSId);
GuestOSVO guestOS = _guestOSDao.findById(selectedGuestOsId);
long guestOSCategoryId = guestOS.getCategoryId();
GuestOSCategoryVO guestOSCategory = _guestOSCategoryDao.findById(guestOSCategoryId);
if (hypervisorType.equals(HypervisorType.VMware)) {
@ -5124,7 +5198,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
List<VmDiskInfo> dataDiskInfoList, Volume volume, Snapshot snapshot) throws InsufficientCapacityException {
return commitUserVm(false, zone, null, null, template, hostName, displayName, owner,
diskOfferingId, diskSize, userData, userDataId, userDataDetails, isDisplayVm, keyboard,
accountId, userId, offering, isIso, sshPublicKeys, networkNicMap,
accountId, userId, offering, isIso, null, sshPublicKeys, networkNicMap,
id, instanceName, uuidName, hypervisorType, customParameters,
extraDhcpOptionMap, dataDiskTemplateToDiskOfferingMap,
userVmOVFPropertiesMap, null, dynamicScalingEnabled, vmType, rootDiskOfferingId, sshkeypairs, dataDiskInfoList, volume, snapshot);
@ -5156,7 +5230,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
@Override
public void generateUsageEvent(VirtualMachine vm, boolean isDisplay, String eventType){
public void generateUsageEvent(VirtualMachine vm, boolean isDisplay, String eventType) {
ServiceOfferingVO serviceOffering = serviceOfferingDao.findById(vm.getId(), vm.getServiceOfferingId());
if (!serviceOffering.isDynamic()) {
UsageEventUtils.publishUsageEvent(eventType, vm.getAccountId(), vm.getDataCenterId(), vm.getId(),
@ -5414,7 +5488,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
}
// add userdata info into vm profile
Nic defaultNic = _networkModel.getDefaultNic(vm.getId());
if(defaultNic != null) {
if (defaultNic != null) {
Network network = _networkModel.getNetwork(defaultNic.getNetworkId());
if (_networkModel.isSharedNetworkWithoutServices(network.getId())) {
final String serviceOffering = serviceOfferingDao.findByIdIncludingRemoved(vm.getId(), vm.getServiceOfferingId()).getDisplayText();
@ -5665,7 +5739,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
try {
VirtualMachineEntity vmEntity = _orchSrvc.getVirtualMachine(vm.getUuid());
if(forced) {
if (forced) {
status = vmEntity.stopForced(Long.toString(userId));
} else {
status = vmEntity.stop(Long.toString(userId));
@ -5846,7 +5920,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
params = createParameterInParameterMap(params, additionalParams, VirtualMachineProfile.Param.VmPassword, password);
}
if(additionalParams.containsKey(VirtualMachineProfile.Param.BootIntoSetup)) {
if (additionalParams.containsKey(VirtualMachineProfile.Param.BootIntoSetup)) {
if (! HypervisorType.VMware.equals(vm.getHypervisorType())) {
throw new InvalidParameterValueException(ApiConstants.BOOT_INTO_SETUP + " makes no sense for " + vm.getHypervisorType());
}
@ -6324,8 +6398,8 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
}
if (!serviceOffering.isDynamic()) {
for(String detail: cmd.getDetails().keySet()) {
if(detail.equalsIgnoreCase(VmDetailConstants.CPU_NUMBER) || detail.equalsIgnoreCase(VmDetailConstants.CPU_SPEED) || detail.equalsIgnoreCase(VmDetailConstants.MEMORY)) {
for (String detail: cmd.getDetails().keySet()) {
if (detail.equalsIgnoreCase(VmDetailConstants.CPU_NUMBER) || detail.equalsIgnoreCase(VmDetailConstants.CPU_SPEED) || detail.equalsIgnoreCase(VmDetailConstants.MEMORY)) {
throw new InvalidParameterValueException("cpuNumber or cpuSpeed or memory should not be specified for static service offering");
}
}
@ -6544,8 +6618,8 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
// check if this templateId has a child ISO
List<VMTemplateVO> child_templates = _templateDao.listByParentTemplatetId(template.getId());
for (VMTemplateVO tmpl: child_templates){
if (tmpl.getFormat() == Storage.ImageFormat.ISO){
for (VMTemplateVO tmpl: child_templates) {
if (tmpl.getFormat() == Storage.ImageFormat.ISO) {
logger.info("MDOV trying to attach disk {} to the VM {}", tmpl, vm);
_tmplService.attachIso(tmpl.getId(), vm.getId(), true);
}
@ -7202,7 +7276,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
checkIfHostOfVMIsInPrepareForMaintenanceState(vm, "Migrate");
if(serviceOfferingDetailsDao.findDetail(vm.getServiceOfferingId(), GPU.Keys.pciDevice.toString()) != null) {
if (serviceOfferingDetailsDao.findDetail(vm.getServiceOfferingId(), GPU.Keys.pciDevice.toString()) != null) {
throw new InvalidParameterValueException("Live Migration of GPU enabled VM is not supported");
}
@ -7817,7 +7891,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
throw ex;
}
if(serviceOfferingDetailsDao.findDetail(vm.getServiceOfferingId(), GPU.Keys.pciDevice.toString()) != null) {
if (serviceOfferingDetailsDao.findDetail(vm.getServiceOfferingId(), GPU.Keys.pciDevice.toString()) != null) {
throw new InvalidParameterValueException("Live Migration of GPU enabled VM is not supported");
}
@ -8794,6 +8868,10 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
throw new InvalidParameterValueException(String.format("Operation not supported for instance: %s",
vm.getName()));
}
if (isVMPartOfAnyCKSCluster(vm)) {
throw new UnsupportedServiceException("Cannot restore VM with id = " + vm.getUuid() +
" as it belongs to a CKS cluster. Please remove the VM from the CKS cluster before restoring.");
}
_accountMgr.checkAccess(caller, null, true, vm);
VMTemplateVO template;
@ -9228,8 +9306,14 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
Long hostId = vm.getHostId() != null ? vm.getHostId() : vm.getLastHostId();
if (hostId != null) {
VolumeInfo volumeInfo = volFactory.getVolume(root.getId());
// default findById() won't search entries with removed field not null
Host host = _hostDao.findById(hostId);
if (host == null) {
logger.warn("Host {} not found", hostId);
return;
}
VolumeInfo volumeInfo = volFactory.getVolume(root.getId());
final Command cmd;
@ -9532,7 +9616,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
@Override
public UserVm importVM(final DataCenter zone, final Host host, final VirtualMachineTemplate template, final String instanceNameInternal, final String displayName,
final Account owner, final String userData, final Account caller, final Boolean isDisplayVm, final String keyboard,
final long accountId, final long userId, final ServiceOffering serviceOffering, final String sshPublicKeys,
final long accountId, final long userId, final ServiceOffering serviceOffering, final String sshPublicKeys, final Long guestOsId,
final String hostName, final HypervisorType hypervisorType, final Map<String, String> customParameters,
final VirtualMachine.PowerState powerState, final LinkedHashMap<String, List<NicProfile>> networkNicMap) throws InsufficientCapacityException {
return Transaction.execute((TransactionCallbackWithException<UserVm, InsufficientCapacityException>) status -> {
@ -9558,7 +9642,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
final Boolean dynamicScalingEnabled = checkIfDynamicScalingCanBeEnabled(null, serviceOffering, template, zone.getId());
return commitUserVm(true, zone, host, lastHost, template, hostName, displayName, owner,
null, null, userData, null, null, isDisplayVm, keyboard,
accountId, userId, serviceOffering, template.getFormat().equals(ImageFormat.ISO), sshPublicKeys, networkNicMap,
accountId, userId, serviceOffering, template.getFormat().equals(ImageFormat.ISO), guestOsId, sshPublicKeys, networkNicMap,
id, instanceName, uuidName, hypervisorType, customParameters,
null, null, null, powerState, dynamicScalingEnabled, null, serviceOffering.getDiskOfferingId(), null, null, null, null);
});
@ -9985,10 +10069,15 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
}
}
public Boolean getDestroyRootVolumeOnVmDestruction(Long domainId){
public Boolean getDestroyRootVolumeOnVmDestruction(Long domainId) {
return DestroyRootVolumeOnVmDestruction.valueIn(domainId);
}
@Override
public boolean isVMPartOfAnyCKSCluster(VMInstanceVO vm) {
return kubernetesServiceHelpers.get(0).findByVmId(vm.getId()) != null;
}
private void setVncPasswordForKvmIfAvailable(Map<String, String> customParameters, UserVmVO vm) {
if (customParameters.containsKey(VmDetailConstants.KVM_VNC_PASSWORD)
&& StringUtils.isNotEmpty(customParameters.get(VmDetailConstants.KVM_VNC_PASSWORD))) {

View File

@ -68,6 +68,7 @@ import org.apache.cloudstack.api.response.VolumeForImportResponse;
import org.apache.cloudstack.api.response.VolumeResponse;
import org.apache.cloudstack.context.CallContext;
import org.apache.cloudstack.engine.orchestration.service.VolumeOrchestrationService;
import org.apache.cloudstack.framework.config.ConfigKey;
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreDao;
import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
@ -394,7 +395,7 @@ public class VolumeImportUnmanageManagerImpl implements VolumeImportUnmanageServ
Map<VolumeOnStorageTO.Detail, String> volumeDetails = volume.getDetails();
if (volumeDetails != null && volumeDetails.containsKey(VolumeOnStorageTO.Detail.BACKING_FILE)) {
String backingFile = volumeDetails.get(VolumeOnStorageTO.Detail.BACKING_FILE);
if (StringUtils.isNotBlank(backingFile)) {
if (StringUtils.isNotBlank(backingFile) && !AllowImportVolumeWithBackingFile.value()) {
logFailureAndThrowException("Volume with backing file cannot be imported or unmanaged.");
}
}
@ -513,4 +514,16 @@ public class VolumeImportUnmanageManagerImpl implements VolumeImportUnmanageServ
volume.setRemoved(new Date());
volumeDao.update(volume.getId(), volume);
}
@Override
public String getConfigComponentName() {
return VolumeImportUnmanageManagerImpl.class.getSimpleName();
}
@Override
public ConfigKey<?>[] getConfigKeys() {
return new ConfigKey<?>[]{
AllowImportVolumeWithBackingFile
};
}
}

View File

@ -155,8 +155,6 @@ import org.apache.cloudstack.api.command.admin.vm.ListUnmanagedInstancesCmd;
import org.apache.cloudstack.api.command.admin.vm.ListVmsForImportCmd;
import org.apache.cloudstack.api.command.admin.vm.UnmanageVMInstanceCmd;
import org.apache.cloudstack.api.response.ListResponse;
import org.apache.cloudstack.api.response.NicResponse;
import org.apache.cloudstack.api.response.UnmanagedInstanceDiskResponse;
import org.apache.cloudstack.api.response.UnmanagedInstanceResponse;
import org.apache.cloudstack.api.response.UserVmResponse;
import org.apache.cloudstack.context.CallContext;
@ -195,15 +193,15 @@ import java.util.stream.Collectors;
import static org.apache.cloudstack.api.ApiConstants.MAX_IOPS;
import static org.apache.cloudstack.api.ApiConstants.MIN_IOPS;
import static org.apache.cloudstack.storage.volume.VolumeImportUnmanageService.AllowImportVolumeWithBackingFile;
import static org.apache.cloudstack.vm.ImportVmTask.Step.CloningInstance;
import static org.apache.cloudstack.vm.ImportVmTask.Step.Completed;
import static org.apache.cloudstack.vm.ImportVmTask.Step.ConvertingInstance;
import static org.apache.cloudstack.vm.ImportVmTask.Step.Importing;
public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager {
public static final String VM_IMPORT_DEFAULT_TEMPLATE_NAME = "system-default-vm-import-dummy-template.iso";
public static final String KVM_VM_IMPORT_DEFAULT_TEMPLATE_NAME = "kvm-default-vm-import-dummy-template";
protected Logger logger = LogManager.getLogger(UnmanagedVMsManagerImpl.class);
private static final long OTHER_LINUX_64_GUEST_OS_ID = 99;
private static final List<Hypervisor.HypervisorType> importUnmanagedInstancesSupportedHypervisors =
Arrays.asList(Hypervisor.HypervisorType.VMware, Hypervisor.HypervisorType.KVM);
@ -326,7 +324,7 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager {
try {
template = VMTemplateVO.createSystemIso(templateDao.getNextInSequence(Long.class, "id"), templateName, templateName, true,
"", true, 64, Account.ACCOUNT_ID_SYSTEM, "",
"VM Import Default Template", false, 1);
"VM Import Default Template", false, OTHER_LINUX_64_GUEST_OS_ID);
template.setState(VirtualMachineTemplate.State.Inactive);
template = templateDao.persist(template);
if (template == null) {
@ -340,68 +338,6 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager {
return template;
}
private UnmanagedInstanceResponse createUnmanagedInstanceResponse(UnmanagedInstanceTO instance, Cluster cluster, Host host) {
UnmanagedInstanceResponse response = new UnmanagedInstanceResponse();
response.setName(instance.getName());
if (cluster != null) {
response.setClusterId(cluster.getUuid());
}
if (host != null) {
response.setHostId(host.getUuid());
response.setHostName(host.getName());
}
response.setPowerState(instance.getPowerState().toString());
response.setCpuCores(instance.getCpuCores());
response.setCpuSpeed(instance.getCpuSpeed());
response.setCpuCoresPerSocket(instance.getCpuCoresPerSocket());
response.setMemory(instance.getMemory());
response.setOperatingSystemId(instance.getOperatingSystemId());
response.setOperatingSystem(instance.getOperatingSystem());
response.setObjectName("unmanagedinstance");
if (instance.getDisks() != null) {
for (UnmanagedInstanceTO.Disk disk : instance.getDisks()) {
UnmanagedInstanceDiskResponse diskResponse = new UnmanagedInstanceDiskResponse();
diskResponse.setDiskId(disk.getDiskId());
if (StringUtils.isNotEmpty(disk.getLabel())) {
diskResponse.setLabel(disk.getLabel());
}
diskResponse.setCapacity(disk.getCapacity());
diskResponse.setController(disk.getController());
diskResponse.setControllerUnit(disk.getControllerUnit());
diskResponse.setPosition(disk.getPosition());
diskResponse.setImagePath(disk.getImagePath());
diskResponse.setDatastoreName(disk.getDatastoreName());
diskResponse.setDatastoreHost(disk.getDatastoreHost());
diskResponse.setDatastorePath(disk.getDatastorePath());
diskResponse.setDatastoreType(disk.getDatastoreType());
response.addDisk(diskResponse);
}
}
if (instance.getNics() != null) {
for (UnmanagedInstanceTO.Nic nic : instance.getNics()) {
NicResponse nicResponse = new NicResponse();
nicResponse.setId(nic.getNicId());
nicResponse.setNetworkName(nic.getNetwork());
nicResponse.setMacAddress(nic.getMacAddress());
if (StringUtils.isNotEmpty(nic.getAdapterType())) {
nicResponse.setAdapterType(nic.getAdapterType());
}
if (!CollectionUtils.isEmpty(nic.getIpAddress())) {
nicResponse.setIpAddresses(nic.getIpAddress());
}
nicResponse.setVlanId(nic.getVlan());
nicResponse.setIsolatedPvlanId(nic.getPvlan());
nicResponse.setIsolatedPvlanType(nic.getPvlanType());
response.addNic(nicResponse);
}
}
return response;
}
private List<String> getAdditionalNameFilters(Cluster cluster) {
List<String> additionalNameFilter = new ArrayList<>();
if (cluster == null) {
@ -1145,7 +1081,7 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager {
private UserVm importVirtualMachineInternal(final UnmanagedInstanceTO unmanagedInstance, final String instanceNameInternal, final DataCenter zone, final Cluster cluster, final HostVO host,
final VirtualMachineTemplate template, final String displayName, final String hostName, final Account caller, final Account owner, final Long userId,
final ServiceOfferingVO serviceOffering, final Map<String, Long> dataDiskOfferingMap,
final Map<String, Long> nicNetworkMap, final Map<String, Network.IpAddresses> callerNicIpAddressMap,
final Map<String, Long> nicNetworkMap, final Map<String, Network.IpAddresses> callerNicIpAddressMap, final Long guestOsId,
final Map<String, String> details, final boolean migrateAllowed, final boolean forced, final boolean isImportUnmanagedFromSameHypervisor) {
logger.debug(LogUtils.logGsonWithoutException("Trying to import VM [%s] with name [%s], in zone [%s], cluster [%s], and host [%s], using template [%s], service offering [%s], disks map [%s], NICs map [%s] and details [%s].",
unmanagedInstance, displayName, zone, cluster, host, template, serviceOffering, dataDiskOfferingMap, nicNetworkMap, details));
@ -1231,7 +1167,7 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager {
try {
userVm = userVmManager.importVM(zone, host, template, internalCSName, displayName, owner,
null, caller, true, null, owner.getAccountId(), userId,
validatedServiceOffering, null, hostName,
validatedServiceOffering, null, guestOsId, hostName,
cluster.getHypervisorType(), allDetails, powerState, null);
} catch (InsufficientCapacityException ice) {
String errorMsg = String.format("Failed to import VM [%s] due to [%s].", displayName, ice.getMessage());
@ -1550,10 +1486,11 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager {
protected VMTemplateVO getTemplateForImportInstance(Long templateId, Hypervisor.HypervisorType hypervisorType) {
VMTemplateVO template;
if (templateId == null) {
String templateName = (Hypervisor.HypervisorType.KVM.equals(hypervisorType)) ? KVM_VM_IMPORT_DEFAULT_TEMPLATE_NAME : VM_IMPORT_DEFAULT_TEMPLATE_NAME;
boolean isKVMHypervisor = Hypervisor.HypervisorType.KVM.equals(hypervisorType);
String templateName = (isKVMHypervisor) ? KVM_VM_IMPORT_DEFAULT_TEMPLATE_NAME : VM_IMPORT_DEFAULT_TEMPLATE_NAME;
template = templateDao.findByName(templateName);
if (template == null) {
template = createDefaultDummyVmImportTemplate(Hypervisor.HypervisorType.KVM == hypervisorType);
template = createDefaultDummyVmImportTemplate(isKVMHypervisor);
if (template == null) {
throw new InvalidParameterValueException(String.format("Default VM import template with unique name: %s for hypervisor: %s cannot be created. Please use templateid parameter for import", templateName, hypervisorType.toString()));
}
@ -1633,7 +1570,7 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager {
userVm = importVirtualMachineInternal(unmanagedInstance, instanceName, zone, cluster, host,
template, displayName, hostName, CallContext.current().getCallingAccount(), owner, userId,
serviceOffering, dataDiskOfferingMap,
nicNetworkMap, nicIpAddressMap,
nicNetworkMap, nicIpAddressMap, null,
details, migrateAllowed, forced, true);
break;
}
@ -1713,6 +1650,7 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager {
Long convertStoragePoolId = cmd.getConvertStoragePoolId();
String extraParams = cmd.getExtraParams();
boolean forceConvertToPool = cmd.getForceConvertToPool();
Long guestOsId = cmd.getGuestOsId();
if ((existingVcenterId == null && vcenter == null) || (existingVcenterId != null && vcenter != null)) {
throw new ServerApiException(ApiErrorCode.PARAM_ERROR,
@ -1800,7 +1738,7 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager {
UserVm userVm = importVirtualMachineInternal(convertedInstance, null, zone, destinationCluster, null,
template, displayName, hostName, caller, owner, userId,
serviceOffering, dataDiskOfferingMap,
nicNetworkMap, nicIpAddressMap,
nicNetworkMap, nicIpAddressMap, guestOsId,
details, false, forced, false);
long timeElapsedInSecs = (System.currentTimeMillis() - importStartTime) / 1000;
logger.debug(String.format("VMware VM %s imported successfully to CloudStack instance %s (%s), Time taken: %d secs, OVF files imported from %s, Source VMware VM details - OS: %s, PowerState: %s, Disks: %s, NICs: %s",
@ -2366,6 +2304,8 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager {
* Perform validations before attempting to unmanage a VM from CloudStack:
* - VM must not have any associated volume snapshot
* - VM must not have an attached ISO
* - VM must not belong to any CKS cluster
* @throws UnsupportedServiceException in case any of the validations above fail
*/
void performUnmanageVMInstancePrechecks(VMInstanceVO vmVO) {
if (hasVolumeSnapshotsPriorToUnmanageVM(vmVO)) {
@ -2377,6 +2317,11 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager {
throw new UnsupportedServiceException("Cannot unmanage VM with id = " + vmVO.getUuid() +
" as there is an ISO attached. Please detach ISO before unmanaging.");
}
if (userVmManager.isVMPartOfAnyCKSCluster(vmVO)) {
throw new UnsupportedServiceException("Cannot unmanage VM with id = " + vmVO.getUuid() +
" as it belongs to a CKS cluster. Please remove the VM from the CKS cluster before unmanaging.");
}
}
private boolean hasVolumeSnapshotsPriorToUnmanageVM(VMInstanceVO vmVO) {
@ -2677,7 +2622,7 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager {
try {
userVm = userVmManager.importVM(zone, null, template, null, displayName, owner,
null, caller, true, null, owner.getAccountId(), userId,
serviceOffering, null, hostName,
serviceOffering, null, null, hostName,
Hypervisor.HypervisorType.KVM, allDetails, powerState, null);
} catch (InsufficientCapacityException ice) {
logger.error(String.format("Failed to import vm name: %s", instanceName), ice);
@ -2815,7 +2760,7 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager {
try {
userVm = userVmManager.importVM(zone, null, template, null, displayName, owner,
null, caller, true, null, owner.getAccountId(), userId,
serviceOffering, null, hostName,
serviceOffering, null, null, hostName,
Hypervisor.HypervisorType.KVM, allDetails, powerState, networkNicMap);
} catch (InsufficientCapacityException ice) {
logger.error(String.format("Failed to import vm name: %s", instanceName), ice);
@ -2909,7 +2854,7 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager {
}
if (volumeDetails.containsKey(VolumeOnStorageTO.Detail.BACKING_FILE)) {
String backingFile = volumeDetails.get(VolumeOnStorageTO.Detail.BACKING_FILE);
if (StringUtils.isNotBlank(backingFile)) {
if (StringUtils.isNotBlank(backingFile) && !AllowImportVolumeWithBackingFile.value()) {
logFailureAndThrowException("Volume with backing file cannot be imported or unmanaged.");
}
}
@ -3000,9 +2945,8 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager {
!instance.getName().toLowerCase().contains(keyword)) {
continue;
}
responses.add(createUnmanagedInstanceResponse(instance, null, null));
responses.add(responseGenerator.createUnmanagedInstanceResponse(instance, null, null));
}
ListResponse<UnmanagedInstanceResponse> listResponses = new ListResponse<>();
listResponses.setResponses(responses, responses.size());
return listResponses;

View File

@ -77,6 +77,7 @@ import org.apache.cloudstack.api.command.user.vm.ResetVMSSHKeyCmd;
import org.apache.cloudstack.api.command.user.vm.ResetVMUserDataCmd;
import org.apache.cloudstack.api.command.user.vm.RestoreVMCmd;
import org.apache.cloudstack.api.command.user.vm.UpdateVMCmd;
import org.apache.cloudstack.api.command.user.vm.UpdateVmNicCmd;
import org.apache.cloudstack.api.command.user.volume.ResizeVolumeCmd;
import org.apache.cloudstack.backup.BackupManager;
import org.apache.cloudstack.backup.BackupVO;
@ -198,6 +199,7 @@ import com.cloud.utils.db.EntityManager;
import com.cloud.utils.db.UUIDManager;
import com.cloud.utils.exception.CloudRuntimeException;
import com.cloud.utils.exception.ExceptionProxyObject;
import com.cloud.utils.fsm.NoTransitionException;
import com.cloud.vm.dao.NicDao;
import com.cloud.vm.dao.UserVmDao;
import com.cloud.vm.dao.VMInstanceDetailsDao;
@ -244,6 +246,9 @@ public class UserVmManagerImplTest {
@Mock
private UpdateVMCmd updateVmCommand;
@Mock
private UpdateVmNicCmd updateVmNicCmd;
@Mock
private AccountManager accountManager;
@ -271,6 +276,9 @@ public class UserVmManagerImplTest {
@Mock
private UserVO callerUser;
@Mock
private NicVO nicMock;
@Mock
private VMTemplateDao templateDao;
@ -454,6 +462,8 @@ public class UserVmManagerImplTest {
private static final long vmId = 1l;
private static final long zoneId = 2L;
private static final long accountId = 3L;
private static final long nicId = 4L;
private static final long networkId = 5L;
private static final long serviceOfferingId = 10L;
private static final long templateId = 11L;
private static final long volumeId = 1L;
@ -1501,6 +1511,7 @@ public class UserVmManagerImplTest {
when(cmd.getVmId()).thenReturn(vmId);
when(cmd.getTemplateId()).thenReturn(2L);
when(userVmDao.findById(vmId)).thenReturn(userVmVoMock);
Mockito.doReturn(false).when(userVmManagerImpl).isVMPartOfAnyCKSCluster(userVmVoMock);
userVmManagerImpl.restoreVM(cmd);
}
@ -4251,4 +4262,111 @@ public class UserVmManagerImplTest {
verify(vmInstanceDetailsDao, never()).removeDetailsWithPrefix(anyLong(), anyString());
verify(userVmManagerImpl, never()).addExtraConfig(any(UserVmVO.class), anyString());
}
@Test(expected = InvalidParameterValueException.class)
public void updateVirtualMachineNicTestInvalidNicThrowInvalidParameterValueException() {
Long invalidId = -1L;
Mockito.doReturn(invalidId).when(updateVmNicCmd).getNicId();
userVmManagerImpl.updateVirtualMachineNic(updateVmNicCmd);
}
@Test(expected = InvalidParameterValueException.class)
public void updateVirtualMachineNicTestInvalidNicUserVmThrowInvalidParameterValueException() {
Mockito.doReturn(nicId).when(updateVmNicCmd).getNicId();
Mockito.doReturn(nicMock).when(nicDao).findById(nicId);
userVmManagerImpl.updateVirtualMachineNic(updateVmNicCmd);
}
@Test(expected = InvalidParameterValueException.class)
public void updateVirtualMachineNicTestInvalidNicNetworkThrowInvalidParameterValueException() {
Mockito.doReturn(nicId).when(updateVmNicCmd).getNicId();
Mockito.doReturn(true).when(updateVmNicCmd).isEnabled();
Mockito.doReturn(nicMock).when(nicDao).findById(nicId);
Mockito.doReturn(vmId).when(nicMock).getInstanceId();
Mockito.doReturn(userVmVoMock).when(userVmDao).findById(vmId);
userVmManagerImpl.updateVirtualMachineNic(updateVmNicCmd);
}
@Test(expected = CloudRuntimeException.class)
public void updateVirtualMachineNicTestInvalidNicNetworkThrowCloudRuntimeException() {
Mockito.doReturn(nicId).when(updateVmNicCmd).getNicId();
Mockito.doReturn(true).when(updateVmNicCmd).isEnabled();
Mockito.doReturn(nicMock).when(nicDao).findById(nicId);
Mockito.doReturn(vmId).when(nicMock).getInstanceId();
Mockito.doReturn(userVmVoMock).when(userVmDao).findById(vmId);
userVmManagerImpl.updateVirtualMachineNic(updateVmNicCmd);
}
@Test
public void updateVirtualMachineNicTestValidInputReturnNicUserVm() throws ResourceUnavailableException {
Mockito.doReturn(nicId).when(updateVmNicCmd).getNicId();
Mockito.doReturn(true).when(updateVmNicCmd).isEnabled();
Mockito.doReturn(nicMock).when(nicDao).findById(nicId);
Mockito.doReturn(vmId).when(nicMock).getInstanceId();
Mockito.doReturn(userVmVoMock).when(userVmDao).findById(vmId);
Mockito.doReturn(Hypervisor.HypervisorType.KVM).when(userVmVoMock).getHypervisorType();
Mockito.doReturn(networkId).when(nicMock).getNetworkId();
Mockito.doReturn(networkMock).when(_networkDao).findById(networkId);
Mockito.doReturn(true).when(virtualMachineManager).updateVmNic(Mockito.any(), Mockito.any(), Mockito.any());
UserVm result = userVmManagerImpl.updateVirtualMachineNic(updateVmNicCmd);
Assert.assertNotNull(result);
}
@Test
public void testTransitionExpungingToErrorVmInExpungingState() throws Exception {
UserVmVO vm = mock(UserVmVO.class);
when(vm.getState()).thenReturn(VirtualMachine.State.Expunging);
when(vm.getUuid()).thenReturn("test-uuid");
when(userVmDao.findById(vmId)).thenReturn(vm);
when(virtualMachineManager.stateTransitTo(eq(vm), eq(VirtualMachine.Event.OperationFailedToError), eq(null))).thenReturn(true);
java.lang.reflect.Method method = UserVmManagerImpl.class.getDeclaredMethod("transitionExpungingToError", long.class);
method.setAccessible(true);
method.invoke(userVmManagerImpl, vmId);
Mockito.verify(virtualMachineManager).stateTransitTo(vm, VirtualMachine.Event.OperationFailedToError, null);
}
@Test
public void testTransitionExpungingToErrorVmNotInExpungingState() throws Exception {
UserVmVO vm = mock(UserVmVO.class);
when(vm.getState()).thenReturn(VirtualMachine.State.Stopped);
when(userVmDao.findById(vmId)).thenReturn(vm);
java.lang.reflect.Method method = UserVmManagerImpl.class.getDeclaredMethod("transitionExpungingToError", long.class);
method.setAccessible(true);
method.invoke(userVmManagerImpl, vmId);
Mockito.verify(virtualMachineManager, Mockito.never()).stateTransitTo(any(VirtualMachine.class), any(VirtualMachine.Event.class), any());
}
@Test
public void testTransitionExpungingToErrorVmNotFound() throws Exception {
when(userVmDao.findById(vmId)).thenReturn(null);
java.lang.reflect.Method method = UserVmManagerImpl.class.getDeclaredMethod("transitionExpungingToError", long.class);
method.setAccessible(true);
method.invoke(userVmManagerImpl, vmId);
Mockito.verify(virtualMachineManager, Mockito.never()).stateTransitTo(any(VirtualMachine.class), any(VirtualMachine.Event.class), any());
}
@Test
public void testTransitionExpungingToErrorHandlesNoTransitionException() throws Exception {
UserVmVO vm = mock(UserVmVO.class);
when(vm.getState()).thenReturn(VirtualMachine.State.Expunging);
when(userVmDao.findById(vmId)).thenReturn(vm);
when(virtualMachineManager.stateTransitTo(eq(vm), eq(VirtualMachine.Event.OperationFailedToError), eq(null)))
.thenThrow(new NoTransitionException("no transition"));
java.lang.reflect.Method method = UserVmManagerImpl.class.getDeclaredMethod("transitionExpungingToError", long.class);
method.setAccessible(true);
method.invoke(userVmManagerImpl, vmId);
}
}

View File

@ -31,6 +31,7 @@ import static org.mockito.Mockito.when;
import java.net.URI;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedHashMap;
@ -39,6 +40,9 @@ import java.util.Map;
import java.util.UUID;
import com.cloud.offering.DiskOffering;
import com.cloud.storage.Snapshot;
import com.cloud.storage.SnapshotVO;
import com.cloud.storage.dao.SnapshotDao;
import com.cloud.vm.ImportVMTaskVO;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.ResponseGenerator;
@ -241,6 +245,8 @@ public class UnmanagedVMsManagerImplTest {
private StoragePoolHostDao storagePoolHostDao;
@Mock
private ImportVmTasksManager importVmTasksManager;
@Mock
private SnapshotDao snapshotDao;
@Mock
private VMInstanceVO virtualMachine;
@ -360,7 +366,7 @@ public class UnmanagedVMsManagerImplTest {
when(primaryDataStoreDao.listPoolByHostPath(Mockito.anyString(), Mockito.anyString())).thenReturn(pools);
when(userVmManager.importVM(nullable(DataCenter.class), nullable(Host.class), nullable(VirtualMachineTemplate.class), nullable(String.class), nullable(String.class),
nullable(Account.class), nullable(String.class), nullable(Account.class), nullable(Boolean.class), nullable(String.class),
nullable(Long.class), nullable(Long.class), nullable(ServiceOffering.class), nullable(String.class),
nullable(Long.class), nullable(Long.class), nullable(ServiceOffering.class), nullable(String.class), nullable(Long.class),
nullable(String.class), nullable(Hypervisor.HypervisorType.class), nullable(Map.class), nullable(VirtualMachine.PowerState.class), nullable(LinkedHashMap.class))).thenReturn(userVm);
NetworkVO networkVO = Mockito.mock(NetworkVO.class);
when(networkVO.getGuestType()).thenReturn(Network.GuestType.L2);
@ -568,6 +574,53 @@ public class UnmanagedVMsManagerImplTest {
unmanagedVMsManager.unmanageVMInstance(virtualMachineId, null, false);
}
@Test(expected = UnsupportedServiceException.class)
public void testUnmanageVMInstanceWithVolumeSnapshotsFail() {
when(virtualMachine.getType()).thenReturn(VirtualMachine.Type.User);
when(virtualMachine.getHypervisorType()).thenReturn(Hypervisor.HypervisorType.KVM);
when(virtualMachine.getState()).thenReturn(VirtualMachine.State.Stopped);
when(virtualMachine.getId()).thenReturn(virtualMachineId);
UserVmVO userVmVO = mock(UserVmVO.class);
when(userVmDao.findById(anyLong())).thenReturn(userVmVO);
when(vmDao.findById(virtualMachineId)).thenReturn(virtualMachine);
VolumeVO volumeVO = mock(VolumeVO.class);
long volumeId = 20L;
when(volumeVO.getId()).thenReturn(volumeId);
SnapshotVO snapshotVO = mock(SnapshotVO.class);
when(snapshotVO.getState()).thenReturn(Snapshot.State.BackedUp);
when(snapshotDao.listByVolumeId(volumeId)).thenReturn(Collections.singletonList(snapshotVO));
when(volumeDao.findByInstance(virtualMachineId)).thenReturn(Collections.singletonList(volumeVO));
unmanagedVMsManager.unmanageVMInstance(virtualMachineId, null, false);
}
@Test(expected = UnsupportedServiceException.class)
public void testUnmanageVMInstanceWithAssociatedIsoFail() {
when(virtualMachine.getType()).thenReturn(VirtualMachine.Type.User);
when(virtualMachine.getHypervisorType()).thenReturn(Hypervisor.HypervisorType.KVM);
when(virtualMachine.getState()).thenReturn(VirtualMachine.State.Stopped);
when(virtualMachine.getId()).thenReturn(virtualMachineId);
UserVmVO userVmVO = mock(UserVmVO.class);
when(userVmVO.getIsoId()).thenReturn(null);
when(userVmDao.findById(anyLong())).thenReturn(userVmVO);
when(vmDao.findById(virtualMachineId)).thenReturn(virtualMachine);
when(userVmVO.getIsoId()).thenReturn(1L);
unmanagedVMsManager.unmanageVMInstance(virtualMachineId, null, false);
}
@Test(expected = UnsupportedServiceException.class)
public void testUnmanageVMInstanceBelongingToCksClusterFail() {
when(virtualMachine.getType()).thenReturn(VirtualMachine.Type.User);
when(virtualMachine.getHypervisorType()).thenReturn(Hypervisor.HypervisorType.KVM);
when(virtualMachine.getState()).thenReturn(VirtualMachine.State.Stopped);
when(virtualMachine.getId()).thenReturn(virtualMachineId);
UserVmVO userVmVO = mock(UserVmVO.class);
when(userVmVO.getIsoId()).thenReturn(null);
when(userVmDao.findById(anyLong())).thenReturn(userVmVO);
when(vmDao.findById(virtualMachineId)).thenReturn(virtualMachine);
when(userVmManager.isVMPartOfAnyCKSCluster(virtualMachine)).thenReturn(true);
unmanagedVMsManager.unmanageVMInstance(virtualMachineId, null, false);
}
@Test
public void testListRemoteInstancesTest() {
ListVmsForImportCmd cmd = Mockito.mock(ListVmsForImportCmd.class);

View File

@ -542,7 +542,7 @@ class TestRouters(cloudstackTestCase):
# Validate the following
# 1. PreReq: have rounters that are owned by other account
# 1. PreReq: have routers that are owned by other account
# 2. Create domain and create accounts in that domain
# 3. Create one VM for each account
# 4. Using Admin , run listRouters. It should return all the routers

View File

@ -136,7 +136,11 @@ class TestSecStorageServices(cloudstackTestCase):
'Up',
"Check state of primary storage pools is Up or not"
)
for _ in range(2):
# Poll until all SSVMs are Running, or timeout after 3 minutes
timeout = 180
interval = 15
list_ssvm_response = []
while timeout > 0:
list_ssvm_response = list_ssvms(
self.apiclient,
systemvmtype='secondarystoragevm',
@ -154,10 +158,12 @@ class TestSecStorageServices(cloudstackTestCase):
"Check list System VMs response"
)
for ssvm in list_ssvm_response:
if ssvm.state != 'Running':
time.sleep(30)
continue
if all(ssvm.state == 'Running' for ssvm in list_ssvm_response):
break
time.sleep(interval)
timeout -= interval
for ssvm in list_ssvm_response:
self.assertEqual(
ssvm.state,

Some files were not shown because too many files have changed in this diff Show More