├── .gitignore ├── .travis.yml ├── GETTING-STARTED.md ├── LICENSE ├── README.md ├── build.config.js ├── images ├── backconfig_restore.png ├── backup_conf_restore_fail.png ├── backupconf_overview.png └── backupconf_popup.png ├── package.json ├── pom.xml ├── src ├── deb │ └── control │ │ └── control ├── main │ ├── java │ │ └── org │ │ │ └── graylog │ │ │ └── plugins │ │ │ └── backup │ │ │ ├── BackupConfiguration.java │ │ │ ├── BackupConfigurationMetaData.java │ │ │ ├── BackupConfigurationModule.java │ │ │ ├── BackupConfigurationPeriodical.java │ │ │ ├── BackupConfigurationPlugin.java │ │ │ ├── BackupException.java │ │ │ ├── RestoreException.java │ │ │ ├── model │ │ │ └── BackupStruct.java │ │ │ ├── service │ │ │ ├── BackupResource.java │ │ │ ├── BackupService.java │ │ │ └── impl │ │ │ │ └── BackupServiceImpl.java │ │ │ └── strategy │ │ │ ├── AbstractMongoBackupStrategy.java │ │ │ ├── BackupFactoryStrategy.java │ │ │ ├── BackupStrategy.java │ │ │ ├── FsBackupStrategy.java │ │ │ └── S3Strategy.java │ └── resources │ │ ├── META-INF │ │ └── services │ │ │ └── org.graylog2.plugin.Plugin │ │ └── org.graylog.plugins.graylog-plugin-backup-configuration │ │ └── graylog-plugin.properties ├── test │ ├── java │ │ └── org │ │ │ └── graylog │ │ │ └── plugins │ │ │ └── backup │ │ │ ├── BackConfigurationPeriodicalTest.java │ │ │ └── BackupStructTest.java │ └── resources │ │ ├── fakefiles │ │ ├── 201609190618.zip │ │ └── 201609190620.zip │ │ └── log4j.xml └── web │ ├── components │ ├── BackupActions.jsx │ ├── BackupConfiguration.jsx │ └── BackupStore.jsx │ └── index.jsx └── webpack.config.js /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | *.iml 3 | *.ipr 4 | *.iws 5 | .classpath 6 | .project 7 | .settings/ 8 | target/ 9 | dependency-reduced-pom.xml 10 | node_modules 11 | node 12 | build 13 | build.config.js.sample 14 | 15 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: required 2 | dist: trusty 3 | language: java 4 | jdk: 5 | - oraclejdk8 6 | install: 7 | - mvn install -DskipTests=true -Dmaven.javadoc.skip=true -Dskip.web.build=true -B 8 | -V 9 | script: 10 | - mvn test -Dskip.web.build=true -B 11 | addons: 12 | apt: 13 | packages: 14 | - rpm 15 | before_deploy: 16 | - mvn jdeb:jdeb && export RELEASE_DEB_FILE=$(ls target/*.deb) 17 | - mvn rpm:rpm && export RELEASE_RPM_FILE=$(find target/ -name '*.rpm' | tail -1) 18 | - rm -f target/original-*.jar 19 | - export RELEASE_PKG_FILE=$(ls target/*.jar) 20 | - echo "Deploying release to GitHub releases" 21 | deploy: 22 | provider: releases 23 | file: 24 | - "${RELEASE_PKG_FILE}" 25 | - "${RELEASE_DEB_FILE}" 26 | - "${RELEASE_RPM_FILE}" 27 | skip_cleanup: true 28 | on: 29 | tags: true 30 | jdk: oraclejdk8 31 | api-key: 32 | secure: XaTXBpkGY3z9usbo1ZJweaSHNql9RE8hpW6nLNmNXxT4jVnlkxL+caiyHOCYTqTNvnC1b5Vy/6wubDuy4XwExvNpmyAbQaZkDjvwimVEUC2mcFCXRxz3D9aCu6hvaQfCnY/BQzEde1lccLPnawfnfkXeY1joDOPV07/RRmVPyw6GeTbR4EtgiKo+lqw/VhA1hAV3zLti239ZpaIYEF6Zvy4mJ9/+qTrEcCB5yFtSim0aTRVwOo8StgKIcd2I32Re1+IIq6NNj/PTLkNWUMjefDkmlJ99YwfdDRqmco0CI2fY/UxWmVOCxLgqFQd+KZd/cXDMa7qtrexjXt0ObZXLldZhE5RtvvggjkxGqbHp60FdQ/pbMn811Ox79FWnFUHNrCeNLWyMfchosnul6EjKV3yIEQJ+glIUBMthT0gjWZiO9iF3IHQ5b0TXaphLoy8cf23AsCAMQsuj4bWo9Q1XJTEXXfQU9dj1v5eHHuA/fScHIKG44cv68uoWxQggmhg7cZ4CELN6uR9pbLoGiyatUO4BeGKBQ720/roHfD/hNmMoZ3O3x9yGQ+V10g3XhbtFW1XhI8b9jaKWY/31dNVvAXAyBIYIO9vvWV+pAfgm+54A9hCGhRysz2DR/BNGf87nKcePMjw7BJNNY+lpDPuEtc+1TvzcKDAls55QEJ3f5kM= 33 | -------------------------------------------------------------------------------- /GETTING-STARTED.md: -------------------------------------------------------------------------------- 1 | Getting started with your new Graylog plugin 2 | ============================================ 3 | 4 | Welcome to your new Graylog plugin! 5 | 6 | Please refer to http://docs.graylog.org/en/latest/pages/plugins.html for documentation on how to write 7 | plugins for Graylog. 8 | 9 | Travis CI 10 | --------- 11 | 12 | There is a `.travis.yml` template in this project which is prepared to automatically 13 | deploy the plugin artifacts (JAR, DEB, RPM) to GitHub releases. 14 | 15 | You just have to add your encrypted GitHub access token to the `.travis.yml`. 16 | The token can be generated in your [GitHub personal access token settings](https://github.com/settings/tokens). 17 | 18 | Before Travis CI works, you have to enable it. Install the Travis CI command line 19 | application and execute `travis enable`. 20 | 21 | To encrypt your GitHub access token you can use `travis encrypt`. 22 | 23 | Alternatively you can use `travis setup -f releases` to automatically create a GitHub 24 | access token and add it to the `.travis.yml` file. **Attention:** doing this 25 | will replace some parts of the `.travis.yml` file and you have to restore previous 26 | settings. 27 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # This project is now ARCHIVED and not maintained. Feel free to fork it and improve 2 | 3 | # BackupConfig Plugin for Graylog 4 | 5 | [![Build Status](https://api.travis-ci.org/fbalicchia/graylog-plugin-backup-configuration.svg?branch=master)](https://travis-ci.org/fbalicchia/graylog-plugin-backup-configuration.git) 6 | [![Github Downloads](https://img.shields.io/github/downloads/fbalicchia/graylog-plugin-backup-configuration/total.svg)](https://github.com/fbalicchia/graylog-plugin-backup-configuration/releases) 7 | 8 | 9 | This plugin provides the possibility of saving and restore graylog environment configurations like registered user, dashboard, input etc.etc. To do this task the plugin uses directly **mongorestore** and **mongodump** command. 10 | At the moment is supported only unix-like os and dump can be stored only on filesystem and not on other Storage Service like s3 etc.etc 11 | 12 | Any feedback are wellcome ! 13 | 14 | **Required Graylog version:** 2.1 and later 15 | 16 | Installation 17 | ------------ 18 | 19 | [Download the plugin](https://github.com/fbalicchia/graylog-plugin-backup-configuration/releases) 20 | and place the `.jar` file in your Graylog plugin directory. The plugin directory 21 | is the `plugins/` folder relative from your `graylog-server` directory by default 22 | and can be configured in your `graylog.conf` file. 23 | Restart `graylog-server` and you are done. 24 | 25 | "Official" release is cut around the last Graylog build of plugins release in this case 2.1.2, nothing prevents to compile it independently using 26 | for example rc or beta version. In the same way binary package install jar under folder '/usr/share/graylog-server/plugin' 27 | 28 | To adapt it to yours environment just change 'graylog.version' and 'graylog.plugin-dir' properties in pom file 29 | the is created using a third library and not '-gzip' flag introduced with 3.2 Mongo's version 30 | 31 | 32 | Usage 33 | ----- 34 | 35 | You can configure backup plugin Under System -> Configurations. 36 | 37 | [![](https://github.com/fbalicchia/graylog-plugin-backup-configuration/blob/master/images/backupconf_overview.png)] 38 | 39 | Using `update configuration button` is possible adapt configuration to your environment. If not specified back data is saved under graylog data directory. 40 | 41 | [![](https://github.com/fbalicchia/graylog-plugin-backup-configuration/blob/master/images/backupconf_popup.png)] 42 | 43 | Backup file follow the this naming convention **graylogyyyyMMddHHmm.zip** 44 | 45 | For restore data is necessary to put backup file under restore folder. 46 | At the moment there is a limitation that under restore folder there is only zip without any directory. 47 | 48 | * Under System-configuration press `Restore data button`. If something fails the system show the corresponding error 49 | 50 | [![](https://github.com/fbalicchia/graylog-plugin-backup-configuration/blob/master/images/backup_conf_restore_fail.png)] 51 | 52 | Otherwise if process ends successfully 53 | 54 | [![](https://github.com/fbalicchia/graylog-plugin-backup-configuration/blob/master/images/backconfig_restore.png)] 55 | 56 | 57 | `Simple configuration example` 58 | * threshold PT1M (every minute) 59 | * Enable backup Process 60 | * Select directory where you want to save data for example /tmp/data/bck and /tmp/data/restore 61 | * find where MongoDump is installed. On ubuntu, for example, by default is under */usr/bin* 62 | 63 | To restore your data please put the zip in this restore folder in this case /tmp/data/restore then from GUI click restore data 64 | 65 | 66 | 67 | 68 | 69 | -------------------------------------------------------------------------------- /build.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | 3 | module.exports = { 4 | // Make sure that this is the correct path to the web interface part of the Graylog server repository. 5 | web_src_path: path.resolve(__dirname, '../graylog2-server', 'graylog2-web-interface'), 6 | }; 7 | -------------------------------------------------------------------------------- /images/backconfig_restore.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fbalicchia/graylog-plugin-backup-configuration/fbbe7f0ba00518e35fc891b3a62949376d8ab2e9/images/backconfig_restore.png -------------------------------------------------------------------------------- /images/backup_conf_restore_fail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fbalicchia/graylog-plugin-backup-configuration/fbbe7f0ba00518e35fc891b3a62949376d8ab2e9/images/backup_conf_restore_fail.png -------------------------------------------------------------------------------- /images/backupconf_overview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fbalicchia/graylog-plugin-backup-configuration/fbbe7f0ba00518e35fc891b3a62949376d8ab2e9/images/backupconf_overview.png -------------------------------------------------------------------------------- /images/backupconf_popup.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fbalicchia/graylog-plugin-backup-configuration/fbbe7f0ba00518e35fc891b3a62949376d8ab2e9/images/backupconf_popup.png -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "BackupConfiguration", 3 | "version": "1.0.3-SNAPSHOT", 4 | "description": "", 5 | "repository": { 6 | "type": "git", 7 | "url": "fbalicchia/graylog-plugin-backup-configuration.git" 8 | }, 9 | "scripts": { 10 | "start": "./node_modules/.bin/webpack-dev-server", 11 | "build": "./node_modules/.bin/webpack", 12 | "lint": "./node_modules/.bin/eslint -c .eslintrc src/**/*" 13 | }, 14 | "keywords": [ 15 | "graylog" 16 | ], 17 | "author": "Filippo Balicchia ", 18 | "license": "MIT", 19 | "dependencies": { 20 | "history": "^1.17.0", 21 | "react": "0.14.x", 22 | "react-bootstrap": "^0.28.1", 23 | "react-dom": "^0.14.5", 24 | "react-router": "~1.0.0", 25 | "react-router-bootstrap": "^0.19.0", 26 | "reflux": "^0.2.12" 27 | }, 28 | "devDependencies": { 29 | "webpack": "^1.12.2", 30 | "graylog-web-plugin": "file:../graylog2-server/graylog2-web-interface/packages/graylog-web-plugin" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.sonatype.oss 7 | oss-parent 8 | 9 9 | 10 | 11 | 12 | 13 | 3.1 14 | 15 | 16 | org.graylog.plugins 17 | graylog-plugin-backup-configuration 18 | 1.0.3-SNAPSHOT 19 | jar 20 | 21 | ${project.artifactId} 22 | Graylog ${project.artifactId} plugin. 23 | https://www.graylog.org 24 | 25 | 26 | 27 | Filippo Balicchia 28 | fbalicchia@gmail.com 29 | 30 | 31 | 32 | 33 | scm:git:git@github.com:fbalicchia/graylog-plugin-backup-configuration.git 34 | scm:git:git@github.com:fbalicchia/graylog-plugin-backup-configuration.git 35 | 36 | https://github.com/fbalicchia/graylog-plugin-backup-configuration.git 37 | HEAD 38 | 39 | 40 | UTF-8 41 | 1.8 42 | 1.8 43 | 2.1.2 44 | /usr/share/graylog-server/plugin 45 | 1.10.19 46 | 0.29 47 | 4.12 48 | 1.3 49 | 1.9 50 | 1.11.105 51 | 52 | 53 | 54 | 55 | 56 | sonatype-nexus-snapshots 57 | Sonatype Nexus Snapshots 58 | https://oss.sonatype.org/content/repositories/snapshots 59 | 60 | 61 | sonatype-nexus-staging 62 | Nexus Release Repository 63 | https://oss.sonatype.org/service/local/staging/deploy/maven2/ 64 | 65 | 66 | 67 | 68 | 69 | 70 | sonatype-nexus-snapshots 71 | Sonatype Nexus Snapshots 72 | https://oss.sonatype.org/content/repositories/snapshots 73 | 74 | false 75 | 76 | 77 | 78 | 79 | 80 | sonatype-nexus-releases 81 | Sonatype Nexus Releases 82 | https://oss.sonatype.org/content/repositories/releases 83 | 84 | 85 | 86 | false 87 | 88 | 89 | 90 | 91 | 92 | 93 | org.graylog2 94 | graylog2-server 95 | ${graylog.version} 96 | provided 97 | 98 | 99 | org.mockito 100 | mockito-core 101 | ${mokito.version} 102 | test 103 | 104 | 105 | com.google.truth 106 | truth 107 | ${thruth.version} 108 | test 109 | 110 | 111 | junit 112 | junit 113 | ${junit.version} 114 | 115 | 116 | com.google.auto.value 117 | auto-value 118 | ${autovale.version} 119 | provided 120 | 121 | 122 | org.zeroturnaround 123 | zt-zip 124 | ${zzip.version} 125 | 126 | 127 | com.amazonaws 128 | aws-java-sdk 129 | ${awssdk.version} 130 | 131 | 132 | 133 | 134 | 135 | 136 | build 137 | 138 | 139 | src/main/resources 140 | true 141 | 142 | 143 | 144 | 145 | maven-assembly-plugin 146 | 147 | true 148 | 149 | 150 | 151 | 152 | org.apache.maven.plugins 153 | maven-jar-plugin 154 | 2.6 155 | 156 | 157 | 158 | ${project.groupId}.${project.artifactId} 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | org.apache.maven.plugins 167 | maven-shade-plugin 168 | 2.4.1 169 | 170 | false 171 | 172 | 173 | 174 | package 175 | 176 | shade 177 | 178 | 179 | 180 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | org.apache.maven.plugins 190 | maven-release-plugin 191 | 2.5.2 192 | 193 | true 194 | forked-path 195 | @{project.version} 196 | clean test 197 | package 198 | 199 | 200 | 201 | 202 | jdeb 203 | org.vafer 204 | 1.4 205 | 206 | ${project.build.directory}/${project.artifactId}-${project.version}.deb 207 | 208 | 209 | ${project.build.directory}/${project.build.finalName}.jar 210 | file 211 | 212 | perm 213 | ${graylog.plugin-dir} 214 | 644 215 | root 216 | root 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | org.codehaus.mojo 225 | rpm-maven-plugin 226 | 2.1.4 227 | 228 | Application/Internet 229 | 230 | /usr 231 | 232 | 233 | _unpackaged_files_terminate_build 0 234 | _binaries_in_noarch_packages_terminate_build 0 235 | 236 | 644 237 | 755 238 | root 239 | root 240 | 241 | 242 | ${graylog.plugin-dir} 243 | 244 | 245 | ${project.build.directory}/ 246 | 247 | ${project.build.finalName}.jar 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | web-interface-build 260 | 261 | 262 | !skip.web.build 263 | 264 | 265 | 266 | 267 | 268 | com.github.eirslett 269 | frontend-maven-plugin 270 | 1.3 271 | 272 | 273 | 274 | install node and npm 275 | 276 | install-node-and-npm 277 | 278 | 279 | v6.9.2 280 | 4.0.3 281 | 282 | 283 | 284 | 285 | npm install 286 | 287 | npm 288 | 289 | 290 | 291 | install 292 | 293 | 294 | 295 | 296 | npm run build 297 | 298 | npm 299 | 300 | 301 | run build 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | -------------------------------------------------------------------------------- /src/deb/control/control: -------------------------------------------------------------------------------- 1 | Package: [[name]] 2 | Version: [[version]] 3 | Architecture: all 4 | Maintainer: Filippo Balicchia 5 | Section: web 6 | Priority: optional 7 | Depends: graylog-server | graylog-radio 8 | Description: [[description]] 9 | -------------------------------------------------------------------------------- /src/main/java/org/graylog/plugins/backup/BackupConfiguration.java: -------------------------------------------------------------------------------- 1 | package org.graylog.plugins.backup; 2 | 3 | import com.fasterxml.jackson.annotation.JsonAutoDetect; 4 | import com.fasterxml.jackson.annotation.JsonProperty; 5 | import com.fasterxml.jackson.databind.annotation.JsonDeserialize; 6 | import com.google.auto.value.AutoValue; 7 | 8 | import org.joda.time.DateTime; 9 | import org.joda.time.Period; 10 | 11 | import javax.annotation.Nullable; 12 | 13 | 14 | @AutoValue 15 | @JsonDeserialize(builder = AutoValue_BackupConfiguration.Builder.class) 16 | @JsonAutoDetect 17 | public abstract class BackupConfiguration { 18 | public static Builder builder() 19 | { 20 | return new AutoValue_BackupConfiguration.Builder( ); 21 | } 22 | 23 | @JsonProperty("cfg_backup_path") 24 | public abstract String backupPath(); 25 | 26 | @JsonProperty("cfg_restore_path") 27 | public abstract String restorePath(); 28 | 29 | @JsonProperty("mongodump_path") 30 | public abstract String mongoDumpPath(); 31 | 32 | @JsonProperty("scheduled_period") 33 | public abstract Period scheduledPeriod(); 34 | 35 | @JsonProperty("enabled") 36 | public abstract boolean enabled(); 37 | 38 | @JsonProperty("lastbackup_time") 39 | @Nullable 40 | public abstract DateTime lastbackupTime(); 41 | 42 | @JsonProperty("number_of_day_before") 43 | @Nullable 44 | public abstract Integer numberOfDaysBefore(); 45 | 46 | 47 | 48 | public static BackupConfiguration defaultConfig() 49 | { 50 | return builder( ).enabled(false).backupPath("data/backup").restorePath("data/restore").mongoDumpPath("/usr/bin").scheduledPeriod(Period.days(15)).build( ); 51 | } 52 | 53 | @AutoValue.Builder 54 | public static abstract class Builder 55 | { 56 | 57 | abstract BackupConfiguration build(); 58 | 59 | @JsonProperty("cfg_backup_path") 60 | public abstract Builder backupPath(String backupPath); 61 | 62 | @JsonProperty("cfg_restore_path") 63 | public abstract Builder restorePath(@Nullable String restorePath); 64 | 65 | @JsonProperty("mongodump_path") 66 | public abstract Builder mongoDumpPath(String mongodumpPath); 67 | 68 | @JsonProperty("scheduled_period") 69 | public abstract Builder scheduledPeriod(Period scheduledPeriod); 70 | 71 | @JsonProperty("enabled") 72 | public abstract Builder enabled(boolean enabled); 73 | 74 | @JsonProperty("lastbackup_time") 75 | public abstract Builder lastbackupTime(DateTime lastBackupTime); 76 | 77 | @JsonProperty("number_of_day_before") 78 | public abstract Builder numberOfDaysBefore(Integer numberOfDaysBefore); 79 | 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/main/java/org/graylog/plugins/backup/BackupConfigurationMetaData.java: -------------------------------------------------------------------------------- 1 | package org.graylog.plugins.backup; 2 | 3 | import org.graylog2.plugin.PluginMetaData; 4 | import org.graylog2.plugin.ServerStatus; 5 | import org.graylog2.plugin.Version; 6 | 7 | import java.net.URI; 8 | import java.util.Collections; 9 | import java.util.Set; 10 | 11 | /** 12 | * Implement the PluginMetaData interface here. 13 | */ 14 | public class BackupConfigurationMetaData implements PluginMetaData { 15 | private static final String PLUGIN_PROPERTIES = "org.graylog.plugins.graylog-plugin-backup-configuration/graylog-plugin.properties"; 16 | 17 | @Override 18 | public String getUniqueId() { 19 | return "org.graylog.plugins.backup.BackupConfigurationPlugin"; 20 | } 21 | 22 | @Override 23 | public String getName() { 24 | return "BackupConfiguration"; 25 | } 26 | 27 | @Override 28 | public String getAuthor() { 29 | return "Filippo Balicchia "; 30 | } 31 | 32 | @Override 33 | public URI getURL() { 34 | return URI.create("https://github.com/fbalicchia/graylog-plugin-backup-configuration.git"); 35 | } 36 | 37 | @Override 38 | public Version getVersion() { 39 | return Version.fromPluginProperties(getClass(), PLUGIN_PROPERTIES, "version", Version.from(0, 0, 0, "unknown")); 40 | } 41 | 42 | @Override 43 | public String getDescription() { 44 | // TODO Insert correct plugin description 45 | return "Description of BackupConfiguration plugin"; 46 | } 47 | 48 | @Override 49 | public Version getRequiredVersion() { 50 | return Version.fromPluginProperties(getClass(), PLUGIN_PROPERTIES, "graylog.version", Version.from(0, 0, 0, "unknown")); 51 | } 52 | 53 | @Override 54 | public Set getRequiredCapabilities() { 55 | return Collections.emptySet(); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/main/java/org/graylog/plugins/backup/BackupConfigurationModule.java: -------------------------------------------------------------------------------- 1 | package org.graylog.plugins.backup; 2 | 3 | import org.graylog.plugins.backup.service.BackupResource; 4 | import org.graylog.plugins.backup.service.BackupService; 5 | import org.graylog.plugins.backup.service.impl.BackupServiceImpl; 6 | import org.graylog2.plugin.PluginConfigBean; 7 | import org.graylog2.plugin.PluginModule; 8 | 9 | import java.util.Collections; 10 | import java.util.Set; 11 | import org.slf4j.Logger; 12 | 13 | /** 14 | * Extend the PluginModule abstract class here to add you plugin to the system. 15 | */ 16 | public class BackupConfigurationModule extends PluginModule { 17 | 18 | private static final Logger LOG = org.slf4j.LoggerFactory.getLogger(BackupConfigurationModule.class); 19 | 20 | /** 21 | * Returns all configuration beans required by this plugin. 22 | * 23 | * Implementing this method is optional. The default method returns an empty {@link Set}. 24 | */ 25 | @Override 26 | public Set getConfigBeans() { 27 | return Collections.emptySet(); 28 | } 29 | 30 | @Override 31 | protected void configure() { 32 | bind(BackupService.class).to(BackupServiceImpl.class); 33 | addPeriodical(BackupConfigurationPeriodical.class); 34 | addRestResource(BackupResource.class); 35 | addConfigBeans(); 36 | LOG.info("graylog-plugin-backup-configuration plugin started"); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/org/graylog/plugins/backup/BackupConfigurationPeriodical.java: -------------------------------------------------------------------------------- 1 | package org.graylog.plugins.backup; 2 | 3 | import com.google.common.base.MoreObjects; 4 | import org.graylog.plugins.backup.service.BackupService; 5 | import org.graylog2.plugin.Tools; 6 | import org.graylog2.plugin.cluster.ClusterConfigService; 7 | import org.graylog2.plugin.periodical.Periodical; 8 | import org.joda.time.*; 9 | import org.slf4j.Logger; 10 | 11 | import javax.inject.Inject; 12 | 13 | import static org.joda.time.DateTimeFieldType.*; 14 | 15 | 16 | /** 17 | * This is the plugin. Your class should implement one of the existing plugin 18 | * interfaces. (i.e. AlarmCallback, MessageInput, MessageOutput) 19 | */ 20 | public class BackupConfigurationPeriodical extends Periodical 21 | { 22 | 23 | private BackupService backupService; 24 | 25 | private ClusterConfigService clusterConfigService; 26 | 27 | private static final Logger LOG = org.slf4j.LoggerFactory.getLogger(BackupConfigurationPeriodical.class); 28 | 29 | @Inject 30 | public BackupConfigurationPeriodical(BackupService backupService, ClusterConfigService clusterConfigService) 31 | { 32 | this.backupService = backupService; 33 | this.clusterConfigService = clusterConfigService; 34 | } 35 | 36 | @Override 37 | public boolean runsForever() 38 | { 39 | return false; 40 | } 41 | 42 | @Override 43 | public boolean stopOnGracefulShutdown() 44 | { 45 | return true; 46 | } 47 | 48 | @Override 49 | public boolean masterOnly() 50 | { 51 | return true; 52 | } 53 | 54 | @Override 55 | public boolean startOnThisNode() 56 | { 57 | return true; 58 | } 59 | 60 | @Override 61 | public boolean isDaemon() 62 | { 63 | return true; 64 | } 65 | 66 | @Override 67 | public int getInitialDelaySeconds() 68 | { 69 | return 0; 70 | } 71 | 72 | @Override 73 | public int getPeriodSeconds() 74 | { 75 | return 60; 76 | } 77 | 78 | @Override 79 | protected Logger getLogger() 80 | { 81 | return LOG; 82 | } 83 | 84 | @Override 85 | public void doRun() 86 | { 87 | BackupConfiguration info = clusterConfigService.getOrDefault(BackupConfiguration.class, BackupConfiguration.defaultConfig( )); 88 | if (canStartBackup(info)) 89 | { 90 | try 91 | { 92 | backupService.start(info); 93 | LOG.info("Backup GrayLog configuration completed "); 94 | BackupConfiguration newInfo = BackupConfiguration.builder( ).enabled(info.enabled( )).scheduledPeriod(info.scheduledPeriod( )).mongoDumpPath(info.mongoDumpPath( )).restorePath(info.restorePath( )).backupPath(info.backupPath( )).lastbackupTime(Tools.nowUTC( )).build( ); 95 | clusterConfigService.write(newInfo); 96 | } 97 | catch (BackupException e) 98 | { 99 | LOG.error("", e); 100 | } 101 | } 102 | 103 | } 104 | 105 | 106 | public Boolean canStartBackup(BackupConfiguration backupConfiguration) 107 | { 108 | if (!backupConfiguration.enabled( )) 109 | { 110 | return false; 111 | } 112 | DateTime nextTime = determineRotationPeriodAnchor(backupConfiguration).plus(backupConfiguration.scheduledPeriod( )); 113 | if (nextTime.isAfter(Tools.nowUTC( ))) 114 | { 115 | LOG.debug("Next time backup {}", nextTime.toString( )); 116 | } 117 | return backupConfiguration.lastbackupTime( ) == null || !nextTime.isAfterNow( ); 118 | } 119 | 120 | 121 | /** 122 | * I like the approach used in TimeBasedRotationStrategy but i don't want to have refence to that class 123 | * This method come from org.graylog2.indexer.rotation.strategies.TimeBasedRotationStrategy 124 | * 125 | * @param backupConfiguration 126 | * @return 127 | */ 128 | private DateTime determineRotationPeriodAnchor(BackupConfiguration backupConfiguration) 129 | { 130 | 131 | DateTime lastAnchor = backupConfiguration.lastbackupTime( ); 132 | Period period = backupConfiguration.scheduledPeriod( ); 133 | 134 | final Period normalized = period.normalizedStandard( ); 135 | int years = normalized.getYears( ); 136 | int months = normalized.getMonths( ); 137 | int weeks = normalized.getWeeks( ); 138 | int days = normalized.getDays( ); 139 | int hours = normalized.getHours( ); 140 | int minutes = normalized.getMinutes( ); 141 | int seconds = normalized.getSeconds( ); 142 | 143 | if (years == 0 && months == 0 && weeks == 0 && days == 0 && hours == 0 && minutes == 0 && seconds == 0) 144 | { 145 | throw new IllegalArgumentException("Invalid rotation period specified"); 146 | } 147 | 148 | // find the largest non-zero stride in the period. that's our anchor type. statement order matters here! 149 | DateTimeFieldType largestStrideType = null; 150 | if (seconds > 0) 151 | largestStrideType = secondOfMinute( ); 152 | if (minutes > 0) 153 | largestStrideType = minuteOfHour( ); 154 | if (hours > 0) 155 | largestStrideType = hourOfDay( ); 156 | if (days > 0) 157 | largestStrideType = dayOfMonth( ); 158 | if (weeks > 0) 159 | largestStrideType = weekOfWeekyear( ); 160 | if (months > 0) 161 | largestStrideType = monthOfYear( ); 162 | if (years > 0) 163 | largestStrideType = year( ); 164 | if (largestStrideType == null) 165 | { 166 | throw new IllegalArgumentException("Could not determine rotation stride length."); 167 | } 168 | 169 | final DateTime anchorTime = MoreObjects.firstNonNull(lastAnchor, Tools.nowUTC( )); 170 | 171 | final DateTimeField field = largestStrideType.getField(anchorTime.getChronology( )); 172 | // use normalized here to make sure we actually have the largestStride type available! see https://github.com/Graylog2/graylog2-server/issues/836 173 | int periodValue = normalized.get(largestStrideType.getDurationType( )); 174 | final long fieldValue = field.roundFloor(anchorTime.getMillis( )); 175 | 176 | final int fieldValueInUnit = field.get(fieldValue); 177 | if (periodValue == 0) 178 | { 179 | // https://github.com/Graylog2/graylog2-server/issues/836 180 | LOG.warn("Determining stride length failed because of a 0 period. Defaulting back to 1 period to avoid crashing, but this is a bug!"); 181 | periodValue = 1; 182 | } 183 | final long difference = (fieldValueInUnit % periodValue); 184 | final long newValue = field.add(fieldValue, -1 * difference); 185 | return new DateTime(newValue, DateTimeZone.UTC); 186 | } 187 | } 188 | 189 | -------------------------------------------------------------------------------- /src/main/java/org/graylog/plugins/backup/BackupConfigurationPlugin.java: -------------------------------------------------------------------------------- 1 | package org.graylog.plugins.backup; 2 | 3 | import org.graylog2.plugin.Plugin; 4 | import org.graylog2.plugin.PluginMetaData; 5 | import org.graylog2.plugin.PluginModule; 6 | 7 | import java.util.Collection; 8 | import java.util.Collections; 9 | 10 | /** 11 | * Implement the Plugin interface here. 12 | */ 13 | public class BackupConfigurationPlugin implements Plugin { 14 | @Override 15 | public PluginMetaData metadata() { 16 | return new BackupConfigurationMetaData(); 17 | } 18 | 19 | @Override 20 | public Collection modules () { 21 | return Collections.singletonList(new BackupConfigurationModule()); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/org/graylog/plugins/backup/BackupException.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) ${project.inceptionYear} ${owner} (hello@graylog.com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.graylog.plugins.backup; 17 | 18 | 19 | public class BackupException extends Exception 20 | { 21 | public BackupException() { 22 | super(); 23 | } 24 | 25 | public BackupException(String msg) { 26 | super(msg); 27 | } 28 | 29 | public BackupException(String message, Throwable cause) 30 | { 31 | super(message, cause); 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/org/graylog/plugins/backup/RestoreException.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) ${project.inceptionYear} ${owner} (hello@graylog.com) 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * Unless required by applicable law or agreed to in writing, software 8 | * distributed under the License is distributed on an "AS IS" BASIS, 9 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | * See the License for the specific language governing permissions and 11 | * limitations under the License. 12 | */ 13 | package org.graylog.plugins.backup; 14 | 15 | 16 | public class RestoreException extends Exception 17 | { 18 | public RestoreException() 19 | { 20 | super( ); 21 | } 22 | 23 | public RestoreException(String msg) 24 | { 25 | super(msg); 26 | } 27 | 28 | public RestoreException(String message, Throwable cause) 29 | { 30 | super(message, cause); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/org/graylog/plugins/backup/model/BackupStruct.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) ${project.inceptionYear} ${owner} (hello@graylog.com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.graylog.plugins.backup.model; 17 | 18 | import org.apache.commons.lang3.StringUtils; 19 | import org.apache.commons.lang3.builder.ToStringBuilder; 20 | 21 | 22 | 23 | public class BackupStruct 24 | { 25 | 26 | private String hostName; 27 | 28 | private String port; 29 | 30 | private String targetPath; 31 | 32 | private String sourcePath; 33 | 34 | private String mongoInstallPath; 35 | 36 | 37 | public String getHostName() 38 | { 39 | return StringUtils.trim(hostName); 40 | } 41 | 42 | public String getPort() 43 | { 44 | return StringUtils.trim(port); 45 | } 46 | 47 | public String getTargetPath() 48 | { 49 | return StringUtils.trim(targetPath); 50 | } 51 | 52 | public String getSourcePath() 53 | { 54 | return StringUtils.trim(sourcePath); 55 | } 56 | 57 | public String getMongoInstallPath() 58 | { 59 | return StringUtils.trim(mongoInstallPath); 60 | } 61 | 62 | public BackupStruct(BackupStructBuilder backupStructBuilder) 63 | { 64 | hostName = backupStructBuilder._hostName; 65 | port = backupStructBuilder._port; 66 | targetPath = backupStructBuilder._targetPath; 67 | sourcePath = backupStructBuilder._sourcePath; 68 | mongoInstallPath = backupStructBuilder._mongoInstallPath; 69 | } 70 | 71 | public static class BackupStructBuilder 72 | { 73 | private String _hostName; 74 | 75 | private String _port = "27017"; 76 | 77 | private String _targetPath; 78 | 79 | private String _sourcePath; 80 | 81 | private String _mongoInstallPath; 82 | 83 | 84 | public BackupStructBuilder setHostName(String _hostName) 85 | { 86 | this._hostName = _hostName; 87 | return this; 88 | } 89 | 90 | public BackupStructBuilder setPort(String _port) 91 | { 92 | this._port = _port; 93 | return this; 94 | } 95 | 96 | public BackupStructBuilder setTargetPath(String _targetPath) 97 | { 98 | this._targetPath = _targetPath; 99 | return this; 100 | } 101 | 102 | public BackupStructBuilder setSourcePath(String _sourcePath) 103 | { 104 | this._sourcePath = _sourcePath; 105 | return this; 106 | } 107 | 108 | public BackupStructBuilder setMongoInstallPath(String mongoInstallPath) 109 | { 110 | this._mongoInstallPath = mongoInstallPath; 111 | return this; 112 | } 113 | 114 | public BackupStruct build() 115 | { 116 | return new BackupStruct(this); 117 | } 118 | } 119 | 120 | 121 | @Override 122 | public String toString() 123 | { 124 | return new ToStringBuilder(this) 125 | .append(hostName) 126 | .append(port) 127 | .append(targetPath) 128 | .append(sourcePath) 129 | .append(mongoInstallPath).toString(); 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /src/main/java/org/graylog/plugins/backup/service/BackupResource.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) ${project.inceptionYear} ${owner} (hello@graylog.com) 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * Unless required by applicable law or agreed to in writing, software 8 | * distributed under the License is distributed on an "AS IS" BASIS, 9 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | * See the License for the specific language governing permissions and 11 | * limitations under the License. 12 | */ 13 | package org.graylog.plugins.backup.service; 14 | 15 | import com.codahale.metrics.annotation.Timed; 16 | import io.swagger.annotations.Api; 17 | import io.swagger.annotations.ApiOperation; 18 | import io.swagger.annotations.ApiResponse; 19 | import io.swagger.annotations.ApiResponses; 20 | import org.apache.shiro.authz.annotation.RequiresAuthentication; 21 | 22 | import org.graylog.plugins.backup.BackupConfiguration; 23 | import org.graylog.plugins.backup.RestoreException; 24 | import org.graylog2.plugin.cluster.ClusterConfigService; 25 | import org.graylog2.plugin.rest.PluginRestResource; 26 | import org.graylog2.shared.rest.resources.RestResource; 27 | import org.slf4j.Logger; 28 | import org.slf4j.LoggerFactory; 29 | 30 | import javax.inject.Inject; 31 | import javax.ws.rs.*; 32 | import javax.ws.rs.core.MediaType; 33 | import javax.ws.rs.core.Response; 34 | 35 | 36 | @RequiresAuthentication 37 | @Api(value = "backupConfig", description = "Graylog backup config api") 38 | @Path("/") 39 | public class BackupResource extends RestResource implements PluginRestResource 40 | { 41 | 42 | private Logger LOG = LoggerFactory.getLogger(BackupResource.class); 43 | 44 | private BackupService backupService; 45 | 46 | private ClusterConfigService clusterConfigService; 47 | 48 | @Inject 49 | public BackupResource(BackupService backupService, ClusterConfigService clusterConfigService) 50 | { 51 | this.backupService = backupService; 52 | this.clusterConfigService = clusterConfigService; 53 | } 54 | 55 | 56 | @POST 57 | @Path("launchrestore") 58 | @Timed 59 | @ApiOperation(value = "Restore config data") 60 | @ApiResponses(value = { 61 | @ApiResponse(code = 202, message = "Restore config done") 62 | }) 63 | @Produces(MediaType.APPLICATION_JSON) 64 | public Response launchRestore() 65 | { 66 | try 67 | { 68 | LOG.info("Graylog restore perform"); 69 | BackupConfiguration aDefault = clusterConfigService.getOrDefault(BackupConfiguration.class, BackupConfiguration.defaultConfig( )); 70 | 71 | LOG.info("Restore configuration {}",aDefault.toString()); 72 | 73 | backupService.restore(aDefault); 74 | return Response.accepted( ).build( ); 75 | } 76 | catch (RestoreException e) 77 | { 78 | LOG.error("", e); 79 | return Response.serverError( ).build( ); 80 | } 81 | } 82 | 83 | } 84 | -------------------------------------------------------------------------------- /src/main/java/org/graylog/plugins/backup/service/BackupService.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) ${project.inceptionYear} ${owner} (hello@graylog.com) 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * Unless required by applicable law or agreed to in writing, software 8 | * distributed under the License is distributed on an "AS IS" BASIS, 9 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | * See the License for the specific language governing permissions and 11 | * limitations under the License. 12 | */ 13 | package org.graylog.plugins.backup.service; 14 | 15 | 16 | import org.graylog.plugins.backup.BackupConfiguration; 17 | import org.graylog.plugins.backup.BackupException; 18 | import org.graylog.plugins.backup.RestoreException; 19 | 20 | 21 | public interface BackupService 22 | { 23 | void start(BackupConfiguration backupConfig) throws BackupException; 24 | 25 | void restore(BackupConfiguration backupConfig) throws RestoreException; 26 | 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/org/graylog/plugins/backup/service/impl/BackupServiceImpl.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) ${project.inceptionYear} ${owner} (hello@graylog.com) 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * Unless required by applicable law or agreed to in writing, software 8 | * distributed under the License is distributed on an "AS IS" BASIS, 9 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | * See the License for the specific language governing permissions and 11 | * limitations under the License. 12 | */ 13 | package org.graylog.plugins.backup.service.impl; 14 | 15 | import com.google.common.base.Throwables; 16 | import org.apache.commons.lang3.StringUtils; 17 | import org.graylog.plugins.backup.BackupConfiguration; 18 | import org.graylog.plugins.backup.BackupException; 19 | import org.graylog.plugins.backup.RestoreException; 20 | import org.graylog.plugins.backup.model.BackupStruct; 21 | import org.graylog.plugins.backup.service.BackupService; 22 | import org.graylog.plugins.backup.strategy.BackupFactoryStrategy; 23 | import org.graylog.plugins.backup.strategy.BackupStrategy; 24 | import org.graylog2.configuration.MongoDbConfiguration; 25 | import org.slf4j.Logger; 26 | import org.slf4j.LoggerFactory; 27 | 28 | import javax.inject.Inject; 29 | import javax.inject.Singleton; 30 | import java.nio.file.Files; 31 | import java.nio.file.Paths; 32 | import java.util.List; 33 | import java.util.stream.Collectors; 34 | 35 | 36 | @Singleton 37 | public class BackupServiceImpl implements BackupService 38 | { 39 | 40 | private static final Logger LOG = LoggerFactory.getLogger(BackupServiceImpl.class); 41 | 42 | private MongoDbConfiguration mongoDbConfiguration; 43 | 44 | 45 | @Inject 46 | public BackupServiceImpl(MongoDbConfiguration mongoDbConfiguration) 47 | { 48 | this.mongoDbConfiguration = mongoDbConfiguration; 49 | } 50 | 51 | 52 | @Override 53 | public void start(BackupConfiguration backupConfig) throws BackupException 54 | { 55 | 56 | List bckList = mongoDbConfiguration.getMongoClientURI( ).getHosts( ).stream( ).filter(item -> StringUtils.isNotEmpty(item)).map(item -> 57 | { 58 | String[] addressToken = item.split(":"); 59 | 60 | String host = StringUtils.EMPTY; 61 | String port = StringUtils.EMPTY; 62 | if (addressToken.length == 2) 63 | { 64 | host = addressToken[0]; 65 | port = addressToken[1]; 66 | } 67 | return new BackupStruct.BackupStructBuilder( ).setMongoInstallPath(backupConfig.mongoDumpPath( )).setPort(port).setHostName(host).setTargetPath(backupConfig.backupPath( )).build( ); 68 | }).collect(Collectors.toList( )); 69 | 70 | for (BackupStruct item : bckList) 71 | { 72 | doDump(item); 73 | } 74 | 75 | } 76 | 77 | @Override 78 | public void restore(BackupConfiguration backupConfig) throws RestoreException 79 | { 80 | BackupStruct backupStruct = new BackupStruct.BackupStructBuilder( ).setMongoInstallPath(backupConfig.mongoDumpPath( )).setTargetPath(backupConfig.backupPath( )).setSourcePath(backupConfig.restorePath( )).build( ); 81 | doRestore(backupStruct); 82 | } 83 | 84 | private void doRestore(BackupStruct backupStruct) throws RestoreException 85 | { 86 | 87 | if (!Files.exists(Paths.get(backupStruct.getSourcePath( )))) 88 | { 89 | LOG.error("Cannot access to directory at {}, please check the permissions", 90 | backupStruct.getSourcePath( )); 91 | Throwables.propagate(new RestoreException("Dest folder doesn't exists ")); 92 | } 93 | 94 | BackupStrategy backupStrategy = BackupFactoryStrategy.create(backupStruct); 95 | backupStrategy.restoreData( ); 96 | } 97 | 98 | private void doDump(BackupStruct backupStruct) throws BackupException 99 | { 100 | BackupStrategy backupStrategy = BackupFactoryStrategy.create(backupStruct); 101 | backupStrategy.saveData( ); 102 | } 103 | 104 | 105 | } 106 | -------------------------------------------------------------------------------- /src/main/java/org/graylog/plugins/backup/strategy/AbstractMongoBackupStrategy.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) ${project.inceptionYear} ${owner} (hello@graylog.com) 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * Unless required by applicable law or agreed to in writing, software 8 | * distributed under the License is distributed on an "AS IS" BASIS, 9 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | * See the License for the specific language governing permissions and 11 | * limitations under the License. 12 | */ 13 | package org.graylog.plugins.backup.strategy; 14 | 15 | import org.apache.commons.lang.SystemUtils; 16 | import org.graylog.plugins.backup.model.BackupStruct; 17 | import org.slf4j.Logger; 18 | import org.slf4j.LoggerFactory; 19 | 20 | import java.util.List; 21 | import java.util.Timer; 22 | import java.util.TimerTask; 23 | 24 | 25 | public abstract class AbstractMongoBackupStrategy implements BackupStrategy 26 | { 27 | 28 | 29 | private static final Logger LOG = LoggerFactory.getLogger(AbstractMongoBackupStrategy.class); 30 | 31 | protected BackupStruct backupStruct; 32 | 33 | protected abstract void pack() throws Exception; 34 | 35 | 36 | protected String osShellPath() 37 | { 38 | 39 | if (SystemUtils.IS_OS_UNIX) 40 | { 41 | return "/bin/sh"; 42 | } 43 | 44 | throw new IllegalArgumentException("At the moment your system is not supported"); 45 | } 46 | 47 | 48 | protected synchronized void processCommand(List command) throws Exception 49 | { 50 | //need to find a a smart way to manage processBuilder 51 | 52 | ProcessBuilder pb = new ProcessBuilder(command); 53 | pb.redirectErrorStream(true); 54 | Process p = pb.start( ); 55 | 56 | Timer timeOut = new Timer( ); 57 | timeOut.schedule(new TimerTask( ) 58 | { 59 | @Override 60 | public void run() 61 | { 62 | if(p.isAlive()) 63 | { 64 | LOG.warn("restore process take more than 15 sec I'll destroy it"); 65 | p.destroy( ); 66 | } 67 | } 68 | 69 | //this parameter need to be configurable 70 | 71 | }, 15000); 72 | 73 | p.waitFor( ); 74 | timeOut.cancel( ); 75 | 76 | } 77 | } 78 | 79 | 80 | 81 | -------------------------------------------------------------------------------- /src/main/java/org/graylog/plugins/backup/strategy/BackupFactoryStrategy.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) ${project.inceptionYear} ${owner} (hello@graylog.com) 3 | *

4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | *

8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | *

10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.graylog.plugins.backup.strategy; 17 | 18 | 19 | import org.graylog.plugins.backup.model.BackupStruct; 20 | 21 | 22 | public class BackupFactoryStrategy { 23 | 24 | public static BackupStrategy create(BackupStruct backupStruct) { 25 | 26 | if (!backupStruct.getTargetPath().startsWith("s3")) { 27 | return new FsBackupStrategy(backupStruct); 28 | } else { 29 | 30 | return new S3Strategy(backupStruct); 31 | 32 | } 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/org/graylog/plugins/backup/strategy/BackupStrategy.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) ${project.inceptionYear} ${owner} (hello@graylog.com) 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * Unless required by applicable law or agreed to in writing, software 8 | * distributed under the License is distributed on an "AS IS" BASIS, 9 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | * See the License for the specific language governing permissions and 11 | * limitations under the License. 12 | */ 13 | package org.graylog.plugins.backup.strategy; 14 | 15 | import org.graylog.plugins.backup.BackupException; 16 | import org.graylog.plugins.backup.RestoreException; 17 | 18 | import java.io.IOException; 19 | 20 | 21 | public interface BackupStrategy 22 | { 23 | 24 | public void saveData() throws BackupException; 25 | 26 | public void restoreData() throws RestoreException; 27 | 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/org/graylog/plugins/backup/strategy/FsBackupStrategy.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) ${project.inceptionYear} ${owner} (hello@graylog.com) 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * Unless required by applicable law or agreed to in writing, software 8 | * distributed under the License is distributed on an "AS IS" BASIS, 9 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | * See the License for the specific language governing permissions and 11 | * limitations under the License. 12 | */ 13 | package org.graylog.plugins.backup.strategy; 14 | 15 | import com.google.common.base.Throwables; 16 | import com.google.common.collect.Lists; 17 | import org.apache.commons.io.FileUtils; 18 | import org.graylog.plugins.backup.BackupException; 19 | import org.graylog.plugins.backup.RestoreException; 20 | import org.graylog.plugins.backup.model.BackupStruct; 21 | import org.slf4j.Logger; 22 | import org.slf4j.LoggerFactory; 23 | import org.zeroturnaround.zip.ZipUtil; 24 | 25 | import java.io.File; 26 | import java.time.LocalDateTime; 27 | import java.time.format.DateTimeFormatter; 28 | import java.util.List; 29 | 30 | 31 | public class FsBackupStrategy extends AbstractMongoBackupStrategy 32 | { 33 | 34 | private DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMddHHmm"); 35 | 36 | private static Logger LOG = LoggerFactory.getLogger(FsBackupStrategy.class); 37 | 38 | private final static String RESTORE_FOLDER = "graylog"; 39 | 40 | private final static String GRAYLOG_SCHEMA_NAME = "graylog"; 41 | 42 | 43 | public FsBackupStrategy(BackupStruct backupStruct) 44 | { 45 | this.backupStruct = backupStruct; 46 | } 47 | 48 | @Override 49 | public void saveData() throws BackupException 50 | { 51 | 52 | List commands = Lists.newArrayList( ); 53 | commands.add(osShellPath( )); 54 | commands.add("-c"); 55 | commands.add(buildCommandLine(backupStruct)); 56 | try 57 | { 58 | processCommand(commands); 59 | pack( ); 60 | } 61 | catch (Exception e) 62 | { 63 | throw new BackupException("Error during backup configuration", e); 64 | } 65 | } 66 | 67 | 68 | public void unpack(String path) throws RestoreException 69 | { 70 | File[] fileList = new File(path).listFiles( ); 71 | 72 | if (fileList.length != 1) 73 | { 74 | LOG.error("There is 0 or more then 1 files in the restore folder {}", 75 | path); 76 | Throwables.propagate(new RestoreException("There is 0 or more then 1 files in the restore folder. Please drop in only Zip file ")); 77 | } 78 | 79 | if (fileList[0].getName( ).endsWith("zip")) 80 | { 81 | File source = new File(backupStruct.getSourcePath( ) + File.separator + fileList[0].getName( )); 82 | 83 | if (source.canRead( ) && source.canWrite( )) 84 | { 85 | ZipUtil.unpack(source, new File(backupStruct.getSourcePath( ) + File.separator + RESTORE_FOLDER)); 86 | } 87 | else 88 | { 89 | LOG.error("Please check permission on file {} ", 90 | backupStruct.getSourcePath( ) + File.separator + fileList[0].getName( )); 91 | Throwables.propagate(new RestoreException("File permission problem ")); 92 | } 93 | 94 | 95 | } 96 | else 97 | { 98 | LOG.error("There is no zip file in {} ", path); 99 | throw new RestoreException("Please check zip file"); 100 | } 101 | 102 | } 103 | 104 | 105 | @Override 106 | public void restoreData() throws RestoreException 107 | { 108 | unpack(backupStruct.getSourcePath( )); 109 | 110 | StringBuilder restoreStr = new StringBuilder(backupStruct.getMongoInstallPath( )) 111 | .append(File.separator) 112 | .append("mongorestore") 113 | .append(" ") 114 | .append("-d").append(" ").append("graylog") 115 | .append(" ") 116 | .append(backupStruct.getSourcePath( )) 117 | .append(File.separator) 118 | .append(RESTORE_FOLDER); 119 | 120 | LOG.info("Command lunch {} ", restoreStr.toString( )); 121 | 122 | List commands = Lists.newArrayList( ); 123 | commands.add(osShellPath( )); 124 | commands.add("-c"); 125 | commands.add(restoreStr.toString( )); 126 | try 127 | { 128 | processCommand(commands); 129 | } 130 | catch (Exception e) 131 | { 132 | throw new RestoreException("Error during restore data", e); 133 | } 134 | 135 | 136 | } 137 | 138 | private String buildCommandLine(BackupStruct backupStruct) 139 | { 140 | StringBuilder result = new StringBuilder(backupStruct.getMongoInstallPath( )); 141 | result.append(File.separator).append("mongodump").append(" -d graylog").append(" -o ").append(backupStruct.getTargetPath( )); 142 | result.append(" ").append("--dumpDbUsersAndRoles"); 143 | return result.toString( ); 144 | } 145 | 146 | @Override 147 | protected void pack() throws Exception 148 | { 149 | LocalDateTime now = LocalDateTime.now( ); 150 | String dateFormat = now.format(formatter); 151 | String srcFolder = backupStruct.getTargetPath( ) + File.separator + GRAYLOG_SCHEMA_NAME; 152 | String dstFolder = backupStruct.getTargetPath( ) + File.separator + GRAYLOG_SCHEMA_NAME + dateFormat + ".zip"; 153 | ZipUtil.pack(new File(srcFolder), new File(dstFolder)); 154 | LOG.info("Graylog config backup completed"); 155 | FileUtils.deleteDirectory(new File(srcFolder)); 156 | } 157 | } 158 | -------------------------------------------------------------------------------- /src/main/java/org/graylog/plugins/backup/strategy/S3Strategy.java: -------------------------------------------------------------------------------- 1 | package org.graylog.plugins.backup.strategy; 2 | 3 | import com.amazonaws.auth.BasicAWSCredentials; 4 | import com.amazonaws.services.s3.model.ListObjectsRequest; 5 | import com.amazonaws.services.s3.model.ObjectListing; 6 | import com.amazonaws.services.s3.model.S3ObjectSummary; 7 | import org.apache.commons.io.FileUtils; 8 | import org.graylog.plugins.backup.BackupException; 9 | import org.graylog.plugins.backup.RestoreException; 10 | import org.graylog.plugins.backup.model.BackupStruct; 11 | import com.amazonaws.services.s3.AmazonS3; 12 | import com.amazonaws.services.s3.AmazonS3Client; 13 | 14 | import java.io.File; 15 | import java.time.LocalDateTime; 16 | 17 | import com.amazonaws.regions.Region; 18 | import com.amazonaws.regions.Regions; 19 | 20 | import com.amazonaws.services.s3.model.PutObjectRequest; 21 | 22 | import com.amazonaws.auth.BasicAWSCredentials; 23 | import org.slf4j.Logger; 24 | import org.slf4j.LoggerFactory; 25 | import org.zeroturnaround.zip.ZipUtil; 26 | 27 | 28 | /** 29 | * Created by fbalicchia on 19/03/17. 30 | */ 31 | public class S3Strategy extends AbstractMongoBackupStrategy { 32 | 33 | 34 | private AmazonS3 s3Client; 35 | 36 | private Logger LOG = LoggerFactory.getLogger(S3Strategy.class.getName()); 37 | 38 | 39 | public S3Strategy(BackupStruct backupStruct) { 40 | this.backupStruct = backupStruct; 41 | } 42 | 43 | 44 | private void initClient() { 45 | AmazonS3 s3Client = new AmazonS3Client(new BasicAWSCredentials("accessKey", "Secrectkey")); 46 | Region euWest2 = Region.getRegion(Regions.EU_WEST_1); 47 | s3Client.setRegion(euWest2); 48 | 49 | } 50 | 51 | 52 | @Override 53 | public void saveData() throws BackupException { 54 | s3Client.putObject(new PutObjectRequest("numeeor12 ", "key", new File(""))); 55 | } 56 | 57 | @Override 58 | public void restoreData() throws RestoreException { 59 | 60 | ObjectListing objectListing = s3Client.listObjects(new ListObjectsRequest() 61 | .withBucketName("bucketname") 62 | .withPrefix("My")); 63 | 64 | for (S3ObjectSummary objectSummary : objectListing.getObjectSummaries()) { 65 | LOG.info(" - " + objectSummary.getKey() + " " + 66 | "(size = " + objectSummary.getSize() + ")"); 67 | } 68 | 69 | 70 | } 71 | 72 | @Override 73 | @Deprecated 74 | protected void pack() throws Exception { 75 | 76 | LocalDateTime now = LocalDateTime.now( ); 77 | //String dateFormat = now.format(formatter); 78 | // String srcFolder = backupStruct.getTargetPath( ) + File.separator + GRAYLOG_SCHEMA_NAME; 79 | // String dstFolder = backupStruct.getTargetPath( ) + File.separator + GRAYLOG_SCHEMA_NAME + dateFormat + ".zip"; 80 | //ZipUtil.pack(new File(srcFolder), new File(dstFolder)); 81 | LOG.info("Graylog config backup completed"); 82 | //FileUtils.deleteDirectory(new File(srcFolder)); 83 | 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/main/resources/META-INF/services/org.graylog2.plugin.Plugin: -------------------------------------------------------------------------------- 1 | org.graylog.plugins.backup.BackupConfigurationPlugin -------------------------------------------------------------------------------- /src/main/resources/org.graylog.plugins.graylog-plugin-backup-configuration/graylog-plugin.properties: -------------------------------------------------------------------------------- 1 | # The plugin version 2 | version=${project.version} 3 | 4 | # The required Graylog server version 5 | graylog.version=${graylog.version} 6 | 7 | # When set to true (the default) the plugin gets a separate class loader 8 | # when loading the plugin. When set to false, the plugin shares a class loader 9 | # with other plugins that have isolated=false. 10 | # 11 | # Do not disable this unless this plugin depends on another plugin! 12 | isolated=true 13 | -------------------------------------------------------------------------------- /src/test/java/org/graylog/plugins/backup/BackConfigurationPeriodicalTest.java: -------------------------------------------------------------------------------- 1 | package org.graylog.plugins.backup; 2 | 3 | import org.apache.commons.lang3.StringUtils; 4 | import org.graylog2.plugin.InstantMillisProvider; 5 | import org.graylog2.plugin.Tools; 6 | import org.graylog2.plugin.cluster.ClusterConfigService; 7 | import org.joda.time.DateTime; 8 | import org.joda.time.DateTimeUtils; 9 | import org.joda.time.DateTimeZone; 10 | import org.joda.time.Period; 11 | import org.junit.Before; 12 | import org.junit.Test; 13 | import org.mockito.Mock; 14 | 15 | import static com.google.common.truth.Truth.assertThat; 16 | import static org.mockito.Mockito.mock; 17 | 18 | 19 | public class BackConfigurationPeriodicalTest 20 | { 21 | @Mock 22 | private BackupConfiguration backupConfigurationMock; 23 | @Mock 24 | private ClusterConfigService clusterConfigServiceMock; 25 | 26 | @Before 27 | public void setUp() 28 | { 29 | backupConfigurationMock = mock(BackupConfiguration.class); 30 | clusterConfigServiceMock = mock(ClusterConfigService.class); 31 | 32 | } 33 | 34 | @Test 35 | public void canStartBackup() 36 | { 37 | final DateTime initialTime = new DateTime(2016, 9, 26, 23, 0, 35, 0, DateTimeZone.UTC); 38 | 39 | final InstantMillisProvider clock = new InstantMillisProvider(initialTime); 40 | DateTimeUtils.setCurrentMillisProvider(clock); 41 | 42 | BackupConfiguration testinfo = BackupConfiguration.builder( ).enabled(false).scheduledPeriod(Period.days(1)) 43 | .mongoDumpPath(StringUtils.EMPTY) 44 | .restorePath(StringUtils.EMPTY) 45 | .backupPath(StringUtils.EMPTY) 46 | .lastbackupTime(Tools.nowUTC( )).build( ); 47 | 48 | BackupConfigurationPeriodical configuration = new BackupConfigurationPeriodical(null, null); 49 | assertThat(configuration.canStartBackup(testinfo)).isFalse( ); 50 | 51 | DateTime lastBackup = new DateTime(2016, 9, 26, 22, 56, 0, 0); 52 | testinfo = BackupConfiguration.builder( ).enabled(true).scheduledPeriod(Period.minutes(1)).mongoDumpPath("").restorePath("").backupPath("").lastbackupTime(lastBackup).build( ); 53 | assertThat(configuration.canStartBackup(testinfo)).isTrue( ); 54 | 55 | lastBackup = new DateTime(2016, 9, 26, 23, 2, 0, 0, DateTimeZone.UTC); 56 | testinfo = BackupConfiguration.builder( ).enabled(true).scheduledPeriod(Period.minutes(1)).mongoDumpPath("").restorePath("").backupPath("").lastbackupTime(lastBackup).build( ); 57 | assertThat(configuration.canStartBackup(testinfo)).isFalse( ); 58 | 59 | } 60 | 61 | } 62 | -------------------------------------------------------------------------------- /src/test/java/org/graylog/plugins/backup/BackupStructTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) ${project.inceptionYear} ${owner} (hello@graylog.com) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.graylog.plugins.backup; 17 | 18 | 19 | import org.graylog.plugins.backup.model.BackupStruct; 20 | import org.junit.Test; 21 | import static com.google.common.truth.Truth.assertThat; 22 | 23 | /** 24 | * Created by fbalicchia on 08/09/16. 25 | */ 26 | public class BackupStructTest 27 | { 28 | 29 | @Test 30 | public void builderStrunctTest() 31 | { 32 | BackupStruct backupStruct = new BackupStruct.BackupStructBuilder() 33 | .setMongoInstallPath("aaaa") 34 | .setHostName("bbb") 35 | .setTargetPath("cccc") 36 | .setPort("1234") 37 | .setSourcePath("zzzss").build(); 38 | 39 | assertThat("aaaa").isEqualTo(backupStruct.getMongoInstallPath()); 40 | assertThat("bbb").isEqualTo(backupStruct.getHostName()); 41 | assertThat("cccc").isEqualTo(backupStruct.getTargetPath()); 42 | assertThat("1234").isEqualTo(backupStruct.getPort()); 43 | assertThat("zzzss").isEqualTo(backupStruct.getSourcePath()); 44 | } 45 | 46 | 47 | 48 | 49 | @Test 50 | public void builderStructTestTrim() 51 | { 52 | BackupStruct backupStruct = new BackupStruct.BackupStructBuilder() 53 | .setMongoInstallPath(" aaaa") 54 | .setHostName("bbb ") 55 | .setTargetPath(" cccc ") 56 | .setPort(" 1234 ") 57 | .setSourcePath(" zzzss ").build(); 58 | 59 | assertThat("aaaa").isEqualTo(backupStruct.getMongoInstallPath()); 60 | assertThat("bbb").isEqualTo(backupStruct.getHostName()); 61 | assertThat("cccc").isEqualTo(backupStruct.getTargetPath()); 62 | assertThat("1234").isEqualTo(backupStruct.getPort()); 63 | assertThat("zzzss").isEqualTo(backupStruct.getSourcePath()); 64 | } 65 | 66 | 67 | } 68 | -------------------------------------------------------------------------------- /src/test/resources/fakefiles/201609190618.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fbalicchia/graylog-plugin-backup-configuration/fbbe7f0ba00518e35fc891b3a62949376d8ab2e9/src/test/resources/fakefiles/201609190618.zip -------------------------------------------------------------------------------- /src/test/resources/fakefiles/201609190620.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fbalicchia/graylog-plugin-backup-configuration/fbbe7f0ba00518e35fc891b3a62949376d8ab2e9/src/test/resources/fakefiles/201609190620.zip -------------------------------------------------------------------------------- /src/test/resources/log4j.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/web/components/BackupActions.jsx: -------------------------------------------------------------------------------- 1 | import Reflux from 'reflux'; 2 | 3 | const BackupActions = Reflux.createActions({ 4 | launchRestore: { asyncResult: true }, 5 | }); 6 | 7 | export default BackupActions; -------------------------------------------------------------------------------- /src/web/components/BackupConfiguration.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Input, Button } from 'react-bootstrap'; 3 | import BootstrapModalForm from 'components/bootstrap/BootstrapModalForm'; 4 | import { IfPermitted, Select, ISODurationInput } from 'components/common'; 5 | import ObjectUtils from 'util/ObjectUtils'; 6 | import BackupActions from "components/BackupActions"; 7 | import BackupStore from "components/BackupStore"; 8 | 9 | const BackupConfiguration = React.createClass({ 10 | propTypes: { 11 | config: React.PropTypes.object, 12 | updateConfig: React.PropTypes.func.isRequired, 13 | }, 14 | 15 | 16 | getDefaultProps() { 17 | return { 18 | config: { 19 | enabled: false, 20 | cfg_backup_path: 'data/bck', 21 | cfg_restore_path: 'data/restore', 22 | mongodump_path: '/usr/bin', 23 | scheduled_period: 'P15D', 24 | }, 25 | }; 26 | }, 27 | 28 | getInitialState() { 29 | return { 30 | config: ObjectUtils.clone(this.props.config), 31 | }; 32 | }, 33 | 34 | componentWillReceiveProps(newProps) { 35 | this.setState({config: ObjectUtils.clone(newProps.config)}); 36 | }, 37 | 38 | _updateConfigField(field, value) { 39 | const update = ObjectUtils.clone(this.state.config); 40 | update[field] = value; 41 | this.setState({config: update}); 42 | }, 43 | 44 | _onCheckboxClick(field, ref) { 45 | return () => { 46 | this._updateConfigField(field, this.refs[ref].getChecked()); 47 | }; 48 | }, 49 | 50 | _onSelect(field) { 51 | return (selection) => { 52 | this._updateConfigField(field, selection); 53 | }; 54 | }, 55 | 56 | _onUpdate(field) { 57 | return (e) => { 58 | this._updateConfigField(field, e.target.value); 59 | }; 60 | }, 61 | 62 | _onUpdatePeriod(field) { 63 | return (value) => { 64 | const update = ObjectUtils.clone(this.state.config); 65 | update[field] = value; 66 | this.setState({ config: update }); 67 | }; 68 | }, 69 | 70 | 71 | _expirationThresholdValidator(milliseconds) { 72 | return milliseconds >= 60 * 1000; 73 | }, 74 | 75 | _openModal() { 76 | this.refs.backupConfigModal.open(); 77 | }, 78 | 79 | _closeModal() { 80 | this.refs.backupConfigModal.close(); 81 | }, 82 | 83 | _launchRestore() { 84 | BackupActions.launchRestore(); 85 | }, 86 | 87 | _resetConfig() { 88 | // Reset to initial state when the modal is closed without saving. 89 | this.setState(this.getInitialState()); 90 | }, 91 | 92 | _saveConfig() { 93 | this.props.updateConfig(this.state.config).then(() => { 94 | this._closeModal(); 95 | }); 96 | }, 97 | 98 | render() { 99 | return ( 100 |

101 |

Backup configuration

102 |

103 | Graylog backup plugin for dump Graylog configuration data. 104 | With Update Configuration is possible to adapt backup configuration to your needs and system. Restore data button restore data under directory Backuprestore/graylog 105 |

106 |
107 |
Enabled:
108 |
{this.state.config.enabled === true ? 'yes' : 'no'}
109 |
Backup frequency:
110 |
{this.state.config.scheduled_period}
111 |
BackupPath:
112 |
{this.state.config.cfg_backup_path}
113 |
Backuprestore:
114 |
{this.state.config.cfg_restore_path}
115 |
Mongodump path:
116 |
{this.state.config.mongodump_path}
117 |
118 | 119 | 120 | 121 | 122 | 123 | 124 | 129 |
130 | 136 | 137 | 142 | 143 | 148 | 149 | 154 | 155 | 162 |
163 |
164 |
165 | ); 166 | }, 167 | }); 168 | 169 | export default BackupConfiguration; 170 | -------------------------------------------------------------------------------- /src/web/components/BackupStore.jsx: -------------------------------------------------------------------------------- 1 | import Reflux from 'reflux'; 2 | 3 | 4 | import BackupActions from 'components/BackupActions' 5 | 6 | 7 | import UserNotification from 'util/UserNotification'; 8 | import URLUtils from 'util/URLUtils'; 9 | import fetch from 'logic/rest/FetchProvider'; 10 | 11 | const urlPrefix = '/plugins/org.graylog.plugins.backup'; 12 | 13 | const BackupStore = Reflux.createStore({ 14 | listenables: [BackupActions], 15 | 16 | getInitialState() { 17 | return { 18 | config: undefined, 19 | }; 20 | }, 21 | 22 | _errorHandler(message, title, cb) { 23 | return (error) => { 24 | let errorMessage; 25 | try { 26 | errorMessage = error.additional.body.message; 27 | } catch (e) { 28 | errorMessage = error.message; 29 | } 30 | UserNotification.error(`${message}: ${errorMessage}`, title); 31 | if (cb) { 32 | cb(error); 33 | } 34 | }; 35 | }, 36 | 37 | _url(path) { 38 | return URLUtils.qualifyUrl(`${urlPrefix}${path}`); 39 | }, 40 | 41 | 42 | launchRestore() { 43 | console.log("restore chiamato"); 44 | const promise = fetch('POST', this._url('/launchrestore')); 45 | promise.then((response) => { 46 | this.trigger({ config: response }); 47 | UserNotification.success('Configuration restore was completed successfully'); 48 | }, this._errorHandler('Backup restore failed', 'Unable restore config')); 49 | 50 | BackupActions.launchRestore.promise(promise); 51 | }, 52 | 53 | 54 | }); 55 | 56 | export default BackupStore; -------------------------------------------------------------------------------- /src/web/index.jsx: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line no-unused-vars 2 | import webpackEntry from 'webpack-entry'; 3 | 4 | import packageJson from '../../package.json'; 5 | import { PluginManifest, PluginStore } from 'graylog-web-plugin/plugin'; 6 | import BackupConfiguration from "components/BackupConfiguration"; 7 | 8 | PluginStore.register(new PluginManifest(packageJson, { 9 | systemConfigurations: [ 10 | { 11 | component: BackupConfiguration, 12 | configType: 'org.graylog.plugins.backup.BackupConfiguration', 13 | }, 14 | ], 15 | })); 16 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | const PluginWebpackConfig = require('graylog-web-plugin').PluginWebpackConfig; 2 | const loadBuildConfig = require('graylog-web-plugin').loadBuildConfig; 3 | const path = require('path'); 4 | 5 | // Remember to use the same name here and in `getUniqueId()` in the java MetaData class 6 | module.exports = new PluginWebpackConfig('org.graylog.plugins.backup.BackupConfigurationPlugin', loadBuildConfig(path.resolve(__dirname, './build.config')), { 7 | // Here goes your additional webpack configuration. 8 | }); 9 | --------------------------------------------------------------------------------