Giter Club home page Giter Club logo

consul-api's Introduction

consul-api

Build Status

Java client for Consul HTTP API (http://consul.io)

Supports all API endpoints (http://www.consul.io/docs/agent/http.html), all consistency modes and parameters (tags, datacenters etc.)

How to use

ConsulClient client = new ConsulClient("localhost");

// set KV
byte[] binaryData = new byte[] {1,2,3,4,5,6,7};
client.setKVBinaryValue("someKey", binaryData);

client.setKVValue("com.my.app.foo", "foo");
client.setKVValue("com.my.app.bar", "bar");
client.setKVValue("com.your.app.foo", "hello");
client.setKVValue("com.your.app.bar", "world");

// get single KV for key
Response<GetValue> keyValueResponse = client.getKVValue("com.my.app.foo");
System.out.println(keyValueResponse.getValue().getKey() + ": " + keyValueResponse.getValue().getDecodedValue()); // prints "com.my.app.foo: foo"

// get list of KVs for key prefix (recursive)
Response<List<GetValue>> keyValuesResponse = client.getKVValues("com.my");
keyValuesResponse.getValue().forEach(value -> System.out.println(value.getKey() + ": " + value.getDecodedValue())); // prints "com.my.app.foo: foo" and "com.my.app.bar: bar"

//list known datacenters
Response<List<String>> response = client.getCatalogDatacenters();
System.out.println("Datacenters: " + response.getValue());

// register new service
NewService newService = new NewService();
newService.setId("myapp_01");
newService.setName("myapp");
newService.setTags(Arrays.asList("EU-West", "EU-East"));
newService.setPort(8080);
client.agentServiceRegister(newService);

// register new service with associated health check
NewService newService = new NewService();
newService.setId("myapp_02");
newService.setTags(Collections.singletonList("EU-East"));
newService.setName("myapp");
newService.setPort(8080);

NewService.Check serviceCheck = new NewService.Check();
serviceCheck.setScript("/usr/bin/some-check-script");
serviceCheck.setInterval("10s");
newService.setCheck(serviceCheck);

client.agentServiceRegister(newService);

// query for healthy services based on name (returns myapp_01 and myapp_02 if healthy)
HealthServicesRequest request = HealthServicesRequest.newBuilder()
					.setPassing(true)
					.setQueryParams(QueryParams.DEFAULT)
					.build();
Response<List<HealthService>> healthyServices = client.getHealthServices("myapp", request);

// query for healthy services based on name and tag (returns myapp_01 if healthy)
HealthServicesRequest request = HealthServicesRequest.newBuilder()
					.setTag("EU-West")
					.setPassing(true)
					.setQueryParams(QueryParams.DEFAULT)
					.build();
Response<List<HealthService>> healthyServices = client.getHealthServices("myapp", request);

How to add consul-api into your project

Gradle

compile "com.ecwid.consul:consul-api:1.4.5"

Maven

<dependency>
  <groupId>com.ecwid.consul</groupId>
  <artifactId>consul-api</artifactId>
  <version>1.4.5</version>
</dependency>

How to build from sources

  • Checkout the sources
  • ./gradlew build

Gradle will compile sources, package classes (sources and javadocs too) into jars and run all tests. The build results will located in build/libs/ folder

consul-api's People

Contributors

aleksandrserbin avatar cosmin-marian avatar csabakos avatar dimarabkin avatar dindinw avatar dmitryskripunov avatar haleystorm avatar ianmcderp avatar jakubdyszkiewicz avatar johndemic avatar josefeg avatar jostyee avatar kamilszymanski avatar lazystone avatar martinpfannemueller avatar matlockx avatar mikekwright avatar nstdio avatar peka45 avatar porshkevich avatar pwielgolaski avatar ruslansennov avatar sirlatrom avatar skaruppiah avatar spencergibb avatar tbet avatar vgv avatar xiaoshuang-lu avatar yangfuhai avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

consul-api's Issues

Method ConsulClient#getHealthChecksState(QueryParams) leads to improper response

Whenever I call this method response is wrong - it doesn't return anything, but should return check for any state.

As I checked code problem lies with line #93 of HealthConsulClient. I think it should be:
String status = checkStatus == null ? "any" : checkStatus.name().toLowerCase();
instead of
String status = checkStatus == null ? "ANY" : checkStatus.name().toLowerCase();

Asynchronous blocking API

Currently blocking requests have to be made synchronously and there doesn't seem to be any way to cancel a blocked request other than via a timeout:

Response<List<HealthService>> response = client.getHealthServices("myService", false, new QueryParams(timeout, index));

This means having to continually poll periodically which puts more load on the cluster. It would be great to have an async approach instead that eg returned a Future that could be cancelled.

I'd be happy to take a look at implementing this myself and sending a pull request though I won't have much time to do so until the New Year.

Implement CAS support for delete method

Consul (at least of version 0.6) returns boolean value for delete operation that marks it's success (normal deletion) or failure (e.g. cas parameter set to invalid value). It would be quite cool to add same support (ability to pass cas parameter and return boolean value) for client implementation.

QueryParams waitTime and index should be long

In the Consul code, QueryParams.waitTime is an int64 and QueryParam.index is a uint64. It's unlikely the waitTime being an int on the Java side will ever matter but the index being an int is a potential issue. With a busy and long-running Consul cluster an index might eventually exceed 2^31-1, at which point blocking requests will start returning immediately due to the mismatch between client and server.

In theory changing QueryParams.index to a long still doesn't solve the problem completely due to the signed/unsigned mismatch but the likelihood of an index ever getting high enough to matter would be extremely small. Checking for a negative index and writing the parameter as an unsigned value would solve that but I'm not sure it's worth the bother?

How to aquire a value?

Hi, I am trying to implement leader election using this client and I can find aquiring method:

curl -X PUT -d <body> http://localhost:8500/v1/kv/<key>?acquire=<session>

Can I do it somehow?

add socket/connection timeout defaults

Currently the default socket/connection timeouts are undefined at best, likely infinity. I think that it could be good to set something sane for a default. If anyone is worried about this being a problem they could be set to something like 5 minutes. I doubt that anybody wants a request to consul to take greater than 5 minutes.

Currently these can be set by doing.

final DefaultHttpClient httpClient = new DefaultHttpClient();
httpClient.getParams().setParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, 30000);
httpClient.getParams().setParameter(CoreConnectionPNames.SO_TIMEOUT, 60000);
final ConsulRawClient consulRawClient = new ConsulRawClient("www.google.com", 81, httpClient);
final ConsulClient client = new ConsulClient(consulRawClient);
client.getKVBinaryValue("test")

I am using google port 81 because it will not respond to syn's and so will hang forever without the connection timeout set.

Deregistering a service instance - fails in test

The following test code fails:

        NewService service = new NewService();
        service.setAddress("10.20.30.40");
        service.setPort(99);
        service.setId("test-service-1");
        service.setName("Test Service");
       ConsulClient client = new ConsulClient("localhost");
        client.agentServiceRegister(service);
       QueryParams dcQueryParams = new QueryParams("dc1");
        Response<Map<String, List<String>>> servicesResponse =      client.getCatalogServices(dcQueryParams);
        assertThat(servicesResponse.getValue().keySet().size(), equalTo(2));
        assertThat(servicesResponse.getValue().keySet(), hasItem("Test Service"));

        client.agentServiceDeregister("test-service-1");
        servicesResponse = client.getCatalogServices(dcQueryParams);
        assertThat(servicesResponse.getValue().keySet().size(), equalTo(1));
        assertThat(servicesResponse.getValue().keySet(), not(hasItem("Test Service")));

Release Notes/Tags

Any chance we can get release notes and have the releases tagged in github?

list of all services on consul

i !

I need to get list of all services configured on a particular data center.

Can anyone please provide me link or a sample code for that.

Make client interruptible

right now when using long polls its impossible to interrupt/stop/shutdown the client. this means that if i want my application to react to, for example, shutdowns, in a reasonable time i need a short poll period. here's a test case to demonstrate it:

@Test
public void testClientInterruptible() throws Exception {
    ConsulClient client = new ConsulClient("localhost", 8500);
    CountDownLatch latch = new CountDownLatch(1);

    Thread victim = new Thread(() -> {
        long start = System.currentTimeMillis();
        try {
            Long serverIndex = client.getKVValue("someKey").getConsulIndex();
            latch.countDown();
            client.getKVValue("someKey", new QueryParams(10, serverIndex));
        } finally {
            System.err.println("snapped out of it after " + (System.currentTimeMillis() - start) + " millis");
        }
    });
    victim.start();

    long start = System.currentTimeMillis();
    try {
        latch.await();
        Thread.sleep(1000L); //be extra certain
        victim.interrupt(); //attempt to interrupt victim
        victim.join();
    } finally {
        System.err.println("waited " + (System.currentTimeMillis() - start) + " millis");
    }
}

on my machine this prints
snapped out of it after 10567 millis
waited 10581 millis

HTTP Check

In Consul we can add Checks with HTTP and interval.
But in this client, NewCheck does not provide the abitility to add checks based on HTTP.

https://www.consul.io/docs/agent/checks.html
Please add it

Also please provide me a sample to add HealthCheck for a service.

com.ecwid.consul.Util.generateUrl can generate malformed URLs

If a base url is passed into generateUrl with a trailing slash and a single URL parameter then the resulting URL will be malformed.

For example, if ConsulClient.getKeyValues is called with a keyPrefix of "somefolder/somekey/" then the base URL generated by ConsulRawClient.makeGetRequest() is "http://localhost:8500/v1/kv/somefolder/somekey/". If the call to getKeyValues is from KeyValueConsulClient.getKVValues() then a URL parameter of "recurse" will be passed.

In this case ConsulRawClient.makeGetRequest() will pass "http://localhost:8500/v1/kv/somefolder/somekey/" as a base URL and "recurse" as a parameter to
Util.generateUrl() which will return "http://localhost:8500/v1/kv/somefolder/somekey/?recurse" which Consul will always 404 on.

Consul service not reachable. com.ecwid.consul.transport.TransportException: java.net.SocketException: Connection reset

I am trying to diagnose a problem that I don't know if it is a bug in Consul API (1.1.7) or the way I am running Consul (v 0.6). I get the following stack repeatedly in my logs. I'm using the Consul API in conjunction with a Netflix Archaius wrapper but looking at the code I'm not sure it is a bug there. Seems to be an issue with the way Consul API is trying to create a catalog client.

2016-05-04T19:04:29,435 ERROR [net.researchgate.archaius.ConsulConfigurationSource] [pollingConfigurationSource] Consul service not reachable. i-699d84ae: com.ecwid.consul.transport.TransportException: java.net.SocketException: Connection reset
    at com.ecwid.consul.transport.AbstractHttpTransport.executeRequest(AbstractHttpTransport.java:80) [consul-api-1.1.7.jar:]
    at com.ecwid.consul.transport.AbstractHttpTransport.makeGetRequest(AbstractHttpTransport.java:39) [consul-api-1.1.7.jar:]
    at com.ecwid.consul.v1.ConsulRawClient.makeGetRequest(ConsulRawClient.java:81) [consul-api-1.1.7.jar:]
    at com.ecwid.consul.v1.catalog.CatalogConsulClient.getCatalogService(CatalogConsulClient.java:129) [consul-api-1.1.7.jar:]
    at com.ecwid.consul.v1.catalog.CatalogConsulClient.getCatalogService(CatalogConsulClient.java:122) [consul-api-1.1.7.jar:]
    at com.ecwid.consul.v1.ConsulClient.getCatalogService(ConsulClient.java:284) [consul-api-1.1.7.jar:]
    at net.researchgate.archaius.ConsulConfigurationSource.setClient(ConsulConfigurationSource.java:82) [archaius-consul-0.1.2.jar:]
    at net.researchgate.archaius.ConsulConfigurationSource.poll(ConsulConfigurationSource.java:66) [archaius-consul-0.1.2.jar:]
    at com.netflix.config.AbstractPollingScheduler$1.run(AbstractPollingScheduler.java:163) [archaius-core-0.7.3.jar:0.7.3]
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) [rt.jar:1.8.0_72-internal]
    at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:308) [rt.jar:1.8.0_72-internal]
    at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(ScheduledThreadPoolExecutor.java:180) [rt.jar:1.8.0_72-internal]
    at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:294) [rt.jar:1.8.0_72-internal]
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) [rt.jar:1.8.0_72-internal]
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) [rt.jar:1.8.0_72-internal]
    at java.lang.Thread.run(Thread.java:745) [rt.jar:1.8.0_72-internal]
