diff --git a/compute/src/test/java/org/jclouds/compute/callables/RunScriptOnNodeUsingSshTest.java b/compute/src/test/java/org/jclouds/compute/callables/RunScriptOnNodeUsingSshTest.java index 2a6bed2249..7030c05570 100644 --- a/compute/src/test/java/org/jclouds/compute/callables/RunScriptOnNodeUsingSshTest.java +++ b/compute/src/test/java/org/jclouds/compute/callables/RunScriptOnNodeUsingSshTest.java @@ -126,7 +126,7 @@ public class RunScriptOnNodeUsingSshTest { expect(sshClient.getUsername()).andReturn("tester"); expect(sshClient.getHostAddress()).andReturn("somewhere.example.com"); expect( - sshClient.exec("sudo sh <<'RUN_SCRIPT_AS_ROOT_SSH'\n" + "mkdir -p /home/users\n" + sshClient.exec("sudo sh <<'RUN_SCRIPT_AS_ROOT_SSH'\n" + "mkdir -p /home/users/testuser\n" + "useradd -s /bin/bash -m -d /home/users/testuser testuser\n" + "chown -R testuser /home/users/testuser\n" + "RUN_SCRIPT_AS_ROOT_SSH\n")).andReturn( new ExecResponse("done", null, 0)); diff --git a/compute/src/test/java/org/jclouds/compute/internal/BaseComputeServiceLiveTest.java b/compute/src/test/java/org/jclouds/compute/internal/BaseComputeServiceLiveTest.java index 995eae4d83..d9f512ccfa 100644 --- a/compute/src/test/java/org/jclouds/compute/internal/BaseComputeServiceLiveTest.java +++ b/compute/src/test/java/org/jclouds/compute/internal/BaseComputeServiceLiveTest.java @@ -244,9 +244,9 @@ public abstract class BaseComputeServiceLiveTest extends BaseComputeServiceConte checkNodes(nodes, group, "runScriptWithCreds"); // test adding AdminAccess later changes the default boot user, in this - // case to foo + // case to foo, with home dir /over/ridden/foo ListenableFuture future = client.submitScriptOnNode(node.getId(), AdminAccess.builder() - .adminUsername("foo").build(), nameTask("adminUpdate")); + .adminUsername("foo").adminHome("/over/ridden/foo").build(), nameTask("adminUpdate")); response = future.get(3, TimeUnit.MINUTES); diff --git a/compute/src/test/resources/initscript_with_java.sh b/compute/src/test/resources/initscript_with_java.sh index 093c4c2c2f..f4220a0132 100644 --- a/compute/src/test/resources/initscript_with_java.sh +++ b/compute/src/test/resources/initscript_with_java.sh @@ -182,7 +182,7 @@ END_OF_JCLOUDS_SCRIPT %wheel ALL = (ALL) NOPASSWD:ALL END_OF_JCLOUDS_FILE chmod 0440 /etc/sudoers - mkdir -p /home/users + mkdir -p /home/users/defaultAdminUsername groupadd -f wheel useradd -s /bin/bash -g wheel -m -d /home/users/defaultAdminUsername -p 'crypt(randompassword)' defaultAdminUsername mkdir -p /home/users/defaultAdminUsername/.ssh diff --git a/compute/src/test/resources/initscript_with_jboss.sh b/compute/src/test/resources/initscript_with_jboss.sh index f9bd79504b..031c842642 100644 --- a/compute/src/test/resources/initscript_with_jboss.sh +++ b/compute/src/test/resources/initscript_with_jboss.sh @@ -182,7 +182,7 @@ END_OF_JCLOUDS_SCRIPT %wheel ALL = (ALL) NOPASSWD:ALL END_OF_JCLOUDS_FILE chmod 0440 /etc/sudoers - mkdir -p /home/users + mkdir -p /home/users/web groupadd -f wheel useradd -s /bin/bash -g wheel -m -d /home/users/web -p 'crypt(randompassword)' web mkdir -p /home/users/web/.ssh diff --git a/compute/src/test/resources/runscript_adminUpdate.sh b/compute/src/test/resources/runscript_adminUpdate.sh index 068aa3457b..802e808a9a 100644 --- a/compute/src/test/resources/runscript_adminUpdate.sh +++ b/compute/src/test/resources/runscript_adminUpdate.sh @@ -89,15 +89,15 @@ END_OF_JCLOUDS_SCRIPT %wheel ALL = (ALL) NOPASSWD:ALL END_OF_JCLOUDS_FILE chmod 0440 /etc/sudoers - mkdir -p /home/users + mkdir -p /over/ridden/foo groupadd -f wheel - useradd -s /bin/bash -g wheel -m -d /home/users/foo -p 'crypt(randompassword)' foo - mkdir -p /home/users/foo/.ssh - cat >> /home/users/foo/.ssh/authorized_keys <<-'END_OF_JCLOUDS_FILE' + useradd -s /bin/bash -g wheel -m -d /over/ridden/foo -p 'crypt(randompassword)' foo + mkdir -p /over/ridden/foo/.ssh + cat >> /over/ridden/foo/.ssh/authorized_keys <<-'END_OF_JCLOUDS_FILE' publicKey END_OF_JCLOUDS_FILE - chmod 600 /home/users/foo/.ssh/authorized_keys - chown -R foo /home/users/foo + chmod 600 /over/ridden/foo/.ssh/authorized_keys + chown -R foo /over/ridden/foo exec 3<> /etc/ssh/sshd_config && awk -v TEXT="PasswordAuthentication no PermitRootLogin no " 'BEGIN {print TEXT}{print}' /etc/ssh/sshd_config >&3 diff --git a/scriptbuilder/src/main/java/org/jclouds/scriptbuilder/statements/login/AdminAccess.java b/scriptbuilder/src/main/java/org/jclouds/scriptbuilder/statements/login/AdminAccess.java index 273c106c0e..8557568722 100644 --- a/scriptbuilder/src/main/java/org/jclouds/scriptbuilder/statements/login/AdminAccess.java +++ b/scriptbuilder/src/main/java/org/jclouds/scriptbuilder/statements/login/AdminAccess.java @@ -109,6 +109,7 @@ public class AdminAccess implements Statement { } private String adminUsername; + private String adminHome; private String adminPublicKey; private File adminPublicKeyFile; private String adminPrivateKey; @@ -126,6 +127,11 @@ public class AdminAccess implements Statement { return this; } + public AdminAccess.Builder adminHome(String adminHome) { + this.adminHome = adminHome; + return this; + } + public AdminAccess.Builder adminPassword(String adminPassword) { this.adminPassword = adminPassword; return this; @@ -197,8 +203,8 @@ public class AdminAccess implements Statement { String adminPrivateKey = this.adminPrivateKey; if (adminPrivateKey == null && adminPrivateKeyFile != null) adminPrivateKey = Files.toString(adminPrivateKeyFile, UTF_8); - return new Config(adminUsername, adminPublicKey, adminPrivateKey, adminPassword, loginPassword, lockSsh, - grantSudoToAdminUser, authorizeAdminPublicKey, installAdminPrivateKey, resetLoginPassword, + return new Config(adminUsername, adminHome, adminPublicKey, adminPrivateKey, adminPassword, loginPassword, + lockSsh, grantSudoToAdminUser, authorizeAdminPublicKey, installAdminPrivateKey, resetLoginPassword, cryptFunction); } catch (IOException e) { throw Throwables.propagate(e); @@ -208,6 +214,7 @@ public class AdminAccess implements Statement { protected static class Config { private final String adminUsername; + private final String adminHome; private final String adminPublicKey; private final String adminPrivateKey; private final String adminPassword; @@ -220,11 +227,12 @@ public class AdminAccess implements Statement { private final Function cryptFunction; private final Credentials adminCredentials; - protected Config(@Nullable String adminUsername, @Nullable String adminPublicKey, + protected Config(@Nullable String adminUsername, @Nullable String adminHome, @Nullable String adminPublicKey, @Nullable String adminPrivateKey, @Nullable String adminPassword, @Nullable String loginPassword, boolean lockSsh, boolean grantSudoToAdminUser, boolean authorizeAdminPublicKey, boolean installAdminPrivateKey, boolean resetLoginPassword, Function cryptFunction) { this.adminUsername = adminUsername; + this.adminHome = adminHome; this.adminPublicKey = adminPublicKey; this.adminPrivateKey = adminPrivateKey; this.adminPassword = adminPassword; @@ -245,6 +253,10 @@ public class AdminAccess implements Statement { return adminUsername; } + public String getAdminHome() { + return adminHome; + } + public String getAdminPublicKey() { return adminPublicKey; } @@ -324,6 +336,7 @@ public class AdminAccess implements Statement { Builder builder = AdminAccess.builder(configuration.cryptFunction()); builder.adminUsername(config.getAdminUsername() != null ? config.getAdminUsername() : configuration .defaultAdminUsername().get()); + builder.adminHome(config.getAdminHome()); builder.adminPassword(config.getAdminPassword() != null ? config.getAdminPassword() : configuration .passwordGenerator().get()); Map adminSshKeys = (config.getAdminPublicKey() != null && config.getAdminPrivateKey() != null) ? ImmutableMap @@ -363,6 +376,8 @@ public class AdminAccess implements Statement { ImmutableList.Builder statements = ImmutableList.builder(); UserAdd.Builder userBuilder = UserAdd.builder(); userBuilder.login(config.getAdminUsername()); + if (config.getAdminHome() != null) + userBuilder.home(config.getAdminHome()); if (config.shouldAuthorizeAdminPublicKey()) userBuilder.authorizeRSAPublicKey(config.getAdminPublicKey()); userBuilder.password(config.getAdminPassword()); diff --git a/scriptbuilder/src/main/java/org/jclouds/scriptbuilder/statements/login/UserAdd.java b/scriptbuilder/src/main/java/org/jclouds/scriptbuilder/statements/login/UserAdd.java index 22dccd9492..14751d1fbe 100644 --- a/scriptbuilder/src/main/java/org/jclouds/scriptbuilder/statements/login/UserAdd.java +++ b/scriptbuilder/src/main/java/org/jclouds/scriptbuilder/statements/login/UserAdd.java @@ -60,6 +60,7 @@ public class UserAdd implements Statement { public static class Builder { private String defaultHome = "/home/users"; + private String home; private String login; private String password; private String RSAPrivateKey; @@ -67,6 +68,17 @@ public class UserAdd implements Statement { private List authorizeRSAPublicKeys = Lists.newArrayList(); private String shell = "/bin/bash"; + /** + * See --home in `man useradd`. + */ + public UserAdd.Builder home(String home) { + this.home = home; + return this; + } + + /** + * See --base-dir in `man useradd`. + */ public UserAdd.Builder defaultHome(String defaultHome) { this.defaultHome = defaultHome; return this; @@ -115,22 +127,29 @@ public class UserAdd implements Statement { } public UserAdd build() { - return new UserAdd(login, groups, password, RSAPrivateKey, authorizeRSAPublicKeys, defaultHome, shell); + return new UserAdd(login, groups, password, RSAPrivateKey, authorizeRSAPublicKeys, home, defaultHome, shell); } } public UserAdd(String login, List groups, @Nullable String password, @Nullable String installRSAPrivateKey, List authorizeRSAPublicKeys, String defaultHome, String shell) { + this(login, groups, password, installRSAPrivateKey, authorizeRSAPublicKeys, null, defaultHome, shell); + } + + public UserAdd(String login, List groups, @Nullable String password, @Nullable String installRSAPrivateKey, + List authorizeRSAPublicKeys, @Nullable String home, String defaultHome, String shell) { this.login = checkNotNull(login, "login"); this.password = password; this.groups = ImmutableList.copyOf(checkNotNull(groups, "groups")); this.installRSAPrivateKey = installRSAPrivateKey; this.authorizeRSAPublicKeys = ImmutableList .copyOf(checkNotNull(authorizeRSAPublicKeys, "authorizeRSAPublicKeys")); + this.home = home; this.defaultHome = checkNotNull(defaultHome, "defaultHome"); this.shell = checkNotNull(shell, "shell"); } + private final String home; private final String defaultHome; private final String login; private final List groups; @@ -159,10 +178,10 @@ public class UserAdd implements Statement { checkNotNull(family, "family"); if (family == OsFamily.WINDOWS) throw new UnsupportedOperationException("windows not yet implemented"); - String homeDir = defaultHome + "{fs}" + login; + String homeDir = (home != null) ? home : (defaultHome + "{fs}" + login); ImmutableList.Builder statements = ImmutableList.builder(); // useradd cannot create the default homedir - statements.add(Statements.exec("{md} " + defaultHome)); + statements.add(Statements.exec("{md} " + homeDir)); ImmutableMap.Builder userAddOptions = ImmutableMap.builder(); userAddOptions.put("-s", shell); diff --git a/scriptbuilder/src/test/java/org/jclouds/scriptbuilder/statements/login/AdminAccessTest.java b/scriptbuilder/src/test/java/org/jclouds/scriptbuilder/statements/login/AdminAccessTest.java index 0d389fec19..2aad9257df 100644 --- a/scriptbuilder/src/test/java/org/jclouds/scriptbuilder/statements/login/AdminAccessTest.java +++ b/scriptbuilder/src/test/java/org/jclouds/scriptbuilder/statements/login/AdminAccessTest.java @@ -52,8 +52,9 @@ public class AdminAccessTest { try { assertEquals( AdminAccess.builder().adminPassword("bar").adminPrivateKey("fooPrivateKey") - .adminPublicKey("fooPublicKey").adminUsername("foo").build().init(TestConfiguration.INSTANCE) - .render(OsFamily.UNIX), CharStreams.toString(Resources.newReaderSupplier( + .adminPublicKey("fooPublicKey").adminUsername("foo").adminHome("/over/ridden/foo").build() + .init(TestConfiguration.INSTANCE).render(OsFamily.UNIX), + CharStreams.toString(Resources.newReaderSupplier( Resources.getResource("test_adminaccess_params.sh"), Charsets.UTF_8))); } finally { TestConfiguration.INSTANCE.reset(); diff --git a/scriptbuilder/src/test/java/org/jclouds/scriptbuilder/statements/login/UserAddTest.java b/scriptbuilder/src/test/java/org/jclouds/scriptbuilder/statements/login/UserAddTest.java index e9d6bf3ecc..a41a60fa6d 100644 --- a/scriptbuilder/src/test/java/org/jclouds/scriptbuilder/statements/login/UserAddTest.java +++ b/scriptbuilder/src/test/java/org/jclouds/scriptbuilder/statements/login/UserAddTest.java @@ -33,41 +33,51 @@ public class UserAddTest { public void testUNIX() { assertEquals(UserAdd.builder().login("me").build().render(OsFamily.UNIX), - "mkdir -p /home/users\nuseradd -s /bin/bash -m -d /home/users/me me\nchown -R me /home/users/me\n"); + "mkdir -p /home/users/me\nuseradd -s /bin/bash -m -d /home/users/me me\nchown -R me /home/users/me\n"); } public void testWithBaseUNIX() { assertEquals(UserAdd.builder().login("me").defaultHome("/export/home").build().render(OsFamily.UNIX), - "mkdir -p /export/home\nuseradd -s /bin/bash -m -d /export/home/me me\nchown -R me /export/home/me\n"); + "mkdir -p /export/home/me\nuseradd -s /bin/bash -m -d /export/home/me me\nchown -R me /export/home/me\n"); } public void testWithGroupUNIX() { assertEquals(UserAdd.builder().login("me").group("wheel").build().render(OsFamily.UNIX), - "mkdir -p /home/users\ngroupadd -f wheel\nuseradd -s /bin/bash -g wheel -m -d /home/users/me me\nchown -R me /home/users/me\n"); + "mkdir -p /home/users/me\ngroupadd -f wheel\nuseradd -s /bin/bash -g wheel -m -d /home/users/me me\nchown -R me /home/users/me\n"); } public void testWithGroupsUNIX() { assertEquals(UserAdd.builder().login("me").groups(ImmutableList.of("wheel", "candy")).build().render( OsFamily.UNIX), - "mkdir -p /home/users\ngroupadd -f wheel\ngroupadd -f candy\nuseradd -s /bin/bash -g wheel -G candy -m -d /home/users/me me\nchown -R me /home/users/me\n"); + "mkdir -p /home/users/me\ngroupadd -f wheel\ngroupadd -f candy\nuseradd -s /bin/bash -g wheel -G candy -m -d /home/users/me me\nchown -R me /home/users/me\n"); } public void testWithPasswordUNIX() { String userAdd = UserAdd.builder().login("me").password("foo").group("wheel").build().render(OsFamily.UNIX); - assert userAdd.startsWith("mkdir -p /home/users\ngroupadd -f wheel\nuseradd -s /bin/bash -g wheel -m -d /home/users/me -p '$6$") : userAdd; + assert userAdd.startsWith("mkdir -p /home/users/me\ngroupadd -f wheel\nuseradd -s /bin/bash -g wheel -m -d /home/users/me -p '$6$") : userAdd; assert userAdd.endsWith("' me\nchown -R me /home/users/me\n") : userAdd; } public void testWithSshAuthorizedKeyUNIX() { assertEquals( UserAdd.builder().login("me").authorizeRSAPublicKey("rsapublickey").build().render(OsFamily.UNIX), - "mkdir -p /home/users\nuseradd -s /bin/bash -m -d /home/users/me me\nmkdir -p /home/users/me/.ssh\ncat >> /home/users/me/.ssh/authorized_keys <<-'END_OF_JCLOUDS_FILE'\n\trsapublickey\nEND_OF_JCLOUDS_FILE\nchmod 600 /home/users/me/.ssh/authorized_keys\nchown -R me /home/users/me\n"); + "mkdir -p /home/users/me\nuseradd -s /bin/bash -m -d /home/users/me me\nmkdir -p /home/users/me/.ssh\ncat >> /home/users/me/.ssh/authorized_keys <<-'END_OF_JCLOUDS_FILE'\n\trsapublickey\nEND_OF_JCLOUDS_FILE\nchmod 600 /home/users/me/.ssh/authorized_keys\nchown -R me /home/users/me\n"); } public void testWithSshInstalledKeyUNIX() { assertEquals( UserAdd.builder().login("me").installRSAPrivateKey("rsaprivate").build().render(OsFamily.UNIX), - "mkdir -p /home/users\nuseradd -s /bin/bash -m -d /home/users/me me\nmkdir -p /home/users/me/.ssh\nrm /home/users/me/.ssh/id_rsa\ncat >> /home/users/me/.ssh/id_rsa <<-'END_OF_JCLOUDS_FILE'\n\trsaprivate\nEND_OF_JCLOUDS_FILE\nchmod 600 /home/users/me/.ssh/id_rsa\nchown -R me /home/users/me\n"); + "mkdir -p /home/users/me\nuseradd -s /bin/bash -m -d /home/users/me me\nmkdir -p /home/users/me/.ssh\nrm /home/users/me/.ssh/id_rsa\ncat >> /home/users/me/.ssh/id_rsa <<-'END_OF_JCLOUDS_FILE'\n\trsaprivate\nEND_OF_JCLOUDS_FILE\nchmod 600 /home/users/me/.ssh/id_rsa\nchown -R me /home/users/me\n"); + } + + public void testWithHomeUNIX() { + assertEquals(UserAdd.builder().login("me").home("/myhome/myme").build().render( + OsFamily.UNIX), + "mkdir -p /myhome/myme\nuseradd -s /bin/bash -m -d /myhome/myme me\nchown -R me /myhome/myme\n"); + + assertEquals(UserAdd.builder().login("me").home("/myhome/myme").defaultHome("/ignoreddefault").build().render( + OsFamily.UNIX), + "mkdir -p /myhome/myme\nuseradd -s /bin/bash -m -d /myhome/myme me\nchown -R me /myhome/myme\n"); } @Test(expectedExceptions = UnsupportedOperationException.class) diff --git a/scriptbuilder/src/test/resources/test_adminaccess_params.sh b/scriptbuilder/src/test/resources/test_adminaccess_params.sh index 6f1e1d0589..30fd511d57 100644 --- a/scriptbuilder/src/test/resources/test_adminaccess_params.sh +++ b/scriptbuilder/src/test/resources/test_adminaccess_params.sh @@ -3,15 +3,15 @@ cat > /etc/sudoers <<-'END_OF_JCLOUDS_FILE' %wheel ALL = (ALL) NOPASSWD:ALL END_OF_JCLOUDS_FILE chmod 0440 /etc/sudoers -mkdir -p /home/users +mkdir -p /over/ridden/foo groupadd -f wheel -useradd -s /bin/bash -g wheel -m -d /home/users/foo -p 'crypt(bar)' foo -mkdir -p /home/users/foo/.ssh -cat >> /home/users/foo/.ssh/authorized_keys <<-'END_OF_JCLOUDS_FILE' +useradd -s /bin/bash -g wheel -m -d /over/ridden/foo -p 'crypt(bar)' foo +mkdir -p /over/ridden/foo/.ssh +cat >> /over/ridden/foo/.ssh/authorized_keys <<-'END_OF_JCLOUDS_FILE' fooPublicKey END_OF_JCLOUDS_FILE -chmod 600 /home/users/foo/.ssh/authorized_keys -chown -R foo /home/users/foo +chmod 600 /over/ridden/foo/.ssh/authorized_keys +chown -R foo /over/ridden/foo exec 3<> /etc/ssh/sshd_config && awk -v TEXT="PasswordAuthentication no PermitRootLogin no " 'BEGIN {print TEXT}{print}' /etc/ssh/sshd_config >&3 diff --git a/scriptbuilder/src/test/resources/test_adminaccess_plainuser.sh b/scriptbuilder/src/test/resources/test_adminaccess_plainuser.sh index 68325f9e01..e63f6f2269 100644 --- a/scriptbuilder/src/test/resources/test_adminaccess_plainuser.sh +++ b/scriptbuilder/src/test/resources/test_adminaccess_plainuser.sh @@ -1,4 +1,4 @@ -mkdir -p /home/users +mkdir -p /home/users/defaultAdminUsername useradd -s /bin/bash -m -d /home/users/defaultAdminUsername -p 'crypt(0)' defaultAdminUsername mkdir -p /home/users/defaultAdminUsername/.ssh cat >> /home/users/defaultAdminUsername/.ssh/authorized_keys <<-'END_OF_JCLOUDS_FILE' diff --git a/scriptbuilder/src/test/resources/test_adminaccess_standard.sh b/scriptbuilder/src/test/resources/test_adminaccess_standard.sh index 28d184988a..6c48413996 100644 --- a/scriptbuilder/src/test/resources/test_adminaccess_standard.sh +++ b/scriptbuilder/src/test/resources/test_adminaccess_standard.sh @@ -3,7 +3,7 @@ cat > /etc/sudoers <<-'END_OF_JCLOUDS_FILE' %wheel ALL = (ALL) NOPASSWD:ALL END_OF_JCLOUDS_FILE chmod 0440 /etc/sudoers -mkdir -p /home/users +mkdir -p /home/users/defaultAdminUsername groupadd -f wheel useradd -s /bin/bash -g wheel -m -d /home/users/defaultAdminUsername -p 'crypt(0)' defaultAdminUsername mkdir -p /home/users/defaultAdminUsername/.ssh