We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
imagePullPolicy is set to Always
We should have a more sensible setup for our default YAML

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `end-to-end/demotest.py`
Content:
```
1 #!/usr/bin/env python
2 
3 import sys
4 
5 import json
6 import os
7 import requests
8 import time
9 import yaml
10 
11 # Yes, it's a terrible idea to use skip cert verification for TLS.
12 # We really don't care for this test though.
13 import urllib3
14 urllib3.disable_warnings()
15 
16 def call(url, headers=None, iterations=1):
17     got = {}
18 
19     for x in range(iterations):
20         # Yes, it's a terrible idea to use skip cert verification for TLS.
21         # We really don't care for this test though.
22         result = requests.get(url, headers=headers, verify=False)
23         version = 'unknown'
24 
25         sys.stdout.write('.')
26         sys.stdout.flush()
27 
28         if result.status_code != 200:
29             version='failure %d' % result.status_code
30         elif result.text.startswith('VERSION '):
31             version=result.text[len('VERSION '):]
32         else:
33             version='unknown %s' % result.text
34 
35         got.setdefault(version, 0)
36         got[version] += 1
37 
38     sys.stdout.write("\n")
39     sys.stdout.flush()
40     
41     return got
42 
43 def test_demo(base, v2_wanted):
44     url = "%s/demo/" % base
45 
46     attempts = 3
47 
48     while attempts > 0:
49         print("2.0.0: attempts left %d" % attempts)
50         got = call(url, iterations=1000)
51 
52         print(got)
53         v2_seen = ((got.get('2.0.0', 0) + 5) // 10)
54         delta = abs(v2_seen - v2_wanted)
55         rc = (delta <= 2)
56 
57         print("2.0.0: wanted %d, got %d (delta %d) => %s" % 
58               (v2_wanted, v2_seen, delta, "pass" if rc else "FAIL"))
59 
60         if rc:
61             return rc
62 
63         attempts -= 1
64         print("waiting for retry")
65         time.sleep(5)
66 
67     return False
68 
69 def test_from_yaml(base, yaml_path):
70     spec = yaml.safe_load(open(yaml_path, "r"))
71 
72     url = spec['url'].replace('{BASE}', base)
73 
74     test_num = 0
75     rc = True
76 
77     for test in spec['tests']:
78         test_num += 1
79         name = test.get('name', "%s.%d" % (os.path.basename(yaml_path), test_num))
80 
81         headers = test.get('headers', None)
82         host = test.get('host', None)
83         versions = test.get('versions', None)
84         iterations = test.get('iterations', 100)
85 
86         if not versions:
87             print("missing versions in %s?" % name)
88             print("%s" % yaml.safe_dump(test))
89             return False
90 
91         if host:
92             if not headers:
93                 headers = {}
94 
95             headers['Host'] = host
96 
97         attempts = 3
98 
99         while attempts > 0:
100             print("%s: attempts left %d" % (name, attempts))
101             print("%s: headers %s" % (name, headers))
102 
103             got = call(url, headers=headers, iterations=iterations)
104 
105             print("%s: %s" % (name, json.dumps(got)))
106 
107             test_ok = True
108 
109             for version, wanted_count in versions.items():
110                 got_count = got.get(version, 0)
111                 delta = abs(got_count - wanted_count)
112 
113                 print("%s %s: wanted %d, got %d (delta %d)" % 
114                       (name, version, wanted_count, got_count, delta))
115 
116                 if delta > 2:
117                     test_ok = False
118 
119             if test_ok:
120                 print("%s: passed" % name)
121                 break
122             else:
123                 attempts -= 1
124 
125                 if attempts <= 0:
126                     print("%s: FAILED" % name)
127                     rc = False
128 
129     return rc
130 
131 if __name__ == "__main__":
132     base = sys.argv[1]
133 
134     if not (base.startswith("http://") or base.startswith("https://")):
135         base = "http://%s" % base
136 
137     v2_percent = None
138 
139     try:
140         v2_percent = int(sys.argv[2])
141     except ValueError:
142         pass
143 
144     if v2_percent != None:
145         rc = test_demo(base, v2_percent)
146     else:
147         rc = test_from_yaml(base, sys.argv[2])
148 
149     if rc:
150         sys.exit(0)
151     else:
152         print("FAILED")
153         sys.exit(1)
154
```

