This is the 10 minute intro into BundleWrap. Fasten your seatbelt.


First, open a terminal and install BundleWrap:

pip install bundlewrap

Create a repository

Now you'll need to create your repository:

mkdir my_bundlewrap_repo
cd my_bundlewrap_repo
bw repo create

You will note that some files have been created. Let's check them out:

cat nodes.py
cat groups.py

The contents should be fairly self-explanatory, but you can always check the docs on these files if you want to go deeper.

It is highly recommended to use git or a similar tool to keep track of your repository. You may want to start doing that right away.

At this point you will want to edit nodes.py and maybe change "localhost" to the hostname of a system you have passwordless (including sudo) SSH access to.

BundleWrap will honor your ~/.ssh/config, so if ssh mynode.example.com sudo id works without any password prompts in your terminal, you're good to go.

Run a command

The first thing you can do is run a command on your army of one node:

bw -a run node-1 "uptime"
The -a switch tells bw to automatically trust unknown SSH host keys (when you're connecting to a new node). By default, only known host keys will be accepted.

You should see something like this:

› node-1   20:16:26 up 34 days,  4:10,  0 users,  load average: 0.00, 0.01, 0.05
✓ node-1  completed successfully after 3.499531s

Instead of a node name ("node-1" in this case) you can also use a group name (such as "all") from your groups.py.

Create a bundle

BundleWrap stores node configuration in bundles. A bundle is a collection of items such as files, system packages or users. To create your first bundle, type:

bw repo bundle create mybundle

Now that you have created your bundle, it's important to tell BundleWrap which nodes will have this bundle. You can assign bundles to nodes using either groups.py or nodes.py, here we'll use the latter:

nodes = {
    'node-1': {
        'bundles': (
        'hostname': "mynode-1.local",

Create a file template

To manage a file, you need two things:

  1. a file item in your bundle
  2. a template for the file contents

Add this to your bundles/mybundle/items.py:

files = {
    '/etc/motd': {
        'source': "etc/motd",

Then write the file template::

mkdir bundles/mybundle/files/etc
vim bundles/mybundle/files/etc/motd

You can use this for example content:

Welcome to ${node.name}!

Note that the source attribute in items.py contains a path relative to the files directory of your bundle.

Apply configuration

Now all that's left is to run bw apply:

bw apply -i node-1

BundleWrap will ask to replace your previous MOTD:

i node-1 run started at 2016-02-13 21:25:45
? node-1
? node-1  ╭─ file:/etc/motd
? node-1  │
? node-1  │  content
? node-1  │  --- <node>
? node-1  │  +++ <bundlewrap>
? node-1  │  @@ -1 +1 @@
? node-1  │  -your old motd
? node-1  │  +Welcome to node-1!
? node-1  │
? node-1  ╰─ Fix file:/etc/motd? [Y/n]

That completes the quickstart tutorial!

Further reading

Here are some suggestions on what to do next:

Have fun! If you have any questions, feel free to drop by on IRC.