Index: /trunk/Monitoring/Analyze/analyze
===================================================================
--- /trunk/Monitoring/Analyze/analyze	(revision 859)
+++ /trunk/Monitoring/Analyze/analyze	(revision 859)
@@ -0,0 +1,132 @@
+#!/usr/bin/env python
+# -*- coding: ISO-8859-1 -*-
+
+##################################
+#  @program        smon
+#  @description    simulation monitor
+#  @copyright      Copyright â(c)2009 Centre National de la Recherche Scientifique CNRS. 
+#                             All Rights Reservedâ
+#  @svn_file       $Id: analyzer 2545 2013-02-01 09:58:10Z jripsl $
+#  @version        $Rev: 2545 $
+#  @lastrevision   $Date: 2013-02-01 10:58:10 +0100 (Fri, 01 Feb 2013) $
+#  @license        CeCILL (http://dods.ipsl.jussieu.fr/jripsl/smon/LICENSE)
+##################################
+
+import sys
+import signal
+import traceback
+import smtplib
+from email.mime.text import MIMEText
+import time;
+from datetime import datetime
+
+from smon import repo_io
+
+
+
+"""
+Code list reminder
+
+0000 (la simulation dÃ©marre)
+1000 (le job d'une simulation dÃ©marre)
+2000 (PushStack)
+3000 (PopStack OK)
+9000 (PopStack NOK)
+9999 (FATAL)
+"""
+
+class CheckList():
+	max_time_between_msg=10 # unit => seconds
+
+	@classmethod
+	def datetime_to_epoch(cls,datetime):
+		epoch = time.mktime(time.strptime(datetime, "%d.%m.%Y %H:%M:%S")).time(); # assuming datetime format is "29.08.2011 11:05:02"
+		return epoch
+
+	@classmethod
+	def msg_timeout(cls,message):
+
+		msg_time=cls.datetime_to_epoch(message.timestamp)
+		current_time=time.time()
+
+		diff=current_time-msg_time
+
+
+		if diff>cls.max_time_between_msg:
+
+			return True
+		else:
+			return False
+
+	@classmethod
+	def C0001(cls):
+		"""
+		description
+		  check heartbeat (currently, heartbeat is implemented using simulation progress messages).
+		  if progress messages suddently stops, it is likely that the simulation was Killed or
+		  a Segfault occurs. In such case, we inform the other components (failover, prodiguer GUI..) by
+		  changing the simulation status 
+		"""
+		running_simulations=repo_io.get_running_simulations()
+		for simulation in running_simulations:
+			message=repo_io.retrieve_last_messages(simulation)
+
+			if msg_timeout(message):
+
+				repo_io.update_simulation_status(simulation) #from "running" to "killed"
+
+class Analyzer():
+
+	@classmethod
+	def start(cls):
+		pass
+
+	@classmethod
+	def stop(cls):
+		pass
+
+	@classmethod
+	def main(self):
+
+		"""
+		# parse args
+		parser = argparse.ArgumentParser(prog='analyzer')
+		parser.add_argument('-v', dest='verbose',required=False,action='store_true')
+		args = parser.parse_args()
+
+		# check
+		if not os.path.exists(SMON.smon_home):
+			sys.exit(1)
+
+		SMON.init_singleton()
+		"""
+
+		print ' [*] Analyzer running. To exit press CTRL+C'
+
+		CheckList.C0001()
+
+
+		sleep(10)
+
+		"""
+		SMON.free_singleton()
+		"""
+
+def signal_handler(signal, frame):
+		print 'You pressed Ctrl+C!'
+		sys.exit(0)
+
+if __name__ == '__main__':
+
+	signal.signal(signal.SIGINT, signal_handler)
+
+	try:
+		Analyzer.main()
+
+		sys.exit(0)
+
+	except Exception, e:
+
+		traceback.print_exc()
+
+		sys.exit(1)
Index: /trunk/Monitoring/Watch/README
===================================================================
--- /trunk/Monitoring/Watch/README	(revision 859)
+++ /trunk/Monitoring/Watch/README	(revision 859)
@@ -0,0 +1,3 @@
+- to run the watcher, do
+	- source /opt/python2.6_ve/bin/activate
+	- python watch
Index: /trunk/Monitoring/Watch/watch
===================================================================
--- /trunk/Monitoring/Watch/watch	(revision 858)
+++ /trunk/Monitoring/Watch/watch	(revision 859)
@@ -13,5 +13,4 @@
 ##################################
 
