Beispiel #1
0
    def common(self,
               fun: Callable[[entities.Model], entities.Model],
               pbBefore: str,
               pbAfter: str,
               keepPriority: bool = False):
        with open(pbBefore, "r") as f:
            before = f.read()
            before: entities.Model = text_format.Parse(before,
                                                       entities.Model())

        after: entities.Model = fun(before)

        with open(pbAfter, "r") as f:
            expected = f.read()
            expected: entities.Model = text_format.Parse(
                expected, entities.Model())

        before = getTrimmedRoutes(before.routes, keepPriority)

        after = getTrimmedRoutes(after.routes, keepPriority)
        expected = getTrimmedRoutes(expected.routes, keepPriority)

        print("=======after=========")
        print(after)
        print("=======expected=========")
        print(expected)

        self.assertEqual(after, expected)
Beispiel #2
0
def deriveAfterBgpMedChanged(_model: entities.Model, vpnTunnel: Union[entities.VPNTunnel, str],
                             MED_diff: int) -> entities.Model:
    """
    Will change the priority of all influenced routes, and propagate
    """
    model: entities.Model = entities.Model()
    model.CopyFrom(_model)

    if isinstance(vpnTunnel, str):
        vpnTunnel = findVpnTunnel(model, vpnTunnel)

    peerTunnel = findPeeringVpnTunnel(model, vpnTunnel)
    if not peerTunnel: return model

    routes = list(filter(lambda r: r.next_hop_tunnel == peerTunnel.url and r.from_local, model.routes))

    for route in routes:
        derivedRoutes = FindDerivedRoutes(model, route)
        print("===========Changing Priorities of Routes============")
        derivedRoutes.append(route)
        print(derivedRoutes)
        for r in derivedRoutes:
            r.priority += MED_diff

    return model
Beispiel #3
0
def deriveAfterVpnTunnelRemoval(_model: entities.Model, vpnTunnel: Union[entities.VPNTunnel, str]) -> entities.Model:
    """
    Will remove all learned routes and custom prefixes on this side, and propagate the removal
    """
    model: entities.Model = entities.Model()
    model.CopyFrom(_model)

    if isinstance(vpnTunnel, str):
        vpnTunnel = findVpnTunnel(model, vpnTunnel)

    peerTunnel = findPeeringVpnTunnel(model, vpnTunnel)
    if not peerTunnel: return model

    routes = list(filter(lambda r: r.next_hop_tunnel in [vpnTunnel.url, peerTunnel.url] and r.from_local, model.routes))

    for route in routes:
        derivedRoutes = FindDerivedRoutes(model, route)
        print("===========Deleting Routes============")
        derivedRoutes.append(route)
        print(derivedRoutes)
        for r in derivedRoutes:
            model.routes.remove(r)

    model.vpn_tunnels.remove(vpnTunnel)

    return model
Beispiel #4
0
def deriveAfterSubnetRemoved(_model: entities.Model, subnet: Union[entities.Subnet, str]) -> entities.Model:
    """
    the pre-requisite is that no instance is under this subnet.
    remove subnet routes in this network and peers, and remove a region, if this subnet is the last in the region
    """
    model: entities.Model = entities.Model()
    model.CopyFrom(_model)

    if isinstance(subnet, str):
        subnet = findSubnet(model, subnet)

    network = findNetwork(model, subnet.network)
    prefixes = [subnet.ipv4_range] + list(subnet.secondary_ranges)

    model.subnets.remove(subnet)
    if not next((s for s in model.subnets if s.network == subnet.network and s.region == subnet.region), None):
        network.regions.remove(subnet.region)

    routes = []
    for route in model.routes:
        if route.route_type == rules.Route.RouteType.SUBNET and route.dest_range in prefixes:
            routes.append(route)

    print("===========Root Routes============")
    print(routes)

    for route in routes:
        derivedRoutes = FindDerivedRoutes(model, route)
        print("===========Deleting Routes============")
        derivedRoutes.append(route)
        print(derivedRoutes)
        for r in derivedRoutes:
            model.routes.remove(r)

    return model
