diff --git a/scriptbuilder/src/main/java/org/jclouds/scriptbuilder/functionloader/FunctionNotFoundException.java b/scriptbuilder/src/main/java/org/jclouds/scriptbuilder/functionloader/FunctionNotFoundException.java index ba0650997a..8eac699de3 100644 --- a/scriptbuilder/src/main/java/org/jclouds/scriptbuilder/functionloader/FunctionNotFoundException.java +++ b/scriptbuilder/src/main/java/org/jclouds/scriptbuilder/functionloader/FunctionNotFoundException.java @@ -22,6 +22,8 @@ import org.jclouds.scriptbuilder.domain.OsFamily; public class FunctionNotFoundException extends RuntimeException { + private static final long serialVersionUID = 1L; + public FunctionNotFoundException(String functionName, OsFamily family) { super("function: " + functionName + " not found for family: " + family); } diff --git a/scriptbuilder/src/main/java/org/jclouds/scriptbuilder/statements/chef/ChefSolo.java b/scriptbuilder/src/main/java/org/jclouds/scriptbuilder/statements/chef/ChefSolo.java index 9027869907..bcdc270bd8 100644 --- a/scriptbuilder/src/main/java/org/jclouds/scriptbuilder/statements/chef/ChefSolo.java +++ b/scriptbuilder/src/main/java/org/jclouds/scriptbuilder/statements/chef/ChefSolo.java @@ -73,6 +73,7 @@ public class ChefSolo implements Statement { private List roles = Lists.newArrayList(); private List databags = Lists.newArrayList(); private RunList runlist; + private String chefVersion; /** * Directory where Chef Solo will store files. @@ -232,13 +233,22 @@ public class ChefSolo implements Statement { return this; } + /** + * The version of the Chef gem to install. + */ + public Builder chefVersion(String chefVersion) { + this.chefVersion = checkNotNull(chefVersion, "chefVersion"); + return this; + } + public ChefSolo build() { return new ChefSolo(Optional.of(fileCachePath), Optional.fromNullable(rolePath), Optional.fromNullable(databagPath), Optional.of(cookbookPath.build()), Optional.fromNullable(cookbooksArchiveLocation), Optional.fromNullable(jsonAttributes), Optional.fromNullable(group), Optional.fromNullable(interval), Optional.fromNullable(logLevel), Optional.fromNullable(logFile), Optional.fromNullable(nodeName), Optional.fromNullable(splay), - Optional.fromNullable(user), Optional.of(roles), Optional.of(databags), Optional.fromNullable(runlist)); + Optional.fromNullable(user), Optional.of(roles), Optional.of(databags), Optional.fromNullable(runlist), + Optional.fromNullable(chefVersion)); } } @@ -259,13 +269,14 @@ public class ChefSolo implements Statement { private Optional> roles; private Optional> databags; private RunList runlist; - private final InstallChefGems installChefGems = new InstallChefGems(); + private final InstallChefGems installChefGems; public ChefSolo(Optional fileCachePath, Optional rolePath, Optional databagPath, Optional> cookbookPath, Optional cookbooksArchiveLocation, Optional jsonAttributes, Optional group, Optional interval, Optional logLevel, Optional logFile, Optional nodeName, Optional splay, - Optional user, Optional> roles, Optional> databags, Optional runlist) { + Optional user, Optional> roles, Optional> databags, + Optional runlist, Optional chefVersion) { this.fileCachePath = checkNotNull(fileCachePath, "fileCachePath must be set").or(DEFAULT_SOLO_PATH); this.rolePath = checkNotNull(rolePath, "rolePath must be set").or(this.fileCachePath + "/roles"); this.databagPath = checkNotNull(databagPath, "databagPath must be set").or(this.fileCachePath + "/data_bags"); @@ -281,11 +292,13 @@ public class ChefSolo implements Statement { this.roles = checkNotNull(roles, "roles must be set"); this.databags = checkNotNull(databags, "databags must be set"); this.runlist = checkNotNull(runlist, "runlist must be set").or(RunList.builder().build()); + this.user = checkNotNull(user, "chefVersion must be set"); if (!checkNotNull(cookbookPath, "cookbookPath must be set").isPresent() || cookbookPath.get().isEmpty()) { this.cookbookPath = ImmutableList. of(this.fileCachePath + "/cookbooks"); } else { this.cookbookPath = ImmutableList. copyOf(cookbookPath.get()); } + this.installChefGems = InstallChefGems.builder().version(chefVersion.orNull()).build(); } @Override diff --git a/scriptbuilder/src/main/java/org/jclouds/scriptbuilder/statements/chef/InstallChefGems.java b/scriptbuilder/src/main/java/org/jclouds/scriptbuilder/statements/chef/InstallChefGems.java index 9128588999..5d259572d5 100644 --- a/scriptbuilder/src/main/java/org/jclouds/scriptbuilder/statements/chef/InstallChefGems.java +++ b/scriptbuilder/src/main/java/org/jclouds/scriptbuilder/statements/chef/InstallChefGems.java @@ -20,21 +20,46 @@ package org.jclouds.scriptbuilder.statements.chef; import static org.jclouds.scriptbuilder.domain.Statements.exec; +import org.jclouds.javax.annotation.Nullable; import org.jclouds.scriptbuilder.domain.OsFamily; -import org.jclouds.scriptbuilder.domain.StatementList; -import org.jclouds.scriptbuilder.statements.ruby.InstallRuby; +import org.jclouds.scriptbuilder.domain.Statement; + +import com.google.common.base.Optional; +import com.google.common.collect.ImmutableSet; /** * Installs Chef gems onto a host. * * @author Ignasi Barrera */ -public class InstallChefGems extends StatementList { +public class InstallChefGems implements Statement { - public InstallChefGems() { - // Chef versions prior to 10.16.4 install an incompatible moneta gem. - // See: http://tickets.opscode.com/browse/CHEF-3721 - super(new InstallRuby(), exec("gem install chef --no-rdoc --no-ri")); + public static Builder builder() { + return new Builder(); + } + + public static class Builder { + private Optional version = Optional.absent(); + + /** + * The version of the Chef gem to install. + *

+ * Can be something like '>= 0.10.8'. + */ + public Builder version(@Nullable String version) { + this.version = Optional.fromNullable(version); + return this; + } + + public InstallChefGems build() { + return new InstallChefGems(version); + } + } + + private Optional version; + + public InstallChefGems(Optional version) { + this.version = version; } @Override @@ -42,7 +67,16 @@ public class InstallChefGems extends StatementList { if (family == OsFamily.WINDOWS) { throw new UnsupportedOperationException("windows not yet implemented"); } - return super.render(family); + + Statement statement = version.isPresent() ? exec(String.format("gem install chef -v '%s' --no-rdoc --no-ri", + version.get())) : exec("gem install chef --no-rdoc --no-ri"); + + return statement.render(family); + } + + @Override + public Iterable functionDependencies(OsFamily family) { + return ImmutableSet. of(); } } diff --git a/scriptbuilder/src/main/java/org/jclouds/scriptbuilder/statements/ruby/InstallRuby.java b/scriptbuilder/src/main/java/org/jclouds/scriptbuilder/statements/ruby/InstallRuby.java index 833882baca..896512601f 100644 --- a/scriptbuilder/src/main/java/org/jclouds/scriptbuilder/statements/ruby/InstallRuby.java +++ b/scriptbuilder/src/main/java/org/jclouds/scriptbuilder/statements/ruby/InstallRuby.java @@ -19,41 +19,19 @@ package org.jclouds.scriptbuilder.statements.ruby; import static org.jclouds.scriptbuilder.domain.Statements.call; -import static org.jclouds.scriptbuilder.domain.Statements.exec; -import static org.jclouds.scriptbuilder.domain.Statements.extractTargzAndFlattenIntoDirectory; - -import java.net.URI; import org.jclouds.scriptbuilder.domain.OsFamily; -import org.jclouds.scriptbuilder.domain.Statement; import org.jclouds.scriptbuilder.domain.StatementList; /** - * Installs Ruby and Rubygems gems onto a host. + * Installs Ruby onto a host. * * @author Ignasi Barrera */ public class InstallRuby extends StatementList { - private static final URI RUBYGEMS_URI = URI.create("http://production.cf.rubygems.org/rubygems/rubygems-1.8.10.tgz"); - - public static Statement installRubyGems() { - return new StatementList(// - exec("if ! hash gem 2>/dev/null; then"), // - exec("("), // - extractTargzAndFlattenIntoDirectory(RUBYGEMS_URI, "/tmp/rubygems"), // - exec("{cd} /tmp/rubygems"), // - exec("ruby setup.rb --no-format-executable"), // - exec("{rm} -fr /tmp/rubygems"), // - exec(")"), // - exec("fi"), // - // Make sure RubyGems is up to date - exec("gem update --system"), // - exec("gem update --no-rdoc --no-ri")); - } - public InstallRuby() { - super(call("setupPublicCurl"), call("installRuby"), installRubyGems()); + super(call("setupPublicCurl"), call("installRuby")); } @Override diff --git a/scriptbuilder/src/main/java/org/jclouds/scriptbuilder/statements/ruby/InstallRubyGems.java b/scriptbuilder/src/main/java/org/jclouds/scriptbuilder/statements/ruby/InstallRubyGems.java new file mode 100644 index 0000000000..1b4e14a62f --- /dev/null +++ b/scriptbuilder/src/main/java/org/jclouds/scriptbuilder/statements/ruby/InstallRubyGems.java @@ -0,0 +1,144 @@ +/** + * 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.scriptbuilder.statements.ruby; + +import static com.google.common.base.Preconditions.checkNotNull; +import static org.jclouds.scriptbuilder.domain.Statements.exec; +import static org.jclouds.scriptbuilder.domain.Statements.extractTargzAndFlattenIntoDirectory; + +import java.net.URI; + +import org.jclouds.javax.annotation.Nullable; +import org.jclouds.scriptbuilder.domain.OsFamily; +import org.jclouds.scriptbuilder.domain.Statement; +import org.jclouds.scriptbuilder.domain.StatementList; + +import com.google.common.base.Optional; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; + +/** + * Installs RubyGems onto a host. + * + * @author Ignasi Barrera + */ +public class InstallRubyGems implements Statement { + + public static final String DEFAULT_RUBYGEMS_VERSION = "1.8.10"; + private static final String RUBYGEMS_URI_TEMPLATE = "http://production.cf.rubygems.org/rubygems/rubygems-%s.tgz"; + + public static Builder builder() { + return new Builder(); + } + + public static class Builder { + private Optional version = Optional.absent(); + private boolean updateSystem = false; + private Optional updateSystemVersion = Optional.absent(); + private boolean updateExistingGems = false; + + /** + * The version of RubyGems to install. + */ + public Builder version(@Nullable String version) { + this.version = Optional.fromNullable(version); + return this; + } + + /** + * Update the gem system after installing RubyGems. + */ + public Builder updateSystem(boolean updateSystem) { + this.updateSystem = updateSystem; + this.updateSystemVersion = Optional.absent(); + return this; + } + + /** + * Update the gem system after installing RubyGems, forcing the update to + * a concrete version. + */ + public Builder updateSystem(boolean updateSystem, @Nullable String updateSystemVersion) { + this.updateSystem = updateSystem; + this.updateSystemVersion = Optional.fromNullable(updateSystemVersion); + return this; + } + + /** + * Update the existing gems after installing RubyGems. + */ + public Builder updateExistingGems(boolean updateExistingGems) { + this.updateExistingGems = updateExistingGems; + return this; + } + + public InstallRubyGems build() { + return new InstallRubyGems(version, updateSystem, updateSystemVersion, updateExistingGems); + } + + } + + private Optional version; + private boolean updateSystem; + private Optional updateSystemVersion; + private boolean updateExistingGems; + + public InstallRubyGems(Optional version, boolean updateSystem, Optional updateSystemVersion, + boolean updateExistingGems) { + this.version = checkNotNull(version, "version must be set"); + this.updateSystem = updateSystem; + this.updateSystemVersion = checkNotNull(updateSystemVersion, "updateSystemVersion must be set"); + this.updateExistingGems = updateExistingGems; + } + + @Override + public String render(OsFamily family) { + if (family == OsFamily.WINDOWS) { + throw new UnsupportedOperationException("windows not yet implemented"); + } + + URI rubygemsUri = URI.create(String.format(RUBYGEMS_URI_TEMPLATE, version.or(DEFAULT_RUBYGEMS_VERSION))); + + ImmutableList.Builder statements = ImmutableList.builder(); + statements.add(exec("if ! hash gem 2>/dev/null; then")); + statements.add(exec("(")); + statements.add(extractTargzAndFlattenIntoDirectory(rubygemsUri, "/tmp/rubygems")); + statements.add(exec("{cd} /tmp/rubygems")); + statements.add(exec("ruby setup.rb --no-format-executable")); + statements.add(exec("{rm} -fr /tmp/rubygems")); + statements.add(exec(")")); + statements.add(exec("fi")); + + if (updateSystem) { + statements.add(updateSystemVersion.isPresent() ? exec("gem update --system " + updateSystemVersion.get()) + : exec("gem update --system")); + } + if (updateExistingGems) { + statements.add(exec("gem update --no-rdoc --no-ri")); + } + + return new StatementList(statements.build()).render(family); + } + + @Override + public Iterable functionDependencies(OsFamily family) { + return ImmutableSet. of(); + } + +} diff --git a/scriptbuilder/src/test/java/org/jclouds/scriptbuilder/ScriptBuilderTest.java b/scriptbuilder/src/test/java/org/jclouds/scriptbuilder/ScriptBuilderTest.java index f45ae0fc45..c550f49535 100644 --- a/scriptbuilder/src/test/java/org/jclouds/scriptbuilder/ScriptBuilderTest.java +++ b/scriptbuilder/src/test/java/org/jclouds/scriptbuilder/ScriptBuilderTest.java @@ -26,7 +26,6 @@ import static org.jclouds.scriptbuilder.domain.Statements.kill; import static org.jclouds.scriptbuilder.domain.Statements.newStatementList; import static org.jclouds.scriptbuilder.domain.Statements.switchArg; import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertTrue; import java.io.IOException; import java.net.MalformedURLException; diff --git a/scriptbuilder/src/test/java/org/jclouds/scriptbuilder/domain/SwitchArgTest.java b/scriptbuilder/src/test/java/org/jclouds/scriptbuilder/domain/SwitchArgTest.java index 7f5b6bb7c5..bd36e59bde 100644 --- a/scriptbuilder/src/test/java/org/jclouds/scriptbuilder/domain/SwitchArgTest.java +++ b/scriptbuilder/src/test/java/org/jclouds/scriptbuilder/domain/SwitchArgTest.java @@ -23,8 +23,6 @@ import static org.jclouds.scriptbuilder.domain.Statements.interpret; import static org.jclouds.scriptbuilder.domain.Statements.newStatementList; import static org.testng.Assert.assertEquals; -import java.util.Collections; - import org.testng.annotations.Test; import com.google.common.collect.ImmutableList; diff --git a/scriptbuilder/src/test/java/org/jclouds/scriptbuilder/statements/chef/ChefSoloTest.java b/scriptbuilder/src/test/java/org/jclouds/scriptbuilder/statements/chef/ChefSoloTest.java index 8f423ba8a1..e2d36d7b67 100644 --- a/scriptbuilder/src/test/java/org/jclouds/scriptbuilder/statements/chef/ChefSoloTest.java +++ b/scriptbuilder/src/test/java/org/jclouds/scriptbuilder/statements/chef/ChefSoloTest.java @@ -26,17 +26,14 @@ import static org.testng.Assert.assertTrue; import java.io.IOException; import org.jclouds.scriptbuilder.domain.OsFamily; -import org.jclouds.scriptbuilder.domain.ShellToken; import org.jclouds.scriptbuilder.domain.Statement; import org.jclouds.scriptbuilder.domain.chef.DataBag; import org.jclouds.scriptbuilder.domain.chef.Role; import org.jclouds.scriptbuilder.domain.chef.RunList; import org.testng.annotations.Test; -import com.google.common.base.Charsets; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; -import com.google.common.io.Resources; /** * Unit tests for the {@link ChefSoloTest} statement. @@ -380,9 +377,18 @@ public class ChefSoloTest { + "chef-solo -c /var/chef/solo.rb -j /var/chef/node.json -N `hostname` -u foo\n"); } + public void testChefSoloWithChefGemVersion() throws IOException { + String script = ChefSolo.builder().chefVersion(">= 0.10.8").build().render(OsFamily.UNIX); + assertEquals(script, installChefGems(">= 0.10.8") + createConfigFile() + createNodeFile() + + "chef-solo -c /var/chef/solo.rb -j /var/chef/node.json -N `hostname`\n"); + } + private static String installChefGems() throws IOException { - return Resources.toString(Resources.getResource("test_install_ruby." + ShellToken.SH.to(OsFamily.UNIX)), - Charsets.UTF_8) + "gem install chef --no-rdoc --no-ri\n"; + return "gem install chef --no-rdoc --no-ri\n"; + } + + private static String installChefGems(String version) throws IOException { + return "gem install chef -v '" + version + "' --no-rdoc --no-ri\n"; } private static String createConfigFile() { diff --git a/scriptbuilder/src/test/java/org/jclouds/scriptbuilder/statements/chef/InstallChefGemsTest.java b/scriptbuilder/src/test/java/org/jclouds/scriptbuilder/statements/chef/InstallChefGemsTest.java index 2f9ad7df74..d828c2ea10 100644 --- a/scriptbuilder/src/test/java/org/jclouds/scriptbuilder/statements/chef/InstallChefGemsTest.java +++ b/scriptbuilder/src/test/java/org/jclouds/scriptbuilder/statements/chef/InstallChefGemsTest.java @@ -40,21 +40,22 @@ public class InstallChefGemsTest { @Test(expectedExceptions = UnsupportedOperationException.class, expectedExceptionsMessageRegExp = "windows not yet implemented") public void installChefGemsInWindows() { - new InstallChefGems().render(OsFamily.WINDOWS); + InstallChefGems.builder().build().render(OsFamily.WINDOWS); } public void installChefGemsUnix() throws IOException { - assertEquals( - new InstallChefGems().render(OsFamily.UNIX), - Resources.toString(Resources.getResource("test_install_ruby." + ShellToken.SH.to(OsFamily.UNIX)), - Charsets.UTF_8) + "gem install chef --no-rdoc --no-ri\n"); + assertEquals(InstallChefGems.builder().build().render(OsFamily.UNIX), "gem install chef --no-rdoc --no-ri\n"); } - public void installChefGemsUnixInScriptBuilderSourcesSetupPublicCurl() throws IOException { - assertEquals( - InitScript.builder().name("install_chef_gems").run(new InstallChefGems()).build().render(OsFamily.UNIX), - Resources.toString( - Resources.getResource("test_install_chef_gems_scriptbuilder." + ShellToken.SH.to(OsFamily.UNIX)), - Charsets.UTF_8)); + public void installChefGemsUnixWithCustomVersion() throws IOException { + assertEquals(InstallChefGems.builder().version(">= 0.10.8").build().render(OsFamily.UNIX), + "gem install chef -v '>= 0.10.8' --no-rdoc --no-ri\n"); + } + + public void installChefGemsUnixInScriptBuilder() throws IOException { + assertEquals(InitScript.builder().name("install_chef_gems").run(InstallChefGems.builder().build()).build() + .render(OsFamily.UNIX), Resources.toString( + Resources.getResource("test_install_chef_gems_scriptbuilder." + ShellToken.SH.to(OsFamily.UNIX)), + Charsets.UTF_8)); } } diff --git a/scriptbuilder/src/test/java/org/jclouds/scriptbuilder/statements/ruby/InstallRubyGemsTest.java b/scriptbuilder/src/test/java/org/jclouds/scriptbuilder/statements/ruby/InstallRubyGemsTest.java new file mode 100644 index 0000000000..7c61b2f879 --- /dev/null +++ b/scriptbuilder/src/test/java/org/jclouds/scriptbuilder/statements/ruby/InstallRubyGemsTest.java @@ -0,0 +1,112 @@ +/** + * 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.scriptbuilder.statements.ruby; + +import static org.jclouds.scriptbuilder.statements.ruby.InstallRubyGems.DEFAULT_RUBYGEMS_VERSION; +import static org.testng.Assert.assertEquals; + +import java.io.IOException; + +import org.jclouds.scriptbuilder.InitScript; +import org.jclouds.scriptbuilder.domain.OsFamily; +import org.jclouds.scriptbuilder.domain.ShellToken; +import org.testng.annotations.Test; + +import com.google.common.base.Charsets; +import com.google.common.io.Resources; + +/** + * Unit tests for the {@link InstallRubyGemsTest} statement. + * + * @author Ignasi Barrera + */ +@Test(groups = "unit", testName = "InstallRubyGemsTest") +public class InstallRubyGemsTest { + + @Test(expectedExceptions = UnsupportedOperationException.class, expectedExceptionsMessageRegExp = "windows not yet implemented") + public void installRubyGemsInWindows() { + new InstallRuby().render(OsFamily.WINDOWS); + } + + public void installRubyGemsDefaultsUnix() throws IOException { + assertEquals(InstallRubyGems.builder().build().render(OsFamily.UNIX), installRubyGems(DEFAULT_RUBYGEMS_VERSION)); + } + + public void installRubyGemsForcingVersion() throws IOException { + assertEquals(InstallRubyGems.builder().version("1.8.25").build().render(OsFamily.UNIX), installRubyGems("1.8.25")); + } + + public void installRubyGemsAndUpdateSystem() throws IOException { + assertEquals(InstallRubyGems.builder().updateSystem(true).build().render(OsFamily.UNIX), + installRubyGems(DEFAULT_RUBYGEMS_VERSION) + updateSystem(null)); + } + + public void installRubyGemsAndUpdateSystemForcingUpdateVersion() throws IOException { + assertEquals(InstallRubyGems.builder().updateSystem(true, "1.8.25").build().render(OsFamily.UNIX), + installRubyGems(DEFAULT_RUBYGEMS_VERSION) + updateSystem("1.8.25")); + } + + public void installRubyGemsAndUpdateGems() throws IOException { + assertEquals(InstallRubyGems.builder().updateExistingGems(true).build().render(OsFamily.UNIX), + installRubyGems(DEFAULT_RUBYGEMS_VERSION) + updateGems()); + } + + public void installRubyGemsUpdatingSystemAndGems() throws IOException { + assertEquals(InstallRubyGems.builder().version("1.2.3").updateSystem(true, "1.2.4").updateExistingGems(true) + .build().render(OsFamily.UNIX), installRubyGems("1.2.3") + updateSystem("1.2.4") + updateGems()); + } + + public void installRubyGemsDefaultsWithUpgrade() throws IOException { + assertEquals(InstallRubyGems.builder().updateSystem(true).updateExistingGems(true).build().render(OsFamily.UNIX), + Resources.toString(Resources.getResource("test_install_rubygems." + ShellToken.SH.to(OsFamily.UNIX)), + Charsets.UTF_8)); + } + + public void installRubyGemsUnixDefaultsInScriptBuilder() throws IOException { + assertEquals( + InitScript.builder().name("install_rubygems").run(InstallRubyGems.builder().build()).build() + .render(OsFamily.UNIX), Resources.toString( + Resources.getResource("test_install_rubygems_scriptbuilder." + ShellToken.SH.to(OsFamily.UNIX)), + Charsets.UTF_8)); + } + + private static String installRubyGems(String version) { + String script = "if ! hash gem 2>/dev/null; then\n" + + "(\n" + + "mkdir /tmp/$$\n" + + "curl -q -s -S -L --connect-timeout 10 --max-time 600 --retry 20 -X GET http://production.cf.rubygems.org/rubygems/rubygems-" + + version + ".tgz |(mkdir -p /tmp/$$ &&cd /tmp/$$ &&tar -xpzf -)\n" + "mkdir -p /tmp/rubygems\n" + + "mv /tmp/$$/*/* /tmp/rubygems\n" + "rm -rf /tmp/$$\n" + "cd /tmp/rubygems\n" + + "ruby setup.rb --no-format-executable\n" // + + "rm -fr /tmp/rubygems\n" + // + ")\n" + // + "fi\n"; + + return script; + } + + private static String updateSystem(String version) { + return version == null ? "gem update --system\n" : "gem update --system " + version + "\n"; + } + + private static String updateGems() { + return "gem update --no-rdoc --no-ri\n"; + } + +} diff --git a/scriptbuilder/src/test/resources/test_install_chef_gems_scriptbuilder.sh b/scriptbuilder/src/test/resources/test_install_chef_gems_scriptbuilder.sh index b96fa7695b..d08f1cd055 100644 --- a/scriptbuilder/src/test/resources/test_install_chef_gems_scriptbuilder.sh +++ b/scriptbuilder/src/test/resources/test_install_chef_gems_scriptbuilder.sh @@ -77,89 +77,6 @@ END_OF_JCLOUDS_SCRIPT export INSTANCE_NAME='$INSTANCE_NAME' export INSTANCE_HOME='$INSTANCE_HOME' export LOG_DIR='$LOG_DIR' -END_OF_JCLOUDS_SCRIPT - cat >> $INSTANCE_HOME/install_chef_gems.sh <<-'END_OF_JCLOUDS_SCRIPT' - function abort { - echo "aborting: $@" 1>&2 - exit 1 -} -alias apt-get-update="apt-get update -qq" -alias apt-get-install="apt-get install -f -y -qq --force-yes" -alias yum-install="yum --quiet --nogpgcheck -y install" - -function ensure_cmd_or_install_package_apt(){ - local cmd=$1 - shift - local pkg=$* - - hash $cmd 2>/dev/null || ( apt-get-update && apt-get-install $pkg ) -} - -function ensure_cmd_or_install_package_yum(){ - local cmd=$1 - shift - local pkg=$* - hash $cmd 2>/dev/null || yum-install $pkg -} - -function ensure_netutils_apt() { - ensure_cmd_or_install_package_apt nslookup dnsutils - ensure_cmd_or_install_package_apt curl curl -} - -function ensure_netutils_yum() { - ensure_cmd_or_install_package_yum nslookup bind-utils - ensure_cmd_or_install_package_yum curl curl -} - -# most network services require that the hostname is in -# the /etc/hosts file, or they won't operate -function ensure_hostname_in_hosts() { - [ -n "$SSH_CONNECTION" ] && { - local ipaddr=`echo $SSH_CONNECTION | awk '{print $3}'` - } || { - local ipaddr=`hostname -i` - } - # NOTE: we blindly trust existing hostname settings in /etc/hosts - egrep -q `hostname` /etc/hosts || echo "$ipaddr `hostname`" >> /etc/hosts -} - -# download locations for many services are at public dns -function ensure_can_resolve_public_dns() { - nslookup yahoo.com | grep yahoo.com > /dev/null || echo nameserver 208.67.222.222 >> /etc/resolv.conf -} - -function setupPublicCurl() { - ensure_hostname_in_hosts - if which dpkg &> /dev/null; then - ensure_netutils_apt - elif which rpm &> /dev/null; then - ensure_netutils_yum - else - abort "we only support apt-get and yum right now... please contribute!" - return 1 - fi - ensure_can_resolve_public_dns - return 0 -} -function installRuby() { - if ! hash ruby 2>/dev/null; then - if which dpkg &> /dev/null; then - apt-get-update - apt-get install -y ruby ruby-dev build-essential - elif which rpm &> /dev/null; then - # Disable chef from the base repo (http://tickets.opscode.com/browse/CHEF-2906) - sed -i "s/\[base\]/\0\n\exclude=ruby*/g" /etc/yum.repos.d/CentOS-Base.repo - # Make sure to install an appropriate ruby version - yum erase -y ruby ruby-libs - rpm -Uvh http://rbel.co/rbel5 - yum install -y ruby ruby-devel make gcc gcc-c++ automake autoconf - else - abort "we only support apt-get and yum right now... please contribute" - fi - fi -} - END_OF_JCLOUDS_SCRIPT # add desired commands from the user @@ -167,23 +84,6 @@ END_OF_JCLOUDS_SCRIPT cd $INSTANCE_HOME rm -f $INSTANCE_HOME/rc trap 'echo $?>$INSTANCE_HOME/rc' 0 1 2 3 15 - setupPublicCurl || exit 1 - installRuby || exit 1 - if ! hash gem 2>/dev/null; then - ( - mkdir /tmp/$$ - curl -q -s -S -L --connect-timeout 10 --max-time 600 --retry 20 -X GET http://production.cf.rubygems.org/rubygems/rubygems-1.8.10.tgz |(mkdir -p /tmp/$$ &&cd /tmp/$$ &&tar -xpzf -) - mkdir -p /tmp/rubygems - mv /tmp/$$/*/* /tmp/rubygems - rm -rf /tmp/$$ - cd /tmp/rubygems - ruby setup.rb --no-format-executable - rm -fr /tmp/rubygems - ) - fi - gem update --system - gem update --no-rdoc --no-ri - gem install chef --no-rdoc --no-ri END_OF_JCLOUDS_SCRIPT diff --git a/scriptbuilder/src/test/resources/test_install_ruby.sh b/scriptbuilder/src/test/resources/test_install_ruby.sh index 16ecc36a9c..631cbb1bb8 100644 --- a/scriptbuilder/src/test/resources/test_install_ruby.sh +++ b/scriptbuilder/src/test/resources/test_install_ruby.sh @@ -1,16 +1,2 @@ setupPublicCurl || return 1 installRuby || return 1 -if ! hash gem 2>/dev/null; then -( -mkdir /tmp/$$ -curl -q -s -S -L --connect-timeout 10 --max-time 600 --retry 20 -X GET http://production.cf.rubygems.org/rubygems/rubygems-1.8.10.tgz |(mkdir -p /tmp/$$ &&cd /tmp/$$ &&tar -xpzf -) -mkdir -p /tmp/rubygems -mv /tmp/$$/*/* /tmp/rubygems -rm -rf /tmp/$$ -cd /tmp/rubygems -ruby setup.rb --no-format-executable -rm -fr /tmp/rubygems -) -fi -gem update --system -gem update --no-rdoc --no-ri diff --git a/scriptbuilder/src/test/resources/test_install_ruby_scriptbuilder.sh b/scriptbuilder/src/test/resources/test_install_ruby_scriptbuilder.sh index 3eb8fc45aa..0ae5aaba52 100644 --- a/scriptbuilder/src/test/resources/test_install_ruby_scriptbuilder.sh +++ b/scriptbuilder/src/test/resources/test_install_ruby_scriptbuilder.sh @@ -171,21 +171,6 @@ END_OF_JCLOUDS_SCRIPT installRuby || exit 1 - if ! hash gem 2>/dev/null; then - ( - mkdir /tmp/$$ - curl -q -s -S -L --connect-timeout 10 --max-time 600 --retry 20 -X GET http://production.cf.rubygems.org/rubygems/rubygems-1.8.10.tgz |(mkdir -p /tmp/$$ &&cd /tmp/$$ &&tar -xpzf -) - mkdir -p /tmp/rubygems - mv /tmp/$$/*/* /tmp/rubygems - rm -rf /tmp/$$ - cd /tmp/rubygems - ruby setup.rb --no-format-executable - rm -fr /tmp/rubygems - ) - fi - gem update --system - gem update --no-rdoc --no-ri - END_OF_JCLOUDS_SCRIPT # add runscript footer diff --git a/scriptbuilder/src/test/resources/test_install_rubygems.sh b/scriptbuilder/src/test/resources/test_install_rubygems.sh new file mode 100644 index 0000000000..c9363d24cc --- /dev/null +++ b/scriptbuilder/src/test/resources/test_install_rubygems.sh @@ -0,0 +1,14 @@ +if ! hash gem 2>/dev/null; then +( +mkdir /tmp/$$ +curl -q -s -S -L --connect-timeout 10 --max-time 600 --retry 20 -X GET http://production.cf.rubygems.org/rubygems/rubygems-1.8.10.tgz |(mkdir -p /tmp/$$ &&cd /tmp/$$ &&tar -xpzf -) +mkdir -p /tmp/rubygems +mv /tmp/$$/*/* /tmp/rubygems +rm -rf /tmp/$$ +cd /tmp/rubygems +ruby setup.rb --no-format-executable +rm -fr /tmp/rubygems +) +fi +gem update --system +gem update --no-rdoc --no-ri diff --git a/scriptbuilder/src/test/resources/test_install_rubygems_scriptbuilder.sh b/scriptbuilder/src/test/resources/test_install_rubygems_scriptbuilder.sh new file mode 100644 index 0000000000..1c4bb5f8c5 --- /dev/null +++ b/scriptbuilder/src/test/resources/test_install_rubygems_scriptbuilder.sh @@ -0,0 +1,151 @@ +#!/bin/bash +set +u +shopt -s xpg_echo +shopt -s expand_aliases +unset PATH JAVA_HOME LD_LIBRARY_PATH +function abort { + echo "aborting: $@" 1>&2 + exit 1 +} +function default { + export INSTANCE_NAME="install_rubygems" +export INSTANCE_HOME="/tmp/$INSTANCE_NAME" +export LOG_DIR="$INSTANCE_HOME" + return $? +} +function install_rubygems { + return $? +} +function findPid { + unset FOUND_PID; + [ $# -eq 1 ] || { + abort "findPid requires a parameter of pattern to match" + return 1 + } + local PATTERN="$1"; shift + local _FOUND=`ps auxwww|grep "$PATTERN"|grep -v " $0"|grep -v grep|grep -v $$|awk '{print $2}'` + [ -n "$_FOUND" ] && { + export FOUND_PID=$_FOUND + return 0 + } || { + return 1 + } +} +function forget { + unset FOUND_PID; + [ $# -eq 3 ] || { + abort "forget requires parameters INSTANCE_NAME SCRIPT LOG_DIR" + return 1 + } + local INSTANCE_NAME="$1"; shift + local SCRIPT="$1"; shift + local LOG_DIR="$1"; shift + mkdir -p $LOG_DIR + findPid $INSTANCE_NAME + [ -n "$FOUND_PID" -a -f $LOG_DIR/stdout.log ] && { + echo $INSTANCE_NAME already running pid $FOUND_PID + return 1; + } || { + nohup $SCRIPT >$LOG_DIR/stdout.log 2>$LOG_DIR/stderr.log & + RETURN=$? + # this is generally followed by findPid, so we shouldn't exit + # immediately as the proc may not have registered in ps, yet + test $RETURN && sleep 1 + return $RETURN; + } +} +export PATH=/usr/ucb/bin:/bin:/sbin:/usr/bin:/usr/sbin +case $1 in +init) + default || exit 1 + install_rubygems || exit 1 + mkdir -p $INSTANCE_HOME + + # create runscript header + cat > $INSTANCE_HOME/install_rubygems.sh <<-'END_OF_JCLOUDS_SCRIPT' + #!/bin/bash + set +u + shopt -s xpg_echo + shopt -s expand_aliases + + PROMPT_COMMAND='echo -ne \"\033]0;install_rubygems\007\"' + export PATH=/usr/ucb/bin:/bin:/sbin:/usr/bin:/usr/sbin + + export INSTANCE_NAME='install_rubygems' +END_OF_JCLOUDS_SCRIPT + cat >> $INSTANCE_HOME/install_rubygems.sh <<-END_OF_JCLOUDS_SCRIPT + export INSTANCE_NAME='$INSTANCE_NAME' + export INSTANCE_HOME='$INSTANCE_HOME' + export LOG_DIR='$LOG_DIR' +END_OF_JCLOUDS_SCRIPT + + # add desired commands from the user + cat >> $INSTANCE_HOME/install_rubygems.sh <<-'END_OF_JCLOUDS_SCRIPT' + cd $INSTANCE_HOME + rm -f $INSTANCE_HOME/rc + trap 'echo $?>$INSTANCE_HOME/rc' 0 1 2 3 15 + if ! hash gem 2>/dev/null; then + ( + mkdir /tmp/$$ + curl -q -s -S -L --connect-timeout 10 --max-time 600 --retry 20 -X GET http://production.cf.rubygems.org/rubygems/rubygems-1.8.10.tgz |(mkdir -p /tmp/$$ &&cd /tmp/$$ &&tar -xpzf -) + mkdir -p /tmp/rubygems + mv /tmp/$$/*/* /tmp/rubygems + rm -rf /tmp/$$ + cd /tmp/rubygems + ruby setup.rb --no-format-executable + rm -fr /tmp/rubygems + ) + fi + +END_OF_JCLOUDS_SCRIPT + + # add runscript footer + cat >> $INSTANCE_HOME/install_rubygems.sh <<-'END_OF_JCLOUDS_SCRIPT' + exit $? + +END_OF_JCLOUDS_SCRIPT + + chmod u+x $INSTANCE_HOME/install_rubygems.sh + ;; +status) + default || exit 1 + findPid $INSTANCE_NAME || exit 1 + echo $FOUND_PID + ;; +stop) + default || exit 1 + findPid $INSTANCE_NAME || exit 1 + [ -n "$FOUND_PID" ] && { + echo stopping $FOUND_PID + kill -9 $FOUND_PID + } + ;; +start) + default || exit 1 + forget $INSTANCE_NAME $INSTANCE_HOME/$INSTANCE_NAME.sh $LOG_DIR || exit 1 + ;; +stdout) + default || exit 1 + cat $LOG_DIR/stdout.log + ;; +stderr) + default || exit 1 + cat $LOG_DIR/stderr.log + ;; +exitstatus) + default || exit 1 + [ -f $LOG_DIR/rc ] && cat $LOG_DIR/rc;; +tail) + default || exit 1 + tail $LOG_DIR/stdout.log + ;; +tailerr) + default || exit 1 + tail $LOG_DIR/stderr.log + ;; +run) + default || exit 1 + $INSTANCE_HOME/$INSTANCE_NAME.sh + ;; +esac +exit $?