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")
75 if dnsubnet
.add_base(configDn
) == False:
76 raise SubnetException("dnsubnet.add_base() failed")
77 if dnsubnet
.add_child("CN=X") == False:
78 raise SubnetException("dnsubnet.add_child() failed")
79 dnsubnet
.set_component(0, "CN", subnet_name
)
84 m
["objectclass"] = ldb
.MessageElement("subnet", FLAG_MOD_ADD
,
86 m
["siteObject"] = ldb
.MessageElement(str(dn_site
), FLAG_MOD_ADD
,
89 except ldb
.LdbError
as e
:
91 if enum
== ldb
.ERR_INVALID_DN_SYNTAX
:
92 raise SubnetInvalid("%s is not a valid subnet: %s" % (subnet_name
, estr
))
93 elif enum
== ldb
.ERR_ENTRY_ALREADY_EXISTS
:
94 # Subnet collisions are checked by exact match only, not
95 # overlapping range. This won't stop you creating
96 # 10.1.1.0/24 when there is already 10.1.0.0/16, or
97 # prevent you from having numerous IPv6 subnets that refer
98 # to the same range (e.g 5::0/16, 5::/16, 5:0:0::/16).
99 raise SubnetAlreadyExists('A subnet with the CIDR %s already exists'
105 def delete_subnet(samdb
, configDn
, subnet_name
):
108 :param samdb: A samdb connection
109 :param configDn: The DN of the configuration partition
110 :param subnet_name: Name of the subnet to delete
112 :raise SubnetNotFound: if the subnet to be deleted does not exist.
114 dnsubnet
= ldb
.Dn(samdb
, "CN=Subnets,CN=Sites")
115 if dnsubnet
.add_base(configDn
) == False:
116 raise SubnetException("dnsubnet.add_base() failed")
117 if dnsubnet
.add_child("CN=X") == False:
118 raise SubnetException("dnsubnet.add_child() failed")
119 dnsubnet
.set_component(0, "CN", subnet_name
)
122 ret
= samdb
.search(base
=dnsubnet
, scope
=ldb
.SCOPE_BASE
,
123 expression
="objectClass=subnet")
125 raise SubnetNotFound('Subnet %s does not exist' % subnet_name
)
126 except LdbError
as e1
:
127 (enum
, estr
) = e1
.args
128 if enum
== ldb
.ERR_NO_SUCH_OBJECT
:
129 raise SubnetNotFound('Subnet %s does not exist' % subnet_name
)
131 samdb
.delete(dnsubnet
)
134 def rename_subnet(samdb
, configDn
, subnet_name
, new_name
):
137 :param samdb: A samdb connection
138 :param configDn: The DN of the configuration partition
139 :param subnet_name: Name of the subnet to rename
140 :param new_name: New name for the subnet
142 :raise SubnetNotFound: if the subnet to be renamed does not exist.
143 :raise SubnetExists: if the subnet to be created already exists.
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
)
152 newdnsubnet
= ldb
.Dn(samdb
, str(dnsubnet
))
153 newdnsubnet
.set_component(0, "CN", new_name
)
155 samdb
.rename(dnsubnet
, newdnsubnet
)
156 except LdbError
as e2
:
157 (enum
, estr
) = e2
.args
158 if enum
== ldb
.ERR_NO_SUCH_OBJECT
:
159 raise SubnetNotFound('Subnet %s does not exist' % dnsubnet
)
160 elif enum
== ldb
.ERR_ENTRY_ALREADY_EXISTS
:
161 raise SubnetAlreadyExists('A subnet with the CIDR %s already exists'
163 elif enum
== ldb
.ERR_INVALID_DN_SYNTAX
:
164 raise SubnetInvalid("%s is not a valid subnet: %s" % (new_name
,
170 def set_subnet_site(samdb
, configDn
, subnet_name
, site_name
):
171 """Assign a subnet to a site.
173 This dissociates the subnet from its previous site.
175 :param samdb: A samdb connection
176 :param configDn: The DN of the configuration partition
177 :param subnet_name: Name of the subnet
178 :param site_name: Name of the site
180 :raise SubnetNotFound: if the subnet does not exist.
181 :raise SiteNotFound: if the site does not exist.
184 dnsubnet
= ldb
.Dn(samdb
, "CN=Subnets,CN=Sites")
185 if dnsubnet
.add_base(configDn
) == False:
186 raise SubnetException("dnsubnet.add_base() failed")
187 if dnsubnet
.add_child("CN=X") == False:
188 raise SubnetException("dnsubnet.add_child() failed")
189 dnsubnet
.set_component(0, "CN", subnet_name
)
192 ret
= samdb
.search(base
=dnsubnet
, scope
=ldb
.SCOPE_BASE
,
193 expression
="objectClass=subnet")
195 raise SubnetNotFound('Subnet %s does not exist' % subnet_name
)
196 except LdbError
as e3
:
197 (enum
, estr
) = e3
.args
198 if enum
== ldb
.ERR_NO_SUCH_OBJECT
:
199 raise SubnetNotFound('Subnet %s does not exist' % subnet_name
)
201 dnsite
= ldb
.Dn(samdb
, "CN=Sites")
202 if dnsite
.add_base(configDn
) == False:
203 raise SubnetException("dnsites.add_base() failed")
204 if dnsite
.add_child("CN=X") == False:
205 raise SubnetException("dnsites.add_child() failed")
206 dnsite
.set_component(0, "CN", site_name
)
208 dnservers
= ldb
.Dn(samdb
, "CN=Servers")
209 dnservers
.add_base(dnsite
)
212 ret
= samdb
.search(base
=dnsite
, scope
=ldb
.SCOPE_BASE
,
213 expression
="objectClass=site")
215 raise SiteNotFoundException('Site %s does not exist' % site_name
)
216 except LdbError
as e4
:
217 (enum
, estr
) = e4
.args
218 if enum
== ldb
.ERR_NO_SUCH_OBJECT
:
219 raise SiteNotFoundException('Site %s does not exist' % site_name
)
221 siteDn
= str(ret
[0].dn
)
225 m
["siteObject"] = ldb
.MessageElement(siteDn
, FLAG_MOD_REPLACE
,