Skip to content
Closed
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
81 changes: 70 additions & 11 deletions compute/src/main/java/org/zstack/compute/vm/VmAllocateNicFlow.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import org.zstack.core.componentloader.PluginRegistry;
import org.zstack.core.db.DatabaseFacade;
import org.zstack.core.db.SQLBatch;
import org.zstack.core.db.SQLBatchWithReturn;
import org.zstack.core.errorcode.ErrorFacade;
import org.zstack.header.core.Completion;
import org.zstack.header.core.WhileDoneCompletion;
Expand All @@ -18,9 +19,11 @@
import org.zstack.header.core.workflow.FlowTrigger;
import org.zstack.header.errorcode.ErrorCode;
import org.zstack.header.errorcode.ErrorCodeList;
import org.zstack.header.errorcode.OperationFailureException;
import org.zstack.header.image.ImagePlatform;
import org.zstack.header.message.APIMessage;
import org.zstack.header.network.l3.*;
import org.zstack.header.network.NetworkDeleteGuardExtensionPoint;
import org.zstack.header.vm.*;
import org.zstack.network.l3.L3NetworkManager;
import org.zstack.resourceconfig.ResourceConfig;
Expand Down Expand Up @@ -94,7 +97,6 @@ public void run(final FlowTrigger trigger, final Map data) {
data.put(VmInstanceConstant.Params.VmAllocateNicFlow_nics.toString(), nics);
List<ErrorCode> errs = new ArrayList<>();
List<String> vmSystemTags = spec.getMessage() instanceof APIMessage ? ((APIMessage) spec.getMessage()).getSystemTags() : null;

new While<>(VmNicSpec.getFirstL3NetworkInventoryOfSpec(spec.getL3Networks())).each((nicSpec, wcomp) -> {
L3NetworkInventory nw = nicSpec.getL3Invs().get(0);
int deviceId = deviceIdBitmap.nextClearBit(0);
Expand Down Expand Up @@ -123,20 +125,47 @@ public void run(final FlowTrigger trigger, final Map data) {

// Persist VmNicVO first so that ResourceVO entry exists before extensions
// (e.g. SDN controllers) attempt to create SystemTags referencing the NIC UUID.
VmNicVO nicVO = vnicFactory.createVmNic(nic, spec);
VmNicVO nicVO;
try {
nicVO = new SQLBatchWithReturn<VmNicVO>() {
@Override
protected VmNicVO scripts() {
ErrorCode guardError = checkNetworkDeleteGuards(nw.getUuid(), true);
if (guardError != null) {
throw new OperationFailureException(guardError);
}
return vnicFactory.createVmNic(nic, spec);
}
}.execute();
} catch (OperationFailureException e) {
errs.add(e.getErrorCode());
wcomp.allDone();
return;
}

callBeforeAllocateVmNicExtensions(nic, spec, new Completion(wcomp) {
@Override
public void success() {
new SQLBatch() {
@Override
protected void scripts() {
persistStaticIpIfNeeded(nic, nicVO, nw, nicNetworkInfoMap, spec);
nics.add(nic);
VmNicVO updated = dbf.updateAndRefresh(nicVO);
addVmNicConfig(updated, spec, nicSpec);
}
}.execute();
try {
new SQLBatch() {
@Override
protected void scripts() {
ErrorCode guardError = checkNetworkDeleteGuards(nw.getUuid(), true);
if (guardError != null) {
throw new OperationFailureException(guardError);
}
persistStaticIpIfNeeded(nic, nicVO, nw, nicNetworkInfoMap, spec);
VmNicVO updated = dbf.updateAndRefresh(nicVO);
addVmNicConfig(updated, spec, nicSpec);
}
}.execute();
} catch (OperationFailureException e) {
dbf.removeByPrimaryKey(nicVO.getUuid(), VmNicVO.class);
errs.add(e.getErrorCode());
wcomp.allDone();
return;
}
nics.add(nic);
if (customMac != null) {
mo.deleteCustomMacSystemTag(spec.getVmInventory().getUuid(), nw.getUuid(), customMac);
}
Expand Down Expand Up @@ -263,6 +292,13 @@ private void addVmNicConfig(VmNicVO vmNicVO, VmInstanceSpec vmSpec, VmNicSpec ni

VmNicParam vmNicParm = vmNicParms.get(0);

if (vmNicParm.getInboundBandwidth() != null || vmNicParm.getOutboundBandwidth() != null) {
ErrorCode qosError = validateVmNicQos(vmNicVO.getL3NetworkUuid());
if (qosError != null) {
throw new OperationFailureException(qosError);
}
}

// add vmnic bandwidth systemtag
if (vmNicParm.getInboundBandwidth() != null || vmNicParm.getOutboundBandwidth() != null) {
VmNicQosConfigBackend backend = vmMgr.getVmNicQosConfigBackend(vmSpec.getVmInventory().getType());
Expand All @@ -277,6 +313,29 @@ private void addVmNicConfig(VmNicVO vmNicVO, VmInstanceSpec vmSpec, VmNicSpec ni
}
}

private ErrorCode checkNetworkDeleteGuards(String l3NetworkUuid, boolean lock) {
for (NetworkDeleteGuardExtensionPoint extension :
pluginRgty.getExtensionList(NetworkDeleteGuardExtensionPoint.class)) {
ErrorCode errorCode = lock ? extension.checkL3NetworkWithLock(l3NetworkUuid)
: extension.checkL3Network(l3NetworkUuid);
if (errorCode != null) {
return errorCode;
}
}
return null;
}

private ErrorCode validateVmNicQos(String l3NetworkUuid) {
for (VmNicQosConfigExtensionPoint extension :
pluginRgty.getExtensionList(VmNicQosConfigExtensionPoint.class)) {
ErrorCode errorCode = extension.validateVmNicQos(l3NetworkUuid);
if (errorCode != null) {
return errorCode;
}
}
return null;
}

private void callBeforeAllocateVmNicExtensions(VmNicInventory nic, VmInstanceSpec spec, Completion completion) {
List<BeforeAllocateVmNicExtensionPoint> exts = pluginRgty.getExtensionList(BeforeAllocateVmNicExtensionPoint.class);
if (exts.isEmpty()) {
Expand Down
41 changes: 37 additions & 4 deletions compute/src/main/java/org/zstack/compute/zone/ZoneBase.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Configurable;
import org.zstack.core.cascade.CascadeConstant;
import org.zstack.core.cascade.CascadeAction;
import org.zstack.core.cascade.CascadeFacade;
import org.zstack.core.cloudbus.CloudBus;
import org.zstack.core.db.DatabaseFacade;
Expand Down Expand Up @@ -178,28 +179,60 @@ protected void handle(APIDeleteZoneMsg msg) {
final String issuer = ZoneVO.class.getSimpleName();
ZoneInventory zinv = ZoneInventory.valueOf(self);
final List<ZoneInventory> ctx = Arrays.asList(zinv);
final CascadeAction cascadeAction = new CascadeAction().setRootIssuer(issuer)
.setRootIssuerContext(ctx).setParentIssuer(issuer).setParentIssuerContext(ctx);
FlowChain chain = FlowChainBuilder.newSimpleFlowChain();
chain.setName(String.format("delete-zone-%s", msg.getUuid()));
chain.then(new NoRollbackFlow() {
@Override
public void run(FlowTrigger trigger, Map data) {
cascadeAction.setActionCode(msg.getDeletionMode() == APIDeleteMessage.DeletionMode.Enforcing
? CascadeConstant.DELETION_FORCE_DELETE_CODE
: CascadeConstant.DELETION_CHECK_CODE);
extpEmitter.prepareCascadeDelete(zinv, cascadeAction, new Completion(trigger) {
@Override
public void success() {
trigger.next();
}

@Override
public void fail(ErrorCode errorCode) {
trigger.fail(errorCode);
}
});
}
});
if (msg.getDeletionMode() == APIDeleteMessage.DeletionMode.Permissive) {
chain.then(new NoRollbackFlow() {
@Override
public void run(final FlowTrigger trigger, Map data) {
casf.asyncCascade(CascadeConstant.DELETION_CHECK_CODE, issuer, ctx, new Completion(trigger) {
casf.asyncCascade(cascadeAction.setActionCode(CascadeConstant.DELETION_CHECK_CODE), new Completion(trigger) {
@Override
public void success() {
trigger.next();
}

@Override
public void fail(ErrorCode errorCode) {
trigger.fail(errorCode);
extpEmitter.cancelCascadeDelete(zinv, cascadeAction,
new Completion(trigger) {
@Override
public void success() {
trigger.fail(errorCode);
}

@Override
public void fail(ErrorCode cancelError) {
trigger.fail(errorCode);
}
});
}
});
}
}).then(new NoRollbackFlow() {
@Override
public void run(final FlowTrigger trigger, Map data) {
casf.asyncCascade(CascadeConstant.DELETION_DELETE_CODE, issuer, ctx, new Completion(trigger) {
casf.asyncCascade(cascadeAction.setActionCode(CascadeConstant.DELETION_DELETE_CODE), new Completion(trigger) {
@Override
public void success() {
trigger.next();
Expand All @@ -216,7 +249,7 @@ public void fail(ErrorCode errorCode) {
chain.then(new NoRollbackFlow() {
@Override
public void run(final FlowTrigger trigger, Map data) {
casf.asyncCascade(CascadeConstant.DELETION_FORCE_DELETE_CODE, issuer, ctx, new Completion(trigger) {
casf.asyncCascade(cascadeAction.setActionCode(CascadeConstant.DELETION_FORCE_DELETE_CODE), new Completion(trigger) {
@Override
public void success() {
trigger.next();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,24 +1,36 @@
package org.zstack.compute.zone;

import org.springframework.beans.factory.annotation.Autowired;
import org.zstack.core.asyncbatch.While;
import org.zstack.core.cascade.CascadeAction;
import org.zstack.core.cascade.BeforeZoneCascadeDeleteExtensionPoint;
import org.zstack.core.componentloader.PluginExtension;
import org.zstack.core.componentloader.PluginRegistry;
import org.zstack.core.errorcode.ErrorFacade;
import org.zstack.header.Component;
import org.zstack.header.core.Completion;
import org.zstack.header.core.WhileDoneCompletion;
import org.zstack.header.errorcode.ErrorCode;
import org.zstack.header.errorcode.ErrorCodeList;
import org.zstack.header.zone.*;
import org.zstack.utils.CollectionUtils;
import org.zstack.utils.Utils;
import org.zstack.utils.function.ForEachFunction;
import org.zstack.utils.logging.CLogger;

import java.util.ArrayList;
import java.util.List;

class ZoneExtensionPointEmitter implements Component {
private static final CLogger logger = Utils.getLogger(ZoneExtensionPointEmitter.class);

@Autowired
private PluginRegistry pluginRgty;
@Autowired
private ErrorFacade errf;

private List<ZoneDeleteExtensionPoint> delExts;
private List<BeforeZoneCascadeDeleteExtensionPoint> cascadeDelExts;
private List<ZoneChangeStateExtensionPoint> changeExts;

void preDelete(ZoneInventory zinv) throws ZoneException {
Expand Down Expand Up @@ -52,6 +64,79 @@ public void run(ZoneDeleteExtensionPoint arg) {
}
});
}

void prepareCascadeDelete(ZoneInventory inventory, CascadeAction action, Completion completion) {
List<BeforeZoneCascadeDeleteExtensionPoint> prepared = new ArrayList<>();
new While<>(cascadeDelExts).each((extension, whileCompletion) -> {
try {
extension.beforeDelete(inventory, action, new Completion(whileCompletion) {
@Override
public void success() {
prepared.add(extension);
whileCompletion.done();
}

@Override
public void fail(ErrorCode errorCode) {
whileCompletion.addError(errorCode);
whileCompletion.allDone();
}
});
} catch (RuntimeException e) {
whileCompletion.addError(errf.throwableToInternalError(e));
whileCompletion.allDone();
}
}).run(new WhileDoneCompletion(completion) {
@Override
public void done(ErrorCodeList errors) {
if (errors.getCauses().isEmpty()) {
completion.success();
return;
}
cancelCascadeDelete(inventory, action, prepared, errors.getCauses().get(0), completion);
}
});
}

void cancelCascadeDelete(ZoneInventory inventory, CascadeAction action, Completion completion) {
cancelCascadeDelete(inventory, action, cascadeDelExts, null, completion);
}

private void cancelCascadeDelete(ZoneInventory inventory, CascadeAction action,
List<BeforeZoneCascadeDeleteExtensionPoint> extensions,
ErrorCode originalError,
Completion completion) {
new While<>(extensions).each((extension, whileCompletion) -> {
try {
extension.cancel(inventory, action, new Completion(whileCompletion) {
@Override
public void success() {
whileCompletion.done();
}

@Override
public void fail(ErrorCode errorCode) {
whileCompletion.addError(errorCode);
whileCompletion.allDone();
}
});
} catch (RuntimeException e) {
whileCompletion.addError(errf.throwableToInternalError(e));
whileCompletion.allDone();
}
}).run(new WhileDoneCompletion(completion) {
@Override
public void done(ErrorCodeList errors) {
if (originalError != null) {
completion.fail(originalError);
} else if (errors.getCauses().isEmpty()) {
completion.success();
} else {
completion.fail(errors.getCauses().get(0));
}
}
});
}

void preChange(ZoneVO vo, ZoneStateEvent event) throws ZoneException {
ZoneInventory zinv = ZoneInventory.valueOf(vo);
Expand Down Expand Up @@ -99,6 +184,7 @@ public boolean start() {

private void populateExtensions() {
delExts = pluginRgty.getExtensionList(ZoneDeleteExtensionPoint.class);
cascadeDelExts = pluginRgty.getExtensionList(BeforeZoneCascadeDeleteExtensionPoint.class);
changeExts = pluginRgty.getExtensionList(ZoneChangeStateExtensionPoint.class);
}

Expand Down
Loading