blob: 59a4418385621b666e551b373e5aef47c9e0549f [file] [log] [blame]
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds 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.jclouds.cloudstack.compute.functions;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.collect.Iterables.filter;
import static com.google.common.collect.Iterables.transform;
import static com.google.common.collect.Sets.newHashSet;
import static org.jclouds.util.InetAddresses2.isPrivateIPAddress;
import java.util.Map;
import java.util.Set;
import javax.annotation.Nullable;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.jclouds.cloudstack.domain.IPForwardingRule;
import org.jclouds.cloudstack.domain.NIC;
import org.jclouds.cloudstack.domain.VirtualMachine;
import org.jclouds.collect.FindResourceInSet;
import org.jclouds.collect.Memoized;
import org.jclouds.compute.domain.Hardware;
import org.jclouds.compute.domain.HardwareBuilder;
import org.jclouds.compute.domain.Image;
import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.compute.domain.NodeMetadataBuilder;
import org.jclouds.compute.domain.Processor;
import org.jclouds.compute.domain.NodeMetadata.Status;
import org.jclouds.compute.functions.GroupNamingConvention;
import org.jclouds.domain.Location;
import org.jclouds.rest.ResourceNotFoundException;
import org.jclouds.util.Throwables2;
import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.base.Supplier;
import com.google.common.base.Throwables;
import com.google.common.cache.LoadingCache;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Iterables;
import com.google.common.util.concurrent.UncheckedExecutionException;
/**
* @author Adrian Cole, Andrei Savu
*/
@Singleton
public class VirtualMachineToNodeMetadata implements Function<VirtualMachine, NodeMetadata> {
public static final Map<VirtualMachine.State, Status> vmStateToNodeStatus = ImmutableMap
.<VirtualMachine.State, Status> builder().put(VirtualMachine.State.STARTING, Status.PENDING)
.put(VirtualMachine.State.RUNNING, Status.RUNNING).put(VirtualMachine.State.STOPPING, Status.PENDING)
.put(VirtualMachine.State.STOPPED, Status.SUSPENDED)
.put(VirtualMachine.State.DESTROYED, Status.TERMINATED)
.put(VirtualMachine.State.EXPUNGING, Status.TERMINATED)
.put(VirtualMachine.State.MIGRATING, Status.PENDING).put(VirtualMachine.State.ERROR, Status.ERROR)
.put(VirtualMachine.State.UNKNOWN, Status.UNRECOGNIZED)
// TODO: is this really a state?
.put(VirtualMachine.State.SHUTDOWNED, Status.PENDING)
.put(VirtualMachine.State.UNRECOGNIZED, Status.UNRECOGNIZED).build();
private final FindLocationForVirtualMachine findLocationForVirtualMachine;
private final FindImageForVirtualMachine findImageForVirtualMachine;
private final LoadingCache<String, Set<IPForwardingRule>> getIPForwardingRulesByVirtualMachine;
private final GroupNamingConvention nodeNamingConvention;
@Inject
VirtualMachineToNodeMetadata(FindLocationForVirtualMachine findLocationForVirtualMachine,
FindImageForVirtualMachine findImageForVirtualMachine,
LoadingCache<String, Set<IPForwardingRule>> getIPForwardingRulesByVirtualMachine,
GroupNamingConvention.Factory namingConvention) {
this.nodeNamingConvention = checkNotNull(namingConvention, "namingConvention").createWithoutPrefix();
this.findLocationForVirtualMachine = checkNotNull(findLocationForVirtualMachine, "findLocationForVirtualMachine");
this.findImageForVirtualMachine = checkNotNull(findImageForVirtualMachine, "findImageForVirtualMachine");
this.getIPForwardingRulesByVirtualMachine = checkNotNull(getIPForwardingRulesByVirtualMachine,
"getIPForwardingRulesByVirtualMachine");
}
@Override
public NodeMetadata apply(VirtualMachine from) {
// convert the result object to a jclouds NodeMetadata
NodeMetadataBuilder builder = new NodeMetadataBuilder();
builder.ids(from.getId() + "");
builder.name(from.getName());
// TODO: in cloudstack 2.2.12, when "name" was set fine on the backend,
// but wrong API response was returned to the user
// http://bugs.cloud.com/show_bug.cgi?id=11664
//
// we set displayName to the same value as name, but this could be wrong
// on hosts not started with jclouds
builder.hostname(from.getDisplayName());
builder.location(findLocationForVirtualMachine.apply(from));
builder.group(nodeNamingConvention.groupInUniqueNameOrNull(from.getDisplayName()));
Image image = findImageForVirtualMachine.apply(from);
if (image != null) {
builder.imageId(image.getId());
builder.operatingSystem(image.getOperatingSystem());
}
builder.hardware(new HardwareBuilder()
.ids(from.getServiceOfferingId() + "")
.name(from.getServiceOfferingName() + "")
// .tags() TODO
.processors(ImmutableList.of(new Processor(from.getCpuCount(), from.getCpuSpeed())))
.ram((int)from.getMemory())//
.hypervisor(from.getHypervisor())//
.build());
builder.status(vmStateToNodeStatus.get(from.getState()));
Set<String> publicAddresses = newHashSet(), privateAddresses = newHashSet();
if (from.getIPAddress() != null) {
boolean isPrivate = isPrivateIPAddress(from.getIPAddress());
if (isPrivate) {
privateAddresses.add(from.getIPAddress());
} else {
publicAddresses.add(from.getIPAddress());
}
}
if (from.getPublicIP() != null) {
publicAddresses.add(from.getPublicIP());
}
for (NIC nic : from.getNICs()) {
if (nic.getIPAddress() != null) {
if (isPrivateIPAddress(nic.getIPAddress())) {
privateAddresses.add(nic.getIPAddress());
} else {
publicAddresses.add(nic.getIPAddress());
}
}
}
try {
/* Also add to the list of public IPs any public IP address that has a
forwarding rule that links to this machine */
Iterables.addAll(publicAddresses, transform(
filter(getIPForwardingRulesByVirtualMachine.getUnchecked(from.getId()),
new Predicate<IPForwardingRule>() {
@Override
public boolean apply(@Nullable IPForwardingRule rule) {
return !"Deleting".equals(rule.getState());
}
}), new Function<IPForwardingRule, String>() {
@Override
public String apply(@Nullable IPForwardingRule rule) {
return rule.getIPAddress();
}
}));
} catch (UncheckedExecutionException e) {
if (Throwables2.getFirstThrowableOfType(e, ResourceNotFoundException.class) == null) {
Throwables.propagateIfPossible(e.getCause());
throw e;
}
}
return builder.privateAddresses(privateAddresses).publicAddresses(publicAddresses).build();
}
@Singleton
public static class FindLocationForVirtualMachine extends FindResourceInSet<VirtualMachine, Location> {
@Inject
public FindLocationForVirtualMachine(@Memoized Supplier<Set<? extends Location>> location) {
super(location);
}
@Override
public boolean matches(VirtualMachine from, Location input) {
return input.getId().equals(from.getZoneId());
}
}
@Singleton
public static class FindHardwareForVirtualMachine extends FindResourceInSet<VirtualMachine, Hardware> {
@Inject
public FindHardwareForVirtualMachine(@Memoized Supplier<Set<? extends Hardware>> location) {
super(location);
}
@Override
public boolean matches(VirtualMachine from, Hardware input) {
return input.getProviderId().equals(from.getServiceOfferingId());
}
}
@Singleton
public static class FindImageForVirtualMachine extends FindResourceInSet<VirtualMachine, Image> {
@Inject
public FindImageForVirtualMachine(@Memoized Supplier<Set<? extends Image>> location) {
super(location);
}
@Override
public boolean matches(VirtualMachine from, Image input) {
return input.getProviderId().equals(from.getTemplateId() + "")
// either location free image (location is null)
// or in the same zone as the VM
&& (input.getLocation() == null || input.getId().equals(from.getZoneId() + ""));
}
}
}