Caused by: java.net.SocketException: Connection reset
    at java.net.SocketInputStream.read(SocketInputStream.java:209) [rt.jar:1.8.0_72-internal]
    at java.net.SocketInputStream.read(SocketInputStream.java:141) [rt.jar:1.8.0_72-internal]
    at org.apache.http.impl.io.AbstractSessionInputBuffer.fillBuffer(AbstractSessionInputBuffer.java:160) [httpcore-4.3.3.jar:4.3.3]
    at org.apache.http.impl.io.SocketInputBuffer.fillBuffer(SocketInputBuffer.java:84) [httpcore-4.3.3.jar:4.3.3]
    at org.apache.http.impl.io.AbstractSessionInputBuffer.readLine(AbstractSessionInputBuffer.java:273) [httpcore-4.3.3.jar:4.3.3]
    at org.apache.http.impl.conn.LoggingSessionInputBuffer.readLine(LoggingSessionInputBuffer.java:116) [httpclient-4.3.6.jar:4.3.6]
    at org.apache.http.impl.conn.DefaultHttpResponseParser.parseHead(DefaultHttpResponseParser.java:140) [httpclient-4.3.6.jar:4.3.6]
    at org.apache.http.impl.conn.DefaultHttpResponseParser.parseHead(DefaultHttpResponseParser.java:57) [httpclient-4.3.6.jar:4.3.6]
    at org.apache.http.impl.io.AbstractMessageParser.parse(AbstractMessageParser.java:260) [httpcore-4.3.3.jar:4.3.3]
    at org.apache.http.impl.AbstractHttpClientConnection.receiveResponseHeader(AbstractHttpClientConnection.java:283) [httpcore-4.3.3.jar:4.3.3]
    at org.apache.http.impl.conn.DefaultClientConnection.receiveResponseHeader(DefaultClientConnection.java:251) [httpclient-4.3.6.jar:4.3.6]
    at org.apache.http.impl.conn.ManagedClientConnectionImpl.receiveResponseHeader(ManagedClientConnectionImpl.java:197) [httpclient-4.3.6.jar:4.3.6]
    at org.apache.http.protocol.HttpRequestExecutor.doReceiveResponse(HttpRequestExecutor.java:271) [httpcore-4.3.3.jar:4.3.3]
    at org.apache.http.protocol.HttpRequestExecutor.execute(HttpRequestExecutor.java:123) [httpcore-4.3.3.jar:4.3.3]
    at org.apache.http.impl.client.DefaultRequestDirector.tryExecute(DefaultRequestDirector.java:685) [httpclient-4.3.6.jar:4.3.6]
    at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:487) [httpclient-4.3.6.jar:4.3.6]
    at org.apache.http.impl.client.AbstractHttpClient.doExecute(AbstractHttpClient.java:863) [httpclient-4.3.6.jar:4.3.6]
    at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:72) [httpclient-4.3.6.jar:4.3.6]
    at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:214) [httpclient-4.3.6.jar:4.3.6]
    at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:160) [httpclient-4.3.6.jar:4.3.6]
    at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:136) [httpclient-4.3.6.jar:4.3.6]
    at com.ecwid.consul.transport.AbstractHttpTransport.executeRequest(AbstractHttpTransport.java:64) [consul-api-1.1.7.jar:]

