package io.cattle.platform.core.dao.impl;
import static io.cattle.platform.core.model.tables.CertificateTable.*;
import static io.cattle.platform.core.model.tables.HealthcheckInstanceHostMapTable.*;
import static io.cattle.platform.core.model.tables.HealthcheckInstanceTable.*;
import static io.cattle.platform.core.model.tables.HostTable.*;
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.ServiceIndexTable.*;
import static io.cattle.platform.core.model.tables.ServiceTable.*;
import static io.cattle.platform.core.model.tables.StackTable.*;
import io.cattle.platform.core.addon.HealthcheckState;
import io.cattle.platform.core.constants.CommonStatesConstants;
import io.cattle.platform.core.constants.InstanceConstants;
import io.cattle.platform.core.constants.LoadBalancerConstants;
import io.cattle.platform.core.dao.ServiceDao;
import io.cattle.platform.core.model.Certificate;
import io.cattle.platform.core.model.HealthcheckInstance;
import io.cattle.platform.core.model.HealthcheckInstanceHostMap;
import io.cattle.platform.core.model.Instance;
import io.cattle.platform.core.model.Service;
import io.cattle.platform.core.model.ServiceIndex;
import io.cattle.platform.core.model.tables.HealthcheckInstanceHostMapTable;
import io.cattle.platform.core.model.tables.HostTable;
import io.cattle.platform.core.model.tables.InstanceTable;
import io.cattle.platform.core.model.tables.records.HealthcheckInstanceRecord;
import io.cattle.platform.core.model.tables.records.ServiceRecord;
import io.cattle.platform.db.jooq.dao.impl.AbstractJooqDao;
import io.cattle.platform.db.jooq.mapper.MultiRecordMapper;
import io.cattle.platform.json.JsonMapper;
import io.cattle.platform.object.ObjectManager;
import io.cattle.platform.object.util.DataAccessor;
import io.github.ibuildthecloud.gdapi.id.IdFormatter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.inject.Inject;
import javax.inject.Named;
import org.jooq.Record;
import org.jooq.Record2;
import org.jooq.Record3;
import org.jooq.Record6;
import org.jooq.RecordHandler;
@Named
public class ServiceDaoImpl extends AbstractJooqDao implements ServiceDao {
@Inject
ObjectManager objectManager;
@Inject
JsonMapper jsonMapper;
@Override
public Service getServiceByExternalId(Long accountId, String externalId) {
return create().selectFrom(SERVICE)
.where(SERVICE.ACCOUNT_ID.eq(accountId))
.and(SERVICE.REMOVED.isNull())
.and(SERVICE.EXTERNAL_ID.eq(externalId))
.fetchAny();
}
@Override
public ServiceIndex createServiceIndex(Service service, String launchConfigName, String serviceIndex) {
ServiceIndex serviceIndexObj = objectManager.findAny(ServiceIndex.class, SERVICE_INDEX.SERVICE_ID,
service.getId(),
SERVICE_INDEX.LAUNCH_CONFIG_NAME, launchConfigName, SERVICE_INDEX.SERVICE_INDEX_, serviceIndex,
SERVICE_INDEX.REMOVED, null);
if (serviceIndexObj == null) {
serviceIndexObj = objectManager.create(ServiceIndex.class, SERVICE_INDEX.SERVICE_ID,
service.getId(),
SERVICE_INDEX.LAUNCH_CONFIG_NAME, launchConfigName, SERVICE_INDEX.SERVICE_INDEX_, serviceIndex,
SERVICE_INDEX.ACCOUNT_ID, service.getAccountId());
}
return serviceIndexObj;
}
@Override
public Service getServiceByServiceIndexId(long serviceIndexId) {
Record record = create()
.select(SERVICE.fields())
.from(SERVICE)
.join(SERVICE_INDEX).on(SERVICE.ID.eq(SERVICE_INDEX.SERVICE_ID))
.where(SERVICE_INDEX.ID.eq(serviceIndexId))
.fetchAny();
return record == null ? null : record.into(Service.class);
}
@Override
public boolean isServiceInstance(Instance instance) {
return instance.getDeploymentUnitUuid() != null;
}
@Override
public Map<Long, List<Object>> getServicesForInstances(List<Long> ids, final IdFormatter idFormatter) {
final Map<Long, List<Object>> result = new HashMap<>();
create().select(SERVICE_EXPOSE_MAP.INSTANCE_ID, SERVICE_EXPOSE_MAP.SERVICE_ID)
.from(SERVICE_EXPOSE_MAP)
.join(SERVICE)
.on(SERVICE.ID.eq(SERVICE_EXPOSE_MAP.SERVICE_ID))
.where(SERVICE_EXPOSE_MAP.REMOVED.isNull()
.and(SERVICE.REMOVED.isNull())
.and(SERVICE_EXPOSE_MAP.INSTANCE_ID.in(ids)))
.fetchInto(new RecordHandler<Record2<Long, Long>>() {
@Override
public void next(Record2<Long, Long> record) {
Long serviceId = record.getValue(SERVICE_EXPOSE_MAP.SERVICE_ID);
Long instanceId = record.getValue(SERVICE_EXPOSE_MAP.INSTANCE_ID);
List<Object> list = result.get(instanceId);
if (list == null) {
list = new ArrayList<>();
result.put(instanceId, list);
}
list.add(idFormatter.formatId("service", serviceId));
}
});
return result;
}
@Override
public Map<Long, List<Object>> getInstances(List<Long> ids, final IdFormatter idFormatter) {
final Map<Long, List<Object>> result = new HashMap<>();
create().select(SERVICE_EXPOSE_MAP.INSTANCE_ID, SERVICE_EXPOSE_MAP.SERVICE_ID)
.from(SERVICE_EXPOSE_MAP)
.join(INSTANCE)
.on(INSTANCE.ID.eq(SERVICE_EXPOSE_MAP.INSTANCE_ID))
.where(SERVICE_EXPOSE_MAP.REMOVED.isNull()
.and(INSTANCE.REMOVED.isNull())
.and(SERVICE_EXPOSE_MAP.SERVICE_ID.in(ids))
.and(SERVICE_EXPOSE_MAP.REMOVED.isNull()))
.fetchInto(new RecordHandler<Record2<Long, Long>>() {
@Override
public void next(Record2<Long, Long> record) {
Long serviceId = record.getValue(SERVICE_EXPOSE_MAP.SERVICE_ID);
Long instanceId = record.getValue(SERVICE_EXPOSE_MAP.INSTANCE_ID);
List<Object> list = result.get(serviceId);
if (list == null) {
list = new ArrayList<>();
result.put(serviceId, list);
}
list.add(idFormatter.formatId(InstanceConstants.TYPE, instanceId));
}
});
return result;
}
@Override
public Map<Long, List<ServiceLink>> getServiceLinks(List<Long> ids) {
final Map<Long, List<ServiceLink>> result = new HashMap<>();
create().select(SERVICE_CONSUME_MAP.NAME, SERVICE_CONSUME_MAP.SERVICE_ID, SERVICE.ID,
SERVICE.NAME, STACK.ID, STACK.NAME)
.from(SERVICE_CONSUME_MAP)
.join(SERVICE)
.on(SERVICE.ID.eq(SERVICE_CONSUME_MAP.CONSUMED_SERVICE_ID))
.join(STACK)
.on(STACK.ID.eq(SERVICE.STACK_ID))
.where(SERVICE_CONSUME_MAP.SERVICE_ID.in(ids)
.and(SERVICE_CONSUME_MAP.REMOVED.isNull()))
.fetchInto(new RecordHandler<Record6<String, Long, Long, String, Long, String>>(){
@Override
public void next(Record6<String, Long, Long, String, Long, String> record) {
Long serviceId = record.getValue(SERVICE_CONSUME_MAP.SERVICE_ID);
List<ServiceLink> links = result.get(serviceId);
if (links == null) {
links = new ArrayList<>();
result.put(serviceId, links);
}
links.add(new ServiceLink(
record.getValue(SERVICE_CONSUME_MAP.NAME),
record.getValue(SERVICE.NAME),
record.getValue(SERVICE.ID),
record.getValue(STACK.ID),
record.getValue(STACK.NAME)));
}
});
return result;
}
@Override
public List<Certificate> getLoadBalancerServiceCertificates(Service lbService) {
List<? extends Long> certIds = DataAccessor.fields(lbService)
.withKey(LoadBalancerConstants.FIELD_LB_CERTIFICATE_IDS).withDefault(Collections.EMPTY_LIST)
.asList(jsonMapper, Long.class);
Long defaultCertId = DataAccessor.fieldLong(lbService, LoadBalancerConstants.FIELD_LB_DEFAULT_CERTIFICATE_ID);
List<Long> allCertIds = new ArrayList<>();
allCertIds.addAll(certIds);
allCertIds.add(defaultCertId);
return create()
.select(CERTIFICATE.fields())
.from(CERTIFICATE)
.where(CERTIFICATE.REMOVED.isNull())
.and(CERTIFICATE.ID.in(allCertIds))
.fetchInto(Certificate.class);
}
@Override
public Certificate getLoadBalancerServiceDefaultCertificate(Service lbService) {
Long defaultCertId = DataAccessor.fieldLong(lbService, LoadBalancerConstants.FIELD_LB_DEFAULT_CERTIFICATE_ID);
List<? extends Certificate> certs = create()
.select(CERTIFICATE.fields())
.from(CERTIFICATE)
.where(CERTIFICATE.REMOVED.isNull())
.and(CERTIFICATE.ID.eq(defaultCertId))
.fetchInto(Certificate.class);
if (certs.isEmpty()) {
return null;
}
return certs.get(0);
}
@Override
public HealthcheckInstanceHostMap getHealthCheckInstanceUUID(String hostUUID, String instanceUUID) {
MultiRecordMapper<HealthcheckInstanceHostMap> mapper = new MultiRecordMapper<HealthcheckInstanceHostMap>() {
@Override
protected HealthcheckInstanceHostMap map(List<Object> input) {
if (input.get(0) != null) {
return (HealthcheckInstanceHostMap) input.get(0);
}
return null;
}
};
HealthcheckInstanceHostMapTable hostMap = mapper.add(HEALTHCHECK_INSTANCE_HOST_MAP);
InstanceTable instance = mapper.add(INSTANCE, INSTANCE.UUID, INSTANCE.ID);
HostTable host = mapper.add(HOST, HOST.UUID, HOST.ID);
List<HealthcheckInstanceHostMap> maps = create()
.select(mapper.fields())
.from(hostMap)
.join(instance)
.on(instance.ID.eq(hostMap.INSTANCE_ID))
.join(host)
.on(host.ID.eq(hostMap.HOST_ID))
.where(host.UUID.eq(hostUUID))
.and(instance.UUID.eq(instanceUUID))
.and(hostMap.REMOVED.isNull())
.fetch().map(mapper);
if (maps.size() == 0) {
return null;
}
return maps.get(0);
}
@Override
public Map<Long, List<HealthcheckState>> getHealthcheckStatesForInstances(List<Long> ids,
final IdFormatter idFormatter) {
final Map<Long, List<HealthcheckState>> result = new HashMap<>();
create().select(HEALTHCHECK_INSTANCE_HOST_MAP.INSTANCE_ID, HEALTHCHECK_INSTANCE_HOST_MAP.HOST_ID,
HEALTHCHECK_INSTANCE_HOST_MAP.HEALTH_STATE)
.from(HEALTHCHECK_INSTANCE_HOST_MAP)
.join(HOST)
.on(HOST.ID.eq(HEALTHCHECK_INSTANCE_HOST_MAP.HOST_ID))
.where(HEALTHCHECK_INSTANCE_HOST_MAP.REMOVED.isNull()
.and(HOST.REMOVED.isNull())
.and(HEALTHCHECK_INSTANCE_HOST_MAP.INSTANCE_ID.in(ids)))
.fetchInto(new RecordHandler<Record3<Long, Long, String>>() {
@Override
public void next(Record3<Long, Long, String> record) {
Long instanceId = record.getValue(HEALTHCHECK_INSTANCE_HOST_MAP.INSTANCE_ID);
Long hostId = record.getValue(HEALTHCHECK_INSTANCE_HOST_MAP.HOST_ID);
String healthState = record.getValue(HEALTHCHECK_INSTANCE_HOST_MAP.HEALTH_STATE);
List<HealthcheckState> list = result.get(instanceId);
if (list == null) {
list = new ArrayList<>();
result.put(instanceId, list);
}
HealthcheckState state = new HealthcheckState(idFormatter.formatId("host", hostId).toString(), healthState);
list.add(state);
}
});
return result;
}
@Override
public List<? extends HealthcheckInstance> findBadHealthcheckInstance(int limit) {
return create()
.select(HEALTHCHECK_INSTANCE.fields())
.from(HEALTHCHECK_INSTANCE)
.join(INSTANCE)
.on(INSTANCE.ID.eq(HEALTHCHECK_INSTANCE.INSTANCE_ID))
.where(INSTANCE.STATE.eq(CommonStatesConstants.PURGED)
.and(HEALTHCHECK_INSTANCE.REMOVED.isNull())
.and(HEALTHCHECK_INSTANCE.STATE.notIn(CommonStatesConstants.DEACTIVATING,
CommonStatesConstants.REMOVING)))
.limit(limit)
.fetchInto(HealthcheckInstanceRecord.class);
}
@Override
public List<? extends Service> getSkipServices(long accountId) {
return create()
.select(SERVICE.fields())
.from(SERVICE)
.where(SERVICE.ACCOUNT_ID.eq(accountId)
.and(SERVICE.REMOVED.isNull())
.and(SERVICE.SKIP.isTrue()))
.fetchInto(ServiceRecord.class);
}
}