Skip to content
This repository was archived by the owner on Jan 14, 2021. It is now read-only.

Commit 9d3ed4c

Browse files
authored
Merge pull request #63 from mprahl/retirement
Add a handler so that PDC branches are EOL'd when the branch is retired
2 parents 1362112 + e2d5289 commit 9d3ed4c

File tree

2 files changed

+513
-0
lines changed

2 files changed

+513
-0
lines changed

pdcupdater/handlers/retirement.py

Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
import logging
2+
from datetime import datetime
3+
import requests
4+
5+
import pdcupdater.services
6+
7+
log = logging.getLogger(__name__)
8+
9+
10+
class RetireComponentHandler(pdcupdater.handlers.BaseHandler):
11+
""" When a component's branch is retired, EOL all SLAs on that branch. """
12+
13+
@property
14+
def topic_suffixes(self):
15+
return ['git.receive']
16+
17+
def can_handle(self, pdc, msg):
18+
""" Return true if this handler can/should handle a message. """
19+
if not msg['topic'].endswith('git.receive'):
20+
return False
21+
22+
# If there is no dead.package in the commit, then it can be ignored
23+
if 'dead.package' not in msg['msg']['commit']['stats']['files']:
24+
return False
25+
26+
dead_package_commit = \
27+
msg['msg']['commit']['stats']['files']['dead.package']
28+
# Only handles the message if the dead.package was added, not deleted
29+
return dead_package_commit['additions'] > 0 \
30+
and dead_package_commit['deletions'] == 0
31+
32+
def handle(self, pdc, msg):
33+
""" Handle an incoming bus message.
34+
35+
The message should be a dist-git retirement message (where someone adds
36+
a dead.package file to the repo). In response, this method will retire
37+
the package in PDC.
38+
"""
39+
branch = msg['msg']['commit']['branch']
40+
repo = msg['msg']['commit']['repo']
41+
namespace = msg['msg']['commit']['namespace']
42+
component_type = self._namespace_to_pdc(namespace)
43+
# This query guarantees a unique component branch, so a count of 1 is
44+
# expected
45+
branch_query_rv = pdc['component-branches']._(
46+
name=branch, type=component_type, global_component=repo)
47+
48+
if branch_query_rv['count'] != 1:
49+
log.error('"{0}/{1}" was not found in PDC'.format(namespace, repo))
50+
return
51+
52+
branch = branch_query_rv['results'][0]
53+
# If the branch is already EOL in PDC, don't do anything
54+
if branch['active'] is False:
55+
return
56+
57+
self._retire_branch(pdc, branch)
58+
59+
@staticmethod
60+
def _retire_branch(pdc, branch):
61+
""" Internal method for retiring a branch in PDC. """
62+
today = datetime.utcnow().date()
63+
for sla in branch['slas']:
64+
sla_eol = datetime.strptime(sla['eol'], '%Y-%m-%d').date()
65+
if sla_eol > today:
66+
pdc['component-branch-slas'][sla['id']]._ \
67+
+= {'eol': str(today)}
68+
69+
@staticmethod
70+
def _namespace_to_pdc(namespace):
71+
namespace_to_pdc = {
72+
'rpms': 'rpm',
73+
'modules': 'module',
74+
'container': 'container',
75+
}
76+
if namespace not in namespace_to_pdc:
77+
raise ValueError('The namespace "{0}" is not supported'
78+
.format(namespace))
79+
else:
80+
return namespace_to_pdc[namespace]
81+
82+
@staticmethod
83+
def _pdc_to_namespace(pdc_type):
84+
pdc_to_namespace = {
85+
'rpm': 'rpms',
86+
'module': 'modules',
87+
'container': 'container',
88+
}
89+
if pdc_type not in pdc_to_namespace:
90+
raise ValueError('The PDC type "{0}" is not supported'
91+
.format(pdc_type))
92+
else:
93+
return pdc_to_namespace[pdc_type]
94+
95+
@staticmethod
96+
def _is_retired_in_cgit(namespace, repo, branch, requests_session=None):
97+
if requests_session is None:
98+
requests_session = requests.Session()
99+
100+
cgit_url = 'https://src.fedoraproject.org/cgit'
101+
# Check to see if they have a dead.package file in dist-git
102+
url = '{base}/{namespace}/{repo}.git/plain/dead.package?h={branch}'
103+
response = requests_session.head(url.format(
104+
base=cgit_url,
105+
namespace=namespace,
106+
repo=repo,
107+
branch=branch,
108+
))
109+
110+
# If there is a dead.package, then the branch is retired in cgit
111+
if response.status_code in [200, 404]:
112+
return response.status_code == 200
113+
else:
114+
raise ValueError(
115+
'The connection to cgit failed. Retirement status could not '
116+
'be determined. The status code was: {0}. The content was: '
117+
'{1}'.format(response.status_code, response.content))
118+
119+
def audit(self, pdc):
120+
""" Returns the difference in retirement status in PDC and dist-git.
121+
122+
This function compares the status in PDC and the status in the
123+
"real world" (i.e., in dist-git) and return the difference.
124+
"""
125+
branches_retired_in_distgit = set()
126+
branches_retired_in_pdc = set()
127+
session = requests.Session()
128+
129+
log.info('Looking up all branches from PDC.')
130+
for branch in pdc.get_paged(pdc['component-branches']._):
131+
branch_str = '{type}/{global_component}#{name}'.format(**branch)
132+
log.debug('Considering {0}'.format(branch_str))
133+
retired_in_cgit = self._is_retired_in_cgit(
134+
namespace=self._pdc_to_namespace(branch['type']),
135+
repo=branch['global_component'],
136+
branch=branch['name'],
137+
requests_session=session
138+
)
139+
140+
if retired_in_cgit:
141+
branches_retired_in_distgit.add(branch_str)
142+
if not branch['active']:
143+
branches_retired_in_pdc.add(branch_str)
144+
145+
present = branches_retired_in_pdc - branches_retired_in_distgit
146+
absent = branches_retired_in_distgit - branches_retired_in_pdc
147+
148+
return present, absent
149+
150+
def initialize(self, pdc):
151+
""" Initialize PDC retirement status from analyzing dist-git.
152+
153+
This steps over all the branches in dist-git and retires any branches
154+
in PDC that have a dead.package file in dist-git.
155+
"""
156+
session = requests.Session()
157+
158+
# Look up all non-retired branches from PDC
159+
log.info('Looking up active branches from PDC.')
160+
161+
for branch in pdc.get_paged(pdc['component-branches']._, active=True):
162+
log.debug('Considering {type}/{global_component}#{name}'
163+
.format(**branch))
164+
retired_in_cgit = self._is_retired_in_cgit(
165+
namespace=self._pdc_to_namespace(branch['type']),
166+
repo=branch['global_component'],
167+
branch=branch['name'],
168+
requests_session=session
169+
)
170+
171+
if retired_in_cgit:
172+
self._retire_branch(pdc, branch)

0 commit comments

Comments
 (0)