class UpdateMetadataServer(Method):
    """
   Update a metadata server. A user can only update a metadata server that he/she owns.  An admin can update any metadata server.
   If the server is running, this method restarts it on successful application of the updated fields
   """

    accepts = [
        Auth(),
        Mixed(MDServer.fields['server_id'], MDServer.fields['name']),
        dict([(n, MDServer.fields[n])
              for n in ['auth_read', 'auth_write', 'portnum']])
    ]
    roles = ['admin', 'user']
    returns = Parameter(int, "1 if successful; negative error code otherwise")

    def load_mdserver(self, mdserver_name_or_id):
        mdserver = None
        try:
            mdservers = []
            if isinstance(mdserver_name_or_id, str):
                mdservers = MDServers(self.api, {'name': mdserver_name_or_id})
            else:
                mdservers = MDServers(self.api,
                                      {'server_id': mdserver_name_or_id})

            mdserver = mdservers[0]
        except Exception, e:
            raise MDObjectNotFound("MDServer(%s)" % mdserver_name_or_id)

        return mdserver
Esempio n. 2
0
class GetContentServers( Method ):
   """
   Read zero or more content servers.  If no filter is given, every content server added by the caller is read.
   Admins can see all content servers; users can only see their own
   """
   
   accepts = [
         Auth(),
         Parameter( dict, "Fields to filter on", nullok = True ),
         Parameter( [str], "List of fields to return", nullok = True )
   ]
   roles = ['admin','user']
   returns = [Content.fields]
   
   """
   def call(self, auth, content_filter, return_fields):
      assert self.caller is not None
      
      
      # ask the CDN for the content 
      content = self.api.cdn.get_content( content_filter, return_fields )
      return content
  
   """
   
   def call(self, auth, content_filter, return_fields):
      assert self.caller is not None
      
      roles = self.caller['roles']
      
      if not content_filter:
         content_filter = {}
      
      if not return_fields:
         return_fields = [name for (name,param) in Content.fields.items()]
      
      users = Users(self.api, {'username': auth['Username']}) 
      user = users[0]
      
      if content_filter.get('owner') != None and content_filter['owner'] != user['user_id'] and (self.caller == None or 'admin' not in roles):
         raise MDUnauthorized( "User(%s) is not allowed to read content servers from User(%s)" % (user['username'], content_filter['owner']) )
      
      # if the caller isn't an admin, then only read content servers with the caller's user id
      if 'admin' not in roles:
         content_filter['owner'] = user['user_id']
      
      contents = Contents( self.api, content_filter )
      
      # remove non-specified return fields
      ret = []
      for c in contents:
         c_dict = {}
         for rf in return_fields:
            if rf in c:
               c_dict[rf] = c[rf]
            
         ret.append( c_dict )
            
      return ret
class AddUserToMetadataServer( Method ):
   """
   Add a user to a metadata server.  The caller must be the owner of the metadata server, or an admin.
   """
   
   accepts = [
         Auth(),
         Mixed(Parameter(int, "User ID of the user who will be added to this server"),
               Parameter(str, "Username of the user who will be added to this server")),
         
         Mixed(MDServer.fields['server_id'], MDServer.fields['name'])
   ]
   roles = ['admin','user']
   returns = Parameter(int, "1 if successful; otherwise a negative error code from failing to update the metadata server")
   
   
   def call(self, auth, username_or_id, metadata_server_name_or_id):
      assert self.caller is not None
      
      roles = self.caller['roles']
      
      owner = None
      try:
         owners = Users(self.api, {'username': auth['Username']})
         owner = owners[0]
      except:
         raise MDObjectNotFound( auth['Username'], "Caller not found" )
      
      # look up this metadata server
      mdservers = None
      mdserver = None
      try:
         if isinstance( metadata_server_name_or_id, int ):
            mdservers = MDServers( self.api, {'server_id': metadata_server_name_or_id} )
         else:
            mdservers = MDServers( self.api, {'name': metadata_server_name_or_id} )
            
         mdserver = mdservers[0]
      except Exception, e:
         raise MDObjectNotFound( 'MDServer(%s)' % (metadata_server_name_or_id), str(e))
      
      # make sure this server is owned by the caller, or that the caller is an admin
      if 'admin' not in roles and mdserver['owner'] != owner['user_id']:
         raise MDUnauthorized( "User(%s) is not the owner of MDServer(%s)" % (owner['username'], metadata_server_name_or_id) )
         
      # look up this user to be added
      users = None
      user = None
      try:
         if isinstance(username_or_id, str):
            users = Users( self.api, {'username':username_or_id, 'enabled': True})
         else:
            users = Users( self.api, {'user_id':username_or_id, 'enabled': True})
         
         user = users[0]
      except Exception, e:
         raise MDObjectNotFound( 'User(%s)' % (username_or_id), str(e) )
