Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

This is the initial commit of the docs found in the original project.…

… Doing 'make html' won't work because the paths referenced in the docs are not correct and will be fixed when we decide on definite module path names.
  • Loading branch information...
commit 6a5c287b4579ac0cf971c437e2d68d3c040b4807 1 parent 66d883c
@uberj uberj authored
View
6 docs/BIND.rst
@@ -0,0 +1,6 @@
+.. _bind:
+
+Bind Files
+==========
+.. automodule:: mozdns.mozbind.build
+ :inherited-members:
View
53 docs/DHCP.rst
@@ -0,0 +1,53 @@
+.. _dhcp:
+.. |intr_ref| replace:: :ref:`StaticInterface`
+.. |intr| replace:: :class:`StaticInterface`
+.. |range| replace:: :class:`Range`
+
+DHCP
+====
+
+.. warning::
+ DHCP is implemented for |intr_ref| objects with IPv4 addresses. |intr|'s with IPv6 addresses
+ will not be included in the build output.
+
+The core function of the DHCP build system is the :func:`build_subnet` function which accecpts a
+:ref:`Network` instance as it's only input. Using the ``network``'s network address
+(``network_start``) and network broadcast (``network_end``) every |intr| with an IPv4 address
+greater than ``network_start`` less than ``network_end`` is used to generate a ``host`` statement::
+
+ host {{ intr.dhcp_name() }} {
+ hardware ethernet {{ intr.mac }};
+ fixed-address {{ intr.ip_str }};
+ }
+
+The above example is a ``host`` statement where jinja2 syntax is used to show how data from the
+|intr| is used to fill in data. The |intr| member function :func:`dhcp_name` is used as a way to
+make sure no two ``host`` statements have the same ``hostname``.
+
+.. note::
+
+ Because we are on a tight schedule, it might be worth it to just generate the host entries and
+ include them in the DHCP flat files in SVN like we are doing with current inventory. This would
+ be a slight modification and would save us time. Doing this means we don't have to put pool and
+ subnet options into inventory (could be time consuming sinse they are hard to parse and would
+ probably need to be entered by hand).
+
+Address Pools
+---------------
+There is a 1-to-1 mapping betweek address pools and :ref:`range` objects. A |range| object has a
+reference back to it's containing :ref:`Network`, so :func:`build_subnet` selects all |range|
+objects and passes the objects one by one into :func:`build_pool`. For each range all statements and
+options are gathered and added to the build output. Finally ``range.start_lower`` and
+``range.end_lower`` are used as the start and end number in the ``range`` statement (``start_upper``
+and ``end_upper`` are only relevent for IPv6 addresses who have more than 64 bits of information).
+
+DHCP Options and Statements
+---------------------------
+
+Both ranges and networks have ways of controlling what options and statements go into their
+respective ``subnet`` and ``pool`` statements. These options and statements are stored in the
+:class:`NetworkKeyValue` and :class:`RangeKeyValue` tables as Key Value pairs.
+
+
+.. autofunction:: core.build.subnet.build_subnet
+.. autofunction:: core.build.subnet.build_pool
View
7 docs/address_record.rst
@@ -0,0 +1,7 @@
+.. _address_record:
+
+Address Record
+==============
+.. automodule:: mozdns.address_record.models
+ :inherited-members:
+
View
75 docs/api.rst
@@ -0,0 +1,75 @@
+Inventory DNS API
+=================
+
+A high level view of how the API works::
+
+ +------+
+ | User |
+ +------+
+ |
+ +------------------------+
+ | Command Line Interface | <----------- See page on CLI for this
+ +------------------------+
+ |
+ +---------------+
+ | HTTP POST/GET | <----------- This document defines what is happening here.
+ +---------------+
+ |
+ +----------+
+ | Iventory |
+ +----------+
+ |
+ +----------+
+ | Database |
+ +----------+
+
+DNS Objects
+-----------
+The following DNS objects can be created, updated, and deleted via HTTP API requests.
+
+ * A records
+ * AAAA records
+ * CNAME records
+ * TXT records
+ * MX records
+ * SRV records
+ * NS records
+ * SSHFP records
+
+The following cannot be created, updated, or deleted via HTTP API requests.
+
+ * SOA records
+ * Certain Domain objects
+ - see :ref:`label_domain`. Only purgeable domains can be created via the API.
+
+Views and Key Value
+-------------------
+View objects need their associated object to exist before they can be created. Underneath the hood,
+these objects are validated and saved *after* their associtated object is saved or updated.
+
+Currently, updating views is done by supplying the desired objects' state. For example, if you
+want to add an object to the public view and the object was already in the private view, you would
+post the list::
+
+ 'views': ['public', 'private']
+
+If you were to send an emtry list::
+
+ 'views': []
+
+Any views the object was associated with would be deleted.
+
+The best way to update an object is to first GET the object, modify the JSON returned by the API,
+and then PATCH it back.
+
+Key Value Pairs
+---------------
+Updating key value (kv) pairs that are associated with an object is done just like any other
+attribute on the object except it must be done with only the 'key' and 'value' parameters in the
+request. This means that updating a field, like 'comment', and a key value pair is not allowed::
+
+ {'key': 'foo', 'value': 'bar', 'comment': 'a new comment'}
+
+The above is not allowed because 'key' and 'value' must be the only elements in the JSON.
+
+You should post kv pairs to the end point of the object is associated to the kv pair.
View
17 docs/cname.rst
@@ -0,0 +1,17 @@
+.. _cname:
+
+CNAME
+=====
+
+ "Don't go overboard with CNAMEs."
+
+ "Domain names in RRs which point at another name should always point at the primary name and not the
+ alias."
+
+ -- `RFC 1034 <http://tools.ietf.org/html/rfc1034>`_
+
+
+CNAME
+-----
+.. automodule:: mozdns.cname.models
+ :inherited-members:
View
40 docs/coding_standard.rst
@@ -0,0 +1,40 @@
+.. _coding_standards:
+
+Coding Ideas (Standards)
+========================
+
+The Zen of Python, by Tim Peters::
+
+ Beautiful is better than ugly.
+ Explicit is better than implicit.
+ Simple is better than complex.
+ Complex is better than complicated.
+ Flat is better than nested.
+ Sparse is better than dense.
+ Readability counts.
+ Special cases aren't special enough to break the rules.
+ Although practicality beats purity.
+ Errors should never pass silently.
+ Unless explicitly silenced.
+ In the face of ambiguity, refuse the temptation to guess.
+ There should be one-- and preferably only one --obvious way to do it.
+ Although that way may not be obvious at first unless you're Dutch.
+ Now is better than never.
+ Although never is often better than *right* now.
+ If the implementation is hard to explain, it's a bad idea.
+ If the implementation is easy to explain, it may be a good idea.
+ Namespaces are one honking great idea -- let's do more of those!
+
+
+Follow pep8::
+
+ pip install pep8
+ pep8 <all of the files!!>
+
+Model code should have 100% statement coverage.
+
+Before you do anything with an IP address (as a string or int) put it into the ipaddr library
+functions IPv4Address and IPv6Address. This will standardize how things are formated, stored, and
+displayed.
+
+In most cases policy should happen in forms and function should happen in models.
View
13 docs/common_record.rst
@@ -0,0 +1,13 @@
+.. _common_record:
+
+Common Record
+=============
+
+The common record class is inherited by common DNS record classes. ``CommonRecord`` is an abstract class meaning there is not table in the database coresponding to it's declaration. It is subclassed by the ``TXT``, ``MX``, ``CNAME``, and ``SRV`` classes.
+
+
+.. automodule:: mozdns.models
+ :inherited-members:
+
+.. automodule:: mozdns.views
+ :inherited-members:
View
2  docs/conf.py
@@ -17,7 +17,7 @@
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
-#sys.path.insert(0, os.path.abspath('.'))
+sys.path.insert(0, os.path.abspath('.'))
# -- General configuration -----------------------------------------------------
View
93 docs/core.rst
@@ -0,0 +1,93 @@
+.. _core:
+
+IPAM
+====
+A system that manages DNS and DHCP is useless without knowledge of the networks
+the hosts using DNS and DHCP are located in. The core of inventory is it's
+:class:`Site`\s, :class:`Network`\s, and :class:`Range`\s.
+
+Sites
+-----
+A :ref:`site` represents a datacenter or a business unit. Much like
+:ref:`domain`\s are organized into a hierarchy with 'master domains', a site
+can have a 'parent site'.
+
+
+.. figure:: images/mozcore_sites.png
+
+Here four sites are shown. Scl3 is the parent site of Releng and Phx1 is the
+Parent site of Svc. If Relenge were also in Scl2, there would be another
+instance of a site called Relenge that had a parent site of Scl2.
+
+Networks
+--------
+A :ref:`network` represents an IPv4/IPv6 network. Networks also related to eachother in a heirarchical way. Since networks are inherently contained within other networks, no explicit parent child relationship is stored in the database. Networks are homed in a site.
+
+
+.. figure:: images/mozcore_networks.png
+
+Here networks are laid out along their logical CIDER boundaries. Multiple networks can
+be associated with one site, but a network cannot be associated with multiple
+sites.
+
+Vlans
+-----
+
+For the majority of cases, a network is associated with a :ref:`vlan`.
+
+.. figure:: images/mozcore_all.png
+
+Here networks are shown under vlans. A network can belong to zero or one vlan.
+Many networks can belong to the same vlan.
+
+The little red lines under the network objects are :ref:`range` objects.
+
+Ranges
+------
+
+Range objects belong inside of a network; a range's start number is greater than or equal to the
+network address and the range's end number is less than the broadcast address. Ranges are used to
+help determine where free IP's lay within a network, which is useful when creating a
+:ref:`staticinterface`.
+
+Here is a beautiful depiction of a range and a network::
+
+ Network: 192.168.0.0/24
+ |--------------------------------------------------------------|
+ 192.168.0.0 192.168.0.255
+
+ Range:
+ |-------------------------------------------------|
+ 192.168.0.10 192.168.0.254
+
+
+Ranges can be used as a pool of allocatable IP addresses. When a new :ref:`staticinterface`
+(seriously, read about these things) is created it needs an IP address and a range is where the
+interface will look if the interface is to have it's IP address assigned automatically.
+
+Other Purposes
+++++++++++++++
+
+.. note::
+ These features (as of 08/12/2012) are not implemented.
+
+Ranges are multipurpose. For example a range can be used as a 'dynamic' range. A dynamic range is a
+pool ip addresses where wireless clients or other clients that don't need a fixed addresses have
+their IP assignment come from. In DHCP these dynamic ranges usually associated with a pool statement
+that contains an ``allow`` clause. In DNS a dynamic range will usually have a long list of similar
+names statically created for every ip in the range; for example ``GENERATE 4-100
+dynamic-$.vlan.mozilla.com``. When you flag a range as 'dynamic' the DNS build scripts will
+automatically print these records when DNS zone files are generated.
+
+
+
+
+
+
+
+
+
+
+
+
+
View
45 docs/cyder_intro.rst
@@ -0,0 +1,45 @@
+`Cyder <https://github.com/uberj/Cyder>`_ is an `IPAM <http://en.wikipedia.org/wiki/IP_address_management>`_ solution. It is split up into two logically separate apps; ``cydns`` (DNS) and ``cydhcp`` (DHCP). The goal is two have the two apps be standalone and have less generic code 'glue' them together.
+
+The 'glue' (not to be confused with DNS glue records) is found in ``core/``.
+
+Maintain
+--------
+Cyder is designed to replace `Maintain <http://maintainproject.osuosl.org/>`_. Maintain 2.5 was the
+last version released. Maintain 3 was written in purely in PHP and didn't work too well.
+Aside from initially being written almost a decade ago, Maintain has been used in production at OSU
+for over 10 years.
+
+Taken from Maintain's README, here are the abridged requirements of Maintain:
+
+* Web-based interface
+* Ability to delegate authority of zone information to individual users/groups
+* Quick updates (changes need to be reflected within 10 minutes)
+* Advanced error reporting for zone transfers and DHCP server problems
+* Generate zone files and DHCP configurations for primary and secondary DNS & DHCP servers
+* Edit host information including MAC address, hostname, domain name, etc.
+* Zone statistics such as total bandwidth used and bandwidth history for individual hosts
+* Support for automatic registration on public networks (using authentication)
+* Search by hostname, domain, zone, IP address and any other DNS type
+* Ability to develop additional features through a module interface
+
+Cyder will have all of these features and more.
+
+Maintain Bugs
++++++++++++++
+* DNSSEC is not supported.
+* Certain DNS records that were at domain level were not supported (they have been hacked in).
+* No support of other DNS output types. Only ``tinydns`` is supported.
+* The following DNS record types are not supported ``SRV``, ``TXT``, (more)?
+* DNS Zone delegation is broken.
+* When a (maintain) zone administrator wants to manually assign an IP address to a client, DHCP needs to be bypassed.
+ Maintian does this by providing a mac with all zeroes. It's a kludge.
+* There can be several different ``defualt_domains`` assigned to the same range.
+* Poor searching capabilities.
+* Maintain was not built with a web framework. Ironically, this makes the code very hard to maintain.
+* Written in PHP.
+
+Maintain has it's weaknesses, but overall it does get the job done. It has already been shown that
+Maintain's existing DNS scheme *does* `support building bind files
+<https://github.com/uberj/maintain-bindbuilds>`_ (some modification to data in the database was
+required due to poor data validation). Cyder is Maintain with a more formal structure. Cyder uses
+many core concepts from Maintain.
View
289 docs/dns_views.rst
@@ -0,0 +1,289 @@
+.. _dns_views:
+.. |project| replace:: cyder
+.. |org| replace:: Oregon State
+
+View
+====
+
+ The Internet Assigned Numbers Authority (IANA) has reserved the
+ following three blocks of the IP address space for private internets
+
+ 10.0.0.0 - 10.255.255.255 (10/8 prefix)
+
+ 172.16.0.0 - 172.31.255.255 (172.16/12 prefix)
+
+ 192.168.0.0 - 192.168.255.255 (192.168/16 prefix)
+
+ -- `RFC 1918 <http://www.ietf.org/rfc/rfc1918.txt>`_
+
+ At the present time, AAAA and PTR records for locally assigned local IPv6
+ addresses (fc00::/7) are not recommended to be installed in the global DNS.
+
+ -- `RFC 4193 <http://tools.ietf.org/html/rfc4193>`_
+
+|project| has built in support for classifying records into different views. By default |project|
+supports two views ``public`` and ``private``. Records can be classified three different ways.
+
+ 1) public only
+
+ 2) private only
+
+ 3) public and private
+
+When a record is in class 1, it is accessible from the internet, including |org|'s external facing
+machines, but not accessible from inside of |org|'s internal network.
+
+When a record is in class 2, it is accessible from within |org|'s private network but not accessible
+from the internet which includes |org|'s external facing machines.
+
+When a record is in class 3, it is accessible from within |org|'s private network and from the
+internet; if you can ping the nameserver, you have access to the record and it's data.
+
+
+Enforcing RFC 1918
+------------------
+It is important that data that is considered 'internal' not be allowed into any view with public
+facing data. RFC 1918 says that certain ip's should not be allowed into public DNS space. |project|
+enforces these restrictions.
+
+If an :ref:`address_record`/:ref:`staticinterface` record points to an IP that is in a network
+specified in RFC 1918, it is not allowed to be part of a public view.
+
+If a :ref:`ptr` record points to an IP that is in a network specified in RFC 1918, it is not allowed
+to be part of a public view.
+
+
+.. note::
+ This CNAME requirement is probably not going to be implemented right away. Since an A/PTR will
+ return a NXDOMAIN in a view that they are not a part of there is not too much of an information
+ leek if a CNAME resolves to a missing record.
+
+If a :ref:`CNAME`, :ref:`SRV`, or :ref:`MX` has a canonical name that has the type :class:`A`,
+:class:`PTR`, or :class:`StaticInterface` and has an IP within one of the networks specified in RFC
+1918, it is not allowed to be part of a public view::
+
+ foo CNAME bar bar A 10.0.0.1
+
+ ^ ^
+ | |
+ +-- foo is tagged as a public CNAME +-- bar is tagged as private only
+
+
+All other records are allowed to be in any combination of views.
+
+Split Horizon
+-------------
+Split Horizon records are when a name server returns different data for a record depending on whether
+you are coming from the Internet or from the Intranet.
+
+Here is an example of a split horizon record: assume a record has a name X. When X is queried from
+the internet some data Y is returned by the name server. When X is queried from an internal network
+some data Z is returned by the name server. If X != Y, then this is a split horizon record.
+
+A common use case of split horizon records is when you want a host's name to resolve to a private
+address when a query is coming from a trusted private network and a public address when the query is
+coming from an untrusted public network. The split horizon record helps facilitate untrusted
+public flows first going through some sort of firewall while directing queries from a trusted private
+network to an internal non-firewalled ip address.
+
+Usings Views
+============
+
+Every record that can exist in a zone file has an attribute ``views`` that can be used to manage
+which views the record is in.::
+
+ A = AddressRecord.objects.get(fqdn="somehost.example.com")
+ cname = CNAME.objects.get(fqdn="www.somehost.example.com")
+ ptr = PTR.objects.get(name="somehost.example.com")
+
+Here we have retrieved a few objects from our hypothetical database. By default these objects are
+not put into DNS views and will not be included in the zone file for that view.
+
+.. note::
+ If you want a record to be in the output of a zone file, you probably need to assign it to a
+ view. Usually this is either the 'private' or 'public' view.
+
+For the sake of example, let's create and then get a view from the hypothetical database::
+
+ from mozdns.view.models import View
+ private = View(name="private")
+ private.save()
+
+If the view already existed in the database we would do this::
+
+ private = View.objects.get(name="private")
+
+If we wanted to add some of our records to the ``private`` view, we would use the ``views`` attribute on an
+object::
+
+ A.views.add(private)
+ A.save()
+
+ cname.views.add(private)
+ cname.save()
+
+Objects can be in more than one view::
+
+ public, _ = View.objects.get_or_create(name="public")
+
+ A.views.add(public)
+ A.save()
+
+At this point the ``A`` record for ``somehost.example.com`` would be included in the public and
+private views.
+
+For more information see `Django Many to Many Fields <https://docs.djangoproject.com/en/dev/topics/db/examples/many_to_many/>`_.
+
+.. note::
+ The rest of this page is mostly notes.
+
+DNS Views
+---------
+It is highly likely that some records should be viewable from one network and
+not visable from another. To do this use bind DNS views.
+
+The nameserver conf file::
+
+ view "internal-view" {
+ match-clients { 128.193.0.0/16; 10.0.0.0/8 };
+ zone "foo.com" IN {
+ type master;
+ file "zones/db.foo.com.internal";
+ };
+ };
+
+ view "external-view" {
+ match-clients { any; };
+ zone "foo.com" IN {
+ type master;
+ file "zones/db.foo.com.external";
+ };
+ ...
+ ... (More zone statements)
+ ...
+ };
+
+The zone files::
+
+ FILE: db.foo.com.soa
+ @ 1D IN SOA ns1.foo.com hostmaster.foo.com (
+ 1;
+ 2;
+ 3;
+ 4;
+ 5;
+ )
+
+ FILE: db.foo.com.data.external
+
+ @ IN NS ns1.foo.com
+ @ MX 10 mail.foo.com
+ ns1 A 128.193.1.4
+ mail A 128.193.1.5
+
+ FILE: db.foo.com.data.internal
+
+ bob A 10.0.0.2
+ mary A 10.0.0.3
+
+The external zone file::
+
+ FILE: db.foo.com.external
+
+ $INCLUDE db.foo.com.soa
+ $INCLUDE db.foo.com.external
+
+The internal zone file::
+
+ FILE: db.foo.com.internal
+
+ $INCLUDE db.foo.com.soa
+ $INCLUDE db.foo.com.data.external
+ $INCLUDE db.foo.com.data.internal
+
+Questions:
+
+.. note::
+ Views are being introduced later in the design of the DNS side of cyder.
+
+`How will views be represented in the database?`
+
+A new table called 'views' will be created. This table will have entries that
+represent different views. Here is the planed scheme::
+
+ +------------------+--------------+------+-----+---------+----------------+
+ | Field | Type | Null | Key | Default | Extra |
+ +------------------+--------------+------+-----+---------+----------------+
+ | id | int(11) | NO | PRI | NULL | auto_increment |
+ | name | varchar(100) | NO | UNI | NULL | |
+ | comment | varchar(255) | NO | UNI | NULL | |
+ +------------------+--------------+------+-----+---------+----------------+
+
+`Who/How will you create/delete a View?`
+
+Only super admins should be able to create/delete views. To create a view an
+admin would add en entry to the view table. To a delete a view no objects can
+reference that view.
+
+`Changes to models.`
+
+Models that belong to views will need to be tied to views in the database.
+This should be done with a many-to-many table between views and records::
+
+ +-----+--------+ +-----+------+ +----+-------------+
+ | id | Record | | Rec | View | | id | View |
+ +-----+--------+ +-----+------+ +----+-------------+
+ | 1 | A | | 1 | 1 | | 1 | Public |
+ | 2 | A | | 1 | 2 | | 2 | Private |
+ | 3 | A | | 1 | 3 | | 3 | DataCenter |
+ | 4 | A | | 2 | 1 | +----+-------------+
+ +-----+--------+ | 3 | 3 |
+ | 4 | 3 |
+ +-----+------+
+
+Here four :class:`AddressRecord` objects are being used to show how records relate
+to views. Instead of keeping which view a record belongs to in the table that
+the record is defined, a second intermediate table is used to link the records
+to a view. In this example there are three views: `Public`, `Private`, and
+`DataCenter`. The first A record is in all three of the views. The second A
+record is in just the `Public` view and the third and fourth A records are only
+in the `DataCenter` View.
+
+The above example illustrated how the :class:`AddressRecord` type would be
+linked to a view. Because the intermediate table relies on an object's primary
+key, two different objects types cannot share the same intermediate table. `Each
+record type will need it's own intermediate table`.
+
+`How does a record 'belong' to a certain View? Can a record 'belong' to
+multiple views?`
+
+A record will be in a view because it will have an entry in it's intermediate
+table linking it to a particular view. A record can be in multiple views at the
+same time by having multiple entries in it's intermediate table.
+
+
+`How will views be used during the build process?`
+
+Views add a new complexity to building DNS zone file.
+
+DNS builds and views
+--------------------
+Forward zone files::
+
+ for all SOAs
+ get all the domains in that soa
+ for each domain
+ for each section
+ generate a file contain all records in that domain and section
+
+Reverse zone files::
+
+ for all SOAs
+ get all the reverse domains in that soa
+ for each reverse domain
+ for each view
+ generate a file contain all records in that domain and view
+
+Right now there are files for a zone's soa and domains. Views will introduce
+more files (`(# domains - 1) * # views` more files).
+
View
296 docs/domain.rst
@@ -0,0 +1,296 @@
+.. _domain:
+
+Domain
+======
+
+.. |project| replace:: mozinv
+
+Domains and Reverse Domains are at the core of the DNS app.
+
+Domains
++++++++
+
+Every domain has a name (like ``foo.example.com``). Every domain with a name comprised of two or
+more labels has a master domain. From the child's prespective, it's master domain's name is always
+it's own name with the far left label removed. For example the domain ``foo.example.com`` has a
+master domain ``example.com``.
+
+A ``domain`` with fewer than two labels is permitted to have a master domain of ``None``. In all
+other cases a domain *must* have a master domain. |project|'s django models enforce this.
+
+The ``domain`` table stores all domain objects::
+
+ +------------------+--------------+------+-----+---------+----------------+
+ | Field | Type | Null | Key | Default | Extra |
+ +------------------+--------------+------+-----+---------+----------------+
+ | id | int(11) | NO | PRI | NULL | auto_increment |
+ | name | varchar(100) | NO | UNI | NULL | |
+ | master_domain_id | int(11) | YES | MUL | NULL | |
+ | soa_id | int(11) | YES | MUL | NULL | |
+ +------------------+--------------+------+-----+---------+----------------+
+
+Note that ``master_domain_id`` is a foreign key that points back to the ``domain`` table. The
+``soa_id`` field is a foreign key to the ``soa`` table.
+
+Consider ``foo.example.com`` and ``bar.example.com``. The domain tree would look like the following::
+
+ com
+ |
+ example
+ | \
+ foo bar
+
+The ``domain`` table in the database would have these entries::
+
+ id name master_domain SOA
+
+ 1 com None None
+ 2 example.com 1 1 <--- the SOA table is not shown here
+ 3 foo.example.com 2 1
+ 4 bar.example.com 2 1
+
+Note that the ``com`` domain is in the table even though we are not authoritative for that domain.
+
+You are not be able to add ``foo.example.com`` without first adding ``example.com``. |project|
+enforces that a full domain tree be maintained at all times.
+
+If you agree with the idea of keeping a full domain tree, skip to _`Reverse Domains`. Else, keep reading.
+
+Advantages of a Full Domain Tree
+++++++++++++++++++++++++++++++++
+Having a full tree makes things more complete. When adding a new domain, having a full tree removes any ambiguity when searching for a master domain.
+
+Here are two examples of adding a domain. The first examples uses a partial domain tree. The second example uses a complete tree.
+
+Using an Incomplete Tree
+````````````````````````
+Say we want to add ``cute.cat.com`` and assume we are *not* keeping a complete tree in the DB and that ``cute.cat.com`` is the first domain being added to the database (the ``domain`` table is empty). With an incomplete tree, ``cute.cat.com`` would have the master domain of ``None``. We are authoritative for ``cure.cat.com`` so we have an :ref:`soa` for that domain::
+
+ id name master_domain SOA
+
+ 1 cute.cat.com None 1 <--- the SOA table is not show here
+
+Let's now assume we are going to add ``cat.com``. At this point *if* we were using a full tree the ``com`` domain would be ``cute.com``'s master domain. But with the partial tree, the ``com`` domain is missing so ``cute.com``'s master domain is ``None``::
+
+ id name master_domain SOA
+
+ 1 cute.cat.com None 1
+ 2 cat.com None 1
+
+After we add ``cat.com``, ``cute.cat.com``'s master domain is not correct. We need to search the
+domain table to change ``cute.cat.com``'s master_domain to ``cat.com``'s ``id``, which is ``2``::
+
+ id name master_domain SOA
+
+ 1 cute.cat.com 2 1
+ 2 cat.com None 1
+
+Even when we didn't explicitly keep a complete tree, our data was converging towards completeness.
+If we had added ``com`` we would have needed to update master domains and would be left with a full
+tree.
+
+Using a Full Tree Example
+`````````````````````````
+If we had to create all domains before we add a domain, adding the ``cute.cat.com`` domain would have resulted with the following records in the ``domain`` table::
+
+ id name master_domain SOA
+
+ 1 com None None
+ 2 cat.com 1 None
+ 3 cute.cat.com 2 1
+
+When we now add ``cat.com``, all we need to do is change the SOA field to signal that we are
+authoritative for the domain::
+
+ id name master_domain SOA
+
+ 1 com None None
+ 2 cat.com 1 1
+ 3 cute.cat.com 2 1
+
+Reverse Domains
++++++++++++++++
+
+Reverse Domains are stored in the same table as Forward Domains.
+
+Reverse Domains have the same domain/master domain relationship as Forward Domains. Consider
+the reverse domain ``0.168.192.in-addr.arpa``::
+
+ arpa
+ |
+ in-addr
+ |
+ 192
+ |
+ 168
+ |
+ 0
+
+If we added the reverse domain ``1.168.192.in-addr.arpa``, the tree would look like this::
+
+ arpa
+ |
+ in-addr
+ |
+ 192
+ |
+ 168
+ | \
+ 0 1
+
+The ``domain`` table would have the records::
+
+ id name master_domain SOA
+
+ 1 arpa None None
+ 2 in-addr.arpa 1 None
+ 3 192 2 None
+ 4 192.168 3 1 <--- the SOA table is not shown here
+ 5 192.168.0 4 1
+ 6 192.168.1 4 1
+
+Reverse Domains that you are not authoritative for should not have a
+relationship back to an SOA.
+
+Reason For Reverse Domains
+``````````````````````````
+Reverse domains are used for DNS reverse mapping. In |project|, every IP that ends up in a reverse
+zone file is mapped to an appropriate reverse domain. See the :ref:`ptr` documentation for more on
+Reverse Domains.
+
+Adding Reverse Domains
+``````````````````````
+Adding IPv4 reverse domains is easy to do by hand. It is not easy to do add IPv6 reverse domains by
+hand. IPv6 reverse domain names are very long and it is tedious to add them one by one. There is a
+function, :func:`bootstap_ipv6_reverse_domain`, that can aid in the construction of IPv6 reverse domains.
+
+
+DNS Records
++++++++++++
+Most DNS records in |project| have similar structure. In general, a record (like TXT, A, AAAA, etc.)
+consists of a label, domain, and some data. A *record's* label can be thought as a leaf node on the
+DNS tree, while the label's that compose domain names can be leaf node's *or* core nodes in the
+tree.
+
+.. figure:: images/label_domain1.png
+
+The full name of any node is the sequence of labels from a node to the root of the DNS tree with dot's separating each label.
+
+Records that 'hang off' and are attached to domains.
+
+.. figure:: images/label_domain2.png
+
+In the figure above, the domain ``example.com`` is shown with record sets hanging off.
+
+*Every DNS record (except :ref:`soa`) in |project| has a Foriegn Key back to a domain.*
+
+Domain Level Records
+````````````````````
+Sometimes the name of a DNS record has to be the same as the name of a domain. To have a DNS record
+like this, set the record's label to the empty string '' and it's domain to the domain with a name
+that is equal to desired name for the record.
+
+Example: Assume we have two domains::
+
+ example.com
+ foo.example.com
+
+Also, assume we are authoritative for both domains.
+
+The ``domain`` table would have the following data::
+
+ id name master_domain SOA
+ 1 com None None
+ 2 example.com 1 1
+ 3 foo.example.com 2 1
+
+With this configuration an A record like ``foo.example.com A 192.168.0.3`` would have a label
+equal to the empty string '', and it's domain set to ``foo.example.com``::
+
+ (A Record table)
+ id name domain ip
+ 1 '' 3 192.168.0.3
+
+The entry shown above is the correct way::
+
+ (A Record table)
+ id name domain ip
+ 1 foo 2 192.168.0.3
+
+The entry shown above is the wrong way and is not allowed.
+
+This policy applies to all DNS records that have the label and domain fields.
+
+.. note::
+
+ The DNS build scripts are smart enough not to emit '.foo.example.com' as the A record's name.
+
+Changing from Record to Domain
+``````````````````````````````
+
+When an existing DNS record has a name that needs to become a domain's name (for example
+``bar.example.com`` is an A record, but then it is decided that the domain ``bar.example.com``
+should be made) the consistent thing to do would be to shuffle any records that have the name
+'bar.example.com'. An admin will have to delete the DNS records that conflict with the new domain's
+name, make the new domain, and then create a `Domain Level Record` for the records that were
+deleted.
+
+.. note::
+ Eventually, it might be nice to have a feature in the UI that does the record shuffling
+ automatically.
+
+SOA Records, Domains, and Zones
+```````````````````````````````
+An ``SOA`` record can only exist in one zone. It is critical that no two domains point to the same ``SOA`` record *and* be in different zones.
+
+.. note::
+
+ The rest of this page is not important if you are just here for the TL;DR
+
+Domain Delegation
+-----------------
+
+.. warning::
+
+ *This feature is incomplete*
+
+Records in a delegated domain abide by different rules than records in a non delegated domain.
+
+ * The name of an A record in a delegated domain must be the same as the server attribute of the :ref:`nameserver` that is serving the delegated domain.
+
+ * Only A and NS records can be created in a delegated domain.
+
+Because a `Nameserver` cannot exist without a glue record (if the glue
+record is whithin the `Nameserver`\s domain) and an `AddressRecord` cannot
+exist in a delegated domain without a `Nameserver` pointing too it, a special
+form will need to be used to create `Nameserver`/`AddressRecord` pairs.
+Underneath the hood, the form will:
+
+ 1. Undelegate the domain.
+ 2. Create the `AddressRecord`
+ 3. Create the `Nameserver`
+ 4. Re-delegate the domain.
+
+
+The UI should *only* have a link to the create address record form and to the
+form that creates an NS record and an A record in one submit.
+
+When an admin creates a domain, the UI should prompt to configure it
+as one of three types:
+
+ * Subdomain - :ref:`soa` exists at a higher level; e.g. you are creating
+ ``foo.example.com`` as a subdomain of ``example.com``, and ``example.com`` already exists
+ with an SOA. This should be the default behavior.
+
+ * Top-level domain, not delegated - "top-level" as in "at the top of a
+ new zone" - UI should require you to create an :ref:`soa` and :ref:`nameserver` records.
+
+ * Top-level domain, delegated - UI should require :ref:`nameserver` records (and glue)
+ but not require nor allow an :ref:`soa`. Also, the restrictions above should be
+ followed.
+
+Domain
+======
+
+.. automodule:: mozdns.domain.models
+ :inherited-members: Domain, boot_strap_ipv6_reverse_domain
View
31 docs/flows.rst
@@ -0,0 +1,31 @@
+.. _flows:
+
+Network Flows
+=============
+Network Flow language::
+
+ <stmt> -> permit <sevice> from <objects>
+
+ <service> -> <app> | <app>, <service>
+ <app> -> <proto>: <port> <DSO>
+ <proto> -> ICMP | UDP | TCP ...
+ <port> -> [0 .. 2**32]
+ <DSO> -> Device (system) specific options
+
+ <objects> -> <net_list> <site_list> <host_list>
+
+ <net_list> -> <network> | <network>, <net_list> | Null
+ <network> -> IPv6Network | IPv4Network
+
+ <site_list> -> <site> | <site>, <site_list> | Null
+ <site> -> Network with shortest prefix length in the site
+
+ <host_list> -> <system> | <system>, <system_list> | Null
+ <host> -> <hostname> <limiter>
+
+ <limiter> -> <interface name> | <vlan> | <vlan>:<site>
+
+ <intr_name> -> ethX.Y | mgmtX.Y
+ <vlan> -> <name> | <number>
+
+ <site> -> <name>
View
93 docs/index.rst
@@ -1,29 +1,92 @@
-========================================
-Welcome to this project's documentation!
-========================================
+.. |project| replace:: cyder
-This is a documentation template for a **web application based on Playdoh**.
-Feel free to change this to your liking.
+Welcome to |project|'s documentation!
+=====================================
+.. include:: cyder_intro.rst
-About playdoh
--------------
-This project is based on **playdoh**. Mozilla's Playdoh is an open source
-web application template based on `Django <http://www.djangoproject.com/>`_.
+Vocabulary (DNS Jargon)
+=======================
+* Name and Label: "Each node in the DNS tree has a name consisting of zero or more labels" `RFC4343 <http://tools.ietf.org/html/rfc4343>`_ . The name ``x.y.z`` consists of the labels ``x``, ``y``, and ``z``. When talking about a name that corresponds to an actual system, the last label is sometimes referred to as the 'hostname'.
-To learn more about it, step by the `playdoh project page
-<https://github.com/mozilla/playdoh>`_.
+* Forward: Used to reference the part of DNS that maps names to Ip addresses.
-Contents
---------
+* Reverse: Used to reverence the part of DNS that maps Ip addresses to names.
+
+Quick Read
+==========
+*Read these pages for a TL;DR*
+
+* :ref:`core`
+
+* :ref:`domain`
+
+Q: Who are these docs for?
+
+A: People who have to read the source code of this project.
+
+Core
+====
+
+.. toctree::
+ :maxdepth: 2
+
+ staticinterface
+ core
+ site
+ vlan
+ network
+ range
+ flows
+
+DNS
+===
+
+The following dns records are supported: A, AAAA, PTR, CNAME, MX, NS, SRV, TXT, SSHFP and SOA
+
+.. toctree::
+ :maxdepth: 2
+
+ domain
+ label_domain
+ BIND
+ dns_views
+ soa
+ nameserver
+ mx
+ ip
+ common_record
+ address_record
+ ptr
+ cname
+ srv
+ txt
+ sshfp
+ validation
+
+DHCP
+====
+.. toctree::
+ :maxdepth: 2
+
+ DHCP
+
+Lib
+===
.. toctree::
- :maxdepth: 1
+ :maxdepth: 2
+
+ coding_standard
+ rage
+ lib
+ api
+
Indices and tables
-------------------
+==================
* :ref:`genindex`
* :ref:`modindex`
View
7 docs/ip.rst
@@ -0,0 +1,7 @@
+.. _ip:
+
+IP
+==
+.. automodule:: mozdns.ip.models
+ :inherited-members:
+
View
102 docs/label_domain.rst
@@ -0,0 +1,102 @@
+.. _label_domain:
+
+Label Domain Paradigm
+=====================
+This page only applied to forward domains.
+
+.. |project| replace:: Cyder
+
+All DNS records are centered around the 'label and domain' paradigm. This is a good unambiguous
+underlying data structure for the system to understand but it quite unfriendly to the user.
+
+An interesting case is this: say we only have two domains in our db, ``com`` and ``example.com``,
+and we want to add the :ref:`address_record` ``foo.bar.x.y.z.example.com A 192.168.3.3``. Four
+new domains would need to be created to store this record: ``z.example.com``, ``y.z.example.com``,
+``x.y.z.example.com``, and ``bar.x.y.z.example.com``. The last domain would be the record's domain
+and ``foo`` would be the value of it's label. Instead of having the user create all these domains,
+just saying 'create an ``A`` record with the name ``foo.bar.x.y.z.example.com``' should be possible.
+
+The algorithm for creating a new name::
+
+ def ensure_label_domain(fqdn):
+ """Returns a label and domain object."""
+ if Domain.objects.filter(name=fqdn).exists():
+ return '', Domain.objects.get(name=fqdn)
+ fqdn_partition = fqdn.split('.')
+ if len(fqdn_partition) == 1:
+ domain = Domain(name=fqdn)
+ domain.full_clean()
+ domain.save()
+ return '', domain
+ else:
+ label, domain_name = fqdn_partition[0], fqdn_partition[1:]
+ domain = ensure_domain(domain_name, purgeable=True)
+
+ def ensure_domain(domain_name, purgeable=False):
+ """This function will take ``domain_name`` and make sure that that domain with that name
+ exists in the db. If this function creates a domain it will set the domain's purgeable flag
+ to the value of the named arguement ``purgeable``."""
+ # Complicated code.
+
+Deleting an object that caused four domains to be created should not clutter the domain table with
+unused domains. *A domain is considered 'unused' when it's id, or pk (primary key), is not used in
+any DNS record*. When a record is deleted the effect of the following function should be applied to the
+record's domain after it is deleted::
+
+ def prune_tree(domain):
+ if domain.has_record_set():
+ return False # There are records for this domain
+ elif not domain.purgeable:
+ return False # This domain should not be deleted by a computer.
+ else:
+ child_domains = domain.domain_set.all()
+ domain.delete()
+ for child_domain in child_domains:
+ prune_tree(child_domain)
+ return True
+
+During the process of creating a new domain, a new domain's name could conflict with an existing
+record's name. For example, while creating the domain ``foo.example.com`` there may already be a
+record with a label equal to ``foo`` and it's domain pointed at ``example.com``. To handle these
+conflicts the function ``ensure_domain`` will delete conflicting records, create the new domain, and
+then recreate the record in the newly created domain and set the record's label to ``''`` (the empty string).
+
+Purgeable Domains
+-----------------
+
+The domain's ``purgeable`` attribute is set to ``True`` when it is created with the
+``ensure_label_domain`` function. When a record is deleted, the ``prune_tree`` function may delete
+unused domains. Some domains that are created should not be purged if they are empty, these domains
+should have purgeable set to ``False``. Some example of domain types that should not be purged:
+
+ * Any domain created in the Web UI should default to purgeable = False.
+ - If a user has gone out of his way to fill out a form to create a domain, don't delete it.
+ * All domains that are at the root of a SOA should default to purgeable = False.
+
+Some examples of when a domain will be passed to the ``prune_tree`` function.
+
+ * A record that has just been deleted will pass it's domain to ``prune_tree``.
+ * When a record is saved the domain that the record had *before* the update will have
+ ``prune_tree`` called on it (this doesn't happen when the record is first created).
+
+.. note::
+ When calling ``ensure_label_domain`` it is optimal to not allow domain leaks to happen. One way
+ a domain leak can happen is if you call ``ensure_label_domain``, assign the returned domain to
+ an object, and then back out of the creation of the object for some reason (likely an error
+ during object validation). To prevent this kind of leak, you should call ``prune_tree`` on the
+ domain returned by ``ensure_label_domain`` if the creation of an object fails.
+
+Delegated Domains
+-----------------
+If a request is made to ``ensure_label_domain`` that would cause domains to be created under a
+delegated domain, a :class:`ValidationError` is raised.
+
+SOA Requirements
+----------------
+The first domain that ``ensure_label_domain`` creates must be under a domain that claims to be part
+of zone (points to an SOA). This requirement is meant to ward off mass domain creation due to a
+typo. For exmaple: when attempting to create ``bar.x.y.z.example.com`` a user could accidentally
+write ``bar.x.y.z.example.cm`` and end up creating a stray root domain and five sub-domains.
+
+If a request is made to ``ensure_label_domain`` that would cause the creation of a domain that isn't
+in a zone, a :class:`ValidationError` is raised.
View
16 docs/lib.rst
@@ -0,0 +1,16 @@
+.. _lib:
+
+Usefull functions
+=================
+
+.. automodule:: core.lib.utils
+ :inherited-members:
+ :undoc-members:
+
+.. automodule:: core.keyvalue.models
+ :inherited-members:
+ :undoc-members:
+
+.. automodule:: core.keyvalue.utils
+ :inherited-members:
+ :undoc-members:
View
14 docs/mx.rst
@@ -0,0 +1,14 @@
+.. _mx:
+
+MX (Mail Server Record)
+=======================
+
+MX records should not point to cnames.
+
+MX
+--
+.. automodule:: mozdns.mx.models
+ :inherited-members:
+
+.. automodule:: mozdns.mx.views
+ :inherited-members:
View
40 docs/nameserver.rst
@@ -0,0 +1,40 @@
+.. _nameserver:
+
+Nameservers
+===========
+
+ "If the name server does lie within the domain it should have a corresponding A record"
+
+ -- `zytrax.com <http://www.zytrax.com/books/dns/ch8/ns.html>`_.
+
+This corresponding A record is called a *glue record*. The Nameserver model will inforce the
+existance of glue records where they are needed. If you create an NS record for a domain that you
+are authoritative for, you will be forced to create a glue record.
+
+For example: You are authoritative for the ``foo.com`` domain, child domains of ``foo.com`` and all
+records in those domains. Everything is in the ``foo.com`` zone. Now, you go to create an NS
+entry for your nameserver ``ns1.foo.com``. You want the record::
+
+ foo.com NS ns1.foo.com
+
+
+Before you add the NS entry, you need to create a glue record for ``ns1.foo.com``. The glue record
+is just a ``A`` or ``AAAA`` record. The Nameserver model will not allow the creation of the NS entry
+before the glue record exists.
+
+If you create an NS record that points to a name that exists outside of the domain you are making the
+NS record for, you don't need to create the glue record.
+
+For example: You are authoritative for the ``foo.com`` zone in the exact same way you were for the
+previous example. You go to create an NS record for the ``foo.com`` domain and you choose the name
+server ``ns1.bar.com``. You want the record::
+
+ foo.com NS ns1.bar.com
+
+You do not need to create a glue record.
+
+Nameserver
+----------
+.. automodule:: mozdns.nameserver.models
+ :inherited-members:
+
View
7 docs/network.rst
@@ -0,0 +1,7 @@
+.. _network:
+
+
+Network
+--------
+.. automodule:: core.network.models
+ :inherited-members:
View
48 docs/ptr.rst
@@ -0,0 +1,48 @@
+.. _ptr:
+
+PTR
+===
+
+.. |ptr| replace:: :class:`PTR`
+
+A |ptr| instance represents a reverse ip maping. Because in BIND |ptr| recrods need to go into a reverse zone file that contain an SOA, every |ptr| must be under a domain that the system is authoritative for.
+
+Some examples: Let's assume we are authoritative for the network 192.168.0.0/16 and that we want to create a ptr for the name ``foo.example.com`` to ``192.168.1.9``. If we were to try to add the |ptr| without first makeing a reverse domain for that ptr, a :class:`ValidationError` would be raises::
+
+ >>> from mozdns.ptr.models import PTR
+ >>> ptr = PTR(ip_str="192.168.1.9", name="foo.example.com", ip_type='4')
+ >>> ptr.full_clean()
+ Traceback (most recent call last):
+ File "<console>", line 1, in <module>
+ File "/var/www/inventory/mozdns/ptr/models.py", line 83, in clean
+ self.clean_ip(update_reverse_domain=urd)
+ File "/var/www/inventory/mozdns/ip/models.py", line 94, in clean_ip
+ ip_type='4'))
+ File "/var/www/inventory/vendor/src/django/django/db/models/fields/related.py", line 327, in __set__
+ (instance._meta.object_name, self.field.name))
+ ValueError: Cannot assign None: "PTR.reverse_domain" does not allow null values.
+
+:func:`full_clean` looks for a reverse domain for ``192.128.1.9``. In the code shown above, no reverse domain is found and a :class:`ValidationError` is raised (admittedly, the error message could be a little more descriptive). Adding an appropriate reverse domain will resolve the traceback::
+
+ >>> domain, _ = Domain.objects.get_or_create("192.in-addr.arpa")
+ >>> ptr = PTR(ip_str="192.168.1.9", name="foo.example.com", ip_type='4')
+ >>> ptr.full_clean()
+ >>> ptr.save()
+
+If we look at the reverse domain of the ptr we created, it will be the reverse domain we just created::
+
+ >>> ptr.reverse_domain
+ <Domain '192.in-addr.arpa'>
+
+If we add a new reverse domain that is a better fit for our PTR, the PTR will be assigned that reverse domain::
+
+ >>> domain, _ = Domain.objects.get_or_create("168.192.in-addr.arpa")
+ >>> domain.master_domain
+ <Domain '192.in-addr.arpa'>
+ >>> ptr.reverse_domain
+ <Domain '168.192.in-addr.arpa'>
+
+
+
+.. automodule:: mozdns.ptr.models
+ :inherited-members:
View
8 docs/range.rst
@@ -0,0 +1,8 @@
+.. _range:
+
+Range
+=====
+Ranges exist inside Networks.
+
+.. automodule:: core.range.models
+ :inherited-members:
View
7 docs/site.rst
@@ -0,0 +1,7 @@
+.. _site:
+
+Site
+====
+
+.. automodule:: core.site.models
+ :inherited-members:
View
8 docs/soa.rst
@@ -0,0 +1,8 @@
+.. _soa:
+
+SOA (Start Of Authority)
+========================
+
+.. automodule:: mozdns.soa.models
+ :inherited-members:
+
View
7 docs/srv.rst
@@ -0,0 +1,7 @@
+.. _srv:
+
+SRV (Service Record)
+====================
+
+.. automodule:: mozdns.srv.models
+ :inherited-members:
View
8 docs/sshfp.rst
@@ -0,0 +1,8 @@
+.. _sshfp:
+
+SSHFP
+=====
+http://tools.ietf.org/html/rfc4255
+
+.. automodule:: mozdns.sshfp.models
+ :inherited-members:
View
74 docs/staticinterface.rst
@@ -0,0 +1,74 @@
+.. _staticinterface:
+
+Static Interface
+================
+A static interface allows a user to easily create an A/AAAA :class:`AddressRecord` record,
+:class:`PTR` record and register the interface in the DHCP configs.
+
+A static interface relys on having a ``hostname``, ``ip`` and a ``mac`` to
+generates DNS and DHCP entries. The DNS entries are an A/AAAA record and a PTR record::
+
+ <hostname> A <ip>
+ <ip> PTR <hostname>
+
+The DHCP entry is a host clause::
+
+ host <hostname> {
+ fixed-address <ip>;
+ hardware ethernet <mac>;
+ }
+
+By choosing an ``ip`` you are in effect assigning the registration to a :class:`Range`.
+
+Automatically Choosing an IP address for an Interface
+-----------------------------------------------------
+
+Just by looking at an Interfaces requested hostname we can determine which site
+(datacenter and possible business unit) and vlan an Interface is in. Using the
+names of the site and vlan we can use information stored in the :ref:`core`
+core of inventory to determine which IP address to choose for the interface.
+For example::
+
+
+ webnode1.webops.scl3.mozilla.com
+
+
+This Interface is in scl3 in the webops vlan. Since Inventory tracks both sites
+and vlans getting these objects is just a matter of querying the database.::
+
+ site_scl3 = Site.objects.get(name='scl3')
+ vlan_webops = Vlan.objects.get(name='webops')
+
+Networks are associated to vlan's so retreving which networks are in the webops
+vlan is one query away.::
+
+ webops_networks = vlan_webops.network_set.all()
+
+Since the webops vlan can exist in multiple datacenters, we only want to look
+at networks that are in the webops vlan *and* are in scl3.::
+
+ scl3_webops_networks = []
+ for network in webops_networks:
+ if network.site == site_scl3:
+ scl3_webops_networks.append(network)
+
+We now look for a free IP in a range in one of the networks in ``scl3_webops_networks``.
+
+.. note::
+ In most cases there is only one network associated with a vlan in a particular datacenter.
+
+Getting a free ip is easy.::
+
+ network = scl3_webops_networks[0] # Let's just choose the first one for the sake of example.
+ ip = None
+ for range in network.range_set.all():
+ ip = range.get_next_ip()
+ if ip:
+ break
+
+We just found a free ip in vlan webops in scl3.
+
+Static Interface
+----------------
+.. automodule:: core.interface.static_intr.models
+ :inherited-members: StaticInterface
View
7 docs/txt.rst
@@ -0,0 +1,7 @@
+.. _txt:
+
+TXT
+===
+
+.. automodule:: mozdns.txt.models
+ :inherited-members:
View
52 docs/validation.rst
@@ -0,0 +1,52 @@
+.. _validation:
+
+Validation
+==========
+
+Validation happens all over the place. These are validation functions that ended up in the same file.
+
+Domain/ReverseDomain Validation
+-------------------------------
+
+Use the function ``do_zone_validation`` in model code.
+
+.. autofunction:: mozdns.validation.do_zone_validation
+.. autofunction:: mozdns.validation.check_for_master_delegation
+.. autofunction:: mozdns.validation.validate_zone_soa
+.. autofunction:: mozdns.validation.check_for_soa_partition
+.. autofunction:: mozdns.validation.find_root_domain
+
+Name and Label Validation
+-------------------------
+
+.. autofunction:: mozdns.validation.validate_label
+.. autofunction:: mozdns.validation.validate_domain_name
+.. autofunction:: mozdns.validation.validate_name
+.. autofunction:: mozdns.validation.validate_reverse_name
+
+TTL Validation
+--------------
+
+.. autofunction:: mozdns.validation.validate_ttl
+
+SRV Validation
+--------------
+
+:class:`SRV` objects need special validation because of the ``_`` the precedes their names. They also have other fields like ``weight``, ``port`` and ``priority`` that need to be validated.
+
+.. autofunction:: mozdns.validation.validate_srv_port
+.. autofunction:: mozdns.validation.validate_srv_priority
+.. autofunction:: mozdns.validation.validate_srv_weight
+.. autofunction:: mozdns.validation.validate_srv_label
+.. autofunction:: mozdns.validation.validate_srv_name
+
+
+MX Validation
+-------------
+
+.. autofunction:: mozdns.validation.validate_mx_priority
+
+IP type Validation
+------------------
+
+.. autofunction:: mozdns.validation.validate_ip_type
View
8 docs/vlan.rst
@@ -0,0 +1,8 @@
+.. _vlan:
+
+VLAN
+====
+Vlans exist inside of networks.
+
+.. automodule:: core.vlan.models
+ :inherited-members:
Please sign in to comment.
Something went wrong with that request. Please try again.