Skip to content

Instantly share code, notes, and snippets.

@tbatchelli
Created March 25, 2013 17:03
Show Gist options
  • Save tbatchelli/5238708 to your computer and use it in GitHub Desktop.
Save tbatchelli/5238708 to your computer and use it in GitHub Desktop.
(ns proto.jenkins
(:use [pallet.phase :only (phase-fn)]
[pallet.action.package :only (package)]
[pallet.crate.automated-admin-user :only (automated-admin-user)]
[pallet.action.exec-script :only (exec-checked-script)]
[proto.common :only (user)] )
(:require [pallet.core :as pc]
[pallet.crate.tomcat :as tomcat]
[pallet.crate.git :as git]
[pallet.crate.hudson :as hudson]
[pallet.crate.java :as java]
[pallet.crate.maven :as maven]
[pallet.action.user :as user]
[pallet.action.service :as service]
[pallet.action.package :as package]
[pallet.crate.etc-default :as etc-default]
[pallet.action.remote-file :as remote-file]
[pallet.crate.sudoers :as sudoers]
[pallet.action.user :as user]
[pallet.configure]
[pallet.parameter :as parameter]))
(def keystore-file "/etc/tomcat6/tc.ks")
(defn ssl-keystore
"Create a keystore with a self signed ssl certificate."
[session]
;; dname values taken from keytool manpage
(exec-checked-script
session
"Create keystore"
(when (not (file-exists? ~keystore-file))
(keytool
-genkey -alias tomcat -keyalg RSA
-dname
(quoted "CN=Mark Smith, OU=Java, O=Sun, L=Cupertino, S=California, C=US")
-keystore ~keystore-file -storepass changeit -keypass changeit))))
;; Base node for jenkins on VBox
(def jenkins-vbox-node
(pc/node-spec
:image {:image-id :ubuntu+12.04
:os-family :ubuntu}
:hardware {:min-ram 1024}))
;; Base node for jenkins on AMZ EC2
(def jenkins-ec2-east-node
(pc/node-spec
:image {:image-id "us-east-1/ami-3d4ff254"}
:hardware {:min-ram 1024
:inbound-ports [22 80 443]}))
;; the configuration for the tomcat server
(def tomcat-config
(tomcat/server
:port "8005"
:shutdown "SHUTDOWN"
(tomcat/engine "Catalina" "localhost")
(tomcat/service
(tomcat/global-resources)
(tomcat/connector
:scheme "http" :port "80"
:protocol "HTTP/1.1"
:connectionTimeout "20000"
:redirectPort "443")
(tomcat/connector
:scheme "https"
:secure "true"
:SSLEnabled "true"
:keystoreFile keystore-file
:keystorePass "changeit"
:clientAuth "false"
:sslProtocol "TLS"
:port "443" :protocol "HTTP/1.1"
:connectionTimeout "20000"))))
;; jenkins jobs
(defn setup-hudson-jobs [s]
(->
s
;; note: we're not creating jobs at this point
;;
;; (hudson/job :maven2 "test"
;; :maven-name "default maven"
;; :goals "-P clean deploy"
;; :group-id "test"
;; :artifact-id "test"
;; :github {:projectUrl "https://github.com/tbatchelli/vmfest"}
;; :maven-opts ""
;; :aggregator-style-build true
;; :scm ["git://github.com/tbatchelli/vmfest.git"])
))
(def tomcat-user "tomcat6")
(def tomcat-group "tomcat6")
(def tomcat-service "tomcat6")
(def jenkins-data-path "/var/lib/hudson")
(defn configure-hudson [s]
(->
s
(hudson/config :use-secrurity true
;; Security based on unix auth/auth
:security-realm :pam
;; :disable-signup true not needed for PAM auth
:authorization-strategy :global-matrix
:permissions
;; Unix users of the group jenkins can do
;; everything. Everyone else cannot do and see
;; anything.
[{:user "jenkins" :permissions hudson/all-permissions}
{:user "Anonymous" :permissions []}])
;; this is only for hudson-based authentication
;;
;; Passwords are SHA-256 using salt. Here is an easy way to create
;; the hash: http://www.hashgenerator.de
;;
;; Selecting SHA-256 and then entering "PASSWORD{SALT}" in the form
;; will result in a HASH. In the field :password-hash below, use
;; the resulting hash and the salt used, using the format
;; "SALT:HASH"
;;
;; (hudson/user "alexy"
;; { :full-name "user name"
;; :password-hash "abcdefg:6f4c61....1e60dd40126cb32a41a40"
;; :email "[email protected]"})
))
(defn hudson-setup [s]
(->
s
;; install oracle JDK
(java/java-settings {:vendor :oracle ;; openjdk for installing OpenJDK
:components #{:jdk}})
(java/install-java)
;; install git
(git/git)
;;
;; Prepare the tomcat install (version 6 at this point)
;;
;; using SSL, so we need a certificate. This creates a self-signed
;; cert and installs it in a keystore
(ssl-keystore)
;; configure tomcat
(tomcat/tomcat-settings
;; NOTE: we shouldn't need to override the tomcat user, but this
;; tomcat-crate needs to be fixed first.
{:group tomcat-group
:user tomcat-user
:owner tomcat-user
:server tomcat-config
:version "6"})
;; install tomcat
(tomcat/install-tomcat)
;; The tomcat user must belong to the "shadow" group in order to be
;; able to authenticate based on unix user/group via PAM
(user/user tomcat-user :action :manage :groups [tomcat-group "shadow"])
;; configure tomcat
(tomcat/server-configuration)
;; Jenkins requires the path to the directory where it will store
;; it's data to be passed as an environment variable. The default,
;; which is writing into the tomcat directory, will not work
;; because of the lack of permissions (and it is not a good practice)
(etc-default/write tomcat-service
"TOMCAT6_USER" tomcat-user
"TOMCAT6_GROUP" tomcat-group
"JAVA_OPTS" "-Djava.awt.headless=true -Xmx128m -XX:+UseConcMarkSweepGC"
"HUDSON_HOME" jenkins-data-path
;; AUTHBIND is necessary for tomcat to be able
;; to use privileged ports
"AUTHBIND" "yes")
;; NOTE: Hudson versions 1.446 onwards cannot be reinstalled. the
;; system won't start: https://issues.jenkins-ci.org/browse/JENKINS-12338
(hudson/tomcat-deploy :version "1.445")
(configure-hudson)
;; crete the jenkins obs
(setup-hudson-jobs)))
(defn create-users
([s] ;; by the fault, we look in the environment for this
(when-let [user-maps (pallet.environment/get-for s [:proto :users])]
(create-users s user-maps)))
([s user-maps]
(-> s
(pallet.thread-expr/for->
[{:keys [username password groups public-keys]} user-maps]
(user username password groups public-keys)))))
(defn add-salted-passwords [user-maps salt]
(for [user user-maps]
(assoc user :password (str (:username user) salt))))
(def users
[{:username "someone"
:groups ["jenkins"]
:public-keys ["ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEA6n/Xv0SAbH8feh7EN7jNPuDBbdGfY8QIoQT+iite8s/rz+lP9gnmjanT40B/sW+TCp/IvOrreBJRAM7Gkx7khN40PXT18fOTpEf5EfCyKmRqD8r9fvCDZ3YV3lQCwaZ3ebEJyBp7ULCso8QbEvcokL1F63rDLcUWiYFGZ5MWk2J0/Y/1es7BJfFzFgaqKtp9NABQvsAJdWnEYCtNZtTG+AzolIn1ru55gEOkZDpPLtqF/59YzCJx5YPx5w/MLrhgVOeggJbpvuTZWdpEK8srItXKJ2IIBK2kBLLWMMZ4iqHuQysbcyWp5PGI8F0R2s1DWQ7pHZtvFSQ5bWl71HDOZQ=="]}
{:username "anotherone"
:groups ["jenkins"]}])
(def jenkins-server
(pc/server-spec
:phases
{:configure (phase-fn
hudson-setup)
:create-users (phase-fn
;; ensure the running user is not left out of the
;; sudoers list
(automated-admin-user)
;; create all the users
(create-users (add-salted-passwords users "-zzz")))
:start-tomcat (phase-fn
(service/service "tomcat6" :action :start))
:stop-tomcat (phase-fn
(service/service "tomcat76" :action :stop))
:restart-tomcat (phase-fn
(service/service "tomcat6" :action :restart))}))
;;; group for running on virtual box
(def jenkins-vbox
(pc/group-spec
"jenkins"
:extends [jenkins-server]
:node-spec jenkins-vbox-node
:phases
{:bootstrap automated-admin-user}))
;;; group for running on EC2
(def jenkins-ec2-east
(pc/group-spec
"jenkins"
:extends [jenkins-server]
:node-spec jenkins-ec2-east-node
:phases
{:bootstrap automated-admin-user}))
(defn jenkins-ip [session]
(let [all-jenkins-nodes (pallet.session/nodes-in-group session "jenkins")
jenkins-node (first (filter pallet.node/running? all-jenkins-nodes ))]
(pallet.node/primary-ip jenkins-node) ))
(defn ec2-provider [identity credential]
(pallet.configure/compute-service-from-map
{:provider "aws-ec2"
:identity identity
:credential credential}))
(defn vmfest-provider []
(pallet.configure/compute-service-from-map
{:provider "vmfest"}))
(defn build-jenkins [provider spec]
(let [results (pc/converge {spec 1}
:compute provider
:phase [:create-users
:restart-tomcat])
ip (jenkins-ip results)]
(format "https://%s/hudson" ip)))
(defn destroy-jenkins [provider spec]
(pc/converge {spec 0}
:compute provider)
true)
(defn update-users [provider spec]
(pc/lift [spec]
:compute provider
:phase [:create-users])
true)
(defn restart-jenkins [provider spec]
(pc/lift [spec]
:compute provider
:phase [:restart-tomcat])
true)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment