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
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
9 changes: 6 additions & 3 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,13 +179,15 @@ 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()));
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();
Expand All @@ -199,7 +202,7 @@ public void fail(ErrorCode 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 +219,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
105 changes: 105 additions & 0 deletions conf/db/upgrade/V5.5.38__schema.sql
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,108 @@ CREATE TABLE IF NOT EXISTS `zstack`.`SnmpEngineVO` (
`lastOpDate` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00' ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`uuid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- ZNS segment binding state and controller inventory

CALL ADD_COLUMN('ZnsControllerVO', 'zcfAccessKeyId', 'VARCHAR(64)', 1, NULL);
CALL ADD_COLUMN('ZnsControllerVO', 'zcfAccessKeySecret', 'TEXT', 1, NULL);

CREATE TABLE IF NOT EXISTS `zstack`.`ZnsControllerStateVO` (
`sdnControllerUuid` varchar(32) NOT NULL,
`activeScanToken` varchar(255) DEFAULT NULL,
`activeScanStartedAt` timestamp NULL DEFAULT NULL,
`previousCompleteScanToken` varchar(255) DEFAULT NULL,
`previousCompleteScanDigest` varchar(64) DEFAULT NULL,
`previousCompleteScanTotal` int DEFAULT NULL,
`migrationState` varchar(32) NOT NULL DEFAULT 'NotStarted',
`compatibilityMode` varchar(32) NOT NULL DEFAULT 'LEGACY',
`compatibilityEpoch` bigint NOT NULL DEFAULT 0,
`remoteCompatibilityEpoch` bigint DEFAULT NULL,
`capabilityDigest` varchar(64) DEFAULT NULL,
`migrationDigest` varchar(64) DEFAULT NULL,
`pendingContractEpoch` bigint DEFAULT NULL,
`pendingContractRequestDigest` varchar(64) DEFAULT NULL,
`lastSuccessfulScanDate` timestamp NULL DEFAULT NULL,
`lastErrorCode` varchar(128) DEFAULT NULL,
`lastErrorDetails` text DEFAULT NULL,
`lastOpDate` timestamp NOT NULL DEFAULT '2000-01-01 00:00:00' ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`sdnControllerUuid`),
CONSTRAINT `fkZnsControllerStateVOSdnControllerVO`
FOREIGN KEY (`sdnControllerUuid`) REFERENCES `zstack`.`SdnControllerVO` (`uuid`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

CREATE TABLE IF NOT EXISTS `zstack`.`ZnsSegmentInventoryVO` (
`uuid` varchar(32) NOT NULL,
`sdnControllerUuid` varchar(32) NOT NULL,
`znsSegmentUuid` varchar(36) NOT NULL,
`name` varchar(255) NOT NULL,
`transportZoneUuid` varchar(36) NOT NULL,
`availability` varchar(32) NOT NULL,
`reasonCode` varchar(128) DEFAULT NULL,
`lastSeenToken` varchar(36) NOT NULL,
`lastSeenDate` timestamp NOT NULL DEFAULT '2000-01-01 00:00:00',
`createDate` timestamp NOT NULL DEFAULT '2000-01-01 00:00:00',
`lastOpDate` timestamp NOT NULL DEFAULT '2000-01-01 00:00:00' ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`uuid`),
UNIQUE KEY `uk_zns_seg_inv_controller_segment` (`sdnControllerUuid`, `znsSegmentUuid`),
KEY `idx_zns_seg_inv_candidate` (`sdnControllerUuid`, `transportZoneUuid`, `availability`),
CONSTRAINT `fkZnsSegmentInventoryVOSdnControllerVO`
FOREIGN KEY (`sdnControllerUuid`) REFERENCES `zstack`.`SdnControllerVO` (`uuid`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

CREATE TABLE IF NOT EXISTS `zstack`.`ZnsSegmentRefVO` (
`uuid` varchar(32) NOT NULL,
`sdnControllerUuid` varchar(32) NOT NULL,
`znsSegmentUuid` varchar(36) DEFAULT NULL,
`zoneUuid` varchar(32) NOT NULL,
`l2NetworkUuid` varchar(32) NOT NULL,
`accountUuid` varchar(32) NOT NULL,
`l3NetworkUuid` varchar(32) DEFAULT NULL,
`znsTenantRouterUuid` varchar(36) DEFAULT NULL,
`state` varchar(32) NOT NULL,
`operationUuid` varchar(36) DEFAULT NULL,
`operationStep` varchar(32) DEFAULT NULL,
`operationDigest` varchar(64) DEFAULT NULL,
`currentConfigVersion` bigint DEFAULT NULL,
`appliedConfigVersion` bigint DEFAULT NULL,
`lastErrorCode` varchar(128) DEFAULT NULL,
`lastErrorDetails` text DEFAULT NULL,
`createDate` timestamp NOT NULL DEFAULT '2000-01-01 00:00:00',
`lastOpDate` timestamp NOT NULL DEFAULT '2000-01-01 00:00:00' ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`uuid`),
UNIQUE KEY `uk_zns_seg_ref_controller_segment`
(`sdnControllerUuid`, `znsSegmentUuid`),
UNIQUE KEY `uk_zns_seg_ref_l2` (`l2NetworkUuid`),
KEY `idx_zns_seg_ref_account` (`accountUuid`),
KEY `idx_zns_seg_ref_state` (`sdnControllerUuid`, `state`),
CONSTRAINT `fkZnsSegmentRefVOSdnControllerVO`
FOREIGN KEY (`sdnControllerUuid`) REFERENCES `zstack`.`SdnControllerVO` (`uuid`) ON DELETE CASCADE,
CONSTRAINT `chk_zns_seg_ref_segment_state`
CHECK (`znsSegmentUuid` IS NOT NULL OR `state` = 'MigrationFailed')
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

DROP TRIGGER IF EXISTS `zstack`.`trg_zns_seg_ref_validate_insert`;
DELIMITER $$
CREATE TRIGGER `zstack`.`trg_zns_seg_ref_validate_insert`
BEFORE INSERT ON `zstack`.`ZnsSegmentRefVO`
FOR EACH ROW
BEGIN
IF NEW.`znsSegmentUuid` IS NULL AND NEW.`state` <> 'MigrationFailed' THEN
SIGNAL SQLSTATE '45000'
SET MESSAGE_TEXT = 'ZnsSegmentRefVO requires znsSegmentUuid unless migration failed';
END IF;
END$$
DELIMITER ;

DROP TRIGGER IF EXISTS `zstack`.`trg_zns_seg_ref_validate_update`;
DELIMITER $$
CREATE TRIGGER `zstack`.`trg_zns_seg_ref_validate_update`
BEFORE UPDATE ON `zstack`.`ZnsSegmentRefVO`
FOR EACH ROW
BEGIN
IF NEW.`znsSegmentUuid` IS NULL AND NEW.`state` <> 'MigrationFailed' THEN
SIGNAL SQLSTATE '45000'
SET MESSAGE_TEXT = 'ZnsSegmentRefVO requires znsSegmentUuid unless migration failed';
END IF;
END$$
DELIMITER ;
4 changes: 4 additions & 0 deletions conf/serviceConfig/sdnController.xml
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@
<serviceId>query</serviceId>
</message>

<message>
<name>org.zstack.sdnController.header.APIPullSdnControllerMsg</name>
</message>

<message>
<name>org.zstack.network.hostNetworkInterface.APIQueryPhysicalSwitchMsg</name>
<serviceId>query</serviceId>
Expand Down
1 change: 1 addition & 0 deletions conf/springConfigXml/sdnController.xml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
<zstack:extension interface="org.zstack.sdnController.SdnControllerManager" />
<zstack:extension interface="org.zstack.header.network.l2.L2NetworkCreateExtensionPoint" />
<zstack:extension interface="org.zstack.header.network.l2.L2NetworkDeleteExtensionPoint" />
<zstack:extension interface="org.zstack.header.network.l2.L2DeleteConfirmExtensionPoint" />
<zstack:extension interface="org.zstack.network.securitygroup.SecurityGroupGetSdnBackendExtensionPoint"/>
<zstack:extension interface="org.zstack.header.network.l3.AfterAddIpRangeExtensionPoint"/>
<zstack:extension interface="org.zstack.header.network.l3.IpRangeDeletionExtensionPoint"/>
Expand Down
13 changes: 13 additions & 0 deletions core/src/main/java/org/zstack/core/cascade/CascadeAction.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

import org.zstack.header.exception.CloudRuntimeException;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
*/
public class CascadeAction implements Cloneable {
Expand All @@ -11,6 +14,7 @@ public class CascadeAction implements Cloneable {
private Object rootIssuerContext;
private String actionCode;
private boolean fullTraverse;
private Map<String, Object> contexts = new ConcurrentHashMap<>();

public boolean isFullTraverse() {
return fullTraverse;
Expand Down Expand Up @@ -65,6 +69,15 @@ public CascadeAction copy() {
}
}

public CascadeAction putContext(String key, Object value) {
contexts.put(key, value);
return this;
}

public <T> T getContext(String key) {
return (T) contexts.get(key);
}

public String getActionCode() {
return actionCode;
}
Expand Down
Loading