test_ssh_tunnels.py 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. # Copyright Materialize, Inc. and contributors. All rights reserved.
  2. #
  3. # Use of this software is governed by the Business Source License
  4. # included in the LICENSE file at the root of this repository.
  5. #
  6. # As of the Change Date specified in that file, in accordance with
  7. # the Business Source License, use of this software will be governed
  8. # by the Apache License, Version 2.0.
  9. from textwrap import dedent
  10. from materialize.cloudtest.app.materialize_application import MaterializeApplication
  11. from materialize.cloudtest.util.wait import wait
  12. def test_ssh_tunnels(mz: MaterializeApplication) -> None:
  13. mz.testdrive.run(
  14. input=dedent(
  15. """
  16. > CREATE CONNECTION IF NOT EXISTS ssh_conn TO SSH TUNNEL (
  17. HOST 'ssh-bastion-host',
  18. USER 'mz',
  19. PORT 22
  20. );
  21. """
  22. )
  23. )
  24. (id, public_key) = mz.environmentd.sql_query(
  25. "SELECT id, public_key_1 FROM mz_ssh_tunnel_connections"
  26. )[0]
  27. assert id is not None
  28. secret = f"user-managed-{id}"
  29. # If the secret didn't exist, this would throw an exception
  30. mz.kubectl("describe", "secret", secret)
  31. # Add public key to SSH bastion host
  32. mz.kubectl(
  33. "exec",
  34. "svc/ssh-bastion-host",
  35. "--",
  36. "bash",
  37. "-c",
  38. f"echo '{public_key}' > /etc/authorized_keys/mz",
  39. )
  40. mz.testdrive.run(
  41. input=dedent(
  42. """
  43. > CREATE SECRET pgpass AS 'postgres'
  44. > CREATE CONNECTION pg TO POSTGRES (
  45. HOST 'postgres',
  46. DATABASE postgres,
  47. USER postgres,
  48. PASSWORD SECRET pgpass,
  49. SSL MODE require,
  50. SSH TUNNEL ssh_conn
  51. );
  52. $ postgres-execute connection=postgres://postgres:postgres@postgres
  53. ALTER USER postgres WITH replication;
  54. DROP SCHEMA IF EXISTS public CASCADE;
  55. DROP PUBLICATION IF EXISTS mz_source;
  56. CREATE SCHEMA public;
  57. CREATE TABLE t1 (f1 INTEGER);
  58. ALTER TABLE t1 REPLICA IDENTITY FULL;
  59. INSERT INTO t1 VALUES (1);
  60. CREATE PUBLICATION mz_source FOR TABLE t1;
  61. > CREATE SOURCE mz_source
  62. FROM POSTGRES CONNECTION pg
  63. (PUBLICATION 'mz_source');
  64. > CREATE TABLE t1 FROM SOURCE mz_source (REFERENCE t1);
  65. > SELECT COUNT(*) = 1 FROM t1;
  66. true
  67. > SELECT f1 FROM t1;
  68. 1
  69. $ postgres-execute connection=postgres://postgres:postgres@postgres
  70. INSERT INTO t1 VALUES (1), (2);
  71. > SELECT f1 FROM t1 ORDER BY f1 ASC;
  72. 1
  73. 1
  74. 2
  75. """
  76. ),
  77. no_reset=True,
  78. )
  79. environmentd_pod_name = "pod/environmentd-0"
  80. # Kill environmentd to force a restart, to test reloading secrets on restart
  81. mz.kubectl(
  82. "exec",
  83. environmentd_pod_name,
  84. "--",
  85. "bash",
  86. "-c",
  87. "kill -9 `pidof environmentd`",
  88. )
  89. mz.testdrive.run(
  90. input=dedent(
  91. """
  92. > SELECT f1 FROM t1 ORDER BY f1 ASC;
  93. 1
  94. 1
  95. 2
  96. $ postgres-execute connection=postgres://postgres:postgres@postgres
  97. INSERT INTO t1 VALUES (3), (4);
  98. > SELECT f1 FROM t1 ORDER BY f1 ASC;
  99. 1
  100. 1
  101. 2
  102. 3
  103. 4
  104. """
  105. ),
  106. no_reset=True,
  107. )
  108. mz.environmentd.sql("DROP CONNECTION ssh_conn CASCADE")
  109. # Verify that secret associated with the SSH tunnel is deleted from k8s
  110. wait(condition="delete", resource=f"secret/{secret}")