blob: 22f32321ff754afeba12d0a322f815f6a271a300 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF 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 org.apache.stratos.cloud.controller.services.impl;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.stratos.cloud.controller.config.CloudControllerConfig;
import org.apache.stratos.cloud.controller.context.CloudControllerContext;
import org.apache.stratos.cloud.controller.domain.*;
import org.apache.stratos.cloud.controller.domain.kubernetes.KubernetesCluster;
import org.apache.stratos.cloud.controller.domain.kubernetes.KubernetesClusterContext;
import org.apache.stratos.cloud.controller.domain.kubernetes.KubernetesHost;
import org.apache.stratos.cloud.controller.domain.kubernetes.KubernetesMaster;
import org.apache.stratos.cloud.controller.exception.*;
import org.apache.stratos.cloud.controller.iaases.Iaas;
import org.apache.stratos.cloud.controller.messaging.topology.TopologyBuilder;
import org.apache.stratos.cloud.controller.messaging.topology.TopologyHolder;
import org.apache.stratos.cloud.controller.services.CloudControllerService;
import org.apache.stratos.cloud.controller.util.CloudControllerConstants;
import org.apache.stratos.cloud.controller.util.CloudControllerUtil;
import org.apache.stratos.common.Property;
import org.apache.stratos.common.domain.LoadBalancingIPType;
import org.apache.stratos.common.threading.StratosThreadPool;
import org.apache.stratos.messaging.domain.topology.*;
import org.wso2.carbon.registry.core.exceptions.RegistryException;
import java.util.*;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.locks.Lock;
/**
* Cloud Controller Service is responsible for starting up new server instances,
* terminating already started instances, providing pending instance count etc.
*/
public class CloudControllerServiceImpl implements CloudControllerService {
private static final Log log = LogFactory.getLog(CloudControllerServiceImpl.class);
private static final String PERSISTENCE_MAPPING = "PERSISTENCE_MAPPING";
public static final String PAYLOAD_PARAMETER = "payload_parameter.";
public static final String KUBERNETES_PROVIDER = "kubernetes";
public static final String KUBERNETES_CLUSTER = "cluster";
private CloudControllerContext cloudControllerContext = CloudControllerContext.getInstance();
private ExecutorService executorService;
public CloudControllerServiceImpl() {
executorService = StratosThreadPool.getExecutorService("cloud.controller.instance.manager.thread.pool", 50);
}
public boolean addCartridge(Cartridge cartridgeConfig)
throws InvalidCartridgeDefinitionException, InvalidIaasProviderException, CartridgeAlreadyExistsException {
handleNullObject(cartridgeConfig, "Cartridge definition is null");
if (log.isInfoEnabled()) {
log.info("Adding cartridge: [cartridge-type] " + cartridgeConfig.getType());
}
if (log.isDebugEnabled()) {
log.debug("Cartridge definition: " + cartridgeConfig.toString());
}
try {
CloudControllerUtil.extractIaaSProvidersFromCartridge(cartridgeConfig);
} catch (Exception e) {
String message = "Invalid cartridge definition: [cartridge-type] " + cartridgeConfig.getType();
log.error(message, e);
throw new InvalidCartridgeDefinitionException(message, e);
}
String cartridgeType = cartridgeConfig.getType();
if (cloudControllerContext.getCartridge(cartridgeType) != null) {
String message = "Cartridge already exists: [cartridge-type] " + cartridgeType;
log.error(message);
throw new CartridgeAlreadyExistsException(message);
}
try {
// Add cartridge to the cloud controller context and persist
CloudControllerContext.getInstance().addCartridge(cartridgeConfig);
CloudControllerContext.getInstance().persist();
List<Cartridge> cartridgeList = new ArrayList<>();
cartridgeList.add(cartridgeConfig);
TopologyBuilder.handleServiceCreated(cartridgeList);
} catch (RegistryException e) {
log.error("Could not persist data in registry data store", e);
return false;
}
if (log.isInfoEnabled()) {
log.info("Successfully added cartridge: [cartridge-type] " + cartridgeType);
}
return true;
}
@Override
public boolean updateCartridge(Cartridge cartridge)
throws InvalidCartridgeDefinitionException, InvalidIaasProviderException,
CartridgeDefinitionNotExistsException {
handleNullObject(cartridge, "Cartridge definition is null");
if (log.isInfoEnabled()) {
log.info("Updating cartridge: [cartridge-type] " + cartridge.getType());
}
if (log.isDebugEnabled()) {
log.debug("Cartridge definition: " + cartridge.toString());
}
try {
CloudControllerUtil.extractIaaSProvidersFromCartridge(cartridge);
} catch (Exception e) {
String msg = "Invalid cartridge definition: [cartridge-type] " + cartridge.getType();
log.error(msg, e);
throw new InvalidCartridgeDefinitionException(msg, e);
}
String cartridgeType = cartridge.getType();
if (cloudControllerContext.getCartridge(cartridgeType) != null) {
Cartridge cartridgeToBeRemoved = cloudControllerContext.getCartridge(cartridgeType);
try {
removeCartridgeFromCC(cartridgeToBeRemoved.getType());
} catch (InvalidCartridgeTypeException ignore) {
}
copyIaasProviders(cartridge, cartridgeToBeRemoved);
} else {
throw new CartridgeDefinitionNotExistsException("This cartridge definition not exists");
}
try {
// Add cartridge to the cloud controller context and persist
CloudControllerContext.getInstance().addCartridge(cartridge);
CloudControllerContext.getInstance().persist();
// transaction ends
if (log.isInfoEnabled()) {
log.info("Successfully updated cartridge: [cartridge-type] " + cartridgeType);
}
return true;
} catch (Exception e) {
log.error("Failed to update cartridge [cartridge-type] " + cartridgeType, e);
return false;
}
}
private void copyIaasProviders(Cartridge destCartridge, Cartridge sourceCartridge) {
List<IaasProvider> newIaasProviders = CloudControllerContext.getInstance()
.getIaasProviders(destCartridge.getType());
Map<String, IaasProvider> iaasProviderMap = CloudControllerContext.getInstance()
.getPartitionToIaasProvider(sourceCartridge.getType());
if (iaasProviderMap != null) {
for (Entry<String, IaasProvider> entry : iaasProviderMap.entrySet()) {
if (entry == null) {
continue;
}
String partitionId = entry.getKey();
IaasProvider iaasProvider = entry.getValue();
if (newIaasProviders.contains(iaasProvider)) {
if (log.isDebugEnabled()) {
log.debug("Copying partition from the cartridge that is undeployed, to the new cartridge: "
+ "[partition-id] " + partitionId + " [cartridge-type] " + destCartridge.getType());
}
CloudControllerContext.getInstance().addIaasProvider(destCartridge.getType(), partitionId,
newIaasProviders.get(newIaasProviders.indexOf(iaasProvider)));
}
}
}
}
public boolean removeCartridge(String cartridgeType) throws InvalidCartridgeTypeException {
//Removing the cartridge from CC
Cartridge cartridge = removeCartridgeFromCC(cartridgeType);
//removing the cartridge from Topology
// sends the service removed event
List<Cartridge> cartridgeList = new ArrayList<>();
cartridgeList.add(cartridge);
try {
TopologyBuilder.handleServiceRemoved(cartridgeList);
} catch (RegistryException e) {
log.error("Could not persist data in registry data store", e);
return false;
}
if (log.isInfoEnabled()) {
log.info("Successfully removed cartridge: [cartridge-type] " + cartridgeType);
}
return true;
}
private Cartridge removeCartridgeFromCC(String cartridgeType) throws InvalidCartridgeTypeException {
Cartridge cartridge;
if ((cartridge = CloudControllerContext.getInstance().getCartridge(cartridgeType)) != null) {
if (CloudControllerContext.getInstance().getCartridges().remove(cartridge)) {
// invalidate partition validation cache
CloudControllerContext.getInstance().removeFromCartridgeTypeToPartitionIds(cartridgeType);
if (log.isDebugEnabled()) {
log.debug("Partition cache invalidated for cartridge " + cartridgeType);
}
try {
CloudControllerContext.getInstance().persist();
} catch (RegistryException e) {
log.error("Could not remove cartridge " + cartridgeType, e);
return null;
}
if (log.isInfoEnabled()) {
log.info("Successfully removed cartridge: [cartridge-type] " + cartridgeType);
}
return cartridge;
}
}
String msg = "Cartridge not found: [cartridge-type] " + cartridgeType;
log.error(msg);
throw new InvalidCartridgeTypeException(msg);
}
public boolean addServiceGroup(ServiceGroup servicegroup) throws InvalidServiceGroupException {
if (servicegroup == null) {
String msg = "Invalid ServiceGroup Definition: Definition is null.";
log.error(msg);
throw new IllegalArgumentException(msg);
}
CloudControllerContext.getInstance().addServiceGroup(servicegroup);
try {
CloudControllerContext.getInstance().persist();
} catch (RegistryException e) {
log.error("Could not add service group: [service-group] " + servicegroup, e);
return false;
}
return true;
}
public boolean removeServiceGroup(String name) throws InvalidServiceGroupException {
if (log.isDebugEnabled()) {
log.debug("CloudControllerServiceImpl:removeServiceGroup: " + name);
}
ServiceGroup serviceGroup;
serviceGroup = CloudControllerContext.getInstance().getServiceGroup(name);
if (serviceGroup != null) {
if (CloudControllerContext.getInstance().getServiceGroups().remove(serviceGroup)) {
try {
CloudControllerContext.getInstance().persist();
} catch (RegistryException e) {
log.error("Could not remove service group [service-group] " + name);
return false;
}
if (log.isInfoEnabled()) {
log.info("Successfully removed the cartridge group: [group-name] " + serviceGroup);
}
return true;
}
}
String msg = "Cartridge group not found: [group-name] " + name;
log.error(msg);
throw new InvalidServiceGroupException(msg);
}
@Override
public ServiceGroup getServiceGroup(String name) throws InvalidServiceGroupException {
if (log.isDebugEnabled()) {
log.debug("getServiceGroupDefinition:" + name);
}
ServiceGroup serviceGroup = CloudControllerContext.getInstance().getServiceGroup(name);
if (serviceGroup == null) {
String message = "Cartridge group not found: [group-name] " + name;
if (log.isDebugEnabled()) {
log.debug(message);
}
throw new InvalidServiceGroupException(message);
}
return serviceGroup;
}
public String[] getServiceGroupSubGroups(String name) throws InvalidServiceGroupException {
ServiceGroup serviceGroup = this.getServiceGroup(name);
if (serviceGroup == null) {
throw new InvalidServiceGroupException("Invalid service group: [group-name] " + name);
}
return serviceGroup.getSubGroups();
}
/**
*
*/
public String[] getServiceGroupCartridges(String name) throws InvalidServiceGroupException {
ServiceGroup serviceGroup = this.getServiceGroup(name);
if (serviceGroup == null) {
throw new InvalidServiceGroupException("Invalid service group: [group-name] " + name);
}
return serviceGroup.getCartridges();
}
public Dependencies getServiceGroupDependencies(String name) throws InvalidServiceGroupException {
ServiceGroup serviceGroup = this.getServiceGroup(name);
if (serviceGroup == null) {
throw new InvalidServiceGroupException("Invalid service group: [group-name] " + name);
}
return serviceGroup.getDependencies();
}
@Override
public MemberContext[] startInstances(InstanceContext[] instanceContexts)
throws CartridgeNotFoundException, InvalidIaasProviderException, CloudControllerException {
handleNullObject(instanceContexts, "Instance start-up failed, member contexts is null");
List<MemberContext> memberContextList = new ArrayList<>();
for (InstanceContext instanceContext : instanceContexts) {
if (instanceContext != null) {
MemberContext memberContext = startInstance(instanceContext);
memberContextList.add(memberContext);
}
}
return memberContextList.toArray(new MemberContext[memberContextList.size()]);
}
public MemberContext startInstance(InstanceContext instanceContext)
throws CartridgeNotFoundException, InvalidIaasProviderException, CloudControllerException {
try {
// Validate instance context
handleNullObject(instanceContext, "Could not start instance, instance context is null");
if (log.isDebugEnabled()) {
log.debug("Starting up instance: " + instanceContext);
}
// Validate partition
Partition partition = instanceContext.getPartition();
handleNullObject(partition, "Could not start instance, partition is null");
// Validate cluster
String partitionId = partition.getId();
String clusterId = instanceContext.getClusterId();
ClusterContext clusterContext = CloudControllerContext.getInstance().getClusterContext(clusterId);
handleNullObject(clusterContext,
"Could not start instance, cluster context not found: [cluster-id] " + clusterId);
// Validate cartridge
String cartridgeType = clusterContext.getCartridgeType();
Cartridge cartridge = CloudControllerContext.getInstance().getCartridge(cartridgeType);
if (cartridge == null) {
String msg = "Could not startup instance, cartridge not found: [cartridge-type] " + cartridgeType;
log.error(msg);
throw new CartridgeNotFoundException(msg);
}
// Validate iaas provider
IaasProvider iaasProvider = CloudControllerContext.getInstance()
.getIaasProviderOfPartition(cartridge.getType(), partitionId);
if (iaasProvider == null) {
String msg = String.format("Could not start instance, " +
"IaaS provider not found in cartridge %s for partition %s, " +
"partitions found: %s ", cartridgeType, partitionId,
CloudControllerContext.getInstance().getPartitionToIaasProvider(cartridge.getType()).keySet()
.toString());
log.error(msg);
throw new InvalidIaasProviderException(msg);
}
// Generate member ID
String memberId = generateMemberId(clusterId);
// Create member context
String applicationId = clusterContext.getApplicationId();
// if the IaaS Provider type is 'ec2', add region and zone information to the Member via
// properties of Instance Context -> properties of Member Context
if (CloudControllerConstants.IAAS_TYPE_EC2.equalsIgnoreCase(iaasProvider.getType())) {
instanceContext.getProperties().addProperty(
new Property(CloudControllerConstants.INSTANCE_CTXT_EC2_REGION,
instanceContext.getPartition().getProperties()
.getProperty(CloudControllerConstants.REGION_ELEMENT).getValue()));
instanceContext.getProperties().addProperty(
new Property(CloudControllerConstants.INSTANCE_CTXT_EC2_AVAILABILITY_ZONE,
instanceContext.getPartition().getProperties()
.getProperty(CloudControllerConstants.ZONE_ELEMENT).getValue()));
if (log.isDebugEnabled()) {
log.debug("ec2Region in InstanceContext: " + instanceContext.getProperties()
.getProperty(CloudControllerConstants.INSTANCE_CTXT_EC2_REGION));
log.debug("ec2AvailabilityZone in InstanceContext: " + instanceContext.getProperties()
.getProperty(CloudControllerConstants.INSTANCE_CTXT_EC2_AVAILABILITY_ZONE));
}
}
MemberContext memberContext = createMemberContext(applicationId, cartridgeType, memberId,
CloudControllerUtil.getLoadBalancingIPTypeEnumFromString(cartridge.getLoadBalancingIPType()),
instanceContext);
// Prepare payload
StringBuilder payload = new StringBuilder(clusterContext.getPayload());
addToPayload(payload, "MEMBER_ID", memberId);
addToPayload(payload, "INSTANCE_ID", memberContext.getInstanceId());
addToPayload(payload, "CLUSTER_INSTANCE_ID", memberContext.getClusterInstanceId());
addToPayload(payload, "LB_CLUSTER_ID", memberContext.getLbClusterId());
addToPayload(payload, "NETWORK_PARTITION_ID", memberContext.getNetworkPartitionId());
addToPayload(payload, "PARTITION_ID", partitionId);
addToPayload(payload, "INTERNAL", "false");
if (memberContext.getProperties() != null) {
org.apache.stratos.common.Properties properties = memberContext.getProperties();
for (Property prop : properties.getProperties()) {
addToPayload(payload, prop.getName(), String.valueOf(prop.getValue()));
}
}
NetworkPartition networkPartition = CloudControllerContext.getInstance()
.getNetworkPartition(memberContext.getNetworkPartitionId());
if (networkPartition.getProperties() != null) {
if (networkPartition.getProperties().getProperties() != null) {
for (Property property : networkPartition.getProperties().getProperties()) {
// check if a property is related to the payload. Currently
// this is done by checking if the
// property name starts with 'payload_parameter.' suffix. If
// so the payload param name will
// be taken as the substring from the index of '.' to the
// end of the property name.
if (property.getName().startsWith(PAYLOAD_PARAMETER)) {
String propertyName = property.getName();
String payloadParamName = propertyName.substring(propertyName.indexOf(".") + 1);
if (payload.toString().contains(payloadParamName)) {
replaceInPayload(payloadParamName, payload, payloadParamName, property.getValue());
} else {
addToPayload(payload, payloadParamName, property.getValue());
}
}
}
}
}
Iaas iaas = iaasProvider.getIaas();
if (clusterContext.isVolumeRequired()) {
addToPayload(payload, PERSISTENCE_MAPPING, getPersistencePayload(clusterContext, iaas).toString());
}
if (log.isDebugEnabled()) {
log.debug("Payload: " + payload.toString());
}
if (clusterContext.isVolumeRequired()) {
Volume[] volumes = clusterContext.getVolumes();
if (volumes != null) {
for (int i = 0; i < volumes.length; i++) {
if (volumes[i].getId() == null) {
// Create a new volume
volumes[i] = createVolumeAndSetInClusterContext(volumes[i], iaasProvider);
}
}
}
clusterContext.setVolumes(volumes);
}
// Handle member created event
TopologyBuilder.handleMemberCreatedEvent(memberContext);
// Persist member context
CloudControllerContext.getInstance().addMemberContext(memberContext);
CloudControllerContext.getInstance().persist();
// Start instance in a new thread
if (log.isDebugEnabled()) {
log.debug(String.format("Starting instance creator thread: [cluster] %s [cluster-instance] %s "
+ "[member] %s [application-id] %s", instanceContext.getClusterId(),
instanceContext.getClusterInstanceId(), memberId, applicationId));
}
executorService.execute(new InstanceCreator(memberContext, iaasProvider, payload.toString().getBytes()));
return memberContext;
} catch (Exception e) {
String msg = String.format("Could not start instance: [cluster] %s [cluster-instance] %s",
instanceContext.getClusterId(), instanceContext.getClusterInstanceId());
log.error(msg, e);
throw new CloudControllerException(msg, e);
}
}
private MemberContext createMemberContext(String applicationId, String cartridgeType, String memberId,
LoadBalancingIPType loadBalancingIPType, InstanceContext instanceContext) {
MemberContext memberContext = new MemberContext(applicationId, cartridgeType, instanceContext.getClusterId(),
memberId);
memberContext.setClusterInstanceId(instanceContext.getClusterInstanceId());
memberContext.setNetworkPartitionId(instanceContext.getNetworkPartitionId());
memberContext.setPartition(cloudControllerContext.getNetworkPartition(instanceContext.getNetworkPartitionId()).
getPartition(instanceContext.getPartition().getId()));
memberContext.setInitTime(instanceContext.getInitTime());
memberContext.setProperties(instanceContext.getProperties());
memberContext.setLoadBalancingIPType(loadBalancingIPType);
memberContext.setInitTime(System.currentTimeMillis());
memberContext.setObsoleteExpiryTime(instanceContext.getObsoleteExpiryTime());
return memberContext;
}
private Volume createVolumeAndSetInClusterContext(Volume volume, IaasProvider iaasProvider) {
// iaas cannot be null at this state #startInstance method
Iaas iaas = iaasProvider.getIaas();
int sizeGB = volume.getSize();
String snapshotId = volume.getSnapshotId();
if (StringUtils.isNotEmpty(volume.getVolumeId())) {
// volumeID is specified, so not creating additional volumes
if (log.isDebugEnabled()) {
log.debug("Volume creation is skipping since a volume ID is specified. [Volume ID] " + volume
.getVolumeId());
}
volume.setId(volume.getVolumeId());
} else {
String volumeId = iaas.createVolume(sizeGB, snapshotId);
volume.setId(volumeId);
}
volume.setIaasType(iaasProvider.getType());
return volume;
}
private StringBuilder getPersistencePayload(ClusterContext ctx, Iaas iaas) {
StringBuilder persistencePayload = new StringBuilder();
if (isPersistenceMappingAvailable(ctx)) {
for (Volume volume : ctx.getVolumes()) {
if (log.isDebugEnabled()) {
log.debug("Adding persistence mapping " + volume.toString());
}
if (persistencePayload.length() != 0) {
persistencePayload.append("|");
}
persistencePayload.append(iaas.getIaasDevice(volume.getDevice()));
persistencePayload.append("|");
persistencePayload.append(volume.getId());
persistencePayload.append("|");
persistencePayload.append(volume.getMappingPath());
}
}
if (log.isDebugEnabled()) {
log.debug("Persistence payload: " + persistencePayload.toString());
}
return persistencePayload;
}
private boolean isPersistenceMappingAvailable(ClusterContext ctx) {
return ctx.getVolumes() != null && ctx.isVolumeRequired();
}
private void addToPayload(StringBuilder payload, String name, String value) {
payload.append(",");
payload.append(name).append("=").append(value);
}
private void replaceInPayload(String payloadParamName, StringBuilder payload, String name, String value) {
payload.replace(payload.indexOf(payloadParamName), payload.indexOf(",", payload.indexOf(payloadParamName)),
"," + name + "=" + value);
}
private String generateMemberId(String clusterId) {
UUID memberId = UUID.randomUUID();
return clusterId + memberId.toString();
}
public boolean terminateInstanceForcefully(String memberId) {
log.info(String.format("Starting to forcefully terminate the member [member-id] %s", memberId));
boolean memberTerminated = true;
try {
this.terminateInstance(memberId);
} catch (InvalidMemberException | InvalidCartridgeTypeException | CloudControllerException e) {
memberTerminated = false;
}
if (memberTerminated) {
log.info(String.format("Member terminated [member-id] %s ", memberId));
} else {
log.warn(String.format("Stratos could not terminate the member [member-id] %s. This may due to a issue "
+ "in the underlying IaaS, Please terminate the member manually if it is available", memberId));
MemberContext memberContext = CloudControllerContext.getInstance().getMemberContextOfMemberId(memberId);
try {
CloudControllerServiceUtil.executeMemberTerminationPostProcess(memberContext);
} catch (RegistryException e) {
log.error(String.format(
"Could not persist data in registry data store while forcefully terminating member "
+ "[member-id] %s", memberId), e);
return false;
}
}
return true;
}
@Override
public boolean terminateInstance(String memberId)
throws InvalidMemberException, InvalidCartridgeTypeException, CloudControllerException {
try {
handleNullObject(memberId, "Could not terminate instance, member id is null.");
MemberContext memberContext = CloudControllerContext.getInstance().getMemberContextOfMemberId(memberId);
if (memberContext == null) {
String msg = "Could not terminate instance, member context not found: [member-id] " + memberId;
if (log.isErrorEnabled()) {
log.error(msg);
}
throw new InvalidMemberException(msg);
}
if (StringUtils.isBlank(memberContext.getInstanceId())) {
if (log.isErrorEnabled()) {
log.error(String.format("Could not terminate instance, instance id is blank: [member-id] %s "
+ ", removing member from topology...", memberContext.getMemberId()));
}
CloudControllerServiceUtil.executeMemberTerminationPostProcess(memberContext);
String msg = "Could not terminate instance, member instance id is empty: " + memberContext.toString();
throw new InvalidMemberException(msg);
}
try {
// check if status == active, if true, then this is a termination on member faulty
TopologyHolder.acquireWriteLock();
Topology topology = TopologyHolder.getTopology();
org.apache.stratos.messaging.domain.topology.Service service = topology
.getService(memberContext.getCartridgeType());
if (service != null) {
Cluster cluster = service.getCluster(memberContext.getClusterId());
if (cluster != null) {
Member member = cluster.getMember(memberId);
if (member != null) {
// check if ready to shutdown member is expired and send
// member terminated if it is.
if (isMemberExpired(member, memberContext.getObsoleteInitTime(),
memberContext.getObsoleteExpiryTime())) {
if (log.isInfoEnabled()) {
log.info(String.format(
"Member pending termination in ReadyToShutdown state exceeded expiry time. "
+ "This member has to be manually deleted: %s",
memberContext.getMemberId()));
}
CloudControllerServiceUtil.executeMemberTerminationPostProcess(memberContext);
return false;
}
}
}
}
executorService.execute(new InstanceTerminator(memberContext));
} finally {
TopologyHolder.releaseWriteLock();
}
} catch (Exception e) {
String message = "Could not terminate instance: [member-id] " + memberId;
throw new CloudControllerException(message, e);
}
return true;
}
/**
* Check if a member has been in the ReadyToShutdown status for a specified expiry time
*
* @param member Member to be checked for expiration timeout
* @param initTime Member started time
* @param expiryTime Member expiry time
* @return Returns true if member has been in ReadyToShutdown status for specified time period, otherwise false
*/
private boolean isMemberExpired(Member member, long initTime, long expiryTime) {
if (member.getStatus() == MemberStatus.ReadyToShutDown) {
if (initTime == 0) {
// obsolete init time hasn't been set, i.e. not a member detected faulty.
// this is a graceful shutdown
return false;
}
// member detected faulty, calculate ready to shutdown waiting period
long timeInReadyToShutdownStatus = System.currentTimeMillis() - initTime;
return timeInReadyToShutdownStatus >= expiryTime;
}
return false;
}
@Override
public boolean terminateInstances(String clusterId) throws InvalidClusterException {
log.info("Starting to terminate all instances of cluster : " + clusterId);
handleNullObject(clusterId, "Instance termination failed. Cluster id is null.");
List<MemberContext> memberContexts = CloudControllerContext.getInstance()
.getMemberContextsOfClusterId(clusterId);
if (memberContexts == null) {
String msg = "Instance termination failed. No members found for cluster id: " + clusterId;
log.warn(msg);
return false;
}
for (MemberContext memberContext : memberContexts) {
executorService.execute(new InstanceTerminator(memberContext));
}
return true;
}
@Override
public boolean registerService(Registrant registrant) throws CartridgeNotFoundException {
String cartridgeType = registrant.getCartridgeType();
handleNullObject(cartridgeType, "Service registration failed, cartridge Type is null.");
String clusterId = registrant.getClusterId();
handleNullObject(clusterId, "Service registration failed, cluster id is null.");
String payload = registrant.getPayload();
handleNullObject(payload, "Service registration failed, payload is null.");
String hostName = registrant.getHostName();
handleNullObject(hostName, "Service registration failed, hostname is null.");
if ((CloudControllerContext.getInstance().getCartridge(cartridgeType)) == null) {
String msg = "Registration of cluster: " + clusterId +
" failed, cartridge not found: [cartridge-type] " + cartridgeType;
log.error(msg);
throw new CartridgeNotFoundException(msg);
}
try {
CloudControllerContext.getInstance().persist();
} catch (RegistryException e) {
log.error("Could not register service for cartridge [cartridge-type] " + cartridgeType, e);
return false;
}
log.info("Successfully registered service: " + registrant);
return true;
}
@Override
public String[] getCartridges() {
// get the list of cartridges registered
Collection<Cartridge> cartridges = CloudControllerContext.getInstance().getCartridges();
if (cartridges == null) {
log.info("No registered Cartridge found.");
return new String[0];
}
String[] cartridgeTypes = new String[cartridges.size()];
int i = 0;
if (log.isDebugEnabled()) {
log.debug("Registered Cartridges : \n");
}
for (Cartridge cartridge : cartridges) {
if (log.isDebugEnabled()) {
log.debug(cartridge);
}
cartridgeTypes[i] = cartridge.getType();
i++;
}
return cartridgeTypes;
}
@Override
public Cartridge getCartridge(String cartridgeType) throws CartridgeNotFoundException {
Cartridge cartridge = CloudControllerContext.getInstance().getCartridge(cartridgeType);
if (cartridge != null) {
return cartridge;
}
String msg = "Could not find cartridge: [cartridge-type] " + cartridgeType;
throw new CartridgeNotFoundException(msg);
}
@Override
public boolean unregisterService(String clusterId) throws UnregisteredClusterException {
final String clusterId_ = clusterId;
ClusterContext ctxt = CloudControllerContext.getInstance().getClusterContext(clusterId_);
handleNullObject(ctxt, "Service unregistration failed. Invalid cluster id: " + clusterId);
final String cartridgeType = ctxt.getCartridgeType();
Cartridge cartridge = CloudControllerContext.getInstance().getCartridge(cartridgeType);
if (cartridge == null) {
String msg = String
.format("Service unregistration failed. No matching cartridge found: [cartridge-type] %s "
+ "[application-id] %s", cartridgeType, ctxt.getApplicationId());
log.error(msg);
throw new UnregisteredClusterException(msg);
}
Runnable terminateInTimeout = new Runnable() {
@Override
public void run() {
ClusterContext ctxt = CloudControllerContext.getInstance().getClusterContext(clusterId_);
if (ctxt == null) {
String msg = String
.format("Service unregistration failed. Cluster not found: [cluster-id] %s ", clusterId_);
log.error(msg);
return;
}
Collection<Member> members = TopologyHolder.getTopology().
getService(ctxt.getCartridgeType()).getCluster(clusterId_).getMembers();
//finding the responding members from the existing members in the topology.
int sizeOfRespondingMembers = 0;
for (Member member : members) {
if (member.getStatus().getCode() >= MemberStatus.Active.getCode()) {
sizeOfRespondingMembers++;
}
}
long endTime = System.currentTimeMillis() + ctxt.getTimeoutInMillis() * sizeOfRespondingMembers;
while (System.currentTimeMillis() < endTime) {
CloudControllerUtil.sleep(1000);
}
// if there are still alive members
if (members.size() > 0) {
//forcefully terminate them
for (Member member : members) {
try {
terminateInstance(member.getMemberId());
} catch (Exception e) {
// we are not gonna stop the execution due to errors.
log.warn((String.format(
"Instance termination failed of member [member-id] %s " + "[application-id] %s",
member.getMemberId(), ctxt.getApplicationId())), e);
}
}
}
}
};
Runnable unregister = new Runnable() {
public void run() {
Lock lock = null;
try {
lock = CloudControllerContext.getInstance().acquireClusterContextWriteLock();
ClusterContext ctxt = CloudControllerContext.getInstance().getClusterContext(clusterId_);
if (ctxt == null) {
String msg = String.format("Service unregistration failed. Cluster not found: [cluster-id] %s ",
clusterId_);
log.error(msg);
return;
}
Collection<Member> members = TopologyHolder.getTopology().
getService(ctxt.getCartridgeType()).getCluster(clusterId_).getMembers();
while (members.size() > 0) {
//waiting until all the members got removed from the Topology/ timed out
CloudControllerUtil.sleep(1000);
}
log.info(String.format("Unregistering service cluster: [cluster-id] %s [application-id] %s",
clusterId_, ctxt.getApplicationId()));
deleteVolumes(ctxt);
TopologyBuilder.handleClusterRemoved(ctxt);
CloudControllerContext.getInstance().removeClusterContext(clusterId_);
CloudControllerContext.getInstance().removeMemberContextsOfCluster(clusterId_);
CloudControllerContext.getInstance().persist();
} catch (RegistryException e) {
log.error("Could not persist data in registry data store", e);
} finally {
if (lock != null) {
CloudControllerContext.getInstance().releaseWriteLock(lock);
}
}
}
private void deleteVolumes(ClusterContext ctxt) {
if (ctxt.isVolumeRequired()) {
Lock lock = null;
try {
lock = CloudControllerContext.getInstance().acquireCartridgesWriteLock();
Cartridge cartridge = CloudControllerContext.getInstance()
.getCartridge(ctxt.getCartridgeType());
if (cartridge != null
&& CloudControllerContext.getInstance().getIaasProviders(cartridge.getType()) != null
&& ctxt.getVolumes() != null) {
for (Volume volume : ctxt.getVolumes()) {
if (volume.getId() != null) {
String iaasType = volume.getIaasType();
Iaas iaas = CloudControllerContext.getInstance()
.getIaasProvider(cartridge.getType(), iaasType).getIaas();
if (iaas != null) {
try {
// delete the volumes if remove on unsubscription is true.
if (volume.isRemoveOntermination()) {
iaas.deleteVolume(volume.getId());
volume.setId(null);
}
} catch (Exception ignore) {
if (log.isErrorEnabled()) {
log.error((String.format(
"Error while deleting volume [id] %s [application-id] %s",
volume.getId(), ctxt.getApplicationId())), ignore);
}
}
}
}
}
CloudControllerContext.getInstance().updateCartridge(cartridge);
}
} finally {
if (lock != null) {
CloudControllerContext.getInstance().releaseWriteLock(lock);
}
}
}
}
};
new Thread(terminateInTimeout).start();
new Thread(unregister).start();
return true;
}
/**
* FIXME: A validate method shouldn't persist data
*/
@Override
public boolean validateDeploymentPolicyNetworkPartition(String cartridgeType, String networkPartitionId)
throws InvalidPartitionException, InvalidCartridgeTypeException {
NetworkPartition networkPartition = CloudControllerContext.getInstance()
.getNetworkPartition(networkPartitionId);
Lock lock = null;
try {
lock = CloudControllerContext.getInstance().acquireCartridgesWriteLock();
List<String> validatedPartitions = CloudControllerContext.getInstance().getPartitionIds(cartridgeType);
if (validatedPartitions != null) {
// cache hit for this cartridge
// get list of partitions
if (log.isDebugEnabled()) {
log.debug("Partition validation cache hit for cartridge type: " + cartridgeType);
}
}
Map<String, IaasProvider> partitionToIaasProviders = new ConcurrentHashMap<String, IaasProvider>();
if (log.isDebugEnabled()) {
log.debug("Deployment policy validation started for cartridge type: " + cartridgeType);
}
Cartridge cartridge = CloudControllerContext.getInstance().getCartridge(cartridgeType);
if (cartridge == null) {
String msg = "Cartridge not found: " + cartridgeType;
log.error(msg);
throw new InvalidCartridgeTypeException(msg);
}
for (Partition partition : networkPartition.getPartitions()) {
if (validatedPartitions != null && validatedPartitions.contains(partition.getId())) {
// partition cache hit
String provider = partition.getProvider();
IaasProvider iaasProvider = CloudControllerContext.getInstance()
.getIaasProvider(cartridge.getType(), provider);
partitionToIaasProviders.put(partition.getId(), iaasProvider);
continue;
}
if (log.isDebugEnabled()) {
log.debug("Partition validation started for " + partition + " of " + cartridge);
}
// cache miss
IaasProvider iaasProvider = CloudControllerContext.getInstance()
.getIaasProvider(cartridge.getType(), partition.getProvider());
IaasProvider updatedIaasProvider = CloudControllerServiceUtil
.validatePartitionAndGetIaasProvider(partition, iaasProvider);
try {
if (updatedIaasProvider != null) {
partitionToIaasProviders.put(partition.getId(), updatedIaasProvider);
}
// add to cache
CloudControllerContext.getInstance()
.addToCartridgeTypeToPartitionIdMap(cartridgeType, partition.getId());
if (log.isDebugEnabled()) {
log.debug("Partition " + partition.getId() + " added to the cache against " + "cartridge: " +
"[cartridge-type] " + cartridgeType);
}
} catch (Exception e) {
String message = "Could not cache partitions against the cartridge: [cartridge-type] "
+ cartridgeType;
log.error(message, e);
throw new InvalidPartitionException(message, e);
}
}
// if and only if the deployment policy valid
CloudControllerContext.getInstance().addIaasProviders(cartridgeType, partitionToIaasProviders);
CloudControllerContext.getInstance().updateCartridge(cartridge);
// persist data
CloudControllerContext.getInstance().persist();
log.info("All partitions [" + CloudControllerUtil.getPartitionIds(networkPartition.getPartitions()) + "]" +
" were validated successfully, against the cartridge: " + cartridgeType);
return true;
} catch (RegistryException e) {
log.error("Failed to persist data in registry data store", e);
return false;
} finally {
if (lock != null) {
CloudControllerContext.getInstance().releaseWriteLock(lock);
}
}
}
@Override
public boolean validatePartition(Partition partition) throws InvalidPartitionException {
handleNullObject(partition, "Partition validation failed. Partition is null.");
String provider = partition.getProvider();
String partitionId = partition.getId();
handleNullObject(provider, "Partition [" + partitionId + "] validation failed. Partition provider is null.");
IaasProvider iaasProvider = CloudControllerConfig.getInstance().getIaasProvider(provider);
return CloudControllerServiceUtil.validatePartition(partition, iaasProvider);
}
public ClusterContext getClusterContext(String clusterId) {
return CloudControllerContext.getInstance().getClusterContext(clusterId);
}
@Override
public boolean updateClusterStatus(String serviceName, String clusterId, String instanceId, ClusterStatus status) {
//TODO
return true;
}
private void handleNullObject(Object obj, String errorMsg) {
if (obj == null) {
log.error(errorMsg);
throw new CloudControllerException(errorMsg);
}
}
@Override
public boolean createApplicationClusters(String appId, ApplicationClusterContext[] appClustersContexts)
throws ApplicationClusterRegistrationException {
if (appClustersContexts == null || appClustersContexts.length == 0) {
String errorMsg = "No application cluster information found, unable to create clusters: " +
"[application-id] " + appId;
log.error(errorMsg);
throw new ApplicationClusterRegistrationException(errorMsg);
}
Lock lock = null;
try {
lock = CloudControllerContext.getInstance().acquireClusterContextWriteLock();
// Create a cluster context & cluster object for each cluster in the application
List<Cluster> clusters = new ArrayList<>();
for (ApplicationClusterContext appClusterCtxt : appClustersContexts) {
ClusterContext clusterContext = new ClusterContext(appId, appClusterCtxt.getCartridgeType(),
appClusterCtxt.getClusterId(), appClusterCtxt.getTextPayload(), appClusterCtxt.getHostName(),
appClusterCtxt.isLbCluster(), appClusterCtxt.getProperties());
if (appClusterCtxt.isVolumeRequired()) {
clusterContext.setVolumeRequired(true);
clusterContext.setVolumes(appClusterCtxt.getVolumes());
}
CloudControllerContext.getInstance().addClusterContext(clusterContext);
// Create cluster object
List<String> loadBalancerIps = findLoadBalancerIps(appId, appClusterCtxt);
Cluster cluster = new Cluster(appClusterCtxt.getCartridgeType(), appClusterCtxt.getClusterId(),
appClusterCtxt.getDeploymentPolicyName(), appClusterCtxt.getAutoscalePolicyName(), appId);
cluster.setLbCluster(false);
cluster.setTenantRange(appClusterCtxt.getTenantRange());
cluster.setHostNames(Collections.singletonList(appClusterCtxt.getHostName()));
cluster.setLoadBalancerIps(loadBalancerIps);
if (appClusterCtxt.getProperties() != null) {
Properties properties = CloudControllerUtil.toJavaUtilProperties(appClusterCtxt.getProperties());
cluster.setProperties(properties);
}
clusters.add(cluster);
}
TopologyBuilder.handleApplicationClustersCreated(appId, clusters);
CloudControllerContext.getInstance().persist();
} catch (RegistryException e) {
log.error("Could not persist data in registry data store", e);
} finally {
if (lock != null) {
CloudControllerContext.getInstance().releaseWriteLock(lock);
}
}
return true;
}
/**
* Find load balancer ips from application subscribable properties or network partition properties.
*
* @param applicationId
* @param applicationClusterContext
* @return
*/
private List<String> findLoadBalancerIps(String applicationId,
ApplicationClusterContext applicationClusterContext) {
Cartridge cartridge = CloudControllerContext.getInstance().
getCartridge(applicationClusterContext.getCartridgeType());
if (cartridge == null) {
throw new CloudControllerException("Cartridge not found: " + applicationClusterContext.getCartridgeType());
}
String clusterId = applicationClusterContext.getClusterId();
org.apache.stratos.common.Properties appClusterContextProperties = applicationClusterContext.getProperties();
if (appClusterContextProperties != null) {
// Find load balancer ips from application subscribable properties
Property ipListProperty = appClusterContextProperties
.getProperty(CloudControllerConstants.LOAD_BALANCER_IPS);
if (ipListProperty != null) {
log.info(String.format("Load balancer IPs found in application: [application] %s [cluster] %s "
+ "[load-balancer-ip-list] %s", applicationId, clusterId, ipListProperty.getValue()));
return transformToList(ipListProperty);
}
// Find load balancer ips from network partition properties
Property npListProperty = appClusterContextProperties
.getProperty(CloudControllerConstants.NETWORK_PARTITION_ID_LIST);
if (npListProperty != null) {
String npIdListStr = npListProperty.getValue();
if (StringUtils.isNotEmpty(npIdListStr)) {
List<String> loadBalancerIps = new ArrayList<>();
String[] npIdArray = npIdListStr.split(",");
for (String networkPartitionId : npIdArray) {
NetworkPartition networkPartition = CloudControllerContext.getInstance().
getNetworkPartition(networkPartitionId);
if (networkPartition == null) {
throw new CloudControllerException(String.format(
"Network partition not found: [application] %s " + "[network-partition] %s",
applicationId, networkPartitionId));
}
org.apache.stratos.common.Properties npProperties = networkPartition.getProperties();
if (npProperties != null) {
ipListProperty = npProperties.getProperty(CloudControllerConstants.LOAD_BALANCER_IPS);
if (ipListProperty != null) {
log.info(String.format("Load balancer IPs found in network partition: "
+ "[application] %s [cluster] %s [load-balancer-ip-list] %s",
applicationId,
clusterId, ipListProperty.getValue()));
String[] ipArray = ipListProperty.getValue().split(",");
for (String ip : ipArray) {
loadBalancerIps.add(ip);
}
}
}
}
return loadBalancerIps;
}
}
}
return null;
}
private List<String> transformToList(Property listProperty) {
List<String> stringList = new ArrayList<>();
String[] array = listProperty.getValue().split(",");
for (String item : array) {
stringList.add(item);
}
return stringList;
}
public boolean createClusterInstance(String serviceType, String clusterId, String alias, String instanceId,
String partitionId, String networkPartitionId) throws ClusterInstanceCreationException {
Lock lock = null;
try {
lock = CloudControllerContext.getInstance().acquireClusterContextWriteLock();
TopologyBuilder.handleClusterInstanceCreated(serviceType, clusterId, alias, instanceId, partitionId,
networkPartitionId);
CloudControllerContext.getInstance().persist();
} catch (RegistryException e) {
log.error("Could not persist data in registry data store", e);
} finally {
if (lock != null) {
CloudControllerContext.getInstance().releaseWriteLock(lock);
}
}
return true;
}
@Override
public KubernetesCluster[] getKubernetesClusters() {
return CloudControllerContext.getInstance().getKubernetesClusters();
}
@Override
public KubernetesCluster getKubernetesCluster(String kubernetesClusterId)
throws NonExistingKubernetesClusterException {
return CloudControllerContext.getInstance().getKubernetesCluster(kubernetesClusterId);
}
@Override
public KubernetesMaster getMasterForKubernetesCluster(String kubernetesClusterId)
throws NonExistingKubernetesClusterException {
return CloudControllerContext.getInstance().getKubernetesMasterInGroup(kubernetesClusterId);
}
@Override
public KubernetesHost[] getHostsForKubernetesCluster(String kubernetesClusterId)
throws NonExistingKubernetesClusterException {
return CloudControllerContext.getInstance().getKubernetesHostsInGroup(kubernetesClusterId);
}
@Override
public boolean addKubernetesCluster(KubernetesCluster kubernetesCluster)
throws InvalidKubernetesClusterException, KubernetesClusterAlreadyExistsException {
if (kubernetesCluster == null) {
throw new InvalidKubernetesClusterException("Kubernetes cluster cannot be null");
}
try {
if (CloudControllerContext.getInstance().getKubernetesCluster(kubernetesCluster.getClusterId()) != null) {
throw new KubernetesClusterAlreadyExistsException("Kubernetes cluster already exists");
}
} catch (NonExistingKubernetesClusterException ignore) {
}
Lock lock = null;
try {
lock = CloudControllerContext.getInstance().acquireKubernetesClusterWriteLock();
if (log.isInfoEnabled()) {
log.info(String.format("Adding kubernetes cluster: [kubernetes-cluster-id] %s",
kubernetesCluster.getClusterId()));
}
CloudControllerUtil.validateKubernetesCluster(kubernetesCluster);
// Add to information model
CloudControllerContext.getInstance().addKubernetesCluster(kubernetesCluster);
CloudControllerContext.getInstance().persist();
if (log.isInfoEnabled()) {
log.info(String.format("Kubernetes cluster added successfully: [kubernetes-cluster-id] %s",
kubernetesCluster.getClusterId()));
}
return true;
} catch (Exception e) {
log.error("Error occurred when adding kubernetes cluster. " + e.getMessage(), e);
throw new InvalidKubernetesClusterException(e.getMessage(), e);
} finally {
if (lock != null) {
CloudControllerContext.getInstance().releaseWriteLock(lock);
}
}
}
@Override
public boolean updateKubernetesCluster(KubernetesCluster kubernetesCluster)
throws InvalidKubernetesClusterException {
if (kubernetesCluster == null) {
throw new InvalidKubernetesClusterException("Kubernetes cluster cannot be null");
}
Lock lock = null;
try {
lock = CloudControllerContext.getInstance().acquireKubernetesClusterWriteLock();
if (log.isInfoEnabled()) {
log.info(String.format("Updating kubernetes cluster: [kubernetes-cluster-id] %s",
kubernetesCluster.getClusterId()));
}
CloudControllerUtil.validateKubernetesCluster(kubernetesCluster);
// Updating the information model
CloudControllerContext.getInstance().updateKubernetesCluster(kubernetesCluster);
KubernetesClusterContext kubClusterContext = CloudControllerContext.getInstance().
getKubernetesClusterContext(kubernetesCluster.getClusterId());
// Update necessary parameters of kubClusterContext using the updated kubCluster
kubClusterContext.updateKubClusterContextParams(kubernetesCluster);
CloudControllerContext.getInstance().updateKubernetesClusterContext(kubClusterContext);
CloudControllerContext.getInstance().persist();
if (log.isInfoEnabled()) {
log.info(String.format("Kubernetes cluster updated successfully: [kubernetes-cluster-id] %s",
kubernetesCluster.getClusterId()));
}
return true;
} catch (Exception e) {
throw new InvalidKubernetesClusterException(e.getMessage(), e);
} finally {
if (lock != null) {
CloudControllerContext.getInstance().releaseWriteLock(lock);
}
}
}
@Override
public boolean addKubernetesHost(String kubernetesClusterId, KubernetesHost kubernetesHost)
throws InvalidKubernetesHostException, NonExistingKubernetesClusterException {
if (kubernetesHost == null) {
throw new InvalidKubernetesHostException("Kubernetes host cannot be null");
}
if (StringUtils.isEmpty(kubernetesClusterId)) {
throw new NonExistingKubernetesClusterException("Kubernetes cluster id cannot be null");
}
Lock lock = null;
try {
lock = CloudControllerContext.getInstance().acquireKubernetesClusterWriteLock();
if (log.isInfoEnabled()) {
log.info(String.format(
"Adding kubernetes host for kubernetes cluster: [kubernetes-cluster-id] %s " + "[hostname] %s",
kubernetesClusterId, kubernetesHost.getHostname()));
}
CloudControllerUtil.validateKubernetesHost(kubernetesHost);
KubernetesCluster kubernetesCluster = getKubernetesCluster(kubernetesClusterId);
ArrayList<KubernetesHost> kubernetesHostArrayList;
if (kubernetesCluster.getKubernetesHosts() == null) {
kubernetesHostArrayList = new ArrayList<>();
} else {
if (CloudControllerContext.getInstance().kubernetesHostExists(kubernetesHost.getHostId())) {
throw new InvalidKubernetesHostException(
"Kubernetes host already exists: [hostname] " + kubernetesHost.getHostId());
}
kubernetesHostArrayList = new ArrayList<>(Arrays.asList(kubernetesCluster.getKubernetesHosts()));
}
kubernetesHostArrayList.add(kubernetesHost);
// Update information model
kubernetesCluster.setKubernetesHosts(
kubernetesHostArrayList.toArray(new KubernetesHost[kubernetesHostArrayList.size()]));
CloudControllerContext.getInstance().updateKubernetesCluster(kubernetesCluster);
CloudControllerContext.getInstance().persist();
if (log.isInfoEnabled()) {
log.info(
String.format("Kubernetes host added successfully: [id] %s", kubernetesCluster.getClusterId()));
}
return true;
} catch (Exception e) {
throw new InvalidKubernetesHostException(e.getMessage(), e);
} finally {
if (lock != null) {
CloudControllerContext.getInstance().releaseWriteLock(lock);
}
}
}
@Override
public boolean removeKubernetesCluster(String kubernetesClusterId)
throws NonExistingKubernetesClusterException, KubernetesClusterAlreadyUsedException {
if (StringUtils.isEmpty(kubernetesClusterId)) {
throw new NonExistingKubernetesClusterException("Kubernetes cluster id cannot be empty");
}
Collection<NetworkPartition> networkPartitions = CloudControllerContext.getInstance().getNetworkPartitions();
for (NetworkPartition networkPartition : networkPartitions) {
if (networkPartition.getProvider().equals(KUBERNETES_PROVIDER)) {
for (Partition partition : networkPartition.getPartitions()) {
if (partition.getProperties().getProperty(KUBERNETES_CLUSTER).getValue()
.equals(kubernetesClusterId)) {
throw new KubernetesClusterAlreadyUsedException(
"Kubernetes cluster is already used in the network partition");
}
}
}
}
Lock lock = null;
try {
lock = CloudControllerContext.getInstance().acquireKubernetesClusterWriteLock();
if (log.isInfoEnabled()) {
log.info("Removing Kubernetes cluster: " + kubernetesClusterId);
}
// Remove entry from information model
CloudControllerContext.getInstance().removeKubernetesCluster(kubernetesClusterId);
if (log.isInfoEnabled()) {
log.info(String.format("Kubernetes cluster removed successfully: [id] %s", kubernetesClusterId));
}
CloudControllerContext.getInstance().persist();
} catch (RegistryException e) {
log.error("Could not remove Kubernetes cluster", e);
return false;
} finally {
if (lock != null) {
CloudControllerContext.getInstance().releaseWriteLock(lock);
}
}
return true;
}
@Override
public boolean removeKubernetesHost(String kubernetesHostId) throws NonExistingKubernetesHostException {
if (kubernetesHostId == null) {
throw new NonExistingKubernetesHostException("Kubernetes host id cannot be null");
}
Lock lock = null;
try {
lock = CloudControllerContext.getInstance().acquireKubernetesClusterWriteLock();
if (log.isInfoEnabled()) {
log.info("Removing Kubernetes Host: " + kubernetesHostId);
}
try {
KubernetesCluster kubernetesClusterStored = CloudControllerContext.getInstance()
.getKubernetesClusterContainingHost(kubernetesHostId);
// Kubernetes master cannot be removed
if (kubernetesClusterStored.getKubernetesMaster().getHostId().equals(kubernetesHostId)) {
throw new NonExistingKubernetesHostException(
"Kubernetes master is not allowed to be removed [id] " + kubernetesHostId);
}
List<KubernetesHost> kubernetesHostList = new ArrayList<>();
for (KubernetesHost kubernetesHost : kubernetesClusterStored.getKubernetesHosts()) {
if (!kubernetesHost.getHostId().equals(kubernetesHostId)) {
kubernetesHostList.add(kubernetesHost);
}
}
// member count will be equal only when host object was not found
if (kubernetesHostList.size() == kubernetesClusterStored.getKubernetesHosts().length) {
throw new NonExistingKubernetesHostException(
"Kubernetes host not found for [id] " + kubernetesHostId);
}
KubernetesHost[] kubernetesHostsArray = new KubernetesHost[kubernetesHostList.size()];
kubernetesHostList.toArray(kubernetesHostsArray);
// Update information model
kubernetesClusterStored.setKubernetesHosts(kubernetesHostsArray);
if (log.isInfoEnabled()) {
log.info(String.format("Kubernetes host removed successfully: [id] %s", kubernetesHostId));
}
CloudControllerContext.getInstance().persist();
return true;
} catch (Exception e) {
throw new NonExistingKubernetesHostException(e.getMessage(), e);
}
} finally {
if (lock != null) {
CloudControllerContext.getInstance().releaseWriteLock(lock);
}
}
}
@Override
public boolean updateKubernetesMaster(KubernetesMaster kubernetesMaster)
throws InvalidKubernetesMasterException, NonExistingKubernetesMasterException {
Lock lock = null;
try {
lock = CloudControllerContext.getInstance().acquireKubernetesClusterWriteLock();
CloudControllerUtil.validateKubernetesMaster(kubernetesMaster);
if (log.isInfoEnabled()) {
log.info("Updating Kubernetes master: " + kubernetesMaster);
}
try {
KubernetesCluster kubernetesClusterStored = CloudControllerContext.getInstance()
.getKubernetesClusterContainingHost(kubernetesMaster.getHostId());
// Update information model
kubernetesClusterStored.setKubernetesMaster(kubernetesMaster);
CloudControllerContext.getInstance().persist();
if (log.isInfoEnabled()) {
log.info(String.format("Kubernetes master updated successfully: [id] %s",
kubernetesMaster.getHostId()));
}
return true;
} catch (Exception e) {
throw new InvalidKubernetesMasterException(e.getMessage(), e);
}
} finally {
if (lock != null) {
CloudControllerContext.getInstance().releaseWriteLock(lock);
}
}
}
@Override
public boolean updateKubernetesHost(KubernetesHost kubernetesHost)
throws InvalidKubernetesHostException, NonExistingKubernetesHostException {
Lock lock = null;
try {
lock = CloudControllerContext.getInstance().acquireKubernetesClusterWriteLock();
CloudControllerUtil.validateKubernetesHost(kubernetesHost);
if (log.isInfoEnabled()) {
log.info("Updating Kubernetes Host: " + kubernetesHost);
}
try {
KubernetesCluster kubernetesClusterStored = CloudControllerContext.getInstance()
.getKubernetesClusterContainingHost(kubernetesHost.getHostId());
KubernetesHost[] kubernetesHosts = kubernetesClusterStored.getKubernetesHosts();
for (int i = 0; i < kubernetesHosts.length; i++) {
if (kubernetesHosts[i].getHostId().equals(kubernetesHost.getHostId())) {
// Update the information model
kubernetesHosts[i] = kubernetesHost;
if (log.isInfoEnabled()) {
log.info(String.format("Kubernetes host updated successfully: [id] %s",
kubernetesHost.getHostId()));
}
CloudControllerContext.getInstance().updateKubernetesCluster(kubernetesClusterStored);
CloudControllerContext.getInstance().persist();
return true;
}
}
} catch (Exception e) {
throw new InvalidKubernetesHostException(e.getMessage(), e);
}
} finally {
if (lock != null) {
CloudControllerContext.getInstance().releaseWriteLock(lock);
}
}
throw new NonExistingKubernetesHostException("Kubernetes host not found [id] " + kubernetesHost.getHostId());
}
@Override
public boolean addNetworkPartition(NetworkPartition networkPartition)
throws NetworkPartitionAlreadyExistsException, InvalidNetworkPartitionException {
handleNullObject(networkPartition, "Network Partition is null");
handleNullObject(networkPartition.getId(), "Network Partition ID is null");
if (log.isInfoEnabled()) {
log.info(String.format("Adding network partition: [network-partition-id] %s", networkPartition.getId()));
}
String networkPartitionID = networkPartition.getId();
if (cloudControllerContext.getNetworkPartition(networkPartitionID) != null) {
String message = "Network partition already exists: [network-partition-id] " + networkPartitionID;
log.error(message);
throw new NetworkPartitionAlreadyExistsException(message);
}
if (networkPartition.getPartitions() != null && networkPartition.getPartitions().length != 0) {
for (Partition partition : networkPartition.getPartitions()) {
if (partition != null) {
if (log.isInfoEnabled()) {
log.info(String.format("Validating partition: [network-partition-id] %s [partition-id] %s",
networkPartition.getId(), partition.getId()));
}
// Overwrites partition provider with network partition provider
partition.setProvider(networkPartition.getProvider());
try {
validatePartition(partition);
// add Partition to partition map
CloudControllerContext.getInstance().addPartition(partition);
} catch (InvalidPartitionException e) {
//Following message is shown to the end user in all the the API clients(GUI/CLI/Rest API)
throw new InvalidNetworkPartitionException(String.format(
"Network partition " + " %s, is invalid since the partition %s is invalid",
networkPartition.getId(), partition.getId()), e);
}
if (log.isInfoEnabled()) {
log.info(String.format(
"Partition validated successfully: [network-partition-id] %s " + "[partition-id] %s",
networkPartition.getId(), partition.getId()));
}
}
}
} else {
//Following message is shown to the end user in all the the API clients(GUI/CLI/Rest API)
throw new InvalidNetworkPartitionException(
String.format("Network partition: " + "%s doesn't not have any partitions ",
networkPartition.getId()));
}
// adding network partition to CC-Context
CloudControllerContext.getInstance().addNetworkPartition(networkPartition);
// persisting CC-Context
try {
CloudControllerContext.getInstance().persist();
} catch (RegistryException e) {
log.error("Could not add network partition [network-partition-id] " + networkPartitionID, e);
return false;
}
if (log.isInfoEnabled()) {
log.info(String.format("Network partition added successfully: [network-partition-id] %s",
networkPartition.getId()));
}
return true;
}
@Override
public boolean removeNetworkPartition(String networkPartitionId) throws NetworkPartitionNotExistsException {
try {
if (log.isInfoEnabled()) {
log.info(String.format("Removing network partition: [network-partition-id] %s", networkPartitionId));
}
handleNullObject(networkPartitionId, "Network Partition ID is null");
if (cloudControllerContext.getNetworkPartition(networkPartitionId) == null) {
String message = "Network partition not found: [network-partition-id] " + networkPartitionId;
log.error(message);
throw new NetworkPartitionNotExistsException(message);
}
// remove partitions from the partition map
for (Partition partition : cloudControllerContext.getNetworkPartition(networkPartitionId).getPartitions()) {
CloudControllerContext.getInstance().removePartition(partition.getId());
}
// removing from CC-Context
CloudControllerContext.getInstance().removeNetworkPartition(networkPartitionId);
// persisting CC-Context
CloudControllerContext.getInstance().persist();
if (log.isInfoEnabled()) {
log.info(String.format("Network partition removed successfully: [network-partition-id] %s",
networkPartitionId));
}
} catch (Exception e) {
String message = e.getMessage();
log.error(message);
throw new CloudControllerException(message, e);
}
return true;
}
@Override
public boolean updateNetworkPartition(NetworkPartition networkPartition) throws NetworkPartitionNotExistsException {
try {
handleNullObject(networkPartition, "Network Partition is null");
handleNullObject(networkPartition.getId(), "Network Partition ID is null");
if (log.isInfoEnabled()) {
log.info(String.format("Updating network partition: [network-partition-id] %s",
networkPartition.getId()));
}
String networkPartitionID = networkPartition.getId();
if (cloudControllerContext.getNetworkPartition(networkPartitionID) == null) {
String message = "Network partition not found: [network-partition-id] " + networkPartitionID;
log.error(message);
throw new NetworkPartitionNotExistsException(message);
}
if (networkPartition.getPartitions() != null) {
for (Partition partition : networkPartition.getPartitions()) {
if (partition != null) {
if (log.isInfoEnabled()) {
log.info(String.format("Validating partition: [network-partition-id] %s [partition-id] %s",
networkPartition.getId(), partition.getId()));
}
// Overwrites partition provider with network partition provider
partition.setProvider(networkPartition.getProvider());
validatePartition(partition);
// add Partition to partition map
CloudControllerContext.getInstance().addPartition(partition);
if (log.isInfoEnabled()) {
log.info(String.format("Partition validated successfully: [network-partition-id] %s "
+ "[partition-id] %s", networkPartition.getId(), partition.getId()));
}
}
}
}
// overriding network partition to CC-Context
CloudControllerContext.getInstance().addNetworkPartition(networkPartition);
// persisting CC-Context
CloudControllerContext.getInstance().persist();
if (log.isInfoEnabled()) {
log.info(String.format("Network partition updated successfully: [network-partition-id] %s",
networkPartition.getId()));
}
return true;
} catch (Exception e) {
String message = e.getMessage();
log.error(message);
throw new CloudControllerException(message, e);
}
}
@Override
public NetworkPartition[] getNetworkPartitions() {
try {
Collection<NetworkPartition> networkPartitionList = cloudControllerContext.getNetworkPartitions();
return networkPartitionList.toArray(new NetworkPartition[networkPartitionList.size()]);
} catch (Exception e) {
String message = "Could not get network partitions";
log.error(message);
throw new CloudControllerException(message, e);
}
}
@Override
public NetworkPartition getNetworkPartition(String networkPartitionId) {
try {
return CloudControllerContext.getInstance().getNetworkPartition(networkPartitionId);
} catch (Exception e) {
String message = String
.format("Could not get network partition: [network-partition-id] %s", networkPartitionId);
log.error(message);
throw new CloudControllerException(message, e);
}
}
@Override
public String[] getIaasProviders() {
try {
Collection<IaasProvider> iaasProviders = CloudControllerConfig.getInstance().getIaasProviders();
List<String> iaases = new ArrayList<>();
for (IaasProvider iaas : iaasProviders) {
iaases.add(iaas.getType());
}
return iaases.toArray(new String[iaases.size()]);
} catch (Exception e) {
String message = "Could not get Iaas Providers";
log.error(message);
throw new CloudControllerException(message, e);
}
}
}