Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
R
rwm
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
Package registry
Container registry
Model registry
Operate
Environments
Terraform modules
Monitor
Incidents
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
GitLab community forum
Contribute to GitLab
Provide feedback
Terms and privacy
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
Radoslav Bodó
rwm
Commits
c4ffc750
Commit
c4ffc750
authored
Apr 11, 2024
by
Radoslav Bodó
Browse files
Options
Downloads
Patches
Plain Diff
rwm: refactor storage detailed info from storage_list to separate storage_info command
parent
17878948
No related branches found
No related tags found
No related merge requests found
Changes
5
Show whitespace changes
Inline
Side-by-side
Showing
5 changed files
README.md
+2
-2
2 additions, 2 deletions
README.md
rwm.py
+80
-41
80 additions, 41 deletions
rwm.py
tests/test_default.py
+2
-0
2 additions, 0 deletions
tests/test_default.py
tests/test_rwm.py
+14
-1
14 additions, 1 deletion
tests/test_rwm.py
tests/test_storage.py
+16
-1
16 additions, 1 deletion
tests/test_storage.py
with
114 additions
and
45 deletions
README.md
+
2
−
2
View file @
c4ffc750
...
@@ -83,9 +83,9 @@ Two distinct S3 accounts required (*admin*, *user1*)
...
@@ -83,9 +83,9 @@ Two distinct S3 accounts required (*admin*, *user1*)
```
```
cp examples/rwm-admin.conf admin.conf
cp examples/rwm-admin.conf admin.conf
rwm --confg admin.conf create_storage bucket1 user1
rwm --confg admin.conf storage_check_policy bucket1
rwm --confg admin.conf storage_list
rwm --confg admin.conf storage_list
rwm --confg admin.conf storage_create bucket1 user1
rwm --confg admin.conf storage_info bucket1
cp examples/rwm-backups.conf rwm.conf
cp examples/rwm-backups.conf rwm.conf
rwm restic init
rwm restic init
...
...
This diff is collapsed.
Click to expand it.
rwm.py
+
80
−
41
View file @
c4ffc750
...
@@ -6,7 +6,6 @@ import gzip
...
@@ -6,7 +6,6 @@ import gzip
import
json
import
json
import
logging
import
logging
import
os
import
os
import
re
import
shlex
import
shlex
import
subprocess
import
subprocess
import
sys
import
sys
...
@@ -152,6 +151,11 @@ class StorageManager:
...
@@ -152,6 +151,11 @@ class StorageManager:
logger
.
error
(
"
rwm bucket_policy error, %s
"
,
(
exc
))
logger
.
error
(
"
rwm bucket_policy error, %s
"
,
(
exc
))
return
None
return
None
def
bucket_acl
(
self
,
name
):
"""
api stub
"""
acl
=
self
.
s3
.
Bucket
(
name
).
Acl
()
return
{
"
owner
"
:
acl
.
owner
,
"
grants
"
:
acl
.
grants
}
def
list_buckets
(
self
):
def
list_buckets
(
self
):
"""
aws s3 resource api stub
"""
"""
aws s3 resource api stub
"""
return
list
(
self
.
s3
.
buckets
.
all
())
return
list
(
self
.
s3
.
buckets
.
all
())
...
@@ -240,19 +244,15 @@ class StorageManager:
...
@@ -240,19 +244,15 @@ class StorageManager:
return
False
return
False
def
storage_list
(
self
,
show_full
=
False
,
name_filter
=
""
):
def
storage_list
(
self
):
"""
storage list
"""
"""
storage list
"""
pattern
=
re
.
compile
(
name_filter
)
buckets
=
[
bucket
for
bucket
in
self
.
list_buckets
()
if
pattern
.
search
(
bucket
.
name
)]
paginator
=
self
.
s3
.
meta
.
client
.
get_paginator
(
'
list_object_versions
'
)
output
=
[]
output
=
[]
for
bucket
in
self
.
list_buckets
():
for
bucket
in
buckets
:
result
=
{}
result
=
{}
result
[
"
name
"
]
=
bucket
.
name
result
[
"
name
"
]
=
bucket
.
name
result
[
"
policy
"
]
=
"
OK
"
if
self
.
storage_check_policy
(
bucket
.
name
)
else
"
FAILED
"
result
[
"
policy
"
]
=
"
OK
"
if
self
.
storage_check_policy
(
bucket
.
name
)
else
"
FAILED
"
result
[
"
owner
"
]
=
self
.
bucket_owner
(
bucket
.
name
).
split
(
"
$
"
)[
-
1
]
result
[
"
short_
owner
"
]
=
self
.
bucket_owner
(
bucket
.
name
).
split
(
"
$
"
)[
-
1
]
if
result
[
"
policy
"
]
==
"
OK
"
:
if
result
[
"
policy
"
]
==
"
OK
"
:
user_statement
=
self
.
_policy_statements_user
(
self
.
bucket_policy
(
bucket
.
name
))[
0
]
user_statement
=
self
.
_policy_statements_user
(
self
.
bucket_policy
(
bucket
.
name
))[
0
]
...
@@ -260,14 +260,28 @@ class StorageManager:
...
@@ -260,14 +260,28 @@ class StorageManager:
else
:
else
:
result
[
"
target_user
"
]
=
None
result
[
"
target_user
"
]
=
None
if
show_full
:
output
.
append
(
result
)
return
output
def
storage_info
(
self
,
bucket_name
):
"""
grabs storage bucket detailed info
"""
result
=
{}
result
[
"
name
"
]
=
bucket_name
result
[
"
check_policy
"
]
=
"
OK
"
if
self
.
storage_check_policy
(
bucket_name
)
else
"
FAILED
"
result
[
"
owner
"
]
=
self
.
bucket_owner
(
bucket_name
)
result
[
"
acl
"
]
=
self
.
bucket_acl
(
bucket_name
)
result
[
"
policy
"
]
=
self
.
bucket_policy
(
bucket_name
)
result
[
"
objects
"
]
=
0
result
[
"
objects
"
]
=
0
result
[
"
delete_markers
"
]
=
0
result
[
"
delete_markers
"
]
=
0
result
[
"
old_versions
"
]
=
0
result
[
"
old_versions
"
]
=
0
result
[
"
size
"
]
=
0
result
[
"
size
"
]
=
0
result
[
"
old_size
"
]
=
0
result
[
"
old_size
"
]
=
0
result
[
"
saved_states
"
]
=
[]
for
page
in
paginator
.
paginate
(
Bucket
=
bucket
.
name
):
paginator
=
self
.
s3
.
meta
.
client
.
get_paginator
(
'
list_object_versions
'
)
for
page
in
paginator
.
paginate
(
Bucket
=
bucket_name
):
for
obj
in
page
.
get
(
"
Versions
"
,
[]):
for
obj
in
page
.
get
(
"
Versions
"
,
[]):
if
obj
[
"
IsLatest
"
]:
if
obj
[
"
IsLatest
"
]:
result
[
"
objects
"
]
+=
1
result
[
"
objects
"
]
+=
1
...
@@ -276,12 +290,11 @@ class StorageManager:
...
@@ -276,12 +290,11 @@ class StorageManager:
result
[
"
old_versions
"
]
+=
1
result
[
"
old_versions
"
]
+=
1
result
[
"
old_size
"
]
+=
obj
[
"
Size
"
]
result
[
"
old_size
"
]
+=
obj
[
"
Size
"
]
result
[
"
delete_markers
"
]
+=
len
(
page
.
get
(
"
DeleteMarkers
"
,
[]))
result
[
"
delete_markers
"
]
+=
len
(
page
.
get
(
"
DeleteMarkers
"
,
[]))
result
[
"
size
"
]
=
size_fmt
(
result
[
"
size
"
])
result
[
"
old_size
"
]
=
size_fmt
(
result
[
"
old_size
"
])
output
.
append
(
result
)
for
page
in
paginator
.
paginate
(
Bucket
=
bucket_name
,
Prefix
=
"
rwm
"
):
result
[
"
saved_states
"
]
+=
[
x
[
"
Key
"
]
for
x
in
page
.
get
(
"
Versions
"
,
[])]
return
outpu
t
return
resul
t
def
storage_drop_versions
(
self
,
bucket_name
):
def
storage_drop_versions
(
self
,
bucket_name
):
"""
deletes all old versions and delete markers from storage to reclaim space
"""
"""
deletes all old versions and delete markers from storage to reclaim space
"""
...
@@ -311,10 +324,9 @@ class StorageManager:
...
@@ -311,10 +324,9 @@ class StorageManager:
def
_bucket_state
(
self
,
bucket_name
):
def
_bucket_state
(
self
,
bucket_name
):
"""
dumps current bucket state into dict
"""
"""
dumps current bucket state into dict
"""
acl
=
self
.
s3
.
Bucket
(
bucket_name
).
Acl
()
state
=
{
state
=
{
"
bucket_name
"
:
bucket_name
,
"
bucket_name
"
:
bucket_name
,
"
bucket_acl
"
:
{
"
owner
"
:
acl
.
owner
,
"
grants
"
:
acl
.
grants
}
,
"
bucket_acl
"
:
self
.
bucket_acl
(
bucket_name
)
,
"
bucket_policy
"
:
self
.
bucket_policy
(
bucket_name
),
"
bucket_policy
"
:
self
.
bucket_policy
(
bucket_name
),
"
time_start
"
:
datetime
.
now
(),
"
time_start
"
:
datetime
.
now
(),
"
time_end
"
:
None
,
"
time_end
"
:
None
,
...
@@ -490,22 +502,46 @@ class RWM:
...
@@ -490,22 +502,46 @@ class RWM:
return
self
.
storage_manager
.
storage_delete
(
bucket_name
)
return
self
.
storage_manager
.
storage_delete
(
bucket_name
)
def
storage_list
(
self
,
show_full
=
False
,
name_filter
=
""
)
->
int
:
def
storage_list
(
self
)
->
int
:
"""
storage_list command
"""
"""
storage_list command
"""
print
(
tabulate
(
print
(
tabulate
(
self
.
storage_manager
.
storage_list
(),
headers
=
"
keys
"
,
numalign
=
"
left
"
))
self
.
storage_manager
.
storage_list
(
show_full
,
name_filter
),
headers
=
"
keys
"
,
numalign
=
"
left
"
))
return
0
return
0
def
storage_drop_versions
(
self
,
bucket_name
):
def
storage_info
(
self
,
bucket_name
)
->
int
:
"""
storage_list command
"""
sinfo
=
self
.
storage_manager
.
storage_info
(
bucket_name
)
total_size
=
sinfo
[
"
size
"
]
+
sinfo
[
"
old_size
"
]
print
(
f
'
Storage bucket:
{
sinfo
[
"
name
"
]
}
'
)
print
(
"
----------------------------------------
"
)
print
(
f
'
RWM policy check:
{
sinfo
[
"
check_policy
"
]
}
'
)
print
(
f
'
Owner:
{
sinfo
[
"
owner
"
]
}
'
)
print
(
f
'
Objects:
{
sinfo
[
"
objects
"
]
}
'
)
print
(
f
'
Delete markers:
{
sinfo
[
"
delete_markers
"
]
}
'
)
print
(
f
'
Old versions:
{
sinfo
[
"
old_versions
"
]
}
'
)
print
(
f
'
Size:
{
size_fmt
(
sinfo
[
"
size
"
])
}
'
)
print
(
f
'
Old size:
{
size_fmt
(
sinfo
[
"
old_size
"
])
}
'
)
print
(
f
'
Total size:
{
size_fmt
(
total_size
)
}
'
)
print
(
"
----------------------------------------
"
)
print
(
"
Bucket ACL:
"
)
print
(
json
.
dumps
(
sinfo
[
"
acl
"
],
indent
=
2
))
print
(
"
----------------------------------------
"
)
print
(
"
Bucket policy:
"
)
print
(
json
.
dumps
(
sinfo
[
"
policy
"
],
indent
=
2
))
print
(
"
----------------------------------------
"
)
print
(
"
RWM saved states:
"
)
print
(
"
\n
"
.
join
(
sorted
(
sinfo
[
"
saved_states
"
])))
return
0
def
storage_drop_versions
(
self
,
bucket_name
)
->
int
:
"""
storage_drop_versions command
"""
"""
storage_drop_versions command
"""
return
self
.
storage_manager
.
storage_drop_versions
(
bucket_name
)
return
self
.
storage_manager
.
storage_drop_versions
(
bucket_name
)
def
storage_restore_state
(
self
,
source_bucket
,
target_bucket
,
state_object_key
):
def
storage_restore_state
(
self
,
source_bucket
,
target_bucket
,
state_object_key
)
->
int
:
"""
storage restore state
"""
"""
storage restore state
"""
return
self
.
storage_manager
.
storage_restore_state
(
source_bucket
,
target_bucket
,
state_object_key
)
return
self
.
storage_manager
.
storage_restore_state
(
source_bucket
,
target_bucket
,
state_object_key
)
...
@@ -553,9 +589,10 @@ def parse_arguments(argv):
...
@@ -553,9 +589,10 @@ def parse_arguments(argv):
storage_delete_cmd_parser
=
subparsers
.
add_parser
(
"
storage_delete
"
,
help
=
"
delete storage
"
)
storage_delete_cmd_parser
=
subparsers
.
add_parser
(
"
storage_delete
"
,
help
=
"
delete storage
"
)
storage_delete_cmd_parser
.
add_argument
(
"
bucket_name
"
,
help
=
"
bucket name
"
)
storage_delete_cmd_parser
.
add_argument
(
"
bucket_name
"
,
help
=
"
bucket name
"
)
storage_list_cmd_parser
=
subparsers
.
add_parser
(
"
storage_list
"
,
help
=
"
list storages
"
)
_
=
subparsers
.
add_parser
(
"
storage_list
"
,
help
=
"
list storages
"
)
storage_list_cmd_parser
.
add_argument
(
"
--full
"
,
action
=
"
store_true
"
,
help
=
"
show object counts
"
)
storage_list_cmd_parser
.
add_argument
(
"
--filter
"
,
default
=
""
,
help
=
"
name filter regex
"
)
storage_info_cmd_parser
=
subparsers
.
add_parser
(
"
storage_info
"
,
help
=
"
show detailed storage info
"
)
storage_info_cmd_parser
.
add_argument
(
"
bucket_name
"
,
help
=
"
bucket name
"
)
storage_drop_versions_cmd_parser
=
subparsers
.
add_parser
(
storage_drop_versions_cmd_parser
=
subparsers
.
add_parser
(
"
storage_drop_versions
"
,
"
storage_drop_versions
"
,
...
@@ -606,7 +643,9 @@ def main(argv=None): # pylint: disable=too-many-branches
...
@@ -606,7 +643,9 @@ def main(argv=None): # pylint: disable=too-many-branches
if
args
.
command
==
"
storage_delete
"
:
if
args
.
command
==
"
storage_delete
"
:
ret
=
rwmi
.
storage_delete
(
args
.
bucket_name
)
ret
=
rwmi
.
storage_delete
(
args
.
bucket_name
)
if
args
.
command
==
"
storage_list
"
:
if
args
.
command
==
"
storage_list
"
:
ret
=
rwmi
.
storage_list
(
args
.
full
,
args
.
filter
)
ret
=
rwmi
.
storage_list
()
if
args
.
command
==
"
storage_info
"
:
ret
=
rwmi
.
storage_info
(
args
.
bucket_name
)
if
args
.
command
==
"
storage_drop_versions
"
:
if
args
.
command
==
"
storage_drop_versions
"
:
ret
=
rwmi
.
storage_drop_versions
(
args
.
bucket_name
)
ret
=
rwmi
.
storage_drop_versions
(
args
.
bucket_name
)
if
args
.
command
==
"
storage_restore_state
"
:
if
args
.
command
==
"
storage_restore_state
"
:
...
...
This diff is collapsed.
Click to expand it.
tests/test_default.py
+
2
−
0
View file @
c4ffc750
...
@@ -57,6 +57,8 @@ def test_main(tmpworkdir: str): # pylint: disable=unused-argument
...
@@ -57,6 +57,8 @@ def test_main(tmpworkdir: str): # pylint: disable=unused-argument
assert
rwm_main
([
"
storage_delete
"
,
"
bucket
"
])
==
0
assert
rwm_main
([
"
storage_delete
"
,
"
bucket
"
])
==
0
with
patch
.
object
(
rwm
.
RWM
,
"
storage_list
"
,
mock_ok
):
with
patch
.
object
(
rwm
.
RWM
,
"
storage_list
"
,
mock_ok
):
assert
rwm_main
([
"
storage_list
"
])
==
0
assert
rwm_main
([
"
storage_list
"
])
==
0
with
patch
.
object
(
rwm
.
RWM
,
"
storage_info
"
,
mock_ok
):
assert
rwm_main
([
"
storage_info
"
,
"
dummy
"
])
==
0
with
patch
.
object
(
rwm
.
RWM
,
"
storage_drop_versions
"
,
mock_ok
):
with
patch
.
object
(
rwm
.
RWM
,
"
storage_drop_versions
"
,
mock_ok
):
assert
rwm_main
([
"
storage_drop_versions
"
,
"
bucket
"
])
==
0
assert
rwm_main
([
"
storage_drop_versions
"
,
"
bucket
"
])
==
0
with
patch
.
object
(
rwm
.
RWM
,
"
storage_restore_state
"
,
mock_ok
):
with
patch
.
object
(
rwm
.
RWM
,
"
storage_restore_state
"
,
mock_ok
):
...
...
This diff is collapsed.
Click to expand it.
tests/test_rwm.py
+
14
−
1
View file @
c4ffc750
...
@@ -243,6 +243,19 @@ def test_storage_list(tmpworkdir: str): # pylint: disable=unused-argument
...
@@ -243,6 +243,19 @@ def test_storage_list(tmpworkdir: str): # pylint: disable=unused-argument
assert
trwm
.
storage_list
()
==
0
assert
trwm
.
storage_list
()
==
0
def
test_storage_info
(
tmpworkdir
:
str
,
microceph
:
str
,
radosuser_admin
:
rwm
.
StorageManager
):
# pylint: disable=unused-argument
"""
test storage_list
"""
trwm
=
rwm
.
RWM
({
"
rwm_s3_endpoint_url
"
:
radosuser_admin
.
url
,
"
rwm_s3_access_key
"
:
radosuser_admin
.
access_key
,
"
rwm_s3_secret_key
"
:
radosuser_admin
.
secret_key
,
})
trwm
.
storage_create
(
"
dummy
"
,
"
dummy
"
)
assert
trwm
.
storage_info
(
"
dummy
"
)
==
0
def
test_storage_drop_versions
(
tmpworkdir
:
str
):
# pylint: disable=unused-argument
def
test_storage_drop_versions
(
tmpworkdir
:
str
):
# pylint: disable=unused-argument
"""
test storage drop versions
"""
"""
test storage drop versions
"""
...
@@ -287,7 +300,7 @@ def test_storage_restore_state_restic(tmpworkdir: str, radosuser_admin: rwm.Stor
...
@@ -287,7 +300,7 @@ def test_storage_restore_state_restic(tmpworkdir: str, radosuser_admin: rwm.Stor
assert
len
(
snapshots
)
==
2
assert
len
(
snapshots
)
==
2
assert
len
(
snapshot_files
)
==
1
assert
len
(
snapshot_files
)
==
1
assert
"
/testdatadir/testdata2.txt
"
==
snapshot_files
[
0
]
assert
"
/testdatadir/testdata2.txt
"
==
snapshot_files
[
0
]
states
=
sorted
([
x
.
key
for
x
in
trwm
.
storage_manager
.
s3
.
Bucket
(
trwm
.
config
[
"
rwm_restic_bucket
"
]).
objects
.
filter
(
Prefix
=
"
rwm
"
)])
states
=
sorted
([
x
.
key
for
x
in
trwm
.
storage_manager
.
s3
.
Bucket
(
trwm
.
config
[
"
rwm_restic_bucket
"
]).
object
_version
s
.
filter
(
Prefix
=
"
rwm
"
)])
assert
len
(
states
)
==
2
assert
len
(
states
)
==
2
# create restore bucket
# create restore bucket
...
...
This diff is collapsed.
Click to expand it.
tests/test_storage.py
+
16
−
1
View file @
c4ffc750
...
@@ -159,11 +159,26 @@ def test_storage_list(
...
@@ -159,11 +159,26 @@ def test_storage_list(
target_username
=
"
test1
"
target_username
=
"
test1
"
radosuser_admin
.
bucket_create
(
"
no-acl-dummy
"
)
radosuser_admin
.
bucket_create
(
"
no-acl-dummy
"
)
radosuser_admin
.
storage_create
(
bucket_name
,
target_username
)
assert
radosuser_admin
.
storage_list
()
def
test_storage_info
(
tmpworkdir
:
str
,
microceph
:
str
,
radosuser_admin
:
rwm
.
StorageManager
,
):
# pylint: disable=unused-argument
"""
test managet list storage
"""
bucket_name
=
"
rwmbackup-test1
"
target_username
=
"
test1
"
bucket
=
radosuser_admin
.
storage_create
(
bucket_name
,
target_username
)
bucket
=
radosuser_admin
.
storage_create
(
bucket_name
,
target_username
)
assert
radosuser_admin
.
storage_list
()
bucket
.
upload_fileobj
(
BytesIO
(
b
"
dummydata1
"
),
"
dummykey
"
)
bucket
.
upload_fileobj
(
BytesIO
(
b
"
dummydata1
"
),
"
dummykey
"
)
bucket
.
upload_fileobj
(
BytesIO
(
b
"
dummydata1
"
),
"
dummykey1
"
)
bucket
.
upload_fileobj
(
BytesIO
(
b
"
dummydata1
"
),
"
dummykey1
"
)
bucket
.
Object
(
"
dummykey1
"
).
delete
()
bucket
.
Object
(
"
dummykey1
"
).
delete
()
assert
len
(
radosuser_admin
.
storage_
list
(
show_full
=
True
,
name_filter
=
"
a
"
))
==
2
assert
radosuser_admin
.
storage_
info
(
bucket_name
)[
"
delete_markers
"
]
==
1
def
test_storage_drop_versions
(
tmpworkdir
:
str
,
microceph
:
str
,
radosuser_admin
:
rwm
.
StorageManager
):
# pylint: disable=unused-argument
def
test_storage_drop_versions
(
tmpworkdir
:
str
,
microceph
:
str
,
radosuser_admin
:
rwm
.
StorageManager
):
# pylint: disable=unused-argument
...
...
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