Followed by 2 Apache http error messages:

Retrying request to {}->http://172.31.2.106:8300
I/O exception (java.net.SocketException) caught when processing request to {}->http://172.31.2.106:8300: Connection reset

A lot of Googling shows similar errors with connection reset on port 8300 saying that the client should be trying to connect to 8301 instead. Is this some problem in the way I have Consul configured or is this a bug in the Consul client?

Thanks!

Allow specifying ACL token to getCatalogServices()

Though apparently undocumented, it is possible, at least in consul 0.6.0, to specify a ?token=<ACL-token> query parameter on the endpoints /v1/catalog/services and /v1/catalog/service/<service>.

Consider this situation: If the "anonymous" token has the following policy (which I'm aware disables DNS discovery, but we're not using that where I work):

service "" {
  policy = "deny"
}

... then snooping individuals will not be able to list registered services and their IP addresses and port numbers. Meanwhile, a client with a different ACL token which provides a policy like the following will be successfully able to list the registered services:

service "" {
  policy = "read"
}

With a setup like the above, it would be very useful indeed to be able to provide an ACL token to the ConsulClient#getCatalogServices() and various ConsulClient#getCatalogService() methods, which would then be passed as a query parameter to the /v1/catalog/services and /v1/catalog/service/<service> endpoints, respectively.

Problem while getting value from KV Store

While using the client to get a value from KV Store we get the following exception:

com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_ARRAY but was STRING at line 1 column 92
        at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:176)
        at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.read(TypeAdapterRuntimeTypeWrapper.java:40)
        at com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.read(CollectionTypeAdapterFactory.java:81)
        at com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.read(CollectionTypeAdapterFactory.java:60)
        at com.google.gson.Gson.fromJson(Gson.java:803)
        at com.google.gson.Gson.fromJson(Gson.java:768)
        at com.google.gson.Gson.fromJson(Gson.java:717)
        at com.ecwid.consul.v1.kv.KeyValueConsulClient.getKVBinaryValue(KeyValueConsulClient.java:114)
        at com.ecwid.consul.v1.kv.KeyValueConsulClient.getKVBinaryValue(KeyValueConsulClient.java:105)
        at com.ecwid.consul.v1.kv.KeyValueConsulClient.getKVBinaryValue(KeyValueConsulClient.java:95)
        at com.ecwid.consul.v1.ConsulClient.getKVBinaryValue(ConsulClient.java:364)
        at

The entry in column 92 starts with rO0AB (e.g."Value":"rO0AB...")

Missing field "name" in Session

I just realized that com.ecwid.consul.v1.session.model.Session is missing the field "name" and the corresponding Getters and Getters. Would it possible to add them in a future release (as in com.ecwid.consul.v1.session.model.NewSession)?

Support tokens in AgentClient

It would be helpful to support ACL tokens in AgentClient. Specifically, some consul deployments may require an application specific acl token to register/deregister services.

