package org.zstack.network.service.userdata;
import org.springframework.beans.factory.annotation.Autowired;
import org.zstack.core.cloudbus.CloudBus;
import org.zstack.core.componentloader.PluginRegistry;
import org.zstack.core.db.DatabaseFacade;
import org.zstack.header.Component;
import org.zstack.header.core.Completion;
import org.zstack.header.core.NoErrorCompletion;
import org.zstack.header.errorcode.ErrorCode;
import org.zstack.header.exception.CloudRuntimeException;
import org.zstack.header.network.l3.L3NetworkInventory;
import org.zstack.header.network.service.NetworkServiceL3NetworkRefInventory;
import org.zstack.header.network.service.NetworkServiceProviderInventory;
import org.zstack.header.network.service.NetworkServiceProviderVO;
import org.zstack.header.network.service.NetworkServiceType;
import org.zstack.header.vm.VmInstanceSpec;
import org.zstack.network.service.AbstractNetworkServiceExtension;
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.HashMap;
import java.util.Map;
/**
* Created by frank on 10/13/2015.
*/
public class UserdataExtension extends AbstractNetworkServiceExtension implements Component {
private CLogger logger = Utils.getLogger(UserdataExtension.class);
@Autowired
private DatabaseFacade dbf;
@Autowired
private CloudBus bus;
@Autowired
private PluginRegistry pluginRgty;
private Map<String, UserdataBackend> backends = new HashMap<String, UserdataBackend>();
@Override
public boolean start() {
populateExtensions();
return true;
}
private void populateExtensions() {
for (UserdataBackend bkd : pluginRgty.getExtensionList(UserdataBackend.class)) {
UserdataBackend old = backends.get(bkd.getProviderType().toString());
if (old != null) {
throw new CloudRuntimeException(String.format("duplicated UserdataBackend[%s, %s] for type[%s]", bkd, old, old.getProviderType()));
}
backends.put(bkd.getProviderType().toString(), bkd);
}
}
@Override
public boolean stop() {
return true;
}
@Override
public NetworkServiceType getNetworkServiceType() {
return UserdataConstant.USERDATA_TYPE;
}
private NetworkServiceProviderInventory findProvider(final VmInstanceSpec spec) {
L3NetworkInventory defaultL3 = CollectionUtils.find(spec.getL3Networks(), new Function<L3NetworkInventory, L3NetworkInventory>() {
@Override
public L3NetworkInventory call(L3NetworkInventory arg) {
return arg.getUuid().equals(spec.getVmInventory().getDefaultL3NetworkUuid()) ? arg : null;
}
});
for (NetworkServiceL3NetworkRefInventory ref : defaultL3.getNetworkServices()) {
if (UserdataConstant.USERDATA_TYPE_STRING.equals(ref.getNetworkServiceType())) {
return NetworkServiceProviderInventory.valueOf(dbf.findByUuid(ref.getNetworkServiceProviderUuid(), NetworkServiceProviderVO.class));
}
}
return null;
}
private UserdataBackend getUserdataBackend(String providerType) {
UserdataBackend bkd = backends.get(providerType);
if (bkd == null) {
throw new CloudRuntimeException(String.format("cannot find UserdataBackend for provider[type:%s]", providerType));
}
return bkd;
}
@Override
public void applyNetworkService(final VmInstanceSpec servedVm, Map<String, Object> data, Completion completion) {
L3NetworkInventory defaultL3 = CollectionUtils.find(servedVm.getL3Networks(), new Function<L3NetworkInventory, L3NetworkInventory>() {
@Override
public L3NetworkInventory call(L3NetworkInventory arg) {
return arg.getUuid().equals(servedVm.getVmInventory().getDefaultL3NetworkUuid()) ? arg : null;
}
});
if (defaultL3 == null) {
// the L3 for operation is not the default L3
completion.success();
return;
}
NetworkServiceProviderInventory provider = findProvider(servedVm);
if (provider == null) {
completion.success();
return;
}
UserdataStruct struct = new UserdataStruct();
struct.setL3NetworkUuid(servedVm.getVmInventory().getDefaultL3NetworkUuid());
struct.setParametersFromVmSpec(servedVm);
struct.setUserdata(servedVm.getUserdata());
UserdataBackend bkd = getUserdataBackend(provider.getType());
bkd.applyUserdata(struct, completion);
}
@Override
public void releaseNetworkService(final VmInstanceSpec servedVm, Map<String, Object> data, final NoErrorCompletion completion) {
if (servedVm.getUserdata() == null) {
completion.done();
return;
}
L3NetworkInventory defaultL3 = CollectionUtils.find(servedVm.getL3Networks(), new Function<L3NetworkInventory, L3NetworkInventory>() {
@Override
public L3NetworkInventory call(L3NetworkInventory arg) {
return arg.getUuid().equals(servedVm.getVmInventory().getDefaultL3NetworkUuid()) ? arg : null;
}
});
if (defaultL3 == null) {
// the L3 for operation is not the default L3
completion.done();
return;
}
NetworkServiceProviderInventory provider = findProvider(servedVm);
if (provider == null) {
completion.done();
return;
}
UserdataStruct struct = new UserdataStruct();
struct.setL3NetworkUuid(servedVm.getVmInventory().getDefaultL3NetworkUuid());
struct.setParametersFromVmSpec(servedVm);
struct.setUserdata(servedVm.getUserdata());
UserdataBackend bkd = getUserdataBackend(provider.getType());
bkd.releaseUserdata(struct, new Completion(completion) {
@Override
public void success() {
completion.done();
}
@Override
public void fail(ErrorCode errorCode) {
//TODO add GC
logger.warn(String.format("unable to release user data for vm[uuid:%s], %s", servedVm.getVmInventory().getUuid(), errorCode));
completion.done();
}
});
}
}