feat: add hatchet-admin command and improve dockerfiles (#18)

* feat: add `hatchet-admin` command and improve dockerfiles

- Also bumps `prisma-client-go` version
This commit is contained in:
abelanger5
2023-12-21 16:38:17 -05:00
committed by GitHub
parent 806dae5742
commit 14ecac8b81
27 changed files with 806 additions and 227 deletions

View File

@@ -28,6 +28,30 @@ jobs:
- name: Push to GHCR
run: |
docker push ghcr.io/hatchet-dev/hatchet/hatchet-api:${{steps.tag_name.outputs.tag}}
build-push-hatchet-admin:
name: hatchet-admin
runs-on: ubuntu-latest
steps:
- name: Get tag name
id: tag_name
run: echo "tag=${GITHUB_TAG/refs\/tags\//}" >> $GITHUB_OUTPUT
env:
GITHUB_TAG: ${{ github.ref }}
- name: Checkout
uses: actions/checkout@v3
- name: Login to GHCR
id: login-ghcr
run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin
- name: Build
run: |
DOCKER_BUILDKIT=1 docker build -f ./build/package/servers.Dockerfile \
-t ghcr.io/hatchet-dev/hatchet/hatchet-admin:${{steps.tag_name.outputs.tag}} \
--build-arg SERVER_TARGET=admin \
--build-arg VERSION=${{steps.tag_name.outputs.tag}} \
.
- name: Push to GHCR
run: |
docker push ghcr.io/hatchet-dev/hatchet/hatchet-admin:${{steps.tag_name.outputs.tag}}
build-push-hatchet-engine:
name: hatchet-engine
runs-on: ubuntu-latest

View File

@@ -27,6 +27,11 @@ jobs:
docker pull ghcr.io/hatchet-dev/hatchet/hatchet-engine:${{steps.tag_name.outputs.tag}}
docker tag ghcr.io/hatchet-dev/hatchet/hatchet-engine:${{steps.tag_name.outputs.tag}} ghcr.io/hatchet-dev/hatchet/hatchet-engine:latest
docker push ghcr.io/hatchet-dev/hatchet/hatchet-engine:latest
- name: Pull and push hatchet-admin
run: |
docker pull ghcr.io/hatchet-dev/hatchet/hatchet-admin:${{steps.tag_name.outputs.tag}}
docker tag ghcr.io/hatchet-dev/hatchet/hatchet-admin:${{steps.tag_name.outputs.tag}} ghcr.io/hatchet-dev/hatchet/hatchet-admin:latest
docker push ghcr.io/hatchet-dev/hatchet/hatchet-admin:latest
- name: Pull and push hatchet-frontend
run: |
docker pull ghcr.io/hatchet-dev/hatchet/hatchet-frontend:${{steps.tag_name.outputs.tag}}

1
.gitignore vendored
View File

@@ -23,6 +23,7 @@ dump.rdb
*.csr
*.pfx
*.cert
generated
node_modules

View File

@@ -13,7 +13,7 @@ tasks:
seed-dev:
cmds:
- sh ./hack/dev/run-npx-with-env.sh prisma db push --force-reset
- sh ./hack/dev/run-go-with-env.sh run ./cmd/seed
- SEED_DEVELOPMENT=true sh ./hack/dev/run-go-with-env.sh run ./cmd/hatchet-admin seed
start-dev:
deps:
- task: start-api

View File

@@ -49,7 +49,7 @@ const (
// Defines values for StepRunStatus.
const (
StepRunStatusASSIGNED StepRunStatus = "ASSIGNED"
StepRunStatusCANCELLED StepRunStatus = "CANCELLED"
StepRunStatusCancelled StepRunStatus = "CANCELLED"
StepRunStatusFAILED StepRunStatus = "FAILED"
StepRunStatusPENDING StepRunStatus = "PENDING"
StepRunStatusPENDINGASSIGNMENT StepRunStatus = "PENDING_ASSIGNMENT"

View File

@@ -5,7 +5,17 @@ WORKDIR /hatchet
RUN apk update && apk add --no-cache gcc musl-dev git protoc protobuf-dev
RUN go install google.golang.org/protobuf/cmd/protoc-gen-go@v1.28
RUN go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@v1.2
RUN go install github.com/deepmap/oapi-codegen/v2/cmd/oapi-codegen@v2.0.0
COPY go.mod go.sum ./
RUN go mod download
# prefetch the binaries, so that they will be cached and not downloaded on each change
RUN go run github.com/steebchen/prisma-client-go prefetch
COPY /api ./api
COPY /api-contracts ./api-contracts
COPY /internal ./internal
@@ -14,16 +24,6 @@ COPY /hack ./hack
COPY /prisma ./prisma
COPY /cmd ./cmd
RUN go install google.golang.org/protobuf/cmd/protoc-gen-go@v1.28
RUN go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@v1.2
RUN go install github.com/deepmap/oapi-codegen/v2/cmd/oapi-codegen@latest
RUN --mount=type=cache,target=$GOPATH/pkg/mod \
go mod download
# prefetch the binaries, so that they will be cached and not downloaded on each change
RUN go run github.com/steebchen/prisma-client-go prefetch
# generate the Prisma Client Go client
RUN go run github.com/steebchen/prisma-client-go generate --generator go
@@ -32,12 +32,12 @@ RUN go run github.com/steebchen/prisma-client-go generate --generator go
FROM node:16-alpine as build-openapi
WORKDIR /openapi
COPY /api-contracts/openapi ./openapi
RUN npm install -g npm@8.1
RUN npm install -g @apidevtools/swagger-cli prisma
COPY /api-contracts/openapi ./openapi
RUN swagger-cli bundle ./openapi/openapi.yaml --outfile ./bin/oas/openapi.yaml --type yaml
# Go build environment
@@ -49,9 +49,9 @@ ARG VERSION=v0.1.0-alpha.0
# can be set to "api" or "engine"
ARG SERVER_TARGET
# check if the target is empty or not set to api or engine
RUN if [ -z "$SERVER_TARGET" ] || [ "$SERVER_TARGET" != "api" ] && [ "$SERVER_TARGET" != "engine" ]; then \
echo "SERVER_TARGET must be set to 'api' or 'engine'"; \
# check if the target is empty or not set to api, engine, or admin
RUN if [ -z "$SERVER_TARGET" ] || [ "$SERVER_TARGET" != "api" ] && [ "$SERVER_TARGET" != "engine" ] && [ "$SERVER_TARGET" != "admin" ]; then \
echo "SERVER_TARGET must be set to 'api', 'engine', or 'admin'"; \
exit 1; \
fi
@@ -73,8 +73,12 @@ FROM alpine AS deployment
# can be set to "api" or "engine"
ARG SERVER_TARGET=engine
RUN apk update && apk add --no-cache gcc musl-dev
WORKDIR /hatchet
# openssl and bash needed for admin build
RUN apk update && apk add --no-cache gcc musl-dev openssl bash
COPY --from=base /hatchet/prisma ./prisma
COPY --from=build-go /hatchet/bin/hatchet-${SERVER_TARGET} /hatchet/
EXPOSE 8080

View File

@@ -0,0 +1,17 @@
[req]
default_bits = 4096
prompt = no
default_md = sha256
req_extensions = req_ext
distinguished_name = dn
[dn]
C = US
ST = NY
O = Hatchet
CN = cluster
[req_ext]
subjectAltName = @alt_names
[alt_names]
DNS.1 = cluster
IP.1 = ::1
IP.2 = 127.0.0.1

View File

@@ -0,0 +1,23 @@
#!/bin/bash
# This scripts generates test keys and certificates for the sample.
CERTS_DIR=$1
echo "generating certs in dir: $1"
# Generate a private key and a certificate for a test certificate authority
openssl genrsa -out $CERTS_DIR/ca.key 4096
openssl req -new -x509 -key $CERTS_DIR/ca.key -sha256 -subj "/C=US/ST=NY/O=Hatchet" -days 365 -out $CERTS_DIR/ca.cert
# Generate a private key and a certificate for cluster
openssl genrsa -out $CERTS_DIR/cluster.key 4096
openssl req -new -key $CERTS_DIR/cluster.key -out $CERTS_DIR/cluster.csr -config $CERTS_DIR/cluster-cert.conf
openssl x509 -req -in $CERTS_DIR/cluster.csr -CA $CERTS_DIR/ca.cert -CAkey $CERTS_DIR/ca.key -CAcreateserial -out $CERTS_DIR/cluster.pem -days 365 -sha256 -extfile $CERTS_DIR/cluster-cert.conf -extensions req_ext
# Generate a private key and a certificate for internal admin client
openssl req -newkey rsa:4096 -nodes -keyout "$CERTS_DIR/client-internal-admin.key" -out "$CERTS_DIR/client-internal-admin.csr" -config $CERTS_DIR/internal-admin-client-cert.conf
openssl x509 -req -in $CERTS_DIR/client-internal-admin.csr -CA $CERTS_DIR/ca.cert -CAkey $CERTS_DIR/ca.key -CAcreateserial -out $CERTS_DIR/client-internal-admin.pem -days 365 -sha256 -extfile $CERTS_DIR/internal-admin-client-cert.conf -extensions req_ext
# Generate a private key and a certificate for worker client
openssl req -newkey rsa:4096 -nodes -keyout "$CERTS_DIR/client-worker.key" -out "$CERTS_DIR/client-worker.csr" -config $CERTS_DIR/worker-client-cert.conf
openssl x509 -req -in $CERTS_DIR/client-worker.csr -CA $CERTS_DIR/ca.cert -CAkey $CERTS_DIR/ca.key -CAcreateserial -out $CERTS_DIR/client-worker.pem -days 365 -sha256 -extfile $CERTS_DIR/worker-client-cert.conf -extensions req_ext

View File

@@ -0,0 +1,17 @@
[req]
default_bits = 4096
prompt = no
default_md = sha256
req_extensions = req_ext
distinguished_name = dn
[dn]
C = US
ST = NY
O = Hatchet
CN = internal-admin
[req_ext]
subjectAltName = @alt_names
[alt_names]
DNS.1 = localhost
IP.1 = ::1
IP.2 = 127.0.0.1

View File

@@ -0,0 +1,17 @@
[req]
default_bits = 4096
prompt = no
default_md = sha256
req_extensions = req_ext
distinguished_name = dn
[dn]
C = US
ST = NY
O = Hatchet
CN = worker
[req_ext]
subjectAltName = @alt_names
[alt_names]
DNS.1 = localhost
IP.1 = ::1
IP.2 = 127.0.0.1

View File

@@ -0,0 +1,338 @@
package cli
import (
_ "embed"
"io/ioutil"
"fmt"
"os"
"os/exec"
"path/filepath"
"strings"
"github.com/fatih/color"
"github.com/hatchet-dev/hatchet/internal/config/database"
"github.com/hatchet-dev/hatchet/internal/config/loader"
"github.com/hatchet-dev/hatchet/internal/config/server"
"github.com/hatchet-dev/hatchet/internal/encryption"
"sigs.k8s.io/yaml"
"github.com/spf13/cobra"
)
var certDir string
var generatedConfigDir string
var skip []string
var overwrite bool
const (
StageCerts string = "certs"
StageKeys string = "keys"
StageSeed string = "seed"
)
var quickstartCmd = &cobra.Command{
Use: "quickstart",
Short: "Command used to setup a Hatchet instance",
Run: func(cmd *cobra.Command, args []string) {
err := runQuickstart()
if err != nil {
red := color.New(color.FgRed)
red.Printf("Error running [%s]:%s\n", cmd.Use, err.Error())
os.Exit(1)
}
},
}
func init() {
rootCmd.AddCommand(quickstartCmd)
quickstartCmd.PersistentFlags().StringVar(
&certDir,
"cert-dir",
"./certs",
"path to the directory where certificates should be stored",
)
quickstartCmd.PersistentFlags().StringVar(
&generatedConfigDir,
"generated-config-dir",
"./generated",
"path to the directory where the generated config should be written",
)
quickstartCmd.PersistentFlags().StringArrayVar(
&skip,
"skip",
[]string{},
"a list of steps to skip. possible values are \"certs\"",
)
quickstartCmd.PersistentFlags().BoolVar(
&overwrite,
"overwrite",
true,
"whether generated files should be overwritten, if they exist",
)
}
func runQuickstart() error {
generated, err := loadBaseConfigFiles()
if err != nil {
return fmt.Errorf("could not get base config files: %w", err)
}
if !shouldSkip(StageCerts) {
err := setupCerts(generated)
if err != nil {
return fmt.Errorf("could not setup certs: %w", err)
}
}
if !shouldSkip(StageKeys) {
err := generateKeys(generated)
if err != nil {
return fmt.Errorf("could not generate keys: %w", err)
}
}
err = writeGeneratedConfig(generated)
if err != nil {
return fmt.Errorf("could not write generated config files: %w", err)
}
if !shouldSkip(StageSeed) {
// reload config at this point
configLoader := loader.NewConfigLoader(configDirectory)
err = runSeed(configLoader)
if err != nil {
return fmt.Errorf("could not run seed: %w", err)
}
}
return nil
}
func shouldSkip(stage string) bool {
for _, skipStage := range skip {
if stage == skipStage {
return true
}
}
return false
}
//go:embed certs/cluster-cert.conf
var ClusterCertConf []byte
//go:embed certs/internal-admin-client-cert.conf
var InternalAdminClientCertConf []byte
//go:embed certs/worker-client-cert.conf
var WorkerClientCertConf []byte
//go:embed certs/generate-certs.sh
var GenerateCertsScript string
type generatedConfigFiles struct {
sc *server.ServerConfigFile
dc *database.ConfigFile
}
func setupCerts(generated *generatedConfigFiles) error {
color.New(color.FgGreen).Printf("Generating certificates in cert directory %s\n", certDir)
// verify that bash and openssl are installed on the system
if !commandExists("openssl") {
return fmt.Errorf("openssl must be installed and available in your $PATH")
}
if !commandExists("bash") {
return fmt.Errorf("bash must be installed and available in your $PATH")
}
// write certificate config files to system
fullPathCertDir, err := filepath.Abs(certDir)
if err != nil {
return err
}
err = os.MkdirAll(fullPathCertDir, os.ModePerm)
if err != nil {
return fmt.Errorf("could not create cert directory: %w", err)
}
err = os.WriteFile(filepath.Join(fullPathCertDir, "./cluster-cert.conf"), ClusterCertConf, 0666)
if err != nil {
return fmt.Errorf("could not create cluster-cert.conf file: %w", err)
}
err = os.WriteFile(filepath.Join(fullPathCertDir, "./internal-admin-client-cert.conf"), InternalAdminClientCertConf, 0666)
if err != nil {
return fmt.Errorf("could not create internal-admin-client-cert.conf file: %w", err)
}
err = os.WriteFile(filepath.Join(fullPathCertDir, "./worker-client-cert.conf"), WorkerClientCertConf, 0666)
if err != nil {
return fmt.Errorf("could not create worker-client-cert.conf file: %w", err)
}
// run openssl commands
c := exec.Command("bash", "-s", "-", fullPathCertDir)
c.Stdin = strings.NewReader(GenerateCertsScript)
c.Stdout = os.Stdout
c.Stderr = os.Stderr
err = c.Run()
if err != nil {
return err
}
generated.sc.TLS.TLSRootCAFile = filepath.Join(fullPathCertDir, "ca.cert")
generated.sc.TLS.TLSCertFile = filepath.Join(fullPathCertDir, "client-internal-admin.pem")
generated.sc.TLS.TLSKeyFile = filepath.Join(fullPathCertDir, "client-internal-admin.key")
return nil
}
func generateKeys(generated *generatedConfigFiles) error {
color.New(color.FgGreen).Printf("Generating encryption keys for Hatchet server\n")
cookieHashKey, err := encryption.GenerateRandomBytes(8)
if err != nil {
return fmt.Errorf("could not generate hash key for instance: %w", err)
}
cookieBlockKey, err := encryption.GenerateRandomBytes(8)
if err != nil {
return fmt.Errorf("could not generate block key for instance: %w", err)
}
if overwrite || (generated.sc.Auth.Cookie.Secrets == "") {
generated.sc.Auth.Cookie.Secrets = fmt.Sprintf("%s %s", cookieHashKey, cookieBlockKey)
}
return nil
}
func fileExists(filename string) bool {
info, err := os.Stat(filename)
if os.IsNotExist(err) {
return false
}
return !info.IsDir()
}
func commandExists(cmd string) bool {
_, err := exec.LookPath(cmd)
return err == nil
}
func loadBaseConfigFiles() (*generatedConfigFiles, error) {
res := &generatedConfigFiles{}
var err error
res.dc, err = loader.LoadDatabaseConfigFile(getFiles("database.yaml")...)
if err != nil {
return nil, err
}
res.sc, err = loader.LoadServerConfigFile(getFiles("server.yaml")...)
if err != nil {
return nil, err
}
return res, nil
}
func shouldWriteConfig(conf string) bool {
return overwrite || conf == ""
}
func getFiles(name string) [][]byte {
files := [][]byte{}
basePath := filepath.Join(configDirectory, name)
if fileExists(basePath) {
configFileBytes, err := ioutil.ReadFile(basePath)
if err != nil {
panic(err)
}
files = append(files, configFileBytes)
}
generatedPath := filepath.Join(generatedConfigDir, name)
if fileExists(generatedPath) {
generatedFileBytes, err := ioutil.ReadFile(filepath.Join(generatedConfigDir, name))
if err != nil {
panic(err)
}
files = append(files, generatedFileBytes)
}
return files
}
func writeGeneratedConfig(generated *generatedConfigFiles) error {
color.New(color.FgGreen).Printf("Generating config files %s\n", generatedConfigDir)
err := os.MkdirAll(generatedConfigDir, os.ModePerm)
if err != nil {
return fmt.Errorf("could not create generated config directory: %w", err)
}
databasePath := filepath.Join(generatedConfigDir, "./database.yaml")
databaseConfigBytes, err := yaml.Marshal(generated.dc)
if err != nil {
return err
}
err = ioutil.WriteFile(databasePath, databaseConfigBytes, 0666)
if err != nil {
return fmt.Errorf("could not write database.yaml file: %w", err)
}
serverPath := filepath.Join(generatedConfigDir, "./server.yaml")
serverConfigBytes, err := yaml.Marshal(generated.sc)
if err != nil {
return err
}
err = ioutil.WriteFile(serverPath, serverConfigBytes, 0666)
if err != nil {
return fmt.Errorf("could not write server.yaml file: %w", err)
}
return nil
}

View File

@@ -0,0 +1,63 @@
package cli
import (
"fmt"
"os"
"github.com/spf13/cobra"
)
// Version will be linked by an ldflag during build
var Version string = "v0.1.0-alpha.0"
var printVersion bool
var configDirectory string
// rootCmd represents the base command when called without any subcommands
var rootCmd = &cobra.Command{
Use: "hatchet-admin",
Short: "hatchet-admin performs administrative tasks for a Hatchet instance.",
PersistentPreRun: func(cmd *cobra.Command, args []string) {
if printVersion {
fmt.Println(Version)
os.Exit(0)
}
// var err error
// configLoader := loader.NewConfigLoader(configDirectory)
// sc, err = configLoader.LoadServerConfig()
// if err != nil {
// fmt.Printf("Fatal: could not load server config: %v\n", err)
// os.Exit(1)
// }
},
Run: func(cmd *cobra.Command, args []string) {
return
},
}
// Execute adds all child commands to the root command and sets flags appropriately.
// This is called by main.main(). It only needs to happen once to the rootCmd.
func Execute() {
rootCmd.PersistentFlags().BoolVar(
&printVersion,
"version",
false,
"print version and exit.",
)
rootCmd.PersistentFlags().StringVar(
&configDirectory,
"config",
"",
"The path the config folder.",
)
if err := rootCmd.Execute(); err != nil {
fmt.Println(err)
os.Exit(1)
}
}

View File

@@ -0,0 +1,185 @@
package cli
import (
"errors"
"fmt"
"os"
"github.com/hatchet-dev/hatchet/internal/config/loader"
"github.com/hatchet-dev/hatchet/internal/datautils"
"github.com/hatchet-dev/hatchet/internal/repository"
"github.com/hatchet-dev/hatchet/internal/repository/prisma/db"
"github.com/spf13/cobra"
)
// seedCmd seeds the database with initial data
var seedCmd = &cobra.Command{
Use: "seed",
Short: "seed create initial data in the database.",
Run: func(cmd *cobra.Command, args []string) {
var err error
configLoader := loader.NewConfigLoader(configDirectory)
err = runSeed(configLoader)
if err != nil {
fmt.Printf("Fatal: could not load server config: %v\n", err)
os.Exit(1)
}
},
}
func init() {
rootCmd.AddCommand(seedCmd)
}
func runSeed(cf *loader.ConfigLoader) error {
// load the config
dc, err := cf.LoadDatabaseConfig()
if err != nil {
panic(err)
}
shouldSeedUser := dc.Seed.AdminEmail != "" && dc.Seed.AdminPassword != ""
var userId string
if shouldSeedUser {
// seed an example user
hashedPw, err := repository.HashPassword(dc.Seed.AdminPassword)
if err != nil {
return err
}
user, err := dc.Repository.User().GetUserByEmail(dc.Seed.AdminEmail)
if err != nil {
if errors.Is(err, db.ErrNotFound) {
user, err = dc.Repository.User().CreateUser(&repository.CreateUserOpts{
Email: dc.Seed.AdminEmail,
Name: repository.StringPtr(dc.Seed.AdminName),
EmailVerified: repository.BoolPtr(true),
Password: *hashedPw,
})
if err != nil {
return err
}
} else {
return err
}
}
userId = user.ID
}
tenant, err := dc.Repository.Tenant().GetTenantBySlug("default")
if err != nil {
if errors.Is(err, db.ErrNotFound) {
// seed an example tenant
// initialize a tenant
tenant, err = dc.Repository.Tenant().CreateTenant(&repository.CreateTenantOpts{
Name: dc.Seed.DefaultTenantName,
Slug: dc.Seed.DefaultTenantSlug,
})
if err != nil {
return err
}
fmt.Println("created tenant", tenant.ID)
// add the user to the tenant
_, err = dc.Repository.Tenant().CreateTenantMember(tenant.ID, &repository.CreateTenantMemberOpts{
Role: "OWNER",
UserId: userId,
})
if err != nil {
return err
}
} else {
return err
}
}
if dc.Seed.IsDevelopment {
err = seedDev(dc.Repository, tenant.ID)
if err != nil {
return err
}
}
return nil
}
func seedDev(repo repository.Repository, tenantId string) error {
// seed example workflows
firstInput, _ := datautils.ToJSONType(map[string]interface{}{
"message": "Username is {{ .input.username }}",
})
secondInput, _ := datautils.ToJSONType(map[string]interface{}{
"message": "Above message is: {{ .steps.echo1.message }}",
})
thirdInput, _ := datautils.ToJSONType(map[string]interface{}{
"message": "Above message is: {{ .steps.echo1.message }}",
})
workflow, err := repo.Workflow().GetWorkflowByName(tenantId, "test-workflow")
if err != nil {
if errors.Is(err, db.ErrNotFound) {
_, err := repo.Workflow().CreateNewWorkflow(tenantId, &repository.CreateWorkflowVersionOpts{
Name: "test-workflow",
Description: repository.StringPtr("This is a test workflow."),
Version: "v0.1.0",
EventTriggers: []string{
"user:create",
},
Tags: []repository.CreateWorkflowTagOpts{
{
Name: "Preview",
},
},
Jobs: []repository.CreateWorkflowJobOpts{
{
Name: "job-name",
Steps: []repository.CreateWorkflowStepOpts{
{
ReadableId: "echo1",
Action: "echo:echo",
Inputs: firstInput,
},
{
ReadableId: "echo2",
Action: "echo:echo",
Inputs: secondInput,
},
{
ReadableId: "echo3",
Action: "echo:echo",
Inputs: thirdInput,
},
},
},
},
})
if err != nil {
return err
}
fmt.Println("created workflow", workflow.ID, workflow.Name)
}
return err
}
return nil
}

View File

@@ -0,0 +1,9 @@
package main
import (
"github.com/hatchet-dev/hatchet/cmd/hatchet-admin/cli"
)
func main() {
cli.Execute()
}

View File

@@ -11,6 +11,7 @@ import (
)
var printVersion bool
var configDirectory string
// rootCmd represents the base command when called without any subcommands
var rootCmd = &cobra.Command{
@@ -22,7 +23,7 @@ var rootCmd = &cobra.Command{
os.Exit(0)
}
cf := &loader.ConfigLoader{}
cf := loader.NewConfigLoader(configDirectory)
interruptChan := cmdutils.InterruptChan()
startServerOrDie(cf, interruptChan)
@@ -40,16 +41,21 @@ func main() {
"print version and exit.",
)
rootCmd.PersistentFlags().StringVar(
&configDirectory,
"config",
"",
"The path the config folder.",
)
if err := rootCmd.Execute(); err != nil {
fmt.Println(err)
os.Exit(1)
}
}
func startServerOrDie(configLoader *loader.ConfigLoader, interruptCh <-chan interface{}) {
func startServerOrDie(cf *loader.ConfigLoader, interruptCh <-chan interface{}) {
// init the repository
cf := &loader.ConfigLoader{}
sc, err := cf.LoadServerConfig()
if err != nil {

View File

@@ -18,6 +18,7 @@ import (
)
var printVersion bool
var configDirectory string
// rootCmd represents the base command when called without any subcommands
var rootCmd = &cobra.Command{
@@ -29,7 +30,7 @@ var rootCmd = &cobra.Command{
os.Exit(0)
}
cf := &loader.ConfigLoader{}
cf := loader.NewConfigLoader(configDirectory)
interruptChan := cmdutils.InterruptChan()
startEngineOrDie(cf, interruptChan)
@@ -47,6 +48,13 @@ func main() {
"print version and exit.",
)
rootCmd.PersistentFlags().StringVar(
&configDirectory,
"config",
"",
"The path the config folder.",
)
if err := rootCmd.Execute(); err != nil {
fmt.Println(err)
os.Exit(1)

View File

@@ -1,159 +0,0 @@
package main
import (
"errors"
"fmt"
"github.com/hatchet-dev/hatchet/internal/config/loader"
"github.com/hatchet-dev/hatchet/internal/datautils"
"github.com/hatchet-dev/hatchet/internal/repository"
"github.com/hatchet-dev/hatchet/internal/repository/prisma/db"
)
func main() {
// init the repository
cf := &loader.ConfigLoader{}
// load the config
dc, err := cf.LoadDatabaseConfig()
if err != nil {
panic(err)
}
// seed an example user
hashedPw, err := repository.HashPassword("Admin123!!")
if err != nil {
panic(err)
}
user, err := dc.Repository.User().GetUserByEmail("admin@example.com")
if err != nil {
if errors.Is(err, db.ErrNotFound) {
user, err = dc.Repository.User().CreateUser(&repository.CreateUserOpts{
Email: "admin@example.com",
Name: repository.StringPtr("Admin"),
EmailVerified: repository.BoolPtr(true),
Password: *hashedPw,
})
if err != nil {
panic(err)
}
} else {
panic(err)
}
}
tenant, err := dc.Repository.Tenant().GetTenantBySlug("default")
if err != nil {
if errors.Is(err, db.ErrNotFound) {
// seed an example tenant
// initialize a tenant
tenant, err = dc.Repository.Tenant().CreateTenant(&repository.CreateTenantOpts{
Name: "Default",
Slug: "default",
})
if err != nil {
panic(err)
}
fmt.Println("created tenant", tenant.ID)
// add the user to the tenant
_, err = dc.Repository.Tenant().CreateTenantMember(tenant.ID, &repository.CreateTenantMemberOpts{
Role: "OWNER",
UserId: user.ID,
})
if err != nil {
panic(err)
}
} else {
panic(err)
}
}
// seed example workflows
firstInput, _ := datautils.ToJSONType(map[string]interface{}{
"message": "Username is {{ .input.username }}",
})
secondInput, _ := datautils.ToJSONType(map[string]interface{}{
"message": "Above message is: {{ .steps.echo1.message }}",
})
thirdInput, _ := datautils.ToJSONType(map[string]interface{}{
"message": "Above message is: {{ .steps.echo1.message }}",
})
_, err = dc.Repository.Workflow().CreateNewWorkflow(tenant.ID, &repository.CreateWorkflowVersionOpts{
Name: "test-workflow",
Description: repository.StringPtr("This is a test workflow."),
Version: "v0.1.0",
EventTriggers: []string{
"user:create",
},
Tags: []repository.CreateWorkflowTagOpts{
{
Name: "Preview",
},
},
Jobs: []repository.CreateWorkflowJobOpts{
{
Name: "job-name",
Steps: []repository.CreateWorkflowStepOpts{
{
ReadableId: "echo1",
Action: "echo:echo",
Inputs: firstInput,
},
{
ReadableId: "echo2",
Action: "echo:echo",
Inputs: secondInput,
},
{
ReadableId: "echo3",
Action: "echo:echo",
Inputs: thirdInput,
},
},
},
},
})
if err != nil {
panic(err)
}
workflows, err := dc.Repository.Workflow().ListWorkflowsForEvent(tenant.ID, "user:create")
if err != nil {
panic(err)
}
for _, workflow := range workflows {
fmt.Println("created workflow", workflow.ID, workflow.Workflow().Name, workflow.Version)
}
// seed example events
generateEvents(dc.Repository, tenant.ID)
}
func generateEvents(repo repository.Repository, tenantId string) {
for i := 0; i < 600; i++ {
_, err := repo.Event().CreateEvent(&repository.CreateEventOpts{
TenantId: tenantId,
Key: fmt.Sprintf("user-%d:create", i),
})
if err != nil {
panic(err)
}
}
}

14
go.mod
View File

@@ -7,6 +7,7 @@ replace golang.org/x/exp => golang.org/x/exp v0.0.0-20230713183714-613f0c0eb8a1
require (
github.com/creasty/defaults v1.7.0
github.com/fatih/color v1.16.0
github.com/getkin/kin-openapi v0.122.0
github.com/gorilla/securecookie v1.1.2
github.com/gorilla/sessions v1.2.2
@@ -17,9 +18,10 @@ require (
github.com/labstack/echo/v4 v4.11.3
github.com/oapi-codegen/runtime v1.1.0
github.com/shopspring/decimal v1.3.1
github.com/spf13/cobra v1.8.0
github.com/spf13/viper v1.16.0
github.com/steebchen/prisma-client-go v0.27.1
github.com/takuoki/gocase v1.0.0
github.com/steebchen/prisma-client-go v0.31.3
sigs.k8s.io/yaml v1.4.0
)
require (
@@ -44,7 +46,6 @@ require (
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect
github.com/perimeterx/marshmallow v1.1.5 // indirect
github.com/rogpeppe/go-internal v1.10.0 // indirect
github.com/spf13/cobra v1.8.0 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/valyala/fasttemplate v1.2.2 // indirect
golang.org/x/time v0.3.0 // indirect
@@ -62,10 +63,9 @@ require (
github.com/gorilla/schema v1.2.1
github.com/hashicorp/errwrap v1.0.0 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/iancoleman/strcase v0.2.0
github.com/magiconair/properties v1.8.7 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.19 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mitchellh/mapstructure v1.5.0
github.com/pelletier/go-toml/v2 v2.1.0 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
@@ -83,8 +83,8 @@ require (
golang.org/x/crypto v0.14.0
golang.org/x/net v0.17.0 // indirect
golang.org/x/sync v0.4.0
golang.org/x/sys v0.13.0 // indirect
golang.org/x/text v0.13.0
golang.org/x/sys v0.14.0 // indirect
golang.org/x/text v0.13.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20230920204549-e6e6cdab5c13 // indirect
google.golang.org/grpc v1.58.2
google.golang.org/protobuf v1.31.0

27
go.sum
View File

@@ -63,6 +63,8 @@ github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1m
github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po=
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY=
github.com/frankban/quicktest v1.14.4/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
@@ -181,9 +183,6 @@ github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs
github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/iancoleman/strcase v0.0.0-20190422225806-e506e3ef7365/go.mod h1:SK73tn/9oHe+/Y0h39VT4UCxmurVJkR5NA7kMEAOgSE=
github.com/iancoleman/strcase v0.2.0 h1:05I4QRnGpI0m37iZQRuskXh+w77mr6Z41lwQzuHLwW0=
github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho=
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
@@ -231,8 +230,9 @@ github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxec
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw=
@@ -280,8 +280,8 @@ github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An
github.com/spf13/viper v1.16.0 h1:rGGH0XDZhdUOryiDWjmIvUSWpbNqisK8Wk0Vyefw8hc=
github.com/spf13/viper v1.16.0/go.mod h1:yg78JgCJcbrQOvV9YLXgkLaZqUidkY9K+Dd1FofRzQg=
github.com/spkg/bom v0.0.0-20160624110644-59b7046e48ad/go.mod h1:qLr4V1qq6nMqFKkMo8ZTx3f+BZEkzsRUY10Xsm2mwU0=
github.com/steebchen/prisma-client-go v0.27.1 h1:AIyQqsH0z65T5CCpgZzZW7ymlgRfRxtuJENiXbONLJw=
github.com/steebchen/prisma-client-go v0.27.1/go.mod h1:uLyNTrma4goWuhfbpZuxCRRennjQHJtFps0+M36Iqwc=
github.com/steebchen/prisma-client-go v0.31.3 h1:ubqSRFfPUTAHZijY/HqeTlKJWJpI3Lj4O338AqvqBeg=
github.com/steebchen/prisma-client-go v0.31.3/go.mod h1:ksKELgUZSn56rbAv1jlF8D7o8V6lis0Tc2LEgv2qNbs=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
@@ -298,8 +298,6 @@ github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcU
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
github.com/takuoki/gocase v1.0.0 h1:gPwLJTWVm2T1kUiCsKirg/faaIUGVTI0FA3SYr75a44=
github.com/takuoki/gocase v1.0.0/go.mod h1:QgOKJrbuJoDrtoKswBX1/Dw8mJrkOV9tbQZJaxaJ6zc=
github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU=
github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
@@ -354,7 +352,6 @@ golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.11.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -390,7 +387,6 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
@@ -413,7 +409,6 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.4.0 h1:zxkM55ReGkDlKSM+Fu41A+zmbZuaPVbGMzvvdUPznYQ=
golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -457,15 +452,13 @@ golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q=
golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@@ -475,7 +468,6 @@ golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
@@ -528,7 +520,6 @@ golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4f
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@@ -652,3 +643,5 @@ honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E=
sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY=

View File

@@ -12,12 +12,27 @@ type ConfigFile struct {
PostgresPassword string `mapstructure:"password" json:"password,omitempty" default:"hatchet"`
PostgresDbName string `mapstructure:"dbName" json:"dbName,omitempty" default:"hatchet"`
PostgresSSLMode string `mapstructure:"sslMode" json:"sslMode,omitempty" default:"disable"`
Seed SeedConfigFile `mapstructure:"seed" json:"seed,omitempty"`
}
type SeedConfigFile struct {
AdminEmail string `mapstructure:"adminEmail" json:"adminEmail,omitempty" default:"admin@example.com"`
AdminPassword string `mapstructure:"adminPassword" json:"adminPassword,omitempty" default:"Admin123!!"`
AdminName string `mapstructure:"adminName" json:"adminName,omitempty" default:"Admin"`
DefaultTenantName string `mapstructure:"defaultTenantName" json:"defaultTenantName,omitempty" default:"default"`
DefaultTenantSlug string `mapstructure:"defaultTenantSlug" json:"defaultTenantSlug,omitempty" default:"default"`
IsDevelopment bool `mapstructure:"isDevelopment" json:"isDevelopment,omitempty" default:"false"`
}
type Config struct {
Disconnect func() error
Repository repository.Repository
Seed SeedConfigFile
}
func BindAllEnv(v *viper.Viper) {
@@ -27,4 +42,11 @@ func BindAllEnv(v *viper.Viper) {
v.BindEnv("password", "DATABASE_POSTGRES_PASSWORD")
v.BindEnv("dbName", "DATABASE_POSTGRES_DB_NAME")
v.BindEnv("sslMode", "DATABASE_POSTGRES_SSL_MODE")
v.BindEnv("seed.adminEmail", "ADMIN_EMAIL")
v.BindEnv("seed.adminPassword", "ADMIN_PASSWORD")
v.BindEnv("seed.adminName", "ADMIN_NAME")
v.BindEnv("seed.defaultTenantName", "DEFAULT_TENANT_NAME")
v.BindEnv("seed.defaultTenantSlug", "DEFAULT_TENANT_SLUG")
v.BindEnv("seed.isDevelopment", "SEED_DEVELOPMENT")
}

View File

@@ -85,7 +85,11 @@ func LoadConfigFromViper(bindFunc func(v *viper.Viper), configFile interface{},
}
type ConfigLoader struct {
version, directory string
directory string
}
func NewConfigLoader(directory string) *ConfigLoader {
return &ConfigLoader{directory}
}
// LoadDatabaseConfig loads the database configuration
@@ -162,9 +166,12 @@ func getConfigBytes(configFilePath string) ([][]byte, error) {
func fileExists(filename string) bool {
info, err := os.Stat(filename)
if os.IsNotExist(err) {
if err != nil && os.IsNotExist(err) {
return false
} else if err != nil {
return false
}
return !info.IsDir()
}
@@ -179,10 +186,10 @@ func GetDatabaseConfigFromConfigFile(cf *database.ConfigFile) (res *database.Con
cf.PostgresSSLMode,
)
os.Setenv("DATABASE_URL", databaseUrl)
// os.Setenv("DATABASE_URL", databaseUrl)
client := db.NewClient(
db.WithDatasourceURL(databaseUrl),
// db.WithDatasourceURL(databaseUrl),
)
if err := client.Prisma.Connect(); err != nil {
@@ -198,6 +205,7 @@ func GetDatabaseConfigFromConfigFile(cf *database.ConfigFile) (res *database.Con
return &database.Config{
Disconnect: client.Prisma.Disconnect,
Repository: prisma.NewPrismaRepository(client, pool),
Seed: cf.Seed,
}, nil
}

View File

@@ -22,8 +22,6 @@ type ServerConfigFile struct {
Services []string `mapstructure:"services" json:"services,omitempty" default:"[\"ticker\", \"grpc\", \"eventscontroller\", \"jobscontroller\"]"`
Namespaces []string `mapstructure:"namespaces" json:"namespaces,omitempty" default:"[\"default\"]"`
TLS shared.TLSConfigFile `mapstructure:"tls" json:"tls,omitempty"`
}

View File

@@ -65,7 +65,7 @@ const (
StepRunStatusRUNNING StepRunStatus = "RUNNING"
StepRunStatusSUCCEEDED StepRunStatus = "SUCCEEDED"
StepRunStatusFAILED StepRunStatus = "FAILED"
StepRunStatusCANCELLED StepRunStatus = "CANCELLED"
StepRunStatusCancelled StepRunStatus = "CANCELLED"
)
func (e *StepRunStatus) Scan(src interface{}) error {

View File

@@ -79,7 +79,7 @@ func (j *stepRunRepository) ListStepRuns(tenantId string, opts *repository.ListS
params,
db.StepRun.RequeueAfter.Before(time.Now()),
db.StepRun.WorkerID.IsNull(),
db.StepRun.Status.Equals(db.StepRunStatusPENDINGASSIGNMENT),
db.StepRun.Status.Equals(db.StepRunStatusPendingAssignment),
// db.StepRun.Or(
// db.StepRun.Prev
// db.StepRun.Step.Where(
@@ -298,9 +298,9 @@ func (j *stepRunRepository) GetStepRunById(tenantId, stepRunId string) (*db.Step
func (j *stepRunRepository) CancelPendingStepRuns(tenantId, jobRunId, reason string) error {
_, err := j.client.StepRun.FindMany(
db.StepRun.JobRunID.Equals(jobRunId),
db.StepRun.Status.Equals(db.StepRunStatusPENDING),
db.StepRun.Status.Equals(db.StepRunStatusPending),
).Update(
db.StepRun.Status.Set(db.StepRunStatusCANCELLED),
db.StepRun.Status.Set(db.StepRunStatusCancelled),
db.StepRun.CancelledAt.Set(time.Now()),
db.StepRun.CancelledReason.Set(reason),
).Exec(context.Background())

View File

@@ -281,7 +281,7 @@ func (w *workerRepository) AddStepRun(tenantId, workerId, stepRunId string) erro
tx2 := w.client.StepRun.FindUnique(
db.StepRun.ID.Equals(stepRunId),
).Update(
db.StepRun.Status.Set(db.StepRunStatusASSIGNED),
db.StepRun.Status.Set(db.StepRunStatusAssigned),
).Tx()
err := w.client.Prisma.Transaction(tx1, tx2).Exec(context.Background())

View File

@@ -131,7 +131,7 @@ func (s *DispatcherImpl) Listen(request *contracts.WorkerListenRequest, stream c
defer func() {
s.workers.Delete(request.WorkerId)
inactive := db.WorkerStatusINACTIVE
inactive := db.WorkerStatusInactive
_, err := s.repo.Worker().UpdateWorker(request.TenantId, request.WorkerId, &repository.UpdateWorkerOpts{
Status: &inactive,

View File

@@ -255,7 +255,7 @@ func (ec *JobsControllerImpl) handleJobRunTimedOut(ctx context.Context, task *ta
stepRuns, err := ec.repo.StepRun().ListStepRuns(metadata.TenantId, &repository.ListStepRunsOpts{
JobRunId: &jobRun.ID,
Status: repository.StepRunStatusPtr(db.StepRunStatusRUNNING),
Status: repository.StepRunStatusPtr(db.StepRunStatusRunning),
})
if err != nil {
@@ -276,7 +276,7 @@ func (ec *JobsControllerImpl) handleJobRunTimedOut(ctx context.Context, task *ta
stepRun, err := ec.repo.StepRun().UpdateStepRun(metadata.TenantId, currStepRun.ID, &repository.UpdateStepRunOpts{
CancelledAt: &now,
CancelledReason: repository.StringPtr("JOB_RUN_TIMED_OUT"),
Status: repository.StepRunStatusPtr(db.StepRunStatusCANCELLED),
Status: repository.StepRunStatusPtr(db.StepRunStatusCancelled),
})
if err != nil {
@@ -483,7 +483,7 @@ func (ec *JobsControllerImpl) queueStepRun(ctx context.Context, tenantId, stepId
func (ec *JobsControllerImpl) scheduleStepRun(ctx context.Context, tenantId, stepId, stepRunId string) error {
// indicate that the step run is pending assignment
stepRun, err := ec.repo.StepRun().UpdateStepRun(tenantId, stepRunId, &repository.UpdateStepRunOpts{
Status: repository.StepRunStatusPtr(db.StepRunStatusPENDINGASSIGNMENT),
Status: repository.StepRunStatusPtr(db.StepRunStatusPendingAssignment),
})
if err != nil {
@@ -598,7 +598,7 @@ func (ec *JobsControllerImpl) handleStepRunStarted(ctx context.Context, task *ta
_, err = ec.repo.StepRun().UpdateStepRun(metadata.TenantId, payload.StepRunId, &repository.UpdateStepRunOpts{
StartedAt: &startedAt,
Status: repository.StepRunStatusPtr(db.StepRunStatusRUNNING),
Status: repository.StepRunStatusPtr(db.StepRunStatusRunning),
})
return err
@@ -639,7 +639,7 @@ func (ec *JobsControllerImpl) handleStepRunFinished(ctx context.Context, task *t
stepRun, err := ec.repo.StepRun().UpdateStepRun(metadata.TenantId, payload.StepRunId, &repository.UpdateStepRunOpts{
FinishedAt: &finishedAt,
Status: repository.StepRunStatusPtr(db.StepRunStatusSUCCEEDED),
Status: repository.StepRunStatusPtr(db.StepRunStatusSucceeded),
Output: &outputJSON,
})
@@ -743,7 +743,7 @@ func (ec *JobsControllerImpl) handleStepRunFailed(ctx context.Context, task *tas
stepRun, err := ec.repo.StepRun().UpdateStepRun(metadata.TenantId, payload.StepRunId, &repository.UpdateStepRunOpts{
FinishedAt: &failedAt,
Error: &payload.Error,
Status: repository.StepRunStatusPtr(db.StepRunStatusFAILED),
Status: repository.StepRunStatusPtr(db.StepRunStatusFailed),
})
if err != nil {
@@ -806,7 +806,7 @@ func (ec *JobsControllerImpl) handleStepRunTimedOut(ctx context.Context, task *t
stepRun, err := ec.repo.StepRun().UpdateStepRun(metadata.TenantId, payload.StepRunId, &repository.UpdateStepRunOpts{
CancelledAt: &now,
CancelledReason: repository.StringPtr("TIMED_OUT"),
Status: repository.StepRunStatusPtr(db.StepRunStatusCANCELLED),
Status: repository.StepRunStatusPtr(db.StepRunStatusCancelled),
})
if err != nil {
@@ -875,7 +875,7 @@ func (ec *JobsControllerImpl) handleTickerRemoved(ctx context.Context, task *tas
// get all step runs assigned to the ticker
stepRuns, err := ec.repo.StepRun().ListAllStepRuns(&repository.ListAllStepRunsOpts{
NoTickerId: repository.BoolPtr(true),
Status: repository.StepRunStatusPtr(db.StepRunStatusRUNNING),
Status: repository.StepRunStatusPtr(db.StepRunStatusRunning),
})
if err != nil {
@@ -913,7 +913,7 @@ func (ec *JobsControllerImpl) handleTickerRemoved(ctx context.Context, task *tas
// get all step runs assigned to the ticker
jobRuns, err := ec.repo.JobRun().ListAllJobRuns(&repository.ListAllJobRunsOpts{
NoTickerId: repository.BoolPtr(true),
Status: repository.JobRunStatusPtr(db.JobRunStatusRUNNING),
Status: repository.JobRunStatusPtr(db.JobRunStatusRunning),
})
if err != nil {