Checkin of 0.2.98 upstream source
[time-slider.git] / usr / share / time-slider / lib / time_slider / autosnapsmf.py
1 #!/usr/bin/python2.6
2 #
3 # CDDL HEADER START
4 #
5 # The contents of this file are subject to the terms of the
6 # Common Development and Distribution License (the "License").
7 # You may not use this file except in compliance with the License.
8 #
9 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 # or http://www.opensolaris.org/os/licensing.
11 # See the License for the specific language governing permissions
12 # and limitations under the License.
13 #
14 # When distributing Covered Code, include this CDDL HEADER in each
15 # file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 # If applicable, add the following below this CDDL HEADER, with the
17 # fields enclosed by brackets "[]" replaced with your own identifying
18 # information: Portions Copyright [yyyy] [name of copyright owner]
19 #
20 # CDDL HEADER END
21 #
22
23 import threading
24 import smf
25 import util
26
27 factoryDefaultSchedules = ("monthly", "weekly", "daily", "hourly", "frequent")
28
29 BASESVC= "svc:/system/filesystem/zfs/auto-snapshot"
30 SNAPLABELPREFIX = "zfs-auto-snap"
31 ZFSPROPGROUP = "zfs"
32
33
34 # Bombarding the class with schedule queries causes the occasional
35 # OSError exception due to interrupted system calls.
36 # Serialising them helps prevent this unlikely event from occuring.
37 _scheddetaillock = threading.RLock()
38
39 class AutoSnap(smf.SMFInstance):
40
41     def __init__(self, schedule):
42         smf.SMFInstance.__init__(self, "%s:%s" % (BASESVC, schedule))
43         self.schedule = schedule
44
45     def get_schedule_details(self):
46         svc= "%s:%s" % (BASESVC, self.schedule)
47         _scheddetaillock.acquire()
48         try:
49             interval = self.get_prop(ZFSPROPGROUP, "interval")
50             period = int(self.get_prop(ZFSPROPGROUP, "period"))
51             keep =  int(self.get_prop(ZFSPROPGROUP, "keep"))
52
53         except OSError, message:
54             raise RuntimeError, "%s subprocess error:\n %s" % \
55                                 (cmd, str(message))
56         finally:
57             _scheddetaillock.release()
58       
59         return [self.schedule, interval, period, keep]
60
61 # FIXME - merge with enable_default_schedules()
62 def disable_default_schedules():
63     """
64     Disables the default auto-snapshot SMF instances corresponding
65     to: "frequent", "hourly", "daily", "weekly" and "monthly"
66     schedules
67     Raises RuntimeError exception if unsuccessful
68     """
69
70     for s in factoryDefaultSchedules:
71         # Acquire the scheddetail lock since their status will
72         # likely be changed as a result of enabling the instances.
73         _scheddetaillock.acquire()
74         instanceName = "%s:%s" % (BASESVC,s)
75         svc = smf.SMFInstance(instanceName)
76         svc.disable_service()
77         _scheddetaillock.release()
78
79 def enable_default_schedules():
80     """
81     Enables the default auto-snapshot SMF instances corresponding
82     to: "frequent", "hourly", "daily", "weekly" and "monthly"
83     schedules
84     Raises RuntimeError exception if unsuccessful
85     """
86     for s in factoryDefaultSchedules:
87         # Acquire the scheddetail lock since their status will
88         # likely be changed as a result of enabling the instances.
89         _scheddetaillock.acquire()
90         instanceName = "%s:%s" % (BASESVC,s)
91         svc = smf.SMFInstance(instanceName)
92         svc.enable_service()
93         _scheddetaillock.release()
94
95 def get_default_schedules():
96     """
97     Finds the default schedules that are enabled (online, offline or degraded)
98     """
99     #This is not the fastest method but it is the safest, we need
100     #to ensure that default schedules are processed in the pre-defined
101     #order to ensure that the overlap between them is adhered to
102     #correctly. monthly->weekly->daily->hourly->frequent. They have
103     #to be processed first and they HAVE to be in the correct order.
104     _defaultSchedules = []
105     for s in factoryDefaultSchedules:
106         instanceName = "%s:%s" % (BASESVC,s)
107         cmd = [smf.SVCSCMD, "-H", "-o", "state", instanceName]
108         _scheddetaillock.acquire()
109         try:
110             outdata,errdata = util.run_command(cmd)
111         finally:
112             _scheddetaillock.release()
113         result = outdata.rstrip()
114         # Note that the schedules, being dependent on the time-slider service
115         # itself will typically be in an offline state when enabled. They will
116         # transition to an "online" state once time-slider itself comes
117         # "online" to satisfy it's dependency
118         if result == "online" or result == "offline" or result == "degraded":
119             instance = AutoSnap(s)
120             try:
121                 _defaultSchedules.append(instance.get_schedule_details())
122             except RuntimeError, message:
123                 raise RuntimeError, "Error getting schedule details for " + \
124                                     "default auto-snapshot SMF instance:" + \
125                                     "\n\t" + instanceName + "\nDetails:\n" + \
126                                     str(message)
127     return _defaultSchedules
128
129 def get_custom_schedules():
130     """
131     Finds custom schedules ie. not the factory default
132     'monthly', 'weekly', 'hourly', 'daily' and 'frequent' schedules
133     """
134     _customSchedules = []
135     cmd = [smf.SVCSCMD, "-H", "-o", "state,FMRI", BASESVC]
136     _scheddetaillock.acquire()
137     try:
138         outdata,errdata = util.run_command(cmd)
139     finally:
140         _scheddetaillock.release()
141
142     for line in outdata.rstrip().split('\n'):
143         line = line.rstrip().split()
144         state = line[0]
145         fmri = line[1]
146         fmri = fmri.rsplit(":", 1)
147         label = fmri[1]
148         if label not in factoryDefaultSchedules:
149         # Note that the schedules, being dependent on the time-slider service
150         # itself will typically be in an offline state when enabled. They will
151         # transition to an "online" state once time-slider itself comes
152         # "online" to satisfy it's dependency
153             if state == "online" or state == "offline" or state == "degraded":
154                 instance = AutoSnap(label)
155                 try:
156                     _customSchedules.append(instance.get_schedule_details())
157                 except RuntimeError, message:
158                     raise RuntimeError, "Error getting schedule details " + \
159                                         "for custom auto-snapshot SMF " + \
160                                         "instance:\n\t" + label + "\n" + \
161                                         "Details:\n" + str(message) 
162     return _customSchedules
163
164
165 if __name__ == "__main__":
166     defaults = get_default_schedules()
167     for sched in defaults:
168         S = AutoSnap(sched[0])
169         print S.get_schedule_details()
170