Esempio n. 1
0
    def test_rapid_additions_and_deletions(self):
        namespace = 'watt-rapid'

        # Install Ambassador
        install_ambassador(namespace=namespace)

        # Install QOTM
        apply_kube_artifacts(namespace=namespace, artifacts=qotm_manifests)

        # Install QOTM Ambassador manifests
        self.apply_qotm_endpoint_manifests(namespace=namespace)

        # Now let's wait for ambassador and QOTM pods to become ready
        run_and_assert([
            'kubectl', 'wait', '--timeout=90s', '--for=condition=Ready', 'pod',
            '-l', 'service=ambassador', '-n', namespace
        ])
        run_and_assert([
            'kubectl', 'wait', '--timeout=90s', '--for=condition=Ready', 'pod',
            '-l', 'service=qotm', '-n', namespace
        ])

        # Let's port-forward ambassador service to talk to QOTM
        port_forward_port = 6000
        port_forward_command = [
            'kubectl', 'port-forward', '--namespace', namespace,
            'service/ambassador', f'{port_forward_port}:80'
        ]
        run_and_assert(port_forward_command, communicate=False)
        qotm_url = f'http://localhost:{port_forward_port}/qotm/'

        # Assert 200 OK at /qotm/ endpoint
        qotm_ready = False

        loop_limit = 60
        while not qotm_ready:
            assert loop_limit > 0, "QOTM is not ready yet, aborting..."
            try:
                qotm_http_code = get_code_with_retry(qotm_url)
                assert qotm_http_code == 200, f"Expected 200 OK, got {qotm_http_code}"
                print(f"{qotm_url} is ready")
                qotm_ready = True

            except Exception as e:
                print(f"Error: {e}")
                print(f"{qotm_url} not ready yet, trying again...")
                time.sleep(1)
                loop_limit -= 1

        # Try to mess up Ambassador by applying and deleting QOTM mapping over and over
        for i in range(10):
            self.delete_qotm_mapping(namespace=namespace)
            self.create_qotm_mapping(namespace=namespace)

        # Let's give Ambassador a few seconds to register the changes...
        time.sleep(5)

        # Assert 200 OK at /qotm/ endpoint
        qotm_http_code = get_code_with_retry(qotm_url)
        assert qotm_http_code == 200, f"Expected 200 OK, got {qotm_http_code}"
Esempio n. 2
0
    def test_rapid_additions_and_deletions(self):
        namespace = 'watt-rapid'

        # Make sure telepresence is connected. Do this early on in the test to give the TP daemon plenty of
        # time to do its thing while we wait for other k8 resources to reconcile.
        run_with_retry(['telepresence', 'connect'])

        # Install Ambassador
        install_ambassador(namespace=namespace)

        # Install QOTM
        apply_kube_artifacts(namespace=namespace, artifacts=qotm_manifests)

        # Install QOTM Ambassador manifests
        self.apply_qotm_endpoint_manifests(namespace=namespace)

        # Now let's wait for ambassador and QOTM pods to become ready
        run_and_assert([
            'kubectl', 'wait', '--timeout=90s', '--for=condition=Ready', 'pod',
            '-l', 'service=ambassador', '-n', namespace
        ])
        run_and_assert([
            'kubectl', 'wait', '--timeout=90s', '--for=condition=Ready', 'pod',
            '-l', 'service=qotm', '-n', namespace
        ])

        # Assume we can reach Ambassador through telepresence
        qotm_host = "ambassador." + namespace
        qotm_url = f"http://{qotm_host}/qotm/"

        # Assert 200 OK at /qotm/ endpoint
        qotm_ready = False

        loop_limit = 60
        while not qotm_ready:
            assert loop_limit > 0, "QOTM is not ready yet, aborting..."
            try:
                qotm_http_code = get_code_with_retry(qotm_url)
                assert qotm_http_code == 200, f"Expected 200 OK, got {qotm_http_code}"
                print(f"{qotm_url} is ready")
                qotm_ready = True

            except Exception as e:
                print(f"Error: {e}")
                print(f"{qotm_url} not ready yet, trying again...")
                time.sleep(1)
                loop_limit -= 1

        # Try to mess up Ambassador by applying and deleting QOTM mapping over and over
        for i in range(10):
            self.delete_qotm_mapping(namespace=namespace)
            self.create_qotm_mapping(namespace=namespace)

        # Let's give Ambassador a few seconds to register the changes...
        time.sleep(5)

        # Assert 200 OK at /qotm/ endpoint
        qotm_http_code = get_code_with_retry(qotm_url)
        assert qotm_http_code == 200, f"Expected 200 OK, got {qotm_http_code}"
