def generate_privileges(datastore, allow_create, volume_maxsize_in_MB,
                        volume_totalsize_in_MB):
    """ Generate privileges based on input params """
    logging.debug(
        "generate_privileges: datastore=%s allow_create=%s"
        "volume_maxsize_in_MB=%s volume_totalsize_in_MB=%s", datastore,
        allow_create, volume_maxsize_in_MB, volume_totalsize_in_MB)
    privileges = default_privileges()[0]
    if datastore == auth.DEFAULT_DS:
        datastore_url = auth.DEFAULT_DS_URL
    else:
        datastore_url = vmdk_utils.get_datastore_url(datastore)
    privileges[auth_data_const.COL_DATASTORE_URL] = datastore_url

    if allow_create is True:
        set_privileges(allow_create, privileges, 1)

    if volume_maxsize_in_MB:
        privileges[auth_data_const.COL_MAX_VOLUME_SIZE] = volume_maxsize_in_MB

    if volume_totalsize_in_MB:
        privileges[auth_data_const.COL_USAGE_QUOTA] = volume_totalsize_in_MB

    logging.debug("generate_privileges: privileges=%s", privileges)
    return privileges
示例#2
0
def get_total_storage_used(tenant_uuid, datastore):
    """ Return total storage used by (tenant_uuid, datastore)
        by querying auth DB.

        Return value:
        -- error_msg: return None on success or error info on failure
        -- total_storage_used: return total storage used for given (tenant_uuid, datastore)
                               return None on failure

    """
    total_storage_used = 0
    err_msg, _auth_mgr = get_auth_mgr()
    if err_msg:
        return err_msg, total_storage_used

    datastore_url = vmdk_utils.get_datastore_url(datastore)
    try:
        cur = _auth_mgr.conn.execute(
            "SELECT SUM(volume_size) FROM volumes WHERE tenant_id = ? and datastore_url = ?",
            (tenant_uuid, datastore_url)
            )
    except sqlite3.Error as e:
        logging.error("Error %s when querying storage table for tenant_id %s and datastore %s",
                      e, tenant_uuid, datastore)
        return str(e), total_storage_used
    result = cur.fetchone()
    if result:
        if result[0]:
            total_storage_used = result[0]
            logging.debug("total storage used for (tenant %s datastore %s) is %s MB", tenant_uuid,
                          datastore, total_storage_used)

    return None, total_storage_used
示例#3
0
def get_privileges(tenant_uuid, datastore):
    """ Return privileges for given (tenant_uuid, datastore) pair by
        querying the auth DB.
        Return value:
        -- error_msg: return None on success or error info on failure
        -- privilegs: return a list of privileges for given (tenant_uuid, datastore)
           return None on failure
    """
    err_msg, _auth_mgr = get_auth_mgr()
    if err_msg:
        return err_msg, None
    privileges = []
    logging.debug("get_privileges tenant_uuid=%s datastore=%s", tenant_uuid, datastore)
    datastore_url = vmdk_utils.get_datastore_url(datastore)
    try:
        cur = _auth_mgr.conn.execute(
            "SELECT * FROM privileges WHERE tenant_id = ? and datastore_url = ?",
            (tenant_uuid, datastore_url)
            )
        privileges = cur.fetchone()
    except sqlite3.Error as e:
        logging.error("Error %s when querying privileges table for tenant_id %s and datastore %s",
                      e, tenant_uuid, datastore)
        return str(e), None
    if privileges:
        return None, privileges
    else:
        # check default privileges
        error_msg, privileges = get_default_privileges()
        return error_msg, privileges
