def ip_to_range(ip):
    """Attempt to map an IP into a range"""
    ip_type = resolve_ip_type(ip)

    ip_upper, ip_lower = one_to_two(ip_to_int(ip, ip_type[0]))
    # If it's within the uppers, it's definitely within the lowers
    upper_q = Q(
        ~Q(start_upper=F('end_upper')),
        start_upper__lte=ip_upper, end_upper__gte=ip_upper
    )

    # If the uppers match, look in the lowers
    lower_q = Q(
        Q(start_upper=F('end_upper')),
        start_lower__lte=ip_lower, end_lower__gte=ip_lower
    )
    try:
        return Range.objects.get(upper_q | lower_q)
    except Range.DoesNotExist:
        pass
Exemplo n.º 2
0
def integrate_real_ranges(network, template_ranges):
    """
    Say we have a network::

        10.8.0.0                                                     10.8.0.255
        |------------------------------------------------------....--|


    For every network there is (or should be) a range template. This breaks up
    the range into reservations that the user can then select from when finding
    a free ip address::

        10.8.0.0                                                     10.8.0.255
        |------------------------------------------------------....--|
         |--template--|             |------template-----|
         10.8.0.1     10.8.0.10     10.8.0.50           10.8.0.100


    "Template" ranges are not real objects in the database; they do not have
    detail pages, they do not show up in search, and they do not have primary
    keys. They are a simple *default* overlay onto a network's ip space.

    There is, however, a real version of a range that is stored in Inventory's
    database; it has a detail page, shows up in searches, and has a primary
    key. These range objects have a ``start`` and ``end`` ip address and have a
    foreign key back to a specific Inventory network object. They serve the
    same purpose as a template range except they are defined by the user via
    the GUI or invtool. Inventory makes sure that these real range objects are
    always within the bounds of their parent network and that no two ranges
    overlap.

    What happens to the template ranges when a real range is defined inside an
    Inventory network?

    For example::

        10.8.0.0                                                     10.8.0.255
        |------------------------------------------------------....--|
         |-- template --|           |----- user defined range -----|
         10.8.0.1     10.8.0.10     10.8.0.50                      10.8.0.100


    In this case both the template range and the user defined range is
    returned.

    Another example::

        10.8.0.0                                                     10.8.0.255
        |------------------------------------------------------....--|
                            |----- template ------|
                            10.8.0.15            10.8.0.60
         |-- template --|           |----- user defined range ----|
         10.8.0.1     10.8.0.10     10.8.0.50                      10.8.0.100

    In this case the overlapping template range is filtered out.


    This function looks at the ranges in the db and removed template ranges
    that overlap with real ranges. This function also injects the real ranges
    in with the template ranges.

    The return format is the same as :func:`calc_ranges`.
    """
    real_ranges = network.range_set.all()
    if not real_ranges:
        return template_ranges

    name_fragment = calc_name_fragment(network)
    dhcp_scope = network.calc_dhcp_scope_name()
    filtered_ranges = []
    no_ovlp_templates = []

    for tr in template_ranges:
        ol = False
        for r in real_ranges:
            ol = overlap(
                (r.start_str, r.end_str), (tr['start'], tr['end']),
                ip_type=network.ip_type, cast_to_int=True
            )
            if ol:
                break

        if not ol:
            no_ovlp_templates.append(tr)

    for r in real_ranges:
        filtered_ranges.append({
            'name': r.name,
            'rtype': r.name,
            'start': r.start_str,
            'end': r.end_str,
            'dhcp_scope': dhcp_scope,
            'name_fragment': name_fragment,
            'pk': r.pk
        })

    filtered_ranges += no_ovlp_templates

    return sorted(
        filtered_ranges, key=lambda r: ip_to_int(r['start'], network.ip_type)
    )
Exemplo n.º 3
0
def integrate_real_ranges(network, template_ranges):
    """
    Say we have a network::

        10.8.0.0                                                     10.8.0.255
        |------------------------------------------------------....--|


    For every network there is (or should be) a range template. This breaks up
    the range into reservations that the user can then select from when finding
    a free ip address::

        10.8.0.0                                                     10.8.0.255
        |------------------------------------------------------....--|
         |--template--|             |------template-----|
         10.8.0.1     10.8.0.10     10.8.0.50           10.8.0.100


    "Template" ranges are not real objects in the database; they do not have
    detail pages, they do not show up in search, and they do not have primary
    keys. They are a simple *default* overlay onto a network's ip space.

    There is, however, a real version of a range that is stored in Inventory's
    database; it has a detail page, shows up in searches, and has a primary
    key. These range objects have a ``start`` and ``end`` ip address and have a
    foreign key back to a specific Inventory network object. They serve the
    same purpose as a template range except they are defined by the user via
    the GUI or invtool. Inventory makes sure that these real range objects are
    always within the bounds of their parent network and that no two ranges
    overlap.

    What happens to the template ranges when a real range is defined inside an
    Inventory network?

    For example::

        10.8.0.0                                                     10.8.0.255
        |------------------------------------------------------....--|
         |-- template --|           |----- user defined range -----|
         10.8.0.1     10.8.0.10     10.8.0.50                      10.8.0.100


    In this case both the template range and the user defined range is
    returned.

    Another example::

        10.8.0.0                                                     10.8.0.255
        |------------------------------------------------------....--|
                            |----- template ------|
                            10.8.0.15            10.8.0.60
         |-- template --|           |----- user defined range ----|
         10.8.0.1     10.8.0.10     10.8.0.50                      10.8.0.100

    In this case the overlapping template range is filtered out.


    This function looks at the ranges in the db and removed template ranges
    that overlap with real ranges. This function also injects the real ranges
    in with the template ranges.

    The return format is the same as :func:`calc_ranges`.
    """
    real_ranges = network.range_set.all()
    if not real_ranges:
        return template_ranges

    name_fragment = calc_name_fragment(network)
    dhcp_scope = network.calc_dhcp_scope_name()
    filtered_ranges = []
    no_ovlp_templates = []

    for tr in template_ranges:
        ol = False
        for r in real_ranges:
            ol = overlap((r.start_str, r.end_str), (tr['start'], tr['end']),
                         ip_type=network.ip_type,
                         cast_to_int=True)
            if ol:
                break

        if not ol:
            no_ovlp_templates.append(tr)

    for r in real_ranges:
        filtered_ranges.append({
            'name': r.name,
            'rtype': r.name,
            'start': r.start_str,
            'end': r.end_str,
            'dhcp_scope': dhcp_scope,
            'name_fragment': name_fragment,
            'pk': r.pk
        })

    filtered_ranges += no_ovlp_templates

    return sorted(filtered_ranges,
                  key=lambda r: ip_to_int(r['start'], network.ip_type))