package io.cattle.platform.process.instance; import static io.cattle.platform.core.model.tables.CredentialInstanceMapTable.*; import static io.cattle.platform.core.model.tables.NicTable.*; import static io.cattle.platform.core.model.tables.VolumeTable.*; import io.cattle.iaas.labels.service.LabelsService; import io.cattle.platform.core.constants.CommonStatesConstants; import io.cattle.platform.core.constants.InstanceConstants; import io.cattle.platform.core.dao.GenericResourceDao; import io.cattle.platform.core.dao.LabelsDao; import io.cattle.platform.core.model.CredentialInstanceMap; import io.cattle.platform.core.model.Instance; import io.cattle.platform.core.model.Nic; import io.cattle.platform.core.model.Volume; import io.cattle.platform.engine.handler.HandlerResult; import io.cattle.platform.engine.process.ProcessInstance; import io.cattle.platform.engine.process.ProcessState; import io.cattle.platform.json.JsonMapper; import io.cattle.platform.object.process.ObjectProcessManager; import io.cattle.platform.object.process.StandardProcess; import io.cattle.platform.object.util.DataAccessor; import io.cattle.platform.object.util.DataUtils; import io.cattle.platform.process.base.AbstractDefaultProcessHandler; import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.TreeSet; import javax.inject.Inject; import javax.inject.Named; @Named public class InstanceCreate extends AbstractDefaultProcessHandler { @Inject LabelsService labelsService; @Inject GenericResourceDao resourceDao; @Inject JsonMapper jsonMapper; @Inject ObjectProcessManager processManager; @Inject LabelsDao labelsDao; @Override public HandlerResult handle(ProcessState state, ProcessInstance process) { setCreateStart(state); Instance instance = (Instance) state.getResource(); List<Volume> volumes = objectManager.children(instance, Volume.class); List<String> dataVolumes = processManagedVolumes(instance); List<Nic> nics = objectManager.children(instance, Nic.class); Set<Long> creds = createCreds(instance, state.getData()); Set<Long> volumesIds = createVolumes(instance, volumes, state.getData()); Set<Long> nicIds = createNics(instance, nics, state.getData()); HandlerResult result = new HandlerResult("_volumeIds", volumesIds, "_nicIds", nicIds, "_creds", creds, InstanceConstants.FIELD_DATA_VOLUMES, dataVolumes); result.shouldDelegate(shouldStart(instance)); createLabels(instance); return result; } private List<String> processManagedVolumes(Instance instance) { List<String> dataVolumes = DataAccessor.fieldStringList(instance, InstanceConstants.FIELD_DATA_VOLUMES); if (dataVolumes == null) { dataVolumes = new ArrayList<String>(); } Map<String, Object> dataVolumeMounts = DataAccessor.fieldMap(instance, InstanceConstants.FIELD_DATA_VOLUME_MOUNTS); if (dataVolumeMounts == null) { return dataVolumes; } for (Map.Entry<String, Object> mountedVols : dataVolumeMounts.entrySet()) { Long volId = ((Number) mountedVols.getValue()).longValue(); Volume vol = objectManager.loadResource(Volume.class, volId); if (vol != null) { String volDescriptor = vol.getName() + ":" + mountedVols.getKey().trim(); if (!dataVolumes.contains(volDescriptor)) { dataVolumes.add(volDescriptor); } } } return dataVolumes; } protected boolean shouldStart(Instance instance) { return DataAccessor.fields(instance) .withKey(InstanceConstants.FIELD_START_ON_CREATE) .withDefault(true) .as(Boolean.class); } private void createLabels(Instance instance) { @SuppressWarnings("unchecked") Map<String, String> labels = DataAccessor.fields(instance).withKey(InstanceConstants.FIELD_LABELS).as(Map.class); if (labels == null) { return; } for (Map.Entry<String, String> labelEntry : labels.entrySet()) { String labelKey = labelEntry.getKey(); String labelValue = labelEntry.getValue(); labelsService.createContainerLabel(instance.getAccountId(), instance.getId(), labelKey, labelValue); } } protected Set<Long> createVolumes(Instance instance, List<Volume> volumes, Map<String, Object> data) { Set<Long> volumeIds = new TreeSet<Long>(); Volume root = createRoot(instance, volumes, data); if (root != null) { volumeIds.add(root.getId()); } return volumeIds; } protected Volume createRoot(Instance instance, List<Volume> volumes, Map<String, Object> data) { Volume root = getRoot(instance, volumes); if (root == null) { return null; } processManager.executeStandardProcess(StandardProcess.CREATE, root, data); return root; } protected Volume getRoot(Instance instance, List<Volume> volumes) { if (instance.getImageId() == null) { return null; } for (Volume volume : volumes) { if (volume.getDeviceNumber() != null && volume.getDeviceNumber().intValue() == 0) { return volume; } } return objectManager.create(Volume.class, VOLUME.ACCOUNT_ID, instance.getAccountId(), VOLUME.INSTANCE_ID, instance.getId(), VOLUME.IMAGE_ID, instance .getImageId(), VOLUME.DEVICE_NUMBER, 0, VOLUME.ATTACHED_STATE, CommonStatesConstants.ACTIVE); } protected Set<Long> createNics(Instance instance, List<Nic> nics, Map<String, Object> data) { List<Long> networkIds = populateNetworks(instance); return createNicsFromIds(instance, nics, data, networkIds); } protected List<Long> populateNetworks(Instance instance) { return DataUtils.getFieldList(instance.getData(), InstanceConstants.FIELD_NETWORK_IDS, Long.class); } protected Set<Long> createNicsFromIds(Instance instance, List<Nic> nics, Map<String, Object> data, List<Long> networkIds) { Set<Long> nicIds = new TreeSet<Long>(); int deviceId = 0; if (networkIds != null) { for (int i = 0; i < networkIds.size(); i++) { Number createId = networkIds.get(i); if (createId == null) { deviceId++; continue; } Nic newNic = null; for (Nic nic : nics) { if (nic.getNetworkId() == createId.longValue()) { newNic = nic; break; } } if (newNic == null) { newNic = objectManager.create(Nic.class, NIC.ACCOUNT_ID, instance.getAccountId(), NIC.NETWORK_ID, createId, NIC.INSTANCE_ID, instance .getId(), NIC.DEVICE_NUMBER, deviceId); } deviceId++; processManager.executeStandardProcess(StandardProcess.CREATE, newNic, data); nicIds.add(newNic.getId()); } } return nicIds; } protected Set<Long> createCreds(Instance instance, Map<String, Object> data) { List<Long> credIds = DataUtils.getFieldList(instance.getData(), InstanceConstants.FIELD_CREDENTIAL_IDS, Long.class); return createCredsFromIds(credIds, instance, data); } protected Set<Long> createCredsFromIds(List<Long> credIds, Instance instance, Map<String, Object> data) { if (credIds == null) { return Collections.emptySet(); } Set<Long> created = new HashSet<Long>(); List<CredentialInstanceMap> maps = new ArrayList<CredentialInstanceMap>(); for (CredentialInstanceMap map : children(instance, CredentialInstanceMap.class)) { maps.add(map); created.add(map.getCredentialId()); } for (Long credId : credIds) { if (!created.contains(credId)) { maps.add(objectManager.create(CredentialInstanceMap.class, CREDENTIAL_INSTANCE_MAP.INSTANCE_ID, instance.getId(), CREDENTIAL_INSTANCE_MAP.CREDENTIAL_ID, credId)); } } for (CredentialInstanceMap map : maps) { createThenActivate(map, data); } return new TreeSet<Long>(credIds); } public static boolean isCreateStart(ProcessState state) { Boolean startOnCreate = DataAccessor.fromMap(state.getData()).withScope(InstanceCreate.class).withKey(InstanceConstants.FIELD_START_ON_CREATE).as( Boolean.class); return startOnCreate == null ? false : startOnCreate; } protected void setCreateStart(ProcessState state) { DataAccessor.fromMap(state.getData()).withScope(InstanceCreate.class).withKey(InstanceConstants.FIELD_START_ON_CREATE).set(true); } }