Autoinst Example Usage
Let's say we have a Apache+PHP application (let's say we're setting up OpenX webservers) that we want to configure using Autoinst. First, let's see what we have in our example environment.
Servers - we have two production webservers in the east coast and two in the west coast, we also have a QA machine.
First off, for each of our hosts, we want to create a version controlled entry in Autoinst representing properties for that host.
$ ai create -o web1.east.example.com $ ai create -o web2.east.example.com $ ai create -o web1.west.example.com $ ai create -o web2.west.example.com $ ai create -o web1.qa.example.com
Since we don't yet have any custom properties, the default host entry will suffice.
Now, we want to organize these hosts into a group. Autoinst groups are containers that can group together hosts. So we create the following groups:
$ ai create -g datacenter.east $ ai create -g datacenter.west $ ai create -g datacenter.qa
So, we've just created three groups -- one group represents our east coast servers, one represents our west coast servers, and one group represents our QA servers.
So far, so good. Except our groups don't have any hosts in them! So let's add hosts to the groups.
$ ai edit -g openx.east <?xml version="1.0" encoding="UTF-8"?> <group version="3.0.0" name="datacenter.east"> <hosts> <host name="web1.east.example.com"/> <host name="web2.east.example.com"/> </hosts> <groups/> <profiles/> <!-- properties specific to this group --> <properties/> </group>
What this just did was add 'web1.east.example.com' and 'web2.east.example.com' to the 'datacenter.east' group. Repeat this for the 'datacenter.west' and 'datacenter.qa' groups.
Profiles represent a basket of actions that should be applied to a host. An action represents a single configuration file. So a profile can be used to manage a set of configuration files that should be applied to a host.
In our example, we only need one profile, since it will represent all the configuration files on our hosts:
$ ai create -p openx.web
Linking Profiles to Groups
Now that we have a profile created, we want to link it to our new groups. What this means is that all three of the groups now have the 'openx' profile as a set of configuration files to manage.
$ ai edit -g datacenter.west <?xml version="1.0" encoding="UTF-8"?> <group version="3.0.0" name="datacenter.west"> <hosts> <host name="web1.west.example.com"/> <host name="web2.west.example.com"/> </hosts> <groups/> <profiles> <profile name="openx.web"/> </profiles> <!-- properties specific to this group --> <properties/> </group>
But what does this accomplish? Nothing yet, because all three groups have the same profile, although they do have a different set of hosts.
Actions are configuration templates. You can think of each action as being a one-to-one mapping to a single configuration file on the system.
Let's say we want to manage the file '/var/www/html/openx/var/db.conf' using autoinst. This file gets included by other static configuration files, but the file needs to be different depending on the datacenter (because each datacenter uses a different database server).
$ ai create -a openx.web.db.conf <?xml version="1.0" encoding="UTF-8"?> <action version="3.0.0" name="openx.web.db.conf" filename="/var/www/html/openx/var/db.conf" user="apache" group="apache" mode="0644" stylesheet="default.xsl" method="text" encoding="UTF-8"> <properties> <property name="openx.db.host">localhost</property> </properties> <template> [database] type=mysql host=<property name="openx.db.host"/> socket= port=3306 username=openx password=abc123 name=openx persistent= mysql4_compatibility=1 protocol=tcp </template> </action>
What does this accomplish? This creates a configuration template that manages /var/www/html/openx/var/db.conf, and it has a placeholder for the 'host' entry called 'openx.db.host'. However, the default is 'localhost', which isn't going to work for us in production. We'll fix that in a minute.
Linking Actions to Profiles
Now that we've created the action, we need to link it to our profile.
$ ai edit -p openx.web <?xml version="1.0" encoding="UTF-8"?> <profile version="3.0.0" name="openx.web"> <!-- the actions that are associated with this profile --> <actions> <action name="openx.web.db.conf"/> </actions> <properties/> </profile>
What have we accomplished so far?
- Created host entries for all our servers.
- Created a group entry for west, east, and QA.
- Created a profile called 'openx.web' which represents all of our OpenX webservers.
- Created an action template that manages the db.conf file on all our machines.
- Linked everything together - group to hosts, group to profiles, and profile to action.
Properties are one of the things that make Autoinst useful for managing configuration files. In our example, we want to set a different DB hostname depending on what datacenter our server is in. Well, it just happens that we've created an Autoinst group for each of our datacenters!
So how do we set this up? By setting group properties:
$ ai edit -g datacenter.east <?xml version="1.0" encoding="UTF-8"?> <group version="3.0.0" name="datacenter.east"> <hosts> <host name="web1.east.example.com"/> <host name="web2.east.example.com"/> </hosts> <groups/> <profiles> <profile name="openx.web"/> </profiles> <!-- properties specific to this group --> <properties> <property name="openx.db.host">db1.east.example.com</property> </properties> </group>
But we set things up differently in the 'datacenter.west' group:
$ ai edit -g datacenter.west <?xml version="1.0" encoding="UTF-8"?> <group version="3.0.0" name="datacenter.west"> <hosts> <host name="web1.west.example.com"/> <host name="web2.west.example.com"/> </hosts> <groups/> <profiles> <profile name="openx.web"/> </profiles> <!-- properties specific to this group --> <properties> <property name="openx.db.host">db1.west.example.com</property> </properties> </group>
What does this all mean? What we've done is configured group-specific properties for each group. When we finally get to the point where we generate configuration files, the template will be populated with the property for that group depending on the context of group membership. In other words, we want the servers in the 'datacenter.west' group to connect to 'db1.west.example.com', and the server in the 'datacenter.east' group to connect to 'db1.east.example.com'. Our templates and group properties let us do this by writing a single template, and then configuring group-specific properties.
Besides group-level properties, profiles and hosts can have properties. Why might you need to use this?
- If you have multiple profiles re-using the same action template, they might have different default settings.
- If you want to test out something on a single host, you might want to override a setting at the host level.
- Any other reason you might want to be flexible.
Properties are merged in the following order:
- Action properties are overridden by profile properties
- Profile properties are overridden by group properties
- Group properties are overridden by host properties
This lets you go from the least specific (template defaults) to the most specific (host-level settings)
However, the bulk of properties will (and should) be at the group level, because the group represents a container of "hosts that should be configured in the same way".
Testing the Configuration
Now that we've got our configuration framework setup, let's test it out:
$ ai run -g datacenter.west -p openx.web -a openx.web.db.conf [database] type=mysql host=db1.west.example.com socket= port=3306 username=openx password=abc123 name=openx persistent= mysql4_compatibility=1 protocol=tcp
'ai run' let's us see what the final configuration file will look like for a given group. We feed it the group name, profile name, and action name, and it returns the merged configuration file, basically what belongs on all the hosts in this group. If we specified a host (and had host-specific properties), then the configuration file for that host would be shown in the output.
$ ai run -o web1.west.example.com -g datacenter.west -p openx.web -a openx.web.db.conf [database] type=mysql host=db1.west.example.com socket= port=3306 username=openx password=abc123 name=openx persistent= mysql4_compatibility=1 protocol=tcp
Except this returns the same thing, because we don't have any host-specific properties.
Managing Hosts using 'aiupdate'
Autoinst comes with a tool called 'aiupdate' that lets you manage Autoinst-managed configurations on a host. It's completely optional for you to use. 'aiupdate' has very few prerequisites and should work with most stock installations of Python 2.x without any additional modules or extensions.
If we login to one of our hosts, let's say 'web1.east.example.com', we can run this command:
$ aiupdate Actions to install for web1.east.example.com: ============================================================================= Action Group Profile ============================================================================= openx.web.db.conf datacenter.east openx.web Confirm [y/N]: y
If we look in /var/www/html/openx/var/db.conf, we should see our configuration file, substituted with the settings specific to our host, group, and profile.
If gethostname() is not reliable on your system, you can feed options to aiupdate, e.g. 'aiupdate -H web1.east.example.com' will force the hostname to be 'web1.east.example.com'.
You can also feed 'aiupdate' options to be silent and answer 'yes' to all questions, if you wanted to run it from 'cron'.
If you use another mechanism to manage hosts (e.g. cfengine, Puppet, or slack), then you can simply run 'ai run' to generate files (as shown in the previous section), and use Autoinst as a way to version control configuration files, and then your other tool as a distribution mechanism.
Tagging the Configuration
Because everything is managed in version control, it is straightforward for us to use tags to manage our deployments. This is useful, because we can always recreate our configuration environment at any time, for any version.
Let's say we wanted to create a tag to represent a deployment tomorrow, and we'll arbitrarily call the tag 'LAUNCH-21' since this is our 21st launch.
$ ai tag LAUNCH-21 Enter username for Autoinst at localhost: admin Enter password for admin in Autoinst at localhost: OK
This creates a SVN tag of the repository named 'TEST1'.
Now we can do a configuration deployment from this tag. If someone makes a change to the trunk, it doesn't matter, since we are deploying from a tag. For example:
$ aiupdate -t LAUNCH-21
$ ai run -o web1.west.example.com -g datacenter.west -p openx.web -a openx.web.db.conf -t LAUNCH-21
This would update everything on the host from tag LAUNCH-21. Everyone else can continue working on trunk, but production will update from this tag.
Branching the Configuration
Autoinst also support branches. Let's say you wanted to work on some configuration changes on a branch, but didn't want to disrupt the rest of the team's work on the trunk.
$ ai branch MY_TEST_BRANCH
This would create a new branch. If you want to make changes to it, simply specify the branch name in the tools:
$ ai edit -g datacenter.west -b MY_TEST_BRANCH
This would edit the 'datacenter.west' group on the MY_TEST_BRANCH.
You can test out changes on the branch, for example:
$ ai run -o web1.west.example.com -g datacenter.west -p openx.web -a openx.web.db.conf -b LAUNCH-21
When you're done, you can copy and paste the changes into the trunk, or even create a tag. A merge command is not supported at this time, only copy-paste hand merges.
When you're done, you can delete the branch:
$ ai remove -b MY_TEST_BRANCH