示例#4
0
def set_default_ds(tenant, default_datastore, check_existing):
    """
        Set "default_datastore" for given tenant and create a full access privilege
        to "default_datastore" if entry does not exist
        Need to check whether the default_datastore to be set is the same as exiting
        default_datastore when @Param check_existing is set to True
    """
    # @Param tenant is a DockerVolumeTenant object
    logging.debug(
        "set_default_ds: tenant_name=%s default_datastore=%s check_existing=%d",
        tenant.name, default_datastore, check_existing)

    error_info, auth_mgr = get_auth_mgr_object()
    if error_info:
        return error_info

    datastore_url = vmdk_utils.get_datastore_url(default_datastore)
    # datastore_url will be set to "None" by "vmdk_utils.get_datastore_url" is "default_datastore"
    # is not a valid datastore
    if datastore_url is None:
        error_info = generate_error_info(ErrorCode.DS_DEFAULT_NAME_INVALID,
                                         default_datastore)
        return error_info

    existing_default_ds_url = None
    if check_existing:
        error_msg, existing_default_ds_url = tenant.get_default_datastore(
            auth_mgr.conn)
        if error_msg:
            error_info = generate_error_info(ErrorCode.INTERNAL_ERROR,
                                             error_msg)
            return error_info

        # the "default_datastore" to be set is the same as existing "default_datastore" for this tenant
        if datastore_url == existing_default_ds_url:
            return None

    error_msg = tenant.set_default_datastore(auth_mgr.conn, datastore_url)
    if error_msg:
        error_info = generate_error_info(ErrorCode.INTERNAL_ERROR, error_msg)
        return error_info
    existing_default_ds = vmdk_utils.get_datastore_name(
        existing_default_ds_url
    ) if existing_default_ds_url is not None else None
    logging.info(
        "Existing default_datastore %s is being changed to %s for tenant %s",
        existing_default_ds, default_datastore, tenant)

    # create full access privilege to default_datastore
    error_info = _tenant_access_add(name=tenant.name,
                                    datastore=default_datastore,
                                    allow_create=True)
    # privilege to default_datastore already exist, no need to create
    if error_info and error_info.code == ErrorCode.PRIVILEGE_ALREADY_EXIST:
        logging.info(error_info.msg +
                     " not overwriting the existing access privilege")
        error_info = None

    return error_info
def _tenant_update(name,
                   new_name=None,
                   description=None,
                   default_datastore=None):
    """ API to update a tenant """
    error_info, tenant = get_tenant_from_db(name)
    if error_info:
        return error_info

    if not tenant:
        error_info = error_code.generate_error_info(ErrorCode.TENANT_NOT_EXIST,
                                                    name)
        return error_info

    error_info, auth_mgr = get_auth_mgr_object()

    if error_info:
        return error_info

    if new_name:
        # check whether tenant with new_name already exist or not
        error_msg, exist_tenant = auth_mgr.get_tenant(new_name)
        if error_msg:
            error_info = error_code.generate_error_info(
                ErrorCode.INTERNAL_ERROR, error_msg)
            return error_info

        if exist_tenant:
            error_info = error_code.generate_error_info(
                ErrorCode.TENANT_ALREADY_EXIST, name)
            return error_info

        if not is_tenant_name_valid(name):
            error_info = error_code.generate_error_info(
                ErrorCode.TENANT_NAME_INVALID, name, VALID_TENANT_NAME_REGEXP)
            return error_info, None

        error_msg = tenant.set_name(auth_mgr.conn, name, new_name)
        if error_msg:
            error_info = error_code.generate_error_info(
                ErrorCode.INTERNAL_ERROR, error_msg)
            return error_info
    if description:
        error_msg = tenant.set_description(auth_mgr.conn, description)
        if error_msg:
            error_info = error_code.generate_error_info(
                ErrorCode.INTERNAL_ERROR, error_msg)
            return error_info
    if default_datastore:
        datastore_url = vmdk_utils.get_datastore_url(default_datastore)
        error_msg = tenant.set_default_datastore(auth_mgr.conn, datastore_url)
        if error_msg:
            error_info = error_code.generate_error_info(
                ErrorCode.INTERNAL_ERROR, error_msg)
            return error_info

    return None
