aboutsummaryrefslogtreecommitdiffstats
path: root/pgaas
diff options
context:
space:
mode:
authorlj1412 <lji@research.att.com>2017-02-14 15:10:09 +0000
committerlj1412 <lji@research.att.com>2017-02-14 15:10:11 +0000
commit7927ff179242b796330d17869c83fa07751abf95 (patch)
treeba2b93e26ec71bff863bc7be9fb5dbd0b5d9c928 /pgaas
parentd1bf35c127a238238b573103edf7dbcb1ebd48ed (diff)
Init dcae.pgaas
Change-Id: Ieef6b600f4cbb0bf4ee3910c1bfc6b36773cd2d2 Signed-off-by: lj1412 <lji@research.att.com>
Diffstat (limited to 'pgaas')
-rwxr-xr-xpgaas/src/common/postinst55
-rw-r--r--pgaas/src/makefile41
-rw-r--r--pgaas/src/repackage.json25
-rwxr-xr-xpgaas/src/stage/opt/app/pgaas/bin/check_cluster154
-rwxr-xr-xpgaas/src/stage/opt/app/pgaas/bin/dcae_admin_db.py819
-rwxr-xr-xpgaas/src/stage/opt/app/pgaas/bin/in.json97
-rwxr-xr-xpgaas/src/stage/opt/app/pgaas/bin/isrw28
-rwxr-xr-xpgaas/src/stage/opt/app/pgaas/bin/list_masters43
-rw-r--r--pgaas/src/stage/opt/app/pgaas/bin/makefile47
-rwxr-xr-xpgaas/src/stage/opt/app/pgaas/bin/pg_ctl_promote23
-rwxr-xr-xpgaas/src/stage/opt/app/pgaas/bin/pg_ctl_restart41
-rwxr-xr-xpgaas/src/stage/opt/app/pgaas/bin/pg_ctl_start30
-rwxr-xr-xpgaas/src/stage/opt/app/pgaas/bin/pg_ctl_status23
-rwxr-xr-xpgaas/src/stage/opt/app/pgaas/bin/pg_ctl_stop23
-rw-r--r--pgaas/src/stage/opt/app/pgaas/bin/repmgrc29
-rw-r--r--pgaas/src/stage/opt/app/pgaas/bin/repmgrdc29
-rwxr-xr-xpgaas/src/stage/opt/app/pgaas/bin/runpsql30
-rwxr-xr-xpgaas/src/stage/opt/app/pgaas/bin/runpsqll30
-rwxr-xr-xpgaas/src/stage/opt/app/pgaas/bin/setpropvalue67
-rwxr-xr-xpgaas/src/stage/opt/app/pgaas/bin/show_pg_is_in_recovery19
-rwxr-xr-xpgaas/src/stage/opt/app/pgaas/bin/show_pg_stat_activity19
-rwxr-xr-xpgaas/src/stage/opt/app/pgaas/bin/show_pg_stat_archiver19
-rwxr-xr-xpgaas/src/stage/opt/app/pgaas/bin/show_pg_stat_bgwriter19
-rwxr-xr-xpgaas/src/stage/opt/app/pgaas/bin/show_pg_stat_database19
-rwxr-xr-xpgaas/src/stage/opt/app/pgaas/bin/show_pg_stat_database_conflicts19
-rwxr-xr-xpgaas/src/stage/opt/app/pgaas/bin/show_pg_stat_user_indexes19
-rwxr-xr-xpgaas/src/stage/opt/app/pgaas/bin/show_pg_stat_user_tables19
-rwxr-xr-xpgaas/src/stage/opt/app/pgaas/bin/show_pg_statio_user_functions19
-rwxr-xr-xpgaas/src/stage/opt/app/pgaas/bin/show_pg_statio_user_indexes19
-rwxr-xr-xpgaas/src/stage/opt/app/pgaas/bin/show_pg_statio_user_sequences19
-rwxr-xr-xpgaas/src/stage/opt/app/pgaas/bin/show_pg_statio_user_tables19
-rw-r--r--pgaas/src/stage/opt/app/pgaas/bin/startpsql29
-rwxr-xr-xpgaas/src/stage/opt/app/pgaas/bin/update_var_run_isrw30
-rwxr-xr-xpgaas/src/stage/opt/app/pgaas/bin/verify_pg_privileges188
-rw-r--r--pgaas/src/stage/opt/app/pgaas/etc/create_dcae_rotate.sql21
-rw-r--r--pgaas/src/stage/opt/app/pgaas/etc/dcae_admin_db.cfg2
-rw-r--r--pgaas/src/stage/opt/app/pgaas/etc/makefile25
-rw-r--r--pgaas/src/stage/opt/app/pgaas/lib/CommonLogger.py889
-rw-r--r--pgaas/src/stage/opt/app/pgaas/lib/dcae_admin_db.json42
-rw-r--r--pgaas/src/stage/opt/app/pgaas/lib/init-logger.cfg40
-rw-r--r--pgaas/src/stage/opt/app/pgaas/lib/makefile25
-rw-r--r--pgaas/src/stage/opt/app/pgaas/lib/pgaas.cfg31
-rw-r--r--pgaas/src/stage/opt/app/pgaas/makefile31
-rw-r--r--pgaas/src/stage/opt/app/pgaas/man/.gitignore1
-rw-r--r--pgaas/src/stage/opt/app/pgaas/man/check_cluster.man34
-rw-r--r--pgaas/src/stage/opt/app/pgaas/man/dcae_admin_db.man72
-rw-r--r--pgaas/src/stage/opt/app/pgaas/man/isrw.man19
-rw-r--r--pgaas/src/stage/opt/app/pgaas/man/list_masters.man30
-rw-r--r--pgaas/src/stage/opt/app/pgaas/man/makefile97
-rw-r--r--pgaas/src/stage/opt/app/pgaas/man/pg_ctl_promote.man20
-rw-r--r--pgaas/src/stage/opt/app/pgaas/man/pg_ctl_restart.man19
-rw-r--r--pgaas/src/stage/opt/app/pgaas/man/pg_ctl_start.man19
-rw-r--r--pgaas/src/stage/opt/app/pgaas/man/pg_ctl_status.man19
-rw-r--r--pgaas/src/stage/opt/app/pgaas/man/pg_ctl_stop.man19
-rw-r--r--pgaas/src/stage/opt/app/pgaas/man/repmgrc.man19
-rw-r--r--pgaas/src/stage/opt/app/pgaas/man/repmgrdc.man19
-rw-r--r--pgaas/src/stage/opt/app/pgaas/man/runpsql.man21
-rw-r--r--pgaas/src/stage/opt/app/pgaas/man/runpsqll.man22
-rw-r--r--pgaas/src/stage/opt/app/pgaas/man/setpropvalue.man26
-rw-r--r--pgaas/src/stage/opt/app/pgaas/man/show_pg_is_in_recovery.man19
-rw-r--r--pgaas/src/stage/opt/app/pgaas/man/show_pg_stat_activity.man19
-rw-r--r--pgaas/src/stage/opt/app/pgaas/man/show_pg_stat_archiver.man19
-rw-r--r--pgaas/src/stage/opt/app/pgaas/man/show_pg_stat_bgwriter.man20
-rw-r--r--pgaas/src/stage/opt/app/pgaas/man/show_pg_stat_database.man19
-rw-r--r--pgaas/src/stage/opt/app/pgaas/man/show_pg_stat_database_conflicts.man19
-rw-r--r--pgaas/src/stage/opt/app/pgaas/man/show_pg_stat_user_indexes.man19
-rw-r--r--pgaas/src/stage/opt/app/pgaas/man/show_pg_stat_user_tables.man20
-rw-r--r--pgaas/src/stage/opt/app/pgaas/man/show_pg_statio_user_functions.man19
-rw-r--r--pgaas/src/stage/opt/app/pgaas/man/show_pg_statio_user_indexes.man19
-rw-r--r--pgaas/src/stage/opt/app/pgaas/man/show_pg_statio_user_sequences.man19
-rw-r--r--pgaas/src/stage/opt/app/pgaas/man/show_pg_statio_user_tables.man19
-rw-r--r--pgaas/src/stage/opt/app/pgaas/man/startpsql.man21
-rw-r--r--pgaas/src/stage/opt/app/pgaas/man/update_var_run_isrw.man23
73 files changed, 3945 insertions, 0 deletions
diff --git a/pgaas/src/common/postinst b/pgaas/src/common/postinst
new file mode 100755
index 0000000..f24e364
--- /dev/null
+++ b/pgaas/src/common/postinst
@@ -0,0 +1,55 @@
+#!/bin/bash
+# Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this code except in compliance
+# with the License. You may obtain a copy of the License
+# at http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# permissions and limitations under the License.
+
+
+exec 1> /tmp/pgaas.out 2>&1
+set -x
+if [ -d /opt/app/postgresql-9.5.2 ]
+then export OPENECOMP=false NOTOPENECOMP=true
+else export OPENECOMP=true NOTOPENECOMP=false
+fi
+
+if $OPENECOMP
+then INSTALL_ROOT=
+fi
+
+echo STARTING $0 $(date)
+umask 0
+echo STARTING $0 $(date) >> /tmp/pgaas.inst.report
+set -x
+
+export CDFCFG=${INSTALL_ROOT}/opt/app/cdf/lib/cdf.cfg
+export PGAASCFG=${INSTALL_ROOT}/opt/app/pgaas/lib/pgaas.cfg
+
+if [ -d /opt/app/postgresql-9.5.2 ]
+then PGDIR=/opt/app/postgresql-9.5.2
+else PGDIR=/usr/lib/postgresql/9.5
+fi
+if [ -d /opt/app/postgresql-config-9.5.2/ ]
+then CFGDIR=/opt/app/postgresql-config-9.5.2
+else CFGDIR=/opt/app/postgresql-config
+fi
+
+(
+ grep '^postgres.x' < $CDFCFG | sed -e 's/^postgres/dcae_admin_db_password/'
+ echo "db_configuration=$CFGDIR/main/postgresql.conf"
+ echo "pg_bin_directory=$PGDIR/bin"
+ echo "skip_configuration_file=$CFGDIR/lib/ignore-database-reconfiguration"
+) >> $PGAASCFG
+
+echo ENDING $0 $(date)
+echo ENDING $0 $(date) >> /tmp/pgaas.inst.report
+if $NOTOPENECOMP
+then sed -n '/^STARTING/,/^ENDING/p' `dirname $0`/../../proc_out >> /tmp/pgaas.inst.report
+fi
diff --git a/pgaas/src/makefile b/pgaas/src/makefile
new file mode 100644
index 0000000..73fe4eb
--- /dev/null
+++ b/pgaas/src/makefile
@@ -0,0 +1,41 @@
+
+DEVBIN=../../bin
+PKG=pgaas
+REPACKAGESWMOPTS=
+REPACKAGEDEBIANOPTS=
+
+INS= ../install
+INSSTG= $(INS)/stage
+INSCOM= $(INS)/common
+KEEP=
+
+all:
+
+clean-stage:
+ rm -rf $(INSSTG)
+
+clean-common:
+ rm -rf $(INSCOM)
+
+clean-ins: clean-stage clean-common
+ rm -rf $(INS)
+
+clean: clean-ins
+ rm -rf *~
+
+build:
+
+stage: clean-stage
+ cd stage/opt/app/pgaas && $(MAKE) stage STAGEDIR=../../../../$(INSSTG)
+ find common ! -name makefile ! -name '*~' | cpio -pudmv $(INS)
+ cp -p repackage.* $(INS)
+
+
+debian: stage
+ repackage -b debian $(REPACKAGEDEBIANOPTS) -d $(INS) -u
+ repackage -b debian $(REPACKAGEDEBIANOPTS) -d $(INS) -u -B LATEST
+ @echo debian built
+
+upload-javadocs:
+ @echo nothing to do here
+
diff --git a/pgaas/src/repackage.json b/pgaas/src/repackage.json
new file mode 100644
index 0000000..578fe76
--- /dev/null
+++ b/pgaas/src/repackage.json
@@ -0,0 +1,25 @@
+{
+ "executionGroup": "postgres",
+ "executionUser": "postgres",
+ "applicationName": "pgaas",
+ "description": " PostgreSQL as a Service main scripts ",
+ "maintainer": "OpenECOMP <dcae@lists.openecomp.org>",
+ "fileUser": "postgres",
+ "internalDependencies": [],
+ "directoryTreeTops": {
+ "/opt": "/opt/app/pgaas"
+ },
+ "debian": {
+ "conflicts": [],
+ "groupId": "org.openecomp.dcae.storage.pgaas",
+ "replaces": [],
+ "externalDependencies": []
+ },
+ "fileGroup": "postgres",
+ "docker": {
+ "tag": "latest",
+ "externalDependencies": []
+ },
+ "version": "1.0.0",
+ "groupId": "org.openecomp.dcae.storage.pgaas"
+} \ No newline at end of file
diff --git a/pgaas/src/stage/opt/app/pgaas/bin/check_cluster b/pgaas/src/stage/opt/app/pgaas/bin/check_cluster
new file mode 100755
index 0000000..0af6d95
--- /dev/null
+++ b/pgaas/src/stage/opt/app/pgaas/bin/check_cluster
@@ -0,0 +1,154 @@
+#!/bin/bash
+# Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this code except in compliance
+# with the License. You may obtain a copy of the License
+# at http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# permissions and limitations under the License.
+
+
+# NAME
+# check_cluster - check the state of the cluster
+#
+# USAGE
+# check_cluster [-v] [-l] [-t timeout]
+# -l do not check localhost first (and restarting the service if necessary)
+# -t timeout set how long to wait when accessing the servers
+# -v verbose
+#
+# DESCRIPTION
+# Loop through the nodes in the cluster, using pgwget to determine how many are masters, secondaries, or not up.
+# Complain about certain situations.
+# If there are multiple masters, and this not the first master in the list, then:
+# run pg_ctl_restart
+# prevent /ro from returning true
+
+CDF=/opt/app/cdf
+if [ -d /opt/app/postgresql-9.5.2 ]
+then PGDIR=/opt/app/postgresql-9.5.2
+else PGDIR=/usr/lib/postgresql/9.5
+fi
+if [ -d /opt/app/postgresql-config-9.5.2/ ]
+then CFGDIR=/opt/app/postgresql-config-9.5.2/
+else CFGDIR=/opt/app/postgresql-config/
+fi
+PATH=$PGDIR/bin:$CDF/bin:/opt/app/pgaas/bin:/opt/app/postgresql-prep/bin:$PATH
+
+usage()
+{
+ exec 1>&2
+ [ $# -gt 0 ] && echo "$@"
+ echo "Usage: $0 [-v] [-l] [-t timeout]"
+ echo -e " -l do not check localhost first (and restarting the service if necessary)"
+ echo -e " -t timeout set how long to wait when accessing the servers"
+ echo -e " -v verbose"
+ exit 1
+}
+
+VERBOSE=false
+TIMEOUT=10
+TESTLOCAL=:
+while getopts lt:v c
+do
+ case "$c" in
+ l ) TESTLOCAL=false ;;
+ t ) TIMEOUT=$OPTARG ;;
+ v ) VERBOSE=: ;;
+ \?) usage ;;
+ esac
+done
+shift $(($OPTIND - 1))
+
+# loop through the nodes in the cluster, using pgwget to determine if any are a master. Save in $@
+master_count=0
+secondary_count=0
+total_count=0
+down_count=0
+
+DOWNS=
+MASTERS=
+SECONDARIES=
+
+MSEP=
+SSEP=
+DSEP=
+HOSTNAME=$(hostname -f)
+FOUNDPREVIOUSMASTER=
+DOPGCTLSTOP=
+
+if $TESTLOCAL
+then
+ isrw=`pgwget --tries=1 --read-timeout=$TIMEOUT --quiet -O/dev/stdout http://localhost:8000/isrw`
+ case "$isrw" in
+ Master | Secondary ) ;;
+ * )
+ echo "$(date)|WARNING|RESTARTED|Local iDNS-responder.py not responding. Restarting."
+ ps -fu postgres | grep "python3 /opt/app/postgresql-prep/bin/iDNS-responder.py" | grep -v grep | awk '{print "kill " $2}' | sh
+ sleep 10
+ ;;
+ esac
+fi
+
+for i in $(getpropvalue -n pgnodes | sed 's/|/ /g')
+do
+ $VERBOSE && echo -n "Checking $i"
+ isrw=`pgwget --tries=1 --read-timeout=10 --quiet -O/dev/stdout http://$i:8000/isrw`
+ $VERBOSE && echo ": $isrw"
+ case "$isrw" in
+ Master )
+ (( master_count = master_count + 1 ))
+ (( total_count = total_count + 1 ))
+ MASTERS="$MASTERS$MSEP$i"
+ MSEP=" "
+ if [ -z "$FOUNDPREVIOUSMASTER" ]
+ then FOUNDPREVIOUSMASTER=yes
+ elif [ -n "$FOUNDPREVIOUSMASTER" -a "$i" = $HOSTNAME ]
+ then DOPGCTLSTOP=yes
+ fi
+ ;;
+ Secondary )
+ (( secondary_count = secondary_count + 1 ))
+ (( total_count = total_count + 1 ))
+ SECONDARIES="$SECONDARIES$SSEP$i"
+ SSEP=" "
+ ;;
+ * )
+ DOWNS="$DOWNS$DSEP$i"
+ DSEP=" "
+ (( down_count = down_count + 1 ))
+ (( total_count = total_count + 1 ))
+ ;;
+ esac
+done
+
+(( up_count = master_count + secondary_count ))
+
+date=$(date)
+echo "$date|INFO|masters=$master_count $MASTERS|secondaries=$secondary_count $SECONDARIES|down=$down_count $DOWNS|"
+
+FORCEROOFF=/var/run/postgresql/force-ro-off
+if [ $master_count -lt 1 ]
+then echo "$date|FATAL|NOMASTER|NO MASTER FOUND|"
+elif [ $master_count -gt 1 ]
+then echo "$date|FATAL|MULTIPLEMASTERS|TOO MANY MASTERS FOUND|"
+ if [ -n "$DOPGCTLSTOP" ]
+ then
+ touch "$FORCEROOFF"
+ pg_ctl_stop
+ fi
+fi
+if [ -z "$DOPGCTLSTOP" -a -f "$FORCEROOFF" ]
+then rm -f "$FORCEROOFF"
+fi
+if [ $up_count -eq 0 ]
+then echo "$date|FATAL|NOREADER|NO SECONDARY FOUND"
+fi
+if [ $down_count -ne 0 ]
+then echo "$date|ERROR|DOWN|One or more systems are down: $DOWNS"
+fi
diff --git a/pgaas/src/stage/opt/app/pgaas/bin/dcae_admin_db.py b/pgaas/src/stage/opt/app/pgaas/bin/dcae_admin_db.py
new file mode 100755
index 0000000..80da148
--- /dev/null
+++ b/pgaas/src/stage/opt/app/pgaas/bin/dcae_admin_db.py
@@ -0,0 +1,819 @@
+#!/usr/bin/python3
+# -*- indent-tabs-mode: nil -*-
+# Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this code except in compliance
+# with the License. You may obtain a copy of the License
+# at http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# permissions and limitations under the License.
+
+
+"""
+
+NAME
+ dcae_admin_db.py - given a database description json file, update the current VM accordingly
+
+USAGE
+ dcae_admin_db.py [options] configurationChanged json-file
+ dcae_admin_db.py [options] suspend
+ dcae_admin_db.py [options] resume
+ dcae_admin_db.py [options] test
+
+ options:
+
+ -H / --dbhost= - host name, defaults to CFG['dcae_admin_db_hostname']
+ -d / --dbdir= - database directory path, defaults to CFG['db_directory']
+ -c / --dbconf= - database configuration path, defaults to CFG['db_configuration']
+ -D / --dbname= - database name, defaults to CFG['dcae_admin_db_databasename']
+ -U / --user= - user to login as, defaults to CFG['dcae_admin_db_username']
+ -P / --password= - password for user, defaults to CFG['dcae_admin_db_password']
+ -B / --bindir= - postgresql bin directory, defaults to CFG['pg_bin_directory']
+ -i / --ignorefile= - skip configuration if this file is present, defaults to CFG['skip_configuration_file']
+ -n / --nocreate - do not create the databases / users
+ -I / --ignoredb - ignore current state of database
+ -R / --remove - remove old databases / users
+ -J / --jsontop= - top of json tree, as in \"['pgaas']\"
+ -e / --errors= - where to redirect error output, defaults to CFG['dcae_admin_db_errors_file'] then stderr
+ -t / --trace= - where to redirect trace output, defaults to CFG['dcae_admin_db_trace_file'] then stderr
+ -v / --verbose - verbose, defaults to CFG['dcae_admin_db_verbosity']
+
+DESCRIPTION
+ This program is intended to be executed by the DCAE controller manager.
+
+When creating a database and set of users, execute the equivalent of this:
+
+ CREATE USER tstdb_admin WITH PASSWORD 'tst';
+ CREATE USER tstdb_user WITH PASSWORD 'tst';
+ CREATE USER tstdb_viewer WITH PASSWORD 'tst';
+
+ CREATE ROLE testdb_common_user_role;
+ CREATE ROLE testdb_common_viewer_role;
+
+ CREATE DATABASE testdb with owner tstdb_admin;
+
+ \connect testdb
+
+ REVOKE ALL on DATABASE testdb FROM testdb_common_viewer_role;
+ REVOKE ALL on DATABASE testdb FROM testdb_common_user_role;
+ REVOKE ALL on DATABASE testdb FROM tstdb_user;
+ REVOKE ALL on DATABASE testdb FROM tstdb_viewer;
+
+ GRANT testdb_common_viewer_role TO testdb_common_user_role; /* user can do everything viewer can */
+ GRANT testdb_common_user_role TO tstdb_admin; /* admin can do everything user and viewer can */
+
+ GRANT CONNECT ON DATABASE testdb TO testdb_common_viewer_role; /* viewer, user, admin can connect */
+
+ CREATE SCHEMA testdb_db_common AUTHORIZATION tstdb_admin; /* create a schema we can optionally use */
+
+ ALTER ROLE tstdb_admin IN DATABASE testdb SET search_path = public, testdb_db_common; /* search_path is not inherited, so set it here */
+ ALTER ROLE testdb_common_user_role IN DATABASE testdb SET search_path = public, testdb_db_common; /* search_path is not inherited, so set it here */
+ ALTER ROLE testdb_common_viewer_role IN DATABASE testdb SET search_path = public, testdb_db_common; /* search_path is not inherited, so set it here */
+
+ GRANT USAGE ON SCHEMA testdb_db_common TO testdb_common_viewer_role; /* viewer,user can select from schema */
+ GRANT CREATE ON SCHEMA testdb_db_common TO tstdb_admin; /* admin can create on schema */
+
+ ALTER DEFAULT PRIVILEGES FOR ROLE tstdb_admin GRANT SELECT ON TABLES TO testdb_common_viewer_role; /* viewer, user, admin can select on tables */
+ ALTER DEFAULT PRIVILEGES FOR ROLE tstdb_admin GRANT INSERT, UPDATE, DELETE, TRUNCATE ON TABLES TO testdb_common_user_role; /* user, admin can ins/upd/del/tru on tables */
+ ALTER DEFAULT PRIVILEGES FOR ROLE tstdb_admin GRANT USAGE, SELECT, UPDATE ON SEQUENCES TO testdb_common_user_role; /* user, admin can update on sequences */
+
+ GRANT TEMP ON DATABASE testdb TO testdb_common_user_role; /* user, admin can create temp tables */
+
+ GRANT testdb_common_user_role TO tstdb_user;
+ GRANT testdb_common_viewer_role TO tstdb_viewer;
+ ALTER ROLE tstdb_user IN DATABASE testdb SET search_path = public, testdb_db_common; /* search_path is not inherited, so set it here */
+ ALTER ROLE tstdb_viewer IN DATABASE testdb SET search_path = public, testdb_db_common; /* search_path is not inherited, so set it here */
+
+"""
+
+import getopt
+import psycopg2
+import sys
+import re
+import subprocess
+import json
+import os
+import time
+
+sys.path.append("/opt/app/pgaas/lib")
+import CommonLogger
+
+verbose = 0
+quiet = False
+errorOutput = sys.stderr
+traceOutput = sys.stderr
+errorLogger = debugLogger = auditLogger = metricsLogger = None
+
+def usage(msg = None):
+ """
+ Print a usage message and exit
+ """
+ sys.stdout = sys.stderr
+ if msg != None:
+ print(msg)
+ print("Usage:")
+ print("dcae_admin_db.py [options] configurationChanged json-file")
+ print("dcae_admin_db.py [options] suspend")
+ print("dcae_admin_db.py [options] resume")
+ print("dcae_admin_db.py [options] test")
+ print("")
+ print("options:")
+ print("-H / --dbhost= - host name, defaults to CFG['dcae_admin_db_hostname']")
+ print("-d / --dbdir= - database directory path, defaults to CFG['db_directory']")
+ print("-c / --dbconf= - database directory path, defaults to CFG['db_configuration']")
+ print("-D / --dbname= - database name, defaults to CFG['dcae_admin_db_databasename']")
+ print("-n / --nocreate - do not create the databases / users")
+ print("-I / --ignoredb - ignore current state of database")
+ print("-U / --user= - user to login as, defaults to CFG['dcae_admin_db_username']")
+ print("-P / --password= - password for user, defaults to CFG['dcae_admin_db_password']")
+ print("-B / --bindir= - postgresql bin directory, defaults to CFG['pg_bin_directory']")
+ print("-i / --ignorefile= - skip configuration if this file is present, defaults to CFG['skip_configuration_file']")
+ print("-R / --remove - remove old databases / users")
+ print("-J / --jsontop= - top of json tree, as in \"['pgaas']\"")
+ print("-l / --logcfg= - ECOMP DCAE Common Logging configuration file")
+ print("-e / --errors= - where to redirect error output, defaults to CFG['dcae_admin_db_errors_file'] then stderr")
+ print("-t / --trace= - where to redirect trace output, defaults to CFG['dcae_admin_db_trace_file'] then stderr")
+ print("-v - verbose")
+ sys.exit(2)
+
+def checkOption(options, name, propname, optletter, encrypted=False, cdfPropname = None):
+ """
+ Check if the specified option exists. If not, grab it from the configuration file.
+ Complain if it still does not exist.
+ """
+ if name not in options:
+ ret = getPgaasPropValue(propname, encrypted=encrypted, dflt=None, skipComplaining=True)
+ if ret is None and cdfPropname is not None:
+ ret = getCdfPropValue(cdfPropname, encrypted=encrypted)
+ options[name] = ret
+ requireOption("either %s or config[%s]" % (optletter, propname), options[name])
+
+def reviewOpts():
+ """
+ Parse the options passed to the command, and return them in the dictionary
+ """
+ try:
+ opts, args = getopt.getopt(sys.argv[1:], "B:c:D:d:e:H:IJ:l:nP:Rt:U:hv?",
+ [ "dbhost=", "dbdir=", "dbconf=",
+ "dbname=", "dbuser=", "dbpassword=",
+ "bindir=", "errors=", "trace=", "logcfg=",
+ "nocreate", "ignoredb", "remove", "ignorefile=",
+ "jsontop=",
+ "help", "verbose"])
+ except getopt.GetoptError as err:
+ usage(str(err))
+
+ propVerbosity = getPgaasPropValue("dcae_admin_db_verbosity", dflt='0')
+ if propVerbosity is not None:
+ global verbose
+ verbose = int(propVerbosity)
+ retOptions = { }
+ ignoreFile = getPgaasPropValue("skip_configuration_file", dflt=None)
+ for o, a in opts:
+ if o in ("-v", "--verbose"):
+ # global verbose
+ verbose += 1
+ elif o in ("-c", "--dbconf"):
+ retOptions["dbconf"] = a
+ elif o in ("-H", "--dbhost"):
+ retOptions["dbhost"] = a
+ elif o in ("-d", "--dbdir"):
+ retOptions["dbdir"] = a
+ elif o in ("-D", "--dbname"):
+ retOptions["dbname"] = a
+ elif o in ("-U", "--dbuser"):
+ retOptions["dbuser"] = a
+ elif o in ("-P", "--dbpassword"):
+ retOptions["dbpassword"] = a
+ elif o in ("-B", "--bindir"):
+ retOptions["bindir"] = a
+ elif o in ("-n", "--nocreate"):
+ retOptions["nocreate"] = True
+ elif o in ("-I", "--ignoredb"):
+ retOptions["ignoredb"] = True
+ elif o in ("-R", "--remove"):
+ retOptions["noremove"] = True
+ elif o in ("-J", "--jsontop"):
+ retOptions["jsontop"] = a
+ elif o in ("-l", "--logcfg"):
+ retOptions["logcfg"] = a
+ elif o in ("-e", "--errors"):
+ retOptions["errors"] = a
+ elif o in ("-i", "--ignorefile"):
+ ignoreFile = a
+ elif o in ("-t", "--trace"):
+ retOptions["trace"] = a
+ elif o in ("-h", "--help"):
+ usage()
+ else:
+ usage("unhandled option: %s" % o)
+ if "errors" not in retOptions:
+ retOptions["errors"] = getPgaasPropValue("dcae_admin_db_errors_file")
+ if "errors" in retOptions and retOptions["errors"] is not None:
+ try:
+ errorOutput = open(retOptions["errors"], "a")
+ except Exception as e:
+ die("Cannot open errors file '%s': %s" % (retOptions["errors"], e))
+ if ignoreFile is not None:
+ trace("checking to see if skip_configuration_file(%s) exists" % ignoreFile)
+ retOptions["ignorefile"] = "yes" if os.path.isfile(ignoreFile) else "no"
+ trace("ignorefile=%s" % retOptions["ignorefile"])
+ else:
+ retOptions["ignorefile"] = None
+ if "trace" not in retOptions:
+ retOptions["trace"] = getPgaasPropValue("dcae_admin_db_trace_file")
+ if "trace" in retOptions and retOptions["trace"] is not None:
+ try:
+ traceOutput = open(retOptions["trace"], "a")
+ except Exception as e:
+ die("Cannot open trace file '%s': %s" % (retOptions["trace"], e))
+ if "logcfg" not in retOptions:
+ retOptions["logcfg"] = getPgaasPropValue("dcae_admin_db_common_logger_config")
+ if "logcfg" in retOptions and retOptions["logcfg"] is not None:
+ logcfg = retOptions["logcfg"]
+ import uuid
+ instanceUUID = uuid.uuid1()
+ serviceName = "DCAE/pgaas"
+ # print(">>>>>>>>>>>>>>>> using common logger. UUID=%s, serviceName=%s, cfg=%s" % (instanceUUID, serviceName, logcfg))
+ global errorLogger, debugLogger, auditLogger, metricsLogger
+ errorLogger = CommonLogger.CommonLogger(logcfg, "error", instanceUUID=instanceUUID, serviceName=serviceName)
+ debugLogger = CommonLogger.CommonLogger(logcfg, "debug", instanceUUID=instanceUUID, serviceName=serviceName)
+ auditLogger = CommonLogger.CommonLogger(logcfg, "audit", instanceUUID=instanceUUID, serviceName=serviceName)
+ metricsLogger = CommonLogger.CommonLogger(logcfg, "metrics", instanceUUID=instanceUUID, serviceName=serviceName)
+ auditLogger.info("using common logger. UUID=%s, serviceName=%s, cfg=%s" % (instanceUUID, serviceName, logcfg))
+
+ checkOption(retOptions, "dbname", "dcae_admin_db_databasename", "-D")
+ checkOption(retOptions, "dbuser", "dcae_admin_db_username", "-U")
+ checkOption(retOptions, "dbpassword", "dcae_admin_db_password", "-P", encrypted=True, cdfPropname="postgres")
+ checkOption(retOptions, "dbhost", "dcae_admin_db_hostname", "-H")
+ checkOption(retOptions, "dbdir", "db_directory", "-d")
+ checkOption(retOptions, "bindir", "pg_bin_directory", "-B")
+ if "jsontop" not in retOptions:
+ retOptions["jsontop"] = getPgaasPropValue("dcae_admin_db_jsontop")
+ trace("env=%s" % str(os.environ))
+ trace("ignorefile=%s" % ignoreFile)
+ return retOptions, args
+
+def main():
+ keyedOptions, args = reviewOpts()
+ trace("Invoked as: %s" % str(sys.argv))
+ audit("Invoked as: %s" % str(sys.argv))
+
+ if len(args) == 0:
+ usage("no operation specified")
+ elif args[0] == "configurationChanged":
+ if len(args) != 2:
+ usage("too many arguments")
+ configurationChanged(keyedOptions, args[1])
+ elif args[0] == "suspend":
+ if len(args) != 1:
+ usage("too many arguments")
+ suspendOperations(keyedOptions)
+ elif args[0] == "resume":
+ if len(args) != 1:
+ usage("too many arguments")
+ resumeOperations(keyedOptions)
+ elif args[0] == "test":
+ if len(args) != 1:
+ usage("too many arguments")
+ testOperations(keyedOptions)
+ else:
+ usage("unrecognized operation '%s'" % args[0])
+
+def suspendOperations(options):
+ """
+ Execute the "suspend" sub-command.
+ """
+ runProgram(["pkill", "repmgrd"])
+ program = options["bindir"] + "/pg_ctl"
+ cmd = [program, "stop", "-D", options["dbdir"]]
+ runProgram(cmd)
+ audit("suspendOperations")
+
+def resumeOperations(options):
+ """
+ Execute the "resume" sub-command.
+ """
+ cmd = [options["bindir"] + "/pg_ctl", "start", "-D", options["dbdir"], "-o", "configfile=" + options["dbconf"]]
+ runProgram(cmd)
+ runProgram(["/opt/app/pgaas/bin/repmgrcd", "-d"])
+ audit("resumeOperations")
+
+def testOperations(options):
+ """
+ Respond to the "test" sub-command.
+ """
+ program = options["bindir"] + "/pg_ctl"
+ cmd = [program, "status", "-D", options["dbdir"]]
+ ret = runProgram(cmd)
+ # pg_ctl: no server running
+ # pg_ctl: server is running (PID: 13988)
+ cmdRepmgr = ["pgrep", "repmgrd"]
+ retRepmgr = runProgram(cmdRepmgr)
+
+ msg = "????"
+ if re.search("no server running", ret):
+ msg = "RED: no PG server running"
+ elif re.search("server is running", ret) and re.search("[0-9]+", retRepmgr):
+ msg = "GREEN"
+ elif re.search("server is running", ret):
+ msg = "YELLOW: no repmgrd running"
+ elif re.search("[0-9]+", retRepmgr):
+ msg = "YELLOW: no PG server running"
+ else:
+ msg = "YELLOW: neither PG server nor repmgrd are running"
+ audit("test: " + msg)
+ print(msg, end="")
+
+def runProgram(cmd):
+ """
+ Run the given command, returning the standard output as a string.
+ If there is an error, return None.
+ """
+ try:
+ p=subprocess.Popen(cmd,shell=False,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
+ (stdout, stderr) = p.communicate()
+ except Exception as e:
+ print("Error running program because: {0}".format(e), file=errorOutput)
+ return None
+ else:
+ if stderr:
+ print("Error running program because: {0} ".format(stderr), file=errorOutput)
+ return None
+ else:
+ trace("runProgram() => " + str(stdout), minLevel=2)
+ return stdout.decode('utf-8').rstrip('\n')
+
+def configurationChanged(options, jsonFile):
+ """
+ We received a new JSON configuration file
+ """
+ audit("configurationChanged " + jsonFile)
+ if options["ignorefile"] == "yes":
+ trace("skipping database reconfiguration because skip_configuration_file exists")
+ return
+
+ if not os.path.isfile(jsonFile):
+ die("json file %s does not exist" % jsonFile)
+
+ try:
+ inp = json.load(open(jsonFile,"r"))
+ except Exception as e:
+ die("Cannot open jsonFile '%s': %s" % (jsonFile, e))
+
+ if verbose:
+ dumpJSON(inp, "incoming JSON")
+
+ jsonTop = options["jsontop"]
+ if not jsonTop is None:
+ e = "inp" + jsonTop
+ trace("eval(%s)" % e)
+ inp = eval(e,{"__builtins__":None},{"inp":inp})
+ if verbose:
+ dumpJSON(inp, "modified JSON")
+
+ # trace("version=%s" % requireJSON("version", inp, "version"))
+ requireJSON("databases", inp, "databases")
+ con = None
+ try:
+ con = dbConnect(database = options["dbname"], user = options["dbuser"], password = options["dbpassword"], host = options["dbhost"])
+ setupDatabases(con, options, requireJSON("databases", inp, "databases"))
+
+ except psycopg2.DatabaseError as e:
+ die('Error %s' % e)
+
+ finally:
+ if con:
+ con.commit()
+ con.close()
+
+def dumpJSON(js, msg):
+ tracePrint("vvvvvvvvvvvvvvvv %s" % msg)
+ tracePrint(json.dumps(js, indent=4))
+ tracePrint("^^^^^^^^^^^^^^^^ %s" % msg)
+
+def setupDatabases(con, options, dbList):
+ """
+ Do what is needed to set up all of the databases
+ """
+ currentDatabases = dbGetFirstColumnAsMap(con, "select datname from pg_database where datistemplate = false")
+ currentRolenames = dbGetFirstColumnAsMap(con, "select rolname from pg_roles")
+ trace("currentDatabases = " + str(currentDatabases))
+ for dbName in dbList:
+ trace("dbName='%s'" % str(dbName))
+ setupDatabase(con, options, currentDatabases, currentRolenames, dbName, dbList[dbName])
+
+def setupDatabase(con, options, currentDatabases, currentRolenames, dbName, dbInfo):
+ """
+ Do what is needed to set up a given databases and its users
+ """
+
+ dbOwnerRole = requireJSON("databases[].ownerRole", dbInfo, "ownerRole")
+ trace("dbName='%s', dbOwnerRole='%s'" % (dbName, dbOwnerRole))
+ doesDbExist = dbName in currentDatabases
+ trace("does %s exist? %s" % (dbName, doesDbExist))
+ foundOwnerRole = False
+ dbRoles = dbInfo["roles"]
+ for name in dbRoles:
+ u = dbRoles[name]
+ if name == dbOwnerRole and u["role"] == "admin":
+ foundOwnerRole = True
+ if u["role"] not in ("admin","writer","reader"):
+ die("For database %s, the role '%s' is not one of admin/writer/reader" % (dbName, u.role))
+ if not foundOwnerRole:
+ die("For database %s, information on the ownerRole '%s' was not found" % (dbName, dbOwnerRole))
+ for name in dbRoles:
+ userInfo = dbRoles[name]
+ if name in currentRolenames and ("ignoredb" not in options or not options["ignoredb"]):
+ trace("The role %s already exists, skipping" % name)
+ updatePassword(con, options, dbName, name, userInfo)
+ else:
+ setupUser(con, options, dbName, name, userInfo)
+ if doesDbExist and ("ignoredb" not in options or not options["ignoredb"]):
+ trace("The database %s already exists, skipping" % dbName)
+ else:
+ makeDatabase(con, options, dbName, dbOwnerRole, dbInfo, dbRoles)
+ for name in dbRoles:
+ userInfo = dbRoles[name]
+ if name in currentRolenames and ("ignoredb" not in options or not options["ignoredb"]):
+ trace("The role %s already exists, skipping grants" % name)
+ else:
+ modifyGrants(con, options, dbName, name, userInfo)
+
+def makeDatabase(con, options, dbName, dbOwnerRole, dbInfo, dbRoles):
+ """
+ Execute the SQL to create a database
+
+ TODO: verify grants against what is actually there
+ """
+ ownerRole = dbInfo["ownerRole"]
+ userRole = "{0}_common_user_role".format(dbName)
+ viewerRole = "{0}_common_viewer_role".format(dbName)
+
+ optionalDbExecute(con, options, "CREATE ROLE {0}".format(userRole))
+ optionalDbExecute(con, options, "CREATE ROLE {0}".format(viewerRole))
+
+ trace("Creating database %s with owner '%s'" % (dbName, ownerRole))
+ optionalDbExecute(con, options, "CREATE DATABASE %s WITH OWNER %s" % (dbName, ownerRole))
+ con2 = None
+ try:
+ con2 = dbConnect(database = dbName, user = options["dbuser"], password = options["dbpassword"], host = options["dbhost"])
+
+ optionalDbExecute(con2, options, "REVOKE ALL on DATABASE {0} FROM {1}".format(dbName, viewerRole))
+ optionalDbExecute(con2, options, "REVOKE ALL on DATABASE {0} FROM {1}".format(dbName, userRole))
+ for name in dbRoles:
+ userInfo = dbRoles[name]
+ if userInfo["role"] == "writer" or userInfo["role"] == "reader":
+ optionalDbExecute(con2, options, "REVOKE ALL on DATABASE {0} FROM {1}".format(dbName, name))
+
+ # user can do everything viewer can
+ optionalDbExecute(con2, options, "GRANT {0} TO {1}".format(viewerRole, userRole))
+ # admin can do everything user and viewer can
+ optionalDbExecute(con2, options, "GRANT {0} TO {1}".format(userRole, ownerRole))
+
+ # viewer, user, admin can connect
+ optionalDbExecute(con2, options, "GRANT CONNECT ON DATABASE {0} TO {1}".format(dbName, viewerRole))
+
+ # create a schema we can optionally use *
+ schemaName = "{0}_db_common".format(dbName)
+ optionalDbExecute(con2, options, "CREATE SCHEMA if not exists {0} AUTHORIZATION {1}".format(schemaName, ownerRole))
+
+ # search_path is not inherited, so set it here
+ for role in [ ownerRole, userRole, viewerRole ]:
+ optionalDbExecute(con2, options, "ALTER ROLE {1} IN DATABASE {0} SET search_path = public, {2}".format(dbName, role, schemaName))
+
+ # viewer,user can select from schema
+ optionalDbExecute(con2, options, "GRANT USAGE ON SCHEMA {0} TO {1}".format(schemaName, viewerRole))
+ # admin can create on schema
+ optionalDbExecute(con2, options, "GRANT CREATE ON SCHEMA {0} TO {1}".format(schemaName, ownerRole))
+
+ # viewer, user, admin can select on tables
+ optionalDbExecute(con2, options, "ALTER DEFAULT PRIVILEGES FOR ROLE {1} GRANT SELECT ON TABLES TO {0}".format(viewerRole, ownerRole))
+ # user, admin can ins/upd/del/tru on tables
+ optionalDbExecute(con2, options, "ALTER DEFAULT PRIVILEGES FOR ROLE {1} GRANT INSERT, UPDATE, DELETE, TRUNCATE ON TABLES TO {0}".format(userRole, ownerRole))
+ # user, admin can update on sequences
+ optionalDbExecute(con2, options, "ALTER DEFAULT PRIVILEGES FOR ROLE {1} GRANT USAGE, SELECT, UPDATE ON SEQUENCES TO {0}".format(userRole, ownerRole))
+
+ # user, admin can create temp tables
+ optionalDbExecute(con2, options, "GRANT TEMP ON DATABASE {0} TO {1}".format(dbName, userRole))
+
+ for name in dbRoles:
+ userInfo = dbRoles[name]
+ if userInfo["role"] == "writer":
+ optionalDbExecute(con2, options, "GRANT {0} TO {1}".format(userRole, name))
+ elif userInfo["role"] == "reader":
+ optionalDbExecute(con2, options, "GRANT {0} TO {1}".format(viewerRole, name))
+
+ # search_path is not inherited, so set it here
+ optionalDbExecute(con2, options, "ALTER ROLE {1} IN DATABASE {0} SET search_path = public, {2}".format(dbName, name, schemaName))
+
+ except psycopg2.DatabaseError as e:
+ die('Error %s' % e)
+
+ finally:
+ if con2:
+ con2.commit()
+ con2.close()
+
+def checkUsername(userName):
+ """
+ A value of type name is a string of 63 or fewer characters1. A name must start
+ with a letter or an underscore; the rest of the string can contain letters,
+ digits, and underscores.
+ """
+ trace("checkUsername(%s)" % userName)
+ if re.match("[A-Za-z_][A-Za-z0-9_]*$", userName):
+ return True
+ else:
+ errorPrint("%s is not a valid userName" % userName)
+ return False
+
+def setupUser(con, options, dbName, userName, userInfo):
+ """
+ Do what is needed to to set up a user for a database
+ """
+ if checkUsername(userName):
+ trace("For dbName='%s', create user '%s'" % (dbName, userName))
+ userPassword = userInfo["password"]
+ optionalDbExecute(con, options, "create user %s with password '%s'" % (userName, userPassword))
+
+def updatePassword(con, options, dbName, userName, userInfo):
+ """
+ Do what is needed to update a user's password
+ """
+ if checkUsername(userName):
+ trace("For dbName='%s', alter user '%s' password" % (dbName, userName))
+ userPassword = userInfo["password"]
+ optionalDbExecute(con, options, "alter user %s with password '%s'" % (userName, userPassword))
+
+def modifyGrants(con, options, dbName, userName, userInfo):
+ """
+ Do what is needed to to set up a user for a database with the proper grants
+
+ TODO: if user exist, verify current grants
+ """
+ if checkUsername(userName):
+ userRole = userInfo["role"]
+ trace("For dbName='%s', set up user '%s' as a '%s'" % (dbName, userName, userRole))
+ if userRole == "writer":
+ optionalDbExecute(con, options, "grant %s_common_user_role to %s" % (dbName, userName))
+ elif userRole == "reader":
+ optionalDbExecute(con, options, "grant %s_common_viewer_role to %s" % (dbName, userName))
+ # elif userRole == "admin":
+ # optionalDbExecute(con, options, "grant %s_common_admin_role to %s" % (dbName, userName))
+ else:
+ trace("nothing to grant %s" % userName)
+
+def optionalDbExecute(con, options, cmd):
+ if "nocreate" in options and options["nocreate"]:
+ print(cmd)
+ else:
+ audit("Running: " + cmd)
+ dbExecute(con, cmd)
+
+"""
+database utility functions
+"""
+
+# def dbGetMap(con, cmd, args=[], skipTrace=False):
+# def dbGetOneRowMap(con, cmd, args=[], skipTrace=False):
+
+def dbGetFirstRowOneValue(con, cmd, args=[], skipTrace=False):
+ """
+ Do a select and return a single value from the first row
+ """
+ row = dbGetFirstRow(con, cmd, args, skipTrace)
+ trace("row=" + str(row))
+ if row is not None and len(row) > 0:
+ return row[0]
+ return None
+
+def dbGetFirstRow(con, cmd, args=[], skipTrace=False):
+ """
+ Do a select and return the values from the first row
+ """
+ cursor = dbExecute(con, cmd, args, skipTrace)
+ return cursor.fetchone()
+
+def dbGetFirstColumn(con, cmd, args=[], skipTrace=False):
+ """
+ Do a select and return the first column's value from each row
+ """
+ ret = []
+ cursor = dbExecute(con, cmd, args, skipTrace)
+ for row in cursor:
+ for col in row:
+ ret.append(col)
+ break
+ return ret
+
+def dbGetFirstColumnAsMap(con, cmd, args=[], skipTrace=False, val=1):
+ """
+ Do a select and return the first column's value from each row
+ """
+ ret = {}
+ cursor = dbExecute(con, cmd, args, skipTrace)
+ for row in cursor:
+ for col in row:
+ ret[col] = val
+ break
+ return ret
+
+def dumpTable(con, tableName, max=-1):
+ """
+ If being extra verbose, print out the entire table
+ """
+ if verbose < 2:
+ return
+ print("================ " + tableName + " ================", file=traceOutput)
+
+ cols = dbGetFirstColumn(con, "select column_name from information_schema.columns where table_name='" + tableName + "'", skipTrace=True)
+ print("num", end="|", file=traceOutput)
+ for col in cols:
+ print(col, end="|", file=traceOutput)
+ print("", file=traceOutput)
+
+ if max > -1:
+ cursor = dbExecute(con, "select * from " + tableName + " limit " + str(max), skipTrace=True)
+ else:
+ cursor = dbExecute(con, "select * from " + tableName, skipTrace=True)
+ i = 0
+ for row in cursor:
+ print("%d" % i, end="|", file=traceOutput)
+ i += 1
+ for col in row:
+ print("%s" % (col), end="|", file=traceOutput)
+ print("", file=traceOutput)
+ print("================================================", file=traceOutput)
+
+def dbExecute(con, statement, args=[], skipTrace=False):
+ """
+ Create a cursor, instantiate the arguments into a statement, trace print the statement, and execute the statement.
+ Return the cursor
+ """
+ cursor = con.cursor()
+ stmt = cursor.mogrify(statement, args);
+ if not skipTrace:
+ trace("executing:" + str(stmt))
+ cursor.execute(stmt)
+ global quiet
+ if not skipTrace:
+ trace("statusmessage=" + cursor.statusmessage + ", rowcount=" + str(cursor.rowcount))
+ return cursor
+
+def dbConnect(database, user, password, host, autocommit = True):
+ """
+ Create a connection, logging it in the process
+ Return the connection
+ """
+ trace("connecting to database %s as %s on host %s" % (database, user, host))
+ con =psycopg2.connect(database = database, user = user, password = password, host = host)
+ con.autocommit = autocommit
+ return con
+
+"""
+Utility functions
+"""
+
+def die(msg):
+ """
+ Print a message to the error file and exit.
+ """
+ errorPrint(msg)
+ sys.exit(1)
+
+def errorPrint(msg, file=errorOutput):
+ """
+ Print a message to the error file.
+ """
+ global errorLogger
+ # print("----------------> errorLogger=%s" % str(errorLogger))
+ if errorLogger is not None:
+ errorLogger.error(msg)
+ else:
+ taggedPrint("ERROR", msg, file=file)
+
+
+def tracePrint(msg, file=traceOutput):
+ """
+ Print a message to the trace file.
+ """
+ global debugLogger
+ # print("----------------> debugLogger=%s" % str(debugLogger))
+ if debugLogger is not None:
+ debugLogger.debug(msg)
+ else:
+ taggedPrint("DEBUG", msg, file=file)
+
+def taggedPrint(tag, msg, file):
+ """
+ Print a message to the trace file.
+ """
+ dt = time.strftime('%Y-%m-%d %T', time.localtime())
+ print("%s %s: %s" % (dt, tag, msg), file=file)
+
+def requireOption(nm, val):
+ """
+ Die if a program parameter is not set
+ """
+ return require("option", nm, val)
+
+def requireJSON(prnm, dict, nm):
+ """
+ Die if a JSON value is not set
+ """
+ if nm not in dict:
+ die("The JSON value '%s' is missing" % prnm)
+ return dict[nm]
+
+def require(type, nm, val):
+ """
+ Die if a value is not set
+ """
+ if val is None:
+ die("The %s '%s' is missing" % (type, nm))
+ return val
+
+def trace(msg, minLevel=1):
+ """
+ Print a message to trace output if verbose is turned on.
+ """
+ global verbose
+ if verbose >= minLevel:
+ tracePrint(msg)
+
+def audit(msg):
+ """
+ Print a message to audit log if one is being used
+ """
+ global auditLogger
+ if auditLogger is not None:
+ auditLogger.info(msg)
+
+def getCdfPropValue(nm, encrypted=False, cfg="/opt/app/cdf/lib/cdf.cfg", dflt=None, skipComplaining=False):
+ """
+ Return a value from the configuration file /opt/app/cdf/lib/cdf.cfg
+ """
+ return getPropValue(nm=nm, encrypted=encrypted, cfg=cfg, dflt=dflt, skipComplaining=skipComplaining)
+
+def getPgaasPropValue(nm, encrypted=False, cfg="/opt/app/pgaas/lib/pgaas.cfg", dflt=None, skipComplaining=False):
+ """
+ Return a value from the configuration file /opt/app/pgaas/lib/pgaas.cfg
+ """
+ return getPropValue(nm=nm, encrypted=encrypted, cfg=cfg, dflt=dflt, skipComplaining=skipComplaining)
+
+getPropDict = { }
+
+def getPropValue(nm, encrypted=False, cfg=None, dflt=None, skipComplaining=False):
+ """
+ Return a value from the specified configuration file
+ """
+ if cfg is None:
+ return None
+ global getPropDict
+ if getPropDict.get(cfg):
+ savedDate = getPropDict[cfg]
+ # trace("getPropValue: savedDate[" + cfg + "]=" + str(savedDate))
+ cfgDate = os.path.getmtime(cfg)
+ # trace("getPropValue: cfgDate=" + str(cfgDate))
+ if float(savedDate) >= float(cfgDate): # cfg has not changed
+ val = getPropDict.get(cfg + ":" + nm)
+ # trace("getPropValue: val=" + val)
+ if val is not None:
+ # trace("getPropValue: getPropValue(saved) => '%s'" % str(val))
+ return val
+ else: # clear out any previously saved keys
+ cfgcolon = cfg + ":"
+ for k in list(getPropDict.keys()):
+ if re.match(cfgcolon, k):
+ del getPropDict[k]
+ getPropValueProgram = '/opt/app/cdf/bin/getpropvalue'
+ if encrypted:
+ cmd = [getPropValueProgram, "-f", cfg, "-x", "-n", nm]
+ else:
+ cmd = [getPropValueProgram, "-f", cfg, "-n", nm]
+ # trace("getPgaasPropValue: cmd=" + str(cmd))
+
+ try:
+ with subprocess.Popen(cmd,shell=False,stdout=subprocess.PIPE,stderr=subprocess.PIPE) as p:
+ (origString, stderrString) = p.communicate()
+ except Exception as e:
+ traceback.print_exc()
+ print("Error decoding string because {0}".format(e), file=errorOutput)
+ return None
+ else:
+ if stderrString:
+ if not re.search("Configuration property .* must be defined", stderrString.decode('utf-8')) and not skipComplaining:
+ print("Error decoding string because: {0} ".format(stderr), file=errorOutput)
+ return dflt
+ else:
+ trace("getPgaasPropValue() => " + str(origString), minLevel=2)
+ return origString.decode('utf-8').rstrip('\n')
+
+if __name__ == "__main__":
+ main()
diff --git a/pgaas/src/stage/opt/app/pgaas/bin/in.json b/pgaas/src/stage/opt/app/pgaas/bin/in.json
new file mode 100755
index 0000000..cad8790
--- /dev/null
+++ b/pgaas/src/stage/opt/app/pgaas/bin/in.json
@@ -0,0 +1,97 @@
+{
+ # sample configuration file for dcae_admin_db
+ "vmConfiguration": {
+ "$class": "org.openecomp.dcae.controller.service.storage.postgres.service.PostgresServiceConfiguration",
+ "state": "master",
+ "databases": {
+ "odcit": {
+ "created": "2016-05-10T01:52:39.431+0000",
+ "description": "A&AI DCAE Central Inventory",
+ "ownerRole": "odcit_admin",
+ "contacts": {"ws4361": {
+ "created": "2016-05-10T01:52:39.431+0000",
+ "fullName": "Wen Shang"
+ }},
+ "roles": {
+ "odcit_admin": {
+ "created": "2016-05-10T01:52:39.431+0000",
+ "password": "odcit123",
+ "role": "admin",
+ "roleComments": []
+ },
+ "odcit_user": {
+ "created": "2016-05-10T01:52:39.431+0000",
+ "password": "odcit123",
+ "role": "writer",
+ "roleComments": []
+ },
+ "odcit_viewer": {
+ "created": "2016-05-10T01:52:39.431+0000",
+ "password": "odcit123",
+ "role": "reader",
+ "roleComments": []
+ }
+ }
+ },
+ "dmaap": {
+ "created": "2016-05-10T01:52:39.431+0000",
+ "description": "DMAAP Databus Configuration",
+ "ownerRole": "dmaap_admin",
+ "contacts": {"dl715d": {
+ "created": "2016-05-10T01:52:39.431+0000",
+ "fullName": "Dominic Lunanuova"
+ }},
+ "roles": {
+ "dmaap_admin": {
+ "created": "2016-05-10T01:52:39.431+0000",
+ "password": "dmaap123",
+ "role": "admin",
+ "roleComments": []
+ },
+ "dmaap_user": {
+ "created": "2016-05-10T01:52:39.431+0000",
+ "password": "dmaap123",
+ "role": "writer",
+ "roleComments": []
+ },
+ "dmaap_viewer": {
+ "created": "2016-05-10T01:52:39.431+0000",
+ "password": "dmaap123",
+ "role": "reader",
+ "roleComments": []
+ }
+ }
+ },
+ "dcae_inv": {
+ "created": "2016-05-10T01:52:39.431+0000",
+ "description": "Running DCAE Services",
+ "ownerRole": "dcae_inv_admin",
+ "contacts": {
+ "mh677g": {
+ "created": "2016-05-10T01:52:39.431+0000",
+ "fullName": "Michael Hwang"
+ }},
+ "roles": {
+ "dcae_inv_admin": {
+ "created": "2016-05-10T01:52:39.431+0000",
+ "password": "dcae_inv123",
+ "role": "admin",
+ "roleComments": []
+ },
+ "dcae_inv_user": {
+ "created": "2016-05-10T01:52:39.431+0000",
+ "password": "dcae_inv123",
+ "role": "writer",
+ "roleComments": []
+ },
+ "dcae_inv_viewer": {
+ "created": "2016-05-10T01:52:39.431+0000",
+ "password": "dcae_inv123",
+ "role": "reader",
+ "roleComments": []
+ }
+ }
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/pgaas/src/stage/opt/app/pgaas/bin/isrw b/pgaas/src/stage/opt/app/pgaas/bin/isrw
new file mode 100755
index 0000000..4ec3dcb
--- /dev/null
+++ b/pgaas/src/stage/opt/app/pgaas/bin/isrw
@@ -0,0 +1,28 @@
+#!/bin/bash
+# Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this code except in compliance
+# with the License. You may obtain a copy of the License
+# at http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# permissions and limitations under the License.
+
+
+if [ -d /usr/lib/postgresql/9.5/bin ]
+then PATH=$PATH:/usr/lib/postgresql/9.5/bin
+elif [ -d /opt/app/postgresql-9.5.2/bin ]
+then PATH=$PATH:/opt/app/postgresql-9.5.2/bin
+else echo "$0: Cannot find PostgreSQL bin" 1>&2; exit 1
+fi
+
+export PATH=$PATH:/opt/java/jdk/jdk170/bin:/opt/app/cdf/bin:/opt/app/pgaas/bin:$PATH
+
+case `show_pg_is_in_recovery` in
+ *f* ) echo "Master" ;;
+ *t* ) echo "Secondary" ;;
+esac
diff --git a/pgaas/src/stage/opt/app/pgaas/bin/list_masters b/pgaas/src/stage/opt/app/pgaas/bin/list_masters
new file mode 100755
index 0000000..d922739
--- /dev/null
+++ b/pgaas/src/stage/opt/app/pgaas/bin/list_masters
@@ -0,0 +1,43 @@
+#!/bin/bash
+# Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this code except in compliance
+# with the License. You may obtain a copy of the License
+# at http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# permissions and limitations under the License.
+
+
+# NAME
+# list_masters - loop through the nodes in the cluster, using pgwget to determine if any are a master.
+
+CDF=/opt/app/cdf
+if [ -d /opt/app/postgresql-9.5.2 ]
+then PGDIR=/opt/app/postgresql-9.5.2
+else PGDIR=/usr/lib/postgresql/9.5
+fi
+if [ -d /opt/app/postgresql-config-9.5.2/ ]
+then CFGDIR=/opt/app/postgresql-config-9.5.2/
+else CFGDIR=/opt/app/postgresql-config/
+fi
+PATH=$PGDIR/bin:$CDF/bin:/opt/app/pgaas/bin:/opt/app/postgresql-prep/bin:$PATH
+
+# loop through the nodes in the cluster, using pgwget to determine if any are a master. Save in $@
+for i in $(getpropvalue -n pgnodes | sed 's/|/ /g')
+do
+ if pgwget --quiet -O/dev/null http://$i:8000/rw
+ then set -- "$@" $i
+ fi
+done
+
+echo "$@"
+case $# in
+ 1 ) exit 0 ;; # one master exists and is running
+ 0 ) exit 1 ;; # no masters exist
+ * ) exit 2 ;; # more than one master exist
+esac
diff --git a/pgaas/src/stage/opt/app/pgaas/bin/makefile b/pgaas/src/stage/opt/app/pgaas/bin/makefile
new file mode 100644
index 0000000..877f8ba
--- /dev/null
+++ b/pgaas/src/stage/opt/app/pgaas/bin/makefile
@@ -0,0 +1,47 @@
+# Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this code except in compliance
+# with the License. You may obtain a copy of the License
+# at http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# permissions and limitations under the License.
+
+
+all:
+
+test:
+ sudo -u postgres ./dcae_admin_db.py configurationChanged in.json
+
+STAGEDIR=/dev/null
+DISTPATH=/opt/app/pgaas
+
+PYFILES= dcae_admin_db.py
+SHFILES= check_cluster isrw list_masters \
+ pg_ctl_promote pg_ctl_restart pg_ctl_start pg_ctl_status pg_ctl_stop repmgrc repmgrdc \
+ runpsql runpsqll startpsql setpropvalue show_pg_is_in_recovery show_pg_stat_activity show_pg_stat_archiver show_pg_stat_bgwriter \
+ show_pg_stat_database show_pg_stat_database_conflicts show_pg_statio_user_functions show_pg_statio_user_indexes \
+ show_pg_statio_user_sequences show_pg_statio_user_tables show_pg_stat_user_indexes show_pg_stat_user_tables \
+ update_var_run_isrw
+
+stage:
+ rm -rf $(STAGEDIR)/$(DISTPATH)/bin
+ mkdir -p $(STAGEDIR)/$(DISTPATH)/bin
+ for i in *; do \
+ case $$i in \
+ *.py ) \
+ j=`basename $$i .py`; \
+ cp $$i $(STAGEDIR)/$(DISTPATH)/bin/$$j; \
+ chmod a+x $(STAGEDIR)/$(DISTPATH)/bin/$$j; \
+ ;; \
+ makefile | *~ ) ;; \
+ * ) \
+ cp $$i $(STAGEDIR)/$(DISTPATH)/bin/$$i; \
+ chmod a+x $(STAGEDIR)/$(DISTPATH)/bin/$$i; \
+ ;; \
+ esac; \
+ done
diff --git a/pgaas/src/stage/opt/app/pgaas/bin/pg_ctl_promote b/pgaas/src/stage/opt/app/pgaas/bin/pg_ctl_promote
new file mode 100755
index 0000000..b7d011c
--- /dev/null
+++ b/pgaas/src/stage/opt/app/pgaas/bin/pg_ctl_promote
@@ -0,0 +1,23 @@
+#!/bin/bash
+# Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this code except in compliance
+# with the License. You may obtain a copy of the License
+# at http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# permissions and limitations under the License.
+
+
+if [ -d /usr/lib/postgresql/9.5/bin ]
+then PATH=$PATH:/usr/lib/postgresql/9.5/bin
+elif [ -d /opt/app/postgresql-9.5.2/bin ]
+then PATH=$PATH:/opt/app/postgresql-9.5.2/bin
+else echo "$0: Cannot find PostgreSQL bin" 1>&2; exit 1
+fi
+
+pg_ctl promote -D /dbroot/pgdata/main/
diff --git a/pgaas/src/stage/opt/app/pgaas/bin/pg_ctl_restart b/pgaas/src/stage/opt/app/pgaas/bin/pg_ctl_restart
new file mode 100755
index 0000000..db00739
--- /dev/null
+++ b/pgaas/src/stage/opt/app/pgaas/bin/pg_ctl_restart
@@ -0,0 +1,41 @@
+#!/bin/bash
+# Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this code except in compliance
+# with the License. You may obtain a copy of the License
+# at http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# permissions and limitations under the License.
+
+
+if [ -d /usr/lib/postgresql/9.5/bin ]
+then PATH=$PATH:/usr/lib/postgresql/9.5/bin
+elif [ -d /opt/app/postgresql-9.5.2/bin ]
+then PATH=$PATH:/opt/app/postgresql-9.5.2/bin
+else echo "$0: Cannot find PostgreSQL bin" 1>&2; exit 1
+fi
+
+if [ -f /opt/app/postgresql-config/main/postgresql.conf ]
+then CONF=/opt/app/postgresql-config/main/postgresql.conf
+elif [ -f /opt/app/postgresql-config-9.5.2/main/postgresql.conf ]
+then CONF=/opt/app/postgresql-config-9.5.2/main/postgresql.conf
+else echo "$0: Cannot find PostgreSQL configuration" 1>&2; exit 1
+fi
+
+pg_ctl stop -D /dbroot/pgdata/main/
+echo Restarting in 5
+sleep 1
+echo Restarting in 4
+sleep 1
+echo Restarting in 3
+sleep 1
+echo Restarting in 2
+sleep 1
+echo Restarting in 1
+sleep 1
+pg_ctl start -D /dbroot/pgdata/main/ -o "-c config_file=$CONF"
diff --git a/pgaas/src/stage/opt/app/pgaas/bin/pg_ctl_start b/pgaas/src/stage/opt/app/pgaas/bin/pg_ctl_start
new file mode 100755
index 0000000..8cb831c
--- /dev/null
+++ b/pgaas/src/stage/opt/app/pgaas/bin/pg_ctl_start
@@ -0,0 +1,30 @@
+#!/bin/bash
+# Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this code except in compliance
+# with the License. You may obtain a copy of the License
+# at http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# permissions and limitations under the License.
+
+
+if [ -d /usr/lib/postgresql/9.5/bin ]
+then PATH=$PATH:/usr/lib/postgresql/9.5/bin
+elif [ -d /opt/app/postgresql-9.5.2/bin ]
+then PATH=$PATH:/opt/app/postgresql-9.5.2/bin
+else echo "$0: Cannot find PostgreSQL bin" 1>&2; exit 1
+fi
+
+if [ -f /opt/app/postgresql-config/main/postgresql.conf ]
+then CONF=/opt/app/postgresql-config/main/postgresql.conf
+elif [ -f /opt/app/postgresql-config-9.5.2/main/postgresql.conf ]
+then CONF=/opt/app/postgresql-config-9.5.2/main/postgresql.conf
+else echo "$0: Cannot find PostgreSQL configuration" 1>&2; exit 1
+fi
+
+pg_ctl start -D /dbroot/pgdata/main/ -o "-c config_file=$CONF"
diff --git a/pgaas/src/stage/opt/app/pgaas/bin/pg_ctl_status b/pgaas/src/stage/opt/app/pgaas/bin/pg_ctl_status
new file mode 100755
index 0000000..416a00e
--- /dev/null
+++ b/pgaas/src/stage/opt/app/pgaas/bin/pg_ctl_status
@@ -0,0 +1,23 @@
+#!/bin/bash
+# Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this code except in compliance
+# with the License. You may obtain a copy of the License
+# at http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# permissions and limitations under the License.
+
+
+if [ -d /usr/lib/postgresql/9.5/bin ]
+then PATH=$PATH:/usr/lib/postgresql/9.5/bin
+elif [ -d /opt/app/postgresql-9.5.2/bin ]
+then PATH=$PATH:/opt/app/postgresql-9.5.2/bin
+else echo "$0: Cannot find PostgreSQL bin" 1>&2; exit 1
+fi
+
+pg_ctl status -D /dbroot/pgdata/main/
diff --git a/pgaas/src/stage/opt/app/pgaas/bin/pg_ctl_stop b/pgaas/src/stage/opt/app/pgaas/bin/pg_ctl_stop
new file mode 100755
index 0000000..0d9a23c
--- /dev/null
+++ b/pgaas/src/stage/opt/app/pgaas/bin/pg_ctl_stop
@@ -0,0 +1,23 @@
+#!/bin/bash
+# Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this code except in compliance
+# with the License. You may obtain a copy of the License
+# at http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# permissions and limitations under the License.
+
+
+if [ -d /usr/lib/postgresql/9.5/bin ]
+then PATH=$PATH:/usr/lib/postgresql/9.5/bin
+elif [ -d /opt/app/postgresql-9.5.2/bin ]
+then PATH=$PATH:/opt/app/postgresql-9.5.2/bin
+else echo "$0: Cannot find PostgreSQL bin" 1>&2; exit 1
+fi
+
+pg_ctl stop -D /dbroot/pgdata/main/
diff --git a/pgaas/src/stage/opt/app/pgaas/bin/repmgrc b/pgaas/src/stage/opt/app/pgaas/bin/repmgrc
new file mode 100644
index 0000000..57240cf
--- /dev/null
+++ b/pgaas/src/stage/opt/app/pgaas/bin/repmgrc
@@ -0,0 +1,29 @@
+# Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this code except in compliance
+# with the License. You may obtain a copy of the License
+# at http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# permissions and limitations under the License.
+
+
+if [ -d /usr/lib/postgresql/9.5/bin ]
+then PATH=$PATH:/usr/lib/postgresql/9.5/bin
+elif [ -d /opt/app/postgresql-9.5.2/bin ]
+then PATH=$PATH:/opt/app/postgresql-9.5.2/bin
+else echo "$0: Cannot find PostgreSQL bin" 1>&2; exit 1
+fi
+
+if [ -f /opt/app/postgresql-config/main/repmgr.conf ]
+then CONF=/opt/app/postgresql-config/main/repmgr.conf
+elif [ -f /opt/app/postgresql-config-9.5.2/main/repmgr.conf ]
+then CONF=/opt/app/postgresql-config-9.5.2/main/repmgr.conf
+else echo "$0: Cannot find repmgr configuration" 1>&2; exit 1
+fi
+
+repmgr -f $CONF "$@"
diff --git a/pgaas/src/stage/opt/app/pgaas/bin/repmgrdc b/pgaas/src/stage/opt/app/pgaas/bin/repmgrdc
new file mode 100644
index 0000000..cfbaa22
--- /dev/null
+++ b/pgaas/src/stage/opt/app/pgaas/bin/repmgrdc
@@ -0,0 +1,29 @@
+# Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this code except in compliance
+# with the License. You may obtain a copy of the License
+# at http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# permissions and limitations under the License.
+
+
+if [ -d /usr/lib/postgresql/9.5/bin ]
+then PATH=$PATH:/usr/lib/postgresql/9.5/bin
+elif [ -d /opt/app/postgresql-9.5.2/bin ]
+then PATH=$PATH:/opt/app/postgresql-9.5.2/bin
+else echo "$0: Cannot find PostgreSQL bin" 1>&2; exit 1
+fi
+
+if [ -f /opt/app/postgresql-config/main/repmgr.conf ]
+then CONF=/opt/app/postgresql-config/main/repmgr.conf
+elif [ -f /opt/app/postgresql-config-9.5.2/main/repmgr.conf ]
+then CONF=/opt/app/postgresql-config-9.5.2/main/repmgr.conf
+else echo "$0: Cannot find repmgr configuration" 1>&2; exit 1
+fi
+
+repmgrd -f $CONF "$@"
diff --git a/pgaas/src/stage/opt/app/pgaas/bin/runpsql b/pgaas/src/stage/opt/app/pgaas/bin/runpsql
new file mode 100755
index 0000000..be7f705
--- /dev/null
+++ b/pgaas/src/stage/opt/app/pgaas/bin/runpsql
@@ -0,0 +1,30 @@
+#!/bin/bash
+# Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this code except in compliance
+# with the License. You may obtain a copy of the License
+# at http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# permissions and limitations under the License.
+
+
+if [ -d /usr/lib/postgresql/9.5/bin ]
+then PATH=$PATH:/usr/lib/postgresql/9.5/bin
+elif [ -d /opt/app/postgresql-9.5.2/bin ]
+then PATH=$PATH:/opt/app/postgresql-9.5.2/bin
+else echo "$0: Cannot find PostgreSQL bin" 1>&2; exit 1
+fi
+
+export PATH=$PATH:/opt/java/jdk/jdk170/bin:/opt/app/cdf/bin:/opt/app/pgaas/bin
+
+[ -z "$PGUSER" ] && PGUSER=postgres
+[ -z "$PGHOST" ] && PGHOST=`hostname -f`
+[ -z "$PGDBNM" ] && PGDBNM=postgres
+echo "$@;" |
+psql --host=$PGHOST --username=$PGUSER --dbname=$PGDBNM
+
diff --git a/pgaas/src/stage/opt/app/pgaas/bin/runpsqll b/pgaas/src/stage/opt/app/pgaas/bin/runpsqll
new file mode 100755
index 0000000..749ae5d
--- /dev/null
+++ b/pgaas/src/stage/opt/app/pgaas/bin/runpsqll
@@ -0,0 +1,30 @@
+#!/bin/bash
+# Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this code except in compliance
+# with the License. You may obtain a copy of the License
+# at http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# permissions and limitations under the License.
+
+
+if [ -d /usr/lib/postgresql/9.5/bin ]
+then PATH=$PATH:/usr/lib/postgresql/9.5/bin
+elif [ -d /opt/app/postgresql-9.5.2/bin ]
+then PATH=$PATH:/opt/app/postgresql-9.5.2/bin
+else echo "$0: Cannot find PostgreSQL bin" 1>&2; exit 1
+fi
+
+export PATH=$PATH:/opt/java/jdk/jdk170/bin:/opt/app/cdf/bin:/opt/app/pgaas/bin
+
+[ -z "$PGUSER" ] && PGUSER=postgres
+[ -z "$PGHOST" ] && PGHOST=`hostname -f`
+[ -z "$PGDBNM" ] && PGDBNM=postgres
+echo "$@;" |
+psql --tuples-only --host=$PGHOST --username=$PGUSER --dbname=$PGDBNM
+
diff --git a/pgaas/src/stage/opt/app/pgaas/bin/setpropvalue b/pgaas/src/stage/opt/app/pgaas/bin/setpropvalue
new file mode 100755
index 0000000..2b45fa8
--- /dev/null
+++ b/pgaas/src/stage/opt/app/pgaas/bin/setpropvalue
@@ -0,0 +1,67 @@
+#!/bin/bash
+
+# Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this code except in compliance
+# with the License. You may obtain a copy of the License
+# at http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# permissions and limitations under the License.
+
+
+die()
+{
+ exec 1>&2
+ echo "$@"
+ exit 1
+}
+
+usage()
+{
+ exec 1>&2
+ [ $# -gt 0 ] && echo "$@"
+ echo "Usage: $0 -n name -v value [-x]"
+ echo " -n\tname to configure"
+ echo " -v\tvalue to set"
+ echo " -x\tencrypt the value"
+ exit 1
+}
+
+NAME=
+VAL=
+ENCRYPT=false
+FILE=/opt/app/pgaas/lib/pgaas.cfg
+
+while getopts f:n:v:x c
+do
+ case "$c" in
+ f ) FILE=$OPTARG ;;
+ n ) NAME=$OPTARG ;;
+ v ) VAL=$OPTARG ;;
+ x ) ENCRYPT=true ;;
+ \?) usage ;;
+ esac
+done
+shift $(($OPTIND - 1))
+
+[ -n "$NAME" ] || die "-n name is required"
+[ -n "$VAL" ] || die "-v value is required"
+[ -f "$FILE" -a -w "$FILE" ] || die "-f file must exist and be writable"
+
+ed $FILE <<-!
+ H
+ g/^$NAME[=]/d
+ g/^$NAME[.]x=/d
+ w
+ q
+!
+
+if $ENCRYPT
+then /opt/app/cdf/bin/getpropvalue -e AES -n $NAME -v $VAL >> $FILE
+else echo "$NAME='$VAL'" >> $FILE
+fi
diff --git a/pgaas/src/stage/opt/app/pgaas/bin/show_pg_is_in_recovery b/pgaas/src/stage/opt/app/pgaas/bin/show_pg_is_in_recovery
new file mode 100755
index 0000000..b26904d
--- /dev/null
+++ b/pgaas/src/stage/opt/app/pgaas/bin/show_pg_is_in_recovery
@@ -0,0 +1,19 @@
+#!/bin/bash
+# Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this code except in compliance
+# with the License. You may obtain a copy of the License
+# at http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# permissions and limitations under the License.
+
+
+export PATH=/opt/app/pgaas/bin:$PATH
+
+runpsqll "select * from pg_is_in_recovery()"
+
diff --git a/pgaas/src/stage/opt/app/pgaas/bin/show_pg_stat_activity b/pgaas/src/stage/opt/app/pgaas/bin/show_pg_stat_activity
new file mode 100755
index 0000000..d9f43c8
--- /dev/null
+++ b/pgaas/src/stage/opt/app/pgaas/bin/show_pg_stat_activity
@@ -0,0 +1,19 @@
+#!/bin/bash
+# Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this code except in compliance
+# with the License. You may obtain a copy of the License
+# at http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# permissions and limitations under the License.
+
+
+export PATH=/opt/app/pgaas/bin:$PATH
+
+runpsql "select * from pg_stat_activity"
+
diff --git a/pgaas/src/stage/opt/app/pgaas/bin/show_pg_stat_archiver b/pgaas/src/stage/opt/app/pgaas/bin/show_pg_stat_archiver
new file mode 100755
index 0000000..fac0bdb
--- /dev/null
+++ b/pgaas/src/stage/opt/app/pgaas/bin/show_pg_stat_archiver
@@ -0,0 +1,19 @@
+#!/bin/bash
+# Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this code except in compliance
+# with the License. You may obtain a copy of the License
+# at http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# permissions and limitations under the License.
+
+
+export PATH=/opt/app/pgaas/bin:$PATH
+
+runpsql "select * from pg_stat_archiver"
+
diff --git a/pgaas/src/stage/opt/app/pgaas/bin/show_pg_stat_bgwriter b/pgaas/src/stage/opt/app/pgaas/bin/show_pg_stat_bgwriter
new file mode 100755
index 0000000..cf6d01a
--- /dev/null
+++ b/pgaas/src/stage/opt/app/pgaas/bin/show_pg_stat_bgwriter
@@ -0,0 +1,19 @@
+#!/bin/bash
+# Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this code except in compliance
+# with the License. You may obtain a copy of the License
+# at http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# permissions and limitations under the License.
+
+
+export PATH=/opt/app/pgaas/bin:$PATH
+
+runpsql "select * from pg_stat_bgwriter"
+
diff --git a/pgaas/src/stage/opt/app/pgaas/bin/show_pg_stat_database b/pgaas/src/stage/opt/app/pgaas/bin/show_pg_stat_database
new file mode 100755
index 0000000..c74316e
--- /dev/null
+++ b/pgaas/src/stage/opt/app/pgaas/bin/show_pg_stat_database
@@ -0,0 +1,19 @@
+#!/bin/bash
+# Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this code except in compliance
+# with the License. You may obtain a copy of the License
+# at http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# permissions and limitations under the License.
+
+
+export PATH=/opt/app/pgaas/bin:$PATH
+
+runpsql "select * from pg_stat_database"
+
diff --git a/pgaas/src/stage/opt/app/pgaas/bin/show_pg_stat_database_conflicts b/pgaas/src/stage/opt/app/pgaas/bin/show_pg_stat_database_conflicts
new file mode 100755
index 0000000..73d47bd
--- /dev/null
+++ b/pgaas/src/stage/opt/app/pgaas/bin/show_pg_stat_database_conflicts
@@ -0,0 +1,19 @@
+#!/bin/bash
+# Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this code except in compliance
+# with the License. You may obtain a copy of the License
+# at http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# permissions and limitations under the License.
+
+
+export PATH=/opt/app/pgaas/bin:$PATH
+
+runpsql "select * from pg_stat_database_conflicts"
+
diff --git a/pgaas/src/stage/opt/app/pgaas/bin/show_pg_stat_user_indexes b/pgaas/src/stage/opt/app/pgaas/bin/show_pg_stat_user_indexes
new file mode 100755
index 0000000..9ff29d9
--- /dev/null
+++ b/pgaas/src/stage/opt/app/pgaas/bin/show_pg_stat_user_indexes
@@ -0,0 +1,19 @@
+#!/bin/bash
+# Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this code except in compliance
+# with the License. You may obtain a copy of the License
+# at http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# permissions and limitations under the License.
+
+
+export PATH=/opt/app/pgaas/bin:$PATH
+
+runpsql "select * from pg_stat_user_indexes"
+
diff --git a/pgaas/src/stage/opt/app/pgaas/bin/show_pg_stat_user_tables b/pgaas/src/stage/opt/app/pgaas/bin/show_pg_stat_user_tables
new file mode 100755
index 0000000..5eb1393
--- /dev/null
+++ b/pgaas/src/stage/opt/app/pgaas/bin/show_pg_stat_user_tables
@@ -0,0 +1,19 @@
+#!/bin/bash
+# Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this code except in compliance
+# with the License. You may obtain a copy of the License
+# at http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# permissions and limitations under the License.
+
+
+export PATH=/opt/app/pgaas/bin:$PATH
+
+runpsql "select * from pg_stat_user_tables"
+
diff --git a/pgaas/src/stage/opt/app/pgaas/bin/show_pg_statio_user_functions b/pgaas/src/stage/opt/app/pgaas/bin/show_pg_statio_user_functions
new file mode 100755
index 0000000..dfaf570
--- /dev/null
+++ b/pgaas/src/stage/opt/app/pgaas/bin/show_pg_statio_user_functions
@@ -0,0 +1,19 @@
+#!/bin/bash
+# Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this code except in compliance
+# with the License. You may obtain a copy of the License
+# at http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# permissions and limitations under the License.
+
+
+export PATH=/opt/app/pgaas/bin:$PATH
+
+runpsql "select * from pg_statio_user_functions"
+
diff --git a/pgaas/src/stage/opt/app/pgaas/bin/show_pg_statio_user_indexes b/pgaas/src/stage/opt/app/pgaas/bin/show_pg_statio_user_indexes
new file mode 100755
index 0000000..6ec3043
--- /dev/null
+++ b/pgaas/src/stage/opt/app/pgaas/bin/show_pg_statio_user_indexes
@@ -0,0 +1,19 @@
+#!/bin/bash
+# Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this code except in compliance
+# with the License. You may obtain a copy of the License
+# at http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# permissions and limitations under the License.
+
+
+export PATH=/opt/app/pgaas/bin:$PATH
+
+runpsql "select * from pg_statio_user_indexes"
+
diff --git a/pgaas/src/stage/opt/app/pgaas/bin/show_pg_statio_user_sequences b/pgaas/src/stage/opt/app/pgaas/bin/show_pg_statio_user_sequences
new file mode 100755
index 0000000..9d658e4
--- /dev/null
+++ b/pgaas/src/stage/opt/app/pgaas/bin/show_pg_statio_user_sequences
@@ -0,0 +1,19 @@
+#!/bin/bash
+# Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this code except in compliance
+# with the License. You may obtain a copy of the License
+# at http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# permissions and limitations under the License.
+
+
+export PATH=/opt/app/pgaas/bin:$PATH
+
+runpsql "select * from pg_statio_user_sequences"
+
diff --git a/pgaas/src/stage/opt/app/pgaas/bin/show_pg_statio_user_tables b/pgaas/src/stage/opt/app/pgaas/bin/show_pg_statio_user_tables
new file mode 100755
index 0000000..4017988
--- /dev/null
+++ b/pgaas/src/stage/opt/app/pgaas/bin/show_pg_statio_user_tables
@@ -0,0 +1,19 @@
+#!/bin/bash
+# Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this code except in compliance
+# with the License. You may obtain a copy of the License
+# at http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# permissions and limitations under the License.
+
+
+export PATH=/opt/app/pgaas/bin:$PATH
+
+runpsql "select * from pg_statio_user_tables"
+
diff --git a/pgaas/src/stage/opt/app/pgaas/bin/startpsql b/pgaas/src/stage/opt/app/pgaas/bin/startpsql
new file mode 100644
index 0000000..5368fc8
--- /dev/null
+++ b/pgaas/src/stage/opt/app/pgaas/bin/startpsql
@@ -0,0 +1,29 @@
+#!/bin/bash
+# Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this code except in compliance
+# with the License. You may obtain a copy of the License
+# at http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# permissions and limitations under the License.
+
+
+if [ -d /usr/lib/postgresql/9.5/bin ]
+then PATH=$PATH:/usr/lib/postgresql/9.5/bin
+elif [ -d /opt/app/postgresql-9.5.2/bin ]
+then PATH=$PATH:/opt/app/postgresql-9.5.2/bin
+else echo "$0: Cannot find PostgreSQL bin" 1>&2; exit 1
+fi
+
+export PATH=$PATH:/opt/java/jdk/jdk170/bin:/opt/app/cdf/bin:/opt/app/pgaas/bin
+
+[ -z "$PGUSER" ] && PGUSER=postgres
+[ -z "$PGHOST" ] && PGHOST=`hostname -f`
+[ -z "$PGDBNM" ] && PGDBNM=postgres
+
+psql --host=$PGHOST --username=$PGUSER --dbname=$PGDBNM
diff --git a/pgaas/src/stage/opt/app/pgaas/bin/update_var_run_isrw b/pgaas/src/stage/opt/app/pgaas/bin/update_var_run_isrw
new file mode 100755
index 0000000..082c094
--- /dev/null
+++ b/pgaas/src/stage/opt/app/pgaas/bin/update_var_run_isrw
@@ -0,0 +1,30 @@
+#!/bin/bash
+# Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this code except in compliance
+# with the License. You may obtain a copy of the License
+# at http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# permissions and limitations under the License.
+
+
+if [ -d /usr/lib/postgresql/9.5/bin ]
+then PATH=$PATH:/usr/lib/postgresql/9.5/bin
+elif [ -d /opt/app/postgresql-9.5.2/bin ]
+then PATH=$PATH:/opt/app/postgresql-9.5.2/bin
+else echo "$0: Cannot find PostgreSQL bin" 1>&2; exit 1
+fi
+
+export PATH=$PATH:/opt/java/jdk/jdk170/bin:/opt/app/cdf/bin:/opt/app/pgaas/bin
+
+for i in 1 2 3 4 5 6
+do
+ isrw > /var/run/postgresql/isrw.tmp 2>&1 &&
+ mv /var/run/postgresql/isrw.tmp /var/run/postgresql/isrw
+ sleep 10
+done
diff --git a/pgaas/src/stage/opt/app/pgaas/bin/verify_pg_privileges b/pgaas/src/stage/opt/app/pgaas/bin/verify_pg_privileges
new file mode 100755
index 0000000..628b63d
--- /dev/null
+++ b/pgaas/src/stage/opt/app/pgaas/bin/verify_pg_privileges
@@ -0,0 +1,188 @@
+#!/bin/bash
+# Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this code except in compliance
+# with the License. You may obtain a copy of the License
+# at http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# permissions and limitations under the License.
+
+
+defdbname="test"
+defprefix="tst"
+dbname="$defdbname"
+prefix="$defprefix"
+
+usage()
+{
+ exec 1>&2
+ [ -n $# ] && echo " $@"
+ echo "Usage: $0 -A pswd -U pswd -V pswd [-d dbname] [-p prefix] [-P] [-v]"
+ echo " -d dbname - database name, defaults to '$defdbname'"
+ echo " -p prefix - prefix of usernames, defaults to '$defprefix'"
+ echo " -A pswd - password for admin role"
+ echo " -U pswd - password for user role"
+ echo " -V pswd - password for viewer role"
+ echo " -v verbose"
+ echo " -P do not print VERIFIED"
+ exit 1
+}
+
+PRINTVERIFIED=:
+VERBOSE=false
+PSWDA=
+PSWDU=
+PSWDV=
+while getopts A:d:p:PU:vV: c
+do
+ case $c in
+ A ) PSWDA="$OPTARG" ;;
+ d ) dbname="$OPTARG" ;;
+ p ) prefix="$OPTARG" ;;
+ P ) PRINTVERIFIED=false ;;
+ U ) PSWDU="$OPTARG" ;;
+ v ) VERBOSE=: ;;
+ V ) PSWDV="$OPTARG" ;;
+ '?' ) usage ;;
+ esac
+done
+shift `expr $OPTIND - 1`
+
+[ -n "$PSWDA" ] || usage "-A is missing"
+[ -n "$PSWDU" ] || usage "-U is missing"
+[ -n "$PSWDV" ] || usage "-V is missing"
+
+admin="${prefix}_admin"
+user="${prefix}_user"
+viewer="${prefix}_viewer"
+
+TMP1=$(mktemp /tmp/vpp1.$$.XXXXXXXXXX)
+TMP2=$(mktemp /tmp/vpp2.$$.XXXXXXXXXX)
+trap 'rm -f $TMP1 $TMP2' 0 1 2 3 15
+
+VERIFIEDCOUNT=0
+FAILEDCOUNT=0
+TOTALCOUNT=0
+
+verified()
+{
+ (( VERIFIEDCOUNT = VERIFIEDCOUNT + 1 ))
+ (( TOTALCOUNT = TOTALCOUNT + 1 ))
+ $PRINTVERIFIED && echo "VERIFIED: $@"
+}
+
+failed()
+{
+ (( FAILEDCOUNT = FAILEDCOUNT + 1 ))
+ (( TOTALCOUNT = TOTALCOUNT + 1 ))
+ echo "FAILED: $@"
+}
+
+tabtext()
+{
+ echo "$@" | sed 's/^/ /'
+}
+
+tabfile()
+{
+ sed 's/^/ /' "$@"
+}
+
+runtests()
+{
+ name="$1"
+ pswd="$2"
+ while read cmd; read expected
+ do
+ echo "$cmd" | psql --host=localhost --dbname="$dbname" --username="$name" > $TMP1 2>&1
+ if fgrep "$expected" $TMP1 > /dev/null
+ then verified "user $name executed $cmd, expected $expected"
+ $VERBOSE && echo -e "\tGot:" && tabfile "$TMP1"
+ else failed "user $name executed $cmd, expected $expected, got:"; tabfile $TMP1
+ fi
+ done
+}
+
+psql --host=localhost --dbname="$dbname" --username="$admin" <<EOF > /dev/null
+ drop table if exists foo;
+ drop table if exists foou;
+ drop table if exists fooud;
+ drop table if exists foouc;
+ drop table if exists foov;
+ drop table if exists foovd;
+ drop table if exists foovc;
+EOF
+
+# tests to be run as admin user
+cat <<-EOF > $TMP2
+ create table foo ( fooint int ); /* table for admin to add and drop */
+ CREATE TABLE
+ insert into foo (fooint) values (1); /* admin can add values */
+ INSERT 0 1
+ select count(*) from foo; /* admin can select */
+ (1 row)
+ delete from foo where fooint = '1'; /* admin can delete */
+ DELETE 1
+ select * from foo; /* admin can select */
+ (0 rows)
+ drop table foo; /* admin can drop */
+ DROP TABLE
+ create table foou (fooint int ); /* table for user to add/delete to */
+ CREATE TABLE
+ create table fooud (fooint int ); /* table for user to try dropping */
+ CREATE TABLE
+ create table foov (fooint int ); /* table for viewer to try adding/deleting from */
+ CREATE TABLE
+ create table foovd (fooint int ); /* table for viewer to try dropping */
+ CREATE TABLE
+EOF
+runtests "$admin" "$PWDA" < $TMP2
+
+# tests to be run as writer
+cat <<-EOF > $TMP2
+ create table foouc ( fooint int ); /* user cannot create a table */
+ ERROR:
+ drop table fooud; /* user cannot drop a table */
+ ERROR:
+ insert into foou (fooint) values (1); /* user can add values */
+ INSERT 0 1
+ select count(*) from foou; /* user can select values */
+ (1 row)
+ insert into foou (fooint) values (2); /* user can add values */
+ INSERT 0 1
+ select * from foou; /* user can select values */
+ (2 rows)
+ delete from foou where fooint = '2'; /* user can delete values */
+ DELETE 1
+ select * from foou; /* user can select values */
+ (1 row)
+EOF
+runtests "$user" "$PWDU" < $TMP2
+
+# tests to be run as read-only
+cat <<-EOF > $TMP2
+ create table foovc ( fooint int ); /* user cannot create a table */
+ ERROR:
+ drop table foovd; /* user cannot drop a table */
+ ERROR:
+ insert into foov (fooint) values (1); /* user can add values */
+ ERROR:
+ select count(*) from foov; /* user can select values */
+ (1 row)
+ insert into foov (fooint) values (2); /* user can add values */
+ ERROR:
+ select * from foov; /* user can select values */
+ (0 rows)
+ delete from foov where fooint = '2'; /* user can delete values */
+ ERROR:
+ select * from foov; /* user can select values */
+ (0 rows)
+EOF
+runtests "$viewer" "$PWDV" < $TMP2
+
+echo "$VERIFIEDCOUNT tests passed, $FAILEDCOUNT tests failed, $TOTALCOUNT total tests run"
diff --git a/pgaas/src/stage/opt/app/pgaas/etc/create_dcae_rotate.sql b/pgaas/src/stage/opt/app/pgaas/etc/create_dcae_rotate.sql
new file mode 100644
index 0000000..2200362
--- /dev/null
+++ b/pgaas/src/stage/opt/app/pgaas/etc/create_dcae_rotate.sql
@@ -0,0 +1,21 @@
+/*
+ Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this code except in compliance
+ with the License. You may obtain a copy of the License
+ at http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied. See the License for the specific language governing
+ permissions and limitations under the License.
+
+*/
+create table dcae_rotate (
+ basetablename varchar(129) not null, /* the base table name to derive other tables from */
+ columnname varchar(64) not null, /* which column name to use as the datestamp */
+ count int, /* how many periods to keep around */
+ period varchar(20) /* one of 'week', 'month' or 'day' */
+);
diff --git a/pgaas/src/stage/opt/app/pgaas/etc/dcae_admin_db.cfg b/pgaas/src/stage/opt/app/pgaas/etc/dcae_admin_db.cfg
new file mode 100644
index 0000000..139597f
--- /dev/null
+++ b/pgaas/src/stage/opt/app/pgaas/etc/dcae_admin_db.cfg
@@ -0,0 +1,2 @@
+
+
diff --git a/pgaas/src/stage/opt/app/pgaas/etc/makefile b/pgaas/src/stage/opt/app/pgaas/etc/makefile
new file mode 100644
index 0000000..b997f14
--- /dev/null
+++ b/pgaas/src/stage/opt/app/pgaas/etc/makefile
@@ -0,0 +1,25 @@
+# Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this code except in compliance
+# with the License. You may obtain a copy of the License
+# at http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# permissions and limitations under the License.
+
+
+all:
+
+STAGEDIR=/dev/null
+DISTPATH=/opt/app/pgaas
+
+CFGFILES= create_dcae_rotate.sql
+
+stage:
+ rm -rf $(STAGEDIR)/$(DISTPATH)/etc
+ mkdir -p $(STAGEDIR)/$(DISTPATH)/etc
+ cp $(CFGFILES) $(STAGEDIR)/$(DISTPATH)/etc
diff --git a/pgaas/src/stage/opt/app/pgaas/lib/CommonLogger.py b/pgaas/src/stage/opt/app/pgaas/lib/CommonLogger.py
new file mode 100644
index 0000000..d18fc7d
--- /dev/null
+++ b/pgaas/src/stage/opt/app/pgaas/lib/CommonLogger.py
@@ -0,0 +1,889 @@
+#!/usr/bin/python
+# -*- indent-tabs-mode: nil -*- vi: set expandtab:
+"""ECOMP Common Logging library in Python.
+
+CommonLogger.py
+
+# Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this code except in compliance
+# with the License. You may obtain a copy of the License
+# at http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# permissions and limitations under the License.
+
+
+Original Written by: Terry Schmalzried
+Date written: October 1, 2015
+Last updated: December 1, 2016
+
+version 0.8
+"""
+
+from __future__ import print_function
+import os, sys, getopt, logging, logging.handlers, time, re, uuid, socket, threading
+
+class CommonLogger:
+ """ECOMP Common Logging object.
+
+ Public methods:
+ __init__
+ setFields
+ debug
+ info
+ warn
+ error
+ fatal
+ """
+
+ UnknownFile = -1
+ ErrorFile = 0
+ DebugFile = 1
+ AuditFile = 2
+ MetricsFile = 3
+ DateFmt = '%Y-%m-%dT%H:%M:%S'
+
+ def __init__(self, configFile, logKey, **kwargs):
+ """Construct a Common Logger for one Log File.
+
+ Arguments:
+ configFile -- configuration filename.
+ logKey -- the keyword in configFile that identifies the log filename.
+
+ Keyword arguments: Annotations are d:debug, a=audit, m=metrics, e=error
+ style -- the log file format (style) to use when writing log messages,
+ one of CommonLogger.ErrorFile, CommonLogger.DebugFile,
+ CommonLogger.AuditFile and CommonLogger.MetricsFile, or
+ one of the strings "error", "debug", "audit" or "metrics".
+ May also be set in the config file using a field named
+ <logKey>Style (where <logKey> is the value of the logKey
+ parameter). The keyword value overrides the value in the
+ config file.
+ requestID (dame) -- optional default value for this log record field.
+ serviceInstanceID (am) -- optional default value for this log record field.
+ threadID (am) -- optional default value for this log record field.
+ serverName (am) -- optional default value for this log record field.
+ serviceName (am) -- optional default value for this log record field.
+ instanceUUID (am) -- optional default value for this log record field.
+ severity (am) -- optional default value for this log record field.
+ serverIPAddress (am) -- optional default value for this log record field.
+ server (am) -- optional default value for this log record field.
+ IPAddress (am) -- optional default value for this log record field.
+ className (am) -- optional default value for this log record field.
+ timer (am) -- (ElapsedTime) optional default value for this log record field.
+ partnerName (ame) -- optional default value for this log record field.
+ targetEntity (me) -- optional default value for this log record field.
+ targetServiceName (me) -- optional default value for this log record field.
+ statusCode (am) -- optional default value for this log record field.
+ responseCode (am) -- optional default value for this log record field.
+ responseDescription (am) -- optional default value for this log record field.
+ processKey (am) -- optional default value for this log record field.
+ targetVirtualEntity (m) -- optional default value for this log record field.
+ customField1 (am) -- optional default value for this log record field.
+ customField2 (am) -- optional default value for this log record field.
+ customField3 (am) -- optional default value for this log record field.
+ customField4 (am) -- optional default value for this log record field.
+ errorCategory (e) -- optional default value for this log record field.
+ errorCode (e) -- optional default value for this log record field.
+ errorDescription (e) -- optional default value for this log record field.
+
+ Note: the pipe '|' character is not allowed in any log record field.
+ """
+
+ self._monitorFlag = False
+
+ # Get configuration parameters
+ self._logKey = str(logKey)
+ self._configFile = str(configFile)
+ self._rotateMethod = 'time'
+ self._timeRotateIntervalType = 'midnight'
+ self._timeRotateInterval = 1
+ self._sizeMaxBytes = 0
+ self._sizeRotateMode = 'a'
+ self._socketHost = None
+ self._socketPort = 0
+ self._typeLogger = 'filelogger'
+ self._backupCount = 6
+ self._logLevelThreshold = self._intLogLevel('')
+ self._logFile = None
+ self._begTime = None
+ self._begMsec = 0
+ self._fields = {}
+ self._fields["style"] = CommonLogger.UnknownFile
+ try:
+ self._configFileModified = os.path.getmtime(self._configFile)
+ for line in open(self._configFile):
+ line = line.split('#',1)[0] # remove comments
+ if '=' in line:
+ key, value = [x.strip() for x in line.split('=',1)]
+ if key == 'rotateMethod' and value.lower() in ['time', 'size', 'none']:
+ self._rotateMethod = value.lower()
+ elif key == 'timeRotateIntervalType' and value in ['S', 'M', 'H', 'D', 'W0', 'W1', 'W2', 'W3', 'W4', 'W5', 'W6', 'midnight']:
+ self._timeRotateIntervalType = value
+ elif key == 'timeRotateInterval' and int( value ) > 0:
+ self._timeRotateInterval = int( value )
+ elif key == 'sizeMaxBytes' and int( value ) >= 0:
+ self._sizeMaxBytes = int( value )
+ elif key == 'sizeRotateMode' and value in ['a']:
+ self._sizeRotateMode = value
+ elif key == 'backupCount' and int( value ) >= 0:
+ self._backupCount = int( value )
+ elif key == self._logKey + 'SocketHost':
+ self._socketHost = value
+ elif key == self._logKey + 'SocketPort' and int( value ) == 0:
+ self._socketPort = int( value )
+ elif key == self._logKey + 'LogType' and value.lower() in ['filelogger', 'stdoutlogger', 'stderrlogger', 'socketlogger', 'nulllogger']:
+ self._typeLogger = value.lower()
+ elif key == self._logKey + 'LogLevel':
+ self._logLevelThreshold = self._intLogLevel(value.upper())
+ elif key == self._logKey + 'Style':
+ self._fields["style"] = value
+ elif key == self._logKey:
+ self._logFile = value
+ except Exception as x:
+ print("exception reading '%s' configuration file: %s" %(self._configFile, str(x)), file=sys.stderr)
+ sys.exit(2)
+ except:
+ print("exception reading '%s' configuration file" %(self._configFile), file=sys.stderr)
+ sys.exit(2)
+
+ if self._logFile is None:
+ print('configuration file %s is missing definition %s for log file' %(self._configFile, self._logKey), file=sys.stderr)
+ sys.exit(2)
+
+
+ # initialize default log fields
+ # timestamp will automatically be generated
+ for key in ['style', 'requestID', 'serviceInstanceID', 'threadID', 'serverName', 'serviceName', 'instanceUUID', \
+ 'severity', 'serverIPAddress', 'server', 'IPAddress', 'className', 'timer', \
+ 'partnerName', 'targetEntity', 'targetServiceName', 'statusCode', 'responseCode', \
+ 'responseDescription', 'processKey', 'targetVirtualEntity', 'customField1', \
+ 'customField2', 'customField3', 'customField4', 'errorCategory', 'errorCode', \
+ 'errorDescription' ]:
+ if key in kwargs and kwargs[key] != None:
+ self._fields[key] = kwargs[key]
+
+ self._resetStyleField()
+
+ # Set up logger
+ self._logLock = threading.Lock()
+ with self._logLock:
+ self._logger = logging.getLogger(self._logKey)
+ self._logger.propagate = False
+ self._createLogger()
+
+ self._defaultServerInfo()
+
+ # spawn a thread to monitor configFile for logLevel and logFile changes
+ self._monitorFlag = True
+ self._monitorThread = threading.Thread(target=self._monitorConfigFile, args=())
+ self._monitorThread.daemon = True
+ self._monitorThread.start()
+
+
+ def _createLogger(self):
+ if self._typeLogger == 'filelogger':
+ self._mkdir_p(self._logFile)
+ if self._rotateMethod == 'time':
+ self._logHandler = logging.handlers.TimedRotatingFileHandler(self._logFile, \
+ when=self._timeRotateIntervalType, interval=self._timeRotateInterval, \
+ backupCount=self._backupCount, encoding=None, delay=False, utc=True)
+ elif self._rotateMethod == 'size':
+ self._logHandler = logging.handlers.RotatingFileHandler(self._logFile, \
+ mode=self._sizeRotateMode, maxBytes=self._sizeMaxBytes, \
+ backupCount=self._backupCount, encoding=None, delay=False)
+
+ else:
+ self._logHandler = logging.handlers.WatchedFileHandler(self._logFile, \
+ mode=self._sizeRotateMode, \
+ encoding=None, delay=False)
+ elif self._typeLogger == 'stderrlogger':
+ self._logHandler = logging.handlers.StreamHandler(sys.stderr)
+ elif self._typeLogger == 'stdoutlogger':
+ self._logHandler = logging.handlers.StreamHandler(sys.stdout)
+ elif self._typeLogger == 'socketlogger':
+ self._logHandler = logging.handlers.SocketHandler(self._socketHost, self._socketPort)
+ elif self._typeLogger == 'nulllogger':
+ self._logHandler = logging.handlers.NullHandler()
+
+ if self._fields["style"] == CommonLogger.AuditFile or self._fields["style"] == CommonLogger.MetricsFile:
+ self._logFormatter = logging.Formatter(fmt='%(begtime)s,%(begmsecs)03d+00:00|%(endtime)s,%(endmsecs)03d+00:00|%(message)s', datefmt=CommonLogger.DateFmt)
+ else:
+ self._logFormatter = logging.Formatter(fmt='%(asctime)s,%(msecs)03d+00:00|%(message)s', datefmt='%Y-%m-%dT%H:%M:%S')
+ self._logFormatter.converter = time.gmtime
+ self._logHandler.setFormatter(self._logFormatter)
+ self._logger.addHandler(self._logHandler)
+
+ def _resetStyleField(self):
+ styleFields = ["error", "debug", "audit", "metrics"]
+ if self._fields['style'] in styleFields:
+ self._fields['style'] = styleFields.index(self._fields['style'])
+
+ def __del__(self):
+ if self._monitorFlag == False:
+ return
+
+ self._monitorFlag = False
+
+ if self._monitorThread is not None and self._monitorThread.is_alive():
+ self._monitorThread.join()
+
+ self._monitorThread = None
+
+
+ def _defaultServerInfo(self):
+
+ # If not set or purposely set = None, then set default
+ if self._fields.get('server') is None:
+ try:
+ self._fields['server'] = socket.getfqdn()
+ except Exception as err:
+ try:
+ self._fields['server'] = socket.gethostname()
+ except Exception as err:
+ self._fields['server'] = ""
+
+ # If not set or purposely set = None, then set default
+ if self._fields.get('serverIPAddress') is None:
+ try:
+ self._fields['serverIPAddress'] = socket.gethostbyname(self._fields['server'])
+ except Exception as err:
+ self._fields['serverIPAddress'] = ""
+
+
+ def _monitorConfigFile(self):
+ while self._monitorFlag:
+ try:
+ fileTime = os.path.getmtime(self._configFile)
+ if fileTime > self._configFileModified:
+ self._configFileModified = fileTime
+ ReopenLogFile = False
+ logFile = self._logFile
+ with open(self._configFile) as fp:
+ for line in fp:
+ line = line.split('#',1)[0] # remove comments
+ if '=' in line:
+ key, value = [x.strip() for x in line.split('=',1)]
+ if key == 'rotateMethod' and value.lower() in ['time', 'size', 'none'] and self._rotateMethod != value:
+ self._rotateMethod = value.lower()
+ ReopenLogFile = True
+ elif key == 'timeRotateIntervalType' and value in ['S', 'M', 'H', 'D', 'W0', 'W1', 'W2', 'W3', 'W4', 'W5', 'W6', 'midnight']:
+ self._timeRotateIntervalType = value
+ ReopenLogFile = True
+ elif key == 'timeRotateInterval' and int( value ) > 0:
+ self._timeRotateInterval = int( value )
+ ReopenLogFile = True
+ elif key == 'sizeMaxBytes' and int( value ) >= 0:
+ self._sizeMaxBytes = int( value )
+ ReopenLogFile = True
+ elif key == 'sizeRotateMode' and value in ['a']:
+ self._sizeRotateMode = value
+ ReopenLogFile = True
+ elif key == 'backupCount' and int( value ) >= 0:
+ self._backupCount = int( value )
+ ReopenLogFile = True
+ elif key == self._logKey + 'SocketHost' and self._socketHost != value:
+ self._socketHost = value
+ ReopenLogFile = True
+ elif key == self._logKey + 'SocketPort' and self._socketPort > 0 and self._socketPort != int( value ):
+ self._socketPort = int( value )
+ ReopenLogFile = True
+ elif key == self._logKey + 'LogLevel' and self._logLevelThreshold != self._intLogLevel( value.upper() ):
+ self._logLevelThreshold = self._intLogLevel(value.upper())
+ elif key == self._logKey + 'LogType' and self._typeLogger != value and value.lower() in ['filelogger', 'stdoutlogger', 'stderrlogger', 'socketlogger', 'nulllogger']:
+ self._typeLogger = value.lower()
+ ReopenLogFile = True
+ elif key == self._logKey + 'Style':
+ self._fields["style"] = value
+ self._resetStyleField()
+ elif key == self._logKey and self._logFile != value:
+ logFile = value
+ ReopenLogFile = True
+ if ReopenLogFile:
+ with self._logLock:
+ self._logger.removeHandler(self._logHandler)
+ self._logFile = logFile
+ self._createLogger()
+ except Exception as err:
+ pass
+
+ time.sleep(5)
+
+
+ def setFields(self, **kwargs):
+ """Set default values for log fields.
+
+ Keyword arguments: Annotations are d:debug, a=audit, m=metrics, e=error
+ style -- the log file format (style) to use when writing log messages
+ requestID (dame) -- optional default value for this log record field.
+ serviceInstanceID (am) -- optional default value for this log record field.
+ threadID (am) -- optional default value for this log record field.
+ serverName (am) -- optional default value for this log record field.
+ serviceName (am) -- optional default value for this log record field.
+ instanceUUID (am) -- optional default value for this log record field.
+ severity (am) -- optional default value for this log record field.
+ serverIPAddress (am) -- optional default value for this log record field.
+ server (am) -- optional default value for this log record field.
+ IPAddress (am) -- optional default value for this log record field.
+ className (am) -- optional default value for this log record field.
+ timer (am) -- (ElapsedTime) optional default value for this log record field.
+ partnerName (ame) -- optional default value for this log record field.
+ targetEntity (me) -- optional default value for this log record field.
+ targetServiceName (me) -- optional default value for this log record field.
+ statusCode (am) -- optional default value for this log record field.
+ responseCode (am) -- optional default value for this log record field.
+ responseDescription (am) -- optional default value for this log record field.
+ processKey (am) -- optional default value for this log record field.
+ targetVirtualEntity (m) -- optional default value for this log record field.
+ customField1 (am) -- optional default value for this log record field.
+ customField2 (am) -- optional default value for this log record field.
+ customField3 (am) -- optional default value for this log record field.
+ customField4 (am) -- optional default value for this log record field.
+ errorCategory (e) -- optional default value for this log record field.
+ errorCode (e) -- optional default value for this log record field.
+ errorDescription (e) -- optional default value for this log record field.
+
+ Note: the pipe '|' character is not allowed in any log record field.
+ """
+
+ for key in ['style', 'requestID', 'serviceInstanceID', 'threadID', 'serverName', 'serviceName', 'instanceUUID', \
+ 'severity', 'serverIPAddress', 'server', 'IPAddress', 'className', 'timer', \
+ 'partnerName', 'targetEntity', 'targetServiceName', 'statusCode', 'responseCode', \
+ 'responseDescription', 'processKey', 'targetVirtualEntity', 'customField1', \
+ 'customField2', 'customField3', 'customField4', 'errorCategory', 'errorCode', \
+ 'errorDescription' ]:
+ if key in kwargs:
+ if kwargs[key] != None:
+ self._fields[key] = kwargs[key]
+ elif key in self._fields:
+ del self._fields[key]
+
+ self._defaultServerInfo()
+
+
+ def debug(self, message, **kwargs):
+ """Write a DEBUG level message to the log file.
+
+ Arguments:
+ message -- value for the last log record field.
+
+ Keyword arguments: Annotations are d:debug, a=audit, m=metrics, e=error
+ style -- the log file format (style) to use when writing log messages
+ requestID (dame) -- optional default value for this log record field.
+ serviceInstanceID (am) -- optional default value for this log record field.
+ threadID (am) -- optional default value for this log record field.
+ serverName (am) -- optional default value for this log record field.
+ serviceName (am) -- optional default value for this log record field.
+ instanceUUID (am) -- optional default value for this log record field.
+ severity (am) -- optional default value for this log record field.
+ serverIPAddress (am) -- optional default value for this log record field.
+ server (am) -- optional default value for this log record field.
+ IPAddress (am) -- optional default value for this log record field.
+ className (am) -- optional default value for this log record field.
+ timer (am) -- (ElapsedTime) optional default value for this log record field.
+ partnerName (ame) -- optional default value for this log record field.
+ targetEntity (me) -- optional default value for this log record field.
+ targetServiceName (me) -- optional default value for this log record field.
+ statusCode (am) -- optional default value for this log record field.
+ responseCode (am) -- optional default value for this log record field.
+ responseDescription (am) -- optional default value for this log record field.
+ processKey (am) -- optional default value for this log record field.
+ targetVirtualEntity (m) -- optional default value for this log record field.
+ customField1 (am) -- optional default value for this log record field.
+ customField2 (am) -- optional default value for this log record field.
+ customField3 (am) -- optional default value for this log record field.
+ customField4 (am) -- optional default value for this log record field.
+ errorCategory (e) -- optional default value for this log record field.
+ errorCode (e) -- optional default value for this log record field.
+ errorDescription (e) -- optional default value for this log record field.
+
+ Note: the pipe '|' character is not allowed in any log record field.
+ """
+
+ self._log('DEBUG', message, **kwargs)
+
+ def info(self, message, **kwargs):
+ """Write an INFO level message to the log file.
+
+ Arguments:
+ message -- value for the last log record field.
+
+ Keyword arguments: Annotations are d:debug, a=audit, m=metrics, e=error
+ style -- the log file format (style) to use when writing log messages
+ requestID (dame) -- optional default value for this log record field.
+ serviceInstanceID (am) -- optional default value for this log record field.
+ threadID (am) -- optional default value for this log record field.
+ serverName (am) -- optional default value for this log record field.
+ serviceName (am) -- optional default value for this log record field.
+ instanceUUID (am) -- optional default value for this log record field.
+ severity (am) -- optional default value for this log record field.
+ serverIPAddress (am) -- optional default value for this log record field.
+ server (am) -- optional default value for this log record field.
+ IPAddress (am) -- optional default value for this log record field.
+ className (am) -- optional default value for this log record field.
+ timer (am) -- (ElapsedTime) optional default value for this log record field.
+ partnerName (ame) -- optional default value for this log record field.
+ targetEntity (me) -- optional default value for this log record field.
+ targetServiceName (me) -- optional default value for this log record field.
+ statusCode (am) -- optional default value for this log record field.
+ responseCode (am) -- optional default value for this log record field.
+ responseDescription (am) -- optional default value for this log record field.
+ processKey (am) -- optional default value for this log record field.
+ targetVirtualEntity (m) -- optional default value for this log record field.
+ customField1 (am) -- optional default value for this log record field.
+ customField2 (am) -- optional default value for this log record field.
+ customField3 (am) -- optional default value for this log record field.
+ customField4 (am) -- optional default value for this log record field.
+ errorCategory (e) -- optional default value for this log record field.
+ errorCode (e) -- optional default value for this log record field.
+ errorDescription (e) -- optional default value for this log record field.
+
+ Note: the pipe '|' character is not allowed in any log record field.
+ """
+
+ self._log('INFO', message, **kwargs)
+
+ def warn(self, message, **kwargs):
+ """Write a WARN level message to the log file.
+
+ Arguments:
+ message -- value for the last log record field.
+
+ Keyword arguments: Annotations are d:debug, a=audit, m=metrics, e=error
+ style -- the log file format (style) to use when writing log messages
+ requestID (dame) -- optional default value for this log record field.
+ serviceInstanceID (am) -- optional default value for this log record field.
+ threadID (am) -- optional default value for this log record field.
+ serverName (am) -- optional default value for this log record field.
+ serviceName (am) -- optional default value for this log record field.
+ instanceUUID (am) -- optional default value for this log record field.
+ severity (am) -- optional default value for this log record field.
+ serverIPAddress (am) -- optional default value for this log record field.
+ server (am) -- optional default value for this log record field.
+ IPAddress (am) -- optional default value for this log record field.
+ className (am) -- optional default value for this log record field.
+ timer (am) -- (ElapsedTime) optional default value for this log record field.
+ partnerName (ame) -- optional default value for this log record field.
+ targetEntity (me) -- optional default value for this log record field.
+ targetServiceName (me) -- optional default value for this log record field.
+ statusCode (am) -- optional default value for this log record field.
+ responseCode (am) -- optional default value for this log record field.
+ responseDescription (am) -- optional default value for this log record field.
+ processKey (am) -- optional default value for this log record field.
+ targetVirtualEntity (m) -- optional default value for this log record field.
+ customField1 (am) -- optional default value for this log record field.
+ customField2 (am) -- optional default value for this log record field.
+ customField3 (am) -- optional default value for this log record field.
+ customField4 (am) -- optional default value for this log record field.
+ errorCategory (e) -- optional default value for this log record field.
+ errorCode (e) -- optional default value for this log record field.
+ errorDescription (e) -- optional default value for this log record field.
+
+ Note: the pipe '|' character is not allowed in any log record field.
+ """
+
+ self._log('WARN', message, **kwargs)
+
+ def error(self, message, **kwargs):
+ """Write an ERROR level message to the log file.
+
+ Arguments:
+ message -- value for the last log record field.
+
+ Keyword arguments: Annotations are d:debug, a=audit, m=metrics, e=error
+ style -- the log file format (style) to use when writing log messages
+ requestID (dame) -- optional default value for this log record field.
+ serviceInstanceID (am) -- optional default value for this log record field.
+ threadID (am) -- optional default value for this log record field.
+ serverName (am) -- optional default value for this log record field.
+ serviceName (am) -- optional default value for this log record field.
+ instanceUUID (am) -- optional default value for this log record field.
+ severity (am) -- optional default value for this log record field.
+ serverIPAddress (am) -- optional default value for this log record field.
+ server (am) -- optional default value for this log record field.
+ IPAddress (am) -- optional default value for this log record field.
+ className (am) -- optional default value for this log record field.
+ timer (am) -- (ElapsedTime) optional default value for this log record field.
+ partnerName (ame) -- optional default value for this log record field.
+ targetEntity (me) -- optional default value for this log record field.
+ targetServiceName (me) -- optional default value for this log record field.
+ statusCode (am) -- optional default value for this log record field.
+ responseCode (am) -- optional default value for this log record field.
+ responseDescription (am) -- optional default value for this log record field.
+ processKey (am) -- optional default value for this log record field.
+ targetVirtualEntity (m) -- optional default value for this log record field.
+ customField1 (am) -- optional default value for this log record field.
+ customField2 (am) -- optional default value for this log record field.
+ customField3 (am) -- optional default value for this log record field.
+ customField4 (am) -- optional default value for this log record field.
+ errorCategory (e) -- optional default value for this log record field.
+ errorCode (e) -- optional default value for this log record field.
+ errorDescription (e) -- optional default value for this log record field.
+
+ Note: the pipe '|' character is not allowed in any log record field.
+ """
+
+ self._log('ERROR', message, **kwargs)
+
+ def fatal(self, message, **kwargs):
+ """Write a FATAL level message to the log file.
+
+ Arguments:
+ message -- value for the last log record field.
+
+ Keyword arguments: Annotations are d:debug, a=audit, m=metrics, e=error
+ style -- the log file format (style) to use when writing log messages
+ requestID (dame) -- optional default value for this log record field.
+ serviceInstanceID (am) -- optional default value for this log record field.
+ threadID (am) -- optional default value for this log record field.
+ serverName (am) -- optional default value for this log record field.
+ serviceName (am) -- optional default value for this log record field.
+ instanceUUID (am) -- optional default value for this log record field.
+ severity (am) -- optional default value for this log record field.
+ serverIPAddress (am) -- optional default value for this log record field.
+ server (am) -- optional default value for this log record field.
+ IPAddress (am) -- optional default value for this log record field.
+ className (am) -- optional default value for this log record field.
+ timer (am) -- (ElapsedTime) optional default value for this log record field.
+ partnerName (ame) -- optional default value for this log record field.
+ targetEntity (me) -- optional default value for this log record field.
+ targetServiceName (me) -- optional default value for this log record field.
+ statusCode (am) -- optional default value for this log record field.
+ responseCode (am) -- optional default value for this log record field.
+ responseDescription (am) -- optional default value for this log record field.
+ processKey (am) -- optional default value for this log record field.
+ targetVirtualEntity (m) -- optional default value for this log record field.
+ customField1 (am) -- optional default value for this log record field.
+ customField2 (am) -- optional default value for this log record field.
+ customField3 (am) -- optional default value for this log record field.
+ customField4 (am) -- optional default value for this log record field.
+ errorCategory (e) -- optional default value for this log record field.
+ errorCode (e) -- optional default value for this log record field.
+ errorDescription (e) -- optional default value for this log record field.
+
+ Note: the pipe '|' character is not allowed in any log record field.
+ """
+
+ self._log('FATAL', message, **kwargs)
+
+ def _log(self, logLevel, message, **kwargs):
+ """Write a message to the log file.
+
+ Arguments:
+ logLevel -- value ('DEBUG', 'INFO', 'WARN', 'ERROR', 'FATAL', ...) for the log record.
+ message -- value for the last log record field.
+
+ Keyword arguments: Annotations are d:debug, a=audit, m=metrics, e=error
+ style -- the log file format (style) to use when writing log messages
+ requestID (dame) -- optional default value for this log record field.
+ serviceInstanceID (am) -- optional default value for this log record field.
+ threadID (am) -- optional default value for this log record field.
+ serverName (am) -- optional default value for this log record field.
+ serviceName (am) -- optional default value for this log record field.
+ instanceUUID (am) -- optional default value for this log record field.
+ severity (am) -- optional default value for this log record field.
+ serverIPAddress (am) -- optional default value for this log record field.
+ server (am) -- optional default value for this log record field.
+ IPAddress (am) -- optional default value for this log record field.
+ className (am) -- optional default value for this log record field.
+ timer (am) -- (ElapsedTime) optional default value for this log record field.
+ partnerName (ame) -- optional default value for this log record field.
+ targetEntity (me) -- optional default value for this log record field.
+ targetServiceName (me) -- optional default value for this log record field.
+ statusCode (am) -- optional default value for this log record field.
+ responseCode (am) -- optional default value for this log record field.
+ responseDescription (am) -- optional default value for this log record field.
+ processKey (am) -- optional default value for this log record field.
+ targetVirtualEntity (m) -- optional default value for this log record field.
+ customField1 (am) -- optional default value for this log record field.
+ customField2 (am) -- optional default value for this log record field.
+ customField3 (am) -- optional default value for this log record field.
+ customField4 (am) -- optional default value for this log record field.
+ errorCategory (e) -- optional default value for this log record field.
+ errorCode (e) -- optional default value for this log record field.
+ errorDescription (e) -- optional default value for this log record field.
+
+ Note: the pipe '|' character is not allowed in any log record field.
+ """
+
+ # timestamp will automatically be inserted
+ style = int(self._getVal('style', '', **kwargs))
+ requestID = self._getVal('requestID', '', **kwargs)
+ serviceInstanceID = self._getVal('serviceInstanceID', '', **kwargs)
+ threadID = self._getVal('threadID', threading.currentThread().getName(), **kwargs)
+ serverName = self._getVal('serverName', '', **kwargs)
+ serviceName = self._getVal('serviceName', '', **kwargs)
+ instanceUUID = self._getVal('instanceUUID', '', **kwargs)
+ upperLogLevel = self._noSep(logLevel.upper())
+ severity = self._getVal('severity', '', **kwargs)
+ serverIPAddress = self._getVal('serverIPAddress', '', **kwargs)
+ server = self._getVal('server', '', **kwargs)
+ IPAddress = self._getVal('IPAddress', '', **kwargs)
+ className = self._getVal('className', '', **kwargs)
+ timer = self._getVal('timer', '', **kwargs)
+ partnerName = self._getVal('partnerName', '', **kwargs)
+ targetEntity = self._getVal('targetEntity', '', **kwargs)
+ targetServiceName = self._getVal('targetServiceName', '', **kwargs)
+ statusCode = self._getVal('statusCode', '', **kwargs)
+ responseCode = self._getVal('responseCode', '', **kwargs)
+ responseDescription = self._noSep(self._getVal('responseDescription', '', **kwargs))
+ processKey = self._getVal('processKey', '', **kwargs)
+ targetVirtualEntity = self._getVal('targetVirtualEntity', '', **kwargs)
+ customField1 = self._getVal('customField1', '', **kwargs)
+ customField2 = self._getVal('customField2', '', **kwargs)
+ customField3 = self._getVal('customField3', '', **kwargs)
+ customField4 = self._getVal('customField4', '', **kwargs)
+ errorCategory = self._getVal('errorCategory', '', **kwargs)
+ errorCode = self._getVal('errorCode', '', **kwargs)
+ errorDescription = self._noSep(self._getVal('errorDescription', '', **kwargs))
+
+ detailMessage = self._noSep(message)
+ if bool(re.match(r" *$", detailMessage)):
+ return # don't log empty messages
+
+ useLevel = self._intLogLevel(upperLogLevel)
+ if useLevel >= self._logLevelThreshold:
+ with self._logLock:
+ if style == CommonLogger.ErrorFile:
+ self._logger.log(50, '%s|%s|%s|%s|%s|%s|%s|%s|%s|%s' \
+ %(requestID, threadID, serviceName, partnerName, targetEntity, targetServiceName,
+ errorCategory, errorCode, errorDescription, detailMessage))
+ elif style == CommonLogger.DebugFile:
+ self._logger.log(50, '%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s' \
+ %(requestID, threadID, serverName, serviceName, instanceUUID, upperLogLevel,
+ severity, serverIPAddress, server, IPAddress, className, timer, detailMessage))
+ elif style == CommonLogger.AuditFile:
+ endAuditTime, endAuditMsec = self._getTime()
+ if self._begTime is not None:
+ d = { 'begtime': self._begTime, 'begmsecs': self._begMsec, 'endtime': endAuditTime, 'endmsecs': endAuditMsec }
+ else:
+ d = { 'begtime': endAuditTime, 'begmsecs': endAuditMsec, 'endtime': endAuditTime, 'endmsecs': endAuditMsec }
+ self._begTime = None
+ unused = ""
+ self._logger.log(50, '%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s' \
+ %(requestID, serviceInstanceID, threadID, serverName, serviceName, partnerName,
+ statusCode, responseCode, responseDescription, instanceUUID, upperLogLevel,
+ severity, serverIPAddress, timer, server, IPAddress, className, unused,
+ processKey, customField1, customField2, customField3, customField4, detailMessage), extra=d)
+ elif style == CommonLogger.MetricsFile:
+ endMetricsTime, endMetricsMsec = self._getTime()
+ if self._begTime is not None:
+ d = { 'begtime': self._begTime, 'begmsecs': self._begMsec, 'endtime': endMetricsTime, 'endmsecs': endMetricsMsec }
+ else:
+ d = { 'begtime': endMetricsTime, 'begmsecs': endMetricsMsec, 'endtime': endMetricsTime, 'endmsecs': endMetricsMsec }
+ self._begTime = None
+ unused = ""
+ self._logger.log(50, '%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s|%s' \
+ %(requestID, serviceInstanceID, threadID, serverName, serviceName, partnerName,
+ targetEntity, targetServiceName, statusCode, responseCode, responseDescription,
+ instanceUUID, upperLogLevel, severity, serverIPAddress, timer, server, IPAddress,
+ className, unused, processKey, targetVirtualEntity, customField1, customField2,
+ customField3, customField4, detailMessage), extra=d)
+ else:
+ print("!!!!!!!!!!!!!!!! style not set: %s" % self._fields["style"])
+
+ def _getTime(self):
+ ct = time.time()
+ lt = time.localtime(ct)
+ return (time.strftime(CommonLogger.DateFmt, lt), (ct - int(ct)) * 1000)
+
+ def setStartRecordEvent(self):
+ """
+ Set the start time to be saved for both audit and metrics records
+ """
+ self._begTime, self._begMsec = self._getTime()
+
+ def _getVal(self, key, default, **kwargs):
+ val = self._fields.get(key)
+ if key in kwargs: val = kwargs[key]
+ if val is None: val = default
+ return self._noSep(val)
+
+ def _noSep(self, message):
+ if message is None: return ''
+ return re.sub(r'[\|\n]', ' ', str(message))
+
+ def _intLogLevel(self, logLevel):
+ if logLevel == 'FATAL': useLevel = 50
+ elif logLevel == 'ERROR': useLevel = 40
+ elif logLevel == 'WARN': useLevel = 30
+ elif logLevel == 'INFO': useLevel = 20
+ elif logLevel == 'DEBUG': useLevel = 10
+ else: useLevel = 0
+ return useLevel
+
+ def _mkdir_p(self, filename):
+ """Create missing directories from a full filename path like mkdir -p"""
+
+ if filename is None:
+ return
+
+ folder=os.path.dirname(filename)
+
+ if folder == "":
+ return
+
+ if not os.path.exists(folder):
+ try:
+ os.makedirs(folder)
+ except OSError as err:
+ print("error number %d creating %s directory to hold %s logfile: %s" %(err.errno, err.filename, filename, err.strerror), file=sys.stderr)
+ sys.exit(2)
+ except Exception as err:
+ print("error creating %s directory to hold %s logfile: %s" %(folder, filename, str(err)), file=sys.stderr)
+ sys.exit(2)
+
+def __checkTime1(line):
+ format = r'[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]T[0-9][0-9]:[0-9][0-9]:[0-9][0-9],[0-9][0-9][0-9][+]00:00[|]'
+ format = r'[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2},[0-9]{3}[+]00:00[|]'
+ m = re.match(format, line)
+ if not m:
+ print("ERROR: time string did not match proper time format, %s" %line)
+ print("\t: format=%s" % format)
+ return 1
+ return 0
+
+def __checkTime2(line, different):
+ format = '[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]T[0-9][0-9]:[0-9][0-9]:([0-9][0-9]),([0-9][0-9][0-9])[+]00:00[|][0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]T[0-9][0-9]:[0-9][0-9]:([0-9][0-9]),([0-9][0-9][0-9])[+]00:00[|]'
+ format = r'[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:([0-9]{2}),([0-9]{3})[+]00:00[|][0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:([0-9]{2}),([0-9]{3})[+]00:00[|]'
+ m = re.match(format, line)
+ if not m:
+ print("ERROR: time strings did not match proper time format, %s" %line)
+ print("\t: format=%s" % format)
+ return 1
+ second1 = int(m.group(1))
+ msec1 = int(m.group(2))
+ second2 = int(m.group(3))
+ msec2 = int(m.group(4))
+ if second1 > second2: second2 += 60
+ t1 = second1 * 1000 + msec1
+ t2 = second2 * 1000 + msec2
+ diff = t2 - t1
+ # print("t1=%d (%d,%d) t2=%d (%d,%d), diff = %d" % (t1, second1, msec1, t2, second2, msec2, diff))
+ if different:
+ if diff < 500:
+ print("ERROR: times did not differ enough: %s" % line)
+ return 1
+ else:
+ if diff > 10:
+ print("ERROR: times were too far apart: %s" % line)
+ return 1
+ return 0
+
+def __checkLog(logfile, numLines, numFields):
+ lineCount = 0
+ errorCount = 0
+ with open(logfile, "r") as fp:
+ for line in fp:
+ # print("saw line %s" % line)
+ lineCount += 1
+ c = line.count('|')
+ if c != numFields:
+ print("ERROR: wrong number of fields. Expected %d, got %d: %s" % (numFields, c, line))
+ errorCount += 1
+ if re.search("should not appear", line):
+ print("ERROR: a line appeared that should not have appeared, %s" % line)
+ errorCount += 1
+ elif re.search("single time", line):
+ errorCount += __checkTime1(line)
+ elif re.search("time should be the same", line):
+ errorCount += __checkTime2(line, different=False)
+ elif re.search("time should be different", line):
+ errorCount += __checkTime2(line, different=True)
+ else:
+ print("ERROR: an unknown message appeared, %s" % line)
+ errorCount += 1
+
+ if lineCount != numLines:
+ print("ERROR: expected %d lines, but got %d lines" % (numLines, lineCount))
+ errorCount += 1
+ return errorCount
+
+if __name__ == "__main__":
+ import os
+ keepLogs = False
+ spid = str(os.getpid())
+ if keepLogs:
+ spid = ""
+ logcfg = "/tmp/log" + spid + ".cfg"
+ errorLog = "/tmp/error" + spid + ".log"
+ metricsLog = "/tmp/metrics" + spid + ".log"
+ auditLog = "/tmp/audit" + spid + ".log"
+ debugLog = "/tmp/debug" + spid + ".log"
+
+ import atexit
+ def cleanupTmps():
+ for f in [ logcfg, errorLog, metricsLog, auditLog, debugLog ]:
+ try:
+ os.remove(f)
+ except:
+ pass
+ if not keepLogs:
+ atexit.register(cleanupTmps)
+
+ with open(logcfg, "w") as o:
+ o.write("error = " + errorLog + "\n" +
+ "errorLogLevel = WARN\n" +
+ "metrics = " + metricsLog + "\n" +
+ "metricsLogLevel = INFO\n" +
+ "audit = " + auditLog + "\n" +
+ "auditLogLevel = INFO\n" +
+ "debug = " + debugLog + "\n" +
+ "debugLogLevel = DEBUG\n")
+
+ import uuid
+ instanceUUID = uuid.uuid1()
+ serviceName = "testharness"
+ errorLogger = CommonLogger(logcfg, "error", style=CommonLogger.ErrorFile, instanceUUID=instanceUUID, serviceName=serviceName)
+ debugLogger = CommonLogger(logcfg, "debug", style=CommonLogger.DebugFile, instanceUUID=instanceUUID, serviceName=serviceName)
+ auditLogger = CommonLogger(logcfg, "audit", style=CommonLogger.AuditFile, instanceUUID=instanceUUID, serviceName=serviceName)
+ metricsLogger = CommonLogger(logcfg, "metrics", style=CommonLogger.MetricsFile, instanceUUID=instanceUUID, serviceName=serviceName)
+
+ testsRun = 0
+ errorCount = 0
+ errorLogger.debug("error calling debug (should not appear)")
+ errorLogger.info("error calling info (should not appear)")
+ errorLogger.warn("error calling warn (single time)")
+ errorLogger.error("error calling error (single time)")
+ errorLogger.setStartRecordEvent()
+ time.sleep(1)
+ errorLogger.fatal("error calling fatal, after setStartRecordEvent and sleep (start should be ignored, single time)")
+ testsRun += 6
+ errorCount += __checkLog(errorLog, 3, 10)
+
+ auditLogger.debug("audit calling debug (should not appear)")
+ auditLogger.info("audit calling info (time should be the same)")
+ auditLogger.warn("audit calling warn (time should be the same)")
+ auditLogger.error("audit calling error (time should be the same)")
+ auditLogger.setStartRecordEvent()
+ time.sleep(1)
+ auditLogger.fatal("audit calling fatal, after setStartRecordEvent and sleep, time should be different)")
+ testsRun += 6
+ errorCount += __checkLog(auditLog, 4, 25)
+
+ debugLogger.debug("debug calling debug (single time)")
+ debugLogger.info("debug calling info (single time)")
+ debugLogger.warn("debug calling warn (single time)")
+ debugLogger.setStartRecordEvent()
+ time.sleep(1)
+ debugLogger.error("debug calling error, after SetStartRecordEvent and sleep (start should be ignored, single time)")
+ debugLogger.fatal("debug calling fatal (single time)")
+ errorCount += __checkLog(debugLog, 5, 13)
+ testsRun += 6
+
+ metricsLogger.debug("metrics calling debug (should not appear)")
+ metricsLogger.info("metrics calling info (time should be the same)")
+ metricsLogger.warn("metrics calling warn (time should be the same)")
+ metricsLogger.setStartRecordEvent()
+ time.sleep(1)
+ metricsLogger.error("metrics calling error, after SetStartRecordEvent and sleep, time should be different")
+ metricsLogger.fatal("metrics calling fatal (time should be the same)")
+ testsRun += 6
+ errorCount += __checkLog(metricsLog, 4, 28)
+
+ print("%d tests run, %d errors found" % (testsRun, errorCount))
diff --git a/pgaas/src/stage/opt/app/pgaas/lib/dcae_admin_db.json b/pgaas/src/stage/opt/app/pgaas/lib/dcae_admin_db.json
new file mode 100644
index 0000000..1e869e8
--- /dev/null
+++ b/pgaas/src/stage/opt/app/pgaas/lib/dcae_admin_db.json
@@ -0,0 +1,42 @@
+{
+ "version": "1.0",
+
+ "global":
+ {
+ "state": "master",
+ "sendWalTo":
+ [
+ {
+
+ }
+ ]
+ },
+
+ "databases":
+ [
+ {
+ "name": "ojcit",
+ "users":
+ [
+ {
+ "id": "ojcitadmin",
+ "password": "bar",
+ "role": "admin",
+ "roleComment": "admin|writer|reader"
+ },
+ {
+ "id": "ojcituser",
+ "password": "bar",
+ "role": "writer",
+ "roleComment": "admin|writer|reader"
+ },
+ {
+ "id": "ojcitviewer",
+ "password": "bar",
+ "role": "reader",
+ "roleComment": "admin|writer|reader"
+ }
+ ]
+ }
+ ]
+} \ No newline at end of file
diff --git a/pgaas/src/stage/opt/app/pgaas/lib/init-logger.cfg b/pgaas/src/stage/opt/app/pgaas/lib/init-logger.cfg
new file mode 100644
index 0000000..0cfae0d
--- /dev/null
+++ b/pgaas/src/stage/opt/app/pgaas/lib/init-logger.cfg
@@ -0,0 +1,40 @@
+# You may change this file while your program is running and CommonLogger will automatically reconfigure accordingly.
+# Changing these parameters may leave old log files lying around.
+
+
+#--- Parameters that apply to all logs
+#
+# rotateMethod: time or size
+#... Note: the following two parameters apply only when rotateMethod=time
+# timeRotateIntervalType: S, M, H, D, W0 - W6, or midnight (seconds, minutes, hours, days, weekday (0=Monday), or midnight UTC)
+# timeRotateInterval: >= 1 (1 means every timeRotateIntervalType, 2 every other, 3 every third, etc.)
+#... Note: the following parameter applies only when rotateMethod=size
+# sizeMaxBytes: >= 0 (0 means no limit, else maximum filesize in Bytes)
+# backupCount: >= 0 (Number of rotated backup files to retain. If rotateMethod=time, 0 retains *all* backups. If rotateMethod=size, 0 retains *no* backups.)
+#
+rotateMethod = none
+# timeRotateIntervalType = midnight
+# timeRotateInterval = 1
+# sizeMaxBytes = 0
+# backupCount = 6
+
+
+#--- Parameters that define log filenames and their initial LogLevel threshold
+#... Note: CommonLogger will exit if your process does not have permission to write to the file.
+#
+
+error = /opt/app/log/postgresql/init/error.log
+errorLogLevel = WARN
+errorStyle = error
+
+metrics = /opt/app/log/postgresql/init/metrics.log
+metricsLogLevel = INFO
+metricsStyle = metrics
+
+audit = /opt/app/log/postgresql/init/audit.log
+auditLogLevel = INFO
+auditStyle = audit
+
+debug = /opt/app/log/postgresql/init/debug.log
+debugLogLevel = DEBUG
+debugStyle = debug
diff --git a/pgaas/src/stage/opt/app/pgaas/lib/makefile b/pgaas/src/stage/opt/app/pgaas/lib/makefile
new file mode 100644
index 0000000..a6f3266
--- /dev/null
+++ b/pgaas/src/stage/opt/app/pgaas/lib/makefile
@@ -0,0 +1,25 @@
+# Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this code except in compliance
+# with the License. You may obtain a copy of the License
+# at http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# permissions and limitations under the License.
+
+
+all:
+
+STAGEDIR=/dev/null
+DISTPATH=/opt/app/pgaas
+
+CFGFILES= CommonLogger.py pgaas.cfg init-logger.cfg
+
+stage:
+ rm -rf $(STAGEDIR)/$(DISTPATH)/lib
+ mkdir -p $(STAGEDIR)/$(DISTPATH)/lib
+ cp $(CFGFILES) $(STAGEDIR)/$(DISTPATH)/lib
diff --git a/pgaas/src/stage/opt/app/pgaas/lib/pgaas.cfg b/pgaas/src/stage/opt/app/pgaas/lib/pgaas.cfg
new file mode 100644
index 0000000..0d4cc04
--- /dev/null
+++ b/pgaas/src/stage/opt/app/pgaas/lib/pgaas.cfg
@@ -0,0 +1,31 @@
+# Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this code except in compliance
+# with the License. You may obtain a copy of the License
+# at http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# permissions and limitations under the License.
+
+
+####
+#### PostgreSQL as a Service Configuration Parameters
+####
+
+db_directory=/dbroot/pgdata/main
+# db_configuration=
+# pg_bin_directory=
+
+dcae_admin_db_hostname=localhost
+dcae_admin_db_databasename=postgres
+dcae_admin_db_username=postgres
+dcae_admin_db_verbosity=1
+dcae_admin_db_jsontop="['vmConfiguration']"
+dcae_admin_db_errors_file=/opt/app/log/postgresql/init/error.log
+dcae_admin_db_trace_file=/opt/app/log/postgresql/init/trace.log
+dcae_admin_db_common_logger_config=/opt/app/pgaas/lib/init-logger.cfg
+# skip_configuration_file=
diff --git a/pgaas/src/stage/opt/app/pgaas/makefile b/pgaas/src/stage/opt/app/pgaas/makefile
new file mode 100644
index 0000000..73232db
--- /dev/null
+++ b/pgaas/src/stage/opt/app/pgaas/makefile
@@ -0,0 +1,31 @@
+# Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this code except in compliance
+# with the License. You may obtain a copy of the License
+# at http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# permissions and limitations under the License.
+
+
+STAGEDIR=/dev/null
+all:
+
+stage:
+ for i in bin lib etc man; do \
+ ( cd $$i && $(MAKE) stage STAGEDIR=../$(STAGEDIR) ) \
+ done
+
+clean:
+ for i in bin lib etc man; do \
+ ( cd $$i && $(MAKE) clean ) \
+ done
+
+clobber:
+ for i in bin lib etc man; do \
+ ( cd $$i && $(MAKE) clobber ) \
+ done
diff --git a/pgaas/src/stage/opt/app/pgaas/man/.gitignore b/pgaas/src/stage/opt/app/pgaas/man/.gitignore
new file mode 100644
index 0000000..f7e585b
--- /dev/null
+++ b/pgaas/src/stage/opt/app/pgaas/man/.gitignore
@@ -0,0 +1 @@
+*.1
diff --git a/pgaas/src/stage/opt/app/pgaas/man/check_cluster.man b/pgaas/src/stage/opt/app/pgaas/man/check_cluster.man
new file mode 100644
index 0000000..dc6fcce
--- /dev/null
+++ b/pgaas/src/stage/opt/app/pgaas/man/check_cluster.man
@@ -0,0 +1,34 @@
+'\" Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+'\"
+'\" Licensed under the Apache License, Version 2.0 (the "License");
+'\" you may not use this code except in compliance
+'\" with the License. You may obtain a copy of the License
+'\" at http://www.apache.org/licenses/LICENSE-2.0
+'\"
+'\" Unless required by applicable law or agreed to in writing, software
+'\" distributed under the License is distributed on an "AS IS" BASIS,
+'\" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+'\" implied. See the License for the specific language governing
+'\" permissions and limitations under the License.
+.TH check_cluster 1PG {{DATE}} OpenECOMP OpenECOMP
+.SH NAME
+check_cluster - check the state of the cluster
+.SH SYNOPSIS
+check_cluster [-v] [-l] [-t timeout]
+.HP 20
+-l
+do not check localhost first (and restarting the service if necessary)
+.HP 20
+-t timeout
+set how long to wait when accessing the servers
+.HP 20
+-v
+verbose
+.SH DESCRIPTION
+Loop through the nodes in the cluster, using pgwget to determine how many are masters, secondaries, or not up.
+Complain about certain situations.
+If there are multiple masters, and this not the first master in the list, then:
+
+run pg_ctl_restart
+
+prevent /ro from returning true
diff --git a/pgaas/src/stage/opt/app/pgaas/man/dcae_admin_db.man b/pgaas/src/stage/opt/app/pgaas/man/dcae_admin_db.man
new file mode 100644
index 0000000..84b7cbb
--- /dev/null
+++ b/pgaas/src/stage/opt/app/pgaas/man/dcae_admin_db.man
@@ -0,0 +1,72 @@
+'\" Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+'\"
+'\" Licensed under the Apache License, Version 2.0 (the "License");
+'\" you may not use this code except in compliance
+'\" with the License. You may obtain a copy of the License
+'\" at http://www.apache.org/licenses/LICENSE-2.0
+'\"
+'\" Unless required by applicable law or agreed to in writing, software
+'\" distributed under the License is distributed on an "AS IS" BASIS,
+'\" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+'\" implied. See the License for the specific language governing
+'\" permissions and limitations under the License.
+.TH dcae_admin_db.py 1PG {{DATE}} OpenECOMP OpenECOMP
+.SH NAME
+dcae_admin_db.py - interface with DCAE controller
+.SH SYNOPSIS
+dcae_admin_db.py [options] configurationChanged json-file
+.br
+dcae_admin_db.py [options] suspend
+.br
+dcae_admin_db.py [options] resume
+.br
+dcae_admin_db.py [options] test
+.SS OPTIONS
+.HP 20
+-H / --dbhost=
+host name, defaults to CFG['dcae_admin_db_hostname']
+.HP 20
+-d / --dbdir=
+database directory path, defaults to CFG['db_directory']
+.HP 20
+-c / --dbconf=
+database configuration path, defaults to CFG['db_configuration']
+.HP 20
+-D / --dbname=
+database name, defaults to CFG['dcae_admin_db_databasename']
+.HP 20
+-U / --user=
+user to login as, defaults to CFG['dcae_admin_db_username']
+.HP 20
+-P / --password=
+password for user, defaults to CFG['dcae_admin_db_password']
+.HP 20
+-B / --bindir=
+postgresql bin directory, defaults to CFG['pg_bin_directory']
+.HP 20
+-i / --ignorefile=
+skip configuration if this file is present, defaults to CFG['skip_configuration_file']
+.HP 20
+-n / --nocreate
+do not create the databases / users
+.HP 20
+-I / --ignoredb
+ignore current state of database
+.HP 20
+-R / --remove
+remove old databases / users
+.HP 20
+-J / --jsontop=
+top of json tree, as in \"['pgaas']\"
+.HP 20
+-e / --errors=
+where to redirect error output, defaults to CFG['dcae_admin_db_errors_file'] then stderr
+.HP 20
+-t / --trace=
+where to redirect trace output, defaults to CFG['dcae_admin_db_trace_file'] then stderr
+.HP 20
+-v / --verbose
+verbose, defaults to CFG['dcae_admin_db_verbosity']
+.SH DESCRIPTION
+This program is intended to be executed by the DCAE controller manager.
+Given a database description json file, update the current VM accordingly
diff --git a/pgaas/src/stage/opt/app/pgaas/man/isrw.man b/pgaas/src/stage/opt/app/pgaas/man/isrw.man
new file mode 100644
index 0000000..4c4207d
--- /dev/null
+++ b/pgaas/src/stage/opt/app/pgaas/man/isrw.man
@@ -0,0 +1,19 @@
+'\" Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+'\"
+'\" Licensed under the Apache License, Version 2.0 (the "License");
+'\" you may not use this code except in compliance
+'\" with the License. You may obtain a copy of the License
+'\" at http://www.apache.org/licenses/LICENSE-2.0
+'\"
+'\" Unless required by applicable law or agreed to in writing, software
+'\" distributed under the License is distributed on an "AS IS" BASIS,
+'\" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+'\" implied. See the License for the specific language governing
+'\" permissions and limitations under the License.
+.TH isrw 1PG {{DATE}} OpenECOMP OpenECOMP
+.SH NAME
+isrw - check if a running PostgreSQL is a master or secondary
+.SH SYNOPSIS
+isrw
+.SH DESCRIPTION
+Either prints Master or Secondary depending on the state of the running PostgreSQL server.
diff --git a/pgaas/src/stage/opt/app/pgaas/man/list_masters.man b/pgaas/src/stage/opt/app/pgaas/man/list_masters.man
new file mode 100644
index 0000000..be5b2bd
--- /dev/null
+++ b/pgaas/src/stage/opt/app/pgaas/man/list_masters.man
@@ -0,0 +1,30 @@
+'\" Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+'\"
+'\" Licensed under the Apache License, Version 2.0 (the "License");
+'\" you may not use this code except in compliance
+'\" with the License. You may obtain a copy of the License
+'\" at http://www.apache.org/licenses/LICENSE-2.0
+'\"
+'\" Unless required by applicable law or agreed to in writing, software
+'\" distributed under the License is distributed on an "AS IS" BASIS,
+'\" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+'\" implied. See the License for the specific language governing
+'\" permissions and limitations under the License.
+.TH list_masters 1PG {{DATE}} OpenECOMP OpenECOMP
+.SH NAME
+list_masters - loop through the nodes in the cluster, using a remote call to determine if any are a master.
+.SH SYNOPSIS
+list_masters
+.SH DESCRIPTION
+List_masters loops through the nodes in the cluster, using a remote call to the iDNS-responder running on each server to determine if any are a master.
+The names of the masters are printed (there should only be one).
+.SS Exit Codes
+.HP 20
+0
+one master exists and is running
+.HP 20
+1
+no masters exist
+.HP 20
+2
+more than one master exist
diff --git a/pgaas/src/stage/opt/app/pgaas/man/makefile b/pgaas/src/stage/opt/app/pgaas/man/makefile
new file mode 100644
index 0000000..9cd2090
--- /dev/null
+++ b/pgaas/src/stage/opt/app/pgaas/man/makefile
@@ -0,0 +1,97 @@
+# Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this code except in compliance
+# with the License. You may obtain a copy of the License
+# at http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# permissions and limitations under the License.
+
+
+.SUFFIXES: .man .1
+
+TR2MAN =
+%.1 : %.man
+ $(TR2MAN)
+
+STAGEDIR=/dev/null
+DISTPATH=/opt/app/pgaas
+
+TRFILES := $(wildcard *.man)
+MANFILES := $(patsubst %.man,%.1,$(wildcard *.man))
+
+all: $(MANFILES)
+
+stage: $(MANFILES)
+ rm -rf $(STAGEDIR)/$(DISTPATH)/man
+ mkdir -p $(STAGEDIR)/$(DISTPATH)/man
+ cp -p $(MANFILES) $(STAGEDIR)/$(DISTPATH)/man
+
+clean:
+ rm -f *~
+
+clobber: clean
+ rm -f *.1
+
+# really should not need to list each of the files individually here with how to make them
+
+check_cluster.1: check_cluster.man
+ DATE=$$(date +%Y-%m-%d); sed "1s/ {{DATE}} / $$DATE /" < $< | nroff -Tlp -man > $@
+dcae_admin_db.1: dcae_admin_db.man
+ DATE=$$(date +%Y-%m-%d); sed "1s/ {{DATE}} / $$DATE /" < $< | nroff -Tlp -man > $@
+isrw.1: isrw.man
+ DATE=$$(date +%Y-%m-%d); sed "1s/ {{DATE}} / $$DATE /" < $< | nroff -Tlp -man > $@
+list_masters.1: list_masters.man
+ DATE=$$(date +%Y-%m-%d); sed "1s/ {{DATE}} / $$DATE /" < $< | nroff -Tlp -man > $@
+pg_ctl_promote.1: pg_ctl_promote.man
+ DATE=$$(date +%Y-%m-%d); sed "1s/ {{DATE}} / $$DATE /" < $< | nroff -Tlp -man > $@
+pg_ctl_restart.1: pg_ctl_restart.man
+ DATE=$$(date +%Y-%m-%d); sed "1s/ {{DATE}} / $$DATE /" < $< | nroff -Tlp -man > $@
+pg_ctl_start.1: pg_ctl_start.man
+ DATE=$$(date +%Y-%m-%d); sed "1s/ {{DATE}} / $$DATE /" < $< | nroff -Tlp -man > $@
+pg_ctl_status.1: pg_ctl_status.man
+ DATE=$$(date +%Y-%m-%d); sed "1s/ {{DATE}} / $$DATE /" < $< | nroff -Tlp -man > $@
+pg_ctl_stop.1: pg_ctl_stop.man
+ DATE=$$(date +%Y-%m-%d); sed "1s/ {{DATE}} / $$DATE /" < $< | nroff -Tlp -man > $@
+repmgrc.1: repmgrc.man
+ DATE=$$(date +%Y-%m-%d); sed "1s/ {{DATE}} / $$DATE /" < $< | nroff -Tlp -man > $@
+repmgrdc.1: repmgrdc.man
+ DATE=$$(date +%Y-%m-%d); sed "1s/ {{DATE}} / $$DATE /" < $< | nroff -Tlp -man > $@
+runpsqll.1: runpsqll.man
+ DATE=$$(date +%Y-%m-%d); sed "1s/ {{DATE}} / $$DATE /" < $< | nroff -Tlp -man > $@
+runpsql.1: runpsql.man
+ DATE=$$(date +%Y-%m-%d); sed "1s/ {{DATE}} / $$DATE /" < $< | nroff -Tlp -man > $@
+setpropvalue.1: setpropvalue.man
+ DATE=$$(date +%Y-%m-%d); sed "1s/ {{DATE}} / $$DATE /" < $< | nroff -Tlp -man > $@
+show_pg_is_in_recovery.1: show_pg_is_in_recovery.man
+ DATE=$$(date +%Y-%m-%d); sed "1s/ {{DATE}} / $$DATE /" < $< | nroff -Tlp -man > $@
+show_pg_stat_activity.1: show_pg_stat_activity.man
+ DATE=$$(date +%Y-%m-%d); sed "1s/ {{DATE}} / $$DATE /" < $< | nroff -Tlp -man > $@
+show_pg_stat_archiver.1: show_pg_stat_archiver.man
+ DATE=$$(date +%Y-%m-%d); sed "1s/ {{DATE}} / $$DATE /" < $< | nroff -Tlp -man > $@
+show_pg_stat_bgwriter.1: show_pg_stat_bgwriter.man
+ DATE=$$(date +%Y-%m-%d); sed "1s/ {{DATE}} / $$DATE /" < $< | nroff -Tlp -man > $@
+show_pg_stat_database_conflicts.1: show_pg_stat_database_conflicts.man
+ DATE=$$(date +%Y-%m-%d); sed "1s/ {{DATE}} / $$DATE /" < $< | nroff -Tlp -man > $@
+show_pg_stat_database.1: show_pg_stat_database.man
+ DATE=$$(date +%Y-%m-%d); sed "1s/ {{DATE}} / $$DATE /" < $< | nroff -Tlp -man > $@
+show_pg_statio_user_functions.1: show_pg_statio_user_functions.man
+ DATE=$$(date +%Y-%m-%d); sed "1s/ {{DATE}} / $$DATE /" < $< | nroff -Tlp -man > $@
+show_pg_statio_user_indexes.1: show_pg_statio_user_indexes.man
+ DATE=$$(date +%Y-%m-%d); sed "1s/ {{DATE}} / $$DATE /" < $< | nroff -Tlp -man > $@
+show_pg_statio_user_sequences.1: show_pg_statio_user_sequences.man
+ DATE=$$(date +%Y-%m-%d); sed "1s/ {{DATE}} / $$DATE /" < $< | nroff -Tlp -man > $@
+show_pg_statio_user_tables.1: show_pg_statio_user_tables.man
+ DATE=$$(date +%Y-%m-%d); sed "1s/ {{DATE}} / $$DATE /" < $< | nroff -Tlp -man > $@
+show_pg_stat_user_indexes.1: show_pg_stat_user_indexes.man
+ DATE=$$(date +%Y-%m-%d); sed "1s/ {{DATE}} / $$DATE /" < $< | nroff -Tlp -man > $@
+show_pg_stat_user_tables.1: show_pg_stat_user_tables.man
+ DATE=$$(date +%Y-%m-%d); sed "1s/ {{DATE}} / $$DATE /" < $< | nroff -Tlp -man > $@
+startpsql.1: startpsql.man
+ DATE=$$(date +%Y-%m-%d); sed "1s/ {{DATE}} / $$DATE /" < $< | nroff -Tlp -man > $@
+update_var_run_isrw.1: update_var_run_isrw.man
+ DATE=$$(date +%Y-%m-%d); sed "1s/ {{DATE}} / $$DATE /" < $< | nroff -Tlp -man > $@
diff --git a/pgaas/src/stage/opt/app/pgaas/man/pg_ctl_promote.man b/pgaas/src/stage/opt/app/pgaas/man/pg_ctl_promote.man
new file mode 100644
index 0000000..21d7b82
--- /dev/null
+++ b/pgaas/src/stage/opt/app/pgaas/man/pg_ctl_promote.man
@@ -0,0 +1,20 @@
+'\" Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+'\"
+'\" Licensed under the Apache License, Version 2.0 (the "License");
+'\" you may not use this code except in compliance
+'\" with the License. You may obtain a copy of the License
+'\" at http://www.apache.org/licenses/LICENSE-2.0
+'\"
+'\" Unless required by applicable law or agreed to in writing, software
+'\" distributed under the License is distributed on an "AS IS" BASIS,
+'\" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+'\" implied. See the License for the specific language governing
+'\" permissions and limitations under the License.
+.TH pg_ctl_promote 1PG {{DATE}} OpenECOMP OpenECOMP
+.SH NAME
+pg_ctl_promote - helper function to run pg_ctl promote
+.SH SYNOPSIS
+pg_ctl_promote
+.SH DESCRIPTION
+Finds the pg_ctl command, the location of the database and its configurations and runs "pg_ctl promote".
+
diff --git a/pgaas/src/stage/opt/app/pgaas/man/pg_ctl_restart.man b/pgaas/src/stage/opt/app/pgaas/man/pg_ctl_restart.man
new file mode 100644
index 0000000..e6bf6c9
--- /dev/null
+++ b/pgaas/src/stage/opt/app/pgaas/man/pg_ctl_restart.man
@@ -0,0 +1,19 @@
+'\" Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+'\"
+'\" Licensed under the Apache License, Version 2.0 (the "License");
+'\" you may not use this code except in compliance
+'\" with the License. You may obtain a copy of the License
+'\" at http://www.apache.org/licenses/LICENSE-2.0
+'\"
+'\" Unless required by applicable law or agreed to in writing, software
+'\" distributed under the License is distributed on an "AS IS" BASIS,
+'\" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+'\" implied. See the License for the specific language governing
+'\" permissions and limitations under the License.
+.TH pg_ctl_restart 1PG {{DATE}} OpenECOMP OpenECOMP
+.SH NAME
+pg_ctl_restart - helper function to run pg_ctl restart
+.SH SYNOPSIS
+pg_ctl_restart
+.SH DESCRIPTION
+Finds the pg_ctl command, the location of the database and its configurations and runs "pg_ctl stop" and "pg_ctl start".
diff --git a/pgaas/src/stage/opt/app/pgaas/man/pg_ctl_start.man b/pgaas/src/stage/opt/app/pgaas/man/pg_ctl_start.man
new file mode 100644
index 0000000..81f171d
--- /dev/null
+++ b/pgaas/src/stage/opt/app/pgaas/man/pg_ctl_start.man
@@ -0,0 +1,19 @@
+'\" Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+'\"
+'\" Licensed under the Apache License, Version 2.0 (the "License");
+'\" you may not use this code except in compliance
+'\" with the License. You may obtain a copy of the License
+'\" at http://www.apache.org/licenses/LICENSE-2.0
+'\"
+'\" Unless required by applicable law or agreed to in writing, software
+'\" distributed under the License is distributed on an "AS IS" BASIS,
+'\" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+'\" implied. See the License for the specific language governing
+'\" permissions and limitations under the License.
+.TH pg_ctl_start 1PG {{DATE}} OpenECOMP OpenECOMP
+.SH NAME
+pg_ctl_start - helper function to run pg_ctl start
+.SH SYNOPSIS
+pg_ctl_start
+.SH DESCRIPTION
+Finds the pg_ctl command, the location of the database and its configurations and runs "pg_ctl start".
diff --git a/pgaas/src/stage/opt/app/pgaas/man/pg_ctl_status.man b/pgaas/src/stage/opt/app/pgaas/man/pg_ctl_status.man
new file mode 100644
index 0000000..5a6256d
--- /dev/null
+++ b/pgaas/src/stage/opt/app/pgaas/man/pg_ctl_status.man
@@ -0,0 +1,19 @@
+'\" Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+'\"
+'\" Licensed under the Apache License, Version 2.0 (the "License");
+'\" you may not use this code except in compliance
+'\" with the License. You may obtain a copy of the License
+'\" at http://www.apache.org/licenses/LICENSE-2.0
+'\"
+'\" Unless required by applicable law or agreed to in writing, software
+'\" distributed under the License is distributed on an "AS IS" BASIS,
+'\" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+'\" implied. See the License for the specific language governing
+'\" permissions and limitations under the License.
+.TH pg_ctl_status 1PG {{DATE}} OpenECOMP OpenECOMP
+.SH NAME
+pg_ctl_status - helper function to run pg_ctl status
+.SH SYNOPSIS
+pg_ctl_status
+.SH DESCRIPTION
+Finds the pg_ctl command, the location of the database and its configurations and runs "pg_ctl status".
diff --git a/pgaas/src/stage/opt/app/pgaas/man/pg_ctl_stop.man b/pgaas/src/stage/opt/app/pgaas/man/pg_ctl_stop.man
new file mode 100644
index 0000000..ba4e71e
--- /dev/null
+++ b/pgaas/src/stage/opt/app/pgaas/man/pg_ctl_stop.man
@@ -0,0 +1,19 @@
+'\" Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+'\"
+'\" Licensed under the Apache License, Version 2.0 (the "License");
+'\" you may not use this code except in compliance
+'\" with the License. You may obtain a copy of the License
+'\" at http://www.apache.org/licenses/LICENSE-2.0
+'\"
+'\" Unless required by applicable law or agreed to in writing, software
+'\" distributed under the License is distributed on an "AS IS" BASIS,
+'\" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+'\" implied. See the License for the specific language governing
+'\" permissions and limitations under the License.
+.TH pg_ctl_stop 1PG {{DATE}} OpenECOMP OpenECOMP
+.SH NAME
+pg_ctl_stop - helper function to run pg_ctl stop
+.SH SYNOPSIS
+pg_ctl_stop
+.SH DESCRIPTION
+Finds the pg_ctl command, the location of the database and its configurations and runs "pg_ctl stop".
diff --git a/pgaas/src/stage/opt/app/pgaas/man/repmgrc.man b/pgaas/src/stage/opt/app/pgaas/man/repmgrc.man
new file mode 100644
index 0000000..18c8848
--- /dev/null
+++ b/pgaas/src/stage/opt/app/pgaas/man/repmgrc.man
@@ -0,0 +1,19 @@
+'\" Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+'\"
+'\" Licensed under the Apache License, Version 2.0 (the "License");
+'\" you may not use this code except in compliance
+'\" with the License. You may obtain a copy of the License
+'\" at http://www.apache.org/licenses/LICENSE-2.0
+'\"
+'\" Unless required by applicable law or agreed to in writing, software
+'\" distributed under the License is distributed on an "AS IS" BASIS,
+'\" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+'\" implied. See the License for the specific language governing
+'\" permissions and limitations under the License.
+.TH repmgr 1PG {{DATE}} OpenECOMP OpenECOMP
+.SH NAME
+repmgrc - helper function to run repmgr command
+.SH SYNOPSIS
+repmgrc
+.SH DESCRIPTION
+Finds the repmgr command and its configurations and runs "repmgr" appropriately.
diff --git a/pgaas/src/stage/opt/app/pgaas/man/repmgrdc.man b/pgaas/src/stage/opt/app/pgaas/man/repmgrdc.man
new file mode 100644
index 0000000..9d9617f
--- /dev/null
+++ b/pgaas/src/stage/opt/app/pgaas/man/repmgrdc.man
@@ -0,0 +1,19 @@
+'\" Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+'\"
+'\" Licensed under the Apache License, Version 2.0 (the "License");
+'\" you may not use this code except in compliance
+'\" with the License. You may obtain a copy of the License
+'\" at http://www.apache.org/licenses/LICENSE-2.0
+'\"
+'\" Unless required by applicable law or agreed to in writing, software
+'\" distributed under the License is distributed on an "AS IS" BASIS,
+'\" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+'\" implied. See the License for the specific language governing
+'\" permissions and limitations under the License.
+.TH repmgrd 1PG {{DATE}} OpenECOMP OpenECOMP
+.SH NAME
+repmgrdc - helper function to run repmgrd command
+.SH SYNOPSIS
+repmgrdc
+.SH DESCRIPTION
+Finds the repmgrd command and its configurations and runs "repmgrd" appropriately.
diff --git a/pgaas/src/stage/opt/app/pgaas/man/runpsql.man b/pgaas/src/stage/opt/app/pgaas/man/runpsql.man
new file mode 100644
index 0000000..1903d7a
--- /dev/null
+++ b/pgaas/src/stage/opt/app/pgaas/man/runpsql.man
@@ -0,0 +1,21 @@
+'\" Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+'\"
+'\" Licensed under the Apache License, Version 2.0 (the "License");
+'\" you may not use this code except in compliance
+'\" with the License. You may obtain a copy of the License
+'\" at http://www.apache.org/licenses/LICENSE-2.0
+'\"
+'\" Unless required by applicable law or agreed to in writing, software
+'\" distributed under the License is distributed on an "AS IS" BASIS,
+'\" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+'\" implied. See the License for the specific language governing
+'\" permissions and limitations under the License.
+.TH runpsql 1PG {{DATE}} OpenECOMP OpenECOMP
+.SH NAME
+runpsql - run the psql command that is given on the command line
+.SH SYNOPSIS
+runpsql sql command ...
+.SH DESCRIPTION
+Locate the psql command and run the command specified as the arguments on the command line.
+.SH "SEE ALSO"
+runpsqll, startpsql
diff --git a/pgaas/src/stage/opt/app/pgaas/man/runpsqll.man b/pgaas/src/stage/opt/app/pgaas/man/runpsqll.man
new file mode 100644
index 0000000..2098688
--- /dev/null
+++ b/pgaas/src/stage/opt/app/pgaas/man/runpsqll.man
@@ -0,0 +1,22 @@
+'\" Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+'\"
+'\" Licensed under the Apache License, Version 2.0 (the "License");
+'\" you may not use this code except in compliance
+'\" with the License. You may obtain a copy of the License
+'\" at http://www.apache.org/licenses/LICENSE-2.0
+'\"
+'\" Unless required by applicable law or agreed to in writing, software
+'\" distributed under the License is distributed on an "AS IS" BASIS,
+'\" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+'\" implied. See the License for the specific language governing
+'\" permissions and limitations under the License.
+.TH runpsqll 1PG {{DATE}} OpenECOMP OpenECOMP
+.SH NAME
+runpsqll - run the psql command that is given on the command line, no labels
+.SH SYNOPSIS
+runpsqll sql command ...
+.SH DESCRIPTION
+Locate the psql command and run the command specified as the arguments on the command line.
+Only output the tuples.
+.SH "SEE ALSO"
+runpsql, startpsql
diff --git a/pgaas/src/stage/opt/app/pgaas/man/setpropvalue.man b/pgaas/src/stage/opt/app/pgaas/man/setpropvalue.man
new file mode 100644
index 0000000..d56a2e7
--- /dev/null
+++ b/pgaas/src/stage/opt/app/pgaas/man/setpropvalue.man
@@ -0,0 +1,26 @@
+'\" Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+'\"
+'\" Licensed under the Apache License, Version 2.0 (the "License");
+'\" you may not use this code except in compliance
+'\" with the License. You may obtain a copy of the License
+'\" at http://www.apache.org/licenses/LICENSE-2.0
+'\"
+'\" Unless required by applicable law or agreed to in writing, software
+'\" distributed under the License is distributed on an "AS IS" BASIS,
+'\" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+'\" implied. See the License for the specific language governing
+'\" permissions and limitations under the License.
+.TH setpropvalue 1PG {{DATE}} OpenECOMP OpenECOMP
+.SH NAME
+setpropvalue - set a property in the CDF property file
+.SH SYNOPSIS
+setpropvalue -n name -v value [-x]
+.HP 20
+-n
+name to configure
+.HP 20
+-v
+value to set
+.HP 20
+-x
+encrypt the value
diff --git a/pgaas/src/stage/opt/app/pgaas/man/show_pg_is_in_recovery.man b/pgaas/src/stage/opt/app/pgaas/man/show_pg_is_in_recovery.man
new file mode 100644
index 0000000..a4c9474
--- /dev/null
+++ b/pgaas/src/stage/opt/app/pgaas/man/show_pg_is_in_recovery.man
@@ -0,0 +1,19 @@
+'\" Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+'\"
+'\" Licensed under the Apache License, Version 2.0 (the "License");
+'\" you may not use this code except in compliance
+'\" with the License. You may obtain a copy of the License
+'\" at http://www.apache.org/licenses/LICENSE-2.0
+'\"
+'\" Unless required by applicable law or agreed to in writing, software
+'\" distributed under the License is distributed on an "AS IS" BASIS,
+'\" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+'\" implied. See the License for the specific language governing
+'\" permissions and limitations under the License.
+.TH show_pg_is_in_recovery 1PG {{DATE}} OpenECOMP OpenECOMP
+.SH NAME
+show_pg_is_in_recovery - convenience program to extract info from the database
+.SH SYNOPSIS
+show_pg_is_in_recovery
+.SH DESCRIPTION
+show_pg_is_in_recovery is a convenience program to extract the pg_is_in_recovery information from the database.
diff --git a/pgaas/src/stage/opt/app/pgaas/man/show_pg_stat_activity.man b/pgaas/src/stage/opt/app/pgaas/man/show_pg_stat_activity.man
new file mode 100644
index 0000000..ef10efc
--- /dev/null
+++ b/pgaas/src/stage/opt/app/pgaas/man/show_pg_stat_activity.man
@@ -0,0 +1,19 @@
+'\" Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+'\"
+'\" Licensed under the Apache License, Version 2.0 (the "License");
+'\" you may not use this code except in compliance
+'\" with the License. You may obtain a copy of the License
+'\" at http://www.apache.org/licenses/LICENSE-2.0
+'\"
+'\" Unless required by applicable law or agreed to in writing, software
+'\" distributed under the License is distributed on an "AS IS" BASIS,
+'\" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+'\" implied. See the License for the specific language governing
+'\" permissions and limitations under the License.
+.TH show_pg_stat_activity 1PG {{DATE}} OpenECOMP OpenECOMP
+.SH NAME
+show_pg_stat_activity - convenience program to extract info from the database
+.SH SYNOPSIS
+show_pg_stat_activity
+.SH DESCRIPTION
+show_pg_stat_activity is a convenience program to extract the pg_stat_activity information from the database.
diff --git a/pgaas/src/stage/opt/app/pgaas/man/show_pg_stat_archiver.man b/pgaas/src/stage/opt/app/pgaas/man/show_pg_stat_archiver.man
new file mode 100644
index 0000000..f1044e2
--- /dev/null
+++ b/pgaas/src/stage/opt/app/pgaas/man/show_pg_stat_archiver.man
@@ -0,0 +1,19 @@
+'\" Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+'\"
+'\" Licensed under the Apache License, Version 2.0 (the "License");
+'\" you may not use this code except in compliance
+'\" with the License. You may obtain a copy of the License
+'\" at http://www.apache.org/licenses/LICENSE-2.0
+'\"
+'\" Unless required by applicable law or agreed to in writing, software
+'\" distributed under the License is distributed on an "AS IS" BASIS,
+'\" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+'\" implied. See the License for the specific language governing
+'\" permissions and limitations under the License.
+.TH show_pg_stat_archiver 1PG {{DATE}} OpenECOMP OpenECOMP
+.SH NAME
+show_pg_stat_archiver - convenience program to extract info from the database
+.SH SYNOPSIS
+show_pg_stat_archiver
+.SH DESCRIPTION
+show_pg_stat_archiver is a convenience program to extract the pg_stat_archiver information from the database.
diff --git a/pgaas/src/stage/opt/app/pgaas/man/show_pg_stat_bgwriter.man b/pgaas/src/stage/opt/app/pgaas/man/show_pg_stat_bgwriter.man
new file mode 100644
index 0000000..a05a18a
--- /dev/null
+++ b/pgaas/src/stage/opt/app/pgaas/man/show_pg_stat_bgwriter.man
@@ -0,0 +1,20 @@
+'\" Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+'\"
+'\" Licensed under the Apache License, Version 2.0 (the "License");
+'\" you may not use this code except in compliance
+'\" with the License. You may obtain a copy of the License
+'\" at http://www.apache.org/licenses/LICENSE-2.0
+'\"
+'\" Unless required by applicable law or agreed to in writing, software
+'\" distributed under the License is distributed on an "AS IS" BASIS,
+'\" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+'\" implied. See the License for the specific language governing
+'\" permissions and limitations under the License.
+.TH show_pg_stat_bgwriter 1PG {{DATE}} OpenECOMP OpenECOMP
+.SH NAME
+show_pg_stat_bgwriter - convenience program to extract info from the database
+.SH SYNOPSIS
+show_pg_stat_bgwriter
+.SH DESCRIPTION
+show_pg_stat_bgwriter is a convenience program to extract the pg_stat_bgwriter information from the database.
+
diff --git a/pgaas/src/stage/opt/app/pgaas/man/show_pg_stat_database.man b/pgaas/src/stage/opt/app/pgaas/man/show_pg_stat_database.man
new file mode 100644
index 0000000..5bbceb5
--- /dev/null
+++ b/pgaas/src/stage/opt/app/pgaas/man/show_pg_stat_database.man
@@ -0,0 +1,19 @@
+'\" Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+'\"
+'\" Licensed under the Apache License, Version 2.0 (the "License");
+'\" you may not use this code except in compliance
+'\" with the License. You may obtain a copy of the License
+'\" at http://www.apache.org/licenses/LICENSE-2.0
+'\"
+'\" Unless required by applicable law or agreed to in writing, software
+'\" distributed under the License is distributed on an "AS IS" BASIS,
+'\" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+'\" implied. See the License for the specific language governing
+'\" permissions and limitations under the License.
+.TH show_pg_stat_database 1PG {{DATE}} OpenECOMP OpenECOMP
+.SH NAME
+show_pg_stat_database - convenience program to extract info from the database
+.SH SYNOPSIS
+show_pg_stat_database
+.SH DESCRIPTION
+show_pg_stat_database is a convenience program to extract the pg_stat_database information from the database.
diff --git a/pgaas/src/stage/opt/app/pgaas/man/show_pg_stat_database_conflicts.man b/pgaas/src/stage/opt/app/pgaas/man/show_pg_stat_database_conflicts.man
new file mode 100644
index 0000000..d5b9b1f
--- /dev/null
+++ b/pgaas/src/stage/opt/app/pgaas/man/show_pg_stat_database_conflicts.man
@@ -0,0 +1,19 @@
+'\" Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+'\"
+'\" Licensed under the Apache License, Version 2.0 (the "License");
+'\" you may not use this code except in compliance
+'\" with the License. You may obtain a copy of the License
+'\" at http://www.apache.org/licenses/LICENSE-2.0
+'\"
+'\" Unless required by applicable law or agreed to in writing, software
+'\" distributed under the License is distributed on an "AS IS" BASIS,
+'\" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+'\" implied. See the License for the specific language governing
+'\" permissions and limitations under the License.
+.TH show_pg_stat_database_conflicts 1PG {{DATE}} OpenECOMP OpenECOMP
+.SH NAME
+show_pg_stat_database_conflicts - convenience program to extract info from the database
+.SH SYNOPSIS
+show_pg_stat_database_conflicts
+.SH DESCRIPTION
+show_pg_stat_database_conflicts is a convenience program to extract the pg_stat_database_conflicts information from the database.
diff --git a/pgaas/src/stage/opt/app/pgaas/man/show_pg_stat_user_indexes.man b/pgaas/src/stage/opt/app/pgaas/man/show_pg_stat_user_indexes.man
new file mode 100644
index 0000000..729e018
--- /dev/null
+++ b/pgaas/src/stage/opt/app/pgaas/man/show_pg_stat_user_indexes.man
@@ -0,0 +1,19 @@
+'\" Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+'\"
+'\" Licensed under the Apache License, Version 2.0 (the "License");
+'\" you may not use this code except in compliance
+'\" with the License. You may obtain a copy of the License
+'\" at http://www.apache.org/licenses/LICENSE-2.0
+'\"
+'\" Unless required by applicable law or agreed to in writing, software
+'\" distributed under the License is distributed on an "AS IS" BASIS,
+'\" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+'\" implied. See the License for the specific language governing
+'\" permissions and limitations under the License.
+.TH show_pg_stat_user_indexes 1PG {{DATE}} OpenECOMP OpenECOMP
+.SH NAME
+show_pg_stat_user_indexes - convenience program to extract info from the database
+.SH SYNOPSIS
+show_pg_stat_user_indexes
+.SH DESCRIPTION
+show_pg_stat_user_indexes is a convenience program to extract the pg_stat_user_indexes information from the database.
diff --git a/pgaas/src/stage/opt/app/pgaas/man/show_pg_stat_user_tables.man b/pgaas/src/stage/opt/app/pgaas/man/show_pg_stat_user_tables.man
new file mode 100644
index 0000000..39fa971
--- /dev/null
+++ b/pgaas/src/stage/opt/app/pgaas/man/show_pg_stat_user_tables.man
@@ -0,0 +1,20 @@
+'\" Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+'\"
+'\" Licensed under the Apache License, Version 2.0 (the "License");
+'\" you may not use this code except in compliance
+'\" with the License. You may obtain a copy of the License
+'\" at http://www.apache.org/licenses/LICENSE-2.0
+'\"
+'\" Unless required by applicable law or agreed to in writing, software
+'\" distributed under the License is distributed on an "AS IS" BASIS,
+'\" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+'\" implied. See the License for the specific language governing
+'\" permissions and limitations under the License.
+.TH show_pg_stat_user_indexes 1PG {{DATE}} OpenECOMP OpenECOMP
+.SH NAME
+show_pg_stat_user_tables - convenience program to extract info from the database
+.SH SYNOPSIS
+show_pg_stat_user_tables
+.SH DESCRIPTION
+show_pg_stat_user_tables is a convenience program to extract the pg_stat_user_tables information from the database.
+
diff --git a/pgaas/src/stage/opt/app/pgaas/man/show_pg_statio_user_functions.man b/pgaas/src/stage/opt/app/pgaas/man/show_pg_statio_user_functions.man
new file mode 100644
index 0000000..171c161
--- /dev/null
+++ b/pgaas/src/stage/opt/app/pgaas/man/show_pg_statio_user_functions.man
@@ -0,0 +1,19 @@
+'\" Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+'\"
+'\" Licensed under the Apache License, Version 2.0 (the "License");
+'\" you may not use this code except in compliance
+'\" with the License. You may obtain a copy of the License
+'\" at http://www.apache.org/licenses/LICENSE-2.0
+'\"
+'\" Unless required by applicable law or agreed to in writing, software
+'\" distributed under the License is distributed on an "AS IS" BASIS,
+'\" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+'\" implied. See the License for the specific language governing
+'\" permissions and limitations under the License.
+.TH show_pg_statio_user_functions 1PG {{DATE}} OpenECOMP OpenECOMP
+.SH NAME
+show_pg_statio_user_functions - convenience program to extract info from the database
+.SH SYNOPSIS
+show_pg_statio_user_functions
+.SH DESCRIPTION
+show_pg_statio_user_functions is a convenience program to extract the pg_statio_user_functions information from the database.
diff --git a/pgaas/src/stage/opt/app/pgaas/man/show_pg_statio_user_indexes.man b/pgaas/src/stage/opt/app/pgaas/man/show_pg_statio_user_indexes.man
new file mode 100644
index 0000000..f54f0b5
--- /dev/null
+++ b/pgaas/src/stage/opt/app/pgaas/man/show_pg_statio_user_indexes.man
@@ -0,0 +1,19 @@
+'\" Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+'\"
+'\" Licensed under the Apache License, Version 2.0 (the "License");
+'\" you may not use this code except in compliance
+'\" with the License. You may obtain a copy of the License
+'\" at http://www.apache.org/licenses/LICENSE-2.0
+'\"
+'\" Unless required by applicable law or agreed to in writing, software
+'\" distributed under the License is distributed on an "AS IS" BASIS,
+'\" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+'\" implied. See the License for the specific language governing
+'\" permissions and limitations under the License.
+.TH show_pg_statio_user_indexes 1PG {{DATE}} OpenECOMP OpenECOMP
+.SH NAME
+show_pg_statio_user_indexes - convenience program to extract info from the database
+.SH SYNOPSIS
+show_pg_statio_user_indexes
+.SH DESCRIPTION
+show_pg_statio_user_indexes is a convenience program to extract the pg_statio_user_indexes information from the database.
diff --git a/pgaas/src/stage/opt/app/pgaas/man/show_pg_statio_user_sequences.man b/pgaas/src/stage/opt/app/pgaas/man/show_pg_statio_user_sequences.man
new file mode 100644
index 0000000..cc94f5a
--- /dev/null
+++ b/pgaas/src/stage/opt/app/pgaas/man/show_pg_statio_user_sequences.man
@@ -0,0 +1,19 @@
+'\" Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+'\"
+'\" Licensed under the Apache License, Version 2.0 (the "License");
+'\" you may not use this code except in compliance
+'\" with the License. You may obtain a copy of the License
+'\" at http://www.apache.org/licenses/LICENSE-2.0
+'\"
+'\" Unless required by applicable law or agreed to in writing, software
+'\" distributed under the License is distributed on an "AS IS" BASIS,
+'\" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+'\" implied. See the License for the specific language governing
+'\" permissions and limitations under the License.
+.TH show_pg_statio_user_sequences 1PG {{DATE}} OpenECOMP OpenECOMP
+.SH NAME
+show_pg_statio_user_sequences - convenience program to extract info from the database
+.SH SYNOPSIS
+show_pg_statio_user_sequences
+.SH DESCRIPTION
+show_pg_statio_user_sequences is a convenience program to extract the pg_statio_user_sequences information from the database.
diff --git a/pgaas/src/stage/opt/app/pgaas/man/show_pg_statio_user_tables.man b/pgaas/src/stage/opt/app/pgaas/man/show_pg_statio_user_tables.man
new file mode 100644
index 0000000..14afc43
--- /dev/null
+++ b/pgaas/src/stage/opt/app/pgaas/man/show_pg_statio_user_tables.man
@@ -0,0 +1,19 @@
+'\" Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+'\"
+'\" Licensed under the Apache License, Version 2.0 (the "License");
+'\" you may not use this code except in compliance
+'\" with the License. You may obtain a copy of the License
+'\" at http://www.apache.org/licenses/LICENSE-2.0
+'\"
+'\" Unless required by applicable law or agreed to in writing, software
+'\" distributed under the License is distributed on an "AS IS" BASIS,
+'\" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+'\" implied. See the License for the specific language governing
+'\" permissions and limitations under the License.
+.TH show_pg_statio_user_tables 1PG {{DATE}} OpenECOMP OpenECOMP
+.SH NAME
+show_pg_statio_user_tables - convenience program to extract info from the database
+.SH SYNOPSIS
+show_pg_statio_user_tables
+.SH DESCRIPTION
+show_pg_statio_user_tables is a convenience program to extract the pg_statio_user_tables information from the database.
diff --git a/pgaas/src/stage/opt/app/pgaas/man/startpsql.man b/pgaas/src/stage/opt/app/pgaas/man/startpsql.man
new file mode 100644
index 0000000..dc792f6
--- /dev/null
+++ b/pgaas/src/stage/opt/app/pgaas/man/startpsql.man
@@ -0,0 +1,21 @@
+'\" Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+'\"
+'\" Licensed under the Apache License, Version 2.0 (the "License");
+'\" you may not use this code except in compliance
+'\" with the License. You may obtain a copy of the License
+'\" at http://www.apache.org/licenses/LICENSE-2.0
+'\"
+'\" Unless required by applicable law or agreed to in writing, software
+'\" distributed under the License is distributed on an "AS IS" BASIS,
+'\" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+'\" implied. See the License for the specific language governing
+'\" permissions and limitations under the License.
+.TH startpsq 1PG {{DATE}} OpenECOMP OpenECOMP
+.SH NAME
+startpsql - run the psql command
+.SH SYNOPSIS
+startpsql
+.SH DESCRIPTION
+Locate the psql command and run it.
+.SH "SEE ALSO"
+runpsql, runpsqll
diff --git a/pgaas/src/stage/opt/app/pgaas/man/update_var_run_isrw.man b/pgaas/src/stage/opt/app/pgaas/man/update_var_run_isrw.man
new file mode 100644
index 0000000..bc5ecc8
--- /dev/null
+++ b/pgaas/src/stage/opt/app/pgaas/man/update_var_run_isrw.man
@@ -0,0 +1,23 @@
+'\" Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+'\"
+'\" Licensed under the Apache License, Version 2.0 (the "License");
+'\" you may not use this code except in compliance
+'\" with the License. You may obtain a copy of the License
+'\" at http://www.apache.org/licenses/LICENSE-2.0
+'\"
+'\" Unless required by applicable law or agreed to in writing, software
+'\" distributed under the License is distributed on an "AS IS" BASIS,
+'\" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+'\" implied. See the License for the specific language governing
+'\" permissions and limitations under the License.
+.TH startpsq 1PG {{DATE}} OpenECOMP OpenECOMP
+.SH NAME
+update_var_run_isrw - update the /var/run/postgresql/isrw file
+.SH SYNOPSIS
+update_var_run_isrw
+.SH DESCRIPTION
+This program updates the /var/run/postgresql/isrw file using the output of the isrw(1PG) command.
+The file is updated 6 times separated by 10 seconds.
+It is meant to be run from the postgres cron.
+.SH "SEE ALSO"
+isrw