├── .gitignore ├── README.md ├── basic ├── .gitignore ├── README.md ├── project.clj └── src │ └── demo.clj ├── bin └── set-version.sh ├── blank-project ├── .gitignore ├── README.md ├── project.clj ├── resources │ └── logback.xml ├── settings.xml ├── src │ └── blank_project │ │ └── core.clj ├── test-resources │ └── logback-test.xml └── test │ └── blank_project │ └── test │ └── core.clj ├── check-readmes.sh ├── hudson ├── .gitignore ├── README.md ├── project.clj ├── resources │ ├── log4j.properties │ └── log4j.properties.debug ├── src │ └── hudson │ │ └── ci.clj └── test │ └── hudson │ └── test │ └── core.clj ├── integration-tests ├── README ├── cake-test.sh ├── lein-test.sh └── log4j.properties ├── mini-webapp ├── .gitignore ├── README.md ├── project.clj ├── src │ ├── mini_webapp │ │ ├── Servlet.clj │ │ ├── app.clj │ │ ├── core.clj │ │ └── jetty.clj │ └── web.xml └── test │ └── mini_webapp │ └── test │ └── core.clj ├── nano-webapp ├── pom.xml └── src │ └── main │ └── webapp │ ├── WEB-INF │ └── web.xml │ └── index.jsp ├── test-all.sh └── webapp-haproxy-nodes ├── README.md ├── config.clj ├── project.clj ├── resources └── logback.xml └── src └── webapp_nodes ├── crates.clj └── nodes.clj /.gitignore: -------------------------------------------------------------------------------- 1 | lein 2 | log 3 | logs 4 | *.war 5 | .cake 6 | checkouts 7 | lib 8 | target 9 | tmp 10 | **/test-resources/log4j.properties 11 | **/pom.xml 12 | integration.log 13 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # pallet-examples 2 | 3 | This repository contains various examples of using 4 | [pallet](https://github.com/pallet/pallet). 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 |
projectdescription
basicBasic interactive usage.
blank-projectA project that is configured to use pallet
webapp-haproxy-nodesA muilti-node containing webapp and proxy definitions to setup a number of webapps proxied by one node running haproxy
hudson(NOTICE: not yet tested for pallet 0.6.x) A project containing pallet node definition for setting up a hudson ci server
27 | 28 | ![pallet logo](https://github.com/downloads/pallet/pallet/pallet-logo.png) 29 | 30 | ## License 31 | 32 | Copyright (C) 2010 Hugo Duncan 33 | 34 | Distributed under the Eclipse Public License. 35 | -------------------------------------------------------------------------------- /basic/.gitignore: -------------------------------------------------------------------------------- 1 | pom.xml 2 | *jar 3 | lib 4 | classes 5 | -------------------------------------------------------------------------------- /basic/README.md: -------------------------------------------------------------------------------- 1 | # basic 2 | 3 | Project with basic pallet usage. 4 | 5 | This project assumes you are using some sort of Linux or Unix. It can 6 | work with Windows too, but you might have to manually setup SSH. 7 | 8 | ## Usage 9 | 10 | - `git clone https://github.com/pallet/pallet-examples` or, download 11 | the [tarball](https://github.com/pallet/pallet-examples/tarball/master). 12 | 13 | - Install [Leiningen](http://github.com/technomancy/leiningen). 14 | 15 | - In a shell, assuming the code is in the pallet-examples directory, enter 16 | 17 | $ cd pallet-examples/basic 18 | $ lein deps 19 | $ lein repl 20 | 21 | - Work through the code in [pallet-examples/basic/src/demo.clj](https://github.com/pallet/pallet-examples/blob/master/basic/src/demo.clj) 22 | 23 | ## License 24 | 25 | Copyright (C) 2010 Hugo Duncan 26 | 27 | Distributed under the Eclipse Public License. 28 | -------------------------------------------------------------------------------- /basic/project.clj: -------------------------------------------------------------------------------- 1 | (defproject basic "0.6.0" 2 | :description "Basic Pallet Usage" 3 | :dependencies [[org.cloudhoist/pallet "0.6.8"] 4 | [org.cloudhoist/pallet-crates-all "0.5.0"] 5 | ;; jclouds imports 6 | [org.jclouds/jclouds-all "1.2.1"] 7 | [org.jclouds/jclouds-compute "1.2.1"] 8 | [org.jclouds/jclouds-blobstore "1.2.1"] 9 | [org.jclouds.driver/jclouds-jsch "1.2.1"] 10 | [org.jclouds.driver/jclouds-slf4j "1.2.1"] 11 | ;; logging 12 | [ch.qos.logback/logback-core "1.0.0"] 13 | [ch.qos.logback/logback-classic "1.0.0"]] 14 | :dev-dependencies [[swank-clojure/swank-clojure "1.3.2"] ; swank 15 | [org.cloudhoist/pallet-lein "0.4.1"]] ; lein 16 | :repositories 17 | {"sonatype" "http://oss.sonatype.org/content/repositories/releases"}) 18 | -------------------------------------------------------------------------------- /basic/src/demo.clj: -------------------------------------------------------------------------------- 1 | (ns #^{:author "Hugo Duncan"} 2 | demo 3 | "This is an introductory example of using pallet.") 4 | 5 | ;; First we load the pallet commands into 6 | (require 'pallet.repl) 7 | (pallet.repl/use-pallet) 8 | (use '[pallet.phase :only [phase-fn]]) 9 | 10 | 11 | ;; Supported providers can be found with: 12 | (supported-providers) 13 | 14 | ;; We provide some credentials to our cloud provider... 15 | (def my-user "your user") 16 | (def my-password "your api key") 17 | 18 | ;; ...and log in to the cloud using the credentials defined above. 19 | ;; provider is a string specifiying the provider, as returned 20 | ;; from (supported-providers). For example, for Amazon Web Service's 21 | ;; EC2, the provider is "aws-ec2" 22 | (def my-service 23 | (compute-service "provider" :identity my-user :credential my-password)) 24 | 25 | ;; current compute nodes in your account can be listed with the nodes 26 | ;; function (you might see none now if your account is new): 27 | (nodes my-service) 28 | 29 | ;; Pallet does not address nodes directly, the smallest unit it 30 | ;; addresses is a node group or just `group`. A group can have any 31 | ;; number of identical nodes. A single node is then a group with just 32 | ;; one istance of a node. 33 | 34 | ;; In order to create compute nodes, we need to first define a node 35 | ;; group, and we do so with `group-spec`. The group-spec function 36 | ;; takes one mandatory argument: `name` which is the name that pallet 37 | ;; will use to identify nodes in this group created in the cloud 38 | ;; provider. For example, the following is a minimal group 39 | ;; specification, named `webserver` 40 | 41 | (def webserver (group-spec "webserver")) 42 | 43 | ;; The other arguments for group-spec are optional. For now we will 44 | ;; use the parameter `:node-spec` which provides a hardware, OS (image) and 45 | ;; network specificaton for the nodes. For example, the following 46 | ;; group spec defines nodes of the smalles size provided by the cloud 47 | ;; provider and running Ubuntu, and with the network firewalls 48 | ;; configured so that ports 80 and 8080 are publicly accessible. 49 | 50 | (def balancer 51 | (group-spec "balancer" 52 | :node-spec {:image {:os-family :ubuntu} 53 | :hardware {:smallest true} 54 | :network {:inbound-ports [80 8080]}})) 55 | 56 | ;; At this point we can start creating nodes via the cloud provider. 57 | ;; The way it is done is by specifying how many nodes of each group we 58 | ;; want. Pallet will ensure that we have as many nodes as we need. To 59 | ;; do so, it will first check with the cloud provider for existing 60 | ;; nodes of this group, and then will determine if it needs to create 61 | ;; more nodes, destroy some or do nothing. 62 | ;; 63 | ;; converge is the function that will perform this task. In the 64 | ;; following example we instruct pallet to make it so that we have 2 65 | ;; nodes of the `webserver` group. Notice that we specify with which 66 | ;; cloud provider we want pallet to work in `:compute`; in this case 67 | ;; we use the one we just created. 68 | 69 | (converge {webserver 2} :compute my-service) 70 | 71 | ;; Now let's say we want two webservers and one balancer: 72 | 73 | (converge {webserver 2 balancer 1} :compute my-service) 74 | 75 | ;; Finally, if we want to remove all the nodes in one group, we do the 76 | ;; following. (Please NOTE: at this point make sure run this command, as the 77 | ;; rest of the tutorial assumes you did so) 78 | 79 | (converge {webserver 0 balancer 0} :compute my-service) 80 | 81 | ;; Images are configured differently between clouds and os's. 82 | ;; Pallet comes with some \"crates\" that can be used to normalise 83 | ;; the images. 84 | ;; 85 | ;; One very useful examples is `automated-admin-user`, a crate that 86 | ;; creates an admin user for your nodes. The default behavior for this 87 | ;; crate is to use your current login name, and authorize your local 88 | ;; ssh key (id_rsa in ~/.ssh in your home directory). This way, you 89 | ;; can quickly ssh into your node without needing to log into your 90 | ;; cloud provider to download the password or authentication keys. 91 | 92 | ;; The following code creates a new group-spec that contains what's 93 | ;; called a phase (defined under `:phases`. A Phase is just a named 94 | ;; function that can be executed during a converge session. 95 | 96 | ;; By default, when a node is newly created, if a `:bootstrap` phase 97 | ;; is defined, this phase will be run. This is a special phase that is 98 | ;; executed by the cloud provider itself right after the node is 99 | ;; created and doesn't require any authentication, hence is the 100 | ;; perfect time to create our user. 101 | 102 | (use 'pallet.crate.automated-admin-user) 103 | 104 | (def webserver 105 | (group-spec "webserver" 106 | :phases {:bootstrap (phase-fn (automated-admin-user))})) 107 | 108 | ;; Assuming you have deleted all the nodes as instructed above, the 109 | ;; next command will create a new `webserver` node, this time with an 110 | ;; admin user created, named as your user, and with your ssh keys 111 | ;; authenticated to it. The results of this command will be stored in 112 | ;; `results`. 113 | 114 | (def results 115 | (converge {webserver 1} :compute my-service)) 116 | 117 | ;; results will contain a large amount of information, including the 118 | ;; logs resulting from Pallet running all the scripts on the nodes on 119 | ;; your behalf (in this case, to create this admin user). 120 | 121 | ;; For now, we want to get the IP address of the nodes in the 122 | ;; `webserver` group. To do so we just inspect the contents of 123 | ;; :all-nodes in the results, which will print some of the relevant 124 | ;; node information, including the public address. 125 | 126 | (:all-nodes results) 127 | 128 | ;; Go ahead and ssh into the public address of your freshly created 129 | ;; node. If all went well, you should be logged right in, no password 130 | ;; needed. 131 | 132 | ;; Crates can do many (every?) things, for example, install software. 133 | ;; The following conde snippet redefines the `webservice` group to 134 | ;; install `Java` during the `:configure` phase. `:configure` is 135 | ;; another special phase that is run by configure by default, uless 136 | ;; otherwise specified. (There is only another special phase, 137 | ;; `:settings`, not covered in this tutorial) 138 | 139 | (use 'pallet.crate.java) 140 | (def webserver 141 | (group-spec "webserver" 142 | :phases {:bootstrap (phase-fn (automated-admin-user)) 143 | :configure (phase-fn (java :openjdk))})) 144 | 145 | ;; Reconverging the group will result in Java being installed in all 146 | ;; the nodes of the group. 147 | 148 | (converge {webserver 1} :compute my-service) 149 | 150 | ;; If you do not want to adjust the number of nodes, there is also 151 | ;; a lift function, which can be used to apply the configuration to 152 | ;; all existing nodes of the group. 153 | 154 | (lift webserver :compute my-service) 155 | 156 | ;; The following group-spec redefines `webserver` to add an arbitrary 157 | ;; phase that will install `curl` on the nodes in the group. 158 | 159 | (def webserver 160 | (group-spec "webserver" 161 | :phases {:bootstrap (phase-fn (automated-admin-user)) 162 | :configure (phase-fn (java :openjdk)) 163 | :install-curl (phase-fn (package "cur"))})) 164 | 165 | ;; Now, if we only wanted to install curl, we'd do the following 166 | 167 | (converge {webserver 1} 168 | :compute my-service 169 | :phase :install-curl) 170 | 171 | ;; But if we wanted both Java and curl to be installed, then we'd do: 172 | 173 | (converge {webserver 1} 174 | :compute my-service 175 | :phase [:configure :install-curl]) 176 | 177 | ;; Alternativley, you can define a phase to be executed in a ad-hoc 178 | ;; manner just like in the following example in which instead of a 179 | ;; phase keyword (:install-curl) there is the phase definition. This 180 | ;; is great for quickly running scripts on all the nodes from the REPL 181 | ;; itself 182 | 183 | (converge {webserver 1} 184 | :compute my-service 185 | :phase [:configure (phase-fn (package "curl"))]) 186 | 187 | ;; :configure is also the default phase for lift, but unlike with 188 | ;; converge, the :configure phase is not added if not specified. The 189 | ;; following example will *only* run :install-curl, but not configure. 190 | 191 | (lift [webserver] :compute my-service :phase [:install-curl]) 192 | 193 | 194 | -------------------------------------------------------------------------------- /bin/set-version.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Script to set the pallet version across the examples 4 | # Note this is OSX specific sed usage 5 | projects="basic blank-project hudson mini-webapp nano-webapp webapp-haproxy-nodes webapp-nodes" 6 | 7 | if [ $# -lt 1 ]; then 8 | echo "Usage: set-version version-string" 9 | echo " eg. set-version 0.4.0-SNAPSHOT" 10 | exit 1 11 | fi 12 | 13 | version=$1 14 | echo Setting version to $version 15 | 16 | for project in $projects; do 17 | if [ -e $project/project.clj ]; then 18 | echo $project/project.clj 19 | sed -E -i .bak \ 20 | -e "s!defproject ([^ ]+).*!defproject \1 \"${version}\"!" \ 21 | -e "s!hoist/pallet \"[^\"]+\"!hoist/pallet \"${version}\"!" \ 22 | -e "s!/pallet-crates-all \"[^\"]+\"!/pallet-crates-all \"${version}\"!" \ 23 | $project/project.clj 24 | fi 25 | done 26 | -------------------------------------------------------------------------------- /blank-project/.gitignore: -------------------------------------------------------------------------------- 1 | pom.xml 2 | *jar 3 | lib 4 | classes -------------------------------------------------------------------------------- /blank-project/README.md: -------------------------------------------------------------------------------- 1 | # blank-project 2 | 3 | This example is a blank project that contains 4 | [pallet](http://github.com/pallet/pallet). The project can be used as 5 | starting point for your own projects. 6 | 7 | ## Creating 8 | 9 | ### lein 10 | 11 | The first thing we need is 12 | [leiningen](http://github.com/technomancy/leiningen), a build tool for 13 | clojure. 14 | 15 | bash$ curl -O http://github.com/technomancy/leiningen/raw/stable/bin/lein 16 | bash$ chmod +x lein 17 | 18 | Now we can create the project: 19 | 20 | bash$ lein new blank-project 21 | Created new project in: blank-project 22 | bash$ cd blank-project 23 | 24 | Leiningen creates a `project.clj` file, and we need to add pallet and 25 | jclouds to the `:dependencies`, and pallet-lein to the 26 | `:dev-dependencies`, so it looks like: 27 | 28 | (defproject blank-project "0.6.0" 29 | :description "blank-project for pallet" 30 | :dependencies [;; pallet lib 31 | [org.cloudhoist/pallet "0.6.6"] 32 | ;; all pallet crates 33 | [org.cloudhoist/pallet-crates-all "0.5.0"] 34 | ;; jclouds imports 35 | [org.jclouds/jclouds-all "1.2.1"] 36 | [org.jclouds/jclouds-compute "1.2.1"] 37 | [org.jclouds/jclouds-blobstore "1.2.1"] 38 | [org.jclouds.driver/jclouds-jsch "1.2.1"] 39 | [org.jclouds.driver/jclouds-slf4j "1.2.1"] 40 | ;; logging 41 | [ch.qos.logback/logback-core "1.0.0"] 42 | [ch.qos.logback/logback-classic "1.0.0"]] 43 | :dev-dependencies [[swank-clojure/swank-clojure "1.3.2"] ; swank 44 | [org.cloudhoist/pallet-lein "0.4.1"]] ; lein 45 | :repositories 46 | ;; pallet and jclouds libraries live at sonatype 47 | {"sonatype" "https://oss.sonatype.org/content/repositories/releases/"}) 48 | 49 | Note that `jclouds-all` is rather heavy. You can use the list of 50 | supported clouds and individual jclouds provider jars to slim the 51 | dependency down. 52 | 53 | lein deps 54 | lein pallet providers 55 | 56 | ## Credentials 57 | 58 | The last configuration step is to specify your cloud credentials. 59 | 60 | ### ~/.pallet/config.clj 61 | 62 | You can create `~/.pallet/config.clj` to include your cloud credentials. 63 | 64 | (defpallet 65 | :services 66 | {:aws {:provider "aws-ec2" :identity "key" :credential "secret-key"} 67 | :rs {:provider "cloudservers-us" :identity "username" :credential "key"}}) 68 | 69 | 70 | ## Testing 71 | 72 | To test the configuration, we can use the pallet-lein plugin, to list 73 | the nodes in your cloud account (the first that appears in the 74 | `defpallet` declaration above, in this example being `:aws`.) 75 | 76 | bash$ lein deps 77 | bash$ lein pallet nodes 78 | 79 | If you wanted to pick another provider from your list in `defpallet`, 80 | you can do it by passing the provider as a parameter the following way 81 | (in this case, selecting the second provider `:rs`): 82 | 83 | bash$ lein pallet -P rs nodes 84 | 85 | Alternatively we can start a REPL, to do the same. 86 | 87 | bash$ lein deps 88 | bash$ lein repl 89 | user> (use 'pallet.compute) 90 | user> (def my-service (compute-service-from-config-file)) 91 | user> (nodes my-service) 92 | 93 | The above snipped selected the default provider too, but from the REPL 94 | you can also easily select another provider from your list, for 95 | example RackSpace Cloudservers (`:rs` in the `defpallet` declaration). 96 | 97 | user> (def my-service (compute-service-from-config-file :rs)) 98 | 99 | Both of these should show any instances that you have running in your 100 | cloud account. 101 | 102 | ## Options 103 | 104 | ### Logging 105 | 106 | The project contains a `resources/logback.xml` file that configures 107 | [logback](http://logback.qos.ch/) logging into the log subdirectory. 108 | Edit this to control the placement and detail level of the logs. 109 | 110 | ### Swank 111 | 112 | If you use [SLIME](http://common-lisp.net/project/slime), you can add 113 | swank-clojure to the `project.clj`. 114 | 115 | :dev-dependencies [[swank-clojure/swank-clojure "1.3.2"]] 116 | 117 | ### jclouds provider specific jars 118 | 119 | When we added jclouds, we specified `jclouds-all` as the dependency. 120 | jclouds also has fine grained jars for each individual cloud provider 121 | that can be used instead to reduce the size of the jclouds dependency. 122 | 123 | ### Eclipse 124 | 125 | If you use eclipse, you can generate the project files using a 126 | combination of lein and mvn. When finished, you can import this as an 127 | existing project. 128 | 129 | bash$ lein pom 130 | bash$ mvn eclipse:eclipse -DdownloadSources=true -DdownloadJavadocs=true 131 | 132 | ## License 133 | 134 | Copyright (C) 2010 Hugo Duncan 135 | 136 | Distributed under the Eclipse Public License. 137 | -------------------------------------------------------------------------------- /blank-project/project.clj: -------------------------------------------------------------------------------- 1 | (defproject blank-project "0.6.0" 2 | :description "blank-project for pallet" 3 | :dependencies [;; pallet lib 4 | [org.cloudhoist/pallet "0.6.6"] 5 | ;; all pallet crates 6 | [org.cloudhoist/pallet-crates-all "0.5.0"] 7 | ;; jclouds imports 8 | [org.jclouds/jclouds-all "1.2.1"] 9 | [org.jclouds/jclouds-compute "1.2.1"] 10 | [org.jclouds/jclouds-blobstore "1.2.1"] 11 | [org.jclouds.driver/jclouds-jsch "1.2.1"] 12 | [org.jclouds.driver/jclouds-slf4j "1.2.1"] 13 | ;; logging 14 | [ch.qos.logback/logback-core "1.0.0"] 15 | [ch.qos.logback/logback-classic "1.0.0"]] 16 | :dev-dependencies [[swank-clojure/swank-clojure "1.3.2"] ; swank 17 | [org.cloudhoist/pallet-lein "0.4.1"]] ; lein 18 | :repositories 19 | ;; pallet and jclouds libraries live at sonatype 20 | {"sonatype" "https://oss.sonatype.org/content/repositories/releases/"}) 21 | -------------------------------------------------------------------------------- /blank-project/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n 5 | 6 | 7 | 8 | 9 | logs/jclouds-compute.log 10 | 11 | logs/old/jclouds-compute.%d{yyyy-MM-dd}.log 12 | 3 13 | 14 | 15 | %date %level [%thread] %logger{10} [%file:%line] %msg%n 16 | 17 | 18 | 19 | 20 | logs/jclouds-wire.log 21 | 22 | logs/old/jclouds-wire.%d{yyyy-MM-dd}.log 23 | 3 24 | 25 | 26 | %date %level [%thread] %logger{10} [%file:%line] %msg%n 27 | 28 | 29 | 30 | 31 | logs/pallet.log 32 | 33 | logs/old/pallet.%d{yyyy-MM-dd}.log 34 | 3 35 | 36 | 37 | %date %level [%thread] %logger{10} [%file:%line] %msg%n 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | -------------------------------------------------------------------------------- /blank-project/settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | cloud-credentials 6 | 7 | true 8 | 9 | 10 | cloudservers 11 | username 12 | key 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /blank-project/src/blank_project/core.clj: -------------------------------------------------------------------------------- 1 | (ns blank-project.core) 2 | -------------------------------------------------------------------------------- /blank-project/test-resources/logback-test.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n 5 | 6 | 7 | 8 | 9 | logs/jclouds-compute.log 10 | 11 | logs/old/jclouds-compute.%d{yyyy-MM-dd}.log 12 | 3 13 | 14 | 15 | %date %level [%thread] %logger{10} [%file:%line] %msg%n 16 | 17 | 18 | 19 | 20 | logs/jclouds-wire.log 21 | 22 | logs/old/jclouds-wire.%d{yyyy-MM-dd}.log 23 | 3 24 | 25 | 26 | %date %level [%thread] %logger{10} [%file:%line] %msg%n 27 | 28 | 29 | 30 | 31 | logs/pallet.log 32 | 33 | logs/old/pallet.%d{yyyy-MM-dd}.log 34 | 3 35 | 36 | 37 | %date %level [%thread] %logger{10} [%file:%line] %msg%n 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | -------------------------------------------------------------------------------- /blank-project/test/blank_project/test/core.clj: -------------------------------------------------------------------------------- 1 | (ns blank-project.test.core 2 | (:use [blank-project.core] :reload) 3 | (:use [clojure.test])) 4 | 5 | (deftest replace-me ;; FIXME: write 6 | (is false "No tests have been written.")) 7 | -------------------------------------------------------------------------------- /check-readmes.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | grep org.cloudhoist */README* 4 | grep cake-pallet */README* 5 | grep pallet-lein */README* 6 | -------------------------------------------------------------------------------- /hudson/.gitignore: -------------------------------------------------------------------------------- 1 | pom.xml 2 | *jar 3 | lib 4 | classes 5 | -------------------------------------------------------------------------------- /hudson/README.md: -------------------------------------------------------------------------------- 1 | # hudson 2 | 3 | This is an example project for launching a fully configured hudson server for a 4 | maven project, using [pallet](http://github.com/hugoduncan/pallet). 5 | 6 | ## Usage 7 | 8 | Create a clojure project with 9 | 10 | bash$ lein new hudson 11 | Created new project in: hudson 12 | bash$ cd hudson 13 | 14 | Leiningen creates a `project.clj` file, and we need to add pallet and jclouds to 15 | the :dependencies, and pallet-lein to the :dev-dependencies, so it looks like: 16 | 17 | (defproject blank-project "0.3.0" 18 | :description "blank-project for pallet" 19 | :dependencies [[org.cloudhoist/pallet "0.4.6"] 20 | [org.cloudhoist/pallet-crates-standalone "0.4.0"] 21 | [org.jclouds/jclouds-all "1.0-beta-8"] 22 | [org.jclouds/jclouds-jsch "1.0-beta-8"] 23 | [org.jclouds/jclouds-log4j "1.0-beta-8"] 24 | [org.jclouds/jclouds-enterprise "1.0-beta-8"] 25 | [log4j/log4j "1.2.14"]] 26 | :dev-dependencies [[org.cloudhoist/pallet-lein "0.4.0"]] 27 | :repositories {"sonatype" "https://oss.sonatype.org/content/repositories/releases"}) 28 | 29 | You can create `~/.pallet/config.clj` to include your cloud credentials. 30 | 31 | (defpallet 32 | :serivces 33 | {:aws {:provider "ec2" :identity "key" :credential "secret-key"} 34 | :rs {:provider "cloudservers" :identity "username" :credential "key"}}) 35 | 36 | Lein will create `src/hudson/core.clj` which we will rename to `src/hudson/ci.clj`. 37 | See [ci.clj](http://github.com/hugoduncan/pallet-examples/blob/master/hudson/src/hudson/ci.clj) 38 | 39 | 40 | To launch the server: 41 | 42 | bash$ lein deps 43 | bash$ lein pallet converge hudson.ci/hudson 1 :deploy 44 | 45 | 46 | 47 | ## License 48 | 49 | Copyright (C) 2010 Hugo Duncan 50 | 51 | Distributed under the Eclipse Public License. 52 | -------------------------------------------------------------------------------- /hudson/project.clj: -------------------------------------------------------------------------------- 1 | (defproject blank-project "0.4.0" 2 | :description "hudson example project for pallet" 3 | :dependencies [[org.cloudhoist/pallet "0.4.3"] 4 | [org.cloudhoist/pallet-crates-standalone "0.4.0"] 5 | [org.jclouds/jclouds-all "1.0-beta-8"] 6 | [org.jclouds/jclouds-jsch "1.0-beta-8"] 7 | [org.jclouds/jclouds-log4j "1.0-beta-8"] 8 | [org.jclouds/jclouds-enterprise "1.0-beta-8"] 9 | [log4j/log4j "1.2.14"]] 10 | :dev-dependencies [[swank-clojure/swank-clojure "1.2.1"] ; swank 11 | [vmfest "0.2.2"] ; virtualbox 12 | [org.cloudhoist/pallet-lein "0.4.0"] ; lein 13 | [cake-pallet "0.4.0"]] ; cake 14 | :repositories 15 | {"sonatype" "https://oss.sonatype.org/content/repositories/releases"} 16 | :tasks [cake-pallet.tasks]) 17 | -------------------------------------------------------------------------------- /hudson/resources/log4j.properties: -------------------------------------------------------------------------------- 1 | log4j.rootLogger=debug, stdout, R 2 | 3 | log4j.appender.stdout=org.apache.log4j.ConsoleAppender 4 | log4j.appender.stdout.layout=org.apache.log4j.PatternLayout 5 | log4j.appender.stdout.Threshold=info 6 | 7 | # Pattern to output the caller's file name and line number. 8 | log4j.appender.stdout.layout.ConversionPattern=%5p %d %c - %m%n 9 | 10 | log4j.appender.R=org.apache.log4j.RollingFileAppender 11 | log4j.appender.R.File=log/webapp-nodes.log 12 | log4j.appender.R.Threshold=trace 13 | 14 | log4j.appender.R.MaxFileSize=100KB 15 | # Keep one backup file 16 | # log4j.appender.R.MaxBackupIndex=1 17 | 18 | log4j.appender.R.layout=org.apache.log4j.PatternLayout 19 | log4j.appender.R.layout.ConversionPattern=%p [%t] %d %c - %m%n 20 | 21 | 22 | log4j.category.org.jclouds=trace, jclouds 23 | log4j.appender.jclouds=org.apache.log4j.RollingFileAppender 24 | log4j.appender.jclouds.File=log/jclouds.log 25 | log4j.appender.jclouds.Threshold=trace 26 | 27 | log4j.appender.jclouds.MaxFileSize=100KB 28 | # Keep one backup file 29 | # log4j.appender.R.MaxBackupIndex=1 30 | 31 | log4j.appender.jclouds.layout=org.apache.log4j.PatternLayout 32 | log4j.appender.jclouds.layout.ConversionPattern=%p [%t] %d %c - %m%n 33 | -------------------------------------------------------------------------------- /hudson/resources/log4j.properties.debug: -------------------------------------------------------------------------------- 1 | log4j.rootLogger=debug, stdout, R 2 | 3 | log4j.appender.stdout=org.apache.log4j.ConsoleAppender 4 | log4j.appender.stdout.layout=org.apache.log4j.PatternLayout 5 | 6 | # Pattern to output the caller's file name and line number. 7 | log4j.appender.stdout.layout.ConversionPattern=%5p %d %c - %m%n 8 | 9 | log4j.appender.R=org.apache.log4j.RollingFileAppender 10 | log4j.appender.R.File=log/blank_project.log 11 | log4j.appender.R.Threshold=trace 12 | 13 | log4j.appender.R.MaxFileSize=100KB 14 | # Keep one backup file 15 | # log4j.appender.R.MaxBackupIndex=1 16 | 17 | log4j.appender.R.layout=org.apache.log4j.PatternLayout 18 | log4j.appender.R.layout.ConversionPattern=%p [%t] %d %c - %m%n 19 | 20 | 21 | log4j.category.org.jclouds=trace, jclouds 22 | log4j.appender.jclouds=org.apache.log4j.RollingFileAppender 23 | log4j.appender.jclouds.File=log/jclouds.log 24 | log4j.appender.jclouds.Threshold=trace 25 | 26 | log4j.appender.jclouds.MaxFileSize=100KB 27 | # Keep one backup file 28 | # log4j.appender.R.MaxBackupIndex=1 29 | 30 | log4j.appender.jclouds.layout=org.apache.log4j.PatternLayout 31 | log4j.appender.jclouds.layout.ConversionPattern=%p [%t] %d %c - %m%n 32 | 33 | 34 | -------------------------------------------------------------------------------- /hudson/src/hudson/ci.clj: -------------------------------------------------------------------------------- 1 | (ns hudson.ci 2 | (:require 3 | [pallet.core :as core] 4 | [pallet.crate.automated-admin-user :as automated-admin-user] 5 | [pallet.crate.git :as git] 6 | [pallet.crate.hudson :as hudson] 7 | [pallet.crate.java :as java] 8 | [pallet.crate.tomcat :as tomcat] 9 | [pallet.crate.maven :as maven] 10 | [pallet.parameter :as parameter] 11 | [pallet.request-map :as request-map] 12 | [pallet.resource :as resource] 13 | [pallet.resource.directory :as directory] 14 | [pallet.resource.package :as package] 15 | [pallet.resource.remote-file :as remote-file] 16 | [pallet.resource.service :as service] 17 | [pallet.resource.user :as user] 18 | [pallet.stevedore :as stevedore]) 19 | (:use 20 | pallet.thread-expr)) 21 | 22 | (defn setup-users 23 | "Setup the hudson user" 24 | [request] 25 | (let [user (parameter/get-for-target request [:hudson :user])] 26 | (-> 27 | request 28 | (user/user user :comment "\"hudson,,,\"")))) 29 | 30 | (defn ci-config 31 | [request] 32 | (-> 33 | request 34 | (maven/package) 35 | (git/git) 36 | (java/java :sun) 37 | (tomcat/tomcat) 38 | (user/user "testuser" :create-home true :shell :bash) 39 | (service/with-restart "tomcat6" 40 | (tomcat/server-configuration (tomcat/server)) 41 | (hudson/tomcat-deploy) 42 | (hudson/config :use-security false) 43 | (setup-users) 44 | (hudson/plugin :git) 45 | (hudson/plugin :github) 46 | (hudson/plugin :instant-messaging) 47 | (hudson/plugin 48 | :ircbot 49 | :enabled true :hostname "irc.freenode.net" :port 6667 50 | :nick "jcloudsci" :nick-serv-password "jcloudsci" 51 | :hudson-login "" 52 | :hudson-password "" 53 | :default-targets [{:name "#jcloudstest"}] 54 | :command-prefix "!jcloudsci") 55 | (hudson/maven "default maven" "2.2.1") 56 | (hudson/job :maven2 "jclouds" 57 | :maven-name "default maven" 58 | :goals "-P clean deploy" 59 | :group-id "org.jclouds" 60 | :artifact-id "jclouds" 61 | :branches ["origin/master"] 62 | :github {:projectUrl "http://github.com/hugoduncan/pallet/"} 63 | :aggregator-style-build true 64 | :maven-opts "" 65 | :scm ["git://github.com/jclouds/jclouds.git"] 66 | :publishers {:ircbot 67 | {:targets [{:name "#jcloudstest"}] 68 | :strategy :all}})))) 69 | 70 | (core/defnode hudson 71 | "Hudson node" 72 | {:inbound-ports [8080 22]} 73 | :bootstrap (resource/phase 74 | (automated-admin-user/automated-admin-user)) 75 | :configure (resource/phase 76 | (ci-config)) 77 | :restart-tomcat (resource/phase 78 | (service/service "tomcat6" :action :restart)) 79 | :reload-configuration (resource/phase 80 | (hudson/reload-configuration)) 81 | :build-pallet (resource/phase (hudson/build "jclouds"))) 82 | -------------------------------------------------------------------------------- /hudson/test/hudson/test/core.clj: -------------------------------------------------------------------------------- 1 | (ns hudson.test.core 2 | (:use [hudson.core] :reload) 3 | (:use [clojure.test])) 4 | 5 | (deftest replace-me ;; FIXME: write 6 | (is false "No tests have been written.")) 7 | -------------------------------------------------------------------------------- /integration-tests/README: -------------------------------------------------------------------------------- 1 | This directory contains integration tests run against each of the pallet projects. 2 | -------------------------------------------------------------------------------- /integration-tests/cake-test.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | cake=${CAKE-~/bin/cake} 4 | compute_service=${pallet_compute_service-${PALLET_COMPUTE_SERVICE-live-test}} 5 | let fails=0 6 | 7 | fail() { 8 | r=$? 9 | let fails=(fails + 1) 10 | echo "FAIL: cake $1 failed" 11 | return $r 12 | } 13 | 14 | # test with cake 15 | echo "cake deps" 16 | ${cake} deps || fail "deps" 17 | echo "cake pallet nodes" 18 | ${cake} pallet nodes -- -P $compute_service || fail "pallet nodes" 19 | echo "cake clean" 20 | ${cake} clean || fail "clean" 21 | echo "cake kill" 22 | ${cake} kill -9 || fail "kill" 23 | 24 | exit $fails 25 | -------------------------------------------------------------------------------- /integration-tests/lein-test.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | lein=${LEIN-~/bin/lein} 4 | compute_service=${pallet_compute_service-${PALLET_COMPUTE_SERVICE-live-test}} 5 | let fails=0 6 | 7 | fail() { 8 | r=$? 9 | let fails=(fails + 1) 10 | echo "FAIL: lein $1 failed" 11 | return $r 12 | } 13 | 14 | # test with lein 15 | echo "lein deps" 16 | ${lein} deps || fail "deps" 17 | echo "lein pallet nodes" 18 | ${lein} pallet -P $compute_service nodes || fail "pallet nodes" 19 | echo "lein clean" 20 | ${lein} clean || fail "clean" 21 | 22 | exit $fails 23 | -------------------------------------------------------------------------------- /integration-tests/log4j.properties: -------------------------------------------------------------------------------- 1 | log4j.rootLogger=debug, stdout, R 2 | 3 | log4j.appender.stdout=org.apache.log4j.ConsoleAppender 4 | log4j.appender.stdout.layout=org.apache.log4j.PatternLayout 5 | log4j.appender.stdout.Threshold=info 6 | 7 | # Pattern to output the caller's file name and line number. 8 | log4j.appender.stdout.layout.ConversionPattern=%5p %d %c - %m%n 9 | 10 | log4j.appender.R=org.apache.log4j.RollingFileAppender 11 | log4j.appender.R.File=log/webapp-nodes.log 12 | log4j.appender.R.Threshold=trace 13 | 14 | log4j.appender.R.MaxFileSize=100KB 15 | # Keep one backup file 16 | # log4j.appender.R.MaxBackupIndex=1 17 | 18 | log4j.appender.R.layout=org.apache.log4j.PatternLayout 19 | log4j.appender.R.layout.ConversionPattern=%p [%t] %d %c - %m%n 20 | 21 | 22 | log4j.category.pallet.main-invoker=trace, R 23 | log4j.category.pallet.main=trace, R 24 | log4j.category.vmfest=info, R 25 | 26 | log4j.category.root=R 27 | 28 | log4j.category.org.jclouds=trace, jclouds 29 | log4j.appender.jclouds=org.apache.log4j.RollingFileAppender 30 | log4j.appender.jclouds.File=log/jclouds.log 31 | log4j.appender.jclouds.Threshold=trace 32 | 33 | log4j.appender.jclouds.MaxFileSize=100KB 34 | # Keep one backup file 35 | # log4j.appender.R.MaxBackupIndex=1 36 | 37 | log4j.appender.jclouds.layout=org.apache.log4j.PatternLayout 38 | log4j.appender.jclouds.layout.ConversionPattern=%p [%t] %d %c - %m%n 39 | -------------------------------------------------------------------------------- /mini-webapp/.gitignore: -------------------------------------------------------------------------------- 1 | pom.xml 2 | *jar 3 | lib 4 | classes -------------------------------------------------------------------------------- /mini-webapp/README.md: -------------------------------------------------------------------------------- 1 | # mini-webapp 2 | 3 | This is a very simple web app for demonstration purposes. 4 | 5 | ## Creating 6 | 7 | We create a blank clojure project. 8 | 9 | ### project.clj 10 | lein new mini-webapp 11 | 12 | We'll use the [ring](http://github.com/mmcgrana/ring) library, so we'll add that 13 | to the project.clj `:depenencies` 14 | 15 | [ring "0.2.6"] 16 | 17 | To create a war file we'll also use the leiningen-war plugin, so we add it to 18 | `:dev-depenencies` 19 | 20 | [uk.org.alienscience/leiningen-war "0.0.7"] 21 | 22 | We also need the servlet to be AOT compiled, so we'll add an :aot entry for 23 | mini-webapp.servlet. 24 | 25 | :aot [mini-webapp.Servlet] 26 | 27 | ### servlet 28 | 29 | We need three files - the servlet, the app and the web descriptor file. 30 | 31 | First the servlet. 32 | 33 | 34 | ## War file 35 | 36 | lein deps 37 | lein compile 38 | lein uberwar 39 | 40 | 41 | ## Installation 42 | 43 | See webapp-haproxy-nodes project. 44 | 45 | ## License 46 | 47 | Copyright (C) 2010 Hugo Duncan 48 | 49 | Distributed under the Eclipse Public License. 50 | -------------------------------------------------------------------------------- /mini-webapp/project.clj: -------------------------------------------------------------------------------- 1 | (defproject mini-webapp "0.4.0-SNAPSHOT" 2 | :description "mini-webapp" 3 | :aot [mini-webapp.Servlet] 4 | :dependencies [[org.clojure/clojure "1.2.0"] 5 | [org.clojure/clojure-contrib "1.2.0"] 6 | [ring "0.2.6"]] 7 | :dev-dependencies [[uk.org.alienscience/leiningen-war "0.0.7"] 8 | [swank-clojure/swank-clojure "1.2.1"]]) 9 | -------------------------------------------------------------------------------- /mini-webapp/src/mini_webapp/Servlet.clj: -------------------------------------------------------------------------------- 1 | (ns mini-webapp.Servlet 2 | "Servlet stub that delegates to our application." 3 | (:gen-class :extends javax.servlet.http.HttpServlet) 4 | (:require ring.util.servlet)) 5 | 6 | ;; Reference to our application code 7 | (defonce the-app (atom nil)) 8 | 9 | (defn start-swank 10 | "Function to start swank server. This can be run when the server is 11 | started to give a remote repl. swank-clojure will need to be added 12 | as a dependency tot he war file." 13 | [] 14 | (require 'swank.swank) 15 | (let [start-repl (var-get (ns-resolve (the-ns 'swank.swank) 'start-repl))] 16 | (start-repl))) 17 | 18 | (defn resolve-and-start-app 19 | "This ia a workaround for the recursive AOT compilation in closure. By 20 | dynamically requiring and resolving, the rest of the application is not 21 | AOT compiled." 22 | [] 23 | (require 'mini-webapp.app) 24 | (do 25 | ;; Uncomment the following line, and add swank-clojure as a dependency, 26 | ;; to run a remote repl inside your web app. 27 | ;; (start-swank) 28 | 29 | ;; there is a potential race condition here, but given that we shall 30 | ;; not be invoking this from multiple threads, I'm not worried 31 | (reset! the-app (var-get (ns-resolve (the-ns 'mini-webapp.app) 'app))))) 32 | 33 | ;; delay app, so that resolve-and-start-app is called once 34 | (def app (delay (resolve-and-start-app))) 35 | 36 | 37 | ;; set up a server that serves heynote-app 38 | (ring.util.servlet/defservice @app) 39 | -------------------------------------------------------------------------------- /mini-webapp/src/mini_webapp/app.clj: -------------------------------------------------------------------------------- 1 | (ns mini-webapp.app 2 | "mini-webapp application" 3 | (:require 4 | [ring.util.response :as response]) 5 | (:import (java.net InetAddress))) 6 | 7 | (defn app [req] 8 | (response/response (str "Hello World! from: " 9 | (.getHostAddress (InetAddress/getLocalHost))))) 10 | -------------------------------------------------------------------------------- /mini-webapp/src/mini_webapp/core.clj: -------------------------------------------------------------------------------- 1 | (ns mini-webapp.core) 2 | -------------------------------------------------------------------------------- /mini-webapp/src/mini_webapp/jetty.clj: -------------------------------------------------------------------------------- 1 | (ns mini-webapp.jetty 2 | (:require 3 | [ring.adapter.jetty :as jetty] 4 | [mini-webapp.app :as app])) 5 | 6 | 7 | ;; Keep track of the server, so we can stop it if required 8 | (defonce server (atom nil)) 9 | 10 | (defn start 11 | "Start the app, keeping track of the server" 12 | [& {:keys [port join?] :or {port 8080 join? false}}] 13 | (reset! server (jetty/run-jetty #'app/app {:port port :join? join?}))) 14 | 15 | (defn stop 16 | "Stop the app" 17 | [] 18 | (swap! server (fn [server] (.stop server) nil))) 19 | -------------------------------------------------------------------------------- /mini-webapp/src/web.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 10 | mini_webapp 11 | mini_webapp.Servlet 12 | 1 13 | 14 | 15 | 16 | mini_webapp 17 | / 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /mini-webapp/test/mini_webapp/test/core.clj: -------------------------------------------------------------------------------- 1 | (ns mini-webapp.test.core 2 | (:use [mini-webapp.core] :reload) 3 | (:use [clojure.test])) 4 | 5 | (deftest replace-me ;; FIXME: write 6 | (is false "No tests have been written.")) 7 | -------------------------------------------------------------------------------- /nano-webapp/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | com.cloudhoist 5 | nano-webapp 6 | war 7 | 0.3.0 8 | nano-webapp Maven Webapp 9 | http://maven.apache.org 10 | 11 | 12 | junit 13 | junit 14 | 3.8.1 15 | test 16 | 17 | 18 | 19 | nano-webapp 20 | 21 | 22 | -------------------------------------------------------------------------------- /nano-webapp/src/main/webapp/WEB-INF/web.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | Archetype Created Web Application 7 | 8 | -------------------------------------------------------------------------------- /nano-webapp/src/main/webapp/index.jsp: -------------------------------------------------------------------------------- 1 | 2 | <%@ page language="java" %> 3 | 4 |

Hello World! from <%= java.net.InetAddress.getLocalHost().getHostAddress() %>

5 | 6 | 7 | -------------------------------------------------------------------------------- /test-all.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # run some sanity checks 4 | 5 | projects="basic blank-project hudson webapp-haproxy-nodes webapp-nodes" 6 | 7 | log=${PALLETLOG-$(pwd)/integration.log} 8 | pallet_compute_service=${PALLET_COMPUTE_SERVICE-live-test} 9 | root=$(pwd) 10 | JVM_OPTS="-Xms256M -Xmx256M -Xmn128M -Djava.awt.headless=true -XX:MaxPermSize=128m" 11 | 12 | export root 13 | export pallet_compute_service 14 | export JVM_OPTS 15 | echo "STARTING integration tests $(date)" | tee -a $log 16 | 17 | let fails=0 18 | 19 | for project in ${projects} 20 | do 21 | echo "testing $project" 22 | # propogate log4j.properties 23 | mkdir -p $project/test-resources 24 | cp ${root}/integration-tests/log4j.properties $project/test-resources 25 | ( \ 26 | echo "global tests" 27 | cd $project 28 | for script in ${root}/integration-tests/*.sh; do 29 | before="$(date +%s)" 30 | ( /usr/bin/env bash $script ) | tee -a $log 2>&1 31 | let fails=(fails + $?) 32 | after="$(date +%s)" 33 | elapsed_seconds="$(expr $after - $before)" 34 | echo "Test ran in $elapsed_seconds secs : $script" 35 | done 36 | ) 37 | ( \ 38 | echo "local tests" 39 | if [ -e $project/integration-tests ]; then 40 | cd $project 41 | for script in integration-tests/*.sh; do 42 | ( /usr/bin/env bash $script ) | tee -a $log 2>&1 43 | let fails=(fails + $?) 44 | done 45 | fi 46 | ) 47 | done 48 | 49 | echo "FINISHED integration tests $(date)" | tee -a $log 50 | echo "FAILURES $fails" | tee -a $log 2>&1 51 | -------------------------------------------------------------------------------- /webapp-haproxy-nodes/README.md: -------------------------------------------------------------------------------- 1 | # webapp-haproxy-nodes 2 | 3 | This example is a project that contains 4 | [pallet](http://github.com/hugoduncan/pallet) node configurations and 5 | phases to deploy web applications to the cloud proxied by HAProxy. 6 | The project can be used as starting point for your own multi-node 7 | projects. 8 | 9 | ## Testing 10 | 11 | ### Setting up your environment 12 | 13 | If you haven't created the file `~/.pallet/config.clj` with your cloud 14 | provider data, do it so now by copying the file 15 | [settings.xml](tree/master/webapp-haproxy-nodes/config.clj) into your 16 | `~/.pallet` directory (create the directory if necessary). Change the 17 | provider keys to match your cloud provider and your identity and 18 | credential to sign into the cloud provider. The currently supported 19 | providers are: 20 | 21 | :openhosting-east1 22 | :serverlove-z1-man 23 | :cloudsigma-zrh 24 | :aws-ec2 25 | :eucalyptus-partnercloud-ec2 26 | :bluelock-vcloud-zone01 27 | :bluelock-vcdirector 28 | :cloudservers-us 29 | :elastichosts-lon-p 30 | :skalicloud-sdg-my 31 | :deltacloud 32 | :nova 33 | :trmk-vcloudexpress 34 | :eucalyptus 35 | :bluelock-vcloud-vcenterprise 36 | :elastichosts-lon-b 37 | :stratogen-vcloud-mycloud 38 | :cloudservers-uk 39 | :trmk-ecloud 40 | :elastichosts-sat-p 41 | :slicehost 42 | :gogrid 43 | :stub 44 | :vcloud 45 | :elasticstack 46 | :savvis-symphonyvpdc 47 | :rimuhosting 48 | :byon 49 | :node-list 50 | :virtualbox 51 | 52 | ### Building the demo webapps 53 | 54 | We will use two different web applications for this example: 55 | `nano-webapp` and `mini-webapp`. 56 | 57 | First we build the war file in the 58 | [mini-webapp](http://github.com/pallet/pallet-examples/tree/master/mini-webapp/) 59 | project directory. 60 | 61 | bash$ lein deps 62 | bash$ lein compile 63 | bash$ lein uberwar 64 | 65 | Then we build the war file in the 66 | [nano-webapp](http://github.com/pallet/pallet-examples/tree/master/nano-webapp) 67 | project directory. 68 | 69 | bash$ mvn clean package 70 | 71 | ### Testing from the command line 72 | 73 | To test the configuration, from the webapp-nodes directory, we start a 74 | webapp single instance of the 'proxied' node with nano-webapp 75 | deployed. 76 | 77 | bash$ lein deps 78 | bash$ lein pallet converge webapp-nodes.nodes/proxied 1 :deploy-nano-webapp :restart-tomcat 79 | 80 | Using the public IP address of your new node, check that the newly 81 | deployed application is running by visiting `http://:8080` 82 | 83 | To obtain the IP addresses of your nodes, run the following to get the 84 | list of running nodes and their public (and private) IP addresses: 85 | 86 | bash$ lein pallet nodes 87 | 88 | __NOTE__: When using `lein pallet`, pallet will automatically use the first 89 | provider defined in `~/.pallet/config.clj`. If you want to use another 90 | provider you should pass its name to pallet via the `-P` command line 91 | option to `lein pallet`, e.g.: 92 | 93 | bash$ lein pallet -P converge ... 94 | 95 | ### Testing from the REPL 96 | 97 | Alternatively, we can start a REPL from the webapp-nodes directory, 98 | start a webapp node, and deploy our application (NOTE: in the REPL 99 | examples, replace the key `:aws` for whatever you named the cloud 100 | provider service configuration in `~/.pallet/config.clj`) 101 | 102 | bash$ lein deps 103 | bash$ lein repl 104 | user> (require 'webapp-nodes.nodes) 105 | user> (require 'pallet.compute) 106 | user> (require 'pallet.core) 107 | user> (def service (pallet.compute/compute-service-from-config-file :aws)) 108 | user> (pallet.core/converge {webapp-nodes.nodes/proxied 1} 109 | :compute service 110 | :phase [:deploy-nano-webapp :restart-tomcat]) 111 | 112 | Using the public IP address of your new node, check that the newly 113 | deployed application is running by visiting `http://:8080`. To get the IP address of your nodes, run the following: 115 | 116 | user> (pallet.compute/nodes service) 117 | 118 | This will return the listing below. What we're looking for is the 119 | public ip address 23.20.96.254 in this case. 120 | 121 | ``` 122 | ( proxied 123 | ZONE/us-east-1d.REGION/us-east-1.PROVIDER/aws-ec2 null 124 | amzn-linux paravirtual null amazon/amzn-ami-pv-2012.03.1.x86_64-ebs 125 | RUNNING 126 | public: 23.20.96.254 private: 10.214.221.179) 127 | ``` 128 | 129 | ### Redeploying your web application 130 | 131 | Further deploys can be run with the `lift` function. 132 | 133 | bash$ lein pallet lift webapp-nodes.nodes/proxied :deploy-nano-webapp 134 | 135 | or 136 | 137 | user> (pallet.core/lift webapp-nodes.nodes/proxied 138 | :compute service 139 | :phase :deploy-nano-webapp) 140 | 141 | NOTE: The above methods should also work with mini-webapp by using the 142 | phase `:deploy-mini-webapp`. 143 | 144 | ## Tearing down a deployment 145 | 146 | If you want to destroy the node/s you just created, all you need to do 147 | is set the count to 0 on converge, e.g.: 148 | 149 | bash$ lein pallet converge webapp-nodes.nodes/proxied 0 150 | 151 | or 152 | 153 | user> (pallet.core/converge {webapp-nodes.nodes/proxied 0} :compute service) 154 | 155 | ## Multinode deployments 156 | 157 | We are going to deploy a few 'proxied' nodes and a 'haproxy' node that 158 | will be configured with HAProxy. For this job there are not many 159 | changes needed, though. 160 | 161 | ### At the command line 162 | 163 | $ lein pallet converge webapp-nodes.nodes/proxied 2 webapp-nodes.nodes/haproxy 1 :deploy-nano-webapp :restart-tomcat :restart-haproxy 164 | 165 | Visit `http:///` and confirm that the proxy is 166 | working. The IP address reported by the webapps should change between 167 | refreshes of the page, reflecting the fact that the proxy is balancing 168 | the requests. (NOTE: it might take a while for HAProxy to switch 169 | webapps) 170 | 171 | ### At the REPL 172 | 173 | user> (pallet.core/converge {webapp-nodes.nodes/proxied 2 174 | webapp-nodes.nodes/haproxy 1} 175 | :compute service 176 | :phase [:deploy-nano-webapp :restart-tomcat :restart-haproxy]) 177 | 178 | ### Finishing up 179 | 180 | To finish up, destroy all the nodes: 181 | 182 | $ lein pallet converge webapp-nodes.nodes/proxied 0 webapp-nodes.nodes/haproxy 0 183 | 184 | or 185 | 186 | user> (pallet.core/converge {webapp-nodes.nodes/proxied 0 187 | webapp-nodes.nodes/haproxy 0} 188 | :compute service) 189 | 190 | ## License 191 | 192 | Copyright (C) 2010 Hugo Duncan 193 | 194 | Distributed under the Eclipse Public License. 195 | -------------------------------------------------------------------------------- /webapp-haproxy-nodes/config.clj: -------------------------------------------------------------------------------- 1 | (defpallet 2 | :services 3 | {:aws {:proivder "aws-ec2" 4 | :identity "" 5 | :credential ""}}) 6 | -------------------------------------------------------------------------------- /webapp-haproxy-nodes/project.clj: -------------------------------------------------------------------------------- 1 | (defproject webapp-haproxy-nodes "0.6.0" 2 | :description "Webapp with haproxy load balancer" 3 | :dependencies [[org.clojure/clojure "1.2.0"] 4 | [org.clojure/clojure-contrib "1.2.0"] 5 | [org.cloudhoist/pallet "0.6.8"] 6 | [org.cloudhoist/haproxy "0.6.0"] 7 | [org.cloudhoist/java "0.5.1"] 8 | [org.cloudhoist/tomcat "0.6.0"] 9 | [org.cloudhoist/automated-admin-user "0.5.0" ] 10 | [org.jclouds/jclouds-all "1.2.1"] 11 | [org.jclouds.driver/jclouds-jsch "1.2.1"] 12 | [org.jclouds.driver/jclouds-slf4j "1.2.1"] 13 | [org.jclouds/jclouds-compute "1.2.1"] 14 | [org.jclouds/jclouds-blobstore "1.2.1"] 15 | [ch.qos.logback/logback-core "1.0.1"] 16 | [ch.qos.logback/logback-classic "1.0.1"]] 17 | :dev-dependencies [[swank-clojure/swank-clojure "1.3.2"] ; swank 18 | [org.cloudhoist/pallet-lein "0.4.2"]] ; leiningen 19 | :repositories 20 | {"sonatype" "https://oss.sonatype.org/content/repositories/releases/"}) 21 | -------------------------------------------------------------------------------- /webapp-haproxy-nodes/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | ERROR 7 | 8 | 9 | %d{HH:mm:ss.SSS} %-5level %logger{36} - %msg%n 10 | 11 | 12 | 13 | log/pallet.log 14 | 15 | %date %level %logger{10} %msg%n 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /webapp-haproxy-nodes/src/webapp_nodes/crates.clj: -------------------------------------------------------------------------------- 1 | (ns webapp-nodes.crates 2 | "Crates for configuring and deploying to a web application server" 3 | (:require 4 | [pallet.resource :as resource] 5 | [pallet.crate.automated-admin-user :as automated-admin-user] 6 | [pallet.crate.haproxy :as haproxy] 7 | [pallet.crate.java :as java] 8 | [pallet.crate.tomcat :as tomcat])) 9 | 10 | (defn bootstrap 11 | "Common Bootstrap" 12 | [request] 13 | (automated-admin-user/automated-admin-user request)) 14 | 15 | (defn tomcat 16 | "Tomcat server configuration" 17 | [request] 18 | (-> request 19 | (java/java :openjdk) 20 | (tomcat/settings {}) 21 | (tomcat/install))) 22 | 23 | (defn tomcat-deploy 24 | "Tomcat deploy as ROOT application" 25 | [request path] 26 | (-> request 27 | (tomcat/settings {}) 28 | (tomcat/deploy "ROOT" :local-file path :clear-existing true))) 29 | 30 | (defn haproxy 31 | "haproxy server with app1 on port 80." 32 | [request] 33 | (-> request 34 | (haproxy/install-package) 35 | (haproxy/configure 36 | :listen {:app1 {:server-address "0.0.0.0:80" 37 | :balance "roundrobin"}}))) 38 | 39 | (defn reverse-proxy 40 | "Declare node as being reverse proxied by haproxy on tag." 41 | [request tag app port] 42 | (-> request 43 | (haproxy/proxied-by 44 | tag app :server-port port :check true :weight 1 :maxconn 50))) 45 | -------------------------------------------------------------------------------- /webapp-haproxy-nodes/src/webapp_nodes/nodes.clj: -------------------------------------------------------------------------------- 1 | (ns webapp-nodes.nodes 2 | (:require 3 | [pallet.core :as core] 4 | [pallet.resource :as resource] 5 | [pallet.resource.service :as service] 6 | [webapp-nodes.crates :as crates])) 7 | 8 | (core/defnode haproxy 9 | "Simple haproxy" 10 | {:inbound-ports [80 22]} ;; 80 for haproxy, 22 for SSH 11 | :bootstrap (resource/phase 12 | (crates/bootstrap)) 13 | :configure (resource/phase 14 | (crates/haproxy) 15 | (service/service "haproxy" :action :restart)) 16 | :restart-haproxy (resource/phase 17 | (service/service "haproxy" :action :restart))) 18 | 19 | (core/defnode proxied 20 | "A proxied web app" 21 | {:inbound-ports [8080 22]} ;; 8080 for tomcat, 22 for SSH 22 | :bootstrap (resource/phase 23 | (crates/bootstrap)) 24 | :configure (resource/phase 25 | (crates/tomcat) 26 | (crates/reverse-proxy :haproxy :app1 8080)) 27 | :deploy-mini-webapp (resource/phase 28 | (crates/tomcat-deploy 29 | "../mini-webapp/mini-webapp-1.0.0-SNAPSHOT.war")) 30 | :deploy-nano-webapp (resource/phase 31 | (crates/tomcat-deploy 32 | "../nano-webapp/target/nano-webapp.war")) 33 | :restart-tomcat (resource/phase 34 | (service/service "tomcat6" :action :restart))) 35 | --------------------------------------------------------------------------------