def _tenant_access_rm(name, datastore):
    """ API to remove datastore access for a tenant """
    logging.debug("_tenant_access_rm: name=%s datastore=%s", name, datastore)
    error_info, tenant = get_tenant_from_db(name)
    if error_info:
        return error_info

    if not tenant:
        error_info = error_code.generate_error_info(ErrorCode.TENANT_NOT_EXIST,
                                                    name)
        return error_info

    error_info = check_datastore(datastore)
    if error_info:
        return error_info

    error_info, existing_privileges = _tenant_access_ls(name)
    if error_info:
        return error_info

    if not privilege_exist(existing_privileges, datastore):
        error_info = error_code.generate_error_info(
            ErrorCode.PRIVILEGE_NOT_FOUND, name, datastore)
        return error_info

    error_info, auth_mgr = get_auth_mgr_object()

    if error_info:
        return error_info

    if datastore == auth.DEFAULT_DS:
        datastore_url = auth.DEFAULT_DS_URL
    else:
        datastore_url = vmdk_utils.get_datastore_url(datastore)
    logging.debug("_tenant_access_rm: datastore_url=%s", datastore_url)
    error_msg = tenant.remove_datastore_access_privileges(
        auth_mgr.conn, datastore_url)
    if error_msg:
        error_info = error_code.generate_error_info(ErrorCode.INTERNAL_ERROR,
                                                    error_msg)
        return error_info

    # get dafault_datastore, if default_datastore is the same as param "datastore"
    # need to set default_datastore_url to "" in tenants table
    error_info, default_datastore = get_default_datastore(name)
    if error_info:
        return error_info

    if default_datastore == datastore:
        error_msg = tenant.set_default_datastore(auth_mgr.conn, "")
        if error_msg:
            error_info = error_code.generate_error_info(
                ErrorCode.INTERNAL_ERROR, error_msg)

    return error_info
示例#7
0
def _tenant_access_rm(name, datastore):
    """ API to remove datastore access for a tenant """
    logging.debug("_tenant_access_rm: name=%s datastore=%s", name, datastore)
    error_info, tenant = get_tenant_from_db(name)
    if error_info:
        return error_info

    if not tenant:
        error_info = generate_error_info(ErrorCode.TENANT_NOT_EXIST, name)
        return error_info

    error_info = check_datastore(datastore)
    if error_info:
        return error_info

    datastore_url = vmdk_utils.get_datastore_url(datastore)

    error_info, existing_privileges = _tenant_access_ls(name)
    if error_info:
        return error_info

    if not privilege_exist(existing_privileges, datastore_url):
        error_info = generate_error_info(ErrorCode.PRIVILEGE_NOT_FOUND, name,
                                         datastore)
        return error_info

    error_info, auth_mgr = get_auth_mgr_object()
    if error_info:
        return error_info

    # get dafault_datastore for this tenant
    # if the default_datastore is equal to param "datastore", which means
    # we are trying to remove a row in "privilege" table with datastore which is
    # marked as default_datastore of this tenant, should return with error
    error_info, default_datastore_url = get_default_datastore_url(name)
    if error_info:
        return error_info

    if default_datastore_url == datastore_url:
        error_info = generate_error_info(
            ErrorCode.PRIVILEGE_REMOVE_NOT_ALLOWED)
        return error_info

    logging.debug("_tenant_access_rm: datastore_url=%s", datastore_url)
    error_msg = tenant.remove_datastore_access_privileges(
        auth_mgr.conn, datastore_url)
    if error_msg:
        error_info = generate_error_info(ErrorCode.INTERNAL_ERROR, error_msg)
        return error_info

    return None
示例#8
0
def remove_volume_from_volumes_table(tenant_uuid, datastore, vol_name):
    """
        Remove volume from volumes table.
        Return None on success or error string.
    """
    err_msg, _auth_mgr = get_auth_mgr()
    if err_msg:
        return err_msg

    logging.debug("remove volumes from volumes table(%s %s %s)", tenant_uuid, datastore,
                  vol_name)
    datastore_url = vmdk_utils.get_datastore_url(datastore)
    try:
        _auth_mgr.conn.execute(
                    "DELETE FROM volumes WHERE tenant_id = ? AND datastore_url = ? AND volume_name = ?",
                    [tenant_uuid, datastore_url, vol_name]
            )
        _auth_mgr.conn.commit()
    except sqlite3.Error as e:
        logging.error("Error %s when remove from volumes table for tenant_id %s and datastore %s",
                      e, tenant_uuid, datastore)
        return str(e)

    return None
