Package io.fathom.cloud.lbaas.services

Source Code of io.fathom.cloud.lbaas.services.LoadBalanceServiceImpl

package io.fathom.cloud.lbaas.services;

import io.fathom.cloud.CloudException;
import io.fathom.cloud.dns.DnsService;
import io.fathom.cloud.dns.DnsService.DnsRecordSpec;
import io.fathom.cloud.dns.DnsService.DnsRecordsetSpec;
import io.fathom.cloud.lbaas.backend.LbaasBackend;
import io.fathom.cloud.lbaas.backend.LbaasBackends;
import io.fathom.cloud.lbaas.state.LbaasRepository;
import io.fathom.cloud.loadbalancer.LoadBalanceService;
import io.fathom.cloud.openstack.client.loadbalance.model.LbaasMapping;
import io.fathom.cloud.openstack.client.loadbalance.model.LbaasServer;
import io.fathom.cloud.protobuf.LbaasModel.LbaasMappingData;
import io.fathom.cloud.protobuf.LbaasModel.LbaasServerData;
import io.fathom.cloud.server.model.Project;
import io.fathom.cloud.state.NumberedItemCollection;

import java.net.Inet6Address;
import java.net.InetAddress;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.inject.Inject;
import javax.inject.Singleton;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.google.common.net.InetAddresses;
import com.google.inject.persist.Transactional;

@Singleton
@Transactional
public class LoadBalanceServiceImpl implements LoadBalanceService {
    private static final Logger log = LoggerFactory.getLogger(LoadBalanceServiceImpl.class);

    @Inject
    LbaasBackends backends;

    @Inject
    LbaasRepository repository;

    @Inject
    DnsService dns;

    @Override
    public void setMappings(String systemKey, Project project, List<LbaasMapping> mappings) throws CloudException {
        List<LbaasMappingData> records = LbaasMappingMapper.INSTANCE.toData(project, systemKey, mappings);

        setLbaasRecords(systemKey, project, records);
    }

    @Override
    public void setServers(String systemKey, Project project, List<LbaasServer> servers) throws CloudException {
        List<LbaasServerData> records = LbaasServerMapper.INSTANCE.toData(project, systemKey, servers);

        setLbaasServers(systemKey, project, records);
    }

    private void setLbaasRecords(String systemKey, Project project, List<LbaasMappingData> requests)
            throws CloudException {
        // This is where a database would be awesome!
        LbaasMappingMapper mapper = LbaasMappingMapper.INSTANCE;

        NumberedItemCollection<LbaasMappingData> collection = repository.getMappings(project);

        Map<LbaasMappingData, LbaasMappingData> rawToDbMap = Maps.newHashMap();
        Map<Long, LbaasMappingData> dbMap = Maps.newHashMap();
        for (LbaasMappingData mapping : collection.list()) {
            if (!mapping.hasSystemKey()) {
                continue;
            }

            if (!systemKey.equals(mapping.getSystemKey())) {
                continue;
            }

            rawToDbMap.put(mapper.toComparable(mapping), mapping);
            dbMap.put(mapping.getId(), mapping);
        }

        List<LbaasMappingData> add = Lists.newArrayList();
        Map<Long, LbaasMappingData> remove = Maps.newHashMap(dbMap);

        for (LbaasMappingData mapping : requests) {
            LbaasMappingData db = rawToDbMap.get(mapping);
            if (db == null) {
                add.add(mapping);
            } else {
                remove.remove(db.getId());
            }
        }

        Set<String> dirtyHosts = Sets.newHashSet();

        for (LbaasMappingData a : add) {
            LbaasMappingData.Builder b = LbaasMappingData.newBuilder(a);
            collection.create(b);

            dirtyHosts.add(b.getHost());
        }

        for (LbaasMappingData r : remove.values()) {
            collection.delete(r.getId());

            dirtyHosts.add(r.getHost());
        }

        for (String host : dirtyHosts) {
            updateHost(project, host);
        }
    }

