/
notifier.py
4284 lines (3619 loc) · 158 KB
/
notifier.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
#!/usr/bin/env python
#-
# Copyright (c) 2010-2011 iXsystems, Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
#
""" Helper for FreeNAS to execute command line tools
This helper class abstracts operating system operations like starting,
stopping, restarting services out from the normal Django stuff and makes
future extensions/changes to the command system easier. When used as a
command line utility, this helper class can also be used to do these
actions.
"""
from collections import defaultdict, OrderedDict
import ctypes
import errno
import glob
import grp
import libxml2
import logging
import os
import platform
import pwd
import re
import select
import shutil
import signal
import sqlite3
import stat
from subprocess import Popen, PIPE
import subprocess
import sys
import tempfile
import threading
import time
import types
WWW_PATH = "/usr/local/www"
FREENAS_PATH = os.path.join(WWW_PATH, "freenasUI")
NEED_UPDATE_SENTINEL = '/data/need-update'
VERSION_FILE = '/etc/version'
GELI_KEYPATH = '/data/geli'
sys.path.append(WWW_PATH)
sys.path.append(FREENAS_PATH)
os.environ["DJANGO_SETTINGS_MODULE"] = "freenasUI.settings"
from django.db import models
from django.db.models import Q
from freenasUI.common.acl import ACL_FLAGS_OS_WINDOWS, ACL_WINDOWS_FILE
from freenasUI.common.freenasacl import ACL, ACL_Hierarchy
from freenasUI.common.jail import Jls, Jexec
from freenasUI.common.locks import mntlock
from freenasUI.common.pbi import (pbi_add, pbi_delete,
pbi_info, pbi_create, pbi_makepatch, pbi_patch,
PBI_ADD_FLAGS_NOCHECKSIG, PBI_ADD_FLAGS_INFO,
PBI_ADD_FLAGS_EXTRACT_ONLY, PBI_ADD_FLAGS_OUTDIR,
PBI_ADD_FLAGS_OUTPATH, PBI_ADD_FLAGS_FORCE,
PBI_INFO_FLAGS_VERBOSE, PBI_CREATE_FLAGS_OUTDIR,
PBI_CREATE_FLAGS_BACKUP, PBI_MAKEPATCH_FLAGS_OUTDIR,
PBI_MAKEPATCH_FLAGS_NOCHECKSIG, PBI_PATCH_FLAGS_OUTDIR,
PBI_PATCH_FLAGS_NOCHECKSIG)
from freenasUI.common.system import get_mounted_filesystems, umount, get_sw_name
from freenasUI.common.warden import (Warden, WardenJail,
WARDEN_KEY_HOST, WARDEN_KEY_TYPE, WARDEN_KEY_STATUS,
WARDEN_TYPE_PLUGINJAIL, WARDEN_STATUS_RUNNING)
from freenasUI.middleware import zfs
from freenasUI.middleware.encryption import random_wipe
from freenasUI.middleware.exceptions import MiddlewareError
from freenasUI.middleware.multipath import Multipath
log = logging.getLogger('middleware.notifier')
class Byte(object):
"""
Used in sysctl hack to return a byte array
"""
def __init__(self, array, as_string=True):
self.array = array
self.as_string = as_string
@property
def value(self):
array = ""
for byte in self.array:
if byte == 0 and self.as_string:
break
array += chr(byte)
return array
class StartNotify(threading.Thread):
"""
Use kqueue to watch for an event before actually calling start/stop
This should help against synchronization and more responsive notify.
"""
def __init__(self, pidfile, verb, *args, **kwargs):
self._pidfile = pidfile
self._verb = verb
super(StartNotify, self).__init__(*args, **kwargs)
def run(self):
if not self._pidfile:
return None
"""
If we are using start or restart we expect that a .pid file will
exists at the end of the process, so attach to the directory waiting
for that file.
Otherwise we will be stopping and expect the .pid to be deleted, so
attach to the .pid file and wait for it to be removed
"""
if self._verb in ('start', 'restart'):
fflags = select.KQ_NOTE_WRITE|select.KQ_NOTE_EXTEND
_file = os.path.dirname(self._pidfile)
else:
fflags = select.KQ_NOTE_WRITE|select.KQ_NOTE_DELETE
if os.path.exists(self._pidfile):
_file = self._pidfile
else:
_file = os.path.dirname(self._pidfile)
fd = os.open(_file, os.O_RDONLY)
evts = [
select.kevent(fd,
filter=select.KQ_FILTER_VNODE,
flags=select.KQ_EV_ADD|select.KQ_EV_CLEAR,
fflags=fflags,
)
]
kq = select.kqueue()
kq.control(evts, 0, 0)
tries = 1
while tries < 4:
rv = kq.control(None, 2, 1)
if self._verb in ('start', 'restart'):
if os.path.exists(self._pidfile):
# The file might have been created but it may take a little bit
# for the daemon to write the PID
time.sleep(0.1)
if os.path.exists(self._pidfile) and os.stat(self._pidfile).st_size > 0:
break
elif self._verb == "stop" and not os.path.exists(self._pidfile):
break
tries += 1
kq.close()
os.close(fd)
class notifier:
from os import system as ___system
from pwd import getpwnam as ___getpwnam
IDENTIFIER = 'notifier'
def __system(self, command):
log.debug("Executing: %s", command)
# TODO: python's signal class should be taught about sigprocmask(2)
# This is hacky hack to work around this issue.
libc = ctypes.cdll.LoadLibrary("libc.so.7")
omask = (ctypes.c_uint32 * 4)(0, 0, 0, 0)
mask = (ctypes.c_uint32 * 4)(0, 0, 0, 0)
pmask = ctypes.pointer(mask)
pomask = ctypes.pointer(omask)
libc.sigprocmask(signal.SIGQUIT, pmask, pomask)
try:
self.___system("(" + command + ") 2>&1 | logger -p daemon.notice -t %s"
% (self.IDENTIFIER, ))
finally:
libc.sigprocmask(signal.SIGQUIT, pomask, None)
log.debug("Executed: %s", command)
def __system_nolog(self, command):
log.debug("Executing: %s", command)
# TODO: python's signal class should be taught about sigprocmask(2)
# This is hacky hack to work around this issue.
libc = ctypes.cdll.LoadLibrary("libc.so.7")
omask = (ctypes.c_uint32 * 4)(0, 0, 0, 0)
mask = (ctypes.c_uint32 * 4)(0, 0, 0, 0)
pmask = ctypes.pointer(mask)
pomask = ctypes.pointer(omask)
libc.sigprocmask(signal.SIGQUIT, pmask, pomask)
try:
retval = self.___system("(" + command + ") >/dev/null 2>&1")
finally:
libc.sigprocmask(signal.SIGQUIT, pomask, None)
retval >>= 8
log.debug("Executed: %s; returned %d", command, retval)
return retval
def __pipeopen(self, command):
log.debug("Popen()ing: %s", command)
return Popen(command, stdin=PIPE, stdout=PIPE, stderr=PIPE, shell=True, close_fds=True)
def _do_nada(self):
pass
def _simplecmd(self, action, what):
log.debug("Calling: %s(%s) ", action, what)
f = getattr(self, '_' + action + '_' + what, None)
if f is None:
# Provide generic start/stop/restart verbs for rc.d scripts
if action in ("start", "stop", "restart", "reload"):
if action == 'restart':
self.__system("/usr/sbin/service " + what + " forcestop ")
self.__system("/usr/sbin/service " + what + " " + action)
f = self._do_nada
else:
raise ValueError("Internal error: Unknown command")
f()
__service2daemon = {
'ssh': ('sshd', '/var/run/sshd.pid'),
'rsync': ('rsync', '/var/run/rsyncd.pid'),
'nfs': ('nfsd', None),
'afp': ('afpd', None),
'cifs': ('smbd', '/var/run/samba/smbd.pid'),
'dynamicdns': ('inadyn-mt', None),
'snmp': ('bsnmpd', '/var/run/snmpd.pid'),
'ftp': ('proftpd', '/var/run/proftpd.pid'),
'tftp': ('inetd', '/var/run/inetd.pid'),
'iscsitarget': ('istgt', '/var/run/istgt.pid'),
'ups': ('upsd', '/var/db/nut/upsd.pid'),
'upsmon': ('upsmon', '/var/db/nut/upsmon.pid'),
'smartd': ('smartd', '/var/run/smartd.pid'),
'webshell': (None, '/var/run/webshell.pid'),
}
def _started_notify(self, verb, what):
"""
The check for started [or not] processes is currently done in 2 steps
This is the first step which involves a thread StartNotify that watch for event
before actually start/stop rc.d scripts
Returns:
StartNotify object if the service is known or None otherwise
"""
if what in self.__service2daemon:
procname, pidfile = self.__service2daemon[what]
sn = StartNotify(verb=verb, pidfile=pidfile)
sn.start()
return sn
else:
return None
def _started(self, what, notify=None):
"""
This is the second step::
Wait for the StartNotify thread to finish and then check for the
status of pidfile/procname using pgrep
Returns:
True whether the service is alive, False otherwise
"""
if what in self.__service2daemon:
procname, pidfile = self.__service2daemon[what]
if notify:
notify.join()
if pidfile:
procname = " " + procname if procname else ""
retval = self.__pipeopen("/bin/pgrep -F %s%s" % (pidfile, procname)).wait()
else:
retval = self.__pipeopen("/bin/pgrep %s" % (procname,)).wait()
if retval == 0:
return True
else:
return False
else:
return False
def init(self, what, objectid=None, *args, **kwargs):
""" Dedicated command to create "what" designated by an optional objectid.
The helper will use method self._init_[what]() to create the object"""
if objectid is None:
self._simplecmd("init", what)
else:
f = getattr(self, '_init_' + what)
f(objectid, *args, **kwargs)
def destroy(self, what, objectid=None):
if objectid is None:
raise ValueError("Calling destroy without id")
else:
f = getattr(self, '_destroy_' + what)
f(objectid)
def start(self, what):
""" Start the service specified by "what".
The helper will use method self._start_[what]() to start the service.
If the method does not exist, it would fallback using service(8)."""
sn = self._started_notify("start", what)
self._simplecmd("start", what)
return self.started(what, sn)
def started(self, what, sn=None):
""" Test if service specified by "what" has been started. """
f = getattr(self, '_started_' + what, None)
if callable(f):
return f()
else:
return self._started(what, sn)
def stop(self, what):
""" Stop the service specified by "what".
The helper will use method self._stop_[what]() to stop the service.
If the method does not exist, it would fallback using service(8)."""
sn = self._started_notify("stop", what)
self._simplecmd("stop", what)
return self.started(what, sn)
def restart(self, what):
""" Restart the service specified by "what".
The helper will use method self._restart_[what]() to restart the service.
If the method does not exist, it would fallback using service(8)."""
sn = self._started_notify("restart", what)
self._simplecmd("restart", what)
return self.started(what, sn)
def reload(self, what):
""" Reload the service specified by "what".
The helper will use method self._reload_[what]() to reload the service.
If the method does not exist, the helper will try self.restart of the
service instead."""
try:
self._simplecmd("reload", what)
except:
self.restart(what)
return self.started(what)
def change(self, what):
""" Notify the service specified by "what" about a change.
The helper will use method self.reload(what) to reload the service.
If the method does not exist, the helper will try self.start the
service instead."""
try:
self.reload(what)
except:
self.start(what)
def _start_webshell(self):
self.__system_nolog("/usr/local/bin/python /usr/local/www/freenasUI/tools/webshell.py")
def _restart_webshell(self):
try:
with open('/var/run/webshell.pid', 'r') as f:
pid = f.read()
os.kill(int(pid), signal.SIGHUP)
time.sleep(0.2)
except:
pass
self.__system_nolog("/usr/local/bin/python /usr/local/www/freenasUI/tools/webshell.py")
def _restart_iscsitarget(self):
self.__system("/usr/sbin/service ix-istgt quietstart")
self.__system("/usr/sbin/service istgt forcestop")
self.__system("/usr/sbin/service istgt restart")
def _restart_collectd(self):
self.__system("/usr/sbin/service ix-collectd quietstart")
self.__system("/usr/sbin/service collectd restart")
def _start_iscsitarget(self):
self.__system("/usr/sbin/service ix-istgt quietstart")
self.__system("/usr/sbin/service istgt restart")
def _stop_iscsitarget(self):
self.__system("/usr/sbin/service istgt forcestop")
def _reload_iscsitarget(self):
self.__system("/usr/sbin/service ix-istgt quietstart")
self.__system("/usr/sbin/service istgt reload")
def _start_sysctl(self):
self.__system("/usr/sbin/service sysctl start")
self.__system("/usr/sbin/service ix-sysctl quietstart")
def _reload_sysctl(self):
self.__system("/usr/sbin/service sysctl start")
self.__system("/usr/sbin/service ix-sysctl reload")
def _start_network(self):
c = self.__open_db()
c.execute("SELECT COUNT(n.id) FROM network_interfaces n LEFT JOIN network_alias a ON a.alias_interface_id=n.id WHERE int_ipv6auto = 1 OR int_ipv6address != '' OR alias_v6address != ''")
ipv6_interfaces = c.fetchone()[0]
if ipv6_interfaces > 0:
try:
auto_linklocal = self.sysctl("net.inet6.ip6.auto_linklocal", _type='INT')
except AssertionError:
auto_linklocal = 0
if auto_linklocal == 0:
self.__system("/sbin/sysctl net.inet6.ip6.auto_linklocal=1")
self.__system("/usr/sbin/service autolink auto_linklocal quietstart")
self.__system("/usr/sbin/service netif stop")
self.__system("/etc/netstart")
def ifconfig_alias(self, iface, oldip=None, newip=None, oldnetmask=None, newnetmask=None):
if not iface:
return False
cmd = "/sbin/ifconfig %s" % iface
if newip and newnetmask:
cmd += " alias %s/%s" % (newip, newnetmask)
elif newip:
cmd += " alias %s" % newip
else:
cmd = None
if cmd:
p = self.__pipeopen(cmd)
if p.wait() != 0:
return False
cmd = "/sbin/ifconfig %s" % iface
if newip:
cmd += " -alias %s" % oldip
p = self.__pipeopen(cmd)
if p.wait() != 0:
return False
if newnetmask and not newip:
cmd += " alias %s/%s" % (oldip, newnetmask)
else:
cmd = None
if cmd:
p = self.__pipeopen(cmd)
if p.wait() != 0:
return False
return True
def _reload_named(self):
self.__system("/usr/sbin/service named reload")
def _reload_networkgeneral(self):
self.__system('/bin/hostname ""')
self.__system("/usr/sbin/service ix-hostname quietstart")
self.__system("/usr/sbin/service hostname quietstart")
self.__system("/usr/sbin/service routing restart")
def _reload_timeservices(self):
self.__system("/usr/sbin/service ix-localtime quietstart")
self.__system("/usr/sbin/service ix-ntpd quietstart")
self.__system("/usr/sbin/service ntpd restart")
c = self.__open_db()
c.execute("SELECT stg_timezone FROM system_settings ORDER BY -id LIMIT 1")
os.environ['TZ'] = c.fetchone()[0]
time.tzset()
def _restart_smartd(self):
self.__system("/usr/sbin/service ix-smartd quietstart")
self.__system("/usr/sbin/service smartd forcestop")
self.__system("/usr/sbin/service smartd restart")
def _reload_ssh(self):
self.__system("/usr/sbin/service ix-sshd quietstart")
self.__system("/usr/sbin/service sshd reload")
def _start_ssh(self):
self.__system("/usr/sbin/service ix-sshd quietstart")
self.__system("/usr/sbin/service sshd start")
def _stop_ssh(self):
self.__system("/usr/sbin/service sshd forcestop")
def _restart_ssh(self):
self.__system("/usr/sbin/service ix-sshd quietstart")
self.__system("/usr/sbin/service sshd forcestop")
self.__system("/usr/sbin/service sshd restart")
def _reload_rsync(self):
self.__system("/usr/sbin/service ix-rsyncd quietstart")
self.__system("/usr/sbin/service rsyncd restart")
def _restart_rsync(self):
self.__system("/usr/sbin/service ix-rsyncd quietstart")
self.__system("/usr/sbin/service rsyncd forcestop")
self.__system("/usr/sbin/service rsyncd restart")
def _get_stg_directoryservice(self):
c = self.__open_db()
c.execute("SELECT stg_directoryservice FROM system_settings ORDER BY -id LIMIT 1")
return c.fetchone()[0]
def _started_nis(self):
res = False
if self._get_stg_directoryservice() == 'nis':
res = self.__system_nolog("/etc/directoryservice/NIS/ctl status")
return (True if res == 0 else False)
def _start_nis(self):
res = False
if self._get_stg_directoryservice() == 'nis':
res = self.__system_nolog("/etc/directoryservice/NIS/ctl start")
return (True if res == 0 else False)
def _restart_nis(self):
res = False
if self._get_stg_directoryservice() == 'nis':
res = self.__system_nolog("/etc/directoryservice/NIS/ctl restart")
return (True if res == 0 else False)
def _stop_nis(self):
res = False
if self._get_stg_directoryservice() == 'nis':
res = self.__system_nolog("/etc/directoryservice/NIS/ctl stop")
return (True if res == 0 else False)
def _started_ldap(self):
from freenasUI.common.freenasldap import FreeNAS_LDAP, FLAGS_DBINIT
from freenasUI.common.system import ldap_enabled
ret = False
if ldap_enabled():
f = FreeNAS_LDAP(flags=FLAGS_DBINIT)
f.open()
if f.isOpen():
ret = True
else:
ret = False
f.close()
return ret
def _start_ldap(self):
res = False
if self._get_stg_directoryservice() == 'ldap':
res = self.__system_nolog("/etc/directoryservice/LDAP/ctl start")
return (True if res == 0 else False)
def _stop_ldap(self):
res = False
if self._get_stg_directoryservice() == 'ldap':
res = self.__system_nolog("/etc/directoryservice/LDAP/ctl stop")
return (True if res == 0 else False)
def _restart_ldap(self):
res = False
if self._get_stg_directoryservice() == 'ldap':
res = self.__system_nolog("/etc/directoryservice/LDAP/ctl restart")
return (True if res == 0 else False)
def _clear_activedirectory_config(self):
self.__system("/bin/rm -f /etc/directoryservice/ActiveDirectory/config")
def _started_nt4(self):
res = False
if self._get_stg_directoryservice() == 'nt4':
res = self.__system_nolog("/etc/rc.d/ix-nt4 status")
return (True if res == 0 else False)
def _start_nt4(self):
res = False
if self._get_stg_directoryservice() == 'nt4':
res = self.__system_nolog("/etc/directoryservice/NT4/ctl start")
return (True if res == 0 else False)
def _restart_nt4(self):
res = False
if self._get_stg_directoryservice() == 'nt4':
res = self.__system_nolog("/etc/directoryservice/NT4/ctl restart")
return (True if res == 0 else False)
def _stop_nt4(self):
res = False
if self._get_stg_directoryservice() == 'nt4':
res = self.__system_nolog("/etc/directoryservice/NT4/ctl stop")
return (True if res == 0 else False)
def _started_activedirectory(self):
from freenasUI.common.freenasldap import (FreeNAS_ActiveDirectory, FLAGS_DBINIT)
from freenasUI.common.system import activedirectory_enabled
for srv in ('kinit', 'activedirectory', ):
if (self.__system_nolog('/usr/sbin/service ix-%s status' % (srv, ))
!= 0):
return False
ret = False
if activedirectory_enabled():
f = FreeNAS_ActiveDirectory(flags=FLAGS_DBINIT)
f.open()
if f.isOpen():
ret = True
else:
ret = False
f.close()
return ret
def _start_activedirectory(self):
res = False
if self._get_stg_directoryservice() == 'activedirectory':
res = self.__system_nolog("/etc/directoryservice/ActiveDirectory/ctl start")
return (True if res == 0 else False)
def _stop_activedirectory(self):
res = False
if self._get_stg_directoryservice() == 'activedirectory':
res = self.__system_nolog("/etc/directoryservice/ActiveDirectory/ctl stop")
return (True if res == 0 else False)
def _restart_activedirectory(self):
res = False
if self._get_stg_directoryservice() == 'activedirectory':
res = self.__system_nolog("/etc/directoryservice/ActiveDirectory/ctl restart")
return (True if res == 0 else False)
def _restart_syslogd(self):
self.__system("/usr/sbin/service ix-syslogd quietstart")
self.__system("/usr/sbin/service syslogd restart")
def _start_syslogd(self):
self.__system("/usr/sbin/service ix-syslogd quietstart")
self.__system("/usr/sbin/service syslogd start")
def _reload_tftp(self):
self.__system("/usr/sbin/service ix-inetd quietstart")
self.__system("/usr/sbin/service inetd forcestop")
self.__system("/usr/sbin/service inetd restart")
def _restart_tftp(self):
self.__system("/usr/sbin/service ix-inetd quietstart")
self.__system("/usr/sbin/service inetd forcestop")
self.__system("/usr/sbin/service inetd restart")
def _restart_cron(self):
self.__system("/usr/sbin/service ix-crontab quietstart")
self.__system("/usr/sbin/service cron restart")
def _start_motd(self):
self.__system("/usr/sbin/service ix-motd quietstart")
self.__system("/usr/sbin/service motd quietstart")
def _start_ttys(self):
self.__system("/usr/sbin/service ix-ttys quietstart")
def _reload_ftp(self):
self.__system("/usr/sbin/service ix-proftpd quietstart")
self.__system("/usr/sbin/service proftpd restart")
def _restart_ftp(self):
self.__system("/usr/sbin/service ix-proftpd quietstart")
self.__system("/usr/sbin/service proftpd forcestop")
self.__system("/usr/sbin/service proftpd restart")
self.__system("sleep 1")
def _start_ftp(self):
self.__system("/usr/sbin/service ix-proftpd quietstart")
self.__system("/usr/sbin/service proftpd start")
def _start_ups(self):
self.__system("/usr/sbin/service ix-ups quietstart")
self.__system("/usr/sbin/service nut start")
self.__system("/usr/sbin/service nut_upsmon start")
self.__system("/usr/sbin/service nut_upslog start")
def _stop_ups(self):
self.__system("/usr/sbin/service nut_upslog forcestop")
self.__system("/usr/sbin/service nut_upsmon forcestop")
self.__system("/usr/sbin/service nut forcestop")
def _restart_ups(self):
self.__system("/usr/sbin/service ix-ups quietstart")
self.__system("/usr/sbin/service nut forcestop")
self.__system("/usr/sbin/service nut_upsmon forcestop")
self.__system("/usr/sbin/service nut_upslog forcestop")
self.__system("/usr/sbin/service nut restart")
self.__system("/usr/sbin/service nut_upsmon restart")
self.__system("/usr/sbin/service nut_upslog restart")
def _started_ups(self):
from freenasUI.services.models import UPS
mode = UPS.objects.order_by('-id')[0].ups_mode
if mode == "master":
svc = "ups"
else:
svc = "upsmon"
sn = self._started_notify("upsmon")
return self._started(svc, sn)
def _load_afp(self):
self.__system("/usr/sbin/service ix-afpd quietstart")
self.__system("/usr/sbin/service dbus quietstart")
self.__system("/usr/sbin/service avahi-daemon quietstart")
self.__system("/usr/sbin/service netatalk quietstart")
def _start_afp(self):
self.__system("/usr/sbin/service ix-afpd start")
self.__system("/usr/sbin/service dbus start")
self.__system("/usr/sbin/service avahi-daemon start")
self.__system("/usr/sbin/service netatalk start")
def _stop_afp(self):
# XXX: fix rc.d/netatalk to honor the force verbs properly.
self.__system("killall afpd")
self.__system("/usr/sbin/service avahi-daemon forcestop")
self.__system("/usr/sbin/service dbus forcestop")
def _restart_afp(self):
self._stop_afp()
self._start_afp()
def _reload_afp(self):
self.__system("/usr/sbin/service ix-afpd quietstart")
self.__system("killall -1 avahi-daemon")
self.__system("killall -1 afpd")
def _reload_nfs(self):
self.__system("/usr/sbin/service ix-nfsd quietstart")
self.__system("/usr/sbin/service mountd reload")
def _restart_nfs(self):
self.__system("/usr/sbin/service lockd forcestop")
self.__system("/usr/sbin/service statd forcestop")
self.__system("/usr/sbin/service mountd forcestop")
self.__system("/usr/sbin/service nfsd forcestop")
self.__system("/usr/sbin/service ix-nfsd quietstart")
self.__system("/usr/sbin/service mountd quietstart")
self.__system("/usr/sbin/service nfsd quietstart")
self.__system("/usr/sbin/service statd quietstart")
self.__system("/usr/sbin/service lockd quietstart")
def _stop_nfs(self):
self.__system("/usr/sbin/service lockd forcestop")
self.__system("/usr/sbin/service statd forcestop")
self.__system("/usr/sbin/service mountd forcestop")
self.__system("/usr/sbin/service nfsd forcestop")
def _start_nfs(self):
self.__system("/usr/sbin/service ix-nfsd quietstart")
self.__system("/usr/sbin/service mountd quietstart")
self.__system("/usr/sbin/service nfsd quietstart")
self.__system("/usr/sbin/service statd quietstart")
self.__system("/usr/sbin/service lockd quietstart")
def _force_stop_jail(self):
self.__system("/usr/sbin/service jail forcestop")
def _start_plugins(self, jail=None, plugin=None):
if jail and plugin:
self.__system_nolog("/usr/sbin/service ix-plugins forcestart %s:%s" % (jail, plugin))
else:
self.__system_nolog("/usr/sbin/service ix-plugins forcestart")
def _stop_plugins(self, jail=None, plugin=None):
if jail and plugin:
self.__system_nolog("/usr/sbin/service ix-plugins forcestop %s:%s" % (jail, plugin))
else:
self.__system_nolog("/usr/sbin/service ix-plugins forcestop")
def _restart_plugins(self, jail=None, plugin=None):
self._stop_plugins(jail, plugin)
self._start_plugins(jail, plugin)
def _started_plugins(self, jail=None, plugin=None):
res = False
if jail and plugin:
if self.__system_nolog("/usr/sbin/service ix-plugins status %s:%s" % (jail, plugin)) == 0:
res = True
else:
if self.__system_nolog("/usr/sbin/service ix-plugins status") == 0:
res = True
return res
def pluginjail_running(self, pjail=None):
running = False
try:
wlist = Warden().list()
for wj in wlist:
wj = WardenJail(**wj)
if pjail and wj.host == pjail:
if wj.type == WARDEN_TYPE_PLUGINJAIL and \
wj.status == WARDEN_STATUS_RUNNING:
running = True
break
elif not pjail and wj.type == WARDEN_TYPE_PLUGINJAIL and \
wj.status == WARDEN_STATUS_RUNNING:
running = True
break
except:
pass
return running
def start_ataidle(self, what=None):
if what is not None:
self.__system("/usr/sbin/service ix-ataidle quietstart %s" % what)
else:
self.__system("/usr/sbin/service ix-ataidle quietstart")
def start_ssl(self, what=None):
if what is not None:
self.__system("/usr/sbin/service ix-ssl quietstart %s" % what)
else:
self.__system("/usr/sbin/service ix-ssl quietstart")
def _restart_dynamicdns(self):
self.__system("/usr/sbin/service ix-inadyn quietstart")
self.__system("/usr/sbin/service inadyn-mt restart")
def _restart_system(self):
self.__system("/bin/sleep 3 && /sbin/shutdown -r now &")
def _stop_system(self):
self.__system("/sbin/shutdown -p now")
def _reload_cifs(self):
self.__system("/usr/sbin/service ix-samba quietstart")
self.__system("killall -1 avahi-daemon")
self.__system("/usr/sbin/service samba forcereload")
def _restart_cifs(self):
self.__system("/usr/sbin/service ix-samba quietstart")
self.__system("/usr/sbin/service dbus forcestop")
self.__system("/usr/sbin/service dbus restart")
self.__system("/usr/sbin/service avahi-daemon forcestop")
self.__system("/usr/sbin/service avahi-daemon restart")
self.__system("/usr/sbin/service samba forcestop")
self.__system("/usr/sbin/service samba quietrestart")
def _start_cifs(self):
self.__system("/usr/sbin/service ix-samba quietstart")
self.__system("/usr/sbin/service dbus quietstart")
self.__system("/usr/sbin/service avahi-daemon quietstart")
self.__system("/usr/sbin/service samba quietstart")
def _stop_cifs(self):
self.__system("/usr/sbin/service dbus forcestop")
self.__system("/usr/sbin/service dbus restart")
self.__system("/usr/sbin/service avahi-daemon forcestop")
self.__system("/usr/sbin/service avahi-daemon restart")
self.__system("/usr/sbin/service samba forcestop")
def _start_snmp(self):
self.__system("/usr/sbin/service ix-bsnmpd quietstart")
self.__system("/usr/sbin/service bsnmpd quietstart")
def _stop_snmp(self):
self.__system("/usr/sbin/service bsnmpd quietstop")
def _restart_snmp(self):
self.__system("/usr/sbin/service ix-bsnmpd quietstart")
self.__system("/usr/sbin/service bsnmpd forcestop")
self.__system("/usr/sbin/service bsnmpd quietstart")
def _restart_http(self):
self.__system("/usr/sbin/service ix-nginx quietstart")
self.__system("/usr/sbin/service nginx restart")
def _reload_http(self):
self.__system("/usr/sbin/service ix-nginx quietstart")
self.__system("/usr/sbin/service nginx reload")
def _reload_loader(self):
self.__system("/usr/sbin/service ix-loader reload")
def _start_loader(self):
self.__system("/usr/sbin/service ix-loader quietstart")
def __saver_loaded(self):
pipe = os.popen("kldstat|grep daemon_saver")
out = pipe.read().strip('\n')
pipe.close()
return (len(out) > 0)
def _start_saver(self):
if not self.__saver_loaded():
self.__system("kldload daemon_saver")
def _stop_saver(self):
if self.__saver_loaded():
self.__system("kldunload daemon_saver")
def _restart_saver(self):
self._stop_saver()
self._start_saver()
def __open_db(self, ret_conn=False):
"""Open and return a cursor object for database access."""
try:
from freenasUI.settings import DATABASES
dbname = DATABASES['default']['NAME']
except:
dbname = '/data/freenas-v1.db'
conn = sqlite3.connect(dbname)
c = conn.cursor()
if ret_conn:
return c, conn
return c
def __gpt_labeldisk(self, type, devname, swapsize=2):
"""Label the whole disk with GPT under the desired label and type"""
# Calculate swap size.
swapgb = swapsize
swapsize = swapsize * 1024 * 1024 * 2
# Round up to nearest whole integral multiple of 128 and subtract by 34
# so next partition starts at mutiple of 128.
swapsize = ((swapsize+127)/128)*128
# To be safe, wipe out the disk, both ends... before we start
self.__system("dd if=/dev/zero of=/dev/%s bs=1m count=1" % (devname, ))
try:
p1 = self.__pipeopen("diskinfo %s" % (devname, ))
size = int(re.sub(r'\s+', ' ', p1.communicate()[0]).split()[2]) / (1024)
except:
log.error("Unable to determine size of %s", devname)
else:
# The GPT header takes about 34KB + alignment, round it to 100
if size - 100 <= swapgb * 1024 * 1024:
raise MiddlewareError('Your disk size must be higher than %dGB' % (swapgb, ))
# HACK: force the wipe at the end of the disk to always succeed. This
# is a lame workaround.
self.__system("dd if=/dev/zero of=/dev/%s bs=1m oseek=%s" % (
devname,
size / 1024 - 4,
))
commands = []
commands.append("gpart create -s gpt /dev/%s" % (devname, ))
if swapsize > 0:
commands.append("gpart add -b 128 -t freebsd-swap -s %d %s" % (swapsize, devname))
commands.append("gpart add -t %s %s" % (type, devname))
else:
commands.append("gpart add -b 128 -t %s %s" % (type, devname))
# Install a dummy boot block so system gives meaningful message if booting
# from the wrong disk.
commands.append("gpart bootcode -b /boot/pmbr-datadisk /dev/%s" % (devname))
for command in commands:
proc = self.__pipeopen(command)
proc.wait()
if proc.returncode != 0:
raise MiddlewareError('Unable to GPT format the disk "%s"' % devname)
# We might need to sync with reality (e.g. devname -> uuid)
# Invalidating confxml is required or changes wont be seen
self.__confxml = None
self.sync_disk(devname)
def __gpt_unlabeldisk(self, devname):
"""Unlabel the disk"""
swapdev = self.part_type_from_device('swap', devname)
if swapdev != '':
self.__system("swapoff /dev/%s.eli" % swapdev)
self.__system("geli detach /dev/%s" % swapdev)
self.__system("gpart destroy -F /dev/%s" % devname)
# Wipe out the partition table by doing an additional iterate of create/destroy
self.__system("gpart create -s gpt /dev/%s" % devname)
self.__system("gpart destroy -F /dev/%s" % devname)
# We might need to sync with reality (e.g. uuid -> devname)
# Invalidating confxml is required or changes wont be seen
self.__confxml = None