CAMEL-11156 - Camel-Kubernetes: Add support for Deployment resources
Project: http://git-wip-us.apache.org/repos/asf/camel/repo Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/e6c57eb7 Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/e6c57eb7 Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/e6c57eb7 Branch: refs/heads/master Commit: e6c57eb74398d267675963b653029b7fff64d5cf Parents: ae8fc55 Author: Andrea Cosentino <anco...@gmail.com> Authored: Tue Jul 25 15:32:11 2017 +0200 Committer: Andrea Cosentino <anco...@gmail.com> Committed: Tue Jul 25 15:36:27 2017 +0200 ---------------------------------------------------------------------- .../kubernetes/KubernetesConstants.java | 3 + .../kubernetes/KubernetesOperations.java | 7 + .../consumer/common/DeploymentEvent.java | 47 ++++++ .../KubernetesDeploymentsComponent.java | 28 ++++ .../KubernetesDeploymentsConsumer.java | 143 ++++++++++++++++ .../KubernetesDeploymentsEndpoint.java | 52 ++++++ .../KubernetesDeploymentsProducer.java | 165 +++++++++++++++++++ .../camel/component/kubernetes-deployments | 18 ++ .../KubernetesDeploymentsProducerTest.java | 140 ++++++++++++++++ ...esDeploymentsComponentAutoConfiguration.java | 130 +++++++++++++++ ...rnetesDeploymentsComponentConfiguration.java | 50 ++++++ .../main/resources/META-INF/spring.factories | 4 +- 12 files changed, 786 insertions(+), 1 deletion(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/camel/blob/e6c57eb7/components/camel-kubernetes/src/main/java/org/apache/camel/component/kubernetes/KubernetesConstants.java ---------------------------------------------------------------------- diff --git a/components/camel-kubernetes/src/main/java/org/apache/camel/component/kubernetes/KubernetesConstants.java b/components/camel-kubernetes/src/main/java/org/apache/camel/component/kubernetes/KubernetesConstants.java index a56b42f..4814076 100644 --- a/components/camel-kubernetes/src/main/java/org/apache/camel/component/kubernetes/KubernetesConstants.java +++ b/components/camel-kubernetes/src/main/java/org/apache/camel/component/kubernetes/KubernetesConstants.java @@ -47,6 +47,9 @@ public interface KubernetesConstants { String KUBERNETES_SERVICE_ACCOUNT = "CamelKubernetesServiceAccount"; String KUBERNETES_NODES_LABELS = "CamelKubernetesNodesLabels"; String KUBERNETES_NODE_NAME = "CamelKubernetesNodeName"; + String KUBERNETES_DEPLOYMENTS_LABELS = "CamelKubernetesDeploymentsLabels"; + String KUBERNETES_DEPLOYMENT_NAME = "CamelKubernetesDeploymentName"; + String KUBERNETES_DEPLOYMENT_SPEC = "CamelKubernetesDeploymentSpec"; String KUBERNETES_CONFIGMAPS_LABELS = "CamelKubernetesConfigMapsLabels"; String KUBERNETES_CONFIGMAP_NAME = "CamelKubernetesConfigMapName"; String KUBERNETES_CONFIGMAP_DATA = "CamelKubernetesConfigData"; http://git-wip-us.apache.org/repos/asf/camel/blob/e6c57eb7/components/camel-kubernetes/src/main/java/org/apache/camel/component/kubernetes/KubernetesOperations.java ---------------------------------------------------------------------- diff --git a/components/camel-kubernetes/src/main/java/org/apache/camel/component/kubernetes/KubernetesOperations.java b/components/camel-kubernetes/src/main/java/org/apache/camel/component/kubernetes/KubernetesOperations.java index 6f5bb38..6ea4ed6 100644 --- a/components/camel-kubernetes/src/main/java/org/apache/camel/component/kubernetes/KubernetesOperations.java +++ b/components/camel-kubernetes/src/main/java/org/apache/camel/component/kubernetes/KubernetesOperations.java @@ -85,6 +85,13 @@ public interface KubernetesOperations { String LIST_NODES_BY_LABELS_OPERATION = "listNodesByLabels"; String GET_NODE_OPERATION = "getNode"; + // Deployments + String LIST_DEPLOYMENTS = "listDeployments"; + String LIST_DEPLOYMENTS_BY_LABELS_OPERATION = "listDeploymentsByLabels"; + String GET_DEPLOYMENT = "getDeployment"; + String DELETE_DEPLOYMENT = "deleteDeployment"; + String CREATE_DEPLOYMENT = "createDeployment"; + // Config Maps String LIST_CONFIGMAPS = "listConfigMaps"; String LIST_CONFIGMAPS_BY_LABELS_OPERATION = "listConfigMapsByLabels"; http://git-wip-us.apache.org/repos/asf/camel/blob/e6c57eb7/components/camel-kubernetes/src/main/java/org/apache/camel/component/kubernetes/consumer/common/DeploymentEvent.java ---------------------------------------------------------------------- diff --git a/components/camel-kubernetes/src/main/java/org/apache/camel/component/kubernetes/consumer/common/DeploymentEvent.java b/components/camel-kubernetes/src/main/java/org/apache/camel/component/kubernetes/consumer/common/DeploymentEvent.java new file mode 100644 index 0000000..56e85d1 --- /dev/null +++ b/components/camel-kubernetes/src/main/java/org/apache/camel/component/kubernetes/consumer/common/DeploymentEvent.java @@ -0,0 +1,47 @@ +/** + * 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.camel.component.kubernetes.consumer.common; + +import io.fabric8.kubernetes.api.model.extensions.Deployment; +import io.fabric8.kubernetes.client.Watcher.Action; + +public class DeploymentEvent { + private io.fabric8.kubernetes.client.Watcher.Action action; + + private Deployment deployment; + + public DeploymentEvent(Action action, Deployment deployment) { + this.action = action; + this.deployment = deployment; + } + + public io.fabric8.kubernetes.client.Watcher.Action getAction() { + return action; + } + + public void setAction(io.fabric8.kubernetes.client.Watcher.Action action) { + this.action = action; + } + + public Deployment getDeployment() { + return deployment; + } + + public void setNode(Deployment deployment) { + this.deployment = deployment; + } +} http://git-wip-us.apache.org/repos/asf/camel/blob/e6c57eb7/components/camel-kubernetes/src/main/java/org/apache/camel/component/kubernetes/deployments/KubernetesDeploymentsComponent.java ---------------------------------------------------------------------- diff --git a/components/camel-kubernetes/src/main/java/org/apache/camel/component/kubernetes/deployments/KubernetesDeploymentsComponent.java b/components/camel-kubernetes/src/main/java/org/apache/camel/component/kubernetes/deployments/KubernetesDeploymentsComponent.java new file mode 100644 index 0000000..04e10e4 --- /dev/null +++ b/components/camel-kubernetes/src/main/java/org/apache/camel/component/kubernetes/deployments/KubernetesDeploymentsComponent.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 org.apache.camel.component.kubernetes.deployments; + +import org.apache.camel.component.kubernetes.AbstractKubernetesComponent; +import org.apache.camel.component.kubernetes.KubernetesConfiguration; + +public class KubernetesDeploymentsComponent extends AbstractKubernetesComponent { + + protected KubernetesDeploymentsEndpoint doCreateEndpoint(String uri, String remaining, KubernetesConfiguration config) throws Exception { + KubernetesDeploymentsEndpoint endpoint = new KubernetesDeploymentsEndpoint(uri, this, config); + return endpoint; + } +} http://git-wip-us.apache.org/repos/asf/camel/blob/e6c57eb7/components/camel-kubernetes/src/main/java/org/apache/camel/component/kubernetes/deployments/KubernetesDeploymentsConsumer.java ---------------------------------------------------------------------- diff --git a/components/camel-kubernetes/src/main/java/org/apache/camel/component/kubernetes/deployments/KubernetesDeploymentsConsumer.java b/components/camel-kubernetes/src/main/java/org/apache/camel/component/kubernetes/deployments/KubernetesDeploymentsConsumer.java new file mode 100644 index 0000000..14c1d6c --- /dev/null +++ b/components/camel-kubernetes/src/main/java/org/apache/camel/component/kubernetes/deployments/KubernetesDeploymentsConsumer.java @@ -0,0 +1,143 @@ +/** + * 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.camel.component.kubernetes.deployments; + +import java.util.concurrent.ExecutorService; + +import io.fabric8.kubernetes.api.model.DoneableNode; +import io.fabric8.kubernetes.api.model.Node; +import io.fabric8.kubernetes.api.model.NodeList; +import io.fabric8.kubernetes.api.model.extensions.Deployment; +import io.fabric8.kubernetes.api.model.extensions.DeploymentList; +import io.fabric8.kubernetes.api.model.extensions.DoneableDeployment; +import io.fabric8.kubernetes.client.KubernetesClientException; +import io.fabric8.kubernetes.client.Watch; +import io.fabric8.kubernetes.client.Watcher; +import io.fabric8.kubernetes.client.dsl.NonNamespaceOperation; +import io.fabric8.kubernetes.client.dsl.Resource; +import io.fabric8.kubernetes.client.dsl.ScalableResource; + +import org.apache.camel.Exchange; +import org.apache.camel.Processor; +import org.apache.camel.component.kubernetes.AbstractKubernetesEndpoint; +import org.apache.camel.component.kubernetes.KubernetesConstants; +import org.apache.camel.component.kubernetes.KubernetesEndpoint; +import org.apache.camel.component.kubernetes.consumer.common.DeploymentEvent; +import org.apache.camel.component.kubernetes.consumer.common.NodeEvent; +import org.apache.camel.impl.DefaultConsumer; +import org.apache.camel.util.ObjectHelper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class KubernetesDeploymentsConsumer extends DefaultConsumer { + + private static final Logger LOG = LoggerFactory.getLogger(KubernetesDeploymentsConsumer.class); + + private final Processor processor; + private ExecutorService executor; + private DeploymentsConsumerTask deploymentsWatcher; + + public KubernetesDeploymentsConsumer(AbstractKubernetesEndpoint endpoint, Processor processor) { + super(endpoint, processor); + this.processor = processor; + } + + @Override + public AbstractKubernetesEndpoint getEndpoint() { + return (AbstractKubernetesEndpoint) super.getEndpoint(); + } + + @Override + protected void doStart() throws Exception { + super.doStart(); + executor = getEndpoint().createExecutor(); + + deploymentsWatcher = new DeploymentsConsumerTask(); + executor.submit(deploymentsWatcher); + } + + @Override + protected void doStop() throws Exception { + super.doStop(); + + LOG.debug("Stopping Kubernetes Deployments Consumer"); + if (executor != null) { + if (getEndpoint() != null && getEndpoint().getCamelContext() != null) { + if (deploymentsWatcher != null) { + deploymentsWatcher.getWatch().close(); + } + getEndpoint().getCamelContext().getExecutorServiceManager().shutdownNow(executor); + } else { + if (deploymentsWatcher != null) { + deploymentsWatcher.getWatch().close(); + } + executor.shutdownNow(); + } + } + executor = null; + } + + class DeploymentsConsumerTask implements Runnable { + + private Watch watch; + + @Override + public void run() { + NonNamespaceOperation<Deployment, DeploymentList, DoneableDeployment, ScalableResource<Deployment, DoneableDeployment>> w = getEndpoint().getKubernetesClient().extensions().deployments(); + if (ObjectHelper.isNotEmpty(getEndpoint().getKubernetesConfiguration().getLabelKey()) + && ObjectHelper.isNotEmpty(getEndpoint().getKubernetesConfiguration().getLabelValue())) { + w.withLabel(getEndpoint().getKubernetesConfiguration().getLabelKey(), getEndpoint().getKubernetesConfiguration().getLabelValue()); + } + if (ObjectHelper.isNotEmpty(getEndpoint().getKubernetesConfiguration().getResourceName())) { + w.withName(getEndpoint().getKubernetesConfiguration().getResourceName()); + } + watch = w.watch(new Watcher<Deployment>() { + + @Override + public void eventReceived(io.fabric8.kubernetes.client.Watcher.Action action, + Deployment resource) { + DeploymentEvent de = new DeploymentEvent(action, resource); + Exchange exchange = getEndpoint().createExchange(); + exchange.getIn().setBody(de.getDeployment()); + exchange.getIn().setHeader(KubernetesConstants.KUBERNETES_EVENT_ACTION, de.getAction()); + exchange.getIn().setHeader(KubernetesConstants.KUBERNETES_EVENT_TIMESTAMP, System.currentTimeMillis()); + try { + processor.process(exchange); + } catch (Exception e) { + getExceptionHandler().handleException("Error during processing", exchange, e); + } + } + + @Override + public void onClose(KubernetesClientException cause) { + if (cause != null) { + LOG.error(cause.getMessage(), cause); + } + + } + }); + } + + public Watch getWatch() { + return watch; + } + + public void setWatch(Watch watch) { + this.watch = watch; + } + } +} http://git-wip-us.apache.org/repos/asf/camel/blob/e6c57eb7/components/camel-kubernetes/src/main/java/org/apache/camel/component/kubernetes/deployments/KubernetesDeploymentsEndpoint.java ---------------------------------------------------------------------- diff --git a/components/camel-kubernetes/src/main/java/org/apache/camel/component/kubernetes/deployments/KubernetesDeploymentsEndpoint.java b/components/camel-kubernetes/src/main/java/org/apache/camel/component/kubernetes/deployments/KubernetesDeploymentsEndpoint.java new file mode 100644 index 0000000..21cceb9 --- /dev/null +++ b/components/camel-kubernetes/src/main/java/org/apache/camel/component/kubernetes/deployments/KubernetesDeploymentsEndpoint.java @@ -0,0 +1,52 @@ +/** + * 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.camel.component.kubernetes.deployments; + +import org.apache.camel.Consumer; +import org.apache.camel.Processor; +import org.apache.camel.Producer; +import org.apache.camel.component.kubernetes.AbstractKubernetesEndpoint; +import org.apache.camel.component.kubernetes.KubernetesConfiguration; +import org.apache.camel.spi.UriEndpoint; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * The Kubernetes Nodes component provides a producer to execute kubernetes node operations + * and a consumer to consume node events. + */ +@UriEndpoint(firstVersion = "2.20.0", scheme = "kubernetes-deployments", title = "Kubernetes Deployments", + syntax = "kubernetes-deployments:masterUrl", consumerClass = KubernetesDeploymentsConsumer.class, label = "container,cloud,paas") +public class KubernetesDeploymentsEndpoint extends AbstractKubernetesEndpoint { + + private static final Logger LOG = LoggerFactory.getLogger(KubernetesDeploymentsEndpoint.class); + + public KubernetesDeploymentsEndpoint(String uri, KubernetesDeploymentsComponent component, KubernetesConfiguration config) { + super(uri, component, config); + } + + @Override + public Producer createProducer() throws Exception { + return new KubernetesDeploymentsProducer(this); + } + + @Override + public Consumer createConsumer(Processor processor) throws Exception { + return new KubernetesDeploymentsConsumer(this, processor); + } + +} http://git-wip-us.apache.org/repos/asf/camel/blob/e6c57eb7/components/camel-kubernetes/src/main/java/org/apache/camel/component/kubernetes/deployments/KubernetesDeploymentsProducer.java ---------------------------------------------------------------------- diff --git a/components/camel-kubernetes/src/main/java/org/apache/camel/component/kubernetes/deployments/KubernetesDeploymentsProducer.java b/components/camel-kubernetes/src/main/java/org/apache/camel/component/kubernetes/deployments/KubernetesDeploymentsProducer.java new file mode 100644 index 0000000..29015c5 --- /dev/null +++ b/components/camel-kubernetes/src/main/java/org/apache/camel/component/kubernetes/deployments/KubernetesDeploymentsProducer.java @@ -0,0 +1,165 @@ +/** + * 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.camel.component.kubernetes.deployments; + +import java.util.Map; + +import io.fabric8.kubernetes.api.model.extensions.Deployment; +import io.fabric8.kubernetes.api.model.extensions.DeploymentBuilder; +import io.fabric8.kubernetes.api.model.extensions.DeploymentList; +import io.fabric8.kubernetes.api.model.extensions.DeploymentSpec; +import io.fabric8.kubernetes.api.model.extensions.DoneableDeployment; +import io.fabric8.kubernetes.client.dsl.NonNamespaceOperation; +import io.fabric8.kubernetes.client.dsl.ScalableResource; + +import org.apache.camel.Exchange; +import org.apache.camel.component.kubernetes.AbstractKubernetesEndpoint; +import org.apache.camel.component.kubernetes.KubernetesConstants; +import org.apache.camel.component.kubernetes.KubernetesOperations; +import org.apache.camel.impl.DefaultProducer; +import org.apache.camel.util.MessageHelper; +import org.apache.camel.util.ObjectHelper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class KubernetesDeploymentsProducer extends DefaultProducer { + + private static final Logger LOG = LoggerFactory.getLogger(KubernetesDeploymentsProducer.class); + + public KubernetesDeploymentsProducer(AbstractKubernetesEndpoint endpoint) { + super(endpoint); + } + + @Override + public AbstractKubernetesEndpoint getEndpoint() { + return (AbstractKubernetesEndpoint) super.getEndpoint(); + } + + @Override + public void process(Exchange exchange) throws Exception { + String operation; + + if (ObjectHelper.isEmpty(getEndpoint().getKubernetesConfiguration().getOperation())) { + operation = exchange.getIn().getHeader(KubernetesConstants.KUBERNETES_OPERATION, String.class); + } else { + operation = getEndpoint().getKubernetesConfiguration().getOperation(); + } + + switch (operation) { + + case KubernetesOperations.LIST_DEPLOYMENTS: + doList(exchange, operation); + break; + + case KubernetesOperations.LIST_DEPLOYMENTS_BY_LABELS_OPERATION: + doListDeploymentsByLabels(exchange, operation); + break; + + case KubernetesOperations.GET_DEPLOYMENT: + doGetDeployment(exchange, operation); + break; + + case KubernetesOperations.DELETE_DEPLOYMENT: + doDeleteDeployment(exchange, operation); + break; + + case KubernetesOperations.CREATE_DEPLOYMENT: + doCreateDeployment(exchange, operation); + break; + + default: + throw new IllegalArgumentException("Unsupported operation " + operation); + } + } + + protected void doList(Exchange exchange, String operation) throws Exception { + DeploymentList deploymentsList = getEndpoint().getKubernetesClient().extensions().deployments().list(); + + MessageHelper.copyHeaders(exchange.getIn(), exchange.getOut(), true); + exchange.getOut().setBody(deploymentsList.getItems()); + } + + protected void doListDeploymentsByLabels(Exchange exchange, String operation) throws Exception { + DeploymentList deploymentList = null; + Map<String, String> labels = exchange.getIn().getHeader(KubernetesConstants.KUBERNETES_DEPLOYMENTS_LABELS, Map.class); + NonNamespaceOperation<Deployment, DeploymentList, DoneableDeployment, ScalableResource<Deployment, DoneableDeployment>> deployments = getEndpoint().getKubernetesClient() + .extensions().deployments(); + for (Map.Entry<String, String> entry : labels.entrySet()) { + deployments.withLabel(entry.getKey(), entry.getValue()); + } + deploymentList = deployments.list(); + + MessageHelper.copyHeaders(exchange.getIn(), exchange.getOut(), true); + exchange.getOut().setBody(deploymentList.getItems()); + } + + protected void doGetDeployment(Exchange exchange, String operation) throws Exception { + Deployment deployment = null; + String deploymentName = exchange.getIn().getHeader(KubernetesConstants.KUBERNETES_DEPLOYMENT_NAME, String.class); + if (ObjectHelper.isEmpty(deploymentName)) { + LOG.error("Get a specific Deployment require specify a Deployment name"); + throw new IllegalArgumentException("Get a specific Deployment require specify a Deployment name"); + } + deployment = getEndpoint().getKubernetesClient().extensions().deployments().withName(deploymentName).get(); + + MessageHelper.copyHeaders(exchange.getIn(), exchange.getOut(), true); + exchange.getOut().setBody(deployment); + } + + protected void doDeleteDeployment(Exchange exchange, String operation) { + String deploymentName = exchange.getIn().getHeader(KubernetesConstants.KUBERNETES_DEPLOYMENT_NAME, String.class); + String namespaceName = exchange.getIn().getHeader(KubernetesConstants.KUBERNETES_NAMESPACE_NAME, String.class); + if (ObjectHelper.isEmpty(deploymentName)) { + LOG.error("Delete a specific deployment require specify a deployment name"); + throw new IllegalArgumentException("Delete a specific deployment require specify a deployment name"); + } + if (ObjectHelper.isEmpty(namespaceName)) { + LOG.error("Delete a specific deployment require specify a namespace name"); + throw new IllegalArgumentException("Delete a specific deployment require specify a namespace name"); + } + + Boolean deployment = getEndpoint().getKubernetesClient().extensions().deployments().inNamespace(namespaceName).withName(deploymentName).delete(); + + MessageHelper.copyHeaders(exchange.getIn(), exchange.getOut(), true); + exchange.getOut().setBody(deployment); + } + + protected void doCreateDeployment(Exchange exchange, String operation) throws Exception { + Deployment deployment = null; + String deploymentName = exchange.getIn().getHeader(KubernetesConstants.KUBERNETES_DEPLOYMENT_NAME, String.class); + String namespaceName = exchange.getIn().getHeader(KubernetesConstants.KUBERNETES_NAMESPACE_NAME, String.class); + DeploymentSpec deSpec = exchange.getIn().getHeader(KubernetesConstants.KUBERNETES_DEPLOYMENT_SPEC, DeploymentSpec.class); + if (ObjectHelper.isEmpty(deploymentName)) { + LOG.error("Create a specific Deployment require specify a Deployment name"); + throw new IllegalArgumentException("Create a specific pod require specify a pod name"); + } + if (ObjectHelper.isEmpty(namespaceName)) { + LOG.error("Create a specific pod require specify a namespace name"); + throw new IllegalArgumentException("Create a specific pod require specify a namespace name"); + } + if (ObjectHelper.isEmpty(deSpec)) { + LOG.error("Create a specific Deployment require specify a Deployment spec bean"); + throw new IllegalArgumentException("Create a specific Deployment require specify a Deployment spec bean"); + } + Map<String, String> labels = exchange.getIn().getHeader(KubernetesConstants.KUBERNETES_DEPLOYMENTS_LABELS, Map.class); + Deployment deploymentCreating = new DeploymentBuilder().withNewMetadata().withName(deploymentName).withLabels(labels).endMetadata().withSpec(deSpec).build(); + deployment = getEndpoint().getKubernetesClient().extensions().deployments().inNamespace(namespaceName).create(deploymentCreating); + + MessageHelper.copyHeaders(exchange.getIn(), exchange.getOut(), true); + exchange.getOut().setBody(deployment); + } +} http://git-wip-us.apache.org/repos/asf/camel/blob/e6c57eb7/components/camel-kubernetes/src/main/resources/META-INF/services/org/apache/camel/component/kubernetes-deployments ---------------------------------------------------------------------- diff --git a/components/camel-kubernetes/src/main/resources/META-INF/services/org/apache/camel/component/kubernetes-deployments b/components/camel-kubernetes/src/main/resources/META-INF/services/org/apache/camel/component/kubernetes-deployments new file mode 100644 index 0000000..bcf5f73 --- /dev/null +++ b/components/camel-kubernetes/src/main/resources/META-INF/services/org/apache/camel/component/kubernetes-deployments @@ -0,0 +1,18 @@ +# +# 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. +# + +class=org.apache.camel.component.kubernetes.deployments.KubernetesDeploymentsComponent http://git-wip-us.apache.org/repos/asf/camel/blob/e6c57eb7/components/camel-kubernetes/src/test/java/org/apache/camel/component/kubernetes/producer/KubernetesDeploymentsProducerTest.java ---------------------------------------------------------------------- diff --git a/components/camel-kubernetes/src/test/java/org/apache/camel/component/kubernetes/producer/KubernetesDeploymentsProducerTest.java b/components/camel-kubernetes/src/test/java/org/apache/camel/component/kubernetes/producer/KubernetesDeploymentsProducerTest.java new file mode 100644 index 0000000..3b71c13 --- /dev/null +++ b/components/camel-kubernetes/src/test/java/org/apache/camel/component/kubernetes/producer/KubernetesDeploymentsProducerTest.java @@ -0,0 +1,140 @@ +/** + * 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.camel.component.kubernetes.producer; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import io.fabric8.kubernetes.api.model.Namespace; +import io.fabric8.kubernetes.api.model.NamespaceBuilder; +import io.fabric8.kubernetes.api.model.Secret; +import io.fabric8.kubernetes.api.model.SecretBuilder; +import io.fabric8.kubernetes.api.model.extensions.Deployment; +import io.fabric8.kubernetes.api.model.extensions.DeploymentBuilder; +import io.fabric8.kubernetes.api.model.extensions.DeploymentListBuilder; +import io.fabric8.kubernetes.client.server.mock.KubernetesServer; + +import org.apache.camel.Exchange; +import org.apache.camel.Processor; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.component.kubernetes.KubernetesConstants; +import org.apache.camel.component.kubernetes.KubernetesTestSupport; +import org.apache.camel.impl.JndiRegistry; +import org.junit.Rule; +import org.junit.Test; + +public class KubernetesDeploymentsProducerTest extends KubernetesTestSupport { + + @Rule + public KubernetesServer server = new KubernetesServer(); + + @Override + protected JndiRegistry createRegistry() throws Exception { + JndiRegistry registry = super.createRegistry(); + registry.bind("kubernetesClient", server.getClient()); + return registry; + } + + @Test + public void listTest() throws Exception { + server.expect().withPath("/apis/extensions/v1beta1/namespaces/test/deployments").andReturn(200, new DeploymentListBuilder().addNewItem().and().build()).once(); + List<Deployment> result = template.requestBody("direct:list", "", + List.class); + + assertEquals(1, result.size()); + } + + @Test + public void listByLabelsTest() throws Exception { + server.expect().withPath("/apis/extensions/v1beta1/namespaces/test/deployments?labelSelector=" + toUrlEncoded("key1=value1,key2=value2")) + .andReturn(200, new DeploymentListBuilder().addNewItem().and().addNewItem().and().addNewItem().and().build()).once(); + Exchange ex = template.request("direct:listByLabels", new Processor() { + + @Override + public void process(Exchange exchange) throws Exception { + Map<String, String> labels = new HashMap<String, String>(); + labels.put("key1", "value1"); + labels.put("key2", "value2"); + exchange.getIn() + .setHeader( + KubernetesConstants.KUBERNETES_DEPLOYMENTS_LABELS, + labels); + } + }); + + List<Deployment> result = ex.getOut().getBody(List.class); + + assertEquals(3, result.size()); + } + + @Test + public void createAndDeleteDeployment() throws Exception { + Deployment de1 = new DeploymentBuilder().withNewMetadata() + .withNamespace("test") + .withName("de1") + .withResourceVersion("1") + .withGeneration(2L) + .endMetadata() + .withNewSpec() + .withReplicas(0) + .endSpec() + .withNewStatus() + .withReplicas(1) + .withObservedGeneration(1L) + .endStatus() + .build(); + + server.expect().withPath("/apis/extensions/v1beta1/namespaces/test/deployments/de1").andReturn(200, de1).once(); + server.expect().withPath("/apis/extensions/v1beta1/namespaces/test/deployments/de1").andReturn(200, new DeploymentBuilder(de1) + .editStatus() + .withReplicas(0) + .withObservedGeneration(2L) + .endStatus() + .build()).times(5); + + Exchange ex = template.request("direct:deleteDeployment", new Processor() { + + @Override + public void process(Exchange exchange) throws Exception { + exchange.getIn().setHeader(KubernetesConstants.KUBERNETES_DEPLOYMENT_NAME, "de1"); + exchange.getIn().setHeader(KubernetesConstants.KUBERNETES_NAMESPACE_NAME, "test"); + } + }); + + boolean deDeleted = ex.getOut().getBody(Boolean.class); + + assertTrue(deDeleted); + } + + @Override + protected RouteBuilder createRouteBuilder() throws Exception { + return new RouteBuilder() { + @Override + public void configure() throws Exception { + from("direct:list") + .toF("kubernetes-deployments:///?kubernetesClient=#kubernetesClient&operation=listDeployments"); + from("direct:listByLabels") + .toF("kubernetes-deployments:///?kubernetesClient=#kubernetesClient&operation=listDeploymentsByLabels"); + from("direct:deleteDeployment") + .toF("kubernetes-deployments:///?kubernetesClient=#kubernetesClient&operation=deleteDeployment"); + from("direct:createDeployment") + .toF("kubernetes-deployments:///?kubernetesClient=#kubernetesClient&operation=createDeployment"); + } + }; + } +} http://git-wip-us.apache.org/repos/asf/camel/blob/e6c57eb7/platforms/spring-boot/components-starter/camel-kubernetes-starter/src/main/java/org/apache/camel/component/kubernetes/deployments/springboot/KubernetesDeploymentsComponentAutoConfiguration.java ---------------------------------------------------------------------- diff --git a/platforms/spring-boot/components-starter/camel-kubernetes-starter/src/main/java/org/apache/camel/component/kubernetes/deployments/springboot/KubernetesDeploymentsComponentAutoConfiguration.java b/platforms/spring-boot/components-starter/camel-kubernetes-starter/src/main/java/org/apache/camel/component/kubernetes/deployments/springboot/KubernetesDeploymentsComponentAutoConfiguration.java new file mode 100644 index 0000000..c5da065 --- /dev/null +++ b/platforms/spring-boot/components-starter/camel-kubernetes-starter/src/main/java/org/apache/camel/component/kubernetes/deployments/springboot/KubernetesDeploymentsComponentAutoConfiguration.java @@ -0,0 +1,130 @@ +/** + * 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.camel.component.kubernetes.deployments.springboot; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import javax.annotation.Generated; +import org.apache.camel.CamelContext; +import org.apache.camel.component.kubernetes.deployments.KubernetesDeploymentsComponent; +import org.apache.camel.spi.ComponentCustomizer; +import org.apache.camel.spi.HasId; +import org.apache.camel.spring.boot.CamelAutoConfiguration; +import org.apache.camel.spring.boot.ComponentConfigurationProperties; +import org.apache.camel.spring.boot.util.ConditionalOnCamelContextAndAutoConfigurationBeans; +import org.apache.camel.spring.boot.util.GroupCondition; +import org.apache.camel.spring.boot.util.HierarchicalPropertiesEvaluator; +import org.apache.camel.util.IntrospectionSupport; +import org.apache.camel.util.ObjectHelper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.AutoConfigureAfter; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Conditional; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Lazy; + +/** + * Generated by camel-package-maven-plugin - do not edit this file! + */ +@Generated("org.apache.camel.maven.packaging.SpringBootAutoConfigurationMojo") +@Configuration +@Conditional({ConditionalOnCamelContextAndAutoConfigurationBeans.class, + KubernetesDeploymentsComponentAutoConfiguration.GroupConditions.class}) +@AutoConfigureAfter(CamelAutoConfiguration.class) +@EnableConfigurationProperties({ComponentConfigurationProperties.class, + KubernetesDeploymentsComponentConfiguration.class}) +public class KubernetesDeploymentsComponentAutoConfiguration { + + private static final Logger LOGGER = LoggerFactory + .getLogger(KubernetesDeploymentsComponentAutoConfiguration.class); + @Autowired + private ApplicationContext applicationContext; + @Autowired + private CamelContext camelContext; + @Autowired + private KubernetesDeploymentsComponentConfiguration configuration; + @Autowired(required = false) + private List<ComponentCustomizer<KubernetesDeploymentsComponent>> customizers; + + static class GroupConditions extends GroupCondition { + public GroupConditions() { + super("camel.component", "camel.component.kubernetes-deployments"); + } + } + + @Lazy + @Bean(name = "kubernetes-deployments-component") + @ConditionalOnMissingBean(KubernetesDeploymentsComponent.class) + public KubernetesDeploymentsComponent configureKubernetesDeploymentsComponent() + throws Exception { + KubernetesDeploymentsComponent component = new KubernetesDeploymentsComponent(); + component.setCamelContext(camelContext); + Map<String, Object> parameters = new HashMap<>(); + IntrospectionSupport.getProperties(configuration, parameters, null, + false); + for (Map.Entry<String, Object> entry : parameters.entrySet()) { + Object value = entry.getValue(); + Class<?> paramClass = value.getClass(); + if (paramClass.getName().endsWith("NestedConfiguration")) { + Class nestedClass = null; + try { + nestedClass = (Class) paramClass.getDeclaredField( + "CAMEL_NESTED_CLASS").get(null); + HashMap<String, Object> nestedParameters = new HashMap<>(); + IntrospectionSupport.getProperties(value, nestedParameters, + null, false); + Object nestedProperty = nestedClass.newInstance(); + IntrospectionSupport.setProperties(camelContext, + camelContext.getTypeConverter(), nestedProperty, + nestedParameters); + entry.setValue(nestedProperty); + } catch (NoSuchFieldException e) { + } + } + } + IntrospectionSupport.setProperties(camelContext, + camelContext.getTypeConverter(), component, parameters); + if (ObjectHelper.isNotEmpty(customizers)) { + for (ComponentCustomizer<KubernetesDeploymentsComponent> customizer : customizers) { + boolean useCustomizer = (customizer instanceof HasId) + ? HierarchicalPropertiesEvaluator + .evaluate( + applicationContext.getEnvironment(), + "camel.component.customizer", + "camel.component.kubernetes-deployments.customizer", + ((HasId) customizer).getId()) + : HierarchicalPropertiesEvaluator + .evaluate(applicationContext.getEnvironment(), + "camel.component.customizer", + "camel.component.kubernetes-deployments.customizer"); + if (useCustomizer) { + LOGGER.debug("Configure component {}, with customizer {}", + component, customizer); + customizer.customize(component); + } + } + } + return component; + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/camel/blob/e6c57eb7/platforms/spring-boot/components-starter/camel-kubernetes-starter/src/main/java/org/apache/camel/component/kubernetes/deployments/springboot/KubernetesDeploymentsComponentConfiguration.java ---------------------------------------------------------------------- diff --git a/platforms/spring-boot/components-starter/camel-kubernetes-starter/src/main/java/org/apache/camel/component/kubernetes/deployments/springboot/KubernetesDeploymentsComponentConfiguration.java b/platforms/spring-boot/components-starter/camel-kubernetes-starter/src/main/java/org/apache/camel/component/kubernetes/deployments/springboot/KubernetesDeploymentsComponentConfiguration.java new file mode 100644 index 0000000..6d2893f --- /dev/null +++ b/platforms/spring-boot/components-starter/camel-kubernetes-starter/src/main/java/org/apache/camel/component/kubernetes/deployments/springboot/KubernetesDeploymentsComponentConfiguration.java @@ -0,0 +1,50 @@ +/** + * 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.camel.component.kubernetes.deployments.springboot; + +import javax.annotation.Generated; +import org.apache.camel.spring.boot.ComponentConfigurationPropertiesCommon; +import org.springframework.boot.context.properties.ConfigurationProperties; + +/** + * The Kubernetes Nodes component provides a producer to execute kubernetes node + * operations and a consumer to consume node events. + * + * Generated by camel-package-maven-plugin - do not edit this file! + */ +@Generated("org.apache.camel.maven.packaging.SpringBootAutoConfigurationMojo") +@ConfigurationProperties(prefix = "camel.component.kubernetes-deployments") +public class KubernetesDeploymentsComponentConfiguration + extends + ComponentConfigurationPropertiesCommon { + + /** + * Whether the component should resolve property placeholders on itself when + * starting. Only properties which are of String type can use property + * placeholders. + */ + private Boolean resolvePropertyPlaceholders = true; + + public Boolean getResolvePropertyPlaceholders() { + return resolvePropertyPlaceholders; + } + + public void setResolvePropertyPlaceholders( + Boolean resolvePropertyPlaceholders) { + this.resolvePropertyPlaceholders = resolvePropertyPlaceholders; + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/camel/blob/e6c57eb7/platforms/spring-boot/components-starter/camel-kubernetes-starter/src/main/resources/META-INF/spring.factories ---------------------------------------------------------------------- diff --git a/platforms/spring-boot/components-starter/camel-kubernetes-starter/src/main/resources/META-INF/spring.factories b/platforms/spring-boot/components-starter/camel-kubernetes-starter/src/main/resources/META-INF/spring.factories index 4323838..6c9d8d4 100644 --- a/platforms/spring-boot/components-starter/camel-kubernetes-starter/src/main/resources/META-INF/spring.factories +++ b/platforms/spring-boot/components-starter/camel-kubernetes-starter/src/main/resources/META-INF/spring.factories @@ -28,7 +28,9 @@ org.apache.camel.component.kubernetes.replication_controllers.springboot.Kuberne org.apache.camel.component.kubernetes.persistent_volumes.springboot.KubernetesPersistentVolumesComponentAutoConfiguration,\ org.apache.camel.component.kubernetes.build_configs.springboot.KubernetesBuildConfigsComponentAutoConfiguration,\ org.apache.camel.component.kubernetes.config_maps.springboot.KubernetesConfigMapsComponentAutoConfiguration,\ -org.apache.camel.component.kubernetes.persistent_volumes_claims.springboot.KubernetesPersistentVolumesClaimsComponentAutoConfiguration +org.apache.camel.component.kubernetes.persistent_volumes_claims.springboot.KubernetesPersistentVolumesClaimsComponentAutoConfiguration,\ +org.apache.camel.component.kubernetes.deployments.springboot.KubernetesDeploymentsComponentAutoConfiguration +