def test_on_present_rollback(self): lbaas_spec = mock.sentinel.lbaas_spec lbaas_spec.type = 'ClusterIp' lbaas_spec.lb_ip = '1.2.3.4' lbaas_spec.project_id = '12345678' lbaas_state = mock.sentinel.lbaas_state lbaas_state.service_pub_ip_info = None loadbalancer = mock.Mock() loadbalancer.port_id = 12345678 lbaas_state.loadbalancer = loadbalancer m_drv_service_pub_ip = mock.Mock() m_drv_service_pub_ip.acquire_service_pub_ip_info.return_value = None m_drv_service_pub_ip.associate_pub_ip.return_value = True endpoints = mock.sentinel.endpoints m_handler = mock.Mock(spec=h_lbaas.LoadBalancerHandler) m_handler._get_lbaas_spec.return_value = lbaas_spec m_handler._should_ignore.return_value = False m_handler._get_lbaas_state.return_value = lbaas_state m_handler._sync_lbaas_members.return_value = True m_handler._set_lbaas_state.side_effect = ( k_exc.K8sResourceNotFound('ep')) m_handler._drv_service_pub_ip = m_drv_service_pub_ip h_lbaas.LoadBalancerHandler.on_present(m_handler, endpoints) m_handler._get_lbaas_spec.assert_called_once_with(endpoints) m_handler._should_ignore.assert_called_once_with(endpoints, lbaas_spec) m_handler._get_lbaas_state.assert_called_once_with(endpoints) m_handler._sync_lbaas_members.assert_called_once_with( endpoints, lbaas_state, lbaas_spec) m_handler._set_lbaas_state.assert_called_once_with( endpoints, lbaas_state) m_handler.on_deleted.assert_called_once_with( endpoints, lbaas_state)
def annotate(self, path, annotations, resource_version=None): """Pushes a resource annotation to the K8s API resource The annotate operation is made with a PATCH HTTP request of kind: application/merge-patch+json as described in: https://github.com/kubernetes/community/blob/master/contributors/devel/api-conventions.md#patch-operations # noqa """ LOG.debug("Annotate %(path)s: %(names)s", { 'path': path, 'names': list(annotations) }) content_type = 'application/merge-patch+json' url, header = self._get_url_and_header(path, content_type) while itertools.count(1): metadata = {"annotations": annotations} if resource_version: metadata['resourceVersion'] = resource_version data = jsonutils.dumps({"metadata": metadata}, sort_keys=True) response = requests.patch(url, data=data, headers=header, cert=self.cert, verify=self.verify_server) if response.ok: return response.json()['metadata']['annotations'] if response.status_code == requests.codes.conflict: resource = self.get(path) new_version = resource['metadata']['resourceVersion'] retrieved_annotations = resource['metadata'].get( 'annotations', {}) for k, v in annotations.items(): if v != retrieved_annotations.get(k, v): break else: # No conflicting annotations found. Retry patching resource_version = new_version continue LOG.debug( "Annotations for %(path)s already present: " "%(names)s", { 'path': path, 'names': retrieved_annotations }) LOG.error( "Exception response, headers: %(headers)s, " "content: %(content)s, text: %(text)s" % { 'headers': response.headers, 'content': response.content, 'text': response.text }) if response.status_code == requests.codes.not_found: raise exc.K8sResourceNotFound(response.text) else: raise exc.K8sClientException(response.text)
def test_get_vifs_pod_not_found(self, ged, k8s): ged.return_value = [self._driver] kp = kuryrport.KuryrPortHandler() kp.k8s.get.side_effect = k_exc.K8sResourceNotFound(self._pod) self.assertRaises(k_exc.K8sResourceNotFound, kp.get_vifs, self._kp) kp.k8s.get.assert_called_once_with(self._pod_uri) kp.k8s.remove_finalizer.assert_called_once_with( self._kp, constants.KURYRPORT_FINALIZER)
def _raise_from_response(self, response): if response.status_code == requests.codes.not_found: raise exc.K8sResourceNotFound(response.text) if response.status_code == requests.codes.conflict: raise exc.K8sConflict(response.text) if response.status_code == requests.codes.forbidden: if 'because it is being terminated' in response.json()['message']: raise exc.K8sNamespaceTerminating(response.text) raise exc.K8sForbidden(response.text) if not response.ok: raise exc.K8sClientException(response.text)
def test_get_namespace_not_found(self): namespace_name = mock.sentinel.namespace_name kubernetes = self.useFixture(k_fix.MockK8sClient()).client kubernetes.get.side_effect = exceptions.K8sResourceNotFound( mock.sentinel.resource) resp = utils.get_namespace(namespace_name) self.assertIsNone(resp) kubernetes.get.assert_called_once_with('{}/namespaces/{}'.format( constants.K8S_API_BASE, namespace_name))
def test_on_present_pod_not_found(self, ged, get_k8s_client, activate_vif): ged.return_value = [self._driver] kp = kuryrport.KuryrPortHandler() self._kp['status']['vifs'] = self._vifs_primitive with mock.patch.object(kp, 'k8s') as k8s: k8s.get.side_effect = k_exc.K8sResourceNotFound(self._pod) self.assertRaises(k_exc.K8sResourceNotFound, kp.on_present, self._kp) k8s.get.assert_called_once_with(self._pod_uri)
def test_on_finalize_crd_not_found(self): self._handler.k8s.get.return_value = self._kp (self._handler.k8s.delete.side_effect) = k_exc.K8sResourceNotFound( self._pod) h_vif.VIFHandler.on_finalize(self._handler, self._pod) self._handler.k8s.delete.assert_called_once_with( h_vif.KURYRPORT_URI.format(ns=self._pod["metadata"]["namespace"], crd=self._pod["metadata"]["name"])) (self._handler.k8s.remove_finalizer.assert_called_once_with( self._pod, k_const.POD_FINALIZER))
def test_on_finalize_exception_on_pod(self, ged, k8s): ged.return_value = [self._driver] kp = kuryrport.KuryrPortHandler() self._kp['status']['vifs'] = self._vifs_primitive with mock.patch.object(kp, 'k8s') as k8s: k8s.get.side_effect = k_exc.K8sResourceNotFound(self._pod) self.assertIsNone(kp.on_finalize(self._kp)) k8s.get.assert_called_once_with(self._pod_uri) k8s.remove_finalizer.assert_called_once_with( self._kp, constants.KURYRPORT_FINALIZER)
def test_call_outdated_event(self, m_sleep, m_count): m_handler = mock.Mock() m_count.return_value = list(range(1, 5)) obj = {'metadata': {'selfLink': mock.sentinel.selflink}} event = {'type': 'MODIFIED', 'object': obj} self.k8s.get.side_effect = exceptions.K8sResourceNotFound(obj) retry = h_retry.Retry(m_handler) retry(event) self.k8s.get.assert_called_once_with(obj['metadata']['selfLink']) m_handler.assert_not_called() m_sleep.assert_not_called()
def test_on_finalize_crd_not_found(self, m_get_kuryrport, m_get_k8s_client): m_get_kuryrport.return_value = self._kp k8s = mock.MagicMock() m_get_k8s_client.return_value = k8s k8s.delete.side_effect = k_exc.K8sResourceNotFound(self._pod) h_vif.VIFHandler.on_finalize(self._handler, self._pod) k8s.delete.assert_called_once_with( h_vif.KURYRPORT_URI.format(ns=self._pod["metadata"]["namespace"], crd=self._pod["metadata"]["name"])) (k8s.remove_finalizer.assert_called_once_with(self._pod, k_const.POD_FINALIZER))
def delete(self, path): LOG.debug("Delete %(path)s", {'path': path}) url = self._base_url + path header = {'Content-Type': 'application/json'} if self.token: header.update({'Authorization': 'Bearer %s' % self.token}) response = self.session.delete(url, cert=self.cert, verify=self.verify_server, headers=header) if response.ok: return response.json() else: if response.status_code == requests.codes.not_found: raise exc.K8sResourceNotFound(response.text) raise exc.K8sClientException(response)
def test_on_present_fail_update_crd(self, ged, get_k8s_client, activate_vif, update_crd, get_project, get_sg, release_vif): ged.return_value = [self._driver] kp = kuryrport.KuryrPortHandler() self._kp['status']['vifs'] = self._vifs_primitive update_crd.side_effect = k_exc.K8sResourceNotFound(self._kp) get_project.return_value = self._project_id get_sg.return_value = self._security_groups with mock.patch.object(kp, 'k8s') as k8s: k8s.get.return_value = self._pod kp.on_present(self._kp) k8s.get.assert_called_once_with(self._pod_uri)
def test_call_outdated_event(self, m_sleep, m_count): m_handler = mock.Mock() m_count.return_value = list(range(1, 5)) self_link = '/api/v1/namespaces/ns1/services/srv1' obj = {'apiVersion': 'v1', 'kind': 'Service', 'metadata': {'name': 'srv1', 'namespace': 'ns1'}} event = {'type': 'MODIFIED', 'object': obj} self.k8s.get.side_effect = exceptions.K8sResourceNotFound(obj) retry = h_retry.Retry(m_handler) retry(event) self.k8s.get.assert_called_once_with(self_link) m_handler.assert_not_called() m_sleep.assert_not_called()
def get(self, path, json=True, headers=None): LOG.debug("Get %(path)s", {'path': path}) url = self._base_url + path header = {} if self.token: header.update({'Authorization': 'Bearer %s' % self.token}) if headers: header.update(headers) response = self.session.get(url, cert=self.cert, verify=self.verify_server, headers=header) if response.status_code == requests.codes.not_found: raise exc.K8sResourceNotFound(response.text) if not response.ok: raise exc.K8sClientException(response.text) result = response.json() if json else response.text return result
def _raise_from_response(self, response): if response.status_code == requests.codes.not_found: raise exc.K8sResourceNotFound(response.text) if response.status_code == requests.codes.conflict: raise exc.K8sConflict(response.text) if response.status_code == requests.codes.forbidden: if 'because it is being terminated' in response.json()['message']: raise exc.K8sNamespaceTerminating(response.text) raise exc.K8sForbidden(response.text) if response.status_code == requests.codes.unprocessable_entity: # NOTE(gryf): on k8s API code 422 is also Forbidden, but specified # to FieldValueForbidden. Perhaps there are other usages for # throwing unprocessable entity errors in different cases. if ('FieldValueForbidden' in response.text and 'Forbidden' in response.json()['message']): raise exc.K8sFieldValueForbidden(response.text) raise exc.K8sUnprocessableEntity(response.text) if not response.ok: raise exc.K8sClientException(response.text)
def test_bump_nps(self, get_client): m_k8s = mock.Mock() get_client.return_value = m_k8s m_k8s.get.return_value = { 'items': [ {'metadata': {'annotations': { 'networkPolicyLink': mock.sentinel.link1}}}, {'metadata': {'annotations': { 'networkPolicyLink': mock.sentinel.link2}}}, {'metadata': {'annotations': { 'networkPolicyLink': mock.sentinel.link3}}}, ] } m_k8s.annotate.side_effect = ( None, exceptions.K8sResourceNotFound('NP'), None) self.handler._bump_nps() m_k8s.get.assert_called_once_with( constants.K8S_API_CRD_KURYRNETWORKPOLICIES) m_k8s.annotate.assert_has_calls([ mock.call(mock.sentinel.link1, mock.ANY), mock.call(mock.sentinel.link2, mock.ANY), mock.call(mock.sentinel.link3, mock.ANY), ])
def test_on_present_rollback(self): lbaas_spec = mock.sentinel.lbaas_spec lbaas_state = mock.sentinel.lbaas_state endpoints = mock.sentinel.endpoints m_handler = mock.Mock(spec=h_lbaas.LoadBalancerHandler) m_handler._get_lbaas_spec.return_value = lbaas_spec m_handler._should_ignore.return_value = False m_handler._get_lbaas_state.return_value = lbaas_state m_handler._sync_lbaas_members.return_value = True m_handler._set_lbaas_state.side_effect = ( k_exc.K8sResourceNotFound('ep')) h_lbaas.LoadBalancerHandler.on_present(m_handler, endpoints) m_handler._get_lbaas_spec.assert_called_once_with(endpoints) m_handler._should_ignore.assert_called_once_with(endpoints, lbaas_spec) m_handler._get_lbaas_state.assert_called_once_with(endpoints) m_handler._sync_lbaas_members.assert_called_once_with( endpoints, lbaas_state, lbaas_spec) m_handler._set_lbaas_state.assert_called_once_with( endpoints, lbaas_state) m_handler.on_deleted.assert_called_once_with(endpoints, lbaas_state)
def test__remove_endpoints_not_found(self, log): m_handler = mock.Mock() m_handler.k8s.patch_crd.side_effect = k_exc.K8sResourceNotFound('foo') h_lbaas.EndpointsHandler._remove_endpoints(m_handler, self._ep) log.assert_called_once()
def _raise_from_response(self, response): if response.status_code == requests.codes.not_found: raise exc.K8sResourceNotFound(response.text) if not response.ok: raise exc.K8sClientException(response.text)