1
0
mirror of https://github.com/netbox-community/netbox.git synced 2024-05-10 07:54:54 +00:00
2020-02-21 15:26:55 -05:00

183 lines
5.2 KiB
Python

from django.db.models import IntegerField, Lookup, Transform, lookups
class NetFieldDecoratorMixin(object):
def process_lhs(self, qn, connection, lhs=None):
lhs = lhs or self.lhs
lhs_string, lhs_params = qn.compile(lhs)
lhs_string = 'TEXT(%s)' % lhs_string
return lhs_string, lhs_params
class IExact(NetFieldDecoratorMixin, lookups.IExact):
def get_rhs_op(self, connection, rhs):
return '= LOWER(%s)' % rhs
class EndsWith(NetFieldDecoratorMixin, lookups.EndsWith):
pass
class IEndsWith(NetFieldDecoratorMixin, lookups.IEndsWith):
pass
def get_rhs_op(self, connection, rhs):
return 'LIKE LOWER(%s)' % rhs
class StartsWith(NetFieldDecoratorMixin, lookups.StartsWith):
lookup_name = 'startswith'
class IStartsWith(NetFieldDecoratorMixin, lookups.IStartsWith):
pass
def get_rhs_op(self, connection, rhs):
return 'LIKE LOWER(%s)' % rhs
class Regex(NetFieldDecoratorMixin, lookups.Regex):
pass
class IRegex(NetFieldDecoratorMixin, lookups.IRegex):
pass
class NetContainsOrEquals(Lookup):
lookup_name = 'net_contains_or_equals'
def as_sql(self, qn, connection):
lhs, lhs_params = self.process_lhs(qn, connection)
rhs, rhs_params = self.process_rhs(qn, connection)
params = lhs_params + rhs_params
return '%s >>= %s' % (lhs, rhs), params
class NetContains(Lookup):
lookup_name = 'net_contains'
def as_sql(self, qn, connection):
lhs, lhs_params = self.process_lhs(qn, connection)
rhs, rhs_params = self.process_rhs(qn, connection)
params = lhs_params + rhs_params
return '%s >> %s' % (lhs, rhs), params
class NetContained(Lookup):
lookup_name = 'net_contained'
def as_sql(self, qn, connection):
lhs, lhs_params = self.process_lhs(qn, connection)
rhs, rhs_params = self.process_rhs(qn, connection)
params = lhs_params + rhs_params
return '%s << %s' % (lhs, rhs), params
class NetContainedOrEqual(Lookup):
lookup_name = 'net_contained_or_equal'
def as_sql(self, qn, connection):
lhs, lhs_params = self.process_lhs(qn, connection)
rhs, rhs_params = self.process_rhs(qn, connection)
params = lhs_params + rhs_params
return '%s <<= %s' % (lhs, rhs), params
class NetHost(Lookup):
lookup_name = 'net_host'
def as_sql(self, qn, connection):
lhs, lhs_params = self.process_lhs(qn, connection)
rhs, rhs_params = self.process_rhs(qn, connection)
# Query parameters are automatically converted to IPNetwork objects, which are then turned to strings. We need
# to omit the mask portion of the object's string representation to match PostgreSQL's HOST() function.
if rhs_params:
rhs_params[0] = rhs_params[0].split('/')[0]
params = lhs_params + rhs_params
return 'HOST(%s) = %s' % (lhs, rhs), params
class NetIn(Lookup):
lookup_name = 'net_in'
def get_prep_lookup(self):
# Don't cast the query value to a netaddr object, since it may or may not include a mask.
return self.rhs
def as_sql(self, qn, connection):
lhs, lhs_params = self.process_lhs(qn, connection)
rhs, rhs_params = self.process_rhs(qn, connection)
with_mask, without_mask = [], []
for address in rhs_params[0]:
if '/' in address:
with_mask.append(address)
else:
without_mask.append(address)
address_in_clause = self.create_in_clause('{} IN ('.format(lhs), len(with_mask))
host_in_clause = self.create_in_clause('HOST({}) IN ('.format(lhs), len(without_mask))
if with_mask and not without_mask:
return address_in_clause, with_mask
elif not with_mask and without_mask:
return host_in_clause, without_mask
in_clause = '({}) OR ({})'.format(address_in_clause, host_in_clause)
with_mask.extend(without_mask)
return in_clause, with_mask
@staticmethod
def create_in_clause(clause_part, max_size):
clause_elements = [clause_part]
for offset in range(0, max_size):
if offset > 0:
clause_elements.append(', ')
clause_elements.append('%s')
clause_elements.append(')')
return ''.join(clause_elements)
class NetHostContained(Lookup):
"""
Check for the host portion of an IP address without regard to its mask. This allows us to find e.g. 192.0.2.1/24
when specifying a parent prefix of 192.0.2.0/26.
"""
lookup_name = 'net_host_contained'
def as_sql(self, qn, connection):
lhs, lhs_params = self.process_lhs(qn, connection)
rhs, rhs_params = self.process_rhs(qn, connection)
params = lhs_params + rhs_params
return 'CAST(HOST(%s) AS INET) << %s' % (lhs, rhs), params
class NetFamily(Transform):
lookup_name = 'family'
function = 'FAMILY'
@property
def output_field(self):
return IntegerField()
class NetMaskLength(Transform):
function = 'MASKLEN'
lookup_name = 'net_mask_length'
@property
def output_field(self):
return IntegerField()
class Host(Transform):
function = 'HOST'
lookup_name = 'host'
class Inet(Transform):
function = 'INET'
lookup_name = 'inet'