Path: `ambassador/ambassador/mapping.py`
Content:
```
1 import hashlib
2 
3 from .utils import SourcedDict
4 
5 class Mapping (object):
6     @classmethod
7     def group_id(klass, method, prefix, headers):
8         # Yes, we're using a  cryptographic hash here. Cope. [ :) ]
9 
10         h = hashlib.new('sha1')
11         h.update(method.encode('utf-8'))
12         h.update(prefix.encode('utf-8'))
13 
14         for hdr in headers:
15             h.update(hdr['name'].encode('utf-8'))
16 
17             if 'value' in hdr:
18                 h.update(hdr['value'].encode('utf-8'))
19 
20         return h.hexdigest()
21 
22     @classmethod
23     def route_weight(klass, route):
24         prefix = route['prefix']
25         method = route.get('method', 'GET')
26         headers = route.get('headers', [])
27 
28         weight = [ len(prefix) + len(headers), prefix, method ]
29         weight += [ hdr['name'] + '-' + hdr.get('value', '*') for hdr in headers ]
30 
31         return tuple(weight)
32 
33     TransparentRouteKeys = {
34         "host_redirect": True,
35         "path_redirect": True,
36         "host_rewrite": True,
37         "auto_host_rewrite": True,
38         "case_sensitive": True,
39         "use_websocket": True,
40         "timeout_ms": True,
41         "priority": True,
42     }
43 
44     def __init__(self, _source="--internal--", _from=None, **kwargs):
45         # Save the raw input...
46         self.attrs = dict(**kwargs)
47 
48         if _from and ('_source' in _from):
49             self.attrs['_source'] = _from['_source']
50         else:
51             self.attrs['_source'] = _source
52 
53         # ...and cache some useful first-class stuff.
54         self.name = self['name']
55         self.kind = self['kind']
56         self.prefix = self['prefix']
57         self.method = self.get('method', 'GET')
58 
59         # Next up, build up the headers. We do this unconditionally at init
60         # time because we need the headers to work out the group ID.
61         self.headers = []
62 
63         for name, value in self.get('headers', {}).items():
64             if value == True:
65                 self.headers.append({ "name": name })
66             else:
67                 self.headers.append({ "name": name, "value": value, "regex": False })
68 
69         for name, value in self.get('regex_headers', []):
70             self.headers.append({ "name": name, "value": value, "regex": True })
71 
72         if 'host' in self.attrs:
73             self.headers.append({
74                 "name": ":authority",
75                 "value": self['host'],
76                 "regex": self.get('host_regex', False)
77             })
78 
79         if 'method' in self.attrs:
80             self.headers.append({
81                 "name": ":method",
82                 "value": self['method'],
83                 "regex": self.get('method_regex', False)
84             })
85 
86         # OK. After all that we can compute the group ID.
87         self.group_id = Mapping.group_id(self.method, self.prefix, self.headers)
88 
89     def __getitem__(self, key):
90         return self.attrs[key]
91 
92     def get(self, key, *args):
93         if len(args) > 0:
94             return self.attrs.get(key, args[0])
95         else:
96             return self.attrs.get(key)
97 
98     def new_route(self, cluster_name):
99         route = SourcedDict(
100             _source=self['_source'],
101             _group_id=self.group_id,
102             prefix=self.prefix,
103             prefix_rewrite=self.get('rewrite', '/'),
104             clusters=[ { "name": cluster_name,
105                          "weight": self.get("weight", None) } ]
106         )
107 
108         if self.headers:
109             route['headers'] = self.headers
110 
111         # Even though we don't use it for generating the Envoy config, go ahead
112         # and make sure that any ':method' header match gets saved under the
113         # route's '_method' key -- diag uses it to make life easier.
114 
115         route['_method'] = self.method
116 
117         # We refer to this route, of course.
118         route._mark_referenced_by(self['_source'])
119 
120         # There's a slew of things we'll just copy over transparently; handle
121         # those.
122 
123         for key, value in self.attrs.items():
124             if key in Mapping.TransparentRouteKeys:
125                 route[key] = value
126 
127         # Done!
128         return route
129 
130 if __name__ == "__main__":
131     import sys
132 
133     import json
134     import os
135 
136     import yaml
137 
138     for path in sys.argv[1:]:
139         try:
140             # XXX This is a bit of a hack -- yaml.safe_load_all returns a
141             # generator, and if we don't use list() here, any exception
142             # dealing with the actual object gets deferred 
143             objects = list(yaml.safe_load_all(open(path, "r")))
144         except Exception as e:
145             print("%s: could not parse YAML: %s" % (path, e))
146             continue
147 
148         ocount = 0
149         for obj in objects:
150             ocount += 1
151             srckey = "%s.%d" % (path, ocount)
152 
153             if obj['kind'] == 'Mapping':
154                 m = Mapping(srckey, **obj)
155 
156                 print("%s: %s" % (m.name, m.group_id))
157 
158                 print(json.dumps(m.new_route("test_cluster"), indent=4, sort_keys=True))
159
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/ambassador/ambassador/mapping.py b/ambassador/ambassador/mapping.py
--- a/ambassador/ambassador/mapping.py
+++ b/ambassador/ambassador/mapping.py
@@ -31,14 +31,14 @@
         return tuple(weight)
 
     TransparentRouteKeys = {
-        "host_redirect": True,
-        "path_redirect": True,
-        "host_rewrite": True,
         "auto_host_rewrite": True,
         "case_sensitive": True,
-        "use_websocket": True,
-        "timeout_ms": True,
+        "host_redirect": True,
+        "host_rewrite": True,
+        "path_redirect": True,
         "priority": True,
+        "timeout_ms": True,
+        "use_websocket": True,
     }
 
     def __init__(self, _source="--internal--", _from=None, **kwargs):
@@ -108,6 +108,12 @@
         if self.headers:
             route['headers'] = self.headers
 
+        add_request_headers = self.get('add_request_headers')
+        if add_request_headers:
+            route['request_headers_to_add'] = []
+            for key, value in add_request_headers.items():
+              route['request_headers_to_add'].append({"key": key, "value": value})
+
         # Even though we don't use it for generating the Envoy config, go ahead
         # and make sure that any ':method' header match gets saved under the
         # route's '_method' key -- diag uses it to make life easier.
diff --git a/end-to-end/demotest.py b/end-to-end/demotest.py
--- a/end-to-end/demotest.py
+++ b/end-to-end/demotest.py
@@ -8,6 +8,8 @@
 import time
 import yaml
 
+DEFAULT_ITERATIONS=500
+
 # Yes, it's a terrible idea to use skip cert verification for TLS.
 # We really don't care for this test though.
 import urllib3
@@ -40,17 +42,22 @@
     
     return got
 
+def to_percentage(count, iterations):
+    bias = iterations // 2
+    return ((count * 100) + bias) // iterations
+
 def test_demo(base, v2_wanted):
     url = "%s/demo/" % base
 
     attempts = 3
+    iterations = DEFAULT_ITERATIONS
 
     while attempts > 0:
         print("2.0.0: attempts left %d" % attempts)
-        got = call(url, iterations=1000)
+        got = call(url, iterations=iterations)
 
         print(got)
-        v2_seen = ((got.get('2.0.0', 0) + 5) // 10)
+        v2_seen = to_percentage(got.get('2.0.0', 0), iterations)
         delta = abs(v2_seen - v2_wanted)
         rc = (delta <= 2)
 
@@ -81,7 +88,7 @@
         headers = test.get('headers', None)
         host = test.get('host', None)
         versions = test.get('versions', None)
-        iterations = test.get('iterations', 100)
+        iterations = test.get('iterations', DEFAULT_ITERATIONS)
 
         if not versions:
             print("missing versions in %s?" % name)
@@ -107,7 +114,8 @@
             test_ok = True
 
             for version, wanted_count in versions.items():
-                got_count = got.get(version, 0)
+                # Convert iterations to percent.
+                got_count = to_percentage(got.get(version, 0), iterations)
                 delta = abs(got_count - wanted_count)
 
                 print("%s %s: wanted %d, got %d (delta %d)" %

{"golden_diff": "diff --git a/ambassador/ambassador/mapping.py b/ambassador/ambassador/mapping.py\n--- a/ambassador/ambassador/mapping.py\n+++ b/ambassador/ambassador/mapping.py\n@@ -31,14 +31,14 @@\n         return tuple(weight)\n \n     TransparentRouteKeys = {\n-        \"host_redirect\": True,\n-        \"path_redirect\": True,\n-        \"host_rewrite\": True,\n         \"auto_host_rewrite\": True,\n         \"case_sensitive\": True,\n-        \"use_websocket\": True,\n-        \"timeout_ms\": True,\n+        \"host_redirect\": True,\n+        \"host_rewrite\": True,\n+        \"path_redirect\": True,\n         \"priority\": True,\n+        \"timeout_ms\": True,\n+        \"use_websocket\": True,\n     }\n \n     def __init__(self, _source=\"--internal--\", _from=None, **kwargs):\n@@ -108,6 +108,12 @@\n         if self.headers:\n             route['headers'] = self.headers\n \n+        add_request_headers = self.get('add_request_headers')\n+        if add_request_headers:\n+            route['request_headers_to_add'] = []\n+            for key, value in add_request_headers.items():\n+              route['request_headers_to_add'].append({\"key\": key, \"value\": value})\n+\n         # Even though we don't use it for generating the Envoy config, go ahead\n         # and make sure that any ':method' header match gets saved under the\n         # route's '_method' key -- diag uses it to make life easier.\ndiff --git a/end-to-end/demotest.py b/end-to-end/demotest.py\n--- a/end-to-end/demotest.py\n+++ b/end-to-end/demotest.py\n@@ -8,6 +8,8 @@\n import time\n import yaml\n \n+DEFAULT_ITERATIONS=500\n+\n # Yes, it's a terrible idea to use skip cert verification for TLS.\n # We really don't care for this test though.\n import urllib3\n@@ -40,17 +42,22 @@\n     \n     return got\n \n+def to_percentage(count, iterations):\n+    bias = iterations // 2\n+    return ((count * 100) + bias) // iterations\n+\n def test_demo(base, v2_wanted):\n     url = \"%s/demo/\" % base\n \n     attempts = 3\n+    iterations = DEFAULT_ITERATIONS\n \n     while attempts > 0:\n         print(\"2.0.0: attempts left %d\" % attempts)\n-        got = call(url, iterations=1000)\n+        got = call(url, iterations=iterations)\n \n         print(got)\n-        v2_seen = ((got.get('2.0.0', 0) + 5) // 10)\n+        v2_seen = to_percentage(got.get('2.0.0', 0), iterations)\n         delta = abs(v2_seen - v2_wanted)\n         rc = (delta <= 2)\n \n@@ -81,7 +88,7 @@\n         headers = test.get('headers', None)\n         host = test.get('host', None)\n         versions = test.get('versions', None)\n-        iterations = test.get('iterations', 100)\n+        iterations = test.get('iterations', DEFAULT_ITERATIONS)\n \n         if not versions:\n             print(\"missing versions in %s?\" % name)\n@@ -107,7 +114,8 @@\n             test_ok = True\n \n             for version, wanted_count in versions.items():\n-                got_count = got.get(version, 0)\n+                # Convert iterations to percent.\n+                got_count = to_percentage(got.get(version, 0), iterations)\n                 delta = abs(got_count - wanted_count)\n \n                 print(\"%s %s: wanted %d, got %d (delta %d)\" %\n", "issue": "imagePullPolicy is set to Always\nWe should have a more sensible setup for our default YAML\n", "before_files": [{"content": "#!/usr/bin/env python\n\nimport sys\n\nimport json\nimport os\nimport requests\nimport time\nimport yaml\n\n# Yes, it's a terrible idea to use skip cert verification for TLS.\n# We really don't care for this test though.\nimport urllib3\nurllib3.disable_warnings()\n\ndef call(url, headers=None, iterations=1):\n    got = {}\n\n    for x in range(iterations):\n        # Yes, it's a terrible idea to use skip cert verification for TLS.\n        # We really don't care for this test though.\n        result = requests.get(url, headers=headers, verify=False)\n        version = 'unknown'\n\n        sys.stdout.write('.')\n        sys.stdout.flush()\n\n        if result.status_code != 200:\n            version='failure %d' % result.status_code\n        elif result.text.startswith('VERSION '):\n            version=result.text[len('VERSION '):]\n        else:\n            version='unknown %s' % result.text\n\n        got.setdefault(version, 0)\n        got[version] += 1\n\n    sys.stdout.write(\"\\n\")\n    sys.stdout.flush()\n    \n    return got\n\ndef test_demo(base, v2_wanted):\n    url = \"%s/demo/\" % base\n\n    attempts = 3\n\n    while attempts > 0:\n        print(\"2.0.0: attempts left %d\" % attempts)\n        got = call(url, iterations=1000)\n\n        print(got)\n        v2_seen = ((got.get('2.0.0', 0) + 5) // 10)\n        delta = abs(v2_seen - v2_wanted)\n        rc = (delta <= 2)\n\n        print(\"2.0.0: wanted %d, got %d (delta %d) => %s\" % \n              (v2_wanted, v2_seen, delta, \"pass\" if rc else \"FAIL\"))\n\n        if rc:\n            return rc\n\n        attempts -= 1\n        print(\"waiting for retry\")\n        time.sleep(5)\n\n    return False\n\ndef test_from_yaml(base, yaml_path):\n    spec = yaml.safe_load(open(yaml_path, \"r\"))\n\n    url = spec['url'].replace('{BASE}', base)\n\n    test_num = 0\n    rc = True\n\n    for test in spec['tests']:\n        test_num += 1\n        name = test.get('name', \"%s.%d\" % (os.path.basename(yaml_path), test_num))\n\n        headers = test.get('headers', None)\n        host = test.get('host', None)\n        versions = test.get('versions', None)\n        iterations = test.get('iterations', 100)\n\n        if not versions:\n            print(\"missing versions in %s?\" % name)\n            print(\"%s\" % yaml.safe_dump(test))\n            return False\n\n        if host:\n            if not headers:\n                headers = {}\n\n            headers['Host'] = host\n\n        attempts = 3\n\n        while attempts > 0:\n            print(\"%s: attempts left %d\" % (name, attempts))\n            print(\"%s: headers %s\" % (name, headers))\n\n            got = call(url, headers=headers, iterations=iterations)\n\n            print(\"%s: %s\" % (name, json.dumps(got)))\n\n            test_ok = True\n\n            for version, wanted_count in versions.items():\n                got_count = got.get(version, 0)\n                delta = abs(got_count - wanted_count)\n\n                print(\"%s %s: wanted %d, got %d (delta %d)\" % \n                      (name, version, wanted_count, got_count, delta))\n\n                if delta > 2:\n                    test_ok = False\n\n            if test_ok:\n                print(\"%s: passed\" % name)\n                break\n            else:\n                attempts -= 1\n\n                if attempts <= 0:\n                    print(\"%s: FAILED\" % name)\n                    rc = False\n\n    return rc\n\nif __name__ == \"__main__\":\n    base = sys.argv[1]\n\n    if not (base.startswith(\"http://\") or base.startswith(\"https://\")):\n        base = \"http://%s\" % base\n\n    v2_percent = None\n\n    try:\n        v2_percent = int(sys.argv[2])\n    except ValueError:\n        pass\n\n    if v2_percent != None:\n        rc = test_demo(base, v2_percent)\n    else:\n        rc = test_from_yaml(base, sys.argv[2])\n\n    if rc:\n        sys.exit(0)\n    else:\n        print(\"FAILED\")\n        sys.exit(1)\n", "path": "end-to-end/demotest.py"}, {"content": "import hashlib\n\nfrom .utils import SourcedDict\n\nclass Mapping (object):\n    @classmethod\n    def group_id(klass, method, prefix, headers):\n        # Yes, we're using a  cryptographic hash here. Cope. [ :) ]\n\n        h = hashlib.new('sha1')\n        h.update(method.encode('utf-8'))\n        h.update(prefix.encode('utf-8'))\n\n        for hdr in headers:\n            h.update(hdr['name'].encode('utf-8'))\n\n            if 'value' in hdr:\n                h.update(hdr['value'].encode('utf-8'))\n\n        return h.hexdigest()\n\n    @classmethod\n    def route_weight(klass, route):\n        prefix = route['prefix']\n        method = route.get('method', 'GET')\n        headers = route.get('headers', [])\n\n        weight = [ len(prefix) + len(headers), prefix, method ]\n        weight += [ hdr['name'] + '-' + hdr.get('value', '*') for hdr in headers ]\n\n        return tuple(weight)\n\n    TransparentRouteKeys = {\n        \"host_redirect\": True,\n        \"path_redirect\": True,\n        \"host_rewrite\": True,\n        \"auto_host_rewrite\": True,\n        \"case_sensitive\": True,\n        \"use_websocket\": True,\n        \"timeout_ms\": True,\n        \"priority\": True,\n    }\n\n    def __init__(self, _source=\"--internal--\", _from=None, **kwargs):\n        # Save the raw input...\n        self.attrs = dict(**kwargs)\n\n        if _from and ('_source' in _from):\n            self.attrs['_source'] = _from['_source']\n        else:\n            self.attrs['_source'] = _source\n\n        # ...and cache some useful first-class stuff.\n        self.name = self['name']\n        self.kind = self['kind']\n        self.prefix = self['prefix']\n        self.method = self.get('method', 'GET')\n\n        # Next up, build up the headers. We do this unconditionally at init\n        # time because we need the headers to work out the group ID.\n        self.headers = []\n\n        for name, value in self.get('headers', {}).items():\n            if value == True:\n                self.headers.append({ \"name\": name })\n            else:\n                self.headers.append({ \"name\": name, \"value\": value, \"regex\": False })\n\n        for name, value in self.get('regex_headers', []):\n            self.headers.append({ \"name\": name, \"value\": value, \"regex\": True })\n\n        if 'host' in self.attrs:\n            self.headers.append({\n                \"name\": \":authority\",\n                \"value\": self['host'],\n                \"regex\": self.get('host_regex', False)\n            })\n\n        if 'method' in self.attrs:\n            self.headers.append({\n                \"name\": \":method\",\n                \"value\": self['method'],\n                \"regex\": self.get('method_regex', False)\n            })\n\n        # OK. After all that we can compute the group ID.\n        self.group_id = Mapping.group_id(self.method, self.prefix, self.headers)\n\n    def __getitem__(self, key):\n        return self.attrs[key]\n\n    def get(self, key, *args):\n        if len(args) > 0:\n            return self.attrs.get(key, args[0])\n        else:\n            return self.attrs.get(key)\n\n    def new_route(self, cluster_name):\n        route = SourcedDict(\n            _source=self['_source'],\n            _group_id=self.group_id,\n            prefix=self.prefix,\n            prefix_rewrite=self.get('rewrite', '/'),\n            clusters=[ { \"name\": cluster_name,\n                         \"weight\": self.get(\"weight\", None) } ]\n        )\n\n        if self.headers:\n            route['headers'] = self.headers\n\n        # Even though we don't use it for generating the Envoy config, go ahead\n        # and make sure that any ':method' header match gets saved under the\n        # route's '_method' key -- diag uses it to make life easier.\n\n        route['_method'] = self.method\n\n        # We refer to this route, of course.\n        route._mark_referenced_by(self['_source'])\n\n        # There's a slew of things we'll just copy over transparently; handle\n        # those.\n\n        for key, value in self.attrs.items():\n            if key in Mapping.TransparentRouteKeys:\n                route[key] = value\n\n        # Done!\n        return route\n\nif __name__ == \"__main__\":\n    import sys\n\n    import json\n    import os\n\n    import yaml\n\n    for path in sys.argv[1:]:\n        try:\n            # XXX This is a bit of a hack -- yaml.safe_load_all returns a\n            # generator, and if we don't use list() here, any exception\n            # dealing with the actual object gets deferred \n            objects = list(yaml.safe_load_all(open(path, \"r\")))\n        except Exception as e:\n            print(\"%s: could not parse YAML: %s\" % (path, e))\n            continue\n\n        ocount = 0\n        for obj in objects:\n            ocount += 1\n            srckey = \"%s.%d\" % (path, ocount)\n\n            if obj['kind'] == 'Mapping':\n                m = Mapping(srckey, **obj)\n\n                print(\"%s: %s\" % (m.name, m.group_id))\n\n                print(json.dumps(m.new_route(\"test_cluster\"), indent=4, sort_keys=True))\n", "path": "ambassador/ambassador/mapping.py"}], "after_files": [{"content": "#!/usr/bin/env python\n\nimport sys\n\nimport json\nimport os\nimport requests\nimport time\nimport yaml\n\nDEFAULT_ITERATIONS=500\n\n# Yes, it's a terrible idea to use skip cert verification for TLS.\n# We really don't care for this test though.\nimport urllib3\nurllib3.disable_warnings()\n\ndef call(url, headers=None, iterations=1):\n    got = {}\n\n    for x in range(iterations):\n        # Yes, it's a terrible idea to use skip cert verification for TLS.\n        # We really don't care for this test though.\n        result = requests.get(url, headers=headers, verify=False)\n        version = 'unknown'\n\n        sys.stdout.write('.')\n        sys.stdout.flush()\n\n        if result.status_code != 200:\n            version='failure %d' % result.status_code\n        elif result.text.startswith('VERSION '):\n            version=result.text[len('VERSION '):]\n        else:\n            version='unknown %s' % result.text\n\n        got.setdefault(version, 0)\n        got[version] += 1\n\n    sys.stdout.write(\"\\n\")\n    sys.stdout.flush()\n    \n    return got\n\ndef to_percentage(count, iterations):\n    bias = iterations // 2\n    return ((count * 100) + bias) // iterations\n\ndef test_demo(base, v2_wanted):\n    url = \"%s/demo/\" % base\n\n    attempts = 3\n    iterations = DEFAULT_ITERATIONS\n\n    while attempts > 0:\n        print(\"2.0.0: attempts left %d\" % attempts)\n        got = call(url, iterations=iterations)\n\n        print(got)\n        v2_seen = to_percentage(got.get('2.0.0', 0), iterations)\n        delta = abs(v2_seen - v2_wanted)\n        rc = (delta <= 2)\n\n        print(\"2.0.0: wanted %d, got %d (delta %d) => %s\" % \n              (v2_wanted, v2_seen, delta, \"pass\" if rc else \"FAIL\"))\n\n        if rc:\n            return rc\n\n        attempts -= 1\n        print(\"waiting for retry\")\n        time.sleep(5)\n\n    return False\n\ndef test_from_yaml(base, yaml_path):\n    spec = yaml.safe_load(open(yaml_path, \"r\"))\n\n    url = spec['url'].replace('{BASE}', base)\n\n    test_num = 0\n    rc = True\n\n    for test in spec['tests']:\n        test_num += 1\n        name = test.get('name', \"%s.%d\" % (os.path.basename(yaml_path), test_num))\n\n        headers = test.get('headers', None)\n        host = test.get('host', None)\n        versions = test.get('versions', None)\n        iterations = test.get('iterations', DEFAULT_ITERATIONS)\n\n        if not versions:\n            print(\"missing versions in %s?\" % name)\n            print(\"%s\" % yaml.safe_dump(test))\n            return False\n\n        if host:\n            if not headers:\n                headers = {}\n\n            headers['Host'] = host\n\n        attempts = 3\n\n        while attempts > 0:\n            print(\"%s: attempts left %d\" % (name, attempts))\n            print(\"%s: headers %s\" % (name, headers))\n\n            got = call(url, headers=headers, iterations=iterations)\n\n            print(\"%s: %s\" % (name, json.dumps(got)))\n\n            test_ok = True\n\n            for version, wanted_count in versions.items():\n                # Convert iterations to percent.\n                got_count = to_percentage(got.get(version, 0), iterations)\n                delta = abs(got_count - wanted_count)\n\n                print(\"%s %s: wanted %d, got %d (delta %d)\" % \n                      (name, version, wanted_count, got_count, delta))\n\n                if delta > 2:\n                    test_ok = False\n\n            if test_ok:\n                print(\"%s: passed\" % name)\n                break\n            else:\n                attempts -= 1\n\n                if attempts <= 0:\n                    print(\"%s: FAILED\" % name)\n                    rc = False\n\n    return rc\n\nif __name__ == \"__main__\":\n    base = sys.argv[1]\n\n    if not (base.startswith(\"http://\") or base.startswith(\"https://\")):\n        base = \"http://%s\" % base\n\n    v2_percent = None\n\n    try:\n        v2_percent = int(sys.argv[2])\n    except ValueError:\n        pass\n\n    if v2_percent != None:\n        rc = test_demo(base, v2_percent)\n    else:\n        rc = test_from_yaml(base, sys.argv[2])\n\n    if rc:\n        sys.exit(0)\n    else:\n        print(\"FAILED\")\n        sys.exit(1)\n", "path": "end-to-end/demotest.py"}, {"content": "import hashlib\n\nfrom .utils import SourcedDict\n\nclass Mapping (object):\n    @classmethod\n    def group_id(klass, method, prefix, headers):\n        # Yes, we're using a  cryptographic hash here. Cope. [ :) ]\n\n        h = hashlib.new('sha1')\n        h.update(method.encode('utf-8'))\n        h.update(prefix.encode('utf-8'))\n\n        for hdr in headers:\n            h.update(hdr['name'].encode('utf-8'))\n\n            if 'value' in hdr:\n                h.update(hdr['value'].encode('utf-8'))\n\n        return h.hexdigest()\n\n    @classmethod\n    def route_weight(klass, route):\n        prefix = route['prefix']\n        method = route.get('method', 'GET')\n        headers = route.get('headers', [])\n\n        weight = [ len(prefix) + len(headers), prefix, method ]\n        weight += [ hdr['name'] + '-' + hdr.get('value', '*') for hdr in headers ]\n\n        return tuple(weight)\n\n    TransparentRouteKeys = {\n        \"auto_host_rewrite\": True,\n        \"case_sensitive\": True,\n        \"host_redirect\": True,\n        \"host_rewrite\": True,\n        \"path_redirect\": True,\n        \"priority\": True,\n        \"timeout_ms\": True,\n        \"use_websocket\": True,\n    }\n\n    def __init__(self, _source=\"--internal--\", _from=None, **kwargs):\n        # Save the raw input...\n        self.attrs = dict(**kwargs)\n\n        if _from and ('_source' in _from):\n            self.attrs['_source'] = _from['_source']\n        else:\n            self.attrs['_source'] = _source\n\n        # ...and cache some useful first-class stuff.\n        self.name = self['name']\n        self.kind = self['kind']\n        self.prefix = self['prefix']\n        self.method = self.get('method', 'GET')\n\n        # Next up, build up the headers. We do this unconditionally at init\n        # time because we need the headers to work out the group ID.\n        self.headers = []\n\n        for name, value in self.get('headers', {}).items():\n            if value == True:\n                self.headers.append({ \"name\": name })\n            else:\n                self.headers.append({ \"name\": name, \"value\": value, \"regex\": False })\n\n        for name, value in self.get('regex_headers', []):\n            self.headers.append({ \"name\": name, \"value\": value, \"regex\": True })\n\n        if 'host' in self.attrs:\n            self.headers.append({\n                \"name\": \":authority\",\n                \"value\": self['host'],\n                \"regex\": self.get('host_regex', False)\n            })\n\n        if 'method' in self.attrs:\n            self.headers.append({\n                \"name\": \":method\",\n                \"value\": self['method'],\n                \"regex\": self.get('method_regex', False)\n            })\n\n        # OK. After all that we can compute the group ID.\n        self.group_id = Mapping.group_id(self.method, self.prefix, self.headers)\n\n    def __getitem__(self, key):\n        return self.attrs[key]\n\n    def get(self, key, *args):\n        if len(args) > 0:\n            return self.attrs.get(key, args[0])\n        else:\n            return self.attrs.get(key)\n\n    def new_route(self, cluster_name):\n        route = SourcedDict(\n            _source=self['_source'],\n            _group_id=self.group_id,\n            prefix=self.prefix,\n            prefix_rewrite=self.get('rewrite', '/'),\n            clusters=[ { \"name\": cluster_name,\n                         \"weight\": self.get(\"weight\", None) } ]\n        )\n\n        if self.headers:\n            route['headers'] = self.headers\n\n        add_request_headers = self.get('add_request_headers')\n        if add_request_headers:\n            route['request_headers_to_add'] = []\n            for key, value in add_request_headers.items():\n              route['request_headers_to_add'].append({\"key\": key, \"value\": value})\n\n        # Even though we don't use it for generating the Envoy config, go ahead\n        # and make sure that any ':method' header match gets saved under the\n        # route's '_method' key -- diag uses it to make life easier.\n\n        route['_method'] = self.method\n\n        # We refer to this route, of course.\n        route._mark_referenced_by(self['_source'])\n\n        # There's a slew of things we'll just copy over transparently; handle\n        # those.\n\n        for key, value in self.attrs.items():\n            if key in Mapping.TransparentRouteKeys:\n                route[key] = value\n\n        # Done!\n        return route\n\nif __name__ == \"__main__\":\n    import sys\n\n    import json\n    import os\n\n    import yaml\n\n    for path in sys.argv[1:]:\n        try:\n            # XXX This is a bit of a hack -- yaml.safe_load_all returns a\n            # generator, and if we don't use list() here, any exception\n            # dealing with the actual object gets deferred \n            objects = list(yaml.safe_load_all(open(path, \"r\")))\n        except Exception as e:\n            print(\"%s: could not parse YAML: %s\" % (path, e))\n            continue\n\n        ocount = 0\n        for obj in objects:\n            ocount += 1\n            srckey = \"%s.%d\" % (path, ocount)\n\n            if obj['kind'] == 'Mapping':\n                m = Mapping(srckey, **obj)\n\n                print(\"%s: %s\" % (m.name, m.group_id))\n\n                print(json.dumps(m.new_route(\"test_cluster\"), indent=4, sort_keys=True))\n", "path": "ambassador/ambassador/mapping.py"}]}