1  """ 
  2  DC administration interface. 
  3  """ 
  4   
  5   
  6   
  7   
  8   
  9   
 10   
 11  from __future__ import print_function 
 12   
 13  import os 
 14  import sys 
 15   
 16  from gavo import base 
 17  from gavo import rscdesc   
 18  from gavo.base import sqlsupport 
 19  from gavo.protocols import uws 
 20  from gavo.utils import Arg, exposedFunction, makeCLIParser 
 25   
 26   
 27  @exposedFunction([ 
 28          Arg("user", help="the user name"), 
 29          Arg("password", help="a password for the user"), 
 30          Arg("remarks", help="optional remarks",  
 31                  default="", nargs='?')], 
 32          help="add a user/password pair and a matching group to the DC server") 
 34          try: 
 35                  querier.query("INSERT INTO dc.users (username, password, remarks)" 
 36                          " VALUES (%(user)s, %(password)s, %(remarks)s)", args.__dict__) 
 37          except base.IntegrityError: 
 38                  raise base.ui.logOldExc(ArgError("User %s already exists." 
 39                          "  Use 'changeuser' command to edit."%args.user)) 
 40          querier.query("INSERT INTO dc.groups (username, groupname)" 
 41                  " VALUES (%(user)s, %(user)s)", args.__dict__) 
  42   
 43   
 44  @exposedFunction([ 
 45          Arg("user", help="the user name to remove")], 
 46          help="remove a user from the DC server") 
 59   
 60   
 61  @exposedFunction([ 
 62          Arg("user", help="the user name"), 
 63          Arg("password", help="a password for the user"), 
 64          Arg("remarks", help="optional remarks",  
 65                  default="", nargs='?')], 
 66          help="change remarks and/or password for a DC user") 
 68                  if args.remarks is None: 
 69                          c = querier.query("UPDATE dc.users SET password=%(password)s" 
 70                          " WHERE username=%(user)s", args.__dict__) 
 71                  else: 
 72                          c = querier.query("UPDATE dc.users SET password=%(password)s," 
 73                          " remarks=%(remarks)s WHERE username=%(user)s", args.__dict__) 
 74                  if not c.rowcount: 
 75                          sys.stderr.write("Warning: No rows changed for user %s\n"%args.user) 
  76   
 77   
 78  @exposedFunction([ 
 79          Arg("user", help="a user name"), 
 80          Arg("group", help="the group to add the user to")], 
 81          help="add a user to a group") 
 83          try: 
 84                  querier.query("INSERT INTO dc.groups (username, groupname)" 
 85                          " VALUES (%(user)s, %(group)s)", args.__dict__) 
 86          except sqlsupport.IntegrityError: 
 87                  raise base.ui.logOldExc(ArgError("User %s doesn't exist."%args.user)) 
  88   
 89   
 90  @exposedFunction([ 
 91          Arg("user", help="a user name"), 
 92          Arg("group", help="the group to remove the user from")], 
 93          help="remove a user from a group") 
 95          c = querier.query("DELETE FROM dc.groups WHERE groupname=%(group)s" 
 96                  " and username=%(user)s", args.__dict__) 
 97          if not c.rowcount: 
 98                  sys.stderr.write("Warning: No rows deleted while deleting user" 
 99                          " %s from group %s\n"%(args.user, args.group)) 
 100   
101   
102  @exposedFunction(help="list users known to the DC") 
103 -def listusers(querier, args): 
 104          data = list(querier.query("SELECT username, groupname, remarks" 
105                  " FROM dc.users NATURAL JOIN dc.groups ORDER BY username")) 
106          curUser = None 
107          for user, group, remark in data: 
108                  if user!=curUser: 
109                          print("\n%s (%s) --"%(user, remark), end=' ') 
110                          curUser = user 
111                  print(group, end=' ') 
112          print() 
 113   
114   
115  @exposedFunction([ 
116          Arg("-f", help="also remove all jobs in ERROR and ABORTED states (only use" 
117                  " if you are sure what you are doing).", action="store_true", 
118                  dest="includeFailed"), 
119          Arg("-p", help="also remove all jobs in PENDING states (only use" 
120                  " if you are sure what you are doing).", action="store_true", 
121                  dest="includeForgotten"), 
122          Arg("--all", help="remove all jobs (this is extremely unfriendly." 
123                  "  Don't use this on public UWSes)", action="store_true", 
124                  dest="includeAll"), 
125          Arg("--nuke-completed", help="also remove COMPLETEd jobs (this is" 
126                  " unfriendly.  Don't do this on public UWSes).", action="store_true", 
127                  dest="includeCompleted"),], 
128          help="remove expired UWS jobs") 
135   
136   
137  @exposedFunction([ 
138          Arg("jobId", help="id of the job to abort"), 
139          Arg("helpMsg", help="A helpful message to add to the abort message")], 
140          help="manually abort a TAP job and send some message to a user") 
151   
152   
153  @exposedFunction([Arg(help="identifier of the deleted service", 
154                  dest="svcId")], 
155          help="Declare an identifier as deleted (for when" 
156          " you've removed the RD but the identifier still floats on" 
157          " some registries)") 
159          import datetime 
160   
161          from gavo import registry 
162          from gavo import rsc 
163   
164          authority, path = registry.parseIdentifier(args.svcId) 
165          if authority!=base.getConfig("ivoa", "authority"): 
166                  raise base.ReportableError("You can only declare ivo ids from your" 
167                          " own authority as deleted.") 
168          idParts = path.split("/") 
169          svcsRD = base.caches.getRD("//services") 
170   
171           
172          resTable = rsc.TableForDef(svcsRD.getById("resources"), 
173                  connection=querier.connection) 
174          newRow = resTable.tableDef.getDefaults() 
175          newRow["sourceRD"] = "/".join(idParts[:-1]) 
176          newRow["resId"] = idParts[-1] 
177          newRow["deleted"] = True 
178          newRow["title"] = "Ex "+args.svcId 
179          newRow["dateUpdated"] = newRow["recTimestamp"] = datetime.datetime.utcnow() 
180          resTable.addRow(newRow) 
181   
182           
183          resTable = rsc.TableForDef(svcsRD.getById("sets"), 
184                  connection=querier.connection) 
185          newRow = resTable.tableDef.getDefaults() 
186          newRow["sourceRD"] = "/".join(idParts[:-1]) 
187          newRow["renderer"] = "null" 
188          newRow["resId"] = idParts[-1] 
189          newRow["setName"] = "ivo_managed" 
190          newRow["deleted"] = True 
191          resTable.addRow(newRow) 
 192   
