Improved RubyGems installation.

Enable users to configure the version of RubyGems that will be installed
and also if the system and existing gems have to be upgraded after the
installation.

Also modifies the InstallChefGems statement to allow users to specify
the desired version of the Chef gem to install.
This commit is contained in:
Ignasi Barrera 2013-03-06 18:03:22 +01:00
parent c31145e42e
commit fb70b3fd22
15 changed files with 506 additions and 183 deletions

View File

@ -22,6 +22,8 @@ import org.jclouds.scriptbuilder.domain.OsFamily;
public class FunctionNotFoundException extends RuntimeException { public class FunctionNotFoundException extends RuntimeException {
private static final long serialVersionUID = 1L;
public FunctionNotFoundException(String functionName, OsFamily family) { public FunctionNotFoundException(String functionName, OsFamily family) {
super("function: " + functionName + " not found for family: " + family); super("function: " + functionName + " not found for family: " + family);
} }

View File

@ -73,6 +73,7 @@ public class ChefSolo implements Statement {
private List<Role> roles = Lists.newArrayList(); private List<Role> roles = Lists.newArrayList();
private List<DataBag> databags = Lists.newArrayList(); private List<DataBag> databags = Lists.newArrayList();
private RunList runlist; private RunList runlist;
private String chefVersion;
/** /**
* Directory where Chef Solo will store files. * Directory where Chef Solo will store files.
@ -232,13 +233,22 @@ public class ChefSolo implements Statement {
return this; 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() { public ChefSolo build() {
return new ChefSolo(Optional.of(fileCachePath), Optional.fromNullable(rolePath), return new ChefSolo(Optional.of(fileCachePath), Optional.fromNullable(rolePath),
Optional.fromNullable(databagPath), Optional.of(cookbookPath.build()), Optional.fromNullable(databagPath), Optional.of(cookbookPath.build()),
Optional.fromNullable(cookbooksArchiveLocation), Optional.fromNullable(jsonAttributes), Optional.fromNullable(cookbooksArchiveLocation), Optional.fromNullable(jsonAttributes),
Optional.fromNullable(group), Optional.fromNullable(interval), Optional.fromNullable(logLevel), Optional.fromNullable(group), Optional.fromNullable(interval), Optional.fromNullable(logLevel),
Optional.fromNullable(logFile), Optional.fromNullable(nodeName), Optional.fromNullable(splay), 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<List<Role>> roles; private Optional<List<Role>> roles;
private Optional<List<DataBag>> databags; private Optional<List<DataBag>> databags;
private RunList runlist; private RunList runlist;
private final InstallChefGems installChefGems = new InstallChefGems(); private final InstallChefGems installChefGems;
public ChefSolo(Optional<String> fileCachePath, Optional<String> rolePath, Optional<String> databagPath, public ChefSolo(Optional<String> fileCachePath, Optional<String> rolePath, Optional<String> databagPath,
Optional<ImmutableList<String>> cookbookPath, Optional<String> cookbooksArchiveLocation, Optional<ImmutableList<String>> cookbookPath, Optional<String> cookbooksArchiveLocation,
Optional<String> jsonAttributes, Optional<String> group, Optional<Integer> interval, Optional<String> jsonAttributes, Optional<String> group, Optional<Integer> interval,
Optional<String> logLevel, Optional<String> logFile, Optional<String> nodeName, Optional<Integer> splay, Optional<String> logLevel, Optional<String> logFile, Optional<String> nodeName, Optional<Integer> splay,
Optional<String> user, Optional<List<Role>> roles, Optional<List<DataBag>> databags, Optional<RunList> runlist) { Optional<String> user, Optional<List<Role>> roles, Optional<List<DataBag>> databags,
Optional<RunList> runlist, Optional<String> chefVersion) {
this.fileCachePath = checkNotNull(fileCachePath, "fileCachePath must be set").or(DEFAULT_SOLO_PATH); 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.rolePath = checkNotNull(rolePath, "rolePath must be set").or(this.fileCachePath + "/roles");
this.databagPath = checkNotNull(databagPath, "databagPath must be set").or(this.fileCachePath + "/data_bags"); 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.roles = checkNotNull(roles, "roles must be set");
this.databags = checkNotNull(databags, "databags must be set"); this.databags = checkNotNull(databags, "databags must be set");
this.runlist = checkNotNull(runlist, "runlist must be set").or(RunList.builder().build()); 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()) { if (!checkNotNull(cookbookPath, "cookbookPath must be set").isPresent() || cookbookPath.get().isEmpty()) {
this.cookbookPath = ImmutableList.<String> of(this.fileCachePath + "/cookbooks"); this.cookbookPath = ImmutableList.<String> of(this.fileCachePath + "/cookbooks");
} else { } else {
this.cookbookPath = ImmutableList.<String> copyOf(cookbookPath.get()); this.cookbookPath = ImmutableList.<String> copyOf(cookbookPath.get());
} }
this.installChefGems = InstallChefGems.builder().version(chefVersion.orNull()).build();
} }
@Override @Override

View File

@ -20,21 +20,46 @@ package org.jclouds.scriptbuilder.statements.chef;
import static org.jclouds.scriptbuilder.domain.Statements.exec; 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.OsFamily;
import org.jclouds.scriptbuilder.domain.StatementList; import org.jclouds.scriptbuilder.domain.Statement;
import org.jclouds.scriptbuilder.statements.ruby.InstallRuby;
import com.google.common.base.Optional;
import com.google.common.collect.ImmutableSet;
/** /**
* Installs Chef gems onto a host. * Installs Chef gems onto a host.
* *
* @author Ignasi Barrera * @author Ignasi Barrera
*/ */
public class InstallChefGems extends StatementList { public class InstallChefGems implements Statement {
public InstallChefGems() { public static Builder builder() {
// Chef versions prior to 10.16.4 install an incompatible moneta gem. return new Builder();
// See: http://tickets.opscode.com/browse/CHEF-3721 }
super(new InstallRuby(), exec("gem install chef --no-rdoc --no-ri"));
public static class Builder {
private Optional<String> version = Optional.absent();
/**
* The version of the Chef gem to install.
* <p>
* 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<String> version;
public InstallChefGems(Optional<String> version) {
this.version = version;
} }
@Override @Override
@ -42,7 +67,16 @@ public class InstallChefGems extends StatementList {
if (family == OsFamily.WINDOWS) { if (family == OsFamily.WINDOWS) {
throw new UnsupportedOperationException("windows not yet implemented"); 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<String> functionDependencies(OsFamily family) {
return ImmutableSet.<String> of();
} }
} }

View File

@ -19,41 +19,19 @@
package org.jclouds.scriptbuilder.statements.ruby; package org.jclouds.scriptbuilder.statements.ruby;
import static org.jclouds.scriptbuilder.domain.Statements.call; 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.OsFamily;
import org.jclouds.scriptbuilder.domain.Statement;
import org.jclouds.scriptbuilder.domain.StatementList; import org.jclouds.scriptbuilder.domain.StatementList;
/** /**
* Installs Ruby and Rubygems gems onto a host. * Installs Ruby onto a host.
* *
* @author Ignasi Barrera * @author Ignasi Barrera
*/ */
public class InstallRuby extends StatementList { 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() { public InstallRuby() {
super(call("setupPublicCurl"), call("installRuby"), installRubyGems()); super(call("setupPublicCurl"), call("installRuby"));
} }
@Override @Override

View File

@ -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<String> version = Optional.absent();
private boolean updateSystem = false;
private Optional<String> 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<String> version;
private boolean updateSystem;
private Optional<String> updateSystemVersion;
private boolean updateExistingGems;
public InstallRubyGems(Optional<String> version, boolean updateSystem, Optional<String> 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<Statement> 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<String> functionDependencies(OsFamily family) {
return ImmutableSet.<String> of();
}
}

View File

@ -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.newStatementList;
import static org.jclouds.scriptbuilder.domain.Statements.switchArg; import static org.jclouds.scriptbuilder.domain.Statements.switchArg;
import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertTrue;
import java.io.IOException; import java.io.IOException;
import java.net.MalformedURLException; import java.net.MalformedURLException;

View File

@ -23,8 +23,6 @@ import static org.jclouds.scriptbuilder.domain.Statements.interpret;
import static org.jclouds.scriptbuilder.domain.Statements.newStatementList; import static org.jclouds.scriptbuilder.domain.Statements.newStatementList;
import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertEquals;
import java.util.Collections;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;

View File

@ -26,17 +26,14 @@ import static org.testng.Assert.assertTrue;
import java.io.IOException; import java.io.IOException;
import org.jclouds.scriptbuilder.domain.OsFamily; import org.jclouds.scriptbuilder.domain.OsFamily;
import org.jclouds.scriptbuilder.domain.ShellToken;
import org.jclouds.scriptbuilder.domain.Statement; import org.jclouds.scriptbuilder.domain.Statement;
import org.jclouds.scriptbuilder.domain.chef.DataBag; import org.jclouds.scriptbuilder.domain.chef.DataBag;
import org.jclouds.scriptbuilder.domain.chef.Role; import org.jclouds.scriptbuilder.domain.chef.Role;
import org.jclouds.scriptbuilder.domain.chef.RunList; import org.jclouds.scriptbuilder.domain.chef.RunList;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import com.google.common.base.Charsets;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import com.google.common.io.Resources;
/** /**
* Unit tests for the {@link ChefSoloTest} statement. * 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"); + "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 { private static String installChefGems() throws IOException {
return Resources.toString(Resources.getResource("test_install_ruby." + ShellToken.SH.to(OsFamily.UNIX)), return "gem install chef --no-rdoc --no-ri\n";
Charsets.UTF_8) + "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() { private static String createConfigFile() {

View File

@ -40,21 +40,22 @@ public class InstallChefGemsTest {
@Test(expectedExceptions = UnsupportedOperationException.class, expectedExceptionsMessageRegExp = "windows not yet implemented") @Test(expectedExceptions = UnsupportedOperationException.class, expectedExceptionsMessageRegExp = "windows not yet implemented")
public void installChefGemsInWindows() { public void installChefGemsInWindows() {
new InstallChefGems().render(OsFamily.WINDOWS); InstallChefGems.builder().build().render(OsFamily.WINDOWS);
} }
public void installChefGemsUnix() throws IOException { public void installChefGemsUnix() throws IOException {
assertEquals( assertEquals(InstallChefGems.builder().build().render(OsFamily.UNIX), "gem install chef --no-rdoc --no-ri\n");
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");
} }
public void installChefGemsUnixInScriptBuilderSourcesSetupPublicCurl() throws IOException { public void installChefGemsUnixWithCustomVersion() throws IOException {
assertEquals( assertEquals(InstallChefGems.builder().version(">= 0.10.8").build().render(OsFamily.UNIX),
InitScript.builder().name("install_chef_gems").run(new InstallChefGems()).build().render(OsFamily.UNIX), "gem install chef -v '>= 0.10.8' --no-rdoc --no-ri\n");
Resources.toString( }
Resources.getResource("test_install_chef_gems_scriptbuilder." + ShellToken.SH.to(OsFamily.UNIX)),
Charsets.UTF_8)); 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));
} }
} }

View File

@ -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";
}
}

View File

@ -77,89 +77,6 @@ END_OF_JCLOUDS_SCRIPT
export INSTANCE_NAME='$INSTANCE_NAME' export INSTANCE_NAME='$INSTANCE_NAME'
export INSTANCE_HOME='$INSTANCE_HOME' export INSTANCE_HOME='$INSTANCE_HOME'
export LOG_DIR='$LOG_DIR' 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 END_OF_JCLOUDS_SCRIPT
# add desired commands from the user # add desired commands from the user
@ -167,23 +84,6 @@ END_OF_JCLOUDS_SCRIPT
cd $INSTANCE_HOME cd $INSTANCE_HOME
rm -f $INSTANCE_HOME/rc rm -f $INSTANCE_HOME/rc
trap 'echo $?>$INSTANCE_HOME/rc' 0 1 2 3 15 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 gem install chef --no-rdoc --no-ri
END_OF_JCLOUDS_SCRIPT END_OF_JCLOUDS_SCRIPT

View File

@ -1,16 +1,2 @@
setupPublicCurl || return 1 setupPublicCurl || return 1
installRuby || 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

View File

@ -171,21 +171,6 @@ END_OF_JCLOUDS_SCRIPT
installRuby || 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
END_OF_JCLOUDS_SCRIPT END_OF_JCLOUDS_SCRIPT
# add runscript footer # add runscript footer

View File

@ -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

View File

@ -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 $?