Esempio n. 4
0
class DeleteUser(Method):
    """
   Remove a user account.  A user may remove himself/herself, but no one else.  An admin may remove anyone.
   All of the user's registered content and metadata servers will be removed as well.  The user will be
   removed from all metadata servers.
   """

    accepts = [Auth(), Mixed(User.fields['user_id'], User.fields['username'])]

    roles = ['admin', 'user']
    returns = Parameter(int, "1 if successful")

    def call(self, auth, username_or_id):
        assert self.caller is not None

        roles = self.caller['roles']

        user = None
        try:
            if isinstance(username_or_id, str):
                users = Users(self.api, {'username': username_or_id})
            else:
                users = Users(self.api, {'user_id': username_or_id})

            user = users[0]
        except Exception, e:
            raise MDObjectNotFound('User(%s)' % (username_or_id), str(e))

        # user can only delete himself/herself, unless admin
        if ('admin' not in roles) and user['username'] != auth['Username']:
            raise MDUnauthorized("User(%s) cannot be deleted by User(%s)" %
                                 (username_or_id, auth['Username']))

        # unregister this user from every metadata server it's subscribed to
        for md_id in user['sub_mdserver_ids']:
            md = None
            try:
                mds = MDServers(self.api, {'server_id': md_id})
                md = mds[0]
            except:
                continue

            try:
                md.remove_user(user)
            except MDException, mde:
                raise MDMethodFailed(
                    "Could not remove User(%s) from MDServer(%s)" %
                    (user['username'], md_id), mde)
            except Exception, e:
                raise MDMethodFailed(
                    "Failed to destroy User(%s)" % username_or_id, str(e))
Esempio n. 5
0
class GetMetadataFromServer(Method):
    """
   Get metadata from a running metadata server, given its URL, ID, or (hostname, portnum) tuple
   """

    accepts = [
        Auth(),
        Mixed(Mixed(MDServer.fields['host'], MDServer.fields['portnum']),
              Parameter(str, "Metadata server URL"),
              Parameter(int, "Metadata server ID"))
    ]
    roles = ['user', 'admin']
    returns = Parameter([str], "List of metadata entries as strings")

    def call(self, auth, host_portnum_or_url_or_id):
        assert self.caller is not None

        md_server_url = None

        if isinstance(host_portnum_or_url_or_id, list) or isinstance(
                host_portnum_or_url_or_id, tuple):
            md_server_url = host_portnum_or_url_or_id[0] + '/' + str(
                host_portnum_or_url_or_id[1])
        elif isinstance(host_portnum_or_url_or_id, str):
            md_server_url = host_portnum_or_url_or_id
        else:
            # look up metadata server and get its URL
            mdservers = MDServers({'server_id': host_portnum_or_url_or_id})
            if len(mdservers) <= 0:
                # not found
                raise MDObjectNotFound('mdserver', host_portnum_or_url_or_id)

        # perform a GET on the url, with the caller's credentials
        auth_header = urllib2.HTTPBasicAuthHandler()
        auth_header.add_password(realm=None,
                                 uri=md_server_url,
                                 user=auth.get('Username'),
                                 passwd=auth.get('AuthString'))
        opener = urllib2.build_opener(auth_header)

        urllib2.install_opener(opener)

        metadata = None
        try:
            md_handle = urllib2.urlopen(md_server_url)
            metadata = md_handle.read()
            md_handle.close()
        except Exception, e:
            raise MDMethodFailed("Could not open '%s'" % (md_server_url), e)

        return metadata.split("\n")[:-1]
Esempio n. 6
0
class DeleteMetadataServer(Method):
    """
   Delete a metadata server.  This will also stop it.  Unregister all other users from this server.
   The caller can delete only their own metadata servers, unless they are an admin.
   """

    accepts = [
        Auth(),
        Mixed(MDServer.fields['name'], MDServer.fields['server_id'])
    ]
    roles = ['admin', 'user']
    returns = Parameter(
        int,
        "1 if successful; otherwise a negative error code resulting from a failure to shut down the metadata server"
    )

    def call(self, auth, mdserver_name_or_id):
        assert self.caller is not None

        roles = self.caller['roles']

        # look up the mdserver
        md = None
        try:
            if isinstance(mdserver_name_or_id, str):
                mds = MDServers(self.api, {'name': mdserver_name_or_id})
            else:
                mds = MDServers(self.api, {'server_id': mdserver_name_or_id})
            md = mds[0]
        except Exception, e:
            raise MDObjectNotFound("MDServer(%s)" % (mdserver_name_or_id),
                                   str(e))

        # look up the user
        user = None
        try:
            user_identifier = None
            if 'admin' not in roles:
                users = Users(self.api, {'username': auth['Username']})
                user_identifier = auth['Username']
            else:
                users = Users(self.api, {'user_id': md['owner']})
                user_identifier = md['owner']
            user = users[0]
        except Exception, e:
            raise MDObjectNotFound("User(%s)" % user_identifier, str(e))
