package io.fathom.cloud.compute.services; import io.fathom.cloud.CloudException; import io.fathom.cloud.compute.state.ComputeRepository; import io.fathom.cloud.protobuf.CloudModel.InstanceData; import io.fathom.cloud.protobuf.CloudModel.MetadataData; import io.fathom.cloud.protobuf.CloudModel.MetadataEntryData; import io.fathom.cloud.server.model.Project; import java.util.Map; import java.util.Map.Entry; import javax.inject.Inject; import javax.inject.Singleton; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.common.collect.Maps; import com.google.inject.persist.Transactional; @Transactional @Singleton public class MetadataServices { private static final Logger log = LoggerFactory.getLogger(MetadataServices.class); @Inject ComputeRepository computeRepository; @Inject ComputeDerivedMetadata magicMetadata; InstanceData findInstance(Project project, long instanceId) throws CloudException { return computeRepository.getInstances(project.getId()).find(instanceId); } public InstanceData replaceMetadata(Project project, long instanceId, Map<String, String> model, boolean replaceAll) throws CloudException { InstanceData instance = findInstance(project, instanceId); if (instance == null) { throw new IllegalArgumentException("Instance not found: " + instanceId); } InstanceData.Builder b = InstanceData.newBuilder(instance); if (replaceAll) { b.clearMetadata(); MetadataData.Builder mb = b.getMetadataBuilder(); for (Entry<String, String> entry : model.entrySet()) { MetadataEntryData.Builder eb = mb.addEntryBuilder(); eb.setKey(entry.getKey()); eb.setValue(entry.getValue()); } } else { MetadataData.Builder mb = b.getMetadataBuilder(); for (Entry<String, String> entry : model.entrySet()) { if (!setMetadataKey(mb, entry.getKey(), entry.getValue())) { throw new IllegalArgumentException(); } } } InstanceData updated = computeRepository.getInstances(project.getId()).update(b); magicMetadata.instanceUpdated(project, updated); return updated; } public static Map<String, String> toMap(MetadataData metadata) { Map<String, String> model = Maps.newHashMap(); if (metadata != null) { for (MetadataEntryData entry : metadata.getEntryList()) { String key = entry.getKey(); String value = entry.getValue(); model.put(key, value); } } return model; } public InstanceData replaceMetadataKey(Project project, long instanceId, String key, String value) throws CloudException { InstanceData instance = findInstance(project, instanceId); if (instance == null) { throw new IllegalArgumentException(); } InstanceData.Builder b = InstanceData.newBuilder(instance); MetadataData.Builder mb = b.getMetadataBuilder(); if (!setMetadataKey(mb, key, value)) { log.warn("Could not replace metadata key: {}={}. Metadata={}", key, value, mb.build()); throw new IllegalArgumentException(); } InstanceData updated = computeRepository.getInstances(project.getId()).update(b); magicMetadata.instanceUpdated(project, updated); return updated; } private boolean setMetadataKey(io.fathom.cloud.protobuf.CloudModel.MetadataData.Builder mb, String key, String value) { boolean found = false; for (int i = 0; i < mb.getEntryCount(); i++) { MetadataEntryData.Builder eb = mb.getEntryBuilder(i); if (key.equals(eb.getKey())) { found = true; if (value == null) { mb.removeEntry(i); } else { eb.setValue(value); } break; } } if (!found) { if (value == null) { return false; } else { MetadataEntryData.Builder eb = mb.addEntryBuilder(); eb.setKey(key); eb.setValue(value); } } return true; } }