source: n4d-nfs/trunk/fuentes/install/usr/share/n4d/python-plugins/NfsManager.py @ 2264

Last change on this file since 2264 was 2264, checked in by Juanma, 3 years ago

Added nfs backup/restore

File size: 8.0 KB
Line 
1import subprocess
2import re
3import os
4import tempfile
5from jinja2 import Environment
6from jinja2.loaders import FileSystemLoader
7from jinja2 import Template
8
9
10class NfsManager:
11       
12        def __init__(self):
13               
14                self.nfs_dir="/etc/exports.d/"
15                self.nfs_file=self.nfs_dir+"net.exports"
16                self.default_options="rw,sync,no_subtree_check"
17                self.regex_pattern="^(/[\-/\w]+)(\s+)((((\d{1,3}\.){3}\d{1,3})|\w+)\((.*)\)(\s+|$))+"
18                self.file_header="#\n# File generated by NfsManager plugin. Do not edit\n#\n\n"
19               
20                self.default_mount_options="rw,hard,intr,nosuid"
21                self.tpl_env = Environment(loader=FileSystemLoader('/usr/share/n4d/templates/nfs'))
22               
23                self.backup_files=[r'/lib/systemd/system/net-server\x2dsync.mount']
24                self.backup_dirs=["/etc/exports.d/"]
25
26                # LLX TESTING
27                #self.nfs_file="/tmp/exports"
28                #
29               
30                if not os.path.exists(self.nfs_dir):
31                        os.makedirs(self.nfs_dir)
32               
33               
34        #def __init__
35               
36               
37        def parse_exports_file(self,f=None):
38               
39                if f==None:
40                        f=self.nfs_file
41
42                if not os.path.isfile(f):
43                        return {}
44               
45                f=open(f)
46                lines=f.readlines()
47                f.close()
48               
49                exports={}
50               
51                for line in lines:
52                        ret=re.match(self.regex_pattern,line)
53                        if ret:
54                                d,ip_list=ret.group(1),ret.group(3)
55                               
56                                for info in ip_list.split(" "):
57                                        info=info.strip("\n")
58                                        info=info.split("(")
59                                        p=info[0]
60                                        options=info[1].strip(")")
61                                       
62                                        if d not in exports:
63                                                exports[d]={}
64                                       
65                                        exports[d][ip]=options
66                return exports
67
68       
69        #def parse_exports_file
70       
71
72        def export_directories(self):
73               
74                #ret=os.system("exportfs -ra")
75                p=subprocess.Popen(["exportfs","-ra"],stdout=subprocess.PIPE,stderr=subprocess.PIPE)
76                ret=p.communicate()
77               
78                if p.poll()==0:
79               
80                        return {"status":True , "msg": "NFS shares exported"}
81                       
82                else:
83                       
84                        return {"status":False, "msg":ret[1]}
85               
86        #def export_directories
87
88       
89        def add_share(self,d,ip,options=None):
90               
91                if options==None:
92                        options=self.default_options
93                       
94                exports=self.parse_exports_file()
95       
96                if d not in exports:
97                        exports[d]={}
98                exports[d][ip]=options
99                return self.write_exports_file(exports)
100               
101        #def add_share
102       
103       
104        def remove_ip_from_share(self,share,ip):
105               
106                exports=self.parse_exports_file()
107               
108                if share in exports:
109                        if ip in exports[share]:
110                                exports[share].pop(ip)
111                               
112                                self.write_exports_file(exports)
113                               
114                                return {"status":True,"msg":"Removed IP from server"}
115                       
116                        else:
117                                return {"status":False,"msg":"IP not found"}
118                               
119                else:
120                        return {"status":True,"msg":"Share dir. not found"}
121                       
122               
123        #def remove_ip_from_share
124       
125       
126       
127        def write_exports_file(self,exports,f=None):
128               
129                if f==None:
130                        f=self.nfs_file
131                       
132                file_lines=[]
133                file_lines.append(self.file_header)
134                       
135                for d in exports:
136                        line="%s\t\t%s\n"
137                        ip_list=""
138                        for ip in exports[d]:
139                                ip_list+="%s(%s) "%(ip,exports[d][ip])
140                        ip_list=ip_list.rstrip(" ")
141                        file_lines.append(line%(d,ip_list))
142                       
143                file_lines.append("\n")
144               
145                f=open(f,"w")
146                for line in file_lines:
147                        f.write(line)
148                f.close()
149                self.export_directories()
150                return {"status":True,"msg":"NFS exports.d file written"}
151                       
152        #def write_exports_file
153       
154       
155        def configure_mount_on_boot(self,source,target,options=None):
156               
157                if options==None:
158                        options=self.default_mount_options
159                       
160               
161                template_cname = self.tpl_env.get_template("mount.skel")
162                list_variables = {}
163                list_variables["SRC"]=source
164                list_variables["DEST"]=target
165                list_variables["OPTIONS"]=options
166               
167                string_template = template_cname.render(list_variables).encode('UTF-8')
168               
169                fd, tmpfilepath = tempfile.mkstemp()
170                new_export_file = open(tmpfilepath,'w')
171                new_export_file.write(string_template)
172                new_export_file.close()
173                os.close(fd)
174               
175                p=subprocess.Popen(["systemd-escape",target.lstrip("/")],stdout=subprocess.PIPE)
176                file_name=p.communicate()[0].strip("\n")+".mount"
177                file_dest="/lib/systemd/system/"+file_name
178                print tmpfilepath
179                print target.lstrip("/")
180                print file_dest
181               
182                n4d_mv(tmpfilepath,file_dest,True,'root','root','0644',False )
183               
184                os.system("systemctl daemon-reload")
185                o=subprocess.Popen(["systemctl","enable",file_name],stdout=subprocess.PIPE,stderr=subprocess.PIPE).communicate()
186                o2=subprocess.Popen(["systemctl","start",file_name],stdout=subprocess.PIPE,stderr=subprocess.PIPE).communicate()
187               
188                ret=(o,o2)
189               
190                return {"status":True,"msg":ret}
191               
192        #def configure_mount_on_boot
193       
194        def remove_mount_on_boot(self,target):
195               
196                p=subprocess.Popen(["systemd-escape",target.lstrip("/")],stdout=subprocess.PIPE)
197                file_name=p.communicate()[0].strip("\n")+".mount"
198                file_dest="/lib/systemd/system/"+file_name
199               
200                ret=""
201               
202                if os.path.exists(file_dest):
203                        o2=subprocess.Popen(["systemctl","stop",file_name],stdout=subprocess.PIPE,stderr=subprocess.PIPE).communicate()
204                        o=subprocess.Popen(["systemctl","disable",file_name],stdout=subprocess.PIPE,stderr=subprocess.PIPE).communicate()
205                        os.remove(file_dest)
206                        ret=(o,o2)
207                       
208                return {"status":True,"msg":ret}
209               
210        #def remove_mount_on_boot
211       
212        def clean_exports_file(self):
213               
214                if os.path.exists(self.nfs_file):
215                        os.remove(self.nfs_file)
216                        self.export_directories()
217               
218                return {"status":True,"msg":"NfsManager exports.d file is now clean"}
219
220        def makedir(self,dir_path=None):
221
222                if not os.path.isdir(dir_path):
223                        os.makedirs(dir_path)
224
225                return [True]
226               
227        def backup(self,dir_path="/backup"):
228                try:
229                        self.makedir(dir_path)
230
231                        #get_backup_name es una funcion que esta definida en n4d
232                        file_path=dir_path+"/"+get_backup_name("NfsManager")
233
234                        tar=tarfile.open(file_path,"w:gz")
235                        for f in self.backup_files:
236                                if os.path.exists(f):
237                                        tar.add(f)
238                        for d in self.backup_dirs:
239                             if os.path.exists(d):
240                                for f in os.listdir(d):
241                                        tar.add(d+f)
242
243                        tar.close()
244                        print "Backup generated in %s" % file_path
245                        return [True,file_path]
246
247
248                except Exception as e:
249                                print "Backup failed", e
250                                return [False,str(e)]
251
252        #def backup
253
254
255        def restore(self,file_path=None):
256
257                #Ordeno de manera alfabetica el directorio y busco el fichero que tiene mi cadena
258                if file_path==None:
259                        dir_path="/backup"
260                        for f in sorted(os.listdir(dir_path),reverse=True):
261
262                                if "NfsManager" in f:
263                                        file_path=dir_path+"/"+f
264                                        break
265
266                #Descomprimo el fichero y solo las cadenas que espero encontrar son las que restauro, reiniciando el servicio
267
268
269                try:
270                        if os.path.exists(file_path):
271
272                                tmp_dir=tempfile.mkdtemp()
273                                tar=tarfile.open(file_path)
274                                tar.extractall(tmp_dir)
275                                tar.close
276
277                                for f in self.backup_files:
278                                                tmp_path=tmp_dir+f
279                                                if os.path.exists(tmp_path):
280                                                        shutil.copy(tmp_path,f)
281
282
283                                for d in self.backup_dirs:
284                                        tmp_path=tmp_dir+d     
285                                        if os.path.exists(tmp_path):
286                                                cmd="cp -r " + tmp_path + "/* " + d
287                                                if not os.path.exists(d):
288                                                        os.makedirs(d)
289                                                os.system(cmd)
290
291
292                        print "File is restored in %s" % self.backup_files
293
294                        return [True,""]
295
296
297                except Exception as e:
298
299                        print "Restored failed", e
300                        return [False,str(e)]
301
302                pass
303
304        #def restore
305
306       
307       
308#class NfsManager
309
310if __name__=="__main__":
311       
312        nfsman=NfsManager()
313       
314        #nfsman.add_share("/net","172.20.8.5")
315        nfsman.parse_exports_file()
316        nfsman.remove_ip_from_share("/net","1.2.3.4")
317        nfsman.add_share("/pepito","2.3.4.4","one,two,three")
318        nfsman.configure_mount_on_boot("server:/net","/net/server-sync")
319
Note: See TracBrowser for help on using the repository browser.