summaryrefslogtreecommitdiffstats
path: root/cobbler
diff options
context:
space:
mode:
authorMichael DeHaan <mdehaan@mdehaan.rdu.redhat.com>2007-09-11 18:41:35 -0400
committerMichael DeHaan <mdehaan@mdehaan.rdu.redhat.com>2007-09-11 18:41:35 -0400
commitbe10c5605d5376a8c5c14a3be5b306bb951fd0f2 (patch)
treeb91b754cca3707cb65c30716d6ecc838c4a93532 /cobbler
parent17ffb1ded3928943abfad248e12240868678ac3f (diff)
downloadthird_party-cobbler-be10c5605d5376a8c5c14a3be5b306bb951fd0f2.tar.gz
third_party-cobbler-be10c5605d5376a8c5c14a3be5b306bb951fd0f2.tar.xz
third_party-cobbler-be10c5605d5376a8c5c14a3be5b306bb951fd0f2.zip
Check in beginings of Cobbler WebUI packaging (thanks: Al Tobey). More work TBA.
Diffstat (limited to 'cobbler')
-rw-r--r--cobbler/action_sync.py2
-rw-r--r--cobbler/webui/CobblerWeb.py191
-rw-r--r--cobbler/webui/__init__.py0
-rw-r--r--cobbler/webui/master.py240
-rwxr-xr-xcobbler/webui/webui-cgi.py47
-rwxr-xr-xcobbler/webui/webui-cherrypy3.py10
6 files changed, 489 insertions, 1 deletions
diff --git a/cobbler/action_sync.py b/cobbler/action_sync.py
index 19c6d63..86aaa2f 100644
--- a/cobbler/action_sync.py
+++ b/cobbler/action_sync.py
@@ -249,7 +249,7 @@ class BootSync:
if not x.endswith(".py"):
self.rmfile(path)
if os.path.isdir(path):
- if not x in ["localmirror","repo_mirror","ks_mirror","kickstarts","kickstarts_sys","distros","images","systems","profiles","links"] :
+ if not x in ["webui", "localmirror","repo_mirror","ks_mirror","kickstarts","kickstarts_sys","distros","images","systems","profiles","links"] :
# delete directories that shouldn't exist
self.rmtree(path)
if x in ["kickstarts","kickstarts_sys","images","systems","distros","profiles"]:
diff --git a/cobbler/webui/CobblerWeb.py b/cobbler/webui/CobblerWeb.py
new file mode 100644
index 0000000..4ed8d39
--- /dev/null
+++ b/cobbler/webui/CobblerWeb.py
@@ -0,0 +1,191 @@
+#!/usr/bin/env python
+
+import xmlrpclib
+from Cheetah.Template import Template
+import os
+
+class CobblerWeb(object):
+ def __init__(self, server=None, base_url='/'):
+ self.server = server
+ self.base_url = base_url
+
+ def xmlrpc(self):
+ return xmlrpclib.ServerProxy(self.server, allow_none=True)
+
+ def __render(self, template, data):
+ data['base_url'] = self.base_url
+ #filepath = "%s/%s" % (os.path.dirname(__file__), template)
+ filepath = os.path.join("/usr/share/cobbler/webui_templates/",template)
+ tmpl = Template( file=filepath, searchList=data )
+ return str(tmpl)
+
+ def modes(self):
+ retval = list()
+ for m in dir(self):
+ func = getattr( self, m )
+ if hasattr(func, 'exposed') and getattr(func,'exposed'):
+ retval.append(m)
+ return retval
+
+ # ------------------------------------------------------------------------ #
+ # Index
+ # ------------------------------------------------------------------------ #
+ def index(self):
+ return self.__render( 'index.tmpl', dict() )
+
+ # ------------------------------------------------------------------------ #
+ # Settings
+ # ------------------------------------------------------------------------ #
+ def settings_view(self):
+ return self.__render( 'item.tmpl', {
+ 'item_data': self.xmlrpc().get_settings(),
+ 'caption': "Cobbler Settings"
+ } )
+
+ # ------------------------------------------------------------------------ #
+ # Distributions
+ # ------------------------------------------------------------------------ #
+ def distro_view(self, distribution):
+ # get_distro_for_koan() flattens out the inherited options
+ #distro = self.xmlrpc().get_distro_for_koan(distribution)
+ return self.__render( 'item.tmpl', {
+ 'item_data': self.xmlrpc().get_distro(distribution),
+ 'caption': "Distribution \"%s\" Details" % distribution
+ } )
+
+ def distro_list(self):
+ return self.__render( 'distro_list.tmpl', {
+ 'distros': self.xmlrpc().get_distros()
+ } )
+
+ # ------------------------------------------------------------------------ #
+ # Systems
+ # ------------------------------------------------------------------------ #
+ # if the system list is huge, this will probably need to use an
+ # iterator so the list doesn't get copied around
+ def system_list(self):
+ return self.__render( 'system_list.tmpl', {
+ 'systems': self.xmlrpc().get_systems()
+ } )
+
+ def system_add(self):
+ return self.__render( 'system_edit.tmpl', {
+ 'profiles': self.xmlrpc().get_profiles()
+ } )
+
+ def system_view(self, name):
+ return self.__render( 'item.tmpl', {
+ 'item_data': self.xmlrpc().get_profile(name),
+ 'caption': "Profile %s Settings" % name
+ } )
+
+ def system_save(self, name, profile, submit, new_or_edit, mac=None, ip=None, hostname=None, kopts=None, ksmeta=None, netboot='n'):
+ # parameter checking
+ if name is None:
+ return self.error_page("System name parameter is REQUIRED.")
+
+ if mac is None and ip is None and hostname is None:
+ return self.error_page("System must have at least one of MAC/IP/hostname.")
+
+ # resolve_ip, is_mac, and is_ip are from cobbler.utils
+ if hostname and not ip:
+ ip = resolve_ip( hostname )
+
+ if mac and not is_mac( mac ):
+ return self.error_page("The provided MAC address appears to be invalid.")
+
+ if ip and not is_ip( ip ):
+ return self.error_page("The provided IP address appears to be invalid.")
+
+ if new_or_edit == "edit":
+ system = self.xmlrpc().get_system(name)
+ else:
+ # FIXME: convert to r/w xmlrpc
+ system = None
+ #system = self.api.new_system()
+ system.set_name( name )
+ self.api.systems().add( system )
+
+ system.set_profile( profile )
+
+ return self.__render( 'item.tmpl', {
+ 'item_data': system,
+ 'caption': "Profile %s Settings" % name
+ } )
+
+ def system_edit(self, name):
+ return self.__render( 'system_edit.tmpl', {
+ 'system': self.xmlrpc().get_system(name),
+ 'profiles': self.xmlrpc().get_profiles()
+ } )
+
+ # ------------------------------------------------------------------------ #
+ # Profiles
+ # ------------------------------------------------------------------------ #
+ def profile_list(self):
+ return self.__render( 'profile_list.tmpl', {
+ 'profiles': self.xmlrpc().get_profiles()
+ } )
+
+ def profile_add(self):
+ return self.__render( 'profile_add.tmpl', {
+ 'distros': self.xmlrpc().get_distros(),
+ 'ksfiles': self.__ksfiles()
+ } )
+
+ def profile_save(self):
+ pass
+
+ # ------------------------------------------------------------------------ #
+ # Kickstart files
+ # ------------------------------------------------------------------------ #
+ def ksfile_list(self):
+ return self.__render( 'ksfile_list.tmpl', {
+ 'ksfiles': self.__ksfiles()
+ } )
+
+ def ksfile_view(self, ksfile):
+ return self.__render( 'ksfile_view.tmpl', {
+ 'ksdata': self.__ksfile_data( ksfile ),
+ 'ksfile': ksfile
+ } )
+
+ def __ksfiles(self):
+ ksfiles = list()
+ for profile in self.xmlrpc().get_profiles():
+ ksfile = profile['kickstart']
+ if not ksfile in ksfiles:
+ ksfiles.append( ksfile )
+ return ksfiles
+
+ def __ksfile_data(self, ksfile):
+ pass
+
+ # ------------------------------------------------------------------------ #
+ # Miscellaneous
+ # ------------------------------------------------------------------------ #
+ def error_page(self, message):
+ return self.__render( 'error_page.tmpl', {
+ 'message': message
+ } )
+
+ # make CherryPy and related frameworks able to use this module easily
+ # by borrowing the 'exposed' function attritbute standard and using
+ # it for the modes() method
+ modes.exposed = False
+ error_page.exposed = False
+ distro_list.exposed = True
+ distro_view.exposed = True
+ index.exposed = True
+ profile_add.exposed = True
+ profile_list.exposed = True
+ profile_save.exposed = True
+ settings_view.exposed = True
+ system_add.exposed = True
+ system_edit.exposed = True
+ system_list.exposed = True
+ system_save.exposed = True
+ system_view.exposed = True
+ ksfile_view.exposed = True
+ ksfile_list.exposed = True
+
diff --git a/cobbler/webui/__init__.py b/cobbler/webui/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/cobbler/webui/__init__.py
diff --git a/cobbler/webui/master.py b/cobbler/webui/master.py
new file mode 100644
index 0000000..58b5047
--- /dev/null
+++ b/cobbler/webui/master.py
@@ -0,0 +1,240 @@
+#!/usr/bin/env python
+
+
+
+
+##################################################
+## DEPENDENCIES
+import sys
+import os
+import os.path
+from os.path import getmtime, exists
+import time
+import types
+import __builtin__
+from Cheetah.Version import MinCompatibleVersion as RequiredCheetahVersion
+from Cheetah.Version import MinCompatibleVersionTuple as RequiredCheetahVersionTuple
+from Cheetah.Template import Template
+from Cheetah.DummyTransaction import DummyTransaction
+from Cheetah.NameMapper import NotFound, valueForName, valueFromSearchList, valueFromFrameOrSearchList
+from Cheetah.CacheRegion import CacheRegion
+import Cheetah.Filters as Filters
+import Cheetah.ErrorCatchers as ErrorCatchers
+
+##################################################
+## MODULE CONSTANTS
+try:
+ True, False
+except NameError:
+ True, False = (1==1), (1==0)
+VFFSL=valueFromFrameOrSearchList
+VFSL=valueFromSearchList
+VFN=valueForName
+currentTime=time.time
+__CHEETAH_version__ = '2.0rc8'
+__CHEETAH_versionTuple__ = (2, 0, 0, 'candidate', 8)
+__CHEETAH_genTime__ = 1189393696.009383
+__CHEETAH_genTimestamp__ = 'Sun Sep 9 20:08:16 2007'
+__CHEETAH_src__ = 'master.tmpl'
+__CHEETAH_srcLastModified__ = 'Sun Sep 9 20:02:36 2007'
+__CHEETAH_docstring__ = 'Autogenerated by CHEETAH: The Python-Powered Template Engine'
+
+if __CHEETAH_versionTuple__ < RequiredCheetahVersionTuple:
+ raise AssertionError(
+ 'This template was compiled with Cheetah version'
+ ' %s. Templates compiled before version %s must be recompiled.'%(
+ __CHEETAH_version__, RequiredCheetahVersion))
+
+##################################################
+## CLASSES
+
+class master(Template):
+
+ ##################################################
+ ## CHEETAH GENERATED METHODS
+
+
+ def __init__(self, *args, **KWs):
+
+ Template.__init__(self, *args, **KWs)
+ if not self._CHEETAH__instanceInitialized:
+ cheetahKWArgs = {}
+ allowedKWs = 'searchList namespaces filter filtersLib errorCatcher'.split()
+ for k,v in KWs.items():
+ if k in allowedKWs: cheetahKWArgs[k] = v
+ self._initCheetahInstance(**cheetahKWArgs)
+
+
+ def body(self, **KWS):
+
+
+
+ ## CHEETAH: generated from #block body at line 46, col 1.
+ trans = KWS.get("trans")
+ if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+ trans = self.transaction # is None unless self.awake() was called
+ if not trans:
+ trans = DummyTransaction()
+ _dummyTrans = True
+ else: _dummyTrans = False
+ write = trans.response().write
+ SL = self._CHEETAH__searchList
+ _filter = self._CHEETAH__currentFilter
+
+ ########################################
+ ## START - generated method body
+
+ write('''
+ <h1 style="color: red;">Template Failure</h1>
+
+''')
+
+ ########################################
+ ## END - generated method body
+
+ return _dummyTrans and trans.response().getvalue() or ""
+
+
+ def respond(self, trans=None):
+
+
+
+ ## CHEETAH: main method generated for this template
+ if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)):
+ trans = self.transaction # is None unless self.awake() was called
+ if not trans:
+ trans = DummyTransaction()
+ _dummyTrans = True
+ else: _dummyTrans = False
+ write = trans.response().write
+ SL = self._CHEETAH__searchList
+ _filter = self._CHEETAH__currentFilter
+
+ ########################################
+ ## START - generated method body
+
+ write('''<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xml:lang="en" lang="en" xmlns="http://www.w3.org/1999/xhtml">
+<head>
+ <title>''')
+ _v = VFFSL(SL,"title",True) # '$title' on line 5, col 12
+ if _v is not None: write(_filter(_v, rawExpr='$title')) # from line 5, col 12.
+ write('''</title>
+ <meta http-equiv="Content-Type" content="text/html;charset=utf-8"/>
+
+ <link rel="stylesheet" type="text/css" media="all" href="/cobbler/webui/style.css" />
+ <link rel="stylesheet" type="text/css" media="all" href="/cobbler/webui/cobblerweb.css" />
+</head>
+
+<body>
+
+<div id="wrap">
+ <h1 id="masthead">
+ <a href="''')
+ _v = VFFSL(SL,"base_url",True) # '$base_url' on line 16, col 18
+ if _v is not None: write(_filter(_v, rawExpr='$base_url')) # from line 16, col 18.
+ write('''/index">
+ <img alt="Cobbler Logo"
+ src="/cobbler/webui/logo-cobbler.png"/>
+ </a>
+ </h1>
+</div>
+
+<div id="main">
+
+<div id="sidebar">
+ <ul id="nav">
+ <li>
+ <select name="cobbler_server" style="text-transform: none;">
+ <option value="http://localhost:25151">http://localhost:25151</option>
+ </select>
+ </li>
+ <li><hr/></li>
+ <li><a href="''')
+ _v = VFFSL(SL,"base_url",True) # '$base_url' on line 33, col 22
+ if _v is not None: write(_filter(_v, rawExpr='$base_url')) # from line 33, col 22.
+ write('''/settings_view" class="menu">Cobbler Settings</a></li>
+ <li><hr/></li>
+ <li><a href="''')
+ _v = VFFSL(SL,"base_url",True) # '$base_url' on line 35, col 22
+ if _v is not None: write(_filter(_v, rawExpr='$base_url')) # from line 35, col 22.
+ write('''/profile_list" class="menu">List Profiles</a></li>
+ <li><a href="''')
+ _v = VFFSL(SL,"base_url",True) # '$base_url' on line 36, col 22
+ if _v is not None: write(_filter(_v, rawExpr='$base_url')) # from line 36, col 22.
+ write('''/distro_list" class="menu">List Distros</a></li>
+ <li><a href="''')
+ _v = VFFSL(SL,"base_url",True) # '$base_url' on line 37, col 22
+ if _v is not None: write(_filter(_v, rawExpr='$base_url')) # from line 37, col 22.
+ write('''/system_list" class="menu">List Systems</a></li>
+ <li><a href="''')
+ _v = VFFSL(SL,"base_url",True) # '$base_url' on line 38, col 22
+ if _v is not None: write(_filter(_v, rawExpr='$base_url')) # from line 38, col 22.
+ write('''/ksfile_list" class="menu">List KS Files</a></li>
+ <li><hr/></li>
+ <li><a href="''')
+ _v = VFFSL(SL,"base_url",True) # '$base_url' on line 40, col 22
+ if _v is not None: write(_filter(_v, rawExpr='$base_url')) # from line 40, col 22.
+ write('''/system_add" class="menu">Add System</a></li>
+ <li><a href="''')
+ _v = VFFSL(SL,"base_url",True) # '$base_url' on line 41, col 22
+ if _v is not None: write(_filter(_v, rawExpr='$base_url')) # from line 41, col 22.
+ write('''/profile_add" class="menu">Add Profile</a></li>
+ </ul>
+</div>
+
+<div id="content">
+''')
+ self.body(trans=trans)
+ write('''</div><!-- content -->
+</div><!-- main -->
+
+</body>
+</html>
+''')
+
+ ########################################
+ ## END - generated method body
+
+ return _dummyTrans and trans.response().getvalue() or ""
+
+ ##################################################
+ ## CHEETAH GENERATED ATTRIBUTES
+
+
+ _CHEETAH__instanceInitialized = False
+
+ _CHEETAH_version = __CHEETAH_version__
+
+ _CHEETAH_versionTuple = __CHEETAH_versionTuple__
+
+ _CHEETAH_genTime = __CHEETAH_genTime__
+
+ _CHEETAH_genTimestamp = __CHEETAH_genTimestamp__
+
+ _CHEETAH_src = __CHEETAH_src__
+
+ _CHEETAH_srcLastModified = __CHEETAH_srcLastModified__
+
+ title = "Cobbler Web Interface"
+
+ _mainCheetahMethod_for_master= 'respond'
+
+## END CLASS DEFINITION
+
+if not hasattr(master, '_initCheetahAttributes'):
+ templateAPIClass = getattr(master, '_CHEETAH_templateClass', Template)
+ templateAPIClass._addCheetahPlumbingCodeToClass(master)
+
+
+# CHEETAH was developed by Tavis Rudd and Mike Orr
+# with code, advice and input from many other volunteers.
+# For more information visit http://www.CheetahTemplate.org/
+
+##################################################
+## if run from command line:
+if __name__ == '__main__':
+ from Cheetah.TemplateCmdLineIface import CmdLineIface
+ CmdLineIface(templateObj=master()).run()
+
+
diff --git a/cobbler/webui/webui-cgi.py b/cobbler/webui/webui-cgi.py
new file mode 100755
index 0000000..42387bd
--- /dev/null
+++ b/cobbler/webui/webui-cgi.py
@@ -0,0 +1,47 @@
+#!/usr/bin/env python
+
+import cgi
+import cgitb
+import wsgiref
+import os
+import sys
+from cobbler.webui.CobblerWeb import CobblerWeb
+
+def map_modes():
+ path = os.environ.get( 'PATH_INFO', 'index' )
+
+ if path.startswith('/'):
+ path = path[1:]
+ if path.endswith('/'):
+ path = path[:-1]
+
+ if path is '':
+ path = 'index'
+
+ return path
+
+def base_url():
+ return os.environ.get('SCRIPT_NAME', '')
+
+def main():
+ print "Content-type: text/html"
+ print
+
+ path = map_modes()
+ form = cgi.parse()
+
+ # ditch single-element arrays in the 'form' dictionary
+ # - may be bad for form elements that are sometimes lists and sometimes
+ # single items
+ for key,val in form.items():
+ if isinstance(val, list):
+ if len(val) == 1:
+ form[key] = val[0]
+
+ cw = CobblerWeb( server="http://localhost:25151", base_url=base_url() )
+
+ if path in cw.modes():
+ func = getattr( cw, path )
+ print func( **form )
+
+main()
diff --git a/cobbler/webui/webui-cherrypy3.py b/cobbler/webui/webui-cherrypy3.py
new file mode 100755
index 0000000..fff5e77
--- /dev/null
+++ b/cobbler/webui/webui-cherrypy3.py
@@ -0,0 +1,10 @@
+#!/usr/bin/env python
+
+from CobblerWeb import CobblerWeb
+import cherrypy
+
+cherrypy.tree.mount( CobblerWeb(server="http://localhost:25151", base_url=''), script_name='/', config='webui-cherrypy.cfg' )
+cherrypy.server.quickstart()
+cherrypy.engine.start()
+cherrypy.engine.block()
+