/usr/lib/boinc-server/tools/appmgr is in boinc-server-maker 7.0.24+dfsg-1.
This file is owned by root:root, with mode 0o755.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 | #! /usr/bin/env python
#
# Written by Gabor Gombas <gombasg@sztaki.hu>
# Licensed under the same terms as the rest of BOINC.
"""
Manage applications and platforms from the command line.
Run "appmgr --help" to list the available commands.
Run "appmgr <command> --help" to get the description of a command.
"""
import time, os, re, string
from optparse import OptionParser
from xml.dom.minidom import parseString
import boinc_path_config
from Boinc import database, db_mid, configxml
# The list of standard platforms
standard_platforms = {
'windows_intelx86': 'Microsoft Windows (98 or later) running on an Intel x86-compatible CPU',
'windows_x86_64': 'Microsoft Windows running on an AMD x86_64 or Intel EM64T CPU',
'i686-pc-linux-gnu': 'Linux running on an Intel x86-compatible CPU',
'x86_64-pc-linux-gnu': 'Linux running on an AMD x86_64 or Intel EM64T CPU',
'powerpc-apple-darwin': 'Mac OS X 10.3 or later running on Motorola PowerPC',
'i686-apple-darwin': 'Mac OS 10.4 or later running on Intel',
'x86_64-apple-darwin': 'Intel 64-bit Mac OS 10.5 or later',
'sparc-sun-solaris2.7': 'Solaris 2.7 running on a SPARC-compatible CPU',
'sparc-sun-solaris': 'Solaris 2.8 or later running on a SPARC-compatible CPU',
'sparc64-sun-solaris': 'Solaris 2.8 or later running on a SPARC 64-bit CPU',
'powerpc64-ps3-linux-gnu': 'Sony Playstation 3 running Linux',
'anonymous': 'anonymous'}
def remove_directory(dir):
"""Remove a directory and all files inside it."""
for file in os.listdir(dir):
os.unlink(os.path.join(dir, file))
os.rmdir(dir)
def remove_app_directory(appver, config):
"""Remove files for an app version under <projectroot>/apps"""
appdir = os.path.join(config.app_dir, appver.app.name)
for path in map(lambda file: os.path.join(appdir, file), os.listdir(appdir)):
match = re.match('^[^.]+_([0-9]+)[.]([0-9]+)_([^.]+?(?:[0-9][0-9.]*[0-9])?)(?:__([^.])+)?(?:[.][a-zA-Z0-9\_\-]*)?$', os.path.basename(path))
if not match:
continue
major, minor, platform_name, plan_class = match.groups()
version_num = int(major) * 100 + int(minor)
if plan_class is None:
plan_class = ''
if platform_name != appver.platform.name:
continue
if appver.version_num != version_num:
continue
if appver.plan_class != plan_class:
continue
if os.path.isdir(path):
remove_directory(path)
else:
os.unlink(path)
# If all versions are gone, remove the parent directory as well
try:
os.rmdir(appdir)
except:
pass
def do_delete_app_version(appver):
"""Delete both the files and the database entry for an app version."""
config = configxml.default_config().config
# Remove files/directories under app_dir
appdir = os.path.join(config.app_dir, appver.app.name)
if os.path.isdir(appdir):
remove_app_directory(appver, config)
# Remove files under download_dir
# appver.xml_doc does not have a parent node, so we have to add one
xml = parseString('<xml>' + appver.xml_doc + '</xml>')
for file in xml.getElementsByTagName('file_info'):
name = ''
for node in file.getElementsByTagName('name')[0].childNodes:
if node.nodeType == node.TEXT_NODE:
name += node.data
if not name:
continue
os.unlink(os.path.join(config.download_dir, name))
tmp = str(appver)
appver.remove()
print "Removed " + tmp
def add_platform(args):
usage = """%prog add_platform <name> <user-friendly name>
Add a new platform definition to the database."""
parser = OptionParser(usage = usage)
options, extra_args = parser.parse_args(args)
if len(extra_args) != 2:
parser.error("Wrong number of arguments")
platform = database.Platform(create_time = time.time(),
name = extra_args[0],
user_friendly_name = extra_args[1],
deprecated = 0)
platform.commit()
print "Added " + str(platform)
def del_platform(args):
usage = """%prog delete_platform <name>
Deletes a platform from the database. If the --force flag is specified, it also
deletes all application versions for this platform. Otherwise, if there is an
application version available for this platform, the command will fail."""
parser = OptionParser(usage = usage)
parser.add_option("-f", "--force",
dest = "force",
action = "store_true",
default = False,
help = "remove any app versions that still exist for this platform")
options, extra_args = parser.parse_args(args)
if len(extra_args) != 1:
parser.error("Wrong number of arguments")
platforms = database.Platforms.find(name = extra_args[0])
if len(platforms) < 1:
raise SystemExit("Unknown platform name")
platform = platforms[0]
# If there are still application versions defined for this platform, then
# either bail out, or if --force was given, blow those application versions
# first
for appver in database.AppVersions.find(platform = platform):
if not options.force:
raise SystemExit("There are still application versions for this "
"platform, bailing out")
do_delete_app_version(appver)
# The id is gone after .remove(), so we have to save the stringified form
tmp = str(platform)
platform.remove()
print "Deleted " + tmp
def update_platform(args):
usage = """%prog update_platform <name> [options]
Update platform data."""
parser = OptionParser(usage = usage)
parser.add_option("--deprecated",
action = "store_const",
const = 1,
help = "mark the platform as deprecated")
parser.add_option("--no-deprecated",
dest = "deprecated",
action = "store_const",
const = 0,
help = "remove the deprecation mark")
parser.add_option("--user_friendly_name",
metavar = "DESC",
help = "set the user-friendly name of the platform")
options, extra_args = parser.parse_args(args)
if len(extra_args) != 1:
parser.error("Wrong number of arguments")
platforms = database.Platforms.find(name = extra_args[0])
if not platforms:
raise SystemExit("Unknown platform name")
platform = platforms[0]
if options.deprecated is not None:
platform.deprecated = options.deprecated
if options.user_friendly_name:
platform.user_friendly_name = options.user_friendly_name
platform.commit()
print "Updated " + str(platform)
def list_platform(args):
usage = """%prog list_platform
List all defined platforms."""
parser = OptionParser(usage = usage)
parser.add_option("--short",
action = "store_true",
help = "show the short names only")
options, extra_args = parser.parse_args(args)
if extra_args:
parser.error("Extra arguments on the command line")
# Ensure consistent ordering
database.Platforms.select_args = 'ORDER BY name'
for platform in database.Platforms.find():
if options.short:
print platform.name
else:
desc = platform.name + ": " + platform.user_friendly_name
if platform.deprecated:
desc += " (Deprecated)"
print desc
def add_standard_platforms(args):
usage = """%prog add_standard_platforms
Add all standard platform definitions to the database. If some of them
already exist they will not be modified."""
parser = OptionParser(usage = usage)
options, extra_args = parser.parse_args(args)
if extra_args:
parser.error("Extra arguments on the command line")
for name in standard_platforms.keys():
if database.Platforms.find(name = name):
continue
platform = database.Platform(create_time = time.time(),
name = name,
user_friendly_name = standard_platforms[name],
deprecated = 0)
platform.commit()
print "Added " + str(platform)
def add_app(args):
usage = """%prog add <name> <user-friendly name> [options]
Register a new application in the database."""
hr_types = { 'no': 0, 'fine': 1, 'coarse': 2}
parser = OptionParser(usage = usage)
parser.add_option("--hr",
choices = hr_types.keys(),
default = "no",
metavar = "(no|fine|coarse)",
help = "set the homogeneous redundancy type")
parser.add_option("--beta",
action = "store_const",
default = 0,
const = 1,
help = "the application is still in beta testing, and only "
"users participating in the test program will run it")
parser.add_option("--weight",
type = "float",
default = 1,
metavar = "NUM",
help = "set the weight of the application when application "
"interleaving is enabled in the feeder")
parser.add_option("--target_nresults",
type = "int",
default = 0,
metavar = "NUM",
help = "default number of replicas for adaptive replication")
options, extra_args = parser.parse_args(args)
if len(extra_args) != 2:
parser.error("Wrong number of arguments")
app = database.App(create_time = time.time(),
name = extra_args[0],
min_version = 0,
deprecated = 0,
user_friendly_name = extra_args[1],
homogeneous_redundancy = hr_types[options.hr],
weight = options.weight,
beta = options.beta,
target_nresults = options.target_nresults)
try:
app.commit()
except Exception, e:
print "Failed to add application"
return
print "Added " + str(app)
def del_app(args):
usage = """%prog delete <name> [options]
Delete application versions. This command deletes the matching database
entries and all corresponding files under <projectroot>/apps and
<projectroot>/download. If more than one of the --version, --platform and
--plan_class options are specified, they are AND'ed together. If no
version/platform/plan class options are given, all versions of the application
are deleted and the application is removed from the 'app' table as well."""
parser = OptionParser(usage = usage)
parser.add_option("--version",
type = "float",
metavar = "VER",
help = "delete versions with the given version number")
parser.add_option("--platform",
metavar = "NAME",
help = "delete versions for the given platform")
parser.add_option("--plan_class",
metavar = "NAME",
help = "delete versions for the given plan class")
options, extra_args = parser.parse_args(args)
if len(extra_args) != 1:
parser.error("Wrong number of arguments")
apps = database.Apps.find(name = extra_args[0])
if not apps:
raise SystemExit("No such application")
app = apps[0]
kwargs = { 'app': app }
if options.version:
kwargs['version_num'] = int(options.version * 100)
if options.platform:
platforms = database.Platforms.find(name = options.platform)
if not platforms:
raise SystemExit("Unknown platform name")
kwargs['platform'] = platforms[0]
if options.plan_class:
kwargs['plan_class'] = options.plan_class
for appver in database.AppVersions.find(**kwargs):
do_delete_app_version(appver)
# If the user requested to remove all versions, then remove the entry
# from the 'app' table as well
if not options.version and not options.platform and not options.plan_class:
tmp = str(app)
app.remove()
print "Removed " + tmp
def update_app(args):
usage = """%prog update <name> [options]
Update the properties of the given application."""
hr_types = { 'no': 0, 'fine': 1, 'coarse': 2}
parser = OptionParser(usage = usage)
parser.add_option("--hr",
choices = hr_types.keys(),
default = "no",
metavar = "(no|fine|coarse)",
help = "set the homogeneous redundancy type")
parser.add_option("--beta",
action = "store_const",
const = 1,
help = "the application is still in beta testing, and only "
"users participating in the test program will run it")
parser.add_option("--no-beta",
action = "store_const",
dest = "beta",
const = 0,
help = "the application is no more in beta testing")
parser.add_option("--weight",
type = "float",
metavar = "NUM",
help = "set the weight of the application when application "
"interleaving is enabled in the feeder")
parser.add_option("--target_nresults",
type = "int",
metavar = "NUM",
help = "default number of replicas for adaptive replication")
parser.add_option("--user_friendly_name",
metavar = "DESC",
help = "set the user-friendly description of the application")
parser.add_option("--min_version",
type = "float",
metavar = "VER",
help = "set the minimum app version clients allowed to use")
parser.add_option("--deprecated",
action = "store_const",
const = 1,
help = "mark the application as deprecated")
parser.add_option("--no-deprecated",
dest = "deprecated",
action = "store_const",
const = 0,
help = "remove the deprecation mark")
options, extra_args = parser.parse_args(args)
if len(extra_args) != 1:
parser.error("Wrong number of arguments")
apps = database.Apps.find(name = extra_args[0])
if not apps:
raise SystemExit("No such application")
app = apps[0]
if options.hr is not None:
app.homogeneous_redundancy = hr_types[options.hr]
if options.beta is not None:
app.beta = options.beta
if options.weight is not None:
app.weight = options.weight
if options.target_nresults is not None:
app.target_nresults = options.target_nresults
if options.user_friendly_name:
app.user_friendly_name = options.user_friendly_name
if options.min_version is not None:
app.min_version = int(options.min_version * 100)
if options.deprecated is not None:
app.deprecated = options.deprecated
app.commit()
print "Updated " + str(app)
def list_app(args):
usage = """%prog list
List all applications and application versions."""
parser = OptionParser(usage = usage)
parser.add_option("--no-versions",
action = "store_true",
default = False,
help = "do not list application versions")
options, extra_args = parser.parse_args(args)
if extra_args:
parser.error("Extra arguments on the command line")
# Ensure consistent ordering for the output
database.Apps.select_args = 'ORDER BY name'
# It would be nice to order by platform name...
database.AppVersions.select_args = 'ORDER BY version_num, platformid, plan_class'
hr_classes = {0: 'No', 1: 'Fine-grained', 2: 'Coarse'}
for app in database.Apps.find():
title = app.name + ": " + app.user_friendly_name
print title
print "-" * len(title)
props = []
if app.deprecated:
props.append("Deprecated.")
if app.beta:
props.append("Beta.")
if app.min_version:
props.append("Min. version: %.2f." % (float(app.min_version) / 100))
props.append(hr_classes[app.homogeneous_redundancy] +
' homogeneous redundancy.')
props.append("Weight %g." % app.weight)
if app.target_nresults:
props.append(str(app.target_nresults) + " adaptive replicas.")
print string.join(props, ' ')
if options.no_versions:
print
continue
print "Versions:\n"
for appver in database.AppVersions.find(app = app):
desc = "\t%5.2f" % (float(appver.version_num) / 100)
desc += " " + appver.platform.name
props = []
if appver.plan_class:
props.append("Plan: " + appver.plan_class + ".")
if appver.deprecated:
props.append("Deprecated.")
if appver.min_core_version:
props.append("Min. core version: %g." % \
(float(appver.min_core_version) / 100))
if appver.max_core_version:
props.append("Max. core version: %g." % \
(float(appver.max_core_version) / 100))
if props:
desc += " (" + string.join(props, ' ') + ')'
print desc
print
def update_appver(args):
usage = """%prog update_appver <name> [options]
Update the properties of the given application version(s). If none
of the --version, --platform, --plan_class options are specified,
then all versions for the given application are updated."""
parser = OptionParser(usage = usage)
parser.add_option("--version",
type = "float",
metavar = "VER",
help = "update just the given version number")
parser.add_option("--platform",
metavar = "NAME",
help = "update just the given platform")
parser.add_option("--plan_class",
metavar = "NAME",
help = "update just the given plan class")
parser.add_option("--min_core_version",
type = "float",
metavar = "VER",
help = "set the minimum usable core client version")
parser.add_option("--max_core_version",
type = "float",
metavar = "VER",
help = "set the maximum usable core client version")
parser.add_option("--deprecated",
action = "store_const",
const = 1,
help = "mark this version as deprecated")
parser.add_option("--no-deprecated",
dest = "deprecated",
action = "store_const",
const = 0,
help = "remove the deprecation mark")
options, extra_args = parser.parse_args(args)
if len(extra_args) != 1:
parser.error("Wrong number of arguments")
apps = database.Apps.find(name = extra_args[0])
if not apps:
raise SystemExit("No such application")
app = apps[0]
kwargs = { 'app': app }
if options.version:
kwargs['version_num'] = int(options.version * 100)
if options.platform:
platforms = database.Platforms.find(name = options.platform)
if not platforms:
raise SystemExit("Unknown platform name")
kwargs['platform'] = platforms[0]
if options.plan_class:
kwargs['plan_class'] = options.plan_class
for appver in database.AppVersions.find(**kwargs):
if options.deprecated is not None:
appver.deprecated = options.deprecated
if options.min_core_version is not None:
appver.min_core_version = int(options.min_core_version * 100)
if options.max_core_version is not None:
appver.max_core_version = int(options.max_core_version * 100)
appver.commit()
print "Updated " + str(appver)
command_table = {
'add': add_app,
'delete': del_app,
'update': update_app,
'list': list_app,
'update_appver': update_appver,
'add_platform': add_platform,
'delete_platform': del_platform,
'update_platform': update_platform,
'list_platform': list_platform,
'add_standard_platforms': add_standard_platforms}
usage = """%%prog [global options] <command> [command arguments]
Available commands:
%s
Use "%%prog <command> --help" to get a description of the command.""" % \
string.join(map(lambda x: "\t" + x, sorted(command_table.keys())), "\n")
parser = OptionParser(usage=usage)
parser.disable_interspersed_args()
global_options, args = parser.parse_args()
if not args:
parser.error("Command is not provided")
if not args[0] in command_table:
parser.error("Unknown command " + args[0])
database.connect()
command_table[args[0]](args[1:])
|