示例#9
0
def add_volume_to_volumes_table(tenant_uuid, datastore, vol_name, vol_size_in_MB):
    """
        Insert volume to volumes table.
        Return None on success or error string.
    """
    err_msg, _auth_mgr = get_auth_mgr()
    if err_msg:
        return err_msg

    logging.debug("add to volumes table(%s %s %s %s)", tenant_uuid, datastore,
                  vol_name, vol_size_in_MB)
    datastore_url = vmdk_utils.get_datastore_url(datastore)
    try:
        _auth_mgr.conn.execute(
            "INSERT INTO volumes(tenant_id, datastore_url, volume_name, volume_size) VALUES (?, ?, ?, ?)",
            (tenant_uuid, datastore_url, vol_name, vol_size_in_MB)
            )
        _auth_mgr.conn.commit()
    except sqlite3.Error as e:
        logging.error("Error %s when insert into volumes table for tenant_id %s and datastore %s",
                      e, tenant_uuid, datastore)
        return str(e)

    return None
示例#10
0
def _tenant_access_add(name,
                       datastore,
                       allow_create=None,
                       volume_maxsize_in_MB=None,
                       volume_totalsize_in_MB=None):
    """ API to add datastore access for a tenant """

    logging.debug(
        "_tenant_access_add: name=%s datastore=%s, allow_create=%s "
        "volume_maxsize(MB)=%s volume_totalsize(MB)=%s", name, datastore,
        allow_create, volume_maxsize_in_MB, volume_totalsize_in_MB)

    error_info, tenant = get_tenant_from_db(name)
    if error_info:
        return error_info

    if not tenant:
        error_info = generate_error_info(ErrorCode.TENANT_NOT_EXIST, name)
        return error_info

    error_info = check_datastore(datastore)
    if error_info:
        return error_info

    error_info = check_usage_quota(datastore, volume_totalsize_in_MB)
    if error_info:
        return error_info

    datastore_url = vmdk_utils.get_datastore_url(datastore)

    error_info, existing_privileges = _tenant_access_ls(name)
    if error_info:
        return error_info

    if privilege_exist(existing_privileges, datastore_url):
        error_info = generate_error_info(ErrorCode.PRIVILEGE_ALREADY_EXIST,
                                         name, datastore)
        return error_info

    # Possible value:
    # None -  no change required
    # True/False (boolean or string) - change to corresponding True/False
    if allow_create is not None:
        # validate to boolean value if it is a string
        allow_create_val, valid = validate_string_to_bool(allow_create)

        if not valid:
            err_code = ErrorCode.PRIVILEGE_INVALID_ALLOW_CREATE_VALUE
            err_msg = error_code_to_message[err_code].format(allow_create)
            logging.error(err_msg)
            return ErrorInfo(err_code, err_msg)

        allow_create = allow_create_val

    privileges = generate_privileges(
        datastore_url=datastore_url,
        allow_create=allow_create,
        volume_maxsize_in_MB=volume_maxsize_in_MB,
        volume_totalsize_in_MB=volume_totalsize_in_MB)
    logging.debug("_tenant_access_add: privileges=%s", privileges)

    error_info = check_privilege_parameters(privilege=privileges)
    if error_info:
        return error_info

    error_info, auth_mgr = get_auth_mgr_object()
    if error_info:
        return error_info

    error_msg = tenant.set_datastore_access_privileges(auth_mgr.conn,
                                                       [privileges])
    if error_msg:
        error_info = generate_error_info(ErrorCode.INTERNAL_ERROR, error_msg)
        return error_info

    return error_info
