Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
slapos
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Léo-Paul Géneau
slapos
Commits
9c59c5fc
Commit
9c59c5fc
authored
Nov 05, 2021
by
Xavier Thompson
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
software/theia: Fix resilient signature checking
parent
5763522b
Changes
4
Show whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
203 additions
and
116 deletions
+203
-116
software/theia/buildout.hash.cfg
software/theia/buildout.hash.cfg
+3
-3
software/theia/theia_common.py
software/theia/theia_common.py
+43
-30
software/theia/theia_export.py
software/theia/theia_export.py
+67
-36
software/theia/theia_import.py
software/theia/theia_import.py
+90
-47
No files found.
software/theia/buildout.hash.cfg
View file @
9c59c5fc
...
@@ -35,15 +35,15 @@ md5sum = d78a9f885bdebf6720197209e0c21aa0
...
@@ -35,15 +35,15 @@ md5sum = d78a9f885bdebf6720197209e0c21aa0
[theia-common]
[theia-common]
_update_hash_filename_ = theia_common.py
_update_hash_filename_ = theia_common.py
md5sum =
38eba0fb605953677b5a2a2e686a66a2
md5sum =
6a25c6a7f1beb27232a3c9acd8a76500
[theia-export]
[theia-export]
_update_hash_filename_ = theia_export.py
_update_hash_filename_ = theia_export.py
md5sum =
d338b2d3ba1dcd7a919c0baf51dd11da
md5sum =
e2f6c483cce09f87ab1e63ae8be0daf4
[theia-import]
[theia-import]
_update_hash_filename_ = theia_import.py
_update_hash_filename_ = theia_import.py
md5sum =
3580f1eec1099bebd550ba1eacd9c116
md5sum =
5dea99b0106cccba65f8ae90d110e111
[yarn.lock]
[yarn.lock]
_update_hash_filename_ = yarn.lock
_update_hash_filename_ = yarn.lock
...
...
software/theia/theia_common.py
View file @
9c59c5fc
...
@@ -81,7 +81,6 @@ def remove(path):
...
@@ -81,7 +81,6 @@ def remove(path):
def
parse_installed
(
partition
):
def
parse_installed
(
partition
):
paths
=
[]
paths
=
[]
custom_script
=
os
.
path
.
join
(
partition
,
'srv'
,
'.backup_identity_script'
)
for
cfg
in
glob
.
glob
(
os
.
path
.
join
(
partition
,
'.installed*.cfg'
)):
for
cfg
in
glob
.
glob
(
os
.
path
.
join
(
partition
,
'.installed*.cfg'
)):
try
:
try
:
with
open
(
cfg
)
as
f
:
with
open
(
cfg
)
as
f
:
...
@@ -93,7 +92,7 @@ def parse_installed(partition):
...
@@ -93,7 +92,7 @@ def parse_installed(partition):
for
section
in
six
.
itervalues
(
installed_cfg
):
for
section
in
six
.
itervalues
(
installed_cfg
):
for
p
in
section
.
get
(
'__buildout_installed__'
,
''
).
splitlines
():
for
p
in
section
.
get
(
'__buildout_installed__'
,
''
).
splitlines
():
p
=
p
.
strip
()
p
=
p
.
strip
()
if
p
and
p
!=
custom_script
:
if
p
:
paths
.
append
(
p
)
paths
.
append
(
p
)
return
paths
return
paths
...
@@ -108,31 +107,44 @@ def sha256sum(file_path, chunk_size=1024 * 1024):
...
@@ -108,31 +107,44 @@ def sha256sum(file_path, chunk_size=1024 * 1024):
return
sha256
.
hexdigest
()
return
sha256
.
hexdigest
()
def
hashwalk
(
backup_dir
,
mirror_partitions
):
def
fast_hashwalk
(
root_dir
):
scripts
=
{}
for
dirpath
,
dirnames
,
filenames
in
os
.
walk
(
root_dir
):
for
p
in
mirror_partitions
:
script_path
=
os
.
path
.
join
(
p
,
'srv'
,
'.backup_identity_script'
)
if
os
.
path
.
exists
(
script_path
):
scripts
[
os
.
path
.
abspath
(
p
)]
=
script_path
for
dirpath
,
dirnames
,
filenames
in
os
.
walk
(
backup_dir
):
filenames
.
sort
()
for
f
in
filenames
:
for
f
in
filenames
:
filepath
=
os
.
path
.
join
(
dirpath
,
f
)
filepath
=
os
.
path
.
join
(
dirpath
,
f
)
if
os
.
path
.
isfile
(
filepath
):
if
os
.
path
.
isfile
(
filepath
):
displaypath
=
os
.
path
.
relpath
(
filepath
,
start
=
backup
_dir
)
displaypath
=
os
.
path
.
relpath
(
filepath
,
start
=
root
_dir
)
yield
'%s %s'
%
(
sha256sum
(
filepath
),
displaypath
)
yield
'%s %s'
%
(
sha256sum
(
filepath
),
displaypath
)
remaining_dirnames
=
[]
for
subdir
in
dirnames
:
subdirpath
=
os
.
path
.
abspath
(
os
.
path
.
join
(
dirpath
,
subdir
))
def
exclude_hashwalk
(
root_dir
,
instance_dir
):
custom_hashscript
=
scripts
.
get
(
subdirpath
)
root_dir
=
os
.
path
.
abspath
(
root_dir
)
if
custom_hashscript
:
instance_dir
=
os
.
path
.
abspath
(
instance_dir
)
print
(
'Using custom signature script %s'
%
custom_hashscript
)
for
dirpath
,
dirnames
,
filenames
in
os
.
walk
(
root_dir
):
for
s
in
hashcustom
(
subdirpath
,
backup_dir
,
custom_hashscript
):
for
f
in
filenames
:
yield
s
filepath
=
os
.
path
.
join
(
dirpath
,
f
)
else
:
if
os
.
path
.
isfile
(
filepath
):
remaining_dirnames
.
append
(
subdir
)
displaypath
=
os
.
path
.
relpath
(
filepath
,
start
=
root_dir
)
remaining_dirnames
.
sort
()
yield
'%s %s'
%
(
sha256sum
(
filepath
),
displaypath
)
dirnames
[:]
=
remaining_dirnames
if
dirpath
==
instance_dir
:
remaining_dirs
=
[]
for
d
in
dirnames
:
if
not
d
.
startswith
(
'slappart'
):
remaining_dirs
.
append
(
d
)
dirnames
[:]
=
remaining_dirs
def
hashwalk
(
root_dir
,
instance_dir
=
None
):
if
instance_dir
and
not
os
.
path
.
relpath
(
instance_dir
,
start
=
root_dir
).
startswith
(
os
.
pardir
):
return
exclude_hashwalk
(
root_dir
,
instance_dir
)
return
fast_hashwalk
(
root_dir
)
def
hashscript
(
partition
):
script
=
os
.
path
.
join
(
partition
,
'srv'
,
'.backup_identity_script'
)
if
os
.
path
.
exists
(
script
):
return
script
return
None
@
contextlib
.
contextmanager
@
contextlib
.
contextmanager
...
@@ -145,10 +157,11 @@ def cwd(path):
...
@@ -145,10 +157,11 @@ def cwd(path):
os
.
chdir
(
old_path
)
os
.
chdir
(
old_path
)
def
hashcustom
(
mirrordir
,
backup_dir
,
custom_hash
script
):
def
hashcustom
(
partition
,
script
):
workingdir
=
os
.
path
.
join
(
mirrordir
,
os
.
pardir
,
os
.
pardir
,
os
.
pardir
)
workingdir
=
os
.
path
.
join
(
partition
,
os
.
pardir
,
os
.
pardir
,
os
.
pardir
)
with
cwd
(
os
.
path
.
abspath
(
workingdir
)):
with
cwd
(
os
.
path
.
abspath
(
workingdir
)):
for
dirpath
,
_
,
filenames
in
os
.
walk
(
mirrordir
):
for
dirpath
,
dirnames
,
filenames
in
os
.
walk
(
partition
):
dirnames
.
sort
()
filepaths
=
[]
filepaths
=
[]
for
f
in
filenames
:
for
f
in
filenames
:
path
=
os
.
path
.
join
(
dirpath
,
f
)
path
=
os
.
path
.
join
(
dirpath
,
f
)
...
@@ -157,16 +170,16 @@ def hashcustom(mirrordir, backup_dir, custom_hashscript):
...
@@ -157,16 +170,16 @@ def hashcustom(mirrordir, backup_dir, custom_hashscript):
if
not
filepaths
:
if
not
filepaths
:
continue
continue
hashprocess
=
sp
.
Popen
(
hashprocess
=
sp
.
Popen
(
custom_hash
script
,
stdin
=
sp
.
PIPE
,
stdout
=
sp
.
PIPE
,
stderr
=
sp
.
PIPE
)
script
,
stdin
=
sp
.
PIPE
,
stdout
=
sp
.
PIPE
,
stderr
=
sp
.
PIPE
)
out
,
err
=
hashprocess
.
communicate
(
str2bytes
(
'
\
0
'
.
join
(
filepaths
)))
out
,
err
=
hashprocess
.
communicate
(
str2bytes
(
'
\
0
'
.
join
(
filepaths
)))
if
hashprocess
.
returncode
!=
0
:
if
hashprocess
.
returncode
!=
0
:
template
=
"Custom signature script %s failed on inputs:
\
n
%s"
template
=
"Custom signature script %s failed on inputs:
\
n
%s"
msg
=
template
%
(
custom_hash
script
,
'
\
n
'
.
join
(
filepaths
))
msg
=
template
%
(
script
,
'
\
n
'
.
join
(
filepaths
))
msg
+=
"
\
n
with stdout:
\
n
%s"
%
bytes2str
(
out
)
msg
+=
"
\
n
with stdout:
\
n
%s"
%
bytes2str
(
out
)
msg
+=
"
\
n
and stderr:
\
n
%s"
%
bytes2str
(
err
)
msg
+=
"
\
n
and stderr:
\
n
%s"
%
bytes2str
(
err
)
raise
Exception
(
msg
)
raise
Exception
(
msg
)
signatures
=
bytes2str
(
out
).
strip
(
'
\
n
'
).
split
(
'
\
n
'
)
signatures
=
bytes2str
(
out
).
strip
(
'
\
n
'
).
split
(
'
\
n
'
)
signatures
.
sort
()
signatures
.
sort
()
displaypath
=
os
.
path
.
relpath
(
dirpath
,
start
=
backup_dir
)
displaypath
=
os
.
path
.
relpath
(
dirpath
,
start
=
partition
)
for
s
in
signatures
:
for
s
in
signatures
:
yield
'%s %s
/ (custom)
'
%
(
s
,
displaypath
)
yield
'%s %s'
%
(
s
,
displaypath
)
software/theia/theia_export.py
View file @
9c59c5fc
...
@@ -55,49 +55,74 @@ class TheiaExport(object):
...
@@ -55,49 +55,74 @@ class TheiaExport(object):
self
.
copytree_partitions_args
=
{}
self
.
copytree_partitions_args
=
{}
self
.
logs
=
[]
self
.
logs
=
[]
def
mirrorpath
(
self
,
src
):
def
mirror
_
path
(
self
,
src
):
return
os
.
path
.
abspath
(
os
.
path
.
join
(
return
os
.
path
.
abspath
(
os
.
path
.
join
(
self
.
backup_dir
,
os
.
path
.
relpath
(
src
,
start
=
self
.
root_dir
)))
self
.
backup_dir
,
os
.
path
.
relpath
(
src
,
start
=
self
.
root_dir
)))
def
backuptree
(
self
,
src
,
exclude
=
(),
extrargs
=
(),
verbosity
=
'-v'
):
def
backup_tree
(
self
,
src
):
dst
=
self
.
mirrorpath
(
src
)
return
copytree
(
self
.
rsync_bin
,
src
,
self
.
mirror_path
(
src
))
return
copytree
(
self
.
rsync_bin
,
src
,
dst
,
exclude
,
extrargs
,
verbosity
)
def
backupfile
(
self
,
src
):
def
backup_file
(
self
,
src
):
dst
=
self
.
mirrorpath
(
src
)
return
copyfile
(
src
,
self
.
mirror_path
(
src
))
return
copyfile
(
src
,
dst
)
def
backupdb
(
self
):
def
backup
_
db
(
self
):
copydb
(
self
.
sqlite3_bin
,
self
.
proxy_db
,
self
.
mirrorpath
(
self
.
proxy_db
))
copydb
(
self
.
sqlite3_bin
,
self
.
proxy_db
,
self
.
mirror
_
path
(
self
.
proxy_db
))
def
backuppartition
(
self
,
partition
):
def
backup
_
partition
(
self
,
partition
):
installed
=
parse_installed
(
partition
)
installed
=
parse_installed
(
partition
)
rules
=
os
.
path
.
join
(
partition
,
'srv'
,
'exporter.exclude'
)
rules
=
os
.
path
.
join
(
partition
,
'srv'
,
'exporter.exclude'
)
extrargs
=
(
'--filter=.-/ '
+
rules
,)
if
os
.
path
.
exists
(
rules
)
else
()
extrargs
=
(
'--filter=.-/ '
+
rules
,)
if
os
.
path
.
exists
(
rules
)
else
()
self
.
backuptree
(
partition
,
exclude
=
installed
,
extrargs
=
extrargs
)
dst
=
self
.
mirror_path
(
partition
)
self
.
copytree_partitions_args
[
partition
]
=
(
installed
,
extrargs
)
copytree
(
self
.
rsync_bin
,
partition
,
dst
,
installed
,
extrargs
)
self
.
copytree_partitions_args
[
partition
]
=
(
dst
,
installed
,
extrargs
)
def
sign
(
self
,
signaturefile
):
def
sign
(
self
,
signaturefile
,
signatures
):
remove
(
signaturefile
)
remove
(
signaturefile
)
pardir
=
os
.
path
.
abspath
(
os
.
path
.
join
(
self
.
backup_dir
,
os
.
pardir
))
pardir
=
os
.
path
.
abspath
(
os
.
path
.
join
(
self
.
backup_dir
,
os
.
pardir
))
tmpfile
=
os
.
path
.
join
(
pardir
,
'backup.signature.tmp'
)
tmpfile
=
os
.
path
.
join
(
pardir
,
os
.
path
.
basename
(
signaturefile
)
+
'.tmp'
)
mirror_partitions
=
[
self
.
mirrorpath
(
p
)
for
p
in
self
.
partition_dirs
]
with
open
(
tmpfile
,
'w'
)
as
f
:
with
open
(
tmpfile
,
'w'
)
as
f
:
for
s
in
hashwalk
(
self
.
backup_dir
,
mirror_partitions
)
:
for
s
in
signatures
:
f
.
write
(
s
+
'
\
n
'
)
f
.
write
(
s
+
'
\
n
'
)
os
.
rename
(
tmpfile
,
signaturefile
)
os
.
rename
(
tmpfile
,
signaturefile
)
def
checkpartition
(
self
,
partition
,
pattern
=
'/srv/backup/'
):
def
sign_root
(
self
):
installed
,
extrargs
=
self
.
copytree_partitions_args
[
partition
]
signaturefile
=
os
.
path
.
join
(
self
.
backup_dir
,
'backup.signature'
)
output
=
self
.
backuptree
(
signatures
=
hashwalk
(
self
.
backup_dir
,
self
.
mirror_path
(
self
.
instance_dir
))
self
.
sign
(
signaturefile
,
signatures
)
def
sign_partition
(
self
,
partition
):
dst
=
self
.
mirror_path
(
partition
)
filename
=
os
.
path
.
basename
(
partition
)
+
'.backup.signature'
signaturefile
=
os
.
path
.
join
(
self
.
backup_dir
,
filename
)
script
=
hashscript
(
partition
)
if
script
:
signaturefile
+=
'.custom'
self
.
sign
(
signaturefile
,
hashcustom
(
dst
,
script
))
else
:
self
.
sign
(
signaturefile
,
hashwalk
(
dst
))
def
remove_signatures
(
self
):
pattern
=
os
.
path
.
join
(
self
.
backup_dir
,
'*backup.signature*'
)
signature_files
=
glob
.
glob
(
pattern
)
for
f
in
signature_files
:
try
:
os
.
remove
(
f
)
except
OSError
:
pass
def
check_partition
(
self
,
partition
,
pattern
=
'/srv/backup/'
):
dst
,
installed
,
extrargs
=
self
.
copytree_partitions_args
[
partition
]
output
=
copytree
(
self
.
rsync_bin
,
partition
,
partition
,
dst
,
exclude
=
installed
,
exclude
=
installed
,
extrargs
=
extrargs
+
(
'--dry-run'
,
'--update'
),
extrargs
=
extrargs
+
(
'--dry-run'
,
'--update'
),
verbosity
=
'--out-format=%n'
,
verbosity
=
'--out-format=%n'
,
)
)
return
[
path
for
path
in
output
.
splitlines
()
if
pattern
in
path
]
return
[
path
for
path
in
output
.
splitlines
()
if
pattern
in
path
]
def
log
info
(
self
,
msg
):
def
log
(
self
,
msg
):
print
(
msg
)
print
(
msg
)
self
.
logs
.
append
(
msg
)
self
.
logs
.
append
(
msg
)
...
@@ -126,36 +151,42 @@ class TheiaExport(object):
...
@@ -126,36 +151,42 @@ class TheiaExport(object):
with
open
(
timestamp
,
'w'
)
as
f
:
with
open
(
timestamp
,
'w'
)
as
f
:
f
.
write
(
str
(
export_start_date
))
f
.
write
(
str
(
export_start_date
))
self
.
loginfo
(
'Backup resilient timestamp '
+
timestamp
)
self
.
remove_signatures
()
self
.
backupfile
(
timestamp
)
self
.
log
(
'Backup resilient timestamp '
+
timestamp
)
self
.
backup_file
(
timestamp
)
for
d
in
self
.
dirs
:
for
d
in
self
.
dirs
:
self
.
log
info
(
'Backup directory '
+
d
)
self
.
log
(
'Backup directory '
+
d
)
self
.
backuptree
(
d
)
self
.
backup
_
tree
(
d
)
self
.
log
info
(
'Backup slapproxy database'
)
self
.
log
(
'Backup slapproxy database'
)
self
.
backupdb
()
self
.
backup
_
db
()
self
.
log
info
(
'Backup partitions'
)
self
.
log
(
'Backup partitions'
)
for
p
in
self
.
partition_dirs
:
for
p
in
self
.
partition_dirs
:
self
.
backuppartition
(
p
)
self
.
backup
_
partition
(
p
)
self
.
loginfo
(
'Compute backup signature'
)
self
.
log
(
'Compute root backup signature'
)
self
.
sign
(
os
.
path
.
join
(
self
.
backup_dir
,
'backup.signature'
))
self
.
sign_root
()
self
.
log
(
'Compute partitions backup signatures'
)
for
p
in
self
.
partition_dirs
:
self
.
sign_partition
(
p
)
time
.
sleep
(
10
)
time
.
sleep
(
10
)
self
.
log
info
(
'Check partitions'
)
self
.
log
(
'Check partitions'
)
modified
=
list
(
itertools
.
chain
.
from_iterable
(
modified
=
list
(
itertools
.
chain
.
from_iterable
(
self
.
checkpartition
(
p
)
for
p
in
self
.
partition_dirs
))
self
.
check
_
partition
(
p
)
for
p
in
self
.
partition_dirs
))
if
modified
:
if
modified
:
msg
=
'Some files have been modified since the backup started'
msg
=
'Some files have been modified since the backup started'
self
.
log
info
(
msg
+
':'
)
self
.
log
(
msg
+
':'
)
self
.
log
info
(
'
\
n
'
.
join
(
modified
))
self
.
log
(
'
\
n
'
.
join
(
modified
))
self
.
log
info
(
"Let's wait %d minutes and try again"
%
BACKUP_WAIT
)
self
.
log
(
"Let's wait %d minutes and try again"
%
BACKUP_WAIT
)
time
.
sleep
(
BACKUP_WAIT
*
60
)
time
.
sleep
(
BACKUP_WAIT
*
60
)
raise
Exception
(
msg
)
raise
Exception
(
msg
)
self
.
log
info
(
'Done'
)
self
.
log
(
'Done'
)
if
__name__
==
'__main__'
:
if
__name__
==
'__main__'
:
...
...
software/theia/theia_import.py
View file @
9c59c5fc
...
@@ -57,32 +57,32 @@ class TheiaImport(object):
...
@@ -57,32 +57,32 @@ class TheiaImport(object):
configp
.
read
(
cfg
)
configp
.
read
(
cfg
)
self
.
proxy_db
=
configp
.
get
(
'slapproxy'
,
'database_uri'
)
self
.
proxy_db
=
configp
.
get
(
'slapproxy'
,
'database_uri'
)
self
.
instance_dir
=
configp
.
get
(
'slapos'
,
'instance_root'
)
self
.
instance_dir
=
configp
.
get
(
'slapos'
,
'instance_root'
)
mirror_dir
=
self
.
mirrorpath
(
self
.
instance_dir
)
mirror_dir
=
self
.
mirror
_
path
(
self
.
instance_dir
)
partitions
=
glob
.
glob
(
os
.
path
.
join
(
mirror_dir
,
'slappart*'
))
partitions
=
glob
.
glob
(
os
.
path
.
join
(
mirror_dir
,
'slappart*'
))
self
.
mirror_partition_dirs
=
[
p
for
p
in
partitions
if
os
.
path
.
isdir
(
p
)]
self
.
mirror_partition_dirs
=
[
p
for
p
in
partitions
if
os
.
path
.
isdir
(
p
)]
self
.
logs
=
[]
self
.
logs
=
[]
def
mirrorpath
(
self
,
dst
):
def
mirror
_
path
(
self
,
dst
):
return
os
.
path
.
abspath
(
os
.
path
.
join
(
return
os
.
path
.
abspath
(
os
.
path
.
join
(
self
.
backup_dir
,
os
.
path
.
relpath
(
dst
,
start
=
self
.
root_dir
)))
self
.
backup_dir
,
os
.
path
.
relpath
(
dst
,
start
=
self
.
root_dir
)))
def
dstpath
(
self
,
src
):
def
dst
_
path
(
self
,
src
):
return
os
.
path
.
abspath
(
os
.
path
.
join
(
return
os
.
path
.
abspath
(
os
.
path
.
join
(
self
.
root_dir
,
os
.
path
.
relpath
(
src
,
start
=
self
.
backup_dir
)))
self
.
root_dir
,
os
.
path
.
relpath
(
src
,
start
=
self
.
backup_dir
)))
def
restoretree
(
self
,
dst
,
exclude
=
(),
extrargs
=
(),
verbosity
=
'-v'
):
def
restore
_
tree
(
self
,
dst
,
exclude
=
(),
extrargs
=
(),
verbosity
=
'-v'
):
src
=
self
.
mirrorpath
(
dst
)
src
=
self
.
mirror
_
path
(
dst
)
return
copytree
(
self
.
rsync_bin
,
src
,
dst
,
exclude
,
extrargs
,
verbosity
)
return
copytree
(
self
.
rsync_bin
,
src
,
dst
,
exclude
,
extrargs
,
verbosity
)
def
restorefile
(
self
,
dst
):
def
restore
_
file
(
self
,
dst
):
src
=
self
.
mirrorpath
(
dst
)
src
=
self
.
mirror
_
path
(
dst
)
return
copyfile
(
src
,
dst
)
return
copyfile
(
src
,
dst
)
def
restoredb
(
self
):
def
restore
_
db
(
self
):
copydb
(
self
.
sqlite3_bin
,
self
.
mirrorpath
(
self
.
proxy_db
),
self
.
proxy_db
)
copydb
(
self
.
sqlite3_bin
,
self
.
mirror
_
path
(
self
.
proxy_db
),
self
.
proxy_db
)
def
restorepartition
(
self
,
mirror_partition
):
def
restore
_
partition
(
self
,
mirror_partition
):
p
=
self
.
dstpath
(
mirror_partition
)
p
=
self
.
dst
_
path
(
mirror_partition
)
installed
=
parse_installed
(
p
)
if
os
.
path
.
exists
(
p
)
else
[]
installed
=
parse_installed
(
p
)
if
os
.
path
.
exists
(
p
)
else
[]
copytree
(
self
.
rsync_bin
,
mirror_partition
,
p
,
exclude
=
installed
)
copytree
(
self
.
rsync_bin
,
mirror_partition
,
p
,
exclude
=
installed
)
...
@@ -97,31 +97,60 @@ class TheiaImport(object):
...
@@ -97,31 +97,60 @@ class TheiaImport(object):
print
(
' '
.
join
(
command
))
print
(
' '
.
join
(
command
))
sp
.
check_call
(
command
)
sp
.
check_call
(
command
)
def
verify
(
self
,
signaturefile
):
def
sign
(
self
,
signaturefile
,
root_dir
):
pardir
=
os
.
path
.
abspath
(
os
.
path
.
join
(
self
.
backup_dir
,
os
.
pardir
))
with
open
(
signaturefile
,
'r'
)
as
f
:
moved
=
os
.
path
.
join
(
pardir
,
'backup.signature.moved'
)
for
line
in
f
:
proof
=
os
.
path
.
join
(
pardir
,
'backup.signature.proof'
)
try
:
if
os
.
path
.
exists
(
signaturefile
):
_
,
relpath
=
line
.
strip
().
split
(
None
,
1
)
os
.
rename
(
signaturefile
,
moved
)
except
ValueError
:
if
not
os
.
path
.
exists
(
moved
):
yield
'Could not parse: %s'
%
line
msg
=
'ERROR the backup signature file is missing'
continue
print
(
msg
)
filepath
=
os
.
path
.
join
(
root_dir
,
relpath
)
try
:
signature
=
sha256sum
(
filepath
)
except
IOError
:
yield
'Could not read: %s'
%
filepath
continue
yield
'%s %s'
%
(
signature
,
relpath
)
def
sign_custom
(
self
,
root_dir
):
partition
=
self
.
dst_path
(
root_dir
)
script
=
hashscript
(
partition
)
if
not
script
:
msg
=
'ERROR: missing custom signature script for partition '
+
partition
raise
Exception
(
msg
)
raise
Exception
(
msg
)
return
hashcustom
(
root_dir
,
script
)
def
find_signature_file
(
self
,
partition
):
filename
=
os
.
path
.
basename
(
partition
)
+
'.backup.signature'
signaturefile
=
os
.
path
.
join
(
self
.
backup_dir
,
filename
)
if
os
.
path
.
exists
(
signaturefile
):
return
signaturefile
,
False
signaturefile
+=
'.custom'
if
os
.
path
.
exists
(
signaturefile
):
return
signaturefile
,
True
raise
Exception
(
'ERROR: missing signature file for partition '
+
partition
)
def
verify
(
self
,
signaturefile
,
root_dir
,
custom
=
False
):
proof
=
signaturefile
+
'.proof'
if
custom
:
signatures
=
self
.
sign_custom
(
root_dir
)
else
:
signatures
=
self
.
sign
(
signaturefile
,
root_dir
)
with
open
(
proof
,
'w'
)
as
f
:
with
open
(
proof
,
'w'
)
as
f
:
for
s
in
hashwalk
(
self
.
backup_dir
,
self
.
mirror_partition_dirs
)
:
for
s
in
signatures
:
f
.
write
(
s
+
'
\
n
'
)
f
.
write
(
s
+
'
\
n
'
)
diffcommand
=
(
'diff'
,
moved
,
proof
)
diffcommand
=
(
'diff'
,
signaturefile
,
proof
)
print
(
' '
.
join
(
diffcommand
))
try
:
try
:
sp
.
check_output
(
sp
.
check_output
(
diffcommand
,
stderr
=
sp
.
STDOUT
,
universal_newlines
=
True
)
diffcommand
,
stderr
=
sp
.
STDOUT
,
universal_newlines
=
True
)
except
sp
.
CalledProcessError
as
e
:
except
sp
.
CalledProcessError
as
e
:
template
=
'ERROR the backup signatures do not match
\
n
\
n
%s'
template
=
'ERROR the backup signatures do not match
\
n
\
n
%s
\
n
%s
'
msg
=
template
%
e
.
output
msg
=
template
%
(
' '
.
join
(
diffcommand
),
e
.
output
)
print
(
msg
)
print
(
msg
)
raise
Exception
(
msg
)
raise
Exception
(
msg
)
def
log
info
(
self
,
msg
):
def
log
(
self
,
msg
):
print
(
msg
)
print
(
msg
)
self
.
logs
.
append
(
msg
)
self
.
logs
.
append
(
msg
)
...
@@ -144,44 +173,54 @@ class TheiaImport(object):
...
@@ -144,44 +173,54 @@ class TheiaImport(object):
sys
.
exit
(
exitcode
)
sys
.
exit
(
exitcode
)
def
restore
(
self
):
def
restore
(
self
):
self
.
loginfo
(
'Verify backup signature'
)
self
.
log
(
'Verify main backup signature'
)
self
.
verify
(
os
.
path
.
join
(
self
.
backup_dir
,
'backup.signature'
))
signaturefile
=
os
.
path
.
join
(
self
.
backup_dir
,
'backup.signature'
)
self
.
verify
(
signaturefile
,
self
.
backup_dir
)
custom_partition_signatures
=
[]
for
m
in
self
.
mirror_partition_dirs
:
signaturefile
,
custom
=
self
.
find_signature_file
(
m
)
if
custom
:
custom_partition_signatures
.
append
((
signaturefile
,
m
))
else
:
self
.
log
(
'Verify backup signature for '
+
m
)
self
.
verify
(
signaturefile
,
m
)
self
.
log
info
(
'Stop slapproxy'
)
self
.
log
(
'Stop slapproxy'
)
self
.
supervisorctl
(
'stop'
,
'slapos-proxy'
)
self
.
supervisorctl
(
'stop'
,
'slapos-proxy'
)
self
.
log
info
(
'Restore partitions'
)
self
.
log
(
'Restore partitions'
)
for
m
in
self
.
mirror_partition_dirs
:
for
m
in
self
.
mirror_partition_dirs
:
self
.
restorepartition
(
m
)
self
.
restore
_
partition
(
m
)
for
d
in
self
.
dirs
:
for
d
in
self
.
dirs
:
self
.
log
info
(
'Restore directory '
+
d
)
self
.
log
(
'Restore directory '
+
d
)
self
.
restoretree
(
d
)
self
.
restore
_
tree
(
d
)
self
.
log
info
(
'Restore slapproxy database'
)
self
.
log
(
'Restore slapproxy database'
)
self
.
restoredb
()
self
.
restore
_
db
()
timestamp
=
os
.
path
.
join
(
self
.
root_dir
,
'etc'
,
'.resilient_timestamp'
)
timestamp
=
os
.
path
.
join
(
self
.
root_dir
,
'etc'
,
'.resilient_timestamp'
)
self
.
log
info
(
'Restore resilient timestamp '
+
timestamp
)
self
.
log
(
'Restore resilient timestamp '
+
timestamp
)
self
.
restorefile
(
timestamp
)
self
.
restore
_
file
(
timestamp
)
custom_script
=
os
.
path
.
join
(
self
.
root_dir
,
'srv'
,
'runner-import-restore'
)
custom_script
=
os
.
path
.
join
(
self
.
root_dir
,
'srv'
,
'runner-import-restore'
)
if
os
.
path
.
exists
(
custom_script
):
if
os
.
path
.
exists
(
custom_script
):
self
.
log
info
(
'Run custom restore script %s'
%
custom_script
)
self
.
log
(
'Run custom restore script %s'
%
custom_script
)
sp
.
check_call
(
custom_script
)
sp
.
check_call
(
custom_script
)
self
.
log
info
(
'Start slapproxy again'
)
self
.
log
(
'Start slapproxy again'
)
self
.
supervisorctl
(
'start'
,
'slapos-proxy'
)
self
.
supervisorctl
(
'start'
,
'slapos-proxy'
)
self
.
log
info
(
'Reformat partitions'
)
self
.
log
(
'Reformat partitions'
)
self
.
slapos
(
'node'
,
'format'
,
'--now'
)
self
.
slapos
(
'node'
,
'format'
,
'--now'
)
self
.
log
info
(
'Remove old supervisord configuration files'
)
self
.
log
(
'Remove old supervisord configuration files'
)
conf_dir
=
os
.
path
.
join
(
self
.
instance_dir
,
'etc'
,
'supervisor.conf.d'
)
conf_dir
=
os
.
path
.
join
(
self
.
instance_dir
,
'etc'
,
'supervisor.conf.d'
)
for
f
in
glob
.
glob
(
os
.
path
.
join
(
conf_dir
,
'*'
)):
for
f
in
glob
.
glob
(
os
.
path
.
join
(
conf_dir
,
'*'
)):
os
.
remove
(
f
)
os
.
remove
(
f
)
self
.
log
info
(
'Build Software Releases'
)
self
.
log
(
'Build Software Releases'
)
for
i
in
range
(
3
):
for
i
in
range
(
3
):
try
:
try
:
self
.
slapos
(
'node'
,
'software'
,
'--all'
,
'--logfile'
,
self
.
sr_log
)
self
.
slapos
(
'node'
,
'software'
,
'--all'
,
'--logfile'
,
self
.
sr_log
)
...
@@ -191,18 +230,18 @@ class TheiaImport(object):
...
@@ -191,18 +230,18 @@ class TheiaImport(object):
else
:
else
:
break
break
self
.
log
info
(
'Remove old custom instance scripts'
)
self
.
log
(
'Remove old custom instance scripts'
)
partitions_glob
=
os
.
path
.
join
(
self
.
instance_dir
,
'slappart*'
)
partitions_glob
=
os
.
path
.
join
(
self
.
instance_dir
,
'slappart*'
)
scripts
=
os
.
path
.
join
(
partitions_glob
,
'srv'
,
'runner-import-restore'
)
scripts
=
os
.
path
.
join
(
partitions_glob
,
'srv'
,
'runner-import-restore'
)
for
f
in
glob
.
glob
(
scripts
):
for
f
in
glob
.
glob
(
scripts
):
remove
(
f
)
remove
(
f
)
self
.
log
info
(
'Remove partition timestamps'
)
self
.
log
(
'Remove partition timestamps'
)
timestamps
=
os
.
path
.
join
(
partitions_glob
,
'.timestamp'
)
timestamps
=
os
.
path
.
join
(
partitions_glob
,
'.timestamp'
)
for
f
in
glob
.
glob
(
timestamps
):
for
f
in
glob
.
glob
(
timestamps
):
remove
(
f
)
remove
(
f
)
self
.
log
info
(
'Build Instances'
)
self
.
log
(
'Build Instances'
)
cp_log
=
self
.
cp_log
cp_log
=
self
.
cp_log
for
i
in
range
(
3
):
for
i
in
range
(
3
):
try
:
try
:
...
@@ -213,11 +252,15 @@ class TheiaImport(object):
...
@@ -213,11 +252,15 @@ class TheiaImport(object):
else
:
else
:
break
break
self
.
log
(
'Verify custom backup signatures'
)
for
signaturefile
,
m
in
custom_partition_signatures
:
self
.
verify
(
signaturefile
,
m
,
True
)
for
custom_script
in
glob
.
glob
(
scripts
):
for
custom_script
in
glob
.
glob
(
scripts
):
self
.
log
info
(
'Running custom instance script %s'
%
custom_script
)
self
.
log
(
'Running custom instance script %s'
%
custom_script
)
sp
.
check_call
(
custom_script
)
sp
.
check_call
(
custom_script
)
self
.
log
info
(
'Done'
)
self
.
log
(
'Done'
)
if
__name__
==
'__main__'
:
if
__name__
==
'__main__'
:
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment