diff options
27 files changed, 1569 insertions, 0 deletions
diff --git a/daexim-offsite-backup/.gitignore b/daexim-offsite-backup/.gitignore new file mode 100755 index 00000000..a01e90ef --- /dev/null +++ b/daexim-offsite-backup/.gitignore @@ -0,0 +1,38 @@ +tandard .git ignore entries##### + +## IDE Specific Files ## +org.eclipse.core.resources.prefs +.classpath +.project +.settings +.idea +.externalToolBuilders +maven-eclipse.xml +workspace + +## Compilation Files ## +*.class +**/target +target +target-ide +MANIFEST.MF + +## Misc Ignores (OS specific etc) ## +bin/ +dist +*~ +*.ipr +*.iml +*.iws +classes +out/ +.DS_STORE +.metadata + +## Folders which contain auto generated source code ## +yang-gen-config +yang-gen-sal + +#####Archetype specific .git ignore entries####### +generate +Archetype_Next_Steps.README diff --git a/daexim-offsite-backup/README.md b/daexim-offsite-backup/README.md new file mode 100755 index 00000000..26d8a7ed --- /dev/null +++ b/daexim-offsite-backup/README.md @@ -0,0 +1,82 @@ +Introduction +====================== +You have generated an MD-SAL module. + +* You should be able to successfully run ```mvn clean install``` on this project. + +Next Steps +====================== +* run a ```mvn clean install``` if you haven't already. This will generate some code from the yang models. +* Modify the model yang file under the model project. +* Follow the comments in the generated provider class to wire your new provider into the generated +code. +* Modify the generated provider model to respond to and handle the yang model. Depending on what +you added to your model you may need to inherit additional interfaces or make other changes to +the provider model. + +Generated Bundles +====================== +* model + - Provides the yang model for your application. This is your primary northbound interface. +* provider + - Provides a template implementation for a provider to respond to your yang model. +* features + - Defines a karaf feature. If you add dependencies on third-party bundles then you will need to + modify the features.xml to list out the dependencies. +* installer + - Bundles all of the jars and third party dependencies (minus ODL dependencies) into a single + .zip file. + +Usage +====================== +## Purpose +The purpose of this ODL feature is to support local and geo-redundancy by providing a way to +back up and retrieve MD-SAL data exports to and from a Sonatype Nexus server. In order to function, +this module requires the controller to have an installation of the ```data-export-import``` module and a valid export of MD-SAL data. + +## Backup +MD-SAL Backup can be achieved using the ```daexim-offsite-backup:backup-data``` RPC either through the +RESTConf portal or through a tool such as cURL or Postman. While no input is required for this RPC, +the RPC does require the operational, models, and config .JSONs to be present in the daexim directory of the controller. +```sh +export USER=user +export PASSWORD=password +export ODL_HOST=https://yourhost.com:8181 +curl -X POST -u$USER:$PASSWORD ${ODL_HOST}/restconf/operations/daexim-offsite-backup:backup-data +``` +Through this process a timestamped archive is created in the form of ```POD_NAME-yyyyMMdd_HH-odl_backup.zip``` +where ```POD_NAME``` is the name of the ODL, specified through the properties file or through an environment variable. + +## Retrieval +MD-SAL Retrieval can be achieved by using the ```daexim-offsite-backup:retrieve-data``` RPC either through the +RESTConf portal or through a tool such as cURL or Postman. This RPC requires timestamp information and may +be supplied with an optional podName. + +```sh +export USER=user +export PASSWORD=password +export ODL_HOST=https://yourhost.com:8181 +export TARGET_ODL=targetOdlPodName +export TIMESTAMP=yyyyMMdd_HH +export DATA= ' + { + "input": { + "pod-name": "'"$TARGET_ODL"'", + "timestamp": "'"$TIMESTAMP"'" + } + }' +curl -X POST -u$USER:$PASSWORD --data $DATA ${ODL_HOST}/restconf/operations/daexim-offsite-backup:retrieve-data +``` + +Through this process an archive with the specified timestamp (and optional pod name) is downloaded from +the Nexus server and extracted into the controller's daexim directory. After this it is up to the user +to trigger an MD-SAL import. + +## Properties File +Before each RPC execution this module pulls information from a user supplied properties file. The module expects to find: +- daeximDirectory +- credentials +- nexusUrl +- podName + +If the module cannot find the properties file it will default to generic values and attempt to move forward. diff --git a/daexim-offsite-backup/features/ccsdk-daexim-offsite-backup/pom.xml b/daexim-offsite-backup/features/ccsdk-daexim-offsite-backup/pom.xml new file mode 100644 index 00000000..13c06256 --- /dev/null +++ b/daexim-offsite-backup/features/ccsdk-daexim-offsite-backup/pom.xml @@ -0,0 +1,46 @@ +<?xml version="1.0" encoding="UTF-8"?> +<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.ccsdk.parent</groupId> + <artifactId>single-feature-parent</artifactId> + <version>1.2.1-SNAPSHOT</version> + <relativePath /> + </parent> + + <groupId>org.onap.ccsdk.sli.northbound</groupId> + <artifactId>ccsdk-daexim-offsite-backup</artifactId> + <version>0.4.1-SNAPSHOT</version> + <packaging>feature</packaging> + + <name>ccsdk-sli-northbound :: daexim-offsite-backup :: ${project.artifactId}</name> + + <dependencies> + <dependency> + <groupId>org.opendaylight.controller</groupId> + <artifactId>odl-mdsal-broker</artifactId> + <type>xml</type> + <classifier>features</classifier> + </dependency> + <dependency> + <groupId>org.onap.ccsdk.sli.core</groupId> + <artifactId>ccsdk-sli</artifactId> + <version>${ccsdk.sli.core.version}</version> + <type>xml</type> + <classifier>features</classifier> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>${project.groupId}</groupId> + <artifactId>daexim-offsite-backup-model</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>${project.groupId}</groupId> + <artifactId>daexim-offsite-backup-provider</artifactId> + <version>${project.version}</version> + </dependency> + </dependencies> +</project> diff --git a/daexim-offsite-backup/features/ccsdk-daexim-offsite-backup/src/main/feature/feature.xml b/daexim-offsite-backup/features/ccsdk-daexim-offsite-backup/src/main/feature/feature.xml new file mode 100644 index 00000000..3dcb9002 --- /dev/null +++ b/daexim-offsite-backup/features/ccsdk-daexim-offsite-backup/src/main/feature/feature.xml @@ -0,0 +1,7 @@ +<?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<features xmlns="http://karaf.apache.org/xmlns/features/v1.4.0" name="ccsdk-daexim-offsite-backup"> + <repository>mvn:org.onap.ccsdk.sli.core/ccsdk-sli/LATEST/xml/features</repository> + <feature name="ccsdk-daexim-offsite-backup"> + <feature version="${ccsdk.sli.core.version}">ccsdk-sli</feature> + </feature> +</features> diff --git a/daexim-offsite-backup/features/features-daexim-offsite-backup/pom.xml b/daexim-offsite-backup/features/features-daexim-offsite-backup/pom.xml new file mode 100644 index 00000000..d7f823cf --- /dev/null +++ b/daexim-offsite-backup/features/features-daexim-offsite-backup/pom.xml @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="UTF-8"?> +<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.ccsdk.parent</groupId> + <artifactId>feature-repo-parent</artifactId> + <version>1.2.1-SNAPSHOT</version> + <relativePath/> + </parent> + + <groupId>org.onap.ccsdk.sli.northbound</groupId> + <artifactId>features-daexim-offsite-backup</artifactId> + <version>0.4.1-SNAPSHOT</version> + <packaging>feature</packaging> + + <name>ccsdk-sli-northbound :: daexim-offsite-backup :: ${project.artifactId}</name> + + <dependencies> + <dependency> + <groupId>${project.groupId}</groupId> + <artifactId>ccsdk-daexim-offsite-backup</artifactId> + <version>${project.version}</version> + <type>xml</type> + <classifier>features</classifier> + </dependency> + </dependencies> +</project> diff --git a/daexim-offsite-backup/features/pom.xml b/daexim-offsite-backup/features/pom.xml new file mode 100755 index 00000000..8c4eaf5c --- /dev/null +++ b/daexim-offsite-backup/features/pom.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="UTF-8"?> +<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.ccsdk.parent</groupId> + <artifactId>odlparent-lite</artifactId> + <version>1.2.1-SNAPSHOT</version> + </parent> + + <groupId>org.onap.ccsdk.sli.northbound</groupId> + <artifactId>daexim-offsite-backup-features</artifactId> + <version>0.4.1-SNAPSHOT</version> + <packaging>pom</packaging> + + <name>ccsdk-sli-northbound :: daexim-offsite-backup :: ${project.artifactId}</name> + + <modules> + <module>ccsdk-daexim-offsite-backup</module> + <module>features-daexim-offsite-backup</module> + </modules> +</project> diff --git a/daexim-offsite-backup/installer/pom.xml b/daexim-offsite-backup/installer/pom.xml new file mode 100755 index 00000000..2cf83d76 --- /dev/null +++ b/daexim-offsite-backup/installer/pom.xml @@ -0,0 +1,137 @@ +<?xml version="1.0" encoding="UTF-8"?> +<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.ccsdk.parent</groupId> + <artifactId>odlparent-lite</artifactId> + <version>1.2.1-SNAPSHOT</version> + <relativePath/> + </parent> + + <name>ccsdk-sli-northbound :: daexim-offsite-backup :: ${project.artifactId}</name> + <groupId>org.onap.ccsdk.sli.northbound</groupId> + <artifactId>daexim-offsite-backup-installer</artifactId> + <version>0.4.1-SNAPSHOT</version> + <packaging>pom</packaging> + <properties> + <application.name>ccsdk-daexim-offsite-backup</application.name> + <features.boot>${application.name}</features.boot> + <features.repositories>mvn:org.onap.ccsdk.sli.northbound/${features.boot}/${project.version}/xml/features</features.repositories> + <include.transitive.dependencies>false</include.transitive.dependencies> + </properties> + <dependencies> + <dependency> + <groupId>org.onap.ccsdk.sli.northbound</groupId> + <artifactId>${application.name}</artifactId> + <version>${project.version}</version> + <type>xml</type> + <classifier>features</classifier> + <exclusions> + <exclusion> + <groupId>*</groupId> + <artifactId>*</artifactId> + </exclusion> + </exclusions> + </dependency> + <dependency> + <groupId>org.onap.ccsdk.sli.northbound</groupId> + <artifactId>daexim-offsite-backup-provider</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>org.onap.ccsdk.sli.northbound</groupId> + <artifactId>daexim-offsite-backup-model</artifactId> + <version>${project.version}</version> + </dependency> + </dependencies> + <build> + <plugins> + <plugin> + <artifactId>maven-assembly-plugin</artifactId> + <version>2.6</version> + <executions> + <execution> + <id>maven-repo-zip</id> + <goals> + <goal>single</goal> + </goals> + <phase>package</phase> + <configuration> + <attach>true</attach> + <finalName>stage/${application.name}-${project.version}</finalName> + <descriptors> + <descriptor>src/assembly/assemble_mvnrepo_zip.xml</descriptor> + </descriptors> + <appendAssemblyId>true</appendAssemblyId> + </configuration> + </execution> + <execution> + <id>installer-zip</id> + <goals> + <goal>single</goal> + </goals> + <phase>package</phase> + <configuration> + <attach>true</attach> + <finalName>${application.name}-${project.version}-installer</finalName> + <descriptors> + <descriptor>src/assembly/assemble_installer_zip.xml</descriptor> + </descriptors> + <appendAssemblyId>false</appendAssemblyId> + </configuration> + </execution> + </executions> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-dependency-plugin</artifactId> + <executions> + <execution> + <id>copy-dependencies</id> + <goals> + <goal>copy-dependencies</goal> + </goals> + <phase>prepare-package</phase> + <configuration> + <transitive>false</transitive> + <outputDirectory>${project.build.directory}/assembly/system</outputDirectory> + <overWriteReleases>false</overWriteReleases> + <overWriteSnapshots>true</overWriteSnapshots> + <overWriteIfNewer>true</overWriteIfNewer> + <useRepositoryLayout>true</useRepositoryLayout> + <addParentPoms>false</addParentPoms> + <copyPom>false</copyPom> + <includeGroupIds>org.onap.ccsdk.sli.northbound</includeGroupIds> + <scope>provided</scope> + </configuration> + </execution> + </executions> + </plugin> + <plugin> + <artifactId>maven-resources-plugin</artifactId> + <version>2.6</version> + <executions> + <execution> + <id>copy-version</id> + <goals> + <goal>copy-resources</goal> + </goals> + <phase>validate</phase> + <configuration> + <outputDirectory>${basedir}/target/stage</outputDirectory> + <resources> + <resource> + <directory>src/main/resources/scripts</directory> + <includes> + <include>install-feature.sh</include> + </includes> + <filtering>true</filtering> + </resource> + </resources> + </configuration> + </execution> + </executions> + </plugin> + </plugins> + </build> +</project> diff --git a/daexim-offsite-backup/installer/src/assembly/assemble_installer_zip.xml b/daexim-offsite-backup/installer/src/assembly/assemble_installer_zip.xml new file mode 100755 index 00000000..41d23e88 --- /dev/null +++ b/daexim-offsite-backup/installer/src/assembly/assemble_installer_zip.xml @@ -0,0 +1,56 @@ +<!-- + ============LICENSE_START======================================================= + openECOMP : SDN-C + ================================================================================ + Copyright (C) 2018 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========================================================= + --> + +<!-- Defines how we build the .zip file which is our distribution. --> + +<assembly + xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0 http://maven.apache.org/xsd/assembly-1.1.0.xsd"> + <id>installer_zip</id> + <formats> + <format>zip</format> + </formats> + + <!-- we want "system" and related files right at the root level + as this file is suppose to be unzip on top of a karaf + distro. --> + <includeBaseDirectory>false</includeBaseDirectory> + + <fileSets> + <fileSet> + <directory>target/stage/</directory> + <outputDirectory>${application.name}</outputDirectory> + <fileMode>755</fileMode> + <includes> + <include>*.sh</include> + </includes> + </fileSet> + <fileSet> + <directory>target/stage/</directory> + <outputDirectory>${application.name}</outputDirectory> + <fileMode>644</fileMode> + <excludes> + <exclude>*.sh</exclude> + </excludes> + </fileSet> + </fileSets> +</assembly> diff --git a/daexim-offsite-backup/installer/src/assembly/assemble_mvnrepo_zip.xml b/daexim-offsite-backup/installer/src/assembly/assemble_mvnrepo_zip.xml new file mode 100755 index 00000000..27506098 --- /dev/null +++ b/daexim-offsite-backup/installer/src/assembly/assemble_mvnrepo_zip.xml @@ -0,0 +1,47 @@ +<!-- + ============LICENSE_START======================================================= + openECOMP : SDN-C + ================================================================================ + Copyright (C) 2018 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========================================================= + --> + +<!-- Defines how we build the .zip file which is our distribution. --> + +<assembly + xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0 http://maven.apache.org/xsd/assembly-1.1.0.xsd"> + <id>repo</id> + <formats> + <format>zip</format> + </formats> + + <!-- we want "system" and related files right at the root level + as this file is suppose to be unzip on top of a karaf + distro. --> + <includeBaseDirectory>false</includeBaseDirectory> + + <fileSets> + <fileSet> + <directory>target/assembly/</directory> + <outputDirectory>.</outputDirectory> + <excludes> + </excludes> + </fileSet> + </fileSets> + +</assembly> diff --git a/daexim-offsite-backup/installer/src/main/resources/scripts/install-feature.sh b/daexim-offsite-backup/installer/src/main/resources/scripts/install-feature.sh new file mode 100644 index 00000000..1d7be149 --- /dev/null +++ b/daexim-offsite-backup/installer/src/main/resources/scripts/install-feature.sh @@ -0,0 +1,39 @@ +#!/bin/bash + +### +# ============LICENSE_START======================================================= +# openECOMP : SDN-C +# ================================================================================ +# Copyright (C) 2018 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========================================================= +### + +ODL_HOME=${ODL_HOME:-/opt/opendaylight/current} +ODL_KARAF_CLIENT=${ODL_KARAF_CLIENT:-${ODL_HOME}/bin/client} +INSTALLERDIR=$(dirname $0) + +REPOZIP=${INSTALLERDIR}/${features.boot}-${project.version}-repo.zip + +if [ -f ${REPOZIP} ] +then + unzip -d ${ODL_HOME} ${REPOZIP} +else + echo "ERROR : repo zip ($REPOZIP) not found" + exit 1 +fi + +${ODL_KARAF_CLIENT} feature:repo-add ${features.repositories} +${ODL_KARAF_CLIENT} feature:install ${features.boot} diff --git a/daexim-offsite-backup/model/.gitignore b/daexim-offsite-backup/model/.gitignore new file mode 100755 index 00000000..eacf31a6 --- /dev/null +++ b/daexim-offsite-backup/model/.gitignore @@ -0,0 +1 @@ +/target-ide/ diff --git a/daexim-offsite-backup/model/pom.xml b/daexim-offsite-backup/model/pom.xml new file mode 100755 index 00000000..a38f085f --- /dev/null +++ b/daexim-offsite-backup/model/pom.xml @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="UTF-8"?> +<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.ccsdk.parent</groupId> + <artifactId>binding-parent</artifactId> + <version>1.2.1-SNAPSHOT</version> + <relativePath/> + </parent> + + <name>ccsdk-sli-northbound :: daexim-offsite-backup :: ${project.artifactId}</name> + <groupId>org.onap.ccsdk.sli.northbound</groupId> + <artifactId>daexim-offsite-backup-model</artifactId> + <version>0.4.1-SNAPSHOT</version> + <packaging>bundle</packaging> + + <dependencies> + <dependency> + <groupId>org.opendaylight.mdsal.model</groupId> + <artifactId>ietf-inet-types-2013-07-15</artifactId> + </dependency> + <dependency> + <groupId>org.opendaylight.mdsal.model</groupId> + <artifactId>ietf-yang-types-20130715</artifactId> + </dependency> + </dependencies> +</project> diff --git a/daexim-offsite-backup/model/scripts/python/yang2props.py b/daexim-offsite-backup/model/scripts/python/yang2props.py new file mode 100755 index 00000000..559d31b8 --- /dev/null +++ b/daexim-offsite-backup/model/scripts/python/yang2props.py @@ -0,0 +1,57 @@ +#!/usr/bin/python + +import re +import sys + + +# Convert word from foo-bar to FooBar +# words begining with a digit will be converted to _digit +def to_enum(s): + if s[0].isdigit(): + s = "_" + s + else: + s = s[0].upper() + s[1:] + return re.sub(r'(?!^)-([a-zA-Z])', lambda m: m.group(1).upper(), s) + +leaf = "" +val = "" +li = [] + +if len(sys.argv) < 3: + print 'yang2props.py <input yang> <output properties>' + sys.exit(2) + +with open(sys.argv[1], "r") as ins: + for line in ins: + # if we see a leaf save the name for later + if "leaf " in line: + match = re.search(r'leaf (\S+)', line) + if match: + leaf = match.group(1) + + # if we see enum convert the value to enum format and see if it changed + # if the value is different write a property entry + if "enum " in line: + match = re.search(r'enum "(\S+)";', line) + if match: + val = match.group(1) + enum = to_enum(val) + + # see if converting to enum changed the string + if val != enum: + property = "yang."+leaf+"."+enum+"="+val + if property not in li: + li.append( property) + + +# Open output file +fo = open(sys.argv[2], "wb") +fo.write("# yang conversion properties \n") +fo.write("# used to convert Enum back to the original yang value \n") +fo.write("\n".join(li)) +fo.write("\n") + +# Close opend file +fo.close() + + diff --git a/daexim-offsite-backup/model/src/main/yang/daexim-offsite-backup.yang b/daexim-offsite-backup/model/src/main/yang/daexim-offsite-backup.yang new file mode 100755 index 00000000..363136ca --- /dev/null +++ b/daexim-offsite-backup/model/src/main/yang/daexim-offsite-backup.yang @@ -0,0 +1,46 @@ +module daexim-offsite-backup{
+ namespace "org:onap:ccsdk:sli:northbound:daeximoffsitebackup";
+ prefix daexim-offsite-backup;
+
+ import ietf-inet-types {
+ prefix inet;
+ }
+ import ietf-yang-types {
+ prefix yang;
+ }
+ description
+ "This ODL feature is designed for transferring MD-SAL data
+ to an offsite location in the ECOMP-C containerized environments.";
+ revision "2018-09-26" {
+ description
+ "Release 19.02 draft";
+ }
+
+ rpc backup-data {
+ output {
+ leaf status { type string; }
+ leaf message { type string; }
+ }
+ }
+
+ rpc retrieve-data {
+ input {
+ leaf pod-name {
+ type string;
+ description
+ "Name of the desired MD-SAL backup's pod. If not supplied will
+ default to the name of this pod.";
+ }
+ leaf timestamp {
+ type string;
+ description
+ "Timestamp of the desired backup. Format: yyyyMMdd_HH";
+ mandatory true;
+ }
+ }
+ output {
+ leaf status { type string; }
+ leaf message { type string; }
+ }
+ }
+}////closes the module
\ No newline at end of file diff --git a/daexim-offsite-backup/pom.xml b/daexim-offsite-backup/pom.xml new file mode 100755 index 00000000..2542043a --- /dev/null +++ b/daexim-offsite-backup/pom.xml @@ -0,0 +1,48 @@ +<?xml version="1.0" encoding="UTF-8"?> +<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> + + <parent> + <groupId>org.onap.ccsdk.parent</groupId> + <artifactId>odlparent-lite</artifactId> + <version>1.2.1-SNAPSHOT</version> + <relativePath/> + </parent> + + <groupId>org.onap.ccsdk.sli.northbound</groupId> + <artifactId>daexim-offsite-backup</artifactId> + <version>0.4.1-SNAPSHOT</version> + <packaging>pom</packaging> + + <name>ccsdk-sli-northbound :: daexim-offsite-backup</name> + <description>ODL feature used for transferring MD-SAL data to an offsite location.</description> + + <modules> + <module>model</module> + <module>provider</module> + <module>features</module> + <module>installer</module> + </modules> + + <dependencyManagement> + <dependencies> + <dependency> + <groupId>org.onap.ccsdk.sli.northbound</groupId> + <artifactId>daexim-offsite-backup-features</artifactId> + <classifier>features</classifier> + <type>xml</type> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>org.onap.ccsdk.sli.northbound</groupId> + <artifactId>daexim-offsite-backup-model</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>org.onap.ccsdk.sli.northbound</groupId> + <artifactId>daexim-offsite-backup-provider</artifactId> + <version>${project.version}</version> + </dependency> + </dependencies> + </dependencyManagement> +</project> diff --git a/daexim-offsite-backup/provider/.gitignore b/daexim-offsite-backup/provider/.gitignore new file mode 100755 index 00000000..527bb69a --- /dev/null +++ b/daexim-offsite-backup/provider/.gitignore @@ -0,0 +1,3 @@ +/target-ide/ +fileToZip1 +fileToZip2
\ No newline at end of file diff --git a/daexim-offsite-backup/provider/pom.xml b/daexim-offsite-backup/provider/pom.xml new file mode 100755 index 00000000..1dc85585 --- /dev/null +++ b/daexim-offsite-backup/provider/pom.xml @@ -0,0 +1,91 @@ +<?xml version="1.0" encoding="UTF-8"?> +<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.ccsdk.parent</groupId> + <artifactId>binding-parent</artifactId> + <version>1.2.1-SNAPSHOT</version> + <relativePath/> + </parent> + + <name>ccsdk-sli-northbound :: daexim-offsite-backup :: ${project.artifactId}</name> + <groupId>org.onap.ccsdk.sli.northbound</groupId> + <artifactId>daexim-offsite-backup-provider</artifactId> + <version>0.4.1-SNAPSHOT</version> + <packaging>bundle</packaging> + + <build> + <plugins> + <plugin> + <groupId>org.apache.felix</groupId> + <artifactId>maven-bundle-plugin</artifactId> + <extensions>true</extensions> + <configuration> + <instructions> + <Export-Package>org.opendaylight.controller.config.yang.config.daexim-offsite-backup_provider</Export-Package> + <Import-Package>*</Import-Package> + </instructions> + </configuration> + </plugin> + </plugins> + </build> + + <dependencies> + <dependency> + <groupId>org.onap.ccsdk.sli.northbound</groupId> + <artifactId>daexim-offsite-backup-model</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>org.opendaylight.controller</groupId> + <artifactId>sal-binding-api</artifactId> + </dependency> + <dependency> + <groupId>org.opendaylight.controller</groupId> + <artifactId>sal-common-util</artifactId> + </dependency> + <dependency> + <artifactId>sal-test-model</artifactId> + <groupId>org.opendaylight.controller</groupId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.opendaylight.controller</groupId> + <artifactId>sal-binding-broker-impl</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.opendaylight.controller</groupId> + <artifactId>sal-binding-broker-impl</artifactId> + <classifier>tests</classifier> + <type>test-jar</type> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.apache.commons</groupId> + <artifactId>commons-lang3</artifactId> + </dependency> + <dependency> + <groupId>org.onap.ccsdk.sli.core</groupId> + <artifactId>sli-common</artifactId> + <version>${sdnctl.sli.version}</version> + </dependency> + <dependency> + <groupId>org.onap.ccsdk.sli.core</groupId> + <artifactId>sli-provider</artifactId> + <version>${sdnctl.sli.version}</version> + </dependency> + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <version>4.11</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.mockito</groupId> + <artifactId>mockito-core</artifactId> + <version>1.10.19</version> + <scope>test</scope> + </dependency> + </dependencies> +</project> diff --git a/daexim-offsite-backup/provider/src/main/java/org/onap/ccsdk/sli/northbound/daeximoffsitebackup/DaeximOffsiteBackupProvider.java b/daexim-offsite-backup/provider/src/main/java/org/onap/ccsdk/sli/northbound/daeximoffsitebackup/DaeximOffsiteBackupProvider.java new file mode 100755 index 00000000..cc16bf70 --- /dev/null +++ b/daexim-offsite-backup/provider/src/main/java/org/onap/ccsdk/sli/northbound/daeximoffsitebackup/DaeximOffsiteBackupProvider.java @@ -0,0 +1,419 @@ +/* + * ============LICENSE_START======================================================= + * openECOMP : SDN-C + * ================================================================================ + * Copyright (C) 2018 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========================================================= +*/ + +package org.onap.ccsdk.sli.northbound.daeximoffsitebackup; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.HttpURLConnection; +import java.net.URL; +import java.time.Instant; +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; +import java.util.Arrays; +import java.util.Base64; +import java.util.Collection; +import java.util.List; +import java.util.Properties; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.zip.ZipEntry; +import java.util.zip.ZipInputStream; +import java.util.zip.ZipOutputStream; +import javax.annotation.Nonnull; + +import com.google.common.util.concurrent.CheckedFuture; +import com.google.common.util.concurrent.Futures; +import com.google.common.util.concurrent.ListenableFuture; + +import org.opendaylight.controller.md.sal.binding.api.DataBroker; +import org.opendaylight.controller.md.sal.binding.api.DataTreeChangeListener; +import org.opendaylight.controller.md.sal.binding.api.WriteTransaction; +import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException; +import org.opendaylight.controller.sal.binding.api.BindingAwareBroker; +import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry; +import org.opendaylight.yang.gen.v1.org.onap.ccsdk.sli.northbound.daeximoffsitebackup.rev180926.BackupDataInput; +import org.opendaylight.yang.gen.v1.org.onap.ccsdk.sli.northbound.daeximoffsitebackup.rev180926.BackupDataOutput; +import org.opendaylight.yang.gen.v1.org.onap.ccsdk.sli.northbound.daeximoffsitebackup.rev180926.BackupDataOutputBuilder; +import org.opendaylight.yang.gen.v1.org.onap.ccsdk.sli.northbound.daeximoffsitebackup.rev180926.DaeximOffsiteBackupService; +import org.opendaylight.yang.gen.v1.org.onap.ccsdk.sli.northbound.daeximoffsitebackup.rev180926.RetrieveDataOutput; +import org.opendaylight.yang.gen.v1.org.onap.ccsdk.sli.northbound.daeximoffsitebackup.rev180926.RetrieveDataOutputBuilder; +import org.opendaylight.yang.gen.v1.org.onap.ccsdk.sli.northbound.daeximoffsitebackup.rev180926.RetrieveDataInput; +import org.opendaylight.yangtools.yang.common.RpcResult; +import org.opendaylight.yangtools.yang.common.RpcResultBuilder; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class DaeximOffsiteBackupProvider implements AutoCloseable, DaeximOffsiteBackupService, DataTreeChangeListener { + private static final Logger LOG = LoggerFactory.getLogger(DaeximOffsiteBackupProvider.class); + + private static String DAEXIM_DIR; + private static String CREDENTIALS; + private static String NEXUS_URL; + private static String POD_NAME; + private static String PROPERTIES_FILE = System.getenv("SDNC_CONFIG_DIR") + "/daexim-offsite-backup.properties"; + + private static final String OPERATIONAL_JSON = "odl_backup_operational.json"; + private static final String MODELS_JSON = "odl_backup_models.json"; + private static final String CONFIG_JSON = "odl_backup_config.json"; + private static final String BACKUP_ARCHIVE = "odl_backup.zip"; + private static final String appName = "daexim-offsite-backup"; + + private final ExecutorService executor; + private Properties properties; + private DataBroker dataBroker; + private RpcProviderRegistry rpcRegistry; + private BindingAwareBroker.RpcRegistration<DaeximOffsiteBackupService> rpcRegistration; + + public DaeximOffsiteBackupProvider(DataBroker dataBroker, + RpcProviderRegistry rpcProviderRegistry) { + LOG.info("Creating provider for " + appName); + this.executor = Executors.newFixedThreadPool(1); + this.dataBroker = dataBroker; + this.rpcRegistry = rpcProviderRegistry; + initialize(); + } + + public void initialize() { + LOG.info("Initializing provider for " + appName); + // Create the top level containers + createContainers(); + try { + DaeximOffsiteBackupUtil.loadProperties(); + } catch (Exception e) { + LOG.error("Caught Exception while trying to load properties file", e); + } + rpcRegistration = rpcRegistry.addRpcImplementation(DaeximOffsiteBackupService.class, this); + LOG.info("Initialization complete for " + appName); + } + + private void loadProperties() { + LOG.info("Loading properties from " + PROPERTIES_FILE); + if(properties == null) + properties = new Properties(); + File propertiesFile = new File(PROPERTIES_FILE); + if(!propertiesFile.exists()) { + LOG.warn("Properties file (" + PROPERTIES_FILE + ") not found. Using default properties."); + properties.put("daeximDirectory", "/opt/opendaylight/current/daexim/"); + properties.put("credentials", "admin:enc:YWRtaW4xMjM="); + properties.put("nexusUrl", "http://localhost:8081/nexus/content/repositories/"); + properties.put("podName", "UNKNOWN_ODL"); + return; + } + FileInputStream fileInputStream; + try { + fileInputStream = new FileInputStream(propertiesFile); + properties.load(fileInputStream); + fileInputStream.close(); + LOG.info(properties.size() + " properties loaded."); + LOG.info("daeximDirectory: " + properties.getProperty("daeximDirectory")); + LOG.info("nexusUrl: " + properties.getProperty("nexusUrl")); + LOG.info("podName: " + properties.getProperty("podName")); + } catch(IOException e) { + LOG.error("Error loading properties.", e); + } + } + + private void applyProperties() { + LOG.info("Applying properties..."); + if(POD_NAME == null || POD_NAME.isEmpty()) { + LOG.warn("MY_POD_NAME environment variable not set. Using value from properties."); + POD_NAME = properties.getProperty("podName"); + } + DAEXIM_DIR = properties.getProperty("daeximDirectory"); + NEXUS_URL = properties.getProperty("nexusUrl"); + + if(!properties.getProperty("credentials").contains(":")) { //Entire thing is encoded + CREDENTIALS = new String(Base64.getDecoder().decode(properties.getProperty("credentials"))); + } + else { + String[] credentials = properties.getProperty("credentials").split(":", 2); + if(credentials[1].startsWith("enc:")) { // Password is encoded + credentials[1] = new String(Base64.getDecoder().decode(credentials[1].split(":")[1])); + } + CREDENTIALS = credentials[0] + ":" + credentials[1]; + } + LOG.info("Properties applied."); + } + + private void createContainers() { + final WriteTransaction t = dataBroker.newReadWriteTransaction(); + try { + CheckedFuture<Void, TransactionCommitFailedException> checkedFuture = t.submit(); + checkedFuture.get(); + LOG.info("Create Containers succeeded!: "); + } catch (InterruptedException | ExecutionException e) { + LOG.error("Create Containers Failed: " + e); + LOG.error("context", e); + } + } + + protected void initializeChild() { + + } + + @Override + public void close() throws Exception { + LOG.info("Closing provider for " + appName); + executor.shutdown(); + rpcRegistration.close(); + LOG.info("Successfully closed provider for " + appName); + } + + @Override + public void onDataTreeChanged(@Nonnull Collection changes) { + + } + + @Override + public ListenableFuture<RpcResult<BackupDataOutput>> backupData(BackupDataInput input) { + final String SVC_OPERATION = "backup-data"; + LOG.info(appName + ":" + SVC_OPERATION + " called."); + + String statusCode; + String message = "Data sent to offsite location."; + + loadProperties(); + applyProperties(); + + LOG.info("Pod Name: " + POD_NAME); + Instant timestamp = Instant.now(); + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd_HH").withZone(ZoneId.of("GMT")); + String timestampedArchive = DAEXIM_DIR + POD_NAME + '-' + formatter.format(timestamp) + "-" + BACKUP_ARCHIVE; + try { + LOG.info("Creating archive..."); + List<String> daeximFiles = Arrays.asList(DAEXIM_DIR + OPERATIONAL_JSON,DAEXIM_DIR + MODELS_JSON, DAEXIM_DIR + CONFIG_JSON); + createArchive(daeximFiles, timestampedArchive); + LOG.info("Archive created."); + } catch(IOException e) { + LOG.error("Error creating archive " + timestampedArchive); + LOG.error(e.getMessage()); + statusCode = "500"; + message = "Archive creation failed."; + return buildBackupDataFuture(statusCode, message); + } + + try{ + LOG.info("Sending archive to Nexus server: " + NEXUS_URL); + statusCode = Integer.toString(putArchive(timestampedArchive)); + LOG.info("Archive sent to Nexus."); + } catch(IOException e) { + LOG.error("Nexus creation failed.", e); + statusCode = "500"; + message = "Nexus creation failed."; + } + + File archive = new File(timestampedArchive); + if(archive.exists()) { + archive.delete(); // Save some space on the ODL, keep them from piling up + } + + LOG.info("Sending Response statusCode=" + statusCode+ " message=" + message + " | " + SVC_OPERATION); + return buildBackupDataFuture(statusCode, message); + } + + @Override + public ListenableFuture<RpcResult<RetrieveDataOutput>> retrieveData(RetrieveDataInput input) { + final String SVC_OPERATION = "retrieve-data"; + LOG.info(appName + ":" + SVC_OPERATION + " called."); + + String statusCode = "200"; + String message = "Data retrieved from offsite location."; + + loadProperties(); + applyProperties(); + + LOG.info("Pod Name: " + POD_NAME); + String archiveIdentifier = POD_NAME + '-' + input.getTimestamp(); + String timestampedArchive = DAEXIM_DIR + archiveIdentifier + "-" + BACKUP_ARCHIVE; + LOG.info("Trying to retrieve " + timestampedArchive); + try { + statusCode = Integer.toString(getArchive(archiveIdentifier)); + } catch(IOException e) { + LOG.error("Could not retrieve archive.", e); + statusCode = "500"; + message = "Could not retrieve archive."; + return retrieveDataOutputRpcResult(statusCode, message); + } + LOG.info("Retrieved archive."); + + LOG.info("Extracting archive..."); + try { + extractArchive(DAEXIM_DIR + "-" + BACKUP_ARCHIVE); + } catch(IOException e) { + LOG.error("Could not extract archive.", e); + statusCode = "500"; + message = "Could not extract archive."; + return retrieveDataOutputRpcResult(statusCode, message); + } + LOG.info("Archive extracted."); + + return retrieveDataOutputRpcResult(statusCode, message); + } + + private boolean exportExists(List<String> daeximFiles) { + File file; + for(String f : daeximFiles) { + file = new File(f); + if(!file.exists()) { + return false; + } + } + return true; + } + + private void createArchive(List<String> daeximFiles, String timestampedArchive) throws IOException { + if(!exportExists(daeximFiles)) { + LOG.error("Daexim exports do not exist."); + throw new IOException(); + } + LOG.info("Creating " + timestampedArchive); + FileOutputStream fileOutputStream = new FileOutputStream(timestampedArchive); + ZipOutputStream zipOutputStream = new ZipOutputStream(fileOutputStream); + File targetZipFile; + FileInputStream fileInputStream; + ZipEntry zipEntry; + byte[] bytes; + int length; + for(String source : daeximFiles) { + LOG.info("Adding " + source + " to archive..."); + targetZipFile = new File(source); + fileInputStream = new FileInputStream(targetZipFile); + zipEntry = new ZipEntry(targetZipFile.getName()); + zipOutputStream.putNextEntry(zipEntry); + bytes = new byte[1024]; + + while((length = fileInputStream.read(bytes)) >= 0) { + zipOutputStream.write(bytes, 0, length); + } + fileInputStream.close(); + } + + zipOutputStream.close(); + fileOutputStream.close(); + } + + private void extractArchive(String timestampedArchive) throws IOException { + byte[] bytes = new byte[1024]; + ZipInputStream zis = new ZipInputStream(new FileInputStream(timestampedArchive)); + ZipEntry zipEntry = zis.getNextEntry(); + while(zipEntry != null){ + String fileName = zipEntry.getName(); + File newFile = new File(DAEXIM_DIR + fileName); + FileOutputStream fos = new FileOutputStream(newFile); + int len; + while ((len = zis.read(bytes)) > 0) { + fos.write(bytes, 0, len); + } + fos.close(); + LOG.info(zipEntry.getName() + " extracted."); + zipEntry = zis.getNextEntry(); + } + zis.closeEntry(); + zis.close(); + LOG.info(timestampedArchive + " extracted successfully."); + } + + private int putArchive(String timestampedArchive) throws IOException { + File archive = new File(timestampedArchive); + HttpURLConnection connection = getNexusConnection(archive.getName()); + connection.setRequestProperty("Content-Length", Long.toString(archive.length())); + connection.setRequestMethod("PUT"); + connection.setDoOutput(true); + + FileInputStream fileInputStream = new FileInputStream(archive); + OutputStream outputStream = connection.getOutputStream(); + + byte[] bytes = new byte[1024]; + int length; + while((length = fileInputStream.read(bytes)) >= 0) { + outputStream.write(bytes, 0, length); + } + + outputStream.flush(); + outputStream.close(); + fileInputStream.close(); + connection.disconnect(); + + LOG.info("Status: " + connection.getResponseCode()); + LOG.info("Message: " + connection.getResponseMessage()); + return connection.getResponseCode(); + } + + private HttpURLConnection getNexusConnection(String archive) throws IOException { + URL url = new URL(NEXUS_URL + archive); + String auth = "Basic " + javax.xml.bind.DatatypeConverter.printBase64Binary(CREDENTIALS.getBytes()); + HttpURLConnection connection = (HttpURLConnection) url.openConnection(); + connection.addRequestProperty("Authorization", auth); + connection.setRequestProperty("Connection", "keep-alive"); + connection.setRequestProperty("Proxy-Connection", "keep-alive"); + return connection; + } + + private int getArchive(String archiveIdentifier) throws IOException { + File archive = new File(DAEXIM_DIR + "backup.zip"); + if(archive.exists()) { + LOG.info("Recently retrieved archive found. Removing old archive..."); + archive.delete(); + LOG.info("Archive removed."); + } + HttpURLConnection connection = getNexusConnection( archiveIdentifier + "-" + BACKUP_ARCHIVE); + connection.setRequestMethod("GET"); + connection.setDoInput(true); + + InputStream connectionInputStream = connection.getInputStream(); + FileOutputStream fileOutputStream = new FileOutputStream(archive); + + byte[] bytes = new byte[1024]; + int length; + while((length = connectionInputStream.read(bytes)) >= 0) { // while connection has bytes + fileOutputStream.write(bytes, 0, length); // write to archive + } + connection.disconnect(); + + LOG.info("Status: " + connection.getResponseCode()); + LOG.info("Message: " + connection.getResponseMessage()); + LOG.info(archive.getName() + " successfully created."); + return connection.getResponseCode(); + } + + private ListenableFuture<RpcResult<BackupDataOutput>> buildBackupDataFuture(String statusCode, String message) { + BackupDataOutputBuilder outputBuilder = new BackupDataOutputBuilder(); + outputBuilder.setStatus(statusCode); + outputBuilder.setMessage(message); + RpcResult<BackupDataOutput> rpcResult = RpcResultBuilder.<BackupDataOutput> status(true).withResult(outputBuilder.build()).build(); + return Futures.immediateFuture(rpcResult); + } + + private ListenableFuture<RpcResult<RetrieveDataOutput>> retrieveDataOutputRpcResult(String status, String message) { + RetrieveDataOutputBuilder outputBuilder = new RetrieveDataOutputBuilder(); + outputBuilder.setStatus(status); + outputBuilder.setMessage(message); + RpcResult<RetrieveDataOutput> rpcResult = RpcResultBuilder.<RetrieveDataOutput> status(true).withResult(outputBuilder.build()).build(); + return Futures.immediateFuture(rpcResult); + } +} diff --git a/daexim-offsite-backup/provider/src/main/java/org/onap/ccsdk/sli/northbound/daeximoffsitebackup/DaeximOffsiteBackupUtil.java b/daexim-offsite-backup/provider/src/main/java/org/onap/ccsdk/sli/northbound/daeximoffsitebackup/DaeximOffsiteBackupUtil.java new file mode 100755 index 00000000..7adb2fa1 --- /dev/null +++ b/daexim-offsite-backup/provider/src/main/java/org/onap/ccsdk/sli/northbound/daeximoffsitebackup/DaeximOffsiteBackupUtil.java @@ -0,0 +1,78 @@ +/*- + * ============LICENSE_START======================================================= + * openECOMP : SDN-C + * ================================================================================ + * Copyright (C) 2018 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========================================================= + */ + +package org.onap.ccsdk.sli.northbound.daeximoffsitebackup; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.Properties; + +import org.opendaylight.yang.gen.v1.org.onap.ccsdk.sli.northbound.daeximoffsitebackup.rev180926.BackupDataOutputBuilder; + +import org.opendaylight.yang.gen.v1.org.onap.ccsdk.sli.northbound.daeximoffsitebackup.rev180926.RetrieveDataInputBuilder; +import org.opendaylight.yang.gen.v1.org.onap.ccsdk.sli.northbound.daeximoffsitebackup.rev180926.RetrieveDataOutputBuilder; + +import org.onap.ccsdk.sli.core.sli.provider.MdsalHelper; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class DaeximOffsiteBackupUtil extends MdsalHelper { + private static final Logger LOG = LoggerFactory.getLogger(DaeximOffsiteBackupUtil.class); + private static String PROPERTIES_FILE; + + public static void loadProperties() { + File file = new File(PROPERTIES_FILE); + Properties properties = new Properties(); + InputStream input = null; + if(file.isFile() && file.canRead()) { + try { + input = new FileInputStream(file); + properties.load(input); + LOG.info("Loaded properties from " + PROPERTIES_FILE); + setProperties(properties); + } catch (Exception e) { + LOG.error("Failed to load properties " + PROPERTIES_FILE + "\n", e); + } finally { + if(input != null) { + try { + input.close(); + } catch (IOException e) { + LOG.error("Failed to close properties file " + PROPERTIES_FILE + "\n", e); + } + } + } + } + } + + static { + // Trick class loader into loading builders. Some of + // these will be needed later by Reflection classes, but need + // to explicitly "new" them here to get class loader to load them. + + BackupDataOutputBuilder b1 = new BackupDataOutputBuilder(); + + RetrieveDataOutputBuilder b2 = new RetrieveDataOutputBuilder(); + RetrieveDataInputBuilder b3 = new RetrieveDataInputBuilder(); + } +} diff --git a/daexim-offsite-backup/provider/src/main/resources/daexim-offsite-backup.properties b/daexim-offsite-backup/provider/src/main/resources/daexim-offsite-backup.properties new file mode 100755 index 00000000..bdfa8155 --- /dev/null +++ b/daexim-offsite-backup/provider/src/main/resources/daexim-offsite-backup.properties @@ -0,0 +1,6 @@ +# Example properties file + +daeximDirectory=/opt/opendaylight/current/daexim/ +credentials=admin:enc:YWRtaW4xMjM= +nexusUrl=http://localhost:8081/nexus/content/repositories/ +podName=UNKNOWN_ODL
\ No newline at end of file diff --git a/daexim-offsite-backup/provider/src/main/resources/org/opendaylight/blueprint/DaeximOffsiteBackup.xml b/daexim-offsite-backup/provider/src/main/resources/org/opendaylight/blueprint/DaeximOffsiteBackup.xml new file mode 100755 index 00000000..8e2101ad --- /dev/null +++ b/daexim-offsite-backup/provider/src/main/resources/org/opendaylight/blueprint/DaeximOffsiteBackup.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="UTF-8"?> +<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0" + xmlns:odl="http://opendaylight.org/xmlns/blueprint/v1.0.0" + odl:use-default-for-reference-types="true"> + + <reference id="dataBroker" + interface="org.opendaylight.controller.md.sal.binding.api.DataBroker" + odl:type="default" /> + + <reference id="rpcRegistry" + interface="org.opendaylight.controller.sal.binding.api.RpcProviderRegistry" + odl:type="default" /> + + <bean id="provider" class="org.onap.ccsdk.sli.northbound.daeximoffsitebackup.DaeximOffsiteBackupProvider"> + <argument ref="dataBroker" /> + <argument ref="rpcRegistry" /> + </bean> + + <odl:rpc-implementation ref="provider"/> +</blueprint> diff --git a/daexim-offsite-backup/provider/src/test/java/org/onap/ccsdk/sli/northbound/daeximoffsitebackup/DaeximOffsiteBackupProviderTest.java b/daexim-offsite-backup/provider/src/test/java/org/onap/ccsdk/sli/northbound/daeximoffsitebackup/DaeximOffsiteBackupProviderTest.java new file mode 100644 index 00000000..65d0dcaf --- /dev/null +++ b/daexim-offsite-backup/provider/src/test/java/org/onap/ccsdk/sli/northbound/daeximoffsitebackup/DaeximOffsiteBackupProviderTest.java @@ -0,0 +1,223 @@ +/*- + * ============LICENSE_START======================================================= + * openECOMP : SDN-C + * ================================================================================ + * Copyright (C) 2018 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========================================================= + */ + +package org.onap.ccsdk.sli.northbound.daeximoffsitebackup; + +import org.eclipse.jdt.annotation.Nullable; +import org.junit.Before; +import org.junit.Test; + +import org.opendaylight.controller.md.sal.binding.api.*; +import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException; +import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry; + +import org.opendaylight.yang.gen.v1.org.onap.ccsdk.sli.northbound.daeximoffsitebackup.rev180926.DaeximOffsiteBackupService; + +import org.opendaylight.yang.gen.v1.org.onap.ccsdk.sli.northbound.daeximoffsitebackup.rev180926.RetrieveDataInput; + +import org.opendaylight.yangtools.yang.binding.Augmentation; +import org.opendaylight.yangtools.yang.binding.DataContainer; + +import com.google.common.util.concurrent.CheckedFuture; + +import java.io.File; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.List; +import java.util.Properties; +import java.util.concurrent.ExecutionException; + +import static org.mockito.Mockito.*; +import static org.junit.Assert.*; + +public class DaeximOffsiteBackupProviderTest { + public DataBroker dataBroker; + public ReadWriteTransaction writeTransaction; + public CheckedFuture<Void, TransactionCommitFailedException> checkedFuture; + public RpcProviderRegistry rpcRegistry; + public DaeximOffsiteBackupProvider provider; + public Properties resProps; + + @Before + public void setup() { + resProps = new Properties(); + resProps.put("error-code", "200"); + resProps.put("error-message", "Success"); + dataBroker = mock(DataBroker.class); + writeTransaction = mock(ReadWriteTransaction.class); + checkedFuture = mock(CheckedFuture.class); + rpcRegistry = mock(RpcProviderRegistry.class); + when(rpcRegistry.addRoutedRpcImplementation(any(), any(DaeximOffsiteBackupService.class))).thenReturn(null); + try { + when(checkedFuture.get()).thenReturn(null); + } + catch(InterruptedException | ExecutionException e) { + e.printStackTrace(); + } + when(writeTransaction.submit()).thenReturn(checkedFuture); + when(dataBroker.newReadWriteTransaction()).thenReturn(writeTransaction); + + provider = new DaeximOffsiteBackupProvider(dataBroker, rpcRegistry); + } + + @Test + public void initializeTest() { + provider.initialize(); + } + + @Test + public void closeTest() { + try { + provider.close(); + } + catch(Exception e) { + e.printStackTrace(); + } + } + + @Test + public void onDataTreeChangedTest() { + provider.onDataTreeChanged(null); + // onDataTreeChanged is an empty stub + } + + @Test + public void backupDataTest() { + try { + assertNotNull(provider.backupData(null)); + } + catch(Exception e) { + fail(); + } + try { + assertNotNull(provider.backupData(null)); + } + catch(Exception e) { + fail(); + } + try { + assertNotNull(provider.backupData(null)); + } + catch(Exception e) { + fail(); + } + try { + assertNotNull(provider.backupData(null)); + } + catch(Exception e) { + fail(); + } + try { + assertNotNull(provider.backupData(null)); + } + catch(Exception e) { + fail(); + } + } + + @Test + public void retrieveDataTest() { + RetrieveDataInput input = new RetrieveDataInput() { + @Override + public <E extends Augmentation<RetrieveDataInput>> @Nullable E augmentation(Class<E> augmentationType) { + return null; + } + + @Override + public String getPodName() { + return "Some Pod"; + } + + @Override + public String getTimestamp() { + return "Some Timestamp"; + } + + @Override + public Class<? extends DataContainer> getImplementedInterface() { + return null; + } + }; + try { + assertNotNull(provider.retrieveData(input)); + } + catch(Exception e) { + fail(); + } + try { + assertNotNull(provider.retrieveData(input)); + } + catch(Exception e) { + fail(); + } + try { + assertNotNull(provider.retrieveData(input)); + } + catch(Exception e) { + fail(); + } + try { + assertNotNull(provider.retrieveData(input)); + } + catch(Exception e) { + fail(); + } + try { + assertNotNull(provider.retrieveData(input)); + } + catch(Exception e) { + fail(); + } + } + + @Test + public void archiveOperationsTest() { + List<String> files = Arrays.asList("src/test/resources/fileToZip1", "src/test/resources/fileToZip2"); + String archive = "src/test/resources/zippedArchive.zip"; + try { + Method method = provider.getClass().getDeclaredMethod("createArchive", List.class, String.class); + method.setAccessible(true); + method.invoke(provider, files, archive); + + } + catch(NoSuchMethodException | IllegalAccessException | InvocationTargetException e) { + fail(); + } + + try { + Field field = provider.getClass().getDeclaredField("DAEXIM_DIR"); + field.setAccessible(true); + field.set(provider, ""); + Method method = provider.getClass().getDeclaredMethod("extractArchive", String.class); + method.setAccessible(true); + method.invoke(provider, archive); + } + catch(NoSuchMethodException | IllegalAccessException | InvocationTargetException | NoSuchFieldException e) { + fail(); + } + finally { + File zip = new File(archive); + zip.delete(); + } + } +} diff --git a/daexim-offsite-backup/provider/src/test/java/org/onap/ccsdk/sli/northbound/daeximoffsitebackup/DaeximOffsiteBackupUtilTest.java b/daexim-offsite-backup/provider/src/test/java/org/onap/ccsdk/sli/northbound/daeximoffsitebackup/DaeximOffsiteBackupUtilTest.java new file mode 100644 index 00000000..16ce6819 --- /dev/null +++ b/daexim-offsite-backup/provider/src/test/java/org/onap/ccsdk/sli/northbound/daeximoffsitebackup/DaeximOffsiteBackupUtilTest.java @@ -0,0 +1,40 @@ +/*- + * ============LICENSE_START======================================================= + * openECOMP : SDN-C + * ================================================================================ + * Copyright (C) 2018 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========================================================= + */ + +package org.onap.ccsdk.sli.northbound.daeximoffsitebackup; + +import org.junit.Test; + +import java.lang.reflect.Field; + +public class DaeximOffsiteBackupUtilTest { + @Test + public void loadProperties() { + try { + Field field = DaeximOffsiteBackupUtil.class.getDeclaredField("PROPERTIES_FILE"); + field.setAccessible(true); + field.set(new DaeximOffsiteBackupUtil(), "src/test/resources/daexim-offsite-backup.properties"); + DaeximOffsiteBackupUtil.loadProperties(); + } catch(Exception e) { + // Files don't exist on build server + } + } +} diff --git a/daexim-offsite-backup/provider/src/test/resources/daexim-offsite-backup.properties b/daexim-offsite-backup/provider/src/test/resources/daexim-offsite-backup.properties new file mode 100755 index 00000000..49dd133b --- /dev/null +++ b/daexim-offsite-backup/provider/src/test/resources/daexim-offsite-backup.properties @@ -0,0 +1,4 @@ +daeximDirectory=/opt/opendaylight/current/daexim/ +credentials=admin:admin123 +nexusUrl=http://localhost:8081/nexus/content/repositories/ +podName=UNKNOWN_ODL
\ No newline at end of file diff --git a/daexim-offsite-backup/provider/src/test/resources/fileToZip1 b/daexim-offsite-backup/provider/src/test/resources/fileToZip1 new file mode 100644 index 00000000..c7ef4260 --- /dev/null +++ b/daexim-offsite-backup/provider/src/test/resources/fileToZip1 @@ -0,0 +1 @@ +Lorem ipsum.
\ No newline at end of file diff --git a/daexim-offsite-backup/provider/src/test/resources/fileToZip2 b/daexim-offsite-backup/provider/src/test/resources/fileToZip2 new file mode 100644 index 00000000..c7ef4260 --- /dev/null +++ b/daexim-offsite-backup/provider/src/test/resources/fileToZip2 @@ -0,0 +1 @@ +Lorem ipsum.
\ No newline at end of file @@ -107,6 +107,7 @@ <module>lcm</module> <module>dmaap-listener</module> <module>ueb-listener</module> + <module>daexim-offsite-backup</module> <module>features</module> <module>artifacts</module> </modules> |