diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f561faa1fc2d..7e82b777cdb4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -232,7 +232,7 @@ jobs: - name: Install Python dependencies run: | - python3 -m pip install --user --upgrade urllib3 lxml paramiko nose texttable ipmisim pyopenssl pycrypto mock flask netaddr pylint pycodestyle six astroid + python3 -m pip install --user --upgrade urllib3 lxml paramiko nose texttable ipmisim pyopenssl pycrypto mock flask netaddr pylint pycodestyle six astroid pynose - name: Install jacoco dependencies run: | diff --git a/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java b/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java index efceafd1a3a2..b2042c116a7f 100644 --- a/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java +++ b/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java @@ -46,7 +46,6 @@ public class ApiConstants { public static final String BACKUP_OFFERING_NAME = "backupofferingname"; public static final String BACKUP_OFFERING_ID = "backupofferingid"; public static final String BASE64_IMAGE = "base64image"; - public static final String BATCH_SIZE = "batchsize"; public static final String BITS = "bits"; public static final String BOOTABLE = "bootable"; public static final String BIND_DN = "binddn"; @@ -438,12 +437,11 @@ public class ApiConstants { public static final String STATE = "state"; public static final String STATS = "stats"; public static final String STATUS = "status"; + public static final String STORAGE_TYPE = "storagetype"; + public static final String STORAGE_POLICY = "storagepolicy"; + public static final String STORAGE_MOTION_ENABLED = "storagemotionenabled"; public static final String STORAGE_CAPABILITIES = "storagecapabilities"; public static final String STORAGE_CUSTOM_STATS = "storagecustomstats"; - public static final String STORAGE_MOTION_ENABLED = "storagemotionenabled"; - public static final String STORAGE_POLICY = "storagepolicy"; - public static final String STORAGE_POOL = "storagepool"; - public static final String STORAGE_TYPE = "storagetype"; public static final String SUBNET = "subnet"; public static final String OWNER = "owner"; public static final String SWAP_OWNER = "swapowner"; @@ -1108,7 +1106,6 @@ public class ApiConstants { public static final String PARAMETER_DESCRIPTION_IS_TAG_A_RULE = "Whether the informed tag is a JS interpretable rule or not."; public static final String NFS_MOUNT_OPTIONS = "nfsmountopts"; - public static final String VMWARE_DC = "vmwaredc"; /** * This enum specifies IO Drivers, each option controls specific policies on I/O. diff --git a/api/src/main/java/org/apache/cloudstack/api/response/HostResponse.java b/api/src/main/java/org/apache/cloudstack/api/response/HostResponse.java index cb759d9ab6d0..99aabd889134 100644 --- a/api/src/main/java/org/apache/cloudstack/api/response/HostResponse.java +++ b/api/src/main/java/org/apache/cloudstack/api/response/HostResponse.java @@ -152,7 +152,7 @@ public class HostResponse extends BaseResponseWithAnnotations { @Deprecated @SerializedName("memoryallocated") @Param(description = "the amount of the host's memory currently allocated") - private Long memoryAllocated; + private long memoryAllocated; @SerializedName("memoryallocatedpercentage") @Param(description = "the amount of the host's memory currently allocated in percentage") @@ -395,7 +395,7 @@ public void setMemWithOverprovisioning(String memWithOverprovisioning){ this.memWithOverprovisioning=memWithOverprovisioning; } - public void setMemoryAllocated(Long memoryAllocated) { + public void setMemoryAllocated(long memoryAllocated) { this.memoryAllocated = memoryAllocated; } @@ -659,8 +659,8 @@ public Long getMemoryTotal() { return memoryTotal; } - public Long getMemoryAllocated() { - return memoryAllocated == null ? 0 : memoryAllocated; + public long getMemoryAllocated() { + return memoryAllocated; } public void setMemoryAllocatedPercentage(String memoryAllocatedPercentage) { diff --git a/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java b/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java index 055c1a2d444d..f2e90decdea8 100755 --- a/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java +++ b/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java @@ -5248,10 +5248,9 @@ public Outcome migrateVmAwayThroughJobQueue(final String vmUuid, workJob = newVmWorkJobAndInfo.first(); VmWorkMigrateAway workInfo = new VmWorkMigrateAway(newVmWorkJobAndInfo.second(), srcHostId); - workJob.setCmdInfo(VmWorkSerializer.serialize(workInfo)); + setCmdInfoAndSubmitAsyncJob(workJob, workInfo, vmId); } - _jobMgr.submitAsyncJob(workJob, VmWorkConstants.VM_WORK_QUEUE, vmId); AsyncJobExecutionContext.getCurrentExecutionContext().joinJob(workJob.getId()); diff --git a/engine/schema/src/main/java/com/cloud/vm/VMInstanceVO.java b/engine/schema/src/main/java/com/cloud/vm/VMInstanceVO.java index f3560d68f495..320c9a30fb45 100644 --- a/engine/schema/src/main/java/com/cloud/vm/VMInstanceVO.java +++ b/engine/schema/src/main/java/com/cloud/vm/VMInstanceVO.java @@ -502,7 +502,7 @@ public void setRemoved(Date removed) { @Override public String toString() { - return String.format("VM instance %s", ReflectionToStringBuilderUtils.reflectOnlySelectedFields(this, "id", "instanceName", "uuid", "type")); + return String.format("VM instance %s", ReflectionToStringBuilderUtils.reflectOnlySelectedFields(this, "id", "instanceName", "uuid", "type", "state")); } @Override diff --git a/framework/cluster/src/main/java/com/cloud/cluster/ClusterManagerImpl.java b/framework/cluster/src/main/java/com/cloud/cluster/ClusterManagerImpl.java index d601c094ca76..e684f6fd42f4 100644 --- a/framework/cluster/src/main/java/com/cloud/cluster/ClusterManagerImpl.java +++ b/framework/cluster/src/main/java/com/cloud/cluster/ClusterManagerImpl.java @@ -1052,12 +1052,24 @@ public boolean stop() { } if (_mshostId != null) { - final ManagementServerHostVO mshost = _mshostDao.findByMsid(_msId); - final ManagementServerStatusVO mshostStatus = mshostStatusDao.findByMsId(mshost.getUuid()); - mshost.setState(ManagementServerHost.State.Down); - mshostStatus.setLastJvmStop(new Date()); - _mshostDao.update(_mshostId, mshost); - mshostStatusDao.update(mshostStatus.getId(), mshostStatus); + ManagementServerHostVO mshost = _mshostDao.findByMsid(_msId); + if (mshost != null) { + ManagementServerStatusVO mshostStatus = mshostStatusDao.findByMsId(mshost.getUuid()); + if (mshostStatus != null) { + mshost.setState(ManagementServerHost.State.Down); + mshostStatus.setLastJvmStop(new Date()); + _mshostDao.update(_mshostId, mshost); + mshostStatusDao.update(mshostStatus.getId(), mshostStatus); + } else { + s_logger.warn(String.format("Found a management server host [%s] without a status. This should never happen!", mshost)); + mshostStatus = new ManagementServerStatusVO(); + mshostStatus.setMsId(mshost.getUuid()); + mshostStatus.setLastSystemBoot(new Date()); + mshostStatus.setLastJvmStart(new Date()); + mshostStatus.setUpdated(new Date()); + mshostStatusDao.persist(mshostStatus); + } + } } _heartbeatScheduler.shutdownNow(); diff --git a/plugins/acl/dynamic-role-based/src/main/java/org/apache/cloudstack/acl/DynamicRoleBasedAPIAccessChecker.java b/plugins/acl/dynamic-role-based/src/main/java/org/apache/cloudstack/acl/DynamicRoleBasedAPIAccessChecker.java index 005eb2a8fd4f..1dfe20a10be2 100644 --- a/plugins/acl/dynamic-role-based/src/main/java/org/apache/cloudstack/acl/DynamicRoleBasedAPIAccessChecker.java +++ b/plugins/acl/dynamic-role-based/src/main/java/org/apache/cloudstack/acl/DynamicRoleBasedAPIAccessChecker.java @@ -47,14 +47,14 @@ public class DynamicRoleBasedAPIAccessChecker extends AdapterBase implements API private RoleService roleService; private List services; - private Map> annotationRoleBasedApisMap = new HashMap<>(); + private Map> annotationRoleBasedApisMap = new HashMap>(); private static final Logger LOGGER = Logger.getLogger(DynamicRoleBasedAPIAccessChecker.class.getName()); protected DynamicRoleBasedAPIAccessChecker() { super(); for (RoleType roleType : RoleType.values()) { - annotationRoleBasedApisMap.put(roleType, new HashSet<>()); + annotationRoleBasedApisMap.put(roleType, new HashSet()); } } diff --git a/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/VmwareDatacenterService.java b/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/VmwareDatacenterService.java index 6bb473536b86..92d8af6b5f26 100644 --- a/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/VmwareDatacenterService.java +++ b/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/VmwareDatacenterService.java @@ -24,13 +24,12 @@ import com.cloud.exception.ResourceInUseException; import com.cloud.hypervisor.vmware.mo.HostMO; import com.cloud.storage.StoragePool; -import com.cloud.utils.Pair; import com.cloud.utils.component.PluggableService; import com.cloud.utils.exception.CloudRuntimeException; import org.apache.cloudstack.api.command.admin.zone.AddVmwareDcCmd; import org.apache.cloudstack.api.command.admin.zone.ImportVsphereStoragePoliciesCmd; -import org.apache.cloudstack.api.command.admin.zone.ListVmwareDcVmsCmd; import org.apache.cloudstack.api.command.admin.zone.ListVmwareDcHostsCmd; +import org.apache.cloudstack.api.command.admin.zone.ListVmwareDcVmsCmd; import org.apache.cloudstack.api.command.admin.zone.ListVmwareDcsCmd; import org.apache.cloudstack.api.command.admin.zone.ListVsphereStoragePoliciesCmd; import org.apache.cloudstack.api.command.admin.zone.ListVsphereStoragePolicyCompatiblePoolsCmd; @@ -56,7 +55,7 @@ public interface VmwareDatacenterService extends PluggableService { List listVsphereStoragePolicyCompatibleStoragePools(ListVsphereStoragePolicyCompatiblePoolsCmd cmd); - List listHostsInDatacenter(ListVmwareDcHostsCmd cmd); + List listVMsInDatacenter(ListVmwareDcVmsCmd cmd); - Pair> listVMsInDatacenter(ListVmwareDcVmsCmd cmd); + List listHostsInDatacenter(ListVmwareDcHostsCmd cmd); } diff --git a/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/manager/VmwareManagerImpl.java b/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/manager/VmwareManagerImpl.java index 2d733e8a16cb..213deb6f3411 100644 --- a/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/manager/VmwareManagerImpl.java +++ b/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/manager/VmwareManagerImpl.java @@ -19,12 +19,10 @@ import java.io.File; import java.io.FileInputStream; import java.io.IOException; -import java.lang.reflect.InvocationTargetException; import java.net.URI; import java.net.URISyntaxException; import java.net.URL; import java.net.URLDecoder; -import java.nio.charset.StandardCharsets; import java.rmi.RemoteException; import java.time.Duration; import java.time.Instant; @@ -45,11 +43,13 @@ import javax.naming.ConfigurationException; import javax.persistence.EntityExistsException; +import com.cloud.hypervisor.vmware.mo.VirtualMachineMO; +import com.cloud.hypervisor.vmware.util.VmwareClient; import org.apache.cloudstack.api.command.admin.zone.AddVmwareDcCmd; import org.apache.cloudstack.api.command.admin.zone.ImportVsphereStoragePoliciesCmd; -import org.apache.cloudstack.api.command.admin.zone.ListVmwareDcVmsCmd; import org.apache.cloudstack.api.command.admin.zone.ListVmwareDcHostsCmd; import org.apache.cloudstack.api.command.admin.zone.ListVmwareDcItems; +import org.apache.cloudstack.api.command.admin.zone.ListVmwareDcVmsCmd; import org.apache.cloudstack.api.command.admin.zone.ListVmwareDcsCmd; import org.apache.cloudstack.api.command.admin.zone.ListVsphereStoragePoliciesCmd; import org.apache.cloudstack.api.command.admin.zone.ListVsphereStoragePolicyCompatiblePoolsCmd; @@ -90,7 +90,6 @@ import com.cloud.dc.ClusterVO; import com.cloud.dc.ClusterVSMMapVO; import com.cloud.dc.DataCenterVO; -import com.cloud.dc.VmwareDatacenter; import com.cloud.dc.VsphereStoragePolicy; import com.cloud.dc.VsphereStoragePolicyVO; import com.cloud.dc.dao.ClusterDao; @@ -116,8 +115,7 @@ import com.cloud.hypervisor.dao.HypervisorCapabilitiesDao; import com.cloud.hypervisor.vmware.LegacyZoneVO; import com.cloud.hypervisor.vmware.VmwareCleanupMaid; -import com.cloud.hypervisor.vmware.util.VmwareClient; -import com.cloud.hypervisor.vmware.util.VmwareClientException; +import com.cloud.dc.VmwareDatacenter; import com.cloud.hypervisor.vmware.VmwareDatacenterService; import com.cloud.dc.VmwareDatacenterVO; import com.cloud.hypervisor.vmware.VmwareDatacenterZoneMap; @@ -170,18 +168,13 @@ import com.cloud.utils.db.TransactionStatus; import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.script.Script; +import com.cloud.utils.ssh.SshHelper; +import com.cloud.vm.DomainRouterVO; import com.cloud.vm.dao.UserVmCloneSettingDao; import com.cloud.vm.dao.VMInstanceDao; - -// TODO move these items upstream? import com.vmware.pbm.PbmProfile; import com.vmware.vim25.AboutInfo; import com.vmware.vim25.ManagedObjectReference; -import com.vmware.vim25.InvalidLocaleFaultMsg; -import com.vmware.vim25.InvalidLoginFaultMsg; -import com.vmware.vim25.RuntimeFaultFaultMsg; -import com.vmware.vim25.InvalidPropertyFaultMsg; -import org.jetbrains.annotations.NotNull; public class VmwareManagerImpl extends ManagerBase implements VmwareManager, VmwareStorageMount, Listener, VmwareDatacenterService, Configurable { private static final Logger s_logger = Logger.getLogger(VmwareManagerImpl.class); @@ -257,11 +250,11 @@ public class VmwareManagerImpl extends ManagerBase implements VmwareManager, Vmw private StorageLayer _storage; private final String _privateNetworkVSwitchName = "vSwitch0"; - private final int _portsPerDvPortGroup = DEFAULT_PORTS_PER_DV_PORT_GROUP; + private int _portsPerDvPortGroup = DEFAULT_PORTS_PER_DV_PORT_GROUP; private boolean _fullCloneFlag; private boolean _instanceNameFlag; private String _serviceConsoleName; - private String _managementPortGroupName; + private String _managemetPortGroupName; private String _defaultSystemVmNicAdapterType = VirtualEthernetCardType.E1000.toString(); private String _recycleHungWorker = "false"; private int _additionalPortRangeStart; @@ -275,7 +268,7 @@ public class VmwareManagerImpl extends ManagerBase implements VmwareManager, Vmw private final Random _rand = new Random(System.currentTimeMillis()); - private static final ScheduledExecutorService templateCleanupScheduler = Executors.newScheduledThreadPool(1, new NamedThreadFactory("Vmware-FullyClonedTemplateCheck")); + private static ScheduledExecutorService templateCleanupScheduler = Executors.newScheduledThreadPool(1, new NamedThreadFactory("Vmware-FullyClonedTemplateCheck"));; private final VmwareStorageManager _storageMgr; private final GlobalLock _exclusiveOpLock = GlobalLock.getInternLock("vmware.exclusive.op"); @@ -359,9 +352,9 @@ public boolean configure(String name, Map params) throws Configu _serviceConsoleName = "Service Console"; } - _managementPortGroupName = _configDao.getValue(Config.VmwareManagementPortGroup.key()); - if (_managementPortGroupName == null) { - _managementPortGroupName = "Management Network"; + _managemetPortGroupName = _configDao.getValue(Config.VmwareManagementPortGroup.key()); + if (_managemetPortGroupName == null) { + _managemetPortGroupName = "Management Network"; } _defaultSystemVmNicAdapterType = _configDao.getValue(Config.VmwareSystemVmNicDeviceType.key()); @@ -460,7 +453,7 @@ private void prepareHost(HostMO hostMo, String privateTrafficLabel) throws Excep s_logger.info("Preparing network on host " + hostMo.getContext().toString() + " for " + privateTrafficLabel); VirtualSwitchType vsType = VirtualSwitchType.getType(vSwitchType); - //The management network is probably always going to be a physical network with isolation type of vlans, so assume BroadcastDomainType VLAN + //The management network is probably always going to be a physical network with islation type of vlans, so assume BroadcastDomainType VLAN if (VirtualSwitchType.StandardVirtualSwitch == vsType) { HypervisorHostHelper.prepareNetwork(vSwitchName, "cloud.private", hostMo, vlanId, null, null, 180000, false, BroadcastDomainType.Vlan, null, null); } @@ -469,7 +462,7 @@ private void prepareHost(HostMO hostMo, String privateTrafficLabel) throws Excep AboutInfo about = hostMo.getHostAboutInfo(); if (about != null) { String version = about.getApiVersion(); - if (version != null && (version.equals("4.0") || version.equals("4.1")) ) { // && _portsPerDvPortGroup < DEFAULT_PORTS_PER_DV_PORT_GROUP_VSPHERE4_x) + if (version != null && (version.equals("4.0") || version.equals("4.1")) && _portsPerDvPortGroup < DEFAULT_PORTS_PER_DV_PORT_GROUP_VSPHERE4_x) { portsPerDvPortGroup = DEFAULT_PORTS_PER_DV_PORT_GROUP_VSPHERE4_x; } } @@ -492,7 +485,7 @@ private HostMO getOldestExistentHostInCluster(Long clusterId, VmwareContext serv } URI uriForHost = new URI(UriUtils.encodeURIComponent(clusterDetails.get("url") + "/" + host.getName())); - morSrcHost = serviceContext.getHostMorByPath(URLDecoder.decode(uriForHost.getPath(), StandardCharsets.UTF_8)); + morSrcHost = serviceContext.getHostMorByPath(URLDecoder.decode(uriForHost.getPath(), "UTF-8")); if (morSrcHost == null) { return null; } @@ -508,18 +501,19 @@ public List addHostToPodCluster(VmwareContext serviceCon throw new CloudRuntimeException("Invalid serviceContext"); } ManagedObjectReference mor = serviceContext.getHostMorByPath(hostInventoryPath); - String privateTrafficLabel; + String privateTrafficLabel = null; privateTrafficLabel = serviceContext.getStockObject("privateTrafficLabel"); if (privateTrafficLabel == null) { privateTrafficLabel = _privateNetworkVSwitchName; } if (mor != null) { - List returnedHostList = new ArrayList<>(); + List returnedHostList = new ArrayList(); if (mor.getType().equals("ComputeResource")) { List hosts = serviceContext.getVimClient().getDynamicProperty(mor, "host"); - assert (CollectionUtils.isNullOrEmpty(hosts)); + assert (hosts != null && hosts.size() > 0); + // For ESX host, we need to enable host firewall to allow VNC access HostMO hostMo = new HostMO(serviceContext, hosts.get(0)); @@ -530,8 +524,8 @@ public List addHostToPodCluster(VmwareContext serviceCon List hosts = serviceContext.getVimClient().getDynamicProperty(mor, "host"); assert (hosts != null); - if (!hosts.isEmpty()) { - AboutInfo about = serviceContext.getVimClient().getDynamicProperty(hosts.get(0), "config.product"); + if (hosts.size() > 0) { + AboutInfo about = (AboutInfo)(serviceContext.getVimClient().getDynamicProperty(hosts.get(0), "config.product")); String version = about.getApiVersion(); int maxHostsPerCluster = _hvCapabilitiesDao.getMaxHostsPerCluster(HypervisorType.VMware, version); if (hosts.size() > maxHostsPerCluster) { @@ -560,7 +554,7 @@ public List addHostToPodCluster(VmwareContext serviceCon returnedHostList.add(mor); return returnedHostList; } else { - s_logger.error("Unsupported host type " + mor.getType() + ":" + mor.getValue() + " from inventory path: " + hostInventoryPath); + s_logger.error("Unsupport host type " + mor.getType() + ":" + mor.getValue() + " from inventory path: " + hostInventoryPath); return null; } } @@ -625,13 +619,13 @@ public String getServiceConsolePortGroupName() { @Override public String getManagementPortGroupName() { - return _managementPortGroupName; + return _managemetPortGroupName; } @Override public String getManagementPortGroupByHost(HostMO hostMo) throws Exception { if (hostMo.getHostType() == VmwareHostType.ESXi) { - return _managementPortGroupName; + return _managemetPortGroupName; } return _serviceConsoleName; } @@ -641,7 +635,7 @@ public void setupResourceStartupParams(Map params) { params.put("vmware.create.full.clone", _fullCloneFlag); params.put("vm.instancename.flag", _instanceNameFlag); params.put("service.console.name", _serviceConsoleName); - params.put("management.portgroup.name", _managementPortGroupName); + params.put("management.portgroup.name", _managemetPortGroupName); params.put("vmware.root.disk.controller", _rootDiskController); params.put("vmware.data.disk.controller", _dataDiskController); params.put("vmware.recycle.hung.wokervm", _recycleHungWorker); @@ -668,25 +662,25 @@ public boolean needRecycle(String workerTag) { return false; } - String[] tokens = workerTag.split("-"); + String tokens[] = workerTag.split("-"); if (tokens.length != 3) { s_logger.error("Invalid worker VM tag " + workerTag); return false; } long startTick = Long.parseLong(tokens[0]); - long msId = Long.parseLong(tokens[1]); - long runId = Long.parseLong(tokens[2]); + long msid = Long.parseLong(tokens[1]); + long runid = Long.parseLong(tokens[2]); - if (msHostPeerDao.countStateSeenInPeers(msId, runId, ManagementServerHost.State.Down) > 0) { + if (msHostPeerDao.countStateSeenInPeers(msid, runid, ManagementServerHost.State.Down) > 0) { if (s_logger.isInfoEnabled()) s_logger.info("Worker VM's owner management server node has been detected down from peer nodes, recycle it"); return true; } - if (runId != clusterManager.getManagementRunId(msId)) { + if (runid != clusterManager.getManagementRunId(msid)) { if (s_logger.isInfoEnabled()) - s_logger.info("Worker VM's owner management server has changed runId, recycle it"); + s_logger.info("Worker VM's owner management server has changed runid, recycle it"); return true; } @@ -721,7 +715,7 @@ public void prepareSecondaryStorageStore(String storageUrl, Long storeId) { File patchFolder = new File(mountPoint + "/systemvm"); if (!patchFolder.exists()) { if (!patchFolder.mkdirs()) { - String msg = "Unable to create systemvm folder on secondary storage. location: " + patchFolder; + String msg = "Unable to create systemvm folder on secondary storage. location: " + patchFolder.toString(); s_logger.error(msg); throw new CloudRuntimeException(msg); } @@ -740,7 +734,7 @@ public void prepareSecondaryStorageStore(String storageUrl, Long storeId) { } catch (IOException e) { s_logger.error("Unexpected exception ", e); - String msg = "Unable to copy systemvm ISO on secondary storage. src location: " + srcIso + ", dest location: " + destIso; + String msg = "Unable to copy systemvm ISO on secondary storage. src location: " + srcIso.toString() + ", dest location: " + destIso; s_logger.error(msg); throw new CloudRuntimeException(msg); } @@ -782,8 +776,9 @@ private File getSystemVMPatchIsoFile() { isoFile = new File("/usr/share/cloudstack-common/vms/systemvm.iso"); } + assert (isoFile != null); if (!isoFile.exists()) { - s_logger.error("Unable to locate systemvm.iso in your setup at " + isoFile); + s_logger.error("Unable to locate systemvm.iso in your setup at " + isoFile.toString()); } return isoFile; } @@ -798,16 +793,16 @@ public File getSystemVMKeyFile() { if (keyFile == null || !keyFile.exists()) { keyFile = new File("/usr/share/cloudstack-common/scripts/vm/systemvm/id_rsa.cloud"); } - + assert (keyFile != null); if (!keyFile.exists()) { - s_logger.error("Unable to locate id_rsa.cloud in your setup at " + keyFile); + s_logger.error("Unable to locate id_rsa.cloud in your setup at " + keyFile.toString()); } return keyFile; } @Override public String getMountPoint(String storageUrl, String nfsVersion) { - String mountPoint; + String mountPoint = null; synchronized (_storageMounts) { mountPoint = _storageMounts.get(storageUrl); if (mountPoint != null) { @@ -837,7 +832,7 @@ private String setupMountPoint(String parent) { String mountPoint = null; long mshostId = ManagementServerNode.getManagementServerId(); for (int i = 0; i < 10; i++) { - String mntPt = parent + File.separator + mshostId + "." + Integer.toHexString(_rand.nextInt(Integer.MAX_VALUE)); + String mntPt = parent + File.separator + String.valueOf(mshostId) + "." + Integer.toHexString(_rand.nextInt(Integer.MAX_VALUE)); File file = new File(mntPt); if (!file.exists()) { if (_storage.mkdir(mntPt)) { @@ -862,9 +857,10 @@ private void startupCleanup(String parent) { for (String mountPoint : mounts) { s_logger.info("umount NFS mount from previous session: " + mountPoint); + String result = null; Script command = new Script(true, "umount", _timeout, s_logger); command.add(mountPoint); - String result = command.execute(); + result = command.execute(); if (result != null) { s_logger.warn("Unable to umount " + mountPoint + " due to " + result); } @@ -882,7 +878,7 @@ private void shutdownCleanup() { for (String mountPoint : _storageMounts.values()) { s_logger.info("umount NFS mount: " + mountPoint); - String result; + String result = null; Script command = new Script(true, "umount", _timeout, s_logger); command.add(mountPoint); result = command.execute(); @@ -903,8 +899,8 @@ protected String mount(String path, String parent, String nfsVersion) { return null; } - Script script; - String result; + Script script = null; + String result = null; Script command = new Script(true, "mount", _timeout, s_logger); command.add("-t", "nfs"); if (nfsVersion != null){ @@ -991,15 +987,40 @@ public void processHostAdded(long hostId) { @Override public void processConnect(Host host, StartupCommand cmd, boolean forRebalance) { - if (cmd != null) { + if (cmd instanceof StartupCommand) { if (host.getHypervisorType() == HypervisorType.VMware) { updateClusterNativeHAState(host, cmd); + } else { + return; } } } protected final static int DEFAULT_DOMR_SSHPORT = 3922; + protected boolean shutdownRouterVM(DomainRouterVO router) { + if (s_logger.isDebugEnabled()) { + s_logger.debug("Try to shutdown router VM " + router.getInstanceName() + " directly."); + } + + Pair result; + try { + result = SshHelper.sshExecute(router.getPrivateIpAddress(), DEFAULT_DOMR_SSHPORT, "root", getSystemVMKeyFile(), null, "poweroff -f"); + + if (!result.first()) { + s_logger.debug("Unable to shutdown " + router.getInstanceName() + " directly"); + return false; + } + } catch (Throwable e) { + s_logger.warn("Unable to shutdown router " + router.getInstanceName() + " directly."); + return false; + } + if (s_logger.isDebugEnabled()) { + s_logger.debug("Shutdown router " + router.getInstanceName() + " successful."); + } + return true; + } + @Override public boolean processDisconnect(long agentId, Status state) { return false; @@ -1040,16 +1061,16 @@ public void endExclusiveOperation() { @Override public Pair getAddiionalVncPortRange() { - return new Pair<>(_additionalPortRangeStart, _additionalPortRangeSize); + return new Pair(_additionalPortRangeStart, _additionalPortRangeSize); } @Override public Map getNexusVSMCredentialsByClusterId(Long clusterId) { - CiscoNexusVSMDeviceVO nexusVSM; - ClusterVSMMapVO vsmMapVO; + CiscoNexusVSMDeviceVO nexusVSM = null; + ClusterVSMMapVO vsmMapVO = null; vsmMapVO = _vsmMapDao.findByClusterId(clusterId); - long vsmId; + long vsmId = 0; if (vsmMapVO != null) { vsmId = vsmMapVO.getVsmId(); s_logger.info("vsmId is " + vsmId); @@ -1060,7 +1081,7 @@ public Map getNexusVSMCredentialsByClusterId(Long clusterId) { return null; } - Map nexusVSMCredentials = new HashMap<>(); + Map nexusVSMCredentials = new HashMap(); if (nexusVSM != null) { nexusVSMCredentials.put("vsmip", nexusVSM.getipaddr()); nexusVSMCredentials.put("vsmusername", nexusVSM.getUserName()); @@ -1087,7 +1108,7 @@ public int getVcenterSessionTimeout() { @Override public List> getCommands() { - List> cmdList = new ArrayList<>(); + List> cmdList = new ArrayList>(); cmdList.add(AddVmwareDcCmd.class); cmdList.add(UpdateVmwareDcCmd.class); cmdList.add(RemoveVmwareDcCmd.class); @@ -1103,7 +1124,7 @@ public List> getCommands() { @Override @DB public VmwareDatacenterVO addVmwareDatacenter(AddVmwareDcCmd cmd) throws ResourceInUseException { - VmwareDatacenterVO vmwareDc; + VmwareDatacenterVO vmwareDc = null; Long zoneId = cmd.getZoneId(); String userName = cmd.getUsername(); String password = cmd.getPassword(); @@ -1159,10 +1180,10 @@ public VmwareDatacenterVO addVmwareDatacenter(AddVmwareDcCmd cmd) throws Resourc checkIfDcIsUsed(vCenterHost, vmwareDcName, zoneId); VmwareContext context = null; - DatacenterMO dcMo; + DatacenterMO dcMo = null; String dcCustomFieldValue; boolean addDcCustomFieldDef = false; - boolean dcInUse; + boolean dcInUse = false; String guid; ManagedObjectReference dcMor; try { @@ -1195,7 +1216,7 @@ public VmwareDatacenterVO addVmwareDatacenter(AddVmwareDcCmd cmd) throws Resourc // Map zone with vmware datacenter vmwareDcZoneMap = new VmwareDatacenterZoneMapVO(zoneId, vmwareDc.getId()); - vmwareDatacenterZoneMapDao.persist(vmwareDcZoneMap); + vmwareDcZoneMap = vmwareDatacenterZoneMapDao.persist(vmwareDcZoneMap); // Set custom field for this DC if (addDcCustomFieldDef) { @@ -1215,6 +1236,7 @@ public VmwareDatacenterVO addVmwareDatacenter(AddVmwareDcCmd cmd) throws Resourc if (context != null) { context.close(); } + context = null; } importVsphereStoragePoliciesInternal(zoneId, vmwareDc.getId()); return vmwareDc; @@ -1239,9 +1261,9 @@ VmwareDatacenterVO createOrUpdateDc(String guid, String name, String host, Strin * Check if DC is already part of zone * In that case vmware_data_center table should have the DC and a dc zone mapping should exist * - * @param vCenterHost the vcenter appliance hostname - * @param vmwareDcName the name of the vmware DC - * @param zoneId zone that the DC should be connected to + * @param vCenterHost + * @param vmwareDcName + * @param zoneId * @throws ResourceInUseException if the DC can not be used. */ private void checkIfDcIsUsed(String vCenterHost, String vmwareDcName, Long zoneId) throws ResourceInUseException { @@ -1249,7 +1271,7 @@ private void checkIfDcIsUsed(String vCenterHost, String vmwareDcName, Long zoneI vmwareDc = vmwareDcDao.getVmwareDatacenterByGuid(vmwareDcName + "@" + vCenterHost); if (vmwareDc != null) { VmwareDatacenterZoneMapVO mapping = vmwareDatacenterZoneMapDao.findByVmwareDcId(vmwareDc.getId()); - if (mapping != null && zoneId == mapping.getZoneId()) { + if (mapping != null && Long.compare(zoneId, mapping.getZoneId()) == 0) { throw new ResourceInUseException(String.format("This DC (%s) is already part of other CloudStack zone (%d). Cannot add this DC to more zones.", vmwareDc.getUuid(), zoneId)); } } @@ -1258,7 +1280,7 @@ private void checkIfDcIsUsed(String vCenterHost, String vmwareDcName, Long zoneI @Override @ActionEvent(eventType = EventTypes.EVENT_ZONE_EDIT, eventDescription = "updating VMware datacenter") public VmwareDatacenter updateVmwareDatacenter(UpdateVmwareDcCmd cmd) { - final long zoneId = cmd.getZoneId(); + final Long zoneId = cmd.getZoneId(); final String userName = cmd.getUsername(); final String password = cmd.getPassword(); final String vCenterHost = cmd.getVcenter(); @@ -1286,7 +1308,7 @@ public VmwareDatacenter updateVmwareDatacenter(UpdateVmwareDcCmd cmd) { } vmwareDc.setGuid(String.format("%s@%s", vmwareDc.getVmwareDatacenterName(), vmwareDc.getVcenterHost())); - return Transaction.execute(new TransactionCallback<>() { + return Transaction.execute(new TransactionCallback() { @Override public VmwareDatacenter doInTransaction(TransactionStatus status) { if (vmwareDcDao.update(vmwareDc.getId(), vmwareDc)) { @@ -1335,7 +1357,7 @@ public boolean removeVmwareDatacenter(RemoveVmwareDcCmd cmd) throws ResourceInUs String vCenterHost; String userName; String password; - DatacenterMO dcMo; + DatacenterMO dcMo = null; final VmwareDatacenterZoneMapVO vmwareDcZoneMap = vmwareDatacenterZoneMapDao.findByZoneId(zoneId); // Check if zone is associated with VMware DC if (vmwareDcZoneMap == null) { @@ -1372,9 +1394,11 @@ public void doInTransactionWithoutResult(TransactionStatus status) { throw new DiscoveryException(msg); } + assert (dcMo != null); + // Reset custom field property cloud.zone over this DC dcMo.setCustomFieldValue(CustomFieldConstants.CLOUD_ZONE, "false"); - s_logger.info("Successfully reset custom field property cloud.zone over DC " + vmwareDcName); + s_logger.info("Sucessfully reset custom field property cloud.zone over DC " + vmwareDcName); } catch (Exception e) { String msg = "Unable to reset custom field property cloud.zone over DC " + vmwareDcName + " due to : " + VmwareHelper.getExceptionMessage(e); s_logger.error(msg); @@ -1383,6 +1407,7 @@ public void doInTransactionWithoutResult(TransactionStatus status) { if (context != null) { context.close(); } + context = null; } return true; } @@ -1403,7 +1428,7 @@ private void validateZone(Long zoneId) throws InvalidParameterValueException { private void validateZoneWithResources(Long zoneId, String errStr) throws ResourceInUseException { // Check if zone has resources? - For now look for clusters List clusters = clusterDao.listByZoneId(zoneId); - if (!CollectionUtils.isNullOrEmpty(clusters)) { + if (clusters != null && clusters.size() > 0) { // Look for VMware hypervisor. for (ClusterVO cluster : clusters) { if (cluster.getHypervisorType().equals(HypervisorType.VMware)) { @@ -1424,9 +1449,9 @@ public boolean isLegacyZone(long dcId) { } @Override - public List listVmwareDatacenters(ListVmwareDcsCmd cmd) throws CloudRuntimeException { + public List listVmwareDatacenters(ListVmwareDcsCmd cmd) throws CloudRuntimeException, InvalidParameterValueException { Long zoneId = cmd.getZoneId(); - List vmwareDcList = new ArrayList<>(); + List vmwareDcList = new ArrayList(); VmwareDatacenterZoneMapVO vmwareDcZoneMap; VmwareDatacenterVO vmwareDatacenter; long vmwareDcId; @@ -1484,7 +1509,7 @@ public List importVsphereStoragePoliciesInternal String vCenterHost = vmwareDatacenter.getVcenterHost(); String userName = vmwareDatacenter.getUser(); String password = vmwareDatacenter.getPassword(); - List storageProfiles; + List storageProfiles = null; try { s_logger.debug(String.format("Importing vSphere Storage Policies for the vmware DC %d in zone %d", vmwareDcId, zoneId)); VmwareContext context = VmwareContextFactory.getContext(vCenterHost, userName, password); @@ -1512,15 +1537,16 @@ public List importVsphereStoragePoliciesInternal List allStoragePolicies = vsphereStoragePolicyDao.listAll(); List finalStorageProfiles = storageProfiles; List needToMarkRemoved = allStoragePolicies.stream() - .filter(existingPolicy -> finalStorageProfiles.stream() - .noneMatch(storageProfile -> storageProfile.getProfileId().getUniqueId().equals(existingPolicy.getPolicyId()))) + .filter(existingPolicy -> !finalStorageProfiles.stream() + .anyMatch(storageProfile -> storageProfile.getProfileId().getUniqueId().equals(existingPolicy.getPolicyId()))) .collect(Collectors.toList()); for (VsphereStoragePolicyVO storagePolicy : needToMarkRemoved) { vsphereStoragePolicyDao.remove(storagePolicy.getId()); } - return vsphereStoragePolicyDao.listAll(); + List storagePolicies = vsphereStoragePolicyDao.listAll(); + return storagePolicies; } @Override @@ -1565,82 +1591,20 @@ public List listVsphereStoragePolicyCompatibleStoragePools(ListVsph return compatiblePools; } - @Override - public List listHostsInDatacenter(ListVmwareDcHostsCmd cmd) { - VcenterData vmwaredc = getVcenterData(cmd); - - try { - VmwareContext context = getVmwareContext(vmwaredc); - DatacenterMO dcMo = getDatacenterMO(context, vmwaredc); - return dcMo.getAllHostsOnDatacenter(); - } catch (RuntimeFaultFaultMsg | URISyntaxException | VmwareClientException | InvalidLocaleFaultMsg | - InvalidLoginFaultMsg | InvalidPropertyFaultMsg e) { - String errorMsg = String.format("Error retrieving stopped VMs from the VMware VC %s datacenter %s: %s", - vmwaredc.vcenter, vmwaredc.datacenterName, e.getMessage()); - s_logger.error(errorMsg, e); - throw new CloudRuntimeException(errorMsg); - } - - } - - @Override - public Pair> listVMsInDatacenter(ListVmwareDcVmsCmd cmd) { - Integer maxObjects = cmd.getBatchSize(); - String token = cmd.getToken(); - String host = cmd.getHost(); - - VcenterData vmwaredc = getVcenterData(cmd); - - try { - VmwareContext context = getVmwareContext(vmwaredc); - - DatacenterMO dcMo = getDatacenterMO(context, vmwaredc); - - if (com.cloud.utils.StringUtils.isNotBlank(host)) { - ManagedObjectReference hostMor = dcMo.findHost(host); - if (hostMor == null) { - throw new VmwareClientException(String.format("No host '%s' found on DC: %s.", host, dcMo.getName())); - } - HostMO hostMo = new HostMO(context, hostMor); - return hostMo.getVms(maxObjects, token); - } else { - return dcMo.getVms(maxObjects, token); - } - } catch (InvalidParameterValueException | VmwareClientException | InvalidLocaleFaultMsg | InvalidLoginFaultMsg | - RuntimeFaultFaultMsg | URISyntaxException | InvalidPropertyFaultMsg | InvocationTargetException | - NoSuchMethodException | IllegalAccessException e) { - String errorMsg = String.format("Error retrieving stopped VMs from the VMware VC %s datacenter %s: %s", - vmwaredc.vcenter, vmwaredc.datacenterName, e.getMessage()); - s_logger.error(errorMsg, e); - throw new CloudRuntimeException(errorMsg); - } - } + private static class VcenterData { + public final String vcenter; + public final String datacenterName; + public final String username; + public final String password; - @NotNull - private static DatacenterMO getDatacenterMO(VmwareContext context, VcenterData vmwaredc) throws InvalidPropertyFaultMsg, RuntimeFaultFaultMsg { - DatacenterMO dcMo = new DatacenterMO(context, vmwaredc.datacenterName); - ManagedObjectReference dcMor = dcMo.getMor(); - if (dcMor == null) { - String msg = String.format("Unable to find VMware datacenter %s in vCenter %s", - vmwaredc.datacenterName, vmwaredc.vcenter); - s_logger.error(msg); - throw new InvalidParameterValueException(msg); + public VcenterData(String vcenter, String datacenterName, String username, String password) { + this.vcenter = vcenter; + this.datacenterName = datacenterName; + this.username = username; + this.password = password; } - return dcMo; } - @NotNull - private static VmwareContext getVmwareContext(VcenterData vmwaredc) throws RuntimeFaultFaultMsg, URISyntaxException, VmwareClientException, InvalidLocaleFaultMsg, InvalidLoginFaultMsg { - s_logger.debug(String.format("Connecting to the VMware datacenter %s at vCenter %s to retrieve VMs", - vmwaredc.datacenterName, vmwaredc.vcenter)); - String serviceUrl = String.format("https://%s/sdk/vimService", vmwaredc.vcenter); - VmwareClient vimClient = new VmwareClient(vmwaredc.vcenter); - vimClient.connect(serviceUrl, vmwaredc.username, vmwaredc.password); - VmwareContext context = new VmwareContext(vimClient, vmwaredc.vcenter); - return context; - } - - @NotNull private VcenterData getVcenterData(ListVmwareDcItems cmd) { String vcenter = cmd.getVcenter(); String datacenterName = cmd.getDatacenterName(); @@ -1671,23 +1635,88 @@ private VcenterData getVcenterData(ListVmwareDcItems cmd) { return vmwaredc; } - private static class VcenterData { - public final String vcenter; - public final String datacenterName; - public final String username; - public final String password; + private static VmwareContext getVmwareContext(String vcenter, String username, String password) throws Exception { + s_logger.debug(String.format("Connecting to the VMware vCenter %s", vcenter)); + String serviceUrl = String.format("https://%s/sdk/vimService", vcenter); + VmwareClient vimClient = new VmwareClient(vcenter); + vimClient.connect(serviceUrl, username, password); + return new VmwareContext(vimClient, vcenter); + } - public VcenterData(String vcenter, String datacenterName, String username, String password) { - this.vcenter = vcenter; - this.datacenterName = datacenterName; - this.username = username; - this.password = password; + @Override + public List listVMsInDatacenter(ListVmwareDcVmsCmd cmd) { + VcenterData vmwareDC = getVcenterData(cmd); + String vcenter = vmwareDC.vcenter; + String username = vmwareDC.username; + String password = vmwareDC.password; + String datacenterName = vmwareDC.datacenterName; + String keyword = cmd.getKeyword(); + String esxiHostName = cmd.getHostName(); + + try { + VmwareContext context = getVmwareContext(vcenter, username, password); + DatacenterMO dcMo = getDatacenterMO(context, vcenter, datacenterName); + + List vms; + if (StringUtils.isNotBlank(esxiHostName)) { + // List VMs in a specific ESXi Host + ManagedObjectReference hostMor = dcMo.findHost(esxiHostName); + if (hostMor == null) { + String errorMsg = String.format("Cannot find a host with name %s on vcenter %s", esxiHostName, vcenter); + s_logger.error(errorMsg); + throw new CloudRuntimeException(errorMsg); + } + HostMO hostMO = new HostMO(context, hostMor); + vms = hostMO.listAllVmsInHost(); + } else { + // Long lasting method, not recommended - retrieves all the VMs in a datacenter + vms = dcMo.getAllVmsOnDatacenter(); + } + + List instances = VmwareHelper.getUnmanagedInstancesList(vms); + return StringUtils.isBlank(keyword) ? instances : + instances.stream().filter(x -> x.getName().toLowerCase().contains(keyword.toLowerCase())).collect(Collectors.toList()); + } catch (Exception e) { + String errorMsg = String.format("Error retrieving VMs from the VMware VC %s datacenter %s: %s", + vcenter, datacenterName, e.getMessage()); + s_logger.error(errorMsg, e); + throw new CloudRuntimeException(errorMsg); + } + } + + private static DatacenterMO getDatacenterMO(VmwareContext context, String vcenter, String datacenterName) throws Exception { + DatacenterMO dcMo = new DatacenterMO(context, datacenterName); + ManagedObjectReference dcMor = dcMo.getMor(); + if (dcMor == null) { + String msg = String.format("Unable to find VMware datacenter %s in vCenter %s", datacenterName, vcenter); + s_logger.error(msg); + throw new InvalidParameterValueException(msg); + } + return dcMo; + } + + @Override + public List listHostsInDatacenter(ListVmwareDcHostsCmd cmd) { + VcenterData vmwareDC = getVcenterData(cmd); + String vcenter = vmwareDC.vcenter; + String username = vmwareDC.username; + String password = vmwareDC.password; + String datacenterName = vmwareDC.datacenterName; + try { + VmwareContext context = getVmwareContext(vcenter, username, password); + DatacenterMO dcMo = getDatacenterMO(context, vcenter, datacenterName); + return dcMo.getAllHostsOnDatacenter(); + } catch (Exception e) { + String errorMsg = String.format("Error retrieving stopped VMs from the VMware VC %s datacenter %s: %s", + vcenter, datacenterName, e.getMessage()); + s_logger.error(errorMsg, e); + throw new CloudRuntimeException(errorMsg); } } @Override public boolean hasNexusVSM(Long clusterId) { - ClusterVSMMapVO vsmMapVo; + ClusterVSMMapVO vsmMapVo = null; vsmMapVo = _vsmMapDao.findByClusterId(clusterId); if (vsmMapVo == null) { @@ -1737,7 +1766,7 @@ private void startTemplateCleanJobSchedule() { } /** - * This task is to clean-up templates from primary storage that are otherwise not cleaned by the {@see com.cloud.storage.StorageManagerImpl.StorageGarbageCollector}. + * This task is to cleanup templates from primary storage that are otherwise not cleaned by the {@link com.cloud.storage.StorageManagerImpl.StorageGarbageCollector}. * it is called at regular intervals when storage.template.cleanup.enabled == true * It collect all templates that * - are deleted from cloudstack diff --git a/plugins/hypervisors/vmware/src/main/java/org/apache/cloudstack/api/command/admin/zone/AddVmwareDcCmd.java b/plugins/hypervisors/vmware/src/main/java/org/apache/cloudstack/api/command/admin/zone/AddVmwareDcCmd.java index 5da2c7b70033..9f4985a1363b 100644 --- a/plugins/hypervisors/vmware/src/main/java/org/apache/cloudstack/api/command/admin/zone/AddVmwareDcCmd.java +++ b/plugins/hypervisors/vmware/src/main/java/org/apache/cloudstack/api/command/admin/zone/AddVmwareDcCmd.java @@ -37,8 +37,8 @@ import com.cloud.user.Account; import com.cloud.utils.exception.CloudRuntimeException; -@APICommand(name = "addVmwareDc", description = "Adds a Vmware datacenter to specified zone", - responseObject = VmwareDatacenterResponse.class, responseHasSensitiveInfo = false) +@APICommand(name = "addVmwareDc", description = "Adds a VMware datacenter to specified zone", responseObject = VmwareDatacenterResponse.class, + requestHasSensitiveInfo = true, responseHasSensitiveInfo = false) public class AddVmwareDcCmd extends BaseCmd { @Inject @@ -47,7 +47,7 @@ public class AddVmwareDcCmd extends BaseCmd { public static final Logger s_logger = Logger.getLogger(AddVmwareDcCmd.class.getName()); - @Parameter(name = ApiConstants.NAME, type = CommandType.STRING, required = true, description = "Name of Vmware datacenter to be added to specified zone.") + @Parameter(name = ApiConstants.NAME, type = CommandType.STRING, required = true, description = "Name of VMware datacenter to be added to specified zone.") private String name; @Parameter(name = ApiConstants.VCENTER, @@ -56,10 +56,10 @@ public class AddVmwareDcCmd extends BaseCmd { description = "The name/ip of vCenter. Make sure it is IP address or full qualified domain name for host running vCenter server.") private String vCenter; - @Parameter(name = ApiConstants.USERNAME, type = CommandType.STRING, description = "The Username required to connect to resource.") + @Parameter(name = ApiConstants.USERNAME, type = CommandType.STRING, required = false, description = "The Username required to connect to resource.") private String username; - @Parameter(name = ApiConstants.PASSWORD, type = CommandType.STRING, description = "The password for specified username.") + @Parameter(name = ApiConstants.PASSWORD, type = CommandType.STRING, required = false, description = "The password for specified username.") private String password; @Parameter(name = ApiConstants.ZONE_ID, type = CommandType.UUID, entityType = ZoneResponse.class, required = true, description = "The Zone ID.") @@ -101,7 +101,7 @@ public void execute() { response.setResponseName(getCommandName()); response.setObjectName("vmwaredc"); } else { - throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to add Vmware Datacenter to zone."); + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to add VMware Datacenter to zone."); } this.setResponseObject(response); } catch (DiscoveryException ex) { diff --git a/plugins/hypervisors/vmware/src/main/java/org/apache/cloudstack/api/command/admin/zone/ImportVsphereStoragePoliciesCmd.java b/plugins/hypervisors/vmware/src/main/java/org/apache/cloudstack/api/command/admin/zone/ImportVsphereStoragePoliciesCmd.java index 40b479f809cc..c7ba63c02a77 100644 --- a/plugins/hypervisors/vmware/src/main/java/org/apache/cloudstack/api/command/admin/zone/ImportVsphereStoragePoliciesCmd.java +++ b/plugins/hypervisors/vmware/src/main/java/org/apache/cloudstack/api/command/admin/zone/ImportVsphereStoragePoliciesCmd.java @@ -37,6 +37,7 @@ import org.apache.cloudstack.api.response.ListResponse; import org.apache.cloudstack.api.response.ZoneResponse; import org.apache.cloudstack.context.CallContext; +import org.apache.log4j.Logger; import javax.inject.Inject; import java.util.ArrayList; @@ -48,6 +49,9 @@ authorized = {RoleType.Admin}) public class ImportVsphereStoragePoliciesCmd extends BaseCmd { + public static final Logger LOGGER = Logger.getLogger(ImportVsphereStoragePoliciesCmd.class.getName()); + + @Inject public VmwareDatacenterService _vmwareDatacenterService; @@ -72,13 +76,6 @@ public void execute() throws ResourceUnavailableException, InsufficientCapacityE List storagePolicies = _vmwareDatacenterService.importVsphereStoragePolicies(this); final ListResponse responseList = new ListResponse<>(); - final List storagePoliciesResponseList = getVsphereStoragePoliciesResponses(storagePolicies, dataCenter); - responseList.setResponses(storagePoliciesResponseList); - responseList.setResponseName(getCommandName()); - setResponseObject(responseList); - } - - private static List getVsphereStoragePoliciesResponses(List storagePolicies, DataCenter dataCenter) { final List storagePoliciesResponseList = new ArrayList<>(); for (VsphereStoragePolicy storagePolicy : storagePolicies) { final VsphereStoragePoliciesResponse storagePoliciesResponse = new VsphereStoragePoliciesResponse(); @@ -91,7 +88,9 @@ private static List getVsphereStoragePoliciesRes storagePoliciesResponseList.add(storagePoliciesResponse); } - return storagePoliciesResponseList; + responseList.setResponses(storagePoliciesResponseList); + responseList.setResponseName(getCommandName()); + setResponseObject(responseList); } @Override diff --git a/plugins/hypervisors/vmware/src/main/java/org/apache/cloudstack/api/command/admin/zone/ListVmwareDcHostsCmd.java b/plugins/hypervisors/vmware/src/main/java/org/apache/cloudstack/api/command/admin/zone/ListVmwareDcHostsCmd.java index 6f193c9c1b27..c07fd96d7a02 100644 --- a/plugins/hypervisors/vmware/src/main/java/org/apache/cloudstack/api/command/admin/zone/ListVmwareDcHostsCmd.java +++ b/plugins/hypervisors/vmware/src/main/java/org/apache/cloudstack/api/command/admin/zone/ListVmwareDcHostsCmd.java @@ -25,32 +25,27 @@ import com.cloud.hypervisor.vmware.VmwareDatacenterService; import com.cloud.hypervisor.vmware.mo.HostMO; import com.cloud.user.Account; -import com.cloud.utils.exception.CloudRuntimeException; - -import com.vmware.vim25.InvalidPropertyFaultMsg; -import com.vmware.vim25.RuntimeFaultFaultMsg; import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.ApiErrorCode; -import org.apache.cloudstack.api.BaseCmd; -import org.apache.cloudstack.api.BaseResponse; +import org.apache.cloudstack.api.BaseListCmd; import org.apache.cloudstack.api.Parameter; import org.apache.cloudstack.api.ServerApiException; import org.apache.cloudstack.api.response.HostResponse; +import org.apache.cloudstack.api.response.ListResponse; import org.apache.cloudstack.api.response.VmwareDatacenterResponse; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.StringUtils; import javax.inject.Inject; -import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.List; -@APICommand(name = "listVmwareDcHosts", responseObject = VmwareRequestResponse.class, - description = "Lists the VMs in a Vmware Datacenter", +@APICommand(name = "listVmwareDcHosts", responseObject = HostResponse.class, + description = "Lists the Hosts in a Vmware Datacenter", requestHasSensitiveInfo = false, responseHasSensitiveInfo = false) -public class ListVmwareDcHostsCmd extends BaseCmd implements ListVmwareDcItems { +public class ListVmwareDcHostsCmd extends BaseListCmd implements ListVmwareDcItems { @Inject public VmwareDatacenterService _vmwareDatacenterService; @@ -100,25 +95,24 @@ public void execute() throws ResourceUnavailableException, InsufficientCapacityE checkParameters(); try { List hosts = _vmwareDatacenterService.listHostsInDatacenter(this); - List baseResponseList = new ArrayList<>(); + ListResponse response = new ListResponse<>(); + List baseResponseList = new ArrayList<>(); if (CollectionUtils.isNotEmpty(hosts)) { for (HostMO vmwareHost : hosts) { HostResponse resp = createHostResponse(vmwareHost); baseResponseList.add(resp); } } - VmwareRequestResponse response = new VmwareRequestResponse<>(); response.setResponses(baseResponseList, baseResponseList.size()); response.setResponseName(getCommandName()); setResponseObject(response); - } catch (CloudRuntimeException | InvalidPropertyFaultMsg | RuntimeFaultFaultMsg | InvocationTargetException | - NoSuchMethodException | IllegalAccessException e) { + } catch (Exception e) { String errorMsg = String.format("Error retrieving VMs from Vmware VC: %s", e.getMessage()); throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, errorMsg); } } - private HostResponse createHostResponse(HostMO hostInstance) throws InvalidPropertyFaultMsg, RuntimeFaultFaultMsg, InvocationTargetException, NoSuchMethodException, IllegalAccessException { + private HostResponse createHostResponse(HostMO hostInstance) throws Exception { HostResponse response = new HostResponse(); response.setHypervisor(Hypervisor.HypervisorType.VMware.toString()); response.setName(hostInstance.getHostName()); diff --git a/plugins/hypervisors/vmware/src/main/java/org/apache/cloudstack/api/command/admin/zone/ListVmwareDcVmsCmd.java b/plugins/hypervisors/vmware/src/main/java/org/apache/cloudstack/api/command/admin/zone/ListVmwareDcVmsCmd.java index 544e756fe807..ea4bbb3994fa 100644 --- a/plugins/hypervisors/vmware/src/main/java/org/apache/cloudstack/api/command/admin/zone/ListVmwareDcVmsCmd.java +++ b/plugins/hypervisors/vmware/src/main/java/org/apache/cloudstack/api/command/admin/zone/ListVmwareDcVmsCmd.java @@ -23,15 +23,15 @@ import com.cloud.exception.ResourceUnavailableException; import com.cloud.hypervisor.vmware.VmwareDatacenterService; import com.cloud.user.Account; -import com.cloud.utils.Pair; import com.cloud.utils.exception.CloudRuntimeException; import org.apache.cloudstack.api.APICommand; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.ApiErrorCode; -import org.apache.cloudstack.api.BaseCmd; +import org.apache.cloudstack.api.BaseListCmd; import org.apache.cloudstack.api.BaseResponse; import org.apache.cloudstack.api.Parameter; import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.response.ListResponse; import org.apache.cloudstack.api.response.UnmanagedInstanceResponse; import org.apache.cloudstack.api.response.VmwareDatacenterResponse; import org.apache.cloudstack.vm.UnmanagedInstanceTO; @@ -42,10 +42,10 @@ import java.util.ArrayList; import java.util.List; -@APICommand(name = "listVmwareDcVms", responseObject = VmwareRequestResponse.class, - description = "Lists the VMs in a Vmware Datacenter", +@APICommand(name = "listVmwareDcVms", responseObject = UnmanagedInstanceResponse.class, + description = "Lists the VMs in a VMware Datacenter", requestHasSensitiveInfo = false, responseHasSensitiveInfo = false) -public class ListVmwareDcVmsCmd extends BaseCmd implements ListVmwareDcItems { +public class ListVmwareDcVmsCmd extends BaseListCmd implements ListVmwareDcItems { @Inject public VmwareDatacenterService _vmwareDatacenterService; @@ -61,27 +61,18 @@ public class ListVmwareDcVmsCmd extends BaseCmd implements ListVmwareDcItems { description = "The name/ip of vCenter. Make sure it is IP address or full qualified domain name for host running vCenter server.") private String vcenter; - @Parameter(name = ApiConstants.DATACENTER_NAME, type = CommandType.STRING, description = "Name of Vmware datacenter.") + @Parameter(name = ApiConstants.DATACENTER_NAME, type = CommandType.STRING, description = "Name of VMware datacenter.") private String datacenterName; + @Parameter(name = ApiConstants.HOST_NAME, type = CommandType.STRING, description = "Get only the VMs from the specified host.") + private String hostName; + @Parameter(name = ApiConstants.USERNAME, type = CommandType.STRING, description = "The Username required to connect to resource.") private String username; @Parameter(name = ApiConstants.PASSWORD, type = CommandType.STRING, description = "The password for specified username.") private String password; - @Parameter(name = ApiConstants.HOST, type = CommandType.STRING, description = "get only the VMs from the specified host.") - private String host; - - @Parameter(name = ApiConstants.BATCH_SIZE, type = CommandType.INTEGER, description = "The maximum number of results to return.") - private Integer batchSize; - - @Parameter(name = ApiConstants.TOKEN, type = CommandType.STRING, - description = "For listVmwareDcVms, if the maximum number of results (the `batchsize`) is exceeded, " + - " a token is returned. This token can be used in subsequent calls to retrieve more results." + - " As long as a token is returned, more results can be retrieved.") - private String token; - public String getVcenter() { return vcenter; } @@ -94,22 +85,14 @@ public String getPassword() { return password; } - public Integer getBatchSize() { - return batchSize; - } - - public String getHost() { - return host; - } - - public String getToken() { - return token; - } - public String getDatacenterName() { return datacenterName; } + public String getHostName() { + return hostName; + } + public Long getExistingVcenterId() { return existingVcenterId; } @@ -118,8 +101,7 @@ public Long getExistingVcenterId() { public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException, NetworkRuleConflictException { checkParameters(); try { - Pair> results = _vmwareDatacenterService.listVMsInDatacenter(this); - List vms = results.second(); + List vms = _vmwareDatacenterService.listVMsInDatacenter(this); List baseResponseList = new ArrayList<>(); if (CollectionUtils.isNotEmpty(vms)) { for (UnmanagedInstanceTO vmwareVm : vms) { @@ -127,13 +109,16 @@ public void execute() throws ResourceUnavailableException, InsufficientCapacityE baseResponseList.add(resp); } } - VmwareRequestResponse response = new VmwareRequestResponse<>(); - response.setResponses(baseResponseList, baseResponseList.size()); + List pagingList = com.cloud.utils.StringUtils.applyPagination(baseResponseList, this.getStartIndex(), this.getPageSizeVal()); + if (CollectionUtils.isEmpty(pagingList)) { + pagingList = baseResponseList; + } + ListResponse response = new ListResponse<>(); + response.setResponses(pagingList, baseResponseList.size()); response.setResponseName(getCommandName()); - response.setToken(results.first()); setResponseObject(response); } catch (CloudRuntimeException e) { - String errorMsg = String.format("Error retrieving VMs from Vmware VC: %s", e.getMessage()); + String errorMsg = String.format("Error retrieving VMs from VMware VC: %s", e.getMessage()); throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, errorMsg); } } @@ -156,6 +141,6 @@ public long getEntityOwnerId() { @Override public String getCommandName() { - return "listVmwareDcVmsResponse".toLowerCase(); + return "listvmwaredcvmsresponse"; } } diff --git a/plugins/hypervisors/vmware/src/main/java/org/apache/cloudstack/api/command/admin/zone/ListVmwareDcsCmd.java b/plugins/hypervisors/vmware/src/main/java/org/apache/cloudstack/api/command/admin/zone/ListVmwareDcsCmd.java index 9f7c4cf2944e..61b5210bb3a5 100644 --- a/plugins/hypervisors/vmware/src/main/java/org/apache/cloudstack/api/command/admin/zone/ListVmwareDcsCmd.java +++ b/plugins/hypervisors/vmware/src/main/java/org/apache/cloudstack/api/command/admin/zone/ListVmwareDcsCmd.java @@ -43,7 +43,7 @@ import com.cloud.hypervisor.vmware.VmwareDatacenterService; import com.cloud.user.Account; -@APICommand(name = "listVmwareDcs", responseObject = VmwareDatacenterResponse.class, description = "Retrieves Vmware DC(s) associated with a zone.", +@APICommand(name = "listVmwareDcs", responseObject = VmwareDatacenterResponse.class, description = "Retrieves VMware DC(s) associated with a zone.", requestHasSensitiveInfo = false, responseHasSensitiveInfo = false) public class ListVmwareDcsCmd extends BaseListCmd { @@ -52,6 +52,7 @@ public class ListVmwareDcsCmd extends BaseListCmd { public static final Logger s_logger = Logger.getLogger(ListVmwareDcsCmd.class.getName()); + ///////////////////////////////////////////////////// //////////////// API parameters ///////////////////// ///////////////////////////////////////////////////// @@ -74,27 +75,20 @@ public Long getZoneId() { @Override public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException { - List vmwareDcList; + List vmwareDcList = null; try { vmwareDcList = _vmwareDatacenterService.listVmwareDatacenters(this); } catch (InvalidParameterValueException ie) { throw new InvalidParameterValueException("Invalid zone id " + getZoneId()); } catch (Exception e) { - throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to find associated Vmware DCs associated with zone " + getZoneId()); + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to find associated VMware DCs associated with zone " + getZoneId()); } - ListResponse response = new ListResponse<>(); - List vmwareDcResponses = getVmwareDatacenterResponses(vmwareDcList); - response.setResponses(vmwareDcResponses); - response.setResponseName(getCommandName()); - setResponseObject(response); - } + ListResponse response = new ListResponse(); + List vmwareDcResponses = new ArrayList(); - private List getVmwareDatacenterResponses(List vmwareDcList) { - List vmwareDcResponses = new ArrayList<>(); - - if (vmwareDcList != null && !vmwareDcList.isEmpty()) { + if (vmwareDcList != null && vmwareDcList.size() > 0) { for (VmwareDatacenter vmwareDc : vmwareDcList) { VmwareDatacenterResponse vmwareDcResponse = new VmwareDatacenterResponse(); @@ -102,12 +96,14 @@ private List getVmwareDatacenterResponses(List storagePolicies = _vmwareDatacenterService.listVsphereStoragePolicies(this); final ListResponse responseList = new ListResponse<>(); - final List storagePoliciesResponseList = getVsphereStoragePoliciesResponses(storagePolicies, dataCenter); - responseList.setResponses(storagePoliciesResponseList); - responseList.setResponseName(getCommandName()); - setResponseObject(responseList); - } - - private static List getVsphereStoragePoliciesResponses(List storagePolicies, DataCenter dataCenter) { final List storagePoliciesResponseList = new ArrayList<>(); for (VsphereStoragePolicy storagePolicy : storagePolicies) { final VsphereStoragePoliciesResponse storagePoliciesResponse = new VsphereStoragePoliciesResponse(); @@ -86,11 +83,13 @@ private static List getVsphereStoragePoliciesRes storagePoliciesResponse.setName(storagePolicy.getName()); storagePoliciesResponse.setPolicyId(storagePolicy.getPolicyId()); storagePoliciesResponse.setDescription(storagePolicy.getDescription()); - storagePoliciesResponse.setObjectName(ApiConstants.STORAGE_POLICY); + storagePoliciesResponse.setObjectName("StoragePolicy"); storagePoliciesResponseList.add(storagePoliciesResponse); } - return storagePoliciesResponseList; + responseList.setResponses(storagePoliciesResponseList); + responseList.setResponseName(getCommandName()); + setResponseObject(responseList); } @Override diff --git a/plugins/hypervisors/vmware/src/main/java/org/apache/cloudstack/api/command/admin/zone/ListVsphereStoragePolicyCompatiblePoolsCmd.java b/plugins/hypervisors/vmware/src/main/java/org/apache/cloudstack/api/command/admin/zone/ListVsphereStoragePolicyCompatiblePoolsCmd.java index ab697fbad67f..d66972ded2e7 100644 --- a/plugins/hypervisors/vmware/src/main/java/org/apache/cloudstack/api/command/admin/zone/ListVsphereStoragePolicyCompatiblePoolsCmd.java +++ b/plugins/hypervisors/vmware/src/main/java/org/apache/cloudstack/api/command/admin/zone/ListVsphereStoragePolicyCompatiblePoolsCmd.java @@ -68,7 +68,7 @@ public void execute() throws ServerApiException, ConcurrentOperationException { List poolResponses = new ArrayList<>(); for (StoragePool pool : pools) { StoragePoolResponse poolResponse = _responseGenerator.createStoragePoolForMigrationResponse(pool); - poolResponse.setObjectName(ApiConstants.STORAGE_POOL); + poolResponse.setObjectName("storagepool"); poolResponses.add(poolResponse); } response.setResponses(poolResponses); diff --git a/plugins/hypervisors/vmware/src/main/java/org/apache/cloudstack/api/command/admin/zone/RemoveVmwareDcCmd.java b/plugins/hypervisors/vmware/src/main/java/org/apache/cloudstack/api/command/admin/zone/RemoveVmwareDcCmd.java index d15369d2983a..735d00d6ca99 100644 --- a/plugins/hypervisors/vmware/src/main/java/org/apache/cloudstack/api/command/admin/zone/RemoveVmwareDcCmd.java +++ b/plugins/hypervisors/vmware/src/main/java/org/apache/cloudstack/api/command/admin/zone/RemoveVmwareDcCmd.java @@ -35,7 +35,7 @@ import com.cloud.user.Account; import com.cloud.utils.exception.CloudRuntimeException; -@APICommand(name = "removeVmwareDc", responseObject = SuccessResponse.class, description = "Remove a Vmware datacenter from a zone.", +@APICommand(name = "removeVmwareDc", responseObject = SuccessResponse.class, description = "Remove a VMware datacenter from a zone.", requestHasSensitiveInfo = false, responseHasSensitiveInfo = false) public class RemoveVmwareDcCmd extends BaseCmd { @@ -49,7 +49,7 @@ public class RemoveVmwareDcCmd extends BaseCmd { type = CommandType.UUID, entityType = ZoneResponse.class, required = true, - description = "The id of Zone from which Vmware datacenter has to be removed.") + description = "The id of Zone from which VMware datacenter has to be removed.") private Long zoneId; public Long getZoneId() { @@ -65,10 +65,10 @@ public void execute() { response.setResponseName(getCommandName()); setResponseObject(response); } else { - throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to remove Vmware datacenter from zone"); + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to remove VMware datacenter from zone"); } } catch (ResourceInUseException ex) { - s_logger.warn("The zone has one or more resources (like cluster), hence not able to remove Vmware datacenter from zone." + s_logger.warn("The zone has one or more resources (like cluster), hence not able to remove VMware datacenter from zone." + " Please remove all resource from zone, and retry. Exception: ", ex); ServerApiException e = new ServerApiException(ApiErrorCode.INTERNAL_ERROR, ex.getMessage()); for (String proxyObj : ex.getIdProxyList()) { diff --git a/plugins/hypervisors/vmware/src/main/java/org/apache/cloudstack/api/command/admin/zone/UpdateVmwareDcCmd.java b/plugins/hypervisors/vmware/src/main/java/org/apache/cloudstack/api/command/admin/zone/UpdateVmwareDcCmd.java index 5e02d5a96c20..2b6cf5984c51 100644 --- a/plugins/hypervisors/vmware/src/main/java/org/apache/cloudstack/api/command/admin/zone/UpdateVmwareDcCmd.java +++ b/plugins/hypervisors/vmware/src/main/java/org/apache/cloudstack/api/command/admin/zone/UpdateVmwareDcCmd.java @@ -28,15 +28,18 @@ import org.apache.cloudstack.api.ServerApiException; import org.apache.cloudstack.api.response.VmwareDatacenterResponse; import org.apache.cloudstack.api.response.ZoneResponse; +import org.apache.log4j.Logger; import com.cloud.dc.VmwareDatacenter; import com.cloud.hypervisor.vmware.VmwareDatacenterService; import com.cloud.user.Account; -@APICommand(name = "updateVmwareDc", description = "Updates a Vmware datacenter details for a zone", +@APICommand(name = "updateVmwareDc", description = "Updates a VMware datacenter details for a zone", responseObject = VmwareDatacenterResponse.class, responseHasSensitiveInfo = false, since = "4.12.0", authorized = {RoleType.Admin}) public class UpdateVmwareDcCmd extends BaseCmd { + public static final Logger LOG = Logger.getLogger(UpdateVmwareDcCmd.class); + @Inject public VmwareDatacenterService vmwareDatacenterService; @@ -50,7 +53,7 @@ public class UpdateVmwareDcCmd extends BaseCmd { private Long zoneId; @Parameter(name = ApiConstants.NAME, type = CommandType.STRING, - description = "Vmware datacenter name.") + description = "VMware datacenter name.") private String name; @Parameter(name = ApiConstants.VCENTER, type = CommandType.STRING, @@ -105,13 +108,13 @@ public Boolean isRecursive() { public void execute() { final VmwareDatacenter vmwareDatacenter = vmwareDatacenterService.updateVmwareDatacenter(this); if (vmwareDatacenter == null) { - throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to update Vmware datacenter"); + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to update VMware datacenter"); } final VmwareDatacenterResponse response = new VmwareDatacenterResponse(); response.setId(vmwareDatacenter.getUuid()); response.setName(vmwareDatacenter.getVmwareDatacenterName()); response.setResponseName(getCommandName()); - response.setObjectName(ApiConstants.VMWARE_DC); + response.setObjectName("vmwaredc"); setResponseObject(response); } diff --git a/plugins/hypervisors/vmware/src/main/java/org/apache/cloudstack/api/command/admin/zone/VmwareRequestResponse.java b/plugins/hypervisors/vmware/src/main/java/org/apache/cloudstack/api/command/admin/zone/VmwareRequestResponse.java deleted file mode 100644 index 81c58ef27baf..000000000000 --- a/plugins/hypervisors/vmware/src/main/java/org/apache/cloudstack/api/command/admin/zone/VmwareRequestResponse.java +++ /dev/null @@ -1,38 +0,0 @@ -// Licensed to the Apache Software Foundation (ASF) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The ASF licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. - -package org.apache.cloudstack.api.command.admin.zone; - -import com.cloud.serializer.Param; -import com.google.gson.annotations.SerializedName; -import org.apache.cloudstack.api.ApiConstants; -import org.apache.cloudstack.api.ResponseObject; -import org.apache.cloudstack.api.response.ListResponse; - -public class VmwareRequestResponse extends ListResponse { - @SerializedName(ApiConstants.TOKEN) - @Param(description = "The Vmware API token to use for retrieving further responses with") - private String token; - - public String getToken() { - return token; - } - - public void setToken(String token) { - this.token = token; - } -} diff --git a/plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/resource/CitrixResourceBase.java b/plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/resource/CitrixResourceBase.java index f53a70de7228..322f69c95319 100644 --- a/plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/resource/CitrixResourceBase.java +++ b/plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/resource/CitrixResourceBase.java @@ -51,10 +51,6 @@ import javax.naming.ConfigurationException; import javax.xml.parsers.ParserConfigurationException; -import com.trilead.ssh2.SFTPException; -import com.trilead.ssh2.SFTPv3Client; -import com.trilead.ssh2.SFTPv3DirectoryEntry; -import com.trilead.ssh2.SFTPv3FileAttributes; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.diagnostics.CopyToSecondaryStorageAnswer; import org.apache.cloudstack.diagnostics.CopyToSecondaryStorageCommand; @@ -72,6 +68,7 @@ import org.apache.commons.lang3.BooleanUtils; import org.apache.commons.lang3.StringUtils; import org.apache.log4j.Logger; +import org.apache.maven.artifact.versioning.ComparableVersion; import org.apache.xmlrpc.XmlRpcException; import org.joda.time.Duration; import org.w3c.dom.Document; @@ -153,6 +150,10 @@ import com.cloud.vm.VirtualMachine.PowerState; import com.cloud.vm.VmDetailConstants; import com.trilead.ssh2.SCPClient; +import com.trilead.ssh2.SFTPException; +import com.trilead.ssh2.SFTPv3Client; +import com.trilead.ssh2.SFTPv3DirectoryEntry; +import com.trilead.ssh2.SFTPv3FileAttributes; import com.xensource.xenapi.Bond; import com.xensource.xenapi.Connection; import com.xensource.xenapi.Console; @@ -627,7 +628,7 @@ public boolean cleanupHaltedVms(final Connection conn) throws XenAPIException, X if (VmPowerState.HALTED.equals(vmRec.powerState) && vmRec.affinity.equals(host) && !isAlienVm(vm, conn)) { try { - vm.destroy(conn); + destroyVm(vm, conn); } catch (final Exception e) { s_logger.warn("Catch Exception " + e.getClass().getName() + ": unable to destroy VM " + vmRec.nameLabel + " due to ", e); success = false; @@ -1452,7 +1453,7 @@ public VM createVmFromTemplate(final Connection conn, final VirtualMachineTO vmS vm.setPVBootloader(conn, "pygrub"); vm.setPVBootloaderArgs(conn, CitrixHelper.getPVbootloaderArgs(guestOsTypeName)); } else { - vm.destroy(conn); + destroyVm(vm, conn, true); throw new CloudRuntimeException("Unable to handle boot loader type: " + vmSpec.getBootloader()); } } @@ -2038,7 +2039,7 @@ void forceShutdownVM(final Connection conn, final VM vm) { final Long domId = vm.getDomid(conn); callHostPlugin(conn, "vmopspremium", "forceShutdownVM", "domId", domId.toString()); vm.powerStateReset(conn); - vm.destroy(conn); + destroyVm(vm, conn); } catch (final Exception e) { final String msg = "forceShutdown failed due to " + e.toString(); s_logger.warn(msg, e); @@ -3690,7 +3691,7 @@ public String handleVmStartFailure(final Connection conn, final String vmName, f } if (vm.getPowerState(conn) == VmPowerState.HALTED) { try { - vm.destroy(conn); + destroyVm(vm, conn, true); } catch (final Exception e) { s_logger.warn("VM destroy failed due to ", e); } @@ -5208,7 +5209,7 @@ protected void startvmfailhandle(final Connection conn, final VM vm, final List< } if (vm.getPowerState(conn) == VmPowerState.HALTED) { try { - vm.destroy(conn); + destroyVm(vm, conn, true); } catch (final Exception e) { final String msg = "VM destroy failed due to " + e.toString(); s_logger.warn(msg, e); @@ -5875,4 +5876,23 @@ private void umountNfs(Connection conn, String remoteDir, String localDir) { s_logger.warn(errMsg); } } + + public boolean isDestroyHaltedVms() { + ComparableVersion version = new ComparableVersion(getHost().getProductVersion()); + if (version.compareTo(new ComparableVersion("8.0")) >= 0) { + return false; + } + return true; + } + + public void destroyVm(VM vm, Connection connection, boolean forced) throws XenAPIException, XmlRpcException { + if (!isDestroyHaltedVms() && !forced) { + return; + } + vm.destroy(connection); + } + + public void destroyVm(VM vm, Connection connection) throws XenAPIException, XmlRpcException { + destroyVm(vm, connection, false); + } } diff --git a/plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/resource/wrapper/xen56/XenServer56FenceCommandWrapper.java b/plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/resource/wrapper/xen56/XenServer56FenceCommandWrapper.java index 3cebbd9a342e..713807ffaeea 100644 --- a/plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/resource/wrapper/xen56/XenServer56FenceCommandWrapper.java +++ b/plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/resource/wrapper/xen56/XenServer56FenceCommandWrapper.java @@ -56,7 +56,7 @@ public Answer execute(final FenceCommand command, final XenServer56Resource xenS for (final VM vm : vms) { s_logger.info("Fence command for VM " + command.getVmName()); vm.powerStateReset(conn); - vm.destroy(conn); + xenServer56.destroyVm(vm, conn); } return new FenceAnswer(command); } catch (final XmlRpcException e) { diff --git a/plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/resource/wrapper/xen56p1/XenServer56FP1FenceCommandWrapper.java b/plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/resource/wrapper/xen56p1/XenServer56FP1FenceCommandWrapper.java index bc7a4434bd06..dda87101de77 100644 --- a/plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/resource/wrapper/xen56p1/XenServer56FP1FenceCommandWrapper.java +++ b/plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/resource/wrapper/xen56p1/XenServer56FP1FenceCommandWrapper.java @@ -68,7 +68,7 @@ public Answer execute(final FenceCommand command, final XenServer56Resource xenS } s_logger.info("Fence command for VM " + command.getVmName()); vm.powerStateReset(conn); - vm.destroy(conn); + xenServer56.destroyVm(vm, conn); for (final VDI vdi : vdis) { final Map smConfig = vdi.getSmConfig(conn); for (final String key : smConfig.keySet()) { diff --git a/plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/CitrixCreateVMSnapshotCommandWrapper.java b/plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/CitrixCreateVMSnapshotCommandWrapper.java index 68c295717c3e..47c08b0cebe4 100644 --- a/plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/CitrixCreateVMSnapshotCommandWrapper.java +++ b/plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/CitrixCreateVMSnapshotCommandWrapper.java @@ -100,6 +100,7 @@ public Answer execute(final CreateVMSnapshotCommand command, final CitrixResourc vm = citrixResourceBase.getVM(conn, vmName); vmState = vm.getPowerState(conn); } catch (final Exception e) { + s_logger.debug(String.format("Failed to find VM with name: %s due to:", vmName), e); if (!snapshotMemory) { vm = citrixResourceBase.createWorkingVM(conn, vmName, guestOSType, platformEmulator, listVolumeTo); } @@ -178,13 +179,11 @@ public Answer execute(final CreateVMSnapshotCommand command, final CitrixResourc vdi.destroy(conn); } } - vmSnapshot.destroy(conn); + citrixResourceBase.destroyVm(vmSnapshot, conn, true); } } - if (vmState == VmPowerState.HALTED) { - if (vm != null) { - vm.destroy(conn); - } + if (vmState == VmPowerState.HALTED && vm != null) { + citrixResourceBase.destroyVm(vm, conn); } } catch (final Exception e2) { s_logger.error("delete snapshot error due to " + e2.getMessage()); diff --git a/plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/CitrixDeleteVMSnapshotCommandWrapper.java b/plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/CitrixDeleteVMSnapshotCommandWrapper.java index b74111e8441c..0bcbe13c5580 100644 --- a/plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/CitrixDeleteVMSnapshotCommandWrapper.java +++ b/plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/CitrixDeleteVMSnapshotCommandWrapper.java @@ -68,7 +68,7 @@ public Answer execute(final DeleteVMSnapshotCommand command, final CitrixResourc if (command.getTarget().getType() == VMSnapshot.Type.DiskAndMemory) { vdiList.add(snapshot.getSuspendVDI(conn)); } - snapshot.destroy(conn); + citrixResourceBase.destroyVm(snapshot, conn, true); for (final VDI vdi : vdiList) { vdi.destroy(conn); } diff --git a/plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/CitrixRevertToVMSnapshotCommandWrapper.java b/plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/CitrixRevertToVMSnapshotCommandWrapper.java index f8bb1b892420..445e764a38c3 100644 --- a/plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/CitrixRevertToVMSnapshotCommandWrapper.java +++ b/plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/CitrixRevertToVMSnapshotCommandWrapper.java @@ -68,6 +68,7 @@ public Answer execute(final RevertToVMSnapshotCommand command, final CitrixResou try { vm = citrixResourceBase.getVM(conn, vmName); } catch (final Exception e) { + s_logger.debug(String.format("Failed to find VM with name: %s due to:", vmName), e); vm = citrixResourceBase.createWorkingVM(conn, vmName, command.getGuestOSType(), command.getPlatformEmulator(), listVolumeTo); } @@ -90,7 +91,7 @@ public Answer execute(final RevertToVMSnapshotCommand command, final CitrixResou } if (!snapshotMemory) { - vm.destroy(conn); + citrixResourceBase.destroyVm(vm, conn); vmState = PowerState.PowerOff; } else { vmState = PowerState.PowerOn; diff --git a/plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/CitrixStartCommandWrapper.java b/plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/CitrixStartCommandWrapper.java index ad76b7f4541a..5867a151c850 100644 --- a/plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/CitrixStartCommandWrapper.java +++ b/plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/CitrixStartCommandWrapper.java @@ -75,7 +75,7 @@ public Answer execute(final StartCommand command, final CitrixResourceBase citri for (final VM v : vms) { final VM.Record vRec = v.getRecord(conn); if (vRec.powerState == VmPowerState.HALTED) { - v.destroy(conn); + citrixResourceBase.destroyVm(v, conn, true); } else if (vRec.powerState == VmPowerState.RUNNING) { final String host = vRec.residentOn.getUuid(conn); final String msg = "VM " + vmName + " is runing on host " + host; diff --git a/plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/CitrixStopCommandWrapper.java b/plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/CitrixStopCommandWrapper.java index 8e7eb4caec29..87c2cb768229 100644 --- a/plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/CitrixStopCommandWrapper.java +++ b/plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/resource/wrapper/xenbase/CitrixStopCommandWrapper.java @@ -143,7 +143,7 @@ public Answer execute(final StopCommand command, final CitrixResourceBase citrix for (final VIF vif : vifs) { networks.add(vif.getNetwork(conn)); } - vm.destroy(conn); + citrixResourceBase.destroyVm(vm, conn); final SR sr = citrixResourceBase.getISOSRbyVmName(conn, command.getVmName(), false); citrixResourceBase.removeSR(conn, sr); final SR configDriveSR = citrixResourceBase.getISOSRbyVmName(conn, command.getVmName(), true); diff --git a/plugins/shutdown/src/main/java/org/apache/cloudstack/api/response/ReadyForShutdownResponse.java b/plugins/shutdown/src/main/java/org/apache/cloudstack/api/response/ReadyForShutdownResponse.java index d1b2353d2a33..9b2728d9d6e8 100644 --- a/plugins/shutdown/src/main/java/org/apache/cloudstack/api/response/ReadyForShutdownResponse.java +++ b/plugins/shutdown/src/main/java/org/apache/cloudstack/api/response/ReadyForShutdownResponse.java @@ -38,10 +38,10 @@ public class ReadyForShutdownResponse extends BaseResponse { @SerializedName(ApiConstants.MANAGEMENT_SERVER_ID) @Param(description = "The id of the management server") - private Long msId; + private String msUuid; - public ReadyForShutdownResponse(Long msId, Boolean shutdownTriggered, Boolean readyForShutdown, long pendingJobsCount) { - this.msId = msId; + public ReadyForShutdownResponse(String msUuid, Boolean shutdownTriggered, Boolean readyForShutdown, long pendingJobsCount) { + this.msUuid = msUuid; this.shutdownTriggered = shutdownTriggered; this.readyForShutdown = readyForShutdown; this.pendingJobsCount = pendingJobsCount; @@ -70,12 +70,4 @@ public Long getPendingJobsCount() { public void setPendingJobsCount(Long pendingJobsCount) { this.pendingJobsCount = pendingJobsCount; } - - public Long getMsId() { - return msId; - } - - public void setMsId(Long msId) { - this.msId = msId; - } } diff --git a/plugins/shutdown/src/main/java/org/apache/cloudstack/shutdown/ShutdownManagerImpl.java b/plugins/shutdown/src/main/java/org/apache/cloudstack/shutdown/ShutdownManagerImpl.java index da3bba54bdc3..e08b23f6c6ae 100644 --- a/plugins/shutdown/src/main/java/org/apache/cloudstack/shutdown/ShutdownManagerImpl.java +++ b/plugins/shutdown/src/main/java/org/apache/cloudstack/shutdown/ShutdownManagerImpl.java @@ -137,6 +137,7 @@ public void cancelShutdown() { public ReadyForShutdownResponse readyForShutdown(Long managementserverid) { Long[] msIds = null; boolean shutdownTriggeredAnywhere = false; + String msUuid = null; State[] shutdownTriggeredStates = {State.ShuttingDown, State.PreparingToShutDown, State.ReadyToShutDown}; if (managementserverid == null) { List msHosts = msHostDao.listBy(shutdownTriggeredStates); @@ -149,11 +150,12 @@ public ReadyForShutdownResponse readyForShutdown(Long managementserverid) { } } else { ManagementServerHostVO msHost = msHostDao.findById(managementserverid); + msUuid = msHost.getUuid(); msIds = new Long[]{msHost.getMsid()}; shutdownTriggeredAnywhere = Arrays.asList(shutdownTriggeredStates).contains(msHost.getState()); } long pendingJobCount = countPendingJobs(msIds); - return new ReadyForShutdownResponse(managementserverid, shutdownTriggeredAnywhere, pendingJobCount == 0, pendingJobCount); + return new ReadyForShutdownResponse(msUuid, shutdownTriggeredAnywhere, pendingJobCount == 0, pendingJobCount); } @Override diff --git a/plugins/user-authenticators/saml2/src/main/java/org/apache/cloudstack/api/command/ListAndSwitchSAMLAccountCmd.java b/plugins/user-authenticators/saml2/src/main/java/org/apache/cloudstack/api/command/ListAndSwitchSAMLAccountCmd.java index c2f81cd33563..040d5414f26f 100644 --- a/plugins/user-authenticators/saml2/src/main/java/org/apache/cloudstack/api/command/ListAndSwitchSAMLAccountCmd.java +++ b/plugins/user-authenticators/saml2/src/main/java/org/apache/cloudstack/api/command/ListAndSwitchSAMLAccountCmd.java @@ -133,10 +133,12 @@ public String authenticate(final String command, final Map par } if (userUuid != null && domainUuid != null) { + s_logger.debug("User [" + currentUserAccount.getUsername() + "] is requesting to switch from user profile [" + currentUserAccount.getId() + "] to useraccount [" + userUuid + "] in domain [" + domainUuid + "]"); final User user = _userDao.findByUuid(userUuid); final Domain domain = _domainDao.findByUuid(domainUuid); final UserAccount nextUserAccount = _accountService.getUserAccountById(user.getId()); if (nextUserAccount != null && !nextUserAccount.getAccountState().equals(Account.State.ENABLED.toString())) { + s_logger.warn("User [" + currentUserAccount.getUsername() + "] is requesting to switch from user profile [" + currentUserId + "] to user profile [" + userUuid + "] in domain [" + domainUuid + "] but the associated target account [" + nextUserAccount.getAccountName() + "] is not enabled"); throw new ServerApiException(ApiErrorCode.ACCOUNT_ERROR, _apiServer.getSerializedApiError(ApiErrorCode.PARAM_ERROR.getHttpCode(), "The requested user account is locked and cannot be switched to, please contact your administrator.", params, responseType)); @@ -147,20 +149,26 @@ public String authenticate(final String command, final Map par || !nextUserAccount.getExternalEntity().equals(currentUserAccount.getExternalEntity()) || (nextUserAccount.getDomainId() != domain.getId()) || (nextUserAccount.getSource() != User.Source.SAML2)) { + s_logger.warn("User [" + currentUserAccount.getUsername() + "] is requesting to switch from user profile [" + currentUserId + "] to user profile [" + userUuid + "] in domain [" + domainUuid + "] but the associated target account is not found or invalid"); throw new ServerApiException(ApiErrorCode.PARAM_ERROR, _apiServer.getSerializedApiError(ApiErrorCode.PARAM_ERROR.getHttpCode(), "User account is not allowed to switch to the requested account", params, responseType)); } try { if (_apiServer.verifyUser(nextUserAccount.getId())) { + s_logger.info("User [" + currentUserAccount.getUsername() + "] user profile switch is accepted: from [" + currentUserId + "] to user profile [" + userUuid + "] in domain [" + domainUuid + "] with account [" + nextUserAccount.getAccountName() + "]"); + // need to set a sessoin variable to inform the login function of the specific user to login as, rather than using email only (which could have multiple matches) + session.setAttribute("nextUserId", user.getId()); final LoginCmdResponse loginResponse = (LoginCmdResponse) _apiServer.loginUser(session, nextUserAccount.getUsername(), nextUserAccount.getUsername() + nextUserAccount.getSource().toString(), nextUserAccount.getDomainId(), null, remoteAddress, params); SAMLUtils.setupSamlUserCookies(loginResponse, resp); - resp.sendRedirect(SAML2AuthManager.SAMLCloudStackRedirectionUrl.value()); + session.removeAttribute("nextUserId"); + s_logger.debug("User [" + currentUserAccount.getUsername() + "] user profile switch cookies set: from [" + currentUserId + "] to user profile [" + userUuid + "] in domain [" + domainUuid + "] with account [" + nextUserAccount.getAccountName() + "]"); + //resp.sendRedirect(SAML2AuthManager.SAMLCloudStackRedirectionUrl.value()); return ApiResponseSerializer.toSerializedString(loginResponse, responseType); } } catch (CloudAuthenticationException | IOException exception) { - s_logger.debug("Failed to switch to request SAML user account due to: " + exception.getMessage()); + s_logger.debug("User [" + currentUserAccount.getUsername() + "] user profile switch cookies set FAILED: from [" + currentUserId + "] to user profile [" + userUuid + "] in domain [" + domainUuid + "] with account [" + nextUserAccount.getAccountName() + "]", exception); } } else { List switchableAccounts = _userAccountDao.getAllUsersByNameAndEntity(currentUserAccount.getUsername(), currentUserAccount.getExternalEntity()); @@ -178,6 +186,9 @@ public String authenticate(final String command, final Map par accountResponse.setAccountName(userAccount.getAccountName()); accountResponse.setIdpId(user.getExternalEntity()); accountResponses.add(accountResponse); + if (s_logger.isDebugEnabled()) { + s_logger.debug("Returning available useraccount for [" + currentUserAccount.getUsername() + "]: UserUUID: [" + user.getUuid() + "], DomainUUID: [" + domain.getUuid() + "], Account: [" + userAccount.getAccountName() + "]"); + } } ListResponse response = new ListResponse(); response.setResponses(accountResponses); diff --git a/plugins/user-authenticators/saml2/src/main/java/org/apache/cloudstack/api/command/SAML2LoginAPIAuthenticatorCmd.java b/plugins/user-authenticators/saml2/src/main/java/org/apache/cloudstack/api/command/SAML2LoginAPIAuthenticatorCmd.java index 332e06027844..0f25123ff88b 100644 --- a/plugins/user-authenticators/saml2/src/main/java/org/apache/cloudstack/api/command/SAML2LoginAPIAuthenticatorCmd.java +++ b/plugins/user-authenticators/saml2/src/main/java/org/apache/cloudstack/api/command/SAML2LoginAPIAuthenticatorCmd.java @@ -192,7 +192,7 @@ public String authenticate(final String command, final Map par String authnId = SAMLUtils.generateSecureRandomId(); samlAuthManager.saveToken(authnId, domainPath, idpMetadata.getEntityId()); s_logger.debug("Sending SAMLRequest id=" + authnId); - String redirectUrl = SAMLUtils.buildAuthnRequestUrl(authnId, spMetadata, idpMetadata, SAML2AuthManager.SAMLSignatureAlgorithm.value()); + String redirectUrl = SAMLUtils.buildAuthnRequestUrl(authnId, spMetadata, idpMetadata, SAML2AuthManager.SAMLSignatureAlgorithm.value(), SAML2AuthManager.SAMLRequirePasswordLogin.value()); resp.sendRedirect(redirectUrl); return ""; } if (params.containsKey("SAMLart")) { diff --git a/plugins/user-authenticators/saml2/src/main/java/org/apache/cloudstack/saml/SAML2AuthManager.java b/plugins/user-authenticators/saml2/src/main/java/org/apache/cloudstack/saml/SAML2AuthManager.java index 4e8ba16c7398..523f694d80b2 100644 --- a/plugins/user-authenticators/saml2/src/main/java/org/apache/cloudstack/saml/SAML2AuthManager.java +++ b/plugins/user-authenticators/saml2/src/main/java/org/apache/cloudstack/saml/SAML2AuthManager.java @@ -79,6 +79,10 @@ public interface SAML2AuthManager extends PluggableAPIAuthenticator, PluggableSe ConfigKey SAMLUserSessionKeyPathAttribute = new ConfigKey("Advanced", String.class, "saml2.user.sessionkey.path", "", "The Path attribute of sessionkey cookie when SAML users have logged in. If not set, it will be set to the path of SAML redirection URL (saml2.redirect.url).", true); + ConfigKey SAMLRequirePasswordLogin = new ConfigKey("Advanced", Boolean.class, "saml2.require.password", "true", + "When enabled SAML2 will validate that the SAML login was performed with a password. If disabled, other forms of authentication are allowed (two-factor, certificate, etc) on the SAML Authentication Provider", true); + + SAMLProviderMetadata getSPMetadata(); SAMLProviderMetadata getIdPMetadata(String entityId); Collection getAllIdPMetadata(); diff --git a/plugins/user-authenticators/saml2/src/main/java/org/apache/cloudstack/saml/SAML2AuthManagerImpl.java b/plugins/user-authenticators/saml2/src/main/java/org/apache/cloudstack/saml/SAML2AuthManagerImpl.java index a7524ec63a7d..92408141ef29 100644 --- a/plugins/user-authenticators/saml2/src/main/java/org/apache/cloudstack/saml/SAML2AuthManagerImpl.java +++ b/plugins/user-authenticators/saml2/src/main/java/org/apache/cloudstack/saml/SAML2AuthManagerImpl.java @@ -543,6 +543,6 @@ public ConfigKey[] getConfigKeys() { SAMLCloudStackRedirectionUrl, SAMLUserAttributeName, SAMLIdentityProviderMetadataURL, SAMLDefaultIdentityProviderId, SAMLSignatureAlgorithm, SAMLAppendDomainSuffix, SAMLTimeout, SAMLCheckSignature, - SAMLForceAuthn, SAMLUserSessionKeyPathAttribute}; + SAMLForceAuthn, SAMLUserSessionKeyPathAttribute, SAMLRequirePasswordLogin}; } } diff --git a/plugins/user-authenticators/saml2/src/main/java/org/apache/cloudstack/saml/SAMLUtils.java b/plugins/user-authenticators/saml2/src/main/java/org/apache/cloudstack/saml/SAMLUtils.java index fd68e2be1ae9..2460e3826c69 100644 --- a/plugins/user-authenticators/saml2/src/main/java/org/apache/cloudstack/saml/SAMLUtils.java +++ b/plugins/user-authenticators/saml2/src/main/java/org/apache/cloudstack/saml/SAMLUtils.java @@ -151,11 +151,11 @@ public static String getValueFromAssertions(final List assertions, fi return null; } - public static String buildAuthnRequestUrl(final String authnId, final SAMLProviderMetadata spMetadata, final SAMLProviderMetadata idpMetadata, final String signatureAlgorithm) { + public static String buildAuthnRequestUrl(final String authnId, final SAMLProviderMetadata spMetadata, final SAMLProviderMetadata idpMetadata, final String signatureAlgorithm, boolean requirePasswordAuthentication) { String redirectUrl = ""; try { DefaultBootstrap.bootstrap(); - AuthnRequest authnRequest = SAMLUtils.buildAuthnRequestObject(authnId, spMetadata.getEntityId(), idpMetadata.getSsoUrl(), spMetadata.getSsoUrl()); + AuthnRequest authnRequest = SAMLUtils.buildAuthnRequestObject(authnId, spMetadata.getEntityId(), idpMetadata.getSsoUrl(), spMetadata.getSsoUrl(), requirePasswordAuthentication); PrivateKey privateKey = null; if (spMetadata.getKeyPair() != null) { privateKey = spMetadata.getKeyPair().getPrivate(); @@ -168,28 +168,21 @@ public static String buildAuthnRequestUrl(final String authnId, final SAMLProvid return redirectUrl; } - public static AuthnRequest buildAuthnRequestObject(final String authnId, final String spId, final String idpUrl, final String consumerUrl) { + public static AuthnRequest buildAuthnRequestObject(final String authnId, final String spId, final String idpUrl, final String consumerUrl, boolean requirePasswordAuthentication) { // Issuer object IssuerBuilder issuerBuilder = new IssuerBuilder(); Issuer issuer = issuerBuilder.buildObject(); issuer.setValue(spId); - // AuthnContextClass - AuthnContextClassRefBuilder authnContextClassRefBuilder = new AuthnContextClassRefBuilder(); - AuthnContextClassRef authnContextClassRef = authnContextClassRefBuilder.buildObject( - SAMLConstants.SAML20_NS, - "AuthnContextClassRef", "saml"); - authnContextClassRef.setAuthnContextClassRef(AuthnContext.PPT_AUTHN_CTX); - - // AuthnContext - RequestedAuthnContextBuilder requestedAuthnContextBuilder = new RequestedAuthnContextBuilder(); - RequestedAuthnContext requestedAuthnContext = requestedAuthnContextBuilder.buildObject(); - requestedAuthnContext.setComparison(AuthnContextComparisonTypeEnumeration.EXACT); - requestedAuthnContext.getAuthnContextClassRefs().add(authnContextClassRef); - // Creation of AuthRequestObject AuthnRequestBuilder authRequestBuilder = new AuthnRequestBuilder(); AuthnRequest authnRequest = authRequestBuilder.buildObject(); + + // AuthnContextClass. When this is false, the authentication requirements are defered to the SAML IDP and its default or configured workflow + if (requirePasswordAuthentication) { + setRequestedAuthnContext(authnRequest, requirePasswordAuthentication); + } + authnRequest.setID(authnId); authnRequest.setDestination(idpUrl); authnRequest.setVersion(SAMLVersion.VERSION_20); @@ -200,11 +193,25 @@ public static AuthnRequest buildAuthnRequestObject(final String authnId, final S authnRequest.setAssertionConsumerServiceURL(consumerUrl); authnRequest.setProviderName(spId); authnRequest.setIssuer(issuer); - authnRequest.setRequestedAuthnContext(requestedAuthnContext); return authnRequest; } + public static void setRequestedAuthnContext(AuthnRequest authnRequest, boolean requirePasswordAuthentication) { + AuthnContextClassRefBuilder authnContextClassRefBuilder = new AuthnContextClassRefBuilder(); + AuthnContextClassRef authnContextClassRef = authnContextClassRefBuilder.buildObject( + SAMLConstants.SAML20_NS, + "AuthnContextClassRef", "saml"); + authnContextClassRef.setAuthnContextClassRef(AuthnContext.PPT_AUTHN_CTX); + + // AuthnContext + RequestedAuthnContextBuilder requestedAuthnContextBuilder = new RequestedAuthnContextBuilder(); + RequestedAuthnContext requestedAuthnContext = requestedAuthnContextBuilder.buildObject(); + requestedAuthnContext.setComparison(AuthnContextComparisonTypeEnumeration.EXACT); + requestedAuthnContext.getAuthnContextClassRefs().add(authnContextClassRef); + authnRequest.setRequestedAuthnContext(requestedAuthnContext); + } + public static LogoutRequest buildLogoutRequest(String logoutUrl, String spId, String nameIdString) { Issuer issuer = new IssuerBuilder().buildObject(); issuer.setValue(spId); @@ -284,23 +291,6 @@ public static String generateSAMLRequestSignature(final String urlEncodedString, } public static void setupSamlUserCookies(final LoginCmdResponse loginResponse, final HttpServletResponse resp) throws IOException { - resp.addCookie(new Cookie("userid", URLEncoder.encode(loginResponse.getUserId(), HttpUtils.UTF_8))); - resp.addCookie(new Cookie("domainid", URLEncoder.encode(loginResponse.getDomainId(), HttpUtils.UTF_8))); - resp.addCookie(new Cookie("role", URLEncoder.encode(loginResponse.getType(), HttpUtils.UTF_8))); - resp.addCookie(new Cookie("username", URLEncoder.encode(loginResponse.getUsername(), HttpUtils.UTF_8))); - resp.addCookie(new Cookie("account", URLEncoder.encode(loginResponse.getAccount(), HttpUtils.UTF_8))); - resp.addCookie(new Cookie("isSAML", URLEncoder.encode("true", HttpUtils.UTF_8))); - resp.addCookie(new Cookie("twoFaEnabled", URLEncoder.encode(loginResponse.is2FAenabled(), HttpUtils.UTF_8))); - String providerFor2FA = loginResponse.getProviderFor2FA(); - if (StringUtils.isNotEmpty(providerFor2FA)) { - resp.addCookie(new Cookie("twoFaProvider", URLEncoder.encode(loginResponse.getProviderFor2FA(), HttpUtils.UTF_8))); - } - String timezone = loginResponse.getTimeZone(); - if (timezone != null) { - resp.addCookie(new Cookie("timezone", URLEncoder.encode(timezone, HttpUtils.UTF_8))); - } - resp.addCookie(new Cookie("userfullname", URLEncoder.encode(loginResponse.getFirstName() + " " + loginResponse.getLastName(), HttpUtils.UTF_8).replace("+", "%20"))); - String redirectUrl = SAML2AuthManager.SAMLCloudStackRedirectionUrl.value(); String path = SAML2AuthManager.SAMLUserSessionKeyPathAttribute.value(); String domain = null; @@ -316,6 +306,18 @@ public static void setupSamlUserCookies(final LoginCmdResponse loginResponse, fi } catch (URISyntaxException ex) { throw new CloudRuntimeException("Invalid URI: " + redirectUrl); } + + addBaseCookies(loginResponse, resp, domain, path); + + String providerFor2FA = loginResponse.getProviderFor2FA(); + if (StringUtils.isNotEmpty(providerFor2FA)) { + resp.addCookie(newCookie(domain, path,"twoFaProvider", URLEncoder.encode(loginResponse.getProviderFor2FA(), HttpUtils.UTF_8))); + } + String timezone = loginResponse.getTimeZone(); + if (timezone != null) { + resp.addCookie(newCookie(domain, path,"timezone", URLEncoder.encode(timezone, HttpUtils.UTF_8))); + } + String sameSite = ApiServlet.getApiSessionKeySameSite(); String sessionKeyCookie = String.format("%s=%s;Domain=%s;Path=%s;%s", ApiConstants.SESSIONKEY, loginResponse.getSessionKey(), domain, path, sameSite); s_logger.debug("Adding sessionkey cookie to response: " + sessionKeyCookie); @@ -323,6 +325,24 @@ public static void setupSamlUserCookies(final LoginCmdResponse loginResponse, fi resp.addHeader("SET-COOKIE", String.format("%s=%s;HttpOnly;Path=/client/api;%s", ApiConstants.SESSIONKEY, loginResponse.getSessionKey(), sameSite)); } + private static void addBaseCookies(final LoginCmdResponse loginResponse, final HttpServletResponse resp, String domain, String path) throws IOException { + resp.addCookie(newCookie(domain, path, "userid", URLEncoder.encode(loginResponse.getUserId(), HttpUtils.UTF_8))); + resp.addCookie(newCookie(domain, path,"domainid", URLEncoder.encode(loginResponse.getDomainId(), HttpUtils.UTF_8))); + resp.addCookie(newCookie(domain, path,"role", URLEncoder.encode(loginResponse.getType(), HttpUtils.UTF_8))); + resp.addCookie(newCookie(domain, path,"username", URLEncoder.encode(loginResponse.getUsername(), HttpUtils.UTF_8))); + resp.addCookie(newCookie(domain, path,"account", URLEncoder.encode(loginResponse.getAccount(), HttpUtils.UTF_8))); + resp.addCookie(newCookie(domain, path,"isSAML", URLEncoder.encode("true", HttpUtils.UTF_8))); + resp.addCookie(newCookie(domain, path,"twoFaEnabled", URLEncoder.encode(loginResponse.is2FAenabled(), HttpUtils.UTF_8))); + resp.addCookie(newCookie(domain, path,"userfullname", URLEncoder.encode(loginResponse.getFirstName() + " " + loginResponse.getLastName(), HttpUtils.UTF_8).replace("+", "%20"))); + } + + private static Cookie newCookie(final String domain, final String path, final String name, final String value) { + Cookie cookie = new Cookie(name, value); + cookie.setDomain(domain); + cookie.setPath(path); + return cookie; + } + /** * Returns base64 encoded PublicKey * @param key PublicKey diff --git a/plugins/user-authenticators/saml2/src/test/java/org/apache/cloudstack/SAMLUtilsTest.java b/plugins/user-authenticators/saml2/src/test/java/org/apache/cloudstack/SAMLUtilsTest.java index 752845edb642..891d028aebfe 100644 --- a/plugins/user-authenticators/saml2/src/test/java/org/apache/cloudstack/SAMLUtilsTest.java +++ b/plugins/user-authenticators/saml2/src/test/java/org/apache/cloudstack/SAMLUtilsTest.java @@ -58,7 +58,7 @@ public void testBuildAuthnRequestObject() throws Exception { String idpUrl = "http://idp.domain.example"; String spId = "cloudstack"; String authnId = SAMLUtils.generateSecureRandomId(); - AuthnRequest req = SAMLUtils.buildAuthnRequestObject(authnId, spId, idpUrl, consumerUrl); + AuthnRequest req = SAMLUtils.buildAuthnRequestObject(authnId, spId, idpUrl, consumerUrl, true); assertEquals(req.getAssertionConsumerServiceURL(), consumerUrl); assertEquals(req.getDestination(), idpUrl); assertEquals(req.getIssuer().getValue(), spId); @@ -86,7 +86,7 @@ public void testBuildAuthnRequestUrlWithoutQueryParam() throws Exception { idpMetadata.setSsoUrl(idpUrl); idpMetadata.setEntityId(idpId); - URI redirectUrl = new URI(SAMLUtils.buildAuthnRequestUrl(authnId, spMetadata, idpMetadata, SAML2AuthManager.SAMLSignatureAlgorithm.value())); + URI redirectUrl = new URI(SAMLUtils.buildAuthnRequestUrl(authnId, spMetadata, idpMetadata, SAML2AuthManager.SAMLSignatureAlgorithm.value(), true)); assertThat(redirectUrl).hasScheme(urlScheme).hasHost(idpDomain).hasParameter("SAMLRequest"); assertEquals(urlScheme, redirectUrl.getScheme()); assertEquals(idpDomain, redirectUrl.getHost()); @@ -115,7 +115,7 @@ public void testBuildAuthnRequestUrlWithQueryParam() throws Exception { idpMetadata.setSsoUrl(idpUrl); idpMetadata.setEntityId(idpId); - URI redirectUrl = new URI(SAMLUtils.buildAuthnRequestUrl(authnId, spMetadata, idpMetadata, SAML2AuthManager.SAMLSignatureAlgorithm.value())); + URI redirectUrl = new URI(SAMLUtils.buildAuthnRequestUrl(authnId, spMetadata, idpMetadata, SAML2AuthManager.SAMLSignatureAlgorithm.value(), true)); assertThat(redirectUrl).hasScheme(urlScheme).hasHost(idpDomain).hasParameter("idpid").hasParameter("SAMLRequest"); assertEquals(urlScheme, redirectUrl.getScheme()); assertEquals(idpDomain, redirectUrl.getHost()); diff --git a/plugins/user-authenticators/saml2/src/test/java/org/apache/cloudstack/api/command/ListAndSwitchSAMLAccountCmdTest.java b/plugins/user-authenticators/saml2/src/test/java/org/apache/cloudstack/api/command/ListAndSwitchSAMLAccountCmdTest.java index 729334d22ce5..bfee28a7e3b8 100644 --- a/plugins/user-authenticators/saml2/src/test/java/org/apache/cloudstack/api/command/ListAndSwitchSAMLAccountCmdTest.java +++ b/plugins/user-authenticators/saml2/src/test/java/org/apache/cloudstack/api/command/ListAndSwitchSAMLAccountCmdTest.java @@ -213,7 +213,6 @@ public void testListAndSwitchSAMLAccountCmd() throws Exception { loginCmdResponse.set2FAenabled("false"); Mockito.when(apiServer.loginUser(nullable(HttpSession.class), nullable(String.class), nullable(String.class), nullable(Long.class), nullable(String.class), nullable(InetAddress.class), nullable(Map.class))).thenReturn(loginCmdResponse); - Mockito.doNothing().when(resp).sendRedirect(nullable(String.class)); try { cmd.authenticate("command", params, session, null, HttpUtils.RESPONSE_TYPE_JSON, new StringBuilder(), req, resp); } catch (ServerApiException exception) { @@ -221,7 +220,6 @@ public void testListAndSwitchSAMLAccountCmd() throws Exception { } finally { // accountService should have been called 4 times by now, for this case twice and 2 for cases above Mockito.verify(accountService, Mockito.times(4)).getUserAccountById(Mockito.anyLong()); - Mockito.verify(resp, Mockito.times(1)).sendRedirect(anyString()); } } diff --git a/server/src/main/java/com/cloud/api/ApiServer.java b/server/src/main/java/com/cloud/api/ApiServer.java index c78f8e68c2bb..afa5f07c826a 100644 --- a/server/src/main/java/com/cloud/api/ApiServer.java +++ b/server/src/main/java/com/cloud/api/ApiServer.java @@ -1159,7 +1159,14 @@ public ResponseObject loginUser(final HttpSession session, final String username domainId = userDomain.getId(); } - UserAccount userAcct = accountMgr.authenticateUser(username, password, domainId, loginIpAddress, requestParameters); + Long userId = (Long)session.getAttribute("nextUserId"); + UserAccount userAcct = null; + if (userId != null) { + userAcct = accountMgr.getUserAccountById(userId); + } else { + userAcct = accountMgr.authenticateUser(username, password, domainId, loginIpAddress, requestParameters); + } + if (userAcct != null) { final String timezone = userAcct.getTimezone(); float offsetInHrs = 0f; diff --git a/server/src/main/java/com/cloud/ha/HighAvailabilityManagerImpl.java b/server/src/main/java/com/cloud/ha/HighAvailabilityManagerImpl.java index 81ae44a97634..aa43e6b91610 100644 --- a/server/src/main/java/com/cloud/ha/HighAvailabilityManagerImpl.java +++ b/server/src/main/java/com/cloud/ha/HighAvailabilityManagerImpl.java @@ -342,7 +342,8 @@ protected void wakeupWorkers() { @Override public boolean scheduleMigration(final VMInstanceVO vm) { if (vm.getHostId() != null) { - final HaWorkVO work = new HaWorkVO(vm.getId(), vm.getType(), WorkType.Migration, Step.Scheduled, vm.getHostId(), vm.getState(), 0, vm.getUpdated()); + Long hostId = VirtualMachine.State.Migrating.equals(vm.getState()) ? vm.getLastHostId() : vm.getHostId(); + final HaWorkVO work = new HaWorkVO(vm.getId(), vm.getType(), WorkType.Migration, Step.Scheduled, hostId, vm.getState(), 0, vm.getUpdated()); _haDao.persist(work); s_logger.info("Scheduled migration work of VM " + vm.getUuid() + " from host " + _hostDao.findById(vm.getHostId()) + " with HAWork " + work); wakeupWorkers(); @@ -716,6 +717,14 @@ public Long migrate(final HaWorkVO work) { s_logger.info("Unable to find vm: " + vmId + ", skipping migrate."); return null; } + if (VirtualMachine.State.Stopped.equals(vm.getState())) { + s_logger.info(String.format("vm %s is Stopped, skipping migrate.", vm)); + return null; + } + if (VirtualMachine.State.Running.equals(vm.getState()) && srcHostId != vm.getHostId()) { + s_logger.info(String.format("VM %s is running on a different host %s, skipping migration", vm, vm.getHostId())); + return null; + } s_logger.info("Migration attempt: for VM " + vm.getUuid() + "from host id " + srcHostId + ". Starting attempt: " + (1 + work.getTimesTried()) + "/" + _maxRetries + " times."); try { @@ -1022,6 +1031,13 @@ public WorkerThread(String name) { @Override public void run() { + try { + synchronized (this) { + wait(_timeToSleep); + } + } catch (final InterruptedException e) { + s_logger.info("Interrupted"); + } s_logger.info("Starting work"); while (!_stopped) { _managedContext.runWithContext(new Runnable() { diff --git a/server/src/main/java/com/cloud/network/IpAddressManagerImpl.java b/server/src/main/java/com/cloud/network/IpAddressManagerImpl.java index 261dc529434a..63c55966d5b2 100644 --- a/server/src/main/java/com/cloud/network/IpAddressManagerImpl.java +++ b/server/src/main/java/com/cloud/network/IpAddressManagerImpl.java @@ -1044,36 +1044,48 @@ public List listAvailablePublicIps(final long dcId, final Long podI @Override public void markPublicIpAsAllocated(final IPAddressVO addr) { synchronized (allocatedLock) { - Transaction.execute(new TransactionCallbackNoReturn() { + Transaction.execute(new TransactionCallbackWithExceptionNoReturn() { @Override public void doInTransactionWithoutResult(TransactionStatus status) { Account owner = _accountMgr.getAccount(addr.getAllocatedToAccountId()); - if (_ipAddressDao.lockRow(addr.getId(), true) != null) { - final IPAddressVO userIp = _ipAddressDao.findById(addr.getId()); - if (userIp.getState() == IpAddress.State.Allocating || addr.getState() == IpAddress.State.Free || addr.getState() == IpAddress.State.Reserved) { - boolean shouldUpdateIpResourceCount = checkIfIpResourceCountShouldBeUpdated(addr); - addr.setState(IpAddress.State.Allocated); - if (_ipAddressDao.update(addr.getId(), addr)) { - // Save usage event - if (owner.getAccountId() != Account.ACCOUNT_ID_SYSTEM) { - VlanVO vlan = _vlanDao.findById(addr.getVlanId()); - String guestType = vlan.getVlanType().toString(); - if (!isIpDedicated(addr)) { - final boolean usageHidden = isUsageHidden(addr); - UsageEventUtils.publishUsageEvent(EventTypes.EVENT_NET_IP_ASSIGN, owner.getId(), addr.getDataCenterId(), addr.getId(), - addr.getAddress().toString(), addr.isSourceNat(), guestType, addr.getSystem(), usageHidden, - addr.getClass().getName(), addr.getUuid()); - } - if (shouldUpdateIpResourceCount) { - _resourceLimitMgr.incrementResourceCount(owner.getId(), ResourceType.public_ip); - } - } - } else { - s_logger.error("Failed to mark public IP as allocated with id=" + addr.getId() + " address=" + addr.getAddress()); + final IPAddressVO userIp = _ipAddressDao.lockRow(addr.getId(), true); + if (userIp == null) { + s_logger.error(String.format("Failed to acquire row lock to mark public IP as allocated with ID [%s] and address [%s]", addr.getId(), addr.getAddress())); + return; + } + + List expectedIpAddressStates = List.of(IpAddress.State.Allocating, IpAddress.State.Free, IpAddress.State.Reserved); + if (!expectedIpAddressStates.contains(userIp.getState())) { + s_logger.debug(String.format("Not marking public IP with ID [%s] and address [%s] as allocated, since it is in the [%s] state.", addr.getId(), addr.getAddress(), userIp.getState())); + return; + } + + boolean shouldUpdateIpResourceCount = checkIfIpResourceCountShouldBeUpdated(addr); + addr.setState(IpAddress.State.Allocated); + boolean updatedIpAddress = _ipAddressDao.update(addr.getId(), addr); + if (!updatedIpAddress) { + s_logger.error(String.format("Failed to mark public IP as allocated with ID [%s] and address [%s]", addr.getId(), addr.getAddress())); + return; + } + + if (owner.getAccountId() != Account.ACCOUNT_ID_SYSTEM) { + if (shouldUpdateIpResourceCount) { + try (CheckedReservation publicIpReservation = new CheckedReservation(owner, ResourceType.public_ip, 1L, reservationDao, _resourceLimitMgr)) { + _resourceLimitMgr.incrementResourceCount(owner.getId(), ResourceType.public_ip); + } catch (Exception e) { + _ipAddressDao.unassignIpAddress(addr.getId()); + throw new CloudRuntimeException(e); } } - } else { - s_logger.error("Failed to acquire row lock to mark public IP as allocated with id=" + addr.getId() + " address=" + addr.getAddress()); + + VlanVO vlan = _vlanDao.findById(addr.getVlanId()); + String guestType = vlan.getVlanType().toString(); + if (!isIpDedicated(addr)) { + final boolean usageHidden = isUsageHidden(addr); + UsageEventUtils.publishUsageEvent(EventTypes.EVENT_NET_IP_ASSIGN, owner.getId(), addr.getDataCenterId(), addr.getId(), + addr.getAddress().toString(), addr.isSourceNat(), guestType, addr.getSystem(), usageHidden, + addr.getClass().getName(), addr.getUuid()); + } } } }); @@ -1557,28 +1569,30 @@ public IPAddressVO associateIPToGuestNetwork(long ipId, long networkId, boolean } boolean isSourceNat = isSourceNatAvailableForNetwork(owner, ipToAssoc, network); - - s_logger.debug("Associating ip " + ipToAssoc + " to network " + network); - + s_logger.debug(String.format("Associating IP [%s] to network [%s].", ipToAssoc, network)); boolean success = false; IPAddressVO ip = null; - try (CheckedReservation publicIpReservation = new CheckedReservation(owner, ResourceType.public_ip, 1l, reservationDao, _resourceLimitMgr)) { - ip = _ipAddressDao.findById(ipId); - //update ip address with networkId - ip.setAssociatedWithNetworkId(networkId); - ip.setSourceNat(isSourceNat); - _ipAddressDao.update(ipId, ip); - - success = applyIpAssociations(network, false); + try { + Pair updatedIpAddress = Transaction.execute((TransactionCallbackWithException, Exception>) status -> { + IPAddressVO ipAddress = _ipAddressDao.findById(ipId); + ipAddress.setAssociatedWithNetworkId(networkId); + ipAddress.setSourceNat(isSourceNat); + _ipAddressDao.update(ipId, ipAddress); + return new Pair<>(_ipAddressDao.findById(ipId), applyIpAssociations(network, false)); + }); + + ip = updatedIpAddress.first(); + success = updatedIpAddress.second(); if (success) { - s_logger.debug("Successfully associated ip address " + ip.getAddress().addr() + " to network " + network); + s_logger.debug(String.format("Successfully associated IP address [%s] to network [%s]", ip.getAddress().addr(), network)); } else { - s_logger.warn("Failed to associate ip address " + ip.getAddress().addr() + " to network " + network); + s_logger.warn(String.format("Failed to associate IP address [%s] to network [%s]", ip.getAddress().addr(), network)); } - return _ipAddressDao.findById(ipId); + return ip; } catch (Exception e) { - s_logger.error(String.format("Failed to associate ip address %s to network %s", ipToAssoc, network), e); - throw new CloudRuntimeException(String.format("Failed to associate ip address %s to network %s", ipToAssoc, network), e); + String errorMessage = String.format("Failed to associate IP address [%s] to network [%s]", ipToAssoc, network); + s_logger.error(errorMessage, e); + throw new CloudRuntimeException(errorMessage, e); } finally { if (!success && releaseOnFailure) { if (ip != null) { diff --git a/server/src/main/java/com/cloud/network/NetworkServiceImpl.java b/server/src/main/java/com/cloud/network/NetworkServiceImpl.java index bdb928ae919d..ddef3d406acc 100644 --- a/server/src/main/java/com/cloud/network/NetworkServiceImpl.java +++ b/server/src/main/java/com/cloud/network/NetworkServiceImpl.java @@ -1635,10 +1635,19 @@ public Network createGuestNetwork(CreateNetworkCmd cmd) throws InsufficientCapac throwInvalidIdException("Network offering with specified id doesn't support adding multiple ip ranges", ntwkOff.getUuid(), NETWORK_OFFERING_ID); } - if (GuestType.Shared == ntwkOff.getGuestType() && !ntwkOff.isSpecifyVlan() && Objects.isNull(associatedNetworkId)) { - throw new CloudRuntimeException("Associated network must be provided when creating Shared networks when specifyVlan is false"); - } + + if (GuestType.Shared == ntwkOff.getGuestType()) { + if (!ntwkOff.isSpecifyIpRanges()) { + throw new CloudRuntimeException("The 'specifyipranges' parameter should be true for Shared Networks"); + } + if (ipv4 && Objects.isNull(startIP)) { + throw new CloudRuntimeException("IPv4 address range needs to be provided"); + } + if (ipv6) { + s_logger.info(String.format("ip range for network '%s' is specified as %s - %s", name, startIPv6, endIPv6)); + } + } Pair interfaceMTUs = validateMtuConfig(publicMtu, privateMtu, zone.getId()); mtuCheckForVpcNetwork(vpcId, interfaceMTUs, publicMtu); diff --git a/server/src/main/java/com/cloud/network/vpc/VpcManagerImpl.java b/server/src/main/java/com/cloud/network/vpc/VpcManagerImpl.java index 300d6c0109b0..4882659f1cea 100644 --- a/server/src/main/java/com/cloud/network/vpc/VpcManagerImpl.java +++ b/server/src/main/java/com/cloud/network/vpc/VpcManagerImpl.java @@ -42,7 +42,6 @@ import javax.inject.Inject; import javax.naming.ConfigurationException; -import com.cloud.resourcelimit.CheckedReservation; import org.apache.cloudstack.acl.ControlledEntity.ACLType; import org.apache.cloudstack.alert.AlertService; import org.apache.cloudstack.annotation.AnnotationService; @@ -2928,32 +2927,27 @@ public IpAddress associateIPToVpc(final long ipId, final long vpcId) throws Reso // check permissions _accountMgr.checkAccess(caller, null, false, owner, vpc); - s_logger.debug("Associating ip " + ipToAssoc + " to vpc " + vpc); + s_logger.debug(String.format("Associating IP [%s] to VPC [%s]", ipToAssoc, vpc)); final boolean isSourceNatFinal = isSrcNatIpRequired(vpc.getVpcOfferingId()) && getExistingSourceNatInVpc(vpc.getAccountId(), vpcId) == null; - try (CheckedReservation publicIpReservation = new CheckedReservation(owner, ResourceType.public_ip, 1l, reservationDao, _resourceLimitMgr)) { - Transaction.execute(new TransactionCallbackNoReturn() { - @Override - public void doInTransactionWithoutResult(final TransactionStatus status) { + try { + IPAddressVO updatedIpAddress = Transaction.execute((TransactionCallbackWithException) status -> { final IPAddressVO ip = _ipAddressDao.findById(ipId); - // update ip address with networkId ip.setVpcId(vpcId); ip.setSourceNat(isSourceNatFinal); - _ipAddressDao.update(ipId, ip); - - // mark ip as allocated _ipAddrMgr.markPublicIpAsAllocated(ip); - } + return _ipAddressDao.findById(ipId); }); + + s_logger.debug(String.format("Successfully assigned IP [%s] to VPC [%s]", ipToAssoc, vpc)); + CallContext.current().putContextParameter(IpAddress.class, ipToAssoc.getUuid()); + return updatedIpAddress; } catch (Exception e) { - s_logger.error("Failed to associate ip " + ipToAssoc + " to vpc " + vpc, e); - throw new CloudRuntimeException("Failed to associate ip " + ipToAssoc + " to vpc " + vpc, e); + String errorMessage = String.format("Failed to associate IP address [%s] to VPC [%s]", ipToAssoc, vpc); + s_logger.error(errorMessage, e); + throw new CloudRuntimeException(errorMessage, e); } - - s_logger.debug("Successfully assigned ip " + ipToAssoc + " to vpc " + vpc); - CallContext.current().putContextParameter(IpAddress.class, ipToAssoc.getUuid()); - return _ipAddressDao.findById(ipId); } @Override diff --git a/server/src/main/java/com/cloud/template/HypervisorTemplateAdapter.java b/server/src/main/java/com/cloud/template/HypervisorTemplateAdapter.java index 0090b35fb217..47a8f0a54683 100644 --- a/server/src/main/java/com/cloud/template/HypervisorTemplateAdapter.java +++ b/server/src/main/java/com/cloud/template/HypervisorTemplateAdapter.java @@ -295,7 +295,7 @@ public VMTemplateVO create(TemplateProfile profile) { } /** - * For each zone ID in {@link TemplateProfile#zoneIdList}, verifies if there is active heuristic rules for allocating template and returns the + * For each zone ID in {@link TemplateProfile#getZoneIdList()}, verifies if there is active heuristic rules for allocating template and returns the * {@link DataStore} returned by the heuristic rule. If there is not an active heuristic rule, then allocate it to a random {@link DataStore}, if the ISO/template is private * or allocate it to all {@link DataStore} in the zone, if it is public. * @param profile @@ -456,10 +456,10 @@ public List doInTransaction(TransactionStatus /** * If the template/ISO is marked as private, then it is allocated to a random secondary storage; otherwise, allocates to every storage pool in every zone given by the - * {@link TemplateProfile#zoneIdList}. + * {@link TemplateProfile#getZoneIdList()}. */ private void postUploadAllocation(List imageStores, VMTemplateVO template, List payloads) { - Set zoneSet = new HashSet(); + Set zoneSet = new HashSet<>(); Collections.shuffle(imageStores); for (DataStore imageStore : imageStores) { Long zoneId_is = imageStore.getScope().getScopeId(); @@ -702,8 +702,8 @@ public boolean delete(TemplateProfile profile) { } // delete all cache entries for this template - List cacheTmpls = imageFactory.listTemplateOnCache(template.getId()); - for (TemplateInfo tmplOnCache : cacheTmpls) { + List cachedTemplates = imageFactory.listTemplateOnCache(template.getId()); + for (TemplateInfo tmplOnCache : cachedTemplates) { s_logger.info("Delete template: " + tmplOnCache.getId() + " from image cache store: " + tmplOnCache.getDataStore().getName()); tmplOnCache.delete(); } @@ -732,27 +732,32 @@ public boolean delete(TemplateProfile profile) { } // remove its related ACL permission - Pair, Long> tmplt = new Pair, Long>(VirtualMachineTemplate.class, template.getId()); - _messageBus.publish(_name, EntityManager.MESSAGE_REMOVE_ENTITY_EVENT, PublishScope.LOCAL, tmplt); - - checkAndRemoveTemplateDetails(template); - - // Remove comments (if any) - AnnotationService.EntityType entityType = template.getFormat().equals(ImageFormat.ISO) ? - AnnotationService.EntityType.ISO : AnnotationService.EntityType.TEMPLATE; - annotationDao.removeByEntityType(entityType.name(), template.getUuid()); + Pair, Long> templateClassForId = new Pair<>(VirtualMachineTemplate.class, template.getId()); + _messageBus.publish(_name, EntityManager.MESSAGE_REMOVE_ENTITY_EVENT, PublishScope.LOCAL, templateClassForId); + List zoneRegistrations = templateZoneDao.listByTemplateId(template.getId()); + if (zoneRegistrations.isEmpty()) { + removeTemplateDetails(template); + removeTemplateAnnotations(template); + } } return success; } + private void removeTemplateAnnotations(VMTemplateVO template) { + // Remove comments (if any) + AnnotationService.EntityType entityType = template.getFormat().equals(ImageFormat.ISO) ? + AnnotationService.EntityType.ISO : AnnotationService.EntityType.TEMPLATE; + annotationDao.removeByEntityType(entityType.name(), template.getUuid()); + } + /** * removes details of the template and * if the template is registered as deploy as is, * then it also deletes the details related to deploy as is only if there are no VMs using the template * @param template */ - void checkAndRemoveTemplateDetails(VMTemplateVO template) { + private void removeTemplateDetails(VMTemplateVO template) { templateDetailsDao.removeDetails(template.getId()); if (template.isDeployAsIs()) { diff --git a/server/src/main/java/com/cloud/user/AccountManagerImpl.java b/server/src/main/java/com/cloud/user/AccountManagerImpl.java index 8e06c5768818..4e3a2e98564d 100644 --- a/server/src/main/java/com/cloud/user/AccountManagerImpl.java +++ b/server/src/main/java/com/cloud/user/AccountManagerImpl.java @@ -372,6 +372,14 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M "totp", "The default user two factor authentication provider. Eg. totp, staticpin", true, ConfigKey.Scope.Domain); + static ConfigKey userAllowMultipleAccounts = new ConfigKey<>("Advanced", + Boolean.class, + "user.allow.multiple.accounts", + "false", + "Determines if the same username can be added to more than one account in the same domain (SAML-only).", + true, + ConfigKey.Scope.Domain); + protected AccountManagerImpl() { super(); } @@ -1252,8 +1260,8 @@ public UserAccount createUserAccount(final String userName, final String passwor // Check permissions checkAccess(getCurrentCallingAccount(), domain); - if (!_userAccountDao.validateUsernameInDomain(userName, domainId)) { - throw new InvalidParameterValueException("The user " + userName + " already exists in domain " + domainId); + if (!userAllowMultipleAccounts.valueInDomain(domainId) && !_userAccountDao.validateUsernameInDomain(userName, domainId)) { + throw new CloudRuntimeException("The user " + userName + " already exists in domain " + domainId); } if (networkDomain != null && networkDomain.length() > 0) { @@ -1436,9 +1444,16 @@ public UserVO createUser(String userName, String password, String firstName, Str throw new PermissionDeniedException("Account id : " + account.getId() + " is a system account, can't add a user to it"); } - if (!_userAccountDao.validateUsernameInDomain(userName, domainId)) { + if (!userAllowMultipleAccounts.valueInDomain(domainId) && !_userAccountDao.validateUsernameInDomain(userName, domainId)) { throw new CloudRuntimeException("The user " + userName + " already exists in domain " + domainId); } + + List duplicatedUsers = _userDao.findUsersByName(userName); + for (UserVO duplicatedUser : duplicatedUsers) { + // users can't exist in same account + assertUserNotAlreadyInAccount(duplicatedUser, account); + } + UserVO user = null; user = createUser(account.getId(), userName, password, firstName, lastName, email, timeZone, userUUID, source); return user; @@ -1564,7 +1579,7 @@ protected void validateCurrentPassword(UserVO user, String currentPassword) { *
  • The username must be unique in each domain. Therefore, if there is already another user with the same username, an {@link InvalidParameterValueException} is thrown. * */ - protected void validateAndUpdateUsernameIfNeeded(UpdateUserCmd updateUserCmd, UserVO user, Account account) { + protected void validateAndUpdateUsernameIfNeeded(UpdateUserCmd updateUserCmd, UserVO newUser, Account newAccount) { String userName = updateUserCmd.getUsername(); if (userName == null) { return; @@ -1572,18 +1587,21 @@ protected void validateAndUpdateUsernameIfNeeded(UpdateUserCmd updateUserCmd, Us if (StringUtils.isBlank(userName)) { throw new InvalidParameterValueException("Username cannot be empty."); } - List duplicatedUsers = _userDao.findUsersByName(userName); - for (UserVO duplicatedUser : duplicatedUsers) { - if (duplicatedUser.getId() == user.getId()) { + List existingUsers = _userDao.findUsersByName(userName); + for (UserVO existingUser : existingUsers) { + if (existingUser.getId() == newUser.getId()) { continue; } - Account duplicatedUserAccountWithUserThatHasTheSameUserName = _accountDao.findById(duplicatedUser.getAccountId()); - if (duplicatedUserAccountWithUserThatHasTheSameUserName.getDomainId() == account.getDomainId()) { - DomainVO domain = _domainDao.findById(duplicatedUserAccountWithUserThatHasTheSameUserName.getDomainId()); - throw new InvalidParameterValueException(String.format("Username [%s] already exists in domain [id=%s,name=%s]", duplicatedUser.getUsername(), domain.getUuid(), domain.getName())); + + // duplicate usernames cannot exist in same domain unless explicitly configured + if (!userAllowMultipleAccounts.valueInDomain(newAccount.getDomainId())) { + assertUserNotAlreadyInDomain(existingUser, newAccount); } + + // can't rename a username to an existing one in the same account + assertUserNotAlreadyInAccount(existingUser, newAccount); } - user.setUsername(userName); + newUser.setUsername(userName); } /** @@ -1820,7 +1838,7 @@ public UserAccount lockUser(long userId) { // make sure the account is enabled too // if the user is either locked already or disabled already, don't change state...only lock currently enabled -// users + // users boolean success = true; if (user.getState().equals(State.LOCKED)) { // already locked...no-op @@ -3317,7 +3335,8 @@ public String getConfigComponentName() { @Override public ConfigKey[] getConfigKeys() { return new ConfigKey[] {UseSecretKeyInResponse, enableUserTwoFactorAuthentication, - userTwoFactorAuthenticationDefaultProvider, mandateUserTwoFactorAuthentication, userTwoFactorAuthenticationIssuer}; + userTwoFactorAuthenticationDefaultProvider, mandateUserTwoFactorAuthentication, userTwoFactorAuthenticationIssuer, + userAllowMultipleAccounts}; } public List getUserTwoFactorAuthenticationProviders() { @@ -3502,4 +3521,21 @@ public UserAccount clearUserTwoFactorAuthenticationInSetupStateOnLogin(UserAccou return userAccountVO; }); } + + void assertUserNotAlreadyInAccount(User existingUser, Account newAccount) { + System.out.println(existingUser.getAccountId()); + System.out.println(newAccount.getId()); + if (existingUser.getAccountId() == newAccount.getId()) { + AccountVO existingAccount = _accountDao.findById(newAccount.getId()); + throw new InvalidParameterValueException(String.format("Username [%s] already exists in account [id=%s,name=%s]", existingUser.getUsername(), existingAccount.getUuid(), existingAccount.getAccountName())); + } + } + + void assertUserNotAlreadyInDomain(User existingUser, Account originalAccount) { + Account existingAccount = _accountDao.findById(existingUser.getAccountId()); + if (existingAccount.getDomainId() == originalAccount.getDomainId()) { + DomainVO existingDomain = _domainDao.findById(existingAccount.getDomainId()); + throw new InvalidParameterValueException(String.format("Username [%s] already exists in domain [id=%s,name=%s] user account [id=%s,name=%s]", existingUser.getUsername(), existingDomain.getUuid(), existingDomain.getName(), existingAccount.getUuid(), existingAccount.getAccountName())); + } + } } diff --git a/server/src/test/java/com/cloud/user/AccountManagerImplTest.java b/server/src/test/java/com/cloud/user/AccountManagerImplTest.java index e68de194f019..f1cf00086764 100644 --- a/server/src/test/java/com/cloud/user/AccountManagerImplTest.java +++ b/server/src/test/java/com/cloud/user/AccountManagerImplTest.java @@ -1270,4 +1270,75 @@ public void testClearUser2FA_When2FAInSetupState_Disable2FA() { Assert.assertNull(updatedUser.getUser2faProvider()); Assert.assertNull(updatedUser.getKeyFor2fa()); } + + @Test(expected = InvalidParameterValueException.class) + public void testAssertUserNotAlreadyInAccount_UserExistsInAccount() { + User existingUser = new UserVO(); + existingUser.setUsername("testuser"); + existingUser.setAccountId(1L); + + Account newAccount = Mockito.mock(Account.class); + Mockito.when(newAccount.getId()).thenReturn(1L); + + AccountVO existingAccount = Mockito.mock(AccountVO.class); + Mockito.when(existingAccount.getUuid()).thenReturn("existing-account-uuid"); + Mockito.when(existingAccount.getAccountName()).thenReturn("existing-account"); + + Mockito.when(_accountDao.findById(1L)).thenReturn(existingAccount); + + accountManagerImpl.assertUserNotAlreadyInAccount(existingUser, newAccount); + } + + @Test + public void testAssertUserNotAlreadyInAccount_UserExistsInDiffAccount() { + User existingUser = new UserVO(); + existingUser.setUsername("testuser"); + existingUser.setAccountId(2L); + + Account newAccount = Mockito.mock(Account.class); + Mockito.when(newAccount.getId()).thenReturn(1L); + + accountManagerImpl.assertUserNotAlreadyInAccount(existingUser, newAccount); + } + + @Test(expected = InvalidParameterValueException.class) + public void testAssertUserNotAlreadyInDomain_UserExistsInDomain() { + User existingUser = new UserVO(); + existingUser.setUsername("testuser"); + existingUser.setAccountId(1L); + + Account originalAccount = Mockito.mock(Account.class); + Mockito.when(originalAccount.getDomainId()).thenReturn(1L); + + AccountVO existingAccount = Mockito.mock(AccountVO.class); + Mockito.when(existingAccount.getDomainId()).thenReturn(1L); + Mockito.when(existingAccount.getUuid()).thenReturn("existing-account-uuid"); + Mockito.when(existingAccount.getAccountName()).thenReturn("existing-account"); + + DomainVO existingDomain = Mockito.mock(DomainVO.class); + Mockito.when(existingDomain.getUuid()).thenReturn("existing-domain-uuid"); + Mockito.when(existingDomain.getName()).thenReturn("existing-domain"); + + Mockito.when(_accountDao.findById(1L)).thenReturn(existingAccount); + Mockito.when(_domainDao.findById(1L)).thenReturn(existingDomain); + + accountManagerImpl.assertUserNotAlreadyInDomain(existingUser, originalAccount); + } + + @Test + public void testAssertUserNotAlreadyInDomain_UserExistsInDiffDomain() { + User existingUser = new UserVO(); + existingUser.setUsername("testuser"); + existingUser.setAccountId(1L); + + Account originalAccount = Mockito.mock(Account.class); + Mockito.when(originalAccount.getDomainId()).thenReturn(1L); + + AccountVO existingAccount = Mockito.mock(AccountVO.class); + Mockito.when(existingAccount.getDomainId()).thenReturn(2L); + + Mockito.when(_accountDao.findById(1L)).thenReturn(existingAccount); + + accountManagerImpl.assertUserNotAlreadyInDomain(existingUser, originalAccount); + } } diff --git a/systemvm/debian/opt/cloud/bin/cs/CsDhcp.py b/systemvm/debian/opt/cloud/bin/cs/CsDhcp.py index 385cc49a90f8..f9212db2abeb 100755 --- a/systemvm/debian/opt/cloud/bin/cs/CsDhcp.py +++ b/systemvm/debian/opt/cloud/bin/cs/CsDhcp.py @@ -82,7 +82,7 @@ def process(self): CsHelper.service("dnsmasq", "reload") def configure_server(self): - # self.conf.addeq("dhcp-hostsfile=%s" % DHCP_HOSTS) + self.conf.add("bind-interfaces", 0) idx = 0 listen_address = ["127.0.0.1"] for i in self.devinfo: diff --git a/test/integration/smoke/test_certauthority_root.py b/test/integration/smoke/test_certauthority_root.py index f20314ad4c5c..dc6420d6369f 100644 --- a/test/integration/smoke/test_certauthority_root.py +++ b/test/integration/smoke/test_certauthority_root.py @@ -24,13 +24,7 @@ from cryptography import x509 from cryptography.hazmat.backends import default_backend from cryptography.hazmat.primitives import serialization -from OpenSSL.crypto import FILETYPE_PEM, verify, X509 - -PUBKEY_VERIFY=True -try: - from OpenSSL.crypto import load_publickey -except ImportError: - PUBKEY_VERIFY=False +from cryptography.hazmat.primitives.asymmetric import padding class TestCARootProvider(cloudstackTestCase): @@ -52,6 +46,20 @@ def tearDownClass(cls): raise Exception("Warning: Exception during cleanup : %s" % e) + def verifySignature(self, caCert, cert): + print("Verifying Certificate") + caPublicKey = caCert.public_key() + try: + caPublicKey.verify( + cert.signature, + cert.tbs_certificate_bytes, + padding.PKCS1v15(), + cert.signature_hash_algorithm, + ) + print("Certificate is valid!") + except Exception as e: + print(f"Certificate verification failed: {e}") + def setUp(self): self.apiclient = self.testClient.getApiClient() self.dbclient = self.testClient.getDbConnection() @@ -136,13 +144,8 @@ def test_issue_certificate_without_csr(self): self.assertTrue(address in [str(x) for x in altNames.value.get_values_for_type(x509.IPAddress)]) # Validate certificate against CA public key - global PUBKEY_VERIFY - if not PUBKEY_VERIFY: - return caCert = x509.load_pem_x509_certificate(self.getCaCertificate().encode(), default_backend()) - x = X509() - x.set_pubkey(load_publickey(FILETYPE_PEM, caCert.public_key().public_bytes(serialization.Encoding.PEM, serialization.PublicFormat.SubjectPublicKeyInfo))) - verify(x, cert.signature, cert.tbs_certificate_bytes, cert.signature_hash_algorithm.name) + self.verifySignature(caCert, cert) @attr(tags=['advanced', 'simulator', 'basic', 'sg'], required_hardware=False) @@ -165,13 +168,8 @@ def test_issue_certificate_with_csr(self): self.assertEqual(cert.subject.get_attributes_for_oid(x509.oid.NameOID.COMMON_NAME)[0].value, 'v-1-VM') # Validate certificate against CA public key - global PUBKEY_VERIFY - if not PUBKEY_VERIFY: - return caCert = x509.load_pem_x509_certificate(self.getCaCertificate().encode(), default_backend()) - x = X509() - x.set_pubkey(load_publickey(FILETYPE_PEM, caCert.public_key().public_bytes(serialization.Encoding.PEM, serialization.PublicFormat.SubjectPublicKeyInfo))) - verify(x, cert.signature, cert.tbs_certificate_bytes, cert.signature_hash_algorithm.name) + self.verifySignature(caCert, cert) @attr(tags=['advanced', 'simulator', 'basic', 'sg'], required_hardware=False) diff --git a/test/integration/smoke/test_dynamicroles.py b/test/integration/smoke/test_dynamicroles.py index 39f995a14a3b..b91ba9c2eba8 100644 --- a/test/integration/smoke/test_dynamicroles.py +++ b/test/integration/smoke/test_dynamicroles.py @@ -73,7 +73,6 @@ def __init__(self): "listApis": "allow", "listAccounts": "allow", "listClusters": "deny", - "*VmwareDc*": "allow", "*VM*": "allow", "*Host*": "deny" } diff --git a/ui/public/locales/en.json b/ui/public/locales/en.json index ea2ab491fb5b..18df4d2a7bf8 100644 --- a/ui/public/locales/en.json +++ b/ui/public/locales/en.json @@ -2672,6 +2672,7 @@ "message.confirm.remove.vmware.datacenter": "Please confirm you want to remove VMware datacenter.", "message.confirm.remove.vpc.offering": "Are you sure you want to remove this VPC offering?", "message.confirm.replace.acl.new.one": "Do you want to replace the ACL with a new one?", +"message.confirm.reset.configuration.value": "Are you sure you want reset configuration - %x?", "message.confirm.reset.network.permissions": "Are you sure you want to reset this Network permissions?", "message.confirm.scale.up.router.vm": "Do you really want to scale up the router Instance?", "message.confirm.scale.up.system.vm": "Do you really want to scale up the system VM?", diff --git a/ui/src/components/header/SamlDomainSwitcher.vue b/ui/src/components/header/SamlDomainSwitcher.vue index 1d820dcbcffd..082bab7bf13c 100644 --- a/ui/src/components/header/SamlDomainSwitcher.vue +++ b/ui/src/components/header/SamlDomainSwitcher.vue @@ -88,6 +88,7 @@ export default { this.showSwitcher = false return } + this.samlAccounts = samlAccounts this.samlAccounts = _.orderBy(samlAccounts, ['domainPath'], ['asc']) const currentAccount = this.samlAccounts.filter(x => { return x.userId === store.getters.userInfo.id @@ -109,6 +110,8 @@ export default { this.$message.success(`Switched to "${account.accountName} (${account.domainPath})"`) this.$router.go() }) + }).else(error => { + console.log('error refreshing with new user context: ' + error) }) } } diff --git a/ui/src/components/view/InfoCard.vue b/ui/src/components/view/InfoCard.vue index d805f7b2719a..00cb4748a88c 100644 --- a/ui/src/components/view/InfoCard.vue +++ b/ui/src/components/view/InfoCard.vue @@ -629,7 +629,7 @@ {{ resource.podname || resource.pod || resource.podid }} -
    +
    {{ $t('label.zone') }}
    @@ -700,7 +700,7 @@ {{ resource.managementserver || resource.managementserverid }}
    -
    +
    {{ $t('label.created') }}
    {{ $toLocaleDate(resource.created) }} diff --git a/ui/src/components/view/ListView.vue b/ui/src/components/view/ListView.vue index 8f4e58e93c73..8a685830f4a4 100644 --- a/ui/src/components/view/ListView.vue +++ b/ui/src/components/view/ListView.vue @@ -459,7 +459,7 @@ iconTwoToneColor="#52c41a" /> diff --git a/ui/src/components/view/ResourceLimitTab.vue b/ui/src/components/view/ResourceLimitTab.vue index 875d2cc3b402..2717a43eb070 100644 --- a/ui/src/components/view/ResourceLimitTab.vue +++ b/ui/src/components/view/ResourceLimitTab.vue @@ -27,7 +27,7 @@ >
    diff --git a/ui/src/main.js b/ui/src/main.js index 2f1d892fbd86..253801b34a2e 100644 --- a/ui/src/main.js +++ b/ui/src/main.js @@ -35,7 +35,8 @@ import { resourceTypePlugin, fileSizeUtilPlugin, genericUtilPlugin, - localesPlugin + localesPlugin, + dialogUtilPlugin } from './utils/plugins' import { VueAxios } from './utils/request' import directives from './utils/directives' @@ -51,6 +52,7 @@ vueApp.use(resourceTypePlugin) vueApp.use(fileSizeUtilPlugin) vueApp.use(localesPlugin) vueApp.use(genericUtilPlugin) +vueApp.use(dialogUtilPlugin) vueApp.use(extensions) vueApp.use(directives) diff --git a/ui/src/store/modules/user.js b/ui/src/store/modules/user.js index 46a1905619f9..c0a45259a536 100644 --- a/ui/src/store/modules/user.js +++ b/ui/src/store/modules/user.js @@ -290,7 +290,7 @@ const user = { commit('SET_CUSTOM_COLUMNS', cachedCustomColumns) // Ensuring we get the user info so that store.getters.user is never empty when the page is freshly loaded - api('listUsers', { username: Cookies.get('username'), listall: true }).then(response => { + api('listUsers', { id: Cookies.get('userid'), listall: true }).then(response => { const result = response.listusersresponse.user[0] commit('SET_INFO', result) commit('SET_NAME', result.firstname + ' ' + result.lastname) @@ -331,7 +331,7 @@ const user = { }) } - api('listUsers', { username: Cookies.get('username') }).then(response => { + api('listUsers', { id: Cookies.get('userid') }).then(response => { const result = response.listusersresponse.user[0] commit('SET_INFO', result) commit('SET_NAME', result.firstname + ' ' + result.lastname) diff --git a/ui/src/utils/plugins.js b/ui/src/utils/plugins.js index 6beda22a8da5..7f2b2cc7f491 100644 --- a/ui/src/utils/plugins.js +++ b/ui/src/utils/plugins.js @@ -18,7 +18,7 @@ import _ from 'lodash' import { i18n } from '@/locales' import { api } from '@/api' -import { message, notification } from 'ant-design-vue' +import { message, notification, Modal } from 'ant-design-vue' import eventBus from '@/config/eventBus' import store from '@/store' import { sourceToken } from '@/utils/request' @@ -527,3 +527,18 @@ export function createPathBasedOnVmType (vmtype, virtualmachineid) { return path + virtualmachineid } + +export const dialogUtilPlugin = { + install (app) { + app.config.globalProperties.$resetConfigurationValueConfirm = function (configRecord, callback) { + Modal.confirm({ + title: i18n.global.t('label.reset.config.value'), + content: `${i18n.global.t('message.confirm.reset.configuration.value').replace('%x', configRecord.name)}`, + okText: i18n.global.t('label.yes'), + cancelText: i18n.global.t('label.no'), + okType: 'primary', + onOk: () => callback(configRecord) + }) + } + } +} diff --git a/ui/src/views/dashboard/UsageDashboard.vue b/ui/src/views/dashboard/UsageDashboard.vue index 9df3b38c6a9a..5069968a4191 100644 --- a/ui/src/views/dashboard/UsageDashboard.vue +++ b/ui/src/views/dashboard/UsageDashboard.vue @@ -460,9 +460,13 @@ export default { }, listProject () { this.loading = true - api('listProjects', { id: store.getters.project.id }).then(json => { + const params = { + id: store.getters.project.id, + listall: true + } + api('listProjects', params).then(json => { this.loading = false - if (json && json.listprojectsresponse && json.listprojectsresponse.project) { + if (json?.listprojectsresponse?.project) { this.project = json.listprojectsresponse.project[0] } }) diff --git a/ui/src/views/image/IsoZones.vue b/ui/src/views/image/IsoZones.vue index daf1e7e21e0f..75eac8fd97f5 100644 --- a/ui/src/views/image/IsoZones.vue +++ b/ui/src/views/image/IsoZones.vue @@ -48,6 +48,9 @@ {{ $t('label.yes') }} {{ $t('label.no') }} + +