summaryrefslogtreecommitdiffstats
path: root/funcweb
diff options
context:
space:
mode:
authormakkalot <makkalot@gmail.com>2008-07-28 14:18:01 +0300
committermakkalot <makkalot@gmail.com>2008-07-28 14:18:01 +0300
commit8746ffb25fc2c138e457489d38bce1a8cd92835c (patch)
tree370514f3f40405c34ce5ce24d9ce17dddfa426a3 /funcweb
parent6e47882e0dcb86e8b360dc17ac2541fe6875e55d (diff)
parent391a052ccedb1195290aceeea500fc6aea86afdb (diff)
merge from new_layout to master
Diffstat (limited to 'funcweb')
-rw-r--r--funcweb/etc/funcweb.conf12
-rw-r--r--funcweb/etc/funcweb_rotate12
-rw-r--r--funcweb/etc/prod.cfg27
-rw-r--r--funcweb/funcweb.spec10
-rw-r--r--funcweb/funcweb/async_tools.py186
-rw-r--r--funcweb/funcweb/commands.py9
-rw-r--r--funcweb/funcweb/config/app.cfg6
-rw-r--r--funcweb/funcweb/controllers.py169
-rw-r--r--funcweb/funcweb/identity/pam.py2
-rw-r--r--funcweb/funcweb/static/css/style.css1253
-rw-r--r--funcweb/funcweb/static/images/LoadingGIF_2.gifbin0 -> 9697 bytes
-rw-r--r--funcweb/funcweb/static/images/button.jpgbin0 -> 1431 bytes
-rw-r--r--funcweb/funcweb/static/images/button2.jpgbin0 -> 1444 bytes
-rw-r--r--funcweb/funcweb/static/images/button2_hover.jpgbin0 -> 1830 bytes
-rw-r--r--funcweb/funcweb/static/images/button_over.jpgbin0 -> 1838 bytes
-rw-r--r--funcweb/funcweb/static/images/changed.gifbin0 -> 28018 bytes
-rw-r--r--funcweb/funcweb/static/images/footer.jpgbin0 -> 8408 bytes
-rw-r--r--funcweb/funcweb/static/images/header.jpgbin0 -> 53989 bytes
-rw-r--r--funcweb/funcweb/static/images/line.pngbin0 -> 172 bytes
-rw-r--r--funcweb/funcweb/static/images/menuimg.jpgbin0 -> 354 bytes
-rw-r--r--funcweb/funcweb/static/images/menuimghover.jpgbin0 -> 340 bytes
-rw-r--r--funcweb/funcweb/static/images/new.gifbin0 -> 20905 bytes
-rw-r--r--funcweb/funcweb/static/javascript/ajax.js23
-rw-r--r--funcweb/funcweb/static/javascript/async_tools.js35
-rw-r--r--funcweb/funcweb/templates/async_table.html48
-rw-r--r--funcweb/funcweb/templates/index.html49
-rw-r--r--funcweb/funcweb/templates/master.html68
-rw-r--r--funcweb/funcweb/templates/method.html18
-rw-r--r--funcweb/funcweb/templates/method_args.html17
-rw-r--r--funcweb/funcweb/templates/methods.html16
-rw-r--r--funcweb/funcweb/templates/minion.html16
-rw-r--r--funcweb/funcweb/templates/minions.html31
-rw-r--r--funcweb/funcweb/templates/module.html15
-rw-r--r--funcweb/funcweb/templates/modules.html16
-rw-r--r--funcweb/funcweb/templates/result.html (renamed from funcweb/funcweb/templates/run.html)8
-rw-r--r--funcweb/funcweb/templates/widgets.html28
-rw-r--r--funcweb/funcweb/tests/bork.py37
-rw-r--r--funcweb/funcweb/tests/test_async_tools.py176
-rw-r--r--funcweb/funcweb/widget_automation.py35
-rwxr-xr-xfuncweb/init-scripts/funcwebd21
-rw-r--r--funcweb/setup.py7
-rw-r--r--funcweb/version2
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
new file mode 100644
index 0000000..fb5675d
--- /dev/null
+++ b/funcweb/funcweb/static/images/LoadingGIF_2.gif
Binary files differ
diff --git a/funcweb/funcweb/static/images/button.jpg b/funcweb/funcweb/static/images/button.jpg
new file mode 100644
index 0000000..8ec7e04
--- /dev/null
+++ b/funcweb/funcweb/static/images/button.jpg
Binary files differ
diff --git a/funcweb/funcweb/static/images/button2.jpg b/funcweb/funcweb/static/images/button2.jpg
new file mode 100644
index 0000000..207d4db
--- /dev/null
+++ b/funcweb/funcweb/static/images/button2.jpg
Binary files differ
diff --git a/funcweb/funcweb/static/images/button2_hover.jpg b/funcweb/funcweb/static/images/button2_hover.jpg
new file mode 100644
index 0000000..f2a0473
--- /dev/null
+++ b/funcweb/funcweb/static/images/button2_hover.jpg
Binary files differ
diff --git a/funcweb/funcweb/static/images/button_over.jpg b/funcweb/funcweb/static/images/button_over.jpg
new file mode 100644
index 0000000..cdf6cd0
--- /dev/null
+++ b/funcweb/funcweb/static/images/button_over.jpg
Binary files differ
diff --git a/funcweb/funcweb/static/images/changed.gif b/funcweb/funcweb/static/images/changed.gif
new file mode 100644
index 0000000..250a211
--- /dev/null
+++ b/funcweb/funcweb/static/images/changed.gif
Binary files differ
diff --git a/funcweb/funcweb/static/images/footer.jpg b/funcweb/funcweb/static/images/footer.jpg
new file mode 100644
index 0000000..ccb14cc
--- /dev/null
+++ b/funcweb/funcweb/static/images/footer.jpg
Binary files differ
diff --git a/funcweb/funcweb/static/images/header.jpg b/funcweb/funcweb/static/images/header.jpg
new file mode 100644
index 0000000..5583d83
--- /dev/null
+++ b/funcweb/funcweb/static/images/header.jpg
Binary files differ
diff --git a/funcweb/funcweb/static/images/line.png b/funcweb/funcweb/static/images/line.png
new file mode 100644
index 0000000..79d2ef7
--- /dev/null
+++ b/funcweb/funcweb/static/images/line.png
Binary files differ
diff --git a/funcweb/funcweb/static/images/menuimg.jpg b/funcweb/funcweb/static/images/menuimg.jpg
new file mode 100644
index 0000000..d3e232a
--- /dev/null
+++ b/funcweb/funcweb/static/images/menuimg.jpg
Binary files differ
diff --git a/funcweb/funcweb/static/images/menuimghover.jpg b/funcweb/funcweb/static/images/menuimghover.jpg
new file mode 100644
index 0000000..415cff1
--- /dev/null
+++ b/funcweb/funcweb/static/images/menuimghover.jpg
Binary files differ
diff --git a/funcweb/funcweb/static/images/new.gif b/funcweb/funcweb/static/images/new.gif
new file mode 100644
index 0000000..4bea887
--- /dev/null
+++ b/funcweb/funcweb/static/images/new.gif
Binary files differ
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', {&quot;loading&quot;: null, &quot;confirm&quot;: null, &quot;after&quot;: null, &quot;on_complete&quot;: null, &quot;loaded&quot;: null, &quot;on_failure&quot;: null, &quot;on_success&quot;: null, &quot;before&quot;:&quot;myj('#resultcontent').hide();myj('#widgetcontent').hide();myj('#methotdscontent').hide();myj('#modulescontent').hide();&quot;});" 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