package com.sixsq.slipstream.persistence; /* * +=================================================================+ * SlipStream Server (WAR) * ===== * Copyright (C) 2013 SixSq Sarl (sixsq.com) * ===== * Licensed 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. * -=================================================================- */ import java.math.BigInteger; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.persistence.*; import javax.persistence.criteria.CriteriaBuilder; import javax.persistence.criteria.CriteriaQuery; import javax.persistence.criteria.Predicate; import javax.persistence.criteria.Root; import org.simpleframework.xml.Attribute; import com.sixsq.slipstream.exceptions.ConfigurationException; import com.sixsq.slipstream.exceptions.ValidationException; import com.sixsq.slipstream.vm.VmsQueryParameters; /** * Unit test: * * @see VmTest * */ @Entity @Table(uniqueConstraints = {@UniqueConstraint(columnNames={"cloud", "instanceId", "user_"})}) @NamedQueries({ @NamedQuery(name = "byUserAndCloud", query = "SELECT v FROM Vm v WHERE v.user_ = :user AND v.cloud = :cloud"), @NamedQuery(name = "byUser", query = "SELECT v.measurement, v.runUuid, v.runOwner, v.cloud, v.isUsable FROM Vm v WHERE v.user_ = :user"), @NamedQuery(name = "byRun", query = "SELECT v.cloud, v FROM Vm v WHERE v.runUuid = :run"), @NamedQuery(name = "countbyRun", query = "SELECT v.runUuid, count(v.runUuid) FROM Vm v WHERE v.isUsable=TRUE AND v.user_=:user GROUP BY v.runUuid") }) @NamedNativeQuery(name = "countbyRunSuper", query = "SELECT vv.runUuid, count(vv.runUuid) FROM (SELECT v.runUuid FROM Vm v WHERE v.isUsable=TRUE GROUP BY v.cloud, v.instanceId, v.runUuid) vv GROUP BY vv.runUuid") public class Vm { public final static String RESOURCE_URL_PREFIX = "vms/"; public static final int PENDING_TIMEOUT = 900000; // 15 mn @Id @GeneratedValue Long id; @Attribute private String cloud; @Attribute(name = "user") private String user_; @Attribute private String instanceId; @Attribute private String state; @Attribute private Date measurement; @Attribute(required = false) private String runUuid; @Attribute(required = false) private String runOwner; @Attribute(required = false) private String ip; @Attribute(required = false) private String name; @Attribute(required = false) private String nodeName; @Attribute(required = false) private String nodeInstanceId; @Column(nullable = true) @Attribute(required = false) private Boolean isUsable; @Attribute(required = false) private Integer cpu; @Attribute(required = false) private Float ram; @Attribute(required = false) private Float disk; @Attribute(required = false) private String instanceType; @SuppressWarnings("unused") private Vm() { } public Vm(String instanceid, String cloud, String state, String user, boolean isUsable, String cpu, String ram, String disk, String instanceType) { this.instanceId = instanceid; this.cloud = cloud; this.state = state; this.user_ = user; this.isUsable = isUsable; this.cpu = (cpu == null) ? null : Integer.valueOf(cpu); this.ram = (ram == null) ? null : Float.valueOf(ram); this.disk = (disk == null) ? null : Float.valueOf(disk); this.instanceType = instanceType; measurement = new Date(); } public Vm(String instanceid, String cloud, String state, String user, boolean isUsable) { this.instanceId = instanceid; this.cloud = cloud; this.state = state; this.user_ = user; this.isUsable = isUsable; measurement = new Date(); } public static List<Vm> list(User user) throws ConfigurationException, ValidationException { return list(new VmsQueryParameters(user, null, null, null, null, null, null)); } public static List<Vm> list(VmsQueryParameters parameters) throws ConfigurationException, ValidationException { List<Vm> vms = null; EntityManager em = PersistenceUtil.createEntityManager(); try { CriteriaBuilder builder = em.getCriteriaBuilder(); CriteriaQuery<Vm> critQuery = builder.createQuery(Vm.class); Root<Vm> rootQuery = critQuery.from(Vm.class); critQuery.select(rootQuery); Predicate where = viewListCommonQueryOptions(builder, rootQuery, parameters); if (where != null){ critQuery.where(where); } critQuery.orderBy(builder.desc(rootQuery.get("measurement"))); TypedQuery<Vm> query = em.createQuery(critQuery); if (parameters.offset != null) { query.setFirstResult(parameters.offset); } if (parameters.limit != null) { query.setMaxResults(parameters.limit); } vms = query.getResultList(); } finally { em.close(); } return vms; } public static int listCount(VmsQueryParameters parameters) throws ConfigurationException, ValidationException { int count = 0; EntityManager em = PersistenceUtil.createEntityManager(); try { CriteriaBuilder builder = em.getCriteriaBuilder(); CriteriaQuery<Long> critQuery = builder.createQuery(Long.class); Root<Vm> rootQuery = critQuery.from(Vm.class); critQuery.select(builder.count(rootQuery)); Predicate where = viewListCommonQueryOptions(builder, rootQuery, parameters); if (where != null){ critQuery.where(where); } TypedQuery<Long> query = em.createQuery(critQuery); count = (int)(long) query.getSingleResult(); } finally { em.close(); } return count; } private static Predicate andPredicate(CriteriaBuilder builder, Predicate currentPredicate, Predicate newPredicate){ return (currentPredicate != null) ? builder.and(currentPredicate, newPredicate) : newPredicate; } private static Predicate viewListCommonQueryOptions(CriteriaBuilder builder, Root<Vm> rootQuery, VmsQueryParameters parameters) { Predicate where = null; if (!parameters.user.isSuper()) { where = andPredicate(builder, where, builder.equal(rootQuery.get("user_"), parameters.user.getName())); } else if (parameters.userFilter != null) { where = andPredicate(builder, where, builder.equal(rootQuery.get("user_"), parameters.userFilter)); } if (parameters.runUuid != null && !"".equals(parameters.runUuid)) { where = andPredicate(builder, where, builder.equal(rootQuery.get("runUuid"), parameters.runUuid)); } if (parameters.runOwner != null && !"".equals(parameters.runOwner)) { where = andPredicate(builder, where, builder.equal(rootQuery.get("runOwner"), parameters.runOwner)); } if (parameters.cloud != null && !"".equals(parameters.cloud)) { where = andPredicate(builder, where, builder.equal(rootQuery.get("cloud"), parameters.cloud)); } return where; } private static CloudUsage addCloudIntoUsage(Map<String, CloudUsage> usages, String cloud) { CloudUsage usage; if (!usages.containsKey(cloud)) { usage = new CloudUsage(cloud); usages.put(cloud, usage); } else { usage = usages.get(cloud); } return usage; } public static Map<String, Long> countPerRun(User user) { Map<String, Long> vmCountPerRun = new HashMap<>(); List<?> results; EntityManager em = PersistenceUtil.createEntityManager(); try { if (user.isSuper()) { results = em.createNamedQuery("countbyRunSuper").getResultList(); } else { results = em.createNamedQuery("countbyRun").setParameter("user", user.getName()).getResultList(); } } finally { em.close(); } for (Object result : results) { String runUuid = (String) ((Object[]) result)[0]; Object obj = ((Object[]) result)[1]; Long count; if (obj instanceof BigInteger) { count = ((BigInteger) obj).longValue(); } else { count = (Long) obj; } vmCountPerRun.put(runUuid, count); } return vmCountPerRun; } public static Map<String, CloudUsage> usage(String user) { List<?> vms; EntityManager em = PersistenceUtil.createEntityManager(); try { vms = em.createNamedQuery("byUser").setParameter("user", user).getResultList(); } finally { em.close(); } Map<String, CloudUsage> usages = new HashMap<>(); for (Object vm : vms) { Date measurement = (Date) ((Object[]) vm)[0]; String runUuid = (String) ((Object[]) vm)[1]; String runOwner = (String) ((Object[]) vm)[2]; String cloud = (String) ((Object[]) vm)[3]; Boolean isUsable = (Boolean) ((Object[]) vm)[4]; if (user.equals(runOwner)) { if (isUsable) { addCloudIntoUsage(usages, cloud).incrementUserVmUsage(); } else { addCloudIntoUsage(usages, cloud).incrementUserInactiveVmUsage(); } } else if (runUuid != null) { addCloudIntoUsage(usages, cloud).incrementOthersVmUsage(); } else if (((new Date()).getTime() - measurement.getTime()) < PENDING_TIMEOUT) { addCloudIntoUsage(usages, cloud).incrementPendingVmUsage(); } else { addCloudIntoUsage(usages, cloud).incrementUnknownVmUsage(); } } return usages; } /** * This method assumes that the input VMs correspond to a single cloud. * Otherwise, duplicate instance ids would overwrite each other. * * @param vms * for a single cloud * @return mapped VMs by instance id */ public static Map<String, Vm> toMapByInstanceId(List<Vm> vms) { Map<String, Vm> map = new HashMap<String, Vm>(); for (Vm v : vms) { map.put(v.getInstanceId(), v); } return map; } /** * Maps the VMs into list per cloud. * * @param vms * for all or any cloud * @return map of VMs where the key is a cloud, and the value a list of * corresponding VMs for that cloud. */ public static Map<String, List<Vm>> toMapByCloud(List<Vm> vms) { Map<String, List<Vm>> map = new HashMap<String, List<Vm>>(); for (Vm v : vms) { List<Vm> forCloud = map.get(v.getCloud()); if (forCloud == null) { forCloud = new ArrayList<Vm>(); map.put(v.getCloud(), forCloud); } forCloud.add(v); } return map; } /** * Extract for a give run id, the VMs, grouped by cloud * * @param runUuid * @return map of vms grouped by cloud */ public static Map<String, List<Vm>> listByRun(String runUuid) { EntityManager em = PersistenceUtil.createEntityManager(); EntityTransaction transaction = em.getTransaction(); transaction.begin(); Query q = em.createNamedQuery("byRun"); q.setParameter("run", runUuid); List<?> vmList = q.getResultList(); Map<String, List<Vm>> vmMap = new HashMap<String, List<Vm>>(); for (Object o : vmList) { String cloud = (String) ((Object[]) o)[0]; Vm vm = (Vm) ((Object[]) o)[1]; List<Vm> vms = vmMap.get(cloud); if (vms == null) { vms = new ArrayList<Vm>(); vmMap.put(cloud, vms); } vms.add(vm); } transaction.commit(); em.close(); return vmMap; } public void setState(String state) { this.state = state; } public String getCloud() { return cloud; } public String getUser() { return user_; } public String getInstanceId() { return instanceId; } public String getState() { return state; } public Date getMeasurement() { return measurement; } public String getRunUuid() { return runUuid; } public void setRunUuid(String runUuid) { this.runUuid = runUuid; } public String getRunOwner() { return runOwner; } public void setRunOwner(String runOwner) { this.runOwner = runOwner; } public String getIp() { return this.ip; } public void setIp(String ip) { this.ip = ip; } public String getName() { return this.name; } public void setName(String name) { this.name = name; } public String getNodeName() { return this.nodeName; } public void setNodeName(String nodeName) { this.nodeName = nodeName; } public String getNodeInstanceId() { return this.nodeInstanceId; } public void setNodeInstanceId(String nodeInstanceId) { this.nodeInstanceId = nodeInstanceId; } public boolean getIsUsable() { return (this.isUsable == null) ? false : this.isUsable; } public void setIsUsable(boolean isUsable) { this.isUsable = isUsable; } public Integer getCpu() { return this.cpu; } public void setCpu(Integer cpu) { this.cpu = cpu; } public void setCpu(String cpu) { this.cpu = (cpu == null) ? null : Integer.valueOf(cpu); } public Float getRam() { return this.ram; } public void setRam(Float ram) { this.ram = ram; } public void setRam(String ram) { this.ram = (ram == null) ? null : Float.valueOf(ram); } public Float getDisk() { return this.disk; } public void setDisk(Float disk) { this.disk = disk; } public void setDisk(String disk) { this.disk = (disk == null) ? null : Float.valueOf(disk); } public String getInstanceType() { return this.instanceType; } public void setInstanceType(String instanceType) { this.instanceType = instanceType; } public void remove() { EntityManager em = PersistenceUtil.createEntityManager(); EntityTransaction transaction = em.getTransaction(); transaction.begin(); Vm fromDb = em.find(Vm.class, id); if (fromDb != null) { em.remove(fromDb); } transaction.commit(); em.close(); } }