Esempio n. 3
0
    def apply_qotm_endpoint_manifests(self, namespace):
        qotm_resolver = f"""
apiVersion: getambassador.io/v2
kind: KubernetesEndpointResolver
metadata:
  name: qotm-resolver
  namespace: {namespace}
"""

        apply_kube_artifacts(namespace=namespace, artifacts=qotm_resolver)
        self.create_qotm_mapping(namespace=namespace)
Esempio n. 4
0
def create_headerecho_mapping(namespace):
    headerecho_mapping = f"""
---
apiVersion: getambassador.io/v2
kind: Mapping
metadata:
  name:  headerecho-mapping
  namespace: {namespace}
spec:
  prefix: /headerecho/
  rewrite: /
  service: headerecho
"""

    apply_kube_artifacts(namespace=namespace, artifacts=headerecho_mapping)
Esempio n. 5
0
    def create_module(self, namespace):
        manifest = f"""
---
apiVersion: getambassador.io/v2
kind: Module
metadata:
  name: ambassador
spec:
  config:
    header_case_overrides:
    - X-HELLO
    - X-FOO-Bar
        """

        apply_kube_artifacts(namespace=namespace, artifacts=manifest)
Esempio n. 6
0
    def create_qotm_mapping(self, namespace):
        qotm_mapping = f"""
---
apiVersion: getambassador.io/v2
kind: Mapping
metadata:
  name:  qotm-mapping
  namespace: {namespace}
spec:
  prefix: /qotm/
  service: qotm.{namespace}
  resolver: qotm-resolver
  load_balancer:
    policy: round_robin
        """

        apply_kube_artifacts(namespace=namespace, artifacts=qotm_mapping)
