2

I have an expect script which provides the IP address:

#!/bin/expect -f
set nodename [lindex $argv 0]
spawn virsh console $nodename
expect "Escape character is"
send "\n"
expect "localhost login: " {
    send "root\n"
    expect "Password: "
    send "cloud123\n"
}
expect "~]#" {
        send "\n"
        send "ifconfig | grep 192.168.1. | awk \'{print \$2}\'"
        send "\n"
        expect '(\d+\.\d+\.\d+\.\d+)'
        send "logout"
}

I want the script to return this IP address. I am calling this expect script from a shell script as below

#!/bin/bash
ip=$(expect GetIP.exp nodetwo)
echo $ip

How can I make my expect script return output to the shell script?

  • BTW, why don't you just do a dns lookup on nodetwo. e.g. ip=$(host nodetwo | awk '/has address/ {print $4}') – cas Oct 28 '15 at 9:23
  • or use ssh with a key: ssh nodetwo ifconfig | awk '/192\.168\.1\./ { print $2}' – cas Oct 28 '15 at 9:26
  • @cas nodetwo is not hostname its vm name. – karan ratnaparkhi Oct 28 '15 at 16:34
  • Well, perhaps it should be....even if only on a local DNS server serving a bogus local domain. You also have the MAC address (e.g. with `virsh dumpxml nodetwo | grep 'mac address' | ...), so you can either grep that out of the dhcp config (if you are allocating fixed IP addresses based on MAC address) or out of the DHCP log, or the dhcp leases file. – cas Oct 28 '15 at 21:11
  • re: the local dns - if you think ahead like this you can often make difficult tasks a lot easier. – cas Oct 28 '15 at 21:11
4

OK, turning the logging on and off didn't work - timing issues, probably.

The expect script below worked for me when called like this

# ip=$(./virsh-expect nodetwo | tr -d '\r' | grep '^192.168')
# echo $ip 
192.168.122.99

The important thing to note here is that carriage returns are stripped from the output with tr and grepping for the IP here in the shell script. The expect script doesn't even try to "expect" it, it just expects the next root shell prompt and exits.

I have also made the expect script more generic - it just expects "login:" rather than "localhost login:" (which would fail on any VM that actually had a hostname...and most will), and a plain "# " for the root shell prompt.

#!/usr/bin/expect -f
set nodename [lindex $argv 0]
spawn virsh console $nodename
expect "Escape character is"
send "\n\n"
expect "login: " {
    send "root\n"
    expect "Password: "
    send "cloud123\n"
}   
expect "# " {
        send "ifconfig | awk \'/192\.168/ {print \$2}\'"
        send "\n"
        expect "# "
        send "exit"
}

Another alternative is not to use expect at all, but use perl's Expect.pm or python's pexpect instead. These work in pretty much the same way as expect but make it easier to extract data from the expect session.


I still think that there are far better ways to get the IP address of a VM than using expect on virsh console.

Here's a way of doing it that extracts the MAC Address from virsh dumpxml and then greps for the matching dnsmasq-dhcp entry in /var/log/daemon.log using awk:

# mac=$(virsh dumpxml nodetwo | sed -n -e "/mac address/ s/.*'\([^']*\)'.*/\1/ p" | tail -1)
# ip=$(awk "/dnsmasq.*DHCPACK.*$mac/ {print \$7}" /var/log/daemon.log  | tail -1)
# echo $ip
192.168.122.99

On my system, the VM has two network interfaces, and i'm only interested in the last one for this purpose so i'm using tail -1 on the virsh dumpxml line. The tail -1 on the awk line is to ensure we only get the latest dhcp allocation for that MAC address.

(actually, the VM I tested with on my system is called 'sid', not 'nodetwo' but I edited the output, as well as the password in the expect script, to suit your question. Also the IP addresses I'm using for my VMs are 192.168.122.x rather than 192.168.1.x - but that's a trivial difference in detail)


Update

I had to use this myself last night to find the IP of a freebsd vm I created. I use ISC dhcpd rather than dnsmasq, so the log format is slightly different. This version works for both dnsmasq and dhcpd:

$ cat find-vm-ip-by-name.sh
#!/bin/bash

mac=$(virsh dumpxml "$1" | sed -n -e "/mac address/ s/.*'\([^']*\)'.*/\1/ p" | tail -1)
ip=$(awk "/dnsmasq.*DHCPACK.*$mac/ {print \$7} ; /dhcpd.*DHCPACK.*$mac/ {print \$8}" /var/log/daemon.log  | tail -1)
echo $ip
  • after making changes as above when I run script dummy.sh I am getting output as below [root@node3 Documents]# ./dummy.sh [root@localhost ~]# ifconfig | grep 192.168.1. | awk '{print $2}' [root@node3 Documents]# the expect '(\d+\.\d+\.\d+\.\d+)' is not captured in variable ip – karan ratnaparkhi Oct 28 '15 at 16:49
  • ok, try it now. – cas Oct 28 '15 at 22:39

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.