-#from smon import dao
 import pika
 import base64
@@ -25,72 +24,19 @@
 
 
-
-
-sys.path.append("/home/jripsl/snapshot/src") 
-import elixir
-import prodiguer_repository
-
-#import prodiguer_repository.operations.mq_hooks_stub as mq_hooks
-import prodiguer_repository.operations.mq_hooks as mq_hooks
-
+from smon import repo_io
 
 
 """
-mq_hooks.retrieve_simulation(name)
-mq_hooks.delete_simulation(name)
-mq_hooks.create_simulation(activity,
-mq_hooks.update_simulation_status(name,
-mq_hooks.retrieve_messages(name)
-mq_hooks.delete_messages(name)
+Code list reminder
+
+0000 (la simulation dÃ©marre)
+1000 (le job d'une simulation dÃ©marre)
+2000 (PushStack)
+3000 (PopStack OK)
+9000 (PopStack NOK)
+9999 (FATAL)
 """
 
-"""
-from prodiguer_repository.models import (
-	ExecutionState,
-	EXECUTION_STATE_RUNNING,
-	EXECUTION_STATE_SET,
-	Message,
-	Simulation,
-	SIMULATION_SPACE_TEST
-)
-"""
-
-
-
-"""
-scenarios from ticket 136
-
-libIGCM simulent des erreurs (killed, segfault, 1% d'erreur)
-le watcher temps rÃ©el change le status des erreurs dÃ©tÃ©ctÃ©s
-le watcher temps diffÃ©rÃ© dÃ©tÃ©cte et change le statut des killed 
-"""
-
-class Watcher():
-	# prod
-	#message_code_action_mapping = {"0000":["log","mail"],"1000":["log"],"2000":["log"],"3000":["log"],"9000":["log"],"9999":["log","mail"]}
-
-	# dev
-	message_code_action_mapping = {"0000":["log","print_stdout"],"1000":[],"2000":[],"3000":[],"9000":["log"],"9999":["log"]}
-	#message_code_action_mapping = {"0000":[],"1000":[],"2000":[],"3000":[],"9000":["log"],"9999":["log"]}
-
-	# debug
-	#message_code_action_mapping = {"0000":["print_stdout"],"1000":["log"],"2000":[],"3000":[],"9000":["log"],"9999":["log"]}
-
-	@classmethod
-	def get_fake_progress_messages(cls):
-		pass
-
-	@classmethod
-	def start(cls):
-		#dao.insert_progress_messages(cls.get_fake_progress_messages())
-		pass
-
-	@classmethod
-	def stop(cls):
-		pass
-
-	@classmethod
-	def add(cls,message):
-		pass
+class Mail():
 
 	@classmethod
@@ -104,8 +50,4 @@
 
 	@classmethod
-	def mail(cls):
-		cls.mail_example()
-
-	@classmethod
 	def send_mail(cls,me,you,object,body):
 		msg = MIMEText(body)
@@ -119,4 +61,24 @@
 		s.quit()
 
+class Actions():
+
+	@classmethod
+	def store_msg(cls):
+		repo_io.store_messages(name)
+
+	@classmethod
+	def set_sim_status_to_error(cls):
+		repo_io.update_simulation_status()
+
+	@classmethod
+	def crea_sim(cls):
+		#repo_io.retrieve_simulation(name)
+		#repo_io.delete_simulation(name)
+		repo_io.create_simulation()
+
+	@classmethod
+	def mail(cls):
+		cls.mail_example()
+
 	@classmethod
 	def print_stdout(cls,message):
@@ -130,5 +92,4 @@
 	@classmethod
 	def log(cls,message):
-
 		with open("/home/jripsl/supervisor/log/supervisor.log", "a") as log_file:
 			log_file.write("%s %s %s\n"%(datetime.now().strftime('%Y%m%d_%H%M%S'), message["code"],message["jobid"]))
