aboutsummaryrefslogtreecommitdiffstats
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
parentd1bf35c127a238238b573103edf7dbcb1ebd48ed (diff)
Init dcae.pgaas
Change-Id: Ieef6b600f4cbb0bf4ee3910c1bfc6b36773cd2d2 Signed-off-by: lj1412 <lji@research.att.com>
-rw-r--r--.gitreview4
-rw-r--r--LICENSE.txt19
-rw-r--r--README.md17
-rw-r--r--cdf/.gitignore1
-rw-r--r--cdf/src/cdf-prop-value/README.md53
-rw-r--r--cdf/src/cdf-prop-value/buildjars/gnu_getopt.jarbin0 -> 48314 bytes
-rw-r--r--cdf/src/cdf-prop-value/cdf-prop-value/pom.xml28
-rw-r--r--cdf/src/cdf-prop-value/cdf-prop-value/src/main/java/.gitignore1
-rw-r--r--cdf/src/cdf-prop-value/cdf-prop-value/src/main/java/cdf-prop-value.jarbin0 -> 1592 bytes
-rw-r--r--cdf/src/cdf-prop-value/cdf-prop-value/src/main/java/makefile29
-rw-r--r--cdf/src/cdf-prop-value/cdf-prop-value/src/main/java/org/openecomp/dcae/cdf/.gitignore1
-rw-r--r--cdf/src/cdf-prop-value/cdf-prop-value/src/main/java/org/openecomp/dcae/cdf/CdfPropValue.java86
-rw-r--r--cdf/src/cdf-prop-value/cdf-prop-value/src/test/java/org/openecomp/dcae/cdf/cdfpropvalue/AppTest.java53
-rw-r--r--cdf/src/cdf-prop-value/cdf-util/pom.xml26
-rw-r--r--cdf/src/cdf-prop-value/cdf-util/src/main/java/.gitignore1
-rw-r--r--cdf/src/cdf-prop-value/cdf-util/src/main/java/cdf-util.jarbin0 -> 31069 bytes
-rw-r--r--cdf/src/cdf-prop-value/cdf-util/src/main/java/makefile47
-rw-r--r--cdf/src/cdf-prop-value/cdf-util/src/main/java/org/openecomp/dcae/cdf/util/common/.gitignore1
-rw-r--r--cdf/src/cdf-prop-value/cdf-util/src/main/java/org/openecomp/dcae/cdf/util/common/AsHex.java116
-rw-r--r--cdf/src/cdf-prop-value/cdf-util/src/main/java/org/openecomp/dcae/cdf/util/common/Classify.java109
-rw-r--r--cdf/src/cdf-prop-value/cdf-util/src/main/java/org/openecomp/dcae/cdf/util/common/Compress.java131
-rw-r--r--cdf/src/cdf-prop-value/cdf-util/src/main/java/org/openecomp/dcae/cdf/util/common/Convert.java97
-rw-r--r--cdf/src/cdf-prop-value/cdf-util/src/main/java/org/openecomp/dcae/cdf/util/common/G2CookieGen.java209
-rw-r--r--cdf/src/cdf-prop-value/cdf-util/src/main/java/org/openecomp/dcae/cdf/util/common/Hostname.java108
-rw-r--r--cdf/src/cdf-prop-value/cdf-util/src/main/java/org/openecomp/dcae/cdf/util/common/Pair.java40
-rw-r--r--cdf/src/cdf-prop-value/cdf-util/src/main/java/org/openecomp/dcae/cdf/util/common/Pid.java37
-rw-r--r--cdf/src/cdf-prop-value/cdf-util/src/main/java/org/openecomp/dcae/cdf/util/common/Popen.java84
-rw-r--r--cdf/src/cdf-prop-value/cdf-util/src/main/java/org/openecomp/dcae/cdf/util/common/Tuple2.java25
-rw-r--r--cdf/src/cdf-prop-value/cdf-util/src/main/java/org/openecomp/dcae/cdf/util/common/Tuple3.java29
-rw-r--r--cdf/src/cdf-prop-value/cdf-util/src/main/java/org/openecomp/dcae/cdf/util/common/Tuple4.java29
-rw-r--r--cdf/src/cdf-prop-value/cdf-util/src/main/java/org/openecomp/dcae/cdf/util/common/Uid.java69
-rw-r--r--cdf/src/cdf-prop-value/cdf-util/src/main/java/org/openecomp/dcae/cdf/util/config/.gitignore1
-rw-r--r--cdf/src/cdf-prop-value/cdf-util/src/main/java/org/openecomp/dcae/cdf/util/config/Configurable.java28
-rw-r--r--cdf/src/cdf-prop-value/cdf-util/src/main/java/org/openecomp/dcae/cdf/util/config/Configuration.java579
-rw-r--r--cdf/src/cdf-prop-value/cdf-util/src/main/java/org/openecomp/dcae/cdf/util/config/ConfigurationRegistry.java106
-rw-r--r--cdf/src/cdf-prop-value/cdf-util/src/main/java/org/openecomp/dcae/cdf/util/config/EncryptedConfiguration.java219
-rw-r--r--cdf/src/cdf-prop-value/cdf-util/src/main/java/org/openecomp/dcae/cdf/util/config/PropValue.java245
-rw-r--r--cdf/src/cdf-prop-value/cdf-util/src/main/java/org/openecomp/dcae/cdf/util/threads/.gitignore1
-rw-r--r--cdf/src/cdf-prop-value/cdf-util/src/main/java/org/openecomp/dcae/cdf/util/threads/TaskThread.java164
-rw-r--r--cdf/src/cdf-prop-value/cdf-util/src/main/java/org/openecomp/dcae/cdf/util/threads/ThreadCommon.java119
-rw-r--r--cdf/src/cdf-prop-value/cdf-util/src/test/java/org/openecomp/dcae/cdf/util/AppTest.java53
-rw-r--r--cdf/src/cdf-prop-value/makefile13
-rwxr-xr-xcdf/src/common/postinst50
-rw-r--r--cdf/src/makefile52
-rw-r--r--cdf/src/repackage.json29
-rwxr-xr-xcdf/src/stage/opt/app/cdf/bin/getpropvalue31
-rwxr-xr-xcdf/src/stage/opt/app/cdf/bin/setencryptedvalues30
-rw-r--r--cdf/src/stage/opt/app/cdf/lib/cdf.cfg.tmpl18
-rw-r--r--cdf/src/stage/opt/app/cdf/lib/jars/which_files3
-rw-r--r--makefile21
-rw-r--r--pgaas-post/.gitignore1
-rwxr-xr-xpgaas-post/src/common/postinst41
-rwxr-xr-xpgaas-post/src/common/postrm1
-rw-r--r--pgaas-post/src/makefile38
-rw-r--r--pgaas-post/src/repackage.json23
-rw-r--r--pgaas-post/src/stage/opt/app/pgaas-post/bin/pgaas-verify-install227
-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
-rw-r--r--postgresql-config/.gitignore1
-rwxr-xr-xpostgresql-config/src/common/postinst40
-rw-r--r--postgresql-config/src/makefile39
-rw-r--r--postgresql-config/src/repackage.json25
-rw-r--r--postgresql-config/src/stage/opt/app/postgresql-config/etc/common-db-tasks43
-rw-r--r--postgresql-config/src/stage/opt/app/postgresql-config/etc/create-cdf-master44
-rw-r--r--postgresql-config/src/stage/opt/app/postgresql-config/etc/create-cdf-secondary62
-rw-r--r--postgresql-config/src/stage/opt/app/postgresql-config/etc/create-db-backup34
-rw-r--r--postgresql-config/src/stage/opt/app/postgresql-config/etc/create-db-master72
-rw-r--r--postgresql-config/src/stage/opt/app/postgresql-config/etc/create-db-secondary122
-rw-r--r--postgresql-config/src/stage/opt/app/postgresql-config/etc/create-extensions53
-rw-r--r--postgresql-config/src/stage/opt/app/postgresql-config/etc/create-repmgr-user40
-rw-r--r--postgresql-config/src/stage/opt/app/postgresql-config/etc/create-ssh-master40
-rw-r--r--postgresql-config/src/stage/opt/app/postgresql-config/etc/create-ssh-secondary102
-rw-r--r--postgresql-config/src/stage/opt/app/postgresql-config/etc/do-post-install124
-rw-r--r--postgresql-config/src/stage/opt/app/postgresql-config/etc/gen-pgpass33
-rw-r--r--postgresql-config/src/stage/opt/app/postgresql-config/etc/gen-recovery.conf51
-rwxr-xr-xpostgresql-config/src/stage/opt/app/postgresql-config/etc/gen-repmgr.conf63
-rw-r--r--postgresql-config/src/stage/opt/app/postgresql-config/etc/lock-and-create-db-backup33
-rwxr-xr-xpostgresql-config/src/stage/opt/app/postgresql-config/etc/makecerts97
-rw-r--r--postgresql-config/src/stage/opt/app/postgresql-config/etc/ssleay.cnf33
-rw-r--r--postgresql-config/src/stage/opt/app/postgresql-config/etc/start-db32
-rw-r--r--postgresql-config/src/stage/opt/app/postgresql-config/etc/update-db-master63
-rw-r--r--postgresql-config/src/stage/opt/app/postgresql-config/etc/update-db-secondary95
-rw-r--r--postgresql-config/src/stage/opt/app/postgresql-config/etc/update-postgres-user34
-rw-r--r--postgresql-config/src/stage/opt/app/postgresql-config/lib/profile.additions6
-rw-r--r--postgresql-config/src/stage/opt/app/postgresql-config/main/pg_hba.conf.orig127
-rw-r--r--postgresql-config/src/stage/opt/app/postgresql-config/main/pg_ident.conf42
-rw-r--r--postgresql-config/src/stage/opt/app/postgresql-config/main/postgresql.conf.orig655
-rw-r--r--postgresql-prep/.gitignore1
-rwxr-xr-xpostgresql-prep/src/common/postinst177
-rwxr-xr-xpostgresql-prep/src/common/prerm17
-rw-r--r--postgresql-prep/src/makefile43
-rw-r--r--postgresql-prep/src/repackage.json29
-rwxr-xr-xpostgresql-prep/src/stage/opt/app/postgresql-prep/bin/gen-repmgr-info247
-rwxr-xr-xpostgresql-prep/src/stage/opt/app/postgresql-prep/bin/iDNS-responder.py1025
-rw-r--r--postgresql-prep/src/stage/opt/app/postgresql-prep/bin/makefile22
-rw-r--r--postgresql-prep/src/stage/opt/app/postgresql-prep/bin/pgwget4
-rw-r--r--postgresql-prep/src/stage/opt/app/postgresql-prep/bin/repmgrd-status-changes54
-rw-r--r--postgresql-prep/src/stage/opt/app/postgresql-prep/init/init-pgaas-idns.conf21
-rw-r--r--postgresql-prep/src/stage/opt/app/postgresql-prep/init/init-pgaas-init.conf24
-rw-r--r--postgresql-prep/src/stage/opt/app/postgresql-prep/init/logrotate24
-rw-r--r--postgresql-prep/src/stage/opt/app/postgresql-prep/init/pglogs.cron4
-rw-r--r--postgresql-prep/src/stage/opt/app/postgresql-prep/init/systemd-pgaas-idns.service12
-rw-r--r--postgresql-prep/src/stage/opt/app/postgresql-prep/init/tmpfiles-pgaas-init.conf7
-rw-r--r--postgresql-prep/src/stage/opt/app/postgresql-prep/lib/green-flasher-12x10.gifbin0 -> 827 bytes
-rw-r--r--postgresql-prep/src/stage/opt/app/postgresql-prep/lib/grey-flasher-12x10.gifbin0 -> 48 bytes
-rw-r--r--postgresql-prep/src/stage/opt/app/postgresql-prep/lib/red-flasher-12x10.gifbin0 -> 201 bytes
-rw-r--r--postgresql-prep/src/stage/opt/app/postgresql-prep/lib/stoplight-G-12x25.gifbin0 -> 975 bytes
-rw-r--r--postgresql-prep/src/stage/opt/app/postgresql-prep/lib/stoplight-R-12x25.gifbin0 -> 963 bytes
-rw-r--r--postgresql-prep/src/stage/opt/app/postgresql-prep/lib/stoplight-Y-12x25.gifbin0 -> 966 bytes
-rw-r--r--postgresql-prep/src/stage/opt/app/postgresql-prep/lib/stoplight-g-12x25.gifbin0 -> 975 bytes
-rw-r--r--postgresql-prep/src/stage/opt/app/postgresql-prep/lib/stoplight-g2-12x25.gifbin0 -> 916 bytes
-rw-r--r--postgresql-prep/src/stage/opt/app/postgresql-prep/lib/stoplight-master-green.gifbin0 -> 916 bytes
-rw-r--r--postgresql-prep/src/stage/opt/app/postgresql-prep/lib/stoplight-master-red.gifbin0 -> 425 bytes
-rw-r--r--postgresql-prep/src/stage/opt/app/postgresql-prep/lib/stoplight-master-yellow.gifbin0 -> 432 bytes
-rw-r--r--postgresql-prep/src/stage/opt/app/postgresql-prep/lib/stoplight-r-12x25.gifbin0 -> 963 bytes
-rw-r--r--postgresql-prep/src/stage/opt/app/postgresql-prep/lib/stoplight-r2-12x25.gifbin0 -> 909 bytes
-rw-r--r--postgresql-prep/src/stage/opt/app/postgresql-prep/lib/stoplight-r3-12x25.gifbin0 -> 425 bytes
-rw-r--r--postgresql-prep/src/stage/opt/app/postgresql-prep/lib/stoplight-secondary-green.gifbin0 -> 827 bytes
-rw-r--r--postgresql-prep/src/stage/opt/app/postgresql-prep/lib/stoplight-secondary-red.gifbin0 -> 201 bytes
-rw-r--r--postgresql-prep/src/stage/opt/app/postgresql-prep/lib/stoplight-secondary-yellow.gifbin0 -> 256 bytes
-rw-r--r--postgresql-prep/src/stage/opt/app/postgresql-prep/lib/stoplight-y-12x25.gifbin0 -> 966 bytes
-rw-r--r--postgresql-prep/src/stage/opt/app/postgresql-prep/lib/stoplight-y2-12x25.gifbin0 -> 909 bytes
-rw-r--r--postgresql-prep/src/stage/opt/app/postgresql-prep/lib/stoplight-y3-12x25.gifbin0 -> 432 bytes
-rw-r--r--postgresql-prep/src/stage/opt/app/postgresql-prep/lib/yellow-flasher-12x10.gifbin0 -> 256 bytes
-rw-r--r--postgresql-prep/src/testlock/.gitignore1
-rw-r--r--postgresql-prep/src/testlock/makefile56
-rw-r--r--postgresql-prep/src/testlock/testlock.138
-rw-r--r--postgresql-prep/src/testlock/testlock.c110
-rw-r--r--postgresql-prep/src/testlock/testlock.md27
200 files changed, 11636 insertions, 0 deletions
diff --git a/.gitreview b/.gitreview
new file mode 100644
index 0000000..0c21233
--- /dev/null
+++ b/.gitreview
@@ -0,0 +1,4 @@
+[gerrit]
+host=gerrit.openecomp.org
+port=29418
+project=dcae/pgaas.git
diff --git a/LICENSE.txt b/LICENSE.txt
new file mode 100644
index 0000000..c233514
--- /dev/null
+++ b/LICENSE.txt
@@ -0,0 +1,19 @@
+===========LICENSE_START==========================================
+===================================================================
+Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+===================================================================
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file 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.
+
+============LICENSE_END============================================
+
+ECOMP and OpenECOMP are trademarks and service marks of AT&T Intellectual Property.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..9c1717e
--- /dev/null
+++ b/README.md
@@ -0,0 +1,17 @@
+# PostgreSQL as a Service (PGaaS) DB VM.
+
+This package is built on top of the stock PostgreSQL and Repmgr packages.
+
+PGaaS contains a set of configuration scripts, daemons, and administrative scripts
+that allow PostgreSQL to be deployed, configured and managed by the DCAE Controller.
+PGaaS may be deployed singly or in a cascaded cluster.
+
+The running daemons provide health check and other information suitable for the
+DCAE Controller and future dashboard access.
+
+
+## Building the Code
+
+To build the code, use the "make build" command.
+
+To build the code and upload to a debian repository, use the "make debian" command.
diff --git a/cdf/.gitignore b/cdf/.gitignore
new file mode 100644
index 0000000..7c32f55
--- /dev/null
+++ b/cdf/.gitignore
@@ -0,0 +1 @@
+install
diff --git a/cdf/src/cdf-prop-value/README.md b/cdf/src/cdf-prop-value/README.md
new file mode 100644
index 0000000..101471c
--- /dev/null
+++ b/cdf/src/cdf-prop-value/README.md
@@ -0,0 +1,53 @@
+org.openecomp.dcae.cdf [^1]
+======================
+
+This repository contails two modules:
+* `cdf-util`: a port of the support functions needed to support CdfPortValue command
+* `cdf-prop-value` : contains only the CdfPortValue command
+
+## Building
+
+To build:
+* `cd cdf-util-build; mvn package`
+
+## Usage
+
+Command: `/opt/cdf/bin/getpropvalue`
+
+`/opt/cdf/bin/getpropvalue [-x] -n property -f property-file`
+ Extract the named value from the given property-file (or full pathname[^2])
+
+`/opt/cdf/bin/getpropvalue -e method [-n property] [-s salt] -v value`
+ Encrypt the given property with the given name and value
+
+`/opt/cdf/bin/getpropvalue -u value`
+ Decrypt the given value, expressed as a triple METHOD:HEXSALT:HEXVAL
+
+`/opt/cdf/bin/setencryptedvalues` (same as `/opt/cdf/bin/getpropvalue -E`)
+ Encrypt all lines that look like ENCRYPTME.METHOD.name=value
+
+## Examples
+
+ # using config files:
+
+ # echo ENCRYPTME.AES.input=bogus | /opt/cdf/bin/setencryptedvalues > testconfig.txt
+
+ # cat testconfig.txt
+ input.x=AES:353438323235:bf046d8a3e8b12fb678f5dec1e9d5743
+
+ # /opt/cdf/bin/getpropvalue -x -n input -f /home/ht1659/src/cdf/testconfig.txt
+ bogus
+
+ # No file:
+
+ # /opt/cdf/bin/getpropvalue -e AES -v bogus
+ AES:34383638353831:0e699f0f818593e3adbc642efed20341
+
+ # /opt/cdf/bin/getpropvalue -u AES:323937323833:8d95d8803978c4b13497b394d56a4a9c
+ bogus
+
+
+
+[^1]: Version 1.0, 24 Dec 2015
+
+[^2]: The property-file valued currently requires a rooted (full) pathname.
diff --git a/cdf/src/cdf-prop-value/buildjars/gnu_getopt.jar b/cdf/src/cdf-prop-value/buildjars/gnu_getopt.jar
new file mode 100644
index 0000000..8105152
--- /dev/null
+++ b/cdf/src/cdf-prop-value/buildjars/gnu_getopt.jar
Binary files differ
diff --git a/cdf/src/cdf-prop-value/cdf-prop-value/pom.xml b/cdf/src/cdf-prop-value/cdf-prop-value/pom.xml
new file mode 100644
index 0000000..208d5f7
--- /dev/null
+++ b/cdf/src/cdf-prop-value/cdf-prop-value/pom.xml
@@ -0,0 +1,28 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <groupId>org.openecomp.dcae.cdf</groupId>
+ <artifactId>cdf-prop-value</artifactId>
+ <packaging>jar</packaging>
+ <version>1.0-SNAPSHOT</version>
+ <name>cdf-prop-value</name>
+ <url>http://maven.apache.org</url>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.openecomp.dcae.cdf</groupId>
+ <artifactId>cdf-util</artifactId>
+ <version>1.0-SNAPSHOT</version>
+ </dependency>
+
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>3.8.1</version>
+ <scope>test</scope>
+ </dependency>
+
+ </dependencies>
+
+</project>
diff --git a/cdf/src/cdf-prop-value/cdf-prop-value/src/main/java/.gitignore b/cdf/src/cdf-prop-value/cdf-prop-value/src/main/java/.gitignore
new file mode 100644
index 0000000..863d673
--- /dev/null
+++ b/cdf/src/cdf-prop-value/cdf-prop-value/src/main/java/.gitignore
@@ -0,0 +1 @@
+javadoc
diff --git a/cdf/src/cdf-prop-value/cdf-prop-value/src/main/java/cdf-prop-value.jar b/cdf/src/cdf-prop-value/cdf-prop-value/src/main/java/cdf-prop-value.jar
new file mode 100644
index 0000000..ba5a4a7
--- /dev/null
+++ b/cdf/src/cdf-prop-value/cdf-prop-value/src/main/java/cdf-prop-value.jar
Binary files differ
diff --git a/cdf/src/cdf-prop-value/cdf-prop-value/src/main/java/makefile b/cdf/src/cdf-prop-value/cdf-prop-value/src/main/java/makefile
new file mode 100644
index 0000000..3591a88
--- /dev/null
+++ b/cdf/src/cdf-prop-value/cdf-prop-value/src/main/java/makefile
@@ -0,0 +1,29 @@
+go=../../../../buildjars/gnu_getopt.jar
+cu=../../../../cdf-util/src/main/java/cdf-util.jar
+
+.SUFFIXES= .class
+
+JAVA=org/openecomp/dcae/cdf/CdfPropValue.java
+CLASSES=$(JAVA:.java=.class)
+
+all:
+
+build: cdf-prop-value.jar
+
+classes: $(CLASSES)
+
+clean:
+ find . -name '*.class' -exec rm -f {} +
+ rm -rf javadoc
+
+cdf-prop-value.jar: classes
+ rm -f cdf-prop-value.jar
+ jar cvf cdf-prop-value.jar $(CLASSES)
+
+$(CLASSES): $(JAVA)
+ javac -cp $(go):$(cu) $(JAVA)
+
+javadocs:
+ rm -rf javadoc
+ mkdir -p javadoc
+ javadoc -d javadoc -classpath $(go):$(cu) $(JAVA)
diff --git a/cdf/src/cdf-prop-value/cdf-prop-value/src/main/java/org/openecomp/dcae/cdf/.gitignore b/cdf/src/cdf-prop-value/cdf-prop-value/src/main/java/org/openecomp/dcae/cdf/.gitignore
new file mode 100644
index 0000000..6b468b6
--- /dev/null
+++ b/cdf/src/cdf-prop-value/cdf-prop-value/src/main/java/org/openecomp/dcae/cdf/.gitignore
@@ -0,0 +1 @@
+*.class
diff --git a/cdf/src/cdf-prop-value/cdf-prop-value/src/main/java/org/openecomp/dcae/cdf/CdfPropValue.java b/cdf/src/cdf-prop-value/cdf-prop-value/src/main/java/org/openecomp/dcae/cdf/CdfPropValue.java
new file mode 100644
index 0000000..870835a
--- /dev/null
+++ b/cdf/src/cdf-prop-value/cdf-prop-value/src/main/java/org/openecomp/dcae/cdf/CdfPropValue.java
@@ -0,0 +1,86 @@
+/*
+ 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.
+
+*/
+package org.openecomp.dcae.cdf;
+
+import org.openecomp.dcae.cdf.util.config.PropValue;
+import java.util.logging.Logger;
+import org.openecomp.dcae.cdf.util.config.Configuration;
+import java.io.InputStream;
+import java.io.PrintStream;
+
+public class CdfPropValue extends PropValue {
+ public static String getCDFHOME() {
+ String optCdf = System.getProperty("CDF_HOME");
+ if (optCdf == null) optCdf = System.getenv("CDF_HOME");
+ if (optCdf == null) optCdf = "/opt/app/cdf";
+ return optCdf;
+ }
+
+ public static String getGLOBALPROPFILE() {
+ String optCdfCfg = System.getProperty("CDF_CFG");
+ if (optCdfCfg == null) optCdfCfg = System.getenv("CDF_CFG");
+ if (optCdfCfg == null) optCdfCfg = getCDFHOME() + "/lib/cdf.cfg";
+ return optCdfCfg;
+ }
+
+ public static void init() {
+ PropValue.setGlobalPropFile(getGLOBALPROPFILE());
+ PropValue.setEncryptionKeyProperty("Global_Title");
+ }
+ static {
+ init();
+ }
+
+ public static void printEncryptedProperty(String method, String name, String salt, String value, String globalPropFile) {
+ PropValue.printEncryptedProperty(method, name, salt, value, globalPropFile);
+ }
+ public static String generateEncryptedProperty(String method, String salt, String value, String globalPropFile) throws Exception {
+ return PropValue.generateEncryptedProperty(method, salt, value, globalPropFile);
+ }
+ public static String generateEncryptedProperty(String method, String salt, String value, PropValue propValue) throws Exception {
+ return PropValue.generateEncryptedProperty(method, salt, value, propValue);
+ }
+ public static void extractProperty(String f, String name, boolean encrypted) {
+ PropValue.extractProperty(f, name, encrypted);
+ }
+ public static void extractProperty(String f, String name, boolean encrypted, String globalPropFile) {
+ PropValue.extractProperty(f, name, encrypted, globalPropFile);
+ }
+ public static String decryptTriple(String triple, String globalPropFile) {
+ return PropValue.decryptTriple(triple, globalPropFile);
+ }
+ public static String decryptTriple(String triple, PropValue propValue) {
+ return PropValue.decryptTriple(triple, propValue);
+ }
+ public static void encryptInput(InputStream in, PrintStream out) throws Exception {
+ PropValue.encryptInput(in, out);
+ }
+ public static void encryptInput() throws Exception {
+ PropValue.encryptInput();
+ }
+ public static void encryptInput(String globalPropFile, InputStream sysin, PrintStream sysout) throws Exception {
+ PropValue.encryptInput(globalPropFile, sysin, sysout);
+ }
+ public static void main(String args[]) throws Exception {
+ PropValue.main(args);
+ }
+
+
+ public CdfPropValue(Configuration globalConfig, Logger logger) {
+ super(globalConfig, logger);
+ }
+
+}
diff --git a/cdf/src/cdf-prop-value/cdf-prop-value/src/test/java/org/openecomp/dcae/cdf/cdfpropvalue/AppTest.java b/cdf/src/cdf-prop-value/cdf-prop-value/src/test/java/org/openecomp/dcae/cdf/cdfpropvalue/AppTest.java
new file mode 100644
index 0000000..23ae351
--- /dev/null
+++ b/cdf/src/cdf-prop-value/cdf-prop-value/src/test/java/org/openecomp/dcae/cdf/cdfpropvalue/AppTest.java
@@ -0,0 +1,53 @@
+/*
+ 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.
+
+*/
+package org.openecomp.dcae.cdf.cdfpropvalue;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+
+/**
+ * Unit test for simple App.
+ */
+public class AppTest
+ extends TestCase
+{
+ /**
+ * Create the test case
+ *
+ * @param testName name of the test case
+ */
+ public AppTest( String testName )
+ {
+ super( testName );
+ }
+
+ /**
+ * @return the suite of tests being tested
+ */
+ public static Test suite()
+ {
+ return new TestSuite( AppTest.class );
+ }
+
+ /**
+ * Rigourous Test :-)
+ */
+ public void testApp()
+ {
+ assertTrue( true );
+ }
+}
diff --git a/cdf/src/cdf-prop-value/cdf-util/pom.xml b/cdf/src/cdf-prop-value/cdf-util/pom.xml
new file mode 100644
index 0000000..3f012fb
--- /dev/null
+++ b/cdf/src/cdf-prop-value/cdf-util/pom.xml
@@ -0,0 +1,26 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <groupId>org.openecomp.dcae.cdf</groupId>
+ <artifactId>cdf-util</artifactId>
+ <packaging>jar</packaging>
+ <version>1.0-SNAPSHOT</version>
+ <name>cdf-util</name>
+ <url>http://maven.apache.org</url>
+
+ <dependencies>
+ <dependency>
+ <groupId>gnu.getopt</groupId>
+ <artifactId>java-getopt</artifactId>
+ <version>1.0.13</version>
+ </dependency>
+
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>3.8.1</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+</project>
diff --git a/cdf/src/cdf-prop-value/cdf-util/src/main/java/.gitignore b/cdf/src/cdf-prop-value/cdf-util/src/main/java/.gitignore
new file mode 100644
index 0000000..863d673
--- /dev/null
+++ b/cdf/src/cdf-prop-value/cdf-util/src/main/java/.gitignore
@@ -0,0 +1 @@
+javadoc
diff --git a/cdf/src/cdf-prop-value/cdf-util/src/main/java/cdf-util.jar b/cdf/src/cdf-prop-value/cdf-util/src/main/java/cdf-util.jar
new file mode 100644
index 0000000..8c43f9a
--- /dev/null
+++ b/cdf/src/cdf-prop-value/cdf-util/src/main/java/cdf-util.jar
Binary files differ
diff --git a/cdf/src/cdf-prop-value/cdf-util/src/main/java/makefile b/cdf/src/cdf-prop-value/cdf-util/src/main/java/makefile
new file mode 100644
index 0000000..af2f0b0
--- /dev/null
+++ b/cdf/src/cdf-prop-value/cdf-util/src/main/java/makefile
@@ -0,0 +1,47 @@
+
+go=../../../../buildjars/gnu_getopt.jar
+
+.SUFFIXES= .class
+
+JAVA= org/openecomp/dcae/cdf/util/common/Classify.java \
+ org/openecomp/dcae/cdf/util/common/Tuple3.java \
+ org/openecomp/dcae/cdf/util/common/AsHex.java \
+ org/openecomp/dcae/cdf/util/common/G2CookieGen.java \
+ org/openecomp/dcae/cdf/util/common/Compress.java \
+ org/openecomp/dcae/cdf/util/common/Pair.java \
+ org/openecomp/dcae/cdf/util/common/Tuple4.java \
+ org/openecomp/dcae/cdf/util/common/Hostname.java \
+ org/openecomp/dcae/cdf/util/common/Uid.java \
+ org/openecomp/dcae/cdf/util/common/Tuple2.java \
+ org/openecomp/dcae/cdf/util/common/Pid.java \
+ org/openecomp/dcae/cdf/util/common/Convert.java \
+ org/openecomp/dcae/cdf/util/common/Popen.java \
+ org/openecomp/dcae/cdf/util/config/PropValue.java \
+ org/openecomp/dcae/cdf/util/config/Configuration.java \
+ org/openecomp/dcae/cdf/util/config/EncryptedConfiguration.java \
+ org/openecomp/dcae/cdf/util/config/Configurable.java \
+ org/openecomp/dcae/cdf/util/config/ConfigurationRegistry.java \
+ org/openecomp/dcae/cdf/util/threads/TaskThread.java \
+ org/openecomp/dcae/cdf/util/threads/ThreadCommon.java
+
+CLASSES=$(JAVA:.java=.class)
+
+all:
+
+build: cdf-util.jar
+
+cdf-util.jar: $(CLASSES)
+ rm -f cdf-util.jar
+ jar cvf cdf-util.jar $(CLASSES)
+
+clean:
+ find . -name '*.class' -exec rm -f {} +
+ rm -rf javadoc
+
+$(CLASSES): $(JAVA)
+ javac -cp $(go) $(JAVA)
+
+javadocs:
+ rm -rf javadoc
+ mkdir -p javadoc
+ javadoc -d javadoc -classpath $(go) $(JAVA)
diff --git a/cdf/src/cdf-prop-value/cdf-util/src/main/java/org/openecomp/dcae/cdf/util/common/.gitignore b/cdf/src/cdf-prop-value/cdf-util/src/main/java/org/openecomp/dcae/cdf/util/common/.gitignore
new file mode 100644
index 0000000..6b468b6
--- /dev/null
+++ b/cdf/src/cdf-prop-value/cdf-util/src/main/java/org/openecomp/dcae/cdf/util/common/.gitignore
@@ -0,0 +1 @@
+*.class
diff --git a/cdf/src/cdf-prop-value/cdf-util/src/main/java/org/openecomp/dcae/cdf/util/common/AsHex.java b/cdf/src/cdf-prop-value/cdf-util/src/main/java/org/openecomp/dcae/cdf/util/common/AsHex.java
new file mode 100644
index 0000000..9fcbdbf
--- /dev/null
+++ b/cdf/src/cdf-prop-value/cdf-util/src/main/java/org/openecomp/dcae/cdf/util/common/AsHex.java
@@ -0,0 +1,116 @@
+/*
+ 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.
+
+*/
+package org.openecomp.dcae.cdf.util.common;
+
+public class AsHex
+{
+ public static String asHex(byte[] data, int offset, int length, String sep) {
+ return asHex(data, offset, length, true);
+ }
+ public static String asHex(byte[] data, String sep) {
+ return asHex(data, 0, data.length, sep);
+ }
+ public static String asHex(byte[] data, int offset, int length) {
+ return asHex(data, offset, length, " ");
+ }
+ public static String asHex(byte[] data) {
+ return asHex(data, 0, data.length);
+ }
+
+ public static String asHex(String data) {
+ return asHex(data.getBytes());
+ }
+
+ static private int asHexBlockLength = 16;
+ public static void setAsHexBlockLength(int n) { asHexBlockLength = n; }
+ public static int getAsHexBlockLength() { return asHexBlockLength; }
+
+ private final static char[] hexdigits = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
+
+ /**
+ * return a byte buf as a hex string
+ */
+ public static String asHex(byte[] buf, int offset, int length, boolean addFinalNL) {
+ StringBuilder ret = new StringBuilder();
+ return asHex(ret, buf, offset, length, addFinalNL).toString();
+ }
+
+ /**
+ * Return a byte buf as hex into the provided StringBuilder.
+ */
+ public static StringBuilder asHex(StringBuilder ret, byte[] buf, int offset, int length, boolean addFinalNL) {
+ final int blockLength = asHexBlockLength;
+ for (int o = 0; o < length; o += blockLength) {
+ int iend = (o + blockLength < length) ? (o + blockLength) : length;
+ int pend = o + blockLength;
+ for (int i = o; i < iend; i++) {
+ int b = (int)(buf[i+offset] & 0xFF);
+ ret.append(hexdigits[b/16]);
+ ret.append(hexdigits[b%16]);
+ }
+ for (int i = iend; i < pend; i++) {
+ ret.append(" ");
+ }
+ ret.append(" ");
+ for (int i = o; i < iend; i++) {
+ byte b = buf[i+offset];
+ int ib = (int)(b & 0xFF);
+ if ((ib >= 0x20) && (ib < 0x7f)) ret.append((char)b);
+ else ret.append('.');
+ }
+ if (iend < length) ret.append('\n');
+ }
+ if (addFinalNL && (length%blockLength != 0)) ret.append('\n');
+ return ret;
+ }
+
+ /**
+ * Return a byte buf as hex with a maximum number of lines.
+ */
+ public static String asHexWithMaxLines(byte[] buf, int offset, int length, int maxLines, boolean addFinalNL) {
+ StringBuilder ret = new StringBuilder();
+ return asHexWithMaxLines(ret, buf, offset, length, maxLines, addFinalNL).toString();
+ }
+
+ /**
+ * Return a byte buf as hex into the provided StringBuilder with a maximum number of lines.
+ */
+ public static StringBuilder asHexWithMaxLines(StringBuilder ret, byte[] buf, int offset, int length, int maxLines, boolean addFinalNL) {
+ int bytesToPrint = length - offset;
+ if (maxLines < 1) maxLines = 1;
+ int maxBytesToPrint = maxLines * asHexBlockLength;
+ if (bytesToPrint <= maxBytesToPrint) {
+ return asHex(ret, buf, offset, length, addFinalNL);
+ } else {
+ if (bytesToPrint > maxBytesToPrint) bytesToPrint = maxBytesToPrint;
+ asHex(ret, buf, offset, offset + bytesToPrint, false);
+ ret.append(" ....");
+ if (addFinalNL) ret.append("\n");
+ return ret;
+ // return asHex(ret, buf, length - halfBytesToPrint, length, addFinalNL);
+ }
+ }
+
+ // Convert a hex string back to a byte array.
+ // This assumes that there is no whitespace within the string.
+ // public static byte[] fromHex(String hexStr) {
+ // byte[] bts = new byte[hexStr.length() / 2];
+ // for (int i = 0; i < bts.length; i++) {
+ // bts[i] = (byte) Integer.parseInt(hexStr.substring(2*i, 2*i+2), 16);
+ // }
+ // return bts;
+ // }
+}
diff --git a/cdf/src/cdf-prop-value/cdf-util/src/main/java/org/openecomp/dcae/cdf/util/common/Classify.java b/cdf/src/cdf-prop-value/cdf-util/src/main/java/org/openecomp/dcae/cdf/util/common/Classify.java
new file mode 100644
index 0000000..2334579
--- /dev/null
+++ b/cdf/src/cdf-prop-value/cdf-util/src/main/java/org/openecomp/dcae/cdf/util/common/Classify.java
@@ -0,0 +1,109 @@
+/*
+ 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.
+
+*/
+package org.openecomp.dcae.cdf.util.common;
+
+import java.lang.Character;
+
+/**
+ * Classify holds various checking functions.
+ */
+public final class Classify {
+
+ /**
+ * isHex(ch) - is a character a hex value?
+ *
+ * @param ch (char)
+ * @return boolean
+ */
+ public static boolean isHex(char ch) {
+ return (ch >= '0' && ch <= '9') ||
+ (ch >= 'A' && ch <= 'F') ||
+ (ch >= 'a' && ch <= 'f');
+ }
+
+ /**
+ * isValidGuid
+ *
+ * @param input (String)
+ * @return boolean
+ */
+
+ public static boolean isValidGuid(String input) {
+ // Checks if the GUID has the following format: "0f114b6f-3f1d-4c8f-a065-2a2ec3d0f522"
+
+ if ( (input == null) || (input.length() != 36)) return false;
+
+ for (int i=0; i < 36; i++) {
+ char c = input.charAt(i);
+ if ( (i==8 || i==13 || i==18 || i==23)) {
+ if (c != '-') return false;
+ }
+ else if (!isHex(c)) return false;
+ }
+ return true;
+ }
+
+
+ /**
+ * isValidClli
+ *
+ * @param input (String)
+ * @return boolean
+ */
+
+ public static boolean isValidClli(String input) {
+ // Checks if the CLLI only contains letters or digits.
+
+ if (input == null) return false;
+ int len = input.length();
+ if (len == 0) return false;
+
+ for (int i=0; i < len; i++) {
+ char c = input.charAt(i);
+ if (!Character.isLetterOrDigit(c)) return false;
+ }
+ return true;
+ }
+
+
+ /**
+ * isValidCanonicalIpv4Address
+ *
+ * @param ipAddress (String)
+ * @return boolean
+ */
+
+ public static boolean isValidCanonicalIpv4Address(String ipAddress) {
+
+ String[] parts = ipAddress.split( "\\." );
+
+ if ( parts.length != 4 ) {
+ return false;
+ }
+ for ( String s : parts ) {
+ try {
+ int i = Integer.parseInt( s );
+ if ( (i < 0) || (i > 255) ) {
+ return false;
+ }
+ } catch (Exception ex) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+}
diff --git a/cdf/src/cdf-prop-value/cdf-util/src/main/java/org/openecomp/dcae/cdf/util/common/Compress.java b/cdf/src/cdf-prop-value/cdf-util/src/main/java/org/openecomp/dcae/cdf/util/common/Compress.java
new file mode 100644
index 0000000..add6eca
--- /dev/null
+++ b/cdf/src/cdf-prop-value/cdf-util/src/main/java/org/openecomp/dcae/cdf/util/common/Compress.java
@@ -0,0 +1,131 @@
+/*
+ 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.
+
+*/
+package org.openecomp.dcae.cdf.util.common;
+
+import java.util.zip.GZIPOutputStream;
+import java.util.zip.ZipOutputStream;
+import java.util.zip.ZipEntry;
+// import java.io.InputStream;
+import java.io.FileOutputStream;
+import java.io.FileInputStream;
+import java.io.File;
+import java.io.IOException;
+
+public class Compress {
+
+ /**
+ * Compress a file with the gzip algorithm, sending output to outFilename.
+ * Based on code at http://www.java-tips.org/java-se-tips/java.util.zip/how-to-compress-a-file-in-the-gip-format.html.
+ */
+ public static void gzip(String inFilename, String outFilename) throws IOException {
+ String tmpFilename = outFilename + ".tmp";
+ try {
+ // Create the GZIP output stream
+ GZIPOutputStream out = new GZIPOutputStream(new FileOutputStream(tmpFilename));
+
+ // Open the input file
+ FileInputStream in = new FileInputStream(inFilename);
+
+ // Transfer bytes from the input file to the GZIP output stream
+ byte[] buf = new byte[4096];
+ int len;
+ while ((len = in.read(buf)) > 0) {
+ out.write(buf, 0, len);
+ }
+ in.close();
+
+ // Complete the GZIP file
+ out.finish();
+ out.close();
+
+ // rename .gz.tmp to .gz
+ File target = new File(outFilename);
+ if (target.exists()) target.delete();
+ File file = new File(tmpFilename);
+ boolean result = file.renameTo(target);
+ if (!result) throw new IOException("Cannot rename " + tmpFilename + " to " + outFilename);
+ } catch (IOException e) {
+ // If we can't write the gzip file, remove it and pass on the exception.
+ File f = new File(outFilename);
+ f.delete();
+ throw e;
+ }
+ }
+
+ /**
+ * Compress a file with the gzip algorithm, sending output to filename+".gz".
+ */
+ public static void gzip(String filename) throws IOException {
+ gzip(filename, filename + ".gz");
+ }
+
+ /**
+ * Compress a file with the zip algorithm, sending output to outFilename
+ * Based on code at http://www.java-tips.org/java-se-tips/java.util.zip/how-to-compress-a-file-in-the-gip-format.html.
+ */
+ public static void zip(String inFilename, String outFilename) throws IOException {
+ String tmpFilename = outFilename + ".tmp";
+ try {
+ // Create the ZIP output stream
+ ZipOutputStream out = new ZipOutputStream(new FileOutputStream(tmpFilename));
+ ZipEntry zipEntry = new ZipEntry(inFilename);
+ out.putNextEntry(zipEntry);
+
+ // Open the input file
+ FileInputStream in = new FileInputStream(inFilename);
+
+ // Transfer bytes from the input file to the ZIP output stream
+ byte[] buf = new byte[4096];
+ int len;
+ while ((len = in.read(buf)) > 0) {
+ out.write(buf, 0, len);
+ }
+ in.close();
+
+ // Complete the ZIP file
+ out.finish();
+ out.close();
+
+ // rename .zip.tmp to .zip
+ File target = new File(outFilename);
+ if (target.exists()) target.delete();
+ File file = new File(tmpFilename);
+ boolean result = file.renameTo(target);
+ if (!result) throw new IOException("Cannot rename " + tmpFilename + " to " + outFilename);
+ } catch (IOException e) {
+ // If we can't write the zip file, remove it and pass on the exception.
+ File f = new File(outFilename);
+ f.delete();
+ throw e;
+ }
+ }
+
+ /**
+ * Compress a file with the gzip algorithm, sending output to filename+".zip".
+ */
+ public static void zip(String filename) throws IOException {
+ zip(filename, filename + ".zip");
+ }
+
+ public static void main(String args[]) throws Exception {
+ if (args.length == 1) {
+ gzip(args[0]);
+ zip(args[0]);
+ } else {
+ System.err.println("Usage: java Compress filename");
+ }
+ }
+}
diff --git a/cdf/src/cdf-prop-value/cdf-util/src/main/java/org/openecomp/dcae/cdf/util/common/Convert.java b/cdf/src/cdf-prop-value/cdf-util/src/main/java/org/openecomp/dcae/cdf/util/common/Convert.java
new file mode 100644
index 0000000..9deba10
--- /dev/null
+++ b/cdf/src/cdf-prop-value/cdf-util/src/main/java/org/openecomp/dcae/cdf/util/common/Convert.java
@@ -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.
+
+*/
+package org.openecomp.dcae.cdf.util.common;
+
+import java.lang.Character;
+
+/**
+ * Covert holds various conversion functions.
+ */
+public final class Convert {
+
+ private static final char[] HEX_CHARS = "0123456789abcdef".toCharArray();
+
+ /**
+ * toHexString(String) - convert a string into its hex equivalent
+ */
+ public static String toHexString(String buf) {
+ if (buf == null) return "";
+ return toHexString(buf.getBytes());
+ }
+
+ /**
+ * toHexString(byte[]) - convert a byte-string into its hex equivalent
+ */
+ public static String toHexString(byte[] buf) {
+ if (buf == null) return "";
+ char[] chars = new char[2 * buf.length];
+ for (int i = 0; i < buf.length; ++i) {
+ chars[2 * i] = HEX_CHARS[(buf[i] & 0xF0) >>> 4];
+ chars[2 * i + 1] = HEX_CHARS[buf[i] & 0x0F];
+ }
+ return new String(chars);
+ }
+
+ // alternate implementation that's slightly slower
+ // protected static final byte[] Hexhars = {
+ // '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
+ // };
+ // public static String encode(byte[] b) {
+ // StringBuilder s = new StringBuilder(2 * b.length);
+ // for (int i = 0; i < b.length; i++) {
+ // int v = b[i] & 0xff;
+ // s.append((char)Hexhars[v >> 4]);
+ // s.append((char)Hexhars[v & 0xf]);
+ // }
+ // return s.toString();
+ // }
+
+ /**
+ * Convert a hex string to its equivalent value.
+ */
+ public static String stringFromHex(String hexString) throws Exception {
+ if (hexString == null) return "";
+ return stringFromHex(hexString.toCharArray());
+ }
+
+ public static String stringFromHex(char[] hexCharArray) throws Exception {
+ if (hexCharArray == null) return "";
+ return new String(bytesFromHex(hexCharArray));
+ }
+
+ public static byte[] bytesFromHex(String hexString) throws Exception {
+ if (hexString == null) return new byte[0];
+ return bytesFromHex(hexString.toCharArray());
+ }
+
+ public static byte[] bytesFromHex(char[] hexCharArray) throws Exception {
+ if (hexCharArray == null) return new byte[0];
+ int len = hexCharArray.length;
+ if ((len % 2) != 0) throw new Exception("Odd number of characters: '" + hexCharArray + "'");
+ byte [] txtInByte = new byte [len / 2];
+ int j = 0;
+ for (int i = 0; i < len; i += 2) {
+ txtInByte[j++] = (byte)(((fromHexDigit(hexCharArray[i], i) << 4) | fromHexDigit(hexCharArray[i+1], i)) & 0xFF);
+ }
+ return txtInByte;
+ }
+
+ protected final static int fromHexDigit(char ch, int index) throws Exception {
+ int digit = Character.digit(ch, 16);
+ if (digit == -1) throw new Exception("Illegal hex character '" + ch + "' at index " + index);
+ return digit;
+ }
+}
diff --git a/cdf/src/cdf-prop-value/cdf-util/src/main/java/org/openecomp/dcae/cdf/util/common/G2CookieGen.java b/cdf/src/cdf-prop-value/cdf-util/src/main/java/org/openecomp/dcae/cdf/util/common/G2CookieGen.java
new file mode 100644
index 0000000..aeed01b
--- /dev/null
+++ b/cdf/src/cdf-prop-value/cdf-util/src/main/java/org/openecomp/dcae/cdf/util/common/G2CookieGen.java
@@ -0,0 +1,209 @@
+/*
+ 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.
+
+*/
+package org.openecomp.dcae.cdf.util.common;
+
+import javax.crypto.Cipher;
+// import javax.crypto.SecretKey;
+// import javax.crypto.KeyGenerator;
+// import javax.crypto.spec.IvParameterSpec;
+import java.security.Key;
+// import java.security.NoSuchAlgorithmException;
+// import java.security.SecureRandom;
+// import javax.crypto.SecretKey;
+// import sun.misc.*;
+import java.util.*;
+
+public class G2CookieGen
+{
+ private Cipher cipher;
+ private Key key = null;
+
+ private static String alg = "DES";
+ private static String desecb = "DES/ECB/PKCS5Padding";
+
+ public static String G2_CLIENT_MEC_ID_1 = "MEC0001";
+ private static String G2_CLIENT_MEC_ID_2 = "MEC0002";
+ public static String G2_ENCRYPT_KEY = "secretK9";
+ public static String G2_EPOCH_TM_STR = null;
+
+
+ private static long G2_TM_DELTA_IN_MILLISECONDS = 10*60*1000;
+
+ class G2WSSKey implements Key
+ {
+ private final byte[] keyBytes;
+ private final String alg;
+
+ G2WSSKey(String algorithm, byte[] keyBytes)
+ {
+ this.alg = algorithm;
+ this.keyBytes = keyBytes;
+ }
+
+ public String getAlgorithm()
+ {
+ return alg;
+ }
+ public String getFormat()
+ {
+ return "RAW";
+ }
+ public byte[] getEncoded()
+ {
+ return (byte[])keyBytes.clone();
+ }
+ }
+
+
+ public G2CookieGen() {
+ try {
+ cipher = Cipher.getInstance(desecb);
+ } catch (Throwable t) {
+ System.err.println(t.toString());
+ return;
+ }
+ }
+
+
+ public static String getClient1MacId() {
+ return G2_CLIENT_MEC_ID_1;
+ }
+
+ public static String getClient2MacId() {
+ return G2_CLIENT_MEC_ID_2;
+ }
+
+ public static String toHexStringFromByteArray(byte[] bytes)
+ {
+ StringBuilder retString = new StringBuilder();
+ for (int i = 0; i < bytes.length; ++i) {
+ retString.append(Integer.toHexString(0x0100 + (bytes[i] & 0x00FF)).substring(1));
+ }
+ return retString.toString();
+ }
+
+ public static byte[] toByteArrayFromHexString(String hexStr)
+ {
+ byte[] bts = new byte[hexStr.length() / 2];
+ for (int i = 0; i < bts.length; i++) {
+ bts[i] = (byte) Integer.parseInt(hexStr.substring(2*i, 2*i+2), 16);
+ }
+ return bts;
+ }
+
+ public byte[] encryptData(String sData)
+ {
+ try {
+ byte[] data = sData.getBytes();
+ //System.out.println("Original data : " + new String(data));
+ if (key == null) setKey(G2_ENCRYPT_KEY);
+ cipher.init(Cipher.ENCRYPT_MODE, key);
+ byte[] result = cipher.doFinal(data);
+ return result;
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+ public String decryptData(byte[] sData)
+ {
+ try {
+ cipher.init(Cipher.DECRYPT_MODE, key);
+ byte[] result = cipher.doFinal(sData);
+ return new String(result);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+ public String constructCookie(String mechId) {
+ return mechId + ":" + System.currentTimeMillis();
+ }
+
+ public void setKey(String g2EncryptKey) {
+ key = new G2WSSKey(this.alg, g2EncryptKey.getBytes());
+ }
+
+ public String getEncryptedCookie(String mechId, String g2EncryptKey) {
+ setKey(g2EncryptKey);
+ String tmp = constructCookie(mechId);
+ byte[] byteArray = this.encryptData(tmp);
+ return this.toHexStringFromByteArray(byteArray);
+ }
+
+ public long getTimeMillisFromCookie(String cookie) {
+ StringTokenizer tkn = new StringTokenizer(cookie,":");
+ String tmStr = null;
+ while (tkn.hasMoreTokens()) {
+ tmStr = tkn.nextToken();
+ }
+ Long tmLong = new Long(tmStr);
+ return tmLong.longValue();
+ }
+
+ public boolean isValid(long tm) {
+ long ctm = System.currentTimeMillis();
+System.out.println("Current Time="+ctm);
+System.out.println("G2_TM_DELTA_IN_MILLISECONDS="+G2_TM_DELTA_IN_MILLISECONDS);
+ if ( Math.abs(ctm - tm) <= G2_TM_DELTA_IN_MILLISECONDS ) {
+ return true;
+ }
+ return false;
+ }
+
+
+ public static void main(String argv[]) {
+ try {
+ if (argv.length > 0) {
+System.out.println("using Client MACID="+argv[0]);
+ G2_CLIENT_MEC_ID_1 = argv[0];
+
+ }
+
+ if (argv.length > 1) {
+ if (argv[1].length() == 8) {
+System.out.println("using Key="+argv[1]);
+ G2_ENCRYPT_KEY = argv[1];
+ }
+ }
+
+ if (argv.length > 2) {
+System.out.println("using Epoch Time (in seconds) ="+argv[2]);
+ G2_EPOCH_TM_STR = argv[2];
+ }
+
+
+ G2CookieGen wssc = new G2CookieGen();
+
+// System.out.println("tz_diff="+G2_CLIENT_TM_ZONE_TO_PDT_IN_MILLISECONDS);
+System.out.println("macid="+G2_CLIENT_MEC_ID_1);
+
+ String cookie = wssc.constructCookie(G2_EPOCH_TM_STR);
+System.out.println("original cookie="+cookie);
+
+ byte[] byteArrary = wssc.encryptData(cookie);
+ String hexString = wssc.toHexStringFromByteArray(byteArrary);
+System.out.println("encrypted cookie="+hexString);
+ System.exit(0);
+
+ } catch (Exception e) {
+ System.err.println("Error: " + e);
+ System.exit(1);
+ }
+ } /* main */
+}
diff --git a/cdf/src/cdf-prop-value/cdf-util/src/main/java/org/openecomp/dcae/cdf/util/common/Hostname.java b/cdf/src/cdf-prop-value/cdf-util/src/main/java/org/openecomp/dcae/cdf/util/common/Hostname.java
new file mode 100644
index 0000000..56f312b
--- /dev/null
+++ b/cdf/src/cdf-prop-value/cdf-util/src/main/java/org/openecomp/dcae/cdf/util/common/Hostname.java
@@ -0,0 +1,108 @@
+/*
+ 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.
+
+*/
+package org.openecomp.dcae.cdf.util.common;
+
+import java.net.InetAddress;
+
+public class Hostname {
+
+ /**
+ * Hostname FQDN
+ */
+ public static String getHostName() {
+ return getHostName("unknown.unknown");
+ }
+
+ /**
+ * Hostname FQDN
+ */
+ public static String getHostName(String def) {
+ return (uname == null) ? def : hostName;
+ }
+
+ /**
+ * uname, the 1st portion of the hostname FQDN
+ */
+ public static String getUname() {
+ return getUname("unknown");
+ }
+
+ /**
+ * uname, the 1st portion of the hostname FQDN
+ */
+ public static String getUname(String def) {
+ return (uname == null) ? def : uname;
+ }
+
+ /**
+ * Get an IP address for this machine
+ */
+ public static String getLocalIP() {
+ return defaultLocalIP;
+ }
+ /**
+ * Get an IP address for this machine
+ */
+ public static String getLocalIPinHex() {
+ return defaultLocalIPinHex;
+ }
+ /**
+ * Get a host name for this machine
+ */
+ public static String getCanonicalHostName() {
+ return defaultCanonicalHostName;
+ }
+
+ /**
+ * Value returned by getLocalIP() method
+ */
+ private static String defaultLocalIP;
+ private static String defaultLocalIPinHex;
+ private static String defaultCanonicalHostName;
+ private static String hostName = null; // Hostname FQDN
+ private static String uname = null; // Hostname 1st part
+
+ static {
+ try {
+ InetAddress ia = InetAddress.getLocalHost();
+ defaultLocalIP = ia.getHostAddress();
+ byte b[] = ia.getAddress();
+ defaultLocalIPinHex = Convert.toHexString(b);
+ defaultCanonicalHostName = ia.getCanonicalHostName();
+ } catch (Exception e) {
+ defaultLocalIP = "127.0.0.1";
+ defaultLocalIPinHex = "7F000001";
+ defaultCanonicalHostName = "localhost";
+ }
+
+ try {
+ hostName = InetAddress.getLocalHost().getHostName();
+ String hostNameParts[] = hostName.split("\\.");
+ uname = hostNameParts[0];
+ } catch (Exception ex) {
+ }
+ int dotInHostname = hostName.indexOf('.');
+ if (dotInHostname > -1) hostName = hostName.substring(0, dotInHostname);
+ }
+
+ public static void main(String args[]) {
+ System.out.println("getHostName() = '" + getHostName() + "'");
+ System.out.println("getUname() = '" + getUname() + "'");
+ System.out.println("getLocalIP() = '" + getLocalIP() + "'");
+ System.out.println("getLocalIPinHex() = '" + getLocalIPinHex() + "'");
+ System.out.println("getCanonicalHostName() = '" + getCanonicalHostName() + "'");
+ }
+}
diff --git a/cdf/src/cdf-prop-value/cdf-util/src/main/java/org/openecomp/dcae/cdf/util/common/Pair.java b/cdf/src/cdf-prop-value/cdf-util/src/main/java/org/openecomp/dcae/cdf/util/common/Pair.java
new file mode 100644
index 0000000..524aa6b
--- /dev/null
+++ b/cdf/src/cdf-prop-value/cdf-util/src/main/java/org/openecomp/dcae/cdf/util/common/Pair.java
@@ -0,0 +1,40 @@
+/*
+ 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.
+
+*/
+package org.openecomp.dcae.cdf.util.common;
+
+public final class Pair<L,R> {
+ public final L left;
+ public final R right;
+ public Pair(L l, R r) { left = l; right = r; }
+
+ @Override
+ public boolean equals(Object obj) {
+ Pair<L,R> o = (Pair<L,R>)obj;
+ return left.equals(o.left) && right.equals(o.right);
+ }
+ @Override
+ public String toString() {
+ return "(" + left + "," + right + ")";
+ }
+ @Override
+ public int hashCode() {
+ return left.hashCode() + right.hashCode();
+ }
+
+ public static <L,R> Pair<L,R> of(L l, R r) {
+ return new Pair<L,R>(l, r);
+ }
+}
diff --git a/cdf/src/cdf-prop-value/cdf-util/src/main/java/org/openecomp/dcae/cdf/util/common/Pid.java b/cdf/src/cdf-prop-value/cdf-util/src/main/java/org/openecomp/dcae/cdf/util/common/Pid.java
new file mode 100644
index 0000000..1730509
--- /dev/null
+++ b/cdf/src/cdf-prop-value/cdf-util/src/main/java/org/openecomp/dcae/cdf/util/common/Pid.java
@@ -0,0 +1,37 @@
+/*
+ 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.
+
+*/
+package org.openecomp.dcae.cdf.util.common;
+import java.io.File;
+
+public class Pid {
+ /**
+ * Return the pid.
+ */
+ public static int getPid() { return pid; }
+ public static String getPidStr() { return pidStr; }
+
+ private static int pid;
+ private static String pidStr;
+ static {
+ try {
+ pid = Integer.parseInt( ( new File("/proc/self")).getCanonicalFile().getName() );
+ pidStr = Integer.toString(pid);
+ } catch (java.io.IOException e) {
+ pid = -1;
+ pidStr = "-1";
+ }
+ }
+}
diff --git a/cdf/src/cdf-prop-value/cdf-util/src/main/java/org/openecomp/dcae/cdf/util/common/Popen.java b/cdf/src/cdf-prop-value/cdf-util/src/main/java/org/openecomp/dcae/cdf/util/common/Popen.java
new file mode 100644
index 0000000..6d5e8fb
--- /dev/null
+++ b/cdf/src/cdf-prop-value/cdf-util/src/main/java/org/openecomp/dcae/cdf/util/common/Popen.java
@@ -0,0 +1,84 @@
+/*
+ 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.
+
+*/
+package org.openecomp.dcae.cdf.util.common;
+
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.IOException;
+
+public class Popen {
+ public static class Results {
+ public final String stdout, stderr;
+ public final int exitValue;
+ public Results(String so, String se, int e) {
+ stdout = so; stderr = se; exitValue = e;
+ }
+ }
+
+ public static Results popen(String cmd) throws java.io.IOException, java.lang.InterruptedException {
+ return popen(cmd, null);
+ }
+
+ public static Results popen(String cmd, String stdin) throws java.io.IOException, java.lang.InterruptedException {
+ Process process = Runtime.getRuntime().exec(cmd);
+ return proc(process, stdin);
+ }
+
+ public static Results popen(String[] args) throws java.io.IOException, java.lang.InterruptedException {
+ return popen(args, null);
+ }
+
+ public static Results popen(String[] args, String stdin) throws java.io.IOException, java.lang.InterruptedException {
+ Process process = Runtime.getRuntime().exec(args);
+ return proc(process, stdin);
+ }
+
+ private static Results proc(Process process, String stdin) throws java.io.IOException, java.lang.InterruptedException {
+ OutputStream pinput = process.getOutputStream();
+ InputStream poutput = process.getInputStream();
+ InputStream perror = process.getErrorStream();
+
+ if (stdin != null)
+ pinput.write(stdin.getBytes());
+ pinput.close();
+
+ String stdout = captureStream(poutput);
+ poutput.close();
+ String stderr = captureStream(perror);
+ perror.close();
+ process.waitFor();
+ // System.out.println("stdin=\nnvvvvvvvvvvvvvvvv\n");
+ // System.out.println(stdin);
+ // System.out.println("^^^^^^^^^^^^^^^^");
+ // System.out.println("stdout=\nvvvvvvvvvvvvvvvv\n");
+ // System.out.println(stdout);
+ // System.out.println("^^^^^^^^^^^^^^^^");
+ // System.out.println("stderr=\nvvvvvvvvvvvvvvvv\n");
+ // System.out.println(stderr);
+ // System.out.println("^^^^^^^^^^^^^^^^");
+ return new Results(stdout, stderr, process.exitValue());
+ }
+
+ private static String captureStream(InputStream inp) throws java.io.IOException {
+ byte[] buf = new byte[8192];
+ StringBuffer out = new StringBuffer();
+ int b;
+ while ((b = inp.read(buf)) > 0) {
+ out.append(new String(buf, 0, b));
+ }
+ return out.toString();
+ }
+}
diff --git a/cdf/src/cdf-prop-value/cdf-util/src/main/java/org/openecomp/dcae/cdf/util/common/Tuple2.java b/cdf/src/cdf-prop-value/cdf-util/src/main/java/org/openecomp/dcae/cdf/util/common/Tuple2.java
new file mode 100644
index 0000000..dd48ea8
--- /dev/null
+++ b/cdf/src/cdf-prop-value/cdf-util/src/main/java/org/openecomp/dcae/cdf/util/common/Tuple2.java
@@ -0,0 +1,25 @@
+// -*- 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.
+
+*/
+package org.openecomp.dcae.cdf.util.common;
+
+public class Tuple2<T1,T2> {
+ public Tuple2(T1 n1, T2 n2) {
+ t1 = n1; t2 = n2;
+ }
+ public final T1 t1;
+ public final T2 t2;
+}
diff --git a/cdf/src/cdf-prop-value/cdf-util/src/main/java/org/openecomp/dcae/cdf/util/common/Tuple3.java b/cdf/src/cdf-prop-value/cdf-util/src/main/java/org/openecomp/dcae/cdf/util/common/Tuple3.java
new file mode 100644
index 0000000..1293059
--- /dev/null
+++ b/cdf/src/cdf-prop-value/cdf-util/src/main/java/org/openecomp/dcae/cdf/util/common/Tuple3.java
@@ -0,0 +1,29 @@
+// -*- 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.
+
+*/
+package org.openecomp.dcae.cdf.util.common;
+
+public class Tuple3<T1,T2,T3> extends Tuple2<T1,T2> {
+ public Tuple3(T1 n1, T2 n2, T3 n3) {
+ super(n1, n2);
+ t3 = n3;
+ }
+ public Tuple3(Tuple3<T1,T2,T3> t) {
+ super(t.t1, t.t2);
+ t3 = t.t3;
+ }
+ public final T3 t3;
+}
diff --git a/cdf/src/cdf-prop-value/cdf-util/src/main/java/org/openecomp/dcae/cdf/util/common/Tuple4.java b/cdf/src/cdf-prop-value/cdf-util/src/main/java/org/openecomp/dcae/cdf/util/common/Tuple4.java
new file mode 100644
index 0000000..a2c10e8
--- /dev/null
+++ b/cdf/src/cdf-prop-value/cdf-util/src/main/java/org/openecomp/dcae/cdf/util/common/Tuple4.java
@@ -0,0 +1,29 @@
+// -*- 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.
+
+*/
+package org.openecomp.dcae.cdf.util.common;
+
+public class Tuple4<T1,T2,T3,T4> extends Tuple3<T1,T2,T3> {
+ public Tuple4(T1 n1, T2 n2, T3 n3, T4 n4) {
+ super(n1, n2, n3);
+ t4 = n4;
+ }
+ public Tuple4(Tuple4<T1,T2,T3,T4> t) {
+ super(t.t1, t.t2, t.t3);
+ t4 = t.t4;
+ }
+ public final T4 t4;
+}
diff --git a/cdf/src/cdf-prop-value/cdf-util/src/main/java/org/openecomp/dcae/cdf/util/common/Uid.java b/cdf/src/cdf-prop-value/cdf-util/src/main/java/org/openecomp/dcae/cdf/util/common/Uid.java
new file mode 100644
index 0000000..6b2219f
--- /dev/null
+++ b/cdf/src/cdf-prop-value/cdf-util/src/main/java/org/openecomp/dcae/cdf/util/common/Uid.java
@@ -0,0 +1,69 @@
+/*
+ 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.
+
+*/
+package org.openecomp.dcae.cdf.util.common;
+import java.io.File;
+import java.io.BufferedReader;
+import java.io.FileReader;
+import org.openecomp.dcae.cdf.util.common.Popen;
+
+public class Uid {
+ /**
+ * Return the uid.
+ */
+ public static int getUid() { return uid; }
+ public static String getUidStr() { return uidStr; }
+
+ private static int uid = -1;
+ private static String uidStr = "";
+ static {
+ try {
+ uid = getUidFromProcSelfStatus();
+ if (uid == -1) uid = getUidFromIdU();
+ uidStr = Integer.toString(uid);
+ } catch (java.io.IOException e) {
+ uid = -1;
+ uidStr = "-1";
+ System.err.println("Exception: " + e);
+ } catch (Exception e) {
+ System.err.println("Exception: " + e);
+ }
+
+ }
+
+ private static int getUidFromProcSelfStatus() throws java.io.IOException {
+ int uid = -1;
+ if (true) return -1;
+ BufferedReader br = new BufferedReader(new FileReader(new File("/proc/self/status")));
+ String thisLine = null;
+ while ((thisLine = br.readLine()) != null) {
+ if (thisLine.startsWith("Uid:")) {
+ String[] uids = thisLine.split("[: \t]+");
+ if (uids.length > 1) {
+ uid = Integer.parseInt(uids[1]);
+ break;
+ }
+ }
+ }
+ br.close();
+ return uid;
+ }
+
+ private static int getUidFromIdU() throws java.io.IOException, java.lang.InterruptedException {
+ Popen.Results results = Popen.popen("/usr/bin/id -u");
+ uid = Integer.parseInt(results.stdout.trim());
+ return uid;
+ }
+}
diff --git a/cdf/src/cdf-prop-value/cdf-util/src/main/java/org/openecomp/dcae/cdf/util/config/.gitignore b/cdf/src/cdf-prop-value/cdf-util/src/main/java/org/openecomp/dcae/cdf/util/config/.gitignore
new file mode 100644
index 0000000..6b468b6
--- /dev/null
+++ b/cdf/src/cdf-prop-value/cdf-util/src/main/java/org/openecomp/dcae/cdf/util/config/.gitignore
@@ -0,0 +1 @@
+*.class
diff --git a/cdf/src/cdf-prop-value/cdf-util/src/main/java/org/openecomp/dcae/cdf/util/config/Configurable.java b/cdf/src/cdf-prop-value/cdf-util/src/main/java/org/openecomp/dcae/cdf/util/config/Configurable.java
new file mode 100644
index 0000000..39e78ca
--- /dev/null
+++ b/cdf/src/cdf-prop-value/cdf-util/src/main/java/org/openecomp/dcae/cdf/util/config/Configurable.java
@@ -0,0 +1,28 @@
+/*
+ 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.
+
+*/
+package org.openecomp.dcae.cdf.util.config;
+
+/**
+ * The interface for an object that wants to be notified when the
+ * configuration files have changed (so it can re-configure itself)
+ */
+
+public interface Configurable {
+ /**
+ * Configuration files have changed.
+ */
+ public void reConfigure();
+}
diff --git a/cdf/src/cdf-prop-value/cdf-util/src/main/java/org/openecomp/dcae/cdf/util/config/Configuration.java b/cdf/src/cdf-prop-value/cdf-util/src/main/java/org/openecomp/dcae/cdf/util/config/Configuration.java
new file mode 100644
index 0000000..54ebf47
--- /dev/null
+++ b/cdf/src/cdf-prop-value/cdf-util/src/main/java/org/openecomp/dcae/cdf/util/config/Configuration.java
@@ -0,0 +1,579 @@
+/*
+ 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.
+
+*/
+package org.openecomp.dcae.cdf.util.config;
+
+import java.io.*;
+import java.util.*;
+import java.net.*;
+import java.util.logging.*;
+import org.openecomp.dcae.cdf.util.common.*;
+import org.openecomp.dcae.cdf.util.threads.*;
+
+/**
+ * Class to monitor configuration parameters and notify
+ * other objects when they change
+ */
+
+public class Configuration extends Thread implements Configurable {
+ /**
+ * Time between checks of config file in milliseconds
+ */
+ private static int INTERVAL = 30000;
+ private int interval = INTERVAL;
+ /**
+ * Minimum age of config file before loading it in milliseconds
+ */
+ private static final int MINAGE = 30000;
+ private int minage = MINAGE;
+ /**
+ * Value returned by getInstance() method
+ */
+ private static Configuration defaultInstance = new Configuration();
+ /**
+ * Value returned by getLocalIP() method
+ */
+ private static String defaultLocalIP;
+ private static String defaultLocalIPinHex;
+ private static String defaultCanonicalHostName;
+ static {
+ try {
+ InetAddress ia = InetAddress.getLocalHost();
+ defaultLocalIP = ia.getHostAddress();
+ byte b[] = ia.getAddress();
+ defaultLocalIPinHex = Convert.toHexString(b);
+ defaultCanonicalHostName = ia.getCanonicalHostName();
+ } catch (Exception e) {
+ defaultLocalIP = "127.0.0.1";
+ defaultLocalIPinHex = "7F000001";
+ defaultCanonicalHostName = "localhost";
+ }
+ }
+ /**
+ * Get an IP address for this machine
+ */
+ public static String getLocalIP() {
+ return defaultLocalIP;
+ }
+ /**
+ * Get an IP address for this machine
+ */
+ public static String getLocalIPinHex() {
+ return defaultLocalIPinHex;
+ }
+ /**
+ * Get a host name for this machine
+ */
+ public static String getCanonicalHostName() {
+ return defaultCanonicalHostName;
+ }
+ /**
+ * Get a default global instance
+ */
+ public static Configuration getInstance() {
+ return defaultInstance;
+ }
+ /**
+ * The current configuration
+ */
+ private ResourceBundle config;
+ /**
+ * Where to log when things go wrong
+ */
+ private static Logger logger = Logger.getLogger(Configuration.class.getName());
+ /**
+ * The config file to read
+ */
+ private File file;
+ /**
+ * The name of the config to read, when overriding the file.
+ */
+ private String filename;
+ /**
+ * The last modified date of the config file
+ */
+ private long curdate;
+ /**
+ * Should we stop scanning for config file updates?
+ */
+ private boolean closed;
+ static boolean closeAll = false;
+ /**
+ * Have we started scanning for config file updates?
+ */
+ private boolean initialized;
+ /**
+ * The name of the background thread monitoring the file.
+ */
+ private static String monitorThreadName = "Configuration Monitor";
+ /**
+ * How we keep track of registered Configurables.
+ */
+ private ConfigurationRegistry configurationRegistry = new ConfigurationRegistry();
+ /**
+ * included file.
+ */
+ private Configuration subConfig = null;
+ private String subFile = null;
+
+ public void reConfigure() {
+ configurationRegistry.reConfigureAll(logger);
+ }
+
+ /**
+ * Create an instance using the default configuration file
+ * "configfile.properties" from the class path
+ */
+ public Configuration() {
+ // logger.fine("Configuration()");
+ }
+ /**
+ * Create an instance using a configuration file
+ * "FILENAME.properties" from the class path
+ */
+ public Configuration(String filename) {
+ // logger.fine("Configuration(" + filename + ")");
+ this.filename = filename;
+ }
+ /**
+ * Create an instance using a specific configuration file
+ */
+ public Configuration(File file) {
+ this.file = file;
+ // logger.fine("Configuration(File)");
+ }
+
+ /**
+ * Change the configuration file to use
+ */
+ public void setConfig(File file) {
+ this.file = file;
+ curdate = 0;
+ interrupt();
+ }
+ /**
+ * Reset the interval used for rechecking the file.
+ * @param interval
+ */
+ public synchronized void setInterval(int interval) {
+ this.interval = interval;
+ }
+ /**
+ * Reset the default interval used for rechecking the file.
+ * @param interval
+ */
+ public synchronized void setDefaultInterval(int interval) {
+ this.INTERVAL = interval;
+ }
+ /**
+ * Reset the minimum age the file must be before being reread.
+ * This is used to prevent reading the file while it is being written, say by vi.
+ * @param minage
+ */
+ public synchronized void setMinage(int minage) {
+ this.minage = minage;
+ }
+ /**
+ * Stop checking for config changes
+ */
+ public void close() {
+ checkinit();
+ closed = true;
+ if (Thread.currentThread() == this) {
+ return;
+ }
+ interrupt();
+ try {
+ join();
+ } catch (Exception e) {
+ }
+ }
+ /**
+ * Check the config file to see if it has changed
+ */
+ private synchronized void check() {
+ long now = System.currentTimeMillis();
+ if (logger.isLoggable(Level.FINE)) logger.fine("check(): now=" + Long.toString(now));
+ try {
+ long ndate = file.lastModified();
+ if (logger.isLoggable(Level.FINE)) logger.fine("file=" + file + ", ndate=" + Long.toString(ndate) + ", curdate=" + Long.toString(curdate,10));
+ if (ndate == curdate || (now < ndate + minage && curdate != 0)) {
+ return;
+ }
+ if (logger.isLoggable(Level.FINE)) logger.fine("reloading file=" + file);
+ FileInputStream in = new FileInputStream(file);
+ config = new PropertyResourceBundle(in);
+ in.close();
+ try {
+ String inc = config.getString("include");
+ if ((inc != null) && !inc.equals("")) {
+ subFile = inc;
+ subConfig = new Configuration(subFile);
+ subConfig.registerConfigurable(this);
+ }
+ } catch (Exception e) {
+ }
+
+ curdate = ndate;
+ configurationRegistry.reConfigureAll(logger);
+ // logger.info("CNFG0006: Configuration '" + file + "' reloaded");
+ } catch (Exception e) {
+ logger.log(Level.SEVERE, "DAIS0048 Unrecoverable configuration error CNFG0004: Configuration file '" + file + "' inaccessible", e);
+ }
+ }
+ /**
+ * Make sure we're initialized and read the config file
+ * if necessary
+ */
+ public void checkinit() {
+ // System.out.println("checkinit()");
+ if (initialized) {
+ return;
+ }
+ initialized = true;
+ try {
+ if (file == null) {
+ if (filename == null)
+ filename = System.getProperty("configfile", "configfile");
+ // logger.info("DAIS0073 0.8.73 >>> filename=" + filename);
+ if (filename.charAt(0) == '/') {
+ // logger.info("DAIS0073 0.8.73 filename has leading slash: " + filename);
+ file = new File(filename);
+ } else {
+ URI uri = getClass().getClassLoader().getResource(filename + ".properties").toURI();
+ // logger.info("DAIS0073 0.8.73 uri=" + uri.toString());
+ file = new File(uri);
+ }
+ }
+ } catch (Exception e) {
+ logger.log(Level.SEVERE, "DAIS0048 Unrecoverable configuration error CNFG0003: Cannot find configuration file '" + filename + "'", e);
+ }
+ check();
+ setDaemon(true);
+ setName(monitorThreadName);
+ start();
+ }
+ /**
+ * Check the config file to see if it has changed
+ */
+ public void run() {
+ if (logger.isLoggable(Level.FINE)) logger.fine("Configuration::run()");
+ while (!closed && !closeAll) {
+ try {
+ if (logger.isLoggable(Level.FINE)) logger.fine("sleeping " + Integer.toString(interval) + ", id=" + Long.toString(Thread.currentThread().getId()) + ", file=" + filename);
+ Thread.sleep(interval);
+ } catch (Exception e) {
+ }
+ if (logger.isLoggable(Level.FINE)) {
+ Thread currentThread = Thread.currentThread();
+ logger.fine("checking id=" + Long.toString((currentThread != null) ? currentThread.getId() : -1) + ", file=" + filename);
+ }
+ check();
+ }
+ }
+
+ public static void wakeAllThreads() {
+ try {
+ Thread[] threads = ThreadCommon.getAllThreads( monitorThreadName );
+ for ( Thread thread : threads )
+ thread.interrupt();
+ } catch (Exception e) {
+ }
+ }
+
+ public static void closeAllThreads() {
+ closeAll = true;
+ wakeAllThreads();
+ }
+
+ /**
+ * Forward this Configurable to the ConfigurationRegistry to be registered.
+ */
+ public void registerConfigurable(Configurable element) {
+ configurationRegistry.registerConfigurable(element);
+ }
+ /**
+ * Forward this Configurable to the ConfigurationRegistry to be deRegistered.
+ */
+ public void deRegisterConfigurable(Configurable element) {
+ configurationRegistry.deRegisterConfigurable(element);
+ }
+
+ /**
+ * Get a configuration parameter as a String.
+ * If undefined, return null and log an error.
+ * @return String
+ */
+ public String getString(String name) {
+ return getString(name, null, true);
+ }
+ /**
+ * Get a configuration parameter as a String.
+ * If undefined, return the specified default value.
+ * @return String
+ */
+ public String getString(String name, String deflt) {
+ return getString(name, deflt, false);
+ }
+
+ public static String trimQuotes(String str) {
+ if (str == null) return null;
+ str = str.trim();
+ int len = str.length();
+ if (len < 2) return str;
+ char startChar = str.charAt(0);
+ char endChar = str.charAt(len-1);
+ boolean startDoubleQuote = startChar == '"';
+ boolean startSingleQuote = startChar == '\'';
+ boolean endDoubleQuote = endChar == '"';
+ boolean endSingleQuote = endChar == '\'';
+ if ((startDoubleQuote && endDoubleQuote) ||
+ (startSingleQuote && endSingleQuote)) {
+ return str.substring(1, len-1);
+ } else {
+ return str;
+ }
+ }
+
+ /**
+ * Get a configuration parameter as a String.
+ * If undefined, return the specified default value.
+ * If complaining, log an error.
+ * @return String
+ */
+ public String getString(String name, String deflt, boolean complain) {
+ checkinit();
+ try {
+ return trimQuotes(config.getString(name));
+ } catch (Exception e) {
+ if (subConfig != null) {
+ try {
+ return subConfig.getString(name, deflt, complain);
+ } catch (Exception e2) {
+ }
+ }
+ if (complain)
+ logger.log(Level.SEVERE, "DAIS0048 Unrecoverable configuration error CNFG0001: '" + filename + "': Configuration property " + name + " must be defined", e);
+ return deflt;
+ }
+ }
+
+ /**
+ * Get a configuration parameter as a String encoded using URL % escapes.
+ * If undefined, return null and log an error.
+ * @return String
+ */
+ public String getDecodedString(String name) {
+ return getDecodedString(name, null, true);
+ }
+ /**
+ * Get a configuration parameter as a String encoded using URL % escapes.
+ * If undefined, return the specified default value.
+ * @return String
+ */
+ public String getDecodedString(String name, String deflt) {
+ return getDecodedString(name, deflt, false);
+ }
+ /**
+ * Get a configuration parameter as a String encoded using URL % escapes.
+ * If undefined, return the specified default value.
+ * If complaining, log an error.
+ * @return String
+ */
+ public String getDecodedString(String name, String deflt, boolean complain) {
+ checkinit();
+ try {
+ return URLDecoder.decode(config.getString(name), "UTF-8");
+ } catch (UnsupportedEncodingException e) {
+ logger.log(Level.SEVERE, "DAIS0048 Unrecoverable configuration error CNFG0007: UTF-8 is not recognized as a character set encoding", e);
+ return deflt;
+ } catch (Exception e) {
+ if (complain)
+ logger.log(Level.SEVERE, "DAIS0048 Unrecoverable configuration error CNFG0001: '" + filename + "': Configuration property " + name + " must be defined", e);
+ return deflt;
+ }
+ }
+
+ /**
+ * Get a configuration parameter as a String[].
+ * If undefined, return null and log an error.
+ * @return String[]
+ */
+ public String[] getStrings(String name) {
+ return getStrings(name, null, "[ \t,]+", true);
+ }
+ /**
+ * Get a configuration parameter as a String[].
+ * If undefined, return the specified default.
+ * @return String[]
+ */
+ public String[] getStrings(String name, String[] deflt) {
+ return getStrings(name, deflt, "[ \t,]+", false);
+ }
+ /**
+ * Get a configuration parameter as a String[].
+ * If undefined, return the specified default
+ * @return String[]
+ */
+ public String[] getStrings(String name, String[] deflt, String pattern, boolean complain) {
+ name = getString(name, null, complain);
+ if (name == null) {
+ return deflt;
+ }
+ return name.trim().split(pattern);
+ }
+
+ /**
+ * Get a configuration parameter as a String[], each String encoded using URL % escapes.
+ * If undefined, return null and log an error.
+ * @return String[]
+ */
+ public String[] getDecodedStrings(String name) {
+ return getDecodedStrings(name, null, "[ \t,]+", true);
+ }
+ /**
+ * Get a configuration parameter as a String[], each String encoded using URL % escapes.
+ * If undefined, return the specified default.
+ * @return String[]
+ */
+ public String[] getDecodedStrings(String name, String[] deflt) {
+ return getDecodedStrings(name, deflt, "[ \t,]+", false);
+ }
+ /**
+ * Get a configuration parameter as a String[], each String encoded using URL % escapes.
+ * If undefined, return the specified default.
+ * @return String[]
+ */
+ public String[] getDecodedStrings(String name, String[] deflt, String pattern) {
+ return getDecodedStrings(name, deflt, pattern, false);
+ }
+ /**
+ * Get a configuration parameter as a String[], each String encoded using URL % escapes.
+ * If undefined, return the specified default.
+ * @return String[]
+ */
+ public String[] getDecodedStrings(String name, String[] deflt, String pattern, boolean complain) {
+ name = getString(name, null, complain);
+ if (name == null) {
+ return deflt;
+ }
+ String[] strs = (name.trim().split(pattern));
+ try {
+ for (int i = 0; i < strs.length; i++) {
+ strs[i] = URLDecoder.decode(strs[i], "UTF-8");
+ }
+ } catch (UnsupportedEncodingException e) {
+ logger.log(Level.SEVERE, "DAIS0048 Unrecoverable configuration error CNFG0007: UTF-8 is not recognized as a character set encoding", e);
+ }
+ return strs;
+ }
+
+ /**
+ * Get a configuration parameter as a long. If undefined or non-numeric, return -1 and log an error.
+ */
+ public long getLong(String name) {
+ return getLong(name, -1L);
+ }
+ /**
+ * Get a configuration parameter as a long. If undefined, return the specified default
+ * If non-numeric, return the specified default and log an error.
+ */
+ public long getLong(String name, long deflt) {
+ String value = getString(name, null);
+ if (value == null) {
+ return deflt;
+ }
+ try {
+ return Long.parseLong(value.trim());
+ } catch (Exception e) {
+ logger.log(Level.SEVERE, "DAIS0048 Unrecoverable configuration error CNFG0002: '" + filename + "': Configuration property " + name + " must be numeric", e);
+ return deflt;
+ }
+ }
+
+ /**
+ * Get a configuration parameter as an int. If undefined or non-numeric, return -1 and log an error.
+ */
+ public int getInt(String name) {
+ return getInt(name, -1);
+ }
+ /**
+ * Get a configuration parameter as an int. If undefined, return the specified default
+ * If non-numeric, return the specified default and log an error.
+ */
+ public int getInt(String name, int deflt) {
+ String value = getString(name, null);
+ if (value == null) {
+ return deflt;
+ }
+ try {
+ return Integer.parseInt(value.trim());
+ } catch (Exception e) {
+ logger.log(Level.SEVERE, "DAIS0048 Unrecoverable configuration error CNFG0002: '" + filename + "': Configuration property " + name + " must be numeric", e);
+ return deflt;
+ }
+ }
+
+ /**
+ * Get a configuration parameter as an boolean. If undefined or non-numeric, return false and log an error.
+ */
+ public boolean getBoolean(String name) {
+ return getBoolean(name, false);
+ }
+ /**
+ * Get a configuration parameter as an boolean. If undefined, return the specified default
+ * If non-numeric, return the specified default and log an error.
+ */
+ public boolean getBoolean(String name, boolean deflt) {
+ String value = getString(name, null);
+ if (value == null) {
+ return deflt;
+ }
+ try {
+ return Boolean.parseBoolean(value.trim());
+ } catch (Exception e) {
+ logger.log(Level.SEVERE, "DAIS0048 Unrecoverable configuration error CNFG0002: '" + filename + "': Configuration property " + name + " must be true/false", e);
+ return deflt;
+ }
+ }
+
+ /**
+ * Get a configuration parameter as a double. If undefined or non-numeric, return -1 and log an error.
+ */
+ public double getDouble(String name) {
+ return getDouble(name, -1);
+ }
+ /**
+ * Get a configuration parameter as a double. If undefined, return the specified default
+ * If non-numeric, return the specified default and log an error.
+ */
+ public double getDouble(String name, double deflt) {
+ String value = getString(name, null);
+ if (value == null) {
+ return deflt;
+ }
+ try {
+ return Double.parseDouble(value);
+ } catch (Exception e) {
+ logger.log(Level.SEVERE, "DAIS0048 Unrecoverable configuration error CNFG0002: '" + filename + "': Configuration property " + name + " must be numeric", e);
+ return deflt;
+ }
+ }
+
+ public Enumeration getKeys() {
+ checkinit();
+ return (config != null) ? config.getKeys() : null;
+ }
+}
diff --git a/cdf/src/cdf-prop-value/cdf-util/src/main/java/org/openecomp/dcae/cdf/util/config/ConfigurationRegistry.java b/cdf/src/cdf-prop-value/cdf-util/src/main/java/org/openecomp/dcae/cdf/util/config/ConfigurationRegistry.java
new file mode 100644
index 0000000..a8241f8
--- /dev/null
+++ b/cdf/src/cdf-prop-value/cdf-util/src/main/java/org/openecomp/dcae/cdf/util/config/ConfigurationRegistry.java
@@ -0,0 +1,106 @@
+/*
+ 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.
+
+*/
+package org.openecomp.dcae.cdf.util.config;
+
+import java.util.logging.*;
+import java.lang.ref.*;
+
+/**
+ * Class to register and notify other objects when needed.
+ * Those other objects must implement Configurable.
+ */
+
+public class ConfigurationRegistry {
+ public ConfigurationRegistry() { }
+
+ /**
+ * The set of registered configurables
+ */
+ private WeakReference<Configurable>[] configurables = new WeakReference[0];
+
+ /**
+ * Request callback whenever the configuration data changes
+ */
+ public synchronized void registerConfigurable(Configurable element) {
+ // System.out.println("adding " + element.getClass().getName() + ", length=" + Integer.toString(configurables.length));
+ for (int i = 0; i < configurables.length; i++) {
+ if (configurables[i].get() == element) {
+ return;
+ }
+ }
+ WeakReference<Configurable>[] nconfigurables = new WeakReference[configurables.length + 1];
+ System.arraycopy(configurables, 0, nconfigurables, 0, configurables.length);
+ nconfigurables[configurables.length] = new WeakReference<Configurable>(element);
+ configurables = nconfigurables;
+ element.reConfigure();
+ }
+
+ /**
+ * Cancel request for callbacks when configuration changes
+ */
+ public synchronized void deRegisterConfigurable(Configurable element) {
+ // System.out.println("removing " + element.getClass().getName() + ", length=" + Integer.toString(configurables.length));
+ for (int i = 0; i < configurables.length; i++) {
+ if (configurables[i].get() == element) {
+ WeakReference<Configurable>[] nconfigurables = new WeakReference[configurables.length - 1];
+ if (i > 0) {
+ System.arraycopy(configurables, 0, nconfigurables, 0, i);
+ }
+ if (i < nconfigurables.length) {
+ System.arraycopy(configurables, i + 1, nconfigurables, i, nconfigurables.length - i);
+ }
+ configurables = nconfigurables;
+ return;
+ }
+ }
+ }
+
+ /**
+ * Notify all of the Configurables that they need to reConfigure.
+ */
+ public void reConfigureAll() {
+ reConfigureAll(Logger.getLogger(ConfigurationRegistry.class.getName()));
+ }
+
+ /**
+ * Notify all of the Configurables that they need to reConfigure.
+ */
+ public void reConfigureAll(Logger logger) {
+ // System.out.println("reConfigureAll(), length=" + Integer.toString(configurables.length));
+ for (int i = 0; i < configurables.length; i++) {
+ try {
+ // System.out.println("reConfigureAll(), i=" + Integer.toString(i));
+ WeakReference<Configurable> wc = configurables[i];
+ Configurable c = (wc != null) ? wc.get() : null;
+ if (c != null)
+ c.reConfigure();
+ } catch (Exception e) {
+ WeakReference<Configurable> wc = configurables[i];
+ Configurable c = (wc != null) ? wc.get() : null;
+ logger.log(Level.SEVERE, "DAIS0048 Unrecoverable configuration error CNFG0005: Problem while invoking reConfigure for: " +
+ ((wc == null) ? "null" : (c == null) ? "null/null" : c.getClass().getName()) + ": " +
+ e.getMessage(), e);
+ }
+ }
+ }
+
+ /**
+ * Return the number of configurables that are registered.
+ */
+ public int getCount() {
+ return configurables.length;
+ }
+}
diff --git a/cdf/src/cdf-prop-value/cdf-util/src/main/java/org/openecomp/dcae/cdf/util/config/EncryptedConfiguration.java b/cdf/src/cdf-prop-value/cdf-util/src/main/java/org/openecomp/dcae/cdf/util/config/EncryptedConfiguration.java
new file mode 100644
index 0000000..9c546dc
--- /dev/null
+++ b/cdf/src/cdf-prop-value/cdf-util/src/main/java/org/openecomp/dcae/cdf/util/config/EncryptedConfiguration.java
@@ -0,0 +1,219 @@
+/*
+ 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.
+
+*/
+package org.openecomp.dcae.cdf.util.config;
+
+import java.util.logging.*;
+// import java.lang.ref.*;
+import org.openecomp.dcae.cdf.util.common.*;
+import gnu.getopt.Getopt;
+import java.security.*;
+import javax.crypto.*;
+import javax.crypto.spec.SecretKeySpec;
+
+/**
+ * Class to manage encrypted configuration values.
+ */
+
+public class EncryptedConfiguration {
+ /**
+ * Our secret key
+ */
+ private String encryptionKey;
+
+ /**
+ * Where to log when things go wrong
+ */
+ private Logger logger;
+
+ public EncryptedConfiguration(String key, Logger logger) {
+ encryptionKey = key.trim();
+ this.logger = logger;
+ }
+
+ /**
+ * Retrieve an encrypted string from the given configuration.
+ * The name will have ".x" appended to it.
+ * Decoded from hex, it will be "method:hexsalt:hexvalue".
+ * The format of the value will be in hex.
+ * Method will be "r" to begin with, for "rc4".
+ */
+ public String getString(Configuration config, String name, String deflt, boolean complain) throws Exception {
+ return getString(config, name, deflt, complain, encryptionKey);
+ }
+
+ /**
+ * Retrieve an encrypted string from the given configuration.
+ * The name will have ".x" appended to it.
+ * Decoded from hex, it will be "method:hexsalt:hexvalue".
+ * The format of the value will be in hex.
+ * Method will be "r" to begin with, for "rc4".
+ */
+ public String getString(Configuration config, String name, String deflt, boolean complain, String key) throws Exception {
+ String str = config.getString(name + ".x", null, complain);
+ if (str == null) {
+ return deflt;
+ }
+ return decrypt(str, key);
+ }
+
+ /**
+ * Decrypt a string in 'method:hexsalt:hexvalue' format.
+ */
+ public static String decrypt(String triple, String key) throws Exception {
+ String[] strParts = triple.trim().split(":");
+ if (strParts.length != 3) throw new Exception("Encrypted value must look like 'x:y:z'");
+ return decrypt(strParts[0], Convert.stringFromHex(strParts[1]), key, Convert.bytesFromHex(strParts[2]));
+ }
+
+ /**
+ * Decrypt a string 'method:hexsalt:hexvalue' format.
+ */
+ public static String decrypt(String method, String salt, String key, byte[] bvalue) throws Exception {
+ /* if (false) {
+ System.out.println("method length=" + method.length()); System.out.println(AsHex.asHex(method));
+ System.out.println("salt length=" + salt.length()); System.out.println(AsHex.asHex(salt));
+ System.out.println("key length=" + key.length()); System.out.println(AsHex.asHex(key));
+ System.out.println("bvalue length=" + bvalue.length); System.out.println(AsHex.asHex(bvalue));
+ } */
+ byte[] secretKey = runDigest(salt + "." + key);
+
+ SecretKeySpec skeySpec = new SecretKeySpec(secretKey, method);
+
+ Cipher cipher = Cipher.getInstance(method); // "AES"
+ cipher.init(Cipher.DECRYPT_MODE, skeySpec);
+
+ byte[] decrypted = cipher.doFinal(bvalue);
+ return new String(decrypted);
+ }
+
+ /**
+ * Encrypt a string using the given method, salt and key.
+ */
+ public static byte[] encrypt(String method, String salt, String key, String value) throws Exception {
+ byte[] bvalue = value.getBytes();
+ byte[] secretKey = runDigest(salt + "." + key);
+
+ SecretKeySpec skeySpec = new SecretKeySpec(secretKey, method);
+
+ Cipher cipher = Cipher.getInstance(method); // "AES"
+ cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
+
+ byte[] encrypted = cipher.doFinal(bvalue);
+ return encrypted;
+ }
+
+ /**
+ * Prepare a secret key by running a digest on it.
+ */
+ private static byte[] runDigest(String text) throws Exception {
+ MessageDigest md = MessageDigest.getInstance("MD5");
+ md.reset();
+ md.update(text.getBytes(), 0, text.length());
+ return md.digest();
+ }
+
+ /**
+ * Encrypt a string using the given method, salt and key, and return it as a hex-formated triple.
+ */
+ public static String encryptToTriple(String method, String salt, String key, String value) throws Exception {
+ StringBuilder sb = new StringBuilder(method);
+ sb.append(':').append(Convert.toHexString(salt))
+ .append(':').append(Convert.toHexString(encrypt(method, salt, key, value)));
+ return sb.toString();
+ }
+
+ /**
+ * Create a value that can be used as a salt.
+ */
+ public static String generateSalt() {
+ return Long.toString(System.currentTimeMillis() % 1000) + Pid.getPidStr();
+ }
+
+ public static void usage() {
+ usage(null);
+ }
+
+ public static void usage(String msg) {
+ if (msg != null) System.out.println(msg);
+ System.out.println("Usage: java EncryptedConfiguration -D triple -k key\n" +
+ "java EncryptedConfiguration -d string -m method [-s salt | -S] -k key\n" +
+ "java EncryptedConfiguration -e string -m method [-s salt | -S] -k key\n" +
+ "-D\tdecrypt x:y:z triple\n" +
+ "-d\tdecrypt string (in hex)\n" +
+ "-e\tencrypt string\n" +
+ "-S\tgenerate a salt\n"
+ );
+ System.exit(1);
+ }
+
+ public static void main(String args[]) throws Exception {
+ Getopt g = new Getopt( "EncryptedConfiguration", args, "s:Sk:m:e:d:D:?" );
+
+ int c, verbosity = 0;
+ String salt = null, key = null, method = null, encStr = null, decStr = null, triple = null;
+ boolean genSalt = false;
+
+ while ((c = g.getopt()) != -1) {
+ switch (c) {
+ case 's': salt = g.getOptarg(); break;
+ case 'S': genSalt = true; break;
+ case 'k': key = g.getOptarg(); break;
+ case 'm': method = g.getOptarg(); break;
+ case 'e': encStr = g.getOptarg(); break;
+ case 'd': decStr = g.getOptarg(); break;
+ case 'D': triple = g.getOptarg(); break;
+ case '?': usage(); break;
+ }
+ }
+
+ if (triple == null) {
+ if ((salt == null) && !genSalt) usage("one of -s or -S must be specified");
+ if ((salt != null) && genSalt) usage("only one of -s or -S must be specified");
+ if (key == null) usage("-k must be specified");
+ if (method == null) usage("-m must be specified");
+ if ((encStr == null) && (decStr == null)) usage("one of -d or -e must be specified");
+ if ((encStr != null) && (decStr != null)) usage("only one of -d or -e may be specified");
+ if (genSalt) salt = generateSalt();
+ if (encStr != null)
+ System.out.println(encryptToTriple(method, salt, key, encStr));
+ if (decStr != null)
+ System.out.println(decrypt(method, salt, key, Convert.bytesFromHex(decStr)));
+ } else {
+ if (key == null) usage("-k not specified");
+ System.out.println(decrypt(triple, key));
+ }
+
+ // http://forums.sun.com/thread.jspa?threadID=5290983
+ // try {
+ // String message = "Strong Versus Unlimited Strength Cryptography";
+ // SecretKeySpec skeySpec = new SecretKeySpec("0123456789ABCDEF".getBytes(), "AES"); //AES-128
+
+ // Cipher cipher = Cipher.getInstance("AES"); // "AES/ECB/NoPadding"
+ // cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
+
+ // byte[] encrypted = cipher.doFinal(message.getBytes());
+ // System.out.println("encrypted string: " + encrypted); //storing into MySQL DB
+ // System.out.println("in hex: '" + Convert.toHexString(encrypted) + "'");
+
+ // cipher.init(Cipher.DECRYPT_MODE, skeySpec);
+ // byte[] original = cipher.doFinal(encrypted);
+ // String originalString = new String(original);
+ // System.out.println("Original string: " + originalString);
+ // } catch (Exception e) {
+ // System.err.println("Exception caught: " + e.toString());
+ // }
+ }
+}
diff --git a/cdf/src/cdf-prop-value/cdf-util/src/main/java/org/openecomp/dcae/cdf/util/config/PropValue.java b/cdf/src/cdf-prop-value/cdf-util/src/main/java/org/openecomp/dcae/cdf/util/config/PropValue.java
new file mode 100644
index 0000000..07bbe06
--- /dev/null
+++ b/cdf/src/cdf-prop-value/cdf-util/src/main/java/org/openecomp/dcae/cdf/util/config/PropValue.java
@@ -0,0 +1,245 @@
+/*
+ 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.
+
+*/
+package org.openecomp.dcae.cdf.util.config;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.BufferedReader;
+import java.io.PrintStream;
+import java.io.IOException;
+import java.util.logging.Logger;
+import org.openecomp.dcae.cdf.util.config.Configuration;
+import org.openecomp.dcae.cdf.util.config.EncryptedConfiguration;
+import gnu.getopt.Getopt;
+
+public class PropValue {
+ private EncryptedConfiguration encryptedConfiguration;
+ private String encryptionKey;
+
+ public PropValue(Configuration globalConfig, Logger logger) {
+ encryptionKey = globalConfig.getString(getEncryptionKeyProperty());
+ encryptedConfiguration = new EncryptedConfiguration(encryptionKey, logger);
+ }
+
+ public String getEncryptedString(Configuration config, String name, String deflt, boolean complain) throws Exception {
+ return encryptedConfiguration.getString(config, name, deflt, complain);
+ }
+
+ public String generateEncryptedProperty(String method, String salt, String value) throws Exception {
+ return generateEncryptedProperty(method, salt, value, this);
+ }
+
+ public String decryptTriple(String triple) {
+ return decryptTriple(triple, this);
+ }
+
+ public static void printEncryptedProperty(String method, String name, String salt, String value, String globalPropFile) {
+ try {
+ if (name != null) System.out.print(name + ".x=");
+ if (globalPropFile == null) globalPropFile = getGlobalPropFile();
+ if (globalPropFile == null) throw new NullPointerException("globalPropFile not set");
+ System.out.println(generateEncryptedProperty(method, salt, value, globalPropFile));
+ } catch (Exception e) {
+ System.err.println("Cannot encrypt '" + value + "', method '" + method + "' for property '" + name + "': "+ e.toString());
+ }
+ }
+
+ public static String generateEncryptedProperty(String method, String salt, String value, String globalPropFile) throws Exception {
+ Logger logger = Logger.getLogger(Logger.GLOBAL_LOGGER_NAME);
+ if (globalPropFile == null) globalPropFile = getGlobalPropFile();
+ if (globalPropFile == null) throw new NullPointerException("globalPropFile not set");
+ PropValue propValue = new PropValue(new Configuration(globalPropFile), logger);
+ return generateEncryptedProperty(method, salt, value, propValue);
+ }
+
+ public static String generateEncryptedProperty(String method, String salt, String value, PropValue propValue) throws Exception {
+ if (salt == null) salt = EncryptedConfiguration.generateSalt();
+ return EncryptedConfiguration.encryptToTriple(method, salt, propValue.encryptionKey, value);
+ }
+
+ public static void extractProperty(String f, String name, boolean encrypted) {
+ extractProperty(f, name, encrypted, null);
+ }
+
+ public static void extractProperty(String f, String name, boolean encrypted, String globalPropFile) {
+ Configuration config = new Configuration(f);
+ Logger logger = Logger.getLogger(Logger.GLOBAL_LOGGER_NAME);
+ if (globalPropFile == null) globalPropFile = getGlobalPropFile();
+ if (globalPropFile == null) throw new NullPointerException("globalPropFile not set");
+ PropValue propValue = new PropValue(new Configuration(globalPropFile), logger);
+ String val = "";
+ try {
+ if (encrypted)
+ val = propValue.getEncryptedString(config, name, "", true);
+ else
+ val = config.getString(name);
+ System.out.println(val);
+ } catch (Exception e) {
+ System.err.println("Cannot extract '" + name + "' from '" + config + "': " + e.toString());
+ }
+ }
+
+ public static void usage() {
+ usage(null);
+ }
+
+ // public static String decryptTriple(String triple) {
+ // return decryptTriple(triple, null);
+ // }
+
+ public static String decryptTriple(String triple, String globalPropFile) {
+ Logger logger = Logger.getLogger(Logger.GLOBAL_LOGGER_NAME);
+ if (globalPropFile == null) globalPropFile = getGlobalPropFile();
+ if (globalPropFile == null) throw new NullPointerException("globalPropFile not set");
+ PropValue propValue = new PropValue(new Configuration(globalPropFile), logger);
+ return decryptTriple(triple, propValue);
+ }
+
+ public static String decryptTriple(String triple, PropValue propValue) {
+ String ret = null;
+ try {
+ ret = EncryptedConfiguration.decrypt(triple, propValue.encryptionKey);
+ } catch (Exception e) {
+ System.err.println("Cannot decrypt '" + triple + "': " + e.toString());
+ }
+ return ret;
+ }
+
+ public static void encryptInput(InputStream in, PrintStream out) throws Exception {
+ encryptInput(null, in, out);
+ }
+ public static void encryptInput() throws Exception {
+ encryptInput(null, System.in, System.out);
+ }
+
+ private static void printEncryptedValue(Matcher m, PropValue propValue, PrintStream sysout) {
+ String method = m.group(1);
+ String name = m.group(2);
+ String value = m.group(3);
+ try {
+ sysout.println(name + ".x=" +
+ EncryptedConfiguration.encryptToTriple(method,
+ EncryptedConfiguration.generateSalt(),
+ propValue.encryptionKey, value));
+ } catch (Exception e) {
+ System.err.println("Error: Cannot encrypt '" + value + "', method '" + method + "' for property '" + name + "': " + e.toString());
+ }
+ }
+
+ public static void encryptInput(String globalPropFile, InputStream sysin, PrintStream sysout) throws Exception {
+ String s;
+
+ Pattern pDquote = Pattern.compile("^ENCRYPTME[.]([A-Z]*)[.]([^= \t]*)[ \t]*=[ \t]*\"([^\"]*)\"[ \t]*$");
+ Pattern pSquote = Pattern.compile("^ENCRYPTME[.]([A-Z]*)[.]([^= \t]*)[ \t]*=[ \t]*'([^']*)'[ \t]*$");
+ Pattern pNoWhite = Pattern.compile("^ENCRYPTME[.]([A-Z]*)[.]([^= \t]*)[ \t]*=[ \t]*([^ \t'\"]+)[ \t]*$");
+// Pattern pEncryptMe = Pattern.compile("^ENCRYPTME[.]([A-Z]*)[.]([^= \t]*)[ \t]*=");
+
+ Logger logger = Logger.getLogger(Logger.GLOBAL_LOGGER_NAME);
+ if (globalPropFile == null) globalPropFile = getGlobalPropFile();
+ if (globalPropFile == null) throw new NullPointerException("globalPropFile not set");
+ PropValue propValue = new PropValue(new Configuration(globalPropFile), logger);
+
+ BufferedReader in = new BufferedReader(new InputStreamReader(sysin));
+
+ try {
+ while ((s = in.readLine()) != null) {
+ // System.out.println("looking at '" + s + "'");
+ Matcher mDquote = pDquote.matcher(s);
+ Matcher mSquote = pSquote.matcher(s);
+ Matcher mNoWhite = pNoWhite.matcher(s);
+// Matcher mEncryptMe = pNoWhite.matcher(s);
+ if (mDquote.matches()) {
+ printEncryptedValue(mDquote, propValue, sysout);
+ } else if (mSquote.matches()) {
+ printEncryptedValue(mSquote, propValue, sysout);
+ } else if (mNoWhite.matches()) {
+ printEncryptedValue(mNoWhite, propValue, sysout);
+ } else if (s.startsWith("ENCRYPTME")) {
+ throw new Exception("Bad value to encrypt: '" + s + "'");
+ } else {
+ // System.out.println("printing the line: '" + s + "'");
+ sysout.println(s);
+ }
+ }
+ } catch (IOException e) {
+ System.err.println("Error: Cannot read from stdin: " + e.toString());
+ } catch (Exception e) {
+ throw e;
+ }
+ }
+
+ public static void usage(String msg) {
+ if (msg != null) System.err.println(msg);
+ System.err.println("Usage: java PropValue [-x] -n property -f property-file");
+ System.err.println("\tExtract the named value from the given property-file (or full pathname)");
+ System.err.println("Usage: java PropValue -e method [-n property] [-s salt] -v value");
+ System.err.println("\tEncrypt the given property with the given name and value");
+ System.err.println("Usage: java PropValue -E");
+ System.err.println("\tEncrypt all lines that look like ENCRYPTME.METHOD.name=value");
+ System.err.println("Usage: java PropValue -u value");
+ System.err.println("\tDecrypt the given value, expressed as a triple METHOD:HEXSALT:HEXVAL");
+ System.exit(1);
+ }
+
+ public static void setGlobalPropFile(String g) { sGlobalPropFile = g; }
+ public static String getGlobalPropFile() { return sGlobalPropFile; }
+ private static String sGlobalPropFile = null;
+
+ public static void setEncryptionKeyProperty(String e) { encryptionKeyProperty = e; }
+ public static String getEncryptionKeyProperty() { return encryptionKeyProperty; }
+ private static String encryptionKeyProperty = "Global_Title";
+
+ public static void main(String args[]) throws Exception {
+ Getopt g = new Getopt( "PropValue", args, "e:Ef:G:n:s:u:v:x" );
+ String propfile = null, name = null, method = null, value = null, unencrypt = null;
+ String globalPropFile = getGlobalPropFile();
+ boolean useDecryption = false, encryptStdin = false;
+ String salt = null;
+ int c;
+
+ while ((c = g.getopt()) != -1) {
+ switch (c) {
+ case 'e': method = g.getOptarg(); break;
+ case 'E': encryptStdin = true; break;
+ case 'f': propfile = g.getOptarg(); break;
+ case 'G': globalPropFile = g.getOptarg(); break;
+ case 'n': name = g.getOptarg(); break;
+ case 's': salt = g.getOptarg(); break;
+ case 'u': unencrypt = g.getOptarg(); break;
+ case 'v': value = g.getOptarg(); break;
+ case 'x': useDecryption = true; break;
+ case '?': usage(); break;
+ }
+ }
+ if (encryptStdin) {
+ if (name != null || propfile != null || method != null || value != null) usage("cannot use -E with other options");
+ encryptInput(System.in, System.out);
+ } else if (unencrypt == null) {
+ if (method != null) {
+ if (value == null) usage("-v required");
+ printEncryptedProperty(method, name, salt, value, globalPropFile);
+ } else {
+ if (name == null) usage("-n is required");
+ if (propfile == null) usage("-f is required");
+ extractProperty(propfile, name, useDecryption, globalPropFile);
+ }
+ } else {
+ System.out.println(decryptTriple(unencrypt, globalPropFile));
+ }
+ }
+}
diff --git a/cdf/src/cdf-prop-value/cdf-util/src/main/java/org/openecomp/dcae/cdf/util/threads/.gitignore b/cdf/src/cdf-prop-value/cdf-util/src/main/java/org/openecomp/dcae/cdf/util/threads/.gitignore
new file mode 100644
index 0000000..6b468b6
--- /dev/null
+++ b/cdf/src/cdf-prop-value/cdf-util/src/main/java/org/openecomp/dcae/cdf/util/threads/.gitignore
@@ -0,0 +1 @@
+*.class
diff --git a/cdf/src/cdf-prop-value/cdf-util/src/main/java/org/openecomp/dcae/cdf/util/threads/TaskThread.java b/cdf/src/cdf-prop-value/cdf-util/src/main/java/org/openecomp/dcae/cdf/util/threads/TaskThread.java
new file mode 100644
index 0000000..2fee87a
--- /dev/null
+++ b/cdf/src/cdf-prop-value/cdf-util/src/main/java/org/openecomp/dcae/cdf/util/threads/TaskThread.java
@@ -0,0 +1,164 @@
+/*
+ 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.
+
+*/
+package org.openecomp.dcae.cdf.util.threads;
+
+/**
+ * A thread with a queue of runnable tasks to execute in the
+ * thread
+ */
+public class TaskThread extends Thread {
+ /**
+ * Allocates a new TaskThread object.
+ */
+ public TaskThread() {
+ }
+ /**
+ * Allocates a new TaskThread object.
+ */
+ public TaskThread(Runnable target) {
+ super(target);
+ }
+ /**
+ * Allocates a new TaskThread object.
+ */
+ public TaskThread(ThreadGroup group, Runnable target) {
+ super(group, target);
+ }
+ /**
+ * Allocates a new TaskThread object.
+ */
+ public TaskThread(String name) {
+ super(name);
+ }
+ /**
+ * Allocates a new TaskThread object.
+ */
+ public TaskThread(ThreadGroup group, String name) {
+ super(group, name);
+ }
+ /**
+ * Allocates a new TaskThread object.
+ */
+ public TaskThread(Runnable target, String name) {
+ super(target, name);
+ }
+ /**
+ * Allocates a new TaskThread object.
+ */
+ public TaskThread(ThreadGroup group, Runnable target, String name) {
+ super(group, target, name);
+ }
+ /**
+ * A queued request to be run in the TaskThread
+ */
+ private static class Task {
+ public Task next;
+ public Runnable target;
+ public Task(Runnable target) {
+ this.target = target;
+ }
+ }
+ private Task head;
+ private Task tail;
+ protected boolean closed;
+ /**
+ * Queue up a task to be executed by this thread.
+ */
+ protected synchronized void queueRequest(Runnable r) {
+ Task t = new Task(r);
+ if (head == null) {
+ head = t;
+ wakeup();
+ } else {
+ tail.next = t;
+ }
+ tail = t;
+ }
+ /**
+ * Mark as closed and wake up.
+ */
+ protected synchronized void markClosed() {
+ if (!closed) {
+ closed = true;
+ wakeup();
+ }
+ }
+ /**
+ * Wait for the next queued request. If closed, return
+ * null. Relies on the default implementation of wakeup.
+ */
+ protected synchronized Runnable waitNextRequest() {
+ Task t;
+ while ((t = head) == null && !closed) {
+ try {
+ wait();
+ } catch (Exception e) {
+ }
+ }
+ head = t.next;
+ if (head == null) {
+ tail = null;
+ }
+ return t.target;
+ }
+ /**
+ * Get the next queued request or null if none
+ */
+ protected synchronized Runnable nextRequest() {
+ Task t = head;
+ if (t == null) {
+ return null;
+ }
+ head = t.next;
+ if (head == null) {
+ tail = null;
+ }
+ return t.target;
+ }
+ /**
+ * Wake up the thread to process tasks.
+ * Implementation depends on what the thread
+ * is waiting on. The default implementation
+ * does a this.notify().
+ */
+ protected void wakeup() {
+ notify();
+ }
+ /**
+ * Process any pending requests then return
+ */
+ protected void processQueuedRequests() {
+ Runnable r;
+ while ((r = nextRequest()) != null) {
+ r.run();
+ }
+ }
+ /**
+ * Check whether any tasks are pending
+ */
+ protected boolean areTasksPending() {
+ return (head != null);
+ }
+ /**
+ * Wait for and process pending requests until closed
+ */
+ protected void processRequestsForever() {
+ Runnable r;
+ while ((r = waitNextRequest()) != null) {
+ r.run();
+ }
+ }
+}
diff --git a/cdf/src/cdf-prop-value/cdf-util/src/main/java/org/openecomp/dcae/cdf/util/threads/ThreadCommon.java b/cdf/src/cdf-prop-value/cdf-util/src/main/java/org/openecomp/dcae/cdf/util/threads/ThreadCommon.java
new file mode 100644
index 0000000..fd9f3c1
--- /dev/null
+++ b/cdf/src/cdf-prop-value/cdf-util/src/main/java/org/openecomp/dcae/cdf/util/threads/ThreadCommon.java
@@ -0,0 +1,119 @@
+/*
+ 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.
+
+*/
+package org.openecomp.dcae.cdf.util.threads;
+
+/**
+ * Some functions to manipulate thread info. Based on
+ * http://nadeausoftware.com/articles/2008/04/java_tip_how_list_and_find_threads_and_thread_groups
+ * which is licensed under LGPL 2
+ */
+
+import java.lang.management.*;
+// import java.util.Arrays;
+
+public final class ThreadCommon {
+ /**
+ * ThreadCommon is not to be instantiated.
+ */
+ private ThreadCommon() { }
+
+ private static ThreadGroup rootThreadGroup = null;
+
+ /**
+ * Get the root thread group in the thread group tree.
+ * Since there is always a root thread group, this
+ * method never returns null.
+ *
+ * @return the root thread group
+ */
+ public static synchronized ThreadGroup getRootThreadGroup() {
+ if ( rootThreadGroup != null )
+ return rootThreadGroup;
+ ThreadGroup tg = Thread.currentThread().getThreadGroup();
+ ThreadGroup ptg;
+ while ( (ptg = tg.getParent()) != null )
+ tg = ptg;
+ return tg;
+ }
+
+ /**
+ * Get a list of all threads. Since there is always at
+ * least one thread, this method never returns null or
+ * an empty array.
+ *
+ * @return an array of threads
+ */
+ public static Thread[] getAllThreads() {
+ final ThreadGroup root = getRootThreadGroup();
+ final ThreadMXBean thbean = ManagementFactory.getThreadMXBean();
+ int nAlloc = thbean.getThreadCount();
+ int n = 0;
+ Thread[] threads;
+ do {
+ nAlloc *= 2;
+ threads = new Thread[ nAlloc ];
+ n = root.enumerate( threads, true );
+ } while ( n == nAlloc );
+ return copyOf( threads, n );
+ }
+
+ /**
+ * Get the thread with the given name. A null is returned
+ * if no such thread is found. If more than one thread has
+ * the same name, the first one found is returned.
+ *
+ * @param name the thread name to search for
+ * @return the thread, or null if not found
+ * @throws NullPointerException
+ * if the name is null
+ */
+ public static Thread getFirstThread( final String name ) {
+ if ( name == null )
+ throw new NullPointerException( "Null name" );
+ final Thread[] threads = getAllThreads();
+ for ( Thread thread : threads )
+ if ( thread.getName().equals( name ) )
+ return thread;
+ return null;
+ }
+
+ /**
+ * Get a list of all threads with a given thread name.
+ *
+ * @param name the name to look for
+ * @return an array of threads in that state
+ */
+ public static Thread[] getAllThreads( final String name ) {
+ if ( name == null )
+ throw new NullPointerException( "Null name" );
+ final Thread[] allThreads = getAllThreads();
+ final Thread[] found = new Thread[allThreads.length];
+ int nFound = 0;
+ for ( Thread thread : allThreads )
+ if ( thread.getName().equals(name) )
+ found[nFound++] = thread;
+ return copyOf( found, nFound );
+ }
+
+ // return java.util.Arrays.copyOf( found, nFound );
+ private static Thread[] copyOf( Thread[] threads, int n ) {
+ Thread[] nthreads = new Thread[ n ];
+ for (int i = 0; i < n; i++) {
+ nthreads[i] = threads[i];
+ }
+ return nthreads;
+ }
+}
diff --git a/cdf/src/cdf-prop-value/cdf-util/src/test/java/org/openecomp/dcae/cdf/util/AppTest.java b/cdf/src/cdf-prop-value/cdf-util/src/test/java/org/openecomp/dcae/cdf/util/AppTest.java
new file mode 100644
index 0000000..85d5cd8
--- /dev/null
+++ b/cdf/src/cdf-prop-value/cdf-util/src/test/java/org/openecomp/dcae/cdf/util/AppTest.java
@@ -0,0 +1,53 @@
+/*
+ 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.
+
+*/
+package org.openecomp.dcae.cdf.util;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+
+/**
+ * Unit test for simple App.
+ */
+public class AppTest
+ extends TestCase
+{
+ /**
+ * Create the test case
+ *
+ * @param testName name of the test case
+ */
+ public AppTest( String testName )
+ {
+ super( testName );
+ }
+
+ /**
+ * @return the suite of tests being tested
+ */
+ public static Test suite()
+ {
+ return new TestSuite( AppTest.class );
+ }
+
+ /**
+ * Rigourous Test :-)
+ */
+ public void testApp()
+ {
+ assertTrue( true );
+ }
+}
diff --git a/cdf/src/cdf-prop-value/makefile b/cdf/src/cdf-prop-value/makefile
new file mode 100644
index 0000000..194ad29
--- /dev/null
+++ b/cdf/src/cdf-prop-value/makefile
@@ -0,0 +1,13 @@
+all:
+
+build:
+ cd cdf-util/src/main/java && $(MAKE) build
+ cd cdf-prop-value/src/main/java && $(MAKE) build
+
+javadocs:
+ cd cdf-util/src/main/java && $(MAKE) javadocs
+ cd cdf-prop-value/src/main/java && $(MAKE) javadocs
+
+clean:
+ cd cdf-util/src/main/java && $(MAKE) clean
+ cd cdf-prop-value/src/main/java && $(MAKE) clean
diff --git a/cdf/src/common/postinst b/cdf/src/common/postinst
new file mode 100755
index 0000000..7c92a27
--- /dev/null
+++ b/cdf/src/common/postinst
@@ -0,0 +1,50 @@
+#!/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/cdf.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
+
+echo STARTING $0 $(date)
+umask 0
+echo STARTING $0 $(date) >> /tmp/pgaas.inst.report
+
+die()
+{
+ echo $0: "$@" 1>&2
+ echo $0: "$@"
+ umask 022
+ echo $0: "$@" >> /tmp/pgaas-failures
+ exit 1
+}
+
+id
+umask 022
+
+# randomize the the CDF package
+ranval=$(dd if=/dev/urandom count=1 ibs=8 2>/dev/null | od -x -w1000 | sed -e 's/^0000000 //' -e 's/ //g' -e 1q)
+CDFCFG=${INSTALL_ROOT}/opt/app/cdf/lib/cdf.cfg
+rm -f ${CDFCFG}
+sed -e 's/${HOSTNAME}/'"$(hostname -f)"'/' -e 's/${RANDOM}/'"$ranval"'0/' < ${INSTALL_ROOT}/opt/app/cdf/lib/cdf.cfg.tmpl > ${CDFCFG}
+chown postgres:postgres ${CDFCFG}
+
+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/cdf/src/makefile b/cdf/src/makefile
new file mode 100644
index 0000000..2c67454
--- /dev/null
+++ b/cdf/src/makefile
@@ -0,0 +1,52 @@
+
+DEVBIN=../../bin
+PKG=cdf
+REPACKAGESWMOPTS=
+REPACKAGEDEBIANOPTS=
+
+INS= ../install
+INSSTG= $(INS)/stage
+INSCOM= $(INS)/common
+
+all:
+
+clean-stage:
+ rm -rf $(INSSTG)
+
+clean-common:
+ rm -rf $(INSCOM)
+
+clean:
+ rm -rf $(INS)
+ cd cdf-prop-value && $(MAKE) clean
+
+build: javadocs build-java
+
+build-java:
+ cd cdf-prop-value && $(MAKE) build
+
+javadocs:
+ cd cdf-prop-value && $(MAKE) javadocs
+
+stage: build clean-stage clean-common
+ mkdir -p $(INS)
+ find stage common ! -name makefile ! -name '*~' | cpio -pudmv $(INS)
+ cp cdf-prop-value/cdf-prop-value/src/main/java/cdf-prop-value.jar $(INS)/stage/opt/app/cdf/lib/cdf-prop-value-1.0.0.jar
+ cp cdf-prop-value/cdf-util/src/main/java/cdf-util.jar $(INS)/stage/opt/app/cdf/lib/jars/cdf-util-1.0.0.jar
+ chmod a+x $(INSCOM)/*
+ 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: javadocs
+ cd cdf-prop-value && find cdf-*/src/main/java/javadoc -type f | while read f; do \
+ curl -k --user "$${OPENECOMP_NEXUS_USER}:$${OPENECOMP_NEXUS_PASSWORD}" --upload-file "$$f" "$${OPENECOMP_NEXUS_JAVADOC}/org.openecomp.dcae.storage.cdf/1.0.0/$$f"; \
+ done
+ # OPENECOMP_NEXUS_JAVADOC https://ecomp-nexus:8443/repository/dcae-javadoc/
+ # https://162.242.254.138:8443/#browse/browse/components:dcae-javadoc
+
diff --git a/cdf/src/repackage.json b/cdf/src/repackage.json
new file mode 100644
index 0000000..8802627
--- /dev/null
+++ b/cdf/src/repackage.json
@@ -0,0 +1,29 @@
+{
+ "executionUser": "postgres",
+ "maintainer": "OpenECOMP <dcae@lists.openecomp.org>",
+ "executionGroup": "postgres",
+ "directoryTreeTops": {
+ "/opt": "/opt/app/cdf"
+ },
+ "description": " PostgreSQL as a Service main scripts ",
+ "docker": {
+ "tag": "latest",
+ "externalDependencies": []
+ },
+ "version": "1.0.0",
+ "applicationName": "cdf",
+ "internalDependencies": [],
+ "fileGroup": "postgres",
+ "fileUser": "postgres",
+ "groupId": "org.openecomp.dcae.storage.pgaas",
+ "debian": {
+ "externalDependencies": [
+ {
+ "libgetopt-java": ">= 1.0.14"
+ }
+ ],
+ "groupId": "org.openecomp.dcae.storage.pgaas",
+ "conflicts": [],
+ "replaces": []
+ }
+} \ No newline at end of file
diff --git a/cdf/src/stage/opt/app/cdf/bin/getpropvalue b/cdf/src/stage/opt/app/cdf/bin/getpropvalue
new file mode 100755
index 0000000..cd81814
--- /dev/null
+++ b/cdf/src/stage/opt/app/cdf/bin/getpropvalue
@@ -0,0 +1,31 @@
+#!/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.
+
+
+P=/opt/cdf
+CDF=/opt/app/cdf
+
+export PATH=/opt/java/jdk/jdk170/bin:$PATH
+export CLASSPATH=$CDF/lib/cdf-prop-value-1.0.0.jar:$CDF/lib/jars/cdf-util-1.0.0.jar
+if [ -f $CDF/lib/jars/gnu_getopt.jar ]
+then CLASSPATH=$CLASSPATH:$CDF/lib/jars/gnu_getopt.jar ]
+elif [ -f /usr/share/java/gnu-getopt.jar ]
+then CLASSPATH=$CLASSPATH:/usr/share/java/gnu-getopt.jar
+else echo "$0: Cannot find gnu-getopt.jar" 1>&2; exit 1
+fi
+
+PropValue=org.openecomp.dcae.cdf.CdfPropValue
+CfgFile=$CDF/lib/cdf.cfg
+
+java $PropValue -f $CfgFile "$@"
diff --git a/cdf/src/stage/opt/app/cdf/bin/setencryptedvalues b/cdf/src/stage/opt/app/cdf/bin/setencryptedvalues
new file mode 100755
index 0000000..dc5b6d0
--- /dev/null
+++ b/cdf/src/stage/opt/app/cdf/bin/setencryptedvalues
@@ -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.
+
+
+P=/opt/cdf
+CDF=/opt/app/cdf
+
+export PATH=/opt/java/jdk/jdk170/bin:$PATH
+export CLASSPATH=$CDF/lib/cdf-prop-value-1.0.0.jar:$CDF/lib/jars/cdf-util-1.0.0.jar
+if [ -f $CDF/lib/jars/gnu_getopt.jar ]
+then CLASSPATH=$CLASSPATH:$CDF/lib/jars/gnu_getopt.jar ]
+elif [ -f /usr/share/java/gnu-getopt.jar ]
+then CLASSPATH=$CLASSPATH:/usr/share/java/gnu-getopt.jar
+else echo "$0: Cannot find gnu-getopt.jar" 1>&2; exit 1
+fi
+
+PropValue=org.openecomp.dcae.cdf.CdfPropValue
+
+java $PropValue -E "$@"
diff --git a/cdf/src/stage/opt/app/cdf/lib/cdf.cfg.tmpl b/cdf/src/stage/opt/app/cdf/lib/cdf.cfg.tmpl
new file mode 100644
index 0000000..7292963
--- /dev/null
+++ b/cdf/src/stage/opt/app/cdf/lib/cdf.cfg.tmpl
@@ -0,0 +1,18 @@
+# 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.
+
+
+####
+#### nothing should need to change below
+####
+Global_Title="This is the Common DCAE Framework 1.0 ${HOSTNAME} ${RANDOM}"
diff --git a/cdf/src/stage/opt/app/cdf/lib/jars/which_files b/cdf/src/stage/opt/app/cdf/lib/jars/which_files
new file mode 100644
index 0000000..47a7ba7
--- /dev/null
+++ b/cdf/src/stage/opt/app/cdf/lib/jars/which_files
@@ -0,0 +1,3 @@
+The following files were installed here:
+
+gnu_getopt.jar
diff --git a/makefile b/makefile
new file mode 100644
index 0000000..0758d61
--- /dev/null
+++ b/makefile
@@ -0,0 +1,21 @@
+
+all:
+
+STAGEDIRS=cdf postgresql-prep postgresql-config pgaas pgaas-post
+
+build:
+ for i in $(STAGEDIRS); do ( cd $$i/src && $(MAKE) build ) done
+
+clean:
+ for i in $(STAGEDIRS); do ( cd $$i/src && $(MAKE) clean ) done
+
+stage:
+ for i in $(STAGEDIRS); do ( cd $$i/src && $(MAKE) stage ) done
+
+upload-javadocs:
+ for i in $(STAGEDIRS); do ( cd $$i/src && $(MAKE) upload-javadocs ) done
+
+
+debian:
+ for i in $(STAGEDIRS); do ( cd $$i/src && $(MAKE) debian ) done
+
diff --git a/pgaas-post/.gitignore b/pgaas-post/.gitignore
new file mode 100644
index 0000000..7c32f55
--- /dev/null
+++ b/pgaas-post/.gitignore
@@ -0,0 +1 @@
+install
diff --git a/pgaas-post/src/common/postinst b/pgaas-post/src/common/postinst
new file mode 100755
index 0000000..47b1add
--- /dev/null
+++ b/pgaas-post/src/common/postinst
@@ -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.
+
+
+exec 1> /tmp/pgaas-post.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
+
+if [ -d /opt/app/postgresql-9.5.2 ]
+then chmod 751 /opt/app/postgresql-9.5.2 /opt/app/postgresql-9.5.2/bin /opt/app/postgresql-9.5.2/lib
+fi
+
+/opt/app/pgaas-post/bin/pgaas-verify-install
+
+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-post/src/common/postrm b/pgaas-post/src/common/postrm
new file mode 100755
index 0000000..42d2529
--- /dev/null
+++ b/pgaas-post/src/common/postrm
@@ -0,0 +1 @@
+echo STARTING $0 $(date)
diff --git a/pgaas-post/src/makefile b/pgaas-post/src/makefile
new file mode 100644
index 0000000..d66d74b
--- /dev/null
+++ b/pgaas-post/src/makefile
@@ -0,0 +1,38 @@
+
+DEVBIN=../../bin
+PKG=pgaas-post
+REPACKAGESWMOPTS=
+REPACKAGEDEBIANOPTS=
+
+INS= ../install
+INSSTG= $(INS)/stage
+INSCOM= $(INS)/common
+
+all:
+
+clean-stage:
+ rm -rf $(INSSTG)
+
+clean-common:
+ rm -rf $(INSCOM)
+
+clean:
+ rm -rf $(INS)
+
+build:
+
+stage: clean-stage clean-common
+ find common ! -name makefile ! -name '*~' | cpio -pudmv $(INS)
+ find stage ! -name makefile ! -name '*~' | cpio -pudmv $(INS)
+ chmod a+x $(INSSTG)/opt/app/pgaas-post/bin/*
+ cp -p repackage.* $(INS)
+
+
+debian: stage
+ repackage -y repackage.json -b debian -d $(INS) -u
+ repackage -y repackage.json -b debian -d $(INS) -u -B LATEST
+ @echo debian built
+
+upload-javadocs:
+ @echo nothing to do here
+
diff --git a/pgaas-post/src/repackage.json b/pgaas-post/src/repackage.json
new file mode 100644
index 0000000..134c00c
--- /dev/null
+++ b/pgaas-post/src/repackage.json
@@ -0,0 +1,23 @@
+{
+ "version": "1.0.0",
+ "executionUser": "root",
+ "description": " PostgreSQL as a Service main scripts ",
+ "maintainer": "OpenECOMP <dcae@lists.openecomp.org>",
+ "debian": {
+ "replaces": [],
+ "groupId": "org.openecomp.dcae.storage.pgaas",
+ "externalDependencies": [],
+ "conflicts": []
+ },
+ "internalDependencies": [],
+ "fileUser": "root",
+ "docker": {
+ "tag": "latest",
+ "externalDependencies": []
+ },
+ "directoryTreeTops": {},
+ "groupId": "org.openecomp.dcae.storage.pgaas",
+ "fileGroup": "root",
+ "applicationName": "pgaas-post",
+ "executionGroup": "root"
+} \ No newline at end of file
diff --git a/pgaas-post/src/stage/opt/app/pgaas-post/bin/pgaas-verify-install b/pgaas-post/src/stage/opt/app/pgaas-post/bin/pgaas-verify-install
new file mode 100644
index 0000000..5bf3962
--- /dev/null
+++ b/pgaas-post/src/stage/opt/app/pgaas-post/bin/pgaas-verify-install
@@ -0,0 +1,227 @@
+#!/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 "$@"
+ logger --stderr --priority local1.error --tag "DCAE" "$@"
+ exit 1
+}
+
+usage()
+{
+ exec 1>&2
+ [ $# -gt 0 ] && echo "$@"
+ b=$(basename $0)
+ echo "Usage: $b [-v]"
+ echo "$b runs a variety of tests on the PG VM and database"
+ echo "It must be run as root or postgres."
+ echo "If run as root, it will do additional tests that are"
+ echo "not possible as a normal user."
+ echo " -v verbose"
+ echo " -P do not print VERIFIED"
+ exit 1
+}
+
+PRINTVERIFIED=:
+while getopts Pv c
+do
+ case $c in
+ P ) PRINTVERIFIED=false ;;
+ v ) set -x ;;
+ '?' ) usage ;;
+ esac
+done
+shift `expr $OPTIND - 1`
+
+# this can be run as root
+ROOT=false
+case `id` in
+ *"(root)"* ) ROOT=true ;;
+ *"(postgres)"* ) ;;
+ * ) echo "$0 must be run as either root or postgres" ;;
+esac
+
+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/^/ /'
+}
+
+HOSTNAME=$(hostname -f)
+
+################################################################
+################ things set up by ################
+################ openstack ################
+################################################################
+
+case $HOSTNAME in
+ *.*.* ) verified "hostname has a FQDN" ;;
+ * ) failed "hostname does not have a FQDN" ;;
+esac
+
+################################################################
+################ things set up by ################
+################ controller dcae_install ################
+################################################################
+
+if grep '^dcae:' /etc/passwd > /dev/null
+then verified "dcae user exists"
+else failed "dcae user does not exist"
+fi
+if $ROOT
+then
+ if [ -s /etc/sudoers.d/dcae-postgres ]
+ then verified "dcae can sudo to postgres"
+ else failed "dcae cannot sudo to postgres"
+ fi
+fi
+
+SHOWDF=false
+for i in /opt/tools /dbroot/pgdata /dbroot/pglogs
+do
+ if df -h 2>&1 | grep " $i"'$' > /dev/null
+ then verified "$i has its own filesystem"
+ else failed "$i does not have its own filesystem"; SHOWDF=true
+ fi
+done
+$SHOWDF && tabtext "$(df -h 2>&1)"
+
+if grep '^postgres:' /etc/passwd > /dev/null
+then verified "postgres user exists"
+else failed "postgres user does not exist"
+fi
+
+################################################################
+################ things set up by ################
+################ cdf package ################
+################################################################
+
+if [ -d /opt/app/cdf ]
+then verified "/opt/app/cdf is present"
+else failed "/opt/app/cdf is present"
+fi
+
+cdfcall=$(/opt/app/cdf/bin/getpropvalue -n foo 2>&1)
+case "$cdfcall" in
+ *Configuration?property*must?be?defined* ) verified "CDF is installed and working" ;;
+ * ) failed "CDF is not installed and working"; tabtext "$cdfcall" ;;
+esac
+
+################################################################
+################ things set up by ################
+################ postgresql-prep package ################
+################################################################
+
+if grep "^pgnodes=.*$HOSTNAME" /opt/app/cdf/lib/cdf.cfg > /dev/null
+then verified "HOSTNAME is part of cluster (cdf.cfg pgnodes)"
+else failed "HOSTNAME is not part of cluster (cdf.cfg pgnodes)"
+fi
+
+# check for certificate presence goes here
+
+if [ -s /lib/systemd/system/pgaas-idns.service ]
+then verified "found pgaas-idns service properly installed for Ubuntu 16"
+elif [ -s /etc/init/pgaas-init.conf ]
+then verified "found pgaas-idns service properly installed for Ubuntu 14"
+else failed "pgaas-idns service has not bee installed properly"
+fi
+
+if [ -d /var/run/postgresql ]
+then verified "/var/run/postgresql exists"
+else failed "/var/run/postgresql does not exist"
+fi
+
+if [ -s /etc/logrotate.d/pgaas ]
+then verified "/etc/logrotate.d/pgaas has been installed"
+else failed "/etc/logrotate.d/pgaas has not been installed"
+fi
+
+
+################################################################
+################ things set up by ################
+################ postgresql-config ################
+################################################################
+
+if ps -fu postgres | grep "postgres: logger process" > /dev/null
+then verified "postgres is running"
+else failed "postgres does not have a logger process running"
+fi
+
+if pgrep repmgrd > /dev/null
+then verified "repmgrd is running"
+else failed "repmgrd is not running"
+fi
+
+if [ -f /opt/app/pgaas/bin/runpsqll ]
+then
+ verified "/opt/app/pgaas/bin/runpsqll is installed"
+ roles=$( /opt/app/pgaas/bin/runpsqll "select rolname from pg_roles" )
+ case "$roles" in
+ *repmgr* ) verified "postgres repmgr role name is present" ;;
+ * ) failed "postgres repmgr role name was not added"; tabtext "$roles" ;;
+ esac
+ rolcount=$( /opt/app/pgaas/bin/runpsqll "select count(rolname) from pg_roles" | awk 'NF > 0 {print $1}' )
+ case $rolcount in
+ 1 | 2 ) failed "no additional postgresql role names have been added"; tabtext "$roles" ;;
+ * ) verified "additional postgresql role names have been added" ;;
+ esac
+ dxpgtemporal=$( /opt/app/pgaas/bin/runpsqll "select count(extname) from pg_extension where extname = 'temporal_tables'" | awk 'NF > 0 {print $1}' )
+ case $dxpgtemporal in
+ 1 ) verified "temporal_tables extension has been added" ;;
+ * ) failed "temporal_tables extension has not been added" ;;
+ esac
+else
+ failed "/opt/app/pgaas/bin/runpsqll is not installed"
+fi
+
+if ps -ef | grep python3 | grep iDNS-responder.py > /dev/null
+then verified "iDNS-responder.py is running"
+else failed "iDNS-responder.py is not running"
+fi
+
+if [ -f /opt/app/pgaas/bin/check_cluster ]
+then
+ verified "/opt/app/pgaas/bin/check_cluster is installed"
+ ckcl=$( /opt/app/pgaas/bin/check_cluster 2>&1 )
+ case $ckcl in
+ *No?such?file?or?directory* ) failed "check_cluster not found"; tabtext "$ckcl" ;;
+ *ERROR* ) failed "check_cluster returned error:"; tabtext "$ckcl" ;;
+ *WARNING* ) failed "check_cluster returned a warning:"; tabtext "$ckcl" ;;
+ * ) verified "check_cluster succeeded" ;;
+ esac
+else
+ failed "/opt/app/pgaas/bin/check_cluster is not installed"
+fi
+
+echo "$VERIFIEDCOUNT tests passed, $FAILEDCOUNT tests failed, $TOTALCOUNT total tests run"
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
diff --git a/postgresql-config/.gitignore b/postgresql-config/.gitignore
new file mode 100644
index 0000000..7c32f55
--- /dev/null
+++ b/postgresql-config/.gitignore
@@ -0,0 +1 @@
+install
diff --git a/postgresql-config/src/common/postinst b/postgresql-config/src/common/postinst
new file mode 100755
index 0000000..b681058
--- /dev/null
+++ b/postgresql-config/src/common/postinst
@@ -0,0 +1,40 @@
+#!/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/postgresql-config.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
+id
+
+if $OPENECOMP
+then INSTALL_ROOT=
+fi
+
+echo STARTING $0 $(date)
+umask 0
+echo STARTING $0 $(date) >> /tmp/pgaas.inst.report
+
+export CFGDIR=${INSTALL_ROOT}/opt/app/postgresql-config/
+
+$CFGDIR/etc/do-post-install
+
+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/postgresql-config/src/makefile b/postgresql-config/src/makefile
new file mode 100644
index 0000000..bf6ae6b
--- /dev/null
+++ b/postgresql-config/src/makefile
@@ -0,0 +1,39 @@
+
+DEVBIN=../../bin
+PKG=postgresql-config
+REPACKAGESWMOPTS=
+REPACKAGEDEBIANOPTS=
+
+INS= ../install
+INSSTG= $(INS)/stage
+INSCOM= $(INS)/common
+
+all:
+
+clean-stage:
+ rm -rf $(INSSTG)
+
+clean-common:
+ rm -rf $(INSCOM)
+
+clean:
+ rm -rf $(INS)
+
+build:
+
+stage: clean-stage clean-common
+ mkdir -p $(INS)
+ find stage ! -name makefile ! -name '*~' | cpio -pudmv $(INS)
+ find common ! -name makefile ! -name '*~' | cpio -pudmv $(INS)
+ chmod -R a+x $(INS)/stage/opt/app/postgresql-config/etc/*
+ cp -p repackage.* $(INS)
+
+
+debian: stage
+ repackage -y repackage.json -b debian -d $(INS) -u
+ repackage -y repackage.json -b debian -d $(INS) -u -B LATEST
+ @echo debian built
+
+upload-javadocs:
+ @echo nothing to do here
+
diff --git a/postgresql-config/src/repackage.json b/postgresql-config/src/repackage.json
new file mode 100644
index 0000000..d4376fe
--- /dev/null
+++ b/postgresql-config/src/repackage.json
@@ -0,0 +1,25 @@
+{
+ "debian": {
+ "replaces": [],
+ "conflicts": [],
+ "groupId": "org.openecomp.dcae.storage.pgaas",
+ "externalDependencies": []
+ },
+ "fileGroup": "postgres",
+ "version": "1.0.0",
+ "applicationName": "postgresql-config",
+ "internalDependencies": [],
+ "directoryTreeTops": {
+ "/opt": "/opt/app/postgresql-config"
+ },
+ "executionUser": "postgres",
+ "maintainer": "OpenECOMP <dcae@lists.openecomp.org>",
+ "fileUser": "postgres",
+ "docker": {
+ "tag": "latest",
+ "externalDependencies": []
+ },
+ "groupId": "org.openecomp.dcae.storage.pgaas",
+ "description": " PostgreSQL as a Service main scripts ",
+ "executionGroup": "postgres"
+} \ No newline at end of file
diff --git a/postgresql-config/src/stage/opt/app/postgresql-config/etc/common-db-tasks b/postgresql-config/src/stage/opt/app/postgresql-config/etc/common-db-tasks
new file mode 100644
index 0000000..517fabd
--- /dev/null
+++ b/postgresql-config/src/stage/opt/app/postgresql-config/etc/common-db-tasks
@@ -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.
+
+
+set -x
+
+die()
+{
+ echo $0: "$@" 1>&2
+ echo $0: "$@"
+ umask 022
+ echo $0: "$@" >> /tmp/pgaas-failures
+ exit 1
+}
+
+[ -n "$DBROOT" ] || die "DBROOT is not set"
+[ -n "$CFGDIR" ] || die "CFGDIR is not set"
+
+# set up ~/.pgpass
+$CFGDIR/etc/gen-pgpass
+# set up repmgr.conf
+$CFGDIR/etc/gen-repmgr.conf
+
+# We don't really need to save pwd.cfg anymore since we are now forcing the password.
+# PWDCFG=$DBROOT/../pgaas/pwd.cfg
+# egrep '^Global_Title|^postgres|^repmgr' ${INSTALL_ROOT}/opt/app/cdf/lib/cdf.cfg > $PWDCFG
+
+cd $CFGDIR/main || die "Cannot cd $CFGDIR/main"
+
+sed -e "s!%CFGDIR%!$CFGDIR!" < postgresql.conf.orig > postgresql.conf || die "Cannot cp postgresql.conf"
+sed -e "s!%CFGDIR%!$CFGDIR!" < pg_hba.conf.orig > pg_hba.conf || die "Cannot cp pg_hba.conf"
+
diff --git a/postgresql-config/src/stage/opt/app/postgresql-config/etc/create-cdf-master b/postgresql-config/src/stage/opt/app/postgresql-config/etc/create-cdf-master
new file mode 100644
index 0000000..c079b51
--- /dev/null
+++ b/postgresql-config/src/stage/opt/app/postgresql-config/etc/create-cdf-master
@@ -0,0 +1,44 @@
+#!/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.
+
+
+set -x
+
+DBROOT=/dbroot/pgdata/main
+CDFCFG=${INSTALL_ROOT}/opt/app/cdf/lib/cdf.cfg
+
+# We don't really need to save pwd.cfg anymore since we are now forcing the password.
+# PWDCFG=$DBROOT/../pgaas/pwd.cfg
+# if the DB already exists in Cinder storage, grab the password from there for use elsewhere
+# if [ -s $PWDCFG -a $( egrep '^Global_Title' < $PWDCFG ) -eq 1 ]
+# then
+# TMP=$(mktemp /tmp/tmp.ccm.XXXXXXXXXX)
+# trap 'rm -f $TMP' 0 1 2 3 15
+# egrep -v '^Global_Title|^postgres|^repmgr' $CDFCFG > $TMP
+# egrep '^Global_Title|^postgres|^repmgr' $PWDCFG | cat $TMP - > $CDFCFG
+# fi
+
+# generate a 64 hex random value (256 bits of randomness) for the passwords
+if grep '^postgres' $CDFCFG > /dev/null
+then :
+else
+ val2=$(dd if=/dev/urandom count=1 ibs=32 2>/dev/null | od -x -w1000 | sed -e 's/^0000000 //' -e 's/ //g' -e 1q)
+ echo "ENCRYPTME.AES.postgres=$val2" | ${INSTALL_ROOT}/opt/app/cdf/bin/setencryptedvalues >> $CDFCFG
+fi
+if grep '^repmgr' $CDFCFG > /dev/null
+then :
+else
+ val2=$(dd if=/dev/urandom count=1 ibs=32 2>/dev/null | od -x -w1000 | sed -e 's/^0000000 //' -e 's/ //g' -e 1q)
+ echo "ENCRYPTME.AES.repmgr=$val2" | ${INSTALL_ROOT}/opt/app/cdf/bin/setencryptedvalues >> $CDFCFG
+fi
diff --git a/postgresql-config/src/stage/opt/app/postgresql-config/etc/create-cdf-secondary b/postgresql-config/src/stage/opt/app/postgresql-config/etc/create-cdf-secondary
new file mode 100644
index 0000000..034d897
--- /dev/null
+++ b/postgresql-config/src/stage/opt/app/postgresql-config/etc/create-cdf-secondary
@@ -0,0 +1,62 @@
+#!/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.
+
+
+set -x
+
+die()
+{
+ echo $0: "$@" 1>&2
+ echo $0: "$@"
+ umask 022
+ echo $0: "$@" >> /tmp/pgaas-failures
+ exit 1
+}
+
+[ -n "$MASTER" ] || die "MASTER is not set"
+
+umask 077
+TMP=$( mktemp /tmp/tmp.ccs1.XXXXXXXXXX )
+trap 'rm -f $TMP' 0 1 2 3 15
+
+bwget()
+{
+ ${INSTALL_ROOT}/opt/app/postgresql-prep/bin/pgwget --progress=dot:giga "$@"
+}
+
+done=
+max=40
+for s in `seq $max`
+do
+ echo "$s of $max: Waiting for master $MASTER to send cdf.cfg"
+ bwget -O$TMP http://$MASTER:8000/getcdf/`hostname -f`
+ ls -l $TMP
+ if [ -s $TMP ]
+ then
+ msg=$(cat $TMP)
+ case "$msg" in
+ OK* )
+ echo "Received cdf.cfg"
+ done=yes
+ break
+ ;;
+ * ) echo "Received invalid cdf: $msg"
+ ;;
+ esac
+ fi
+ rm -f $TMP
+ sleep 15
+done
+[ "$done" = "yes" ] || die "Master did not send cdf.cfg"
+
diff --git a/postgresql-config/src/stage/opt/app/postgresql-config/etc/create-db-backup b/postgresql-config/src/stage/opt/app/postgresql-config/etc/create-db-backup
new file mode 100644
index 0000000..625ce57
--- /dev/null
+++ b/postgresql-config/src/stage/opt/app/postgresql-config/etc/create-db-backup
@@ -0,0 +1,34 @@
+#!/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 /opt/app/postgresql-9.5.2 ]
+then PGDIR=/opt/app/postgresql-9.5.2
+else PGDIR=/usr/lib/postgresql/9.5
+fi
+
+$PGDIR/bin/psql <<-EOF
+ SELECT pg_start_backup('backup');
+EOF
+
+cd /dbroot/pgdata &&
+{
+ find main | grep -v main/pg_xlog/
+ find main/pg_xlog -type d
+} | cpio -oc | gzip > main.cpio.gz.$$ && mv main.cpio.gz.$$ main.cpio.gz
+
+$PGDIR/bin/psql <<-EOF
+ SELECT pg_stop_backup();
+EOF
+echo /dbroot/pgdata/main.cpio.gz created
diff --git a/postgresql-config/src/stage/opt/app/postgresql-config/etc/create-db-master b/postgresql-config/src/stage/opt/app/postgresql-config/etc/create-db-master
new file mode 100644
index 0000000..f0081be
--- /dev/null
+++ b/postgresql-config/src/stage/opt/app/postgresql-config/etc/create-db-master
@@ -0,0 +1,72 @@
+#!/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.
+
+
+# create a master database
+set -x
+
+die()
+{
+ echo $0: "$@" 1>&2
+ echo $0: "$@"
+ umask 022
+ echo $0: "$@" >> /tmp/pgaas-failures
+ exit 1
+}
+
+[ -n "$PGDIR" ] || die "PGDIR is not set"
+[ -n "$DBROOT" ] || die "DBROOT is not set"
+[ -n "$CFGDIR" ] || die "CFGDIR is not set"
+
+cd $CFGDIR/main || die "Cannot cd $CFGDIR/main"
+
+PATH=${INSTALL_ROOT}/opt/app/postgresql-prep/bin:$CFGDIR/etc:$PGDIR/bin:$PATH
+
+umask 077
+TMP=$(mktemp /tmp/tmp.cdm.XXXXXXXXXX)
+trap 'rm -f $TMP' 0 1 2 3 15
+
+rm -rf $DBROOT/* # initdb fails if the directory is not totally empty
+pswd=$( ${INSTALL_ROOT}/opt/app/cdf/bin/getpropvalue -x -n postgres )
+echo "$pswd" > $TMP
+$PGDIR/bin/initdb -D $DBROOT --pwfile=$TMP
+rm -f $TMP
+
+$CFGDIR/etc/start-db
+sleep 30
+
+# create temporal tables and other extensions, if needed
+$CFGDIR/etc/create-extensions
+
+# create repmgr user/db, if needed
+$CFGDIR/etc/create-repmgr-user
+
+sleep 10
+
+# register as master
+repmgr -f $CFGDIR/main/repmgr.conf master register
+echo repmgr ret=$?
+
+sleep 10
+
+# start repmgrd
+# start repmgrd (verbose logging for testing)
+umask 07
+repmgrd -f $CFGDIR/main/repmgr.conf -d --verbose
+echo repmgrd ret=$?
+# start repmgrd (normal logging)
+# repmgrd -f $CFGDIR/main/repmgr.conf -d
+
+
+# NO LONGER NEEDED $CFGDIR/etc/create-db-backup
diff --git a/postgresql-config/src/stage/opt/app/postgresql-config/etc/create-db-secondary b/postgresql-config/src/stage/opt/app/postgresql-config/etc/create-db-secondary
new file mode 100644
index 0000000..3e2c304
--- /dev/null
+++ b/postgresql-config/src/stage/opt/app/postgresql-config/etc/create-db-secondary
@@ -0,0 +1,122 @@
+#!/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.
+
+
+# create a secondary database
+set -x
+
+die()
+{
+ echo $0: "$@" 1>&2
+ echo $0: "$@"
+ umask 022
+ echo $0: "$@" >> /tmp/pgaas-failures
+ exit 1
+}
+
+[ -n "$MASTER" ] || die "MASTER is not set"
+[ -n "$PGDIR" ] || die "PGDIR is not set"
+[ -n "$DBROOT" ] || die "DBROOT is not set"
+[ -n "$CFGDIR" ] || die "CFGDIR is not set"
+
+cd $CFGDIR/main || die "Cannot cd $CFGDIR/main"
+
+PATH=${INSTALL_ROOT}/opt/app/postgresql-prep/bin:$CFGDIR/etc:$PGDIR/bin:$PATH
+
+bwget()
+{
+ ${INSTALL_ROOT}/opt/app/postgresql-prep/bin/pgwget --progress=dot:giga "$@"
+}
+
+umask 077
+TMP=$(mktemp /tmp/tmp.cds1.XXXXXXXXXX)
+TMP2=$(mktemp /tmp/tmp.cds2.XXXXXXXXXX)
+trap 'rm -f $TMP $TMP2' 0 1 2 3 15
+
+# wait until master DB is active and has repmgr available
+max=40
+for s in `seq $max`
+do
+ echo "$s of $max: Asking master $MASTER if repmgr is ready"
+ bwget -O$TMP http://$MASTER:8000/hasrepmgr
+ ls -l $TMP
+ if [ -s $TMP ]
+ then
+ msg=$(cat $TMP)
+ case $msg in
+ OK* )
+ echo "Master has repmgr ready"
+ done=yes
+ break
+ ;;
+ * )
+ echo "Master does not have repmgr ready, msg=$msg"
+ ;;
+ esac
+ fi
+ rm -f $TMP
+ sleep 15
+done
+[ "$done" = "yes" ] || die "Master never had repmgr available"
+
+
+# clone database from master
+
+# make sure /dbroot/pgdata/main is empty
+mv $DBROOT $DBROOT-$(date +%Y%m%d%H%M%S)
+mkdir -p $DBROOT
+# rm -rf $DBROOT/*
+
+repmgr -v -h $MASTER -U repmgr -d repmgr -D $DBROOT -f $CFGDIR/main/repmgr.conf --ignore-external-config-files standby clone
+
+if [ ! -f $DBROOT/PG_VERSION ]
+then
+ umask 022
+ cat /opt/app/log/postgresql/server/repmgr.log >> /tmp/pgaas-failures
+ die repmgr clone failed
+fi
+
+$CFGDIR/etc/start-db
+
+sleep 10
+
+# register as standby
+repmgr -f $CFGDIR/main/repmgr.conf standby register
+echo repmgr ret=$?
+sleep 10
+
+# start repmgrd
+# start repmgrd (verbose logging for testing)
+umask 07
+
+# wait until repmgrd starts up
+max=20
+REPLOG=/opt/app/log/postgresql/server/repmgr.log
+done=no
+for s in `seq $max`
+do
+ cat $REPLOG > $TMP
+ repmgrd -f $CFGDIR/main/repmgr.conf -d --verbose
+ # start repmgrd (normal logging)
+ # repmgrd -f $CFGDIR/main/repmgr.conf -d
+ echo repmgrd ret=$?
+ sleep 5
+ diff $TMP $REPLOG | grep "ERROR.*terminating" > $TMP2
+ if [ -s "$TMP2" ]
+ then cat "$TMP2"
+ else done=yes; break
+ fi
+ sleep 10
+done
+[ "$done" = "yes" ] || die "Secondary never started repmgrd"
diff --git a/postgresql-config/src/stage/opt/app/postgresql-config/etc/create-extensions b/postgresql-config/src/stage/opt/app/postgresql-config/etc/create-extensions
new file mode 100644
index 0000000..09f0229
--- /dev/null
+++ b/postgresql-config/src/stage/opt/app/postgresql-config/etc/create-extensions
@@ -0,0 +1,53 @@
+#!/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.
+
+
+set -x
+
+die()
+{
+ echo $0: "$@" 1>&2
+ echo $0: "$@"
+ umask 022
+ echo $0: "$@" >> /tmp/pgaas-failures
+ exit 1
+}
+
+[ -n "$PGDIR" ] || die "PGDIR is not set"
+
+PATH=${INSTALL_ROOT}/opt/app/postgresql-prep/bin:$PGDIR/bin:$PATH
+
+TMP=$(mktemp /tmp/tmp.ce.XXXXXXXXXX)
+trap 'rm -f $TMP' 0 1 2 3 15
+
+echo "select datname from pg_database;" | psql --tuples-only | sed -e 's/^ *//' -e '/^$/d' -e '/^template0$/d' -e '/^repmgr$/d' > $TMP
+
+for db in $(< $TMP)
+do
+ # enable temporal tables for use
+ if [ -f /opt/app/postgresql-9.5.2/lib/temporal_tables.so ]
+ then
+ psql --dbname=$db <<-EOF
+ CREATE EXTENSION temporal_tables;
+ EOF
+ else
+ echo "$0: temporal_tables extension is not installed"
+ fi
+
+ # and other extensions
+ psql --dbname=$db <<-EOF
+ CREATE EXTENSION hstore;
+ CREATE EXTENSION pgcrypto;
+ EOF
+done
diff --git a/postgresql-config/src/stage/opt/app/postgresql-config/etc/create-repmgr-user b/postgresql-config/src/stage/opt/app/postgresql-config/etc/create-repmgr-user
new file mode 100644
index 0000000..06b5a0a
--- /dev/null
+++ b/postgresql-config/src/stage/opt/app/postgresql-config/etc/create-repmgr-user
@@ -0,0 +1,40 @@
+#!/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.
+
+
+set -x
+
+die()
+{
+ echo $0: "$@" 1>&2
+ echo $0: "$@"
+ umask 022
+ echo $0: "$@" >> /tmp/pgaas-failures
+ exit 1
+}
+
+[ -n "$PGDIR" ] || die "PGDIR is not set"
+
+PATH=${INSTALL_ROOT}/opt/app/postgresql-prep/bin:$PGDIR/bin:$PATH
+pswd=$( ${INSTALL_ROOT}/opt/app/cdf/bin/getpropvalue -x -n repmgr )
+
+# note: The "pgaas" in "repmgr_pgaas" must match the cluster name used in repmgr.conf
+
+psql <<-EOF
+ CREATE ROLE repmgr SUPERUSER CREATEDB CREATEROLE INHERIT LOGIN;
+ DROP DATABASE repmgr;
+ CREATE DATABASE repmgr OWNER repmgr;
+ ALTER USER repmgr PASSWORD '$pswd';
+ ALTER USER repmgr SET search_path TO repmgr_pgaas, "\$user", public;
+EOF
diff --git a/postgresql-config/src/stage/opt/app/postgresql-config/etc/create-ssh-master b/postgresql-config/src/stage/opt/app/postgresql-config/etc/create-ssh-master
new file mode 100644
index 0000000..5565041
--- /dev/null
+++ b/postgresql-config/src/stage/opt/app/postgresql-config/etc/create-ssh-master
@@ -0,0 +1,40 @@
+#!/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.
+
+
+set -x
+
+die()
+{
+ echo $0: "$@" 1>&2
+ echo $0: "$@"
+ umask 022
+ echo $0: "$@" >> /tmp/pgaas-failures
+ exit 1
+}
+
+umask 077
+mkdir -p ~postgres/.ssh
+chmod 700 ~postgres/.ssh
+
+PGAASDIR=/dbroot/pgdata/pgaas
+if [ -f $PGAASDIR/id_rsa.pub -a -f $PGAASDIR/id_rsa -a $PGAASDIR/authorized_keys ]
+then
+ cp -p $PGAASDIR/id_rsa.pub $PGAASDIR/id_rsa $PGAASDIR/authorized_keys ~postgres/.ssh
+else
+ ssh-keygen -t rsa -N '' -f ~postgres/.ssh/id_rsa
+ cp -p ~postgres/.ssh/id_rsa.pub ~postgres/.ssh/authorized_keys
+ cp -p ~postgres/.ssh/id_rsa ~postgres/.ssh/id_rsa.pub ~postgres/.ssh/authorized_keys $PGAASDIR
+fi
+
diff --git a/postgresql-config/src/stage/opt/app/postgresql-config/etc/create-ssh-secondary b/postgresql-config/src/stage/opt/app/postgresql-config/etc/create-ssh-secondary
new file mode 100644
index 0000000..a5ee2d4
--- /dev/null
+++ b/postgresql-config/src/stage/opt/app/postgresql-config/etc/create-ssh-secondary
@@ -0,0 +1,102 @@
+#!/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.
+
+
+set -x
+
+die()
+{
+ echo $0: "$@" 1>&2
+ echo $0: "$@"
+ umask 022
+ echo $0: "$@" >> /tmp/pgaas-failures
+ exit 1
+}
+
+bwget()
+{
+ ${INSTALL_ROOT}/opt/app/postgresql-prep/bin/pgwget --progress=dot:giga "$@"
+}
+
+[ -n "$MASTER" ] || die "MASTER is not set"
+
+
+
+umask 077
+TMP=$(mktemp /tmp/tmp.css1.XXXXXXXXXX)
+TMP2=$(mktemp /tmp/tmp.css2.XXXXXXXXXX)
+trap 'rm -f $TMP $TMP2' 0 1 2 3 15
+
+# do we have the keys already?
+if [ -f $PGAASDIR/id_rsa.pub -a -f $PGAASDIR/id_rsa -a $PGAASDIR/authorized_keys ]
+then
+ mkdir -p ~postgres/.ssh
+ chmod 700 ~postgres/.ssh
+ cp -p $PGAASDIR/id_rsa.pub $PGAASDIR/id_rsa $PGAASDIR/authorized_keys ~postgres/.ssh
+else
+ # no? copy them from the master
+ done=
+ max=40
+ for s in `seq $max`
+ do
+ echo "$s of $max: Waiting for master $MASTER to come online and send its public key"
+ bwget -O$TMP http://$MASTER:8000/getpubkey
+ ls -l $TMP
+ if [ -s $TMP ]
+ then
+ msg=$(cat $TMP)
+ case "$msg" in
+ ssh-rsa* )
+ echo "Received public key"
+ mkdir -p ~postgres/.ssh
+ chmod 700 ~postgres/.ssh
+ cp -p $TMP ~postgres/.ssh/authorized_keys
+ done=yes
+ break
+ ;;
+ * ) echo "Received invalid public key: $msg"
+ ;;
+ esac
+ else
+ echo "No key available yet"
+ fi
+ rm -f $TMP
+ sleep 15
+ done
+ [ "$done" = "yes" ] || die "Unable to get key from $MASTER"
+
+ done=
+ max=40
+ for s in `seq $max`
+ do
+ echo "$s of $max: Asking for master $MASTER to send remaining ssh files"
+ bwget -O$TMP2 http://$MASTER:8000/getssh/`hostname -f`
+ ls -l $TMP2
+ if [ -s $TMP2 ]
+ then
+ msg=$(cat $TMP2)
+ case "$msg" in
+ OK* ) echo "Master has sent the remaining ssh keys"
+ done=yes
+ break
+ ;;
+ * ) echo "No ssh keys yet: $msg"
+ ;;
+ esac
+ fi
+ rm -f $TMP2
+ sleep 15
+ done
+ [ "$done" = "yes" ] || die "Master did not send ssh keys"
+fi
diff --git a/postgresql-config/src/stage/opt/app/postgresql-config/etc/do-post-install b/postgresql-config/src/stage/opt/app/postgresql-config/etc/do-post-install
new file mode 100644
index 0000000..9b25be8
--- /dev/null
+++ b/postgresql-config/src/stage/opt/app/postgresql-config/etc/do-post-install
@@ -0,0 +1,124 @@
+#!/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.
+
+
+set -x
+
+die()
+{
+ echo "$@" 1>&2
+ echo $0: "$@"
+ umask 022
+ echo $0: "$@" >> /tmp/pgaas-failures
+ exit 1
+}
+
+[ -n "$CFGDIR" ] || die "CFGDIR is not set"
+[ -n "$OPENECOMP" ] || die "OPENECOMP is not set"
+[ -n "$NOTOPENECOMP" ] || die "NOTOPENECOMP is not set"
+
+if $OPENECOMP
+then export PGDIR=${INSTALL_ROOT}/usr/lib/postgresql/9.5
+else export PGDIR=${INSTALL_ROOT}/opt/app/postgresql-9.5.2
+fi
+export DBROOT=/dbroot/pgdata/main
+export PATH=$PATH:${INSTALL_ROOT}/opt/app/postgresql-prep/bin
+
+$CFGDIR/etc/makecerts
+
+cat $CFGDIR/lib/profile.additions >> ~postgres/.profile
+
+# Determine which system is the master.
+# For central, we look first in /tmp/postgres.conf.
+# If we don't find that, we look at the pgnodes list and pick the first one.
+# For edge, we ignore /tmp/postgres.conf and go directly to the pgnodes list.
+# Each edge site has its own master.
+clustertype=$( ${INSTALL_ROOT}/opt/app/cdf/bin/getpropvalue -n cluster )
+ismaster=no
+
+case $clustertype in
+ central )
+ CONF=/tmp/postgres.conf
+ if [ -f $CONF ] # OpenDCAE
+ then
+ umask 077
+ TMP=$(mktemp /tmp/tmp.pi1.XXXXXXXXXX)
+ trap 'rm -f $TMP' 0 1 2 3 15
+ sed -e 's/ *: */="/' -e 's/$/"/' -e 's/=""/="/' -e 's/""$/"/' < $CONF > $TMP
+ . $TMP
+ case `hostname` in
+ $master ) ismaster=yes ;;
+ *?* ) ismaster=no ;;
+ '' ) die "master is not set in $CONF"
+ esac
+ PGNODES=$( ${INSTALL_ROOT}/opt/app/cdf/bin/getpropvalue -n pgnodes )
+ export MASTER=$( gen-repmgr-info -n "$PGNODES" -M "$master" )
+ [ -n "$MASTER" ] || die "Cannot determine master system. $CONF has '$master' (from env.yaml), which cannot be found in pgnodes."
+
+ else
+ # not OpenDCAE
+ ismaster=yes
+ PGNODES=$( ${INSTALL_ROOT}/opt/app/cdf/bin/getpropvalue -n pgnodes )
+ export MASTER=$( gen-repmgr-info -n "$PGNODES" -m )
+ fi
+ ;;
+ edge )
+ host=$( hostname -f )
+ PGNODES=$( ${INSTALL_ROOT}/opt/app/cdf/bin/getpropvalue -n pgnodes )
+ export MASTER=$( gen-repmgr-info -n "$PGNODES" -C $host )
+ case $MASTER in
+ '' ) die "Cannot determine master system. Does cdf.cfg have pgnodes= in it? Is $host listed as a site?" ;;
+ DEFAULT ) ismaster=yes MASTER=$host ;;
+ esac
+ ;;
+esac
+
+ssh_and_cdf_okay=no
+
+case $ismaster in
+ yes ) # master
+ $CFGDIR/etc/create-ssh-master &&
+ $CFGDIR/etc/create-cdf-master &&
+ ssh_and_cdf_okay=yes
+ ;;
+
+ no ) # secondary
+ $CFGDIR/etc/create-ssh-secondary &&
+ $CFGDIR/etc/create-cdf-secondary &&
+ touch $CFGDIR/lib/ignore-database-reconfiguration # prevent dcae_admin_db.py from looking at json DB reconfigurations &&
+ ssh_and_cdf_okay=yes
+ ;;
+esac
+
+[ "$ssh_and_cdf_okay" = yes ] || die "Could not set up ssh or cdf"
+
+$CFGDIR/etc/common-db-tasks
+# check if we have a database already
+if [ ! -s $DBROOT/PG_VERSION ]
+then
+ # need to create it
+ case $ismaster in
+ yes ) $CFGDIR/etc/create-db-master ;;
+ no ) $CFGDIR/etc/create-db-secondary ;;
+ esac
+else
+ # need to update it
+ case $ismaster in
+ yes ) $CFGDIR/etc/update-db-master ;;
+ no )
+ $CFGDIR/etc/create-db-secondary # use repmgr clone even if secondary previously existed
+ # $CFGDIR/etc/update-db-secondary
+ ;;
+ esac
+fi
diff --git a/postgresql-config/src/stage/opt/app/postgresql-config/etc/gen-pgpass b/postgresql-config/src/stage/opt/app/postgresql-config/etc/gen-pgpass
new file mode 100644
index 0000000..ca99a0f
--- /dev/null
+++ b/postgresql-config/src/stage/opt/app/postgresql-config/etc/gen-pgpass
@@ -0,0 +1,33 @@
+#!/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.
+
+
+# create ~postgres/.pgpass
+postgrespswd=$( ${INSTALL_ROOT}/opt/app/cdf/bin/getpropvalue -x -n postgres )
+repmgrpswd=$( ${INSTALL_ROOT}/opt/app/cdf/bin/getpropvalue -x -n repmgr )
+umask 077
+if [ -f ~postgres/.pgpaas ]
+then
+ ed ~postgres/.pgpaas <<-EOF
+ H
+ g/:postgres:/d
+ g/:repmgr:/d
+ w
+ q
+ EOF
+fi
+
+echo "*:*:*:postgres:$postgrespswd" >> ~postgres/.pgpass
+echo "*:*:*:repmgr:$repmgrpswd" >> ~postgres/.pgpass
+chmod go-rwx ~postgres/.pgpass
diff --git a/postgresql-config/src/stage/opt/app/postgresql-config/etc/gen-recovery.conf b/postgresql-config/src/stage/opt/app/postgresql-config/etc/gen-recovery.conf
new file mode 100644
index 0000000..fc80cb0
--- /dev/null
+++ b/postgresql-config/src/stage/opt/app/postgresql-config/etc/gen-recovery.conf
@@ -0,0 +1,51 @@
+#!/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.
+
+
+set -x
+
+die()
+{
+ echo $0: "$@" 1>&2
+ echo $0: "$@"
+ umask 022
+ echo $0: "$@" >> /tmp/pgaas-failures
+ exit 1
+}
+
+[ -n "$DBROOT" ] || die "DBROOT is not set"
+
+cd $DBROOT || die "Cannot cd $DBROOT"
+PATH=${INSTALL_ROOT}/opt/app/postgresql-prep/bin:$PATH
+
+PGNODES=$( ${INSTALL_ROOT}/opt/app/cdf/bin/getpropvalue -n pgnodes )
+HOSTNAME=`hostname -f`
+PGNODEVALUE=$( gen-repmgr-info -n "$PGNODES" -l "$HOSTNAME" )
+
+# node_name from repmgr.conf => application_name in recovery.conf conninfo line
+# "node" value from repmgr.conf => primary_slot_name in recovery.conf with the string "repmgr_slot_" prefixed
+# node_name in repmgr.conf can be the $HOSTNAME value ?
+
+pswd=$( ${INSTALL_ROOT}/opt/app/cdf/bin/getpropvalue -x -n repmgr )
+
+appname=$HOSTNAME
+PGNODEVALUE=$( gen-repmgr-info -n "$PGNODES" -l "$HOSTNAME" )
+umask 07
+cat <<-EOF > $DBROOT/recovery.conf
+ standby_mode = 'on'
+ primary_conninfo = 'user=repmgr password=$pswd host=$HOSTNAME port=5432 application_name=$HOSTNAME sslmode=prefer sslcompression=1'
+ recovery_target_timeline = 'latest'
+ primary_slot_name = repmgr_slot_$PGNODEVALUE
+EOF
+
diff --git a/postgresql-config/src/stage/opt/app/postgresql-config/etc/gen-repmgr.conf b/postgresql-config/src/stage/opt/app/postgresql-config/etc/gen-repmgr.conf
new file mode 100755
index 0000000..ca595f6
--- /dev/null
+++ b/postgresql-config/src/stage/opt/app/postgresql-config/etc/gen-repmgr.conf
@@ -0,0 +1,63 @@
+#!/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.
+
+
+set -x
+
+die()
+{
+ echo $0: "$@" 1>&2
+ echo $0: "$@"
+ umask 022
+ echo $0: "$@" >> /tmp/pgaas-failures
+ exit 1
+}
+
+[ -n "$CFGDIR" ] || die "CFGDIR is not set"
+
+cd $CFGDIR/main || die "Cannot cd $CFGDIR/main"
+PATH=${INSTALL_ROOT}/opt/app/postgresql-prep/bin:$PATH
+LOGDIR=/opt/app/log/postgresql/server
+
+PGNODES=$( ${INSTALL_ROOT}/opt/app/cdf/bin/getpropvalue -n pgnodes )
+
+CLUSTER=pgaas
+HOSTNAME=`hostname -f`
+PGNODEVALUE=$( gen-repmgr-info -n "$PGNODES" -l "$HOSTNAME" )
+UPSTREAMPGNODE=$( gen-repmgr-info -n "$PGNODES" -c "$HOSTNAME" )
+
+UPSTREAMTEXT="#upstream_node="
+case $UPSTREAMPGNODE in
+ DEFAULT ) ;;
+ * ) UPSTREAMTEXT="upstream_node=$UPSTREAMPGNODE" ;;
+esac
+
+cat <<-EOF > repmgr.conf
+ cluster=$CLUSTER
+ node=$PGNODEVALUE
+ node_name=$HOSTNAME
+ conninfo='host=$HOSTNAME user=repmgr dbname=repmgr'
+ use_replication_slots=1
+ $UPSTREAMTEXT
+
+ failover=automatic
+ promote_command='repmgr standby promote -f $CFGDIR/main/repmgr.conf'
+ follow_command='repmgr standby follow -f $CFGDIR/main/repmgr.conf'
+ event_notification_command='/opt/app/postgresql-prep/bin/repmgrd-status-changes %n %e %s "%t" "%d"'
+
+ #Log level: possible values are DEBUG, INFO, NOTICE, WARNING, ERR, ALERT, CRIT or EMERG
+ loglevel=INFO
+ logfile='$LOGDIR/repmgr.log'
+EOF
+
diff --git a/postgresql-config/src/stage/opt/app/postgresql-config/etc/lock-and-create-db-backup b/postgresql-config/src/stage/opt/app/postgresql-config/etc/lock-and-create-db-backup
new file mode 100644
index 0000000..ff942e6
--- /dev/null
+++ b/postgresql-config/src/stage/opt/app/postgresql-config/etc/lock-and-create-db-backup
@@ -0,0 +1,33 @@
+#!/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 /opt/app/postgresql-9.5.2 ]
+then PGDIR=${INSTALL_ROOT}/opt/app/postgresql-9.5.2
+else PGDIR=/usr/lib/postgresql/9.5
+fi
+
+export PATH=$PGDIR/bin:${INSTALL_ROOT}/opt/java/jdk/jdk170/bin:${INSTALL_ROOT}/opt/app/cdf/bin:${INSTALL_ROOT}/opt/app/pgaas/bin:$PATH
+
+LOCKFILE=/var/lock/create-db-backup
+
+testlock -s -t 0 -r 99 ${LOCKFILE} create-db-backup
+retc=$?
+
+if [ $retc -eq 99 ]
+then
+ echo Backup is already being created
+fi
+exit $retc
+
diff --git a/postgresql-config/src/stage/opt/app/postgresql-config/etc/makecerts b/postgresql-config/src/stage/opt/app/postgresql-config/etc/makecerts
new file mode 100755
index 0000000..a272f7b
--- /dev/null
+++ b/postgresql-config/src/stage/opt/app/postgresql-config/etc/makecerts
@@ -0,0 +1,97 @@
+#!/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
+# makecerts - Create elf-signed certificates for PostgreSQL
+#
+# USAGE
+# makecerts [--force-overwrite]
+#
+# FILES
+# /opt/app/postgresql-config/etc
+# ssleay.cnf - template
+# /opt/app/postgresql-config/lib
+# ssl-cert-snakeoil.pem - public key
+# ssl-cert-snakeoil.key - private key
+
+die()
+{
+ echo $0: "$@" 1>&2
+ echo $0: "$@"
+ umask 022
+ echo $0: "$@" >> /tmp/pgaas-failures
+ exit 1
+}
+
+if [ -d ${INSTALL_ROOT}/opt/app/postgresql-config ]
+then dir=${INSTALL_ROOT}/opt/app/postgresql-config
+else dir=${INSTALL_ROOT}/opt/app/postgresql-config-9.5.2
+fi
+etcdir=$dir/etc
+libdir=$dir/lib
+template="$etcdir/ssleay.cnf"
+
+usage()
+{
+ exec 1>&2
+ echo "Usage: $0 [--force-overwrite]"
+ echo "Create self-signed certificates for $dir"
+ exit 1
+}
+
+if [ -f "$libdir/ssl-cert-snakeoil.pem" ] && [ -f "$libdir/ssl-cert-snakeoil.key" ]; then
+ if [ "$1" != "--force-overwrite" ]; then
+ exit 0
+ fi
+fi
+
+# make_snakeoil
+
+if ! HostName="$(hostname -f)" ; then
+ HostName="$(hostname)"
+ echo "$0: Could not get FQDN, using \"$HostName\"."
+ echo "$0: You may want to fix your /etc/hosts and/or DNS setup and run"
+ echo "$0: '$0 --force-overwrite'"
+ echo "$0: again."
+fi
+if [ ${#HostName} -gt 64 ] ; then
+ AltName="DNS:$HostName"
+ HostName="$(hostname)"
+fi
+
+
+TMPFILE="$(mktemp /tmp/tmp.mc1.XXXXXXXXXX)" || die mktemp failed
+TMPOUT="$(mktemp /tmp/tmp.mc2.XXXXXXXXXX)" || die mktemp failed
+
+trap "rm -f $TMPFILE $TMPOUT" EXIT 1 2 3 15
+
+# create_temporary_cnf
+ sed -e s#@HostName@#"$HostName"# $template > $TMPFILE
+ [ -z "$AltName" ] || echo "subjectAltName=$AltName" >> $TMPFILE
+
+# create the certificate.
+
+if ! openssl req -config $TMPFILE -new -x509 -days 3650 -nodes \
+ -out $libdir/ssl-cert-snakeoil.pem \
+ -keyout $libdir/ssl-cert-snakeoil.key > $TMPOUT 2>&1
+then
+ echo Could not create certificate. Openssl output was: >&2
+ cat $TMPOUT >&2
+ die openssl failed
+fi
+chmod 644 $libdir/ssl-cert-snakeoil.pem
+chmod 600 $libdir/ssl-cert-snakeoil.key
+# hash symlink
+ln -sf ssl-cert-snakeoil.pem $libdir/$(openssl x509 -hash -noout -in $libdir/ssl-cert-snakeoil.pem)
diff --git a/postgresql-config/src/stage/opt/app/postgresql-config/etc/ssleay.cnf b/postgresql-config/src/stage/opt/app/postgresql-config/etc/ssleay.cnf
new file mode 100644
index 0000000..2b665cc
--- /dev/null
+++ b/postgresql-config/src/stage/opt/app/postgresql-config/etc/ssleay.cnf
@@ -0,0 +1,33 @@
+# 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.
+
+#
+# SSLeay example configuration file.
+#
+
+RANDFILE = /dev/urandom
+
+[ req ]
+default_bits = 2048
+default_keyfile = privkey.pem
+distinguished_name = req_distinguished_name
+prompt = no
+policy = policy_anything
+req_extensions = v3_req
+x509_extensions = v3_req
+
+[ req_distinguished_name ]
+commonName = @HostName@
+
+[ v3_req ]
+basicConstraints = CA:FALSE
diff --git a/postgresql-config/src/stage/opt/app/postgresql-config/etc/start-db b/postgresql-config/src/stage/opt/app/postgresql-config/etc/start-db
new file mode 100644
index 0000000..2d50b40
--- /dev/null
+++ b/postgresql-config/src/stage/opt/app/postgresql-config/etc/start-db
@@ -0,0 +1,32 @@
+#!/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.
+
+
+set -x
+
+die()
+{
+ echo $0: "$@" 1>&2
+ echo $0: "$@"
+ umask 022
+ echo $0: "$@" >> /tmp/pgaas-failures
+ exit 1
+}
+
+[ -n "$PGDIR" ] || die "PGDIR is not set"
+[ -n "$DBROOT" ] || die "DBROOT is not set"
+[ -n "$CFGDIR" ] || die "CFGDIR is not set"
+
+rm -f $DBROOT/postmaster.pid
+$PGDIR/bin/pg_ctl start -D $DBROOT -o "-c config_file=$CFGDIR/main/postgresql.conf"
diff --git a/postgresql-config/src/stage/opt/app/postgresql-config/etc/update-db-master b/postgresql-config/src/stage/opt/app/postgresql-config/etc/update-db-master
new file mode 100644
index 0000000..0c0c238
--- /dev/null
+++ b/postgresql-config/src/stage/opt/app/postgresql-config/etc/update-db-master
@@ -0,0 +1,63 @@
+#!/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.
+
+
+# update a master database
+set -x
+
+die()
+{
+ echo $0: "$@" 1>&2
+ echo $0: "$@"
+ umask 022
+ echo $0: "$@" >> /tmp/pgaas-failures
+ exit 1
+}
+
+[ -n "$PGDIR" ] || die "PGDIR is not set"
+[ -n "$DBROOT" ] || die "DBROOT is not set"
+[ -n "$CFGDIR" ] || die "CFGDIR is not set"
+
+cd $CFGDIR/main || die "Cannot cd $CFGDIR/main"
+
+PATH=${INSTALL_ROOT}/opt/app/postgresql-prep/bin:$CFGDIR/etc:$PGDIR/bin:$PATH
+
+# update postgresql.conf - got new ones
+# update pg_hba.conf - got new ones
+# set up repmgr.conf - in common
+
+# start the DB
+start-db
+sleep 10
+
+# make sure the postgres password is right
+$CFGDIR/etc/update-postgres-user
+
+# create temporal tables and other extensions, if needed
+$CFGDIR/etc/create-extensions
+
+# create repmgr user/db, if needed
+$CFGDIR/etc/create-repmgr-user
+
+# register as master
+repmgr -f $CFGDIR/main/repmgr.conf master register
+echo repmgr ret=$?
+
+# start repmgrd
+# start repmgrd (verbose logging for testing)
+umask 07
+repmgrd -f $CFGDIR/main/repmgr.conf -d --verbose
+echo repmgrd ret=$?
+# start repmgrd (normal logging)
+# repmgrd -f $CFGDIR/main/repmgr.conf -d
diff --git a/postgresql-config/src/stage/opt/app/postgresql-config/etc/update-db-secondary b/postgresql-config/src/stage/opt/app/postgresql-config/etc/update-db-secondary
new file mode 100644
index 0000000..b819865
--- /dev/null
+++ b/postgresql-config/src/stage/opt/app/postgresql-config/etc/update-db-secondary
@@ -0,0 +1,95 @@
+#!/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.
+
+
+# update a secondary database
+set -x
+
+die()
+{
+ echo $0: "$@" 1>&2
+ echo $0: "$@"
+ umask 022
+ echo $0: "$@" >> /tmp/pgaas-failures
+ exit 1
+}
+
+[ -n "$MASTER" ] || die "MASTER is not set"
+[ -n "$PGDIR" ] || die "PGDIR is not set"
+[ -n "$DBROOT" ] || die "DBROOT is not set"
+[ -n "$CFGDIR" ] || die "CFGDIR is not set"
+
+cd $CFGDIR/main || die "Cannot cd $CFGDIR/main"
+
+PATH=${INSTALL_ROOT}/opt/app/postgresql-prep/bin:$CFGDIR/etc:$PGDIR/bin:$PATH
+
+umask 077
+TMP=$(mktemp /tmp/tmp.uds1.XXXXXXXXXX)
+trap 'rm -f $TMP' 0 1 2 3 15
+
+# update postgresql.conf - got new ones
+# update pg_hba.conf - got new ones
+# set up repmgr.conf - in common
+
+# replace/update recovery.conf
+if [ -f $DBROOT/recovery.conf ];then mv $DBROOT/recovery.conf $DBROOT/recovery.conf.upgraded;fi
+$CFGDIR/etc/gen-recovery.conf
+
+# wait until master DB is active and has repmgr available
+max=40
+for s in `seq $max`
+do
+ echo "$s of $max: Asking master $MASTER if repmgr is ready"
+ pgwget --progress=dot:giga -O$TMP http://$MASTER:8000/hasrepmgr
+ if [ -s $TMP ]
+ then
+ msg=$(cat $TMP)
+ case $msg in
+ OK* )
+ echo "Master has repmgr ready"
+ done=yes
+ break
+ ;;
+ * )
+ echo "Master does not have repmgr ready, msg=$msg"
+ ;;
+ esac
+ fi
+ rm -f $TMP
+ sleep 15
+done
+[ "$done" = "yes" ] || die "Master never had repmgr available"
+
+
+$CFGDIR/etc/start-db
+
+sleep 10
+
+# make sure the postgres password is right
+$CFGDIR/etc/update-postgres-user
+
+# register as standby
+repmgr -f $CFGDIR/main/repmgr.conf standby register
+echo repmgr ret=$?
+sleep 10
+
+# start repmgrd
+# start repmgrd (verbose logging for testing)
+umask 07
+repmgrd -f $CFGDIR/main/repmgr.conf -d --verbose
+echo repmgrd ret=$?
+# start repmgrd (normal logging)
+# repmgrd -f $CFGDIR/main/repmgr.conf -d
+
+chmod 600 recovery.conf
diff --git a/postgresql-config/src/stage/opt/app/postgresql-config/etc/update-postgres-user b/postgresql-config/src/stage/opt/app/postgresql-config/etc/update-postgres-user
new file mode 100644
index 0000000..b7f3762
--- /dev/null
+++ b/postgresql-config/src/stage/opt/app/postgresql-config/etc/update-postgres-user
@@ -0,0 +1,34 @@
+#!/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.
+
+
+set -x
+
+die()
+{
+ echo $0: "$@" 1>&2
+ echo $0: "$@"
+ umask 022
+ echo $0: "$@" >> /tmp/pgaas-failures
+ exit 1
+}
+
+[ -n "$PGDIR" ] || die "PGDIR is not set"
+
+PATH=${INSTALL_ROOT}/opt/app/postgresql-prep/bin:$PGDIR/bin:$PATH
+pswd=$( ${INSTALL_ROOT}/opt/app/cdf/bin/getpropvalue -x -n postgres )
+
+psql <<-EOF
+ ALTER USER postgres PASSWORD '$pswd';
+ EOF
diff --git a/postgresql-config/src/stage/opt/app/postgresql-config/lib/profile.additions b/postgresql-config/src/stage/opt/app/postgresql-config/lib/profile.additions
new file mode 100644
index 0000000..3ee8128
--- /dev/null
+++ b/postgresql-config/src/stage/opt/app/postgresql-config/lib/profile.additions
@@ -0,0 +1,6 @@
+
+if [ -d /opt/app/postgresql-9.5.2 ]
+then PGDIR=/opt/app/postgresql-9.5.2
+else PGDIR=/usr/lib/postgresql/9.5
+fi
+export PATH="$PGDIR/bin:/opt/app/cdf/bin:/opt/app/pgaas/bin:/opt/app/postgresql-prep/bin:$PATH"
diff --git a/postgresql-config/src/stage/opt/app/postgresql-config/main/pg_hba.conf.orig b/postgresql-config/src/stage/opt/app/postgresql-config/main/pg_hba.conf.orig
new file mode 100644
index 0000000..7bf51c1
--- /dev/null
+++ b/postgresql-config/src/stage/opt/app/postgresql-config/main/pg_hba.conf.orig
@@ -0,0 +1,127 @@
+# PostgreSQL Client Authentication Configuration File
+# ===================================================
+#
+# Refer to the "Client Authentication" section in the PostgreSQL
+# documentation for a complete description of this file. A short
+# synopsis follows.
+#
+# This file controls: which hosts are allowed to connect, how clients
+# are authenticated, which PostgreSQL user names they can use, which
+# databases they can access. Records take one of these forms:
+#
+# local DATABASE USER METHOD [OPTIONS]
+# host DATABASE USER ADDRESS METHOD [OPTIONS]
+# hostssl DATABASE USER ADDRESS METHOD [OPTIONS]
+# hostnossl DATABASE USER ADDRESS METHOD [OPTIONS]
+#
+# (The uppercase items must be replaced by actual values.)
+#
+# The first field is the connection type: "local" is a Unix-domain
+# socket, "host" is either a plain or SSL-encrypted TCP/IP socket,
+# "hostssl" is an SSL-encrypted TCP/IP socket, and "hostnossl" is a
+# plain TCP/IP socket.
+#
+# DATABASE can be "all", "sameuser", "samerole", "replication", a
+# database name, or a comma-separated list thereof. The "all"
+# keyword does not match "replication". Access to replication
+# must be enabled in a separate record (see example below).
+#
+# USER can be "all", a user name, a group name prefixed with "+", or a
+# comma-separated list thereof. In both the DATABASE and USER fields
+# you can also write a file name prefixed with "@" to include names
+# from a separate file.
+#
+# ADDRESS specifies the set of hosts the record matches. It can be a
+# host name, or it is made up of an IP address and a CIDR mask that is
+# an integer (between 0 and 32 (IPv4) or 128 (IPv6) inclusive) that
+# specifies the number of significant bits in the mask. A host name
+# that starts with a dot (.) matches a suffix of the actual host name.
+# Alternatively, you can write an IP address and netmask in separate
+# columns to specify the set of hosts. Instead of a CIDR-address, you
+# can write "samehost" to match any of the server's own IP addresses,
+# or "samenet" to match any address in any subnet that the server is
+# directly connected to.
+#
+# METHOD can be "trust", "reject", "md5", "password", "gss", "sspi",
+# "ident", "peer", "pam", "ldap", "radius" or "cert". Note that
+# "password" sends passwords in clear text; "md5" is preferred since
+# it sends encrypted passwords.
+#
+# OPTIONS are a set of options for the authentication in the format
+# NAME=VALUE. The available options depend on the different
+# authentication methods -- refer to the "Client Authentication"
+# section in the documentation for a list of which options are
+# available for which authentication methods.
+#
+# Database and user names containing spaces, commas, quotes and other
+# special characters must be quoted. Quoting one of the keywords
+# "all", "sameuser", "samerole" or "replication" makes the name lose
+# its special character, and just match a database or username with
+# that name.
+#
+# This file is read on server startup and when the postmaster receives
+# a SIGHUP signal. If you edit the file on a running system, you have
+# to SIGHUP the postmaster for the changes to take effect. You can
+# use "pg_ctl reload" to do that.
+
+# Put your actual configuration here
+# ----------------------------------
+#
+# If you want to allow non-local connections, you need to add more
+# "host" records. In that case you will also need to make PostgreSQL
+# listen on a non-local interface via the listen_addresses
+# configuration parameter, or via the -i or -h command line switches.
+
+### @authcomment@
+###
+### # TYPE DATABASE USER ADDRESS METHOD
+###
+### @remove-line-for-nolocal@# "local" is for Unix domain socket connections only
+### @remove-line-for-nolocal@local all all @authmethodlocal@
+### # IPv4 local connections:
+### host all all 127.0.0.1/32 @authmethodhost@
+### # IPv6 local connections:
+### host all all ::1/128 @authmethodhost@
+### # Allow replication connections from localhost, by a user with the
+### # replication privilege.
+### @remove-line-for-nolocal@#local replication @default_username@ @authmethodlocal@
+### #host replication @default_username@ 127.0.0.1/32 @authmethodhost@
+### #host replication @default_username@ ::1/128 @authmethodhost@
+
+# DO NOT DISABLE!
+# If you change this first entry you will need to make sure that the
+# database superuser can access the database using some other method.
+# Noninteractive access to all databases is required during automatic
+# maintenance (custom daily cronjobs, replication, and similar tasks).
+#
+# Database administrative login by Unix domain socket
+local all postgres peer
+
+# TYPE DATABASE USER ADDRESS METHOD
+
+# DCAE IPv4/IPv6 remote connections:
+host all all 0.0.0.0/0 md5
+host all all ::/0 md5
+
+# "local" is for Unix domain socket connections only
+local all all peer
+# IPv4 local connections:
+host all all 127.0.0.1/32 md5
+# IPv6 local connections:
+host all all ::1/128 md5
+# Allow replication connections from localhost, by a user with the
+# replication privilege.
+# local replication postgres peer
+# host replication postgres 127.0.0.1/32 md5
+# host replication postgres 0.0.0.0/0 md5
+# host replication postgres ::1/128 md5
+
+local replication repmgr md5
+host replication repmgr 127.0.0.1/32 md5
+host replication repmgr 0.0.0.0/0 md5
+host replication repmgr ::1/128 md5
+
+local repmgr repmgr md5
+host repmgr repmgr 127.0.0.1/32 md5
+host repmgr repmgr 0.0.0.0/0 md5
+host repmgr repmgr ::1/128 md5
diff --git a/postgresql-config/src/stage/opt/app/postgresql-config/main/pg_ident.conf b/postgresql-config/src/stage/opt/app/postgresql-config/main/pg_ident.conf
new file mode 100644
index 0000000..a5870e6
--- /dev/null
+++ b/postgresql-config/src/stage/opt/app/postgresql-config/main/pg_ident.conf
@@ -0,0 +1,42 @@
+# PostgreSQL User Name Maps
+# =========================
+#
+# Refer to the PostgreSQL documentation, chapter "Client
+# Authentication" for a complete description. A short synopsis
+# follows.
+#
+# This file controls PostgreSQL user name mapping. It maps external
+# user names to their corresponding PostgreSQL user names. Records
+# are of the form:
+#
+# MAPNAME SYSTEM-USERNAME PG-USERNAME
+#
+# (The uppercase quantities must be replaced by actual values.)
+#
+# MAPNAME is the (otherwise freely chosen) map name that was used in
+# pg_hba.conf. SYSTEM-USERNAME is the detected user name of the
+# client. PG-USERNAME is the requested PostgreSQL user name. The
+# existence of a record specifies that SYSTEM-USERNAME may connect as
+# PG-USERNAME.
+#
+# If SYSTEM-USERNAME starts with a slash (/), it will be treated as a
+# regular expression. Optionally this can contain a capture (a
+# parenthesized subexpression). The substring matching the capture
+# will be substituted for \1 (backslash-one) if present in
+# PG-USERNAME.
+#
+# Multiple maps may be specified in this file and used by pg_hba.conf.
+#
+# No map names are defined in the default configuration. If all
+# system user names and PostgreSQL user names are the same, you don't
+# need anything in this file.
+#
+# This file is read on server startup and when the postmaster receives
+# a SIGHUP signal. If you edit the file on a running system, you have
+# to SIGHUP the postmaster for the changes to take effect. You can
+# use "pg_ctl reload" to do that.
+
+# Put your actual configuration here
+# ----------------------------------
+
+# MAPNAME SYSTEM-USERNAME PG-USERNAME
diff --git a/postgresql-config/src/stage/opt/app/postgresql-config/main/postgresql.conf.orig b/postgresql-config/src/stage/opt/app/postgresql-config/main/postgresql.conf.orig
new file mode 100644
index 0000000..b2587db
--- /dev/null
+++ b/postgresql-config/src/stage/opt/app/postgresql-config/main/postgresql.conf.orig
@@ -0,0 +1,655 @@
+# -----------------------------
+# PostgreSQL configuration file
+# -----------------------------
+#
+# This file consists of lines of the form:
+#
+# name = value
+#
+# (The "=" is optional.) Whitespace may be used. Comments are introduced with
+# "#" anywhere on a line. The complete list of parameter names and allowed
+# values can be found in the PostgreSQL documentation.
+#
+# The commented-out settings shown in this file represent the default values.
+# Re-commenting a setting is NOT sufficient to revert it to the default value;
+# you need to reload the server.
+#
+# This file is read on server startup and when the server receives a SIGHUP
+# signal. If you edit the file on a running system, you have to SIGHUP the
+# server for the changes to take effect, or use "pg_ctl reload". Some
+# parameters, which are marked below, require a server shutdown and restart to
+# take effect.
+#
+# Any parameter can also be given as a command-line option to the server, e.g.,
+# "postgres -c log_connections=on". Some parameters can be changed at run time
+# with the "SET" SQL command.
+#
+# Memory units: kB = kilobytes Time units: ms = milliseconds
+# MB = megabytes s = seconds
+# GB = gigabytes min = minutes
+# TB = terabytes h = hours
+# d = days
+
+
+#------------------------------------------------------------------------------
+# FILE LOCATIONS
+#------------------------------------------------------------------------------
+
+# The default values of these variables are driven from the -D command-line
+# option or PGDATA environment variable, represented here as ConfigDir.
+
+data_directory = '/dbroot/pgdata/main' # for DCAE
+#data_directory = 'ConfigDir' # use data in another directory
+ # (change requires restart)
+hba_file = '%CFGDIR%/main/pg_hba.conf' # for DCAE
+#hba_file = 'ConfigDir/pg_hba.conf' # host-based authentication file
+ # (change requires restart)
+ident_file = '%CFGDIR%/main/pg_ident.conf' # for DCAE
+#ident_file = 'ConfigDir/pg_ident.conf' # ident configuration file
+ # (change requires restart)
+
+# If external_pid_file is not explicitly set, no extra PID file is written.
+external_pid_file = '/var/run/postgresql/9.5-main.pid' # for DCAE
+#external_pid_file = '' # write an extra PID file
+ # (change requires restart)
+
+
+#------------------------------------------------------------------------------
+# CONNECTIONS AND AUTHENTICATION
+#------------------------------------------------------------------------------
+
+# - Connection Settings -
+
+# DCAE -- for 1607 IST30, set to '*' to allow remote connections
+listen_addresses = '*' # for DCAE
+
+#listen_addresses = 'localhost' # what IP address(es) to listen on;
+ # comma-separated list of addresses;
+ # defaults to 'localhost'; use '*' for all
+ # (change requires restart)
+#port = 5432 # (change requires restart)
+#max_connections = 100 # (change requires restart)
+# Note: Increasing max_connections costs ~400 bytes of shared memory per
+# connection slot, plus lock space (see max_locks_per_transaction).
+#superuser_reserved_connections = 3 # (change requires restart)
+unix_socket_directories = '/var/run/postgresql,/tmp' # for DCAE
+#unix_socket_directories = '/tmp' # comma-separated list of directories
+ # (change requires restart)
+#unix_socket_group = '' # (change requires restart)
+#unix_socket_permissions = 0777 # begin with 0 to use octal notation
+ # (change requires restart)
+#bonjour = off # advertise server via Bonjour
+ # (change requires restart)
+#bonjour_name = '' # defaults to the computer name
+ # (change requires restart)
+
+# - Security and Authentication -
+
+#authentication_timeout = 1min # 1s-600s
+ssl = true # for DCAE
+#ssl = off # (change requires restart)
+#ssl_ciphers = 'HIGH:MEDIUM:+3DES:!aNULL' # allowed SSL ciphers
+ # (change requires restart)
+#ssl_prefer_server_ciphers = on # (change requires restart)
+#ssl_ecdh_curve = 'prime256v1' # (change requires restart)
+ssl_cert_file = '%CFGDIR%/lib/ssl-cert-snakeoil.pem' # for DCAE
+#ssl_cert_file = 'server.crt' # (change requires restart)
+ssl_key_file = '%CFGDIR%/lib/ssl-cert-snakeoil.key' # for DCAE
+#ssl_key_file = 'server.key' # (change requires restart)
+#ssl_ca_file = '' # (change requires restart)
+#ssl_crl_file = '' # (change requires restart)
+#password_encryption = on
+#db_user_namespace = off
+#row_security = on
+
+# GSSAPI using Kerberos
+#krb_server_keyfile = ''
+#krb_caseins_users = off
+
+# - TCP Keepalives -
+# see "man 7 tcp" for details
+
+#tcp_keepalives_idle = 0 # TCP_KEEPIDLE, in seconds;
+ # 0 selects the system default
+#tcp_keepalives_interval = 0 # TCP_KEEPINTVL, in seconds;
+ # 0 selects the system default
+#tcp_keepalives_count = 0 # TCP_KEEPCNT;
+ # 0 selects the system default
+
+
+#------------------------------------------------------------------------------
+# RESOURCE USAGE (except WAL)
+#------------------------------------------------------------------------------
+
+# - Memory -
+
+#shared_buffers = 32MB # min 128kB
+ # (change requires restart)
+#huge_pages = try # on, off, or try
+ # (change requires restart)
+#temp_buffers = 8MB # min 800kB
+#max_prepared_transactions = 0 # zero disables the feature
+ # (change requires restart)
+# Note: Increasing max_prepared_transactions costs ~600 bytes of shared memory
+# per transaction slot, plus lock space (see max_locks_per_transaction).
+# It is not advisable to set max_prepared_transactions nonzero unless you
+# actively intend to use prepared transactions.
+#work_mem = 4MB # min 64kB
+#maintenance_work_mem = 64MB # min 1MB
+#autovacuum_work_mem = -1 # min 1MB, or -1 to use maintenance_work_mem
+#max_stack_depth = 2MB # min 100kB
+#dynamic_shared_memory_type = posix # the default is the first option
+ # supported by the operating system:
+ # posix
+ # sysv
+ # windows
+ # mmap
+ # use none to disable dynamic shared memory
+
+# - Disk -
+
+#temp_file_limit = -1 # limits per-session temp file space
+ # in kB, or -1 for no limit
+
+# - Kernel Resource Usage -
+
+#max_files_per_process = 1000 # min 25
+ # (change requires restart)
+#shared_preload_libraries = '' # (change requires restart)
+
+# - Cost-Based Vacuum Delay -
+
+#vacuum_cost_delay = 0 # 0-100 milliseconds
+#vacuum_cost_page_hit = 1 # 0-10000 credits
+#vacuum_cost_page_miss = 10 # 0-10000 credits
+#vacuum_cost_page_dirty = 20 # 0-10000 credits
+#vacuum_cost_limit = 200 # 1-10000 credits
+
+# - Background Writer -
+
+#bgwriter_delay = 200ms # 10-10000ms between rounds
+#bgwriter_lru_maxpages = 100 # 0-1000 max buffers written/round
+#bgwriter_lru_multiplier = 2.0 # 0-10.0 multipler on buffers scanned/round
+
+# - Asynchronous Behavior -
+
+#effective_io_concurrency = 1 # 1-1000; 0 disables prefetching
+#max_worker_processes = 8
+
+
+#------------------------------------------------------------------------------
+# WRITE AHEAD LOG
+#------------------------------------------------------------------------------
+
+# - Settings -
+
+# TLH - this is where we do WAL settings
+wal_level = hot_standby # minimal, archive, hot_standby, or logical
+ # (change requires restart)
+#fsync = on # turns forced synchronization on or off
+#synchronous_commit = on # synchronization level;
+ # off, local, remote_write, or on
+#wal_sync_method = fsync # the default is the first option
+ # supported by the operating system:
+ # open_datasync
+ # fdatasync (default on Linux)
+ # fsync
+ # fsync_writethrough
+ # open_sync
+#full_page_writes = on # recover from partial page writes
+#wal_compression = off # enable compression of full-page writes
+wal_log_hints = on # also do full page writes of non-critical updates
+ # (change requires restart)
+#wal_buffers = -1 # min 32kB, -1 sets based on shared_buffers
+ # (change requires restart)
+#wal_writer_delay = 200ms # 1-10000 milliseconds
+
+#commit_delay = 0 # range 0-100000, in microseconds
+#commit_siblings = 5 # range 1-1000
+
+# - Checkpoints -
+
+#checkpoint_timeout = 5min # range 30s-1h
+#max_wal_size = 1GB
+#min_wal_size = 80MB
+#checkpoint_completion_target = 0.5 # checkpoint target duration, 0.0 - 1.0
+#checkpoint_warning = 30s # 0 disables
+
+# - Archiving -
+
+archive_mode = on # enables archiving; off, on, or always
+ # (change requires restart)
+archive_command = 'test ! -f /dbroot/pglogs/main/%f && cp %p /dbroot/pglogs/main/%f'
+ # command to use to archive a logfile segment
+ # placeholders: %p = path of file to archive
+ # %f = file name only
+ # e.g. 'test ! -f /mnt/server/archivedir/%f && cp %p /mnt/server/archivedir/%f'
+archive_timeout = 0 # force a logfile segment switch after this
+ # number of seconds; 0 disables
+
+
+#------------------------------------------------------------------------------
+# REPLICATION
+#------------------------------------------------------------------------------
+
+# - Sending Server(s) -
+
+# Set these on the master and on any standby that will send replication data.
+
+max_wal_senders = 4 # max number of walsender processes
+ # (change requires restart)
+#wal_keep_segments = 0 # in logfile segments, 16MB each; 0 disables
+#wal_sender_timeout = 60s # in milliseconds; 0 disables
+
+max_replication_slots = 5 # max number of replication slots
+ # (change requires restart)
+ # DCAE NOTE: if we ever grow our cluster, change this value to
+ # the number of nodes + 1
+#track_commit_timestamp = off # collect timestamp of transaction commit
+ # (change requires restart)
+
+# - Master Server -
+
+# These settings are ignored on a standby server.
+
+#synchronous_standby_names = '' # standby servers that provide sync rep
+ # comma-separated list of application_name
+ # from standby(s); '*' = all
+#vacuum_defer_cleanup_age = 0 # number of xacts by which cleanup is delayed
+
+# - Standby Servers -
+
+# These settings are ignored on a master server.
+
+hot_standby = on # "on" allows queries during recovery
+ # (change requires restart)
+#max_standby_archive_delay = 30s # max delay before canceling queries
+ # when reading WAL from archive;
+ # -1 allows indefinite delay
+#max_standby_streaming_delay = 30s # max delay before canceling queries
+ # when reading streaming WAL;
+ # -1 allows indefinite delay
+#wal_receiver_status_interval = 10s # send replies at least this often
+ # 0 disables
+#hot_standby_feedback = off # send info from standby to prevent
+ # query conflicts
+#wal_receiver_timeout = 60s # time that receiver waits for
+ # communication from master
+ # in milliseconds; 0 disables
+#wal_retrieve_retry_interval = 5s # time to wait before retrying to
+ # retrieve WAL after a failed attempt
+
+
+#------------------------------------------------------------------------------
+# QUERY TUNING
+#------------------------------------------------------------------------------
+
+# - Planner Method Configuration -
+
+#enable_bitmapscan = on
+#enable_hashagg = on
+#enable_hashjoin = on
+#enable_indexscan = on
+#enable_indexonlyscan = on
+#enable_material = on
+#enable_mergejoin = on
+#enable_nestloop = on
+#enable_seqscan = on
+#enable_sort = on
+#enable_tidscan = on
+
+# - Planner Cost Constants -
+
+#seq_page_cost = 1.0 # measured on an arbitrary scale
+#random_page_cost = 4.0 # same scale as above
+#cpu_tuple_cost = 0.01 # same scale as above
+#cpu_index_tuple_cost = 0.005 # same scale as above
+#cpu_operator_cost = 0.0025 # same scale as above
+#effective_cache_size = 4GB
+
+# - Genetic Query Optimizer -
+
+#geqo = on
+#geqo_threshold = 12
+#geqo_effort = 5 # range 1-10
+#geqo_pool_size = 0 # selects default based on effort
+#geqo_generations = 0 # selects default based on effort
+#geqo_selection_bias = 2.0 # range 1.5-2.0
+#geqo_seed = 0.0 # range 0.0-1.0
+
+# - Other Planner Options -
+
+#default_statistics_target = 100 # range 1-10000
+#constraint_exclusion = partition # on, off, or partition
+#cursor_tuple_fraction = 0.1 # range 0.0-1.0
+#from_collapse_limit = 8
+#join_collapse_limit = 8 # 1 disables collapsing of explicit
+ # JOIN clauses
+
+
+#------------------------------------------------------------------------------
+# ERROR REPORTING AND LOGGING
+#------------------------------------------------------------------------------
+
+# - Where to Log -
+
+#log_destination = 'stderr' # Valid values are combinations of
+ # stderr, csvlog, syslog, and eventlog,
+ # depending on platform. csvlog
+ # requires logging_collector to be on.
+
+# This is used when logging to stderr:
+logging_collector = on # for DCAE
+#logging_collector = off # Enable capturing of stderr and csvlog
+ # into log files. Required to be on for
+ # csvlogs.
+ # (change requires restart)
+
+# These are only used if logging_collector is on:
+log_directory = '/opt/app/log/postgresql/server' # for DCAE
+#log_directory = 'pg_log' # directory where log files are written,
+ # can be absolute or relative to PGDATA
+log_filename = 'error.log' # for DCAE
+#log_filename = 'postgresql-%Y-%m-%d_%H%M%S.log' # log file name pattern,
+ # can include strftime() escapes
+log_file_mode = 0666 # for DCAE
+#log_file_mode = 0600 # creation mode for log files,
+ # begin with 0 to use octal notation
+#log_truncate_on_rotation = off # If on, an existing log file with the
+ # same name as the new log file will be
+ # truncated rather than appended to.
+ # But such truncation only occurs on
+ # time-driven rotation, not on restarts
+ # or size-driven rotation. Default is
+ # off, meaning append to existing files
+ # in all cases.
+log_rotation_age = 1d # for DCAE
+#log_rotation_age = 1d # Automatic rotation of logfiles will
+ # happen after that time. 0 disables.
+log_rotation_size = 0 # for DCAE
+#log_rotation_size = 10MB # Automatic rotation of logfiles will
+ # happen after that much log output.
+ # 0 disables.
+
+# These are relevant when logging to syslog:
+#syslog_facility = 'LOCAL0'
+#syslog_ident = 'postgres'
+
+# This is only relevant when logging to eventlog (win32):
+#event_source = 'PostgreSQL'
+
+# - When to Log -
+
+#client_min_messages = notice # values in order of decreasing detail:
+ # debug5
+ # debug4
+ # debug3
+ # debug2
+ # debug1
+ # log
+ # notice
+ # warning
+ # error
+
+#log_min_messages = warning # values in order of decreasing detail:
+ # debug5
+ # debug4
+ # debug3
+ # debug2
+ # debug1
+ # info
+ # notice
+ # warning
+ # error
+ # log
+ # fatal
+ # panic
+
+#log_min_error_statement = error # values in order of decreasing detail:
+ # debug5
+ # debug4
+ # debug3
+ # debug2
+ # debug1
+ # info
+ # notice
+ # warning
+ # error
+ # log
+ # fatal
+ # panic (effectively off)
+
+#log_min_duration_statement = -1 # -1 is disabled, 0 logs all statements
+ # and their durations, > 0 logs only
+ # statements running at least this number
+ # of milliseconds
+
+
+# - What to Log -
+
+#debug_print_parse = off
+#debug_print_rewritten = off
+#debug_print_plan = off
+#debug_pretty_print = on
+#log_checkpoints = off
+#log_connections = off
+#log_disconnections = off
+#log_duration = off
+#log_error_verbosity = default # terse, default, or verbose messages
+#log_hostname = off
+log_line_prefix = '%t|%a|%u|%d|%i|%e|%r|%c|' # for DCAE
+#log_line_prefix = '' # special values:
+ # %a = application name
+ # %u = user name
+ # %d = database name
+ # %r = remote host and port
+ # %h = remote host
+ # %p = process ID
+ # %t = timestamp without milliseconds
+ # %m = timestamp with milliseconds
+ # %i = command tag
+ # %e = SQL state
+ # %c = session ID
+ # %l = session line number
+ # %s = session start timestamp
+ # %v = virtual transaction ID
+ # %x = transaction ID (0 if none)
+ # %q = stop here in non-session
+ # processes
+ # %% = '%'
+ # e.g. '<%u%%%d> '
+#log_lock_waits = off # log lock waits >= deadlock_timeout
+#log_statement = 'none' # none, ddl, mod, all
+#log_replication_commands = off
+#log_temp_files = -1 # log temporary files equal or larger
+ # than the specified size in kilobytes;
+ # -1 disables, 0 logs all temp files
+#log_timezone = 'GMT'
+
+
+# - Process Title -
+
+#cluster_name = '' # added to process titles if nonempty
+ # (change requires restart)
+#update_process_title = on
+
+
+#------------------------------------------------------------------------------
+# RUNTIME STATISTICS
+#------------------------------------------------------------------------------
+
+# - Query/Index Statistics Collector -
+
+#track_activities = on
+#track_counts = on
+#track_io_timing = off
+#track_functions = none # none, pl, all
+#track_activity_query_size = 1024 # (change requires restart)
+#stats_temp_directory = 'pg_stat_tmp'
+
+
+# - Statistics Monitoring -
+
+#log_parser_stats = off
+#log_planner_stats = off
+#log_executor_stats = off
+#log_statement_stats = off
+
+
+#------------------------------------------------------------------------------
+# AUTOVACUUM PARAMETERS
+#------------------------------------------------------------------------------
+
+#autovacuum = on # Enable autovacuum subprocess? 'on'
+ # requires track_counts to also be on.
+#log_autovacuum_min_duration = -1 # -1 disables, 0 logs all actions and
+ # their durations, > 0 logs only
+ # actions running at least this number
+ # of milliseconds.
+#autovacuum_max_workers = 3 # max number of autovacuum subprocesses
+ # (change requires restart)
+#autovacuum_naptime = 1min # time between autovacuum runs
+#autovacuum_vacuum_threshold = 50 # min number of row updates before
+ # vacuum
+#autovacuum_analyze_threshold = 50 # min number of row updates before
+ # analyze
+#autovacuum_vacuum_scale_factor = 0.2 # fraction of table size before vacuum
+#autovacuum_analyze_scale_factor = 0.1 # fraction of table size before analyze
+#autovacuum_freeze_max_age = 200000000 # maximum XID age before forced vacuum
+ # (change requires restart)
+#autovacuum_multixact_freeze_max_age = 400000000 # maximum multixact age
+ # before forced vacuum
+ # (change requires restart)
+#autovacuum_vacuum_cost_delay = 20ms # default vacuum cost delay for
+ # autovacuum, in milliseconds;
+ # -1 means use vacuum_cost_delay
+#autovacuum_vacuum_cost_limit = -1 # default vacuum cost limit for
+ # autovacuum, -1 means use
+ # vacuum_cost_limit
+
+
+#------------------------------------------------------------------------------
+# CLIENT CONNECTION DEFAULTS
+#------------------------------------------------------------------------------
+
+# - Statement Behavior -
+
+#search_path = '"$user", public' # schema names
+#default_tablespace = '' # a tablespace name, '' uses the default
+#temp_tablespaces = '' # a list of tablespace names, '' uses
+ # only default tablespace
+#check_function_bodies = on
+#default_transaction_isolation = 'read committed'
+#default_transaction_read_only = off
+#default_transaction_deferrable = off
+#session_replication_role = 'origin'
+#statement_timeout = 0 # in milliseconds, 0 is disabled
+#lock_timeout = 0 # in milliseconds, 0 is disabled
+#vacuum_freeze_min_age = 50000000
+#vacuum_freeze_table_age = 150000000
+#vacuum_multixact_freeze_min_age = 5000000
+#vacuum_multixact_freeze_table_age = 150000000
+#bytea_output = 'hex' # hex, escape
+#xmlbinary = 'base64'
+#xmloption = 'content'
+#gin_fuzzy_search_limit = 0
+#gin_pending_list_limit = 4MB
+
+# - Locale and Formatting -
+
+#datestyle = 'iso, mdy'
+#intervalstyle = 'postgres'
+#timezone = 'GMT'
+#timezone_abbreviations = 'Default' # Select the set of available time zone
+ # abbreviations. Currently, there are
+ # Default
+ # Australia (historical usage)
+ # India
+ # You can create your own file in
+ # share/timezonesets/.
+#extra_float_digits = 0 # min -15, max 3
+#client_encoding = sql_ascii # actually, defaults to database
+ # encoding
+
+# These settings are initialized by initdb, but they can be changed.
+#lc_messages = 'C' # locale for system error message
+ # strings
+#lc_monetary = 'C' # locale for monetary formatting
+#lc_numeric = 'C' # locale for number formatting
+#lc_time = 'C' # locale for time formatting
+
+# default configuration for text search
+#default_text_search_config = 'pg_catalog.simple'
+
+# - Other Defaults -
+
+#dynamic_library_path = '$libdir'
+#local_preload_libraries = ''
+#session_preload_libraries = ''
+
+
+#------------------------------------------------------------------------------
+# LOCK MANAGEMENT
+#------------------------------------------------------------------------------
+
+#deadlock_timeout = 1s
+#max_locks_per_transaction = 64 # min 10
+ # (change requires restart)
+# Note: Each lock table slot uses ~270 bytes of shared memory, and there are
+# max_locks_per_transaction * (max_connections + max_prepared_transactions)
+# lock table slots.
+#max_pred_locks_per_transaction = 64 # min 10
+ # (change requires restart)
+
+
+#------------------------------------------------------------------------------
+# VERSION/PLATFORM COMPATIBILITY
+#------------------------------------------------------------------------------
+
+# - Previous PostgreSQL Versions -
+
+#array_nulls = on
+#backslash_quote = safe_encoding # on, off, or safe_encoding
+#default_with_oids = off
+#escape_string_warning = on
+#lo_compat_privileges = off
+#operator_precedence_warning = off
+#quote_all_identifiers = off
+#sql_inheritance = on
+#standard_conforming_strings = on
+#synchronize_seqscans = on
+
+# - Other Platforms and Clients -
+
+#transform_null_equals = off
+
+
+#------------------------------------------------------------------------------
+# ERROR HANDLING
+#------------------------------------------------------------------------------
+
+#exit_on_error = off # terminate session on any error?
+#restart_after_crash = on # reinitialize after backend crash?
+
+
+#------------------------------------------------------------------------------
+# CONFIG FILE INCLUDES
+#------------------------------------------------------------------------------
+
+# These options allow settings to be loaded from files other than the
+# default postgresql.conf.
+
+#include_dir = 'conf.d' # include files ending in '.conf' from
+ # directory 'conf.d'
+#include_if_exists = 'exists.conf' # include file only if it exists
+#include = 'special.conf' # include file
+
+
+#------------------------------------------------------------------------------
+# CUSTOMIZED OPTIONS
+#------------------------------------------------------------------------------
+
+# Add settings for extensions here
+
+# repmgr / repmgrd
+shared_preload_libraries = 'repmgr_funcs'
diff --git a/postgresql-prep/.gitignore b/postgresql-prep/.gitignore
new file mode 100644
index 0000000..7c32f55
--- /dev/null
+++ b/postgresql-prep/.gitignore
@@ -0,0 +1 @@
+install
diff --git a/postgresql-prep/src/common/postinst b/postgresql-prep/src/common/postinst
new file mode 100755
index 0000000..63a76f2
--- /dev/null
+++ b/postgresql-prep/src/common/postinst
@@ -0,0 +1,177 @@
+#!/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/postgresql-prep.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
+
+echo STARTING $0 $(date)
+umask 0
+echo STARTING $0 $(date) >> /tmp/pgaas.inst.report
+
+die()
+{
+ echo $0: "$@" 1>&2
+ echo $0: "$@"
+ umask 022
+ echo $0: "$@" >> /tmp/pgaas-failures
+ exit 1
+}
+
+id
+umask 022
+
+TMP=$( mktemp /tmp/pgprep.$$.XXXXXXXXXX )
+#### TODO remove comment trap 'rm -f $TMP' 0 1 2 3 15
+
+if $OPENECOMP
+then INSTALL_ROOT=
+fi
+
+if [ -f /tmp/postgres.conf ]
+then
+ # DRTR_NODE_KSTOREFILE: /opt/app/dcae-certificate/keystore.jks
+ # DRTR_NODE_KSTOREPASS: "No Certificate"
+ # DRTR_NODE_PVTKEYPASS: "No Certificate"
+ # PG_NODES : uiopmno1qwpstg00.research.example.com|asbczw1vepstg00.dcae.simpledemo.openecomp.org
+ # PG_JAVA_HOME : /opt/app/java/jdk/jdk170
+ # PG_CLUSTER : global
+ sed -e 's/ *: */="/' -e 's/$/"/' -e 's/=""/="/' -e 's/""$/"/' < /tmp/postgres.conf > $TMP
+ . $TMP
+fi
+
+[ -n "$PG_NODES" ] || die "PG_NODES is not set"
+[ -n "$PG_CLUSTER" ] || die "PG_CLUSTER is not set"
+[ -n "$DRTR_NODE_KSTOREFILE" ] || die "DRTR_NODE_KSTOREFILE is not set"
+[ -n "$DRTR_NODE_KSTOREPASS" ] || die "DRTR_NODE_KSTOREPASS is not set"
+[ -n "$DRTR_NODE_PVTKEYPASS" ] || die "DRTR_NODE_PVTKEYPASS is not set"
+
+# create various directories with proper permissions
+mkdir -p ${INSTALL_ROOT}/dbroot/pgdata/main \
+ ${INSTALL_ROOT}/dbroot/pgdata/pgaas \
+ ${INSTALL_ROOT}/dbroot/pglogs/main \
+ ${INSTALL_ROOT}/var/run/postgresql \
+ ${INSTALL_ROOT}/opt/app/log/postgresql/init \
+ ${INSTALL_ROOT}/opt/app/log/postgresql/server \
+ ${INSTALL_ROOT}/opt/app/log/postgresql/idns
+chmod 700 ${INSTALL_ROOT}/dbroot/pgdata/pgaas
+chmod 700 ${INSTALL_ROOT}/dbroot/pglogs
+chmod 700 ${INSTALL_ROOT}/dbroot/pgdata/main
+
+if $OPENECOMP
+then
+ mv /var/lib/postgresql/9.5/main /var/lib/postgresql/9.5/main.sv
+ ln -s /dbroot/dbdata/main /var/lib/postgresql/9.5/main
+
+ mv /etc/postgresql/9.5/main /etc/postgresql/9.5/main.sv
+ ln -s /opt/app/postgresql-config/main /etc/postgresql/9.5/main
+
+fi
+
+chown -R postgres:postgres ${INSTALL_ROOT}/dbroot ${INSTALL_ROOT}/var/run/postgresql ${INSTALL_ROOT}/opt/app/log/postgresql ${INSTALL_ROOT}/opt/app/log/postgresql/idns
+
+chmod 711 ~postgres
+
+# fix up the CDF package so that it works
+ln -sf /opt/app/cdf /opt/cdf
+
+# and save some values within
+(
+ echo "allpgnodes=\"$PG_NODES\""
+ case "$PG_CLUSTER" in
+ global | central )
+ cnodes=$( ${INSTALL_ROOT}/opt/app/postgresql-prep/bin/gen-repmgr-info -n "$PG_NODES" -p )
+ echo "pgnodes=\"$cnodes\""
+ echo "cluster=central"
+ shanodes=$( ${INSTALL_ROOT}/opt/app/postgresql-prep/bin/gen-repmgr-info -n "$PG_NODES" -P )
+ ;;
+ site | edge )
+ HOSTNAME=$( hostname -f )
+ lnodes=$( ${INSTALL_ROOT}/opt/app/postgresql-prep/bin/gen-repmgr-info -n "$PG_NODES" -e $HOSTNAME )
+ echo "pgnodes=\"$lnodes\""
+ if [ -z "$lnodes" ]
+ then die "Cannot determine the name of the system. hostname -f ($HOSTNAME) is not found in PG_NODES ($PG_NODES)"
+ fi
+ shanodes=$( ${INSTALL_ROOT}/opt/app/postgresql-prep/bin/gen-repmgr-info -n "$PG_NODES" -E $HOSTNAME )
+ echo "cluster=edge"
+ ;;
+ * ) die "Cannot determine what type of cluster this is. PG_CLUSTER should be either 'global/central' or 'site/edge'" ;;
+ esac
+
+ echo "drtr_node_kstorefile=$DRTR_NODE_KSTOREFILE"
+ echo "ENCRYPTME.AES.drtr_node_kstorepass='$DRTR_NODE_KSTOREPASS'" | ${INSTALL_ROOT}/opt/app/cdf/bin/setencryptedvalues
+ echo "ENCRYPTME.AES.drtr_node_pvtkeypass='$DRTR_NODE_PVTKEYPASS'" | ${INSTALL_ROOT}/opt/app/cdf/bin/setencryptedvalues
+ echo "ENCRYPTME.AES.wgetpswd=$shanodes" | ${INSTALL_ROOT}/opt/app/cdf/bin/setencryptedvalues
+) >> ${INSTALL_ROOT}/opt/app/cdf/lib/cdf.cfg
+
+# install the init scripts for postgresql
+# init.d-pgaas init-pgaas-idns.conf init-pgaas-init.conf logrotate
+
+INIT=${INSTALL_ROOT}/opt/app/postgresql-prep/init
+
+if $OPENECOMP
+then
+ su postgres -c "crontab $INIT/pglogs.cron"
+
+ # no need to create the /var/run directory because postgresql package already does it
+
+ # install the init script for iDNS
+ cp $INIT/systemd-pgaas-idns.service /lib/systemd/system/pgaas-idns.service
+ systemctl stop pgaas-idns
+ sleep 1
+ systemctl start pgaas-idns
+
+else
+ INITDEST=${INSTALL_ROOT}/opt/app/platform/init.d/pgaas
+ cp $INIT/init.d-pgaas $INITDEST
+ chown postgres:postgres $INITDEST
+ chmod 755 $INITDEST
+
+ cd ${INSTALL_ROOT}/opt/app/platform/rc.d
+ ln -sf ../init.d/pgaas K20pgaas
+ ln -sf ../init.d/pgaas S20pgaas
+
+ CRONDIR=${INSTALL_ROOT}/opt/app/platform/cron/postgres
+ mkdir $CRONDIR
+ chown postgres:postgres $CRONDIR
+ chmod 755 $CRONDIR
+ cp $INIT/pglogs.cron $CRONDIR/pglogs.cron
+ su postgres -c "sh -x ${INSTALL_ROOT}/opt/app/platform/bin/mergeCron"
+
+ # install the init script for init
+ cp $INIT/init-pgaas-init.conf ${INSTALL_ROOT}/etc/init/pgaas-init.conf
+ service pgaas-init stop
+ sleep 1
+ service pgaas-init start
+
+ # install the init script for iDNS
+ cp $INIT/init-pgaas-idns.conf ${INSTALL_ROOT}/etc/init/pgaas-idns.conf
+ service pgaas-idns stop
+ sleep 1
+ service pgaas-idns start
+fi
+
+cp $INIT/logrotate ${INSTALL_ROOT}/etc/logrotate.d/pgaas
+chown root:root ${INSTALL_ROOT}/etc/logrotate.d/pgaas
+chmod 644 ${INSTALL_ROOT}/etc/logrotate.d/pgaas
+
+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/postgresql-prep/src/common/prerm b/postgresql-prep/src/common/prerm
new file mode 100755
index 0000000..a03a13b
--- /dev/null
+++ b/postgresql-prep/src/common/prerm
@@ -0,0 +1,17 @@
+echo STARTING $0 $(date)
+
+set -x
+id
+
+if [ -d /opt/app/postgresql-9.5.2 ]
+then
+ rm -f $INSTALL_ROOT/opt/app/platform/postgres/pglogs.cron
+ su postgres -c "$INSTALL_ROOT/opt/app/platform/bin/mergeCron"
+ rmdir $INSTALL_ROOT/opt/app/platform/postgres
+ rm -f $INSTALL_ROOT/opt/app/platform/init.d/pgaas
+ rm -f $INSTALL_ROOT/opt/app/platform/rc.d/K20pgaas
+ rm -f $INSTALL_ROOT/opt/app/platform/rc.d/S20pgaas
+fi
+
+rm -f $INSTALL_ROOT/etc/init/pgaas-idns.conf $INSTALL_ROOT/etc/init/pgaas-init.conf
+rm -f $INSTALL_ROOT/etc/logrotate.d/pgaas
diff --git a/postgresql-prep/src/makefile b/postgresql-prep/src/makefile
new file mode 100644
index 0000000..1266aa6
--- /dev/null
+++ b/postgresql-prep/src/makefile
@@ -0,0 +1,43 @@
+
+DEVBIN=../../bin
+PKG=postgresql-prep
+REPACKAGESWMOPTS=
+REPACKAGEDEBIANOPTS=
+
+INS= ../install
+INSSTG= $(INS)/stage
+INSCOM= $(INS)/common
+
+all:
+
+clean-stage:
+ rm -rf $(INSSTG)
+
+clean-common:
+ rm -rf $(INSCOM)
+
+clean:
+ rm -rf $(INS) testlock/testlock
+
+testlock/testlock:
+ cd testlock && make testlock
+
+build: testlock/testlock
+
+stage: clean-stage clean-common testlock/testlock
+ mkdir -p $(INS)
+ find stage ! -name makefile ! -name '*~' | cpio -pudmv $(INS)
+ find common ! -name makefile ! -name '*~' | cpio -pudmv $(INS)
+ cp -p testlock/testlock $(INSSTG)/opt/app/postgresql-prep/bin/testlock
+ chmod a+x $(INSSTG)/opt/app/postgresql-prep/bin/*
+ cp -p repackage.* $(INS)
+
+
+debian: stage
+ repackage -y repackage.json -b debian -d $(INS) -u
+ repackage -y repackage.json -b debian -d $(INS) -u -B LATEST
+ @echo debian built
+
+upload-javadocs:
+ @echo nothing to do here
+
diff --git a/postgresql-prep/src/repackage.json b/postgresql-prep/src/repackage.json
new file mode 100644
index 0000000..358fe31
--- /dev/null
+++ b/postgresql-prep/src/repackage.json
@@ -0,0 +1,29 @@
+{
+ "description": " PostgreSQL as a Service main scripts ",
+ "fileGroup": "root",
+ "groupId": "org.openecomp.dcae.storage.pgaas",
+ "fileUser": "root",
+ "executionGroup": "root",
+ "executionUser": "root",
+ "internalDependencies": [],
+ "maintainer": "OpenECOMP <dcae@lists.openecomp.org>",
+ "docker": {
+ "tag": "latest",
+ "externalDependencies": []
+ },
+ "applicationName": "postgresql-prep",
+ "debian": {
+ "groupId": "org.openecomp.dcae.storage.pgaas",
+ "externalDependencies": [
+ {
+ "cdf": ">= 1.0.0"
+ }
+ ],
+ "replaces": [],
+ "conflicts": []
+ },
+ "version": "1.0.0",
+ "directoryTreeTops": {
+ "/opt": "/opt/app/postgresql-prep"
+ }
+} \ No newline at end of file
diff --git a/postgresql-prep/src/stage/opt/app/postgresql-prep/bin/gen-repmgr-info b/postgresql-prep/src/stage/opt/app/postgresql-prep/bin/gen-repmgr-info
new file mode 100755
index 0000000..b210e58
--- /dev/null
+++ b/postgresql-prep/src/stage/opt/app/postgresql-prep/bin/gen-repmgr-info
@@ -0,0 +1,247 @@
+#!/usr/bin/perl
+# 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
+# gen-repmgr-info - extract information about the system appropriate for use with repmgr
+#
+# DESCRIPTION
+# gen-repmgr-info -n hosts options...
+#
+# for a list of hosts such as "uiopzxc5pepstg00.grant.example.com|uiopzxc5pepstg01.grant.example.com|uiopmtc6njpstg00.grant.example.com|uiopmtc6njpstg01.grant.example.com"
+# extract various pieces of information about the list. For example, generate a list of repmgr node numbers like this:
+# uiopzxc5pepstg00.grant.example.com 100
+# uiopzxc5pepstg01.grant.example.com 101
+# uiopmtc6njpstg00.grant.example.com 200
+# uiopmtc6njpstg01.grant.example.com 201
+
+use strict vars;
+
+use Getopt::Std;
+use Digest::SHA qw(sha256_hex);
+
+sub usage {
+ my $msg = shift;
+ print "$msg\n" if $msg;
+ print "Usage: $0 -n 'node|node|node|...' [-S] [-s site] [-L] [-l node] [-c node] [-C node] [-m] [-M node] [-e] [-v] [-p]\n";
+ print "-n list of nodes (FQDNs), |-separated\n";
+ print "-S show list of all sites and their node # values\n";
+ print "-s site\tshow the node # value for a given site\n";
+ print "-L show list of all nodes and their node # values\n";
+ print "-l node\tshow the node # value for a given node\n";
+ print "-C node\tshow the machine name that a given node should cascade from, or DEFAULT\n";
+ print "-c node\tshow the machine node # that a given node should cascade from, or DEFAULT\n";
+ print "-e node\tshow the list of nodes on the same site as the given node, |-separated\n";
+ print "-m\twhich system is the 'master'\n";
+ print "-M node\twhich system matches the given node, taking FQDN into consideration\n";
+ print "-v\tverbose\n";
+ print "-p\tprint the node names in sorted order\n";
+ exit 1;
+}
+
+
+my %optargs;
+getopts('C:c:e:E:Ll:M:mn:pPSs:v', \%optargs) or usage();
+my $verbose = $optargs{v};
+
+my $pgnodes = $optargs{n} or usage("-n is required");
+
+# generate the data about the nodes
+my @pgnodes = sort split(/[|]/, $pgnodes);
+
+# @sites contains the list of all site names.
+# For uiopzxc5pepstg01.grant.example.com, the sitename will be uiopzxc5pepstg.
+my @sites = genSites();
+my %pgnodesToSite = genPgnodeToSites();
+
+# The %siteValues contains 100, 200, etc for each site name
+# print "\nsites=" . join("\n", @sites);
+my %siteValues = genSiteValues();
+
+# The %pgnodeValues contains 100, 101, 200, 201, etc for each node name
+my %pgnodeValues = genPgnodeValues();
+# The %valuesToPgnode contains node names for each value
+my %valuesToPgnode = genValuesToPgnodes();
+
+if ($optargs{L}) {
+ for my $pgnode (@pgnodes) {
+ print "$pgnode $pgnodeValues{$pgnode}\n";
+ }
+}
+
+if ($optargs{S}) {
+ for my $site (@sites) {
+ print "$site $siteValues{$site}\n";
+ }
+}
+
+if ($optargs{s}) {
+ for my $site (@sites) {
+ print "$siteValues{$site}\n" if $site eq $optargs{s};
+ }
+}
+
+if ($optargs{l}) {
+ for my $pgnode (@pgnodes) {
+ print "$pgnodeValues{$pgnode}\n" if $pgnode eq $optargs{l};
+ }
+}
+
+if ($optargs{c}) {
+ my $pgnode = $optargs{c};
+ my $pgnodeValue = $pgnodeValues{$pgnode};
+ my $masterValue = int($pgnodeValue / 100) * 100;
+ if (($masterValue > 100) && (($masterValue % 100) > 0)) {
+ print "$masterValue\n";
+ } else {
+ print "DEFAULT\n";
+ }
+}
+
+if ($optargs{C}) {
+ my $pgnode = $optargs{C};
+ my $pgnodeValue = $pgnodeValues{$pgnode};
+ my $masterValue = int($pgnodeValue / 100) * 100;
+ # print "pgnode=$pgnode, pgnodeValue=$pgnodeValue, masterValue=$masterValue\n";
+ if (($pgnodeValue % 100) > 0) {
+ print "$valuesToPgnode{$masterValue}\n";
+ } else {
+ print "DEFAULT\n";
+ }
+}
+
+sub enodes {
+ my $pgnodeSearch = $optargs{e};
+ my $siteSearch = $pgnodesToSite{$pgnodeSearch};
+ my $ret = "";
+ # print "looking for $pgnodeSearch in $siteSearch\n";
+ my $sep = "";
+ for my $pgnode (@pgnodes) {
+ my $site = $pgnodesToSite{$pgnode};
+ # print "looking at $pgnode in $site\n";
+ if ($site eq $siteSearch) {
+ $ret .= "$sep$pgnode";
+ $sep = "|";
+ }
+ }
+ return $ret;
+}
+
+if ($optargs{e}) {
+ my $ret = enodes();
+ print "$ret\n";
+}
+
+if ($optargs{E}) {
+ print sha256_hex(enodes()) . "\n";
+}
+
+if ($optargs{m}) {
+ print "$pgnodes[0]\n";
+}
+
+if ($optargs{M}) {
+ my $node = $optargs{M};
+ if ($node =~ /[.]/) {
+ print "$node\n";
+ } else {
+ my $found;
+ for my $pgnode (@pgnodes) {
+ if ($pgnode =~ /^$node[.]/) {
+ print $node;
+ $found = 1;
+ last;
+ }
+ }
+ }
+}
+
+sub pnodes {
+ return join("|", @pgnodes);
+}
+
+if ($optargs{p}) {
+ print pnodes() . "\n";
+}
+
+if ($optargs{P}) {
+ print sha256_hex(pnodes()) . "\n";
+}
+
+# for a given node name uiopzxc5pepstg01.grant.example.com, the return uiopzxc5pepstg.
+sub nodeToSite {
+ my $site = shift;
+ $site =~ s/[.].*//;
+ $site =~ s/\d*$//;
+ return $site;
+}
+
+# from a list of nodes, generate the sorted list of sites
+sub genSites {
+ my %sites = ();
+ # print "pgnodes=" . join("\n", @pgnodes);
+ for my $pgnode (@pgnodes) {
+ my $site = nodeToSite($pgnode);
+ $sites{$site} = $site;
+ }
+ my @sites = sort keys %sites;
+ return @sites;
+}
+
+# from a list of nodes, generate a mapping from them to their sites
+sub genPgnodeToSites {
+ my %sites = ();
+ for my $pgnode (@pgnodes) {
+ $sites{$pgnode} = nodeToSite($pgnode);
+ }
+ return %sites;
+}
+
+# generate the 100, 200, etc for each site name
+sub genSiteValues {
+ my %siteValues;
+ for (my $i = 0; $i <= $#sites; $i++) {
+ $siteValues{$sites[$i]} = ($i+1) * 100;
+ }
+ # print "\nsiteValues=\n"; for my $site (@sites) { print "$site $siteValues{$site}\n"; }
+ return %siteValues;
+}
+
+sub genPgnodeValues {
+ my %pgnodeValues;
+ my $i = 0;
+ my $lastSite = '';
+ for my $pgnode (@pgnodes) {
+ my $thisSite = nodeToSite($pgnode);
+ if ($thisSite eq $lastSite) {
+ $i++;
+ } else {
+ $i = 0;
+ }
+ $lastSite = $thisSite;
+ $pgnodeValues{$pgnode} = $siteValues{$thisSite} + $i;
+ }
+ # print "\nnodeValues=\n"; for my $pgnode (@pgnodes) { print "$pgnode $pgnodeValues{$pgnode}\n"; }
+ return %pgnodeValues;
+}
+
+sub genValuesToPgnodes {
+ my %valuesToPgnode;
+ for my $pgnode (keys %pgnodeValues) {
+ my $value = $pgnodeValues{$pgnode};
+ $valuesToPgnode{$value} = $pgnode;
+ }
+ return %valuesToPgnode;
+}
+
diff --git a/postgresql-prep/src/stage/opt/app/postgresql-prep/bin/iDNS-responder.py b/postgresql-prep/src/stage/opt/app/postgresql-prep/bin/iDNS-responder.py
new file mode 100755
index 0000000..b6c5174
--- /dev/null
+++ b/postgresql-prep/src/stage/opt/app/postgresql-prep/bin/iDNS-responder.py
@@ -0,0 +1,1025 @@
+#!/usr/bin/env 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.
+
+
+import http.server
+import time, os, sys, re, subprocess, traceback, html, base64
+import psycopg2
+# TODO - move lots of code to a common library to share with other python modules
+# sys.path.append("/opt/app/postgres-prep/lib")
+# import dbtools
+
+getLogDict = { }
+def openLogFile(fname):
+ """
+ Open a log file for append and remember the file descriptor.
+ Remember its inode/dev pair.
+ If either changes, reopen it.
+ """
+ reopen = False
+ try:
+ curstat = os.stat(fname)
+ except:
+ reopen = True
+ global getLogDict
+ # print("top: reopen(%s)=%s" % (fname, reopen))
+ if not reopen and getLogDict.get(fname):
+ # print("found getLogDict.get(" + fname + ")")
+ d = getLogDict[fname]
+ fd = d["fd"] if "fd" in d else None
+ oldstat = d["stat"] if "stat" in d else None
+ if fd is None:
+ reopen = True
+ elif oldstat is None:
+ reopen = True
+ elif oldstat.st_ino != curstat.st_ino or oldstat.st_dev != curstat.st_dev:
+ reopen = True
+ if reopen or not getLogDict.get(fname):
+ # print("closing old fd")
+ oldd = getLogDict.get(fname)
+ if oldd is not None:
+ oldfd = oldd.get("fd")
+ if oldfd is not None:
+ oldfd.close()
+ # print("reopening " + fname)
+ fd = open(fname, "a")
+ st = os.stat(fname)
+ getLogDict[fname] = { "fd": fd, "stat": st }
+ return getLogDict[fname]["fd"]
+
+debugOn = False
+testOn = False
+
+if len(sys.argv) > 1:
+ debugOn = True
+ testOn = True
+
+else:
+ sys.stderr = openLogFile("/opt/app/log/postgresql/idns/error.log")
+
+HOST_NAME = os.popen("hostname -f").readlines()[0].strip()
+PORT_NUMBER = 8000
+
+validPerDbTables = [ "pg_tables", "pg_indexes", "pg_views" ]
+topButton = "&nbsp;<font size='1'><a href='#'>^</a></font>"
+
+def traceMsg(msg):
+ """ print a trace message. By default, this goes to trace.out """
+ file = sys.stderr if testOn else openLogFile("/opt/app/log/postgresql/idns/trace.log")
+ print(time.asctime(), msg, file=file)
+ file.flush()
+
+def errTrace(msg):
+ """ print an error message. By default, sys.stderr is rerouted to error.log """
+ file = sys.stderr if testOn else openLogFile("/opt/app/log/postgresql/idns/error.log")
+ sys.stderr = file
+ print(time.asctime(), msg, file=file)
+ file.flush()
+
+def debugTrace(msg):
+ """ print a debug message. By default, this goes to debug.log """
+ if debugOn:
+ file = sys.stderr if testOn else openLogFile("/opt/app/log/postgresql/idns/debug.log")
+ print(time.asctime(), msg, file=file)
+ file.flush()
+
+def readFile(file, defStr = None, mode = "r"):
+ """ read a file and return its contents """
+ ret = defStr
+ try:
+ with open(file, mode) as f:
+ ret = f.read()
+ except Exception as e:
+ if defStr is not None:
+ ret = defStr
+ pass
+ else:
+ raise e
+ return ret
+
+def readFileBinary(file, defStr = None):
+ return readFile(file, defStr = defStr, mode = "rb")
+
+def readFileHtml(file, defStr = None):
+ """ read a file and return its contents, escaping anything important to HTML """
+ return html.escape(readFile(file, defStr))
+
+def readPipe(cmd, ignoreError = False):
+ """ read a pipe and return its contents """
+ ret = ""
+ try:
+ with os.popen(cmd) as p:
+ ret = p.read()
+ except Exception as e:
+ if ignoreError:
+ pass
+ else:
+ raise e
+ return ret
+
+def readPipeHtml(file, defStr = None):
+ """ read a pipe and return its contents, escaping anything important to HTML """
+ return html.escape(readPipe(file, defStr))
+
+def readFileOrGz(file, defStr = None):
+ """ read a file and return its contents. If the file ends in .gz, use gunzip on it """
+ if file.endswith(".gz"):
+ return readPipe("gunzip < '" + file + "'", defStr)
+ else:
+ return readFile(file, defStr)
+
+def readFileOrGzHtml(file, defStr = None):
+ """ read a file and return its contents, escaping anything important to HTML. If the file ends in .gz, use gunzip on it """
+ return html.escape(readFileOrGz(file, defStr))
+
+def getCdfPropValue(nm, encrypted=False, cfg="/opt/app/cdf/lib/cdf.cfg", dflt=None):
+ """
+ Return a value from the configuration file /opt/app/cdf/lib/cdf.cfg
+ """
+ return getPropValue(nm=nm, encrypted=encrypted, cfg=cfg, dflt=dflt)
+
+def getPgaasPropValue(nm, encrypted=False, cfg="/opt/app/pgaas/lib/pgaas.cfg", dflt=None):
+ """
+ Return a value from the configuration file /opt/app/pgaas/lib/pgaas.cfg
+ """
+ return getPropValue(nm=nm, encrypted=encrypted, cfg=cfg, dflt=dflt)
+
+getPropDict = { }
+
+def getPropValue(nm, encrypted=False, cfg=None, dflt=None):
+ """
+ Return a value from the specified configuration file
+ """
+ if cfg is None:
+ return None
+ global getPropDict
+ if getPropDict.get(cfg):
+ savedDate = getPropDict[cfg]
+ debugTrace("getPropValue: savedDate[" + cfg + "]=" + str(savedDate))
+ cfgDate = os.path.getmtime(cfg)
+ debugTrace("getPropValue: cfgDate=" + str(cfgDate))
+ if float(savedDate) >= float(cfgDate): # cfg has not changed
+ val = getPropDict.get(cfg + ":" + nm)
+ debugTrace("getPropValue: val=" + str(val))
+ if val is not None:
+ debugTrace("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]
+ debugTrace("getPropValue: cmd=%s" % 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()
+ errTrace("Error decoding string because {0}".format(e))
+ return None
+ else:
+ if stderrString:
+ if not re.search("Configuration property .* must be defined", stderrString.decode('utf-8')): # and dflt is not None:
+ errTrace("Error decoding string because: {0} ".format(stderrString))
+ return dflt
+ else:
+ debugTrace("getPropValue() => '%s'" % str(origString))
+ getPropDict[cfg] = os.path.getmtime(cfg)
+ val = origString.decode('utf-8').rstrip('\n')
+ debugTrace("getPropValue() => '%s'" % val)
+ getPropDict[cfg + ":" + nm] = val
+ return val
+
+def checkFileAge(full_path,number_of_days):
+ """
+ return True if the file is >= number_of_days old from right now
+ """
+ time_n_days_ago = time.time() - (number_of_days * 24 * 60 * 60)
+ stat = os.stat(full_path)
+ return time_n_days_ago >= stat.st_mtime
+
+def jumpTable(prefix, *args):
+ """
+ Return a string consisting of a series of <a href='#prefix-xxx'>xxx</a>.
+ Include <font size='1'></font> around all of it.
+ """
+ header = "<font size='1'>"
+ sep = ""
+ for table in args:
+ header = header + sep + "<a href='#" + prefix + "-" + table + "'>" + table + "</a> "
+ sep = " | "
+ header = header + "</font>"
+ return header
+
+def addFilenameHrefs(prefix, str):
+ """
+ for each line in a list of filenames, change the last two elements of the path to an anchor.
+ """
+ ret = ""
+ for line in str.splitlines():
+ line = re.sub("/([^/]+)/([^/]+)$", '/\g<1>' + "/<a href='" + prefix + '\g<1>/\g<2>' + "'>" + '\g<2>' + "</a>", line)
+ ret = ret + line + "\n"
+ return ret
+
+def ifEmpty(str, defStr):
+ """ if a string is empty, return the defStr in its place """
+ if str is None or str == "":
+ str = defStr
+ return str
+
+def isExe(fname):
+ """ check if a path exists and is executable """
+ return os.path.exists(fname) and os.access(fname, os.X_OK)
+
+class MyHandler(http.server.BaseHTTPRequestHandler):
+
+ def isServerUp(self):
+ """
+ Check if the postgres server is up and running by calling pg_ctl and
+ looking for "server is running" (or "no server running").
+ Then call ps -fu postgres and make sure we're not waiting on a master:
+ postgres 20815 20812 0 15:52 ? 00:00:00 postgres: startup process waiting for 000000010000000000000001
+ """
+ PGCTLPATH1 = "/usr/lib/postgresql/9.5/bin/pg_ctl"
+ PGCTLPATH2 = "/opt/app/postgresql-9.5.2/bin/pg_ctl"
+ if isExe(PGCTLPATH1):
+ statusLines = readPipe(PGCTLPATH1 + " status -D /dbroot/pgdata/main/")
+ else:
+ statusLines = readPipe(PGCTLPATH2 + " status -D /dbroot/pgdata/main/")
+ debugTrace("isServerUp(): statusLines = %s" % statusLines)
+ psLines = readPipe("ps -fu postgres")
+ debugTrace("isServerUp(): ps -fu postgres = %s" % psLines)
+ ret = len(statusLines) > 0 and re.search("server is running", statusLines, re.MULTILINE) and not re.search("startup process\\s+waiting", psLines, re.MULTILINE)
+ debugTrace("isServerUp(): returning = %s" % ret)
+ return ret
+
+ def isRepmgrdUp(self):
+ """
+ Check if the repmgrd server is up and running by calling "pgrep repmgrd" and
+ looking for a process id.
+ """
+ statusLines = readPipe("pgrep repmgrd")
+ debugTrace("isServerUp(): statusLines = %s" % statusLines)
+ ret = len(statusLines) > 0 and re.search("[0-9]+", statusLines, re.MULTILINE) != None
+ debugTrace("isServerUp(): returning = %s" % ret)
+ return ret
+
+ def isMaster(self):
+ """
+ Check if the postgresql server is a master by asking the server if it is in recovery (meaning not a master)
+ """
+ ret = None
+ con = None
+ try:
+ pwd = getCdfPropValue("postgres", True)
+ # debugTrace("using pwd=%s" % pwd)
+ con = psycopg2.connect(database = "postgres", user="postgres", password=pwd, host= HOST_NAME)
+ str = dbGetFirstRowOneValue(con, "select pg_is_in_recovery()")
+ debugTrace("pg_is_in_recovery() <= %s" % str)
+ ret = not str
+
+ except psycopg2.DatabaseError as e:
+ errTrace('Database Error %s' % e)
+
+ except Exception as e:
+ traceback.print_exc()
+ errTrace(str(e))
+
+ finally:
+ if con is not None:
+ con.close()
+
+ debugTrace("isMaster(): returning = %s" % ret)
+ return ret
+
+ def hasRepmgr(self):
+ """
+ Check if the postgresql server is a master by asking the server if it is in recovery (meaning not a master)
+ """
+ ret = None
+ con = None
+ try:
+ pwd = getCdfPropValue("postgres", True)
+ # debugTrace("using pwd=%s" % pwd)
+ con = psycopg2.connect(database = "postgres", user="postgres", password=pwd, host= HOST_NAME)
+ str = dbGetFirstRowOneValue(con, "select * from pg_database where datname = 'repmgr'")
+ debugTrace("repmgr database check() <= %s" % str)
+ ret = str
+
+ except psycopg2.DatabaseError as e:
+ errTrace('Database Error %s' % e)
+
+ except Exception as e:
+ traceback.print_exc()
+ errTrace(str(e))
+
+ finally:
+ if con is not None:
+ con.close()
+
+ debugTrace("isMaster(): returning = %s" % ret)
+ return ret
+
+ def isValidPgHost(self, host):
+ """
+ Check a hostname against the list of nodes stored in the pgnodes CDF configuration file.
+ """
+ pgnodes = getCdfPropValue("pgnodes", "").split('|')
+ ret = host in pgnodes
+ debugTrace("isValidPgHost(): looking for host='%s' in pgnodes='%s' => %s" % (host, str(pgnodes), ret))
+ return ret
+
+ def checkAuth(self):
+ """
+ HTTP/1.1 401 Unauthorized
+ Date: Mon, 04 Feb 2014 16:50:53 GMT
+ WWW-Authenticate: Basic realm="WallyWorld"
+
+ Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==
+ """
+ pswd = getCdfPropValue("wgetpswd", True)
+ b64pswd = base64.b64encode(("pgaas:" + pswd).encode("ascii"))
+ basicPlusPswd = "Basic %s" % b64pswd.decode("ascii")
+
+ if self.headers['Authorization'] == None:
+ return False
+ elif self.headers['Authorization'] == basicPlusPswd:
+ return True
+ else:
+ return False
+
+ def pgStatus(self, *pgargs):
+ """ return a table(s), using the system database of postgres """
+ return self.pgStatusDBx("postgres", *pgargs)
+
+ def pgStatusDB(self, DB, *pgargs):
+ """ return a table(s), using the given database """
+ return self.pgStatusDBx(DB, *pgargs)
+
+ def pgStatusDBx(self, DB, *pgargs):
+ """ return a table(s), using the given database """
+ debugTrace("pgStatusDBx(DB=" + DB + ")")
+ con = None
+ ret = None
+ try:
+ con = psycopg2.connect(database = DB, user="postgres", password=getCdfPropValue("postgres", True), host= HOST_NAME)
+ ret = getTableHtmls(con, DB, pgargs)
+
+ except psycopg2.DatabaseError as e:
+ errTrace('Database Error %s' % e)
+
+ except Exception as e:
+ traceback.print_exc()
+ errTrace(str(e))
+
+ finally:
+ if con is not None:
+ con.close()
+
+ return ret
+
+ def do_HEAD(self):
+ """Respond to a HEAD request."""
+ self.doHEADandGET(False)
+
+ def do_GET(self):
+ """Respond to a GET request."""
+ self.doHEADandGET(True)
+
+ def doHEADandGET(self, sendMsg):
+ resp = 400
+ msg = ""
+ sendBinary = False
+ contentType = "text/plain"
+ global debugOn
+
+ if self.path == "/statusall":
+ self.path = "/all/status/pgstatus"
+ elif self.path == "/pgstatusall":
+ self.path = "/pgstatus"
+
+ if self.path == '/ro':
+ if os.path.isfile("/var/run/postgresql/force-ro-off"):
+ isrw = "FORCE-RO-OFF"
+ elif os.path.isfile("/var/run/postgresql/force-ro-on"):
+ isrw = "Secondary"
+ else:
+ isrw = readFile("/var/run/postgresql/isrw", "n/a")
+ debugTrace("/ro: isrw returns %s" % isrw)
+ if re.match("Secondary", isrw) or re.match("Master", isrw):
+ resp = 200
+ msg = "server is up"
+ else:
+ msg = "server is not up " + isrw
+ errTrace("/ro: isrw returns %s" % isrw)
+
+ elif self.path == '/rw':
+ isrw = readFile("/var/run/postgresql/isrw", "n/a")
+ debugTrace("/rw: isrw returns %s" % isrw)
+ if re.match("Master", isrw):
+ resp = 200
+ msg = "master server is up"
+ elif re.match("Secondary", isrw):
+ msg = "non-master server is up"
+ else:
+ msg = "server is not up " + isrw
+ errTrace("/ro: isrw returns %s" % isrw)
+
+ elif self.path == '/isrw':
+ isrw = readFile("/var/run/postgresql/isrw", "n/a")
+ debugTrace("/rw: isrw returns %s" % isrw)
+ resp = 200
+ msg = isrw
+
+ elif not self.checkAuth():
+ resp = 401
+ msg = "not authenticated"
+
+ elif self.path == '/ismaster':
+ masterYes = self.isMaster()
+ msg = ""
+ if masterYes:
+ resp = 200
+ msg = "master server"
+ else:
+ msg = "non-master server"
+
+ elif self.path == '/issecondary':
+ masterYes = self.isMaster()
+ msg = ""
+ if not masterYes:
+ resp = 200
+ msg = "secondary server"
+ else:
+ msg = "non-secondary server"
+
+ elif self.path == '/getpubkey':
+ try:
+ resp = 200
+ msg = readFile("/home/postgres/.ssh/id_rsa.pub")
+ except:
+ traceback.print_exc()
+ resp = 404
+ msg = "key does not exist"
+
+ elif re.match("/getssh/", self.path):
+ # getssh/hostname - push ssh pub/private keys across
+ host = re.sub("^/getssh/", "", self.path)
+ debugTrace("#1: /getssh/ host='%s'" % host)
+ host = re.sub("[^a-zA-Z0-9_.-]", "", host)
+ debugTrace("#2: /getssh/ host='%s'" % host)
+ if self.isValidPgHost(host):
+ p = readPipe("scp -o StrictHostKeyChecking=no ~postgres/.ssh/id_rsa* " + host + ":.ssh/ 2>&1")
+ debugTrace("#3: /getssh/ to '%s' returns '%s'" % (host, p))
+ msg = "OK " + p
+ resp = 200
+ else:
+ msg = "NOT OK INVALID HOST"
+ resp = 404
+
+ elif re.match("/getcdf/", self.path):
+ # getcdf/hostname - push cdf.cfg file across
+ fi = "/opt/app/cdf/lib/cdf.cfg"
+ # make sure that the file exists and contains the encrypted postgres password
+ if re.search("postgres.x", readFile(fi, "n/a")) and re.search("repmgr.x", readFile(fi, "n/a")):
+ host = re.sub("^/getcdf/", "", self.path)
+ debugTrace("#1: /getcdf/ host='%s'" % host)
+ host = re.sub("[^a-zA-Z0-9_.-]", "", host)
+ debugTrace("#2: /getcdf/ host='%s'" % host)
+ if self.isValidPgHost(host):
+ p = readPipe("scp -o StrictHostKeyChecking=no " + fi + " " + host + ":/opt/app/cdf/lib/cdf.cfg 2>&1")
+ debugTrace("#3: /getcdf/ to '%s' returns '%s'" % (host, p))
+ msg = "OK " + p
+ resp = 200
+ else:
+ msg = "NOT OK INVALID HOST"
+ resp = 404
+ else:
+ msg = "NOT OK YET"
+ resp = 404
+
+ elif self.path == '/hasrepmgr':
+ repmgrYes = self.hasRepmgr()
+ msg = ""
+ if repmgrYes:
+ resp = 200
+ msg = "OK"
+ else:
+ msg = "NOT OK YET"
+
+ elif self.path == '/status':
+ resp = 200
+ contentType = "text/html"
+ isServerUp = self.isServerUp()
+ isRepmgrdUp = self.isRepmgrdUp()
+ isMaster = self.isMaster()
+ color = "green" if (isServerUp and isRepmgrdUp) else "yellow" if (isServerUp or isRepmgrdUp) else "red"
+ dashed = "solid" if isMaster else "dashed"
+ jump = jumpTable("status", "ps", "repmgr", "df", "uptime", "loadavg", "cpuinfo", "meminfo", "pgaas-failures", "pgaas-inst-report", "nslookup", "ip-addr-show", "who-br")
+
+ msg = """<table style='border: 10px %s %s' width='100%%'><tr><td>
+ <b>isServerUp</b> %s
+ <b>isRepmgrdUp</b> %s
+ <b>isMaster</b> %s
+ <b>isrw</b> %s %s\n<br/>
+ %s
+ <h2><a name='status-ps'>ps</a>%s</h2>\n<pre>\n%s\n</pre>\n
+ <h2><a name='status-repmgr'>repmgr cluster show</a>%s</h2>\n<pre>\n%s\n</pre>\n
+ <h2><a name='status-df'>df</a>%s</h2>\n<pre>\n%s\n</pre>\n
+ <h2><a name='status-uptime'>uptime</a>%s</h2>\n<pre>\n%s\n</pre>\n
+ <h2>/proc/uptime%s</h2>\n<pre>\n%s\n</pre>\n
+ <h2><a name='status-loadavg'>loadavg</a>%s</h2>\n<pre>\n%s\n</pre>\n
+ <h2><a name='status-cpuinfo'>cpuinfo</a>%s</h2>\n<pre>\n%s\n</pre>\n
+ <h2><a name='status-meminfo'>meminfo</a>%s</h2>\n<pre>\n%s\n</pre>\n
+ <h2><a name='status-pgaas-failures'>pgaas-failures</a>%s</h2>\n<pre>\n%s\n</pre>\n
+ <h2><a name='status-pgaas-inst-report'>pgaas.inst.report</a>%s</h2>\n<pre>\n%s\n</pre>\n
+ <h2><a name='status-nslookup'>nslookup</a>%s</h2>\n<pre>\n%s\n</pre>\n
+ <h2><a name='status-ip-addr-show'>ip addr</a>%s</h2>\n<pre>\n%s\n</pre>\n
+ <h2><a name='status-who-br'>who -br</a>%s</h2>\n<pre>\n%s\n</pre>\n
+ </td></tr></table>""" % (color, dashed, isServerUp, isRepmgrdUp, isMaster,
+ readFileHtml("/var/run/postgresql/isrw", "n/a"),
+ readPipeHtml("hostname -f"), jump,
+ topButton, readPipeHtml("ps -fu postgres"),
+ topButton, readPipeHtml("/opt/app/pgaas/bin/repmgrc cluster show"),
+ topButton, readPipeHtml("df -h"),
+ topButton, readPipeHtml("uptime", defStr="n/a"),
+ topButton, readFileHtml("/proc/uptime", defStr="n/a"),
+ topButton, readFileHtml("/proc/loadavg", defStr="n/a"),
+ topButton, readFileHtml("/proc/cpuinfo", defStr="n/a"),
+ topButton, readFileHtml("/proc/meminfo", defStr="n/a"),
+ topButton, readFileHtml("/tmp/pgaas-failures", defStr="n/a"),
+ topButton, readFileHtml("/tmp/pgaas.inst.report", defStr="n/a"),
+ topButton, readPipeHtml("nslookup $(hostname -f)", defStr="n/a"),
+ topButton, readPipeHtml("ip addr show", defStr="n/a"),
+ topButton, readPipeHtml("who -br", defStr="n/a"))
+
+ elif self.path == '/stoplight':
+ isServerUp = self.isServerUp()
+ isRepmgrdUp = self.isRepmgrdUp()
+ isMaster = self.isMaster()
+ color = "green" if (isServerUp and isRepmgrdUp) else "yellow" if (isServerUp or isRepmgrdUp) else "red"
+ masterSecondary = "master" if isMaster else "secondary"
+ sendBinary = True
+ contentType = "image/gif"
+ msg = readFileBinary("/opt/app/postgresql-prep/lib/stoplight-" + masterSecondary + "-" + color + ".gif", "")
+
+ elif re.match("/perdb-", self.path):
+ # /perdb-
+ rest = re.sub("^/perdb-", "", self.path)
+ debugTrace("#1: /perdb- others='%s'" % rest)
+ rest = re.sub("[^a-zA-Z0-9_./-]", "", rest)
+ debugTrace("#2: /perdb- rest='%s'" % rest)
+ pgothers = [ x for x in rest.split('-') if x in validPerDbTables ]
+ resp = 200
+ contentType = "text/html"
+ con = None
+ try:
+ pwd = getCdfPropValue("postgres", True)
+ con = psycopg2.connect(database = "postgres", user="postgres", password=pwd, host= HOST_NAME)
+ databases = dbGetFirstColumn(con, "select datname from pg_database")
+ debugTrace("after select datname from pg_database")
+ databases[:] = [DB for DB in databases if not re.match("template[0-9]", DB)]
+ msg = msg + jumpTable("db", *databases) + "<br/>"
+ for DB in databases:
+ debugTrace("looking at DB=" + DB)
+ msg = msg + "<h1><a name='db-" + DB + "'>" + DB + "</a>" + topButton + "</h1>\n"
+ msg = msg + jumpTable(DB + "-table", *pgothers)
+ msg = msg + self.pgStatusDB(DB, *pgothers)
+
+ except psycopg2.DatabaseError as e:
+ errTrace('Database Error %s' % e)
+ msg = "DB is down"
+
+ except Exception as e:
+ traceback.print_exc()
+ errTrace(str(e))
+
+ finally:
+ if con is not None:
+ con.close()
+
+ elif self.path == '/pgstatus':
+ tables = [ "pg_stat_activity", "pg_stat_archiver", "pg_stat_bgwriter", "pg_stat_database", "pg_stat_database_conflicts", "pg_stat_user_tables", "pg_stat_user_indexes", "pg_statio_user_tables", "pg_statio_user_indexes", "pg_statio_user_sequences", "pg_roles", "pg_database", "pg_tables", "pg_namespace", "pg_roles", "pg_group" ]
+ header = jumpTable("postgres-table", *tables)
+ msg = self.pgStatus(*tables)
+ if msg is not None:
+ contentType = "text/html"
+ resp = 200
+ msg = header + msg
+
+ elif self.path == '/pg_stat_activity':
+ msg = self.pgStatus("pg_stat_activity")
+ if msg is not None:
+ contentType = "text/html"
+ resp = 200
+
+ elif self.path == '/pg_stat_archiver':
+ msg = self.pgStatus("pg_stat_archiver")
+ if msg is not None:
+ contentType = "text/html"
+ resp = 200
+
+ elif self.path == '/pg_stat_bgwriter':
+ msg = self.pgStatus("pg_stat_bgwriter")
+ if msg is not None:
+ contentType = "text/html"
+ resp = 200
+
+ elif self.path == '/pg_stat_database':
+ msg = self.pgStatus("pg_stat_database")
+ if msg is not None:
+ contentType = "text/html"
+ resp = 200
+
+ elif self.path == '/pg_stat_database_conflicts':
+ msg = self.pgStatus("pg_stat_database_conflicts")
+ if msg is not None:
+ contentType = "text/html"
+ resp = 200
+
+ elif self.path == '/pg_stat_user_tables':
+ msg = self.pgStatus("pg_stat_user_tables")
+ if msg is not None:
+ contentType = "text/html"
+ resp = 200
+
+ elif self.path == '/pg_stat_user_indexes':
+ msg = self.pgStatus("pg_stat_user_indexes")
+ if msg is not None:
+ contentType = "text/html"
+ resp = 200
+
+ elif self.path == '/pg_statio_user_tables':
+ msg = self.pgStatus("pg_statio_user_tables")
+ if msg is not None:
+ contentType = "text/html"
+ resp = 200
+
+ elif self.path == '/pg_statio_user_indexes':
+ msg = self.pgStatus("pg_statio_user_indexes")
+ if msg is not None:
+ contentType = "text/html"
+ resp = 200
+
+ elif self.path == '/pg_statio_user_sequences':
+ msg = self.pgStatus("pg_statio_user_sequences")
+ if msg is not None:
+ contentType = "text/html"
+ resp = 200
+
+ elif self.path == '/pg_roles':
+ msg = self.pgStatus("pg_roles")
+ if msg is not None:
+ contentType = "text/html"
+ resp = 200
+
+ elif self.path == '/pg_database':
+ msg = self.pgStatus("pg_database")
+ if msg is not None:
+ contentType = "text/html"
+ resp = 200
+
+ elif self.path == '/pg_tables':
+ msg = self.pgStatus("pg_tables")
+ if msg is not None:
+ contentType = "text/html"
+ resp = 200
+
+ elif self.path == '/pg_namespace':
+ msg = self.pgStatus("pg_namespace")
+ if msg is not None:
+ contentType = "text/html"
+ resp = 200
+
+ elif self.path == '/pg_group':
+ msg = self.pgStatus("pg_group")
+ if msg is not None:
+ contentType = "text/html"
+ resp = 200
+
+ elif re.match("/all/", self.path) or re.match("/small/", self.path):
+ if re.match("/small/", self.path):
+ height = 40
+ else:
+ height = 400
+ # /all/others
+ rest = re.sub("^/all/", "", self.path)
+ rest = re.sub("^/small/", "", self.path)
+ rest = re.sub("[^a-zA-Z0-9_./-]", "", rest)
+ debugTrace("/all/ rest='%s'" % rest)
+ others = rest.split('/')
+ try:
+ resp = 200
+ contentType = "text/html"
+ pgnodes = getCdfPropValue("pgnodes", "").split('|')
+ msg = msg + jumpTable("node", *pgnodes)
+ for node in pgnodes:
+ hnode = html.escape(node)
+ msg = msg + "<h2><a name='node-" + hnode + "'>" + hnode + "</a>" + topButton + "</h2>\n"
+ msg = msg + jumpTable(hnode + "-other", *others)
+ for other in others:
+ msg = msg + "<h3><a name='" + hnode + "-other-" + other + "'>" + other + "</a>" + topButton + "</h3>\n"
+ msg = msg + "<iframe src='http://" + hnode + ":" + str(PORT_NUMBER) + "/" + other + "' frameborder='1' scrolling='yes' height='" + str(height) + "' width='1200'></iframe>\n"
+ except Exception as e:
+ traceback.print_exc()
+ errTrace(str(e))
+
+
+ elif self.path == '/debugon':
+ msg = "ON"
+ resp = 200
+ debugOn = True
+
+ elif self.path == '/debugoff':
+ msg = "OFF"
+ resp = 200
+ debugOn = False
+
+ elif self.path == '/log' or self.path == '/log/':
+ msg = "<h2>%s</h2><pre>\n%s\n</pre>" % (self.path, addFilenameHrefs("/log/", readPipeHtml("ls -l /opt/app/log/postgresql/*/*")))
+ resp = 200
+ contentType = "text/html"
+
+ elif self.path == '/mlog' or self.path == '/mlog/':
+ # /opt/app/dcae-controller-service-common-vm-manager/logs
+ msg = "<h2>%s</h2><pre>\n%s\n</pre>" % (self.path, addFilenameHrefs("/mlog/", readPipeHtml("ls -l /opt/app/dcae-controller-service-common-vm-manager/logs/*")))
+ resp = 200
+ contentType = "text/html"
+
+ elif self.path == '/tmp' or self.path == '/tmp/':
+ msg = "<h2>%s</h2><pre>\n%s\n</pre>" % (self.path, addFilenameHrefs("/tmp/", readPipeHtml("ls -l /tmp/*")))
+ resp = 200
+ contentType = "text/html"
+
+ elif re.match("/log/", self.path):
+ # /log/dir/path
+ rest = re.sub("^/log/", "", self.path)
+ debugTrace("#1: /log/ others='%s'" % rest)
+ rest = re.sub("[^a-zA-Z0-9_./-]", "", rest)
+ rest = re.sub("/[.][.]/", "", rest)
+ debugTrace("#2: /log/ rest='%s'" % rest)
+ msg = "<h2>%s</h2><pre>\n%s\n</pre>" % (rest, ifEmpty(readFileOrGzHtml("/opt/app/log/postgresql/" + rest, "n/a"), "<i>empty</i>"))
+ resp = 200
+ contentType = "text/html"
+
+ elif re.match("/mlog/", self.path):
+ # /log/dir/path
+ rest = re.sub("^/mlog/", "", self.path)
+ debugTrace("#1: /mlog/ others='%s'" % rest)
+ rest = re.sub("[^a-zA-Z0-9_./-]", "", rest)
+ rest = re.sub("/[.][.]/", "", rest)
+ rest = re.sub("^logs/", "", rest)
+ debugTrace("#2: /mlog/ rest='%s'" % rest)
+ msg = "<h2>%s</h2><pre>\n%s\n</pre>" % (rest, ifEmpty(readFileOrGzHtml("/opt/app/dcae-controller-service-common-vm-manager/logs/" + rest, "n/a"), "<i>empty</i>"))
+ resp = 200
+ contentType = "text/html"
+
+ elif re.match("/tmp/", self.path):
+ # /log/dir/path
+ rest = re.sub("^/tmp/", "", self.path)
+ debugTrace("#1: /tmp/ others='%s'" % rest)
+ rest = re.sub("[^a-zA-Z0-9_./-]", "", rest)
+ rest = re.sub("/[.][.]/", "", rest)
+ rest = re.sub("^tmp/", "", rest)
+ debugTrace("#2: /tmp/ rest='%s'" % rest)
+ msg = "<h2>%s</h2><pre>\n%s\n</pre>" % (rest, ifEmpty(readFileOrGzHtml("/tmp/" + rest, "n/a"), "<i>empty</i>"))
+ resp = 200
+ contentType = "text/html"
+
+ elif self.path == '/oldro':
+ serverYes = self.isServerUp()
+ if serverYes:
+ resp = 200
+ msg = "server is up"
+ else:
+ msg = "server is not up"
+
+ elif self.path == '/oldrw':
+ serverYes = self.isServerUp()
+ masterYes = self.isMaster()
+ msg = ""
+ if serverYes:
+ if masterYes:
+ resp = 200
+ msg = "master server is up"
+ elif masterYes is not None:
+ msg = "non-master server is up"
+ else:
+ msg = "master status is up, but not answering"
+ else:
+ if masterYes:
+ msg = "status is down, but responded as master server"
+ elif masterYes is not None:
+ msg = "status is down, but responded as non-master"
+ else:
+ msg = "status is down, server is not up"
+
+ elif self.path == "/help":
+ resp = 200
+ contentType = "text/html"
+ msg = """<pre>
+ <a href='/statusall'>statusall</a> == all/status/pgstatus
+ <a href='/ro'>ro</a> == iDNS readonly
+ <a href='/rw'>rw</a> == iDNS readwrite
+ <a href='/isrw'>isrw</a> == /var/run/postgresql/isrw
+ <a href='/ismaster'>ismaster</a> == is master
+ <a href='/issecondary'>issecondary</a> == is secondary
+ <a href='/getpubkey'>getpubkey</a> == retrieve public key
+ <a href='/hasrepmgr'>hasrepmgr</a> == repmgr id and database are set up
+ <a href='/status'>status</a> == lots of info
+ <a href='/perdb-pg_tables-pg_indexes-pg_views'>perdb</a>-{<a href='/perdb-pg_tables'>pg_tables</a>-<a href='/perdb-pg_indexes'>pg_indexes</a>-<a href='/perdb-pg_views'>pg_views</a>} == info per DB
+ <a href='/pgstatus'>pgstatus</a> == lots of database info
+ <a href='/pg_stat_activity'>pg_stat_activity</a>, <a href='/pg_stat_archiver'>pg_stat_archiver</a>, <a href='/pg_stat_bgwriter'>pg_stat_bgwriter</a>,
+ <a href='/pg_stat_database'>pg_stat_database</a>, <a href='/pg_stat_database_conflicts'>pg_stat_database_conflicts</a>, <a href='/pg_stat_user_tables'>pg_stat_user_tables</a>,
+ <a href='/pg_stat_user_indexes'>pg_stat_user_indexes</a>, <a href='/pg_statio_user_tables'>pg_statio_user_tables</a>, <a href='/pg_statio_user_indexes'>pg_statio_user_indexes</a>,
+ <a href='/pg_statio_user_sequences'>pg_statio_user_sequences</a>,
+ <a href='/pg_roles'>pg_roles</a>, <a href='/pg_database'>pg_database</a>,
+ <a href='/pg_tables'>pg_tables</a>, <a href='/pg_namespace'>pg_namespace</a>,
+ <a href='/pg_group'>pg_group</a>,
+ <a href='/swmstatus'>swm proc_out files</a>
+ <a href='/log'>log</a> == ls -l logs
+ log/foo == log foo
+ <a href='/mlog'>mlog</a> == ls -l manager logs
+ mlog/foo == mlog foo
+ <a href='/tmp'>tmp</a> == ls -l /tmp
+ </pre>"""
+ else:
+ resp = 404
+ msg = "path does not exist"
+
+ # TODO == encode msg when binary
+ if sendBinary:
+ debugTrace("%s: Returning %d/%d/%s" % (self.path, resp, len(msg), "--binary--"))
+ else:
+ debugTrace("%s: Returning %d/%d/%s" % (self.path, resp, len(msg), msg))
+ traceMsg("- %s - \"%s %s %s\" %d %d" % (self.client_address[0], self.command, self.path, self.request_version, resp, len(msg)))
+ self.send_response(resp)
+ if resp == 401:
+ self.send_header('WWW-Authenticate', 'Basic realm="PGaaS"')
+ self.send_header("Content-type", contentType)
+ self.end_headers()
+ if sendMsg:
+ if msg is None:
+ msg = ""
+ if sendBinary:
+ self.wfile.write(msg)
+ else:
+ self.wfile.write((msg + "\n").encode("utf-8"))
+ sys.stderr.flush()
+
+"""
+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)
+ debugTrace("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
+ traceOutput = sys.stderr if testOn else openLogFile("/opt/app/log/postgresql/idns/debug.log")
+ 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 getTableHtmls(con, DB, tableNames):
+ """
+ Retrieve a dump of all specified tables, in HTML format
+ """
+ ret = ""
+ for tn in tableNames:
+ ret = ret + getTableHtml(con, DB, tn)
+ return ret
+
+def getTableHtml(con, DB, tableName, max=-1):
+ """
+ Retrieve a dump of a given table, in HTML format
+ """
+ # errTrace("getting %s" % str(tableName))
+ ret = "<h2><a name='" + DB + "-table-" + tableName + "'>" + DB + "&nbsp;" + tableName + "</a>" + topButton + "</h2>\n"
+ ret = ret + "<table border='1'>\n"
+ # ret = ret + "<tr><th colspan='" + str(len(cols)+1) + "'>" + tableName + "</th></tr>\n"
+ cols = dbGetFirstColumn(con, "select column_name from information_schema.columns where table_name='" + tableName + "'", skipTrace=True)
+
+ ret = ret + "<tr><th>num</th>"
+ for col in cols:
+ ret = ret + "<th>" + str(col) + "</th>"
+ ret = ret + "</tr>\n"
+
+ 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:
+ ret = ret + "<tr><th>" + str(i) + "</th>"
+ i = i + 1
+ for col in row:
+ ret = ret + "<td>" + str(col) + "</td>"
+ ret = ret + "</tr>\n"
+ ret = ret + "</table>\n"
+ return ret
+
+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:
+ debugTrace("executing:" + str(stmt))
+ cursor.execute(stmt)
+ if not skipTrace:
+ debugTrace("statusmessage=" + cursor.statusmessage + ", rowcount=" + str(cursor.rowcount))
+ return cursor
+
+if __name__ == '__main__':
+ server_class = http.server.HTTPServer
+ httpd = server_class(("0.0.0.0", PORT_NUMBER), MyHandler)
+ errTrace("Server Starts - %s:%s" % (HOST_NAME, PORT_NUMBER))
+ try:
+ httpd.serve_forever()
+ except KeyboardInterrupt:
+ pass
+ httpd.server_close()
+ errTrace("Server Stops - %s:%s" % (HOST_NAME, PORT_NUMBER))
diff --git a/postgresql-prep/src/stage/opt/app/postgresql-prep/bin/makefile b/postgresql-prep/src/stage/opt/app/postgresql-prep/bin/makefile
new file mode 100644
index 0000000..2a94789
--- /dev/null
+++ b/postgresql-prep/src/stage/opt/app/postgresql-prep/bin/makefile
@@ -0,0 +1,22 @@
+all:
+
+NODES="uiopmno5qwpstg01.grant.example.com|uiopmno5qwpstg00.grant.example.com|uiopmno6qwpstg00.grant.example.com|uiopmno6qwpstg01.grant.example.com"
+
+test:
+ ./gen-repmgr-info -n $(NODES)
+ ./gen-repmgr-info -S -L -n $(NODES)
+ ./gen-repmgr-info -s uiopmno6qwpstg -n $(NODES)
+ ./gen-repmgr-info -l uiopmno6qwpstg01.grant.example.com -n $(NODES)
+ ./gen-repmgr-info -c uiopmno5qwpstg00.grant.example.com -n $(NODES)
+ ./gen-repmgr-info -c uiopmno5qwpstg01.grant.example.com -n $(NODES)
+ ./gen-repmgr-info -c uiopmno6qwpstg00.grant.example.com -n $(NODES)
+ ./gen-repmgr-info -c uiopmno6qwpstg01.grant.example.com -n $(NODES)
+ ./gen-repmgr-info -e uiopmno5qwpstg01.grant.example.com -n $(NODES)
+ ./gen-repmgr-info -e uiopmno6qwpstg01.grant.example.com -n $(NODES)
+ ./gen-repmgr-info -m -n $(NODES)
+ ./gen-repmgr-info -C uiopmno5qwpstg00.grant.example.com -n $(NODES)
+ ./gen-repmgr-info -C uiopmno5qwpstg01.grant.example.com -n $(NODES)
+ ./gen-repmgr-info -C uiopmno6qwpstg00.grant.example.com -n $(NODES)
+ ./gen-repmgr-info -C uiopmno6qwpstg01.grant.example.com -n $(NODES)
+ ./gen-repmgr-info -p -n $(NODES)
+
diff --git a/postgresql-prep/src/stage/opt/app/postgresql-prep/bin/pgwget b/postgresql-prep/src/stage/opt/app/postgresql-prep/bin/pgwget
new file mode 100644
index 0000000..d1d5f98
--- /dev/null
+++ b/postgresql-prep/src/stage/opt/app/postgresql-prep/bin/pgwget
@@ -0,0 +1,4 @@
+# this command is used to access the iDNS status server running on a PGaaS instance
+
+wgetpswd=`/opt/app/cdf/bin/getpropvalue -x -n wgetpswd`
+wget --http-user=pgaas --http-password=$wgetpswd "$@"
diff --git a/postgresql-prep/src/stage/opt/app/postgresql-prep/bin/repmgrd-status-changes b/postgresql-prep/src/stage/opt/app/postgresql-prep/bin/repmgrd-status-changes
new file mode 100644
index 0000000..083b96f
--- /dev/null
+++ b/postgresql-prep/src/stage/opt/app/postgresql-prep/bin/repmgrd-status-changes
@@ -0,0 +1,54 @@
+#!/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.
+
+
+# %n - node ID
+# %e - event type
+# %s - success (1 or 0)
+# %t - timestamp
+# %d - details
+
+nodeID="$1"
+eventType="$2"
+success="$3"
+timestamp="$4"
+details="$5"
+
+LOG=/opt/app/log/postgresql/server/repmgrstatus.log
+PROMOTIONLOG=/var/run/postgresql/repmgr-promotion
+echo `date` "$@" >> $LOG
+
+# The following event types are available:
+# master_register
+# standby_register
+# standby_unregister
+# standby_clone
+# standby_promote
+# standby_follow
+# standby_switchover
+# standby_disconnect_manual
+# witness_create
+# witness_register
+# witness_unregister
+# repmgrd_start
+# repmgrd_shutdown
+# repmgrd_failover_promote
+# repmgrd_failover_follow
+
+case "$eventType" in
+ standby_promote )
+ if [ "$success" -eq 1 ]
+ then echo $(date +%Y%m%d%H%M%S) "$@" >> $PROMOTIONLOG
+ fi
+esac
diff --git a/postgresql-prep/src/stage/opt/app/postgresql-prep/init/init-pgaas-idns.conf b/postgresql-prep/src/stage/opt/app/postgresql-prep/init/init-pgaas-idns.conf
new file mode 100644
index 0000000..8ed39fb
--- /dev/null
+++ b/postgresql-prep/src/stage/opt/app/postgresql-prep/init/init-pgaas-idns.conf
@@ -0,0 +1,21 @@
+# PGaaS - PostgreSQL as a Service
+#
+# The PGaaS iDNS server provides information on the system, primarily for the iDNS system
+
+description "PGaaS iDNS server"
+
+start on runlevel [2345]
+stop on runlevel [!2345]
+
+respawn
+respawn limit 10 5
+umask 022
+setuid postgres
+
+pre-start script
+ test -x /opt/app/postgresql-prep/bin/iDNS-responder.py || { stop; exit 0; }
+end script
+
+script
+ /opt/app/postgresql-prep/bin/iDNS-responder.py
+end script
diff --git a/postgresql-prep/src/stage/opt/app/postgresql-prep/init/init-pgaas-init.conf b/postgresql-prep/src/stage/opt/app/postgresql-prep/init/init-pgaas-init.conf
new file mode 100644
index 0000000..4564129
--- /dev/null
+++ b/postgresql-prep/src/stage/opt/app/postgresql-prep/init/init-pgaas-init.conf
@@ -0,0 +1,24 @@
+# PGaaS - PostgreSQL as a Service
+#
+# The PGaaS init process needs a directory to be created on reboot
+#
+# The best way to do this is to have a file in /usr/lib/tmpfiles.d/pgaas:
+# d /var/run/postgresql 0755 postgres postgres -
+#
+# This is a workaround because systemd-tmpfiles is not present.
+
+description "PGaaS init setup"
+
+start on runlevel [2345]
+stop on runlevel [!2345]
+
+umask 022
+
+pre-start script
+ mkdir /var/run/postgresql
+ chown postgres:postgres /var/run/postgresql
+end script
+
+script
+ :
+end script
diff --git a/postgresql-prep/src/stage/opt/app/postgresql-prep/init/logrotate b/postgresql-prep/src/stage/opt/app/postgresql-prep/init/logrotate
new file mode 100644
index 0000000..aaa5e35
--- /dev/null
+++ b/postgresql-prep/src/stage/opt/app/postgresql-prep/init/logrotate
@@ -0,0 +1,24 @@
+# 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.
+
+
+# rotate PGaaS log files
+
+/opt/app/log/postgresql/init/*.log /opt/app/log/postgresql/idns/*.log /opt/app/log/postgresql/server/*.log {
+ missingok
+ compress
+ daily
+ rotate 60
+ create
+ dateext
+}
diff --git a/postgresql-prep/src/stage/opt/app/postgresql-prep/init/pglogs.cron b/postgresql-prep/src/stage/opt/app/postgresql-prep/init/pglogs.cron
new file mode 100644
index 0000000..e905633
--- /dev/null
+++ b/postgresql-prep/src/stage/opt/app/postgresql-prep/init/pglogs.cron
@@ -0,0 +1,4 @@
+30 * * * * ( date ; find /dbroot/pglogs -type f -mtime +3 -exec rm {} + ) >> /tmp/cleanpglogs.log 2>&1
+50 1 * * * ( mv -f /tmp/cleanpglogs.log /tmp/cleanpglogs.log.old ) > /dev/null 2>&1
+* * * * * [ -x /opt/app/pgaas/bin/update_var_run_isrw ] && /opt/app/pgaas/bin/update_var_run_isrw
+* * * * * [ -x /opt/app/pgaas/bin/check_cluster ] && /opt/app/pgaas/bin/check_cluster >> /opt/app/log/postgresql/idns/cluster.log
diff --git a/postgresql-prep/src/stage/opt/app/postgresql-prep/init/systemd-pgaas-idns.service b/postgresql-prep/src/stage/opt/app/postgresql-prep/init/systemd-pgaas-idns.service
new file mode 100644
index 0000000..bbc28ea
--- /dev/null
+++ b/postgresql-prep/src/stage/opt/app/postgresql-prep/init/systemd-pgaas-idns.service
@@ -0,0 +1,12 @@
+# PGaaS - PostgreSQL as a Service
+#
+# The PGaaS iDNS server provides information on the system, primarily for the iDNS system
+
+[Unit]
+Description=PGaaS iDNS server
+
+[Service]
+ExecStart= /opt/app/postgresql-prep/bin/iDNS-responder.py
+
+[Install]
+WantedBy=multi-user.target
diff --git a/postgresql-prep/src/stage/opt/app/postgresql-prep/init/tmpfiles-pgaas-init.conf b/postgresql-prep/src/stage/opt/app/postgresql-prep/init/tmpfiles-pgaas-init.conf
new file mode 100644
index 0000000..9341a95
--- /dev/null
+++ b/postgresql-prep/src/stage/opt/app/postgresql-prep/init/tmpfiles-pgaas-init.conf
@@ -0,0 +1,7 @@
+# PGaaS - PostgreSQL as a Service
+#
+# The PGaaS init process needs a directory to be created on reboot
+#
+
+d /var/run/postgresql 0755 postgres postgres -
+
diff --git a/postgresql-prep/src/stage/opt/app/postgresql-prep/lib/green-flasher-12x10.gif b/postgresql-prep/src/stage/opt/app/postgresql-prep/lib/green-flasher-12x10.gif
new file mode 100644
index 0000000..c6d33b5
--- /dev/null
+++ b/postgresql-prep/src/stage/opt/app/postgresql-prep/lib/green-flasher-12x10.gif
Binary files differ
diff --git a/postgresql-prep/src/stage/opt/app/postgresql-prep/lib/grey-flasher-12x10.gif b/postgresql-prep/src/stage/opt/app/postgresql-prep/lib/grey-flasher-12x10.gif
new file mode 100644
index 0000000..dfa81a2
--- /dev/null
+++ b/postgresql-prep/src/stage/opt/app/postgresql-prep/lib/grey-flasher-12x10.gif
Binary files differ
diff --git a/postgresql-prep/src/stage/opt/app/postgresql-prep/lib/red-flasher-12x10.gif b/postgresql-prep/src/stage/opt/app/postgresql-prep/lib/red-flasher-12x10.gif
new file mode 100644
index 0000000..ab16a81
--- /dev/null
+++ b/postgresql-prep/src/stage/opt/app/postgresql-prep/lib/red-flasher-12x10.gif
Binary files differ
diff --git a/postgresql-prep/src/stage/opt/app/postgresql-prep/lib/stoplight-G-12x25.gif b/postgresql-prep/src/stage/opt/app/postgresql-prep/lib/stoplight-G-12x25.gif
new file mode 100644
index 0000000..0ce2785
--- /dev/null
+++ b/postgresql-prep/src/stage/opt/app/postgresql-prep/lib/stoplight-G-12x25.gif
Binary files differ
diff --git a/postgresql-prep/src/stage/opt/app/postgresql-prep/lib/stoplight-R-12x25.gif b/postgresql-prep/src/stage/opt/app/postgresql-prep/lib/stoplight-R-12x25.gif
new file mode 100644
index 0000000..0750594
--- /dev/null
+++ b/postgresql-prep/src/stage/opt/app/postgresql-prep/lib/stoplight-R-12x25.gif
Binary files differ
diff --git a/postgresql-prep/src/stage/opt/app/postgresql-prep/lib/stoplight-Y-12x25.gif b/postgresql-prep/src/stage/opt/app/postgresql-prep/lib/stoplight-Y-12x25.gif
new file mode 100644
index 0000000..4f95bf0
--- /dev/null
+++ b/postgresql-prep/src/stage/opt/app/postgresql-prep/lib/stoplight-Y-12x25.gif
Binary files differ
diff --git a/postgresql-prep/src/stage/opt/app/postgresql-prep/lib/stoplight-g-12x25.gif b/postgresql-prep/src/stage/opt/app/postgresql-prep/lib/stoplight-g-12x25.gif
new file mode 100644
index 0000000..0ce2785
--- /dev/null
+++ b/postgresql-prep/src/stage/opt/app/postgresql-prep/lib/stoplight-g-12x25.gif
Binary files differ
diff --git a/postgresql-prep/src/stage/opt/app/postgresql-prep/lib/stoplight-g2-12x25.gif b/postgresql-prep/src/stage/opt/app/postgresql-prep/lib/stoplight-g2-12x25.gif
new file mode 100644
index 0000000..1be7fa1
--- /dev/null
+++ b/postgresql-prep/src/stage/opt/app/postgresql-prep/lib/stoplight-g2-12x25.gif
Binary files differ
diff --git a/postgresql-prep/src/stage/opt/app/postgresql-prep/lib/stoplight-master-green.gif b/postgresql-prep/src/stage/opt/app/postgresql-prep/lib/stoplight-master-green.gif
new file mode 100644
index 0000000..1be7fa1
--- /dev/null
+++ b/postgresql-prep/src/stage/opt/app/postgresql-prep/lib/stoplight-master-green.gif
Binary files differ
diff --git a/postgresql-prep/src/stage/opt/app/postgresql-prep/lib/stoplight-master-red.gif b/postgresql-prep/src/stage/opt/app/postgresql-prep/lib/stoplight-master-red.gif
new file mode 100644
index 0000000..daa6960
--- /dev/null
+++ b/postgresql-prep/src/stage/opt/app/postgresql-prep/lib/stoplight-master-red.gif
Binary files differ
diff --git a/postgresql-prep/src/stage/opt/app/postgresql-prep/lib/stoplight-master-yellow.gif b/postgresql-prep/src/stage/opt/app/postgresql-prep/lib/stoplight-master-yellow.gif
new file mode 100644
index 0000000..1bd8731
--- /dev/null
+++ b/postgresql-prep/src/stage/opt/app/postgresql-prep/lib/stoplight-master-yellow.gif
Binary files differ
diff --git a/postgresql-prep/src/stage/opt/app/postgresql-prep/lib/stoplight-r-12x25.gif b/postgresql-prep/src/stage/opt/app/postgresql-prep/lib/stoplight-r-12x25.gif
new file mode 100644
index 0000000..0750594
--- /dev/null
+++ b/postgresql-prep/src/stage/opt/app/postgresql-prep/lib/stoplight-r-12x25.gif
Binary files differ
diff --git a/postgresql-prep/src/stage/opt/app/postgresql-prep/lib/stoplight-r2-12x25.gif b/postgresql-prep/src/stage/opt/app/postgresql-prep/lib/stoplight-r2-12x25.gif
new file mode 100644
index 0000000..ff26986
--- /dev/null
+++ b/postgresql-prep/src/stage/opt/app/postgresql-prep/lib/stoplight-r2-12x25.gif
Binary files differ
diff --git a/postgresql-prep/src/stage/opt/app/postgresql-prep/lib/stoplight-r3-12x25.gif b/postgresql-prep/src/stage/opt/app/postgresql-prep/lib/stoplight-r3-12x25.gif
new file mode 100644
index 0000000..daa6960
--- /dev/null
+++ b/postgresql-prep/src/stage/opt/app/postgresql-prep/lib/stoplight-r3-12x25.gif
Binary files differ
diff --git a/postgresql-prep/src/stage/opt/app/postgresql-prep/lib/stoplight-secondary-green.gif b/postgresql-prep/src/stage/opt/app/postgresql-prep/lib/stoplight-secondary-green.gif
new file mode 100644
index 0000000..c6d33b5
--- /dev/null
+++ b/postgresql-prep/src/stage/opt/app/postgresql-prep/lib/stoplight-secondary-green.gif
Binary files differ
diff --git a/postgresql-prep/src/stage/opt/app/postgresql-prep/lib/stoplight-secondary-red.gif b/postgresql-prep/src/stage/opt/app/postgresql-prep/lib/stoplight-secondary-red.gif
new file mode 100644
index 0000000..ab16a81
--- /dev/null
+++ b/postgresql-prep/src/stage/opt/app/postgresql-prep/lib/stoplight-secondary-red.gif
Binary files differ
diff --git a/postgresql-prep/src/stage/opt/app/postgresql-prep/lib/stoplight-secondary-yellow.gif b/postgresql-prep/src/stage/opt/app/postgresql-prep/lib/stoplight-secondary-yellow.gif
new file mode 100644
index 0000000..5e16750
--- /dev/null
+++ b/postgresql-prep/src/stage/opt/app/postgresql-prep/lib/stoplight-secondary-yellow.gif
Binary files differ
diff --git a/postgresql-prep/src/stage/opt/app/postgresql-prep/lib/stoplight-y-12x25.gif b/postgresql-prep/src/stage/opt/app/postgresql-prep/lib/stoplight-y-12x25.gif
new file mode 100644
index 0000000..4f95bf0
--- /dev/null
+++ b/postgresql-prep/src/stage/opt/app/postgresql-prep/lib/stoplight-y-12x25.gif
Binary files differ
diff --git a/postgresql-prep/src/stage/opt/app/postgresql-prep/lib/stoplight-y2-12x25.gif b/postgresql-prep/src/stage/opt/app/postgresql-prep/lib/stoplight-y2-12x25.gif
new file mode 100644
index 0000000..886e548
--- /dev/null
+++ b/postgresql-prep/src/stage/opt/app/postgresql-prep/lib/stoplight-y2-12x25.gif
Binary files differ
diff --git a/postgresql-prep/src/stage/opt/app/postgresql-prep/lib/stoplight-y3-12x25.gif b/postgresql-prep/src/stage/opt/app/postgresql-prep/lib/stoplight-y3-12x25.gif
new file mode 100644
index 0000000..1bd8731
--- /dev/null
+++ b/postgresql-prep/src/stage/opt/app/postgresql-prep/lib/stoplight-y3-12x25.gif
Binary files differ
diff --git a/postgresql-prep/src/stage/opt/app/postgresql-prep/lib/yellow-flasher-12x10.gif b/postgresql-prep/src/stage/opt/app/postgresql-prep/lib/yellow-flasher-12x10.gif
new file mode 100644
index 0000000..5e16750
--- /dev/null
+++ b/postgresql-prep/src/stage/opt/app/postgresql-prep/lib/yellow-flasher-12x10.gif
Binary files differ
diff --git a/postgresql-prep/src/testlock/.gitignore b/postgresql-prep/src/testlock/.gitignore
new file mode 100644
index 0000000..0618485
--- /dev/null
+++ b/postgresql-prep/src/testlock/.gitignore
@@ -0,0 +1 @@
+testlock
diff --git a/postgresql-prep/src/testlock/makefile b/postgresql-prep/src/testlock/makefile
new file mode 100644
index 0000000..c3bbb7a
--- /dev/null
+++ b/postgresql-prep/src/testlock/makefile
@@ -0,0 +1,56 @@
+# 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: testlock
+
+TESTLOCK=./testlock
+
+ttestlock: testlock
+ @echo;echo should print usage list
+ -$(TESTLOCK)
+ @echo;echo should print usage list
+ -$(TESTLOCK) -?
+ @echo;echo should print missing lock filename
+ -$(TESTLOCK) -t 0
+ @echo;echo should print missing command
+ -$(TESTLOCK) -t 0 /var/tmp/tl
+ @echo;echo should run immediately
+ $(TESTLOCK) -t 0 /var/tmp/tl /bin/echo hello
+ @echo;echo grab lock, done SHOULD run after lock becomes available
+ date;$(TESTLOCK) /var/tmp/tl sleep 5 & sleep 1; $(TESTLOCK) /var/tmp/tl /bin/echo done;date
+ $(TESTLOCK) /var/tmp/tl true # cleanup
+ @echo;echo grab lock, not waiting should NOT run
+ date;$(TESTLOCK) /var/tmp/tl sleep 5 & sleep 1; $(TESTLOCK) -t 0 /var/tmp/tl /bin/echo not waiting;date
+ $(TESTLOCK) /var/tmp/tl true # cleanup
+ @echo;echo grab lock, echo should NOT run because lock does not become available in 4 seconds
+ date;$(TESTLOCK) /var/tmp/tl sleep 5 & sleep 1; $(TESTLOCK) -t 3 /var/tmp/tl /bin/echo waiting up to 3 seconds;date
+ $(TESTLOCK) /var/tmp/tl true # cleanup
+ @echo;echo grab lock, echo should SILENTLY NOT run because lock does not become available in 4 seconds
+ date;$(TESTLOCK) /var/tmp/tl sleep 5 & sleep 1; $(TESTLOCK) -t 3 -s /var/tmp/tl /bin/echo waiting up to 3 seconds;date
+ $(TESTLOCK) /var/tmp/tl true # cleanup
+ @echo;echo grab lock, echo SHOULD run after lock becomes available in 5 seconds
+ date;$(TESTLOCK) /var/tmp/tl sleep 5 & sleep 1; $(TESTLOCK) -t 10 /var/tmp/tl /bin/echo waiting up to 10 seconds;date
+ $(TESTLOCK) /var/tmp/tl true # cleanup
+
+testlock: testlock.c
+ gcc -o testlock testlock.c
+
+clean:
+ rm -f *~
+
+clobber: clean
+ rm -f testlock
+
+stage: testlock
+ cp -p testlock ../postgresql-prep/Linux/dist_files/opt/app/postgresql-prep/bin/
diff --git a/postgresql-prep/src/testlock/testlock.1 b/postgresql-prep/src/testlock/testlock.1
new file mode 100644
index 0000000..12dbb9d
--- /dev/null
+++ b/postgresql-prep/src/testlock/testlock.1
@@ -0,0 +1,38 @@
+'\" 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 testlock 1 "April 26 2006" "" ""
+.SH NAME
+testlock \- lock a file and run a command with the lock held
+.SH SYNOPSIS
+testlock [-v] [-t timeout] [-s] [-r exittcode] filename command args ...
+.SH DESCRIPTION
+.PP
+Testlock will acquire a file lock and then execute a command while the lock is held.
+If no timeout is provided, testlock will wait indefinitely until the file can be locked,
+and then execute the command.
+If a timeout is given, it will stop waiting after that many seconds have passed.
+.SS Options
+.IP -t
+Abort if the lock cannot be acquired after
+.I timeout
+seconds.
+If
+.I timeout
+is 0, the lock will be totally non-blocking.
+.IP -s
+Silently ignore errors with locking.
+(Other errors will still be reported.)
+.IP -r exitcode
+If the lock cannot be acquired, use this exit code instead of the default exit code of 99.
+.SH AUTHOR
+Tony Hansen.
diff --git a/postgresql-prep/src/testlock/testlock.c b/postgresql-prep/src/testlock/testlock.c
new file mode 100644
index 0000000..41bea59
--- /dev/null
+++ b/postgresql-prep/src/testlock/testlock.c
@@ -0,0 +1,110 @@
+/*
+ Usage: testlock [-t timeout] [-s] filename command args ...
+
+ 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.
+
+*/
+
+#include <sys/file.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <string.h>
+
+void usage(const char *prog0, const char *msg)
+{
+ if (msg) fprintf(stderr, "%s\n", msg);
+ fprintf(stderr, "Usage: %s [-v] [-t timeout] [-s] [-r retcode] lock-filename command args ...\n", prog0);
+ fprintf(stderr, "-t ##\thow long to wait for a lock to be freed. 0 means exit immediately\n");
+ fprintf(stderr, "-s\tsilently ignore errors with locking\n");
+ fprintf(stderr, "-r ##\texit with this code when the lock fails\n");
+ fprintf(stderr, "-v\tbe verbose\n");
+ fprintf(stderr, "Note:\tlock-filename is created (if it does not exist) and truncated before locking.\n");
+ fprintf(stderr, "\tlock-filename is not removed after the command finishes\n");
+ exit(1);
+}
+
+int main(int argc, char **argv)
+{
+ const char *prog0 = argv[0];
+
+ int c;
+ int timeout = -1;
+ bool silent = false;
+ bool verbose = false;
+ int nolockret = 99;
+
+ while ((c = getopt(argc, argv, "t:r:sv?")) != -1) {
+ switch (c) {
+ case 's': silent = true; break;
+ case 't': timeout = atoi(optarg); break;
+ case 'r': nolockret = atoi(optarg); break;
+ case 'v': verbose = true; break;
+ default: usage(prog0, NULL);
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if (argc < 1) {
+ usage(prog0, "Missing lock filename");
+ } else if (argc < 2) {
+ usage(prog0, "Missing command to run");
+ }
+
+ const char *lockFilename = *argv++;
+ if (verbose) printf("lockfilename=%s\n", lockFilename);
+
+ int lockfd = creat(lockFilename, 0666);
+ if (lockfd < 0) {
+ fprintf(stderr, "Cannot open %s: %s\n", lockFilename, strerror(errno));
+ exit(2);
+ }
+
+ if (timeout < 0) {
+ /* wait forever */
+ lockf(lockfd, F_LOCK, 0);
+ } else {
+ /* try each second (for up to timeout seconds) to get the lock */
+ int lockret = lockf(lockfd, F_TLOCK, 0);
+ int count = 0;
+ while ((lockret < 0) && (count++ < timeout)) {
+ sleep(1);
+ lockret = lockf(lockfd, F_TLOCK, 0);
+ }
+ if (lockret < 0) {
+ if (!silent) {
+ fprintf(stderr, "Cannot lock %s: %s\n", lockFilename, strerror(errno));
+ }
+ exit(nolockret);
+ }
+ }
+
+ /* now execute the given command */
+ if (verbose) {
+ char **a = argv;
+ printf("calling program '%s'\n", *a);
+ while (*++a) {
+ printf("with argument '%s'\n", *a);
+ }
+ }
+ execvp(argv[0], argv);
+}
diff --git a/postgresql-prep/src/testlock/testlock.md b/postgresql-prep/src/testlock/testlock.md
new file mode 100644
index 0000000..8ec2a48
--- /dev/null
+++ b/postgresql-prep/src/testlock/testlock.md
@@ -0,0 +1,27 @@
+# testlock 1 "April 26 2006" "" ""
+## NAME
+testlock \- lock a file and run a command with the lock held
+## SYNOPSIS
+testlock [-v] [-t timeout] [-s] [-r exittcode] filename command args ...
+## DESCRIPTION
+
+Testlock will acquire a file lock and then execute a command while the lock is held.
+If no timeout is provided, testlock will wait indefinitely until the file can be locked,
+and then execute the command.
+If a timeout is given, it will stop waiting after that many seconds have passed.
+
+### Options
+
+-t
+Abort if the lock cannot be acquired after _timeout_ seconds.
+If _timeout_ is 0, the lock will be totally non-blocking.
+
+-s
+Silently ignore errors with locking.
+(Other errors will still be reported.)
+
+-r exitcode
+If the lock cannot be acquired, use this exit code instead of the default exit code of 99.
+
+## AUTHOR
+Tony Hansen.