3

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?

5
  • 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, 2015 at 9:23
  • or use ssh with a key: ssh nodetwo ifconfig | awk '/192\.168\.1\./ { print $2}'
    – cas
    Oct 28, 2015 at 9:26
  • @cas nodetwo is not hostname its vm name. Oct 28, 2015 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, 2015 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, 2015 at 21:11

2 Answers 2

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
2
  • 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 Oct 28, 2015 at 16:49
  • ok, try it now.
    – cas
    Oct 28, 2015 at 22:39
0

You can try the following way:

send_user $ip

"send_user" output that gets sent to stdout. This is used for sending message to the screen as the script runs. It is great for user feedback, banners, and for generating error messages.

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.