Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -40,14 +40,15 @@ public class TagAllocatorFlow extends AbstractHostAllocatorFlow {
private List<InstanceOfferingTagAllocatorExtensionPoint> instanceOfferingExtensions;
private List<DiskOfferingTagAllocatorExtensionPoint> diskOfferingExtensions;

public TagAllocatorFlow() {
private void loadExtensions() {
instanceOfferingExtensions = pluginRgty.getExtensionList(InstanceOfferingTagAllocatorExtensionPoint.class);
diskOfferingExtensions = pluginRgty.getExtensionList(DiskOfferingTagAllocatorExtensionPoint.class);
}

@Override
public void allocate() {
throwExceptionIfIAmTheFirstFlow();
loadExtensions();

if (!instanceOfferingExtensions.isEmpty()) {
SimpleQuery<SystemTagVO> q = dbf.createQuery(SystemTagVO.class);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,14 @@
import org.zstack.header.apimediator.ApiMessageInterceptionException;
import org.zstack.header.apimediator.ApiMessageInterceptor;
import org.zstack.header.apimediator.StopRoutingException;
import org.zstack.header.cluster.ClusterVO;
import org.zstack.header.cluster.ClusterVO_;
import org.zstack.header.host.*;
import org.zstack.header.message.APIMessage;
import org.zstack.header.zone.ManagementNetworkIpVersionManager;
import org.zstack.utils.ShellResult;
import org.zstack.utils.ShellUtils;
import org.zstack.utils.network.IPv6NetworkUtils;
import org.zstack.utils.network.NetworkUtils;

import static org.zstack.core.Platform.argerr;
Expand All @@ -28,12 +32,19 @@
* To change this template use File | Settings | File Templates.
*/
public class HostApiInterceptor implements ApiMessageInterceptor {
private static final String INVALID_MANAGEMENT_IP_ERROR =
"managementIp[%s] is not a valid IPv4 address, IPv6 address, or hostname";
private static final String RESERVED_MANAGEMENT_IPV6_ERROR =
"managementIp[%s] is an IPv6 address that cannot be used as a management address";

@Autowired
private CloudBus bus;
@Autowired
private ErrorFacade errf;
@Autowired
private DatabaseFacade dbf;
@Autowired
private ManagementNetworkIpVersionManager managementNetworkIpVersionManager;

private void setServiceId(APIMessage msg) {
if (msg instanceof HostMessage) {
Expand Down Expand Up @@ -112,18 +123,70 @@ private void validate(APIDeleteHostMsg msg) {

private void validate(APIUpdateHostMsg msg) {
if (msg.getManagementIp() != null) {
msg.setManagementIp(validateManagementEndpoint(msg.getManagementIp()));

SimpleQuery<HostVO> q = dbf.createQuery(HostVO.class);
q.add(HostVO_.managementIp, Op.EQ, msg.getManagementIp());
if (q.isExists()) {
throw new ApiMessageInterceptionException(argerr(ORG_ZSTACK_COMPUTE_HOST_10112, "there has been a host having managementIp[%s]", msg.getManagementIp()));
}

String zoneUuid = Q.New(HostVO.class)
.select(HostVO_.zoneUuid)
.eq(HostVO_.uuid, msg.getUuid())
.findValue();
managementNetworkIpVersionManager.validateEndpointInZone(zoneUuid, msg.getManagementIp(),
"host", msg.getUuid(), ORG_ZSTACK_COMPUTE_HOST_10130);
}
}

private void validate(APIAddHostMsg msg) {
if (!NetworkUtils.isIpv4Address(msg.getManagementIp()) && !NetworkUtils.isHostname(msg.getManagementIp())) {
throw new ApiMessageInterceptionException(argerr(ORG_ZSTACK_COMPUTE_HOST_10113, "managementIp[%s] is neither an IPv4 address nor a valid hostname", msg.getManagementIp()));
validateManagementEndpoint(msg);
String zoneUuid = Q.New(ClusterVO.class)
.select(ClusterVO_.zoneUuid)
.eq(ClusterVO_.uuid, msg.getClusterUuid())
.findValue();
managementNetworkIpVersionManager.validateEndpointInZone(zoneUuid, msg.getManagementIp(),
"host", msg.getName(), ORG_ZSTACK_COMPUTE_HOST_10130);
}

static void validateManagementEndpoint(APIAddHostMsg msg) {
String managementIp = msg.getManagementIp();
msg.setManagementIp(validateManagementEndpoint(managementIp));
}

static String validateManagementEndpoint(String managementIp) {
if (IPv6NetworkUtils.isIpv6Address(managementIp)) {
if (!IPv6NetworkUtils.isValidManagementIpv6Address(managementIp)) {
throw new ApiMessageInterceptionException(argerr(
ORG_ZSTACK_COMPUTE_HOST_10129,
RESERVED_MANAGEMENT_IPV6_ERROR,
managementIp));
}
} else if (!isValidManagementEndpoint(managementIp)) {
throw new ApiMessageInterceptionException(argerr(
ORG_ZSTACK_COMPUTE_HOST_10128,
INVALID_MANAGEMENT_IP_ERROR,
managementIp));
}

if (IPv6NetworkUtils.isIpv6Address(managementIp)) {
return IPv6NetworkUtils.getIpv6AddressCanonicalString(managementIp);
}

return managementIp;
}

static String getManagementEndpointValidationErrorCode(String managementIp) {
if (IPv6NetworkUtils.isIpv6Address(managementIp)) {
return IPv6NetworkUtils.isValidManagementIpv6Address(managementIp) ? null : ORG_ZSTACK_COMPUTE_HOST_10129;
}

return isValidManagementEndpoint(managementIp) ? null : ORG_ZSTACK_COMPUTE_HOST_10128;
}

private static boolean isValidManagementEndpoint(String endpoint) {
return IPv6NetworkUtils.isValidManagementEndpoint(endpoint);
}

private void validate(APIChangeHostStateMsg msg){
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,8 @@ public class VmCreateOnHypervisorFlow implements Flow {
@Autowired
private EventFacade evtf;

private final List<VmBeforeCreateOnHypervisorExtensionPoint> exts = pluginRgty.getExtensionList(VmBeforeCreateOnHypervisorExtensionPoint.class);

private void fireExtensions(VmInstanceSpec spec) {
for (VmBeforeCreateOnHypervisorExtensionPoint ext : exts) {
for (VmBeforeCreateOnHypervisorExtensionPoint ext : pluginRgty.getExtensionList(VmBeforeCreateOnHypervisorExtensionPoint.class)) {
ext.beforeCreateVmOnHypervisor(spec);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,9 @@ public class VmInstantiateResourceForChangeImageFlow implements Flow {
@Autowired
private PluginRegistry pluginRgty;

private final List<ChangeVmImageExtensionPoint> extensions = pluginRgty.getExtensionList(ChangeVmImageExtensionPoint.class);

private List<ChangeVmImageExtensionPoint> getExtensions() {
return pluginRgty.getExtensionList(ChangeVmImageExtensionPoint.class);
}

private void runExtensions(final Iterator<ChangeVmImageExtensionPoint> it, final VmInstanceSpec spec, final FlowTrigger chain) {
if (!it.hasNext()) {
Expand All @@ -53,6 +54,7 @@ public void fail(ErrorCode errorCode) {
@Override
public void run(FlowTrigger chain, Map data) {
VmInstanceSpec spec = (VmInstanceSpec) data.get(VmInstanceConstant.Params.VmInstanceSpec.toString());
List<ChangeVmImageExtensionPoint> extensions = getExtensions();
for (ChangeVmImageExtensionPoint extp : extensions) {
try {
extp.preBeforeInstantiateVmResource(spec);
Expand Down Expand Up @@ -89,6 +91,6 @@ public void fail(ErrorCode errorCode) {
@Override
public void rollback(FlowRollback chain, Map data) {
VmInstanceSpec spec = (VmInstanceSpec) data.get(VmInstanceConstant.Params.VmInstanceSpec.toString());
rollbackExtensions(extensions.iterator(), spec, chain);
rollbackExtensions(getExtensions().iterator(), spec, chain);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,13 @@ public class VmInstantiateResourcePostFlow implements Flow {
@Autowired
private PluginRegistry pluginRgty;

private final List<PostVmInstantiateResourceExtensionPoint> extensions = pluginRgty.getExtensionList(PostVmInstantiateResourceExtensionPoint.class);

private List<PostVmInstantiateResourceExtensionPoint> getExtensions() {
return pluginRgty.getExtensionList(PostVmInstantiateResourceExtensionPoint.class);
}

public void run(FlowTrigger trigger, Map data) {
VmInstanceSpec spec = (VmInstanceSpec) data.get(VmInstanceConstant.Params.VmInstanceSpec.toString());
List<PostVmInstantiateResourceExtensionPoint> extensions = getExtensions();
for (PostVmInstantiateResourceExtensionPoint ext : extensions) {
ext.postBeforeInstantiateVmResource(spec);
}
Expand Down Expand Up @@ -64,7 +66,7 @@ public void fail(ErrorCode errorCode) {
@Override
public void rollback(FlowRollback trigger, Map data) {
VmInstanceSpec spec = (VmInstanceSpec) data.get(VmInstanceConstant.Params.VmInstanceSpec.toString());
rollbackExtensions(extensions.iterator(), spec, trigger);
rollbackExtensions(getExtensions().iterator(), spec, trigger);
}

private void rollbackExtensions(final Iterator<PostVmInstantiateResourceExtensionPoint> iterator, final VmInstanceSpec spec, final FlowRollback trigger) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,9 @@ public class VmInstantiateResourcePreFlow implements Flow {
@Autowired
private PluginRegistry pluginRgty;

private final List<PreVmInstantiateResourceExtensionPoint> extensions = pluginRgty.getExtensionList(PreVmInstantiateResourceExtensionPoint.class);

private List<PreVmInstantiateResourceExtensionPoint> getExtensions() {
return pluginRgty.getExtensionList(PreVmInstantiateResourceExtensionPoint.class);
}

private void runExtensions(final Iterator<PreVmInstantiateResourceExtensionPoint> it, final VmInstanceSpec spec, final FlowTrigger chain) {
if (!it.hasNext()) {
Expand Down Expand Up @@ -61,6 +62,7 @@ public void fail(ErrorCode errorCode) {
@Override
public void run(FlowTrigger chain, Map data) {
VmInstanceSpec spec = (VmInstanceSpec) data.get(VmInstanceConstant.Params.VmInstanceSpec.toString());
List<PreVmInstantiateResourceExtensionPoint> extensions = getExtensions();
for (PreVmInstantiateResourceExtensionPoint extp : extensions) {
try {
extp.preBeforeInstantiateVmResource(spec);
Expand Down Expand Up @@ -97,6 +99,6 @@ public void fail(ErrorCode errorCode) {
@Override
public void rollback(FlowRollback chain, Map data) {
VmInstanceSpec spec = (VmInstanceSpec) data.get(VmInstanceConstant.Params.VmInstanceSpec.toString());
rollbackExtensions(extensions.iterator(), spec, chain);
rollbackExtensions(getExtensions().iterator(), spec, chain);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,10 @@ public class VmReleaseResourceFlow implements Flow {

@Autowired
private PluginRegistry pluginRgty;

private final List<VmReleaseResourceExtensionPoint> extensions = pluginRgty.getExtensionList(VmReleaseResourceExtensionPoint.class);

private List<VmReleaseResourceExtensionPoint> getExtensions() {
return pluginRgty.getExtensionList(VmReleaseResourceExtensionPoint.class);
}

private void fireExtensions(final Iterator<VmReleaseResourceExtensionPoint> it, final VmInstanceSpec spec, final Map<String, Object> ctx, final FlowTrigger chain) {
if (!it.hasNext()) {
Expand All @@ -53,7 +54,7 @@ public void fail(ErrorCode errorCode) {
@Override
public void run(FlowTrigger chain, Map data) {
VmInstanceSpec spec = (VmInstanceSpec) data.get(VmInstanceConstant.Params.VmInstanceSpec.toString());
fireExtensions(extensions.iterator(), spec, data, chain);
fireExtensions(getExtensions().iterator(), spec, data, chain);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
package org.zstack.compute.zone;

import org.springframework.beans.factory.annotation.Autowired;
import org.zstack.core.componentloader.PluginRegistry;
import org.zstack.core.db.DatabaseFacade;
import org.zstack.core.db.Q;
import org.zstack.header.apimediator.ApiMessageInterceptionException;
import org.zstack.header.host.HostVO;
import org.zstack.header.host.HostVO_;
import org.zstack.header.tag.SystemTagInventory;
import org.zstack.header.zone.ManagementNetworkIpVersionManager;
import org.zstack.header.zone.ManagementNetworkIpVersionResourceExtensionPoint;
import org.zstack.header.zone.ZoneVO;
import org.zstack.utils.network.ManagementNetworkIpVersionUtils;

import java.util.List;
import java.util.Map;

import static org.zstack.core.Platform.argerr;
import static org.zstack.utils.clouderrorcode.CloudOperationsErrorCode.ORG_ZSTACK_COMPUTE_ZONE_10004;
import static org.zstack.utils.clouderrorcode.CloudOperationsErrorCode.ORG_ZSTACK_COMPUTE_ZONE_10005;
import static org.zstack.utils.clouderrorcode.CloudOperationsErrorCode.ORG_ZSTACK_COMPUTE_ZONE_10006;
import static org.zstack.utils.clouderrorcode.CloudOperationsErrorCode.ORG_ZSTACK_COMPUTE_ZONE_10007;

public class ManagementNetworkIpVersionManagerImpl implements ManagementNetworkIpVersionManager {
private static final String DEFAULT_ZONE_IP_VERSION = ManagementNetworkIpVersionUtils.IPV4;
private static final String HOST_RESOURCE_TYPE = "host";
private static final String MISMATCH_ERROR =
"%s[%s] uses %s endpoint[%s], but zone[uuid:%s] management network ipVersion is %s";

@Autowired
private DatabaseFacade dbf;
@Autowired
private PluginRegistry pluginRgty;

@Override
public void validateEndpointInZone(String zoneUuid, String endpoint, String resourceType, String resourceIdentity, String errorCode) {
if (zoneUuid == null || endpoint == null) {
return;
}

validateEndpointMatchesIpVersion(zoneUuid, getZoneIpVersion(zoneUuid), endpoint, resourceType, resourceIdentity, errorCode);
}

@Override
public void validateEndpointMatchesIpVersion(String zoneUuid, String ipVersion, String endpoint,
String resourceType, String resourceIdentity, String errorCode) {
if (zoneUuid == null || ipVersion == null || endpoint == null) {
return;
}

if (ManagementNetworkIpVersionUtils.isIpv6LinkLocalEndpoint(endpoint)) {
throw new ApiMessageInterceptionException(argerr(
ORG_ZSTACK_COMPUTE_ZONE_10007,
"%s[%s] uses IPv6 link-local endpoint[%s], which is not supported for zone[uuid:%s] management network",
resourceType, resourceIdentity, endpoint, zoneUuid));
}

String endpointIpVersion = ManagementNetworkIpVersionUtils.getEndpointIpVersion(endpoint);
if (endpointIpVersion == null || endpointIpVersion.equals(ipVersion)) {
return;
}

throw new ApiMessageInterceptionException(argerr(errorCode, MISMATCH_ERROR,
resourceType, resourceIdentity, endpointIpVersion, endpoint, zoneUuid, ipVersion));
}

@Override
public String getZoneIpVersion(String zoneUuid) {
Map<String, String> tokens = ZoneSystemTags.MANAGEMENT_NETWORK_IP_VERSION.getTokensByResourceUuid(zoneUuid);
if (tokens == null) {
return DEFAULT_ZONE_IP_VERSION;
}

return ManagementNetworkIpVersionUtils.normalizeIpVersion(
tokens.get(ZoneSystemTags.MANAGEMENT_NETWORK_IP_VERSION_TOKEN));
}

@Override
public void validateZoneCompatibleWithExistingResources(String zoneUuid, String ipVersion) {
validateExistingHosts(zoneUuid, ipVersion);
for (ManagementNetworkIpVersionResourceExtensionPoint ext :
pluginRgty.getExtensionList(ManagementNetworkIpVersionResourceExtensionPoint.class)) {
ext.validateExistingResourcesInZone(zoneUuid, ipVersion);
}
}

public void validateZoneIpVersionTag(String resourceUuid, String systemTag) {
validateZoneIpVersionTag(resourceUuid, systemTag, null);
}

public void validateZoneIpVersionTag(String resourceUuid, String systemTag, String excludedTagUuid) {
validateZoneIpVersionTagValue(resourceUuid, systemTag);
validateZoneHasNoOtherIpVersionTag(resourceUuid, excludedTagUuid);
}

public void validateZoneIpVersionTagValue(String resourceUuid, String systemTag) {
if (!ZoneSystemTags.MANAGEMENT_NETWORK_IP_VERSION.isMatch(systemTag)) {
return;
}

if (!dbf.isExist(resourceUuid, ZoneVO.class)) {
return;
}

String ipVersion = ZoneSystemTags.MANAGEMENT_NETWORK_IP_VERSION.getTokenByTag(
systemTag,
ZoneSystemTags.MANAGEMENT_NETWORK_IP_VERSION_TOKEN);
String normalizedIpVersion = ManagementNetworkIpVersionUtils.normalizeIpVersion(ipVersion);
if (normalizedIpVersion == null) {
throw new ApiMessageInterceptionException(argerr(
ORG_ZSTACK_COMPUTE_ZONE_10004,
"management network ipVersion[%s] is invalid, allowed values are [%s, %s]",
ipVersion,
ManagementNetworkIpVersionUtils.IPV4,
ManagementNetworkIpVersionUtils.IPV6));
}

validateZoneCompatibleWithExistingResources(resourceUuid, normalizedIpVersion);
}

private void validateZoneHasNoOtherIpVersionTag(String zoneUuid, String excludedTagUuid) {
for (SystemTagInventory tag : ZoneSystemTags.MANAGEMENT_NETWORK_IP_VERSION.getTagInventories(zoneUuid)) {
if (excludedTagUuid != null && excludedTagUuid.equals(tag.getUuid())) {
continue;
}

throw new ApiMessageInterceptionException(argerr(
ORG_ZSTACK_COMPUTE_ZONE_10006,
"zone[uuid:%s] already has management network ipVersion system tag[%s], update or delete it before creating another one",
zoneUuid, tag.getTag()));
}
}

private void validateExistingHosts(String zoneUuid, String ipVersion) {
List<HostVO> hosts = Q.New(HostVO.class)
.eq(HostVO_.zoneUuid, zoneUuid)
.list();

for (HostVO host : hosts) {
validateEndpointMatchesIpVersion(zoneUuid, ipVersion, host.getManagementIp(),
HOST_RESOURCE_TYPE, host.getUuid(), ORG_ZSTACK_COMPUTE_ZONE_10005);
}
}
}
Loading