class AddContentServer(Method):
    """
   Add a content server under the control of a user.  Register the server
   on the underlying CDN as well.
   
   The owner of this content will be the user that calls this method.
   """

    accepts = [Auth(), dict([(k, Content.fields[k]) for k in ['host_url']])]
    roles = ['admin', 'user']
    returns = Parameter(int,
                        "The content's ID (positive number) if successful")

    def call(self, auth, content_fields):
        assert self.caller is not None

        users = Users(self.api, {'username': auth['Username']})
        user = users[0]

        # how many contents has this user created?
        num_contents = len(user['content_ids'])

        if num_contents > user['max_contents']:
            raise MDResourceExceeded('User(%s)' % (user['username']),
                                     'content server')

        content_fields['owner'] = user['user_id']

        # register this content on the CDN
        remote_content_id = self.api.cdn.add_content(
            user, content_fields['host_url'])
        if remote_content_id == None or remote_content_id < 0:
            raise MDInternalError(
                "AddContentServer: CDN could not add '%s' to the CDN with user '%s'"
                % (content_fields.get('host_url'),
                   content_fields.get('username')))

        c = Content(self.api, content_fields)
        c['content_id'] = remote_content_id
        c.sync(insert=True)

        user.add_content(c)  # will synchronize itself
        user.sync()

        return c['content_id']
class StartMetadataServer(Method):
    """
   Activate an existing metadata server.  The caller must own the metadata server, unless they are an admin.
   """

    accepts = [
        Auth(),
        Mixed(MDServer.fields['server_id'], MDServer.fields['name'])
    ]
    roles = ['admin', 'user']
    returns = Parameter(
        [str], "The read and write URLs of the metadata server (on success)")

    def call(self, auth, mdserver_name_or_id):
        roles = []
        if self.caller:
            roles = self.caller['roles']

        users = Users(self.api, {'username': auth['Username']})
        user = users[0]

        mdserver = None
        try:
            mdservers = None
            if isinstance(mdserver_name_or_id, str):
                mdservers = MDServers(self.api, {'name': mdserver_name_or_id})
            else:
                mdservers = MDServers(self.api,
                                      {'server_id': mdserver_name_or_id})

            mdserver = mdservers[0]
        except Exception, e:
            raise MDObjectNotFound("MDServer(%s)", mdserver_name_or_id, e)

        if (self.caller == None or 'admin'
                not in roles) and mdserver['owner'] != user['user_id']:
            raise MDUnauthorized("MDServer(%s) cannot be started by User(%s)" %
                                 (mdserver_name_or_id, user['username']))

        rc = mdserver.start_server()
        if not rc:
            raise MDMetadataServerError("Could not start server")
        else:
            # started up!
            return rc
class DeleteContentServer(Method):
    """
   Delete a content server.  This method will work either if this user is an admin
   or the user owns the content server
   """

    accepts = [Auth(), Content.fields['content_id']]
    roles = ['admin', 'user']
    returns = Parameter(
        int,
        "1 if successful; negative error code if the content server could not be unregistered from the CDN"
    )

    def call(self, auth, content_id):
        assert self.caller is not None

        roles = self.caller['roles']

        # look up user
        user = None
        try:
            users = Users(self.api, {'username': auth['Username']})
            user = users[0]
        except Exception, e:
            raise MDObjectNotFound("User(%s)" % auth['Username'], str(e))

        # sanity check
        if content_id not in user['content_ids']:
            raise MDInvalidArgument(
                "Content(%s) is not owned by User(%s)" %
                (content_id, auth['Username']), "DeleteContentServer")

        # look up content
        content = None
        try:
            contents = Contents(self.api, {'content_id': content_id})
            content = contents[0]
        except Exception, e:
            raise MDObjectNotFound("Content(%s)" % content_id, str(e))
Esempio n. 10
0
class AddUser(Method):
    """
   Add a user account.  The account will be disabled at first.
   """

    accepts = [
        Auth(),
        dict([(n, User.fields[n]) for n in ['username', 'password', 'email']])
    ]
    roles = ['admin']
    returns = Parameter(int, "The user's UID (positive number) if successful")

    def call(self, auth, user_fields):
        assert self.caller is not None

        # hash the password before we store it
        m = SMDS.auth.new_sha1()
        m.update(user_fields['password'])
        password_hash = m.hexdigest().lower()
        user_fields['password'] = password_hash

        # default constraints on a user's power
        user_fields['max_mdservers'] = self.api.DEFAULT_MAX_MDSERVERS
        user_fields['max_contents'] = self.api.DEFAULT_MAX_CONTENTS
        user_fields['enabled'] = False
        user_fields['roles'] = ['user']

        u = User(self.api, user_fields)

        # register this user on the CDN
        rc = self.api.cdn.add_user(u)
        if rc != 1:
            raise MDInternalError(
                "AddUser: could not add User(%s) to the CDN" % (u['username']))

        u.sync()

        return u['user_id']
Esempio n. 11
0
class GetUsers(Method):
    """
   Get a list of users
   """

    accepts = [
        Auth(),
        Filter(User.fields),
        Parameter([str], "List of fields to return", nullok=True)
    ]
    roles = ['admin', 'user']
    returns = [User.fields]

    def call(self, auth, user_fields, return_fields=None):
        assert self.caller is not None

        if 'password' in user_fields:
            del user_fields['password']

        if not return_fields:
            return_fields = [name for (name, param) in User.fields.items()]

        if 'password' in return_fields:
            return_fields.remove('password')

        users = Users(self.api, user_fields)

        ret = []
        for u in users:
            u_dict = {}
            for rf in return_fields:
                if rf in u.keys():
                    u_dict[rf] = u[rf]

            ret.append(u_dict)

        return ret
class GetMetadataServers(Method):
    """
   Get a list of zero or more extant metadata servers.
   """

    accepts = [
        Auth(),
        Filter(MDServer.fields),
        Parameter([str], "List of fields to return", nullok=True)
    ]
    roles = ['admin', 'user']
    returns = [MDServer.fields]

    def call(self, auth, mdserver_fields, return_fields):

        assert self.caller is not None

        roles = self.caller['roles']

        users = Users(self.api, {'username': auth['Username']})
        user = users[0]

        if not return_fields:
            return_fields = [name for (name, param) in MDServer.fields.items()]

        mdservers = MDServers(self.api, mdserver_fields)

        ret = []
        for md in mdservers:
            md_dict = {}
            for rf in return_fields:
                if rf in md:
                    md_dict[rf] = md[rf]
            ret.append(md_dict)

        return ret
Esempio n. 13
0
class UpdateUser(Method):
    """
   Update a user.  A user can only update himself/herself, and only a few fields at that.  An admin can update anyone, with some admin-specific fields.
   """

    admin_only_fields = [
        'max_mdservers', 'max_contents', 'enabled', 'roles', 'username'
    ]

    accepts = [
        Auth(),
        Mixed(User.fields['username'], User.fields['user_id']),
        dict([(n, User.fields[n])
              for n in set(User.fields.keys()).difference(set(['user_id']))])
    ]
    roles = ['admin', 'user']
    returns = Parameter(int, "1 if successful; negative error code otherwise")

    def call(self, auth, username_or_id, user_fields):
        assert self.caller is not None

        roles = self.caller['roles']

        # look up the caller user ID
        calling_users = Users(self.api, {'username': auth['Username']})
        calling_user = calling_users[0]

        # look up this user
        user = None
        try:
            users = None
            if isinstance(username_or_id, str):
                users = Users(self.api, {'username': username_or_id})
            else:
                users = Users(self.api, {'user_id': username_or_id})

            user = users[0]
        except Exception, e:
            raise MDObjectNotFound("User(%s)" % username_or_id, e)

        # can we update this user?
        if ('admin'
                not in roles) and user['user_id'] != calling_user['user_id']:
            raise MDUnauthorized("User(%s) cannot be updated by User(%s)" %
                                 (username_or_id, Auth['Username']))

        if 'admin' not in roles:
            # not an admin, so make sure that the admin-only fields don't change
            bad_fields = []
            for aof in self.admin_only_fields:
                if aof in user_fields.keys():
                    bad_fields.append(aof)

            if len(bad_fields) > 0:
                raise MDUnauthorized(
                    "Only an admin can update fields %s of User(%s)" %
                    (username_or_id, ", ".join(bad_fields)))

        if 'password' in user_fields.keys():
            # hash the password
            m = Auth.new_sha1()
            m.update(user_fields['password'])
            password_hash = m.hexdigest().lower()
            user_fields['password'] = password_hash

        user.update(user_fields)
        user.sync()

        return 1
class DeleteUserFromMetadataServer(Method):
    """
   Remove one or more users from a metadata server.  The caller is only allowed to call this method on his/her own metadata server;
   but an admin can call this method on any metadata server.
   
   The caller is not allowed to remove a user from the metadata server owned by that user.
   """

    accepts = [
        Auth(),
        Mixed(
            Parameter(int,
                      "User ID of the user to be removed from this server"),
            Parameter(str,
                      "Username of the user to be removed from this server"),
            Parameter([int],
                      "User IDs of the users to be removed from this server")),
        Mixed(Parameter(int, "Metadata server ID"),
              Parameter(str, "Metadata name"))
    ]
    roles = ['admin', 'user']
    returns = Parameter(
        int,
        "1 if successful; otherwise a negative error code from failure to update the metadata server"
    )

    def load_mdserver(self, metadata_server_id):
        mdservers = None
        if isinstance(metadata_server_id, str):
            mdservers = MDServers(self.api, {'name': metadata_server_id})
        else:
            mdservers = MDServers(self.api, {'server_id': metadata_server_id})

        mdserver = mdservers[0]
        return mdserver

    def call(self, auth, username_or_id, metadata_server_id):
        assert self.caller is not None

        roles = self.caller['roles']

        owners = Users(self.api, {'username': auth['Username']})
        owner = owners[0]

        # look up this metadata server
        mdservers = None
        mdserver = None
        try:
            mdserver = self.load_mdserver(metadata_server_id)
        except Exception, e:
            raise MDObjectNotFound('MDServer(%s)' % (metadata_server_id),
                                   str(e))

        # make sure this server is owned by the caller, or that the caller is an admin
        if ('admin' not in roles) and mdserver['owner'] != owner['user_id']:
            raise MDUnauthorized("User(%s) is not the owner of MDServer(%s)" %
                                 (owner['username'], mdserver['server_id']))

        # look up this user to be removed
        users = None
        user = None
        remove_many = False
        try:
            if isinstance(username_or_id, str):
                users = Users(self.api, {'username': username_or_id})
            elif isinstance(username_or_id, int) or isinstance(
                    username_or_id, long):
                users = Users(self.api, {'user_id': username_or_id})
            elif isinstance(username_or_id, list):
                users = Users(self.api, username_or_id)
                remove_many = True

            user = users[0]
        except Exception, e:
            raise MDObjectNotFound('User(%s)' % (username_or_id), str(e))
Esempio n. 15
0
class AddMetadataServer(Method):
    """
   Add a metadata server.  Does not start it, but adds an entry for it in our database.
   The owner of this metadata server will be the user that calls this method.
   """

    accepts = [
        Auth(),
        dict([(n, MDServer.fields[n])
              for n in set(MDServer.fields.keys()).difference(
                  set(['owner', 'status', 'user_ids']))])
    ]
    roles = ['admin', 'user']
    returns = Parameter(
        int, "The metadata server's ID (positive number) if successful")

    def call(self, auth, mdserver_fields):
        assert self.caller is not None

        # look up the user ID
        users = Users(self.api, {'username': auth['Username']})
        user = users[0]

        # how many metadata servers does this user have?
        num_md_servers = len(user['my_mdserver_ids'])
        if num_md_servers > user['max_mdservers']:
            raise MDResourceExceeded('User(%s)' % user['username'],
                                     'metadata server')

        mdserver_fields['owner'] = user['user_id']
        mdserver_fields['status'] = 'stopped'

        # url-encode the name, if it exists.  Otherwise use a UUID
        if mdserver_fields.get('name'):
            mdserver_fields['name'] = urllib2.quote(mdserver_fields['name'])
        else:
            mdserver_fields['name'] = urllib2.quote(uuid.uuid4().hex)

        # authenticate read/write by default
        if not mdserver_fields.get('auth_read'):
            mdserver_fields['auth_read'] = True

        if not mdserver_fields.get('auth_write'):
            mdserver_fields['auth_write'] = True

        # get a hostname, if one was not given
        # if we don't have a host, then pick one
        if not mdserver_fields.get('host'):
            host = self.api.next_server_host()
            mdserver_fields['host'] = host

        md = MDServer(self.api, mdserver_fields)
        md.sync()

        # update join tables
        user.add_mdserver(md)
        md.add_user(user)
        server_id = md['server_id']

        # reload
        md = MDServers(self.api, [server_id])[0]

        rc = md.create_server()
        if rc != 1:
            raise MDMethodFailed(
                "md.create_server()",
                "Could not create metadata server, rc = %s" % rc)

        return md['server_id']