Esempio n. 7
0
    def test_header_case_overrides(self):
        # Is there any reason not to use the default namespace?
        namespace = 'header-case-overrides'

        # Install Ambassador
        install_ambassador(namespace=namespace)

        # Install httpbin
        apply_kube_artifacts(namespace=namespace, artifacts=httpbin_manifests)

        # Install headerecho
        apply_kube_artifacts(namespace=namespace, artifacts=headerecho_manifests)

        # Install module
        self.create_module(namespace)

        # Install httpbin mapping
        create_httpbin_mapping(namespace=namespace)

        # Install headerecho mapping
        create_headerecho_mapping(namespace=namespace)

        # Now let's wait for ambassador and httpbin pods to become ready
        run_and_assert(['kubectl', 'wait', '--timeout=90s', '--for=condition=Ready', 'pod', '-l', 'service=ambassador', '-n', namespace])
        run_and_assert(['kubectl', 'wait', '--timeout=90s', '--for=condition=Ready', 'pod', '-l', 'service=httpbin', '-n', namespace])

        # Let's port-forward ambassador service to talk to Ambassador.
        # IMPORTANT: We _must_ choose a unique port_forward_port so long as test_watt.py,
        # test_knative.py, and others like it, run in the same environment as this test.
        # Otherwise we get port collisions and it's madness.
        port_forward_port = 6123
        port_forward_command = ['kubectl', 'port-forward', '--namespace', namespace, 'service/ambassador', f'{port_forward_port}:80']
        run_and_assert(port_forward_command, communicate=False)

        print("Waiting 5 seconds, just because...")
        time.sleep(2)

        # Assert 200 OK at httpbin/status/200 endpoint
        ready = False
        httpbin_url = f'http://localhost:{port_forward_port}/httpbin/status/200'
        headerecho_url = f'http://localhost:{port_forward_port}/headerecho/'

        loop_limit = 10
        while not ready:
            assert loop_limit > 0, "httpbin is not ready yet, aborting..."
            try:
                print(f"trying {httpbin_url}...")
                resp = requests.get(httpbin_url, timeout=5)
                code = resp.status_code
                assert code == 200, f"Expected 200 OK, got {code}"
                resp.close()
                print(f"{httpbin_url} is ready")

                print(f"trying {headerecho_url}...")
                resp = requests.get(headerecho_url, timeout=5)
                code = resp.status_code
                assert code == 200, f"Expected 200 OK, got {code}"
                resp.close()
                print(f"{headerecho_url} is ready")

                ready = True

            except Exception as e:
                print(f"Error: {e}")
                print(f"{httpbin_url} not ready yet, trying again...")
                time.sleep(1)
                loop_limit -= 1

        assert ready

        httpbin_url = f'http://localhost:{port_forward_port}/httpbin/response-headers?x-Hello=1&X-foo-Bar=1&x-Lowercase1=1&x-lowercase2=1'
        resp = requests.get(httpbin_url, timeout=5)
        code = resp.status_code
        assert code == 200, f"Expected 200 OK, got {code}"

        # First, test that the response headers have the correct case.

        # Very important: this test relies on matching case sensitive header keys.
        # Fortunately it appears that we can convert resp.headers, a case insensitive
        # dictionary, into a list of case sensitive keys.
        keys = [ h for h in resp.headers.keys() ]
        for k in keys:
            print(f"header key: {k}")

        assert 'x-hello' not in keys
        assert 'X-HELLO' in keys
        assert 'x-foo-bar' not in keys
        assert 'X-FOO-Bar' in keys
        assert 'x-lowercase1' in keys
        assert 'x-Lowercase1' not in keys
        assert 'x-lowercase2' in keys
        resp.close()

        # Second, test that the request headers sent to the headerecho server
        # have the correct case.

        headers = {
            'x-Hello': '1',
            'X-foo-Bar': '1',
            'x-Lowercase1': '1',
            'x-lowercase2': '1'
        }
        resp = requests.get(headerecho_url, headers=headers, timeout=5)
        code = resp.status_code
        assert code == 200, f"Expected 200 OK, got {code}"

        response_obj = json.loads(resp.text)
        print(f"response_obj = {response_obj}")
        assert response_obj
        assert 'headers' in response_obj

        hdrs = response_obj['headers']
        assert 'x-hello' not in hdrs
        assert 'X-HELLO' in hdrs
        assert 'x-foo-bar' not in hdrs
        assert 'X-FOO-Bar' in hdrs
        assert 'x-lowercase1' in hdrs
        assert 'x-Lowercase1' not in hdrs
        assert 'x-lowercase2' in hdrs
