How to advertise extended resources for a node using fabric8 API

7/22/2019

I want to add extended resources for kubernetes nodes, and I can do this by curl command indicated in: https://kubernetes.io/docs/tasks/administer-cluster/extended-resource-node/, that is:

curl --header "Content-Type: application/json-patch+json" \
--request PATCH \
--data '[{"op": "add", "path": "/status/capacity/example.com~1dongle", 
"value": "4"}]' \
http://localhost:8001/api/v1/nodes/<your-node-name>/status

and then, I can create a pod requiring example.com/dongle resource.

but, how to do this using fabric8 java API?

I tried it in my java demo application with all nodes related API, but it doesn't work. The snippet code is as following:

String ns = "thisisatest";
String master = "http://192.168.1.45:8080/";

Config config = new ConfigBuilder().withMasterUrl(master).build();
try (KubernetesClient client = new DefaultKubernetesClient(config)) {
  try {
    if(client.namespaces().withName(ns).get() == null) {
      log("Create namespace:", client.namespaces().create(new NamespaceBuilder().withNewMetadata().withName(ns).endMetadata().build()));
    }

    String podNameWithExtRes = "k8s-n1";

    /*step 1: patch extended resource*/
    NodeStatus ndStatus = client.nodes().withName(podNameWithExtRes).get().getStatus();
    Map<String, Quantity> ndCap = ndStatus.getCapacity();
    ndCap.put("example.com/dongle", new Quantity("2"));
    ndStatus.setCapacity(ndCap);
    log("status info: \n", ndStatus.toString());
    // ndStatus.setAllocatable(mapSrc);
    Node n1 = client.nodes().withName(podNameWithExtRes).get();
    n1.setStatus(ndStatus);
    // client.nodes().withName(podNameWithExtRes).delete(); // it can be deleted successfully
    // client.nodes().create(n1); // error
    client.nodes().createOrReplace(n1);

    log("n1 status: \n", n1.getStatus().toString());
    log("get node status: \n", client.nodes().withName(podNameWithExtRes).get().getStatus().toString());
    // ...
  }
}

At the beginning, I didn't add client.nodes().create* clause, but it didn't take any effect. I realize it may need to write back the settings. However, even I add it, it doesn't take effect either.

  1. createOrReplace() runs without error, but it doesn't save the effect to the node.

logs of "n1 status":

capacity={cpu=Quantity(amount=4, format=null,additionalProperties={}), ..., pods=Quantity(amount=110, format=null, additionalProperties={}), example.com/dongle=Quantity(amount=2, format=null, additionalProperties={})},

logs of "get node status":

capacity={cpu=Quantity(amount=4, format=null, additionalProperties={}), ..., pods=Quantity(amount=110, format=null, additionalProperties={})}, 

And, it responses nothing when I run the command in the terminal:

kubectl describe node k8s-n1 | grep dongle
  1. create(n1) prompts the following error:

    io.fabric8.kubernetes.client.KubernetesClientException: Failure executing: POST at: http://192.168.1.45:8080/api/v1/nodes. Message: resourceVersion should not be set on objects to be created. Received status: Status(apiVersion=v1, code=500, details=null, kind=Status, message=resourceVersion should not be set on objects to be created, metadata=ListMeta(_continue=null, resourceVersion=null, selfLink=null, additionalProperties={}), reason=null, status=Failure, additionalProperties={}).

How to make it work?

-- Michael Wang
fabric8
kubernetes

1 Answer

7/25/2019

I've tried more fabric8 APIs as following, but none of them works:

// client.nodes().withName(podNameWithExtRes).get().setStatus(ndStatus); // not working
// client.nodes().withName(podNameWithExtRes).patch(n1); // not working
// client.nodes().withName(podNameWithExtRes).patch(n1).setStatus(ndStatus); // not working
// client.nodes().withName(podNameWithExtRes).edit().withStatus(ndStatus).done(); // not working
// client.nodes().withName(podNameWithExtRes).edit().withStatus(ndStatus).buildStatus(); // not working
// client.nodes().withName(podNameWithExtRes).replace(n1); // not working

finally, I make it work with a workaround:

import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpPatch;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;

private static void patchRequest(String request) throws IOException {
try {
  String urlStr = "http://192.168.1.45:8080/api/v1/nodes/k8s-n1/status";
  String requestContents = "[{\"op\": \"" + request + "\", \"path\": \"/status/capacity/example.com~1dongle\", \"value\": \"2\"}]";

  CloseableHttpClient httpclient = HttpClients.createDefault();
  HttpPatch newPatch = new HttpPatch(urlStr);
  newPatch.setEntity(new StringEntity(requestContents, ContentType.parse("application/json-patch+json")));
  HttpResponse response = httpclient.execute(newPatch);

  logger.info(response.toString());
  String resultBody = EntityUtils.toString(response.getEntity());
  EntityUtils.consume(response.getEntity());
  logger.info("Response Code : " + response.getStatusLine().getStatusCode());
  logger.info(resultBody);
  httpclient.close();
} catch (IOException e) {
  logger.error("patchRequest exception:", e);
  throw e;
}
}

public static void main(String[] args) {
  // ...
  try {
      logger.info("add the extended resource");
      patchRequest("add");
      // ...
      log("get node status: \n", client.nodes().withName(podNameWithExtRes).get().getStatus().toString());
      // ...
      logger.info("remove the extended resource");
      patchRequest("remove");
  } catch (IOException e) {
    logger.error(e.getMessage(), e);
  }
  // ...
}

Now, logs of "get node status":

capacity={cpu=Quantity(amount=4, format=null, additionalProperties={}), example.com/dongle=Quantity(amount=1, format=null, additionalProperties={}), ... pods=Quantity(amount=110, format=null, additionalProperties={})},
-- Michael Wang
Source: StackOverflow