/*
* Copyright 2017 Netflix, Inc.
*
* 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.
*/
package com.netflix.fenzo;
import org.apache.mesos.Protos;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
/* package */ class InternalVMCloner {
/**
* Creates a VM lease object representing the max of resources from the given collection of VMs. Attributes
* are created by adding all unique attributes across the collection.
* @param avms Collection of VMs to create the new lease object from.
* @return VM lease object representing the max of resources from the given collection of VMs
*/
/* package */ VirtualMachineLease getClonedMaxResourcesLease(Collection<AssignableVirtualMachine> avms) {
double cpus = 0.0;
double mem = 0.0;
double disk = 0.0;
double network = 0.0;
double ports = 0.0;
final Map<String, Double> scalars = new HashMap<>();
final Map<String, Protos.Attribute> attributeMap = new HashMap<>();
if (avms != null) {
for(AssignableVirtualMachine avm: avms) {
final Map<VMResource, Double[]> resourceStatus = avm.getResourceStatus();
Double[] values = resourceStatus.get(VMResource.CPU);
if (values != null && values.length == 2)
cpus = Math.max(cpus, values[0] + values[1]);
values = resourceStatus.get(VMResource.Memory);
if (values != null && values.length == 2)
mem = Math.max(mem, values[0] + values[1]);
values = resourceStatus.get(VMResource.Disk);
if (values != null && values.length == 2)
disk = Math.max(disk, values[0] + values[1]);
values = resourceStatus.get(VMResource.Network);
if (values != null && values.length == 2)
network = Math.max(network, values[0] + values[1]);
values = resourceStatus.get(VMResource.Ports);
if (values != null && values.length == 2)
ports = Math.max(ports, values[0] + values[1]);
final Map<String, Double> maxScalars = avm.getMaxScalars();
if (maxScalars != null && !maxScalars.isEmpty()) {
for (String k: maxScalars.keySet())
scalars.compute(k, (s, oldVal) -> {
if (oldVal == null)
oldVal = 0.0;
Double aDouble = maxScalars.get(k);
if (aDouble == null)
aDouble = 0.0;
return oldVal + aDouble;
});
}
final Map<String, Protos.Attribute> attrs = avm.getCurrTotalLease().getAttributeMap();
if (attrs != null && !attrs.isEmpty()) {
for (Map.Entry<String, Protos.Attribute> e: attrs.entrySet())
attributeMap.putIfAbsent(e.getKey(), e.getValue());
}
}
}
final double fcpus = cpus;
final double fmem = mem;
final double fdisk = disk;
final double fnetwork = network;
final List<VirtualMachineLease.Range> fports = Collections.singletonList(
new VirtualMachineLease.Range(100, 100 + (int)ports));
return new VirtualMachineLease() {
@Override
public String getId() {
return "NoID";
}
@Override
public long getOfferedTime() {
return 0;
}
@Override
public String hostname() {
return "NoHostname";
}
@Override
public String getVMID() {
return "NoID";
}
@Override
public double cpuCores() {
return fcpus;
}
@Override
public double memoryMB() {
return fmem;
}
@Override
public double networkMbps() {
return fnetwork;
}
@Override
public double diskMB() {
return fdisk;
}
@Override
public List<Range> portRanges() {
return fports;
}
@Override
public Protos.Offer getOffer() {
return null;
}
@Override
public Map<String, Protos.Attribute> getAttributeMap() {
return attributeMap;
}
@Override
public Double getScalarValue(String name) {
return scalars.get(name);
}
@Override
public Map<String, Double> getScalarValues() {
return scalars;
}
};
}
/* package */ VirtualMachineLease cloneLease(VirtualMachineLease lease, final String hostname, long now) {
final List<VirtualMachineLease.Range> ports = new LinkedList<>();
final List<VirtualMachineLease.Range> ranges = lease.portRanges();
if (ranges != null && !ranges.isEmpty()) {
for (VirtualMachineLease.Range r: ranges)
ports.add(new VirtualMachineLease.Range(r.getBeg(), r.getEnd()));
}
final double cpus = lease.cpuCores();
final double memory = lease.memoryMB();
final double network = lease.networkMbps();
final double disk = lease.diskMB();
final Map<String, Protos.Attribute> attributes = new HashMap<>(lease.getAttributeMap());
final Map<String, Double> scalarValues = new HashMap<>(lease.getScalarValues());
return new VirtualMachineLease() {
@Override
public String getId() {
return hostname;
}
@Override
public long getOfferedTime() {
return now;
}
@Override
public String hostname() {
return hostname;
}
@Override
public String getVMID() {
return hostname;
}
@Override
public double cpuCores() {
return cpus;
}
@Override
public double memoryMB() {
return memory;
}
@Override
public double networkMbps() {
return network;
}
@Override
public double diskMB() {
return disk;
}
@Override
public List<Range> portRanges() {
return ports;
}
@Override
public Protos.Offer getOffer() {
return null;
}
@Override
public Map<String, Protos.Attribute> getAttributeMap() {
return attributes;
}
@Override
public Double getScalarValue(String name) {
return scalarValues.get(name);
}
@Override
public Map<String, Double> getScalarValues() {
return scalarValues;
}
};
}
}