package io.cattle.platform.core.dao.impl; import static io.cattle.platform.core.model.tables.AccountTable.*; import static io.cattle.platform.core.model.tables.IpAddressTable.*; import static io.cattle.platform.core.model.tables.NetworkDriverTable.*; import static io.cattle.platform.core.model.tables.NetworkTable.*; import static io.cattle.platform.core.model.tables.NicTable.*; import static io.cattle.platform.core.model.tables.ServiceExposeMapTable.*; import static io.cattle.platform.core.model.tables.SubnetTable.*; import io.cattle.platform.archaius.util.ArchaiusUtil; import io.cattle.platform.core.constants.CommonStatesConstants; import io.cattle.platform.core.constants.PortConstants; import io.cattle.platform.core.constants.SubnetConstants; import io.cattle.platform.core.dao.AccountDao; import io.cattle.platform.core.dao.GenericResourceDao; import io.cattle.platform.core.dao.NetworkDao; import io.cattle.platform.core.model.Account; import io.cattle.platform.core.model.Instance; import io.cattle.platform.core.model.Network; import io.cattle.platform.core.model.Nic; import io.cattle.platform.core.model.Port; import io.cattle.platform.core.model.Subnet; import io.cattle.platform.core.model.tables.records.NetworkRecord; import io.cattle.platform.core.util.PortSpec; import io.cattle.platform.db.jooq.dao.impl.AbstractJooqDao; 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.object.util.DataAccessor; import io.cattle.platform.util.net.NetUtils; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.inject.Inject; import javax.inject.Named; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.tuple.Pair; import com.netflix.config.DynamicStringListProperty; @Named public class NetworkDaoImpl extends AbstractJooqDao implements NetworkDao { DynamicStringListProperty DOCKER_VIP_SUBNET_CIDR = ArchaiusUtil.getList("docker.vip.subnet.cidr"); @Inject ObjectManager objectManager; @Inject AccountDao accountDao; @Inject GenericResourceDao resourceDao; @Inject ObjectProcessManager objectProcessManager; @Inject LockManager lockManager; @Override public Nic getPrimaryNic(long instanceId) { return create() .selectFrom(NIC) .where(NIC.INSTANCE_ID.eq(instanceId) .and(NIC.DEVICE_NUMBER.eq(0)) .and(NIC.REMOVED.isNull())) .fetchAny(); } @Override public Network getNetworkByKind(long accountId, String kind) { return objectManager.findAny(Network.class, NETWORK.KIND, kind, NETWORK.ACCOUNT_ID, accountId, NETWORK.REMOVED, null); } @Override public Network getNetworkByName(long accountId, String name) { return objectManager.findAny(Network.class, NETWORK.NAME, name, NETWORK.ACCOUNT_ID, accountId, NETWORK.REMOVED, null); } protected Network getInstancePrimaryNetwork(Instance instance) { Nic primaryNic = getPrimaryNic(instance.getId()); return objectManager.loadResource(Network.class, primaryNic.getNetworkId()); } @Override public Subnet addVIPSubnet(final long accountId) { return lockManager.lock(new SubnetCreateLock(accountId), new LockCallback<Subnet>() { @Override public Subnet doWithLock() { List<Subnet> subnets = objectManager.find(Subnet.class, SUBNET.ACCOUNT_ID, accountId, SUBNET.KIND, SubnetConstants.KIND_VIP_SUBNET); if (subnets.size() > 0) { return subnets.get(0); } Pair<String, Integer> cidr = NetUtils.getCidrAndSize(DOCKER_VIP_SUBNET_CIDR.get().get(0)); return resourceDao.createAndSchedule(Subnet.class, SUBNET.ACCOUNT_ID, accountId, SUBNET.CIDR_SIZE, cidr.getRight(), SUBNET.NETWORK_ADDRESS, cidr.getLeft(), SUBNET.KIND, SubnetConstants.KIND_VIP_SUBNET); } }); } @Override public Network getDefaultNetwork(Long accountId) { Account account = objectManager.loadResource(Account.class, accountId); if (account == null) { return null; } return objectManager.loadResource(Network.class, account.getDefaultNetworkId()); } @Override public List<Long> findInstancesInUseByServiceDriver(Long serviceId) { Long[] ignore = create() .select(SERVICE_EXPOSE_MAP.INSTANCE_ID) .from(SERVICE_EXPOSE_MAP) .where(SERVICE_EXPOSE_MAP.SERVICE_ID.eq(serviceId) .and(SERVICE_EXPOSE_MAP.REMOVED.isNull())) .fetch().intoArray(SERVICE_EXPOSE_MAP.INSTANCE_ID); return create().select(NIC.INSTANCE_ID) .from(NIC) .join(NETWORK) .on(NIC.NETWORK_ID.eq(NETWORK.ID)) .join(NETWORK_DRIVER) .on(NETWORK_DRIVER.ID.eq(NETWORK.NETWORK_DRIVER_ID)) .where(NETWORK_DRIVER.SERVICE_ID.eq(serviceId) .and(NIC.REMOVED.isNull()) .and(NIC.INSTANCE_ID.notIn(ignore))) .fetchInto(Long.class); } @Override public List<Subnet> getSubnets(Network network) { return objectManager.find(Subnet.class, SUBNET.NETWORK_ID, network.getId(), SUBNET.STATE, CommonStatesConstants.ACTIVE); } @Override public List<? extends Network> getActiveNetworks(Long accountId) { return create().select(NETWORK.fields()) .from(NETWORK) .where(NETWORK.ACCOUNT_ID.eq(accountId) .and(NETWORK.STATE.in(CommonStatesConstants.ACTIVATING, CommonStatesConstants.ACTIVE, CommonStatesConstants.UPDATING_ACTIVE))) .fetchInto(NetworkRecord.class); } @Override public void updateInstancePorts(Instance instance, List<String> newPortDefs, List<Port> toCreate, List<Port> toRemove, Map<String, Port> toRetain) { Map<String, Port> existingPorts = new HashMap<>(); for (Port port : objectManager.children(instance, Port.class)) { if (port.getRemoved() != null || port.getState().equalsIgnoreCase(CommonStatesConstants.REMOVING)) { continue; } existingPorts.put(toKey(port), port); } for (String port : newPortDefs) { PortSpec spec = new PortSpec(port); if (existingPorts.containsKey(toKey(spec))) { toRetain.put(toKey(spec), existingPorts.get(toKey(spec))); continue; } Port portObj = objectManager.newRecord(Port.class); portObj.setAccountId(instance.getAccountId()); portObj.setKind(PortConstants.KIND_USER); portObj.setInstanceId(instance.getId()); portObj.setPublicPort(spec.getPublicPort()); portObj.setPrivatePort(spec.getPrivatePort()); portObj.setProtocol(spec.getProtocol()); if (StringUtils.isNotEmpty(spec.getIpAddress())) { DataAccessor.fields(portObj).withKey(PortConstants.FIELD_BIND_ADDR).set(spec.getIpAddress()); } toCreate.add(portObj); toRetain.put(toKey(portObj), portObj); } // remove extra ports for (String existing : existingPorts.keySet()) { if (!toRetain.containsKey(existing)) { toRemove.add(existingPorts.get(existing)); } } } protected String toKey(PortSpec spec) { return String.format("%d:%d/%s", spec.getPublicPort(), spec.getPrivatePort(), spec.getProtocol()); } protected String toKey(Port port) { return String.format("%d:%d/%s", port.getPublicPort(), port.getPrivatePort(), port.getProtocol()); } @Override public void migrateToNetwork(Network network) { Network hostOnly = objectManager.findAny(Network.class, NETWORK.ACCOUNT_ID, network.getAccountId(), NETWORK.KIND, "hostOnlyNetwork"); if (hostOnly != null) { create() .update(SUBNET) .set(SUBNET.NETWORK_ID, network.getId()) .where(SUBNET.NETWORK_ID.eq(hostOnly.getId())) .execute(); create() .update(IP_ADDRESS) .set(IP_ADDRESS.NETWORK_ID, network.getId()) .where(IP_ADDRESS.NETWORK_ID.eq(hostOnly.getId())) .execute(); create() .update(NIC) .set(NIC.NETWORK_ID, network.getId()) .where(NIC.NETWORK_ID.eq(hostOnly.getId())) .execute(); } create() .update(ACCOUNT) .set(ACCOUNT.DEFAULT_NETWORK_ID, network.getId()) .where(ACCOUNT.ID.eq(network.getAccountId())) .execute(); } @Override public List<? extends Network> findBadNetworks(int count) { return create().select(NETWORK.fields()) .from(NETWORK) .join(ACCOUNT) .on(ACCOUNT.ID.eq(NETWORK.ACCOUNT_ID)) .where(NETWORK.REMOVED.isNull() .and(ACCOUNT.STATE.eq(CommonStatesConstants.PURGED)) .and(NETWORK.STATE.notIn(CommonStatesConstants.REMOVING))) .limit(count) .fetchInto(NetworkRecord.class); } }