1 # Add/remove subnets to sites.
3 # Copyright (C) Catalyst.Net Ltd 2015
4 # Copyright Matthieu Patou <mat@matws.net> 2011
6 # Catalyst.Net's contribution was written by Douglas Bagnall
7 # <douglas.bagnall@catalyst.net.nz>.
9 # This program is free software; you can redistribute it and/or modify
10 # it under the terms of the GNU General Public License as published by
11 # the Free Software Foundation; either version 3 of the License, or
12 # (at your option) any later version.
14 # This program is distributed in the hope that it will be useful,
15 # but WITHOUT ANY WARRANTY; without even the implied warranty of
16 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 # GNU General Public License for more details.
19 # You should have received a copy of the GNU General Public License
20 # along with this program. If not, see <http://www.gnu.org/licenses/>.
24 from ldb
import FLAG_MOD_ADD
, FLAG_MOD_REPLACE
, LdbError
25 from sites
import SiteNotFoundException
27 class SubnetException(Exception):
28 """Base element for Subnet errors"""
32 class SubnetNotFound(SubnetException
):
33 """The subnet requested does not exist."""
37 class SubnetAlreadyExists(SubnetException
):
38 """The subnet being added already exists."""
42 class SubnetInvalid(SubnetException
):
43 """The subnet CIDR is invalid."""
47 class SiteNotFound(SubnetException
):
48 """The site to be used for the subnet does not exist."""
52 def create_subnet(samdb
, configDn
, subnet_name
, site_name
):
53 """Create a subnet and associate it with a site.
55 :param samdb: A samdb connection
56 :param configDn: The DN of the configuration partition
57 :param subnet_name: name of the subnet to create (a CIDR range)
59 :raise SubnetAlreadyExists: if the subnet to be created already exists.
60 :raise SiteNotFound: if the site does not exist.
62 ret
= samdb
.search(base
=configDn
, scope
=ldb
.SCOPE_SUBTREE
,
63 expression
='(&(objectclass=Site)(cn=%s))' %
64 ldb
.binary_encode(site_name
))
66 raise SiteNotFound('A site with the name %s does not exist' %
70 if not isinstance(subnet_name
, str):
71 raise SubnetInvalid("%s is not a valid subnet (not a string)" % subnet_name
)
73 dnsubnet
= ldb
.Dn(samdb
, "CN=Subnets,CN=Sites")
74 if dnsubnet
.add_base(configDn
) == False:
75 raise SubnetException("dnsubnet.add_base() failed")
76 if dnsubnet
.add_child("CN=X") == False:
77 raise SubnetException("dnsubnet.add_child() failed")
78 dnsubnet
.set_component(0, "CN", subnet_name
)
83 m
["objectclass"] = ldb
.MessageElement("subnet", FLAG_MOD_ADD
,
85 m
["siteObject"] = ldb
.MessageElement(str(dn_site
), FLAG_MOD_ADD
,
88 except ldb
.LdbError
as (enum
, estr
):
89 if enum
== ldb
.ERR_INVALID_DN_SYNTAX
:
90 raise SubnetInvalid("%s is not a valid subnet: %s" % (subnet_name
, estr
))
91 elif enum
== ldb
.ERR_ENTRY_ALREADY_EXISTS
:
92 # Subnet collisions are checked by exact match only, not
93 # overlapping range. This won't stop you creating
94 # 10.1.1.0/24 when there is already 10.1.0.0/16, or
95 # prevent you from having numerous IPv6 subnets that refer
96 # to the same range (e.g 5::0/16, 5::/16, 5:0:0::/16).
97 raise SubnetAlreadyExists('A subnet with the CIDR %s already exists'
103 def delete_subnet(samdb
, configDn
, subnet_name
):
106 :param samdb: A samdb connection
107 :param configDn: The DN of the configuration partition
108 :param subnet_name: Name of the subnet to delete
110 :raise SubnetNotFound: if the subnet to be deleted does not exist.
112 dnsubnet
= ldb
.Dn(samdb
, "CN=Subnets,CN=Sites")
113 if dnsubnet
.add_base(configDn
) == False:
114 raise SubnetException("dnsubnet.add_base() failed")
115 if dnsubnet
.add_child("CN=X") == False:
116 raise SubnetException("dnsubnet.add_child() failed")
117 dnsubnet
.set_component(0, "CN", subnet_name
)
120 ret
= samdb
.search(base
=dnsubnet
, scope
=ldb
.SCOPE_BASE
,
121 expression
="objectClass=subnet")
123 raise SubnetNotFound('Subnet %s does not exist' % subnet_name
)
124 except LdbError
as (enum
, estr
):
125 if enum
== ldb
.ERR_NO_SUCH_OBJECT
:
126 raise SubnetNotFound('Subnet %s does not exist' % subnet_name
)
128 samdb
.delete(dnsubnet
)
131 def set_subnet_site(samdb
, configDn
, subnet_name
, site_name
):
132 """Assign a subnet to a site.
134 This dissociates the subnet from its previous site.
136 :param samdb: A samdb connection
137 :param configDn: The DN of the configuration partition
138 :param subnet_name: Name of the subnet
139 :param site_name: Name of the site
141 :raise SubnetNotFound: if the subnet does not exist.
142 :raise SiteNotFound: if the site does not exist.
145 dnsubnet
= ldb
.Dn(samdb
, "CN=Subnets,CN=Sites")
146 if dnsubnet
.add_base(configDn
) == False:
147 raise SubnetException("dnsubnet.add_base() failed")
148 if dnsubnet
.add_child("CN=X") == False:
149 raise SubnetException("dnsubnet.add_child() failed")
150 dnsubnet
.set_component(0, "CN", subnet_name
)
153 ret
= samdb
.search(base
=dnsubnet
, scope
=ldb
.SCOPE_BASE
,
154 expression
="objectClass=subnet")
156 raise SubnetNotFound('Subnet %s does not exist' % subnet_name
)
157 except LdbError
as (enum
, estr
):
158 if enum
== ldb
.ERR_NO_SUCH_OBJECT
:
159 raise SubnetNotFound('Subnet %s does not exist' % subnet_name
)
161 dnsite
= ldb
.Dn(samdb
, "CN=Sites")
162 if dnsite
.add_base(configDn
) == False:
163 raise SubnetException("dnsites.add_base() failed")
164 if dnsite
.add_child("CN=X") == False:
165 raise SubnetException("dnsites.add_child() failed")
166 dnsite
.set_component(0, "CN", site_name
)
168 dnservers
= ldb
.Dn(samdb
, "CN=Servers")
169 dnservers
.add_base(dnsite
)
172 ret
= samdb
.search(base
=dnsite
, scope
=ldb
.SCOPE_BASE
,
173 expression
="objectClass=site")
175 raise SiteNotFoundException('Site %s does not exist' % site_name
)
176 except LdbError
as (enum
, estr
):
177 if enum
== ldb
.ERR_NO_SUCH_OBJECT
:
178 raise SiteNotFoundException('Site %s does not exist' % site_name
)
180 siteDn
= str(ret
[0].dn
)
184 m
["siteObject"] = ldb
.MessageElement(siteDn
, FLAG_MOD_REPLACE
,