/*
(c) Copyright 2011 Telefonica, I+D. Printed in Spain (Europe). All Rights
Reserved.
The copyright to the software program(s) is property of Telefonica I+D.
The program(s) may be used and or copied only with the express written
consent of Telefonica I+D or in accordance with the terms and conditions
stipulated in the agreement/contract under which the program(s) have
been supplied.
*/
package com.telefonica.claudia.slm.deployment;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.OneToOne;
import javax.persistence.Transient;
import org.apache.log4j.Logger;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import com.telefonica.claudia.slm.common.PersistentObject;
import com.telefonica.claudia.slm.monitoring.MeasurableElement;
import com.telefonica.claudia.slm.naming.DirectoryEntry;
import com.telefonica.claudia.slm.naming.FQN;
import com.telefonica.claudia.slm.naming.ReservoirDirectory;
import com.telefonica.claudia.smi.TCloudConstants;
import com.telefonica.claudia.smi.TCloudConstants.StateType;
@Entity
public class VEEReplica extends DirectoryEntry implements PersistentObject, MeasurableElement {
private static Logger logger = Logger.getLogger(VEEReplica.class);
public static enum ActiveSubStateType {INIT, PROLOG, BOOT, RUNNING, MIGRATE, SAVE_STOP, SAVE_SUSPEND, SAVE_MIGRATE, PROLOG_MIGRATE, PROLOG_RESUME, EPILOG_STOP, EPILOG, SHUTDOWN, CANCEL};
@Id
@GeneratedValue
public long internalId;
@Column(columnDefinition = "TEXT")
private String customizationInformation = null;
@ManyToOne
private VEE vee = null;
/**
* Replica number, unique among the replicas of the related VEE.
*/
private int id = 0;
@Enumerated(EnumType.STRING)
private StateType state = StateType.initial;
@Enumerated(EnumType.STRING)
private ActiveSubStateType subState = null;
@Transient
private FQN veeReplicaFQN = null;
@OneToMany(mappedBy="veeReplica", cascade=CascadeType.ALL)
private List<Disk> disks = new ArrayList<Disk>();
@OneToMany(mappedBy="veeReplica", cascade=CascadeType.ALL)
private List<CPU> cpus = new ArrayList<CPU>();
@OneToMany(mappedBy="veeReplica", cascade=CascadeType.ALL)
private List<NIC> nics = new ArrayList<NIC>();
@OneToOne(mappedBy="veeReplica", cascade=CascadeType.ALL, fetch=FetchType.EAGER)
private Memory memory = null;
private long initialTime;
private String osBoot = null;
@ManyToOne(fetch=FetchType.EAGER)
private CloudProvider deployedOn = null;
/**
* OVF document that describe the VM as it was deployed in the underlying infrastructure.
*/
@Column(columnDefinition = "TEXT")
private String ovfRepresentation=null;
/**
* Identifier of the Virtual Machine represented by the replica in the underlying
* infraestructure.
*/
private String infraestructureId;
private long monitoringTime;
@Transient
private Set<String> availablePowerOperations = new HashSet<String>();
private boolean deployed=false;
private boolean running=false;
public VEEReplica() {}
public VEEReplica(VEE vee) {
if(vee == null)
throw new IllegalArgumentException("VEE cannot be null");
this.vee = vee;
id = vee.nextVEEReplicaId();
if(vee.getMemoryConf()!=null)
memory = new Memory(vee.getMemoryConf(),this);
List<CPUConf> cpusConfs = vee.getCPUsConf();
if(cpusConfs != null) {
int cpuId = 1;
for(CPUConf cpuConf : cpusConfs)
cpus.add(new CPU(cpuId++, cpuConf, this));
}
List<DiskConf> disksConfs = vee.getDisksConf();
if(disksConfs != null) {
int diskId = 1;
for(DiskConf diskConf : disksConfs) {
System.out.println(" >>> CREATING DISK FOR REPLICA " + this.getFQN() + ", CONF IS :");
System.out.println(" >>> Capacity: " + diskConf.getCapacity());
System.out.println(" >>> Type: " + diskConf.getType());
System.out.println(" >>> File System: " + diskConf.getFileSystem());
System.out.println(" >>> Image URL: " + diskConf.getImageURL());
disks.add(new Disk(diskId++, diskConf, this));
}
}
List<NICConf> nicsConfs = vee.getNICsConf();
if(nicsConfs != null) {
int nicId = 1;
for(NICConf nicConf : nicsConfs) {
NIC newNic = new NIC(nicId++,nicConf, this);
newNic.getFQN();
nics.add(newNic);
}
}
List<Disk> disks;
disks = getDisks();
Iterator<Disk> diskIt = disks.iterator();
while (diskIt.hasNext()) {
// create disk
Disk disk = diskIt.next();
if (disk.getDiskConf().getImageURL() != null) {
String urlDisk;
if (disk.getDiskConf().getImageURL().toString().contains("file:/"))
urlDisk = disk.getDiskConf().getImageURL().toString().replace("file:/", "file:///");
else
urlDisk = disk.getDiskConf().getImageURL().toString();
disk.setUrlImage(urlDisk);
}
disk.setReadOnly(false);
disk.setCloneDisk(true);
}
this.getFQN();
}
@SuppressWarnings("unchecked")
public void registerHwElementsInResDir() {
if(memory != null)
ReservoirDirectory.getInstance().registerObject(memory.getFQN(), memory);
for(Disk disk : disks)
ReservoirDirectory.getInstance().registerObject(disk.getFQN(), disk);
for(CPU cpu : cpus)
ReservoirDirectory.getInstance().registerObject(cpu.getFQN(), cpu);
for(NIC nic : nics)
ReservoirDirectory.getInstance().registerObject(nic.getFQN(), nic);
}
public synchronized StateType getVEEReplicaVmState() {
return state;
}
public synchronized void setVEEReplicaVmState(StateType replicaState) {
this.state = replicaState;
}
public ActiveSubStateType getVEEReplicaVmSubState() {
return subState;
}
public void setVEEReplicaVmSubState(ActiveSubStateType replicaSubState) {
this.subState = replicaSubState;
}
public String getOVFEnvironment() {
return customizationInformation;
}
public void setOVFEnvironment(String env) {
customizationInformation=env;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getInfraestructureId() {
return infraestructureId;
}
public void setInfraestructureId(String id) {
this.infraestructureId = id;
}
public VEE getParentVEE() {
return vee;
}
public void addDisk(Disk disk) {
disks.add(disk);
}
public List<Disk> getDisks() {
return disks;
}
public void addCPU(CPU cpu) {
cpus.add(cpu);
}
public List<CPU> getCPUs() {
return cpus;
}
public void addNIC(NIC nic) {
nics.add(nic);
}
public List<NIC> getNICs() {
return nics;
}
public void setMemory(Memory memory) {
this.memory = memory;
}
public Memory getMemory() {
return memory;
}
public String getOsBoot() {
return osBoot;
}
public void setOsBoot(String osBoot) {
this.osBoot = osBoot;
}
public FQN getFQN() {
if(veeReplicaFQN == null)
veeReplicaFQN = ReservoirDirectory.getInstance().buildFQN(this);
return veeReplicaFQN;
}
@Override
public String toString() {
return getFQN().toString();
}
@Override
public int hashCode() {
return (int) (internalId%5);
}
@Override
public boolean equals(Object object) {
if(object == null)
return false;
if(!(object instanceof VEEReplica))
return false;
return ((VEEReplica)object).internalId == internalId;
}
public void setMonitoringTime(long parseLong) {
this.monitoringTime = parseLong;
}
public long getMonitoringTime() {
return this.monitoringTime;
}
public void setOvfRepresentation(String ovfRepresentation) {
this.ovfRepresentation = ovfRepresentation;
}
public String getOvfRepresentation() {
return ovfRepresentation;
}
public Set<Object> getDescendants() {
Set<Object> result = new HashSet<Object>();
result.add(this);
for (DirectoryEntry de: getDisks())
result.addAll(de.getDescendants());
for (DirectoryEntry de: getCPUs())
result.addAll(de.getDescendants());
for (DirectoryEntry de: getNICs())
result.addAll(de.getDescendants());
result.add(memory);
return result;
}
public void setDeployedOn(CloudProvider deployedOn) {
this.deployedOn = deployedOn;
}
public CloudProvider getDeployedOn() {
return deployedOn;
}
public void setDeployed(boolean deployed) {
this.deployed = deployed;
}
public boolean isDeployed() {
return deployed;
}
public void setRunning(boolean running) {
this.running = running;
}
public boolean isRunning() {
return running;
}
public long getObjectId() {
return internalId;
}
public void setInitialTime(long initialTime) {
this.initialTime = initialTime;
}
public long getInitialTime() {
return initialTime;
}
public Set<String> getAvailablePowerOperations() {
return availablePowerOperations;
}
public void updateReplicaInfo() {
CloudProvider cp = getDeployedOn();
if (cp!= null&&cp.isProviderAvailable()) {
Document result=null;
try {
result = cp.getRemoteReplicaDescription(this);
} catch (Throwable t) {
logger.error("Replica could not be updated: " + t.getMessage());
t.printStackTrace();
return;
}
NodeList nl = result.getElementsByTagName("VApp");
if (nl.getLength()>0) {
Element vappElement = (Element) nl.item(0);
String status = vappElement.getAttribute("status");
if (StateType.valueOf(status) != null) {
setVEEReplicaVmState(StateType.valueOf(status));
}
// Update available power operation availablePowerOperations
NodeList linksList = result.getElementsByTagName("Link");
availablePowerOperations.clear();
for (int i=0; i < linksList.getLength(); i++) {
Element linkElement = (Element) linksList.item(i);
String relType = linkElement.getAttribute("rel");
String linkValue = linkElement.getAttribute("href");
if (relType.matches("power.*")&&linkValue!=null&!linkValue.isEmpty()) {
availablePowerOperations.add(relType);
}
}
NodeList identifierList = vappElement.getElementsByTagNameNS(TCloudConstants.NAMESPACE_VSSD, "VirtualSystemIdentifier");
if (identifierList.getLength() > 0) {
Element identifierElement = (Element) identifierList.item(0);
infraestructureId = identifierElement.getTextContent().trim();
}
// Update hardware info
NodeList items = vappElement.getElementsByTagName("Item");
for (int i =0; i < items.getLength(); i++) {
Element item = (Element) items.item(i);
NodeList resourceTypeList = item.getElementsByTagNameNS(TCloudConstants.NAMESPACE_RASD, "ResourceType");
if (resourceTypeList.getLength()==0) {
logger.error("Network item didn't had a ResourceType element.");
continue;
}
Element resourceType = (Element) resourceTypeList.item(0);
if (resourceType.getTextContent().trim().equals("10")) {
NodeList connectionList = item.getElementsByTagNameNS(TCloudConstants.NAMESPACE_RASD, "Connection");
if (connectionList.getLength()==0) {
logger.error("Network item didn't had a Connection element.");
continue;
}
Element connection = (Element) connectionList.item(0);
NodeList addresList = item.getElementsByTagNameNS(TCloudConstants.NAMESPACE_RASD, "Address");
Element address = null;
if (addresList.getLength()==0) {
logger.error("Network item didn't had a Address element.");
} else {
address = (Element) addresList.item(0);
}
NodeList ipList = item.getElementsByTagNameNS(TCloudConstants.NAMESPACE_IEP, "IPv4Address");
NodeList instanceIdList = item.getElementsByTagNameNS(TCloudConstants.NAMESPACE_RASD, "InstanceID");
Element instanceId = null;
if (instanceIdList.getLength()==0) {
logger.error("Network item didn't had a InstanceId element.");
} else {
instanceId = (Element) instanceIdList.item(0);
}
for (NIC nic: nics) {
if (nic.getNicConf().getNetwork().getName().trim().equals(connection.getTextContent().trim())) {
if (address!=null)
nic.setMacAddress(address.getTextContent().trim());
if (instanceId !=null)
nic.setInstanceId(instanceId.getTextContent().trim());
nic.getIPAddresses().clear();
for (int j=0; j < ipList.getLength(); j++) {
Element ip = (Element) ipList.item(j);
nic.addIPAddress(ip.getTextContent());
}
}
}
}
}
}
} else {
logger.error("The replica does not have an associated Cloud Provider.");
}
}
}