Beispiel #5
0
def deriveAfterBgpWithdrawals(_model: entities.Model, vpnTunnel: Union[entities.VPNTunnel, str],
                              prefixes: List[rules.Ipv4Range]) -> entities.Model:
    """
    When the other side withdrawals some prefixes, delete the derived routes on this side.
    The prefixes should be existing, and no prefix aggregation is done inside this function.
    """
    model: entities.Model = entities.Model()
    model.CopyFrom(_model)

    if isinstance(vpnTunnel, str):
        vpnTunnel = findVpnTunnel(model, vpnTunnel)

    routes = []
    for route in model.routes:
        if route.next_hop_tunnel == vpnTunnel.url and route.dest_range in prefixes and route.from_local:
            routes.append(route)

    print("===========Root Routes============")
    print(routes)

    for route in routes:
        derivedRoutes = FindDerivedRoutes(model, route)
        print("===========Deleting Routes============")
        derivedRoutes.append(route)
        print(derivedRoutes)
        for r in derivedRoutes:
            model.routes.remove(r)

    return model
Beispiel #6
0
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
Beispiel #7
0
    def test_integrity(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())

        rootRoutes = derivationFunctions.IdentifyRootRoutes(model)

        derivedRootRoutes = derivationFunctions.FindRootRoute(
            model, rootRoutes)

        self.assertEqual(derivedRootRoutes, rootRoutes)

        derived = derivationFunctions.Derive(model, rootRoutes)

        for routes in derived:
            for route in routes:
                self.assertTrue(route not in rootRoutes)

        flatten = lambda x: [y for l in x
                             for y in flatten(l)] if type(x) is list else [x]

        allRoutes = rootRoutes + flatten(derived)

        self.assertEqual(getTrimmedRoutes(allRoutes),
                         getTrimmedRoutes(model.routes))
Beispiel #8
0
def deriveAfterStaticRouteRemoved(_model: entities.Model, route: rules.Route) -> entities.Model:
    """
    Remove the static route and propagate to peers
    """
    model: entities.Model = entities.Model()
    model.CopyFrom(_model)

    for r in FindDerivedRoutes(model, route):
        model.routes.remove(r)
    model.routes.remove(route)

    return model
Beispiel #9
0
def deriveAfterStaticRouteAdded(_model: entities.Model, route: rules.Route) -> entities.Model:
    """
    Add the static route and propagate to peers
    """
    model: entities.Model = entities.Model()
    model.CopyFrom(_model)

    model.routes.append(route)

    Derive(model, [route])

    return model
Beispiel #10
0
    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()))
Beispiel #11
0
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
Beispiel #12
0
def deriveAfterIpRangeEnlarged(_model: entities.Model, subnet: Union[entities.Subnet, str],
                               ipRanges: List[Tuple[Union[rules.Ipv4Range, str], Union[rules.Ipv4Range, str]]]
                               ) -> entities.Model:
    """
    If ranges of a subnet is enlarged, then the corresponding routes are changed accordingly
    """
    model: entities.Model = entities.Model()
    model.CopyFrom(_model)

    if isinstance(subnet, str):
        subnet = findSubnet(model, subnet)

    for range, enlargedRange in ipRanges:
        if isinstance(range, str):
            range = ipv4StrToRange(range)
        if isinstance(enlargedRange, str):
            enlargedRange = ipv4StrToRange(enlargedRange)

        if subnet.ipv4_range == range:
            subnet.ipv4_range = enlargedRange
        else:  # this branch is not possible in the web interface. But we support this
            subnet.secondary_ranges.remove(range)
            subnet.secondary_ranges.append(enlargedRange)

        for route in model.routes:
            if route.route_type == rules.Route.RouteType.SUBNET and route.dest_range == range:
                derivedRoutes = FindDerivedRoutes(model, route)

                print("===========Enlarging Routes============")
                derivedRoutes.append(route)
                print(derivedRoutes)
                for r in derivedRoutes:
                    r.dest_range.ip = enlargedRange.ip
                    r.dest_range.mask = enlargedRange.mask

                break

    return model
Beispiel #13
0
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
Beispiel #14
0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from google.protobuf import text_format
import proto.cloud_network_model_pb2 as entities
import proto.rules_pb2 as rules

if __name__ == '__main__':
    with open("combined_model_0922_clear.pb", "r") as f:
        str = f.read()

        topo: entities.Model = text_format.Parse(str, entities.Model())

        copy = entities.Model()
        copy.CopyFrom(topo)

        subnet = entities.Subnet()

        subnet.id = "Deep copy"
        copy.subnets.append(subnet)
        subnet.id = "Shallow copy"

        print(copy.subnets[-1].id)
        copy.subnets[-1].id = 'Should show this'
        print(copy.subnets[-1].id)

        subnet = entities.Subnet()
Beispiel #15
0
        def justDerive(_model: entities.Model) -> entities.Model:
            model: entities.Model = entities.Model()
            model.CopyFrom(_model)

            derivationFunctions.Derive(model)
            return model