package at.ac.tuwien.dsg.icomot.examples.test_HUNG_on_workspace;
import at.ac.tuwien.dsg.comot.api.ToscaDescriptionBuilder;
import at.ac.tuwien.dsg.comot.api.ToscaDescriptionBuilderImpl;
import java.util.Map;
import static at.ac.tuwien.dsg.comot.common.model.ArtifactTemplate.MiscArtifact;
import static at.ac.tuwien.dsg.comot.common.model.ArtifactTemplate.SingleScriptArtifact;
import static at.ac.tuwien.dsg.comot.common.model.BASHAction.BASHAction;
import at.ac.tuwien.dsg.comot.common.model.Capability;
import static at.ac.tuwien.dsg.comot.common.model.CommonOperatingSystemSpecification.OpenstackMicro;
import static at.ac.tuwien.dsg.comot.common.model.CommonOperatingSystemSpecification.OpenstackSmall;
import at.ac.tuwien.dsg.comot.common.model.Constraint;
import at.ac.tuwien.dsg.comot.common.model.Constraint.Metric;
import static at.ac.tuwien.dsg.comot.common.model.EntityRelationship.ConnectToRelation;
import static at.ac.tuwien.dsg.comot.common.model.EntityRelationship.HostedOnRelation;
import at.ac.tuwien.dsg.comot.common.model.OperatingSystemUnit;
import static at.ac.tuwien.dsg.comot.common.model.OperatingSystemUnit.OperatingSystemUnit;
import at.ac.tuwien.dsg.comot.common.model.Requirement;
import at.ac.tuwien.dsg.comot.common.model.CloudService;
import static at.ac.tuwien.dsg.comot.common.model.CloudService.ServiceTemplate;
import at.ac.tuwien.dsg.comot.common.model.ElasticityCapability;
import at.ac.tuwien.dsg.comot.common.model.LifecyclePhase;
import at.ac.tuwien.dsg.comot.common.model.ServiceTopology;
import static at.ac.tuwien.dsg.comot.common.model.ServiceTopology.ServiceTopology;
import at.ac.tuwien.dsg.comot.common.model.ServiceUnit;
import static at.ac.tuwien.dsg.comot.common.model.SoftwareNode.SingleSoftwareUnit;
import static at.ac.tuwien.dsg.comot.common.model.Strategy.Strategy;
import at.ac.tuwien.dsg.icomot.iCOMOTOrchestrator;
import at.ac.tuwien.dsg.icomot.util.ProcessArgs;
import at.ac.tuwien.dsg.icomot.util.ProcessArgs.Arg;
/**
* This example deploys an elastic IOT platform running in the cloud
*
* @author http://dsg.tuwien.ac.at
*/
public class ElasticIoTPlatform {
public static void main(String[] args) {
//specify service units in terms of software
String platformRepo = "http://128.130.172.215/iCOMOTTutorial/files/ElasticIoTCloudPlatform/";
String miscRepo = "http://128.130.172.215/iCOMOTTutorial/files/Misc/";
//need to specify details of VM and operating system to deploy the software servide units on
OperatingSystemUnit dataControllerVM = OperatingSystemUnit("DataControllerUnitVM")
.providedBy(OpenstackSmall()
//OS image having JDK and Ganglia preinstalled, for faster deploy time
.withBaseImage("a82e054f-4f01-49f9-bc4c-77a98045739c")
);
OperatingSystemUnit dataNodeVM = OperatingSystemUnit("DataNodeUnitVM")
.providedBy(OpenstackMicro()
.withBaseImage("a82e054f-4f01-49f9-bc4c-77a98045739c"));
//finally, we define Vm types for event processing
OperatingSystemUnit loadbalancerVM = OperatingSystemUnit("LoadBalancerUnitVM")
.providedBy(OpenstackSmall()
.withBaseImage("a82e054f-4f01-49f9-bc4c-77a98045739c"));
OperatingSystemUnit eventProcessingVM = OperatingSystemUnit("EventProcessingUnitVM")
.providedBy(OpenstackSmall()
.withBaseImage("a82e054f-4f01-49f9-bc4c-77a98045739c"));
OperatingSystemUnit localProcessingVM = OperatingSystemUnit("LocalProcessingUnitVM")
.providedBy(OpenstackSmall()
.withBaseImage("a82e054f-4f01-49f9-bc4c-77a98045739c"));
OperatingSystemUnit mqttQueueVM = OperatingSystemUnit("MqttQueueVM")
.providedBy(OpenstackSmall()
.withBaseImage("a82e054f-4f01-49f9-bc4c-77a98045739c"));
OperatingSystemUnit momVM = OperatingSystemUnit("MoMVM")
.providedBy(OpenstackSmall()
.withBaseImage("a82e054f-4f01-49f9-bc4c-77a98045739c"));
//start with Data End, and first with Data Controller
ServiceUnit dataControllerUnit = SingleSoftwareUnit("DataControllerUnit")
//software artifacts needed for unit deployment = software artifact archive and script to deploy Cassandra
.deployedBy(SingleScriptArtifact(platformRepo + "scripts/OpenStack/deployCassandraSeed.sh"))
.deployedBy(MiscArtifact(platformRepo + "artifacts/ElasticCassandraSetup-1.0.tar.gz"))
//data controller exposed its IP
.exposes(Capability.Variable("DataController_IP_information"));
ElasticityCapability dataNodeUnitScaleIn = ElasticityCapability.ScaleIn();
ElasticityCapability dataNodeUnitScaleOut = ElasticityCapability.ScaleOut();
//specify data node
ServiceUnit dataNodeUnit = SingleSoftwareUnit("DataNodeUnit")
.deployedBy(SingleScriptArtifact(platformRepo + "scripts/OpenStack/deployCassandraNode.sh"))
.deployedBy(MiscArtifact(platformRepo + "artifacts/ElasticCassandraSetup-1.0.tar.gz"))
//data node MUST KNOW the IP of cassandra seed, to connect to it and join data cluster
.requires(Requirement.Variable("DataController_IP_Data_Node_Req").withName("requiringDataNodeIP"))
//.provides(dataNodeUnitScaleIn, dataNodeUnitScaleOut)
//express elasticity strategy: Scale IN Data Node when cpu usage < 40%
.controlledBy(Strategy("DN_ST1")
.when(Constraint.MetricConstraint("DN_ST1_CO1", new Metric("cpuUsage", "%")).lessThan("40"))
.enforce(dataNodeUnitScaleIn)
)
.controlledBy(Strategy("DN_ST2")
.when(Constraint.MetricConstraint("DN_ST2_CO1", new Metric("cpuUsage", "%")).greaterThan("80"))
.enforce(dataNodeUnitScaleOut)
)
.withLifecycleAction(LifecyclePhase.STOP, BASHAction("sudo service joinRing stop"));
//add the service units belonging to the event processing topology
ServiceUnit momUnit = SingleSoftwareUnit("MOMUnit")
//load balancer must provide IP
.exposes(Capability.Variable("MOM_IP_information"))
.deployedBy(SingleScriptArtifact(platformRepo + "scripts/OpenStack/deployMoM.sh"))
.deployedBy(MiscArtifact(platformRepo + "artifacts/DaaSQueue-1.0.tar.gz"));
ElasticityCapability eventProcessingUnitScaleIn = ElasticityCapability.ScaleIn();
ElasticityCapability eventProcessingUnitScaleOut = ElasticityCapability.ScaleOut();
//add the service units belonging to the event processing topology
ServiceUnit eventProcessingUnit = SingleSoftwareUnit("EventProcessingUnit")
.deployedBy(SingleScriptArtifact(platformRepo + "scripts/OpenStack/deployEventProcessing.sh"))
.deployedBy(MiscArtifact(platformRepo + "artifacts/DaaS-1.0.tar.gz"))
//event processing must register in Load Balancer, so it needs the IP
.requires(Requirement.Variable("EventProcessingUnit_LoadBalancer_IP_Req"))
//event processing also needs to querry the Data Controller to access data
.requires(Requirement.Variable("EventProcessingUnit_DataController_IP_Req"))
.requires(Requirement.Variable("EventProcessingUnit_MOM_IP_Req"))
.provides(eventProcessingUnitScaleIn, eventProcessingUnitScaleOut)
//scale IN if throughput < 200 and responseTime < 200
.controlledBy(Strategy("EP_ST1")
.when(Constraint.MetricConstraint("EP_ST1_CO1", new Metric("responseTime", "ms")).lessThan("100"))
.and(Constraint.MetricConstraint("EP_ST1_CO2", new Metric("avgThroughput", "operations/s")).lessThan("200"))
.enforce(eventProcessingUnitScaleIn)
)
.controlledBy(Strategy("EP_ST2")
.when(Constraint.MetricConstraint("EP_ST2_CO1", new Metric("responseTime", "ms")).greaterThan("100"))
.and(Constraint.MetricConstraint("EP_ST2_CO2", new Metric("avgThroughput", "operations/s")).greaterThan("200"))
.enforce(eventProcessingUnitScaleOut)
)
.withLifecycleAction(LifecyclePhase.STOP, BASHAction("sudo service event-processing stop"));
//add the service units belonging to the event processing topology
ServiceUnit loadbalancerUnit = SingleSoftwareUnit("LoadBalancerUnit")
//load balancer must provide IP
.exposes(Capability.Variable("LoadBalancer_IP_information"))
.deployedBy(SingleScriptArtifact(platformRepo + "scripts/OpenStack/deployLoadBalancer.sh"))
.deployedBy(MiscArtifact(platformRepo + "artifacts/HAProxySetup-1.0.tar.gz"));
ServiceUnit mqttUnit = SingleSoftwareUnit("QueueUnit")
//load balancer must provide IP
.exposes(Capability.Variable("brokerIp_Capability"))
.deployedBy(SingleScriptArtifact(platformRepo + "scripts/OpenStack/run_mqtt_broker.sh"));
ElasticityCapability localProcessingUnitScaleIn = ElasticityCapability.ScaleIn().withPrimitiveOperations("Salsa.scaleIn");
ElasticityCapability localProcessingUnitScaleOut = ElasticityCapability.ScaleOut().withPrimitiveOperations("Salsa.scaleOut");
ServiceUnit localProcessingUnit = SingleSoftwareUnit("LocalProcessingUnit")
//load balancer must provide IP
.requires(Requirement.Variable("brokerIp_Requirement"))
.requires(Requirement.Variable("loadBalancerIp_Requirement"))
.provides(localProcessingUnitScaleIn, localProcessingUnitScaleOut)
.deployedBy(SingleScriptArtifact(platformRepo + "scripts/OpenStack/deployLocalAnalysis.sh"))
.deployedBy(MiscArtifact(miscRepo + "artifacts/jre-7-linux-x64.tar.gz"))
.deployedBy(MiscArtifact(platformRepo + "artifacts/LocalDataAnalysis.tar.gz"));
//Describe a Data End service topology containing the previous 2 software service units
ServiceTopology dataEndTopology = ServiceTopology("DataEndTopology")
.withServiceUnits(dataControllerUnit, dataNodeUnit //add also OS units to topology
, dataControllerVM, dataNodeVM
);
//specify constraints on the data topology
//thus, the CPU usage of all Service Unit instances of the data end Topology must be below 80%
dataEndTopology.controlledBy(Strategy("EP_ST3")
.when(Constraint.MetricConstraint("DET_CO1", new Metric("cpuUsage", "%")).lessThan("80"))
.enforce(eventProcessingUnitScaleOut)
);
//define event processing unit topology
ServiceTopology eventProcessingTopology = ServiceTopology("EventProcessingTopology")
.withServiceUnits(loadbalancerUnit, eventProcessingUnit, momUnit //add vm types to topology
, loadbalancerVM, eventProcessingVM, momVM
);
ServiceTopology localProcessinTopology = ServiceTopology("Gateway")
.withServiceUnits(mqttQueueVM, mqttUnit, localProcessingUnit, localProcessingVM
);
localProcessingUnit.
controlledBy(Strategy("LPT_ST1").when(Constraint.MetricConstraint("LPT_ST1_CO1", new Metric("avgBufferSize", "#")).lessThan("50"))
.enforce(localProcessingUnitScaleIn));
localProcessingUnit.
controlledBy(Strategy("LPT_ST2").when(Constraint.MetricConstraint("LPT_ST2_CO1", new Metric("avgBufferSize", "#")).greaterThan("50"))
.enforce(localProcessingUnitScaleOut));
//describe the service template which will hold more topologies
CloudService serviceTemplate = ServiceTemplate("ElasticIoTPlatform")
.consistsOfTopologies(dataEndTopology)
.consistsOfTopologies(eventProcessingTopology)
.consistsOfTopologies(localProcessinTopology)
//defining CONNECT_TO and HOSTED_ON relationships
.andRelationships(
//Data Controller IP send to Data Node
ConnectToRelation("dataNodeToDataController")
.from(dataControllerUnit.getContext().get("DataController_IP_information"))
.to(dataNodeUnit.getContext().get("DataController_IP_Data_Node_Req")) //specify which software unit goes to which VM
,
//event processing gets IP from load balancer
ConnectToRelation("eventProcessingToLoadBalancer")
.from(loadbalancerUnit.getContext().get("LoadBalancer_IP_information"))
.to(eventProcessingUnit.getContext().get("EventProcessingUnit_LoadBalancer_IP_Req")) //specify which software unit goes to which VM
,
//event processing gets IP from data controller
ConnectToRelation("eventProcessingToDataController")
.from(dataControllerUnit.getContext().get("DataController_IP_information"))
.to(eventProcessingUnit.getContext().get("EventProcessingUnit_DataController_IP_Req")) //specify which software unit goes to which VM
,
ConnectToRelation("eventProcessingToMOM")
.from(momUnit.getContext().get("MOM_IP_information"))
.to(eventProcessingUnit.getContext().get("EventProcessingUnit_MOM_IP_Req")) //specify which software unit goes to which VM
,
ConnectToRelation("mqtt_broker")
.from(mqttUnit.getContext().get("brokerIp_Capability"))
.to(localProcessingUnit.getContext().get("brokerIp_Requirement")) //specify which software unit goes to which VM
,
ConnectToRelation("load_balancer")
.from(loadbalancerUnit.getContext().get("LoadBalancer_IP_information"))
.to(localProcessingUnit.getContext().get("loadBalancerIp_Requirement")) //specify which software unit goes to which VM
,
HostedOnRelation("dataControllerToVM")
.from(dataControllerUnit)
.to(dataControllerVM),
HostedOnRelation("dataNodeToVM")
.from(dataNodeUnit)
.to(dataNodeVM) //add hosted on relatinos
, HostedOnRelation("loadbalancerToVM")
.from(loadbalancerUnit)
.to(loadbalancerVM),
HostedOnRelation("eventProcessingToVM")
.from(eventProcessingUnit)
.to(eventProcessingVM),
HostedOnRelation("momToVM")
.from(momUnit)
.to(momVM),
HostedOnRelation("localProcessingToVM")
.from(localProcessingUnit)
.to(localProcessingVM),
HostedOnRelation("mqttToVM")
.from(mqttUnit)
.to(mqttQueueVM)
)
.withDefaultMetrics();
iCOMOTOrchestrator orchestrator = new iCOMOTOrchestrator("localhost");
// added to make it easier to run as jar from cmd line
{
Map<Arg, String> argsMap = ProcessArgs.processArgs(args);
for (Arg key : argsMap.keySet()) {
switch (key) {
case ORCHESTRATOR_IP:
orchestrator.withIP(argsMap.get(key));
break;
case SALSA_IP:
orchestrator.withSalsaIP(argsMap.get(key));
break;
case SALSA_PORT:
orchestrator.withSalsaPort(Integer.parseInt(argsMap
.get(key)));
break;
case rSYBL_IP:
orchestrator.withRsyblIP(argsMap.get(key));
break;
case rSYBL_PORT:
orchestrator.withRsyblPort(Integer.parseInt(argsMap
.get(key)));
break;
case GovOps_IP:
orchestrator.withGovOpsIP(argsMap.get(key));
break;
case GovOps_PORT:
orchestrator.withGovOpsPort(Integer.parseInt(argsMap
.get(key)));
break;
}
}
}
orchestrator.withGovOpsIP("128.130.172.199").withGovOpsPort(8080)
.withSalsaIP("128.130.172.215").withSalsaPort(8888)
.withRsyblIP("128.130.172.215").withRsyblPort(8080);
ToscaDescriptionBuilder tosca = new ToscaDescriptionBuilderImpl();
System.out.println(tosca.toXml(serviceTemplate));
//orchestrator.deploy(serviceTemplate);
//only to deploy
//orchestrator.deploy(serviceTemplate);
//for updating anything
//orchestrator.controlExisting(serviceTemplate);
}
}