• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

supabase / supavisor / e5e7ebfe80dbec4965226225050d4ef5c8216e88-PR-605

21 Feb 2025 02:35PM UTC coverage: 45.973% (-0.03%) from 46.003%
e5e7ebfe80dbec4965226225050d4ef5c8216e88-PR-605

Pull #605

github

hauleth
fix: remaining SSL connections that need to set `verify_none` option
Pull Request #605: fix: remaining SSL connections that need to set `verify_none` option

2 of 9 new or added lines in 3 files covered. (22.22%)

267 existing lines in 26 files now uncovered.

959 of 2086 relevant lines covered (45.97%)

635.02 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

50.0
/lib/supavisor_web/controllers/tenant_controller.ex
1
defmodule SupavisorWeb.TenantController do
2
  use SupavisorWeb, :controller
3
  use OpenApiSpex.ControllerSpecs
4

5
  require Logger
6

7
  alias Supavisor.{
8
    Helpers,
9
    Repo,
10
    Tenants
11
  }
12

13
  alias Tenants.Tenant, as: TenantModel
14

15
  alias SupavisorWeb.OpenApiSchemas.{
16
    Created,
17
    Empty,
18
    NotFound,
19
    Tenant,
20
    TenantCreate,
21
    TenantList
22
  }
23

24
  action_fallback(SupavisorWeb.FallbackController)
25

26
  @authorization [
27
    in: :header,
28
    name: "Authorization",
29
    schema: %OpenApiSpex.Schema{type: :string},
30
    required: true,
31
    example:
32
      "Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE2ODAxNjIxNTR9.U9orU6YYqXAtpF8uAiw6MS553tm4XxRzxOhz2IwDhpY"
33
  ]
34

35
  operation(:index,
×
36
    summary: "List tenants",
37
    parameters: [authorization: @authorization],
38
    responses: %{
39
      200 => TenantList.response()
40
    }
41
  )
42

43
  def index(conn, _params) do
44
    tenants = Tenants.list_tenants()
×
45
    render(conn, "index.json", tenants: tenants)
×
46
  end
47

48
  def create(conn, %{"tenant" => tenant_params}) do
UNCOV
49
    with {:ok, %TenantModel{} = tenant} <- Tenants.create_tenant(tenant_params) do
3✔
50
      conn
51
      |> put_status(:created)
52
      |> put_resp_header("location", Routes.tenant_path(conn, :show, tenant))
UNCOV
53
      |> render("show.json", tenant: tenant)
1✔
54
    end
55
  end
56

57
  operation(:show,
×
58
    summary: "Fetch Tenant",
59
    parameters: [
60
      external_id: [in: :path, description: "External id", type: :string],
61
      authorization: @authorization
62
    ],
63
    responses: %{
64
      200 => Tenant.response(),
65
      404 => NotFound.response()
66
    }
67
  )
68

69
  def show(conn, %{"external_id" => id}) do
70
    id
71
    |> Tenants.get_tenant_by_external_id()
UNCOV
72
    |> case do
2✔
73
      %TenantModel{} = tenant ->
UNCOV
74
        render(conn, "show.json", tenant: tenant)
1✔
75

76
      nil ->
77
        conn
78
        |> put_status(404)
UNCOV
79
        |> render("not_found.json", tenant: nil)
1✔
80
    end
81
  end
82

83
  operation(:update,
×
84
    summary: "Create or update tenant",
85
    parameters: [
86
      external_id: [in: :path, description: "External id", type: :string],
87
      authorization: @authorization
88
    ],
89
    request_body: TenantCreate.params(),
90
    responses: %{
91
      201 => Created.response(Tenant),
92
      404 => NotFound.response()
93
    }
94
  )
95

96
  # convert cert to pem format
97
  def update(conn, %{
98
        "external_id" => id,
99
        "tenant" => %{"upstream_tls_ca" => "-----BEGIN" <> _ = upstream_tls_ca} = tenant_params
100
      }) do
101
    case Helpers.cert_to_bin(upstream_tls_ca) do
×
102
      {:ok, bin} ->
103
        update(conn, %{
×
104
          "external_id" => id,
105
          "tenant" => %{tenant_params | "upstream_tls_ca" => bin}
106
        })
