Initial support for multi kubernetes clusters for k8s nodes
Change-Id: I6ca132898f8e157e0583de38a637fdc135f21d6f
(cherry picked from commit e2a04cedde73618ef24575e70cb221e03854de1d)
diff --git a/apps/k8s-node/app/src/main/java/org/onosproject/k8snode/web/K8sNodeCodecRegister.java b/apps/k8s-node/app/src/main/java/org/onosproject/k8snode/web/K8sNodeCodecRegister.java
index 9138539..4bca46e 100644
--- a/apps/k8s-node/app/src/main/java/org/onosproject/k8snode/web/K8sNodeCodecRegister.java
+++ b/apps/k8s-node/app/src/main/java/org/onosproject/k8snode/web/K8sNodeCodecRegister.java
@@ -16,9 +16,13 @@
package org.onosproject.k8snode.web;
import org.onosproject.codec.CodecService;
+import org.onosproject.k8snode.api.HostNodesInfo;
import org.onosproject.k8snode.api.K8sApiConfig;
+import org.onosproject.k8snode.api.K8sHost;
import org.onosproject.k8snode.api.K8sNode;
+import org.onosproject.k8snode.codec.HostNodesInfoCodec;
import org.onosproject.k8snode.codec.K8sApiConfigCodec;
+import org.onosproject.k8snode.codec.K8sHostCodec;
import org.onosproject.k8snode.codec.K8sNodeCodec;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
@@ -45,6 +49,8 @@
codecService.registerCodec(K8sNode.class, new K8sNodeCodec());
codecService.registerCodec(K8sApiConfig.class, new K8sApiConfigCodec());
+ codecService.registerCodec(HostNodesInfo.class, new HostNodesInfoCodec());
+ codecService.registerCodec(K8sHost.class, new K8sHostCodec());
log.info("Started");
}
@@ -54,6 +60,8 @@
codecService.unregisterCodec(K8sNode.class);
codecService.unregisterCodec(K8sApiConfig.class);
+ codecService.unregisterCodec(HostNodesInfo.class);
+ codecService.unregisterCodec(K8sHost.class);
log.info("Stopped");
}
diff --git a/apps/k8s-node/app/src/main/java/org/onosproject/k8snode/web/K8sNodeWebResource.java b/apps/k8s-node/app/src/main/java/org/onosproject/k8snode/web/K8sNodeWebResource.java
index df4f63f..1b20fd4 100644
--- a/apps/k8s-node/app/src/main/java/org/onosproject/k8snode/web/K8sNodeWebResource.java
+++ b/apps/k8s-node/app/src/main/java/org/onosproject/k8snode/web/K8sNodeWebResource.java
@@ -19,8 +19,11 @@
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.google.common.collect.Sets;
+import org.onlab.packet.IpAddress;
import org.onosproject.k8snode.api.K8sApiConfig;
import org.onosproject.k8snode.api.K8sApiConfigAdminService;
+import org.onosproject.k8snode.api.K8sHost;
+import org.onosproject.k8snode.api.K8sHostAdminService;
import org.onosproject.k8snode.api.K8sNode;
import org.onosproject.k8snode.api.K8sNodeAdminService;
import org.onosproject.k8snode.api.K8sNodeState;
@@ -42,6 +45,7 @@
import javax.ws.rs.core.UriBuilder;
import javax.ws.rs.core.UriInfo;
import java.io.InputStream;
+import java.util.HashSet;
import java.util.Set;
import static com.fasterxml.jackson.databind.SerializationFeature.INDENT_OUTPUT;
@@ -61,11 +65,15 @@
private final Logger log = LoggerFactory.getLogger(getClass());
private static final String MESSAGE_NODE = "Received node %s request";
+ private static final String MESSAGE_HOST = "Received host %s request";
private static final String NODES = "nodes";
private static final String API_CONFIGS = "apiConfigs";
+ private static final String HOSTS = "hosts";
+ private static final String NODE_NAMES = "nodeNames";
private static final String CREATE = "CREATE";
private static final String UPDATE = "UPDATE";
private static final String NODE_ID = "NODE_ID";
+ private static final String HOST_IP = "HOST_IP";
private static final String REMOVE = "REMOVE";
private static final String QUERY = "QUERY";
private static final String INIT = "INIT";
@@ -78,6 +86,7 @@
private static final String ERROR_MESSAGE = " cannot be null";
private final K8sNodeAdminService nodeAdminService = get(K8sNodeAdminService.class);
+ private final K8sHostAdminService hostAdminService = get(K8sHostAdminService.class);
private final K8sApiConfigAdminService configAdminService = get(K8sApiConfigAdminService.class);
@Context
@@ -155,8 +164,8 @@
public Response deleteNodes(@PathParam("hostname") String hostname) {
log.trace(String.format(MESSAGE_NODE, REMOVE));
- K8sNode existing =
- nodeAdminService.node(nullIsIllegal(hostname, HOST_NAME + ERROR_MESSAGE));
+ K8sNode existing = nodeAdminService.node(
+ nullIsIllegal(hostname, HOST_NAME + ERROR_MESSAGE));
if (existing == null) {
log.warn("There is no node configuration to delete : {}", hostname);
@@ -293,30 +302,6 @@
return ok(mapper().createObjectNode().put(RESULT, result)).build();
}
- private Set<K8sNode> readNodeConfiguration(InputStream input) {
- Set<K8sNode> nodeSet = Sets.newHashSet();
- try {
- JsonNode jsonTree = readTreeFromStream(mapper().enable(INDENT_OUTPUT), input);
- ArrayNode nodes = (ArrayNode) jsonTree.path(NODES);
- nodes.forEach(node -> {
- try {
- ObjectNode objectNode = node.deepCopy();
- K8sNode k8sNode =
- codec(K8sNode.class).decode(objectNode, this);
-
- nodeSet.add(k8sNode);
- } catch (Exception e) {
- log.error("Exception occurred due to {}", e);
- throw new IllegalArgumentException();
- }
- });
- } catch (Exception e) {
- throw new IllegalArgumentException(e);
- }
-
- return nodeSet;
- }
-
/**
* Creates a set of kubernetes API config from the JSON input stream.
*
@@ -387,8 +372,8 @@
public Response deleteApiConfig(@PathParam("endpoint") String endpoint) {
log.trace(String.format(MESSAGE_NODE, REMOVE));
- K8sApiConfig existing =
- configAdminService.apiConfig(nullIsIllegal(endpoint, ENDPOINT + ERROR_MESSAGE));
+ K8sApiConfig existing = configAdminService.apiConfig(
+ nullIsIllegal(endpoint, ENDPOINT + ERROR_MESSAGE));
if (existing == null) {
log.warn("There is no API configuration to delete : {}", endpoint);
@@ -400,6 +385,139 @@
return Response.noContent().build();
}
+ /**
+ * Creates a set of kubernetes hosts' config from the JSON input stream.
+ *
+ * @param input kubernetes hosts JSON input stream
+ * @return 201 CREATED if the JSON is correct, 400 BAD_REQUEST if the JSON
+ * is malformed
+ * @onos.rsModel K8sHosts
+ */
+ @POST
+ @Path("host")
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ public Response createHosts(InputStream input) {
+ log.trace(String.format(MESSAGE_NODE, CREATE));
+
+ readHostsConfiguration(input).forEach(host -> {
+ K8sHost existing = hostAdminService.host(host.hostIp());
+ if (existing == null) {
+ hostAdminService.createHost(host);
+ }
+ });
+
+ UriBuilder locationBuilder = uriInfo.getBaseUriBuilder()
+ .path(HOSTS)
+ .path(HOST_IP);
+
+ return created(locationBuilder.build()).build();
+ }
+
+ /**
+ * Add a set of new nodes into the existing host.
+ *
+ * @param hostIp host IP address
+ * @param input kubernetes node names JSON input stream
+ * @return 200 UPDATED if the JSON is correct, 400 BAD_REQUEST if the JSON
+ * is malformed
+ * @onos.rsModel K8sNodeNames
+ */
+ @PUT
+ @Path("host/add/nodes/{hostIp}")
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ public Response addNodesToHost(@PathParam("hostIp") String hostIp,
+ InputStream input) {
+ log.trace(String.format(MESSAGE_HOST, UPDATE));
+
+ Set<String> newNodeNames = readNodeNamesConfiguration(input);
+ K8sHost host = hostAdminService.host(IpAddress.valueOf(hostIp));
+ Set<String> existNodeNames = host.nodeNames();
+ existNodeNames.addAll(newNodeNames);
+ K8sHost updated = host.updateNodeNames(existNodeNames);
+ hostAdminService.updateHost(updated);
+ return Response.ok().build();
+ }
+
+ /**
+ * Remove a set of new nodes from the existing host.
+ *
+ * @param hostIp host IP address
+ * @param input kubernetes node names JSON input stream
+ * @return 200 UPDATED if the JSON is correct, 400 BAD_REQUEST if the JSON
+ * is malformed
+ * @onos.rsModel K8sNodeNames
+ */
+ @PUT
+ @Path("host/delete/nodes/{hostIp}")
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ public Response removeNodesFromHost(@PathParam("hostIp") String hostIp,
+ InputStream input) {
+ log.trace(String.format(MESSAGE_HOST, UPDATE));
+
+ Set<String> newNodeNames = readNodeNamesConfiguration(input);
+ K8sHost host = hostAdminService.host(IpAddress.valueOf(hostIp));
+ Set<String> existNodeNames = host.nodeNames();
+ existNodeNames.removeAll(newNodeNames);
+ K8sHost updated = host.updateNodeNames(existNodeNames);
+ hostAdminService.updateHost(updated);
+ return Response.ok().build();
+ }
+
+ /**
+ * Removes a kubernetes host' config.
+ *
+ * @param hostIp host IP contained in kubernetes nodes configuration
+ * @return 204 NO_CONTENT, 400 BAD_REQUEST if the JSON is malformed, and
+ * 304 NOT_MODIFIED without the updated config
+ */
+ @DELETE
+ @Path("host/{hostIp}")
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ public Response deleteHost(@PathParam("hostIp") String hostIp) {
+ log.trace(String.format(MESSAGE_HOST, REMOVE));
+
+ K8sHost existing = hostAdminService.host(IpAddress.valueOf(
+ nullIsIllegal(hostIp, HOST_IP + ERROR_MESSAGE)));
+
+ if (existing == null) {
+ log.warn("There is no host configuration to delete : {}", hostIp);
+ return Response.notModified().build();
+ } else {
+ hostAdminService.removeHost(IpAddress.valueOf(
+ nullIsIllegal(hostIp, HOST_IP + ERROR_MESSAGE)));
+ }
+
+ return Response.noContent().build();
+ }
+
+ private Set<K8sNode> readNodeConfiguration(InputStream input) {
+ Set<K8sNode> nodeSet = Sets.newHashSet();
+ try {
+ JsonNode jsonTree = readTreeFromStream(mapper().enable(INDENT_OUTPUT), input);
+ ArrayNode nodes = (ArrayNode) jsonTree.path(NODES);
+ nodes.forEach(node -> {
+ try {
+ ObjectNode objectNode = node.deepCopy();
+ K8sNode k8sNode =
+ codec(K8sNode.class).decode(objectNode, this);
+
+ nodeSet.add(k8sNode);
+ } catch (Exception e) {
+ log.error("Exception occurred due to {}", e);
+ throw new IllegalArgumentException();
+ }
+ });
+ } catch (Exception e) {
+ throw new IllegalArgumentException(e);
+ }
+
+ return nodeSet;
+ }
+
private Set<K8sApiConfig> readApiConfigConfiguration(InputStream input) {
Set<K8sApiConfig> configSet = Sets.newHashSet();
try {
@@ -423,4 +541,49 @@
return configSet;
}
+
+ private Set<K8sHost> readHostsConfiguration(InputStream input) {
+ Set<K8sHost> hostSet = new HashSet<>();
+ try {
+ JsonNode jsonTree = readTreeFromStream(mapper().enable(INDENT_OUTPUT), input);
+ ArrayNode hosts = (ArrayNode) jsonTree.path(HOSTS);
+ hosts.forEach(host -> {
+ try {
+ ObjectNode objectNode = host.deepCopy();
+ K8sHost k8sHost =
+ codec(K8sHost.class).decode(objectNode, this);
+
+ hostSet.add(k8sHost);
+ } catch (Exception e) {
+ log.error("Exception occurred due to {}", e);
+ throw new IllegalArgumentException();
+ }
+ });
+ } catch (Exception e) {
+ throw new IllegalArgumentException(e);
+ }
+
+ return hostSet;
+ }
+
+ private Set<String> readNodeNamesConfiguration(InputStream input) {
+ Set<String> nodeNames = new HashSet<>();
+ try {
+ JsonNode jsonTree = readTreeFromStream(mapper().enable(INDENT_OUTPUT), input);
+ ArrayNode names = (ArrayNode) jsonTree.path(NODE_NAMES);
+ names.forEach(name -> {
+ try {
+ ObjectNode objectNode = name.deepCopy();
+ nodeNames.add(objectNode.asText());
+ } catch (Exception e) {
+ log.error("Exception occurred due to {}", e);
+ throw new IllegalArgumentException();
+ }
+ });
+ } catch (Exception e) {
+ throw new IllegalArgumentException(e);
+ }
+
+ return nodeNames;
+ }
}