Using Kubernetes C Client to Patch a Deployment

82 Views Asked by At

I'm trying to create a patch for the existing Kubernetes deployment in my local minikube cluster. I have successfully implemented a function to create a new deployment.

For the deployment patch, I think I have to use the following function in the api\AppsV1API.c:

v1_deployment_t *
AppsV1API_patchNamespacedDeployment(apiClient_t *apiClient, char *name, char *_namespace, object_t *body, char *pretty, char *dryRun, char *fieldManager, char *fieldValidation, int force)

I don't understand the function's correct argument for the object_t *body.

Deployment configuration file:

{
    "apiVersion": "apps/v1",
    "kind": "Deployment",
    "metadata": {
      "name": "busybox-deployment"
    },
    "spec": {
      "replicas": 1,
      "selector": {
        "matchLabels": {
          "app": "busybox"
        }
      },
      "template": {
        "metadata": {
          "labels": {
            "app": "busybox"
          }
        },
        "spec": {
          "containers": [
            {
              "name": "busybox-container",
              "image": "busybox",
              "command": ["sleep", "3600"]
            }
          ]
        }
      }
    }
  }
  

I want to change the replicas from 1 to 3.

Code I have used to insert [{'op': 'replace', 'path': '/spec/replicas', 'value': 2}] as the body:

cJSON *jsonArray = cJSON_CreateArray();

cJSON *jsonObject = cJSON_CreateObject();
cJSON_AddStringToObject(jsonObject, "op", "replace");
cJSON_AddStringToObject(jsonObject, "path", "/spec/replicas");
cJSON_AddNumberToObject(jsonObject, "value", 2);

cJSON_AddItemToArray(jsonArray, jsonObject);
object_t *body = object_parseFromJSON(jsonArray);

v1_deployment_t *updatedDeployment = AppsV1API_patchNamespacedDeployment(apiClient, deploymentInfo->metadata->name, namespc, body, NULL, NULL, NULL, NULL, 0);

Code I have used to insert {'spec': {'replicas': 2}} as the body:

cJSON *root = cJSON_CreateObject();

cJSON *specObject = cJSON_CreateObject();

cJSON_AddNumberToObject(specObject, "replicas", 2);

cJSON_AddItemToObject(root, "spec", specObject);
object_t *body = object_parseFromJSON(root);

v1_deployment_t *updatedDeployment = AppsV1API_patchNamespacedDeployment(apiClient, deploymentInfo->metadata->name, namespc, body, NULL, NULL, NULL, NULL, 0);

Both fail with the apiClient->responseCode as 422 (Payload error).

1

There are 1 best solutions below

2
On

Your code seems to work for me substantially as written. Here's my complete test case (the call to AppsV1API_patchNamespacedDeployment is identical to yours, except that name and namespace are specified using string literals):

#include <config/kube_config.h>
#include <api/AppsV1API.h>
#include <model/object.h>
#include <stdio.h>

void patch_deployment(apiClient_t *apiClient)
{
    v1_deployment_t *deploy;
    object_t * body;

    cJSON *jsonArray = cJSON_CreateArray();
    cJSON *jsonObject = cJSON_CreateObject();
    cJSON_AddStringToObject(jsonObject, "op", "replace");
    cJSON_AddStringToObject(jsonObject, "path", "/spec/replicas");
    cJSON_AddNumberToObject(jsonObject, "value", 2);

    cJSON_AddItemToArray(jsonArray, jsonObject);

    body = object_parseFromJSON(jsonArray);
    if (! body) {
        fprintf(stderr, "failed to convert patch to object\n");
        return;
    }

    v1_deployment_t *updatedDeployment = AppsV1API_patchNamespacedDeployment(
            apiClient,
            "web",
            "default",
            body,
            NULL,
            NULL,
            NULL,
            NULL,
            0);

    if (apiClient->response_code != 200) {
        fprintf(stderr, "failed to patch resource: %ld\n", apiClient->response_code);
    }
}

int main()
{
    char *basePath = NULL;
    sslConfig_t *sslConfig = NULL;
    list_t *apiKeys = NULL;
    int rc = load_kube_config(&basePath, &sslConfig, &apiKeys, NULL); /* NULL means loading configuration from $HOME/.kube/config */
    if (rc != 0)
    {
        printf("Cannot load kubernetes configuration.\n");
        return -1;
    }
    apiClient_t *apiClient = apiClient_create_with_base_path(basePath, sslConfig, apiKeys);
    if (!apiClient)
    {
        printf("Cannot create a kubernetes client.\n");
        return -1;
    }

    patch_deployment(apiClient);

    apiClient_free(apiClient);
    apiClient = NULL;
    free_client_config(basePath, sslConfig, apiKeys);
    basePath = NULL;
    sslConfig = NULL;
    apiKeys = NULL;
    apiClient_unsetupGlobalEnv();

    return 0;
}

Given the following deployment:

$ kubectl get deploy
NAME   READY   UP-TO-DATE   AVAILABLE   AGE
web    1/1     1            1           32d

The above code runs successfully, and results in:

NAME   READY   UP-TO-DATE   AVAILABLE   AGE
web    2/2     2            2           32d