| #!/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 WeavePing class that tests Weave Echo among Weave Nodes. |
| # |
| |
| import os |
| import sys |
| |
| from happy.ReturnMsg import ReturnMsg |
| from happy.Utils import * |
| from happy.HappyNode import HappyNode |
| from happy.HappyNetwork import HappyNetwork |
| |
| from plugin.WeaveTest import WeaveTest |
| |
| |
| options = {"count": None, |
| "udp": False, |
| "tcp": False, |
| "wrmp": False, |
| "quiet": False, |
| "no_service": False, |
| "interval": None, |
| "tap": None, |
| "case": False, |
| "case_shared": False, |
| "timeout": None, |
| "client_process_tag": "WEAVE-ECHO-CLIENT", |
| "server_process_tag": "WEAVE-ECHO-SERVER", |
| "endpoint": "Echo", |
| "clients_info": [], |
| "server_node_id": None, |
| "strace": True, |
| "case_cert_path": None, |
| "case_key_path": None, |
| "use_persistent_storage": True, |
| "plaid_server_env": {}, |
| "plaid_client_env": {} |
| } |
| |
| |
| def option(): |
| return options.copy() |
| |
| |
| class WeavePing(HappyNode, HappyNetwork, WeaveTest): |
| """ |
| weave-ping [-h --help] [-q --quiet] [-o --origin <NAME>] [-s --server <NAME>] |
| [-c --count <NUMBER>] [-u --udp] [-t --tcp] [-w --wrmp] [-i --interval <ms>] [-p --tap <TAP_INTERFACE>] |
| [-C --case] [--case-shared] [-E --case_cert_path <path>] [-T --case_key_path <path>] |
| command to test weave ping over UDP: |
| $ weave-ping -o node01 -s node02 -u -i 100 -c 5 |
| |
| command to test weave ping over TCP: |
| $ weave-ping -o node01 -s node02 -t |
| |
| command to test weave ping over WRMP: |
| $ weave-ping -o node01 -s node02 -w |
| |
| command to test weave ping over WRMP and CASE: |
| $ weave-ping -o node01 -s node02 -w --case --case_cert_path path --case_key_path path |
| |
| command to test weave ping over WRMP with shared CASE session to the Nest Core Router: |
| $ weave-ping -o node01 -s node02 -w --case-shared --case_cert_path path --case_key_path path |
| |
| return: |
| 0-100 percentage of the lost packets |
| |
| """ |
| def __init__(self, opts = options): |
| HappyNode.__init__(self) |
| HappyNetwork.__init__(self) |
| WeaveTest.__init__(self) |
| self.__dict__.update(opts) |
| |
| def __pre_check(self): |
| # clear network info |
| self.clients_info = [] |
| # Make sure that fabric was created |
| if self.getFabricId() == None: |
| emsg = "Weave Fabric has not been created yet." |
| self.logger.error("[localhost] WeavePing: %s" % (emsg)) |
| sys.exit(1) |
| |
| if self.count != None and self.count.isdigit(): |
| self.count = int(float(self.count)) |
| else: |
| self.count = 1 |
| |
| for client in self.clients: |
| client_node_id = None |
| |
| # Check if Weave Ping client node is given. |
| if client == None: |
| emsg = "Missing name or address of the Weave Ping client node." |
| self.logger.error("[localhost] WeavePing: %s" % (emsg)) |
| sys.exit(1) |
| |
| # Check if Weave Ping client node exists. |
| if self._nodeExists(client): |
| client_node_id = client |
| |
| # Check if client is provided in a form of IP address |
| if self.isIpAddress(client): |
| client_node_id = self.getNodeIdFromAddress(client) |
| |
| if client_node_id == None: |
| emsg = "Unknown identity of the client node." |
| self.logger.error("[localhost] WeavePing: %s" % (emsg)) |
| sys.exit(1) |
| |
| if self.getNodeType(client_node_id) == "service": |
| client_ip = self.getServiceWeaveIPAddress(self.endpoint, client_node_id) |
| client_weave_id = self.getServiceWeaveID(self.endpoint, client_node_id) |
| else: |
| client_ip = self.getNodeWeaveIPAddress(client_node_id) |
| client_weave_id = self.getWeaveNodeID(client_node_id) |
| |
| if client_ip == None: |
| emsg = "Could not find IP address of the client node." |
| self.logger.error("[localhost] WeavePing: %s" % (emsg)) |
| sys.exit(1) |
| |
| if client_weave_id == None: |
| emsg = "Could not find Weave node ID of the client node." |
| self.logger.error("[localhost] WeavePing: %s" % (emsg)) |
| sys.exit(1) |
| |
| self.clients_info.append({'client': client, 'client_node_id': client_node_id, 'client_ip': client_ip, |
| 'client_weave_id': client_weave_id, 'client_process_tag': client + "_" + self.client_process_tag + client}) |
| |
| |
| # Check if Weave Ping server node is given. |
| if self.server == None: |
| emsg = "Missing name or address of the Weave Ping server node." |
| self.logger.error("[localhost] WeavePing: %s" % (emsg)) |
| sys.exit(1) |
| |
| # Check if Weave Ping server node exists. |
| if self._nodeExists(self.server): |
| self.server_node_id = self.server |
| |
| # Check if server is provided in a form of IP address |
| if self.isIpAddress(self.server): |
| self.no_service = True |
| self.server_ip = self.server |
| self.server_weave_id = self.IPv6toWeaveId(self.server) |
| elif self.isDomainName(self.server) or self.server == "service": |
| self.no_service = True |
| self.server_ip = self.getServiceWeaveIPAddress(self.endpoint) |
| self.server_weave_id = self.IPv6toWeaveId(self.server_ip) |
| else: |
| # Check if server is a true clound service instance |
| if self.getNodeType(self.server) == self.node_type_service: |
| self.no_service = True |
| |
| if not self.no_service and self.server_node_id == None: |
| emsg = "Unknown identity of the server node." |
| self.logger.error("[localhost] WeavePing: %s" % (emsg)) |
| sys.exit(1) |
| |
| if self.getNodeType(self.server_node_id) == "service": |
| self.server_ip = self.getServiceWeaveIPAddress(self.endpoint, self.server_node_id) |
| self.server_weave_id = self.getServiceWeaveID(self.endpoint, self.server_node_id) |
| else: |
| if not self.no_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.server_ip == None: |
| emsg = "Could not find IP address of the server node." |
| self.logger.error("[localhost] WeavePing: %s" % (emsg)) |
| sys.exit(1) |
| |
| if not self.no_service and self.server_weave_id == None: |
| emsg = "Could not find Weave node ID of the server node." |
| self.logger.error("[localhost] WeavePing: %s" % (emsg)) |
| sys.exit(1) |
| |
| |
| def __process_results(self, client_info, output): |
| # search for '%' e.g. 1/1(100.00%) |
| loss_percentage = None |
| |
| for line in output.split("\n"): |
| if not "%" in line: |
| continue |
| |
| for token in line.split(): |
| if "%" in token: |
| loss_percentage = token.strip().split("(")[1] |
| loss_percentage = loss_percentage.translate(None, "()%") |
| |
| if loss_percentage == None: |
| # hmmm, we haven't found our line |
| loss_percentage = 100 |
| else: |
| loss_percentage = float(loss_percentage) |
| loss_percentage = 100 - loss_percentage |
| |
| if self.quiet == False: |
| print "weave-ping from node %s (%s) to node %s (%s) : " % \ |
| (client_info['client_node_id'], client_info['client_ip'], |
| self.server_node_id, self.server_ip), |
| |
| if loss_percentage == 0: |
| print hgreen("%f%% packet loss" % (loss_percentage)) |
| else: |
| print hred("%f%% packet loss" % (loss_percentage)) |
| |
| return loss_percentage # indicate the loss for each client |
| |
| |
| def __start_server_side(self): |
| if self.no_service: |
| return |
| |
| cmd = self.getWeavePingPath() |
| if not cmd: |
| return |
| |
| if self.tcp: |
| cmd += " --tcp" |
| elif self.udp: |
| # default is UDP |
| cmd += " --udp" |
| elif self.wrmp: |
| cmd += " --wrmp" |
| |
| if self.tap: |
| cmd += " --interface " + self.tap |
| |
| self.start_simple_weave_server(cmd, self.server_ip, |
| self.server_node_id, self.server_process_tag, use_persistent_storage = self.use_persistent_storage, env=self.plaid_server_env) |
| |
| |
| def __start_client_side(self, client_info): |
| cmd = self.getWeavePingPath() |
| if not cmd: |
| return |
| |
| if self.tcp: |
| cmd += " --tcp" |
| elif self.udp: |
| # default is UDP |
| cmd += " --udp" |
| elif self.wrmp: |
| cmd += " --wrmp" |
| |
| if self.interval != None: |
| cmd += " --interval " + self.interval |
| |
| cmd += " --count " + str(self.count) |
| |
| if self.tap: |
| cmd += " --interface " + self.tap |
| |
| if self.case: |
| if self.case_shared: |
| cmd += " --case-shared" |
| else: |
| cmd += " --case" |
| |
| if not self.case_cert_path == 'default': |
| self.cert_file = self.case_cert_path if self.case_cert_path else os.path.join(self.main_conf['log_directory'], client_info["client_weave_id"].upper() + '-cert.weave-b64') |
| self.key_file = self.case_key_path if self.case_key_path else os.path.join(self.main_conf['log_directory'], client_info["client_weave_id"].upper() + '-key.weave-b64') |
| cmd += ' --node-cert ' + self.cert_file + ' --node-key ' + self.key_file |
| |
| self.start_simple_weave_client(cmd, client_info['client_ip'], |
| self.server_ip, self.server_weave_id, |
| client_info['client_node_id'], client_info['client_process_tag'], use_persistent_storage=self.use_persistent_storage, env=self.plaid_client_env) |
| |
| |
| def __wait_for_client(self, client_info): |
| self.wait_for_test_to_end(client_info["client_node_id"], client_info["client_process_tag"], timeout=self.timeout) |
| |
| |
| def __stop_server_side(self): |
| if self.no_service: |
| return |
| |
| self.stop_weave_process(self.server_node_id, self.server_process_tag) |
| |
| |
| def run(self): |
| all_data = [] |
| self.logger.debug("[localhost] WeavePing: Run.") |
| |
| self.__pre_check() |
| |
| self.__start_server_side() |
| |
| emsg = "WeavePing %s should be running." % (self.server_process_tag) |
| self.logger.debug("[%s] WeavePing: %s" % (self.server_node_id, emsg)) |
| |
| for client_info in self.clients_info: |
| self.__start_client_side(client_info) |
| for client_info in self.clients_info: |
| self.__wait_for_client(client_info) |
| for client_info in self.clients_info: |
| client_output_value, client_output_data = \ |
| self.get_test_output(client_info['client_node_id'], client_info['client_process_tag'], True) |
| client_strace_value, client_strace_data = \ |
| self.get_test_strace(client_info['client_node_id'], client_info['client_process_tag'], True) |
| |
| if self.no_service: |
| server_output_data = "" |
| server_strace_data = "" |
| else: |
| self.__stop_server_side() |
| server_output_value, server_output_data = \ |
| self.get_test_output(self.server_node_id, self.server_process_tag, True) |
| server_strace_value, server_strace_data = \ |
| self.get_test_strace(self.server_node_id, self.server_process_tag, True) |
| |
| loss_percentage = self.__process_results(client_info, client_output_data) |
| |
| data = {} |
| data.update(client_info) |
| 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 |
| all_data.append(data) |
| |
| self.logger.debug("[localhost] WeavePing: Done.") |
| |
| return ReturnMsg(loss_percentage, all_data) |
| |