rv_connect.py 11.6 KB
Newer Older
1 2 3 4 5 6 7
"""
rv_connect.py - connect with remote-viewer to remote target

Requires: binaries remote-viewer, Xorg, netstat
          Use example kickstart RHEL-6-spice.ks

"""
L
Lucas Meneghel Rodrigues 已提交
8 9 10
import logging
import sys
import socket
11 12
from virttest.aexpect import ShellStatusError
from virttest.aexpect import ShellProcessTerminatedError
13
from virttest import utils_net, utils_spice, remote, utils_misc
14
from autotest.client.shared import error
15

L
Lucas Meneghel Rodrigues 已提交
16

17
def str_input(client_vm, ticket):
18 19
    """
    sends spice_password trough vm.send_key()
L
Lucas Meneghel Rodrigues 已提交
20 21
    :param client_session - vm() object
    :param ticket - use params.get("spice_password")
22 23
    """
    logging.info("Passing ticket '%s' to the remote-viewer.", ticket)
L
Lucas Meneghel Rodrigues 已提交
24 25 26 27 28 29
    char_mapping = {":": "shift-semicolon",
                    ",": "comma",
                    ".": "dot",
                    "/": "slash",
                    "?": "shift-slash",
                    "=": "equal"}
30
    for character in ticket:
31 32
        if character in char_mapping:
            character = char_mapping[character]
33 34
        client_vm.send_key(character)

35
    client_vm.send_key("kp_enter")  # send enter
36

37

38 39 40
def print_rv_version(client_session, rv_binary):
    """
    prints remote-viewer and spice-gtk version available inside client_session
L
Lucas Meneghel Rodrigues 已提交
41 42
    :param client_session - vm.wait_for_login()
    :param rv_binary - remote-viewer binary
43 44
    """
    logging.info("remote-viewer version: %s",
L
Lucas Meneghel Rodrigues 已提交
45
                 client_session.cmd(rv_binary + " -V"))
46
    logging.info("spice-gtk version: %s",
L
Lucas Meneghel Rodrigues 已提交
47
                 client_session.cmd(rv_binary + " --spice-gtk-version"))
48 49 50 51 52 53 54 55


def launch_rv(client_vm, guest_vm, params):
    """
    Launches rv_binary with args based on spice configuration
    inside client_session on background.
    remote-viewer will try to connect from vm1 from vm2

L
Lucas Meneghel Rodrigues 已提交
56 57 58
    :param client_vm - vm object
    :param guest_vm - vm object
    :param params
59 60
    """
    rv_binary = params.get("rv_binary", "remote-viewer")
61
    rv_ld_library_path = params.get("rv_ld_library_path")
62
    host_ip = utils_net.get_host_ip_address(params)
63 64 65 66
    if guest_vm.get_spice_var("listening_addr") == "ipv6":
        host_ip = "[" + utils_misc.convert_ipv4_to_ipv6(host_ip) + "]"
    check_spice_info = params.get("spice_info")
    ssltype = params.get("ssltype")
67
    test_type = params.get("test_type")
68
    host_port = None
69
    full_screen = params.get("full_screen")
70
    disable_audio = params.get("disable_audio", "no")
71 72
    display = params.get("display")
    ticket = None
73 74
    ticket_send = params.get("spice_password_send")
    qemu_ticket = params.get("qemu_password")
75 76 77 78
    gencerts = params.get("gencerts")
    certdb = params.get("certdb")
    smartcard = params.get("smartcard")
    menu = params.get("rv_menu", None)
L
Lucas Meneghel Rodrigues 已提交
79
    # cmd var keeps final remote-viewer command line to be executed on client
80
    cmd = rv_binary + " --display=:0.0"
81

L
Lucas Meneghel Rodrigues 已提交
82
    # If qemu_ticket is set, set the password of the VM using the qemu-monitor
83 84
    if qemu_ticket:
        guest_vm.monitor.cmd("set_password spice %s" % qemu_ticket)
85
        logging.info("Sending to qemu monitor: set_password spice %s"
86
                     % qemu_ticket)
87 88

    client_session = client_vm.wait_for_login(
L
Lucas Meneghel Rodrigues 已提交
89
        timeout=int(params.get("login_timeout", 360)))
90 91 92 93 94

    if display == "spice":
        ticket = guest_vm.get_spice_var("spice_password")

        if guest_vm.get_spice_var("spice_ssl") == "yes":
95 96
            host_tls_port = guest_vm.get_spice_var("spice_tls_port")
            host_port = guest_vm.get_spice_var("spice_port")
