All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.bodybuilding.turbine.discovery.DnsInstanceDiscovery Maven / Gradle / Ivy

There is a newer version: 0.7.2
Show newest version
/*
 * Copyright (C) 2015 Bodybuilding.com
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.bodybuilding.turbine.discovery;

import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Splitter;
import com.google.common.collect.Lists;
import com.netflix.config.DynamicIntProperty;
import com.netflix.config.DynamicPropertyFactory;
import com.netflix.config.DynamicStringProperty;
import com.netflix.turbine.discovery.Instance;
import com.netflix.turbine.discovery.InstanceDiscovery;

import java.net.*;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;

/**
 * Fork of {@link com.netflix.turbine.discovery.ConfigPropertyBasedDiscovery} that allows integer format strings (%d) in hostnames.
 * The integer is incremented until 2 consecutive lookups fail. Only a single %d may be present.
 */
public class DnsInstanceDiscovery implements InstanceDiscovery {
    private static final DynamicStringProperty DefaultClusterInstanceList = DynamicPropertyFactory.getInstance().getStringProperty("turbine.ConfigPropertyBasedDiscovery.default.instances", null);

    private static final DynamicStringProperty ClusterList = DynamicPropertyFactory.getInstance().getStringProperty(TURBINE_AGGREGATOR_CLUSTER_CONFIG, null);
    private static final DynamicIntProperty DnsMaxLookupErrors = DynamicPropertyFactory.getInstance().getIntProperty("DnsInstanceDiscovery.maxLookupErrors", 2);

    private static final Splitter PropertySplitter = Splitter.on(',').omitEmptyStrings().trimResults();

    @Override
    public Collection getInstanceList() throws Exception {

        List clusters = getClusterList();
        List instances = new ArrayList<>();
        for (String cluster : clusters) {
            instances.addAll(getInstancesForCluster(cluster));
        }
        return instances;
    }

    private List getClusterList() throws Exception {

        String clusterConfig = ClusterList.get();
        if (clusterConfig == null || clusterConfig.trim().length() == 0) {
            // check if there is a list of default instances. If yes, then use 'default' as the cluster
            String defaultInstanceList = DefaultClusterInstanceList.get();
            if (defaultInstanceList == null || defaultInstanceList.trim().length() == 0) {
                throw new Exception("Must configure instance list using property: " + DefaultClusterInstanceList.getName());
            }
            // return cluster as default
            return Lists.newArrayList("default");
        }
        // cluster config is not null. Parse cluster config.
        List clusters = Lists.newArrayList(PropertySplitter.split(clusterConfig));

        if (clusters.size() == 0) {
            throw new Exception("Must configure property: " + ClusterList.getName());
        }
        return clusters;
    }

    private List getInstancesForCluster(String cluster) throws Exception {

        DynamicStringProperty instanceListProp = DynamicPropertyFactory.getInstance().getStringProperty("turbine.ConfigPropertyBasedDiscovery." + cluster + ".instances", null);
        String instanceList = instanceListProp.get();
        if (instanceList == null || instanceList.trim().length() == 0) {
            throw new Exception("Must configure Instance list property: " + instanceListProp.getName());
        }

        Iterable parts = PropertySplitter.split(instanceList);

        List instances = new ArrayList<>();
        for (String s : parts) {
            instances.addAll(resolveInstances(s, cluster));
        }
        return instances;
    }

    /**
     * Resolves instances using DNS if they contain %d
     * @param url url to use for lookup
     * @param cluster the cluster these instances belong to
     * @return collection of instances that resolved
     * @throws MalformedURLException
     */
    private Collection resolveInstances(final String url, String cluster) throws MalformedURLException {
        List instanceList = Lists.newArrayList();

        String withSchema = url;
        if (!withSchema.contains("://")) {
            withSchema = "http://" + url;
        }
        String host = new URL(withSchema).getHost();
        if(!host.contains("%")) {
            return Collections.singleton(new Instance(url, cluster, true));
        }
        int errors = 0;
        int i = 1;
        do {
            String newHost = String.format(host, i++);
            InetAddress address = resolveHost(newHost);
            if (address == null) {
                errors++;
            } else {
                errors = 0;
                instanceList.add(new Instance(url.replace(host, newHost), cluster, true));
            }

        } while (errors < DnsMaxLookupErrors.get());

        return instanceList;
    }

    @VisibleForTesting
    protected InetAddress resolveHost(String host) {
        try {
            return InetAddress.getByName(host);
        } catch (UnknownHostException e) {
            return null;
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy