Skip to content

Agent-local operations & Consul Intentions #225

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

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package com.ecwid.consul.json;

import com.google.gson.Gson;
import com.google.gson.TypeAdapter;
import com.google.gson.TypeAdapterFactory;
import com.google.gson.reflect.TypeToken;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonToken;
import com.google.gson.stream.JsonWriter;
import java.io.IOException;
import java.security.cert.Certificate;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

public class CertificateChainTypeAdapterFactory implements TypeAdapterFactory {

private final CertificateTypeAdapter certificateTypeAdapter = new CertificateTypeAdapter();

@Override
@SuppressWarnings("unchecked")
public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
Class<? super T> rawType = type.getRawType();
if (!Collection.class.isAssignableFrom(rawType)) {
return null;
}
return new TypeAdapter<T>() {

@Override
public void write(JsonWriter out, T value) throws IOException {
List<Certificate> certificates = (List<Certificate>) value;
if (certificates == null) {
out.nullValue();
} else {
out.beginArray();
for (Certificate certificate : certificates) {
certificateTypeAdapter.write(out, certificate);
}
out.endArray();
}
}

@Override
public T read(JsonReader in) throws IOException {
final List<Certificate> certificates = new ArrayList<>();
in.beginArray();
while (in.peek() == JsonToken.STRING) {
certificates.add(certificateTypeAdapter.read(in));
}
in.endArray();
return (T) certificates;
}
};
}

}
64 changes: 64 additions & 0 deletions src/main/java/com/ecwid/consul/json/CertificateTypeAdapter.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package com.ecwid.consul.json;

import com.google.gson.TypeAdapter;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonToken;
import com.google.gson.stream.JsonWriter;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.security.cert.Certificate;
import java.security.cert.CertificateEncodingException;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.util.Base64;

public class CertificateTypeAdapter extends TypeAdapter<Certificate> {

private static final String BEGIN_CERT = "-----BEGIN CERTIFICATE-----";

private static final String END_CERT = "-----END CERTIFICATE-----";

private static final String LINE_SEPARATOR = System.getProperty("line.separator");

private static final int LINE_LENGTH = 64;

@Override
public void write(JsonWriter out, Certificate value) throws IOException {
if (value == null) {
out.nullValue();
} else {
try {
Base64.Encoder encoder = Base64.getMimeEncoder(
LINE_LENGTH, LINE_SEPARATOR.getBytes(StandardCharsets.UTF_8));
final String encoded = BEGIN_CERT
+ LINE_SEPARATOR
+ new String(encoder.encode(value.getEncoded()), StandardCharsets.UTF_8)
+ LINE_SEPARATOR
+ END_CERT;
out.value(encoded);
} catch (CertificateEncodingException ex) {
throw new IOException(ex);
}
}
}

@Override
public Certificate read(JsonReader in) throws IOException {
if (in.peek() == JsonToken.NULL) {
in.nextNull();
return null;
} else {
String certificate = in.nextString();
try {
return CertificateFactory.getInstance("X509")
.generateCertificate(
new ByteArrayInputStream(
certificate.getBytes(StandardCharsets.UTF_8)));
} catch (CertificateException ex) {
throw new IOException(ex);
}
}
}

}
32 changes: 32 additions & 0 deletions src/main/java/com/ecwid/consul/json/OffsetDateTimeTypeAdapter.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package com.ecwid.consul.json;

import com.google.gson.TypeAdapter;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonToken;
import com.google.gson.stream.JsonWriter;
import java.io.IOException;
import java.time.OffsetDateTime;

