Skip to content

Commit

Permalink
Add credential module for cluster
Browse files Browse the repository at this point in the history
  • Loading branch information
zacksiri committed Jun 21, 2024
1 parent b1fdefe commit 3d34da9
Show file tree
Hide file tree
Showing 2 changed files with 129 additions and 1 deletion.
60 changes: 59 additions & 1 deletion lib/polar/machines/cluster.ex
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,34 @@ defmodule Polar.Machines.Cluster do
use Ecto.Schema
import Ecto.Changeset

alias __MODULE__.Credential

@valid_attrs ~w(
name
type
arch
credential
)a

@required_attrs ~w(
name
type
arch
credential_endpoint
credential_password
credential_password_confirmation
)a

schema "clusters" do
field :name, :string
field :current_state, :string, default: "created"

field :type, :string
field :type, :string, default: "lxd"
field :arch, :string

field :credential_endpoint, :string, virtual: true
field :credential_password, :string, virtual: true
field :credential_password_confirmation, :string, virtual: true
field :credential, Polar.Encrypted.Map

timestamps(type: :utc_datetime_usec)
Expand All @@ -26,5 +40,49 @@ defmodule Polar.Machines.Cluster do
cluster
|> cast(attrs, @valid_attrs)
|> validate_required(@valid_attrs)
|> validate_inclusion(:type, ["lxd", "incus"])
|> validate_inclusion(:arch, ["amd64", "arm64"])
|> process_credential()
end

def update_changeset(cluster, attrs) do
cluster
|> cast(attrs, [:credential_endpoint])
|> maybe_update_credential()
end

defp maybe_update_credential(%{data: %{credential: credential}} = changeset) do
if changeset.valid? do
endpoint = get_change(changeset, :credential_endpoint)

credential =
%Credential{
endpoint: credential["endpoint"],
private_key: credential["private_key"],
certificate: credential["certificate"]
}
|> Credential.update!(%{endpoint: "https://#{endpoint}"})

put_change(changeset, :credential, credential)
else
changeset
end
end

defp process_credential(changeset) do
if changeset.valid? do
endpoint = get_change(changeset, :credential_endpoint)

credential =
Credential.create!(%{
endpoint: "https://#{endpoint}",
password: get_change(changeset, :credential_password),
password_confirmation: get_change(changeset, :credential_password_confirmation)
})

put_change(changeset, :credential, credential)
else
changeset
end
end
end
70 changes: 70 additions & 0 deletions lib/polar/machines/cluster/credential.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
defmodule Polar.Machines.Cluster.Credential do
use Ecto.Schema
import Ecto.Changeset

@valid_attrs ~w(endpoint password password_confirmation)a
@required_attrs ~w(endpoint password private_key certificate)a

@primary_key false
embedded_schema do
field :endpoint, :string

field :password, :string
field :password_confirmation, :string, virtual: true

field :private_key, :string
field :certificate, :string
end

@spec create!(map) :: %__MODULE__{}
def create!(attrs) do
%__MODULE__{}
|> changeset(attrs)
|> apply_action!(:insert)
end

def update!(credential, attrs) do
credential
|> cast(attrs, [:endpoint])
|> apply_action!(:insert)
end

def changeset(credential, attrs) do
credential
|> cast(attrs, @valid_attrs)
|> generate_certificate()
|> validate_password()
|> validate_required(@required_attrs)
end

defp validate_password(changeset) do
validate_change(changeset, :password, fn :password, password ->
password_confirmation = get_change(changeset, :password_confirmation)

if password == password_confirmation do
[]
else
[password: "do not match"]
end
end)
end

defp generate_certificate(changeset) do
ca_key = X509.PrivateKey.new_ec(:secp256r1)

ca =
X509.Certificate.self_signed(
ca_key,
"/C=US/ST=DE/L=Newark/O=Upmaru/CN=instellar.app",
template: :root_ca
)

ca_key = X509.PrivateKey.to_pem(ca_key)

ca = X509.Certificate.to_pem(ca)

changeset
|> put_change(:private_key, ca_key)
|> put_change(:certificate, ca)
end
end

0 comments on commit 3d34da9

Please sign in to comment.