diff options
Diffstat (limited to 'cobbler/remote.py')
-rw-r--r-- | cobbler/remote.py | 545 |
1 files changed, 404 insertions, 141 deletions
diff --git a/cobbler/remote.py b/cobbler/remote.py index 8154dc58..10e9cc20 100644 --- a/cobbler/remote.py +++ b/cobbler/remote.py @@ -27,10 +27,13 @@ import sys import socket import time import os +import base64 import SimpleXMLRPCServer import xmlrpclib import random +import stat import base64 +import fcntl import string import traceback import glob @@ -45,7 +48,7 @@ import item_system import item_repo import item_image from utils import * -from utils import _ # * does not import _ +from utils import _ # FIXME: make configurable? TOKEN_TIMEOUT = 60*60 # 60 minutes @@ -53,25 +56,86 @@ OBJECT_TIMEOUT = 60*60 # 60 minutes TOKEN_CACHE = {} OBJECT_CACHE = {} +class DataCache: + + def __init__(self, api): + """ + Constructor + """ + self.api = api + + def update(self,collection_type, name): + data = self.api.deserialize_item_raw(collection_type, name) + + if data is None: + return False + + if collection_type == "distro": + obj = item_distro.Distro(self.api._config) + obj.from_datastruct(data) + self.api.add_distro(obj, False, False) + + if collection_type == "profile": + subprofile = False + if data.has_key("parent") and data["parent"] != "": + subprofile = True + obj = item_profile.Profile(self.api._config, is_subobject = subprofile) + obj.from_datastruct(data) + self.api.add_profile(obj, False, False) + + if collection_type == "system": + obj = item_system.System(self.api._config) + obj.from_datastruct(data) + self.api.add_system(obj, False, False, False) + + if collection_type == "repo": + obj = item_repo.Repo(self.api._config) + obj.from_datastruct(data) + self.api.add_repo(obj, False, False) + + if collection_type == "image": + obj = item_image.Image(self.api._config) + obj.from_datastruct(data) + self.api.add_image(obj, False, False) + + + def remove(self,collection_type, name): + # for security reasons, only remove if actually gone + data = self.api.deserialize_item_raw(collection_type, name) + if data is None: + if collection_type == "distro": + self.api.remove_distro(name, delete=False, recursive=True, with_triggers=False) + if collection_type == "profile": + self.api.remove_profile(name, delete=False, recursive=True, with_triggers=False) + if collection_type == "system": + self.api.remove_system(name, delete=False, recursive=True, with_triggers=False) + if collection_type == "repo": + self.api.remove_repo(name, delete=False, recursive=True, with_triggers=False) + if collection_type == "image": + self.api.remove_image(name, delete=False, recursive=True, with_triggers=False) + # ********************************************************************* # ********************************************************************* class CobblerXMLRPCInterface: """ - This is the interface used for all public XMLRPC methods, for instance, - as used by koan. The read-write interface which inherits from this adds - more methods, though that interface can be disabled. + This is the interface used for all XMLRPC methods, for instance, + as used by koan or CobblerWeb note: public methods take an optional parameter token that is just - here for consistancy with the ReadWrite API. The tokens for the read only - interface are intentionally /not/ validated. It's a public API. + here for consistancy with the ReadWrite API. Read write operations do + require the token. """ - def __init__(self,api,logger,enable_auth_if_relevant): + def __init__(self,api,enable_auth_if_relevant): self.api = api - self.logger = logger self.auth_enabled = enable_auth_if_relevant + self.cache = DataCache(self.api) + self.logger = self.api.logger + self.token_cache = TOKEN_CACHE + self.object_cache = OBJECT_CACHE self.timestamp = self.api.last_modified_time() + random.seed(time.time()) def __sorter(self,a,b): return cmp(a["name"],b["name"]) @@ -85,10 +149,15 @@ class CobblerXMLRPCInterface: return self.api.last_modified_time() def update(self, token=None): - now = self.api.last_modified_time() - if (now > self.timestamp): - self.timestamp = now - self.api.update() + # no longer neccessary + return True + + def internal_cache_update(self, collection_type, data): + self.cache.update(collection_type, data) + return True + + def internal_cache_remove(self, collection_type, data): + self.cache.remove(collection_type, data) return True def ping(self): @@ -163,11 +232,26 @@ class CobblerXMLRPCInterface: # FIXME: a global lock or module around data access loading # would be useful for non-db backed storage - data = self.api.deserialize_raw(collection_name) - total_items = len(data) - if collection_name == "settings": - return self._fix_none(data) + data = self.api.deserialize_raw("settings") + return self.xmlrpc_hacks(data) + else: + contents = [] + if collection_name.startswith("distro"): + contents = self.api.distros() + elif collection_name.startswith("profile"): + contents = self.api.profiles() + elif collection_name.startswith("system"): + contents = self.api.systems() + elif collection_name.startswith("repo"): + contents = self.api.repos() + elif collection_name.startswith("image"): + contents = self.api.images() + else: + raise CX("internal error, collection name is %s" % collection_name) + # FIXME: speed this up + data = contents.to_datastruct() + total_items = len(data) data.sort(self.__sorter) @@ -184,9 +268,9 @@ class CobblerXMLRPCInterface: start_point = total_items - 1 # correct ??? if end_point > total_items: end_point = total_items - data = self._fix_none(data[start_point:end_point]) + data = self.xmlrpc_hacks(data[start_point:end_point]) - return self._fix_none(data) + return self.xmlrpc_hacks(data) def get_kickstart_templates(self,token=None,**rest): """ @@ -208,10 +292,6 @@ class CobblerXMLRPCInterface: def generate_kickstart(self,profile=None,system=None,REMOTE_ADDR=None,REMOTE_MAC=None,**rest): self._log("generate_kickstart") - - if profile and not system: - regrc = self.register_mac(REMOTE_MAC,profile) - return self.api.generate_kickstart(profile,system) def get_settings(self,token=None,**rest): @@ -219,7 +299,9 @@ class CobblerXMLRPCInterface: Return the contents of /etc/cobbler/settings, which is a hash. """ self._log("get_settings",token=token) - return self.__get_all("settings") + results = self.api.settings().to_datastruct() + self._log("my settings are: %s" % results) + return self.xmlrpc_hacks(results) def get_repo_config_for_profile(self,profile_name,**rest): """ @@ -259,43 +341,78 @@ class CobblerXMLRPCInterface: return "# object not found: %s" % system_name return self.api.get_template_file_for_system(obj,path) - def register_mac(self,mac,profile,token=None,**rest): + def register_new_system(self,info,token=None,**rest): """ If register_new_installs is enabled in settings, this allows - kickstarts to add new system records for per-profile-provisioned - systems automatically via a wget in %post. This has security - implications. - READ: https://fedorahosted.org/cobbler/wiki/AutoRegistration + /usr/bin/cobbler-register (part of the koan package) to add + new system records remotely if they don't already exist. + There is a cobbler_register snippet that helps with doing + this automatically for new installs but it can also be used + for existing installs. See "AutoRegistration" on the Wiki. """ - - if mac is None: - # don't go further if not being called by anaconda - return 1 - - if not self.api.settings().register_new_installs: - # must be enabled in settings - return 2 - - system = self.api.find_system(mac_address=mac) - if system is not None: - # do not allow overwrites - return 3 - - # the MAC probably looks like "eth0 AA:BB:CC:DD:EE:FF" now, fix it - if mac.find(" ") != -1: - mac = mac.split()[-1] - - dup = self.api.find_system(mac_address=mac) - if dup is not None: - return 4 - - self._log("register mac for profile %s" % profile,token=token,name=mac) + + enabled = self.api.settings().register_new_installs + if not str(enabled) in [ "1", "y", "yes", "true" ]: + raise CX("registration is disabled in cobbler settings") + + # validate input + name = info.get("name","") + profile = info.get("profile","") + hostname = info.get("hostname","") + interfaces = info.get("interfaces",{}) + ilen = len(interfaces.keys()) + + if name == "": + raise CX("no system name submitted") + if profile == "": + raise CX("profile not submitted") + if ilen == 0: + raise CX("no interfaces submitted") + if ilen >= 64: + raise CX("too many interfaces submitted") + + # validate things first + name = info.get("name","") + inames = interfaces.keys() + if self.api.find_system(name=name): + raise CX("system name conflicts") + if hostname != "" and self.api.find_system(hostname=hostname): + raise CX("hostname conflicts") + + for iname in inames: + mac = info["interfaces"][iname].get("mac_address","") + ip = info["interfaces"][iname].get("ip_address","") + if ip.find("/") != -1: + raise CX("no CIDR ips are allowed") + if mac == "": + raise CX("missing MAC address for interface %s" % iname) + if mac != "": + system = self.api.find_system(mac_address=mac) + if system is not None: + raise CX("mac conflict: %s" % mac) + if ip != "": + system = self.api.find_system(ip_address=ip) + if system is not None: + raise CX("ip conflict: %s"% ip) + + # looks like we can go ahead and create a system now obj = self.api.new_system() obj.set_profile(profile) - name = mac.replace(":","_") obj.set_name(name) - obj.set_mac_address(mac, "eth0") + if hostname != "": + obj.set_hostname(hostname) obj.set_netboot_enabled(False) + for iname in inames: + mac = info["interfaces"][iname].get("mac_address","") + ip = info["interfaces"][iname].get("ip_address","") + netmask = info["interfaces"][iname].get("netmask","") + obj.set_mac_address(mac, iname) + if hostname != "": + obj.set_dns_name(hostname, iname) + if ip != "": + obj.set_ip_address(ip, iname) + if netmask != "": + obj.set_subnet(netmask, iname) self.api.add_system(obj) return 0 @@ -320,6 +437,109 @@ class CobblerXMLRPCInterface: systems.add(obj,save=True,with_triggers=False,with_sync=False,quick_pxe_update=True) return True + def upload_log_data(self, sys_name, file, size, offset, data, token=None,**rest): + + """ + This is a logger function used by the "anamon" logging system to + upload all sorts of auxilliary data from Anaconda. + As it's a bit of a potential log-flooder, it's off by default + and needs to be enabled in /etc/cobbler/settings. + """ + + self._log("upload_log_data (file: '%s', size: %s, offset: %s)" % (file, size, offset), token=token, name=sys_name) + + # Check if enabled in self.api.settings() + if not self.api.settings().anamon_enabled: + # feature disabled! + return False + + # Find matching system record + systems = self.api.systems() + obj = systems.find(name=sys_name) + if obj == None: + # system not found! + self._log("upload_log_data - system '%s' not found" % sys_name, token=token, name=sys_name) + return False + + return self.__upload_file(sys_name, file, size, offset, data) + + def __upload_file(self, sys_name, file, size, offset, data): + ''' + system: the name of the system + name: the name of the file + size: size of contents (bytes) + data: base64 encoded file contents + offset: the offset of the chunk + files can be uploaded in chunks, if so the size describes + the chunk rather than the whole file. the offset indicates where + the chunk belongs + the special offset -1 is used to indicate the final chunk''' + contents = base64.decodestring(data) + del data + if offset != -1: + if size is not None: + if size != len(contents): + return False + + #XXX - have an incoming dir and move after upload complete + # SECURITY - ensure path remains under uploadpath + tt = string.maketrans("/","+") + fn = string.translate(file, tt) + if fn.startswith('..'): + raise CX(_("invalid filename used: %s") % fn) + + # FIXME ... get the base dir from cobbler settings() + udir = "/var/log/cobbler/anamon/%s" % sys_name + if not os.path.isdir(udir): + os.mkdir(udir, 0755) + + fn = "%s/%s" % (udir, fn) + try: + st = os.lstat(fn) + except OSError, e: + if e.errno == errno.ENOENT: + pass + else: + raise + else: + if not stat.S_ISREG(st.st_mode): + raise CX(_("destination not a file: %s") % fn) + + fd = os.open(fn, os.O_RDWR | os.O_CREAT, 0644) + # log_error("fd=%r" %fd) + try: + if offset == 0 or (offset == -1 and size == len(contents)): + #truncate file + fcntl.lockf(fd, fcntl.LOCK_EX|fcntl.LOCK_NB) + try: + os.ftruncate(fd, 0) + # log_error("truncating fd %r to 0" %fd) + finally: + fcntl.lockf(fd, fcntl.LOCK_UN) + if offset == -1: + os.lseek(fd,0,2) + else: + os.lseek(fd,offset,0) + #write contents + fcntl.lockf(fd, fcntl.LOCK_EX|fcntl.LOCK_NB, len(contents), 0, 2) + try: + os.write(fd, contents) + # log_error("wrote contents") + finally: + fcntl.lockf(fd, fcntl.LOCK_UN, len(contents), 0, 2) + if offset == -1: + if size is not None: + #truncate file + fcntl.lockf(fd, fcntl.LOCK_EX|fcntl.LOCK_NB) + try: + os.ftruncate(fd, size) + # log_error("truncating fd %r to size %r" % (fd,size)) + finally: + fcntl.lockf(fd, fcntl.LOCK_UN) + finally: + os.close(fd) + return True + def run_install_triggers(self,mode,objtype,name,ip,token=None,**rest): """ @@ -339,7 +559,7 @@ class CobblerXMLRPCInterface: # time if reinstalling all of a cluster all at once. # we can do that at "cobbler check" time. - utils.run_triggers(None, "/var/lib/cobbler/triggers/install/%s/*" % mode, additional=[objtype,name,ip]) + utils.run_triggers(self.api, None, "/var/lib/cobbler/triggers/install/%s/*" % mode, additional=[objtype,name,ip]) return True @@ -366,41 +586,81 @@ class CobblerXMLRPCInterface: self._log("get_distros",token=token) return self.__get_all("distro",page,results_per_page) + + def __find(self,find_function,criteria={},expand=False,token=None): + name = criteria.get("name",None) + if name is not None: + del criteria["name"] + if not expand: + data = [x.name for x in find_function(name, True, True, **criteria)] + else: + data = [x.to_datastruct() for x in find_function(name, True, True, **criteria)] + return self.xmlrpc_hacks(data) + + def find_distro(self,criteria={},expand=False,token=None,**rest): + self._log("find_distro", token=token) + # FIXME DEBUG + self._log(criteria) + data = self.__find(self.api.find_distro,criteria,expand=expand,token=token) + # FIXME DEBUG + self._log(data) + return data + + def find_profile(self,criteria={},expand=False,token=None,**rest): + self._log("find_profile", token=token) + data = self.__find(self.api.find_profile,criteria,expand=expand,token=token) + return data + + def find_system(self,criteria={},expand=False,token=None,**rest): + self._log("find_system", token=token) + data = self.__find(self.api.find_system,criteria,expand=expand,token=token) + return data + + def find_repo(self,criteria={},expand=False,token=None,**rest): + self._log("find_repo", token=token) + data = self.__find(self.api.find_repo,criteria,expand=expand,token=token) + return data + + def find_image(self,criteria={},expand=False,token=None,**rest): + self._log("find_image", token=token) + data = self.__find(self.api.find_image,criteria,expand=expand,token=token) + return data + def get_distros_since(self,mtime): """ Return all of the distro objects that have been modified after mtime. """ data = self.api.get_distros_since(mtime, collapse=True) - return self._fix_none(data) + return self.xmlrpc_hacks(data) def get_profiles_since(self,mtime): """ See documentation for get_distros_since """ data = self.api.get_profiles_since(mtime, collapse=True) - return self._fix_none(data) + return self.xmlrpc_hacks(data) def get_systems_since(self,mtime): """ See documentation for get_distros_since """ data = self.api.get_systems_since(mtime, collapse=True) - return self._fix_none(data) + return self.xmlrpc_hacks(data) def get_repos_since(self,mtime): """ See documentation for get_distros_since """ data = self.api.get_repos_since(mtime, collapse=True) - return self._fix_none(data) + return self.xmlrpc_hacks(data) def get_images_since(self,mtime): """ See documentation for get_distros_since """ data = self.api.get_images_since(mtime, collapse=True) - return self._fix_none(data) + return self.xmlrpc_hacks(data) def get_profiles(self,page=None,results_per_page=None,token=None,**rest): """ @@ -476,7 +736,7 @@ class CobblerXMLRPCInterface: return {} if flatten: result = utils.flatten(result) - return self._fix_none(result) + return self.xmlrpc_hacks(result) def get_distro(self,name,flatten=False,token=None,**rest): """ @@ -541,8 +801,8 @@ class CobblerXMLRPCInterface: self._log("get_distro_as_rendered",name=name,token=token) obj = self.api.find_distro(name=name) if obj is not None: - return self._fix_none(utils.blender(self.api, True, obj)) - return self._fix_none({}) + return self.xmlrpc_hacks(utils.blender(self.api, True, obj)) + return self.xmlrpc_hacks({}) def get_profile_as_rendered(self,name,token=None,**rest): """ @@ -559,8 +819,8 @@ class CobblerXMLRPCInterface: self._log("get_profile_as_rendered", name=name, token=token) obj = self.api.find_profile(name=name) if obj is not None: - return self._fix_none(utils.blender(self.api, True, obj)) - return self._fix_none({}) + return self.xmlrpc_hacks(utils.blender(self.api, True, obj)) + return self.xmlrpc_hacks({}) def get_system_as_rendered(self,name,token=None,**rest): """ @@ -577,8 +837,8 @@ class CobblerXMLRPCInterface: self._log("get_system_as_rendered",name=name,token=token) obj = self.api.find_system(name=name) if obj is not None: - return self._fix_none(utils.blender(self.api, True, obj)) - return self._fix_none({}) + return self.xmlrpc_hacks(utils.blender(self.api, True, obj)) + return self.xmlrpc_hacks({}) def get_repo_as_rendered(self,name,token=None,**rest): """ @@ -595,8 +855,8 @@ class CobblerXMLRPCInterface: self._log("get_repo_as_rendered",name=name,token=token) obj = self.api.find_repo(name=name) if obj is not None: - return self._fix_none(utils.blender(self.api, True, obj)) - return self._fix_none({}) + return self.xmlrpc_hacks(utils.blender(self.api, True, obj)) + return self.xmlrpc_hacks({}) def get_image_as_rendered(self,name,token=None,**rest): """ @@ -613,8 +873,8 @@ class CobblerXMLRPCInterface: self._log("get_image_as_rendered",name=name,token=token) obj = self.api.find_image(name=name) if obj is not None: - return self._fix_none(utils.blender(self.api, True, obj)) - return self._fix_none({}) + return self.xmlrpc_hacks(utils.blender(self.api, True, obj)) + return self.xmlrpc_hacks({}) def get_random_mac(self,token=None,**rest): """ @@ -625,21 +885,29 @@ class CobblerXMLRPCInterface: self._log("get_random_mac",token=None) return utils.get_random_mac(self.api) - def _fix_none(self,data): + def xmlrpc_hacks(self,data): """ - Convert None in XMLRPC to just '~'. The above - XMLRPC module hack should do this, but let's make extra sure. + Convert None in XMLRPC to just '~' to make extra sure a client + that can't allow_none can deal with this. ALSO: a weird hack ensuring + that when dicts with integer keys (or other types) are transmitted + with string keys. """ if data is None: data = '~' elif type(data) == list: - data = [ self._fix_none(x) for x in data ] + data = [ self.xmlrpc_hacks(x) for x in data ] elif type(data) == dict: + data2 = {} for key in data.keys(): - data[key] = self._fix_none(data[key]) + keydata = data[key] + data2[str(key)] = self.xmlrpc_hacks(data[key]) + return data2 + + else: + data = '~' return data @@ -649,50 +917,11 @@ class CobblerXMLRPCInterface: """ return self.api.status() -# ********************************************************************************* -# ********************************************************************************* - -class CobblerXMLRPCServer(SimpleXMLRPCServer.SimpleXMLRPCServer): - def __init__(self, args): - self.allow_reuse_address = True - SimpleXMLRPCServer.SimpleXMLRPCServer.__init__(self,args) - -# ********************************************************************************* -# ********************************************************************************* - + ###### + # READ WRITE METHODS BELOW REQUIRE A TOKEN, use login() + # TO OBTAIN ONE + ###### -class ProxiedXMLRPCInterface: - - def __init__(self,api,logger,proxy_class,enable_auth_if_relevant=True): - self.logger = logger - self.proxied = proxy_class(api,logger,enable_auth_if_relevant) - - def _dispatch(self, method, params, **rest): - - if not hasattr(self.proxied, method): - self.logger.error("remote:unknown method %s" % method) - raise CX(_("Unknown remote method")) - - method_handle = getattr(self.proxied, method) - - try: - return method_handle(*params) - except Exception, e: - utils.log_exc(self.logger) - raise e - -# ********************************************************************** - -class CobblerReadWriteXMLRPCInterface(CobblerXMLRPCInterface): - - def __init__(self,api,logger,enable_auth_if_relevant): - self.api = api - self.auth_enabled = enable_auth_if_relevant - self.logger = logger - self.token_cache = TOKEN_CACHE - self.object_cache = OBJECT_CACHE - self.timestamp = self.api.last_modified_time() - random.seed(time.time()) def __next_id(self,retry=0): """ @@ -701,7 +930,7 @@ class CobblerReadWriteXMLRPCInterface(CobblerXMLRPCInterface): """ if retry > 10: # I have no idea why this would happen but I want to be through :) - raise CX(_("internal error")) + raise CX(_("internal error, retry exceeded")) next_id = self.__get_random(25) if self.object_cache.has_key(next_id): return self.__next_id(retry=retry+1) @@ -907,6 +1136,7 @@ class CobblerReadWriteXMLRPCInterface(CobblerXMLRPCInterface): do reposync this way. Would be nice to send output over AJAX/other later. """ + # FIXME: performance self._log("sync",token=token) self.check_access(token,"sync") return self.api.sync() @@ -1136,7 +1366,6 @@ class CobblerReadWriteXMLRPCInterface(CobblerXMLRPCInterface): object. """ self._log("rename_distro",object_id=object_id,token=token) - self.api.deserialize() # FIXME: make this unneeded obj = self.__get_object(object_id) return self.api.rename_distro(obj,newname) @@ -1161,7 +1390,6 @@ class CobblerReadWriteXMLRPCInterface(CobblerXMLRPCInterface): def rename_image(self,object_id,newname,token=None): self._log("rename_image",object_id=object_id,token=token) self.check_access(token,"rename_image") - self.api.deserialize() # FIXME: make this unneeded obj = self.__get_object(object_id) return self.api.rename_image(obj,newname) @@ -1335,18 +1563,41 @@ class CobblerReadWriteXMLRPCInterface(CobblerXMLRPCInterface): return rc -# ********************************************************************* -# ********************************************************************* -class CobblerReadWriteXMLRPCServer(SimpleXMLRPCServer.SimpleXMLRPCServer): - """ - This is just a wrapper used for launching the Read/Write XMLRPC Server. - """ + +# ********************************************************************************* +# ********************************************************************************* + +class CobblerXMLRPCServer(SimpleXMLRPCServer.SimpleXMLRPCServer): def __init__(self, args): self.allow_reuse_address = True SimpleXMLRPCServer.SimpleXMLRPCServer.__init__(self,args) +# ********************************************************************************* +# ********************************************************************************* + + +class ProxiedXMLRPCInterface: + + def __init__(self,api,proxy_class,enable_auth_if_relevant=True): + self.proxied = proxy_class(api,enable_auth_if_relevant) + self.logger = self.proxied.api.logger + + def _dispatch(self, method, params, **rest): + + if not hasattr(self.proxied, method): + self.logger.error("remote:unknown method %s" % method) + raise CX(_("Unknown remote method")) + + method_handle = getattr(self.proxied, method) + + try: + return method_handle(*params) + except Exception, e: + utils.log_exc(self.logger) + raise e + # ********************************************************************* # ********************************************************************* @@ -1360,7 +1611,9 @@ def _test_setup_modules(authn="authn_testing",authz="authz_allowall",pxe_once=1) MODULES_TEMPLATE = "installer_templates/modules.conf.template" DEFAULTS = "installer_templates/defaults" - data = yaml.loadFile(DEFAULTS).next() + fh = open(DEFAULTS) + data = yaml.load(fh.read()) + fh.close() data["authn_module"] = authn data["authz_module"] = authz data["pxe_once"] = pxe_once @@ -1379,7 +1632,9 @@ def _test_setup_settings(pxe_once=1): MODULES_TEMPLATE = "installer_templates/settings.template" DEFAULTS = "installer_templates/defaults" - data = yaml.loadFile(DEFAULTS).next() + fh = open(DEFAULTS) + data = yaml.load(fh.read()) + fh.close() data["pxe_once"] = pxe_once t = Template.Template(file=MODULES_TEMPLATE, searchList=[data]) @@ -1393,13 +1648,13 @@ def _test_bootstrap_restart(): assert rc1 == 0 rc2 = subprocess.call(["/sbin/service","httpd","restart"],shell=False,close_fds=True) assert rc2 == 0 - time.sleep(2) + time.sleep(5) _test_remove_objects() def _test_remove_objects(): - api = cobbler_api.BootAPI() + api = cobbler_api.BootAPI() # local handle # from ro tests d0 = api.find_distro("distro0") @@ -1444,8 +1699,7 @@ def test_xmlrpc_ro(): # now populate with something more useful # using the non-remote API - api = cobbler_api.BootAPI() - api.deserialize() # FIXME: redundant + api = cobbler_api.BootAPI() # local handle before_distros = len(api.distros()) before_profiles = len(api.profiles()) @@ -1453,10 +1707,14 @@ def test_xmlrpc_ro(): before_repos = len(api.repos()) before_images = len(api.images()) + fake = open("/tmp/cobbler.fake","w+") + fake.write("") + fake.close() + distro = api.new_distro() distro.set_name("distro0") - distro.set_kernel("/etc/hosts") - distro.set_initrd("/etc/hosts") + distro.set_kernel("/tmp/cobbler.fake") + distro.set_initrd("/tmp/cobbler.fake") api.add_distro(distro) repo = api.new_repo() @@ -1488,7 +1746,7 @@ def test_xmlrpc_ro(): image = api.new_image() image.set_name("image0") - image.set_file("/etc/hosts") + image.set_file("/tmp/cobbler.fake") api.add_image(image) # reposync is required in order to create the repo config files @@ -1676,8 +1934,8 @@ def test_xmlrpc_rw(): _test_setup_modules(authn="authn_testing",authz="authz_allowall") _test_bootstrap_restart() - server = xmlrpclib.Server("http://127.0.0.1/cobbler_api_rw") # remote - api = cobbler_api.BootAPI() # local + server = xmlrpclib.Server("http://127.0.0.1/cobbler_api") # remote + api = cobbler_api.BootAPI() # local instance, /DO/ ping cobblerd # note if authn_testing is not engaged this will not work # test getting token, will raise remote exception on fail @@ -1687,17 +1945,18 @@ def test_xmlrpc_rw(): # create distro did = server.new_distro(token) server.modify_distro(did, "name", "distro1", token) - server.modify_distro(did, "kernel", "/etc/hosts", token) - server.modify_distro(did, "initrd", "/etc/hosts", token) + server.modify_distro(did, "kernel", "/tmp/cobbler.fake", token) + server.modify_distro(did, "initrd", "/tmp/cobbler.fake", token) server.modify_distro(did, "kopts", { "dog" : "fido", "cat" : "fluffy" }, token) # hash or string server.modify_distro(did, "ksmeta", "good=sg1 evil=gould", token) # hash or string server.modify_distro(did, "breed", "redhat", token) server.modify_distro(did, "os-version", "rhel5", token) server.modify_distro(did, "owners", "sam dave", token) # array or string server.modify_distro(did, "mgmt-classes", "blip", token) # list or string - server.modify_distro(did, "template-files", "/etc/hosts=/tmp/a /etc/fstab=/tmp/b",token) # hash or string + server.modify_distro(did, "template-files", "/tmp/cobbler.fake=/tmp/a /etc/fstab=/tmp/b",token) # hash or string server.modify_distro(did, "comment", "...", token) server.modify_distro(did, "redhat_management_key", "ALPHA", token) + server.modify_distro(did, "redhat_management_server", "rhn.example.com", token) server.save_distro(did, token) # use the non-XMLRPC API to check that it's added seeing we tested XMLRPC RW APIs above @@ -1723,7 +1982,9 @@ def test_xmlrpc_rw(): server.modify_profile(pid, "mgmt-classes", "one two three", token) server.modify_profile(pid, "comment", "...", token) server.modify_profile(pid, "name_servers", ["one","two"], token) + server.modify_profile(pid, "name_servers_search", ["one","two"], token) server.modify_profile(pid, "redhat_management_key", "BETA", token) + server.modify_distro(did, "redhat_management_server", "sat.example.com", token) server.save_profile(pid, token) api.deserialize() @@ -1741,6 +2002,7 @@ def test_xmlrpc_rw(): server.modify_system(sid, 'virt-path', "/opt/images", token) server.modify_system(sid, 'virt-type', 'qemu', token) server.modify_system(sid, 'name_servers', 'one two three four', token) + server.modify_system(sid, 'name_servers_search', 'one two three four', token) server.modify_system(sid, 'modify-interface', { "macaddress-eth0" : "AA:BB:CC:EE:EE:EE", "ipaddress-eth0" : "192.168.10.50", @@ -1764,6 +2026,7 @@ def test_xmlrpc_rw(): server.modify_system(sid, "power_pass", "magic", token) server.modify_system(sid, "power_id", "7", token) server.modify_system(sid, "redhat_management_key", "GAMMA", token) + server.modify_distro(did, "redhat_management_server", "spacewalk.example.com", token) server.save_system(sid,token) |