The pattern for providing a token exists in the KeyValueClient/KeyValueConsulClient, and the same pattern could be appropriate in the AgentClient.

Another approach would be to provide a default token in the ConsulRawClient, which would probably cover the majority of use cases.

QueryParams.toUrlParameters() should treat index as unsigned

If a negative (signed) long is passed in for the index, the request fails with a 400 error. Consul expects an unsigned long value instead.

I've hit this problem in practice when I'm trying to make blocking ConsulClient.eventList() calls. The indexes I need to supply are generated from a UUID and hence often end up as a negative value when represented as a signed long.

QueryParams.toUrlParameters() currently contains:

params.add("index=" + index);

I think it should actually be:

params.add("index=" + Long.toUnsignedString(index));

That assumes Java 8. Otherwise something like this should work for the conversion:

  private static String toUnsignedString(long l) {
    if (l > 0) {
      return Long.toString(l);
    } else {
      long quot = (l >>> 1) / 5;
      long rem = l - quot * 10;
      return Long.toString(quot) + rem;
    }
  }

Provide content of http response in exception

I found that OperationException I was experiencing is related to invalid session id being passed to /v1/kv?acquire=.... Exception doesn't have such information and reads just like OperationException{statusCode=500, statusMessage='Internal Server Error'}. See hashicorp/consul#1139 that consul actually responds with proper message which much more useful than standard HTTP error phrase.

Accessing consul behind a proxy

Consul instances behind a proxy may have a different application path. For example: http://server:8000/**consul**/v1/kv/...

If a consul instance behind a proxy, that has a different application path, needs to be accessed with consul-api it will not be possible to configure the necessary consul URL given the current set of constructors in ConsulClient. A constructor accepting the base application path is needed.

Pass token for catalog service

Would be nice if catalog service accepts token as well, for now I'm using this wrapper:

class CustomRawClient extends ConsulRawClient {
    private String token;

    public CustomRawClient(String token, String agentHost, int agentPort) {
        super(agentHost, agentPort);
        this.token = token;
    }

    public RawResponse makeGetRequest(String endpoint, UrlParameters... urlParams) {
        return super.makeGetRequest(endpoint, this.appendToken(urlParams));
    }

    public RawResponse makePutRequest(String endpoint, String content, UrlParameters... urlParams) {
        return super.makePutRequest(endpoint, content, this.appendToken(urlParams));
    }

    public RawResponse makePutRequest(String endpoint, byte[] content, UrlParameters... urlParams) {
        return super.makePutRequest(endpoint, content, this.appendToken(urlParams));
    }

    public RawResponse makeDeleteRequest(String endpoint, UrlParameters... urlParams) {
        return super.makeDeleteRequest(endpoint, this.appendToken(urlParams));
    }

    private UrlParameters[] appendToken(UrlParameters... urlParams) {
        UrlParameters tokenParam = new SingleUrlParameters("token", this.token);
        List<UrlParameters> params = new ArrayList<>();
        params.addAll(Arrays.asList(urlParams));
        params.add(tokenParam);
        return params.toArray(new UrlParameters[params.size()]);
    }
}

Usage:

CustomRawClient rawClient = new CustomRawClient("secret", "127.0.0.1", 8500);
ConsulClient client = new ConsulClient(rawClient);
...

Add client support for Watches

It would be great if real-time notification of config changes (KV data changes) were possible on the client-side.

I believe this concept is supported in the "raw" Consult API via watches, however I don't see that concept supported by this library.

The idea is simple:

  • Allow clients to register their own callbacks/watches with the Consul cluster
  • The callback/watch will now execute when the cluster senses a change to config data (or anything really)

The idea is to allow GOSSIP to "do its thing" and update clients in real-time, rather than forcing clients to poll.

Add getKVValueString() convenience methods to KeyValueClient that do base64 decoding

When accessing strings stored in Consul Key-Value store, the value is always returned in base64 encoding.

KeyValueClient provides the getKVValue() and getKVBinaryValue() family of functions for retrieving values, but in both cases a manual conversion step is needed to reconstruct the original string: base64 decoding is needed after getKVValue(), and byte[] to String conversion is needed after getKVBinaryValue().

It would be nice to introduce a getKVValueString() family of convenience functions that does this manual conversion step automatically.

no support for https

It appears ConsulRawClient is hardcoded for http. Consul supports TLS connections so the client needs to support https.

Response objects do not contain all available consul fields

Ignore this issue… I found it ;D

This is an example response from a GET request.

{
"CreateIndex": 100,
"ModifyIndex": 200,
"LockIndex": 200,
"Key": "zip",
"Flags": 0,
"Value": "dGVzdA==",
"Session": "adf4238a-882b-9ddc-4a9d-5b6758e4159e"
}

The most important missing piece is the session.
I need the session of a lock to check if it still acquired and by who.

Any plans on adding that? Or do you have another way to check the locks session?

Attempt to get info for non-existing session end up in NPE

The call is as simple as

this.sessionClient.getSessionInfo(this.sessionId, new QueryParams(-1, -1));

The result is

java.lang.NullPointerException: null
    at com.ecwid.consul.v1.session.SessionConsulClient.getSessionInfo(SessionConsulClient.java:73)

exception error messages

Whenever I log exceptions from this api there are no exception messages. I see

! com.ecwid.consul.v1.OperationException: null

It would be nice to have a message that make sense, rather than having to catch the OperationException and read the statusCode and statusMessage off of it.

Also this help if I log exc.getMessage() which is helpful if you are logging a warning (because you are going to retry) and do not want to get the entire stack

P.S. on a semi relate note, is there a reason that the ConsulException is Runtime and not IO? I usually like to force people to catch exceptions rather than making them remember that this runtime exception could occur.

2-way SSL from Spring to Consul fails. (Keystore is not being read)

We have a very simple application. All it does is read KVs from Consul. During SSL handshake, the client fails to send the client certificate resulting in bad certificate error. What we found was that ID keystore specified in command line JVM param -Djavax.net.ssl.keyStore was not being read. Appears to be a bug in the library. While debugging through the code, we saw that Spring Consul library is using deprecated classes of http client. Is that the reason we are seeing this issue?

Here is the code. We have a single file.

com.test.TestApp.java;

package com.test;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;


/**
 * Main Spring Boot Application class for
 * the TestApp Consul implementation.
 */