Esempio n. 8
0
    def test_knative(self):
        namespace = 'knative-testing'

        # Install Knative
        apply_kube_artifacts(namespace=None,
                             artifacts=load_manifest("knative_serving_crds"))
        apply_kube_artifacts(namespace='knative-serving',
                             artifacts=load_manifest("knative_serving_0.18.0"))
        run_and_assert([
            'kubectl', 'patch', 'configmap/config-network', '--type', 'merge',
            '--patch',
            r'{"data": {"ingress.class": "ambassador.ingress.networking.knative.dev"}}',
            '-n', 'knative-serving'
        ])

        # Wait for Knative to become ready
        run_and_assert([
            'kubectl', 'wait', '--timeout=90s', '--for=condition=Ready', 'pod',
            '-l', 'app=activator', '-n', 'knative-serving'
        ])
        run_and_assert([
            'kubectl', 'wait', '--timeout=90s', '--for=condition=Ready', 'pod',
            '-l', 'app=controller', '-n', 'knative-serving'
        ])
        run_and_assert([
            'kubectl', 'wait', '--timeout=90s', '--for=condition=Ready', 'pod',
            '-l', 'app=webhook', '-n', 'knative-serving'
        ])
        run_and_assert([
            'kubectl', 'wait', '--timeout=90s', '--for=condition=Ready', 'pod',
            '-l', 'app=autoscaler', '-n', 'knative-serving'
        ])

        # Install Ambassador
        install_ambassador(namespace=namespace,
                           envs=[{
                               'name': 'AMBASSADOR_KNATIVE_SUPPORT',
                               'value': 'true'
                           }])

        # Install QOTM
        apply_kube_artifacts(namespace=namespace, artifacts=qotm_manifests)
        create_qotm_mapping(namespace=namespace)

        # Now let's wait for ambassador and QOTM pods to become ready
        run_and_assert([
            'kubectl', 'wait', '--timeout=90s', '--for=condition=Ready', 'pod',
            '-l', 'service=ambassador', '-n', namespace
        ])
        run_and_assert([
            'kubectl', 'wait', '--timeout=90s', '--for=condition=Ready', 'pod',
            '-l', 'service=qotm', '-n', namespace
        ])

        # Create kservice
        apply_kube_artifacts(namespace=namespace,
                             artifacts=knative_service_example)

        # Let's port-forward ambassador service to talk to QOTM
        port_forward_port = 7000
        port_forward_command = [
            'kubectl', 'port-forward', '--namespace', namespace,
            'service/ambassador', f'{port_forward_port}:80'
        ]
        run_and_assert(port_forward_command, communicate=False)

        # Assert 200 OK at /qotm/ endpoint
        qotm_url = f'http://localhost:{port_forward_port}/qotm/'
        code = get_code_with_retry(qotm_url)
        assert code == 200, f"Expected 200 OK, got {code}"
        print(f"{qotm_url} is ready")

        # Assert 200 OK at / with Knative Host header and 404 with other/no header
        kservice_url = f'http://localhost:{port_forward_port}/'

        code = get_code_with_retry(kservice_url)
        assert code == 404, f"Expected 404, got {code}"
        print(f"{kservice_url} returns 404 with no host")

        code = get_code_with_retry(kservice_url,
                                   headers={'Host': 'random.host.whatever'})
        assert code == 404, f"Expected 404, got {code}"
        print(f"{kservice_url} returns 404 with a random host")

        # Wait for kservice
        run_and_assert([
            'kubectl', 'wait', '--timeout=90s', '--for=condition=Ready',
            'ksvc', 'helloworld-go', '-n', namespace
        ])

        # kservice pod takes some time to spin up, so let's try a few times
        code = 000
        host = f'helloworld-go.{namespace}.example.com'
        for _ in range(5):
            code = get_code_with_retry(kservice_url, headers={'Host': host})
            if code == 200:
                break

        assert code == 200, f"Expected 200, got {code}"
        print(
            f"{kservice_url} returns 200 OK with host helloworld-go.{namespace}.example.com"
        )
    def test_knative(self):
        namespace = 'knative-testing'

        # Make sure telepresence is connected. Do this early on in the test to give the TP daemon plenty of
        # time to do its thing while we wait for other k8 resources to reconcile.
        run_with_retry(['telepresence', 'connect'])

        # Install Knative
        apply_kube_artifacts(namespace=None,
                             artifacts=load_manifest("knative_serving_crds"))
        apply_kube_artifacts(namespace='knative-serving',
                             artifacts=load_manifest("knative_serving_0.18.0"))
        run_and_assert([
            'kubectl', 'patch', 'configmap/config-network', '--type', 'merge',
            '--patch',
            r'{"data": {"ingress.class": "ambassador.ingress.networking.knative.dev"}}',
            '-n', 'knative-serving'
        ])

        # Wait for Knative to become ready
        run_and_assert([
            'kubectl', 'wait', '--timeout=90s', '--for=condition=Ready', 'pod',
            '-l', 'app=activator', '-n', 'knative-serving'
        ])
        run_and_assert([
            'kubectl', 'wait', '--timeout=90s', '--for=condition=Ready', 'pod',
            '-l', 'app=controller', '-n', 'knative-serving'
        ])
        run_and_assert([
            'kubectl', 'wait', '--timeout=90s', '--for=condition=Ready', 'pod',
            '-l', 'app=webhook', '-n', 'knative-serving'
        ])
        run_and_assert([
            'kubectl', 'wait', '--timeout=90s', '--for=condition=Ready', 'pod',
            '-l', 'app=autoscaler', '-n', 'knative-serving'
        ])

        # Install Ambassador
        install_ambassador(namespace=namespace,
                           envs=[{
                               'name': 'AMBASSADOR_KNATIVE_SUPPORT',
                               'value': 'true'
                           }])

        # Install QOTM
        apply_kube_artifacts(namespace=namespace, artifacts=qotm_manifests)
        create_qotm_mapping(namespace=namespace)

        # Now let's wait for ambassador and QOTM pods to become ready
        run_and_assert([
            'kubectl', 'wait', '--timeout=90s', '--for=condition=Ready', 'pod',
            '-l', 'service=ambassador', '-n', namespace
        ])
        run_and_assert([
            'kubectl', 'wait', '--timeout=90s', '--for=condition=Ready', 'pod',
            '-l', 'service=qotm', '-n', namespace
        ])

        # Create kservice
        apply_kube_artifacts(namespace=namespace,
                             artifacts=knative_service_example)

        # Assume we can reach Ambassador through telepresence
        qotm_host = "ambassador." + namespace

        # Assert 200 OK at /qotm/ endpoint
        qotm_url = f'http://{qotm_host}/qotm/'
        code = get_code_with_retry(qotm_url)
        assert code == 200, f"Expected 200 OK, got {code}"
        print(f"{qotm_url} is ready")

        # Assert 200 OK at / with Knative Host header and 404 with other/no header
        kservice_url = f'http://{qotm_host}/'

        code = get_code_with_retry(kservice_url)
        assert code == 404, f"Expected 404, got {code}"
        print(f"{kservice_url} returns 404 with no host")

        code = get_code_with_retry(kservice_url,
                                   headers={'Host': 'random.host.whatever'})
        assert code == 404, f"Expected 404, got {code}"
        print(f"{kservice_url} returns 404 with a random host")

        # Wait for kservice
        run_and_assert([
            'kubectl', 'wait', '--timeout=90s', '--for=condition=Ready',
            'ksvc', 'helloworld-go', '-n', namespace
        ])

        # kservice pod takes some time to spin up, so let's try a few times
        code = 000
        host = f'helloworld-go.{namespace}.example.com'
        for _ in range(5):
            code = get_code_with_retry(kservice_url, headers={'Host': host})
            if code == 200:
                break

        assert code == 200, f"Expected 200, got {code}"
        print(
            f"{kservice_url} returns 200 OK with host helloworld-go.{namespace}.example.com"
        )
    def test_header_case_overrides(self):
        # Is there any reason not to use the default namespace?
        namespace = 'header-case-overrides'

        # Make sure telepresence is connected. Do this early on in the test to give the TP daemon plenty of
        # time to do its thing while we wait for other k8 resources to reconcile.
        run_with_retry(['telepresence', 'connect'])

        # Install Ambassador
        install_ambassador(namespace=namespace)

        # Install httpbin
        apply_kube_artifacts(namespace=namespace, artifacts=httpbin_manifests)

        # Install headerecho
        apply_kube_artifacts(namespace=namespace,
                             artifacts=headerecho_manifests)

        # Install module
        self.create_module(namespace)

        # Install httpbin mapping
        create_httpbin_mapping(namespace=namespace)

        # Install headerecho mapping
        create_headerecho_mapping(namespace=namespace)

        # Now let's wait for ambassador and httpbin pods to become ready
        run_and_assert([
            'kubectl', 'wait', '--timeout=90s', '--for=condition=Ready', 'pod',
            '-l', 'service=ambassador', '-n', namespace
        ])
        run_and_assert([
            'kubectl', 'wait', '--timeout=90s', '--for=condition=Ready', 'pod',
            '-l', 'service=httpbin', '-n', namespace
        ])

        # Assume we can reach Ambassador through telepresence
        ambassador_host = "ambassador." + namespace

        # Assert 200 OK at httpbin/status/200 endpoint
        ready = False
        httpbin_url = f'http://{ambassador_host}/httpbin/status/200'
        headerecho_url = f'http://{ambassador_host}/headerecho/'

        loop_limit = 10
        while not ready:
            assert loop_limit > 0, "httpbin is not ready yet, aborting..."
            try:
                print(f"trying {httpbin_url}...")
                resp = requests.get(httpbin_url, timeout=5)
                code = resp.status_code
                assert code == 200, f"Expected 200 OK, got {code}"
                resp.close()
                print(f"{httpbin_url} is ready")

                print(f"trying {headerecho_url}...")
                resp = requests.get(headerecho_url, timeout=5)
                code = resp.status_code
                assert code == 200, f"Expected 200 OK, got {code}"
                resp.close()
                print(f"{headerecho_url} is ready")

                ready = True

            except Exception as e:
                print(f"Error: {e}")
                print(f"{httpbin_url} not ready yet, trying again...")
                time.sleep(1)
                loop_limit -= 1

        assert ready

        httpbin_url = f'http://{ambassador_host}/httpbin/response-headers?x-Hello=1&X-foo-Bar=1&x-Lowercase1=1&x-lowercase2=1'
        resp = requests.get(httpbin_url, timeout=5)
        code = resp.status_code
        assert code == 200, f"Expected 200 OK, got {code}"

        # First, test that the response headers have the correct case.

        # Very important: this test relies on matching case sensitive header keys.
        # Fortunately it appears that we can convert resp.headers, a case insensitive
        # dictionary, into a list of case sensitive keys.
        keys = [h for h in resp.headers.keys()]
        for k in keys:
            print(f"header key: {k}")

        assert 'x-hello' not in keys
        assert 'X-HELLO' in keys
        assert 'x-foo-bar' not in keys
        assert 'X-FOO-Bar' in keys
        assert 'x-lowercase1' in keys
        assert 'x-Lowercase1' not in keys
        assert 'x-lowercase2' in keys
        resp.close()

        # Second, test that the request headers sent to the headerecho server
        # have the correct case.

        headers = {
            'x-Hello': '1',
            'X-foo-Bar': '1',
            'x-Lowercase1': '1',
            'x-lowercase2': '1'
        }
        resp = requests.get(headerecho_url, headers=headers, timeout=5)
        code = resp.status_code
        assert code == 200, f"Expected 200 OK, got {code}"

        response_obj = json.loads(resp.text)
        print(f"response_obj = {response_obj}")
        assert response_obj
        assert 'headers' in response_obj

        hdrs = response_obj['headers']
        assert 'x-hello' not in hdrs
        assert 'X-HELLO' in hdrs
        assert 'x-foo-bar' not in hdrs
        assert 'X-FOO-Bar' in hdrs
        assert 'x-lowercase1' in hdrs
        assert 'x-Lowercase1' not in hdrs
        assert 'x-lowercase2' in hdrs