You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@stratos.apache.org by im...@apache.org on 2015/06/15 14:43:14 UTC
[09/12] stratos git commit: Migrating Kubernetes API client to Fabric8
http://git-wip-us.apache.org/repos/asf/stratos/blob/3414e7ce/dependencies/fabric8/kubernetes-api/src/main/java/io/fabric8/kubernetes/api/Entity.java
----------------------------------------------------------------------
diff --git a/dependencies/fabric8/kubernetes-api/src/main/java/io/fabric8/kubernetes/api/Entity.java b/dependencies/fabric8/kubernetes-api/src/main/java/io/fabric8/kubernetes/api/Entity.java
new file mode 100644
index 0000000..1b37892
--- /dev/null
+++ b/dependencies/fabric8/kubernetes-api/src/main/java/io/fabric8/kubernetes/api/Entity.java
@@ -0,0 +1,28 @@
+/**
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.fabric8.kubernetes.api;
+
+/**
+ * The base interface for all entities which have an ID and a kind
+ */
+public interface Entity {
+
+ String getId();
+
+ String getKind();
+}
http://git-wip-us.apache.org/repos/asf/stratos/blob/3414e7ce/dependencies/fabric8/kubernetes-api/src/main/java/io/fabric8/kubernetes/api/ExceptionResponseMapper.java
----------------------------------------------------------------------
diff --git a/dependencies/fabric8/kubernetes-api/src/main/java/io/fabric8/kubernetes/api/ExceptionResponseMapper.java b/dependencies/fabric8/kubernetes-api/src/main/java/io/fabric8/kubernetes/api/ExceptionResponseMapper.java
new file mode 100644
index 0000000..263dfee
--- /dev/null
+++ b/dependencies/fabric8/kubernetes-api/src/main/java/io/fabric8/kubernetes/api/ExceptionResponseMapper.java
@@ -0,0 +1,69 @@
+package io.fabric8.kubernetes.api;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import io.fabric8.kubernetes.api.model.base.Status;
+import io.fabric8.utils.IOHelpers;
+import io.fabric8.utils.Strings;
+import org.apache.cxf.jaxrs.client.ResponseExceptionMapper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.Response;
+import java.io.IOException;
+import java.io.InputStream;
+
+public class ExceptionResponseMapper implements ResponseExceptionMapper<Exception> {
+ private static final transient Logger LOG = LoggerFactory.getLogger(ExceptionResponseMapper.class);
+
+ @Override
+ public Exception fromResponse(Response response) {
+ try {
+ Object entity = response.getEntity();
+ String message = extractErrorMessage(entity);
+ message = "HTTP " + response.getStatus() + " " + message;
+ return new WebApplicationException(message, response);
+ } catch (Exception ex) {
+ return new Exception(
+ "Could not deserialize server side exception: " + ex.getMessage());
+ }
+ }
+
+ public static String extractErrorMessage(Object entity) {
+ String message = "No message";
+ ObjectMapper mapper = KubernetesFactory.createObjectMapper();
+ try {
+ String json = null;
+ if (entity instanceof InputStream) {
+ InputStream inputStream = (InputStream) entity;
+ json = IOHelpers.readFully(inputStream);
+ } else if (entity != null) {
+ json = entity.toString();
+ }
+ if (Strings.isNotBlank(json)) {
+ message = json;
+ if (textLooksLikeJsonObject(json)) {
+ try {
+ Status error = mapper.readValue(json, Status.class);
+ if (error != null) {
+ message = error.getMessage();
+ if (Strings.isNullOrBlank(message)) {
+ message = error.getReason();
+ }
+ }
+ } catch (IOException e) {
+ LOG.warn("Failed to parse Status from JSON:" + json + ". Reason: " + e, e);
+ }
+ }
+ }
+ } catch (Exception e) {
+ message = "Failed to extract message from request: " + e;
+ }
+ return message;
+ }
+
+ protected static boolean textLooksLikeJsonObject(String text) {
+ text = text.trim();
+ return text.startsWith("{") && text.endsWith("}");
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/stratos/blob/3414e7ce/dependencies/fabric8/kubernetes-api/src/main/java/io/fabric8/kubernetes/api/Kubernetes.java
----------------------------------------------------------------------
diff --git a/dependencies/fabric8/kubernetes-api/src/main/java/io/fabric8/kubernetes/api/Kubernetes.java b/dependencies/fabric8/kubernetes-api/src/main/java/io/fabric8/kubernetes/api/Kubernetes.java
new file mode 100644
index 0000000..49a34ef
--- /dev/null
+++ b/dependencies/fabric8/kubernetes-api/src/main/java/io/fabric8/kubernetes/api/Kubernetes.java
@@ -0,0 +1,283 @@
+/**
+ * Copyright 2005-2014 Red Hat, Inc.
+ *
+ * Red Hat licenses this file to you under the Apache License, version
+ * 2.0 (the "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+package io.fabric8.kubernetes.api;
+
+import io.fabric8.kubernetes.api.model.Endpoints;
+import io.fabric8.kubernetes.api.model.EndpointsList;
+import io.fabric8.kubernetes.api.model.Namespace;
+import io.fabric8.kubernetes.api.model.NamespaceList;
+import io.fabric8.kubernetes.api.model.Node;
+import io.fabric8.kubernetes.api.model.NodeList;
+import io.fabric8.kubernetes.api.model.Pod;
+import io.fabric8.kubernetes.api.model.PodList;
+import io.fabric8.kubernetes.api.model.ReplicationController;
+import io.fabric8.kubernetes.api.model.ReplicationControllerList;
+import io.fabric8.kubernetes.api.model.Secret;
+import io.fabric8.kubernetes.api.model.SecretList;
+import io.fabric8.kubernetes.api.model.Service;
+import io.fabric8.kubernetes.api.model.ServiceList;
+
+import javax.validation.constraints.NotNull;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+
+/**
+ * Represents the Remote API to working with <a href="http://kubernetes.io/">Kubernetes</a> providing a facade
+ * over the generated JAXRS client.
+ */
+@Path(Kubernetes.ROOT_API_PATH)
+@Produces("application/json")
+@Consumes("application/json")
+public interface Kubernetes {
+
+ static final String ROOT_API_PATH = "api/v1beta3";
+
+ static final String NAMESPACE_ALL = "";
+ static final String NAMESPACE_DEFAULT = "default";
+
+ static final String SERVICE_ACCOUNT_TOKEN_FILE = "/var/run/secrets/kubernetes.io/servicaccount/token";
+
+ /**
+ * List all namespaces on this cluster
+ */
+ @GET
+ @Path("namespaces")
+ NamespaceList getNamespaces();
+
+
+ @POST
+ @Path("namespaces")
+ @Consumes("application/json")
+ String createNamespace(Namespace entity) throws Exception;
+
+ /**
+ * Get a specific Namespace
+ */
+ @GET
+ @Path("namespaces/{name}")
+ Namespace getNamespace(@PathParam("name") @NotNull String name);
+
+ /**
+ * Update a namespace
+ * @param namespaceId
+ * @param entity
+ */
+ @PUT
+ @Path("namespaces/{name}")
+ @Consumes("application/json")
+ String updateNamespace(@PathParam("name") @NotNull String namespaceId, Namespace entity) throws Exception;
+
+ @DELETE
+ @Path("namespaces/{name}")
+ @Consumes("text/plain")
+ String deleteNamespace(@PathParam("name") @NotNull String name) throws Exception;
+
+ /**
+ * List all pods on this cluster
+ * @param namespace
+ */
+ @GET
+ @Path("namespaces/{namespace}/pods")
+ PodList getPods(@PathParam("namespace") String namespace);
+
+ @POST
+ @Path("namespaces/{namespace}/pods")
+ @Consumes("application/json")
+ String createPod(Pod entity, @PathParam("namespace") String namespace) throws Exception;
+
+ /**
+ * Get a specific pod
+ *
+ * @param podId
+ * @param namespace
+ */
+ @GET
+ @Path("namespaces/{namespace}/pods/{podId}")
+ Pod getPod(@PathParam("podId") @NotNull String podId, @PathParam("namespace") String namespace);
+
+ /**
+ * Update a pod
+ * @param podId
+ * @param entity
+ * @param namespace
+ */
+ @PUT
+ @Path("namespaces/{namespace}/pods/{podId}")
+ @Consumes("application/json")
+ String updatePod(@PathParam("podId") @NotNull String podId, Pod entity, @PathParam("namespace") String namespace) throws Exception;
+
+ @DELETE
+ @Path("namespaces/{namespace}/pods/{podId}")
+ @Consumes("text/plain")
+ String deletePod(@PathParam("podId") @NotNull String podId, @PathParam("namespace") String namespace) throws Exception;
+
+ /**
+ * List all services on this cluster
+ * @param namespace
+ */
+ @Path("namespaces/{namespace}/services")
+ @GET
+ @Produces("application/json")
+ ServiceList getServices(@PathParam("namespace") String namespace);
+
+ @Path("namespaces/{namespace}/services")
+ @POST
+ @Consumes("application/json")
+ String createService(Service entity, @PathParam("namespace") String namespace) throws Exception;
+
+ /**
+ * Get a specific service
+ *
+ * @param serviceId
+ * @param namespace
+ */
+ @GET
+ @Path("namespaces/{namespace}/services/{serviceId}")
+ @Produces("application/json")
+ Service getService(@PathParam("serviceId") @NotNull String serviceId, @PathParam("namespace") String namespace);
+
+ /**
+ * Update a service
+ */
+ @PUT
+ @Path("namespaces/{namespace}/services/{serviceId}")
+ @Consumes("application/json")
+ String updateService(@PathParam("serviceId") @NotNull String serviceId, Service entity, @PathParam("namespace") String namespace) throws Exception;
+
+ @DELETE
+ @Path("namespaces/{namespace}/services/{serviceId}")
+ @Produces("application/json")
+ @Consumes("text/plain")
+ String deleteService(@PathParam("serviceId") @NotNull String serviceId, @PathParam("namespace") String namespace) throws Exception;
+
+ /**
+ * List all replicationControllers on this cluster
+ * @param namespace
+ */
+ @Path("namespaces/{namespace}/replicationcontrollers")
+ @GET
+ @Produces("application/json")
+ ReplicationControllerList getReplicationControllers(@PathParam("namespace") String namespace);
+
+ @Path("namespaces/{namespace}/replicationcontrollers")
+ @POST
+ @Consumes("application/json")
+ String createReplicationController(ReplicationController entity, @PathParam("namespace") String namespace) throws Exception;
+
+ @PUT
+ @Path("namespaces/{namespace}/replicationcontrollers/{controllerId}")
+ @Consumes("application/json")
+ String updateReplicationController(@PathParam("controllerId") @NotNull String controllerId, ReplicationController entity, @PathParam("namespace") String namespace) throws Exception;
+
+ /**
+ * Get a specific controller
+ *
+ * @param controllerId
+ * @param namespace
+ */
+ @GET
+ @Path("namespaces/{namespace}/replicationcontrollers/{controllerId}")
+ @Produces("application/json")
+ ReplicationController getReplicationController(@PathParam("controllerId") @NotNull String controllerId, @PathParam("namespace") String namespace);
+
+ /**
+ * Delete a specific controller
+ *
+ * @param controllerId
+ */
+ @DELETE
+ @Path("namespaces/{namespace}/replicationcontrollers/{controllerId}")
+ @Produces("application/json")
+ @Consumes("text/plain")
+ String deleteReplicationController(@PathParam("controllerId") @NotNull String controllerId, @PathParam("namespace") String namespace) throws Exception;
+
+ /**
+ * List all service endpoints on this cluster
+ */
+ @GET
+ @Path("namespaces/{namespace}/endpoints")
+ EndpointsList getEndpoints(@PathParam("namespace") String namespace);
+
+ /**
+ * List all endpoints for a service
+ */
+ @GET
+ @Path("namespaces/{namespace}/endpoints/{serviceId}")
+ Endpoints endpointsForService(@PathParam("serviceId") @NotNull String serviceId, @PathParam("namespace") String namespace);
+
+
+ /**
+ * List all secrets on this cluster
+ * @param namespace
+ */
+ @Path("namespaces/{namespace}/secrets")
+ @GET
+ @Produces("application/json")
+ SecretList getSecrets(@PathParam("namespace") String namespace);
+
+ @Path("namespaces/{namespace}/secrets")
+ @POST
+ @Consumes("application/json")
+ String createSecret(Secret entity, @PathParam("namespace") String namespace) throws Exception;
+
+ /**
+ * Get a specific secret
+ *
+ * @param secretId
+ * @param namespace
+ */
+ @GET
+ @Path("namespaces/{namespace}/secrets/{secretId}")
+ @Produces("application/json")
+ Secret getSecret(@PathParam("secretId") @NotNull String secretId, @PathParam("namespace") String namespace);
+
+ /**
+ * Update a secret
+ */
+ @PUT
+ @Path("namespaces/{namespace}/secrets/{secretId}")
+ @Consumes("application/json")
+ String updateSecret(@PathParam("secretId") @NotNull String secretId, Secret entity, @PathParam("namespace") String namespace) throws Exception;
+
+ @DELETE
+ @Path("namespaces/{namespace}/secrets/{secretId}")
+ @Produces("application/json")
+ @Consumes("text/plain")
+ String deleteSecret(@PathParam("secretId") @NotNull String secretId, @PathParam("namespace") String namespace) throws Exception;
+
+
+
+ /**
+ * List all the minions on this cluster
+ */
+ @GET
+ @Path("nodes")
+ NodeList getNodes();
+
+ /**
+ * List all endpoints for a service
+ */
+ @GET
+ @Path("nodes/{nodeId}")
+ Node node(@PathParam("nodeId") @NotNull String nodeId);
+
+}
http://git-wip-us.apache.org/repos/asf/stratos/blob/3414e7ce/dependencies/fabric8/kubernetes-api/src/main/java/io/fabric8/kubernetes/api/KubernetesApiException.java
----------------------------------------------------------------------
diff --git a/dependencies/fabric8/kubernetes-api/src/main/java/io/fabric8/kubernetes/api/KubernetesApiException.java b/dependencies/fabric8/kubernetes-api/src/main/java/io/fabric8/kubernetes/api/KubernetesApiException.java
new file mode 100644
index 0000000..d04c863
--- /dev/null
+++ b/dependencies/fabric8/kubernetes-api/src/main/java/io/fabric8/kubernetes/api/KubernetesApiException.java
@@ -0,0 +1,11 @@
+package io.fabric8.kubernetes.api;
+
+public class KubernetesApiException extends Exception {
+
+ public KubernetesApiException() {
+ }
+
+ public KubernetesApiException(String msg) {
+ super(msg);
+ }
+}
http://git-wip-us.apache.org/repos/asf/stratos/blob/3414e7ce/dependencies/fabric8/kubernetes-api/src/main/java/io/fabric8/kubernetes/api/KubernetesClient.java
----------------------------------------------------------------------
diff --git a/dependencies/fabric8/kubernetes-api/src/main/java/io/fabric8/kubernetes/api/KubernetesClient.java b/dependencies/fabric8/kubernetes-api/src/main/java/io/fabric8/kubernetes/api/KubernetesClient.java
new file mode 100644
index 0000000..78faa40
--- /dev/null
+++ b/dependencies/fabric8/kubernetes-api/src/main/java/io/fabric8/kubernetes/api/KubernetesClient.java
@@ -0,0 +1,1618 @@
+/**
+ * Copyright 2005-2014 Red Hat, Inc.
+ *
+ * Red Hat licenses this file to you under the Apache License, version
+ * 2.0 (the "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+package io.fabric8.kubernetes.api;
+
+import io.fabric8.kubernetes.api.builds.Builds;
+import io.fabric8.kubernetes.api.extensions.Configs;
+import io.fabric8.kubernetes.api.model.*;
+import io.fabric8.kubernetes.api.model.config.Config;
+import io.fabric8.kubernetes.api.model.config.Context;
+import io.fabric8.openshift.api.model.*;
+import io.fabric8.openshift.api.model.template.Template;
+import io.fabric8.utils.*;
+import org.apache.cxf.jaxrs.client.WebClient;
+import org.eclipse.jetty.websocket.client.ClientUpgradeRequest;
+import org.eclipse.jetty.websocket.client.WebSocketClient;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.validation.constraints.NotNull;
+import javax.ws.rs.*;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.Response;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStreamWriter;
+import java.net.HttpURLConnection;
+import java.net.URI;
+import java.net.URL;
+import java.util.*;
+import java.util.Objects;
+import java.util.concurrent.Callable;
+
+import static io.fabric8.kubernetes.api.KubernetesHelper.*;
+
+/**
+ * A simple client interface abstracting away the details of working with
+ * the {@link io.fabric8.kubernetes.api.KubernetesFactory} and the differences between
+ * the core {@link io.fabric8.kubernetes.api.Kubernetes} API and the {@link io.fabric8.kubernetes.api.KubernetesExtensions}
+ */
+public class KubernetesClient implements Kubernetes, KubernetesExtensions, KubernetesGlobalExtensions {
+ private static final transient Logger LOG = LoggerFactory.getLogger(KubernetesClient.class);
+ private static final long DEFAULT_TRIGGER_TIMEOUT = 60 * 1000;
+
+ private KubernetesFactory factory;
+ private Kubernetes kubernetes;
+ private KubernetesExtensions kubernetesExtensions;
+ private KubernetesGlobalExtensions kubernetesGlobalExtensions;
+ private String namespace = defaultNamespace();
+
+ public static String defaultNamespace() {
+ String namespace = System.getenv("KUBERNETES_NAMESPACE");
+ if (Strings.isNullOrBlank(namespace)) {
+ namespace = findDefaultOpenShiftNamespace();
+ }
+ if (Strings.isNotBlank(namespace)) {
+ return namespace;
+ }
+ return "default";
+ }
+
+ public static String findDefaultOpenShiftNamespace() {
+ Config config = Configs.parseConfigs();
+ if (config != null) {
+ Context context = Configs.getCurrentContext(config);
+ if (context != null) {
+ return context.getNamespace();
+ }
+ }
+ return null;
+ }
+
+ public KubernetesClient() {
+ this(new KubernetesFactory());
+ }
+
+ public KubernetesClient(String url) {
+ this(new KubernetesFactory(url));
+ }
+
+ public KubernetesClient(KubernetesFactory factory) {
+ this.factory = factory;
+ }
+
+ // Properties
+ //-------------------------------------------------------------------------
+ public String getNamespace() {
+ return namespace;
+ }
+
+ public void setNamespace(String namespace) {
+ this.namespace = namespace;
+ }
+
+ public Kubernetes getKubernetes() {
+ if (kubernetes == null) {
+ kubernetes = getFactory().createKubernetes();
+ }
+ return kubernetes;
+ }
+
+ public KubernetesExtensions getKubernetesExtensions() {
+ if (kubernetesExtensions == null) {
+ kubernetesExtensions = getFactory().createKubernetesExtensions();
+ }
+ return kubernetesExtensions;
+ }
+
+ public KubernetesGlobalExtensions getKubernetesGlobalExtensions() {
+ if (kubernetesGlobalExtensions == null) {
+ kubernetesGlobalExtensions = getFactory().createKubernetesGlobalExtensions();
+ }
+ return kubernetesGlobalExtensions;
+ }
+
+ public KubernetesFactory getFactory() {
+ if (factory == null) {
+ factory = new KubernetesFactory();
+ }
+ return factory;
+ }
+
+ public void setFactory(KubernetesFactory factory) {
+ this.factory = factory;
+ }
+
+ public String getAddress() {
+ return getFactory().getAddress();
+ }
+
+ public String getWriteableAddress() {
+ return getFactory().getAddress();
+ }
+
+
+ // Delegated Kubernetes API
+ //-------------------------------------------------------------------------
+
+ @Override
+ @GET
+ @Path("namespaces")
+ public NamespaceList getNamespaces() {
+ return getKubernetes().getNamespaces();
+ }
+
+ @Override
+ public String createNamespace(Namespace entity) throws Exception {
+ return getKubernetes().createNamespace(entity);
+ }
+
+ @Override
+ @GET
+ @Path("namespaces/{name}")
+ public Namespace getNamespace(final @NotNull String name) {
+ return handle404ByReturningNull(new Callable<Namespace>() {
+ @Override
+ public Namespace call() throws Exception {
+ return getKubernetes().getNamespace(name);
+ }
+ });
+ }
+
+ @Override
+ @PUT
+ @Path("namespaces/{name}")
+ @Consumes("application/json")
+ public String updateNamespace(@NotNull String namespaceId, Namespace entity) throws Exception {
+ return getKubernetes().updateNamespace(namespaceId, entity);
+ }
+
+ @Override
+ @DELETE
+ @Path("namespaces/{name}")
+ @Consumes("text/plain")
+ public String deleteNamespace(@NotNull String name) throws Exception {
+ return getKubernetes().deleteNamespace(name);
+ }
+
+ @GET
+ @Path("pods")
+ public PodList getPods() {
+ return getPods(getNamespace());
+ }
+
+ @Override
+ public PodList getPods(@QueryParam("namespace") String namespace) {
+ validateNamespace(namespace, null);
+ return getKubernetes().getPods(namespace);
+ }
+
+ @DELETE
+ @Path("pods/{podId}")
+ public String deletePod(@NotNull String podId) throws Exception {
+ validateNamespace(namespace, podId);
+ return getKubernetes().deletePod(podId, getNamespace());
+ }
+
+ @Override
+ @DELETE
+ @Path("pods/{podId}")
+ @Consumes("text/plain")
+ public String deletePod(@NotNull String podId, String namespace) throws Exception {
+ validateNamespace(namespace, podId);
+ return getKubernetes().deletePod(podId, namespace);
+ }
+
+ @GET
+ @Path("replicationControllers/{controllerId}")
+ @Produces("application/json")
+ public ReplicationController getReplicationController(@NotNull String controllerId) {
+ validateNamespace(namespace, controllerId);
+ return getReplicationController(controllerId, getNamespace());
+ }
+
+ @Override
+ public ReplicationController getReplicationController(final @PathParam("controllerId") @NotNull String controllerId, final @QueryParam("namespace") String namespace) {
+ validateNamespace(namespace, controllerId);
+ return handle404ByReturningNull(new Callable<ReplicationController>() {
+ @Override
+ public ReplicationController call() throws Exception {
+ return getKubernetes().getReplicationController(controllerId, namespace);
+ }
+ });
+ }
+
+ @DELETE
+ @Path("replicationControllers/{controllerId}")
+ @Produces("application/json")
+ public String deleteReplicationController(@NotNull String controllerId) throws Exception {
+ validateNamespace(namespace, controllerId);
+ return getKubernetes().deleteReplicationController(controllerId, getNamespace());
+ }
+
+ @Override
+ @DELETE
+ @Path("replicationControllers/{controllerId}")
+ @Produces("application/json")
+ @Consumes("text/plain")
+ public String deleteReplicationController(@NotNull String controllerId, String namespace) throws Exception {
+ validateNamespace(namespace, controllerId);
+ return getKubernetes().deleteReplicationController(controllerId, namespace);
+ }
+
+ @Override
+ @DELETE
+ @Path("services/{serviceId}")
+ @Produces("application/json")
+ @Consumes("text/plain")
+ public String deleteService(@NotNull String serviceId, String namespace) throws Exception {
+ validateNamespace(namespace, serviceId);
+ return getKubernetes().deleteService(serviceId, namespace);
+ }
+
+ @Path("replicationControllers")
+ @GET
+ @Produces("application/json")
+ public ReplicationControllerList getReplicationControllers() {
+ return getReplicationControllers(getNamespace());
+ }
+
+ @Override
+ public ReplicationControllerList getReplicationControllers(@QueryParam("namespace") String namespace) {
+ validateNamespace(namespace, null);
+ return getKubernetes().getReplicationControllers(namespace);
+ }
+
+ @PUT
+ @Path("replicationControllers/{controllerId}")
+ @Consumes("application/json")
+ public String updateReplicationController(@NotNull String controllerId, ReplicationController entity) throws Exception {
+ validateNamespace(namespace, entity);
+ return updateReplicationController(controllerId, entity, getNamespace());
+ }
+
+ @PUT
+ @Path("replicationControllers/{controllerId}")
+ @Consumes("application/json")
+ public String updateReplicationController(@NotNull String controllerId, ReplicationController entity, String namespace) throws Exception {
+ validateNamespace(namespace, entity);
+ if (!KubernetesHelper.hasResourceVersion(entity)) {
+ // lets load it from the oldEntity
+ ReplicationController oldEntity = getReplicationController(controllerId, namespace);
+ if (oldEntity == null) {
+ // no entity exists so lets create a new one
+ return createReplicationController(entity, namespace);
+ }
+ String resourceVersion = KubernetesHelper.getResourceVersion(oldEntity);
+ KubernetesHelper.getOrCreateMetadata(entity).setResourceVersion(resourceVersion);
+ }
+ return getKubernetes().updateReplicationController(controllerId, entity, namespace);
+ }
+
+ @PUT
+ @Path("services/{serviceId}")
+ @Consumes("application/json")
+ public String updateService(@NotNull String serviceId, Service entity) throws Exception {
+ validateNamespace(namespace, entity);
+ return updateService(serviceId, entity, getNamespace());
+ }
+
+ @Override
+ public String updateService(@PathParam("serviceId") @NotNull String serviceId, Service entity, @QueryParam("namespace") String namespace) throws Exception {
+ validateNamespace(namespace, entity);
+ if (!KubernetesHelper.hasResourceVersion(entity)) {
+ // lets load it from the old service
+ Service service = getService(serviceId, namespace);
+ if (service == null) {
+ // no service so lets create the service
+ return createService(entity, namespace);
+ }
+ String resourceVersion = KubernetesHelper.getResourceVersion(service);
+ KubernetesHelper.getOrCreateMetadata(entity).setResourceVersion(resourceVersion);
+
+ // lets copy over some fields set on the spec by kubernetes
+ ServiceSpec oldSpec = service.getSpec();
+ ServiceSpec newSpec = entity.getSpec();
+ if (oldSpec != null && newSpec != null) {
+ if (Strings.isNullOrBlank(newSpec.getPortalIP())) {
+ newSpec.setPortalIP(oldSpec.getPortalIP());
+ }
+ }
+
+ }
+ return getKubernetes().updateService(serviceId, entity, namespace);
+ }
+
+ @GET
+ @Path("services/{serviceId}")
+ @Produces("application/json")
+ public Service getService(@NotNull String serviceId) {
+ return getService(serviceId, getNamespace());
+ }
+
+ @Override
+ public Service getService(final @PathParam("serviceId") @NotNull String serviceId, final @QueryParam("namespace") String namespace) {
+ validateNamespace(namespace, serviceId);
+ return handle404ByReturningNull(new Callable<Service>() {
+ @Override
+ public Service call() throws Exception {
+ return getKubernetes().getService(serviceId, namespace);
+ }
+ });
+ }
+
+ @DELETE
+ @Path("services/{serviceId}")
+ @Produces("application/json")
+ public String deleteService(@NotNull String serviceId) throws Exception {
+ validateNamespace(namespace, serviceId);
+ return deleteService(serviceId, getNamespace());
+ }
+
+ @GET
+ @Path("pods/{podId}")
+ public Pod getPod(@NotNull String podId) {
+ return getPod(podId, getNamespace());
+ }
+
+ @Override
+ public Pod getPod(final @PathParam("podId") @NotNull String podId, final @QueryParam("namespace") String namespace) {
+ validateNamespace(namespace, podId);
+ return handle404ByReturningNull(new Callable<Pod>() {
+ @Override
+ public Pod call() throws Exception {
+ return getKubernetes().getPod(podId, namespace);
+ }
+ });
+ }
+
+ @PUT
+ @Path("pods/{podId}")
+ @Consumes("application/json")
+ public String updatePod(@NotNull String podId, Pod entity) throws Exception {
+ return updatePod(podId, entity, getNamespace());
+ }
+
+ @Override
+ public String updatePod(@PathParam("podId") @NotNull String podId, Pod entity, @QueryParam("namespace") String namespace) throws Exception {
+ validateNamespace(namespace, podId);
+ return getKubernetes().updatePod(podId, entity, namespace);
+ }
+
+ @Path("services")
+ @GET
+ @Produces("application/json")
+ public ServiceList getServices() {
+ validateNamespace(namespace, null);
+ return getServices(getNamespace());
+ }
+
+ @Override
+ public ServiceList getServices(@QueryParam("namespace") String namespace) {
+ validateNamespace(namespace, null);
+ return getKubernetes().getServices(namespace);
+ }
+
+ @POST
+ @Path("pods")
+ @Consumes("application/json")
+ public String createPod(Pod entity) throws Exception {
+ validateNamespace(namespace, entity);
+ return createPod(entity, getNamespace());
+ }
+
+ @Override
+ @POST
+ @Path("pods")
+ @Consumes("application/json")
+ public String createPod(Pod entity, String namespace) throws Exception {
+ validateNamespace(namespace, entity);
+ getOrCreateMetadata(entity).setNamespace(namespace);
+ return getKubernetes().createPod(entity, namespace);
+ }
+
+ @Path("services")
+ @POST
+ @Consumes("application/json")
+ public String createService(Service entity) throws Exception {
+ validateNamespace(namespace, entity);
+ return createService(entity, getNamespace());
+ }
+
+ @Override
+ @Path("services")
+ @POST
+ @Consumes("application/json")
+ public String createService(Service entity, String namespace) throws Exception {
+ validateNamespace(namespace, entity);
+ getOrCreateMetadata(entity).setNamespace(namespace);
+ return getKubernetes().createService(entity, namespace);
+ }
+
+ @Path("replicationControllers")
+ @POST
+ @Consumes("application/json")
+ public String createReplicationController(ReplicationController entity) throws Exception {
+ validateNamespace(namespace, entity);
+ return createReplicationController(entity, getNamespace());
+ }
+
+ @Override
+ @Path("replicationControllers")
+ @POST
+ @Consumes("application/json")
+ public String createReplicationController(ReplicationController entity, String namespace) throws Exception {
+ validateNamespace(namespace, entity);
+ getOrCreateMetadata(entity).setNamespace(namespace);
+ return getKubernetes().createReplicationController(entity, namespace);
+ }
+
+ @GET
+ @Path("endpoints")
+ public EndpointsList getEndpoints() {
+ return getEndpoints(getNamespace());
+ }
+
+ @Override
+ @GET
+ @Path("endpoints")
+ public EndpointsList getEndpoints(String namespace) {
+ validateNamespace(namespace, null);
+ return getKubernetes().getEndpoints(namespace);
+ }
+
+ @Override
+ @GET
+ @Path("endpoints/{serviceId}")
+ public Endpoints endpointsForService(@NotNull String serviceId, String namespace) {
+ try {
+ validateNamespace(namespace, serviceId);
+ return getKubernetes().endpointsForService(serviceId, namespace);
+ } catch (WebApplicationException e) {
+ if (e.getResponse().getStatus() == 404) {
+ // does not exist
+ Endpoints answer = new Endpoints();
+ answer.setSubsets(new ArrayList<EndpointSubset>());
+ return answer;
+ } else {
+ throw e;
+ }
+ }
+ }
+
+ @Override
+ @Path("namespaces/{namespace}/secrets")
+ @POST
+ @Consumes("application/json")
+ public String createSecret(Secret entity, String namespace) throws Exception {
+ validateNamespace(namespace, entity);
+ return getKubernetes().createSecret(entity, namespace);
+ }
+
+ @Override
+ @DELETE
+ @Path("namespaces/{namespace}/secrets/{secretId}")
+ @Produces("application/json")
+ @Consumes("text/plain")
+ public String deleteSecret(@NotNull String secretId, String namespace) throws Exception {
+ validateNamespace(namespace, secretId);
+ return getKubernetes().deleteSecret(secretId, namespace);
+ }
+
+ @Override
+ @GET
+ @Path("namespaces/{namespace}/secrets/{secretId}")
+ @Produces("application/json")
+ public Secret getSecret(final @NotNull String secretId, final String namespace) {
+ validateNamespace(namespace, secretId);
+ return handle404ByReturningNull(new Callable<Secret>() {
+ @Override
+ public Secret call() throws Exception {
+ return getKubernetes().getSecret(secretId, namespace);
+ }
+ });
+ }
+
+ @Override
+ @Path("namespaces/{namespace}/secrets")
+ @GET
+ @Produces("application/json")
+ public SecretList getSecrets(final String namespace) {
+ validateNamespace(namespace, null);
+ SecretList answer = handle404ByReturningNull(new Callable<SecretList>() {
+ @Override
+ public SecretList call() throws Exception {
+ return getKubernetes().getSecrets(namespace);
+ }
+ });
+ if (answer == null) {
+ answer = new SecretList();
+ }
+ return answer;
+ }
+
+ @Override
+ @PUT
+ @Path("namespaces/{namespace}/secrets/{secretId}")
+ @Consumes("application/json")
+ public String updateSecret(@NotNull String secretId, Secret entity, String namespace) throws Exception {
+ validateNamespace(namespace, entity);
+ return getKubernetes().updateSecret(secretId, entity, namespace);
+ }
+
+ @Override
+ @GET
+ @Path("nodes")
+ public NodeList getNodes() {
+ return getKubernetes().getNodes();
+ }
+
+ @Override
+ @GET
+ @Path("nodes/{nodeId}")
+ public Node node(@NotNull String nodeId) {
+ return getKubernetes().node(nodeId);
+ }
+
+ // Delegated KubernetesExtensions API
+ //-------------------------------------------------------------------------
+
+
+ @Override
+ @POST
+ @Path("oauthclients")
+ @Consumes("application/json")
+ public String createOAuthClient(OAuthClient entity) throws Exception {
+ getOrCreateMetadata(entity).setNamespace(namespace);
+ String id = getName(entity);
+ LOG.info("Creating OAuthClient " + id + " " + summaryText(entity));
+ return getKubernetesGlobalExtensions().createOAuthClient(entity);
+ }
+
+ @Override
+ @DELETE
+ @Path("oauthclients/{name}")
+ public String deleteOAuthClient(@NotNull String name) {
+ LOG.info("Deleting OAuthClient " + name);
+ return getKubernetesGlobalExtensions().deleteOAuthClient(name);
+ }
+
+ @Override
+ @GET
+ @Path("oauthclients/{name}")
+ public OAuthClient getOAuthClient(final @NotNull String name) {
+ return handle404ByReturningNull(new Callable<OAuthClient>() {
+ @Override
+ public OAuthClient call() throws Exception {
+ return getKubernetesGlobalExtensions().getOAuthClient(name);
+ }
+ });
+ }
+
+ @Override
+ @PUT
+ @Path("oauthclients/{name}")
+ @Consumes("application/json")
+ public String updateOAuthClient(@NotNull String name, OAuthClient entity) throws Exception {
+ LOG.info("Updating OAuthClient " + name + " " + summaryText(entity));
+ return getKubernetesGlobalExtensions().updateOAuthClient(name, entity);
+ }
+
+ @Override
+ @POST
+ @Path("routes")
+ public String createRoute(Route entity, String namespace) throws Exception {
+ validateNamespace(namespace, entity);
+ return getKubernetesExtensions().createRoute(entity, namespace);
+ }
+
+ /**
+ * Temporary workaround for 0.4.x of Openshift not having osapi/v1beta3
+ * @param entity
+ * @param namespace
+ */
+ public void createRouteOldAPi(Route entity, String namespace) {
+ validateNamespace(namespace, entity);
+
+ WebClient webClient = getFactory().createWebClient();
+ String name = getName(entity);
+ RouteSpec spec = entity.getSpec();
+ String host = null;
+ String serviceName = null;
+ if (spec != null) {
+ host = spec.getHost();
+ ObjectReference to = spec.getTo();
+ if (to != null) {
+ serviceName = to.getName();
+ }
+ }
+ if (Strings.isNullOrBlank(host)) {
+ throw new IllegalArgumentException("No host defined!");
+ }
+ if (Strings.isNullOrBlank(serviceName)) {
+ throw new IllegalArgumentException("No to.name defined!");
+ }
+ String json = "{ \"kind\": \"Route\", \"apiVersion\": \"v1beta1\", \"metadata\": { \"name\": \"" + name + "\"}, \"host\": \"" + host + "\", \"serviceName\": \"" + serviceName + "\"}";
+ System.out.println("Posting JSON: " + json);
+ Response response = webClient.path("/osapi/v1beta1/routes").query("namespace", namespace).post(json);
+ Object responseEntity = response.getEntity();
+ if (responseEntity instanceof InputStream) {
+ InputStream inputStream = (InputStream) responseEntity;
+ try {
+ responseEntity = IOHelpers.readFully(inputStream);
+ } catch (IOException e) {
+ LOG.error("Failed to parse response: " + e, e);
+ }
+ }
+ System.out.println("Result: " + responseEntity);
+ int status = response.getStatus();
+ System.out.println("Posted and got result: " + status);
+ }
+
+ @Override
+ @POST
+ @Path("deploymentConfigs")
+ public String createDeploymentConfig(DeploymentConfig entity, String namespace) throws Exception {
+ validateNamespace(namespace, entity);
+ getOrCreateMetadata(entity).setNamespace(namespace);
+ return getKubernetesExtensions().createDeploymentConfig(entity, namespace);
+ }
+
+ @Override
+ @POST
+ @Path("templates")
+ @Consumes("application/json")
+ public String processTemplate(Template entity, String namespace) throws Exception {
+ validateNamespace(namespace, entity);
+ return getKubernetesExtensions().processTemplate(entity, namespace);
+ }
+
+ @Override
+ @Path("templates")
+ @POST
+ @Consumes("application/json")
+ public String createTemplate(Template entity, String namespace) throws Exception {
+ validateNamespace(namespace, entity);
+ return getKubernetesExtensions().createTemplate(entity, namespace);
+ }
+
+ @Override
+ @GET
+ @Path("templates/{name}")
+ @Produces("application/json")
+ public Template getTemplate(final @NotNull String name, final String namespace) {
+ return handle404ByReturningNull(new Callable<Template>() {
+ @Override
+ public Template call() throws Exception {
+ return getKubernetesExtensions().getTemplate(name, namespace);
+ }
+ });
+ }
+
+ @Override
+ @PUT
+ @Path("templates/{name}")
+ @Consumes("application/json")
+ public String updateTemplate(@NotNull String name, Template entity, String namespace) throws Exception {
+ validateNamespace(namespace, entity);
+ if (!KubernetesHelper.hasResourceVersion(entity)) {
+ // lets load it from the oldEntity
+ ReplicationController oldEntity = getReplicationController(name, namespace);
+ if (oldEntity == null) {
+ // no entity exists so lets create a new one
+ return createTemplate(entity, namespace);
+ }
+ String resourceVersion = KubernetesHelper.getResourceVersion(oldEntity);
+ KubernetesHelper.getOrCreateMetadata(entity).setResourceVersion(resourceVersion);
+ }
+ return getKubernetesExtensions().updateTemplate(name, entity, namespace);
+ }
+
+ @Override
+ @DELETE
+ @Path("templates/{name}")
+ @Produces("application/json")
+ @Consumes("text/plain")
+ public String deleteTemplate(@NotNull String name, String namespace) throws Exception {
+ return getKubernetesExtensions().deleteTemplate(name, namespace);
+ }
+
+ @Override
+ @DELETE
+ @Path("buildConfigs/{name}")
+ public String deleteBuildConfig(@NotNull String name, String namespace) {
+ validateNamespace(namespace, name);
+ return getKubernetesExtensions().deleteBuildConfig(name, namespace);
+ }
+
+ @Override
+ @DELETE
+ @Path("deploymentConfigs/{name}")
+ public String deleteDeploymentConfig(@NotNull String name, String namespace) {
+ validateNamespace(namespace, name);
+ return getKubernetesExtensions().deleteDeploymentConfig(name, namespace);
+ }
+
+ @GET
+ @Path("routes")
+ @Override
+ public RouteList getRoutes(final @QueryParam("namespace") String namespace) {
+ validateNamespace(namespace, null);
+ RouteList answer = handle404ByReturningNull(new Callable<RouteList>() {
+ @Override
+ public RouteList call() throws Exception {
+ return getKubernetesExtensions().getRoutes(namespace);
+ }
+ });
+ if (answer == null) {
+ answer = new RouteList();
+ }
+ return answer;
+ }
+
+ @GET
+ @Path("routes/{name}")
+ @Override
+ public Route getRoute(final @PathParam("name") @NotNull String name, final @QueryParam("namespace") String namespace) {
+ validateNamespace(namespace, name);
+ return handle404ByReturningNull(new Callable<Route>() {
+ @Override
+ public Route call() throws Exception {
+ return getKubernetesExtensions().getRoute(name, namespace);
+ }
+ });
+ }
+
+ @Override
+ @PUT
+ @Path("routes/{name}")
+ @Consumes("application/json")
+ public String updateRoute(@NotNull String name, Route entity, String namespace) throws Exception {
+ validateNamespace(namespace, entity);
+ return getKubernetesExtensions().updateRoute(name, entity, namespace);
+ }
+
+ @Override
+ @DELETE
+ @Path("routes/{name}")
+ public String deleteRoute(@NotNull String name, String namespace) {
+ validateNamespace(namespace, name);
+ return getKubernetesExtensions().deleteRoute(name, namespace);
+ }
+
+ @Override
+ @POST
+ @Path("builds")
+ public String createBuild(Build entity, String namespace) throws Exception {
+ validateNamespace(namespace, entity);
+ getOrCreateMetadata(entity).setNamespace(namespace);
+ return getKubernetesExtensions().createBuild(entity, namespace);
+ }
+
+ @Override
+ @DELETE
+ @Path("builds/{name}")
+ public String deleteBuild(@NotNull String name, String namespace) {
+ validateNamespace(namespace, name);
+ return getKubernetesExtensions().deleteBuild(name, namespace);
+ }
+
+ @Override
+ @GET
+ @Path("builds/{name}")
+ public Build getBuild(final @NotNull String name, final String namespace) {
+ validateNamespace(namespace, name);
+ return handle404ByReturningNull(new Callable<Build>() {
+ @Override
+ public Build call() throws Exception {
+ return getKubernetesExtensions().getBuild(name, namespace);
+ }
+ });
+ }
+
+ @Override
+ @GET
+ @Path("builds")
+ @Produces("application/json")
+ public BuildList getBuilds(final String namespace) {
+ validateNamespace(namespace, null);
+ BuildList answer = handle404ByReturningNull(new Callable<BuildList>() {
+ @Override
+ public BuildList call() throws Exception {
+ return getKubernetesExtensions().getBuilds(namespace);
+ }
+ });
+ if (answer == null) {
+ answer = new BuildList();
+ }
+ return answer;
+ }
+
+ @Override
+ @PUT
+ @Path("builds/{name}")
+ @Consumes("application/json")
+ public String updateBuild(@NotNull String name, Build entity, String namespace) throws Exception {
+ validateNamespace(namespace, entity);
+ return getKubernetesExtensions().updateBuild(name, entity, namespace);
+ }
+
+ @Override
+ @GET
+ @Path("buildConfigs/{name}")
+ public BuildConfig getBuildConfig(final @NotNull String name, final String namespace) {
+ validateNamespace(namespace, name);
+ return handle404ByReturningNull(new Callable<BuildConfig>() {
+ @Override
+ public BuildConfig call() throws Exception {
+ return getKubernetesExtensions().getBuildConfig(name, namespace);
+ }
+ });
+ }
+
+ @Override
+ @GET
+ @Path("buildConfigs")
+ public BuildConfigList getBuildConfigs(String namespace) {
+ validateNamespace(namespace, null);
+ return getKubernetesExtensions().getBuildConfigs(namespace);
+ }
+
+ @Override
+ @GET
+ @Path("deploymentConfigs/{name}")
+ public DeploymentConfig getDeploymentConfig(final @NotNull String name, final String namespace) {
+ validateNamespace(namespace, name);
+ return handle404ByReturningNull(new Callable<DeploymentConfig>() {
+ @Override
+ public DeploymentConfig call() throws Exception {
+ return getKubernetesExtensions().getDeploymentConfig(name, namespace);
+ }
+ });
+ }
+
+ @Override
+ @GET
+ @Path("deploymentConfigs")
+ public DeploymentConfigList getDeploymentConfigs(final String namespace) {
+ validateNamespace(namespace, null);
+ DeploymentConfigList answer = handle404ByReturningNull(new Callable<DeploymentConfigList>() {
+ @Override
+ public DeploymentConfigList call() throws Exception {
+ return getKubernetesExtensions().getDeploymentConfigs(namespace);
+ }
+ });
+ if (answer == null) {
+ answer = new DeploymentConfigList();
+ }
+ return answer;
+ }
+
+ @Override
+ @PUT
+ @Path("buildConfigs/{name}")
+ @Consumes("application/json")
+ public String updateBuildConfig(@NotNull String name, BuildConfig entity, String namespace) throws Exception {
+ validateNamespace(namespace, entity);
+ return getKubernetesExtensions().updateBuildConfig(name, entity, namespace);
+ }
+
+ @Override
+ @PUT
+ @Path("deploymentConfigs/{name}")
+ @Consumes("application/json")
+ public String updateDeploymentConfig(@NotNull String name, DeploymentConfig entity, String namespace) throws Exception {
+ validateNamespace(namespace, entity);
+ return getKubernetesExtensions().updateDeploymentConfig(name, entity, namespace);
+ }
+
+ @Override
+ @POST
+ @Path("buildConfigs")
+ public String createBuildConfig(BuildConfig entity, String namespace) throws Exception {
+ validateNamespace(namespace, entity);
+ getOrCreateMetadata(entity).setNamespace(namespace);
+ return getKubernetesExtensions().createBuildConfig(entity, namespace);
+ }
+
+ @Override
+ @GET
+ @Path("imageStreams/{name}")
+ public ImageStream getImageStream(final @NotNull String name, final String namespace) {
+ validateNamespace(namespace, name);
+ return handle404ByReturningNull(new Callable<ImageStream>() {
+ @Override
+ public ImageStream call() throws Exception {
+ return getKubernetesExtensions().getImageStream(name, namespace);
+ }
+ });
+ }
+
+ @Override
+ @GET
+ @Path("imageStreams")
+ public ImageStreamList getImageStreams(final String namespace) {
+ validateNamespace(namespace, null);
+ ImageStreamList answer = handle404ByReturningNull(new Callable<ImageStreamList>() {
+ @Override
+ public ImageStreamList call() throws Exception {
+ return getKubernetesExtensions().getImageStreams(namespace);
+ }
+ });
+ if (answer == null) {
+ answer = new ImageStreamList();
+ }
+ return answer;
+ }
+
+ @Override
+ @PUT
+ @Path("imageStreams/{name}")
+ @Consumes("application/json")
+ public String updateImageStream(@NotNull String name, ImageStream entity, String namespace) throws Exception {
+ validateNamespace(namespace, entity);
+ return getKubernetesExtensions().updateImageStream(name, entity, namespace);
+ }
+
+ @Override
+ @DELETE
+ @Path("imageStreams/{name}")
+ public String deleteImageStream(@NotNull String name, String namespace) {
+ validateNamespace(namespace, name);
+ return getKubernetesExtensions().deleteImageStream(name, namespace);
+ }
+
+ @Override
+ @POST
+ @Path("imageStreams")
+ public String createImageStream(ImageStream entity, String namespace) throws Exception {
+ validateNamespace(namespace, entity);
+ getOrCreateMetadata(entity).setNamespace(namespace);
+ return getKubernetesExtensions().createImageStream(entity, namespace);
+ }
+
+ @Override
+ @POST
+ @Path("buildConfigHooks/{name}/{secret}/{type}")
+ public String triggerBuild(@NotNull String name, String namespace, @NotNull String secret, @NotNull String type, byte[] body) {
+ validateNamespace(namespace, name);
+ return getKubernetesExtensions().triggerBuild(name, namespace, secret, type, body);
+ }
+
+ // Helper methods
+ //-------------------------------------------------------------------------
+ public void deletePod(Pod entity, String namespace) throws Exception {
+ if (Strings.isNotBlank(namespace)) {
+ entity.getMetadata().setNamespace(namespace);
+ }
+ deletePod(entity);
+ }
+
+ public void deletePod(Pod entity) throws Exception {
+ String namespace = KubernetesHelper.getNamespace(entity);
+ String id = getName(entity);
+ validateNamespace(namespace, entity);
+ LOG.info("Deleting Pod: " + id + " namespace: " + namespace);
+ if (Strings.isNotBlank(namespace)) {
+ deletePod(id, namespace);
+ } else {
+ deletePod(id);
+ }
+ }
+
+ public void deleteService(Service entity, String namespace) throws Exception {
+ if (Strings.isNotBlank(namespace)) {
+ entity.getMetadata().setNamespace(namespace);
+ }
+ deleteService(entity);
+ }
+
+ public void deleteService(Service entity) throws Exception {
+ String namespace = KubernetesHelper.getNamespace(entity);
+ String id = getName(entity);
+ validateNamespace(namespace, entity);
+ LOG.info("Deleting Service: " + id + " namespace: " + namespace);
+ if (Strings.isNotBlank(namespace)) {
+ deleteService(id, namespace);
+ } else {
+ deleteService(id);
+ }
+ }
+
+ public void deleteReplicationControllerAndPods(ReplicationController replicationController, String namespace) throws Exception {
+ if (Strings.isNotBlank(namespace)) {
+ replicationController.getMetadata().setNamespace(namespace);
+ }
+ deleteReplicationControllerAndPods(replicationController);
+ }
+
+ public void deleteReplicationControllerAndPods(ReplicationController replicationController) throws Exception {
+ String id = getName(replicationController);
+ String namespace = KubernetesHelper.getNamespace(replicationController);
+ validateNamespace(namespace, replicationController);
+ LOG.info("Deleting ReplicationController: " + id + " namespace: " + namespace);
+ deleteReplicationController(replicationController);
+ List<Pod> podsToDelete = getPodsForReplicationController(replicationController);
+ for (Pod pod : podsToDelete) {
+ deletePod(pod);
+ }
+ }
+
+ /**
+ * Validates a namespace is supplied giving a meaningful error if not
+ */
+ protected void validateNamespace(String namespace, Object entity) {
+ if (Strings.isNullOrBlank(namespace)) {
+ String message = "No namespace supported";
+ if (entity != null) {
+ message += " for " + KubernetesHelper.summaryText(entity);
+ }
+ throw new IllegalArgumentException(message);
+ }
+ }
+
+ public void deleteReplicationController(ReplicationController replicationController, String namespace) throws Exception {
+ if (Strings.isNotBlank(namespace)) {
+ replicationController.getMetadata().setNamespace(namespace);
+ }
+ deleteReplicationController(replicationController);
+ }
+
+ public void deleteReplicationController(ReplicationController entity) throws Exception {
+ String namespace = KubernetesHelper.getNamespace(entity);
+ String id = getName(entity);
+ if (Strings.isNotBlank(namespace)) {
+ deleteReplicationController(id, namespace);
+ } else {
+ deleteReplicationController(id);
+ }
+ }
+
+ public ReplicationController getReplicationControllerForPod(String podId) {
+ Pod pod = getPod(podId);
+ return getReplicationControllerForPod(pod);
+ }
+
+ public ReplicationController getReplicationControllerForPod(Pod pod) {
+ if (pod != null) {
+ Map<String, String> labels = pod.getMetadata().getLabels();
+ if (labels != null && labels.size() > 0) {
+ ReplicationControllerList replicationControllers = getReplicationControllers();
+ List<ReplicationController> items = replicationControllers.getItems();
+ if (items != null) {
+ List<ReplicationController> matched = new ArrayList<>();
+ for (ReplicationController item : items) {
+ if (filterLabels(labels, item.getMetadata().getLabels())) {
+ matched.add(item);
+ }
+ }
+ int matchedSize = matched.size();
+ if (matchedSize > 1) {
+ // lets remove all the RCs with no current replicas and hope there's only 1 left
+ List<ReplicationController> nonZeroReplicas = Filters.filter(matched, new Filter<ReplicationController>() {
+ @Override
+ public boolean matches(ReplicationController replicationController) {
+ ReplicationControllerSpec replicationControllerSpec = replicationController.getSpec();
+ if (replicationControllerSpec != null) {
+ Integer desiredReplicas = replicationControllerSpec.getReplicas();
+ if (desiredReplicas != null && desiredReplicas.intValue() > 0) {
+ ReplicationControllerStatus currentStatus = replicationController.getStatus();
+ if (currentStatus != null) {
+ Integer replicas = currentStatus.getReplicas();
+ if (replicas != null && replicas.intValue() > 0) {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+ }
+ });
+ int size = nonZeroReplicas.size();
+ if (size > 0) {
+ // lets pick the first one for now :)
+ return nonZeroReplicas.get(0);
+ }
+ }
+ if (matchedSize >= 1) {
+ // otherwise lets pick the first one we found
+ return matched.get(0);
+ }
+ }
+ }
+ }
+ return null;
+ }
+
+ public List<Pod> getPodsForReplicationController(ReplicationController service) {
+ return KubernetesHelper.getPodsForReplicationController(service, getPodList());
+ }
+
+ public List<Pod> getPodsForReplicationController(String replicationControllerId) {
+ ReplicationController replicationController = getReplicationController(replicationControllerId);
+ if (replicationController == null) {
+ return Collections.EMPTY_LIST;
+ } else {
+ return getPodsForReplicationController(replicationController);
+ }
+ }
+
+ public List<Pod> getPodsForService(Service service) {
+ return KubernetesHelper.getPodsForService(service, getPodList());
+ }
+
+ public List<Pod> getPodsForService(String serviceId) {
+ Service service = getService(serviceId);
+ if (service == null) {
+ return Collections.EMPTY_LIST;
+ } else {
+ return getPodsForService(service);
+ }
+ }
+
+ public WebSocketClient watchPods(Watcher<Pod> watcher) throws Exception {
+ return watchPods(null, watcher);
+ }
+
+ public WebSocketClient watchPods(Map<String, String> labels, Watcher<Pod> watcher) throws Exception {
+ return watchPods(getNamespace(), labels, watcher);
+ }
+
+ public WebSocketClient watchPods(String namespace, Map<String, String> labels, Watcher<Pod> watcher) throws Exception {
+ PodList currentPodList = getPods(namespace);
+ return watchPods(namespace, labels, watcher,
+ currentPodList.getMetadata().getResourceVersion());
+ }
+
+ public WebSocketClient watchPods(String namespace, Map<String, String> labels, Watcher<Pod> watcher, String resourceVersion) throws Exception {
+ return watchKubernetesEntities("pods", namespace, labels, watcher, resourceVersion);
+ }
+
+ public WebSocketClient watchServices(Watcher<Service> watcher) throws Exception {
+ return watchServices(null, watcher);
+ }
+
+ public WebSocketClient watchServices(Map<String, String> labels, Watcher<Service> watcher) throws Exception {
+ return watchServices(getNamespace(), labels, watcher);
+ }
+
+ public WebSocketClient watchServices(String namespace, Map<String, String> labels, Watcher<Service> watcher) throws Exception {
+ ServiceList currentServiceList = getServices(namespace);
+ return watchServices(namespace, labels, watcher,
+ currentServiceList.getMetadata().getResourceVersion());
+ }
+
+ public WebSocketClient watchServices(String namespace, Map<String, String> labels, Watcher<Service> watcher, String resourceVersion) throws Exception {
+ return watchKubernetesEntities("services", namespace, labels, watcher, resourceVersion);
+ }
+
+ public WebSocketClient watchEndpoints(Watcher<Endpoints> watcher) throws Exception {
+ return watchEndpoints(null, watcher);
+ }
+
+ public WebSocketClient watchEndpoints(Map<String, String> labels, Watcher<Endpoints> watcher) throws Exception {
+ return watchEndpoints(getNamespace(), labels, watcher);
+ }
+
+ public WebSocketClient watchEndpoints(String namespace, Map<String, String> labels, Watcher<Endpoints> watcher) throws Exception {
+ EndpointsList currentEndpointList = getEndpoints(namespace);
+ return watchEndpoints(namespace, labels, watcher,
+ currentEndpointList.getMetadata().getResourceVersion());
+ }
+
+ public WebSocketClient watchEndpoints(String namespace, Map<String, String> labels, Watcher<Endpoints> watcher, String resourceVersion) throws Exception {
+ return watchKubernetesEntities("endpoints", namespace, labels, watcher, resourceVersion);
+ }
+
+ public WebSocketClient watchReplicationControllers(Watcher<ReplicationController> watcher) throws Exception {
+ return watchReplicationControllers(null, watcher);
+ }
+
+ public WebSocketClient watchReplicationControllers(Map<String, String> labels, Watcher<ReplicationController> watcher) throws Exception {
+ return watchReplicationControllers(getNamespace(), labels, watcher);
+ }
+
+ public WebSocketClient watchReplicationControllers(String namespace, Map<String, String> labels, Watcher<ReplicationController> watcher) throws Exception {
+ ReplicationControllerList currentReplicationControllerList = getReplicationControllers(namespace);
+ return watchReplicationControllers(namespace, labels, watcher,
+ currentReplicationControllerList.getMetadata().getResourceVersion());
+ }
+
+ public WebSocketClient watchReplicationControllers(String namespace, Map<String, String> labels, Watcher<ReplicationController> watcher, String resourceVersion) throws Exception {
+ return watchKubernetesEntities("replicationcontrollers", namespace, labels, watcher, resourceVersion);
+ }
+
+ public WebSocketClient watchBuilds(Watcher<Build> watcher) throws Exception {
+ return watchBuilds(null, watcher);
+ }
+
+ public WebSocketClient watchBuilds(Map<String, String> labels, Watcher<Build> watcher) throws Exception {
+ return watchBuilds(getNamespace(), labels, watcher);
+ }
+
+ public WebSocketClient watchBuilds(String namespace, Map<String, String> labels, Watcher<Build> watcher) throws Exception {
+ BuildList currentList = getBuilds(namespace);
+ return watchBuilds(namespace, labels, watcher,
+ currentList.getMetadata().getResourceVersion());
+ }
+
+ public WebSocketClient watchBuilds(String namespace, Map<String, String> labels, Watcher<Build> watcher, String resourceVersion) throws Exception {
+ return watchOpenShiftEntities("builds", namespace, labels, watcher, resourceVersion);
+ }
+
+ public WebSocketClient watchRoutes(Watcher<Route> watcher) throws Exception {
+ return watchRoutes(null, watcher);
+ }
+
+ public WebSocketClient watchRoutes(Map<String, String> labels, Watcher<Route> watcher) throws Exception {
+ return watchRoutes(getNamespace(), labels, watcher);
+ }
+
+ public WebSocketClient watchRoutes(String namespace, Map<String, String> labels, Watcher<Route> watcher) throws Exception {
+ RouteList currentList = getRoutes(namespace);
+ return watchRoutes(namespace, labels, watcher,
+ currentList.getMetadata().getResourceVersion());
+ }
+
+ public WebSocketClient watchRoutes(String namespace, Map<String, String> labels, Watcher<Route> watcher, String resourceVersion) throws Exception {
+ return watchOpenShiftEntities("routes", namespace, labels, watcher, resourceVersion);
+ }
+
+ public WebSocketClient watchDeploymentConfigs(Watcher<DeploymentConfig> watcher) throws Exception {
+ return watchDeploymentConfigs(null, watcher);
+ }
+
+ public WebSocketClient watchDeploymentConfigs(Map<String, String> labels, Watcher<DeploymentConfig> watcher) throws Exception {
+ return watchDeploymentConfigs(getNamespace(), labels, watcher);
+ }
+
+ public WebSocketClient watchDeploymentConfigs(String namespace, Map<String, String> labels, Watcher<DeploymentConfig> watcher) throws Exception {
+ DeploymentConfigList currentList = getDeploymentConfigs(namespace);
+ return watchDeploymentConfigs(namespace, labels, watcher,
+ currentList.getMetadata().getResourceVersion());
+ }
+
+ public WebSocketClient watchDeploymentConfigs(String namespace, Map<String, String> labels, Watcher<DeploymentConfig> watcher, String resourceVersion) throws Exception {
+ return watchOpenShiftEntities("deploymentconfigs", namespace, labels, watcher, resourceVersion);
+ }
+
+ private WebSocketClient watchKubernetesEntities(String entityType, String namespace, Map<String, String> labels, Watcher<? extends HasMetadata> watcher, String resourceVersion) throws Exception {
+ return watchEntities(Kubernetes.ROOT_API_PATH, entityType, namespace, labels, watcher, resourceVersion);
+ }
+
+ private WebSocketClient watchOpenShiftEntities(String entityType, String namespace, Map<String, String> labels, Watcher<? extends HasMetadata> watcher, String resourceVersion) throws Exception {
+ return watchEntities(KubernetesExtensions.OSAPI_ROOT_PATH, entityType, namespace, labels, watcher, resourceVersion);
+ }
+
+ private WebSocketClient watchEntities(String apiPath, String entityType, String namespace, Map<String, String> labels, Watcher<? extends HasMetadata> watcher, String resourceVersion) throws Exception {
+ String watchUrl = getAddress().replaceFirst("^http", "ws") + "/" + apiPath + "/namespaces/" + namespace + "/" + entityType + "?watch=true&resourceVersion=" + resourceVersion;
+ String labelsString = toLabelsString(labels);
+ if (Strings.isNotBlank(labelsString)) {
+ watchUrl += "&labelSelector=" + labelsString;
+ }
+ LOG.debug("Connecting to {}", watchUrl);
+
+ WebSocketClient client = getFactory().createWebSocketClient();
+ try {
+ URI watchUri = URI.create(watchUrl);
+ ClientUpgradeRequest upgradeRequest = new ClientUpgradeRequest();
+ upgradeRequest.setRequestURI(watchUri);
+ upgradeRequest.setHeader("Origin", watchUri.getHost() + ":" + watchUri.getPort());
+ String token = getFactory().findToken();
+ if (token != null) {
+ upgradeRequest.setHeader("Authorization", "Bearer " + token);
+ }
+ client.start();
+ client.connect(watcher, watchUri, upgradeRequest);
+ return client;
+ } catch (Throwable t) {
+ LOG.error("Failed to watch pods", t);
+ return null;
+ }
+ }
+
+ /**
+ * Returns the URL to access the service; using the environment variables, routes
+ * or service portalIP address
+ *
+ * @throws IllegalArgumentException if the URL cannot be found for the serviceName and namespace
+ */
+ public String getServiceURL(String serviceName, String namespace, String serviceProtocol, boolean serviceExternal) {
+ Service srv = null;
+ String serviceHost = serviceToHost(serviceName);
+ String servicePort = serviceToPort(serviceName);
+ String serviceProto = serviceProtocol != null ? serviceProtocol : serviceToProtocol(serviceName, servicePort);
+
+ //1. Inside Kubernetes: Services as ENV vars
+ if (!serviceExternal && Strings.isNotBlank(serviceHost) && Strings.isNotBlank(servicePort) && Strings.isNotBlank(serviceProtocol)) {
+ return serviceProtocol + "://" + serviceHost + ":" + servicePort;
+ //2. Anywhere: When namespace is passed System / Env var. Mostly needed for integration tests.
+ } else if (Strings.isNotBlank(namespace)) {
+ srv = getService(serviceName, namespace);
+ } else {
+ for (Service s : getServices().getItems()) {
+ String sid = getName(s);
+ if (serviceName.equals(sid)) {
+ srv = s;
+ break;
+ }
+ }
+ }
+ if (srv == null) {
+ throw new IllegalArgumentException("No kubernetes service could be found for name: " + serviceName + " in namespace: " + namespace);
+ }
+ RouteList routeList = getRoutes(namespace);
+ for (Route route : routeList.getItems()) {
+ if (route.getSpec().getTo().getName().equals(serviceName)) {
+ return (serviceProto + "://" + route.getSpec().getHost()).toLowerCase();
+ }
+ }
+ return (serviceProto + "://" + srv.getSpec().getPortalIP() + ":" + srv.getSpec().getPorts().iterator().next().getPort()).toLowerCase();
+ }
+
+
+ // Extension helper methods
+ //-------------------------------------------------------------------------
+
+ /**
+ * Returns the route for the given id and namespace or null if it could not be found.
+ */
+ public Route findRoute(String id, String namespace) {
+ Route route = null;
+ try {
+ route = getRoute(id, namespace);
+ } catch (WebApplicationException e) {
+ if (e.getResponse().getStatus() == 404) {
+ // does not exist
+ } else {
+ throw e;
+ }
+ }
+ return route;
+ }
+
+ /**
+ * Triggers a build and returns the UID of the newly created build if it can be found within the default time period
+ */
+ public String triggerBuildAndGetUuid(@NotNull String name, String namespace) {
+ return triggerBuildAndGetUuid(name, namespace, DEFAULT_TRIGGER_TIMEOUT);
+ }
+
+ /**
+ * Triggers a build and returns the UID of the newly created build if it can be found within the given time period
+ */
+ public String triggerBuildAndGetUuid(@NotNull String name, String namespace, long maxTimeoutMs) {
+ String answer = triggerBuild(name, namespace);
+ if (Strings.isNullOrBlank(answer)) {
+ // lets poll the builds to find the latest build for this name
+ int sleepMillis = 2000;
+ long endTime = System.currentTimeMillis() + maxTimeoutMs;
+ while (true) {
+ Build build = findLatestBuild(name, namespace);
+ // lets assume that the build is created immediately on the webhook
+ if (build != null) {
+ String uid = Builds.getUid(build);
+ answer = uid;
+ break;
+ }
+ if (System.currentTimeMillis() > endTime) {
+ break;
+ } else {
+ try {
+ Thread.sleep(sleepMillis);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ }
+ return answer;
+ }
+
+ /**
+ * Returns all the builds for the given buildConfigName and namespace
+ */
+ public List<Build> findBuilds(String buildConfigName, String namespace) {
+ List<Build> answer = new ArrayList<>();
+ BuildList buildList = getBuilds(namespace);
+ if (buildList != null) {
+ List<Build> items = buildList.getItems();
+ if (items != null) {
+ for (Build build : items) {
+ String namespace2 = Builds.getNamespace(build);
+ String name2 = Builds.getBuildConfigName(build);
+ if (Objects.equals(namespace, namespace2) && Objects.equals(buildConfigName, name2)) {
+ answer.add(build);
+ }
+ }
+ }
+ }
+ return answer;
+ }
+
+ public Build findLatestBuild(String name, String namespace) {
+ List<Build> builds = findBuilds(name, namespace);
+ int size = builds.size();
+ if (size < 1) {
+ return null;
+ } else if (size == 1) {
+ return builds.get(0);
+ } else {
+ // TODO add each build and sort by date...
+ SortedMap<Date, Build> map = new TreeMap<>();
+ for (Build build : builds) {
+ Date date = Builds.getCreationTimestampDate(build);
+ if (date != null) {
+ Build otherBuild = map.get(date);
+ if (otherBuild != null) {
+ LOG.warn("Got 2 builds at the same time: " + build + " and " + otherBuild);
+ } else {
+ map.put(date, build);
+ }
+ }
+ }
+ Date lastKey = map.lastKey();
+ Build build = map.get(lastKey);
+ if (build == null) {
+ LOG.warn("Should have a value for the last key " + lastKey + " for builds " + map);
+ }
+ return build;
+ }
+ }
+
+ public String triggerBuild(@NotNull String name, String namespace) {
+ BuildConfig buildConfig = getBuildConfig(name, namespace);
+ if (buildConfig != null) {
+ List<BuildTriggerPolicy> triggers = buildConfig.getSpec().getTriggers();
+ String type = null;
+ String secret = null;
+ for (BuildTriggerPolicy trigger : triggers) {
+ WebHookTrigger hook = trigger.getGeneric();
+ if (hook != null) {
+ secret = hook.getSecret();
+ String aType = trigger.getType();
+ if (Strings.isNotBlank(secret) && Strings.isNotBlank(aType)) {
+ type = aType;
+ }
+ }
+ }
+ if (Strings.isNullOrBlank(secret) || Strings.isNullOrBlank(type)) {
+ for (BuildTriggerPolicy trigger : triggers) {
+ WebHookTrigger hook = trigger.getGithub();
+ if (hook != null) {
+ secret = hook.getSecret();
+ String aType = trigger.getType();
+ if (Strings.isNotBlank(secret) && Strings.isNotBlank(aType)) {
+ type = aType;
+ }
+ }
+ }
+ }
+ if (Strings.isNullOrBlank(type)) {
+ throw new IllegalArgumentException("BuildConfig does not have a generic or github trigger for build: " + name + " namespace: "+ namespace);
+ }
+ if (Strings.isNullOrBlank(secret)) {
+ throw new IllegalArgumentException("BuildConfig does not have secret for build: " + name + " namespace: "+ namespace);
+ }
+ LOG.info("Triggering build " + name + " namespace: " + namespace + " type: " + type);
+ return doTriggerBuild(name, namespace, type, secret);
+ } else {
+ throw new IllegalArgumentException("No BuildConfig for build: " + name + " namespace: "+ namespace);
+ }
+ }
+
+ protected String doTriggerBuild(String name, String namespace, String type, String secret) {
+ String baseUrl;
+ String url;
+ WebClient webClient;
+ boolean useVanillaUrl = true;
+ boolean useFabric8Console = true;
+ if (useFabric8Console) {
+ // lets proxy through the fabric8 console REST API to work around bugs in OpenShift...
+ baseUrl = getServiceURL(ServiceNames.FABRIC8_CONSOLE, namespace, "http", false);
+ url = URLUtils.pathJoin("/kubernetes/osapi", defaultOsApiVersion, "buildConfigHooks", name, secret, type);
+ webClient = new KubernetesFactory(baseUrl, true).createWebClient();
+ } else {
+ // using the direct REST API...
+ KubernetesFactory factory = getFactory();
+ baseUrl = factory.getAddress();
+ webClient = factory.createWebClient();
+ url = URLUtils.pathJoin("/osapi", defaultOsApiVersion, "buildConfigHooks", name, secret, type);
+ }
+ if (Strings.isNotBlank(namespace)) {
+ url += "?namespace=" + namespace;
+ }
+ if (useVanillaUrl) {
+ String triggerBuildUrlText = URLUtils.pathJoin(baseUrl, url);
+ LOG.info("Using a URL to trigger: " + triggerBuildUrlText);
+ try {
+ URL triggerBuildURL = new URL(triggerBuildUrlText);
+ HttpURLConnection connection = (HttpURLConnection) triggerBuildURL.openConnection();
+ connection.setRequestMethod("POST");
+ connection.setRequestProperty("Content-Type", "application/json");
+ connection.setRequestProperty("Accept", "application/json");
+ connection.setDoOutput(true);
+
+ OutputStreamWriter out = new OutputStreamWriter(
+ connection.getOutputStream());
+ out.close();
+
+ int status = connection.getResponseCode();
+ String message = connection.getResponseMessage();
+ System.out.println("Got response code: " + status + " message: " + message);
+ if (status != 200) {
+ throw new WebApplicationException(status + ": " + message, status);
+ } else {
+ return null;
+ }
+ } catch (IOException e) {
+ throw new WebApplicationException(e, 400);
+ }
+
+ } else {
+
+ LOG.info("Triggering build by posting to: " + url);
+
+ webClient.getHeaders().remove(HttpHeaders.ACCEPT);
+ webClient = webClient.path(url).
+ header(HttpHeaders.CONTENT_TYPE, "application/json");
+
+ Response response = webClient.
+ post(new HashMap());
+ int status = response.getStatus();
+ if (status != 200) {
+ Object entity = response.getEntity();
+ if (entity != null) {
+ String message = ExceptionResponseMapper.extractErrorMessage(entity);
+ throw new WebApplicationException(status + ": " + message, status);
+ } else {
+ throw new WebApplicationException(status);
+ }
+ }
+ return null;
+ }
+ //return getKubernetesExtensions().triggerBuild(name, namespace, secret, type, new byte[0]);
+ }
+
+
+
+ /**
+ * A helper method to handle REST APIs which throw a 404 by just returning null
+ */
+ protected static <T> T handle404ByReturningNull(Callable<T> callable) {
+ try {
+ return callable.call();
+ } catch (WebApplicationException e) {
+ if (e.getResponse().getStatus() == 404) {
+ return null;
+ } else {
+ throw e;
+ }
+ } catch (Exception e) {
+ throw new WebApplicationException(e);
+ }
+ }
+
+
+ // implementation methods
+ //-------------------------------------------------------------------------
+
+ protected Collection<Pod> getPodList() {
+ return getPodMap(this, namespace).values();
+ }
+
+}