Skip to content

Commit

Permalink
Merge pull request #178 from cliveseldon/crd_create
Browse files Browse the repository at this point in the history
Updated Helm Chart and auto create of CRD
  • Loading branch information
ukclivecox committed Jul 5, 2018
2 parents aeb25c1 + 27208b5 commit 42186d1
Show file tree
Hide file tree
Showing 33 changed files with 4,940 additions and 428 deletions.
2 changes: 1 addition & 1 deletion api-frontend/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM openjdk:8u131-jre-alpine
FROM openjdk:8u171-jre-alpine3.7

ARG APP_VERSION=UNKOWN_VERSION

Expand Down
2 changes: 1 addition & 1 deletion api-frontend/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

<groupId>io.seldon.apife</groupId>
<artifactId>seldon-apife</artifactId>
<version>0.2.1-SNAPSHOT</version>
<version>0.2.1-SNAPSHOT-CRD</version>
<packaging>jar</packaging>

<name>api-frontend</name>
Expand Down
2 changes: 1 addition & 1 deletion cluster-manager/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM openjdk:8u131-jre-alpine
FROM openjdk:8u171-jre-alpine3.7

ARG APP_VERSION=UNKOWN_VERSION

Expand Down
2 changes: 1 addition & 1 deletion cluster-manager/README.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
Local testing:

export SELDON_CLUSTER_MANAGER_POD_NAMESPACE=seldon
export ENGINE_CONTAINER_IMAGE_AND_VERSION=seldonio/engine:0.1.8-SNAPSHOT
export ENGINE_CONTAINER_IMAGE_AND_VERSION=seldonio/engine:<VERSION>
2 changes: 1 addition & 1 deletion cluster-manager/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<groupId>io.seldon.clustermanager</groupId>
<artifactId>seldon-cluster-manager</artifactId>
<packaging>jar</packaging>
<version>0.2.1-SNAPSHOT</version>
<version>0.2.1-SNAPSHOT-CRD</version>
<name>seldon-cluster-manager</name>
<url>http://maven.apache.org</url>

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
package io.seldon.clustermanager.k8s;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.reflect.Type;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.gson.reflect.TypeToken;

import io.kubernetes.client.ApiClient;
import io.kubernetes.client.ApiException;
import io.kubernetes.client.ApiResponse;
import io.kubernetes.client.Pair;
import io.kubernetes.client.ProgressRequestBody;
import io.kubernetes.client.ProgressResponseBody;
import io.kubernetes.client.models.V1beta1CustomResourceDefinition;
import io.kubernetes.client.util.Config;

