com.netflix.nfsidecar.identity.InstanceIdentity Maven / Gradle / Ivy
/**
* Copyright 2013 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.nfsidecar.identity;
import java.net.UnknownHostException;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Random;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.base.Predicate;
import com.google.common.base.Supplier;
import com.google.common.collect.ListMultimap;
import com.google.common.collect.Lists;
import com.google.common.collect.Multimaps;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import com.netflix.nfsidecar.config.AWSCommonConfig;
import com.netflix.nfsidecar.config.CommonConfig;
import com.netflix.nfsidecar.instance.InstanceDataRetriever;
import com.netflix.nfsidecar.resources.env.IEnvVariables;
import com.netflix.nfsidecar.tokensdb.IAppsInstanceFactory;
import com.netflix.nfsidecar.utils.ITokenManager;
import com.netflix.nfsidecar.utils.RetryableCallable;
import com.netflix.nfsidecar.utils.Sleeper;
/**
* This class provides the central place to create and consume the identity of
* the instance - token, seeds etc.
*
*/
@Singleton
public class InstanceIdentity {
private static final Logger logger = LoggerFactory.getLogger(InstanceIdentity.class);
private static final String DUMMY_INSTANCE_ID = "new_slot";
private final ListMultimap locMap = Multimaps
.newListMultimap(new HashMap>(), new Supplier>() {
public List get() {
return Lists.newArrayList();
}
});
private final IAppsInstanceFactory factory;
private final IMembership membership;
private final CommonConfig commonConfig;
private final AWSCommonConfig aWSCommonConfig;
private final Sleeper sleeper;
private final ITokenManager tokenManager;
private final InstanceEnvIdentity insEnvIdentity;
private final InstanceDataRetriever retriever;
private final IEnvVariables envVariables;
private final Predicate differentHostPredicate = new Predicate() {
@Override
public boolean apply(AppsInstance instance) {
return (!instance.getInstanceId().equalsIgnoreCase(DUMMY_INSTANCE_ID)
&& !instance.getHostName().equals(myInstance.getHostName()));
}
};
private AppsInstance myInstance;
private boolean isReplace = false;
private boolean isTokenPregenerated = false;
private boolean isNewToken = false;
private String replacedIp = "";
@Inject
public InstanceIdentity(IAppsInstanceFactory factory, IMembership membership, AWSCommonConfig aWSCommonConfig,
CommonConfig commonConfig, Sleeper sleeper, ITokenManager tokenManager, InstanceEnvIdentity insEnvIdentity,
InstanceDataRetriever retriever, IEnvVariables envVariables) throws Exception {
this.factory = factory;
this.membership = membership;
this.commonConfig = commonConfig;
this.aWSCommonConfig = aWSCommonConfig;
this.sleeper = sleeper;
this.tokenManager = tokenManager;
this.insEnvIdentity = insEnvIdentity;
this.retriever = retriever;
this.envVariables = envVariables;
init();
}
public AppsInstance getInstance() {
return myInstance;
}
public void init() throws Exception {
// try to grab the token which was already assigned
myInstance = new RetryableCallable() {
@Override
public AppsInstance retriableCall() throws Exception {
// Check if this node is decommissioned
for (AppsInstance ins : factory.getAllIds(envVariables.getDynomiteClusterName() + "-dead")) {
logger.debug(String.format("[Dead] Iterating though the hosts: %s", ins.getInstanceId()));
if (ins.getInstanceId().equals(retriever.getInstanceId())) {
ins.setOutOfService(true);
return ins;
}
}
for (AppsInstance ins : factory.getAllIds(envVariables.getDynomiteClusterName())) {
logger.debug(String.format("[Alive] Iterating though the hosts: %s My id = [%s]",
ins.getInstanceId(), ins.getId()));
if (ins.getInstanceId().equals(retriever.getInstanceId()))
return ins;
}
return null;
}
}.call();
// Grab a dead token
if (null == myInstance)
myInstance = new GetDeadToken().call();
// Grab a pre-generated token if there is such one
if (null == myInstance)
myInstance = new GetPregeneratedToken().call();
// Grab a new token
if (null == myInstance) {
GetNewToken newToken = new GetNewToken();
newToken.set(100, 100);
myInstance = newToken.call();
}
logger.info("My token: " + myInstance.getToken());
}
private void populateRacMap() {
locMap.clear();
for (AppsInstance ins : factory.getAllIds(envVariables.getDynomiteClusterName())) {
locMap.put(ins.getZone(), ins);
}
if (locMap.isEmpty()) {
logger.error("Could not find " + envVariables.getDynomiteClusterName() + " in the Cassandra cluster");
}
}
private List getDualAccountRacMembership(List asgInstances) {
logger.info("Dual Account cluster");
List crossAccountAsgInstances = membership.getCrossAccountRacMembership();
if (insEnvIdentity.isClassic()) {
logger.info("EC2 classic instances (local ASG): " + Arrays.toString(asgInstances.toArray()));
logger.info("VPC Account (cross-account ASG): " + Arrays.toString(crossAccountAsgInstances.toArray()));
} else {
logger.info("VPC Account (local ASG): " + Arrays.toString(asgInstances.toArray()));
logger.info("EC2 classic instances (cross-account ASG): "
+ Arrays.toString(crossAccountAsgInstances.toArray()));
}
// Remove duplicates (probably there are not)
asgInstances.removeAll(crossAccountAsgInstances);
// Merge the two lists
asgInstances.addAll(crossAccountAsgInstances);
logger.info("Combined Instances in the AZ: " + asgInstances);
return asgInstances;
}
public class GetDeadToken extends RetryableCallable {
@Override
public AppsInstance retriableCall() throws Exception {
final List allIds = factory.getAllIds(envVariables.getDynomiteClusterName());
List asgInstances = membership.getRacMembership();
if (aWSCommonConfig.isDualAccount()) {
asgInstances = getDualAccountRacMembership(asgInstances);
} else {
logger.info("Single Account cluster");
}
// Sleep random interval - upto 15 sec
sleeper.sleep(new Random().nextInt(5000) + 10000);
for (AppsInstance dead : allIds) {
// test same dc and is it is alive.
if (!dead.getRack().equals(envVariables.getRack()) || asgInstances.contains(dead.getInstanceId()))
continue;
logger.info("Found dead instances: " + dead.getInstanceId());
// AppsInstance markAsDead = factory.create(dead.getApp() +
// "-dead", dead.getId(), dead.getInstanceId(),
// dead.getHostName(), dead.getHostIP(), dead.getZone(),
// dead.getVolumes(), dead.getToken(), dead.getRack());
// remove it as we marked it down...
// factory.delete(dead);
isReplace = true;
replacedIp = dead.getHostIP();
String payLoad = dead.getToken();
logger.info("Trying to grab slot {} with availability zone {}", dead.getId(), dead.getZone());
return factory.create(envVariables.getDynomiteClusterName(), dead.getId(), retriever.getInstanceId(),
retriever.getPublicHostname(), retriever.getPublicIP(), retriever.getRac(), dead.getVolumes(),
payLoad, envVariables.getRack());
}
return null;
}
public void forEachExecution() {
populateRacMap();
}
}
public class GetPregeneratedToken extends RetryableCallable {
@Override
public AppsInstance retriableCall() throws Exception {
logger.info("Looking for any pre-generated token");
final List allIds = factory.getAllIds(envVariables.getDynomiteClusterName());
List asgInstances = membership.getRacMembership();
// Sleep random interval - upto 15 sec
sleeper.sleep(new Random().nextInt(5000) + 10000);
for (AppsInstance dead : allIds) {
// test same zone and is it is alive.
if (!dead.getRack().equals(envVariables.getRack()) || asgInstances.contains(dead.getInstanceId())
|| !isInstanceDummy(dead))
continue;
logger.info("Found pre-generated token: " + dead.getToken());
// AppsInstance markAsDead = factory.create(dead.getApp() +
// "-dead", dead.getId(), dead.getInstanceId(),
// dead.getHostName(), dead.getHostIP(), dead.getRack(),
// dead.getVolumes(),
// dead.getToken());
// remove it as we marked it down...
factory.delete(dead);
isTokenPregenerated = true;
String payLoad = dead.getToken();
logger.info("Trying to grab slot {} with availability zone {}", dead.getId(), dead.getRack());
return factory.create(envVariables.getDynomiteClusterName(), dead.getId(), retriever.getInstanceId(),
retriever.getPublicHostname(), retriever.getPublicIP(), retriever.getRac(), dead.getVolumes(),
payLoad, envVariables.getRack());
}
return null;
}
public void forEachExecution() {
populateRacMap();
}
}
public class GetNewToken extends RetryableCallable {
public AppsInstance retriableCall() throws Exception {
// Sleep random interval - upto 15 sec
sleeper.sleep(new Random().nextInt(15000));
int hash = tokenManager.regionOffset(envVariables.getRack());
// use this hash so that the nodes are spred far away from the other
// regions.
String myInstanceId = retriever.getInstanceId();
List asgInstanceIds = membership.getRacMembership();
logger.info("My Instance Id: " + myInstanceId);
for (String instanceId : asgInstanceIds) {
logger.info("InstanceId in ASG: " + instanceId);
}
int my_slot = asgInstanceIds.indexOf(myInstanceId);
logger.info("my_slot ::: " + my_slot);
isNewToken = true;
int rackMembershipSize;
if (aWSCommonConfig.isDualAccount()) {
rackMembershipSize = membership.getRacMembershipSize() + membership.getCrossAccountRacMembershipSize();
} else {
rackMembershipSize = membership.getRacMembershipSize();
}
logger.info(String.format(
"Trying to createToken with slot %d with rac count %d with rac membership size %d with dc %s",
my_slot, commonConfig.getRacks().size(), rackMembershipSize, envVariables.getRegion()));
// String payload = tokenManager.createToken(my_slot,
// membership.getRacCount(), membership.getRacMembershipSize(),
// config.getDataCenter());
String payload = tokenManager.createToken(my_slot, rackMembershipSize, envVariables.getRack());
return factory.create(envVariables.getDynomiteClusterName(), my_slot + hash, retriever.getInstanceId(),
retriever.getPublicHostname(), retriever.getPublicIP(), retriever.getRac(), null, payload,
envVariables.getRack());
}
public void forEachExecution() {
populateRacMap();
}
}
/*
* public List getSeeds1() throws UnknownHostException {
* populateRacMap(); List seeds = new LinkedList(); //
* Handle single zone deployment if (config.getRacs().size() == 1) { //
* Return empty list if all nodes are not up if
* (membership.getRacMembershipSize() !=
* locMap.get(myInstance.getRac()).size()) return seeds; // If seed node,
* return the next node in the list //if
* (locMap.get(myInstance.getRac()).size() > 1 &&
* locMap.get(myInstance.getRac()).get(0).getHostIP().equals(myInstance.
* getHostIP())) //{
* //seeds.add(locMap.get(myInstance.getRac()).get(1).getHostName());
* //seedp.add(seed + ":" + config.getPeerListenerPort() + ":" +
* config.getDataCenter() + ":5622637");
* seeds.add(locMap.get(myInstance.getRac()).get(1).getHostName() + ":" +
* config.getPeerListenerPort() + ":" + config.getDataCenter() + ":" +
* locMap.get(myInstance.getRac()).get(1).getToken()); //} } for (String loc
* : locMap.keySet()) { AppsInstance instance =
* Iterables.tryFind(locMap.get(loc), differentHostPredicate).orNull(); if
* (instance != null) { //seeds.add(instance.getHostName());
* seeds.add(instance.getHostName() + ":" + config.getPeerListenerPort() +
* ":" + config.getDataCenter() + ":" + instance.getToken()); } } return
* seeds; }
*/
public List getSeeds() throws UnknownHostException {
// populateRacMap();
List seeds = new LinkedList();
for (AppsInstance ins : factory.getAllIds(envVariables.getDynomiteClusterName())) {
if (!ins.getInstanceId().equals(myInstance.getInstanceId())) {
logger.debug("Adding node: " + ins.getInstanceId());
seeds.add(ins.getHostName() + ":" + commonConfig.getStoragePeerPort() + ":" + ins.getRack() + ":"
+ ins.getDatacenter() + ":" + ins.getToken());
}
}
return seeds;
}
public List getClusterInfo() throws UnknownHostException {
List nodes = new LinkedList();
for (AppsInstance ins : factory.getAllIds(envVariables.getDynomiteClusterName())) {
nodes.add(ins);
}
return nodes;
}
public boolean isSeed() {
populateRacMap();
logger.info("Zone " + myInstance.getZone());
String ip = locMap.get(myInstance.getZone()).get(0).getHostName();
return myInstance.getHostName().equals(ip);
}
public boolean isReplace() {
return isReplace;
}
public boolean isTokenPregenerated() {
return isTokenPregenerated;
}
public boolean isNewToken() {
return isNewToken;
}
public String getReplacedIp() {
return replacedIp;
}
public String getTokens() {
return myInstance.getToken();
}
private boolean isInstanceDummy(AppsInstance instance) {
return instance.getInstanceId().equals(DUMMY_INSTANCE_ID);
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy