image_test/network/network-tester.py (83 lines of code) (raw):

#!/usr/bin/env python3 # Copyright 2018 Google 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. import logging import time import urllib.error import urllib.request from google import auth from googleapiclient import discovery import netaddr import utils class RequestError(Exception): def __init__(self, name, instance, ip_range, positive_test=True): self.name = name self.instance = instance self.ip_range = ip_range self.positive_test = positive_test def __str__(self): text = "%s didn't redirect ip traffic from %s to instance %s" if not self.positive_test: text = "%s redirected ip traffic from %s to instance %s but it shouldn't" return text % (self.name, self.ip_range, self.instance) def _RequestInfo(URL, timeout=10): logging.info('Retrieving: %s' % URL) request = urllib.request.Request(URL) return urllib.request.urlopen(request).read().decode() def RequestOS(addr): return _RequestInfo("http://%s/os" % addr) def RequestHostname(addr): return _RequestInfo("http://%s/hostname" % addr) def TestIPAlias(instance, ip_alias, ip_mask): testee_hostname = RequestHostname(instance) cidr = "%s/%s" % (ip_alias, ip_mask) # caching ips out of range for using it on negative tests ips = [str(ip) for ip in netaddr.IPNetwork( "{}/{}".format(ip_alias, ip_mask))] # positive test on expected IPs for ip in ips: try: if testee_hostname != RequestHostname(ip): raise Exception("Alias hostname should be the same from host machine.") except urllib.error.URLError: raise RequestError("ip_alias", instance, cidr) # negative test superset_ips = [str(ip) for ip in netaddr.IPNetwork( "{}/{}".format(ip_alias, int(ip_mask) - 1))] invalid_ip = superset_ips[superset_ips.index(ips[0]) - 1] try: if testee_hostname == RequestHostname(invalid_ip): raise RequestError("ip_alias", instance, cidr, positive_test=False) except urllib.error.URLError: # great, it didn't even respond! So no machine is using that ip. pass def SetIPAlias(MD, instance, ip_alias=None, ip_mask=None): # by default, remove the aliasing alias_ip_ranges = [] if ip_alias: cidr = "%s/%s" % (ip_alias, ip_mask) alias_ip_ranges = [{'ipCidrRange': cidr}] info = { 'aliasIpRanges': alias_ip_ranges, # a previous fingerprint is needed in order to change the instance 'fingerprint': MD.GetInstanceIfaces(instance)[0][u'fingerprint'] } MD.Wait(MD.SetInstanceIface(instance, info)) # The operation is completed but it might not guarantee that the agent has # already applied the rule. For that reason, wait time.sleep(30) def TestForwardingRule(MD, instance, rule_name): ip = MD.GetForwardingRuleIP(rule_name) if RequestHostname(instance) != RequestHostname(ip): raise RequestError(rule_name, instance, ip) def main(): MM = utils.MetadataManager testee = MM.FetchMetadataDefault('testee') alias_ip = MM.FetchMetadataDefault('alias_ip') alias_ip_mask = MM.FetchMetadataDefault('alias_ip_mask') credentials, _ = auth.default() compute = utils.GetCompute(discovery, credentials) MD = MM(compute, testee) # Verify IP aliasing is working: not available on Windows environment if RequestOS(testee) != 'windows': # 1) Testing if it works on creation time TestIPAlias(testee, alias_ip, alias_ip_mask) # 2) Removing it and guaranteeing that it doesn't work anymore SetIPAlias(MD, testee, []) try: TestIPAlias(testee, alias_ip, alias_ip_mask) except RequestError as e: # the positive test is expected to fail, as no alias ip exists. if not e.positive_test: raise e # 3) Re-add it while the machine is running and verify that it works SetIPAlias(MD, testee, alias_ip, alias_ip_mask) TestIPAlias(testee, alias_ip, alias_ip_mask) # Ensure routes are added when ForwardingRules are created testee_fr = MM.FetchMetadataDefault('testee_forwarding_rule') TestForwardingRule(MD, testee, testee_fr) if __name__ == '__main__': utils.RunTest(main)