| #!/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 WeavePairing class that tests Weave Pairing among Weave node and device manager. |
| # |
| |
| import os |
| import random |
| import re |
| import sys |
| import time |
| |
| from happy.ReturnMsg import ReturnMsg |
| from happy.utils.IP import IP |
| from happy.HappyNode import HappyNode |
| from happy.HappyNetwork import HappyNetwork |
| |
| from WeaveTest import WeaveTest |
| |
| |
| options = {"quiet": False, |
| "mobile": None, |
| "device": None, |
| "server": None, |
| "tap": None, |
| "tier": None, |
| "username": None, |
| "password": None, |
| "devices_info": [], |
| 'mobile_process_tag': "WEAVE-PAIRING-MOBILE", |
| 'device_process_tag': "WEAVE-PAIRING-DEVICE", |
| 'server_process_tag': "WEAVE-PAIRING-SERVER", |
| 'mobile_node_id': None, |
| 'server_node_id': None, |
| 'register_cmd': None} |
| |
| |
| def option(): |
| return options.copy() |
| |
| |
| class WeavePairing(HappyNode, HappyNetwork, WeaveTest): |
| """ |
| weave-pairing [-h --help] [-q --quiet] [-m --mobile <NAME>] [-d --device <NAME>] [-s --server <NAME>] |
| |
| command to test pairing using a local mock server: |
| $ weave-pairing --mobile node01 --device node02 --server node03 |
| |
| command to test pairing using the default Weave ServiceProvisioning node-id over the internet: |
| $ weave-pairing --mobile node01 --device node02 --server service |
| |
| command to test pairing using a custom Weave ServiceProvisioning server over the internet: |
| $ weave-pairing --mobile node01 --device node02 --server <ip address> |
| |
| return: |
| 0 success |
| 1 failure |
| |
| """ |
| |
| def __init__(self, opts=options): |
| HappyNode.__init__(self) |
| HappyNetwork.__init__(self) |
| WeaveTest.__init__(self) |
| self.__dict__.update(opts) |
| |
| def __pre_check(self): |
| device_node_id = None |
| # Set the produce resource that mock-device is paired to |
| resourceDictionaries = self.getResourceIds() |
| resourceIndexList = os.environ.get("RESOURCE_IDS", "thd1").split(" ") |
| self.resources = [resourceDictionaries[resourceIndex] |
| for resourceIndex in resourceIndexList] |
| # Check if Weave Pairing device node is given. |
| if self.devices is None: |
| emsg = "Missing name or address of the Weave Pairing device node." |
| self.logger.error("[localhost] WeavePairing: %s" % (emsg)) |
| sys.exit(1) |
| |
| # Check if Weave Pairing mobile node is given. |
| if self.mobile is None: |
| emsg = "Missing name or address of the Weave Pairing mobile node." |
| self.logger.error("[localhost] WeavePairing: %s" % (emsg)) |
| sys.exit(1) |
| |
| # Check if Weave Pairing server info is given. |
| if self.server is None: |
| emsg = "Missing name or address of the Weave Pairing server node." |
| self.logger.error("[localhost] WeavePairing: %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] WeavePairing: %s" % (emsg)) |
| sys.exit(1) |
| |
| # Check if Weave Pairing mobile node exists. |
| if self._nodeExists(self.mobile): |
| self.mobile_node_id = self.mobile |
| |
| # Check if mobile is provided in a form of IP address |
| if IP.isIpAddress(self.mobile): |
| self.mobile_node_id = self.getNodeIdFromAddress(self.mobile) |
| |
| if self.mobile_node_id is None: |
| emsg = "Unknown identity of the mobile node." |
| self.logger.error("[localhost] WeavePairing: %s" % (emsg)) |
| sys.exit(1) |
| |
| # Find out whether to use a local mock server or a server |
| # reachable over the internet |
| if self._nodeExists(self.server): |
| self.server_node_id = self.server |
| self.server_ip = self.getNodeWeaveIPAddress(self.server_node_id) |
| self.server_weave_id = self.getWeaveNodeID(self.server_node_id) |
| elif IP.isIpAddress(self.server): |
| self.server_ip = self.server |
| self.server_weave_id = self.IPv6toWeaveId(self.server) |
| elif IP.isDomainName(self.server) or self.server == "service": |
| self.server_ip = self.getServiceWeaveIPAddress("ServiceProvisioning") |
| self.server_weave_id = self.IPv6toWeaveId(self.server_ip) |
| |
| self.mobile_ip = self.getNodeWeaveIPAddress(self.mobile_node_id) |
| |
| self.mobile_weave_id = self.getWeaveNodeID(self.mobile_node_id) |
| |
| for device, resource in zip(self.devices, self.resources): |
| # Check if Weave Pairing device node exists. |
| if self._nodeExists(device): |
| device_node_id = device |
| # Check if device is provided in a form of IP address |
| if IP.isIpAddress(device): |
| device_node_id = self.getNodeIdFromAddress(device) |
| |
| if device_node_id is None: |
| emsg = "Unknown identity of the device node." |
| self.logger.error("[localhost] WeavePairing: %s" % (emsg)) |
| sys.exit(1) |
| |
| device_ip = self.getNodeWeaveIPAddress(device_node_id) |
| device_weave_id = self.getWeaveNodeID(device_node_id) |
| |
| if device_ip is None: |
| emsg = "Could not find IP address of the device node." |
| self.logger.error("[localhost] WeavePairing: %s" % (emsg)) |
| sys.exit(1) |
| |
| if device_weave_id is None: |
| emsg = "Could not find Weave node ID of the device node." |
| self.logger.error("[localhost] WeavePairing: %s" % (emsg)) |
| sys.exit(1) |
| self.devices_info.append({'device': device, 'device_node_id': device_node_id, 'device_ip': device_ip, |
| 'device_weave_id': device_weave_id, 'device_process_tag': device + "_" + self.device_process_tag, 'resource': resource}) |
| |
| if self.mobile_ip is None: |
| emsg = "Could not find IP address of the mobile node." |
| self.logger.error("[localhost] WeavePairing: %s" % (emsg)) |
| sys.exit(1) |
| |
| if self.mobile_weave_id is None: |
| emsg = "Could not find Weave node ID of the mobile node." |
| self.logger.error("[localhost] WeavePairing: %s" % (emsg)) |
| sys.exit(1) |
| |
| if self.server_ip is None: |
| emsg = "Could not find IP address of the server." |
| self.logger.error("[localhost] WeavePairing: %s" % (emsg)) |
| sys.exit(1) |
| |
| if self.server_weave_id is None: |
| emsg = "Could not find Weave node ID of the server." |
| self.logger.error("[localhost] WeavePairing: %s" % (emsg)) |
| sys.exit(1) |
| |
| def getResourceIds(self): |
| resource_ids = {} |
| |
| resource_ids['np1'] = {} |
| resource_ids['np1']['vendor_id'] = '9050' |
| resource_ids['np1']['software_id'] = '1.0' |
| resource_ids['np1']['product_id'] = '8' |
| resource_ids['np1']['id'] = 'np1' |
| |
| resource_ids['nf1'] = {} |
| resource_ids['nf1']['vendor_id'] = '9050' |
| resource_ids['nf1']['software_id'] = '1.0' |
| resource_ids['nf1']['product_id'] = '12' |
| resource_ids['nf1']['id'] = 'nf1' |
| |
| resource_ids['nan1'] = {} |
| resource_ids['nan1']['vendor_id'] = '9050' |
| resource_ids['nan1']['software_id'] = '1.0' |
| resource_ids['nan1']['product_id'] = '22' |
| resource_ids['nan1']['id'] = 'nan1' |
| |
| resource_ids['ntl2'] = {} |
| resource_ids['ntl2']['vendor_id'] = '9050' |
| resource_ids['ntl2']['software_id'] = '1.0' |
| resource_ids['ntl2']['product_id'] = '32' |
| resource_ids['ntl2']['id'] = 'ntl2' |
| |
| resource_ids['ntb2'] = {} |
| resource_ids['ntb2']['vendor_id'] = '9050' |
| resource_ids['ntb2']['software_id'] = '1.0' |
| resource_ids['ntb2']['product_id'] = '33' |
| resource_ids['ntb2']['id'] = 'ntb2' |
| |
| resource_ids['gn1'] = {} |
| resource_ids['gn1']['vendor_id'] = '57600' |
| resource_ids['gn1']['software_id'] = '1.0' |
| resource_ids['gn1']['product_id'] = '1' |
| resource_ids['gn1']['id'] = 'gn1' |
| |
| resource_ids['gv1'] = {} |
| resource_ids['gv1']['vendor_id'] = '57600' |
| resource_ids['gv1']['software_id'] = '1.0' |
| resource_ids['gv1']['product_id'] = '3' |
| resource_ids['gv1']['id'] = 'gv1' |
| |
| resource_ids['gm1'] = {} |
| resource_ids['gm1']['vendor_id'] = '57600' |
| resource_ids['gm1']['software_id'] = '1.0' |
| resource_ids['gm1']['product_id'] = '4' |
| resource_ids['gm1']['id'] = 'gm1' |
| |
| resource_ids['gsl1'] = {} |
| resource_ids['gsl1']['vendor_id'] = '57600' |
| resource_ids['gsl1']['software_id'] = '1.0' |
| resource_ids['gsl1']['product_id'] = '65024' |
| resource_ids['gsl1']['id'] = 'gsl1' |
| |
| resource_ids['gsrbr1'] = {} |
| resource_ids['gsrbr1']['vendor_id'] = '57600' |
| resource_ids['gsrbr1']['software_id'] = '1.0' |
| resource_ids['gsrbr1']['product_id'] = '65025' |
| resource_ids['gsrbr1']['id'] = 'gsrbr1' |
| |
| resource_ids['thd1'] = {} |
| resource_ids['thd1']['vendor_id'] = '9050' |
| resource_ids['thd1']['software_id'] = '1.0' |
| resource_ids['thd1']['product_id'] = '65534' |
| resource_ids['thd1']['id'] = 'thd1' |
| |
| resource_ids['tst1'] = {} |
| resource_ids['tst1']['vendor_id'] = '9050' |
| resource_ids['tst1']['software_id'] = '1.0' |
| resource_ids['tst1']['product_id'] = '65024' |
| resource_ids['tst1']['id'] = 'tst1' |
| |
| return resource_ids |
| |
| def __start_server(self): |
| cmd = self.getWeaveMockDevicePath() |
| if not cmd: |
| return |
| |
| cmd += " --node-addr " + self.server_ip |
| if self.tap: |
| cmd += " --tap-device " + self.tap |
| |
| self.start_weave_process( |
| self.server_node_id, |
| cmd, |
| self.server_process_tag, |
| sync_on_output=self.ready_to_service_events_str) |
| |
| def __start_mobile_side(self, device_info, mobile_process_tag): |
| os.environ['WEAVE_DEVICE_MGR_PATH'] = self.getWeaveDeviceMgrPath() |
| os.environ['WEAVE_DEVICE_MGR_LIB_PATH'] = self.getWeaveDeviceMgrLibPath() |
| cmd = "/usr/bin/env python " + \ |
| os.path.dirname(os.path.realpath(__file__)) + "/../lib/WeaveDeviceManager.py" |
| if not cmd: |
| return |
| |
| cmd += " " + device_info['device_ip'] + " " + device_info['device_weave_id'] |
| cmd += " --pairing-code TEST" |
| |
| if self.server is not None and not self.server_node_id: |
| if not self.register_cmd: |
| import ServiceAccountManager |
| options = ServiceAccountManager.option() |
| options["tier"] = self.tier |
| options["username"] = self.username |
| options["password"] = self.password |
| |
| registration = ServiceAccountManager.ServiceAccountManager(self.logger, options) |
| self.register_cmd = registration.run() |
| |
| if self.register_cmd: |
| cmd += self.register_cmd |
| else: |
| raise ValueError('register_cmd is empty') |
| |
| if self.tap: |
| cmd += " --tap-device " + self.tap |
| |
| self.start_weave_process(self.mobile_node_id, cmd, mobile_process_tag, env=os.environ) |
| |
| def __start_device_side(self, device_info): |
| cmd = self.getWeaveMockDevicePath() |
| if not cmd: |
| return |
| |
| cmd += " --node-addr " + device_info['device_ip'] + " --pairing-code TEST" |
| cmd += " --wdm-resp-mutual-sub --test-case 10 --total-count 0 --wdm-update-timing NoSub " |
| |
| if self.server is not None: |
| cmd += " --pairing-server " + self.server_ip \ |
| + " --wrm-pairing" \ |
| + " --vendor-id " + device_info['resource']['vendor_id'] \ |
| + " --software-version " + '"' + device_info['resource']['software_id'] + '"' \ |
| + " --product-id " + device_info['resource']['product_id'] \ |
| + " --suppress-ac" # Suppress access controls to work around WEAV-2024 |
| |
| if self.server_node_id is not None: |
| # if the server is a local mock, we need to override the default endpoint id |
| cmd += " --pairing-endpoint-id " + self.server_weave_id |
| |
| if self.tap: |
| cmd += " --tap-device " + self.tap |
| |
| self.start_weave_process( |
| device_info['device_node_id'], |
| cmd, |
| device_info['device_process_tag'], |
| sync_on_output=self.ready_to_service_events_str) |
| |
| def __process_results(self, mobiles_output, devices_info): |
| result_list = [] |
| for mobile_output in mobiles_output: |
| if "Shutdown complete" in mobile_output: |
| result_list.append(True) |
| else: |
| result_list.append(False) |
| |
| for device_info, result in zip(devices_info, result_list): |
| print " %s weave-pairing from mobile %s (%s) to device %s (%s) : " % \ |
| ("Success for" if result else "Fail for", self.mobile_node_id, |
| self.mobile_ip, device_info['device_node_id'], device_info['device_ip']) |
| |
| return result_list |
| |
| def __wait_for_mobile(self, mobile_process_tag): |
| self.wait_for_test_to_end(self.mobile_node_id, mobile_process_tag) |
| |
| def __stop_device_side(self, device_info): |
| self.stop_weave_process(device_info['device_node_id'], device_info['device_process_tag']) |
| |
| def __stop_server_side(self): |
| self.stop_weave_process(self.server_node_id, self.server_process_tag) |
| |
| def run(self): |
| self.logger.debug("[localhost] WeavePairing: Run.") |
| |
| self.__pre_check() |
| |
| devices_output_data = [] |
| devices_strace_data = [] |
| mobiles_output_data = [] |
| mobiles_strace_data = [] |
| |
| for device_info in self.devices_info: |
| self.__start_device_side(device_info) |
| # delay Execution |
| time.sleep(0.5) |
| |
| emsg = "WeavePairing %s should be running." % (device_info['device_process_tag']) |
| self.logger.debug("[%s] WeavePairing: %s" % (device_info['device_node_id'], emsg)) |
| |
| if self.server_node_id: |
| self.__start_server() |
| mobile_process_tag = self.mobile_process_tag + device_info['device'] |
| self.__start_mobile_side(device_info, mobile_process_tag) |
| self.__wait_for_mobile(mobile_process_tag) |
| |
| mobile_output_value, mobile_output_data = \ |
| self.get_test_output(self.mobile_node_id, mobile_process_tag, True) |
| mobile_strace_value, mobile_strace_data = \ |
| self.get_test_strace(self.mobile_node_id, mobile_process_tag, True) |
| |
| self.__stop_device_side(device_info) |
| |
| device_output_value, device_output_data = \ |
| self.get_test_output( |
| device_info['device_node_id'], |
| device_info['device_process_tag'], |
| True) |
| device_strace_value, device_strace_data = \ |
| self.get_test_strace( |
| device_info['device_node_id'], |
| device_info['device_process_tag'], |
| True) |
| |
| devices_output_data.append(device_output_data) |
| devices_strace_data.append(device_strace_data) |
| mobiles_output_data.append(mobile_output_data) |
| mobiles_strace_data.append(mobile_strace_data) |
| # delay execution |
| time.sleep(3) |
| server_output_value = None |
| server_output_data = None |
| server_strace_value = None |
| server_strace_data = None |
| |
| if self.server_node_id: |
| 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) |
| |
| result_list = self.__process_results(mobiles_output_data, self.devices_info) |
| |
| data = {} |
| data["devices_output"] = devices_output_data |
| data["devices_strace"] = devices_strace_data |
| data["mobiles_output"] = mobiles_output_data |
| data["mobiles_strace"] = mobiles_strace_data |
| data["server_output"] = server_output_data |
| data["server_strace"] = server_strace_data |
| data["devices_info"] = self.devices_info |
| |
| self.logger.debug("[localhost] WeavePairing: Done.") |
| return ReturnMsg(result_list, data) |