package org.zstack.network.l2.vxlan.vtep;
import org.springframework.beans.factory.annotation.Autowired;
import org.zstack.core.asyncbatch.While;
import org.zstack.core.cascade.AbstractAsyncCascadeExtension;
import org.zstack.core.cascade.CascadeAction;
import org.zstack.core.cascade.CascadeConstant;
import org.zstack.core.cloudbus.CloudBus;
import org.zstack.core.cloudbus.CloudBusCallBack;
import org.zstack.core.db.DatabaseFacade;
import org.zstack.core.db.Q;
import org.zstack.core.errorcode.ErrorFacade;
import org.zstack.header.core.Completion;
import org.zstack.header.core.NoErrorCompletion;
import org.zstack.header.message.MessageReply;
import org.zstack.header.network.l2.*;
import org.zstack.utils.CollectionUtils;
import org.zstack.utils.Utils;
import org.zstack.utils.function.Function;
import org.zstack.utils.logging.CLogger;
import java.util.*;
/**
* Created by weiwang on 12/05/2017.
*/
public class VtepCascadeExtension extends AbstractAsyncCascadeExtension {
private static final CLogger logger = Utils.getLogger(VtepCascadeExtension.class);
@Override
public void asyncCascade(CascadeAction action, Completion completion) {
if (action.isActionCode(CascadeConstant.DELETION_DELETE_CODE, CascadeConstant.DELETION_FORCE_DELETE_CODE)) {
handleDeletion(action, completion);
} else if (action.isActionCode(CascadeConstant.DELETION_CLEANUP_CODE)) {
handleDeletionCleanup(action, completion);
} else if (action.isActionCode(L2NetworkConstant.DETACH_L2NETWORK_CODE)) {
handleDetach(action, completion);
} else {
completion.success();
}
}
@Autowired
private DatabaseFacade dbf;
@Autowired
private CloudBus bus;
@Autowired
private ErrorFacade errf;
private static final String NAME = VtepVO.class.getSimpleName();
@Override
public List<String> getEdgeNames() {
return Arrays.asList(L2NetworkVO.class.getSimpleName());
}
@Override
public String getCascadeResourceName() {
return NAME;
}
private void handleDetach(CascadeAction action, final Completion completion) {
List<L2NetworkDetachStruct> structs = action.getParentIssuerContext();
List<VtepVO> vteps = new ArrayList<>();
for (L2NetworkDetachStruct s : structs) {
vteps.addAll(Q.New(VtepVO.class).eq(VtepVO_.poolUuid, s.getL2NetworkUuid()).eq(VtepVO_.clusterUuid, s.getClusterUuid()).list());
}
if (vteps.isEmpty()) {
completion.success();
return;
}
new While<>(vteps).all((vtep, completion1) -> {
DeleteVtepMsg msg = new DeleteVtepMsg();
msg.setL2NetworkUuid(vtep.getPoolUuid());
msg.setVtepUuid(vtep.getUuid());
bus.makeTargetServiceIdByResourceUuid(msg, L2NetworkConstant.SERVICE_ID, msg.getL2NetworkUuid());
bus.send(msg, new CloudBusCallBack(completion1) {
@Override
public void run(MessageReply reply) {
if (!reply.isSuccess()) {
logger.warn(reply.getError().toString());
}
completion1.done();
}
});
}).run(new NoErrorCompletion(completion) {
@Override
public void done() {
completion.success();
}
});
}
private void handleDeletionCleanup(CascadeAction action, Completion completion) {
dbf.eoCleanup(VtepVO.class);
completion.success();
}
private void handleDeletion(final CascadeAction action, final Completion completion) {
List<VtepInventory> vteps = vtepFromAction(action);
new While<>(vteps).all((vtep, completion1) -> {
DeleteVtepMsg msg = new DeleteVtepMsg();
msg.setL2NetworkUuid(vtep.getPoolUuid());
msg.setVtepUuid(vtep.getUuid());
bus.makeTargetServiceIdByResourceUuid(msg, L2NetworkConstant.SERVICE_ID, msg.getL2NetworkUuid());
bus.send(msg, new CloudBusCallBack(completion1) {
@Override
public void run(MessageReply reply) {
if (!reply.isSuccess()) {
logger.warn(reply.getError().toString());
}
completion1.done();
}
});
}).run(new NoErrorCompletion(completion) {
@Override
public void done() {
completion.success();
}
});
}
private List<VtepInventory> vtepFromAction(CascadeAction action) {
List<VtepInventory> ret = null;
if (L2NetworkVO.class.getSimpleName().equals(action.getParentIssuer())) {
List<String> l2uuids = CollectionUtils.transformToList((List<L2NetworkInventory>)action.getParentIssuerContext(), new Function<String, L2NetworkInventory>() {
@Override
public String call(L2NetworkInventory arg) {
return arg.getUuid();
}
});
List<VtepVO> vos = Q.New(VtepVO.class).in(VtepVO_.poolUuid, l2uuids).list();
if (!vos.isEmpty()) {
ret = VtepInventory.valueOf(vos);
}
} else if (NAME.equals(action.getParentIssuer())) {
ret = action.getParentIssuerContext();
}
return ret;
}
@Override
public CascadeAction createActionForChildResource(CascadeAction action) {
if (CascadeConstant.DELETION_CODES.contains(action.getActionCode())) {
List<VtepInventory> ctx = vtepFromAction(action);
if (ctx != null) {
return action.copy().setParentIssuer(NAME).setParentIssuerContext(ctx);
}
}
return null;
}
}