Skip to content

fixing structured app discovery #1375

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jan 31, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 66 additions & 11 deletions core/src/main/java/oracle/weblogic/deploy/util/FileUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
Expand Down Expand Up @@ -637,6 +638,40 @@ public static PrintWriter getPrintWriter(String fileName) {
}
}

/**
* Set OS file permissions given an Octal permission set.
* Needed due to Jython 2.2 did not offer an os.chmod function.
* @param path file name to be changed
* @param octals octal number set like OS chmod permissions
* @throws IOException if permissions update fails
*/
public static void chmod(String path, int octals) throws IOException {
if(!WINDOWS) {
Files.setPosixFilePermissions(Paths.get(path), getPermissions(octals));
}
}

public static String getCommonRootDirectory(File firstDir, File secondDir) {
if (firstDir == null || secondDir == null) {
return null;
}

String[] firstDirComponents = getFileComponents(firstDir);
String[] secondDirComponents = getFileComponents(secondDir);
int maxLength = Math.min(firstDirComponents.length, secondDirComponents.length);

List<String> resultComponents = new ArrayList<>();
for (int i = 0; i < maxLength; i++) {
if (firstDirComponents[i].equals(secondDirComponents[i])) {
resultComponents.add(firstDirComponents[i]);
} else {
break;
}
}
File result = getFileFromComponents(resultComponents.toArray(new String[0]));
return result != null ? getCanonicalPath(result) : null;
}

///////////////////////////////////////////////////////////////////////////
// Private helper methods //
///////////////////////////////////////////////////////////////////////////
Expand Down Expand Up @@ -724,7 +759,6 @@ public boolean accept(File dir, String name) {
}
}


