def deriveAfterLearnedBgpAdvertisements(_model: entities.Model, vpnTunnel: Union[entities.VPNTunnel, str], prefixes: List[rules.Ipv4Range]) -> entities.Model: """ Some prefixes are advertised from the other end of the vpnTunnel. Derive routes based on that. """ model: entities.Model = entities.Model() model.CopyFrom(_model) if isinstance(vpnTunnel, str): vpnTunnel = findVpnTunnel(model, vpnTunnel) gw = findVpnGateway(model, vpnTunnel.vpn_gateway) context = DestinationContext(network=gw.network, region=vpnTunnel.region, peer_info=vpnTunnel.url) routes = [] for prefix in prefixes: # reuse the existing route construction functions to build a correct route route = rules.Route(dest_range=prefix, region=vpnTunnel.region) route = deriveRoute(model, route, context, Destination.BGP_PEERS) routes.append(route) model.routes.append(route) Derive(model, routes) return model
def test_deriveAfterStaticRouteUpdated(self): route = text_format.Parse( """ id: "6567481593092089925" name: "test-project-sq2::added-route" priority: 1000 dest_range { ip: 168165376 mask: 24 } next_hop_ip: 167903235 instance_filter { network: "projects/test-project-sq2/global/networks/n2" } url: "projects/test-project-sq2/global/routes/added-route" route_type: STATIC """, rules.Route()) newRoute = text_format.Parse( """ id: "7724679716894648665" name: "test-project-sq2::added-route" priority: 1000 dest_range { ip: 168165376 mask: 24 } next_hop_ip: 167903235 instance_filter { network: "projects/test-project-sq2/global/networks/n2" attributes { tag: "test-tag" } } url: "projects/test-project-sq2/global/routes/added-route" route_type: STATIC """, rules.Route()) self.common( lambda model: derivationFunctions.deriveAfterStaticRouteUpdated( model, [(route, newRoute)]), "test_data/case9.1/test_project_sq2_10132020_1.pb", "test_data/case9.1/test_project_sq2_10132020_2.pb") self.common( lambda model: derivationFunctions.deriveAfterStaticRouteUpdated( model, [(newRoute, route)]), "test_data/case9.1/test_project_sq2_10132020_2.pb", "test_data/case9.1/test_project_sq2_10132020_3.pb")
def test_deriveAfterStaticRouteAdded(self): self.common( lambda model: derivationFunctions.deriveAfterStaticRouteAdded( model, text_format.Parse( """ id: "6845072321650144437" name: "test-project-sq2::added-static-route" priority: 1000 dest_range { ip: 168230912 mask: 24 } next_hop_ip: 167903235 instance_filter { network: "projects/test-project-sq2/global/networks/n2" } url: "projects/test-project-sq2/global/routes/added-static-route" route_type: STATIC """, rules.Route())), "test_data/case8.0/test_project_sq2_10062020_1.pb", "test_data/case8.0/test_project_sq2_10062020_2.pb") self.common( lambda model: derivationFunctions.deriveAfterStaticRouteAdded( model, text_format.Parse( """ id: "7345242974329025248" name: "test-project-sq2::added-route" priority: 1000 dest_range { ip: 168165376 mask: 24 } next_hop_ip: 167903235 instance_filter { network: "projects/test-project-sq2/global/networks/n2" attributes { tag: "test-tag" } } url: "projects/test-project-sq2/global/routes/added-route" route_type: STATIC """, rules.Route())), "test_data/case8.2/test_project_sq2_10062020_1.pb", "test_data/case8.2/test_project_sq2_10062020_2.pb")
def test_findRoot(self): with open("test_data/big_project/big_project.pb", "r") as f: model = f.read() model: entities.Model = text_format.Parse(model, entities.Model()) root = derivationFunctions.FindRootRoute( model, text_format.Parse( """ id: "3679872279986331686" name: "reachability-e2e-test::peering-route-1426b0141f4aa8cc" priority: 0 dest_range { ip: 167903488 mask: 24 } instance_filter { network: "projects/reachability-e2e-test/global/networks/peer1-route-test" } next_hop_peering: "reachability-e2e-test::peer1-route-test::peering1-peer-route-test" url: "projects/reachability-e2e-test/global/routes/peering-route-1426b0141f4aa8cc" route_type: PEERING_SUBNET creation_timestamp: "2019-11-11T14:20:57.515-08:00" description: "Auto generated route via peering [peering1-peer-route-test]." """, rules.Route())) self.assertEqual( root, text_format.Parse( """ id: "6980694499687424046" name: "reachability-e2e-test::default-route-b56e783807428e99" priority: 0 dest_range { ip: 167903488 mask: 24 } next_hop_network: "projects/reachability-e2e-test/global/networks/route-test" instance_filter { network: "projects/reachability-e2e-test/global/networks/route-test" } url: "projects/reachability-e2e-test/global/routes/default-route-b56e783807428e99" route_type: SUBNET creation_timestamp: "2019-11-11T14:20:49.544-08:00" description: "Default local route to the subnetwork 10.2.1.0/24." """, rules.Route()))
def trimRoute(route, keep_priority=False): trimmed = rules.Route() trimmed.CopyFrom(route) for field in ["id", "name", "url", "creation_timestamp", "description"]: trimmed.ClearField(field) trimmed.priority = route.priority if keep_priority else 0 return trimmed
def deriveRoute(model: entities.Model, route: rules.Route, context: DestinationContext, destination: Destination, extraRule: str = None) -> rules.Route: """ A single derivation, based on the current model, the route generating the derived route, the context and destination for the generation. If the matching generation rule has a name, then the specified generation rule with name extraRule is further loaded and applied after all other rules. """ dstName = Destination.DESCRIPTOR.values_by_number[destination].name functionNames = ["COMMON", dstName, ] derived = rules.Route() derived.CopyFrom(route) for functionName in functionNames + (["%s_%s" % (extraRule, dstName)] if extraRule else []): functionName = toCamelCase(functionName) f = RouteGenerators[functionName] f(derived, context, model) return derived
def deriveAfterIpRangesAdded(_model: entities.Model, subnet: Union[entities.Subnet, str], ipRanges: List[Union[rules.Ipv4Range, str]]) -> entities.Model: """ Adding some secondary ipRanges to a subnet requires the range update in the subnet, and installing subnet derivation_rules to the network and peers. """ model: entities.Model = entities.Model() model.CopyFrom(_model) if isinstance(subnet, str): subnet = findSubnet(model, subnet) network = findNetwork(model, subnet.network) projectName = ParseProjectFromUrl(subnet.url) routes = [] for prefix in ipRanges: if isinstance(prefix, str): prefix = ipv4StrToRange(prefix) subnet.secondary_ranges.append(prefix) hexId = genHex(16) # reuse the existing route construction functions to build a correct route route = rules.Route( id=genId(), name=projectName + "::default-route-" + hexId, priority=0, dest_range=prefix, next_hop_network=network.url, instance_filter=rules.InstanceFilter(network=network.url), url="projects/%s/global/routes/default-route-%s" % (projectName, hexId), route_type=rules.Route.RouteType.SUBNET ) routes.append(route) model.routes.append(route) Derive(model, routes) return model
def deriveAfterSubnetAdded(_model: entities.Model, subnet: entities.Subnet) -> entities.Model: """ When a subnet is added, the associated subnet route is created and propagated """ model: entities.Model = entities.Model() model.CopyFrom(_model) network = findNetwork(model, subnet.network) projectName = ParseProjectFromUrl(subnet.url) model.subnets.append(subnet) if subnet.region not in network.regions: network.regions.append(subnet.region) routes = [] prefixes = [subnet.ipv4_range] + list(subnet.secondary_ranges) for prefix in prefixes: hexId = genHex(16) # reuse the existing route construction functions to build a correct route route = rules.Route( id=genId(), name=projectName + "::default-route-" + hexId, priority=0, dest_range=prefix, next_hop_network=network.url, instance_filter=rules.InstanceFilter(network=network.url), url="projects/%s/global/routes/default-route-%s" % (projectName, hexId), route_type=rules.Route.RouteType.SUBNET ) routes.append(route) model.routes.append(route) Derive(model, routes) return model