finish cert upload impl

This commit is contained in:
Mengyi Zhou 2015-10-30 14:11:41 +08:00
parent 5fe9dce08c
commit b5220207eb
5 changed files with 137 additions and 26 deletions

View file

@ -2,16 +2,15 @@ package com.ctrip.zeus.client;
import com.ctrip.zeus.auth.impl.IPAuthenticationFilter; import com.ctrip.zeus.auth.impl.IPAuthenticationFilter;
import com.ctrip.zeus.auth.impl.TokenManager; import com.ctrip.zeus.auth.impl.TokenManager;
import com.netflix.config.DynamicBooleanProperty;
import com.netflix.config.DynamicIntProperty; import com.netflix.config.DynamicIntProperty;
import com.netflix.config.DynamicPropertyFactory; import com.netflix.config.DynamicPropertyFactory;
import org.glassfish.jersey.client.ClientConfig; import org.glassfish.jersey.client.ClientConfig;
import org.glassfish.jersey.client.ClientProperties; import org.glassfish.jersey.client.ClientProperties;
import org.glassfish.jersey.media.multipart.MultiPartFeature;
import org.glassfish.jersey.uri.UriComponent; import org.glassfish.jersey.uri.UriComponent;
import javax.ws.rs.client.Client; import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder; import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.Invocation;
import javax.ws.rs.client.WebTarget; import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.MultivaluedHashMap; import javax.ws.rs.core.MultivaluedHashMap;
import javax.ws.rs.core.MultivaluedMap; import javax.ws.rs.core.MultivaluedMap;
@ -28,10 +27,12 @@ public abstract class AbstractRestClient {
private static DynamicIntProperty readTimeout = DynamicPropertyFactory.getInstance().getIntProperty("client.read.timeout", 30000); private static DynamicIntProperty readTimeout = DynamicPropertyFactory.getInstance().getIntProperty("client.read.timeout", 30000);
protected AbstractRestClient(String url) { protected AbstractRestClient(String url) {
ClientConfig config = new ClientConfig(); Client client = ClientBuilder.newBuilder()
Client client = ClientBuilder.newClient(config); .withConfig(new ClientConfig())
.register(MultiPartFeature.class)
.build();
client.property(ClientProperties.CONNECT_TIMEOUT, connectTimeout.get()); client.property(ClientProperties.CONNECT_TIMEOUT, connectTimeout.get());
client.property(ClientProperties.READ_TIMEOUT,readTimeout.get()); client.property(ClientProperties.READ_TIMEOUT, readTimeout.get());
webTarget = client.target(url); webTarget = client.target(url);
} }
@ -39,11 +40,11 @@ public abstract class AbstractRestClient {
return UriComponent.encode(url, UriComponent.Type.PATH_SEGMENT); return UriComponent.encode(url, UriComponent.Type.PATH_SEGMENT);
} }
protected WebTarget getTarget(){ protected WebTarget getTarget() {
return webTarget; return webTarget;
} }
protected MultivaluedMap<String, Object> getDefaultHeaders(){ protected MultivaluedMap<String, Object> getDefaultHeaders() {
MultivaluedMap<String, Object> map = new MultivaluedHashMap<>(); MultivaluedMap<String, Object> map = new MultivaluedHashMap<>();
map.putSingle(IPAuthenticationFilter.SERVER_TOKEN_HEADER, TokenManager.generateToken()); map.putSingle(IPAuthenticationFilter.SERVER_TOKEN_HEADER, TokenManager.generateToken());
return map; return map;

View file

@ -269,12 +269,12 @@ public class OperationResource {
@Consumes(MediaType.MULTIPART_FORM_DATA) @Consumes(MediaType.MULTIPART_FORM_DATA)
@Authorize(name = "uploadCerts") @Authorize(name = "uploadCerts")
public Response uploadCerts(@Context HttpServletRequest request, public Response uploadCerts(@Context HttpServletRequest request,
@Context HttpHeaders hh, @Context HttpHeaders hh,
@FormDataParam("cert") InputStream cert, @FormDataParam("cert") InputStream cert,
@FormDataParam("key") InputStream key, @FormDataParam("key") InputStream key,
@QueryParam("vsId") Long vsId, @QueryParam("vsId") Long vsId,
@QueryParam("ip") List<String> ips, @QueryParam("ip") List<String> ips,
@QueryParam("domain") String domain) throws Exception { @QueryParam("domain") String domain) throws Exception {
if (domain != null && !domain.isEmpty()) { if (domain != null && !domain.isEmpty()) {
Set<Long> check = virtualServerCriteriaQuery.queryByDomain(domain); Set<Long> check = virtualServerCriteriaQuery.queryByDomain(domain);
if (!check.contains(vsId)) if (!check.contains(vsId))
@ -303,6 +303,20 @@ public class OperationResource {
return responseHandler.handle("Certificates uploaded.", hh.getMediaType()); return responseHandler.handle("Certificates uploaded.", hh.getMediaType());
} }
@POST
@Path("/installcerts")
@Consumes(MediaType.MULTIPART_FORM_DATA)
@Authorize(name = "installCerts")
public Response installCerts(@Context HttpServletRequest request,
@Context HttpHeaders hh,
@FormDataParam("cert") InputStream cert,
@FormDataParam("key") InputStream key,
@QueryParam("vsId") Long vsId) throws Exception {
final String installDir = "/data/nginx/ssl/" + vsId;
certificateService.save(cert, key, installDir);
return responseHandler.handle("Certificates are installed successfully.", hh.getMediaType());
}
private Response memberOps(HttpHeaders hh, Long groupId, List<String> ips, boolean up, String type) throws Exception { private Response memberOps(HttpHeaders hh, Long groupId, List<String> ips, boolean up, String type) throws Exception {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();

View file

@ -0,0 +1,35 @@
package com.ctrip.zeus.service.nginx;
/**
* Created by zhoumy on 2015/10/30.
*/
public class CertificateConfig {
public static final boolean OVERWRITE_IF_EXIST = false;
public static final boolean APPEND_ONLY = true;
private String cacheDir;
private boolean writeFileOption;
public CertificateConfig() {
cacheDir = "tmp/certs/";
writeFileOption = OVERWRITE_IF_EXIST;
}
public String getCacheDir() {
return cacheDir;
}
public void setCacheDir(String cacheDir) {
if (!cacheDir.endsWith("/"))
cacheDir += "/";
this.cacheDir = cacheDir;
}
public boolean getWriteFileOption() {
return writeFileOption;
}
public void setWriteFileOption(boolean writeFileOption) {
this.writeFileOption = writeFileOption;
}
}

View file

@ -8,9 +8,11 @@ import java.util.List;
*/ */
public interface CertificateService { public interface CertificateService {
CertificateConfig getConfig();
void cache(InputStream cert, InputStream key, Long vsId) throws Exception; void cache(InputStream cert, InputStream key, Long vsId) throws Exception;
void cache(InputStream cert, InputStream key, String dir) throws Exception; void save(InputStream cert, InputStream key, String dir) throws Exception;
void sendIfExist(Long vsId, List<String> ip); void sendIfExist(Long vsId, List<String> ips) throws Exception;
} }

View file

@ -1,9 +1,17 @@
package com.ctrip.zeus.service.nginx.impl; package com.ctrip.zeus.service.nginx.impl;
import com.ctrip.zeus.client.AbstractRestClient;
import com.ctrip.zeus.exceptions.ValidationException;
import com.ctrip.zeus.service.nginx.CertificateConfig;
import com.ctrip.zeus.service.nginx.CertificateService; import com.ctrip.zeus.service.nginx.CertificateService;
import com.ctrip.zeus.util.IOUtils; import com.ctrip.zeus.util.IOUtils;
import org.glassfish.jersey.media.multipart.MultiPart;
import org.glassfish.jersey.media.multipart.file.FileDataBodyPart;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import javax.ws.rs.client.Entity;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.io.*; import java.io.*;
import java.util.List; import java.util.List;
@ -12,29 +20,80 @@ import java.util.List;
*/ */
@Service("certificateService") @Service("certificateService")
public class CertificateServiceImpl implements CertificateService { public class CertificateServiceImpl implements CertificateService {
private final static String TempDir = "tmp/certs/"; private CertificateConfig config = new CertificateConfig();
@Override @Override
public void cache(InputStream cert, InputStream key, Long vsId) throws Exception { public CertificateConfig getConfig() {
cache(cert, key, TempDir + vsId); return config;
} }
@Override @Override
public void cache(InputStream cert, InputStream key, String dir) throws Exception { public void cache(InputStream cert, InputStream key, Long vsId) throws Exception {
save(cert, key, config.getCacheDir() + vsId);
}
@Override
public void save(InputStream cert, InputStream key, String dir) throws Exception {
File f = new File(dir); File f = new File(dir);
if (!f.exists()) { if (!f.exists()) {
f.mkdirs(); f.mkdirs();
} }
OutputStream certos = new FileOutputStream(f.getPath() + "/ssl.crt"); OutputStream certos = new FileOutputStream(f.getPath() + "/ssl.crt", config.getWriteFileOption());
IOUtils.copy(cert, certos); OutputStream keyos = new FileOutputStream(f.getPath() + "/ssl.key", config.getWriteFileOption());
certos.flush(); try {
OutputStream keyos = new FileOutputStream(f.getPath()+"/ssl.key"); IOUtils.copy(cert, certos);
IOUtils.copy(key, keyos); certos.flush();
certos.flush(); IOUtils.copy(key, keyos);
certos.flush();
} finally {
certos.close();
keyos.close();
}
} }
@Override @Override
public void sendIfExist(Long vsId, List<String> ip) { public void sendIfExist(Long vsId, List<String> ips) throws Exception {
String errMsg = "";
boolean success = true;
for (String ip : ips) {
CertSyncClient c = new CertSyncClient("http://" + ip + ":8099/api/op/installcerts", config.getCacheDir() + vsId);
Response res = c.sync(vsId);
// retry
if (res.getStatus() / 100 > 2)
res = c.sync(vsId);
// still failed after retry
if (res.getStatus() / 100 > 2) {
success &= false;
try {
errMsg += ip + ":" + IOUtils.inputStreamStringify((InputStream) res.getEntity()) + ";";
} catch (IOException e) {
errMsg += ip + ":" + "Unable to parse response entity.";
}
}
}
if (success)
return;
throw new Exception(errMsg);
}
private static class CertSyncClient extends AbstractRestClient {
private final String fileDir;
protected CertSyncClient(String url, String fileDir) {
super(url);
this.fileDir = fileDir;
}
public Response sync(Long vsId) throws ValidationException {
File cert = new File(fileDir + "/ssl.crt");
File key = new File(fileDir + "/ssl.key");
if (cert.exists() && key.exists()) {
MultiPart mp = new MultiPart().bodyPart(new FileDataBodyPart("cert", cert, MediaType.APPLICATION_OCTET_STREAM_TYPE))
.bodyPart(new FileDataBodyPart("key", key, MediaType.APPLICATION_OCTET_STREAM_TYPE));
return getTarget().queryParam("vsId", vsId).request(MediaType.MULTIPART_FORM_DATA).post(
Entity.entity(mp, mp.getMediaType()));
}
throw new ValidationException("Certificate files cannot be found under " + fileDir);
}
} }
} }