From: Katy Feng Date: Mon, 13 Nov 2023 20:07:33 +0000 (-0800) Subject: Checking flag 'disable_vmware_customization' in more cloud-init config files X-Git-Tag: stable-12.4.0~68 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=92cc832c4493c272cb9227a87f68a9ae0cf18fec;p=thirdparty%2Fopen-vm-tools.git Checking flag 'disable_vmware_customization' in more cloud-init config files Currently, the deployPkg plugin checks the existence of the flag 'disable_vmware_customization: false' in the /etc/cloud/cloud.cfg file to determine whether VMware customization is enabled on cloud-init side when cloud-init is available in guest. Instead, keep local settings, such as this flag, in config files under the /etc/cloud/cloud.cfg.d directory, for example: /etc/cloud/cloud.cfg.d/somefile.cfg This change implements the following adjustments to make sure this flag is handled the same way as cloud-init does in ds-identify and Datasource: 1. Instead of regex matching flag 'disable_vmware_customization: false', check the value of flag 'disable_vmware_customization': If the value is 'false', it means VMware customization is enabled. If the value is 'true', it means VMware customization is disabled. If the flag is not set, by default VMware customization is disabled on cloud-init side. 2. Besides cloud-init /etc/cloud/cloud.cfg file, also check all .cfg files under /etc/cloud/cloud.cfg.d directory. 3. The value of flag 'disable_vmware_customization' in .cfg files under /etc/cloud/cloud.cfg.d directory will overwrite the one in the /etc/cloud/cloud.cfg file. 4. The value of flag 'disable_vmware_customization' in a .cfg file listed further down in alphabetical order under the /etc/cloud/cloud.cfg.d directory will overwrite the value in a .cfg file listed earier. 5. If a cloud-init config file contains more than one instance of this flag, the value of the later flag will overwrite the former one. Github Issue: https://github.com/vmware/open-vm-tools/issues/310 --- diff --git a/open-vm-tools/libDeployPkg/linuxDeployment.c b/open-vm-tools/libDeployPkg/linuxDeployment.c index 0faaaf8b8..4ddf3477a 100644 --- a/open-vm-tools/libDeployPkg/linuxDeployment.c +++ b/open-vm-tools/libDeployPkg/linuxDeployment.c @@ -1,5 +1,5 @@ /********************************************************* - * Copyright (c) 2006-2022 VMware, Inc. All rights reserved. + * Copyright (c) 2006-2023 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published @@ -1236,7 +1236,6 @@ UseCloudInitWorkflow(const char* dirPath, bool ignoreCloudInit) { static const char cfgName[] = "cust.cfg"; static const char metadataName[] = "metadata"; - static const char cloudInitConfigFilePath[] = "/etc/cloud/cloud.cfg"; static const char cloudInitCommand[] = "/usr/bin/cloud-init -v"; char cloudInitCommandOutput[MAX_LENGTH_CLOUDINIT_VERSION]; int forkExecResult; @@ -1288,7 +1287,7 @@ UseCloudInitWorkflow(const char* dirPath, bool ignoreCloudInit) return USE_CLOUDINIT_OK; } } else { - if (IsCloudInitEnabled(cloudInitConfigFilePath)) { + if (IsCloudInitCustomizationEnabled()) { return USE_CLOUDINIT_OK; } else { return USE_CLOUDINIT_DISABLED; diff --git a/open-vm-tools/libDeployPkg/linuxDeploymentUtilities.c b/open-vm-tools/libDeployPkg/linuxDeploymentUtilities.c index 8de2f7f00..61ccd54d3 100644 --- a/open-vm-tools/libDeployPkg/linuxDeploymentUtilities.c +++ b/open-vm-tools/libDeployPkg/linuxDeploymentUtilities.c @@ -1,5 +1,5 @@ /********************************************************* - * Copyright (C) 2016-2019 VMware, Inc. All rights reserved. + * Copyright (c) 2016-2019, 2023 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published @@ -18,70 +18,99 @@ #include #include +#include #include #include #include #include #include "linuxDeploymentUtilities.h" +#include "str.h" extern LogFunction sLog; +// The status code of flag 'disable_vmware_customization' +typedef enum DISABLE_VMWARE_CUSTIOMIZATION_FLAG_STATUS_CODE { + DISABLE_VMWARE_CUSTOMIZATION_FLAG_UNSET = 0, + DISABLE_VMWARE_CUSTOMIZATION_FLAG_SET_TRUE, + DISABLE_VMWARE_CUSTOMIZATION_FLAG_SET_FALSE, +} DISABLE_VMWARE_CUSTIOMIZATION_FLAG_STATUS_CODE; + +// Private functions +static DISABLE_VMWARE_CUSTIOMIZATION_FLAG_STATUS_CODE +GetDisableVMwareCustomizationFlagStatus(const char* cloudInitConfigFilePath); +static int +FilterCfgExt(const struct dirent *dir); + /** *---------------------------------------------------------------------------- * - * IsCloudInitEnabled + * IsCloudInitCustomizationEnabled * - * Function to determine if cloud-init is enabled. + * Function to determine if cloud-init customization workflow is enabled. * Essentially it does - * - read a cloud-init config file - * - Find if a particular flag is enabled or disabled. + * - Read all cloud-init configuration files under /etc/cloud/cloud.cfg.d/ + * - Read the cloud-init configuration file /etc/cloud/cloud.cfg + * - Find if a particular flag is enabled or disabled + * - Particularly, the value of flag in files under /etc/cloud/cloud.cfg.d/ + * has higher priority than the one in file /etc/cloud/cloud.cfg, and the + * value of flag in file listed behind in alphabetical sort under + * /etc/cloud/cloud.cfg.d/ has higher priority than the one in file listed + * in front * - * @param [IN] cloudFilePath path of the cloud-init config file - * @returns TRUE if disable_vmware_customization is false and FALSE otherwise. + * @returns TRUE if value of the flag 'disable_vmware_customization' is false + * FALSE otherwise * *---------------------------------------------------------------------------- **/ bool -IsCloudInitEnabled(const char *cloudFilePath) +IsCloudInitCustomizationEnabled() { - bool isEnabled = false; - FILE *cloudFile; - char line[256]; - regex_t regex; - const char *cloudInitRegex = - "^\\s*disable_vmware_customization\\s*:\\s*false\\s*$"; - int reti; + DISABLE_VMWARE_CUSTIOMIZATION_FLAG_STATUS_CODE flagStatus = + DISABLE_VMWARE_CUSTOMIZATION_FLAG_UNSET; + static const char cloudInitBaseConfigFilePath[] = "/etc/cloud/cloud.cfg"; + static const char cloudInitConfigDirPath[] = "/etc/cloud/cloud.cfg.d/"; + struct dirent **fileList; + int i, fileCount; + size_t filePathLength; + char *filePath = NULL; - sLog(log_info, "Checking if cloud.cfg exists and if cloud-init is enabled."); - cloudFile = fopen(cloudFilePath, "r"); - if (cloudFile == NULL) { - sLog(log_info, "Could not open file: %s", strerror(errno)); - return isEnabled; - } - - reti = regcomp(®ex, cloudInitRegex, 0); - if (reti != 0) { - char buf[256]; - regerror(reti, ®ex, buf, sizeof(buf)); - sLog(log_error, "Error compiling regex for cloud-init flag: %s", buf); - goto done; - } - - while (fgets(line, sizeof(line), cloudFile) != NULL) { - if (regexec(®ex, line, 0, NULL, 0) == 0) { - isEnabled = true; - break; + sLog(log_info, "Checking if cloud-init customization is enabled."); + fileCount = + scandir(cloudInitConfigDirPath, &fileList, FilterCfgExt, alphasort); + if (fileCount < 0) { + sLog(log_warning, "Could not scan directory %s, error: %s.", + cloudInitConfigDirPath, strerror(errno)); + } else { + for (i = fileCount - 1; i >= 0; i--) { + filePathLength = Str_Strlen(cloudInitConfigDirPath, PATH_MAX) + + Str_Strlen(fileList[i]->d_name, FILENAME_MAX) + 1; + filePath = malloc(filePathLength); + if (filePath == NULL) { + sLog(log_warning, "Error allocating memory to copy '%s'.", + cloudInitConfigDirPath); + break; + } + Str_Strcpy(filePath, cloudInitConfigDirPath, filePathLength); + Str_Strcat(filePath, fileList[i]->d_name, filePathLength); + flagStatus = GetDisableVMwareCustomizationFlagStatus(filePath); + free(filePath); + filePath = NULL; + if (flagStatus != DISABLE_VMWARE_CUSTOMIZATION_FLAG_UNSET) { + break; + } + } + for (i = 0; i < fileCount; i++) { + free(fileList[i]); } } - if (ferror(cloudFile) != 0) { - sLog(log_warning, "Error reading file: %s", strerror(errno)); - isEnabled = false; + free(fileList); + + if (flagStatus == DISABLE_VMWARE_CUSTOMIZATION_FLAG_UNSET) { + flagStatus = + GetDisableVMwareCustomizationFlagStatus(cloudInitBaseConfigFilePath); } - regfree(®ex); -done: - fclose(cloudFile); - return isEnabled; + return (flagStatus == DISABLE_VMWARE_CUSTOMIZATION_FLAG_SET_FALSE); } /** @@ -113,7 +142,7 @@ GetCustomScript(const char* dirPath) sLog(log_info, "Check if custom script(pre/post customization) exists."); tempDir = opendir(dirPath); if (tempDir == NULL) { - sLog(log_warning, "Could not open directory %s: error: %s", dirPath, + sLog(log_warning, "Could not open directory %s: error: %s.", dirPath, strerror(errno)); return scriptName; } @@ -123,7 +152,7 @@ GetCustomScript(const char* dirPath) char buf[256]; regerror(regRet, &scriptRegex, buf, sizeof(buf)); - sLog(log_error, "Error compiling regex for custom script: %s", buf); + sLog(log_error, "Error compiling regex for custom script: %s.", buf); goto done; } @@ -131,7 +160,7 @@ GetCustomScript(const char* dirPath) if (regexec(&scriptRegex, dir->d_name, 0, NULL, 0) == 0) { scriptName = strdup(dir->d_name); if (scriptName == NULL) { - sLog(log_warning, "Could not allocate memory for scriptName: %s", + sLog(log_warning, "Could not allocate memory for scriptName: %s.", strerror(errno)); break; } @@ -145,3 +174,106 @@ done: return scriptName; } +/** + *---------------------------------------------------------------------------- + * + * GetDisableVMwareCustomizationFlagStatus + * + * Function to get status code of the flag 'disable_vmware_customization' from + * a cloud-init config file. + * Essentially it does + * - Read a cloud-init config file + * - Get status code of the flag according to its value + * + * @param [IN] cloudInitConfigFilePath path of a cloud-int config file + * @returns The status code of this particular flag + * + *---------------------------------------------------------------------------- + **/ +static DISABLE_VMWARE_CUSTIOMIZATION_FLAG_STATUS_CODE +GetDisableVMwareCustomizationFlagStatus(const char* cloudInitConfigFilePath) +{ + DISABLE_VMWARE_CUSTIOMIZATION_FLAG_STATUS_CODE flagStatus = + DISABLE_VMWARE_CUSTOMIZATION_FLAG_UNSET; + FILE *cloudInitConfigFile; + char line[256]; + regex_t regex; + size_t maxGroups = 2, flagValueLength = 0; + regmatch_t groupArray[maxGroups]; + const char *flagPattern = + "^\\s*disable_vmware_customization\\s*:\\s*(true|false)\\s*$"; + int reti; + + cloudInitConfigFile = fopen(cloudInitConfigFilePath, "r"); + if (cloudInitConfigFile == NULL) { + sLog(log_warning, "Could not open file: %s.", strerror(errno)); + return flagStatus; + } + + reti = regcomp(®ex, flagPattern, REG_EXTENDED); + if (reti != 0) { + char buf[256]; + regerror(reti, ®ex, buf, sizeof(buf)); + sLog(log_error, "Error compiling regex for cloud-init flag: %s.", buf); + goto done; + } + + while (fgets(line, sizeof(line), cloudInitConfigFile) != NULL) { + if (regexec(®ex, line, maxGroups, groupArray, 0) == 0) { + flagValueLength = groupArray[1].rm_eo - groupArray[1].rm_so; + if (flagValueLength > 0) { + char flagValue[flagValueLength + 1]; + Str_Strncpy(flagValue, flagValueLength + 1, + line + groupArray[1].rm_so, flagValueLength); + sLog(log_info, + "Flag 'disable_vmware_customization' set in %s with value: %s.", + cloudInitConfigFilePath, flagValue); + if (Str_Strequal(flagValue, "false")) { + flagStatus = DISABLE_VMWARE_CUSTOMIZATION_FLAG_SET_FALSE; + } else if (Str_Strequal(flagValue, "true")) { + flagStatus = DISABLE_VMWARE_CUSTOMIZATION_FLAG_SET_TRUE; + } + } + } + } + if (ferror(cloudInitConfigFile) != 0) { + sLog(log_warning, "Error reading file: %s.", strerror(errno)); + flagStatus = DISABLE_VMWARE_CUSTOMIZATION_FLAG_UNSET; + } + regfree(®ex); + +done: + fclose(cloudInitConfigFile); + return flagStatus; +} + +/** + *----------------------------------------------------------------------------- + * + * FilterCfgExt + * + * Filter files with .cfg extension when calling scandir. + * + * @param [IN] dir struct dirent of a directory entry + * @returns 1 if dir is a regular file and its file extension is .cfg + * 0 otherwise + * + * ---------------------------------------------------------------------------- + **/ +static int +FilterCfgExt(const struct dirent *dir) +{ + if (!dir) + return 0; + + if (dir->d_type == DT_REG) { + const char *ext = Str_Strrchr(dir->d_name, '.'); + if ((!ext) || (ext == dir->d_name)) { + return 0; + } else if (Str_Strequal(ext, ".cfg")) { + return 1; + } + } + + return 0; +} diff --git a/open-vm-tools/libDeployPkg/linuxDeploymentUtilities.h b/open-vm-tools/libDeployPkg/linuxDeploymentUtilities.h index 80ab04ef0..b461e4bcf 100644 --- a/open-vm-tools/libDeployPkg/linuxDeploymentUtilities.h +++ b/open-vm-tools/libDeployPkg/linuxDeploymentUtilities.h @@ -1,5 +1,5 @@ /********************************************************* - * Copyright (C) 2016-2019 VMware, Inc. All rights reserved. + * Copyright (c) 2016-2019, 2023 VMware, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published @@ -24,7 +24,7 @@ #include "imgcust-common/imgcust-api.h" IMGCUST_API bool -IsCloudInitEnabled(const char* configFile); +IsCloudInitCustomizationEnabled(); IMGCUST_API char * GetCustomScript(const char* dirPath);