A replacement for Vagrant when testing Chef before making a PR, with chef-solo.
Currently, solo supports DigitalOcean only, as it depends on the snapshot feature.
TL;DR: How to Use
-
Solo base image and base node are used to reduce the converge time on the solo nodes
-
Solo nodes are the nodes to actually run chef tests on
-
Base node is deployed with
role[base]and runningchef-soloperiodically to keep itself up-to-date -
Base image is the nightly snapshot of base node, and used to rebuild clean solo nodes
-
CI will
rsynclatest changes of staging branch to base node and idle solo nodes once tests pass -
SSH pubkeys of DevOps team members and CI machines are pre-deployed in base node
Solo API is a python web app that keeps the statuses of solo nodes, images and interacts with DigitalOcean.
Here are the endpoints of Solo API:
-
/solos, acceptsGET:Sample output:
idle 1234567 1 2015-06-26 18:27:21 nobody idle 1234568 2 2015-06-25 18:33:06 nobody idle 1234569 3 2015-06-25 18:33:08 nobodyWhich means:
status droplet solo_id updated_at user -
/solos/create, acceptsPOST:Sample params:
user eric- Mark an idle solo node as assigned, to you.
-
/solos/2, acceptsGETandDELETE:GETidle 1234568 2 2015-06-25 18:33:06 nobodyDELETEparams: user eric-
Rebuild the Droplet of that solo with the base image
-
Mark the user of that solo as
solobot -
Once the rebuild process is done, the status will be set back to
idleand user tonobody
-
There are two scripts running as cron jobs on the API server:
-
update_rebuild_status.py-
Check if the rebuild process for solo nodes are done and update the status and user accordingly.
-
Triggered once per minute.
-
-
take_base_snapshot.py-
Take nightly snapshot of the base node.
-
Triggered once per day in the early morning.
-
Solo CLI is a shell wrapper for solo-api and common tasks for solo nodes with ssh and rsync.
-
solo listGET /solos -
solo upPOST /solos/create -
solo destroyDELETE /solos/2 -
solo statusGET /solos/2 -
solo sshssh root@solo2.yourdomain.tld -
solo syncSync the solo chef dir with the local one.
-
solo provisionDo
solo syncfirst and then provision with the given Chef role (ROLE=banana solo provision). Alternatively, you can also passRUN_LIST=...tosolo provision(RUN_LIST=recipe[banana],recipe[orange] solo provision) to test multiple roles/recipes.
Solo-API accepts the requests from Solo-CLI and interacts with DigitalOcean API.
This server does not have to be a DigitalOcean Droplet.
-
Clone the repo and deploy
solo-apidirectory on your server. Here I will use/opt/soloapifor example.Note that you need to copy
local_settings.py.exampletolocal_settings.pyand changedigitalocean_tokenas your own. -
Install dependencies. Use virtualenv if you like.
cd /opt/soloapi pip install -r requirements.txt -
Fire up soloapi service with your favorite service management system. Here I will use
supervisor:cat /etc/supervisor/conf.d/soloapi.conf [program:soloapi] command = gunicorn soloapi:app -w 4 -b 127.0.0.1:5086 --log-file - --access-logfile - autorestart = true directory = /opt/soloapi environment = API_KEY=YOUR_SOLO_API_KEY user = www-dataRemeber the
API_KEYyou set here, which will be used forsolo-clilater. -
Add nginx config file for SoloAPI.
server { listen 80; listen 443 ssl; server_name soloapi.yourdomain.tld; server_tokens off; ssl_certificate /etc/certificates/yourdomain-chain.pem; ssl_certificate_key /etc/certificates/yourdomain-key.pem; include proxy_params; location / { proxy_pass http://127.0.0.1:5086; } }SSL is not mandatory, but highly recommended. If you have decide to not use SSL, change scheme to
httpinsolo-cli.sh. -
Create your solo base node, install Chef and drop your chef repo in
/root/chef. Take a snapshot of the base node with the name ofbase_image_namein yourlocal_settings.py.Add the ssh pubkeys of the potential users of your solo setup to
/root/.ssh/authorized_keys. This can be definitely improved and automated better. -
Deploy at least one solo node with the snapshot taken and initialise the database.
cd /opt/soloapi sqlite3 solo.db < schema.sql echo "INSERT INTO solos VALUES (1, 'idle', 'nobody', '2015-01-01 11:11:11', 1234567)" | sqlite3 solo.dbHere
1234567is your droplet id. -
Configure the DNS records for
solo-api.yourdomain.tldand your solo nodes, likesolo1.yourdomain.tld, etc. -
Add 2 cron jobs for
update_rebuild_status.pyandtake_base_snapshot.py. Example:* * * * * www-data /opt/soloapi/update_rebuild_status.py >/dev/null 2>&1 0 4 * * * www-data /opt/soloapi/take_base_snapshot.py >/dev/null 2>&1
-
Symlink
solo-clito your PATH:ln -sf YOUR_PATH_TO_SOLO/solo-cli.sh /usr/local/bin/solo -
Export environment variables needed by
solo-cli, in your.bashrcor.zshrc.export CHEF_REPO_DIR=.... export SOLO_API_KEY=.... -
Play with it like you did with
vagrant!solo up solo provision ROLE=alerting solo provision solo ssh solo destroy
-
Modify
ci/ci.example.shper your own CI infrastructure. -
Add an additional build step to your current CI configuration for Chef. Remeber to add the ssh pubkey of your CI user to your solo base node.