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:15 UTC

[10/12] stratos git commit: Migrating Kubernetes API client to Fabric8

http://git-wip-us.apache.org/repos/asf/stratos/blob/3414e7ce/components/org.apache.stratos.kubernetes.client/src/main/java/org/apache/stratos/kubernetes/client/model/Volume.java
----------------------------------------------------------------------
diff --git a/components/org.apache.stratos.kubernetes.client/src/main/java/org/apache/stratos/kubernetes/client/model/Volume.java b/components/org.apache.stratos.kubernetes.client/src/main/java/org/apache/stratos/kubernetes/client/model/Volume.java
deleted file mode 100644
index 91b59b0..0000000
--- a/components/org.apache.stratos.kubernetes.client/src/main/java/org/apache/stratos/kubernetes/client/model/Volume.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- *
- * 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 org.apache.stratos.kubernetes.client.model;
-
-public class Volume {
-
-    private String name;
-
-    public String getName() {
-        return name;
-    }
-
-    public void setName(String name) {
-        this.name = name;
-    }
-
-    @Override
-    public String toString() {
-        return "Volume [name=" + name + "]";
-    }
-
-
-}

http://git-wip-us.apache.org/repos/asf/stratos/blob/3414e7ce/components/org.apache.stratos.kubernetes.client/src/main/java/org/apache/stratos/kubernetes/client/model/VolumeMount.java
----------------------------------------------------------------------
diff --git a/components/org.apache.stratos.kubernetes.client/src/main/java/org/apache/stratos/kubernetes/client/model/VolumeMount.java b/components/org.apache.stratos.kubernetes.client/src/main/java/org/apache/stratos/kubernetes/client/model/VolumeMount.java
deleted file mode 100644
index 1534988..0000000
--- a/components/org.apache.stratos.kubernetes.client/src/main/java/org/apache/stratos/kubernetes/client/model/VolumeMount.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- *
- * 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 org.apache.stratos.kubernetes.client.model;
-
-public class VolumeMount {
-
-    private String name;
-    private String mountPath;
-    private boolean readOnly;
-
-    public String getName() {
-        return name;
-    }
-
-    public void setName(String name) {
-        this.name = name;
-    }
-
-    public String getMountPath() {
-        return mountPath;
-    }
-
-    public void setMountPath(String mountPath) {
-        this.mountPath = mountPath;
-    }
-
-    public boolean isReadOnly() {
-        return readOnly;
-    }
-
-    public void setReadOnly(boolean readOnly) {
-        this.readOnly = readOnly;
-    }
-
-    @Override
-    public String toString() {
-        return "VolumeMount [name=" + name + ", mountPath=" + mountPath
-                + ", readOnly=" + readOnly + "]";
-    }
-
-
-}

http://git-wip-us.apache.org/repos/asf/stratos/blob/3414e7ce/components/org.apache.stratos.kubernetes.client/src/main/java/org/apache/stratos/kubernetes/client/rest/HttpResponse.java
----------------------------------------------------------------------
diff --git a/components/org.apache.stratos.kubernetes.client/src/main/java/org/apache/stratos/kubernetes/client/rest/HttpResponse.java b/components/org.apache.stratos.kubernetes.client/src/main/java/org/apache/stratos/kubernetes/client/rest/HttpResponse.java
deleted file mode 100644
index 6a287c1..0000000
--- a/components/org.apache.stratos.kubernetes.client/src/main/java/org/apache/stratos/kubernetes/client/rest/HttpResponse.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * 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 org.apache.stratos.kubernetes.client.rest;
-
-/**
- * Holds the data extracted from a HttpResponse.
- */
-public class HttpResponse {
-
-    private int statusCode;
-    private String content;
-    private String reason;
-    private KubernetesResponse kubernetesResponse;
-
-    public int getStatusCode() {
-        return statusCode;
-    }
-
-    public void setStatusCode(int statusCode) {
-        this.statusCode = statusCode;
-    }
-
-    public String getContent() {
-        return content;
-    }
-
-    public void setContent(String content) {
-        this.content = content;
-    }
-
-    public String getReason() {
-        return reason;
-    }
-
-    public void setReason(String reason) {
-        this.reason = reason;
-    }
-
-    public KubernetesResponse getKubernetesResponse() {
-        return kubernetesResponse;
-    }
-
-    public void setKubernetesResponse(KubernetesResponse kubernetesResponse) {
-        this.kubernetesResponse = kubernetesResponse;
-    }
-
-    @Override
-    public String toString() {
-        return "HttpResponse [statusCode=" + statusCode + ", content=" + content
-                + ", reason=" + reason + ", kubernetesResponse=" + kubernetesResponse + "]";
-    }
-}

http://git-wip-us.apache.org/repos/asf/stratos/blob/3414e7ce/components/org.apache.stratos.kubernetes.client/src/main/java/org/apache/stratos/kubernetes/client/rest/KubernetesResponse.java
----------------------------------------------------------------------
diff --git a/components/org.apache.stratos.kubernetes.client/src/main/java/org/apache/stratos/kubernetes/client/rest/KubernetesResponse.java b/components/org.apache.stratos.kubernetes.client/src/main/java/org/apache/stratos/kubernetes/client/rest/KubernetesResponse.java
deleted file mode 100644
index e700a1c..0000000
--- a/components/org.apache.stratos.kubernetes.client/src/main/java/org/apache/stratos/kubernetes/client/rest/KubernetesResponse.java
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * 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 org.apache.stratos.kubernetes.client.rest;
-
-/**
- * Kubernetes response.
- */
-public class KubernetesResponse {
-    private String kind;
-    private String creationTimestamp;
-    private String selfLink;
-    private String apiVersion;
-    private String status;
-    private String message;
-    private int code;
-
-    public String getKind() {
-        return kind;
-    }
-
-    public void setKind(String kind) {
-        this.kind = kind;
-    }
-
-    public String getCreationTimestamp() {
-        return creationTimestamp;
-    }
-
-    public void setCreationTimestamp(String creationTimestamp) {
-        this.creationTimestamp = creationTimestamp;
-    }
-
-    public String getSelfLink() {
-        return selfLink;
-    }
-
-    public void setSelfLink(String selfLink) {
-        this.selfLink = selfLink;
-    }
-
-    public String getApiVersion() {
-        return apiVersion;
-    }
-
-    public void setApiVersion(String apiVersion) {
-        this.apiVersion = apiVersion;
-    }
-
-    public String getStatus() {
-        return status;
-    }
-
-    public void setStatus(String status) {
-        this.status = status;
-    }
-
-    public String getMessage() {
-        return message;
-    }
-
-    public void setMessage(String message) {
-        this.message = message;
-    }
-
-    public int getCode() {
-        return code;
-    }
-
-    public void setCode(int code) {
-        this.code = code;
-    }
-}

http://git-wip-us.apache.org/repos/asf/stratos/blob/3414e7ce/components/org.apache.stratos.kubernetes.client/src/main/java/org/apache/stratos/kubernetes/client/rest/KubernetesResponseHandler.java
----------------------------------------------------------------------
diff --git a/components/org.apache.stratos.kubernetes.client/src/main/java/org/apache/stratos/kubernetes/client/rest/KubernetesResponseHandler.java b/components/org.apache.stratos.kubernetes.client/src/main/java/org/apache/stratos/kubernetes/client/rest/KubernetesResponseHandler.java
deleted file mode 100644
index 6530a09..0000000
--- a/components/org.apache.stratos.kubernetes.client/src/main/java/org/apache/stratos/kubernetes/client/rest/KubernetesResponseHandler.java
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- *
- * 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 org.apache.stratos.kubernetes.client.rest;
-
-import com.google.gson.Gson;
-import com.google.gson.GsonBuilder;
-import com.google.gson.JsonSyntaxException;
-import org.apache.commons.lang3.StringUtils;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.apache.http.HttpEntity;
-import org.apache.http.StatusLine;
-import org.apache.http.client.ClientProtocolException;
-import org.apache.http.client.ResponseHandler;
-
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.InputStreamReader;
-
-/**
- * Handles a HttpResponse and returns a {@link HttpResponse}
- */
-public class KubernetesResponseHandler implements ResponseHandler<HttpResponse> {
-    private static final Log log = LogFactory.getLog(KubernetesResponseHandler.class);
-
-    @Override
-    public HttpResponse handleResponse(org.apache.http.HttpResponse response) throws ClientProtocolException,
-            IOException {
-        StatusLine statusLine = response.getStatusLine();
-        HttpEntity entity = response.getEntity();
-        if (entity == null) {
-            throw new ClientProtocolException("Response contains no content");
-        }
-
-        BufferedReader reader = new BufferedReader(new InputStreamReader(
-                (response.getEntity().getContent())));
-
-        String output;
-        String result = "";
-
-        while ((output = reader.readLine()) != null) {
-            result += output;
-        }
-
-        HttpResponse httpResponse = new HttpResponse();
-        httpResponse.setStatusCode(statusLine.getStatusCode());
-        httpResponse.setContent(result);
-        if (StringUtils.isNotBlank(result) && (isJson(result))) {
-            httpResponse.setKubernetesResponse(parseKubernetesResponse(result));
-        }
-        httpResponse.setReason(statusLine.getReasonPhrase());
-
-        if (log.isDebugEnabled()) {
-            log.debug("Extracted Kubernetes Response: " + httpResponse.toString());
-        }
-
-        return httpResponse;
-    }
-
-    private boolean isJson(String content) {
-        try {
-            GsonBuilder gsonBuilder = new GsonBuilder();
-            Gson gson = gsonBuilder.create();
-            gson.fromJson(content, Object.class);
-            return true;
-        } catch (JsonSyntaxException ignore) {
-            return false;
-        }
-    }
-
-    private KubernetesResponse parseKubernetesResponse(String result) {
-        try {
-            GsonBuilder gsonBuilder = new GsonBuilder();
-            Gson gson = gsonBuilder.create();
-            return gson.fromJson(result, KubernetesResponse.class);
-        } catch (Exception e) {
-            log.error("Could not parse kubernetes api response", e);
-            return null;
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/stratos/blob/3414e7ce/components/org.apache.stratos.kubernetes.client/src/main/java/org/apache/stratos/kubernetes/client/rest/RestClient.java
----------------------------------------------------------------------
diff --git a/components/org.apache.stratos.kubernetes.client/src/main/java/org/apache/stratos/kubernetes/client/rest/RestClient.java b/components/org.apache.stratos.kubernetes.client/src/main/java/org/apache/stratos/kubernetes/client/rest/RestClient.java
deleted file mode 100644
index 271f38c..0000000
--- a/components/org.apache.stratos.kubernetes.client/src/main/java/org/apache/stratos/kubernetes/client/rest/RestClient.java
+++ /dev/null
@@ -1,118 +0,0 @@
-/**
- * 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
- * <p/>
- * http://www.apache.org/licenses/LICENSE-2.0
- * <p/>
- * 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 org.apache.stratos.kubernetes.client.rest;
-
-import org.apache.http.client.methods.*;
-import org.apache.http.entity.StringEntity;
-import org.apache.http.impl.client.DefaultHttpClient;
-import org.apache.http.impl.conn.PoolingClientConnectionManager;
-
-import java.net.URI;
-
-public class RestClient {
-
-    private DefaultHttpClient httpClient;
-
-    public RestClient() {
-        PoolingClientConnectionManager cm = new PoolingClientConnectionManager();
-        // Increase max total connection to 200
-        cm.setMaxTotal(200);
-        // Increase default max connection per route to 50
-        cm.setDefaultMaxPerRoute(50);
-
-        httpClient = new DefaultHttpClient(cm);
-    }
-
-    /**
-     * Handle http post request. Return String
-     *
-     * @param resourcePath    This should be REST endpoint
-     * @param jsonParamString The json string which should be executed from the post request
-     * @return The HttpResponse
-     * @throws Exception if any errors occur when executing the request
-     */
-    public HttpResponse doPost(URI resourcePath, String jsonParamString) throws Exception {
-        HttpPost postRequest = null;
-        try {
-            postRequest = new HttpPost(resourcePath);
-
-            StringEntity input = new StringEntity(jsonParamString);
-            input.setContentType("application/json");
-            postRequest.setEntity(input);
-
-            return httpClient.execute(postRequest, new KubernetesResponseHandler());
-        } finally {
-            releaseConnection(postRequest);
-        }
-    }
-
-    /**
-     * Handle http get request. Return String
-     *
-     * @param resourcePath This should be REST endpoint
-     * @return The HttpResponse
-     * @throws org.apache.http.client.ClientProtocolException and IOException
-     *                                                        if any errors occur when executing the request
-     */
-    public HttpResponse doGet(URI resourcePath) throws Exception {
-        HttpGet getRequest = null;
-        try {
-            getRequest = new HttpGet(resourcePath);
-            getRequest.addHeader("Content-Type", "application/json");
-
-            return httpClient.execute(getRequest, new KubernetesResponseHandler());
-        } finally {
-            releaseConnection(getRequest);
-        }
-    }
-
-    public HttpResponse doDelete(URI resourcePath) throws Exception {
-        HttpDelete httpDelete = null;
-        try {
-            httpDelete = new HttpDelete(resourcePath);
-            httpDelete.addHeader("Content-Type", "application/json");
-
-            return httpClient.execute(httpDelete, new KubernetesResponseHandler());
-        } finally {
-            releaseConnection(httpDelete);
-        }
-    }
-
-    public HttpResponse doPut(URI resourcePath, String jsonParamString) throws Exception {
-
-        HttpPut putRequest = null;
-        try {
-            putRequest = new HttpPut(resourcePath);
-
-            StringEntity input = new StringEntity(jsonParamString);
-            input.setContentType("application/json");
-            putRequest.setEntity(input);
-
-            return httpClient.execute(putRequest, new KubernetesResponseHandler());
-        } finally {
-            releaseConnection(putRequest);
-        }
-    }
-
-    private void releaseConnection(HttpRequestBase request) {
-        if (request != null) {
-            request.releaseConnection();
-        }
-    }
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/stratos/blob/3414e7ce/components/org.apache.stratos.kubernetes.client/src/test/java/org/apache/stratos/kubernetes/client/live/AbstractLiveTest.java
----------------------------------------------------------------------
diff --git a/components/org.apache.stratos.kubernetes.client/src/test/java/org/apache/stratos/kubernetes/client/live/AbstractLiveTest.java b/components/org.apache.stratos.kubernetes.client/src/test/java/org/apache/stratos/kubernetes/client/live/AbstractLiveTest.java
index 03a2b0f..29b7ed4 100644
--- a/components/org.apache.stratos.kubernetes.client/src/test/java/org/apache/stratos/kubernetes/client/live/AbstractLiveTest.java
+++ b/components/org.apache.stratos.kubernetes.client/src/test/java/org/apache/stratos/kubernetes/client/live/AbstractLiveTest.java
@@ -19,6 +19,11 @@
 
 package org.apache.stratos.kubernetes.client.live;
 
+import io.fabric8.kubernetes.api.model.Container;
+import io.fabric8.kubernetes.api.model.ContainerPort;
+import io.fabric8.kubernetes.api.model.Pod;
+import io.fabric8.kubernetes.api.model.Service;
+import io.fabric8.kubernetes.api.model.resource.Quantity;
 import junit.framework.TestCase;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.commons.logging.Log;
@@ -26,15 +31,14 @@ import org.apache.commons.logging.LogFactory;
 import org.apache.stratos.kubernetes.client.KubernetesApiClient;
 import org.apache.stratos.kubernetes.client.KubernetesConstants;
 import org.apache.stratos.kubernetes.client.exceptions.KubernetesClientException;
-import org.apache.stratos.kubernetes.client.model.Pod;
-import org.apache.stratos.kubernetes.client.model.Port;
-import org.apache.stratos.kubernetes.client.model.Service;
 import org.junit.AfterClass;
 import org.junit.BeforeClass;
 
 import java.io.IOException;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
+import java.util.Map;
 import java.util.concurrent.CopyOnWriteArrayList;
 
 /**
@@ -65,7 +69,7 @@ public class AbstractLiveTest extends TestCase {
     protected int containerPort;
     protected boolean testPodActivation;
     protected boolean testServiceSocket;
-    protected String[] minionPublicIPs = {"172.17.8.102"};
+    protected List<String> minionPublicIPs = Arrays.asList("172.17.8.102");
     protected List<String> podIdList = new CopyOnWriteArrayList<String>();
     protected List<String> serviceIdList = new CopyOnWriteArrayList<String>();
 
@@ -74,8 +78,7 @@ public class AbstractLiveTest extends TestCase {
         log.info("Setting up live test...");
         endpoint = System.getProperty(KUBERNETES_API_ENDPOINT);
         if (endpoint == null) {
-            endpoint = "http://" + DEFAULT_KUBERNETES_MASTER_IP + ":" + KUBERNETES_API_PORT + "/api/"
-                    + KubernetesConstants.KUBERNETES_API_VERSION + "/";
+            endpoint = "http://" + DEFAULT_KUBERNETES_MASTER_IP + ":" + KUBERNETES_API_PORT;
         }
         log.info(KUBERNETES_API_ENDPOINT + ": " + endpoint);
         client = new KubernetesApiClient(endpoint);
@@ -110,7 +113,7 @@ public class AbstractLiveTest extends TestCase {
 
         String minionPublicIPsStr = System.getProperty(MINION_PUBLIC_IPS);
         if (StringUtils.isNotBlank(minionPublicIPsStr)) {
-            minionPublicIPs = minionPublicIPsStr.split(",");
+            minionPublicIPs = Arrays.asList(minionPublicIPsStr.split(","));
         }
         log.info(MINION_PUBLIC_IPS + ": " + minionPublicIPsStr);
         log.info("Kubernetes live test setup completed");
@@ -124,9 +127,11 @@ public class AbstractLiveTest extends TestCase {
         log.info("Kubernetes resources cleaned");
     }
 
-    protected void createPod(String podId, String podName, String containerPortName, int cpu, int memory) throws KubernetesClientException {
+    protected void createPod(String podId, String podName, String containerPortName, int cpu, int memory)
+            throws KubernetesClientException {
+
         log.info("Creating pod: [pod] " + podId);
-        List<Port> ports = createPorts(containerPortName);
+        List<ContainerPort> ports = createPorts(containerPortName);
         client.createPod(podId, podName, dockerImage, cpu, memory, ports, null);
         podIdList.add(podId);
 
@@ -135,6 +140,17 @@ public class AbstractLiveTest extends TestCase {
         assertNotNull(pod);
         log.info("Pod created successfully: [pod] " + podId);
 
+        List<Container> containers = pod.getSpec().getContainers();
+        assertEquals(1, containers.size());
+
+        Map<String, Quantity> limits = containers.get(0).getResources().getLimits();
+        int memoryInMb = memory * 1024 * 1024;
+
+        log.info("Verifying container resource limits...");
+        assertEquals(String.valueOf(cpu), limits.get(KubernetesConstants.RESOURCE_CPU).getAmount());
+        assertEquals(String.valueOf(memoryInMb), limits.get(KubernetesConstants.RESOURCE_MEMORY).getAmount());
+        log.info("Container resource limits verified successfully");
+
         if (testPodActivation) {
             boolean activated = false;
             long startTime = System.currentTimeMillis();
@@ -148,17 +164,21 @@ public class AbstractLiveTest extends TestCase {
                 log.info("Waiting pod status to be changed to running: [pod] " + podId);
                 sleep(2000);
                 pod = client.getPod(podId);
-                if ((pod != null) && (pod.getCurrentState().getStatus().equals(KubernetesConstants.POD_STATUS_RUNNING))) {
+                if ((pod != null) && (pod.getStatus().getPhase().equals(KubernetesConstants.POD_STATUS_RUNNING))) {
                     activated = true;
-                    log.info("Pod state changed to running: [pod]" + pod.getId());
+                    log.info("Pod state changed to running: [pod]" + pod.getMetadata().getName());
                 }
             }
 
             assertNotNull(pod);
-            assertEquals(KubernetesConstants.POD_STATUS_RUNNING, pod.getCurrentState().getStatus());
+            assertEquals(KubernetesConstants.POD_STATUS_RUNNING, pod.getStatus().getPhase());
         }
     }
 
+    Pod getPod(String podId) throws KubernetesClientException {
+        return client.getPod(podId);
+    }
+
     void deletePod(String podId) throws KubernetesClientException {
         log.info("Deleting pod: " + podId);
         client.deletePod(podId);
@@ -180,9 +200,9 @@ public class AbstractLiveTest extends TestCase {
     }
 
     protected void createService(String serviceId, String serviceName, int servicePort, String containerPortName,
-                                 String[] publicIPs) throws KubernetesClientException, InterruptedException, IOException {
+                                 int containerPort, List<String> publicIPs) throws KubernetesClientException, InterruptedException, IOException {
         log.info("Creating service...");
-        client.createService(serviceId, serviceName, servicePort, containerPortName, publicIPs,
+        client.createService(serviceId, serviceName, servicePort, containerPortName, containerPort, publicIPs,
                 KubernetesConstants.SESSION_AFFINITY_CLIENT_IP);
         serviceIdList.add(serviceId);
 
@@ -192,6 +212,10 @@ public class AbstractLiveTest extends TestCase {
         log.info("Service creation successful");
     }
 
+    Service getService(String serviceId) throws KubernetesClientException {
+        return client.getService(serviceId);
+    }
+
     void deleteService(String serviceId) throws KubernetesClientException {
         log.info(String.format("Deleting service: [service] %s", serviceId));
         client.deleteService(serviceId);
@@ -219,9 +243,9 @@ public class AbstractLiveTest extends TestCase {
         }
     }
 
-    protected List<Port> createPorts(String containerPortName) {
-        List<Port> ports = new ArrayList<Port>();
-        Port port = new Port();
+    protected List<ContainerPort> createPorts(String containerPortName) {
+        List<ContainerPort> ports = new ArrayList<ContainerPort>();
+        ContainerPort port = new ContainerPort();
         port.setName(containerPortName);
         port.setContainerPort(containerPort);
         port.setProtocol("tcp");

http://git-wip-us.apache.org/repos/asf/stratos/blob/3414e7ce/components/org.apache.stratos.kubernetes.client/src/test/java/org/apache/stratos/kubernetes/client/live/KubernetesApiClientLiveTest.java
----------------------------------------------------------------------
diff --git a/components/org.apache.stratos.kubernetes.client/src/test/java/org/apache/stratos/kubernetes/client/live/KubernetesApiClientLiveTest.java b/components/org.apache.stratos.kubernetes.client/src/test/java/org/apache/stratos/kubernetes/client/live/KubernetesApiClientLiveTest.java
index 7983194..64c2f69 100644
--- a/components/org.apache.stratos.kubernetes.client/src/test/java/org/apache/stratos/kubernetes/client/live/KubernetesApiClientLiveTest.java
+++ b/components/org.apache.stratos.kubernetes.client/src/test/java/org/apache/stratos/kubernetes/client/live/KubernetesApiClientLiveTest.java
@@ -20,6 +20,7 @@
  */
 package org.apache.stratos.kubernetes.client.live;
 
+import io.fabric8.kubernetes.api.model.Pod;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.apache.stratos.kubernetes.client.exceptions.KubernetesClientException;
@@ -47,7 +48,7 @@ public class KubernetesApiClientLiveTest extends AbstractLiveTest {
     public void testPodCreation() throws Exception {
         log.info("Testing pod creation...");
 
-        createPod("stratos-test-pod-2", "stratos-test-pod", "http-1", 1, 512);
+        createPod("stratos-test-pod-1", "stratos-test-pod", "http-1", 1, 512);
         createPod("stratos-test-pod-2", "stratos-test-pod", "http-1", 2, 512);
 
         deletePod("stratos-test-pod-1");
@@ -71,23 +72,24 @@ public class KubernetesApiClientLiveTest extends AbstractLiveTest {
         String serviceName = "stratos-test-pod";
         String containerPortName = "http-1";
 
-        createService(serviceId, serviceName, SERVICE_PORT, containerPortName, minionPublicIPs);
+        createService(serviceId, serviceName, SERVICE_PORT, containerPortName, containerPort, minionPublicIPs);
 
-        createPod("stratos-test-pod-1", serviceName, containerPortName, 1, 512);
-        createPod("stratos-test-pod-2", serviceName, containerPortName, 2, 512);
+        createPod("stratos-test-pod-3", serviceName, containerPortName, 1, 512);
+        createPod("stratos-test-pod-4", serviceName, containerPortName, 2, 512);
 
         if (testServiceSocket) {
             // test service accessibility
-            log.info(String.format("Connecting to service: [portal] %s:%d", minionPublicIPs[0], SERVICE_PORT));
+            log.info(String.format("Connecting to service: [portal] %s:%d", minionPublicIPs.get(0), SERVICE_PORT));
             sleep(4000);
-            Socket socket = new Socket(minionPublicIPs[0], SERVICE_PORT);
+            Socket socket = new Socket(minionPublicIPs.get(0), SERVICE_PORT);
             assertTrue(socket.isConnected());
-            log.info(String.format("Connecting to service successful: [portal] %s:%d", minionPublicIPs[0], SERVICE_PORT));
+            log.info(String.format("Connecting to service successful: [portal] %s:%d", minionPublicIPs.get(0),
+                    SERVICE_PORT));
         }
 
         deleteService(serviceId);
 
-        deletePod("stratos-test-pod-1");
-        deletePod("stratos-test-pod-2");
+        deletePod("stratos-test-pod-3");
+        deletePod("stratos-test-pod-4");
     }
 }

http://git-wip-us.apache.org/repos/asf/stratos/blob/3414e7ce/components/org.apache.stratos.kubernetes.client/src/test/java/org/apache/stratos/kubernetes/client/live/KubernetesClusterCleanTest.java
----------------------------------------------------------------------
diff --git a/components/org.apache.stratos.kubernetes.client/src/test/java/org/apache/stratos/kubernetes/client/live/KubernetesClusterCleanTest.java b/components/org.apache.stratos.kubernetes.client/src/test/java/org/apache/stratos/kubernetes/client/live/KubernetesClusterCleanTest.java
index b8af5ca..c94cd0e 100644
--- a/components/org.apache.stratos.kubernetes.client/src/test/java/org/apache/stratos/kubernetes/client/live/KubernetesClusterCleanTest.java
+++ b/components/org.apache.stratos.kubernetes.client/src/test/java/org/apache/stratos/kubernetes/client/live/KubernetesClusterCleanTest.java
@@ -19,11 +19,11 @@
 
 package org.apache.stratos.kubernetes.client.live;
 
+import io.fabric8.kubernetes.api.model.Pod;
+import io.fabric8.kubernetes.api.model.Service;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.apache.stratos.kubernetes.client.exceptions.KubernetesClientException;
-import org.apache.stratos.kubernetes.client.model.Pod;
-import org.apache.stratos.kubernetes.client.model.Service;
 import org.junit.Test;
 
 import java.util.ArrayList;
@@ -43,7 +43,7 @@ public class KubernetesClusterCleanTest extends AbstractLiveTest {
             List<Pod> podList = getPods();
             while ((podList != null) && (podList.size() > 0)) {
                 for (Pod pod : podList) {
-                    deletePod(pod.getId());
+                    deletePod(pod.getMetadata().getName());
                 }
                 podList = client.getPods();
             }
@@ -51,7 +51,7 @@ public class KubernetesClusterCleanTest extends AbstractLiveTest {
             List<Service> serviceList = getServices();
             while ((serviceList != null) && (serviceList.size() > 0)) {
                 for (Service service : serviceList) {
-                    deleteService(service.getId());
+                    deleteService(service.getMetadata().getName());
                 }
                 serviceList = getServices();
             }
@@ -64,7 +64,7 @@ public class KubernetesClusterCleanTest extends AbstractLiveTest {
     private List<Pod> getPods() throws KubernetesClientException {
         List<Pod> podList = new ArrayList<Pod>();
         for(Pod pod : client.getPods()) {
-            if(!pod.getId().startsWith("kube")) {
+            if(!pod.getMetadata().getName().startsWith("kube")) {
                 podList.add(pod);
             }
         }
@@ -74,7 +74,7 @@ public class KubernetesClusterCleanTest extends AbstractLiveTest {
     private List<Service> getServices() throws KubernetesClientException {
         List<Service> serviceList = new ArrayList<Service>();
         for (Service service : client.getServices()) {
-            if (!service.getId().startsWith("kube")) {
+            if (!service.getMetadata().getName().startsWith("kube")) {
                 serviceList.add(service);
             }
         }

http://git-wip-us.apache.org/repos/asf/stratos/blob/3414e7ce/components/org.apache.stratos.kubernetes.client/src/test/java/org/apache/stratos/kubernetes/client/unit/PodUnitTest.java
----------------------------------------------------------------------
diff --git a/components/org.apache.stratos.kubernetes.client/src/test/java/org/apache/stratos/kubernetes/client/unit/PodUnitTest.java b/components/org.apache.stratos.kubernetes.client/src/test/java/org/apache/stratos/kubernetes/client/unit/PodUnitTest.java
deleted file mode 100644
index 27c2f54..0000000
--- a/components/org.apache.stratos.kubernetes.client/src/test/java/org/apache/stratos/kubernetes/client/unit/PodUnitTest.java
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- *
- * 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 org.apache.stratos.kubernetes.client.unit;
-
-import junit.framework.TestCase;
-import org.apache.stratos.kubernetes.client.model.*;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.experimental.categories.Category;
-
-@Category(org.apache.stratos.kubernetes.client.UnitTests.class)
-public class PodUnitTest extends TestCase {
-
-    @Before
-    public void setUp() {
-    }
-
-    @Test
-    public void testPods() throws Exception {
-        String podId = "nirmal-test-pod";
-        String time = "2014/11/02";
-        String selfLink = "link";
-        Pod pod = new Pod();
-        String apiVersion = "v1beta1";
-        pod.setApiVersion(apiVersion);
-        pod.setId(podId);
-        pod.setCreationTimestamp(time);
-        pod.setSelfLink(selfLink);
-        pod.setResourceVersion(apiVersion);
-        String kind = "Pod";
-        pod.setKind(kind);
-        Labels l = new Labels();
-        l.setName("nirmal");
-        pod.setLabels(l);
-        State desiredState = new State();
-        Manifest m = new Manifest();
-        m.setId(podId);
-        m.setVersion(apiVersion);
-        Container c = new Container();
-        c.setName("master");
-        c.setImage("image");
-        Port p = new Port();
-        p.setContainerPort(8379);
-        p.setHostPort(8379);
-        c.addPort(p);
-        m.addContainer(c);
-        desiredState.setManifest(m);
-        pod.setDesiredState(desiredState);
-        State currentState = desiredState;
-        pod.setCurrentState(currentState);
-
-        assertEquals(podId, pod.getId());
-        assertEquals(apiVersion, pod.getApiVersion());
-        assertEquals(apiVersion, pod.getResourceVersion());
-        assertEquals(kind, pod.getKind());
-        assertEquals(l, pod.getLabels());
-        assertEquals(currentState, pod.getCurrentState());
-        assertEquals(selfLink, pod.getSelfLink());
-        assertEquals(desiredState, pod.getDesiredState());
-        assertEquals(time, pod.getCreationTimestamp());
-
-        assertEquals(true, pod.equals(pod));
-
-        Pod pod2 = new Pod();
-        pod2.setId(podId);
-
-        assertEquals(true, pod.equals(pod2));
-        assertEquals(true, pod.hashCode() == pod2.hashCode());
-
-        pod2.setId("aa");
-        assertEquals(false, pod.equals(pod2));
-
-        pod2.setId(null);
-        assertEquals(false, pod.equals(pod2));
-
-        assertEquals(false, pod.equals(null));
-        assertEquals(false, pod.equals(desiredState));
-
-        pod.setId(null);
-        pod2.setId(podId);
-        assertEquals(false, pod.equals(pod2));
-
-        pod2.setId(null);
-        assertEquals(true, pod.equals(pod2));
-        assertEquals(true, pod.hashCode() == pod2.hashCode());
-
-    }
-}

http://git-wip-us.apache.org/repos/asf/stratos/blob/3414e7ce/components/org.apache.stratos.messaging/pom.xml
----------------------------------------------------------------------
diff --git a/components/org.apache.stratos.messaging/pom.xml b/components/org.apache.stratos.messaging/pom.xml
index f75f11c..7316270 100644
--- a/components/org.apache.stratos.messaging/pom.xml
+++ b/components/org.apache.stratos.messaging/pom.xml
@@ -30,7 +30,7 @@
     <groupId>org.apache.stratos</groupId>
     <artifactId>org.apache.stratos.messaging</artifactId>
     <packaging>bundle</packaging>
-    <name>Apache Stratos - Messaging Component</name>
+    <name>Apache Stratos - Messaging</name>
     <url>http://apache.org</url>
 
     <dependencies>
@@ -113,12 +113,12 @@
                         <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
                         <Bundle-Name>${project.artifactId}</Bundle-Name>
                         <Export-Package>
+                            org.apache.stratos.messaging,
                             org.apache.stratos.messaging.*,
+                            org.apache.stratos.messaging.topology,
+                            org.apache.stratos.messaging.topology.*,
                             org.apache.stratos.messaging.util.MessagingConstants,
                         </Export-Package>
-                        <!--Private-Package>
-                        	org.apache.stratos.messaging.internal;
-                        </Private-Package-->
                         <Import-Package>
                             !org.apache.commons.logging,
                             org.apache.commons.logging; version=0.0.0,

http://git-wip-us.apache.org/repos/asf/stratos/blob/3414e7ce/components/pom.xml
----------------------------------------------------------------------
diff --git a/components/pom.xml b/components/pom.xml
index 7bbe37d..ff05c41 100644
--- a/components/pom.xml
+++ b/components/pom.xml
@@ -66,7 +66,6 @@
         <!-- Redirector -->
         <module>org.apache.stratos.sso.redirector.ui</module>
         <module>org.apache.stratos.keystore.mgt</module>
-        <module>org.apache.stratos.activation</module>
         <!--Logging mgt-->
         <module>org.apache.stratos.logging.view.ui</module>
         <!-- RESTful admin services -->

http://git-wip-us.apache.org/repos/asf/stratos/blob/3414e7ce/dependencies/fabric8/kubernetes-api/README.md
----------------------------------------------------------------------
diff --git a/dependencies/fabric8/kubernetes-api/README.md b/dependencies/fabric8/kubernetes-api/README.md
new file mode 100644
index 0000000..1f8c473
--- /dev/null
+++ b/dependencies/fabric8/kubernetes-api/README.md
@@ -0,0 +1,7 @@
+## Fabric8 Kubernetes Client API
+
+Fabric8 Kubernetes Client API 2.1.11 has been forked to fix issue [1]. The fix has been merged to master branch,
+once the next Fabric8 release is published to Nexus this fork can be removed.
+
+[1] [origin-schema-generator/pull/50] (https://github.com/fabric8io/origin-schema-generator/pull/50)
+

http://git-wip-us.apache.org/repos/asf/stratos/blob/3414e7ce/dependencies/fabric8/kubernetes-api/pom.xml
----------------------------------------------------------------------
diff --git a/dependencies/fabric8/kubernetes-api/pom.xml b/dependencies/fabric8/kubernetes-api/pom.xml
new file mode 100644
index 0000000..936935a
--- /dev/null
+++ b/dependencies/fabric8/kubernetes-api/pom.xml
@@ -0,0 +1,214 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+     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.
+
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <groupId>org.apache.stratos</groupId>
+    <artifactId>stratos-dependencies-fabric8</artifactId>
+    <version>4.1.0-SNAPSHOT</version>
+    <relativePath>../pom.xml</relativePath>
+  </parent>
+
+  <artifactId>kubernetes-api</artifactId>
+  <version>2.1.11-stratosv1</version>
+  <packaging>bundle</packaging>
+
+  <name>Fabric8 :: Kubernetes API</name>
+
+  <dependencies>
+    <dependency>
+      <groupId>io.fabric8</groupId>
+      <artifactId>cxf-utils</artifactId>
+      <version>2.1.11</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.stratos</groupId>
+      <artifactId>kubernetes-model</artifactId>
+      <version>2.1.11-stratosv1</version>
+    </dependency>
+    <dependency>
+      <groupId>com.fasterxml.jackson.jaxrs</groupId>
+      <artifactId>jackson-jaxrs-json-provider</artifactId>
+      <version>2.4.1</version>
+    </dependency>
+    <dependency>
+      <groupId>com.fasterxml.jackson.dataformat</groupId>
+      <artifactId>jackson-dataformat-yaml</artifactId>
+      <version>2.4.1</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.cxf</groupId>
+      <artifactId>cxf-rt-rs-client</artifactId>
+      <version>3.0.4</version>
+    </dependency>
+    <dependency>
+      <groupId>org.slf4j</groupId>
+      <artifactId>slf4j-api</artifactId>
+      <version>1.7.12</version>
+    </dependency>
+    <dependency>
+      <groupId>org.yaml</groupId>
+      <artifactId>snakeyaml</artifactId>
+      <version>1.5</version>
+    </dependency>
+    <dependency>
+      <groupId>org.json</groupId>
+      <artifactId>json</artifactId>
+      <version>20140107</version>
+    </dependency>
+    <dependency>
+      <groupId>net.oauth.core</groupId>
+      <artifactId>oauth</artifactId>
+      <version>20100527</version>
+    </dependency>
+    <dependency>
+      <groupId>dnsjava</groupId>
+      <artifactId>dnsjava</artifactId>
+      <version>2.1.7</version>
+    </dependency>
+    <dependency>
+      <groupId>org.eclipse.jetty.websocket</groupId>
+      <artifactId>websocket-client</artifactId>
+      <version>9.1.5.v20140505</version>
+    </dependency>
+    <dependency>
+      <groupId>org.eclipse.jetty</groupId>
+      <artifactId>jetty-io</artifactId>
+      <version>9.1.5.v20140505</version>
+    </dependency>
+    <dependency>
+      <groupId>org.eclipse.jetty</groupId>
+      <artifactId>jetty-util</artifactId>
+      <version>9.1.5.v20140505</version>
+    </dependency>
+    <!-- dependency>
+      <groupId>javax.ws.rs</groupId>
+      <artifactId>javax.ws.rs-api</artifactId>
+      <version>2.0.1</version>
+    </dependency -->
+    <!-- testing -->
+    <dependency>
+      <groupId>org.assertj</groupId>
+      <artifactId>assertj-core</artifactId>
+      <version>1.7.0</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.slf4j</groupId>
+      <artifactId>slf4j-log4j12</artifactId>
+      <version>1.7.12</version>
+      <scope>test</scope>
+    </dependency>
+    <!-- lets force the codegen to run first -->
+    <dependency>
+      <groupId>io.fabric8</groupId>
+      <artifactId>kubernetes-codegen</artifactId>
+      <version>2.1.11</version>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-bundle-plugin</artifactId>
+        <extensions>true</extensions>
+        <version>2.3.7</version>
+        <configuration>
+          <instructions>
+            <Bundle-SymbolicName>${project.groupId}.${project.artifactId}</Bundle-SymbolicName>
+            <Export-Package>
+              io.fabric8.kubernetes.api.*,
+            </Export-Package>
+            <Import-Package>
+              !javax.xml.bind.annotation.adapters,
+              org.osgi.framework,
+              *;resolution:=optional
+            </Import-Package>
+            <DynamicImport-Package>*</DynamicImport-Package>
+            <!-- Embedding apache cxf dependencies as they cannot be imported into carbon runtime at the moment -->
+            <Embed-Dependency>
+              jackson-annotations,jackson-core,jackson-databind,jackson-jaxrs-base,jackson-jaxrs-json-provider,
+              jackson-module-jaxb-annotations,jackson-dataformat-yaml,javax.annotation-api,javax.ws.rs-api,
+              jetty-io,jetty-util,json,oauth,xmlschema-core,fabric8-utils,cxf-utils,
+              cxf-rt-rs-client,cxf-rt-transports-http,cxf-rt-frontend-jaxrs,cxf-core,dnsjava
+            </Embed-Dependency>
+            <Embed-Transitive>true</Embed-Transitive>
+          </instructions>
+        </configuration>
+      </plugin>
+      <plugin>
+        <groupId>org.codehaus.mojo</groupId>
+        <artifactId>exec-maven-plugin</artifactId>
+        <version>1.2.1</version>
+        <executions>
+          <execution>
+            <goals>
+              <goal>java</goal>
+            </goals>
+          </execution>
+        </executions>
+        <configuration>
+          <mainClass>io.fabric8.kubernetes.api.Example</mainClass>
+          <classpathScope>test</classpathScope>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+
+
+  <profiles>
+    <profile>
+      <id>trigger</id>
+      <properties>
+        <build>console-build</build>
+      </properties>
+
+      <build>
+        <plugins>
+          <plugin>
+            <groupId>org.codehaus.mojo</groupId>
+            <artifactId>exec-maven-plugin</artifactId>
+            <version>${exec-maven-plugin.version}</version>
+            <executions>
+              <execution>
+                <goals>
+                  <goal>exec</goal>
+                </goals>
+              </execution>
+            </executions>
+            <configuration>
+              <executable>java</executable>
+              <classpathScope>test</classpathScope>
+              <!-- TODO for some reason this fails when running inside maven - wacky! -->
+              <arguments>
+                <argument>-classpath</argument>
+                <classpath />
+                <argument>io.fabric8.kubernetes.api.TriggerBuild</argument>
+                <argument>${build}</argument>
+              </arguments>
+            </configuration>
+          </plugin>
+        </plugins>
+      </build>
+    </profile>
+  </profiles>
+</project>

http://git-wip-us.apache.org/repos/asf/stratos/blob/3414e7ce/dependencies/fabric8/kubernetes-api/src/main/java/io/fabric8/kubernetes/api/AbstractWatcher.java
----------------------------------------------------------------------
diff --git a/dependencies/fabric8/kubernetes-api/src/main/java/io/fabric8/kubernetes/api/AbstractWatcher.java b/dependencies/fabric8/kubernetes-api/src/main/java/io/fabric8/kubernetes/api/AbstractWatcher.java
new file mode 100644
index 0000000..68793bc
--- /dev/null
+++ b/dependencies/fabric8/kubernetes-api/src/main/java/io/fabric8/kubernetes/api/AbstractWatcher.java
@@ -0,0 +1,61 @@
+package io.fabric8.kubernetes.api;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import io.fabric8.kubernetes.api.model.HasMetadata;
+import io.fabric8.kubernetes.api.watch.WatchEvent;
+import org.eclipse.jetty.websocket.api.Session;
+import org.eclipse.jetty.websocket.api.UpgradeException;
+import org.eclipse.jetty.websocket.api.WebSocketAdapter;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+
+public abstract class AbstractWatcher<T extends HasMetadata> extends WebSocketAdapter implements Watcher<T> {
+
+    private static final transient Logger LOG = LoggerFactory.getLogger(KubernetesClient.class);
+
+    private ObjectMapper objectMapper;
+
+    @Override
+    public void onWebSocketConnect(Session sess) {
+        super.onWebSocketConnect(sess);
+        LOG.debug("Got connect: {}", sess);
+        objectMapper = KubernetesFactory.createObjectMapper();
+    }
+
+    @Override
+    public void onWebSocketClose(int statusCode, String reason) {
+        super.onWebSocketClose(statusCode, reason);
+        LOG.debug("Connection closed: {} - {}", statusCode, reason);
+        objectMapper = null;
+    }
+
+    @Override
+    public void onWebSocketText(String message) {
+        LOG.trace("Received message: {}", message);
+        if (message != null && message.length() > 0) {
+            try {
+                WatchEvent event = objectMapper.reader(WatchEvent.class).readValue(message);
+                T obj = (T) event.getObject();
+                Action action = Action.valueOf(event.getType());
+                eventReceived(action, obj);
+            } catch (IOException e) {
+                LOG.error("Could not deserialize watch event: {}", message, e);
+            } catch (ClassCastException e) {
+                LOG.error("Received wrong type of object for watch", e);
+            } catch (IllegalArgumentException e) {
+                LOG.error("Invalid event type", e);
+            }
+        }
+    }
+
+    public void onWebSocketError(Throwable cause) {
+        if (cause instanceof UpgradeException) {
+            LOG.error("WebSocketError: Could not upgrade connection: {}", (((UpgradeException) cause).getResponseStatusCode()), cause);
+        } else {
+            LOG.error("WebSocketError: {}", cause);
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/stratos/blob/3414e7ce/dependencies/fabric8/kubernetes-api/src/main/java/io/fabric8/kubernetes/api/Controller.java
----------------------------------------------------------------------
diff --git a/dependencies/fabric8/kubernetes-api/src/main/java/io/fabric8/kubernetes/api/Controller.java b/dependencies/fabric8/kubernetes-api/src/main/java/io/fabric8/kubernetes/api/Controller.java
new file mode 100644
index 0000000..3e90776
--- /dev/null
+++ b/dependencies/fabric8/kubernetes-api/src/main/java/io/fabric8/kubernetes/api/Controller.java
@@ -0,0 +1,850 @@
+/**
+ *  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 com.fasterxml.jackson.core.JsonProcessingException;
+import io.fabric8.kubernetes.api.extensions.Templates;
+import io.fabric8.kubernetes.api.model.HasMetadata;
+import io.fabric8.kubernetes.api.model.KubernetesList;
+import io.fabric8.kubernetes.api.model.Namespace;
+import io.fabric8.kubernetes.api.model.Pod;
+import io.fabric8.kubernetes.api.model.PodSpec;
+import io.fabric8.kubernetes.api.model.PodTemplateSpec;
+import io.fabric8.kubernetes.api.model.ReplicationController;
+import io.fabric8.kubernetes.api.model.ReplicationControllerSpec;
+import io.fabric8.kubernetes.api.model.SecretVolumeSource;
+import io.fabric8.kubernetes.api.model.Service;
+import io.fabric8.kubernetes.api.model.Volume;
+import io.fabric8.openshift.api.model.BuildConfig;
+import io.fabric8.openshift.api.model.DeploymentConfig;
+import io.fabric8.openshift.api.model.ImageStream;
+import io.fabric8.openshift.api.model.OAuthClient;
+import io.fabric8.openshift.api.model.Route;
+import io.fabric8.openshift.api.model.template.Template;
+import io.fabric8.utils.Files;
+import io.fabric8.utils.IOHelpers;
+import io.fabric8.utils.Objects;
+import io.fabric8.utils.Strings;
+import org.json.JSONObject;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.yaml.snakeyaml.Yaml;
+
+import javax.ws.rs.WebApplicationException;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.List;
+import java.util.Map;
+
+import static io.fabric8.kubernetes.api.KubernetesHelper.getName;
+import static io.fabric8.kubernetes.api.KubernetesHelper.getObjectId;
+import static io.fabric8.kubernetes.api.KubernetesHelper.getOrCreateMetadata;
+import static io.fabric8.kubernetes.api.KubernetesHelper.getPodMap;
+import static io.fabric8.kubernetes.api.KubernetesHelper.getReplicationControllerMap;
+import static io.fabric8.kubernetes.api.KubernetesHelper.getServiceMap;
+import static io.fabric8.kubernetes.api.KubernetesHelper.loadJson;
+import static io.fabric8.kubernetes.api.KubernetesHelper.summaryText;
+import static io.fabric8.kubernetes.api.KubernetesHelper.toItemList;
+
+/**
+ * Applies DTOs to the current Kubernetes master
+ */
+public class Controller {
+    private static final transient Logger LOG = LoggerFactory.getLogger(Controller.class);
+
+    private final KubernetesClient kubernetes;
+    private Map<String, Pod> podMap;
+    private Map<String, ReplicationController> replicationControllerMap;
+    private Map<String, Service> serviceMap;
+    private boolean throwExceptionOnError = true;
+    private boolean allowCreate = true;
+    private boolean recreateMode;
+    private boolean servicesOnlyMode;
+    private boolean ignoreServiceMode;
+    private boolean ignoreRunningOAuthClients = true;
+    private boolean processTemplatesLocally;
+    private File logJsonDir;
+    private File basedir;
+
+    public Controller() {
+        this(new KubernetesClient());
+    }
+
+    public Controller(KubernetesClient kubernetes) {
+        this.kubernetes = kubernetes;
+    }
+
+    public String apply(File file) throws Exception {
+        String ext = Files.getFileExtension(file);
+
+        if ("yaml".equalsIgnoreCase(ext)) {
+            return applyYaml(file);
+        } else if ("json".equalsIgnoreCase(ext)) {
+            return applyJson(file);
+        } else {
+            throw new IllegalArgumentException("Unknown file type " + ext);
+        }
+    }
+
+    /**
+     * Applies the given JSON to the underlying REST APIs in a single operation without needing to explicitly parse first.
+     */
+    public String applyJson(byte[] json) throws Exception {
+        Object dto = loadJson(json);
+        apply(dto, "REST call");
+        return "";
+    }
+
+    /**
+     * Applies the given JSON to the underlying REST APIs in a single operation without needing to explicitly parse first.
+     */
+    public String applyJson(String json) throws Exception {
+        Object dto = loadJson(json);
+        apply(dto, "REST call");
+        return "";
+    }
+
+    /**
+     * Applies the given JSON to the underlying REST APIs in a single operation without needing to explicitly parse first.
+     */
+    public String applyJson(File json) throws Exception {
+        Object dto = loadJson(json);
+        apply(dto, "REST call");
+        return "";
+    }
+
+    /**
+     * Applies the given YAML to the underlying REST APIs in a single operation without needing to explicitly parse first.
+     */
+    public String applyYaml(String yaml) throws Exception {
+        String json = convertYamlToJson(yaml);
+        Object dto = loadJson(json);
+        apply(dto, "REST call");
+        return "";
+    }
+
+    /**
+     * Applies the given YAML to the underlying REST APIs in a single operation without needing to explicitly parse first.
+     */
+    public String applyYaml(File yaml) throws Exception {
+        String json = convertYamlToJson(yaml);
+        Object dto = loadJson(json);
+        apply(dto, "REST call");
+        return "";
+    }
+
+    private String convertYamlToJson(String yamlString) throws FileNotFoundException {
+        Yaml yaml = new Yaml();
+
+        Map<String, Object> map = (Map<String, Object>) yaml.load(yamlString);
+        JSONObject jsonObject = new JSONObject(map);
+
+        return jsonObject.toString();
+    }
+
+    private String convertYamlToJson(File yamlFile) throws FileNotFoundException {
+        Yaml yaml = new Yaml();
+        FileInputStream fstream = new FileInputStream(yamlFile);
+
+        Map<String, Object> map = (Map<String, Object>) yaml.load(fstream);
+        JSONObject jsonObject = new JSONObject(map);
+
+        return jsonObject.toString();
+    }
+
+    /**
+     * Applies the given JSON to the underlying REST APIs in a single operation without needing to explicitly parse first.
+     */
+    public String applyJson(InputStream json) throws Exception {
+        Object dto = loadJson(json);
+        apply(dto, "REST call");
+        return "";
+    }
+
+    /**
+     * Applies the given DTOs onto the Kubernetes master
+     */
+    public void apply(Object dto, String sourceName) throws Exception {
+        if (dto instanceof List) {
+            List list = (List) dto;
+            for (Object element : list) {
+                if (dto == element) {
+                    LOG.warn("Found recursive nested object for " + dto + " of class: " + dto.getClass().getName());
+                    continue;
+                }
+                apply(element, sourceName);
+            }
+        } else if (dto instanceof KubernetesList) {
+            applyList((KubernetesList) dto, sourceName);
+        } else if (dto != null) {
+            applyEntity(dto, sourceName);
+        }
+    }
+
+    /**
+     * Applies the given DTOs onto the Kubernetes master
+     */
+    public void applyEntity(Object dto, String sourceName) throws Exception {
+        if (dto instanceof Pod) {
+            applyPod((Pod) dto, sourceName);
+        } else if (dto instanceof ReplicationController) {
+            applyReplicationController((ReplicationController) dto, sourceName);
+        } else if (dto instanceof Service) {
+            applyService((Service) dto, sourceName);
+        } else if (dto instanceof Namespace) {
+            applyNamespace((Namespace) dto);
+        } else if (dto instanceof Route) {
+            applyRoute((Route) dto, sourceName);
+        } else if (dto instanceof BuildConfig) {
+            applyBuildConfig((BuildConfig) dto, sourceName);
+        } else if (dto instanceof DeploymentConfig) {
+            applyDeploymentConfig((DeploymentConfig) dto, sourceName);
+        } else if (dto instanceof ImageStream) {
+            applyImageStream((ImageStream) dto, sourceName);
+        } else if (dto instanceof OAuthClient) {
+            applyOAuthClient((OAuthClient) dto, sourceName);
+        } else if (dto instanceof Template) {
+            applyTemplate((Template) dto, sourceName);
+        } else {
+            throw new IllegalArgumentException("Unknown entity type " + dto);
+        }
+    }
+
+    public void applyOAuthClient(OAuthClient entity, String sourceName) {
+        String id = getName(entity);
+        Objects.notNull(id, "No name for " + entity + " " + sourceName);
+        if (isServicesOnlyMode()) {
+            LOG.debug("Only processing Services right now so ignoring OAuthClient: " + id);
+            return;
+        }
+        OAuthClient old = kubernetes.getOAuthClient(id);
+        if (isRunning(old)) {
+            if (isIgnoreRunningOAuthClients()) {
+                LOG.info("Not updating the OAuthClient which are shared across namespaces as its already running");
+                return;
+            }
+            if (UserConfigurationCompare.configEqual(entity, old)) {
+                LOG.info("OAuthClient hasn't changed so not doing anything");
+            } else {
+                if (isRecreateMode()) {
+                    kubernetes.deleteOAuthClient(id);
+                    doCreateOAuthClient(entity, sourceName);
+                } else {
+                    try {
+                        Object answer = kubernetes.updateOAuthClient(id, entity);
+                        LOG.info("Updated pod result: " + answer);
+                    } catch (Exception e) {
+                        onApplyError("Failed to update pod from " + sourceName + ". " + e + ". " + entity, e);
+                    }
+                }
+            }
+        } else {
+            if (!isAllowCreate()) {
+                LOG.warn("Creation disabled so not creating an OAuthClient from " + sourceName + " name " + getName(entity));
+            } else {
+                doCreateOAuthClient(entity, sourceName);
+            }
+        }
+    }
+
+    protected void doCreateOAuthClient(OAuthClient entity, String sourceName) {
+        Object result = null;
+        try {
+            result = kubernetes.createOAuthClient(entity);
+        } catch (Exception e) {
+            onApplyError("Failed to create OAuthClient from " + sourceName + ". " + e + ". " + entity, e);
+        }
+    }
+
+    /**
+     * Creates/updates the template and processes it returning the processed DTOs
+     */
+    public Object applyTemplate(Template entity, String sourceName) throws Exception {
+        if (!isProcessTemplatesLocally()) {
+            String namespace = getNamespace();
+            String id = getName(entity);
+            Objects.notNull(id, "No name for " + entity + " " + sourceName);
+            Template old = kubernetes.getTemplate(id, namespace);
+            if (isRunning(old)) {
+                if (UserConfigurationCompare.configEqual(entity, old)) {
+                    LOG.info("Template hasn't changed so not doing anything");
+                } else {
+                    boolean recreateMode = isRecreateMode();
+                    // TODO seems you can't update templates right now
+                    recreateMode = true;
+                    if (recreateMode) {
+                        kubernetes.deleteTemplate(id, namespace);
+                        doCreateTemplate(entity, namespace, sourceName);
+                    } else {
+                        LOG.info("Updating a entity from " + sourceName);
+                        try {
+                            Object answer = kubernetes.updateTemplate(id, entity, namespace);
+                            LOG.info("Updated entity: " + answer);
+                        } catch (Exception e) {
+                            onApplyError("Failed to update controller from " + sourceName + ". " + e + ". " + entity, e);
+                        }
+                    }
+                }
+            } else {
+                if (!isAllowCreate()) {
+                    LOG.warn("Creation disabled so not creating a entity from " + sourceName + " namespace " + namespace + " name " + getName(entity));
+                } else {
+                    doCreateTemplate(entity, namespace, sourceName);
+                }
+            }
+        }
+        return processTemplate(entity, sourceName);
+    }
+
+    protected void doCreateTemplate(Template entity, String namespace, String sourceName) {
+        LOG.info("Creating a template from " + sourceName + " namespace " + namespace + " name " + getName(entity));
+        try {
+            Object answer = kubernetes.createTemplate(entity, namespace);
+            logGeneratedEntity("Created template: ", namespace, entity, answer);
+        } catch (Exception e) {
+            onApplyError("Failed to template entity from " + sourceName + ". " + e + ". " + entity, e);
+        }
+    }
+
+    protected void logGeneratedEntity(String message, String namespace, HasMetadata entity, Object result) {
+        if (logJsonDir != null) {
+            File namespaceDir = new File(logJsonDir, namespace);
+            namespaceDir.mkdirs();
+            String kind = KubernetesHelper.getKind(entity);
+            String name = KubernetesHelper.getName(entity);
+            if (Strings.isNotBlank(kind)) {
+                name = kind.toLowerCase() + "-" + name;
+            }
+            if (Strings.isNullOrBlank(name)) {
+                LOG.warn("No name for the entity " + entity);
+            } else {
+                String fileName = name + ".json";
+                File file = new File(namespaceDir, fileName);
+                if (file.exists()) {
+                    int idx = 1;
+                    while (true) {
+                        fileName = name + "-" + idx++ + ".json";
+                        file = new File(namespaceDir, fileName);
+                        if (!file.exists()) {
+                            break;
+                        }
+                    }
+                }
+                String text;
+                if (result instanceof String) {
+                    text = result.toString();
+                } else {
+                    try {
+                        text = KubernetesHelper.toJson(result);
+                    } catch (JsonProcessingException e) {
+                        LOG.warn("Could not convert " + result + " to JSON: " + e, e);
+                        if (result != null) {
+                            text = result.toString();
+                        } else {
+                            text = "null";
+                        }
+                    }
+                }
+                try {
+                    IOHelpers.writeFully(file, text);
+                    Object fileLocation = file;
+                    if (basedir != null) {
+                        String path = Files.getRelativePath(basedir, file);
+                        if (path != null) {
+                            fileLocation = Strings.stripPrefix(path, "/");
+                        }
+                    }
+                    LOG.info(message + fileLocation);
+                } catch (IOException e) {
+                    LOG.warn("Failed to write to file " + file + ". " + e, e);
+                }
+                return;
+            }
+        }
+        LOG.info(message + result);
+    }
+
+    public Object processTemplate(Template entity, String sourceName) {
+        if (isProcessTemplatesLocally()) {
+            try {
+                return Templates.processTemplatesLocally(entity);
+            } catch (IOException e) {
+                onApplyError("Failed to process template " + sourceName + ". " + e + ". " + entity, e);
+                return null;
+            }
+        } else {
+            String id = getName(entity);
+            Objects.notNull(id, "No name for " + entity + " " + sourceName);
+            String namespace = KubernetesHelper.getNamespace(entity);
+            LOG.info("Creating Template " + namespace + ":" + id + " " + summaryText(entity));
+            Object result = null;
+            try {
+                String json = kubernetes.processTemplate(entity, namespace);
+                logGeneratedEntity("Template processed into: ", namespace, entity, json);
+                result = loadJson(json);
+                printSummary(result);
+            } catch (Exception e) {
+                onApplyError("Failed to create controller from " + sourceName + ". " + e + ". " + entity, e);
+            }
+            return result;
+        }
+    }
+
+
+    protected void printSummary(Object kubeResource) throws IOException {
+        if (kubeResource != null) {
+            LOG.debug("  " + kubeResource.getClass().getSimpleName() + " " + kubeResource);
+        }
+        if (kubeResource instanceof Template) {
+            Template template = (Template) kubeResource;
+            String id = getName(template);
+            LOG.info("  Template " + id + " " + summaryText(template));
+            printSummary(template.getObjects());
+            return;
+        }
+        List<HasMetadata> list = toItemList(kubeResource);
+        for (HasMetadata object : list) {
+            if (object != null) {
+                if (object == list) {
+                    LOG.warn("Ignoring recursive list " + list);
+                    continue;
+                } else if (object instanceof List) {
+                    printSummary(object);
+                } else {
+                    String kind = object.getClass().getSimpleName();
+                    String id = getObjectId(object);
+                    LOG.info("    " + kind + " " + id + " " + summaryText(object));
+                }
+            }
+        }
+    }
+
+    public void applyRoute(Route entity, String sourceName) {
+        String id = getName(entity);
+        Objects.notNull(id, "No name for " + entity + " " + sourceName);
+        String namespace = KubernetesHelper.getNamespace(entity);
+        if (Strings.isNullOrBlank(namespace)) {
+            namespace = kubernetes.getNamespace();
+        }
+        Route route = kubernetes.findRoute(id, namespace);
+        if (route == null) {
+            try {
+                LOG.info("Creating Route " + namespace + ":" + id + " " + KubernetesHelper.summaryText(entity));
+                kubernetes.createRoute(entity, namespace);
+            } catch (WebApplicationException e) {
+                if (e.getResponse().getStatus() == 404) {
+                    // could be OpenShift 0.4.x which has the old style REST API - lets try that...
+                    LOG.warn("Got a 404 - could be an old Kubernetes/OpenShift environment - lets try the old style REST API...");
+                    try {
+                        kubernetes.createRouteOldAPi(entity, namespace);
+                    } catch (Exception e1) {
+                        onApplyError("Failed to create Route from " + sourceName + ". " + e1 + ". " + entity, e1);
+                    }
+                } else {
+                    onApplyError("Failed to create Route from " + sourceName + ". " + e + ". " + entity, e);
+                }
+            } catch (Exception e) {
+                onApplyError("Failed to create Route from " + sourceName + ". " + e + ". " + entity, e);
+            }
+        }
+    }
+
+    public void applyBuildConfig(BuildConfig entity, String sourceName) {
+        String id = getName(entity);
+        Objects.notNull(id, "No name for " + entity + " " + sourceName);
+        String namespace = KubernetesHelper.getNamespace(entity);
+        if (Strings.isNullOrBlank(namespace)) {
+            namespace = kubernetes.getNamespace();
+        }
+        BuildConfig old = kubernetes.getBuildConfig(id, namespace);
+        if (isRunning(old)) {
+            if (UserConfigurationCompare.configEqual(entity, old)) {
+                LOG.info("BuildConfig hasn't changed so not doing anything");
+            } else {
+                if (isRecreateMode()) {
+                    kubernetes.deleteBuildConfig(id, namespace);
+                    doCreateBuildConfig(entity, namespace, sourceName);
+                } else {
+                    LOG.info("Updating BuildConfig from " + sourceName);
+                    try {
+                        String resourceVersion = KubernetesHelper.getResourceVersion(old);
+                        KubernetesHelper.getOrCreateMetadata(entity).setResourceVersion(resourceVersion);
+                        Object answer = kubernetes.updateBuildConfig(id, entity, namespace);
+                        logGeneratedEntity("Updated BuildConfig: ", namespace, entity, answer);
+                    } catch (Exception e) {
+                        onApplyError("Failed to update BuildConfig from " + sourceName + ". " + e + ". " + entity, e);
+                    }
+                }
+            }
+        } else {
+            if (!isAllowCreate()) {
+                LOG.warn("Creation disabled so not creating BuildConfig from " + sourceName + " namespace " + namespace + " name " + getName(entity));
+            } else {
+                doCreateBuildConfig(entity, namespace, sourceName);
+            }
+        }
+    }
+
+    public void doCreateBuildConfig(BuildConfig entity, String namespace ,String sourceName) {
+        try {
+            kubernetes.createBuildConfig(entity, namespace);
+        } catch (Exception e) {
+            onApplyError("Failed to create BuildConfig from " + sourceName + ". " + e, e);
+        }
+    }
+
+    public void applyDeploymentConfig(DeploymentConfig entity, String sourceName) {
+        try {
+            kubernetes.createDeploymentConfig(entity, getNamespace());
+        } catch (Exception e) {
+            onApplyError("Failed to create DeploymentConfig from " + sourceName + ". " + e, e);
+        }
+    }
+
+    public void applyImageStream(ImageStream entity, String sourceName) {
+        try {
+            kubernetes.createImageStream(entity, getNamespace());
+        } catch (Exception e) {
+            onApplyError("Failed to create BuildConfig from " + sourceName + ". " + e, e);
+        }
+    }
+
+    public void applyList(KubernetesList list, String sourceName) throws Exception {
+        List<HasMetadata> entities = list.getItems();
+        if (entities != null) {
+            for (Object entity : entities) {
+                applyEntity(entity, sourceName);
+            }
+        }
+    }
+
+    public void applyService(Service service, String sourceName) throws Exception {
+        String namespace = getNamespace();
+        String id = getName(service);
+        Objects.notNull(id, "No name for " + service + " " + sourceName);
+        if (isIgnoreServiceMode()) {
+            LOG.debug("Ignoring Service: " + namespace + ":" + id);
+            return;
+        }
+        if (serviceMap == null) {
+            serviceMap = getServiceMap(kubernetes, namespace);
+        }
+        Service old = serviceMap.get(id);
+        if (isRunning(old)) {
+            if (UserConfigurationCompare.configEqual(service, old)) {
+                LOG.info("Service hasn't changed so not doing anything");
+            } else {
+                if (isRecreateMode()) {
+                    kubernetes.deleteService(service, namespace);
+                    doCreateService(service, namespace, sourceName);
+                } else {
+                    LOG.info("Updating a service from " + sourceName);
+                    try {
+                        Object answer = kubernetes.updateService(id, service, namespace);
+                        logGeneratedEntity("Updated service: ", namespace, service, answer);
+                    } catch (Exception e) {
+                        onApplyError("Failed to update controller from " + sourceName + ". " + e + ". " + service, e);
+                    }
+                }
+            }
+        } else {
+            if (!isAllowCreate()) {
+                LOG.warn("Creation disabled so not creating a service from " + sourceName + " namespace " + namespace + " name " + getName(service));
+            } else {
+                doCreateService(service, namespace, sourceName);
+            }
+        }
+    }
+
+    protected void doCreateService(Service service, String namespace, String sourceName) {
+        LOG.info("Creating a service from " + sourceName + " namespace " + namespace + " name " + getName(service));
+        try {
+            Object answer;
+            if (Strings.isNotBlank(namespace)) {
+                answer = kubernetes.createService(service, namespace);
+            } else {
+                answer = kubernetes.createService(service);
+            }
+            logGeneratedEntity("Created service: ", namespace, service, answer);
+        } catch (Exception e) {
+            onApplyError("Failed to create service from " + sourceName + ". " + e + ". " + service, e);
+        }
+    }
+
+    public void applyNamespace(Namespace entity) {
+        String namespace = getOrCreateMetadata(entity).getName();
+        LOG.info("Creating a namespace " + namespace);
+        try {
+            Object answer = kubernetes.createNamespace(entity);
+            logGeneratedEntity("Created namespace: ", namespace, entity, answer);
+        } catch (Exception e) {
+            onApplyError("Failed to create namespace. " + e + ". " + entity, e);
+        }
+    }
+
+    public void applyReplicationController(ReplicationController replicationController, String sourceName) throws Exception {
+        String namespace = getNamespace();
+        String id = getName(replicationController);
+        Objects.notNull(id, "No name for " + replicationController + " " + sourceName);
+        if (isServicesOnlyMode()) {
+            LOG.debug("Only processing Services right now so ignoring ReplicationController: " + namespace + ":" + id);
+            return;
+        }
+        if (replicationControllerMap == null) {
+            replicationControllerMap = getReplicationControllerMap(kubernetes, namespace);
+        }
+        ReplicationController old = replicationControllerMap.get(id);
+        if (isRunning(old)) {
+            if (UserConfigurationCompare.configEqual(replicationController, old)) {
+                LOG.info("ReplicationController hasn't changed so not doing anything");
+            } else {
+                if (isRecreateMode()) {
+                    kubernetes.deleteReplicationControllerAndPods(replicationController, namespace);
+                    doCreateReplicationController(replicationController, namespace, sourceName);
+                } else {
+                    LOG.info("Updating replicationController from " + sourceName + " namespace " + namespace + " name " + getName(replicationController));
+                    try {
+                        Object answer = kubernetes.updateReplicationController(id, replicationController);
+                        logGeneratedEntity("Updated replicationController: ", namespace, replicationController, answer);
+                    } catch (Exception e) {
+                        onApplyError("Failed to update replicationController from " + sourceName + ". " + e + ". " + replicationController, e);
+                    }
+                }
+            }
+        } else {
+            if (!isAllowCreate()) {
+                LOG.warn("Creation disabled so not creating a replicationController from " + sourceName + " namespace " + namespace + " name " + getName(replicationController));
+            } else {
+                doCreateReplicationController(replicationController, namespace, sourceName);
+            }
+        }
+    }
+
+    protected void doCreateReplicationController(ReplicationController replicationController, String namespace, String sourceName) {
+        LOG.info("Creating a replicationController from " + sourceName + " namespace " + namespace + " name " + getName(replicationController));
+        try {
+            // lets check that if secrets are required they exist
+            ReplicationControllerSpec spec = replicationController.getSpec();
+            if (spec != null) {
+                PodTemplateSpec template = spec.getTemplate();
+                if (template != null) {
+                    PodSpec podSpec = template.getSpec();
+                    validatePodSpec(podSpec, namespace);
+                }
+            }
+            Object answer;
+            if (Strings.isNotBlank(namespace)) {
+                answer = kubernetes.createReplicationController(replicationController, namespace);
+            } else {
+                answer = kubernetes.createReplicationController(replicationController);
+            }
+            logGeneratedEntity("Created replicationController: ", namespace, replicationController, answer);
+        } catch (Exception e) {
+            onApplyError("Failed to create replicationController from " + sourceName + ". " + e + ". " + replicationController, e);
+        }
+    }
+
+    /**
+     * Lets verify that any dependencies are available; such as volumes or secrets
+     */
+    protected void validatePodSpec(PodSpec podSpec, String namespace) {
+        List<Volume> volumes = podSpec.getVolumes();
+        if (volumes != null) {
+            for (Volume volume : volumes) {
+                SecretVolumeSource secret = volume.getSecret();
+                if (secret != null) {
+                    String secretName = secret.getSecretName();
+                    if (Strings.isNotBlank(secretName)) {
+                        KubernetesHelper.validateSecretExists(kubernetes, namespace, secretName);
+                    }
+                }
+            }
+        }
+    }
+
+    public void applyPod(Pod pod, String sourceName) throws Exception {
+        String namespace = getNamespace();
+        String id = getName(pod);
+        Objects.notNull(id, "No name for " + pod + " " + sourceName);
+        if (isServicesOnlyMode()) {
+            LOG.debug("Only processing Services right now so ignoring Pod: " + namespace + ":" + id);
+            return;
+        }
+        if (podMap == null) {
+            podMap = getPodMap(kubernetes, namespace);
+        }
+        Pod old = podMap.get(id);
+        if (isRunning(old)) {
+            if (UserConfigurationCompare.configEqual(pod, old)) {
+                LOG.info("Pod hasn't changed so not doing anything");
+            } else {
+                if (isRecreateMode()) {
+                    kubernetes.deletePod(pod, namespace);
+                    doCreatePod(pod, namespace, sourceName);
+                } else {
+                    LOG.info("Updating a pod from " + sourceName + " namespace " + namespace + " name " + getName(pod));
+                    try {
+                        Object answer = kubernetes.updatePod(id, pod);
+                        LOG.info("Updated pod result: " + answer);
+                    } catch (Exception e) {
+                        onApplyError("Failed to update pod from " + sourceName + ". " + e + ". " + pod, e);
+                    }
+                }
+            }
+        } else {
+            if (!isAllowCreate()) {
+                LOG.warn("Creation disabled so not creating a pod from " + sourceName + " namespace " + namespace + " name " + getName(pod));
+            } else {
+                doCreatePod(pod, namespace, sourceName);
+            }
+        }
+    }
+
+    protected void doCreatePod(Pod pod, String namespace, String sourceName) {
+        LOG.info("Creating a pod from " + sourceName + " namespace " + namespace + " name " + getName(pod));
+        try {
+            PodSpec podSpec = pod.getSpec();
+            if (podSpec != null) {
+                validatePodSpec(podSpec, namespace);
+            }
+            Object answer;
+            if (Strings.isNotBlank(namespace)) {
+                answer = kubernetes.createPod(pod, namespace);
+            } else {
+                answer = kubernetes.createPod(pod);
+            }
+            LOG.info("Created pod result: " + answer);
+        } catch (Exception e) {
+            onApplyError("Failed to create pod from " + sourceName + ". " + e + ". " + pod, e);
+        }
+    }
+
+    public String getNamespace() {
+        return kubernetes.getNamespace();
+    }
+
+    public void setNamespace(String namespace) {
+        kubernetes.setNamespace(namespace);
+    }
+
+    public boolean isThrowExceptionOnError() {
+        return throwExceptionOnError;
+    }
+
+    public void setThrowExceptionOnError(boolean throwExceptionOnError) {
+        this.throwExceptionOnError = throwExceptionOnError;
+    }
+
+    public boolean isProcessTemplatesLocally() {
+        return processTemplatesLocally;
+    }
+
+    public void setProcessTemplatesLocally(boolean processTemplatesLocally) {
+        this.processTemplatesLocally = processTemplatesLocally;
+    }
+
+    public File getLogJsonDir() {
+        return logJsonDir;
+    }
+
+    /**
+     * Lets you configure the directory where JSON logging files should go
+     */
+    public void setLogJsonDir(File logJsonDir) {
+        this.logJsonDir = logJsonDir;
+    }
+
+    public File getBasedir() {
+        return basedir;
+    }
+
+    public void setBasedir(File basedir) {
+        this.basedir = basedir;
+    }
+
+    protected boolean isRunning(HasMetadata entity) {
+        return entity != null;
+    }
+
+
+    /**
+     * Logs an error applying some JSON to Kubernetes and optionally throws an exception
+     */
+    protected void onApplyError(String message, Exception e) {
+        LOG.error(message, e);
+        if (throwExceptionOnError) {
+            throw new RuntimeException(message, e);
+        }
+    }
+
+    /**
+     * Returns true if this controller allows new resources to be created in the given namespace
+     */
+    public boolean isAllowCreate() {
+        return allowCreate;
+    }
+
+    public void setAllowCreate(boolean allowCreate) {
+        this.allowCreate = allowCreate;
+    }
+
+    /**
+     * If enabled then updates are performed by deleting the resource first then creating it
+     */
+    public boolean isRecreateMode() {
+        return recreateMode;
+    }
+
+    public void setRecreateMode(boolean recreateMode) {
+        this.recreateMode = recreateMode;
+    }
+
+    public void setServicesOnlyMode(boolean servicesOnlyMode) {
+        this.servicesOnlyMode = servicesOnlyMode;
+    }
+
+    /**
+     * If enabled then only services are created/updated to allow services to be created/updated across
+     * a number of apps before any pods/replication controllers are updated
+     */
+    public boolean isServicesOnlyMode() {
+        return servicesOnlyMode;
+    }
+
+    /**
+     * If enabled then all services are ignored to avoid them being recreated. This is useful if you want to
+     * recreate ReplicationControllers and Pods but leave Services as they are to avoid the portalIP addresses
+     * changing
+     */
+    public boolean isIgnoreServiceMode() {
+        return ignoreServiceMode;
+    }
+
+    public void setIgnoreServiceMode(boolean ignoreServiceMode) {
+        this.ignoreServiceMode = ignoreServiceMode;
+    }
+
+    public boolean isIgnoreRunningOAuthClients() {
+        return ignoreRunningOAuthClients;
+    }
+
+    public void setIgnoreRunningOAuthClients(boolean ignoreRunningOAuthClients) {
+        this.ignoreRunningOAuthClients = ignoreRunningOAuthClients;
+    }
+}