@SpringBootApplication
public class TestApp {

    public static void main(String[] args) {
        SpringApplication app = new SpringApplication( TestApp.class );
        app.run( args );
    }

}

Here is the gradle build file:

buildscript {
    ext {
        springBootVersion = '1.3.5.RELEASE'
    }
    repositories {
        mavenLocal()
        maven { url "http://artifactory:8081/artifactory/repo" }
        mavenCentral()
        maven { url "http://repo.spring.io/libs-release" }
    }
    dependencies {
        classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}") 
        classpath('io.spring.gradle:dependency-management-plugin:0.6.0.RELEASE')
    }
}

apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'idea'
apply plugin: 'spring-boot' 
apply plugin: 'io.spring.dependency-management' 

jar {
    baseName = 'TestApp'
    version = '1.0.3'
}
sourceCompatibility = 1.8
targetCompatibility = 1.8

repositories {
    mavenLocal()
    maven { url "http://artifactory:8081/artifactory/repo" }
    mavenCentral()
    maven { url "http://repo.spring.io/libs-release" }
    maven { url "http://repo.spring.io/libs-milestone" }
}

dependencies {
    compile('org.springframework.boot:spring-boot-starter-actuator')
    compile('org.springframework.boot:spring-boot-configuration-processor')
    compile('org.springframework.cloud:spring-cloud-starter-consul-all')
    testCompile('org.springframework.boot:spring-boot-starter-test') 
    testCompile('org.mockito:mockito-all:1.10.19')
}

dependencyManagement {
    imports { 
        mavenBom "org.springframework.cloud:spring-cloud-starter-parent:Brixton.SR5" 
        mavenBom "org.springframework.cloud:spring-cloud-consul-dependencies:1.0.2.RELEASE" 
    }
}

task sourcesJar(type: Jar, dependsOn: classes) {
    classifier = 'sources'
    from sourceSets.main.allSource
}
artifacts {
    archives sourcesJar
}

eclipse {
    classpath {
         containers.remove('org.eclipse.jdt.launching.JRE_CONTAINER')
         containers 'org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8'
    }
}

task wrapper(type: Wrapper) {
    gradleVersion = '2.14'
}

def filesToCopy = copySpec {
    from 'build/libs/'
    include '*SHOT.jar'
}

Here is the log file contents with SSL debug enabled:

2016-08-30 13:35:51.292  INFO 34035 --- [           main] s.c.a.AnnotationConfigApplicationContext : Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@608416bd: startup date [Tue Aug 30 13:35:51 CDT 2016]; root of context hierarchy
2016-08-30 13:35:52.023  INFO 34035 --- [           main] f.a.AutowiredAnnotationBeanPostProcessor : JSR-330 'javax.inject.Inject' annotation found and supported for autowiring
2016-08-30 13:35:52.107  INFO 34035 --- [           main] trationDelegate$BeanPostProcessorChecker : Bean 'configurationPropertiesRebinderAutoConfiguration' of type [class org.springframework.cloud.autoconfigure.ConfigurationPropertiesRebinderAutoConfiguration$$EnhancerBySpringCGLIB$$4dc2a8d4] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
trustStore is: /<REDACTED>
trustStore type is : jks
trustStore provider is :
init truststore
adding as trusted cert:
<REDACTED>
trigger seeding of SecureRandom
done seeding SecureRandom

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v1.3.5.RELEASE)

Ignoring unavailable cipher suite: TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA
Ignoring unavailable cipher suite: TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA
Ignoring unavailable cipher suite: TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
Ignoring unavailable cipher suite: TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA
Ignoring unavailable cipher suite: TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
Ignoring unavailable cipher suite: TLS_ECDH_RSA_WITH_AES_128_CBC_SHA
Ignoring unavailable cipher suite: TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256
Ignoring unavailable cipher suite: TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA
Ignoring unavailable cipher suite: TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384
Ignoring unavailable cipher suite: TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384
Ignoring unavailable cipher suite: TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256
Ignoring unavailable cipher suite: TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384
Ignoring unavailable cipher suite: TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA
Ignoring unavailable cipher suite: TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256
Ignoring unavailable cipher suite: TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384
Ignoring unavailable cipher suite: TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256
Ignoring unavailable cipher suite: TLS_ECDH_RSA_WITH_AES_256_CBC_SHA
Ignoring unavailable cipher suite: TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA
Ignoring unavailable cipher suite: TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384
Ignoring unavailable cipher suite: TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA
Ignoring unavailable cipher suite: TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256
Ignoring unavailable cipher suite: TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA
Ignoring unavailable cipher suite: TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384
Ignoring unavailable cipher suite: TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA
Ignoring unavailable cipher suite: TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256
Ignoring unavailable cipher suite: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
Ignoring unavailable cipher suite: TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA
Ignoring unavailable cipher suite: TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
main, setSoTimeout(60000) called
Allow unsafe renegotiation: false
Allow legacy hello messages: true
Is initial handshake: true
Is secure renegotiation: false
Ignoring unsupported cipher suite: TLS_RSA_WITH_AES_256_CBC_SHA256 for TLSv1
Ignoring unsupported cipher suite: TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 for TLSv1
Ignoring unsupported cipher suite: TLS_DHE_DSS_WITH_AES_256_CBC_SHA256 for TLSv1
Ignoring unsupported cipher suite: TLS_RSA_WITH_AES_256_CBC_SHA256 for TLSv1.1
Ignoring unsupported cipher suite: TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 for TLSv1.1
Ignoring unsupported cipher suite: TLS_DHE_DSS_WITH_AES_256_CBC_SHA256 for TLSv1.1
%% No cached client session
*** ClientHello, TLSv1.2
RandomCookie:  GMT: 1455739401 bytes = { 131, 144, 62, 92, 121, 62, 206, 192, 62, 91, 69, 244, 64, 45, 201, 1, 95, 138, 111, 228, 1, 200, 50, 90, 207, 86, 60, 197 }
Session ID:  {}
Cipher Suites: [TLS_RSA_WITH_AES_256_CBC_SHA256, TLS_DHE_RSA_WITH_AES_256_CBC_SHA256, TLS_DHE_DSS_WITH_AES_256_CBC_SHA256, TLS_RSA_WITH_AES_256_CBC_SHA, TLS_DHE_RSA_WITH_AES_256_CBC_SHA, TLS_DHE_DSS_WITH_AES_256_CBC_SHA, TLS_RSA_WITH_AES_128_CBC_SHA256, TLS_DHE_RSA_WITH_AES_128_CBC_SHA256, TLS_DHE_DSS_WITH_AES_128_CBC_SHA256, TLS_RSA_WITH_AES_128_CBC_SHA, TLS_DHE_RSA_WITH_AES_128_CBC_SHA, TLS_DHE_DSS_WITH_AES_128_CBC_SHA, TLS_RSA_WITH_AES_256_GCM_SHA384, TLS_DHE_RSA_WITH_AES_256_GCM_SHA384, TLS_DHE_DSS_WITH_AES_256_GCM_SHA384, TLS_RSA_WITH_AES_128_GCM_SHA256, TLS_DHE_RSA_WITH_AES_128_GCM_SHA256, TLS_DHE_DSS_WITH_AES_128_GCM_SHA256, SSL_RSA_WITH_3DES_EDE_CBC_SHA, SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA, SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA, TLS_EMPTY_RENEGOTIATION_INFO_SCSV]
Compression Methods:  { 0 }
Extension signature_algorithms, signature_algorithms: SHA512withECDSA, SHA512withRSA, SHA384withECDSA, SHA384withRSA, SHA256withECDSA, SHA256withRSA, SHA224withECDSA, SHA224withRSA, SHA1withECDSA, SHA1withRSA, SHA1withDSA
***
[write] MD5 and SHA1 hashes:  len = 117
0000: 01 00 00 71 03 03 57 C5   D2 09 83 90 3E 5C 79 3E  ...q..W.....>\y>
0010: CE C0 3E 5B 45 F4 40 2D   C9 01 5F 8A 6F E4 01 C8  ..>[E.@-.._.o...
0020: 32 5A CF 56 3C C5 00 00   2C 00 3D 00 6B 00 6A 00  2Z.V<...,.=.k.j.
0030: 35 00 39 00 38 00 3C 00   67 00 40 00 2F 00 33 00  5.9.8.<.g.@./.3.
0040: 32 00 9D 00 9F 00 A3 00   9C 00 9E 00 A2 00 0A 00  2...............
0050: 16 00 13 00 FF 01 00 00   1C 00 0D 00 18 00 16 06  ................
0060: 03 06 01 05 03 05 01 04   03 04 01 03 03 03 01 02  ................
0070: 03 02 01 02 02                                     .....
main, WRITE: TLSv1.2 Handshake, length = 117
[Raw write]: length = 122
0000: 16 03 03 00 75 01 00 00   71 03 03 57 C5 D2 09 83  ....u...q..W....
0010: 90 3E 5C 79 3E CE C0 3E   5B 45 F4 40 2D C9 01 5F  .>\y>..>[E.@-.._
0020: 8A 6F E4 01 C8 32 5A CF   56 3C C5 00 00 2C 00 3D  .o...2Z.V<...,.=
0030: 00 6B 00 6A 00 35 00 39   00 38 00 3C 00 67 00 40  .k.j.5.9.8.<.g.@
0040: 00 2F 00 33 00 32 00 9D   00 9F 00 A3 00 9C 00 9E  ./.3.2..........
0050: 00 A2 00 0A 00 16 00 13   00 FF 01 00 00 1C 00 0D  ................
0060: 00 18 00 16 06 03 06 01   05 03 05 01 04 03 04 01  ................
0070: 03 03 03 01 02 03 02 01   02 02                    ..........
[Raw read]: length = 5
0000: 16 03 03 00 31                                     ....1
[Raw read]: length = 49
0000: 02 00 00 2D 03 03 33 39   BD CB CE 4B E2 D5 30 19  ...-..39...K..0.
0010: 56 D9 F3 E4 BC 67 D2 C6   A6 90 23 0F 58 CF 2D FF  V....g....#.X.-.
0020: E3 18 17 5C A8 13 00 00   35 00 00 05 FF 01 00 01  ...\....5.......
0030: 00                                                 .
main, READ: TLSv1.2 Handshake, length = 49
*** ServerHello, TLSv1.2
RandomCookie:  GMT: 859356363 bytes = { 206, 75, 226, 213, 48, 25, 86, 217, 243, 228, 188, 103, 210, 198, 166, 144, 35, 15, 88, 207, 45, 255, 227, 24, 23, 92, 168, 19 }
Session ID:  {}
Cipher Suite: TLS_RSA_WITH_AES_256_CBC_SHA
Compression Method: 0
Extension renegotiation_info, renegotiated_connection: <empty>
***
%% Initialized:  [Session-1, TLS_RSA_WITH_AES_256_CBC_SHA]
** TLS_RSA_WITH_AES_256_CBC_SHA
[read] MD5 and SHA1 hashes:  len = 49
0000: 02 00 00 2D 03 03 33 39   BD CB CE 4B E2 D5 30 19  ...-..39...K..0.
0010: 56 D9 F3 E4 BC 67 D2 C6   A6 90 23 0F 58 CF 2D FF  V....g....#.X.-.
0020: E3 18 17 5C A8 13 00 00   35 00 00 05 FF 01 00 01  ...\....5.......
0030: 00                                                 .
[Raw read]: length = 5
0000: 16 03 03 09 3B                                     ....;
[Raw read]: length = 2363
<REDACTED>
main, READ: TLSv1.2 Handshake, length = 2363
*** Certificate chain
chain [0] = [
<REDACTED>
]
  Algorithm: [SHA256withRSA]
  Signature:
]
chain [1] = [
[
<REDACTED>
]

]
  Algorithm: [SHA1withRSA]
  Signature:
<REDACTED>
]
***
Found trusted certificate:
[
[
REDACTED]
]

]
  Algorithm: [SHA1withRSA]
  Signature:
REDACTED
]
[read] MD5 and SHA1 hashes:  len = 2363
REDACTED
[Raw read]: length = 5
REDACTED
[Raw read]: length = 97
REDACTED

