def create_firewall(self, context, firewall, host): """Handle Rpc from plugin to create a firewall.""" router_ids = self._get_router_ids_for_fw(context, firewall) if not router_ids: return router_info_list = self._get_router_info_list_for_tenant( router_ids, firewall['tenant_id']) LOG.debug("Create: Add firewall on Router List: '%s'", [ri.router['id'] for ri in router_info_list]) # call into the driver try: self.fwaas_driver.create_firewall(self.conf.agent_mode, router_info_list, firewall) if firewall['admin_state_up']: status = nl_constants.ACTIVE else: status = nl_constants.DOWN except fw_ext.FirewallInternalDriverError: LOG.error( _LE("Firewall Driver Error for create_firewall " "for firewall: %(fwid)s"), {'fwid': firewall['id']}) status = nl_constants.ERROR try: # send status back to plugin self.fwplugin_rpc.set_firewall_status(context, firewall['id'], status) except Exception: LOG.exception( _LE("FWaaS RPC failure in create_firewall " "for firewall: %(fwid)s"), {'fwid': firewall['id']}) self.services_sync_needed = True
def get(self, path, etag=None, raw=False): json_result = None etag_out = None headers = {'accept': 'application/json', 'content-type': 'application/json'} if etag: headers['ETag'] = etag try: result = self.session_op("get", path, raw, headers=headers) if 'etag' in result.headers: etag_out = result.headers['etag'] json_result = result.json() if result.status_code == "404": LOG.error(_LE("%(msg)s %(detail)s"), {'msg': json_result["message"], 'detail': json_result["details"]}) except Exception: LOG.error(_LE("exception when GET operation")) raise r = [json_result] if etag_out: r.append(etag_out) return [json_result]
def get(self, path, etag=None, raw=False): json_result = None etag_out = None headers = { 'accept': 'application/json', 'content-type': 'application/json' } if etag: headers['ETag'] = etag try: result = self.session_op("get", path, raw, headers=headers) if 'etag' in result.headers: etag_out = result.headers['etag'] json_result = result.json() if result.status_code == "404": LOG.error( _LE("%(msg)s %(detail)s"), { 'msg': json_result["message"], 'detail': json_result["details"] }) except Exception: LOG.error(_LE("exception when GET operation")) raise r = [json_result] if etag_out: r.append(etag_out) return [json_result]
def _validate_firewall_rule_data(self, firewall): if 'firewall_rule_list' not in firewall: LOG.error(_LE("no rule list")) return False for rule in firewall['firewall_rule_list']: if 'name' not in rule: LOG.error(_LE("CsrAcl: no rule name")) return False ip_version = rule.get('ip_version') if ip_version != 4: LOG.error( _LE("invalid ip version %(ip_version)s in " "rule %(rule)s"), { 'ip_version': ip_version, 'rule': rule['name'] }) return False if 'protocol' not in rule: LOG.error(_LE("no protocol in rule [%s]"), rule['name']) return False if rule.get('action', '').lower() not in ('allow', 'deny'): LOG.error(_LE("invalid action in rule [%s]"), rule['name']) return False return True
def delete_firewall_group(self, context, firewall_group, host): """Handles RPC from plugin to delete a firewall group. """ ports_for_fwg = self._get_firewall_group_ports(context, firewall_group, to_delete=True) if not ports_for_fwg: return fw_ports = [p for ri_ports in ports_for_fwg for p in ri_ports[1]] LOG.debug("Delete firewall group %(fwg_id)s on ports: %(ports)s" % { 'fwg_id': firewall_group['id'], 'ports': ', '.join(fw_ports) }) # Set the firewall group's status to return to plugin; status may be # overwritten if call to driver fails. if firewall_group['admin_state_up']: status = n_const.ACTIVE else: status = n_const.DOWN try: self.fwaas_driver.delete_firewall_group(self.conf.agent_mode, ports_for_fwg, firewall_group) # Call the driver. except fw_ext.FirewallInternalDriverError: LOG.exception( _LE("FWaaS driver error in delete_firewall_group " "for firewall group: %(fwg_id)s"), {'fwg_id': firewall_group['id']}) status = n_const.ERROR # Notify plugin of deletion or return firewall group's status to # plugin, as appopriate. try: if status in [n_const.ACTIVE, n_const.DOWN]: self.fwplugin_rpc.firewall_group_deleted( context, firewall_group['id']) else: self.fwplugin_rpc.set_firewall_group_status( context, firewall_group['id'], status) except Exception: LOG.exception( _LE("FWaaS RPC failure in delete_firewall_group " "for firewall group: %(fwg_id)s"), {'fwg_id': firewall_group['id']}) self.services_sync_needed = True
def _invoke_driver_for_sync_from_plugin(self, ctx, port, firewall_group): """Calls the FWaaS driver's delete_firewall_group method if firewall group has status of PENDING_DELETE; calls driver's update_firewall_group method for all other statuses. Both of these methods are idempotent. """ port_list = self._get_in_ns_ports([port['id']]) if firewall_group['status'] == nl_constants.PENDING_DELETE: try: self.fwaas_driver.delete_firewall_group( self.conf.agent_mode, port_list, firewall_group) self.fwplugin_rpc.firewall_group_deleted( ctx, firewall_group['id']) except fw_ext.FirewallInternalDriverError: msg = _LE("FWaaS driver error on %(status)s " "for firewall group: %(fwg_id)s") LOG.exception( msg, { 'status': firewall_group['status'], 'fwg_id': firewall_group['id'] }) self.fwplugin_rpc.set_firewall_group_status( ctx, firewall_group['id'], nl_constants.ERROR) else: # PENDING_UPDATE, PENDING_CREATE, ... # Prepare firewall group status to return to plugin; may be # overwritten if call to driver fails. if firewall_group['admin_state_up']: status = nl_constants.ACTIVE else: status = nl_constants.DOWN # Call the driver. try: self.fwaas_driver.update_firewall_group( self.conf.agent_mode, port_list, firewall_group) except fw_ext.FirewallInternalDriverError: msg = _LE("FWaaS driver error on %(status)s for firewall " "group: " "%(fwg_id)s") LOG.exception( msg, { 'status': firewall_group['status'], 'fwg_id': firewall_group['id'] }) status = nl_constants.ERROR # Notify the plugin of firewall group's status. self.fwplugin_rpc.set_firewall_group_status( ctx, firewall_group['id'], status)
def process_services_sync(self, ctx): """Syncs with plugin and applies the sync data. """ if not self.services_sync_needed or not self.fwaas_enabled: return try: # Fetch from the plugin the list of projects with firewall groups. project_ids = \ self.fwplugin_rpc.get_projects_with_firewall_groups(ctx) LOG.debug("Projects with firewall groups: %s", ', '.join(project_ids)) for project_id in project_ids: ctx = context.Context('', project_id) fwg_list = \ self.fwplugin_rpc.get_firewall_groups_for_project(ctx) for firewall_group in fwg_list: if firewall_group['status'] == n_const.PENDING_DELETE: self.delete_firewall_group(ctx, firewall_group, self.host) # No need to apply sync data for ACTIVE firewall group. elif firewall_group['status'] != n_const.ACTIVE: self.update_firewall_group(ctx, firewall_group, self.host) self.services_sync_needed = False except Exception: LOG.exception(_LE("Failed FWaaS process services sync.")) self.services_sync_needed = True
def _process_event_q(self): while True: try: event_data = self.event_q.dequeue(CSR_FW_EVENT_Q_NAME) if not event_data: return except ValueError: LOG.debug("_process_event_q: no queue yet") return LOG.debug("_process_event_q: event_data %s", event_data) event = event_data['event'] context = event_data['context'] firewall = event_data['firewall'] if event == CSR_FW_EVENT_CREATE: self._invoke_firewall_driver(context, firewall, 'create_firewall') elif event == CSR_FW_EVENT_UPDATE: self._invoke_firewall_driver(context, firewall, 'update_firewall') elif event == CSR_FW_EVENT_DELETE: self._invoke_firewall_driver(context, firewall, 'delete_firewall') else: LOG.error(_LE("invalid event %s"), event)
def apply_default_policy(self, agent_mode, apply_list, firewall): LOG.debug('Applying firewall %(fw_id)s for tenant %(tid)s', {'fw_id': firewall['id'], 'tid': firewall['tenant_id']}) fwid = firewall['id'] try: for router_info in apply_list: ipt_if_prefix_list = self._get_ipt_mgrs_with_if_prefix( agent_mode, router_info) for ipt_if_prefix in ipt_if_prefix_list: # the following only updates local memory; no hole in FW ipt_mgr = ipt_if_prefix['ipt'] self._remove_chains(fwid, ipt_mgr) self._remove_default_chains(ipt_mgr) # create default 'DROP ALL' policy chain self._add_default_policy_chain_v4v6(ipt_mgr) self._enable_policy_chain(fwid, ipt_if_prefix) # apply the changes immediately (no defer in firewall path) ipt_mgr.defer_apply_off() except (LookupError, RuntimeError): # catch known library exceptions and raise Fwaas generic exception LOG.exception( _LE("Failed to apply default policy on firewall: %s"), fwid) raise fw_ext.FirewallInternalDriverError(driver=FWAAS_DRIVER_NAME)
def _post_acl(self, csr, acl_data): response = csr.post_request(ACL_API, acl_data) if csr.status == requests.codes.CREATED: return response[response.rfind('/') + 1:] LOG.error(_LE("status %s"), csr.status) return ''
def _process_event_q(self): while True: try: event_data = self.event_q.dequeue(CSR_FW_EVENT_Q_NAME) if not event_data: return except ValueError: LOG.debug("_process_event_q: no queue yet") return LOG.debug("_process_event_q: event_data %s", event_data) event = event_data['event'] context = event_data['context'] firewall = event_data['firewall'] if event == CSR_FW_EVENT_CREATE: self._invoke_firewall_driver( context, firewall, 'create_firewall') elif event == CSR_FW_EVENT_UPDATE: self._invoke_firewall_driver( context, firewall, 'update_firewall') elif event == CSR_FW_EVENT_DELETE: self._invoke_firewall_driver( context, firewall, 'delete_firewall') else: LOG.error(_LE("invalid event %s"), event)
def _post_acl_to_interfaces(self, firewall, csr, acl_id, status_data): acl_interface_url = ACL_API_ACLID_IF % acl_id for firewall_interface in firewall['vendor_ext']['if_list']: if_name = self._get_interface_name_from_hosting_port( firewall_interface['port']) acl_interface_req = { 'if-id': if_name, 'direction': firewall_interface['direction'] } LOG.debug("acl_interface_url %s", acl_interface_url) csr.post_request(acl_interface_url, acl_interface_req) if csr.status == requests.codes.CREATED: status_data['if_list'].append({ 'port_id': firewall_interface['port']['id'], 'status': 'OK' }) else: LOG.error(_LE("status %s"), csr.status) status_data['if_list'].append({ 'port_id': firewall_interface['port']['id'], 'status': 'ERROR' })
def process_services_sync(self, ctx): if not self.services_sync_needed: return """On RPC issues sync with plugin and apply the sync data.""" # avoid msg to plugin when fwaas is not configured if not self.fwaas_enabled: return try: # get the list of tenants with firewalls configured # from the plugin tenant_ids = self.fwplugin_rpc.get_tenants_with_firewalls(ctx) LOG.debug("Tenants with Firewalls: '%s'", tenant_ids) for tenant_id in tenant_ids: ctx = context.Context('', tenant_id) fw_list = self.fwplugin_rpc.get_firewalls_for_tenant(ctx) for fw in fw_list: if fw['status'] == n_const.PENDING_DELETE: self.delete_firewall(ctx, fw, self.host) # no need to apply sync data for ACTIVE fw elif fw['status'] != n_const.ACTIVE: self.update_firewall(ctx, fw, self.host) self.services_sync_needed = False except Exception: LOG.exception(_LE("Failed fwaas process services sync")) self.services_sync_needed = True
def process_services_sync(self, ctx): if not self.services_sync_needed: return """On RPC issues sync with plugin and apply the sync data.""" # avoid msg to plugin when fwaas is not configured if not self.fwaas_enabled: return try: # get the list of tenants with firewalls configured # from the plugin tenant_ids = self.fwplugin_rpc.get_tenants_with_firewalls(ctx) LOG.debug("Tenants with Firewalls: '%s'", tenant_ids) for tenant_id in tenant_ids: ctx = context.Context('', tenant_id) fw_list = self.fwplugin_rpc.get_firewalls_for_tenant(ctx) for fw in fw_list: if fw['status'] == nl_constants.PENDING_DELETE: self.delete_firewall(ctx, fw, self.host) # no need to apply sync data for ACTIVE fw elif fw['status'] != nl_constants.ACTIVE: self.update_firewall(ctx, fw, self.host) self.services_sync_needed = False except Exception: LOG.exception(_LE("Failed fwaas process services sync")) self.services_sync_needed = True
def _post_acl(self, csr, acl_data): response = csr.post_request(ACL_API, acl_data) if csr.status == requests.codes.CREATED: return response[response.rfind('/') + 1:] LOG.error(_LE("status %s"), csr.status) return ''
def _get_acl_interface(self, csr, acl_id): my_api = ACL_API_ACLID_IF % acl_id response = csr.get_request(my_api) if csr.status == requests.codes.OK: return response['items'] LOG.error(_LE("status %s"), csr.status) return ''
def _put_acl(self, csr, acl_id, acl_data): my_api = ACL_API_ACLID % acl_id csr.put_request(my_api, acl_data) if csr.status == requests.codes.NO_CONTENT: return True LOG.error(_LE("status %s"), csr.status) return False
def _delete_acl(self, csr, acl_id): my_api = ACL_API_ACLID % acl_id csr.delete_request(my_api) if csr.status == requests.codes.NO_CONTENT: return True LOG.error(_LE("status %s"), csr.status) return False
def _delete_acl_on_interface(self, csr, acl_id, csr_firewall_interface_list): for interface in csr_firewall_interface_list: my_api = ACL_API_ACLID_IFID_DIR % ( acl_id, interface['if-id'], interface['direction']) csr.delete_request(my_api) if csr.status != requests.codes.NO_CONTENT: LOG.error(_LE("status %s"), csr.status)
def _put_acl(self, csr, acl_id, acl_data): my_api = ACL_API_ACLID % acl_id csr.put_request(my_api, acl_data) if csr.status == requests.codes.NO_CONTENT: return True LOG.error(_LE("status %s"), csr.status) return False
def _delete_acl(self, csr, acl_id): my_api = ACL_API_ACLID % acl_id csr.delete_request(my_api) if csr.status == requests.codes.NO_CONTENT: return True LOG.error(_LE("status %s"), csr.status) return False
def _get_acl_interface(self, csr, acl_id): my_api = ACL_API_ACLID_IF % acl_id response = csr.get_request(my_api) if csr.status == requests.codes.OK: return response['items'] LOG.error(_LE("status %s"), csr.status) return ''
def _delete_acl_on_interface(self, csr, acl_id, csr_firewall_interface_list): for interface in csr_firewall_interface_list: my_api = ACL_API_ACLID_IFID_DIR % (acl_id, interface['if-id'], interface['direction']) csr.delete_request(my_api) if csr.status != requests.codes.NO_CONTENT: LOG.error(_LE("status %s"), csr.status)
def create_firewall_group(self, context, firewall_group, host): """Handles RPC from plugin to create a firewall group. """ # Get the in-namespace ports to which to add the firewall group. ports_for_fwg = self._get_firewall_group_ports(context, firewall_group) if not ports_for_fwg: return LOG.debug( "Create firewall group %(fwg_id)s on ports: %(ports)s" % { 'fwg_id': firewall_group['id'], 'ports': ', '.join( [p for ri_ports in ports_for_fwg for p in ri_ports[1]]) }) # Set firewall group status; will be overwritten if call to driver # fails. if firewall_group['admin_state_up']: status = n_const.ACTIVE else: status = n_const.DOWN # Call the driver. try: self.fwaas_driver.create_firewall_group(self.conf.agent_mode, ports_for_fwg, firewall_group) except fw_ext.FirewallInternalDriverError: msg = _LE("FWaaS driver error in create_firewall_group " "for firewall group: %(fwg_id)s") LOG.exception(msg, {'fwg_id': firewall_group['id']}) status = n_const.ERROR # Send firewall group's status to plugin. try: self.fwplugin_rpc.set_firewall_group_status( context, firewall_group['id'], status) except Exception: msg = _LE("FWaaS RPC failure in create_firewall_group " "for firewall group: %(fwg_id)s") LOG.exception(msg, {'fwg_id': firewall_group['id']}) self.services_sync_needed = True
def _remove_conntrack_by_cmd(self, cmd): if cmd: try: linux_utils.execute(cmd, run_as_root=True, check_exit_code=True, extra_ok_codes=[1]) except RuntimeError: LOG.exception( _LE("Failed execute conntrack command %s"), str(cmd))
def delete_firewall(self, context, firewall, host): """Handle Rpc from plugin to delete a firewall.""" router_ids = self._get_router_ids_for_fw( context, firewall, to_delete=True) if router_ids: router_info_list = self._get_router_info_list_for_tenant( router_ids, firewall['tenant_id']) LOG.debug( "Delete firewall %(fw)s on routers: '%(routers)s'" % {'fw': firewall['id'], 'routers': [ri.router['id'] for ri in router_info_list]}) # call into the driver try: self.fwaas_driver.delete_firewall( self.conf.agent_mode, router_info_list, firewall) if firewall['admin_state_up']: status = n_const.ACTIVE else: status = n_const.DOWN except fw_ext.FirewallInternalDriverError: LOG.error(_LE("Firewall Driver Error for delete_firewall " "for firewall: %(fwid)s"), {'fwid': firewall['id']}) status = n_const.ERROR try: # send status back to plugin if status in [n_const.ACTIVE, n_const.DOWN]: self.fwplugin_rpc.firewall_deleted(context, firewall['id']) else: self.fwplugin_rpc.set_firewall_status( context, firewall['id'], status) except Exception: LOG.exception( _LE("FWaaS RPC failure in delete_firewall " "for firewall: %(fwid)s"), {'fwid': firewall['id']}) self.services_sync_needed = True
def delete_firewall(self, context, firewall, host): """Handle Rpc from plugin to delete a firewall.""" router_ids = self._get_router_ids_for_fw( context, firewall, to_delete=True) if router_ids: router_info_list = self._get_router_info_list_for_tenant( router_ids, firewall['tenant_id']) LOG.debug( "Delete firewall %(fw)s on routers: '%(routers)s'" % {'fw': firewall['id'], 'routers': [ri.router['id'] for ri in router_info_list]}) # call into the driver try: self.fwaas_driver.delete_firewall( self.conf.agent_mode, router_info_list, firewall) if firewall['admin_state_up']: status = n_const.ACTIVE else: status = n_const.DOWN except fw_ext.FirewallInternalDriverError: LOG.error(_LE("Firewall Driver Error for delete_firewall " "for firewall: %(fwid)s"), {'fwid': firewall['id']}) status = n_const.ERROR try: # send status back to plugin if status in [n_const.ACTIVE, n_const.DOWN]: self.fwplugin_rpc.firewall_deleted(context, firewall['id']) else: self.fwplugin_rpc.set_firewall_status( context, firewall['id'], status) except Exception: LOG.exception( _LE("FWaaS RPC failure in delete_firewall " "for firewall: %(fwid)s"), {'fwid': firewall['id']}) self.services_sync_needed = True
def _invoke_driver_for_sync_from_plugin(self, ctx, router_info_list, fw): """Invoke the delete driver method for status of PENDING_DELETE and update method for all other status to (re)apply on driver which is Idempotent. """ if fw['status'] == n_const.PENDING_DELETE: try: self.fwaas_driver.delete_firewall( self.conf.agent_mode, router_info_list, fw) self.fwplugin_rpc.firewall_deleted( ctx, fw['id']) except fw_ext.FirewallInternalDriverError: LOG.error(_LE("Firewall Driver Error on fw state %(fwmsg)s " "for fw: %(fwid)s"), {'fwmsg': fw['status'], 'fwid': fw['id']}) self.fwplugin_rpc.set_firewall_status( ctx, fw['id'], n_const.ERROR) else: # PENDING_UPDATE, PENDING_CREATE, ... try: self.fwaas_driver.update_firewall( self.conf.agent_mode, router_info_list, fw) if fw['admin_state_up']: status = n_const.ACTIVE else: status = n_const.DOWN except fw_ext.FirewallInternalDriverError: LOG.error(_LE("Firewall Driver Error on fw state %(fwmsg)s " "for fw: %(fwid)s"), {'fwmsg': fw['status'], 'fwid': fw['id']}) status = n_const.ERROR self.fwplugin_rpc.set_firewall_status( ctx, fw['id'], status)
def _invoke_driver_for_sync_from_plugin(self, ctx, router_info_list, fw): """Invoke the delete driver method for status of PENDING_DELETE and update method for all other status to (re)apply on driver which is Idempotent. """ if fw['status'] == n_const.PENDING_DELETE: try: self.fwaas_driver.delete_firewall( self.conf.agent_mode, router_info_list, fw) self.fwplugin_rpc.firewall_deleted( ctx, fw['id']) except fw_ext.FirewallInternalDriverError: LOG.error(_LE("Firewall Driver Error on fw state %(fwmsg)s " "for fw: %(fwid)s"), {'fwmsg': fw['status'], 'fwid': fw['id']}) self.fwplugin_rpc.set_firewall_status( ctx, fw['id'], n_const.ERROR) else: # PENDING_UPDATE, PENDING_CREATE, ... try: self.fwaas_driver.update_firewall( self.conf.agent_mode, router_info_list, fw) if fw['admin_state_up']: status = n_const.ACTIVE else: status = n_const.DOWN except fw_ext.FirewallInternalDriverError: LOG.error(_LE("Firewall Driver Error on fw state %(fwmsg)s " "for fw: %(fwid)s"), {'fwmsg': fw['status'], 'fwid': fw['id']}) status = n_const.ERROR self.fwplugin_rpc.set_firewall_status( ctx, fw['id'], status)
def get_initial_contact_data(self): """Get the element's configuration data used to contact to SMC server. Contact data is a configuration string including the SMC server's IP, interfaces defined and special one-time password. eg. first create the L3 element on behalf of sg-engine in SMC server and generate the contact data, then boot the sg-engine with it and engine will init properly and connect to SMC server finally. """ data = None result = self.get_element("%s/%s/node" % (self.element_type, self.element_id)) LOG.debug("resule = %s", result) node_ref = result[0]['result'][0]['href'].replace( self.smc_api_connection.host_api_url + "/elements/", "") LOG.debug("Node ref is %s", node_ref) extra_options = [] if self.keyboard: extra_options.append("keyboard=%s" % (self.keyboard)) if self.timezone: extra_options.append("time_zone=%s" % (self.timezone)) if extra_options: extra_options = "&" + extra_options else: extra_options = "" result = self.smc_api_connection.post_element( "%s/initial_contact?enable_ssh=true%s" % (node_ref, extra_options), "") if result.is_text(): d1 = str(result).split("\n") idx = 0 for l in d1: if l.find("ssh/enabled") != -1: l = l.replace("false", "true") d1[idx] = l idx += 1 result.result = "\n".join(d1) data = result result = self.smc_api_connection.post_element( "%s/bind_license" % (node_ref), "") if result.code != 200: LOG.error( _LE("Could not bind license. " "Maybe SMC license pool is empty. " "SMC API details: %s"), result) return data
def _get_routers_in_project(self, project_id): if self.agent_api is None: LOG.exception(_LE("FWaaS RPC call failed; L3 agent_api failure")) router_info = self.agent_api._router_info if project_id: return [ ri for ri in router_info.values() if ri.router['tenant_id'] == project_id ] else: return []
def get_initial_contact_data(self): """Get the element's configuration data used to contact to SMC server. Contact data is a configuration string including the SMC server's IP, interfaces defined and special one-time password. eg. first create the L3 element on behalf of sg-engine in SMC server and generate the contact data, then boot the sg-engine with it and engine will init properly and connect to SMC server finally. """ data = None result = self.get_element("%s/%s/node" % (self.element_type, self.element_id)) LOG.debug("resule = %s", result) node_ref = result[0]['result'][0]['href'].replace( self.smc_api_connection.host_api_url + "/elements/", "") LOG.debug("Node ref is %s", node_ref) extra_options = [] if self.keyboard: extra_options.append("keyboard=%s" % (self.keyboard)) if self.timezone: extra_options.append("time_zone=%s" % (self.timezone)) if extra_options: extra_options = "&" + extra_options else: extra_options = "" result = self.smc_api_connection.post_element( "%s/initial_contact?enable_ssh=true%s" % (node_ref, extra_options), "") if result.is_text(): d1 = str(result).split("\n") idx = 0 for l in d1: if l.find("ssh/enabled") != -1: l = l.replace("false", "true") d1[idx] = l idx += 1 result.result = "\n".join(d1) data = result result = self.smc_api_connection.post_element( "%s/bind_license" % (node_ref), "") if result.code != 200: LOG.error(_LE("Could not bind license. " "Maybe SMC license pool is empty. " "SMC API details: %s"), result) return data
def delete(self, path, raw=False): del_result = SMCAPIResult("text") try: result = self.session_op("delete", path, raw) self.check_ret("DELETE", path, result, del_result) except Exception: LOG.error(_LE("exception when DELETE operation")) raise return del_result
def create_firewall(self, agent_mode, apply_list, firewall): LOG.debug('Creating firewall %(fw_id)s for tenant %(tid)s', {'fw_id': firewall['id'], 'tid': firewall['tenant_id']}) try: if firewall['admin_state_up']: self._setup_firewall(agent_mode, apply_list, firewall) else: self.apply_default_policy(agent_mode, apply_list, firewall) except (LookupError, RuntimeError): # catch known library exceptions and raise Fwaas generic exception LOG.exception(_LE("Failed to create firewall: %s"), firewall['id']) raise fw_ext.FirewallInternalDriverError(driver=FWAAS_DRIVER_NAME)
def delete(self, path, raw=False): del_result = SMCAPIResult("text") try: result = self.session_op("delete", path, raw) self.check_ret("DELETE", path, result, del_result) except Exception: LOG.error(_LE("exception when DELETE operation")) raise return del_result
def _load_firewall_extension_driver(namespace, driver): """Loads driver using alias or class name :param namespace: namespace where alias is defined :param driver: driver alias or class name :returns driver that is loaded :raises ImportError if fails to load driver """ try: return utils.load_class_by_alias_or_classname(namespace, driver) except ImportError: with excutils.save_and_reraise_exception(): LOG.error(_LE("Driver '%s' not found."), driver)
def session_op(self, attr, path, raw=False, data=None, headers=None): op = getattr(self.session, attr) if raw: result = op(path, headers=headers, data=data) else: result = op("%s/%s" % (self.host_api_url, path), headers=headers, data=data) if result.status_code == "404": LOG.error(_LE("SMC Error 404 %s"), result.reason) return result
def add_router(self, context, new_router): """Handles agent restart and router add. Fetches firewall groups from plugin and updates driver. """ if not self.fwaas_enabled: return try: self._process_router_update(new_router) except Exception: LOG.exception(_LE("FWaaS router add RPC info call failed for %s"), new_router['id']) self.services_sync_needed = True
def _validate_firewall_rule_data(self, firewall): if 'firewall_rule_list' not in firewall: LOG.error(_LE("no rule list")) return False for rule in firewall['firewall_rule_list']: if 'name' not in rule: LOG.error(_LE("CsrAcl: no rule name")) return False ip_version = rule.get('ip_version') if ip_version != 4: LOG.error(_LE("invalid ip version %(ip_version)s in " "rule %(rule)s"), {'ip_version': ip_version, 'rule': rule['name']}) return False if 'protocol' not in rule: LOG.error(_LE("no protocol in rule [%s]"), rule['name']) return False if rule.get('action', '').lower() not in ('allow', 'deny'): LOG.error(_LE("invalid action in rule [%s]"), rule['name']) return False return True
def create_firewall(self, context, firewall, host): """Handle Rpc from plugin to create a firewall.""" router_ids = self._get_router_ids_for_fw(context, firewall) if not router_ids: return router_info_list = self._get_router_info_list_for_tenant( router_ids, firewall['tenant_id']) LOG.debug("Create: Add firewall on Router List: '%s'", [ri.router['id'] for ri in router_info_list]) # call into the driver try: self.fwaas_driver.create_firewall( self.conf.agent_mode, router_info_list, firewall) if firewall['admin_state_up']: status = n_const.ACTIVE else: status = n_const.DOWN except fw_ext.FirewallInternalDriverError: LOG.error(_LE("Firewall Driver Error for create_firewall " "for firewall: %(fwid)s"), {'fwid': firewall['id']}) status = n_const.ERROR try: # send status back to plugin self.fwplugin_rpc.set_firewall_status( context, firewall['id'], status) except Exception: LOG.exception( _LE("FWaaS RPC failure in create_firewall " "for firewall: %(fwid)s"), {'fwid': firewall['id']}) self.services_sync_needed = True
def session_op(self, attr, path, raw=False, data=None, headers=None): op = getattr(self.session, attr) if raw: result = op(path, headers=headers, data=data) else: result = op("%s/%s" % (self.host_api_url, path), headers=headers, data=data) if result.status_code == "404": LOG.error(_LE("SMC Error 404 %s"), result.reason) return result
def rest_api(self, method, url, body=None, headers=None): url = REST_URL_PREFIX + url if body: body_data = jsonutils.dumps(body) else: body_data = '' if not headers: headers = {} enc = base64.b64encode('%s:%s' % (self.user, self.key)) headers['Authorization'] = 'Basic ' + enc LOG.debug("vArmourRestAPI: %(server)s %(port)s", { 'server': self.server, 'port': self.port }) try: action = "https://" + self.server + ":" + self.port + url LOG.debug( "vArmourRestAPI Sending: " "%(method)s %(action)s %(headers)s %(body_data)s", { 'method': method, 'action': action, 'headers': headers, 'body_data': body_data }) h = httplib2.Http(timeout=3, disable_ssl_certificate_validation=True) resp, resp_str = h.request(action, method, body=body_data, headers=headers) LOG.debug("vArmourRestAPI Response: %(status)s %(resp_str)s", { 'status': resp.status, 'resp_str': resp_str }) if resp.status == 200: return { 'status': resp.status, 'reason': resp.reason, 'body': jsonutils.loads(resp_str) } except Exception: LOG.error( _LE('vArmourRestAPI: Could not establish HTTP ' 'connection'))
def create_firewall(self, agent_mode, apply_list, firewall): LOG.debug('Creating firewall %(fw_id)s for tenant %(tid)s', {'fw_id': firewall['id'], 'tid': firewall['tenant_id']}) try: if firewall['admin_state_up']: self._setup_firewall(agent_mode, apply_list, firewall) self._remove_conntrack_new_firewall(agent_mode, apply_list, firewall) self.pre_firewall = dict(firewall) else: self.apply_default_policy(agent_mode, apply_list, firewall) except (LookupError, RuntimeError): # catch known library exceptions and raise Fwaas generic exception LOG.exception(_LE("Failed to create firewall: %s"), firewall['id']) raise fw_ext.FirewallInternalDriverError(driver=FWAAS_DRIVER_NAME)
def _validate_firewall_data(self, firewall): data = ('admin_state_up', 'vendor_ext') is_valid = all(x in firewall for x in data) if not is_valid: LOG.error(_LE("missing data in firewall")) return is_valid data = ('host_mngt_ip', 'host_usr_nm', 'host_usr_pw', 'if_list') is_valid = all(x in firewall['vendor_ext'] for x in data) if not is_valid: LOG.error(_LE("missing data in firewall vendor_ext")) return is_valid for firewall_interface in firewall['vendor_ext']['if_list']: if firewall_interface.get('direction', '') not in ( 'inside', 'outside', 'both'): LOG.error(_LE("invalid direction")) return False if 'port' not in firewall_interface: LOG.error(_LE("no port")) return False port = firewall_interface['port'] if 'id' not in port: LOG.error(_LE("no port id")) return False if 'hosting_info' not in port: LOG.error(_LE("no hosting_info")) return False if 'segmentation_id' not in port['hosting_info']: LOG.error(_LE("no segmentation_id")) return False if 'hosting_port_name' not in port['hosting_info']: LOG.error(_LE("hosting_port_name")) return False interface_type = port['hosting_info'][ 'hosting_port_name'].split(':')[0] + ':' if interface_type not in ('t1_p:', 't2_p:'): LOG.error(_LE("invalide interface type %s"), interface_type) return False return True
def update_router(self, context, updated_router): """Handles agent restart and router add. Fetches firewall groups from plugin and updates driver. """ if not self.fwaas_enabled: return try: self._process_router_update(updated_router) except Exception: #TODO(njohnston): This repr should be replaced. LOG.exception( _LE("FWaaS router update RPC info call failed for %s"), repr(updated_router)) self.services_sync_needed = True
def _validate_firewall_data(self, firewall): data = ('admin_state_up', 'vendor_ext') is_valid = all(x in firewall for x in data) if not is_valid: LOG.error(_LE("missing data in firewall")) return is_valid data = ('host_mngt_ip', 'host_usr_nm', 'host_usr_pw', 'if_list') is_valid = all(x in firewall['vendor_ext'] for x in data) if not is_valid: LOG.error(_LE("missing data in firewall vendor_ext")) return is_valid for firewall_interface in firewall['vendor_ext']['if_list']: if firewall_interface.get('direction', '') not in ('inside', 'outside', 'both'): LOG.error(_LE("invalid direction")) return False if 'port' not in firewall_interface: LOG.error(_LE("no port")) return False port = firewall_interface['port'] if 'id' not in port: LOG.error(_LE("no port id")) return False if 'hosting_info' not in port: LOG.error(_LE("no hosting_info")) return False if 'segmentation_id' not in port['hosting_info']: LOG.error(_LE("no segmentation_id")) return False if 'hosting_port_name' not in port['hosting_info']: LOG.error(_LE("hosting_port_name")) return False interface_type = port['hosting_info']['hosting_port_name'].split( ':')[0] + ':' if interface_type not in ('t1_p:', 't2_p:'): LOG.error(_LE("invalide interface type %s"), interface_type) return False return True
def post(self, path, json_element, raw=False): headers = {'accept': '*/*', 'content-type': 'application/json'} post_result = SMCAPIResult("text") try: result = self.session_op( "post", path, raw, headers=headers, data=json_element) self.check_ret("POST", path, result, post_result) post_result.headers = result.headers except Exception: LOG.error(_LE("exception when POST operation")) raise return post_result
def add_router(self, context, new_router): """On router add, get fw with rules from plugin and update driver. Handles agent restart, when a router is added, query the plugin to check if this router is in the router list for any firewall. If so install firewall rules on this router. """ # avoid msg to plugin when fwaas is not configured if not self.fwaas_enabled: return try: self._process_router_add(new_router) except Exception: LOG.exception(_LE("FWaaS RPC info call failed for '%s'."), new_router['id']) self.services_sync_needed = True
def login(self): self.session = requests.session() post_addr = ("%s/login?authenticationkey=%s&beta=true" % (self.host_api_url, self.auth_key)) res = self.session.post(post_addr) if res.status_code == 200: return True LOG.error(_LE("connect to %(host)s failed" " (%(msg)s/ code %(code)s)"), {'host': post_addr, 'msg': res.reason, 'code': res.status_code}) return False
def delete_firewall(self, agent_mode, apply_list, firewall): LOG.debug('Deleting firewall %(fw_id)s for tenant %(tid)s', {'fw_id': firewall['id'], 'tid': firewall['tenant_id']}) fwid = firewall['id'] try: for router_info in apply_list: ipt_if_prefix_list = self._get_ipt_mgrs_with_if_prefix( agent_mode, router_info) for ipt_if_prefix in ipt_if_prefix_list: ipt_mgr = ipt_if_prefix['ipt'] self._remove_chains(fwid, ipt_mgr) self._remove_default_chains(ipt_mgr) # apply the changes immediately (no defer in firewall path) ipt_mgr.defer_apply_off() except (LookupError, RuntimeError): # catch known library exceptions and raise Fwaas generic exception LOG.exception(_LE("Failed to delete firewall: %s"), fwid) raise fw_ext.FirewallInternalDriverError(driver=FWAAS_DRIVER_NAME)
def _delete_firewall(self, firewall): """Delete ACL. :param firewall: firewall dictionary :return: True if OK :return: False if there is an error """ if not self._validate_firewall_data(firewall): return False acl_id = firewall['vendor_ext'].get('acl_id') if not acl_id: LOG.error(_LE("firewall (%s) has no acl_id"), firewall['id']) return False csr = self._get_csr_host(firewall['vendor_ext']) return self._delete_acl(csr, acl_id)
def process_service(self, device_ids=None, removed_devices_info=None): try: if self.fullsync: self.fullsync = False self._process_fullsync() else: if device_ids: self._process_devices(device_ids) if removed_devices_info: LOG.debug("process_service: removed_devices_info %s", removed_devices_info) # do nothing for now else: self._process_event_q() except Exception: LOG.exception(_LE('process_service exception ERROR'))
def _update_firewall(self, firewall): """Update ACL and associated interfaces. :param firewall: firewall dictionary :return: True and status_data if OK :return: False and {} if there is an error """ if not self._validate_firewall_data(firewall): return False, {} if not self._validate_firewall_rule_data(firewall): return False, {} acl_id = firewall['vendor_ext'].get('acl_id') if not acl_id: LOG.error(_LE("firewall (%s) has no acl_id"), firewall['id']) return False, {} csr = self._get_csr_host(firewall['vendor_ext']) rest_acl_rules = self._get_acl_rule_data(firewall) rest_acl_rules['acl-id'] = acl_id # update ACL rules response = self._put_acl(csr, acl_id, rest_acl_rules) if not response: return False, {} status_data = { 'fw_id': firewall['id'], 'acl_id': acl_id, 'if_list': [] } # update ACL interface # get all interfaces with this acl_id csr_fw_interface_list = self._get_acl_interface(csr, acl_id) self._delete_acl_on_interface(csr, acl_id, csr_fw_interface_list) if not firewall['admin_state_up']: return True, status_data self._post_acl_to_interfaces(firewall, csr, acl_id, status_data) return True, status_data
def process_router_add(self, ri): """On router add, get fw with rules from plugin and update driver. Handles agent restart, when a router is added, query the plugin to check if this router is in the router list for any firewall. If so install firewall rules on this router. """ # avoid msg to plugin when fwaas is not configured if not self.fwaas_enabled: return try: # TODO(sridar): as per discussion with pc_m, we may want to hook # this up to the l3 agent observer notification self._process_router_add(ri) except Exception: LOG.exception( _LE("FWaaS RPC info call failed for '%s'."), ri.router['id']) self.services_sync_needed = True
def _post_acl_to_interfaces(self, firewall, csr, acl_id, status_data): acl_interface_url = ACL_API_ACLID_IF % acl_id for firewall_interface in firewall['vendor_ext']['if_list']: if_name = self._get_interface_name_from_hosting_port( firewall_interface['port']) acl_interface_req = { 'if-id': if_name, 'direction': firewall_interface['direction'] } LOG.debug("acl_interface_url %s", acl_interface_url) csr.post_request(acl_interface_url, acl_interface_req) if csr.status == requests.codes.CREATED: status_data['if_list'].append( {'port_id': firewall_interface['port']['id'], 'status': 'OK'}) else: LOG.error(_LE("status %s"), csr.status) status_data['if_list'].append( {'port_id': firewall_interface['port']['id'], 'status': 'ERROR'})
def _get_router_ids_for_fw(self, context, fw, to_delete=False): """Return the router_ids either from fw dict or tenant routers.""" if self._has_router_insertion_fields(fw): # it is a new version of plugin return (fw['del-router-ids'] if to_delete else fw['add-router-ids']) else: # we are in a upgrade and msg from older version of plugin try: routers = self.plugin_rpc.get_routers(context) except Exception: LOG.exception( _LE("FWaaS RPC failure in _get_router_ids_for_fw " "for firewall: %(fwid)s"), {'fwid': fw['id']}) self.services_sync_needed = True return [ router['id'] for router in routers if router['tenant_id'] == fw['tenant_id']]
def login_server(self): if self.session: yield else: ret = self.login() LOG.debug("SMC server LOGIN successfully.") if ret: try: yield except Exception: LOG.exception(_LE("exception while connect to server!")) raise n_exc.ServiceUnavailable(resource='SMC server', msg=_("OPERATION failed")) finally: self.logout() else: raise n_exc.BadRequest(resource='SMC server', msg=_("LOGIN failed!"))
def rest_api(self, method, url, body=None, headers=None): url = REST_URL_PREFIX + url if body: body_data = jsonutils.dumps(body) else: body_data = '' if not headers: headers = {} enc = base64.b64encode('%s:%s' % (self.user, self.key)) headers['Authorization'] = 'Basic ' + enc LOG.debug("vArmourRestAPI: %(server)s %(port)s", {'server': self.server, 'port': self.port}) try: action = "https://" + self.server + ":" + self.port + url LOG.debug("vArmourRestAPI Sending: " "%(method)s %(action)s %(headers)s %(body_data)s", {'method': method, 'action': action, 'headers': headers, 'body_data': body_data}) h = httplib2.Http(timeout=3, disable_ssl_certificate_validation=True) resp, resp_str = h.request(action, method, body=body_data, headers=headers) LOG.debug("vArmourRestAPI Response: %(status)s %(resp_str)s", {'status': resp.status, 'resp_str': resp_str}) if resp.status == 200: return {'status': resp.status, 'reason': resp.reason, 'body': jsonutils.loads(resp_str)} except Exception: LOG.error(_LE('vArmourRestAPI: Could not establish HTTP ' 'connection'))