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

Last change on this file since 6094 was 6094, checked in by hectorgh, 2 years ago

adding add_mirror functionality

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