[libvirt] ESX [01/12]: Add esxNodeGetFreeMemory()

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



* src/esx/esx_driver.c: add esxNodeGetFreeMemory(), cache IP address
* src/esx/esx_vi.[ch]: refactor resource pool query into esxVI_GetResourcePool()
* src/esx/esx_vi_types.[ch]: bind VI type ResourcePoolResourceUsage
diff --git a/src/esx/esx_driver.c b/src/esx/esx_driver.c
index 8d1af71..fb4edbc 100644
--- a/src/esx/esx_driver.c
+++ b/src/esx/esx_driver.c
@@ -139,7 +139,8 @@ static virDrvOpenStatus
 esxOpen(virConnectPtr conn, virConnectAuthPtr auth, int flags ATTRIBUTE_UNUSED)
 {
     esxPrivate *priv = NULL;
-    char ipAddress[NI_MAXHOST] = "";
+    char hostIpAddress[NI_MAXHOST] = "";
+    char vCenterIpAddress[NI_MAXHOST] = "";
     char *url = NULL;
     char *vCenter = NULL;
     int noVerify = 0; // boolean
@@ -189,13 +190,13 @@ esxOpen(virConnectPtr conn, virConnectAuthPtr auth, int flags ATTRIBUTE_UNUSED)
             goto failure;
         }
 