示例#11
0
def _tenant_access_set(name,
                       datastore,
                       allow_create=None,
                       volume_maxsize_in_MB=None,
                       volume_totalsize_in_MB=None):
    """ API to modify datastore access for a tenant """
    logging.debug(
        "_tenant_access_set: name=%s datastore=%s, allow_create=%s "
        "volume_maxsize(MB)=%s volume_totalsize(MB)=%s", name, datastore,
        allow_create, volume_maxsize_in_MB, volume_totalsize_in_MB)

    error_info, tenant = get_tenant_from_db(name)
    if error_info:
        return error_info

    if not tenant:
        error_info = generate_error_info(ErrorCode.TENANT_NOT_EXIST, name)
        return error_info

    error_info = check_datastore(datastore)
    if error_info:
        return error_info

    error_info = check_usage_quota(datastore, volume_totalsize_in_MB)
    if error_info:
        return error_info

    datastore_url = vmdk_utils.get_datastore_url(datastore)

    error_info, existing_privileges = _tenant_access_ls(name)
    if error_info:
        return error_info

    if not privilege_exist(existing_privileges, datastore_url):
        error_info = generate_error_info(ErrorCode.PRIVILEGE_NOT_FOUND, name,
                                         datastore)
        return error_info

    logging.debug("_tenant_access_set: datastore_url=%s", datastore_url)
    privileges = [
        d for d in tenant.privileges if d.datastore_url == datastore_url
    ]

    if not privileges:
        err_code = ErrorCode.PRIVILEGE_NOT_FOUND
        err_msg = error_code_to_message[err_code].format(name, datastore)
        error_info = ErrorInfo(err_code, err_msg)
        return error_info

    if allow_create is not None:
        allow_create_val, valid = validate_string_to_bool(allow_create)

        if not valid:
            err_code = ErrorCode.PRIVILEGE_INVALID_ALLOW_CREATE_VALUE
            err_msg = error_code_to_message[err_code].format(allow_create)
            logging.error(err_msg)
            return ErrorInfo(err_code, err_msg)

        allow_create = allow_create_val

    privileges_dict = generate_privileges_dict(privileges[0])
    logging.debug("_tenant_access_set: originial privileges_dict=%s",
                  privileges_dict)
    privileges_dict = modify_privileges(
        privileges=privileges_dict,
        allow_create=allow_create,
        volume_maxsize_in_MB=volume_maxsize_in_MB,
        volume_totalsize_in_MB=volume_totalsize_in_MB)
    logging.debug("_tenant_access_set: modified privileges_dict=%s",
                  privileges_dict)

    error_info = check_privilege_parameters(privilege=privileges_dict)
    if error_info:
        return error_info

    error_info, auth_mgr = get_auth_mgr_object()

    if error_info:
        return error_info

    error_msg = tenant.set_datastore_access_privileges(auth_mgr.conn,
                                                       [privileges_dict])
    if error_msg:
        error_info = generate_error_info(ErrorCode.INTERNAL_ERROR, error_msg)
    return error_info
