From f8e85e1a4c20666b00b3851e98935fdcd948a9ea Mon Sep 17 00:00:00 2001 From: waterWang Date: Tue, 25 Aug 2026 18:30:47 +0800 Subject: [PATCH] Fix SSVM entity download URL creation: ensure userdata base dir exists and is writable by www-data When handleCreateEntityURLCommand runs on the SSVM it builds the download URL by creating /var/www/html/userdata// as the www-data user (su www-data -c "mkdir -p ..."). On stock systemvm templates the /var/www/html/userdata base directory does not exist and /var/www/html is not writable by www-data, so the mkdir fails with "Permission denied" and getDiagnosticsData / extractVolume / extractTemplate async jobs error out with code 530 and no download URL is produced. Fix: create the base extract directory and set its ownership to www-data before dropping privileges to create the per-entity subdirectory. This makes the SSVM self-healing on first use and matches the directory layout expected by the Apache docroot. References #13959 --- .../storage/template/UploadManagerImpl.java | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/services/secondary-storage/server/src/main/java/org/apache/cloudstack/storage/template/UploadManagerImpl.java b/services/secondary-storage/server/src/main/java/org/apache/cloudstack/storage/template/UploadManagerImpl.java index 4ee6d28e3291..e74157f93aec 100644 --- a/services/secondary-storage/server/src/main/java/org/apache/cloudstack/storage/template/UploadManagerImpl.java +++ b/services/secondary-storage/server/src/main/java/org/apache/cloudstack/storage/template/UploadManagerImpl.java @@ -276,13 +276,24 @@ public CreateEntityDownloadURLAnswer handleCreateEntityURLCommand(CreateEntityDo // Create the directory structure so that its visible under apache server root String extractDir = BASE_EXTRACT_PATH; extractDir = extractDir + cmd.getFilepathInExtractURL() + File.separator; + // Ensure the base extract directory exists and is owned by www-data so that + // the www-data user can create the per-entity subdirectory inside it. + Script baseDirCommand = new Script("/bin/bash", logger); + baseDirCommand.add("-c"); + baseDirCommand.add("mkdir -p " + BASE_EXTRACT_PATH + " && chown www-data:www-data " + BASE_EXTRACT_PATH); + String result = baseDirCommand.execute(); + if (result != null) { + String errorString = "Error in creating base extract directory =" + result; + logger.error(errorString); + return new CreateEntityDownloadURLAnswer(errorString, CreateEntityDownloadURLAnswer.RESULT_FAILURE); + } Script command = new Script("/bin/su", logger); command.add("-s"); command.add("/bin/bash"); command.add("-c"); command.add("mkdir -p " + extractDir); command.add("www-data"); - String result = command.execute(); + result = command.execute(); if (result != null) { String errorString = "Error in creating directory =" + result; logger.error(errorString);