main, READ: TLSv1.2 Handshake, length = 97
*** CertificateRequest
Cert Types: RSA, ECDSA
Supported Signature Algorithms: SHA256withRSA, SHA256withECDSA, SHA384withRSA, SHA384withECDSA, SHA1withRSA, SHA1withECDSA
Cert Authorities:
REDACTED
[read] MD5 and SHA1 hashes:  len = 97
REDACTED
[Raw read]: length = 5
REDACTED
[Raw read]: length = 4
REDACTED
main, READ: TLSv1.2 Handshake, length = 4
*** ServerHelloDone
[read] MD5 and SHA1 hashes:  len = 4
0000: 0E 00 00 00                                        ....
Warning: no suitable certificate found - continuing without client authentication
*** Certificate chain
<Empty>
***
*** ClientKeyExchange, RSA PreMasterSecret, TLSv1.2
[write] MD5 and SHA1 hashes:  len = 269
REDACTED
main, WRITE: TLSv1.2 Handshake, length = 269
[Raw write]: length = 274
REDACTED
SESSION KEYGEN:
PreMaster Secret:
REDACTED
CONNECTION KEYGEN:
Client Nonce:
REDACTED
Server Nonce:
REDACTED
Master Secret:
REDACTED
Client MAC write Secret:
REDACTED
Server MAC write Secret:
REDACTED
Client write key:
REDACTED
Server write key:
REDACTED
... no IV derived for this protocol
main, WRITE: TLSv1.2 Change Cipher Spec, length = 1
[Raw write]: length = 6
0000: 14 03 03 00 01 01                                  ......
*** Finished
verify_data:  { 3, 113, 121, 151, 216, 225, 246, 250, 255, 32, 107, 196 }
***
[write] MD5 and SHA1 hashes:  len = 16
REDACTED
Padded plaintext before ENCRYPTION:  len = 64
REDACTED
main, WRITE: TLSv1.2 Handshake, length = 64
main, waiting for close_notify or alert: state 1
[Raw read]: length = 5
0000: 15 03 03 00 02                                     .....
[Raw read]: length = 2
0000: 02 2A                                              .*
main, READ: TLSv1.2 Alert, length = 2
main, RECV TLSv1.2 ALERT:  fatal, bad_certificate
%% Invalidated:  [Session-1, TLS_RSA_WITH_AES_256_CBC_SHA]
main, called closeSocket()
main, Exception while waiting for close javax.net.ssl.SSLHandshakeException: Received fatal alert: bad_certificate
main, handling exception: javax.net.ssl.SSLHandshakeException: Received fatal alert: bad_certificate
main, called close()
main, called closeInternal(true)
2016-08-30 13:35:53.922 ERROR 34035 --- [           main] o.s.c.c.c.ConsulPropertySourceLocator    : Fail fast is set and there was an error reading configuration from consul.
2016-08-30 13:35:53.925 ERROR 34035 --- [           main] o.s.boot.SpringApplication               : Application startup failed

com.ecwid.consul.transport.TransportException: javax.net.ssl.SSLHandshakeException: Received fatal alert: bad_certificate
        at com.ecwid.consul.transport.AbstractHttpTransport.executeRequest(AbstractHttpTransport.java:91) ~[consul-api-1.1.10.jar!/:na]
        at com.ecwid.consul.transport.AbstractHttpTransport.makeGetRequest(AbstractHttpTransport.java:50) ~[consul-api-1.1.10.jar!/:na]
        at com.ecwid.consul.v1.ConsulRawClient.makeGetRequest(ConsulRawClient.java:81) ~[consul-api-1.1.10.jar!/:na]
        at com.ecwid.consul.v1.kv.KeyValueConsulClient.getKVValues(KeyValueConsulClient.java:150) ~[consul-api-1.1.10.jar!/:na]
        at com.ecwid.consul.v1.ConsulClient.getKVValues(ConsulClient.java:404) ~[consul-api-1.1.10.jar!/:na]
        at org.springframework.cloud.consul.config.ConsulPropertySource.init(ConsulPropertySource.java:64) ~[spring-cloud-consul-config-1.0.2.RELEASE.jar!/:1.0.2.RELEASE]
        at org.springframework.cloud.consul.config.ConsulPropertySourceLocator.create(ConsulPropertySourceLocator.java:135) ~[spring-cloud-consul-config-1.0.2.RELEASE.jar!/:1.0.2.RELEASE]
        at org.springframework.cloud.consul.config.ConsulPropertySourceLocator.locate(ConsulPropertySourceLocator.java:113) ~[spring-cloud-consul-config-1.0.2.RELEASE.jar!/:1.0.2.RELEASE]
        at org.springframework.cloud.bootstrap.config.PropertySourceBootstrapConfiguration.initialize(PropertySourceBootstrapConfiguration.java:89) ~[spring-cloud-context-1.1.0.RELEASE.jar!/:1.1.0.RELEASE]
        at org.springframework.boot.SpringApplication.applyInitializers(SpringApplication.java:640) ~[spring-boot-1.3.5.RELEASE.jar!/:1.3.5.RELEASE]
        at org.springframework.boot.SpringApplication.createAndRefreshContext(SpringApplication.java:343) ~[spring-boot-1.3.5.RELEASE.jar!/:1.3.5.RELEASE]
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:307) ~[spring-boot-1.3.5.RELEASE.jar!/:1.3.5.RELEASE]
        at com.test.TestApp.main(TestApp.java:23) [TestApp-1.0.3.jar!/:na]
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_101]
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_101]
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_101]
        at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_101]
        at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:54) [TestApp-1.0.3.jar!/:na]
        at java.lang.Thread.run(Thread.java:745) [na:1.8.0_101]
