Compare commits
9 Commits
c5a1ac0551
...
aa8a68aa80
Author | SHA1 | Date | |
---|---|---|---|
aa8a68aa80 | |||
7fcc5afc64 | |||
e7e98d0b47 | |||
8479c378ee | |||
274e1e2e59 | |||
eb0bdaedbd | |||
99dc6e0abf | |||
e8ba6df102 | |||
ffd9bf3d39 |
@ -17,9 +17,8 @@ jobs:
|
|||||||
python-version: '3.12'
|
python-version: '3.12'
|
||||||
cache: 'pip' # caching pip dependencies
|
cache: 'pip' # caching pip dependencies
|
||||||
- run: pip install ruff
|
- run: pip install ruff
|
||||||
- run: |
|
- run: |
|
||||||
ruff check .
|
ruff check .
|
||||||
ruff fix .
|
|
||||||
# - uses: stefanzweifel/git-auto-commit-action@v4
|
# - uses: stefanzweifel/git-auto-commit-action@v4
|
||||||
# with:
|
# with:
|
||||||
# commit_message: 'style fixes by ruff'
|
# commit_message: 'style fixes by ruff'
|
||||||
|
2
.gitignore
vendored
2
.gitignore
vendored
@ -2,11 +2,13 @@
|
|||||||
*.swp
|
*.swp
|
||||||
*~
|
*~
|
||||||
*.pyc
|
*.pyc
|
||||||
|
__pycache__/*
|
||||||
/tasks.sqlite
|
/tasks.sqlite
|
||||||
/tasks.sqlite-wal
|
/tasks.sqlite-wal
|
||||||
/srvinstallation
|
/srvinstallation
|
||||||
/tasks.sqlite-shm
|
/tasks.sqlite-shm
|
||||||
.idea
|
.idea
|
||||||
|
.ruff_cache/*
|
||||||
/deb/builddir
|
/deb/builddir
|
||||||
/deb/*.deb
|
/deb/*.deb
|
||||||
/lib
|
/lib
|
||||||
|
13
.hadolint.yml
Normal file
13
.hadolint.yml
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
DL3008failure-threshold: warning
|
||||||
|
format: tty
|
||||||
|
ignored:
|
||||||
|
- DL3007
|
||||||
|
override:
|
||||||
|
error:
|
||||||
|
- DL3015
|
||||||
|
warning:
|
||||||
|
- DL3015
|
||||||
|
info:
|
||||||
|
- DL3008
|
||||||
|
style:
|
||||||
|
- DL3015
|
7
.pre-commit-config.yaml
Normal file
7
.pre-commit-config.yaml
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
repos:
|
||||||
|
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||||
|
rev: v5.0.0
|
||||||
|
hooks:
|
||||||
|
- id: trailing-whitespace
|
||||||
|
- id: end-of-file-fixer
|
||||||
|
- id: check-yaml
|
2
.vscode/launch.json
vendored
2
.vscode/launch.json
vendored
@ -19,4 +19,4 @@
|
|||||||
"console": "integratedTerminal"
|
"console": "integratedTerminal"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
20
Dockerfile
Executable file
20
Dockerfile
Executable file
@ -0,0 +1,20 @@
|
|||||||
|
FROM python:3.12-slim
|
||||||
|
|
||||||
|
WORKDIR /opt/tisbackup
|
||||||
|
|
||||||
|
COPY entrypoint.sh /entrypoint.sh
|
||||||
|
COPY . /opt/tisbackup
|
||||||
|
|
||||||
|
RUN apt-get update \
|
||||||
|
&& apt-get install --no-install-recommends -y rsync ssh cron \
|
||||||
|
&& rm -rf /var/lib/apt/lists/* \
|
||||||
|
&& /usr/local/bin/python3.12 -m pip install --no-cache-dir -r requirements.txt \
|
||||||
|
&& mkdir -p /var/spool/cron/crontabs \
|
||||||
|
&& echo '59 03 * * * root /bin/bash /opt/tisbackup/backup.sh' > /etc/crontab \
|
||||||
|
&& echo '' >> /etc/crontab \
|
||||||
|
&& crontab /etc/crontab
|
||||||
|
|
||||||
|
EXPOSE 8080
|
||||||
|
|
||||||
|
ENTRYPOINT ["/entrypoint.sh"]
|
||||||
|
CMD ["/usr/local/bin/python3.12","/opt/tisbackup/tisbackup_gui.py"]
|
41
compose.yml
Executable file
41
compose.yml
Executable file
@ -0,0 +1,41 @@
|
|||||||
|
services:
|
||||||
|
tisbackup_gui:
|
||||||
|
container_name: tisbackup_gui
|
||||||
|
image: "tisbackup:latest"
|
||||||
|
build: .
|
||||||
|
volumes:
|
||||||
|
- ./config/:/etc/tis/
|
||||||
|
- ./backup/:/backup/
|
||||||
|
- /etc/timezone:/etc/timezone:ro
|
||||||
|
- /etc/localtime:/etc/localtime:ro
|
||||||
|
restart: unless-stopped
|
||||||
|
ports:
|
||||||
|
- 9980:8080
|
||||||
|
deploy:
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
cpus: 0.50
|
||||||
|
memory: 512M
|
||||||
|
reservations:
|
||||||
|
cpus: 0.25
|
||||||
|
memory: 128M
|
||||||
|
tisbackup_cron:
|
||||||
|
container_name: tisbackup_cron
|
||||||
|
image: "tisbackup:latest"
|
||||||
|
build: .
|
||||||
|
volumes:
|
||||||
|
- ./config/:/etc/tis/
|
||||||
|
- ./ssh/:/config_ssh/
|
||||||
|
- ./backup/:/backup/
|
||||||
|
- /etc/timezone:/etc/timezone:ro
|
||||||
|
- /etc/localtime:/etc/localtime:ro
|
||||||
|
restart: always
|
||||||
|
command: "/bin/bash /opt/tisbackup/cron.sh"
|
||||||
|
deploy:
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
cpus: 0.50
|
||||||
|
memory: 512M
|
||||||
|
reservations:
|
||||||
|
cpus: 0.25
|
||||||
|
memory: 128M
|
13
config.py
Normal file → Executable file
13
config.py
Normal file → Executable file
@ -1,10 +1,9 @@
|
|||||||
import os,sys
|
import os
|
||||||
from huey.backends.sqlite_backend import SqliteQueue,SqliteDataStore
|
import sys
|
||||||
from huey.api import Huey, create_task
|
|
||||||
|
|
||||||
|
from huey.contrib.sql_huey import SqlHuey
|
||||||
|
from huey.storage import SqliteStorage
|
||||||
|
|
||||||
tisbackup_root_dir = os.path.abspath(os.path.join(os.path.dirname(__file__)))
|
tisbackup_root_dir = os.path.abspath(os.path.join(os.path.dirname(__file__)))
|
||||||
tasks_db = os.path.join(tisbackup_root_dir,"tasks.sqlite")
|
tasks_db = os.path.join(tisbackup_root_dir, "tasks.sqlite")
|
||||||
queue = SqliteQueue('tisbackups',tasks_db)
|
huey = SqlHuey(name="tisbackups",filename=tasks_db,always_eager=False,storage_class=SqliteStorage)
|
||||||
result_store = SqliteDataStore('tisbackups',tasks_db)
|
|
||||||
huey = Huey(queue,result_store,always_eager=False)
|
|
||||||
|
4
cron.sh
Executable file
4
cron.sh
Executable file
@ -0,0 +1,4 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
set -x
|
||||||
|
echo "Starting cron job for TIS Backup"
|
||||||
|
cron -f -l 2
|
@ -1,42 +1,42 @@
|
|||||||
## tisbackup for python3
|
## tisbackup for python3
|
||||||
|
|
||||||
### Install
|
### Install
|
||||||
|
|
||||||
Once the deb package is created, one can use it to install tisbackup on a debian machine. The command is:
|
Once the deb package is created, one can use it to install tisbackup on a debian machine. The command is:
|
||||||
```
|
```
|
||||||
apt install ./tis-tisbackup-1-2-0.170-deb11.deb
|
apt install ./tis-tisbackup-1-2-0.170-deb11.deb
|
||||||
```
|
```
|
||||||
Note that the version numbers might be different depending on the system you used to build the package.
|
Note that the version numbers might be different depending on the system you used to build the package.
|
||||||
|
|
||||||
Then create a directory where to backup the files from your machines. The default is ```/backup```.
|
Then create a directory where to backup the files from your machines. The default is ```/backup```.
|
||||||
This can be changed in the configuration file ```/etc/tis/tisback-config.ini```. Usually this
|
This can be changed in the configuration file ```/etc/tis/tisback-config.ini```. Usually this
|
||||||
directory is mounted from a shared ressource on a NAS with great capacity.
|
directory is mounted from a shared ressource on a NAS with great capacity.
|
||||||
|
|
||||||
Configure your backup jobs:
|
Configure your backup jobs:
|
||||||
```
|
```
|
||||||
cd /etc/tis
|
cd /etc/tis
|
||||||
cp tisbackup-config.ini.sample tisbackup-config.ini
|
cp tisbackup-config.ini.sample tisbackup-config.ini
|
||||||
vi tisbackup-config.ini
|
vi tisbackup-config.ini
|
||||||
```
|
```
|
||||||
|
|
||||||
After this, one have to generate the public and private certificates, as root:
|
After this, one have to generate the public and private certificates, as root:
|
||||||
```
|
```
|
||||||
cd
|
cd
|
||||||
ssh-keygen -t rsa -b 2048
|
ssh-keygen -t rsa -b 2048
|
||||||
```
|
```
|
||||||
(press enter for each step)
|
(press enter for each step)
|
||||||
|
|
||||||
Then propagate the public certificate on the machines targetted for backup:
|
Then propagate the public certificate on the machines targetted for backup:
|
||||||
```
|
```
|
||||||
ssh-copy-id -i /root/.ssh/id_rsa.pub root@machine1
|
ssh-copy-id -i /root/.ssh/id_rsa.pub root@machine1
|
||||||
ssh-copy-id -i /root/.ssh/id_rsa.pub root@machine2
|
ssh-copy-id -i /root/.ssh/id_rsa.pub root@machine2
|
||||||
```
|
```
|
||||||
etc.
|
etc.
|
||||||
|
|
||||||
|
|
||||||
Eventually modify ```/etc/cron.d/tisbackup``` for your needs.
|
Eventually modify ```/etc/cron.d/tisbackup``` for your needs.
|
||||||
|
|
||||||
Finalize the installation with:
|
Finalize the installation with:
|
||||||
```
|
```
|
||||||
tisbackup -d backup
|
tisbackup -d backup
|
||||||
systemctl start tisbackup_gui
|
systemctl start tisbackup_gui
|
||||||
@ -52,5 +52,3 @@ The documentation for tisbackup is here: [tisbackup doc](https://tisbackup.readt
|
|||||||
dpkg --force-all --purge tis-tisbackup
|
dpkg --force-all --purge tis-tisbackup
|
||||||
apt autoremove
|
apt autoremove
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
@ -3,8 +3,7 @@ Version: 1-__VERSION__
|
|||||||
Section: base
|
Section: base
|
||||||
Priority: optional
|
Priority: optional
|
||||||
Architecture: all
|
Architecture: all
|
||||||
Depends: unzip, ssh, rsync, python3-paramiko, python3-pyvmomi, python3-pexpect, python3-flask,python3-simplejson, python3-pip
|
Depends: unzip, ssh, rsync, python3-paramiko, python3-pyvmomi, python3-pexpect, python3-flask,python3-simplejson, python3-pip
|
||||||
Maintainer: Tranquil-IT <technique@tranquil.it>
|
Maintainer: Tranquil-IT <technique@tranquil.it>
|
||||||
Description: TISBackup backup management
|
Description: TISBackup backup management
|
||||||
Homepage: https://www.tranquil.it
|
Homepage: https://www.tranquil.it
|
||||||
|
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
VERSION_DEB=$(cat /etc/debian_version | cut -d "." -f 1)
|
VERSION_DEB=$(cat /etc/debian_version | cut -d "." -f 1)
|
||||||
VERSION_SHORT=$(cat ../tisbackup.py | grep "__version__" | cut -d "=" -f 2 | sed 's/"//g')
|
VERSION_SHORT=$(cat ../tisbackup.py | grep "__version__" | cut -d "=" -f 2 | sed 's/"//g')
|
||||||
GIT_COUNT=`git rev-list HEAD --count`
|
GIT_COUNT=`git rev-list HEAD --count`
|
||||||
VERSION="${VERSION_SHORT}.${GIT_COUNT}-deb${VERSION_DEB}"
|
VERSION="${VERSION_SHORT}.${GIT_COUNT}-deb${VERSION_DEB}"
|
||||||
|
|
||||||
rm -f *.deb
|
rm -f *.deb
|
||||||
@ -32,5 +32,3 @@ rsync -aP ../samples/tisbackup-config.ini.sample ./builddir/etc/tis/tisbackup-c
|
|||||||
chmod 755 ./builddir/opt/tisbackup/tisbackup.py
|
chmod 755 ./builddir/opt/tisbackup/tisbackup.py
|
||||||
|
|
||||||
dpkg-deb --build builddir tis-tisbackup-1-${VERSION}.deb
|
dpkg-deb --build builddir tis-tisbackup-1-${VERSION}.deb
|
||||||
|
|
||||||
|
|
||||||
|
2
docs/_static/basic.css
vendored
2
docs/_static/basic.css
vendored
@ -765,4 +765,4 @@ div.math:hover a.headerlink {
|
|||||||
#top-link {
|
#top-link {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
2
docs/_static/css/badge_only.css
vendored
2
docs/_static/css/badge_only.css
vendored
@ -1 +1 @@
|
|||||||
.fa:before{-webkit-font-smoothing:antialiased}.clearfix{*zoom:1}.clearfix:after,.clearfix:before{display:table;content:""}.clearfix:after{clear:both}@font-face{font-family:FontAwesome;font-style:normal;font-weight:400;src:url(fonts/fontawesome-webfont.eot?674f50d287a8c48dc19ba404d20fe713?#iefix) format("embedded-opentype"),url(fonts/fontawesome-webfont.woff2?af7ae505a9eed503f8b8e6982036873e) format("woff2"),url(fonts/fontawesome-webfont.woff?fee66e712a8a08eef5805a46892932ad) format("woff"),url(fonts/fontawesome-webfont.ttf?b06871f281fee6b241d60582ae9369b9) format("truetype"),url(fonts/fontawesome-webfont.svg?912ec66d7572ff821749319396470bde#FontAwesome) format("svg")}.fa:before{font-family:FontAwesome;font-style:normal;font-weight:400;line-height:1}.fa:before,a .fa{text-decoration:inherit}.fa:before,a .fa,li .fa{display:inline-block}li .fa-large:before{width:1.875em}ul.fas{list-style-type:none;margin-left:2em;text-indent:-.8em}ul.fas li .fa{width:.8em}ul.fas li .fa-large:before{vertical-align:baseline}.fa-book:before,.icon-book:before{content:"\f02d"}.fa-caret-down:before,.icon-caret-down:before{content:"\f0d7"}.fa-caret-up:before,.icon-caret-up:before{content:"\f0d8"}.fa-caret-left:before,.icon-caret-left:before{content:"\f0d9"}.fa-caret-right:before,.icon-caret-right:before{content:"\f0da"}.rst-versions{position:fixed;bottom:0;left:0;width:300px;color:#fcfcfc;background:#1f1d1d;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;z-index:400}.rst-versions a{color:#2980b9;text-decoration:none}.rst-versions .rst-badge-small{display:none}.rst-versions .rst-current-version{padding:12px;background-color:#272525;display:block;text-align:right;font-size:90%;cursor:pointer;color:#27ae60}.rst-versions .rst-current-version:after{clear:both;content:"";display:block}.rst-versions .rst-current-version .fa{color:#fcfcfc}.rst-versions .rst-current-version .fa-book,.rst-versions .rst-current-version .icon-book{float:left}.rst-versions .rst-current-version.rst-out-of-date{background-color:#e74c3c;color:#fff}.rst-versions .rst-current-version.rst-active-old-version{background-color:#f1c40f;color:#000}.rst-versions.shift-up{height:auto;max-height:100%;overflow-y:scroll}.rst-versions.shift-up .rst-other-versions{display:block}.rst-versions .rst-other-versions{font-size:90%;padding:12px;color:grey;display:none}.rst-versions .rst-other-versions hr{display:block;height:1px;border:0;margin:20px 0;padding:0;border-top:1px solid #413d3d}.rst-versions .rst-other-versions dd{display:inline-block;margin:0}.rst-versions .rst-other-versions dd a{display:inline-block;padding:6px;color:#fcfcfc}.rst-versions.rst-badge{width:auto;bottom:20px;right:20px;left:auto;border:none;max-width:300px;max-height:90%}.rst-versions.rst-badge .fa-book,.rst-versions.rst-badge .icon-book{float:none;line-height:30px}.rst-versions.rst-badge.shift-up .rst-current-version{text-align:right}.rst-versions.rst-badge.shift-up .rst-current-version .fa-book,.rst-versions.rst-badge.shift-up .rst-current-version .icon-book{float:left}.rst-versions.rst-badge>.rst-current-version{width:auto;height:30px;line-height:30px;padding:0 6px;display:block;text-align:center}@media screen and (max-width:768px){.rst-versions{width:85%;display:none}.rst-versions.shift{display:block}}
|
.fa:before{-webkit-font-smoothing:antialiased}.clearfix{*zoom:1}.clearfix:after,.clearfix:before{display:table;content:""}.clearfix:after{clear:both}@font-face{font-family:FontAwesome;font-style:normal;font-weight:400;src:url(fonts/fontawesome-webfont.eot?674f50d287a8c48dc19ba404d20fe713?#iefix) format("embedded-opentype"),url(fonts/fontawesome-webfont.woff2?af7ae505a9eed503f8b8e6982036873e) format("woff2"),url(fonts/fontawesome-webfont.woff?fee66e712a8a08eef5805a46892932ad) format("woff"),url(fonts/fontawesome-webfont.ttf?b06871f281fee6b241d60582ae9369b9) format("truetype"),url(fonts/fontawesome-webfont.svg?912ec66d7572ff821749319396470bde#FontAwesome) format("svg")}.fa:before{font-family:FontAwesome;font-style:normal;font-weight:400;line-height:1}.fa:before,a .fa{text-decoration:inherit}.fa:before,a .fa,li .fa{display:inline-block}li .fa-large:before{width:1.875em}ul.fas{list-style-type:none;margin-left:2em;text-indent:-.8em}ul.fas li .fa{width:.8em}ul.fas li .fa-large:before{vertical-align:baseline}.fa-book:before,.icon-book:before{content:"\f02d"}.fa-caret-down:before,.icon-caret-down:before{content:"\f0d7"}.fa-caret-up:before,.icon-caret-up:before{content:"\f0d8"}.fa-caret-left:before,.icon-caret-left:before{content:"\f0d9"}.fa-caret-right:before,.icon-caret-right:before{content:"\f0da"}.rst-versions{position:fixed;bottom:0;left:0;width:300px;color:#fcfcfc;background:#1f1d1d;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;z-index:400}.rst-versions a{color:#2980b9;text-decoration:none}.rst-versions .rst-badge-small{display:none}.rst-versions .rst-current-version{padding:12px;background-color:#272525;display:block;text-align:right;font-size:90%;cursor:pointer;color:#27ae60}.rst-versions .rst-current-version:after{clear:both;content:"";display:block}.rst-versions .rst-current-version .fa{color:#fcfcfc}.rst-versions .rst-current-version .fa-book,.rst-versions .rst-current-version .icon-book{float:left}.rst-versions .rst-current-version.rst-out-of-date{background-color:#e74c3c;color:#fff}.rst-versions .rst-current-version.rst-active-old-version{background-color:#f1c40f;color:#000}.rst-versions.shift-up{height:auto;max-height:100%;overflow-y:scroll}.rst-versions.shift-up .rst-other-versions{display:block}.rst-versions .rst-other-versions{font-size:90%;padding:12px;color:grey;display:none}.rst-versions .rst-other-versions hr{display:block;height:1px;border:0;margin:20px 0;padding:0;border-top:1px solid #413d3d}.rst-versions .rst-other-versions dd{display:inline-block;margin:0}.rst-versions .rst-other-versions dd a{display:inline-block;padding:6px;color:#fcfcfc}.rst-versions.rst-badge{width:auto;bottom:20px;right:20px;left:auto;border:none;max-width:300px;max-height:90%}.rst-versions.rst-badge .fa-book,.rst-versions.rst-badge .icon-book{float:none;line-height:30px}.rst-versions.rst-badge.shift-up .rst-current-version{text-align:right}.rst-versions.rst-badge.shift-up .rst-current-version .fa-book,.rst-versions.rst-badge.shift-up .rst-current-version .icon-book{float:left}.rst-versions.rst-badge>.rst-current-version{width:auto;height:30px;line-height:30px;padding:0 6px;display:block;text-align:center}@media screen and (max-width:768px){.rst-versions{width:85%;display:none}.rst-versions.shift{display:block}}
|
||||||
|
1418
docs/_static/css/fonts/fontawesome-webfont.svg
vendored
1418
docs/_static/css/fonts/fontawesome-webfont.svg
vendored
File diff suppressed because it is too large
Load Diff
Before Width: | Height: | Size: 434 KiB After Width: | Height: | Size: 433 KiB |
2
docs/_static/css/theme.css
vendored
2
docs/_static/css/theme.css
vendored
File diff suppressed because one or more lines are too long
2
docs/_static/documentation_options.js
vendored
2
docs/_static/documentation_options.js
vendored
@ -9,4 +9,4 @@ var DOCUMENTATION_OPTIONS = {
|
|||||||
HAS_SOURCE: true,
|
HAS_SOURCE: true,
|
||||||
SOURCELINK_SUFFIX: '.txt',
|
SOURCELINK_SUFFIX: '.txt',
|
||||||
NAVIGATION_WITH_KEYS: false
|
NAVIGATION_WITH_KEYS: false
|
||||||
};
|
};
|
||||||
|
1418
docs/_static/fonts/fontawesome-webfont.svg
vendored
1418
docs/_static/fonts/fontawesome-webfont.svg
vendored
File diff suppressed because it is too large
Load Diff
Before Width: | Height: | Size: 434 KiB After Width: | Height: | Size: 433 KiB |
2
docs/_static/js/badge_only.js
vendored
2
docs/_static/js/badge_only.js
vendored
@ -1 +1 @@
|
|||||||
!function(e){var t={};function r(n){if(t[n])return t[n].exports;var o=t[n]={i:n,l:!1,exports:{}};return e[n].call(o.exports,o,o.exports,r),o.l=!0,o.exports}r.m=e,r.c=t,r.d=function(e,t,n){r.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:n})},r.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},r.t=function(e,t){if(1&t&&(e=r(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var n=Object.create(null);if(r.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)r.d(n,o,function(t){return e[t]}.bind(null,o));return n},r.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return r.d(t,"a",t),t},r.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},r.p="",r(r.s=4)}({4:function(e,t,r){}});
|
!function(e){var t={};function r(n){if(t[n])return t[n].exports;var o=t[n]={i:n,l:!1,exports:{}};return e[n].call(o.exports,o,o.exports,r),o.l=!0,o.exports}r.m=e,r.c=t,r.d=function(e,t,n){r.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:n})},r.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},r.t=function(e,t){if(1&t&&(e=r(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var n=Object.create(null);if(r.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)r.d(n,o,function(t){return e[t]}.bind(null,o));return n},r.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return r.d(t,"a",t),t},r.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},r.p="",r(r.s=4)}({4:function(e,t,r){}});
|
||||||
|
2
docs/_static/js/html5shiv-printshiv.min.js
vendored
2
docs/_static/js/html5shiv-printshiv.min.js
vendored
@ -1,4 +1,4 @@
|
|||||||
/**
|
/**
|
||||||
* @preserve HTML5 Shiv 3.7.3-pre | @afarkas @jdalton @jon_neal @rem | MIT/GPL2 Licensed
|
* @preserve HTML5 Shiv 3.7.3-pre | @afarkas @jdalton @jon_neal @rem | MIT/GPL2 Licensed
|
||||||
*/
|
*/
|
||||||
!function(a,b){function c(a,b){var c=a.createElement("p"),d=a.getElementsByTagName("head")[0]||a.documentElement;return c.innerHTML="x<style>"+b+"</style>",d.insertBefore(c.lastChild,d.firstChild)}function d(){var a=y.elements;return"string"==typeof a?a.split(" "):a}function e(a,b){var c=y.elements;"string"!=typeof c&&(c=c.join(" ")),"string"!=typeof a&&(a=a.join(" ")),y.elements=c+" "+a,j(b)}function f(a){var b=x[a[v]];return b||(b={},w++,a[v]=w,x[w]=b),b}function g(a,c,d){if(c||(c=b),q)return c.createElement(a);d||(d=f(c));var e;return e=d.cache[a]?d.cache[a].cloneNode():u.test(a)?(d.cache[a]=d.createElem(a)).cloneNode():d.createElem(a),!e.canHaveChildren||t.test(a)||e.tagUrn?e:d.frag.appendChild(e)}function h(a,c){if(a||(a=b),q)return a.createDocumentFragment();c=c||f(a);for(var e=c.frag.cloneNode(),g=0,h=d(),i=h.length;i>g;g++)e.createElement(h[g]);return e}function i(a,b){b.cache||(b.cache={},b.createElem=a.createElement,b.createFrag=a.createDocumentFragment,b.frag=b.createFrag()),a.createElement=function(c){return y.shivMethods?g(c,a,b):b.createElem(c)},a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+d().join().replace(/[\w\-:]+/g,function(a){return b.createElem(a),b.frag.createElement(a),'c("'+a+'")'})+");return n}")(y,b.frag)}function j(a){a||(a=b);var d=f(a);return!y.shivCSS||p||d.hasCSS||(d.hasCSS=!!c(a,"article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}mark{background:#FF0;color:#000}template{display:none}")),q||i(a,d),a}function k(a){for(var b,c=a.getElementsByTagName("*"),e=c.length,f=RegExp("^(?:"+d().join("|")+")$","i"),g=[];e--;)b=c[e],f.test(b.nodeName)&&g.push(b.applyElement(l(b)));return g}function l(a){for(var b,c=a.attributes,d=c.length,e=a.ownerDocument.createElement(A+":"+a.nodeName);d--;)b=c[d],b.specified&&e.setAttribute(b.nodeName,b.nodeValue);return e.style.cssText=a.style.cssText,e}function m(a){for(var b,c=a.split("{"),e=c.length,f=RegExp("(^|[\\s,>+~])("+d().join("|")+")(?=[[\\s,>+~#.:]|$)","gi"),g="$1"+A+"\\:$2";e--;)b=c[e]=c[e].split("}"),b[b.length-1]=b[b.length-1].replace(f,g),c[e]=b.join("}");return c.join("{")}function n(a){for(var b=a.length;b--;)a[b].removeNode()}function o(a){function b(){clearTimeout(g._removeSheetTimer),d&&d.removeNode(!0),d=null}var d,e,g=f(a),h=a.namespaces,i=a.parentWindow;return!B||a.printShived?a:("undefined"==typeof h[A]&&h.add(A),i.attachEvent("onbeforeprint",function(){b();for(var f,g,h,i=a.styleSheets,j=[],l=i.length,n=Array(l);l--;)n[l]=i[l];for(;h=n.pop();)if(!h.disabled&&z.test(h.media)){try{f=h.imports,g=f.length}catch(o){g=0}for(l=0;g>l;l++)n.push(f[l]);try{j.push(h.cssText)}catch(o){}}j=m(j.reverse().join("")),e=k(a),d=c(a,j)}),i.attachEvent("onafterprint",function(){n(e),clearTimeout(g._removeSheetTimer),g._removeSheetTimer=setTimeout(b,500)}),a.printShived=!0,a)}var p,q,r="3.7.3",s=a.html5||{},t=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,u=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,v="_html5shiv",w=0,x={};!function(){try{var a=b.createElement("a");a.innerHTML="<xyz></xyz>",p="hidden"in a,q=1==a.childNodes.length||function(){b.createElement("a");var a=b.createDocumentFragment();return"undefined"==typeof a.cloneNode||"undefined"==typeof a.createDocumentFragment||"undefined"==typeof a.createElement}()}catch(c){p=!0,q=!0}}();var y={elements:s.elements||"abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output picture progress section summary template time video",version:r,shivCSS:s.shivCSS!==!1,supportsUnknownElements:q,shivMethods:s.shivMethods!==!1,type:"default",shivDocument:j,createElement:g,createDocumentFragment:h,addElements:e};a.html5=y,j(b);var z=/^$|\b(?:all|print)\b/,A="html5shiv",B=!q&&function(){var c=b.documentElement;return!("undefined"==typeof b.namespaces||"undefined"==typeof b.parentWindow||"undefined"==typeof c.applyElement||"undefined"==typeof c.removeNode||"undefined"==typeof a.attachEvent)}();y.type+=" print",y.shivPrint=o,o(b),"object"==typeof module&&module.exports&&(module.exports=y)}("undefined"!=typeof window?window:this,document);
|
!function(a,b){function c(a,b){var c=a.createElement("p"),d=a.getElementsByTagName("head")[0]||a.documentElement;return c.innerHTML="x<style>"+b+"</style>",d.insertBefore(c.lastChild,d.firstChild)}function d(){var a=y.elements;return"string"==typeof a?a.split(" "):a}function e(a,b){var c=y.elements;"string"!=typeof c&&(c=c.join(" ")),"string"!=typeof a&&(a=a.join(" ")),y.elements=c+" "+a,j(b)}function f(a){var b=x[a[v]];return b||(b={},w++,a[v]=w,x[w]=b),b}function g(a,c,d){if(c||(c=b),q)return c.createElement(a);d||(d=f(c));var e;return e=d.cache[a]?d.cache[a].cloneNode():u.test(a)?(d.cache[a]=d.createElem(a)).cloneNode():d.createElem(a),!e.canHaveChildren||t.test(a)||e.tagUrn?e:d.frag.appendChild(e)}function h(a,c){if(a||(a=b),q)return a.createDocumentFragment();c=c||f(a);for(var e=c.frag.cloneNode(),g=0,h=d(),i=h.length;i>g;g++)e.createElement(h[g]);return e}function i(a,b){b.cache||(b.cache={},b.createElem=a.createElement,b.createFrag=a.createDocumentFragment,b.frag=b.createFrag()),a.createElement=function(c){return y.shivMethods?g(c,a,b):b.createElem(c)},a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+d().join().replace(/[\w\-:]+/g,function(a){return b.createElem(a),b.frag.createElement(a),'c("'+a+'")'})+");return n}")(y,b.frag)}function j(a){a||(a=b);var d=f(a);return!y.shivCSS||p||d.hasCSS||(d.hasCSS=!!c(a,"article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}mark{background:#FF0;color:#000}template{display:none}")),q||i(a,d),a}function k(a){for(var b,c=a.getElementsByTagName("*"),e=c.length,f=RegExp("^(?:"+d().join("|")+")$","i"),g=[];e--;)b=c[e],f.test(b.nodeName)&&g.push(b.applyElement(l(b)));return g}function l(a){for(var b,c=a.attributes,d=c.length,e=a.ownerDocument.createElement(A+":"+a.nodeName);d--;)b=c[d],b.specified&&e.setAttribute(b.nodeName,b.nodeValue);return e.style.cssText=a.style.cssText,e}function m(a){for(var b,c=a.split("{"),e=c.length,f=RegExp("(^|[\\s,>+~])("+d().join("|")+")(?=[[\\s,>+~#.:]|$)","gi"),g="$1"+A+"\\:$2";e--;)b=c[e]=c[e].split("}"),b[b.length-1]=b[b.length-1].replace(f,g),c[e]=b.join("}");return c.join("{")}function n(a){for(var b=a.length;b--;)a[b].removeNode()}function o(a){function b(){clearTimeout(g._removeSheetTimer),d&&d.removeNode(!0),d=null}var d,e,g=f(a),h=a.namespaces,i=a.parentWindow;return!B||a.printShived?a:("undefined"==typeof h[A]&&h.add(A),i.attachEvent("onbeforeprint",function(){b();for(var f,g,h,i=a.styleSheets,j=[],l=i.length,n=Array(l);l--;)n[l]=i[l];for(;h=n.pop();)if(!h.disabled&&z.test(h.media)){try{f=h.imports,g=f.length}catch(o){g=0}for(l=0;g>l;l++)n.push(f[l]);try{j.push(h.cssText)}catch(o){}}j=m(j.reverse().join("")),e=k(a),d=c(a,j)}),i.attachEvent("onafterprint",function(){n(e),clearTimeout(g._removeSheetTimer),g._removeSheetTimer=setTimeout(b,500)}),a.printShived=!0,a)}var p,q,r="3.7.3",s=a.html5||{},t=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,u=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,v="_html5shiv",w=0,x={};!function(){try{var a=b.createElement("a");a.innerHTML="<xyz></xyz>",p="hidden"in a,q=1==a.childNodes.length||function(){b.createElement("a");var a=b.createDocumentFragment();return"undefined"==typeof a.cloneNode||"undefined"==typeof a.createDocumentFragment||"undefined"==typeof a.createElement}()}catch(c){p=!0,q=!0}}();var y={elements:s.elements||"abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output picture progress section summary template time video",version:r,shivCSS:s.shivCSS!==!1,supportsUnknownElements:q,shivMethods:s.shivMethods!==!1,type:"default",shivDocument:j,createElement:g,createDocumentFragment:h,addElements:e};a.html5=y,j(b);var z=/^$|\b(?:all|print)\b/,A="html5shiv",B=!q&&function(){var c=b.documentElement;return!("undefined"==typeof b.namespaces||"undefined"==typeof b.parentWindow||"undefined"==typeof c.applyElement||"undefined"==typeof c.removeNode||"undefined"==typeof a.attachEvent)}();y.type+=" print",y.shivPrint=o,o(b),"object"==typeof module&&module.exports&&(module.exports=y)}("undefined"!=typeof window?window:this,document);
|
||||||
|
2
docs/_static/js/html5shiv.min.js
vendored
2
docs/_static/js/html5shiv.min.js
vendored
@ -1,4 +1,4 @@
|
|||||||
/**
|
/**
|
||||||
* @preserve HTML5 Shiv 3.7.3 | @afarkas @jdalton @jon_neal @rem | MIT/GPL2 Licensed
|
* @preserve HTML5 Shiv 3.7.3 | @afarkas @jdalton @jon_neal @rem | MIT/GPL2 Licensed
|
||||||
*/
|
*/
|
||||||
!function(a,b){function c(a,b){var c=a.createElement("p"),d=a.getElementsByTagName("head")[0]||a.documentElement;return c.innerHTML="x<style>"+b+"</style>",d.insertBefore(c.lastChild,d.firstChild)}function d(){var a=t.elements;return"string"==typeof a?a.split(" "):a}function e(a,b){var c=t.elements;"string"!=typeof c&&(c=c.join(" ")),"string"!=typeof a&&(a=a.join(" ")),t.elements=c+" "+a,j(b)}function f(a){var b=s[a[q]];return b||(b={},r++,a[q]=r,s[r]=b),b}function g(a,c,d){if(c||(c=b),l)return c.createElement(a);d||(d=f(c));var e;return e=d.cache[a]?d.cache[a].cloneNode():p.test(a)?(d.cache[a]=d.createElem(a)).cloneNode():d.createElem(a),!e.canHaveChildren||o.test(a)||e.tagUrn?e:d.frag.appendChild(e)}function h(a,c){if(a||(a=b),l)return a.createDocumentFragment();c=c||f(a);for(var e=c.frag.cloneNode(),g=0,h=d(),i=h.length;i>g;g++)e.createElement(h[g]);return e}function i(a,b){b.cache||(b.cache={},b.createElem=a.createElement,b.createFrag=a.createDocumentFragment,b.frag=b.createFrag()),a.createElement=function(c){return t.shivMethods?g(c,a,b):b.createElem(c)},a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+d().join().replace(/[\w\-:]+/g,function(a){return b.createElem(a),b.frag.createElement(a),'c("'+a+'")'})+");return n}")(t,b.frag)}function j(a){a||(a=b);var d=f(a);return!t.shivCSS||k||d.hasCSS||(d.hasCSS=!!c(a,"article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}mark{background:#FF0;color:#000}template{display:none}")),l||i(a,d),a}var k,l,m="3.7.3-pre",n=a.html5||{},o=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,p=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,q="_html5shiv",r=0,s={};!function(){try{var a=b.createElement("a");a.innerHTML="<xyz></xyz>",k="hidden"in a,l=1==a.childNodes.length||function(){b.createElement("a");var a=b.createDocumentFragment();return"undefined"==typeof a.cloneNode||"undefined"==typeof a.createDocumentFragment||"undefined"==typeof a.createElement}()}catch(c){k=!0,l=!0}}();var t={elements:n.elements||"abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output picture progress section summary template time video",version:m,shivCSS:n.shivCSS!==!1,supportsUnknownElements:l,shivMethods:n.shivMethods!==!1,type:"default",shivDocument:j,createElement:g,createDocumentFragment:h,addElements:e};a.html5=t,j(b),"object"==typeof module&&module.exports&&(module.exports=t)}("undefined"!=typeof window?window:this,document);
|
!function(a,b){function c(a,b){var c=a.createElement("p"),d=a.getElementsByTagName("head")[0]||a.documentElement;return c.innerHTML="x<style>"+b+"</style>",d.insertBefore(c.lastChild,d.firstChild)}function d(){var a=t.elements;return"string"==typeof a?a.split(" "):a}function e(a,b){var c=t.elements;"string"!=typeof c&&(c=c.join(" ")),"string"!=typeof a&&(a=a.join(" ")),t.elements=c+" "+a,j(b)}function f(a){var b=s[a[q]];return b||(b={},r++,a[q]=r,s[r]=b),b}function g(a,c,d){if(c||(c=b),l)return c.createElement(a);d||(d=f(c));var e;return e=d.cache[a]?d.cache[a].cloneNode():p.test(a)?(d.cache[a]=d.createElem(a)).cloneNode():d.createElem(a),!e.canHaveChildren||o.test(a)||e.tagUrn?e:d.frag.appendChild(e)}function h(a,c){if(a||(a=b),l)return a.createDocumentFragment();c=c||f(a);for(var e=c.frag.cloneNode(),g=0,h=d(),i=h.length;i>g;g++)e.createElement(h[g]);return e}function i(a,b){b.cache||(b.cache={},b.createElem=a.createElement,b.createFrag=a.createDocumentFragment,b.frag=b.createFrag()),a.createElement=function(c){return t.shivMethods?g(c,a,b):b.createElem(c)},a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+d().join().replace(/[\w\-:]+/g,function(a){return b.createElem(a),b.frag.createElement(a),'c("'+a+'")'})+");return n}")(t,b.frag)}function j(a){a||(a=b);var d=f(a);return!t.shivCSS||k||d.hasCSS||(d.hasCSS=!!c(a,"article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}mark{background:#FF0;color:#000}template{display:none}")),l||i(a,d),a}var k,l,m="3.7.3-pre",n=a.html5||{},o=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,p=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,q="_html5shiv",r=0,s={};!function(){try{var a=b.createElement("a");a.innerHTML="<xyz></xyz>",k="hidden"in a,l=1==a.childNodes.length||function(){b.createElement("a");var a=b.createDocumentFragment();return"undefined"==typeof a.cloneNode||"undefined"==typeof a.createDocumentFragment||"undefined"==typeof a.createElement}()}catch(c){k=!0,l=!0}}();var t={elements:n.elements||"abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output picture progress section summary template time video",version:m,shivCSS:n.shivCSS!==!1,supportsUnknownElements:l,shivMethods:n.shivMethods!==!1,type:"default",shivDocument:j,createElement:g,createDocumentFragment:h,addElements:e};a.html5=t,j(b),"object"==typeof module&&module.exports&&(module.exports=t)}("undefined"!=typeof window?window:this,document);
|
||||||
|
2
docs/_static/js/theme.js
vendored
2
docs/_static/js/theme.js
vendored
@ -1 +1 @@
|
|||||||
!function(n){var e={};function t(i){if(e[i])return e[i].exports;var o=e[i]={i:i,l:!1,exports:{}};return n[i].call(o.exports,o,o.exports,t),o.l=!0,o.exports}t.m=n,t.c=e,t.d=function(n,e,i){t.o(n,e)||Object.defineProperty(n,e,{enumerable:!0,get:i})},t.r=function(n){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(n,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(n,"__esModule",{value:!0})},t.t=function(n,e){if(1&e&&(n=t(n)),8&e)return n;if(4&e&&"object"==typeof n&&n&&n.__esModule)return n;var i=Object.create(null);if(t.r(i),Object.defineProperty(i,"default",{enumerable:!0,value:n}),2&e&&"string"!=typeof n)for(var o in n)t.d(i,o,function(e){return n[e]}.bind(null,o));return i},t.n=function(n){var e=n&&n.__esModule?function(){return n.default}:function(){return n};return t.d(e,"a",e),e},t.o=function(n,e){return Object.prototype.hasOwnProperty.call(n,e)},t.p="",t(t.s=0)}([function(n,e,t){t(1),n.exports=t(3)},function(n,e,t){(function(){var e="undefined"!=typeof window?window.jQuery:t(2);n.exports.ThemeNav={navBar:null,win:null,winScroll:!1,winResize:!1,linkScroll:!1,winPosition:0,winHeight:null,docHeight:null,isRunning:!1,enable:function(n){var t=this;void 0===n&&(n=!0),t.isRunning||(t.isRunning=!0,e((function(e){t.init(e),t.reset(),t.win.on("hashchange",t.reset),n&&t.win.on("scroll",(function(){t.linkScroll||t.winScroll||(t.winScroll=!0,requestAnimationFrame((function(){t.onScroll()})))})),t.win.on("resize",(function(){t.winResize||(t.winResize=!0,requestAnimationFrame((function(){t.onResize()})))})),t.onResize()})))},enableSticky:function(){this.enable(!0)},init:function(n){n(document);var e=this;this.navBar=n("div.wy-side-scroll:first"),this.win=n(window),n(document).on("click","[data-toggle='wy-nav-top']",(function(){n("[data-toggle='wy-nav-shift']").toggleClass("shift"),n("[data-toggle='rst-versions']").toggleClass("shift")})).on("click",".wy-menu-vertical .current ul li a",(function(){var t=n(this);n("[data-toggle='wy-nav-shift']").removeClass("shift"),n("[data-toggle='rst-versions']").toggleClass("shift"),e.toggleCurrent(t),e.hashChange()})).on("click","[data-toggle='rst-current-version']",(function(){n("[data-toggle='rst-versions']").toggleClass("shift-up")})),n("table.docutils:not(.field-list,.footnote,.citation)").wrap("<div class='wy-table-responsive'></div>"),n("table.docutils.footnote").wrap("<div class='wy-table-responsive footnote'></div>"),n("table.docutils.citation").wrap("<div class='wy-table-responsive citation'></div>"),n(".wy-menu-vertical ul").not(".simple").siblings("a").each((function(){var t=n(this);expand=n('<span class="toctree-expand"></span>'),expand.on("click",(function(n){return e.toggleCurrent(t),n.stopPropagation(),!1})),t.prepend(expand)}))},reset:function(){var n=encodeURI(window.location.hash)||"#";try{var e=$(".wy-menu-vertical"),t=e.find('[href="'+n+'"]');if(0===t.length){var i=$('.document [id="'+n.substring(1)+'"]').closest("div.section");0===(t=e.find('[href="#'+i.attr("id")+'"]')).length&&(t=e.find('[href="#"]'))}t.length>0&&($(".wy-menu-vertical .current").removeClass("current"),t.addClass("current"),t.closest("li.toctree-l1").addClass("current"),t.closest("li.toctree-l1").parent().addClass("current"),t.closest("li.toctree-l1").addClass("current"),t.closest("li.toctree-l2").addClass("current"),t.closest("li.toctree-l3").addClass("current"),t.closest("li.toctree-l4").addClass("current"),t.closest("li.toctree-l5").addClass("current"),t[0].scrollIntoView())}catch(n){console.log("Error expanding nav for anchor",n)}},onScroll:function(){this.winScroll=!1;var n=this.win.scrollTop(),e=n+this.winHeight,t=this.navBar.scrollTop()+(n-this.winPosition);n<0||e>this.docHeight||(this.navBar.scrollTop(t),this.winPosition=n)},onResize:function(){this.winResize=!1,this.winHeight=this.win.height(),this.docHeight=$(document).height()},hashChange:function(){this.linkScroll=!0,this.win.one("hashchange",(function(){this.linkScroll=!1}))},toggleCurrent:function(n){var e=n.closest("li");e.siblings("li.current").removeClass("current"),e.siblings().find("li.current").removeClass("current"),e.find("> ul li.current").removeClass("current"),e.toggleClass("current")}},"undefined"!=typeof window&&(window.SphinxRtdTheme={Navigation:n.exports.ThemeNav,StickyNav:n.exports.ThemeNav}),function(){for(var n=0,e=["ms","moz","webkit","o"],t=0;t<e.length&&!window.requestAnimationFrame;++t)window.requestAnimationFrame=window[e[t]+"RequestAnimationFrame"],window.cancelAnimationFrame=window[e[t]+"CancelAnimationFrame"]||window[e[t]+"CancelRequestAnimationFrame"];window.requestAnimationFrame||(window.requestAnimationFrame=function(e,t){var i=(new Date).getTime(),o=Math.max(0,16-(i-n)),r=window.setTimeout((function(){e(i+o)}),o);return n=i+o,r}),window.cancelAnimationFrame||(window.cancelAnimationFrame=function(n){clearTimeout(n)})}()}).call(window)},function(n,e){n.exports=jQuery},function(n,e,t){}]);
|
!function(n){var e={};function t(i){if(e[i])return e[i].exports;var o=e[i]={i:i,l:!1,exports:{}};return n[i].call(o.exports,o,o.exports,t),o.l=!0,o.exports}t.m=n,t.c=e,t.d=function(n,e,i){t.o(n,e)||Object.defineProperty(n,e,{enumerable:!0,get:i})},t.r=function(n){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(n,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(n,"__esModule",{value:!0})},t.t=function(n,e){if(1&e&&(n=t(n)),8&e)return n;if(4&e&&"object"==typeof n&&n&&n.__esModule)return n;var i=Object.create(null);if(t.r(i),Object.defineProperty(i,"default",{enumerable:!0,value:n}),2&e&&"string"!=typeof n)for(var o in n)t.d(i,o,function(e){return n[e]}.bind(null,o));return i},t.n=function(n){var e=n&&n.__esModule?function(){return n.default}:function(){return n};return t.d(e,"a",e),e},t.o=function(n,e){return Object.prototype.hasOwnProperty.call(n,e)},t.p="",t(t.s=0)}([function(n,e,t){t(1),n.exports=t(3)},function(n,e,t){(function(){var e="undefined"!=typeof window?window.jQuery:t(2);n.exports.ThemeNav={navBar:null,win:null,winScroll:!1,winResize:!1,linkScroll:!1,winPosition:0,winHeight:null,docHeight:null,isRunning:!1,enable:function(n){var t=this;void 0===n&&(n=!0),t.isRunning||(t.isRunning=!0,e((function(e){t.init(e),t.reset(),t.win.on("hashchange",t.reset),n&&t.win.on("scroll",(function(){t.linkScroll||t.winScroll||(t.winScroll=!0,requestAnimationFrame((function(){t.onScroll()})))})),t.win.on("resize",(function(){t.winResize||(t.winResize=!0,requestAnimationFrame((function(){t.onResize()})))})),t.onResize()})))},enableSticky:function(){this.enable(!0)},init:function(n){n(document);var e=this;this.navBar=n("div.wy-side-scroll:first"),this.win=n(window),n(document).on("click","[data-toggle='wy-nav-top']",(function(){n("[data-toggle='wy-nav-shift']").toggleClass("shift"),n("[data-toggle='rst-versions']").toggleClass("shift")})).on("click",".wy-menu-vertical .current ul li a",(function(){var t=n(this);n("[data-toggle='wy-nav-shift']").removeClass("shift"),n("[data-toggle='rst-versions']").toggleClass("shift"),e.toggleCurrent(t),e.hashChange()})).on("click","[data-toggle='rst-current-version']",(function(){n("[data-toggle='rst-versions']").toggleClass("shift-up")})),n("table.docutils:not(.field-list,.footnote,.citation)").wrap("<div class='wy-table-responsive'></div>"),n("table.docutils.footnote").wrap("<div class='wy-table-responsive footnote'></div>"),n("table.docutils.citation").wrap("<div class='wy-table-responsive citation'></div>"),n(".wy-menu-vertical ul").not(".simple").siblings("a").each((function(){var t=n(this);expand=n('<span class="toctree-expand"></span>'),expand.on("click",(function(n){return e.toggleCurrent(t),n.stopPropagation(),!1})),t.prepend(expand)}))},reset:function(){var n=encodeURI(window.location.hash)||"#";try{var e=$(".wy-menu-vertical"),t=e.find('[href="'+n+'"]');if(0===t.length){var i=$('.document [id="'+n.substring(1)+'"]').closest("div.section");0===(t=e.find('[href="#'+i.attr("id")+'"]')).length&&(t=e.find('[href="#"]'))}t.length>0&&($(".wy-menu-vertical .current").removeClass("current"),t.addClass("current"),t.closest("li.toctree-l1").addClass("current"),t.closest("li.toctree-l1").parent().addClass("current"),t.closest("li.toctree-l1").addClass("current"),t.closest("li.toctree-l2").addClass("current"),t.closest("li.toctree-l3").addClass("current"),t.closest("li.toctree-l4").addClass("current"),t.closest("li.toctree-l5").addClass("current"),t[0].scrollIntoView())}catch(n){console.log("Error expanding nav for anchor",n)}},onScroll:function(){this.winScroll=!1;var n=this.win.scrollTop(),e=n+this.winHeight,t=this.navBar.scrollTop()+(n-this.winPosition);n<0||e>this.docHeight||(this.navBar.scrollTop(t),this.winPosition=n)},onResize:function(){this.winResize=!1,this.winHeight=this.win.height(),this.docHeight=$(document).height()},hashChange:function(){this.linkScroll=!0,this.win.one("hashchange",(function(){this.linkScroll=!1}))},toggleCurrent:function(n){var e=n.closest("li");e.siblings("li.current").removeClass("current"),e.siblings().find("li.current").removeClass("current"),e.find("> ul li.current").removeClass("current"),e.toggleClass("current")}},"undefined"!=typeof window&&(window.SphinxRtdTheme={Navigation:n.exports.ThemeNav,StickyNav:n.exports.ThemeNav}),function(){for(var n=0,e=["ms","moz","webkit","o"],t=0;t<e.length&&!window.requestAnimationFrame;++t)window.requestAnimationFrame=window[e[t]+"RequestAnimationFrame"],window.cancelAnimationFrame=window[e[t]+"CancelAnimationFrame"]||window[e[t]+"CancelRequestAnimationFrame"];window.requestAnimationFrame||(window.requestAnimationFrame=function(e,t){var i=(new Date).getTime(),o=Math.max(0,16-(i-n)),r=window.setTimeout((function(){e(i+o)}),o);return n=i+o,r}),window.cancelAnimationFrame||(window.cancelAnimationFrame=function(n){clearTimeout(n)})}()}).call(window)},function(n,e){n.exports=jQuery},function(n,e,t){}]);
|
||||||
|
4
docs/_static/language_data.js
vendored
4
docs/_static/language_data.js
vendored
@ -13,7 +13,7 @@
|
|||||||
var stopwords = ["a","and","are","as","at","be","but","by","for","if","in","into","is","it","near","no","not","of","on","or","such","that","the","their","then","there","these","they","this","to","was","will","with"];
|
var stopwords = ["a","and","are","as","at","be","but","by","for","if","in","into","is","it","near","no","not","of","on","or","such","that","the","their","then","there","these","they","this","to","was","will","with"];
|
||||||
|
|
||||||
|
|
||||||
/* Non-minified version JS is _stemmer.js if file is provided */
|
/* Non-minified version JS is _stemmer.js if file is provided */
|
||||||
/**
|
/**
|
||||||
* Porter Stemmer
|
* Porter Stemmer
|
||||||
*/
|
*/
|
||||||
@ -293,5 +293,3 @@ function splitQuery(query) {
|
|||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
2
docs/_static/pygments.css
vendored
2
docs/_static/pygments.css
vendored
@ -71,4 +71,4 @@ span.linenos.special { color: #000000; background-color: #ffffc0; padding-left:
|
|||||||
.highlight .vg { color: #bb60d5 } /* Name.Variable.Global */
|
.highlight .vg { color: #bb60d5 } /* Name.Variable.Global */
|
||||||
.highlight .vi { color: #bb60d5 } /* Name.Variable.Instance */
|
.highlight .vi { color: #bb60d5 } /* Name.Variable.Instance */
|
||||||
.highlight .vm { color: #bb60d5 } /* Name.Variable.Magic */
|
.highlight .vm { color: #bb60d5 } /* Name.Variable.Magic */
|
||||||
.highlight .il { color: #208050 } /* Literal.Number.Integer.Long */
|
.highlight .il { color: #208050 } /* Literal.Number.Integer.Long */
|
||||||
|
@ -9,75 +9,75 @@
|
|||||||
<meta content="Documentation, TISBackup, configuration, backup jobs" name="keywords" />
|
<meta content="Documentation, TISBackup, configuration, backup jobs" name="keywords" />
|
||||||
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
|
||||||
<title>Configuring the backup jobs — TISBackup 1.8.2 documentation</title>
|
|
||||||
|
|
||||||
|
|
||||||
|
<title>Configuring the backup jobs — TISBackup 1.8.2 documentation</title>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<link rel="stylesheet" href="_static/css/theme.css" type="text/css" />
|
<link rel="stylesheet" href="_static/css/theme.css" type="text/css" />
|
||||||
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
|
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
|
||||||
<link rel="stylesheet" href="_static/css/custom.css" type="text/css" />
|
<link rel="stylesheet" href="_static/css/custom.css" type="text/css" />
|
||||||
<link rel="stylesheet" href="_static/css/ribbon.css" type="text/css" />
|
<link rel="stylesheet" href="_static/css/ribbon.css" type="text/css" />
|
||||||
<link rel="stylesheet" href="_static/theme_overrides.css" type="text/css" />
|
<link rel="stylesheet" href="_static/theme_overrides.css" type="text/css" />
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<link rel="shortcut icon" href="_static/favicon.ico"/>
|
<link rel="shortcut icon" href="_static/favicon.ico"/>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<!--[if lt IE 9]>
|
<!--[if lt IE 9]>
|
||||||
<script src="_static/js/html5shiv.min.js"></script>
|
<script src="_static/js/html5shiv.min.js"></script>
|
||||||
<![endif]-->
|
<![endif]-->
|
||||||
|
|
||||||
|
|
||||||
<script type="text/javascript" id="documentation_options" data-url_root="./" src="_static/documentation_options.js"></script>
|
<script type="text/javascript" id="documentation_options" data-url_root="./" src="_static/documentation_options.js"></script>
|
||||||
<script src="_static/jquery.js"></script>
|
<script src="_static/jquery.js"></script>
|
||||||
<script src="_static/underscore.js"></script>
|
<script src="_static/underscore.js"></script>
|
||||||
<script src="_static/doctools.js"></script>
|
<script src="_static/doctools.js"></script>
|
||||||
<script src="_static/language_data.js"></script>
|
<script src="_static/language_data.js"></script>
|
||||||
|
|
||||||
<script type="text/javascript" src="_static/js/theme.js"></script>
|
<script type="text/javascript" src="_static/js/theme.js"></script>
|
||||||
|
|
||||||
|
|
||||||
<link rel="index" title="Index" href="genindex.html" />
|
<link rel="index" title="Index" href="genindex.html" />
|
||||||
<link rel="search" title="Search" href="search.html" />
|
<link rel="search" title="Search" href="search.html" />
|
||||||
<link rel="next" title="Using TISBackup" href="using_tisbackup.html" />
|
<link rel="next" title="Using TISBackup" href="using_tisbackup.html" />
|
||||||
<link rel="prev" title="Installing and configuring TISBackup on Debian" href="installing_tisbackup.html" />
|
<link rel="prev" title="Installing and configuring TISBackup on Debian" href="installing_tisbackup.html" />
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body class="wy-body-for-nav">
|
<body class="wy-body-for-nav">
|
||||||
|
|
||||||
|
|
||||||
<div class="wy-grid-for-nav">
|
<div class="wy-grid-for-nav">
|
||||||
|
|
||||||
<nav data-toggle="wy-nav-shift" class="wy-nav-side">
|
<nav data-toggle="wy-nav-shift" class="wy-nav-side">
|
||||||
<div class="wy-side-scroll">
|
<div class="wy-side-scroll">
|
||||||
<div class="wy-side-nav-search" >
|
<div class="wy-side-nav-search" >
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<a href="index.html" class="icon icon-home"> TISBackup
|
<a href="index.html" class="icon icon-home"> TISBackup
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<div class="version">
|
<div class="version">
|
||||||
1.8
|
1.8
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<div role="search">
|
<div role="search">
|
||||||
<form id="rtd-search-form" class="wy-form" action="search.html" method="get">
|
<form id="rtd-search-form" class="wy-form" action="search.html" method="get">
|
||||||
<input type="text" name="q" placeholder="Search docs" />
|
<input type="text" name="q" placeholder="Search docs" />
|
||||||
@ -86,17 +86,17 @@
|
|||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="main navigation">
|
<div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="main navigation">
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<p><span class="caption-text">Presenting TISBackup</span></p>
|
<p><span class="caption-text">Presenting TISBackup</span></p>
|
||||||
<ul class="current">
|
<ul class="current">
|
||||||
<li class="toctree-l1"><a class="reference internal" href="presenting_tisbackup.html">Technical background for TISBackup</a></li>
|
<li class="toctree-l1"><a class="reference internal" href="presenting_tisbackup.html">Technical background for TISBackup</a></li>
|
||||||
@ -125,29 +125,29 @@
|
|||||||
<li class="toctree-l1"><a class="reference internal" href="screenshots.html">Screenshots of TISBackup</a></li>
|
<li class="toctree-l1"><a class="reference internal" href="screenshots.html">Screenshots of TISBackup</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
<section data-toggle="wy-nav-shift" class="wy-nav-content-wrap">
|
<section data-toggle="wy-nav-shift" class="wy-nav-content-wrap">
|
||||||
|
|
||||||
|
|
||||||
<nav class="wy-nav-top" aria-label="top navigation">
|
<nav class="wy-nav-top" aria-label="top navigation">
|
||||||
|
|
||||||
<i data-toggle="wy-nav-top" class="fa fa-bars"></i>
|
<i data-toggle="wy-nav-top" class="fa fa-bars"></i>
|
||||||
<a href="index.html">TISBackup</a>
|
<a href="index.html">TISBackup</a>
|
||||||
|
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
|
|
||||||
<div class="wy-nav-content">
|
<div class="wy-nav-content">
|
||||||
|
|
||||||
<div class="rst-content">
|
<div class="rst-content">
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -168,28 +168,28 @@
|
|||||||
<div role="navigation" aria-label="breadcrumbs navigation">
|
<div role="navigation" aria-label="breadcrumbs navigation">
|
||||||
|
|
||||||
<ul class="wy-breadcrumbs">
|
<ul class="wy-breadcrumbs">
|
||||||
|
|
||||||
<li><a href="index.html" class="icon icon-home"></a> »</li>
|
<li><a href="index.html" class="icon icon-home"></a> »</li>
|
||||||
|
|
||||||
<li>Configuring the backup jobs</li>
|
<li>Configuring the backup jobs</li>
|
||||||
|
|
||||||
|
|
||||||
<li class="wy-breadcrumbs-aside">
|
<li class="wy-breadcrumbs-aside">
|
||||||
|
|
||||||
|
|
||||||
<a href="_sources/configuring_tisbackup.rst.txt" rel="nofollow"> View page source</a>
|
<a href="_sources/configuring_tisbackup.rst.txt" rel="nofollow"> View page source</a>
|
||||||
|
|
||||||
|
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
|
||||||
<hr/>
|
<hr/>
|
||||||
</div>
|
</div>
|
||||||
<div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article">
|
<div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article">
|
||||||
<div itemprop="articleBody">
|
<div itemprop="articleBody">
|
||||||
|
|
||||||
<section id="configuring-the-backup-jobs">
|
<section id="configuring-the-backup-jobs">
|
||||||
<h1>Configuring the backup jobs<a class="headerlink" href="#configuring-the-backup-jobs" title="Permalink to this headline">¶</a></h1>
|
<h1>Configuring the backup jobs<a class="headerlink" href="#configuring-the-backup-jobs" title="Permalink to this headline">¶</a></h1>
|
||||||
<p id="configuring-backup-jobs">The configuration of the backups is done in an <em class="mimetype">.ini</em> file,
|
<p id="configuring-backup-jobs">The configuration of the backups is done in an <em class="mimetype">.ini</em> file,
|
||||||
@ -440,7 +440,7 @@ with read-write access only for it.</p>
|
|||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<footer>
|
<footer>
|
||||||
<div class="rst-footer-buttons" role="navigation" aria-label="footer navigation">
|
<div class="rst-footer-buttons" role="navigation" aria-label="footer navigation">
|
||||||
@ -456,14 +456,14 @@ with read-write access only for it.</p>
|
|||||||
|
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a
|
Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a
|
||||||
|
|
||||||
<a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a>
|
<a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a>
|
||||||
|
|
||||||
provided by <a href="https://readthedocs.org">Read the Docs</a>.
|
provided by <a href="https://readthedocs.org">Read the Docs</a>.
|
||||||
|
|
||||||
</footer>
|
</footer>
|
||||||
</div>
|
</div>
|
||||||
@ -472,7 +472,7 @@ with read-write access only for it.</p>
|
|||||||
</section>
|
</section>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
jQuery(function () {
|
jQuery(function () {
|
||||||
@ -480,11 +480,11 @@ with read-write access only for it.</p>
|
|||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Global site tag (gtag.js) - Google Analytics -->
|
<!-- Global site tag (gtag.js) - Google Analytics -->
|
||||||
<script async src="https://www.googletagmanager.com/gtag/js?id=UA-89790248-2"></script>
|
<script async src="https://www.googletagmanager.com/gtag/js?id=UA-89790248-2"></script>
|
||||||
@ -499,4 +499,4 @@ gtag('config', 'UA-89790248-2');
|
|||||||
|
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
@ -5,75 +5,75 @@
|
|||||||
<html class="writer-html5" lang="en" >
|
<html class="writer-html5" lang="en" >
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
||||||
|
|
||||||
<title>Index — TISBackup 1.8.2 documentation</title>
|
|
||||||
|
|
||||||
|
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
|
||||||
|
<title>Index — TISBackup 1.8.2 documentation</title>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<link rel="stylesheet" href="_static/css/theme.css" type="text/css" />
|
<link rel="stylesheet" href="_static/css/theme.css" type="text/css" />
|
||||||
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
|
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
|
||||||
<link rel="stylesheet" href="_static/css/custom.css" type="text/css" />
|
<link rel="stylesheet" href="_static/css/custom.css" type="text/css" />
|
||||||
<link rel="stylesheet" href="_static/css/ribbon.css" type="text/css" />
|
<link rel="stylesheet" href="_static/css/ribbon.css" type="text/css" />
|
||||||
<link rel="stylesheet" href="_static/theme_overrides.css" type="text/css" />
|
<link rel="stylesheet" href="_static/theme_overrides.css" type="text/css" />
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<link rel="shortcut icon" href="_static/favicon.ico"/>
|
<link rel="shortcut icon" href="_static/favicon.ico"/>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<!--[if lt IE 9]>
|
<!--[if lt IE 9]>
|
||||||
<script src="_static/js/html5shiv.min.js"></script>
|
<script src="_static/js/html5shiv.min.js"></script>
|
||||||
<![endif]-->
|
<![endif]-->
|
||||||
|
|
||||||
|
|
||||||
<script type="text/javascript" id="documentation_options" data-url_root="./" src="_static/documentation_options.js"></script>
|
<script type="text/javascript" id="documentation_options" data-url_root="./" src="_static/documentation_options.js"></script>
|
||||||
<script src="_static/jquery.js"></script>
|
<script src="_static/jquery.js"></script>
|
||||||
<script src="_static/underscore.js"></script>
|
<script src="_static/underscore.js"></script>
|
||||||
<script src="_static/doctools.js"></script>
|
<script src="_static/doctools.js"></script>
|
||||||
<script src="_static/language_data.js"></script>
|
<script src="_static/language_data.js"></script>
|
||||||
|
|
||||||
<script type="text/javascript" src="_static/js/theme.js"></script>
|
<script type="text/javascript" src="_static/js/theme.js"></script>
|
||||||
|
|
||||||
|
|
||||||
<link rel="index" title="Index" href="#" />
|
<link rel="index" title="Index" href="#" />
|
||||||
<link rel="search" title="Search" href="search.html" />
|
<link rel="search" title="Search" href="search.html" />
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body class="wy-body-for-nav">
|
<body class="wy-body-for-nav">
|
||||||
|
|
||||||
|
|
||||||
<div class="wy-grid-for-nav">
|
<div class="wy-grid-for-nav">
|
||||||
|
|
||||||
<nav data-toggle="wy-nav-shift" class="wy-nav-side">
|
<nav data-toggle="wy-nav-shift" class="wy-nav-side">
|
||||||
<div class="wy-side-scroll">
|
<div class="wy-side-scroll">
|
||||||
<div class="wy-side-nav-search" >
|
<div class="wy-side-nav-search" >
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<a href="index.html" class="icon icon-home"> TISBackup
|
<a href="index.html" class="icon icon-home"> TISBackup
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<div class="version">
|
<div class="version">
|
||||||
1.8
|
1.8
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<div role="search">
|
<div role="search">
|
||||||
<form id="rtd-search-form" class="wy-form" action="search.html" method="get">
|
<form id="rtd-search-form" class="wy-form" action="search.html" method="get">
|
||||||
<input type="text" name="q" placeholder="Search docs" />
|
<input type="text" name="q" placeholder="Search docs" />
|
||||||
@ -82,17 +82,17 @@
|
|||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="main navigation">
|
<div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="main navigation">
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<p><span class="caption-text">Presenting TISBackup</span></p>
|
<p><span class="caption-text">Presenting TISBackup</span></p>
|
||||||
<ul>
|
<ul>
|
||||||
<li class="toctree-l1"><a class="reference internal" href="presenting_tisbackup.html">Technical background for TISBackup</a></li>
|
<li class="toctree-l1"><a class="reference internal" href="presenting_tisbackup.html">Technical background for TISBackup</a></li>
|
||||||
@ -106,29 +106,29 @@
|
|||||||
<li class="toctree-l1"><a class="reference internal" href="screenshots.html">Screenshots of TISBackup</a></li>
|
<li class="toctree-l1"><a class="reference internal" href="screenshots.html">Screenshots of TISBackup</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
<section data-toggle="wy-nav-shift" class="wy-nav-content-wrap">
|
<section data-toggle="wy-nav-shift" class="wy-nav-content-wrap">
|
||||||
|
|
||||||
|
|
||||||
<nav class="wy-nav-top" aria-label="top navigation">
|
<nav class="wy-nav-top" aria-label="top navigation">
|
||||||
|
|
||||||
<i data-toggle="wy-nav-top" class="fa fa-bars"></i>
|
<i data-toggle="wy-nav-top" class="fa fa-bars"></i>
|
||||||
<a href="index.html">TISBackup</a>
|
<a href="index.html">TISBackup</a>
|
||||||
|
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
|
|
||||||
<div class="wy-nav-content">
|
<div class="wy-nav-content">
|
||||||
|
|
||||||
<div class="rst-content">
|
<div class="rst-content">
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -149,36 +149,36 @@
|
|||||||
<div role="navigation" aria-label="breadcrumbs navigation">
|
<div role="navigation" aria-label="breadcrumbs navigation">
|
||||||
|
|
||||||
<ul class="wy-breadcrumbs">
|
<ul class="wy-breadcrumbs">
|
||||||
|
|
||||||
<li><a href="index.html" class="icon icon-home"></a> »</li>
|
<li><a href="index.html" class="icon icon-home"></a> »</li>
|
||||||
|
|
||||||
<li>Index</li>
|
<li>Index</li>
|
||||||
|
|
||||||
|
|
||||||
<li class="wy-breadcrumbs-aside">
|
<li class="wy-breadcrumbs-aside">
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
|
||||||
<hr/>
|
<hr/>
|
||||||
</div>
|
</div>
|
||||||
<div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article">
|
<div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article">
|
||||||
<div itemprop="articleBody">
|
<div itemprop="articleBody">
|
||||||
|
|
||||||
|
|
||||||
<h1 id="index">Index</h1>
|
<h1 id="index">Index</h1>
|
||||||
|
|
||||||
<div class="genindex-jumpbox">
|
<div class="genindex-jumpbox">
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<footer>
|
<footer>
|
||||||
|
|
||||||
@ -190,14 +190,14 @@
|
|||||||
|
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a
|
Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a
|
||||||
|
|
||||||
<a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a>
|
<a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a>
|
||||||
|
|
||||||
provided by <a href="https://readthedocs.org">Read the Docs</a>.
|
provided by <a href="https://readthedocs.org">Read the Docs</a>.
|
||||||
|
|
||||||
</footer>
|
</footer>
|
||||||
</div>
|
</div>
|
||||||
@ -206,7 +206,7 @@
|
|||||||
</section>
|
</section>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
jQuery(function () {
|
jQuery(function () {
|
||||||
@ -214,11 +214,11 @@
|
|||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Global site tag (gtag.js) - Google Analytics -->
|
<!-- Global site tag (gtag.js) - Google Analytics -->
|
||||||
<script async src="https://www.googletagmanager.com/gtag/js?id=UA-89790248-2"></script>
|
<script async src="https://www.googletagmanager.com/gtag/js?id=UA-89790248-2"></script>
|
||||||
@ -233,4 +233,4 @@ gtag('config', 'UA-89790248-2');
|
|||||||
|
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
140
docs/index.html
140
docs/index.html
@ -9,74 +9,74 @@
|
|||||||
<meta content="Documentation, TISBackup, introduction, welcome page, Welcome" name="keywords" />
|
<meta content="Documentation, TISBackup, introduction, welcome page, Welcome" name="keywords" />
|
||||||
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
|
||||||
<title>Presenting TISBackup — TISBackup 1.8.2 documentation</title>
|
|
||||||
|
|
||||||
|
|
||||||
|
<title>Presenting TISBackup — TISBackup 1.8.2 documentation</title>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<link rel="stylesheet" href="_static/css/theme.css" type="text/css" />
|
<link rel="stylesheet" href="_static/css/theme.css" type="text/css" />
|
||||||
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
|
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
|
||||||
<link rel="stylesheet" href="_static/css/custom.css" type="text/css" />
|
<link rel="stylesheet" href="_static/css/custom.css" type="text/css" />
|
||||||
<link rel="stylesheet" href="_static/css/ribbon.css" type="text/css" />
|
<link rel="stylesheet" href="_static/css/ribbon.css" type="text/css" />
|
||||||
<link rel="stylesheet" href="_static/theme_overrides.css" type="text/css" />
|
<link rel="stylesheet" href="_static/theme_overrides.css" type="text/css" />
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<link rel="shortcut icon" href="_static/favicon.ico"/>
|
<link rel="shortcut icon" href="_static/favicon.ico"/>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<!--[if lt IE 9]>
|
<!--[if lt IE 9]>
|
||||||
<script src="_static/js/html5shiv.min.js"></script>
|
<script src="_static/js/html5shiv.min.js"></script>
|
||||||
<![endif]-->
|
<![endif]-->
|
||||||
|
|
||||||
|
|
||||||
<script type="text/javascript" id="documentation_options" data-url_root="./" src="_static/documentation_options.js"></script>
|
<script type="text/javascript" id="documentation_options" data-url_root="./" src="_static/documentation_options.js"></script>
|
||||||
<script src="_static/jquery.js"></script>
|
<script src="_static/jquery.js"></script>
|
||||||
<script src="_static/underscore.js"></script>
|
<script src="_static/underscore.js"></script>
|
||||||
<script src="_static/doctools.js"></script>
|
<script src="_static/doctools.js"></script>
|
||||||
<script src="_static/language_data.js"></script>
|
<script src="_static/language_data.js"></script>
|
||||||
|
|
||||||
<script type="text/javascript" src="_static/js/theme.js"></script>
|
<script type="text/javascript" src="_static/js/theme.js"></script>
|
||||||
|
|
||||||
|
|
||||||
<link rel="index" title="Index" href="genindex.html" />
|
<link rel="index" title="Index" href="genindex.html" />
|
||||||
<link rel="search" title="Search" href="search.html" />
|
<link rel="search" title="Search" href="search.html" />
|
||||||
<link rel="next" title="Technical background for TISBackup" href="presenting_tisbackup.html" />
|
<link rel="next" title="Technical background for TISBackup" href="presenting_tisbackup.html" />
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body class="wy-body-for-nav">
|
<body class="wy-body-for-nav">
|
||||||
|
|
||||||
|
|
||||||
<div class="wy-grid-for-nav">
|
<div class="wy-grid-for-nav">
|
||||||
|
|
||||||
<nav data-toggle="wy-nav-shift" class="wy-nav-side">
|
<nav data-toggle="wy-nav-shift" class="wy-nav-side">
|
||||||
<div class="wy-side-scroll">
|
<div class="wy-side-scroll">
|
||||||
<div class="wy-side-nav-search" >
|
<div class="wy-side-nav-search" >
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<a href="#" class="icon icon-home"> TISBackup
|
<a href="#" class="icon icon-home"> TISBackup
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<div class="version">
|
<div class="version">
|
||||||
1.8
|
1.8
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<div role="search">
|
<div role="search">
|
||||||
<form id="rtd-search-form" class="wy-form" action="search.html" method="get">
|
<form id="rtd-search-form" class="wy-form" action="search.html" method="get">
|
||||||
<input type="text" name="q" placeholder="Search docs" />
|
<input type="text" name="q" placeholder="Search docs" />
|
||||||
@ -85,17 +85,17 @@
|
|||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="main navigation">
|
<div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="main navigation">
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<p><span class="caption-text">Presenting TISBackup</span></p>
|
<p><span class="caption-text">Presenting TISBackup</span></p>
|
||||||
<ul>
|
<ul>
|
||||||
<li class="toctree-l1"><a class="reference internal" href="presenting_tisbackup.html">Technical background for TISBackup</a></li>
|
<li class="toctree-l1"><a class="reference internal" href="presenting_tisbackup.html">Technical background for TISBackup</a></li>
|
||||||
@ -109,29 +109,29 @@
|
|||||||
<li class="toctree-l1"><a class="reference internal" href="screenshots.html">Screenshots of TISBackup</a></li>
|
<li class="toctree-l1"><a class="reference internal" href="screenshots.html">Screenshots of TISBackup</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
<section data-toggle="wy-nav-shift" class="wy-nav-content-wrap">
|
<section data-toggle="wy-nav-shift" class="wy-nav-content-wrap">
|
||||||
|
|
||||||
|
|
||||||
<nav class="wy-nav-top" aria-label="top navigation">
|
<nav class="wy-nav-top" aria-label="top navigation">
|
||||||
|
|
||||||
<i data-toggle="wy-nav-top" class="fa fa-bars"></i>
|
<i data-toggle="wy-nav-top" class="fa fa-bars"></i>
|
||||||
<a href="#">TISBackup</a>
|
<a href="#">TISBackup</a>
|
||||||
|
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
|
|
||||||
<div class="wy-nav-content">
|
<div class="wy-nav-content">
|
||||||
|
|
||||||
<div class="rst-content">
|
<div class="rst-content">
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -152,28 +152,28 @@
|
|||||||
<div role="navigation" aria-label="breadcrumbs navigation">
|
<div role="navigation" aria-label="breadcrumbs navigation">
|
||||||
|
|
||||||
<ul class="wy-breadcrumbs">
|
<ul class="wy-breadcrumbs">
|
||||||
|
|
||||||
<li><a href="#" class="icon icon-home"></a> »</li>
|
<li><a href="#" class="icon icon-home"></a> »</li>
|
||||||
|
|
||||||
<li>Presenting TISBackup</li>
|
<li>Presenting TISBackup</li>
|
||||||
|
|
||||||
|
|
||||||
<li class="wy-breadcrumbs-aside">
|
<li class="wy-breadcrumbs-aside">
|
||||||
|
|
||||||
|
|
||||||
<a href="_sources/index.rst.txt" rel="nofollow"> View page source</a>
|
<a href="_sources/index.rst.txt" rel="nofollow"> View page source</a>
|
||||||
|
|
||||||
|
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
|
||||||
<hr/>
|
<hr/>
|
||||||
</div>
|
</div>
|
||||||
<div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article">
|
<div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article">
|
||||||
<div itemprop="articleBody">
|
<div itemprop="articleBody">
|
||||||
|
|
||||||
<figure class="align-center">
|
<figure class="align-center">
|
||||||
<a class="reference internal image-reference" href="_images/tisbackup_logo.png"><img alt="TISBackup Logo" src="_images/tisbackup_logo.png" style="width: 700.0px; height: 206.0px;" /></a>
|
<a class="reference internal image-reference" href="_images/tisbackup_logo.png"><img alt="TISBackup Logo" src="_images/tisbackup_logo.png" style="width: 700.0px; height: 206.0px;" /></a>
|
||||||
</figure>
|
</figure>
|
||||||
@ -275,7 +275,7 @@ if there is a problem during the backup.</p></li>
|
|||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<footer>
|
<footer>
|
||||||
<div class="rst-footer-buttons" role="navigation" aria-label="footer navigation">
|
<div class="rst-footer-buttons" role="navigation" aria-label="footer navigation">
|
||||||
@ -290,14 +290,14 @@ if there is a problem during the backup.</p></li>
|
|||||||
|
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a
|
Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a
|
||||||
|
|
||||||
<a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a>
|
<a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a>
|
||||||
|
|
||||||
provided by <a href="https://readthedocs.org">Read the Docs</a>.
|
provided by <a href="https://readthedocs.org">Read the Docs</a>.
|
||||||
|
|
||||||
</footer>
|
</footer>
|
||||||
</div>
|
</div>
|
||||||
@ -306,7 +306,7 @@ if there is a problem during the backup.</p></li>
|
|||||||
</section>
|
</section>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
jQuery(function () {
|
jQuery(function () {
|
||||||
@ -314,11 +314,11 @@ if there is a problem during the backup.</p></li>
|
|||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Global site tag (gtag.js) - Google Analytics -->
|
<!-- Global site tag (gtag.js) - Google Analytics -->
|
||||||
<script async src="https://www.googletagmanager.com/gtag/js?id=UA-89790248-2"></script>
|
<script async src="https://www.googletagmanager.com/gtag/js?id=UA-89790248-2"></script>
|
||||||
@ -333,4 +333,4 @@ gtag('config', 'UA-89790248-2');
|
|||||||
|
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
@ -9,75 +9,75 @@
|
|||||||
<meta content="Documentation, TISBackup, installation, configuration" name="keywords" />
|
<meta content="Documentation, TISBackup, installation, configuration" name="keywords" />
|
||||||
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
|
||||||
<title>Installing and configuring TISBackup on Debian — TISBackup 1.8.2 documentation</title>
|
|
||||||
|
|
||||||
|
|
||||||
|
<title>Installing and configuring TISBackup on Debian — TISBackup 1.8.2 documentation</title>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<link rel="stylesheet" href="_static/css/theme.css" type="text/css" />
|
<link rel="stylesheet" href="_static/css/theme.css" type="text/css" />
|
||||||
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
|
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
|
||||||
<link rel="stylesheet" href="_static/css/custom.css" type="text/css" />
|
<link rel="stylesheet" href="_static/css/custom.css" type="text/css" />
|
||||||
<link rel="stylesheet" href="_static/css/ribbon.css" type="text/css" />
|
<link rel="stylesheet" href="_static/css/ribbon.css" type="text/css" />
|
||||||
<link rel="stylesheet" href="_static/theme_overrides.css" type="text/css" />
|
<link rel="stylesheet" href="_static/theme_overrides.css" type="text/css" />
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<link rel="shortcut icon" href="_static/favicon.ico"/>
|
<link rel="shortcut icon" href="_static/favicon.ico"/>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<!--[if lt IE 9]>
|
<!--[if lt IE 9]>
|
||||||
<script src="_static/js/html5shiv.min.js"></script>
|
<script src="_static/js/html5shiv.min.js"></script>
|
||||||
<![endif]-->
|
<![endif]-->
|
||||||
|
|
||||||
|
|
||||||
<script type="text/javascript" id="documentation_options" data-url_root="./" src="_static/documentation_options.js"></script>
|
<script type="text/javascript" id="documentation_options" data-url_root="./" src="_static/documentation_options.js"></script>
|
||||||
<script src="_static/jquery.js"></script>
|
<script src="_static/jquery.js"></script>
|
||||||
<script src="_static/underscore.js"></script>
|
<script src="_static/underscore.js"></script>
|
||||||
<script src="_static/doctools.js"></script>
|
<script src="_static/doctools.js"></script>
|
||||||
<script src="_static/language_data.js"></script>
|
<script src="_static/language_data.js"></script>
|
||||||
|
|
||||||
<script type="text/javascript" src="_static/js/theme.js"></script>
|
<script type="text/javascript" src="_static/js/theme.js"></script>
|
||||||
|
|
||||||
|
|
||||||
<link rel="index" title="Index" href="genindex.html" />
|
<link rel="index" title="Index" href="genindex.html" />
|
||||||
<link rel="search" title="Search" href="search.html" />
|
<link rel="search" title="Search" href="search.html" />
|
||||||
<link rel="next" title="Configuring the backup jobs" href="configuring_tisbackup.html" />
|
<link rel="next" title="Configuring the backup jobs" href="configuring_tisbackup.html" />
|
||||||
<link rel="prev" title="Technical background for TISBackup" href="presenting_tisbackup.html" />
|
<link rel="prev" title="Technical background for TISBackup" href="presenting_tisbackup.html" />
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body class="wy-body-for-nav">
|
<body class="wy-body-for-nav">
|
||||||
|
|
||||||
|
|
||||||
<div class="wy-grid-for-nav">
|
<div class="wy-grid-for-nav">
|
||||||
|
|
||||||
<nav data-toggle="wy-nav-shift" class="wy-nav-side">
|
<nav data-toggle="wy-nav-shift" class="wy-nav-side">
|
||||||
<div class="wy-side-scroll">
|
<div class="wy-side-scroll">
|
||||||
<div class="wy-side-nav-search" >
|
<div class="wy-side-nav-search" >
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<a href="index.html" class="icon icon-home"> TISBackup
|
<a href="index.html" class="icon icon-home"> TISBackup
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<div class="version">
|
<div class="version">
|
||||||
1.8
|
1.8
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<div role="search">
|
<div role="search">
|
||||||
<form id="rtd-search-form" class="wy-form" action="search.html" method="get">
|
<form id="rtd-search-form" class="wy-form" action="search.html" method="get">
|
||||||
<input type="text" name="q" placeholder="Search docs" />
|
<input type="text" name="q" placeholder="Search docs" />
|
||||||
@ -86,17 +86,17 @@
|
|||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="main navigation">
|
<div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="main navigation">
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<p><span class="caption-text">Presenting TISBackup</span></p>
|
<p><span class="caption-text">Presenting TISBackup</span></p>
|
||||||
<ul class="current">
|
<ul class="current">
|
||||||
<li class="toctree-l1"><a class="reference internal" href="presenting_tisbackup.html">Technical background for TISBackup</a></li>
|
<li class="toctree-l1"><a class="reference internal" href="presenting_tisbackup.html">Technical background for TISBackup</a></li>
|
||||||
@ -123,29 +123,29 @@
|
|||||||
<li class="toctree-l1"><a class="reference internal" href="screenshots.html">Screenshots of TISBackup</a></li>
|
<li class="toctree-l1"><a class="reference internal" href="screenshots.html">Screenshots of TISBackup</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
<section data-toggle="wy-nav-shift" class="wy-nav-content-wrap">
|
<section data-toggle="wy-nav-shift" class="wy-nav-content-wrap">
|
||||||
|
|
||||||
|
|
||||||
<nav class="wy-nav-top" aria-label="top navigation">
|
<nav class="wy-nav-top" aria-label="top navigation">
|
||||||
|
|
||||||
<i data-toggle="wy-nav-top" class="fa fa-bars"></i>
|
<i data-toggle="wy-nav-top" class="fa fa-bars"></i>
|
||||||
<a href="index.html">TISBackup</a>
|
<a href="index.html">TISBackup</a>
|
||||||
|
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
|
|
||||||
<div class="wy-nav-content">
|
<div class="wy-nav-content">
|
||||||
|
|
||||||
<div class="rst-content">
|
<div class="rst-content">
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -166,28 +166,28 @@
|
|||||||
<div role="navigation" aria-label="breadcrumbs navigation">
|
<div role="navigation" aria-label="breadcrumbs navigation">
|
||||||
|
|
||||||
<ul class="wy-breadcrumbs">
|
<ul class="wy-breadcrumbs">
|
||||||
|
|
||||||
<li><a href="index.html" class="icon icon-home"></a> »</li>
|
<li><a href="index.html" class="icon icon-home"></a> »</li>
|
||||||
|
|
||||||
<li>Installing and configuring TISBackup on Debian</li>
|
<li>Installing and configuring TISBackup on Debian</li>
|
||||||
|
|
||||||
|
|
||||||
<li class="wy-breadcrumbs-aside">
|
<li class="wy-breadcrumbs-aside">
|
||||||
|
|
||||||
|
|
||||||
<a href="_sources/installing_tisbackup.rst.txt" rel="nofollow"> View page source</a>
|
<a href="_sources/installing_tisbackup.rst.txt" rel="nofollow"> View page source</a>
|
||||||
|
|
||||||
|
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
|
||||||
<hr/>
|
<hr/>
|
||||||
</div>
|
</div>
|
||||||
<div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article">
|
<div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article">
|
||||||
<div itemprop="articleBody">
|
<div itemprop="articleBody">
|
||||||
|
|
||||||
<section id="installing-and-configuring-tisbackup-on-debian">
|
<section id="installing-and-configuring-tisbackup-on-debian">
|
||||||
<h1>Installing and configuring TISBackup on Debian<a class="headerlink" href="#installing-and-configuring-tisbackup-on-debian" title="Permalink to this headline">¶</a></h1>
|
<h1>Installing and configuring TISBackup on Debian<a class="headerlink" href="#installing-and-configuring-tisbackup-on-debian" title="Permalink to this headline">¶</a></h1>
|
||||||
<section id="setting-up-the-gnu-linux-debian-server">
|
<section id="setting-up-the-gnu-linux-debian-server">
|
||||||
@ -423,7 +423,7 @@ of your TISBackup server on port 8080.</p>
|
|||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<footer>
|
<footer>
|
||||||
<div class="rst-footer-buttons" role="navigation" aria-label="footer navigation">
|
<div class="rst-footer-buttons" role="navigation" aria-label="footer navigation">
|
||||||
@ -439,14 +439,14 @@ of your TISBackup server on port 8080.</p>
|
|||||||
|
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a
|
Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a
|
||||||
|
|
||||||
<a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a>
|
<a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a>
|
||||||
|
|
||||||
provided by <a href="https://readthedocs.org">Read the Docs</a>.
|
provided by <a href="https://readthedocs.org">Read the Docs</a>.
|
||||||
|
|
||||||
</footer>
|
</footer>
|
||||||
</div>
|
</div>
|
||||||
@ -455,7 +455,7 @@ of your TISBackup server on port 8080.</p>
|
|||||||
</section>
|
</section>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
jQuery(function () {
|
jQuery(function () {
|
||||||
@ -463,11 +463,11 @@ of your TISBackup server on port 8080.</p>
|
|||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Global site tag (gtag.js) - Google Analytics -->
|
<!-- Global site tag (gtag.js) - Google Analytics -->
|
||||||
<script async src="https://www.googletagmanager.com/gtag/js?id=UA-89790248-2"></script>
|
<script async src="https://www.googletagmanager.com/gtag/js?id=UA-89790248-2"></script>
|
||||||
@ -482,4 +482,4 @@ gtag('config', 'UA-89790248-2');
|
|||||||
|
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
@ -9,75 +9,75 @@
|
|||||||
<meta content="Documentation, TISBackup, technical background" name="keywords" />
|
<meta content="Documentation, TISBackup, technical background" name="keywords" />
|
||||||
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
|
||||||
<title>Technical background for TISBackup — TISBackup 1.8.2 documentation</title>
|
|
||||||
|
|
||||||
|
|
||||||
|
<title>Technical background for TISBackup — TISBackup 1.8.2 documentation</title>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<link rel="stylesheet" href="_static/css/theme.css" type="text/css" />
|
<link rel="stylesheet" href="_static/css/theme.css" type="text/css" />
|
||||||
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
|
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
|
||||||
<link rel="stylesheet" href="_static/css/custom.css" type="text/css" />
|
<link rel="stylesheet" href="_static/css/custom.css" type="text/css" />
|
||||||
<link rel="stylesheet" href="_static/css/ribbon.css" type="text/css" />
|
<link rel="stylesheet" href="_static/css/ribbon.css" type="text/css" />
|
||||||
<link rel="stylesheet" href="_static/theme_overrides.css" type="text/css" />
|
<link rel="stylesheet" href="_static/theme_overrides.css" type="text/css" />
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<link rel="shortcut icon" href="_static/favicon.ico"/>
|
<link rel="shortcut icon" href="_static/favicon.ico"/>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<!--[if lt IE 9]>
|
<!--[if lt IE 9]>
|
||||||
<script src="_static/js/html5shiv.min.js"></script>
|
<script src="_static/js/html5shiv.min.js"></script>
|
||||||
<![endif]-->
|
<![endif]-->
|
||||||
|
|
||||||
|
|
||||||
<script type="text/javascript" id="documentation_options" data-url_root="./" src="_static/documentation_options.js"></script>
|
<script type="text/javascript" id="documentation_options" data-url_root="./" src="_static/documentation_options.js"></script>
|
||||||
<script src="_static/jquery.js"></script>
|
<script src="_static/jquery.js"></script>
|
||||||
<script src="_static/underscore.js"></script>
|
<script src="_static/underscore.js"></script>
|
||||||
<script src="_static/doctools.js"></script>
|
<script src="_static/doctools.js"></script>
|
||||||
<script src="_static/language_data.js"></script>
|
<script src="_static/language_data.js"></script>
|
||||||
|
|
||||||
<script type="text/javascript" src="_static/js/theme.js"></script>
|
<script type="text/javascript" src="_static/js/theme.js"></script>
|
||||||
|
|
||||||
|
|
||||||
<link rel="index" title="Index" href="genindex.html" />
|
<link rel="index" title="Index" href="genindex.html" />
|
||||||
<link rel="search" title="Search" href="search.html" />
|
<link rel="search" title="Search" href="search.html" />
|
||||||
<link rel="next" title="Installing and configuring TISBackup on Debian" href="installing_tisbackup.html" />
|
<link rel="next" title="Installing and configuring TISBackup on Debian" href="installing_tisbackup.html" />
|
||||||
<link rel="prev" title="Presenting TISBackup" href="index.html" />
|
<link rel="prev" title="Presenting TISBackup" href="index.html" />
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body class="wy-body-for-nav">
|
<body class="wy-body-for-nav">
|
||||||
|
|
||||||
|
|
||||||
<div class="wy-grid-for-nav">
|
<div class="wy-grid-for-nav">
|
||||||
|
|
||||||
<nav data-toggle="wy-nav-shift" class="wy-nav-side">
|
<nav data-toggle="wy-nav-shift" class="wy-nav-side">
|
||||||
<div class="wy-side-scroll">
|
<div class="wy-side-scroll">
|
||||||
<div class="wy-side-nav-search" >
|
<div class="wy-side-nav-search" >
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<a href="index.html" class="icon icon-home"> TISBackup
|
<a href="index.html" class="icon icon-home"> TISBackup
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<div class="version">
|
<div class="version">
|
||||||
1.8
|
1.8
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<div role="search">
|
<div role="search">
|
||||||
<form id="rtd-search-form" class="wy-form" action="search.html" method="get">
|
<form id="rtd-search-form" class="wy-form" action="search.html" method="get">
|
||||||
<input type="text" name="q" placeholder="Search docs" />
|
<input type="text" name="q" placeholder="Search docs" />
|
||||||
@ -86,17 +86,17 @@
|
|||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="main navigation">
|
<div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="main navigation">
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<p><span class="caption-text">Presenting TISBackup</span></p>
|
<p><span class="caption-text">Presenting TISBackup</span></p>
|
||||||
<ul class="current">
|
<ul class="current">
|
||||||
<li class="toctree-l1 current"><a class="current reference internal" href="#">Technical background for TISBackup</a><ul>
|
<li class="toctree-l1 current"><a class="current reference internal" href="#">Technical background for TISBackup</a><ul>
|
||||||
@ -116,29 +116,29 @@
|
|||||||
<li class="toctree-l1"><a class="reference internal" href="screenshots.html">Screenshots of TISBackup</a></li>
|
<li class="toctree-l1"><a class="reference internal" href="screenshots.html">Screenshots of TISBackup</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
<section data-toggle="wy-nav-shift" class="wy-nav-content-wrap">
|
<section data-toggle="wy-nav-shift" class="wy-nav-content-wrap">
|
||||||
|
|
||||||
|
|
||||||
<nav class="wy-nav-top" aria-label="top navigation">
|
<nav class="wy-nav-top" aria-label="top navigation">
|
||||||
|
|
||||||
<i data-toggle="wy-nav-top" class="fa fa-bars"></i>
|
<i data-toggle="wy-nav-top" class="fa fa-bars"></i>
|
||||||
<a href="index.html">TISBackup</a>
|
<a href="index.html">TISBackup</a>
|
||||||
|
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
|
|
||||||
<div class="wy-nav-content">
|
<div class="wy-nav-content">
|
||||||
|
|
||||||
<div class="rst-content">
|
<div class="rst-content">
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -159,28 +159,28 @@
|
|||||||
<div role="navigation" aria-label="breadcrumbs navigation">
|
<div role="navigation" aria-label="breadcrumbs navigation">
|
||||||
|
|
||||||
<ul class="wy-breadcrumbs">
|
<ul class="wy-breadcrumbs">
|
||||||
|
|
||||||
<li><a href="index.html" class="icon icon-home"></a> »</li>
|
<li><a href="index.html" class="icon icon-home"></a> »</li>
|
||||||
|
|
||||||
<li>Technical background for TISBackup</li>
|
<li>Technical background for TISBackup</li>
|
||||||
|
|
||||||
|
|
||||||
<li class="wy-breadcrumbs-aside">
|
<li class="wy-breadcrumbs-aside">
|
||||||
|
|
||||||
|
|
||||||
<a href="_sources/presenting_tisbackup.rst.txt" rel="nofollow"> View page source</a>
|
<a href="_sources/presenting_tisbackup.rst.txt" rel="nofollow"> View page source</a>
|
||||||
|
|
||||||
|
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
|
||||||
<hr/>
|
<hr/>
|
||||||
</div>
|
</div>
|
||||||
<div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article">
|
<div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article">
|
||||||
<div itemprop="articleBody">
|
<div itemprop="articleBody">
|
||||||
|
|
||||||
<section id="technical-background-for-tisbackup">
|
<section id="technical-background-for-tisbackup">
|
||||||
<h1>Technical background for TISBackup<a class="headerlink" href="#technical-background-for-tisbackup" title="Permalink to this headline">¶</a></h1>
|
<h1>Technical background for TISBackup<a class="headerlink" href="#technical-background-for-tisbackup" title="Permalink to this headline">¶</a></h1>
|
||||||
<p>The deduplication of this solution is based on the hardlinks
|
<p>The deduplication of this solution is based on the hardlinks
|
||||||
@ -274,7 +274,7 @@ and <a class="reference internal" href="installing_tisbackup.html#base-debian-se
|
|||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<footer>
|
<footer>
|
||||||
<div class="rst-footer-buttons" role="navigation" aria-label="footer navigation">
|
<div class="rst-footer-buttons" role="navigation" aria-label="footer navigation">
|
||||||
@ -290,14 +290,14 @@ and <a class="reference internal" href="installing_tisbackup.html#base-debian-se
|
|||||||
|
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a
|
Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a
|
||||||
|
|
||||||
<a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a>
|
<a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a>
|
||||||
|
|
||||||
provided by <a href="https://readthedocs.org">Read the Docs</a>.
|
provided by <a href="https://readthedocs.org">Read the Docs</a>.
|
||||||
|
|
||||||
</footer>
|
</footer>
|
||||||
</div>
|
</div>
|
||||||
@ -306,7 +306,7 @@ and <a class="reference internal" href="installing_tisbackup.html#base-debian-se
|
|||||||
</section>
|
</section>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
jQuery(function () {
|
jQuery(function () {
|
||||||
@ -314,11 +314,11 @@ and <a class="reference internal" href="installing_tisbackup.html#base-debian-se
|
|||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Global site tag (gtag.js) - Google Analytics -->
|
<!-- Global site tag (gtag.js) - Google Analytics -->
|
||||||
<script async src="https://www.googletagmanager.com/gtag/js?id=UA-89790248-2"></script>
|
<script async src="https://www.googletagmanager.com/gtag/js?id=UA-89790248-2"></script>
|
||||||
@ -333,4 +333,4 @@ gtag('config', 'UA-89790248-2');
|
|||||||
|
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
@ -9,74 +9,74 @@
|
|||||||
<meta content="Documentation, TISBackup, screenshots" name="keywords" />
|
<meta content="Documentation, TISBackup, screenshots" name="keywords" />
|
||||||
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
|
||||||
<title>Screenshots of TISBackup — TISBackup 1.8.2 documentation</title>
|
|
||||||
|
|
||||||
|
|
||||||
|
<title>Screenshots of TISBackup — TISBackup 1.8.2 documentation</title>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<link rel="stylesheet" href="_static/css/theme.css" type="text/css" />
|
<link rel="stylesheet" href="_static/css/theme.css" type="text/css" />
|
||||||
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
|
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
|
||||||
<link rel="stylesheet" href="_static/css/custom.css" type="text/css" />
|
<link rel="stylesheet" href="_static/css/custom.css" type="text/css" />
|
||||||
<link rel="stylesheet" href="_static/css/ribbon.css" type="text/css" />
|
<link rel="stylesheet" href="_static/css/ribbon.css" type="text/css" />
|
||||||
<link rel="stylesheet" href="_static/theme_overrides.css" type="text/css" />
|
<link rel="stylesheet" href="_static/theme_overrides.css" type="text/css" />
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<link rel="shortcut icon" href="_static/favicon.ico"/>
|
<link rel="shortcut icon" href="_static/favicon.ico"/>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<!--[if lt IE 9]>
|
<!--[if lt IE 9]>
|
||||||
<script src="_static/js/html5shiv.min.js"></script>
|
<script src="_static/js/html5shiv.min.js"></script>
|
||||||
<![endif]-->
|
<![endif]-->
|
||||||
|
|
||||||
|
|
||||||
<script type="text/javascript" id="documentation_options" data-url_root="./" src="_static/documentation_options.js"></script>
|
<script type="text/javascript" id="documentation_options" data-url_root="./" src="_static/documentation_options.js"></script>
|
||||||
<script src="_static/jquery.js"></script>
|
<script src="_static/jquery.js"></script>
|
||||||
<script src="_static/underscore.js"></script>
|
<script src="_static/underscore.js"></script>
|
||||||
<script src="_static/doctools.js"></script>
|
<script src="_static/doctools.js"></script>
|
||||||
<script src="_static/language_data.js"></script>
|
<script src="_static/language_data.js"></script>
|
||||||
|
|
||||||
<script type="text/javascript" src="_static/js/theme.js"></script>
|
<script type="text/javascript" src="_static/js/theme.js"></script>
|
||||||
|
|
||||||
|
|
||||||
<link rel="index" title="Index" href="genindex.html" />
|
<link rel="index" title="Index" href="genindex.html" />
|
||||||
<link rel="search" title="Search" href="search.html" />
|
<link rel="search" title="Search" href="search.html" />
|
||||||
<link rel="prev" title="Contacting Tranquil IT" href="tranquil-it-contacts.html" />
|
<link rel="prev" title="Contacting Tranquil IT" href="tranquil-it-contacts.html" />
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body class="wy-body-for-nav">
|
<body class="wy-body-for-nav">
|
||||||
|
|
||||||
|
|
||||||
<div class="wy-grid-for-nav">
|
<div class="wy-grid-for-nav">
|
||||||
|
|
||||||
<nav data-toggle="wy-nav-shift" class="wy-nav-side">
|
<nav data-toggle="wy-nav-shift" class="wy-nav-side">
|
||||||
<div class="wy-side-scroll">
|
<div class="wy-side-scroll">
|
||||||
<div class="wy-side-nav-search" >
|
<div class="wy-side-nav-search" >
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<a href="index.html" class="icon icon-home"> TISBackup
|
<a href="index.html" class="icon icon-home"> TISBackup
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<div class="version">
|
<div class="version">
|
||||||
1.8
|
1.8
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<div role="search">
|
<div role="search">
|
||||||
<form id="rtd-search-form" class="wy-form" action="search.html" method="get">
|
<form id="rtd-search-form" class="wy-form" action="search.html" method="get">
|
||||||
<input type="text" name="q" placeholder="Search docs" />
|
<input type="text" name="q" placeholder="Search docs" />
|
||||||
@ -85,17 +85,17 @@
|
|||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="main navigation">
|
<div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="main navigation">
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<p><span class="caption-text">Presenting TISBackup</span></p>
|
<p><span class="caption-text">Presenting TISBackup</span></p>
|
||||||
<ul>
|
<ul>
|
||||||
<li class="toctree-l1"><a class="reference internal" href="presenting_tisbackup.html">Technical background for TISBackup</a></li>
|
<li class="toctree-l1"><a class="reference internal" href="presenting_tisbackup.html">Technical background for TISBackup</a></li>
|
||||||
@ -109,29 +109,29 @@
|
|||||||
<li class="toctree-l1 current"><a class="current reference internal" href="#">Screenshots of TISBackup</a></li>
|
<li class="toctree-l1 current"><a class="current reference internal" href="#">Screenshots of TISBackup</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
<section data-toggle="wy-nav-shift" class="wy-nav-content-wrap">
|
<section data-toggle="wy-nav-shift" class="wy-nav-content-wrap">
|
||||||
|
|
||||||
|
|
||||||
<nav class="wy-nav-top" aria-label="top navigation">
|
<nav class="wy-nav-top" aria-label="top navigation">
|
||||||
|
|
||||||
<i data-toggle="wy-nav-top" class="fa fa-bars"></i>
|
<i data-toggle="wy-nav-top" class="fa fa-bars"></i>
|
||||||
<a href="index.html">TISBackup</a>
|
<a href="index.html">TISBackup</a>
|
||||||
|
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
|
|
||||||
<div class="wy-nav-content">
|
<div class="wy-nav-content">
|
||||||
|
|
||||||
<div class="rst-content">
|
<div class="rst-content">
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -152,28 +152,28 @@
|
|||||||
<div role="navigation" aria-label="breadcrumbs navigation">
|
<div role="navigation" aria-label="breadcrumbs navigation">
|
||||||
|
|
||||||
<ul class="wy-breadcrumbs">
|
<ul class="wy-breadcrumbs">
|
||||||
|
|
||||||
<li><a href="index.html" class="icon icon-home"></a> »</li>
|
<li><a href="index.html" class="icon icon-home"></a> »</li>
|
||||||
|
|
||||||
<li>Screenshots of TISBackup</li>
|
<li>Screenshots of TISBackup</li>
|
||||||
|
|
||||||
|
|
||||||
<li class="wy-breadcrumbs-aside">
|
<li class="wy-breadcrumbs-aside">
|
||||||
|
|
||||||
|
|
||||||
<a href="_sources/screenshots.rst.txt" rel="nofollow"> View page source</a>
|
<a href="_sources/screenshots.rst.txt" rel="nofollow"> View page source</a>
|
||||||
|
|
||||||
|
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
|
||||||
<hr/>
|
<hr/>
|
||||||
</div>
|
</div>
|
||||||
<div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article">
|
<div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article">
|
||||||
<div itemprop="articleBody">
|
<div itemprop="articleBody">
|
||||||
|
|
||||||
<section id="screenshots-of-tisbackup">
|
<section id="screenshots-of-tisbackup">
|
||||||
<h1>Screenshots of TISBackup<a class="headerlink" href="#screenshots-of-tisbackup" title="Permalink to this headline">¶</a></h1>
|
<h1>Screenshots of TISBackup<a class="headerlink" href="#screenshots-of-tisbackup" title="Permalink to this headline">¶</a></h1>
|
||||||
<figure class="align-center" id="id1">
|
<figure class="align-center" id="id1">
|
||||||
@ -222,7 +222,7 @@
|
|||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<footer>
|
<footer>
|
||||||
<div class="rst-footer-buttons" role="navigation" aria-label="footer navigation">
|
<div class="rst-footer-buttons" role="navigation" aria-label="footer navigation">
|
||||||
@ -237,14 +237,14 @@
|
|||||||
|
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a
|
Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a
|
||||||
|
|
||||||
<a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a>
|
<a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a>
|
||||||
|
|
||||||
provided by <a href="https://readthedocs.org">Read the Docs</a>.
|
provided by <a href="https://readthedocs.org">Read the Docs</a>.
|
||||||
|
|
||||||
</footer>
|
</footer>
|
||||||
</div>
|
</div>
|
||||||
@ -253,7 +253,7 @@
|
|||||||
</section>
|
</section>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
jQuery(function () {
|
jQuery(function () {
|
||||||
@ -261,11 +261,11 @@
|
|||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Global site tag (gtag.js) - Google Analytics -->
|
<!-- Global site tag (gtag.js) - Google Analytics -->
|
||||||
<script async src="https://www.googletagmanager.com/gtag/js?id=UA-89790248-2"></script>
|
<script async src="https://www.googletagmanager.com/gtag/js?id=UA-89790248-2"></script>
|
||||||
@ -280,4 +280,4 @@ gtag('config', 'UA-89790248-2');
|
|||||||
|
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
148
docs/search.html
148
docs/search.html
@ -4,78 +4,78 @@
|
|||||||
<html class="writer-html5" lang="en" >
|
<html class="writer-html5" lang="en" >
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
||||||
|
|
||||||
<title>Search — TISBackup 1.8.2 documentation</title>
|
|
||||||
|
|
||||||
|
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
|
||||||
|
<title>Search — TISBackup 1.8.2 documentation</title>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<link rel="stylesheet" href="_static/css/theme.css" type="text/css" />
|
<link rel="stylesheet" href="_static/css/theme.css" type="text/css" />
|
||||||
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
|
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
|
||||||
<link rel="stylesheet" href="_static/css/custom.css" type="text/css" />
|
<link rel="stylesheet" href="_static/css/custom.css" type="text/css" />
|
||||||
<link rel="stylesheet" href="_static/css/ribbon.css" type="text/css" />
|
<link rel="stylesheet" href="_static/css/ribbon.css" type="text/css" />
|
||||||
<link rel="stylesheet" href="_static/theme_overrides.css" type="text/css" />
|
<link rel="stylesheet" href="_static/theme_overrides.css" type="text/css" />
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<link rel="shortcut icon" href="_static/favicon.ico"/>
|
<link rel="shortcut icon" href="_static/favicon.ico"/>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<!--[if lt IE 9]>
|
<!--[if lt IE 9]>
|
||||||
<script src="_static/js/html5shiv.min.js"></script>
|
<script src="_static/js/html5shiv.min.js"></script>
|
||||||
<![endif]-->
|
<![endif]-->
|
||||||
|
|
||||||
|
|
||||||
<script type="text/javascript" id="documentation_options" data-url_root="./" src="_static/documentation_options.js"></script>
|
<script type="text/javascript" id="documentation_options" data-url_root="./" src="_static/documentation_options.js"></script>
|
||||||
<script src="_static/jquery.js"></script>
|
<script src="_static/jquery.js"></script>
|
||||||
<script src="_static/underscore.js"></script>
|
<script src="_static/underscore.js"></script>
|
||||||
<script src="_static/doctools.js"></script>
|
<script src="_static/doctools.js"></script>
|
||||||
<script src="_static/language_data.js"></script>
|
<script src="_static/language_data.js"></script>
|
||||||
|
|
||||||
<script type="text/javascript" src="_static/js/theme.js"></script>
|
<script type="text/javascript" src="_static/js/theme.js"></script>
|
||||||
|
|
||||||
|
|
||||||
<script type="text/javascript" src="_static/searchtools.js"></script>
|
<script type="text/javascript" src="_static/searchtools.js"></script>
|
||||||
<script type="text/javascript" src="_static/language_data.js"></script>
|
<script type="text/javascript" src="_static/language_data.js"></script>
|
||||||
<link rel="index" title="Index" href="genindex.html" />
|
<link rel="index" title="Index" href="genindex.html" />
|
||||||
<link rel="search" title="Search" href="#" />
|
<link rel="search" title="Search" href="#" />
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body class="wy-body-for-nav">
|
<body class="wy-body-for-nav">
|
||||||
|
|
||||||
|
|
||||||
<div class="wy-grid-for-nav">
|
<div class="wy-grid-for-nav">
|
||||||
|
|
||||||
<nav data-toggle="wy-nav-shift" class="wy-nav-side">
|
<nav data-toggle="wy-nav-shift" class="wy-nav-side">
|
||||||
<div class="wy-side-scroll">
|
<div class="wy-side-scroll">
|
||||||
<div class="wy-side-nav-search" >
|
<div class="wy-side-nav-search" >
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<a href="index.html" class="icon icon-home"> TISBackup
|
<a href="index.html" class="icon icon-home"> TISBackup
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<div class="version">
|
<div class="version">
|
||||||
1.8
|
1.8
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<div role="search">
|
<div role="search">
|
||||||
<form id="rtd-search-form" class="wy-form" action="#" method="get">
|
<form id="rtd-search-form" class="wy-form" action="#" method="get">
|
||||||
<input type="text" name="q" placeholder="Search docs" />
|
<input type="text" name="q" placeholder="Search docs" />
|
||||||
@ -84,17 +84,17 @@
|
|||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="main navigation">
|
<div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="main navigation">
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<p><span class="caption-text">Presenting TISBackup</span></p>
|
<p><span class="caption-text">Presenting TISBackup</span></p>
|
||||||
<ul>
|
<ul>
|
||||||
<li class="toctree-l1"><a class="reference internal" href="presenting_tisbackup.html">Technical background for TISBackup</a></li>
|
<li class="toctree-l1"><a class="reference internal" href="presenting_tisbackup.html">Technical background for TISBackup</a></li>
|
||||||
@ -108,29 +108,29 @@
|
|||||||
<li class="toctree-l1"><a class="reference internal" href="screenshots.html">Screenshots of TISBackup</a></li>
|
<li class="toctree-l1"><a class="reference internal" href="screenshots.html">Screenshots of TISBackup</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
<section data-toggle="wy-nav-shift" class="wy-nav-content-wrap">
|
<section data-toggle="wy-nav-shift" class="wy-nav-content-wrap">
|
||||||
|
|
||||||
|
|
||||||
<nav class="wy-nav-top" aria-label="top navigation">
|
<nav class="wy-nav-top" aria-label="top navigation">
|
||||||
|
|
||||||
<i data-toggle="wy-nav-top" class="fa fa-bars"></i>
|
<i data-toggle="wy-nav-top" class="fa fa-bars"></i>
|
||||||
<a href="index.html">TISBackup</a>
|
<a href="index.html">TISBackup</a>
|
||||||
|
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
|
|
||||||
<div class="wy-nav-content">
|
<div class="wy-nav-content">
|
||||||
|
|
||||||
<div class="rst-content">
|
<div class="rst-content">
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -151,24 +151,24 @@
|
|||||||
<div role="navigation" aria-label="breadcrumbs navigation">
|
<div role="navigation" aria-label="breadcrumbs navigation">
|
||||||
|
|
||||||
<ul class="wy-breadcrumbs">
|
<ul class="wy-breadcrumbs">
|
||||||
|
|
||||||
<li><a href="index.html" class="icon icon-home"></a> »</li>
|
<li><a href="index.html" class="icon icon-home"></a> »</li>
|
||||||
|
|
||||||
<li>Search</li>
|
<li>Search</li>
|
||||||
|
|
||||||
|
|
||||||
<li class="wy-breadcrumbs-aside">
|
<li class="wy-breadcrumbs-aside">
|
||||||
|
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
|
||||||
<hr/>
|
<hr/>
|
||||||
</div>
|
</div>
|
||||||
<div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article">
|
<div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article">
|
||||||
<div itemprop="articleBody">
|
<div itemprop="articleBody">
|
||||||
|
|
||||||
<noscript>
|
<noscript>
|
||||||
<div id="fallback" class="admonition warning">
|
<div id="fallback" class="admonition warning">
|
||||||
<p class="last">
|
<p class="last">
|
||||||
@ -177,13 +177,13 @@
|
|||||||
</div>
|
</div>
|
||||||
</noscript>
|
</noscript>
|
||||||
|
|
||||||
|
|
||||||
<div id="search-results">
|
<div id="search-results">
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<footer>
|
<footer>
|
||||||
|
|
||||||
@ -195,14 +195,14 @@
|
|||||||
|
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a
|
Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a
|
||||||
|
|
||||||
<a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a>
|
<a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a>
|
||||||
|
|
||||||
provided by <a href="https://readthedocs.org">Read the Docs</a>.
|
provided by <a href="https://readthedocs.org">Read the Docs</a>.
|
||||||
|
|
||||||
</footer>
|
</footer>
|
||||||
</div>
|
</div>
|
||||||
@ -211,7 +211,7 @@
|
|||||||
</section>
|
</section>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
jQuery(function () {
|
jQuery(function () {
|
||||||
@ -219,17 +219,17 @@
|
|||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
jQuery(function() { Search.loadIndex("searchindex.js"); });
|
jQuery(function() { Search.loadIndex("searchindex.js"); });
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script type="text/javascript" id="searchindexloader"></script>
|
<script type="text/javascript" id="searchindexloader"></script>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Global site tag (gtag.js) - Google Analytics -->
|
<!-- Global site tag (gtag.js) - Google Analytics -->
|
||||||
<script async src="https://www.googletagmanager.com/gtag/js?id=UA-89790248-2"></script>
|
<script async src="https://www.googletagmanager.com/gtag/js?id=UA-89790248-2"></script>
|
||||||
@ -245,4 +245,4 @@ gtag('config', 'UA-89790248-2');
|
|||||||
|
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
File diff suppressed because one or more lines are too long
@ -9,75 +9,75 @@
|
|||||||
<meta content="TISBackup, documentation, website, editor, Twitter, official website" name="keywords" />
|
<meta content="TISBackup, documentation, website, editor, Twitter, official website" name="keywords" />
|
||||||
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
|
||||||
<title>Contacting Tranquil IT — TISBackup 1.8.2 documentation</title>
|
|
||||||
|
|
||||||
|
|
||||||
|
<title>Contacting Tranquil IT — TISBackup 1.8.2 documentation</title>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<link rel="stylesheet" href="_static/css/theme.css" type="text/css" />
|
<link rel="stylesheet" href="_static/css/theme.css" type="text/css" />
|
||||||
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
|
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
|
||||||
<link rel="stylesheet" href="_static/css/custom.css" type="text/css" />
|
<link rel="stylesheet" href="_static/css/custom.css" type="text/css" />
|
||||||
<link rel="stylesheet" href="_static/css/ribbon.css" type="text/css" />
|
<link rel="stylesheet" href="_static/css/ribbon.css" type="text/css" />
|
||||||
<link rel="stylesheet" href="_static/theme_overrides.css" type="text/css" />
|
<link rel="stylesheet" href="_static/theme_overrides.css" type="text/css" />
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<link rel="shortcut icon" href="_static/favicon.ico"/>
|
<link rel="shortcut icon" href="_static/favicon.ico"/>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<!--[if lt IE 9]>
|
<!--[if lt IE 9]>
|
||||||
<script src="_static/js/html5shiv.min.js"></script>
|
<script src="_static/js/html5shiv.min.js"></script>
|
||||||
<![endif]-->
|
<![endif]-->
|
||||||
|
|
||||||
|
|
||||||
<script type="text/javascript" id="documentation_options" data-url_root="./" src="_static/documentation_options.js"></script>
|
<script type="text/javascript" id="documentation_options" data-url_root="./" src="_static/documentation_options.js"></script>
|
||||||
<script src="_static/jquery.js"></script>
|
<script src="_static/jquery.js"></script>
|
||||||
<script src="_static/underscore.js"></script>
|
<script src="_static/underscore.js"></script>
|
||||||
<script src="_static/doctools.js"></script>
|
<script src="_static/doctools.js"></script>
|
||||||
<script src="_static/language_data.js"></script>
|
<script src="_static/language_data.js"></script>
|
||||||
|
|
||||||
<script type="text/javascript" src="_static/js/theme.js"></script>
|
<script type="text/javascript" src="_static/js/theme.js"></script>
|
||||||
|
|
||||||
|
|
||||||
<link rel="index" title="Index" href="genindex.html" />
|
<link rel="index" title="Index" href="genindex.html" />
|
||||||
<link rel="search" title="Search" href="search.html" />
|
<link rel="search" title="Search" href="search.html" />
|
||||||
<link rel="next" title="Screenshots of TISBackup" href="screenshots.html" />
|
<link rel="next" title="Screenshots of TISBackup" href="screenshots.html" />
|
||||||
<link rel="prev" title="Using TISBackup" href="using_tisbackup.html" />
|
<link rel="prev" title="Using TISBackup" href="using_tisbackup.html" />
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body class="wy-body-for-nav">
|
<body class="wy-body-for-nav">
|
||||||
|
|
||||||
|
|
||||||
<div class="wy-grid-for-nav">
|
<div class="wy-grid-for-nav">
|
||||||
|
|
||||||
<nav data-toggle="wy-nav-shift" class="wy-nav-side">
|
<nav data-toggle="wy-nav-shift" class="wy-nav-side">
|
||||||
<div class="wy-side-scroll">
|
<div class="wy-side-scroll">
|
||||||
<div class="wy-side-nav-search" >
|
<div class="wy-side-nav-search" >
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<a href="index.html" class="icon icon-home"> TISBackup
|
<a href="index.html" class="icon icon-home"> TISBackup
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<div class="version">
|
<div class="version">
|
||||||
1.8
|
1.8
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<div role="search">
|
<div role="search">
|
||||||
<form id="rtd-search-form" class="wy-form" action="search.html" method="get">
|
<form id="rtd-search-form" class="wy-form" action="search.html" method="get">
|
||||||
<input type="text" name="q" placeholder="Search docs" />
|
<input type="text" name="q" placeholder="Search docs" />
|
||||||
@ -86,17 +86,17 @@
|
|||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="main navigation">
|
<div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="main navigation">
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<p><span class="caption-text">Presenting TISBackup</span></p>
|
<p><span class="caption-text">Presenting TISBackup</span></p>
|
||||||
<ul>
|
<ul>
|
||||||
<li class="toctree-l1"><a class="reference internal" href="presenting_tisbackup.html">Technical background for TISBackup</a></li>
|
<li class="toctree-l1"><a class="reference internal" href="presenting_tisbackup.html">Technical background for TISBackup</a></li>
|
||||||
@ -110,29 +110,29 @@
|
|||||||
<li class="toctree-l1"><a class="reference internal" href="screenshots.html">Screenshots of TISBackup</a></li>
|
<li class="toctree-l1"><a class="reference internal" href="screenshots.html">Screenshots of TISBackup</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
<section data-toggle="wy-nav-shift" class="wy-nav-content-wrap">
|
<section data-toggle="wy-nav-shift" class="wy-nav-content-wrap">
|
||||||
|
|
||||||
|
|
||||||
<nav class="wy-nav-top" aria-label="top navigation">
|
<nav class="wy-nav-top" aria-label="top navigation">
|
||||||
|
|
||||||
<i data-toggle="wy-nav-top" class="fa fa-bars"></i>
|
<i data-toggle="wy-nav-top" class="fa fa-bars"></i>
|
||||||
<a href="index.html">TISBackup</a>
|
<a href="index.html">TISBackup</a>
|
||||||
|
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
|
|
||||||
<div class="wy-nav-content">
|
<div class="wy-nav-content">
|
||||||
|
|
||||||
<div class="rst-content">
|
<div class="rst-content">
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -153,28 +153,28 @@
|
|||||||
<div role="navigation" aria-label="breadcrumbs navigation">
|
<div role="navigation" aria-label="breadcrumbs navigation">
|
||||||
|
|
||||||
<ul class="wy-breadcrumbs">
|
<ul class="wy-breadcrumbs">
|
||||||
|
|
||||||
<li><a href="index.html" class="icon icon-home"></a> »</li>
|
<li><a href="index.html" class="icon icon-home"></a> »</li>
|
||||||
|
|
||||||
<li>Contacting Tranquil IT</li>
|
<li>Contacting Tranquil IT</li>
|
||||||
|
|
||||||
|
|
||||||
<li class="wy-breadcrumbs-aside">
|
<li class="wy-breadcrumbs-aside">
|
||||||
|
|
||||||
|
|
||||||
<a href="_sources/tranquil-it-contacts.rst.txt" rel="nofollow"> View page source</a>
|
<a href="_sources/tranquil-it-contacts.rst.txt" rel="nofollow"> View page source</a>
|
||||||
|
|
||||||
|
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
|
||||||
<hr/>
|
<hr/>
|
||||||
</div>
|
</div>
|
||||||
<div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article">
|
<div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article">
|
||||||
<div itemprop="articleBody">
|
<div itemprop="articleBody">
|
||||||
|
|
||||||
<section id="contacting-tranquil-it">
|
<section id="contacting-tranquil-it">
|
||||||
<span id="contact-tranquil-it"></span><h1>Contacting Tranquil IT<a class="headerlink" href="#contacting-tranquil-it" title="Permalink to this headline">¶</a></h1>
|
<span id="contact-tranquil-it"></span><h1>Contacting Tranquil IT<a class="headerlink" href="#contacting-tranquil-it" title="Permalink to this headline">¶</a></h1>
|
||||||
<ul class="simple">
|
<ul class="simple">
|
||||||
@ -185,7 +185,7 @@
|
|||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<footer>
|
<footer>
|
||||||
<div class="rst-footer-buttons" role="navigation" aria-label="footer navigation">
|
<div class="rst-footer-buttons" role="navigation" aria-label="footer navigation">
|
||||||
@ -201,14 +201,14 @@
|
|||||||
|
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a
|
Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a
|
||||||
|
|
||||||
<a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a>
|
<a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a>
|
||||||
|
|
||||||
provided by <a href="https://readthedocs.org">Read the Docs</a>.
|
provided by <a href="https://readthedocs.org">Read the Docs</a>.
|
||||||
|
|
||||||
</footer>
|
</footer>
|
||||||
</div>
|
</div>
|
||||||
@ -217,7 +217,7 @@
|
|||||||
</section>
|
</section>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
jQuery(function () {
|
jQuery(function () {
|
||||||
@ -225,11 +225,11 @@
|
|||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Global site tag (gtag.js) - Google Analytics -->
|
<!-- Global site tag (gtag.js) - Google Analytics -->
|
||||||
<script async src="https://www.googletagmanager.com/gtag/js?id=UA-89790248-2"></script>
|
<script async src="https://www.googletagmanager.com/gtag/js?id=UA-89790248-2"></script>
|
||||||
@ -244,4 +244,4 @@ gtag('config', 'UA-89790248-2');
|
|||||||
|
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
@ -9,75 +9,75 @@
|
|||||||
<meta content="Documentation, TISBackup, usage, options, exporting" name="keywords" />
|
<meta content="Documentation, TISBackup, usage, options, exporting" name="keywords" />
|
||||||
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
|
||||||
<title>Using TISBackup — TISBackup 1.8.2 documentation</title>
|
|
||||||
|
|
||||||
|
|
||||||
|
<title>Using TISBackup — TISBackup 1.8.2 documentation</title>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<link rel="stylesheet" href="_static/css/theme.css" type="text/css" />
|
<link rel="stylesheet" href="_static/css/theme.css" type="text/css" />
|
||||||
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
|
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
|
||||||
<link rel="stylesheet" href="_static/css/custom.css" type="text/css" />
|
<link rel="stylesheet" href="_static/css/custom.css" type="text/css" />
|
||||||
<link rel="stylesheet" href="_static/css/ribbon.css" type="text/css" />
|
<link rel="stylesheet" href="_static/css/ribbon.css" type="text/css" />
|
||||||
<link rel="stylesheet" href="_static/theme_overrides.css" type="text/css" />
|
<link rel="stylesheet" href="_static/theme_overrides.css" type="text/css" />
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<link rel="shortcut icon" href="_static/favicon.ico"/>
|
<link rel="shortcut icon" href="_static/favicon.ico"/>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<!--[if lt IE 9]>
|
<!--[if lt IE 9]>
|
||||||
<script src="_static/js/html5shiv.min.js"></script>
|
<script src="_static/js/html5shiv.min.js"></script>
|
||||||
<![endif]-->
|
<![endif]-->
|
||||||
|
|
||||||
|
|
||||||
<script type="text/javascript" id="documentation_options" data-url_root="./" src="_static/documentation_options.js"></script>
|
<script type="text/javascript" id="documentation_options" data-url_root="./" src="_static/documentation_options.js"></script>
|
||||||
<script src="_static/jquery.js"></script>
|
<script src="_static/jquery.js"></script>
|
||||||
<script src="_static/underscore.js"></script>
|
<script src="_static/underscore.js"></script>
|
||||||
<script src="_static/doctools.js"></script>
|
<script src="_static/doctools.js"></script>
|
||||||
<script src="_static/language_data.js"></script>
|
<script src="_static/language_data.js"></script>
|
||||||
|
|
||||||
<script type="text/javascript" src="_static/js/theme.js"></script>
|
<script type="text/javascript" src="_static/js/theme.js"></script>
|
||||||
|
|
||||||
|
|
||||||
<link rel="index" title="Index" href="genindex.html" />
|
<link rel="index" title="Index" href="genindex.html" />
|
||||||
<link rel="search" title="Search" href="search.html" />
|
<link rel="search" title="Search" href="search.html" />
|
||||||
<link rel="next" title="Contacting Tranquil IT" href="tranquil-it-contacts.html" />
|
<link rel="next" title="Contacting Tranquil IT" href="tranquil-it-contacts.html" />
|
||||||
<link rel="prev" title="Configuring the backup jobs" href="configuring_tisbackup.html" />
|
<link rel="prev" title="Configuring the backup jobs" href="configuring_tisbackup.html" />
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body class="wy-body-for-nav">
|
<body class="wy-body-for-nav">
|
||||||
|
|
||||||
|
|
||||||
<div class="wy-grid-for-nav">
|
<div class="wy-grid-for-nav">
|
||||||
|
|
||||||
<nav data-toggle="wy-nav-shift" class="wy-nav-side">
|
<nav data-toggle="wy-nav-shift" class="wy-nav-side">
|
||||||
<div class="wy-side-scroll">
|
<div class="wy-side-scroll">
|
||||||
<div class="wy-side-nav-search" >
|
<div class="wy-side-nav-search" >
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<a href="index.html" class="icon icon-home"> TISBackup
|
<a href="index.html" class="icon icon-home"> TISBackup
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<div class="version">
|
<div class="version">
|
||||||
1.8
|
1.8
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<div role="search">
|
<div role="search">
|
||||||
<form id="rtd-search-form" class="wy-form" action="search.html" method="get">
|
<form id="rtd-search-form" class="wy-form" action="search.html" method="get">
|
||||||
<input type="text" name="q" placeholder="Search docs" />
|
<input type="text" name="q" placeholder="Search docs" />
|
||||||
@ -86,17 +86,17 @@
|
|||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="main navigation">
|
<div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="main navigation">
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<p><span class="caption-text">Presenting TISBackup</span></p>
|
<p><span class="caption-text">Presenting TISBackup</span></p>
|
||||||
<ul class="current">
|
<ul class="current">
|
||||||
<li class="toctree-l1"><a class="reference internal" href="presenting_tisbackup.html">Technical background for TISBackup</a></li>
|
<li class="toctree-l1"><a class="reference internal" href="presenting_tisbackup.html">Technical background for TISBackup</a></li>
|
||||||
@ -113,29 +113,29 @@
|
|||||||
<li class="toctree-l1"><a class="reference internal" href="screenshots.html">Screenshots of TISBackup</a></li>
|
<li class="toctree-l1"><a class="reference internal" href="screenshots.html">Screenshots of TISBackup</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
<section data-toggle="wy-nav-shift" class="wy-nav-content-wrap">
|
<section data-toggle="wy-nav-shift" class="wy-nav-content-wrap">
|
||||||
|
|
||||||
|
|
||||||
<nav class="wy-nav-top" aria-label="top navigation">
|
<nav class="wy-nav-top" aria-label="top navigation">
|
||||||
|
|
||||||
<i data-toggle="wy-nav-top" class="fa fa-bars"></i>
|
<i data-toggle="wy-nav-top" class="fa fa-bars"></i>
|
||||||
<a href="index.html">TISBackup</a>
|
<a href="index.html">TISBackup</a>
|
||||||
|
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
|
|
||||||
<div class="wy-nav-content">
|
<div class="wy-nav-content">
|
||||||
|
|
||||||
<div class="rst-content">
|
<div class="rst-content">
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -156,28 +156,28 @@
|
|||||||
<div role="navigation" aria-label="breadcrumbs navigation">
|
<div role="navigation" aria-label="breadcrumbs navigation">
|
||||||
|
|
||||||
<ul class="wy-breadcrumbs">
|
<ul class="wy-breadcrumbs">
|
||||||
|
|
||||||
<li><a href="index.html" class="icon icon-home"></a> »</li>
|
<li><a href="index.html" class="icon icon-home"></a> »</li>
|
||||||
|
|
||||||
<li>Using TISBackup</li>
|
<li>Using TISBackup</li>
|
||||||
|
|
||||||
|
|
||||||
<li class="wy-breadcrumbs-aside">
|
<li class="wy-breadcrumbs-aside">
|
||||||
|
|
||||||
|
|
||||||
<a href="_sources/using_tisbackup.rst.txt" rel="nofollow"> View page source</a>
|
<a href="_sources/using_tisbackup.rst.txt" rel="nofollow"> View page source</a>
|
||||||
|
|
||||||
|
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
|
||||||
<hr/>
|
<hr/>
|
||||||
</div>
|
</div>
|
||||||
<div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article">
|
<div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article">
|
||||||
<div itemprop="articleBody">
|
<div itemprop="articleBody">
|
||||||
|
|
||||||
<section id="using-tisbackup">
|
<section id="using-tisbackup">
|
||||||
<h1>Using TISBackup<a class="headerlink" href="#using-tisbackup" title="Permalink to this headline">¶</a></h1>
|
<h1>Using TISBackup<a class="headerlink" href="#using-tisbackup" title="Permalink to this headline">¶</a></h1>
|
||||||
<p id="id1">As seen in the <a class="reference internal" href="installing_tisbackup.html#install-tisbackup-debian"><span class="std std-ref">section on installing TISbackup</span></a>,
|
<p id="id1">As seen in the <a class="reference internal" href="installing_tisbackup.html#install-tisbackup-debian"><span class="std std-ref">section on installing TISbackup</span></a>,
|
||||||
@ -291,7 +291,7 @@ e2label /dev/xvdc1 tisbackup
|
|||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<footer>
|
<footer>
|
||||||
<div class="rst-footer-buttons" role="navigation" aria-label="footer navigation">
|
<div class="rst-footer-buttons" role="navigation" aria-label="footer navigation">
|
||||||
@ -307,14 +307,14 @@ e2label /dev/xvdc1 tisbackup
|
|||||||
|
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a
|
Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a
|
||||||
|
|
||||||
<a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a>
|
<a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a>
|
||||||
|
|
||||||
provided by <a href="https://readthedocs.org">Read the Docs</a>.
|
provided by <a href="https://readthedocs.org">Read the Docs</a>.
|
||||||
|
|
||||||
</footer>
|
</footer>
|
||||||
</div>
|
</div>
|
||||||
@ -323,7 +323,7 @@ e2label /dev/xvdc1 tisbackup
|
|||||||
</section>
|
</section>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
jQuery(function () {
|
jQuery(function () {
|
||||||
@ -331,11 +331,11 @@ e2label /dev/xvdc1 tisbackup
|
|||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Global site tag (gtag.js) - Google Analytics -->
|
<!-- Global site tag (gtag.js) - Google Analytics -->
|
||||||
<script async src="https://www.googletagmanager.com/gtag/js?id=UA-89790248-2"></script>
|
<script async src="https://www.googletagmanager.com/gtag/js?id=UA-89790248-2"></script>
|
||||||
@ -350,4 +350,4 @@ gtag('config', 'UA-89790248-2');
|
|||||||
|
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
7
entrypoint.sh
Executable file
7
entrypoint.sh
Executable file
@ -0,0 +1,7 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
env >> /etc/environment
|
||||||
|
|
||||||
|
# execute CMD
|
||||||
|
echo "$@"
|
||||||
|
exec "$@"
|
@ -55,11 +55,12 @@
|
|||||||
# --------------------------------------------------------------------
|
# --------------------------------------------------------------------
|
||||||
|
|
||||||
import gettext
|
import gettext
|
||||||
import six.moves.xmlrpc_client as xmlrpclib
|
|
||||||
import six.moves.http_client as httplib
|
|
||||||
import socket
|
import socket
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
import six.moves.http_client as httplib
|
||||||
|
import six.moves.xmlrpc_client as xmlrpclib
|
||||||
|
|
||||||
translation = gettext.translation('xen-xm', fallback = True)
|
translation = gettext.translation('xen-xm', fallback = True)
|
||||||
|
|
||||||
API_VERSION_1_1 = '1.1'
|
API_VERSION_1_1 = '1.1'
|
||||||
|
@ -15,4 +15,3 @@
|
|||||||
# along with TISBackup. If not, see <http://www.gnu.org/licenses/>.
|
# along with TISBackup. If not, see <http://www.gnu.org/licenses/>.
|
||||||
#
|
#
|
||||||
# -----------------------------------------------------------------------
|
# -----------------------------------------------------------------------
|
||||||
|
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
|
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
try:
|
try:
|
||||||
sys.stderr = open('/dev/null') # Silence silly warnings from paramiko
|
sys.stderr = open('/dev/null') # Silence silly warnings from paramiko
|
||||||
import paramiko
|
import paramiko
|
||||||
@ -32,6 +33,7 @@ sys.stderr = sys.__stderr__
|
|||||||
|
|
||||||
from libtisbackup.common import *
|
from libtisbackup.common import *
|
||||||
|
|
||||||
|
|
||||||
class backup_mysql(backup_generic):
|
class backup_mysql(backup_generic):
|
||||||
"""Backup a mysql database as gzipped sql file through ssh"""
|
"""Backup a mysql database as gzipped sql file through ssh"""
|
||||||
type = 'mysql+ssh'
|
type = 'mysql+ssh'
|
||||||
|
@ -18,16 +18,17 @@
|
|||||||
#
|
#
|
||||||
# -----------------------------------------------------------------------
|
# -----------------------------------------------------------------------
|
||||||
|
|
||||||
import os
|
|
||||||
import datetime
|
import datetime
|
||||||
|
import os
|
||||||
|
|
||||||
from .common import *
|
from .common import *
|
||||||
|
|
||||||
|
|
||||||
class backup_null(backup_generic):
|
class backup_null(backup_generic):
|
||||||
"""Null backup to register servers which don't need any backups
|
"""Null backup to register servers which don't need any backups
|
||||||
but we still want to know they are taken in account"""
|
but we still want to know they are taken in account"""
|
||||||
type = 'null'
|
type = 'null'
|
||||||
|
|
||||||
required_params = ['type','server_name','backup_name']
|
required_params = ['type','server_name','backup_name']
|
||||||
optional_params = []
|
optional_params = []
|
||||||
|
|
||||||
@ -43,9 +44,8 @@ class backup_null(backup_generic):
|
|||||||
return {}
|
return {}
|
||||||
def checknagios(self,maxage_hours=30):
|
def checknagios(self,maxage_hours=30):
|
||||||
return (nagiosStateOk,"No backups needs to be performed")
|
return (nagiosStateOk,"No backups needs to be performed")
|
||||||
|
|
||||||
register_driver(backup_null)
|
register_driver(backup_null)
|
||||||
|
|
||||||
if __name__=='__main__':
|
if __name__=='__main__':
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
#
|
#
|
||||||
# -----------------------------------------------------------------------
|
# -----------------------------------------------------------------------
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
try:
|
try:
|
||||||
sys.stderr = open('/dev/null') # Silence silly warnings from paramiko
|
sys.stderr = open('/dev/null') # Silence silly warnings from paramiko
|
||||||
import paramiko
|
import paramiko
|
||||||
@ -27,15 +28,17 @@ except ImportError as e:
|
|||||||
|
|
||||||
sys.stderr = sys.__stderr__
|
sys.stderr = sys.__stderr__
|
||||||
|
|
||||||
import datetime
|
|
||||||
import base64
|
import base64
|
||||||
|
import datetime
|
||||||
import os
|
import os
|
||||||
from libtisbackup.common import *
|
|
||||||
import re
|
import re
|
||||||
|
|
||||||
|
from libtisbackup.common import *
|
||||||
|
|
||||||
|
|
||||||
class backup_oracle(backup_generic):
|
class backup_oracle(backup_generic):
|
||||||
"""Backup a oracle database as zipped file through ssh"""
|
"""Backup a oracle database as zipped file through ssh"""
|
||||||
type = 'oracle+ssh'
|
type = 'oracle+ssh'
|
||||||
required_params = backup_generic.required_params + ['db_name','private_key', 'userid']
|
required_params = backup_generic.required_params + ['db_name','private_key', 'userid']
|
||||||
optional_params = ['username', 'remote_backup_dir', 'ignore_error_oracle_code']
|
optional_params = ['username', 'remote_backup_dir', 'ignore_error_oracle_code']
|
||||||
db_name=''
|
db_name=''
|
||||||
@ -44,7 +47,7 @@ class backup_oracle(backup_generic):
|
|||||||
ignore_error_oracle_code = [ ]
|
ignore_error_oracle_code = [ ]
|
||||||
|
|
||||||
def do_backup(self,stats):
|
def do_backup(self,stats):
|
||||||
|
|
||||||
self.logger.debug('[%s] Connecting to %s with user %s and key %s',self.backup_name,self.server_name,self.username,self.private_key)
|
self.logger.debug('[%s] Connecting to %s with user %s and key %s',self.backup_name,self.server_name,self.username,self.private_key)
|
||||||
try:
|
try:
|
||||||
mykey = paramiko.RSAKey.from_private_key_file(self.private_key)
|
mykey = paramiko.RSAKey.from_private_key_file(self.private_key)
|
||||||
@ -54,8 +57,8 @@ class backup_oracle(backup_generic):
|
|||||||
|
|
||||||
self.ssh = paramiko.SSHClient()
|
self.ssh = paramiko.SSHClient()
|
||||||
self.ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
self.ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
||||||
self.ssh.connect(self.server_name,username=self.username,pkey = mykey,port=self.ssh_port)
|
self.ssh.connect(self.server_name,username=self.username,pkey = mykey,port=self.ssh_port)
|
||||||
|
|
||||||
t = datetime.datetime.now()
|
t = datetime.datetime.now()
|
||||||
self.backup_start_date = t.strftime('%Y%m%d-%Hh%Mm%S')
|
self.backup_start_date = t.strftime('%Y%m%d-%Hh%Mm%S')
|
||||||
dumpfile= self.remote_backup_dir + '/' + self.db_name + '_' + self.backup_start_date+'.dmp'
|
dumpfile= self.remote_backup_dir + '/' + self.db_name + '_' + self.backup_start_date+'.dmp'
|
||||||
@ -68,10 +71,10 @@ class backup_oracle(backup_generic):
|
|||||||
else:
|
else:
|
||||||
print(('mkdir "%s"' % self.dest_dir))
|
print(('mkdir "%s"' % self.dest_dir))
|
||||||
else:
|
else:
|
||||||
raise Exception('backup destination directory already exists : %s' % self.dest_dir)
|
raise Exception('backup destination directory already exists : %s' % self.dest_dir)
|
||||||
# dump db
|
# dump db
|
||||||
stats['status']='Dumping'
|
stats['status']='Dumping'
|
||||||
cmd = "exp '%s' file='%s' grants=y log='%s'"% (self.userid,dumpfile, dumplog)
|
cmd = "exp '%s' file='%s' grants=y log='%s'"% (self.userid,dumpfile, dumplog)
|
||||||
self.logger.debug('[%s] Dump DB : %s',self.backup_name,cmd)
|
self.logger.debug('[%s] Dump DB : %s',self.backup_name,cmd)
|
||||||
if not self.dry_run:
|
if not self.dry_run:
|
||||||
(error_code,output) = ssh_exec(cmd,ssh=self.ssh)
|
(error_code,output) = ssh_exec(cmd,ssh=self.ssh)
|
||||||
@ -94,7 +97,7 @@ class backup_oracle(backup_generic):
|
|||||||
|
|
||||||
# zip the file
|
# zip the file
|
||||||
stats['status']='Zipping'
|
stats['status']='Zipping'
|
||||||
cmd = 'gzip %s' % dumpfile
|
cmd = 'gzip %s' % dumpfile
|
||||||
self.logger.debug('[%s] Compress backup : %s',self.backup_name,cmd)
|
self.logger.debug('[%s] Compress backup : %s',self.backup_name,cmd)
|
||||||
if not self.dry_run:
|
if not self.dry_run:
|
||||||
(error_code,output) = ssh_exec(cmd,ssh=self.ssh)
|
(error_code,output) = ssh_exec(cmd,ssh=self.ssh)
|
||||||
@ -117,7 +120,7 @@ class backup_oracle(backup_generic):
|
|||||||
stats['total_files_count']=1
|
stats['total_files_count']=1
|
||||||
stats['written_files_count']=1
|
stats['written_files_count']=1
|
||||||
stats['total_bytes']=os.stat(localpath).st_size
|
stats['total_bytes']=os.stat(localpath).st_size
|
||||||
stats['written_bytes']=os.stat(localpath).st_size
|
stats['written_bytes']=os.stat(localpath).st_size
|
||||||
stats['log']='gzip dump of DB %s:%s (%d bytes) to %s' % (self.server_name,self.db_name, stats['written_bytes'], localpath)
|
stats['log']='gzip dump of DB %s:%s (%d bytes) to %s' % (self.server_name,self.db_name, stats['written_bytes'], localpath)
|
||||||
stats['backup_location'] = self.dest_dir
|
stats['backup_location'] = self.dest_dir
|
||||||
stats['status']='RMTemp'
|
stats['status']='RMTemp'
|
||||||
@ -131,7 +134,7 @@ class backup_oracle(backup_generic):
|
|||||||
|
|
||||||
filelist = os.listdir(self.backup_dir)
|
filelist = os.listdir(self.backup_dir)
|
||||||
filelist.sort()
|
filelist.sort()
|
||||||
p = re.compile('^\d{8,8}-\d{2,2}h\d{2,2}m\d{2,2}$')
|
p = re.compile('^\d{8,8}-\d{2,2}h\d{2,2}m\d{2,2}$')
|
||||||
for item in filelist:
|
for item in filelist:
|
||||||
if p.match(item):
|
if p.match(item):
|
||||||
dir_name = os.path.join(self.backup_dir,item)
|
dir_name = os.path.join(self.backup_dir,item)
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
#
|
#
|
||||||
# -----------------------------------------------------------------------
|
# -----------------------------------------------------------------------
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
try:
|
try:
|
||||||
sys.stderr = open('/dev/null') # Silence silly warnings from paramiko
|
sys.stderr = open('/dev/null') # Silence silly warnings from paramiko
|
||||||
import paramiko
|
import paramiko
|
||||||
@ -29,6 +30,7 @@ sys.stderr = sys.__stderr__
|
|||||||
|
|
||||||
from .common import *
|
from .common import *
|
||||||
|
|
||||||
|
|
||||||
class backup_pgsql(backup_generic):
|
class backup_pgsql(backup_generic):
|
||||||
"""Backup a postgresql database as gzipped sql file through ssh"""
|
"""Backup a postgresql database as gzipped sql file through ssh"""
|
||||||
type = 'pgsql+ssh'
|
type = 'pgsql+ssh'
|
||||||
|
@ -18,19 +18,19 @@
|
|||||||
#
|
#
|
||||||
# -----------------------------------------------------------------------
|
# -----------------------------------------------------------------------
|
||||||
|
|
||||||
import os
|
|
||||||
import datetime
|
import datetime
|
||||||
from libtisbackup.common import *
|
|
||||||
import time
|
|
||||||
import logging
|
import logging
|
||||||
import re
|
import os
|
||||||
import os.path
|
import os.path
|
||||||
import datetime
|
import re
|
||||||
|
import time
|
||||||
|
|
||||||
|
from libtisbackup.common import *
|
||||||
|
|
||||||
|
|
||||||
class backup_rsync(backup_generic):
|
class backup_rsync(backup_generic):
|
||||||
"""Backup a directory on remote server with rsync and rsync protocol (requires running remote rsync daemon)"""
|
"""Backup a directory on remote server with rsync and rsync protocol (requires running remote rsync daemon)"""
|
||||||
type = 'rsync'
|
type = 'rsync'
|
||||||
required_params = backup_generic.required_params + ['remote_user','remote_dir','rsync_module','password_file']
|
required_params = backup_generic.required_params + ['remote_user','remote_dir','rsync_module','password_file']
|
||||||
optional_params = backup_generic.optional_params + ['compressionlevel','compression','bwlimit','exclude_list','protect_args','overload_args']
|
optional_params = backup_generic.optional_params + ['compressionlevel','compression','bwlimit','exclude_list','protect_args','overload_args']
|
||||||
|
|
||||||
@ -46,7 +46,7 @@ class backup_rsync(backup_generic):
|
|||||||
overload_args = None
|
overload_args = None
|
||||||
compressionlevel = 0
|
compressionlevel = 0
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def read_config(self,iniconf):
|
def read_config(self,iniconf):
|
||||||
assert(isinstance(iniconf,ConfigParser))
|
assert(isinstance(iniconf,ConfigParser))
|
||||||
@ -54,7 +54,7 @@ class backup_rsync(backup_generic):
|
|||||||
if not self.bwlimit and iniconf.has_option('global','bw_limit'):
|
if not self.bwlimit and iniconf.has_option('global','bw_limit'):
|
||||||
self.bwlimit = iniconf.getint('global','bw_limit')
|
self.bwlimit = iniconf.getint('global','bw_limit')
|
||||||
if not self.compressionlevel and iniconf.has_option('global','compression_level'):
|
if not self.compressionlevel and iniconf.has_option('global','compression_level'):
|
||||||
self.compressionlevel = iniconf.getint('global','compression_level')
|
self.compressionlevel = iniconf.getint('global','compression_level')
|
||||||
|
|
||||||
def do_backup(self,stats):
|
def do_backup(self,stats):
|
||||||
if not self.set_lock():
|
if not self.set_lock():
|
||||||
@ -216,7 +216,7 @@ class backup_rsync(backup_generic):
|
|||||||
raise
|
raise
|
||||||
|
|
||||||
|
|
||||||
finally:
|
finally:
|
||||||
self.remove_lock()
|
self.remove_lock()
|
||||||
|
|
||||||
def get_latest_backup(self,current):
|
def get_latest_backup(self,current):
|
||||||
@ -225,8 +225,8 @@ class backup_rsync(backup_generic):
|
|||||||
filelist.sort()
|
filelist.sort()
|
||||||
filelist.reverse()
|
filelist.reverse()
|
||||||
full = ''
|
full = ''
|
||||||
r_full = re.compile('^\d{8,8}-\d{2,2}h\d{2,2}m\d{2,2}$')
|
r_full = re.compile('^\d{8,8}-\d{2,2}h\d{2,2}m\d{2,2}$')
|
||||||
r_partial = re.compile('^\d{8,8}-\d{2,2}h\d{2,2}m\d{2,2}.rsync$')
|
r_partial = re.compile('^\d{8,8}-\d{2,2}h\d{2,2}m\d{2,2}.rsync$')
|
||||||
# we take all latest partials younger than the latest full and the latest full
|
# we take all latest partials younger than the latest full and the latest full
|
||||||
for item in filelist:
|
for item in filelist:
|
||||||
if r_partial.match(item) and item<current:
|
if r_partial.match(item) and item<current:
|
||||||
@ -245,7 +245,7 @@ class backup_rsync(backup_generic):
|
|||||||
|
|
||||||
filelist = os.listdir(self.backup_dir)
|
filelist = os.listdir(self.backup_dir)
|
||||||
filelist.sort()
|
filelist.sort()
|
||||||
p = re.compile('^\d{8,8}-\d{2,2}h\d{2,2}m\d{2,2}$')
|
p = re.compile('^\d{8,8}-\d{2,2}h\d{2,2}m\d{2,2}$')
|
||||||
for item in filelist:
|
for item in filelist:
|
||||||
if p.match(item):
|
if p.match(item):
|
||||||
dir_name = os.path.join(self.backup_dir,item)
|
dir_name = os.path.join(self.backup_dir,item)
|
||||||
@ -288,7 +288,7 @@ class backup_rsync(backup_generic):
|
|||||||
return False
|
return False
|
||||||
else:
|
else:
|
||||||
self.logger.info("[" + self.backup_name + "] incorrrect lock file : no pid line")
|
self.logger.info("[" + self.backup_name + "] incorrrect lock file : no pid line")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
def set_lock(self):
|
def set_lock(self):
|
||||||
@ -317,7 +317,7 @@ class backup_rsync(backup_generic):
|
|||||||
|
|
||||||
class backup_rsync_ssh(backup_rsync):
|
class backup_rsync_ssh(backup_rsync):
|
||||||
"""Backup a directory on remote server with rsync and ssh protocol (requires rsync software on remote host)"""
|
"""Backup a directory on remote server with rsync and ssh protocol (requires rsync software on remote host)"""
|
||||||
type = 'rsync+ssh'
|
type = 'rsync+ssh'
|
||||||
required_params = backup_generic.required_params + ['remote_user','remote_dir','private_key']
|
required_params = backup_generic.required_params + ['remote_user','remote_dir','private_key']
|
||||||
optional_params = backup_generic.optional_params + ['compression','bwlimit','ssh_port','exclude_list','protect_args','overload_args', 'cipher_spec']
|
optional_params = backup_generic.optional_params + ['compression','bwlimit','ssh_port','exclude_list','protect_args','overload_args', 'cipher_spec']
|
||||||
cipher_spec = ''
|
cipher_spec = ''
|
||||||
@ -341,4 +341,3 @@ if __name__=='__main__':
|
|||||||
b.read_config(cp)
|
b.read_config(cp)
|
||||||
b.process_backup()
|
b.process_backup()
|
||||||
print((b.checknagios()))
|
print((b.checknagios()))
|
||||||
|
|
||||||
|
@ -18,20 +18,19 @@
|
|||||||
#
|
#
|
||||||
# -----------------------------------------------------------------------
|
# -----------------------------------------------------------------------
|
||||||
|
|
||||||
import os
|
|
||||||
import datetime
|
import datetime
|
||||||
from .common import *
|
|
||||||
import time
|
|
||||||
import logging
|
import logging
|
||||||
import re
|
import os
|
||||||
import os.path
|
import os.path
|
||||||
import datetime
|
import re
|
||||||
|
import time
|
||||||
|
|
||||||
from .common import *
|
from .common import *
|
||||||
|
|
||||||
|
|
||||||
class backup_rsync_btrfs(backup_generic):
|
class backup_rsync_btrfs(backup_generic):
|
||||||
"""Backup a directory on remote server with rsync and btrfs protocol (requires running remote rsync daemon)"""
|
"""Backup a directory on remote server with rsync and btrfs protocol (requires running remote rsync daemon)"""
|
||||||
type = 'rsync+btrfs'
|
type = 'rsync+btrfs'
|
||||||
required_params = backup_generic.required_params + ['remote_user','remote_dir','rsync_module','password_file']
|
required_params = backup_generic.required_params + ['remote_user','remote_dir','rsync_module','password_file']
|
||||||
optional_params = backup_generic.optional_params + ['compressionlevel','compression','bwlimit','exclude_list','protect_args','overload_args']
|
optional_params = backup_generic.optional_params + ['compressionlevel','compression','bwlimit','exclude_list','protect_args','overload_args']
|
||||||
|
|
||||||
@ -47,7 +46,7 @@ class backup_rsync_btrfs(backup_generic):
|
|||||||
overload_args = None
|
overload_args = None
|
||||||
compressionlevel = 0
|
compressionlevel = 0
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def read_config(self,iniconf):
|
def read_config(self,iniconf):
|
||||||
assert(isinstance(iniconf,ConfigParser))
|
assert(isinstance(iniconf,ConfigParser))
|
||||||
@ -55,7 +54,7 @@ class backup_rsync_btrfs(backup_generic):
|
|||||||
if not self.bwlimit and iniconf.has_option('global','bw_limit'):
|
if not self.bwlimit and iniconf.has_option('global','bw_limit'):
|
||||||
self.bwlimit = iniconf.getint('global','bw_limit')
|
self.bwlimit = iniconf.getint('global','bw_limit')
|
||||||
if not self.compressionlevel and iniconf.has_option('global','compression_level'):
|
if not self.compressionlevel and iniconf.has_option('global','compression_level'):
|
||||||
self.compressionlevel = iniconf.getint('global','compression_level')
|
self.compressionlevel = iniconf.getint('global','compression_level')
|
||||||
|
|
||||||
def do_backup(self,stats):
|
def do_backup(self,stats):
|
||||||
if not self.set_lock():
|
if not self.set_lock():
|
||||||
@ -74,7 +73,7 @@ class backup_rsync_btrfs(backup_generic):
|
|||||||
returncode = process.returncode
|
returncode = process.returncode
|
||||||
if (returncode != 0):
|
if (returncode != 0):
|
||||||
self.logger.error("[" + self.backup_name + "] shell program exited with error code: %s"%log)
|
self.logger.error("[" + self.backup_name + "] shell program exited with error code: %s"%log)
|
||||||
raise Exception("[" + self.backup_name + "] shell program exited with error code " + str(returncode), cmd)
|
raise Exception("[" + self.backup_name + "] shell program exited with error code " + str(returncode), cmd)
|
||||||
else:
|
else:
|
||||||
self.logger.info("[" + self.backup_name + "] create btrs volume: %s"%dest_dir)
|
self.logger.info("[" + self.backup_name + "] create btrs volume: %s"%dest_dir)
|
||||||
else:
|
else:
|
||||||
@ -235,7 +234,7 @@ class backup_rsync_btrfs(backup_generic):
|
|||||||
raise
|
raise
|
||||||
|
|
||||||
|
|
||||||
finally:
|
finally:
|
||||||
self.remove_lock()
|
self.remove_lock()
|
||||||
|
|
||||||
def get_latest_backup(self,current):
|
def get_latest_backup(self,current):
|
||||||
@ -244,8 +243,8 @@ class backup_rsync_btrfs(backup_generic):
|
|||||||
filelist.sort()
|
filelist.sort()
|
||||||
filelist.reverse()
|
filelist.reverse()
|
||||||
full = ''
|
full = ''
|
||||||
r_full = re.compile('^\d{8,8}-\d{2,2}h\d{2,2}m\d{2,2}$')
|
r_full = re.compile('^\d{8,8}-\d{2,2}h\d{2,2}m\d{2,2}$')
|
||||||
r_partial = re.compile('^\d{8,8}-\d{2,2}h\d{2,2}m\d{2,2}.rsync$')
|
r_partial = re.compile('^\d{8,8}-\d{2,2}h\d{2,2}m\d{2,2}.rsync$')
|
||||||
# we take all latest partials younger than the latest full and the latest full
|
# we take all latest partials younger than the latest full and the latest full
|
||||||
for item in filelist:
|
for item in filelist:
|
||||||
if r_partial.match(item) and item<current:
|
if r_partial.match(item) and item<current:
|
||||||
@ -263,7 +262,7 @@ class backup_rsync_btrfs(backup_generic):
|
|||||||
|
|
||||||
filelist = os.listdir(self.backup_dir)
|
filelist = os.listdir(self.backup_dir)
|
||||||
filelist.sort()
|
filelist.sort()
|
||||||
p = re.compile('^\d{8,8}-\d{2,2}h\d{2,2}m\d{2,2}$')
|
p = re.compile('^\d{8,8}-\d{2,2}h\d{2,2}m\d{2,2}$')
|
||||||
for item in filelist:
|
for item in filelist:
|
||||||
if p.match(item):
|
if p.match(item):
|
||||||
dir_name = os.path.join(self.backup_dir,item)
|
dir_name = os.path.join(self.backup_dir,item)
|
||||||
@ -306,7 +305,7 @@ class backup_rsync_btrfs(backup_generic):
|
|||||||
return False
|
return False
|
||||||
else:
|
else:
|
||||||
self.logger.info("[" + self.backup_name + "] incorrrect lock file : no pid line")
|
self.logger.info("[" + self.backup_name + "] incorrrect lock file : no pid line")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
def set_lock(self):
|
def set_lock(self):
|
||||||
@ -335,7 +334,7 @@ class backup_rsync_btrfs(backup_generic):
|
|||||||
|
|
||||||
class backup_rsync__btrfs_ssh(backup_rsync_btrfs):
|
class backup_rsync__btrfs_ssh(backup_rsync_btrfs):
|
||||||
"""Backup a directory on remote server with rsync,ssh and btrfs protocol (requires rsync software on remote host)"""
|
"""Backup a directory on remote server with rsync,ssh and btrfs protocol (requires rsync software on remote host)"""
|
||||||
type = 'rsync+btrfs+ssh'
|
type = 'rsync+btrfs+ssh'
|
||||||
required_params = backup_generic.required_params + ['remote_user','remote_dir','private_key']
|
required_params = backup_generic.required_params + ['remote_user','remote_dir','private_key']
|
||||||
optional_params = backup_generic.optional_params + ['compression','bwlimit','ssh_port','exclude_list','protect_args','overload_args','cipher_spec']
|
optional_params = backup_generic.optional_params + ['compression','bwlimit','ssh_port','exclude_list','protect_args','overload_args','cipher_spec']
|
||||||
cipher_spec = ''
|
cipher_spec = ''
|
||||||
@ -359,4 +358,3 @@ if __name__=='__main__':
|
|||||||
b.read_config(cp)
|
b.read_config(cp)
|
||||||
b.process_backup()
|
b.process_backup()
|
||||||
print((b.checknagios()))
|
print((b.checknagios()))
|
||||||
|
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
|
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
try:
|
try:
|
||||||
sys.stderr = open('/dev/null') # Silence silly warnings from paramiko
|
sys.stderr = open('/dev/null') # Silence silly warnings from paramiko
|
||||||
import paramiko
|
import paramiko
|
||||||
@ -32,6 +33,7 @@ sys.stderr = sys.__stderr__
|
|||||||
|
|
||||||
from .common import *
|
from .common import *
|
||||||
|
|
||||||
|
|
||||||
class backup_samba4(backup_generic):
|
class backup_samba4(backup_generic):
|
||||||
"""Backup a samba4 databases as gzipped tdbs file through ssh"""
|
"""Backup a samba4 databases as gzipped tdbs file through ssh"""
|
||||||
type = 'samba4'
|
type = 'samba4'
|
||||||
@ -163,4 +165,4 @@ class backup_samba4(backup_generic):
|
|||||||
self.logger.info('Skipping %s, already registered',dir_name)
|
self.logger.info('Skipping %s, already registered',dir_name)
|
||||||
|
|
||||||
|
|
||||||
register_driver(backup_samba4)
|
register_driver(backup_samba4)
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
|
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
try:
|
try:
|
||||||
sys.stderr = open('/dev/null') # Silence silly warnings from paramiko
|
sys.stderr = open('/dev/null') # Silence silly warnings from paramiko
|
||||||
import paramiko
|
import paramiko
|
||||||
@ -30,11 +31,13 @@ except ImportError as e:
|
|||||||
|
|
||||||
sys.stderr = sys.__stderr__
|
sys.stderr = sys.__stderr__
|
||||||
|
|
||||||
import datetime
|
|
||||||
import base64
|
import base64
|
||||||
|
import datetime
|
||||||
import os
|
import os
|
||||||
|
|
||||||
from .common import *
|
from .common import *
|
||||||
|
|
||||||
|
|
||||||
class backup_sqlserver(backup_generic):
|
class backup_sqlserver(backup_generic):
|
||||||
"""Backup a SQLSERVER database as gzipped sql file through ssh"""
|
"""Backup a SQLSERVER database as gzipped sql file through ssh"""
|
||||||
type = 'sqlserver+ssh'
|
type = 'sqlserver+ssh'
|
||||||
|
@ -18,23 +18,26 @@
|
|||||||
#
|
#
|
||||||
# -----------------------------------------------------------------------
|
# -----------------------------------------------------------------------
|
||||||
|
|
||||||
import os
|
|
||||||
import datetime
|
|
||||||
from .common import *
|
|
||||||
from . import XenAPI
|
|
||||||
import time
|
|
||||||
import logging
|
|
||||||
import re
|
|
||||||
import os.path
|
|
||||||
import datetime
|
|
||||||
import select
|
|
||||||
import urllib.request, urllib.error, urllib.parse, urllib.request, urllib.parse, urllib.error
|
|
||||||
import base64
|
import base64
|
||||||
|
import datetime
|
||||||
|
import logging
|
||||||
|
import os
|
||||||
|
import os.path
|
||||||
|
import re
|
||||||
|
import select
|
||||||
import socket
|
import socket
|
||||||
import requests
|
import time
|
||||||
import pexpect
|
import urllib.error
|
||||||
|
import urllib.parse
|
||||||
|
import urllib.request
|
||||||
from stat import *
|
from stat import *
|
||||||
|
|
||||||
|
import pexpect
|
||||||
|
import requests
|
||||||
|
|
||||||
|
from . import XenAPI
|
||||||
|
from .common import *
|
||||||
|
|
||||||
|
|
||||||
class backup_switch(backup_generic):
|
class backup_switch(backup_generic):
|
||||||
"""Backup a startup-config on a switch"""
|
"""Backup a startup-config on a switch"""
|
||||||
@ -149,7 +152,7 @@ class backup_switch(backup_generic):
|
|||||||
else:
|
else:
|
||||||
child.sendline(self.switch_user)
|
child.sendline(self.switch_user)
|
||||||
child.expect(".*#")
|
child.expect(".*#")
|
||||||
|
|
||||||
child.sendline( "terminal datadump")
|
child.sendline( "terminal datadump")
|
||||||
child.expect("#")
|
child.expect("#")
|
||||||
child.sendline( "show startup-config")
|
child.sendline( "show startup-config")
|
||||||
@ -259,4 +262,3 @@ if __name__=='__main__':
|
|||||||
cp.read('/opt/tisbackup/configtest.ini')
|
cp.read('/opt/tisbackup/configtest.ini')
|
||||||
b = backup_xva()
|
b = backup_xva()
|
||||||
b.read_config(cp)
|
b.read_config(cp)
|
||||||
|
|
||||||
|
@ -18,25 +18,25 @@
|
|||||||
#
|
#
|
||||||
# -----------------------------------------------------------------------
|
# -----------------------------------------------------------------------
|
||||||
|
|
||||||
from .common import *
|
|
||||||
import pyVmomi
|
|
||||||
from pyVmomi import vim
|
|
||||||
from pyVmomi import vmodl
|
|
||||||
from pyVim.connect import SmartConnect, Disconnect
|
|
||||||
|
|
||||||
from datetime import datetime, date, timedelta
|
|
||||||
import atexit
|
import atexit
|
||||||
import getpass
|
import getpass
|
||||||
|
from datetime import date, datetime, timedelta
|
||||||
|
|
||||||
|
import pyVmomi
|
||||||
import requests
|
import requests
|
||||||
|
from pyVim.connect import Disconnect, SmartConnect
|
||||||
|
from pyVmomi import vim, vmodl
|
||||||
# Disable HTTPS verification warnings.
|
# Disable HTTPS verification warnings.
|
||||||
from requests.packages import urllib3
|
from requests.packages import urllib3
|
||||||
|
|
||||||
|
from .common import *
|
||||||
|
|
||||||
urllib3.disable_warnings()
|
urllib3.disable_warnings()
|
||||||
import os
|
import os
|
||||||
import time
|
import re
|
||||||
import tarfile
|
import tarfile
|
||||||
import re
|
import time
|
||||||
import xml.etree.ElementTree as ET
|
import xml.etree.ElementTree as ET
|
||||||
|
|
||||||
from stat import *
|
from stat import *
|
||||||
|
|
||||||
|
|
||||||
@ -59,15 +59,15 @@ class backup_vmdk(backup_generic):
|
|||||||
cookie_text = " " + cookie_value + "; $" + cookie_path
|
cookie_text = " " + cookie_value + "; $" + cookie_path
|
||||||
# Make a cookie
|
# Make a cookie
|
||||||
cookie = dict()
|
cookie = dict()
|
||||||
cookie[cookie_name] = cookie_text
|
cookie[cookie_name] = cookie_text
|
||||||
return cookie
|
return cookie
|
||||||
|
|
||||||
|
|
||||||
def download_file(self,url, local_filename, cookie, headers):
|
def download_file(self,url, local_filename, cookie, headers):
|
||||||
r = requests.get(url, stream=True, headers=headers,cookies=cookie,verify=False)
|
r = requests.get(url, stream=True, headers=headers,cookies=cookie,verify=False)
|
||||||
with open(local_filename, 'wb') as f:
|
with open(local_filename, 'wb') as f:
|
||||||
for chunk in r.iter_content(chunk_size=1024*1024*64):
|
for chunk in r.iter_content(chunk_size=1024*1024*64):
|
||||||
if chunk:
|
if chunk:
|
||||||
f.write(chunk)
|
f.write(chunk)
|
||||||
f.flush()
|
f.flush()
|
||||||
return local_filename
|
return local_filename
|
||||||
@ -78,7 +78,7 @@ class backup_vmdk(backup_generic):
|
|||||||
try:
|
try:
|
||||||
infos = HttpNfcLease.info
|
infos = HttpNfcLease.info
|
||||||
device_urls = infos.deviceUrl
|
device_urls = infos.deviceUrl
|
||||||
vmdks = []
|
vmdks = []
|
||||||
for device_url in device_urls:
|
for device_url in device_urls:
|
||||||
deviceId = device_url.key
|
deviceId = device_url.key
|
||||||
deviceUrlStr = device_url.url
|
deviceUrlStr = device_url.url
|
||||||
@ -89,7 +89,7 @@ class backup_vmdk(backup_generic):
|
|||||||
cookie = self.make_compatible_cookie(si._stub.cookie)
|
cookie = self.make_compatible_cookie(si._stub.cookie)
|
||||||
headers = {'Content-Type': 'application/octet-stream'}
|
headers = {'Content-Type': 'application/octet-stream'}
|
||||||
self.logger.debug("[%s] exporting disk: %s" %(self.server_name,diskFileName))
|
self.logger.debug("[%s] exporting disk: %s" %(self.server_name,diskFileName))
|
||||||
|
|
||||||
self.download_file(diskUrlStr, diskFileName, cookie, headers)
|
self.download_file(diskUrlStr, diskFileName, cookie, headers)
|
||||||
vmdks.append({"filename":diskFileName,"id":deviceId})
|
vmdks.append({"filename":diskFileName,"id":deviceId})
|
||||||
finally:
|
finally:
|
||||||
@ -99,8 +99,8 @@ class backup_vmdk(backup_generic):
|
|||||||
|
|
||||||
def create_ovf(self,vm,vmdks):
|
def create_ovf(self,vm,vmdks):
|
||||||
ovfDescParams = vim.OvfManager.CreateDescriptorParams()
|
ovfDescParams = vim.OvfManager.CreateDescriptorParams()
|
||||||
ovf = si.content.ovfManager.CreateDescriptor(vm, ovfDescParams)
|
ovf = si.content.ovfManager.CreateDescriptor(vm, ovfDescParams)
|
||||||
root = ET.fromstring(ovf.ovfDescriptor)
|
root = ET.fromstring(ovf.ovfDescriptor)
|
||||||
new_id = list(root[0][1].attrib.values())[0][1:3]
|
new_id = list(root[0][1].attrib.values())[0][1:3]
|
||||||
ovfFiles = []
|
ovfFiles = []
|
||||||
for vmdk in vmdks:
|
for vmdk in vmdks:
|
||||||
@ -109,14 +109,14 @@ class backup_vmdk(backup_generic):
|
|||||||
ovfFiles.append(vim.OvfManager.OvfFile(size=os.path.getsize(vmdk['filename']), path=vmdk['filename'], deviceId=id))
|
ovfFiles.append(vim.OvfManager.OvfFile(size=os.path.getsize(vmdk['filename']), path=vmdk['filename'], deviceId=id))
|
||||||
|
|
||||||
ovfDescParams = vim.OvfManager.CreateDescriptorParams()
|
ovfDescParams = vim.OvfManager.CreateDescriptorParams()
|
||||||
ovfDescParams.ovfFiles = ovfFiles;
|
ovfDescParams.ovfFiles = ovfFiles;
|
||||||
|
|
||||||
ovf = si.content.ovfManager.CreateDescriptor(vm, ovfDescParams)
|
ovf = si.content.ovfManager.CreateDescriptor(vm, ovfDescParams)
|
||||||
ovf_filename = vm.name+".ovf"
|
ovf_filename = vm.name+".ovf"
|
||||||
self.logger.debug("[%s] creating ovf file: %s" %(self.server_name,ovf_filename))
|
self.logger.debug("[%s] creating ovf file: %s" %(self.server_name,ovf_filename))
|
||||||
|
|
||||||
with open(ovf_filename, "w") as f:
|
with open(ovf_filename, "w") as f:
|
||||||
f.write(ovf.ovfDescriptor)
|
f.write(ovf.ovfDescriptor)
|
||||||
return ovf_filename
|
return ovf_filename
|
||||||
|
|
||||||
def create_ova(self,vm, vmdks, ovf_filename):
|
def create_ova(self,vm, vmdks, ovf_filename):
|
||||||
@ -131,9 +131,9 @@ class backup_vmdk(backup_generic):
|
|||||||
|
|
||||||
def clone_vm(self,vm):
|
def clone_vm(self,vm):
|
||||||
task = self.wait_task(vm.CreateSnapshot_Task(name="backup",description="Automatic backup "+datetime.now().strftime("%Y-%m-%d %H:%M:%s"),memory=False,quiesce=True))
|
task = self.wait_task(vm.CreateSnapshot_Task(name="backup",description="Automatic backup "+datetime.now().strftime("%Y-%m-%d %H:%M:%s"),memory=False,quiesce=True))
|
||||||
snapshot=task.info.result
|
snapshot=task.info.result
|
||||||
prefix_vmclone = self.prefix_clone
|
prefix_vmclone = self.prefix_clone
|
||||||
clone_name = prefix_vmclone + vm.name
|
clone_name = prefix_vmclone + vm.name
|
||||||
datastore = '[%s]' % vm.datastore[0].name
|
datastore = '[%s]' % vm.datastore[0].name
|
||||||
|
|
||||||
|
|
||||||
@ -146,16 +146,16 @@ class backup_vmdk(backup_generic):
|
|||||||
config = vim.vm.ConfigSpec(name=clone_name, memoryMB=vm.summary.config.memorySizeMB, numCPUs=vm.summary.config.numCpu, files=vmx_file)
|
config = vim.vm.ConfigSpec(name=clone_name, memoryMB=vm.summary.config.memorySizeMB, numCPUs=vm.summary.config.numCpu, files=vmx_file)
|
||||||
|
|
||||||
hosts = datacenter.hostFolder.childEntity
|
hosts = datacenter.hostFolder.childEntity
|
||||||
resource_pool = hosts[0].resourcePool
|
resource_pool = hosts[0].resourcePool
|
||||||
|
|
||||||
self.wait_task(vmFolder.CreateVM_Task(config=config,pool=resource_pool))
|
self.wait_task(vmFolder.CreateVM_Task(config=config,pool=resource_pool))
|
||||||
|
|
||||||
new_vm = [x for x in vmFolder.childEntity if x.name == clone_name][0]
|
new_vm = [x for x in vmFolder.childEntity if x.name == clone_name][0]
|
||||||
|
|
||||||
controller = vim.vm.device.VirtualDeviceSpec()
|
controller = vim.vm.device.VirtualDeviceSpec()
|
||||||
controller.operation = vim.vm.device.VirtualDeviceSpec.Operation.add
|
controller.operation = vim.vm.device.VirtualDeviceSpec.Operation.add
|
||||||
controller.device = vim.vm.device.VirtualLsiLogicController(busNumber=0,sharedBus='noSharing')
|
controller.device = vim.vm.device.VirtualLsiLogicController(busNumber=0,sharedBus='noSharing')
|
||||||
controller.device.key = 0
|
controller.device.key = 0
|
||||||
i=0
|
i=0
|
||||||
|
|
||||||
vm_devices = []
|
vm_devices = []
|
||||||
@ -189,7 +189,7 @@ class backup_vmdk(backup_generic):
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
vm_devices.append(controller)
|
vm_devices.append(controller)
|
||||||
|
|
||||||
config.deviceChange=vm_devices
|
config.deviceChange=vm_devices
|
||||||
self.wait_task(new_vm.ReconfigVM_Task(config))
|
self.wait_task(new_vm.ReconfigVM_Task(config))
|
||||||
@ -198,7 +198,7 @@ class backup_vmdk(backup_generic):
|
|||||||
def wait_task(self,task):
|
def wait_task(self,task):
|
||||||
while task.info.state in ["queued", "running"]:
|
while task.info.state in ["queued", "running"]:
|
||||||
time.sleep(2)
|
time.sleep(2)
|
||||||
self.logger.debug("[%s] %s",self.server_name,task.info.descriptionId)
|
self.logger.debug("[%s] %s",self.server_name,task.info.descriptionId)
|
||||||
return task
|
return task
|
||||||
|
|
||||||
|
|
||||||
@ -213,7 +213,7 @@ class backup_vmdk(backup_generic):
|
|||||||
else:
|
else:
|
||||||
print('mkdir "%s"' % dest_dir)
|
print('mkdir "%s"' % dest_dir)
|
||||||
else:
|
else:
|
||||||
raise Exception('backup destination directory already exists : %s' % dest_dir)
|
raise Exception('backup destination directory already exists : %s' % dest_dir)
|
||||||
os.chdir(dest_dir)
|
os.chdir(dest_dir)
|
||||||
user_esx, password_esx, null = open(self.password_file).read().split('\n')
|
user_esx, password_esx, null = open(self.password_file).read().split('\n')
|
||||||
|
|
||||||
@ -237,27 +237,27 @@ class backup_vmdk(backup_generic):
|
|||||||
if vm.name == self.server_name:
|
if vm.name == self.server_name:
|
||||||
vm_is_off = vm.summary.runtime.powerState == "poweredOff"
|
vm_is_off = vm.summary.runtime.powerState == "poweredOff"
|
||||||
if str2bool(self.halt_vm):
|
if str2bool(self.halt_vm):
|
||||||
vm.ShutdownGuest()
|
vm.ShutdownGuest()
|
||||||
vm_is_off = True
|
vm_is_off = True
|
||||||
|
|
||||||
if vm_is_off:
|
if vm_is_off:
|
||||||
vmdks = self.export_vmdks(vm)
|
vmdks = self.export_vmdks(vm)
|
||||||
ovf_filename = self.create_ovf(vm, vmdks)
|
ovf_filename = self.create_ovf(vm, vmdks)
|
||||||
else:
|
else:
|
||||||
new_vm = self.clone_vm(vm)
|
new_vm = self.clone_vm(vm)
|
||||||
vmdks = self.export_vmdks(new_vm)
|
vmdks = self.export_vmdks(new_vm)
|
||||||
ovf_filename = self.create_ovf(vm, vmdks)
|
ovf_filename = self.create_ovf(vm, vmdks)
|
||||||
self.wait_task(new_vm.Destroy_Task())
|
self.wait_task(new_vm.Destroy_Task())
|
||||||
|
|
||||||
if str2bool(self.create_ovafile):
|
if str2bool(self.create_ovafile):
|
||||||
ova_filename = self.create_ova(vm, vmdks, ovf_filename)
|
ova_filename = self.create_ova(vm, vmdks, ovf_filename)
|
||||||
|
|
||||||
if str2bool(self.halt_vm):
|
if str2bool(self.halt_vm):
|
||||||
vm.PowerOnVM()
|
vm.PowerOnVM()
|
||||||
|
|
||||||
|
|
||||||
if os.path.exists(dest_dir):
|
if os.path.exists(dest_dir):
|
||||||
for file in os.listdir(dest_dir):
|
for file in os.listdir(dest_dir):
|
||||||
stats['written_bytes'] += os.stat(file)[ST_SIZE]
|
stats['written_bytes'] += os.stat(file)[ST_SIZE]
|
||||||
stats['total_files_count'] += 1
|
stats['total_files_count'] += 1
|
||||||
stats['written_files_count'] += 1
|
stats['written_files_count'] += 1
|
||||||
@ -266,10 +266,10 @@ class backup_vmdk(backup_generic):
|
|||||||
stats['written_bytes'] = 0
|
stats['written_bytes'] = 0
|
||||||
|
|
||||||
stats['backup_location'] = dest_dir
|
stats['backup_location'] = dest_dir
|
||||||
|
|
||||||
stats['log']='XVA backup from %s OK, %d bytes written' % (self.server_name,stats['written_bytes'])
|
stats['log']='XVA backup from %s OK, %d bytes written' % (self.server_name,stats['written_bytes'])
|
||||||
stats['status']='OK'
|
stats['status']='OK'
|
||||||
|
|
||||||
|
|
||||||
except BaseException as e:
|
except BaseException as e:
|
||||||
stats['status']='ERROR'
|
stats['status']='ERROR'
|
||||||
@ -279,4 +279,3 @@ class backup_vmdk(backup_generic):
|
|||||||
|
|
||||||
|
|
||||||
register_driver(backup_vmdk)
|
register_driver(backup_vmdk)
|
||||||
|
|
||||||
|
@ -20,12 +20,14 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
from .common import *
|
|
||||||
import paramiko
|
import paramiko
|
||||||
|
|
||||||
|
from .common import *
|
||||||
|
|
||||||
|
|
||||||
class backup_xcp_metadata(backup_generic):
|
class backup_xcp_metadata(backup_generic):
|
||||||
"""Backup metatdata of a xcp pool using xe pool-dump-database"""
|
"""Backup metatdata of a xcp pool using xe pool-dump-database"""
|
||||||
type = 'xcp-dump-metadata'
|
type = 'xcp-dump-metadata'
|
||||||
required_params = ['type','server_name','private_key','backup_name']
|
required_params = ['type','server_name','private_key','backup_name']
|
||||||
|
|
||||||
def do_backup(self,stats):
|
def do_backup(self,stats):
|
||||||
@ -58,7 +60,7 @@ class backup_xcp_metadata(backup_generic):
|
|||||||
stats['total_files_count']=1
|
stats['total_files_count']=1
|
||||||
stats['written_files_count']=1
|
stats['written_files_count']=1
|
||||||
stats['total_bytes']=os.stat(localpath).st_size
|
stats['total_bytes']=os.stat(localpath).st_size
|
||||||
stats['written_bytes']=os.stat(localpath).st_size
|
stats['written_bytes']=os.stat(localpath).st_size
|
||||||
stats['log']='gzip dump of DB %s:%s (%d bytes) to %s' % (self.server_name,'xcp metadata dump', stats['written_bytes'], localpath)
|
stats['log']='gzip dump of DB %s:%s (%d bytes) to %s' % (self.server_name,'xcp metadata dump', stats['written_bytes'], localpath)
|
||||||
stats['backup_location'] = localpath
|
stats['backup_location'] = localpath
|
||||||
stats['status']='OK'
|
stats['status']='OK'
|
||||||
@ -72,7 +74,7 @@ class backup_xcp_metadata(backup_generic):
|
|||||||
|
|
||||||
filelist = os.listdir(self.backup_dir)
|
filelist = os.listdir(self.backup_dir)
|
||||||
filelist.sort()
|
filelist.sort()
|
||||||
p = re.compile('^%s-(?P<date>\d{8,8}-\d{2,2}h\d{2,2}m\d{2,2}).dump.gz$' % self.server_name)
|
p = re.compile('^%s-(?P<date>\d{8,8}-\d{2,2}h\d{2,2}m\d{2,2}).dump.gz$' % self.server_name)
|
||||||
for item in filelist:
|
for item in filelist:
|
||||||
sr = p.match(item)
|
sr = p.match(item)
|
||||||
if sr:
|
if sr:
|
||||||
@ -82,7 +84,7 @@ class backup_xcp_metadata(backup_generic):
|
|||||||
self.logger.info('Registering %s from %s',file_name,fileisodate(file_name))
|
self.logger.info('Registering %s from %s',file_name,fileisodate(file_name))
|
||||||
size_bytes = int(os.popen('du -sb "%s"' % file_name).read().split('\t')[0])
|
size_bytes = int(os.popen('du -sb "%s"' % file_name).read().split('\t')[0])
|
||||||
self.logger.debug(' Size in bytes : %i',size_bytes)
|
self.logger.debug(' Size in bytes : %i',size_bytes)
|
||||||
if not self.dry_run:
|
if not self.dry_run:
|
||||||
self.dbstat.add(self.backup_name,self.server_name,'',\
|
self.dbstat.add(self.backup_name,self.server_name,'',\
|
||||||
backup_start=start,backup_end=fileisodate(file_name),status='OK',total_bytes=size_bytes,backup_location=file_name)
|
backup_start=start,backup_end=fileisodate(file_name),status='OK',total_bytes=size_bytes,backup_location=file_name)
|
||||||
else:
|
else:
|
||||||
|
@ -18,20 +18,23 @@
|
|||||||
#
|
#
|
||||||
# -----------------------------------------------------------------------
|
# -----------------------------------------------------------------------
|
||||||
|
|
||||||
import logging
|
|
||||||
import re
|
|
||||||
import os
|
|
||||||
import datetime
|
import datetime
|
||||||
import urllib.request, urllib.parse, urllib.error
|
|
||||||
import socket
|
|
||||||
import tarfile
|
|
||||||
import hashlib
|
import hashlib
|
||||||
from stat import *
|
import logging
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
import socket
|
||||||
import ssl
|
import ssl
|
||||||
|
import tarfile
|
||||||
|
import urllib.error
|
||||||
|
import urllib.parse
|
||||||
|
import urllib.request
|
||||||
|
from stat import *
|
||||||
|
|
||||||
import requests
|
import requests
|
||||||
|
|
||||||
from .common import *
|
|
||||||
from . import XenAPI
|
from . import XenAPI
|
||||||
|
from .common import *
|
||||||
|
|
||||||
if hasattr(ssl, '_create_unverified_context'):
|
if hasattr(ssl, '_create_unverified_context'):
|
||||||
ssl._create_default_https_context = ssl._create_unverified_context
|
ssl._create_default_https_context = ssl._create_unverified_context
|
||||||
|
@ -18,19 +18,19 @@
|
|||||||
#
|
#
|
||||||
# -----------------------------------------------------------------------
|
# -----------------------------------------------------------------------
|
||||||
|
|
||||||
from abc import ABC, abstractmethod
|
|
||||||
import os
|
|
||||||
import subprocess
|
|
||||||
import re
|
|
||||||
import logging
|
|
||||||
import datetime
|
import datetime
|
||||||
import time
|
import logging
|
||||||
from iniparse import ConfigParser
|
import os
|
||||||
import sqlite3
|
import re
|
||||||
import shutil
|
|
||||||
import select
|
import select
|
||||||
|
import shutil
|
||||||
|
import sqlite3
|
||||||
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
|
import time
|
||||||
|
from abc import ABC, abstractmethod
|
||||||
|
|
||||||
|
from iniparse import ConfigParser
|
||||||
|
|
||||||
try:
|
try:
|
||||||
sys.stderr = open('/dev/null') # Silence silly warnings from paramiko
|
sys.stderr = open('/dev/null') # Silence silly warnings from paramiko
|
||||||
|
@ -18,23 +18,25 @@
|
|||||||
#
|
#
|
||||||
# -----------------------------------------------------------------------
|
# -----------------------------------------------------------------------
|
||||||
|
|
||||||
import os
|
|
||||||
import datetime
|
|
||||||
from .common import *
|
|
||||||
from . import XenAPI
|
|
||||||
import time
|
|
||||||
import logging
|
|
||||||
import re
|
|
||||||
import os.path
|
|
||||||
import os
|
|
||||||
import datetime
|
|
||||||
import select
|
|
||||||
import urllib.request, urllib.error, urllib.parse
|
|
||||||
import base64
|
import base64
|
||||||
|
import datetime
|
||||||
|
import logging
|
||||||
|
import os
|
||||||
|
import os.path
|
||||||
|
import re
|
||||||
|
import select
|
||||||
import socket
|
import socket
|
||||||
|
import ssl
|
||||||
|
import time
|
||||||
|
import urllib.error
|
||||||
|
import urllib.parse
|
||||||
|
import urllib.request
|
||||||
from stat import *
|
from stat import *
|
||||||
import ssl
|
|
||||||
if hasattr(ssl, '_create_unverified_context'):
|
from . import XenAPI
|
||||||
|
from .common import *
|
||||||
|
|
||||||
|
if hasattr(ssl, '_create_unverified_context'):
|
||||||
ssl._create_default_https_context = ssl._create_unverified_context
|
ssl._create_default_https_context = ssl._create_unverified_context
|
||||||
|
|
||||||
|
|
||||||
@ -44,23 +46,23 @@ class copy_vm_xcp(backup_generic):
|
|||||||
|
|
||||||
required_params = backup_generic.required_params + ['server_name','storage_name','password_file','vm_name','network_name']
|
required_params = backup_generic.required_params + ['server_name','storage_name','password_file','vm_name','network_name']
|
||||||
optional_params = backup_generic.optional_params + ['start_vm','max_copies', 'delete_snapshot', 'halt_vm']
|
optional_params = backup_generic.optional_params + ['start_vm','max_copies', 'delete_snapshot', 'halt_vm']
|
||||||
|
|
||||||
start_vm = "no"
|
start_vm = "no"
|
||||||
max_copies = 1
|
max_copies = 1
|
||||||
halt_vm = "no"
|
halt_vm = "no"
|
||||||
delete_snapshot = "yes"
|
delete_snapshot = "yes"
|
||||||
|
|
||||||
def read_config(self,iniconf):
|
def read_config(self,iniconf):
|
||||||
assert(isinstance(iniconf,ConfigParser))
|
assert(isinstance(iniconf,ConfigParser))
|
||||||
backup_generic.read_config(self,iniconf)
|
backup_generic.read_config(self,iniconf)
|
||||||
if self.start_vm in 'no' and iniconf.has_option('global','start_vm'):
|
if self.start_vm in 'no' and iniconf.has_option('global','start_vm'):
|
||||||
self.start_vm = iniconf.get('global','start_vm')
|
self.start_vm = iniconf.get('global','start_vm')
|
||||||
if self.max_copies == 1 and iniconf.has_option('global','max_copies'):
|
if self.max_copies == 1 and iniconf.has_option('global','max_copies'):
|
||||||
self.max_copies = iniconf.getint('global','max_copies')
|
self.max_copies = iniconf.getint('global','max_copies')
|
||||||
if self.delete_snapshot == "yes" and iniconf.has_option('global','delete_snapshot'):
|
if self.delete_snapshot == "yes" and iniconf.has_option('global','delete_snapshot'):
|
||||||
self.delete_snapshot = iniconf.get('global','delete_snapshot')
|
self.delete_snapshot = iniconf.get('global','delete_snapshot')
|
||||||
|
|
||||||
|
|
||||||
def copy_vm_to_sr(self, vm_name, storage_name, dry_run, delete_snapshot="yes"):
|
def copy_vm_to_sr(self, vm_name, storage_name, dry_run, delete_snapshot="yes"):
|
||||||
user_xen, password_xen, null = open(self.password_file).read().split('\n')
|
user_xen, password_xen, null = open(self.password_file).read().split('\n')
|
||||||
session = XenAPI.Session('https://'+self.server_name)
|
session = XenAPI.Session('https://'+self.server_name)
|
||||||
@ -68,25 +70,25 @@ class copy_vm_xcp(backup_generic):
|
|||||||
session.login_with_password(user_xen,password_xen)
|
session.login_with_password(user_xen,password_xen)
|
||||||
except XenAPI.Failure as error:
|
except XenAPI.Failure as error:
|
||||||
msg,ip = error.details
|
msg,ip = error.details
|
||||||
|
|
||||||
if msg == 'HOST_IS_SLAVE':
|
if msg == 'HOST_IS_SLAVE':
|
||||||
server_name = ip
|
server_name = ip
|
||||||
session = XenAPI.Session('https://'+server_name)
|
session = XenAPI.Session('https://'+server_name)
|
||||||
session.login_with_password(user_xen,password_xen)
|
session.login_with_password(user_xen,password_xen)
|
||||||
|
|
||||||
|
|
||||||
self.logger.debug("[%s] VM (%s) to backup in storage: %s",self.backup_name,vm_name,storage_name)
|
self.logger.debug("[%s] VM (%s) to backup in storage: %s",self.backup_name,vm_name,storage_name)
|
||||||
now = datetime.datetime.now()
|
now = datetime.datetime.now()
|
||||||
|
|
||||||
#get storage opaqueRef
|
#get storage opaqueRef
|
||||||
try:
|
try:
|
||||||
storage = session.xenapi.SR.get_by_name_label(storage_name)[0]
|
storage = session.xenapi.SR.get_by_name_label(storage_name)[0]
|
||||||
except IndexError as error:
|
except IndexError as error:
|
||||||
result = (1,"error get SR opaqueref %s"%(error))
|
result = (1,"error get SR opaqueref %s"%(error))
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
#get vm to copy opaqueRef
|
#get vm to copy opaqueRef
|
||||||
try:
|
try:
|
||||||
vm = session.xenapi.VM.get_by_name_label(vm_name)[0]
|
vm = session.xenapi.VM.get_by_name_label(vm_name)[0]
|
||||||
except IndexError as error:
|
except IndexError as error:
|
||||||
@ -99,96 +101,96 @@ class copy_vm_xcp(backup_generic):
|
|||||||
except IndexError as error:
|
except IndexError as error:
|
||||||
result = (1, "error get VM network opaqueref %s" % (error))
|
result = (1, "error get VM network opaqueref %s" % (error))
|
||||||
return result
|
return result
|
||||||
|
|
||||||
if str2bool(self.halt_vm):
|
if str2bool(self.halt_vm):
|
||||||
status_vm = session.xenapi.VM.get_power_state(vm)
|
status_vm = session.xenapi.VM.get_power_state(vm)
|
||||||
self.logger.debug("[%s] Status of VM: %s",self.backup_name,status_vm)
|
self.logger.debug("[%s] Status of VM: %s",self.backup_name,status_vm)
|
||||||
if status_vm == "Running":
|
if status_vm == "Running":
|
||||||
self.logger.debug("[%s] Shutdown in progress",self.backup_name)
|
self.logger.debug("[%s] Shutdown in progress",self.backup_name)
|
||||||
if dry_run:
|
if dry_run:
|
||||||
print("session.xenapi.VM.clean_shutdown(vm)")
|
print("session.xenapi.VM.clean_shutdown(vm)")
|
||||||
else:
|
else:
|
||||||
session.xenapi.VM.clean_shutdown(vm)
|
session.xenapi.VM.clean_shutdown(vm)
|
||||||
snapshot = vm
|
snapshot = vm
|
||||||
else:
|
else:
|
||||||
#do the snapshot
|
#do the snapshot
|
||||||
self.logger.debug("[%s] Snapshot in progress",self.backup_name)
|
self.logger.debug("[%s] Snapshot in progress",self.backup_name)
|
||||||
try:
|
try:
|
||||||
snapshot = session.xenapi.VM.snapshot(vm,"tisbackup-%s"%(vm_name))
|
snapshot = session.xenapi.VM.snapshot(vm,"tisbackup-%s"%(vm_name))
|
||||||
except XenAPI.Failure as error:
|
except XenAPI.Failure as error:
|
||||||
result = (1,"error when snapshot %s"%(error))
|
result = (1,"error when snapshot %s"%(error))
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
#get snapshot opaqueRef
|
#get snapshot opaqueRef
|
||||||
snapshot = session.xenapi.VM.get_by_name_label("tisbackup-%s"%(vm_name))[0]
|
snapshot = session.xenapi.VM.get_by_name_label("tisbackup-%s"%(vm_name))[0]
|
||||||
session.xenapi.VM.set_name_description(snapshot,"snapshot created by tisbackup on : %s"%(now.strftime("%Y-%m-%d %H:%M")))
|
session.xenapi.VM.set_name_description(snapshot,"snapshot created by tisbackup on : %s"%(now.strftime("%Y-%m-%d %H:%M")))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
vm_backup_name = "zzz-%s-"%(vm_name)
|
vm_backup_name = "zzz-%s-"%(vm_name)
|
||||||
|
|
||||||
|
|
||||||
#Check if old backup exit
|
#Check if old backup exit
|
||||||
list_backups = []
|
list_backups = []
|
||||||
for vm_ref in session.xenapi.VM.get_all():
|
for vm_ref in session.xenapi.VM.get_all():
|
||||||
name_lablel = session.xenapi.VM.get_name_label(vm_ref)
|
name_lablel = session.xenapi.VM.get_name_label(vm_ref)
|
||||||
if vm_backup_name in name_lablel:
|
if vm_backup_name in name_lablel:
|
||||||
list_backups.append(name_lablel)
|
list_backups.append(name_lablel)
|
||||||
|
|
||||||
list_backups.sort()
|
list_backups.sort()
|
||||||
|
|
||||||
if len(list_backups) >= 1:
|
if len(list_backups) >= 1:
|
||||||
|
|
||||||
# Shutting last backup if started
|
# Shutting last backup if started
|
||||||
last_backup_vm = session.xenapi.VM.get_by_name_label(list_backups[-1])[0]
|
last_backup_vm = session.xenapi.VM.get_by_name_label(list_backups[-1])[0]
|
||||||
if not "Halted" in session.xenapi.VM.get_power_state(last_backup_vm):
|
if not "Halted" in session.xenapi.VM.get_power_state(last_backup_vm):
|
||||||
self.logger.debug("[%s] Shutting down last backup vm : %s", self.backup_name, list_backups[-1] )
|
self.logger.debug("[%s] Shutting down last backup vm : %s", self.backup_name, list_backups[-1] )
|
||||||
session.xenapi.VM.hard_shutdown(last_backup_vm)
|
session.xenapi.VM.hard_shutdown(last_backup_vm)
|
||||||
|
|
||||||
# Delete oldest backup if exist
|
# Delete oldest backup if exist
|
||||||
if len(list_backups) >= int(self.max_copies):
|
if len(list_backups) >= int(self.max_copies):
|
||||||
for i in range(len(list_backups)-int(self.max_copies)+1):
|
for i in range(len(list_backups)-int(self.max_copies)+1):
|
||||||
oldest_backup_vm = session.xenapi.VM.get_by_name_label(list_backups[i])[0]
|
oldest_backup_vm = session.xenapi.VM.get_by_name_label(list_backups[i])[0]
|
||||||
if not "Halted" in session.xenapi.VM.get_power_state(oldest_backup_vm):
|
if not "Halted" in session.xenapi.VM.get_power_state(oldest_backup_vm):
|
||||||
self.logger.debug("[%s] Shutting down old vm : %s", self.backup_name, list_backups[i] )
|
self.logger.debug("[%s] Shutting down old vm : %s", self.backup_name, list_backups[i] )
|
||||||
session.xenapi.VM.hard_shutdown(oldest_backup_vm)
|
session.xenapi.VM.hard_shutdown(oldest_backup_vm)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self.logger.debug("[%s] Deleting old vm : %s", self.backup_name, list_backups[i])
|
self.logger.debug("[%s] Deleting old vm : %s", self.backup_name, list_backups[i])
|
||||||
for vbd in session.xenapi.VM.get_VBDs(oldest_backup_vm):
|
for vbd in session.xenapi.VM.get_VBDs(oldest_backup_vm):
|
||||||
if session.xenapi.VBD.get_type(vbd) == 'CD'and session.xenapi.VBD.get_record(vbd)['empty'] == False:
|
if session.xenapi.VBD.get_type(vbd) == 'CD'and session.xenapi.VBD.get_record(vbd)['empty'] == False:
|
||||||
session.xenapi.VBD.eject(vbd)
|
session.xenapi.VBD.eject(vbd)
|
||||||
else:
|
else:
|
||||||
vdi = session.xenapi.VBD.get_VDI(vbd)
|
vdi = session.xenapi.VBD.get_VDI(vbd)
|
||||||
if not 'NULL' in vdi:
|
if not 'NULL' in vdi:
|
||||||
session.xenapi.VDI.destroy(vdi)
|
session.xenapi.VDI.destroy(vdi)
|
||||||
|
|
||||||
session.xenapi.VM.destroy(oldest_backup_vm)
|
session.xenapi.VM.destroy(oldest_backup_vm)
|
||||||
except XenAPI.Failure as error:
|
except XenAPI.Failure as error:
|
||||||
result = (1,"error when destroy old backup vm %s"%(error))
|
result = (1,"error when destroy old backup vm %s"%(error))
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
self.logger.debug("[%s] Copy %s in progress on %s",self.backup_name,vm_name,storage_name)
|
self.logger.debug("[%s] Copy %s in progress on %s",self.backup_name,vm_name,storage_name)
|
||||||
try:
|
try:
|
||||||
backup_vm = session.xenapi.VM.copy(snapshot,vm_backup_name+now.strftime("%Y-%m-%d %H:%M"),storage)
|
backup_vm = session.xenapi.VM.copy(snapshot,vm_backup_name+now.strftime("%Y-%m-%d %H:%M"),storage)
|
||||||
except XenAPI.Failure as error:
|
except XenAPI.Failure as error:
|
||||||
result = (1,"error when copy %s"%(error))
|
result = (1,"error when copy %s"%(error))
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
# define VM as a template
|
# define VM as a template
|
||||||
session.xenapi.VM.set_is_a_template(backup_vm,False)
|
session.xenapi.VM.set_is_a_template(backup_vm,False)
|
||||||
|
|
||||||
#change the network of the new VM
|
#change the network of the new VM
|
||||||
try:
|
try:
|
||||||
vifDestroy = session.xenapi.VM.get_VIFs(backup_vm)
|
vifDestroy = session.xenapi.VM.get_VIFs(backup_vm)
|
||||||
except IndexError as error:
|
except IndexError as error:
|
||||||
result = (1,"error get VIF opaqueref %s"%(error))
|
result = (1,"error get VIF opaqueref %s"%(error))
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
for i in vifDestroy:
|
for i in vifDestroy:
|
||||||
vifRecord = session.xenapi.VIF.get_record(i)
|
vifRecord = session.xenapi.VIF.get_record(i)
|
||||||
session.xenapi.VIF.destroy(i)
|
session.xenapi.VIF.destroy(i)
|
||||||
@ -216,13 +218,13 @@ class copy_vm_xcp(backup_generic):
|
|||||||
except Exception as error:
|
except Exception as error:
|
||||||
result = (1,error)
|
result = (1,error)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
if self.start_vm in ['true', '1', 't', 'y', 'yes', 'oui']:
|
if self.start_vm in ['true', '1', 't', 'y', 'yes', 'oui']:
|
||||||
session.xenapi.VM.start(backup_vm,False,True)
|
session.xenapi.VM.start(backup_vm,False,True)
|
||||||
|
|
||||||
session.xenapi.VM.set_name_description(backup_vm,"snapshot created by tisbackup on : %s"%(now.strftime("%Y-%m-%d %H:%M")))
|
session.xenapi.VM.set_name_description(backup_vm,"snapshot created by tisbackup on : %s"%(now.strftime("%Y-%m-%d %H:%M")))
|
||||||
|
|
||||||
size_backup = 0
|
size_backup = 0
|
||||||
for vbd in session.xenapi.VM.get_VBDs(backup_vm):
|
for vbd in session.xenapi.VM.get_VBDs(backup_vm):
|
||||||
if session.xenapi.VBD.get_type(vbd) == 'CD' and session.xenapi.VBD.get_record(vbd)['empty'] == False:
|
if session.xenapi.VBD.get_type(vbd) == 'CD' and session.xenapi.VBD.get_record(vbd)['empty'] == False:
|
||||||
@ -231,11 +233,11 @@ class copy_vm_xcp(backup_generic):
|
|||||||
vdi = session.xenapi.VBD.get_VDI(vbd)
|
vdi = session.xenapi.VBD.get_VDI(vbd)
|
||||||
if not 'NULL' in vdi:
|
if not 'NULL' in vdi:
|
||||||
size_backup = size_backup + int(session.xenapi.VDI.get_record(vdi)['physical_utilisation'])
|
size_backup = size_backup + int(session.xenapi.VDI.get_record(vdi)['physical_utilisation'])
|
||||||
|
|
||||||
result = (0,size_backup)
|
result = (0,size_backup)
|
||||||
if self.delete_snapshot == 'no':
|
if self.delete_snapshot == 'no':
|
||||||
return result
|
return result
|
||||||
|
|
||||||
#Disable automatic boot
|
#Disable automatic boot
|
||||||
if 'auto_poweron' in session.xenapi.VM.get_other_config(backup_vm):
|
if 'auto_poweron' in session.xenapi.VM.get_other_config(backup_vm):
|
||||||
session.xenapi.VM.remove_from_other_config(backup_vm, "auto_poweron")
|
session.xenapi.VM.remove_from_other_config(backup_vm, "auto_poweron")
|
||||||
@ -258,25 +260,25 @@ class copy_vm_xcp(backup_generic):
|
|||||||
if status_vm == "Running":
|
if status_vm == "Running":
|
||||||
self.logger.debug("[%s] Starting in progress",self.backup_name)
|
self.logger.debug("[%s] Starting in progress",self.backup_name)
|
||||||
if dry_run:
|
if dry_run:
|
||||||
print("session.xenapi.VM.start(vm,False,True)")
|
print("session.xenapi.VM.start(vm,False,True)")
|
||||||
else:
|
else:
|
||||||
session.xenapi.VM.start(vm,False,True)
|
session.xenapi.VM.start(vm,False,True)
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
def do_backup(self,stats):
|
def do_backup(self,stats):
|
||||||
try:
|
try:
|
||||||
timestamp = int(time.time())
|
timestamp = int(time.time())
|
||||||
cmd = self.copy_vm_to_sr(self.vm_name, self.storage_name, self.dry_run, delete_snapshot=self.delete_snapshot)
|
cmd = self.copy_vm_to_sr(self.vm_name, self.storage_name, self.dry_run, delete_snapshot=self.delete_snapshot)
|
||||||
|
|
||||||
if cmd[0] == 0:
|
if cmd[0] == 0:
|
||||||
timeExec = int(time.time()) - timestamp
|
timeExec = int(time.time()) - timestamp
|
||||||
stats['log']='copy of %s to an other storage OK' % (self.backup_name)
|
stats['log']='copy of %s to an other storage OK' % (self.backup_name)
|
||||||
stats['status']='OK'
|
stats['status']='OK'
|
||||||
stats['total_files_count'] = 1
|
stats['total_files_count'] = 1
|
||||||
stats['total_bytes'] = cmd[1]
|
stats['total_bytes'] = cmd[1]
|
||||||
|
|
||||||
stats['backup_location'] = self.storage_name
|
stats['backup_location'] = self.storage_name
|
||||||
else:
|
else:
|
||||||
stats['status']='ERROR'
|
stats['status']='ERROR'
|
||||||
|
@ -3,18 +3,16 @@
|
|||||||
# Copyright (c) 2007 Tim Lauridsen <tla@rasmil.dk>
|
# Copyright (c) 2007 Tim Lauridsen <tla@rasmil.dk>
|
||||||
# All Rights Reserved. See LICENSE-PSF & LICENSE for details.
|
# All Rights Reserved. See LICENSE-PSF & LICENSE for details.
|
||||||
|
|
||||||
from .ini import INIConfig, change_comment_syntax
|
from .compat import ConfigParser, RawConfigParser, SafeConfigParser
|
||||||
from .config import BasicConfig, ConfigNamespace
|
from .config import BasicConfig, ConfigNamespace
|
||||||
from .compat import RawConfigParser, ConfigParser, SafeConfigParser
|
from .configparser import (DEFAULTSECT, MAX_INTERPOLATION_DEPTH,
|
||||||
|
DuplicateSectionError, InterpolationDepthError,
|
||||||
|
InterpolationMissingOptionError,
|
||||||
|
InterpolationSyntaxError, NoOptionError,
|
||||||
|
NoSectionError)
|
||||||
|
from .ini import INIConfig, change_comment_syntax
|
||||||
from .utils import tidy
|
from .utils import tidy
|
||||||
|
|
||||||
from .configparser import DuplicateSectionError, \
|
|
||||||
NoSectionError, NoOptionError, \
|
|
||||||
InterpolationMissingOptionError, \
|
|
||||||
InterpolationDepthError, \
|
|
||||||
InterpolationSyntaxError, \
|
|
||||||
DEFAULTSECT, MAX_INTERPOLATION_DEPTH
|
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
'BasicConfig', 'ConfigNamespace',
|
'BasicConfig', 'ConfigNamespace',
|
||||||
'INIConfig', 'tidy', 'change_comment_syntax',
|
'INIConfig', 'tidy', 'change_comment_syntax',
|
||||||
|
@ -12,21 +12,18 @@ The underlying INIConfig object can be accessed as cfg.data
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
import re
|
import re
|
||||||
from .configparser import DuplicateSectionError, \
|
|
||||||
NoSectionError, NoOptionError, \
|
|
||||||
InterpolationMissingOptionError, \
|
|
||||||
InterpolationDepthError, \
|
|
||||||
InterpolationSyntaxError, \
|
|
||||||
DEFAULTSECT, MAX_INTERPOLATION_DEPTH
|
|
||||||
|
|
||||||
# These are imported only for compatiability.
|
|
||||||
# The code below does not reference them directly.
|
|
||||||
from .configparser import Error, InterpolationError, \
|
|
||||||
MissingSectionHeaderError, ParsingError
|
|
||||||
|
|
||||||
import six
|
import six
|
||||||
|
|
||||||
from . import ini
|
from . import ini
|
||||||
|
# These are imported only for compatiability.
|
||||||
|
# The code below does not reference them directly.
|
||||||
|
from .configparser import (DEFAULTSECT, MAX_INTERPOLATION_DEPTH,
|
||||||
|
DuplicateSectionError, Error,
|
||||||
|
InterpolationDepthError, InterpolationError,
|
||||||
|
InterpolationMissingOptionError,
|
||||||
|
InterpolationSyntaxError, MissingSectionHeaderError,
|
||||||
|
NoOptionError, NoSectionError, ParsingError)
|
||||||
|
|
||||||
|
|
||||||
class RawConfigParser(object):
|
class RawConfigParser(object):
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
try:
|
try:
|
||||||
from ConfigParser import *
|
|
||||||
# not all objects get imported with __all__
|
# not all objects get imported with __all__
|
||||||
|
from ConfigParser import *
|
||||||
from ConfigParser import Error, InterpolationMissingOptionError
|
from ConfigParser import Error, InterpolationMissingOptionError
|
||||||
except ImportError:
|
except ImportError:
|
||||||
from configparser import *
|
from configparser import *
|
||||||
|
@ -42,11 +42,11 @@ Example:
|
|||||||
# Backward-compatiable with ConfigParser
|
# Backward-compatiable with ConfigParser
|
||||||
|
|
||||||
import re
|
import re
|
||||||
from .configparser import DEFAULTSECT, ParsingError, MissingSectionHeaderError
|
|
||||||
|
|
||||||
import six
|
import six
|
||||||
|
|
||||||
from . import config
|
from . import config
|
||||||
|
from .configparser import DEFAULTSECT, MissingSectionHeaderError, ParsingError
|
||||||
|
|
||||||
|
|
||||||
class LineType(object):
|
class LineType(object):
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
from . import compat
|
from . import compat
|
||||||
from .ini import LineContainer, EmptyLine
|
from .ini import EmptyLine, LineContainer
|
||||||
|
|
||||||
|
|
||||||
def tidy(cfg):
|
def tidy(cfg):
|
||||||
|
10
pyproject.toml
Normal file
10
pyproject.toml
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
[tool.black]
|
||||||
|
line-length = 140
|
||||||
|
|
||||||
|
[tool.ruff]
|
||||||
|
# Allow lines to be as long as 120.
|
||||||
|
line-length = 140
|
||||||
|
indent-width = 4
|
||||||
|
|
||||||
|
[tool.ruff.lint]
|
||||||
|
ignore = ["F401","F403","F405","E402"]
|
7
requirements.txt
Normal file → Executable file
7
requirements.txt
Normal file → Executable file
@ -1,3 +1,10 @@
|
|||||||
six
|
six
|
||||||
requests
|
requests
|
||||||
paramiko
|
paramiko
|
||||||
|
pexpect
|
||||||
|
flask
|
||||||
|
simplejson
|
||||||
|
huey
|
||||||
|
iniparse
|
||||||
|
redis
|
||||||
|
peewee
|
||||||
|
@ -7,9 +7,8 @@ mkdir -p BUILD RPMS
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
VERSION=`git rev-list HEAD --count`
|
VERSION=`git rev-list HEAD --count`
|
||||||
echo $VERSION > __VERSION__
|
echo $VERSION > __VERSION__
|
||||||
|
|
||||||
rpmbuild -bb --buildroot $PWD/builddir -v --clean tis-tisbackup.spec
|
rpmbuild -bb --buildroot $PWD/builddir -v --clean tis-tisbackup.spec
|
||||||
cp RPMS/*/*.rpm .
|
cp RPMS/*/*.rpm .
|
||||||
|
|
||||||
|
@ -15,7 +15,7 @@ Source0: ../
|
|||||||
Prefix: /
|
Prefix: /
|
||||||
|
|
||||||
%if "%{rhel}" == "8"
|
%if "%{rhel}" == "8"
|
||||||
Requires: unzip rsync python3-paramiko python3-pyvmomi nfs-utils python3-flask python3-simplejson autofs python3-pexpect
|
Requires: unzip rsync python3-paramiko python3-pyvmomi nfs-utils python3-flask python3-simplejson autofs python3-pexpect
|
||||||
%endif
|
%endif
|
||||||
%if "%{rhel}" == "7"
|
%if "%{rhel}" == "7"
|
||||||
Requires: unzip rsync python36-paramiko python3-pyvmomi nfs-utils python3-flask python3-simplejson autofs pexpect
|
Requires: unzip rsync python36-paramiko python3-pyvmomi nfs-utils python3-flask python3-simplejson autofs pexpect
|
||||||
|
@ -14,5 +14,3 @@ else
|
|||||||
sleep 3
|
sleep 3
|
||||||
fi
|
fi
|
||||||
echo $(date +%Y-%m-%d\ %H:%M:%S) : Fin Export TISBackup sur Disque USB : $target >> /var/log/tisbackup.log
|
echo $(date +%Y-%m-%d\ %H:%M:%S) : Fin Export TISBackup sur Disque USB : $target >> /var/log/tisbackup.log
|
||||||
|
|
||||||
|
|
||||||
|
@ -20,7 +20,7 @@ maximum_backup_age=30
|
|||||||
;type=rsync+ssh
|
;type=rsync+ssh
|
||||||
;server_name=srvzimbra
|
;server_name=srvzimbra
|
||||||
;remote_dir=/
|
;remote_dir=/
|
||||||
;exclude_list="/proc/**","/sys/**","/dev/**"
|
;exclude_list="/proc/**","/sys/**","/dev/**"
|
||||||
;private_key=/root/.ssh/id_rsa
|
;private_key=/root/.ssh/id_rsa
|
||||||
;ssh_port = 22
|
;ssh_port = 22
|
||||||
|
|
||||||
@ -95,4 +95,3 @@ maximum_backup_age=30
|
|||||||
;type=xcp-dump-metadata
|
;type=xcp-dump-metadata
|
||||||
;server_name=srvxen1
|
;server_name=srvxen1
|
||||||
;private_key=/root/.ssh/id_rsa
|
;private_key=/root/.ssh/id_rsa
|
||||||
|
|
||||||
|
@ -18,4 +18,3 @@ password_file=/home/homes/ssamson/tisbackup-pra/xen_passwd
|
|||||||
network_name=net-test
|
network_name=net-test
|
||||||
#start_vm=no
|
#start_vm=no
|
||||||
#max_copies=3
|
#max_copies=3
|
||||||
|
|
||||||
|
@ -4,4 +4,3 @@
|
|||||||
# m h dom mon dow user command
|
# m h dom mon dow user command
|
||||||
30 22 * * * root /opt/tisbackup/tisbackup.py -c /etc/tis/tisbackup-config.ini backup >> /var/log/tisbackup.log 2>&1
|
30 22 * * * root /opt/tisbackup/tisbackup.py -c /etc/tis/tisbackup-config.ini backup >> /var/log/tisbackup.log 2>&1
|
||||||
30 12 * * * root /opt/tisbackup/tisbackup.py -c /etc/tis/tisbackup-config.ini cleanup >> /var/log/tisbackup.log 2>&1
|
30 12 * * * root /opt/tisbackup/tisbackup.py -c /etc/tis/tisbackup-config.ini cleanup >> /var/log/tisbackup.log 2>&1
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
[general]
|
[general]
|
||||||
config_tisbackup= /etc/tis/tisbackup-config.ini
|
config_tisbackup= /etc/tis/tisbackup-config.ini
|
||||||
sections=
|
sections=
|
||||||
ADMIN_EMAIL=technique@tranquil-it-systems.fr
|
ADMIN_EMAIL=technique@tranquil-it-systems.fr
|
||||||
base_config_dir= /etc/tis/
|
base_config_dir= /etc/tis/
|
||||||
|
@ -95,4 +95,3 @@ case "$1" in
|
|||||||
esac
|
esac
|
||||||
|
|
||||||
exit 0
|
exit 0
|
||||||
|
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
[Unit]
|
[Unit]
|
||||||
Description=tisbackup
|
Description=tisbackup
|
||||||
|
|
||||||
[Service]
|
[Service]
|
||||||
Type=simple
|
Type=simple
|
||||||
ExecStart=/usr/bin/python3 /opt/tisbackup/tisbackup_gui.py
|
ExecStart=/usr/bin/python3 /opt/tisbackup/tisbackup_gui.py
|
||||||
|
|
||||||
[Install]
|
[Install]
|
||||||
WantedBy=multi-user.target
|
WantedBy=multi-user.target
|
||||||
|
@ -95,4 +95,3 @@ case "$1" in
|
|||||||
esac
|
esac
|
||||||
|
|
||||||
exit 0
|
exit 0
|
||||||
|
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
[Unit]
|
[Unit]
|
||||||
Description=tisbackup
|
Description=tisbackup
|
||||||
|
|
||||||
[Service]
|
[Service]
|
||||||
Type=simple
|
Type=simple
|
||||||
ExecStart=huey_consumer.py -n tisbackup_gui.huey
|
ExecStart=huey_consumer.py -n tisbackup_gui.huey
|
||||||
WorkingDirectory=/opt/tisbackup
|
WorkingDirectory=/opt/tisbackup
|
||||||
[Install]
|
[Install]
|
||||||
WantedBy=multi-user.target
|
WantedBy=multi-user.target
|
||||||
|
2
static/js/bootstrap.js
vendored
2
static/js/bootstrap.js
vendored
File diff suppressed because one or more lines are too long
3825
static/js/jquery.dataTables.js
vendored
3825
static/js/jquery.dataTables.js
vendored
File diff suppressed because it is too large
Load Diff
2
static/js/jquery.js
vendored
2
static/js/jquery.js
vendored
File diff suppressed because one or more lines are too long
@ -2,4 +2,4 @@ $(document).ready(function () {
|
|||||||
$('[data-toggle="offcanvas"]').click(function () {
|
$('[data-toggle="offcanvas"]').click(function () {
|
||||||
$('.row-offcanvas').toggleClass('active')
|
$('.row-offcanvas').toggleClass('active')
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
2
static/styles/bootstrap.css
vendored
2
static/styles/bootstrap.css
vendored
File diff suppressed because one or more lines are too long
6
tasks.py
6
tasks.py
@ -1,6 +1,8 @@
|
|||||||
from huey import RedisHuey
|
|
||||||
import os
|
|
||||||
import logging
|
import logging
|
||||||
|
import os
|
||||||
|
|
||||||
|
from huey import RedisHuey
|
||||||
|
|
||||||
from tisbackup import tis_backup
|
from tisbackup import tis_backup
|
||||||
|
|
||||||
huey = RedisHuey('tisbackup', host='localhost')
|
huey = RedisHuey('tisbackup', host='localhost')
|
||||||
|
@ -61,7 +61,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if backup_list['rsync_list']|count != 0 %}
|
{% if backup_list['rsync_list']|count != 0 %}
|
||||||
|
@ -9,9 +9,9 @@
|
|||||||
{% for message in messages %}
|
{% for message in messages %}
|
||||||
<div class="alert alert-success fade in">
|
<div class="alert alert-success fade in">
|
||||||
<a href="#" class="close" data-dismiss="alert">×</a>
|
<a href="#" class="close" data-dismiss="alert">×</a>
|
||||||
<strong>Success!</strong> {{ message }}
|
<strong>Success!</strong> {{ message }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endwith %}
|
{% endwith %}
|
||||||
@ -19,7 +19,7 @@
|
|||||||
<p>
|
<p>
|
||||||
<div class="alert alert-danger fade in"><strong>Error</strong>: {{ error }}</div>
|
<div class="alert alert-danger fade in"><strong>Error</strong>: {{ error }}</div>
|
||||||
<div class="alert alert-warning"><strong>Notice</strong>: {{ info }}</div>
|
<div class="alert alert-warning"><strong>Notice</strong>: {{ info }}</div>
|
||||||
|
|
||||||
<h4>Also, you can contact your <a href="mailto:{{ email }}?Subject=TISBACKUP%20Export"> System Administrator</a> for more details </h4>
|
<h4>Also, you can contact your <a href="mailto:{{ email }}?Subject=TISBACKUP%20Export"> System Administrator</a> for more details </h4>
|
||||||
</p>
|
</p>
|
||||||
{% elif not start %}
|
{% elif not start %}
|
||||||
@ -31,28 +31,28 @@
|
|||||||
$("#backup").submit();
|
$("#backup").submit();
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
$('#selectall').click(function(event) { //on click
|
$('#selectall').click(function(event) { //on click
|
||||||
if(this.checked) { // check select status
|
if(this.checked) { // check select status
|
||||||
$('.checkbox1').each(function() { //loop through each checkbox
|
$('.checkbox1').each(function() { //loop through each checkbox
|
||||||
this.checked = true; //select all checkboxes with class "checkbox1"
|
this.checked = true; //select all checkboxes with class "checkbox1"
|
||||||
});
|
});
|
||||||
}else{
|
}else{
|
||||||
$('.checkbox1').each(function() { //loop through each checkbox
|
$('.checkbox1').each(function() { //loop through each checkbox
|
||||||
this.checked = false; //deselect all checkboxes with class "checkbox1"
|
this.checked = false; //deselect all checkboxes with class "checkbox1"
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
<form id="backup" action='/export_backup'>
|
<form id="backup" action='/export_backup'>
|
||||||
<p> Select backups to save : <br/>
|
<p> Select backups to save : <br/>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="checkbox"><label><input type="checkbox" class="checkbox1" id="selectall" checked>Select all</label></div>
|
<div class="checkbox"><label><input type="checkbox" class="checkbox1" id="selectall" checked>Select all</label></div>
|
||||||
{% for entry in sections|sort %}
|
{% for entry in sections|sort %}
|
||||||
<div class="col-xs-6 col-md-4">
|
<div class="col-xs-6 col-md-4">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="checkbox"><label><input type="checkbox" name="sections" class="checkbox1" value="{{entry}}" checked>{{entry}}</label></div>
|
<div class="checkbox"><label><input type="checkbox" name="sections" class="checkbox1" value="{{entry}}" checked>{{entry}}</label></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
@ -65,7 +65,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
{% else %}
|
{% else %}
|
||||||
<h2 class="title">Backups is running: </h2>
|
<h2 class="title">Backups is running: </h2>
|
||||||
<table id="table" class='table'>
|
<table id="table" class='table'>
|
||||||
@ -79,7 +79,7 @@
|
|||||||
</table>
|
</table>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
|
||||||
|
|
||||||
//Refresh periode in seconds
|
//Refresh periode in seconds
|
||||||
var refresh = 5;
|
var refresh = 5;
|
||||||
@ -97,7 +97,7 @@ function status(){
|
|||||||
done = false;
|
done = false;
|
||||||
}else{
|
}else{
|
||||||
$('tbody').append('<td>'+val.status+'</td>');
|
$('tbody').append('<td>'+val.status+'</td>');
|
||||||
|
|
||||||
done = data.finish;
|
done = data.finish;
|
||||||
}
|
}
|
||||||
$('#table-design').append('</tr>');
|
$('#table-design').append('</tr>');
|
||||||
|
@ -24,7 +24,7 @@
|
|||||||
"aTargets": [ 0 ],
|
"aTargets": [ 0 ],
|
||||||
"mData": "backup_start",
|
"mData": "backup_start",
|
||||||
"mRender": function ( data, type, full ) {
|
"mRender": function ( data, type, full ) {
|
||||||
var d = new Date(data);
|
var d = new Date(data);
|
||||||
return d.getFullYear()+"/"+(d.getMonth()+1)+"/"+d.getDate()+" "+d.toLocaleTimeString();
|
return d.getFullYear()+"/"+(d.getMonth()+1)+"/"+d.getDate()+" "+d.toLocaleTimeString();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -32,7 +32,7 @@
|
|||||||
"aTargets": [ 1 ],
|
"aTargets": [ 1 ],
|
||||||
"mData": "backup_start",
|
"mData": "backup_start",
|
||||||
"mRender": function ( data, type, full ) {
|
"mRender": function ( data, type, full ) {
|
||||||
var d = new Date(data);
|
var d = new Date(data);
|
||||||
return d.getFullYear()+"/"+(d.getMonth()+1)+"/"+d.getDate()+" "+d.toLocaleTimeString();
|
return d.getFullYear()+"/"+(d.getMonth()+1)+"/"+d.getDate()+" "+d.toLocaleTimeString();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -79,7 +79,7 @@
|
|||||||
$('#inputDatabaseName').keyup(function () { delay(function(){ oTable.fnLengthChange($('#inputDatabaseName').val() ); }, 300 )});
|
$('#inputDatabaseName').keyup(function () { delay(function(){ oTable.fnLengthChange($('#inputDatabaseName').val() ); }, 300 )});
|
||||||
$(".dataTables_length").remove()
|
$(".dataTables_length").remove()
|
||||||
var nb_row = GetURLParameter('row');
|
var nb_row = GetURLParameter('row');
|
||||||
if (nb_row ){
|
if (nb_row ){
|
||||||
oTable.fnLengthChange( nb_row) ;
|
oTable.fnLengthChange( nb_row) ;
|
||||||
$('#inputDatabaseName').val(nb_row);
|
$('#inputDatabaseName').val(nb_row);
|
||||||
}
|
}
|
||||||
@ -96,7 +96,7 @@
|
|||||||
{
|
{
|
||||||
/* Get the DataTables object again - this is not a recreation, just a get of the object */
|
/* Get the DataTables object again - this is not a recreation, just a get of the object */
|
||||||
var oTable = $('#table-design').dataTable();
|
var oTable = $('#table-design').dataTable();
|
||||||
|
|
||||||
var bVis = oTable.fnSettings().aoColumns[iCol].bVisible;
|
var bVis = oTable.fnSettings().aoColumns[iCol].bVisible;
|
||||||
oTable.fnSetColumnVis( iCol, bVis ? false : true );
|
oTable.fnSetColumnVis( iCol, bVis ? false : true );
|
||||||
}
|
}
|
||||||
@ -111,10 +111,10 @@
|
|||||||
{
|
{
|
||||||
var sPageURL = window.location.search.substring(1);
|
var sPageURL = window.location.search.substring(1);
|
||||||
var sURLVariables = sPageURL.split('&');
|
var sURLVariables = sPageURL.split('&');
|
||||||
for (var i = 0; i < sURLVariables.length; i++)
|
for (var i = 0; i < sURLVariables.length; i++)
|
||||||
{
|
{
|
||||||
var sParameterName = sURLVariables[i].split('=');
|
var sParameterName = sURLVariables[i].split('=');
|
||||||
if (sParameterName[0] == sParam)
|
if (sParameterName[0] == sParam)
|
||||||
{
|
{
|
||||||
return sParameterName[1];
|
return sParameterName[1];
|
||||||
}
|
}
|
||||||
@ -135,7 +135,7 @@
|
|||||||
{
|
{
|
||||||
oSettings._iDisplayLength = iDisplay;
|
oSettings._iDisplayLength = iDisplay;
|
||||||
oSettings.oApi._fnCalculateEnd( oSettings );
|
oSettings.oApi._fnCalculateEnd( oSettings );
|
||||||
|
|
||||||
/* If we have space to show extra rows (backing up from the end point - then do so */
|
/* If we have space to show extra rows (backing up from the end point - then do so */
|
||||||
if ( oSettings._iDisplayEnd == oSettings.aiDisplay.length )
|
if ( oSettings._iDisplayEnd == oSettings.aiDisplay.length )
|
||||||
{
|
{
|
||||||
@ -145,14 +145,14 @@
|
|||||||
oSettings._iDisplayStart = 0;
|
oSettings._iDisplayStart = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( oSettings._iDisplayLength == -1 )
|
if ( oSettings._iDisplayLength == -1 )
|
||||||
{
|
{
|
||||||
oSettings._iDisplayStart = 0;
|
oSettings._iDisplayStart = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
oSettings.oApi._fnDraw( oSettings );
|
oSettings.oApi._fnDraw( oSettings );
|
||||||
|
|
||||||
if ( oSettings.aanFeatures.l )
|
if ( oSettings.aanFeatures.l )
|
||||||
{
|
{
|
||||||
$('select', oSettings.aanFeatures.l).val( iDisplay );
|
$('select', oSettings.aanFeatures.l).val( iDisplay );
|
||||||
@ -179,7 +179,7 @@
|
|||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
|
|
||||||
</tbody>
|
</tbody>
|
||||||
<tfoot>
|
<tfoot>
|
||||||
<tr>
|
<tr>
|
||||||
@ -204,7 +204,7 @@
|
|||||||
<div class="checkbox"><label><input type="checkbox" onclick="fnShowHide( 4 );" checked> Backup duration</label></div>
|
<div class="checkbox"><label><input type="checkbox" onclick="fnShowHide( 4 );" checked> Backup duration</label></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col-xs-6 col-md-4">
|
<div class="col-xs-6 col-md-4">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="checkbox"><label><input type="checkbox" onclick="fnShowHide( 6 );"checked> Written bytes</label></div>
|
<div class="checkbox"><label><input type="checkbox" onclick="fnShowHide( 6 );"checked> Written bytes</label></div>
|
||||||
@ -213,9 +213,9 @@
|
|||||||
<div class="checkbox"><label><input type="checkbox" onclick="fnShowHide( 9 );"/> Total bytes</label></div>
|
<div class="checkbox"><label><input type="checkbox" onclick="fnShowHide( 9 );"/> Total bytes</label></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col-xs-6 col-md-4">
|
<div class="col-xs-6 col-md-4">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="checkbox"><label><input type="checkbox" onclick="fnShowHide( 10 );"> Backup location</label></div>
|
<div class="checkbox"><label><input type="checkbox" onclick="fnShowHide( 10 );"> Backup location</label></div>
|
||||||
<div class="checkbox"><label><input type="checkbox" onclick="fnShowHide( 11);">Description </label></div>
|
<div class="checkbox"><label><input type="checkbox" onclick="fnShowHide( 11);">Description </label></div>
|
||||||
<div class="checkbox"><label><input type="checkbox" onclick="fnShowHide( 12);"> Log</label></div>
|
<div class="checkbox"><label><input type="checkbox" onclick="fnShowHide( 12);"> Log</label></div>
|
||||||
@ -225,7 +225,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@ -55,7 +55,7 @@
|
|||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
</div><!--/row-->
|
</div><!--/row-->
|
||||||
|
|
||||||
<hr>
|
<hr>
|
||||||
|
|
||||||
<footer>
|
<footer>
|
||||||
@ -80,7 +80,7 @@
|
|||||||
if ( data.configs.length > 1){
|
if ( data.configs.length > 1){
|
||||||
$('#choix_conf').removeClass('hidden');
|
$('#choix_conf').removeClass('hidden');
|
||||||
$("#choix_conf").show();
|
$("#choix_conf").show();
|
||||||
|
|
||||||
$.each(data.configs, function(key,val){
|
$.each(data.configs, function(key,val){
|
||||||
if (key == data.config_number)
|
if (key == data.config_number)
|
||||||
$('#choix_conf').append('<option vaulue="'+key+'" selected>'+val+'</option>');
|
$('#choix_conf').append('<option vaulue="'+key+'" selected>'+val+'</option>');
|
||||||
@ -89,7 +89,7 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
$( "#choix_conf" ).change(function() {
|
$( "#choix_conf" ).change(function() {
|
||||||
$.get( "/config_number/"+this.selectedIndex, function( data ) {location.reload();});
|
$.get( "/config_number/"+this.selectedIndex, function( data ) {location.reload();});
|
||||||
});
|
});
|
||||||
@ -98,4 +98,3 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
</body></html>
|
</body></html>
|
||||||
|
|
||||||
|
311
tisbackup.py
311
tisbackup.py
@ -18,41 +18,43 @@
|
|||||||
#
|
#
|
||||||
# -----------------------------------------------------------------------
|
# -----------------------------------------------------------------------
|
||||||
import datetime
|
import datetime
|
||||||
import subprocess
|
import os
|
||||||
import os,sys
|
import sys
|
||||||
from os.path import isfile, join
|
from os.path import isfile, join
|
||||||
|
|
||||||
tisbackup_root_dir = os.path.dirname(os.path.realpath(__file__))
|
tisbackup_root_dir = os.path.dirname(os.path.realpath(__file__))
|
||||||
sys.path.insert(0,os.path.join(tisbackup_root_dir,'lib'))
|
sys.path.insert(0, os.path.join(tisbackup_root_dir, "lib"))
|
||||||
sys.path.insert(0,os.path.join(tisbackup_root_dir,'libtisbackup'))
|
sys.path.insert(0, os.path.join(tisbackup_root_dir, "libtisbackup"))
|
||||||
|
|
||||||
from iniparse import ini,ConfigParser
|
|
||||||
from optparse import OptionParser
|
|
||||||
import re
|
|
||||||
import getopt
|
|
||||||
import os.path
|
|
||||||
import logging
|
|
||||||
import errno
|
import errno
|
||||||
from libtisbackup.common import *
|
import logging
|
||||||
|
import os.path
|
||||||
|
|
||||||
|
from optparse import OptionParser
|
||||||
|
|
||||||
|
from iniparse import ConfigParser, ini
|
||||||
|
|
||||||
from libtisbackup.backup_mysql import backup_mysql
|
from libtisbackup.backup_mysql import backup_mysql
|
||||||
from libtisbackup.backup_rsync import backup_rsync
|
|
||||||
from libtisbackup.backup_rsync import backup_rsync_ssh
|
# from libtisbackup.backup_vmdk import backup_vmdk
|
||||||
#from libtisbackup.backup_oracle import backup_oracle
|
# from libtisbackup.backup_switch import backup_switch
|
||||||
from libtisbackup.backup_rsync_btrfs import backup_rsync_btrfs
|
|
||||||
from libtisbackup.backup_rsync_btrfs import backup_rsync__btrfs_ssh
|
|
||||||
from libtisbackup.backup_pgsql import backup_pgsql
|
|
||||||
from libtisbackup.backup_xva import backup_xva
|
|
||||||
#from libtisbackup.backup_vmdk import backup_vmdk
|
|
||||||
#from libtisbackup.backup_switch import backup_switch
|
|
||||||
from libtisbackup.backup_null import backup_null
|
from libtisbackup.backup_null import backup_null
|
||||||
from libtisbackup.backup_xcp_metadata import backup_xcp_metadata
|
from libtisbackup.backup_pgsql import backup_pgsql
|
||||||
from libtisbackup.copy_vm_xcp import copy_vm_xcp
|
from libtisbackup.backup_rsync import backup_rsync, backup_rsync_ssh
|
||||||
#from libtisbackup.backup_sqlserver import backup_sqlserver
|
|
||||||
|
# from libtisbackup.backup_oracle import backup_oracle
|
||||||
|
from libtisbackup.backup_rsync_btrfs import backup_rsync__btrfs_ssh, backup_rsync_btrfs
|
||||||
|
|
||||||
|
# from libtisbackup.backup_sqlserver import backup_sqlserver
|
||||||
from libtisbackup.backup_samba4 import backup_samba4
|
from libtisbackup.backup_samba4 import backup_samba4
|
||||||
|
from libtisbackup.backup_xcp_metadata import backup_xcp_metadata
|
||||||
|
from libtisbackup.backup_xva import backup_xva
|
||||||
|
from libtisbackup.common import *
|
||||||
|
from libtisbackup.copy_vm_xcp import copy_vm_xcp
|
||||||
|
|
||||||
__version__="2.0"
|
__version__ = "2.0"
|
||||||
|
|
||||||
usage="""\
|
usage = """\
|
||||||
%prog -c configfile action
|
%prog -c configfile action
|
||||||
|
|
||||||
TIS Files Backup system.
|
TIS Files Backup system.
|
||||||
@ -67,52 +69,75 @@ action is either :
|
|||||||
exportbackup : copy lastest OK backups from local to location defned by --exportdir parameter
|
exportbackup : copy lastest OK backups from local to location defned by --exportdir parameter
|
||||||
register_existing : scan backup directories and add missing backups to database"""
|
register_existing : scan backup directories and add missing backups to database"""
|
||||||
|
|
||||||
version="VERSION"
|
version = "VERSION"
|
||||||
|
|
||||||
|
parser = OptionParser(usage=usage, version="%prog " + version)
|
||||||
|
parser.add_option(
|
||||||
|
"-c", "--config", dest="config", default="/etc/tis/tisbackup-config.ini", help="Config file full path (default: %default)"
|
||||||
|
)
|
||||||
|
parser.add_option("-d", "--dry-run", dest="dry_run", default=False, action="store_true", help="Dry run (default: %default)")
|
||||||
|
parser.add_option("-v", "--verbose", dest="verbose", default=False, action="store_true", help="More information (default: %default)")
|
||||||
|
parser.add_option(
|
||||||
|
"-s", "--sections", dest="sections", default="", help="Comma separated list of sections (backups) to process (default: All)"
|
||||||
|
)
|
||||||
|
parser.add_option(
|
||||||
|
"-l",
|
||||||
|
"--loglevel",
|
||||||
|
dest="loglevel",
|
||||||
|
default="info",
|
||||||
|
type="choice",
|
||||||
|
choices=["debug", "warning", "info", "error", "critical"],
|
||||||
|
metavar="LOGLEVEL",
|
||||||
|
help="Loglevel (default: %default)",
|
||||||
|
)
|
||||||
|
parser.add_option("-n", "--len", dest="statscount", default=30, type="int", help="Number of lines to list for dumpstat (default: %default)")
|
||||||
|
parser.add_option(
|
||||||
|
"-b",
|
||||||
|
"--backupdir",
|
||||||
|
dest="backup_base_dir",
|
||||||
|
default="",
|
||||||
|
help="Base directory for all backups (default: [global] backup_base_dir in config file)",
|
||||||
|
)
|
||||||
|
parser.add_option(
|
||||||
|
"-x", "--exportdir", dest="exportdir", default="", help="Directory where to export latest backups with exportbackup (nodefault)"
|
||||||
|
)
|
||||||
|
|
||||||
parser=OptionParser(usage=usage,version="%prog " + version)
|
|
||||||
parser.add_option("-c","--config", dest="config", default='/etc/tis/tisbackup-config.ini', help="Config file full path (default: %default)")
|
|
||||||
parser.add_option("-d","--dry-run", dest="dry_run", default=False, action='store_true', help="Dry run (default: %default)")
|
|
||||||
parser.add_option("-v","--verbose", dest="verbose", default=False, action='store_true', help="More information (default: %default)")
|
|
||||||
parser.add_option("-s","--sections", dest="sections", default='', help="Comma separated list of sections (backups) to process (default: All)")
|
|
||||||
parser.add_option("-l","--loglevel", dest="loglevel", default='info', type='choice', choices=['debug','warning','info','error','critical'], metavar='LOGLEVEL',help="Loglevel (default: %default)")
|
|
||||||
parser.add_option("-n","--len", dest="statscount", default=30, type='int', help="Number of lines to list for dumpstat (default: %default)")
|
|
||||||
parser.add_option("-b","--backupdir", dest="backup_base_dir", default='', help="Base directory for all backups (default: [global] backup_base_dir in config file)")
|
|
||||||
parser.add_option("-x","--exportdir", dest="exportdir", default='', help="Directory where to export latest backups with exportbackup (nodefault)")
|
|
||||||
|
|
||||||
class tis_backup:
|
class tis_backup:
|
||||||
logger = logging.getLogger('tisbackup')
|
logger = logging.getLogger("tisbackup")
|
||||||
|
|
||||||
def __init__(self,dry_run=False,verbose=False,backup_base_dir=''):
|
def __init__(self, dry_run=False, verbose=False, backup_base_dir=""):
|
||||||
self.dry_run = dry_run
|
self.dry_run = dry_run
|
||||||
self.verbose = verbose
|
self.verbose = verbose
|
||||||
self.backup_base_dir = backup_base_dir
|
self.backup_base_dir = backup_base_dir
|
||||||
self.backup_base_dir = ''
|
self.backup_base_dir = ""
|
||||||
self.backup_list = []
|
self.backup_list = []
|
||||||
self.dry_run = dry_run
|
self.dry_run = dry_run
|
||||||
self.verbose=False
|
self.verbose = False
|
||||||
|
|
||||||
def read_ini_file(self,filename):
|
def read_ini_file(self, filename):
|
||||||
ini.change_comment_syntax()
|
ini.change_comment_syntax()
|
||||||
cp = ConfigParser()
|
cp = ConfigParser()
|
||||||
cp.read(filename)
|
cp.read(filename)
|
||||||
|
|
||||||
if not self.backup_base_dir:
|
if not self.backup_base_dir:
|
||||||
self.backup_base_dir = cp.get('global','backup_base_dir')
|
self.backup_base_dir = cp.get("global", "backup_base_dir")
|
||||||
if not os.path.isdir(self.backup_base_dir):
|
if not os.path.isdir(self.backup_base_dir):
|
||||||
self.logger.info('Creating backup directory %s' % self.backup_base_dir)
|
self.logger.info("Creating backup directory %s" % self.backup_base_dir)
|
||||||
os.makedirs(self.backup_base_dir)
|
os.makedirs(self.backup_base_dir)
|
||||||
|
|
||||||
self.logger.debug("backup directory : " + self.backup_base_dir)
|
self.logger.debug("backup directory : " + self.backup_base_dir)
|
||||||
self.dbstat = BackupStat(os.path.join(self.backup_base_dir,'log','tisbackup.sqlite'))
|
self.dbstat = BackupStat(os.path.join(self.backup_base_dir, "log", "tisbackup.sqlite"))
|
||||||
|
|
||||||
for section in cp.sections():
|
for section in cp.sections():
|
||||||
if (section != 'global'):
|
if section != "global":
|
||||||
self.logger.debug("reading backup config " + section)
|
self.logger.debug("reading backup config " + section)
|
||||||
backup_item = None
|
backup_item = None
|
||||||
type = cp.get(section,'type')
|
type = cp.get(section, "type")
|
||||||
|
|
||||||
backup_item = backup_drivers[type](backup_name=section,
|
backup_item = backup_drivers[type](
|
||||||
backup_dir=os.path.join(self.backup_base_dir,section),dbstat=self.dbstat,dry_run=self.dry_run)
|
backup_name=section, backup_dir=os.path.join(self.backup_base_dir, section), dbstat=self.dbstat, dry_run=self.dry_run
|
||||||
|
)
|
||||||
backup_item.read_config(cp)
|
backup_item.read_config(cp)
|
||||||
backup_item.verbose = self.verbose
|
backup_item.verbose = self.verbose
|
||||||
|
|
||||||
@ -122,35 +147,34 @@ class tis_backup:
|
|||||||
# TODO socket.gethostbyaddr('64.236.16.20')
|
# TODO socket.gethostbyaddr('64.236.16.20')
|
||||||
# TODO limit backup to one backup on the command line
|
# TODO limit backup to one backup on the command line
|
||||||
|
|
||||||
|
def checknagios(self, sections=[]):
|
||||||
def checknagios(self,sections=[]):
|
|
||||||
try:
|
try:
|
||||||
if not sections:
|
if not sections:
|
||||||
sections = [backup_item.backup_name for backup_item in self.backup_list]
|
sections = [backup_item.backup_name for backup_item in self.backup_list]
|
||||||
|
|
||||||
self.logger.debug('Start of check nagios for %s' % (','.join(sections),))
|
self.logger.debug("Start of check nagios for %s" % (",".join(sections),))
|
||||||
try:
|
try:
|
||||||
worst_nagiosstatus = None
|
worst_nagiosstatus = None
|
||||||
ok = []
|
ok = []
|
||||||
warning = []
|
warning = []
|
||||||
critical = []
|
critical = []
|
||||||
unknown = []
|
unknown = []
|
||||||
nagiosoutput = ''
|
nagiosoutput = ""
|
||||||
for backup_item in self.backup_list:
|
for backup_item in self.backup_list:
|
||||||
if not sections or backup_item.backup_name in sections:
|
if not sections or backup_item.backup_name in sections:
|
||||||
(nagiosstatus,log) = backup_item.checknagios()
|
(nagiosstatus, log) = backup_item.checknagios()
|
||||||
if nagiosstatus == nagiosStateCritical:
|
if nagiosstatus == nagiosStateCritical:
|
||||||
critical.append((backup_item.backup_name,log))
|
critical.append((backup_item.backup_name, log))
|
||||||
elif nagiosstatus == nagiosStateWarning :
|
elif nagiosstatus == nagiosStateWarning:
|
||||||
warning.append((backup_item.backup_name,log))
|
warning.append((backup_item.backup_name, log))
|
||||||
elif nagiosstatus == nagiosStateOk:
|
elif nagiosstatus == nagiosStateOk:
|
||||||
ok.append((backup_item.backup_name,log))
|
ok.append((backup_item.backup_name, log))
|
||||||
else:
|
else:
|
||||||
unknown.append((backup_item.backup_name,log))
|
unknown.append((backup_item.backup_name, log))
|
||||||
self.logger.debug('[%s] nagios:"%i" log: %s',backup_item.backup_name,nagiosstatus,log)
|
self.logger.debug('[%s] nagios:"%i" log: %s', backup_item.backup_name, nagiosstatus, log)
|
||||||
|
|
||||||
if not ok and not critical and not unknown and not warning:
|
if not ok and not critical and not unknown and not warning:
|
||||||
self.logger.debug('Nothing processed')
|
self.logger.debug("Nothing processed")
|
||||||
worst_nagiosstatus = nagiosStateUnknown
|
worst_nagiosstatus = nagiosStateUnknown
|
||||||
nagiosoutput = 'UNKNOWN : Unknown backup sections "%s"' % sections
|
nagiosoutput = 'UNKNOWN : Unknown backup sections "%s"' % sections
|
||||||
|
|
||||||
@ -159,156 +183,154 @@ class tis_backup:
|
|||||||
if unknown:
|
if unknown:
|
||||||
if not worst_nagiosstatus:
|
if not worst_nagiosstatus:
|
||||||
worst_nagiosstatus = nagiosStateUnknown
|
worst_nagiosstatus = nagiosStateUnknown
|
||||||
nagiosoutput = 'UNKNOWN status backups %s' % (','.join([b[0] for b in unknown]))
|
nagiosoutput = "UNKNOWN status backups %s" % (",".join([b[0] for b in unknown]))
|
||||||
globallog.extend(unknown)
|
globallog.extend(unknown)
|
||||||
|
|
||||||
if critical:
|
if critical:
|
||||||
if not worst_nagiosstatus:
|
if not worst_nagiosstatus:
|
||||||
worst_nagiosstatus = nagiosStateCritical
|
worst_nagiosstatus = nagiosStateCritical
|
||||||
nagiosoutput = 'CRITICAL backups %s' % (','.join([b[0] for b in critical]))
|
nagiosoutput = "CRITICAL backups %s" % (",".join([b[0] for b in critical]))
|
||||||
globallog.extend(critical)
|
globallog.extend(critical)
|
||||||
|
|
||||||
if warning:
|
if warning:
|
||||||
if not worst_nagiosstatus:
|
if not worst_nagiosstatus:
|
||||||
worst_nagiosstatus = nagiosStateWarning
|
worst_nagiosstatus = nagiosStateWarning
|
||||||
nagiosoutput = 'WARNING backups %s' % (','.join([b[0] for b in warning]))
|
nagiosoutput = "WARNING backups %s" % (",".join([b[0] for b in warning]))
|
||||||
globallog.extend(warning)
|
globallog.extend(warning)
|
||||||
|
|
||||||
if ok:
|
if ok:
|
||||||
if not worst_nagiosstatus:
|
if not worst_nagiosstatus:
|
||||||
worst_nagiosstatus = nagiosStateOk
|
worst_nagiosstatus = nagiosStateOk
|
||||||
nagiosoutput = 'OK backups %s' % (','.join([b[0] for b in ok]))
|
nagiosoutput = "OK backups %s" % (",".join([b[0] for b in ok]))
|
||||||
globallog.extend(ok)
|
globallog.extend(ok)
|
||||||
|
|
||||||
if worst_nagiosstatus == nagiosStateOk:
|
if worst_nagiosstatus == nagiosStateOk:
|
||||||
nagiosoutput = 'ALL backups OK %s' % (','.join(sections))
|
nagiosoutput = "ALL backups OK %s" % (",".join(sections))
|
||||||
|
|
||||||
|
|
||||||
except BaseException as e:
|
except BaseException as e:
|
||||||
worst_nagiosstatus = nagiosStateCritical
|
worst_nagiosstatus = nagiosStateCritical
|
||||||
nagiosoutput = 'EXCEPTION',"Critical : %s" % str(e)
|
nagiosoutput = "EXCEPTION", "Critical : %s" % str(e)
|
||||||
raise
|
raise
|
||||||
|
|
||||||
finally:
|
finally:
|
||||||
self.logger.debug('worst nagios status :"%i"',worst_nagiosstatus)
|
self.logger.debug('worst nagios status :"%i"', worst_nagiosstatus)
|
||||||
print('%s (tisbackup V%s)' %(nagiosoutput,version))
|
print("%s (tisbackup V%s)" % (nagiosoutput, version))
|
||||||
print('\n'.join(["[%s]:%s" % (l[0],l[1]) for l in globallog]))
|
print("\n".join(["[%s]:%s" % (log_elem[0], log_elem[1]) for log_elem in globallog]))
|
||||||
sys.exit(worst_nagiosstatus)
|
sys.exit(worst_nagiosstatus)
|
||||||
|
|
||||||
def process_backup(self,sections=[]):
|
def process_backup(self, sections=[]):
|
||||||
processed = []
|
processed = []
|
||||||
errors = []
|
errors = []
|
||||||
if not sections:
|
if not sections:
|
||||||
sections = [backup_item.backup_name for backup_item in self.backup_list]
|
sections = [backup_item.backup_name for backup_item in self.backup_list]
|
||||||
|
|
||||||
self.logger.info('Processing backup for %s' % (','.join(sections)) )
|
self.logger.info("Processing backup for %s" % (",".join(sections)))
|
||||||
for backup_item in self.backup_list:
|
for backup_item in self.backup_list:
|
||||||
if not sections or backup_item.backup_name in sections:
|
if not sections or backup_item.backup_name in sections:
|
||||||
try:
|
try:
|
||||||
assert(isinstance(backup_item,backup_generic))
|
assert isinstance(backup_item, backup_generic)
|
||||||
self.logger.info('Processing [%s]',(backup_item.backup_name))
|
self.logger.info("Processing [%s]", (backup_item.backup_name))
|
||||||
stats = backup_item.process_backup()
|
stats = backup_item.process_backup()
|
||||||
processed.append((backup_item.backup_name,stats))
|
processed.append((backup_item.backup_name, stats))
|
||||||
except BaseException as e:
|
except BaseException as e:
|
||||||
self.logger.critical('Backup [%s] processed with error : %s',backup_item.backup_name,e)
|
self.logger.critical("Backup [%s] processed with error : %s", backup_item.backup_name, e)
|
||||||
errors.append((backup_item.backup_name,str(e)))
|
errors.append((backup_item.backup_name, str(e)))
|
||||||
if not processed and not errors:
|
if not processed and not errors:
|
||||||
self.logger.critical('No backup properly finished or processed')
|
self.logger.critical("No backup properly finished or processed")
|
||||||
else:
|
else:
|
||||||
if processed:
|
if processed:
|
||||||
self.logger.info('Backup processed : %s' , ",".join([b[0] for b in processed]))
|
self.logger.info("Backup processed : %s", ",".join([b[0] for b in processed]))
|
||||||
if errors:
|
if errors:
|
||||||
self.logger.error('Backup processed with errors: %s' , ",".join([b[0] for b in errors]))
|
self.logger.error("Backup processed with errors: %s", ",".join([b[0] for b in errors]))
|
||||||
|
|
||||||
def export_backups(self,sections=[],exportdir=''):
|
def export_backups(self, sections=[], exportdir=""):
|
||||||
processed = []
|
processed = []
|
||||||
errors = []
|
errors = []
|
||||||
if not sections:
|
if not sections:
|
||||||
sections = [backup_item.backup_name for backup_item in self.backup_list]
|
sections = [backup_item.backup_name for backup_item in self.backup_list]
|
||||||
|
|
||||||
self.logger.info('Exporting OK backups for %s to %s' % (','.join(sections),exportdir) )
|
self.logger.info("Exporting OK backups for %s to %s" % (",".join(sections), exportdir))
|
||||||
|
|
||||||
for backup_item in self.backup_list:
|
for backup_item in self.backup_list:
|
||||||
if backup_item.backup_name in sections:
|
if backup_item.backup_name in sections:
|
||||||
try:
|
try:
|
||||||
assert(isinstance(backup_item,backup_generic))
|
assert isinstance(backup_item, backup_generic)
|
||||||
self.logger.info('Processing [%s]',(backup_item.backup_name))
|
self.logger.info("Processing [%s]", (backup_item.backup_name))
|
||||||
stats = backup_item.export_latestbackup(destdir=exportdir)
|
stats = backup_item.export_latestbackup(destdir=exportdir)
|
||||||
processed.append((backup_item.backup_name,stats))
|
processed.append((backup_item.backup_name, stats))
|
||||||
except BaseException as e:
|
except BaseException as e:
|
||||||
self.logger.critical('Export Backup [%s] processed with error : %s',backup_item.backup_name,e)
|
self.logger.critical("Export Backup [%s] processed with error : %s", backup_item.backup_name, e)
|
||||||
errors.append((backup_item.backup_name,str(e)))
|
errors.append((backup_item.backup_name, str(e)))
|
||||||
if not processed and not errors:
|
if not processed and not errors:
|
||||||
self.logger.critical('No export backup properly finished or processed')
|
self.logger.critical("No export backup properly finished or processed")
|
||||||
else:
|
else:
|
||||||
if processed:
|
if processed:
|
||||||
self.logger.info('Export Backups processed : %s' , ",".join([b[0] for b in processed]))
|
self.logger.info("Export Backups processed : %s", ",".join([b[0] for b in processed]))
|
||||||
if errors:
|
if errors:
|
||||||
self.logger.error('Export Backups processed with errors: %s' , ",".join([b[0] for b in errors]))
|
self.logger.error("Export Backups processed with errors: %s", ",".join([b[0] for b in errors]))
|
||||||
|
|
||||||
def retry_failed_backups(self,maxage_hours=30):
|
def retry_failed_backups(self, maxage_hours=30):
|
||||||
processed = []
|
processed = []
|
||||||
errors = []
|
errors = []
|
||||||
|
|
||||||
# before mindate, backup is too old
|
# before mindate, backup is too old
|
||||||
mindate = datetime2isodate((datetime.datetime.now() - datetime.timedelta(hours=maxage_hours)))
|
mindate = datetime2isodate((datetime.datetime.now() - datetime.timedelta(hours=maxage_hours)))
|
||||||
failed_backups = self.dbstat.query("""\
|
failed_backups = self.dbstat.query(
|
||||||
|
"""\
|
||||||
select distinct backup_name as bname
|
select distinct backup_name as bname
|
||||||
from stats
|
from stats
|
||||||
where status="OK" and backup_start>=?""",(mindate,))
|
where status="OK" and backup_start>=?""",
|
||||||
|
(mindate,),
|
||||||
|
)
|
||||||
defined_backups = list(map(lambda f:f.backup_name, [ x for x in self.backup_list if not isinstance(x, backup_null) ]))
|
|
||||||
failed_backups_names = set(defined_backups) - set([b['bname'] for b in failed_backups if b['bname'] in defined_backups])
|
|
||||||
|
|
||||||
|
defined_backups = list(map(lambda f: f.backup_name, [x for x in self.backup_list if not isinstance(x, backup_null)]))
|
||||||
|
failed_backups_names = set(defined_backups) - set([b["bname"] for b in failed_backups if b["bname"] in defined_backups])
|
||||||
|
|
||||||
if failed_backups_names:
|
if failed_backups_names:
|
||||||
self.logger.info('Processing backup for %s',','.join(failed_backups_names))
|
self.logger.info("Processing backup for %s", ",".join(failed_backups_names))
|
||||||
for backup_item in self.backup_list:
|
for backup_item in self.backup_list:
|
||||||
if backup_item.backup_name in failed_backups_names:
|
if backup_item.backup_name in failed_backups_names:
|
||||||
try:
|
try:
|
||||||
assert(isinstance(backup_item,backup_generic))
|
assert isinstance(backup_item, backup_generic)
|
||||||
self.logger.info('Processing [%s]',(backup_item.backup_name))
|
self.logger.info("Processing [%s]", (backup_item.backup_name))
|
||||||
stats = backup_item.process_backup()
|
stats = backup_item.process_backup()
|
||||||
processed.append((backup_item.backup_name,stats))
|
processed.append((backup_item.backup_name, stats))
|
||||||
except BaseException as e:
|
except BaseException as e:
|
||||||
self.logger.critical('Backup [%s] not processed, error : %s',backup_item.backup_name,e)
|
self.logger.critical("Backup [%s] not processed, error : %s", backup_item.backup_name, e)
|
||||||
errors.append((backup_item.backup_name,str(e)))
|
errors.append((backup_item.backup_name, str(e)))
|
||||||
if not processed and not errors:
|
if not processed and not errors:
|
||||||
self.logger.critical('No backup properly finished or processed')
|
self.logger.critical("No backup properly finished or processed")
|
||||||
else:
|
else:
|
||||||
if processed:
|
if processed:
|
||||||
self.logger.info('Backup processed : %s' , ",".join([b[0] for b in errors]))
|
self.logger.info("Backup processed : %s", ",".join([b[0] for b in errors]))
|
||||||
if errors:
|
if errors:
|
||||||
self.logger.error('Backup processed with errors: %s' , ",".join([b[0] for b in errors]))
|
self.logger.error("Backup processed with errors: %s", ",".join([b[0] for b in errors]))
|
||||||
else:
|
else:
|
||||||
self.logger.info('No recent failed backups found in database')
|
self.logger.info("No recent failed backups found in database")
|
||||||
|
|
||||||
|
def cleanup_backup_section(self, sections=[]):
|
||||||
def cleanup_backup_section(self,sections = []):
|
|
||||||
log = ''
|
|
||||||
processed = False
|
processed = False
|
||||||
if not sections:
|
if not sections:
|
||||||
sections = [backup_item.backup_name for backup_item in self.backup_list]
|
sections = [backup_item.backup_name for backup_item in self.backup_list]
|
||||||
|
|
||||||
self.logger.info('Processing cleanup for %s' % (','.join(sections)) )
|
self.logger.info("Processing cleanup for %s" % (",".join(sections)))
|
||||||
for backup_item in self.backup_list:
|
for backup_item in self.backup_list:
|
||||||
if backup_item.backup_name in sections:
|
if backup_item.backup_name in sections:
|
||||||
try:
|
try:
|
||||||
assert(isinstance(backup_item,backup_generic))
|
assert isinstance(backup_item, backup_generic)
|
||||||
self.logger.info('Processing cleanup of [%s]',(backup_item.backup_name))
|
self.logger.info("Processing cleanup of [%s]", (backup_item.backup_name))
|
||||||
backup_item.cleanup_backup()
|
backup_item.cleanup_backup()
|
||||||
processed = True
|
processed = True
|
||||||
except BaseException as e:
|
except BaseException as e:
|
||||||
self.logger.critical('Cleanup of [%s] not processed, error : %s',backup_item.backup_name,e)
|
self.logger.critical("Cleanup of [%s] not processed, error : %s", backup_item.backup_name, e)
|
||||||
if not processed:
|
if not processed:
|
||||||
self.logger.critical('No cleanup properly finished or processed')
|
self.logger.critical("No cleanup properly finished or processed")
|
||||||
|
|
||||||
def register_existingbackups(self,sections = []):
|
def register_existingbackups(self, sections=[]):
|
||||||
if not sections:
|
if not sections:
|
||||||
sections = [backup_item.backup_name for backup_item in self.backup_list]
|
sections = [backup_item.backup_name for backup_item in self.backup_list]
|
||||||
|
|
||||||
self.logger.info('Append existing backups to database...')
|
self.logger.info("Append existing backups to database...")
|
||||||
for backup_item in self.backup_list:
|
for backup_item in self.backup_list:
|
||||||
if backup_item.backup_name in sections:
|
if backup_item.backup_name in sections:
|
||||||
backup_item.register_existingbackups()
|
backup_item.register_existingbackups()
|
||||||
@ -316,26 +338,26 @@ class tis_backup:
|
|||||||
def html_report(self):
|
def html_report(self):
|
||||||
for backup_item in self.backup_list:
|
for backup_item in self.backup_list:
|
||||||
if not section or section == backup_item.backup_name:
|
if not section or section == backup_item.backup_name:
|
||||||
assert(isinstance(backup_item,backup_generic))
|
assert isinstance(backup_item, backup_generic)
|
||||||
if not maxage_hours:
|
if not maxage_hours:
|
||||||
maxage_hours = backup_item.maximum_backup_age
|
maxage_hours = backup_item.maximum_backup_age
|
||||||
(nagiosstatus,log) = backup_item.checknagios(maxage_hours=maxage_hours)
|
(nagiosstatus, log) = backup_item.checknagios(maxage_hours=maxage_hours)
|
||||||
globallog.append('[%s] %s' % (backup_item.backup_name,log))
|
globallog.append("[%s] %s" % (backup_item.backup_name, log))
|
||||||
self.logger.debug('[%s] nagios:"%i" log: %s',backup_item.backup_name,nagiosstatus,log)
|
self.logger.debug('[%s] nagios:"%i" log: %s', backup_item.backup_name, nagiosstatus, log)
|
||||||
processed = True
|
# processed = True
|
||||||
if nagiosstatus >= worst_nagiosstatus:
|
# if nagiosstatus >= worst_nagiosstatus:
|
||||||
worst_nagiosstatus = nagiosstatus
|
# worst_nagiosstatus = nagiosstatus
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
(options,args)=parser.parse_args()
|
(options, args) = parser.parse_args()
|
||||||
|
|
||||||
if len(args) != 1:
|
if len(args) != 1:
|
||||||
print("ERROR : You must provide one action to perform")
|
print("ERROR : You must provide one action to perform")
|
||||||
parser.print_usage()
|
parser.print_usage()
|
||||||
sys.exit(2)
|
sys.exit(2)
|
||||||
|
|
||||||
backup_start_date = datetime.datetime.now().strftime('%Y%m%d-%Hh%Mm%S')
|
backup_start_date = datetime.datetime.now().strftime("%Y%m%d-%Hh%Mm%S")
|
||||||
|
|
||||||
# options
|
# options
|
||||||
action = args[0]
|
action = args[0]
|
||||||
@ -344,23 +366,23 @@ def main():
|
|||||||
print(backup_drivers[t].get_help())
|
print(backup_drivers[t].get_help())
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
|
||||||
config_file =options.config
|
config_file = options.config
|
||||||
dry_run = options.dry_run
|
dry_run = options.dry_run
|
||||||
verbose = options.verbose
|
verbose = options.verbose
|
||||||
|
|
||||||
loglevel = options.loglevel
|
loglevel = options.loglevel
|
||||||
|
|
||||||
# setup Logger
|
# setup Logger
|
||||||
logger = logging.getLogger('tisbackup')
|
logger = logging.getLogger("tisbackup")
|
||||||
hdlr = logging.StreamHandler()
|
hdlr = logging.StreamHandler()
|
||||||
hdlr.setFormatter(logging.Formatter('%(asctime)s %(levelname)s %(message)s'))
|
hdlr.setFormatter(logging.Formatter("%(asctime)s %(levelname)s %(message)s"))
|
||||||
logger.addHandler(hdlr)
|
logger.addHandler(hdlr)
|
||||||
|
|
||||||
# set loglevel
|
# set loglevel
|
||||||
if loglevel in ('debug','warning','info','error','critical'):
|
if loglevel in ("debug", "warning", "info", "error", "critical"):
|
||||||
numeric_level = getattr(logging, loglevel.upper(), None)
|
numeric_level = getattr(logging, loglevel.upper(), None)
|
||||||
if not isinstance(numeric_level, int):
|
if not isinstance(numeric_level, int):
|
||||||
raise ValueError('Invalid log level: %s' % loglevel)
|
raise ValueError("Invalid log level: %s" % loglevel)
|
||||||
logger.setLevel(numeric_level)
|
logger.setLevel(numeric_level)
|
||||||
|
|
||||||
# Config file
|
# Config file
|
||||||
@ -371,36 +393,36 @@ def main():
|
|||||||
cp = ConfigParser()
|
cp = ConfigParser()
|
||||||
cp.read(config_file)
|
cp.read(config_file)
|
||||||
|
|
||||||
backup_base_dir = options.backup_base_dir or cp.get('global','backup_base_dir')
|
backup_base_dir = options.backup_base_dir or cp.get("global", "backup_base_dir")
|
||||||
log_dir = os.path.join(backup_base_dir,'log')
|
log_dir = os.path.join(backup_base_dir, "log")
|
||||||
if not os.path.exists(log_dir):
|
if not os.path.exists(log_dir):
|
||||||
os.makedirs(log_dir)
|
os.makedirs(log_dir)
|
||||||
|
|
||||||
# if we run the nagios check, we don't create log file, everything is piped to stdout
|
# if we run the nagios check, we don't create log file, everything is piped to stdout
|
||||||
if action!='checknagios':
|
if action != "checknagios":
|
||||||
try:
|
try:
|
||||||
hdlr = logging.FileHandler(os.path.join(log_dir,'tisbackup_%s.log' % (backup_start_date)))
|
hdlr = logging.FileHandler(os.path.join(log_dir, "tisbackup_%s.log" % (backup_start_date)))
|
||||||
hdlr.setFormatter(logging.Formatter('%(asctime)s %(levelname)s %(message)s'))
|
hdlr.setFormatter(logging.Formatter("%(asctime)s %(levelname)s %(message)s"))
|
||||||
logger.addHandler(hdlr)
|
logger.addHandler(hdlr)
|
||||||
except IOError as e:
|
except IOError as e:
|
||||||
if action == 'cleanup' and e.errno == errno.ENOSPC:
|
if action == "cleanup" and e.errno == errno.ENOSPC:
|
||||||
logger.warning("No space left on device, disabling file logging.")
|
logger.warning("No space left on device, disabling file logging.")
|
||||||
else:
|
else:
|
||||||
raise e
|
raise e
|
||||||
|
|
||||||
# Main
|
# Main
|
||||||
backup = tis_backup(dry_run=dry_run,verbose=verbose,backup_base_dir=backup_base_dir)
|
backup = tis_backup(dry_run=dry_run, verbose=verbose, backup_base_dir=backup_base_dir)
|
||||||
backup.read_ini_file(config_file)
|
backup.read_ini_file(config_file)
|
||||||
|
|
||||||
backup_sections = options.sections.split(',') if options.sections else []
|
backup_sections = options.sections.split(",") if options.sections else []
|
||||||
|
|
||||||
all_sections = [backup_item.backup_name for backup_item in backup.backup_list]
|
all_sections = [backup_item.backup_name for backup_item in backup.backup_list]
|
||||||
if not backup_sections:
|
if not backup_sections:
|
||||||
backup_sections = all_sections
|
backup_sections = all_sections
|
||||||
else:
|
else:
|
||||||
for b in backup_sections:
|
for b in backup_sections:
|
||||||
if not b in all_sections:
|
if b not in all_sections:
|
||||||
raise Exception('Section %s is not defined in config file' % b)
|
raise Exception("Section %s is not defined in config file" % b)
|
||||||
|
|
||||||
if dry_run:
|
if dry_run:
|
||||||
logger.warning("WARNING : DRY RUN, nothing will be done, just printing on screen...")
|
logger.warning("WARNING : DRY RUN, nothing will be done, just printing on screen...")
|
||||||
@ -409,23 +431,22 @@ def main():
|
|||||||
backup.process_backup(backup_sections)
|
backup.process_backup(backup_sections)
|
||||||
elif action == "exportbackup":
|
elif action == "exportbackup":
|
||||||
if not options.exportdir:
|
if not options.exportdir:
|
||||||
raise Exception('No export directory supplied dor exportbackup action')
|
raise Exception("No export directory supplied dor exportbackup action")
|
||||||
backup.export_backups(backup_sections,options.exportdir)
|
backup.export_backups(backup_sections, options.exportdir)
|
||||||
elif action == "cleanup":
|
elif action == "cleanup":
|
||||||
backup.cleanup_backup_section(backup_sections)
|
backup.cleanup_backup_section(backup_sections)
|
||||||
elif action == "checknagios":
|
elif action == "checknagios":
|
||||||
backup.checknagios(backup_sections)
|
backup.checknagios(backup_sections)
|
||||||
elif action == "dumpstat":
|
elif action == "dumpstat":
|
||||||
for s in backup_sections:
|
for s in backup_sections:
|
||||||
backup.dbstat.last_backups(s,count=options.statscount)
|
backup.dbstat.last_backups(s, count=options.statscount)
|
||||||
elif action == "retryfailed":
|
elif action == "retryfailed":
|
||||||
backup.retry_failed_backups()
|
backup.retry_failed_backups()
|
||||||
elif action == "register_existing":
|
elif action == "register_existing":
|
||||||
backup.register_existingbackups(backup_sections)
|
backup.register_existingbackups(backup_sections)
|
||||||
|
|
||||||
|
|
||||||
else:
|
else:
|
||||||
logger.error('Unhandled action "%s", quitting...',action)
|
logger.error('Unhandled action "%s", quitting...', action)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
404
tisbackup_gui.py
404
tisbackup_gui.py
@ -17,89 +17,89 @@
|
|||||||
# along with TISBackup. If not, see <http://www.gnu.org/licenses/>.
|
# along with TISBackup. If not, see <http://www.gnu.org/licenses/>.
|
||||||
#
|
#
|
||||||
# -----------------------------------------------------------------------
|
# -----------------------------------------------------------------------
|
||||||
import os,sys
|
import os
|
||||||
|
import sys
|
||||||
from os.path import isfile, join
|
from os.path import isfile, join
|
||||||
|
|
||||||
tisbackup_root_dir = os.path.abspath(os.path.join(os.path.dirname(__file__)))
|
tisbackup_root_dir = os.path.abspath(os.path.join(os.path.dirname(__file__)))
|
||||||
sys.path.append(os.path.join(tisbackup_root_dir,'lib'))
|
sys.path.append(os.path.join(tisbackup_root_dir, "lib"))
|
||||||
sys.path.append(os.path.join(tisbackup_root_dir,'libtisbackup'))
|
sys.path.append(os.path.join(tisbackup_root_dir, "libtisbackup"))
|
||||||
|
|
||||||
|
|
||||||
from shutil import *
|
|
||||||
from iniparse import ConfigParser,RawConfigParser
|
|
||||||
from libtisbackup.common import *
|
|
||||||
import time
|
|
||||||
from flask import request, Flask, session, g, appcontext_pushed, redirect, url_for, abort, render_template, flash, jsonify, Response
|
|
||||||
from urllib.parse import urlparse
|
|
||||||
import json
|
|
||||||
import glob
|
import glob
|
||||||
import time
|
import json
|
||||||
|
|
||||||
from config import huey
|
|
||||||
from tasks import run_export_backup, get_task, set_task
|
|
||||||
|
|
||||||
from tisbackup import tis_backup
|
|
||||||
import logging
|
import logging
|
||||||
import re
|
import re
|
||||||
|
import time
|
||||||
|
from shutil import *
|
||||||
|
from urllib.parse import urlparse
|
||||||
|
|
||||||
|
from flask import Flask, Response, abort, appcontext_pushed, flash, g, jsonify, redirect, render_template, request, session, url_for
|
||||||
|
from iniparse import ConfigParser, RawConfigParser
|
||||||
|
|
||||||
|
from config import huey
|
||||||
|
from libtisbackup.common import *
|
||||||
|
from tasks import get_task, run_export_backup, set_task
|
||||||
|
from tisbackup import tis_backup
|
||||||
|
|
||||||
cp = ConfigParser()
|
cp = ConfigParser()
|
||||||
cp.read("/etc/tis/tisbackup_gui.ini")
|
cp.read("/etc/tis/tisbackup_gui.ini")
|
||||||
|
|
||||||
CONFIG = cp.get('general','config_tisbackup').split(",")
|
CONFIG = cp.get("general", "config_tisbackup").split(",")
|
||||||
SECTIONS = cp.get('general','sections')
|
SECTIONS = cp.get("general", "sections")
|
||||||
ADMIN_EMAIL = cp.get('general','ADMIN_EMAIL')
|
ADMIN_EMAIL = cp.get("general", "ADMIN_EMAIL")
|
||||||
BASE_DIR = cp.get('general','base_config_dir')
|
BASE_DIR = cp.get("general", "base_config_dir")
|
||||||
|
|
||||||
tisbackup_config_file= CONFIG[0]
|
tisbackup_config_file = CONFIG[0]
|
||||||
config_number=0
|
config_number = 0
|
||||||
|
|
||||||
cp = ConfigParser()
|
cp = ConfigParser()
|
||||||
cp.read(tisbackup_config_file)
|
cp.read(tisbackup_config_file)
|
||||||
backup_base_dir = cp.get('global','backup_base_dir')
|
backup_base_dir = cp.get("global", "backup_base_dir")
|
||||||
dbstat = BackupStat(os.path.join(backup_base_dir,'log','tisbackup.sqlite'))
|
dbstat = BackupStat(os.path.join(backup_base_dir, "log", "tisbackup.sqlite"))
|
||||||
mindate = None
|
mindate = None
|
||||||
error = None
|
error = None
|
||||||
info = None
|
info = None
|
||||||
app = Flask(__name__)
|
app = Flask(__name__)
|
||||||
app.secret_key = 'fsiqefiuqsefARZ4Zfesfe34234dfzefzfe'
|
app.secret_key = "fsiqefiuqsefARZ4Zfesfe34234dfzefzfe"
|
||||||
app.config['PROPAGATE_EXCEPTIONS'] = True
|
app.config["PROPAGATE_EXCEPTIONS"] = True
|
||||||
|
|
||||||
tasks_db = os.path.join(tisbackup_root_dir,"tasks.sqlite")
|
tasks_db = os.path.join(tisbackup_root_dir, "tasks.sqlite")
|
||||||
|
|
||||||
|
|
||||||
def read_all_configs(base_dir):
|
def read_all_configs(base_dir):
|
||||||
raw_configs = []
|
raw_configs = []
|
||||||
list_config = []
|
list_config = []
|
||||||
config_base_dir = base_dir
|
# config_base_dir = base_dir
|
||||||
|
|
||||||
for file in os.listdir(base_dir):
|
for file in os.listdir(base_dir):
|
||||||
if isfile(join(base_dir,file)):
|
if isfile(join(base_dir, file)):
|
||||||
raw_configs.append(join(base_dir,file))
|
raw_configs.append(join(base_dir, file))
|
||||||
|
|
||||||
for elem in raw_configs:
|
for elem in raw_configs:
|
||||||
line = open(elem).readline()
|
line = open(elem).readline()
|
||||||
if 'global' in line:
|
if "global" in line:
|
||||||
list_config.append(elem)
|
list_config.append(elem)
|
||||||
|
|
||||||
backup_dict = {}
|
backup_dict = {}
|
||||||
backup_dict['rsync_ssh_list'] = []
|
backup_dict["rsync_ssh_list"] = []
|
||||||
backup_dict['rsync_btrfs_list'] = []
|
backup_dict["rsync_btrfs_list"] = []
|
||||||
backup_dict['rsync_list'] = []
|
backup_dict["rsync_list"] = []
|
||||||
backup_dict['null_list'] = []
|
backup_dict["null_list"] = []
|
||||||
backup_dict['pgsql_list'] = []
|
backup_dict["pgsql_list"] = []
|
||||||
backup_dict['mysql_list'] = []
|
backup_dict["mysql_list"] = []
|
||||||
#backup_dict['sqlserver_list'] = []
|
# backup_dict['sqlserver_list'] = []
|
||||||
backup_dict['xva_list'] = []
|
backup_dict["xva_list"] = []
|
||||||
backup_dict['metadata_list'] = []
|
backup_dict["metadata_list"] = []
|
||||||
#backup_dict['switch_list'] = []
|
# backup_dict['switch_list'] = []
|
||||||
#backup_dict['oracle_list'] = []
|
# backup_dict['oracle_list'] = []
|
||||||
|
|
||||||
result = []
|
result = []
|
||||||
cp = ConfigParser()
|
cp = ConfigParser()
|
||||||
for config_file in list_config:
|
for config_file in list_config:
|
||||||
cp.read(config_file)
|
cp.read(config_file)
|
||||||
|
|
||||||
backup_base_dir = cp.get('global', 'backup_base_dir')
|
backup_base_dir = cp.get("global", "backup_base_dir")
|
||||||
backup = tis_backup(backup_base_dir=backup_base_dir)
|
backup = tis_backup(backup_base_dir=backup_base_dir)
|
||||||
backup.read_ini_file(config_file)
|
backup.read_ini_file(config_file)
|
||||||
|
|
||||||
@ -110,11 +110,12 @@ def read_all_configs(base_dir):
|
|||||||
backup_sections = all_sections
|
backup_sections = all_sections
|
||||||
else:
|
else:
|
||||||
for b in backup_sections:
|
for b in backup_sections:
|
||||||
if not b in all_sections:
|
if b not in all_sections:
|
||||||
raise Exception('Section %s is not defined in config file' % b)
|
raise Exception("Section %s is not defined in config file" % b)
|
||||||
|
|
||||||
if not backup_sections:
|
# never used..
|
||||||
sections = [backup_item.backup_name for backup_item in backup.backup_list]
|
# if not backup_sections:
|
||||||
|
# sections = [backup_item.backup_name for backup_item in backup.backup_list]
|
||||||
|
|
||||||
for backup_item in backup.backup_list:
|
for backup_item in backup.backup_list:
|
||||||
if backup_item.backup_name in backup_sections:
|
if backup_item.backup_name in backup_sections:
|
||||||
@ -125,35 +126,28 @@ def read_all_configs(base_dir):
|
|||||||
result.append(b)
|
result.append(b)
|
||||||
|
|
||||||
for row in result:
|
for row in result:
|
||||||
backup_name = row['backup_name']
|
backup_name = row["backup_name"]
|
||||||
server_name = row['server_name']
|
server_name = row["server_name"]
|
||||||
backup_type = row['type']
|
backup_type = row["type"]
|
||||||
if backup_type == "xcp-dump-metadata":
|
if backup_type == "xcp-dump-metadata":
|
||||||
backup_dict['metadata_list'].append(
|
backup_dict["metadata_list"].append([server_name, backup_name, backup_type, ""])
|
||||||
[server_name, backup_name, backup_type, ""])
|
|
||||||
if backup_type == "rsync+ssh":
|
if backup_type == "rsync+ssh":
|
||||||
remote_dir = row['remote_dir']
|
remote_dir = row["remote_dir"]
|
||||||
backup_dict['rsync_ssh_list'].append(
|
backup_dict["rsync_ssh_list"].append([server_name, backup_name, backup_type, remote_dir])
|
||||||
[server_name, backup_name, backup_type, remote_dir])
|
|
||||||
if backup_type == "rsync+btrfs+ssh":
|
if backup_type == "rsync+btrfs+ssh":
|
||||||
remote_dir = row['remote_dir']
|
remote_dir = row["remote_dir"]
|
||||||
backup_dict['rsync_btrfs_list'].append(
|
backup_dict["rsync_btrfs_list"].append([server_name, backup_name, backup_type, remote_dir])
|
||||||
[server_name, backup_name, backup_type, remote_dir])
|
|
||||||
if backup_type == "rsync":
|
if backup_type == "rsync":
|
||||||
remote_dir = row['remote_dir']
|
remote_dir = row["remote_dir"]
|
||||||
backup_dict['rsync_list'].append(
|
backup_dict["rsync_list"].append([server_name, backup_name, backup_type, remote_dir])
|
||||||
[server_name, backup_name, backup_type, remote_dir])
|
|
||||||
if backup_type == "null":
|
if backup_type == "null":
|
||||||
backup_dict['null_list'].append(
|
backup_dict["null_list"].append([server_name, backup_name, backup_type, ""])
|
||||||
[server_name, backup_name, backup_type, ""])
|
|
||||||
if backup_type == "pgsql+ssh":
|
if backup_type == "pgsql+ssh":
|
||||||
db_name = row['db_name'] if len(row['db_name']) > 0 else '*'
|
db_name = row["db_name"] if len(row["db_name"]) > 0 else "*"
|
||||||
backup_dict['pgsql_list'].append(
|
backup_dict["pgsql_list"].append([server_name, backup_name, backup_type, db_name])
|
||||||
[server_name, backup_name, backup_type, db_name])
|
|
||||||
if backup_type == "mysql+ssh":
|
if backup_type == "mysql+ssh":
|
||||||
db_name = row['db_name'] if len(row['db_name']) > 0 else '*'
|
db_name = row["db_name"] if len(row["db_name"]) > 0 else "*"
|
||||||
backup_dict['mysql_list'].append(
|
backup_dict["mysql_list"].append([server_name, backup_name, backup_type, db_name])
|
||||||
[server_name, backup_name, backup_type, db_name])
|
|
||||||
# if backup_type == "sqlserver+ssh":
|
# if backup_type == "sqlserver+ssh":
|
||||||
# db_name = row['db_name']
|
# db_name = row['db_name']
|
||||||
# backup_dict['sqlserver_list'].append(
|
# backup_dict['sqlserver_list'].append(
|
||||||
@ -163,12 +157,11 @@ def read_all_configs(base_dir):
|
|||||||
# backup_dict['oracle_list'].append(
|
# backup_dict['oracle_list'].append(
|
||||||
# [server_name, backup_name, backup_type, db_name])
|
# [server_name, backup_name, backup_type, db_name])
|
||||||
if backup_type == "xen-xva":
|
if backup_type == "xen-xva":
|
||||||
backup_dict['xva_list'].append(
|
backup_dict["xva_list"].append([server_name, backup_name, backup_type, ""])
|
||||||
[server_name, backup_name, backup_type, ""])
|
|
||||||
# if backup_type == "switch":
|
# if backup_type == "switch":
|
||||||
# backup_dict['switch_list'].append(
|
# backup_dict['switch_list'].append(
|
||||||
# [server_name, backup_name, backup_type, ""])
|
# [server_name, backup_name, backup_type, ""])
|
||||||
|
|
||||||
return backup_dict
|
return backup_dict
|
||||||
|
|
||||||
|
|
||||||
@ -177,7 +170,7 @@ def read_config():
|
|||||||
cp = ConfigParser()
|
cp = ConfigParser()
|
||||||
cp.read(config_file)
|
cp.read(config_file)
|
||||||
|
|
||||||
backup_base_dir = cp.get('global','backup_base_dir')
|
backup_base_dir = cp.get("global", "backup_base_dir")
|
||||||
backup = tis_backup(backup_base_dir=backup_base_dir)
|
backup = tis_backup(backup_base_dir=backup_base_dir)
|
||||||
backup.read_ini_file(config_file)
|
backup.read_ini_file(config_file)
|
||||||
|
|
||||||
@ -188,56 +181,58 @@ def read_config():
|
|||||||
backup_sections = all_sections
|
backup_sections = all_sections
|
||||||
else:
|
else:
|
||||||
for b in backup_sections:
|
for b in backup_sections:
|
||||||
if not b in all_sections:
|
if b not in all_sections:
|
||||||
raise Exception('Section %s is not defined in config file' % b)
|
raise Exception("Section %s is not defined in config file" % b)
|
||||||
|
|
||||||
result = []
|
result = []
|
||||||
if not backup_sections:
|
|
||||||
sections = [backup_item.backup_name for backup_item in backup.backup_list]
|
# not used ...
|
||||||
|
# if not backup_sections:
|
||||||
|
# sections = [backup_item.backup_name for backup_item in backup.backup_list]
|
||||||
|
|
||||||
for backup_item in backup.backup_list:
|
for backup_item in backup.backup_list:
|
||||||
if backup_item.backup_name in backup_sections:
|
if backup_item.backup_name in backup_sections:
|
||||||
b = {}
|
b = {}
|
||||||
for attrib_name in backup_item.required_params+backup_item.optional_params:
|
for attrib_name in backup_item.required_params + backup_item.optional_params:
|
||||||
if hasattr(backup_item,attrib_name):
|
if hasattr(backup_item, attrib_name):
|
||||||
b[attrib_name] = getattr(backup_item,attrib_name)
|
b[attrib_name] = getattr(backup_item, attrib_name)
|
||||||
result.append(b)
|
result.append(b)
|
||||||
|
|
||||||
backup_dict = {}
|
backup_dict = {}
|
||||||
backup_dict['rsync_ssh_list'] = []
|
backup_dict["rsync_ssh_list"] = []
|
||||||
backup_dict['rsync_btrfs_list'] = []
|
backup_dict["rsync_btrfs_list"] = []
|
||||||
backup_dict['rsync_list'] = []
|
backup_dict["rsync_list"] = []
|
||||||
backup_dict['null_list'] = []
|
backup_dict["null_list"] = []
|
||||||
backup_dict['pgsql_list'] = []
|
backup_dict["pgsql_list"] = []
|
||||||
backup_dict['mysql_list'] = []
|
backup_dict["mysql_list"] = []
|
||||||
#backup_dict['sqlserver_list'] = []
|
# backup_dict['sqlserver_list'] = []
|
||||||
backup_dict['xva_list'] = []
|
backup_dict["xva_list"] = []
|
||||||
backup_dict['metadata_list'] = []
|
backup_dict["metadata_list"] = []
|
||||||
#backup_dict['switch_list'] = []
|
# backup_dict['switch_list'] = []
|
||||||
#backup_dict['oracle_list'] = []
|
# backup_dict['oracle_list'] = []
|
||||||
for row in result:
|
for row in result:
|
||||||
backup_name = row['backup_name']
|
backup_name = row["backup_name"]
|
||||||
server_name = row['server_name']
|
server_name = row["server_name"]
|
||||||
backup_type = row['type']
|
backup_type = row["type"]
|
||||||
if backup_type == "xcp-dump-metadata":
|
if backup_type == "xcp-dump-metadata":
|
||||||
backup_dict['metadata_list'].append([server_name, backup_name, backup_type, ""])
|
backup_dict["metadata_list"].append([server_name, backup_name, backup_type, ""])
|
||||||
if backup_type == "rsync+ssh":
|
if backup_type == "rsync+ssh":
|
||||||
remote_dir = row['remote_dir']
|
remote_dir = row["remote_dir"]
|
||||||
backup_dict['rsync_ssh_list'].append([server_name, backup_name, backup_type,remote_dir])
|
backup_dict["rsync_ssh_list"].append([server_name, backup_name, backup_type, remote_dir])
|
||||||
if backup_type == "rsync+btrfs+ssh":
|
if backup_type == "rsync+btrfs+ssh":
|
||||||
remote_dir = row['remote_dir']
|
remote_dir = row["remote_dir"]
|
||||||
backup_dict['rsync_btrfs_list'].append([server_name, backup_name, backup_type,remote_dir])
|
backup_dict["rsync_btrfs_list"].append([server_name, backup_name, backup_type, remote_dir])
|
||||||
if backup_type == "rsync":
|
if backup_type == "rsync":
|
||||||
remote_dir = row['remote_dir']
|
remote_dir = row["remote_dir"]
|
||||||
backup_dict['rsync_list'].append([server_name, backup_name, backup_type,remote_dir])
|
backup_dict["rsync_list"].append([server_name, backup_name, backup_type, remote_dir])
|
||||||
if backup_type == "null":
|
if backup_type == "null":
|
||||||
backup_dict['null_list'].append([server_name, backup_name, backup_type, ""])
|
backup_dict["null_list"].append([server_name, backup_name, backup_type, ""])
|
||||||
if backup_type == "pgsql+ssh":
|
if backup_type == "pgsql+ssh":
|
||||||
db_name = row['db_name'] if len(row['db_name']) > 0 else '*'
|
db_name = row["db_name"] if len(row["db_name"]) > 0 else "*"
|
||||||
backup_dict['pgsql_list'].append([server_name, backup_name, backup_type, db_name])
|
backup_dict["pgsql_list"].append([server_name, backup_name, backup_type, db_name])
|
||||||
if backup_type == "mysql+ssh":
|
if backup_type == "mysql+ssh":
|
||||||
db_name = row['db_name'] if len(row['db_name']) > 0 else '*'
|
db_name = row["db_name"] if len(row["db_name"]) > 0 else "*"
|
||||||
backup_dict['mysql_list'].append([server_name, backup_name, backup_type, db_name])
|
backup_dict["mysql_list"].append([server_name, backup_name, backup_type, db_name])
|
||||||
# if backup_type == "sqlserver+ssh":
|
# if backup_type == "sqlserver+ssh":
|
||||||
# db_name = row['db_name']
|
# db_name = row['db_name']
|
||||||
# backup_dict['sqlserver_list'].append([server_name, backup_name, backup_type, db_name])
|
# backup_dict['sqlserver_list'].append([server_name, backup_name, backup_type, db_name])
|
||||||
@ -245,49 +240,68 @@ def read_config():
|
|||||||
# db_name = row['db_name']
|
# db_name = row['db_name']
|
||||||
# backup_dict['oracle_list'].append([server_name, backup_name, backup_type, db_name])
|
# backup_dict['oracle_list'].append([server_name, backup_name, backup_type, db_name])
|
||||||
if backup_type == "xen-xva":
|
if backup_type == "xen-xva":
|
||||||
backup_dict['xva_list'].append([server_name, backup_name, backup_type, ""])
|
backup_dict["xva_list"].append([server_name, backup_name, backup_type, ""])
|
||||||
# if backup_type == "switch":
|
# if backup_type == "switch":
|
||||||
# backup_dict['switch_list'].append([server_name, backup_name, backup_type, ""])
|
# backup_dict['switch_list'].append([server_name, backup_name, backup_type, ""])
|
||||||
return backup_dict
|
return backup_dict
|
||||||
|
|
||||||
@app.route('/')
|
|
||||||
|
@app.route("/")
|
||||||
def backup_all():
|
def backup_all():
|
||||||
backup_dict = read_config()
|
backup_dict = read_config()
|
||||||
return render_template('backups.html', backup_list = backup_dict)
|
return render_template("backups.html", backup_list=backup_dict)
|
||||||
|
|
||||||
|
|
||||||
@app.route('/config_number/')
|
@app.route("/config_number/")
|
||||||
@app.route('/config_number/<int:id>')
|
@app.route("/config_number/<int:id>")
|
||||||
def set_config_number(id=None):
|
def set_config_number(id=None):
|
||||||
if id != None and len(CONFIG) > id:
|
if id is not None and len(CONFIG) > id:
|
||||||
global config_number
|
global config_number
|
||||||
config_number=id
|
config_number = id
|
||||||
read_config()
|
read_config()
|
||||||
return jsonify(configs=CONFIG,config_number=config_number)
|
return jsonify(configs=CONFIG, config_number=config_number)
|
||||||
|
|
||||||
|
|
||||||
@app.route('/all_json')
|
@app.route("/all_json")
|
||||||
def backup_all_json():
|
def backup_all_json():
|
||||||
backup_dict = read_all_configs(BASE_DIR)
|
backup_dict = read_all_configs(BASE_DIR)
|
||||||
return json.dumps(backup_dict['rsync_list']+backup_dict['rsync_btrfs_list']+backup_dict['rsync_ssh_list']+backup_dict['pgsql_list']+backup_dict['mysql_list']+backup_dict['xva_list']+backup_dict['null_list']+backup_dict['metadata_list'])
|
return json.dumps(
|
||||||
#+ backup_dict['switch_list'])+backup_dict['sqlserver_list']
|
backup_dict["rsync_list"]
|
||||||
|
+ backup_dict["rsync_btrfs_list"]
|
||||||
|
+ backup_dict["rsync_ssh_list"]
|
||||||
|
+ backup_dict["pgsql_list"]
|
||||||
|
+ backup_dict["mysql_list"]
|
||||||
|
+ backup_dict["xva_list"]
|
||||||
|
+ backup_dict["null_list"]
|
||||||
|
+ backup_dict["metadata_list"]
|
||||||
|
)
|
||||||
|
# + backup_dict['switch_list'])+backup_dict['sqlserver_list']
|
||||||
|
|
||||||
|
|
||||||
@app.route('/json')
|
@app.route("/json")
|
||||||
def backup_json():
|
def backup_json():
|
||||||
backup_dict = read_config()
|
backup_dict = read_config()
|
||||||
return json.dumps(backup_dict['rsync_list']+backup_dict['rsync_btrfs_list']+backup_dict['rsync_ssh_list']+backup_dict['pgsql_list']+backup_dict['mysql_list']+backup_dict['xva_list']+backup_dict['null_list']+backup_dict['metadata_list'])
|
return json.dumps(
|
||||||
#+ backup_dict['switch_list'])+backup_dict['sqlserver_list']
|
backup_dict["rsync_list"]
|
||||||
|
+ backup_dict["rsync_btrfs_list"]
|
||||||
|
+ backup_dict["rsync_ssh_list"]
|
||||||
|
+ backup_dict["pgsql_list"]
|
||||||
|
+ backup_dict["mysql_list"]
|
||||||
|
+ backup_dict["xva_list"]
|
||||||
|
+ backup_dict["null_list"]
|
||||||
|
+ backup_dict["metadata_list"]
|
||||||
|
)
|
||||||
|
# + backup_dict['switch_list'])+backup_dict['sqlserver_list']
|
||||||
|
|
||||||
|
|
||||||
def check_usb_disk():
|
def check_usb_disk():
|
||||||
"""This method returns the mounts point of FIRST external disk"""
|
"""This method returns the mounts point of FIRST external disk"""
|
||||||
# disk_name = []
|
# disk_name = []
|
||||||
usb_disk_list = []
|
usb_disk_list = []
|
||||||
for name in glob.glob('/dev/sd[a-z]'):
|
for name in glob.glob("/dev/sd[a-z]"):
|
||||||
for line in os.popen("udevadm info -q env -n %s" % name):
|
for line in os.popen("udevadm info -q env -n %s" % name):
|
||||||
if re.match("ID_PATH=.*usb.*", line):
|
if re.match("ID_PATH=.*usb.*", line):
|
||||||
usb_disk_list += [ name ]
|
usb_disk_list += [name]
|
||||||
|
|
||||||
if len(usb_disk_list) == 0:
|
if len(usb_disk_list) == 0:
|
||||||
raise_error("Cannot find any external usb disk", "You should plug the usb hard drive into the server")
|
raise_error("Cannot find any external usb disk", "You should plug the usb hard drive into the server")
|
||||||
@ -296,20 +310,23 @@ def check_usb_disk():
|
|||||||
|
|
||||||
usb_partition_list = []
|
usb_partition_list = []
|
||||||
for usb_disk in usb_disk_list:
|
for usb_disk in usb_disk_list:
|
||||||
cmd = "udevadm info -q path -n %s" % usb_disk + '1'
|
cmd = "udevadm info -q path -n %s" % usb_disk + "1"
|
||||||
output = os.popen(cmd).read()
|
output = os.popen(cmd).read()
|
||||||
print("cmd : " + cmd)
|
print("cmd : " + cmd)
|
||||||
print("output : " + output)
|
print("output : " + output)
|
||||||
|
|
||||||
if '/devices/pci' in output:
|
if "/devices/pci" in output:
|
||||||
#flash("partition found: %s1" % usb_disk)
|
# flash("partition found: %s1" % usb_disk)
|
||||||
usb_partition_list.append(usb_disk + "1")
|
usb_partition_list.append(usb_disk + "1")
|
||||||
|
|
||||||
print(usb_partition_list)
|
print(usb_partition_list)
|
||||||
|
|
||||||
if len(usb_partition_list) ==0:
|
if len(usb_partition_list) == 0:
|
||||||
raise_error("The drive %s has no partition" % (usb_disk_list[0] ), "You should initialize the usb drive and format an ext4 partition with TISBACKUP label")
|
raise_error(
|
||||||
return ""
|
"The drive %s has no partition" % (usb_disk_list[0]),
|
||||||
|
"You should initialize the usb drive and format an ext4 partition with TISBACKUP label",
|
||||||
|
)
|
||||||
|
return ""
|
||||||
|
|
||||||
tisbackup_partition_list = []
|
tisbackup_partition_list = []
|
||||||
for usb_partition in usb_partition_list:
|
for usb_partition in usb_partition_list:
|
||||||
@ -317,133 +334,139 @@ def check_usb_disk():
|
|||||||
flash("tisbackup backup partition found: %s" % usb_partition)
|
flash("tisbackup backup partition found: %s" % usb_partition)
|
||||||
tisbackup_partition_list.append(usb_partition)
|
tisbackup_partition_list.append(usb_partition)
|
||||||
|
|
||||||
print(tisbackup_partition_list)
|
print(tisbackup_partition_list)
|
||||||
|
|
||||||
if len(tisbackup_partition_list) ==0:
|
if len(tisbackup_partition_list) == 0:
|
||||||
raise_error("No tisbackup partition exist on disk %s" % (usb_disk_list[0] ), "You should initialize the usb drive and format an ext4 partition with TISBACKUP label")
|
raise_error(
|
||||||
|
"No tisbackup partition exist on disk %s" % (usb_disk_list[0]),
|
||||||
|
"You should initialize the usb drive and format an ext4 partition with TISBACKUP label",
|
||||||
|
)
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
if len(tisbackup_partition_list) > 1:
|
if len(tisbackup_partition_list) > 1:
|
||||||
raise_error("There are many usb disk", "You should plug remove one of them")
|
raise_error("There are many usb disk", "You should plug remove one of them")
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
|
|
||||||
return tisbackup_partition_list[0]
|
return tisbackup_partition_list[0]
|
||||||
|
|
||||||
|
|
||||||
def check_already_mount(partition_name,refresh):
|
def check_already_mount(partition_name, refresh):
|
||||||
with open('/proc/mounts') as f:
|
with open("/proc/mounts") as f:
|
||||||
mount_point = ""
|
mount_point = ""
|
||||||
for line in f.readlines():
|
for line in f.readlines():
|
||||||
if line.startswith(partition_name):
|
if line.startswith(partition_name):
|
||||||
mount_point = line.split(' ')[1]
|
mount_point = line.split(" ")[1]
|
||||||
if not refresh:
|
if not refresh:
|
||||||
run_command("/bin/umount %s" % mount_point)
|
run_command("/bin/umount %s" % mount_point)
|
||||||
os.rmdir(mount_point)
|
os.rmdir(mount_point)
|
||||||
return mount_point
|
return mount_point
|
||||||
|
|
||||||
|
|
||||||
def run_command(cmd, info=""):
|
def run_command(cmd, info=""):
|
||||||
flash("Executing: %s"% cmd)
|
flash("Executing: %s" % cmd)
|
||||||
from subprocess import CalledProcessError, check_output
|
from subprocess import CalledProcessError, check_output
|
||||||
result =""
|
|
||||||
|
result = ""
|
||||||
try:
|
try:
|
||||||
result = check_output(cmd, stderr=subprocess.STDOUT,shell=True)
|
result = check_output(cmd, stderr=subprocess.STDOUT, shell=True)
|
||||||
except CalledProcessError as e:
|
except CalledProcessError:
|
||||||
raise_error(result,info)
|
raise_error(result, info)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def check_mount_disk(partition_name, refresh):
|
|
||||||
|
|
||||||
mount_point = check_already_mount(partition_name, refresh)
|
|
||||||
if not refresh:
|
|
||||||
|
|
||||||
|
|
||||||
mount_point = "/mnt/TISBACKUP-" +str(time.time())
|
def check_mount_disk(partition_name, refresh):
|
||||||
|
|
||||||
|
mount_point = check_already_mount(partition_name, refresh)
|
||||||
|
if not refresh:
|
||||||
|
|
||||||
|
mount_point = "/mnt/TISBACKUP-" + str(time.time())
|
||||||
os.mkdir(mount_point)
|
os.mkdir(mount_point)
|
||||||
flash("must mount " + partition_name )
|
flash("must mount " + partition_name)
|
||||||
cmd = "mount %s %s" % (partition_name, mount_point)
|
cmd = "mount %s %s" % (partition_name, mount_point)
|
||||||
if run_command(cmd,"You should manualy mount the usb drive") != "":
|
if run_command(cmd, "You should manualy mount the usb drive") != "":
|
||||||
flash("Remove directory: %s" % mount_point)
|
flash("Remove directory: %s" % mount_point)
|
||||||
os.rmdir(mount_point)
|
os.rmdir(mount_point)
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
return mount_point
|
return mount_point
|
||||||
|
|
||||||
@app.route('/status.json')
|
|
||||||
|
@app.route("/status.json")
|
||||||
def export_backup_status():
|
def export_backup_status():
|
||||||
exports = dbstat.query('select * from stats where TYPE="EXPORT" and backup_start>="%s"' % mindate)
|
exports = dbstat.query('select * from stats where TYPE="EXPORT" and backup_start>="%s"' % mindate)
|
||||||
error = ""
|
error = ""
|
||||||
finish=not runnings_backups()
|
finish = not runnings_backups()
|
||||||
if get_task() != None and finish:
|
if get_task() is not None and finish:
|
||||||
status = get_task().get()
|
status = get_task().get()
|
||||||
if status != "ok":
|
if status != "ok":
|
||||||
error = "Export failing with error: "+status
|
error = "Export failing with error: " + status
|
||||||
|
|
||||||
|
return jsonify(data=exports, finish=finish, error=error)
|
||||||
|
|
||||||
|
|
||||||
return jsonify(data=exports,finish=finish,error=error)
|
|
||||||
|
|
||||||
def runnings_backups():
|
def runnings_backups():
|
||||||
task = get_task()
|
task = get_task()
|
||||||
is_runnig = (task != None)
|
is_runnig = task is not None
|
||||||
finish = ( is_runnig and task.get() != None)
|
finish = is_runnig and task.get() is not None
|
||||||
return is_runnig and not finish
|
return is_runnig and not finish
|
||||||
|
|
||||||
|
|
||||||
@app.route('/backups.json')
|
@app.route("/backups.json")
|
||||||
def last_backup_json():
|
def last_backup_json():
|
||||||
exports = dbstat.query('select * from stats where TYPE="BACKUP" ORDER BY backup_start DESC ')
|
exports = dbstat.query('select * from stats where TYPE="BACKUP" ORDER BY backup_start DESC ')
|
||||||
return Response(response=json.dumps(exports),
|
return Response(response=json.dumps(exports), status=200, mimetype="application/json")
|
||||||
status=200,
|
|
||||||
mimetype="application/json")
|
|
||||||
|
|
||||||
|
|
||||||
@app.route('/last_backups')
|
@app.route("/last_backups")
|
||||||
def last_backup():
|
def last_backup():
|
||||||
exports = dbstat.query('select * from stats where TYPE="BACKUP" ORDER BY backup_start DESC LIMIT 20 ')
|
exports = dbstat.query('select * from stats where TYPE="BACKUP" ORDER BY backup_start DESC LIMIT 20 ')
|
||||||
return render_template("last_backups.html", backups=exports)
|
return render_template("last_backups.html", backups=exports)
|
||||||
|
|
||||||
|
|
||||||
@app.route('/export_backup')
|
@app.route("/export_backup")
|
||||||
def export_backup():
|
def export_backup():
|
||||||
|
|
||||||
raise_error("", "")
|
raise_error("", "")
|
||||||
backup_dict = read_config()
|
backup_dict = read_config()
|
||||||
sections = []
|
sections = []
|
||||||
backup_sections = []
|
backup_sections = []
|
||||||
for backup_types in backup_dict:
|
for backup_types in backup_dict:
|
||||||
if backup_types == "null_list":
|
if backup_types == "null_list":
|
||||||
continue
|
continue
|
||||||
for section in backup_dict[backup_types]:
|
for section in backup_dict[backup_types]:
|
||||||
#if section.count > 0:
|
# if section.count > 0:
|
||||||
if len(section) > 0:
|
if len(section) > 0:
|
||||||
sections.append(section[1])
|
sections.append(section[1])
|
||||||
|
|
||||||
noJobs = (not runnings_backups())
|
noJobs = not runnings_backups()
|
||||||
if "start" in list(request.args.keys()) or not noJobs:
|
if "start" in list(request.args.keys()) or not noJobs:
|
||||||
start=True
|
start = True
|
||||||
if "sections" in list(request.args.keys()):
|
if "sections" in list(request.args.keys()):
|
||||||
backup_sections = request.args.getlist('sections')
|
backup_sections = request.args.getlist("sections")
|
||||||
|
|
||||||
|
|
||||||
else:
|
else:
|
||||||
start=False
|
start = False
|
||||||
cp.read(tisbackup_config_file)
|
cp.read(tisbackup_config_file)
|
||||||
|
|
||||||
partition_name = check_usb_disk()
|
partition_name = check_usb_disk()
|
||||||
if partition_name:
|
if partition_name:
|
||||||
if noJobs:
|
if noJobs:
|
||||||
mount_point = check_mount_disk( partition_name, False)
|
mount_point = check_mount_disk(partition_name, False)
|
||||||
else:
|
else:
|
||||||
mount_point = check_mount_disk( partition_name, True)
|
mount_point = check_mount_disk(partition_name, True)
|
||||||
if noJobs:
|
if noJobs:
|
||||||
global mindate
|
global mindate
|
||||||
mindate = datetime2isodate(datetime.datetime.now())
|
mindate = datetime2isodate(datetime.datetime.now())
|
||||||
if not error and start:
|
if not error and start:
|
||||||
print(tisbackup_config_file)
|
print(tisbackup_config_file)
|
||||||
task = run_export_backup(base=backup_base_dir, config_file=CONFIG[config_number], mount_point=mount_point, backup_sections=",".join([str(x) for x in backup_sections]))
|
task = run_export_backup(
|
||||||
|
base=backup_base_dir,
|
||||||
|
config_file=CONFIG[config_number],
|
||||||
|
mount_point=mount_point,
|
||||||
|
backup_sections=",".join([str(x) for x in backup_sections]),
|
||||||
|
)
|
||||||
set_task(task)
|
set_task(task)
|
||||||
|
|
||||||
|
|
||||||
return render_template("export_backup.html", error=error, start=start, info=info, email=ADMIN_EMAIL, sections=sections)
|
return render_template("export_backup.html", error=error, start=start, info=info, email=ADMIN_EMAIL, sections=sections)
|
||||||
|
|
||||||
|
|
||||||
@ -453,9 +476,10 @@ def raise_error(strError, strInfo):
|
|||||||
info = strInfo
|
info = strInfo
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
read_config()
|
read_config()
|
||||||
from os import environ
|
from os import environ
|
||||||
if 'WINGDB_ACTIVE' in environ:
|
|
||||||
|
if "WINGDB_ACTIVE" in environ:
|
||||||
app.debug = False
|
app.debug = False
|
||||||
app.run(host= '0.0.0.0',port=8080)
|
app.run(host="0.0.0.0", port=8080)
|
||||||
|
Loading…
Reference in New Issue
Block a user