mirror of https://github.com/apache/cloudstack.git
Merge branch 'main' into domain-name-regex-characters-not-scaped
This commit is contained in:
commit
e26c9a68ec
|
|
@ -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
|
||||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -162,4 +162,6 @@ public interface Nic extends Identity, InternalIdentity {
|
|||
String getIPv6Address();
|
||||
|
||||
Integer getMtu();
|
||||
|
||||
boolean isEnabled();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
//
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
||||
public void setVmId(String vmId) {
|
||||
this.vmId = vmId;
|
||||
}
|
||||
|
|
@ -416,4 +420,12 @@ public class NicResponse extends BaseResponse {
|
|||
public void setPublicIp(String publicIp) {
|
||||
this.publicIp = publicIp;
|
||||
}
|
||||
|
||||
public Boolean getEnabled() {
|
||||
return isEnabled;
|
||||
}
|
||||
|
||||
public void setEnabled(Boolean enabled) {
|
||||
isEnabled = enabled;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -230,6 +230,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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -114,3 +114,6 @@ 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'' ');
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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`,
|
||||
`vpc`.`id` AS `vpc_id`,
|
||||
`vpc`.`uuid` AS `vpc_uuid`,
|
||||
`networks`.`uuid` AS `network_uuid`,
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@
|
|||
<appender-ref ref="EventLogAppender"/>
|
||||
</root>
|
||||
</log4net>
|
||||
|
||||
|
||||
<applicationSettings>
|
||||
<CloudStack.Plugin.AgentShell.AgentSettings>
|
||||
<setting name="cpus" serializeAs="String">
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
-->
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
-->
|
||||
|
|
|
|||
|
|
@ -275,6 +275,7 @@ public class BridgeVifDriver extends VifDriverBase {
|
|||
if (nic.getPxeDisable()) {
|
||||
intf.setPxeDisable(true);
|
||||
}
|
||||
intf.setLinkStateUp(nic.isEnabled());
|
||||
|
||||
return intf;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -2230,6 +2230,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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1929,6 +1929,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);
|
||||
|
|
@ -4844,6 +4850,8 @@ public class ApiResponseHelper implements ResponseGenerator {
|
|||
VpcVO vpc = _entityMgr.findByUuidIncludingRemoved(VpcVO.class, userVm.getVpcUuid());
|
||||
response.setVpcName(vpc.getName());
|
||||
}
|
||||
|
||||
response.setEnabled(result.isEnabled());
|
||||
return response;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -358,6 +358,7 @@ public class UserVmJoinDaoImpl extends GenericDaoBaseWithTagInformation<UserVmJo
|
|||
nicResponse.setIp6Address(userVm.getIp6Address());
|
||||
nicResponse.setIp6Gateway(userVm.getIp6Gateway());
|
||||
nicResponse.setIp6Cidr(userVm.getIp6Cidr());
|
||||
nicResponse.setEnabled(userVm.isNicEnabled());
|
||||
if (userVm.getBroadcastUri() != null) {
|
||||
nicResponse.setBroadcastUri(userVm.getBroadcastUri().toString());
|
||||
}
|
||||
|
|
@ -625,6 +626,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>();
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -345,6 +345,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;
|
||||
|
||||
|
|
@ -1089,4 +1092,8 @@ public class UserVmJoinVO extends BaseViewWithTagInformationVO implements Contro
|
|||
public String getLeaseActionExecution() {
|
||||
return leaseActionExecution;
|
||||
}
|
||||
|
||||
public boolean isNicEnabled() {
|
||||
return isNicEnabled;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
|
|
|
|||
|
|
@ -567,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;
|
||||
|
|
@ -4165,6 +4166,7 @@ public class ManagementServerImpl extends MutualExclusiveIdsManagerBase implemen
|
|||
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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
@ -3886,6 +3888,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);
|
||||
|
|
|
|||
|
|
@ -99,6 +99,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;
|
||||
|
|
@ -1899,6 +1900,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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
@ -245,6 +246,9 @@ public class UserVmManagerImplTest {
|
|||
@Mock
|
||||
private UpdateVMCmd updateVmCommand;
|
||||
|
||||
@Mock
|
||||
private UpdateVmNicCmd updateVmNicCmd;
|
||||
|
||||
@Mock
|
||||
private AccountManager accountManager;
|
||||
|
||||
|
|
@ -272,6 +276,9 @@ public class UserVmManagerImplTest {
|
|||
@Mock
|
||||
private UserVO callerUser;
|
||||
|
||||
@Mock
|
||||
private NicVO nicMock;
|
||||
|
||||
@Mock
|
||||
private VMTemplateDao templateDao;
|
||||
|
||||
|
|
@ -455,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;
|
||||
|
|
@ -4254,6 +4263,61 @@ public class UserVmManagerImplTest {
|
|||
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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -174,6 +174,7 @@ known_categories = {
|
|||
'removeIpFromNic': 'Nic',
|
||||
'updateVmNicIp': 'Nic',
|
||||
'listNics':'Nic',
|
||||
'updateVmNic': 'Nic',
|
||||
'AffinityGroup': 'Affinity Group',
|
||||
'ImageStore': 'Image Store',
|
||||
'addImageStore': 'Image Store',
|
||||
|
|
|
|||
|
|
@ -5,9 +5,9 @@
|
|||
# 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
|
||||
|
|
|
|||
|
|
@ -5,9 +5,9 @@
|
|||
# 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
|
||||
|
|
|
|||
|
|
@ -15,14 +15,14 @@ What this tool is capable to do is
|
|||
|
||||
The usage is as follows
|
||||
1. First run fresh_install_data_collection.sh file to generate data from fresh install setup .
|
||||
This will be used for comparing between fresh install and upgrade setup.
|
||||
This will be used for comparing between fresh install and upgrade setup.
|
||||
This is a onetime activity and need to be repeated only when there is some DB changes for that release .
|
||||
Output of this script will come in a base_data folder
|
||||
Output of this script will come in a base_data folder
|
||||
|
||||
2. Just before upgrade you need to run before_upgrade_data_collection.sh file to collect required data needed to compare before upgrade and after upgrade setup data
|
||||
The output of this script will come in folder data_before_upgrade
|
||||
|
||||
3. After upgrade run cloud_schema_comparision.sh to compare cloud database all tables schema between fresh and upgraded setup.
|
||||
3. After upgrade run cloud_schema_comparision.sh to compare cloud database all tables schema between fresh and upgraded setup.
|
||||
NOTE: this script requires step 1 output in current working directory
|
||||
|
||||
4. After upgrade run usage_schema_comparision.sh to compare cloud usage all tables schema between fresh and upgraded setup
|
||||
|
|
@ -41,4 +41,4 @@ The usage is as follows
|
|||
• Database user
|
||||
• Database user password
|
||||
|
||||
8. Result will be shown in the form of files .
|
||||
8. Result will be shown in the form of files .
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ The following tree shows the basic UI codebase filesystem:
|
|||
|
||||
```bash
|
||||
src
|
||||
├── assests # sprites, icons, images
|
||||
├── assets # sprites, icons, images
|
||||
├── components # Shared vue files used to render various generic / widely used components
|
||||
├── config # Contains the layout details of the various routes / sections available in the UI
|
||||
├── locales # Custom translation keys for the various supported languages
|
||||
|
|
|
|||
|
|
@ -993,6 +993,7 @@
|
|||
"label.edit.acl": "Edit ACL",
|
||||
"label.edit.acl.rule": "Edit ACL rule",
|
||||
"label.edit.autoscale.vmprofile": "Edit AutoScale Instance Profile",
|
||||
"label.edit.nic": "Edit NIC",
|
||||
"label.edit.project.details": "Edit project details",
|
||||
"label.edit.project.role": "Edit project role",
|
||||
"label.edit.role": "Edit Role",
|
||||
|
|
@ -3735,6 +3736,7 @@
|
|||
"message.network.selection": "Choose one or more Networks to attach the Instance to.",
|
||||
"message.network.selection.new.network": "A new Network can also be created here.",
|
||||
"message.network.updateip": "Please confirm that you would like to change the IP address for this NIC on the Instance.",
|
||||
"message.network.update.nic": "Please confirm that you would like to update this NIC.",
|
||||
"message.network.usage.info.data.points": "Each data point represents the difference in data traffic since the last data point.",
|
||||
"message.network.usage.info.sum.of.vnics": "The Network usage shown is made up of the sum of data traffic from all the vNICs in the Instance.",
|
||||
"message.nfs.mount.options.description": "Comma separated list of NFS mount options for KVM hosts. Supported options : vers=[3,4.0,4.1,4.2], nconnect=[1...16]",
|
||||
|
|
@ -4018,13 +4020,14 @@
|
|||
"message.success.delete.vgpu.profile": "Successfully deleted vGPU profile",
|
||||
"message.success.update.custom.action": "Successfully updated Custom Action",
|
||||
"message.success.update.extension": "Successfully updated Extension",
|
||||
"message.success.update.sharedfs": "Successfully updated Shared FileSystem",
|
||||
"message.success.update.ipaddress": "Successfully updated IP address",
|
||||
"message.success.update.iprange": "Successfully updated IP range",
|
||||
"message.success.update.ipv4.subnet": "Successfully updated IPv4 subnet",
|
||||
"message.success.update.iso": "Successfully updated ISO",
|
||||
"message.success.update.kubeversion": "Successfully updated Kubernetes supported version",
|
||||
"message.success.update.network": "Successfully updated Network",
|
||||
"message.success.update.nic": "Successfully updated NIC",
|
||||
"message.success.update.sharedfs": "Successfully updated Shared FileSystem",
|
||||
"message.success.update.template": "Successfully updated Template",
|
||||
"message.success.update.user": "Successfully updated User",
|
||||
"message.success.update.vpn.customer.gateway": "Successfully updated VPN Customer Gateway",
|
||||
|
|
@ -4074,6 +4077,7 @@
|
|||
"message.two.fa.setup.page": "Two factor authentication (2FA) is an extra layer of security to your account.<br> Once setup is done, on every login you will be prompted to enter the 2FA code.<br>",
|
||||
"message.two.fa.view.setup.key": "Click here to view the setup key",
|
||||
"message.two.fa.view.static.pin": "Click here to view the static PIN",
|
||||
"message.update.nic.processing": "Updating NIC...",
|
||||
"message.update.ipaddress.processing": "Updating IP Address...",
|
||||
"message.update.resource.count": "Please confirm that you want to update resource counts for this Account.",
|
||||
"message.update.resource.count.domain": "Please confirm that you want to update resource counts for this domain.",
|
||||
|
|
|
|||
|
|
@ -623,6 +623,7 @@
|
|||
"label.edit": "Editar",
|
||||
"label.edit.acl": "Editar lista ACL",
|
||||
"label.edit.acl.rule": "Editar regra ACL",
|
||||
"label.edit.nic": "Editar NIC",
|
||||
"label.edit.project.details": "Editar detalhes do projeto",
|
||||
"label.edit.project.role": "Editar fun\u00e7\u00e3o do projeto",
|
||||
"label.edit.role": "Editar fun\u00e7\u00e3o",
|
||||
|
|
@ -2298,6 +2299,7 @@
|
|||
"message.network.removenic": "Por favor, confirme que deseja remover esta interface de rede, esta a\u00e7\u00e3o tamb\u00e9m ir\u00e1 remover a rede associada \u00e0 VM.",
|
||||
"message.network.secondaryip": "Por favor, confirme que voc\u00ea gostaria de adquirir um novo IP secund\u00e1rio para este NIC. \n NOTA: Voc\u00ea precisa configurar manualmente o IP secund\u00e1rio rec\u00e9m-adquirido dentro da m\u00e1quina virtual.",
|
||||
"message.network.updateip": "Por favor, confirme que voc\u00ea gostaria de mudar o endere\u00e7o IP da NIC em VM.",
|
||||
"message.network.update.nic": "Por favor, confirme que voc\u00ea gostaria de atualizar esta NIC.",
|
||||
"message.network.usage.info.data.points": "Cada ponto no gr\u00e1fico representa a diferen\u00e7a de dados trafegados desde a \u00faltima coleta de estat\u00edstica realizada (o ponto anterior)",
|
||||
"message.network.usage.info.sum.of.vnics": "O uso de rede apresentado \u00e9 composto pela soma de dados trafegados por todas as vNICs da VM",
|
||||
"message.no.data.to.show.for.period": "Nenhum dado para mostrar no per\u00edodo selecionado.",
|
||||
|
|
@ -2455,6 +2457,7 @@
|
|||
"message.success.update.iprange": "Intervalo de IP atualizado com sucesso",
|
||||
"message.success.update.kubeversion": "Vers\u00e3o compat\u00edvel com Kubernetes atualizada com sucesso",
|
||||
"message.success.update.network": "Rede atualizada com sucesso",
|
||||
"message.success.update.nic": "NIC atualizada com sucesso",
|
||||
"message.success.update.user": "Usu\u00e1rio atualizado com sucesso",
|
||||
"message.success.upgrade.kubernetes": "Cluster do Kubernetes atualizado com sucesso",
|
||||
"message.success.upload": "Carregado com sucesso",
|
||||
|
|
@ -2471,6 +2474,7 @@
|
|||
"message.template.iso": "Selecione o template ou ISO para continuar",
|
||||
"message.tooltip.reserved.system.netmask": "O prefixo de rede que define a subrede deste pod. utilize a nota\u00e7\u00e3o CIDR.",
|
||||
"message.traffic.type.to.basic.zone": "Tipo de tr\u00e1fego para a zona b\u00e1sica",
|
||||
"message.update.nic.processing": "Atualizando NIC...",
|
||||
"message.update.ipaddress.processing": "Atualizando endere\u00e7o IP...",
|
||||
"message.update.resource.count": "Por favor confirme que voc\u00ea quer atualizar a contagem de recursos para esta conta.",
|
||||
"message.update.resource.count.domain": "Por favor, confirme que voc\u00ea deseja atualizar as contagens de recursos para este dom\u00ednio.",
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="52px" height="45px" viewBox="0 0 52 45" version="1.1"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
<svg width="52px" height="45px" viewBox="0 0 52 45" version="1.1"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<defs>
|
||||
<filter x="-9.4%" y="-6.2%" width="118.8%" height="122.5%" filterUnits="objectBoundingBox" id="filter-1">
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 2.5 KiB |
|
|
@ -54,6 +54,13 @@
|
|||
icon="environment-outlined"
|
||||
:disabled="(!('addIpToNic' in $store.getters.apis) && !('addIpToNic' in $store.getters.apis))"
|
||||
@onClick="onAcquireSecondaryIPAddress(record)" />
|
||||
<tooltip-button
|
||||
v-if="resource.hypervisor === 'KVM'"
|
||||
tooltipPlacement="bottom"
|
||||
:tooltip="$t('label.edit.nic')"
|
||||
icon="edit-outlined"
|
||||
:disabled="(!('updateVmNic' in $store.getters.apis))"
|
||||
@onClick="onUpdateNic(record)" />
|
||||
<a-popconfirm
|
||||
:title="$t('message.network.removenic')"
|
||||
@confirm="removeNIC(record.nic)"
|
||||
|
|
@ -195,7 +202,7 @@
|
|||
<a-divider />
|
||||
<div v-ctrl-enter="submitSecondaryIP">
|
||||
<div class="modal-form">
|
||||
<p class="modal-form__label">{{ $t('label.publicip') }}:</p>
|
||||
<p class="modal-form__label--no-margin">{{ $t('label.publicip') }}:</p>
|
||||
<a-select
|
||||
v-if="editNicResource.type==='Shared'"
|
||||
v-model:value="newSecondaryIp"
|
||||
|
|
@ -243,6 +250,31 @@
|
|||
</a-list-item>
|
||||
</a-list>
|
||||
</a-modal>
|
||||
|
||||
<a-modal
|
||||
:visible="showUpdateNicModal"
|
||||
:title="$t('label.edit.nic')"
|
||||
:maskClosable="false"
|
||||
:closable="true"
|
||||
:footer="null"
|
||||
@cancel="closeModals"
|
||||
>
|
||||
{{ $t('message.network.update.nic') }}
|
||||
|
||||
<a-form
|
||||
@finish="submitUpdateNic"
|
||||
v-ctrl-enter="submitUpdateNic">
|
||||
<a-form-item name="linkstate" ref="linkstate">
|
||||
<p class="modal-form__label">{{ $t('state.enabled') }}:</p>
|
||||
<a-switch v-model:checked="editNicStateValue" @change="val => { editNicStateValue = val }" />
|
||||
</a-form-item>
|
||||
|
||||
<div :span="24" class="action-button">
|
||||
<a-button @click="closeModals">{{ $t('label.cancel') }}</a-button>
|
||||
<a-button type="primary" ref="submit" @click="submitUpdateNic">{{ $t('label.ok') }}</a-button>
|
||||
</div>
|
||||
</a-form>
|
||||
</a-modal>
|
||||
</a-spin>
|
||||
</template>
|
||||
|
||||
|
|
@ -279,6 +311,7 @@ export default {
|
|||
showAddNetworkModal: false,
|
||||
showUpdateIpModal: false,
|
||||
showSecondaryIpModal: false,
|
||||
showUpdateNicModal: false,
|
||||
addNetworkData: {
|
||||
allNetworks: [],
|
||||
network: '',
|
||||
|
|
@ -289,6 +322,7 @@ export default {
|
|||
editIpAddressNic: '',
|
||||
editIpAddressValue: '',
|
||||
editNetworkId: '',
|
||||
editNicStateValue: false,
|
||||
secondaryIPs: [],
|
||||
selectedNicId: '',
|
||||
newSecondaryIp: '',
|
||||
|
|
@ -360,6 +394,7 @@ export default {
|
|||
this.showAddNetworkModal = false
|
||||
this.showUpdateIpModal = false
|
||||
this.showSecondaryIpModal = false
|
||||
this.showUpdateNicModal = false
|
||||
this.addNetworkData.network = ''
|
||||
this.addNetworkData.ipaddress = ''
|
||||
this.addNetworkData.macaddress = ''
|
||||
|
|
@ -386,6 +421,11 @@ export default {
|
|||
this.editNetworkId = record.nic.networkid
|
||||
this.fetchSecondaryIPs(record.nic.id)
|
||||
},
|
||||
onUpdateNic (record) {
|
||||
this.editNicResource = record.nic
|
||||
this.editNicStateValue = record.nic.enabled
|
||||
this.showUpdateNicModal = true
|
||||
},
|
||||
submitAddNetwork () {
|
||||
if (this.loadingNic) return
|
||||
const params = {}
|
||||
|
|
@ -609,12 +649,46 @@ export default {
|
|||
this.loadingNic = false
|
||||
this.fetchSecondaryIPs(this.selectedNicId)
|
||||
})
|
||||
},
|
||||
submitUpdateNic () {
|
||||
if (this.loadingNic) return
|
||||
this.loadingNic = true
|
||||
this.showUpdateNicModal = false
|
||||
const params = {
|
||||
nicId: this.editNicResource.id,
|
||||
enabled: this.editNicStateValue
|
||||
}
|
||||
postAPI('updateVmNic', params).then(response => {
|
||||
this.$pollJob({
|
||||
jobId: response.updatevmnicresponse.jobid,
|
||||
successMessage: this.$t('message.success.update.nic'),
|
||||
successMethod: () => {
|
||||
this.loadingNic = false
|
||||
this.closeModals()
|
||||
},
|
||||
errorMessage: this.$t('label.error'),
|
||||
errorMethod: () => {
|
||||
this.loadingNic = false
|
||||
this.closeModals()
|
||||
},
|
||||
loadingMessage: this.$t('message.update.nic.processing'),
|
||||
catchMessage: this.$t('error.fetching.async.job.result'),
|
||||
catchMethod: () => {
|
||||
this.loadingNic = false
|
||||
this.closeModals()
|
||||
this.$emit('refresh')
|
||||
}
|
||||
})
|
||||
}).catch(error => {
|
||||
this.$notifyError(error)
|
||||
this.loadingNic = false
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
<style lang="scss" scoped>
|
||||
.modal-form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
|
@ -626,6 +700,7 @@ export default {
|
|||
|
||||
&--no-margin {
|
||||
margin-top: 0;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -71,6 +71,9 @@
|
|||
{{ $t('label.default') }}
|
||||
</a-tag>
|
||||
</template>
|
||||
<template v-if="column.key === 'enabled'">
|
||||
<status :text="text ? 'enabled' : 'disabled'"/> {{ text ? 'Enabled' : 'Disabled' }}
|
||||
</template>
|
||||
</template>
|
||||
</a-table>
|
||||
</template>
|
||||
|
|
@ -78,6 +81,7 @@
|
|||
<script>
|
||||
import { getAPI } from '@/api'
|
||||
import ResourceIcon from '@/components/view/ResourceIcon'
|
||||
import Status from '@/components/widgets/Status'
|
||||
|
||||
export default {
|
||||
name: 'NicsTable',
|
||||
|
|
@ -92,7 +96,8 @@ export default {
|
|||
}
|
||||
},
|
||||
components: {
|
||||
ResourceIcon
|
||||
ResourceIcon,
|
||||
Status
|
||||
},
|
||||
inject: ['parentFetchData'],
|
||||
data () {
|
||||
|
|
@ -123,6 +128,11 @@ export default {
|
|||
{
|
||||
title: this.$t('label.gateway'),
|
||||
dataIndex: 'gateway'
|
||||
},
|
||||
{
|
||||
key: 'enabled',
|
||||
title: this.$t('label.state'),
|
||||
dataIndex: 'enabled'
|
||||
}
|
||||
],
|
||||
networkicon: {},
|
||||
|
|
|
|||
|
|
@ -380,7 +380,7 @@ public class Link {
|
|||
if (caService != null) {
|
||||
return caService.createSSLEngine(sslContext, clientAddress);
|
||||
}
|
||||
LOGGER.error("CA service is not configured, by-passing CA manager to create SSL engine");
|
||||
LOGGER.error("CA service is not configured, bypassing CA manager to create SSL engine");
|
||||
char[] passphrase = KeyStoreUtils.DEFAULT_KS_PASSPHRASE;
|
||||
final KeyStore ks = loadKeyStore(NioConnection.class.getResourceAsStream("/cloud.keystore"), passphrase);
|
||||
final KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
|
||||
|
|
|
|||
|
|
@ -753,7 +753,7 @@ public class VmwareHelper {
|
|||
|
||||
recommendedController = guestOsDescriptor.getRecommendedDiskController();
|
||||
|
||||
// By-pass auto detected PVSCSI controller to use LsiLogic Parallel instead
|
||||
// Bypass auto detected PVSCSI controller to use LsiLogic Parallel instead
|
||||
if (DiskControllerType.getType(recommendedController) == DiskControllerType.pvscsi) {
|
||||
recommendedController = DiskControllerType.lsilogic.toString();
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue