예제 #1
0
class AdminRestService(object):

    writeMethodsExposed = True

    ## Constructor call: instantiate IRservice, retrieve logger
    def __init__(self):
        super(AdminRestService, self).__init__()
        self.service = IRService()
        self.msg = ""
        self._log = self.service.getLog()
        self.provider = "ldappass"

    ## Returning the html output from a Rest call
    def results(self) :
        # adds the ending html tags and possible footer here                                      
        self.msg += "<br> <br> <a href = \"index\"> Return to the main page </a> "
        self.msg += "</body> </html>"
        return self.msg
    results.exposed = True

    ## Adding to the HTML output from a REST call
    def setMessage(self, message) :
        if self.msg == None :
            self.msg = "<html> <body> %s " % message
        else :
            self.msg += message
        return

    ## HTML Listing of all the REST functions 
    def index(self) :
        self.msg = ""
        message = "<b> User Commands </b><br> "
        message += "<a href=\"help\"> Get help information </a> <br>"
        message += "<a href=\"list\"> Get list of images that meet the criteria </a> <br>"
        message += "<a href=\"setPermission\">  Set access permission </a> <br>"
        message += "<a href=\"get\"> Retrieve image </a> <br>"
        message += "<a href=\"put\"> Upload/register an image </a> <br>"
        message += "<a href=\"modify\"> Modify an image </a> <br>"
        message += "<a href=\"remove\">  Remove an image from the repository </a> <br>"
        message += "<a href=\"histimg\"> Usage info of an image </a> <br>"
        message += " <br>"
        message += "<b>Commands only for Admins</b> <br>"
        message += "<a href=\"histuser\">  Usage info of a user </a> <br>"
        message += "<a href=\"useradd\"> Add user </a> <br>"
        message += "<a href=\"userdel\"> Remove user </a> <br>"
        message += "<a href=\"userlist\"> List of users </a> <br>"
        message += "<a href=\"setquota\"> Modify user quota </a> <br>"
        message += "<a href=\"setrole\"> Modify user role </a> <br>"
        message += "<a href=\"setuserstatus\"> Modify user status </a> <br>"
        self.setMessage(message)
        raise cherrypy.HTTPRedirect("results")
    index.exposed = True;

    ## Document to the user, what are the REST services and what they do.
    def help (self) :
        self.msg = ""
        message = "\n------------------------------------------------------------------<br>"
        message += "FutureGrid Image Repository Help <br>"
        message += "------------------------------------------------------------------<br>"
        message += '''        
        <b>help:</b> get help information<br>
        <b>auth:</b> login/authentication<br>
        <b>list</b> [queryString]: get list of images that meet the criteria<br>
        <b>setPermission</b> &lt;imgId> <permissionString>: set access permission<br>
        <b>get</b> &lt;imgId&gt: get an image<br>
        <b>put</b> &lt;imgFile&gt [attributeString]: upload/register an image<br>
        <b>modify</b> &lt;imgId&gt &lt;attributeString&gt: update Metadata   <br>
        <b>remove</b> &lt;imgId&gt: remove an image        <br>
        <b>histimg</b> [imgId]: get usage info of an image<br>
        <br>
        <b>Commands only for Admins</b> <br>
        <b>useradd</b> &lt;userId&gt: add user <br>
        <b>userdel</b> &lt;userId&gt: remove user<br>
        <b>userlist</b>: list of users<br>
        <b>setuserquota</b> &lt;userId&gt &lt;quota>: modify user quota<br>
        <b>setuserrole</b>  &lt;userId&gt &lt;role>: modify user role<br>
        <b>setuserstatus</b> &lt;userId&gt &lt;status>: modify user status<br>        
        <b>histuser</b> &lt;userId&gt: get usage info of a user<br>
              <br>
              <br>
    Notes:<br>
        <br>
        <b>attributeString</b> example (you do not need to provide all of them): <br>
            vmtype=xen & imgtype=opennebula & os=linux & arch=x86_64 & <br>
            description=my image & tag=tag1,tag2 & permission=public & <br>
            imgStatus=available.<br>
        <br>
        <b>queryString</b>: * or * where field=XX, field2=YY or <br>
             field1,field2 where field3=XX<br>
        <br>
        Some argument's values are controlled:<br>'''


        first = True
        for line in textwrap.wrap("<b>vmtype</b>= " + str(ImgMeta.VmType), 100):
            if first:
                message += "         %s<br>" % (line)
                first = False
            else:
                message += "           %s<br>" % (line)
        first = True
        for line in textwrap.wrap("<b>imgtype</b>= " + str(ImgMeta.ImgType), 100):
            if first:
                message += "         %s<br>" % (line)
                first = False
            else:
                message += "               %s<br>" % (line)
        first = True
        for line in textwrap.wrap("<b>imgStatus</b>= " + str(ImgMeta.ImgStatus), 100):
            if first:
                message += "         %s<br>" % (line)
                first = False
            else:
                message += "           %s<br>" % (line)
        first = True
        for line in textwrap.wrap("<b>Permission</b>= " + str(ImgMeta.Permission), 100):
            if first:
                message += "         %s<br>" % (line)
                first = False
            else:
                message += "           %s<br>" % (line)
        for line in textwrap.wrap("<b>User Role</b>= " + str(IRUser.Role), 100):
            if first:
                message += "         %s<br>" % (line)
                first = False
            else:
                message += "           %s<br>" % (line)
        for line in textwrap.wrap("<b>User Status</b>= " + str(IRUser.Status), 100):
            if first:
                message += "         %s<br>" % (line)
                first = False
            else:
                message += "           %s<br>" % (line)
        self.setMessage(message)
        raise cherrypy.HTTPRedirect("results")
    help.exposed = True;

    ## Callback function to the list service
    # @param userId user id to represent list
    # @param userCred user password in MD5 digested format
    # @param queryString (not required) string to help narrow down the query 
    def actionList (self, userId, userCred, queryString):
        self.msg = ""
        userId = userId.strip()
        #userCred = IRCredential("ldappass", userCred)
        if (len(userId) > 0):
            authstatus=self.service.auth(userId, userCred, self.provider)
            if authstatus == True:
                if (len(queryString) == 0):
                    imgsList = self.service.query(userId.strip(), "*")
                else:
                    imgsList = self.service.query(userId.strip(), queryString.strip())
    
                if( imgsList == None):
                    self.msg = "No list of images returned"
                else:                                    
                    try:                    
                        imgs = imgsList            
                        for key in imgs.keys():                                
                            self.msg = self.msg + str(imgs[key]) + "<br>"
                    except:
                        self.msg = "Server replied: " + str(imgsList) + "<br>"
                        self.msg = "list: Error:" + str(sys.exc_info()) + "</br>"
                        self._log.error("list: Error interpreting the list of images from Image Repository" + str(sys.exc_info())+ "<br>")
            elif authstatus == False:
                self.msg = "ERROR: Wrong password"
            elif authstatus == "NoUser":
                self.msg = "ERROR: User "+ userId + " does not exist"
            elif authstatus == "NoActive":
                self.msg = "ERROR: The status of the user "+ userId + " is not active"
            else: #this should not be used
                self.msg = authstatus
                    
        else:
            self.msg = "Please specify valid userId"
            
        raise cherrypy.HTTPRedirect("results")
    actionList.exposed = True

    ## list service
    def list (self) :
        self.msg = """ <form method=get action=actionList> 
        Username: <input type=string name=userId><br>
        Password: <input type=password name=userCred><br>
        Query string: <input type=string name=queryString> <br> 
        <input type=submit> </form> """
        return self.msg;
    list.exposed = True

    ## Callback function to the set permission service
    # @param userId login/account name of the Rest user to invoke this service
    # @param imgId id of the uploaded Rest image for the specified user.
    # @param userCred user password in MD5 digested format
    # @permissionString permission string
    def actionSetPermission (self, userId, userCred, imgId, permissionString) :
        self.msg = ""
        userId = userId.strip()
        imgId = imgId.strip()
        permstring = permissionString.strip()
        #userCred = IRCredential("ldappass", userCred)
        if (len(userId) > 0 and len(imgId) > 0):           
            print permissionString
            print  permissionString in ImgMeta.Permission
            if(permissionString in ImgMeta.Permission):
                authstatus=self.service.auth(userId, userCred, self.provider)
                if authstatus == True:
                    permstring = "permission=" + permissionString
                    status = self.service.updateItem(userId, imgId, permstring)
                    if(status == True):
                        self.msg = "Permission of image " + imgId + " updated"
                    else:
                        self.msg = "The permission of image " + imgId + " has not been changed."
                elif authstatus == False:
                    self.msg = "ERROR: Wrong password"
                elif authstatus == "NoUser":
                    self.msg = "ERROR: User "+ userId + " does not exist"
                elif authstatus == "NoActive":
                    self.msg = "ERROR: The status of the user "+ userId + " is not active"
                else: #this should not be used
                    self.msg = authstatus
            else:
                self.msg = "Error: Not valid permission string. Available options: " + str(ImgMeta.Permission)
        else:
            self.msg = "Please verify the input information, you need to include userId/password, imageId and permission string"
    
        raise cherrypy.HTTPRedirect("results")
    actionSetPermission.exposed = True;

    ## Set permission service
    def setPermission (self):
        message = """ <form method=get action=actionSetPermission>
        UserId: <input type=string name=userId> <br>
        Password: <input type=password name=userCred> <br>
        Image Id: <input type=string name=imgId> <br>                                                                                 
        Permission string: <input type=string name=permissionString> <br>                                                              
        <input type=submit> </form> """
        return message
    setPermission.exposed = True;

    ## Callback function to the get service. 
    # @param userId login/account name of the Rest user to invoke this service
    # @param userCred user password in MD5 digested format
    # @param imgId id of the uploaded Rest image for a specified user.
    def actionGet(self, userId, userCred, imgId):
        self.msg = ""

        option = "img"
        imgId = imgId.strip()
        userId = userId.strip()
        #userCred = IRCredential("ldappass", userCred)
        if (len(userId) > 0 and len(imgId) > 0):              
            authstatus=self.service.auth(userId, userCred, self.provider)
            if authstatus == True:  
                filepath = self.service.get(userId, option, imgId)
                if (filepath != None):
                    #if (len(imgId) > 0) :
                    self.msg = "Downloading img to %s " % filepath.__str__()
                    return serve_file(filepath, "application/x-download", "attachment")
                    #else :
                    #    self.msg = "URL:  %s " % filepath.__str__()
                else:
                    self.msg = "Cannot get access to the image with imgId = " + imgId                    
            elif authstatus == False:
                self.msg = "ERROR: Wrong password"
            elif authstatus == "NoUser":
                self.msg = "ERROR: User "+ userId + " does not exist"
            elif authstatus == "NoActive":
                self.msg = "ERROR: The status of the user "+ userId + " is not active"
            else: #this should not be used
                self.msg = authstatus
        else :
            self.msg="Please verify the input information, you need to include userId/password and imageId"            
        
        raise cherrypy.HTTPRedirect("results")

        
        #raise cherrypy.HTTPRedirect("results")

    actionGet.exposed = True

    ## get Rest service. Retrieves image
    def get (self):
        return """<html><body><form method=get action=actionGet>
         Username: <input type=string name=userId><br>
         Password: <input type=password name=userCred><br>
         Image Id: <input type=string name=imgId> <br>          
         <input type=submit> </form> </body></html>
       """
       #Option ('img' or 'uri'): <input type=string name=option> <br>
    get.exposed = True;

    ## Callback function to the put service
    # @param userId login/account name of the Rest user to invoke this service
    # @param userCred user password in MD5 digested format
    # @param imageFileName request based object file representing the user file name
    # @param attributeString attribute string
    def actionPut (self, userId, userCred, imageFileName, attributeString):
        # retrieve the data                                                                                                                       
        size = 0
        self.fromSite = "actionPut"
        self.msg = ""
        userId = userId.strip()
        attributeString = attributeString.strip()
        #userCred = IRCredential("ldappass", userCred)
        if (len(userId) > 0 and imageFileName.file != None):
            authstatus=self.service.auth(userId, userCred, self.provider)
            if authstatus == True:                
                #check metadata
                
                correct = self.checkMeta(attributeString)
                if correct:
                    while 1:
                        data = imageFileName.file.read(1024 * 8) # Read blocks of 8KB at a time                                                               
                        size += len(data)
                        if not data: break
                    #check quota
                    isPermitted = self.service.uploadValidator(userId.strip(), size)
                    
                    if (isPermitted == True):
                        imgId = self.service.genImgId() #this is needed when we are not using mongodb as image storage backend
                        if imgId != None:
                            extension = os.path.splitext(imageFileName.filename)[1]
                            imageId = self.service.put(userId, imgId, imageFileName, attributeString, size, extension)
        
                            self.msg = "Image %s successfully uploaded." % imageFileName.filename
                            self.msg += " Image size %s " % size
                            self.msg += " Image extension is %s " % extension
                            self.msg += "<br> The image ID is %s " % imageId
                        else:
                            self.msg += "Error generating the imgId"
                    #This elif is not going to be used.Leave it for now. Just in case we change the new auth method (2/10/2012).
                    elif (isPermitted.strip() == "NoUser"):  
                        self.msg = "the image has NOT been uploaded<br>"
                        self.msg = "The User does not exist"
                    #This elif is not going to be used.Leave it for now. Just in case we change the new auth method (2/10/2012).
                    elif (isPermitted.strip() == "NoActive"):
                        self.msg = "The image has NOT been uploaded<br>"
                        self.msg = "The User is not active"
                    else:
                        self.msg = "The image has NOT been uploaded<br>"
                        self.msg = "The file exceed the quota"
                else:
                    self.msg += "The image has NOT been uploaded. Please, verify that the metadata string is valid. You can also leave the "
            elif authstatus == False:
                self.msg = "The image has NOT been uploaded<br>"
                self.msg += "ERROR: Wrong password"
            elif authstatus == "NoUser":
                self.msg = "The image has NOT been uploaded <br>"
                self.msg += "ERROR: User "+ userId + " does not exist"
            elif authstatus == "NoActive":
                self.msg = "The image has NOT been uploaded<br>"
                self.msg += "ERROR: The status of the user "+ userId + " is not active"
            else: #this should not be used
                self.msg = authstatus
        else:
            self.msg="Please verify the input information, you need to include userId/password and select and image"
                
        raise cherrypy.HTTPRedirect("results")
    actionPut.exposed = True

    ## put Rest service. Download an image to the Rest service.
    def put (self) :
        return """<html><body><form method=post action=actionPut enctype="multipart/form-data">
       Upload a file: <input type=file name=imageFileName><br>
       Username: <input type=string name=userId><br>
       Password: <input type=password name=userCred><br>
       attributeString: <input type=string name=attributeString> <br>
       <input type=submit></form></body></html>      
        """
    put.exposed = True;


    ############################################################
    # checkMeta
    ############################################################
    def checkMeta(self, attributeString):
        attributes = attributeString.split("&")
        correct = True
        for item in attributes:
            attribute = item.strip()
            #print attribute
            tmp = attribute.split("=")
            if (len(tmp) == 2):
                key = string.lower(tmp[0])
                value = tmp[1]
                if key in ImgMeta.metaArgsIdx.keys():
                    if (key == "vmtype"):
                        value = string.lower(value)
                        if not (value in ImgMeta.VmType):
                            self.msg = "Wrong value for VmType, please use: " + str(ImgMeta.VmType) + "<br>"
                            correct = False
                            break
                    elif (key == "imgtype"):
                        value = string.lower(value)
                        if not (value in ImgMeta.ImgType):
                            self.msg = "Wrong value for ImgType, please use: " + str(ImgMeta.ImgType) + "<br>"
                            correct = False
                            break
                    elif(key == "permission"):
                        value = string.lower(value)
                        if not (value in ImgMeta.Permission):
                            self.msg = "Wrong value for Permission, please use: " + str(ImgMeta.Permission) + "<br>"
                            correct = False
                            break
                    elif (key == "imgstatus"):
                        value = string.lower(value)
                        if not (value in ImgMeta.ImgStatus):
                            self.msg = "Wrong value for ImgStatus, please use: " + str(ImgMeta.ImgStatus) + "<br>"
                            correct = False
                            break

        return correct

    ## Callback function to the modify service. Modifies the imageid based on attribute string
    # @param userId login/account name of the Rest user to invoke this service
    # @param userCred user password in MD5 digested format
    # @param imgId id of the uploaded Rest image for the specified user.
    # @param attributeString
    def actionModify (self, userId, userCred, imgId, attributeString):
        self.msg = ""
        success = False
        print imgId
        userId = userId.strip()
        imgId = imgId.strip()
        attributeString = attributeString.strip()
        #userCred = IRCredential("ldappass", userCred)
        if (len(userId) > 0 and len(imgId) > 0 and len(attributeString) > 0 and self.checkMeta(attributeString)):
            authstatus=self.service.auth(userId, userCred, self.provider)
            if authstatus == True:
                success = self.service.updateItem(userId, imgId, attributeString)            
                if (success):
                    self.msg = "The image %s was successfully updated" % imgId
                else:
                    self.msg += "Error in the update.<br> Please verify that you are the owner or that you introduced the correct arguments"
            elif authstatus == False:
                self.msg = "The image has NOT been modified<br>"
                self.msg += "ERROR: Wrong password"
            elif authstatus == "NoUser":
                self.msg = "The image has NOT been modified <br>"
                self.msg += "ERROR: User "+ userId + " does not exist"
            elif authstatus == "NoActive":
                self.msg = "The image has NOT been modified<br>"
                self.msg += "ERROR: The status of the user "+ userId + " is not active"
            else: #this should not be used
                self.msg = authstatus
        else:
            self.msg += "Please verify the input information, you need to include userId/password, imageId and a valid attributeString"
                
        raise cherrypy.HTTPRedirect("results")
    actionModify.exposed = writeMethodsExposed;

    # modify Rest service
    def modify (self, imgId = None, attributeString = None):
        self.msg = """ <form method=get action=actionModify>
        User Id: <input type=string name=userId> <br>
        Password: <input type=password name=userCred><br>
        Image Id: <input type=string name=imgId> <br>
        Atribute String: <input type=string name=attributeString> <br> 
         <input type=submit> </form> """
        return self.msg;
    modify.exposed = writeMethodsExposed;


    ## Callback function to the remove Rest service
    # @param userId login/account name of the Rest user to invoke this service
    # @param userCred user password in MD5 digested format
    # @param imgId id of the uploaded Rest image for the specified user.
    def actionRemove (self, userId, userCred, imgId):
        userId = userId.strip()
        imgId = imgId.strip()
        #userCred = IRCredential("ldappass", userCred)
        if (len(userId) > 0 and len(imgId) > 0):
            authstatus=self.service.auth(userId, userCred, self.provider)
            if authstatus == True:
                status = self.service.remove(userId, imgId)
                self.msg = ""
                if (status == True):
                    self.msg = "The image with imgId=" + imgId + " has been removed"
                else:
                    self.msg = "The image with imgId=" + imgId + " has NOT been removed.</br>Please verify the imgId and if you are the image owner"
            elif authstatus == False:
                self.msg = "The image has NOT been removed<br>"
                self.msg += "ERROR: Wrong password"
            elif authstatus == "NoUser":
                self.msg = "The image has NOT been removed <br>"
                self.msg += "ERROR: User "+ userId + " does not exist"
            elif authstatus == "NoActive":
                self.msg = "The image has NOT been removed<br>"
                self.msg += "ERROR: The status of the user "+ userId + " is not active"
            else: #this should not be used
                self.msg = authstatus
        else:
            self.msg += "Please verify the input information, you need to include userId/password and imageId"
        raise cherrypy.HTTPRedirect("results")
    actionRemove.exposed = True;

    ## Remove Rest service.
    # Removes image based on specified image id and user id
    def remove (self):
        self.msg = """ <form method=get action=actionRemove>
        User Id: <input type=string name=userId> <br>
        Password: <input type=password name=userCred><br>
        Image Id: <input type=string name=imgId> <br>
        <input type=submit> </form> """
        return self.msg
    remove.exposed = True

    ## Callback function to the histimage service
    # @param userId login/account name of the Rest user to invoke this service
    # @param userCred user password in MD5 digested format
    # @param imgId id of the uploaded Rest image for the specified user.
    def actionHistImage (self, userId, userCred, imgId):
        self.msg = ""
        userId = userId.strip()
        imgId = imgId.strip()
        #userCred = IRCredential("ldappass", userCred)
        imgsList=None
        if (len(userId) > 0):
            authstatus=self.service.auth(userId, userCred, self.provider)
            if authstatus == True:
                if(len(imgId) > 0):                    
                    imgsList = self.service.histImg(userId, imgId)
                else:
                    imgsList = self.service.histImg(userId, "None")                
                if imgsList == None:
                    self.msg =  "ERROR: Not image record found <br>"
                else:               
                    try:
                        imgs = eval(imgsList)            
                        for key in imgs.keys():                                
                            self.msg = self.msg + imgs[key] + "<br>"
                    except:
                        self.msg = "Server replied: " + str(imgsList)
                        self.msg = self.msg + "histimg: Error:" + str(sys.exc_info())+ "<br>" 
                        self._log.error("histimg: Error interpreting the list of images from Image Repository" + str(sys.exc_info()) + "<br>")
            elif authstatus == False:                
                self.msg = "ERROR: Wrong password"
            elif authstatus == "NoUser":                
                self.msg = "ERROR: User "+ userId + " does not exist"
            elif authstatus == "NoActive":
                self.msg = "ERROR: The status of the user "+ userId + " is not active"
            else: #this should not be used
                self.msg = authstatus        
        else:
            self.msg = "Please introduce your userId and password"
        raise cherrypy.HTTPRedirect("results")
    actionHistImage.exposed = True;

    ## histimg Rest service. 
    def histimg (self):
        self.msg = """ <form method=get action=actionHistImage>
        User Id: <input type=string name=userId> <br>
        Password: <input type=password name=userCred><br>
        Image Id: <input type=string name=imgId> <br>
        <input type=submit> </form> """
        return self.msg;
    histimg.exposed = True;


    ## Callback function to the histuser service
    # @param adminId login/account name of the admin user to invoke this service
    # @param adminCred user password in MD5 digested format
    # @param userCred user password in MD5 digested format
    # @param userIdtoSearch user id that is the subject of the search
    def actionHistUser (self, adminId, adminCred, userIdtoSearch):
        self.msg = ""
        adminId = adminId.strip()
        userIdtoSearch = userIdtoSearch.strip()
        #userCred = IRCredential("ldappass", userCred)
        if (len(adminId) > 0 ):
            authstatus=self.service.auth(adminId, adminCred, self.provider)
            if authstatus == True:
                if (len(userIdtoSearch) > 0):
                    userList = self.service.histUser(adminId, userIdtoSearch)
                else:
                    userList = self.service.histUser(adminId, "None")
               
                if userList == None:
                    self.msg =  "ERROR: Not user found <br>"
                else:            
                    try:
                        users = eval(userList)            
                        for key in users.keys():                
                            self.msg = self.msg + users[key] + "<br>"
                    except:
                        self.msg = "Server replied: " + str(userList) + "<br>"                    
                        self.msg = self.msg + "histuser: Error:" + str(sys.exc_info())+ "<br>" 
                        self._log.error("histuser: Error interpreting the list of users from Image Repository" + str(sys.exc_info())+ "<br>")               
            elif authstatus == False:                
                self.msg = "ERROR: Wrong password"
            elif authstatus == "NoUser":                
                self.msg = "ERROR: User "+ adminId + " does not exist"
            elif authstatus == "NoActive":                
                self.msg = "ERROR: The status of the user "+ adminId + " is not active"
            else: #this should not be used
                self.msg = authstatus
        else:
            self.msg = "Please introduce your userId and password"

        raise cherrypy.HTTPRedirect("results")
    actionHistUser.exposed = True;

    ## histuser Rest service
    def histuser (self) :
        self.msg = """ <form method=get action=actionHistUser>
        Admin Username: <input type=string name=adminId><br>
        Admin Password: <input type=password name=adminCred><br>
        UserId to Search: <input type=string name=userIdtoSearch> <br>
        <input type=submit> </form> """
        return self.msg
    histuser.exposed = True;


    ## Callback function to the userAdd Rest service
    # @param adminId login/account name of the admin user to invoke this service
    # @param adminCred user password in MD5 digested format
    # @param userCred user password in MD5 digested format
    # @param userIdtoAdd user id that is the subject of the add in the datbase
    def actionUserAdd (self, adminId, adminCred, userIdtoAdd):
        self.msg = ""
        adminId = adminId.strip()
        userIdtoAdd = userIdtoAdd.strip()
        #adminCred = IRCredential("ldappass", adminCred)
        if (len(adminId) > 0 and len(userIdtoAdd) > 0):
            authstatus=self.service.auth(adminId, adminCred, self.provider)
            if authstatus == True:            
                status = self.service.userAdd(adminId, userIdtoAdd)
                if(status):
                    self.msg = "User created successfully.</br>"
                    self.msg = self.msg + "Remember that you still need to activate this user (see setuserstatus command)</br>"
                else:
                    self.msg = "The user has not been created.</br>"
                    self.msg = self.msg + "Please verify that you are admin and that the username does not exist </br>"
            elif authstatus == False:                
                self.msg = "ERROR: Wrong password"
            elif authstatus == "NoUser":                
                self.msg = "ERROR: User "+ adminId + " does not exist"
            elif authstatus == "NoActive":                
                self.msg = "ERROR: The status of the user "+ adminId + " is not active"
            else: #this should not be used
                self.msg = authstatus
        else:
            self.msg = "Please introduce your userId/password and the userId to add"
        raise cherrypy.HTTPRedirect("results")
    actionUserAdd.exposed = True

    ## useradd Rest service.  Adding a new user to the database
    def useradd (self, userId = None) :
        self.msg = """ <form method=get action=actionUserAdd>
        Admin Username: <input type=string name=adminId><br>
        Admin Password: <input type=password name=adminCred><br>
        UserId to Add: <input type=string name=userIdtoAdd> <br>
        <input type=submit> </form> """
        return self.msg
    useradd.exposed = True;

    ## Callback function to the userdel Rest service
    # @param adminId login/account name of the Rest user to invoke this service
    # @param adminCred user password in MD5 digested format
    # @param userIdtoDel user id that is the subject of the delete in the datbase
    def actionUserDel(self, adminId, adminCred, userIdtoDel):
        adminId = adminId.strip()
        userIdtoDel = userIdtoDel.strip()
        #adminCred = IRCredential("ldappass", adminCred)
        if (len(adminId) > 0 and len(userIdtoDel) > 0):            
            authstatus=self.service.auth(adminId, adminCred, self.provider)
            if authstatus == True: 
                status = self.service.userDel(adminId, userIdtoDel)
                self.msg = ""
                if(status == True):
                    self.msg = "User deleted successfully."
                else:
                    self.msg = "The user has not been deleted.</br>"
                    self.msg = self.msg + "Please verify that you are admin and that the username \"" + userIdtoDel + "\" exists \n"
            elif authstatus == False:                
                self.msg = "ERROR: Wrong password"
            elif authstatus == "NoUser":                
                self.msg = "ERROR: User "+ adminId + " does not exist"
            elif authstatus == "NoActive":                
                self.msg = "ERROR: The status of the user "+ adminId + " is not active"
            else: #this should not be used
                self.msg = authstatus
        else:
            self.msg = "Please introduce your userId/password and the userId to delete"
        raise cherrypy.HTTPRedirect("results")
    actionUserDel.exposed = True

    ## userdel Rest service. Removing a user from the database.
    def userdel (self, userId = None) :
        self.msg = """ <form method=get action=actionUserDel>
        Admin Username: <input type=string name=adminId><br>
        Admin Password: <input type=password name=adminCred><br>
        UserId to Delete: <input type=string name=userIdtoDel> <br>
        <input type=submit> </form> """
        return self.msg
    userdel.exposed = True

    ## Callback function to the userlist Rest service
    # @param adminId login/account name of the Rest user to invoke this service
    # @param adminCred user password in MD5 digested format
    def actionUserList(self, adminId, adminCred):
        self.msg = ""
        adminId = adminId.strip()
        #adminCred = IRCredential("ldappass", adminCred)
        if (len(adminId) > 0):
            authstatus=self.service.auth(adminId, adminCred, self.provider)
            if authstatus == True:
                usersList = self.service.userList(adminId)
                if (usersList != None):
                    try:
                        self.msg = "<br>" + str(len(usersList)) + " users found </br>"
                        self.msg = self.msg + "<br> UserId Cred fsCap fsUsed lastLogin status role ownedImgs </br>"
                        for user in usersList.items():
                            self.msg = self.msg + "<br>" + str(user[1])[1:len(str(user[1])) - 1]
                            self.msg = self.msg + "</br>"
                    except:
                        self.msg = "userlist: Error:" + str(sys.exc_info()) + "<br>"                    
                        self.msg = self.msg +"list: Error:" + str(sys.exc_info()) + "</br>"
                        self._log.error("userlist: Error interpreting the list of images from Image Repository" + str(sys.exc_info())+ "<br>")
                else:
                    self.msg = "No list of users returned. \n" + \
                            "Please verify that you are admin \n"
            elif authstatus == False:                
                self.msg = "ERROR: Wrong password"
            elif authstatus == "NoUser":                
                self.msg = "ERROR: User "+ adminId + " does not exist"
            elif authstatus == "NoActive":                
                self.msg = "ERROR: The status of the user "+ adminId + " is not active"
            else: #this should not be used
                self.msg = authstatus
        else:
            self.msg = "<br> Please introduce your userId and password"

        raise cherrypy.HTTPRedirect("results")
    actionUserList.exposed = True;

    ## userlist Rest service. 
    def userlist (self, userId = None) :
        self.msg = """ <form method=get action=actionUserList>
        Admin Username: <input type=string name=adminId><br>
        Admin Password: <input type=password name=adminCred><br>     
        <input type=submit> </form> """
        return self.msg
    userlist.exposed = True;

    ## Callback function to the setquota Rest service
    # @param adminId login/account name of the admin user to invoke this service
    # @param adminCred user password in MD5 digested format
    # @param userIdtoModify user id where the quota is modified
    # @param quota quota of the specified user
    def actionQuota (self, adminId, adminCred, userIdtoModify, quota) :
        self.msg = ""
        adminId = adminId.strip()
        userIdtoModify = userIdtoModify.strip()
        #adminCred = IRCredential("ldappass", adminCred)
        if (len(adminId) > 0 and len(userIdtoModify) > 0):
            try:
                quota = eval(quota)
            except:
                self.msg = "<br> The quota must be a number or a valid math function"
                raise cherrypy.HTTPRedirect("results")
            
            authstatus=self.service.auth(adminId, adminCred, self.provider)
            if authstatus == True:
                status = self.service.setUserQuota(adminId, userIdtoModify, quota)
                if(status == True):
                    self.msg = "Quota changed successfully."
                else:
                    self.msg = "The user quota has not been changed.</br>"
                    self.msg = self.msg + "Please verify that you are admin and that the username \""+userIdtoModify+"\" exists"                
            elif authstatus == False:                
                self.msg = "ERROR: Wrong password"
            elif authstatus == "NoUser":                
                self.msg = "ERROR: User "+ adminId + " does not exist"
            elif authstatus == "NoActive":                
                self.msg = "ERROR: The status of the user "+ adminId + " is not active"
            else: #this should not be used
                self.msg = authstatus
            
        else:
            self.msg = "<br> Please verify the input information, you need to include your userId/password, the userId to modify and the quota in bytes (math operation allowed)"           
        raise cherrypy.HTTPRedirect("results")
        
    actionQuota.exposed = True

    # setquota Rest service
    def setquota (self) :
        self.msg = """ <form method=get action=actionQuota>
        Admin Username: <input type=string name=adminId><br>
        Admin Password: <input type=password name=adminCred><br>
        UserId to Modify: <input type=string name=userIdtoModify> <br>
        Quota : <input type=string name=quota> <br>
        <input type=submit> </form> """
        return self.msg
    setquota.exposed = True;

    ## Callback function to Rest service setrole.
    # @param adminId login/account name of the admin user to invoke this service
    # @param adminCred user password in MD5 digested format
    # @param userIdtoModify user id that is the subject of the set role in the datbase
    # @param role
    def actionUserRole (self, adminId, adminCred, userIdtoModify, role) :
        self.msg = ""
        adminId = adminId.strip()
        userIdtoModify = userIdtoModify.strip()
        role = role.strip()
        #adminCred = IRCredential("ldappass", adminCred)
        if (len(adminId) > 0 and len(userIdtoModify) > 0 and len(role) > 0):
            if role in IRUser.Role:                
                authstatus=self.service.auth(adminId, adminCred, self.provider)
                if authstatus == True:
                    status = self.service.setUserRole(adminId, userIdtoModify, role)                                
                    if (status == True):
                        self.msg = "Role changed successfully."
                    else:
                        self.msg = "The user role has not been changed </br>"
                        self.msg = self.msg + "Please verify that you are admin and that the username \""+userIdtoModify+"\" exists"
                elif authstatus == False:                
                    self.msg = "ERROR: Wrong password"
                elif authstatus == "NoUser":                
                    self.msg = "ERROR: User "+ adminId + " does not exist"
                elif authstatus == "NoActive":                
                    self.msg = "ERROR: The status of the user "+ adminId + " is not active"
                else: #this should not be used
                    self.msg = authstatus
            else:
                self.msg = "ERROR: The user role is not valid. Available options: " + str(IRUser.Role)
        else:
            self.msg = "<br> Please introduce your userId, the userId to modify and the role"
        raise cherrypy.HTTPRedirect("results")
    actionUserRole.exposed = True

    ## setrole Rest service
    def setrole (self) :
        self.msg = """ <form method=post action=actionUserRole>
                        Admin Username: <input type=string name=adminId><br>
                        Admin Password: <input type=password name=adminCred><br>
                        UserId to Modify: <input type=string name=userIdtoModify> <br>
                Role : <input type=string name=role> <br>
                <input type=submit> </form> """
        return self.msg;
    setrole.exposed = True;

    ## Callback function to the setuserstatus Rest service.
    # @param adminId login/account name of the admin user to invoke this service
    # @param adminCred user password in MD5 digested format
    # @param userIdtoModfiy user id that is the subject of the delete in the datbase
    # @param status 
    def actionUserStatus (self, adminId, adminCred, userIdtoModify, status) :
        adminId = adminId.strip()
        userIdtoModify = userIdtoModify.strip()
        status = status.strip()
        #adminCred = IRCredential("ldappass", adminCred)
        if (len(adminId) > 0 and len(userIdtoModify) > 0 and len(status) > 0):            
            if(status in IRUser.Status):
                authstatus=self.service.auth(adminId, adminCred, self.provider)
                if authstatus == True:
                    status = self.service.setUserStatus(adminId, userIdtoModify, status)
                    self.msg = ""
                    if(status == True):
                        self.msg = "Status changed successfully."
                    else:
                        self.msg = "The user status has not been changed.</br>"
                        self.msg = self.msg + "Please verify that you are admin and that the username \"" +userIdtoModify+ "\" exists \n"
                elif authstatus == False:                
                    self.msg = "ERROR: Wrong password"
                elif authstatus == "NoUser":                
                    self.msg = "ERROR: User "+ adminId + " does not exist"
                elif authstatus == "NoActive":                
                    self.msg = "ERROR: The status of the user "+ adminId + " is not active"
                else: #this should not be used
                    self.msg = authstatus
            else:
               self.msg = "Error: Not valid status string. Available options: " + str(IRUser.Status)
        else:
            self.msg = "<br> Please introduce your userId, the userId to modify and the status"
        raise cherrypy.HTTPRedirect("results")
    actionUserStatus.exposed = True

    ## setuserstatus Rest service
    def setuserstatus (self) :
        self.msg = """ <form method=post action=actionUserStatus>
        Admin Username: <input type=string name=adminId><br>
        Admin Password: <input type=password name=adminCred><br>
        UserId to Modify: <input type=string name=userIdtoModify> <br>
        Status : <input type=string name=status> <br>
        <input type=submit> </form> """
        return self.msg;
    setuserstatus.exposed = True;
예제 #2
0
class IRServer(object):

    ############################################################
    # __init__
    ############################################################
    def __init__(self):
        super(IRServer, self).__init__()

        self.numparams = 4

        self._service = IRService()
        self._log = self._service.getLog()
        self._repoconf = self._service.getRepoConf()

        self.port = self._repoconf.getPort()
        self.proc_max = self._repoconf.getProcMax()
        self.refresh_status = self._repoconf.getRefreshStatus()
        self._authorizedUsers = self._repoconf.getAuthorizedUsers()    
        
        self._ca_certs = self._repoconf.getCaCerts()
        self._certfile = self._repoconf.getCertFile()
        self._keyfile = self._repoconf.getKeyFile()
        
    def start(self):
        
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        sock.bind(('', self.port))
        sock.listen(1) #Maximum of system unaccepted connections. Maximum value depend of the system (usually 5) 
        self._log.info('Starting Server on port ' + str(self.port))        
        proc_list = []
        total_count = 0
        while True:            
            if len(proc_list) == self.proc_max:
                full = True
                while full:
                    for i in range(len(proc_list) - 1, -1, -1):
                        #self._log.debug(str(proc_list[i]))
                        if not proc_list[i].is_alive():
                            #print "dead"                        
                            proc_list.pop(i)
                            #put here terminate?? just in case the process is not done but neither alive?? I have noticed that when IOError the process keep running
                            full = False
                    if full:
                        time.sleep(self.refresh_status)
            
            total_count += 1            
            #channel, details = sock.accept()
            newsocket, fromaddr = sock.accept()
            connstream = None
            try:
                connstream = ssl.wrap_socket(newsocket,
                              server_side=True,
                              ca_certs=self._ca_certs,
                              cert_reqs=ssl.CERT_REQUIRED,
                              certfile=self._certfile,
                              keyfile=self._keyfile,
                              ssl_version=ssl.PROTOCOL_TLSv1)
                #print connstream                                
                proc_list.append(Process(target=self.repo, args=(connstream,)))            
                proc_list[len(proc_list) - 1].start()
            except ssl.SSLError:
                self._log.error("Unsuccessful connection attempt from: " + repr(fromaddr) + " " + str(sys.exc_info()))
            except socket.error:
                self._log.error("Error with the socket connection")
            except:
                self._log.error("Uncontrolled Error: " + str(sys.exc_info()))
                if type(connstream) is ssl.SSLSocket: 
                    connstream.shutdown(socket.SHUT_RDWR)
                    connstream.close()
                     
    #def auth(self, userCred):
    #    return FGAuth.auth(self.user, userCred)        
      
    
    def repo(self, channel):
        
        self._log = self._log.getLogger("Img Repo Server." + str(os.getpid()))
        
        self._service.setLog(self._log)
        
        self._log.info('Processing request')
        #it will have the IP of the VM
        vmaddr = ""        
        options = ''    
        vmID = 0
        
        #receive the message
        data = channel.read(2048)
        
        self._log.debug("received data: " + data)
        
        params = data.split('|')

        #params[0] is user that authenticates  
        #params[1] is the user password
        #params[2] is the type of password
        #params[3] is the command
        #params[4] is the user that interact with the repo. Usually is the same that params[0]
        #params[5...] are the options 

        if (len(params) <= self.numparams):
            msg = "ERROR: Invalid Number of Parameters"    
            self.errormsg(channel, msg)
            sys.exit(1)
        
        self.user = params[0].strip() #ONLY for authentication. To specify the user that call methods you need to use params[4]
        passwd = params[1].strip()
        passwdtype = params[2].strip()
        command = params[3].strip()
                
        for i in range(len(params)):
            params[i] = params[i].strip()

        
        if not self.user in self._authorizedUsers:
            if not (self.user == params[4]):
                msg = "ERROR: You are not authorized to act in behalf of other user"    
                self.errormsg(channel, msg)
                sys.exit(1)
        
        
        retry = 0
        maxretry = 3
        endloop = False
        while (not endloop):
            #userCred = FGCredential(passwd, passwdtype)
            status = self._service.auth(self.user, passwd, passwdtype)
            if status == True:
                channel.write("OK")
                endloop = True
            elif status == False:
                #_authorizedUsers is not used currently. If we want to activate it, we need to make sure that the authizedUsers are in the Repository database
                if self.user in self._authorizedUsers: #because these users are services that cannot retry.
                    msg = "ERROR: authentication failed"                    
                    self.errormsg(channel, msg)
                    sys.exit(1)
                else:
                    msg = "ERROR: authentication failed. Try again"
                    self._log.error(msg)
                    retry += 1
                    if retry < maxretry:
                        channel.write("TryAuthAgain")
                        passwd = channel.read(2048)
                    else:
                        msg = "ERROR: authentication failed"                        
                        self.errormsg(channel, msg)
                        sys.exit(1)
            else:
                msg = status #this is NoActive or NoUser                
                self.errormsg(channel, msg)
                sys.exit(1)
        
        #channel.write("OK")
        
        ## For test, remove previous line
                
        needtoclose = False      
        if (command == "list"):
            if (len(params) == self.numparams + 2):
                #user, query string
                #print params[5]
                output = self._service.query(params[4], params[5])                
                channel.write(str(output))
                needtoclose = True
            else:
                msg = "Invalid Number of Parameters"
                self.errormsg(channel, msg)        
        elif (command == "get"):
            #user, img/uri, imgid
            if (len(params) == self.numparams + 3):
                output = self._service.get(params[4], params[5], params[6])
                channel.write(str(output))
                if output != None:
                    status = channel.read(1024) ##just to wait for client answer.
                    if status != 'OK':
                        self._log.error("ERROR: Client did not receive the image")
                        needtoclose = False
                    else:
                        needtoclose = True                 
                    if (self._service.getBackend() != "mysql"):
                        cmdrm = " rm -f " + output             
                        self._log.debug("Deleting Temporal file: " + cmdrm)           
                        os.system(cmdrm)                
            else:
                msg = "Invalid Number of Parameters"
                self.errormsg(channel, msg)
        elif (command == "put"):
            #user, img_size, extension, attributeString   
            if (len(params) == self.numparams + 4):
                self._log.debug("Before uploadValidator ")
                output = self._service.uploadValidator(params[4], long(params[5]))
                self._log.debug("After uploadValidator "+str(output))                
                if str(output) == 'True':
                    self._log.debug("Before genImgId ")                               
                    imgId = self._service.genImgId()
                    self._log.debug("After genImgId "+str(imgId))
                    if imgId != None:
                        self._log.debug("sending to the client: "+str(self._service.getImgStore())+ " , "+str(imgId))
                        channel.write(self._service.getImgStore() + "," + str(imgId))
                        self._log.debug("sent and waiting in the read")
                        #waiting for client to upload image
                        output = channel.read(2048)                    
                        if output != 'Fail':
                            #user, imgId, imgFile(uri), attributeString, size, extension
                            output = self._service.put(params[4], imgId, output, params[7], long(params[5]), params[6])
                            channel.write(str(output))
                            needtoclose = True
                        else:
                            os.system("rm -f "+self._service.getImgStore() + "/" + str(imgId))
                            self._log.debug("rm -f "+self._service.getImgStore() + "/" + str(imgId))                    
                    else:
                        channel.write()
                        msg = "ERROR: The imgId generation failed"
                        self.errormsg(channel, msg)
                else:
                    output = str(output)
                    if output == "NoUser":                    
                        status = "ERROR: The User does not exist"
                    elif (output == "NoActive"):                    
                        status = "ERROR: The User is not active"
                    elif (output == 'False'):
                        status = "ERROR: The file exceed the quota"
                    else:
                        status = "ERROR: " + output
                    msg = status
                    self.errormsg(channel, msg)
            else:
                msg = "ERROR: Invalid Number of Parameters"
                self.errormsg(channel, msg)    
            #send storage directory, temporal or not
            #receive the OK, meaning that the image is already there
        elif (command == "modify"):
            #userid, imgid, attributestring
            if (len(params) == self.numparams + 3):
                output = self._service.updateItem(params[4], params[5], params[6])
                channel.write(str(output))
            else:
                msg = "Invalid Number of Parameters"
                self.errormsg(channel, msg)
        elif (command == "remove"):
            #user, imgid
            if (len(params) == self.numparams + 2):
                output = self._service.remove(params[4], params[5])
                channel.write(str(output))
            else:
                msg = "Invalid Number of Parameters"
                self.errormsg(channel, msg)
        elif (command == "setPermission"):
            #user, imgid, query
            if (len(params) == self.numparams + 3):                
                output = self._service.updateItem(params[4], params[5], "permission=" + params[6])
                channel.write(str(output))
            else:
                msg = "Invalid Number of Parameters"
                self.errormsg(channel, msg)
        elif (command == "histimg"):
            #userId, imgId
            if (len(params) == self.numparams + 2):
                output = self._service.histImg(params[4], params[5])
                channel.write(str(output))                
            else:
                msg = "Invalid Number of Parameters"
                self.errormsg(channel, msg)
        elif (command == "histuser"):
            #userId, userId
            if (len(params) == self.numparams + 2):
                output = self._service.histUser(params[4], params[5])
                channel.write(str(output))
            else:
                msg = "Invalid Number of Parameters"
                self.errormsg(channel, msg)
        #elif (command == "uploadValidator"):
        #    #user, size of the img to upload
        #    if (len(optionlist) != 2):
        #        output = self._service.uploadValidator(optionlist[0], long(optionlist[1]))
        #        channel.write(str(output))
        #    else:
        #        msg = "Invalid Number of Parameters"
        #        self.errormsg(channel, msg)
        #elif (command == "genImgId"):
        #    if (len(optionlist) != 1):
        #        output = self._service.genImgId()
        #        channel.write(str(output))
        #    else:
        #        msg = "Invalid Number of Parameters"
        #        self.errormsg(channel, msg)
        elif (command == "getBackend"):
            if (len(params) == self.numparams + 1):
                output = self._service.getBackend()
                output1 = self._service.getImgStore()
                channel.write(str(output) + str(output1))
            else:
                msg = "Invalid Number of Parameters"
                self.errormsg(channel, msg)
        elif (command == "useradd"):
            #userid, useridtoadd
            if (len(params) == self.numparams + 2):
                output = self._service.userAdd(params[4], params[5])
                channel.write(str(output))
            else:
                msg = "Invalid Number of Parameters"
                self.errormsg(channel, msg)
        elif (command == "userdel"):
            #userid, useridtodel
            if (len(params) == self.numparams + 2):
                output = self._service.userDel(params[4], params[5])
                channel.write(str(output))
            else:
                msg = "Invalid Number of Parameters"
                self.errormsg(channel, msg)
        elif (command == "userlist"):
            #userid
            if (len(params) == self.numparams + 1):
                output = self._service.userList(params[4])
                channel.write(str(output))
            else:
                msg = "Invalid Number of Parameters"
                self.errormsg(channel, msg)
        elif (command == "setUserQuota"):
            #userid, useridtomodify, quota in bytes
            if (len(params) == self.numparams + 3):
                output = self._service.setUserQuota(params[4], params[5], long(params[6]))
                channel.write(str(output))
            else:
                msg = "Invalid Number of Parameters"
                self.errormsg(channel, msg)
        elif (command == "setUserRole"):
            #userid, useridtomodify, role
            if (len(params) == self.numparams + 3):
                output = self._service.setUserRole(params[4], params[5], params[6])
                channel.write(str(output))
            else:
                msg = "Invalid Number of Parameters"
                self.errormsg(channel, msg)
        elif (command == "setUserStatus"):
            if (len(params) == self.numparams + 3):
                output = self._service.setUserStatus(params[4], params[5], params[6])
                channel.write(str(output))
            else:
                msg = "Invalid Number of Parameters"
                self.errormsg(channel, msg)
        elif (command == "getUserStatus"):
            #userId
            if (len(params) == self.numparams + 1):
                output = self._service.getUserStatus(params[4])
                channel.write(str(output))
            else:
                msg = "Invalid Number of Parameters"
                self.errormsg(channel, msg)
        else:
            msg = "Invalid Command: " + command
            self.errormsg(channel, msg)
            needtoclose = False
        
        if needtoclose:
            channel.shutdown(socket.SHUT_RDWR)
            channel.close()
            self._log.info("Image Repository Request DONE")
        else:
            self._log.info("Image Repository Request DONE")
        
    def errormsg(self, channel, msg):
        self._log.error(msg)
        try:        
            channel.write(msg)                    
            channel.shutdown(socket.SHUT_RDWR)
            channel.close()
        except:
            self._log.debug("In errormsg: " + str(sys.exc_info()))
        self._log.info("Image Repository Request DONE")