diff options
| author | makkalot <makkalot@gmail.com> | 2008-07-28 14:18:01 +0300 |
|---|---|---|
| committer | makkalot <makkalot@gmail.com> | 2008-07-28 14:18:01 +0300 |
| commit | 8746ffb25fc2c138e457489d38bce1a8cd92835c (patch) | |
| tree | 370514f3f40405c34ce5ce24d9ce17dddfa426a3 /funcweb | |
| parent | 6e47882e0dcb86e8b360dc17ac2541fe6875e55d (diff) | |
| parent | 391a052ccedb1195290aceeea500fc6aea86afdb (diff) | |
merge from new_layout to master
Diffstat (limited to 'funcweb')
42 files changed, 1430 insertions, 922 deletions
diff --git a/funcweb/etc/funcweb.conf b/funcweb/etc/funcweb.conf index 2b73eb7..0f8cf76 100644 --- a/funcweb/etc/funcweb.conf +++ b/funcweb/etc/funcweb.conf @@ -1,7 +1,7 @@ -NameVirtualHost 127.0.0.1:443 +NameVirtualHost localhost:443 -<VirtualHost 127.0.0.1:443> - ServerName 127.0.0.1 +<VirtualHost localhost:443> + ServerName localhost SSLEngine on SSLCertificateFile /etc/pki/tls/certs/localhost.crt SSLCertificateKeyFile /etc/pki/tls/private/localhost.key @@ -13,6 +13,8 @@ NameVirtualHost 127.0.0.1:443 ProxyPreserveHost On ProxyRequests Off #ProxyPass /static/ ! - ProxyPass / http://127.0.0.1:51236/ - ProxyPassReverse / http://127.0.0.1:51236/ + ProxyPass /tg_widgets http://127.0.0.1:51236/tg_widgets + ProxyPassReverse /tg_widgets http://127.0.0.1:51236/tg_widgets + ProxyPass /funcweb http://127.0.0.1:51236/funcweb + ProxyPassReverse /funcweb http://127.0.0.1:51236/funcweb </VirtualHost> diff --git a/funcweb/etc/funcweb_rotate b/funcweb/etc/funcweb_rotate new file mode 100644 index 0000000..864011b --- /dev/null +++ b/funcweb/etc/funcweb_rotate @@ -0,0 +1,12 @@ +/var/log/funcweb/server.log { + missingok + notifempty + rotate 4 + weekly + postrotate + if [ -f /var/lock/subsys/funcwebd ]; then + /etc/init.d/funcwebd condrestart + fi + endscript +} + diff --git a/funcweb/etc/prod.cfg b/funcweb/etc/prod.cfg index 91d8e3f..f766a42 100644 --- a/funcweb/etc/prod.cfg +++ b/funcweb/etc/prod.cfg @@ -45,22 +45,43 @@ tg.strict_parameters = True # Deployment independent log configuration is in funcweb/config/log.cfg [logging] +[[handlers]] +[[[error_out]]] +level='WARN' +class='FileHandler' +formatter='full_content' +args="('/var/log/funcweb/server.log','a+')" + +[[[debug_out]]] +class='FileHandler' +formatter='full_content' +args="('/var/log/funcweb/server.log','a+')" + + + +[[[access_out]]] +level='INFO' +class='FileHandler' +formatter='full_content' +args="('/var/log/funcweb/server.log','a+')" + + [[loggers]] [[[funcweb]]] level='DEBUG' qualname='funcweb' -handlers=['error_out'] +handlers=['debug_out'] [[[access]]] level='INFO' qualname='turbogears.access' -handlers=['error_out'] +handlers=['error_out','access_out'] propagate=0 [[[identity]]] level='INFO' qualname='turbogears.identity' -handlers=['error_out'] +handlers=['debug_out'] propagate=0 diff --git a/funcweb/funcweb.spec b/funcweb/funcweb.spec index 54c41a1..df5aee7 100644 --- a/funcweb/funcweb.spec +++ b/funcweb/funcweb.spec @@ -4,7 +4,7 @@ %define is_suse %(test -e /etc/SuSE-release && echo 1 || echo 0) %define version 0.1 -Summary: Web GUI for FUNC API +Summary: Web application for Func API Name: funcweb Source1: version Version: %(echo `awk '{ print $1 }' %{SOURCE1}`) @@ -20,6 +20,7 @@ Requires: certmaster >= 0.1 Requires: mod_ssl >= 2.0 Requires: httpd >= 2.0 Requires: TurboGears >= 1.0.4.2 +Requires: pam #the build requires BuildRequires: python-devel @@ -38,7 +39,7 @@ BuildArch: noarch Url: https://hosted.fedoraproject.org/projects/func/ %description -FuncWeb is the Web GUI management tool for commandline based tool func. +Web interface for managing systems controlled by Func %prep %setup -q @@ -55,10 +56,8 @@ rm -fr $RPM_BUILD_ROOT %files %defattr(-, root, root, -) -%if 0%{?fedora} >= 8 %dir %{python_sitelib}/funcweb*egg-info %{python_sitelib}/funcweb*egg-info/* -%endif #creating the directory structure %dir %{python_sitelib}/funcweb/ @@ -71,8 +70,10 @@ rm -fr $RPM_BUILD_ROOT %dir %{python_sitelib}/funcweb/static/javascript %dir %{python_sitelib}/funcweb/identity %dir %{_sysconfdir}/%{name} +%dir /var/log/funcweb %config(noreplace) %{_sysconfdir}/httpd/conf.d/funcweb.conf %config(noreplace) %{_sysconfdir}/%{name}/prod.cfg +%config(noreplace) /etc/logrotate.d/funcweb_rotate #adding the server startup shutdown thing /etc/init.d/funcwebd @@ -91,6 +92,7 @@ rm -fr $RPM_BUILD_ROOT %{python_sitelib}/funcweb/static/css/*.css %{python_sitelib}/funcweb/static/css/Makefile %{python_sitelib}/funcweb/static/images/*.png +%{python_sitelib}/funcweb/static/images/*.jpg %{python_sitelib}/funcweb/static/images/*.ico %{python_sitelib}/funcweb/static/images/*.gif %{python_sitelib}/funcweb/static/images/Makefile diff --git a/funcweb/funcweb/async_tools.py b/funcweb/funcweb/async_tools.py new file mode 100644 index 0000000..1d6e4ce --- /dev/null +++ b/funcweb/funcweb/async_tools.py @@ -0,0 +1,186 @@ +from func.overlord.client import Overlord +from func.jobthing import JOB_ID_RUNNING,JOB_ID_FINISHED,JOB_ID_LOST_IN_SPACE,JOB_ID_PARTIAL,JOB_ID_REMOTE_ERROR + +class AsyncResultManager(object): + """ + A class to check the async result updates,changes to + be able to display on UI + """ + + JOB_CODE_CHANGED = 1 + JOB_CODE_NEW = 2 + JOB_CODE_SAME = 3 + + pull_property_options = ('FINISHED','ERROR','NEW','CHANGED','RUNNING','PARTIAL') + + def __init__(self): + #we keep all the entries in memory it may seems + #that it will occuppy lots of space but all it has + #is job_id:code pairs with some status info : changed,new + #and etc all other stuff is kept in DB + #so if someone does 1000 async queries will occupy + #1000 * (integer*2) not big deal :) + #the format will be job_id : [code,status] + self.__current_list = {} + + #create a dummy Overlord object + self.fc = Overlord("*") + + def __get_current_list(self,check_for_change=False): + """ + Method returns back the current + list of the job_ids : result_code pairs + """ + changed = [] + tmp_ids = self.fc.open_job_ids() + for job_id,code in tmp_ids.iteritems(): + #is it a new code ? + if self.__current_list.has_key(job_id): + #the code is same no change occured + if self.__current_list[job_id][0] == code: + #print "I have that code %s no change will be reported"%job_id + self.__current_list[job_id][1] = self.JOB_CODE_SAME + else: + #we have change i db + #print "That is a change from %d to %d for %s"%(self.__current_list[job_id][0],code,job_id) + self.__current_list[job_id]=[code,self.JOB_CODE_CHANGED] + if check_for_change: + changed.append(job_id) + else: + # a new code was added + #print "A new code was added %s"%job_id + self.__current_list[job_id] = [code,self.JOB_CODE_NEW] + if check_for_change: + changed.append(job_id) + + #if true the db was updated and ours is outofdate + if len(self.__current_list.keys()) != len(tmp_ids.keys()): + self.__update_current_list(tmp_ids.keys()) + + #if we want to know if sth has changed + if check_for_change and changed: + return changed + + return None + + + def __update_current_list(self,tmp_db_hash): + """ + Synch the memory and local db + """ + for mem_job_id in self.__current_list.keys(): + if mem_job_id not in tmp_db_hash: + del self.__current_list[mem_job_id] + + + def check_for_changes(self): + """ + Method will be called by js on client side to check if something + interesting happened in db in "before defined" time interval + If have lots of methods running async that may take a while to finish + but user will not be interrupted about that situation ... + """ + tmp_ids = self.fc.open_job_ids() + should_check_change = False + for job_id,code in tmp_ids.iteritems(): + #check only the partials and others + if code == JOB_ID_RUNNING or code == JOB_ID_PARTIAL: + #that operation updates the db at the same time + try : + #print "The status from %s is %s in check_for_changes"%(job_id,self.fc.job_status(job_id)[0]) + tmp_code = self.fc.job_status(job_id)[0] + #should_check_change = True + except Exception,e: + print "Some exception in pulling the job_id_status",e + continue + #else: + # print "The job_id is not checked remotely :%s in check_for_changes and the code is %s"%(job_id,code) + + #if you thing there is sth to check interesting send it + #if should_check_change: + return self.__get_current_list(check_for_change=True) + + + + def select_from(self,pull_property): + """ + Gets only ones that matches to pull_property_options + """ + #may have some concurency problems ??? + code = None + status = None + #get the list of the finished jobs + if pull_property == self.pull_property_options[0]: + code = JOB_ID_FINISHED + #get the jobs that caused error + elif pull_property == self.pull_property_options[1]: + code = JOB_ID_REMOTE_ERROR + #get the jobs which are new + elif pull_property == self.pull_property_options[2]: + status = self.JOB_CODE_NEW + #the changed ones + elif pull_property == self.pull_property_options[3]: + status = self.JOB_CODE_CHANGED + #the running job ids + elif pull_property == self.pull_property_options[4]: + code = JOB_ID_RUNNING + #the partials + elif pull_property == self.pull_property_options[5]: + code = JOB_ID_PARTIAL + else: + #there is no case like that :) + return None + #now pull the list and return it back + final_list = [] + #print "The current list in the selct is :",self.__current_list + for job_id,code_status_pack in self.__current_list.iteritems(): + if code != None and code == code_status_pack[0]: + tmp_hash = {} + tmp_hash[job_id]=code_status_pack + + #print "To select %s with code %s"%(job_id,code) + final_list.append(tmp_hash) + elif status != None and code_status_pack[1] == status: + tmp_hash = {} + tmp_hash[job_id]=code_status_pack + final_list.append(tmp_hash) + + #get the final list here + return final_list + + def job_id_result(self,job_id): + """ + A simple wrapper around fc.job_status to get some to display + in the Web UI + """ + try: + result=self.fc.job_status(job_id) + except Exception,e: + print "Some exception in getting job_status" + return None + + return result + + def current_db(self): + """ + Just return back the private hash + """ + if not self.__current_list: + self.__get_current_list() + return self.__current_list + + def reset_current_list(self): + "Reset the list may need it sometimes :)" + self.__current_list = {} + + + def refresh_list(self): + """ + Simple one to checkout to prepopulate the current memory list + """ + self.__get_current_list() + + +if __name__ == "__main__": + pass + diff --git a/funcweb/funcweb/commands.py b/funcweb/funcweb/commands.py index cfd76d1..6d6d338 100644 --- a/funcweb/funcweb/commands.py +++ b/funcweb/funcweb/commands.py @@ -32,24 +32,19 @@ def start(): # 'prod.cfg' in the current directory and then for a default # config file called 'default.cfg' packaged in the egg. if exists("/etc/funcweb/prod.cfg"): - print "I use the production ito the etc !" configfile = "/etc/funcweb/prod.cfg" elif len(sys.argv) > 1: - print "We got something from the sys" configfile = sys.argv[1] elif exists(join(setupdir, "setup.py")): - print "I use the dev one into the dev dir" configfile = join(setupdir, "dev.cfg") elif exists(join(curdir, "prod.cfg")): - print "I use the prod one into the cur dir" configfile = join(curdir, "prod.cfg") else: try: configfile = pkg_resources.resource_filename( pkg_resources.Requirement.parse("funcweb"), "config/default.cfg") - print "That is another default conf" except pkg_resources.DistributionNotFound: raise ConfigurationError("Could not find default configuration.") @@ -64,5 +59,5 @@ def start(): try: turbogears.start_server(Root()) except Exception,e: - print "Exception occured :",e - sys.exit(1) + print "Debug information from cherrypy server ...: ",e + #sys.exit(1) diff --git a/funcweb/funcweb/config/app.cfg b/funcweb/funcweb/config/app.cfg index 336dc84..a33826c 100644 --- a/funcweb/funcweb/config/app.cfg +++ b/funcweb/funcweb/config/app.cfg @@ -80,7 +80,7 @@ identity.on=True # [REQUIRED] URL to which CherryPy will internally redirect when an access # control check fails. If Identity management is turned on, a value for this # option must be specified. -identity.failure_url="/login" +identity.failure_url="/funcweb/login" identity.provider='pam' @@ -125,10 +125,10 @@ identity.provider='pam' # gzip_filter.on = True # gzip_filter.mime_types = ["application/x-javascript", "text/javascript", "text/html", "text/css", "text/plain"] -[/static] +[/funcweb/static] static_filter.on = True static_filter.dir = "%(top_level_dir)s/static" -[/favicon.ico] +[/funcweb/favicon.ico] static_filter.on = True static_filter.file = "%(top_level_dir)s/static/images/favicon.ico" diff --git a/funcweb/funcweb/controllers.py b/funcweb/funcweb/controllers.py index b2748a6..2bdbe80 100644 --- a/funcweb/funcweb/controllers.py +++ b/funcweb/funcweb/controllers.py @@ -5,6 +5,8 @@ from turbogears import controllers, expose, flash, identity, redirect, error_han from func.overlord.client import Overlord, Minions from funcweb.widget_automation import WidgetListFactory,RemoteFormAutomation,RemoteFormFactory from funcweb.widget_validation import WidgetSchemaFactory +from funcweb.async_tools import AsyncResultManager +from func.jobthing import purge_old_jobs,JOB_ID_RUNNING,JOB_ID_FINISHED,JOB_ID_PARTIAL # it is assigned into method_display on every request global_form = None @@ -26,12 +28,12 @@ def validate_decorator_updater(validator_value=None): global global_form return global_form -class Root(controllers.RootController): - +class Funcweb(object): #preventing the everytime polling and getting #func = Overlord("name") thing func_cache={ 'fc_object':None,#the fc = Overlord() thing, + 'fc_async_obj':None, 'glob':None, 'minion_name':None, 'module_name':None, @@ -39,13 +41,16 @@ class Root(controllers.RootController): 'minions':None, 'methods':None } + async_manager = None + first_run = True #will be reused for widget validation - @expose(template="funcweb.templates.minions") + @expose(allow_json=True) @identity.require(identity.not_anonymous()) - def minions(self, glob='*'): + def minions(self, glob='*',submit=None): """ Return a list of our minions that match a given glob """ #make the cache thing + if self.func_cache['glob'] == glob: minions = self.func_cache['minions'] else: @@ -53,12 +58,16 @@ class Root(controllers.RootController): minions=Minions(glob).get_all_hosts() self.func_cache['glob']=glob self.func_cache['minions']=minions + + if not submit: + return dict(minions=minions,tg_template="funcweb.templates.index") + else: + return dict(minions=minions,tg_template="funcweb.templates.minions") - return dict(minions=minions) index = minions # start with our minion view, for now - @expose(template="funcweb.templates.minion") + @expose(template="funcweb.templates.modules") @identity.require(identity.not_anonymous()) def minion(self, name="*", module=None, method=None): """ Display module or method details for a specific minion. @@ -128,12 +137,12 @@ class Root(controllers.RootController): self.func_cache['methods'] = modules #display em return dict(modules=modules, module=module, - tg_template="funcweb.templates.module") + tg_template="funcweb.templates.methods") else: return "Wrong place :)" - @expose(template="funcweb.templates.method_args") + @expose(template="funcweb.templates.widgets") @identity.require(identity.not_anonymous()) def method_display(self,minion=None,module=None,method=None): """ @@ -210,9 +219,10 @@ class Root(controllers.RootController): "this resource.") else: msg=_("Please log in.") - forward_url= request.headers.get("Referer", "/") + forward_url= request.headers.get("Referer", ".") response.status=403 + return dict(message=msg, previous_url=previous_url, logging_in=True, original_parameters=request.params, forward_url=forward_url) @@ -277,13 +287,36 @@ class Root(controllers.RootController): cmd_args[index_of_arg]=kw[arg] #now execute the stuff - result = getattr(getattr(fc,module),method)(*cmd_args) + #at the final execute it as a multiple if the glob suits for that + #if not (actually there shouldnt be an option like that but who knows :)) + #it will run as a normal single command to clicked minion + if self.func_cache['glob']: + fc_async = Overlord(self.func_cache['glob'],async=True) + + result_id = getattr(getattr(fc_async,module),method)(*cmd_args) + result = "".join(["The id for current job is :",str(result_id)," You will be notified when there is some change about that command !"]) + + #that part gives a chance for short methods to finish their jobs and display them + #immediately so user will not wait for new notifications for that short thing + import time + time.sleep(4) + tmp_as_res = fc_async.job_status(result_id) + if tmp_as_res[0] == JOB_ID_FINISHED: + result = tmp_as_res[1] + + if not self.async_manager: + #cleanup tha database firstly + purge_old_jobs() + self.async_manager = AsyncResultManager() + self.async_manager.refresh_list() + + #TODO reformat that returning string to be more elegant to display :) return str(result) else: return "Missing arguments sorry can not proceess the form" - @expose(template="funcweb.templates.method_args") + @expose(template="funcweb.templates.result") @identity.require(identity.not_anonymous()) def execute_link(self,minion=None,module=None,method=None): """ @@ -291,21 +324,102 @@ class Root(controllers.RootController): arguments so they provide only some information,executed by pressing only the link ! """ - if self.func_cache['minion_name'] == minion: - fc = self.func_cache['fc_object'] + if self.func_cache['glob']: + fc = Overlord(self.func_cache['glob'],async = True) else: - fc = Overlord(minion) - self.func_cache['fc_object']=fc - self.func_cache['minion_name']=minion - #reset the children :) - self.func_cache['module_name']=module - self.func_cache['modules']=None - self.func_cache['methods']=None + if self.func_cache['minion_name'] == minion: + fc = self.func_cache['fc_async_obj'] + else: + fc = Overlord(minion,async = True) + self.func_cache['fc_async_obj']=fc + self.func_cache['minion_name']=minion + #reset the children :) + self.func_cache['module_name']=module + self.func_cache['modules']=None + self.func_cache['methods']=None - result = getattr(getattr(fc,module),method)() - return str(result) + #i assume that they are long enough so dont poll here + result_id = getattr(getattr(fc,module),method)() + result = "".join(["The id for current id is :",str(result_id)," You will be notified when there is some change about that command !"]) + return dict(result=str(result)) + @expose(format = "json") + @identity.require(identity.not_anonymous()) + def check_async(self,check_change = False): + """ + That method is polled by js code to see if there is some + interesting change in current db + """ + changed = False + if not check_change : + msg = "Method invoked with False parameter which makes it useless" + return dict(changed = False,changes = [],remote_error=msg) + + if not self.async_manager: + #cleanup tha database firstly + purge_old_jobs() + self.async_manager = AsyncResultManager() + changes = self.async_manager.check_for_changes() + if changes: + if not self.first_run: + changed = True + else: + self.first_run = False + + return dict(changed = changed,changes = changes) + + + @expose(template="funcweb.templates.result") + @identity.require(identity.not_anonymous()) + def check_job_status(self,job_id): + """ + Checking the job status for specific job_id + that method will be useful to see the results from + async_results table ... + """ + if not job_id: + return dict(result = "job id shouldn be empty!") + + if not self.func_cache['fc_async_obj']: + if self.func_cache['glob']: + fc_async = Overlord(self.func_cache['glob'],async=True) + #store also into the cache + else: + fc_async = Overlord("*",async=True) + + self.func_cache['fc_async_obj'] = fc_async + + else: + fc_async = self.func_cache['fc_async_obj'] + + id_result = fc_async.job_status(job_id) + + #the final id_result + return dict(result=id_result) + + @expose(template="funcweb.templates.async_table") + @identity.require(identity.not_anonymous()) + def display_async_results(self): + """ + Displaying the current db results that are in the memory + """ + if not self.async_manager: + #here should run the clean_old ids + purge_old_jobs() + self.async_manager = AsyncResultManager() + else: + #make a refresh of the memory copy + self.async_manager.refresh_list() + #get the actual db + func_db = self.async_manager.current_db() + + for job_id,code_status_pack in func_db.iteritems(): + parsed_job_id = job_id.split("-") + func_db[job_id].extend(parsed_job_id) + + #print func_db + return dict(func_db = func_db) @expose() def logout(self): @@ -314,3 +428,14 @@ class Root(controllers.RootController): """ identity.current.logout() raise redirect("/") + + + +class Root(controllers.RootController): + + @expose() + def index(self): + raise redirect("/funcweb") + + index = index # start with our minion view, for now + funcweb = Funcweb() diff --git a/funcweb/funcweb/identity/pam.py b/funcweb/funcweb/identity/pam.py index aed5420..87bc126 100644 --- a/funcweb/funcweb/identity/pam.py +++ b/funcweb/funcweb/identity/pam.py @@ -15,7 +15,7 @@ from ctypes import CDLL, POINTER, Structure, CFUNCTYPE, cast, pointer, sizeof from ctypes import c_void_p, c_uint, c_char_p, c_char, c_int -LIBPAM = CDLL("libpam.so") +LIBPAM = CDLL("libpam.so.0") LIBC = CDLL("libc.so.6") CALLOC = LIBC.calloc diff --git a/funcweb/funcweb/static/css/style.css b/funcweb/funcweb/static/css/style.css index 703e22e..15745c8 100644 --- a/funcweb/funcweb/static/css/style.css +++ b/funcweb/funcweb/static/css/style.css @@ -1,721 +1,532 @@ -* -{ - margin: 0; - padding: 0; -} - -html, body -{ - height: 100%; -} - -body -{ - color: #666666; - font-size: 80%; - background: #FFFFFF url(http://fedoraproject.org/static/images/border-left.png) 0 0 repeat-y; -} - -a img -{ - border: none; -} - -.wrapper -{ - margin-left: 18px; - font: normal 2.3ex/1.5 sans-serif; - min-height: 100%; - background: #FFFFFF url(http://fedoraproject.org/static/images/border-right.png) 100% 0 repeat-y; - padding-right: 18px; - overflow: auto; -} - -.head -{ - border-top: 10px solid #337ACC; - padding: 1ex 2ex 17px; - background: #FFFFFF url(http://fedoraproject.org/static/images/line.png) 0 100% repeat-x; -} - -.head h1 a -{ - display: block; - text-indent: -9999px; - /*background: url(http://fedoraproject.org/static/images/fedora-logo.png) 20px 50% no-repeat;*/ - height: 73px; - width: 138px; - overflow: hidden; -} - -#sidebar -{ - float: left; - width: 230px; - margin: 2ex 0; - background: #FFFFFF; - padding-bottom: 100px; -} - -#banner img -{ - display: block; - width: 200px; - margin: 0 3ex; -} - -#get -{ - text-align: center; - margin: 1ex 0.5ex; - font-weight: bold; -} - -#get ul -{ - font-weight: normal; - list-style: none; - display: inline; - font-size: 1.7ex; -} - -#get li -{ - display: inline; - border-left: 1px solid #CCCCCC; - margin-left: -1px; - padding: 0 1ex; -} - -#get li.first -{ - border-left: none; -} - -#get a -{ - color: #00356B; -} - -#nav -{ - margin: 0 1.5ex; - padding: 0 1.5ex; -} - -#nav h2 -{ - border-bottom: 1px dotted #AAAAAA; - color: #444444; - font-size: 1.725ex; - margin: 2ex 0 1ex; - text-transform: uppercase; - font-weight: normal; -} - -#nav ul -{ - list-style: url(http://fedoraproject.org/static/images/arrow.png); - margin-left: 15px; -} - -#nav li -{ - margin: 0.25ex 1ex; - color: #777777; - font-size: 1.4ex; -} - -#nav a -{ - font-weight: bold; - margin-right: 0.75ex; - color: #729FCF; - font-size: 2.4ex; - display: block; -} - -.home #nav-home a, .get #nav-get a, .join #nav-join a -{ - color: #777777; - text-decoration: none; -} - -.content -{ - margin-left: 0px; - margin-right: 10px; - color: #666666; - background: #FFFFFF; - display: inline-block; -} - -/* Blame IE6 and the guillotine bug for this one */ -.content { display: block; } - -.content h2 -{ - font-size: 3.25ex; -} - -.content h2 div { - font-size: 1ex; - font-weight: normal; -} - -.content h3 -{ - color: #337acc; - margin: 1.5ex 0 0.5ex; - font-size: 2.5ex; -} - -.content table -{ - border-collapse: collapse; -} - -.content table th -{ - background: #DDDDDD; -} - -.content table th, .content table td -{ - border: 1px solid #000000; - padding: 0.6ex; -} - -.content p -{ - margin: 1ex 5ex 1ex 0; -} - -.content ul -{ - list-style: square; - margin: 0 3ex 2ex; -} - -.content img -{ - margin: 2ex 0; -} - -.content a -{ - color: #337ACC; -} - -.download -{ - list-style-image: url(http://fedoraproject.org/static/images/arrow.png); - list-style-position: outside; - margin: 1.6ex 3ex; -} - -.download li -{ - color: #777777; - font-size: 1.8ex; - background: #EFEFEF; - padding: 1ex; - border-bottom: 1px dotted #AAAAAA; -} - -.download a -{ - font-weight: bold; -} - -.roles -{ - margin: 0!important; - list-style: none!important; - background: red; - display: inline; -} - -.roles li -{ - float: left; - margin-bottom: 0.5ex; -} - -.roles a -{ - line-height: 1; - width: 130px; - height: 150px; - text-align: center; - display: block; - text-decoration: none; -} - -.roles a:hover -{ - background-color: #EFEFEF; -} - -.roles img -{ -} - -#footer -{ - position: relative; - font: normal 1.5ex/1.5 sans-serif; - text-align: center; - background: #FFFFFF url(http://fedoraproject.org/static/images/line-bottom.png) 0 0 repeat-x; - margin: -90px 0 0; - border-bottom: 10px solid #337ACC; - height: 80px; - color: #AAAAAA; -} - -#bottom -{ - margin-left: 18px; - padding-right: 18px; -} - -#footer ul -{ - list-style: none; -} - -#footer li -{ - display: inline; - border-left: 1px solid #AAAAAA; - padding: 0 0.75ex; - margin-left: -1px; -} - -#footer li.first -{ - border-left: none; -} - -#footer a -{ - color: #223344; -} - -#footer a:hover -{ - color: #112233; -} - -#footer p -{ - margin: 0 1.5ex; -} - -#footer .copy -{ - padding-top: 3ex; -} - -#footer .disclaimer -{ -} - -#screenshot-banner a { - font-size: 1.6ex; - text-align: left; -} - -#screenshot-banner ul -{ - list-style: none; -} - -#screenshot-banner li -{ - display: inline; - margin-right: 2ex; -} - -#screenshot-banner img -{ - vertical-align: bottom; - border: 0; -} - -input, textarea, select -{ - border: #AAA 1px solid; -} - -input, textarea, option -{ - padding: 2px 5px 2px 5px; -} - -#content #sponsors -{ - list-style: none; - margin: 0; - padding: 0; - overflow: auto; -} - -#content #sponsors li -{ - text-align: center; - float: left; - width: 150px; - margin: 0 1ex; -} - -#content #sponsors li img -{ - display: block; -} - -#content ul.downloadbox -{ - overflow: hidden; - list-style: none; - margin: 0 2ex; - padding: 6ex 2ex 4ex 180px; - border-radius: 1.5ex; - -webkit-border-radius: 1.5ex; - -moz-border-radius: 1.5ex; - background: #C0DBDD 30px 50% no-repeat; - font-size: 1.7ex; - display: inline-block; -} - -#content ul.installdvd { background-image: url(http://fedoraproject.org/static/images/installdvd.png); } -#content ul.gnomelive { background-image: url(http://fedoraproject.org/static/images/gnomelive.png); } -#content ul.kdelive { background-image: url(http://fedoraproject.org/static/images/kdelive.png); } - -.downloadbox li -{ - width: 32ex; - float: left; - padding: 0 0 2ex; -} - -.downloadbox li li -{ - width: auto; - float: none; - padding: 0; -} - - -#content pre.command -{ - font-size: 2.25ex; - border: solid #DDDDDD; - border-width: 1px 1px 1px 5px; - background: #F2F5F6; - padding: 0.5ex 2ex; -} - - -#content p.note -{ - padding: 1ex 2ex; - font-size: 1.75ex; - border: 1px solid #DDDDDD; - background: #F2F5F6; -} - -#content ul#resources -{ - list-style: none; -} - -#content ul#resources a -{ - padding-left: 20px; - background: url(http://fedoraproject.org/static/images/arrow.png) 0 50% no-repeat; -} - -#content ul#resources li -{ - padding-left: 70px; - margin-bottom: 3.5ex; -} - -ul#resources li.resource-docs -{ - background: url(http://fedoraproject.org/static/images/icon-docs.png) 0 50% no-repeat; -} - -ul#resources li.resource-communicate -{ - background: url(http://fedoraproject.org/static/images/icon-communicate.png) 0 50% no-repeat; -} - -ul#resources li.resource-download -{ - background: url(http://fedoraproject.org/static/images/icon-download.png) 0 50% no-repeat; -} - - -#tabfloat { - right:25px; - position:absolute; - top:77px; - width:100%; - z-index:2; -} - -ul#primary-links { - list-style-type:none; - margin:0px; - padding:0px 0px 0px 255px; -} - -ul#primary-links li { - background:transparent url(http://fedoraproject.org/static/images/header-tab1.png) no-repeat scroll 0%; - float:right; - list-style-type:none; - margin:0px 0px; - padding:0px; -} - -ul#primary-links li a { - background:transparent url(http://fedoraproject.org/static/images/header-tab2.png) no-repeat scroll 100% 0px; - color: #666666; - display:block; - font-weight:bold; - font-size:larger; - height:33px; - list-style-type:none; - margin:0px; - padding:4px 20px 0px; - text-decoration:none; - white-space:nowrap; -} - -ul#primary-links li:hover { -background-image:url(/static/images/header-tab1.png); -background-position:0% -24px; -} -ul#primary-links li:hover a { -background-image:url(/static/images/header-tab2.png); -background-position:100% -24px; -} - -/*********** My Fedora Widget stuff *************/ - -.col { - margin: 10px - padding: 0 0 2ex; -} - -.downloadbox li li -{ - width: auto; - float: none; - padding: 0; -} - - -.content pre.command -{ - font-size: 2.25ex; - border: solid #DDDDDD; - border-width: 1px 1px 1px 5px; - background: #F2F5F6; - padding: 0.5ex 2ex; -} - -#results -{ - border: 1px solid #DDDDDD; - background: #F2F5F6; - font-size: 1.50ex; - width: 450px; - height: 400px; - overflow: auto; - display: none; -} - -.content p.note -{ - padding: 1ex 2ex; - font-size: 1.75ex; - border: 1px solid #DDDDDD; - background: #F2F5F6; -} - -.content ul#resources -{ - list-style: none; -} - -.content ul#resources a -{ - padding-left: 20px; - background: url(http://fedoraproject.org/static/images/arrow.png) 0 50% no-repeat; -} - -.content ul#resources li -{ - padding-left: 70px; - margin-bottom: 3.5ex; -} - -ul#resources li.resource-docs -{ - background: url(http://fedoraproject.org/static/images/icon-docs.png) 0 50% no-repeat; -} - -ul#resources li.resource-communicate -{ - background: url(http://fedoraproject.org/static/images/icon-communicate.png) 0 50% no-repeat; -} - -ul#resources li.resource-download -{ - background: url(http://fedoraproject.org/static/images/icon-download.png) 0 50% no-repeat; -} - - -#tabfloat { - right:25px; - position:absolute; - top:77px; - width:100%; - z-index:2; -} - -ul#primary-links { - list-style-type:none; - margin:0px; - padding:0px 0px 0px 255px; -} - -ul#primary-links li { - background:transparent url(/static/images/header-tab1.png) no-repeat scroll 0%; - float:right; - list-style-type:none; - margin:0px 0px; - padding:0px; -} - -ul#primary-links li a { - background:transparent url(/static/images/header-tab2.png) no-repeat scroll 100% 0px; - color: #666666; - display:block; - font-weight:bold; - font-size:larger; - height:33px; - list-style-type:none; - margin:0px; - padding:4px 20px 0px; - text-decoration:none; - white-space:nowrap; -} - -ul#primary-links li:hover { -background-image:url(/static/images/header-tab1.png); -background-position:0% -24px; -} -ul#primary-links li:hover a { -background-image:url(/static/images/header-tab2.png); -background-position:100% -24px; -} - -.mainsearch - { - top: 18px; - right: 28px; - z-index:2; - width: 300; - z-index:2; - position:absolute; -} - -/*********** My Fedora Widget stuff *************/ - -.col-group { - overflow: hidden; -} - -.col { - float: left; - margin: 30px; - padding: 0 0 2ex; - padding-bottom: 32767px; - margin-bottom: -32767px; - /*display: table-column; */ -} - -.col ul { - font-weight: normal; - list-style: none; - font-size: 1.7ex; -} - -.widget-list { - list-style: none; -} - -#col1 { - width: 150px; - height: 100%; -} - -#col2 { - width: 150px; -} - -#col3 { - width: 150px; -} - -#col4 { - width: 200px; - -} - -#col5 { - width: 200px; - margin-left: 500px; -} -.widget-list { - /*display: table-cell;*/ -} - -#col1 .widget { - border-width: 1px 1px 1px 1px; - border-spacing: 2px; - border-style: outset outset outset outset; - border-color: gray gray gray gray; - border-collapse: separate; - background-color: white; -} - -#col3 .widget { - border-width: 1px 1px 1px 1px; - border-spacing: 2px; - border-style: outset outset outset outset; - border-color: gray gray gray gray; - border-collapse: separate; - background-color: white; -} - - - -.widget h2 { - border-width: 1px 1px 1px 1px; - font-weight: bold; - text-align: center; -} - -#col2 .widget h2 { - text-align: left; -} - -.usernav { - margin-bottom: 10px; - text-align: right; -} +@charset "utf-8";
+
+
+#header {
+background-image:url(../images/header.jpg);
+background-repeat:no-repeat;
+height:89px;
+width: 900px;
+margin-left:auto;
+margin-right:auto;
+margin-top: 0px;
+display: block;
+overflow: hidden;
+padding-top: 0px;
+}
+
+#underheader {
+background-image:url(../images/line.png);
+background-repeat:repeat-x;
+height:17px;
+width:100%;
+}
+#container {
+width: 900px;
+margin-left:auto;
+margin-right:auto;
+}
+
+#minionglob {
+width:260px;
+float:right;
+height:50px;
+padding: 5px;
+font-size:18px;
+font-weight:bold;
+color: #666666;
+margin-right:2.2em;
+margin-left:2em;
+margin-top:5px;
+margin-bottom:5px;
+}
+
+.minionbox {
+background-color:#f2f5f6;
+border: 2px solid #dddddd;
+width:160px;
+height:20px;
+}
+#container {
+width:100%;
+margin-left:auto;
+margin-right:auto;
+}
+#minionsbigbox {
+background-color:#f7f7f7;
+min-height: 150px;
+width: 90%;
+padding:10px;
+border: 2px solid #dddddd;
+float:left;
+margin-left:30px;
+margin-right:30px;
+}
+#minions {
+background-color:#f1f5f6;
+max-height: 20px;
+min-width: 120px;
+margin-left: auto;
+margin-right: auto;
+margin-top: 1em;
+margin-bottom: 2px;
+padding:4px;
+border: 2px solid #dddddd;
+font-family: Arial, Helvetica, sans-serif;
+font-size:14px;
+color: #666666;
+text-decoration:none;
+}
+
+.minions {
+background-color:#f1f5f6;
+height:20px;
+min-width:200px;
+padding:10px;
+border: 2px solid #dddddd;
+margin-left:auto;
+margin-right:auto;
+}
+
+.graytexts {
+font-family: Arial, Helvetica, sans-serif;
+font-size:16px;
+font-weight:bold;
+color: #666666;
+}
+
+.graytexts2 {
+font-family: Arial, Helvetica, sans-serif;
+font-size:14px;
+font-weight:bold;
+color: #666666;
+}
+
+#minionstexts {
+float:left;
+margin-left: 4em;
+height:20px;
+max-width: 280px;
+margin-top: 2em;
+}
+
+.minionstextblue {
+font-family: Arial, Helvetica, sans-serif;
+font-size:18px;
+color: #5499d4;
+text-decoration:none;
+}
+.minionstextblue:link {
+font-family: Arial, Helvetica, sans-serif;
+font-size:18px;
+color: #5499d4;
+text-decoration:none;
+}
+.minionstextblue:hover {
+font-family: Arial, Helvetica, sans-serif;
+font-size:18px;
+color: #5499d4;
+text-decoration:underline;
+}
+#methodsbigbox {
+background-color:#f7f7f7;
+min-height: 150px;
+width: 90%;
+padding:10px;
+border: 2px solid #dddddd;
+float:left;
+margin-left:30px;
+margin-right:30px;
+}
+
+#modulesbigbox {
+background-color:#f7f7f7;
+min-height: 150px;
+width: 90%;
+padding:10px;
+border: 2px solid #dddddd;
+float:left;
+margin-left:30px;
+margin-right:30px;
+}
+
+#methodstextbox {
+float:left;
+margin-left: 4em;
+height:20px;
+max-width: 200px;
+margin-top: 2em;
+}
+
+#modulestexts {
+float:left;
+margin-left: 4em;
+height:20px;
+max-width: 200px;
+margin-top: 2em;
+}
+#widgetbgbox {
+background-color:#f7f7f7;
+min-height: 150px;
+width: 90%;
+padding:10px;
+border: 2px solid #dddddd;
+float:left;
+margin-left:30px;
+margin-right:30px;
+}
+#widgettext {
+float:left;
+margin-left: 4em;
+height:20px;
+max-width: 200px;
+margin-top: 2em;
+}
+.resultbigbox {
+background-color:#f7f7f7;
+min-height: 150px;
+width: 90%;
+padding:10px;
+border: 2px solid #dddddd;
+float:left;
+margin-left:30px;
+margin-right:30px;
+}
+#resultbox {
+background-color:#f1f5f6;
+overflow: auto;
+height: 300px;
+width: 900px;
+margin-left: auto;
+margin-right: auto;
+margin-top: 2em;
+margin-bottom: 2px;
+padding:4px;
+border: 2px solid #dddddd;
+font-family: Arial, Helvetica, sans-serif;
+font-size:14px;
+color: #666666;
+text-decoration:none;
+min-height: 250px;
+}
+
+#inwidgetbox {
+background-color:#f1f5f6;
+min-height: 150px;
+width: 900px;
+margin-left: auto;
+margin-right: auto;
+margin-top: 2em;
+margin-bottom: 2px;
+padding:4px;
+border: 2px solid #dddddd;
+font-family: Arial, Helvetica, sans-serif;
+font-size:14px;
+color: #666666;
+text-decoration:none;
+}
+.minionbutton {
+height:25px;
+width:80px;;
+background-image: url(../images/button.jpg);
+border: 0px;
+padding-bottom:5px;
+}
+.minionbutton:link {
+height:25px;
+width:80px;;
+background-image: url(../images/button.jpg);
+border: 0px;
+}
+.minionbutton:hover {
+height:25px;
+width:80px;;
+background-image: url(../images/button_over.jpg);
+border: 0px;
+}
+#errorbox {
+margin:5px;
+width:850px;
+min-height:100px;
+margin-left:auto;
+margin-right:auto;
+font-family: Arial, Helvetica, sans-serif;
+font-size:14px;
+color: #990000;
+font-weight:bold;
+text-decoration:none;
+}
+#widgetresult {
+margin:5px;
+width:850px;
+min-height:20px;
+margin-left:auto;
+margin-right:auto;
+}
+#minionglobtext {
+height:20px;
+width:90px;
+margin-left:8em;
+}
+#loadingimage {
+background-image:url(../images/LoadingGIF_2.gif);
+background-repeat:no-repeat;
+height: 50px;
+width: 50px;
+float:left;
+margin:2px;
+margin-top:1em;
+}
+.minioncontent {
+width:100%;
+min-height:200px;
+margin-left:10px;
+margin-right:10px;
+float:left;
+margin-top: 10px;
+margin-bottom: 2px;
+padding:5px;
+}
+#emptyimagebox {
+margin-left:2.5em;
+min-height:20px;
+width:60px;
+float:left;
+padding:1px;
+}
+#footer {
+background-image: url(../images/footer.jpg);
+background-repeat:no-repeat;
+height:50px;
+margin-left:auto;
+margin-right:auto;
+margin-top: 0px;
+width:900px;
+}
+#footercontent {
+width: 100%;
+float:left;
+}
+
+#widgetdescrition {
+margin:5px;
+width:850px;
+min-height:20px;
+margin-left:auto;
+margin-right:auto;
+}
+#globalerror {
+
+min-height:20px;
+margin:5px;
+width:900px;
+margin-left:auto;
+margin-right:1em;
+font-family: Arial, Helvetica, sans-serif;
+font-size:14px;
+color: #990000;
+font-weight:bold;
+text-decoration:none;
+border: 1px dashed #dddddd;
+padding:1px;
+}
+#globalerrorbig {
+
+min-height:40px;
+width:930px;
+margin-left:auto;
+margin-right:8em;
+
+}
+
+#runmethodbutton{
+height:50px;
+width:300px;
+float:left;
+margin-left:4em;
+}
+
+#runmethoddiv{
+height:55px;
+width:320px;
+float:left;
+margin-left:3em;
+}
+
+
+.runmethoddiv {
+height:25px;
+width:113px;;
+background-image: url(../images/button2.jpg);
+background-repeat:no-repeat;
+border: 0px;
+}
+.runmethoddiv:hover{
+height:25px;
+width:113px;;
+background-image: url(../images/button2_hover.jpg);
+background-repeat:no-repeat;
+border: 0px;
+}
+#tablecontent {
+}
+#tablebigbox {
+background-color:#F7F7F7;
+min-height: 150px;
+width: 90%;
+padding:10px;
+border: 2px solid #dddddd;
+float:left;
+margin-left:30px;
+margin-right:30px;
+}
+
+#tablebox {
+background-color:#f1f5f6;
+overflow: auto;
+min-height: 150px;
+width: 900px;
+margin-left: auto;
+margin-right: auto;
+margin-top: 2em;
+margin-bottom: 2px;
+padding:4px;
+border: 2px solid #dddddd;
+font-family: Arial, Helvetica, sans-serif;
+font-size:14px;
+color: #666666;
+text-decoration:none;
+}
+.column {
+min-height:25px;
+width:177px;
+border: 1px solid #dddddd;
+float:left;
+}
+
+.tableboxes {
+width:170px;
+border: 2px solid #dddddd;
+background-color:#f1f5f6;
+}
+
+.navlinks {
+display:block;
+height:30px;
+min-width:90px;
+font-family: Arial, Helvetica, sans-serif;
+font-size:14px;
+color: #666666;
+font-weight:bold;
+text-decoration:none;
+padding-top:5px;
+padding-left:1em;
+padding-right:1em;
+float:left;
+}
+
+.navlinks:hover {
+background:#FFFFFF;
+display:block;
+height:30px;
+min-width:90px;
+font-weight:bold;
+font-family: Arial, Helvetica, sans-serif;
+font-size:14px;
+color: #6CACE9;
+font-weight:bold;
+text-decoration:none;
+padding-top:5px;
+float:left;
+padding-left:1em;
+padding-right:1em;
+}
+
+.lines{
+display:block;
+height:30px;
+font-family: Arial, Helvetica, sans-serif;
+font-size:14px;
+color: #666666;
+font-weight:bold;
+text-decoration:none;
+padding:5px;
+float:left;
+}
+
+#menudiv {
+background-image:url(../images/menuimg.jpg);
+background-repeat:repeat-x;
+height:30px;
+width:100%;
+}
+
+#navigaton {
+width:100%;
+height:30px;
+float:left;
+margin-left:8em;
+}
+
+.intabletext {
+font-family: Arial, Helvetica, sans-serif;
+font-size:14px;
+color: #666666;
+text-decoration:none;
+}
+#newico {
+height:30px;
+width:41px;
+background-image:url(../images/new.gif);
+background-repeat:no-repeat;
+margin-left:auto;
+margin-right:auto;
+}
+#changedimg {
+height:30px;
+width:41px;
+margin-left:auto;
+margin-right:auto;
+background-image: url(../images/changed.gif);
+background-repeat:no-repeat;
+
+}
+
+
+a{
+font-family: Arial, Helvetica, sans-serif;
+font-size:16px;
+color: #5499d4;
+text-decoration:none;
+
+}
+
+table
+{
+ border-collapse: collapse;
+}
+
+table th
+{
+ background: #DDDDDD;
+}
+
+table th,table td
+{
+ border: 1px solid #000000;
+ padding: 0.6ex;
+}
+
+p
+{
+ margin: 1ex 5ex 1ex 0;
+}
+
+input, textarea, select
+{
+ border: #AAA 1px solid;
+}
+
+input, textarea, option
+{
+ padding: 2px 5px 2px 5px;
+}
diff --git a/funcweb/funcweb/static/images/LoadingGIF_2.gif b/funcweb/funcweb/static/images/LoadingGIF_2.gif Binary files differnew file mode 100644 index 0000000..fb5675d --- /dev/null +++ b/funcweb/funcweb/static/images/LoadingGIF_2.gif diff --git a/funcweb/funcweb/static/images/button.jpg b/funcweb/funcweb/static/images/button.jpg Binary files differnew file mode 100644 index 0000000..8ec7e04 --- /dev/null +++ b/funcweb/funcweb/static/images/button.jpg diff --git a/funcweb/funcweb/static/images/button2.jpg b/funcweb/funcweb/static/images/button2.jpg Binary files differnew file mode 100644 index 0000000..207d4db --- /dev/null +++ b/funcweb/funcweb/static/images/button2.jpg diff --git a/funcweb/funcweb/static/images/button2_hover.jpg b/funcweb/funcweb/static/images/button2_hover.jpg Binary files differnew file mode 100644 index 0000000..f2a0473 --- /dev/null +++ b/funcweb/funcweb/static/images/button2_hover.jpg diff --git a/funcweb/funcweb/static/images/button_over.jpg b/funcweb/funcweb/static/images/button_over.jpg Binary files differnew file mode 100644 index 0000000..cdf6cd0 --- /dev/null +++ b/funcweb/funcweb/static/images/button_over.jpg diff --git a/funcweb/funcweb/static/images/changed.gif b/funcweb/funcweb/static/images/changed.gif Binary files differnew file mode 100644 index 0000000..250a211 --- /dev/null +++ b/funcweb/funcweb/static/images/changed.gif diff --git a/funcweb/funcweb/static/images/footer.jpg b/funcweb/funcweb/static/images/footer.jpg Binary files differnew file mode 100644 index 0000000..ccb14cc --- /dev/null +++ b/funcweb/funcweb/static/images/footer.jpg diff --git a/funcweb/funcweb/static/images/header.jpg b/funcweb/funcweb/static/images/header.jpg Binary files differnew file mode 100644 index 0000000..5583d83 --- /dev/null +++ b/funcweb/funcweb/static/images/header.jpg diff --git a/funcweb/funcweb/static/images/line.png b/funcweb/funcweb/static/images/line.png Binary files differnew file mode 100644 index 0000000..79d2ef7 --- /dev/null +++ b/funcweb/funcweb/static/images/line.png diff --git a/funcweb/funcweb/static/images/menuimg.jpg b/funcweb/funcweb/static/images/menuimg.jpg Binary files differnew file mode 100644 index 0000000..d3e232a --- /dev/null +++ b/funcweb/funcweb/static/images/menuimg.jpg diff --git a/funcweb/funcweb/static/images/menuimghover.jpg b/funcweb/funcweb/static/images/menuimghover.jpg Binary files differnew file mode 100644 index 0000000..415cff1 --- /dev/null +++ b/funcweb/funcweb/static/images/menuimghover.jpg diff --git a/funcweb/funcweb/static/images/new.gif b/funcweb/funcweb/static/images/new.gif Binary files differnew file mode 100644 index 0000000..4bea887 --- /dev/null +++ b/funcweb/funcweb/static/images/new.gif diff --git a/funcweb/funcweb/static/javascript/ajax.js b/funcweb/funcweb/static/javascript/ajax.js index 7df4749..b54ed7a 100644 --- a/funcweb/funcweb/static/javascript/ajax.js +++ b/funcweb/funcweb/static/javascript/ajax.js @@ -1,3 +1,26 @@ +function addDomAjaxREsult(){ + + //just creates the sturctore that is in result.html + if (getElement('resultbox')==null){ + var result_header = DIV({'align':'center','class':'graytexts'}); + result_header.innerHTML = "Result"; + var minions = DIV({'class':'minions','id':'minions'},result_header); + var results = DIV({'class':'resultbox','id':'resultbox'}); + var main = DIV( + {'class':'resultbigbox','id':'resultbigbox'}, + minions, + results + ); + + //adding those to main part .. + var result_container=getElement("resultcontent"); + appendChildNodes(result_container,main); + } + else + getElement('resultbox').innerHTML = ""; +} + + function remoteFormRequest(form, target, options) { var query = Array(); var contents = formContents(form); diff --git a/funcweb/funcweb/static/javascript/async_tools.js b/funcweb/funcweb/static/javascript/async_tools.js new file mode 100644 index 0000000..f96ebd2 --- /dev/null +++ b/funcweb/funcweb/static/javascript/async_tools.js @@ -0,0 +1,35 @@ +function poll_async_changes(result){ + + /** + * Simple method that calls another to check the async results + */ + + //runs on the index page and polls the server side if there is new + //change in the async db + if (result['changed']==true){ + //alert('Check it '); + var the_change_msg = "We have some async changes : "; + the_change_msg = the_change_msg + repr(result['changes'])+" check the <a href='/funcweb/display_async_results'>RESULTS</a> page!"; + getElement('globalerror').innerHTML = the_change_msg; + window.setTimeout('check_async_change()',50000); + } + else + window.setTimeout('check_async_change()',50000); +} + +function check_async_change(){ + /** + * Method that sends the xmlhttp request to check the changes + */ + d = loadJSONDoc("/funcweb/check_async?"+queryString( + { + 'check_change':true + } + )); + d.addCallback(poll_async_changes); + +} + +function poll_error(error){ + alert("Some error in xmlHttpRequest check your connection : "); +} diff --git a/funcweb/funcweb/templates/async_table.html b/funcweb/funcweb/templates/async_table.html new file mode 100644 index 0000000..ca8849d --- /dev/null +++ b/funcweb/funcweb/templates/async_table.html @@ -0,0 +1,48 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" + xmlns:py="http://genshi.edgewall.org/" + xmlns:xi="http://www.w3.org/2001/XInclude"> + <xi:include href="master.html"/> + <head/> + <body onLoad = "window.setTimeout('check_async_change()',10000);"> + + <div class="minioncontent" id="tablecontent"> + <div id="tablebigbox"> + <div class="graytexts" id="tablename"> + <div align="center">Async Call Result Table</div> + </div> + <div class="tablebox" id="tablebox"> + <table width="900" align="center" cellpadding="1" cellspacing="3" bordercolor="#DDDDDD" bgcolor="#F1F5F6"> + <tr> + <td width="180" class="tableboxes"><div align="center" class="graytexts">Glob</div></td> + <td width="180" class="tableboxes"><div align="center" class="graytexts">Module</div></td> + <td width="180" class="tableboxes"><div align="center" class="graytexts">Method</div></td> + <td width="180" class="tableboxes"><div align="center" class="graytexts">Job id</div></td> + <td width="180" class="tableboxes"><div align="center" class="graytexts">Job status</div></td> + </tr> + <tr py:for="job_id,job_pack in func_db.iteritems()"> + <td class="tableboxes"><p class="intabletext">${job_pack[2]}</p></td> + <td class="tableboxes"><p class="intabletext">${job_pack[3]}</p></td> + <td class="tableboxes"><p class="intabletext">${job_pack[4]}</p></td> + <td class="tableboxes"><p class="intabletext">${job_id}</p></td> + <td class="tableboxes"> + <div class="newico" id="newico" py:if="job_pack[1] == 2"></div> + <div class="changedimg" id="changedimg" py:if="job_pack[1] == 1"></div> + <span py:if="job_pack[0] == 0"><a href="#resultcontent" onclick="myj('#resultcontent').hide().load('/funcweb/check_job_status/${job_id}').show('slow');">RUNNING</a></span> + <span py:if="job_pack[0] == 1"><a href="#resultcontent" onclick="myj('#resultcontent').hide().load('/funcweb/check_job_status/${job_id}').show('slow');">FINISHED</a></span> + <span py:if="job_pack[0] == 3"><a href="#resultcontent" onclick="myj('#resultcontent').hide().load('/funcweb/check_job_status/${job_id}').show('slow');">PARTIAL</a></span> + <span py:if="job_pack[0] == 4"><a href="#resultcontent" onclick="myj('#resultcontent').hide().load('/funcweb/check_job_status/${job_id}').show('slow');">ERROR</a></span> + + </td> + </tr> + </table> + </div> + </div> + </div> + + + <div class="minioncontent" id="resultcontent"></div> + <a name="resultcontent"/> + +</body> +</html> diff --git a/funcweb/funcweb/templates/index.html b/funcweb/funcweb/templates/index.html new file mode 100644 index 0000000..87c446e --- /dev/null +++ b/funcweb/funcweb/templates/index.html @@ -0,0 +1,49 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" + xmlns:py="http://genshi.edgewall.org/" + xmlns:xi="http://www.w3.org/2001/XInclude"> + <xi:include href="master.html"/> + <head/> + <body onLoad = "window.setTimeout('check_async_change()',10000);"> + + <div class="minionglob" id="minionglob"> + <form action="/funcweb/minions" method="post" onsubmit="return !remoteFormRequest(this, 'minioncontent', {"loading": null, "confirm": null, "after": null, "on_complete": null, "loaded": null, "on_failure": null, "on_success": null, "before":"myj('#resultcontent').hide();myj('#widgetcontent').hide();myj('#methotdscontent').hide();myj('#modulescontent').hide();"});" class="tableform" name="minion_form"> + + <div class="graytexts2" id="minionglobtext"> + <div align="center">Minion Glob</div> + </div> + <input name="submit" type="submit" class="minionbutton" id="button" value="submit" border="0"/> + <input name="glob" type="text" class="minionbox" id="textfield" /> + </form> + </div> + + + <div class="emptyimagebox" id="emptyimagebox"></div> + <div class="minioncontent" id="minioncontent"> + <div class="minionsbigbox" id="minionsbigbox" py:if="minions"> + <div align="center" class="graytexts">Mininons</div> + <div id="minionstexts" py:for="minion in minions"> + <a onclick="myj('#resultcontent').hide();myj('#widgetcontent').hide();myj('#methotdscontent').hide();myj('#modulescontent').hide().load('/funcweb/minion/${minion}').show('slow');" href="#modulescontent" class="minionstextblue">${minion}</a> + </div> + </div> + <div class="errorbox" id="errorbox" py:if="not minions">There is no minion to display with that glob, try something different</div> + </div> + + <div class="emptyimagebox" id="emptyimagebox"></div> + <div class="minioncontent" id="modulescontent"></div> + <a name="modulescontent"/> + + <div class="emptyimagebox" id="emptyimagebox"></div> + <div class="minioncontent" id="methotdscontent"></div> + <a name="methotdscontent"/> + + <div class="emptyimagebox" id="emptyimagebox"></div> + <div class="minioncontent" id="widgetcontent"></div> + <a name="widgetcontent"/> + + <div class="emptyimagebox" id="emptyimagebox"></div> + <div class="minioncontent" id="resultcontent"></div> + <a name="resultcontent"/> + +</body> +</html> diff --git a/funcweb/funcweb/templates/master.html b/funcweb/funcweb/templates/master.html index 0ac8ebb..0b5bcae 100644 --- a/funcweb/funcweb/templates/master.html +++ b/funcweb/funcweb/templates/master.html @@ -8,23 +8,20 @@ py:replace="''" /> <title py:content="'Your Title Goes Here'"></title> - <script type="text/javascript" src="${tg.url('/static/javascript/jquery.js')}" /> + <script type="text/javascript" src="${tg.url('/funcweb/static/javascript/jquery.js')}" /> <link py:for="js in tg_js_head" py:strip="">${ET(js.display())}</link> <link py:for="css in tg_css" py:strip="">${ET(css.display())}</link> - <script type="text/javascript" src="${tg.url('/static/javascript/ajax.js')}" /> + <script type="text/javascript" src="${tg.url('/funcweb/static/javascript/ajax.js')}" /> - <link href="${tg.url('/static/images/favicon.ico')}" - type="image/vnd.microsoft.icon" rel="shortcut icon" /> - <link href="${tg.url('/static/images/favicon.ico')}" - type="image/x-icon" rel="shortcut icon"/> <style type="text/css" media="screen"> - @import url("/static/css/style.css"); + @import url("/funcweb/static/css/style.css"); </style> - <link media="screen" href="/static/css/expanding_form.css" type="text/css" rel="stylesheet"/> - <script src="../static/javascript/expanding_form.js" type="text/javascript"></script> - + <link media="screen" href="/funcweb/static/css/expanding_form.css" type="text/css" rel="stylesheet"/> + <script src="${tg.url('/funcweb/static/javascript/expanding_form.js')}" type="text/javascript"/> + <script src="${tg.url('/funcweb/static/javascript/async_tools.js')}" type="text/javascript"/> + <script type="text/javascript"> jQuery._$ = MochiKit.DOM.getElement; var myj = jQuery.noConflict(); @@ -33,37 +30,32 @@ </head> <body py:match="body" py:attrs="select('@*')"> <div py:for="js in tg_js_bodytop" py:replace="ET(js.display())" /> - <div class="wrapper"> - <div class="head"> - <h1><a href="http://fedorahosted.org/func">Func</a></h1> - <div class="mainsearch"> - <form action="${tg.url('/search')}" method="get"> - <input type="text" name="search" /> - </form> + + <div class="header" id="header"></div> + <div class="underheader" id="underheader"></div> + <div id="menudiv"> + <div class="navgation" id="navigaton"> + <span class="lines">|</span><a href="/funcweb/" class="navlinks">Home</a><span class="lines">|</span><a href="/funcweb/display_async_results" class="navlinks">Async Results</a><span class="lines">|</span> </div> - </div> - <div class="content"> - <!-- - <div py:if="tg.config('identity.on',False) and not 'logging_in' in locals()" id="pageLogin" class="usernav"> - <span py:if="tg.identity.anonymous"> - You are not logged in yet <a class="loginButton" href="${tg.url('/login/')}">login</a> - </span> - <span py:if="not tg.identity.anonymous"> - <a href="${tg.url('/users/info/')}">profile</a> | - <a class="loginButton" href="${tg.url('/logout/')}">logout</a> - </span> + </div> + + + <div class="container" id="container"> + + + <div class="globalerrorbig" id="globalerrorbig"> + <div class="globalerror" id="globalerror"></div> </div> - --> <div py:replace="select('*|text()')" /> - </div> - </div> - <div id="bottom"> - <div id="footer"> - <img src="${tg.url('/static/images/under_the_hood_blue.png')}"/> - <center> - Powered by <a href="http://fedorahosted.org/func">func</a>. - </center> - </div> + + + <div class="footercontent" id="footercontent"> + <div class="footer" id="footer"></div> + </div> + </div> + + + </body> </html> diff --git a/funcweb/funcweb/templates/method.html b/funcweb/funcweb/templates/method.html deleted file mode 100644 index af20d86..0000000 --- a/funcweb/funcweb/templates/method.html +++ /dev/null @@ -1,18 +0,0 @@ -<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> -<html xmlns="http://www.w3.org/1999/xhtml" - xmlns:py="http://genshi.edgewall.org/" - xmlns:xi="http://www.w3.org/2001/XInclude"> - - -<body> - <div class="method"> - ${minion}.${module}.${method} - - <form action="" method="GET" onsubmit="myj('#results').hide().load('/run/${minion}/${module}/${method}/').show('slow'); return false;"> - <input type="text" name="arguments" id="methodargs" class="methodargs"/> - </form> - <div class="results" id="results" /> - - </div> -</body> -</html> diff --git a/funcweb/funcweb/templates/method_args.html b/funcweb/funcweb/templates/method_args.html deleted file mode 100644 index 870d562..0000000 --- a/funcweb/funcweb/templates/method_args.html +++ /dev/null @@ -1,17 +0,0 @@ -<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> -<html xmlns="http://www.w3.org/1999/xhtml" - xmlns:py="http://genshi.edgewall.org/" - xmlns:xi="http://www.w3.org/2001/XInclude"> - -<body> - <div py:if="minion_form" id="men"> - <p py:if="description">Description : ${description}</p> - ${ET(minion_form.display(displays_on='genshi'))} - </div> - <div py:if="not minion_form" id="men"> - <a href="#" onclick="myj('#results').hide().load('/execute_link/${minion}/${module}/${method}/').show('slow');">Run Method</a> - <div class="results" id="results" /> - </div> -</body> -</html> - diff --git a/funcweb/funcweb/templates/methods.html b/funcweb/funcweb/templates/methods.html new file mode 100644 index 0000000..9f06cbb --- /dev/null +++ b/funcweb/funcweb/templates/methods.html @@ -0,0 +1,16 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" + xmlns:py="http://genshi.edgewall.org/" + xmlns:xi="http://www.w3.org/2001/XInclude"> + +<body> + <div class="methodsbigbox" id="methodsbigbox"> + <span py:for="minion, methods in modules.items()"> + <div align="center" class="graytexts">${minion}.${module}</div> + <div class="minionstextblue" id="methodstextbox" py:for="method in methods"> + <a href="#widgetcontent" onclick="myj('#resultcontent').hide();myj('#widgetcontent').hide().load('/funcweb/method_display/${minion}/${module}/${method}').show('slow')" class="minionstextblue">${method}</a> + </div> + </span> + </div> +</body> +</html> diff --git a/funcweb/funcweb/templates/minion.html b/funcweb/funcweb/templates/minion.html deleted file mode 100644 index a526764..0000000 --- a/funcweb/funcweb/templates/minion.html +++ /dev/null @@ -1,16 +0,0 @@ -<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> -<html xmlns="http://www.w3.org/1999/xhtml" - xmlns:py="http://genshi.edgewall.org/" - xmlns:xi="http://www.w3.org/2001/XInclude"> - -<body> - <div id="modules" class="modules"> - <ul py:for="minion, mods in modules.items()"> - <h2>${minion[:13]}</h2> - <li py:for="module in mods"> - <a href="#" onclick="myj('#col5').hide();myj('#col3').hide().load('/minion/${minion}/${module}').show('slow');">${module}</a> - </li> - </ul> - </div> -</body> -</html> diff --git a/funcweb/funcweb/templates/minions.html b/funcweb/funcweb/templates/minions.html index 1db0f38..08863e8 100644 --- a/funcweb/funcweb/templates/minions.html +++ b/funcweb/funcweb/templates/minions.html @@ -2,22 +2,15 @@ <html xmlns="http://www.w3.org/1999/xhtml" xmlns:py="http://genshi.edgewall.org/" xmlns:xi="http://www.w3.org/2001/XInclude"> - <xi:include href="master.html"/> - <head/> -<body> - <div class="col-group"> - <div class="col" id="col1"> - <ul> - <li><h2>minions</h2></li> - <li py:for="minion in minions"> - <a onclick="jQuery('#col3').hide();myj('#col4').hide();myj('#col5').hide();getElement('col2').innerHTML=toHTML(IMG({src:'../static/images/loading.gif',width:'100',height:'100'}));myj('#col2').hide().load('/minion/${minion}').show('slow');" href="#">${minion}</a> - </li> - </ul> - </div> - <div class="col" id="col2" /> - <div class="col" id="col3" /> - <div class="col" id="col4" /> - <div class="col" id="col5" /> - </div> -</body> -</html> + <head/> + <body> + <div class="minionsbigbox" id="minionsbigbox" py:if="minions"> + <div align="center" class="graytexts">Minions</div> + <div id="minionstexts" py:for="minion in minions"> + <a onclick="myj('#resultcontent').hide();myj('#widgetcontent').hide();myj('#methotdscontent').hide();myj('#modulescontent').hide().load('/funcweb/minion/${minion}').show('slow');" href="#modulescontent" class="minionstextblue">${minion}</a> + </div> + </div> + <div class="errorbox" id="errorbox" py:if="not minions">There is no minion to display with that glob, try something different</div> + + </body> + </html> diff --git a/funcweb/funcweb/templates/module.html b/funcweb/funcweb/templates/module.html deleted file mode 100644 index a4794d0..0000000 --- a/funcweb/funcweb/templates/module.html +++ /dev/null @@ -1,15 +0,0 @@ -<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> -<html xmlns="http://www.w3.org/1999/xhtml" - xmlns:py="http://genshi.edgewall.org/" - xmlns:xi="http://www.w3.org/2001/XInclude"> -<body> - <div id="module" class="module"> - <ul py:for="minion, methods in modules.items()"> - <h2>${module}</h2> - <li py:for="method in methods"> - <a href="#" onclick="myj('#col2').hide();myj('#col5').hide().show('slow');myj('#col4').hide().load('/method_display/${minion}/${module}/${method}').show('slow')">${method}</a> - </li> - </ul> - </div> -</body> -</html> diff --git a/funcweb/funcweb/templates/modules.html b/funcweb/funcweb/templates/modules.html new file mode 100644 index 0000000..2d8107b --- /dev/null +++ b/funcweb/funcweb/templates/modules.html @@ -0,0 +1,16 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" + xmlns:py="http://genshi.edgewall.org/" + xmlns:xi="http://www.w3.org/2001/XInclude"> +<body> + <div class="modulesbigbox" id="modulesbigbox"> + <span py:for="minion, modules in modules.items()"> + <div align="center" class="graytexts">${minion}</div> + + <div class="modulestexts" id="modulestexts" py:for="module in modules"> + <a href="#methotdscontent" class="minionstextblue" onclick="myj('#widgetcontent').hide();myj('#resultcontent').hide();myj('#methotdscontent').hide().load('/funcweb/minion/${minion}/${module}').show('slow')">${module}</a> + </div> + </span> + </div> +</body> +</html> diff --git a/funcweb/funcweb/templates/run.html b/funcweb/funcweb/templates/result.html index 7ae047b..7c3d6d1 100644 --- a/funcweb/funcweb/templates/run.html +++ b/funcweb/funcweb/templates/result.html @@ -2,8 +2,12 @@ <html xmlns="http://www.w3.org/1999/xhtml" xmlns:py="http://genshi.edgewall.org/" xmlns:xi="http://www.w3.org/2001/XInclude"> - <body> - ${results.values()[0]} +<body> + <div class="resultbigbox" id="resultbigbox"> + <div align="center" class="graytexts">Result</div> + <div class="resultbox" id="resultbox">${result}</div> + </div> </body> </html> + diff --git a/funcweb/funcweb/templates/widgets.html b/funcweb/funcweb/templates/widgets.html new file mode 100644 index 0000000..d898134 --- /dev/null +++ b/funcweb/funcweb/templates/widgets.html @@ -0,0 +1,28 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" + xmlns:py="http://genshi.edgewall.org/" + xmlns:xi="http://www.w3.org/2001/XInclude"> + +<body> + <div class="widgetbgbox" id="widgetbgbox"> + <div align="center" class="graytexts">${method}</div> + <div class="inwidgetbox" id="inwidgetbox"> + <div class="widgetdescrition" id="widgetdescrition" py:if="description" align="center">Description :${description}</div> + <div class="widgetresult" id="widgetresult" align="center"> + <span py:if="minion_form"> + ${ET(minion_form.display(displays_on='genshi'))} + </span> + <span py:if="not minion_form"> + <a href="#resultcontent" onclick="myj('#resultcontent').hide().load('/funcweb/execute_link/${minion}/${module}/${method}/').show('slow');">Run Method</a> + </span> + </div> + <div class="errorbox" id="errorbox"> + </div> + </div> + </div> + +</body> +</html> + + + diff --git a/funcweb/funcweb/tests/bork.py b/funcweb/funcweb/tests/bork.py new file mode 100644 index 0000000..45631f7 --- /dev/null +++ b/funcweb/funcweb/tests/bork.py @@ -0,0 +1,37 @@ +from func.overlord.client import Overlord +from func.jobthing import * +import time + + +print "Now running one with getattr " +module = "echo" +method = "run_int" + +fc_new = Overlord("*",async = True) +new_job_id = getattr(getattr(fc_new,module),method)(500) +code_status = fc_new.job_status(new_job_id)[0] + +print "The code status is : ",code_status + +while code_status != JOB_ID_FINISHED: + print "Waiting the run_int to finish " + code_status = fc_new.job_status(new_job_id)[0] + time.sleep(2) +print "The int operation is finished" + + + +print "Creating the object" +fc = Overlord("*",async = True) +job_id = fc.echo.run_string("Merhaba") +code_status = fc.job_status(job_id)[0] + +print "The code status is : ",code_status + +while code_status != JOB_ID_FINISHED: + print "Waiting the run_string to finish " + code_status = fc.job_status(job_id)[0] + time.sleep(2) +print "The run_string was finished" + + diff --git a/funcweb/funcweb/tests/test_async_tools.py b/funcweb/funcweb/tests/test_async_tools.py new file mode 100644 index 0000000..7af53ba --- /dev/null +++ b/funcweb/funcweb/tests/test_async_tools.py @@ -0,0 +1,176 @@ +from funcweb.async_tools import AsyncResultManager +from func.overlord.client import Overlord +from func.jobthing import * +import unittest + +class AsyncResultManagerTest(object): + + def setUp(self): + self.fc = Overlord("*") + self.async_manager = AsyncResultManager() + + def get_current_list_test(self): + #that is tested in test_current_db + pass + + def update_current_list_test(self): + pass + + + def check_for_changes_test(self): + print "***** Testing check_for_changes *****" + self.reset_stuff() + #now make a new entry into database to have a only one + #new entry in the db ... + #running a new command which is a short one + new_fc = Overlord("*",async=True) + new_job_id=new_fc.test.add(1,2) + #print "The job id we got is :",new_job_id + changes = self.async_manager.check_for_changes() + print "The latest Changes for add method are :",changes + assert len(changes) == 1 + assert changes[0] == new_job_id + + #check if that one is finished + another_test = False + while new_fc.job_status(new_job_id)[0] != JOB_ID_FINISHED: + print "Waiting for add command to finish " + time.sleep(2) + another_test = True + + # that probably may happen so should add it here + if another_test: + changes = self.async_manager.check_for_changes() + assert len(changes) == 1 + assert changes[0] == new_job_id + print "The changes are for add finish :",changes + + #now should run another command that is longer to see what happens + new_job_id = new_fc.test.sleep(4) + # we have now one entry in the db what to do ? + # when now run the check changes should have ne entry in the changes :) + changes = self.async_manager.check_for_changes() + print "The changes for sleep are :",changes + assert len(changes) == 1 + assert changes[0] == new_job_id + + #if we already have the finished message we dont have to run the other test after that one + another_test = False + while new_fc.job_status(new_job_id)[0] != JOB_ID_FINISHED: + print "Waiting for sleep command to finish " + time.sleep(2) + another_test = True + + if another_test: + changes = self.async_manager.check_for_changes() + assert len(changes) == 1 + assert changes[0] == new_job_id + print "The changes for sleep finish are :",changes + + + def select_from_test(self): + print "****Testing select_from**** " + #these tests are a little bit tricky so may not have + #the exact results all depends on remote machines :) + self.reset_stuff() + new_fc = Overlord("*",async=True) + #new_job_id=new_fc.test.add(1,2) + new_job_id = new_fc.test.sleep(6) + + #insert one running + #now we have one entry into async_manager + result_ids = new_fc.open_job_ids() + self.async_manager.refresh_list() + if result_ids.has_key(new_job_id) and result_ids[new_job_id] == JOB_ID_RUNNING: + print "Testing for SELECT RUNNING ..." + select_list = self.async_manager.select_from('RUNNING') + #print "Result form selct RUNNING :",select_list + assert len(select_list) == 1 + assert select_list[0].has_key(new_job_id) + assert select_list[0][new_job_id][0] == JOB_ID_RUNNING + + #pull_property_options = ('FINISHED','ERROR','NEW','CHANGED','RUNNING','PARTIAL') + #insert one that finishes + #get one NEW + print "Testing for SELECT NEW ..." + select_list = self.async_manager.select_from('NEW') + #print "The select list is :",select_list + assert len(select_list) == 1 + assert select_list[0].has_key(new_job_id) + assert select_list[0][new_job_id][1] == self.async_manager.JOB_CODE_NEW + + #test the ones that are changed :) + another_test = False + current_job_status = new_fc.job_status(new_job_id)[0] + while current_job_status != JOB_ID_FINISHED: + print "Waiting for sleep command to finish " + time.sleep(1) + another_test = True + + #test also for partial resultst status + if current_job_status == JOB_ID_PARTIAL: + #populate the list + print "Testing for SELECT PARTIAL ..." + self.async_manager.refresh_list() + select_list = self.async_manager.select_from('PARTIAL') + assert select_list[0].has_key(new_job_id) + assert select_list[0][new_job_id][0] == JOB_ID_PARTIAL + + current_job_status = new_fc.job_status(new_job_id)[0] + + + if another_test: + + print "Testing for SELECT CHANGED ..." + self.async_manager.refresh_list() + select_list = self.async_manager.select_from('CHANGED') + #print "current Select list is :",select_list + assert len(select_list) == 1 + assert select_list[0].has_key(new_job_id) + assert select_list[0][new_job_id][1] == self.async_manager.JOB_CODE_CHANGED + + print "Testing for SELECT FINISHED ..." + assert select_list[0][new_job_id][0] == JOB_ID_FINISHED + + #didnt test for ERROR and others they are not present in overlord :) + + #insert one raises error + #insert one another + + def job_id_result_test(self): + pass + + def current_db_test(self): + #that test also test the test_get_current_list with no changes option + + result_ids = self.fc.open_job_ids() + manual_list = {} + for job_id,code in result_ids.iteritems(): + manual_list[job_id]=[code,self.async_manager.JOB_CODE_NEW] + + real_result =self.async_manager.current_db() + #print real_result + assert manual_list ==real_result + + def reset_stuff(self): + #first reset the database to see what is there + self.remove_db() + #all of them are new now + self.async_manager.reset_current_list() + + + def remove_db(self): + import os + root_dir = "/var/lib/func" + db_file_list = os.listdir(root_dir) + for f in db_file_list: + if not f.startswith("."): + os.remove("".join([root_dir,"/",f])) + + print "The database is removed" +# we do it that way because when run it from nosetest we hae failings +tester = AsyncResultManagerTest() +tester.setUp() +#tester.current_db_test() +tester.check_for_changes_test() +tester.select_from_test() diff --git a/funcweb/funcweb/widget_automation.py b/funcweb/funcweb/widget_automation.py index 351603b..fa83fcf 100644 --- a/funcweb/funcweb/widget_automation.py +++ b/funcweb/funcweb/widget_automation.py @@ -240,7 +240,7 @@ class RemoteFormAutomation(CoreWD): template = """ <div> - ${for_widget.display(action='post_form')} + ${for_widget.display(action='/funcweb/post_form')} <div id="loading"></div> <div id="post_data"></div> </div> @@ -260,9 +260,10 @@ class RemoteFormAutomation(CoreWD): fields = generated_fields, validator = validator_schema, name = "minion_form", - update = "col5", - before='getElement(\'loading\').innerHTML=toHTML(IMG({src:\'../static/images/loading.gif\',width:\'100\',height:\'100\'}));', + update = "resultbox", + before='myj(\'#resultcontent\').hide().show(\'slow\');addDomAjaxREsult();getElement(\'loading\').innerHTML=toHTML(IMG({src:\'../funcweb/static/images/loading.gif\',width:\'100\',height:\'100\'}));', on_complete='getElement(\'loading\' ).innerHTML=\'Done!\';', + submit_text = "Send Command to Glob" ) #################################################################################################### @@ -275,10 +276,10 @@ class RemoteFormFactory(object): #some values that may want to change later name = "minion_form", update = "col5", - before='getElement(\'loading\').innerHTML=toHTML(IMG({src:\'../static/images/loading.gif\',width:\'100\',height:\'100\'}));', + before='getElement(\'loading\').innerHTML=toHTML(IMG({src:\'../funcweb/static/images/loading.gif\',width:\'100\',height:\'100\'}));', on_complete='getElement(\'loading\' ).innerHTML=\'Done!\';', submit_text = "Send Minion Form" - action = "/post_form" + action = "/funcweb/post_form" def __init__(self,wlist_object,validator_schema): self.wlist_object = wlist_object @@ -299,30 +300,6 @@ class RemoteFormFactory(object): validator = self.validator_schema ) -class RemoteLinkFactory(CoreWD): - """ - A rpc executer for the methods without arguments - """ - - name = "Minion Remote Link Executer" - - template =""" - <div> - ${for_widget.display()} - <div id="items">Minion Result</div> - </div> - """ - - def __init__(self,*args,**kwargs): - """The init part here""" - super(SomeRemoteLink,self).__init__(*args,**kwargs) - self.for_widget = LinkRemoteFunction( - name = "catexecuter", - action = "/catlister", - data = dict(give_all="all"), - update = "items" - ) - ############################################################################################# def pretty_label(name_to_label): diff --git a/funcweb/init-scripts/funcwebd b/funcweb/init-scripts/funcwebd index 01ee280..11be5e2 100755 --- a/funcweb/init-scripts/funcwebd +++ b/funcweb/init-scripts/funcwebd @@ -28,6 +28,8 @@ SERVICE=funcwebd PROCESS=funcwebd DAEMON=/usr/bin/funcwebd +CERTMASTER=/usr/bin/certmaster +CERTMASTER_PROC=certmaster CONFIG_ARGS="--daemon" @@ -66,6 +68,25 @@ fi RETVAL=0 start() { + + ps wt? | grep "$CERTMASTER" 2>&1 > /dev/null + if [ "x$?" = "x0" ]; then + CERT_RVAL=0 + echo "certmaster is running" + else + CERT_RVAL=3 + echo "certmaster is not running" + fi + + if [ $CERT_RVAL -eq 3 ]; then + echo -n $"Starting certmaster daemon: " + START_DAEMON $CERTMASTER_PROC $CONFIG_ARGS + CERT_RVAL=$? + echo + [ $CERT_RVAL -eq 0 ] && touch /var/lock/subsys/$CERTMASTER_PROC + fi + + echo -n $"Starting funcweb server" START_DAEMON $PROCESS $CONFIG_ARGS RETVAL=$? diff --git a/funcweb/setup.py b/funcweb/setup.py index 40c2e00..e4e6cf7 100644 --- a/funcweb/setup.py +++ b/funcweb/setup.py @@ -20,6 +20,9 @@ etcpath = "/etc/httpd/conf.d" self_etcpath = "/etc/funcweb" #the init path for starting and stoping the server ! initpath = "/etc/init.d" +#the log path +logpath = "/var/log/funcweb" +rotpath = "/etc/logrotate.d" #the setup part setup( @@ -88,6 +91,8 @@ setup( data_files = [ (etcpath,['etc/funcweb.conf']), (self_etcpath,['etc/prod.cfg']), - (initpath,['init-scripts/funcwebd']) + (initpath,['init-scripts/funcwebd']), + (logpath,[]), + (rotpath,['etc/funcweb_rotate']) ], ) diff --git a/funcweb/version b/funcweb/version index 084a74c..38e365e 100644 --- a/funcweb/version +++ b/funcweb/version @@ -1 +1 @@ -0.1 1 +0.1 4 |