/**
* Convert an octal number into Posix File Permissions.
* @param octals 3 octal digits representing posix file permissions rwxrwxrwx
Expand Down Expand Up @@ -763,16 +797,37 @@ static Set<PosixFilePermission> getPermissions(int octals) {
return result;
}

/**
* Set OS file permissions given an Octal permission set.
* Needed due to Jython 2.2 did not offer a os.chmod function.
* @param path file name to be changed
* @param octals octal number set like OS chmod permissions
* @throws IOException if permissions update fails
*/
public static void chmod(String path, int octals) throws IOException {
if(!WINDOWS) {
Files.setPosixFilePermissions(Paths.get(path), getPermissions(octals));
private static String[] getFileComponents(File file) {
String[] result;
if (file != null) {
File canonicalFile = getCanonicalFile(file);
List<String> names = new ArrayList<>();
while(true) {
File parent = canonicalFile.getParentFile();
if (parent == null) {
names.add(canonicalFile.getPath());
break;
} else {
names.add(canonicalFile.getName());
canonicalFile = parent;
}
}
Collections.reverse(names);
result = names.toArray(new String[0]);
} else {
result = new String[0];
}
return result;
}

private static File getFileFromComponents(String[] components) {
File result = null;
if (components != null && components.length > 0) {
result = new File(components[0]);
for (int i = 1; i < components.length; i++) {
result = new File(result, components[i]);
}
}
return result;
}
}
116 changes: 50 additions & 66 deletions core/src/main/java/oracle/weblogic/deploy/util/WLSDeployArchive.java
Original file line number Diff line number Diff line change
Expand Up @@ -370,18 +370,6 @@ public static String getDomainBinScriptArchivePath(String domainBinPath) {
return getArchiveName(ARCHIVE_DOM_BIN_TARGET_DIR, domainBinPath);
}

/**
* Get the archive path for the application in a well-formed application directory
*
* @param appPath name of the application path
* @return archive path for use in the model
*/
public static String getApplicationDirectoryArchivePath(String appName, String appPath) {
File zipAppPath = new File(appPath).getParentFile();
File zipAppFile = new File(appPath);
return ARCHIVE_STRUCT_APPS_TARGET_DIR + "/" + appName + "/" + zipAppPath.getName() + "/" + zipAppFile.getName();
}

/**
* Get the archive path for the classpath library for use in the model.
*
Expand All @@ -403,15 +391,57 @@ public static String getApplicationPlanArchivePath(String planFile) {
}

/**
* Get the archive path of a well-formed plan directory in app directory,
* Convert the provided structured application's application installation directory into the
* proper archive path.
*
* @param appName The application name of the app directory
* @param planDir The deployment plan file directory
* @return Archive path for use in the model
* @param installRoot the full path to the structured application install directory on the file system
* @return the converted application installation directory or null if there is no parent directory
*/
public static String getStructuredApplicationArchivePath(String installRoot) {
final String METHOD = "getStructuredApplicationArchivePath";
LOGGER.entering(CLASS, METHOD, installRoot);

String installRootDir = FileUtils.getCanonicalPath(installRoot);
String installParentDir = new File(installRootDir).getParent();
String result = null;
if (!StringUtils.isEmpty(installParentDir)) {
result = installRootDir.replace(installParentDir, ARCHIVE_STRUCT_APPS_TARGET_DIR);
}

LOGGER.exiting(CLASS, METHOD, result);
return result;
}

/**
* Convert the provided fileName into the proper archive path based on the application
* installation directory of the structured application.
*
* @param originalInstallRoot the full path to the structured application install directory on the file system
* @param newInstallRoot the path to the structured application install directory in the archive file
* @param fileName the file name to convert
* @return the converted file name if the fileName starts with the installRoot; if not, the original file name
*/
public static String getApplicationPlanDirArchivePath(String appName, String planDir) {
File zipPath = new File(planDir);
return ARCHIVE_STRUCT_APPS_TARGET_DIR + "/" + appName + "/" + zipPath.getName();
public static String getStructuredApplicationArchivePath(String originalInstallRoot, String newInstallRoot,
String fileName) {
final String METHOD = "getStructuredApplicationArchivePath";
LOGGER.entering(CLASS, METHOD, originalInstallRoot, newInstallRoot, fileName);

String result = fileName;
File file = new File(fileName);
if (file.isAbsolute() && fileName.startsWith(originalInstallRoot) && !StringUtils.isEmpty(newInstallRoot)) {
String originalRoot = originalInstallRoot;
if (originalInstallRoot.endsWith(File.separator) || originalInstallRoot.endsWith(ZIP_SEP)) {
originalRoot = originalInstallRoot.substring(0, originalInstallRoot.length() - 1);
}
String newRoot = newInstallRoot;
if (newInstallRoot.endsWith(File.separator) || newInstallRoot.endsWith(ZIP_SEP)) {
newRoot = newInstallRoot.substring(0, newInstallRoot.length() - 1);
}
result = fileName.replace(originalRoot, newRoot);
}

LOGGER.exiting(CLASS, METHOD, result);
return result;
}

/**
Expand Down Expand Up @@ -1216,13 +1246,11 @@ public int removeApplicationDeploymentPlan(String planPath, boolean silent) thro
* @throws IllegalArgumentException if the directory passed or its app subdirectory does not exist
*/
public String addStructuredApplication(String installRoot) throws WLSDeployArchiveIOException {
final String METHOD = "addApplicationFolder";
final String METHOD = "addStructuredApplication";
LOGGER.entering(CLASS, METHOD, installRoot);

File filePath = FileUtils.getCanonicalFile(installRoot);
File appDir = new File(filePath, "app");
validateExistingDirectory(filePath, "installRoot", getArchiveFileName(), METHOD);
validateExistingDirectory(appDir, "appDir", getArchiveFileName(), METHOD);

String newName = addItemToZip(ARCHIVE_STRUCT_APPS_TARGET_DIR, filePath);
LOGGER.exiting(CLASS, METHOD, newName);
Expand Down Expand Up @@ -1291,36 +1319,6 @@ public void extractStructuredApplication(String appPath, File domainHome) throws
LOGGER.exiting(CLASS, METHOD);
}

// TODO - Need to verify that discovery produces an archive that is consistent with the add/replace methods above.
// Once verified, change method name to be consistent and add javadoc.
public String addApplicationFolder(String appName, String appPath)
throws WLSDeployArchiveIOException {
final String METHOD = "addApplicationFolder";
LOGGER.entering(CLASS, METHOD, appName, appPath);
File zipPath = new File(appPath);
if (zipPath.getParentFile() != null) {
zipPath = zipPath.getParentFile();
}
String firstPrefix = ARCHIVE_STRUCT_APPS_TARGET_DIR + ZIP_SEP + appName + ZIP_SEP + zipPath.getName();
String newName = walkDownFolders(firstPrefix, zipPath);
LOGGER.exiting(CLASS, METHOD, newName);
return newName;
}

// TODO - Need to verify that discovery produces an archive that is consistent with the add/replace methods above.
// Once verified, change method name to be consistent and add javadoc.
public String addApplicationPlanFolder(String appName, String planDir)
throws WLSDeployArchiveIOException {
final String METHOD = "addApplicationPathFolder";
LOGGER.entering(CLASS, METHOD, appName, planDir);
File zipPlan = new File(planDir);
String zipPrefix = ARCHIVE_STRUCT_APPS_TARGET_DIR + ZIP_SEP + appName + ZIP_SEP + zipPlan.getName();
String newName = walkDownFolders(zipPrefix, zipPlan);

LOGGER.exiting(CLASS, METHOD, newName);
return zipPrefix;
}

/**
* Remove the named structured application from the archive file. If this is the only entry
* in the archive file directory, the directory entry will also be removed, if present.
Expand Down Expand Up @@ -4785,20 +4783,6 @@ private boolean filterEntry(String entry, String prefix, String name, FileOrDire
return result;
}

// TODO - remove me and replace calls with addItemToZip() to get the correct behavior.
private String walkDownFolders(String zipPrefix, File zipPath) throws WLSDeployArchiveIOException {
String newSourceName = null;
if (zipPath != null) {
File[] fileList = zipPath.listFiles();
if (fileList != null) {
for (File item : fileList) {
newSourceName = addItemToZip(zipPrefix, item);
}
}
}
return newSourceName;
}

private void checkForZipSlip(File extractLocation, String zipEntry) throws WLSDeployArchiveIOException {
String canonicalExtractLocation = FileUtils.getCanonicalPath(extractLocation);
String canonicalZipEntry = FileUtils.getCanonicalPath(new File(extractLocation, zipEntry));
Expand Down
6 changes: 4 additions & 2 deletions core/src/main/python/wlsdeploy/aliases/aliases.py
Original file line number Diff line number Diff line change
Expand Up @@ -1000,10 +1000,11 @@ def is_model_password_attribute(self, location, model_name):
self._raise_exception(ae, _method_name, 'WLSDPLY-19040', model_name, location.get_folder_path(),
ae.getLocalizedMessage())

def get_model_uses_path_tokens_attribute_names(self, location):
def get_model_uses_path_tokens_attribute_names(self, location, only_readable=False):
"""
Get the list of attribute names that "use path tokens" (i.e., ones whose values are file system paths).
:param location: the location
:param only_readable: If true, filter out all attributes that cannot be read (i.e., IGNORED)
:return: a list of the model attribute names
:raises: Tool type exception: if an error occurs
"""
Expand All @@ -1020,7 +1021,8 @@ def get_model_uses_path_tokens_attribute_names(self, location):

for key, value in module_folder[ATTRIBUTES].iteritems():
if USES_PATH_TOKENS in value and alias_utils.convert_boolean(value[USES_PATH_TOKENS]):
model_attribute_names.append(key)
if not (only_readable and ACCESS in value and value[ACCESS] == IGNORED):
model_attribute_names.append(key)

return model_attribute_names
except AliasException, ae:
Expand Down
Loading