From 4546248b5cbc445d636ece091e3a5463c4493f8a Mon Sep 17 00:00:00 2001 From: Binh Nguyen Date: Wed, 26 Feb 2014 23:30:08 -0800 Subject: [PATCH 1/2] Initial import of Vagrant scripts and shells --- vagrant/.gitignore | 5 + vagrant/LICENSE | 20 + vagrant/README.md | 19 + vagrant/Vagrantfile | 65 ++ vagrant/scripts/setup.sh | 37 + .../scripts/vagrant-shell-scripts/.gitignore | 2 + vagrant/scripts/vagrant-shell-scripts/.lvimrc | 13 + .../scripts/vagrant-shell-scripts/LICENSE.md | 22 + .../scripts/vagrant-shell-scripts/README.md | 739 ++++++++++++++++ .../vagrant-shell-scripts/ubuntu-extras.sh | 142 ++++ .../vagrant-shell-scripts/ubuntu-postfix.sh | 65 ++ .../vagrant-shell-scripts/ubuntu-postgres.sh | 53 ++ .../scripts/vagrant-shell-scripts/ubuntu.sh | 796 ++++++++++++++++++ .../scripts/vagrant-shell-scripts/vagrant.rb | 26 + 14 files changed, 2004 insertions(+) create mode 100644 vagrant/.gitignore create mode 100644 vagrant/LICENSE create mode 100644 vagrant/README.md create mode 100644 vagrant/Vagrantfile create mode 100644 vagrant/scripts/setup.sh create mode 100644 vagrant/scripts/vagrant-shell-scripts/.gitignore create mode 100644 vagrant/scripts/vagrant-shell-scripts/.lvimrc create mode 100644 vagrant/scripts/vagrant-shell-scripts/LICENSE.md create mode 100644 vagrant/scripts/vagrant-shell-scripts/README.md create mode 100644 vagrant/scripts/vagrant-shell-scripts/ubuntu-extras.sh create mode 100644 vagrant/scripts/vagrant-shell-scripts/ubuntu-postfix.sh create mode 100644 vagrant/scripts/vagrant-shell-scripts/ubuntu-postgres.sh create mode 100644 vagrant/scripts/vagrant-shell-scripts/ubuntu.sh create mode 100644 vagrant/scripts/vagrant-shell-scripts/vagrant.rb diff --git a/vagrant/.gitignore b/vagrant/.gitignore new file mode 100644 index 0000000000000..0cbe0c9d527f1 --- /dev/null +++ b/vagrant/.gitignore @@ -0,0 +1,5 @@ +.downloads +.DS_STORE +*.box +.vagrant +.bashrc diff --git a/vagrant/LICENSE b/vagrant/LICENSE new file mode 100644 index 0000000000000..e138104ab7538 --- /dev/null +++ b/vagrant/LICENSE @@ -0,0 +1,20 @@ +The MIT License (MIT) + +Copyright (c) 2014 Binh Nguyen + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/vagrant/README.md b/vagrant/README.md new file mode 100644 index 0000000000000..0d4557f9066bf --- /dev/null +++ b/vagrant/README.md @@ -0,0 +1,19 @@ +Vagrant template with shell provision for Ubuntu Precise clusers with JDK 7. +=========== + +## Installation +1. Install [vagrant](//www.vagrantup.com). *Tested with version 1.4.3* +2. Install [virtualbox](//www.virtualbox.org). *Tested with version 4.2.16 but should work with any 4.+* +3. Checkout this repo `git clone git@github.com:ngbinh/vagrant_jdk.git` +4. Change to the directory `cd vagrant_jdk` +5. Bring up the nodes `vagrant up` +6. Wait a while, then make sure the nodes are up: `vagrant status`. You should see three nodes named `spark-master`, `spark-worker-1` and `spark-worker-2` running. +7. Access the nodes with user `spark-user` and password `spark`. + +Note that it will take a while to download Ubuntu Precise image at the first run. Subsequent runs should not have to re-download. + +### Customization +1. You can change the number of nodes, their basic parameters by modifying `Vagrantfile`. +2. You can change the JDK version by modifying `scripts/setup.sh` + + diff --git a/vagrant/Vagrantfile b/vagrant/Vagrantfile new file mode 100644 index 0000000000000..e2d8f4f16b23f --- /dev/null +++ b/vagrant/Vagrantfile @@ -0,0 +1,65 @@ +# -*- mode: ruby -*- +# vi: set ft=ruby : + +# Using Vagrant shell scripts +# https://github.com/StanAngeloff/vagrant-shell-scripts +require File.join(File.dirname(__FILE__), 'scripts/vagrant-shell-scripts/vagrant') + +# Vagrantfile API/syntax version. Don't touch unless you know what you're doing! +VAGRANTFILE_API_VERSION = "2" +Vagrant.require_version ">= 1.4.2" + +# the domain of all the nodes +DOMAIN = 'local' + +# Ubuntu 12.04.4 LTS (Precise Pangolin) 64 bit +BOX = 'precise64' +BOX_URL = 'http://files.vagrantup.com/precise64.box' + +# define all the nodes here. +# :host is the id in Vagrant of the node. It will also be its hostname +# :ip the ip address of the node +# :cpu the number of core for the node +# :ram the amount of RAM allocated to the node in MBytes. +NODES = [ + { :host => 'spark-master', :ip => '192.168.2.10', :cpu => 1, :ram => '3072' }, + { :host => 'spark-worker-1', :ip => '192.168.2.20', :cpu => 1, :ram => '2048' }, + { :host => 'spark-worker-2', :ip => '192.168.2.21', :cpu => 1, :ram => '2048' } +] + +Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| + NODES.each do | node | + config.vm.define node[:host] do | node_config | + node_config.vm.box = BOX + node_config.vm.box_url = BOX_URL + + node_config.vm.hostname = node[:host] + "." + DOMAIN + node_config.vm.network :private_network, ip: node[:ip] + + # by default, the current folder is shared as /vagrant in the nodes + # you can also share an outside folder here + # node_config.vm.synced_folder "shared", "/shared" + + memory = node[:ram] ? node[:ram] : 1024 + cpu = node[:cpu] ? node[:cpu] : 1 + + node_config.vm.provider :virtualbox do | vbox | + vbox.gui = false + vbox.customize ['modifyvm', :id, '--memory', memory.to_s] + vbox.customize ['modifyvm', :id, '--cpus', cpu.to_s] + + # fix the connection slow + # https://github.com/mitchellh/vagrant/issues/1807 + vbox.customize ["modifyvm", :id, "--natdnshostresolver1", "on"] + vbox.customize ["modifyvm", :id, "--natdnsproxy1", "on"] + end + + node_config.vm.provision :shell do |shell| + vagrant_shell_scripts_configure( + shell, + File.dirname(__FILE__), + 'scripts/setup.sh') + end + end + end +end diff --git a/vagrant/scripts/setup.sh b/vagrant/scripts/setup.sh new file mode 100644 index 0000000000000..cb359b8885fc2 --- /dev/null +++ b/vagrant/scripts/setup.sh @@ -0,0 +1,37 @@ +#!/bin/bash + +<%= import 'scripts/vagrant-shell-scripts/ubuntu.sh' %> +<%= import 'scripts/vagrant-shell-scripts/ubuntu-extras.sh' %> + +# }}} + +# Use Google Public DNS for resolving domain names. +# The default is host-only DNS which may not be installed. +# nameservers-local-purge +# nameservers-append '8.8.8.8' +# nameservers-append '8.8.4.4' + +# Update packages cache. +apt-packages-update + +# Install VM packages. +apt-packages-install \ + rsync \ + telnet \ + wget \ + git \ + curl\ + whois + +download_dir="/vagrant/.downloads/oracle-jdk-download" +mkdir -p "$download_dir" && oracle-jdk-install "Cookie: gpw_e24=http%3A%2F%2Fwww.oracle.com" "http://download.oracle.com/otn-pub/java/jdk/7u51-b13/jdk-7u51-linux-x64.tar.gz" "$download_dir" + +# create user spark if necessary +if [ getent passwd spark-user > /dev/null 2>&1 ]; then + echo "user spark-user exists. Skipping create user" +else + echo "creating (sudo) user spark-user" + sudo useradd -m -G `groups vagrant | cut -d" " -f4- | sed 's/ /,/g'` -s/bin/bash -p `mkpasswd spark` spark-user + echo "sucess" +fi +# done. Create user diff --git a/vagrant/scripts/vagrant-shell-scripts/.gitignore b/vagrant/scripts/vagrant-shell-scripts/.gitignore new file mode 100644 index 0000000000000..72c9085101861 --- /dev/null +++ b/vagrant/scripts/vagrant-shell-scripts/.gitignore @@ -0,0 +1,2 @@ +.bundle +.vagrant diff --git a/vagrant/scripts/vagrant-shell-scripts/.lvimrc b/vagrant/scripts/vagrant-shell-scripts/.lvimrc new file mode 100644 index 0000000000000..aa14f058597b3 --- /dev/null +++ b/vagrant/scripts/vagrant-shell-scripts/.lvimrc @@ -0,0 +1,13 @@ +let s:roundup_command = 'bin/roundup' + +let VimuxResetSequence = "q C-c C-u" + +augroup runTestOnSave + au! + au BufWritePost *-test.sh call VimuxRunCommand(s:roundup_command . ' ' . expand('%:p:~:.')) +augroup END + +augroup reloadLocalConfiguration + au! + au BufWritePost .lvimrc source % +augroup END diff --git a/vagrant/scripts/vagrant-shell-scripts/LICENSE.md b/vagrant/scripts/vagrant-shell-scripts/LICENSE.md new file mode 100644 index 0000000000000..63bc22b224539 --- /dev/null +++ b/vagrant/scripts/vagrant-shell-scripts/LICENSE.md @@ -0,0 +1,22 @@ +The MIT License +=============== + +> Copyright (c) 2011 Stan Angeloff +> +> Permission is hereby granted, free of charge, to any person obtaining a copy +> of this software and associated documentation files (the "Software"), to deal +> in the Software without restriction, including without limitation the rights +> to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +> copies of the Software, and to permit persons to whom the Software is +> furnished to do so, subject to the following conditions: +> +> The above copyright notice and this permission notice shall be included in +> all copies or substantial portions of the Software. +> +> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +> IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +> FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +> AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +> LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +> OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +> THE SOFTWARE. diff --git a/vagrant/scripts/vagrant-shell-scripts/README.md b/vagrant/scripts/vagrant-shell-scripts/README.md new file mode 100644 index 0000000000000..496cf802db3d8 --- /dev/null +++ b/vagrant/scripts/vagrant-shell-scripts/README.md @@ -0,0 +1,739 @@ +vagrant-shell-scripts +===================== + +A collection of scripts (Ubuntu-only at this time) to ease Vagrant box provisioning using the [shell][shell] method. + + [shell]: http://vagrantup.com/v1/docs/provisioners/shell.html + +Usage +----- + +1. Place on top of your `Vagrantfile` before `Vagrant.configure(..)`: + + ```ruby + require File.join(File.dirname(__FILE__), 'path/to/vagrant-shell-scripts/vagrant') + ``` + +2. Place at the end of your `Vagrantfile` before the last `end`: + + ```ruby + config.vm.provision :shell do |shell| + vagrant_shell_scripts_configure( + shell, + File.dirname(__FILE__), + 'path/to/provisioning_script' + ) + end + ``` + +3. Place on top of your provisioning script: + + ```bash + #!/usr/bin/env bash + + <%= import 'ubuntu.sh' %> + ``` + +Functions +--------- + +### Utility + +- `script-argument-create(value, expected)` + + Return the value of the first argument or exit with an error message if empty. + + Example: + + ```bash + MYSQL_DBNAME=$( script-argument-create "$1" 'a MySQL database name as the first argument' ) + ``` + +### Nameservers + +- `nameservers-local-purge` + + Drop all local `10.0.x.x` nameservers in `resolv.conf`. + +- `nameservers-append(ip)` + + Set up an IP as a DNS name server if not already present in `resolv.conf`. + + Example (set up Google DNS): + + ```bash + nameservers-local-purge + nameservers-append '8.8.8.8' + nameservers-append '8.8.4.4' + ``` + +### Aptitude + +- `apt-mirror-pick(iso2)` + + Set up a specific two-letter country code as the preferred `aptitude` mirror. + + Example (use Ubuntu Bulgaria as a mirror): + + ```bash + apt-mirror-pick 'bg' + ``` + +- `apt-packages-repository(repository[, repository[, ...]][, key[, server = 'keyserver.ubuntu.com']])` + + Add a custom repository as a software source. + + Each `repository` is a line as it would appear in your `/etc/apt/sources.list` file, e.g., `deb URL DISTRIBUTION CATEGORY`. + + `key` and `server` are the signing key and server. + You need to add the key to your system so Ubuntu can verify the packages from the repository. + + Example (install MongoDB from official repositories): + + ``` + apt-packages-repository 'deb http://downloads-distro.mongodb.org/repo/ubuntu-upstart dist 10gen' '7F0CEB10' + apt-packages-update + apt-packages-install mongodb-10gen + ``` + +- `apt-packages-ppa(repository[, key[, server = 'keyserver.ubuntu.com']])` + + Add a Launchpad PPA as a software source. + + The `repository` is the Launchpad user and project name, e.g., `chris-lea/node.js`. + + `key` and `server` are the signing key and server. + The key needs to added to your system so Ubuntu can verify the packages from the PPA. + + Example (install Node.js from unofficial PPA): + + ```bash + apt-packages-ppa 'chris-lea/node.js' + apt-packages-update + apt-packages-install \ + nodejs \ + npm + ``` + +- `apt-packages-update` + + Update `aptitude` packages without any prompts. + +- `apt-packages-install(package[, package[, ...]])` + + Perform an unattended installation of package(s). + + Example: + + ```bash + apt-packages-update + apt-packages-install \ + apache2-mpm-worker \ + apache2-suexec-custom \ + mysql-server-5.1 \ + libapache2-mod-fastcgi \ + php5-cgi + ``` + +- `apt-packages-purge(package[, package[, ...]])` + + Perform an unattended complete removal (purge) of package(s). + + Example (purge `apache2` unnecessarily installed as part of the `php5` meta-package): + + ```bash + apt-packages-update + apt-packages-install php5 + apt-packages-purge 'apache2*' + ``` + +### System + +- `system-upgrade()` + + Run a complete system upgrade. + Be extremely careful as this operation can break packages, e.g., VirtualBox Guest Additions if a new kernel is installed. + + Example: + + ```bash + apt-packages-update + system-upgrade + ``` + +- `system-service(name, action)` + + Command a system service, e.g., `apache2`, `mysql`, etc. + + Example: + + ```bash + system-service php5-fpm restart + ``` + +- `system-escape([glue = '-'])` + + Escape and normalize a string so it can be used safely in file names, etc. + You can optionally specify `glue` to be a different character, e.g., an underscore `_` if you are using the result as part of a variable name. + + Example: + + ```bash + echo "Hello World!" | system-escape # prints 'hello-world' + ``` + +### Default Commands + +- `alternatives-ruby-install(version[, bin_path = '/usr/bin/'[, man_path = '/usr/share/man/man1/'[, priority = 500]]])` + + Update the Ruby binary link to point to a specific version. + + Example: + + ```bash + apt-packages-install \ + ruby1.9.1 \ + ruby1.9.1-dev \ + rubygems1.9.1 + alternatives-ruby-install 1.9.1 + ``` + +- `alternatives-ruby-gems()` + + Create symbolic links to RubyGems binaries. + + By default, RubyGems on Ubuntu does not create binaries on `$PATH`. + Using this function would create a symbolic link in the directory of your `ruby` binary which is assumed to be on `$PATH`. + + Example (install stable versions of Sass and link it as `/usr/bin/sass`): + + ```bash + apt-packages-install \ + ruby1.9.1 \ + ruby1.9.1-dev \ + rubygems1.9.1 + alternatives-ruby-install 1.9.1 + github-gems-install 'nex3/sass' + alternatives-ruby-gems 'sass' + ``` + +### Apache + +- `apache-modules-enable(module[, module[, ...]])` + + Enable a list of Apache modules. This requires a server restart. + +- `apache-modules-disable(module[, module[, ...]])` + + Disable a list of Apache modules. This requires a server restart. + +- `apache-sites-enable(name[, name[, ...]])` + + Enable a list of Apache sites. This requires a server restart. + +- `apache-sites-disable(name[, name[, ...]])` + + Disable a list of Apache sites. This requires a server restart. + +- `[PHP=/path/to/binary] apache-sites-create(name[, path = name[, user = name[, group = user[, verbosity = info]]]])` + + Create a new Apache site and set up Fast-CGI components. + + The function creates a new file under `sites-available/name` where `name` is the first argument to the function. + + To set up Fact-CGI, a new directory `.cgi-bin` is created in `path` if it doesn't already exist. + + The virtual host is pointed to `path` or `/name` if `path` is omitted. + + **SuExec is required** and a user and group options are set up so permissions can work properly. + + If you prefix the function with `PHP=/path/to/binary`, PHP will be enabled through a Fast-CGI script in `.cgi-bin`. You must have PHP installed. + + Example (create a new `vagrant` website from `/vagrant` and enable PHP): + + ```bash + PHP=/usr/bin/php-cgi apache-sites-create 'vagrant' + apache-sites-enable vagrant + apache-restart + ``` + +- `apache-restart` + + Restart the Apache server and reload with new configuration. + + Example: + + ```bash + apache-modules-enable actions rewrite fastcgi suexec + apache-restart + ``` + +### Nginx + +- `nginx-sites-enable(name[, name[, ...]])` + + Enable a list of Nginx sites. This requires a server restart. + +- `nginx-sites-disable(name[, name[, ...]])` + + Disable a list of Nginx sites. This requires a server restart. + +- `[PHP=any-value] nginx-sites-create(name[, path = name[, user = name[, group = user[, index = 'index.html'[, verbosity = info]]]]])` + + Create a new Nginx site and set up Fast-CGI components. + + The function creates a new file under `sites-available/name` where `name` is the first argument to the function. + + The virtual host is pointed to `path` or `/name` if `path` is omitted. + + If you prefix the function with `PHP=any-value`, PHP will be enabled through a PHP-FPM. You must have `php5-fpm` installed. + + The arguments `user` and `group` are used to re-configure PHP-FPM's default `www` pool to run under the given account. + + You can optionally specify space-separated directory index files to look for if a file name wasn't specified in the request. + + Example (create a new `vagrant` website from `/vagrant` and enable PHP): + + ```bash + PHP=/usr/bin/php5-fpm nginx-sites-create 'vagrant' + nginx-sites-enable vagrant + nginx-restart + ``` + +### PHP + +- `php-settings-update(name, value)` + + Update a PHP setting value. + This function will look for all `php.ini` files in `/etc`. + For each file, a `conf.d` directory would be created in the parent directory (if one doesn't already exist) and inside a file specifying the setting name/value will be placed. + + Example (create a default timezone): + + ```bash + php-settings-update 'date.timezone' 'Europe/London' + ``` + +- `php-pecl-install(extension[, extension[, ...]])` + + Install (download, build, install) and enable a PECL extension. + + You may optionally specify the state/version using '@version'. + + Example (install MongoDB driver): + + ```bash + apt-packages-install \ + php5-dev \ + php-pear + php-pecl-install mongo + + # Install a specific version of 'proctitle'. + php-pecl-install proctitle@0.1.2 + ``` + +- `php-fpm-restart` + + Restart the PHP5-FPM server. + +### MySQL + +- `mysql-database-create(name[, charset = 'utf8'[, collision = 'utf8_general_ci']])` + + Create a database if one doesn't already exist. + +- `mysql-database-restore(name, path)` + + Restore a MySQL database from an archived backup. + + This function scans for files in `path` (non-recursive) that match the format: + + ``` + ^[0-9]{8}-[0-9]{4}.tar.bz2$ + ``` + + e.g., `20120101-1200.tar.bz2`. The matching files are sorted based on the file name and the newest one is picked. + + If the database `name` is empty, i.e., it doesn't contain any tables, the latest backup is piped to `mysql`. + + Example (where `/database-backups` is shared from `Vagrantfile`): + + ```bash + mysql-database-restore 'project' '/database-backups' + ``` + +- `mysql-remote-access-allow` + + Allow remote passwordless `root` access for anywhere. + + This is only a good idea if the box is configured in 'Host-Only' network mode. + +- `mysql-restart` + + Restart the MySQL server and reload with new configuration. + +### RubyGems + +- `ruby-gems-version(package)` + + Check the installed version of a package, if any. + + When a package is not installed, `0.0.0` is returned. + +- `ruby-gems-install(package[, arg[, ...]])` + + Perform an unattended installation of a package. + + If a package is already installed, it will not be re-installed or upgraded. + + Example: + + ```bash + apt-packages-install \ + ruby1.9.1 \ + ruby1.9.1-dev \ + rubygems1.9.1 + alternatives-ruby-install 1.9.1 + ruby-gems-install pkg-config + ruby-gems-install sass --version '3.2.1' + ``` + +### NPM (Node Package Manager) + +- `npm-packages-install(package[, package[, ...]])` + + Perform an unattended **global** installation of package(s). + + Example (install UglifyJS): + + ```bash + apt-packages-ppa 'chris-lea/node.js' + apt-packages-update + apt-packages-install \ + nodejs \ + npm + npm-packages-install uglify-js + ``` + +### GitHub + +- `github-gems-install(repository[, repository[, ...]])` + + Download and install RubyGems from GitHub. + + The format of each `repository` is `user/project[@branch]` where `branch` can be omitted and defaults to `master`. + + If a package is already installed, it will not be re-installed or upgraded. + + Example (install unstable versions of Sass and Compass): + + ```bash + apt-packages-install \ + ruby1.9.1 \ + ruby1.9.1-dev \ + rubygems1.9.1 + alternatives-ruby-install 1.9.1 + github-gems-install \ + 'ttilley/fssm' \ + 'nex3/sass@master' \ + 'wvanbergen/chunky_png' \ + 'chriseppstein/compass@master' + ``` + +- `github-php-extension-install(specification[, specification[, ...]])` + + Download and install PHP extensions from GitHub. + + The `specification` is a string which contains the repository name (mandatory), version (optional) and `./configure` arguments (optional): + `repository@version --option --option argument` + + Example (install native PHP Redis extension from GitHub): + + ```bash + github-php-extension-install 'nicolasff/phpredis' + + # Use a specific commit and pass arguments to `./configure`. + github-php-extension-install 'nicolasff/phpredis@5e5fa7895f --enable-redis-igbinary' + ``` + +### Environment + +- `env-append(env_key, env_value[, env_comment])` + + Append an environment line to the global Bash/Zsh profile. + + `env_key` can be anything, but the following values have special meaning: + + * `PATH` - extend the `PATH` environment variable with a new directory, + * `source` - include an external file (be careful not to `set -e`). + + Any other key would be `export`ed when a new session is initialized. + + Example (set `JAVA_HOME` for scripts that rely on it): + + ```bash + env-append 'JAVA_HOME' "/usr/lib/jvm/java-7-openjdk-$( uname -i )" + + # $ tail -2 /etc/profile + # # AUTO-GENERATED: JAVA_HOME. + # [ -z "$JAVA_HOME" ] && export JAVA_HOME='/usr/lib/jvm/java-7-openjdk-i386' + ``` + +Extras +------ + +The `ubuntu-extras.sh` file provides useful but rarely used commands. + +### Archives + +- `archive-file-unpack(file[, directory])` + + Unpack the given archive `file` in `directory` (created if missing). The format is guessed from the file extension. + + Example: + + ```bash + archive-file-unpack 'rsync-HEAD.tar.gz' '/tmp/' + ``` + +### Packages (e.g., ZIP distributions) + +- `package-ignore-preserve(package_name, package_path, preserved_path)` + + Read a `.gitignore` file in the given `package_path` and remove matching files in `{preserved_path}/{package_name}-*`. + This is useful when the contents of an unpacked archive are to be copied over a version-controlled directory and certain files should **not** be overwritten. + + Example: + + ```bash + package-ignore-preserve 'hadoop' 'vendor/hadoop' '/tmp/hadoop-download' + ``` + +- `package-uri-download(uri[, target])` + + Download the file at `uri` to the given directory `target` or `STDOUT`. + + Example: + + ```bash + package-uri-download 'http://www.samba.org/ftp/rsync/nightly/rsync-HEAD.tar.gz' '/tmp' + ``` + +- `package-uri-install(package_name, package_uri[, package_index[, package_path[, package_version]]])` + + Download, unpack and install the package at `package_uri` to `package_path`. + This function does a lot internally and can be used to automate installations of certain ZIP distributions. + The URI and path support placeholders: + + * `%name` will be substituted with the `package_name`, + * `%path` for `package_path`, + * `%version` for `package_version`. + + `package_index` should be a file which determines if the package has already been installed. It would usually point to a binary file inside the distribution archive. If omitted, it defaults to `{package_path}/bin/{package_name}`. + + If `package_path` is omitted, a variable `{PACKAGE_NAME}_PATH` is expected. E.g., if `package_name` is 'rsync' a variable named `RSYNC_PATH` must exist. + If `package_version` is omitted, a variable `{PACKAGE_NAME}_VERSION` is expected. + + Requires `curl` to be installed. + + Example (installing Node.js from binary distribution): + + ```bash + # {{{ Configuration + + NODE_PATH='/vagrant/vendor/node' + NODE_VERSION=0.8.22 + NODE_PLATFORM=x86 + + PHANTOMJS_VERSION=1.8.1 + PHANTOMJS_PATH='/vagrant/vendor/phantomjs' + PHANTOMJS_PLATFORM=i686 + + # }}} + + # Download and install Node.js from the official website. + package-uri-install 'node' "http://nodejs.org/dist/v%version/node-v%version-linux-${NODE_PLATFORM}.tar.gz" + + # Download and install PhantomJS from the official website. + package-uri-install 'phantomjs' "https://phantomjs.googlecode.com/files/phantomjs-%version-linux-${PHANTOMJS_PLATFORM}.tar.bz2" + + # Node.js installed as: /vagrant/vendor/node/bin/node + # PhantomJS installed as: /vagrant/vendor/phantomjs/bin/phantomjs + ``` + +### Temporary Files + +- `temporary-cleanup(tmp_path[, ...])` + + Delete the contents of each `tmp_path` and halt script with the exit code of the last executed command. + + Example (compile a project and clean up on failure): + + ```bash + TMP_PATH="$( mktemp -d -t 'package-XXXXXXXX' )" + git clone 'git://github.com/project/package.git' "$TMP_PATH" + ( \ + cd "$TMP_PATH" && \ + ./configure && \ + make && make install \ + ) || temporary-cleanup "$TMP_PATH" + ``` + +PostgreSQL +---------- + +The `ubuntu-postgres.sh` file provides functions for manipulating a PostgreSQL server instance. + +- `postgres-remote-access-allow()` + + Allow remote access for the private `192.168.1.1/22` network (`192.168.0.1` through `192.168.3.254`). + + This is only a good idea if the box is configured in 'Host-Only' network mode. + +- `postgres-password-reset(password)` + + Reset the `postgres` user server password. This also allows password-based authentication. + + Example: + + ```bash + postgres-password-reset 'password' + ``` + +- `postgres-autovacuum-on()` + + Turn [autovacuuming](http://www.postgresql.org/docs/9.2/static/runtime-config-autovacuum.html) on. + +- `postgres-template-encoding(encoding = 'UTF8'[, ctype = 'en_GB.utf8'[, collate = ctype]])` + + Set the default database encoding and collision. + Newly created databases will inherit those properties. + + Example (use UTF-8 for all new databases): + + ```bash + postgres-template-encoding 'UTF8' 'en_GB.utf8' + ``` + +Postfix +------- + +The `ubuntu-postfix.sh` file provides functions for manipulating an SMTP server instance using Postfix. + +- `smtp-sink-install(directory[, template = '%Y%m%d/%H%M.'[, port = 25[, user = 'vagrant'[, service = 'smtp-sink'[, backlog = 10]]]]])` + + Hassle-free SMTP in development. Create a new system service which logs all outgoing e-mails to disk. + + > `directory` specifies the process root directory. + > The single-message files are created by expanding the `template` via strftime(3) and appending a pseudo-random hexadecimal number (example: "%Y%m%d%H/%M." expands into "2006081203/05.809a62e3"). If the template contains "/" characters, missing directories are created automatically. + + `port` specifies the port on which to listen. + `user` switches the user privileges after opening the network socket. The user must have permissions to write in `directory`. + + `service` is an optional name of the system Upstart service. A file with this name is created under `/etc/init/`. + + `backlog` specifies the maximum length the queue of pending connections, as defined by the listen(2) system call. + + Example (log all messages to the `mail/` directory in the project root): + + ```bash + smtp-sink-install '/vagrant/mail' + ``` + + The logged messages can be read using Thunderbird (append `.eml` to the file name). + +Environment +----------- + +The following variables can be defined before including the `ubuntu.sh` script: + +- `SUDO[ = 'sudo']` + + Specify the prefix for all super-user commands. If your system is configured with no `sudo` command, use an empty value. + + Example (set up Google DNS on a system with no `sudo` command): + + ```bash + SUDO= + + nameservers-local-purge + nameservers-append '8.8.8.8' + nameservers-append '8.8.4.4' + ``` + +- `COLORS[ = 'always']` + + Use terminal escape codes to print colourised output. If you wish to disable this, use a value other than `{always,yes,true,1}`. + + Example (turn off colours in output): + + ```bash + COLORS=never + + apt-packages-update + ``` + +Goal +---- + +As I explore different OSes, I hope to add support for more platforms. + +The functions should remain the same, so provisioning scripts are somewhat 'portable'. + +Full Example +------------ + +The provisioning script below sets up Apache, SuExec, a virtual host for `/vagrant` (the default share) and remote `root` access to MySQL. + +```bash +#!/usr/bin/env bash + +# {{{ Ubuntu utilities + +<%= import 'vagrant-shell-scripts/ubuntu.sh' %> + +# }}} + +# Use Google Public DNS for resolving domain names. +# The default is host-only DNS which may not be installed. +nameservers-local-purge +nameservers-append '8.8.8.8' +nameservers-append '8.8.4.4' + +# Use a local Ubuntu mirror, results in faster downloads. +apt-mirror-pick 'bg' + +# Update packages cache. +apt-packages-update + +# Install VM packages. +apt-packages-install \ + apache2-mpm-worker \ + apache2-suexec-custom \ + mysql-server-5.1 \ + libapache2-mod-fastcgi \ + php5-cgi \ + php5-gd \ + php5-mysql + +# Allow modules for Apache. +apache-modules-enable actions rewrite fastcgi suexec + +# Replace the default Apache site. +PHP=/usr/bin/php-cgi apache-sites-create 'vagrant' +apache-sites-disable default default-ssl +apache-sites-enable vagrant + +# Restart Apache web service. +apache-restart + +# Allow unsecured remote access to MySQL. +mysql-remote-access-allow + +# Restart MySQL service for changes to take effect. +mysql-restart +``` + +### Copyright + +> Copyright (c) 2012 Stan Angeloff. See [LICENSE.md](https://github.com/StanAngeloff/vagrant-shell-scripts/blob/master/LICENSE.md) for details. diff --git a/vagrant/scripts/vagrant-shell-scripts/ubuntu-extras.sh b/vagrant/scripts/vagrant-shell-scripts/ubuntu-extras.sh new file mode 100644 index 0000000000000..752fab3242102 --- /dev/null +++ b/vagrant/scripts/vagrant-shell-scripts/ubuntu-extras.sh @@ -0,0 +1,142 @@ +#!/usr/bin/env bash + +set -e + +# {{{ Archives + +archive-file-unpack() { + log-operation "$FUNCNAME" "$@" + if [ $# -lt 1 ]; then + echo 'Usage: '"$0"' FILE [DIRECTORY]' >/dev/stderr + return 1 + fi + local file + local directory + local command + local dependency + file="$( readlink -f "$1" )" + directory="${2:-.}" + case "$file" in + *.tar.gz | *.tgz ) command='tar -zxf' ;; + *.tar.bz2 | *.tbz2 ) command='tar -jxf' ;; + *.tar.xz ) command='tar -Jxf' ;; + *.tar ) command='tar -xf' ;; + *.zip ) command='unzip -q' ; dependency='unzip' ;; + *.7z ) command='7za x' ;; + *.gzip | *.gz ) command='gunzip -q' ;; + *.bzip2 | *.bz2 ) command='bunzip2 -q' ; dependency='bzip2' ;; + * ) + echo "$0: Unsupported file format: $file" >/dev/stderr ; + return 2 + ;; + esac + if [ ! -d "$directory" ]; then + mkdir -p "$directory" + fi + if [ -n "$dependency" ]; then + dependency-install "$dependency" + fi + ( cd "$directory" && eval $command \"\$file\" ) +} + +# }}} + +# {{{ Packages (e.g., ZIP distributions) + +package-ignore-preserve() { + local package_name="$1" package_path="$2" preserved_path="$3" + if [ -f "${package_path}/.gitignore" ]; then + for preserve in `cat "${package_path}/.gitignore" | grep '^!' | grep -v '/$' | sed -e 's#^!##g'`; do + eval "rm -f \"${preserved_path}/${package_name}-\"*\"/\"${preserve}" + done + fi +} + +package-uri-download() { + local uri + local target + dependency-install 'curl' + uri="$1" + shift + if [ -z "$1" ]; then + target="-s" + else + target="-o $1" + shift + fi + curl '-#' --insecure -L "$@" $target "$uri" +} + +package-uri-install() { + local package_name + local package_uri + local package_path + local package_version + local package_index + package_name="$1" + package_uri="$2" + package_index="$3" + package_path="$4" + package_version="$5" + if [ -z "$package_path" ]; then + package_path="$( echo "$package_name" | tr '-' '_' | tr 'a-z' 'A-Z' )_PATH" + package_path="${!package_path}" + fi + if [ -z "$package_version" ]; then + package_version="$( echo "$package_name" | tr '-' '_' | tr 'a-z' 'A-Z' )_VERSION" + package_version="${!package_version}" + fi + if [ -z "$package_index" ]; then + package_index="${package_path}/bin/${package_name}" + fi + for variable_name in 'package_uri' 'package_index'; do + eval "$variable_name"=\""$( \ + echo "${!variable_name}" | \ + sed -e 's#%name#'"$package_name"'#g' | \ + sed -e 's#%version#'"$package_version"'#g' | + sed -e 's#%path#'"$package_path"'#g' \ + )"\" + done + log-operation "$FUNCNAME" \ + "$package_name" \ + "$package_uri" \ + "$package_index" \ + "$package_path" \ + "$package_version" + if [ ! -f "$package_index" ]; then + dependency-install 'rsync' + TMP_PATH="$( mktemp -d -t "${package_name}-XXXXXXXX" )" + TMP_FILE="$TMP_PATH/$( basename "$package_uri" )" + package-uri-download "$package_uri" "$TMP_FILE" -f || return $? + archive-file-unpack "$TMP_FILE" "$TMP_PATH" + rm -f "$TMP_FILE" + package-ignore-preserve "$package_name" "$package_path" "$TMP_PATH" + rsync -rlptDP "$TMP_PATH/${package_name}-"*'/' "${package_path}/" + rm -Rf "$TMP_PATH" + fi +} + +# }}} + +# {{{ Temporary Files + +temporary-cleanup() { + local exit_code=$? tmp_path + for tmp_path in "$@"; do + if [ -d "$tmp_path" ]; then + rm -Rf "$tmp_path" + fi + done + exit $exit_code +} + +# }}} + +# {{{ Dependency Management + +# Create associations for packages we are going to install. +dependency-package-associate 'unzip' 'unzip' +dependency-package-associate 'bzip2' 'bzip2' +dependency-package-associate 'rsync' 'rsync' + +# }}} diff --git a/vagrant/scripts/vagrant-shell-scripts/ubuntu-postfix.sh b/vagrant/scripts/vagrant-shell-scripts/ubuntu-postfix.sh new file mode 100644 index 0000000000000..1f4010a931588 --- /dev/null +++ b/vagrant/scripts/vagrant-shell-scripts/ubuntu-postfix.sh @@ -0,0 +1,65 @@ +#!/usr/bin/env bash + +set -e + +# {{{ SMTP + +# Install an SMTP sink service which logs all outgoing e-mails to disk. +smtp-sink-install() { + log-operation "$FUNCNAME" "$@" + local smtp_sink_directory="$1" \ + smtp_sink_template="${2:-%Y%m%d/%H%M.}" \ + smtp_port="${3:-25}" \ + smtp_user="${4:-vagrant}" \ + smtp_service="${5:-smtp-sink}" \ + smtp_hard_bounce_reply="550 5.3.0 Sink'd." \ + smtp_hostname='localhost.localdomain' \ + smtp_backlog="${6:-10}" + if [ -z "$smtp_sink_directory" ]; then + echo -e "${ERROR_BOLD}E: ${ERROR_NORMAL}You must specify 'smtp_sink_directory' to '${FUNCNAME}' at position '1'.${RESET}" 1>&2 + exit 1 + fi + dependency-install 'postfix' + # If Postfix is currently running, stop it. + QUIET=1 system-service postfix status && system-service postfix stop || : + # Stop Postfix from running at start up. + $SUDO update-rc.d -f 'postfix' remove 1>/dev/null + # Kill any running smtp-sink services, try graceful shutdown first. + QUIET=1 system-service "$smtp_service" stop 1>/dev/null 2>&1 || : + $SUDO killall -q -9 smtp-sink || : + # Create a new service to log all e-mails to disk. + cat <<-EOD | $SUDO tee "/etc/init/${smtp_service}.conf" 1>/dev/null +# ${smtp_service} +# +# SMTP server which logs all outgoing e-mails to disk. + +description "${smtp_service}, logs all outgoing e-mails" + +start on runlevel [2345] +stop on runlevel [!2345] + +console log + +respawn +respawn limit 3 5 + +pre-start exec mkdir -p "$smtp_sink_directory" + +exec start-stop-daemon --start --exec "$( which smtp-sink )" -- \\ + -u "$smtp_user" \\ + -R "$( echo "$smtp_sink_directory" | sed -e 's#/$##' )/" -d "$smtp_sink_template" \\ + -f '.' -B "$smtp_hard_bounce_reply" \\ + -h "$smtp_hostname" "$smtp_port" "$smtp_backlog" +EOD + # Start the service. It will also run on next start up + system-service "$smtp_service" start +} + +# }}} + +# {{{ Dependency Management + +# Create associations for packages we are going to install. +dependency-package-associate 'postfix' 'postfix' + +# }}} diff --git a/vagrant/scripts/vagrant-shell-scripts/ubuntu-postgres.sh b/vagrant/scripts/vagrant-shell-scripts/ubuntu-postgres.sh new file mode 100644 index 0000000000000..65f20681396c1 --- /dev/null +++ b/vagrant/scripts/vagrant-shell-scripts/ubuntu-postgres.sh @@ -0,0 +1,53 @@ +#!/usr/bin/env bash + +set -e + +# {{{ PostgreSQL + +postgres-remote-access-allow() { + log-operation "$FUNCNAME" "$@" + $SUDO sed -e "s/[#]\?listen_addresses = .*/listen_addresses = '*'/g" -i '/etc/postgresql/'*'/main/postgresql.conf' + $SUDO grep '192.168.1.1' '/etc/postgresql/'*'/main/pg_hba.conf' | \ + ( echo 'host all all 192.168.1.1/22 md5' | $SUDO tee -a '/etc/postgresql/'*'/main/pg_hba.conf' >/dev/null ) +} + +postgres-password-reset() { + log-operation "$FUNCNAME" + $SUDO -u 'postgres' psql -c "ALTER ROLE postgres WITH ENCRYPTED PASSWORD '$1'" 1>/dev/null +} + +postgres-autovacuum-on() { + log-operation "$FUNCNAME" + $SUDO sed -e "s/[#]\?autovacuum = .*/autovacuum = on/g" -i '/etc/postgresql/'*'/main/postgresql.conf' + $SUDO sed -e "s/[#]\?track_counts = .*/track_counts = on/g" -i '/etc/postgresql/'*'/main/postgresql.conf' +} + +postgres-template-encoding() { + local encoding + local ctype + local collate + encoding="${1:-UTF8}" + ctype="${2:-en_GB.$( echo "$encoding" | tr 'A-Z' 'a-z' )}" + collate="${3:-$ctype}" + log-operation "$FUNCNAME" "$@" + SQL_TMP_FILE="$( mktemp -t 'sql-XXXXXXXX' )" + cat > "$SQL_TMP_FILE" <<-EOD +UPDATE pg_database SET datallowconn = TRUE WHERE datname = 'template0'; +\\c template0; +UPDATE pg_database SET datistemplate = FALSE WHERE datname = 'template1'; +DROP DATABASE template1; +CREATE DATABASE template1 WITH template = template0 ENCODING = '${encoding}' LC_CTYPE = '${ctype}' LC_COLLATE = '${collate}'; +UPDATE pg_database SET datistemplate = TRUE WHERE datname = 'template1'; +\\c template1; +UPDATE pg_database SET datallowconn = FALSE WHERE datname = 'template0'; +EOD + $SUDO chmod 0777 "$SQL_TMP_FILE" + $SUDO -u 'postgres' psql -f "$SQL_TMP_FILE" 1>/dev/null || { + EXIT_CODE=$? + rm "$SQL_TMP_FILE" + exit $EXIT_CODE + } + rm "$SQL_TMP_FILE" +} + +# }}} diff --git a/vagrant/scripts/vagrant-shell-scripts/ubuntu.sh b/vagrant/scripts/vagrant-shell-scripts/ubuntu.sh new file mode 100644 index 0000000000000..68020c9a71c23 --- /dev/null +++ b/vagrant/scripts/vagrant-shell-scripts/ubuntu.sh @@ -0,0 +1,796 @@ +#!/usr/bin/env bash + +set -e + +[ -n "${SUDO-x}" ] && SUDO='sudo' + +ERROR_BOLD="\e[1;31m" +ERROR_NORMAL="\e[0;31m" +DEBUG_BOLD="\e[1;35m" +DEBUG_NORMAL="\e[0;35m" +RESET="\e[00m" + +if [[ -n "$COLORS" ]] && [[ ! "$COLORS" =~ ^(always|yes|true|1)$ ]]; then + unset ERROR_BOLD + unset ERROR_NORMAL + unset DEBUG_BOLD + unset DEBUG_NORMAL + unset RESET +fi + +# {{{ Utils + +# Return the value of the first argument or exit with an error message if empty. +script-argument-create() { + [ -z "$1" ] && { + echo -e "${ERROR_BOLD}E: ${ERROR_NORMAL}You must specify $2 to '${BASH_SOURCE[0]}'.${RESET}" 1>&2 + exit 1 + } + echo "$1" +} + +# Log an operation +log-operation() { + local function_name + local function_values + local arg + function_name="$1" + shift + for arg in "$@"; do + function_values="$function_values ""'$( echo "$arg" | sed -e 's#\s\+# #g' )'" + done + [ -z "$QUIET" ] && echo -e "${DEBUG_BOLD}$function_name${DEBUG_NORMAL}(""$( echo "$function_values" | sed -e 's#^ ##' -e "s#\s\+''\$##g" )"")...${RESET}" +} + +# }}} + +# {{{ Nameservers + +# Drop all local 10.0.x.x nameservers in 'resolv.conf'. +nameservers-local-purge() { + log-operation "$FUNCNAME" "$@" + $SUDO sed -e 's#nameserver\s*10\.0\..*$##g' -i '/etc/resolv.conf' +} + +# Set up an IP as a DNS name server if not already present in 'resolv.conf'. +nameservers-append() { + log-operation "$FUNCNAME" "$@" + grep "$1" '/etc/resolv.conf' >/dev/null || \ + ( echo "nameserver $1" | $SUDO tee -a '/etc/resolv.conf' >/dev/null ) +} + +# }}} + +# {{{ Aptitude + +# Set up a specific two-letter country code as the preferred `aptitude` mirror. +apt-mirror-pick() { + log-operation "$FUNCNAME" "$@" + $SUDO sed -i \ + -e "s#\w\+\.archive\.ubuntu\.com#$1.archive.ubuntu.com#g" \ + -e "s#security\.ubuntu\.com#$1.archive.ubuntu.com#g" \ + '/etc/apt/sources.list' +} + +# Add a custom repository as a software source. +apt-packages-repository() { + log-operation "$FUNCNAME" "$@" + dependency-install 'add-apt-repository' + while [[ "$1" =~ ^deb ]] || [[ "$1" =~ ^ppa ]]; do + $SUDO add-apt-repository -y "$( echo "$1" | sed -e 's#^deb-src\b#deb#' )" 1>/dev/null + # See https://bugs.launchpad.net/ubuntu/+source/software-properties/+bug/972617 + if [[ "$1" =~ ^deb ]] && [[ ! "$1" =~ ^deb-src ]]; then + $SUDO add-apt-repository --remove -y "$( echo "$1" | sed -e 's#^deb\b#deb-src#' )" 1>/dev/null + fi + shift + done + if [ -n "$1" ] && ! $SUDO apt-key list | grep -q "$1"; then + $SUDO apt-key adv -q --keyserver "${2:-keyserver.ubuntu.com}" --recv-keys "$1" 1>/dev/null + fi +} + +# Add a Launchpad PPA as a software source. +apt-packages-ppa() { + local ppa_repository="$1" + shift + # If the repository is already set up, don't re-add it. + if ! apt-cache policy | grep "$ppa_repository" 1>/dev/null 2>&1; then + apt-packages-repository "ppa:${ppa_repository}" "$@" + fi +} + +# Perform a non-interactive `apt-get` command. +apt-non-interactive() { + log-operation "$FUNCNAME" "$@" + $SUDO \ + DEBIAN_FRONTEND=noninteractive \ + apt-get \ + -o Dpkg::Options::='--force-confdef' \ + -o Dpkg::Options::='--force-confold' \ + -f -y -qq \ + --no-install-recommends \ + "$@" +} + +# Update `aptitude` packages without any prompts. +apt-packages-update() { + apt-non-interactive update +} + +# Perform an unattended installation of package(s). +apt-packages-install() { + apt-non-interactive install "$@" +} + +# Perform an unattended complete removal (purge) of package(s). +apt-packages-purge() { + local result + local code + result=$( apt-non-interactive -q purge "$@" 2>&1 ) || { + code=$? + # If no packages matched, it's OK. + if [[ ! "$result" =~ "E: Couldn't find package" ]]; then + echo "$result" 1>&2 + exit $code + fi + } + # Take care of any leftovers. + apt-non-interactive autoremove +} + +# }}} + +# {{{ System + +# Run a complete system upgrade. +system-upgrade() { + apt-non-interactive upgrade +} + +# Command a system service, e.g., apache2, mysql, etc. +system-service() { + log-operation "$FUNCNAME" "$@" + $SUDO service "$1" "$2" 1>/dev/null +} + +# Escape and normalize a string so it can be used safely in file names, etc. +system-escape() { + local glue + glue=${1:--} + while read arg; do + echo "${arg,,}" | sed -e 's#[^[:alnum:]]\+#'"$glue"'#g' -e 's#^'"$glue"'\+\|'"$glue"'\+$##g' + done +} + +# }}} + +# {{{ Default Commands + +# Update the Ruby binary link to point to a specific version. +alternatives-ruby-install() { + log-operation "$FUNCNAME" "$@" + local bin_path + local man_path + bin_path="${2:-/usr/bin/}" + man_path="${3:-/usr/share/man/man1/}" + $SUDO update-alternatives \ + --install "${bin_path}ruby" ruby "${bin_path}ruby$1" "${4:-500}" \ + --slave "${man_path}ruby.1.gz" ruby.1.gz "${man_path}ruby$1.1.gz" \ + --slave "${bin_path}ri" ri "${bin_path}ri$1" \ + --slave "${bin_path}irb" irb "${bin_path}irb$1" \ + --slave "${bin_path}rdoc" rdoc "${bin_path}rdoc$1" + $SUDO update-alternatives --verbose \ + --set ruby "${bin_path}ruby$1" +} + +# Create symbolic links to RubyGems binaries. +alternatives-ruby-gems() { + log-operation "$FUNCNAME" "$@" + local ruby_binary + local ruby_version + local binary_name + local binary_path + ruby_binary=$( $SUDO update-alternatives --query 'ruby' | grep 'Value:' | cut -d' ' -f2- ) + ruby_version="${ruby_binary#*ruby}" + if grep -v '^[0-9.]*$' <<< "$ruby_version"; then + echo "E: Could not determine version of RubyGems." + fi + for binary_name in "$@"; do + binary_path="/var/lib/gems/$ruby_version/bin/$binary_name" + $SUDO update-alternatives --install "$( dirname "$ruby_binary" )/$binary_name" "$binary_name" "$binary_path" 500 + $SUDO update-alternatives --verbose --set "$binary_name" "$binary_path" + done +} + +# }}} + +# {{{ Apache + +# Enable a list of Apache modules. This requires a server restart. +apache-modules-enable() { + log-operation "$FUNCNAME" "$@" + $SUDO a2enmod $* 1>/dev/null +} + +# Disable a list of Apache modules. This requires a server restart. +apache-modules-disable() { + log-operation "$FUNCNAME" "$@" + $SUDO a2dismod $* 1>/dev/null +} + +# Enable a list of Apache sites. This requires a server restart. +apache-sites-enable() { + log-operation "$FUNCNAME" "$@" + $SUDO a2ensite $* 1>/dev/null +} + +# Disable a list of Apache sites. This requires a server restart. +apache-sites-disable() { + log-operation "$FUNCNAME" "$@" + $SUDO a2dissite $* 1>/dev/null +} + +# Create a new Apache site and set up Fast-CGI components. +apache-sites-create() { + log-operation "$FUNCNAME" "$@" + local apache_site_name + local apache_site_path + local apache_site_user + local apache_site_group + local apache_site_config + local apache_verbosity + local cgi_action + local cgi_apache_path + local cgi_system_path + local code_block + apache_site_name="$1" + apache_site_path="${2:-/$apache_site_name}" + apache_site_user="${3:-$apache_site_name}" + apache_site_group="${4:-$apache_site_user}" + apache_verbosity="${5:-info}" + apache_site_config="/etc/apache2/sites-available/$apache_site_name" + cgi_apache_path="/cgi-bin/" + cgi_system_path="$apache_site_path/.cgi-bin/" + # Create the /.cgi-bin/ directory and set permissions for SuExec. + $SUDO mkdir -p "$cgi_system_path" + $SUDO chmod 0755 "$cgi_system_path" + # Define a new virtual host with mod_fastcgi configured to use SuExec. + code_block=$( cat <<-EOD + + FastCgiWrapper /usr/lib/apache2/suexec + FastCgiConfig -pass-header HTTP_AUTHORIZATION -autoUpdate -killInterval 120 -idle-timeout 30 + + + + DocumentRoot ${apache_site_path} + + LogLevel ${apache_verbosity} + ErrorLog /var/log/apache2/error.${apache_site_name}.log + CustomLog /var/log/apache2/access.${apache_site_name}.log combined + + SuexecUserGroup ${apache_site_user} ${apache_site_group} + ScriptAlias ${cgi_apache_path} ${cgi_system_path} + + # Do not use kernel sendfile to deliver files to the client. + EnableSendfile Off + + + Options All + AllowOverride All + +EOD + ) + # Is PHP required? + if [ ! -z "$PHP" ]; then + cgi_action="php-fcgi" + code_block=$( cat <<-EOD +${code_block} + + + + SetHandler fastcgi-script + Options +ExecCGI +FollowSymLinks + Order Allow,Deny + Allow from all + + AddHandler ${cgi_action} .php + Action ${cgi_action} ${cgi_apache_path}${cgi_action} + +EOD + ) + $SUDO cat > "$cgi_system_path$cgi_action" <<-EOD +#!/bin/bash + +export PHP_FCGI_CHILDREN=4 +export PHP_FCGI_MAX_REQUESTS=200 + +export PHPRC="${cgi_system_path}php.ini" + +exec ${PHP} +EOD + $SUDO chmod 0755 "$cgi_system_path$cgi_action" + fi + code_block=$( cat <<-EOD +${code_block} +${EXTRA} + +EOD + ) + # Write site configuration to Apache. + echo "$code_block" | $SUDO tee "$apache_site_config" >/dev/null + # Configure permissions for /.cgi-bin/ and SuExec. + $SUDO chown -R "$apache_site_user":"$apache_site_group" "$cgi_system_path" + # Update SuExec to accept the new document root for this website. + grep "$apache_site_path" '/etc/apache2/suexec/www-data' >/dev/null || \ + ( $SUDO sed -e '1s#^#'"$apache_site_path""\n"'#' -i '/etc/apache2/suexec/www-data' >/dev/null ) +} + +# Restart the Apache server and reload with new configuration. +apache-restart() { + system-service apache2 restart +} + +# }}} + +# {{{ Nginx + +# Figure out the path to a particular Nginx site. +nginx-sites-path() { + echo "/etc/nginx/sites-${2:-available}/$1" +} + +# Enable a list of Nginx sites. This requires a server restart. +nginx-sites-enable() { + log-operation "$FUNCNAME" "$@" + local name + local file + for name in "$@"; do + file="$( nginx-sites-path "$name" 'enabled' )" + if [ ! -L "$file" ]; then + # '-f'orce because '! -L' above would still evaluate for broken symlinks. + $SUDO ln -fs "$( nginx-sites-path "$name" 'available' )" "$file" + fi + done +} + +# Disable a list of Nginx sites. This requires a server restart. +nginx-sites-disable() { + log-operation "$FUNCNAME" "$@" + local name + local file + for name in "$@"; do + file="$( nginx-sites-path "$name" 'enabled' )" + if [ -L "$file" ]; then + $SUDO unlink "$file" + fi + done +} + +# Create a new Nginx site and set up Fast-CGI components. +nginx-sites-create() { + log-operation "$FUNCNAME" "$@" + local nginx_site_name + local nginx_site_path + local nginx_site_index + local nginx_site_user + local nginx_site_group + local nginx_verbosity + local nginx_site_config + local code_block + nginx_site_name="$1" + nginx_site_path="${2:-/$nginx_site_name}" + nginx_site_user="${3:-$nginx_site_name}" + nginx_site_group="${4:-$nginx_site_user}" + nginx_site_index="${5:-index.html}" + nginx_verbosity="${6:-info}" + nginx_site_config="$( nginx-sites-path "$nginx_site_name" 'available' )" + # Is PHP required? + if [ ! -z "$PHP" ]; then + if ! which php5-fpm >/dev/null; then + echo 'E: You must install php5-fpm to use PHP in Nginx.' 1>&2 + exit 1 + fi + nginx_site_index="index.php $nginx_site_index" + fi + code_block=$( cat <<-EOD +server { + listen 80; + + root ${nginx_site_path}; + + error_log /var/log/nginx/error.${nginx_site_name}.log ${nginx_verbosity}; + access_log /var/log/nginx/access.${nginx_site_name}.log combined; + + index ${nginx_site_index}; + + # Do not use kernel sendfile to deliver files to the client. + sendfile off; + + # Prevent access to hidden files. + location ~ /\. { + access_log off; + log_not_found off; + deny all; + } +EOD + ) + # Is PHP required? + if [ ! -z "$PHP" ]; then + code_block=$( cat <<-EOD +${code_block} + + # Pass PHP scripts to PHP-FPM. + location ~ \.php\$ { + include fastcgi_params; + fastcgi_pass unix:/var/run/php5-fpm.${nginx_site_name}.sock; + fastcgi_index index.php; + fastcgi_split_path_info ^((?U).+\.php)(/?.+)\$; + fastcgi_param PATH_INFO \$fastcgi_path_info; + fastcgi_param PATH_TRANSLATED \$document_root\$fastcgi_path_info; + fastcgi_param HTTP_AUTHORIZATION \$http_authorization; + } +EOD + ) + # Run PHP-FPM as the selected user and group. + $SUDO sed \ + -e 's#^\[www\]$#['"$nginx_site_name"']#g' \ + -e 's#^\(user\)\s*=\s*[A-Za-z0-9-]\+#\1 = '"$nginx_site_user"'#g' \ + -e 's#^\(group\)\s*=\s*[A-Za-z0-9-]\+#\1 = '"$nginx_site_group"'#g' \ + -e 's#^\(listen\)\s*=\s*.\+$#\1 = /var/run/php5-fpm.'"$nginx_site_name"'.sock#g' \ + < '/etc/php5/fpm/pool.d/www.conf' | $SUDO tee '/etc/php5/fpm/pool.d/'"$nginx_site_name"'.conf' >/dev/null + fi + code_block=$( cat <<-EOD +${code_block} +${EXTRA} +} +EOD + ) + # Write site configuration to Nginx. + echo "$code_block" | $SUDO tee "$nginx_site_config" >/dev/null +} + +# Restart the Nginx server and reload with new configuration. +nginx-restart() { + system-service nginx restart +} + +# }}} + +# {{{ PHP + +# Update a PHP setting value in all instances of 'php.ini'. +php-settings-update() { + log-operation "$FUNCNAME" "$@" + local args + local settings_name + local php_ini + local php_extra + args=( "$@" ) + PREVIOUS_IFS="$IFS" + IFS='=' + args="${args[*]}" + IFS="$PREVIOUS_IFS" + settings_name="$( echo "$args" | system-escape )" + for php_ini in $( $SUDO find /etc -type f -iname 'php*.ini' ); do + php_extra="$( dirname "$php_ini" )/conf.d" + $SUDO mkdir -p "$php_extra" + echo "$args" | $SUDO tee "$php_extra/0-$settings_name.ini" >/dev/null + done +} + +# Install (download, build, install) and enable a PECL extension. +php-pecl-install() { + log-operation "$FUNCNAME" "$@" + local specification extension + local mode + dependency-install 'make' + dependency-install 'pecl' + dependency-install 'phpize' + for specification in "$@"; do + extension="${specification%@*}" + if ! $SUDO pecl list | grep "^${extension}" >/dev/null; then + $SUDO pecl install -s "${specification/@/-}" 1>/dev/null + fi + # Special case for Zend extensions. + if [[ "$extension" =~ ^(xdebug)$ ]]; then + mode="zend_extension" + extension="$( php-config --extension-dir )/${extension}" + else + mode="extension" + fi + php-settings-update "$mode" "${extension}.so" + done +} + +# Restart the PHP5-FPM server. +php-fpm-restart() { + system-service php5-fpm restart +} + +# }}} + +# {{{ MySQL + +# Create a database if one doesn't already exist. +mysql-database-create() { + log-operation "$FUNCNAME" "$@" + mysql -u root -e "CREATE DATABASE IF NOT EXISTS \`$1\` CHARACTER SET ${2:-utf8} COLLATE '${3:-utf8_general_ci}'" +} + +# Restore a MySQL database from an archived backup. +mysql-database-restore() { + log-operation "$FUNCNAME" "$@" + local backups_database + local backups_path + local backups_file + local tables_length + backups_database="$1" + backups_path="$2" + if [ -d "$backups_path" ]; then + tables_length=$( mysql -u root --skip-column-names -e "USE '$backups_database'; SHOW TABLES" | wc -l ) + if [ "$tables_length" -lt 1 ]; then + backups_file=$( find "$backups_path" -maxdepth 1 -type f -regextype posix-basic -regex '^.*[0-9]\{8\}-[0-9]\{4\}.tar.bz2$' | \ + sort -g | \ + tail -1 ) + if [ ! -z "$backups_file" ]; then + tar -xjf "$backups_file" -O | mysql -u root "$backups_database" + fi + fi + fi +} + +# Allow remote passwordless 'root' access for anywhere. +# This is only a good idea if the box is configured in 'Host-Only' network mode. +mysql-remote-access-allow() { + log-operation "$FUNCNAME" "$@" + mysql -u root -e "GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY '' WITH GRANT OPTION; FLUSH PRIVILEGES;" + $SUDO sed -e 's#127.0.0.1#0.0.0.0#g' -i '/etc/mysql/my.cnf' +} + +# Restart the MySQL server and reload with new configuration. +mysql-restart() { + system-service mysql restart +} + +# }}} + +# {{{ RubyGems + +# Check the installed version of a package. +ruby-gems-version() { + $SUDO ruby -rubygems -e "puts Gem::Specification::find_by_name('$1').version" 2>/dev/null || \ + echo '0.0.0' +} + +# Perform an unattended installation of a package. +ruby-gems-install() { + log-operation "$FUNCNAME" "$@" + local gem_version + gem_version="$( ruby-gems-version "$1" )" + if [[ "$gem_version" = '0.0.0' ]]; then + $SUDO gem install --no-ri --no-rdoc "$@" + fi +} + +# }}} + +# {{{ NPM (Node Package Manager) + +# Perform an unattended **global** installation of package(s). +npm-packages-install() { + log-operation "$FUNCNAME" "$@" + $SUDO npm config set yes true + $SUDO npm install -g $* +} + +# }}} + +# {{{ Oracle JDK (Oracle Java Development Kit) + +# Install Oracle JDK to /opt/java, update defaults and add it to PATH +oracle-jdk-install() { + log-operation "$FUNCNAME" "$@" + dependency-install 'curl' + local cookie + local jdk_link + local target + cookie="$1" + jdk_link="$2" + temp_dir="$3" + temp_out_file="$temp_dir"/oracle_jdk.tar.gz + # download if the file is not exists + if [ ! -f "$temp_out_file" ]; then + curl -L --progress-bar --header "$cookie" "$jdk_link" -z "$temp_out_file" -o "$temp_out_file" + fi + + tar -xf "$temp_out_file" -C "$temp_dir" + $SUDO mkdir -p /opt/ + $SUDO mv "$temp_dir"/jdk* /opt/java + + $SUDO update-alternatives --install "/usr/bin/java" "java" "/opt/java/bin/java" 1 + $SUDO update-alternatives --install "/usr/bin/javac" "javac" "/opt/java/bin/javac" 1 + $SUDO update-alternatives --install "/usr/bin/javaws" "javaws" "/opt/java/bin/javaws" 1 + + env-append 'JAVA_HOME' "/opt/java/" + env-append 'PATH' "/opt/java/bin/" +} + +# }}} + +# {{{ GitHub + +# Download and install RubyGems from GitHub. +github-gems-install() { + log-operation "$FUNCNAME" "$@" + local repository + local clone_path + local configuration + local gem_version + dependency-install 'git' + which 'gem' >/dev/null || { + echo 'E: Please install RubyGems to continue.' 1>&2 + exit 1 + } + for repository in "$@"; do + configuration=(${repository//@/"${IFS}"}) + gem_version="$( ruby-gems-version "${configuration[0]#*\/}" )" + if [[ "$gem_version" = '0.0.0' ]]; then + clone_path="$( mktemp -d -t 'github-'$( echo "${configuration[0]}" | system-escape )'-XXXXXXXX' )" + git clone --progress "git://github.com/${configuration[0]}" "$clone_path" + ( \ + cd "$clone_path" && \ + git checkout -q "${configuration[1]:-master}" && \ + gem build *.gemspec && \ + ruby-gems-install *.gem \ + ) + rm -Rf "$clone_path" + fi + done +} + +# Install (download, build, install) and enable a PECL extension. +github-php-extension-install() { + log-operation "$FUNCNAME" "$@" + local specification repository version arguments extension + local raw_config_uri clone_path + # We must have 'phpize' available when compiling extensions from source. + dependency-install 'git' + dependency-install 'curl' + dependency-install 'phpize' + for specification in "$@"; do + repository="$specification" + version='master' + # If we have a space anywhere in the string, assume `configure` arguments. + if [[ "$repository" =~ ' ' ]]; then + arguments=( ${repository#* } ) + repository="${repository%% *}" + fi + # If we have a version specified, split the repository name and version. + if [[ "$repository" =~ '@' ]]; then + version="${repository#*@}" + repository="${repository%@*}" + fi + # Let's figure out the extension name by looking at the autoconf file. + raw_config_uri="https://raw.github.com/${repository}/${version}/config.m4" + extension="$( curl --insecure --silent "$raw_config_uri" | grep -e 'PHP_NEW_EXTENSION' | cut -d'(' -f2 | cut -d',' -f1 | tr -d ' ' )" + if [ -z "$extension" ]; then + echo -e "${ERROR_BOLD}E: ${ERROR_NORMAL}Cannot find extension name in ${raw_config_uri}, expected 'PHP_NEW_EXTENSION'.${RESET}" 1>&2 + exit 1 + fi + # We can't use PECL to determine if the extension is installed + # so let's look for the .so file in the PHP extensions directory. + if ! $SUDO ls -1 "$( php-config --extension-dir )" | grep "^${extension}.so$" >/dev/null; then + clone_path="$( mktemp -d -t 'github-'$( echo "${repository}" | system-escape )'-XXXXXXXX' )" + # Clone, configure, make, install... the usual. + git clone --progress "git://github.com/${repository}" "$clone_path" + ( \ + cd "$clone_path" && \ + git checkout -q "$version" && \ + phpize && \ + ./configure "${arguments[@]}" && \ + make && $SUDO make install \ + ) + # Clean up and explicitly load the extension. + rm -Rf "$clone_path" + php-settings-update 'extension' "${extension}.so" + fi + done +} + +# }}} + +# {{{ Environment + +env-append() { + local env_key="$1" env_lookup=1 env_value="$2" env_comment="$3" env_line + log-operation "$FUNCNAME" "$@" + for profile_env in '/etc/profile' '/etc/zsh/zshenv'; do + if [ -f "$profile_env" ]; then + if [ "$env_key" == 'PATH' ]; then + env_line="export ${env_key}='${env_value}':"'"$PATH"' + elif [[ "$env_key" =~ ^(source|eval)$ ]]; then + env_line="${env_key} ${env_value} || :" + else + env_line="[ -z "'"$'"$env_key"'"'" ] && export ${env_key}='${env_value}'" + fi + eval "$env_line" || : + if ! grep "${env_key}.*${env_value}" "$profile_env" &>/dev/null; then + echo -e "\n# AUTO-GENERATED: ${env_key}$( echo ", ${env_comment}" | sed -e 's/^,\s*$//' ).\n${env_line}" | $SUDO tee -a "$profile_env" 1>/dev/null + fi + fi + done +} + +# }}} + +# {{{ Dependency Management + +# Associate a package name with a command, e.g., 'git' <- 'git-core'. +dependency-package-associate() { + local variable_name + variable_name="DEPENDENCY_$(echo "$1" | system-escape '_' | tr '[a-z]' '[A-Z]' )" + # If a second argument was specified... + if [ -n "$2" ]; then + # ...and a package name hasn't been associated with the command yet... + if [ -z "${!variable_name}" ]; then + # ...create a new association. + eval $variable_name=\""$2"\" + fi + else + echo "${!variable_name}" + fi +} + +# Satisfy a dependency by installing the associated package. +dependency-install() { + local binary_name + local package_name + local apt_update_required=0 + local apt_update_performed=0 + local apt_update_datetime apt_update_timestamp apt_update_ago + local timestamp_now + for binary_name in "$@"; do + which "$binary_name" >/dev/null || { + package_name="$( dependency-package-associate "$binary_name" )" + # If we cannot find the package name in the cache, request an update. + # This may happen if `apt-get update` was not run on the machine before. + if ! $SUDO apt-cache pkgnames | grep "$package_name" 1>/dev/null 2>&1; then + apt_update_required=1 + fi + # If the last time we updated the cache was more than a day ago, request an update. + # This is needed to prevent errors when trying to install an out-of-date package from the cache. + if [[ $apt_update_required -lt 1 ]] && [[ $apt_update_performed -lt 1 ]]; then + # Determine the last date/time any lists files were modified, newest first. + apt_update_datetime="$( \ + ls -lt --time-style='long-iso' '/var/lib/apt/lists/' 2>/dev/null | grep -o '\([0-9]\{2,4\}[^0-9]\)\{3\}[0-9]\{2\}:[0-9]\{2\}' -m 1 || \ + date +'%Y-%m-%d %H:%M' + )" + # Convert the YYYY-MM-DD HH:MM format to a Unix timestamo. + apt_update_timestamp=$( date --date="$apt_update_datetime" +'%s' 2>/dev/null || echo 0 ) + # Calculate the number of seconds that have passed since the newest update. + timestamp_now=$( date +'%s' ) + apt_update_ago=$(( $timestamp_now-$apt_update_timestamp )) + if [ $apt_update_ago -gt 86400 ]; then + apt_update_required=1 + fi + fi + # If the cache needs updating, do so before installing the package (once per call only). + if [[ $apt_update_required -gt 0 ]] && [[ $apt_update_performed -lt 1 ]]; then + apt_update_required=0 + apt_update_performed=1 + apt-packages-update + fi + apt-packages-install "$package_name" + } + done +} + +# Create associations for packages we are going to install. +dependency-package-associate 'add-apt-repository' 'python-software-properties' +dependency-package-associate 'curl' 'curl' +dependency-package-associate 'git' 'git-core' +dependency-package-associate 'make' 'build-essential' +dependency-package-associate 'pecl' 'php-pear' +dependency-package-associate 'phpize' 'php5-dev' + +# }}} diff --git a/vagrant/scripts/vagrant-shell-scripts/vagrant.rb b/vagrant/scripts/vagrant-shell-scripts/vagrant.rb new file mode 100644 index 0000000000000..aef95a52b2913 --- /dev/null +++ b/vagrant/scripts/vagrant-shell-scripts/vagrant.rb @@ -0,0 +1,26 @@ +require 'erb' + +def vagrant_shell_scripts_configure(shell, scripts_path, script_name = 'provision') + shell.privileged = false + shell.inline = ERB.new(<<-eos +<% + +def import(file) + ['#{ scripts_path }', '#{ File.dirname(__FILE__) }'].each do |path| + if File.file?(File.join(path, file)) + return ERB.new( + File.read( + File.join(path, file) + ) + ).result(binding) + end + end + raise ArgumentError, 'The file "' + file + '" cannot be imported.' +end + +%> + +<%= import '#{ script_name }' %> + eos + ).result +end \ No newline at end of file From 42907d051923ff815da7e59608d867df6ab859ca Mon Sep 17 00:00:00 2001 From: Binh Nguyen Date: Thu, 27 Feb 2014 00:25:05 -0800 Subject: [PATCH 2/2] Shell scripts to copy public key to Vagrant nodes --- vagrant/copy-keys.sh | 11 +++++++++++ vagrant/vagrant_nodes.sh | 16 ++++++++++++++++ 2 files changed, 27 insertions(+) create mode 100755 vagrant/copy-keys.sh create mode 100644 vagrant/vagrant_nodes.sh diff --git a/vagrant/copy-keys.sh b/vagrant/copy-keys.sh new file mode 100755 index 0000000000000..9889ed3bd271e --- /dev/null +++ b/vagrant/copy-keys.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env bash + +# make sure all the nodes are up +# vagrant up 1>/dev/null 2>&1 + +source vagrant_nodes.sh + +sshpass -p "$VAGRANT_SPARK_PASSWORD" ssh-copy-id "$VAGRANT_SPARK_USER"@"$VAGRANT_SPARK_MASTER" 1>/dev/null 2>&1 +sshpass -p "$VAGRANT_SPARK_PASSWORD" ssh-copy-id "$VAGRANT_SPARK_USER"@"$VAGRANT_SPARK_WORKER_1" 1>/dev/null 2>&1 +sshpass -p "$VAGRANT_SPARK_PASSWORD" ssh-copy-id "$VAGRANT_SPARK_USER"@"$VAGRANT_SPARK_WORKER_2" 1>/dev/null 2>&1 + diff --git a/vagrant/vagrant_nodes.sh b/vagrant/vagrant_nodes.sh new file mode 100644 index 0000000000000..bd6fa7740c33f --- /dev/null +++ b/vagrant/vagrant_nodes.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash + +# user +export VAGRANT_SPARK_USER="spark-user" + +# password +export VAGRANT_SPARK_PASSWORD="spark" + +# master ip +export VAGRANT_SPARK_MASTER="192.168.2.10" + +# worker 1 ip +export VAGRANT_SPARK_WORKER_1="192.168.2.20" + +# worker 2 ip +export VAGRANT_SPARK_WORKER_2="192.168.2.21"