diff --git a/CHANGELOG.md b/CHANGELOG.md index b90ad29b922..f582c24789e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,6 +27,7 @@ * Fix #2311: Add Support for creating bootstrap project template * Fix #2287: Add support for V1 and V1Beta1 CustomResourceDefinition * Fix #2319: Create Config without using auto-configure functionality or setting env variables +* Fix #2284: Supports create and run a particular image in a pod operation using client _**Note**_: Some classes have been moved to other packages: - CustomResourceDefinition has been moved to `io.fabric8.kubernetes.api.model.apiextensions.v1` and `io.fabric8.kubernetes.api.model.apiextensions.v1beta1` diff --git a/doc/CHEATSHEET.md b/doc/CHEATSHEET.md index 724fa3b3a74..52a654ec6c3 100644 --- a/doc/CHEATSHEET.md +++ b/doc/CHEATSHEET.md @@ -40,6 +40,8 @@ This document contains common usages of different resources using Fabric8 Kubern * [Delete Options](#delete-options) * [Watch Options](#watch-options) * [Serializing to yaml](#serializing-to-yaml) + * [Running a Pod](#running-a-pod) + * [Running a Deployment](#running-a-deployment) * [OpenShift Client DSL Usage](#openshift-client-dsl-usage) * [Initializing OpenShift Client](#initializing-openshift-client) @@ -2288,6 +2290,60 @@ String myPodAsYaml = SerializationUtils.dumpAsYaml(myPod); String myPodAsYamlWithoutRuntimeState = SerializationUtils.dumpWithoutRuntimeStateAsYaml(myPod); ``` +#### Running a Pod +Kubernetes Client also provides mechanism similar to `kubectl run` in which you can spin a `Pod` just by specifying it's image and name: +- Running a `Pod` by just providing image and name: +``` +try (KubernetesClient client = new DefaultKubernetesClient()) { + client.run().pods().inNamespace("default") + .withName("hazelcast") + .withImage("hazelcast/hazelcast:3.12.9") + .done(); +} +``` +- You can also provide slighly complex configuration with `withGeneratorConfig` method in which you can specify labels, environment variables, ports etc: +``` +try (KubernetesClient client = new DefaultKubernetesClient()) { + client.run().pods().inNamespace("default") + .inNamespace("default") + .withRunConfig(new GeneratorRunConfig.Builder() + .withName("hazelcast") + .withImage("hazelcast/hazelcast:latest") + .withPort(5701) + .withLabels(Collections.singletonMap("rohan", "kumar")) + .withEnv(Collections.singletonMap("KUBERNETES_TEST", "fabric8")) + .build()) + .done(); +} +``` + +#### Running a Deployment +Similar to `client.run().pods()`, you can also do `client.run().deployments()` with a very similar syntax, the only difference is that `Deployment` would be generated instead of a `Pod`: +- Create a `Deployment` with just an image and name: +``` +try (KubernetesClient client = new DefaultKubernetesClient()) { + client.run().deployments().inNamespace("default") + .withName("nginx") + .withImage("nginx:latest") + .done(); +} +``` +- Create `Deployment` with `GeneratorRunConfig`: +``` +try (KubernetesClient client = new DefaultKubernetesClient()) { + client.run().deployments().inNamespace("default") + .withRunConfig(new GeneratorRunConfig.Builder() + .withName("nginx") + .withReplicas(1) + .withImage("nginx:latest") + .withPort(5701) + .withLabels(Collections.singletonMap("foo", "bar")) + .withEnv(Collections.singletonMap("KUBERNETES_TEST", "fabric8")) + .build()) + .done(); +} +``` + ### OpenShift Client DSL Usage Fabric8 Kubernetes Client also has an extension for OpenShift. It is pretty much the same as Kubernetes Client but has support for some additional OpenShift resources. diff --git a/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/AutoAdaptableKubernetesClient.java b/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/AutoAdaptableKubernetesClient.java index 109a478a945..7b9d87b7349 100644 --- a/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/AutoAdaptableKubernetesClient.java +++ b/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/AutoAdaptableKubernetesClient.java @@ -261,6 +261,11 @@ public MixedOperation Boolean isAdaptable(Class type) { return delegate.isAdaptable(type); diff --git a/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/DefaultKubernetesClient.java b/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/DefaultKubernetesClient.java index 01b1fcea899..ae45120413f 100644 --- a/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/DefaultKubernetesClient.java +++ b/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/DefaultKubernetesClient.java @@ -439,4 +439,9 @@ public LeaderElectorBuilder leaderElector() { public MixedOperation> leases() { return new LeaseOperationsImpl(httpClient, getConfiguration()); } + + @Override + public GeneratorRunDSL run() { + return adapt(GeneratorRunClient.class); + } } diff --git a/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/GeneratorRunClient.java b/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/GeneratorRunClient.java new file mode 100644 index 00000000000..73726f91cd1 --- /dev/null +++ b/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/GeneratorRunClient.java @@ -0,0 +1,39 @@ +/** + * Copyright (C) 2015 Red Hat, Inc. + * + * Licensed 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.client; + +import io.fabric8.kubernetes.client.dsl.GeneratorRunDSL; +import io.fabric8.kubernetes.client.utils.DeploymentGeneratorImpl; +import io.fabric8.kubernetes.client.utils.GeneratorRunConfig; +import io.fabric8.kubernetes.client.utils.PodGeneratorImpl; +import okhttp3.OkHttpClient; + +public class GeneratorRunClient extends BaseClient implements GeneratorRunDSL { + + public GeneratorRunClient(OkHttpClient httpClient, final Config config) { + super(httpClient, config); + } + + @Override + public PodGeneratorImpl pods() { + return new PodGeneratorImpl(httpClient, getConfiguration(), null, new GeneratorRunConfig.Builder()); + } + + @Override + public DeploymentGeneratorImpl deployments() { + return new DeploymentGeneratorImpl(httpClient, getConfiguration(), null, new GeneratorRunConfig.Builder()); + } +} diff --git a/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/GeneratorRunExtensionAdapter.java b/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/GeneratorRunExtensionAdapter.java new file mode 100644 index 00000000000..4a74736052d --- /dev/null +++ b/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/GeneratorRunExtensionAdapter.java @@ -0,0 +1,36 @@ +/** + * Copyright (C) 2015 Red Hat, Inc. + * + * Licensed 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.client; + +import okhttp3.OkHttpClient; + +public class GeneratorRunExtensionAdapter extends APIGroupExtensionAdapter { + + @Override + protected String getAPIGroupName() { + return "run"; + } + + @Override + public Class getExtensionType() { + return GeneratorRunClient.class; + } + + @Override + protected GeneratorRunClient newInstance(Client client) { + return new GeneratorRunClient(client.adapt(OkHttpClient.class), client.getConfiguration()); + } +} diff --git a/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/KubernetesClient.java b/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/KubernetesClient.java index d8a2e09203e..43ed4577fc3 100644 --- a/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/KubernetesClient.java +++ b/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/KubernetesClient.java @@ -514,4 +514,12 @@ public interface KubernetesClient extends Client { * @return V1APIGroupDSL DSL object for core v1 resources */ V1APIGroupDSL v1(); + + /** + * Utility method for quickly creating a Pod or Deployment based on + * some opinionated defaults. + * + * @return {@link GeneratorRunDSL} for run generator options + */ + GeneratorRunDSL run(); } diff --git a/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/GeneratorRunDSL.java b/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/GeneratorRunDSL.java new file mode 100644 index 00000000000..781e5032edb --- /dev/null +++ b/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/GeneratorRunDSL.java @@ -0,0 +1,36 @@ +/** + * Copyright (C) 2015 Red Hat, Inc. + * + * Licensed 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.client.dsl; + +import io.fabric8.kubernetes.client.Client; +import io.fabric8.kubernetes.client.utils.DeploymentGeneratorImpl; +import io.fabric8.kubernetes.client.utils.PodGeneratorImpl; + +public interface GeneratorRunDSL extends Client { + /** + * Run a Pod (core/v1) + * + * @return returns {@link PodGeneratorImpl} that allows you to run a pod based on few parameters(e.g. name, image etc) + */ + PodGeneratorImpl pods(); + + /** + * Run a Deployment (apps/v1) + * + * @return returns {@link DeploymentGeneratorImpl} that allows you to run a Deployment based on few parameters(e.g. name, image etc) + */ + DeploymentGeneratorImpl deployments(); +} diff --git a/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/osgi/ManagedKubernetesClient.java b/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/osgi/ManagedKubernetesClient.java index 558aa2cc71c..0d0cd0f0a84 100644 --- a/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/osgi/ManagedKubernetesClient.java +++ b/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/osgi/ManagedKubernetesClient.java @@ -102,6 +102,7 @@ import io.fabric8.kubernetes.client.dsl.Createable; import io.fabric8.kubernetes.client.dsl.ExtensionsAPIGroupDSL; import io.fabric8.kubernetes.client.dsl.FunctionCallable; +import io.fabric8.kubernetes.client.dsl.GeneratorRunDSL; import io.fabric8.kubernetes.client.dsl.KubernetesListMixedOperation; import io.fabric8.kubernetes.client.dsl.MetricAPIGroupDSL; import io.fabric8.kubernetes.client.dsl.MixedOperation; @@ -557,4 +558,9 @@ public NamespacedKubernetesClient inNamespace(String name) { public FunctionCallable withRequestConfig(RequestConfig requestConfig) { return delegate.withRequestConfig(requestConfig); } + + @Override + public GeneratorRunDSL run() { + return delegate.run(); + } } diff --git a/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/utils/DeploymentGeneratorImpl.java b/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/utils/DeploymentGeneratorImpl.java new file mode 100644 index 00000000000..6d9a07f8ceb --- /dev/null +++ b/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/utils/DeploymentGeneratorImpl.java @@ -0,0 +1,94 @@ +/** + * Copyright (C) 2015 Red Hat, Inc. + * + * Licensed 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.client.utils; + +import io.fabric8.kubernetes.api.model.apps.Deployment; +import io.fabric8.kubernetes.api.model.apps.DeploymentBuilder; +import io.fabric8.kubernetes.client.Config; +import io.fabric8.kubernetes.client.dsl.internal.apps.v1.DeploymentOperationsImpl; +import okhttp3.OkHttpClient; + +public class DeploymentGeneratorImpl { + private final OkHttpClient client; + private final Config config; + private final String namespace; + private final GeneratorRunConfig.Builder generatorRunConfigBuilder; + + public DeploymentGeneratorImpl(OkHttpClient client, Config config, String namespace, GeneratorRunConfig.Builder runConfig) { + this.client = client; + this.config = config; + this.namespace = namespace; + this.generatorRunConfigBuilder = runConfig; + } + + /** + * Specify namespace for the operation + * + * @param namespace namespace in which resource needs to be created + * @return {@link DeploymentGeneratorImpl} with injected namespace + */ + public DeploymentGeneratorImpl inNamespace(String namespace) { + return new DeploymentGeneratorImpl(this.client, this.config, namespace, this.generatorRunConfigBuilder); + } + + /** + * Specify image for the Deployment + * + * @param image image as a string + * @return {@link DeploymentGeneratorImpl} with image injected into {@link GeneratorRunConfig} + */ + public DeploymentGeneratorImpl withImage(String image) { + return new DeploymentGeneratorImpl(this.client, this.config, namespace, this.generatorRunConfigBuilder.withImage(image)); + } + + /** + * Specify name for the Deployment + * + * @param name name of the pod to be created + * @return {@link DeploymentGeneratorImpl} with name injected into {@link GeneratorRunConfig} + */ + public DeploymentGeneratorImpl withName(String name) { + return new DeploymentGeneratorImpl(this.client, this.config, namespace, this.generatorRunConfigBuilder.withName(name)); + } + + /** + * Specify complex configuration for Deployment creating using {@link GeneratorRunConfig} + * + * @param generatorRunConfig {@link GeneratorRunConfig} which allows to provide configuring environment variables, labels, resources, ports etc + * @return {@link DeploymentGeneratorImpl} with specified configuration + */ + public DeploymentGeneratorImpl withRunConfig(GeneratorRunConfig generatorRunConfig) { + return new DeploymentGeneratorImpl(this.client, this.config, namespace, new GeneratorRunConfig.Builder(generatorRunConfig)); + } + + /** + * Apply the {@link GeneratorRunConfig} onto the cluster and create Deployment + * + * @return Deployment which got created from the operation + */ + public Deployment done() { + DeploymentOperationsImpl podOperations = new DeploymentOperationsImpl(client, config, namespace); + return podOperations.create(convertRunConfigIntoDeployment()); + } + + protected Deployment convertRunConfigIntoDeployment() { + GeneratorRunConfig finalGeneratorConfig = generatorRunConfigBuilder.build(); + return new DeploymentBuilder() + .withMetadata(GeneratorRunConfigUtil.getObjectMetadataFromRunConfig(finalGeneratorConfig)) + .withSpec(GeneratorRunConfigUtil.getDeploymentSpecFromRunConfig(finalGeneratorConfig)) + .build(); + } +} diff --git a/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/utils/GeneratorRunConfig.java b/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/utils/GeneratorRunConfig.java new file mode 100644 index 00000000000..ed5863a3bac --- /dev/null +++ b/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/utils/GeneratorRunConfig.java @@ -0,0 +1,236 @@ +/** + * Copyright (C) 2015 Red Hat, Inc. + * + * Licensed 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.client.utils; + +import io.fabric8.kubernetes.api.model.Quantity; + +import java.util.Map; + +/** + * Configuration for client run + */ +public class GeneratorRunConfig { + /** + * Name of resource + */ + private String name; + /** + * Image to use + */ + private String image; + /** + * ImagePullPolicy to be used + */ + private String imagePullPolicy; + /** + * Pod restart policy + */ + private String restartPolicy; + /** + * Service Account name to be used + */ + private String serviceAccount; + /** + * labels to add + */ + private Map labels; + /** + * Environment variables to be add + */ + private Map env; + /** + * Resource limits + */ + private Map limits; + /** + * Resource requests + */ + private Map requests; + /** + * replicas + */ + private int replicas; + /** + * Port to use + */ + private int port; + + public String getName() { return name; } + + public String getImage() { + return image; + } + + public String getImagePullPolicy() { + return imagePullPolicy; + } + + public Map getLabels() { + return labels; + } + + public Map getEnv() { + return env; + } + + public Map getLimits() { + return limits; + } + + public Map getRequests() { + return requests; + } + + public int getReplicas() { + return replicas; + } + + public int getPort() { + return port; + } + + public String getRestartPolicy() { + return restartPolicy; + } + + public String getServiceAccount() { + return serviceAccount; + } + + public void setRestartPolicy(String restartPolicy) { + this.restartPolicy = restartPolicy; + } + + public void setName(String name) { + this.name = name; + } + + public void setServiceAccount(String serviceAccount) { + this.serviceAccount = serviceAccount; + } + public void setPort(int port) { + this.port = port; + } + + public void setReplicas(int replicas) { + this.replicas = replicas; + } + + public void setRequests(Map requests) { + this.requests = requests; + } + + public void setLimits(Map limits) { + this.limits = limits; + } + + public void setEnv(Map env) { + this.env = env; + } + + public void setLabels(Map labels) { + this.labels = labels; + } + + public void setImagePullPolicy(String imagePullPolicy) { + this.imagePullPolicy = imagePullPolicy; + } + + public void setImage(String image) { + this.image = image; + } + + public static class Builder { + private final GeneratorRunConfig generatorRunConfig; + + public Builder() { + this.generatorRunConfig = new GeneratorRunConfig(); + } + + public Builder(GeneratorRunConfig generatorRunConfig) { + this.generatorRunConfig = new GeneratorRunConfig(); + this.generatorRunConfig.name = generatorRunConfig.name; + this.generatorRunConfig.image = generatorRunConfig.image; + this.generatorRunConfig.imagePullPolicy = generatorRunConfig.imagePullPolicy; + this.generatorRunConfig.restartPolicy = generatorRunConfig.restartPolicy; + this.generatorRunConfig.labels = generatorRunConfig.labels; + this.generatorRunConfig.env = generatorRunConfig.env; + this.generatorRunConfig.limits = generatorRunConfig.limits; + this.generatorRunConfig.requests = generatorRunConfig.requests; + this.generatorRunConfig.replicas = generatorRunConfig.replicas; + this.generatorRunConfig.port = generatorRunConfig.port; + } + + public GeneratorRunConfig.Builder withName(String name) { + this.generatorRunConfig.name = name; + return this; + } + + public GeneratorRunConfig.Builder withImage(String image) { + this.generatorRunConfig.image = image; + return this; + } + + public GeneratorRunConfig.Builder withImagePullPolicy(String imagePullPolicy) { + this.generatorRunConfig.imagePullPolicy = imagePullPolicy; + return this; + } + + public GeneratorRunConfig.Builder withServiceAccount(String serviceAccount) { + this.generatorRunConfig.serviceAccount = serviceAccount; + return this; + } + + public GeneratorRunConfig.Builder withLabels(Map labels) { + this.generatorRunConfig.labels = labels; + return this; + } + + public GeneratorRunConfig.Builder withEnv(Map env) { + this.generatorRunConfig.env = env; + return this; + } + + public GeneratorRunConfig.Builder withLimits(Map limits) { + this.generatorRunConfig.limits = limits; + return this; + } + + public GeneratorRunConfig.Builder withRequests(Map requests) { + this.generatorRunConfig.requests = requests; + return this; + } + + public GeneratorRunConfig.Builder withReplicas(int replicas) { + this.generatorRunConfig.replicas = replicas; + return this; + } + + public GeneratorRunConfig.Builder withPort(int port) { + this.generatorRunConfig.port = port; + return this; + } + + public GeneratorRunConfig.Builder withRestartPolicy(String restartPolicy) { + this.generatorRunConfig.restartPolicy = restartPolicy; + return this; + } + + public GeneratorRunConfig build() { + return this.generatorRunConfig; + } + } +} diff --git a/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/utils/GeneratorRunConfigUtil.java b/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/utils/GeneratorRunConfigUtil.java new file mode 100644 index 00000000000..2f60e397d2f --- /dev/null +++ b/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/utils/GeneratorRunConfigUtil.java @@ -0,0 +1,143 @@ +/** + * Copyright (C) 2015 Red Hat, Inc. + * + * Licensed 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.client.utils; + +import io.fabric8.kubernetes.api.model.Container; +import io.fabric8.kubernetes.api.model.ContainerBuilder; +import io.fabric8.kubernetes.api.model.ContainerPortBuilder; +import io.fabric8.kubernetes.api.model.ObjectMeta; +import io.fabric8.kubernetes.api.model.ObjectMetaBuilder; +import io.fabric8.kubernetes.api.model.PodSpec; +import io.fabric8.kubernetes.api.model.PodSpecBuilder; +import io.fabric8.kubernetes.api.model.PodTemplateSpec; +import io.fabric8.kubernetes.api.model.PodTemplateSpecBuilder; +import io.fabric8.kubernetes.api.model.apps.DeploymentSpec; +import io.fabric8.kubernetes.api.model.apps.DeploymentSpecBuilder; + +import java.util.Collections; + +public class GeneratorRunConfigUtil { + private static final int DEFAULT_REPLICAS = 1; + private static final String DEFAULT_RESTART_POLICY = "Always"; + private GeneratorRunConfigUtil() { } + + public static ObjectMeta getObjectMetadataFromRunConfig(GeneratorRunConfig generatorRunConfig) { + ObjectMetaBuilder objectMetaBuilder = new ObjectMetaBuilder(); + if (generatorRunConfig.getName() != null) { + objectMetaBuilder.withName(generatorRunConfig.getName()); + objectMetaBuilder.addToLabels("run", generatorRunConfig.getName()); + } + + if (generatorRunConfig.getLabels() != null) { + objectMetaBuilder.addToLabels(generatorRunConfig.getLabels()); + } + + return objectMetaBuilder.build(); + } + + public static PodSpec getPodSpecFromRunConfig(GeneratorRunConfig generatorRunConfig) { + PodSpecBuilder podSpecBuilder = new PodSpecBuilder(); + if (generatorRunConfig.getRestartPolicy() != null) { + podSpecBuilder.withRestartPolicy(generatorRunConfig.getRestartPolicy()); + } else { + podSpecBuilder.withRestartPolicy(DEFAULT_RESTART_POLICY); + } + + if (generatorRunConfig.getServiceAccount() != null) { + podSpecBuilder.withServiceAccountName(generatorRunConfig.getServiceAccount()); + } + + podSpecBuilder.addToContainers(getContainersFromRunConfig(generatorRunConfig)); + + return podSpecBuilder.build(); + } + + public static Container getContainersFromRunConfig(GeneratorRunConfig generatorRunConfig) { + ContainerBuilder containerBuilder = new ContainerBuilder(); + if (generatorRunConfig.getName() != null) { + containerBuilder.withName(generatorRunConfig.getName()); + } + + if (generatorRunConfig.getImage() != null) { + containerBuilder.withImage(generatorRunConfig.getImage()); + } + + if (generatorRunConfig.getImagePullPolicy() != null) { + containerBuilder.withImagePullPolicy(generatorRunConfig.getImagePullPolicy()); + } + + if (generatorRunConfig.getEnv() != null) { + containerBuilder.withEnv(KubernetesResourceUtil.convertMapToEnvVarList(generatorRunConfig.getEnv())); + } + + if (generatorRunConfig.getPort() > 0) { + containerBuilder.withPorts(new ContainerPortBuilder() + .withContainerPort(generatorRunConfig.getPort()) + .build()); + } + + if (generatorRunConfig.getLimits() != null) { + containerBuilder.editOrNewResources() + .addToLimits(generatorRunConfig.getLimits()) + .endResources(); + } + + if (generatorRunConfig.getRequests() != null) { + containerBuilder.editOrNewResources() + .addToRequests(generatorRunConfig.getRequests()) + .endResources(); + } + return containerBuilder.build(); + } + + public static DeploymentSpec getDeploymentSpecFromRunConfig(GeneratorRunConfig generatorRunConfig) { + DeploymentSpecBuilder deploymentSpecBuilder = new DeploymentSpecBuilder(); + if (generatorRunConfig.getReplicas() > 0) { + deploymentSpecBuilder.withReplicas(generatorRunConfig.getReplicas()); + } else { + deploymentSpecBuilder.withReplicas(DEFAULT_REPLICAS); + } + + if (generatorRunConfig.getName() != null) { + deploymentSpecBuilder.editOrNewSelector() + .withMatchLabels(Collections.singletonMap("run", generatorRunConfig.getName())) + .endSelector(); + } + deploymentSpecBuilder.withTemplate(getPodTemplateSpecFromRunConfig(generatorRunConfig)); + + return deploymentSpecBuilder.build(); + } + + public static PodTemplateSpec getPodTemplateSpecFromRunConfig(GeneratorRunConfig generatorRunConfig) { + PodTemplateSpecBuilder podTemplateBuilder = new PodTemplateSpecBuilder(); + if (generatorRunConfig.getName() != null) { + podTemplateBuilder.withNewMetadata() + .addToLabels("run", generatorRunConfig.getName()) + .endMetadata(); + } + + if (generatorRunConfig.getLabels() != null) { + podTemplateBuilder.editOrNewMetadata() + .addToLabels(generatorRunConfig.getLabels()) + .endMetadata(); + } + + podTemplateBuilder.withNewSpec() + .addToContainers(getContainersFromRunConfig(generatorRunConfig)) + .endSpec(); + return podTemplateBuilder.build(); + } +} diff --git a/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/utils/KubernetesResourceUtil.java b/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/utils/KubernetesResourceUtil.java index 06b4fc99202..c7f4e0430cb 100644 --- a/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/utils/KubernetesResourceUtil.java +++ b/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/utils/KubernetesResourceUtil.java @@ -16,6 +16,8 @@ package io.fabric8.kubernetes.client.utils; +import io.fabric8.kubernetes.api.model.EnvVar; +import io.fabric8.kubernetes.api.model.EnvVarBuilder; import io.fabric8.kubernetes.api.model.Event; import io.fabric8.kubernetes.api.model.HasMetadata; import io.fabric8.kubernetes.api.model.KubernetesList; @@ -23,6 +25,7 @@ import io.fabric8.kubernetes.api.model.OwnerReference; import java.time.Instant; +import java.util.ArrayList; import java.util.Collections; import java.util.LinkedHashMap; import java.util.List; @@ -328,4 +331,17 @@ public static void sortEventListBasedOnTimestamp(List eventList) { }); } } + + public static List convertMapToEnvVarList(Map envVarMap) { + List envVars = new ArrayList<>(); + for (Map.Entry entry : envVarMap.entrySet()) { + if (entry.getKey() != null && entry.getValue() != null) { + envVars.add(new EnvVarBuilder() + .withName(entry.getKey()) + .withValue(entry.getValue()) + .build()); + } + } + return envVars; + } } diff --git a/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/utils/PodGeneratorImpl.java b/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/utils/PodGeneratorImpl.java new file mode 100644 index 00000000000..47a5472c30a --- /dev/null +++ b/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/utils/PodGeneratorImpl.java @@ -0,0 +1,94 @@ +/** + * Copyright (C) 2015 Red Hat, Inc. + * + * Licensed 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.client.utils; + +import io.fabric8.kubernetes.api.model.Pod; +import io.fabric8.kubernetes.api.model.PodBuilder; +import io.fabric8.kubernetes.client.Config; +import io.fabric8.kubernetes.client.dsl.internal.core.v1.PodOperationsImpl; +import okhttp3.OkHttpClient; + +public class PodGeneratorImpl { + private final OkHttpClient client; + private final Config config; + private final String namespace; + private final GeneratorRunConfig.Builder generatorRunConfigBuilder; + + public PodGeneratorImpl(OkHttpClient client, Config config, String namespace, GeneratorRunConfig.Builder runConfig) { + this.client = client; + this.config = config; + this.namespace = namespace; + this.generatorRunConfigBuilder = runConfig; + } + + /** + * Specify namespace for the operation + * + * @param namespace namespace in which resource needs to be created + * @return {@link PodGeneratorImpl} with injected namespace + */ + public PodGeneratorImpl inNamespace(String namespace) { + return new PodGeneratorImpl(this.client, this.config, namespace, this.generatorRunConfigBuilder); + } + + /** + * Specify image for the Pod + * + * @param image image as a string + * @return {@link PodGeneratorImpl} with image injected into {@link GeneratorRunConfig} + */ + public PodGeneratorImpl withImage(String image) { + return new PodGeneratorImpl(this.client, this.config, namespace, this.generatorRunConfigBuilder.withImage(image)); + } + + /** + * Specify name for the Pod + * + * @param name name of the pod to be created + * @return {@link PodGeneratorImpl} with name injected into {@link GeneratorRunConfig} + */ + public PodGeneratorImpl withName(String name) { + return new PodGeneratorImpl(this.client, this.config, namespace, this.generatorRunConfigBuilder.withName(name)); + } + + /** + * Specify complex configuration for Pod creating using {@link GeneratorRunConfig} + * + * @param generatorRunConfig {@link GeneratorRunConfig} which allows to provide configuring environment variables, labels, resources, ports etc + * @return {@link PodGeneratorImpl} with specified configuration + */ + public PodGeneratorImpl withRunConfig(GeneratorRunConfig generatorRunConfig) { + return new PodGeneratorImpl(this.client, this.config, namespace, new GeneratorRunConfig.Builder(generatorRunConfig)); + } + + /** + * Apply the {@link GeneratorRunConfig} onto the cluster and create Pod + * + * @return Pod which got created from the operation + */ + public Pod done() { + PodOperationsImpl podOperations = new PodOperationsImpl(client, config, namespace); + return podOperations.create(convertRunConfigIntoPod()); + } + + protected Pod convertRunConfigIntoPod() { + GeneratorRunConfig finalGeneratorConfig = generatorRunConfigBuilder.build(); + return new PodBuilder() + .withMetadata(GeneratorRunConfigUtil.getObjectMetadataFromRunConfig(finalGeneratorConfig)) + .withSpec(GeneratorRunConfigUtil.getPodSpecFromRunConfig(finalGeneratorConfig)) + .build(); + } +} diff --git a/kubernetes-client/src/main/resources/META-INF/services/io.fabric8.kubernetes.client.ExtensionAdapter b/kubernetes-client/src/main/resources/META-INF/services/io.fabric8.kubernetes.client.ExtensionAdapter index 3ef1f039af0..3f82a186419 100644 --- a/kubernetes-client/src/main/resources/META-INF/services/io.fabric8.kubernetes.client.ExtensionAdapter +++ b/kubernetes-client/src/main/resources/META-INF/services/io.fabric8.kubernetes.client.ExtensionAdapter @@ -38,3 +38,4 @@ io.fabric8.kubernetes.client.V1ApiextensionsAPIGroupExtensionAdapter io.fabric8.kubernetes.client.V1beta1ApiextensionsAPIGroupExtensionAdapter io.fabric8.kubernetes.client.V1AuthorizationAPIGroupExtensionAdapter io.fabric8.kubernetes.client.V1beta1AuthorizationAPIGroupExtensionAdapter +io.fabric8.kubernetes.client.GeneratorRunExtensionAdapter diff --git a/kubernetes-client/src/test/java/io/fabric8/kubernetes/client/utils/DeploymentGeneratorImplTest.java b/kubernetes-client/src/test/java/io/fabric8/kubernetes/client/utils/DeploymentGeneratorImplTest.java new file mode 100644 index 00000000000..07eaa185253 --- /dev/null +++ b/kubernetes-client/src/test/java/io/fabric8/kubernetes/client/utils/DeploymentGeneratorImplTest.java @@ -0,0 +1,81 @@ +package io.fabric8.kubernetes.client.utils; + +import io.fabric8.kubernetes.api.model.Quantity; +import io.fabric8.kubernetes.api.model.apps.Deployment; +import io.fabric8.kubernetes.client.Config; +import io.fabric8.kubernetes.client.ConfigBuilder; +import okhttp3.OkHttpClient; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +class DeploymentGeneratorImplTest { + private OkHttpClient mockClient; + private Config config; + + @BeforeEach + public void init() { + this.mockClient = Mockito.mock(OkHttpClient.class, Mockito.RETURNS_DEEP_STUBS); + this.config = new ConfigBuilder().withMasterUrl("https://localhost:8443/").build(); + } + + @Test + void testConvertRunConfigIntoDeployment() { + // Given + Map limits = new HashMap<>(); + limits.put("cpu", new Quantity("200m")); + limits.put("memory", new Quantity("512Mi")); + Map requests = new HashMap<>(); + requests.put("memory", new Quantity("64Mi")); + requests.put("cpu", new Quantity("150m")); + Map labels = new HashMap<>(); + labels.put("first", "FIRST"); + labels.put("second", "SECOND"); + GeneratorRunConfig.Builder generatorRunConfig = new GeneratorRunConfig.Builder() + .withName("test") + .withImage("test:latest") + .withLabels(labels) + .withReplicas(1) + .withEnv(Collections.singletonMap("TEST_KEY", "TEST_VALUE")) + .withImagePullPolicy("IfNotPresent") + .withPort(5701) + .withLimits(limits) + .withRequests(requests); + DeploymentGeneratorImpl deploymentGenerator = new DeploymentGeneratorImpl(mockClient, config, "ns1", generatorRunConfig); + + // When + Deployment deployment = deploymentGenerator.convertRunConfigIntoDeployment(); + + // Then + assertNotNull(deployment); + assertEquals("test", deployment.getMetadata().getName()); + assertEquals("FIRST", deployment.getMetadata().getLabels().get("first")); + assertEquals("SECOND", deployment.getMetadata().getLabels().get("second")); + assertEquals("test", deployment.getMetadata().getLabels().get("run")); + assertNotNull(deployment.getSpec()); + assertEquals("test", deployment.getSpec().getSelector().getMatchLabels().get("run")); + assertEquals(1, deployment.getSpec().getReplicas()); + assertNotNull(deployment.getSpec().getTemplate()); + assertNotNull(deployment.getSpec().getTemplate().getSpec()); + assertEquals(1, deployment.getSpec().getTemplate().getSpec().getContainers().size()); + assertEquals("test", deployment.getSpec().getTemplate().getSpec().getContainers().get(0).getName()); + assertEquals("IfNotPresent", deployment.getSpec().getTemplate().getSpec().getContainers().get(0).getImagePullPolicy()); + assertEquals("test:latest", deployment.getSpec().getTemplate().getSpec().getContainers().get(0).getImage()); + assertEquals(1, deployment.getSpec().getTemplate().getSpec().getContainers().get(0).getEnv().size()); + assertEquals(1, deployment.getSpec().getTemplate().getSpec().getContainers().get(0).getPorts().size()); + assertEquals(5701, deployment.getSpec().getTemplate().getSpec().getContainers().get(0).getPorts().get(0).getContainerPort()); + assertEquals("TEST_KEY", deployment.getSpec().getTemplate().getSpec().getContainers().get(0).getEnv().get(0).getName()); + assertEquals("TEST_VALUE", deployment.getSpec().getTemplate().getSpec().getContainers().get(0).getEnv().get(0).getValue()); + assertEquals(new Quantity("200m"), deployment.getSpec().getTemplate().getSpec().getContainers().get(0).getResources().getLimits().get("cpu")); + assertEquals(new Quantity("512Mi"), deployment.getSpec().getTemplate().getSpec().getContainers().get(0).getResources().getLimits().get("memory")); + assertEquals(new Quantity("150m"), deployment.getSpec().getTemplate().getSpec().getContainers().get(0).getResources().getRequests().get("cpu")); + assertEquals(new Quantity("64Mi"), deployment.getSpec().getTemplate().getSpec().getContainers().get(0).getResources().getRequests().get("memory")); + } +} diff --git a/kubernetes-client/src/test/java/io/fabric8/kubernetes/client/utils/GeneratorRunConfigUtilTest.java b/kubernetes-client/src/test/java/io/fabric8/kubernetes/client/utils/GeneratorRunConfigUtilTest.java new file mode 100644 index 00000000000..cba81e1ad0d --- /dev/null +++ b/kubernetes-client/src/test/java/io/fabric8/kubernetes/client/utils/GeneratorRunConfigUtilTest.java @@ -0,0 +1,182 @@ +/** + * Copyright (C) 2015 Red Hat, Inc. + * + * Licensed 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.client.utils; + +import io.fabric8.kubernetes.api.model.Container; +import io.fabric8.kubernetes.api.model.ObjectMeta; +import io.fabric8.kubernetes.api.model.PodSpec; +import io.fabric8.kubernetes.api.model.PodTemplateSpec; +import io.fabric8.kubernetes.api.model.Quantity; +import io.fabric8.kubernetes.api.model.apps.DeploymentSpec; +import org.junit.jupiter.api.Test; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +class GeneratorRunConfigUtilTest { + @Test + void testGetObjectMetadataFromRunConfig() { + // Given + GeneratorRunConfig config = new GeneratorRunConfig.Builder() + .withName("test") + .withLabels(Collections.singletonMap("foo", "bar")) + .build(); + + // When + ObjectMeta objectMeta = GeneratorRunConfigUtil.getObjectMetadataFromRunConfig(config); + + // Then + assertNotNull(objectMeta); + assertEquals("test", objectMeta.getName()); + assertFalse(objectMeta.getLabels().isEmpty()); + assertEquals("bar", objectMeta.getLabels().get("foo")); + } + + @Test + void testGetPodSpecFromRunConfig() { + // Given + GeneratorRunConfig config = new GeneratorRunConfig.Builder() + .withName("test") + .withImage("test:latest") + .withEnv(Collections.singletonMap("TEST_KEY", "TEST_VALUE")) + .withImagePullPolicy("IfNotPresent") + .withLimits(getLimits()) + .build(); + + // When + PodSpec podSpec = GeneratorRunConfigUtil.getPodSpecFromRunConfig(config); + + // Then + assertNotNull(podSpec); + assertNotNull(podSpec.getContainers()); + assertEquals(1, podSpec.getContainers().size()); + assertEquals("test", podSpec.getContainers().get(0).getName()); + assertEquals("IfNotPresent", podSpec.getContainers().get(0).getImagePullPolicy()); + assertEquals("test:latest", podSpec.getContainers().get(0).getImage()); + assertEquals(1, podSpec.getContainers().get(0).getEnv().size()); + assertEquals("TEST_KEY", podSpec.getContainers().get(0).getEnv().get(0).getName()); + assertEquals("TEST_VALUE", podSpec.getContainers().get(0).getEnv().get(0).getValue()); + } + + @Test + void testGetContainersFromRunConfig() { + // Given + GeneratorRunConfig config = getCompleteGeneratorRunConfig(); + + // When + Container container = GeneratorRunConfigUtil.getContainersFromRunConfig(config); + + // Then + assertNotNull(container); + assertEquals("test", container.getName()); + assertEquals("IfNotPresent", container.getImagePullPolicy()); + assertEquals("test:latest", container.getImage()); + assertEquals(1, container.getEnv().size()); + assertEquals(1, container.getPorts().size()); + assertEquals(5701, container.getPorts().get(0).getContainerPort()); + assertEquals("TEST_KEY", container.getEnv().get(0).getName()); + assertEquals("TEST_VALUE", container.getEnv().get(0).getValue()); + assertEquals(new Quantity("200m"), container.getResources().getLimits().get("cpu")); + assertEquals(new Quantity("512Mi"), container.getResources().getLimits().get("memory")); + assertEquals(new Quantity("150m"), container.getResources().getRequests().get("cpu")); + assertEquals(new Quantity("64Mi"), container.getResources().getRequests().get("memory")); + } + + @Test + void testGetDeploymentSpecFromRunConfig() { + // Given + GeneratorRunConfig config = getCompleteGeneratorRunConfig(); + + // When + DeploymentSpec deploymentSpec = GeneratorRunConfigUtil.getDeploymentSpecFromRunConfig(config); + + // Then + assertNotNull(deploymentSpec); + assertEquals(1, deploymentSpec.getReplicas()); + assertNotNull(deploymentSpec.getTemplate()); + assertNotNull(deploymentSpec.getTemplate().getSpec()); + assertEquals(1, deploymentSpec.getTemplate().getSpec().getContainers().size()); + assertEquals("test", deploymentSpec.getTemplate().getSpec().getContainers().get(0).getName()); + assertEquals("IfNotPresent", deploymentSpec.getTemplate().getSpec().getContainers().get(0).getImagePullPolicy()); + assertEquals("test:latest", deploymentSpec.getTemplate().getSpec().getContainers().get(0).getImage()); + assertEquals(1, deploymentSpec.getTemplate().getSpec().getContainers().get(0).getEnv().size()); + assertEquals(1, deploymentSpec.getTemplate().getSpec().getContainers().get(0).getPorts().size()); + assertEquals(5701, deploymentSpec.getTemplate().getSpec().getContainers().get(0).getPorts().get(0).getContainerPort()); + assertEquals("TEST_KEY", deploymentSpec.getTemplate().getSpec().getContainers().get(0).getEnv().get(0).getName()); + assertEquals("TEST_VALUE", deploymentSpec.getTemplate().getSpec().getContainers().get(0).getEnv().get(0).getValue()); + assertEquals(new Quantity("200m"), deploymentSpec.getTemplate().getSpec().getContainers().get(0).getResources().getLimits().get("cpu")); + assertEquals(new Quantity("512Mi"), deploymentSpec.getTemplate().getSpec().getContainers().get(0).getResources().getLimits().get("memory")); + assertEquals(new Quantity("150m"), deploymentSpec.getTemplate().getSpec().getContainers().get(0).getResources().getRequests().get("cpu")); + assertEquals(new Quantity("64Mi"), deploymentSpec.getTemplate().getSpec().getContainers().get(0).getResources().getRequests().get("memory")); + } + + @Test + void testGetPodTemplateFromRunConfig() { + // Given + GeneratorRunConfig config = getCompleteGeneratorRunConfig(); + + // When + PodTemplateSpec podTemplateSpec = GeneratorRunConfigUtil.getPodTemplateSpecFromRunConfig(config); + + // Then + assertNotNull(podTemplateSpec); + assertEquals(1, podTemplateSpec.getSpec().getContainers().size()); + assertEquals("test", podTemplateSpec.getSpec().getContainers().get(0).getName()); + assertEquals("IfNotPresent", podTemplateSpec.getSpec().getContainers().get(0).getImagePullPolicy()); + assertEquals("test:latest", podTemplateSpec.getSpec().getContainers().get(0).getImage()); + assertEquals(1, podTemplateSpec.getSpec().getContainers().get(0).getEnv().size()); + assertEquals(1, podTemplateSpec.getSpec().getContainers().get(0).getPorts().size()); + assertEquals(5701, podTemplateSpec.getSpec().getContainers().get(0).getPorts().get(0).getContainerPort()); + assertEquals("TEST_KEY", podTemplateSpec.getSpec().getContainers().get(0).getEnv().get(0).getName()); + assertEquals("TEST_VALUE", podTemplateSpec.getSpec().getContainers().get(0).getEnv().get(0).getValue()); + assertEquals(new Quantity("200m"), podTemplateSpec.getSpec().getContainers().get(0).getResources().getLimits().get("cpu")); + assertEquals(new Quantity("512Mi"), podTemplateSpec.getSpec().getContainers().get(0).getResources().getLimits().get("memory")); + assertEquals(new Quantity("150m"), podTemplateSpec.getSpec().getContainers().get(0).getResources().getRequests().get("cpu")); + assertEquals(new Quantity("64Mi"), podTemplateSpec.getSpec().getContainers().get(0).getResources().getRequests().get("memory")); + } + + private Map getLimits() { + Map limits = new HashMap<>(); + limits.put("cpu", new Quantity("200m")); + limits.put("memory", new Quantity("512Mi")); + return limits; + } + + private Map getRequests() { + Map requests = new HashMap<>(); + requests.put("memory", new Quantity("64Mi")); + requests.put("cpu", new Quantity("150m")); + return requests; + } + + private GeneratorRunConfig getCompleteGeneratorRunConfig() { + return new GeneratorRunConfig.Builder() + .withName("test") + .withImage("test:latest") + .withReplicas(1) + .withEnv(Collections.singletonMap("TEST_KEY", "TEST_VALUE")) + .withImagePullPolicy("IfNotPresent") + .withPort(5701) + .withLimits(getLimits()) + .withRequests(getRequests()) + .build(); + } +} diff --git a/kubernetes-client/src/test/java/io/fabric8/kubernetes/client/utils/PodGeneratorImplTest.java b/kubernetes-client/src/test/java/io/fabric8/kubernetes/client/utils/PodGeneratorImplTest.java new file mode 100644 index 00000000000..d9f94f1559d --- /dev/null +++ b/kubernetes-client/src/test/java/io/fabric8/kubernetes/client/utils/PodGeneratorImplTest.java @@ -0,0 +1,79 @@ +package io.fabric8.kubernetes.client.utils; + +import io.fabric8.kubernetes.api.model.Pod; +import io.fabric8.kubernetes.api.model.Quantity; +import io.fabric8.kubernetes.client.Config; +import io.fabric8.kubernetes.client.ConfigBuilder; +import okhttp3.OkHttpClient; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +class PodGeneratorImplTest { + private OkHttpClient mockClient; + private Config config; + + @BeforeEach + public void init() { + this.mockClient = Mockito.mock(OkHttpClient.class, Mockito.RETURNS_DEEP_STUBS); + this.config = new ConfigBuilder().withMasterUrl("https://localhost:8443/").build(); + } + + @Test + void testConvertRunConfigIntoPod() { + // Given + Map limits = new HashMap<>(); + limits.put("cpu", new Quantity("200m")); + limits.put("memory", new Quantity("512Mi")); + Map requests = new HashMap<>(); + requests.put("memory", new Quantity("64Mi")); + requests.put("cpu", new Quantity("150m")); + Map labels = new HashMap<>(); + labels.put("first", "FIRST"); + labels.put("second", "SECOND"); + GeneratorRunConfig.Builder generatorRunConfig = new GeneratorRunConfig.Builder() + .withName("test") + .withImage("test:latest") + .withLabels(labels) + .withEnv(Collections.singletonMap("TEST_KEY", "TEST_VALUE")) + .withImagePullPolicy("IfNotPresent") + .withRestartPolicy("OnFailure") + .withServiceAccount("ribbon") + .withPort(5701) + .withLimits(limits) + .withRequests(requests); + PodGeneratorImpl deploymentGenerator = new PodGeneratorImpl(mockClient, config, "ns1", generatorRunConfig); + + // When + Pod pod = deploymentGenerator.convertRunConfigIntoPod(); + + // Then + assertNotNull(pod); + assertEquals("test", pod.getMetadata().getName()); + assertEquals("FIRST", pod.getMetadata().getLabels().get("first")); + assertEquals("SECOND", pod.getMetadata().getLabels().get("second")); + assertEquals("test", pod.getMetadata().getLabels().get("run")); + assertNotNull(pod.getSpec()); + assertEquals("OnFailure", pod.getSpec().getRestartPolicy()); + assertEquals("ribbon", pod.getSpec().getServiceAccountName()); + assertEquals("test", pod.getSpec().getContainers().get(0).getName()); + assertEquals("IfNotPresent", pod.getSpec().getContainers().get(0).getImagePullPolicy()); + assertEquals("test:latest", pod.getSpec().getContainers().get(0).getImage()); + assertEquals(1, pod.getSpec().getContainers().get(0).getEnv().size()); + assertEquals(1, pod.getSpec().getContainers().get(0).getPorts().size()); + assertEquals(5701, pod.getSpec().getContainers().get(0).getPorts().get(0).getContainerPort()); + assertEquals("TEST_KEY", pod.getSpec().getContainers().get(0).getEnv().get(0).getName()); + assertEquals("TEST_VALUE", pod.getSpec().getContainers().get(0).getEnv().get(0).getValue()); + assertEquals(new Quantity("200m"), pod.getSpec().getContainers().get(0).getResources().getLimits().get("cpu")); + assertEquals(new Quantity("512Mi"), pod.getSpec().getContainers().get(0).getResources().getLimits().get("memory")); + assertEquals(new Quantity("150m"), pod.getSpec().getContainers().get(0).getResources().getRequests().get("cpu")); + assertEquals(new Quantity("64Mi"), pod.getSpec().getContainers().get(0).getResources().getRequests().get("memory")); + } +} diff --git a/openshift-client/src/main/java/io/fabric8/openshift/client/DefaultOpenShiftClient.java b/openshift-client/src/main/java/io/fabric8/openshift/client/DefaultOpenShiftClient.java index 375d03bb92d..d1d68995c0c 100644 --- a/openshift-client/src/main/java/io/fabric8/openshift/client/DefaultOpenShiftClient.java +++ b/openshift-client/src/main/java/io/fabric8/openshift/client/DefaultOpenShiftClient.java @@ -524,6 +524,11 @@ public V1APIGroupDSL v1() { return adapt(V1APIGroupClient.class); } + @Override + public GeneratorRunDSL run() { + return adapt(GeneratorRunClient.class); + } + @Override public AdmissionRegistrationAPIGroupDSL admissionRegistration() { return adapt(AdmissionRegistrationAPIGroupClient.class); diff --git a/openshift-client/src/main/java/io/fabric8/openshift/client/osgi/ManagedOpenShiftClient.java b/openshift-client/src/main/java/io/fabric8/openshift/client/osgi/ManagedOpenShiftClient.java index 1eaac6ce596..f125212f700 100644 --- a/openshift-client/src/main/java/io/fabric8/openshift/client/osgi/ManagedOpenShiftClient.java +++ b/openshift-client/src/main/java/io/fabric8/openshift/client/osgi/ManagedOpenShiftClient.java @@ -499,6 +499,11 @@ public V1APIGroupDSL v1() { return delegate.v1(); } + @Override + public GeneratorRunDSL run() { + return delegate.run(); + } + @Override public AdmissionRegistrationAPIGroupDSL admissionRegistration() { return delegate.admissionRegistration();