def _validate_shared_net_resource(action, body=None): """Validate keys in outgoing shared network request""" if body: body_set = set(body.keys()) else: return if 'vm-network' in action and 'port' not in action: vmnetwork_set = set(_resource_metadata['vmnetwork']) if body_set - vmnetwork_set: raise c_exc.VSMError(reason='Invalid Request') elif 'port' in action: port_set = set(_resource_metadata['port']) if body_set - port_set: raise c_exc.VSMError(reason='Invalid Request') elif 'subnet' in action: subnet_set = set(_resource_metadata['subnet']) if body_set - subnet_set: raise c_exc.VSMError(reason='Invalid Request') elif '/network-segment/' in action: network_set = set(_resource_metadata['network-segment']) if body_set - network_set: raise c_exc.VSMError(reason='Invalid Request') if body['tenantId'] != '0': raise c_exc.VSMError(reason='Invalid Shared Network Handling') else: return
def _do_request(self, method, action, body=None, headers=None, vsm_ip=None): """Handle outgoing requestes based on type""" if self.broken: raise c_exc.VSMError(reason='VSM:Internal Server Error') if self.inject_params and body: body['invalidKey'] = 'catchMeIfYouCan' if method == 'POST' and self.shared_net: return _validate_shared_net_resource(action, body) # For update to shared network cases, set to shared after net create elif (method == 'POST' and self.upd_shared_net and '/network-segment/' in action): ret = _validate_resource(action, body) self.shared_net = True return ret elif method == 'POST': return _validate_resource(action, body) elif method == 'GET': if 'virtual-port-profile' in action: return _policy_profile_generator(self._get_total_profiles()) else: raise c_exc.VSMError(reason='VSM:Internal Server Error')
def _do_request(self, method, action, body=None, headers=None, vsm_ip=None): """Perform the HTTP request. The response is in either JSON format or plain text. A GET method will invoke a JSON response while a PUT/POST/DELETE returns message from the VSM in plain text format. Exception is raised when VSM replies with an INTERNAL SERVER ERROR HTTP status code (500) i.e. an error has occurred on the VSM or SERVICE UNAVAILABLE (404) i.e. VSM is not reachable. :param method: type of the HTTP request. POST, GET, PUT or DELETE :param action: path to which the client makes request :param body: dict for arguments which are sent as part of the request :param headers: header for the HTTP request :param vsm_ip: vsm_ip for the HTTP request. If not provided then request will be sent to all VSMs. :returns: JSON or plain text in HTTP response """ action = self.action_prefix + action if body: body = jsonutils.dumps(body) LOG.debug("req: %s", body) hosts = [] if vsm_ip: hosts.append(vsm_ip) else: hosts = self.get_vsm_hosts() if not headers: headers = self._get_auth_header() headers['Content-Type'] = headers['Accept'] = "application/json" for vsm_ip in hosts: vsm_action = action % vsm_ip try: resp = self.pool.spawn(requests.request, method, url=vsm_action, data=body, headers=headers, timeout=self.timeout).wait() except Exception as e: raise n1kv_exc.VSMConnectionFailed(reason=e) if resp.status_code != requests.codes.OK: raise n1kv_exc.VSMError(reason=resp.text) if 'application/json' in resp.headers['content-type']: try: return resp.json() except ValueError: return {} elif 'text/plain' in resp.headers['content-type']: LOG.info(_LI("VSM: %s"), resp.text)
def _validate_resource(action, body=None): """Validate expected keys are present in outgoing request""" if body: body_set = set(body.keys()) else: return if 'vm-network' in action and 'port' not in action: vmnetwork_set = set(_resource_metadata['vmnetwork']) if body_set - vmnetwork_set: raise c_exc.VSMError(reason='Invalid Request') elif '/network-segment/' in action: network_set = set(_resource_metadata['network-segment']) if body_set - network_set: raise c_exc.VSMError(reason='Invalid Request') elif 'port' in action: port_set = set(_resource_metadata['port']) if body_set - port_set: raise c_exc.VSMError(reason='Invalid Request') elif 'subnet' in action: subnet_set = set(_resource_metadata['subnet']) if body_set - subnet_set: raise c_exc.VSMError(reason='Invalid Request') else: return
def test_create_network_profile_on_vsm_error(self): """Test a network profile creation when the operation fails on VSM.""" data = self.get_test_network_profile_dict(segment_type='vxlan', sub_type='enhanced') new_net_prof_name = data["network_profile"]["name"] mocked_ex = mock.MagicMock(side_effect=n1kv_exc.VSMError( reason='Internal VSM error')) with mock.patch( n1kv_client.__name__ + ".Client.create_network_segment_pool", mocked_ex): self.create_assert_network_profile_failure( data=data, expected_status=webob.exc.HTTPInternalServerError.code) # list all network profiles netprofs = self.list_resource(resource='network_profiles', tenant_id=self.admin_tenant) # assert that the network profile created is cleaned up on neutron # when creation on VSM fails self.assertNotIn( needle=new_net_prof_name, haystack=[d["name"] for d in netprofs["network_profiles"]])
def test_network_profile_create_on_vsm_error(self): """Test a network profile creation when the operation fails on VSM.""" data = self.get_test_network_profile_dict(segment_type='vxlan', sub_type='enhanced') new_net_prof_name = data["network_profile"]["name"] mocked_ex = mock.MagicMock(side_effect=n1kv_exc.VSMError( reason='Internal VSM error')) with mock.patch(n1kv_client.__name__ + ".Client.create_network_segment_pool", mocked_ex): network_req = self.new_create_request('network_profiles', data) res = network_req.get_response(self.ext_api) self.assertEqual(webob.exc.HTTPInternalServerError.code, res.status_int) # list all network profiles list_req = self.new_list_request('network_profiles') list_res = list_req.get_response(self.ext_api) netprofs = self.deserialize(self.fmt, list_res) # assert that the network profile created is cleaned up on neutron # when creation on VSM fails self.assertNotIn( needle=new_net_prof_name, haystack=[d["name"] for d in netprofs["network_profiles"]])
def _do_request(self, method, action, body=None, headers=None, vsm_ip=None): """Perform the HTTP request. The response is in either JSON format or plain text. A GET method will invoke a JSON response while a PUT/POST/DELETE returns message from the VSM in plain text format. Exception is raised when VSM replies with an INTERNAL SERVER ERROR HTTP status code (500) i.e. an error has occurred on the VSM or SERVICE UNAVAILABLE (404) i.e. VSM is not reachable. :param method: type of the HTTP request. POST, GET, PUT or DELETE :param action: path to which the client makes request :param body: dict for arguments which are sent as part of the request :param headers: header for the HTTP request :param vsm_ip: vsm_ip for the HTTP request. If not provided then request will be sent to all VSMs. :returns: JSON or plain text in HTTP response """ action = self.action_prefix + action if body: body = jsonutils.dumps(body) LOG.debug("req: %s", body) hosts = [] if vsm_ip: hosts.append(vsm_ip) else: hosts = self.vsm_ips if not headers: headers = self._get_auth_header() headers['Content-Type'] = headers['Accept'] = "application/json" for vsm_ip in hosts: if netutils.is_valid_ipv6(vsm_ip): # Enclose IPv6 address in [] in the URL vsm_action = action % ("[%s]" % vsm_ip) else: # IPv4 address vsm_action = action % vsm_ip for attempt in range(self.max_vsm_retries + 1): try: LOG.debug("[VSM %(vsm)s attempt %(id)s]: Connecting.." % { "vsm": vsm_ip, "id": attempt }) resp = self.pool.spawn(requests.request, method, url=vsm_action, data=body, headers=headers, timeout=self.timeout).wait() break except Exception as e: LOG.debug("[VSM %(vsm)s attempt %(id)s]: Conn timeout." % { "vsm": vsm_ip, "id": attempt }) if attempt == self.max_vsm_retries: LOG.error(_LE("VSM %s, Conn failed."), vsm_ip) raise n1kv_exc.VSMConnectionFailed(reason=e) if resp.status_code != requests.codes.OK: LOG.error(_LE("VSM %(vsm)s, Got error: %(err)s"), { "vsm": vsm_ip, "err": resp.text }) raise n1kv_exc.VSMError(reason=resp.text) if 'application/json' in resp.headers['content-type']: try: return resp.json() except ValueError: return {} elif 'text/plain' in resp.headers['content-type']: LOG.info(_LI("VSM: %s"), resp.text)