blob: ae1de2e561580c002a01b6ce032db5c3305a3085 [file] [log] [blame]
#!/usr/bin/env python
#
# Copyright (c) 2015-2017 Nest Labs, Inc.
# All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
#
# @file
# Implements WeaveBDX class that tests Weave BDX among Weave Nodes.
#
import os
import sys
import time
from happy.ReturnMsg import ReturnMsg
from happy.Utils import *
from happy.HappyNode import HappyNode
from happy.HappyNetwork import HappyNetwork
from plugin.WeaveTest import WeaveTest
import plugin.WeaveUtilities as WeaveUtilities
import plugins.plaid.Plaid as Plaid
options = {}
options["quiet"] = False
options["server"] = None
options["client"] = None
options["tmp"] = None
options["receive"] = None
options["download"] = None
options["upload"] = None
options["offset"] = None
options["length"] = None
options["tap"] = None
options["server_version"] = 1
options["client_version"] = 1
options["client_faults"] = None
options["server_faults"] = None
options["strace"] = True
options["test_tag"] = ""
options["iterations"] = 1
options["plaid"] = False
def option():
return options.copy()
class WeaveBDX(HappyNode, HappyNetwork, WeaveTest):
"""
weave-bdx [-h --help] [-q --quiet] [-s --server <NAME>] [-c --client <NAME>]
[-t --tmp <SERVER_TMP_PATH>] [-r --receive <DESTINATION_PATH>]
[-u --upload <SOURCE_PATH>] [-d --download <SOURCE_PATH>]
[-o --offset <SIZE>] [-l --length <SIZE>] [-p --tap <TAP_INTERFACE>]
[-S --server-version <bdx_version>] [-C --client-version <bdx_version>]
commands to test bdx-v0:
$ weave-bdx -s node01 -c node02 -S 0 -C 0 --upload /client_files/test_file.txt --tmp /server/tmp --receive /server_files
Sends /client_files/test_file.txt from node02 to folder /server_files at node01.
$ weave-bdx -s node01 -c node02 -S 0 -C 0 --download /server_files/test_file.txt --tmp /server/tmp --receive /client_files
Receives /server_files/test_file.txt from node01 at /client_files of node02.
commands to test bdx-v1:
$ weave-bdx -s node01 -c node02 -S 1 -C 1 --upload /client_files/test_file.txt --tmp /server/tmp --receive /server_files
Sends /client_files/test_file.txt from node02 to folder /server_files at node01.
$ weave-bdx -s node01 -c node02 -S 1 -C 1 --download /server_files/test_file.txt --tmp /server/tmp --receive /client_files
Receives /server_files/test_file.txt from node01 at /client_files of node02.
commands to test bdx-v0 and bdx-v1 interop:
$ weave-bdx -s node01 -c node02 -S 0 -C 1 --upload /client_files/test_file.txt --tmp /server/tmp --receive /server_files
Sends /client_files/test_file.txt from node02 to folder /server_files at node01.
$ weave-bdx -s node01 -c node02 -S 0 -C 1 --download /server_files/test_file.txt --tmp /server/tmp --receive /client_files
Receives /server_files/test_file.txt from node01 at /client_files of node02.
$ weave-bdx -s node01 -c node02 -S 1 -C 0 --upload /client_files/test_file.txt --tmp /server/tmp --receive /server_files
Sends /client_files/test_file.txt from node02 to folder /server_files at node01.
$ weave-bdx -s node01 -c node02 -S 1 -C 0 --download /server_files/test_file.txt --tmp /server/tmp --receive /client_files
Receives /server_files/test_file.txt from node01 at /client_files of node02.
Note:
special the BDX server and client version with '-S/-C' option, and BDX-v1 would be the default version
return:
0 success
1 failure
"""
def __init__(self, opts = options):
HappyNode.__init__(self)
HappyNetwork.__init__(self)
WeaveTest.__init__(self)
self.quiet = opts["quiet"]
self.client = opts["client"]
self.server = opts["server"]
self.tmp = opts["tmp"]
self.download = opts["download"]
self.upload = opts["upload"]
self.receive = opts["receive"]
self.offset = opts["offset"]
self.length = opts["length"]
self.tap = opts["tap"]
self.server_version = opts["server_version"]
self.client_version = opts["client_version"]
self.server_faults = opts["server_faults"]
self.client_faults = opts["client_faults"]
self.iterations = opts["iterations"]
self.server_process_tag = "WEAVE-BDX-SERVER" + opts["test_tag"]
self.client_process_tag = "WEAVE-BDX-CLIENT" + opts["test_tag"]
self.client_node_id = None
self.server_node_id = None
self.strace = opts["strace"]
plaid_opts = Plaid.default_options()
plaid_opts['quiet'] = self.quiet
self.plaid_server_node_id = 'node03'
plaid_opts['server_node_id'] = self.plaid_server_node_id
plaid_opts['num_clients'] = 2
plaid_opts['server_ip_address'] = self.getNodeWeaveIPAddress(self.plaid_server_node_id)
plaid_opts['strace'] = self.strace
self.plaid = Plaid.Plaid(plaid_opts)
self.use_plaid = opts["plaid"]
if opts["plaid"] == "auto":
if self.server == "service":
# can't use plaid when talking to an external service
self.use_plaid = False
else:
self.use_plaid = self.plaid.isPlaidConfigured()
def __pre_check(self):
# Check if Weave BDX client node is given.
if self.client == None:
emsg = "Missing name or address of the Weave BDX client node."
self.logger.error("[localhost] WeaveBDX: %s" % (emsg))
sys.exit(1)
# Check if Weave BDX server node is given.
if self.server == None:
emsg = "Missing name or address of the Weave BDX server node."
self.logger.error("[localhost] WeaveBDX: %s" % (emsg))
sys.exit(1)
# Check if Weave BDX server version is correct.
if self.server_version != 0 and self.server_version != 1:
emsg = "BDX server version is not correct."
self.logger.error("[localhost] WeaveBDX: %s" % (emsg))
sys.exit(1)
# Check if Weave BDX client version is correct.
if self.client_version != 0 and self.client_version != 1:
emsg = "BDX client version is not correct."
self.logger.error("[localhost] WeaveBDX: %s" % (emsg))
sys.exit(1)
# Make sure that fabric was created
if self.getFabricId() == None:
emsg = "Weave Fabric has not been created yet."
self.logger.error("[localhost] WeaveBDX: %s" % (emsg))
sys.exit(1)
# Check if Weave BDX client node exists.
if self._nodeExists(self.client):
self.client_node_id = self.client
# Check if Weave BDX server node exists.
if self._nodeExists(self.server):
self.server_node_id = self.server
# Check if client is provided in a form of IP address
if self.isIpAddress(self.client):
self.client_node_id = self.getNodeIdFromAddress(self.client)
# Check if server is provided in a form of IP address
if self.isIpAddress(self.server):
self.server_node_id = self.getNodeIdFromAddress(self.server)
elif self.server == "service":
if self.download is not None:
self.server_ip = self.getServiceWeaveIPAddress("FileDownload")
elif self.upload is not None:
self.server_ip = self.getServiceWeaveIPAddress("LogUpload")
self.server_weave_id = self.IPv6toWeaveId(self.server_ip)
self.server_node_id = "service"
if self.client_node_id == None:
emsg = "Unknown identity of the client node."
self.logger.error("[localhost] WeaveBDX: %s" % (emsg))
sys.exit(1)
if self.server_node_id == None:
emsg = "Unknown identity of the server node."
self.logger.error("[localhost] WeaveBDX: %s" % (emsg))
sys.exit(1)
self.client_ip = self.getNodeWeaveIPAddress(self.client_node_id)
self.client_weave_id = self.getWeaveNodeID(self.client_node_id)
if self.server is not "service":
self.server_ip = self.getNodeWeaveIPAddress(self.server_node_id)
self.server_weave_id = self.getWeaveNodeID(self.server_node_id)
# Check if all unknowns were found
if self.client_ip == None:
emsg = "Could not find IP address of the client node."
self.logger.error("[localhost] WeaveBDX: %s" % (emsg))
sys.exit(1)
if self.server_ip == None:
emsg = "Could not find IP address of the server node."
self.logger.error("[localhost] WeaveBDX: %s" % (emsg))
sys.exit(1)
if self.client_weave_id == None:
emsg = "Could not find Weave node ID of the client node."
self.logger.error("[localhost] WeaveBDX: %s" % (emsg))
sys.exit(1)
if self.server_weave_id == None:
emsg = "Could not find Weave node ID of the server node."
self.logger.error("[localhost] WeaveBDX: %s" % (emsg))
sys.exit(1)
# Check tmp, upload, download, receive paths
if self.server is not "service":
if self.tmp == None:
emsg = "Missing path to a temporaty directory that is used by BDX server."
self.logger.error("[localhost] WeaveBDX: %s" % (emsg))
sys.exit(1)
if not os.path.isdir(self.tmp):
emsg = "The server BDX temp %s is not a directory." % (self.tmp)
self.logger.error("[localhost] WeaveBDX: %s" % (emsg))
sys.exit(1)
if self.receive == None:
emsg = "Missing path to receiving directory."
self.logger.error("[localhost] WeaveBDX: %s" % (emsg))
sys.exit(1)
if not os.path.isdir(self.receive):
emsg = "The receiving path %s is not a directory." % (self.receive)
self.logger.error("[localhost] WeaveBDX: %s" % (emsg))
sys.exit(1)
if (self.download == None and self.upload == None) or \
(self.download != None and self.upload != None):
emsg = "Either download or upload path must be specified."
self.logger.error("[localhost] WeaveBDX: %s" % (emsg))
sys.exit(1)
if self.offset != None:
self.offset = str(self.offset)
if not self.offset.isdigit():
emsg = "File offset must be a number, not %s." % (self.offset)
self.logger.error("[localhost] WeaveBDX: %s" % (emsg))
sys.exit(1)
if self.length != None:
self.length = str(self.length)
if not self.length.isdigit():
emsg = "File length must be a number, not %s." % (self.length)
self.logger.error("[localhost] WeaveBDX: %s" % (emsg))
sys.exit(1)
def __start_plaid_server(self):
self.plaid.startPlaidServerProcess()
emsg = "plaid-server should be running."
self.logger.debug("[%s] WeaveWdmNext: %s" % (self.plaid_server_node_id, emsg))
def __start_server_side(self):
if self.server_version == 0:
cmd = self.getWeaveBDXv0ServerPath()
if not cmd:
return;
cmd += " -a " + self.server_ip
if self.download != None:
cmd += " -r " + self.download
else:
cmd += " -R " + self.receive
else:
cmd = self.getWeaveBDXServerPath()
if not cmd:
return
cmd += " -a " + self.server_ip \
+ " -T " + self.tmp
if self.download != None:
# Client downloads file specified in self.download
cmd += " -R " + os.path.dirname(self.download)
else:
cmd += " -R " + self.receive
if self.tap:
cmd += " --interface " + self.tap
if self.server_faults != None:
cmd += " --faults " + self.server_faults
if self.server_faults or self.client_faults:
cmd += " --extra-cleanup-time 10000"
custom_env = {}
if self.use_plaid:
custom_env = self.plaid.getPlaidClientLibEnv(self.server_node_id)
self.start_weave_process(self.server_node_id, cmd, self.server_process_tag, strace=self.strace, env=custom_env, sync_on_output="Weave Node ready to service events")
def __start_client_side(self):
if self.client_version == 0:
cmd = self.getWeaveBDXv0ClientPath()
if not cmd:
return;
cmd += " " + self.server_weave_id + "@" + self.server_ip \
+ " -a " + self.client_ip + " -R " + self.receive + " -T" \
+ " --iterations " + str(self.iterations)
if self.download != None:
if self.server_version == 1:
cmd += " -r" + " file://" + self.download
else:
cmd += " -r " + self.download
else:
cmd += " -r " + self.upload + " -p"
else:
cmd = self.getWeaveBDXClientPath()
if not cmd:
return
if self.server is not "service":
cmd += " " + self.server_weave_id + "@" + self.server_ip \
+ " -a " + self.client_ip + " -T"
else:
cmd += " " + self.server_weave_id + "@" + self.server_ip \
+ " -a " + self.client_ip
cmd += " --iterations " + str(self.iterations)
if self.download != None:
if self.server_version == 1:
if self.server is not "service":
cmd += " -r" + " file://" + self.download + " -R " + self.receive + " -u "
else:
cmd +=" -r" + " weave-bdx://" + self.download + " -R " + self.receive + " -u "
else:
cmd += " -r " + self.download + " -R " + self.receive
else:
if self.server is not "service":
cmd += " -r " + self.upload + " -p"
else:
cmd += " -r " + self.upload + " -p -u"
if self.offset != None:
cmd += " -s " + self.offset
if self.length != None:
cmd += " -l " + self.length
if self.tap:
cmd += " --interface " + self.tap
if self.client_faults != None:
cmd += " --faults " + self.client_faults
if self.server_faults or self.client_faults:
cmd += " --extra-cleanup-time 10000"
custom_env = {}
if self.use_plaid:
custom_env = self.plaid.getPlaidClientLibEnv(self.client_node_id)
self.start_weave_process(self.client_node_id, cmd, self.client_process_tag, strace=self.strace, env=custom_env)
def __process_results(self, client_output, server_output):
parser_error = False
leak_detected = False
transfer_done = False
parser_error, leak_detected = WeaveUtilities.scan_for_leaks_and_parser_errors(client_output)
for line in client_output.split("\n"):
if "WEAVE:BDX: Transfer complete!" in line:
transfer_done = True
break
if self.quiet == False:
if self.download:
print "weave-bdx from server v%s %s (%s) to client v%s %s (%s) : " % \
(self.server_version, self.server_node_id, self.server_ip,
self.client_version, self.client_node_id, self.client_ip)
if transfer_done:
print hgreen("downloaded")
else:
print hred("not downloaded")
else:
print "weave-bdx from client %s (%s) to server %s (%s) : " % \
(self.client_node_id, self.client_ip,
self.server_node_id, self.server_ip)
if transfer_done:
print hgreen("uploaded")
else:
print hred("not uploaded")
if leak_detected:
print hred("resource leak detected in the client's ouput")
if parser_error:
print hred("parser error in the client's output")
pass_test = transfer_done and not leak_detected and not parser_error
if self.server is not "service":
# check the server for leaks and parser errors
parser_error, leak_detected = WeaveUtilities.scan_for_leaks_and_parser_errors(server_output)
if self.quiet == False:
if leak_detected:
print hred("resource leak detected in the server's ouput")
if parser_error:
print hred("parser error in the server's output")
pass_test = pass_test and not parser_error and not leak_detected
return (pass_test, client_output)
def __wait_for_client(self):
self.wait_for_test_to_end(self.client_node_id, self.client_process_tag)
def __stop_server_side(self):
self.stop_weave_process(self.server_node_id, self.server_process_tag)
def __stop_plaid_server(self):
self.plaid.stopPlaidServerProcess()
def run(self):
self.logger.debug("[localhost] WeaveBDX: Run.")
self.__pre_check()
if self.server is "service":
self.__start_client_side()
self.__wait_for_client()
client_output_value, client_output_data = \
self.get_test_output(self.client_node_id, self.client_process_tag, True)
if self.strace:
client_strace_value, client_strace_data = \
self.get_test_strace(self.client_node_id, self.client_process_tag, True)
status, results = self.__process_results(client_output_data, '')
# status = 0
data = {}
data["client_output"] = client_output_data
else:
if self.use_plaid:
self.__start_plaid_server()
self.__start_server_side()
emsg = "WeaveBDX %s should be running." % (self.server_process_tag)
self.logger.debug("[%s] WeaveBDX: %s" % (self.server_node_id, emsg))
self.__start_client_side()
self.__wait_for_client()
client_output_value, client_output_data = \
self.get_test_output(self.client_node_id, self.client_process_tag, True)
if self.strace:
client_strace_value, client_strace_data = \
self.get_test_strace(self.client_node_id, self.client_process_tag, True)
self.__stop_server_side()
if self.use_plaid:
self.__stop_plaid_server()
server_output_value, server_output_data = \
self.get_test_output(self.server_node_id, self.server_process_tag, True)
if self.strace:
server_strace_value, server_strace_data = \
self.get_test_strace(self.server_node_id, self.server_process_tag, True)
status, results = self.__process_results(client_output_data, server_output_data)
data = {}
data["client_output"] = client_output_data
data["server_output"] = server_output_data
if self.strace:
data["client_strace"] = client_strace_data
data["server_strace"] = server_strace_data
self.logger.debug("[localhost] WeaveBDX: Done.")
return ReturnMsg(status, data)