107

108
      {:error, realson} ->
109
        conn
110
        |> put_status(400)
111
        |> render("error.json",
×
112
          error: "Invalid 'upstream_tls_ca' certificate, reason: #{inspect(realson)}"
113
        )
114
    end
115
  end
116

117
  def update(conn, %{"external_id" => id, "tenant" => params}) do
UNCOV
118
    Logger.info("Delete cache dist #{id}: #{inspect(Supavisor.del_all_cache_dist(id))}")
5✔
UNCOV
119
    cert = Helpers.upstream_cert(params["upstream_tls_ca"])
5✔
120

UNCOV
121
    if params["upstream_ssl"] && params["upstream_verify"] == "peer" && !cert do
5✔
122
      conn
123
      |> put_status(400)
124
      |> render("error.json",
×
125
        error: "Invalid 'upstream_verify' value, 'peer' is not allowed without certificate"
126
      )
127
    else
UNCOV
128
      case Tenants.get_tenant_by_external_id(id) do
5✔
129
        nil ->
UNCOV
130
          case Helpers.check_creds_get_ver(params) do
3✔
131
            {:error, reason} ->
132
              conn
133
              |> put_status(400)
134
              |> render("error.json", error: reason)
×
135

136
            {:ok, pg_version} ->
UNCOV
137
              params =
3✔
138
                if pg_version do
UNCOV
139
                  Map.put(params, "default_parameter_status", %{
3✔
140
                    "server_version" => pg_version
141
                  })
142
                else
143
                  params
×
144
                end
145

UNCOV
146
              create(conn, %{"tenant" => Map.put(params, "external_id", id)})
3✔
147
          end
148

149
        tenant ->
UNCOV
150
          tenant = Repo.preload(tenant, :users)
2✔
151

UNCOV
152
          with {:ok, %TenantModel{} = tenant} <-
2✔
153
                 Tenants.update_tenant(tenant, params) do
UNCOV
154
            result = Supavisor.terminate_global(tenant.external_id)
2✔
UNCOV
155
            Logger.warning("Stop #{tenant.external_id}: #{inspect(result)}")
2✔
UNCOV
156
            render(conn, "show.json", tenant: tenant)
2✔
157
          end
158
      end
159
    end
160
  end
161

162
  operation(:delete,
×
163
    summary: "Delete source",
164
    parameters: [
165
      external_id: [in: :path, description: "External id", type: :string],
166
      authorization: @authorization
167
    ],
168
    responses: %{
169
      204 => Empty.response(),
170
      404 => NotFound.response()
171
    }
172
  )
173

174
  def delete(conn, %{"external_id" => id}) do
UNCOV
175
    code = if Tenants.delete_tenant_by_external_id(id), do: 204, else: 404
1✔
176

UNCOV
177
    Logger.info("Delete cache dist #{id}: #{inspect(Supavisor.del_all_cache_dist(id))}")
1✔
178

UNCOV
179
    send_resp(conn, code, "")
1✔
180
  end
181

182
  operation(:terminate,
×
183
    summary: "Stop tenant's pools and clear cache",
184
    parameters: [
185
      external_id: [in: :path, description: "External id", type: :string],
186
      authorization: @authorization
187
    ],
188
    responses: %{
189
      204 => Empty.response(),
190
      404 => NotFound.response()
191
    }
192
  )
193

194
  def terminate(conn, %{"external_id" => external_id}) do
195
    Logger.metadata(project: external_id)
×
196
    result = Supavisor.terminate_global(external_id) |> inspect()
×
197
    Logger.warning("Terminate #{external_id}: #{result}")
×
198

199
    Logger.info(
×
200
      "Delete cache dist #{external_id}: #{inspect(Supavisor.del_all_cache_dist(external_id))}"
×
201
    )
202

203
    render(conn, "show_terminate.json", result: result)
×
204
  end
205

206
  operation(:health,
×
207
    summary: "Health check",
208
    parameters: [],
209
    responses: %{
210
      204 => Empty.response()
211
    }
212
  )
213

214
  def health(conn, _) do
215
    send_resp(conn, 204, "")
×
216
  end
217
end
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc