This is an automated email from the ASF dual-hosted git repository.

pearl11594 pushed a commit to branch 4.20
in repository https://gitbox.apache.org/repos/asf/cloudstack.git

commit 48ed5e24175b9cf7ad797ba39be5ae51c37f1552
Merge: 3aabedd4473 b41acf28d4c
Author: Pearl Dsilva <pearl1...@gmail.com>
AuthorDate: Tue Mar 4 09:17:16 2025 -0500

    Merge branch '4.19' into 4.20

 .../LibvirtGetVmIpAddressCommandWrapper.java       | 167 +++++++----
 .../LibvirtGetVmIpAddressCommandWrapperTest.java   | 320 +++++++++++++++++++++
 setup/bindir/cloud-setup-databases.in              |   2 +
 .../plugins/linstor/test_linstor_volumes.py        | 252 +++++++++++++---
 ui/public/locales/en.json                          |   6 +
 ui/src/config/section/infra/hosts.js               |  12 +-
 ui/src/config/section/storage.js                   |  21 +-
 ui/src/views/infra/ConfigureHostOOBM.vue           | 172 +++++++++++
 ui/src/views/infra/HostInfo.vue                    |  46 ++-
 ui/src/views/storage/CreateTemplate.vue            | 113 ++++----
 10 files changed, 941 insertions(+), 170 deletions(-)

diff --cc 
plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtGetVmIpAddressCommandWrapper.java
index 0f00a6e29bd,0dd52ddfb10..e050cb4e85d
--- 
a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtGetVmIpAddressCommandWrapper.java
+++ 
b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtGetVmIpAddressCommandWrapper.java
@@@ -33,7 -36,28 +34,27 @@@ import com.cloud.utils.script.Script
  @ResourceWrapper(handles =  GetVmIpAddressCommand.class)
  public final class LibvirtGetVmIpAddressCommandWrapper extends 
