Skip to content

Commit 76a9e75

Browse files
committed
backend, frontend: add script to migrate existing build results to Pulp
Fix #3503
1 parent 4ec0f9a commit 76a9e75

File tree

2 files changed

+166
-3
lines changed

2 files changed

+166
-3
lines changed

backend/run/copr-change-storage

Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
#! /usr/bin/python3
2+
3+
"""
4+
Migrate existing build results for a given project and all of its CoprDirs
5+
from one storage (Copr backend) to another (Pulp).
6+
"""
7+
8+
import os
9+
import sys
10+
import argparse
11+
import logging
12+
from copr_common.log import setup_script_logger
13+
from copr_backend.helpers import BackendConfigReader
14+
from copr_backend.storage import PulpStorage
15+
16+
17+
STORAGES = ["backend", "pulp"]
18+
19+
log = logging.getLogger(__name__)
20+
setup_script_logger(log, "/var/log/copr-backend/change-storage.log")
21+
22+
23+
def get_arg_parser():
24+
"""
25+
CLI argument parser
26+
"""
27+
parser = argparse.ArgumentParser()
28+
parser.add_argument(
29+
"--src",
30+
required=True,
31+
choices=STORAGES,
32+
help="The source storage",
33+
)
34+
parser.add_argument(
35+
"--dst",
36+
required=True,
37+
choices=STORAGES,
38+
help="The destination storage",
39+
)
40+
parser.add_argument(
41+
"--project",
42+
required=True,
43+
help="Full name of the project that is to be migrated",
44+
)
45+
parser.add_argument(
46+
"--delete",
47+
action="store_true",
48+
default=False,
49+
help="After migrating the data, remove it from the old storage",
50+
)
51+
return parser
52+
53+
54+
def is_valid_build_directory(name):
55+
"""
56+
See the `copr-backend-resultdir-cleaner`. We may want to share the code
57+
between them.
58+
"""
59+
if name in ["repodata", "devel"]:
60+
return False
61+
62+
if name.startswith("repodata.old") or name.startswith(".repodata."):
63+
return False
64+
65+
if name in ["tmp", "cache", "appdata"]:
66+
return False
67+
68+
parts = name.split("-")
69+
if len(parts) <= 1:
70+
return False
71+
72+
number = parts[0]
73+
if len(number) != 8 or any(not c.isdigit() for c in number):
74+
return False
75+
76+
return True
77+
78+
79+
def main():
80+
"""
81+
The main function
82+
"""
83+
parser = get_arg_parser()
84+
args = parser.parse_args()
85+
86+
if args.src == args.dst:
87+
log.info("The source and destination storage is the same, nothing to do.")
88+
return
89+
90+
if args.src == "pulp":
91+
log.error("Migration from pulp to somewhere else is not supported")
92+
sys.exit(1)
93+
94+
if args.delete:
95+
log.error("Data removal is not supported yet")
96+
sys.exit(1)
97+
98+
config_file = "/etc/copr/copr-be.conf"
99+
config = BackendConfigReader(config_file).read()
100+
owner, project = args.project.split("/")
101+
ownerdir = os.path.join(config.destdir, owner)
102+
103+
for subproject in os.listdir(ownerdir):
104+
if not (subproject == project or subproject.startswith(project + ":")):
105+
continue
106+
107+
coprdir = os.path.join(ownerdir, subproject)
108+
for chroot in os.listdir(coprdir):
109+
if chroot == "srpm-builds":
110+
continue
111+
112+
chrootdir = os.path.join(coprdir, chroot)
113+
if not os.path.isdir(chrootdir):
114+
continue
115+
116+
appstream = None
117+
devel = None
118+
storage = PulpStorage(
119+
owner, subproject, appstream, devel, config, log)
120+
121+
for builddir in os.listdir(chrootdir):
122+
resultdir = os.path.join(chrootdir, builddir)
123+
if not os.path.isdir(resultdir):
124+
continue
125+
126+
if not is_valid_build_directory(builddir):
127+
log.info("Skipping: %s", resultdir)
128+
continue
129+
130+
# TODO Fault-tolerance and data consistency
131+
# Errors when creating things in Pulp will likely happen
132+
# (networking issues, unforseen Pulp validation, etc). We
133+
# should figure out how to ensure that all RPMs were
134+
# successfully uploaded, and if not, we know about it.
135+
#
136+
# We also need to make sure that no builds, actions, or cron,
137+
# are currently writing into the results directory. Otherwise
138+
# we can end up with incosystent data in Pulp.
139+
140+
full_name = "{0}/{1}".format(owner, subproject)
141+
result = storage.init_project(full_name, chroot)
142+
if not result:
143+
log.error("Failed to initialize project: %s", resultdir)
144+
break
145+
146+
# We cannot check return code here
147+
storage.upload_build_results(chroot, resultdir, None)
148+
149+
result = storage.publish_repository(chroot)
150+
if not result:
151+
log.error("Failed to publish a repository: %s", resultdir)
152+
break
153+
154+
log.info("OK: %s", resultdir)
155+
156+
157+
if __name__ == "__main__":
158+
main()

frontend/coprs_frontend/commands/change_storage.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@
66
configure the storage type for a given project and while doing so, it makes sure
77
DNF repositories for the project are created.
88
9-
Existing builds are not migrated from one storage to another. This may be an
10-
useful feature but it is not implemented yet.
9+
To migrate existing build results for a given project and all of its CoprDirs,
10+
run also `copr-change-storage` script on backend.
1111
"""
1212

1313
import sys
@@ -44,4 +44,9 @@ def change_storage(fullname, storage):
4444
db.session.commit()
4545
print("Configured storage for {0} to {1}".format(copr.full_name, storage))
4646
print("Submitted action to create repositories: {0}".format(action.id))
47-
print("Existing builds not migrated (not implemented yet).")
47+
print("To migrate existing build results for this project and all of its "
48+
"CoprDirs, run also this command on backend:")
49+
50+
cmd = "sudo -u copr copr-change-storage --src backend --dst pulp "
51+
cmd += "--project {0}".format(fullname)
52+
print(" {0}".format(cmd))

0 commit comments

Comments
 (0)