diff --git a/src/imagemgr.py b/src/imagemgr.py index 9f44f21..52700d8 100755 --- a/src/imagemgr.py +++ b/src/imagemgr.py @@ -10,7 +10,7 @@ design: out of time. 4. We can show every user their own images and the images are shared by other. User can new a cluster or scale out a new node by them. And user can remove his own images. - 5. When a remove option occur, the image server will delete it. But some physical host may + 5. When a remove option occur, the image server will delete it. But some physical host may also maintain it. I think it doesn't matter. 6. The manage of lvm has been including in this module. """ @@ -20,6 +20,7 @@ from configparser import ConfigParser from io import StringIO import os,sys,subprocess,time,re,datetime,threading,random import xmlrpc.client +from model import db, Image from log import logger import env @@ -30,37 +31,43 @@ class ImageMgr(): #def sys_call(self,command): # output = subprocess.getoutput(command).strip() # return None if output == '' else output - + def sys_return(self,command): return_value = subprocess.call(command,shell=True) return return_value - + def __init__(self): - self.NFS_PREFIX = env.getenv('FS_PREFIX') + self.NFS_PREFIX = env.getenv('FS_PREFIX') self.imgpath = self.NFS_PREFIX + "/global/images/" - self.srcpath = env.getenv('DOCKLET_LIB') + "/" + self.srcpath = env.getenv('DOCKLET_LIB') + "/" self.imageserver = "192.168.6.249" - + def datetime_toString(self,dt): return dt.strftime("%Y-%m-%d %H:%M:%S") def string_toDatetime(self,string): return datetime.datetime.strptime(string, "%Y-%m-%d %H:%M:%S") - - def updateinfo(self,imgpath,image,description): - image_info_file = open(imgpath+"."+image+".info",'w') + + def updateinfo(self,user,image,description): + '''image_info_file = open(imgpath+"."+image+".info",'w') image_info_file.writelines([self.datetime_toString(datetime.datetime.now()) + "\n", "unshare"]) image_info_file.close() image_description_file = open(imgpath+"."+image+".description", 'w') image_description_file.write(description) - image_description_file.close() + image_description_file.close()''' + image = Image.query.filter_by(ownername=user,imagename=image).first() + if image is None: + image = Image(image,False,user,description) + db.session.add(image) + db.session.commit() + def dealpath(self,fspath): if fspath[-1:] == "/": return self.dealpath(fspath[:-1]) else: return fspath - + def createImage(self,user,image,lxc,description="Not thing", imagenum=10): fspath = self.NFS_PREFIX + "/local/volume/" + lxc imgpath = self.imgpath + "private/" + user + "/" @@ -80,14 +87,14 @@ class ImageMgr(): sys_run("tar -cvf %s -C %s ." % (imgpath+image+".tz",self.dealpath(fspath)), True) except Exception as e: logger.error(e) - #try: + #try: #sys_run("cp %s %s" % (tmppath+tmpimage, imgpath+image+".tz"), True) #sys_run("rsync -a --delete --exclude=lost+found/ --exclude=root/nfs/ --exclude=dev/ --exclude=mnt/ --exclude=tmp/ --exclude=media/ --exclude=proc/ --exclude=sys/ %s/ %s/" % (self.dealpath(fspath),imgpath+image),True) #except Exception as e: # logger.error(e) - #sys_run("rm -f %s" % tmppath+tmpimage, True) + #sys_run("rm -f %s" % tmppath+tmpimage, True) #sys_run("rm -f %s" % (imgpath+"."+image+"_docklet_share"),True) - self.updateinfo(imgpath,image,description) + self.updateinfo(user,image,description) logger.info("image:%s from LXC:%s create success" % (image,lxc)) return [True, "create image success"] @@ -116,8 +123,8 @@ class ImageMgr(): #self.sys_call("rsync -a --delete --exclude=nfs/ %s/ %s/" % (imgpath+image,self.dealpath(fspath))) #self.updatetime(imgpath,image) - return - + return + def prepareFS(self,user,image,lxc,size="1000",vgname="docklet-group"): rootfs = "/var/lib/lxc/%s/rootfs" % lxc layer = self.NFS_PREFIX + "/local/volume/" + lxc @@ -130,14 +137,14 @@ class ImageMgr(): if Ret.returncode == 0: logger.info("%s not clean" % layer) sys_run("umount -l %s" % layer) - + try: sys_run("rm -rf %s %s" % (rootfs, layer)) sys_run("mkdir -p %s %s" % (rootfs, layer)) except Exception as e: logger.error(e) - + #prepare volume if check_volume(vgname,lxc): logger.info("volume %s already exists, delete it") @@ -145,7 +152,7 @@ class ImageMgr(): if not new_volume(vgname,lxc,size): logger.error("volume %s create failed" % lxc) return False - + try: sys_run("mkfs.ext4 /dev/%s/%s" % (vgname,lxc),True) sys_run("mount /dev/%s/%s %s" %(vgname,lxc,layer),True) @@ -184,7 +191,7 @@ class ImageMgr(): logger.error(e) return True - + def detachFS(self, lxc, vgname="docklet-group"): rootfs = "/var/lib/lxc/%s/rootfs" % lxc Ret = sys_run("umount %s" % rootfs) @@ -192,7 +199,7 @@ class ImageMgr(): logger.error("cannot umount rootfs:%s" % rootfs) return False return True - + def checkFS(self, lxc, vgname="docklet-group"): rootfs = "/var/lib/lxc/%s/rootfs" % lxc layer = self.NFS_PREFIX + "/local/volume/" + lxc @@ -211,49 +218,58 @@ class ImageMgr(): def removeImage(self,user,image): imgpath = self.imgpath + "private/" + user + "/" try: + image = Image.query.filter_by(imagename=image,ownername=user).first() + db.session.delete(image) + db.session.commit() sys_run("rm -rf %s/" % imgpath+image+".tz", True) - sys_run("rm -f %s" % imgpath+"."+image+".info", True) - sys_run("rm -f %s" % (imgpath+"."+image+".description"), True) + #sys_run("rm -f %s" % imgpath+"."+image+".info", True) + #sys_run("rm -f %s" % (imgpath+"."+image+".description"), True) except Exception as e: logger.error(e) def shareImage(self,user,image): imgpath = self.imgpath + "private/" + user + "/" share_imgpath = self.imgpath + "public/" + user + "/" - image_info_file = open(imgpath+"."+image+".info", 'r') + '''image_info_file = open(imgpath+"."+image+".info", 'r') [createtime, isshare] = image_info_file.readlines() isshare = "shared" image_info_file.close() image_info_file = open(imgpath+"."+image+".info", 'w') image_info_file.writelines([createtime, isshare]) - image_info_file.close() - sys_run("mkdir -p %s" % share_imgpath, True) + image_info_file.close()''' try: + image = Image.query.filter_by(imagename=image,ownername=user).first() + image.isshared = True + db.session.commit() + sys_run("mkdir -p %s" % share_imgpath, True) sys_run("cp %s %s" % (imgpath+image+".tz", share_imgpath+image+".tz"), True) #sys_run("rsync -a --delete %s/ %s/" % (imgpath+image,share_imgpath+image), True) except Exception as e: logger.error(e) - sys_run("cp %s %s" % (imgpath+"."+image+".info",share_imgpath+"."+image+".info"), True) - sys_run("cp %s %s" % (imgpath+"."+image+".description",share_imgpath+"."+image+".description"), True) + #$sys_run("cp %s %s" % (imgpath+"."+image+".info",share_imgpath+"."+image+".info"), True) + #sys_run("cp %s %s" % (imgpath+"."+image+".description",share_imgpath+"."+image+".description"), True) + - def unshareImage(self,user,image): public_imgpath = self.imgpath + "public/" + user + "/" imgpath = self.imgpath + "private/" + user + "/" - if os.path.isfile(imgpath + image + ".tz"): + '''if os.path.isfile(imgpath + image + ".tz"): image_info_file = open(imgpath+"."+image+".info", 'r') [createtime, isshare] = image_info_file.readlines() isshare = "unshare" image_info_file.close() - image_info_file = open(imgpath+"."+image+".info", 'w') + image_info_file = open(imgpath+"."+image+".info", 'w') image_info_file.writelines([createtime, isshare]) - image_info_file.close() + image_info_file.close()''' try: #sys_run("rm -rf %s/" % public_imgpath+image, True) + image = Image.query.filter_by(imagename=image,ownername=user).first() + image.isshared = False + db.session.commit() sys_run("rm -f %s" % public_imgpath+image+".tz", True) - sys_run("rm -f %s" % public_imgpath+"."+image+".info", True) - sys_run("rm -f %s" % public_imgpath+"."+image+".description", True) + #sys_run("rm -f %s" % public_imgpath+"."+image+".info", True) + #sys_run("rm -f %s" % public_imgpath+"."+image+".description", True) except Exception as e: logger.error(e) @@ -272,7 +288,7 @@ class ImageMgr(): logger.error(e) sys_run("rm -rf %s" % tmppath+tmpimage) return True - + def update_base_image(self, user, vclustermgr, image): if not user == "root": logger.info("only root can update base image") @@ -291,7 +307,7 @@ class ImageMgr(): return [True, "update base image"] def get_image_info(self, user, image, imagetype): - if imagetype == "private": + '''if imagetype == "private": imgpath = self.imgpath + "private/" + user + "/" else: imgpath = self.imgpath + "public/" + user + "/" @@ -300,20 +316,28 @@ class ImageMgr(): image_info_file.close() image_description_file = open(imgpath+"."+image+".description",'r') description = image_description_file.read() - image_description_file.close() + image_description_file.close()''' + image = Image.query.filter_by(imagename=image,ownername=user).first() + if image is None: + return ["", ""] + time = image.create_time.strftime("%Y-%m-%d %H:%M:%S") + description = image.description if len(description) > 15: description = description[:15] + "......" return [time, description] def get_image_description(self, user, image): - if image['type'] == "private": + '''if image['type'] == "private": imgpath = self.imgpath + "private/" + user + "/" else: imgpath = self.imgpath + "public/" + image['owner'] + "/" image_description_file = open(imgpath+"."+image['name']+".description", 'r') description = image_description_file.read() - image_description_file.close() - return description + image_description_file.close()''' + image = Image.query.filter_by(imagename=image,ownername=user).first() + if image is None: + return "" + return image.description def list_images(self,user): images = {} @@ -363,13 +387,16 @@ class ImageMgr(): logger.error(e) return images - + def isshared(self,user,image): - imgpath = self.imgpath + "private/" + user + "/" + '''imgpath = self.imgpath + "private/" + user + "/" image_info_file = open(imgpath+"."+image+".info",'r') [time, isshare] = image_info_file.readlines() - image_info_file.close() - if isshare == "shared": + image_info_file.close()''' + image = Image.query.filter_by(imagename=image,ownername=user).first() + if image is None: + return "" + if image.isshared == True: return "true" else: return "false" diff --git a/src/model.py b/src/model.py index 9d3a0fc..f0a18d6 100755 --- a/src/model.py +++ b/src/model.py @@ -365,7 +365,18 @@ class VCluster(db.Model): class Image(db.Model): __bind_key__ = 'system' imagename = db.Column(db.String(50)) - id = db.Column(db.BigInteger, primary_key=True) + id = db.Column(db.Integer, primary_key=True) isshared = db.Column(db.Boolean) ownername = db.Column(db.String(20)) + create_time = db.Colum(db.DateTime) description = db.Column(db.Text) + + def __init__(self,imagename,isshared,ownername,description): + self.imagename = imagename + self.isshared = isshared + self.ownername = ownername + self.description = description + self.create_time = datetime.now() + + def __repr__(self): + return "{\"id\":\"%d\",\"imagename\":\"%s\",\"isshared\":\"%s\",\"ownername\":\"%s\",\"updatetime\":\"%s\",\"description\":\"%s\"}" % (self.id,self.imagename,str(self.isshared),self.create_time.strftime("%Y-%m-%d %H:%M:%S"),self.ownername,self.description) diff --git a/src/vclustermgr.py b/src/vclustermgr.py index b488592..c2c42fb 100755 --- a/src/vclustermgr.py +++ b/src/vclustermgr.py @@ -424,27 +424,24 @@ class VclusterMgr(object): return [True, "image not exists"] def create_image(self,username,clustername,containername,imagename,description,imagenum=10): - [status, info] = self.get_clusterinfo(clustername,username) + [status, vcluster] = self.get_vcluster(clustername,username) if not status: return [False, "cluster not found"] - containers = info['containers'] + containers = vcluster.containers for container in containers: - if container['containername'] == containername: + if container.containername == containername: logger.info("container: %s found" % containername) - worker = xmlrpc.client.ServerProxy("http://%s:%s" % (container['host'], env.getenv("WORKER_PORT"))) + worker = xmlrpc.client.ServerProxy("http://%s:%s" % (containe.host, env.getenv("WORKER_PORT"))) if worker is None: return [False, "The worker can't be found or has been stopped."] res = worker.create_image(username,imagename,containername,description,imagenum) - container['lastsave'] = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S") - container['image'] = imagename + container.lastsave = datetime.datetime.now() + container.image = imagename break else: res = [False, "container not found"] logger.error("container: %s not found" % containername) - clusterpath = self.fspath + "/global/users/" + username + "/clusters/" + clustername - infofile = open(clusterpath, 'w') - infofile.write(json.dumps(info)) - infofile.close() + db.session.commit() return res def delete_cluster(self, clustername, username, user_info):