j@279
|
1 (cl:in-package #:amuse-database-admin)
|
j@279
|
2
|
j@287
|
3 (defvar *amuse-database* nil
|
j@287
|
4 "The default AMuSE-wide database connection is assigned to this
|
j@287
|
5 variable. If for any reason, such as testing database interaction,
|
j@287
|
6 you do not wish to use the default database, this variable can be
|
j@287
|
7 shadowed locally within a particular backend package. For this to
|
j@287
|
8 actually work consistantly, all clsql database functions should
|
j@287
|
9 specify *amuse-database* explicitally as the :database argument. Not
|
j@287
|
10 doing this relies on the value of clsql:*default-database* being the
|
j@287
|
11 connection to the correct database, which in most cases will
|
j@287
|
12 actually be fine so long as you are not connecting to different
|
j@287
|
13 databases.")
|
j@279
|
14
|
j@279
|
15 (defun connect-to-database (&key (database-name "amuse") username
|
j@279
|
16 use-tunnel (make-default t))
|
j@279
|
17 "Well, slightly more secure I guess. Requires that an option file
|
j@279
|
18 exists containing connection-spec s-expressions. If no such file
|
j@279
|
19 exists a skeleton file can be created by calling
|
j@279
|
20 make-db-option-file (the password still needs to be added
|
j@279
|
21 manually). The path is ~/.amuse.lisp.
|
j@279
|
22
|
j@279
|
23 A better approach might be to use something like:
|
j@279
|
24 http://www.cliki.net/trivial-configuration-parser. Or for slime to
|
j@279
|
25 prompt the user for the password something
|
j@279
|
26 like (swank::eval-in-emacs `(read-passwd \"Password: \")). However,
|
j@279
|
27 this presents other security issues.
|
j@279
|
28
|
j@279
|
29 If use-tunnel is t, then regardless of the host specified in the
|
j@279
|
30 connection-spec, it will be set to localhost. It is assumed that the
|
j@279
|
31 tunnel is already set up.
|
j@279
|
32
|
j@279
|
33 When make-default is t, the newly created connection is assigned to
|
j@279
|
34 *amuse-database*. If make-default is nil, then the connection is
|
j@279
|
35 returned and is expected to be handled by the caller. This is useful
|
j@279
|
36 for connecting to different databases within individual
|
j@279
|
37 implementations (mainly for testing purposes)."
|
j@279
|
38 (if (and make-default
|
j@279
|
39 *amuse-database*
|
j@279
|
40 (clsql-mysql::is-database-open *amuse-database*))
|
j@279
|
41 (error "A default AMuSE database connection already exists:
|
j@279
|
42 ~S" (clsql:database-name *amuse-database*))
|
j@279
|
43 (let ((connection-spec (%get-connection-spec database-name
|
j@279
|
44 username)))
|
j@279
|
45 (when use-tunnel
|
j@279
|
46 (setf (car connection-spec) "127.0.0.1"))
|
j@279
|
47 (let ((connection (%get-database-connection connection-spec)))
|
j@279
|
48 (when make-default
|
j@279
|
49 (setf *amuse-database* connection))
|
j@279
|
50 connection))))
|
j@279
|
51
|
j@279
|
52 (defun disconnect-from-database (&optional (database-connection
|
j@279
|
53 *amuse-database*))
|
j@279
|
54 (clsql:disconnect :database database-connection))
|
j@279
|
55
|
j@279
|
56 (defun make-db-option-file (&key database-name host username (port "3306"))
|
j@279
|
57 (with-open-file (stream (%make-db-option-file-pathname) :direction :output)
|
j@279
|
58 (sb-ext:run-program "chmod"
|
j@279
|
59 (list "600" (namestring
|
j@279
|
60 (%make-db-option-file-pathname)))
|
j@279
|
61 :search t)
|
j@279
|
62 (princ "
|
j@279
|
63 ;;; Option file containing connection-spec s-expressions for connecting
|
j@279
|
64 ;;; to a database from within AMuSE. You can have multiple specifications,
|
j@279
|
65 ;;; but they must be uniquely identifiable by database name or a combination
|
j@279
|
66 ;;; of database and username.
|
j@279
|
67
|
j@279
|
68 ;;; You need to fill in the missing <details>." stream)
|
j@279
|
69 (format stream "~2%(~S ~S ~S \"<pwd>\" ~S)"
|
j@279
|
70 (if host host "<host>")
|
j@279
|
71 (if database-name database-name "<db-name>")
|
j@279
|
72 (if username username "<username>")
|
j@279
|
73 port))
|
j@279
|
74 (warn "You now need to manually edit ~A."
|
j@279
|
75 (namestring (%make-db-option-file-pathname))))
|
j@279
|
76
|
j@279
|
77 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
j@279
|
78 ;;; Helper functions
|
j@279
|
79
|
j@279
|
80 (defun %get-database-connection (connection-spec)
|
j@279
|
81 (clsql:connect connection-spec
|
j@279
|
82 :if-exists :old
|
j@279
|
83 :database-type :mysql))
|
j@279
|
84
|
j@279
|
85 (defun %get-connection-spec (db-name username)
|
j@279
|
86 (let ((option-file (probe-file (%make-db-option-file-pathname))))
|
j@279
|
87 (if option-file
|
j@279
|
88 (with-open-file (stream option-file)
|
j@279
|
89 (loop for connection-spec = (read stream nil)
|
j@279
|
90 while connection-spec
|
j@279
|
91 do (destructuring-bind (host db usr pwd prt)
|
j@279
|
92 connection-spec
|
j@279
|
93 (declare (ignore host pwd prt))
|
j@279
|
94 (when (equal db-name db)
|
j@279
|
95 (when (or (null username)
|
j@279
|
96 (equal username usr))
|
j@279
|
97 (return connection-spec))))
|
j@279
|
98 finally (error "No connection-spec exists matching
|
j@279
|
99 database: ~A and username: ~A" db-name username)))
|
j@279
|
100 ;; If file doesn't exist, create it.
|
j@279
|
101 (error "~A option file does not exist.
|
j@279
|
102 You need to run: amuse-database-admin:make-db-option-file."
|
j@279
|
103 (namestring (%make-db-option-file-pathname))))))
|
j@279
|
104
|
j@279
|
105 (defun %make-db-option-file-pathname ()
|
j@279
|
106 (merge-pathnames (user-homedir-pathname) ".amuse.lisp"))
|