def _tenant_access_add(name, datastore, allow_create=None, default_datastore=False,
                       volume_maxsize_in_MB=None, volume_totalsize_in_MB=None):
    """ API to add datastore access for a tenant """

    logging.debug("_tenant_access_add: name=%s datastore=%s, allow_create=%s "
                  "volume_maxsize_in_MB=%s volume_totalsize_in_MB=%s", name, datastore, allow_create,
                  volume_maxsize_in_MB, volume_totalsize_in_MB)

    error_info, tenant = get_tenant_from_db(name)
    if error_info:
        return error_info

    if not tenant:
        error_info = error_code.generate_error_info(ErrorCode.TENANT_NOT_EXIST, name)
        return error_info

    error_info = check_datastore(datastore)
    if error_info:
        return error_info

    datastore_url = vmdk_utils.get_datastore_url(datastore)

    error_info, existing_privileges = _tenant_access_ls(name)
    if error_info:
        return error_info

    if privilege_exist(existing_privileges, datastore_url):
        error_info = error_code.generate_error_info(ErrorCode.PRIVILEGE_ALREADY_EXIST, name, datastore)
        return error_info

    # Possible value:
    # None -  no change required
    # True/False (boolean or string) - change to corresponding True/False
    if allow_create is not None:
        # validate to boolean value if it is a string
        allow_create_val, valid = validate_string_to_bool(allow_create)

        if not valid:
            err_code = ErrorCode.PRIVILEGE_INVALID_ALLOW_CREATE_VALUE
            err_msg = error_code.error_code_to_message[err_code].format(allow_create)
            logging.error(err_msg)
            return ErrorInfo(err_code, err_msg)

        allow_create = allow_create_val

    privileges = generate_privileges(datastore_url=datastore_url,
                                     allow_create=allow_create,
                                     volume_maxsize_in_MB=volume_maxsize_in_MB,
                                     volume_totalsize_in_MB=volume_totalsize_in_MB)
    logging.debug("_tenant_access_add: privileges=%s", privileges)

    error_info = check_privilege_parameters(privilege=privileges)
    if error_info:
        return error_info

    error_info, auth_mgr = get_auth_mgr_object()

    if error_info:
        return error_info

    error_msg = tenant.set_datastore_access_privileges(auth_mgr.conn, [privileges])
    if error_msg:
        error_info = error_code.generate_error_info(ErrorCode.INTERNAL_ERROR, error_msg)
        return error_info

    error_msg, result = auth.get_row_from_privileges_table(auth_mgr.conn, tenant.id)
    # if len(result) == 1, which means "datastore"" is the first datastore for this tenant,
    # and should set this datastore to the "default_datastore" for this tenant
    if error_msg:
        error_info = error_code.generate_error_info(ErrorCode.INTERNAL_ERROR, error_msg)
        return error_info
    logging.debug("_tenant_access_add: get_row_from_privileges_table for tenant id=%s return %s",
                  tenant.id, result)

    if len(result) == 1 or default_datastore:
        if datastore_url == auth_data_const.DEFAULT_DS_URL:
            # Create DEFAULT privilege for DEFAULT tenant, should not set the default_datastore in DB
            error_msg = tenant.set_default_datastore(auth_mgr.conn, "")
        else:
            error_msg = tenant.set_default_datastore(auth_mgr.conn, datastore_url)
        if error_msg:
            error_info = error_code.generate_error_info(ErrorCode.INTERNAL_ERROR, error_msg)

    return error_info
    def _remove_volumes_for_tenant(self, tenant_id):
        """ Delete all volumes belongs to this tenant.

            Do not use it outside of removing a tenant.

        """
        try:
            cur = self.conn.execute("SELECT name FROM tenants WHERE id = ?",
                                    (tenant_id, ))
            result = cur.fetchone()
        except sqlite3.Error as e:
            logging.error("Error %s when querying from tenants table", e)
            return str(e)

        error_msg = ""
        if result:
            logging.debug("remove_volumes_for_tenant: %s %s", tenant_id,
                          result)
            tenant_name = result[0]
            vmdks = vmdk_utils.get_volumes(tenant_name)
            # Delete all volumes for this tenant.
            dir_paths = set()
            for vmdk in vmdks:
                vmdk_path = os.path.join(vmdk['path'],
                                         "{0}".format(vmdk['filename']))
                dir_paths.add(vmdk['path'])
                logging.debug("path=%s filename=%s", vmdk['path'],
                              vmdk['filename'])
                logging.debug("Deleting volume path%s", vmdk_path)
                datastore_url = vmdk_utils.get_datastore_url(vmdk['datastore'])
                err = vmdk_ops.removeVMDK(
                    vmdk_path=vmdk_path,
                    vol_name=vmdk_utils.strip_vmdk_extension(vmdk['filename']),
                    vm_name=None,
                    tenant_uuid=tenant_id,
                    datastore_url=datastore_url)
                if err:
                    logging.error("remove vmdk %s failed with error %s",
                                  vmdk_path, err)
                    error_msg += str(err)

            VOL_RM_LOG_PREFIX = "Tenant <name> %s removal: "
            # delete the symlink /vmfs/volume/datastore_name/tenant_name
            # which point to /vmfs/volumes/datastore_name/tenant_uuid
            for (datastore, url, path) in vmdk_utils.get_datastores():
                dockvol_path, tenant_path = get_dockvol_path_tenant_path(
                    datastore_name=datastore, tenant_id=tenant_id)
                logging.debug(
                    VOL_RM_LOG_PREFIX + "try to remove symlink to %s",
                    tenant_name, tenant_path)

                if os.path.isdir(tenant_path):
                    exist_symlink_path = os.path.join(dockvol_path,
                                                      tenant_name)
                    if os.path.isdir(exist_symlink_path):
                        os.remove(exist_symlink_path)
                        logging.debug(
                            VOL_RM_LOG_PREFIX + "removing symlink %s",
                            tenant_name, exist_symlink_path)

            # Delete path /vmfs/volumes/datastore_name/tenant_uuid
            logging.debug("Deleting dir paths %s", dir_paths)
            for path in list(dir_paths):
                try:
                    os.rmdir(path)
                except os.error as e:
                    msg = "remove dir {0} failed with error {1}".format(
                        path, e)
                    logging.error(msg)
                    error_msg += str(err)

        err = self.remove_volumes_from_volumes_table(tenant_id)
        if err:
            logging.error("Failed to remove volumes from database %s", err)
            error_msg += str(err)

        if error_msg:
            return error_msg

        return None
