Package omero :: Package plugins :: Module db
[hide private]
[frames] | no frames]

Source Code for Module omero.plugins.db

  1  #!/usr/bin/env python 
  2  # -*- coding: utf-8 -*- 
  3   
  4  # 
  5  # Copyright (C) 2008-2013 Glencoe Software, Inc. All Rights Reserved. 
  6  # Use is subject to license terms supplied in LICENSE.txt 
  7  # 
  8  # This program is free software; you can redistribute it and/or modify 
  9  # it under the terms of the GNU General Public License as published by 
 10  # the Free Software Foundation; either version 2 of the License, or 
 11  # (at your option) any later version. 
 12  # 
 13  # This program is distributed in the hope that it will be useful, 
 14  # but WITHOUT ANY WARRANTY; without even the implied warranty of 
 15  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
 16  # GNU General Public License for more details. 
 17  # 
 18  # You should have received a copy of the GNU General Public License along 
 19  # with this program; if not, write to the Free Software Foundation, Inc., 
 20  # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 
 21   
 22  """ 
 23     Plugin for our managing the OMERO database. 
 24   
 25     Plugin read by omero.cli.Cli during initialization. The method(s) 
 26     defined here will be added to the Cli class for later use. 
 27  """ 
 28   
 29  from omero.cli import BaseControl 
 30  from omero.cli import CLI 
 31   
 32  from omero_ext.argparse import FileType 
 33   
 34  from path import path 
 35   
 36  import omero.java 
 37  import time 
 38  import sys 
 39   
 40  HELP = """Database tools for creating scripts, setting passwords, etc.""" 
 41   
 42   
