Skip to content

Commit

Permalink
Fix fabric8io#2284: Support running/creating a particular image in a …
Browse files Browse the repository at this point in the history
…Pod operation

Add support for client.run() with which we should be able to create
Pod/Deployments just based on few parameters. For example, creating
a simple pod should be like:

client.run().pods().withName("nginx").withImage("nginx:1.39").done()
  • Loading branch information
rohanKanojia committed Aug 25, 2020
1 parent d31483b commit 63a7257
Show file tree
Hide file tree
Showing 14 changed files with 669 additions and 0 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Expand Up @@ -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`
Expand Down
26 changes: 26 additions & 0 deletions doc/CHEATSHEET.md
Expand Up @@ -40,6 +40,7 @@ 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)

* [OpenShift Client DSL Usage](#openshift-client-dsl-usage)
* [Initializing OpenShift Client](#initializing-openshift-client)
Expand Down Expand Up @@ -2288,6 +2289,31 @@ 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().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().inNamespace("default")
.withRunConfig(new GeneratorRunConfigBuilder()
.withName("nginx")
.withImage("nginx:latest")
.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.
Expand Down
Expand Up @@ -64,6 +64,7 @@
import io.fabric8.kubernetes.api.model.ServiceAccount;
import io.fabric8.kubernetes.api.model.ServiceAccountList;
import io.fabric8.kubernetes.api.model.ServiceList;
import io.fabric8.kubernetes.client.utils.PodGeneratorImpl;
import okhttp3.OkHttpClient;

import java.io.InputStream;
Expand Down Expand Up @@ -261,6 +262,11 @@ public MixedOperation<LimitRange, LimitRangeList, DoneableLimitRange, Resource<L
return delegate.limitRanges();
}

@Override
public PodGeneratorImpl run() {
return delegate.run();
}

@Override
public <C> Boolean isAdaptable(Class<C> type) {
return delegate.isAdaptable(type);
Expand Down
Expand Up @@ -112,6 +112,8 @@
import io.fabric8.kubernetes.client.dsl.internal.core.v1.ServiceAccountOperationsImpl;
import io.fabric8.kubernetes.client.dsl.internal.core.v1.EventOperationsImpl;
import io.fabric8.kubernetes.client.extended.leaderelection.LeaderElectorBuilder;
import io.fabric8.kubernetes.client.utils.GeneratorRunConfigBuilder;
import io.fabric8.kubernetes.client.utils.PodGeneratorImpl;
import io.fabric8.kubernetes.client.utils.Serialization;
import io.fabric8.kubernetes.client.informers.SharedInformerFactory;
import io.fabric8.kubernetes.client.utils.Utils;
Expand Down Expand Up @@ -439,4 +441,9 @@ public LeaderElectorBuilder<NamespacedKubernetesClient> leaderElector() {
public MixedOperation<Lease, LeaseList, DoneableLease, Resource<Lease, DoneableLease>> leases() {
return new LeaseOperationsImpl(httpClient, getConfiguration());
}

@Override
public PodGeneratorImpl run() {
return new PodGeneratorImpl(httpClient, getConfiguration(), getNamespace(), new GeneratorRunConfigBuilder());
}
}
Expand Up @@ -85,6 +85,7 @@
import io.fabric8.kubernetes.client.dsl.internal.RawCustomResourceOperationsImpl;
import io.fabric8.kubernetes.client.extended.leaderelection.LeaderElectorBuilder;
import io.fabric8.kubernetes.client.informers.SharedInformerFactory;
import io.fabric8.kubernetes.client.utils.PodGeneratorImpl;

import java.io.InputStream;
import java.util.Collection;
Expand Down Expand Up @@ -514,4 +515,11 @@ public interface KubernetesClient extends Client {
* @return V1APIGroupDSL DSL object for core v1 resources
*/
V1APIGroupDSL v1();

/**
* 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 run();
}
Expand Up @@ -124,6 +124,8 @@
import io.fabric8.kubernetes.client.dsl.internal.RawCustomResourceOperationsImpl;
import io.fabric8.kubernetes.client.extended.leaderelection.LeaderElectorBuilder;
import io.fabric8.kubernetes.client.informers.SharedInformerFactory;
import io.fabric8.kubernetes.client.utils.GeneratorRunConfigBuilder;
import io.fabric8.kubernetes.client.utils.PodGeneratorImpl;
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.ConfigurationPolicy;
Expand Down Expand Up @@ -557,4 +559,9 @@ public NamespacedKubernetesClient inNamespace(String name) {
public FunctionCallable<NamespacedKubernetesClient> withRequestConfig(RequestConfig requestConfig) {
return delegate.withRequestConfig(requestConfig);
}

@Override
public PodGeneratorImpl run() {
return new PodGeneratorImpl(httpClient, getConfiguration(), getNamespace(), new GeneratorRunConfigBuilder());
}
}
@@ -0,0 +1,171 @@
/**
* 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 io.sundr.builder.annotations.Buildable;

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<String, String> labels;
/**
* Environment variables to be add
*/
private Map<String, String> env;
/**
* Resource limits
*/
private Map<String, Quantity> limits;
/**
* Resource requests
*/
private Map<String, Quantity> requests;
/**
* replicas
*/
private int replicas;
/**
* Port to use
*/
private int port;

@Buildable(builderPackage = "io.fabric8.kubernetes.api.builder")
public GeneratorRunConfig(String name, String image, String imagePullPolicy, String restartPolicy, String serviceAccount, Map<String, String> labels, Map<String, String> env, Map<String, Quantity> limits, Map<String, Quantity> requests, int replicas, int port) {
this.name = name;
this.image = image;
this.imagePullPolicy = imagePullPolicy;
this.restartPolicy = restartPolicy;
this.serviceAccount = serviceAccount;
this.labels = labels;
this.env = env;
this.limits = limits;
this.requests = requests;
this.replicas = replicas;
this.port = port;
}

public String getName() { return name; }

public String getImage() {
return image;
}

public String getImagePullPolicy() {
return imagePullPolicy;
}

public Map<String, String> getLabels() {
return labels;
}

public Map<String, String> getEnv() {
return env;
}

public Map<String, Quantity> getLimits() {
return limits;
}

public Map<String, Quantity> 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<String, Quantity> requests) {
this.requests = requests;
}

public void setLimits(Map<String, Quantity> limits) {
this.limits = limits;
}

public void setEnv(Map<String, String> env) {
this.env = env;
}

public void setLabels(Map<String, String> labels) {
this.labels = labels;
}

public void setImagePullPolicy(String imagePullPolicy) {
this.imagePullPolicy = imagePullPolicy;
}

public void setImage(String image) {
this.image = image;
}
}
@@ -0,0 +1,98 @@
/**
* 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;

public class GeneratorRunConfigUtil {
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();
}
}

0 comments on commit 63a7257

Please sign in to comment.