Ejemplo 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 some time to register the changes
        time.sleep(60)

        # 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}"
Ejemplo n.º 2
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)
Ejemplo n.º 3
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)
Ejemplo n.º 4
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)
Ejemplo n.º 5
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)
Ejemplo n.º 6
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=None, artifacts=load_manifest("knative_serving_0.11.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=autoscaler-hpa', '-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'
            },
            {
                'name': 'AMBASSADOR_SINGLE_NAMESPACE',
                '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/'
        qotm_http_code = self.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")

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

        req_simple = request.Request(kservice_url)
        connection_simple_code = self.get_code_with_retry(req_simple)
        assert connection_simple_code == 404, f"Expected 404, got {connection_simple_code}"
        print(f"{kservice_url} returns 404 with no host")

        req_random = request.Request(kservice_url)
        req_random.add_header('Host', 'random.host.whatever')
        connection_random_code = self.get_code_with_retry(req_random)
        assert connection_random_code == 404, f"Expected 404, got {connection_random_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])

        req_correct = request.Request(kservice_url)
        req_correct.add_header('Host', f'helloworld-go.{namespace}.example.com')

        # kservice pod takes some time to spin up, so let's try a few times
        connection_correct_code = 000
        for _ in range(5):
            connection_correct_code = self.get_code_with_retry(req_correct)
            if connection_correct_code == 200:
                break

        assert connection_correct_code == 200, f"Expected 200, got {connection_correct_code}"
        print(f"{kservice_url} returns 200 OK with host helloworld-go.default.example.com")
Ejemplo 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, envs=[
            {
                'name': 'AMBASSADOR_SINGLE_NAMESPACE',
                'value': 'true'
            }
        ])

        # 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.

        headerecho_url = f'http://localhost:{port_forward_port}/headerecho/'
        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