Caused by: javax.net.ssl.SSLHandshakeException: Received fatal alert: bad_certificate
        at sun.security.ssl.Alerts.getSSLException(Alerts.java:192) ~[na:1.8.0_101]
        at sun.security.ssl.Alerts.getSSLException(Alerts.java:154) ~[na:1.8.0_101]
        at sun.security.ssl.SSLSocketImpl.recvAlert(SSLSocketImpl.java:2023) ~[na:1.8.0_101]
        at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1125) ~[na:1.8.0_101]
        at sun.security.ssl.SSLSocketImpl.waitForClose(SSLSocketImpl.java:1769) ~[na:1.8.0_101]
        at sun.security.ssl.HandshakeOutStream.flush(HandshakeOutStream.java:124) ~[na:1.8.0_101]
        at sun.security.ssl.Handshaker.sendChangeCipherSpec(Handshaker.java:1083) ~[na:1.8.0_101]
        at sun.security.ssl.ClientHandshaker.sendChangeCipherAndFinish(ClientHandshaker.java:1222) ~[na:1.8.0_101]
        at sun.security.ssl.ClientHandshaker.serverHelloDone(ClientHandshaker.java:1134) ~[na:1.8.0_101]
        at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:348) ~[na:1.8.0_101]
        at sun.security.ssl.Handshaker.processLoop(Handshaker.java:979) ~[na:1.8.0_101]
        at sun.security.ssl.Handshaker.process_record(Handshaker.java:914) ~[na:1.8.0_101]
        at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1062) ~[na:1.8.0_101]
        at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1375) ~[na:1.8.0_101]
        at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1403) ~[na:1.8.0_101]
        at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1387) ~[na:1.8.0_101]
        at org.apache.http.conn.ssl.SSLSocketFactory.connectSocket(SSLSocketFactory.java:543) ~[httpclient-4.5.jar!/:4.5]
        at org.apache.http.conn.ssl.SSLSocketFactory.connectSocket(SSLSocketFactory.java:409) ~[httpclient-4.5.jar!/:4.5]
        at org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:177) ~[httpclient-4.5.jar!/:4.5]
        at org.apache.http.impl.conn.ManagedClientConnectionImpl.open(ManagedClientConnectionImpl.java:304) ~[httpclient-4.5.jar!/:4.5]
        at org.apache.http.impl.client.DefaultRequestDirector.tryConnect(DefaultRequestDirector.java:611) ~[httpclient-4.5.jar!/:4.5]
        at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:446) ~[httpclient-4.5.jar!/:4.5]
        at org.apache.http.impl.client.AbstractHttpClient.doExecute(AbstractHttpClient.java:882) ~[httpclient-4.5.jar!/:4.5]
        at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:71) ~[httpclient-4.5.jar!/:4.5]
        at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:220) ~[httpclient-4.5.jar!/:4.5]
        at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:164) ~[httpclient-4.5.jar!/:4.5]
        at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:139) ~[httpclient-4.5.jar!/:4.5]
        at com.ecwid.consul.transport.AbstractHttpTransport.executeRequest(AbstractHttpTransport.java:75) ~[consul-api-1.1.10.jar!/:na]
        ... 18 common frames omitted

2016-08-30 13:35:53.938  INFO 34035 --- [           main] .b.l.ClasspathLoggingApplicationListener : Application failed to start with classpath: [jar:file:REDACTED, jar:file:REDACTED/]
Exception in thread "main" java.lang.RuntimeException: java.lang.reflect.InvocationTargetException
        at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:62)
        at java.lang.Thread.run(Thread.java:745)
Caused by: java.lang.reflect.InvocationTargetException
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:54)
        ... 1 more
Caused by: com.ecwid.consul.transport.TransportException: javax.net.ssl.SSLHandshakeException: Received fatal alert: bad_certificate
        at com.ecwid.consul.transport.AbstractHttpTransport.executeRequest(AbstractHttpTransport.java:91)
        at com.ecwid.consul.transport.AbstractHttpTransport.makeGetRequest(AbstractHttpTransport.java:50)
        at com.ecwid.consul.v1.ConsulRawClient.makeGetRequest(ConsulRawClient.java:81)
        at com.ecwid.consul.v1.kv.KeyValueConsulClient.getKVValues(KeyValueConsulClient.java:150)
        at com.ecwid.consul.v1.ConsulClient.getKVValues(ConsulClient.java:404)
        at org.springframework.cloud.consul.config.ConsulPropertySource.init(ConsulPropertySource.java:64)
        at org.springframework.cloud.consul.config.ConsulPropertySourceLocator.create(ConsulPropertySourceLocator.java:135)
        at org.springframework.cloud.consul.config.ConsulPropertySourceLocator.locate(ConsulPropertySourceLocator.java:113)
        at org.springframework.cloud.bootstrap.config.PropertySourceBootstrapConfiguration.initialize(PropertySourceBootstrapConfiguration.java:89)
        at org.springframework.boot.SpringApplication.applyInitializers(SpringApplication.java:640)
        at org.springframework.boot.SpringApplication.createAndRefreshContext(SpringApplication.java:343)
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:307)
        at com.test.TestApp.main(TestApp.java:23)
        ... 6 more
Caused by: javax.net.ssl.SSLHandshakeException: Received fatal alert: bad_certificate
        at sun.security.ssl.Alerts.getSSLException(Alerts.java:192)
        at sun.security.ssl.Alerts.getSSLException(Alerts.java:154)
        at sun.security.ssl.SSLSocketImpl.recvAlert(SSLSocketImpl.java:2023)
        at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1125)
        at sun.security.ssl.SSLSocketImpl.waitForClose(SSLSocketImpl.java:1769)
        at sun.security.ssl.HandshakeOutStream.flush(HandshakeOutStream.java:124)
        at sun.security.ssl.Handshaker.sendChangeCipherSpec(Handshaker.java:1083)
        at sun.security.ssl.ClientHandshaker.sendChangeCipherAndFinish(ClientHandshaker.java:1222)
        at sun.security.ssl.ClientHandshaker.serverHelloDone(ClientHandshaker.java:1134)
        at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:348)
        at sun.security.ssl.Handshaker.processLoop(Handshaker.java:979)
        at sun.security.ssl.Handshaker.process_record(Handshaker.java:914)
        at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1062)
        at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1375)
        at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1403)
        at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1387)
        at org.apache.http.conn.ssl.SSLSocketFactory.connectSocket(SSLSocketFactory.java:543)
        at org.apache.http.conn.ssl.SSLSocketFactory.connectSocket(SSLSocketFactory.java:409)
        at org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:177)
        at org.apache.http.impl.conn.ManagedClientConnectionImpl.open(ManagedClientConnectionImpl.java:304)
        at org.apache.http.impl.client.DefaultRequestDirector.tryConnect(DefaultRequestDirector.java:611)
        at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:446)
        at org.apache.http.impl.client.AbstractHttpClient.doExecute(AbstractHttpClient.java:882)
        at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:71)
        at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:220)
        at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:164)
        at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:139)
        at com.ecwid.consul.transport.AbstractHttpTransport.executeRequest(AbstractHttpTransport.java:75)
        ... 18 more

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.