43 -class DatabaseControl(BaseControl):
44
45 - def _configure(self, parser):
46 sub = parser.sub() 47 48 script = sub.add_parser( 49 "script", help="Generates a DB creation script") 50 script.set_defaults(func=self.script) 51 script.add_argument( 52 "-f", "--file", type=FileType(mode="w"), 53 help="Optional file to save to. Use '-' for stdout.") 54 script.add_argument("dbversion", nargs="?") 55 script.add_argument("dbpatch", nargs="?") 56 script.add_argument("password", nargs="?") 57 58 pw = sub.add_parser( 59 "password", 60 help="Prints SQL command for updating your root password") 61 pw.add_argument("password", nargs="?") 62 pw.set_defaults(func=self.password) 63 pw.add_argument("--user-id", 64 help="User ID to salt into the password. " 65 "Defaults to '0', i.e. 'root'", 66 default="0") 67 68 for x in (pw, script): 69 x.add_argument( 70 "--no-salt", action="store_true", 71 help="Disable the salting of passwords")
72
73 - def _lookup(self, data, data2, key, map, hidden=False):
74 """ 75 Read values from data and data2. If value is contained in data 76 then use it without question. If the value is in data2, offer 77 it as a default 78 """ 79 map[key] = data.properties.getProperty("omero.db."+key) 80 if not map[key] or map[key] == "": 81 if data2: 82 default = data2.properties.getProperty("omero.db."+key) 83 else: 84 default = "" 85 map[key] = self.ctx.input("Please enter omero.db.%s [%s]: " 86 % (key, default), hidden) 87 if not map[key] or map[key] == "": 88 map[key] = default 89 if not map[key] or map[key] == "": 90 self.ctx.die(1, "No value entered")
91
92 - def _has_user_id(self, args):
93 return args and "user_id" in args and args.user_id is not None
94
95 - def _get_password_hash(self, args, root_pass=None, old_prompt=False):
96 97 prompt = " for OMERO " 98 if self._has_user_id(args) and not old_prompt: 99 prompt += "user %s" % args.user_id 100 else: 101 prompt += "root user" 102 root_pass = self._ask_for_password(prompt, root_pass) 103 104 server_jar = self.ctx.dir / "lib" / "server" / "server.jar" 105 cmd = ["ome.security.auth.PasswordUtil", root_pass] 106 if not args.no_salt and self._has_user_id(args): 107 cmd.append(args.user_id) 108 p = omero.java.popen(["-cp", str(server_jar)] + cmd) 109 rc = p.wait() 110 if rc != 0: 111 out, err = p.communicate() 112 self.ctx.die(rc, "PasswordUtil failed: %s" % err) 113 value = p.communicate()[0] 114 if not value or len(value) == 0: 115 self.ctx.die(100, "Encoded password is empty") 116 return value.strip()
117
118 - def _copy(self, input_path, output, func, cfg=None):
119 input = open(str(input_path)) 120 try: 121 for s in input.xreadlines(): 122 try: 123 if cfg: 124 output.write(func(s) % cfg) 125 else: 126 output.write(func(s)) 127 except Exception, e: 128 self.ctx.die( 129 154, "Failed to map line: %s\nError: %s" 130 % (s, e)) 131 finally: 132 input.close()
133
134 - def _make_replace(self, root_pass, db_vers, db_patch):
135 def replace_method(str_in): 136 str_out = str_in.replace("@ROOTPASS@", root_pass) 137 str_out = str_out.replace("@DBVERSION@", db_vers) 138 str_out = str_out.replace("@DBPATCH@", db_patch) 139 return str_out
140 return replace_method
141
142 - def _db_profile(self):
143 import re 144 server_lib = self.ctx.dir / "lib" / "server" 145 model_jars = server_lib.glob("model-*.jar") 146 if len(model_jars) != 1: 147 self.ctx.die(200, "Invalid model-*.jar state: %s" 148 % ",".join(model_jars)) 149 model_jar = model_jars[0] 150 model_jar = str(model_jar.basename()) 151 match = re.search("model-(.*?).jar", model_jar) 152 return match.group(1)
153
154 - def _sql_directory(self, db_vers, db_patch):
155 """ 156 See #2689 157 """ 158 dbprofile = self._db_profile() 159 sql_directory = self.ctx.dir / "sql" / dbprofile / \ 160 ("%s__%s" % (db_vers, db_patch)) 161 if not sql_directory.exists(): 162 self.ctx.die(2, "Invalid Database version/patch: %s does not" 163 " exist" % sql_directory) 164 return sql_directory
165
166 - def _create(self, sql_directory, db_vers, db_patch, password_hash, args, 167 location=None):
168 sql_directory = self._sql_directory(db_vers, db_patch) 169 if not sql_directory.exists(): 170 self.ctx.die(2, "Invalid Database version/patch: %s does not" 171 " exist" % sql_directory) 172 173 if args and args.file: 174 output = args.file 175 script = "<filename here>" 176 else: 177 script = "%s__%s.sql" % (db_vers, db_patch) 178 location = path.getcwd() / script 179 output = open(location, 'w') 180 self.ctx.out("Saving to " + location) 181 182 try: 183 dbprofile = self._db_profile() 184 header = sql_directory / ("%s-header.sql" % dbprofile) 185 footer = sql_directory / ("%s-footer.sql" % dbprofile) 186 if header.exists(): 187 # 73 multiple DB support. OMERO 4.3+ 188 cfg = { 189 "TIME": time.ctime(time.time()), 190 "DIR": sql_directory, 191 "SCRIPT": script} 192 self._copy(header, output, str, cfg) 193 self._copy(sql_directory/"schema.sql", output, str) 194 self._copy(sql_directory/"views.sql", output, str) 195 self._copy( 196 footer, output, 197 self._make_replace(password_hash, db_vers, db_patch), cfg) 198 else: 199 # OMERO 4.2.x and before 200 output.write(""" 201 -- 202 -- GENERATED %s from %s 203 -- 204 -- This file was created by the bin/omero db script command 205 -- and contains an MD5 version of your OMERO root users's password. 206 -- You should think about deleting it as soon as possible. 207 -- 208 -- To create your database: 209 -- 210 -- createdb omero 211 -- createlang plpgsql omero 212 -- psql omero < %s 213 -- 214 215 BEGIN; 216 """ % (time.ctime(time.time()), sql_directory, script)) 217 self._copy(sql_directory/"schema.sql", output, str) 218 self._copy( 219 sql_directory/"data.sql", output, 220 self._make_replace(password_hash, db_vers, db_patch)) 221 self._copy(sql_directory/"views.sql", output, str) 222 output.write("COMMIT;\n") 223 224 finally: 225 output.flush() 226 if output != sys.stdout: 227 output.close()
228
229 - def password(self, args):
230 root_pass = None 231 user_id = 0 232 old_prompt = True 233 if self._has_user_id(args): 234 user_id = args.user_id 235 if user_id != '0': # For non-root, use new_prompt 236 old_prompt = False 237 try: 238 root_pass = args.password 239 except Exception, e: 240 self.ctx.dbg("While getting arguments:" + str(e)) 241 password_hash = self._get_password_hash(args, root_pass, old_prompt) 242 self.ctx.out("UPDATE password SET hash = '%s' " 243 "WHERE experimenter_id = %s;""" % 244 (password_hash, user_id))
245
246 - def loaddefaults(self):
247 try: 248 data2 = self.ctx.initData({}) 249 output = self.ctx.readDefaults() 250 self.ctx.parsePropertyFile(data2, output) 251 except Exception, e: 252 self.ctx.dbg(str(e)) 253 data2 = None 254 return data2
255
256 - def script(self, args):
257 258 data = self.ctx.initData({}) 259 data2 = self.loaddefaults() 260 map = {} 261 root_pass = None 262 try: 263 db_vers = args.dbversion 264 db_patch = args.dbpatch 265 if data2: 266 if len(db_vers) == 0: 267 db_vers = data2.properties.getProperty("omero.db.version") 268 if len(db_patch) == 0: 269 db_patch = data2.properties.getProperty("omero.db.patch") 270 data.properties.setProperty("omero.db.version", db_vers) 271 self.ctx.err("Using %s for version" % db_vers) 272 data.properties.setProperty("omero.db.patch", db_patch) 273 self.ctx.err("Using %s for patch" % db_patch) 274 root_pass = args.password 275 self.ctx.err("Using password from commandline") 276 except Exception, e: 277 self.ctx.dbg("While getting arguments:"+str(e)) 278 self._lookup(data, data2, "version", map) 279 self._lookup(data, data2, "patch", map) 280 args.user_id = "0" 281 sql = self._sql_directory(map["version"], map["patch"]) 282 map["pass"] = self._get_password_hash(args, root_pass, True) 283 self._create(sql, map["version"], map["patch"], map["pass"], args)
284 285 try: 286 register("db", DatabaseControl, HELP) 287 except NameError: 288 if __name__ == "__main__": 289 cli = CLI() 290 cli.register("db", DatabaseControl, HELP) 291 cli.invoke(sys.argv[1:]) 292