public class OffsetDateTimeTypeAdapter extends TypeAdapter<OffsetDateTime> {

@Override
public void write(JsonWriter out, OffsetDateTime value) throws IOException {
if (value == null) {
out.nullValue();
} else {
out.value(value.toString());
}
}

@Override
public OffsetDateTime read(JsonReader in) throws IOException {
if (in.peek() == JsonToken.NULL) {
in.nextNull();
return null;
} else {
String timestamp = in.nextString();
return OffsetDateTime.parse(timestamp);
}
}

}
Original file line number Diff line number Diff line change
@@ -1,21 +1,22 @@
package com.ecwid.consul.transport;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Map;
import java.util.logging.Logger;
import org.apache.http.Header;
import org.apache.http.HeaderIterator;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.*;
import org.apache.http.client.methods.HttpDelete;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.entity.StringEntity;
import org.apache.http.util.EntityUtils;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;
import java.util.stream.StreamSupport;

public abstract class AbstractHttpTransport implements HttpTransport {

private static final Logger log = Logger.getLogger(AbstractHttpTransport.class.getName());
@@ -56,6 +57,19 @@ public HttpResponse makeDeleteRequest(HttpRequest request) {
return executeRequest(httpDelete);
}

@Override
public HttpResponse makePostRequest(HttpRequest request) {
HttpPost httpPost = new HttpPost(request.getUrl());
addHeadersToRequest(httpPost, request.getHeaders());
if (request.getContent() != null) {
httpPost.setEntity(new StringEntity(request.getContent(), StandardCharsets.UTF_8));
} else {
httpPost.setEntity(new ByteArrayEntity(request.getBinaryContent()));
}

return executeRequest(httpPost);
}

/**
* You should override this method to instantiate ready to use HttpClient
*
4 changes: 2 additions & 2 deletions src/main/java/com/ecwid/consul/transport/HttpTransport.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
package com.ecwid.consul.transport;

import java.util.Map;

/**
* @author Vasily Vasilkov (vgv@ecwid.com)
*/
@@ -13,4 +11,6 @@ public interface HttpTransport {

public HttpResponse makeDeleteRequest(HttpRequest request);

public HttpResponse makePostRequest(HttpRequest request);

}
81 changes: 79 additions & 2 deletions src/main/java/com/ecwid/consul/v1/ConsulClient.java
Original file line number Diff line number Diff line change
@@ -11,6 +11,16 @@
import com.ecwid.consul.v1.agent.model.*;
import com.ecwid.consul.v1.catalog.*;
import com.ecwid.consul.v1.catalog.model.*;
import com.ecwid.consul.v1.connect.ConnectClient;
import com.ecwid.consul.v1.connect.ConnectConsulClient;
import com.ecwid.consul.v1.connect.intentions.IntentionDeleteRequest;
import com.ecwid.consul.v1.connect.intentions.IntentionListRequest;
import com.ecwid.consul.v1.connect.intentions.IntentionUpsertRequest;
import com.ecwid.consul.v1.connect.intentions.IntentionsClient;
import com.ecwid.consul.v1.connect.intentions.IntentionsConsulClient;
import com.ecwid.consul.v1.connect.intentions.model.IntentionResponse;
import com.ecwid.consul.v1.connect.model.CaConfigurationRequest;
import com.ecwid.consul.v1.connect.model.CaConfigurationResponse;
import com.ecwid.consul.v1.coordinate.CoordinateClient;
import com.ecwid.consul.v1.coordinate.CoordinateConsulClient;
import com.ecwid.consul.v1.coordinate.model.Datacenter;
@@ -56,6 +66,8 @@ public class ConsulClient implements
AclClient,
AgentClient,
CatalogClient,
ConnectClient,
IntentionsClient,
CoordinateClient,
EventClient,
HealthClient,
@@ -67,6 +79,8 @@ public class ConsulClient implements
private final AclClient aclClient;
private final AgentClient agentClient;
private final CatalogClient catalogClient;
private final ConnectClient connectClient;
private final IntentionsClient intentionsClient;
private final CoordinateClient coordinateClient;
private final EventClient eventClient;
private final HealthClient healthClient;
@@ -79,6 +93,8 @@ public ConsulClient(ConsulRawClient rawClient) {
aclClient = new AclConsulClient(rawClient);
agentClient = new AgentConsulClient(rawClient);
catalogClient = new CatalogConsulClient(rawClient);
connectClient = new ConnectConsulClient(rawClient);
intentionsClient = new IntentionsConsulClient(rawClient);
coordinateClient = new CoordinateConsulClient(rawClient);
eventClient = new EventConsulClient(rawClient);
healthClient = new HealthConsulClient(rawClient);
@@ -209,7 +225,7 @@ public Response<List<Member>> getAgentMembers() {
public Response<Self> getAgentSelf() {
return agentClient.getAgentSelf();
}

@Override
public Response<Self> getAgentSelf(String token) {
return agentClient.getAgentSelf(token);
@@ -335,7 +351,27 @@ public Response<Void> agentReload() {
return agentClient.agentReload();
}

// -------------------------------------------------------------------------------------------
@Override
public Response<AuthorizeResponse> agentAuthorize(AuthorizeRequest authorizeRequest) {
return agentClient.agentAuthorize(authorizeRequest);
}

@Override
public Response<CaRoots> agentCaRoots() {
return agentClient.agentCaRoots();
}

@Override
public Response<LeafCertificate> agentLeafCertificate(String service, String namespace) {
return agentClient.agentLeafCertificate(service, namespace);
}

@Override
public Response<LeafCertificate> agentLeafCertificate(String service) {
return agentClient.agentLeafCertificate(service);
}

// -------------------------------------------------------------------------------------------
// Catalog

@Override
@@ -455,6 +491,47 @@ public Response<CatalogNode> getCatalogNode(String nodeName, QueryParams queryPa
return catalogClient.getCatalogNode(nodeName, queryParams);
}

// -------------------------------------------------------------------------------------------
// Connect

@Override
public Response<com.ecwid.consul.v1.connect.model.CaRoots> connectListCaRoots() {
return connectClient.connectListCaRoots();
}

@Override
public Response<CaConfigurationResponse> connectGetCaConfiguration() {
return connectClient.connectGetCaConfiguration();
}

@Override
public Response<CaConfigurationResponse> connectUpdateCaConfiguration(CaConfigurationRequest request) {
return connectClient.connectUpdateCaConfiguration(request);
}

// -------------------------------------------------------------------------------------------
// Intentions

@Override
public Response<Boolean> createIntention(IntentionUpsertRequest request, String token) {
return intentionsClient.createIntention(request, token);
}

@Override
public Response<Boolean> updateIntention(IntentionUpsertRequest request, String token) {
return intentionsClient.updateIntention(request, token);
}

@Override
public Response<List<IntentionResponse>> listIntentions(IntentionListRequest request, String token) {
return intentionsClient.listIntentions(request, token);
}

@Override
public Response<Boolean> deleteIntention(IntentionDeleteRequest request, String token) {
return intentionsClient.deleteIntention(request, token);
}

// -------------------------------------------------------------------------------------------
// Coordinates

14 changes: 14 additions & 0 deletions src/main/java/com/ecwid/consul/v1/ConsulRawClient.java
Original file line number Diff line number Diff line change
@@ -189,6 +189,20 @@ public HttpResponse makeDeleteRequest(Request request) {
return httpTransport.makeDeleteRequest(httpRequest);
}

public HttpResponse makePostRequest(Request request) {
String url = prepareUrl(agentAddress + request.getEndpoint());
url = Utils.generateUrl(url, request.getUrlParameters());

HttpRequest httpRequest = HttpRequest.Builder.newBuilder()
.setUrl(url)
.addHeaders(Utils.createTokenMap(request.getToken()))
.setContent(request.getContent())
.setBinaryContent(request.getBinaryContent())
.build();

return httpTransport.makePostRequest(httpRequest);
}

private String prepareUrl(String url) {
if (url.contains(" ")) {
// temp hack for old clients who did manual encoding and just use %20
Loading