Skip to content

Commit

Permalink
Add apis for managing template viewing in-ui
Browse files Browse the repository at this point in the history
There's a meaningful usecase to understand the generated yaml for a service post-templating.  Think of it as being able to run `helm template` from within our ui instead of locally. Our dry run experience somewhat accomplishes this but will fail for misformatted yaml or other edge cases.
  • Loading branch information
michaeljguarino committed Mar 23, 2024
1 parent 6185458 commit ac845ac
Show file tree
Hide file tree
Showing 7 changed files with 150 additions and 0 deletions.
1 change: 1 addition & 0 deletions lib/console/deployments/events.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ defmodule Console.PubSub.ServiceUpdated, do: use Piazza.PubSub.Event
defmodule Console.PubSub.ServiceDeleted, do: use Piazza.PubSub.Event
defmodule Console.PubSub.ServiceComponentsUpdated, do: use Piazza.PubSub.Event
defmodule Console.PubSub.ServiceHardDeleted, do: use Piazza.PubSub.Event
defmodule Console.PubSub.ServiceManifestsRequested, do: use Piazza.PubSub.Event

defmodule Console.PubSub.ClusterCreated, do: use Piazza.PubSub.Event
defmodule Console.PubSub.ClusterUpdated, do: use Piazza.PubSub.Event
Expand Down
5 changes: 5 additions & 0 deletions lib/console/deployments/pubsub/protocols/broadcastable.ex
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@ defimpl Console.Deployments.PubSub.Broadcastable, for: [
do: {"cluster:#{cluster_id}", "service.event", %{"id" => id}}
end

defimpl Console.Deployments.PubSub.Broadcastable, for: Console.PubSub.ServiceManifestsRequested do
def message(%{item: %{id: id, cluster_id: cluster_id}}),
do: {"cluster:#{cluster_id}", "service.manifests", %{"id" => id}}
end

defimpl Console.Deployments.PubSub.Broadcastable, for: [Console.PubSub.ClusterRestoreCreated] do
def message(%{item: item}) do
%{id: id, backup: %{cluster_id: cluster_id}} = Console.Repo.preload(item, [:backup])
Expand Down
36 changes: 36 additions & 0 deletions lib/console/deployments/services.ex
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,40 @@ defmodule Console.Deployments.Services do

def tarball(%Service{id: id}), do: api_url("v1/git/tarballs?id=#{id}")

@doc """
Pushes a request to the relevant agent to gather manifests for a service
"""
@spec request_manifests(binary, User.t) :: service_resp
def request_manifests(id, %User{} = user) do
get_service!(id)
|> allow(user, :write)
|> notify(:manifests, user)
end

@doc """
Saves the manifests in cache for 30 minutes to be queried by the ui
"""
@spec save_manifests([binary], binary | Service.t, Cluster.t) :: :ok | Console.error
def save_manifests(manifests, %Service{id: id, cluster_id: cid}, %Cluster{id: cid}),
do: Console.Cache.put({:manifests, id}, manifests, ttl: :timer.minutes(30))
def save_manifests(_, %Service{}, %Cluster{}),
do: {:error, "service doesn't belong to this cluster"}
def save_manifests(manifests, id, %Cluster{} = cluster) when is_binary(id),
do: save_manifests(manifests, get_service!(id), cluster)

@doc """
Fetches the manifests from cache at query time
"""
@spec fetch_manifests(binary, User.t) :: {:ok, [binary]} | Console.error
def fetch_manifests(id, %User{} = user) do
get_service!(id)
|> allow(user, :write)
|> when_ok(fn _ ->
Console.Cache.get({:manifests, id})
|> ok()
end)
end

@doc """
Constructs a filestream for the tar artifact of a service, and perhaps performs some JIT modifications
before sending it upstream to the given client.
Expand Down Expand Up @@ -730,6 +764,8 @@ defmodule Console.Deployments.Services do
do: handle_notify(PubSub.ServiceUpdated, svc, actor: user)
defp notify({:ok, %Service{} = svc}, :delete, user),
do: handle_notify(PubSub.ServiceDeleted, svc, actor: user)
defp notify({:ok, %Service{} = svc}, :manifests, user),
do: handle_notify(PubSub.ServiceManifestsRequested, svc, actor: user)
defp notify(pass, _, _), do: pass

defp notify({:ok, %Service{} = svc}, :components),
Expand Down
25 changes: 25 additions & 0 deletions lib/console/graphql/deployments/service.ex
Original file line number Diff line number Diff line change
Expand Up @@ -377,6 +377,15 @@ defmodule Console.GraphQl.Deployments.Service do

safe_resolve &Deployments.update_service_components/2
end

@desc "save the manifests in cache to be retrieved by the requesting user"
field :save_manifests, :boolean do
middleware ClusterAuthenticated
arg :id, non_null(:id)
arg :manifests, list_of(:string)

safe_resolve &Deployments.save_manifests/2
end
end

object :service_queries do
Expand Down Expand Up @@ -413,6 +422,22 @@ defmodule Console.GraphQl.Deployments.Service do

resolve &Deployments.tree/2
end

@desc "request manifests from an agent, to be returned by a future call to fetchManifests"
field :request_manifests, :service_deployment do
middleware Authenticated
arg :id, non_null(:id)

resolve &Deployments.request_manifests/2
end

@desc "Fetches the manifests from cache once the agent has given us them, will be null otherwise"
field :fetch_manifests, list_of(:string) do
middleware Authenticated
arg :id, non_null(:id)

resolve &Deployments.fetch_manifests/2
end
end

object :service_mutations do
Expand Down
11 changes: 11 additions & 0 deletions lib/console/graphql/resolvers/deployments/service.ex
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,17 @@ defmodule Console.GraphQl.Resolvers.Deployments.Service do
def tarball(svc, _, _), do: {:ok, Services.tarball(svc)}
def docs(svc, _, _), do: Services.docs(svc)

def fetch_manifests(%{id: id}, %{context: %{current_user: user}}),
do: Services.fetch_manifests(id, user)

def request_manifests(%{id: id}, %{context: %{current_user: user}}),
do: Services.request_manifests(id, user)

def save_manifests(%{id: id, manifests: mans}, %{context: %{cluster: cluster}}) do
with :ok <- Services.save_manifests(mans, id, cluster),
do: {:ok, true}
end

defp service_filters(query, args) do
Enum.reduce(args, query, fn
{:cluster_id, id}, q -> Service.for_cluster(q, id)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -612,4 +612,28 @@ defmodule Console.GraphQl.Deployments.ServicesMutationsTest do
assert svc["id"]
end
end

describe "saveManifests" do
test "clusters can save manifests" do
service = insert(:service)

{:ok, %{data: %{"saveManifests" => true}}} = run_query("""
mutation Save($manifests: [String], $id: ID!) {
saveManifests(id: $id, manifests: $manifests)
}
""", %{"manifests" => ["testing"], "id" => service.id}, %{cluster: service.cluster})

{:ok, ["testing"]} = Console.Deployments.Services.fetch_manifests(service.id, admin_user())
end

test "clusters cannot save manifests for services on other clusters" do
service = insert(:service)

{:ok, %{errors: [_ | _]}} = run_query("""
mutation Save($manifests: [String], $id: ID!) {
saveManifests(id: $id, manifests: $manifests)
}
""", %{"manifests" => ["testing"], "id" => service.id}, %{cluster: insert(:cluster)})
end
end
end
48 changes: 48 additions & 0 deletions test/console/graphql/queries/deployments/service_queries_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -380,4 +380,52 @@ defmodule Console.GraphQl.Deployments.ServiceQueriesTest do
|> ids_equal(globals)
end
end

describe "requestManifests" do
test "admins can request manifests" do
service = insert(:service)

{:ok, %{data: %{"requestManifests" => found}}} = run_query("""
query Request($id: ID!) {
requestManifests(id: $id) { id }
}
""", %{"id" => service.id}, %{current_user: admin_user()})


assert found["id"] == service.id
end

test "non-admins cannot request manifests" do
service = insert(:service)

{:ok, %{errors: [_ | _]}} = run_query("""
query Request($id: ID!) {
requestManifests(id: $id) { id }
}
""", %{"id" => service.id}, %{current_user: insert(:user)})
end
end

describe "fetchManifests" do
test "admins can fetch manifests" do
service = insert(:service)
Console.Deployments.Services.save_manifests(["testing"], service.id, service.cluster)

{:ok, %{data: %{"fetchManifests" => ["testing"]}}} = run_query("""
query Fetch($id: ID!) {
fetchManifests(id: $id)
}
""", %{"id" => service.id}, %{current_user: admin_user()})
end

test "non-admins cannot request manifests" do
service = insert(:service)

{:ok, %{errors: [_ | _]}} = run_query("""
query Request($id: ID!) {
fetchManifests(id: $id)
}
""", %{"id" => service.id}, %{current_user: insert(:user)})
end
end
end

0 comments on commit ac845ac

Please sign in to comment.