treewide: merge phase1 and phase2 cleanup procedures
[buildbot.git] / phase2 / master.cfg
1 # -*- python -*-
2 # ex: set syntax=python:
3
4 import os
5 import re
6 import base64
7 import subprocess
8 import ConfigParser
9
10 from buildbot import locks
11
12 ini = ConfigParser.ConfigParser()
13 ini.read(os.getenv("BUILDMASTER_CONFIG", "./config.ini"))
14
15 buildbot_url = ini.get("phase2", "buildbot_url")
16
17 # This is a sample buildmaster config file. It must be installed as
18 # 'master.cfg' in your buildmaster's base directory.
19
20 # This is the dictionary that the buildmaster pays attention to. We also use
21 # a shorter alias to save typing.
22 c = BuildmasterConfig = {}
23
24 ####### BUILDSLAVES
25
26 # The 'slaves' list defines the set of recognized buildslaves. Each element is
27 # a BuildSlave object, specifying a unique slave name and password. The same
28 # slave name and password must be configured on the slave.
29 from buildbot.buildslave import BuildSlave
30
31 slave_port = 9990
32 persistent = False
33 other_builds = 0
34 tree_expire = 0
35 git_ssh = False
36 git_ssh_key = None
37
38 if ini.has_option("phase2", "port"):
39 slave_port = ini.getint("phase2", "port")
40
41 if ini.has_option("phase2", "persistent"):
42 persistent = ini.getboolean("phase2", "persistent")
43
44 if ini.has_option("phase2", "other_builds"):
45 other_builds = ini.getint("phase2", "other_builds")
46
47 if ini.has_option("phase2", "expire"):
48 tree_expire = ini.getint("phase2", "expire")
49
50 if ini.has_option("general", "git_ssh"):
51 git_ssh = ini.getboolean("general", "git_ssh")
52
53 if ini.has_option("general", "git_ssh_key"):
54 git_ssh_key = ini.get("general", "git_ssh_key")
55 else:
56 git_ssh = False
57
58 c['slaves'] = []
59 max_builds = dict()
60
61 for section in ini.sections():
62 if section.startswith("slave "):
63 if ini.has_option(section, "name") and ini.has_option(section, "password") and \
64 ini.has_option(section, "phase") and ini.getint(section, "phase") == 2:
65 name = ini.get(section, "name")
66 password = ini.get(section, "password")
67 max_builds[name] = 1
68 if ini.has_option(section, "builds"):
69 max_builds[name] = ini.getint(section, "builds")
70 c['slaves'].append(BuildSlave(name, password, max_builds = max_builds[name]))
71
72 # 'slavePortnum' defines the TCP port to listen on for connections from slaves.
73 # This must match the value configured into the buildslaves (with their
74 # --master option)
75 c['slavePortnum'] = slave_port
76
77 # coalesce builds
78 c['mergeRequests'] = True
79
80 # Reduce amount of backlog data
81 c['buildHorizon'] = 30
82 c['logHorizon'] = 20
83
84 ####### CHANGESOURCES
85
86 work_dir = os.path.abspath(ini.get("general", "workdir") or ".")
87 scripts_dir = os.path.abspath("../scripts")
88
89 rsync_bin_url = ini.get("rsync", "binary_url")
90 rsync_bin_key = ini.get("rsync", "binary_password")
91
92 rsync_src_url = None
93 rsync_src_key = None
94
95 if ini.has_option("rsync", "source_url"):
96 rsync_src_url = ini.get("rsync", "source_url")
97 rsync_src_key = ini.get("rsync", "source_password")
98
99 rsync_sdk_url = None
100 rsync_sdk_key = None
101 rsync_sdk_pat = "openwrt-sdk-*.tar.xz"
102
103 if ini.has_option("rsync", "sdk_url"):
104 rsync_sdk_url = ini.get("rsync", "sdk_url")
105
106 if ini.has_option("rsync", "sdk_password"):
107 rsync_sdk_key = ini.get("rsync", "sdk_password")
108
109 if ini.has_option("rsync", "sdk_pattern"):
110 rsync_sdk_pat = ini.get("rsync", "sdk_pattern")
111
112 repo_url = ini.get("repo", "url")
113 repo_branch = "master"
114
115 if ini.has_option("repo", "branch"):
116 repo_branch = ini.get("repo", "branch")
117
118 usign_key = None
119 usign_comment = "untrusted comment: " + repo_branch.replace("-", " ").title() + " key"
120
121 if ini.has_option("usign", "key"):
122 usign_key = ini.get("usign", "key")
123
124 if ini.has_option("usign", "comment"):
125 usign_comment = ini.get("usign", "comment")
126
127
128 # find arches
129 arches = [ ]
130 archnames = [ ]
131
132 if not os.path.isdir(work_dir+'/source.git'):
133 subprocess.call(["git", "clone", "--depth=1", "--branch="+repo_branch, repo_url, work_dir+'/source.git'])
134 else:
135 subprocess.call(["git", "pull"], cwd = work_dir+'/source.git')
136
137 findarches = subprocess.Popen([scripts_dir + '/dumpinfo.pl', 'architectures'],
138 stdout = subprocess.PIPE, cwd = work_dir+'/source.git')
139
140 while True:
141 line = findarches.stdout.readline()
142 if not line:
143 break
144 at = line.strip().split()
145 arches.append(at)
146 archnames.append(at[0])
147
148
149 # find feeds
150 feeds = []
151 feedbranches = dict()
152
153 from buildbot.changes.gitpoller import GitPoller
154 c['change_source'] = []
155
156 def parse_feed_entry(line):
157 parts = line.strip().split()
158 if parts[0] == "src-git":
159 feeds.append(parts)
160 url = parts[2].strip().split(';')
161 branch = url[1] if len(url) > 1 else 'master'
162 feedbranches[url[0]] = branch
163 c['change_source'].append(GitPoller(url[0], branch=branch, workdir='%s/%s.git' %(os.getcwd(), parts[1]), pollinterval=300))
164
165 make = subprocess.Popen(['make', '--no-print-directory', '-C', work_dir+'/source.git/target/sdk/', 'val.BASE_FEED'],
166 env = dict(os.environ, TOPDIR=work_dir+'/source.git'), stdout = subprocess.PIPE)
167
168 line = make.stdout.readline()
169 if line:
170 parse_feed_entry(line)
171
172 with open(work_dir+'/source.git/feeds.conf.default', 'r') as f:
173 for line in f:
174 parse_feed_entry(line)
175
176
177 ####### SCHEDULERS
178
179 # Configure the Schedulers, which decide how to react to incoming changes. In this
180 # case, just kick off a 'basebuild' build
181
182 def branch_change_filter(change):
183 return change.branch == feedbranches[change.repository]
184
185 from buildbot.schedulers.basic import SingleBranchScheduler
186 from buildbot.schedulers.forcesched import ForceScheduler
187 from buildbot.changes import filter
188 c['schedulers'] = []
189 c['schedulers'].append(SingleBranchScheduler(
190 name="all",
191 change_filter=filter.ChangeFilter(filter_fn=branch_change_filter),
192 treeStableTimer=60,
193 builderNames=archnames))
194
195 c['schedulers'].append(ForceScheduler(
196 name="force",
197 builderNames=archnames))
198
199 ####### BUILDERS
200
201 # The 'builders' list defines the Builders, which tell Buildbot how to perform a build:
202 # what steps, and which slaves can execute them. Note that any particular build will
203 # only take place on one slave.
204
205 from buildbot.process.factory import BuildFactory
206 from buildbot.steps.source import Git
207 from buildbot.steps.shell import ShellCommand
208 from buildbot.steps.shell import SetProperty
209 from buildbot.steps.transfer import FileUpload
210 from buildbot.steps.transfer import FileDownload
211 from buildbot.steps.transfer import StringDownload
212 from buildbot.steps.master import MasterShellCommand
213 from buildbot.process.properties import WithProperties
214
215
216 def GetDirectorySuffix(props):
217 verpat = re.compile('^([0-9]{2})\.([0-9]{2})(?:\.([0-9]+)(?:-rc([0-9]+))?|-(SNAPSHOT))$')
218 if props.hasProperty("release_version"):
219 m = verpat.match(props["release_version"])
220 if m is not None:
221 return "-%02d.%02d" %(int(m.group(1)), int(m.group(2)))
222 return ""
223
224 def GetNumJobs(props):
225 if props.hasProperty("slavename") and props.hasProperty("nproc"):
226 return ((int(props["nproc"]) / (max_builds[props["slavename"]] + other_builds)) + 1)
227 else:
228 return 1
229
230 def GetCwd(props):
231 if props.hasProperty("builddir"):
232 return props["builddir"]
233 elif props.hasProperty("workdir"):
234 return props["workdir"]
235 else:
236 return "/"
237
238 def UsignSec2Pub(seckey, comment="untrusted comment: secret key"):
239 try:
240 seckey = base64.b64decode(seckey)
241 except:
242 return None
243
244 return "{}\n{}".format(re.sub(r"\bsecret key$", "public key", comment),
245 base64.b64encode(seckey[0:2] + seckey[32:40] + seckey[72:]))
246
247
248 c['builders'] = []
249
250 dlLock = locks.SlaveLock("slave_dl")
251
252 slaveNames = [ ]
253
254 for slave in c['slaves']:
255 slaveNames.append(slave.slavename)
256
257 for arch in arches:
258 ts = arch[1].split('/')
259
260 factory = BuildFactory()
261
262 # find number of cores
263 factory.addStep(SetProperty(
264 name = "nproc",
265 property = "nproc",
266 description = "Finding number of CPUs",
267 command = ["nproc"]))
268
269 # prepare workspace
270 factory.addStep(FileDownload(
271 mastersrc = scripts_dir + '/cleanup.sh',
272 slavedest = "../cleanup.sh",
273 mode = 0755))
274
275 if not persistent:
276 factory.addStep(ShellCommand(
277 name = "cleanold",
278 description = "Cleaning previous builds",
279 command = ["./cleanup.sh", buildbot_url, WithProperties("%(slavename)s"), WithProperties("%(buildername)s"), "full"],
280 workdir = ".",
281 haltOnFailure = True,
282 timeout = 2400))
283
284 factory.addStep(ShellCommand(
285 name = "cleanup",
286 description = "Cleaning work area",
287 command = ["./cleanup.sh", buildbot_url, WithProperties("%(slavename)s"), WithProperties("%(buildername)s"), "single"],
288 workdir = ".",
289 haltOnFailure = True,
290 timeout = 2400))
291
292 # expire tree if needed
293 elif tree_expire > 0:
294 factory.addStep(FileDownload(
295 mastersrc = scripts_dir + '/expire.sh',
296 slavedest = "../expire.sh",
297 mode = 0755))
298
299 factory.addStep(ShellCommand(
300 name = "expire",
301 description = "Checking for build tree expiry",
302 command = ["./expire.sh", str(tree_expire)],
303 workdir = ".",
304 haltOnFailure = True,
305 timeout = 2400))
306
307 factory.addStep(ShellCommand(
308 name = "mksdkdir",
309 description = "Preparing SDK directory",
310 command = ["mkdir", "-p", "sdk"],
311 haltOnFailure = True))
312
313 factory.addStep(ShellCommand(
314 name = "downloadsdk",
315 description = "Downloading SDK archive",
316 command = ["rsync", "-4", "-va", "%s/%s/%s/%s" %(rsync_sdk_url, ts[0], ts[1], rsync_sdk_pat), "sdk.archive"],
317 env={'RSYNC_PASSWORD': rsync_sdk_key},
318 haltOnFailure = True,
319 logEnviron = False))
320
321 factory.addStep(ShellCommand(
322 name = "unpacksdk",
323 description = "Unpacking SDK archive",
324 command = "rm -rf sdk_update && mkdir sdk_update && tar --strip-components=1 -C sdk_update/ -vxf sdk.archive",
325 haltOnFailure = True))
326
327 factory.addStep(ShellCommand(
328 name = "updatesdk",
329 description = "Updating SDK",
330 command = "rsync --checksum -av sdk_update/ sdk/ && rm -rf sdk_update",
331 haltOnFailure = True))
332
333 factory.addStep(StringDownload(
334 name = "writeversionmk",
335 s = 'TOPDIR:=${CURDIR}\n\ninclude $(TOPDIR)/include/version.mk\n\nversion:\n\t@echo $(VERSION_NUMBER)\n',
336 slavedest = "sdk/getversion.mk",
337 mode = 0755))
338
339 factory.addStep(SetProperty(
340 name = "getversion",
341 property = "release_version",
342 description = "Finding SDK release version",
343 workdir = "build/sdk",
344 command = ["make", "-f", "getversion.mk"]))
345
346 # install build key
347 if usign_key is not None:
348 factory.addStep(StringDownload(
349 name = "dlkeybuildpub",
350 s = UsignSec2Pub(usign_key, usign_comment),
351 slavedest = "sdk/key-build.pub",
352 mode = 0600))
353
354 factory.addStep(StringDownload(
355 name = "dlkeybuild",
356 s = "# fake private key",
357 slavedest = "sdk/key-build",
358 mode = 0600))
359
360 factory.addStep(StringDownload(
361 name = "dlkeybuilducert",
362 s = "# fake certificate",
363 slavedest = "sdk/key-build.ucert",
364 mode = 0600))
365
366 factory.addStep(ShellCommand(
367 name = "mkdldir",
368 description = "Preparing download directory",
369 command = ["sh", "-c", "mkdir -p $HOME/dl && rm -rf ./sdk/dl && ln -sf $HOME/dl ./sdk/dl"],
370 haltOnFailure = True))
371
372 factory.addStep(ShellCommand(
373 name = "mkconf",
374 description = "Preparing SDK configuration",
375 workdir = "build/sdk",
376 command = ["sh", "-c", "rm -f .config && make defconfig"]))
377
378 factory.addStep(FileDownload(
379 mastersrc = scripts_dir + '/ccache.sh',
380 slavedest = 'sdk/ccache.sh',
381 mode = 0755))
382
383 factory.addStep(ShellCommand(
384 name = "prepccache",
385 description = "Preparing ccache",
386 workdir = "build/sdk",
387 command = ["./ccache.sh"],
388 haltOnFailure = True))
389
390 if git_ssh:
391 factory.addStep(StringDownload(
392 name = "dlgitclonekey",
393 s = git_ssh_key,
394 slavedest = "../git-clone.key",
395 mode = 0600))
396
397 factory.addStep(ShellCommand(
398 name = "patchfeedsconf",
399 description = "Patching feeds.conf",
400 workdir = "build/sdk",
401 command = "sed -e 's#https://#ssh://git@#g' feeds.conf.default > feeds.conf",
402 haltOnFailure = True))
403
404 factory.addStep(ShellCommand(
405 name = "updatefeeds",
406 description = "Updating feeds",
407 workdir = "build/sdk",
408 command = ["./scripts/feeds", "update", "-f"],
409 env = {'GIT_SSH_COMMAND': WithProperties("ssh -o IdentitiesOnly=yes -o IdentityFile=%(cwd)s/git-clone.key -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no", cwd=GetCwd)} if git_ssh else {},
410 haltOnFailure = True))
411
412 if git_ssh:
413 factory.addStep(ShellCommand(
414 name = "rmfeedsconf",
415 description = "Removing feeds.conf",
416 workdir = "build/sdk",
417 command=["rm", "feeds.conf"],
418 haltOnFailure = True))
419
420 factory.addStep(ShellCommand(
421 name = "installfeeds",
422 description = "Installing feeds",
423 workdir = "build/sdk",
424 command = ["./scripts/feeds", "install", "-a"],
425 haltOnFailure = True))
426
427 factory.addStep(ShellCommand(
428 name = "logclear",
429 description = "Clearing failure logs",
430 workdir = "build/sdk",
431 command = ["rm", "-rf", "logs/package/error.txt", "faillogs/"],
432 haltOnFailure = False
433 ))
434
435 factory.addStep(ShellCommand(
436 name = "compile",
437 description = "Building packages",
438 workdir = "build/sdk",
439 timeout = 3600,
440 command = ["make", WithProperties("-j%(jobs)d", jobs=GetNumJobs), "IGNORE_ERRORS=n m y", "BUILD_LOG=1", "CONFIG_AUTOREMOVE=y", "CONFIG_SIGNED_PACKAGES="],
441 env = {'CCACHE_BASEDIR': WithProperties("%(cwd)s", cwd=GetCwd)},
442 haltOnFailure = True))
443
444 factory.addStep(ShellCommand(
445 name = "mkfeedsconf",
446 description = "Generating pinned feeds.conf",
447 workdir = "build/sdk",
448 command = "./scripts/feeds list -s -f > bin/packages/%s/feeds.conf" %(arch[0])))
449
450 if ini.has_option("gpg", "key") or usign_key is not None:
451 factory.addStep(MasterShellCommand(
452 name = "signprepare",
453 description = "Preparing temporary signing directory",
454 command = ["mkdir", "-p", "%s/signing" %(work_dir)],
455 haltOnFailure = True
456 ))
457
458 factory.addStep(ShellCommand(
459 name = "signpack",
460 description = "Packing files to sign",
461 workdir = "build/sdk",
462 command = "find bin/packages/%s/ -mindepth 2 -maxdepth 2 -type f -name Packages -print0 | xargs -0 tar -czf sign.tar.gz" %(arch[0]),
463 haltOnFailure = True
464 ))
465
466 factory.addStep(FileUpload(
467 slavesrc = "sdk/sign.tar.gz",
468 masterdest = "%s/signing/%s.tar.gz" %(work_dir, arch[0]),
469 haltOnFailure = True
470 ))
471
472 factory.addStep(MasterShellCommand(
473 name = "signfiles",
474 description = "Signing files",
475 command = ["%s/signall.sh" %(scripts_dir), "%s/signing/%s.tar.gz" %(work_dir, arch[0])],
476 env = { 'CONFIG_INI': os.getenv("BUILDMASTER_CONFIG", "./config.ini") },
477 haltOnFailure = True
478 ))
479
480 factory.addStep(FileDownload(
481 mastersrc = "%s/signing/%s.tar.gz" %(work_dir, arch[0]),
482 slavedest = "sdk/sign.tar.gz",
483 haltOnFailure = True
484 ))
485
486 factory.addStep(ShellCommand(
487 name = "signunpack",
488 description = "Unpacking signed files",
489 workdir = "build/sdk",
490 command = ["tar", "-xzf", "sign.tar.gz"],
491 haltOnFailure = True
492 ))
493
494 factory.addStep(ShellCommand(
495 name = "uploadprepare",
496 description = "Preparing package directory",
497 workdir = "build/sdk",
498 command = ["rsync", "-4", "-av", "--include", "/%s/" %(arch[0]), "--exclude", "/*", "--exclude", "/%s/*" %(arch[0]), "bin/packages/", WithProperties("%s/packages%%(suffix)s/" %(rsync_bin_url), suffix=GetDirectorySuffix)],
499 env={'RSYNC_PASSWORD': rsync_bin_key},
500 haltOnFailure = True,
501 logEnviron = False
502 ))
503
504 factory.addStep(ShellCommand(
505 name = "packageupload",
506 description = "Uploading package files",
507 workdir = "build/sdk",
508 command = ["rsync", "-4", "--progress", "--delete", "--checksum", "--delay-updates", "--partial-dir=.~tmp~%s" %(arch[0]), "-avz", "bin/packages/%s/" %(arch[0]), WithProperties("%s/packages%%(suffix)s/%s/" %(rsync_bin_url, arch[0]), suffix=GetDirectorySuffix)],
509 env={'RSYNC_PASSWORD': rsync_bin_key},
510 haltOnFailure = True,
511 logEnviron = False
512 ))
513
514 factory.addStep(ShellCommand(
515 name = "logprepare",
516 description = "Preparing log directory",
517 workdir = "build/sdk",
518 command = ["rsync", "-4", "-av", "--include", "/%s/" %(arch[0]), "--exclude", "/*", "--exclude", "/%s/*" %(arch[0]), "bin/packages/", WithProperties("%s/faillogs%%(suffix)s/" %(rsync_bin_url), suffix=GetDirectorySuffix)],
519 env={'RSYNC_PASSWORD': rsync_bin_key},
520 haltOnFailure = True,
521 logEnviron = False
522 ))
523
524 factory.addStep(ShellCommand(
525 name = "logfind",
526 description = "Finding failure logs",
527 workdir = "build/sdk/logs/package/feeds",
528 command = ["sh", "-c", "sed -ne 's!^ *ERROR: package/feeds/\\([^ ]*\\) .*$!\\1!p' ../error.txt | sort -u | xargs -r find > ../../../logs.txt"],
529 haltOnFailure = False
530 ))
531
532 factory.addStep(ShellCommand(
533 name = "logcollect",
534 description = "Collecting failure logs",
535 workdir = "build/sdk",
536 command = ["rsync", "-av", "--files-from=logs.txt", "logs/package/feeds/", "faillogs/"],
537 haltOnFailure = False
538 ))
539
540 factory.addStep(ShellCommand(
541 name = "logupload",
542 description = "Uploading failure logs",
543 workdir = "build/sdk",
544 command = ["rsync", "-4", "--progress", "--delete", "--delay-updates", "--partial-dir=.~tmp~%s" %(arch[0]), "-avz", "faillogs/", WithProperties("%s/faillogs%%(suffix)s/%s/" %(rsync_bin_url, arch[0]), suffix=GetDirectorySuffix)],
545 env={'RSYNC_PASSWORD': rsync_bin_key},
546 haltOnFailure = False,
547 logEnviron = False
548 ))
549
550 if rsync_src_url is not None:
551 factory.addStep(ShellCommand(
552 name = "sourcelist",
553 description = "Finding source archives to upload",
554 workdir = "build/sdk",
555 command = "find dl/ -maxdepth 1 -type f -not -size 0 -not -name '.*' -newer ../sdk.archive -printf '%f\\n' > sourcelist",
556 haltOnFailure = True
557 ))
558
559 factory.addStep(ShellCommand(
560 name = "sourceupload",
561 description = "Uploading source archives",
562 workdir = "build/sdk",
563 command = ["rsync", "--files-from=sourcelist", "-4", "--progress", "--checksum", "--delay-updates",
564 WithProperties("--partial-dir=.~tmp~%s~%%(slavename)s" %(arch[0])), "-avz", "dl/", "%s/" %(rsync_src_url)],
565 env={'RSYNC_PASSWORD': rsync_src_key},
566 haltOnFailure = False,
567 logEnviron = False
568 ))
569
570 factory.addStep(ShellCommand(
571 name = "df",
572 description = "Reporting disk usage",
573 command=["df", "-h", "."],
574 env={'LC_ALL': 'C'},
575 haltOnFailure = False,
576 alwaysRun = True
577 ))
578
579 from buildbot.config import BuilderConfig
580
581 c['builders'].append(BuilderConfig(name=arch[0], slavenames=slaveNames, factory=factory))
582
583
584 ####### STATUS arches
585
586 # 'status' is a list of Status arches. The results of each build will be
587 # pushed to these arches. buildbot/status/*.py has a variety to choose from,
588 # including web pages, email senders, and IRC bots.
589
590 c['status'] = []
591
592 from buildbot.status import html
593 from buildbot.status.web import authz, auth
594
595 if ini.has_option("phase2", "status_bind"):
596 if ini.has_option("phase2", "status_user") and ini.has_option("phase2", "status_password"):
597 authz_cfg=authz.Authz(
598 # change any of these to True to enable; see the manual for more
599 # options
600 auth=auth.BasicAuth([(ini.get("phase2", "status_user"), ini.get("phase2", "status_password"))]),
601 gracefulShutdown = 'auth',
602 forceBuild = 'auth', # use this to test your slave once it is set up
603 forceAllBuilds = 'auth',
604 pingBuilder = False,
605 stopBuild = 'auth',
606 stopAllBuilds = 'auth',
607 cancelPendingBuild = 'auth',
608 )
609 c['status'].append(html.WebStatus(http_port=ini.get("phase2", "status_bind"), authz=authz_cfg))
610 else:
611 c['status'].append(html.WebStatus(http_port=ini.get("phase2", "status_bind")))
612
613 ####### PROJECT IDENTITY
614
615 # the 'title' string will appear at the top of this buildbot
616 # installation's html.WebStatus home page (linked to the
617 # 'titleURL') and is embedded in the title of the waterfall HTML page.
618
619 c['title'] = ini.get("general", "title")
620 c['titleURL'] = ini.get("general", "title_url")
621
622 # the 'buildbotURL' string should point to the location where the buildbot's
623 # internal web server (usually the html.WebStatus page) is visible. This
624 # typically uses the port number set in the Waterfall 'status' entry, but
625 # with an externally-visible host name which the buildbot cannot figure out
626 # without some help.
627
628 c['buildbotURL'] = buildbot_url
629
630 ####### DB URL
631
632 c['db'] = {
633 # This specifies what database buildbot uses to store its state. You can leave
634 # this at its default for all but the largest installations.
635 'db_url' : "sqlite:///state.sqlite",
636 }