ctdb-takeover: Clean up when exiting on error
[Samba.git] / python / samba / subnets.py
blobe859f06e46de63dff1bc471e7f47cb04fc8d6127
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/>.
23 import ldb
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"""
29 pass
32 class SubnetNotFound(SubnetException):
33 """The subnet requested does not exist."""
34 pass
37 class SubnetAlreadyExists(SubnetException):
38 """The subnet being added already exists."""
39 pass
42 class SubnetInvalid(SubnetException):
43 """The subnet CIDR is invalid."""
44 pass
47 class SiteNotFound(SubnetException):
48 """The site to be used for the subnet does not exist."""
49 pass
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)
58 :return: None
59 :raise SubnetAlreadyExists: if the subnet to be created already exists.
60 :raise SiteNotFound: if the site does not exist.
61 """
62 ret = samdb.search(base=configDn, scope=ldb.SCOPE_SUBTREE,
63 expression='(&(objectclass=Site)(cn=%s))' %
64 ldb.binary_encode(site_name))
65 if len(ret) != 1:
66 raise SiteNotFound('A site with the name %s does not exist' %
67 site_name)
68 dn_site = ret[0].dn
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)
80 try:
81 m = ldb.Message()
82 m.dn = dnsubnet
83 m["objectclass"] = ldb.MessageElement("subnet", FLAG_MOD_ADD,
84 "objectclass")
85 m["siteObject"] = ldb.MessageElement(str(dn_site), FLAG_MOD_ADD,
86 "siteObject")
87 samdb.add(m)
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'
98 % subnet_name)
99 else:
100 raise
103 def delete_subnet(samdb, configDn, subnet_name):
104 """Delete a subnet.
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
109 :return: None
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)
119 try:
120 ret = samdb.search(base=dnsubnet, scope=ldb.SCOPE_BASE,
121 expression="objectClass=subnet")
122 if len(ret) != 1:
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
140 :return: None
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)
152 try:
153 ret = samdb.search(base=dnsubnet, scope=ldb.SCOPE_BASE,
154 expression="objectClass=subnet")
155 if len(ret) != 1:
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)
171 try:
172 ret = samdb.search(base=dnsite, scope=ldb.SCOPE_BASE,
173 expression="objectClass=site")
174 if len(ret) != 1:
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)
182 m = ldb.Message()
183 m.dn = dnsubnet
184 m["siteObject"] = ldb.MessageElement(siteDn, FLAG_MOD_REPLACE,
185 "siteObject")
186 samdb.modify(m)