CommandWrapper<GetVmIpAddressCommand, Answer, LibvirtComputingResource> {
  
 -    private static final Logger s_logger = 
Logger.getLogger(LibvirtGetVmIpAddressCommandWrapper.class);
  
+     static String virsh_path = null;
+     static String virt_win_reg_path = null;
+     static String grep_path = null;
+     static String awk_path = null;
+     static String sed_path = null;
+     static String virt_ls_path = null;
+     static String virt_cat_path = null;
+     static String tail_path = null;
+ 
+     static void init() {
+         virt_ls_path = Script.getExecutableAbsolutePath("virt-ls");
+         virt_cat_path = Script.getExecutableAbsolutePath("virt-cat");
+         virt_win_reg_path = Script.getExecutableAbsolutePath("virt-win-reg");
+         tail_path = Script.getExecutableAbsolutePath("tail");
+         grep_path = Script.getExecutableAbsolutePath("grep");
+         awk_path = Script.getExecutableAbsolutePath("awk");
+         sed_path = Script.getExecutableAbsolutePath("sed");
+         virsh_path = Script.getExecutableAbsolutePath("virsh");
+     }
+ 
      @Override
      public Answer execute(final GetVmIpAddressCommand command, final 
LibvirtComputingResource libvirtComputingResource) {
          String ip = null;
@@@ -42,65 -66,113 +63,113 @@@
          if (!NetUtils.verifyDomainNameLabel(vmName, true)) {
              return new Answer(command, result, ip);
          }
+ 
          String sanitizedVmName = sanitizeBashCommandArgument(vmName);
          String networkCidr = command.getVmNetworkCidr();
+ 
+         ip = ipFromDomIf(sanitizedVmName, networkCidr);
+ 
+         if (ip == null) {
+             if(!command.isWindows()) {
+                 ip = ipFromDhcpLeaseFile(sanitizedVmName, networkCidr);
+             } else {
+                 ip = ipFromWindowsRegistry(sanitizedVmName, networkCidr);
+             }
+         }
+ 
+         if(ip != null){
+             result = true;
 -            s_logger.debug("GetVmIp: "+ vmName + " Found Ip: "+ip);
++            logger.debug("GetVmIp: "+ vmName + " Found Ip: "+ip);
+         } else {
 -            s_logger.warn("GetVmIp: "+ vmName + " IP not found.");
++            logger.warn("GetVmIp: "+ vmName + " IP not found.");
+         }
+ 
+         return new Answer(command, result, ip);
+     }
+ 
+     private String ipFromDomIf(String sanitizedVmName, String networkCidr) {
+         String ip = null;
          List<String[]> commands = new ArrayList<>();
-         final String virt_ls_path = 
Script.getExecutableAbsolutePath("virt-ls");
-         final String virt_cat_path = 
Script.getExecutableAbsolutePath("virt-cat");
-         final String virt_win_reg_path = 
Script.getExecutableAbsolutePath("virt-win-reg");
-         final String tail_path = Script.getExecutableAbsolutePath("tail");
-         final String grep_path = Script.getExecutableAbsolutePath("grep");
-         final String awk_path = Script.getExecutableAbsolutePath("awk");
-         final String sed_path = Script.getExecutableAbsolutePath("sed");
-         if(!command.isWindows()) {
-             //List all dhcp lease files inside guestVm
-             commands.add(new String[]{virt_ls_path, sanitizedVmName, 
"/var/lib/dhclient/"});
-             commands.add(new String[]{grep_path, ".*\\*.leases"});
-             String leasesList = Script.executePipedCommands(commands, 
0).second();
-             if(leasesList != null) {
-                 String[] leasesFiles = leasesList.split("\n");
-                 for(String leaseFile : leasesFiles){
-                     //Read from each dhclient lease file inside guest Vm 
using virt-cat libguestfs utility
-                     commands = new ArrayList<>();
-                     commands.add(new String[]{virt_cat_path, sanitizedVmName, 
"/var/lib/dhclient/" + leaseFile});
-                     commands.add(new String[]{tail_path, "-16"});
-                     commands.add(new String[]{grep_path, "fixed-address"});
-                     commands.add(new String[]{awk_path, "{print $2}"});
-                     commands.add(new String[]{sed_path, "-e", "s/;//"});
-                     String ipAddr = Script.executePipedCommands(commands, 
0).second();
-                     // Check if the IP belongs to the network
-                     if((ipAddr != null) && 
NetUtils.isIpWithInCidrRange(ipAddr, networkCidr)) {
-                         ip = ipAddr;
-                         break;
+         commands.add(new String[]{virsh_path, "domifaddr", sanitizedVmName, 
"--source", "agent"});
+         Pair<Integer,String> response = executePipedCommands(commands, 0);
+         if (response != null) {
+             String output = response.second();
+             String[] lines = output.split("\n");
+             for (String line : lines) {
+                 if (line.contains("ipv4")) {
+                     String[] parts = line.split(" ");
+                     String[] ipParts = parts[parts.length-1].split("/");
+                     if (ipParts.length > 1) {
+                         if (NetUtils.isIpWithInCidrRange(ipParts[0], 
networkCidr)) {
+                             ip = ipParts[0];
+                             break;
+                         }
                      }
-                     logger.debug("GetVmIp: "+ vmName + " Ip: "+ipAddr+" does 
not belong to network "+networkCidr);
                  }
              }
          } else {
-             // For windows, read from guest Vm registry using virt-win-reg 
libguestfs ulitiy. Registry Path: 
HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Services\Tcpip\Parameters\Interfaces\<service>\DhcpIPAddress
-             commands = new ArrayList<>();
-             commands.add(new String[]{virt_win_reg_path, 
"--unsafe-printable-strings", sanitizedVmName, 
"HKEY_LOCAL_MACHINE\\SYSTEM\\ControlSet001\\Services\\Tcpip\\Parameters\\Interfaces"});
-             commands.add(new String[]{grep_path, "DhcpIPAddress"});
-             commands.add(new String[]{awk_path, "-F", ":", "{print $2}"});
-             commands.add(new String[]{sed_path, "-e", "s/^\"//", "-e", 
"s/\"$//"});
-             String ipList = Script.executePipedCommands(commands, 0).second();
-             if(ipList != null) {
-                 logger.debug("GetVmIp: "+ vmName + "Ips: "+ipList);
-                 String[] ips = ipList.split("\n");
-                 for (String ipAddr : ips){
-                     // Check if the IP belongs to the network
-                     if((ipAddr != null) && 
NetUtils.isIpWithInCidrRange(ipAddr, networkCidr)){
-                         ip = ipAddr;
-                         break;
-                     }
-                     logger.debug("GetVmIp: "+ vmName + " Ip: "+ipAddr+" does 
not belong to network "+networkCidr);
 -            s_logger.error("ipFromDomIf: Command execution failed for VM: " + 
sanitizedVmName);
++            logger.error("ipFromDomIf: Command execution failed for VM: " + 
sanitizedVmName);
+         }
+         return ip;
+     }
+ 
+     private String ipFromDhcpLeaseFile(String sanitizedVmName, String 
networkCidr) {
+         String ip = null;
+         List<String[]> commands = new ArrayList<>();
+         commands.add(new String[]{virt_ls_path, sanitizedVmName, 
"/var/lib/dhclient/"});
+         commands.add(new String[]{grep_path, ".*\\*.leases"});
+         Pair<Integer,String> response = executePipedCommands(commands, 0);
+ 
+         if(response != null && response.second() != null) {
+             String leasesList = response.second();
+             String[] leasesFiles = leasesList.split("\n");
+             for(String leaseFile : leasesFiles){
+                 commands = new ArrayList<>();
+                 commands.add(new String[]{virt_cat_path, sanitizedVmName, 
"/var/lib/dhclient/" + leaseFile});
+                 commands.add(new String[]{tail_path, "-16"});
+                 commands.add(new String[]{grep_path, "fixed-address"});
+                 commands.add(new String[]{awk_path, "{print $2}"});
+                 commands.add(new String[]{sed_path, "-e", "s/;//"});
+                 String ipAddr = executePipedCommands(commands, 0).second();
+                 if((ipAddr != null) && NetUtils.isIpWithInCidrRange(ipAddr, 
networkCidr)) {
+                     ip = ipAddr;
+                     break;
                  }
 -                s_logger.debug("GetVmIp: "+ sanitizedVmName + " Ip: 
"+ipAddr+" does not belong to network "+networkCidr);
++                logger.debug("GetVmIp: "+ sanitizedVmName + " Ip: "+ipAddr+" 
does not belong to network "+networkCidr);
              }
+         } else {
 -            s_logger.error("ipFromDhcpLeaseFile: Command execution failed for 
VM: " + sanitizedVmName);
++            logger.error("ipFromDhcpLeaseFile: Command execution failed for 
VM: " + sanitizedVmName);
          }
-         if(ip != null){
-             result = true;
-             logger.debug("GetVmIp: "+ vmName + " Found Ip: "+ip);
+         return ip;
+     }
+ 
+     private String ipFromWindowsRegistry(String sanitizedVmName, String 
networkCidr) {
+         String ip = null;
+         List<String[]> commands = new ArrayList<>();
+         commands.add(new String[]{virt_win_reg_path, 
"--unsafe-printable-strings", sanitizedVmName, 
"HKEY_LOCAL_MACHINE\\SYSTEM\\ControlSet001\\Services\\Tcpip\\Parameters\\Interfaces"});
+         commands.add(new String[]{grep_path, "DhcpIPAddress"});
+         commands.add(new String[]{awk_path, "-F", ":", "{print $2}"});
+         commands.add(new String[]{sed_path, "-e", "s/^\"//", "-e", 
"s/\"$//"});
+         Pair<Integer,String> pair = executePipedCommands(commands, 0);
+         if(pair != null && pair.second() != null) {
+             String ipList = pair.second();
+             ipList = ipList.replaceAll("\"", "");
 -            s_logger.debug("GetVmIp: "+ sanitizedVmName + "Ips: "+ipList);
++            logger.debug("GetVmIp: "+ sanitizedVmName + "Ips: "+ipList);
+             String[] ips = ipList.split("\n");
+             for (String ipAddr : ips){
+                 if((ipAddr != null) && NetUtils.isIpWithInCidrRange(ipAddr, 
networkCidr)){
+                     ip = ipAddr;
+                     break;
+                 }
 -                s_logger.debug("GetVmIp: "+ sanitizedVmName + " Ip: 
"+ipAddr+" does not belong to network "+networkCidr);
++                logger.debug("GetVmIp: "+ sanitizedVmName + " Ip: "+ipAddr+" 
does not belong to network "+networkCidr);
+             }
+         } else {
 -            s_logger.error("ipFromWindowsRegistry: Command execution failed 
for VM: " + sanitizedVmName);
++            logger.error("ipFromWindowsRegistry: Command execution failed for 
VM: " + sanitizedVmName);
          }
-         return new Answer(command, result, ip);
+         return ip;
+     }
+ 
+     static Pair<Integer, String> executePipedCommands(List<String[]> 
commands, long timeout) {
+         return Script.executePipedCommands(commands, timeout);
      }
  }
diff --cc ui/public/locales/en.json
index dfdac5963bd,c1c88da62d3..0a67c67ba9a
--- a/ui/public/locales/en.json
+++ b/ui/public/locales/en.json
@@@ -3327,10 -3071,8 +3332,11 @@@
  "message.no.description": "No description entered.",
  "message.offering.internet.protocol.warning": "WARNING: IPv6 supported 
Networks use static routing and will require upstream routes to be configured 
manually.",
  "message.offering.ipv6.warning": "Please refer documentation for creating 
IPv6 enabled Network/VPC offering <a 
href='http://docs.cloudstack.apache.org/en/latest/plugins/ipv6.html#isolated-network-and-vpc-tier'>IPv6
 support in CloudStack - Isolated Networks and VPC Network Tiers</a>",
+ "message.oobm.configured": "Successfully configured out-of-band management 
for host",
  "message.ovf.configurations": "OVF configurations available for the selected 
appliance. Please select the desired value. Incompatible compute offerings will 
get disabled.",
 +"message.password.reset.failed": "Failed to reset password.",
 +"message.password.reset.success": "Password has been reset successfully. 
Please login using your new credentials.",
 +"message.path": "Path : ",
  "message.path.description": "NFS: exported path from the server. VMFS: 
/datacenter name/datastore name. SharedMountPoint: path where primary storage 
is mounted, such as /mnt/primary.",
  "message.please.confirm.remove.ssh.key.pair": "Please confirm that you want 
to remove this SSH key pair.",
  "message.please.confirm.remove.user.data": "Please confirm that you want to 
remove this Userdata",
diff --cc ui/src/config/section/storage.js
index 37f2a4b55e0,a869dfb6e80..a86650874ba
--- a/ui/src/config/section/storage.js
+++ b/ui/src/config/section/storage.js
@@@ -256,27 -254,12 +256,10 @@@ export default 
            label: 'label.action.create.template.from.volume',
            dataView: true,
            show: (record) => {
 -            return !['Destroy', 'Destroyed', 'Expunging', 'Expunged', 
'Migrating', 'Uploading', 'UploadError', 'Creating'].includes(record.state) &&
 -                ((record.type === 'ROOT' && record.vmstate === 'Stopped') ||
 -                    (record.type !== 'ROOT' && !record.virtualmachineid && 
!['Allocated', 'Uploaded'].includes(record.state)))
 +            return record.state === 'Ready' && (record.vmstate === 'Stopped' 
|| !record.virtualmachineid)
            },
-           args: (record, store) => {
-             var fields = ['volumeid', 'name', 'displaytext', 'ostypeid', 
'isdynamicallyscalable', 'requireshvm', 'passwordenabled']
-             if (['Admin', 'DomainAdmin'].includes(store.userInfo.roletype)) {
-               fields.push('domainid')
-               fields.push('account')
-             }
-             if (['Admin'].includes(store.userInfo.roletype) || 
store.features.userpublictemplateenabled) {
-               fields.push('ispublic')
-             }
-             if (['Admin'].includes(store.userInfo.roletype)) {
-               fields.push('isfeatured')
-             }
-             return fields
-           },
-           mapping: {
-             volumeid: {
-               value: (record) => { return record.id }
-             }
-           }
+           popup: true,
+           component: shallowRef(defineAsyncComponent(() => 
import('@/views/storage/CreateTemplate.vue')))
          },
          {
            api: 'recoverVolume',

Reply via email to