@@ -139,9 +100,9 @@
 		message_code=message["code"]
 
-		for action in cls.message_code_action_mapping[message_code]:
+		for action in MessageActionsMapping.mapping[message_code]:
 			proc_name=action
 
 			try:
-				getattr(cls, proc_name)(message)
+				getattr(Actions, proc_name)(message)
 			except Exception,e:
 				traceback.print_exc()
@@ -149,15 +110,25 @@
 				raise Exception("WATCH-ERR002","procedure error (%s,%s)"%(proc_name,str(e)))
 
+class MessageActionsMapping():
+
+	mapping = { "0000":["log", "store_msg", "crea_sim"],
+				"1000":["log", "store_msg"],
+				"2000":["log", "store_msg"],
+				"3000":["log", "store_msg"],
+				"9000":["log", "store_msg", "mail"],
+				"9999":["log", "store_msg", "set_sim_status_to_error", "mail"] }
+
+class Watcher():
+
+	@classmethod
+	def start(cls):
+		pass
+
+	@classmethod
+	def stop(cls):
+		pass
+
 	@classmethod
 	def main(self):
-
-		"""
-		_CONNECTION = "postgresql://postgres:Silence107!@localhost:5432/prodiguer" # Repo connection string.
-		prodiguer_repository.connect(_CONNECTION) # Connect to repo.
-		mq_hooks.create_message("test", 2, "bla")
-		elixir.session.commit()
-		#elixir.session.rollback()
-		"""
-		mq_hooks.create_message()
 
 		"""
@@ -217,5 +188,4 @@
 
 	signal.signal(signal.SIGINT, signal_handler)
-	#print 'Press Ctrl+C'
 
 	try:
Index: /trunk/Monitoring/doc/README
===================================================================
--- /trunk/Monitoring/doc/README	(revision 858)
+++ /trunk/Monitoring/doc/README	(revision 859)
@@ -21,4 +21,12 @@
 				- packages below are needed by Prodiguer library
 					-
+						- pip install psycopg2
+							- doesn't work (Error: pg_config executable not found)
+								- solution is
+									- yum install python-psycopg2.x86_64
+									- yum install libpqxx-devel
+									- yum install python-devel
+									- pip install psycopg2
+										- works
 						- pip install Sqlalchemy
 						- pip install elixir
@@ -29,5 +37,5 @@
 						- SQLAlchemy-0.7.8-py2.6.egg-info
 		- Prodiguer library installation
-			- svn co svn+ssh://<login here>@forge.ipsl.jussieu.fr/ipsl/forge/projets/prodiguer/svn/sw/src/python/trunk/prodiguer_repository/src
+			- svn co svn+ssh://<login here>@forge.ipsl.jussieu.fr/ipsl/forge/projets/prodiguer/svn/sw/src/python/trunk/prodiguer_shared/src
 			- edit "watch" script and edit line below accordingly
 				- sys.path.append("/home/jripsl/snapshot/src") 
Index: /trunk/Monitoring/doc/TODO
===================================================================
--- /trunk/Monitoring/doc/TODO	(revision 859)
+++ /trunk/Monitoring/doc/TODO	(revision 859)
@@ -0,0 +1,1 @@
+- check concurrencies problems related to "simulation.status" column update from different source (GUI, Watcher, Analyser..)
Index: /trunk/Monitoring/smon/repo_io.py
===================================================================
--- /trunk/Monitoring/smon/repo_io.py	(revision 859)
+++ /trunk/Monitoring/smon/repo_io.py	(revision 859)
@@ -0,0 +1,130 @@
+# -*- coding: ISO-8859-1 -*-
+
+##################################
+#  @program        smon
+#  @description    simulation monitor
+#  @copyright      Copyright â(c)2009 Centre National de la Recherche Scientifique CNRS. 
+#                             All Rights Reservedâ
+#  @svn_file       $Id: repo_io.py 2599 2013-03-24 19:01:23Z jripsl $
+#  @version        $Rev: 2599 $
+#  @lastrevision   $Date: 2013-03-24 20:01:23 +0100 (Sun, 24 Mar 2013) $
+#  @license        CeCILL (http://dods.ipsl.jussieu.fr/jripsl/smon/LICENSE)
+##################################
+
+"""
+This module contains repository I/O code
+"""
+
+import sys
+
+# line below is to include Prodiguer database I/O library in the search path
+sys.path.append("/home/jripsl/snapshot/src")
+
+# import Prodiguer database I/O library
+import elixir
+import prodiguer_shared
+
+# set mode
+mode="local_repo" # local_repo, remote_repo, remote_repo__stub
+
+# set repository driver
+if mode=="remote_repo__stub":
+	import prodiguer_shared.repo.mq.hooks_stub as mq_hooks
+elif mode=="remote_repo":
+	import prodiguer_shared.repo.mq.hooks as mq_hooks
+elif mode=="local_repo":
+	import local_repo_hooks as mq_hooks
+else:
+	raise Exception("ERR001 - incorrect mode")
+
+
+
+
+
+_CONNECTION = "postgresql://postgres:Silence107!@localhost:5432/prodiguer"
+
+def init():
+	if mode=="local_repo":
+		pass
+	elif mode=="remote_repo":
+		prodiguer_shared.connect(_CONNECTION)
+	elif mode=="remote_repo__stub":
+		pass
+	else:
+		raise Exception("ERR004 - incorrect mode")
+
+def test():
+	mq_hooks.create_message("test2", 2, "bla2")
+	commit()
+
+	mq_hooks.update_simulation_status('1pctCO22', 'ERROR')
+	commit()
+
+	mq_hooks.create_message("test3", 3, "bla3")
+	rollback()
+
+def commit():
+	if mode=="local_repo":
+		pass
+	elif mode=="remote_repo":
+		elixir.session.commit()
+	elif mode=="remote_repo__stub":
+		pass
+	else:
+		raise Exception("ERR002 - incorrect mode")
+
+def rollback():
+	if mode=="local_repo":
+		pass
+	elif mode=="remote_repo":
+		elixir.session.rollback()
+	elif mode=="remote_repo__stub":
+		pass
+	else:
+		raise Exception("ERR003 - incorrect mode")
+
+def retrieve_simulation(name):
+	mq_hooks.retrieve_simulation(name)
+
+def delete_simulation(name):
+	mq_hooks.delete_simulation(name)
+
+def create_simulation(simulation):
+	mq_hooks.create_simulation(activity,
+
+def update_simulation_status(name):
+	mq_hooks.update_simulation_status(name,
+
+def retrieve_messages(name):
+	mq_hooks.retrieve_messages(name)
+
+def delete_messages(name):
+	mq_hooks.delete_messages(name)
+
+def create_message(name):
+	mq_hooks.create_message()
+
+def retrieve_last_messages(simulation):
+	mq_hooks.retrieve_last_messages(simulation)
+
+"""
+from prodiguer_shared.models import (
+	ExecutionState,
+	EXECUTION_STATE_RUNNING,
+	EXECUTION_STATE_SET,
+	Message,
+	Simulation,
+	SIMULATION_SPACE_TEST
+)
+"""
+
+# --- higher level methods --- #
+
+def get_running_simulations():
+	running_simulation=[]
+
+	for s in retrieve_simulation():
+		if s.status=="running":
+			running_simulation.append(s)
+			
+	return running_simulation
Index: /trunk/Monitoring/smon/test_remote_repo.py
===================================================================
--- /trunk/Monitoring/smon/test_remote_repo.py	(revision 859)
+++ /trunk/Monitoring/smon/test_remote_repo.py	(revision 859)
@@ -0,0 +1,23 @@
+import sys
+sys.path.append("/home/jripsl/snapshot/src")
+
+import elixir
+
+#  Module imports.
+import prodiguer_shared.repo as repo
+import prodiguer_shared.repo.mq.hooks as mq_hooks
+
+
+# Repo connection string.
+_CONNECTION = "postgresql://postgres:Silence107!@localhost:5432/prodiguer"
+
+# Get prodiguer session handler.
+repo.connect(_CONNECTION)
+
+# Invoke hooks.
+mq_hooks.update_simulation_status('1pctCO22', 'ERROR')
+
+# Commit.
+repo.commit()
+
+