示例#14
0
def _tenant_access_add(name,
                       datastore,
                       allow_create=None,
                       default_datastore=False,
                       volume_maxsize_in_MB=None,
                       volume_totalsize_in_MB=None):
    """ API to add datastore access for a tenant """

    logging.debug(
        "_tenant_access_add: name=%s datastore=%s, allow_create=%s "
        "volume_maxsize_in_MB=%s volume_totalsize_in_MB=%s", name, datastore,
        allow_create, volume_maxsize_in_MB, volume_totalsize_in_MB)

    error_info, tenant = get_tenant_from_db(name)
    if error_info:
        return error_info

    if not tenant:
        error_info = error_code.generate_error_info(ErrorCode.TENANT_NOT_EXIST,
                                                    name)
        return error_info

    error_info = check_datastore(datastore)
    if error_info:
        return error_info

    error_info, existing_privileges = _tenant_access_ls(name)
    if error_info:
        return error_info

    if privilege_exist(existing_privileges, datastore):
        error_info = error_code.generate_error_info(
            ErrorCode.PRIVILEGE_ALREADY_EXIST, name, datastore)
        return error_info

    privileges = generate_privileges(
        datastore=datastore,
        allow_create=allow_create,
        volume_maxsize_in_MB=volume_maxsize_in_MB,
        volume_totalsize_in_MB=volume_totalsize_in_MB)
    logging.debug("_tenant_access_add: privileges=%s", privileges)

    error_info = check_privilege_parameters(privilege=privileges)
    if error_info:
        return error_info

    error_info, auth_mgr = get_auth_mgr_object()

    if error_info:
        return error_info

    error_msg = tenant.set_datastore_access_privileges(auth_mgr.conn,
                                                       [privileges])
    if error_msg:
        error_info = error_code.generate_error_info(ErrorCode.INTERNAL_ERROR,
                                                    error_msg)
        return error_info

    error_msg, result = auth.get_row_from_privileges_table(
        auth_mgr.conn, tenant.id)
    # if len(result) == 1, which means "datastore"" is the first datastore for this tenant,
    # and should set this datastore to the "default_datastore" for this tenant
    if error_msg:
        error_info = error_code.generate_error_info(ErrorCode.INTERNAL_ERROR,
                                                    error_msg)
        return error_info
    logging.debug(
        "_tenant_access_add: get_row_from_privileges_table for tenant id=%s return %s",
        tenant.id, result)

    if len(result) == 1 or default_datastore:
        if datastore == auth.DEFAULT_DS:
            datastore_url = auth.DEFAULT_DS_URL
        else:
            datastore_url = vmdk_utils.get_datastore_url(datastore)
        error_msg = tenant.set_default_datastore(auth_mgr.conn, datastore_url)
        if error_msg:
            error_info = error_code.generate_error_info(
                ErrorCode.INTERNAL_ERROR, error_msg)

    return error_info