Skip to content

Commit

Permalink
Merge pull request #2272 from rohanKanojia/pr/issue1868
Browse files Browse the repository at this point in the history
  • Loading branch information
fusesource-ci committed Jun 15, 2020
2 parents 4aafeb5 + b3ea32b commit 2d1a9d4
Show file tree
Hide file tree
Showing 16 changed files with 1,199 additions and 81 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#### Dependency Upgrade

#### New Features
* Fix #1868: Add Support for rolling update

### 4.10.2 (2020-06-02)
#### Bugs
Expand Down
199 changes: 190 additions & 9 deletions doc/CHEATSHEET.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@ This document contains common usages of different resources using Fabric8 Kubern
* [Initializing Tekton Client](#initializing-tekton-client)
* [Tekton Client DSL Usage](#tekton-client-dsl-usage)

* [Knative Client](#knative-client)
* [Initializing Knative Client](#initializing-knative-client)
* [Knative Client DSL Usage](#knative-client-dsl-usage)

### Initializing Kubernetes Client
Typically, we create Kubernetes Client like this:
```
Expand Down Expand Up @@ -343,18 +347,54 @@ Deployment updatedDeploy = client.apps().deployments().inNamespace("default")
.withName("deployment1").edit()
.editSpec().withReplicas(2).endSpec().done();
```
- Rolling update a `Deployment`:
- Update single container image inside `Deployment`:
```
// Not sure about state of this, but this way should work. Otherwise it's a bug
client.apps().deployments().inNamespace("default").withName("ngix-controller")
Deployment updatedDeployment = client.apps().deployments().inNamespace("default").withName("ngix-controller")
.rolling().updateImage("docker.io/nginx:latest");
```
- Update multiple container images inside `Deployment`:
```
Map<String, String> containerToImageMap = new HashMap<>();
containerToImageMap.put("nginx", "nginx:perl");
containerToImageMap.put("sidecar", "someImage:someVersion");
Deployment updatedDeployment = client.apps().deployments()
.inNamespace("default")
.withName("nginx-deployment")
.rolling()
.updateImage(containerToImageMap);
// Workaround specified in https://github.com/fabric8io/kubernetes-client/issues/1868#issuecomment-569908949
client.apps().deployments().inNamespace("default").withName("nginx-controller")
.edit().editSpec().editTemplate().editMetadata()
.addToAnnotations("dummy", "du_"+System.currentTimeMillis())
.endMetadata().endTemplate().endSpec()
.done();
```
- Rollout restart a `Deployment`:
```
Deployment deployment = client.apps().deployments()
.inNamespace("default")
.withName("nginx-deployment")
.rolling()
.restart();
```
- Pause Rollout of a `Deployment`:
```
Deployment deployment = client.apps().deployments()
.inNamespace("default")
.withName("nginx-deployment")
.rolling()
.pause();
```
- Resume Rollout of a `Deployment`:
```
Deployment deployment = client.apps().deployments()
.inNamespace("default")
.withName("nginx-deployment")
.rolling()
.resume();
```
- Undo Rollout of a `Deployment`:
```
Deployment deployment = client.apps().deployments()
.inNamespace("default")
.withName("nginx-deployment")
.rolling()
.undo();
```
- Deleting a `Deployment`:
```
Expand Down Expand Up @@ -502,6 +542,25 @@ client.apps().replicaSets().inNamespace("default").watch(new Watcher<ReplicaSet>
// Scale to 3 replicas
client.apps().replicaSets().inNamespace("default").withName("nginx-rs").scale(3);
```
- Update Image in `ReplicaSet`
```
ReplicaSet replicaSet = client.apps().replicaSets()
.inNamespace("default")
.withName("soaktestrs")
.rolling()
.updateImage("nickchase/soaktest");
```
- Update multiple Images in `ReplicaSet`:
```
Map<String, String> containerToImageMap = new HashMap<>();
containerToImageMap.put("c1", "image1");
containerToImageMap.put("c2", "image2");
ReplicaSet replicaSet = client.apps().replicaSets()
.inNamespace("default")
.withName("soaktestrs")
.rolling()
.updateImage(containerToImageMap);
```

### ReplicationController

Expand Down Expand Up @@ -585,6 +644,25 @@ client.replicationControllers().inNamespace(currentNamespace).watch(new Watcher<
```
ReplicationController rc = client.replicationControllers().inNamespace("default").withName("nginx-controller").scale(2);
```
- Update image in `ReplicationController`:
```
ReplicationController rc = client.replicationControllers()
.inNamespace("default")
.withName("nginx")
.rolling()
.updateImage("nginx:latest");
```
- Update multiple images in `ReplicationController`:
```
Map<String, String> containerToImageMap = new HashMap<>();
containerToImageMap.put("c1", "image1");
containerToImageMap.put("c2", "image2");
ReplicationController rc = client.replicationControllers()
.inNamespace("default")
.withName("nginx")
.rolling()
.updateImage(controllerToImageMap);
```

### ConfigMap
`ConfigMap` resource is available in Kubernetes Client api via the `client.configMaps()`. Here are some examples of common usage:
Expand Down Expand Up @@ -1141,6 +1219,57 @@ client.apps().statefulSets().inNamespace("default").withName("ss1").watch(new Wa
}
})
```
- Update Image in `StatefulSet`:
```
StatefulSet statefulSet = client.apps().statefulSets()
.inNamespace("default")
.withName("web")
.rolling()
.updateImage("nginx:1.19");
```
- Updated multiple containers in `StatefulSet`:
```
Map<String, String> containerToImageMap = new HashMap<>();
containerToImageMap("container1", "nginx:1.9");
containerToImageMap("container2", "busybox:latest");
Statefulset statefulSet = client.apps().statefulSets()
.inNamespace("default")
.withName("web")
.rolling()
.updateImage(params);
```
- Restart Rollout for `StatefulSet`:
```
StatefulSet ss = client.apps().statefulSets()
.inNamespace("default")
.withName("web")
.rolling()
.restart();
```
- Pause Rollout for `StatefulSet`:
```
StatefulSet ss = client.apps().statefulSets()
.inNamespace("default")
.withName("web")
.rolling()
.pause();
```
- Resume Rollout for `StatefulSet`:
```
StatefulSet ss = client.apps().statefulSets()
.inNamespace("default")
.withName("web")
.rolling()
.resume();
```
- Undo Rollout for `StatefulSet`:
```
StatefulSet ss = client.apps().statefulSets()
.inNamespace("default")
.withName("web")
.rolling()
.undo();
```

### DaemonSet
`DaemonSet` resource is available in Kubernetes Client API via `client.apps().daemonSets()`. Here are some examples of its common usage:
Expand Down Expand Up @@ -2353,3 +2482,55 @@ PipelineRun pipelineRun = new PipelineRunBuilder()
tektonClient.v1beta1().pipelineRuns().inNamespace("default").create(pipelineRun);
```

### Knative Client
Fabric8 Kubernetes Client also has an extension for Knative.
It is pretty much the same as Kubernetes Client but has support for some additional Knative resources.

#### Initializing Knative Client
Initializing Knative client is the same as Kubernetes Client.
```
try (final KnativeClient client = new DefaultKnativeClient()) {
// Do stuff with client
}
```
This would pick up default settings, reading your `kubeconfig` file from `~/.kube/config` directory or whatever is defined inside `KUBECONFIG` environment variable.
But if you want to customize creation of client, you can also pass a `Config` object inside `DefaultKnativeClient`.
You can also create `KnativeClient` from an existing instance of `KubernetesClient`.
There is a method called `adapt(..)` for this.
Here is an example:
```
KubernetesClient client = new DefaultKubernetesClient();
KnativeClient knativeClient = client.adapt(KnativeClient.class);
```

#### Knative Client DSL Usage
The usage of the resources follows the same pattern as for K8s resources like Pods or Deployments.
Here are some common examples:

- Listing all `Service` objects in some specific namespace:
```
ServiceList list = knativeClient.services().inNamespace("default").list();
```
- Create a `Service`:
```
try (KnativeClient kn = new DefaultKnativeClient()) {
// Create Service object
Service service = new ServiceBuilder()
.withNewMetadata().withName("helloworld-go").endMetadata()
.withNewSpec()
.withNewTemplate()
.withNewSpec()
.addToContainers(new ContainerBuilder()
.withImage("gcr.io/knative-samples/helloworld-go")
.addNewEnv().withName("TARGET").withValue("Go Sample V1").endEnv()
.build())
.endSpec()
.endTemplate()
.endSpec()
.build();
// Apply it onto Kubernetes Server
kn.services().inNamespace("default").createOrReplace(service);
}
```
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,53 @@
*/
package io.fabric8.kubernetes.client.dsl;

import java.util.Map;

public interface ImageEditReplacePatchable<I, T, D> extends EditReplacePatchable<I, T, D> {

/**
* Update existing container image(s) of resources
*
* @param containerToImageMap Map with keys as container name and value as image
* @return updated resource
*/
T updateImage(Map<String, String> containerToImageMap);

/**
* Update existing container image of single container resource
*
* @param image image to be updated
* @return updated resource
*/
T updateImage(String image);

/**
* Mark the provided resource as paused
*
* @return updated resource
*/
T pause();

/**
* Resume a paused resource. Paused resources will not be reconciled by a controller.
* By resuming a resource, we allow it to be reconciled again.
*
* @return updated resource
*/
T resume();

/**
* Restart a resource. Resource will be rollout restarted.
*
* @return updated resource
*/
T restart();

/**
* Rollback to previous rollout.
*
* @return updated resource
*/
T undo();

}
Original file line number Diff line number Diff line change
Expand Up @@ -854,6 +854,22 @@ protected T handlePatch(T current, T updated) throws ExecutionException, Interru
return handlePatch(current, updated, getType());
}

protected T handlePatch(T current, Map<String, Object> patchedUpdate) throws ExecutionException, InterruptedException, IOException {
updateApiVersionResource(current);
return handlePatch(current, patchedUpdate, getType());
}

protected T sendPatchedObject(T oldObject, T updatedObject) {
try {
return handlePatch(oldObject, updatedObject);
} catch (InterruptedException interruptedException) {
Thread.currentThread().interrupt();
throw KubernetesClientException.launderThrowable(interruptedException);
} catch (ExecutionException | IOException e) {
throw KubernetesClientException.launderThrowable(e);
}
}

protected Scale handleScale(Scale scaleParam) {
try {
return handleScale(getCompleteResourceUrl().toString(), scaleParam);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ public class OperationSupport {

public static final MediaType JSON = MediaType.parse("application/json");
public static final MediaType JSON_PATCH = MediaType.parse("application/json-patch+json");
public static final MediaType STRATEGIC_MERGE_JSON_PATCH = MediaType.parse("application/strategic-merge-patch+json");
protected static final ObjectMapper JSON_MAPPER = Serialization.jsonMapper();
protected static final ObjectMapper YAML_MAPPER = Serialization.yamlMapper();
private static final String CLIENT_STATUS_FLAG = "CLIENT_STATUS_FLAG";
Expand Down Expand Up @@ -316,6 +317,26 @@ protected <T> T handlePatch(T current, T updated, Class<T> type) throws Executio
return handleResponse(requestBuilder, type, Collections.<String, String>emptyMap());
}

/**
* Send an http patch and handle the response.
*
* @param current current object
* @param patchForUpdate updated object spec as json string
* @param type type of object
* @param <T> template argument provided
*
* @return returns de-serialized version of api server response
* @throws ExecutionException Execution Exception
* @throws InterruptedException Interrupted Exception
* @throws KubernetesClientException KubernetesClientException
* @throws IOException IOException
*/
protected <T> T handlePatch(T current, Map<String, Object> patchForUpdate, Class<T> type) throws ExecutionException, InterruptedException, IOException {
RequestBody body = RequestBody.create(STRATEGIC_MERGE_JSON_PATCH, JSON_MAPPER.writeValueAsString(patchForUpdate));
Request.Builder requestBuilder = new Request.Builder().patch(body).url(getResourceUrl(checkNamespace(current), checkName(current)));
return handleResponse(requestBuilder, type, Collections.<String, String>emptyMap());
}

/**
* Replace Scale of specified Kubernetes Resource
*
Expand Down Expand Up @@ -589,6 +610,10 @@ protected static <T> T unmarshal(InputStream is, TypeReference<T> type) throws K
return Serialization.unmarshal(is, type);
}

protected static <T> Map getObjectValueAsMap(T object) {
return JSON_MAPPER.convertValue(object, Map.class);
}

public Config getConfig() {
return config;
}
Expand Down

0 comments on commit 2d1a9d4

Please sign in to comment.