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
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
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
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
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
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
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
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
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
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