193   
194  @exposedFunction([Arg(help="rd#table-id of the table containing the" 
195          " products that should get cached previews", dest="tableId"), 
196          Arg("-w", type=str, 
197                  help="width to compute the preview for", dest="width", default="200"),], 
198          help="Precompute previews for the product interface columns in a table.") 
200          from gavo.web.productrender import PreviewCacheManager 
201          from twisted.internet import reactor 
202   
203          basePath = base.getConfig("inputsDir") 
204          td = base.resolveId(None, args.tableId) 
205          rows = querier.queryToDicts( 
206                  td.getSimpleQuery(["accref", "mime"])) 
207   
208          def runNext(token): 
209                  try: 
210                          row = rows.next() 
211                          res = PreviewCacheManager.getPreviewFor(row["mime"], 
212                                  [str(os.path.join(basePath, row["accref"])), str(args.width)] 
213                          ) 
214   
215                          if getattr(res, "result", None):  
216                                           
217                                  reactor.callLater(0.1, runNext, "continue") 
218                          else: 
219                                  res.addCallback(runNext) 
220                          return res 
221                  except StopIteration: 
222                          pass 
223                  except: 
224                          import traceback 
225                          traceback.print_exc() 
226                  reactor.stop() 
227                  return "" 
 228   
229          reactor.callLater(0, runNext, "startup") 
230          reactor.run() 
231   
232   
233  @exposedFunction([Arg(help="rd#table-id of the table to look at", 
234          dest="tableId")], 
235          help="Make suggestions for UCDs of columns not having one (based" 
236          " on their descriptions; this uses a GAVO web service).") 
238          import SOAPpy 
239          import urllib 
240          from gavo import api 
241           
242          wsdlURL = "http://dc.zah.uni-heidelberg.de/ucds/ui/ui/soap/go/go?wsdl" 
243          proxy = SOAPpy.WSDL.Proxy(urllib.urlopen(wsdlURL).read()) 
244          td = api.getReferencedElement(args.tableId, forceType=api.TableDef) 
245          for col in td: 
246                  if (not col.ucd or col.ucd=="XXX") and col.description: 
247                          try: 
248                                  res = [(row["score"], row["ucd"])  
249                                          for row in proxy.useService(col.description)] 
250                                  res.sort() 
251                                  res.reverse() 
252                                  print(col.name) 
253                                  for score, ucd in res: 
254                                          print("  ", ucd) 
255                          except SOAPpy.Types.faultType: 
256                                   
257                                  pass 
 258                           
259   
260  @exposedFunction([Arg(help="rd#table-id of the table of interest",  
261          dest="tableId")], 
262          help="Show the statements to create the indices on a table.") 
264          import re 
265          td = base.resolveId(None, args.tableId) 
266          for ind in td.indices: 
267                  print("\n".join(re.sub(r"\s+", " ", s) for s in ind.iterCode())) 
 268   
269   
270  @exposedFunction([Arg(help="rd#exec-id of the execute element to run (note:" 
271                  " the title won't work, you have to give the thing an id to use adm exec).", 
272          dest="execId")], 
273          help="Execute the contents of an RD execute element.  You must" 
274          " give that element an explicit id in order to make this work.") 
280   
281   
282  @exposedFunction([Arg(help="Package resource path" 
283          " (like '/inputs/__system__/scs.rd); for system RDs, the special" 
284          " //rd-id syntax is supported.", 
285          dest="path")], 
286          help="Dump the source of a distribution file; this is useful when you want" 
287          " to override them and you are running DaCHS from a zipped egg") 
289          import pkg_resources 
290          if args.path.startswith("//"): 
291                  args.path = "inputs/__system__"+args.path[1:]+".rd" 
292          with pkg_resources.resource_stream('gavo', "resources/"+args.path) as f: 
293                  sys.stdout.write(f.read()) 
 294   
295   
296  @exposedFunction([Arg(help="XML file", dest="path")], 
297          help="Validate a file against built-in VO schemas and with built-in" 
298                  " schema validator.") 
306   
307   
308  @exposedFunction([Arg(help="IVOID to mark as deleted", dest="ivoid")], 
309          help="Add a registry entry for a deleted record with IVOID.  You should" 
310                  " not usually have to do this, except when you added an identifier" 
311                  " meta item to a service that was already published without also" 
312                  " changing its XML id.") 
316   
317   
318  @exposedFunction([], help="Update the TAP_SCHEMA metadata for all" 
319          " RDs mentioned in TAP_SCHEMA.") 
325   
328          with base.AdhocQuerier(base.getWritableAdminConn) as querier: 
329                  args = makeCLIParser(globals()).parse_args() 
330                  args.subAction(querier, args) 
 331