package io.cattle.platform.servicediscovery.dao.impl; import static io.cattle.platform.core.model.tables.InstanceLinkTable.*; import static io.cattle.platform.core.model.tables.InstanceTable.*; import static io.cattle.platform.core.model.tables.ServiceConsumeMapTable.*; import static io.cattle.platform.core.model.tables.ServiceExposeMapTable.*; import static io.cattle.platform.core.model.tables.ServiceTable.*; import io.cattle.platform.core.addon.ServiceLink; import io.cattle.platform.core.constants.CommonStatesConstants; import io.cattle.platform.core.constants.ServiceConstants; import io.cattle.platform.core.model.Instance; import io.cattle.platform.core.model.InstanceLink; import io.cattle.platform.core.model.Service; import io.cattle.platform.core.model.ServiceConsumeMap; import io.cattle.platform.core.model.tables.records.InstanceLinkRecord; import io.cattle.platform.core.model.tables.records.InstanceRecord; import io.cattle.platform.core.model.tables.records.ServiceConsumeMapRecord; import io.cattle.platform.db.jooq.dao.impl.AbstractJooqDao; import io.cattle.platform.json.JsonMapper; import io.cattle.platform.lock.LockCallback; import io.cattle.platform.lock.LockManager; import io.cattle.platform.object.ObjectManager; import io.cattle.platform.object.process.ObjectProcessManager; import io.cattle.platform.servicediscovery.api.dao.ServiceConsumeMapDao; import io.cattle.platform.servicediscovery.deployment.impl.lock.ServiceLinkLock; import io.cattle.platform.util.type.CollectionUtils; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.inject.Inject; import org.jooq.Record2; import org.jooq.RecordHandler; public class ServiceConsumeMapDaoImpl extends AbstractJooqDao implements ServiceConsumeMapDao { @Inject ObjectManager objectManager; @Inject ObjectProcessManager objectProcessManager; @Inject JsonMapper jsonMapper; @Inject LockManager lockManager; @Override public ServiceConsumeMap findMapToRemove(long serviceId, long consumedServiceId) { List<ServiceConsumeMap> maps = objectManager.find(ServiceConsumeMap.class, SERVICE_CONSUME_MAP.SERVICE_ID, serviceId, SERVICE_CONSUME_MAP.CONSUMED_SERVICE_ID, consumedServiceId); for (ServiceConsumeMap map : maps) { if (map != null && (map.getRemoved() == null || map.getState().equals(CommonStatesConstants.REMOVING))) { return map; } } return null; } @Override public ServiceConsumeMap findNonRemovedMap(long serviceId, long consumedServiceId, String linkName) { ServiceConsumeMap map = null; List<? extends ServiceConsumeMap> maps = new ArrayList<>(); if (linkName == null) { maps = objectManager.find(ServiceConsumeMap.class, SERVICE_CONSUME_MAP.SERVICE_ID, serviceId, SERVICE_CONSUME_MAP.CONSUMED_SERVICE_ID, consumedServiceId, SERVICE_CONSUME_MAP.REMOVED, null); } else { maps = objectManager.find(ServiceConsumeMap.class, SERVICE_CONSUME_MAP.SERVICE_ID, serviceId, SERVICE_CONSUME_MAP.CONSUMED_SERVICE_ID, consumedServiceId, SERVICE_CONSUME_MAP.NAME, linkName, SERVICE_CONSUME_MAP.REMOVED, null); } for (ServiceConsumeMap m : maps) { if (m.getState().equalsIgnoreCase(CommonStatesConstants.REMOVING)) { continue; } map = m; } return map; } @Override public List<? extends ServiceConsumeMap> findConsumedServices(long serviceId) { return create() .selectFrom(SERVICE_CONSUME_MAP) .where( SERVICE_CONSUME_MAP.SERVICE_ID.eq(serviceId) .and(SERVICE_CONSUME_MAP.REMOVED.isNull()) .and(SERVICE_CONSUME_MAP.STATE.notIn(CommonStatesConstants.REMOVING))) .fetchInto(ServiceConsumeMapRecord.class); } @Override public List<? extends ServiceConsumeMap> findConsumedServicesForInstance(long instanceId, String kind) { return create() .select(SERVICE_CONSUME_MAP.fields()) .from(SERVICE_CONSUME_MAP) .join(SERVICE_EXPOSE_MAP) .on(SERVICE_EXPOSE_MAP.SERVICE_ID.eq(SERVICE_CONSUME_MAP.SERVICE_ID)) .join(SERVICE) .on(SERVICE.ID.eq(SERVICE_CONSUME_MAP.CONSUMED_SERVICE_ID)) .where( SERVICE_EXPOSE_MAP.INSTANCE_ID.eq(instanceId) .and(SERVICE.KIND.eq(kind)) .and(SERVICE_CONSUME_MAP.REMOVED.isNull()) //Don't include yourself .and(SERVICE_CONSUME_MAP.SERVICE_ID.ne(SERVICE_CONSUME_MAP.CONSUMED_SERVICE_ID)) .and(SERVICE_EXPOSE_MAP.REMOVED.isNull())) .fetchInto(ServiceConsumeMapRecord.class); } @Override public List<? extends InstanceLink> findServiceBasedInstanceLinks(long instanceId) { return create() .select(INSTANCE_LINK.fields()) .from(INSTANCE_LINK) .where(INSTANCE_LINK.INSTANCE_ID.eq(instanceId) .and(INSTANCE_LINK.SERVICE_CONSUME_MAP_ID.isNotNull()) .and(INSTANCE_LINK.REMOVED.isNull())) .fetchInto(InstanceLinkRecord.class); } @Override public Instance findOneInstanceForService(long serviceId) { Instance last = null; List<? extends Instance> instances = create() .select(INSTANCE.fields()) .from(INSTANCE) .join(SERVICE_EXPOSE_MAP) .on(SERVICE_EXPOSE_MAP.INSTANCE_ID.eq(INSTANCE.ID)) .where(INSTANCE.REMOVED.isNull() .and(SERVICE_EXPOSE_MAP.SERVICE_ID.eq(serviceId)) .and(SERVICE_EXPOSE_MAP.REMOVED.isNull())) .orderBy(INSTANCE.CREATED.desc()) .fetchInto(InstanceRecord.class); for (Instance instance : instances) { last = instance; if (last.getFirstRunning() != null) { return last; } } return last; } @Override public List<String> findInstanceNamesForService(long serviceId) { return create() .select(INSTANCE.NAME) .from(INSTANCE) .join(SERVICE_EXPOSE_MAP) .on(SERVICE_EXPOSE_MAP.INSTANCE_ID.eq(INSTANCE.ID)) .where(INSTANCE.REMOVED.isNull() .and(SERVICE_EXPOSE_MAP.REMOVED.isNull()) .and(SERVICE_EXPOSE_MAP.SERVICE_ID.eq(serviceId))) .orderBy(INSTANCE.NAME.asc()) .fetch(INSTANCE.NAME); } @Override public ServiceConsumeMap createServiceLink(final Service service, final ServiceLink serviceLink) { return lockManager.lock(new ServiceLinkLock(service.getId(), serviceLink.getServiceId()), new LockCallback<ServiceConsumeMap>() { @Override public ServiceConsumeMap doWithLock() { return createServiceLinkImpl(service, serviceLink); } }); } protected ServiceConsumeMap createServiceLinkImpl(Service service, ServiceLink serviceLink) { Service linkFrom = objectManager.reload(service); if (linkFrom == null || linkFrom.getRemoved() != null || linkFrom.getState().equalsIgnoreCase(CommonStatesConstants.REMOVING)) { return null; } Service linkTo = objectManager.loadResource(Service.class, serviceLink.getServiceId()); if (linkTo == null || linkTo.getRemoved() != null || linkTo.getState().equalsIgnoreCase(CommonStatesConstants.REMOVING)) { return null; } ServiceConsumeMap map = findNonRemovedMap(service.getId(), serviceLink.getServiceId(), serviceLink.getName()); if (map == null) { Map<Object,Object> properties = CollectionUtils.asMap( (Object)SERVICE_CONSUME_MAP.SERVICE_ID, service.getId(), SERVICE_CONSUME_MAP.CONSUMED_SERVICE_ID, serviceLink.getServiceId(), SERVICE_CONSUME_MAP.ACCOUNT_ID, service.getAccountId(), SERVICE_CONSUME_MAP.NAME, serviceLink.getName()); map = objectManager.create(ServiceConsumeMap.class, objectManager.convertToPropertiesFor(ServiceConsumeMap.class, properties)); } if (map.getState().equalsIgnoreCase(CommonStatesConstants.REQUESTED)) { objectProcessManager.scheduleProcessInstance(ServiceConstants.PROCESS_SERVICE_CONSUME_MAP_CREATE, map, null); } return map; } @Override public List<ServiceConsumeMap> createServiceLinks(List<ServiceLink> serviceLinks) { List<ServiceConsumeMap> result = new ArrayList<>(); for (ServiceLink serviceLink : serviceLinks) { Service service = objectManager.loadResource(Service.class, serviceLink.getConsumingServiceId()); if (service == null) { continue; } ServiceConsumeMap created = createServiceLink(service, serviceLink); if (created != null) { result.add(created); } } return result; } @Override public List<? extends ServiceConsumeMap> findConsumedMapsToRemove(long serviceId) { return create() .selectFrom(SERVICE_CONSUME_MAP) .where( SERVICE_CONSUME_MAP.SERVICE_ID.eq(serviceId) .and((SERVICE_CONSUME_MAP.REMOVED.isNull(). or(SERVICE_CONSUME_MAP.STATE.eq(CommonStatesConstants.REMOVING))))). fetchInto(ServiceConsumeMapRecord.class); } @Override public List<? extends ServiceConsumeMap> findConsumingServices(long serviceId) { return create() .selectFrom(SERVICE_CONSUME_MAP) .where( SERVICE_CONSUME_MAP.CONSUMED_SERVICE_ID.eq(serviceId) .and(SERVICE_CONSUME_MAP.REMOVED.isNull())).fetchInto(ServiceConsumeMapRecord.class); } @Override public List<? extends ServiceConsumeMap> findConsumingMapsToRemove(long serviceId) { return create() .selectFrom(SERVICE_CONSUME_MAP) .where( SERVICE_CONSUME_MAP.CONSUMED_SERVICE_ID.eq(serviceId) .and((SERVICE_CONSUME_MAP.REMOVED.isNull(). or(SERVICE_CONSUME_MAP.STATE.eq(CommonStatesConstants.REMOVING))))). fetchInto(ServiceConsumeMapRecord.class); } @Override public List<? extends Service> findLinkedServices(long serviceId) { return create() .select(SERVICE.fields()) .from(SERVICE) .join(SERVICE_CONSUME_MAP) .on(SERVICE_CONSUME_MAP.CONSUMED_SERVICE_ID.eq(SERVICE.ID)) .where( SERVICE_CONSUME_MAP.SERVICE_ID.eq(serviceId) .and(SERVICE_CONSUME_MAP.REMOVED.isNull())).fetchInto(Service.class); } @Override public Map<Long, Long> findConsumedServicesIdsToStackIdsFromOtherAccounts(long accountId) { final Map<Long, Long> result = new HashMap<>(); create().select(SERVICE.ID, SERVICE.STACK_ID) .from(SERVICE) .join(SERVICE_CONSUME_MAP) .on(SERVICE_CONSUME_MAP.CONSUMED_SERVICE_ID.eq(SERVICE.ID)) .where(SERVICE_CONSUME_MAP.ACCOUNT_ID.eq(accountId) .and(SERVICE_CONSUME_MAP.REMOVED.isNull()) .and(SERVICE.REMOVED.isNull()) .and(SERVICE.ACCOUNT_ID.ne(accountId))) .fetchInto(new RecordHandler<Record2<Long, Long>>() { @Override public void next(Record2<Long, Long> record) { Long serviceId = record.getValue(SERVICE.ID); Long stackId = record.getValue(SERVICE.STACK_ID); result.put(serviceId, stackId); } }); return result; } @Override public Map<Long, Long> findConsumedByServicesIdsToStackIdsFromOtherAccounts(long accountId) { List<Long> serviceIds = Arrays.asList(create().select(SERVICE_CONSUME_MAP.SERVICE_ID) .from(SERVICE_CONSUME_MAP) .join(SERVICE) .on(SERVICE.ID.eq(SERVICE_CONSUME_MAP.CONSUMED_SERVICE_ID)) .where(SERVICE.ACCOUNT_ID.eq(accountId) .and(SERVICE_CONSUME_MAP.REMOVED.isNull()) .and(SERVICE.REMOVED.isNull()) .and(SERVICE_CONSUME_MAP.ACCOUNT_ID.ne(accountId))) .fetch().intoArray(SERVICE_CONSUME_MAP.SERVICE_ID)); Map<Long, Long> result = create().select(SERVICE.ID, SERVICE.STACK_ID) .from(SERVICE) .where(SERVICE.ID.in(serviceIds) .and(SERVICE.REMOVED.isNull())) .fetch().intoMap(SERVICE.ID, SERVICE.STACK_ID); return result; } }