-        if (esxUtil_ResolveHostname(conn, conn->uri->server, ipAddress,
+        if (esxUtil_ResolveHostname(conn, conn->uri->server, hostIpAddress,
                                     NI_MAXHOST) < 0) {
             goto failure;
         }
 
         if (vCenter != NULL &&
-            esxUtil_ResolveHostname(conn, vCenter, ipAddress,
+            esxUtil_ResolveHostname(conn, vCenter, vCenterIpAddress,
                                     NI_MAXHOST) < 0) {
             goto failure;
         }
@@ -256,8 +257,8 @@ esxOpen(virConnectPtr conn, virConnectAuthPtr auth, int flags ATTRIBUTE_UNUSED)
             goto failure;
         }
 
-        if (esxVI_Context_Connect(conn, priv->host, url, username,
-                                  password, noVerify) < 0) {
+        if (esxVI_Context_Connect(conn, priv->host, url, hostIpAddress,
+                                  username, password, noVerify) < 0) {
             goto failure;
         }
 
@@ -309,8 +310,9 @@ esxOpen(virConnectPtr conn, virConnectAuthPtr auth, int flags ATTRIBUTE_UNUSED)
                 goto failure;
             }
 
-            if (esxVI_Context_Connect(conn, priv->vCenter, url, username,
-                                      password, noVerify) < 0) {
+            if (esxVI_Context_Connect(conn, priv->vCenter, url,
+                                      vCenterIpAddress, username, password,
+                                      noVerify) < 0) {
                 goto failure;
             }
 
@@ -2827,9 +2829,6 @@ esxDomainMigratePerform(virDomainPtr domain,
     esxVI_ObjectContent *virtualMachine = NULL;
     esxVI_String *propertyNameList = NULL;
     esxVI_ObjectContent *hostSystem = NULL;
-    esxVI_DynamicProperty *dynamicProperty = NULL;
-    esxVI_ManagedObjectReference *managedObjectReference = NULL;
-    esxVI_ObjectContent *computeResource = NULL;
     esxVI_ManagedObjectReference *resourcePool = NULL;
     esxVI_Event *eventList = NULL;
     esxVI_ManagedObjectReference *task = NULL;
@@ -2879,69 +2878,13 @@ esxDomainMigratePerform(virDomainPtr domain,
 
     if (esxVI_String_AppendValueToList(domain->conn, &propertyNameList,
                                        "parent") < 0 ||
-        esxVI_LookupHostSystemByIp(domain->conn, priv->vCenter,
-                                   hostIpAddress, propertyNameList,
-                                   &hostSystem) < 0) {
+        esxVI_LookupHostSystemByIp(domain->conn, priv->vCenter, hostIpAddress,
+                                   propertyNameList, &hostSystem) < 0) {
         goto failure;
     }
 
-    for (dynamicProperty = hostSystem->propSet; dynamicProperty != NULL;
-         dynamicProperty = dynamicProperty->_next) {
-        if (STREQ(dynamicProperty->name, "parent")) {
-            if (esxVI_ManagedObjectReference_CastFromAnyType
-                  (domain->conn, dynamicProperty->val, &managedObjectReference,
-                   "ComputeResource") < 0) {
-                goto failure;
-            }
-
-            break;
-        } else {
-            VIR_WARN("Unexpected '%s' property", dynamicProperty->name);
-        }
-    }
-
-    if (managedObjectReference == NULL) {
-        ESX_ERROR(domain->conn, VIR_ERR_INTERNAL_ERROR,
-                  "Could not retrieve compute resource of host system");
-        goto failure;
-    }
-
-    esxVI_String_Free(&propertyNameList);
-
-    if (esxVI_String_AppendValueToList(domain->conn, &propertyNameList,
-                                       "resourcePool") < 0 ||
-        esxVI_GetObjectContent(domain->conn, priv->vCenter,
-                               managedObjectReference, "ComputeResource",
-                               propertyNameList, esxVI_Boolean_False,
-                               &computeResource) < 0) {
-        goto failure;
-    }
-
-    if (computeResource == NULL) {
-        ESX_ERROR(domain->conn, VIR_ERR_INTERNAL_ERROR,
-                  "Could not retrieve compute resource of host system");
-        goto failure;
-    }
-
-    for (dynamicProperty = computeResource->propSet; dynamicProperty != NULL;
-         dynamicProperty = dynamicProperty->_next) {
-        if (STREQ(dynamicProperty->name, "resourcePool")) {
-            if (esxVI_ManagedObjectReference_CastFromAnyType
-                  (domain->conn, dynamicProperty->val, &resourcePool,
-                   "ResourcePool") < 0) {
-                goto failure;
-            }
-
-            break;
-        } else {
-            VIR_WARN("Unexpected '%s' property", dynamicProperty->name);
-        }
-    }
-
-    if (resourcePool == NULL) {
-        ESX_ERROR(domain->conn, VIR_ERR_INTERNAL_ERROR,
-                  "Could not retrieve resource pool of compute resource of "
-                  "host system");
+    if (esxVI_GetResourcePool(domain->conn, priv->vCenter, hostSystem,
+                              &resourcePool) < 0) {
         goto failure;
     }
 
@@ -2992,8 +2935,6 @@ esxDomainMigratePerform(virDomainPtr domain,
     esxVI_ObjectContent_Free(&virtualMachine);
     esxVI_String_Free(&propertyNameList);
     esxVI_ObjectContent_Free(&hostSystem);
-    esxVI_ManagedObjectReference_Free(&managedObjectReference);
-    esxVI_ObjectContent_Free(&computeResource);
     esxVI_ManagedObjectReference_Free(&resourcePool);
     esxVI_Event_Free(&eventList);
     esxVI_ManagedObjectReference_Free(&task);
@@ -3020,6 +2961,91 @@ esxDomainMigrateFinish(virConnectPtr dconn, const char *dname,
 
 
 
+static unsigned long long
+esxNodeGetFreeMemory(virConnectPtr conn)
+{
+    unsigned long long result = 0;
+    esxPrivate *priv = (esxPrivate *)conn->privateData;
+    esxVI_String *propertyNameList = NULL;
+    esxVI_ObjectContent *hostSystem = NULL;
+    esxVI_ManagedObjectReference *managedObjectReference = NULL;
+    esxVI_ObjectContent *resourcePool = NULL;
+    esxVI_DynamicProperty *dynamicProperty = NULL;
+    esxVI_ResourcePoolResourceUsage *resourcePoolResourceUsage = NULL;
+
+    if (priv->phantom) {
+        ESX_ERROR(conn, VIR_ERR_OPERATION_INVALID,
+                  "Not possible with a phantom connection");
+        goto failure;
+    }
+
+    if (esxVI_EnsureSession(conn, priv->host) < 0) {
+        goto failure;
+    }
+
+    /* Lookup host system with its resource pool */
+    if (esxVI_String_AppendValueToList(conn, &propertyNameList, "parent") < 0 ||
+        esxVI_LookupHostSystemByIp(conn, priv->host, priv->host->ipAddress,
+                                   propertyNameList, &hostSystem) < 0) {
+        goto failure;
+    }
+
+    if (esxVI_GetResourcePool(conn, priv->host, hostSystem,
+                              &managedObjectReference) < 0) {
+        goto failure;
+    }
+
+    esxVI_String_Free(&propertyNameList);
+
+    /* Get memory usage of resource pool */
+    if (esxVI_String_AppendValueToList(conn, &propertyNameList,
+                                       "runtime.memory") < 0 ||
+        esxVI_GetObjectContent(conn, priv->host, managedObjectReference,
+                               "ResourcePool", propertyNameList,
+                               esxVI_Boolean_False, &resourcePool) < 0) {
+        goto failure;
+    }
+
+    for (dynamicProperty = resourcePool->propSet; dynamicProperty != NULL;
+         dynamicProperty = dynamicProperty->_next) {
+        if (STREQ(dynamicProperty->name, "runtime.memory")) {
+            if (esxVI_ResourcePoolResourceUsage_CastFromAnyType
+                  (conn, dynamicProperty->val,
+                   &resourcePoolResourceUsage) < 0) {
+                goto failure;
+            }
+
+            break;
+        } else {
+            VIR_WARN("Unexpected '%s' property", dynamicProperty->name);
+        }
+    }
+
+    if (resourcePoolResourceUsage == NULL) {
+        ESX_ERROR(conn, VIR_ERR_INTERNAL_ERROR,
+                  "Could not retrieve memory usage of resource pool");
+        goto failure;
+    }
+
+    result = resourcePoolResourceUsage->unreservedForVm->value;
+
+  cleanup:
+    esxVI_String_Free(&propertyNameList);
+    esxVI_ObjectContent_Free(&hostSystem);
+    esxVI_ManagedObjectReference_Free(&managedObjectReference);
+    esxVI_ObjectContent_Free(&resourcePool);
+    esxVI_ResourcePoolResourceUsage_Free(&resourcePoolResourceUsage);
+
+    return result;
+
+  failure:
+    result = 0;
+
+    goto cleanup;
+}
+
+
+
 static virDriver esxDriver = {
     VIR_DRV_ESX,
     "ESX",
@@ -3080,7 +3106,7 @@ static virDriver esxDriver = {
     NULL,                            /* domainBlockPeek */
     NULL,                            /* domainMemoryPeek */
     NULL,                            /* nodeGetCellsFreeMemory */
-    NULL,                            /* nodeGetFreeMemory */
+    esxNodeGetFreeMemory,            /* nodeGetFreeMemory */
     NULL,                            /* domainEventRegister */
     NULL,                            /* domainEventDeregister */
     NULL,                            /* domainMigratePrepare2 */
diff --git a/src/esx/esx_vi.c b/src/esx/esx_vi.c
index a77cfda..29443db 100644
--- a/src/esx/esx_vi.c
+++ b/src/esx/esx_vi.c
@@ -115,6 +115,7 @@ ESX_VI__TEMPLATE__ALLOC(Context);
 ESX_VI__TEMPLATE__FREE(Context,
 {
     VIR_FREE(item->url);
+    VIR_FREE(item->ipAddress);
 
     if (item->curl_handle != NULL) {
         curl_easy_cleanup(item->curl_handle);
@@ -189,21 +190,23 @@ _esxVI_CURL_Debug(CURL *curl ATTRIBUTE_UNUSED, curl_infotype type,
 
 int
 esxVI_Context_Connect(virConnectPtr conn, esxVI_Context *ctx, const char *url,
-                      const char *username, const char *password, int noVerify)
+                      const char *ipAddress, const char *username,
+                      const char *password, int noVerify)
 {
     int result = 0;
     esxVI_String *propertyNameList = NULL;
     esxVI_ObjectContent *datacenterList = NULL;
     esxVI_DynamicProperty *dynamicProperty = NULL;
 
-    if (ctx == NULL || url == NULL || username == NULL || password == NULL ||
-        ctx->url != NULL || ctx->service != NULL || ctx->curl_handle != NULL ||
-        ctx->curl_headers != NULL) {
+    if (ctx == NULL || url == NULL || ipAddress == NULL || username == NULL ||
+        password == NULL || ctx->url != NULL || ctx->service != NULL ||
+        ctx->curl_handle != NULL || ctx->curl_headers != NULL) {
         ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Invalid argument");
         goto failure;
     }
 
-    if (esxVI_String_DeepCopyValue(conn, &ctx->url, url) < 0) {
+    if (esxVI_String_DeepCopyValue(conn, &ctx->url, url) < 0 ||
+        esxVI_String_DeepCopyValue(conn, &ctx->ipAddress, ipAddress) < 0) {
         goto failure;
     }
 
@@ -1477,9 +1480,96 @@ esxVI_GetVirtualMachineIdentity(virConnectPtr conn,
 
 
 
+int esxVI_GetResourcePool(virConnectPtr conn, esxVI_Context *ctx,
+                          esxVI_ObjectContent *hostSystem,
+                          esxVI_ManagedObjectReference **resourcePool)
+{
+    int result = 0;
+    esxVI_String *propertyNameList = NULL;
+    esxVI_DynamicProperty *dynamicProperty = NULL;
+    esxVI_ManagedObjectReference *managedObjectReference = NULL;
+    esxVI_ObjectContent *computeResource = NULL;
+
+    if (resourcePool == NULL || *resourcePool != NULL) {
+        ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR, "Invalid argument");
+        return -1;
+    }
+
+    for (dynamicProperty = hostSystem->propSet; dynamicProperty != NULL;
+         dynamicProperty = dynamicProperty->_next) {
+        if (STREQ(dynamicProperty->name, "parent")) {
+            if (esxVI_ManagedObjectReference_CastFromAnyType
+                  (conn, dynamicProperty->val, &managedObjectReference,
+                   "ComputeResource") < 0) {
+                goto failure;
+            }
+
+            break;
+        } else {
+            VIR_WARN("Unexpected '%s' property", dynamicProperty->name);
+        }
+    }
+
+    if (managedObjectReference == NULL) {
+        ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR,
+                     "Could not retrieve compute resource of host system");
+        goto failure;
+    }
+
+    if (esxVI_String_AppendValueToList(conn, &propertyNameList,
+                                       "resourcePool") < 0 ||
+        esxVI_GetObjectContent(conn, ctx, managedObjectReference,
+                               "ComputeResource", propertyNameList,
+                               esxVI_Boolean_False, &computeResource) < 0) {
+        goto failure;
+    }
+
+    if (computeResource == NULL) {
+        ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR,
+                     "Could not retrieve compute resource of host system");
+        goto failure;
+    }
+
+    for (dynamicProperty = computeResource->propSet; dynamicProperty != NULL;
+         dynamicProperty = dynamicProperty->_next) {
+        if (STREQ(dynamicProperty->name, "resourcePool")) {
+            if (esxVI_ManagedObjectReference_CastFromAnyType
+                  (conn, dynamicProperty->val, resourcePool,
+                   "ResourcePool") < 0) {
+                goto failure;
+            }
+
+            break;
+        } else {
+            VIR_WARN("Unexpected '%s' property", dynamicProperty->name);
+        }
+    }
+
+    if ((*resourcePool) == NULL) {
+        ESX_VI_ERROR(conn, VIR_ERR_INTERNAL_ERROR,
+                     "Could not retrieve resource pool of compute resource");
+        goto failure;
+    }
+
+  cleanup:
+    esxVI_String_Free(&propertyNameList);
+    esxVI_ManagedObjectReference_Free(&managedObjectReference);
+    esxVI_ObjectContent_Free(&computeResource);
+
+    return result;
+
+  failure:
+    result = -1;
+
+    goto cleanup;
+}
+
+
+
 int
 esxVI_LookupHostSystemByIp(virConnectPtr conn, esxVI_Context *ctx,
-                           const char *ip, esxVI_String *propertyNameList,
+                           const char *ipAddress,
+                           esxVI_String *propertyNameList,
                            esxVI_ObjectContent **hostSystem)
 {
     int result = 0;
@@ -1490,8 +1580,8 @@ esxVI_LookupHostSystemByIp(virConnectPtr conn, esxVI_Context *ctx,
         return -1;
     }
 
-    if (esxVI_FindByIp(conn, ctx, ctx->datacenter, ip, esxVI_Boolean_False,
-                       &managedObjectReference) < 0) {
+    if (esxVI_FindByIp(conn, ctx, ctx->datacenter, ipAddress,
+                       esxVI_Boolean_False, &managedObjectReference) < 0) {
         goto failure;
     }
 
diff --git a/src/esx/esx_vi.h b/src/esx/esx_vi.h
index e60ac7f..2aeea55 100644
--- a/src/esx/esx_vi.h
+++ b/src/esx/esx_vi.h
@@ -65,6 +65,7 @@ enum _esxVI_ProductVersion {
 
 struct _esxVI_Context {
     char *url;
+    char *ipAddress;
     CURL *curl_handle;
     struct curl_slist *curl_headers;
     virMutex curl_lock;
@@ -83,8 +84,9 @@ struct _esxVI_Context {
 int esxVI_Context_Alloc(virConnectPtr conn, esxVI_Context **ctx);
 void esxVI_Context_Free(esxVI_Context **ctx);
 int esxVI_Context_Connect(virConnectPtr conn, esxVI_Context *ctx,
-                          const char *url, const char *username,
-                          const char *password, int noVerify);
+                          const char *ipAddress, const char *url,
+                          const char *username, const char *password,
+                          int noVerify);
 int esxVI_Context_Download(virConnectPtr conn, esxVI_Context *ctx,
                            const char *url, char **content);
 int esxVI_Context_Execute(virConnectPtr conn, esxVI_Context *ctx,
@@ -214,8 +216,13 @@ int esxVI_GetVirtualMachineIdentity(virConnectPtr conn,
                                     esxVI_ObjectContent *virtualMachine,
                                     int *id, char **name, unsigned char *uuid);
 
+int esxVI_GetResourcePool(virConnectPtr conn, esxVI_Context *ctx,
+                          esxVI_ObjectContent *hostSystem,
+                          esxVI_ManagedObjectReference **resourcePool);
+
 int esxVI_LookupHostSystemByIp(virConnectPtr conn, esxVI_Context *ctx,
-                               const char *ip, esxVI_String *propertyNameList,
+                               const char *ipAddress,
+                               esxVI_String *propertyNameList,
                                esxVI_ObjectContent **hostSystem);
 
 int esxVI_LookupVirtualMachineByUuid(virConnectPtr conn, esxVI_Context *ctx,
diff --git a/src/esx/esx_vi_types.c b/src/esx/esx_vi_types.c
index 68b7994..1c6e112 100644
--- a/src/esx/esx_vi_types.c
+++ b/src/esx/esx_vi_types.c
@@ -2165,6 +2165,48 @@ ESX_VI__TEMPLATE__SERIALIZE(ResourceAllocationInfo,
 
 
 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * VI Type: ResourcePoolResourceUsage
+ */
+
+/* esxVI_ResourcePoolResourceUsage_Alloc */
+ESX_VI__TEMPLATE__ALLOC(ResourcePoolResourceUsage);
+
+/* esxVI_ResourcePoolResourceUsage_Free */
+ESX_VI__TEMPLATE__FREE(ResourcePoolResourceUsage,
+{
+    esxVI_Long_Free(&item->reservationUsed);
+    esxVI_Long_Free(&item->reservationUsedForVm);
+    esxVI_Long_Free(&item->unreservedForPool);
+    esxVI_Long_Free(&item->unreservedForVm);
+    esxVI_Long_Free(&item->overallUsage);
+    esxVI_Long_Free(&item->maxUsage);
+});
+
+/* esxVI_ResourcePoolResourceUsage_CastFromAnyType */
+ESX_VI__TEMPLATE__CAST_FROM_ANY_TYPE(ResourcePoolResourceUsage);
+
+/* esxVI_ResourcePoolResourceUsage_Deserialize */
+ESX_VI__TEMPLATE__DESERIALIZE(ResourcePoolResourceUsage,
+{
+    ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE(Long, reservationUsed);
+    ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE(Long, reservationUsedForVm);
+    ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE(Long, unreservedForPool);
+    ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE(Long, unreservedForVm);
+    ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE(Long, overallUsage);
+    ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE(Long, maxUsage);
+},
+{
+    ESX_VI__TEMPLATE__PROPERTY__REQUIRED(reservationUsed);
+    ESX_VI__TEMPLATE__PROPERTY__REQUIRED(reservationUsedForVm);
+    ESX_VI__TEMPLATE__PROPERTY__REQUIRED(unreservedForPool);
+    ESX_VI__TEMPLATE__PROPERTY__REQUIRED(unreservedForVm);
+    ESX_VI__TEMPLATE__PROPERTY__REQUIRED(overallUsage);
+    ESX_VI__TEMPLATE__PROPERTY__REQUIRED(maxUsage);
+});
+
+
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  * VI Type: VirtualMachineConfigSpec
  */
 
diff --git a/src/esx/esx_vi_types.h b/src/esx/esx_vi_types.h
index 2e69601..1599b05 100644
--- a/src/esx/esx_vi_types.h
+++ b/src/esx/esx_vi_types.h
@@ -85,6 +85,7 @@ typedef struct _esxVI_ServiceContent esxVI_ServiceContent;
 typedef struct _esxVI_UpdateSet esxVI_UpdateSet;
 typedef struct _esxVI_SharesInfo esxVI_SharesInfo;
 typedef struct _esxVI_ResourceAllocationInfo esxVI_ResourceAllocationInfo;
+typedef struct _esxVI_ResourcePoolResourceUsage esxVI_ResourcePoolResourceUsage;
 typedef struct _esxVI_VirtualMachineConfigSpec esxVI_VirtualMachineConfigSpec;
 typedef struct _esxVI_Event esxVI_Event;
 typedef struct _esxVI_UserSession esxVI_UserSession;
@@ -902,6 +903,33 @@ int esxVI_ResourceAllocationInfo_Serialize
 
 
 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * VI Type: ResourcePoolResourceUsage
+ */
+
+struct _esxVI_ResourcePoolResourceUsage {
+    esxVI_Long *reservationUsed;                           /* required */
+    esxVI_Long *reservationUsedForVm;                      /* required */
+    esxVI_Long *unreservedForPool;                         /* required */
+    esxVI_Long *unreservedForVm;                           /* required */
+    esxVI_Long *overallUsage;                              /* required */
+    esxVI_Long *maxUsage;                                  /* required */
+};
+
+int esxVI_ResourcePoolResourceUsage_Alloc
+      (virConnectPtr conn,
+       esxVI_ResourcePoolResourceUsage **resourcePoolResourceUsage);
+void esxVI_ResourcePoolResourceUsage_Free
+       (esxVI_ResourcePoolResourceUsage **resourcePoolResourceUsage);
+int esxVI_ResourcePoolResourceUsage_CastFromAnyType
+      (virConnectPtr conn, esxVI_AnyType *anyType,
+       esxVI_ResourcePoolResourceUsage **resourcePoolResourceUsage);
+int esxVI_ResourcePoolResourceUsage_Deserialize
+      (virConnectPtr conn, xmlNodePtr node,
+       esxVI_ResourcePoolResourceUsage **resourcePoolResourceUsage);
+
+
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  * VI Type: VirtualMachineConfigSpec
  */
 
--
Libvir-list mailing list
Libvir-list@xxxxxxxxxx
https://www.redhat.com/mailman/listinfo/libvir-list

[Index of Archives]     [Virt Tools]     [Libvirt Users]     [Lib OS Info]     [Fedora Users]     [Fedora Desktop]     [Fedora SELinux]     [Big List of Linux Books]     [Yosemite News]     [KDE Users]     [Fedora Tools]