Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
I
iml-backup
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Releases
Container registry
Model registry
Operate
Environments
Monitor
Incidents
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
IML Open Source
iml-backup
Commits
56b798af
Commit
56b798af
authored
1 year ago
by
Hahn Axel (hahn)
Browse files
Options
Downloads
Patches
Plain Diff
reformat code; fix restore permissions
parent
c9f05d74
Branches
Branches containing commit
No related tags found
1 merge request
!129
Db Profiles
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
localdump.sh
+544
-534
544 additions, 534 deletions
localdump.sh
with
544 additions
and
534 deletions
localdump.sh
+
544
−
534
View file @
56b798af
...
...
@@ -16,9 +16,11 @@
# 2022-02-18 ..... WIP: use class like functions
# 2022-03-17 ..... WIP: add lines with prefix __DB__
# 2022-11-04 ah rename hooks
# 2024-03-14 ah v2.0: use profiles for local and remote databases
# ======================================================================
# --- variables:
# ARCHIVE_BASEDIR {string} base directory for db archive (couchdb2 only)
# BACKUP_BASEDIR {string} base directory for db dumps
# BACKUP_DATE {string} string with current timestamp; will be part of filename for backups
# BACKUP_KEEP_DAYS {int} count of days how long to keep db dumps below $BACKUP_BASEDIR
...
...
@@ -31,606 +33,614 @@
# CONFIG VARS
# ----------------------------------------------------------------------
.
$(
dirname
$0
)
/vendor/ini.class.sh
||
exit
1
.
$(
dirname
$0
)
/vendor/color.class.sh
||
exit
1
.
$(
dirname
$0
)
/vendor/ini.class.sh
||
exit
1
.
$(
dirname
$0
)
/vendor/color.class.sh
||
exit
1
.
$(
dirname
$0
)
/includes/jobhelper.sh
||
exit
1
.
$(
dirname
$0
)
/includes/inc_bash.sh
||
exit
1
.
$(
dirname
$0
)
/includes/jobhelper.sh
||
exit
1
.
$(
dirname
$0
)
/includes/inc_bash.sh
||
exit
1
.
$(
dirname
$0
)
/includes/dbdetect.class.sh
||
exit
1
.
$(
dirname
$0
)
/includes/dbdetect.class.sh
||
exit
1
if
[
!
-r
"
${
JOBFILE
}
"
]
;
then
color.echo error
"ERROR: missing config file
${
JOBFILE
}
."
exit
1
fi
if
[
!
-r
"
${
JOBFILE
}
"
]
;
then
color.echo error
"ERROR: missing config file
${
JOBFILE
}
."
exit
1
fi
LOCALDUMP_LOADED
=
1
LOCALDUMP_LOADED
=
1
ARCHIVE_BASEDIR
=
BACKUP_BASEDIR
=
BACKUP_PLUGINDIR
=
ARCHIVE_BASEDIR
=
BACKUP_BASEDIR
=
BACKUP_PLUGINDIR
=
DBD_DEBUG
=
0
DBD_DEBUG
=
0
# Cleanup local dumps older N days
typeset
-i
BACKUP_KEEP_DAYS
=
0
# Cleanup local dumps older N days
typeset
-i
BACKUP_KEEP_DAYS
=
0
BACKUP_DATE
=
BACKUP_DATE
=
LASTINPUT
=
# ----------------------------------------------------------------------
# FUNCTIONS 4 DB-WRAPPER
# ----------------------------------------------------------------------
# helpfer function for SERVICENAME.backup
# it is called after the service specific dump was done.
# param {string} filename of created dump file
function
db._compressDumpfile
(){
local
_outfile
=
$1
# helpfer function for SERVICENAME.backup
# it is called after the service specific dump was done.
# param {string} filename of created dump file
function
db._compressDumpfile
(){
local
_outfile
=
$1
# $myrc is last returncode - set in fetchrc
if
[
$myrc
-eq
0
]
;
then
echo
-n
"gzip
$_outfile
... "
gzip
-9
-f
"
${
_outfile
}
"
fetchrc
else
color.echo error
"ERROR occured while dumping - no gzip of
$_outfile
"
fi
# echo -n "__DB__$SERVICENAME INFO: backup to "
# ls -l "$_outfile"* 2>&1
# echo
}
# $myrc is last returncode - set in fetchrc
if
[
$myrc
-eq
0
]
;
then
echo
-n
"gzip
$_outfile
... "
gzip
-9
-f
"
${
_outfile
}
"
fetchrc
else
color.echo error
"ERROR occured while dumping - no gzip of
$_outfile
"
fi
# echo -n "__DB__$SERVICENAME INFO: backup to "
# ls -l "$_outfile"* 2>&1
# echo
}
# ----------------------------------------------------------------------
# FUNCTIONS 4 BACKUP
# ----------------------------------------------------------------------
# ------------------------------------------------------------
# cleanup a backup dir: remove old files and delete empty dirs
function
cleanup_backup_target
(){
if
[
-d
"
${
BACKUP_TARGETDIR
}
"
]
;
then
h3
"CLEANUP
${
BACKUP_TARGETDIR
}
older
$BACKUP_KEEP_DAYS
days ..."
echo
find
"
${
BACKUP_TARGETDIR
}
"
-mtime
+
$BACKUP_KEEP_DAYS
-delete
-print
color.preset cmd
find
"
${
BACKUP_TARGETDIR
}
"
-mtime
+
$BACKUP_KEEP_DAYS
-delete
-print
color.reset
if
[
$(
find
"
${
BACKUP_TARGETDIR
}
"
-type
f |
wc
-l
)
-eq
0
]
;
then
echo
"INFO: the directory is empty - deleting it"
rm
-rf
"
${
BACKUP_TARGETDIR
}
"
fi
fi
}
# ------------------------------------------------------------
# compress a file
# shared function in localdump_*
# param string filename of uncompressed output file
function
compress_file
(){
echo
-n
compressing
$1
...
gzip
-9
-f
"
${
1
}
"
fetchrc
}
# ------------------------------------------------------------
# create a backup directory with name of service
# shared function in localdump_*
function
create_targetdir
(){
mkdir
-p
"
${
BACKUP_TARGETDIR
}
"
2>/dev/null
if
[
!
-d
"
${
BACKUP_TARGETDIR
}
"
]
;
then
color.echo
"error"
"FATAL ERROR: directory
${
BACKUP_TARGETDIR
}
was not created"
exit
1
fi
}
# ------------------------------------------------------------
# generate a base filename for backup dump based on on db name
# ... and added timestamp
# param string name of database schema
# --> see listBackupedDBs() and guessDB() - these function must be able to split this
function
get_outfile
(){
echo
$*
__
${
BACKUP_DATE
}
}
# ------------------------------------------------------------
# get name of a service script
# param string name of a service
function
get_service_script
(){
local
_service
=
$1
local
_type
;
_type
=
$(
dbdetect.getType
"
$_service
"
)
ls
-1
${
BACKUP_PLUGINDIR
}
/
${
_type
}
.sh 2>/dev/null
}
# ------------------------------------------------------------
# get a list of existing database profiles
function
get_database_profiles
(){
for
config
in
$(
dbdetect.getConfigs
)
;
do
if
dbdetect.exists
"
$config
"
;
then
echo
"
$(
dbdetect.getProfile
$config
)
"
# ------------------------------------------------------------
# cleanup a backup dir: remove old files and delete empty dirs
function
cleanup_backup_target
(){
if
[
-d
"
${
BACKUP_TARGETDIR
}
"
]
;
then
h3
"CLEANUP
${
BACKUP_TARGETDIR
}
older
$BACKUP_KEEP_DAYS
days ..."
echo
find
"
${
BACKUP_TARGETDIR
}
"
-mtime
+
$BACKUP_KEEP_DAYS
-delete
-print
color.preset cmd
find
"
${
BACKUP_TARGETDIR
}
"
-mtime
+
$BACKUP_KEEP_DAYS
-delete
-print
color.reset
if
[
$(
find
"
${
BACKUP_TARGETDIR
}
"
-type
f |
wc
-l
)
-eq
0
]
;
then
echo
"INFO: the directory is empty - deleting it"
rm
-rf
"
${
BACKUP_TARGETDIR
}
"
fi
fi
done
}
# ------------------------------------------------------------
# show directory infos with count of files and used space
# show used space and count of files and dirs
function
show_info_backup_target
(){
if
[
-d
"
${
BACKUP_TARGETDIR
}
"
]
;
then
h3
"INFO about backup target
${
BACKUP_TARGETDIR
}
"
echo
-n
"used space: "
du
-hs
"
${
BACKUP_TARGETDIR
}
"
echo
-n
"subdirs : "
find
"
${
BACKUP_TARGETDIR
}
"
-type
d |
wc
-l
echo
-n
"files : "
find
"
${
BACKUP_TARGETDIR
}
"
-type
f |
wc
-l
echo
-n
"free space: "
df
-h
"
${
BACKUP_TARGETDIR
}
"
|
tail
-1
|
awk
'{ print $4 }'
echo
fi
}
# ----------------------------------------------------------------------
# FUNCTIONS 4 RESTORE
# ----------------------------------------------------------------------
# ------------------------------------------------------------
# restore: show profiles from that exist backups
# global string BACKUP_BASEDIR base directory of all backups
function
listBackupedServices
(){
(
find
"
${
BACKUP_BASEDIR
}
"
-mindepth
1
-maxdepth
1
-type
d
-exec
basename
{}
\;
test
-n
"
${
ARCHIVE_BASEDIR
}
"
&&
find
"
${
ARCHIVE_BASEDIR
}
"
-mindepth
1
-maxdepth
1
-type
d
-exec
basename
{}
\;
)
|
sort
-u
}
# ------------------------------------------------------------
# restore: show databases or dumps of a given database that can be restored
# global string BACKUP_BASEDIR base directory of all backups of selected dbprofile
# param string optional: DB-Name for file filter to select from existing dumps;
function
listBackupedDBs
(){
if
[
-d
"
${
BACKUP_TARGETDIR
}
"
]
;
then
if
[
-z
$1
]
;
then
# list all databases
find
"
${
BACKUP_TARGETDIR
}
"
-mindepth
1
-maxdepth
1
-type
f
-exec
basename
{}
\;
\
|
sed
"s#__[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]-[0-9][0-9].*##g"
\
|
sed
"s#
\.
.*##g"
\
|
sort
-ud
|
sed
"s#^
\.
/##g"
else
# list dumps of a database
ls
-ltr
${
BACKUP_TARGETDIR
}
/
${
1
}*
gz |
sed
"s,
${
BACKUP_TARGETDIR
}
/,,g"
fi
}
else
color.echo error
"ERROR:
${
BACKUP_TARGETDIR
}
does not exist - here are no backups to restore."
echo
echo
"You can try to restore dumps:"
echo
"1) Restore dump files from a backup set"
echo
"
$(
dirname
$0
)
/restore.sh
$BACKUP_BASEDIR
"
echo
"2) Copy restored dumps into
$BACKUP_TARGETDIR
"
echo
"3) Start database restore again"
echo
"
$(
dirname
$0
)
/localdump.sh restore [profile]"
echo
exit
1
fi
}
# ------------------------------------------------------------
# guess name of the database file
# param string filename of db dump; can be full path or not
function
guessDB
(){
dumpfile
=
$1
# the metafile is written in sqlite backup to store full path
metafile
=
${
BACKUP_TARGETDIR
}
/
${
dumpfile
}
.meta
if
[
-f
$metafile
]
;
then
grep
"^/"
"
$metafile
"
||
grep
"^ File: "
"
$metafile
"
|
cut
-c
9-
else
sBasename
=
$(
basename
$1
)
sDb
=
$(
echo
${
sBasename
}
|
sed
"s#__[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]-[0-9][0-9].*##g"
)
if
[
-z
$sDb
]
;
then
color.echo error
"ERROR: db name was not detected from file
$1
"
exit
1
fi
echo
$sDb
fi
}
# read .meta file (that contains output of stats) and restore last owner and file permissions
# param string filename of db dump
# param string restored database file
function
restorePermissions
(){
local
sMyMeta
=
"
${
1
}
.meta"
local
sTargetfile
=
"
$2
"
if
[
-f
"
${
sMyMeta
}
"
]
;
then
# Access: (0674/-rw-rwxr--) Uid: ( 1000/ axel) Gid: ( 1000/ axel)
# ^ ^ ^
# _sPerm _sUser _sGroup
local
_sPerm
=
$(
grep
"^Access: ("
"
${
sMyMeta
}
"
|
cut
-f
2
-d
'('
|
cut
-f
1
-d
'/'
)
if
[
-n
"
$_sPerm
"
]
;
then
local
_sUser
=
$(
grep
"^Access: ("
"
${
sMyMeta
}
"
|
cut
-f
3
-d
'/'
|
cut
-f
1
-d
')'
|
tr
-d
' '
)
local
_sGroup
=
$(
grep
"^Access: ("
"
${
sMyMeta
}
"
|
cut
-f
4
-d
'/'
|
cut
-f
1
-d
')'
|
tr
-d
' '
)
echo
-n
"Restoring file owner
$_sUser
:
$_sGroup
and permissions
$_sPerm
... "
chown
"
$_sUser
:
$_sGroup
"
"
${
sTargetfile
}
"
&&
chmod
"
$_sPerm
"
"
${
sTargetfile
}
"
# ------------------------------------------------------------
# compress a file
# shared function in localdump_*
# param string filename of uncompressed output file
function
compress_file
(){
echo
-n
compressing
$1
...
gzip
-9
-f
"
${
1
}
"
fetchrc
fi
fi
}
# ------------------------------------------------------------
# show help
# ------------------------------------------------------------
function
showhelp
(){
local
_self
_self
=
$(
basename
"
$0
"
)
echo
echo
"LOCALDUMP detects existing local databases and dumps them locally."
echo
"It is included in the backup.sh to dump all before a file backup will store them."
echo
echo
"It can be started seperately for manual database backups or for restore"
echo
echo
"SYNTAX:"
echo
"
$_self
[OPTIONS] <operation> <profile [more_profiles]>"
echo
echo
"OPTIONS:"
echo
" -h|--help show this help"
echo
echo
"PARAMETERS:"
echo
" operation - one of check|backup|restore; optional parameter"
echo
" backup dump all databases/ schemes of a given service"
echo
" check show info only if the service is available"
echo
" restore import a dump into same or new database"
echo
" Without a filename it starts an interactive mode"
echo
" profile - name of database profiles"
echo
" You get a list of all available services without parameter"
echo
" Use ALL for bulk command"
echo
" file - filename of db dump to restore to origin database scheme"
echo
echo
"EXAMPLES:"
echo
"
$_self
backup"
echo
"
$_self
backup ALL"
echo
" Backup all databases of all found services"
echo
echo
"
$_self
backup mysql"
echo
" Backup all Mysql databases."
echo
echo
"
$_self
restore"
echo
" Start interactive restore of a database of any service."
echo
echo
"
$_self
restore sqlite"
echo
" Start interactive restore of an sqlite database."
echo
echo
"
$_self
restore <file-to-restore> [<database-name>]"
echo
" Restore a given dump file to the origin database scheme or"
echo
" to a new/ other database with the given name."
}
}
# ----------------------------------------------------------------------
# INIT
# ----------------------------------------------------------------------
while
[[
"$#"
-gt
0
]]
;
do case
$1
in
-h
|
--help
)
showhelp
;
exit
0
;;
*
)
if
grep
"^-"
<<<
"
$1
"
>
/dev/null
;
then
echo
;
echo
"ERROR: Unknown parameter:
$1
"
;
echo
;
showhelp
;
exit
2
# ------------------------------------------------------------
# create a backup directory with name of service
# shared function in localdump_*
function
create_targetdir
(){
mkdir
-p
"
${
BACKUP_TARGETDIR
}
"
2>/dev/null
if
[
!
-d
"
${
BACKUP_TARGETDIR
}
"
]
;
then
color.echo
"error"
"FATAL ERROR: directory
${
BACKUP_TARGETDIR
}
was not created"
exit
1
fi
break
;
;;
esac
;
done
mode
=
""
case
"
$1
"
in
backup|check|restore|shell
)
mode
=
$1
shift
1
;;
esac
if
[
-z
"
$mode
"
]
;
then
color.echo error
"ERROR: missing parameter for operation."
echo
showhelp
echo
echo
"Hint: On this machine working profiles:"
get_database_profiles |
nl
echo
exit
1
fi
# ----- init vars
BACKUP_BASEDIR
=
$(
_j_getvar
"
${
JOBFILE
}
"
"dir-localdumps"
)
# check
if
[
-z
"
$BACKUP_BASEDIR
"
]
;
then
color.echo error
"ERROR: missing config for backup target."
echo
There must be an entry dir-localdumps
in
${
JOBFILE
}
exit
1
fi
ARCHIVE_BASEDIR
=
$(
_j_getvar
"
${
JOBFILE
}
"
dir-dbarchive
)
BACKUP_PLUGINDIR
=
$(
dirname
$0
)
/plugins/localdump
DBD_BASEDIR
=
$BACKUP_PLUGINDIR
/profiles
BACKUP_KEEP_DAYS
=
$(
_j_getvar
${
JOBFILE
}
"keep-days"
)
if
[
$BACKUP_KEEP_DAYS
-eq
0
]
;
then
BACKUP_KEEP_DAYS
=
7
fi
BACKUP_DATE
=
$(
/bin/date +%Y%m%d-%H%M
)
# ----- checks
# . /usr/local/bin/inc_cronfunctions.sh
j_requireUser
"root"
h1
$(
date
)
IML BACKUP :: LOCALDUMP ::
$*
}
export
SERVICENAME
=
$1
# BACKUP_TARGETDIR=${BACKUP_BASEDIR}/${SERVICENAME}
# BACKUP_SCRIPT=$( get_service_script ${SERVICENAME} )
# ------------------------------------------------------------
# generate a base filename for backup dump based on on db name
# ... and added timestamp
# param string name of database schema
# --> see listBackupedDBs() and guessDB() - these function must be able to split this
function
get_outfile
(){
echo
$*
__
${
BACKUP_DATE
}
}
case
"
$mode
"
in
# ------------------------------------------------------------
check
)
DBD_DEBUG
=
1
for
PROFILENAME
in
$(
dbdetect.getConfigs
)
do
echo
"-----
$PROFILENAME
"
dbdetect.exists
"
${
PROFILENAME
}
"
echo
done
# . $BACKUP_SCRIPT $mode
;;
# get name of a service script
# param string name of a service
function
get_service_script
(){
local
_service
=
$1
local
_type
;
_type
=
$(
dbdetect.getType
"
$_service
"
)
ls
-1
${
BACKUP_PLUGINDIR
}
/
${
_type
}
.sh 2>/dev/null
}
# ------------------------------------------------------------
backup
)
if
[
"
$1
"
=
"ALL"
]
||
[
-z
"
$1
"
]
;
then
# get a list of existing database profiles
function
get_database_profiles
(){
for
config
in
$(
dbdetect.getConfigs
)
;
do
if
dbdetect.exists
"
$config
"
;
then
echo
"
$(
dbdetect.getProfile
$config
)
"
fi
done
}
profiles2run
=
$(
get_database_profiles
)
echo
AUTO: calling
local
backup scripts
for
all active profiles
echo
"
$profiles2run
"
|
nl
# ------------------------------------------------------------
# show directory infos with count of files and used space
# show used space and count of files and dirs
function
show_info_backup_target
(){
if
[
-d
"
${
BACKUP_TARGETDIR
}
"
]
;
then
h3
"INFO about backup target
${
BACKUP_TARGETDIR
}
"
echo
-n
"used space: "
du
-hs
"
${
BACKUP_TARGETDIR
}
"
echo
-n
"subdirs : "
find
"
${
BACKUP_TARGETDIR
}
"
-type
d |
wc
-l
echo
-n
"files : "
find
"
${
BACKUP_TARGETDIR
}
"
-type
f |
wc
-l
echo
-n
"free space: "
df
-h
"
${
BACKUP_TARGETDIR
}
"
|
tail
-1
|
awk
'{ print $4 }'
echo
else
profiles2run
=
$*
fi
}
# ----- GO
# PROFILENAME mysql_localhost_13306
# SERVICENAME mysql
#
for
PROFILENAME
in
$profiles2run
do
if
dbdetect.setProfile
"
${
PROFILENAME
}
"
;
then
h2
"START PROFILE [
${
PROFILENAME
}
]"
SERVICENAME
=
$(
dbdetect.getType
"
$PROFILENAME
"
)
BACKUP_PARAMS
=
$(
dbdetect.getParams
)
BACKUP_TARGETDIR
=
${
BACKUP_BASEDIR
}
/
${
PROFILENAME
}
ARCHIVE_DIR
=
${
ARCHIVE_BASEDIR
}
/
${
PROFILENAME
}
BACKUP_SCRIPT
=
$(
get_service_script
${
SERVICENAME
}
)
# ------ set env
# echo "BACKUP_PARAMS = $BACKUP_PARAMS"
# dbdetect.setenv
eval
$(
dbdetect.setenv
)
_j_runHooks
"200-before-db-service"
h3
"BACKUP [
${
PROFILENAME
}
] ->
${
SERVICENAME
}
"
.
$BACKUP_SCRIPT
$mode
test
$rc
-gt
0
&&
j_notify
"db
${
SERVICENAME
}
"
"
$BACKUP_SCRIPT
$mode
was finished with rc=
$rc
"
$rc
_j_runHooks
"230-after-db-service"
"
$rc
"
# ------ unset env
eval
$(
dbdetect.unssetenv
)
# ----- post jobs: cleanup
cleanup_backup_target
show_info_backup_target
# ----------------------------------------------------------------------
# FUNCTIONS 4 RESTORE
# ----------------------------------------------------------------------
# ------------------------------------------------------------
# restore: show profiles from that exist backups
# global string BACKUP_BASEDIR base directory of all backups
function
listBackupedServices
(){
(
find
"
${
BACKUP_BASEDIR
}
"
-mindepth
1
-maxdepth
1
-type
d
-exec
basename
{}
\;
test
-n
"
${
ARCHIVE_BASEDIR
}
"
&&
find
"
${
ARCHIVE_BASEDIR
}
"
-mindepth
1
-maxdepth
1
-type
d
-exec
basename
{}
\;
)
|
sort
-u
}
# ------------------------------------------------------------
# restore: show databases or dumps of a given database that can be restored
# global string BACKUP_BASEDIR base directory of all backups of selected dbprofile
# param string optional: DB-Name for file filter to select from existing dumps;
function
listBackupedDBs
(){
if
[
-d
"
${
BACKUP_TARGETDIR
}
"
]
;
then
if
[
-z
$1
]
;
then
# list all databases
find
"
${
BACKUP_TARGETDIR
}
"
-mindepth
1
-maxdepth
1
-type
f
-exec
basename
{}
\;
\
|
sed
"s#__[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]-[0-9][0-9].*##g"
\
|
sed
"s#
\.
.*##g"
\
|
sort
-ud
|
sed
"s#^
\.
/##g"
else
# list dumps of a database
ls
-ltr
${
BACKUP_TARGETDIR
}
/
${
1
}*
gz |
sed
"s,
${
BACKUP_TARGETDIR
}
/,,g"
fi
else
echo
"SKIP: profile '
$PROFILENAME
' "
# see why it is not active
DBD_DEBUG
=
1
;
dbdetect.setProfile
"
${
PROFILENAME
}
"
;
echo
;
DBD_DEBUG
=
0
color.echo error
"ERROR:
${
BACKUP_TARGETDIR
}
does not exist - here are no backups to restore."
echo
echo
"You can try to restore dumps:"
echo
"1) Restore dump files from a backup set"
echo
"
$(
dirname
$0
)
/restore.sh
$BACKUP_BASEDIR
"
echo
"2) Copy restored dumps into
$BACKUP_TARGETDIR
"
echo
"3) Start database restore again"
echo
"
$(
dirname
$0
)
/localdump.sh restore [profile]"
echo
exit
1
fi
}
# just to have it in the output
dbdetect.validate
done
;;
# ------------------------------------------------------------
restore
)
h1
"RESTORE DATABASE"
if
!
listBackupedServices |
grep
-q
.
;
then
color.echo error
"ERROR: No database dump was found in [
${
BACKUP_BASEDIR
}
] nor [
${
ARCHIVE_BASEDIR
}
]."
exit
1
fi
if
[
-z
$1
]
||
[
!
-f
"
$1
"
]
;
then
parService
=
"
$1
"
# ----- interactive selections
h2
"Select profile that has a dump"
if
[
-z
"
${
parService
}
"
]
;
then
if
[
"
$(
listBackupedServices |
wc
-l
)
"
-eq
1
]
;
then
parService
=
"
$(
listBackupedServices
)
"
echo
"Selecting the only existing profile:
$parService
"
fi
fi
if
[
-z
"
${
parService
}
"
]
;
then
listBackupedServices
color.print input
"Restore for profile name >"
read
-r
parService
test
-z
"
$parService
"
&&
exit
1
# guess name of the database file
# param string filename of db dump; can be full path or not
function
guessDB
(){
dumpfile
=
$1
# the metafile is written in sqlite backup to store full path
metafile
=
${
BACKUP_TARGETDIR
}
/
${
dumpfile
}
.meta
if
[
-f
$metafile
]
;
then
grep
"^/"
"
$metafile
"
||
grep
"^ File: "
"
$metafile
"
|
cut
-c
9-
else
echo
"Taken from command line:
$parService
"
sBasename
=
$(
basename
$1
)
sDb
=
$(
echo
${
sBasename
}
|
sed
"s#__[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]-[0-9][0-9].*##g"
|
sed
"s#
\.
couchdbdump
\.
gz
$##
g"
)
# ^ ^
# timestamp in backup file __/ for couchdb2 restore from archive __/
if
[
-z
$sDb
]
;
then
color.echo error
"ERROR: db name was not detected from file
$1
"
exit
1
fi
echo
$sDb
fi
}
# ----- check if profile exists
if
!
dbdetect.setProfile
"
${
parService
}
"
;
then
color.echo error
"ERROR: profile [
${
parService
}
] is not known here (or database service is stopped)."
echo
echo
"Existing database profiles:"
get_database_profiles |
nl
echo
# ------------------------------------------------------------
# show a selection + a prompt and read the input
# - If the selection is just 1 line it will be returned
# - If the user presses just return the script will exit
# param string selection of items to select from
# param string prompt to show
function
showSelectAndInput
(){
local
_selection
=
"
$1
"
local
_prompt
=
"
$2
"
local
_lines
typeset
-i
_lines
;
_lines
=
$(
grep
-c
"."
<<<
"
$_selection
"
)
if
[
$_lines
-eq
"1"
]
;
then
echo
"INFO: No interaction on a single choice. Using '
$_selection
'"
LASTINPUT
=
"
$_selection
"
return
0
else
echo
"
$_selection
"
color.print input
"
${
_prompt
}
>"
read
-r
LASTINPUT
if
[
-z
"
$LASTINPUT
"
]
;
then
echo
"No input given. Aborting."
exit
1
fi
fi
}
# ----- check if dump exists in archive and in backup
if
[
-d
"
${
BACKUP_BASEDIR
}
/
${
parService
}
"
]
&&
[
-d
"
${
ARCHIVE_BASEDIR
}
/
${
parService
}
"
]
;
then
echo
echo
"Backup
${
BACKUP_BASEDIR
}
"
echo
"Archive
${
ARCHIVE_BASEDIR
}
"
color.print input
"Select a source directory >"
read
-r
backupsource
test
-z
"
$backupsource
"
&&
exit
1
BACKUP_BASEDIR
=
"
${
backupsource
}
"
else
# just one test needed because BACKUP_BASEDIR is BACKUP_BASEDIR
test
-d
"
${
ARCHIVE_BASEDIR
}
/
${
parService
}
"
&&
BACKUP_BASEDIR
=
"
${
ARCHIVE_BASEDIR
}
"
# ------------------------------------------------------------
# read .meta file (that contains output of stats) and restore last owner and file permissions
# param string filename of db dump
# param string restored database file
function
restorePermissions
(){
local
sMyMeta
=
"
${
1
}
.meta"
local
sTargetfile
=
"
$2
"
if
[
-f
"
${
sMyMeta
}
"
]
;
then
# Access: (0674/-rw-rwxr--) Uid: ( 1000/ axel) Gid: ( 1000/ axel)
# ^ ^ ^
# _sPerm _sUser _sGroup
local
_sPerm
=
$(
grep
"^Access: ("
"
${
sMyMeta
}
"
|
cut
-f
2
-d
'('
|
cut
-f
1
-d
'/'
)
if
[
-n
"
$_sPerm
"
]
;
then
local
_sUser
=
$(
grep
"^Access: ("
"
${
sMyMeta
}
"
|
cut
-f
3
-d
'('
|
cut
-f
1
-d
'/'
|
tr
-d
' '
)
local
_sGroup
=
$(
grep
"^Access: ("
"
${
sMyMeta
}
"
|
cut
-f
4
-d
'('
|
cut
-f
1
-d
'/'
|
tr
-d
' '
)
echo
-n
"Restoring file owner
$_sUser
:
$_sGroup
and permissions
$_sPerm
... "
chown
"
$_sUser
:
$_sGroup
"
"
${
sTargetfile
}
"
&&
chmod
"
$_sPerm
"
"
${
sTargetfile
}
"
fetchrc
fi
fi
}
# ----- check if target dir with profile exists
if
[
!
-d
"
${
BACKUP_BASEDIR
}
/
${
parService
}
"
]
;
then
color.echo error
"ERROR: Directory does not exist '
${
BACKUP_BASEDIR
}
/
${
parService
}
'."
exit
1
fi
# ------------------------------------------------------------
# show help
# ------------------------------------------------------------
function
showhelp
(){
local
_self
_self
=
$(
basename
"
$0
"
)
cat
<<
EOH
LOCALDUMP detects existing local databases and dumps them locally.
It is included in the backup.sh to dump all before a file backup will store
them. It can be started seperately for manual database backups or for restore.
SYNTAX:
$_self
[OPTIONS] <operation> <profile [more_profiles]>
OPTIONS:
-h|--help show this help
PARAMETERS:"
operation - one of check|backup|restore; optional parameter
backup dump all databases/ schemes of a given service
check show info only if the service is available
restore import a dump into same or new database
Without a filename it starts an interactive mode
profile - name of database profiles
You get a list of all available services without parameter
Use ALL for bulk command
file - filename of db dump to restore to origin database scheme
EXAMPLES:
$_self
backup
$_self
backup ALL
Backup all databases of all found services
$_self
backup mysql
Backup all Mysql databases.
$_self
restore
Start interactive restore of a database of any service.
$_self
restore sqlite
Start interactive restore of an sqlite database.
$_self
restore <file-to-restore> [<database-name>]
Restore a given dump file to the origin database scheme or
to a new/ other database with the given name.
EOH
}
BACKUP_TARGETDIR
=
"
${
BACKUP_BASEDIR
}
/
${
parService
}
"
h2
"Select database"
listBackupedDBs
color.print input
"name of db to restore >"
read
-r
fileprefix
test
-z
"
$fileprefix
"
&&
exit
1
echo
# ----------------------------------------------------------------------
# INIT
# ----------------------------------------------------------------------
h2
"Select a specific dump for that database"
listBackupedDBs
$fileprefix
color.print input
"backupset to import >"
read
-r
dbfile
test
-z
"
$dbfile
"
&&
exit
1
while
[[
"$#"
-gt
0
]]
;
do case
$1
in
-h
|
--help
)
showhelp
;
exit
0
;;
*
)
if
grep
"^-"
<<<
"
$1
"
>
/dev/null
;
then
echo
;
echo
"ERROR: Unknown parameter:
$1
"
;
echo
;
showhelp
;
exit
2
fi
break
;
;;
esac
;
done
mode
=
""
case
"
$1
"
in
backup|check|restore|shell
)
mode
=
$1
shift
1
;;
esac
if
[
-z
"
$mode
"
]
;
then
color.echo error
"ERROR: missing parameter for operation."
echo
sTargetDb
=
$(
guessDB
${
dbfile
}
)
color.print input
"New database name [
$sTargetDb
] >"
read
-r
sTargetDb
if
[
-z
$sTargetDb
]
;
then
sTargetDb
=
$(
guessDB
${
dbfile
}
)
fi
showhelp
echo
echo
"Hint: On this machine working profiles:"
get_database_profiles |
nl
echo
exit
1
fi
sDumpfile
=
"
${
BACKUP_TARGETDIR
}
/
${
dbfile
}
"
else
sDumpfile
=
$1
sTargetDb
=
$2
fi
shift
2
# ----- init vars
BACKUP_BASEDIR
=
$(
_j_getvar
"
${
JOBFILE
}
"
"dir-localdumps"
)
# ----- start restore
# check
if
[
-z
"
$BACKUP_BASEDIR
"
]
;
then
color.echo error
"ERROR: missing config for backup target."
echo
There must be an entry dir-localdumps
in
${
JOBFILE
}
exit
1
fi
ARCHIVE_BASEDIR
=
$(
_j_getvar
"
${
JOBFILE
}
"
dir-dbarchive
)
if
[
!
-f
"
${
sDumpfile
}
"
]
;
then
color.echo error
"ERROR: [
${
sDumpfile
}
] is not a file"
rc
=
$rc
+1
else
BACKUP_PLUGINDIR
=
$(
dirname
$0
)
/plugins/localdump
DBD_BASEDIR
=
$BACKUP_PLUGINDIR
/profiles
PROFILENAME
=
"
${
sDumpfile
//
${
BACKUP_BASEDIR
}
/
}
"
PROFILENAME
=
"
$(
echo
$PROFILENAME
|
sed
"s,^/*,,"
|
cut
-f
1
-d
'/'
)
"
BACKUP_KEEP_DAYS
=
$(
_j_getvar
${
JOBFILE
}
"keep-days"
)
if
dbdetect.setProfile
"
${
PROFILENAME
}
"
;
then
if
[
$BACKUP_KEEP_DAYS
-eq
0
]
;
then
BACKUP_KEEP_DAYS
=
7
fi
BACKUP_DATE
=
$(
/bin/date +%Y%m%d-%H%M
)
# ----- checks
SERVICENAME
=
$(
dbdetect.getType
"
$PROFILENAME
"
)
# . /usr/local/bin/inc_cronfunctions.sh
j_requireUser
"root"
BACKUP_TARGETDIR
=
${
BACKUP_BASEDIR
}
/
${
PROFILENAME
}
BACKUP_SCRIPT
=
$(
get_service_script
${
SERVICENAME
}
)
ARCHIVE_DIR
=
${
ARCHIVE_BASEDIR
}
/
${
PROFILENAME
}
h1
$(
date
)
IML BACKUP :: LOCALDUMP ::
$*
BACKUP_PARAMS
=
$(
dbdetect.getParams
)
eval
$(
dbdetect.setenv
)
.
$BACKUP_SCRIPT
$mode
"
${
sDumpfile
}
"
"
${
sTargetDb
}
"
if
[
$?
-ne
0
-o
$rc
-ne
0
]
;
then
color.echo error
"ERROR:
$mode
failed. See ouput above. :-/"
export
SERVICENAME
=
$1
# BACKUP_TARGETDIR=${BACKUP_BASEDIR}/${SERVICENAME}
# BACKUP_SCRIPT=$( get_service_script ${SERVICENAME} )
case
"
$mode
"
in
# ------------------------------------------------------------
check
)
DBD_DEBUG
=
1
for
PROFILENAME
in
$(
dbdetect.getConfigs
)
do
echo
"-----
$PROFILENAME
"
dbdetect.exists
"
${
PROFILENAME
}
"
echo
done
# . $BACKUP_SCRIPT $mode
;;
# ------------------------------------------------------------
backup
)
if
[
"
$1
"
=
"ALL"
]
||
[
-z
"
$1
"
]
;
then
profiles2run
=
$(
get_database_profiles
)
echo
AUTO: calling
local
backup scripts
for
all active profiles
echo
"
$profiles2run
"
|
nl
echo
else
profiles2run
=
$*
fi
# ----- GO
# PROFILENAME mysql_localhost_13306
# SERVICENAME mysql
#
for
PROFILENAME
in
$profiles2run
do
if
dbdetect.setProfile
"
${
PROFILENAME
}
"
;
then
h2
"START PROFILE [
${
PROFILENAME
}
]"
SERVICENAME
=
$(
dbdetect.getType
"
$PROFILENAME
"
)
BACKUP_PARAMS
=
$(
dbdetect.getParams
)
BACKUP_TARGETDIR
=
${
BACKUP_BASEDIR
}
/
${
PROFILENAME
}
ARCHIVE_DIR
=
${
ARCHIVE_BASEDIR
}
/
${
PROFILENAME
}
BACKUP_SCRIPT
=
$(
get_service_script
${
SERVICENAME
}
)
# ------ set env
# echo "BACKUP_PARAMS = $BACKUP_PARAMS"
# dbdetect.setenv
eval
$(
dbdetect.setenv
)
_j_runHooks
"200-before-db-service"
h3
"BACKUP [
${
PROFILENAME
}
] ->
${
SERVICENAME
}
"
.
$BACKUP_SCRIPT
$mode
test
$rc
-gt
0
&&
j_notify
"db
${
SERVICENAME
}
"
"
$BACKUP_SCRIPT
$mode
was finished with rc=
$rc
"
$rc
_j_runHooks
"230-after-db-service"
"
$rc
"
# ------ unset env
eval
$(
dbdetect.unssetenv
)
# ----- post jobs: cleanup
cleanup_backup_target
show_info_backup_target
else
color.echo ok
"OK,
$mode
was successful."
echo
"SKIP: profile '
$PROFILENAME
' "
# see why it is not active
DBD_DEBUG
=
1
;
dbdetect.setProfile
"
${
PROFILENAME
}
"
;
echo
;
DBD_DEBUG
=
0
fi
# just to have it in the output
dbdetect.validate
done
;;
# ------------------------------------------------------------
restore
)
h1
"RESTORE DATABASE"
if
!
listBackupedServices |
grep
-q
.
;
then
color.echo error
"ERROR: No database dump was found in [
${
BACKUP_BASEDIR
}
] nor [
${
ARCHIVE_BASEDIR
}
]."
exit
1
fi
if
[
-z
$1
]
||
[
!
-f
"
$1
"
]
;
then
parService
=
"
$1
"
# ----- interactive selections
h2
"Select profile that has a dump"
if
[
-z
"
${
parService
}
"
]
;
then
showSelectAndInput
"
$(
listBackupedServices
)
"
"Restore for profile name"
parService
=
"
$LASTINPUT
"
else
echo
"Taken from command line:
$parService
"
fi
# ----- check if profile exists
if
!
dbdetect.setProfile
"
${
parService
}
"
;
then
color.echo error
"ERROR: profile [
${
parService
}
] is not known here (or database service is stopped)."
echo
exit
1
fi
# ----- check if dump exists in archive and in backup
if
[
-d
"
${
BACKUP_BASEDIR
}
/
${
parService
}
"
]
&&
[
-d
"
${
ARCHIVE_BASEDIR
}
/
${
parService
}
"
]
;
then
echo
showSelectAndInput
"
$(
echo
"
${
BACKUP_BASEDIR
}
"
;
echo
"
${
ARCHIVE_BASEDIR
}
"
)
"
"Select a source directory"
BACKUP_BASEDIR
=
"
$LASTINPUT
"
else
# just one test needed because BACKUP_BASEDIR is BACKUP_BASEDIR
test
-d
"
${
ARCHIVE_BASEDIR
}
/
${
parService
}
"
&&
BACKUP_BASEDIR
=
"
${
ARCHIVE_BASEDIR
}
"
fi
# ----- check if target dir with profile exists
if
[
!
-d
"
${
BACKUP_BASEDIR
}
/
${
parService
}
"
]
;
then
color.echo error
"ERROR: Directory does not exist '
${
BACKUP_BASEDIR
}
/
${
parService
}
'."
exit
1
fi
BACKUP_TARGETDIR
=
"
${
BACKUP_BASEDIR
}
/
${
parService
}
"
h2
"Select a database schema"
showSelectAndInput
"
$(
listBackupedDBs
)
"
"Name of database to restore"
fileprefix
=
"
$LASTINPUT
"
echo
h2
"Select a specific dump for that database"
showSelectAndInput
"
$(
listBackupedDBs
$fileprefix
)
"
"Backupset to import"
dbfile
=
"
$LASTINPUT
"
echo
sTargetDb
=
$(
guessDB
${
dbfile
}
)
color.print input
"New database name [
$sTargetDb
] >"
read
-r
sTargetDb
if
[
-z
$sTargetDb
]
;
then
sTargetDb
=
$(
guessDB
${
dbfile
}
)
fi
echo
sDumpfile
=
"
${
BACKUP_TARGETDIR
}
/
${
dbfile
}
"
else
sDumpfile
=
$1
sTargetDb
=
$2
fi
shift
2
# ----- start restore
if
[
!
-f
"
${
sDumpfile
}
"
]
;
then
color.echo error
"ERROR: [
${
sDumpfile
}
] is not a file"
rc
=
$rc
+1
else
PROFILENAME
=
"
${
sDumpfile
//
${
BACKUP_BASEDIR
}
/
}
"
PROFILENAME
=
"
$(
echo
$PROFILENAME
|
sed
"s,^/*,,"
|
cut
-f
1
-d
'/'
)
"
if
dbdetect.setProfile
"
${
PROFILENAME
}
"
;
then
SERVICENAME
=
$(
dbdetect.getType
"
$PROFILENAME
"
)
# ------ unset env
eval
$(
dbdetect.unssetenv
)
else
color.echo error
"ERROR: Profile
$PROFILENAME
was detected but its database service is not available."
fi
fi
;;
# ------------------------------------------------------------
# shell)
# export BACKUP_TARGETDIR
# . $BACKUP_SCRIPT
# (
# mycmd=
# echo
# echo "Starting interactive shell..."
# echo
# echo "STATUS: STILL ALPHA as long existing db plugins are not rewritten."
# echo
# echo "INFO: Try ${SERVICENAME}.help to see database specific commands."
# echo "INFO: Type exit and return to leave the shell."
# echo
# while [ ! "$mycmd" = "exit" ]; do
# echo -n "[${SERVICENAME}]"
# color.print input " $( pwd )"
# echo -n " % "
# read -r mycmd
# if [ ! "$mycmd" = "exit" ];then
# color.preset cmd
# eval $mycmd
# color.reset
# fi
# done
# )
# ;;
BACKUP_TARGETDIR
=
${
BACKUP_BASEDIR
}
/
${
PROFILENAME
}
BACKUP_SCRIPT
=
$(
get_service_script
${
SERVICENAME
}
)
ARCHIVE_DIR
=
${
ARCHIVE_BASEDIR
}
/
${
PROFILENAME
}
BACKUP_PARAMS
=
$(
dbdetect.getParams
)
eval
$(
dbdetect.setenv
)
.
$BACKUP_SCRIPT
$mode
"
${
sDumpfile
}
"
"
${
sTargetDb
}
"
if
[
$?
-ne
0
-o
$rc
-ne
0
]
;
then
color.echo error
"ERROR:
$mode
failed. See ouput above. :-/"
else
color.echo ok
"OK,
$mode
was successful."
fi
# ------ unset env
eval
$(
dbdetect.unssetenv
)
else
color.echo error
"ERROR: Profile
$PROFILENAME
was detected but its database service is not available."
fi
fi
;;
# ------------------------------------------------------------
# shell)
# export BACKUP_TARGETDIR
# . $BACKUP_SCRIPT
# (
# mycmd=
# echo
# echo "Starting interactive shell..."
# echo
# echo "STATUS: STILL ALPHA as long existing db plugins are not rewritten."
# echo
# echo "INFO: Try ${SERVICENAME}.help to see database specific commands."
# echo "INFO: Type exit and return to leave the shell."
# echo
# while [ ! "$mycmd" = "exit" ]; do
# echo -n "[${SERVICENAME}]"
# color.print input " $( pwd )"
# echo -n " % "
# read -r mycmd
# if [ ! "$mycmd" = "exit" ];then
# color.preset cmd
# eval $mycmd
# color.reset
# fi
# done
# )
# ;;
# ----- start restore
*
)
color.echo error
"ERROR: unknown command [
$mode
]"
;;
esac
echo
_______________________________________________________________________________
echo
STATUS
$0
exit
with final returncode
rc
=
$rc
exit
$rc
# ----- start restore
*
)
color.echo error
"ERROR: unknown command [
$mode
]"
;;
esac
echo
_______________________________________________________________________________
echo
STATUS
$0
exit
with final returncode
rc
=
$rc
exit
$rc
# ----------------------------------------------------------------------
\ No newline at end of file
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment