samba-tool: epilog option to OptionParser available in python >= 2.6
[samba.git] / source4 / scripting / python / samba / netcmd / fsmo.py
1 #!/usr/bin/env python
2 #
3 # Changes a FSMO role owner
4 #
5 # Copyright Nadezhda Ivanova 2009
6 # Copyright Jelmer Vernooij 2009
7 # Copyright Giampaolo Lauria 2011 <lauria2@yahoo.com>
8 #
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.
13 #
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.
18 #
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/>.
21 #
22
23 import samba.getopt as options
24 import ldb
25 from ldb import LdbError
26
27 from samba.auth import system_session
28 from samba.netcmd import (
29     Command,
30     CommandError,
31     SuperCommand,
32     Option,
33     )
34 from samba.samdb import SamDB
35
36
37
38 class cmd_fsmo_seize(Command):
39     """Seize the role"""
40      
41     synopsis = "%prog fsmo seize [options]"
42
43     takes_options = [
44         Option("-H", "--URL", help="LDB URL for database or target server", type=str,
45                metavar="URL", dest="H"),
46         Option("--force", help="Force seizing of the role without attempting to transfer first.", action="store_true"),
47         Option("--role", type="choice", choices=["rid", "pdc", "infrastructure","schema","naming","all"],
48                help="""The FSMO role to seize or transfer.\n
49 rid=RidAllocationMasterRole\n
50 schema=SchemaMasterRole\n
51 pdc=PdcEmulationMasterRole\n
52 naming=DomainNamingMasterRole\n
53 infrastructure=InfrastructureMasterRole\n
54 all=all of the above"""),
55         ]
56
57     takes_args = []
58
59     def seize_role(self, role, samdb, force):
60         res = samdb.search("",
61                            scope=ldb.SCOPE_BASE, attrs=["dsServiceName"])
62         assert len(res) == 1
63         serviceName = res[0]["dsServiceName"][0]
64         domain_dn = samdb.domain_dn()
65         m = ldb.Message()
66         if role == "rid":
67             m.dn = ldb.Dn(samdb, self.rid_dn)
68         elif role == "pdc":
69             m.dn = ldb.Dn(samdb, domain_dn)
70         elif role == "naming":
71             m.dn = ldb.Dn(samdb, self.naming_dn)
72         elif role == "infrastructure":
73             m.dn = ldb.Dn(samdb, self.infrastructure_dn)
74         elif role == "schema":
75             m.dn = ldb.Dn(samdb, self.schema_dn)
76         else:
77             raise CommandError("Invalid FSMO role.")
78         #first try to transfer to avoid problem if the owner is still active
79         if force is None:
80             self.message("Attempting transfer...")
81             try:
82                 self.transfer_role(role, samdb)
83             except LdbError, (num, _):
84             #transfer failed, use the big axe...
85                 self.message("Transfer unsuccessful, seizing...")
86                 m["fSMORoleOwner"]= ldb.MessageElement(
87                     serviceName, ldb.FLAG_MOD_REPLACE,
88                     "fSMORoleOwner")
89         else:
90             self.message("Will not attempt transfer, seizing...")
91             m["fSMORoleOwner"]= ldb.MessageElement(
92                 serviceName, ldb.FLAG_MOD_REPLACE,
93                 "fSMORoleOwner")
94         try:
95             samdb.modify(m)
96         except LdbError, (num, msg):
97             raise CommandError("Failed to initiate role seize of '%s' role: %s" % (role, msg))
98         print("FSMO transfer of '%s' role successful" % role)
99
100     def run(self, force=None, H=None, role=None,
101             credopts=None, sambaopts=None, versionopts=None):
102             
103         lp = sambaopts.get_loadparm()
104         creds = credopts.get_credentials(lp, fallback_machine=True)
105
106         samdb = SamDB(url=H, session_info=system_session(),
107                       credentials=creds, lp=lp)
108
109         if role == "all":
110             self.seize_role("rid", samdb, force)
111             self.seize_role("pdc", samdb, force)
112             self.seize_role("naming", samdb, force)
113             self.seize_role("infrastructure", samdb, force)
114             self.seize_role("schema", samdb, force)
115         else:
116             self.seize_role(role, samdb, force)
117
118
119
120 class cmd_fsmo_show(Command):
121     """Show the roles"""
122
123     synopsis = "%prog fsmo show [options]"
124
125     takes_options = [
126         Option("-H", "--URL", help="LDB URL for database or target server", type=str,
127                metavar="URL", dest="H"),
128         ]
129
130     takes_args = []
131
132     def run(self, H=None, 
133             credopts=None, sambaopts=None, versionopts=None):
134         lp = sambaopts.get_loadparm()
135         creds = credopts.get_credentials(lp, fallback_machine=True)
136
137         samdb = SamDB(url=H, session_info=system_session(),
138             credentials=creds, lp=lp)
139
140         domain_dn = samdb.domain_dn()
141         self.infrastructure_dn = "CN=Infrastructure," + domain_dn
142         self.naming_dn = "CN=Partitions,CN=Configuration," + domain_dn
143         self.schema_dn = "CN=Schema,CN=Configuration," + domain_dn
144         self.rid_dn = "CN=RID Manager$,CN=System," + domain_dn
145
146         res = samdb.search(self.infrastructure_dn,
147                            scope=ldb.SCOPE_BASE, attrs=["fSMORoleOwner"])
148         assert len(res) == 1
149         self.infrastructureMaster = res[0]["fSMORoleOwner"][0]
150
151         res = samdb.search(domain_dn,
152                            scope=ldb.SCOPE_BASE, attrs=["fSMORoleOwner"])
153         assert len(res) == 1
154         self.pdcEmulator = res[0]["fSMORoleOwner"][0]
155
156         res = samdb.search(self.naming_dn,
157                            scope=ldb.SCOPE_BASE, attrs=["fSMORoleOwner"])
158         assert len(res) == 1
159         self.namingMaster = res[0]["fSMORoleOwner"][0]
160
161         res = samdb.search(self.schema_dn,
162                            scope=ldb.SCOPE_BASE, attrs=["fSMORoleOwner"])
163         assert len(res) == 1
164         self.schemaMaster = res[0]["fSMORoleOwner"][0]
165
166         res = samdb.search(self.rid_dn,
167                            scope=ldb.SCOPE_BASE, attrs=["fSMORoleOwner"])
168         assert len(res) == 1
169         self.ridMaster = res[0]["fSMORoleOwner"][0]
170
171         self.message("InfrastructureMasterRole owner: " + self.infrastructureMaster)
172         self.message("RidAllocationMasterRole owner: " + self.ridMaster)
173         self.message("PdcEmulationMasterRole owner: " + self.pdcEmulator)
174         self.message("DomainNamingMasterRole owner: " + self.namingMaster)
175         self.message("SchemaMasterRole owner: " + self.schemaMaster)
176     
177
178
179 class cmd_fsmo_transfer(Command):
180     """Transfer the role"""
181
182     synopsis = "%prog fsmo transfer [options]"
183
184     takes_options = [
185         Option("-H", "--URL", help="LDB URL for database or target server", type=str,
186                metavar="URL", dest="H"),
187         Option("--role", type="choice", choices=["rid", "pdc", "infrastructure","schema","naming","all"],
188                help="""The FSMO role to seize or transfer.\n
189 rid=RidAllocationMasterRole\n
190 schema=SchemaMasterRole\n
191 pdc=PdcEmulationMasterRole\n
192 naming=DomainNamingMasterRole\n
193 infrastructure=InfrastructureMasterRole\n
194 all=all of the above"""),
195         ]
196
197     takes_args = []
198
199     def transfer_role(self, role, samdb):
200         m = ldb.Message()
201         m.dn = ldb.Dn(samdb, "")
202         if role == "rid":
203             m["becomeRidMaster"]= ldb.MessageElement(
204                 "1", ldb.FLAG_MOD_REPLACE,
205                 "becomeRidMaster")
206         elif role == "pdc":
207             domain_dn = samdb.domain_dn()
208             res = samdb.search(domain_dn,
209                                scope=ldb.SCOPE_BASE, attrs=["objectSid"])
210             assert len(res) == 1
211             sid = res[0]["objectSid"][0]
212             m["becomePdc"]= ldb.MessageElement(
213                 sid, ldb.FLAG_MOD_REPLACE,
214                 "becomePdc")
215         elif role == "naming":
216             m["becomeDomainMaster"]= ldb.MessageElement(
217                 "1", ldb.FLAG_MOD_REPLACE,
218                 "becomeDomainMaster")
219             samdb.modify(m)
220         elif role == "infrastructure":
221             m["becomeInfrastructureMaster"]= ldb.MessageElement(
222                 "1", ldb.FLAG_MOD_REPLACE,
223                 "becomeInfrastructureMaster")
224         elif role == "schema":
225             m["becomeSchemaMaster"]= ldb.MessageElement(
226                 "1", ldb.FLAG_MOD_REPLACE,
227                 "becomeSchemaMaster")
228         else:
229             raise CommandError("Invalid FSMO role.")
230         try:
231             samdb.modify(m)
232         except LdbError, (num, msg):
233             raise CommandError("Failed to initiate transfer of '%s' role: %s" % (role, msg))
234         print("FSMO transfer of '%s' role successful" % role)    
235
236     def run(self, force=None, H=None, role=None,
237             credopts=None, sambaopts=None, versionopts=None):
238
239         lp = sambaopts.get_loadparm()
240         creds = credopts.get_credentials(lp, fallback_machine=True)
241
242         samdb = SamDB(url=H, session_info=system_session(),
243                       credentials=creds, lp=lp)   
244
245         if role == "all":
246             self.transfer_role("rid", samdb)
247             self.transfer_role("pdc", samdb)
248             self.transfer_role("naming", samdb)
249             self.transfer_role("infrastructure", samdb)
250             self.transfer_role("schema", samdb)
251         else:
252             self.transfer_role(role, samdb)
253
254
255
256 class cmd_fsmo(SuperCommand):
257     """Flexible Single Master Operations (FSMO) roles management"""
258
259     subcommands = {}
260     subcommands["seize"] = cmd_fsmo_seize()
261     subcommands["show"] = cmd_fsmo_show()
262     subcommands["transfer"] = cmd_fsmo_transfer()