Fix CRD podSelector update

When the podSelector of a NP is updated, the podSelector
on the respective CRD must also be updated with the same
value. However, this do not happen in case the field of a label
is updated, for example: Label {'app: demo'} is updated to
{'context:demo'} the result given is {'app: demo', 'context:demo'}
when should be {'context:demo'}. And after that, if the updated label
{'context:demo'} is removed from the NP, it will not be removed from the CRD.
These cases happen because the podSelector field is a dict and not
a list.

This commit fixes the issue by changing the merge strategy to
JSON Patch, instead of JSON Merge Patch.

Change-Id: Ic629c1ba4ac13c2bfaffdf7f904b69abf9521ed3
Closes-Bug: 1810394
This commit is contained in:
Maysa Macedo 2019-02-13 10:45:37 +00:00
parent 5a93e919ec
commit 5cf4b41772
3 changed files with 31 additions and 10 deletions

View File

@ -225,11 +225,11 @@ def patch_kuryr_crd(crd, i_rules, e_rules, pod_selector, np_spec=None):
np_spec = crd['spec']['networkpolicy_spec'] np_spec = crd['spec']['networkpolicy_spec']
LOG.debug('Patching KuryrNetPolicy CRD %s' % crd_name) LOG.debug('Patching KuryrNetPolicy CRD %s' % crd_name)
try: try:
kubernetes.patch('spec', crd['metadata']['selfLink'], kubernetes.patch_crd('spec', crd['metadata']['selfLink'],
{'ingressSgRules': i_rules, {'ingressSgRules': i_rules,
'egressSgRules': e_rules, 'egressSgRules': e_rules,
'podSelector': pod_selector, 'podSelector': pod_selector,
'networkpolicy_spec': np_spec}) 'networkpolicy_spec': np_spec})
except k_exc.K8sClientException: except k_exc.K8sClientException:
LOG.exception('Error updating kuryrnetpolicy CRD %s', crd_name) LOG.exception('Error updating kuryrnetpolicy CRD %s', crd_name)
raise raise

View File

@ -83,9 +83,9 @@ class K8sClient(object):
result = response.json() if json else response.text result = response.json() if json else response.text
return result return result
def _get_url_and_header(self, path): def _get_url_and_header(self, path, content_type):
url = self._base_url + path url = self._base_url + path
header = {'Content-Type': 'application/merge-patch+json', header = {'Content-Type': content_type,
'Accept': 'application/json'} 'Accept': 'application/json'}
if self.token: if self.token:
header.update({'Authorization': 'Bearer %s' % self.token}) header.update({'Authorization': 'Bearer %s' % self.token})
@ -97,7 +97,8 @@ class K8sClient(object):
'path': path, 'data': data}) 'path': path, 'data': data})
if field == 'status': if field == 'status':
path = path + '/' + str(field) path = path + '/' + str(field)
url, header = self._get_url_and_header(path) content_type = 'application/merge-patch+json'
url, header = self._get_url_and_header(path, content_type)
response = requests.patch(url, json={field: data}, response = requests.patch(url, json={field: data},
headers=header, cert=self.cert, headers=header, cert=self.cert,
verify=self.verify_server) verify=self.verify_server)
@ -105,6 +106,25 @@ class K8sClient(object):
return response.json().get('status') return response.json().get('status')
raise exc.K8sClientException(response.text) raise exc.K8sClientException(response.text)
def patch_crd(self, field, path, data):
content_type = 'application/json-patch+json'
url, header = self._get_url_and_header(path, content_type)
data = [{'op': 'replace',
'path': '/{}/{}'.format(field, np_field),
'value': value}
for np_field, value in data.items()]
LOG.debug("Patch %(path)s: %(data)s", {
'path': path, 'data': data})
response = requests.patch(url, data=jsonutils.dumps(data),
headers=header, cert=self.cert,
verify=self.verify_server)
if response.ok:
return response.json().get('status')
raise exc.K8sClientException(response.text)
def post(self, path, body): def post(self, path, body):
LOG.debug("Post %(path)s: %(body)s", {'path': path, 'body': body}) LOG.debug("Post %(path)s: %(body)s", {'path': path, 'body': body})
url = self._base_url + path url = self._base_url + path
@ -142,7 +162,8 @@ class K8sClient(object):
LOG.debug("Annotate %(path)s: %(names)s", { LOG.debug("Annotate %(path)s: %(names)s", {
'path': path, 'names': list(annotations)}) 'path': path, 'names': list(annotations)})
url, header = self._get_url_and_header(path) content_type = 'application/merge-patch+json'
url, header = self._get_url_and_header(path, content_type)
while itertools.count(1): while itertools.count(1):
metadata = {"annotations": annotations} metadata = {"annotations": annotations}

View File

@ -293,7 +293,7 @@ class TestNetworkPolicyDriver(test_base.TestCase):
'parse_network_policy_rules') 'parse_network_policy_rules')
def test_update_security_group_rules_with_k8s_exc(self, m_parse, m_get_crd, def test_update_security_group_rules_with_k8s_exc(self, m_parse, m_get_crd,
m_create_sgr): m_create_sgr):
self._driver.kubernetes.patch.side_effect = ( self._driver.kubernetes.patch_crd.side_effect = (
exceptions.K8sClientException()) exceptions.K8sClientException())
m_get_crd.return_value = self._crd m_get_crd.return_value = self._crd
m_parse.return_value = (self._i_rules, self._e_rules) m_parse.return_value = (self._i_rules, self._e_rules)