Merge lp:~unifield-team/unifield-server/restart-and-update-cto into lp:unifield-server/sprint5

Proposed by Samus CTO (OpenERP)
Status: Merged
Merged at revision: 3415
Proposed branch: lp:~unifield-team/unifield-server/restart-and-update-cto
Merge into: lp:unifield-server/sprint5
Diff against target: 192 lines (+151/-6)
2 files modified
bin/openerp-server.py (+21/-6)
bin/updater.py (+130/-0)
To merge this branch: bzr merge lp:~unifield-team/unifield-server/restart-and-update-cto
Reviewer Review Type Date Requested Status
Samus CTO (OpenERP) (community) Needs Information
jftempo Needs Resubmitting
Review via email: mp+117602@code.launchpad.net

Description of the change

Hello,

This is the Auto-Updater for OpenERP Server Sprint5

To post a comment you must log in.
Revision history for this message
jftempo (jfb-tempo-consulting) wrote :

Please create an issue in Jira, with a description and a link to this branch.
This issue has to be "Runbot Validated" and assigned to me.

And please replace the print statement in your code by a clean log.

review: Needs Resubmitting
Revision history for this message
Samus CTO (OpenERP) (cto-openerp) wrote :

> Please create an issue in Jira, with a description and a link to this branch.
> This issue has to be "Runbot Validated" and assigned to me.
>
> And please replace the print statement in your code by a clean log.

I'm not aware about Jira's process I will ask Duy for that.

In the other hand, I think it's hard to have a better quality code than that with the use of print.

I can use sys.stdout (or stderr) if you prefer.

