def create_acl(self, sg): """Creates an ACL on Arista Switch. Deals with multiple configurations - such as multiple switches """ # Do nothing if Security Groups are not enabled if not self.sg_enabled: return if not sg: msg = _('Invalid or Empty Security Group Specified') raise arista_exc.AristaSecurityGroupError(msg=msg) in_cmds, out_cmds = self._create_acl_shell(sg['id']) for sgr in sg['security_group_rules']: in_cmds, out_cmds = self._create_acl_rule(in_cmds, out_cmds, sgr) in_cmds.append('exit') out_cmds.append('exit') for s in self._servers: try: self._run_openstack_sg_cmds(in_cmds, s) self._run_openstack_sg_cmds(out_cmds, s) except Exception: msg = (_('Failed to create ACL on EOS %s') % s) LOG.exception(msg) raise arista_exc.AristaSecurityGroupError(msg=msg)
def create_acl_rule(self, sgr): """Creates an ACL on Arista Switch. For a given Security Group (ACL), it adds additional rule Deals with multiple configurations - such as multiple switches """ # Do nothing if Security Groups are not enabled if not self.sg_enabled: return name = self._arista_acl_name(sgr['security_group_id'], sgr['direction']) cmds = [] for c in self.aclCreateDict['create']: cmds.append(c.format(name)) in_cmds, out_cmds = self._create_acl_rule(cmds, cmds, sgr) cmds = in_cmds if sgr['direction'] == 'egress': cmds = out_cmds cmds.append('exit') for s in self._servers: try: self._run_openstack_sg_cmds(cmds, s) except Exception: msg = (_('Failed to create ACL rule on EOS %s') % s) LOG.exception(msg) raise arista_exc.AristaSecurityGroupError(msg=msg)
def delete_acl_rule(self, sgr): """Deletes an ACL rule on Arista Switch. For a given Security Group (ACL), it adds removes a rule Deals with multiple configurations - such as multiple switches """ # Do nothing if Security Groups are not enabled if not self.sg_enabled: return # Only deal with valid protocols - skip the rest if not sgr or sgr['protocol'] not in SUPPORTED_SG_PROTOCOLS: return # Build seperate ACL for ingress and egress name = self._arista_acl_name(sgr['security_group_id'], sgr['direction']) remote_ip = sgr['remote_ip_prefix'] if not remote_ip: remote_ip = 'any' min_port = sgr['port_range_min'] if not min_port: min_port = 0 max_port = sgr['port_range_max'] if not max_port and sgr['protocol'] != 'icmp': max_port = 65535 for s in self._servers: try: self._delete_acl_rule_from_eos(name, sgr['protocol'], remote_ip, min_port, max_port, sgr['direction'], s) except Exception: msg = (_('Failed to delete ACL on EOS %s') % s) LOG.exception(msg) raise arista_exc.AristaSecurityGroupError(msg=msg)
def create_security_group_rule(self, sgr): try: self.rpc.create_acl_rule(sgr) except Exception: msg = (_('Failed to create ACL rule on EOS %s') % sgr) LOG.exception(msg) raise arista_exc.AristaSecurityGroupError(msg=msg)
def update_security_group(self, sg): try: self.rpc.create_acl(sg) except Exception: msg = (_('Failed to create ACL on EOS %s') % sg) LOG.exception(msg) raise arista_exc.AristaSecurityGroupError(msg=msg)
def _clean_acls(self, sg, failed_switch, switches_to_clean): """This is a helper function to clean up ACLs on switches. This called from within an exception - when apply_acl fails. Therefore, ensure that exception is raised after the cleanup is done. :param sg: Security Group to be removed :param failed_switch: IP of the switch where ACL failed :param switches_to_clean: List of switches containing link info """ if not switches_to_clean: # This means the no switch needs cleaning - so, simply raise the # the exception and bail out msg = (_("Failed to apply ACL %(sg)s on switch %(switch)s") % { 'sg': sg, 'switch': failed_switch }) LOG.error(msg) for s in switches_to_clean: try: # Port is being updated to remove security groups self.security_group_driver.remove_acl(sg, s['switch_id'], s['port_id'], s['switch_info']) except Exception: msg = (_("Failed to remove ACL %(sg)s on switch %(switch)%") % { 'sg': sg, 'switch': s['switch_info'] }) LOG.warning(msg) raise arista_exc.AristaSecurityGroupError(msg=msg)
def delete_security_group_rule(self, sgr_id): if sgr_id: sgr = self.ndb.get_security_group_rule(sgr_id) if sgr: try: self.rpc.delete_acl_rule(sgr) except Exception: msg = (_('Failed to delete ACL rule on EOS %s') % sgr) LOG.exception(msg) raise arista_exc.AristaSecurityGroupError(msg=msg)
def _create_acl_on_eos(self, in_cmds, out_cmds, protocol, cidr, from_port, to_port, direction): """Creates an ACL on Arista HW Device. :param name: Name for the ACL :param server: Server endpoint on the Arista switch to be configured """ if protocol == 'icmp': # ICMP rules require special processing if ((from_port and to_port) or (not from_port and not to_port)): rule = 'icmp_custom2' elif from_port and not to_port: rule = 'icmp_custom1' else: msg = _('Invalid ICMP rule specified') LOG.exception(msg) raise arista_exc.AristaSecurityGroupError(msg=msg) rule_type = 'in' cmds = in_cmds if direction == 'egress': rule_type = 'out' cmds = out_cmds final_rule = rule_type + '_' + rule acl_dict = self.aclCreateDict[final_rule] # None port is probematic - should be replaced with 0 if not from_port: from_port = 0 if not to_port: to_port = 0 for c in acl_dict: if rule == 'icmp_custom2': cmds.append(c.format(cidr, from_port, to_port)) else: cmds.append(c.format(cidr, from_port)) return in_cmds, out_cmds else: # Non ICMP rules processing here acl_dict = self.aclCreateDict['in_rule'] cmds = in_cmds if direction == 'egress': acl_dict = self.aclCreateDict['out_rule'] cmds = out_cmds if not protocol: acl_dict = self.aclCreateDict['default'] for c in acl_dict: cmds.append(c.format(protocol, cidr, from_port, to_port)) return in_cmds, out_cmds
def apply_acl(self, sgs, switch_id, port_id, switch_info): """Creates an ACL on Arista Switch. Applies ACLs to the baremetal ports only. The port/switch details is passed through the parameters. Deals with multiple configurations - such as multiple switches param sgs: List of Security Groups param switch_id: Switch ID of TOR where ACL needs to be applied param port_id: Port ID of port where ACL needs to be applied param switch_info: IP address of the TOR """ # Do nothing if Security Groups are not enabled if not self.sg_enabled: return # We do not support more than one security group on a port if not sgs or len(sgs) > 1: msg = (_('Only one Security Group Supported on a port %s') % sgs) raise arista_exc.AristaSecurityGroupError(msg=msg) sg = self._ndb.get_security_group(sgs[0]) # We already have ACLs on the TORs. # Here we need to find out which ACL is applicable - i.e. # Ingress ACL, egress ACL or both direction = ['ingress', 'egress'] server = self._make_eapi_client(switch_info) for d in range(len(direction)): name = self._arista_acl_name(sg['id'], direction[d]) try: self._apply_acl_on_eos(port_id, name, direction[d], server) except Exception: msg = (_('Failed to apply ACL on port %s') % port_id) LOG.exception(msg) raise arista_exc.AristaSecurityGroupError(msg=msg)
def delete_acl(self, sg): """Deletes an ACL from Arista Switch. Deals with multiple configurations - such as multiple switches """ # Do nothing if Security Groups are not enabled if not self.sg_enabled: return if not sg: msg = _('Invalid or Empty Security Group Specified') raise arista_exc.AristaSecurityGroupError(msg=msg) direction = ['ingress', 'egress'] for d in range(len(direction)): name = self._arista_acl_name(sg['id'], direction[d]) for s in self._servers: try: self._delete_acl_from_eos(name, s) except Exception: msg = (_('Failed to create ACL on EOS %s') % s) LOG.exception(msg) raise arista_exc.AristaSecurityGroupError(msg=msg)
def _delete_acl_rule_from_eos(self, name, protocol, cidr, from_port, to_port, direction, server): """deletes an ACL from Arista HW Device. :param name: Name for the ACL :param server: Server endpoint on the Arista switch to be configured """ cmds = [] if protocol == 'icmp': # ICMP rules require special processing if ((from_port and to_port) or (not from_port and not to_port)): rule = 'icmp_custom2' elif from_port and not to_port: rule = 'icmp_custom1' else: msg = _('Invalid ICMP rule specified') LOG.exception(msg) raise arista_exc.AristaSecurityGroupError(msg=msg) rule_type = 'del_in' if direction == 'egress': rule_type = 'del_out' final_rule = rule_type + '_' + rule acl_dict = self.aclCreateDict[final_rule] # None port is probematic - should be replaced with 0 if not from_port: from_port = 0 if not to_port: to_port = 0 for c in acl_dict: if rule == 'icmp_custom2': cmds.append(c.format(name, cidr, from_port, to_port)) else: cmds.append(c.format(name, cidr, from_port)) else: acl_dict = self.aclCreateDict['del_in_acl_rule'] if direction == 'egress': acl_dict = self.aclCreateDict['del_out_acl_rule'] for c in acl_dict: cmds.append(c.format(name, protocol, cidr, from_port, to_port)) self._run_openstack_sg_cmds(cmds, server)
def remove_acl(self, sgs, switch_id, port_id, switch_info): """Removes an ACL from Arista Switch. Removes ACLs from the baremetal ports only. The port/switch details is passed throuhg the parameters. param sgs: List of Security Groups param switch_id: Switch ID of TOR where ACL needs to be removed param port_id: Port ID of port where ACL needs to be removed param switch_info: IP address of the TOR """ # Do nothing if Security Groups are not enabled if not self.sg_enabled: return # We do not support more than one security group on a port if not sgs or len(sgs) > 1: msg = (_('Only one Security Group Supported on a port %s') % sgs) raise arista_exc.AristaSecurityGroupError(msg=msg) sg = self._ndb.get_security_group(sgs[0]) # We already have ACLs on the TORs. # Here we need to find out which ACL is applicable - i.e. # Ingress ACL, egress ACL or both direction = [] for sgr in sg['security_group_rules']: # Only deal with valid protocols - skip the rest if not sgr or sgr['protocol'] not in SUPPORTED_SG_PROTOCOLS: continue if sgr['direction'] not in direction: direction.append(sgr['direction']) # THIS IS TOTAL HACK NOW - just for testing # Assumes the credential of all switches are same as specified # in the condig file server = jsonrpclib.Server(self._eapi_host_url(switch_info)) for d in range(len(direction)): name = self._arista_acl_name(sg['id'], direction[d]) try: self._remove_acl_from_eos(port_id, name, direction[d], server) except Exception: msg = (_('Failed to remove ACL on port %s') % port_id) LOG.exception(msg)