fix for issue if SL machine has multiple credentials registered

now just pick the best one. it matters only when we are going to log in to a machine.
the only time the problem has been observed has been with pre-existing machines set up
outwith jclouds with multiple password.
This commit is contained in:
Alex Heneveld 2016-03-08 09:54:40 +00:00 committed by Andrea Turli
parent b96c66dbce
commit 0248931cc1
2 changed files with 108 additions and 1 deletions

View File

@ -18,10 +18,12 @@ package org.jclouds.softlayer.compute.functions;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.collect.FluentIterable.from;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.annotation.Resource;
import javax.inject.Inject;
import javax.inject.Singleton;
@ -34,20 +36,26 @@ import org.jclouds.compute.functions.GroupNamingConvention;
import org.jclouds.domain.Location;
import org.jclouds.domain.LoginCredentials;
import org.jclouds.location.predicates.LocationPredicates;
import org.jclouds.logging.Logger;
import org.jclouds.softlayer.domain.Password;
import org.jclouds.softlayer.domain.TagReference;
import org.jclouds.softlayer.domain.VirtualGuest;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Function;
import com.google.common.base.Supplier;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
@Singleton
public class VirtualGuestToNodeMetadata implements Function<VirtualGuest, NodeMetadata> {
@Resource
protected Logger logger = Logger.NULL;
public static final Map<VirtualGuest.State, Status> serverStateToNodeStatus = ImmutableMap
.<VirtualGuest.State, Status> builder().put(VirtualGuest.State.HALTED, Status.PENDING)
.put(VirtualGuest.State.PAUSED, Status.SUSPENDED).put(VirtualGuest.State.RUNNING, Status.RUNNING)
@ -95,7 +103,7 @@ public class VirtualGuestToNodeMetadata implements Function<VirtualGuest, NodeMe
builder.privateAddresses(ImmutableSet.of(from.getPrimaryBackendIpAddress()));
// TODO simplify once we move domain classes to AutoValue
if (from.getOperatingSystem() != null && from.getOperatingSystem().getPasswords() != null && !from.getOperatingSystem().getPasswords().isEmpty()) {
Password password = Iterables.getOnlyElement(from.getOperatingSystem().getPasswords());
Password password = getBestPassword(from.getOperatingSystem().getPasswords(), from);
builder.credentials(LoginCredentials.builder().identity(password.getUsername()).credential(password.getPassword()).build());
}
if (from.getTagReferences() != null && !from.getTagReferences().isEmpty()) {
@ -110,4 +118,48 @@ public class VirtualGuestToNodeMetadata implements Function<VirtualGuest, NodeMe
return builder.build();
}
@VisibleForTesting
Password getBestPassword(Set<Password> passwords, VirtualGuest context) {
if (passwords == null || passwords.isEmpty()) {
throw new IllegalStateException("No credentials declared for " + context);
}
if (passwords.size() == 1) {
// usual path
return Iterables.getOnlyElement(passwords);
}
// in some setups a there may be multiple passwords; pick the best
Password bestPassword = null;
Set<Password> alternates = Sets.newLinkedHashSet();
int bestScore = -1;
for (Password p : passwords) {
int score = -1;
if ("root".equals(p.getUsername())) score = 10;
else if ("root".equalsIgnoreCase(p.getUsername())) score = 4;
else if ("ubuntu".equals(p.getUsername())) score = 8;
else if ("ubuntu".equalsIgnoreCase(p.getUsername())) score = 3;
else if ("administrator".equals(p.getUsername())) score = 5;
else if ("administrator".equalsIgnoreCase(p.getUsername())) score = 2;
else if (p.getUsername() != null && p.getUsername().length() > 1) score = 1;
if (score > 0) {
if (score > bestScore) {
bestPassword = p;
alternates.clear();
bestScore = score;
} else if (score == bestScore) {
alternates.add(p);
}
}
}
if (bestPassword == null) {
throw new IllegalStateException("No valid credentials available for " + context + "; found: " + passwords);
}
if (!alternates.isEmpty()) {
logger.warn("Multiple credentials for " + bestPassword.getUsername() + "@" + context + "; using first declared " + bestPassword + " and ignoring " + alternates);
} else {
logger.debug("Multiple credentials for " + context + "; using preferred username " + bestPassword.getUsername());
}
return bestPassword;
}
}

View File

@ -19,6 +19,7 @@ package org.jclouds.softlayer.compute.functions;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNotNull;
import static org.testng.Assert.assertTrue;
import java.util.Set;
import org.jclouds.compute.domain.NodeMetadata;
@ -29,6 +30,7 @@ import org.jclouds.domain.LocationBuilder;
import org.jclouds.domain.LocationScope;
import org.jclouds.softlayer.domain.Datacenter;
import org.jclouds.softlayer.domain.OperatingSystem;
import org.jclouds.softlayer.domain.Password;
import org.jclouds.softlayer.domain.PowerState;
import org.jclouds.softlayer.domain.SoftwareDescription;
import org.jclouds.softlayer.domain.SoftwareLicense;
@ -39,6 +41,7 @@ import com.google.common.base.Supplier;
import com.google.common.base.Suppliers;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.common.collect.Sets;
import com.google.inject.Guice;
/**
@ -100,4 +103,56 @@ public class VirtualGuestToNodeMetadataTest {
.build();
}
@Test(expectedExceptions = { IllegalStateException.class })
public void testGetBestPasswordNone() {
Set<Password> passwords = Sets.newLinkedHashSet();
VirtualGuestToNodeMetadata f = new VirtualGuestToNodeMetadata(locationSupplier, namingConvention,
virtualGuestToImage, virtualGuestToHardware);
f.getBestPassword(passwords, null);
}
@Test
public void testGetBestPasswordOneRoot() {
Set<Password> passwords = Sets.newLinkedHashSet();
passwords.add(new Password(1, "root", "pass"));
VirtualGuestToNodeMetadata f = new VirtualGuestToNodeMetadata(locationSupplier, namingConvention,
virtualGuestToImage, virtualGuestToHardware);
Password best = f.getBestPassword(passwords, null);
assertEquals(best.getUsername(), "root");
}
@Test
public void testGetBestPasswordOneNonRoot() {
Set<Password> passwords = Sets.newLinkedHashSet();
passwords.add(new Password(1, "nonroot", "word"));
VirtualGuestToNodeMetadata f = new VirtualGuestToNodeMetadata(locationSupplier, namingConvention,
virtualGuestToImage, virtualGuestToHardware);
Password best = f.getBestPassword(passwords, null);
assertEquals(best.getUsername(), "nonroot");
}
@Test
public void testGetBestPasswordTwoDifferent() {
Set<Password> passwords = Sets.newLinkedHashSet();
passwords.add(new Password(1, "nonroot", "word"));
passwords.add(new Password(2, "root", "pass"));
VirtualGuestToNodeMetadata f = new VirtualGuestToNodeMetadata(locationSupplier, namingConvention,
virtualGuestToImage, virtualGuestToHardware);
Password best = f.getBestPassword(passwords, null);
assertEquals(best.getUsername(), "root");
}
@Test
public void testGetBestPasswordTwoSame() {
Set<Password> passwords = Sets.newLinkedHashSet();
passwords.add(new Password(1, "root", "word"));
passwords.add(new Password(2, "root", "pass"));
VirtualGuestToNodeMetadata f = new VirtualGuestToNodeMetadata(locationSupplier, namingConvention,
virtualGuestToImage, virtualGuestToHardware);
Password best = f.getBestPassword(passwords, null);
assertEquals(best.getUsername(), "root");
// should take the first
assertEquals(best.getPassword(), "word");
}
}