summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG3
-rw-r--r--cobbler/action_litesync.py8
-rw-r--r--cobbler/action_sync.py7
-rw-r--r--cobbler/api.py19
-rw-r--r--cobbler/collection.py46
-rw-r--r--cobbler/collection_distros.py13
-rw-r--r--cobbler/collection_profiles.py7
-rw-r--r--cobbler/collection_repos.py2
-rw-r--r--cobbler/collection_systems.py7
-rw-r--r--cobbler/commands.py7
-rw-r--r--cobbler/modules/cli_distro.py6
-rw-r--r--cobbler/modules/cli_profile.py8
-rw-r--r--cobbler/modules/cli_repo.py8
-rw-r--r--cobbler/modules/cli_system.py10
-rw-r--r--cobbler/remote.py11
-rw-r--r--cobbler/serializer.py47
-rw-r--r--tests/performance.py75
17 files changed, 229 insertions, 55 deletions
diff --git a/CHANGELOG b/CHANGELOG
index deb83da..9d676b0 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -10,6 +10,9 @@ Cobbler CHANGELOG
- Implemented fully pluggable authn/authz system
- WebUI is now mod_python based
- Greatly enhanced logging (goes to /var/log/cobbler/cobbler.log)
+- New --no-triggers and --no-sync on "adds" for performance and other reasons
+- pxe_just_once is now much faster.
+- performance testing scripts (in source checkout)
- ...
* Wed Nov 14 2007 - 0.6.4
diff --git a/cobbler/action_litesync.py b/cobbler/action_litesync.py
index 0cd4318..37d5bd5 100644
--- a/cobbler/action_litesync.py
+++ b/cobbler/action_litesync.py
@@ -92,7 +92,13 @@ class BootLiteSync:
self.sync.rmfile(os.path.join(self.settings.webdir, "profiles", name))
# delete contents on kickstarts/$name directory in webdir
self.sync.rmtree(os.path.join(self.settings.webdir, "kickstarts", name))
-
+
+ def update_system_netboot_status(self,name):
+ system = self.systems.find(name=name)
+ if system is None:
+ raise CX(_("error in system lookup for %s") % name)
+ self.sync.write_all_system_files(system,True)
+
def add_single_system(self, name):
# get the system object:
system = self.systems.find(name=name)
diff --git a/cobbler/action_sync.py b/cobbler/action_sync.py
index 44f1c6b..86bfc0d 100644
--- a/cobbler/action_sync.py
+++ b/cobbler/action_sync.py
@@ -730,7 +730,7 @@ class BootSync:
self.apply_template(infile_data, blended, outfile)
- def write_all_system_files(self,system):
+ def write_all_system_files(self,system,just_edit_pxe=False):
profile = system.get_conceptual_parent()
if profile is None:
@@ -773,7 +773,10 @@ class BootSync:
# ensure the file doesn't exist
self.rmfile(f2)
- self.write_system_file(f3,system)
+ if not just_edit_pxe:
+ # allows netboot-disable to be highly performant
+ # by not invoking the Cheetah engine
+ self.write_system_file(f3,system)
counter = counter + 1
diff --git a/cobbler/api.py b/cobbler/api.py
index 0830342..d44fc73 100644
--- a/cobbler/api.py
+++ b/cobbler/api.py
@@ -25,23 +25,32 @@ import action_validate
import sub_process
import module_loader
import logging
+import os
+import fcntl
ERROR = 100
INFO = 10
DEBUG = 5
+# notes on locking:
+# BootAPI is a singleton object
+# the XMLRPC variants allow 1 simultaneous request
+# therefore we flock on /var/lib/cobbler/settings for now
+# on a request by request basis.
+
class BootAPI:
+
__shared_state = {}
- has_loaded = False
+ __has_loaded = False
def __init__(self):
"""
Constructor
"""
- self.__dict__ = self.__shared_state
- if not BootAPI.has_loaded:
+ self.__dict__ = BootAPI.__shared_state
+ if not BootAPI.__has_loaded:
# NOTE: we do not log all API actions, because
# a simple CLI invocation may call adds and such
@@ -52,7 +61,7 @@ class BootAPI:
self.logger = self.__setup_logger("api")
self.logger_remote = self.__setup_logger("remote")
- BootAPI.has_loaded = True
+ BootAPI.__has_loaded = True
module_loader.load_modules()
self._config = config.Config(self)
self.deserialize()
@@ -202,7 +211,7 @@ class BootAPI:
cobbler_repo.set_mirror(url)
cobbler_repo.set_name(auto_name)
print "auto adding: %s (%s)" % (auto_name, url)
- self._config.repos().add(cobbler_repo,with_copy=True)
+ self._config.repos().add(cobbler_repo,save=True)
print "run cobbler reposync to apply changes"
return True
diff --git a/cobbler/collection.py b/cobbler/collection.py
index 41154ab..2fe3967 100644
--- a/cobbler/collection.py
+++ b/cobbler/collection.py
@@ -36,6 +36,7 @@ class Collection(serializable.Serializable):
self.config = config
self.clear()
self.log_func = self.config.api.log
+ self.lite_sync = None
def factory_produce(self,config,seed_data):
"""
@@ -97,7 +98,7 @@ class Collection(serializable.Serializable):
item = self.factory_produce(self.config,seed_data)
self.add(item)
- def add(self,ref,with_copy=False,with_triggers=True):
+ def add(self,ref,save=False,with_copy=False,with_triggers=True,with_sync=True,quick_pxe_update=False):
"""
Add an object to the collection, if it's valid. Returns True
if the object was added to the collection. Returns False if the
@@ -113,8 +114,18 @@ class Collection(serializable.Serializable):
So, in that case, don't run any triggers and don't deal with any actual files.
"""
+ if self.lite_sync is None:
+ self.lite_sync = action_litesync.BootLiteSync(self.config)
-
+ # migration path for old API parameter that I've renamed.
+ if with_copy and not save:
+ save = with_copy
+
+ if not save:
+ # for people that aren't quite aware of the API
+ # if not saving the object, you can't run these features
+ with_triggers = False
+ with_sync = False
if ref is None or not ref.is_valid():
raise CX(_("insufficient or invalid arguments supplied"))
@@ -122,13 +133,13 @@ class Collection(serializable.Serializable):
if ref.COLLECTION_TYPE != self.collection_type():
raise CX(_("API error: storing wrong data type in collection"))
- if not with_copy:
+ if not save:
# don't need to run triggers, so add it already ...
self.listing[ref.name.lower()] = ref
# perform filesystem operations
- if with_copy:
+ if save:
self.log_func("saving %s %s" % (self.collection_type(), ref.name))
# failure of a pre trigger will prevent the object from being added
if with_triggers:
@@ -139,18 +150,21 @@ class Collection(serializable.Serializable):
# the whole collection
self.config.serialize_item(self, ref)
- lite_sync = action_litesync.BootLiteSync(self.config)
- if isinstance(ref, item_system.System):
- lite_sync.add_single_system(ref.name)
- elif isinstance(ref, item_profile.Profile):
- lite_sync.add_single_profile(ref.name)
- elif isinstance(ref, item_distro.Distro):
- lite_sync.add_single_distro(ref.name)
- elif isinstance(ref, item_repo.Repo):
- pass
- else:
- print _("Internal error. Object type not recognized: %s") % type(ref)
-
+ if with_sync:
+ if isinstance(ref, item_system.System):
+ self.lite_sync.add_single_system(ref.name)
+ elif isinstance(ref, item_profile.Profile):
+ self.lite_sync.add_single_profile(ref.name)
+ elif isinstance(ref, item_distro.Distro):
+ self.lite_sync.add_single_distro(ref.name)
+ elif isinstance(ref, item_repo.Repo):
+ pass
+ else:
+ print _("Internal error. Object type not recognized: %s") % type(ref)
+ if not with_sync and quick_pxe_update:
+ if isinstance(ref, item_system.System):
+ self.lite_sync.update_system_netboot_status(ref.name)
+
# save the tree, so if neccessary, scripts can examine it.
if with_triggers:
self._run_triggers(ref,"/var/lib/cobbler/triggers/add/%s/post/*" % self.collection_type())
diff --git a/cobbler/collection_distros.py b/cobbler/collection_distros.py
index a01e876..a2a0464 100644
--- a/cobbler/collection_distros.py
+++ b/cobbler/collection_distros.py
@@ -31,7 +31,7 @@ class Distros(collection.Collection):
"""
return distro.Distro(config).from_datastruct(seed_data)
- def remove(self,name,with_delete=True,with_triggers=True):
+ def remove(self,name,with_delete=True,with_sync=True,with_triggers=True):
"""
Remove element named 'name' from the collection
"""
@@ -43,14 +43,17 @@ class Distros(collection.Collection):
obj = self.find(name=name)
if obj is not None:
if with_delete:
- if with_triggers: self._run_triggers(obj, "/var/lib/cobbler/triggers/delete/distro/pre/*")
- lite_sync = action_litesync.BootLiteSync(self.config)
- lite_sync.remove_single_profile(name)
+ if with_triggers:
+ self._run_triggers(obj, "/var/lib/cobbler/triggers/delete/distro/pre/*")
+ if with_sync:
+ lite_sync = action_litesync.BootLiteSync(self.config)
+ lite_sync.remove_single_profile(name)
del self.listing[name]
self.config.serialize_delete(self, obj)
if with_delete:
self.log_func("deleted distro %s" % name)
- if with_triggers: self._run_triggers(obj, "/var/lib/cobbler/triggers/delete/distro/post/*")
+ if with_triggers:
+ self._run_triggers(obj, "/var/lib/cobbler/triggers/delete/distro/post/*")
return True
raise CX(_("cannot delete object that does not exist"))
diff --git a/cobbler/collection_profiles.py b/cobbler/collection_profiles.py
index 78dd62f..dcfd701 100644
--- a/cobbler/collection_profiles.py
+++ b/cobbler/collection_profiles.py
@@ -32,7 +32,7 @@ class Profiles(collection.Collection):
def factory_produce(self,config,seed_data):
return profile.Profile(config).from_datastruct(seed_data)
- def remove(self,name,with_delete=True,with_triggers=True):
+ def remove(self,name,with_delete=True,with_sync=True,with_triggers=True):
"""
Remove element named 'name' from the collection
"""
@@ -45,8 +45,9 @@ class Profiles(collection.Collection):
if with_delete:
if with_triggers:
self._run_triggers(obj, "/var/lib/cobbler/triggers/delete/profile/pre/*")
- lite_sync = action_litesync.BootLiteSync(self.config)
- lite_sync.remove_single_profile(name)
+ if with_sync:
+ lite_sync = action_litesync.BootLiteSync(self.config)
+ lite_sync.remove_single_profile(name)
del self.listing[name]
self.config.serialize_delete(self, obj)
if with_delete:
diff --git a/cobbler/collection_repos.py b/cobbler/collection_repos.py
index 720f469..6e24983 100644
--- a/cobbler/collection_repos.py
+++ b/cobbler/collection_repos.py
@@ -36,7 +36,7 @@ class Repos(collection.Collection):
"""
return repo.Repo(config).from_datastruct(seed_data)
- def remove(self,name,with_delete=True,with_triggers=True):
+ def remove(self,name,with_delete=True,with_sync=True,with_triggers=True):
"""
Remove element named 'name' from the collection
"""
diff --git a/cobbler/collection_systems.py b/cobbler/collection_systems.py
index b89048b..bdc8228 100644
--- a/cobbler/collection_systems.py
+++ b/cobbler/collection_systems.py
@@ -33,7 +33,7 @@ class Systems(collection.Collection):
"""
return system.System(config).from_datastruct(seed_data)
- def remove(self,name,with_delete=True,with_triggers=True):
+ def remove(self,name,with_delete=True,with_sync=True,with_triggers=True):
"""
Remove element named 'name' from the collection
"""
@@ -45,8 +45,9 @@ class Systems(collection.Collection):
if with_delete:
if with_triggers:
self._run_triggers(obj, "/var/lib/cobbler/triggers/delete/system/pre/*")
- lite_sync = action_litesync.BootLiteSync(self.config)
- lite_sync.remove_single_system(name)
+ if with_sync:
+ lite_sync = action_litesync.BootLiteSync(self.config)
+ lite_sync.remove_single_system(name)
del self.listing[name]
self.config.serialize_delete(self, obj)
if with_delete:
diff --git a/cobbler/commands.py b/cobbler/commands.py
index 5760b26..4bffe1f 100644
--- a/cobbler/commands.py
+++ b/cobbler/commands.py
@@ -229,7 +229,7 @@ class CobblerFunction:
return obj
- def object_manipulator_finish(self,obj,collect_fn):
+ def object_manipulator_finish(self,obj,collect_fn, options):
"""
Boilerplate for objects that offer add/edit/delete/remove/copy functionality.
"""
@@ -241,7 +241,10 @@ class CobblerFunction:
else:
raise CX(_("--newname is required"))
- rc = collect_fn().add(obj, with_copy=True)
+ opt_sync = not options.nosync
+ opt_triggers = not options.notriggers
+
+ rc = collect_fn().add(obj, save=True, with_sync=opt_sync, with_triggers=opt_triggers)
if "rename" in self.args:
return collect_fn().remove(self.options.name, with_delete=True)
diff --git a/cobbler/modules/cli_distro.py b/cobbler/modules/cli_distro.py
index 3cfa716..d3b32f8 100644
--- a/cobbler/modules/cli_distro.py
+++ b/cobbler/modules/cli_distro.py
@@ -49,6 +49,10 @@ class DistroFunction(commands.CobblerFunction):
if self.matches_args(args,["copy","rename"]):
p.add_option("--newname", dest="newname", help="for copy/rename commands")
+ if not self.matches_args(args,["remove","report","list"]):
+ p.add_option("--no-sync", action="store_true", dest="nosync", help="suppress sync for speed")
+ if not self.matches_args(args,["report","list"]):
+ p.add_option("--no-triggers", action="store_true", dest="notriggers", help="suppress trigger execution")
def run(self):
@@ -67,7 +71,7 @@ class DistroFunction(commands.CobblerFunction):
if self.options.breed:
obj.set_breed(self.options.breed)
- return self.object_manipulator_finish(obj, self.api.distros)
+ return self.object_manipulator_finish(obj, self.api.distros, self.options)
diff --git a/cobbler/modules/cli_profile.py b/cobbler/modules/cli_profile.py
index 3026c3c..19d9ab4 100644
--- a/cobbler/modules/cli_profile.py
+++ b/cobbler/modules/cli_profile.py
@@ -49,6 +49,12 @@ class ProfileFunction(commands.CobblerFunction):
if "copy" in args or "rename" in args:
p.add_option("--newname", dest="newname")
+ if not self.matches_args(args,["remove","report", "list"]):
+ p.add_option("--no-sync", action="store_true", dest="nosync", help="suppress sync for speed")
+ if not self.matches_args(args,["report", "list"]):
+ p.add_option("--no-triggers", action="store_true", dest="notriggers", help="suppress trigger execution")
+
+
if not self.matches_args(args,["remove","report","list"]):
p.add_option("--repos", dest="repos", help="names of cobbler repos")
p.add_option("--server-override", dest="server_override", help="overrides value in settings file")
@@ -85,7 +91,7 @@ class ProfileFunction(commands.CobblerFunction):
if self.options.dhcp_tag: obj.set_dhcp_tag(self.options.dhcp_tag)
if self.options.server_override: obj.set_server(self.options.server)
- return self.object_manipulator_finish(obj, self.api.profiles)
+ return self.object_manipulator_finish(obj, self.api.profiles, self.options)
diff --git a/cobbler/modules/cli_repo.py b/cobbler/modules/cli_repo.py
index 88de685..8bfeb8e 100644
--- a/cobbler/modules/cli_repo.py
+++ b/cobbler/modules/cli_repo.py
@@ -52,6 +52,12 @@ class RepoFunction(commands.CobblerFunction):
p.add_option("--newname", dest="newname", help="used for copy/edit")
+ if not self.matches_args(args,["remove","report","list"]):
+ p.add_option("--no-sync", action="store_true", dest="nosync", help="suppress sync for speed")
+ if not self.matches_args(args,["report","list"]):
+ p.add_option("--no-triggers", action="store_true", dest="notriggers", help="suppress trigger execution")
+
+
def run(self):
obj = self.object_manipulator_start(self.api.new_repo,self.api.repos)
@@ -65,7 +71,7 @@ class RepoFunction(commands.CobblerFunction):
if self.options.priority: obj.set_priority(self.options.priority)
if self.options.mirror: obj.set_mirror(self.options.mirror)
- return self.object_manipulator_finish(obj, self.api.repos)
+ return self.object_manipulator_finish(obj, self.api.repos, self.options)
diff --git a/cobbler/modules/cli_system.py b/cobbler/modules/cli_system.py
index 4056359..3e50a64 100644
--- a/cobbler/modules/cli_system.py
+++ b/cobbler/modules/cli_system.py
@@ -56,12 +56,18 @@ class SystemFunction(commands.CobblerFunction):
p.add_option("--newname", dest="newname", help="for use with copy/edit")
if not self.matches_args(args,["remove","report","list"]):
+ p.add_option("--no-sync", action="store_true", dest="nosync", help="suppress sync for speed")
+ if not self.matches_args(args,["report","list"]):
+ p.add_option("--no-triggers", action="store_true", dest="notriggers", help="suppress trigger execution")
+
+
+ if not self.matches_args(args,["remove","report","list"]):
p.add_option("--profile", dest="profile", help="name of cobbler profile (REQUIRED)")
p.add_option("--server-override", dest="server_override", help="overrides server value in settings file")
p.add_option("--subnet", dest="subnet", help="for static IP / templating usage")
p.add_option("--virt-bridge", dest="virt_bridge", help="ex: virbr0")
p.add_option("--virt-path", dest="virt_path", help="path, partition, or volume")
- p.add_option("--virt-type", dest="virt_type", help="ex: xenpv, qemu")
+ p.add_option("--virt-type", dest="virt_type", help="ex: xenpv, qemu, xenfv")
def run(self):
@@ -90,7 +96,7 @@ class SystemFunction(commands.CobblerFunction):
if self.options.gateway: obj.set_gateway(self.options.gateway, my_interface)
if self.options.dhcp_tag: obj.set_dhcp_tag(self.options.dhcp_tag, my_interface)
- return self.object_manipulator_finish(obj, self.api.systems)
+ return self.object_manipulator_finish(obj, self.api.systems, self.options)
diff --git a/cobbler/remote.py b/cobbler/remote.py
index efa8326..d74b002 100644
--- a/cobbler/remote.py
+++ b/cobbler/remote.py
@@ -183,7 +183,8 @@ class CobblerXMLRPCInterface:
# system not found!
return False
obj.set_netboot_enabled(0)
- systems.add(obj,with_copy=True)
+ # disabling triggers and sync to make this extremely fast.
+ systems.add(obj,save=True,with_triggers=False,with_sync=False,quick_pxe_update=True)
return True
def run_post_install_triggers(self,name,token=None):
@@ -710,7 +711,7 @@ class CobblerReadWriteXMLRPCInterface(CobblerXMLRPCInterface):
self.log("save_distro",object_id=object_id,token=token)
self.check_access(token,"save_distro")
obj = self.__get_object(object_id)
- return self.api.distros().add(obj,with_copy=True)
+ return self.api.distros().add(obj,save=True)
def save_profile(self,object_id,token):
"""
@@ -719,7 +720,7 @@ class CobblerReadWriteXMLRPCInterface(CobblerXMLRPCInterface):
self.log("save_profile",token=token,object_id=object_id)
self.check_access(token,"save_profile")
obj = self.__get_object(object_id)
- return self.api.profiles().add(obj,with_copy=True)
+ return self.api.profiles().add(obj,save=True)
def save_system(self,object_id,token):
"""
@@ -728,7 +729,7 @@ class CobblerReadWriteXMLRPCInterface(CobblerXMLRPCInterface):
self.log("save_system",token=token,object_id=object_id)
self.check_access(token,"save_system")
obj = self.__get_object(object_id)
- return self.api.systems().add(obj,with_copy=True)
+ return self.api.systems().add(obj,save=True)
def save_repo(self,object_id,token=None):
"""
@@ -737,7 +738,7 @@ class CobblerReadWriteXMLRPCInterface(CobblerXMLRPCInterface):
self.log("save_repo",object_id=object_id,token=token)
self.check_access(token,"save_repo")
obj = self.__get_object(object_id)
- return self.api.repos().add(obj,with_copy=True)
+ return self.api.repos().add(obj,save=True)
def __call_method(self, obj, attribute, arg):
"""
diff --git a/cobbler/serializer.py b/cobbler/serializer.py
index 8593aad..ae9f18c 100644
--- a/cobbler/serializer.py
+++ b/cobbler/serializer.py
@@ -16,52 +16,82 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
import errno
import os
from rhpl.translate import _, N_, textdomain, utf8
+import fcntl
from cexceptions import *
import utils
import api as cobbler_api
+LOCK_ENABLED = True
+LOCK_HANDLE = None
+
+def __grab_lock():
+ if not LOCK_ENABLED:
+ return
+ if not os.path.exists("/var/lib/cobbler/lock"):
+ fd = open("/var/lib/cobbler/lock","w+")
+ fd.close()
+ LOCK_HANDLE = open("/var/lib/cobbler/lock","r")
+ fcntl.flock(LOCK_HANDLE.fileno(), fcntl.LOCK_EX)
+
+def __release_lock():
+ if not LOCK_ENABLED:
+ return
+ LOCK_HANDLE = open("/var/lib/cobbler/lock","r")
+ fcntl.flock(LOCK_HANDLE.fileno(), fcntl.LOCK_UN)
+ LOCK_HANDLE.close()
+
def serialize(obj):
"""
Save a collection to disk or other storage.
"""
+ __grab_lock()
storage_module = __get_storage_module(obj.collection_type())
storage_module.serialize(obj)
+ __release_lock()
return True
def serialize_item(collection, item):
"""
Save an item.
"""
+ __grab_lock()
storage_module = __get_storage_module(collection.collection_type())
save_fn = getattr(storage_module, "serialize_item", None)
if save_fn is None:
# print "DEBUG: WARNING: full serializer"
- return storage_module.serialize(collection)
+ rc = storage_module.serialize(collection)
else:
# print "DEBUG: partial serializer"
- return save_fn(collection,item)
+ rc = save_fn(collection,item)
+ __release_lock()
+ return rc
def serialize_delete(collection, item):
"""
Delete an object from a saved state.
"""
+ __grab_lock()
storage_module = __get_storage_module(collection.collection_type())
delete_fn = getattr(storage_module, "serialize_delete", None)
if delete_fn is None:
# print "DEBUG: full delete"
- return storage_module.serialize(collection)
+ rc = storage_module.serialize(collection)
else:
# print "DEBUG: partial delete"
- return delete_fn(collection,item)
-
+ rc = delete_fn(collection,item)
+ __release_lock()
+ return rc
def deserialize(obj,topological=False):
"""
Fill in an empty collection from disk or other storage
"""
+ __grab_lock()
storage_module = __get_storage_module(obj.collection_type())
- return storage_module.deserialize(obj,topological)
+ rc = storage_module.deserialize(obj,topological)
+ __release_lock()
+ return rc
def deserialize_raw(collection_type):
"""
@@ -69,8 +99,11 @@ def deserialize_raw(collection_type):
disk state, without going through the Cobbler object system.
Much faster, when you don't need the objects.
"""
+ __grab_lock()
storage_module = __get_storage_module(collection_type)
- return storage_module.deserialize_raw(collection_type)
+ rc = storage_module.deserialize_raw(collection_type)
+ __release_lock()
+ return rc
def __get_storage_module(collection_type):
"""
diff --git a/tests/performance.py b/tests/performance.py
new file mode 100644
index 0000000..15b9bad
--- /dev/null
+++ b/tests/performance.py
@@ -0,0 +1,75 @@
+# test script to evaluate Cobbler API performance
+#
+# Michael DeHaan <mdehaan@redhat.com>
+
+import os
+import cobbler.api as capi
+import time
+import sys
+import random
+
+N = 200
+print "sample size is %s" % N
+
+api = capi.BootAPI()
+
+# part one ... create our test systems for benchmarking purposes if
+# they do not seem to exist.
+
+if not api.profiles().find("foo"):
+ print "CREATE A PROFILE NAMED 'foo' to be able to run this test"
+ sys.exit(0)
+
+def random_mac():
+ mac = [ 0x00, 0x16, 0x3e,
+ random.randint(0x00, 0x7f),
+ random.randint(0x00, 0xff),
+ random.randint(0x00, 0xff) ]
+ return ':'.join(map(lambda x: "%02x" % x, mac))
+
+print "Deleting autotest entries from a previous run"
+time1 = time.time()
+for x in xrange(0,N):
+ try:
+ sys = api.systems().remove("autotest-%s" % x,with_delete=True)
+ except:
+ pass
+time2 = time.time()
+print "ELAPSED: %s seconds" % (time2 - time1)
+
+print "Creating test systems from scratch"
+time1 = time.time()
+for x in xrange(0,N):
+ sys = api.new_system()
+ sys.set_name("autotest-%s" % x)
+ sys.set_mac_address(random_mac())
+ sys.set_profile("foo") # assumes there is already a foo
+ # print "... adding: %s" % sys.name
+ api.systems().add(sys,save=True,with_sync=False,with_triggers=False)
+time2 = time.time()
+print "ELAPSED %s seconds" % (time2 - time1)
+
+for mode2 in [ "fast", "normal", "full" ]:
+ for mode in [ "on", "off" ]:
+
+ print "Running netboot edit benchmarks (turn %s, %s)" % (mode, mode2)
+ time1 = time.time()
+ for x in xrange(0,N):
+ sys = api.systems().find("autotest-%s" % x)
+ if mode == "off":
+ sys.set_netboot_enabled(0)
+ else:
+ sys.set_netboot_enabled(1)
+ # print "... editing: %s" % sys.name
+ if mode2 == "fast":
+ api.systems().add(sys, save=True, with_sync=False, with_triggers=False, quick_pxe_update=True)
+ if mode2 == "normal":
+ api.systems().add(sys, save=True, with_sync=False, with_triggers=False)
+ if mode2 == "full":
+ api.systems().add(sys, save=True, with_sync=True, with_triggers=True)
+
+ time2 = time.time()
+ print "ELAPSED: %s seconds" % (time2 - time1)
+
+
+