diff --git a/compute/src/main/java/org/zstack/compute/host/HostApiInterceptor.java b/compute/src/main/java/org/zstack/compute/host/HostApiInterceptor.java index d75989d896e..ea8f10e87a8 100755 --- a/compute/src/main/java/org/zstack/compute/host/HostApiInterceptor.java +++ b/compute/src/main/java/org/zstack/compute/host/HostApiInterceptor.java @@ -22,6 +22,13 @@ import org.zstack.utils.ShellResult; import org.zstack.utils.ShellUtils; import org.zstack.utils.network.NetworkUtils; +import org.zstack.header.storage.primary.PrimaryStorageClusterRefVO; +import org.zstack.header.storage.primary.PrimaryStorageClusterRefVO_; +import org.zstack.header.storage.primary.PrimaryStorageConstants; +import org.zstack.header.storage.primary.PrimaryStorageVO; +import org.zstack.header.storage.primary.PrimaryStorageVO_; + +import java.util.List; import static org.zstack.core.Platform.argerr; import static org.zstack.core.Platform.operr; @@ -152,6 +159,10 @@ private void validate(APIGetPhysicalMachineBlockDevicesMsg msg) { } private void validate(APIMountBlockDeviceMsg msg) { + validatePath(msg.getPath()); + validateMountPoint(msg.getMountPoint()); + validateMountPointNotOccupiedByLocalStorage(msg); + if (msg.getPassword() != null) { return; } @@ -162,9 +173,6 @@ private void validate(APIMountBlockDeviceMsg msg) { } msg.setPassword(proxyHardware.getPassword()); msg.setUsername(msg.getUsername() != null ? msg.getUsername() : proxyHardware.getUsername()); - - validatePath(msg.getPath()); - validateMountPoint(msg.getMountPoint()); } private void validate(APIUpdateHostnameMsg msg) { @@ -215,10 +223,6 @@ private void validateMountPoint(String mountPoint) { "invalid value detected: '%s'", SAFE_MOUNT_POINT_PATTERN, mountPoint)); } - if (mountPoint.endsWith("/") && !mountPoint.equals("/")) { - throw new ApiMessageInterceptionException(operr( - "mountPoint should not end with '/' except root directory")); - } } private ProxyHardware getProxyHardware(String hostname) { @@ -230,4 +234,52 @@ private ProxyHardware getProxyHardware(String hostname) { } return null; } + + private String getClusterUuid(String hostname) { + for (ProxyHardwareFactory factory : pluginRgty.getExtensionList(ProxyHardwareFactory.class)) { + String clusterUuid = factory.getClusterUuid(hostname); + if (clusterUuid != null) { + return clusterUuid; + } + } + return null; + } + + private void validateMountPointNotOccupiedByLocalStorage(APIMountBlockDeviceMsg msg) { + String clusterUuid = getClusterUuid(msg.getHostName()); + if (clusterUuid == null) { + return; + } + + List primaryStorageUuids = Q.New(PrimaryStorageClusterRefVO.class) + .select(PrimaryStorageClusterRefVO_.primaryStorageUuid) + .eq(PrimaryStorageClusterRefVO_.clusterUuid, clusterUuid) + .listValues(); + if (primaryStorageUuids.isEmpty()) { + return; + } + + String mountPoint = normalizeMountPoint(msg.getMountPoint()); + List localStorageUrls = Q.New(PrimaryStorageVO.class) + .select(PrimaryStorageVO_.url) + .eq(PrimaryStorageVO_.type, PrimaryStorageConstants.LOCAL_STORAGE_TYPE) + .in(PrimaryStorageVO_.uuid, primaryStorageUuids) + .listValues(); + + for (String url : localStorageUrls) { + if (!mountPoint.equals(normalizeMountPoint(url))) { + continue; + } + throw new ApiMessageInterceptionException(argerr( + "url[%s] has been occupied by local primary storage in cluster[uuid:%s]", + msg.getMountPoint(), clusterUuid)); + } + } + + private static String normalizeMountPoint(String path) { + while (path.length() > 1 && path.endsWith("/")) { + path = path.substring(0, path.length() - 1); + } + return path; + } } diff --git a/header/src/main/java/org/zstack/header/agent/ProxyHardwareFactory.java b/header/src/main/java/org/zstack/header/agent/ProxyHardwareFactory.java index 505b497946b..1597ff5cd77 100644 --- a/header/src/main/java/org/zstack/header/agent/ProxyHardwareFactory.java +++ b/header/src/main/java/org/zstack/header/agent/ProxyHardwareFactory.java @@ -2,4 +2,8 @@ public interface ProxyHardwareFactory { ProxyHardware getProxyHardware(String hostName); + + default String getClusterUuid(String hostName) { + return null; + } } diff --git a/plugin/kvm/src/main/java/org/zstack/kvm/KVMHostFactory.java b/plugin/kvm/src/main/java/org/zstack/kvm/KVMHostFactory.java index 4be7abd072e..ff844974397 100644 --- a/plugin/kvm/src/main/java/org/zstack/kvm/KVMHostFactory.java +++ b/plugin/kvm/src/main/java/org/zstack/kvm/KVMHostFactory.java @@ -1232,4 +1232,12 @@ public ProxyHardware getProxyHardware(String hostName) { "and host.managementIp = :hostname"; return SQL.New(sql, KVMHostVO.class).param("hostname", hostName).find(); } + + @Override + public String getClusterUuid(String hostName) { + return Q.New(HostVO.class) + .select(HostVO_.clusterUuid) + .eq(HostVO_.managementIp, hostName) + .findValue(); + } }