Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Proposal] karyon 3.x server context #259

Open
qiangdavidliu opened this issue Aug 14, 2015 · 0 comments
Open

[Proposal] karyon 3.x server context #259

qiangdavidliu opened this issue Aug 14, 2015 · 0 comments
Milestone

Comments

@qiangdavidliu
Copy link
Contributor

Karyon server metadata are useful by different components of karyon 3.x. For example karyon3-eureka needs metadata for registration, and karyon3-admin can expose similar metadata for admin purposes.

It would be nice if karyon 3.x exposed a common way to define and store these metadata, and also be able to translate the metadata to other formats for different components to consume.

Some example code below:

/**
 * Marker interface for specific context implementations. This interface explicitly 
 * sets no restrictions on what actual implementations should contain. 
 * Any implementers of an actual context should also need to implement 
 * {@link KaryonContextConverter}s to the necessary components.
 */
public interface KaryonContext {
}
/**
 * A converter definition to translate karyon contexts to other formats for component use
 */
public abstract class KaryonContextConverter<C extends KaryonContext, T> {

    protected final C context;

    protected KaryonContextConverter(C context) {
        this.context = context;
    }

    /**
     * @return the context mapped to and instance of type T
     */
    public abstract T convert();
}
import com.netflix.archaius.annotations.Configuration;
import com.netflix.archaius.annotations.DefaultValue;
import com.netflix.karyon.context.KaryonContext;

/**
 * An implementation of karyon context based on archaius2 property loading 
 */
@Configuration(prefix="karyon.context")
public interface ArchaiusKaryonContext extends KaryonContext {

    String getAppName();

    @DefaultValue("localhost")
    String getHostname();

    @DefaultValue("8080")
    int getPort();
}
import com.netflix.appinfo.InstanceInfo;
import com.netflix.karyon.archaius.context.ArchaiusKaryonContext;
import com.netflix.karyon.context.KaryonContextConverter;

/**
 * An example converter for karyon3-eureka to convert karyon context to an instanceInfo builder
 */
public class ArchaiusKaryonContextConverter extends KaryonContextConverter<ArchaiusKaryonContext, InstanceInfo.Builder> {

    protected ArchaiusKaryonContextConverter(ArchaiusKaryonContext context) {
        super(context);
    }

    @Override
    public InstanceInfo.Builder convert() {
        return InstanceInfo.Builder.newBuilder()
                .setAppName(context.getAppName())
                .setHostName(context.getHostname())
                .setPort(context.getPort());
    }
}
import com.netflix.appinfo.EurekaInstanceConfig;
import com.netflix.appinfo.InstanceInfo;
import com.netflix.appinfo.LeaseInfo;
import com.netflix.karyon.eureka.context.ArchaiusKaryonContextConverter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.inject.Inject;
import javax.inject.Provider;
import java.util.Map;

/**
 * An example eureka InstanceInfo provider that merges data from karyon context as well as eurekaInstanceConfig
 * to resolve the final server InstanceInfo for registration.
 * 
 * @author David Liu
 */
public class KaryonInstanceInfoProvider implements Provider<InstanceInfo> {
    private static final Logger logger = LoggerFactory.getLogger(KaryonInstanceInfoProvider.class);

    private final ArchaiusKaryonContextConverter context;
    private final EurekaInstanceConfig eurekaInstanceConfig;

    private InstanceInfo instanceInfo;

    @Inject
    public KaryonInstanceInfoProvider(ArchaiusKaryonContextConverter context, EurekaInstanceConfig eurekaInstanceConfig) {
        this.context = context;
        this.eurekaInstanceConfig = eurekaInstanceConfig;
    }

    @Override
    public synchronized InstanceInfo get() {
        if (instanceInfo == null) {
            // Build the lease information to be passed to the server based
            // on config
            LeaseInfo.Builder leaseInfoBuilder = LeaseInfo.Builder
                    .newBuilder()
                    .setRenewalIntervalInSecs(eurekaInstanceConfig.getLeaseRenewalIntervalInSeconds())
                    .setDurationInSecs(eurekaInstanceConfig.getLeaseExpirationDurationInSeconds());

            InstanceInfo.Builder builder = context.convert()
                    .setNamespace(eurekaInstanceConfig.getNamespace())
                    .setAppGroupName(eurekaInstanceConfig.getAppGroupName())
                    .setDataCenterInfo(eurekaInstanceConfig.getDataCenterInfo())
                    .setIPAddr(eurekaInstanceConfig.getIpAddress())
                    .enablePort(InstanceInfo.PortType.UNSECURE, eurekaInstanceConfig.isNonSecurePortEnabled())
                    .setSecurePort(eurekaInstanceConfig.getSecurePort())
                    .enablePort(InstanceInfo.PortType.SECURE, eurekaInstanceConfig.getSecurePortEnabled())
                    .setVIPAddress(eurekaInstanceConfig.getVirtualHostName())
                    .setSecureVIPAddress(eurekaInstanceConfig.getSecureVirtualHostName())
                    .setHomePageUrl(eurekaInstanceConfig.getHomePageUrlPath(), eurekaInstanceConfig.getHomePageUrl())
                    .setStatusPageUrl(eurekaInstanceConfig.getStatusPageUrlPath(), eurekaInstanceConfig.getStatusPageUrl())
                    .setHealthCheckUrls(eurekaInstanceConfig.getHealthCheckUrlPath(), eurekaInstanceConfig.getHealthCheckUrl(), eurekaInstanceConfig.getSecureHealthCheckUrl())
                    .setASGName(eurekaInstanceConfig.getASGName());

            // Start off with the STARTING state to avoid traffic
            if (!eurekaInstanceConfig.isInstanceEnabledOnit()) {
                InstanceInfo.InstanceStatus initialStatus = InstanceInfo.InstanceStatus.STARTING;
                logger.info("Setting initial instance status as: " + initialStatus);
                builder.setStatus(initialStatus);
            } else {
                logger.info("Setting initial instance status as: {}. This may be too early for the instance to advertise itself as available. "
                        + "You would instead want to control this via a healthcheck handler.", InstanceInfo.InstanceStatus.UP);
            }

            // Add any user-specific metadata information
            for (Map.Entry<String, String> mapEntry : eurekaInstanceConfig.getMetadataMap().entrySet()) {
                String key = mapEntry.getKey();
                String value = mapEntry.getValue();
                builder.add(key, value);
            }

            instanceInfo = builder.build();
            instanceInfo.setLeaseInfo(leaseInfoBuilder.build());
        }
        return instanceInfo;
    }
}
@elandau elandau modified the milestone: v3.0.1 Dec 2, 2015
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants