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
28 class SubnetException(Exception):
29 """Base element for Subnet errors"""
33 class SubnetNotFound(SubnetException
):
34 """The subnet requested does not exist."""
38 class SubnetAlreadyExists(SubnetException
):
39 """The subnet being added already exists."""
43 class SubnetInvalid(SubnetException
):
44 """The subnet CIDR is invalid."""
48 class SiteNotFound(SubnetException
):
49 """The site to be used for the subnet does not exist."""
53 def create_subnet(samdb
, configDn
, subnet_name
, site_name
):
54 """Create a subnet and associate it with a site.
56 :param samdb: A samdb connection
57 :param configDn: The DN of the configuration partition
58 :param subnet_name: name of the subnet to create (a CIDR range)
60 :raise SubnetAlreadyExists: if the subnet to be created already exists.
61 :raise SiteNotFound: if the site does not exist.
63 ret
= samdb
.search(base
=configDn
, scope
=ldb
.SCOPE_SUBTREE
,
64 expression
='(&(objectclass=Site)(cn=%s))' %
65 ldb
.binary_encode(site_name
))
67 raise SiteNotFound('A site with the name %s does not exist' %
71 if not isinstance(subnet_name
, str):
72 raise SubnetInvalid("%s is not a valid subnet (not a string)" % subnet_name
)
74 dnsubnet
= ldb
.Dn(samdb
, "CN=Subnets,CN=Sites")
76 dnsubnet
.add_base(configDn
)
78 raise SubnetException("dnsubnet.add_base() failed")
80 dnsubnet
.add_child("CN=X")
82 raise SubnetException("dnsubnet.add_child() failed")
83 dnsubnet
.set_component(0, "CN", subnet_name
)
88 m
["objectclass"] = ldb
.MessageElement("subnet", FLAG_MOD_ADD
,
90 m
["siteObject"] = ldb
.MessageElement(str(dn_site
), FLAG_MOD_ADD
,
93 except ldb
.LdbError
as e
:
95 if enum
== ldb
.ERR_INVALID_DN_SYNTAX
:
96 raise SubnetInvalid("%s is not a valid subnet: %s" % (subnet_name
, estr
))
97 elif enum
== ldb
.ERR_ENTRY_ALREADY_EXISTS
:
98 # Subnet collisions are checked by exact match only, not
99 # overlapping range. This won't stop you creating
100 # 10.1.1.0/24 when there is already 10.1.0.0/16, or
101 # prevent you from having numerous IPv6 subnets that refer
102 # to the same range (e.g 5::0/16, 5::/16, 5:0:0::/16).
103 raise SubnetAlreadyExists('A subnet with the CIDR %s already exists'
109 def delete_subnet(samdb
, configDn
, subnet_name
):
112 :param samdb: A samdb connection
113 :param configDn: The DN of the configuration partition
114 :param subnet_name: Name of the subnet to delete
116 :raise SubnetNotFound: if the subnet to be deleted does not exist.
118 dnsubnet
= ldb
.Dn(samdb
, "CN=Subnets,CN=Sites")
120 dnsubnet
.add_base(configDn
)
122 raise SubnetException("dnsubnet.add_base() failed")
124 dnsubnet
.add_child("CN=X")
126 raise SubnetException("dnsubnet.add_child() failed")
127 dnsubnet
.set_component(0, "CN", subnet_name
)
130 ret
= samdb
.search(base
=dnsubnet
, scope
=ldb
.SCOPE_BASE
,
131 expression
="objectClass=subnet")
133 raise SubnetNotFound('Subnet %s does not exist' % subnet_name
)
134 except LdbError
as e1
:
135 (enum
, estr
) = e1
.args
136 if enum
== ldb
.ERR_NO_SUCH_OBJECT
:
137 raise SubnetNotFound('Subnet %s does not exist' % subnet_name
)
139 samdb
.delete(dnsubnet
)
142 def rename_subnet(samdb
, configDn
, subnet_name
, new_name
):
145 :param samdb: A samdb connection
146 :param configDn: The DN of the configuration partition
147 :param subnet_name: Name of the subnet to rename
148 :param new_name: New name for the subnet
150 :raise SubnetNotFound: if the subnet to be renamed does not exist.
151 :raise SubnetExists: if the subnet to be created already exists.
153 dnsubnet
= ldb
.Dn(samdb
, "CN=Subnets,CN=Sites")
155 dnsubnet
.add_base(configDn
)
157 raise SubnetException("dnsubnet.add_base() failed")
159 dnsubnet
.add_child("CN=X")
161 raise SubnetException("dnsubnet.add_child() failed")
162 dnsubnet
.set_component(0, "CN", subnet_name
)
164 newdnsubnet
= ldb
.Dn(samdb
, str(dnsubnet
))
165 newdnsubnet
.set_component(0, "CN", new_name
)
167 samdb
.rename(dnsubnet
, newdnsubnet
)
168 except LdbError
as e2
:
169 (enum
, estr
) = e2
.args
170 if enum
== ldb
.ERR_NO_SUCH_OBJECT
:
171 raise SubnetNotFound('Subnet %s does not exist' % dnsubnet
)
172 elif enum
== ldb
.ERR_ENTRY_ALREADY_EXISTS
:
173 raise SubnetAlreadyExists('A subnet with the CIDR %s already exists'
175 elif enum
== ldb
.ERR_INVALID_DN_SYNTAX
:
176 raise SubnetInvalid("%s is not a valid subnet: %s" % (new_name
,
182 def set_subnet_site(samdb
, configDn
, subnet_name
, site_name
):
183 """Assign a subnet to a site.
185 This dissociates the subnet from its previous site.
187 :param samdb: A samdb connection
188 :param configDn: The DN of the configuration partition
189 :param subnet_name: Name of the subnet
190 :param site_name: Name of the site
192 :raise SubnetNotFound: if the subnet does not exist.
193 :raise SiteNotFound: if the site does not exist.
196 dnsubnet
= ldb
.Dn(samdb
, "CN=Subnets,CN=Sites")
198 dnsubnet
.add_base(configDn
)
200 raise SubnetException("dnsubnet.add_base() failed")
202 dnsubnet
.add_child("CN=X")
204 raise SubnetException("dnsubnet.add_child() failed")
205 dnsubnet
.set_component(0, "CN", subnet_name
)
208 ret
= samdb
.search(base
=dnsubnet
, scope
=ldb
.SCOPE_BASE
,
209 expression
="objectClass=subnet")
211 raise SubnetNotFound('Subnet %s does not exist' % subnet_name
)
212 except LdbError
as e3
:
213 (enum
, estr
) = e3
.args
214 if enum
== ldb
.ERR_NO_SUCH_OBJECT
:
215 raise SubnetNotFound('Subnet %s does not exist' % subnet_name
)
217 dnsite
= ldb
.Dn(samdb
, "CN=Sites")
219 dnsite
.add_base(configDn
)
221 raise SubnetException("dnsite.add_base() failed")
223 dnsite
.add_child("CN=X")
225 raise SubnetException("dnsite.add_child() failed")
226 dnsite
.set_component(0, "CN", site_name
)
228 dnservers
= ldb
.Dn(samdb
, "CN=Servers")
229 dnservers
.add_base(dnsite
)
232 ret
= samdb
.search(base
=dnsite
, scope
=ldb
.SCOPE_BASE
,
233 expression
="objectClass=site")
235 raise SiteNotFoundException('Site %s does not exist' % site_name
)
236 except LdbError
as e4
:
237 (enum
, estr
) = e4
.args
238 if enum
== ldb
.ERR_NO_SUCH_OBJECT
:
239 raise SiteNotFoundException('Site %s does not exist' % site_name
)
241 siteDn
= str(ret
[0].dn
)
245 m
["siteObject"] = ldb
.MessageElement(siteDn
, FLAG_MOD_REPLACE
,