97
            cacert = "%s/%s" % (guest_vm.get_spice_var("spice_x509_prefix"),
L
Lucas Meneghel Rodrigues 已提交
98 99 100 101
                                guest_vm.get_spice_var("spice_x509_cacert_file"))
            # cacert subj is in format for create certificate(with '/' delimiter)
            # remote-viewer needs ',' delimiter. And also is needed to remove
            # first character (it's '/')
102
            host_subj = guest_vm.get_spice_var("spice_x509_server_subj")
103
            host_subj = host_subj.replace('/', ',')[1:]
104 105 106 107 108 109 110 111 112 113 114
            if ssltype == "invalid_explicit_hs":
                host_subj = "Invalid Explicit HS"
            else:
                host_subj += host_ip

            # If it's invalid implicit, a remote-viewer connection
            # will be attempted with the hostname, since ssl certs were
            # generated with the ip address
            hostname = socket.gethostname()
            if ssltype == "invalid_implicit_hs":
                spice_url = " spice://%s?tls-port=%s\&port=%s" % (hostname,
L
Lucas Meneghel Rodrigues 已提交
115
                                                                  host_tls_port, host_port)
116 117
            else:
                spice_url = " spice://%s?tls-port=%s\&port=%s" % (host_ip,
L
Lucas Meneghel Rodrigues 已提交
118
                                                                  host_tls_port, host_port)
119 120 121 122 123

            if menu == "yes":
                line = spice_url
            else:
                cmd += spice_url
124 125 126 127 128 129

            cmd += " --spice-ca-file=%s" % cacert

            if params.get("spice_client_host_subject") == "yes":
                cmd += " --spice-host-subject=\"%s\"" % host_subj

L
Lucas Meneghel Rodrigues 已提交
130
            # client needs cacert file
131 132 133 134
            client_session.cmd("rm -rf %s && mkdir -p %s" % (
                               guest_vm.get_spice_var("spice_x509_prefix"),
                               guest_vm.get_spice_var("spice_x509_prefix")))
            remote.copy_files_to(client_vm.get_address(), 'scp',
L
Lucas Meneghel Rodrigues 已提交
135 136 137 138
                                 params.get("username"),
                                 params.get("password"),
                                 params.get("shell_port"),
                                 cacert, cacert)
139 140
        else:
            host_port = guest_vm.get_spice_var("spice_port")
141
            if menu == "yes":
L
Lucas Meneghel Rodrigues 已提交
142 143
                # line to be sent through monitor once r-v is started
                # without spice url
144 145 146
                line = "spice://%s?port=%s" % (host_ip, host_port)
            else:
                cmd += " spice://%s?port=%s" % (host_ip, host_port)
147 148 149 150 151 152

    elif display == "vnc":
        raise NotImplementedError("remote-viewer vnc")

    else:
        raise Exception("Unsupported display value")
153 154 155 156 157 158

    # Check to see if the test is using the full screen option.
    if full_screen == "yes":
        logging.info("Remote Viewer Set to use Full Screen")
        cmd += " --full-screen"

159 160 161 162 163 164 165 166 167
    if disable_audio == "yes":
        logging.info("Remote Viewer Set to disable audio")
        cmd += " --spice-disable-audio"

    # Check to see if the test is using a smartcard.
    if smartcard == "yes":
        logging.info("remote viewer Set to use a smartcard")
        cmd += " --spice-smartcard"

L
Lucas Meneghel Rodrigues 已提交
168
        if certdb is not None:
169 170 171 172
            logging.debug("Remote Viewer set to use the following certificate"
                          " database: " + certdb)
            cmd += " --spice-smartcard-db " + certdb

L
Lucas Meneghel Rodrigues 已提交
173
        if gencerts is not None:
174 175 176
            logging.debug("Remote Viewer set to use the following certs: " +
                          gencerts)
            cmd += " --spice-smartcard-certificates " + gencerts
177

178 179 180 181 182
    if rv_ld_library_path:
        cmd = "export LD_LIBRARY_PATH=" + rv_ld_library_path + "; nohup " + cmd + " &> /dev/null &"  # Launch it on background
    else:
        cmd = "nohup " + cmd + " &> /dev/null &"  # Launch it on background

183
    # Launching the actual set of commands
184
    try:
185 186 187 188 189
        if rv_ld_library_path:
            print_rv_version(client_session, "LD_LIBRARY_PATH=/usr/local/lib " + rv_binary)
        else:
            print_rv_version(client_session, rv_binary)

190
    except ShellStatusError, ShellProcessTerminatedError:
191 192
        # Sometimes It fails with Status error, ingore it and continue.
        # It's not that important to have printed versions in the log.
193 194
        logging.debug("Ignoring a Status Exception that occurs from calling "
                      "print versions of remote-viewer or spice-gtk")
195 196

    logging.info("Launching %s on the client (virtual)", cmd)
