blob: a5c55178b192148b9addc34396e105704624cb6e [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.manager.subscription.utils;
import org.apache.axis2.AxisFault;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.stratos.autoscaler.deployment.policy.DeploymentPolicy;
import org.apache.stratos.cloud.controller.stub.pojo.*;
import org.apache.stratos.manager.client.AutoscalerServiceClient;
import org.apache.stratos.manager.client.CloudControllerServiceClient;
import org.apache.stratos.manager.dao.Cluster;
import org.apache.stratos.manager.deploy.service.Service;
import org.apache.stratos.manager.exception.ADCException;
import org.apache.stratos.manager.exception.DuplicateCartridgeAliasException;
import org.apache.stratos.manager.exception.InvalidCartridgeAliasException;
import org.apache.stratos.manager.exception.UnregisteredCartridgeException;
import org.apache.stratos.manager.lb.category.LBDataContext;
import org.apache.stratos.manager.payload.BasicPayloadData;
import org.apache.stratos.manager.repository.Repository;
import org.apache.stratos.manager.retriever.DataInsertionAndRetrievalManager;
import org.apache.stratos.manager.subscriber.Subscriber;
import org.apache.stratos.messaging.broker.publish.EventPublisher;
import org.apache.stratos.messaging.broker.publish.EventPublisherPool;
import org.apache.stratos.messaging.event.tenant.TenantSubscribedEvent;
import org.apache.stratos.messaging.event.tenant.TenantUnSubscribedEvent;
import org.apache.stratos.messaging.util.Constants;
import java.util.concurrent.Executor;
import java.util.regex.Pattern;
public class CartridgeSubscriptionUtils {
private static Log log = LogFactory.getLog(CartridgeSubscriptionUtils.class);
public static BasicPayloadData createBasicPayload (CartridgeInfo cartridgeInfo, String subscriptionKey, Cluster cluster,
Repository repository, String alias, Subscriber subscriber) {
BasicPayloadData basicPayloadData = new BasicPayloadData();
basicPayloadData.setApplicationPath(cartridgeInfo.getBaseDir());
basicPayloadData.setSubscriptionKey(subscriptionKey);
basicPayloadData.setDeployment("default");//currently hard coded to default
basicPayloadData.setMultitenant(String.valueOf(cartridgeInfo.getMultiTenant()));
basicPayloadData.setPortMappings(createPortMappingPayloadString(cartridgeInfo));
basicPayloadData.setServiceName(cartridgeInfo.getType());
if(repository != null) {
basicPayloadData.setGitRepositoryUrl(repository.getUrl());
}
if (cluster != null) {
basicPayloadData.setClusterId(cluster.getClusterDomain());
basicPayloadData.setHostName(cluster.getHostName());
}
if (alias != null) {
basicPayloadData.setSubscriptionAlias(alias);
}
if (subscriber != null) {
basicPayloadData.setTenantId(subscriber.getTenantId());
}
//TODO:remove. we do not want to know about the tenant rance in subscription!
if(cartridgeInfo.getMultiTenant()) { //TODO: fix properly
basicPayloadData.setTenantRange("*");
} else if (subscriber != null) {
basicPayloadData.setTenantRange(String.valueOf(subscriber.getTenantId()));
}
return basicPayloadData;
}
public static BasicPayloadData createBasicPayload (Service service) {
BasicPayloadData basicPayloadData = new BasicPayloadData();
basicPayloadData.setApplicationPath(service.getCartridgeInfo().getBaseDir());
basicPayloadData.setSubscriptionKey(service.getSubscriptionKey());
basicPayloadData.setClusterId(service.getClusterId());
basicPayloadData.setDeployment("default");//currently hard coded to default
basicPayloadData.setHostName(service.getHostName());
basicPayloadData.setMultitenant(String.valueOf(service.getCartridgeInfo().getMultiTenant()));
basicPayloadData.setPortMappings(createPortMappingPayloadString(service.getCartridgeInfo()));
basicPayloadData.setServiceName(service.getType());
basicPayloadData.setTenantId(service.getTenantId());
basicPayloadData.setTenantRange(service.getTenantRange());
return basicPayloadData;
}
// public static BasicPayloadData createBasicPayload (LBCategoryContext lbCategoryContext) {
//
// BasicPayloadData basicPayloadData = new BasicPayloadData();
// basicPayloadData.setApplicationPath(lbCategoryContext.getCartridgeInfo().getBaseDir());
// basicPayloadData.setSubscriptionKey(lbCategoryContext.getKey());
// basicPayloadData.setClusterId(lbCategoryContext.getCluster().getClusterDomain());
// basicPayloadData.setDeployment("default");//currently hard coded to default
// basicPayloadData.setHostName(lbCategoryContext.getCluster().getHostName());
// basicPayloadData.setMultitenant(String.valueOf(lbCategoryContext.getCartridgeInfo().getMultiTenant()));
// basicPayloadData.setPortMappings(createPortMappingPayloadString(lbCategoryContext.getCartridgeInfo()));
// basicPayloadData.setServiceName(lbCategoryContext.getLbType());
//
// if (lbCategoryContext.getSubscriptionAlias() != null && !lbCategoryContext.getSubscriptionAlias().isEmpty()) {
// basicPayloadData.setSubscriptionAlias(lbCategoryContext.getSubscriptionAlias());
// }
//
// if (lbCategoryContext.getSubscriber() != null) {
// basicPayloadData.setTenantId(lbCategoryContext.getSubscriber().getTenantId());
// }
//
// return basicPayloadData;
// }
private static String createPortMappingPayloadString (CartridgeInfo cartridgeInfo) {
// port mappings
StringBuilder portMapBuilder = new StringBuilder();
PortMapping[] portMappings = cartridgeInfo.getPortMappings();
for (PortMapping portMapping : portMappings) {
String port = portMapping.getPort();
portMapBuilder.append(port).append("|");
}
// remove last "|" character
String portMappingString = portMapBuilder.toString().replaceAll("\\|$", "");
return portMappingString;
}
public static String generateSubscriptionKey() {
String key = RandomStringUtils.randomAlphanumeric(16);
log.info("Generated key : " + key); // TODO -- remove the log
return key;
}
static class TenantSubscribedEventPublisher implements Runnable {
int tenantId;
String serviceName;
public TenantSubscribedEventPublisher(int tenantId, String service) {
this.tenantId = tenantId;
this.serviceName = service;
}
@Override
public void run() {
try {
if(log.isInfoEnabled()) {
log.info(String.format("Publishing tenant subscribed event: [tenant-id] %d [service] %s", tenantId, serviceName));
}
TenantSubscribedEvent subscribedEvent = new TenantSubscribedEvent(tenantId, serviceName);
EventPublisher eventPublisher = EventPublisherPool.getPublisher(Constants.TENANT_TOPIC);
eventPublisher.publish(subscribedEvent);
} catch (Exception e) {
if (log.isErrorEnabled()) {
log.error(String.format("Could not publish tenant subscribed event: [tenant-id] %d [service] %s", tenantId, serviceName), e);
}
}
}
}
public static void publishTenantSubscribedEvent(int tenantId, String serviceName) {
Executor exec = new Executor() {
@Override
public void execute(Runnable command) {
command.run();
}
};
exec.execute(new TenantSubscribedEventPublisher(tenantId, serviceName));
}
public static void publishTenantUnSubscribedEvent(int tenantId, String serviceName) {
try {
if(log.isInfoEnabled()) {
log.info(String.format("Publishing tenant un-subscribed event: [tenant-id] %d [service] %s", tenantId, serviceName));
}
TenantUnSubscribedEvent event = new TenantUnSubscribedEvent(tenantId, serviceName);
EventPublisher eventPublisher = EventPublisherPool.getPublisher(Constants.TENANT_TOPIC);
eventPublisher.publish(event);
} catch (Exception e) {
if (log.isErrorEnabled()) {
log.error(String.format("Could not publish tenant un-subscribed event: [tenant-id] %d [service] %s", tenantId, serviceName), e);
}
}
}
public static void validateCartridgeAlias (int tenantId, String cartridgeType, String alias) throws InvalidCartridgeAliasException, DuplicateCartridgeAliasException, ADCException {
String patternString = "([a-z0-9]+([-][a-z0-9])*)+";
Pattern pattern = Pattern.compile(patternString);
if (!pattern.matcher(alias).matches()) {
String msg = "The alias " + alias + " can contain only alpha-numeric lowercase characters. Please enter a valid alias.";
log.error(msg);
throw new InvalidCartridgeAliasException(msg, tenantId, cartridgeType, alias);
}
boolean isAliasTaken = false;
try {
isAliasTaken = isAliasTaken(tenantId, alias);
} catch (Exception e) {
String msg = "Exception : " + e.getMessage();
log.error(msg, e);
throw new ADCException("Error when checking alias is already taken", e);
}
if (isAliasTaken) {
String msg = "The alias " + alias + " is already taken. Please try again with a different alias.";
log.error(msg);
throw new DuplicateCartridgeAliasException(msg, cartridgeType, alias);
}
}
public static boolean isAliasTaken (int tenantId, String alias) {
DataInsertionAndRetrievalManager dataInsertionAndRetrievalManager = new DataInsertionAndRetrievalManager();
// return (dataInsertionAndRetrievalManager.getCartridgeSubscription(tenantId, alias) == null) ? false : true;
// fixing STRATOS-427, making the alias globally unique
return (dataInsertionAndRetrievalManager.getCartridgeSubscriptionForAlias(alias) == null) ? false : true;
}
public static String limitLengthOfString (String source, int length) {
return source.substring(0, length);
}
public static LBDataContext getLoadBalancerDataContext (int tenantId, String serviceType, String deploymentPolicyName, LoadbalancerConfig lbConfig) throws UnregisteredCartridgeException, ADCException {
String lbCartridgeType = lbConfig.getType();
LBDataContext lbDataCtxt = new LBDataContext();
// set tenant Id
lbDataCtxt.setTenantId(tenantId);
Properties lbReferenceProperties = lbConfig.getProperties();
Property lbRefProperty = new Property();
lbRefProperty.setName(org.apache.stratos.messaging.util.Constants.LOAD_BALANCER_REF);
for (Property prop : lbReferenceProperties.getProperties()) {
String name = prop.getName();
String value = prop.getValue();
// TODO make following a chain of responsibility pattern
if (Constants.NO_LOAD_BALANCER.equals(name)) {
if ("true".equals(value)) {
lbDataCtxt.setLbCategory(Constants.NO_LOAD_BALANCER);
if (log.isDebugEnabled()) {
log.debug("This cartridge does not require a load balancer. " + "[Type] " + serviceType);
}
lbRefProperty.setValue(name);
lbDataCtxt.addLoadBalancedServiceProperty(lbRefProperty);
break;
}
} else if (Constants.EXISTING_LOAD_BALANCERS.equals(name)) {
lbDataCtxt.setLbCategory(Constants.EXISTING_LOAD_BALANCERS);
String clusterIdsVal = value;
if (log.isDebugEnabled()) {
log.debug("This cartridge refers to existing load balancers. " + "[Type] " + serviceType + "[Referenced Cluster Ids] " + clusterIdsVal);
}
String[] clusterIds = clusterIdsVal.split(",");
for (String clusterId : clusterIds) {
try {
AutoscalerServiceClient.getServiceClient().checkLBExistenceAgainstPolicy(clusterId, deploymentPolicyName);
} catch (Exception ex) {
// we don't need to throw the error here.
log.error(ex.getMessage(), ex);
}
}
lbRefProperty.setValue(name);
lbDataCtxt.addLoadBalancedServiceProperty(lbRefProperty);
break;
} else if (Constants.DEFAULT_LOAD_BALANCER.equals(name)) {
if ("true".equals(value)) {
lbDataCtxt.setLbCategory(Constants.DEFAULT_LOAD_BALANCER);
lbRefProperty.setValue(name);
CartridgeInfo lbCartridgeInfo;
try {
lbCartridgeInfo = CloudControllerServiceClient.getServiceClient().getCartridgeInfo(lbCartridgeType);
} catch (Exception e) {
String message = "Error getting info for " + lbCartridgeType;
log.error(message, e);
throw new ADCException(message, e);
}
if (lbCartridgeInfo == null) {
String msg = "Please specify a LB cartridge type for the cartridge: " + serviceType + " as category: " +
Constants.DEFAULT_LOAD_BALANCER;
log.error(msg);
throw new ADCException(msg);
}
lbDataCtxt.setLbCartridgeInfo(lbCartridgeInfo);
if (log.isDebugEnabled()) {
log.debug("This cartridge uses default load balancer. " + "[Type] " + serviceType);
}
try {
// get the valid policies for lb cartridge
DeploymentPolicy[] lbCartridgeDepPolicies =
getAutoscalerServiceClient().getDeploymentPolicies(lbCartridgeType);
// traverse deployment policies of lb cartridge
for (DeploymentPolicy policy : lbCartridgeDepPolicies) {
// check existence of the subscribed policy
if (deploymentPolicyName.equals(policy.getId())) {
if (!getAutoscalerServiceClient().checkDefaultLBExistenceAgainstPolicy(deploymentPolicyName)) {
if(log.isDebugEnabled()){
log.debug(" Default LB doesn't exist for deployment policy ["+deploymentPolicyName+"] ");
}
Properties lbProperties = new Properties();
// if LB cartridge definition has properties as well, combine
if (lbCartridgeInfo.getProperties() != null && lbCartridgeInfo.getProperties().length > 0) {
if(log.isDebugEnabled()){
log.debug(" Combining LB properties ");
}
lbProperties.setProperties(combine(lbCartridgeInfo.getProperties(), new Property[]{lbRefProperty}));
} else {
lbProperties.setProperties(new Property[]{lbRefProperty});
}
lbDataCtxt.addLBProperties(lbProperties);
}
}
}
} catch (Exception ex) {
// we don't need to throw the error here.
log.error(ex.getMessage(), ex);
}
// set deployment and autoscaling policies
lbDataCtxt.setDeploymentPolicy(deploymentPolicyName);
lbDataCtxt.setAutoscalePolicy(lbCartridgeInfo.getDefaultAutoscalingPolicy());
lbDataCtxt.addLoadBalancedServiceProperty(lbRefProperty);
break;
}
} else if (Constants.SERVICE_AWARE_LOAD_BALANCER.equals(name)) {
if ("true".equals(value)) {
lbDataCtxt.setLbCategory(Constants.SERVICE_AWARE_LOAD_BALANCER);
lbRefProperty.setValue(name);
CartridgeInfo lbCartridgeInfo;
try {
lbCartridgeInfo = CloudControllerServiceClient.getServiceClient().getCartridgeInfo(lbCartridgeType);
} catch (Exception e) {
String message = "Error getting info for " + lbCartridgeType;
log.error(message, e);
throw new ADCException(message, e);
}
if (lbCartridgeInfo == null) {
String msg = "Please specify a LB cartridge type for the cartridge: " + serviceType + " as category: " +
Constants.SERVICE_AWARE_LOAD_BALANCER;
log.error(msg);
throw new ADCException(msg);
}
lbDataCtxt.setLbCartridgeInfo(lbCartridgeInfo);
// add a property for the service type
Property loadBalancedServiceTypeProperty = new Property();
loadBalancedServiceTypeProperty.setName(Constants.LOAD_BALANCED_SERVICE_TYPE);
// set the load balanced service type
loadBalancedServiceTypeProperty.setValue(serviceType);
if (log.isDebugEnabled()) {
log.debug("This cartridge uses a service aware load balancer. [Type] " + serviceType);
}
try {
// get the valid policies for lb cartridge
DeploymentPolicy[] lbCartridgeDepPolicies = getAutoscalerServiceClient().getDeploymentPolicies(lbCartridgeType);
// traverse deployment policies of lb cartridge
for (DeploymentPolicy policy : lbCartridgeDepPolicies) {
// check existence of the subscribed policy
if (deploymentPolicyName.equals(policy.getId())) {
if (!getAutoscalerServiceClient().checkServiceLBExistenceAgainstPolicy(serviceType, deploymentPolicyName)) {
Properties lbProperties = new Properties();
// if LB cartridge definition has properties as well, combine
if (lbCartridgeInfo.getProperties() != null && lbCartridgeInfo.getProperties().length > 0) {
lbProperties.setProperties(combine(lbCartridgeInfo.getProperties(), new Property[]{lbRefProperty, loadBalancedServiceTypeProperty}));
} else {
lbProperties.setProperties(new Property[]{lbRefProperty, loadBalancedServiceTypeProperty});
}
// set a payload property for load balanced service type
Property payloadProperty = new Property();
payloadProperty.setName("LOAD_BALANCED_SERVICE_TYPE"); //TODO: refactor hardcoded name
payloadProperty.setValue(serviceType);
lbDataCtxt.addLBProperties(lbProperties);
}
}
}
} catch (Exception ex) {
// we don't need to throw the error here.
log.error(ex.getMessage(), ex);
}
// set deployment and autoscaling policies
lbDataCtxt.setDeploymentPolicy(deploymentPolicyName);
lbDataCtxt.setAutoscalePolicy(lbCartridgeInfo.getDefaultAutoscalingPolicy());
lbDataCtxt.addLoadBalancedServiceProperty(lbRefProperty);
break;
}
}
}
return lbDataCtxt;
}
private static AutoscalerServiceClient getAutoscalerServiceClient () throws ADCException {
try {
return AutoscalerServiceClient.getServiceClient();
} catch (AxisFault axisFault) {
String errorMsg = "Error in getting AutoscalerServiceClient instance";
log.error(errorMsg, axisFault);
throw new ADCException (errorMsg, axisFault);
}
}
private static Property[] combine (Property[] propertyArray1, Property[] propertyArray2) {
int length = propertyArray1.length + propertyArray2.length;
Property[] combinedProperties = new Property[length];
System.arraycopy(propertyArray1, 0, combinedProperties, 0, propertyArray1.length);
System.arraycopy(propertyArray2, 0, combinedProperties, propertyArray1.length, propertyArray2.length);
return combinedProperties;
}
}