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

Agent-local operations & Consul Intentions #225

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
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());
Expand Down Expand Up @@ -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
*
Expand Down
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 ([email protected])
*/
Expand All @@ -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
Expand Up @@ -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;
Expand Down Expand Up @@ -56,6 +66,8 @@ public class ConsulClient implements
AclClient,
AgentClient,
CatalogClient,
ConnectClient,
IntentionsClient,
CoordinateClient,
EventClient,
HealthClient,
Expand All @@ -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;
Expand All @@ -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);
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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

Expand Down
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
Expand Up @@ -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
Expand Down
Loading