This allows a user in non-standalone mode to make a whole new test
database, which is largely a clone of the original database.

The new db refers to the same resources (hosts), and more-or-less
safely borrows some of those hosts.

Currently we don't do anything about the queue and owner daemons.
This means that queue-daemon-based resource allocation is broken when
clients are pointed at the test db.  But non-queue-based allocation
(eg, ./mg-allocate without -U) works, and the test db can be used for
db-related experiments and even support individual ts-* scripts (other
than ts-hosts-allocate of course).

Signed-off-by: Ian Jackson <ian.jack...@eu.citrix.com>
---
v2: Do not set *Daemon{Host,Port} - move this chunk to a later patch
---
 mg-schema-test-database |  452 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 452 insertions(+)
 create mode 100755 mg-schema-test-database

diff --git a/mg-schema-test-database b/mg-schema-test-database
new file mode 100755
index 0000000..1226761
--- /dev/null
+++ b/mg-schema-test-database
@@ -0,0 +1,452 @@
+#!/bin/bash
+#
+# usages:
+#
+#
+#  ./mg-schema-test-database create [_SUFFIX] [TASK...] \
+#              [-fMINFLIGHT | -f-NUMFLIGHTS]
+#
+# does `drop' and then creates
+#   - the database    osstestdb_test_SUFFIX
+#   - a file          local-config.test-database_SUFFIX
+#
+# default for SUFFIX is your local username
+#
+# Resources owned in the main db by a task in the list of specified
+# TASKs become idle in the test copy.  Others become allocated to
+# a specially-created `owned by someone in real db' task.
+#
+#
+#  ./mg-schema-test-database drop [_SUFFIX]
+#
+# deletes your test database and removes the local-config file
+#
+#
+
+set -e -o posix ${OSSTEST_DEBUG:+-x}
+
+. ./cri-getconfig
+. ./mgi-common
+
+if [ $# -lt 1 ]; then fail "need operation"; fi
+
+cmd="$1"; shift
+
+localconfig=local-config.test-database
+
+maindbname=$(perl -we '
+       use Osstest;
+       use Osstest::Executive;
+       use DBI;
+       csreadconfig();
+       print $dbh_tests->{pg_db},"\n"
+            or die $!;
+')
+
+parse_only_suffix () {
+       for arg in "$@"; do
+               case "$arg" in
+               _*)     suffix="$arg" ;;
+               *)      fail 'bad usage' ;;
+               esac
+       done
+}
+
+dbname () {
+       dbname="${maindbname}_test$suffix"
+       t="tmp/testdb$suffix"
+       tcfg=local-config.test-database$suffix
+}
+
+psql_query_internal () {
+       $(get_psql_cmd) -At -R' ' -f- "$@"
+}
+
+psql_query () {
+        if [ x$OSSTEST_DEBUG != x ]; then
+               tee /dev/stderr | psql_query_internal "$@"
+       else
+               psql_query_internal "$@"
+       fi
+}
+
+psql_do_cmd () {
+       echo "$(get_psql_cmd) ${OSSTEST_DEBUG:+-e -a}" 
+}
+
+psql_do () {
+       $(psql_do_cmd) -q -f- "$@"
+}
+
+moretasks () {
+       local ifnone="$1"; shift
+       local where="$1"; shift
+       local r
+       r=$(
+               psql_query "$@" <<END
+                       SELECT taskid
+                         FROM tasks
+                        $where
+END
+       )
+       if [ "x$r" = x ]; then
+               local m="no tasks matched \`$arg'"
+               case $ifnone in
+               error)
+                       fail "error: $m"
+                       ;;
+               warning)
+                       echo >&2 "warning: $m"
+                       ;;
+               *)
+                       fail-bad-moretasks-ifnone-"$ifnone"
+                       ;;
+               esac
+       fi
+
+       tasks+=" $r"
+}
+
+withtest () {
+       OSSTEST_CONFIG="$test_cfg_setting" "$@"
+}
+
+each_copy_table () {
+       local tab=$1; shift
+       local cond=$1; shift
+
+       p=$t.tabledata.$tab
+       rm -f $p
+
+       cat <<END >>$t.export
+               \\COPY (SELECT * FROM $tab WHERE $cond) TO $p $copyhow
+END
+       cat <<END >>$t.import
+               \\COPY $tab FROM $p $copyhow
+END
+}
+
+make_xdbref_task () {
+       local refkey=$1; shift
+       local comment=$1; shift
+       local refinfo=$1; shift
+       echo "
+               INSERT INTO tasks
+                       (type, refkey, username, comment, live, refinfo)
+                 VALUES ('xdbref','$refkey','$username@$nodename',
+                         '$comment','t','$refinfo');
+       "
+}
+
+taskid () {
+       local type=$1; shift
+       local refkey=$1; shift
+       local xcond=$1
+       echo "(SELECT taskid FROM tasks WHERE
+               type='$type' AND refkey='$refkey' $xcond)"
+}
+borrowtaskid () {
+       local bt=$1
+       taskid xdbref $dbname "
+               AND live AND refinfo IS NOT NULL AND refinfo='$bt'
+       "
+}
+
+username=`whoami`
+nodename=`uname -n`
+suffix=_$username
+invocation_now=`date +%s`
+
+case "$cmd" in
+
+#========== CREATE ==========
+
+create)
+       #---------- argument parsing ----------
+
+       tasks=''
+       minflight=-1000
+       for arg in "$@"; do
+               case "$arg" in
+               *@*)
+                       moretasks warning                       \
+                               "WHERE type = 'static'
+                                  AND refkey LIKE :'pattern'"  \
+                               -v pattern="${arg//\*/%}"       \
+                       ;;
+               *" "*" "*)
+                       local rhs="${arg#* }"
+                       moretasks error                         \
+                               "WHERE taskid = :'taskid'
+                                  AND type = :'type'
+                                  AND refkey = :'refkey'"      \
+                               -v taskid="${arg%% *}"          \
+                               -v type="${rhs%% *}"            \
+                               -v refkey="${rhs#* }"
+                       ;;
+               _)      suffix="$arg"
+                       ;;
+               -f*)    minflight="${arg#-f}"
+                       ;;
+               *)      fail "bad arg to create"
+                       ;;
+               esac
+       done
+
+       if [ "x$tasks" = x ]; then
+               moretasks error                                 \
+                       "WHERE type = 'static'
+                          AND refkey = :'refkey'"              \
+                       -v refkey="$(whoami)@$(uname -n)"
+       fi
+
+       tasks_cond=${tasks// / OR T=}
+       tasks_cond=${tasks_cond# OR }
+
+       case "$minflight" in
+       -*)
+               minflight=$( psql_query <<END
+                        SELECT flight FROM
+                                (SELECT flight FROM flights
+                                        ORDER BY flight DESC
+                                        LIMIT ${minflight#-})
+                               AS last
+                                ORDER BY FLIGHT ASC
+                                LIMIT 1
+END
+               )
+               ;;
+       esac
+
+       #---------- preparation and data-gathering ----------
+
+       bad=$(  psql_query <<END
+               SELECT * FROM tasks WHERE (${tasks_cond//T/taskid})
+                               AND NOT live
+END
+       )
+       case "$bad" in
+       *[0-9]*)
+               fail "Borrowing from NON-LIVE TASKS $bad"
+               ;;
+       esac
+
+       # drop any previous test db
+       "$0" drop $suffix
+
+       dbname
+
+       printf "Setting up %s (minflight=%d, tasks=%s)...\n" \
+               $dbname "$minflight" "${tasks# }"
+
+       # create the config overlay
+       perl >$tcfg.tmp -we '
+               use Osstest;
+               use Osstest::Executive;
+               use DBI;
+               csreadconfig();
+               print "ExecutiveDbname_osstestdb ".
+                       "dbname='$dbname';".
+                       "host=$dbh_tests->{pg_host};".
+                       "user=$dbh_tests->{pg_user};".
+                       "port=$dbh_tests->{pg_port}\n"
+                       or die $!;
+       '
+       mv -f $tcfg.tmp $tcfg
+
+       # this makes `withtest' work
+       test_cfg_setting="$(perl -we '
+                       use Osstest;
+                       print globalconfigfiles() or die $!;
+               '):$tcfg"
+
+       # Extract the schema for reference
+       $(get_pgdump_cmd) -s -O -x >$t.schema
+
+       # Keep a copy as it came from dump, for comparison
+       cp $t.schema $t.schema.orig
+
+       # http://www.postgresql.org/message-id/26790.1306355...@sss.pgh.pa.us
+       perl -i~ -pe '
+               s/^/--/ if
+                       m/^CREATE EXTENSION IF NOT EXISTS plpgsql / ||
+                       m/^COMMENT ON EXTENSION plpgsql /;
+       ' $t.schema
+
+       printf "Tables:"
+
+       # What tables are there ?
+       perl -ne <$t.schema >$t.tablevars '
+               if (m/^CREATE SEQUENCE (\w+)/) {
+                       print "sequences+=\" $1\"\n";
+               } elsif (m/^CREATE TABLE (\w+)/) {
+                       $table=$1;
+               } elsif (m/^\s*flight\s+integer/) {
+                       print "ftables+=\" $table\"\n";
+               } elsif ($table && m/^\)\;$/) {
+                       print "tables+=\" $table\"\n";
+               }
+       '
+
+       . $t.tablevars
+
+       >$t.tablesortlist
+
+       for table in $tables; do
+               LC_MESSAGES=C $(get_psql_cmd) <<END >$t.display.$table
+                       \d $table
+END
+               echo >>$t.tablesortlist "$table $table"
+               perl -ne <$t.display.$table >>$t.tablesortlist '
+                       next unless m/^Foreign-key constraints:/ ... m/^\S/;
+                       next if m/DEFERRABLE/;
+                       next unless m/FOREIGN KEY.*REFERENCES (\w+)/;
+                       print "$1 '"$table"'\n" or die $!;
+               '
+               printf " $table"
+       done
+
+       tables=$(tsort <$t.tablesortlist)
+
+       # We don't want to set the permissions
+       perl <executive-postgresql-schema >$t.new-schema -pe '
+               s/^/--/ if
+                       m/^ALTER TABLE .* OWNER TO / ||
+                       m/^GRANT |^REVOKE /
+       '
+
+       #---------- create test db ----------
+
+       psql_do <<END
+               CREATE DATABASE $dbname;
+END
+       $(withtest get_psql_cmd) -q -f $t.new-schema
+
+       printf ".\n"
+
+       # Schema should now be identical to main DB
+       $(withtest get_pgdump_cmd) -s -O -x >$t.schema.created
+       diff -u $t.schema.orig $t.schema.created
+
+       #---------- mark resources that we are going to borrow ----------
+
+       for task in $tasks; do
+               psql_do <<END
+                       BEGIN;
+                       $(make_xdbref_task $dbname 'borrowed for test db' $task)
+                       UPDATE resources SET owntaskid = $(borrowtaskid $task)
+                               WHERE owntaskid=$task;
+                       COMMIT;
+END
+       done
+
+       #---------- copy data from live to test db ----------
+
+       copyhow="CSV HEADER NULL e'\\\\n'"
+
+       rm -f $t.import $t.export
+
+       cat >>$t.import <<END
+               \o $t.import-output
+               BEGIN;
+               SET CONSTRAINTS ALL DEFERRED;
+END
+
+       $(get_pgdump_cmd) -a -O -x ${sequences// / -t } >$t.sequences-import
+       perl <$t.sequences-import >>$t.import -ne '
+               next if m/^--/;
+               next if m/^SET /;
+               next unless m/\S/;
+               print or die $!;
+       '
+
+       for table in $tables; do
+               case " $ftables " in
+               *" $table "*)   condition="flight >= $minflight" ;;
+               *)              condition="1=1" ;;
+               esac
+               each_copy_table $table "$condition"
+       done
+
+       # As we copy, we note everything we're not borrowing as
+       # belonging to the parent db.
+       cat >>$t.import <<END
+               $(make_xdbref_task $maindbname 'not borrowed' '')
+               UPDATE resources
+                       SET owntaskid = $(taskid xdbref $maindbname)
+                       WHERE owntaskid != $(borrowtaskid $task);
+               COMMIT;
+END
+
+       printf "Copy..."
+
+       printf "export..."
+       $(psql_do_cmd) -f $t.export
+
+       printf "import..."
+       $(withtest psql_do_cmd) -f $t.import
+
+       rm -f $t.tabledata.*
+
+       #---------- actually borrow resources ----------
+
+       printf "borrow..."
+
+       for task in $tasks; do
+               withtest psql_do <<END
+                       BEGIN;
+                       UPDATE resources
+                               SET owntaskid = $(taskid magic idle)
+                               WHERE owntaskid = $(borrowtaskid $task);
+                       COMMIT;
+END
+       done
+       withtest psql_do <<END
+               DELETE FROM tasks
+                       WHERE type='xdbref' AND refkey='$dbname';
+END
+
+       printf "\n"
+
+       cat <<END
+Test database $dbname now set up.
+export OSSTEST_CONFIG=$test_cfg_setting
+END
+       ;;
+
+#========== DROP ==========
+
+drop)
+       parse_only_suffix "$@"
+
+       dbname
+
+       printf "Dropping %s.\n" "$dbname"
+
+       psql_do <<END
+                SET client_min_messages = WARNING;
+               DROP DATABASE IF EXISTS $dbname;
+               UPDATE resources
+                       SET owntaskid = CAST(tasks.refinfo AS INTEGER)
+                       FROM tasks
+                       WHERE resources.owntaskid = tasks.taskid
+                          AND tasks.type = 'xdbref'
+                         AND tasks.refkey = '$dbname'
+                         AND tasks.live
+                         AND tasks.refinfo IS NOT NULL;
+               UPDATE tasks
+                       SET live = 'f'
+                       WHERE tasks.type = 'xdbref'
+                         AND tasks.refkey = '$dbname';
+END
+
+       rm -f $tcfg
+
+       ;;
+
+#========== EPILOGUE ==========
+
+*)
+       fail "unknown operation \`$cmd'"
+       ;;
+esac
-- 
1.7.10.4


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
http://lists.xen.org/xen-devel

Reply via email to