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

com.netflix.eureka2.registry.datacenter.AwsDataCenterInfoProvider Maven / Gradle / Ivy

There is a newer version: 2.0.0-DP4
Show newest version
/*
 * Copyright 2014 Netflix, Inc.
 *
 * 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.netflix.eureka2.registry.datacenter;

import io.netty.buffer.ByteBuf;
import io.reactivex.netty.RxNetty;
import io.reactivex.netty.protocol.http.client.HttpClientResponse;
import rx.Observable;
import rx.Subscriber;
import rx.functions.Func1;
import rx.subjects.ReplaySubject;

import java.io.IOException;
import java.nio.charset.Charset;
import java.util.concurrent.atomic.AtomicReference;

/**
 * Loads instance information from AWS metadata host. The data is loaded only once
 * on the first access, and its cashed and reused for subsequent {@link #dataCenterInfo()} calls.
 *
 * @author Tomasz Bak
 */
public class AwsDataCenterInfoProvider implements DataCenterInfoProvider {

    private static final String AWS_API_VERSION = "latest";
    private static final String AWS_METADATA_URI = "http://169.254.169.254/" + AWS_API_VERSION + "/meta-data/";
    private final String metaDataURI;

    enum MetaDataKey {
        AmiId("ami-id") {
            @Override
            public AwsDataCenterInfo.Builder apply(AwsDataCenterInfo.Builder builder, String metaInfoValue) {
                return builder.withAmiId(metaInfoValue);
            }
        },
        InstanceId("instance-id") {
            @Override
            public AwsDataCenterInfo.Builder apply(AwsDataCenterInfo.Builder builder, String metaInfoValue) {
                return builder.withInstanceId(metaInfoValue);
            }
        },
        InstanceType("instance-type") {
            @Override
            public AwsDataCenterInfo.Builder apply(AwsDataCenterInfo.Builder builder, String metaInfoValue) {
                return builder.withInstanceType(metaInfoValue);
            }
        },
        PublicHostname("public-hostname") {
            @Override
            public AwsDataCenterInfo.Builder apply(AwsDataCenterInfo.Builder builder, String metaInfoValue) {
                return builder.withPublicHostName(metaInfoValue);
            }
        },
        PublicIpv4("public-ipv4") {
            @Override
            public AwsDataCenterInfo.Builder apply(AwsDataCenterInfo.Builder builder, String metaInfoValue) {
                return builder.withPublicIPv4(metaInfoValue);
            }
        },
        LocalHostName("local-hostname") {
            @Override
            public AwsDataCenterInfo.Builder apply(AwsDataCenterInfo.Builder builder, String metaInfoValue) {
                return builder.withPrivateHostName(metaInfoValue);
            }
        },
        LocalIpv4("local-ipv4") {
            @Override
            public AwsDataCenterInfo.Builder apply(AwsDataCenterInfo.Builder builder, String metaInfoValue) {
                return builder.withPrivateIPv4(metaInfoValue);
            }
        },
        AvailabilityZone("availability-zone", "placement/") {
            @Override
            public AwsDataCenterInfo.Builder apply(AwsDataCenterInfo.Builder builder, String metaInfoValue) {
                return builder.withZone(metaInfoValue);
            }
        };

        private final String name;
        private final String path;

        MetaDataKey(String name) {
            this(name, "");
        }

        MetaDataKey(String name, String path) {
            this.name = name;
            this.path = path;
        }

        public String getName() {
            return name;
        }

        public String getPath() {
            return path;
        }

        public abstract AwsDataCenterInfo.Builder apply(AwsDataCenterInfo.Builder builder, String metaInfoValue);
    }

    private final AtomicReference> dataCenterInfoRef = new AtomicReference<>();

    public AwsDataCenterInfoProvider() {
        this.metaDataURI = AWS_METADATA_URI;
    }

    // For testing purposes.
    AwsDataCenterInfoProvider(String metaDataURI) {
        this.metaDataURI = metaDataURI;
    }

    @Override
    public Observable dataCenterInfo() {
        if (dataCenterInfoRef.get() != null) {
            return dataCenterInfoRef.get();
        }
        dataCenterInfoRef.compareAndSet(null, readMetaInfo());
        return dataCenterInfoRef.get();
    }

    private Observable readMetaInfo() {
        final ReplaySubject subject = ReplaySubject.create();

        final AwsDataCenterInfo.Builder builder = new AwsDataCenterInfo.Builder();
        Observable.from(MetaDataKey.values()).flatMap(new Func1>() {
            @Override
            public Observable call(final MetaDataKey key) {
                String uri = metaDataURI + '/' + key.getPath() + key.getName();
                return RxNetty.createHttpGet(uri).flatMap(new Func1, Observable>() {
                    @Override
                    public Observable call(HttpClientResponse response) {
                        if (response.getStatus().code() / 100 != 2) {
                            return Observable.error(new IOException("Server returned error status " + response.getStatus()));
                        }
                        return response.getContent().map(new Func1() {
                            @Override
                            public String call(ByteBuf byteBuf) {
                                return byteBuf.toString(Charset.defaultCharset());
                            }
                        });
                    }
                }).map(new Func1() {
                    @Override
                    public Void call(String metaValue) {
                        key.apply(builder, metaValue);
                        return null;
                    }
                });
            }
        }).subscribe(new Subscriber() {
            @Override
            public void onCompleted() {
                subject.onNext(builder.build());
                subject.onCompleted();
            }

            @Override
            public void onError(Throwable e) {
                subject.onError(e);
            }

            @Override
            public void onNext(Void aVoid) {
            }
        });

        return subject;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy