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 8f0d6d58c8..c7a0931435 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
@@ -31,6 +31,8 @@ import org.jclouds.scriptbuilder.domain.Statements;
import org.jclouds.scriptbuilder.domain.chef.DataBag;
import org.jclouds.scriptbuilder.domain.chef.Role;
import org.jclouds.scriptbuilder.domain.chef.RunList;
+import org.jclouds.scriptbuilder.statements.ruby.InstallRuby;
+import org.jclouds.scriptbuilder.statements.ruby.InstallRubyGems;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Function;
@@ -45,6 +47,10 @@ import com.google.common.collect.Lists;
* Bootstraps a node using Chef Solo.
*
* @author Ignasi Barrera
+ *
+ * @see InstallChefGems
+ * @see InstallRuby
+ * @see InstallRubyGems
*/
public class ChefSolo implements Statement {
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 f30c8e4223..5fc5a34ef6 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
@@ -21,14 +21,24 @@ 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.Statement;
+import org.jclouds.scriptbuilder.statements.ruby.InstallRuby;
+import org.jclouds.scriptbuilder.statements.ruby.InstallRubyGems;
import com.google.common.base.Optional;
import com.google.common.collect.ImmutableSet;
/**
* Installs Chef gems onto a host.
+ *
+ * If you only want to install the Chef client and don't care about the version
+ * of Ruby and Rubygems, use the {@link InstallChefUsingOmnibus} statement
+ * instead.
*
* @author Ignasi Barrera
+ *
+ * @see InstallChefUsingOmnibus
+ * @see InstallRuby
+ * @see InstallRubyGems
*/
public class InstallChefGems implements Statement {
diff --git a/scriptbuilder/src/main/java/org/jclouds/scriptbuilder/statements/chef/InstallChefUsingOmnibus.java b/scriptbuilder/src/main/java/org/jclouds/scriptbuilder/statements/chef/InstallChefUsingOmnibus.java
new file mode 100644
index 0000000000..c16b220369
--- /dev/null
+++ b/scriptbuilder/src/main/java/org/jclouds/scriptbuilder/statements/chef/InstallChefUsingOmnibus.java
@@ -0,0 +1,54 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF 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.chef;
+
+import static org.jclouds.scriptbuilder.domain.Statements.call;
+import static org.jclouds.scriptbuilder.domain.Statements.pipeHttpResponseToBash;
+
+import java.net.URI;
+
+import org.jclouds.scriptbuilder.domain.StatementList;
+import org.jclouds.scriptbuilder.statements.ruby.InstallRuby;
+
+import com.google.common.collect.ImmutableMultimap;
+
+/**
+ * Installs the Chef client using the Omnibus installer.
+ *
+ * This will install an entire ruby distribution with all required gems in a
+ * concrete directory so there is no need to manually download or configure any
+ * Ruby version or gem.
+ *
+ * If you want more control on the Ruby version or the gems being installed, use
+ * the {@link InstallChefGems} statement instead.
+ *
+ * @author Ignasi Barrera
+ *
+ * @see InstallChefGems
+ * @see InstallRuby
+ */
+public class InstallChefUsingOmnibus extends StatementList {
+
+ /** The URL for the Omnibus installer */
+ public static final String OMNIBUS_INSTALLER = "https://www.opscode.com/chef/install.sh";
+
+ public InstallChefUsingOmnibus() {
+ super(call("setupPublicCurl"), pipeHttpResponseToBash("GET", URI.create(OMNIBUS_INSTALLER),
+ ImmutableMultimap. of()));
+ }
+
+}
diff --git a/scriptbuilder/src/test/java/org/jclouds/scriptbuilder/statements/chef/InstallChefUsingOmnibusTest.java b/scriptbuilder/src/test/java/org/jclouds/scriptbuilder/statements/chef/InstallChefUsingOmnibusTest.java
new file mode 100644
index 0000000000..0dc6fc2be5
--- /dev/null
+++ b/scriptbuilder/src/test/java/org/jclouds/scriptbuilder/statements/chef/InstallChefUsingOmnibusTest.java
@@ -0,0 +1,56 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF 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.chef;
+
+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 InstallChefUsingOmnibus} statement.
+ *
+ * @author Ignasi Barrera
+ */
+@Test(groups = "unit", testName = "InstallChefClientUsingOmnibusTest")
+public class InstallChefUsingOmnibusTest {
+
+ @Test(expectedExceptions = IllegalArgumentException.class, expectedExceptionsMessageRegExp = "windows not supported")
+ public void installChefUsingOmnibusInWindows() {
+ new InstallChefUsingOmnibus().render(OsFamily.WINDOWS);
+ }
+
+ public void installChefUsingOmnibusInUnix() throws IOException {
+ assertEquals(new InstallChefUsingOmnibus().render(OsFamily.UNIX), "setupPublicCurl || return 1\n"
+ + "curl -q -s -S -L --connect-timeout 10 --max-time 600 --retry 20 "
+ + "-X GET https://www.opscode.com/chef/install.sh |(bash)\n");
+ }
+
+ public void installChefUsingOmnibusInUnixInScriptBuilder() throws IOException {
+ assertEquals(InitScript.builder().name("install_chef_omnibus").run(new InstallChefUsingOmnibus()).build()
+ .render(OsFamily.UNIX), Resources.toString(
+ Resources.getResource("test_install_chef_omnibus_scriptbuilder." + ShellToken.SH.to(OsFamily.UNIX)),
+ Charsets.UTF_8));
+ }
+}
diff --git a/scriptbuilder/src/test/resources/test_install_chef_omnibus_scriptbuilder.sh b/scriptbuilder/src/test/resources/test_install_chef_omnibus_scriptbuilder.sh
new file mode 100644
index 0000000000..e295c330a3
--- /dev/null
+++ b/scriptbuilder/src/test/resources/test_install_chef_omnibus_scriptbuilder.sh
@@ -0,0 +1,208 @@
+#!/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_chef_omnibus"
+export INSTANCE_HOME="/tmp/$INSTANCE_NAME"
+export LOG_DIR="$INSTANCE_HOME"
+ return $?
+}
+function install_chef_omnibus {
+ 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_chef_omnibus || exit 1
+ mkdir -p $INSTANCE_HOME
+
+ # create runscript header
+ cat > $INSTANCE_HOME/install_chef_omnibus.sh <<-'END_OF_JCLOUDS_SCRIPT'
+ #!/bin/bash
+ set +u
+ shopt -s xpg_echo
+ shopt -s expand_aliases
+
+ PROMPT_COMMAND='echo -ne \"\033]0;install_chef_omnibus\007\"'
+ export PATH=/usr/ucb/bin:/bin:/sbin:/usr/bin:/usr/sbin
+
+ export INSTANCE_NAME='install_chef_omnibus'
+END_OF_JCLOUDS_SCRIPT
+ cat >> $INSTANCE_HOME/install_chef_omnibus.sh <<-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_omnibus.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
+}
+
+END_OF_JCLOUDS_SCRIPT
+
+ # add desired commands from the user
+ cat >> $INSTANCE_HOME/install_chef_omnibus.sh <<-'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
+
+ curl -q -s -S -L --connect-timeout 10 --max-time 600 --retry 20 -X GET https://www.opscode.com/chef/install.sh |(bash)
+
+END_OF_JCLOUDS_SCRIPT
+
+ # add runscript footer
+ cat >> $INSTANCE_HOME/install_chef_omnibus.sh <<-'END_OF_JCLOUDS_SCRIPT'
+ exit $?
+
+END_OF_JCLOUDS_SCRIPT
+
+ chmod u+x $INSTANCE_HOME/install_chef_omnibus.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 $?