197 198 199
    try:
        client_session.cmd(cmd)
    except ShellStatusError:
200 201
        logging.debug("Ignoring a status exception, will check connection of"
                      "remote-viewer later")
202

L
Lucas Meneghel Rodrigues 已提交
203
    # Send command line through monitor since r-v was started without spice url
204 205 206 207 208 209 210 211
    if menu == "yes":
        utils_spice.wait_timeout(1)
        str_input(client_vm, line)
        client_vm.send_key("tab")
        client_vm.send_key("tab")
        client_vm.send_key("tab")
        client_vm.send_key("kp_enter")

212
    # client waits for user entry (authentication) if spice_password is set
L
Lucas Meneghel Rodrigues 已提交
213 214
    # use qemu monitor password if set, else check if the normal password is
    # set
215 216 217
    if qemu_ticket:
        # Wait for remote-viewer to launch
        utils_spice.wait_timeout(5)
218
        str_input(client_vm, qemu_ticket)
219 220 221 222
    elif ticket:
        if ticket_send:
            ticket = ticket_send

223
        utils_spice.wait_timeout(5)  # Wait for remote-viewer to launch
224 225
        str_input(client_vm, ticket)

226
    utils_spice.wait_timeout(5)  # Wait for conncetion to establish
227
    is_rv_connected = True
228
    try:
L
Lucas Meneghel Rodrigues 已提交
229 230
        utils_spice.verify_established(
            client_vm, host_ip, host_port, rv_binary)
231 232 233
    except utils_spice.RVConnectError:
        if test_type == "negative":
            logging.info("remote-viewer connection failed as expected")
234
            if ssltype in ("invalid_implicit_hs", "invalid_explicit_hs"):
L
Lucas Meneghel Rodrigues 已提交
235
                # Check the qemu process output to verify what is expected
236 237 238 239 240 241 242
                qemulog = guest_vm.process.get_output()
                if "SSL_accept failed" in qemulog:
                    return
                else:
                    raise error.TestFail("SSL_accept failed not shown in qemu" +
                                         "process as expected.")
            is_rv_connected = False
243
        else:
244
            raise error.TestFail("remote-viewer connection failed")
245

246 247 248 249
    if test_type == "negative" and is_rv_connected:
        raise error.TestFail("remote-viewer connection was established when" +
                             " it was supposed to be unsuccessful")

L
Lucas Meneghel Rodrigues 已提交
250
    # Get spice info
251 252 253 254 255 256 257 258
    output = guest_vm.monitor.cmd("info spice")
    logging.debug("INFO SPICE")
    logging.debug(output)

    # Check to see if ipv6 address is reported back from qemu monitor
    if (check_spice_info == "ipv6"):
        logging.info("Test to check if ipv6 address is reported"
                     " back from the qemu monitor")
L
Lucas Meneghel Rodrigues 已提交
259 260
        # Remove brackets from ipv6 host ip
        if (host_ip[1:len(host_ip) - 1] in output):
261 262 263 264
            logging.info("Reported ipv6 address found in output from"
                         " 'info spice'")
        else:
            raise error.TestFail("ipv6 address not found from qemu monitor"
L
Lucas Meneghel Rodrigues 已提交
265
                                 " command: 'info spice'")
266 267 268 269
    else:
        logging.info("Not checking the value of 'info spice'"
                     " from the qemu monitor")

L
Lucas Meneghel Rodrigues 已提交
270
    # prevent from kill remote-viewer after test finish
271 272 273
    cmd = "disown -ar"
    client_session.cmd(cmd)

274

275 276 277 278 279 280 281 282
def run_rv_connect(test, params, env):
    """
    Simple test for Remote Desktop connection
    Tests expectes that Remote Desktop client (spice/vnc) will be executed
    from within a second guest so we won't be limited to Linux only clients

    The plan is to support remote-viewer at first place

L
Lucas Meneghel Rodrigues 已提交
283 284
    :param test: QEMU test object.  :param params: Dictionary with the test parameters.
    :param env: Dictionary with test environment.
285 286 287 288 289
    """

    guest_vm = env.get_vm(params["guest_vm"])
    guest_vm.verify_alive()
    guest_session = guest_vm.wait_for_login(
L
Lucas Meneghel Rodrigues 已提交
290
        timeout=int(params.get("login_timeout", 360)))
291 292 293 294

    client_vm = env.get_vm(params["client_vm"])
    client_vm.verify_alive()
    client_session = client_vm.wait_for_login(
L
Lucas Meneghel Rodrigues 已提交
295
        timeout=int(params.get("login_timeout", 360)))
296

297 298
    utils_spice.wait_timeout(15)

299 300 301 302
    launch_rv(client_vm, guest_vm, params)

    client_session.close()
    guest_session.close()