]> git.ipfire.org Git - thirdparty/open-vm-tools.git/commitdiff
Checking flag 'disable_vmware_customization' in more cloud-init config files
authorKaty Feng <fkaty@vmware.com>
Mon, 13 Nov 2023 20:07:33 +0000 (12:07 -0800)
committerKaty Feng <fkaty@vmware.com>
Mon, 13 Nov 2023 20:07:33 +0000 (12:07 -0800)
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

open-vm-tools/libDeployPkg/linuxDeployment.c
open-vm-tools/libDeployPkg/linuxDeploymentUtilities.c
open-vm-tools/libDeployPkg/linuxDeploymentUtilities.h

index 0faaaf8b842024c2ff5cedf8bc9b0178b1746f05..4ddf3477a5abb5d89f4773cbfc694c77ced3a6b6 100644 (file)
@@ -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;
index 8de2f7f00e427a6f6e533de573d3ff0e9d3bb3bc..61ccd54d33a736531ee9426cff219c4ca1d3a4b1 100644 (file)
@@ -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
 
 #include <dirent.h>
 #include <errno.h>
+#include <limits.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <regex.h>
 #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(&regex, cloudInitRegex, 0);
-   if (reti != 0) {
-      char buf[256];
-      regerror(reti, &regex, 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(&regex, 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(&regex);
 
-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(&regex, flagPattern, REG_EXTENDED);
+   if (reti != 0) {
+      char buf[256];
+      regerror(reti, &regex, 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(&regex, 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(&regex);
+
+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;
+}
index 80ab04ef0ffe01c75a376c6ae5df4373bdcac5ce..b461e4bcf962b59967f6738fe83161d4ba3a846e 100644 (file)
@@ -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);