Files
holos/internal/server/handler/system.go
Jeff McCune dad12acd8d (#178) Seed the Holos Platform itself
Previously this would have needed to be created in pgAdmin.
2024-06-05 14:17:31 -07:00

933 lines
27 KiB
Go

package handler
import (
"bytes"
"context"
"encoding/json"
"fmt"
"slices"
"strings"
"connectrpc.com/connect"
"github.com/gofrs/uuid"
"github.com/holos-run/holos/internal/ent"
"github.com/holos-run/holos/internal/errors"
"github.com/holos-run/holos/internal/server/middleware/authn"
"github.com/holos-run/holos/internal/server/middleware/logger"
holosstrings "github.com/holos-run/holos/internal/strings"
storage "github.com/holos-run/holos/service/gen/holos/storage/v1alpha1"
system "github.com/holos-run/holos/service/gen/holos/system/v1alpha1"
"github.com/holos-run/holos/version"
fieldmask_utils "github.com/mennanov/fieldmask-utils"
)
var adminEmails = []string{"jeff@openinfrastructure.co", "jeff@ois.run"}
// NewSystemHandler returns a new SystemService implementation.
func NewSystemHandler(db *ent.Client) *SystemHandler {
return &SystemHandler{db: db}
}
// SystemHandler implements the PlatformService interface.
type SystemHandler struct {
db *ent.Client
}
func (h *SystemHandler) checkAdmin(ctx context.Context) error {
authnID, err := authn.FromContext(ctx)
if err != nil {
return connect.NewError(connect.CodePermissionDenied, errors.Wrap(err))
}
if !slices.Contains(adminEmails, authnID.Email()) {
err := fmt.Errorf("not an admin:\n\thave (%+v)\n\twant (%+v)", authnID.Email(), strings.Join(adminEmails, ","))
return connect.NewError(connect.CodePermissionDenied, errors.Wrap(err))
}
return nil
}
func (h *SystemHandler) GetVersion(ctx context.Context, req *connect.Request[system.GetVersionRequest]) (*connect.Response[system.GetVersionResponse], error) {
_, err := authn.FromContext(ctx)
if err != nil {
return nil, connect.NewError(connect.CodePermissionDenied, errors.Wrap(err))
}
mask, err := fieldmask_utils.MaskFromProtoFieldMask(req.Msg.GetFieldMask(), holosstrings.PascalCase)
if err != nil {
return nil, errors.Wrap(err)
}
srcVersion := version.NewVersionInfo()
var rpcVersion system.Version
if err := fieldmask_utils.StructToStruct(mask, &srcVersion, &rpcVersion); err != nil {
return nil, errors.Wrap(err)
}
return connect.NewResponse(&system.GetVersionResponse{Version: &rpcVersion}), nil
}
func (h *SystemHandler) DropTables(ctx context.Context, req *connect.Request[system.DropTablesRequest]) (*connect.Response[system.DropTablesResponse], error) {
if err := h.checkAdmin(ctx); err != nil {
return nil, err
}
log := logger.FromContext(ctx)
if err := WithTx(ctx, h.db, func(tx *ent.Tx) (err error) {
var n int
if n, err = tx.Platform.Delete().Exec(ctx); err != nil {
return errors.Wrap(err)
}
log.WarnContext(ctx, "deleted platforms", "count", n)
if n, err = tx.Organization.Delete().Exec(ctx); err != nil {
return errors.Wrap(err)
}
log.WarnContext(ctx, "deleted organizations", "count", n)
if n, err = tx.User.Delete().Exec(ctx); err != nil {
return errors.Wrap(err)
}
log.WarnContext(ctx, "deleted users", "count", n)
return nil
}); err != nil {
return nil, connect.NewError(connect.CodeFailedPrecondition, errors.Wrap(err))
}
return connect.NewResponse(&system.DropTablesResponse{}), nil
}
func (h *SystemHandler) SeedDatabase(ctx context.Context, req *connect.Request[system.SeedDatabaseRequest]) (*connect.Response[system.SeedDatabaseResponse], error) {
if err := h.checkAdmin(ctx); err != nil {
return nil, err
}
if err := WithTx(ctx, h.db, func(tx *ent.Tx) (err error) {
jeff, err := tx.User.Create().
SetID(uuid.FromStringOrNil("018f36fb-e3f2-7f7f-a72f-ce48eb16c82d")).
SetEmail("jeff@openinfrastructure.co").
SetIss("https://login.holos.run").
SetSub("270167759587952539").
SetName("Jeff McCune").
Save(ctx)
if err != nil {
return errors.Wrap(err)
}
nate, err := tx.User.Create().
SetEmail("nate@openinfrastructure.co").
SetIss("https://login.holos.run").
SetSub("269610170491914136").
SetName("Nate McCurdy").
Save(ctx)
if err != nil {
return errors.Wrap(err)
}
gary, err := tx.User.Create().
SetEmail("gary@openinfrastructure.co").
SetIss("https://login.holos.run").
SetSub("270168639938807707").
SetName("Gary Larizza").
Save(ctx)
if err != nil {
return errors.Wrap(err)
}
// Create the org
org, err := tx.Organization.Create().
SetID(uuid.FromStringOrNil("018f36fb-e3f7-7f7f-a1c5-c85fb735d215")).
SetName("ois").
SetDisplayName("Open Infrastructure Services").
SetCreator(jeff).
SetEditor(jeff).
Save(ctx)
if err != nil {
return errors.Wrap(err)
}
// Add org memebers
org, err = org.Update().AddUsers(jeff, gary, nate).Save(ctx)
if err != nil {
return errors.Wrap(err)
}
decoder := json.NewDecoder(bytes.NewReader([]byte(BareForm)))
decoder.DisallowUnknownFields()
var form storage.Form
if err := decoder.Decode(&form); err != nil {
return errors.Wrap(err)
}
decoder = json.NewDecoder(bytes.NewReader([]byte(Model)))
decoder.DisallowUnknownFields()
var model storage.Model
if err := decoder.Decode(&model); err != nil {
return errors.Wrap(err)
}
// The holos platform
err = tx.Platform.Create().
SetID(uuid.FromStringOrNil("018fa1cf-a609-7463-aa6e-fa53bfded1dc")).
SetName("holos").
SetDisplayName("Holos Platform").
SetForm(&form).
SetModel(&model).
SetCreator(jeff).
SetEditor(jeff).
SetOrgID(org.ID).
Exec(ctx)
if err != nil {
return errors.Wrap(err)
}
// Add a platform
err = tx.Platform.Create().
SetID(uuid.FromStringOrNil("018f36fb-e3ff-7f7f-a5d1-7ca2bf499e94")).
SetName("bare").
SetDisplayName("Bare Platform").
SetForm(&form).
SetModel(&model).
SetCreator(jeff).
SetEditor(jeff).
SetOrgID(org.ID).
Exec(ctx)
if err != nil {
return errors.Wrap(err)
}
return nil
}); err != nil {
return nil, connect.NewError(connect.CodeFailedPrecondition, errors.Wrap(err))
}
return connect.NewResponse(&system.SeedDatabaseResponse{}), nil
}
const Model = `{"model":{}}`
const BareForm = `
{
"field_configs": [
{
"key": "org",
"wrappers": [
"holos-panel"
],
"props": {
"label": "Organization",
"description": "Organization config values are used to derive more specific configuration values throughout the platform."
},
"resetOnHide": true,
"fieldGroup": [
{
"key": "name",
"type": "input",
"props": {
"label": "Name",
"description": "DNS label, e.g. 'example'",
"pattern": "^[a-z]([0-9a-z]|-){1,28}[0-9a-z]$",
"minLength": 3,
"maxLength": 30,
"required": true
},
"validation": {
"messages": {
"pattern": "It must be 3 to 30 lowercase letters, digits, or hyphens. It must start with a letter. Trailing hyphens are prohibited."
}
},
"resetOnHide": true
},
{
"key": "domain",
"type": "input",
"props": {
"label": "Domain",
"placeholder": "example.com",
"minLength": 3,
"maxLength": 100,
"description": "DNS domain, e.g. 'example.com'",
"required": true
},
"resetOnHide": true
},
{
"key": "displayName",
"type": "input",
"props": {
"label": "Display Name",
"placeholder": "Example Organization",
"description": "Display name, e.g. 'Example Organization'",
"maxLength": 100,
"required": true
},
"resetOnHide": true
},
{
"key": "contactEmail",
"type": "input",
"props": {
"label": "Contact Email",
"placeholder": "platform-team@example.com",
"description": "Technical contact email address",
"required": true
},
"resetOnHide": true
}
]
},
{
"key": "cloud",
"wrappers": [
"holos-panel"
],
"props": {
"label": "Cloud Providers",
"description": "Select the services that provide resources for the platform."
},
"resetOnHide": true,
"fieldGroup": [
{
"key": "providers",
"type": "select",
"props": {
"label": "Select Providers",
"description": "Select the cloud providers the platform builds upon.",
"multiple": true,
"selectAllOption": "Select All",
"options": [
{
"value": "aws",
"label": "Amazon Web Services"
},
{
"value": "gcp",
"label": "Google Cloud Platform"
},
{
"value": "azure",
"label": "Microsoft Azure"
},
{
"value": "cloudflare",
"label": "Cloudflare"
},
{
"value": "github",
"label": "GitHub"
},
{
"value": "ois",
"label": "Open Infrastructure Services"
},
{
"value": "onprem",
"label": "On Premises",
"disabled": true
}
]
},
"resetOnHide": true
}
]
},
{
"key": "aws",
"wrappers": [
"holos-panel"
],
"props": {
"label": "Amazon Web Services",
"description": "Provide the information necessary for Holos to manage AWS resources to provide the platform."
},
"expressions": {
"hide": "!formState.model.cloud?.providers?.includes(\"aws\")"
},
"resetOnHide": true,
"fieldGroup": [
{
"key": "primaryRoleARN",
"type": "input",
"props": {
"label": "Holos Admin Role ARN",
"description": "Enter the AWS Role ARN Holos will use to bootstrap resources. For example, arn:aws:iam::123456789012:role/HolosAdminAccess",
"pattern": "^arn:.*",
"minLength": 4,
"required": true
},
"validation": {
"messages": {
"pattern": "Must be a valid ARN. Refer to https://docs.aws.amazon.com/IAM/latest/UserGuide/reference-arns.html"
}
},
"resetOnHide": true
},
{
"key": "regions",
"type": "select",
"props": {
"label": "Select Regions",
"description": "Select the AWS regions this platform operates in.",
"multiple": true,
"required": true,
"selectAllOption": "Select All",
"options": [
{
"value": "us-east-1",
"label": "N. Virginia (us-east-1)"
},
{
"value": "us-east-2",
"label": "Ohio (us-east-2)"
},
{
"value": "us-west-1",
"label": "N. California (us-west-1)"
},
{
"value": "us-west-2",
"label": "Oregon (us-west-2)"
},
{
"value": "us-gov-west1",
"label": "US GovCloud West (us-gov-west1)"
},
{
"value": "us-gov-east1",
"label": "US GovCloud East (us-gov-east1)"
},
{
"value": "ca-central-1",
"label": "Canada (ca-central-1)"
},
{
"value": "eu-north-1",
"label": "Stockholm (eu-north-1)"
},
{
"value": "eu-west-1",
"label": "Ireland (eu-west-1)"
},
{
"value": "eu-west-2",
"label": "London (eu-west-2)"
},
{
"value": "eu-west-3",
"label": "Paris (eu-west-3)"
},
{
"value": "eu-central-1",
"label": "Frankfurt (eu-central-1)"
},
{
"value": "eu-south-1",
"label": "Milan (eu-south-1)"
},
{
"value": "af-south-1",
"label": "Cape Town (af-south-1)"
},
{
"value": "ap-northeast-1",
"label": "Tokyo (ap-northeast-1)"
},
{
"value": "ap-northeast-2",
"label": "Seoul (ap-northeast-2)"
},
{
"value": "ap-northeast-3",
"label": "Osaka (ap-northeast-3)"
},
{
"value": "ap-southeast-1",
"label": "Singapore (ap-southeast-1)"
},
{
"value": "ap-southeast-2",
"label": "Sydney (ap-southeast-2)"
},
{
"value": "ap-east-1",
"label": "Hong Kong (ap-east-1)"
},
{
"value": "ap-south-1",
"label": "Mumbai (ap-south-1)"
},
{
"value": "me-south-1",
"label": "Bahrain (me-south-1)"
},
{
"value": "sa-east-1",
"label": "São Paulo (sa-east-1)"
},
{
"value": "cn-north-1",
"label": "Bejing (cn-north-1)"
},
{
"value": "cn-northwest-1",
"label": "Ningxia (cn-northwest-1)"
},
{
"value": "ap-southeast-3",
"label": "Jakarta (ap-southeast-3)"
}
]
},
"resetOnHide": true
}
]
},
{
"key": "gcp",
"wrappers": [
"holos-panel"
],
"props": {
"label": "Google Cloud Platform",
"description": "Use this form to configure platform level GCP settings."
},
"expressions": {
"hide": "!formState.model.cloud?.providers?.includes(\"gcp\")"
},
"resetOnHide": true,
"fieldGroup": [
{
"key": "regions",
"type": "select",
"props": {
"label": "Select Regions",
"description": "Select the GCP regions this platform operates in.",
"multiple": true,
"selectAllOption": "Select All",
"options": [
{
"value": "africa-south1",
"label": "africa-south1"
},
{
"value": "asia-east1",
"label": "asia-east1"
},
{
"value": "asia-east2",
"label": "asia-east2"
},
{
"value": "asia-northeast1",
"label": "asia-northeast1"
},
{
"value": "asia-northeast2",
"label": "asia-northeast2"
},
{
"value": "asia-northeast3",
"label": "asia-northeast3"
},
{
"value": "asia-south1",
"label": "asia-south1"
},
{
"value": "asia-south2",
"label": "asia-south2"
},
{
"value": "asia-southeast1",
"label": "asia-southeast1"
},
{
"value": "asia-southeast2",
"label": "asia-southeast2"
},
{
"value": "australia-southeast1",
"label": "australia-southeast1"
},
{
"value": "australia-southeast2",
"label": "australia-southeast2"
},
{
"value": "europe-central2",
"label": "europe-central2"
},
{
"value": "europe-north1",
"label": "europe-north1"
},
{
"value": "europe-southwest1",
"label": "europe-southwest1"
},
{
"value": "europe-west1",
"label": "europe-west1"
},
{
"value": "europe-west10",
"label": "europe-west10"
},
{
"value": "europe-west12",
"label": "europe-west12"
},
{
"value": "europe-west2",
"label": "europe-west2"
},
{
"value": "europe-west3",
"label": "europe-west3"
},
{
"value": "europe-west4",
"label": "europe-west4"
},
{
"value": "europe-west6",
"label": "europe-west6"
},
{
"value": "europe-west8",
"label": "europe-west8"
},
{
"value": "europe-west9",
"label": "europe-west9"
},
{
"value": "me-central1",
"label": "me-central1"
},
{
"value": "me-central2",
"label": "me-central2"
},
{
"value": "me-west1",
"label": "me-west1"
},
{
"value": "northamerica-northeast1",
"label": "northamerica-northeast1"
},
{
"value": "northamerica-northeast2",
"label": "northamerica-northeast2"
},
{
"value": "southamerica-east1",
"label": "southamerica-east1"
},
{
"value": "southamerica-west1",
"label": "southamerica-west1"
},
{
"value": "us-central1",
"label": "us-central1"
},
{
"value": "us-east1",
"label": "us-east1"
},
{
"value": "us-east4",
"label": "us-east4"
},
{
"value": "us-east5",
"label": "us-east5"
},
{
"value": "us-south1",
"label": "us-south1"
},
{
"value": "us-west1",
"label": "us-west1"
},
{
"value": "us-west2",
"label": "us-west2"
},
{
"value": "us-west3",
"label": "us-west3"
},
{
"value": "us-west4",
"label": "us-west4"
}
]
},
"resetOnHide": true
},
{
"key": "gcpProjectID",
"type": "input",
"props": {
"label": "Project ID",
"description": "Enter the project id where the provisioner cluster resides.",
"pattern": "^[a-z]([0-9a-z]|-){1,28}[0-9a-z]$",
"minLength": 6,
"maxLength": 30,
"required": true
},
"validation": {
"messages": {
"pattern": "It must be 3 to 30 lowercase letters, digits, or hyphens. It must start with a letter. Trailing hyphens are prohibited."
}
},
"resetOnHide": true
},
{
"key": "gcpProjectNumber",
"type": "input",
"props": {
"label": "Project Number",
"type": "number",
"description": "Enter the project number where the provisioner cluster resides.",
"pattern": "^[0-9]+$",
"required": true
},
"validation": {
"messages": {
"pattern": "Must be a valid project number."
}
},
"resetOnHide": true
},
{
"key": "provisionerCABundle",
"type": "input",
"props": {
"label": "Provisioner CA Bundle",
"description": "Enter the provisioner cluster ca bundle. kubectl config view --minify --flatten -ojsonpath='{.clusters[0].cluster.certificate-authority-data}'",
"pattern": "^[0-9a-zA-Z]+=*$",
"required": true
},
"validation": {
"messages": {
"pattern": "Must be a base64 encoded pem encoded certificate bundle."
}
},
"resetOnHide": true
},
{
"key": "provisionerURL",
"type": "input",
"props": {
"label": "Provisioner URL",
"description": "Enter the URL of the provisioner cluster API endpoint. kubectl config view --minify --flatten -ojsonpath='{.clusters[0].cluster.server}'",
"pattern": "^https://.*$",
"required": true
},
"validation": {
"messages": {
"pattern": "Must be a https:// URL."
}
},
"resetOnHide": true
}
]
},
{
"key": "cloudflare",
"wrappers": [
"holos-panel"
],
"props": {
"label": "Cloudflare",
"description": "Cloudflare is primarily used for DNS automation."
},
"expressions": {
"hide": "!formState.model.cloud?.providers?.includes(\"cloudflare\")"
},
"resetOnHide": true,
"fieldGroup": [
{
"key": "email",
"type": "input",
"props": {
"label": "Account Email",
"description": "Enter the Cloudflare email address to manage DNS",
"minLength": 3,
"required": true
},
"resetOnHide": true
}
]
},
{
"key": "github",
"wrappers": [
"holos-panel"
],
"props": {
"label": "GitHub",
"description": "GitHub is primarily used to host Git repositories and execute Actions workflows."
},
"expressions": {
"hide": "!formState.model.cloud?.providers?.includes(\"github\")"
},
"resetOnHide": true,
"fieldGroup": [
{
"key": "primaryOrg",
"type": "input",
"props": {
"label": "Organization",
"description": "Enter the primary GitHub organization associed with the platform.",
"pattern": "^(?!-)(?!.*--)([a-zA-Z0-9]|-){1,39}$",
"minLength": 1,
"maxLength": 39,
"required": true
},
"validation": {
"messages": {
"pattern": "All characters must be either a hyphen or alphanumeric. Cannot start with a hyphen. Cannot include consecutive hyphens."
}
},
"resetOnHide": true
}
]
},
{
"key": "backups",
"wrappers": [
"holos-panel"
],
"props": {
"label": "Backups",
"description": "Configure platform level data backup settings. Requires AWS."
},
"resetOnHide": true,
"fieldGroup": [
{
"key": "s3bucket",
"type": "select",
"props": {
"label": "S3 Bucket Region",
"description": "Select the S3 Bucket Region.",
"multiple": true,
"options": [
{
"value": "us-east-1",
"label": "N. Virginia (us-east-1)"
},
{
"value": "us-east-2",
"label": "Ohio (us-east-2)"
},
{
"value": "us-west-1",
"label": "N. California (us-west-1)"
},
{
"value": "us-west-2",
"label": "Oregon (us-west-2)"
},
{
"value": "us-gov-west1",
"label": "US GovCloud West (us-gov-west1)"
},
{
"value": "us-gov-east1",
"label": "US GovCloud East (us-gov-east1)"
},
{
"value": "ca-central-1",
"label": "Canada (ca-central-1)"
},
{
"value": "eu-north-1",
"label": "Stockholm (eu-north-1)"
},
{
"value": "eu-west-1",
"label": "Ireland (eu-west-1)"
},
{
"value": "eu-west-2",
"label": "London (eu-west-2)"
},
{
"value": "eu-west-3",
"label": "Paris (eu-west-3)"
},
{
"value": "eu-central-1",
"label": "Frankfurt (eu-central-1)"
},
{
"value": "eu-south-1",
"label": "Milan (eu-south-1)"
},
{
"value": "af-south-1",
"label": "Cape Town (af-south-1)"
},
{
"value": "ap-northeast-1",
"label": "Tokyo (ap-northeast-1)"
},
{
"value": "ap-northeast-2",
"label": "Seoul (ap-northeast-2)"
},
{
"value": "ap-northeast-3",
"label": "Osaka (ap-northeast-3)"
},
{
"value": "ap-southeast-1",
"label": "Singapore (ap-southeast-1)"
},
{
"value": "ap-southeast-2",
"label": "Sydney (ap-southeast-2)"
},
{
"value": "ap-east-1",
"label": "Hong Kong (ap-east-1)"
},
{
"value": "ap-south-1",
"label": "Mumbai (ap-south-1)"
},
{
"value": "me-south-1",
"label": "Bahrain (me-south-1)"
},
{
"value": "sa-east-1",
"label": "São Paulo (sa-east-1)"
},
{
"value": "cn-north-1",
"label": "Bejing (cn-north-1)"
},
{
"value": "cn-northwest-1",
"label": "Ningxia (cn-northwest-1)"
},
{
"value": "ap-southeast-3",
"label": "Jakarta (ap-southeast-3)"
}
]
},
"expressions": {
"props.disabled": "!formState.model.cloud?.providers?.includes(\"aws\")",
"props.required": "formState.model.cloud?.providers?.includes(\"aws\")",
"props.description": "formState.model.cloud?.providers?.includes(\"aws\") ? 'Select the S3 Bucket Region.' : 'Enable AWS in the Cloud Provider section to configure backups.'"
},
"resetOnHide": true
}
]
}
]
}
`