All of lore.kernel.org
 help / color / mirror / Atom feed
From: Ian Jackson <ian.jackson@eu.citrix.com>
To: xen-devel@lists.xenproject.org
Cc: Ian Jackson <Ian.Jackson@eu.citrix.com>,
	Ian Campbell <ian.campbell@citrix.com>
Subject: [OSSTEST PATCH 09/16] mg-schema-test-database: New script
Date: Mon, 7 Dec 2015 17:27:27 +0000	[thread overview]
Message-ID: <1449509254-27007-10-git-send-email-ian.jackson@eu.citrix.com> (raw)
In-Reply-To: <1449509254-27007-1-git-send-email-ian.jackson@eu.citrix.com>

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.Jackson@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.1306355327@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

  parent reply	other threads:[~2015-12-07 17:27 UTC|newest]

Thread overview: 27+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-12-07 17:27 (no subject) Ian Jackson
2015-12-07 17:27 ` [OSSTEST PATCH 01/16] tcl daemons: log host and port number we bind to, at startup Ian Jackson
2015-12-07 17:27 ` [OSSTEST PATCH 02/16] cri-getconfig: Break out exec_resetting_sigint Ian Jackson
2015-12-07 17:27 ` [OSSTEST PATCH 03/16] Configuration: No longer set password=<~/.xen-osstest/db-password> Ian Jackson
2015-12-07 17:27 ` [OSSTEST PATCH 04/16] mg-debug-fail: New utility script for debugging Ian Jackson
2015-12-07 17:27 ` [OSSTEST PATCH 05/16] mg-debug-fail: Catch attempts to read from a tty Ian Jackson
2015-12-07 17:27 ` [OSSTEST PATCH 06/16] cri-getconfig: Provide get_psql_cmd and get_pgdump_cmd Ian Jackson
2015-12-07 17:27 ` [OSSTEST PATCH 07/16] cri-getconfig: Provide debugging for get_psql_cmd Ian Jackson
2015-12-07 17:27 ` [OSSTEST PATCH 08/16] Osstest.pm: Break out and export globalconfigfiles Ian Jackson
2015-12-07 17:27 ` Ian Jackson [this message]
2015-12-08 11:06   ` [OSSTEST PATCH 09/16] mg-schema-test-database: New script Ian Campbell
2015-12-07 17:27 ` [OSSTEST PATCH 10/16] mg-schema-test-database: Move setting of test_cfg_setting to dbname Ian Jackson
2015-12-07 17:27 ` [OSSTEST PATCH 11/16] mg-schema-test-database: Sort out daemons; provide `daemons' subcommand Ian Jackson
2015-12-08 11:06   ` Ian Campbell
2015-12-07 17:27 ` [OSSTEST PATCH 12/16] Configuration: Introduce $c{Username} Ian Jackson
2015-12-08 11:07   ` Ian Campbell
2015-12-08 11:18   ` Ian Campbell
2015-12-07 17:27 ` [OSSTEST PATCH 13/16] mg-schema-test-database: Change username for back-to-main-db xref Ian Jackson
2015-12-08 11:09   ` Ian Campbell
2015-12-08 14:21     ` Ian Jackson
2015-12-07 17:27 ` [OSSTEST PATCH 14/16] mg-schema-test-database: Bump flight sequence number in test DB Ian Jackson
2015-12-08 11:10   ` Ian Campbell
2015-12-07 17:27 ` [OSSTEST PATCH 15/16] mg-schema-test-database: Safety catch in JobDB database open Ian Jackson
2015-12-08 11:16   ` Ian Campbell
2015-12-08 14:24     ` Ian Jackson
2015-12-07 17:27 ` [OSSTEST PATCH 16/16] mg-schema-test-database: Add workflow doc comment Ian Jackson
2015-12-08 11:19   ` Ian Campbell

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1449509254-27007-10-git-send-email-ian.jackson@eu.citrix.com \
    --to=ian.jackson@eu.citrix.com \
    --cc=ian.campbell@citrix.com \
    --cc=xen-devel@lists.xenproject.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.