└── basic ├── .gitignore ├── README.md ├── project.clj └── src └── demo.clj /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 | --------------------------------------------------------------------------------