diff options
201 files changed, 12924 insertions, 0 deletions
diff --git a/.gitreview b/.gitreview new file mode 100644 index 0000000..e6f5926 --- /dev/null +++ b/.gitreview @@ -0,0 +1,4 @@ +[gerrit] +host=gerrit.onap.org +port=29418 +project=ccsdk/storage/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/src/cdf-prop-value/README.md b/cdf/src/cdf-prop-value/README.md new file mode 100644 index 0000000..f83617e --- /dev/null +++ b/cdf/src/cdf-prop-value/README.md @@ -0,0 +1,53 @@ +org.onap.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 Binary files differnew file mode 100644 index 0000000..8105152 --- /dev/null +++ b/cdf/src/cdf-prop-value/buildjars/gnu_getopt.jar 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..43fcf50 --- /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.onap.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.onap.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/javadocs.built b/cdf/src/cdf-prop-value/cdf-prop-value/src/main/java/javadocs.built new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/cdf/src/cdf-prop-value/cdf-prop-value/src/main/java/javadocs.built 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..f3deade --- /dev/null +++ b/cdf/src/cdf-prop-value/cdf-prop-value/src/main/java/makefile @@ -0,0 +1,31 @@ +go=../../../../buildjars/gnu_getopt.jar +cu=../../../../cdf-util/src/main/java/cdf-util.jar + +.SUFFIXES= .class + +JAVA=org/onap/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 javadoc.built + +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: javadocs.built +javadocs.built: cdf-prop-value.jar + rm -rf javadoc + mkdir -p javadoc + javadoc -d javadoc -classpath $(go):$(cu) $(JAVA) + touch javadocs.built diff --git a/cdf/src/cdf-prop-value/cdf-prop-value/src/main/java/org/onap/dcae/cdf/.gitignore b/cdf/src/cdf-prop-value/cdf-prop-value/src/main/java/org/onap/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/onap/dcae/cdf/.gitignore @@ -0,0 +1 @@ +*.class diff --git a/cdf/src/cdf-prop-value/cdf-prop-value/src/main/java/org/onap/dcae/cdf/CdfPropValue.java b/cdf/src/cdf-prop-value/cdf-prop-value/src/main/java/org/onap/dcae/cdf/CdfPropValue.java new file mode 100644 index 0000000..cd9a51c --- /dev/null +++ b/cdf/src/cdf-prop-value/cdf-prop-value/src/main/java/org/onap/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.onap.dcae.cdf; + +import org.onap.dcae.cdf.util.config.PropValue; +import java.util.logging.Logger; +import org.onap.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/onap/dcae/cdf/cdfpropvalue/AppTest.java b/cdf/src/cdf-prop-value/cdf-prop-value/src/test/java/org/onap/dcae/cdf/cdfpropvalue/AppTest.java new file mode 100644 index 0000000..64753bd --- /dev/null +++ b/cdf/src/cdf-prop-value/cdf-prop-value/src/test/java/org/onap/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.onap.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..ed89368 --- /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.onap.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/makefile b/cdf/src/cdf-prop-value/cdf-util/src/main/java/makefile new file mode 100644 index 0000000..268770c --- /dev/null +++ b/cdf/src/cdf-prop-value/cdf-util/src/main/java/makefile @@ -0,0 +1,49 @@ + +go=../../../../buildjars/gnu_getopt.jar + +.SUFFIXES= .class + +JAVA= org/onap/dcae/cdf/util/common/Classify.java \ + org/onap/dcae/cdf/util/common/Tuple3.java \ + org/onap/dcae/cdf/util/common/AsHex.java \ + org/onap/dcae/cdf/util/common/G2CookieGen.java \ + org/onap/dcae/cdf/util/common/Compress.java \ + org/onap/dcae/cdf/util/common/Pair.java \ + org/onap/dcae/cdf/util/common/Tuple4.java \ + org/onap/dcae/cdf/util/common/Hostname.java \ + org/onap/dcae/cdf/util/common/Uid.java \ + org/onap/dcae/cdf/util/common/Tuple2.java \ + org/onap/dcae/cdf/util/common/Pid.java \ + org/onap/dcae/cdf/util/common/Convert.java \ + org/onap/dcae/cdf/util/common/Popen.java \ + org/onap/dcae/cdf/util/config/PropValue.java \ + org/onap/dcae/cdf/util/config/Configuration.java \ + org/onap/dcae/cdf/util/config/EncryptedConfiguration.java \ + org/onap/dcae/cdf/util/config/Configurable.java \ + org/onap/dcae/cdf/util/config/ConfigurationRegistry.java \ + org/onap/dcae/cdf/util/threads/TaskThread.java \ + org/onap/dcae/cdf/util/threads/ThreadUtils.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 javadocs.built + +$(CLASSES): $(JAVA) + javac -cp $(go) $(JAVA) + +javadocs: javadocs.built +javadocs.built: cdf-util.jar + rm -rf javadoc + mkdir -p javadoc + javadoc -d javadoc -classpath $(go) $(JAVA) + touch javadocs.built diff --git a/cdf/src/cdf-prop-value/cdf-util/src/main/java/org/onap/dcae/cdf/util/common/.gitignore b/cdf/src/cdf-prop-value/cdf-util/src/main/java/org/onap/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/onap/dcae/cdf/util/common/.gitignore @@ -0,0 +1 @@ +*.class diff --git a/cdf/src/cdf-prop-value/cdf-util/src/main/java/org/onap/dcae/cdf/util/common/AsHex.java b/cdf/src/cdf-prop-value/cdf-util/src/main/java/org/onap/dcae/cdf/util/common/AsHex.java new file mode 100644 index 0000000..05d8f37 --- /dev/null +++ b/cdf/src/cdf-prop-value/cdf-util/src/main/java/org/onap/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.onap.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/onap/dcae/cdf/util/common/Classify.java b/cdf/src/cdf-prop-value/cdf-util/src/main/java/org/onap/dcae/cdf/util/common/Classify.java new file mode 100644 index 0000000..e0b9203 --- /dev/null +++ b/cdf/src/cdf-prop-value/cdf-util/src/main/java/org/onap/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.onap.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/onap/dcae/cdf/util/common/Compress.java b/cdf/src/cdf-prop-value/cdf-util/src/main/java/org/onap/dcae/cdf/util/common/Compress.java new file mode 100644 index 0000000..86ff60b --- /dev/null +++ b/cdf/src/cdf-prop-value/cdf-util/src/main/java/org/onap/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.onap.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/onap/dcae/cdf/util/common/Convert.java b/cdf/src/cdf-prop-value/cdf-util/src/main/java/org/onap/dcae/cdf/util/common/Convert.java new file mode 100644 index 0000000..6182fde --- /dev/null +++ b/cdf/src/cdf-prop-value/cdf-util/src/main/java/org/onap/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.onap.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/onap/dcae/cdf/util/common/G2CookieGen.java b/cdf/src/cdf-prop-value/cdf-util/src/main/java/org/onap/dcae/cdf/util/common/G2CookieGen.java new file mode 100644 index 0000000..738fb3c --- /dev/null +++ b/cdf/src/cdf-prop-value/cdf-util/src/main/java/org/onap/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.onap.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/onap/dcae/cdf/util/common/Hostname.java b/cdf/src/cdf-prop-value/cdf-util/src/main/java/org/onap/dcae/cdf/util/common/Hostname.java new file mode 100644 index 0000000..4385c01 --- /dev/null +++ b/cdf/src/cdf-prop-value/cdf-util/src/main/java/org/onap/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.onap.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/onap/dcae/cdf/util/common/Pair.java b/cdf/src/cdf-prop-value/cdf-util/src/main/java/org/onap/dcae/cdf/util/common/Pair.java new file mode 100644 index 0000000..5a2a3f4 --- /dev/null +++ b/cdf/src/cdf-prop-value/cdf-util/src/main/java/org/onap/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.onap.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/onap/dcae/cdf/util/common/Pid.java b/cdf/src/cdf-prop-value/cdf-util/src/main/java/org/onap/dcae/cdf/util/common/Pid.java new file mode 100644 index 0000000..c405c44 --- /dev/null +++ b/cdf/src/cdf-prop-value/cdf-util/src/main/java/org/onap/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.onap.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/onap/dcae/cdf/util/common/Popen.java b/cdf/src/cdf-prop-value/cdf-util/src/main/java/org/onap/dcae/cdf/util/common/Popen.java new file mode 100644 index 0000000..d7f5846 --- /dev/null +++ b/cdf/src/cdf-prop-value/cdf-util/src/main/java/org/onap/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.onap.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/onap/dcae/cdf/util/common/Tuple2.java b/cdf/src/cdf-prop-value/cdf-util/src/main/java/org/onap/dcae/cdf/util/common/Tuple2.java new file mode 100644 index 0000000..f4fd441 --- /dev/null +++ b/cdf/src/cdf-prop-value/cdf-util/src/main/java/org/onap/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.onap.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/onap/dcae/cdf/util/common/Tuple3.java b/cdf/src/cdf-prop-value/cdf-util/src/main/java/org/onap/dcae/cdf/util/common/Tuple3.java new file mode 100644 index 0000000..566f910 --- /dev/null +++ b/cdf/src/cdf-prop-value/cdf-util/src/main/java/org/onap/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.onap.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/onap/dcae/cdf/util/common/Tuple4.java b/cdf/src/cdf-prop-value/cdf-util/src/main/java/org/onap/dcae/cdf/util/common/Tuple4.java new file mode 100644 index 0000000..c41d64c --- /dev/null +++ b/cdf/src/cdf-prop-value/cdf-util/src/main/java/org/onap/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.onap.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/onap/dcae/cdf/util/common/Uid.java b/cdf/src/cdf-prop-value/cdf-util/src/main/java/org/onap/dcae/cdf/util/common/Uid.java new file mode 100644 index 0000000..99feeb3 --- /dev/null +++ b/cdf/src/cdf-prop-value/cdf-util/src/main/java/org/onap/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.onap.dcae.cdf.util.common; +import java.io.File; +import java.io.BufferedReader; +import java.io.FileReader; +import org.onap.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/onap/dcae/cdf/util/config/.gitignore b/cdf/src/cdf-prop-value/cdf-util/src/main/java/org/onap/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/onap/dcae/cdf/util/config/.gitignore @@ -0,0 +1 @@ +*.class diff --git a/cdf/src/cdf-prop-value/cdf-util/src/main/java/org/onap/dcae/cdf/util/config/Configurable.java b/cdf/src/cdf-prop-value/cdf-util/src/main/java/org/onap/dcae/cdf/util/config/Configurable.java new file mode 100644 index 0000000..29f709d --- /dev/null +++ b/cdf/src/cdf-prop-value/cdf-util/src/main/java/org/onap/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.onap.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/onap/dcae/cdf/util/config/Configuration.java b/cdf/src/cdf-prop-value/cdf-util/src/main/java/org/onap/dcae/cdf/util/config/Configuration.java new file mode 100644 index 0000000..db54276 --- /dev/null +++ b/cdf/src/cdf-prop-value/cdf-util/src/main/java/org/onap/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.onap.dcae.cdf.util.config; + +import java.io.*; +import java.util.*; +import java.net.*; +import java.util.logging.*; +import org.onap.dcae.cdf.util.common.*; +import org.onap.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 = ThreadUtils.getNamedThreads( 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/onap/dcae/cdf/util/config/ConfigurationRegistry.java b/cdf/src/cdf-prop-value/cdf-util/src/main/java/org/onap/dcae/cdf/util/config/ConfigurationRegistry.java new file mode 100644 index 0000000..f108ced --- /dev/null +++ b/cdf/src/cdf-prop-value/cdf-util/src/main/java/org/onap/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.onap.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/onap/dcae/cdf/util/config/EncryptedConfiguration.java b/cdf/src/cdf-prop-value/cdf-util/src/main/java/org/onap/dcae/cdf/util/config/EncryptedConfiguration.java new file mode 100644 index 0000000..3da0f42 --- /dev/null +++ b/cdf/src/cdf-prop-value/cdf-util/src/main/java/org/onap/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.onap.dcae.cdf.util.config; + +import java.util.logging.*; +// import java.lang.ref.*; +import org.onap.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/onap/dcae/cdf/util/config/PropValue.java b/cdf/src/cdf-prop-value/cdf-util/src/main/java/org/onap/dcae/cdf/util/config/PropValue.java new file mode 100644 index 0000000..efeabc5 --- /dev/null +++ b/cdf/src/cdf-prop-value/cdf-util/src/main/java/org/onap/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.onap.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.onap.dcae.cdf.util.config.Configuration; +import org.onap.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/onap/dcae/cdf/util/threads/.gitignore b/cdf/src/cdf-prop-value/cdf-util/src/main/java/org/onap/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/onap/dcae/cdf/util/threads/.gitignore @@ -0,0 +1 @@ +*.class diff --git a/cdf/src/cdf-prop-value/cdf-util/src/main/java/org/onap/dcae/cdf/util/threads/TaskThread.java b/cdf/src/cdf-prop-value/cdf-util/src/main/java/org/onap/dcae/cdf/util/threads/TaskThread.java new file mode 100644 index 0000000..97d1520 --- /dev/null +++ b/cdf/src/cdf-prop-value/cdf-util/src/main/java/org/onap/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.onap.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/onap/dcae/cdf/util/threads/ThreadUtils.java b/cdf/src/cdf-prop-value/cdf-util/src/main/java/org/onap/dcae/cdf/util/threads/ThreadUtils.java new file mode 100644 index 0000000..34afebe --- /dev/null +++ b/cdf/src/cdf-prop-value/cdf-util/src/main/java/org/onap/dcae/cdf/util/threads/ThreadUtils.java @@ -0,0 +1,89 @@ +/* + 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.onap.dcae.cdf.util.threads; + +import java.util.LinkedList; +import java.util.List; + +/** + * Various utility functions dealing with threads + */ +public class ThreadUtils { + /** + * Get a list of all threads. + * + * @return an array of threads + */ + public static Thread[] getAllThreads() { + ThreadGroup rootGroup = getRootGroup(); + int noThreads = rootGroup.activeCount(); // returns an estimated count of active threads + Thread[] threads = new Thread[noThreads + 1]; + rootGroup.enumerate(threads); + + while ( rootGroup.enumerate( threads, true ) == threads.length ) { // iterate if we filled up the array + threads = new Thread[ threads.length + noThreads ]; + } + // remove null threads + LinkedList<Thread> lthreads = new LinkedList<Thread>(); + for (Thread thread: threads) + if (thread != null) + lthreads.push(thread); + return lthreads.toArray(new Thread[0]); + } + + /** + * Get a list of all threads with a given thread name. + * + * @param name the name to look for + * @return an array of threads with that name + */ + public static Thread[] getNamedThreads(final String name) { + Thread[] allThreads = getAllThreads(); + LinkedList<Thread> lthreads = new LinkedList<Thread>(); + for (Thread thread: allThreads) + if (thread.getName().equals(name)) + lthreads.push(thread); + + return lthreads.toArray(new Thread[0]); + } + + /** + * Get the ultimate root of the threads + * + * @return the root thread + */ + public static ThreadGroup getRootGroup() { + ThreadGroup rootGroup = Thread.currentThread( ).getThreadGroup( ); + ThreadGroup parentGroup; + while ( ( parentGroup = rootGroup.getParent() ) != null ) { + rootGroup = parentGroup; + } + return rootGroup; + } + + public static void main(String args[]) throws Exception { + System.out.println("==== get Root Threads ===="); + System.out.println("Root thread = " + getRootGroup().getName()); + System.out.println("==== get All Threads ===="); + Thread[] threads = getAllThreads(); + for (int i = 0; i < threads.length; i++) + System.out.println("Thread No:" + i + " = " + threads[i].getName()); + System.out.println("==== getNamedThreads(main) ===="); + threads = getNamedThreads("main"); + for (int i = 0; i < threads.length; i++) + System.out.println("Thread No:" + i + " = " + threads[i].getName()); + } +} diff --git a/cdf/src/cdf-prop-value/cdf-util/src/test/java/org/onap/dcae/cdf/util/AppTest.java b/cdf/src/cdf-prop-value/cdf-util/src/test/java/org/onap/dcae/cdf/util/AppTest.java new file mode 100644 index 0000000..60467c9 --- /dev/null +++ b/cdf/src/cdf-prop-value/cdf-util/src/test/java/org/onap/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.onap.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..875b535 --- /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 ONAP=false NOTONAP=true +else export ONAP=true NOTONAP=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 $NOTONAP +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..fdd7748 --- /dev/null +++ b/cdf/src/makefile @@ -0,0 +1,53 @@ + +DEVBIN=../../bin +PKG=cdf +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 *~ + 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 -p cdf-prop-value/cdf-prop-value/src/main/java/cdf-prop-value.jar $(INS)/stage/opt/app/cdf/lib/cdf-prop-value-1.1.0.jar + cp -p cdf-prop-value/cdf-prop-value/src/main/java/cdf-prop-value.jar $(INS)/stage/opt/app/cdf/lib/cdf-prop-value.jar + cp -p cdf-prop-value/cdf-util/src/main/java/cdf-util.jar $(INS)/stage/opt/app/cdf/lib/jars/cdf-util-1.1.0.jar + cp -p cdf-prop-value/cdf-util/src/main/java/cdf-util.jar $(INS)/stage/opt/app/cdf/lib/jars/cdf-util.jar + chmod a+x $(INSCOM)/* + + +debian: stage + sed 's/$${RELLONG}/$(RELLONG)/' < repackage.yaml > $(INS)/repackage.yaml + repackage -b debian $(REPACKAGEDEBIANOPTS) -d $(INS) -u -M "{datetime},LATEST" -y $(INS)/repackage.yaml + @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 "$${ONAP_NEXUS_USER}:$${ONAP_NEXUS_PASSWORD}" --upload-file "$$f" "$${ONAP_NEXUS_JAVADOC}/org.onap.dcae.storage.cdf/1.1.0/$$f"; \ + done + diff --git a/cdf/src/repackage.json b/cdf/src/repackage.json new file mode 100644 index 0000000..4618183 --- /dev/null +++ b/cdf/src/repackage.json @@ -0,0 +1,29 @@ +{ + "debian": { + "groupId": "org.onap.dcae.storage.pgaas", + "conflicts": [], + "replaces": [], + "externalDependencies": [ + { + "libgetopt-java": ">= 1.0.14" + } + ] + }, + "fileGroup": "postgres", + "internalDependencies": [], + "fileUser": "postgres", + "executionUser": "postgres", + "executionGroup": "postgres", + "docker": { + "tag": "latest", + "externalDependencies": [] + }, + "version": "${RELLONG}", + "directoryTreeTops": { + "/opt": "/opt/app/cdf" + }, + "maintainer": "ONAP <dcae@lists.onap.org>", + "groupId": "org.onap.dcae.storage.pgaas", + "applicationName": "cdf", + "description": " PostgreSQL as a Service main scripts " +}
\ 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..78a74b2 --- /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.jar:$CDF/lib/jars/cdf-util.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.onap.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..c60fbad --- /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.jar:$CDF/lib/jars/cdf-util.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.onap.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..df92dbc --- /dev/null +++ b/makefile @@ -0,0 +1,31 @@ + +all: + +STAGEDIRS=cdf pgaas + +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 + + + +pgaas: +generate-sources: +compile: build + +test: + # should run unit tests here +package: +install: diff --git a/pgaas/src/common/postinst b/pgaas/src/common/postinst new file mode 100755 index 0000000..f98f6f6 --- /dev/null +++ b/pgaas/src/common/postinst @@ -0,0 +1,58 @@ +#!/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 ONAP=false NOTONAP=true +else export ONAP=true NOTONAP=false +fi +id + +if $ONAP +then INSTALL_ROOT= +fi + +echo STARTING $0 $(date) +umask 0 +echo STARTING $0 $(date) >> /tmp/pgaas.inst.report + +export CFGDIR=${INSTALL_ROOT}/opt/app/pgaas + +ret=0 + +if $CFGDIR/etc/do-post-install-prep +then + if su postgres -c $CFGDIR/etc/do-post-install-config + then + if su postgres -c $CFGDIR/etc/do-post-install-tools + then + if $CFGDIR/etc/do-post-install-post + then : + else echo do-post-install-post failed; ret=1 + fi + else echo do-post-install-tools failed; ret=1 + fi + else echo do-post-install-config failed; ret=1 + fi +else echo do-post-install-prep failed; ret=1 +fi + +echo ENDING $0 $(date) +echo ENDING $0 $(date) >> /tmp/pgaas.inst.report +if $NOTONAP +then sed -n '/^STARTING/,/^ENDING/p' `dirname $0`/../../proc_out >> /tmp/pgaas.inst.report +fi +exit $ret diff --git a/pgaas/src/makefile b/pgaas/src/makefile new file mode 100644 index 0000000..299c14c --- /dev/null +++ b/pgaas/src/makefile @@ -0,0 +1,48 @@ + +DEVBIN=../../bin +PKG=pgaas +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-testlock: + cd testlock && $(MAKE) clobber + +clean: clean-ins clean-testlock + rm -rf *~ + +testlock/testlock: + cd testlock && $(MAKE) testlock + +build: testlock/testlock + +stage: build clean-stage clean-common + mkdir -p $(INS) + cd stage/opt/app/pgaas && $(MAKE) stage STAGEDIR=../../../../$(INSSTG) + cd testlock && $(MAKE) stage STAGEDIR=../$(INSSTG) DISTPATH=opt/app/pgaas + find common ! -name makefile ! -name '*~' | cpio -pudmv $(INS) + + +debian: stage + sed 's/$${RELLONG}/$(RELLONG)/' < repackage.yaml > $(INS)/repackage.yaml + # repackage -b debian $(REPACKAGEDEBIANOPTS) -d $(INS) -u -M "{datetime},LATEST" -y $(INS)/repackage.yaml + repackage -b debian $(REPACKAGEDEBIANOPTS) -d $(INS) -u -M "LATEST" -y $(INS)/repackage.yaml + @echo debian built + +upload-javadocs: + @echo nothing to do here + diff --git a/pgaas/src/nohup.out b/pgaas/src/nohup.out new file mode 100644 index 0000000..cb1787b --- /dev/null +++ b/pgaas/src/nohup.out @@ -0,0 +1,196 @@ +rm -rf ../install/stage +rm -rf ../install/common +mkdir -p ../install +cd stage/opt/app/pgaas && make stage STAGEDIR=../../../../../install/stage +make[1]: Entering directory `/home/th1395/pgaas/com.att.ecomp.dcae.storage/PGaaS/pgaas/src/stage/opt/app/pgaas' +for i in bin lib etc man init main; do \ + ( cd $i && make stage STAGEDIR=../../../../../../install/stage ) \ + done +make[2]: Entering directory `/home/th1395/pgaas/com.att.ecomp.dcae.storage/PGaaS/pgaas/src/stage/opt/app/pgaas/bin' +rm -rf ../../../../../../install/stage//opt/app/pgaas/bin +mkdir -p ../../../../../../install/stage//opt/app/pgaas/bin +for i in *; do \ + case $i in \ + *.py ) \ + j=`basename $i .py`; \ + cp $i ../../../../../../install/stage//opt/app/pgaas/bin/$j; \ + chmod a+x ../../../../../../install/stage//opt/app/pgaas/bin/$j; \ + ;; \ + makefile | *~ ) ;; \ + * ) \ + if [ -f $i ]; then \ + cp $i ../../../../../../install/stage//opt/app/pgaas/bin/$i; \ + chmod a+x ../../../../../../install/stage//opt/app/pgaas/bin/$i; \ + fi; \ + ;; \ + esac; \ + done +make[2]: Leaving directory `/home/th1395/pgaas/com.att.ecomp.dcae.storage/PGaaS/pgaas/src/stage/opt/app/pgaas/bin' +make[2]: Entering directory `/home/th1395/pgaas/com.att.ecomp.dcae.storage/PGaaS/pgaas/src/stage/opt/app/pgaas/lib' +rm -rf ../../../../../../install/stage//opt/app/pgaas/lib +mkdir -p ../../../../../../install/stage//opt/app/pgaas/lib +for i in *; do \ + case $i in \ + *.py ) \ + j=`basename $i .py`; \ + cp $i ../../../../../../install/stage//opt/app/pgaas/lib/$j; \ + chmod a+x ../../../../../../install/stage//opt/app/pgaas/lib/$j; \ + ;; \ + makefile | *~ ) ;; \ + * ) \ + if [ -f $i ]; then \ + cp $i ../../../../../../install/stage//opt/app/pgaas/lib/$i; \ + chmod a+x ../../../../../../install/stage//opt/app/pgaas/lib/$i; \ + fi; \ + ;; \ + esac; \ + done +make[2]: Leaving directory `/home/th1395/pgaas/com.att.ecomp.dcae.storage/PGaaS/pgaas/src/stage/opt/app/pgaas/lib' +make[2]: Entering directory `/home/th1395/pgaas/com.att.ecomp.dcae.storage/PGaaS/pgaas/src/stage/opt/app/pgaas/etc' +rm -rf ../../../../../../install/stage//opt/app/pgaas/etc +mkdir -p ../../../../../../install/stage//opt/app/pgaas/etc +for i in *; do \ + case $i in \ + *.py | gen*.conf ) \ + j=`basename $i .py`; \ + cp $i ../../../../../../install/stage//opt/app/pgaas/etc/$j; \ + chmod a+x ../../../../../../install/stage//opt/app/pgaas/etc/$j; \ + ;; \ + *.conf | *.cfg | *.cnf | *.sql ) \ + cp $i ../../../../../../install/stage//opt/app/pgaas/etc/$i; \ + chmod a+r ../../../../../../install/stage//opt/app/pgaas/etc/$i; \ + ;; \ + makefile | *~ ) ;; \ + * ) \ + if [ -f $i ]; then \ + cp $i ../../../../../../install/stage//opt/app/pgaas/etc/$i; \ + chmod a+rx ../../../../../../install/stage//opt/app/pgaas/etc/$i; \ + fi; \ + ;; \ + esac; \ + done +make[2]: Leaving directory `/home/th1395/pgaas/com.att.ecomp.dcae.storage/PGaaS/pgaas/src/stage/opt/app/pgaas/etc' +make[2]: Entering directory `/home/th1395/pgaas/com.att.ecomp.dcae.storage/PGaaS/pgaas/src/stage/opt/app/pgaas/man' +rm -rf ../../../../../../install/stage//opt/app/pgaas/man +mkdir -p ../../../../../../install/stage//opt/app/pgaas/man +cp -p check_cluster.1 dcae_admin_db.1 isrw.1 list_masters.1 pg_ctl_promote.1 pg_ctl_restart.1 pg_ctl_start.1 pg_ctl_status.1 pg_ctl_stop.1 repmgrc.1 repmgrdc.1 runpsqll.1 runpsql.1 setpropvalue.1 show_pg_is_in_recovery.1 show_pg_stat_activity.1 show_pg_stat_archiver.1 show_pg_stat_bgwriter.1 show_pg_stat_database_conflicts.1 show_pg_stat_database.1 show_pg_statio_user_functions.1 show_pg_statio_user_indexes.1 show_pg_statio_user_sequences.1 show_pg_statio_user_tables.1 show_pg_stat_user_indexes.1 show_pg_stat_user_tables.1 start_maintenance_mode.1 startpsql.1 stop_maintenance_mode.1 update_var_run_isrw.1 ../../../../../../install/stage//opt/app/pgaas/man +make[2]: Leaving directory `/home/th1395/pgaas/com.att.ecomp.dcae.storage/PGaaS/pgaas/src/stage/opt/app/pgaas/man' +make[2]: Entering directory `/home/th1395/pgaas/com.att.ecomp.dcae.storage/PGaaS/pgaas/src/stage/opt/app/pgaas/init' +rm -rf ../../../../../../install/stage//opt/app/pgaas/init +mkdir -p ../../../../../../install/stage//opt/app/pgaas/init +for i in *; do \ + case $i in \ + *.py ) \ + j=`basename $i .py`; \ + cp $i ../../../../../../install/stage//opt/app/pgaas/init/$j; \ + chmod a+x ../../../../../../install/stage//opt/app/pgaas/init/$j; \ + ;; \ + makefile | *~ ) ;; \ + * ) \ + if [ -f $i ]; then \ + cp $i ../../../../../../install/stage//opt/app/pgaas/init/$i; \ + chmod a+x ../../../../../../install/stage//opt/app/pgaas/init/$i; \ + fi; \ + ;; \ + esac; \ + done +make[2]: Leaving directory `/home/th1395/pgaas/com.att.ecomp.dcae.storage/PGaaS/pgaas/src/stage/opt/app/pgaas/init' +make[2]: Entering directory `/home/th1395/pgaas/com.att.ecomp.dcae.storage/PGaaS/pgaas/src/stage/opt/app/pgaas/main' +rm -rf ../../../../../../install/stage//opt/app/pgaas/main +mkdir -p ../../../../../../install/stage//opt/app/pgaas/main +for i in *; do \ + case $i in \ + *.py ) \ + j=`basename $i .py`; \ + cp $i ../../../../../../install/stage//opt/app/pgaas/main/$j; \ + chmod a+x ../../../../../../install/stage//opt/app/pgaas/main/$j; \ + ;; \ + makefile | *~ ) ;; \ + * ) \ + if [ -f $i ]; then \ + cp $i ../../../../../../install/stage//opt/app/pgaas/main/$i; \ + chmod a+x ../../../../../../install/stage//opt/app/pgaas/main/$i; \ + fi; \ + ;; \ + esac; \ + done +make[2]: Leaving directory `/home/th1395/pgaas/com.att.ecomp.dcae.storage/PGaaS/pgaas/src/stage/opt/app/pgaas/main' +for i in lib/gif; do \ + ( cd $i && make stage STAGEDIR=../../../../../../../install/stage ) \ + done +make[2]: Entering directory `/home/th1395/pgaas/com.att.ecomp.dcae.storage/PGaaS/pgaas/src/stage/opt/app/pgaas/lib/gif' +mkdir -p ../../../../../../../install/stage//opt/app/pgaas/lib/gif +for i in *; do \ + case $i in \ + *.py ) \ + j=`basename $i .py`; \ + cp $i ../../../../../../../install/stage//opt/app/pgaas/lib/gif/$j; \ + chmod a+x ../../../../../../../install/stage//opt/app/pgaas/lib/gif/$j; \ + ;; \ + makefile | *~ ) ;; \ + * ) \ + cp $i ../../../../../../../install/stage//opt/app/pgaas/lib/gif/$i; \ + chmod a+x ../../../../../../../install/stage//opt/app/pgaas/lib/gif/$i; \ + ;; \ + esac; \ + done +make[2]: Leaving directory `/home/th1395/pgaas/com.att.ecomp.dcae.storage/PGaaS/pgaas/src/stage/opt/app/pgaas/lib/gif' +# ATT-ONLY CODE BEGIN +for i in bin/internal-only man/internal-only; do \ + ( cd $i && make stage STAGEDIR=../../../../../../../install/stage ) \ + done +make[2]: Entering directory `/home/th1395/pgaas/com.att.ecomp.dcae.storage/PGaaS/pgaas/src/stage/opt/app/pgaas/bin/internal-only' +mkdir -p ../../../../../../../install/stage//opt/app/pgaas/bin +for i in *; do \ + case $i in \ + *.py ) \ + j=`basename $i .py`; \ + cp $i ../../../../../../../install/stage//opt/app/pgaas/bin/$j; \ + chmod a+x ../../../../../../../install/stage//opt/app/pgaas/bin/$j; \ + ;; \ + makefile | *~ ) ;; \ + * ) \ + cp $i ../../../../../../../install/stage//opt/app/pgaas/bin/$i; \ + chmod a+x ../../../../../../../install/stage//opt/app/pgaas/bin/$i; \ + ;; \ + esac; \ + done +make[2]: Leaving directory `/home/th1395/pgaas/com.att.ecomp.dcae.storage/PGaaS/pgaas/src/stage/opt/app/pgaas/bin/internal-only' +make[2]: Entering directory `/home/th1395/pgaas/com.att.ecomp.dcae.storage/PGaaS/pgaas/src/stage/opt/app/pgaas/man/internal-only' +mkdir -p ../../../../../../../install/stage//opt/app/pgaas/man +cp -p rotate_db_tables.1 vi_proc_out.1 ../../../../../../../install/stage//opt/app/pgaas/man +make[2]: Leaving directory `/home/th1395/pgaas/com.att.ecomp.dcae.storage/PGaaS/pgaas/src/stage/opt/app/pgaas/man/internal-only' +# ATT-ONLY CODE END +make[1]: Leaving directory `/home/th1395/pgaas/com.att.ecomp.dcae.storage/PGaaS/pgaas/src/stage/opt/app/pgaas' +cd testlock && make stage STAGEDIR=../../install/stage DISTPATH=opt/app/pgaas +make[1]: Entering directory `/home/th1395/pgaas/com.att.ecomp.dcae.storage/PGaaS/pgaas/src/testlock' +cp -p testlock ../../install/stage/opt/app/pgaas/bin/testlock +chmod a+x ../../install/stage/opt/app/pgaas/bin/testlock +make[1]: Leaving directory `/home/th1395/pgaas/com.att.ecomp.dcae.storage/PGaaS/pgaas/src/testlock' +find common ! -name makefile ! -name '*~' | cpio -pudmv ../install +../install/common +../install/common/postinst +3 blocks +sed 's/${RELLONG}/17.10.0/' < repackage.yaml > ../install/repackage.yaml +repackage -b swm -d ../install -y ../install/repackage.yaml +0 blocks +Initializing... + +Component Type: SWM +Package Create Started for: com.att.ecomp.dcae.storage.pgaas:pgaas:17.10.0-20170629185041 +Preparing File Group [Linux] +Creating a singleton package +Creating bundle files +Publishing into inventory +Uploading to repository +Complete +-------------------------------------------------------------------------------- +Successful - Elapsed Time Millis: [7581] +-------------------------------------------------------------------------------- +Initializing... + +-------------------------------------------------------------------------------- +Successful - Elapsed Time Millis: [4992] +-------------------------------------------------------------------------------- +2017-06-29 18:50:41:INFO:Building a SWM package ... +../../bin/mark-swm-repackage 17.10.0 diff --git a/pgaas/src/repackage.json b/pgaas/src/repackage.json new file mode 100644 index 0000000..faf7998 --- /dev/null +++ b/pgaas/src/repackage.json @@ -0,0 +1,32 @@ +{ + "maintainer": "ONAP <dcae@lists.onap.org>", + "version": "${RELLONG}", + "applicationName": "pgaas", + "internalDependencies": [], + "executionGroup": "root", + "debian": { + "externalDependencies": [ + { + "cdf": ">= ${RELLONG}" + }, + { + "postgresql": ">= 9.5" + } + ], + "conflicts": [], + "groupId": "org.onap.dcae.storage.pgaas", + "replaces": [] + }, + "docker": { + "externalDependencies": [], + "tag": "latest" + }, + "fileGroup": "postgres", + "directoryTreeTops": { + "/opt": "/opt/app/pgaas" + }, + "fileUser": "postgres", + "executionUser": "root", + "groupId": "org.onap.dcae.storage.pgaas", + "description": " PostgreSQL as a Service main scripts " +}
\ 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..ced7c0a --- /dev/null +++ b/pgaas/src/stage/opt/app/pgaas/bin/check_cluster @@ -0,0 +1,170 @@ +#!/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, down for maintenance, 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 +elif [ -d /usr/lib/postgresql/9.6 ] +then PGDIR=/usr/lib/postgresql/9.6 +elif [ -d /usr/lib/postgresql/9.5 ] +then PGDIR=/usr/lib/postgresql/9.5 +else echo PostgreSQL bin directory not found 1>&2; exit 1 +fi +PATH=$PGDIR/bin:$CDF/bin:/opt/app/pgaas/bin:$PATH + +usage() +{ + exec 1>&2 + [ $# -gt 0 ] && echo "$@" + echo "Usage: $0 [-v] [-l] [-t timeout] [-d file]" + 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" + echo -e " -d file duplicate the status output to the given file" + exit 1 +} + +VERBOSE=false +TIMEOUT=10 +TESTLOCAL=: +DFILE= +while getopts d:lt:v c +do + case "$c" in + d ) DFILE=$OPTARG ;; + 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 +maintenance_count=0 + +MASTERS= +SECONDARIES= +MAINTENANCES= +DOWNS= + +MSEP= +SSEP= +BSEP= +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 | Maintenance ) ;; + * ) + echo "$(date)|WARNING|RESTARTED|Local iDNS-responder not responding. Restarting." + ps -fu postgres | grep "python3 /opt/app/pgaas/lib/iDNS-responder" | 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=" " + ;; + Maintenance ) + (( maintenance_count = maintenance_count + 1 )) + (( total_count = total_count + 1 )) + MAINTENANCES="$MAINTENANCES$BSEP$i" + BSEP=" " + ;; + * ) + 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) +output="$date|INFO|masters=$master_count $MASTERS|secondaries=$secondary_count $SECONDARIES|maintenance=$maintenance_count $MAINTENANCES|down=$down_count $DOWNS|" +echo "$output" +if [ -n "$DFILE" ] +then (umask 022; echo "$output" > $DFILE.tmp && mv $DFILE.tmp $DFILE) +fi + +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..e1ac744 --- /dev/null +++ b/pgaas/src/stage/opt/app/pgaas/bin/dcae_admin_db.py @@ -0,0 +1,892 @@ +#!/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") +sys.path.append("/opt/app/dcae-commonlogging/python") +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("dcae_admin_db.py [options] newdb dbname admin-pswd user-pswd viewer-pswd") + 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) + elif args[0] == "newdb": + if len(args) != 5: + usage("wrong number of arguments") + newDb(keyedOptions, args[1], args[2], args[3], args[4]) + 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) + # does /var/run/postgresql/inmaintenance exist? -> YELLOW + cmdRepmgr = ["pgrep", "repmgrd"] + retRepmgr = runProgram(cmdRepmgr) + + msg = "????" + if os.path.isfile("/var/run/postgresql/inmaintenance"): + msg = "YELLOW: in maintenance mode" + elif 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") + + setupDictionaryDatabases(options, inp) + +def setupDictionaryDatabases(options, inp): + """ + Set up the databases listed in the dictionary + """ + + # 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 newDb(options, dbName, adminPswd, userPswd, viewerPswd): + """ + Given the database name and passwords, set up a database and corresponding users. + For example, with dbname="foo", adminPswd="fooa", userPswd="foou" and viewerPswd="foov", + act the same as if we had received the json configuration: + { + 'databases': { + 'foo': { + 'ownerRole': 'foo_admin', + 'roles': { + 'foo_admin': { + 'password': 'fooa', + 'role': 'admin' + }, + 'foo_user': { + 'password': 'foou', + 'role': 'writer' + }, + 'foo_viewer': { + 'password': 'foov', + 'role': 'reader' + } + } + } + } + } + """ + if not re.match("^[A-Za-z][A-Za-z0-9_]*$", dbName): + errorPrint("'%s' is not a valid database name" % dbName) + return + + adminName = dbName + "_admin" + userName = dbName + "_user" + viewerName = dbName + "_viewer" + + setupDictionaryDatabases(options, { + 'databases': { + dbName: { + 'ownerRole': adminName, + 'roles': { + adminName: { + 'password': adminPswd, + 'role': 'admin' + }, + userName: { + 'password': userPswd, + 'role': 'writer' + }, + viewerName: { + 'password': viewerPswd, + 'role': 'reader' + } + } + } + } + }) + +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/dump-designate-zone b/pgaas/src/stage/opt/app/pgaas/bin/dump-designate-zone new file mode 100755 index 0000000..5e9ff44 --- /dev/null +++ b/pgaas/src/stage/opt/app/pgaas/bin/dump-designate-zone @@ -0,0 +1,88 @@ +#!/usr/bin/env python3 +# 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 requests, sys, os, subprocess, argparse + +def checkstatus(resp, msg): + if resp.status_code >= 300: + print(resp) + print(resp.content) + raise Exception(msg) + +def reportrs(): + resp = requests.get('{0}/v2/zones/{1}/recordsets?limit=1000'.format(dns, zid), headers=osauth) + checkstatus(resp, 'Failed to list recordsets') + for rs in resp.json()['recordsets']: + tl = '' + if 'ttl' in rs and rs['ttl'] is not None: + tl = ' {0}'.format(rs['ttl']) + print('# {0}'.format(rs['id'])) + for r in rs['records']: + print('{0}{1} IN {2} {3}'.format(rs['name'], tl, rs['type'], r)) + +if __name__ == '__main__': + parser = argparse.ArgumentParser(description="Dump a Designate zone registration") + parser.add_argument("-a", "--authurl", type=str, help="Authentication URL), defaults to $DESIGNATEAUTHURL") + parser.add_argument("-t", "--tenantname", type=str, help="Tenant name") + parser.add_argument("-u", "--user", type=str, help="Username, defaults to $DESIGNATEUSER") # , default=os.environ.get('DESIGNATEUSER')) + parser.add_argument("-p", "--password", type=str, help="Password, defaults to $DESIGNATEPASSWORD") # , default=os.environ.get('DESIGNATEPASSWORD')) + parser.add_argument("-d", "--domain", type=str, help="Domain to search, defaults to $DESIGNATEDOMAIN") # , default=os.environ.get('DESIGNATEDOMAIN')) + parser.add_argument("-T", "--timeout", type=int, help="Timeout on requests, defaults to 120", default=120) # , default=os.environ.get('DESIGNATEDOMAIN')) + parser.add_argument("-v", "--verbose", help="turn on debugging", action="store_true") # , default=os.environ.get('DESIGNATEURL')) + args = parser.parse_args() + + def checkarg(arg, var, parms, dflt = None): + if not arg: arg = os.environ.get(var) + if not arg: arg = dflt + if not arg: exit(parms + "/$" + var + " not set") + return arg + + args.authurl = checkarg(args.authurl, "DESIGNATEAUTHURL", "-a/--authurl") + args.tenantname = checkarg(args.tenantname, "DESIGNATETENANTNAME", "-t/--tenantname") + args.user = checkarg(args.user, "DESIGNATEUSER", "-u/--user") + args.password = checkarg(args.password, "DESIGNATEPASSWORD", "-p/--password") + args.domain = checkarg(args.domain, "DESIGNATEDOMAIN", "-d/--domain", subprocess.run(['dnsdomainname'], stdout=subprocess.PIPE).stdout.decode('utf-8').rstrip()) + if not args.domain.endswith("."): args.domain = args.domain + "." + + print("Domain = {0}".format(args.domain)) + + resp = requests.post(args.authurl + '/tokens', json={'auth':{'tenantName': args.tenantname, 'passwordCredentials': {'username': args.user, 'password': args.password }}}, timeout=args.timeout) + checkstatus(resp, 'Failed to get identity token') + respj = resp.json()['access'] + osauth = {'X-Auth-Token': respj['token']['id'] } + dns = None + for se in respj['serviceCatalog']: + if se['type'] == 'dns': + dns = se['endpoints'][0]['publicURL'] + break + if not dns: + printf("No dns record found") + else: + print('DNS is {0}'.format(dns)) + + resp = requests.get('{0}/v2/zones'.format(dns), headers=osauth, timeout=args.timeout) + checkstatus(resp, 'Failed to list zones') + respj = resp.json()['zones'] + zid = None + for z in respj: + if args.verbose: print("Looking at %s" % z, file=sys.stderr) + if z['name'] == args.domain: + zid = z['id'] + break + + if not zid: + print("Domain {0} not found".format(args.domain)) + else: + print('Zone is {0}'.format(zid)) + reportrs() diff --git a/pgaas/src/stage/opt/app/pgaas/bin/gen-repmgr-info b/pgaas/src/stage/opt/app/pgaas/bin/gen-repmgr-info new file mode 100755 index 0000000..b210e58 --- /dev/null +++ b/pgaas/src/stage/opt/app/pgaas/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/pgaas/src/stage/opt/app/pgaas/bin/healthcheck_status b/pgaas/src/stage/opt/app/pgaas/bin/healthcheck_status new file mode 100644 index 0000000..4e99de0 --- /dev/null +++ b/pgaas/src/stage/opt/app/pgaas/bin/healthcheck_status @@ -0,0 +1,3 @@ +curl http://localhost:8000/healthcheck/status +curl http://localhost:8000/healthcheck/writablestatus +curl http://localhost:8000/healthcheck/readonlystatus 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..697a51f --- /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.onap.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..d9e925e --- /dev/null +++ b/pgaas/src/stage/opt/app/pgaas/bin/isrw @@ -0,0 +1,35 @@ +#!/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 +elif [ -d /usr/lib/postgresql/9.6 ] +then PGDIR=/usr/lib/postgresql/9.6 +elif [ -d /usr/lib/postgresql/9.5 ] +then PGDIR=/usr/lib/postgresql/9.5 +else echo PostgreSQL bin directory not found 1>&2; exit 1 +fi + +export PATH=$PATH:$PGDIR/bin:/opt/java/jdk/jdk170/bin:/opt/app/cdf/bin:/opt/app/pgaas/bin:$PATH + +if [ -f /var/run/postgresql/inmaintenance ] +then + echo "Maintenance" +else + case `show_pg_is_in_recovery` in + *f* ) echo "Master" ;; + *t* ) echo "Secondary" ;; + esac +fi 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..a5e4506 --- /dev/null +++ b/pgaas/src/stage/opt/app/pgaas/bin/list_masters @@ -0,0 +1,79 @@ +#!/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 +elif [ -d /usr/lib/postgresql/9.6 ] +then PGDIR=/usr/lib/postgresql/9.6 +elif [ -d /usr/lib/postgresql/9.5 ] +then PGDIR=/usr/lib/postgresql/9.5 +else echo PostgreSQL bin directory not found 1>&2; exit 1 +fi +PATH=$PGDIR/bin:$CDF/bin:/opt/app/pgaas/bin:$PATH + +usage() +{ + exec 1>&2 + [ $# -gt 0 ] && echo "$@" + echo "Usage: $0 [-r] [-v]" + echo -e " -r check /ro instead of /rw" + echo -e " -v verbose" + exit 1 +} + +VERBOSE=false +CMD=rw +QUIET=--quiet +OUTPUT=-O/dev/null +while getopts rvQ c +do + case "$c" in + r ) CMD=ro ;; + Q ) QUIET= OUTPUT= ;; + 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 $@ +for i in $(getpropvalue -n pgnodes | sed 's/|/ /g') +do + $VERBOSE && echo "Checking $i" + if pgwget $QUIET $OUTPUT http://$i:8000/$CMD + then set -- "$@" $i + fi +done + +echo "$@" +case "$CMD" in + rw ) + 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 + ;; + ro ) + case $# in + 0 ) exit 1 ;; # no masters exist + * ) exit 0 ;; # one or more masters+secondaries exist + esac + ;; +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..3e08be0 --- /dev/null +++ b/pgaas/src/stage/opt/app/pgaas/bin/makefile @@ -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. + + +all: + +STAGEDIR=/dev/null +DISTPATH=/opt/app/pgaas + +PYFILES= dcae_admin_db.py +SHFILES= check_cluster isrw list_masters pg_copy \ + 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 startbackup stopbackup + +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 | *~ ) ;; \ + * ) \ + if [ -f $$i ]; then \ + cp $$i $(STAGEDIR)/$(DISTPATH)/bin/$$i; \ + chmod a+x $(STAGEDIR)/$(DISTPATH)/bin/$$i; \ + fi; \ + ;; \ + esac; \ + done + +NODES="uiopmno5qwpstg01.grant.example.com|uiopmno5qwpstg00.grant.example.com|uiopmno6qwpstg00.grant.example.com|uiopmno6qwpstg01.grant.example.com" + +test-admin: + sudo -u postgres ./dcae_admin_db.py configurationChanged in.json + +test-gen: + ./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/pgaas/src/stage/opt/app/pgaas/bin/pg_copy b/pgaas/src/stage/opt/app/pgaas/bin/pg_copy new file mode 100755 index 0000000..cc148cf --- /dev/null +++ b/pgaas/src/stage/opt/app/pgaas/bin/pg_copy @@ -0,0 +1,88 @@ +#!/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 +elif [ -d /usr/lib/postgresql/9.6 ] +then PGDIR=/usr/lib/postgresql/9.6 +elif [ -d /usr/lib/postgresql/9.5 ] +then PGDIR=/usr/lib/postgresql/9.5 +else echo PostgreSQL bin directory not found 1>&2; exit 1 +fi + +export PATH=$PATH:$PGDIR/bin + +# pg_dump -C -h localhost -U localuser dbname | psql -h remotehost -U remoteuser dbname +# pg_dump -C -h remotehost -U remoteuser dbname | psql -h localhost -U localuser dbname + +usage() +{ + exec 1>&2 + [ $# -gt 0 ] && echo "$@" + b=$(basename $0) + echo "Usage: $b [-v] -H fromhost [-P fromport] -U fromuser -D fromdb [-A | -S] -h tohost [-p toport] -h touser -d todb" + echo "Copy a database from a one host to a another" + echo -e "-H\tFQDN of host to copy from" + echo -e "-P\tport of database being copied from" + echo -e "-U\tUSER to login as on remote host being copied from" + echo -e "-U\tDB database on host to be copied from" + echo -e "-A\tcopy data only" + echo -e "-S\tcopy schema only" + echo -e "-h\tFQDN of host to copy to" + echo -e "-p\tport of database being copied to" + echo -e "-u\tUSER to login as on host being copied to" + echo -e "-u\tDB database on host to be copied to" + exit 1 +} + +REMOTEDATAONLY= +REMOTESCHEMAONLY= +REMOTEHOST= +REMOTEPORT= +REMOTEUSER= +REMOTEDB= +LOCALHOST= +LOCALPORT= +LOCALUSER= +LOCALDB= + +while getopts ASH:P:U:D:h:p::u:d: c +do + case $c in + A ) REMOTEDATAONLY=-a ;; + S ) REMOTESCHEMAONLY=-s ;; + H ) REMOTEHOST=$OPTARG ;; + P ) REMOTEPORT=$OPTARG ;; + U ) REMOTEUSER=$OPTARG ;; + D ) REMOTEDB=$OPTARG;; + h ) LOCALHOST=$OPTARG ;; + p ) LOCALPORT=$OPTARG ;; + u ) LOCALUSER=$OPTARG ;; + d ) LOCALDB=$OPTARG;; + esac +done + + +[ -z "$REMOTEHOST" ] && usage "Missing -H option" +[ -z "$REMOTEPORT" ] && usage "Missing -P option" +[ -z "$REMOTEUSER" ] && usage "Missing -U option" +[ -z "$REMOTEDB" ] && usage "Missing -D option" +[ -z "$LOCALHOST" ] && usage "Missing -h option" +[ -z "$LOCALPORT" ] && usage "Missing -p option" +[ -z "$LOCALUSER" ] && usage "Missing -u option" +[ -z "$LOCALDB" ] && usage "Missing -d option" +[ -n "$REMOTEDATAONLY" -a -n "$REMOTESCHEMAONLY" ] && usage "Either -A or -S may be specified, but not both" + +pg_dump -C $REMOTEDATAONLY $REMOTESCHEMAONLY -h $REMOTEHOST -U $REMOTEUSER $REMOTEDB | psql -h $LOCALHOST -U $LOCALUSER $LOCALDB 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..c976afa --- /dev/null +++ b/pgaas/src/stage/opt/app/pgaas/bin/pg_ctl_promote @@ -0,0 +1,27 @@ +#!/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 +elif [ -d /usr/lib/postgresql/9.6 ] +then PGDIR=/usr/lib/postgresql/9.6 +elif [ -d /usr/lib/postgresql/9.5 ] +then PGDIR=/usr/lib/postgresql/9.5 +else echo PostgreSQL bin directory not found 1>&2; exit 1 +fi + +export PATH=$PATH:$PGDIR/bin + +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..6929d60 --- /dev/null +++ b/pgaas/src/stage/opt/app/pgaas/bin/pg_ctl_restart @@ -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. + + +if [ -d /opt/app/postgresql-9.5.2 ] +then PGDIR=/opt/app/postgresql-9.5.2 +elif [ -d /usr/lib/postgresql/9.6 ] +then PGDIR=/usr/lib/postgresql/9.6 +elif [ -d /usr/lib/postgresql/9.5 ] +then PGDIR=/usr/lib/postgresql/9.5 +else echo PostgreSQL bin directory not found 1>&2; exit 1 +fi + +export PATH=$PATH:$PGDIR/bin + +CONF=/opt/app/pgaas/main/postgresql.conf +if [ ! -f $CONF ] +then 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..42117df --- /dev/null +++ b/pgaas/src/stage/opt/app/pgaas/bin/pg_ctl_start @@ -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. + +if [ -d /opt/app/postgresql-9.5.2 ] +then PGDIR=/opt/app/postgresql-9.5.2 +elif [ -d /usr/lib/postgresql/9.6 ] +then PGDIR=/usr/lib/postgresql/9.6 +elif [ -d /usr/lib/postgresql/9.5 ] +then PGDIR=/usr/lib/postgresql/9.5 +else echo PostgreSQL bin directory not found 1>&2; exit 1 +fi + +export PATH=$PATH:$PGDIR/bin + +CONF=/opt/app/pgaas/main/postgresql.conf +if [ ! -f $CONF ] +then 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..3383835 --- /dev/null +++ b/pgaas/src/stage/opt/app/pgaas/bin/pg_ctl_status @@ -0,0 +1,27 @@ +#!/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 +elif [ -d /usr/lib/postgresql/9.6 ] +then PGDIR=/usr/lib/postgresql/9.6 +elif [ -d /usr/lib/postgresql/9.5 ] +then PGDIR=/usr/lib/postgresql/9.5 +else echo PostgreSQL bin directory not found 1>&2; exit 1 +fi + +export PATH=$PATH:$PGDIR/bin + +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..b6c3563 --- /dev/null +++ b/pgaas/src/stage/opt/app/pgaas/bin/pg_ctl_stop @@ -0,0 +1,26 @@ +#!/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 +elif [ -d /usr/lib/postgresql/9.6 ] +then PGDIR=/usr/lib/postgresql/9.6 +elif [ -d /usr/lib/postgresql/9.5 ] +then PGDIR=/usr/lib/postgresql/9.5 +else echo PostgreSQL bin directory not found 1>&2; exit 1 +fi + +export PATH=$PATH:$PGDIR/bin + +pg_ctl stop -D /dbroot/pgdata/main/ diff --git a/pgaas/src/stage/opt/app/pgaas/bin/pgaas-verify-install b/pgaas/src/stage/opt/app/pgaas/bin/pgaas-verify-install new file mode 100644 index 0000000..f80ea2a --- /dev/null +++ b/pgaas/src/stage/opt/app/pgaas/bin/pgaas-verify-install @@ -0,0 +1,233 @@ +#!/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 should 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. If not run as root or" + echo "postgres, other tests may fail." + 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 should 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 ################ +################################################################ + +#### user dcae is no longer used +#### 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 /opt/logs /dbroot/pgdata /dbroot/pglogs /dbroot/pgbackup +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 ################ +################ pgaas-prep step ################ +################################################################ + +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-idns.conf ] +then verified "found pgaas-idns service properly installed for Ubuntu 14" +else failed "pgaas-idns service has not been installed properly" +fi + +if ps -ef | grep '[i]DNS-responder' > /dev/null +then verified "iDNS-responder is running" + if ps -fu postgres | grep '[i]DNS-responder' > /dev/null + then verified "iDNS-responder is running as postgres" + else failed "iDNS-responder is running, but not as postgres" + fi +else failed "postgres does not have a logger process running" +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 ################ +################ pgaas-config step ################ +################################################################ + +if ps -fu postgres | grep "[p]ostgres: 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 [ -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/stage/opt/app/pgaas/bin/pgwget b/pgaas/src/stage/opt/app/pgaas/bin/pgwget new file mode 100644 index 0000000..d1d5f98 --- /dev/null +++ b/pgaas/src/stage/opt/app/pgaas/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/pgaas/src/stage/opt/app/pgaas/bin/repmgrc b/pgaas/src/stage/opt/app/pgaas/bin/repmgrc new file mode 100644 index 0000000..8ce6ebf --- /dev/null +++ b/pgaas/src/stage/opt/app/pgaas/bin/repmgrc @@ -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. + +if [ -d /opt/app/postgresql-9.5.2 ] +then PGDIR=/opt/app/postgresql-9.5.2 +elif [ -d /usr/lib/postgresql/9.6 ] +then PGDIR=/usr/lib/postgresql/9.6 +elif [ -d /usr/lib/postgresql/9.5 ] +then PGDIR=/usr/lib/postgresql/9.5 +else echo PostgreSQL bin directory not found 1>&2; exit 1 +fi + +export PATH=$PATH:$PGDIR/bin + +CONF=/opt/app/pgaas/main/repmgr.conf +if [ ! -f $CONF ] +then echo "$0: Cannot find repmgr configuration" 1>&2; exit 1 +fi + +repmgr -f $CONF "$@" diff --git a/pgaas/src/stage/opt/app/pgaas/bin/repmgrd-status-changes b/pgaas/src/stage/opt/app/pgaas/bin/repmgrd-status-changes new file mode 100644 index 0000000..a735db5 --- /dev/null +++ b/pgaas/src/stage/opt/app/pgaas/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/logs/dcae/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/pgaas/src/stage/opt/app/pgaas/bin/repmgrdc b/pgaas/src/stage/opt/app/pgaas/bin/repmgrdc new file mode 100644 index 0000000..2831ed0 --- /dev/null +++ b/pgaas/src/stage/opt/app/pgaas/bin/repmgrdc @@ -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. + + +if [ -d /opt/app/postgresql-9.5.2 ] +then PGDIR=/opt/app/postgresql-9.5.2 +elif [ -d /usr/lib/postgresql/9.6 ] +then PGDIR=/usr/lib/postgresql/9.6 +elif [ -d /usr/lib/postgresql/9.5 ] +then PGDIR=/usr/lib/postgresql/9.5 +else echo PostgreSQL bin directory not found 1>&2; exit 1 +fi + +export PATH=$PATH:$PGDIR/bin + +CONF=/opt/app/pgaas/main/repmgr.conf +if [ ! -f $CONF ] +then 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..fcb1196 --- /dev/null +++ b/pgaas/src/stage/opt/app/pgaas/bin/runpsql @@ -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. + + +if [ -d /opt/app/postgresql-9.5.2 ] +then PGDIR=/opt/app/postgresql-9.5.2 +elif [ -d /usr/lib/postgresql/9.6 ] +then PGDIR=/usr/lib/postgresql/9.6 +elif [ -d /usr/lib/postgresql/9.5 ] +then PGDIR=/usr/lib/postgresql/9.5 +else echo PostgreSQL bin directory not found 1>&2; exit 1 +fi + +export PATH=$PATH:$PGDIR/bin:/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..864fbf8 --- /dev/null +++ b/pgaas/src/stage/opt/app/pgaas/bin/runpsqll @@ -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. + + +if [ -d /opt/app/postgresql-9.5.2 ] +then PGDIR=/opt/app/postgresql-9.5.2 +elif [ -d /usr/lib/postgresql/9.6 ] +then PGDIR=/usr/lib/postgresql/9.6 +elif [ -d /usr/lib/postgresql/9.5 ] +then PGDIR=/usr/lib/postgresql/9.5 +else echo PostgreSQL bin directory not found 1>&2; exit 1 +fi + +export PATH=$PATH:$PGDIR/bin:/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/start_maintenance_mode b/pgaas/src/stage/opt/app/pgaas/bin/start_maintenance_mode new file mode 100644 index 0000000..47bb37e --- /dev/null +++ b/pgaas/src/stage/opt/app/pgaas/bin/start_maintenance_mode @@ -0,0 +1,48 @@ +#!/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. + +PATH=/opt/app/pgaas/bin:$PATH + +INMAINTENANCE=/var/run/postgresql/inmaintenance +ISRW=/var/run/postgresql/isrw + +if [ -f $INMAINTENANCE ] +then + echo "Already in maintenance mode" 1>&2 + exit 1 +fi + +case `< $ISRW` in + Master ) echo "This is a Master system. It cannot be set to maintenance mode" 1>&2 + exit 2 + ;; +esac + +echo "Setting maintenance mode" +echo inmaintenance > $INMAINTENANCE + +echo "Shutting down the PostgreSQL server" +pg_ctl_stop + +# the following loop is to allow iDNS to get a chance to mark this system as being down +echo "Sleeping for 20 seconds" +for i in `seq 20` +do + echo -n " $i" +done +echo " Done" + + + + 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..9e5c5b4 --- /dev/null +++ b/pgaas/src/stage/opt/app/pgaas/bin/startpsql @@ -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. + + +if [ -d /opt/app/postgresql-9.5.2 ] +then PGDIR=/opt/app/postgresql-9.5.2 +elif [ -d /usr/lib/postgresql/9.6 ] +then PGDIR=/usr/lib/postgresql/9.6 +elif [ -d /usr/lib/postgresql/9.5 ] +then PGDIR=/usr/lib/postgresql/9.5 +else echo PostgreSQL bin directory not found 1>&2; exit 1 +fi + +export PATH=$PATH:$PGDIR/bin:/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/stop_maintenance_mode b/pgaas/src/stage/opt/app/pgaas/bin/stop_maintenance_mode new file mode 100644 index 0000000..5d0b8d1 --- /dev/null +++ b/pgaas/src/stage/opt/app/pgaas/bin/stop_maintenance_mode @@ -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. + +PATH=/opt/app/pgaas/bin:$PATH + +INMAINTENANCE=/var/run/postgresql/inmaintenance + +if [ ! -f $INMAINTENANCE ] +then + echo "Not in maintenance mode" 1>&2 + exit 1 +fi + +echo "Restarting PostgreSQL server" +pg_ctl_start +echo "Returning server to normal rotation" +rm -f $INMAINTENANCE 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..7b51b30 --- /dev/null +++ b/pgaas/src/stage/opt/app/pgaas/bin/update_var_run_isrw @@ -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. + + +if [ -d /opt/app/postgresql-9.5.2 ] +then PGDIR=/opt/app/postgresql-9.5.2 +elif [ -d /usr/lib/postgresql/9.6 ] +then PGDIR=/usr/lib/postgresql/9.6 +elif [ -d /usr/lib/postgresql/9.5 ] +then PGDIR=/usr/lib/postgresql/9.5 +else echo PostgreSQL bin directory not found 1>&2; exit 1 +fi + +export PATH=$PATH:$PGDIR/bin:/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/common-db-tasks b/pgaas/src/stage/opt/app/pgaas/etc/common-db-tasks new file mode 100644 index 0000000..517fabd --- /dev/null +++ b/pgaas/src/stage/opt/app/pgaas/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/pgaas/src/stage/opt/app/pgaas/etc/create-cdf-master b/pgaas/src/stage/opt/app/pgaas/etc/create-cdf-master new file mode 100644 index 0000000..dcbbf46 --- /dev/null +++ b/pgaas/src/stage/opt/app/pgaas/etc/create-cdf-master @@ -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. + + +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= + # if .pgpass has a password for postgres, keep it + # *:*:*:postgres:4069b81b26cb01e064e242611c36e67a50f11a3d0dbe1f05d9b9aaedf2cadab1 + PGPASS=~postgres/.pgpass + if [ -f $PGPASS ] + then val2=$( grep :postgres: $PGPASS | sed 's/^.*://' ) + fi + if [ -z "$val2" ] + then + val2=$(dd if=/dev/urandom count=1 ibs=32 2>/dev/null | od -x -w1000 | sed -e 's/^0000000 //' -e 's/ //g' -e 1q) + fi + 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/pgaas/src/stage/opt/app/pgaas/etc/create-cdf-secondary b/pgaas/src/stage/opt/app/pgaas/etc/create-cdf-secondary new file mode 100644 index 0000000..78c35f9 --- /dev/null +++ b/pgaas/src/stage/opt/app/pgaas/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/pgaas/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/pgaas/src/stage/opt/app/pgaas/etc/create-db-backup b/pgaas/src/stage/opt/app/pgaas/etc/create-db-backup new file mode 100644 index 0000000..d6e856b --- /dev/null +++ b/pgaas/src/stage/opt/app/pgaas/etc/create-db-backup @@ -0,0 +1,38 @@ +#!/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 +elif [ -d /usr/lib/postgresql/9.6 ] +then PGDIR=/usr/lib/postgresql/9.6 +elif [ -d /usr/lib/postgresql/9.5 ] +then PGDIR=/usr/lib/postgresql/9.5 +else echo PostgreSQL bin directory not found +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/pgaas/src/stage/opt/app/pgaas/etc/create-db-master b/pgaas/src/stage/opt/app/pgaas/etc/create-db-master new file mode 100644 index 0000000..eb8fca3 --- /dev/null +++ b/pgaas/src/stage/opt/app/pgaas/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/pgaas/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/pgaas/src/stage/opt/app/pgaas/etc/create-db-secondary b/pgaas/src/stage/opt/app/pgaas/etc/create-db-secondary new file mode 100644 index 0000000..a0cc8e3 --- /dev/null +++ b/pgaas/src/stage/opt/app/pgaas/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/pgaas/bin:$CFGDIR/etc:$PGDIR/bin:$PATH + +bwget() +{ + ${INSTALL_ROOT}/opt/app/pgaas/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/logs/dcae/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/logs/dcae/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/pgaas/src/stage/opt/app/pgaas/etc/create-extensions b/pgaas/src/stage/opt/app/pgaas/etc/create-extensions new file mode 100644 index 0000000..70306a6 --- /dev/null +++ b/pgaas/src/stage/opt/app/pgaas/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/pgaas/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/pgaas/src/stage/opt/app/pgaas/etc/create-repmgr-user b/pgaas/src/stage/opt/app/pgaas/etc/create-repmgr-user new file mode 100644 index 0000000..35ca401 --- /dev/null +++ b/pgaas/src/stage/opt/app/pgaas/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/pgaas/bin:$PGDIR/bin:${INSTALL_ROOT}/opt/app/cdf/bin:$PATH +pswd=$( 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/pgaas/src/stage/opt/app/pgaas/etc/create-ssh-master b/pgaas/src/stage/opt/app/pgaas/etc/create-ssh-master new file mode 100644 index 0000000..5565041 --- /dev/null +++ b/pgaas/src/stage/opt/app/pgaas/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/pgaas/src/stage/opt/app/pgaas/etc/create-ssh-secondary b/pgaas/src/stage/opt/app/pgaas/etc/create-ssh-secondary new file mode 100644 index 0000000..2121eb3 --- /dev/null +++ b/pgaas/src/stage/opt/app/pgaas/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/pgaas/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/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/do-post-install-config b/pgaas/src/stage/opt/app/pgaas/etc/do-post-install-config new file mode 100644 index 0000000..87689ef --- /dev/null +++ b/pgaas/src/stage/opt/app/pgaas/etc/do-post-install-config @@ -0,0 +1,157 @@ +#!/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. + +echo "================ $0 ================" +id +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 "$ONAP" ] || die "ONAP is not set" +[ -n "$NOTONAP" ] || die "NOTONAP is not set" + +if [ -d ${INSTALL_ROOT}/opt/app/postgresql-9.5.2 ] +then PGDIR=${INSTALL_ROOT}/opt/app/postgresql-9.5.2 +elif [ -d ${INSTALL_ROOT}/usr/lib/postgresql/9.6 ] +then PGDIR=${INSTALL_ROOT}/usr/lib/postgresql/9.6 +elif [ -d ${INSTALL_ROOT}/usr/lib/postgresql/9.5 ] +then PGDIR=${INSTALL_ROOT}/usr/lib/postgresql/9.5 +else die PostgreSQL bin directory not found +fi +export PGDIR +export DBROOT=/dbroot/pgdata/main +export PATH=$PATH:${INSTALL_ROOT}/opt/app/pgaas/bin + +$CFGDIR/etc/makecerts + +cat $CFGDIR/lib/profile.additions >> ~postgres/.profile + +# Determine which system is the master. +# For central, we look first in /var/config/DCAE/chef/*-postgres.conf. +# If we don't find that, we look at the pgnodes list and pick the first one. +# For edge, we ignore /var/config/DCAE/chef/*-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 ) + CONFDIR1=/var/config/DCAE/chef + CONFDIR2=/tmp + CONFCOUNT1=$(ls $CONFDIR1/*-postgres.conf 2>/dev/null | wc -l) + CONFCOUNT2=$(ls $CONFDIR2/*-postgres.conf 2>/dev/null | wc -l) + CONFCOUNTBOTH=$(ls $CONFDIR1/*-postgres.conf $CONFDIR2/*-postgres.conf 2>/dev/null | wc -l) + + if [ $CONFCOUNTBOTH -eq 0 ] + then + # not OpenDCAE/ONAP, but it's better if we STILL require a pgaas-postgres.conf file. + die "No xyz-postgres.conf files were found in $CONFDIR1 or $CONFDIR2" + # Alternatively, the following code MIGHT work: + # ismaster=yes + # PGNODES=$( ${INSTALL_ROOT}/opt/app/cdf/bin/getpropvalue -n pgnodes ) + # export MASTER=$( gen-repmgr-info -n "$PGNODES" -m ) + else + if [ $CONFCOUNT1 -eq 1 ] + then CONFDIR=$CONFDIR1 + elif [ $CONFCOUNT2 -eq 1 ] + then CONFDIR=$CONFDIR2 + else CONFDIR= + fi + if [ -n "$CONFDIR" ] + then # OpenDCAE/ONAP + # We need the value of master from xyz-postgres.conf + umask 077 + TMP=$(mktemp /tmp/tmp.pi1.XXXXXXXXXX) + trap 'rm -f $TMP' 0 1 2 3 15 + cat $CONFDIR/*-postgres.conf | + sed -e 's/ *: */="/' -e 's/[ ]*$/"/' -e 's/=""/="/' -e 's/""$/"/' > $TMP + . $TMP + case "$master" in + `hostname` | `hostname -f` ) 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 + if [ $CONFCOUNT1 -gt 1 ] + then die "More than one postgres.conf was found in $CONFDIR1: $(ls $CONFDIR1/*-postgres.conf 2>&1)" + elif [ $CONFCOUNT2 -gt 1 ] + then die "More than one postgres.conf was found in $CONFDIR2: $(ls $CONFDIR2/*-postgres.conf 2>&1)" + fi + fi + 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 + +if pgrep postgres +then pkill postgres +fi + +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/pgaas/src/stage/opt/app/pgaas/etc/do-post-install-post b/pgaas/src/stage/opt/app/pgaas/etc/do-post-install-post new file mode 100644 index 0000000..66eea14 --- /dev/null +++ b/pgaas/src/stage/opt/app/pgaas/etc/do-post-install-post @@ -0,0 +1,35 @@ +#!/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. + +echo "================ $0 ================" +id +set -x + +die() +{ + echo "$@" 1>&2 + echo $0: "$@" + umask 022 + echo $0: "$@" >> /tmp/pgaas-failures + exit 1 +} + +################ nothing needs to be done +BIN=/opt/app/pgaas/bin + +[ -d $BIN ] || die "Cannot find $BIN" + +PATH=$PATH:$BIN + +pgaas-verify-install diff --git a/pgaas/src/stage/opt/app/pgaas/etc/do-post-install-prep b/pgaas/src/stage/opt/app/pgaas/etc/do-post-install-prep new file mode 100644 index 0000000..02eabef --- /dev/null +++ b/pgaas/src/stage/opt/app/pgaas/etc/do-post-install-prep @@ -0,0 +1,259 @@ +#!/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. + +echo "================ $0 ================" +id +set -x + +die() +{ + echo "$@" 1>&2 + echo $0: "$@" + umask 022 + echo $0: "$@" >> /tmp/pgaas-failures + exit 1 +} + +umask 022 + +TMP=$( mktemp /tmp/pgprep.$$.XXXXXXXXXX ) +trap 'rm -f $TMP' 0 1 2 3 15 + +if $ONAP +then INSTALL_ROOT= +fi + + +# There needs to be a configuration file passed in, named something like pgaas-postgres.conf +# and stored either in /var/config/DCAE/chef or /tmp. We need at least one, and there cannot +# be more than one within the directory. (If one exists in both /var/config and /tmp, we trust +# the one in /var/config.) +# +# The variable "master" needs to be in xyz-postgres.conf. It should be the hostname or +# hostname -f value of the VM that is the initial PG master. +# In addition, the following values could be in postgres.conf or +# already in the environment: +# 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.onap.org +# PG_JAVA_HOME : /opt/app/java/jdk/jdk170 +# PG_CLUSTER : global/central | site/edge (pick one) + +CONFDIR1=/var/config/DCAE/chef +CONFDIR2=/tmp +CONFCOUNT1=$(ls $CONFDIR1/*-postgres.conf 2>/dev/null | wc -l) +CONFCOUNT2=$(ls $CONFDIR2/*-postgres.conf 2>/dev/null | wc -l) +CONFCOUNTBOTH=$(ls $CONFDIR1/*-postgres.conf $CONFDIR2/*-postgres.conf 2>/dev/null | wc -l) + +if [ $CONFCOUNTBOTH -eq 0 ] +then + die "No xyz-postgres.conf files were found in $CONFDIR1 or $CONFDIR2" +else + if [ $CONFCOUNT1 -eq 1 ] + then CONFDIR=$CONFDIR1 + elif [ $CONFCOUNT2 -eq 1 ] + then CONFDIR=$CONFDIR2 + else CONFDIR= + fi + if [ -n "$CONFDIR" ] + then # OpenDCAE/ONAP + cat $CONFDIR/*-postgres.conf | + sed -e 's/ *: */="/' -e 's/[ ]*$/"/' -e 's/=""/="/' -e 's/""$/"/' > $TMP + . $TMP + else + if [ $CONFCOUNT1 -gt 1 ] + then die "More than one postgres.conf was found in $CONFDIR1: $(ls $CONFDIR1/*-postgres.conf 2>&1)" + elif [ $CONFCOUNT2 -gt 1 ] + then die "More than one postgres.conf was found in $CONFDIR2: $(ls $CONFDIR2/*-postgres.conf 2>&1)" + fi + fi +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/logs/dcae/postgresql/init \ + ${INSTALL_ROOT}/opt/logs/dcae/postgresql/server \ + ${INSTALL_ROOT}/opt/logs/dcae/postgresql/idns +chmod 700 ${INSTALL_ROOT}/dbroot/pgdata/pgaas +chmod 700 ${INSTALL_ROOT}/dbroot/pglogs +chmod 700 ${INSTALL_ROOT}/dbroot/pgdata/main + +if $ONAP +then + if [ -d /var/lib/postgresql/9.5 ] + then VER=9.5 + elif [ -d /var/lib/postgresql/9.6 ] + then VER=9.6 + else die "Cannot determine version of PostgreSQL. Looking for /var/lib/postgresql/9.[56]." + fi + mv /var/lib/postgresql/$VER/main /var/lib/postgresql/$VER/main.sv + ln -s /dbroot/dbdata/main /var/lib/postgresql/$VER/main + + mv /etc/postgresql/$VER/main /etc/postgresql/$VER/main.sv + ln -s /opt/app/pgaas/main /etc/postgresql/$VER/main + +fi + +chown -R postgres:postgres ${INSTALL_ROOT}/dbroot ${INSTALL_ROOT}/var/run/postgresql ${INSTALL_ROOT}/opt/logs/dcae/postgresql + +chmod 711 ~postgres +if [ -d /opt/app/postgresql-9.5.2 ] +then PGDIR=/opt/app/postgresql-9.5.2 +elif [ -d /usr/lib/postgresql/9.6 ] +then PGDIR=/usr/lib/postgresql/9.6 +elif [ -d /usr/lib/postgresql/9.5 ] +then PGDIR=/usr/lib/postgresql/9.5 +else echo PostgreSQL bin directory not found 1>&2; exit 1 +fi +chmod 751 $PGDIR/bin + +# fix up the CDF package so that it works +if [ ! -L /opt/cdf ] +then rm -f /opt/cdf; ln -sf /opt/app/cdf /opt/cdf +fi + +PATH=${INSTALL_ROOT}/opt/app/pgaas/bin:$PATH + +# and save some values within +( + echo "allpgnodes=\"$PG_NODES\"" + case "$PG_CLUSTER" in + global | central ) + cnodes=$( gen-repmgr-info -n "$PG_NODES" -p ) + echo "pgnodes=\"$cnodes\"" + echo "cluster=central" + shanodes=$( gen-repmgr-info -n "$PG_NODES" -P ) + ;; + site | edge ) + HOSTNAME=$( hostname -f ) + lnodes=$( 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=$( 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/pgaas/init + +# take care of cron jobs +if [ -d ${INSTALL_ROOT}/opt/app/platform/cron ] +then + CRONDIR=${INSTALL_ROOT}/opt/app/platform/cron/postgres + mkdir -p $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" +else + su postgres -c "crontab $INIT/pglogs.cron" +fi + +# take care of PGaaS init job +if [ -d ${INSTALL_ROOT}/opt/app/platform/init.d ] +then + INITDEST=${INSTALL_ROOT}/opt/app/platform/init.d/pgaas + cp $INIT/init.d-pgaas $INITDEST + chown postgres:postgres $INITDEST + chmod 755 $INITDEST +else + cd ${INSTALL_ROOT}/opt/app/platform/rc.d + ln -sf ../init.d/pgaas K20pgaas + ln -sf ../init.d/pgaas S20pgaas +fi + +# take care of /var/run/postgresql directory +if [ -f /usr/lib/tmpfiles.d/postgresql.conf ] +then + : # no need to create the /var/run/postgresql directory (probably because postgresql package already did it) +elif [ -d /usr/lib/tmpfiles.d ] +then + ( + echo "# Directory for PostgreSQL sockets, lockfiles and stats tempfiles" + echo "d /var/run/postgresql 2775 postgres postgres - -" + ) > /usr/lib/tmpfiles.d/postgresql.conf +else + # install an init script to create it + cp $INIT/init-pgaas-init.conf ${INSTALL_ROOT}/etc/init/pgaas-init.conf + service pgaas-init stop + sleep 1 + service pgaas-init start + sleep 1 +fi +# double check to make sure it's been created +if [ ! -d /var/run/postgresql ] +then + mkdir -p /var/run/postgresql + chown postgres:postgres /var/run/postgresql +fi + +# take care of iDNS-responder +if [ -d /lib/systemd/system -a -f /bin/systemctl ] +then + # install the init script for iDNS in systemd + cp $INIT/systemd-pgaas-idns.service /lib/systemd/system/pgaas-idns.service +# if [ -f /usr/sbin/service ] +# then +# service pgaas-idns stop +# sleep 1 +# service pgaas-idns start +# else +# systemctl stop pgaas-idns + sleep 1 + systemctl daemon-reload + sleep 1 + systemctl enable pgaas-idns + sleep 1 + systemctl start pgaas-idns +# fi + +else + # install the init script for iDNS in upstart + cp $INIT/init-pgaas-idns.conf ${INSTALL_ROOT}/etc/init/pgaas-idns.conf + service pgaas-idns stop + sleep 1 + service pgaas-idns start +fi + +# take care of log rotation +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 + +chown -R postgres:postgres ${INSTALL_ROOT}/opt/app/pgaas + +echo ENDING $0 $(date) +echo ENDING $0 $(date) >> /tmp/pgaas.inst.report diff --git a/pgaas/src/stage/opt/app/pgaas/etc/do-post-install-tools b/pgaas/src/stage/opt/app/pgaas/etc/do-post-install-tools new file mode 100644 index 0000000..16cb5e5 --- /dev/null +++ b/pgaas/src/stage/opt/app/pgaas/etc/do-post-install-tools @@ -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. + +echo "================ $0 ================" +id +set -x + +die() +{ + echo "$@" 1>&2 + echo $0: "$@" + umask 022 + echo $0: "$@" >> /tmp/pgaas-failures + exit 1 +} + +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 +elif [ -d /usr/lib/postgresql/9.6 ] +then PGDIR=/usr/lib/postgresql/9.6 +elif [ -d /usr/lib/postgresql/9.5 ] +then PGDIR=/usr/lib/postgresql/9.5 +else die PostgreSQL bin directory not found +fi +CFGDIR=/opt/app/pgaas +CONF=$CFGDIR/main/postgresql.conf +if [ ! -f $CONF ] +then echo "$0: Cannot find PostgreSQL configuration" 1>&2; exit 1 +fi + + +( + grep '^postgres.x' < $CDFCFG | sed -e 's/^postgres/dcae_admin_db_password/' + echo "db_configuration=$CONF" + echo "pg_bin_directory=$PGDIR/bin" + echo "skip_configuration_file=$CFGDIR/lib/ignore-database-reconfiguration" +) >> $PGAASCFG diff --git a/pgaas/src/stage/opt/app/pgaas/etc/do-pre-rm.prep b/pgaas/src/stage/opt/app/pgaas/etc/do-pre-rm.prep new file mode 100755 index 0000000..a03a13b --- /dev/null +++ b/pgaas/src/stage/opt/app/pgaas/etc/do-pre-rm.prep @@ -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/pgaas/src/stage/opt/app/pgaas/etc/gen-pgpass b/pgaas/src/stage/opt/app/pgaas/etc/gen-pgpass new file mode 100644 index 0000000..f97d573 --- /dev/null +++ b/pgaas/src/stage/opt/app/pgaas/etc/gen-pgpass @@ -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. + + +# 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 +pswdfile=~postgres/.pgpass +if [ -f $pswdfile ] +then + sed -i -e '/:postgres:/d' -e '/:repmgr:/d' $pswdfile +fi + +echo "*:*:*:postgres:$postgrespswd" >> $pswdfile +echo "*:*:*:repmgr:$repmgrpswd" >> $pswdfile +chmod 600 $pswdfile diff --git a/pgaas/src/stage/opt/app/pgaas/etc/gen-recovery.conf b/pgaas/src/stage/opt/app/pgaas/etc/gen-recovery.conf new file mode 100644 index 0000000..1ad41c2 --- /dev/null +++ b/pgaas/src/stage/opt/app/pgaas/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/pgaas/bin:${INSTALL_ROOT}/opt/app/cdf/bin:$PATH + +PGNODES=$( 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/pgaas/src/stage/opt/app/pgaas/etc/gen-repmgr.conf b/pgaas/src/stage/opt/app/pgaas/etc/gen-repmgr.conf new file mode 100755 index 0000000..924a097 --- /dev/null +++ b/pgaas/src/stage/opt/app/pgaas/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/pgaas/bin:${INSTALL_ROOT}/opt/app/cdf/bin:$PATH +LOGDIR=/opt/logs/dcae/postgresql/server + +PGNODES=$( 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/pgaas/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/pgaas/src/stage/opt/app/pgaas/etc/lock-and-create-db-backup b/pgaas/src/stage/opt/app/pgaas/etc/lock-and-create-db-backup new file mode 100644 index 0000000..cb8586d --- /dev/null +++ b/pgaas/src/stage/opt/app/pgaas/etc/lock-and-create-db-backup @@ -0,0 +1,37 @@ +#!/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 +elif [ -d /usr/lib/postgresql/9.6 ] +then PGDIR=/usr/lib/postgresql/9.6 +elif [ -d /usr/lib/postgresql/9.5 ] +then PGDIR=/usr/lib/postgresql/9.5 +else echo PostgreSQL bin directory not found +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/pgaas/src/stage/opt/app/pgaas/etc/makecerts b/pgaas/src/stage/opt/app/pgaas/etc/makecerts new file mode 100755 index 0000000..494c78b --- /dev/null +++ b/pgaas/src/stage/opt/app/pgaas/etc/makecerts @@ -0,0 +1,98 @@ +#!/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/pgaas/etc +# ssleay.cnf - template +# /opt/app/pgaas/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 +} + +dir=${INSTALL_ROOT}/opt/app/pgaas +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 +} + +set -x + +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. + +umask 077 + +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/pgaas/src/stage/opt/app/pgaas/etc/makefile b/pgaas/src/stage/opt/app/pgaas/etc/makefile new file mode 100644 index 0000000..b5a5484 --- /dev/null +++ b/pgaas/src/stage/opt/app/pgaas/etc/makefile @@ -0,0 +1,44 @@ +# 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 + for i in *; do \ + case $$i in \ + *.py | gen*.conf ) \ + j=`basename $$i .py`; \ + cp $$i $(STAGEDIR)/$(DISTPATH)/etc/$$j; \ + chmod a+x $(STAGEDIR)/$(DISTPATH)/etc/$$j; \ + ;; \ + *.conf | *.cfg | *.cnf | *.sql ) \ + cp $$i $(STAGEDIR)/$(DISTPATH)/etc/$$i; \ + chmod a+r $(STAGEDIR)/$(DISTPATH)/etc/$$i; \ + ;; \ + makefile | *~ ) ;; \ + * ) \ + if [ -f $$i ]; then \ + cp $$i $(STAGEDIR)/$(DISTPATH)/etc/$$i; \ + chmod a+rx $(STAGEDIR)/$(DISTPATH)/etc/$$i; \ + fi; \ + ;; \ + esac; \ + done diff --git a/pgaas/src/stage/opt/app/pgaas/etc/ssleay.cnf b/pgaas/src/stage/opt/app/pgaas/etc/ssleay.cnf new file mode 100644 index 0000000..2b665cc --- /dev/null +++ b/pgaas/src/stage/opt/app/pgaas/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/pgaas/src/stage/opt/app/pgaas/etc/start-db b/pgaas/src/stage/opt/app/pgaas/etc/start-db new file mode 100644 index 0000000..a91d16a --- /dev/null +++ b/pgaas/src/stage/opt/app/pgaas/etc/start-db @@ -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. + + +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 +chmod 600 $CFGDIR/lib/*.key +$PGDIR/bin/pg_ctl start -D $DBROOT -o "-c config_file=$CFGDIR/main/postgresql.conf" diff --git a/pgaas/src/stage/opt/app/pgaas/etc/update-db-master b/pgaas/src/stage/opt/app/pgaas/etc/update-db-master new file mode 100644 index 0000000..db0d5ba --- /dev/null +++ b/pgaas/src/stage/opt/app/pgaas/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/pgaas/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/pgaas/src/stage/opt/app/pgaas/etc/update-db-secondary b/pgaas/src/stage/opt/app/pgaas/etc/update-db-secondary new file mode 100644 index 0000000..e06c810 --- /dev/null +++ b/pgaas/src/stage/opt/app/pgaas/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/pgaas/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/pgaas/src/stage/opt/app/pgaas/etc/update-postgres-user b/pgaas/src/stage/opt/app/pgaas/etc/update-postgres-user new file mode 100644 index 0000000..0466ad8 --- /dev/null +++ b/pgaas/src/stage/opt/app/pgaas/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/pgaas/bin:$PGDIR/bin:${INSTALL_ROOT}/opt/app/cdf/bin:$PATH +pswd=$( getpropvalue -x -n postgres ) + +psql <<-EOF + ALTER USER postgres PASSWORD '$pswd'; + EOF diff --git a/pgaas/src/stage/opt/app/pgaas/init/init-pgaas-idns.conf b/pgaas/src/stage/opt/app/pgaas/init/init-pgaas-idns.conf new file mode 100644 index 0000000..62714f1 --- /dev/null +++ b/pgaas/src/stage/opt/app/pgaas/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/pgaas/lib/iDNS-responder || { stop; exit 0; } +end script + +script + /opt/app/pgaas/lib/iDNS-responder +end script diff --git a/pgaas/src/stage/opt/app/pgaas/init/init-pgaas-init.conf b/pgaas/src/stage/opt/app/pgaas/init/init-pgaas-init.conf new file mode 100644 index 0000000..6f03c1f --- /dev/null +++ b/pgaas/src/stage/opt/app/pgaas/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 2755 postgres postgres - +# +# This is a workaround because systemd-tmpfiles is not present. + +description "PGaaS /var/run/postgresql setup" + +start on runlevel [2345] +stop on runlevel [!2345] + +umask 022 + +pre-start script + mkdir -p /var/run/postgresql + chown postgres:postgres /var/run/postgresql +end script + +script + : +end script diff --git a/pgaas/src/stage/opt/app/pgaas/init/logrotate b/pgaas/src/stage/opt/app/pgaas/init/logrotate new file mode 100644 index 0000000..8531ed6 --- /dev/null +++ b/pgaas/src/stage/opt/app/pgaas/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/logs/dcae/postgresql/init/*.log /opt/logs/dcae/postgresql/idns/*.log /opt/logs/dcae/postgresql/server/*.log { + missingok + compress + daily + rotate 60 + create + dateext +} diff --git a/pgaas/src/stage/opt/app/pgaas/init/makefile b/pgaas/src/stage/opt/app/pgaas/init/makefile new file mode 100644 index 0000000..d2d8285 --- /dev/null +++ b/pgaas/src/stage/opt/app/pgaas/init/makefile @@ -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. + + +all: + +STAGEDIR=/dev/null +DISTPATH=/opt/app/pgaas + +stage: + rm -rf $(STAGEDIR)/$(DISTPATH)/init + mkdir -p $(STAGEDIR)/$(DISTPATH)/init + for i in *; do \ + case $$i in \ + *.py ) \ + j=`basename $$i .py`; \ + cp $$i $(STAGEDIR)/$(DISTPATH)/init/$$j; \ + chmod a+x $(STAGEDIR)/$(DISTPATH)/init/$$j; \ + ;; \ + makefile | *~ ) ;; \ + * ) \ + if [ -f $$i ]; then \ + cp $$i $(STAGEDIR)/$(DISTPATH)/init/$$i; \ + chmod a+x $(STAGEDIR)/$(DISTPATH)/init/$$i; \ + fi; \ + ;; \ + esac; \ + done diff --git a/pgaas/src/stage/opt/app/pgaas/init/pglogs.cron b/pgaas/src/stage/opt/app/pgaas/init/pglogs.cron new file mode 100644 index 0000000..ff621ba --- /dev/null +++ b/pgaas/src/stage/opt/app/pgaas/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 -d /var/run/postgresql/check_cluster >> /opt/logs/dcae/postgresql/idns/cluster.log diff --git a/pgaas/src/stage/opt/app/pgaas/init/systemd-pgaas-idns.service b/pgaas/src/stage/opt/app/pgaas/init/systemd-pgaas-idns.service new file mode 100644 index 0000000..007ca36 --- /dev/null +++ b/pgaas/src/stage/opt/app/pgaas/init/systemd-pgaas-idns.service @@ -0,0 +1,16 @@ +# 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] +User=postgres +Group=postgres +ExecStart= /opt/app/pgaas/lib/iDNS-responder +Restart=always +RestartSec=10 + +[Install] +WantedBy=multi-user.target diff --git a/pgaas/src/stage/opt/app/pgaas/init/tmpfiles-pgaas-init.conf b/pgaas/src/stage/opt/app/pgaas/init/tmpfiles-pgaas-init.conf new file mode 100644 index 0000000..9341a95 --- /dev/null +++ b/pgaas/src/stage/opt/app/pgaas/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/pgaas/src/stage/opt/app/pgaas/lib/CommonLogger.py b/pgaas/src/stage/opt/app/pgaas/lib/CommonLogger.py new file mode 100755 index 0000000..a50303f --- /dev/null +++ b/pgaas/src/stage/opt/app/pgaas/lib/CommonLogger.py @@ -0,0 +1,941 @@ +#!/usr/bin/python +# -*- indent-tabs-mode: nil -*- vi: set expandtab: +"""ECOMP Common Logging library in Python. + +CommonLogger.py + +# Copyright (C) 2016 AT&T Intellectual Property. All rights reserved. +# +# This code is licensed under the Apache License, Version 2.0; +# you may not use this code for any purpose except in compliance +# with the Apache License. You may obtain a copy of the License +# at http://www.att.com/openecomp.html. + +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, collections + +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' + verbose = False + + 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. + begTime (am) -- optional starting time for this audit/metrics log record. + + Note: the pipe '|' character is not allowed in any log record field. + """ + + self._log('DEBUG', message, errorCategory = 'DEBUG', **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. + begTime (am) -- optional starting time for this audit/metrics log record. + + Note: the pipe '|' character is not allowed in any log record field. + """ + + self._log('INFO', message, errorCategory = 'INFO', **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. + begTime (am) -- optional starting time for this audit/metrics log record. + + Note: the pipe '|' character is not allowed in any log record field. + """ + + self._log('WARN', message, errorCategory = 'WARN', **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. + begTime (am) -- optional starting time for this audit/metrics log record. + + Note: the pipe '|' character is not allowed in any log record field. + """ + + self._log('ERROR', message, errorCategory = 'ERROR', **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. + begTime (am) -- optional starting time for this audit/metrics log record. + + Note: the pipe '|' character is not allowed in any log record field. + """ + + self._log('FATAL', message, errorCategory = 'FATAL', **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. + begTime (am) -- optional starting time for this audit/metrics log record. + + 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)) + nbegTime = self._getArg('begTime', {}, **kwargs) + + detailMessage = self._noSep(message) + if bool(re.match(r" *$", detailMessage)): + return # don't log empty messages + + useLevel = self._intLogLevel(upperLogLevel) + if CommonLogger.verbose: print("logger STYLE=%s" % style) + if useLevel < self._logLevelThreshold: + if CommonLogger.verbose: print("skipping because of level") + pass + else: + with self._logLock: + if style == CommonLogger.ErrorFile: + if CommonLogger.verbose: print("using 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: + if CommonLogger.verbose: print("using 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: + if CommonLogger.verbose: print("using CommonLogger.AuditFile") + endAuditTime, endAuditMsec = self._getTime() + if type(nbegTime) is dict and 'begTime' in nbegTime and 'begMsec' in nbegTime: + d = { 'begtime': self._noSep(nbegTime['begTime']), 'begmsecs': float(self._noSep(nbegTime['begMsec'])), 'endtime': endAuditTime, 'endmsecs': endAuditMsec } + elif 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: + if CommonLogger.verbose: print("using CommonLogger.MetricsFile") + endMetricsTime, endMetricsMsec = self._getTime() + if type(nbegTime) is dict and 'begTime' in nbegTime and 'begMsec' in nbegTime: + d = { 'begtime': self._noSep(nbegTime['begTime']), 'begmsecs': float(self._noSep(nbegTime['begMsec'])), 'endtime': endMetricsTime, 'endmsecs': endMetricsMsec } + elif 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 getStartRecordEvent(self): + """ + Retrieve the start time to be used for either audit and metrics records + """ + begTime, begMsec = self._getTime() + return {'begTime':begTime, 'begMsec':begMsec} + + 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 _getArg(self, key, default, **kwargs): + val = None + if key in kwargs: val = kwargs[key] + if val is None: val = default + return 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) + +if __name__ == "__main__": + + def __checkOneTime(line): + 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 __checkTwoTimes(line, different): + 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 __checkBegTime(line): + format = "begTime should be ([-0-9T:]+)" + # print("checkBegTime(%s)" % line) + strt = 'begTime should be ' + i = line.index(strt) + rest = line[i+len(strt):].rstrip() + if not line.startswith(rest + ","): + print("ERROR: line %s should start with %s" % (line,rest)) + 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 += __checkOneTime(line) + elif re.search("time should be the same", line): + errorCount += __checkTwoTimes(line, different=False) + elif re.search("time should be ", line): + errorCount += __checkTwoTimes(line, different=True) + elif re.search("begTime should be ", line): + errorCount += __checkBegTime(line) + 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 + + import os, argparse + parser = argparse.ArgumentParser(description="test the CommonLogger functions") + parser.add_argument("-k", "--keeplogs", help="Keep the log files after finishing the tests", action="store_true") + parser.add_argument("-v", "--verbose", help="Print debugging messages", action="store_true") + args = parser.parse_args() + + spid = str(os.getpid()) + if args.keeplogs: + spid = "" + logcfg = "/tmp/cl.log" + spid + ".cfg" + errorLog = "/tmp/cl.error" + spid + ".log" + metricsLog = "/tmp/cl.metrics" + spid + ".log" + auditLog = "/tmp/cl.audit" + spid + ".log" + debugLog = "/tmp/cl.debug" + spid + ".log" + if args.verbose: CommonLogger.verbose = True + + import atexit + def cleanupTmps(): + for f in [ logcfg, errorLog, metricsLog, auditLog, debugLog ]: + try: + os.remove(f) + except: + pass + if not args.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)") + bt = auditLogger.getStartRecordEvent() + # print("bt=%s" % bt) + time.sleep(1) + auditLogger.setStartRecordEvent() + time.sleep(1) + auditLogger.fatal("audit calling fatal, after setStartRecordEvent and sleep, time should be different)") + time.sleep(1) + auditLogger.fatal("audit calling fatal, begTime should be %s" % bt['begTime'], begTime=bt) + testsRun += 7 + errorCount += __checkLog(auditLog, 5, 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)") + bt = metricsLogger.getStartRecordEvent() + time.sleep(1) + 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)") + time.sleep(1) + metricsLogger.fatal("metrics calling fatal, begTime should be %s" % bt['begTime'], begTime=bt) + testsRun += 6 + errorCount += __checkLog(metricsLog, 5, 28) + + print("%d tests run, %d errors found" % (testsRun, errorCount)) diff --git a/pgaas/src/stage/opt/app/pgaas/lib/gif/green-flasher-12x10.gif b/pgaas/src/stage/opt/app/pgaas/lib/gif/green-flasher-12x10.gif Binary files differnew file mode 100644 index 0000000..c6d33b5 --- /dev/null +++ b/pgaas/src/stage/opt/app/pgaas/lib/gif/green-flasher-12x10.gif diff --git a/pgaas/src/stage/opt/app/pgaas/lib/gif/grey-flasher-12x10.gif b/pgaas/src/stage/opt/app/pgaas/lib/gif/grey-flasher-12x10.gif Binary files differnew file mode 100644 index 0000000..dfa81a2 --- /dev/null +++ b/pgaas/src/stage/opt/app/pgaas/lib/gif/grey-flasher-12x10.gif diff --git a/pgaas/src/stage/opt/app/pgaas/lib/gif/makefile b/pgaas/src/stage/opt/app/pgaas/lib/gif/makefile new file mode 100644 index 0000000..105033d --- /dev/null +++ b/pgaas/src/stage/opt/app/pgaas/lib/gif/makefile @@ -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. + + +all: + +test: + +STAGEDIR=/dev/null +DISTPATH=/opt/app/pgaas + +stage: + mkdir -p $(STAGEDIR)/$(DISTPATH)/lib/gif + for i in *; do \ + case $$i in \ + *.py ) \ + j=`basename $$i .py`; \ + cp $$i $(STAGEDIR)/$(DISTPATH)/lib/gif/$$j; \ + chmod a+x $(STAGEDIR)/$(DISTPATH)/lib/gif/$$j; \ + ;; \ + makefile | *~ ) ;; \ + * ) \ + cp $$i $(STAGEDIR)/$(DISTPATH)/lib/gif/$$i; \ + chmod a+x $(STAGEDIR)/$(DISTPATH)/lib/gif/$$i; \ + ;; \ + esac; \ + done diff --git a/pgaas/src/stage/opt/app/pgaas/lib/gif/red-flasher-12x10.gif b/pgaas/src/stage/opt/app/pgaas/lib/gif/red-flasher-12x10.gif Binary files differnew file mode 100644 index 0000000..ab16a81 --- /dev/null +++ b/pgaas/src/stage/opt/app/pgaas/lib/gif/red-flasher-12x10.gif diff --git a/pgaas/src/stage/opt/app/pgaas/lib/gif/stoplight-G-12x25.gif b/pgaas/src/stage/opt/app/pgaas/lib/gif/stoplight-G-12x25.gif Binary files differnew file mode 100644 index 0000000..0ce2785 --- /dev/null +++ b/pgaas/src/stage/opt/app/pgaas/lib/gif/stoplight-G-12x25.gif diff --git a/pgaas/src/stage/opt/app/pgaas/lib/gif/stoplight-R-12x25.gif b/pgaas/src/stage/opt/app/pgaas/lib/gif/stoplight-R-12x25.gif Binary files differnew file mode 100644 index 0000000..0750594 --- /dev/null +++ b/pgaas/src/stage/opt/app/pgaas/lib/gif/stoplight-R-12x25.gif diff --git a/pgaas/src/stage/opt/app/pgaas/lib/gif/stoplight-Y-12x25.gif b/pgaas/src/stage/opt/app/pgaas/lib/gif/stoplight-Y-12x25.gif Binary files differnew file mode 100644 index 0000000..4f95bf0 --- /dev/null +++ b/pgaas/src/stage/opt/app/pgaas/lib/gif/stoplight-Y-12x25.gif diff --git a/pgaas/src/stage/opt/app/pgaas/lib/gif/stoplight-g-12x25.gif b/pgaas/src/stage/opt/app/pgaas/lib/gif/stoplight-g-12x25.gif Binary files differnew file mode 100644 index 0000000..0ce2785 --- /dev/null +++ b/pgaas/src/stage/opt/app/pgaas/lib/gif/stoplight-g-12x25.gif diff --git a/pgaas/src/stage/opt/app/pgaas/lib/gif/stoplight-g2-12x25.gif b/pgaas/src/stage/opt/app/pgaas/lib/gif/stoplight-g2-12x25.gif Binary files differnew file mode 100644 index 0000000..1be7fa1 --- /dev/null +++ b/pgaas/src/stage/opt/app/pgaas/lib/gif/stoplight-g2-12x25.gif diff --git a/pgaas/src/stage/opt/app/pgaas/lib/gif/stoplight-master-green.gif b/pgaas/src/stage/opt/app/pgaas/lib/gif/stoplight-master-green.gif Binary files differnew file mode 100644 index 0000000..1be7fa1 --- /dev/null +++ b/pgaas/src/stage/opt/app/pgaas/lib/gif/stoplight-master-green.gif diff --git a/pgaas/src/stage/opt/app/pgaas/lib/gif/stoplight-master-red.gif b/pgaas/src/stage/opt/app/pgaas/lib/gif/stoplight-master-red.gif Binary files differnew file mode 100644 index 0000000..daa6960 --- /dev/null +++ b/pgaas/src/stage/opt/app/pgaas/lib/gif/stoplight-master-red.gif diff --git a/pgaas/src/stage/opt/app/pgaas/lib/gif/stoplight-master-yellow.gif b/pgaas/src/stage/opt/app/pgaas/lib/gif/stoplight-master-yellow.gif Binary files differnew file mode 100644 index 0000000..1bd8731 --- /dev/null +++ b/pgaas/src/stage/opt/app/pgaas/lib/gif/stoplight-master-yellow.gif diff --git a/pgaas/src/stage/opt/app/pgaas/lib/gif/stoplight-r-12x25.gif b/pgaas/src/stage/opt/app/pgaas/lib/gif/stoplight-r-12x25.gif Binary files differnew file mode 100644 index 0000000..0750594 --- /dev/null +++ b/pgaas/src/stage/opt/app/pgaas/lib/gif/stoplight-r-12x25.gif diff --git a/pgaas/src/stage/opt/app/pgaas/lib/gif/stoplight-r2-12x25.gif b/pgaas/src/stage/opt/app/pgaas/lib/gif/stoplight-r2-12x25.gif Binary files differnew file mode 100644 index 0000000..ff26986 --- /dev/null +++ b/pgaas/src/stage/opt/app/pgaas/lib/gif/stoplight-r2-12x25.gif diff --git a/pgaas/src/stage/opt/app/pgaas/lib/gif/stoplight-r3-12x25.gif b/pgaas/src/stage/opt/app/pgaas/lib/gif/stoplight-r3-12x25.gif Binary files differnew file mode 100644 index 0000000..daa6960 --- /dev/null +++ b/pgaas/src/stage/opt/app/pgaas/lib/gif/stoplight-r3-12x25.gif diff --git a/pgaas/src/stage/opt/app/pgaas/lib/gif/stoplight-secondary-green.gif b/pgaas/src/stage/opt/app/pgaas/lib/gif/stoplight-secondary-green.gif Binary files differnew file mode 100644 index 0000000..c6d33b5 --- /dev/null +++ b/pgaas/src/stage/opt/app/pgaas/lib/gif/stoplight-secondary-green.gif diff --git a/pgaas/src/stage/opt/app/pgaas/lib/gif/stoplight-secondary-red.gif b/pgaas/src/stage/opt/app/pgaas/lib/gif/stoplight-secondary-red.gif Binary files differnew file mode 100644 index 0000000..ab16a81 --- /dev/null +++ b/pgaas/src/stage/opt/app/pgaas/lib/gif/stoplight-secondary-red.gif diff --git a/pgaas/src/stage/opt/app/pgaas/lib/gif/stoplight-secondary-yellow.gif b/pgaas/src/stage/opt/app/pgaas/lib/gif/stoplight-secondary-yellow.gif Binary files differnew file mode 100644 index 0000000..5e16750 --- /dev/null +++ b/pgaas/src/stage/opt/app/pgaas/lib/gif/stoplight-secondary-yellow.gif diff --git a/pgaas/src/stage/opt/app/pgaas/lib/gif/stoplight-y-12x25.gif b/pgaas/src/stage/opt/app/pgaas/lib/gif/stoplight-y-12x25.gif Binary files differnew file mode 100644 index 0000000..4f95bf0 --- /dev/null +++ b/pgaas/src/stage/opt/app/pgaas/lib/gif/stoplight-y-12x25.gif diff --git a/pgaas/src/stage/opt/app/pgaas/lib/gif/stoplight-y2-12x25.gif b/pgaas/src/stage/opt/app/pgaas/lib/gif/stoplight-y2-12x25.gif Binary files differnew file mode 100644 index 0000000..886e548 --- /dev/null +++ b/pgaas/src/stage/opt/app/pgaas/lib/gif/stoplight-y2-12x25.gif diff --git a/pgaas/src/stage/opt/app/pgaas/lib/gif/stoplight-y3-12x25.gif b/pgaas/src/stage/opt/app/pgaas/lib/gif/stoplight-y3-12x25.gif Binary files differnew file mode 100644 index 0000000..1bd8731 --- /dev/null +++ b/pgaas/src/stage/opt/app/pgaas/lib/gif/stoplight-y3-12x25.gif diff --git a/pgaas/src/stage/opt/app/pgaas/lib/gif/yellow-flasher-12x10.gif b/pgaas/src/stage/opt/app/pgaas/lib/gif/yellow-flasher-12x10.gif Binary files differnew file mode 100644 index 0000000..5e16750 --- /dev/null +++ b/pgaas/src/stage/opt/app/pgaas/lib/gif/yellow-flasher-12x10.gif diff --git a/pgaas/src/stage/opt/app/pgaas/lib/iDNS-responder.py b/pgaas/src/stage/opt/app/pgaas/lib/iDNS-responder.py new file mode 100755 index 0000000..f295040 --- /dev/null +++ b/pgaas/src/stage/opt/app/pgaas/lib/iDNS-responder.py @@ -0,0 +1,1105 @@ +#!/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, socket +import time, os, sys, re, subprocess, traceback, html, base64, argparse +import psycopg2 +# TODO - move lots of code to a common library to share with other python modules +# sys.path.append("/opt/app/pgaas/lib") +# import dbtools + +DEF_HOST_NAME = os.popen("hostname -f").readlines()[0].strip() +DEF_PORT_NUMBER = 8000 + +validPerDbTables = [ "pg_tables", "pg_indexes", "pg_views" ] +topButton = " <font size='1'><a href='#'>^</a></font>" + +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"] + +def traceMsg(msg): + """ print a trace message. By default, this goes to trace.out """ + file = sys.stderr if testOn else openLogFile("/opt/logs/dcae/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/logs/dcae/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/logs/dcae/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) + +def replaceQuoteNewline(str): + return re.sub('"', "'", re.sub("\n", " ", str)) + +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.6/bin/pg_ctl" + PGCTLPATH2 = "/usr/lib/postgresql/9.5/bin/pg_ctl" + PGCTLPATH3 = "/opt/app/postgresql-9.5.2/bin/pg_ctl" + if isExe(PGCTLPATH1): + statusLines = readPipe(PGCTLPATH1 + " status -D /dbroot/pgdata/main/") + elif isExe(PGCTLPATH2): + statusLines = readPipe(PGCTLPATH2 + " status -D /dbroot/pgdata/main/") + else: + statusLines = readPipe(PGCTLPATH3 + " 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("/isrw: returns %s" % isrw) + resp = 200 + msg = isrw + + elif self.path == '/healthcheck/status': + hs = readFile("/var/run/postgresql/check_cluster", "n/a") + debugTrace("/healthcheck/status: returns %s" % hs) + resp = 429 if hs == "n/a" else 200 + msg = '{ "output": "%s" }' % replaceQuoteNewline(hs) + + elif self.path == '/healthcheck/writablestatus': + isrw = readFile("/var/run/postgresql/isrw", "n/a") + debugTrace("/rw: isrw returns %s" % isrw) + resp = 429 + if re.match("Master", isrw): + resp = 200 + msg = '{ "output": "master server is up" }' + elif re.match("Secondary", isrw): + msg = '{ "output": "non-master server is up" }' + else: + msg = '{ "output": "server is not up %s" }' % replaceQuoteNewline(isrw) + errTrace("/ro: isrw returns %s" % isrw) + + elif self.path == '/healthcheck/readonlystatus': + 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) + resp = 429 + if re.match("Secondary", isrw) or re.match("Master", isrw): + resp = 200 + msg = '{ "output": "server is up" }' + else: + msg = '{ "output": "server is not up %s" }' % replaceQuoteNewline(isrw) + errTrace("/ro: isrw returns %s" % isrw) + + elif self.path == '/': + ui = readFile("/opt/app/pgaas/man/iDNS-responder.swagger.json", "n/a") + debugTrace("/: returns %s" % ui) + msg = ui + if ui != "n/a": + resp = 200 + contentType = "application/json" + + 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 == '/ismaintenance': + msg = "" + if os.path.exists("/var/run/postgresql/inmaintenance"): + resp = 200 + msg = "in maintenance mode" + else: + msg = "not in maintenance mode" + + elif self.path == '/getpubkey': + try: + resp = 200 + msg = readFile(os.path.expanduser("~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 -i ~postgres/.ssh/id_rsa ~postgres/.ssh/id_rsa* postgres@" + 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 -i ~postgres/.ssh/id_rsa " + fi + " postgres@" + 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/lib/gif/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)) + + # ATT-ONLY CODE BEGIN + elif self.path == '/swmstatus': + resp = 200 + contentType = "text/html" + msg = "<pre>\n%s\n</pre>" % readPipeHtml("set -x;sed -n '/^STARTING/,/^ENDING/p' /opt/app/aft/aftswmnode/stage/*/com/att/ecomp/dcae/storage/pgaas/*/*/proc_out") + # ATT-ONLY CODE END + + 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/logs/dcae/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/logs/dcae/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='/ismaintenance'>ismaintenance</a> == is in maintenance mode + <a href='/healthcheck/status'>healthcheck/status</a> == Consul healthcheck + <a href='/healthcheck/writablestatus'>healthcheck/writablestatus</a> == Consul writable healthcheck + <a href='/healthcheck/readonlystatus'>healthcheck/readonlystatus</a> == Consul readonly healthcheck + <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/logs/dcae/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 + " " + 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 + +class HTTPServerIPv6(http.server.HTTPServer): + address_family = socket.AF_INET6 + +if __name__ == '__main__': + parser = argparse.ArgumentParser(description="Respond to HTTP requests") + parser.add_argument("-d","--debug",help="turn on debugging",action="store_true") + parser.add_argument("-t","--test",help="turn on test mode",action="store_true") + parser.add_argument("-H", "--host", type=str, help="Hostname, defaults to '%s'" % DEF_HOST_NAME, + default=DEF_HOST_NAME) + parser.add_argument("-P", "--port", type=int, help="Port to listen on, defaults to '%d'" % DEF_PORT_NUMBER, + default=DEF_PORT_NUMBER) + args = parser.parse_args() + + global debugOn, testOn, HOST_NAME, PORT_NUMBER + debugOn = args.debug + testOn = args.test + HOST_NAME = args.host + PORT_NUMBER = args.port + + if not debugOn: + sys.stderr = openLogFile("/opt/logs/dcae/postgresql/idns/error.log") + + # server_class = http.server.HTTPServer + # httpd = server_class(("0.0.0.0", PORT_NUMBER), MyHandler) + server_class = HTTPServerIPv6 + httpd = server_class(("", 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/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..e48183c --- /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/logs/dcae/postgresql/init/error.log +errorLogLevel = WARN +errorStyle = error + +metrics = /opt/logs/dcae/postgresql/init/metrics.log +metricsLogLevel = INFO +metricsStyle = metrics + +audit = /opt/logs/dcae/postgresql/init/audit.log +auditLogLevel = INFO +auditStyle = audit + +debug = /opt/logs/dcae/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..ea58dba --- /dev/null +++ b/pgaas/src/stage/opt/app/pgaas/lib/makefile @@ -0,0 +1,39 @@ +# 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 + +stage: + rm -rf $(STAGEDIR)/$(DISTPATH)/lib + mkdir -p $(STAGEDIR)/$(DISTPATH)/lib + for i in *; do \ + case $$i in \ + [!C]*.py ) \ + j=`basename $$i .py`; \ + cp $$i $(STAGEDIR)/$(DISTPATH)/lib/$$j; \ + chmod a+x $(STAGEDIR)/$(DISTPATH)/lib/$$j; \ + ;; \ + makefile | *~ ) ;; \ + * ) \ + if [ -f $$i ]; then \ + cp $$i $(STAGEDIR)/$(DISTPATH)/lib/$$i; \ + chmod a+x $(STAGEDIR)/$(DISTPATH)/lib/$$i; \ + fi; \ + ;; \ + esac; \ + done + 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..e28d5e6 --- /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/logs/dcae/postgresql/init/error.log +dcae_admin_db_trace_file=/opt/logs/dcae/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/lib/profile.additions b/pgaas/src/stage/opt/app/pgaas/lib/profile.additions new file mode 100644 index 0000000..ad9decf --- /dev/null +++ b/pgaas/src/stage/opt/app/pgaas/lib/profile.additions @@ -0,0 +1,10 @@ + +if [ -d /opt/app/postgresql-9.5.2 ] +then PGDIR=/opt/app/postgresql-9.5.2 +elif [ -d /usr/lib/postgresql/9.6 ] +then PGDIR=/usr/lib/postgresql/9.6 +elif [ -d /usr/lib/postgresql/9.5 ] +then PGDIR=/usr/lib/postgresql/9.5 +else echo PostgreSQL bin directory not found +fi +export PATH="$PGDIR/bin:/opt/app/cdf/bin:/opt/app/pgaas/bin:$PATH" diff --git a/pgaas/src/stage/opt/app/pgaas/main/makefile b/pgaas/src/stage/opt/app/pgaas/main/makefile new file mode 100644 index 0000000..ca8af9a --- /dev/null +++ b/pgaas/src/stage/opt/app/pgaas/main/makefile @@ -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. + + +all: + +STAGEDIR=/dev/null +DISTPATH=/opt/app/pgaas + +stage: + rm -rf $(STAGEDIR)/$(DISTPATH)/main + mkdir -p $(STAGEDIR)/$(DISTPATH)/main + for i in *; do \ + case $$i in \ + *.py ) \ + j=`basename $$i .py`; \ + cp $$i $(STAGEDIR)/$(DISTPATH)/main/$$j; \ + chmod a+x $(STAGEDIR)/$(DISTPATH)/main/$$j; \ + ;; \ + makefile | *~ ) ;; \ + * ) \ + if [ -f $$i ]; then \ + cp $$i $(STAGEDIR)/$(DISTPATH)/main/$$i; \ + chmod a+x $(STAGEDIR)/$(DISTPATH)/main/$$i; \ + fi; \ + ;; \ + esac; \ + done diff --git a/pgaas/src/stage/opt/app/pgaas/main/pg_hba.conf.orig b/pgaas/src/stage/opt/app/pgaas/main/pg_hba.conf.orig new file mode 100644 index 0000000..7bf51c1 --- /dev/null +++ b/pgaas/src/stage/opt/app/pgaas/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/pgaas/src/stage/opt/app/pgaas/main/pg_ident.conf b/pgaas/src/stage/opt/app/pgaas/main/pg_ident.conf new file mode 100644 index 0000000..a5870e6 --- /dev/null +++ b/pgaas/src/stage/opt/app/pgaas/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/pgaas/src/stage/opt/app/pgaas/main/postgresql.conf.orig b/pgaas/src/stage/opt/app/pgaas/main/postgresql.conf.orig new file mode 100644 index 0000000..cb4d13a --- /dev/null +++ b/pgaas/src/stage/opt/app/pgaas/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/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/logs/dcae/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/pgaas/src/stage/opt/app/pgaas/makefile b/pgaas/src/stage/opt/app/pgaas/makefile new file mode 100644 index 0000000..75ad62b --- /dev/null +++ b/pgaas/src/stage/opt/app/pgaas/makefile @@ -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. + + +STAGEDIR=/dev/null +all: + +stage: + for i in bin lib etc man init main; do \ + ( cd $$i && $(MAKE) stage STAGEDIR=../$(STAGEDIR) ) \ + done + for i in lib/gif; do \ + ( cd $$i && $(MAKE) stage STAGEDIR=../../$(STAGEDIR) ) \ + done + +clean: + for i in bin lib etc man init main; do \ + ( cd $$i && $(MAKE) clean ) \ + done + for i in lib/gif; do \ + ( cd $$i && $(MAKE) stage STAGEDIR=../../$(STAGEDIR) clean ) \ + done + +clobber: + for i in bin lib etc man init main; do \ + ( cd $$i && $(MAKE) clobber ) \ + done + for i in lib/gif; do \ + ( cd $$i && $(MAKE) stage STAGEDIR=../../$(STAGEDIR) 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..071e9d0 --- /dev/null +++ b/pgaas/src/stage/opt/app/pgaas/man/check_cluster.man @@ -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. +.TH check_cluster 1PG {{DATE}} ONAP ONAP +.SH NAME +check_cluster - check the state of the cluster +.SH SYNOPSIS +check_cluster [-d file] [-v] [-l] [-t timeout] +.HP 20 +-d file +duplicate the status output to the given file +.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, in maintenance, 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 + +to prevent /ro from returning true +.PP +When \-d is used, the filename will have ".tmp" appended, writing the output to that temp filename, and then renaming the ".tmp" file to the given filename. 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..5b13a7b --- /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}} ONAP ONAP +.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/iDNS-responder.swagger.json b/pgaas/src/stage/opt/app/pgaas/man/iDNS-responder.swagger.json new file mode 100644 index 0000000..2b59cda --- /dev/null +++ b/pgaas/src/stage/opt/app/pgaas/man/iDNS-responder.swagger.json @@ -0,0 +1,58 @@ +{ + "swagger": "2.0", + "info": { + "version": "1.1.0", + "title": "PostgreSQL as a Service REST API" + }, + "paths": { + "/rw": { + "get": { + "description": "Gets a string indicating if this is a PostgreSQL Master server\n", + "responses": { + "200": { + "description": "Successful response", + "schema": { + "title": "status", + "type": "string" + } + } + } + } + }, + "/ro": { + "get": { + "description": "Gets a string indicating if this is either a PostgreSQL Master or Secondary server\n", + "responses": { + "200": { + "description": "Successful response", + "schema": { + "title": "status", + "type": "string" + } + } + } + } + }, + "/healthcheck/status": { + "get": { + "description": "Gets a string indicating the status of this server\n", + "responses": { + "200": { + "description": "Successful response", + "schema": { + "title": "output", + "type": "string" + } + }, + "429": { + "description": "Error response", + "schema": { + "title": "output", + "type": "string" + } + } + } + } + } + } +} diff --git a/pgaas/src/stage/opt/app/pgaas/man/iDNS-responder.swagger.yaml b/pgaas/src/stage/opt/app/pgaas/man/iDNS-responder.swagger.yaml new file mode 100644 index 0000000..5f3ffee --- /dev/null +++ b/pgaas/src/stage/opt/app/pgaas/man/iDNS-responder.swagger.yaml @@ -0,0 +1,68 @@ +# Example YAML to get you started quickly. +# Be aware that YAML has indentation based scoping. +# Code completion support is available so start typing for available options. +swagger: '2.0' + +# This is your document metadata +info: + version: "1.1.0" + title: PostgreSQL as a Service REST API + +# Describe your paths here +paths: + # This is a path endpoint. Change it. + /rw: + # This is a HTTP operation + get: + # Describe this verb here. Note: you can use markdown + description: | + Gets a string indicating if this is a PostgreSQL Master server + # Expected responses for this operation: + responses: + # Response code + 200: + description: Successful response + # A schema describing your response object. + # Use JSON Schema format + schema: + title: status + type: string + /ro: + # This is a HTTP operation + get: + # Describe this verb here. Note: you can use markdown + description: | + Gets a string indicating if this is either a PostgreSQL Master or Secondary server + # Expected responses for this operation: + responses: + # Response code + 200: + description: Successful response + # A schema describing your response object. + # Use JSON Schema format + schema: + title: status + type: string + /healthcheck/status: + # This is a HTTP operation + get: + # Describe this verb here. Note: you can use markdown + description: | + Gets a string indicating the status of this server + # Expected responses for this operation: + responses: + # Response code + 200: + description: Successful response + # A schema describing your response object. + # Use JSON Schema format + schema: + title: output + type: string + 429: + description: Error response + # A schema describing your response object. + # Use JSON Schema format + schema: + title: output + type: string 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..5aed4b1 --- /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}} ONAP ONAP +.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..d254fef --- /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}} ONAP ONAP +.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..4ce3f6c --- /dev/null +++ b/pgaas/src/stage/opt/app/pgaas/man/makefile @@ -0,0 +1,101 @@ +# 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) *.yaml *.json $(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 > $@ +start_maintenance_mode.1: start_maintenance_mode.man + DATE=$$(date +%Y-%m-%d); sed "1s/ {{DATE}} / $$DATE /" < $< | nroff -Tlp -man > $@ +stop_maintenance_mode.1: stop_maintenance_mode.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..9e12376 --- /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}} ONAP ONAP +.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..6fb7519 --- /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}} ONAP ONAP +.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..cb6a3e5 --- /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}} ONAP ONAP +.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..3051fdc --- /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}} ONAP ONAP +.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..e437a6a --- /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}} ONAP ONAP +.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..f327913 --- /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}} ONAP ONAP +.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..5e8e0ad --- /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}} ONAP ONAP +.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..393f437 --- /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}} ONAP ONAP +.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..556aea0 --- /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}} ONAP ONAP +.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..78b7fb5 --- /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}} ONAP ONAP +.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..d9391d4 --- /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}} ONAP ONAP +.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..3c8e829 --- /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}} ONAP ONAP +.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..8fc85e1 --- /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}} ONAP ONAP +.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..3b960d8 --- /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}} ONAP ONAP +.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..b6e0e7a --- /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}} ONAP ONAP +.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..78e29c3 --- /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}} ONAP ONAP +.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..3b76d21 --- /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}} ONAP ONAP +.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..2356ebd --- /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}} ONAP ONAP +.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..cd51933 --- /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}} ONAP ONAP +.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..713e144 --- /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}} ONAP ONAP +.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..fce6db4 --- /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}} ONAP ONAP +.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..ec2cc5c --- /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}} ONAP ONAP +.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/start_maintenance_mode.man b/pgaas/src/stage/opt/app/pgaas/man/start_maintenance_mode.man new file mode 100644 index 0000000..8e098a4 --- /dev/null +++ b/pgaas/src/stage/opt/app/pgaas/man/start_maintenance_mode.man @@ -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. +.TH start_maintenance_mode 1PG {{DATE}} ONAP ONAP +.SH NAME +start_maintenance_mode - convert this system to maintenance mode +.SH SYNOPSIS +start_maintenance_mode +.SH DESCRIPTION +Take this system out of the normal rotation and mark it as being in maintenance mode. +This command may only be used on a secondary system and not on a master system. +After this command is run, the PostgreSQL server will be brought down, but may be +restarted manually using the pg_ctl_start. +Note that the health checks will not regard this system as being in the normal +rotation until the command stop_maintenance_mode is executed, allowing the DBA to perform +whatever is needed to perform a backup or other maintenance routines, +such as copying the database files. +.SH FILES +/var/run/postgresql/inmaintenance 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..5bba06e --- /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}} ONAP ONAP +.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/stop_maintenance_mode.man b/pgaas/src/stage/opt/app/pgaas/man/stop_maintenance_mode.man new file mode 100644 index 0000000..9ed24bc --- /dev/null +++ b/pgaas/src/stage/opt/app/pgaas/man/stop_maintenance_mode.man @@ -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. +.TH stop_maintenance_mode 1PG {{DATE}} ONAP ONAP +.SH NAME +stop_maintenance_mode - convert this system to maintenance mode +.SH SYNOPSIS +stop_maintenance_mode +.SH DESCRIPTION +Mark this system as no longer being in maintenance mode, and +return this system back to the normal rotation. +This command may only be used on a secondary system and not on a master system. +This command will also restart the PostgreSQL server. +.SH FILES +/var/run/postgresql/inmaintenance diff --git a/pgaas/src/stage/opt/app/pgaas/man/todo b/pgaas/src/stage/opt/app/pgaas/man/todo new file mode 100644 index 0000000..c2b57f8 --- /dev/null +++ b/pgaas/src/stage/opt/app/pgaas/man/todo @@ -0,0 +1,5 @@ +ls: cannot access ../man/gen-repmgr-info.man: No such file or directory +ls: cannot access ../man/pgaas-verify-install.man: No such file or directory +ls: cannot access ../man/pgwget.man: No such file or directory +ls: cannot access ../man/repmgrd-status-changes.man: No such file or directory +ls: cannot access ../man/verify_pg_privileges.man: No such file or directory 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..98470f0 --- /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}} ONAP ONAP +.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/pgaas/src/testlock/.gitignore b/pgaas/src/testlock/.gitignore new file mode 100644 index 0000000..0618485 --- /dev/null +++ b/pgaas/src/testlock/.gitignore @@ -0,0 +1 @@ +testlock diff --git a/pgaas/src/testlock/makefile b/pgaas/src/testlock/makefile new file mode 100644 index 0000000..8e23640 --- /dev/null +++ b/pgaas/src/testlock/makefile @@ -0,0 +1,59 @@ +# 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 +DISTPATH=/dev/null + +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 $(STAGEDIR)/$(DISTPATH)/bin/testlock + chmod a+x $(STAGEDIR)/$(DISTPATH)/bin/testlock diff --git a/pgaas/src/testlock/testlock.1 b/pgaas/src/testlock/testlock.1 new file mode 100644 index 0000000..12dbb9d --- /dev/null +++ b/pgaas/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/pgaas/src/testlock/testlock.c b/pgaas/src/testlock/testlock.c new file mode 100644 index 0000000..41bea59 --- /dev/null +++ b/pgaas/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/pgaas/src/testlock/testlock.md b/pgaas/src/testlock/testlock.md new file mode 100644 index 0000000..8ec2a48 --- /dev/null +++ b/pgaas/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. @@ -0,0 +1,290 @@ +<?xml version="1.0"?> +<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/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + <parent> + <groupId>org.onap.oparent</groupId> + <artifactId>oparent</artifactId> + <version>1.0.0-SNAPSHOT</version> + </parent> + <!-- parent> + <groupId>org.onap.dcae.platform</groupId> + <artifactId>plugins</artifactId> + <version>1.0.0</version> + </parent --> + <groupId>org.onap.ccsdk.storage-pgaas</groupId> + <artifactId>pgaas</artifactId> + <name>storage-PGaaS</name> + <version>1.0.0-SNAPSHOT</version> + <url>http://maven.apache.org</url> + <properties> + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> + <sonar.sources>.</sonar.sources> + <!-- customize the SONARQUBE URL --> + <sonar.host.url>http://localhost:9000</sonar.host.url> + <!-- below are language dependent --> + <!-- for Python --> + <sonar.language>py</sonar.language> + <sonar.pluginName>Python</sonar.pluginName> + <sonar.inclusions>**/*.py</sonar.inclusions> + <!-- for JavaScaript --> + <!-- + <sonar.language>js</sonar.language> + <sonar.pluginName>JS</sonar.pluginName> + <sonar.inclusions>**/*.js</sonar.inclusions> + --> + </properties> + + <build> + <finalName>${project.artifactId}-${project.version}</finalName> + <pluginManagement> + <plugins> + <plugin> + <groupId>org.codehaus.mojo</groupId> + <artifactId>sonar-maven-plugin</artifactId> + <version>2.7.1</version> + </plugin> + </plugins> + </pluginManagement> + + <plugins> + <!-- plugin> + <artifactId>maven-assembly-plugin</artifactId> + <version>2.4.1</version> + <configuration> + <descriptors> + <descriptor>assembly/dep.xml</descriptor> + </descriptors> + </configuration> + <executions> + <execution> + <id>make-assembly</id> + <phase>package</phase> + <goals> + <goal>single</goal> + </goals> + </execution> + </executions> + </plugin --> + + <!-- first disable the default Java plugins at various stages --> + <!-- maven-resources-plugin is called during "*resource" phases by default behavior. it prepares the resources + dir. we do not need it --> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-resources-plugin</artifactId> + <version>2.6</version> + <configuration> + <skip>true</skip> + </configuration> + </plugin> + + <!-- maven-compiler-plugin is called during "compile" phases by default behavior. we do not need it --> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-compiler-plugin</artifactId> + <version>3.1</version> + <configuration> + <skip>true</skip> + </configuration> + </plugin> + + <!-- maven-jar-plugin is called during "compile" phase by default behavior. we do not need it --> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-jar-plugin</artifactId> + <version>2.4</version> + <executions> + <execution> + <id>default-jar</id> + <phase/> + </execution> + </executions> + </plugin> + + <!-- maven-install-plugin is called during "install" phase by default behavior. it tries to copy stuff under + target dir to ~/.m2. we do not need it --> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-install-plugin</artifactId> + <version>2.4</version> + <configuration> + <skip>true</skip> + </configuration> + </plugin> + + <!-- maven-surefire-plugin is called during "test" phase by default behavior. it triggers junit test. + we do not need it --> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-surefire-plugin</artifactId> + <version>2.12.4</version> + <configuration> + <skipTests>true</skipTests> + </configuration> + </plugin> + + + <!-- now we configure custom action (calling a script) at various lifecycle phases --> + <plugin> + <groupId>org.codehaus.mojo</groupId> + <artifactId>exec-maven-plugin</artifactId> + <version>1.2.1</version> + <executions> + <execution> + <id>clean phase script</id> + <phase>clean</phase> + <goals><goal>exec</goal></goals> + <configuration> + <!-- executable>${session.executionRootDirectory}/mvn-phase-script.sh</executable --> + <executable>make</executable> + <arguments> + <argument>${project.artifactId}</argument> + <argument>clean</argument> + </arguments> + <environmentVariables> + <!-- make mvn properties as env for our script --> + <MVN_PROJECT_GROUPID>${project.groupId}</MVN_PROJECT_GROUPID> + <MVN_PROJECT_ARTIFACTID>${project.artifactId}</MVN_PROJECT_ARTIFACTID> + <MVN_PROJECT_VERSION>${project.version}</MVN_PROJECT_VERSION> + <MVN_NEXUSPROXY>${onap.nexus.url}</MVN_NEXUSPROXY> + <!--MVN_DOCKERREG_URL>${docker.push.registry}</MVN_DOCKERREG_URL--> + </environmentVariables> + </configuration> + </execution> + + <execution> + <id>generate-sources script</id> + <phase>generate-sources</phase> + <goals><goal>exec</goal></goals> + <configuration> + <!-- executable>${session.executionRootDirectory}/mvn-phase-script.sh</executable --> + <executable>make</executable> + <arguments> + <argument>${project.artifactId}</argument> + <argument>generate-sources</argument> + </arguments> + <environmentVariables> + <!-- make mvn properties as env for our script --> + <MVN_PROJECT_GROUPID>${project.groupId}</MVN_PROJECT_GROUPID> + <MVN_PROJECT_ARTIFACTID>${project.artifactId}</MVN_PROJECT_ARTIFACTID> + <MVN_PROJECT_VERSION>${project.version}</MVN_PROJECT_VERSION> + <MVN_NEXUSPROXY>${onap.nexus.url}</MVN_NEXUSPROXY> + <!--MVN_DOCKERREG_URL>${docker.push.registry}</MVN_DOCKERREG_URL--> + </environmentVariables> + </configuration> + </execution> + + <execution> + <id>compile script</id> + <phase>compile</phase> + <goals><goal>exec</goal></goals> + <configuration> + <!-- executable>${session.executionRootDirectory}/mvn-phase-script.sh</executable --> + <executable>make</executable> + <arguments> + <argument>${project.artifactId}</argument> + <argument>compile</argument> + </arguments> + <environmentVariables> + <!-- make mvn properties as env for our script --> + <MVN_PROJECT_GROUPID>${project.groupId}</MVN_PROJECT_GROUPID> + <MVN_PROJECT_ARTIFACTID>${project.artifactId}</MVN_PROJECT_ARTIFACTID> + <MVN_PROJECT_VERSION>${project.version}</MVN_PROJECT_VERSION> + <MVN_NEXUSPROXY>${onap.nexus.url}</MVN_NEXUSPROXY> + <!--MVN_DOCKERREG_URL>${docker.push.registry}</MVN_DOCKERREG_URL--> + </environmentVariables> + </configuration> + </execution> + + <execution> + <id>package script</id> + <phase>package</phase> + <goals><goal>exec</goal></goals> + <configuration> + <!-- executable>${session.executionRootDirectory}/mvn-phase-script.sh</executable --> + <executable>make</executable> + <arguments> + <argument>${project.artifactId}</argument> + <argument>package</argument> + </arguments> + <environmentVariables> + <!-- make mvn properties as env for our script --> + <MVN_PROJECT_GROUPID>${project.groupId}</MVN_PROJECT_GROUPID> + <MVN_PROJECT_ARTIFACTID>${project.artifactId}</MVN_PROJECT_ARTIFACTID> + <MVN_PROJECT_VERSION>${project.version}</MVN_PROJECT_VERSION> + <MVN_NEXUSPROXY>${onap.nexus.url}</MVN_NEXUSPROXY> + <!--MVN_DOCKERREG_URL>${docker.push.registry}</MVN_DOCKERREG_URL--> + </environmentVariables> + </configuration> + </execution> + + <execution> + <id>test script</id> + <phase>test</phase> + <goals><goal>exec</goal></goals> + <configuration> + <!-- executable>${session.executionRootDirectory}/mvn-phase-script.sh</executable --> + <executable>make</executable> + <arguments> + <argument>${project.artifactId}</argument> + <argument>test</argument> + </arguments> + <environmentVariables> + <!-- make mvn properties as env for our script --> + <MVN_PROJECT_GROUPID>${project.groupId}</MVN_PROJECT_GROUPID> + <MVN_PROJECT_ARTIFACTID>${project.artifactId}</MVN_PROJECT_ARTIFACTID> + <MVN_PROJECT_VERSION>${project.version}</MVN_PROJECT_VERSION> + <MVN_NEXUSPROXY>${onap.nexus.url}</MVN_NEXUSPROXY> + <!--MVN_DOCKERREG_URL>${docker.push.registry}</MVN_DOCKERREG_URL--> + </environmentVariables> + </configuration> + </execution> + + <execution> + <id>install script</id> + <phase>install</phase> + <goals><goal>exec</goal></goals> + <configuration> + <!-- executable>${session.executionRootDirectory}/mvn-phase-script.sh</executable --> + <executable>make</executable> + <arguments> + <argument>${project.artifactId}</argument> + <argument>install</argument> + </arguments> + <environmentVariables> + <!-- make mvn properties as env for our script --> + <MVN_PROJECT_GROUPID>${project.groupId}</MVN_PROJECT_GROUPID> + <MVN_PROJECT_ARTIFACTID>${project.artifactId}</MVN_PROJECT_ARTIFACTID> + <MVN_PROJECT_VERSION>${project.version}</MVN_PROJECT_VERSION> + <MVN_NEXUSPROXY>${onap.nexus.url}</MVN_NEXUSPROXY> + <!--MVN_DOCKERREG_URL>${docker.push.registry}</MVN_DOCKERREG_URL--> + </environmentVariables> + </configuration> + </execution> + + <execution> + <id>deploy script</id> + <phase>deploy</phase> + <goals><goal>exec</goal></goals> + <configuration> + <!-- executable>${session.executionRootDirectory}/mvn-phase-script.sh</executable --> + <executable>make</executable> + <arguments> + <argument>${project.artifactId}</argument> + <argument>deploy</argument> + </arguments> + <environmentVariables> + <!-- make mvn properties as env for our script --> + <MVN_PROJECT_GROUPID>${project.groupId}</MVN_PROJECT_GROUPID> + <MVN_PROJECT_ARTIFACTID>${project.artifactId}</MVN_PROJECT_ARTIFACTID> + <MVN_PROJECT_VERSION>${project.version}</MVN_PROJECT_VERSION> + <MVN_NEXUSPROXY>${onap.nexus.url}</MVN_NEXUSPROXY> + <!--MVN_DOCKERREG_URL>${docker.push.registry}</MVN_DOCKERREG_URL--> + </environmentVariables> + </configuration> + </execution> + </executions> + </plugin> + </plugins> + </build> +</project> |