The point is the Update process is launched with minimal dependencies as possible (and only Python's ones (and psycopg)). If I want to use logger I will need to import tools.config and netsvc which are OpenERP.

What's your position?

Regards

review: Needs Information

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'bin/openerp-server.py'
2--- bin/openerp-server.py 2011-01-06 13:06:54 +0000
3+++ bin/openerp-server.py 2012-09-27 15:11:20 +0000
4@@ -30,6 +30,9 @@
5 (c) 2003-TODAY, Fabien Pinckaers - OpenERP s.a.
6 """
7
8+from updater import do_update
9+do_update()
10+
11 #----------------------------------------------------------
12 # python imports
13 #----------------------------------------------------------
14@@ -215,7 +218,7 @@
15 if os.name == 'posix':
16 signal.signal(signal.SIGQUIT, dumpstacks)
17
18-def quit():
19+def quit(restart=False):
20 netsvc.Agent.quit()
21 netsvc.Server.quitAll()
22 if tools.config['pidfile']:
23@@ -235,7 +238,17 @@
24 # and would present the forced shutdown
25 thread.join(0.05)
26 time.sleep(0.05)
27- sys.exit(0)
28+ time.sleep(1)
29+ if os.name == 'nt':
30+ try:
31+ logger.info("Killing", thread.getName())
32+ thread._Thread__stop()
33+ except:
34+ logger.info(str(thread.getName()) + ' could not be terminated')
35+ if not restart:
36+ sys.exit(0)
37+ else:
38+ os.execv(sys.executable, [sys.executable] + sys.argv)
39
40 if tools.config['pidfile']:
41 fd = open(tools.config['pidfile'], 'w')
42@@ -247,9 +260,11 @@
43
44 logger.info('OpenERP server is running, waiting for connections...')
45
46-while netsvc.quit_signals_received == 0:
47- time.sleep(60)
48-
49-quit()
50+tools.restart_required = False
51+
52+while netsvc.quit_signals_received == 0 and not tools.restart_required:
53+ time.sleep(5)
54+
55+quit(restart=tools.restart_required)
56
57 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
58
59=== added file 'bin/updater.py'
60--- bin/updater.py 1970-01-01 00:00:00 +0000
61+++ bin/updater.py 2012-09-27 15:11:20 +0000
62@@ -0,0 +1,130 @@
63+import os
64+import sys
65+import psycopg2
66+from datetime import datetime
67+
68+## Unix-like find
69+def find(path):
70+ files = os.listdir(path)
71+ for name in iter(files):
72+ abspath = path+os.path.sep+name
73+ if os.path.isdir( abspath ) and not os.path.islink( abspath ):
74+ files.extend( map(lambda x:name+os.path.sep+x, os.listdir(abspath)) )
75+ return files
76+
77+## Define way to forward logs
78+def warn(*args):
79+ sys.stderr.write(" ".join(map(lambda x:str(x), args))+"\n")
80+
81+## Try...Resume...
82+def Try(command):
83+ try:
84+ command()
85+ except:
86+ e, msg = sys.exc_info()[0].__name__, str(sys.exc_info()[1])
87+ warn(str(msg))
88+ return False
89+ else:
90+ return True
91+
92+## Python free rmtree
93+def rmtree(files, path=None, verbose=False):
94+ if path is None and isinstance(files, str):
95+ path, files = files, find(files)
96+ for f in reversed(files):
97+ target = os.path.join(path, f) if path is not None else f
98+ if os.path.isfile(target) or os.path.islink(target):
99+ warn("unlink", target)
100+ os.unlink( target )
101+ elif os.path.isdir(target):
102+ warn("rmdir", target)
103+ os.rmdir( target )
104+
105+def do_update():
106+## We expect to be in the bin/ directory to proceed
107+ if os.path.exists('update.lock'):
108+ rev_file = os.path.join('.update','revisions.txt')
109+ hist_file = "revision_history.txt"
110+ infos = {'exec_path':os.getcwd()}
111+ revisions = None
112+ cur = None
113+ conn = None
114+ update_revisions = None
115+ files = None
116+ args = list(sys.argv)
117+ for i, x in enumerate(args):
118+ if x in ('-d', '-u'):
119+ args[i] = None
120+ args[i+1] = None
121+ args = filter(lambda x:x is not None, args)
122+ try:
123+ ## Read DB name
124+ f = open('update.lock')
125+ infos = eval(f.read())
126+ f.close()
127+ revisions = ",".join( map(lambda x:"'"+str(x)+"'", infos['revisions']) )
128+ ## Connect to the DB
129+ conn = psycopg2.connect(database=infos['dbname'], user=infos['db_user'], password=infos['db_password'], host=infos['db_host'], port=infos['db_port'])
130+ conn.set_isolation_level(psycopg2.extensions.ISOLATION_LEVEL_AUTOCOMMIT)
131+ cur = conn.cursor()
132+ ## Explore .update directory
133+ files = find('.update')
134+ ## Prepare backup directory
135+ if not os.path.exists('backup'):
136+ os.mkdir('backup')
137+ else:
138+ rmtree('backup')
139+ ## Update Files
140+ warn("Updating...")
141+ for f in files:
142+ target = os.path.join('.update', f)
143+ bak = os.path.join('backup', f)
144+ if os.path.isdir(target):
145+ if os.path.isfile(f) or os.path.islink(f):
146+ os.unlink(f)
147+ if not os.path.exists(f):
148+ os.mkdir(f)
149+ os.mkdir(bak)
150+ else:
151+ if os.path.exists(f):
152+ warn("`%s' -> `%s'" % (f, bak))
153+ os.rename(f, bak)
154+ warn("`%s' -> `%s'" % (target, f))
155+ os.rename(target, f)
156+ ## Update installed revisions in DB
157+ cur.execute("""UPDATE sync_client_version SET state = 'installed', applied = '%s' WHERE name in (%s)"""
158+ % ( datetime.today().strftime("%Y-%m-%d %H:%M:%S"), revisions ))
159+ warn("Update successful.")
160+ warn("Revisions added: ", ", ".join( infos['revisions'] ))
161+ args.extend(['-d', infos['dbname'], '-u', 'all'])
162+ except:
163+ warn("Update failure!")
164+ ## Update DB to mark revisions as not-installed
165+ if cur and infos:
166+ Try(lambda:cur.execute("""UPDATE sync_client_version SET state = 'not-installed' WHERE name in (%s)"""
167+ % ( revisions )))
168+ ## Restore backup and purge .update
169+ if files:
170+ warn("Restoring...")
171+ for f in reversed(files):
172+ target = os.path.join('backup', f)
173+ if os.path.isfile(target) or os.path.islink(target):
174+ warn("`%s' -> `%s'" % (target, f))
175+ elif os.path.isdir(target):
176+ warn("rmdir", target)
177+ os.rmdir( target )
178+ warn("Purging...")
179+ Try(lambda:rmtree(files, '.update'))
180+ warn("rmdir", '.update')
181+ Try(lambda:os.rmdir( '.update' ))
182+ finally:
183+ if cur: cur.close()
184+ if conn: conn.close()
185+ ## Remove lock file
186+ warn("rm", 'update.lock')
187+ Try(lambda:os.unlink( 'update.lock' ))
188+ warn("Restart OpenERP in", infos['exec_path'], "with:",args)
189+ if infos: os.chdir(infos['exec_path'])
190+ os.execv(sys.executable, [sys.executable] + args)
191+
192+

Subscribers

People subscribed via source and target branches

to all changes: