class IPPolicyCIDR(BASEV2, HasId): __tablename__ = "quark_ip_policy_cidrs" ip_policy_id = sa.Column(sa.String(36), sa.ForeignKey( "quark_ip_policy.id", ondelete="CASCADE")) cidr = sa.Column(sa.String(64)) first_ip = sa.Column(custom_types.INET()) last_ip = sa.Column(custom_types.INET())
class Subnet(BASEV2, models.HasId, models.HasTenant, IsHazTags): """Upstream model for IPs. Subnet -> has_many(IPAllocationPool) IPAllocationPool -> has_many(IPAvailabilityRange) As well as first and last _ip markers for some unknown reason first_ip is min(ranges), last_ip is max(ranges) IPAvailabilityRange -> belongs_to(IPAllocationPool) Also has first and last _ip, but only for the range IPAllocation -> belongs_to(port, subnet, network) but NOT IPAllocationPool IPAllocationPool and Range seem superfluous. Just create intelligent CIDRs for your subnet """ __tablename__ = "quark_subnets" name = sa.Column(sa.String(255)) network_id = sa.Column(sa.String(36), sa.ForeignKey('quark_networks.id')) _cidr = sa.Column(sa.String(64), nullable=False) @hybrid.hybrid_property def cidr(self): return self._cidr @cidr.setter def cidr(self, val): self._cidr = val preip = netaddr.IPNetwork(val) self.ip_version = preip.version ip = netaddr.IPNetwork(val).ipv6() self.first_ip = ip.first self.last_ip = ip.last self.next_auto_assign_ip = self.first_ip @cidr.expression def cidr(cls): return Subnet._cidr first_ip = sa.Column(custom_types.INET()) last_ip = sa.Column(custom_types.INET()) ip_version = sa.Column(sa.Integer()) next_auto_assign_ip = sa.Column(custom_types.INET()) allocated_ips = orm.relationship(IPAddress, primaryjoin='and_(Subnet.id==' 'IPAddress.subnet_id, ' 'IPAddress._deallocated!=1)', backref="subnet") routes = orm.relationship(Route, primaryjoin="Route.subnet_id==Subnet.id", backref='subnet', cascade='delete') enable_dhcp = sa.Column(sa.Boolean(), default=False) dns_nameservers = orm.relationship( DNSNameserver, primaryjoin="DNSNameserver.subnet_id==Subnet.id", backref='subnet', cascade='delete') ip_policy = orm.relationship("IPPolicy", uselist=False, backref="subnet")
class IPPolicy(BASEV2, models.HasId, models.HasTenant): __tablename__ = "quark_ip_policy" networks = orm.relationship( "Network", primaryjoin="IPPolicy.id==Network.ip_policy_id", backref="ip_policy") subnets = orm.relationship( "Subnet", primaryjoin="IPPolicy.id==Subnet.ip_policy_id", backref="ip_policy") exclude = orm.relationship( "IPPolicyCIDR", primaryjoin="IPPolicy.id==IPPolicyCIDR.ip_policy_id", backref="ip_policy") name = sa.Column(sa.String(255), nullable=True) description = sa.Column(sa.String(255), nullable=True) size = sa.Column(custom_types.INET()) @staticmethod def get_ip_policy_cidrs(subnet): ip_policy = subnet["ip_policy"] or {} ip_policies = ip_policy.get("exclude", []) ip_policy_cidrs = [ip_policy_cidr.cidr for ip_policy_cidr in ip_policies] return netaddr.IPSet(ip_policy_cidrs)
class IPAddress(BASEV2, models.HasId): """More closely emulate the melange version of the IP table. We always mark the record as deallocated rather than deleting it. Gives us an IP address owner audit log for free, essentially. """ __tablename__ = "quark_ip_addresses" __table_args__ = (sa.UniqueConstraint("subnet_id", "address", name="subnet_id_address"), TABLE_KWARGS) address_readable = sa.Column(sa.String(128), nullable=False) address = sa.Column(custom_types.INET(), nullable=False, index=True) subnet_id = sa.Column(sa.String(36), sa.ForeignKey("quark_subnets.id", ondelete="CASCADE")) network_id = sa.Column(sa.String(36), sa.ForeignKey("quark_networks.id", ondelete="CASCADE")) version = sa.Column(sa.Integer(), index=True) allocated_at = sa.Column(sa.DateTime()) subnet = orm.relationship("Subnet") # Need a constant to facilitate the indexed search for new IPs _deallocated = sa.Column(sa.Boolean()) # Legacy data used_by_tenant_id = sa.Column(sa.String(255)) @hybrid.hybrid_property def deallocated(self): return self._deallocated and not self.ports @deallocated.setter def deallocated(self, val): self._deallocated = val self.deallocated_at = None if val: self.deallocated_at = timeutils.utcnow() self.allocated_at = None # TODO(jkoelker) update the expression to use the jointable as well @deallocated.expression def deallocated(cls): return IPAddress._deallocated def formatted(self): ip = netaddr.IPAddress(self.address_readable) if self.version == 4: return str(ip.ipv4()) return str(ip.ipv6()) deallocated_at = sa.Column(sa.DateTime(), index=True)
class Subnet(BASEV2, HasId, IsHazTags, HasTenant): """Upstream model for IPs. Subnet -> has_many(IPAllocationPool) IPAllocationPool -> has_many(IPAvailabilityRange) As well as first and last _ip markers for some unknown reason first_ip is min(ranges), last_ip is max(ranges) IPAvailabilityRange -> belongs_to(IPAllocationPool) Also has first and last _ip, but only for the range IPAllocation -> belongs_to(port, subnet, network) but NOT IPAllocationPool IPAllocationPool and Range seem superfluous. Just create intelligent CIDRs for your subnet """ __tablename__ = "quark_subnets" id = sa.Column(sa.String(36), primary_key=True) name = sa.Column(sa.String(255)) network_id = sa.Column(sa.String(36), sa.ForeignKey('quark_networks.id')) _cidr = sa.Column(sa.String(64), nullable=False) _allocation_pool_cache = orm.deferred(sa.Column(sa.Text(), nullable=True)) segment_id = sa.Column(sa.String(255), index=True) @hybrid.hybrid_property def cidr(self): return self._cidr @hybrid.hybrid_property def allocation_pools(self): _cache = self.get("_allocation_pool_cache") if _cache: pools = json.loads(_cache) return pools else: if self["ip_policy"]: ip_policy_cidrs = self["ip_policy"].get_cidrs_ip_set() else: ip_policy_cidrs = netaddr.IPSet([]) cidr = netaddr.IPSet([netaddr.IPNetwork(self["cidr"])]) allocatable = cidr - ip_policy_cidrs pools = _pools_from_cidr(allocatable) return pools @cidr.setter def cidr(self, val): self._cidr = val preip = netaddr.IPNetwork(val) self.ip_version = preip.version ip = netaddr.IPNetwork(val).ipv6() self.first_ip = ip.first self.last_ip = ip.last self.next_auto_assign_ip = self.first_ip @cidr.expression def cidr(cls): return Subnet._cidr first_ip = sa.Column(custom_types.INET()) last_ip = sa.Column(custom_types.INET()) ip_version = sa.Column(sa.Integer()) next_auto_assign_ip = sa.Column(custom_types.INET()) allocated_ips = orm.relationship(IPAddress, primaryjoin='and_(Subnet.id==' 'IPAddress.subnet_id,' 'IPAddress._deallocated != 1)') generated_ips = orm.relationship(IPAddress, primaryjoin='Subnet.id==' 'IPAddress.subnet_id') routes = orm.relationship(Route, primaryjoin="Route.subnet_id==Subnet.id", backref='subnet', cascade='delete') enable_dhcp = sa.Column(sa.Boolean(), default=False) dns_nameservers = orm.relationship( DNSNameserver, primaryjoin="DNSNameserver.subnet_id==Subnet.id", backref='subnet', cascade='delete') ip_policy_id = sa.Column(sa.String(36), sa.ForeignKey("quark_ip_policy.id")) # Legacy data do_not_use = sa.Column(sa.Boolean(), default=False)
class DNSNameserver(BASEV2, HasTenant, HasId, IsHazTags): __tablename__ = "quark_dns_nameservers" ip = sa.Column(custom_types.INET()) subnet_id = sa.Column(sa.String(36), sa.ForeignKey("quark_subnets.id", ondelete="CASCADE"))
class IPAddress(BASEV2, HasId): """More closely emulate the melange version of the IP table. We always mark the record as deallocated rather than deleting it. Gives us an IP address owner audit log for free, essentially. """ __tablename__ = "quark_ip_addresses" __table_args__ = (sa.UniqueConstraint("subnet_id", "address", name="subnet_id_address"), TABLE_KWARGS) address_readable = sa.Column(sa.String(128), nullable=False) address = sa.Column(custom_types.INET(), nullable=False, index=True) subnet_id = sa.Column(sa.String(36), sa.ForeignKey("quark_subnets.id", ondelete="CASCADE")) network_id = sa.Column(sa.String(36), sa.ForeignKey("quark_networks.id", ondelete="CASCADE")) network = orm.relationship("Network") version = sa.Column(sa.Integer(), index=True) allocated_at = sa.Column(sa.DateTime()) subnet = orm.relationship("Subnet") # Need a constant to facilitate the indexed search for new IPs _deallocated = sa.Column(sa.Boolean()) # Legacy data used_by_tenant_id = sa.Column(sa.String(255)) address_type = sa.Column(sa.Enum(ip_types.FIXED, ip_types.FLOATING, ip_types.SHARED, ip_types.SCALING, name="quark_ip_address_types")) associations = orm.relationship(PortIpAssociation, backref="ip_address") transaction_id = sa.Column(sa.Integer(), sa.ForeignKey("quark_transactions.id"), nullable=True) lock_id = sa.Column(sa.Integer(), sa.ForeignKey("quark_locks.id"), nullable=True) def is_shared(self): return self.address_type == ip_types.SHARED def has_any_shared_owner(self): for assoc in self["associations"]: if assoc.service != 'none' and assoc.service is not None: return True return False def set_service_for_port(self, port, service): for assoc in self["associations"]: if assoc.port_id == port["id"]: assoc.service = service def get_service_for_port(self, port): for assoc in self["associations"]: if assoc.port_id == port["id"]: return assoc.service def enabled_for_port(self, port): for assoc in self["associations"]: if assoc.port_id == port["id"]: return assoc.enabled @hybrid.hybrid_property def deallocated(self): return self._deallocated and not self.ports @deallocated.setter def deallocated(self, val): self._deallocated = val self.deallocated_at = None if val: self.deallocated_at = timeutils.utcnow() self.allocated_at = None # TODO(jkoelker) update the expression to use the jointable as well @deallocated.expression def deallocated(cls): return IPAddress._deallocated def formatted(self): ip = netaddr.IPAddress(self.address_readable) if self.version == 4: return str(ip.ipv4()) return str(ip.ipv6()) deallocated_at = sa.Column(sa.DateTime(), index=True) fixed_ip = None
def setUp(self): super(TestDBCustomTypesINET, self).setUp() self.inet = custom_types.INET()
class IPPolicyRule(BASEV2, models.HasId): __tablename__ = "quark_ip_policy_rules" ip_policy_id = sa.Column( sa.String(36), sa.ForeignKey("quark_ip_policy.id", ondelete="CASCADE")) address = sa.Column(custom_types.INET()) prefix = sa.Column(sa.Integer())