    private void setLbaasServers(String systemKey, Project project, List<LbaasServerData> requests)
            throws CloudException {
        // This is where a database would be awesome!
        LbaasServerMapper mapper = LbaasServerMapper.INSTANCE;

        NumberedItemCollection<LbaasServerData> collection = repository.getServers(project);

        Map<LbaasServerData, LbaasServerData> rawToDbMap = Maps.newHashMap();
        Map<Long, LbaasServerData> dbMap = Maps.newHashMap();
        for (LbaasServerData mapping : collection.list()) {
            if (!mapping.hasSystemKey()) {
                continue;
            }

            if (!systemKey.equals(mapping.getSystemKey())) {
                continue;
            }

            rawToDbMap.put(mapper.toComparable(mapping), mapping);
            dbMap.put(mapping.getId(), mapping);
        }

        List<LbaasServerData> add = Lists.newArrayList();
        Map<Long, LbaasServerData> remove = Maps.newHashMap(dbMap);

        for (LbaasServerData mapping : requests) {
            LbaasServerData db = rawToDbMap.get(mapping);
            if (db == null) {
                add.add(mapping);
            } else {
                remove.remove(db.getId());
            }
        }

        Set<LbaasServerData> dirtyServers = Sets.newHashSet();

        for (LbaasServerData a : add) {
            log.info("Add LB: {}", a);

            LbaasServerData.Builder b = LbaasServerData.newBuilder(a);
            LbaasServerData created = collection.create(b);

            dirtyServers.add(created);
        }

        for (LbaasServerData r : remove.values()) {
            log.info("Remove LB: {}", r);

            LbaasServerData deleted = collection.delete(r.getId());

            if (deleted == null) {
                throw new IllegalStateException("Did not find server during delete");
            }

            dirtyServers.add(deleted);
        }

        updateServers(project, dirtyServers);
    }

    private void updateServers(Project project, Set<LbaasServerData> dirtyServers) throws CloudException {
        // We need to update all the DNS records to point to the correct servers

        Set<String> hosts = Sets.newHashSet();
        for (LbaasMappingData mapping : repository.getMappings(project).list()) {
            // If we map hosts to specific servers, we'll do that here...
            hosts.add(mapping.getHost());
        }

        List<DnsRecordSpec> ipv4 = Lists.newArrayList();
        List<DnsRecordSpec> ipv6 = Lists.newArrayList();
        for (LbaasServerData server : repository.getServers(project).list()) {
            String ip = server.getIp();

            DnsRecordSpec record = new DnsRecordSpec();
            record.address = ip;

            InetAddress address = InetAddresses.forString(ip);
            if (address instanceof Inet6Address) {
                ipv6.add(record);
            } else {
                ipv4.add(record);
            }
        }

        List<DnsRecordsetSpec> dnsRecordsets = Lists.newArrayList();
        for (String host : hosts) {
            if (!ipv4.isEmpty()) {
                DnsRecordsetSpec dnsRecord = new DnsRecordsetSpec();
                dnsRecord.fqdn = host;
                dnsRecord.type = "A";
                dnsRecord.records = Lists.newArrayList(ipv4);

                dnsRecordsets.add(dnsRecord);
            }

            if (!ipv6.isEmpty()) {
                DnsRecordsetSpec dnsRecord = new DnsRecordsetSpec();
                dnsRecord.fqdn = host;
                dnsRecord.type = "AAAA";
                dnsRecord.records = Lists.newArrayList(ipv6);

                dnsRecordsets.add(dnsRecord);
            }
        }

        String systemKey = "__lb__/" + project.getId();
        dns.setDnsRecordsets(systemKey, project, dnsRecordsets);
    }

    private void updateHost(Project project, String host) throws CloudException {
        LbaasBackend backend = getBackend();
        backend.updateHost(project, host);
    }

    private LbaasBackend getBackend() throws CloudException {
        return backends.getBackend();
    }

    public List<LbaasMapping> listMappings(Project project, String host) throws CloudException {
        LbaasMappingMapper mapper = LbaasMappingMapper.INSTANCE;

        List<LbaasMapping> ret = Lists.newArrayList();

        for (LbaasMappingData mapping : repository.getMappings(project).list()) {
            if (!host.equals(mapping.getHost())) {
                continue;
            }
            ret.add(mapper.toModel(mapping));
        }

        return ret;
    }

}
TOP

Related Classes of io.fathom.cloud.lbaas.services.LoadBalanceServiceImpl

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.