Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
io.fabric8.jube.apimaster.ApiMasterService Maven / Gradle / Ivy
/**
* Copyright 2005-2014 Red Hat, Inc.
*
* Red Hat licenses this file to you 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.jube.apimaster;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import javax.inject.Inject;
import javax.inject.Singleton;
import javax.validation.constraints.NotNull;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import io.fabric8.jube.ServiceIDs;
import io.fabric8.jube.Statuses;
import io.fabric8.jube.local.NodeHelper;
import io.fabric8.jube.local.ProcessMonitor;
import io.fabric8.jube.model.HostNode;
import io.fabric8.jube.model.HostNodeModel;
import io.fabric8.jube.process.Installation;
import io.fabric8.jube.process.ProcessManager;
import io.fabric8.jube.proxy.KubeProxy;
import io.fabric8.jube.replicator.Replicator;
import io.fabric8.kubernetes.api.KubernetesHelper;
import io.fabric8.kubernetes.api.model.Endpoints;
import io.fabric8.kubernetes.api.model.EndpointsList;
import io.fabric8.kubernetes.api.model.Minion;
import io.fabric8.kubernetes.api.model.MinionList;
import io.fabric8.kubernetes.api.model.PodState;
import io.fabric8.kubernetes.api.model.Container;
import io.fabric8.kubernetes.api.model.PodList;
import io.fabric8.kubernetes.api.model.Pod;
import io.fabric8.kubernetes.api.model.ReplicationControllerList;
import io.fabric8.kubernetes.api.model.ReplicationController;
import io.fabric8.kubernetes.api.model.ServiceList;
import io.fabric8.kubernetes.api.model.Service;
import io.fabric8.kubernetes.api.model.util.IntOrString;
import io.fabric8.utils.Objects;
import io.hawt.util.Strings;
import org.apache.deltaspike.core.api.config.ConfigProperty;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static io.fabric8.jube.local.NodeHelper.getOrCreateCurrentState;
import static io.fabric8.utils.Lists.notNullList;
/**
* Implements the local node controller
*/
@Singleton
@Path("v1beta2")
@Produces("application/json")
@Consumes("application/json")
public class ApiMasterService implements KubernetesExtensions {
public static final String DEFAULT_HOSTNAME = "localhost";
public static final String DEFAULT_HTTP_PORT = "8585";
public static final String DEFAULT_NAMESPACE = "default";
public static String hostName = DEFAULT_HOSTNAME;
public static String port = DEFAULT_HTTP_PORT;
private static final transient Logger LOG = LoggerFactory.getLogger(ApiMasterService.class);
private final ProcessManager processManager;
private final ApiMasterKubernetesModel model;
private final Replicator replicator;
private final ProcessMonitor processMonitor;
private final KubeProxy kubeProxy;
private final HostNodeModel hostNodeModel;
private final ExecutorService localCreateThreadPool = Executors.newFixedThreadPool(10);
private String namespace = "default";
@Inject
public ApiMasterService(ProcessManager processManager, ApiMasterKubernetesModel model, Replicator replicator, ProcessMonitor processMonitor, KubeProxy kubeProxy, HostNodeModel hostNodeModel,
@ConfigProperty(name = "JUBE_HOSTNAME", defaultValue = DEFAULT_HOSTNAME)
String hostName,
@ConfigProperty(name = "HTTP_PORT", defaultValue = DEFAULT_HTTP_PORT)
String port) {
this.processManager = processManager;
this.model = model;
this.replicator = replicator;
this.processMonitor = processMonitor;
this.kubeProxy = kubeProxy;
this.hostNodeModel = hostNodeModel;
ApiMasterService.hostName = hostName;
ApiMasterService.port = port;
HostNode node = new HostNode();
node.setHostName(hostName);
node.setWebUrl("http://" + hostName + ":" + port + "/");
node.setId(UUID.randomUUID().toString());
hostNodeModel.write(node);
ensureModelHasKubernetesServices(hostName, port);
}
public static String getHostName() {
return hostName;
}
public static String getPort() {
return port;
}
public String getNamespace() {
return namespace;
}
public void setNamespace(String namespace) {
this.namespace = namespace;
}
// Pods
//-------------------------------------------------------------------------
public PodList getPods() {
return model.getPods();
}
public Pod getPod(@NotNull String podId) {
Map map = model.getPodMap();
return map.get(podId);
}
@Override
public Pod getPod(@NotNull String podId, String namespace) {
return model.getPod(podId, namespace);
}
@Override
public PodList getPods(String namespace) {
return model.getPods(namespace);
}
public String createPod(Pod entity) throws Exception {
return model.remoteCreatePod(entity);
}
@Override
public String createPod(Pod pod, String namespace) throws Exception {
pod.setNamespace(namespace);
return createPod(pod);
}
public String updatePod(final @NotNull String podId, final Pod pod) throws Exception {
// TODO needs implementing remotely!
return NodeHelper.excludeFromProcessMonitor(processMonitor, pod, new Callable() {
@Override
public String call() throws Exception {
System.out.println("Updating pod " + pod);
PodState desiredState = pod.getDesiredState();
Objects.notNull(desiredState, "desiredState");
PodState currentState = getOrCreateCurrentState(pod);
List containers = KubernetesHelper.getContainers(pod);
model.updatePod(podId, pod);
return NodeHelper.createMissingContainers(processManager, model, pod, currentState, containers);
}
});
}
public String deletePod(@NotNull String podId) throws Exception {
model.deletePod(podId, namespace);
return null;
}
@Override
public String deletePod(@NotNull String podId, String namespace) throws Exception {
model.deletePod(podId, namespace);
return null;
}
@Override
public String updatePod(@NotNull String podId, Pod pod, String namespace) throws Exception {
pod.setNamespace(namespace);
return updatePod(podId, pod);
}
@Override
public ServiceList getServices(String namespace) {
return model.getServices(namespace);
}
@Override
public Service getService(@NotNull String serviceId, String namespace) {
return model.getService(serviceId, namespace);
}
@Override
public String updateService(@NotNull String serviceId, Service service, String namespace) throws Exception {
service.setNamespace(namespace);
return updateService(serviceId, service);
}
// Replication Controllers
//-------------------------------------------------------------------------
public ReplicationControllerList getReplicationControllers() {
return model.getReplicationControllers();
}
public ReplicationController getReplicationController(@NotNull String controllerId) {
Map map = KubernetesHelper.getReplicationControllerMap(this);
return map.get(controllerId);
}
@Override
public ReplicationControllerList getReplicationControllers(String namespace) {
return model.getReplicationControllers(namespace);
}
@Override
public ReplicationController getReplicationController(@NotNull String replicationControllerId, String namespace) {
return model.getReplicationController(replicationControllerId, namespace);
}
public String createReplicationController(ReplicationController entity) throws Exception {
String id = model.getOrCreateId(entity.getId(), NodeHelper.KIND_REPLICATION_CONTROLLER);
entity.setId(id);
return updateReplicationController(id, entity);
}
@Override
public String createReplicationController(ReplicationController replicationController, String namespace) throws Exception {
replicationController.setNamespace(namespace);
return createReplicationController(replicationController);
}
@Override
public String updateReplicationController(@PathParam("controllerId") @NotNull String s, ReplicationController replicationController, @QueryParam("namespace") String s1) throws Exception {
replicationController.setNamespace(namespace);
return updateReplicationController(s, replicationController);
}
public String updateReplicationController(@NotNull String controllerId, ReplicationController replicationController) throws Exception {
// lets ensure there's a default namespace set
String namespace = replicationController.getNamespace();
if (Strings.isBlank(namespace)) {
replicationController.setNamespace(DEFAULT_NAMESPACE);
}
model.updateReplicationController(controllerId, replicationController);
return null;
}
public String deleteReplicationController(@NotNull String controllerId) throws Exception {
model.deleteReplicationController(controllerId, namespace);
return null;
}
@Override
public String deleteReplicationController(@NotNull String controllerId, String namespace) throws Exception {
model.deleteReplicationController(controllerId, namespace);
return null;
}
@Override
public EndpointsList getEndpoints(@QueryParam("namespace") String namespace) {
EndpointsList answer = new EndpointsList();
List list = new ArrayList<>();
answer.setItems(list);
ServiceList services = getServices(namespace);
if (services != null) {
List pods = getPods(namespace).getItems();
List items = notNullList(services.getItems());
for (Service service : items) {
Endpoints endpoints = createEndpointsForService(service, pods);
if (endpoints != null) {
list.add(endpoints);
}
}
}
return answer;
}
// Services
//-------------------------------------------------------------------------
public ServiceList getServices() {
return model.getServices();
}
public Service getService(@NotNull String serviceId) {
Map map = model.getServiceMap();
return map.get(serviceId);
}
public String createService(Service entity) throws Exception {
String id = model.getOrCreateId(entity.getId(), NodeHelper.KIND_SERVICE);
entity.setId(id);
return updateService(id, entity);
}
@Override
public String createService(Service service, String namespace) throws Exception {
service.setNamespace(namespace);
return createService(service);
}
public String updateService(@NotNull String id, Service entity) throws Exception {
// lets set the IP
entity.setPortalIP(getHostName());
// lets ensure there's a default namespace set
String namespace = entity.getNamespace();
if (Strings.isBlank(namespace)) {
entity.setNamespace(DEFAULT_NAMESPACE);
}
model.updateService(id, entity);
return null;
}
public String deleteService(@NotNull String serviceId) throws Exception {
model.deleteService(serviceId, namespace);
return null;
}
@Override
public String deleteService(@NotNull String serviceId, String namespace) throws Exception {
model.deleteService(serviceId, namespace);
return null;
}
@Override
public Endpoints endpointsForService(@NotNull String serviceId, String namespace) {
List pods = podList();
Service service = getService(serviceId);
return createEndpointsForService(service, pods);
}
protected List podList() {
PodList podList = getPods();
return notNullList(podList.getItems());
}
protected static Endpoints createEndpointsForService(Service service, List pods) {
if (service == null) {
return null;
}
Endpoints answer = new Endpoints();
answer.setId(service.getId());
List urls = new ArrayList<>();
answer.setEndpoints(urls);
IntOrString containerPort = service.getContainerPort();
if (containerPort != null) {
String strVal = containerPort.getStrVal();
if (strVal == null) {
Integer intVal = containerPort.getIntVal();
if (intVal != null) {
strVal = intVal.toString();
}
}
if (strVal != null) {
String containerPortText = ":" + strVal;
List podsForService = KubernetesHelper.getPodsForService(service, pods);
for (Pod pod : podsForService) {
PodState currentState = pod.getCurrentState();
if (currentState != null) {
String podIP = currentState.getPodIP();
if (podIP != null) {
String url = podIP + containerPortText;
}
}
}
}
}
return answer;
}
public EndpointsList getEndpoints() {
EndpointsList answer = new EndpointsList();
List list = new ArrayList<>();
answer.setItems(list);
ServiceList services = getServices();
if (services != null) {
List pods = podList();
List items = notNullList(services.getItems());
for (Service service : items) {
Endpoints endpoints = createEndpointsForService(service, pods);
if (endpoints != null) {
list.add(endpoints);
}
}
}
return answer;
}
@Override
public MinionList getMinions() {
// TODO we should replace HostNode with Minion...
MinionList answer = new MinionList();
List items = new ArrayList<>();
answer.setItems(items);
Collection values = getHostNodes().values();
for (HostNode value : values) {
Minion minion = new Minion();
minion.setId(value.getId());
minion.setHostIP(value.getHostName());
items.add(minion);
}
return answer;
}
@Override
public Minion minion(@NotNull String name) {
MinionList minionList = getMinions();
List minions = notNullList(minionList.getItems());
for (Minion minion : minions) {
if (Objects.equal(minion.getId(), name)) {
return minion;
}
}
return null;
}
// Host nodes
//-------------------------------------------------------------------------
@GET
@Path("hostNodes")
@Produces("application/json")
public Map getHostNodes() {
return hostNodeModel.getMap();
}
@GET
@Path("hostNodes/{id}")
@Produces("application/json")
public HostNode getHostNode(@PathParam("id") @NotNull String id) {
return hostNodeModel.getEntity(id);
}
// Local operations
//-------------------------------------------------------------------------
@POST
@Path("local/pods")
@Consumes("application/json")
@Override
public String createLocalPod(Pod entity) throws Exception {
String id = model.getOrCreateId(entity.getId(), NodeHelper.KIND_REPLICATION_CONTROLLER);
entity.setId(id);
return updateLocalPod(id, entity);
}
public String updateLocalPod(@NotNull final String podId, final Pod pod) throws Exception {
System.out.println("Updating pod " + pod);
PodState desiredState = pod.getDesiredState();
Objects.notNull(desiredState, "desiredState");
// lets ensure there's a default namespace set
String namespace = pod.getNamespace();
if (Strings.isBlank(namespace)) {
pod.setNamespace(DEFAULT_NAMESPACE);
}
final PodState currentState = getOrCreateCurrentState(pod);
final List containers = KubernetesHelper.getContainers(pod);
NodeHelper.setPodStatus(pod, Statuses.WAITING);
NodeHelper.setContainerRunningState(pod, podId, false);
model.updatePod(podId, pod);
localCreateThreadPool.submit(new Runnable() {
@Override
public void run() {
Runnable task = new Runnable() {
@Override
public void run() {
try {
NodeHelper.createMissingContainers(processManager, model, pod, currentState, containers);
} catch (Exception e) {
LOG.error("Failed to create container " + podId + ". " + e, e);
}
}
};
NodeHelper.excludeFromProcessMonitor(processMonitor, pod, task);
}
});
return pod.getId();
}
@DELETE
@Path("local/pods/{id}")
@Consumes("text/plain")
@Override
public String deleteLocalPod(@PathParam("id") @NotNull String id, @QueryParam("namespace") String namespace) throws Exception {
NodeHelper.deletePod(processManager, model, id, namespace);
return null;
}
@GET
@Path("local/pods")
@Consumes("application/json")
@Override
public PodList getLocalPods() {
ImmutableMap installMap = processManager.listInstallationMap();
ImmutableSet keys = installMap.keySet();
List pods = new ArrayList<>();
for (String key : keys) {
Pod pod = model.getPod(key);
if (pod != null) {
pods.add(pod);
}
}
PodList answer = new PodList();
answer.setItems(pods);
return answer;
}
/**
* Lets ensure that the "kubernetes" and "kubernetes-ro" services are defined so that folks can access the core
* REST API via kubernetes services
*/
protected void ensureModelHasKubernetesServices(String hostName, String port) {
ImmutableMap serviceMap = model.getServiceMap();
Service service = null;
try {
service = serviceMap.get(ServiceIDs.KUBERNETES_SERVICE_ID);
if (service == null) {
service = createService(hostName, port);
service.setId(ServiceIDs.KUBERNETES_SERVICE_ID);
service.setSelector(createKubernetesServiceLabels());
createService(service);
}
service = serviceMap.get(ServiceIDs.KUBERNETES_RO_SERVICE_ID);
if (service == null) {
service = createService(hostName, port);
service.setId(ServiceIDs.KUBERNETES_RO_SERVICE_ID);
service.setSelector(createKubernetesServiceLabels());
createService(service);
}
service = serviceMap.get(ServiceIDs.FABRIC8_CONSOLE_SERVICE_ID);
if (service == null) {
service = createService(hostName, port);
service.setId(ServiceIDs.FABRIC8_CONSOLE_SERVICE_ID);
service.setSelector(createFabric8ConsoleServiceLabels());
createService(service);
}
} catch (Exception e) {
LOG.error("Failed to create service " + service + ". " + e, e);
}
}
protected Map createFabric8ConsoleServiceLabels() {
Map answer = new HashMap<>();
answer.put("component", "fabric8Console");
return answer;
}
protected Map createKubernetesServiceLabels() {
Map answer = new HashMap<>();
answer.put("component", "apiserver");
answer.put("provider", "kubernetes");
return answer;
}
protected Service createService(String hostName, String port) {
Service service = new Service();
service.setKind("Service");
try {
Integer portNumber = Integer.parseInt(port);
if (portNumber != null) {
service.setPort(portNumber);
IntOrString containerPort = new IntOrString();
containerPort.setIntVal(portNumber);
service.setContainerPort(containerPort);
}
} catch (NumberFormatException e) {
LOG.warn("Failed to parse port text: " + port + ". " + e, e);
}
service.setPortalIP(hostName);
return service;
}
}