4 One of Wizard's goals is to replace the previous autoinstaller infrastructure.
5 Pre-wizard autoinstalls live in :file:`/mit/scripts/deploy` and consist of a
6 tarball from upstream, possibly a scripts patch, and possibly some post-install
7 munging (such as the creation of a :file:`php.ini` file and appropriate
10 Conversion to use Wizard involves placing :term:`pristine` versions of the source
11 code (from the upstream tarballs) and appropriately patched scripts
12 versions into a Git repository, as well as writing a :mod:`wizard.app`
13 module for the application that implements application specific logic, such
14 as how to install, upgrade or backup the installation.
16 Here is a tutorial for performing a conversion, using Wordpress as
24 Probably the easiest way to do development is entirely on :term:`AFS`: all
25 of your source code should live in publically readable (i.e.
26 ``system:anyuser`` as read permissions) directories, so that if you
27 SSH into a scripts server to perform testing, you will be able
28 to invoke your tools and read your development repository. In order
29 to be able to run the test scripts in the tests directory, this
30 is preferably in :file:`web_scripts`. In that
31 case, setup is as simple as::
33 git clone /mit/scripts/git/wizard.git /mit/$USER/web_scripts/wizard
34 athrun consult fsr /mit/$USER/web_scripts/wizard system:anyuser read
35 # for any application you're going to do development on, also:
36 git clone /mit/scripts/git/autoinstalls/$APP.git /mit/$USER/web_scripts/wizard/srv/$APP
38 If you'd like to be able to develop offline, just note that you will
39 have to push your changes to AFS once you start doing testing on
40 scripts servers, but before your changes get incorporated into
41 canonical upstream. Git doesn't exactly make this easy, but you
42 can follow this recipe::
44 git clone /mit/scripts/git/wizard.git ~/wizard
50 git remote add afs /mit/$USER/wizard.git
51 git push -f afs master
52 git clone /mit/$USER/wizard.git /mit/$USER/wizard
54 And then you can perform updates from your local copy with::
60 If :file:`/mit/$USER/wizard.git` has write permissions for
61 ``system:scripts-security-upd``, this is especially useful if you were hacking
62 on a copy living on ``not-backward.mit.edu``, and now need to transfer the
63 changes back to the canonical repository (please don't give ``not-backward.mit.edu``
64 your root tickets!) You can also setup a wizard directory similar to the
65 first set of directions for on-server testing.
67 From this point on, we will assume you are doing development from an AFS directory
68 named ``$WIZARD``; note that application repositories live in ``$WIZARD/srv``.
75 This is a tutorial centered around migrating `Wordpress <http://wordpress.org/>`_
76 into our Git repository. For the sake of demonstration,
77 we shall assume that this repository hasn't been created yet.
78 The repository then doesn't exist, we should create it::
87 We also have to create a module for the application, so we
88 create ``$WIZARD/wizard/app/wordpress.py`` and fill it in with a bare bones template::
90 from wizard import app
91 class Application(app.Application):
96 Now we are ready to put some code in our repository: the first thing we will
97 add is the :term:`pristine` branch, which contains verbatim the code from upstream.
98 If we were starting a new autoinstaller, we'd pop off and use the latest version,
99 but since we're dealing with legacy we want to start our repository history
100 with the **oldest** version still extant on our servers. To find this out run::
102 wizard summary version APP
104 You'll need to be in the ``scripts-team`` list in order to access the data to
107 Try running the following command in :file:`$WIZARD/srv/wordpress`::
109 wizard prepare-pristine wordpress-2.0.2
111 .. highlight:: python
113 You should get an error complaining about :meth:`wizard.app.Application.download`
114 not being implemented yet. Let's fix that::
116 class Application(app.Application):
117 def download(self, version):
118 return "http://wordpress.org/wordpress-%s.tar.gz" % version
122 We determined this by finding `Wordpress's Release Archive <http://wordpress.org/download/release-archive/>`_
123 and inferring the naming scheme by inspecting various links. You should now
124 be able to run the prepare-pristine command successfully: when it is
125 done, you'll now have a bunch of files in your repository, and they
126 will be ready to be committed. Inspect the files and commit (note that the
127 format of the commit message is a plain Appname Version.Number)::
130 git commit -asm "Wordpress 2.0.2"
131 git tag wordpress-2.0.2
135 Sometimes, ``http://wordpress.org/wordpress-2.0.2.tar.gz`` won't
136 actually exist anymore (it didn't exist when we did it). In this case,
137 you'll probably be able to find the original tarball in
138 :file:`/mit/scripts/deploy/wordpress-2.0.2`, and you can feed it
139 manually to prepare pristine with
140 ``wizard prepare-pristine /mit/scripts/deploy/wordpress-2.0.2/wordpress-2.0.2.tar.gz``
142 Some last house-keeping bits: now that you have a commit in a repository, you
143 can also create a pristine branch::
147 From the point of view of the pristine branch pointer, history should be a
148 straight-forward progression of versions. Once you have more versions,
149 it will look something like:
151 .. digraph:: pristine_dag
155 subgraph cluster_pristine {
168 In a perfect world, the pristine version would be equivalent to the scriptsified
169 version that would actually get deployed. However, we have historically needed
170 to apply patches and add extra configuration files to get applications to
171 work correctly. Due to the way Git's merge algorithm works, the closer we are
172 able to reconstruct a version of the application that was actually used, the
173 better off we will be when we try to subsequently upgrade those applications.
175 To give you an idea of what the Git history graph will look like when we
176 are done, here is the graph from before, but augmented with the scripts versions:
178 .. digraph:: master_dag
182 subgraph cluster_pristine {
191 subgraph cluster_master {
193 as [label="1.0-scripts"]
194 bs [label="1.1-scripts"]
195 cs [label="2.0-scripts"]
207 First things first: verify that we are on the master branch::
211 Check for pre-existing patches in the old application directory,
212 :file:`/mit/scripts/deploy/wordpress-2.0.2` in the case of Wordpress,
215 patch -n0 < /mit/scripts/deploy/wordpress-2.0.2/wordpress.patch
217 Then, run the following command to setup a :file:`.scripts` directory::
221 This directory holds Wizard related files, and is also used by
222 :command:`parallel-find.pl` to determine if a directory is an autoinstall.
224 Finally, if you are running a PHP application, you'll need to setup
225 a :file:`php.ini` and symlinks to it in all subdirectories::
227 cp /mit/scripts/deploy/php.ini/wordpress php.ini
228 athrun scripts fix-php-ini
232 As of November 2009, all PHP applications load the same :file:`php.ini` file.
234 Now commit, but don't get too attached to your commit; we're going
235 to be heavily modifying it soon::
237 git commit -asm "Wordpress 2.0.2-scripts"
242 We now need to make it possible for a user to install the application.
243 Most web applications have a number of web scripts for generating a
244 configuration file, so creating the install script involves:
246 1. Determining what input values you will need from the user, such
247 as a title for the new application or database credentials; more
250 2. Determining what POST values need to be sent to what URLs.
251 Since you're converting a repository, this job is even simpler: you just
252 need to port the Perl script that was originally used into Python.
254 There's an in-depth explanation of named input values in
255 :mod:`wizard.install`. The short version is that your application
256 contains a class-wide :data:`~wizard.app.Application.install_schema`
257 attribute that encodes this information. The constructor takes
258 an arbitrary number of arguments (to be continued)
260 Some tips and tricks for writing :meth:`wizard.app.Application.install`:
262 * Some configuration file generators will get unhappy if the
263 target directory is not chmod'ed to be writable; dropping
264 in a ``os.chmod(dir, 0777)`` and then undoing the chmod
265 when you're done is a decent workaround.
267 * :func:`wizard.install.fetch` is the standard workhorse for making
268 requests to applications. It accepts three parameters; the first
269 is ``options`` (which was the third argument to ``install`` itself),
270 the second is the page to query, relative to the installation's
271 web root, and ``post`` is a dictionary of keys to values to POST.
273 * You should log any web page output using :func:`logging.debug`.
275 * If you need to manually manipulate the database afterwards, you
276 can use :func:`wizard.sql.mysql_connect` (passing it ``options``)
277 to get a `SQLAlchemy metadata object
278 <http://www.sqlalchemy.org/docs/05/sqlexpression.html>`_, which can
279 consequently be queried. For convenience, we've bound metadata
280 to the connection, you can perform implicit execution.
282 To test if your installation function works, it's probably convenient to
283 create a test script in :file:`tests`; :file:`tests/test-install-wordpress.sh`
284 in the case of Wordpress. It will look something like::
289 TESTNAME="install_wordpress"
292 wizard install "wordpress-$VERSION-scripts" "$TESTDIR" --non-interactive -- --title="My Blog"
294 ``DEFAULT_HEAD=1`` indicates that this script can perform a reasonable
295 operation without any version specified (since we haven't tagged any of our
296 commits yet, we can't use the specific version functionality; not that we'd want
297 to, though). ``TESTNAME`` is simply the name of the file with the leading
298 ``test-`` stripped and dashes converted to underscores.