def initialize(self): """Initialize subnet extension driver.""" self.subnet_cache = {} self.vpc_cidr_cache = {} self.aws_obj = AwsUtils() self.physical_network_cache = {} self.ec2_client_cache = {} self.ec2_cache_timer = datetime.datetime.now() self._ks_session = None LOG.info("SubnetExtensionDriver initialization complete")
def test_add_router_interface(self, mock_create, mock_get, mock_vpc, mock_add): aws_obj = AwsUtils() vpc_id = aws_obj.create_vpc_and_tags(self.context.current['cidr'], self._get_fake_tags()) interface_info = {'subnet_id': '00000000-0000-0000-0000-000000000000'} response = self._create_router(mock_create) router_id = response['id'] mock_get.return_value = {'network_id': 'fake_network_id'} # We need to mock 'get_vpc_from_neutron_network_id' from aws_utils, # because we need a valid vpc_id when attaching internet gateway. mock_vpc.return_value = vpc_id mock_add.return_value = { 'id': 'fake_id', 'subnet_id': 'fake_subnet_id' } response = self._driver.add_router_interface(self.context, router_id, interface_info) self.assertIsInstance(response, dict) mock_add.assert_called_once_with(self.context, router_id, interface_info)
def __init__(self): self.aws_utils = AwsUtils() super(AwsRouterPlugin, self).__init__() l3_db.subscribe()
class AwsRouterPlugin( service_base.ServicePluginBase, common_db_mixin.CommonDbMixin, extraroute_db.ExtraRoute_db_mixin, l3_hamode_db.L3_HA_NAT_db_mixin, l3_gwmode_db.L3_NAT_db_mixin, l3_dvrscheduler_db.L3_DVRsch_db_mixin, l3_hascheduler_db.L3_HA_scheduler_db_mixin): """Implementation of the Neutron L3 Router Service Plugin. This class implements a L3 service plugin that provides router and floatingip resources and manages associated request/response. All DB related work is implemented in classes l3_db.L3_NAT_db_mixin, l3_hamode_db.L3_HA_NAT_db_mixin, l3_dvr_db.L3_NAT_with_dvr_db_mixin, and extraroute_db.ExtraRoute_db_mixin. """ supported_extension_aliases = [ "dvr", "router", "ext-gw-mode", "extraroute", "l3_agent_scheduler", "l3-ha", "security-group" ] @resource_registry.tracked_resources( router=l3_db.Router, floatingip=l3_db.FloatingIP, security_group=securitygroups_db.SecurityGroup) def __init__(self): self.aws_utils = AwsUtils() super(AwsRouterPlugin, self).__init__() l3_db.subscribe() def get_plugin_type(self): return constants.L3_ROUTER_NAT def get_plugin_description(self): """returns string description of the plugin.""" return ("AWS L3 Router Service Plugin for basic L3 forwarding" " between (L2) Neutron networks and access to external" " networks via a NAT gateway.") ########## FLOATING IP FEATURES ############### def create_floatingip(self, context, floatingip): try: response = self.aws_utils.allocate_elastic_ip() public_ip_allocated = response['PublicIp'] LOG.info("Created elastic IP %s" % public_ip_allocated) if 'floatingip' in floatingip: floatingip['floatingip'][ 'floating_ip_address'] = public_ip_allocated if 'port_id' in floatingip['floatingip'] and floatingip[ 'floatingip']['port_id'] is not None: # Associate to a Port port_id = floatingip['floatingip']['port_id'] self._associate_floatingip_to_port(context, public_ip_allocated, port_id) except Exception as e: LOG.error("Error in Allocating EIP: %s " % e) raise e return super(AwsRouterPlugin, self).create_floatingip( context, floatingip, initial_status=n_const.FLOATINGIP_STATUS_DOWN) def _associate_floatingip_to_port(self, context, floating_ip_address, port_id): port = self._core_plugin.get_port(context, port_id) ec2_id = None fixed_ip_address = None # TODO: Assuming that there is only one fixed IP if len(port['fixed_ips']) > 0: fixed_ip = port['fixed_ips'][0] if 'ip_address' in fixed_ip: fixed_ip_address = fixed_ip['ip_address'] search_opts = { 'ip': fixed_ip_address, 'tenant_id': context.tenant_id } server_list = self.aws_utils.get_nova_client().servers.list( search_opts=search_opts) if len(server_list) > 0: server = server_list[0] if 'ec2_id' in server.metadata: ec2_id = server.metadata['ec2_id'] if floating_ip_address is not None and ec2_id is not None: self.aws_utils.associate_elastic_ip_to_ec2_instance( floating_ip_address, ec2_id) LOG.info("EC2 ID found for IP %s : %s" % (fixed_ip_address, ec2_id)) else: LOG.warning("EC2 ID not found to associate the floating IP") raise exceptions.AwsException( error_code="No Server Found", message="No server found with the Required IP") def update_floatingip(self, context, id, floatingip): floating_ip_dict = super(AwsRouterPlugin, self).get_floatingip(context, id) if 'floatingip' in floatingip and 'port_id' in floatingip['floatingip']: port_id = floatingip['floatingip']['port_id'] if port_id is not None: # Associate Floating IP LOG.info("Associating elastic IP %s with port %s" % (floating_ip_dict['floating_ip_address'], port_id)) self._associate_floatingip_to_port( context, floating_ip_dict['floating_ip_address'], port_id) else: # Port Disassociate self.aws_utils.disassociate_elastic_ip_from_ec2_instance( floating_ip_dict['floating_ip_address']) return super(AwsRouterPlugin, self).update_floatingip(context, id, floatingip) def delete_floatingip(self, context, id): floating_ip = super(AwsRouterPlugin, self).get_floatingip(context, id) floating_ip_address = floating_ip['floating_ip_address'] LOG.info("Deleting elastic IP %s" % floating_ip_address) self.aws_utils.delete_elastic_ip(floating_ip_address) return super(AwsRouterPlugin, self).delete_floatingip(context, id) ##### ROUTERS ##### def create_router(self, context, router): try: router_name = router['router']['name'] internet_gw_res = self.aws_utils.create_internet_gateway_resource() ret_obj = super(AwsRouterPlugin, self).create_router(context, router) internet_gw_res.create_tags(Tags=[{ 'Key': 'Name', 'Value': router_name }, { 'Key': 'openstack_router_id', 'Value': ret_obj['id'] }]) LOG.info("Created AWS router %s with openstack id %s" % (router_name, ret_obj['id'])) return ret_obj except Exception as e: LOG.error("Error while creating router %s" % e) raise e def delete_router(self, context, id): try: LOG.info("Deleting router %s" % id) self.aws_utils.detach_internet_gateway_by_router_id(id) self.aws_utils.delete_internet_gateway_by_router_id(id) except Exception as e: LOG.error("Error in Deleting Router: %s " % e) raise e return super(AwsRouterPlugin, self).delete_router(context, id) def update_router(self, context, id, router): ## get internet gateway resource by openstack router id and update the tags try: if 'router' in router and 'name' in router['router']: router_name = router['router']['name'] tags_list = [{ 'Key': 'Name', 'Value': router_name }, { 'Key': 'openstack_router_id', 'Value': id }] LOG.info("Updated router %s" % id) self.aws_utils.create_tags_internet_gw_from_router_id( id, tags_list) except Exception as e: LOG.error("Error in Updating Router: %s " % e) raise e return super(AwsRouterPlugin, self).update_router(context, id, router) ###### ROUTER INTERFACE ###### def add_router_interface(self, context, router_id, interface_info): subnet_id = interface_info['subnet_id'] subnet_obj = self._core_plugin.get_subnet(context, subnet_id) LOG.info("Adding subnet %s to router %s" % (subnet_id, router_id)) neutron_network_id = subnet_obj['network_id'] try: # Get Internet Gateway ID ig_id = self.aws_utils.get_internet_gw_from_router_id(router_id) # Get VPC ID vpc_id = self.aws_utils.get_vpc_from_neutron_network_id( neutron_network_id) self.aws_utils.attach_internet_gateway(ig_id, vpc_id) # Search for a Route table tagged with Router-id route_tables = self.aws_utils.get_route_table_by_router_id( router_id) if len(route_tables) == 0: # If not tagged, Fetch all the Route Tables Select one and tag it route_tables = self.aws_utils.describe_route_tables_by_vpc_id( vpc_id) if len(route_tables) > 0: route_table = route_tables[0] route_table_res = self.aws_utils._get_ec2_resource( ).RouteTable(route_table['RouteTableId']) route_table_res.create_tags(Tags=[{ 'Key': 'openstack_router_id', 'Value': router_id }]) if len(route_tables) > 0: route_table = route_tables[0] self.aws_utils.create_default_route_to_ig( route_table['RouteTableId'], ig_id, ignore_errors=True) except Exception as e: LOG.error("Error in Creating Interface: %s " % e) raise e return super(AwsRouterPlugin, self).add_router_interface(context, router_id, interface_info) def remove_router_interface(self, context, router_id, interface_info): LOG.info("Deleting subnet %s from router %s" % (interface_info['subnet_id'], router_id)) # TODO: Need to delete the route entry in the Route Table of AWS return super(AwsRouterPlugin, self).remove_router_interface(context, router_id, interface_info)
def initialize(self): self.aws_utils = AwsUtils() callbacks.subscribe(self)
class AwsMechanismDriver(api.MechanismDriver): """Ml2 Mechanism driver for AWS""" def __init__(self): self.aws_utils = None super(AwsMechanismDriver, self).__init__() def initialize(self): self.aws_utils = AwsUtils() callbacks.subscribe(self) # NETWORK def create_network_precommit(self, context): pass def create_network_postcommit(self, context): pass def update_network_precommit(self, context): try: network_name = context.current['name'] neutron_network_id = context.current['id'] tags_list = [{'Key': 'Name', 'Value': network_name}] self.aws_utils.create_tags_for_vpc(neutron_network_id, tags_list) except Exception as e: LOG.error("Error in update subnet precommit: %s" % e) raise e def update_network_postcommit(self, context): pass def delete_network_precommit(self, context): neutron_network_id = context.current['id'] # If user is deleting an empty neutron network then nothing to be done # on AWS side if len(context.current['subnets']) > 0: vpc_id = self.aws_utils.get_vpc_from_neutron_network_id( neutron_network_id) if vpc_id is not None: LOG.info("Deleting network %s (VPC_ID: %s)" % (neutron_network_id, vpc_id)) self.aws_utils.delete_vpc(vpc_id=vpc_id) def delete_network_postcommit(self, context): pass # SUBNET def create_subnet_precommit(self, context): LOG.info("Create subnet for network %s" % context.network.current['id']) # External Network doesn't exist on AWS, so no operations permitted if 'provider:physical_network' in context.network.current: if context.network.current[ 'provider:physical_network'] == "external": # Do not create subnets for external & provider networks. Only # allow tenant network subnet creation at the moment. LOG.info('Creating external network {0}'.format( context.network.current['id'])) return if context.current['ip_version'] == 6: raise AwsException(error_code="IPv6Error", message="Cannot create subnets with IPv6") mask = int(context.current['cidr'][-2:]) if mask < 16 or mask > 28: raise AwsException(error_code="InvalidMask", message="Subnet mask has to be >16 and <28") try: # Check if this is the first subnet to be added to a network neutron_network = context.network.current associated_vpc_id = self.aws_utils.get_vpc_from_neutron_network_id( neutron_network['id']) if associated_vpc_id is None: # Need to create EC2 VPC vpc_cidr = context.current['cidr'][:-2] + '16' tags = [{ 'Key': 'Name', 'Value': neutron_network['name'] }, { 'Key': 'openstack_network_id', 'Value': neutron_network['id'] }, { 'Key': 'openstack_tenant_id', 'Value': context.current['tenant_id'] }] associated_vpc_id = self.aws_utils.create_vpc_and_tags( cidr=vpc_cidr, tags_list=tags) # Create Subnet in AWS tags = [{ 'Key': 'Name', 'Value': context.current['name'] }, { 'Key': 'openstack_subnet_id', 'Value': context.current['id'] }, { 'Key': 'openstack_tenant_id', 'Value': context.current['tenant_id'] }] self.aws_utils.create_subnet_and_tags(vpc_id=associated_vpc_id, cidr=context.current['cidr'], tags_list=tags) except Exception as e: LOG.error("Error in create subnet precommit: %s" % e) raise e def create_subnet_postcommit(self, context): pass def update_subnet_precommit(self, context): try: subnet_name = context.current['name'] neutron_subnet_id = context.current['id'] tags_list = [{'Key': 'Name', 'Value': subnet_name}] self.aws_utils.create_subnet_tags(neutron_subnet_id, tags_list) except Exception as e: LOG.error("Error in update subnet precommit: %s" % e) raise e def update_subnet_postcommit(self, context): pass def delete_subnet_precommit(self, context): if 'provider:physical_network' in context.network.current: if context.network.current[ 'provider:physical_network'] == "external": LOG.error("Deleting provider and external networks not " "supported") return try: LOG.info("Deleting subnet %s" % context.current['id']) subnet_id = self.aws_utils.get_subnet_from_neutron_subnet_id( context.current['id']) if subnet_id is not None: self.aws_utils.delete_subnet(subnet_id=subnet_id) except Exception as e: LOG.error("Error in delete subnet precommit: %s" % e) raise e def delete_subnet_postcommit(self, context): neutron_network = context.network.current if 'provider:physical_network' in context.network.current and \ context.network.current['provider:physical_network'] == \ "external": LOG.info('Deleting %s external network' % context.network.current['id']) return try: subnets = neutron_network['subnets'] if (len(subnets) == 1 and subnets[0] == context.current['id'] or len(subnets) == 0): # Last subnet for this network was deleted, so delete VPC # because VPC gets created during first subnet creation under # an OpenStack network vpc_id = self.aws_utils.get_vpc_from_neutron_network_id( neutron_network['id']) LOG.info("Deleting VPC %s since this was the last subnet in " "the vpc" % vpc_id) self.aws_utils.delete_vpc(vpc_id=vpc_id) except Exception as e: LOG.error("Error in delete subnet postcommit: %s" % e) raise e def create_port_precommit(self, context): pass def create_port_postcommit(self, context): pass def update_port_precommit(self, context): pass def update_port_postcommit(self, context): pass def delete_port_precommit(self, context): pass def delete_port_postcommit(self, context): pass def bind_port(self, context): fixed_ip_dict = dict() if 'fixed_ips' in context.current: if len(context.current['fixed_ips']) > 0: fixed_ip_dict = context.current['fixed_ips'][0] fixed_ip_dict['subnet_id'] = \ self.aws_utils.get_subnet_from_neutron_subnet_id( fixed_ip_dict['subnet_id']) secgroup_ids = context.current['security_groups'] self.create_security_groups_if_needed(context, secgroup_ids) segment_id = random.choice(context.network.network_segments)[api.ID] context.set_binding(segment_id, "vip_type_a", json.dumps(fixed_ip_dict), status='ACTIVE') return True def create_security_groups_if_needed(self, context, secgrp_ids): core_plugin = manager.NeutronManager.get_plugin() vpc_id = self.aws_utils.get_vpc_from_neutron_network_id( context.current['network_id']) for secgrp_id in secgrp_ids: tags = [{ 'Key': 'openstack_id', 'Value': secgrp_id }, { 'Key': 'openstack_network_id', 'Value': context.current['network_id'] }] secgrp = core_plugin.get_security_group(context._plugin_context, secgrp_id) aws_secgrp = self.aws_utils.get_sec_group_by_id(secgrp_id, vpc_id=vpc_id) if not aws_secgrp and secgrp['name'] != 'default': grp_name = secgrp['name'] desc = secgrp['description'] rules = secgrp['security_group_rules'] ec2_secgrp = self.aws_utils.create_security_group( grp_name, desc, vpc_id, secgrp_id, tags) self.aws_utils.create_security_group_rules(ec2_secgrp, rules) def delete_security_group(self, security_group_id): self.aws_utils.delete_security_group(security_group_id) def remove_security_group_rule(self, context, rule_id): core_plugin = manager.NeutronManager.get_plugin() rule = core_plugin.get_security_group_rule(context, rule_id) secgrp_id = rule['security_group_id'] secgrp = core_plugin.get_security_group(context, secgrp_id) old_rules = secgrp['security_group_rules'] for idx in range(len(old_rules) - 1, -1, -1): if old_rules[idx]['id'] == rule_id: old_rules.pop(idx) self.aws_utils.update_sec_group(secgrp_id, old_rules) def add_security_group_rule(self, context, rule): core_plugin = manager.NeutronManager.get_plugin() secgrp_id = rule['security_group_id'] secgrp = core_plugin.get_security_group(context, secgrp_id) old_rules = secgrp['security_group_rules'] old_rules.append(rule) self.aws_utils.update_sec_group(secgrp_id, old_rules) def update_security_group_rules(self, context, rule_id): core_plugin = manager.NeutronManager.get_plugin() rule = core_plugin.get_security_group_rule(context, rule_id) secgrp_id = rule['security_group_id'] secgrp = core_plugin.get_security_group(context, secgrp_id) old_rules = secgrp['security_group_rules'] for idx in range(len(old_rules) - 1, -1, -1): if old_rules[idx]['id'] == rule_id: old_rules.pop(idx) break old_rules.append(rule) self.aws_utils.update_sec_group(secgrp_id, old_rules) def secgroup_callback(self, resource, event, trigger, **kwargs): if resource == resources.SECURITY_GROUP: if event == events.BEFORE_DELETE: security_group_id = kwargs.get('security_group_id') if security_group_id: self.delete_security_group(security_group_id) else: LOG.warn('Security group ID not found in delete request') elif resource == resources.SECURITY_GROUP_RULE: context = kwargs['context'] if event == events.BEFORE_CREATE: rule = kwargs['security_group_rule'] self.add_security_group_rule(context, rule) elif event == events.BEFORE_DELETE: rule_id = kwargs['security_group_rule_id'] self.remove_security_group_rule(context, rule_id) elif event == events.BEFORE_UPDATE: rule_id = kwargs['security_group_rule_id'] self.update_security_group_rules(context, rule_id)
class SubnetExtensionDriver(api.ExtensionDriver): """Subnet extension driver to process and extend AZ data.""" _supported_extension_alias = 'subnet_availability_zone' def initialize(self): """Initialize subnet extension driver.""" self.subnet_cache = {} self.vpc_cidr_cache = {} self.aws_obj = AwsUtils() self.physical_network_cache = {} self.ec2_client_cache = {} self.ec2_cache_timer = datetime.datetime.now() self._ks_session = None LOG.info("SubnetExtensionDriver initialization complete") @property def ks_session(self): if self._ks_session is None: self._ks_session = self.aws_obj.get_keystone_session() return self._ks_session def get_context(self, project_id): ctx = context.Context(tenant_id=project_id) ctx.auth_token = self.ks_session.get_token() return ctx def get_ec2_client(self, project_id): tdiff = datetime.datetime.now() - self.ec2_cache_timer if tdiff.total_seconds() > 900: self.ec2_cache_timer = datetime.datetime.now() self.ec2_client_cache = {} if project_id in self.ec2_client_cache: return self.ec2_client_cache[project_id] ctx = self.get_context(project_id=project_id) ec2_client = self.aws_obj._get_ec2_client(ctx, project_id=project_id) self.ec2_client_cache[project_id] = ec2_client return ec2_client def _get_phynet_from_network(self, network_id, tenant_id): if network_id in self.physical_network_cache: return self.physical_network_cache[network_id] ctx = self.get_context(project_id=tenant_id) try: plugin = directory.get_plugin() network = plugin.get_network(ctx, network_id) if providernet.PHYSICAL_NETWORK in network: phy_net = network[providernet.PHYSICAL_NETWORK] self.physical_network_cache[network_id] = phy_net return phy_net except Exception as e: LOG.exception(e) return None @property def extension_alias(self): """Extension alias to load extension.""" return self._supported_extension_alias def process_create_subnet(self, plugin_context, data, result): """Set AZ data in result to use in AWS mechanism.""" result[az_ext.RESOURCE_NAME] = data[az_ext.RESOURCE_NAME] self.subnet_cache[result['id']] = data[az_ext.RESOURCE_NAME] def _check_for_vpc_cidr(self, vpc, result): cidr = result['cidr'] if (vpc, cidr) in self.vpc_cidr_cache: result[az_ext.RESOURCE_NAME] = self.vpc_cidr_cache[(vpc, cidr)] return True project_id = result['tenant_id'] ec2_client = self.get_ec2_client(project_id) response = ec2_client.describe_subnets(Filters=[ { 'Name': 'vpc-id', 'Values': [vpc] }, ]) if 'Subnets' in response: for subnet in response['Subnets']: self.vpc_cidr_cache[(subnet['VpcId'], subnet['CidrBlock'])] = \ subnet['AvailabilityZone'] if (vpc, cidr) in self.vpc_cidr_cache: result[az_ext.RESOURCE_NAME] = self.vpc_cidr_cache[(vpc, cidr)] return True return False def _check_for_openstack_subnet(self, result): ostack_id = result['id'] if ostack_id in self.subnet_cache: result[az_ext.RESOURCE_NAME] = self.subnet_cache[ostack_id] return True project_id = result['tenant_id'] ec2_client = self.get_ec2_client(project_id) response = ec2_client.describe_subnets(Filters=[{ 'Name': 'tag-value', 'Values': [ostack_id] }]) if 'Subnets' in response: for subnet in response['Subnets']: if 'SubnetId' in subnet: self.subnet_cache[ostack_id] = subnet['AvailabilityZone'] result[az_ext.RESOURCE_NAME] = subnet['AvailabilityZone'] return True return False def extend_subnet_dict(self, session, db_data, result): """Extend subnet dict.""" phynet = self._get_phynet_from_network(result['network_id'], result['tenant_id']) if isinstance(phynet, six.string_types): if phynet == 'external': return elif phynet.startswith('vpc') and self._check_for_vpc_cidr( phynet, result): return if self._check_for_openstack_subnet(result): return
def initialize(self): self.aws_utils = AwsUtils()
class AwsMechanismDriver(api.MechanismDriver): """Ml2 Mechanism driver for AWS""" def __init__(self): self.aws_utils = None def initialize(self): self.aws_utils = AwsUtils() # NETWORK def create_network_precommit(self, context): pass def create_network_postcommit(self, context): pass def update_network_precommit(self, context): try: network_name = context.current['name'] neutron_network_id = context.current['id'] tags_list = [{'Key': 'Name', 'Value': network_name}] self.aws_utils.create_tags_for_vpc(neutron_network_id, tags_list) except Exception as e: LOG.error("Error in update subnet precommit: %s" % e) raise e def update_network_postcommit(self, context): pass def delete_network_precommit(self, context): neutron_network_id = context.current['id'] # If user is deleting an empty neutron network then nothing to be done on AWS side if len(context.current['subnets']) > 0: vpc_id = self.aws_utils.get_vpc_from_neutron_network_id( neutron_network_id) if vpc_id is not None: LOG.info("Deleting network %s (VPC_ID: %s)" % (neutron_network_id, vpc_id)) self.aws_utils.delete_vpc(vpc_id=vpc_id) def delete_network_postcommit(self, context): pass # SUBNET def create_subnet_precommit(self, context): LOG.info("Create subnet for network %s" % context.network.current['id']) # External Network doesn't exist on AWS, so no operations permitted if 'provider:physical_network' in context.network.current and context.network.current[ 'provider:physical_network'] == "external": # Do not create subnets for external & provider networks. Only allow tenant network # subnet creation at the moment. return if context.current['ip_version'] == 6: raise AwsException(error_code="IPv6Error", message="Cannot create subnets with IPv6") mask = int(context.current['cidr'][-2:]) if mask < 16 or mask > 28: raise AwsException(error_code="InvalidMask", message="Subnet mask has to be >16 and <28") try: # Check if this is the first subnet to be added to a network neutron_network = context.network.current associated_vpc_id = self.aws_utils.get_vpc_from_neutron_network_id( neutron_network['id']) if associated_vpc_id is None: # Need to create EC2 VPC vpc_cidr = context.current['cidr'][:-2] + '16' tags = [{ 'Key': 'Name', 'Value': neutron_network['name'] }, { 'Key': 'openstack_network_id', 'Value': neutron_network['id'] }] associated_vpc_id = self.aws_utils.create_vpc_and_tags( cidr=vpc_cidr, tags_list=tags) # Create Subnet in AWS tags = [{ 'Key': 'Name', 'Value': context.current['name'] }, { 'Key': 'openstack_subnet_id', 'Value': context.current['id'] }] self.aws_utils.create_subnet_and_tags(vpc_id=associated_vpc_id, cidr=context.current['cidr'], tags_list=tags) except Exception as e: LOG.error("Error in create subnet precommit: %s" % e) raise e def create_subnet_postcommit(self, context): pass def update_subnet_precommit(self, context): try: subnet_name = context.current['name'] neutron_subnet_id = context.current['id'] tags_list = [{'Key': 'Name', 'Value': subnet_name}] self.aws_utils.create_subnet_tags(neutron_subnet_id, tags_list) except Exception as e: LOG.error("Error in update subnet precommit: %s" % e) raise e def update_subnet_postcommit(self, context): pass def delete_subnet_precommit(self, context): if 'provider:physical_network' in context.network.current and context.network.current[ 'provider:physical_network'] == "external": LOG.error("Deleting provider and external networks not supported") return try: LOG.info("Deleting subnet %s" % context.current['id']) subnet_id = self.aws_utils.get_subnet_from_neutron_subnet_id( context.current['id']) if subnet_id is not None: self.aws_utils.delete_subnet(subnet_id=subnet_id) except Exception as e: LOG.error("Error in delete subnet precommit: %s" % e) raise e def delete_subnet_postcommit(self, context): neutron_network = context.network.current if 'provider:physical_network' in context.network.current and context.network.current[ 'provider:physical_network'] == "external": return try: subnets = neutron_network['subnets'] if len(subnets) == 1 and subnets[0] == context.current[ 'id'] or len(subnets) == 0: # Last subnet for this network was deleted, so delete VPC # because VPC gets created during first subnet creation under # an OpenStack network vpc_id = self.aws_utils.get_vpc_from_neutron_network_id( neutron_network['id']) LOG.info( "Deleting VPC %s since this was the last subnet in the vpc" % vpc_id) self.aws_utils.delete_vpc(vpc_id=vpc_id) except Exception as e: LOG.error("Error in delete subnet postcommit: %s" % e) raise e def create_port_precommit(self, context): pass def create_port_postcommit(self, context): pass def update_port_precommit(self, context): pass def update_port_postcommit(self, context): pass def delete_port_precommit(self, context): pass def delete_port_postcommit(self, context): pass def bind_port(self, context): fixed_ip_dict = dict() if 'fixed_ips' in context.current: if len(context.current['fixed_ips']) > 0: fixed_ip_dict = context.current['fixed_ips'][0] fixed_ip_dict[ 'subnet_id'] = self.aws_utils.get_subnet_from_neutron_subnet_id( fixed_ip_dict['subnet_id']) segment_id = random.choice(context.network.network_segments)[api.ID] context.set_binding(segment_id, "vip_type_a", json.dumps(fixed_ip_dict), status='ACTIVE') return True
def __init__(self): self.aws_utils = AwsUtils() super(AwsRouterPlugin, self).__init__()
class AwsRouterPlugin(service_plugin_class, common_db_mixin.CommonDbMixin, extraroute_db.ExtraRoute_db_mixin, l3_hamode_db.L3_HA_NAT_db_mixin, l3_gwmode_db.L3_NAT_db_mixin, l3_dvrscheduler_db.L3_DVRsch_db_mixin, l3_hascheduler_db.L3_HA_scheduler_db_mixin): """Implementation of the Neutron L3 Router Service Plugin. This class implements a L3 service plugin that provides router and floatingip resources and manages associated request/response. All DB related work is implemented in classes l3_db.L3_NAT_db_mixin, l3_hamode_db.L3_HA_NAT_db_mixin, l3_dvr_db.L3_NAT_with_dvr_db_mixin, and extraroute_db.ExtraRoute_db_mixin. """ supported_extension_aliases = [ "dvr", "router", "ext-gw-mode", "extraroute", "l3_agent_scheduler", "l3-ha", "security-group" ] @resource_registry.tracked_resources(router=router, floatingip=floating_ip) def __init__(self): self.aws_utils = AwsUtils() super(AwsRouterPlugin, self).__init__() def get_plugin_type(self): return plugin_type def get_plugin_description(self): """returns string description of the plugin.""" return ("AWS L3 Router Service Plugin for basic L3 forwarding" " between (L2) Neutron networks and access to external" " networks via a NAT gateway.") # FLOATING IP FEATURES def create_floatingip(self, context, floatingip): public_ip_allocated = floatingip['floatingip']['floating_ip_address'] if public_ip_allocated: LOG.info("Discovered floating ip %s", public_ip_allocated) else: public_ip_allocated = None try: response = self.aws_utils.allocate_elastic_ip(context) public_ip_allocated = response['PublicIp'] LOG.info("Created elastic IP %s" % public_ip_allocated) if 'floatingip' in floatingip: floatingip['floatingip'][ 'floating_ip_address'] = public_ip_allocated if ('port_id' in floatingip['floatingip'] and floatingip['floatingip']['port_id'] is not None): # Associate to a Port port_id = floatingip['floatingip']['port_id'] self._associate_floatingip_to_port(context, public_ip_allocated, port_id) except Exception as e: LOG.error("Error in Creation/Allocating EIP") if public_ip_allocated: LOG.error("Deleting Elastic IP: %s" % public_ip_allocated) self.aws_utils.delete_elastic_ip(public_ip_allocated, context) raise e try: res = super(AwsRouterPlugin, self).create_floatingip( context, floatingip, initial_status=const.FLOATINGIP_STATUS_DOWN) except Exception as e: LOG.error("Error when adding floating ip in openstack. " "Deleting Elastic IP: %s" % public_ip_allocated) raise e return res def _associate_floatingip_to_port(self, context, floating_ip_address, port_id): port = self._core_plugin.get_port(context, port_id) ec2_id = None fixed_ip_address = None # TODO(fixed_ip): Assuming that there is only one fixed IP if len(port['fixed_ips']) > 0: fixed_ip = port['fixed_ips'][0] if 'ip_address' in fixed_ip: fixed_ip_address = fixed_ip['ip_address'] search_opts = { 'ip': fixed_ip_address, 'tenant_id': context.tenant_id } server_list = self.aws_utils.get_nova_client().servers.list( search_opts=search_opts) if len(server_list) > 0: server = server_list[0] if 'ec2_id' in server.metadata: ec2_id = server.metadata['ec2_id'] if floating_ip_address is not None and ec2_id is not None: self.aws_utils.associate_elastic_ip_to_ec2_instance( floating_ip_address, ec2_id, context=context) LOG.info("EC2 ID found for IP %s : %s" % (fixed_ip_address, ec2_id)) else: LOG.warning("EC2 ID not found to associate the floating IP") raise AwsException(error_code="No Server Found", message="No server found with the Required IP") def update_floatingip(self, context, fip_id, floatingip): floating_ip_dict = super(AwsRouterPlugin, self).get_floatingip(context, fip_id) if ('floatingip' in floatingip and 'port_id' in floatingip['floatingip']): port_id = floatingip['floatingip']['port_id'] if port_id is not None: # Associate Floating IP LOG.info("Associating elastic IP %s with port %s" % (floating_ip_dict['floating_ip_address'], port_id)) self._associate_floatingip_to_port( context, floating_ip_dict['floating_ip_address'], port_id) else: try: # Port Disassociate self.aws_utils.disassociate_elastic_ip_from_ec2_instance( floating_ip_dict['floating_ip_address'], context) except AwsException as e: if 'Association ID not found' in e.msg: # Since its already disassociated on EC2, we continue # and remove the association here. LOG.warn("Association for Elastic IP not found. " "Probable out of band change on EC2.") elif 'InvalidAddress.NotFound' in e.msg: LOG.warn("Elastic IP cannot be found in EC2. Probably " "removed out of band on EC2.") else: raise e return super(AwsRouterPlugin, self).update_floatingip(context, fip_id, floatingip) def delete_floatingip(self, context, fip_id): floating_ip = super(AwsRouterPlugin, self).get_floatingip(context, fip_id) floating_ip_address = floating_ip['floating_ip_address'] project_id = floating_ip['project_id'] LOG.info("Deleting elastic IP %s" % floating_ip_address) try: self.aws_utils.delete_elastic_ip(floating_ip_address, context, project_id=project_id) except AwsException as e: if 'InvalidAddress.NotFound' in e.msg: LOG.warn("Elastic IP not found on AWS. Cleaning up neutron db") else: raise e return super(AwsRouterPlugin, self).delete_floatingip(context, fip_id) # ROUTERS def create_router(self, context, router): try: router_name = router['router']['name'] ret_obj = super(AwsRouterPlugin, self).create_router(context, router) if router_name and router_name.startswith('igw-'): omni_resources.add_mapping(ret_obj['id'], router_name) LOG.info("Created discovered AWS router %s", router_name) return ret_obj internet_gw_res = self.aws_utils.create_internet_gateway_resource( context) tags = [{ 'Key': 'Name', 'Value': router_name }, { 'Key': 'openstack_router_id', 'Value': ret_obj['id'] }] self.aws_utils.create_resource_tags(internet_gw_res, tags) omni_resources.add_mapping(ret_obj['id'], internet_gw_res.internet_gateway_id) LOG.info("Created AWS router %s with openstack id %s" % (router_name, ret_obj['id'])) return ret_obj except Exception as e: LOG.error("Error while creating router %s" % e) raise e def delete_router(self, context, router_id): LOG.info("Deleting router %s" % router_id) if omni_resources.get_omni_resource(router_id) is None: raise RouterIdInvalidException(router_id=router_id) try: router_obj = self._get_router(context, router_id) if omni_resources.get_omni_resource(router_id) is None: raise AwsException( "Router deletion failed, no AWS mapping found for %s" % (router_id, )) project_id = router_obj['project_id'] router_name = router_obj['name'] try: if router_name and router_name.startswith('igw-'): self.aws_utils.detach_internet_gateway( router_name, context, project_id=project_id) self.aws_utils.delete_internet_gateway( router_name, context, project_id=project_id) else: self.aws_utils.detach_internet_gateway_by_router_id( router_id, context, project_id=project_id) self.aws_utils.delete_internet_gateway_by_router_id( router_id, context, project_id=project_id) except AwsException as e: if 'InvalidInternetGatewayID.NotFound' in e.msg: LOG.warn(e.msg) else: raise e omni_resources.delete_mapping(router_id) except Exception as e: LOG.error("Error in Deleting Router: %s " % e) raise e return super(AwsRouterPlugin, self).delete_router(context, router_id) def update_router(self, context, router_id, router): # get internet gateway resource by openstack router id and update the # tags try: router_obj = self._get_router(context, router_id) router_name = router_obj['name'] if router_name and router_name.startswith('igw-'): return super(AwsRouterPlugin, self).update_router(context, router_id, router) if 'router' in router and 'name' in router['router']: router_name = router['router']['name'] tags_list = [{ 'Key': 'Name', 'Value': router_name }, { 'Key': 'openstack_router_id', 'Value': router_id }] LOG.info("Updated router %s" % router_id) self.aws_utils.create_tags_internet_gw_from_router_id( router_id, tags_list, context) except Exception as e: LOG.error("Error in Updating Router: %s " % e) raise e return super(AwsRouterPlugin, self).update_router(context, router_id, router) # ROUTER INTERFACE def add_router_interface(self, context, router_id, interface_info): subnet_id = interface_info['subnet_id'] subnet_obj = self._core_plugin.get_subnet(context, subnet_id) router_obj = self._get_router(context, router_id) router_name = router_obj['name'] if router_name and router_name.startswith('igw-'): LOG.info("Adding subnet %s to router %s", subnet_id, router_name) return super(AwsRouterPlugin, self).add_router_interface(context, router_id, interface_info) LOG.info("Adding subnet %s to router %s" % (subnet_id, router_id)) neutron_network_id = subnet_obj['network_id'] try: # Get Internet Gateway ID ig_id = self.aws_utils.get_internet_gw_from_router_id( router_id, context) # Get VPC ID vpc_id = self.aws_utils.get_vpc_from_neutron_network_id( neutron_network_id, context) self.aws_utils.attach_internet_gateway(ig_id, vpc_id, context) # Search for a Route table tagged with Router-id route_tables = self.aws_utils.get_route_table_by_router_id( router_id, context) if len(route_tables) == 0: # If not tagged, Fetch all the Route Tables Select one and tag # it route_tables = self.aws_utils.describe_route_tables_by_vpc_id( vpc_id, context) if len(route_tables) > 0: route_table = route_tables[0] route_table_res = self.aws_utils._get_ec2_resource( context).RouteTable(route_table['RouteTableId']) route_table_res.create_tags(Tags=[{ 'Key': 'openstack_router_id', 'Value': router_id }]) if len(route_tables) > 0: route_table = route_tables[0] self.aws_utils.create_default_route_to_ig( route_table['RouteTableId'], ig_id, context=context, ignore_errors=True) except Exception as e: LOG.error("Error in Creating Interface: %s " % e) raise e return super(AwsRouterPlugin, self).add_router_interface(context, router_id, interface_info) def remove_router_interface(self, context, router_id, interface_info): if 'port_id' in interface_info: interface_id = interface_info['port_id'] deleting_by = "port_id" elif 'subnet_id' in interface_info: interface_id = interface_info['subnet_id'] deleting_by = "subnet_id" LOG.info("Deleting interface by {0} {1} from router {2}".format( deleting_by, interface_id, router_id)) router_obj = self._get_router(context, router_id) project_id = router_obj['project_id'] try: self.aws_utils.detach_internet_gateway_by_router_id( router_id, context, project_id=project_id) except AwsException as e: if 'InvalidInternetGatewayID.NotFound' in e.msg: LOG.warn(e.msg) else: raise e route_tables = self.aws_utils.get_route_table_by_router_id( router_id, context, project_id=project_id) if route_tables: route_table_id = route_tables[0]['RouteTableId'] self.aws_utils.delete_default_route_to_ig(route_table_id, context, project_id=project_id) return super(AwsRouterPlugin, self).remove_router_interface(context, router_id, interface_info)
class AwsMechanismDriver(api.MechanismDriver): """Ml2 Mechanism driver for AWS""" def __init__(self): self.aws_utils = None self._default_sgr_to_remove = [] super(AwsMechanismDriver, self).__init__() def initialize(self): self.aws_utils = AwsUtils() callbacks.subscribe(self) # NETWORK def create_network_precommit(self, context): pass def create_network_postcommit(self, context): pass def update_network_precommit(self, context): try: network_name = context.current['name'] original_network_name = context.original['name'] LOG.debug("Update network original: %s current: %s", original_network_name, network_name) if network_name == original_network_name: return neutron_network_id = context.current['id'] project_id = context.current['project_id'] tags_list = [{'Key': 'Name', 'Value': network_name}] self.aws_utils.create_tags_for_vpc(neutron_network_id, tags_list, context=context._plugin_context, project_id=project_id) except Exception as e: LOG.error("Error in update subnet precommit: %s" % e) raise e def update_network_postcommit(self, context): pass def delete_network_precommit(self, context): neutron_network_id = context.current['id'] project_id = context.current['project_id'] # If user is deleting an empty neutron network then nothing to be done # on AWS side if len(context.current['subnets']) > 0: vpc_id = self.aws_utils.get_vpc_from_neutron_network_id( neutron_network_id, context=context._plugin_context, project_id=project_id) if vpc_id is not None: LOG.info("Deleting network %s (VPC_ID: %s)" % (neutron_network_id, vpc_id)) try: self.aws_utils.delete_vpc(vpc_id=vpc_id, context=context._plugin_context, project_id=project_id) except AwsException as e: if 'InvalidVpcID.NotFound' in e.msg: LOG.warn(e.msg) else: raise e omni_resources.delete_mapping(context.current['id']) def delete_network_postcommit(self, context): pass # SUBNET def create_subnet_precommit(self, context): network_id = context.network.current['id'] LOG.info("Create subnet for network %s" % network_id) # External Network doesn't exist on AWS, so no operations permitted physical_network = context.network.current.get( 'provider:physical_network') if physical_network == "external": # Do not create subnets for external & provider networks. Only # allow tenant network subnet creation at the moment. LOG.info('Creating external network {0}'.format(network_id)) return elif physical_network and physical_network.startswith('vpc'): LOG.info('Registering AWS network with vpc %s', physical_network) subnet_cidr = context.current['cidr'] subnet_id = self.aws_utils.get_subnet_from_vpc_and_cidr( context._plugin_context, physical_network, subnet_cidr, context.current['project_id']) omni_resources.add_mapping(network_id, physical_network) omni_resources.add_mapping(context.current['id'], subnet_id) return if context.current['ip_version'] == 6: raise AwsException(error_code="IPv6Error", message="Cannot create subnets with IPv6") mask = int(context.current['cidr'][-2:]) if mask < 16 or mask > 28: raise AwsException(error_code="InvalidMask", message="Subnet mask has to be >16 and <28") try: # Check if this is the first subnet to be added to a network neutron_network = context.network.current associated_vpc_id = self.aws_utils.get_vpc_from_neutron_network_id( neutron_network['id'], context=context._plugin_context) if associated_vpc_id is None: # Need to create EC2 VPC vpc_cidr = context.current['cidr'][:-2] + '16' tags = [{ 'Key': 'Name', 'Value': neutron_network['name'] }, { 'Key': 'openstack_network_id', 'Value': neutron_network['id'] }, { 'Key': 'openstack_tenant_id', 'Value': context.current['tenant_id'] }] associated_vpc_id = self.aws_utils.create_vpc_and_tags( cidr=vpc_cidr, tags_list=tags, context=context._plugin_context) omni_resources.add_mapping(neutron_network['id'], associated_vpc_id) # Create Subnet in AWS tags = [{ 'Key': 'Name', 'Value': context.current['name'] }, { 'Key': 'openstack_subnet_id', 'Value': context.current['id'] }, { 'Key': 'openstack_tenant_id', 'Value': context.current['tenant_id'] }] if AZ in context.current and context.current[AZ]: aws_az = context.current[AZ] elif context.network.current[AZ_HINT]: network_az_hints = context.network.current[AZ_HINT] if len(network_az_hints) > 1: # We use only one AZ hint even if multiple AZ values # are passed while creating network. raise NetworkWithMultipleAZs() aws_az = network_az_hints[0] else: raise AzNotProvided() self._validate_az(aws_az) ec2_subnet_id = self.aws_utils.create_subnet_and_tags( vpc_id=associated_vpc_id, cidr=context.current['cidr'], tags_list=tags, aws_az=aws_az, context=context._plugin_context) omni_resources.add_mapping(context.current['id'], ec2_subnet_id) except Exception as e: LOG.error("Error in create subnet precommit: %s" % e) raise e def _send_request(self, session, url): headers = { 'Content-Type': 'application/json', 'X-Auth-Token': session.get_token() } response = requests.get(url + "/v1/zones", headers=headers) response.raise_for_status() return response.json() def _validate_az(self, aws_az): if not isinstance(aws_az, six.string_types): raise InvalidAzValue() if ',' in aws_az: raise NetworkWithMultipleAZs() session = self.aws_utils.get_keystone_session() azmgr_url = session.get_endpoint(service_type='azmanager', region_name=cfg.CONF.nova_region_name) zones = self._send_request(session, azmgr_url) if aws_az not in zones: LOG.error("Provided az %s not found in zones %s", aws_az, zones) raise InvalidAzValue() def create_subnet_postcommit(self, context): pass def update_subnet_precommit(self, context): try: subnet_name = context.current['name'] neutron_subnet_id = context.current['id'] tags_list = [{'Key': 'Name', 'Value': subnet_name}] self.aws_utils.create_subnet_tags(neutron_subnet_id, tags_list, context=context._plugin_context) except Exception as e: LOG.error("Error in update subnet precommit: %s" % e) raise e def update_subnet_postcommit(self, context): pass def delete_subnet_precommit(self, context): try: LOG.info("Deleting subnet %s" % context.current['id']) project_id = context.current['project_id'] subnet_id = self.aws_utils.get_subnet_from_neutron_subnet_id( context.current['id'], context=context._plugin_context, project_id=project_id) if not subnet_id: raise Exception("Subnet mapping %s not found" % (context.current['id'])) try: self.aws_utils.delete_subnet(subnet_id=subnet_id, context=context._plugin_context, project_id=project_id) omni_resources.delete_mapping(context.current['id']) except AwsException as e: if 'InvalidSubnetID.NotFound' in e.msg: LOG.warn(e.msg) omni_resources.delete_mapping(context.current['id']) else: raise e except Exception as e: LOG.error("Error in delete subnet precommit: %s" % e) raise e def delete_subnet_postcommit(self, context): neutron_network = context.network.current try: subnets = neutron_network['subnets'] if (len(subnets) == 1 and subnets[0] == context.current['id'] or len(subnets) == 0): # Last subnet for this network was deleted, so delete VPC # because VPC gets created during first subnet creation under # an OpenStack network project_id = context.current['project_id'] vpc_id = self.aws_utils.get_vpc_from_neutron_network_id( neutron_network['id'], context=context._plugin_context, project_id=project_id) if not vpc_id: raise Exception("Network mapping %s not found", neutron_network['id']) LOG.info("Deleting VPC %s since this was the last subnet in " "the vpc" % vpc_id) self.aws_utils.delete_vpc(vpc_id=vpc_id, context=context._plugin_context, project_id=project_id) omni_resources.delete_mapping(context.network.current['id']) except Exception as e: LOG.error("Error in delete subnet postcommit: %s" % e) raise e def create_port_precommit(self, context): pass def create_port_postcommit(self, context): pass def update_port_precommit(self, context): original_port = context._original_port updated_port = context._port sorted_original_sgs = sorted(original_port['security_groups']) sorted_updated_sgs = sorted(updated_port['security_groups']) aws_sgs = [] project_id = context.current['project_id'] if sorted_updated_sgs != sorted_original_sgs: for sg in updated_port['security_groups']: aws_secgrps = self.aws_utils.get_sec_group_by_id( sg, context._plugin_context, project_id=project_id) aws_sgs.append(aws_secgrps[0]['GroupId']) if aws_sgs: self.aws_utils.modify_ports(aws_sgs, updated_port['name'], context._plugin_context, project_id) def update_port_postcommit(self, context): pass def delete_port_precommit(self, context): pass def delete_port_postcommit(self, context): pass def bind_port(self, context): fixed_ip_dict = dict() if 'fixed_ips' in context.current: if len(context.current['fixed_ips']) > 0: fixed_ip_dict = context.current['fixed_ips'][0] openstack_subnet_id = fixed_ip_dict['subnet_id'] aws_subnet_id = \ self.aws_utils.get_subnet_from_neutron_subnet_id( openstack_subnet_id, context._plugin_context, project_id=context.current['project_id']) fixed_ip_dict['subnet_id'] = aws_subnet_id secgroup_ids = context.current['security_groups'] ec2_secgroup_ids = self.create_security_groups_if_needed( context, secgroup_ids) fixed_ip_dict['ec2_security_groups'] = ec2_secgroup_ids segment_id = random.choice(context.network.network_segments)[api.ID] context.set_binding(segment_id, "vip_type_a", json.dumps(fixed_ip_dict), status='ACTIVE') return True def create_security_groups_if_needed(self, context, secgrp_ids): project_id = context.current.get('project_id') core_plugin = directory.get_plugin() vpc_id = self.aws_utils.get_vpc_from_neutron_network_id( context.current['network_id'], context=context._plugin_context, project_id=project_id) ec2_secgroup_ids = [] for secgrp_id in secgrp_ids: tags = [{ 'Key': 'openstack_id', 'Value': secgrp_id }, { 'Key': 'openstack_network_id', 'Value': context.current['network_id'] }] secgrp = core_plugin.get_security_group(context._plugin_context, secgrp_id) aws_secgrps = self.aws_utils.get_sec_group_by_id( secgrp_id, group_name=secgrp['name'], vpc_id=vpc_id, context=context._plugin_context, project_id=project_id) if not aws_secgrps and secgrp['name'] != 'default': grp_name = secgrp['name'] tags.append({"Key": "Name", "Value": grp_name}) desc = secgrp['description'] rules = secgrp['security_group_rules'] ec2_secgrp = self.aws_utils.create_security_group( grp_name, desc, vpc_id, secgrp_id, tags, context=context._plugin_context, project_id=project_id) self.aws_utils.create_security_group_rules(ec2_secgrp, rules) # Make sure that omni_resources table is populated with newly # created security group aws_secgrps = self.aws_utils.get_sec_group_by_id( secgrp_id, group_name=secgrp['name'], vpc_id=vpc_id, context=context._plugin_context, project_id=project_id) for aws_secgrp in aws_secgrps: ec2_secgroup_ids.append(aws_secgrp['GroupId']) return ec2_secgroup_ids def delete_security_group(self, security_group_id, context, project_id): core_plugin = directory.get_plugin() secgrp = core_plugin.get_security_group(context, security_group_id) self.aws_utils.delete_security_group(security_group_id, context, project_id, group_name=secgrp['name']) def remove_security_group_rule(self, context, rule_id): core_plugin = directory.get_plugin() rule = core_plugin.get_security_group_rule(context, rule_id) secgrp_id = rule['security_group_id'] secgrp = core_plugin.get_security_group(context, secgrp_id) if "project_id" in rule: project_id = rule['project_id'] else: project_id = context.tenant self.aws_utils.delete_security_group_rule_if_needed( context, secgrp_id, secgrp['name'], project_id, rule) def add_security_group_rule(self, context, rule): core_plugin = directory.get_plugin() secgrp_id = rule['security_group_id'] secgrp = core_plugin.get_security_group(context, secgrp_id) if "project_id" in rule: project_id = rule['project_id'] else: project_id = context.tenant self.aws_utils.create_security_group_rule_if_needed( context, secgrp_id, secgrp['name'], project_id, rule) def update_security_group_rules(self, context, rule_id): core_plugin = directory.get_plugin() rule = core_plugin.get_security_group_rule(context, rule_id) secgrp_id = rule['security_group_id'] secgrp = core_plugin.get_security_group(context, secgrp_id) old_rules = secgrp['security_group_rules'] for idx in range(len(old_rules) - 1, -1, -1): if old_rules[idx]['id'] == rule_id: old_rules.pop(idx) break old_rules.append(rule) if "project_id" in rule: project_id = rule['project_id'] else: project_id = context.tenant self.aws_utils.update_sec_group(secgrp_id, old_rules, context=context, project_id=project_id, group_name=secgrp['name']) def secgroup_callback(self, resource, event, trigger, **kwargs): context = kwargs['context'] if resource == resources.SECURITY_GROUP: if event == events.AFTER_CREATE: project_id = kwargs.get('security_group')['project_id'] secgrp = kwargs.get('security_group') security_group_id = secgrp.get('id') core_plugin = directory.get_plugin() aws_secgrps = self.aws_utils.get_sec_group_by_id( security_group_id, group_name=secgrp.get('name'), context=context, project_id=project_id) if len(aws_secgrps) == 0: return for sgr in secgrp.get('security_group_rules', []): # This is invoked for discovered security groups only. For # discovered security groups we do not need default egress # rules. Those should be reported by discovery service. # When removing these default security group rules we do # not need to check against AWS. Store the security group # rule IDs so that we can ignore them when delete security # group rule is called here. self._default_sgr_to_remove.append(sgr.get('id')) core_plugin.delete_security_group_rule( context, sgr.get('id')) if event == events.BEFORE_DELETE: project_id = kwargs.get('security_group')['project_id'] security_group_id = kwargs.get('security_group_id') if security_group_id: self.delete_security_group(security_group_id, context, project_id) else: LOG.warn('Security group ID not found in delete request') elif resource == resources.SECURITY_GROUP_RULE: if event == events.BEFORE_CREATE: rule = kwargs['security_group_rule'] self.add_security_group_rule(context, rule) elif event == events.BEFORE_DELETE: rule_id = kwargs['security_group_rule_id'] if rule_id in self._default_sgr_to_remove: # Check the comment above in security group rule # AFTER_CREATE event handling self._default_sgr_to_remove.remove(rule_id) else: self.remove_security_group_rule(context, rule_id) elif event == events.BEFORE_UPDATE: rule_id = kwargs['security_group_rule_id'] self.update_security_group_rules(context, rule_id)