Repository: jclouds Updated Branches: refs/heads/master c18371a79 -> d649c90d9
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. Project: http://git-wip-us.apache.org/repos/asf/jclouds/repo Commit: http://git-wip-us.apache.org/repos/asf/jclouds/commit/d649c90d Tree: http://git-wip-us.apache.org/repos/asf/jclouds/tree/d649c90d Diff: http://git-wip-us.apache.org/repos/asf/jclouds/diff/d649c90d Branch: refs/heads/master Commit: d649c90d988cab6fa90f34a7d87037a33e36654a Parents: c18371a Author: Alex Heneveld <[email protected]> Authored: Tue Mar 8 09:54:40 2016 +0000 Committer: Andrea Turli <[email protected]> Committed: Tue Mar 8 14:59:20 2016 +0100 ---------------------------------------------------------------------- .../functions/VirtualGuestToNodeMetadata.java | 54 ++++++++++++++++++- .../VirtualGuestToNodeMetadataTest.java | 55 ++++++++++++++++++++ 2 files changed, 108 insertions(+), 1 deletion(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/jclouds/blob/d649c90d/providers/softlayer/src/main/java/org/jclouds/softlayer/compute/functions/VirtualGuestToNodeMetadata.java ---------------------------------------------------------------------- diff --git a/providers/softlayer/src/main/java/org/jclouds/softlayer/compute/functions/VirtualGuestToNodeMetadata.java b/providers/softlayer/src/main/java/org/jclouds/softlayer/compute/functions/VirtualGuestToNodeMetadata.java index 470fb76..0a76c70 100644 --- a/providers/softlayer/src/main/java/org/jclouds/softlayer/compute/functions/VirtualGuestToNodeMetadata.java +++ b/providers/softlayer/src/main/java/org/jclouds/softlayer/compute/functions/VirtualGuestToNodeMetadata.java @@ -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; + } + } http://git-wip-us.apache.org/repos/asf/jclouds/blob/d649c90d/providers/softlayer/src/test/java/org/jclouds/softlayer/compute/functions/VirtualGuestToNodeMetadataTest.java ---------------------------------------------------------------------- diff --git a/providers/softlayer/src/test/java/org/jclouds/softlayer/compute/functions/VirtualGuestToNodeMetadataTest.java b/providers/softlayer/src/test/java/org/jclouds/softlayer/compute/functions/VirtualGuestToNodeMetadataTest.java index 868e788..86c4cb8 100644 --- a/providers/softlayer/src/test/java/org/jclouds/softlayer/compute/functions/VirtualGuestToNodeMetadataTest.java +++ b/providers/softlayer/src/test/java/org/jclouds/softlayer/compute/functions/VirtualGuestToNodeMetadataTest.java @@ -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"); + } + }