public class CRDCreator {
protected static Logger logger = LoggerFactory.getLogger(CRDCreator.class.getName());
public void createCRD() throws IOException, ApiException
{
String jsonStr = readFileFromClasspath("crd.json");
ApiClient client = Config.defaultClient();
try {
createCustomResourceDefinition(client,jsonStr.getBytes(),null);
logger.info("Created CRD");
} catch (ApiException e) {
if (e.getCode() == 409)// CRD Already Exists
{
logger.info("CRD already exists - ignoring.");
}
else if (e.getCode() == 403)// Forbidden - Maybe CRD exists, but we don't know
{
logger.warn("No auth to create CRD. Hopefully, one exists.",e); // Hopefully a cluster-wide CRD has been created for us
}
else
{
logger.warn("Unexpected error trying to create CRD",e);
throw e;
}
}
}
private String readFromInputStream(InputStream inputStream)
throws IOException {
StringBuilder resultStringBuilder = new StringBuilder();
try (BufferedReader br
= new BufferedReader(new InputStreamReader(inputStream))) {
String line;
while ((line = br.readLine()) != null) {
resultStringBuilder.append(line).append("\n");
}
}
return resultStringBuilder.toString();
}
private String readFileFromClasspath(String name) throws IOException
{
InputStream in = this.getClass().getClassLoader().getResourceAsStream(name);
String data = readFromInputStream(in);
return data;
}

private String readFile(String path, Charset encoding)
throws IOException
{
byte[] encoded = Files.readAllBytes(Paths.get(path));
return new String(encoded, encoding);
}

private V1beta1CustomResourceDefinition createCustomResourceDefinition(ApiClient apiClient,byte[] body, String pretty)
throws ApiException {
ApiResponse<V1beta1CustomResourceDefinition> resp = createCustomResourceDefinitionWithHttpInfo(apiClient,body, pretty);
return resp.getData();
}

private ApiResponse<V1beta1CustomResourceDefinition> createCustomResourceDefinitionWithHttpInfo(ApiClient apiClient,byte[] body,
String pretty) throws ApiException {
com.squareup.okhttp.Call call = createCustomResourceDefinitionCall(apiClient,body, pretty, null, null);
Type localVarReturnType = new TypeToken<V1beta1CustomResourceDefinition>() {
}.getType();
return apiClient.execute(call, localVarReturnType);
}

public com.squareup.okhttp.Call createCustomResourceDefinitionCall(ApiClient apiClient,byte[] body, String pretty,
final ProgressResponseBody.ProgressListener progressListener,
final ProgressRequestBody.ProgressRequestListener progressRequestListener) throws ApiException {
Object localVarPostBody = body;

// create path and map variables
String localVarPath = "/apis/apiextensions.k8s.io/v1beta1/customresourcedefinitions";

List<Pair> localVarQueryParams = new ArrayList<Pair>();
List<Pair> localVarCollectionQueryParams = new ArrayList<Pair>();
if (pretty != null)
localVarQueryParams.addAll(apiClient.parameterToPair("pretty", pretty));

Map<String, String> localVarHeaderParams = new HashMap<String, String>();

Map<String, Object> localVarFormParams = new HashMap<String, Object>();

final String[] localVarAccepts = { "application/json", "application/yaml",
"application/vnd.kubernetes.protobuf" };
final String localVarAccept = apiClient.selectHeaderAccept(localVarAccepts);
if (localVarAccept != null)
localVarHeaderParams.put("Accept", localVarAccept);

final String[] localVarContentTypes = { "*/*" };
final String localVarContentType = apiClient.selectHeaderContentType(localVarContentTypes);
localVarHeaderParams.put("Content-Type", localVarContentType);

if (progressListener != null) {
apiClient.getHttpClient().networkInterceptors().add(new com.squareup.okhttp.Interceptor() {
@Override
public com.squareup.okhttp.Response intercept(com.squareup.okhttp.Interceptor.Chain chain)
throws IOException {
com.squareup.okhttp.Response originalResponse = chain.proceed(chain.request());
return originalResponse.newBuilder()
.body(new ProgressResponseBody(originalResponse.body(), progressListener)).build();
}
});
}

String[] localVarAuthNames = new String[] { "BearerToken" };
return apiClient.buildCall(localVarPath, "POST", localVarQueryParams, localVarCollectionQueryParams,
localVarPostBody, localVarHeaderParams, localVarFormParams, localVarAuthNames, progressRequestListener);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,16 @@
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import io.kubernetes.client.ApiClient;
import io.kubernetes.client.ApiException;
import io.kubernetes.client.ProtoClient;
import io.kubernetes.client.ProtoClient.ObjectOrStatus;
import io.kubernetes.client.apis.CoreV1Api;
import io.kubernetes.client.models.ExtensionsV1beta1Deployment;
import io.kubernetes.client.models.ExtensionsV1beta1DeploymentList;
import io.kubernetes.client.models.V1Service;
import io.kubernetes.client.models.V1ServiceList;
import io.kubernetes.client.models.V1Status;
import io.kubernetes.client.proto.Meta.DeleteOptions;
import io.kubernetes.client.proto.V1.Service;
import io.kubernetes.client.proto.V1beta1Extensions.Deployment;
Expand Down Expand Up @@ -139,6 +142,38 @@ private void removeDeployments(ProtoClient client,String namespace,SeldonDeploym
}
}

private void removeServices(ApiClient client,String namespace,SeldonDeployment seldonDeployment,List<Service> services) throws ApiException, IOException, SeldonDeploymentException
{
Set<String> names = getServiceNames(services);
V1ServiceList svcList = crdHandler.getOwnedServices(seldonDeployment.getSpec().getName());
for(V1Service s : svcList.getItems())
{
if (!names.contains(s.getMetadata().getName()))
{
CoreV1Api api = new CoreV1Api(client);
V1Status status = api.deleteNamespacedService(s.getMetadata().getName(), namespace, null);
if (!"Success".equals(status.getStatus()))
{
logger.error("Failed to delete service "+s.getMetadata().getName());
throw new SeldonDeploymentException("Failed to delete service "+s.getMetadata().getName());
}
else
logger.debug("Deleted deployment "+s.getMetadata().getName());

}
}
}

/**
* Currently Not used as issue with proto client needs further investigation
* @param client
* @param namespace
* @param seldonDeployment
* @param services
* @throws ApiException
* @throws IOException
* @throws SeldonDeploymentException
*/
private void removeServices(ProtoClient client,String namespace,SeldonDeployment seldonDeployment,List<Service> services) throws ApiException, IOException, SeldonDeploymentException
{
Set<String> names = getServiceNames(services);
Expand All @@ -151,9 +186,9 @@ private void removeServices(ProtoClient client,String namespace,SeldonDeployment
.replaceAll("\\{" + "name" + "\\}", client.getApiClient().escapeString(s.getMetadata().getName()))
.replaceAll("\\{" + "namespace" + "\\}", client.getApiClient().escapeString(namespace));
DeleteOptions options = DeleteOptions.newBuilder().setPropagationPolicy("Foreground").build();
ObjectOrStatus<Deployment> os = client.delete(Deployment.newBuilder(),deleteApiPath,options);
ObjectOrStatus<Deployment> os = client.delete(Service.newBuilder(),deleteApiPath,options);
if (os.status != null) {
logger.error("Error deleting deployment:"+ProtoBufUtils.toJson(os.status));
logger.error("Error deleting service:"+ProtoBufUtils.toJson(os.status));
throw new SeldonDeploymentException("Failed to delete service "+s.getMetadata().getName());
}
else {
Expand Down Expand Up @@ -245,7 +280,9 @@ public void createOrReplaceSeldonDeployment(SeldonDeployment mlDep) {
createDeployments(client, namespace, resources.deployments);
removeDeployments(client, namespace, mlDep2, resources.deployments);
createServices(client, namespace, resources.services);
removeServices(client,namespace, mlDep2, resources.services);
//removeServices(client,namespace, mlDep2, resources.services); //Proto Client not presently working for deletion
ApiClient client2 = clientProvider.getClient();
removeServices(client2,namespace, mlDep2, resources.services);
if (!mlDep.getSpec().equals(mlDep2.getSpec()))
{
logger.debug("Pushing updated SeldonDeployment "+mlDep2.getMetadata().getName()+" back to kubectl");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
import io.kubernetes.client.proto.V1.HTTPGetAction;
import io.kubernetes.client.proto.V1.Handler;
import io.kubernetes.client.proto.V1.Lifecycle;
import io.kubernetes.client.proto.V1.PodSecurityContext;
import io.kubernetes.client.proto.V1.PodTemplateSpec;
import io.kubernetes.client.proto.V1.Probe;
import io.kubernetes.client.proto.V1.Service;
Expand Down Expand Up @@ -531,7 +532,9 @@ public DeploymentResources createResources(SeldonDeployment mlDep) throws Seldon
PodTemplateSpec.Builder podSpecBuilder = PodTemplateSpec.newBuilder();
podSpecBuilder.getSpecBuilder()
.addContainers(createEngineContainer(mlDep,p))
.setSecurityContext(PodSecurityContext.newBuilder().setRunAsUser(8888).build())
.setTerminationGracePeriodSeconds(20);

String depName = getSeldonServiceName(mlDep,p,"svc-orch");
podSpecBuilder.getMetadataBuilder()
.putLabels(LABEL_SELDON_APP, mlDep.getSpec().getName())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,11 +57,13 @@ public class SeldonDeploymentWatcher {
private int resourceVersionProcessed = 0;

@Autowired
public SeldonDeploymentWatcher(ClusterManagerProperites clusterManagerProperites,SeldonDeploymentController seldonDeploymentController,SeldonDeploymentCache mlCache) throws IOException
public SeldonDeploymentWatcher(ClusterManagerProperites clusterManagerProperites,SeldonDeploymentController seldonDeploymentController,SeldonDeploymentCache mlCache) throws IOException, ApiException
{
this.seldonDeploymentController = seldonDeploymentController;
this.mlCache = mlCache;
this.clusterManagerProperites = clusterManagerProperites;
CRDCreator crdCreator = new CRDCreator();
crdCreator.createCRD();
}

private void processWatch(SeldonDeployment mldep,String action) throws InvalidProtocolBufferException
Expand Down
Loading

0 comments on commit 42186d1

Please sign in to comment.