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