feat: v1 engine (#1318)

This commit is contained in:
abelanger5
2025-03-11 14:57:13 -04:00
committed by GitHub
parent b7a706a18f
commit 1f2096313d
1583 changed files with 236319 additions and 423777 deletions

View File

@@ -1,5 +1,9 @@
name: "frontend / app"
on: pull_request
on:
pull_request:
paths-ignore:
- 'sdks/**'
jobs:
lint:
runs-on: ubuntu-latest

View File

@@ -1,5 +1,9 @@
name: build
on: pull_request
on:
pull_request:
paths-ignore:
- 'sdks/**'
jobs:
frontend:
runs-on: ubuntu-latest
@@ -63,7 +67,7 @@ jobs:
- name: Clone repository
uses: actions/checkout@v4
- name: Build migrate
run: docker build -f ./build/package/migrate.dockerfile .
run: docker build -f ./build/package/servers.dockerfile . --build-arg SERVER_TARGET=migrate
migrate-arm:
runs-on: hatchet-arm64-2
@@ -71,7 +75,7 @@ jobs:
- name: Clone repository
uses: actions/checkout@v4
- name: Build migrate
run: docker build -f ./build/package/migrate.dockerfile .
run: docker build -f ./build/package/servers.dockerfile . --build-arg SERVER_TARGET=migrate
lite-arm:
runs-on: hatchet-arm64-2
@@ -92,11 +96,18 @@ jobs:
-t hatchet-admin-tmp:arm64 \
. &
DOCKER_BUILDKIT=1 docker build -f ./build/package/servers.dockerfile \
--build-arg SERVER_TARGET=migrate \
--platform linux/arm64 \
-t hatchet-migrate-tmp:arm64 \
. &
wait
DOCKER_BUILDKIT=1 docker build -f ./build/package/lite.dockerfile \
--build-arg HATCHET_LITE_IMAGE=hatchet-lite-tmp:arm64 \
--build-arg HATCHET_ADMIN_IMAGE=hatchet-admin-tmp:arm64 \
--build-arg HATCHET_MIGRATE_IMAGE=hatchet-migrate-tmp:arm64 \
--platform linux/arm64 \
.
@@ -119,11 +130,18 @@ jobs:
-t hatchet-admin-tmp:amd64 \
. &
DOCKER_BUILDKIT=1 docker build -f ./build/package/servers.dockerfile \
--build-arg SERVER_TARGET=migrate \
--platform linux/amd64 \
-t hatchet-migrate-tmp:amd64 \
. &
wait
DOCKER_BUILDKIT=1 docker build -f ./build/package/lite.dockerfile \
--build-arg HATCHET_LITE_IMAGE=hatchet-lite-tmp:amd64 \
--build-arg HATCHET_ADMIN_IMAGE=hatchet-admin-tmp:amd64 \
--build-arg HATCHET_MIGRATE_IMAGE=hatchet-migrate-tmp:amd64 \
--platform linux/amd64 \
.

View File

@@ -1,5 +1,8 @@
name: "frontend / docs"
on: pull_request
on:
pull_request:
paths-ignore:
- 'sdks/**'
jobs:
lint:
runs-on: ubuntu-latest

View File

@@ -1,5 +1,8 @@
name: lint all
on: pull_request
on:
pull_request:
paths-ignore:
- 'sdks/**'
jobs:
lint:
runs-on: ubuntu-latest

View File

@@ -251,7 +251,8 @@ jobs:
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/migrate.dockerfile \
DOCKER_BUILDKIT=1 docker build -f ./build/package/servers.dockerfile \
--build-arg SERVER_TARGET=migrate \
-t ghcr.io/hatchet-dev/hatchet/hatchet-migrate:${{steps.tag_name.outputs.tag}}-amd64 \
--platform linux/amd64 \
.
@@ -274,7 +275,8 @@ jobs:
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/migrate.dockerfile \
DOCKER_BUILDKIT=1 docker build -f ./build/package/servers.dockerfile \
--build-arg SERVER_TARGET=migrate \
-t ghcr.io/hatchet-dev/hatchet/hatchet-migrate:${{steps.tag_name.outputs.tag}}-arm64 \
--platform linux/arm64 \
.
@@ -413,6 +415,12 @@ jobs:
-t hatchet-admin-tmp:amd64 \
. &
DOCKER_BUILDKIT=1 docker build -f ./build/package/servers.dockerfile \
--build-arg SERVER_TARGET=migrate \
--platform linux/amd64 \
-t hatchet-migrate-tmp:amd64 \
. &
wait
DOCKER_BUILDKIT=1 docker build -f ./build/package/lite.dockerfile \
@@ -420,6 +428,7 @@ jobs:
--platform linux/amd64 \
--build-arg HATCHET_LITE_IMAGE=hatchet-lite-tmp:amd64 \
--build-arg HATCHET_ADMIN_IMAGE=hatchet-admin-tmp:amd64 \
--build-arg HATCHET_MIGRATE_IMAGE=hatchet-migrate-tmp:amd64 \
.
- name: Push to GHCR
run: |
@@ -456,6 +465,12 @@ jobs:
-t hatchet-admin-tmp:arm64 \
. &
DOCKER_BUILDKIT=1 docker build -f ./build/package/servers.dockerfile \
--build-arg SERVER_TARGET=migrate \
--platform linux/arm64 \
-t hatchet-migrate-tmp:arm64 \
. &
wait
DOCKER_BUILDKIT=1 docker build -f ./build/package/lite.dockerfile \
@@ -463,6 +478,7 @@ jobs:
--platform linux/arm64 \
--build-arg HATCHET_LITE_IMAGE=hatchet-lite-tmp:arm64 \
--build-arg HATCHET_ADMIN_IMAGE=hatchet-admin-tmp:arm64 \
--build-arg HATCHET_MIGRATE_IMAGE=hatchet-migrate-tmp:arm64 \
.
- name: Push to GHCR
run: |

119
.github/workflows/sdk-python.yml vendored Normal file
View File

@@ -0,0 +1,119 @@
name: python
on:
pull_request:
paths:
- 'sdks/python/**'
- '.github/**'
push:
branches:
- main
paths:
- 'sdks/python/**'
- '.github/**'
defaults:
run:
working-directory: ./sdks/python
jobs:
lint:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.11"
- name: Install Poetry
uses: snok/install-poetry@v1
with:
version: 1.5.1
virtualenvs-create: true
virtualenvs-in-project: true
- name: Install linting tools
run: poetry install --all-extras
- name: Run Black
run: poetry run black . --check --verbose --diff --color
- name: Run Isort
run: poetry run isort . --check-only --diff
- name: Run MyPy
run: poetry run mypy --config-file=pyproject.toml
- name: Run Ruff
run: poetry run ruff check .
test:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ["3.10", "3.11", "3.12", "3.13"]
steps:
- uses: actions/checkout@v4
- name: Run Hatchet Engine
run: docker compose up -d
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
- name: Display Python version
run: python -c "import sys; print(sys.version)"
- name: Install Poetry
uses: snok/install-poetry@v1
with:
version: 1.5.1
virtualenvs-create: true
virtualenvs-in-project: true
- name: Install dependencies
run: poetry install --no-interaction --all-extras
- name: Generate Env File
run: |
cat <<EOF > .env
HATCHET_CLIENT_TOKEN="$(docker compose run --no-deps setup-config /hatchet/hatchet-admin token create --config /hatchet/config --tenant-id 707d0855-80ab-4e1f-a156-f1c4546cbf52 | xargs)"
HATCHET_CLIENT_TLS_STRATEGY=none
EOF
- name: Set HATCHET_CLIENT_NAMESPACE
run: |
PYTHON_VERSION=$(python -c "import sys; print(f'py{sys.version_info.major}{sys.version_info.minor}')")
SHORT_SHA=$(git rev-parse --short HEAD)
echo "HATCHET_CLIENT_NAMESPACE=${PYTHON_VERSION}-${SHORT_SHA}" >> $GITHUB_ENV
- name: Run pytest
run: |
echo "Using HATCHET_CLIENT_NAMESPACE: $HATCHET_CLIENT_NAMESPACE"
poetry run pytest -s -vvv --maxfail=5 --timeout=180 --capture=no
publish:
runs-on: ubuntu-latest
needs: [lint, test]
if: github.ref == 'refs/heads/main'
steps:
- name: Checkout Repository
uses: actions/checkout@v4
with:
submodules: recursive
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.x"
- name: Install Poetry
run: |
pipx install poetry==1.7.1
- name: Run publish.sh script
run: |
sh publish.sh
env:
POETRY_PYPI_TOKEN_PYPI: ${{ secrets.POETRY_PYPI_TOKEN_PYPI }}

View File

@@ -6,3 +6,4 @@ jobs:
steps:
- uses: actions/checkout@v4
- uses: crate-ci/typos@master
continue-on-error: true

View File

@@ -1,5 +1,8 @@
name: test
on: pull_request
on:
pull_request:
paths-ignore:
- 'sdks/**'
jobs:
generate:
runs-on: ubuntu-latest
@@ -37,7 +40,7 @@ jobs:
- name: Generate
run: |
sh ./hack/db/atlas-apply.sh
go run ./cmd/hatchet-migrate
task pre-commit-install
task generate-all
@@ -99,7 +102,7 @@ jobs:
- name: Generate
run: |
sh ./hack/db/atlas-apply.sh
go run ./cmd/hatchet-migrate
task generate-go
task generate-certs
task generate-local-encryption-keys
@@ -173,7 +176,7 @@ jobs:
- name: Generate
run: |
sh ./hack/db/atlas-apply.sh
go run ./cmd/hatchet-migrate
task generate-go
task generate-certs
task generate-local-encryption-keys
@@ -262,7 +265,7 @@ jobs:
- name: Generate
run: |
sh ./hack/db/atlas-apply.sh
go run ./cmd/hatchet-migrate
task generate-go
task generate-certs
task generate-local-encryption-keys
@@ -339,7 +342,7 @@ jobs:
- name: Generate
run: |
sh ./hack/db/atlas-apply.sh
go run ./cmd/hatchet-migrate
task generate-go
task generate-certs
task generate-local-encryption-keys
@@ -415,7 +418,7 @@ jobs:
- name: Generate
run: |
sh ./hack/db/atlas-apply.sh
go run ./cmd/hatchet-migrate
task generate-go
task generate-certs
task generate-local-encryption-keys

View File

@@ -36,8 +36,7 @@ linters-settings:
- "-ST1005"
issues:
exclude-files:
- "pkg/repository/prisma/db/db_gen.go"
exclude-files: []
exclude:
- "by other packages, and that stutters; consider calling this"
- "var-naming:"

View File

@@ -6,9 +6,7 @@ repos:
- id: mixed-line-ending
args: ["--fix=lf"]
- id: end-of-file-fixer
exclude: prisma/migrations/.*\.sql|sql/migrations/.*\.sql
- id: trailing-whitespace
exclude: prisma/migrations/.*\.sql|sql/migrations/.*\.sql
- id: check-yaml
- repo: https://github.com/golangci/golangci-lint
rev: v1.62.0

View File

@@ -70,14 +70,13 @@ tasks:
migrate:
cmds:
- task: generate-sqlc
- task: atlas-compare-schema-to-migrations-dir
- task: atlas-apply-migrations
atlas-compare-schema-to-migrations-dir:
- task: goose-migrate
atlas-migrate:
cmds:
- sh ./hack/dev/atlas-migrate.sh {{.CLI_ARGS}}
atlas-apply-migrations:
goose-migrate:
cmds:
- DATABASE_URL='postgresql://hatchet:hatchet@127.0.0.1:5431/hatchet' sh ./hack/db/atlas-apply.sh
- sh ./hack/dev/migrate.sh
seed-dev:
cmds:
- SEED_DEVELOPMENT=true sh ./hack/dev/run-go-with-env.sh run ./cmd/hatchet-admin seed
@@ -150,7 +149,8 @@ tasks:
- sh ./generate.sh
generate-sqlc:
cmds:
- go run github.com/sqlc-dev/sqlc/cmd/sqlc@v1.24.0 generate --file pkg/repository/prisma/dbsqlc/sqlc.yaml
- go run github.com/sqlc-dev/sqlc/cmd/sqlc@v1.24.0 generate --file pkg/repository/postgres/dbsqlc/sqlc.yaml
- go run github.com/sqlc-dev/sqlc/cmd/sqlc@v1.24.0 generate --file pkg/repository/v1/sqlcv1/sqlc.yaml
lint:
cmds:
- task: lint-go
@@ -161,9 +161,6 @@ tasks:
lint-frontend:
cmds:
- cd frontend/app/ && pnpm run lint:check
kill-query-engines:
cmds:
- ps -A | grep 'prisma-query-engine-darwin-arm64' | grep -v grep | awk '{print $1}' | xargs kill -9 $1
kill-apis:
cmds:
- ps -A | grep 'cmd/hatchet-api' | grep -v grep | awk '{print $1}' | xargs kill -9 $1

View File

@@ -292,3 +292,41 @@ WebhookWorkerCreateResponse:
$ref: "./webhook_worker.yaml#/WebhookWorkerCreateResponse"
WebhookWorkerListResponse:
$ref: "./webhook_worker.yaml#/WebhookWorkerListResponse"
V1TaskSummaryList:
$ref: "./v1/task.yaml#/V1TaskSummaryList"
V1WorkflowRunDisplayNameList:
$ref: "./v1/task.yaml#/V1WorkflowRunDisplayNameList"
V1TaskSummary:
$ref: "./v1/task.yaml#/V1TaskSummary"
V1DagChildren:
$ref: "./v1/task.yaml#/V1DagChildren"
V1TaskEventList:
$ref: "./v1/task.yaml#/V1TaskEventList"
V1TaskStatus:
$ref: "./v1/task.yaml#/V1TaskStatus"
V1TaskRunMetrics:
$ref: "./v1/task.yaml#/V1TaskRunMetrics"
V1TaskPointMetric:
$ref: "./v1/task.yaml#/V1TaskPointMetric"
V1TaskPointMetrics:
$ref: "./v1/task.yaml#/V1TaskPointMetrics"
V1TaskFilter:
$ref: "./v1/task.yaml#/V1TaskFilter"
V1CancelTaskRequest:
$ref: "./v1/task.yaml#/V1CancelTaskRequest"
V1ReplayTaskRequest:
$ref: "./v1/task.yaml#/V1ReplayTaskRequest"
V1WorkflowRun:
$ref: "./v1/workflow_run.yaml#/V1WorkflowRun"
V1WorkflowRunDetails:
$ref: "./v1/workflow_run.yaml#/V1WorkflowRunDetails"
V1TaskRunStatus:
$ref: "./workflow_run.yaml#/V1TaskRunStatus"
V1TriggerWorkflowRunRequest:
$ref: "./v1/workflow_run.yaml#/V1TriggerWorkflowRunRequest"
V1LogLine:
$ref: "./v1/logs.yaml#/V1LogLine"
V1LogLineLevel:
$ref: "./v1/logs.yaml#/V1LogLineLevel"
V1LogLineList:
$ref: "./v1/logs.yaml#/V1LogLineList"

View File

@@ -14,12 +14,23 @@ Tenant:
alertMemberEmails:
type: boolean
description: Whether to alert tenant members.
version:
$ref: "#/TenantVersion"
description: The version of the tenant.
required:
- metadata
- name
- slug
- version
type: object
TenantVersion:
enum:
- "V0"
- "V1"
type: string
TenantAlertingSettings:
properties:
metadata:
@@ -90,6 +101,9 @@ UpdateTenantRequest:
description: The max frequency at which to alert.
x-oapi-codegen-extra-tags:
validate: "omitnil,duration"
version:
$ref: "#/TenantVersion"
description: The version of the tenant.
type: object
TenantResource:

View File

@@ -0,0 +1,33 @@
V1LogLine:
properties:
createdAt:
type: string
format: date-time
description: The creation date of the log line.
message:
type: string
description: The log message.
metadata:
type: object
description: The log metadata.
required:
- createdAt
- message
- metadata
V1LogLineLevel:
type: string
enum:
- DEBUG
- INFO
- WARN
- ERROR
V1LogLineList:
properties:
pagination:
$ref: "../metadata.yaml#/PaginationResponse"
rows:
items:
$ref: "#/V1LogLine"
type: array

View File

@@ -0,0 +1,321 @@
V1WorkflowType:
type: string
enum:
- DAG
- TASK
V1TaskSummary:
properties:
metadata:
$ref: ".././metadata.yaml#/APIResourceMeta"
additionalMetadata:
type: object
description: Additional metadata for the task run.
children:
type: array
items:
$ref: "#/V1TaskSummary"
description: The list of children tasks
createdAt:
type: string
format: date-time
description: The timestamp the task was created.
displayName:
type: string
description: The display name of the task run.
duration:
type: integer
description: The duration of the task run, in milliseconds.
errorMessage:
type: string
description: The error message of the task run (for the latest run)
finishedAt:
type: string
format: date-time
description: The timestamp the task run finished.
input:
type: object
description: The input of the task run.
numSpawnedChildren:
type: integer
description: The number of spawned children tasks
output:
type: object
description: The output of the task run (for the latest run)
status:
$ref: "#/V1TaskStatus"
startedAt:
type: string
format: date-time
description: The timestamp the task run started.
stepId:
type: string
description: The step ID of the task.
format: uuid
minLength: 36
maxLength: 36
taskExternalId:
type: string
description: The external ID of the task.
format: uuid
minLength: 36
maxLength: 36
taskId:
type: integer
description: The ID of the task.
taskInsertedAt:
type: string
format: date-time
description: The timestamp the task was inserted.
tenantId:
type: string
description: The ID of the tenant.
example: bb214807-246e-43a5-a25d-41761d1cff9e
minLength: 36
maxLength: 36
format: uuid
type:
$ref: "#/V1WorkflowType"
description: The type of the workflow (whether it's a DAG or a task)
workflowId:
type: string
format: uuid
workflowName:
type: string
workflowRunExternalId:
type: string
format: uuid
description: The external ID of the workflow run
workflowVersionId:
type: string
format: uuid
description: The version ID of the workflow
required:
- metadata
- createdAt
- displayName
- id
- input
- numSpawnedChildren
- output
- status
- taskExternalId
- taskId
- taskInsertedAt
- tenantId
- type
- workflowId
V1WorkflowRunDisplayName:
properties:
metadata:
$ref: ".././metadata.yaml#/APIResourceMeta"
displayName:
type: string
required:
- metadata
- displayName
V1DagChildren:
type: object
properties:
dagId:
type: string
format: uuid
children:
type: array
items:
$ref: "#/V1TaskSummary"
V1TaskSummaryList:
type: object
properties:
pagination:
$ref: ".././metadata.yaml#/PaginationResponse"
rows:
type: array
items:
$ref: "#/V1TaskSummary"
description: The list of tasks
required:
- pagination
- rows
V1WorkflowRunDisplayNameList:
type: object
properties:
pagination:
$ref: ".././metadata.yaml#/PaginationResponse"
rows:
type: array
items:
$ref: "#/V1WorkflowRunDisplayName"
description: The list of display names
required:
- pagination
- rows
V1TaskEventList:
properties:
pagination:
$ref: ".././metadata.yaml#/PaginationResponse"
rows:
items:
$ref: "#/V1TaskEvent"
type: array
V1TaskEvent:
type: object
properties:
id:
type: integer
taskId:
type: string
format: uuid
timestamp:
type: string
format: date-time
eventType:
$ref: "#/V1TaskEventType"
message:
type: string
errorMessage:
type: string
output:
type: string
workerId:
type: string
format: uuid
taskDisplayName:
type: string
required:
- id
- taskId
- timestamp
- eventType
- message
V1TaskStatus:
type: string
enum:
- QUEUED
- RUNNING
- COMPLETED
- CANCELLED
- FAILED
V1TaskEventType:
type: string
enum:
- REQUEUED_NO_WORKER
- REQUEUED_RATE_LIMIT
- SCHEDULING_TIMED_OUT
- ASSIGNED
- STARTED
- FINISHED
- FAILED
- RETRYING
- CANCELLED
- TIMED_OUT
- REASSIGNED
- SLOT_RELEASED
- TIMEOUT_REFRESHED
- RETRIED_BY_USER
- SENT_TO_WORKER
- RATE_LIMIT_ERROR
- ACKNOWLEDGED
- CREATED
- QUEUED
- SKIPPED
V1TaskRunMetrics:
type: array
items:
$ref: "#/V1TaskRunMetric"
V1TaskRunMetric:
type: object
properties:
status:
$ref: "#/V1TaskStatus"
count:
type: integer
required:
- status
- count
V1TaskPointMetric:
type: object
properties:
time:
type: string
format: date-time
SUCCEEDED:
type: integer
FAILED:
type: integer
required:
- time
- SUCCEEDED
- FAILED
V1TaskPointMetrics:
type: object
properties:
results:
type: array
items:
$ref: "#/V1TaskPointMetric"
V1TaskFilter:
type: object
properties:
since:
type: string
format: date-time
until:
type: string
format: date-time
statuses:
type: array
items:
$ref: "#/V1TaskStatus"
workflowIds:
type: array
items:
type: string
format: uuid
additionalMetadata:
type: array
items:
type: string
required:
- since
V1CancelTaskRequest:
type: object
properties:
externalIds:
type: array
description: A list of external IDs, which can refer to either task or workflow run external IDs
items:
type: string
format: uuid
minLength: 36
maxLength: 36
filter:
$ref: "#/V1TaskFilter"
V1ReplayTaskRequest:
type: object
properties:
externalIds:
type: array
description: A list of external IDs, which can refer to either task or workflow run external IDs
items:
type: string
format: uuid
minLength: 36
maxLength: 36
filter:
$ref: "#/V1TaskFilter"

View File

@@ -0,0 +1,126 @@
V1WorkflowRun:
properties:
metadata:
$ref: ".././metadata.yaml#/APIResourceMeta"
status:
$ref: "./task.yaml#/V1TaskStatus"
startedAt:
type: string
format: date-time
description: The timestamp the task run started.
finishedAt:
type: string
format: date-time
description: The timestamp the task run finished.
duration:
type: integer
description: The duration of the task run, in milliseconds.
tenantId:
type: string
description: The ID of the tenant.
example: bb214807-246e-43a5-a25d-41761d1cff9e
minLength: 36
maxLength: 36
format: uuid
additionalMetadata:
type: object
description: Additional metadata for the task run.
displayName:
type: string
description: The display name of the task run.
workflowId:
type: string
format: uuid
output:
type: object
description: The output of the task run (for the latest run)
errorMessage:
type: string
description: The error message of the task run (for the latest run)
workflowVersionId:
type: string
format: uuid
description: The ID of the workflow version.
input:
type: object
description: The input of the task run.
createdAt:
type: string
format: date-time
description: The timestamp the task run was created.
required:
- metadata
- id
- status
- tenantId
- displayName
- workflowId
- output
- input
WorkflowRunShapeItemForWorkflowRunDetails:
type: object
properties:
taskExternalId:
type: string
format: uuid
minLength: 36
maxLength: 36
stepId:
type: string
format: uuid
minLength: 36
maxLength: 36
childrenStepIds:
type: array
items:
type: string
format: uuid
minLength: 36
maxLength: 36
taskName:
type: string
required:
- taskExternalId
- stepId
- childrenStepIds
- taskName
WorkflowRunShapeForWorkflowRunDetails:
type: array
items:
$ref: "#/WorkflowRunShapeItemForWorkflowRunDetails"
V1WorkflowRunDetails:
properties:
run:
$ref: "#/V1WorkflowRun"
taskEvents:
type: array
items:
$ref: "./task.yaml#/V1TaskEvent"
description: The list of task events for the workflow run
shape:
$ref: "#/WorkflowRunShapeForWorkflowRunDetails"
tasks:
type: array
items:
$ref: "./task.yaml#/V1TaskSummary"
required:
- run
- taskEvents
- shape
- tasks
V1TriggerWorkflowRunRequest:
properties:
workflowName:
type: string
description: The name of the workflow.
input:
type: object
additionalMetadata:
type: object
required:
- workflowName
- input

View File

@@ -219,7 +219,6 @@ ScheduledWorkflows:
- triggerAt
- method
ScheduledWorkflowsMethod:
type: string
enum:
@@ -305,6 +304,20 @@ WorkflowRunsMetricsCounts:
CANCELLED:
type: integer
TaskRunMetricsCounts:
type: object
properties:
PENDING:
type: integer
RUNNING:
type: integer
SUCCEEDED:
type: integer
FAILED:
type: integer
QUEUED:
type: integer
WorkflowRunsMetrics:
type: object
properties:
@@ -335,6 +348,15 @@ JobRunStatus:
- CANCELLED
- BACKOFF
V1TaskRunStatus:
type: string
enum:
- PENDING
- RUNNING
- COMPLETED
- FAILED
- CANCELLED
WorkflowRunStatus:
type: string
enum:

View File

@@ -20,6 +20,32 @@ components:
schemas:
$ref: "./components/schemas/_index.yaml"
paths:
/api/v1/stable/tasks/{task}:
$ref: "./paths/v1/tasks/tasks.yaml#/getTask"
/api/v1/stable/tasks/{task}/task-events:
$ref: "./paths/v1/tasks/tasks.yaml#/listTaskEvents"
/api/v1/stable/tasks/{task}/logs:
$ref: "./paths/v1/tasks/tasks.yaml#/listLogs"
/api/v1/stable/tenants/{tenant}/tasks/cancel:
$ref: "./paths/v1/tasks/tasks.yaml#/cancelTasks"
/api/v1/stable/tenants/{tenant}/tasks/replay:
$ref: "./paths/v1/tasks/tasks.yaml#/replayTasks"
/api/v1/stable/dags/tasks:
$ref: "./paths/v1/tasks/tasks.yaml#/listTasksByDAGIds"
/api/v1/stable/tenants/{tenant}/workflow-runs:
$ref: "./paths/v1/workflow-runs/workflow_run.yaml#/listWorkflowRuns"
/api/v1/stable/tenants/{tenant}/workflow-runs/display-names:
$ref: "./paths/v1/workflow-runs/workflow_run.yaml#/listWorkflowRunDisplayNames"
/api/v1/stable/tenants/{tenant}/workflow-runs/trigger:
$ref: "./paths/v1/workflow-runs/workflow_run.yaml#/trigger"
/api/v1/stable/workflow-runs/{v1-workflow-run}:
$ref: "./paths/v1/workflow-runs/workflow_run.yaml#/getWorkflowRunDetails"
/api/v1/stable/workflow-runs/{v1-workflow-run}/task-events:
$ref: "./paths/v1/workflow-runs/workflow_run.yaml#/listTaskEventsForWorkflowRun"
/api/v1/stable/tenants/{tenant}/task-metrics:
$ref: "./paths/v1/tasks/tasks.yaml#/getTaskStatusMetrics"
/api/v1/stable/tenants/{tenant}/task-point-metrics:
$ref: "./paths/v1/tasks/tasks.yaml#/getTaskPointMetrics"
/api/ready:
$ref: "./paths/metadata/metadata.yaml#/readiness"
/api/live:

View File

@@ -0,0 +1,443 @@
listTasksByDAGIds:
get:
description: Lists all tasks that belong a specific list of dags
operationId: v1-dag:list:tasks
parameters:
- description: The external id of the DAG
in: query
name: dag_ids
required: true
schema:
type: array
items:
type: string
format: uuid
minLength: 36
maxLength: 36
- description: The tenant id
in: query
name: tenant
required: true
schema:
type: string
format: uuid
minLength: 36
maxLength: 36
responses:
"200":
content:
application/json:
schema:
type: array
items:
$ref: "../../../components/schemas/_index.yaml#/V1DagChildren"
description: The list of tasks
description: Successfully listed the tasks
"400":
content:
application/json:
schema:
$ref: "../../../components/schemas/_index.yaml#/APIErrors"
description: A malformed or bad request
"403":
content:
application/json:
schema:
$ref: "../../../components/schemas/_index.yaml#/APIErrors"
description: Forbidden
"501":
content:
application/json:
schema:
$ref: "../../../components/schemas/_index.yaml#/APIErrors"
description: Not implemented
summary: List tasks
tags:
- Task
getTask:
get:
x-resources: ["tenant", "task"]
description: Get a task by id
operationId: v1-task:get
parameters:
- description: The task id
in: path
name: task
required: true
schema:
type: string
format: uuid
minLength: 36
maxLength: 36
responses:
"200":
content:
application/json:
schema:
$ref: "../../../components/schemas/_index.yaml#/V1TaskSummary"
description: Successfully retrieved the task
"400":
content:
application/json:
schema:
$ref: "../../../components/schemas/_index.yaml#/APIErrors"
description: A malformed or bad request
"403":
content:
application/json:
schema:
$ref: "../../../components/schemas/_index.yaml#/APIErrors"
description: Forbidden
"404":
content:
application/json:
schema:
$ref: "../../../components/schemas/_index.yaml#/APIErrors"
description: The task was not found
"501":
content:
application/json:
schema:
$ref: "../../../components/schemas/_index.yaml#/APIErrors"
description: Not implemented
summary: Get a task
tags:
- Task
listTaskEvents:
get:
x-resources: ["tenant", "task"]
description: List events for a task
operationId: v1-task-event:list
parameters:
- description: The task id
in: path
name: task
required: true
schema:
type: string
format: uuid
minLength: 36
maxLength: 36
- description: The number to skip
in: query
name: offset
required: false
schema:
type: integer
format: int64
- description: The number to limit by
in: query
name: limit
required: false
schema:
type: integer
format: int64
responses:
"200":
content:
application/json:
schema:
$ref: "../../../components/schemas/_index.yaml#/V1TaskEventList"
description: Successfully retrieved the events
"400":
content:
application/json:
schema:
$ref: "../../../components/schemas/_index.yaml#/APIErrors"
description: A malformed or bad request
"403":
content:
application/json:
schema:
$ref: "../../../components/schemas/_index.yaml#/APIErrors"
description: Forbidden
"404":
content:
application/json:
schema:
$ref: "../../../components/schemas/_index.yaml#/APIErrors"
description: The task was not found
"501":
content:
application/json:
schema:
$ref: "../../../components/schemas/_index.yaml#/APIErrors"
description: Not implemented
summary: List events for a task
tags:
- Task
getTaskStatusMetrics:
get:
x-resources: ["tenant"]
description: Get a summary of task run metrics for a tenant
operationId: v1-task:list:status-metrics
parameters:
- description: The tenant id
in: path
name: tenant
required: true
schema:
type: string
format: uuid
minLength: 36
maxLength: 36
- description: The start time to get metrics for
in: query
name: since
required: true
schema:
type: string
format: date-time
- description: The workflow id to find runs for
in: query
name: workflow_ids
required: false
schema:
type: array
items:
type: string
format: uuid
minLength: 36
maxLength: 36
- description: The parent task's external id
in: query
name: parent_task_external_id
required: false
schema:
type: string
format: uuid
minLength: 36
maxLength: 36
responses:
"200":
content:
application/json:
schema:
$ref: "../../../components/schemas/_index.yaml#/V1TaskRunMetrics"
description: Successfully retrieved the task run metrics
"400":
content:
application/json:
schema:
$ref: "../../../components/schemas/_index.yaml#/APIErrors"
description: A malformed or bad request
"403":
content:
application/json:
schema:
$ref: "../../../components/schemas/_index.yaml#/APIErrors"
description: Forbidden
"501":
content:
application/json:
schema:
$ref: "../../../components/schemas/_index.yaml#/APIErrors"
description: Not implemented
summary: Get task metrics
tags:
- Task
getTaskPointMetrics:
get:
x-resources: ["tenant"]
description: Get a minute by minute breakdown of task metrics for a tenant
operationId: v1-task:get:point-metrics
parameters:
- description: The tenant id
in: path
name: tenant
required: true
schema:
type: string
format: uuid
minLength: 36
maxLength: 36
- description: The time after the task was created
in: query
name: createdAfter
example: "2021-01-01T00:00:00Z"
required: false
schema:
type: string
format: date-time
- description: The time before the task was completed
in: query
name: finishedBefore
example: "2021-01-01T00:00:00Z"
required: false
schema:
type: string
format: date-time
responses:
"200":
content:
application/json:
schema:
$ref: "../../../components/schemas/_index.yaml#/V1TaskPointMetrics"
description: Successfully retrieved the task point metrics
"400":
content:
application/json:
schema:
$ref: "../../../components/schemas/_index.yaml#/APIErrors"
description: A malformed or bad request
"403":
content:
application/json:
schema:
$ref: "../../../components/schemas/_index.yaml#/APIErrors"
description: Forbidden
"501":
content:
application/json:
schema:
$ref: "../../../components/schemas/_index.yaml#/APIErrors"
description: Not implemented
summary: Get task point metrics
tags:
- Task
cancelTasks:
post:
x-resources: ["tenant"]
description: Cancel tasks
operationId: v1-task:cancel
parameters:
- description: The tenant id
in: path
name: tenant
required: true
schema:
type: string
format: uuid
minLength: 36
maxLength: 36
requestBody:
content:
application/json:
schema:
$ref: "../../../components/schemas/_index.yaml#/V1CancelTaskRequest"
description: The tasks to cancel
required: true
responses:
"200":
description: Successfully cancelled the tasks
"400":
content:
application/json:
schema:
$ref: "../../../components/schemas/_index.yaml#/APIErrors"
description: A malformed or bad request
"403":
content:
application/json:
schema:
$ref: "../../../components/schemas/_index.yaml#/APIErrors"
description: Forbidden
"404":
content:
application/json:
schema:
$ref: "../../../components/schemas/_index.yaml#/APIErrors"
description: The task was not found
"501":
content:
application/json:
schema:
$ref: "../../../components/schemas/_index.yaml#/APIErrors"
description: Not implemented
summary: Cancel tasks
tags:
- Task
replayTasks:
post:
x-resources: ["tenant"]
description: Replay tasks
operationId: v1-task:replay
parameters:
- description: The tenant id
in: path
name: tenant
required: true
schema:
type: string
format: uuid
minLength: 36
maxLength: 36
requestBody:
content:
application/json:
schema:
$ref: "../../../components/schemas/_index.yaml#/V1ReplayTaskRequest"
description: The tasks to replay
required: true
responses:
"200":
description: Successfully replayed the tasks
"400":
content:
application/json:
schema:
$ref: "../../../components/schemas/_index.yaml#/APIErrors"
description: A malformed or bad request
"403":
content:
application/json:
schema:
$ref: "../../../components/schemas/_index.yaml#/APIErrors"
description: Forbidden
"404":
content:
application/json:
schema:
$ref: "../../../components/schemas/_index.yaml#/APIErrors"
description: The task was not found
"501":
content:
application/json:
schema:
$ref: "../../../components/schemas/_index.yaml#/APIErrors"
description: Not implemented
summary: Replay tasks
tags:
- Task
listLogs:
get:
x-resources: ["tenant", "task"]
description: Lists log lines for a task
operationId: v1-log-line:list
parameters:
- description: The task id
in: path
name: task
required: true
schema:
type: string
format: uuid
minLength: 36
maxLength: 36
responses:
"200":
content:
application/json:
schema:
$ref: "../../../components/schemas/_index.yaml#/V1LogLineList"
description: Successfully listed the events
"400":
content:
application/json:
schema:
$ref: "../../../components/schemas/_index.yaml#/APIErrors"
description: A malformed or bad request
"403":
content:
application/json:
schema:
$ref: "../../../components/schemas/_index.yaml#/APIErrors"
description: Forbidden
summary: List log lines
tags:
- Log

View File

@@ -0,0 +1,324 @@
listWorkflowRuns:
get:
x-resources: ["tenant"]
description: Lists workflow runs for a tenant.
operationId: v1-workflow-run:list
parameters:
- description: The tenant id
in: path
name: tenant
required: true
schema:
type: string
format: uuid
minLength: 36
maxLength: 36
- description: The number to skip
in: query
name: offset
required: false
schema:
type: integer
format: int64
- description: The number to limit by
in: query
name: limit
required: false
schema:
type: integer
format: int64
- description: A list of statuses to filter by
in: query
name: statuses
required: false
schema:
type: array
items:
$ref: "../../../components/schemas/_index.yaml#/V1TaskStatus"
- description: The earliest date to filter by
in: query
name: since
required: true
schema:
type: string
format: date-time
- description: The latest date to filter by
in: query
name: until
required: false
schema:
type: string
format: date-time
- description: Additional metadata k-v pairs to filter by
in: query
name: additional_metadata
required: false
schema:
type: array
items:
type: string
- description: The workflow ids to find runs for
in: query
name: workflow_ids
required: false
schema:
type: array
items:
type: string
format: uuid
minLength: 36
maxLength: 36
- description: The worker id to filter by
in: query
name: worker_id
required: false
schema:
type: string
format: uuid
minLength: 36
maxLength: 36
- description: Whether to include DAGs or only to include tasks
in: query
name: only_tasks
required: true
schema:
type: boolean
- description: The parent task external id to filter by
in: query
name: parent_task_external_id
required: false
schema:
type: string
format: uuid
minLength: 36
maxLength: 36
responses:
"200":
content:
application/json:
schema:
$ref: "../../../components/schemas/_index.yaml#/V1TaskSummaryList"
description: Successfully listed the tasks
"400":
content:
application/json:
schema:
$ref: "../../../components/schemas/_index.yaml#/APIErrors"
description: A malformed or bad request
"403":
content:
application/json:
schema:
$ref: "../../../components/schemas/_index.yaml#/APIErrors"
description: Forbidden
"501":
content:
application/json:
schema:
$ref: "../../../components/schemas/_index.yaml#/APIErrors"
description: Not implemented
summary: List workflow runs
tags:
- Workflow Runs
listWorkflowRunDisplayNames:
get:
x-resources: ["tenant"]
description: Lists displayable names of workflow runs for a tenant
operationId: v1-workflow-run:display-names:list
parameters:
- description: The tenant id
in: path
name: tenant
required: true
schema:
type: string
format: uuid
minLength: 36
maxLength: 36
- description: The external ids of the workflow runs to get display names for
in: query
name: external_ids
required: true
schema:
type: array
items:
type: string
format: uuid
minLength: 36
maxLength: 36
responses:
"200":
content:
application/json:
schema:
$ref: "../../../components/schemas/_index.yaml#/V1WorkflowRunDisplayNameList"
description: Successfully listed the tasks
"400":
content:
application/json:
schema:
$ref: "../../../components/schemas/_index.yaml#/APIErrors"
description: A malformed or bad request
"403":
content:
application/json:
schema:
$ref: "../../../components/schemas/_index.yaml#/APIErrors"
description: Forbidden
"501":
content:
application/json:
schema:
$ref: "../../../components/schemas/_index.yaml#/APIErrors"
description: Not implemented
summary: List workflow runs
tags:
- Workflow Runs
listTaskEventsForWorkflowRun:
get:
x-resources: ["tenant", "v1-workflow-run"]
description: List all tasks for a workflow run
operationId: v1-workflow-run:task-events:list
parameters:
- description: The number to skip
in: query
name: offset
required: false
schema:
type: integer
format: int64
- description: The number to limit by
in: query
name: limit
required: false
schema:
type: integer
format: int64
- description: The workflow run id to find runs for
in: path
name: v1-workflow-run
required: true
schema:
type: string
format: uuid
minLength: 36
maxLength: 36
responses:
"200":
content:
application/json:
schema:
$ref: "../../../components/schemas/_index.yaml#/V1TaskEventList"
description: Successfully listed the tasks
"400":
content:
application/json:
schema:
$ref: "../../../components/schemas/_index.yaml#/APIErrors"
description: A malformed or bad request
"403":
content:
application/json:
schema:
$ref: "../../../components/schemas/_index.yaml#/APIErrors"
description: Forbidden
"501":
content:
application/json:
schema:
$ref: "../../../components/schemas/_index.yaml#/APIErrors"
description: Not implemented
summary: List tasks
tags:
- Workflow Runs
getWorkflowRunDetails:
get:
x-resources: ["tenant", "v1-workflow-run"]
description: Get a workflow run and its metadata to display on the "detail" page
operationId: v1-workflow-run:get
parameters:
- description: The workflow run id to get
in: path
name: v1-workflow-run
required: true
schema:
type: string
format: uuid
minLength: 36
maxLength: 36
responses:
"200":
content:
application/json:
schema:
$ref: "../../../components/schemas/_index.yaml#/V1WorkflowRunDetails"
description: Successfully listed the tasks
"400":
content:
application/json:
schema:
$ref: "../../../components/schemas/_index.yaml#/APIErrors"
description: A malformed or bad request
"403":
content:
application/json:
schema:
$ref: "../../../components/schemas/_index.yaml#/APIErrors"
description: Forbidden
"501":
content:
application/json:
schema:
$ref: "../../../components/schemas/_index.yaml#/APIErrors"
description: Not implemented
summary: List tasks
tags:
- Workflow Runs
trigger:
post:
x-resources: ["tenant"]
description: Trigger a new workflow run
operationId: v1-workflow-run:create
parameters:
- description: The tenant id
in: path
name: tenant
required: true
schema:
type: string
format: uuid
minLength: 36
maxLength: 36
requestBody:
content:
application/json:
schema:
$ref: "../../../components/schemas/_index.yaml#/V1TriggerWorkflowRunRequest"
description: The workflow run to create
required: true
responses:
"200":
content:
application/json:
schema:
$ref: "../../../components/schemas/_index.yaml#/V1WorkflowRunDetails"
description: Successfully created the workflow run
"400":
content:
application/json:
schema:
$ref: "../../../components/schemas/_index.yaml#/APIErrors"
description: A malformed or bad request
"403":
content:
application/json:
schema:
$ref: "../../../components/schemas/_index.yaml#/APIErrors"
description: Forbidden
summary: Create workflow run
tags:
- Workflow Runs

View File

@@ -0,0 +1,48 @@
syntax = "proto3";
option go_package = "github.com/hatchet-dev/hatchet/internal/services/admin/v1/contracts";
import "google/protobuf/timestamp.proto";
// AdminService represents a set of RPCs for admin management of tasks, workflows, etc.
service AdminService {
rpc CancelTasks(CancelTasksRequest) returns (CancelTasksResponse);
rpc ReplayTasks(ReplayTasksRequest) returns (ReplayTasksResponse);
rpc TriggerWorkflowRun(TriggerWorkflowRunRequest) returns (TriggerWorkflowRunResponse);
}
message CancelTasksRequest {
repeated string externalIds = 1; // a list of external UUIDs
optional TasksFilter filter = 2;
}
message ReplayTasksRequest {
repeated string externalIds = 1; // a list of external UUIDs
optional TasksFilter filter = 2;
}
message TasksFilter {
repeated string statuses = 1;
google.protobuf.Timestamp since = 2;
optional google.protobuf.Timestamp until = 3;
repeated string workflow_ids = 4;
repeated string additional_metadata = 5;
}
message CancelTasksResponse {
repeated string cancelled_tasks = 1;
}
message ReplayTasksResponse {
repeated string replayed_tasks = 1;
}
message TriggerWorkflowRunRequest {
string workflow_name = 1;
bytes input = 2;
bytes additional_metadata = 3;
}
message TriggerWorkflowRunResponse {
string external_id = 1;
}

View File

@@ -6,13 +6,15 @@ import (
"net/http"
"strings"
"github.com/jackc/pgx/v5"
"github.com/labstack/echo/v4"
"github.com/rs/zerolog"
"github.com/hatchet-dev/hatchet/api/v1/server/middleware"
"github.com/hatchet-dev/hatchet/api/v1/server/middleware/redirect"
"github.com/hatchet-dev/hatchet/pkg/config/server"
"github.com/hatchet-dev/hatchet/pkg/repository/prisma/db"
"github.com/hatchet-dev/hatchet/pkg/repository/postgres/dbsqlc"
"github.com/hatchet-dev/hatchet/pkg/repository/postgres/sqlchelpers"
)
type AuthN struct {
@@ -144,11 +146,11 @@ func (a *AuthN) handleCookieAuth(c echo.Context) error {
return forbidden
}
user, err := a.config.APIRepository.User().GetUserByID(userID)
user, err := a.config.APIRepository.User().GetUserByID(c.Request().Context(), userID)
if err != nil {
a.l.Debug().Err(err).Msg("error getting user by id")
if errors.Is(err, db.ErrNotFound) {
if errors.Is(err, pgx.ErrNoRows) {
return forbidden
}
@@ -167,7 +169,7 @@ func (a *AuthN) handleBearerAuth(c echo.Context) error {
// a tenant id must exist in the context in order for the bearer auth to succeed, since
// these tokens are tenant-scoped
queriedTenant, ok := c.Get("tenant").(*db.TenantModel)
queriedTenant, ok := c.Get("tenant").(*dbsqlc.Tenant)
if !ok {
a.l.Debug().Msgf("tenant not found in context")
@@ -194,7 +196,7 @@ func (a *AuthN) handleBearerAuth(c echo.Context) error {
// Verify that the tenant id which exists in the context is the same as the tenant id
// in the token.
if queriedTenant.ID != tenantId {
if sqlchelpers.UUIDToStr(queriedTenant.ID) != tenantId {
a.l.Debug().Msgf("tenant id in token does not match tenant id in context")
return forbidden

View File

@@ -8,7 +8,8 @@ import (
"github.com/hatchet-dev/hatchet/pkg/config/server"
"github.com/hatchet-dev/hatchet/pkg/random"
"github.com/hatchet-dev/hatchet/pkg/repository/prisma/db"
"github.com/hatchet-dev/hatchet/pkg/repository/postgres/dbsqlc"
"github.com/hatchet-dev/hatchet/pkg/repository/postgres/sqlchelpers"
)
type SessionHelpers struct {
@@ -21,7 +22,7 @@ func NewSessionHelpers(config *server.ServerConfig) *SessionHelpers {
}
}
func (s *SessionHelpers) SaveAuthenticated(c echo.Context, user *db.UserModel) error {
func (s *SessionHelpers) SaveAuthenticated(c echo.Context, user *dbsqlc.User) error {
session, err := s.config.SessionStore.Get(c.Request(), s.config.SessionStore.GetName())
if err != nil {
@@ -29,7 +30,7 @@ func (s *SessionHelpers) SaveAuthenticated(c echo.Context, user *db.UserModel) e
}
session.Values["authenticated"] = true
session.Values["user_id"] = user.ID
session.Values["user_id"] = sqlchelpers.UUIDToStr(user.ID)
return session.Save(c.Request(), c.Response())
}

View File

@@ -9,7 +9,8 @@ import (
"github.com/hatchet-dev/hatchet/api/v1/server/middleware"
"github.com/hatchet-dev/hatchet/pkg/config/server"
"github.com/hatchet-dev/hatchet/pkg/repository/prisma/db"
"github.com/hatchet-dev/hatchet/pkg/repository/postgres/dbsqlc"
"github.com/hatchet-dev/hatchet/pkg/repository/postgres/sqlchelpers"
)
type AuthZ struct {
@@ -64,8 +65,8 @@ func (a *AuthZ) handleCookieAuth(c echo.Context, r *middleware.RouteInfo) error
}
// if tenant is set in the context, verify that the user is a member of the tenant
if tenant, ok := c.Get("tenant").(*db.TenantModel); ok {
user, ok := c.Get("user").(*db.UserModel)
if tenant, ok := c.Get("tenant").(*dbsqlc.Tenant); ok {
user, ok := c.Get("user").(*dbsqlc.User)
if !ok {
a.l.Debug().Msgf("user not found in context")
@@ -74,7 +75,7 @@ func (a *AuthZ) handleCookieAuth(c echo.Context, r *middleware.RouteInfo) error
}
// check if the user is a member of the tenant
tenantMember, err := a.config.APIRepository.Tenant().GetTenantMemberByUserID(tenant.ID, user.ID)
tenantMember, err := a.config.APIRepository.Tenant().GetTenantMemberByUserID(c.Request().Context(), sqlchelpers.UUIDToStr(tenant.ID), sqlchelpers.UUIDToStr(user.ID))
if err != nil {
a.l.Debug().Err(err).Msgf("error getting tenant member")
@@ -125,7 +126,7 @@ var permittedWithUnverifiedEmail = []string{
}
func (a *AuthZ) ensureVerifiedEmail(c echo.Context, r *middleware.RouteInfo) error {
user, ok := c.Get("user").(*db.UserModel)
user, ok := c.Get("user").(*dbsqlc.User)
if !ok {
return nil
@@ -154,15 +155,15 @@ var adminAndOwnerOnly = []string{
"ApiTokenUpdateRevoke",
}
func (a *AuthZ) authorizeTenantOperations(tenant *db.TenantModel, tenantMember *db.TenantMemberModel, r *middleware.RouteInfo) error {
func (a *AuthZ) authorizeTenantOperations(tenant *dbsqlc.Tenant, tenantMember *dbsqlc.PopulateTenantMembersRow, r *middleware.RouteInfo) error {
// if the user is an owner, they can do anything
if tenantMember.Role == db.TenantMemberRoleOwner {
if tenantMember.Role == dbsqlc.TenantMemberRoleOWNER {
return nil
}
// if the user is an admin, they can do anything at the moment. Some downstream handlers will case on
// admin roles, for example admins cannot mark users as owners.
if tenantMember.Role == db.TenantMemberRoleAdmin {
if tenantMember.Role == dbsqlc.TenantMemberRoleADMIN {
return nil
}

View File

@@ -7,11 +7,13 @@ import (
"github.com/hatchet-dev/hatchet/api/v1/server/oas/apierrors"
"github.com/hatchet-dev/hatchet/api/v1/server/oas/gen"
"github.com/hatchet-dev/hatchet/pkg/repository/prisma/db"
"github.com/hatchet-dev/hatchet/pkg/repository/postgres/dbsqlc"
"github.com/hatchet-dev/hatchet/pkg/repository/postgres/sqlchelpers"
)
func (a *APITokenService) ApiTokenCreate(ctx echo.Context, request gen.ApiTokenCreateRequestObject) (gen.ApiTokenCreateResponseObject, error) {
tenant := ctx.Get("tenant").(*db.TenantModel)
tenant := ctx.Get("tenant").(*dbsqlc.Tenant)
tenantId := sqlchelpers.UUIDToStr(tenant.ID)
// validate the request
if apiErrors, err := a.config.Validator.ValidateAPI(request.Body); err != nil {
@@ -34,7 +36,7 @@ func (a *APITokenService) ApiTokenCreate(ctx echo.Context, request gen.ApiTokenC
expiresAt = &e
}
token, err := a.config.Auth.JWTManager.GenerateTenantToken(ctx.Request().Context(), tenant.ID, request.Body.Name, false, expiresAt)
token, err := a.config.Auth.JWTManager.GenerateTenantToken(ctx.Request().Context(), tenantId, request.Body.Name, false, expiresAt)
if err != nil {
return nil, err

View File

@@ -5,13 +5,15 @@ import (
"github.com/hatchet-dev/hatchet/api/v1/server/oas/gen"
"github.com/hatchet-dev/hatchet/api/v1/server/oas/transformers"
"github.com/hatchet-dev/hatchet/pkg/repository/prisma/db"
"github.com/hatchet-dev/hatchet/pkg/repository/postgres/dbsqlc"
"github.com/hatchet-dev/hatchet/pkg/repository/postgres/sqlchelpers"
)
func (a *APITokenService) ApiTokenList(ctx echo.Context, request gen.ApiTokenListRequestObject) (gen.ApiTokenListResponseObject, error) {
tenant := ctx.Get("tenant").(*db.TenantModel)
tenant := ctx.Get("tenant").(*dbsqlc.Tenant)
tenantId := sqlchelpers.UUIDToStr(tenant.ID)
tokens, err := a.config.APIRepository.APIToken().ListAPITokensByTenant(tenant.ID)
tokens, err := a.config.APIRepository.APIToken().ListAPITokensByTenant(ctx.Request().Context(), tenantId)
if err != nil {
return nil, err
@@ -20,7 +22,7 @@ func (a *APITokenService) ApiTokenList(ctx echo.Context, request gen.ApiTokenLis
rows := make([]gen.APIToken, len(tokens))
for i := range tokens {
rows[i] = *transformers.ToAPIToken(&tokens[i])
rows[i] = *transformers.ToAPIToken(tokens[i])
}
return gen.ApiTokenList200JSONResponse(

View File

@@ -5,11 +5,12 @@ import (
"github.com/hatchet-dev/hatchet/api/v1/server/oas/apierrors"
"github.com/hatchet-dev/hatchet/api/v1/server/oas/gen"
"github.com/hatchet-dev/hatchet/pkg/repository/prisma/db"
"github.com/hatchet-dev/hatchet/pkg/repository/postgres/dbsqlc"
"github.com/hatchet-dev/hatchet/pkg/repository/postgres/sqlchelpers"
)
func (a *APITokenService) ApiTokenUpdateRevoke(ctx echo.Context, request gen.ApiTokenUpdateRevokeRequestObject) (gen.ApiTokenUpdateRevokeResponseObject, error) {
apiToken := ctx.Get("api-token").(*db.APITokenModel)
apiToken := ctx.Get("api-token").(*dbsqlc.APIToken)
if apiToken.Internal {
return gen.ApiTokenUpdateRevoke403JSONResponse(
@@ -17,7 +18,7 @@ func (a *APITokenService) ApiTokenUpdateRevoke(ctx echo.Context, request gen.Api
), nil
}
err := a.config.APIRepository.APIToken().RevokeAPIToken(apiToken.ID)
err := a.config.APIRepository.APIToken().RevokeAPIToken(ctx.Request().Context(), sqlchelpers.UUIDToStr(apiToken.ID))
if err != nil {
return nil, err

View File

@@ -10,11 +10,13 @@ import (
"github.com/hatchet-dev/hatchet/api/v1/server/oas/transformers"
"github.com/hatchet-dev/hatchet/pkg/repository"
"github.com/hatchet-dev/hatchet/pkg/repository/metered"
"github.com/hatchet-dev/hatchet/pkg/repository/prisma/db"
"github.com/hatchet-dev/hatchet/pkg/repository/postgres/dbsqlc"
"github.com/hatchet-dev/hatchet/pkg/repository/postgres/sqlchelpers"
)
func (t *EventService) EventCreateBulk(ctx echo.Context, request gen.EventCreateBulkRequestObject) (gen.EventCreateBulkResponseObject, error) {
tenant := ctx.Get("tenant").(*db.TenantModel)
tenant := ctx.Get("tenant").(*dbsqlc.Tenant)
tenantId := sqlchelpers.UUIDToStr(tenant.ID)
eventOpts := make([]*repository.CreateEventOpts, len(request.Body.Events))
@@ -36,13 +38,13 @@ func (t *EventService) EventCreateBulk(ctx echo.Context, request gen.EventCreate
}
eventOpts[i] = &repository.CreateEventOpts{
TenantId: tenant.ID,
TenantId: tenantId,
Key: event.Key,
Data: dataBytes,
AdditionalMetadata: additionalMetadata,
}
}
events, err := t.config.Ingestor.BulkIngestEvent(ctx.Request().Context(), tenant.ID, eventOpts)
events, err := t.config.Ingestor.BulkIngestEvent(ctx.Request().Context(), tenant, eventOpts)
if err != nil {

View File

@@ -12,12 +12,13 @@ import (
"github.com/hatchet-dev/hatchet/internal/msgqueue"
"github.com/hatchet-dev/hatchet/internal/services/shared/tasktypes"
"github.com/hatchet-dev/hatchet/pkg/repository"
"github.com/hatchet-dev/hatchet/pkg/repository/prisma/db"
"github.com/hatchet-dev/hatchet/pkg/repository/prisma/sqlchelpers"
"github.com/hatchet-dev/hatchet/pkg/repository/postgres/dbsqlc"
"github.com/hatchet-dev/hatchet/pkg/repository/postgres/sqlchelpers"
)
func (t *EventService) EventUpdateCancel(ctx echo.Context, request gen.EventUpdateCancelRequestObject) (gen.EventUpdateCancelResponseObject, error) {
tenant := ctx.Get("tenant").(*db.TenantModel)
tenant := ctx.Get("tenant").(*dbsqlc.Tenant)
tenantId := sqlchelpers.UUIDToStr(tenant.ID)
eventIds := make([]string, len(request.Body.EventIds))
@@ -30,7 +31,7 @@ func (t *EventService) EventUpdateCancel(ctx echo.Context, request gen.EventUpda
for i := range eventIds {
eventId := eventIds[i]
runs, err := t.config.EngineRepository.WorkflowRun().ListWorkflowRuns(ctx.Request().Context(), tenant.ID, &repository.ListWorkflowRunsOpts{
runs, err := t.config.EngineRepository.WorkflowRun().ListWorkflowRuns(ctx.Request().Context(), tenantId, &repository.ListWorkflowRunsOpts{
EventId: &eventId,
})
@@ -56,7 +57,7 @@ func (t *EventService) EventUpdateCancel(ctx echo.Context, request gen.EventUpda
defer wg.Done()
// Lookup step runs for the workflow run
jobRun, err := t.config.EngineRepository.JobRun().ListJobRunsForWorkflowRun(ctx.Request().Context(), tenant.ID, runId)
jobRun, err := t.config.EngineRepository.JobRun().ListJobRunsForWorkflowRun(ctx.Request().Context(), tenantId, runId)
if err != nil {
returnErr = multierror.Append(err, fmt.Errorf("failed to list job runs for workflow run %s", runId))
return
@@ -70,7 +71,7 @@ func (t *EventService) EventUpdateCancel(ctx echo.Context, request gen.EventUpda
err = t.config.MessageQueue.AddMessage(
ctx.Request().Context(),
msgqueue.JOB_PROCESSING_QUEUE,
tasktypes.JobRunCancelledToTask(tenant.ID, jobRunId, &reason),
tasktypes.JobRunCancelledToTask(tenantId, jobRunId, &reason),
)
if err != nil {
returnErr = multierror.Append(err, fmt.Errorf("failed to send cancel task for job run %s", jobRunId))

View File

@@ -9,12 +9,12 @@ import (
"github.com/hatchet-dev/hatchet/api/v1/server/oas/gen"
"github.com/hatchet-dev/hatchet/api/v1/server/oas/transformers"
"github.com/hatchet-dev/hatchet/pkg/repository/metered"
"github.com/hatchet-dev/hatchet/pkg/repository/prisma/db"
"github.com/hatchet-dev/hatchet/pkg/repository/prisma/sqlchelpers"
"github.com/hatchet-dev/hatchet/pkg/repository/postgres/dbsqlc"
"github.com/hatchet-dev/hatchet/pkg/repository/postgres/sqlchelpers"
)
func (t *EventService) EventCreate(ctx echo.Context, request gen.EventCreateRequestObject) (gen.EventCreateResponseObject, error) {
tenant := ctx.Get("tenant").(*db.TenantModel)
tenant := ctx.Get("tenant").(*dbsqlc.Tenant)
// marshal the data object to bytes
dataBytes, err := json.Marshal(request.Body.Data)
@@ -33,7 +33,7 @@ func (t *EventService) EventCreate(ctx echo.Context, request gen.EventCreateRequ
}
}
newEvent, err := t.config.Ingestor.IngestEvent(ctx.Request().Context(), tenant.ID, request.Body.Key, dataBytes, additionalMetadata)
newEvent, err := t.config.Ingestor.IngestEvent(ctx.Request().Context(), tenant, request.Body.Key, dataBytes, additionalMetadata)
if err != nil {
if err == metered.ErrResourceExhausted {
@@ -45,13 +45,13 @@ func (t *EventService) EventCreate(ctx echo.Context, request gen.EventCreateRequ
return nil, err
}
dbNewEvent, err := t.config.APIRepository.Event().GetEventById(sqlchelpers.UUIDToStr(newEvent.ID))
dbNewEvent, err := t.config.APIRepository.Event().GetEventById(ctx.Request().Context(), sqlchelpers.UUIDToStr(newEvent.ID))
if err != nil {
return nil, err
}
return gen.EventCreate200JSONResponse(
*transformers.ToEvent(dbNewEvent),
transformers.ToEvent(dbNewEvent),
), nil
}

View File

@@ -5,13 +5,13 @@ import (
"github.com/hatchet-dev/hatchet/api/v1/server/oas/gen"
"github.com/hatchet-dev/hatchet/api/v1/server/oas/transformers"
"github.com/hatchet-dev/hatchet/pkg/repository/prisma/db"
"github.com/hatchet-dev/hatchet/pkg/repository/postgres/dbsqlc"
)
func (t *EventService) EventGet(ctx echo.Context, request gen.EventGetRequestObject) (gen.EventGetResponseObject, error) {
event := ctx.Get("event").(*db.EventModel)
event := ctx.Get("event").(*dbsqlc.Event)
return gen.EventGet200JSONResponse(
*transformers.ToEvent(event),
transformers.ToEvent(event),
), nil
}

View File

@@ -1,21 +1,19 @@
package events
import (
"encoding/json"
"github.com/labstack/echo/v4"
"github.com/hatchet-dev/hatchet/api/v1/server/oas/gen"
"github.com/hatchet-dev/hatchet/pkg/repository/prisma/db"
"github.com/hatchet-dev/hatchet/pkg/repository/postgres/dbsqlc"
)
func (t *EventService) EventDataGet(ctx echo.Context, request gen.EventDataGetRequestObject) (gen.EventDataGetResponseObject, error) {
event := ctx.Get("event").(*db.EventModel)
event := ctx.Get("event").(*dbsqlc.Event)
var dataStr string
if dataType, ok := event.Data(); ok {
dataStr = string(json.RawMessage(dataType))
if len(event.Data) > 0 {
dataStr = string(event.Data)
}
return gen.EventDataGet200JSONResponse(

View File

@@ -14,11 +14,13 @@ import (
"github.com/hatchet-dev/hatchet/api/v1/server/oas/gen"
"github.com/hatchet-dev/hatchet/api/v1/server/oas/transformers"
"github.com/hatchet-dev/hatchet/pkg/repository"
"github.com/hatchet-dev/hatchet/pkg/repository/prisma/db"
"github.com/hatchet-dev/hatchet/pkg/repository/postgres/dbsqlc"
"github.com/hatchet-dev/hatchet/pkg/repository/postgres/sqlchelpers"
)
func (t *EventService) EventList(ctx echo.Context, request gen.EventListRequestObject) (gen.EventListResponseObject, error) {
tenant := ctx.Get("tenant").(*db.TenantModel)
tenant := ctx.Get("tenant").(*dbsqlc.Tenant)
tenantId := sqlchelpers.UUIDToStr(tenant.ID)
limit := 50
offset := 0
@@ -59,10 +61,10 @@ func (t *EventService) EventList(ctx echo.Context, request gen.EventListRequestO
}
if request.Params.Statuses != nil {
statuses := make([]db.WorkflowRunStatus, len(*request.Params.Statuses))
statuses := make([]dbsqlc.WorkflowRunStatus, len(*request.Params.Statuses))
for i, status := range *request.Params.Statuses {
statuses[i] = db.WorkflowRunStatus(status)
statuses[i] = dbsqlc.WorkflowRunStatus(status)
}
listOpts.WorkflowRunStatus = statuses
@@ -105,7 +107,7 @@ func (t *EventService) EventList(ctx echo.Context, request gen.EventListRequestO
dbCtx, cancel := context.WithTimeout(ctx.Request().Context(), 30*time.Second)
defer cancel()
listRes, err := t.config.APIRepository.Event().ListEvents(dbCtx, tenant.ID, listOpts)
listRes, err := t.config.APIRepository.Event().ListEvents(dbCtx, tenantId, listOpts)
if err != nil {
return nil, err

View File

@@ -4,13 +4,15 @@ import (
"github.com/labstack/echo/v4"
"github.com/hatchet-dev/hatchet/api/v1/server/oas/gen"
"github.com/hatchet-dev/hatchet/pkg/repository/prisma/db"
"github.com/hatchet-dev/hatchet/pkg/repository/postgres/dbsqlc"
"github.com/hatchet-dev/hatchet/pkg/repository/postgres/sqlchelpers"
)
func (t *EventService) EventKeyList(ctx echo.Context, request gen.EventKeyListRequestObject) (gen.EventKeyListResponseObject, error) {
tenant := ctx.Get("tenant").(*db.TenantModel)
tenant := ctx.Get("tenant").(*dbsqlc.Tenant)
tenantId := sqlchelpers.UUIDToStr(tenant.ID)
eventKeys, err := t.config.APIRepository.Event().ListEventKeys(tenant.ID)
eventKeys, err := t.config.APIRepository.Event().ListEventKeys(tenantId)
if err != nil {
return nil, err

View File

@@ -8,12 +8,13 @@ import (
"github.com/hatchet-dev/hatchet/api/v1/server/oas/gen"
"github.com/hatchet-dev/hatchet/api/v1/server/oas/transformers"
"github.com/hatchet-dev/hatchet/pkg/repository/metered"
"github.com/hatchet-dev/hatchet/pkg/repository/prisma/db"
"github.com/hatchet-dev/hatchet/pkg/repository/prisma/sqlchelpers"
"github.com/hatchet-dev/hatchet/pkg/repository/postgres/dbsqlc"
"github.com/hatchet-dev/hatchet/pkg/repository/postgres/sqlchelpers"
)
func (t *EventService) EventUpdateReplay(ctx echo.Context, request gen.EventUpdateReplayRequestObject) (gen.EventUpdateReplayResponseObject, error) {
tenant := ctx.Get("tenant").(*db.TenantModel)
tenant := ctx.Get("tenant").(*dbsqlc.Tenant)
tenantId := sqlchelpers.UUIDToStr(tenant.ID)
eventIds := make([]string, len(request.Body.EventIds))
@@ -21,7 +22,7 @@ func (t *EventService) EventUpdateReplay(ctx echo.Context, request gen.EventUpda
eventIds[i] = request.Body.EventIds[i].String()
}
events, err := t.config.EngineRepository.Event().ListEventsByIds(ctx.Request().Context(), tenant.ID, eventIds)
events, err := t.config.EngineRepository.Event().ListEventsByIds(ctx.Request().Context(), tenantId, eventIds)
if err != nil {
return nil, err
@@ -34,7 +35,7 @@ func (t *EventService) EventUpdateReplay(ctx echo.Context, request gen.EventUpda
for i := range events {
event := events[i]
newEvent, err := t.config.Ingestor.IngestReplayedEvent(ctx.Request().Context(), tenant.ID, event)
newEvent, err := t.config.Ingestor.IngestReplayedEvent(ctx.Request().Context(), tenant, event)
if err == metered.ErrResourceExhausted {
return gen.EventUpdateReplay429JSONResponse(
@@ -53,7 +54,7 @@ func (t *EventService) EventUpdateReplay(ctx echo.Context, request gen.EventUpda
return nil, allErrs
}
newEvents, err := t.config.APIRepository.Event().ListEventsById(tenant.ID, newEventIds)
newEvents, err := t.config.APIRepository.Event().ListEventsById(ctx.Request().Context(), tenantId, newEventIds)
if err != nil {
return nil, err
@@ -62,7 +63,7 @@ func (t *EventService) EventUpdateReplay(ctx echo.Context, request gen.EventUpda
rows := make([]gen.Event, len(newEvents))
for i := range newEvents {
rows[i] = *transformers.ToEvent(&newEvents[i])
rows[i] = transformers.ToEvent(newEvents[i])
}
return gen.EventUpdateReplay200JSONResponse(

View File

@@ -34,7 +34,7 @@ func (i *IngestorsService) SnsUpdate(ctx echo.Context, req gen.SnsUpdateRequestO
tenantId := req.Tenant.String()
// verify that the tenant and the topic ARN are set in the database
snsInt, err := i.config.APIRepository.SNS().GetSNSIntegration(tenantId, payload.TopicArn)
snsInt, err := i.config.APIRepository.SNS().GetSNSIntegration(ctx.Request().Context(), tenantId, payload.TopicArn)
if err != nil {
return nil, err
@@ -44,6 +44,12 @@ func (i *IngestorsService) SnsUpdate(ctx echo.Context, req gen.SnsUpdateRequestO
return nil, fmt.Errorf("SNS integration not found for tenant %s and topic ARN %s", tenantId, payload.TopicArn)
}
tenant, err := i.config.APIRepository.Tenant().GetTenantByID(ctx.Request().Context(), tenantId)
if err != nil {
return nil, err
}
switch payload.Type {
case "SubscriptionConfirmation":
_, err := payload.Subscribe()
@@ -58,7 +64,7 @@ func (i *IngestorsService) SnsUpdate(ctx echo.Context, req gen.SnsUpdateRequestO
return nil, err
}
default:
_, err := i.config.Ingestor.IngestEvent(ctx.Request().Context(), req.Tenant.String(), req.Event, body, nil)
_, err := i.config.Ingestor.IngestEvent(ctx.Request().Context(), tenant, req.Event, body, nil)
if err != nil {
return nil, err

View File

@@ -7,11 +7,13 @@ import (
"github.com/hatchet-dev/hatchet/api/v1/server/oas/transformers"
"github.com/hatchet-dev/hatchet/pkg/repository"
"github.com/hatchet-dev/hatchet/pkg/repository/prisma/db"
"github.com/hatchet-dev/hatchet/pkg/repository/postgres/dbsqlc"
"github.com/hatchet-dev/hatchet/pkg/repository/postgres/sqlchelpers"
)
func (i *IngestorsService) SnsCreate(ctx echo.Context, req gen.SnsCreateRequestObject) (gen.SnsCreateResponseObject, error) {
tenant := ctx.Get("tenant").(*db.TenantModel)
tenant := ctx.Get("tenant").(*dbsqlc.Tenant)
tenantId := sqlchelpers.UUIDToStr(tenant.ID)
// validate the request
if apiErrors, err := i.config.Validator.ValidateAPI(req.Body); err != nil {
@@ -25,7 +27,7 @@ func (i *IngestorsService) SnsCreate(ctx echo.Context, req gen.SnsCreateRequestO
}
// create the SNS integration
snsIntegration, err := i.config.APIRepository.SNS().CreateSNSIntegration(tenant.ID, opts)
snsIntegration, err := i.config.APIRepository.SNS().CreateSNSIntegration(ctx.Request().Context(), tenantId, opts)
if err != nil {
return nil, err

View File

@@ -5,15 +5,17 @@ import (
"github.com/hatchet-dev/hatchet/api/v1/server/oas/gen"
"github.com/hatchet-dev/hatchet/pkg/repository/prisma/db"
"github.com/hatchet-dev/hatchet/pkg/repository/postgres/dbsqlc"
"github.com/hatchet-dev/hatchet/pkg/repository/postgres/sqlchelpers"
)
func (i *IngestorsService) SnsDelete(ctx echo.Context, req gen.SnsDeleteRequestObject) (gen.SnsDeleteResponseObject, error) {
tenant := ctx.Get("tenant").(*db.TenantModel)
sns := ctx.Get("sns").(*db.SNSIntegrationModel)
tenant := ctx.Get("tenant").(*dbsqlc.Tenant)
tenantId := sqlchelpers.UUIDToStr(tenant.ID)
sns := ctx.Get("sns").(*dbsqlc.SNSIntegration)
// create the SNS integration
err := i.config.APIRepository.SNS().DeleteSNSIntegration(tenant.ID, sns.ID)
err := i.config.APIRepository.SNS().DeleteSNSIntegration(ctx.Request().Context(), tenantId, sqlchelpers.UUIDToStr(sns.ID))
if err != nil {
return nil, err

View File

@@ -5,15 +5,16 @@ import (
"github.com/hatchet-dev/hatchet/api/v1/server/oas/gen"
"github.com/hatchet-dev/hatchet/api/v1/server/oas/transformers"
"github.com/hatchet-dev/hatchet/pkg/repository/prisma/db"
"github.com/hatchet-dev/hatchet/pkg/repository/postgres/dbsqlc"
"github.com/hatchet-dev/hatchet/pkg/repository/postgres/sqlchelpers"
)
func (i *IngestorsService) SnsList(ctx echo.Context, req gen.SnsListRequestObject) (gen.SnsListResponseObject, error) {
tenant := ctx.Get("tenant").(*db.TenantModel)
tenant := ctx.Get("tenant").(*dbsqlc.Tenant)
tenantId := sqlchelpers.UUIDToStr(tenant.ID)
// create the SNS integration
snsIntegrations, err := i.config.APIRepository.SNS().ListSNSIntegrations(tenant.ID)
snsIntegrations, err := i.config.APIRepository.SNS().ListSNSIntegrations(ctx.Request().Context(), tenantId)
if err != nil {
return nil, err
@@ -24,7 +25,7 @@ func (i *IngestorsService) SnsList(ctx echo.Context, req gen.SnsListRequestObjec
serverUrl := i.config.Runtime.ServerURL
for i := range snsIntegrations {
rows[i] = *transformers.ToSNSIntegration(&snsIntegrations[i], serverUrl)
rows[i] = *transformers.ToSNSIntegration(snsIntegrations[i], serverUrl)
}
return gen.SnsList200JSONResponse(

View File

@@ -9,12 +9,13 @@ import (
"github.com/hatchet-dev/hatchet/api/v1/server/oas/gen"
"github.com/hatchet-dev/hatchet/api/v1/server/oas/transformers"
"github.com/hatchet-dev/hatchet/pkg/repository"
"github.com/hatchet-dev/hatchet/pkg/repository/prisma/db"
"github.com/hatchet-dev/hatchet/pkg/repository/prisma/sqlchelpers"
"github.com/hatchet-dev/hatchet/pkg/repository/postgres/dbsqlc"
"github.com/hatchet-dev/hatchet/pkg/repository/postgres/sqlchelpers"
)
func (t *LogService) LogLineList(ctx echo.Context, request gen.LogLineListRequestObject) (gen.LogLineListResponseObject, error) {
tenant := ctx.Get("tenant").(*db.TenantModel)
tenant := ctx.Get("tenant").(*dbsqlc.Tenant)
tenantId := sqlchelpers.UUIDToStr(tenant.ID)
stepRun := ctx.Get("step-run").(*repository.GetStepRunFull)
limit := 1000
@@ -60,7 +61,7 @@ func (t *LogService) LogLineList(ctx echo.Context, request gen.LogLineListReques
listOpts.Offset = &offset
}
listRes, err := t.config.APIRepository.Log().ListLogLines(tenant.ID, listOpts)
listRes, err := t.config.APIRepository.Log().ListLogLines(tenantId, listOpts)
if err != nil {
return nil, err

View File

@@ -16,9 +16,8 @@ import (
"github.com/hatchet-dev/hatchet/pkg/client"
clientconfig "github.com/hatchet-dev/hatchet/pkg/config/client"
"github.com/hatchet-dev/hatchet/pkg/config/shared"
"github.com/hatchet-dev/hatchet/pkg/repository/prisma/db"
"github.com/hatchet-dev/hatchet/pkg/repository/prisma/dbsqlc"
"github.com/hatchet-dev/hatchet/pkg/repository/prisma/sqlchelpers"
"github.com/hatchet-dev/hatchet/pkg/repository/postgres/dbsqlc"
"github.com/hatchet-dev/hatchet/pkg/repository/postgres/sqlchelpers"
"github.com/hatchet-dev/hatchet/pkg/worker"
)
@@ -28,9 +27,10 @@ func (m *MonitoringService) MonitoringPostRunProbe(ctx echo.Context, request gen
return gen.MonitoringPostRunProbe403JSONResponse{}, nil
}
tenant := ctx.Get("tenant").(*db.TenantModel)
tenant := ctx.Get("tenant").(*dbsqlc.Tenant)
tenantId := sqlchelpers.UUIDToStr(tenant.ID)
if !slices.Contains[[]string](m.permittedTenants, tenant.ID) {
if !slices.Contains[[]string](m.permittedTenants, tenantId) {
err := fmt.Errorf("tenant is not a monitoring tenant for this instance")
@@ -59,7 +59,7 @@ func (m *MonitoringService) MonitoringPostRunProbe(ctx echo.Context, request gen
cf := clientconfig.ClientConfigFile{
Token: token,
TenantId: tenant.ID,
TenantId: tenantId,
Namespace: randomNamespace(),
TLS: clientconfig.ClientTLSConfigFile{
Base: shared.TLSConfigFile{

View File

@@ -11,11 +11,13 @@ import (
"github.com/hatchet-dev/hatchet/api/v1/server/oas/gen"
"github.com/hatchet-dev/hatchet/api/v1/server/oas/transformers"
"github.com/hatchet-dev/hatchet/pkg/repository"
"github.com/hatchet-dev/hatchet/pkg/repository/prisma/db"
"github.com/hatchet-dev/hatchet/pkg/repository/postgres/dbsqlc"
"github.com/hatchet-dev/hatchet/pkg/repository/postgres/sqlchelpers"
)
func (t *RateLimitService) RateLimitList(ctx echo.Context, request gen.RateLimitListRequestObject) (gen.RateLimitListResponseObject, error) {
tenant := ctx.Get("tenant").(*db.TenantModel)
tenant := ctx.Get("tenant").(*dbsqlc.Tenant)
tenantId := sqlchelpers.UUIDToStr(tenant.ID)
limit := 50
offset := 0
@@ -50,7 +52,7 @@ func (t *RateLimitService) RateLimitList(ctx echo.Context, request gen.RateLimit
dbCtx, cancel := context.WithTimeout(ctx.Request().Context(), 30*time.Second)
defer cancel()
listRes, err := t.config.EngineRepository.RateLimit().ListRateLimits(dbCtx, tenant.ID, listOpts)
listRes, err := t.config.EngineRepository.RateLimit().ListRateLimits(dbCtx, tenantId, listOpts)
if err != nil {
return nil, err

View File

@@ -62,6 +62,7 @@ func (g *SlackAppService) UserUpdateSlackOauthCallback(ctx echo.Context, _ gen.U
}
_, err = g.config.APIRepository.Slack().UpsertSlackWebhook(
ctx.Request().Context(),
tenantId,
&repository.UpsertSlackWebhookOpts{
TeamId: resp.Team.ID,

View File

@@ -7,12 +7,14 @@ import (
"github.com/hatchet-dev/hatchet/api/v1/server/authn"
"github.com/hatchet-dev/hatchet/api/v1/server/middleware/redirect"
"github.com/hatchet-dev/hatchet/api/v1/server/oas/gen"
"github.com/hatchet-dev/hatchet/pkg/repository/prisma/db"
"github.com/hatchet-dev/hatchet/pkg/repository/postgres/dbsqlc"
"github.com/hatchet-dev/hatchet/pkg/repository/postgres/sqlchelpers"
)
// Note: we want all errors to redirect, otherwise the user will be greeted with raw JSON in the middle of the login flow.
func (g *SlackAppService) UserUpdateSlackOauthStart(ctx echo.Context, _ gen.UserUpdateSlackOauthStartRequestObject) (gen.UserUpdateSlackOauthStartResponseObject, error) {
tenant := ctx.Get("tenant").(*db.TenantModel)
tenant := ctx.Get("tenant").(*dbsqlc.Tenant)
tenantId := sqlchelpers.UUIDToStr(tenant.ID)
oauth, ok := g.config.AdditionalOAuthConfigs["slack"]
@@ -22,7 +24,7 @@ func (g *SlackAppService) UserUpdateSlackOauthStart(ctx echo.Context, _ gen.User
sh := authn.NewSessionHelpers(g.config)
if err := sh.SaveKV(ctx, "tenant", tenant.ID); err != nil {
if err := sh.SaveKV(ctx, "tenant", tenantId); err != nil {
return nil, redirect.GetRedirectWithError(ctx, g.config.Logger, err, "Could not get cookie. Please make sure cookies are enabled.")
}

View File

@@ -5,14 +5,16 @@ import (
"github.com/hatchet-dev/hatchet/api/v1/server/oas/gen"
"github.com/hatchet-dev/hatchet/pkg/repository/prisma/db"
"github.com/hatchet-dev/hatchet/pkg/repository/postgres/dbsqlc"
"github.com/hatchet-dev/hatchet/pkg/repository/postgres/sqlchelpers"
)
func (i *SlackAppService) SlackWebhookDelete(ctx echo.Context, req gen.SlackWebhookDeleteRequestObject) (gen.SlackWebhookDeleteResponseObject, error) {
tenant := ctx.Get("tenant").(*db.TenantModel)
slack := ctx.Get("slack").(*db.SlackAppWebhookModel)
tenant := ctx.Get("tenant").(*dbsqlc.Tenant)
tenantId := sqlchelpers.UUIDToStr(tenant.ID)
slack := ctx.Get("slack").(*dbsqlc.SlackAppWebhook)
err := i.config.APIRepository.Slack().DeleteSlackWebhook(tenant.ID, slack.ID)
err := i.config.APIRepository.Slack().DeleteSlackWebhook(ctx.Request().Context(), tenantId, sqlchelpers.UUIDToStr(slack.ID))
if err != nil {
return nil, err

View File

@@ -5,14 +5,15 @@ import (
"github.com/hatchet-dev/hatchet/api/v1/server/oas/gen"
"github.com/hatchet-dev/hatchet/api/v1/server/oas/transformers"
"github.com/hatchet-dev/hatchet/pkg/repository/prisma/db"
"github.com/hatchet-dev/hatchet/pkg/repository/postgres/dbsqlc"
"github.com/hatchet-dev/hatchet/pkg/repository/postgres/sqlchelpers"
)
func (s *SlackAppService) SlackWebhookList(ctx echo.Context, req gen.SlackWebhookListRequestObject) (gen.SlackWebhookListResponseObject, error) {
tenant := ctx.Get("tenant").(*db.TenantModel)
tenant := ctx.Get("tenant").(*dbsqlc.Tenant)
tenantId := sqlchelpers.UUIDToStr(tenant.ID)
webhooks, err := s.config.APIRepository.Slack().ListSlackWebhooks(tenant.ID)
webhooks, err := s.config.APIRepository.Slack().ListSlackWebhooks(ctx.Request().Context(), tenantId)
if err != nil {
return nil, err
@@ -21,7 +22,7 @@ func (s *SlackAppService) SlackWebhookList(ctx echo.Context, req gen.SlackWebhoo
rows := make([]gen.SlackWebhook, len(webhooks))
for i := range webhooks {
rows[i] = *transformers.ToSlackWebhook(&webhooks[i])
rows[i] = *transformers.ToSlackWebhook(webhooks[i])
}
return gen.SlackWebhookList200JSONResponse(

View File

@@ -12,13 +12,13 @@ import (
"github.com/hatchet-dev/hatchet/internal/msgqueue"
"github.com/hatchet-dev/hatchet/internal/services/shared/tasktypes"
"github.com/hatchet-dev/hatchet/pkg/repository"
"github.com/hatchet-dev/hatchet/pkg/repository/prisma/db"
"github.com/hatchet-dev/hatchet/pkg/repository/prisma/dbsqlc"
"github.com/hatchet-dev/hatchet/pkg/repository/prisma/sqlchelpers"
"github.com/hatchet-dev/hatchet/pkg/repository/postgres/dbsqlc"
"github.com/hatchet-dev/hatchet/pkg/repository/postgres/sqlchelpers"
)
func (t *StepRunService) StepRunUpdateCancel(ctx echo.Context, request gen.StepRunUpdateCancelRequestObject) (gen.StepRunUpdateCancelResponseObject, error) {
tenant := ctx.Get("tenant").(*db.TenantModel)
tenant := ctx.Get("tenant").(*dbsqlc.Tenant)
tenantId := sqlchelpers.UUIDToStr(tenant.ID)
stepRun := ctx.Get("step-run").(*repository.GetStepRunFull)
// check to see if the step run is in a running or pending state
@@ -36,7 +36,7 @@ func (t *StepRunService) StepRunUpdateCancel(ctx echo.Context, request gen.StepR
engineStepRun, err := t.config.EngineRepository.StepRun().GetStepRunForEngine(
ctx.Request().Context(),
tenant.ID,
tenantId,
sqlchelpers.UUIDToStr(stepRun.ID),
)

View File

@@ -8,7 +8,7 @@ import (
"github.com/hatchet-dev/hatchet/api/v1/server/oas/gen"
"github.com/hatchet-dev/hatchet/api/v1/server/oas/transformers"
"github.com/hatchet-dev/hatchet/pkg/repository"
"github.com/hatchet-dev/hatchet/pkg/repository/prisma/sqlchelpers"
"github.com/hatchet-dev/hatchet/pkg/repository/postgres/sqlchelpers"
)
func (t *StepRunService) StepRunListArchives(ctx echo.Context, request gen.StepRunListArchivesRequestObject) (gen.StepRunListArchivesResponseObject, error) {

View File

@@ -8,7 +8,7 @@ import (
"github.com/hatchet-dev/hatchet/api/v1/server/oas/gen"
"github.com/hatchet-dev/hatchet/api/v1/server/oas/transformers"
"github.com/hatchet-dev/hatchet/pkg/repository"
"github.com/hatchet-dev/hatchet/pkg/repository/prisma/sqlchelpers"
"github.com/hatchet-dev/hatchet/pkg/repository/postgres/sqlchelpers"
)
func (t *StepRunService) StepRunListEvents(ctx echo.Context, request gen.StepRunListEventsRequestObject) (gen.StepRunListEventsResponseObject, error) {

View File

@@ -8,11 +8,13 @@ import (
"github.com/hatchet-dev/hatchet/api/v1/server/oas/gen"
"github.com/hatchet-dev/hatchet/api/v1/server/oas/transformers"
"github.com/hatchet-dev/hatchet/pkg/repository/prisma/db"
"github.com/hatchet-dev/hatchet/pkg/repository/postgres/dbsqlc"
"github.com/hatchet-dev/hatchet/pkg/repository/postgres/sqlchelpers"
)
func (t *StepRunService) WorkflowRunListStepRunEvents(ctx echo.Context, request gen.WorkflowRunListStepRunEventsRequestObject) (gen.WorkflowRunListStepRunEventsResponseObject, error) {
tenant := ctx.Get("tenant").(*db.TenantModel)
tenant := ctx.Get("tenant").(*dbsqlc.Tenant)
tenantId := sqlchelpers.UUIDToStr(tenant.ID)
reqCtx, cancel := context.WithTimeout(ctx.Request().Context(), 5*time.Second)
defer cancel()
@@ -21,7 +23,7 @@ func (t *StepRunService) WorkflowRunListStepRunEvents(ctx echo.Context, request
listRes, err := t.config.APIRepository.StepRun().ListStepRunEventsByWorkflowRunId(
reqCtx,
tenant.ID,
tenantId,
request.WorkflowRun.String(),
lastId,
)

View File

@@ -15,18 +15,19 @@ import (
"github.com/hatchet-dev/hatchet/internal/msgqueue"
"github.com/hatchet-dev/hatchet/internal/services/shared/tasktypes"
"github.com/hatchet-dev/hatchet/pkg/repository"
"github.com/hatchet-dev/hatchet/pkg/repository/prisma/db"
"github.com/hatchet-dev/hatchet/pkg/repository/prisma/sqlchelpers"
"github.com/hatchet-dev/hatchet/pkg/repository/postgres/dbsqlc"
"github.com/hatchet-dev/hatchet/pkg/repository/postgres/sqlchelpers"
)
func (t *StepRunService) StepRunUpdateRerun(ctx echo.Context, request gen.StepRunUpdateRerunRequestObject) (gen.StepRunUpdateRerunResponseObject, error) {
tenant := ctx.Get("tenant").(*db.TenantModel)
tenant := ctx.Get("tenant").(*dbsqlc.Tenant)
tenantId := sqlchelpers.UUIDToStr(tenant.ID)
stepRun := ctx.Get("step-run").(*repository.GetStepRunFull)
// preflight check to verify step run status and worker availability
err := t.config.EngineRepository.StepRun().PreflightCheckReplayStepRun(
ctx.Request().Context(),
tenant.ID,
tenantId,
sqlchelpers.UUIDToStr(stepRun.ID),
)
@@ -80,7 +81,7 @@ func (t *StepRunService) StepRunUpdateRerun(ctx echo.Context, request gen.StepRu
engineStepRun, err := t.config.EngineRepository.StepRun().GetStepRunForEngine(
ctx.Request().Context(),
tenant.ID,
tenantId,
sqlchelpers.UUIDToStr(stepRun.ID),
)

View File

@@ -4,18 +4,19 @@ import (
"context"
"errors"
"github.com/jackc/pgx/v5"
"github.com/labstack/echo/v4"
"github.com/hatchet-dev/hatchet/api/v1/server/oas/apierrors"
"github.com/hatchet-dev/hatchet/api/v1/server/oas/gen"
"github.com/hatchet-dev/hatchet/api/v1/server/oas/transformers"
"github.com/hatchet-dev/hatchet/pkg/repository"
"github.com/hatchet-dev/hatchet/pkg/repository/prisma/db"
"github.com/hatchet-dev/hatchet/pkg/repository/prisma/sqlchelpers"
"github.com/hatchet-dev/hatchet/pkg/repository/postgres/dbsqlc"
"github.com/hatchet-dev/hatchet/pkg/repository/postgres/sqlchelpers"
)
func (t *TenantService) TenantCreate(ctx echo.Context, request gen.TenantCreateRequestObject) (gen.TenantCreateResponseObject, error) {
user := ctx.Get("user").(*db.UserModel)
user := ctx.Get("user").(*dbsqlc.User)
if !t.config.Runtime.AllowCreateTenant {
return gen.TenantCreate400JSONResponse(
@@ -31,16 +32,16 @@ func (t *TenantService) TenantCreate(ctx echo.Context, request gen.TenantCreateR
}
// determine if a tenant with the slug already exists
existingTenant, err := t.config.APIRepository.Tenant().GetTenantBySlug(request.Body.Slug)
_, err := t.config.APIRepository.Tenant().GetTenantBySlug(ctx.Request().Context(), request.Body.Slug)
if err != nil && !errors.Is(err, db.ErrNotFound) {
if err != nil && !errors.Is(err, pgx.ErrNoRows) {
return nil, err
}
if existingTenant != nil {
if err == nil {
// just return bad request
return gen.TenantCreate400JSONResponse(
apierrors.NewAPIErrors("Tenant with the slug already exists."),
apierrors.NewAPIErrors("Tenant with that slug already exists."),
), nil
}
@@ -54,7 +55,7 @@ func (t *TenantService) TenantCreate(ctx echo.Context, request gen.TenantCreateR
}
// write the user to the db
tenant, err := t.config.APIRepository.Tenant().CreateTenant(createOpts)
tenant, err := t.config.APIRepository.Tenant().CreateTenant(ctx.Request().Context(), createOpts)
if err != nil {
return nil, err
@@ -69,8 +70,8 @@ func (t *TenantService) TenantCreate(ctx echo.Context, request gen.TenantCreateR
}
// add the user as an owner of the tenant
_, err = t.config.APIRepository.Tenant().CreateTenantMember(tenantId, &repository.CreateTenantMemberOpts{
UserId: user.ID,
_, err = t.config.APIRepository.Tenant().CreateTenantMember(ctx.Request().Context(), tenantId, &repository.CreateTenantMemberOpts{
UserId: sqlchelpers.UUIDToStr(user.ID),
Role: "OWNER",
})
@@ -85,12 +86,12 @@ func (t *TenantService) TenantCreate(ctx echo.Context, request gen.TenantCreateR
t.config.Analytics.Enqueue(
"tenant:create",
user.ID,
sqlchelpers.UUIDToStr(user.ID),
&tenantId,
nil,
)
return gen.TenantCreate200JSONResponse(
*transformers.ToTenantSqlc(tenant),
*transformers.ToTenant(tenant),
), nil
}

View File

@@ -6,11 +6,13 @@ import (
"github.com/hatchet-dev/hatchet/api/v1/server/oas/gen"
"github.com/hatchet-dev/hatchet/api/v1/server/oas/transformers"
"github.com/hatchet-dev/hatchet/pkg/repository"
"github.com/hatchet-dev/hatchet/pkg/repository/prisma/db"
"github.com/hatchet-dev/hatchet/pkg/repository/postgres/dbsqlc"
"github.com/hatchet-dev/hatchet/pkg/repository/postgres/sqlchelpers"
)
func (t *TenantService) AlertEmailGroupCreate(ctx echo.Context, request gen.AlertEmailGroupCreateRequestObject) (gen.AlertEmailGroupCreateResponseObject, error) {
tenant := ctx.Get("tenant").(*db.TenantModel)
tenant := ctx.Get("tenant").(*dbsqlc.Tenant)
tenantId := sqlchelpers.UUIDToStr(tenant.ID)
// validate the request
if apiErrors, err := t.config.Validator.ValidateAPI(request.Body); err != nil {
@@ -24,7 +26,7 @@ func (t *TenantService) AlertEmailGroupCreate(ctx echo.Context, request gen.Aler
Emails: request.Body.Emails,
}
emailGroup, err := t.config.APIRepository.TenantAlertingSettings().CreateTenantAlertGroup(tenant.ID, createOpts)
emailGroup, err := t.config.APIRepository.TenantAlertingSettings().CreateTenantAlertGroup(ctx.Request().Context(), tenantId, createOpts)
if err != nil {
return nil, err

View File

@@ -11,13 +11,15 @@ import (
"github.com/hatchet-dev/hatchet/api/v1/server/oas/transformers"
"github.com/hatchet-dev/hatchet/internal/integrations/email"
"github.com/hatchet-dev/hatchet/pkg/repository"
"github.com/hatchet-dev/hatchet/pkg/repository/prisma/db"
"github.com/hatchet-dev/hatchet/pkg/repository/postgres/dbsqlc"
"github.com/hatchet-dev/hatchet/pkg/repository/postgres/sqlchelpers"
)
func (t *TenantService) TenantInviteCreate(ctx echo.Context, request gen.TenantInviteCreateRequestObject) (gen.TenantInviteCreateResponseObject, error) {
user := ctx.Get("user").(*db.UserModel)
tenant := ctx.Get("tenant").(*db.TenantModel)
tenantMember := ctx.Get("tenant-member").(*db.TenantMemberModel)
user := ctx.Get("user").(*dbsqlc.User)
tenant := ctx.Get("tenant").(*dbsqlc.Tenant)
tenantId := sqlchelpers.UUIDToStr(tenant.ID)
tenantMember := ctx.Get("tenant-member").(*dbsqlc.PopulateTenantMembersRow)
if !t.config.Runtime.AllowInvites {
t.config.Logger.Warn().Msg("tenant invites are disabled")
return gen.TenantInviteCreate400JSONResponse(
@@ -34,7 +36,7 @@ func (t *TenantService) TenantInviteCreate(ctx echo.Context, request gen.TenantI
}
// ensure that this user isn't already a member of the tenant
if _, err := t.config.APIRepository.Tenant().GetTenantMemberByEmail(tenant.ID, request.Body.Email); err == nil {
if _, err := t.config.APIRepository.Tenant().GetTenantMemberByEmail(ctx.Request().Context(), tenantId, request.Body.Email); err == nil {
t.config.Logger.Warn().Msg("this user is already a member of this tenant")
return gen.TenantInviteCreate400JSONResponse(
apierrors.NewAPIErrors("this user is already a member of this tenant"),
@@ -42,7 +44,7 @@ func (t *TenantService) TenantInviteCreate(ctx echo.Context, request gen.TenantI
}
// if user is not an owner, they cannot change a role to owner
if tenantMember.Role != db.TenantMemberRoleOwner && request.Body.Role == gen.OWNER {
if tenantMember.Role != dbsqlc.TenantMemberRoleOWNER && request.Body.Role == gen.OWNER {
t.config.Logger.Warn().Msg("only an owner can change a role to owner")
return gen.TenantInviteCreate400JSONResponse(
apierrors.NewAPIErrors("only an owner can change a role to owner"),
@@ -59,7 +61,7 @@ func (t *TenantService) TenantInviteCreate(ctx echo.Context, request gen.TenantI
}
// create the invite
invite, err := t.config.APIRepository.TenantInvite().CreateTenantInvite(tenant.ID, createOpts)
invite, err := t.config.APIRepository.TenantInvite().CreateTenantInvite(ctx.Request().Context(), tenantId, createOpts)
if err != nil {
t.config.Logger.Err(err).Msg("could not create tenant invite")
@@ -76,8 +78,8 @@ func (t *TenantService) TenantInviteCreate(ctx echo.Context, request gen.TenantI
name := user.Email
if userName, ok := user.Name(); ok && userName != "" {
name = userName
if user.Name.Valid {
name = user.Name.String
}
if err := t.config.Email.SendTenantInviteEmail(emailCtx, invite.InviteeEmail, email.TenantInviteEmailData{
@@ -90,8 +92,8 @@ func (t *TenantService) TenantInviteCreate(ctx echo.Context, request gen.TenantI
}()
t.config.Analytics.Enqueue("user-invite:create",
user.ID,
&invite.TenantID,
sqlchelpers.UUIDToStr(user.ID),
&tenantId,
nil,
)

View File

@@ -4,15 +4,17 @@ import (
"github.com/labstack/echo/v4"
"github.com/hatchet-dev/hatchet/api/v1/server/oas/gen"
"github.com/hatchet-dev/hatchet/pkg/repository/prisma/db"
"github.com/hatchet-dev/hatchet/pkg/repository/postgres/dbsqlc"
"github.com/hatchet-dev/hatchet/pkg/repository/postgres/sqlchelpers"
)
func (t *TenantService) AlertEmailGroupDelete(ctx echo.Context, request gen.AlertEmailGroupDeleteRequestObject) (gen.AlertEmailGroupDeleteResponseObject, error) {
tenant := ctx.Get("tenant").(*db.TenantModel)
emailGroup := ctx.Get("alert-email-group").(*db.TenantAlertEmailGroupModel)
tenant := ctx.Get("tenant").(*dbsqlc.Tenant)
tenantId := sqlchelpers.UUIDToStr(tenant.ID)
emailGroup := ctx.Get("alert-email-group").(*dbsqlc.TenantAlertEmailGroup)
// delete the invite
err := t.config.APIRepository.TenantAlertingSettings().DeleteTenantAlertGroup(tenant.ID, emailGroup.ID)
err := t.config.APIRepository.TenantAlertingSettings().DeleteTenantAlertGroup(ctx.Request().Context(), tenantId, sqlchelpers.UUIDToStr(emailGroup.ID))
if err != nil {
return nil, err

View File

@@ -5,14 +5,15 @@ import (
"github.com/hatchet-dev/hatchet/api/v1/server/oas/gen"
"github.com/hatchet-dev/hatchet/api/v1/server/oas/transformers"
"github.com/hatchet-dev/hatchet/pkg/repository/prisma/db"
"github.com/hatchet-dev/hatchet/pkg/repository/postgres/dbsqlc"
"github.com/hatchet-dev/hatchet/pkg/repository/postgres/sqlchelpers"
)
func (t *TenantService) TenantInviteDelete(ctx echo.Context, request gen.TenantInviteDeleteRequestObject) (gen.TenantInviteDeleteResponseObject, error) {
invite := ctx.Get("tenant-invite").(*db.TenantInviteLinkModel)
invite := ctx.Get("tenant-invite").(*dbsqlc.TenantInviteLink)
// delete the invite
err := t.config.APIRepository.TenantInvite().DeleteTenantInvite(invite.ID)
err := t.config.APIRepository.TenantInvite().DeleteTenantInvite(ctx.Request().Context(), sqlchelpers.UUIDToStr(invite.ID))
if err != nil {
return nil, err

View File

@@ -5,38 +5,40 @@ import (
"github.com/hatchet-dev/hatchet/api/v1/server/oas/apierrors"
"github.com/hatchet-dev/hatchet/api/v1/server/oas/gen"
"github.com/hatchet-dev/hatchet/pkg/repository/prisma/db"
"github.com/hatchet-dev/hatchet/pkg/repository/postgres/dbsqlc"
"github.com/hatchet-dev/hatchet/pkg/repository/postgres/sqlchelpers"
)
func (t *TenantService) TenantMemberDelete(ctx echo.Context, request gen.TenantMemberDeleteRequestObject) (gen.TenantMemberDeleteResponseObject, error) {
tenant := ctx.Get("tenant").(*db.TenantModel)
tenantMember := ctx.Get("tenant-member").(*db.TenantMemberModel)
tenant := ctx.Get("tenant").(*dbsqlc.Tenant)
tenantId := sqlchelpers.UUIDToStr(tenant.ID)
tenantMember := ctx.Get("tenant-member").(*dbsqlc.PopulateTenantMembersRow)
if tenantMember.Role != db.TenantMemberRoleOwner {
if tenantMember.Role != dbsqlc.TenantMemberRoleOWNER {
return gen.TenantMemberDelete403JSONResponse(
apierrors.NewAPIErrors("Only owners can delete members"),
), nil
}
memberToDelete, err := t.config.APIRepository.Tenant().GetTenantMemberByID(request.Member.String())
memberToDelete, err := t.config.APIRepository.Tenant().GetTenantMemberByID(ctx.Request().Context(), request.Member.String())
if err != nil {
return nil, err
}
if tenantMember.UserID == memberToDelete.UserID {
if sqlchelpers.UUIDToStr(tenantMember.UserId) == sqlchelpers.UUIDToStr(memberToDelete.UserId) {
return gen.TenantMemberDelete403JSONResponse(
apierrors.NewAPIErrors("You cannot delete yourself"),
), nil
}
if memberToDelete.TenantID != tenant.ID {
if sqlchelpers.UUIDToStr(memberToDelete.TenantId) != tenantId {
return gen.TenantMemberDelete404JSONResponse(
apierrors.NewAPIErrors("Member not found"),
), nil
}
_, err = t.config.APIRepository.Tenant().DeleteTenantMember(memberToDelete.ID)
err = t.config.APIRepository.Tenant().DeleteTenantMember(ctx.Request().Context(), sqlchelpers.UUIDToStr(memberToDelete.ID))
if err != nil {
return nil, err

View File

@@ -5,19 +5,21 @@ import (
"github.com/hatchet-dev/hatchet/api/v1/server/oas/gen"
"github.com/hatchet-dev/hatchet/api/v1/server/oas/transformers"
"github.com/hatchet-dev/hatchet/pkg/repository/prisma/db"
"github.com/hatchet-dev/hatchet/pkg/repository/postgres/dbsqlc"
"github.com/hatchet-dev/hatchet/pkg/repository/postgres/sqlchelpers"
)
func (t *TenantService) TenantAlertingSettingsGet(ctx echo.Context, request gen.TenantAlertingSettingsGetRequestObject) (gen.TenantAlertingSettingsGetResponseObject, error) {
tenant := ctx.Get("tenant").(*db.TenantModel)
tenant := ctx.Get("tenant").(*dbsqlc.Tenant)
tenantId := sqlchelpers.UUIDToStr(tenant.ID)
tenantAlerting, err := t.config.APIRepository.TenantAlertingSettings().GetTenantAlertingSettings(tenant.ID)
tenantAlerting, err := t.config.APIRepository.TenantAlertingSettings().GetTenantAlertingSettings(ctx.Request().Context(), tenantId)
if err != nil {
return nil, err
}
return gen.TenantAlertingSettingsGet200JSONResponse(
*transformers.ToTenantAlertingSettings(tenantAlerting),
*transformers.ToTenantAlertingSettings(tenantAlerting.Settings),
), nil
}

View File

@@ -9,11 +9,13 @@ import (
"github.com/hatchet-dev/hatchet/api/v1/server/oas/apierrors"
"github.com/hatchet-dev/hatchet/api/v1/server/oas/gen"
"github.com/hatchet-dev/hatchet/pkg/repository"
"github.com/hatchet-dev/hatchet/pkg/repository/prisma/db"
"github.com/hatchet-dev/hatchet/pkg/repository/postgres/dbsqlc"
"github.com/hatchet-dev/hatchet/pkg/repository/postgres/sqlchelpers"
)
func (t *TenantService) TenantGetQueueMetrics(ctx echo.Context, request gen.TenantGetQueueMetricsRequestObject) (gen.TenantGetQueueMetricsResponseObject, error) {
tenant := ctx.Get("tenant").(*db.TenantModel)
tenant := ctx.Get("tenant").(*dbsqlc.Tenant)
tenantId := sqlchelpers.UUIDToStr(tenant.ID)
opts := repository.GetQueueMetricsOpts{}
@@ -38,13 +40,13 @@ func (t *TenantService) TenantGetQueueMetrics(ctx echo.Context, request gen.Tena
opts.WorkflowIds = *request.Params.Workflows
}
metrics, err := t.config.APIRepository.Tenant().GetQueueMetrics(ctx.Request().Context(), tenant.ID, &opts)
metrics, err := t.config.APIRepository.Tenant().GetQueueMetrics(ctx.Request().Context(), tenantId, &opts)
if err != nil {
return nil, err
}
stepRunQueueCounts, err := t.config.EngineRepository.StepRun().GetQueueCounts(ctx.Request().Context(), tenant.ID)
stepRunQueueCounts, err := t.config.EngineRepository.StepRun().GetQueueCounts(ctx.Request().Context(), tenantId)
if err != nil {
return nil, err

View File

@@ -7,13 +7,15 @@ import (
"github.com/hatchet-dev/hatchet/api/v1/server/oas/gen"
"github.com/hatchet-dev/hatchet/api/v1/server/oas/transformers"
"github.com/hatchet-dev/hatchet/pkg/repository/prisma/db"
"github.com/hatchet-dev/hatchet/pkg/repository/postgres/dbsqlc"
"github.com/hatchet-dev/hatchet/pkg/repository/postgres/sqlchelpers"
)
func (t *TenantService) TenantResourcePolicyGet(ctx echo.Context, request gen.TenantResourcePolicyGetRequestObject) (gen.TenantResourcePolicyGetResponseObject, error) {
tenant := ctx.Get("tenant").(*db.TenantModel)
tenant := ctx.Get("tenant").(*dbsqlc.Tenant)
tenantId := sqlchelpers.UUIDToStr(tenant.ID)
limits, err := t.config.EntitlementRepository.TenantLimit().GetLimits(context.Background(), tenant.ID)
limits, err := t.config.EntitlementRepository.TenantLimit().GetLimits(context.Background(), tenantId)
if err != nil {
return nil, err

View File

@@ -1,16 +1,48 @@
package tenants
import (
"fmt"
"github.com/labstack/echo/v4"
"github.com/hatchet-dev/hatchet/api/v1/server/oas/gen"
"github.com/hatchet-dev/hatchet/pkg/repository/prisma/db"
"github.com/hatchet-dev/hatchet/pkg/repository/postgres/dbsqlc"
"github.com/hatchet-dev/hatchet/pkg/repository/postgres/sqlchelpers"
)
func (t *TenantService) TenantGetStepRunQueueMetrics(ctx echo.Context, request gen.TenantGetStepRunQueueMetricsRequestObject) (gen.TenantGetStepRunQueueMetricsResponseObject, error) {
tenant := ctx.Get("tenant").(*db.TenantModel)
tenant := ctx.Get("tenant").(*dbsqlc.Tenant)
stepRunQueueCounts, err := t.config.EngineRepository.StepRun().GetQueueCounts(ctx.Request().Context(), tenant.ID)
switch tenant.Version {
case dbsqlc.TenantMajorEngineVersionV0:
return t.tenantGetStepRunQueueMetricsV0(ctx, tenant, request)
case dbsqlc.TenantMajorEngineVersionV1:
return t.tenantGetStepRunQueueMetricsV1(ctx, tenant, request)
default:
return nil, fmt.Errorf("unsupported tenant version: %s", string(tenant.Version))
}
}
func (t *TenantService) tenantGetStepRunQueueMetricsV0(ctx echo.Context, tenant *dbsqlc.Tenant, request gen.TenantGetStepRunQueueMetricsRequestObject) (gen.TenantGetStepRunQueueMetricsResponseObject, error) {
tenantId := sqlchelpers.UUIDToStr(tenant.ID)
stepRunQueueCounts, err := t.config.EngineRepository.StepRun().GetQueueCounts(ctx.Request().Context(), tenantId)
if err != nil {
return nil, err
}
resp := gen.TenantStepRunQueueMetrics{
Queues: &stepRunQueueCounts,
}
return gen.TenantGetStepRunQueueMetrics200JSONResponse(resp), nil
}
func (t *TenantService) tenantGetStepRunQueueMetricsV1(ctx echo.Context, tenant *dbsqlc.Tenant, request gen.TenantGetStepRunQueueMetricsRequestObject) (gen.TenantGetStepRunQueueMetricsResponseObject, error) {
tenantId := sqlchelpers.UUIDToStr(tenant.ID)
stepRunQueueCounts, err := t.config.V1.Tasks().GetQueueCounts(ctx.Request().Context(), tenantId)
if err != nil {
return nil, err

View File

@@ -5,13 +5,15 @@ import (
"github.com/hatchet-dev/hatchet/api/v1/server/oas/gen"
"github.com/hatchet-dev/hatchet/api/v1/server/oas/transformers"
"github.com/hatchet-dev/hatchet/pkg/repository/prisma/db"
"github.com/hatchet-dev/hatchet/pkg/repository/postgres/dbsqlc"
"github.com/hatchet-dev/hatchet/pkg/repository/postgres/sqlchelpers"
)
func (t *TenantService) AlertEmailGroupList(ctx echo.Context, request gen.AlertEmailGroupListRequestObject) (gen.AlertEmailGroupListResponseObject, error) {
tenant := ctx.Get("tenant").(*db.TenantModel)
tenant := ctx.Get("tenant").(*dbsqlc.Tenant)
tenantId := sqlchelpers.UUIDToStr(tenant.ID)
emailGroups, err := t.config.APIRepository.TenantAlertingSettings().ListTenantAlertGroups(tenant.ID)
emailGroups, err := t.config.APIRepository.TenantAlertingSettings().ListTenantAlertGroups(ctx.Request().Context(), tenantId)
if err != nil {
return nil, err
@@ -20,7 +22,7 @@ func (t *TenantService) AlertEmailGroupList(ctx echo.Context, request gen.AlertE
rows := make([]gen.TenantAlertEmailGroup, len(emailGroups))
for i := range emailGroups {
rows[i] = *transformers.ToTenantAlertEmailGroup(&emailGroups[i])
rows[i] = *transformers.ToTenantAlertEmailGroup(emailGroups[i])
}
return gen.AlertEmailGroupList200JSONResponse{

View File

@@ -6,13 +6,15 @@ import (
"github.com/hatchet-dev/hatchet/api/v1/server/oas/gen"
"github.com/hatchet-dev/hatchet/api/v1/server/oas/transformers"
"github.com/hatchet-dev/hatchet/pkg/repository"
"github.com/hatchet-dev/hatchet/pkg/repository/prisma/db"
"github.com/hatchet-dev/hatchet/pkg/repository/postgres/dbsqlc"
"github.com/hatchet-dev/hatchet/pkg/repository/postgres/sqlchelpers"
)
func (t *TenantService) TenantInviteList(ctx echo.Context, request gen.TenantInviteListRequestObject) (gen.TenantInviteListResponseObject, error) {
tenant := ctx.Get("tenant").(*db.TenantModel)
tenant := ctx.Get("tenant").(*dbsqlc.Tenant)
tenantId := sqlchelpers.UUIDToStr(tenant.ID)
tenantInvites, err := t.config.APIRepository.TenantInvite().ListTenantInvitesByTenantId(tenant.ID, &repository.ListTenantInvitesOpts{
tenantInvites, err := t.config.APIRepository.TenantInvite().ListTenantInvitesByTenantId(ctx.Request().Context(), tenantId, &repository.ListTenantInvitesOpts{
Expired: repository.BoolPtr(false),
Status: repository.StringPtr("PENDING"),
})
@@ -24,7 +26,7 @@ func (t *TenantService) TenantInviteList(ctx echo.Context, request gen.TenantInv
rows := make([]gen.TenantInvite, len(tenantInvites))
for i := range tenantInvites {
rows[i] = *transformers.ToTenantInviteLink(&tenantInvites[i])
rows[i] = *transformers.ToTenantInviteLink(tenantInvites[i])
}
return gen.TenantInviteList200JSONResponse{

View File

@@ -5,13 +5,15 @@ import (
"github.com/hatchet-dev/hatchet/api/v1/server/oas/gen"
"github.com/hatchet-dev/hatchet/api/v1/server/oas/transformers"
"github.com/hatchet-dev/hatchet/pkg/repository/prisma/db"
"github.com/hatchet-dev/hatchet/pkg/repository/postgres/dbsqlc"
"github.com/hatchet-dev/hatchet/pkg/repository/postgres/sqlchelpers"
)
func (t *TenantService) TenantMemberList(ctx echo.Context, request gen.TenantMemberListRequestObject) (gen.TenantMemberListResponseObject, error) {
tenant := ctx.Get("tenant").(*db.TenantModel)
tenant := ctx.Get("tenant").(*dbsqlc.Tenant)
tenantId := sqlchelpers.UUIDToStr(tenant.ID)
members, err := t.config.APIRepository.Tenant().ListTenantMembers(tenant.ID)
members, err := t.config.APIRepository.Tenant().ListTenantMembers(ctx.Request().Context(), tenantId)
if err != nil {
return nil, err
@@ -20,7 +22,7 @@ func (t *TenantService) TenantMemberList(ctx echo.Context, request gen.TenantMem
rows := make([]gen.TenantMember, len(members))
for i := range members {
rows[i] = *transformers.ToTenantMember(&members[i])
rows[i] = *transformers.ToTenantMember(members[i])
}
return gen.TenantMemberList200JSONResponse{

View File

@@ -6,11 +6,13 @@ import (
"github.com/hatchet-dev/hatchet/api/v1/server/oas/gen"
"github.com/hatchet-dev/hatchet/api/v1/server/oas/transformers"
"github.com/hatchet-dev/hatchet/pkg/repository"
"github.com/hatchet-dev/hatchet/pkg/repository/prisma/db"
"github.com/hatchet-dev/hatchet/pkg/repository/postgres/dbsqlc"
"github.com/hatchet-dev/hatchet/pkg/repository/postgres/sqlchelpers"
)
func (t *TenantService) TenantUpdate(ctx echo.Context, request gen.TenantUpdateRequestObject) (gen.TenantUpdateResponseObject, error) {
tenant := ctx.Get("tenant").(*db.TenantModel)
tenant := ctx.Get("tenant").(*dbsqlc.Tenant)
tenantId := sqlchelpers.UUIDToStr(tenant.ID)
// validate the request
if apiErrors, err := t.config.Validator.ValidateAPI(request.Body); err != nil {
@@ -34,8 +36,15 @@ func (t *TenantService) TenantUpdate(ctx echo.Context, request gen.TenantUpdateR
updateOpts.Name = request.Body.Name
}
if request.Body.Version != nil {
updateOpts.Version = &dbsqlc.NullTenantMajorEngineVersion{
Valid: true,
TenantMajorEngineVersion: dbsqlc.TenantMajorEngineVersion(*request.Body.Version),
}
}
// update the tenant
tenant, err := t.config.APIRepository.Tenant().UpdateTenant(tenant.ID, updateOpts)
tenant, err := t.config.APIRepository.Tenant().UpdateTenant(ctx.Request().Context(), tenantId, updateOpts)
if err != nil {
return nil, err
@@ -47,7 +56,8 @@ func (t *TenantService) TenantUpdate(ctx echo.Context, request gen.TenantUpdateR
request.Body.EnableWorkflowRunFailureAlerts != nil {
_, err = t.config.APIRepository.TenantAlertingSettings().UpsertTenantAlertingSettings(
tenant.ID,
ctx.Request().Context(),
tenantId,
&repository.UpsertTenantAlertingSettingsOpts{
MaxFrequency: request.Body.MaxAlertingFrequency,
EnableExpiringTokenAlerts: request.Body.EnableExpiringTokenAlerts,

View File

@@ -6,11 +6,12 @@ import (
"github.com/hatchet-dev/hatchet/api/v1/server/oas/gen"
"github.com/hatchet-dev/hatchet/api/v1/server/oas/transformers"
"github.com/hatchet-dev/hatchet/pkg/repository"
"github.com/hatchet-dev/hatchet/pkg/repository/prisma/db"
"github.com/hatchet-dev/hatchet/pkg/repository/postgres/dbsqlc"
"github.com/hatchet-dev/hatchet/pkg/repository/postgres/sqlchelpers"
)
func (t *TenantService) AlertEmailGroupUpdate(ctx echo.Context, request gen.AlertEmailGroupUpdateRequestObject) (gen.AlertEmailGroupUpdateResponseObject, error) {
emailGroup := ctx.Get("alert-email-group").(*db.TenantAlertEmailGroupModel)
emailGroup := ctx.Get("alert-email-group").(*dbsqlc.TenantAlertEmailGroup)
// validate the request
if apiErrors, err := t.config.Validator.ValidateAPI(request.Body); err != nil {
@@ -24,7 +25,7 @@ func (t *TenantService) AlertEmailGroupUpdate(ctx echo.Context, request gen.Aler
Emails: request.Body.Emails,
}
emailGroup, err := t.config.APIRepository.TenantAlertingSettings().UpdateTenantAlertGroup(emailGroup.ID, updateOpts)
emailGroup, err := t.config.APIRepository.TenantAlertingSettings().UpdateTenantAlertGroup(ctx.Request().Context(), sqlchelpers.UUIDToStr(emailGroup.ID), updateOpts)
if err != nil {
return nil, err

View File

@@ -7,12 +7,13 @@ import (
"github.com/hatchet-dev/hatchet/api/v1/server/oas/gen"
"github.com/hatchet-dev/hatchet/api/v1/server/oas/transformers"
"github.com/hatchet-dev/hatchet/pkg/repository"
"github.com/hatchet-dev/hatchet/pkg/repository/prisma/db"
"github.com/hatchet-dev/hatchet/pkg/repository/postgres/dbsqlc"
"github.com/hatchet-dev/hatchet/pkg/repository/postgres/sqlchelpers"
)
func (t *TenantService) TenantInviteUpdate(ctx echo.Context, request gen.TenantInviteUpdateRequestObject) (gen.TenantInviteUpdateResponseObject, error) {
tenantMember := ctx.Get("tenant-member").(*db.TenantMemberModel)
invite := ctx.Get("tenant-invite").(*db.TenantInviteLinkModel)
tenantMember := ctx.Get("tenant-member").(*dbsqlc.PopulateTenantMembersRow)
invite := ctx.Get("tenant-invite").(*dbsqlc.TenantInviteLink)
// validate the request
if apiErrors, err := t.config.Validator.ValidateAPI(request.Body); err != nil {
@@ -22,7 +23,7 @@ func (t *TenantService) TenantInviteUpdate(ctx echo.Context, request gen.TenantI
}
// if user is not an owner, they cannot change a role to owner
if tenantMember.Role != db.TenantMemberRoleOwner && request.Body.Role == gen.OWNER {
if tenantMember.Role != dbsqlc.TenantMemberRoleOWNER && request.Body.Role == gen.OWNER {
return gen.TenantInviteUpdate400JSONResponse(
apierrors.NewAPIErrors("only an owner can change a role to owner"),
), nil
@@ -34,7 +35,7 @@ func (t *TenantService) TenantInviteUpdate(ctx echo.Context, request gen.TenantI
}
// update the invite
invite, err := t.config.APIRepository.TenantInvite().UpdateTenantInvite(invite.ID, updateOpts)
invite, err := t.config.APIRepository.TenantInvite().UpdateTenantInvite(ctx.Request().Context(), sqlchelpers.UUIDToStr(invite.ID), updateOpts)
if err != nil {
return nil, err

View File

@@ -4,16 +4,19 @@ import (
"errors"
"time"
"github.com/jackc/pgx/v5"
"github.com/labstack/echo/v4"
"github.com/hatchet-dev/hatchet/api/v1/server/oas/apierrors"
"github.com/hatchet-dev/hatchet/api/v1/server/oas/gen"
"github.com/hatchet-dev/hatchet/pkg/repository"
"github.com/hatchet-dev/hatchet/pkg/repository/prisma/db"
"github.com/hatchet-dev/hatchet/pkg/repository/postgres/dbsqlc"
"github.com/hatchet-dev/hatchet/pkg/repository/postgres/sqlchelpers"
)
func (u *UserService) TenantInviteAccept(ctx echo.Context, request gen.TenantInviteAcceptRequestObject) (gen.TenantInviteAcceptResponseObject, error) {
user := ctx.Get("user").(*db.UserModel)
user := ctx.Get("user").(*dbsqlc.User)
userId := sqlchelpers.UUIDToStr(user.ID)
// validate the request
if apiErrors, err := u.config.Validator.ValidateAPI(request.Body); err != nil {
@@ -29,7 +32,7 @@ func (u *UserService) TenantInviteAccept(ctx echo.Context, request gen.TenantInv
}
// get the invite
invite, err := u.config.APIRepository.TenantInvite().GetTenantInvite(inviteId)
invite, err := u.config.APIRepository.TenantInvite().GetTenantInvite(ctx.Request().Context(), inviteId)
if err != nil {
return nil, err
@@ -41,19 +44,19 @@ func (u *UserService) TenantInviteAccept(ctx echo.Context, request gen.TenantInv
}
// ensure the invite is not expired
if invite.Expires.Before(time.Now()) {
if invite.Expires.Time.Before(time.Now()) {
return gen.TenantInviteAccept400JSONResponse(apierrors.NewAPIErrors("invite is expired")), nil
}
// ensure invite is in a pending state
if invite.Status != db.InviteLinkStatusPending {
if invite.Status != dbsqlc.InviteLinkStatusPENDING {
return gen.TenantInviteAccept400JSONResponse(apierrors.NewAPIErrors("invite has already been used")), nil
}
// ensure the user is not already a member of the tenant
_, err = u.config.APIRepository.Tenant().GetTenantMemberByEmail(invite.TenantID, user.Email)
_, err = u.config.APIRepository.Tenant().GetTenantMemberByEmail(ctx.Request().Context(), sqlchelpers.UUIDToStr(invite.TenantId), user.Email)
if err != nil && !errors.Is(err, db.ErrNotFound) {
if err != nil && !errors.Is(err, pgx.ErrNoRows) {
return nil, err
} else if err == nil {
return gen.TenantInviteAccept400JSONResponse(apierrors.NewAPIErrors("user is already a member of the tenant")), nil
@@ -61,19 +64,19 @@ func (u *UserService) TenantInviteAccept(ctx echo.Context, request gen.TenantInv
// construct the database query
updateOpts := &repository.UpdateTenantInviteOpts{
Status: repository.StringPtr(string(db.InviteLinkStatusAccepted)),
Status: repository.StringPtr(string(dbsqlc.InviteLinkStatusACCEPTED)),
}
// update the invite
invite, err = u.config.APIRepository.TenantInvite().UpdateTenantInvite(invite.ID, updateOpts)
invite, err = u.config.APIRepository.TenantInvite().UpdateTenantInvite(ctx.Request().Context(), sqlchelpers.UUIDToStr(invite.ID), updateOpts)
if err != nil {
return nil, err
}
// add the user to the tenant
_, err = u.config.APIRepository.Tenant().CreateTenantMember(invite.TenantID, &repository.CreateTenantMemberOpts{
UserId: user.ID,
_, err = u.config.APIRepository.Tenant().CreateTenantMember(ctx.Request().Context(), sqlchelpers.UUIDToStr(invite.TenantId), &repository.CreateTenantMemberOpts{
UserId: userId,
Role: string(invite.Role),
})
@@ -81,10 +84,12 @@ func (u *UserService) TenantInviteAccept(ctx echo.Context, request gen.TenantInv
return nil, err
}
tenantId := sqlchelpers.UUIDToStr(invite.TenantId)
u.config.Analytics.Enqueue(
"user-invite:reject",
user.ID,
&invite.TenantID,
"user-invite:accept",
userId,
&tenantId,
nil,
)

View File

@@ -3,13 +3,14 @@ package users
import (
"errors"
"github.com/jackc/pgx/v5"
"github.com/labstack/echo/v4"
"github.com/hatchet-dev/hatchet/api/v1/server/oas/apierrors"
"github.com/hatchet-dev/hatchet/api/v1/server/oas/gen"
"github.com/hatchet-dev/hatchet/api/v1/server/oas/transformers"
"github.com/hatchet-dev/hatchet/pkg/repository"
"github.com/hatchet-dev/hatchet/pkg/repository/prisma/db"
"github.com/hatchet-dev/hatchet/pkg/repository/postgres/sqlchelpers"
"github.com/hatchet-dev/hatchet/api/v1/server/authn"
)
@@ -35,13 +36,13 @@ func (u *UserService) UserCreate(ctx echo.Context, request gen.UserCreateRequest
}
// determine if the user exists before attempting to write the user
existingUser, err := u.config.APIRepository.User().GetUserByEmail(string(request.Body.Email))
_, err := u.config.APIRepository.User().GetUserByEmail(ctx.Request().Context(), string(request.Body.Email))
if err != nil && !errors.Is(err, db.ErrNotFound) {
if err != nil && !errors.Is(err, pgx.ErrNoRows) {
return nil, err
}
if existingUser != nil {
if err == nil {
// just return bad request
return gen.UserCreate400JSONResponse(
apierrors.NewAPIErrors("Email is already registered."),
@@ -66,7 +67,7 @@ func (u *UserService) UserCreate(ctx echo.Context, request gen.UserCreateRequest
}
// write the user to the db
user, err := u.config.APIRepository.User().CreateUser(createOpts)
user, err := u.config.APIRepository.User().CreateUser(ctx.Request().Context(), createOpts)
if err != nil {
return nil, err
}
@@ -79,7 +80,7 @@ func (u *UserService) UserCreate(ctx echo.Context, request gen.UserCreateRequest
u.config.Analytics.Enqueue(
"user:create",
user.ID,
sqlchelpers.UUIDToStr(user.ID),
nil,
map[string]interface{}{
"email": request.Body.Email,

View File

@@ -6,25 +6,28 @@ import (
"encoding/hex"
"errors"
"github.com/jackc/pgx/v5"
"github.com/labstack/echo/v4"
"github.com/hatchet-dev/hatchet/api/v1/server/oas/gen"
"github.com/hatchet-dev/hatchet/api/v1/server/oas/transformers"
"github.com/hatchet-dev/hatchet/pkg/repository/prisma/db"
"github.com/hatchet-dev/hatchet/pkg/repository/postgres/dbsqlc"
"github.com/hatchet-dev/hatchet/pkg/repository/postgres/sqlchelpers"
)
func (u *UserService) UserGetCurrent(ctx echo.Context, request gen.UserGetCurrentRequestObject) (gen.UserGetCurrentResponseObject, error) {
user := ctx.Get("user").(*db.UserModel)
user := ctx.Get("user").(*dbsqlc.User)
userId := sqlchelpers.UUIDToStr(user.ID)
var hasPass bool
pass, err := u.config.APIRepository.User().GetUserPassword(user.ID)
_, err := u.config.APIRepository.User().GetUserPassword(ctx.Request().Context(), userId)
if err != nil && !errors.Is(err, db.ErrNotFound) {
if err != nil && !errors.Is(err, pgx.ErrNoRows) {
return nil, err
}
if pass != nil {
if err == nil {
hasPass = true
}
@@ -42,7 +45,7 @@ func (u *UserService) UserGetCurrent(ctx echo.Context, request gen.UserGetCurren
u.config.Analytics.Enqueue(
"user:current",
user.ID,
userId,
nil,
map[string]interface{}{
"email": user.Email,

View File

@@ -6,6 +6,7 @@ import (
"fmt"
githubsdk "github.com/google/go-github/v57/github"
"github.com/jackc/pgx/v5"
"github.com/labstack/echo/v4"
"golang.org/x/oauth2"
@@ -14,7 +15,8 @@ import (
"github.com/hatchet-dev/hatchet/api/v1/server/oas/gen"
"github.com/hatchet-dev/hatchet/pkg/config/server"
"github.com/hatchet-dev/hatchet/pkg/repository"
"github.com/hatchet-dev/hatchet/pkg/repository/prisma/db"
"github.com/hatchet-dev/hatchet/pkg/repository/postgres/dbsqlc"
"github.com/hatchet-dev/hatchet/pkg/repository/postgres/sqlchelpers"
)
// Note: we want all errors to redirect, otherwise the user will be greeted with raw JSON in the middle of the login flow.
@@ -35,7 +37,7 @@ func (u *UserService) UserUpdateGithubOauthCallback(ctx echo.Context, _ gen.User
return nil, redirect.GetRedirectWithError(ctx, u.config.Logger, fmt.Errorf("invalid token"), "Forbidden")
}
user, err := u.upsertGithubUserFromToken(u.config, token)
user, err := u.upsertGithubUserFromToken(ctx.Request().Context(), u.config, token)
if err != nil {
if errors.Is(err, ErrNotInRestrictedDomain) {
@@ -66,7 +68,7 @@ func (u *UserService) UserUpdateGithubOauthCallback(ctx echo.Context, _ gen.User
}, nil
}
func (u *UserService) upsertGithubUserFromToken(config *server.ServerConfig, tok *oauth2.Token) (*db.UserModel, error) {
func (u *UserService) upsertGithubUserFromToken(ctx context.Context, config *server.ServerConfig, tok *oauth2.Token) (*dbsqlc.User, error) {
gInfo, err := u.getGithubEmailFromToken(tok)
if err != nil {
@@ -96,15 +98,15 @@ func (u *UserService) upsertGithubUserFromToken(config *server.ServerConfig, tok
Provider: "github",
ProviderUserId: gInfo.ID,
AccessToken: accessTokenEncrypted,
RefreshToken: &refreshTokenEncrypted,
RefreshToken: refreshTokenEncrypted,
ExpiresAt: &expiresAt,
}
user, err := u.config.APIRepository.User().GetUserByEmail(gInfo.Email)
user, err := u.config.APIRepository.User().GetUserByEmail(ctx, gInfo.Email)
switch err {
case nil:
user, err = u.config.APIRepository.User().UpdateUser(user.ID, &repository.UpdateUserOpts{
user, err = u.config.APIRepository.User().UpdateUser(ctx, sqlchelpers.UUIDToStr(user.ID), &repository.UpdateUserOpts{
EmailVerified: repository.BoolPtr(gInfo.EmailVerified),
Name: repository.StringPtr(gInfo.Name),
OAuth: oauthOpts,
@@ -113,8 +115,8 @@ func (u *UserService) upsertGithubUserFromToken(config *server.ServerConfig, tok
if err != nil {
return nil, fmt.Errorf("failed to update user: %s", err.Error())
}
case db.ErrNotFound:
user, err = u.config.APIRepository.User().CreateUser(&repository.CreateUserOpts{
case pgx.ErrNoRows:
user, err = u.config.APIRepository.User().CreateUser(ctx, &repository.CreateUserOpts{
Email: gInfo.Email,
EmailVerified: repository.BoolPtr(gInfo.EmailVerified),
Name: repository.StringPtr(gInfo.Name),

View File

@@ -8,6 +8,7 @@ import (
"io"
"net/http"
"github.com/jackc/pgx/v5"
"github.com/labstack/echo/v4"
"golang.org/x/oauth2"
@@ -16,7 +17,8 @@ import (
"github.com/hatchet-dev/hatchet/api/v1/server/oas/gen"
"github.com/hatchet-dev/hatchet/pkg/config/server"
"github.com/hatchet-dev/hatchet/pkg/repository"
"github.com/hatchet-dev/hatchet/pkg/repository/prisma/db"
"github.com/hatchet-dev/hatchet/pkg/repository/postgres/dbsqlc"
"github.com/hatchet-dev/hatchet/pkg/repository/postgres/sqlchelpers"
)
// Note: we want all errors to redirect, otherwise the user will be greeted with raw JSON in the middle of the login flow.
@@ -37,7 +39,7 @@ func (u *UserService) UserUpdateGoogleOauthCallback(ctx echo.Context, _ gen.User
return nil, redirect.GetRedirectWithError(ctx, u.config.Logger, fmt.Errorf("invalid token"), "Forbidden")
}
user, err := u.upsertGoogleUserFromToken(u.config, token)
user, err := u.upsertGoogleUserFromToken(ctx.Request().Context(), u.config, token)
if err != nil {
if errors.Is(err, ErrNotInRestrictedDomain) {
@@ -60,7 +62,7 @@ func (u *UserService) UserUpdateGoogleOauthCallback(ctx echo.Context, _ gen.User
}, nil
}
func (u *UserService) upsertGoogleUserFromToken(config *server.ServerConfig, tok *oauth2.Token) (*db.UserModel, error) {
func (u *UserService) upsertGoogleUserFromToken(ctx context.Context, config *server.ServerConfig, tok *oauth2.Token) (*dbsqlc.User, error) {
gInfo, err := getGoogleUserInfoFromToken(tok)
if err != nil {
return nil, err
@@ -89,15 +91,15 @@ func (u *UserService) upsertGoogleUserFromToken(config *server.ServerConfig, tok
Provider: "google",
ProviderUserId: gInfo.Sub,
AccessToken: accessTokenEncrypted,
RefreshToken: &refreshTokenEncrypted,
RefreshToken: refreshTokenEncrypted,
ExpiresAt: &expiresAt,
}
user, err := u.config.APIRepository.User().GetUserByEmail(gInfo.Email)
user, err := u.config.APIRepository.User().GetUserByEmail(ctx, gInfo.Email)
switch err {
case nil:
user, err = u.config.APIRepository.User().UpdateUser(user.ID, &repository.UpdateUserOpts{
user, err = u.config.APIRepository.User().UpdateUser(ctx, sqlchelpers.UUIDToStr(user.ID), &repository.UpdateUserOpts{
EmailVerified: repository.BoolPtr(gInfo.EmailVerified),
Name: repository.StringPtr(gInfo.Name),
OAuth: oauthOpts,
@@ -106,8 +108,8 @@ func (u *UserService) upsertGoogleUserFromToken(config *server.ServerConfig, tok
if err != nil {
return nil, fmt.Errorf("failed to update user: %s", err.Error())
}
case db.ErrNotFound:
user, err = u.config.APIRepository.User().CreateUser(&repository.CreateUserOpts{
case pgx.ErrNoRows:
user, err = u.config.APIRepository.User().CreateUser(ctx, &repository.CreateUserOpts{
Email: gInfo.Email,
EmailVerified: repository.BoolPtr(gInfo.EmailVerified),
Name: repository.StringPtr(gInfo.Name),

View File

@@ -5,13 +5,15 @@ import (
"github.com/hatchet-dev/hatchet/api/v1/server/oas/gen"
"github.com/hatchet-dev/hatchet/api/v1/server/oas/transformers"
"github.com/hatchet-dev/hatchet/pkg/repository/prisma/db"
"github.com/hatchet-dev/hatchet/pkg/repository/postgres/dbsqlc"
"github.com/hatchet-dev/hatchet/pkg/repository/postgres/sqlchelpers"
)
func (t *UserService) TenantMembershipsList(ctx echo.Context, request gen.TenantMembershipsListRequestObject) (gen.TenantMembershipsListResponseObject, error) {
user := ctx.Get("user").(*db.UserModel)
user := ctx.Get("user").(*dbsqlc.User)
userId := sqlchelpers.UUIDToStr(user.ID)
memberships, err := t.config.APIRepository.User().ListTenantMemberships(user.ID)
memberships, err := t.config.APIRepository.User().ListTenantMemberships(ctx.Request().Context(), userId)
if err != nil {
return nil, err
@@ -20,8 +22,7 @@ func (t *UserService) TenantMembershipsList(ctx echo.Context, request gen.Tenant
rows := make([]gen.TenantMember, len(memberships))
for i, membership := range memberships {
membershipCp := membership
rows[i] = *transformers.ToTenantMember(&membershipCp)
rows[i] = *transformers.ToTenantMember(membership)
}
return gen.TenantMembershipsList200JSONResponse(

View File

@@ -5,13 +5,13 @@ import (
"github.com/hatchet-dev/hatchet/api/v1/server/oas/gen"
"github.com/hatchet-dev/hatchet/api/v1/server/oas/transformers"
"github.com/hatchet-dev/hatchet/pkg/repository/prisma/db"
"github.com/hatchet-dev/hatchet/pkg/repository/postgres/dbsqlc"
)
func (t *UserService) UserListTenantInvites(ctx echo.Context, request gen.UserListTenantInvitesRequestObject) (gen.UserListTenantInvitesResponseObject, error) {
user := ctx.Get("user").(*db.UserModel)
user := ctx.Get("user").(*dbsqlc.User)
invites, err := t.config.APIRepository.TenantInvite().ListTenantInvitesByEmail(user.Email)
invites, err := t.config.APIRepository.TenantInvite().ListTenantInvitesByEmail(ctx.Request().Context(), user.Email)
if err != nil {
return nil, err
@@ -20,7 +20,7 @@ func (t *UserService) UserListTenantInvites(ctx echo.Context, request gen.UserLi
rows := make([]gen.TenantInvite, len(invites))
for i := range invites {
rows[i] = *transformers.ToTenantInviteLink(&invites[i])
rows[i] = *transformers.ToTenantInviteLink(invites[i])
}
return gen.UserListTenantInvites200JSONResponse(gen.TenantInviteList200JSONResponse{

View File

@@ -9,11 +9,13 @@ import (
"github.com/hatchet-dev/hatchet/api/v1/server/oas/apierrors"
"github.com/hatchet-dev/hatchet/api/v1/server/oas/gen"
"github.com/hatchet-dev/hatchet/pkg/repository"
"github.com/hatchet-dev/hatchet/pkg/repository/prisma/db"
"github.com/hatchet-dev/hatchet/pkg/repository/postgres/dbsqlc"
"github.com/hatchet-dev/hatchet/pkg/repository/postgres/sqlchelpers"
)
func (u *UserService) TenantInviteReject(ctx echo.Context, request gen.TenantInviteRejectRequestObject) (gen.TenantInviteRejectResponseObject, error) {
user := ctx.Get("user").(*db.UserModel)
user := ctx.Get("user").(*dbsqlc.User)
userId := sqlchelpers.UUIDToStr(user.ID)
// validate the request
if apiErrors, err := u.config.Validator.ValidateAPI(request.Body); err != nil {
@@ -29,7 +31,7 @@ func (u *UserService) TenantInviteReject(ctx echo.Context, request gen.TenantInv
}
// get the invite
invite, err := u.config.APIRepository.TenantInvite().GetTenantInvite(inviteId)
invite, err := u.config.APIRepository.TenantInvite().GetTenantInvite(ctx.Request().Context(), inviteId)
if err != nil {
return nil, err
@@ -41,31 +43,33 @@ func (u *UserService) TenantInviteReject(ctx echo.Context, request gen.TenantInv
}
// ensure the invite is not expired
if invite.Expires.Before(time.Now()) {
if invite.Expires.Time.Before(time.Now()) {
return gen.TenantInviteReject400JSONResponse(apierrors.NewAPIErrors("invite is expired")), nil
}
// ensure invite is in a pending state
if invite.Status != db.InviteLinkStatusPending {
if invite.Status != dbsqlc.InviteLinkStatusPENDING {
return gen.TenantInviteReject400JSONResponse(apierrors.NewAPIErrors("invite has already been used")), nil
}
// construct the database query
updateOpts := &repository.UpdateTenantInviteOpts{
Status: repository.StringPtr(string(db.InviteLinkStatusRejected)),
Status: repository.StringPtr(string(dbsqlc.InviteLinkStatusREJECTED)),
}
// update the invite
invite, err = u.config.APIRepository.TenantInvite().UpdateTenantInvite(invite.ID, updateOpts)
invite, err = u.config.APIRepository.TenantInvite().UpdateTenantInvite(ctx.Request().Context(), sqlchelpers.UUIDToStr(invite.ID), updateOpts)
if err != nil {
return nil, err
}
tenantId := sqlchelpers.UUIDToStr(invite.TenantId)
u.config.Analytics.Enqueue(
"user-invite:accept",
user.ID,
&invite.TenantID,
"user-invite:reject",
userId,
&tenantId,
nil,
)

View File

@@ -4,6 +4,7 @@ import (
"errors"
"fmt"
"github.com/jackc/pgx/v5"
"github.com/labstack/echo/v4"
"github.com/hatchet-dev/hatchet/api/v1/server/authn"
@@ -11,7 +12,7 @@ import (
"github.com/hatchet-dev/hatchet/api/v1/server/oas/gen"
"github.com/hatchet-dev/hatchet/api/v1/server/oas/transformers"
"github.com/hatchet-dev/hatchet/pkg/repository"
"github.com/hatchet-dev/hatchet/pkg/repository/prisma/db"
"github.com/hatchet-dev/hatchet/pkg/repository/postgres/sqlchelpers"
)
func (u *UserService) UserUpdateLogin(ctx echo.Context, request gen.UserUpdateLoginRequestObject) (gen.UserUpdateLoginResponseObject, error) {
@@ -36,16 +37,16 @@ func (u *UserService) UserUpdateLogin(ctx echo.Context, request gen.UserUpdateLo
}
// determine if the user exists before attempting to write the user
existingUser, err := u.config.APIRepository.User().GetUserByEmail(string(request.Body.Email))
existingUser, err := u.config.APIRepository.User().GetUserByEmail(ctx.Request().Context(), string(request.Body.Email))
if err != nil {
if errors.Is(err, db.ErrNotFound) {
if errors.Is(err, pgx.ErrNoRows) {
return gen.UserUpdateLogin400JSONResponse(apierrors.NewAPIErrors("user not found")), nil
}
return nil, err
}
userPass, err := u.config.APIRepository.User().GetUserPassword(existingUser.ID)
userPass, err := u.config.APIRepository.User().GetUserPassword(ctx.Request().Context(), sqlchelpers.UUIDToStr(existingUser.ID))
if err != nil {
return nil, fmt.Errorf("could not get user password: %w", err)

View File

@@ -6,11 +6,11 @@ import (
"github.com/hatchet-dev/hatchet/api/v1/server/authn"
"github.com/hatchet-dev/hatchet/api/v1/server/oas/gen"
"github.com/hatchet-dev/hatchet/api/v1/server/oas/transformers"
"github.com/hatchet-dev/hatchet/pkg/repository/prisma/db"
"github.com/hatchet-dev/hatchet/pkg/repository/postgres/dbsqlc"
)
func (u *UserService) UserUpdateLogout(ctx echo.Context, request gen.UserUpdateLogoutRequestObject) (gen.UserUpdateLogoutResponseObject, error) {
user := ctx.Get("user").(*db.UserModel)
user := ctx.Get("user").(*dbsqlc.User)
if err := authn.NewSessionHelpers(u.config).SaveUnauthenticated(ctx); err != nil {
return nil, err

View File

@@ -9,12 +9,13 @@ import (
"github.com/hatchet-dev/hatchet/api/v1/server/oas/gen"
"github.com/hatchet-dev/hatchet/api/v1/server/oas/transformers"
"github.com/hatchet-dev/hatchet/pkg/repository"
"github.com/hatchet-dev/hatchet/pkg/repository/prisma/db"
"github.com/hatchet-dev/hatchet/pkg/repository/postgres/dbsqlc"
"github.com/hatchet-dev/hatchet/pkg/repository/postgres/sqlchelpers"
)
func (u *UserService) UserUpdatePassword(ctx echo.Context, request gen.UserUpdatePasswordRequestObject) (gen.UserUpdatePasswordResponseObject, error) {
// determine if the user exists before attempting to write the user
existingUser := ctx.Get("user").(*db.UserModel)
existingUser := ctx.Get("user").(*dbsqlc.User)
if !u.config.Runtime.AllowChangePassword {
return gen.UserUpdatePassword405JSONResponse(
@@ -36,7 +37,9 @@ func (u *UserService) UserUpdatePassword(ctx echo.Context, request gen.UserUpdat
return gen.UserUpdatePassword400JSONResponse(*apiErrors), nil
}
userPass, err := u.config.APIRepository.User().GetUserPassword(existingUser.ID)
userId := sqlchelpers.UUIDToStr(existingUser.ID)
userPass, err := u.config.APIRepository.User().GetUserPassword(ctx.Request().Context(), userId)
if err != nil {
return nil, fmt.Errorf("could not get user password: %w", err)
@@ -54,7 +57,7 @@ func (u *UserService) UserUpdatePassword(ctx echo.Context, request gen.UserUpdat
return nil, fmt.Errorf("could not hash user password: %w", err)
}
user, err := u.config.APIRepository.User().UpdateUser(existingUser.ID, &repository.UpdateUserOpts{
user, err := u.config.APIRepository.User().UpdateUser(ctx.Request().Context(), userId, &repository.UpdateUserOpts{
Password: newPass,
})

View File

@@ -0,0 +1,63 @@
package proxy
import (
"context"
"time"
client "github.com/hatchet-dev/hatchet/pkg/client/v1"
"github.com/hatchet-dev/hatchet/pkg/config/server"
"github.com/hatchet-dev/hatchet/pkg/repository/postgres/dbsqlc"
"github.com/hatchet-dev/hatchet/pkg/repository/postgres/sqlchelpers"
)
type Proxy[in, out any] struct {
config *server.ServerConfig
method func(ctx context.Context, cli *client.GRPCClient, input *in) (*out, error)
}
func NewProxy[in, out any](config *server.ServerConfig, method func(ctx context.Context, cli *client.GRPCClient, input *in) (*out, error)) *Proxy[in, out] {
return &Proxy[in, out]{
config: config,
method: method,
}
}
func (p *Proxy[in, out]) Do(ctx context.Context, tenant *dbsqlc.Tenant, input *in) (*out, error) {
tenantId := sqlchelpers.UUIDToStr(tenant.ID)
expiresAt := time.Now().Add(5 * time.Minute).UTC()
// generate the API token for the proxy request
tok, err := p.config.Auth.JWTManager.GenerateTenantToken(ctx, tenantId, "proxy", true, &expiresAt)
if err != nil {
return nil, err
}
defer func() {
deleteCtx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
// delete the API token
err = p.config.APIRepository.APIToken().DeleteAPIToken(deleteCtx, tenantId, tok.TokenId)
if err != nil {
p.config.Logger.Error().Err(err).Msg("failed to delete API token")
}
}()
c, err := p.config.InternalClientFactory.NewGRPCClient(tok.Token)
if err != nil {
return nil, err
}
// call the client method
res, err := p.method(client.AuthContext(ctx, tok.Token), c, input)
if err != nil {
return nil, err
}
return res, nil
}

View File

@@ -0,0 +1,74 @@
package tasks
import (
"github.com/labstack/echo/v4"
"google.golang.org/protobuf/types/known/timestamppb"
"github.com/hatchet-dev/hatchet/api/v1/server/oas/gen"
"github.com/hatchet-dev/hatchet/internal/services/admin/contracts/v1"
"github.com/hatchet-dev/hatchet/pkg/repository/postgres/dbsqlc"
)
func (t *TasksService) V1TaskCancel(ctx echo.Context, request gen.V1TaskCancelRequestObject) (gen.V1TaskCancelResponseObject, error) {
tenant := ctx.Get("tenant").(*dbsqlc.Tenant)
var err error
grpcReq := &contracts.CancelTasksRequest{}
if request.Body.ExternalIds != nil {
externalIds := make([]string, 0)
for _, id := range *request.Body.ExternalIds {
externalIds = append(externalIds, id.String())
}
grpcReq.ExternalIds = externalIds
}
if request.Body.Filter != nil {
filter := &contracts.TasksFilter{
Since: timestamppb.New(request.Body.Filter.Since),
}
if request.Body.Filter.Until != nil {
filter.Until = timestamppb.New(*request.Body.Filter.Until)
}
if request.Body.Filter.Statuses != nil {
filter.Statuses = make([]string, len(*request.Body.Filter.Statuses))
for i, status := range *request.Body.Filter.Statuses {
filter.Statuses[i] = string(status)
}
}
if request.Body.Filter.WorkflowIds != nil {
filter.WorkflowIds = make([]string, len(*request.Body.Filter.WorkflowIds))
for i, id := range *request.Body.Filter.WorkflowIds {
filter.WorkflowIds[i] = id.String()
}
}
if request.Body.Filter.AdditionalMetadata != nil {
filter.AdditionalMetadata = make([]string, len(*request.Body.Filter.AdditionalMetadata))
copy(filter.AdditionalMetadata, *request.Body.Filter.AdditionalMetadata)
}
grpcReq.Filter = filter
}
_, err = t.proxyCancel.Do(
ctx.Request().Context(),
tenant,
grpcReq,
)
if err != nil {
return nil, err
}
return gen.V1TaskCancel200Response{}, nil
}

View File

@@ -0,0 +1,26 @@
package tasks
import (
"github.com/labstack/echo/v4"
"github.com/hatchet-dev/hatchet/api/v1/server/oas/gen"
"github.com/hatchet-dev/hatchet/pkg/repository/v1/sqlcv1"
transformers "github.com/hatchet-dev/hatchet/api/v1/server/oas/transformers/v1"
)
func (t *TasksService) V1TaskGet(ctx echo.Context, request gen.V1TaskGetRequestObject) (gen.V1TaskGetResponseObject, error) {
task := ctx.Get("task").(*sqlcv1.V1TasksOlap)
taskWithData, workflowRunExternalId, err := t.config.V1.OLAP().ReadTaskRunData(ctx.Request().Context(), task.TenantID, task.ID, task.InsertedAt)
if err != nil {
return nil, err
}
result := transformers.ToTask(taskWithData, workflowRunExternalId)
return gen.V1TaskGet200JSONResponse(
result,
), nil
}

View File

@@ -0,0 +1,51 @@
package tasks
import (
"github.com/google/uuid"
"github.com/jackc/pgx/v5/pgtype"
"github.com/hatchet-dev/hatchet/api/v1/server/oas/gen"
"github.com/hatchet-dev/hatchet/pkg/repository/postgres/dbsqlc"
"github.com/hatchet-dev/hatchet/pkg/repository/postgres/sqlchelpers"
v1 "github.com/hatchet-dev/hatchet/pkg/repository/v1"
"github.com/labstack/echo/v4"
transformers "github.com/hatchet-dev/hatchet/api/v1/server/oas/transformers/v1"
)
func (t *TasksService) V1TaskListStatusMetrics(ctx echo.Context, request gen.V1TaskListStatusMetricsRequestObject) (gen.V1TaskListStatusMetricsResponseObject, error) {
tenant := ctx.Get("tenant").(*dbsqlc.Tenant)
tenantId := sqlchelpers.UUIDToStr(tenant.ID)
var workflowIds []uuid.UUID
if request.Params.WorkflowIds != nil {
workflowIds = *request.Params.WorkflowIds
}
var parentTaskExternalId *pgtype.UUID
if request.Params.ParentTaskExternalId != nil {
uuidPtr := *request.Params.ParentTaskExternalId
uuidVal := sqlchelpers.UUIDFromStr(uuidPtr.String())
parentTaskExternalId = &uuidVal
}
metrics, err := t.config.V1.OLAP().ReadTaskRunMetrics(ctx.Request().Context(), tenantId, v1.ReadTaskRunMetricsOpts{
CreatedAfter: request.Params.Since,
WorkflowIds: workflowIds,
ParentTaskExternalID: parentTaskExternalId,
})
if err != nil {
return nil, err
}
result := transformers.ToTaskRunMetrics(&metrics)
// Search for api errors to see how we handle errors in other cases
return gen.V1TaskListStatusMetrics200JSONResponse(
result,
), nil
}

View File

@@ -0,0 +1,124 @@
package tasks
import (
"errors"
"time"
"github.com/jackc/pgx/v5"
"github.com/labstack/echo/v4"
"github.com/hatchet-dev/hatchet/api/v1/server/oas/apierrors"
"github.com/hatchet-dev/hatchet/api/v1/server/oas/gen"
"github.com/hatchet-dev/hatchet/pkg/repository/postgres/dbsqlc"
"github.com/hatchet-dev/hatchet/pkg/repository/postgres/sqlchelpers"
"github.com/hatchet-dev/hatchet/pkg/repository/v1/sqlcv1"
)
func (t *TasksService) V1TaskGetPointMetrics(ctx echo.Context, request gen.V1TaskGetPointMetricsRequestObject) (gen.V1TaskGetPointMetricsResponseObject, error) {
tenant := ctx.Get("tenant").(*dbsqlc.Tenant)
tenantId := sqlchelpers.UUIDToStr(tenant.ID)
// 24 hours ago, rounded to the nearest minute
lowerBound := time.Now().UTC().Add(-24 * time.Hour).Truncate(30 * time.Minute)
upperBound := time.Now().UTC()
if request.Params.CreatedAfter != nil {
lowerBound = request.Params.CreatedAfter.UTC()
}
if request.Params.FinishedBefore != nil {
upperBound = request.Params.FinishedBefore.UTC()
}
// determine a bucket interval based on the time range. If the time range is less than 1 hour, use 1 minute intervals.
// If the time range is less than 1 day, use 5 minute intervals. Otherwise, use 30 minute intervals.
var bucketInterval time.Duration
switch {
case upperBound.Sub(lowerBound) < 61*time.Minute:
bucketInterval = time.Minute
lowerBound = lowerBound.Truncate(time.Minute)
case upperBound.Sub(lowerBound) < 12*time.Hour:
bucketInterval = 5 * time.Minute
lowerBound = lowerBound.Truncate(5 * time.Minute)
case upperBound.Sub(lowerBound) < 48*time.Hour:
bucketInterval = 30 * time.Minute
lowerBound = lowerBound.Truncate(30 * time.Minute)
case upperBound.Sub(lowerBound) < 8*24*time.Hour:
bucketInterval = 8 * time.Hour
lowerBound = lowerBound.Truncate(8 * time.Hour)
default:
bucketInterval = 24 * time.Hour
lowerBound = lowerBound.Truncate(24 * time.Hour)
}
metrics, err := t.config.V1.OLAP().GetTaskPointMetrics(ctx.Request().Context(), tenantId, &lowerBound, &upperBound, bucketInterval)
if err != nil {
if errors.Is(err, pgx.ErrNoRows) {
return gen.V1TaskGetPointMetrics400JSONResponse(
apierrors.NewAPIErrors("workflow not found"),
), nil
}
return nil, err
}
// Fill missing minutes with 0 values
convertedMetrics := fillMissingMinutesWithZero(lowerBound, upperBound, convertToGenMetrics(metrics), bucketInterval)
return gen.V1TaskGetPointMetrics200JSONResponse{
Results: &convertedMetrics,
}, nil
}
type WorkflowRunEventsMetrics struct {
Results *[]gen.V1TaskPointMetric `json:"results,omitempty"`
}
func convertToGenMetrics(metrics []*sqlcv1.GetTaskPointMetricsRow) []gen.V1TaskPointMetric {
converted := make([]gen.V1TaskPointMetric, len(metrics))
for i, metric := range metrics {
if metric == nil || !metric.Bucket2.Valid {
continue
}
timeMinute := metric.Bucket2.Time.UTC()
converted[i] = gen.V1TaskPointMetric{
FAILED: int(metric.FailedCount),
SUCCEEDED: int(metric.CompletedCount),
Time: timeMinute,
}
}
return converted
}
// fillMissingMinutesWithZero fills in missing minutes between lowerBound and upperBound with 0 values.
func fillMissingMinutesWithZero(lowerBound, upperBound time.Time, metrics []gen.V1TaskPointMetric, bucketInterval time.Duration) []gen.V1TaskPointMetric {
result := []gen.V1TaskPointMetric{}
metricMap := make(map[time.Time]gen.V1TaskPointMetric)
for _, metric := range metrics {
if !metric.Time.IsZero() {
metricMap[(metric.Time).UTC()] = metric
}
}
for t := lowerBound; t.Before(upperBound) || t.Equal(upperBound); t = t.Add(bucketInterval) {
if metric, exists := metricMap[t]; exists {
result = append(result, metric)
} else {
timeCopy := t
result = append(result, gen.V1TaskPointMetric{
FAILED: int(0),
SUCCEEDED: int(0),
Time: timeCopy,
})
}
}
return result
}

View File

@@ -0,0 +1,38 @@
package tasks
import (
"github.com/jackc/pgx/v5/pgtype"
"github.com/labstack/echo/v4"
"github.com/hatchet-dev/hatchet/api/v1/server/oas/gen"
"github.com/hatchet-dev/hatchet/pkg/repository/postgres/sqlchelpers"
transformers "github.com/hatchet-dev/hatchet/api/v1/server/oas/transformers/v1"
)
func (t *TasksService) V1DagListTasks(ctx echo.Context, request gen.V1DagListTasksRequestObject) (gen.V1DagListTasksResponseObject, error) {
tenantId := request.Params.Tenant.String()
dagIds := request.Params.DagIds
pguuids := make([]pgtype.UUID, 0)
for _, dagId := range dagIds {
pguuids = append(pguuids, sqlchelpers.UUIDFromStr(dagId.String()))
}
tasks, taskIdToDagExternalId, err := t.config.V1.OLAP().ListTasksByDAGId(
ctx.Request().Context(),
tenantId,
pguuids,
)
if err != nil {
return nil, err
}
result := transformers.ToDagChildren(tasks, taskIdToDagExternalId)
// Search for api errors to see how we handle errors in other cases
return gen.V1DagListTasks200JSONResponse(
result,
), nil
}

View File

@@ -0,0 +1,30 @@
package tasks
import (
"github.com/labstack/echo/v4"
"github.com/hatchet-dev/hatchet/api/v1/server/oas/gen"
"github.com/hatchet-dev/hatchet/pkg/repository/postgres/dbsqlc"
"github.com/hatchet-dev/hatchet/pkg/repository/postgres/sqlchelpers"
"github.com/hatchet-dev/hatchet/pkg/repository/v1/sqlcv1"
transformers "github.com/hatchet-dev/hatchet/api/v1/server/oas/transformers/v1"
)
func (t *TasksService) V1TaskEventList(ctx echo.Context, request gen.V1TaskEventListRequestObject) (gen.V1TaskEventListResponseObject, error) {
tenant := ctx.Get("tenant").(*dbsqlc.Tenant)
tenantId := sqlchelpers.UUIDToStr(tenant.ID)
task := ctx.Get("task").(*sqlcv1.V1TasksOlap)
taskRunEvents, err := t.config.V1.OLAP().ListTaskRunEvents(ctx.Request().Context(), tenantId, task.ID, task.InsertedAt, *request.Params.Limit, *request.Params.Offset)
if err != nil {
return nil, err
}
result := transformers.ToTaskRunEventMany(taskRunEvents, sqlchelpers.UUIDToStr(task.ExternalID))
return gen.V1TaskEventList200JSONResponse(
result,
), nil
}

View File

@@ -0,0 +1,47 @@
package tasks
import (
"github.com/labstack/echo/v4"
"github.com/hatchet-dev/hatchet/api/v1/server/oas/gen"
"github.com/hatchet-dev/hatchet/pkg/repository/postgres/dbsqlc"
"github.com/hatchet-dev/hatchet/pkg/repository/postgres/sqlchelpers"
v1 "github.com/hatchet-dev/hatchet/pkg/repository/v1"
"github.com/hatchet-dev/hatchet/pkg/repository/v1/sqlcv1"
transformers "github.com/hatchet-dev/hatchet/api/v1/server/oas/transformers/v1"
)
func (t *TasksService) V1LogLineList(ctx echo.Context, request gen.V1LogLineListRequestObject) (gen.V1LogLineListResponseObject, error) {
tenant := ctx.Get("tenant").(*dbsqlc.Tenant)
tenantId := sqlchelpers.UUIDToStr(tenant.ID)
task := ctx.Get("task").(*sqlcv1.V1TasksOlap)
logLines, err := t.config.V1.Logs().ListLogLines(ctx.Request().Context(), tenantId, task.ID, task.InsertedAt, &v1.ListLogsOpts{})
if err != nil {
return nil, err
}
rows := make([]gen.V1LogLine, len(logLines))
for i, log := range logLines {
rows[i] = *transformers.ToV1LogLine(log)
}
// use the total rows and limit to calculate the total pages
totalPages := int64(1)
currPage := int64(1)
nextPage := int64(1)
return gen.V1LogLineList200JSONResponse(
gen.V1LogLineList{
Rows: &rows,
Pagination: &gen.PaginationResponse{
NumPages: &totalPages,
CurrentPage: &currPage,
NextPage: &nextPage,
},
},
), nil
}

View File

@@ -0,0 +1,74 @@
package tasks
import (
"github.com/labstack/echo/v4"
"google.golang.org/protobuf/types/known/timestamppb"
"github.com/hatchet-dev/hatchet/api/v1/server/oas/gen"
"github.com/hatchet-dev/hatchet/internal/services/admin/contracts/v1"
"github.com/hatchet-dev/hatchet/pkg/repository/postgres/dbsqlc"
)
func (t *TasksService) V1TaskReplay(ctx echo.Context, request gen.V1TaskReplayRequestObject) (gen.V1TaskReplayResponseObject, error) {
tenant := ctx.Get("tenant").(*dbsqlc.Tenant)
var err error
grpcReq := &contracts.ReplayTasksRequest{}
if request.Body.ExternalIds != nil {
externalIds := make([]string, 0)
for _, id := range *request.Body.ExternalIds {
externalIds = append(externalIds, id.String())
}
grpcReq.ExternalIds = externalIds
}
if request.Body.Filter != nil {
filter := &contracts.TasksFilter{
Since: timestamppb.New(request.Body.Filter.Since),
}
if request.Body.Filter.Until != nil {
filter.Until = timestamppb.New(*request.Body.Filter.Until)
}
if request.Body.Filter.Statuses != nil {
filter.Statuses = make([]string, len(*request.Body.Filter.Statuses))
for i, status := range *request.Body.Filter.Statuses {
filter.Statuses[i] = string(status)
}
}
if request.Body.Filter.WorkflowIds != nil {
filter.WorkflowIds = make([]string, len(*request.Body.Filter.WorkflowIds))
for i, id := range *request.Body.Filter.WorkflowIds {
filter.WorkflowIds[i] = id.String()
}
}
if request.Body.Filter.AdditionalMetadata != nil {
filter.AdditionalMetadata = make([]string, len(*request.Body.Filter.AdditionalMetadata))
copy(filter.AdditionalMetadata, *request.Body.Filter.AdditionalMetadata)
}
grpcReq.Filter = filter
}
_, err = t.proxyReplay.Do(
ctx.Request().Context(),
tenant,
grpcReq,
)
if err != nil {
return nil, err
}
return gen.V1TaskReplay200Response{}, nil
}

View File

@@ -0,0 +1,33 @@
package tasks
import (
"context"
"github.com/hatchet-dev/hatchet/api/v1/server/handlers/v1/proxy"
admincontracts "github.com/hatchet-dev/hatchet/internal/services/admin/contracts/v1"
"github.com/hatchet-dev/hatchet/pkg/config/server"
client "github.com/hatchet-dev/hatchet/pkg/client/v1"
)
type TasksService struct {
config *server.ServerConfig
proxyCancel *proxy.Proxy[admincontracts.CancelTasksRequest, admincontracts.CancelTasksResponse]
proxyReplay *proxy.Proxy[admincontracts.ReplayTasksRequest, admincontracts.ReplayTasksResponse]
}
func NewTasksService(config *server.ServerConfig) *TasksService {
proxyCancel := proxy.NewProxy(config, func(ctx context.Context, cli *client.GRPCClient, in *admincontracts.CancelTasksRequest) (*admincontracts.CancelTasksResponse, error) {
return cli.Admin().CancelTasks(ctx, in)
})
proxyReplay := proxy.NewProxy(config, func(ctx context.Context, cli *client.GRPCClient, in *admincontracts.ReplayTasksRequest) (*admincontracts.ReplayTasksResponse, error) {
return cli.Admin().ReplayTasks(ctx, in)
})
return &TasksService{
config: config,
proxyCancel: proxyCancel,
proxyReplay: proxyReplay,
}
}

View File

@@ -0,0 +1,92 @@
package workflowruns
import (
"context"
"github.com/google/uuid"
"github.com/jackc/pgx/v5/pgtype"
"github.com/labstack/echo/v4"
"github.com/hatchet-dev/hatchet/api/v1/server/oas/gen"
"github.com/hatchet-dev/hatchet/pkg/repository/postgres/dbsqlc"
"github.com/hatchet-dev/hatchet/pkg/repository/postgres/sqlchelpers"
v1 "github.com/hatchet-dev/hatchet/pkg/repository/v1"
transformers "github.com/hatchet-dev/hatchet/api/v1/server/oas/transformers/v1"
)
func (t *V1WorkflowRunsService) V1WorkflowRunGet(ctx echo.Context, request gen.V1WorkflowRunGetRequestObject) (gen.V1WorkflowRunGetResponseObject, error) {
tenant := ctx.Get("tenant").(*dbsqlc.Tenant)
tenantId := sqlchelpers.UUIDToStr(tenant.ID)
rawWorkflowRun := ctx.Get("v1-workflow-run").(*v1.V1WorkflowRunPopulator)
requestContext := ctx.Request().Context()
details, err := t.getWorkflowRunDetails(
requestContext,
tenantId,
rawWorkflowRun,
)
if err != nil {
return nil, err
}
// Search for api errors to see how we handle errors in other cases
return gen.V1WorkflowRunGet200JSONResponse(
*details,
), nil
}
func (t *V1WorkflowRunsService) getWorkflowRunDetails(
ctx context.Context,
tenantId string,
rawWorkflowRun *v1.V1WorkflowRunPopulator,
) (*gen.V1WorkflowRunDetails, error) {
workflowRun := rawWorkflowRun.WorkflowRun
taskMetadata := rawWorkflowRun.TaskMetadata
workflowRunId := workflowRun.ExternalID
taskRunEvents, err := t.config.V1.OLAP().ListTaskRunEventsByWorkflowRunId(
ctx,
tenantId,
workflowRunId,
)
if err != nil {
return nil, err
}
tasks, err := t.config.V1.OLAP().ListTasksByIdAndInsertedAt(
ctx,
tenantId,
taskMetadata,
)
if err != nil {
return nil, err
}
stepIdToTaskExternalId := make(map[pgtype.UUID]pgtype.UUID)
for _, task := range tasks {
stepIdToTaskExternalId[task.StepID] = task.ExternalID
}
workflowVersionId := uuid.MustParse(sqlchelpers.UUIDToStr(workflowRun.WorkflowVersionId))
shape, err := t.config.APIRepository.WorkflowRun().GetWorkflowRunShape(
ctx, workflowVersionId,
)
if err != nil {
return nil, err
}
result, err := transformers.ToWorkflowRunDetails(taskRunEvents, workflowRun, shape, tasks, stepIdToTaskExternalId)
if err != nil {
return nil, err
}
return &result, nil
}

View File

@@ -0,0 +1,37 @@
package workflowruns
import (
"github.com/labstack/echo/v4"
"github.com/hatchet-dev/hatchet/api/v1/server/oas/gen"
"github.com/hatchet-dev/hatchet/pkg/repository/postgres/dbsqlc"
"github.com/hatchet-dev/hatchet/pkg/repository/postgres/sqlchelpers"
v1 "github.com/hatchet-dev/hatchet/pkg/repository/v1"
transformers "github.com/hatchet-dev/hatchet/api/v1/server/oas/transformers/v1"
)
func (t *V1WorkflowRunsService) V1WorkflowRunTaskEventsList(ctx echo.Context, request gen.V1WorkflowRunTaskEventsListRequestObject) (gen.V1WorkflowRunTaskEventsListResponseObject, error) {
tenant := ctx.Get("tenant").(*dbsqlc.Tenant)
tenantId := sqlchelpers.UUIDToStr(tenant.ID)
rawWorkflowRun := ctx.Get("v1-workflow-run").(*v1.V1WorkflowRunPopulator)
workflowRun := rawWorkflowRun.WorkflowRun
taskRunEvents, err := t.config.V1.OLAP().ListTaskRunEventsByWorkflowRunId(
ctx.Request().Context(),
tenantId,
workflowRun.ExternalID,
)
if err != nil {
return nil, err
}
result := transformers.ToWorkflowRunTaskRunEventsMany(taskRunEvents)
// Search for api errors to see how we handle errors in other cases
return gen.V1WorkflowRunTaskEventsList200JSONResponse(
result,
), nil
}

View File

@@ -0,0 +1,281 @@
package workflowruns
import (
"strings"
"github.com/google/uuid"
"github.com/jackc/pgx/v5/pgtype"
"github.com/labstack/echo/v4"
"github.com/hatchet-dev/hatchet/api/v1/server/oas/gen"
"github.com/hatchet-dev/hatchet/pkg/repository/postgres/dbsqlc"
"github.com/hatchet-dev/hatchet/pkg/repository/postgres/sqlchelpers"
v1 "github.com/hatchet-dev/hatchet/pkg/repository/v1"
"github.com/hatchet-dev/hatchet/pkg/repository/v1/sqlcv1"
transformers "github.com/hatchet-dev/hatchet/api/v1/server/oas/transformers/v1"
)
func (t *V1WorkflowRunsService) WithDags(ctx echo.Context, request gen.V1WorkflowRunListRequestObject) (gen.V1WorkflowRunListResponseObject, error) {
tenant := ctx.Get("tenant").(*dbsqlc.Tenant)
tenantId := sqlchelpers.UUIDToStr(tenant.ID)
var (
statuses = []sqlcv1.V1ReadableStatusOlap{
sqlcv1.V1ReadableStatusOlapQUEUED,
sqlcv1.V1ReadableStatusOlapRUNNING,
sqlcv1.V1ReadableStatusOlapFAILED,
sqlcv1.V1ReadableStatusOlapCOMPLETED,
sqlcv1.V1ReadableStatusOlapCANCELLED,
}
since = request.Params.Since
workflowIds = []uuid.UUID{}
limit int64 = 50
offset int64
)
if request.Params.Statuses != nil {
if len(*request.Params.Statuses) > 0 {
statuses = []sqlcv1.V1ReadableStatusOlap{}
for _, status := range *request.Params.Statuses {
statuses = append(statuses, sqlcv1.V1ReadableStatusOlap(status))
}
}
}
if request.Params.Limit != nil {
limit = *request.Params.Limit
}
if request.Params.Offset != nil {
offset = *request.Params.Offset
}
if request.Params.WorkflowIds != nil {
workflowIds = *request.Params.WorkflowIds
}
opts := v1.ListWorkflowRunOpts{
CreatedAfter: since,
Statuses: statuses,
WorkflowIds: workflowIds,
Limit: limit,
Offset: offset,
}
additionalMetadataFilters := make(map[string]interface{})
if request.Params.AdditionalMetadata != nil {
for _, v := range *request.Params.AdditionalMetadata {
kv_pairs := strings.Split(v, ":")
if len(kv_pairs) == 2 {
additionalMetadataFilters[kv_pairs[0]] = kv_pairs[1]
}
}
opts.AdditionalMetadata = additionalMetadataFilters
}
if request.Params.Until != nil {
opts.FinishedBefore = request.Params.Until
}
if request.Params.ParentTaskExternalId != nil {
parentTaskExternalId := request.Params.ParentTaskExternalId.String()
id := sqlchelpers.UUIDFromStr(parentTaskExternalId)
opts.ParentTaskExternalId = &id
}
dags, total, err := t.config.V1.OLAP().ListWorkflowRuns(
ctx.Request().Context(),
tenantId,
opts,
)
if err != nil {
return nil, err
}
dagExternalIds := make([]pgtype.UUID, 0)
for _, dag := range dags {
if dag.Kind == sqlcv1.V1RunKindDAG {
dagExternalIds = append(dagExternalIds, dag.ExternalID)
}
}
tasks, taskIdToDagExternalId, err := t.config.V1.OLAP().ListTasksByDAGId(
ctx.Request().Context(),
tenantId,
dagExternalIds,
)
if err != nil {
return nil, err
}
pgWorkflowIds := make([]pgtype.UUID, 0)
for _, wf := range dags {
pgWorkflowIds = append(pgWorkflowIds, wf.WorkflowID)
}
workflowNames, err := t.config.V1.Workflows().ListWorkflowNamesByIds(
ctx.Request().Context(),
tenantId,
pgWorkflowIds,
)
if err != nil {
return nil, err
}
taskIdToWorkflowName := make(map[int64]string)
for _, task := range tasks {
if name, ok := workflowNames[task.WorkflowID]; ok {
taskIdToWorkflowName[task.ID] = name
}
}
parsedTasks := transformers.TaskRunDataRowToWorkflowRunsMany(tasks, taskIdToWorkflowName, total, limit, offset)
dagChildren := make(map[uuid.UUID][]gen.V1TaskSummary)
for _, task := range parsedTasks.Rows {
dagExternalId := taskIdToDagExternalId[int64(task.TaskId)]
existing, ok := dagChildren[dagExternalId]
if ok {
dagChildren[dagExternalId] = append(existing, task)
} else {
dagChildren[dagExternalId] = []gen.V1TaskSummary{task}
}
}
result := transformers.ToWorkflowRunMany(dags, dagChildren, workflowNames, total, limit, offset)
// Search for api errors to see how we handle errors in other cases
return gen.V1WorkflowRunList200JSONResponse(
result,
), nil
}
func (t *V1WorkflowRunsService) OnlyTasks(ctx echo.Context, request gen.V1WorkflowRunListRequestObject) (gen.V1WorkflowRunListResponseObject, error) {
tenant := ctx.Get("tenant").(*dbsqlc.Tenant)
tenantId := sqlchelpers.UUIDToStr(tenant.ID)
var (
statuses = []sqlcv1.V1ReadableStatusOlap{
sqlcv1.V1ReadableStatusOlapQUEUED,
sqlcv1.V1ReadableStatusOlapRUNNING,
sqlcv1.V1ReadableStatusOlapFAILED,
sqlcv1.V1ReadableStatusOlapCOMPLETED,
sqlcv1.V1ReadableStatusOlapCANCELLED,
}
since = request.Params.Since
workflowIds = []uuid.UUID{}
limit int64 = 50
offset int64
)
if request.Params.Statuses != nil {
if len(*request.Params.Statuses) > 0 {
statuses = []sqlcv1.V1ReadableStatusOlap{}
for _, status := range *request.Params.Statuses {
statuses = append(statuses, sqlcv1.V1ReadableStatusOlap(status))
}
}
}
if request.Params.Limit != nil {
limit = *request.Params.Limit
}
if request.Params.Offset != nil {
offset = *request.Params.Offset
}
if request.Params.WorkflowIds != nil {
workflowIds = *request.Params.WorkflowIds
}
opts := v1.ListTaskRunOpts{
CreatedAfter: since,
Statuses: statuses,
WorkflowIds: workflowIds,
Limit: limit,
Offset: offset,
WorkerId: request.Params.WorkerId,
}
additionalMetadataFilters := make(map[string]interface{})
if request.Params.AdditionalMetadata != nil {
for _, v := range *request.Params.AdditionalMetadata {
kv_pairs := strings.Split(v, ":")
if len(kv_pairs) == 2 {
additionalMetadataFilters[kv_pairs[0]] = kv_pairs[1]
}
}
opts.AdditionalMetadata = additionalMetadataFilters
}
if request.Params.Until != nil {
opts.FinishedBefore = request.Params.Until
}
tasks, total, err := t.config.V1.OLAP().ListTasks(
ctx.Request().Context(),
tenantId,
opts,
)
if err != nil {
return nil, err
}
taskIdToWorkflowName := make(map[int64]string)
result := transformers.TaskRunDataRowToWorkflowRunsMany(tasks, taskIdToWorkflowName, total, limit, offset)
// Search for api errors to see how we handle errors in other cases
return gen.V1WorkflowRunList200JSONResponse(
result,
), nil
}
func (t *V1WorkflowRunsService) V1WorkflowRunList(ctx echo.Context, request gen.V1WorkflowRunListRequestObject) (gen.V1WorkflowRunListResponseObject, error) {
if request.Params.OnlyTasks {
return t.OnlyTasks(ctx, request)
} else {
return t.WithDags(ctx, request)
}
}
func (t *V1WorkflowRunsService) V1WorkflowRunDisplayNamesList(ctx echo.Context, request gen.V1WorkflowRunDisplayNamesListRequestObject) (gen.V1WorkflowRunDisplayNamesListResponseObject, error) {
tenant := ctx.Get("tenant").(*dbsqlc.Tenant)
externalIds := make([]pgtype.UUID, len(request.Params.ExternalIds))
for i, id := range request.Params.ExternalIds {
externalIds[i] = sqlchelpers.UUIDFromStr(id.String())
}
displayNames, err := t.config.V1.OLAP().ListWorkflowRunDisplayNames(
ctx.Request().Context(),
tenant.ID,
externalIds,
)
if err != nil {
return nil, err
}
result := transformers.ToWorkflowRunDisplayNamesList(displayNames)
return gen.V1WorkflowRunDisplayNamesList200JSONResponse(
result,
), nil
}

View File

@@ -0,0 +1,27 @@
package workflowruns
import (
"context"
"github.com/hatchet-dev/hatchet/api/v1/server/handlers/v1/proxy"
admincontracts "github.com/hatchet-dev/hatchet/internal/services/admin/contracts/v1"
"github.com/hatchet-dev/hatchet/pkg/config/server"
client "github.com/hatchet-dev/hatchet/pkg/client/v1"
)
type V1WorkflowRunsService struct {
config *server.ServerConfig
proxyTrigger *proxy.Proxy[admincontracts.TriggerWorkflowRunRequest, admincontracts.TriggerWorkflowRunResponse]
}
func NewV1WorkflowRunsService(config *server.ServerConfig) *V1WorkflowRunsService {
proxyTrigger := proxy.NewProxy(config, func(ctx context.Context, cli *client.GRPCClient, in *admincontracts.TriggerWorkflowRunRequest) (*admincontracts.TriggerWorkflowRunResponse, error) {
return cli.Admin().TriggerWorkflowRun(ctx, in)
})
return &V1WorkflowRunsService{
config: config,
proxyTrigger: proxyTrigger,
}
}

View File

@@ -0,0 +1,118 @@
package workflowruns
import (
"encoding/json"
"errors"
"fmt"
"time"
"github.com/jackc/pgx/v5"
"github.com/labstack/echo/v4"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
"github.com/hatchet-dev/hatchet/api/v1/server/oas/apierrors"
"github.com/hatchet-dev/hatchet/api/v1/server/oas/gen"
"github.com/hatchet-dev/hatchet/internal/services/admin/contracts/v1"
"github.com/hatchet-dev/hatchet/pkg/repository/postgres/dbsqlc"
"github.com/hatchet-dev/hatchet/pkg/repository/postgres/sqlchelpers"
v1 "github.com/hatchet-dev/hatchet/pkg/repository/v1"
)
func (t *V1WorkflowRunsService) V1WorkflowRunCreate(ctx echo.Context, request gen.V1WorkflowRunCreateRequestObject) (gen.V1WorkflowRunCreateResponseObject, error) {
tenant := ctx.Get("tenant").(*dbsqlc.Tenant)
tenantId := sqlchelpers.UUIDToStr(tenant.ID)
// make sure input can be marshalled and unmarshalled to input type
inputBytes, err := json.Marshal(request.Body.Input)
if err != nil {
return gen.V1WorkflowRunCreate400JSONResponse(
apierrors.NewAPIErrors("Invalid input"),
), nil
}
var additionalMetadataBytes []byte
if request.Body.AdditionalMetadata != nil {
additionalMetadataBytes, err = json.Marshal(request.Body.AdditionalMetadata)
if err != nil {
return gen.V1WorkflowRunCreate400JSONResponse(
apierrors.NewAPIErrors("Invalid additional metadata"),
), nil
}
}
grpcReq := &contracts.TriggerWorkflowRunRequest{
WorkflowName: request.Body.WorkflowName,
Input: inputBytes,
AdditionalMetadata: additionalMetadataBytes,
}
resp, err := t.proxyTrigger.Do(
ctx.Request().Context(),
tenant,
grpcReq,
)
if err != nil {
if e, ok := status.FromError(err); ok {
switch e.Code() { // nolint: gocritic
case codes.InvalidArgument:
return gen.V1WorkflowRunCreate400JSONResponse(
apierrors.NewAPIErrors(e.Message()),
), nil
}
}
return nil, err
}
// loop for workflow to be created in the OLAP database
var rawWorkflowRun *v1.V1WorkflowRunPopulator
retries := 0
for retries < 10 {
rawWorkflowRun, err = t.config.V1.OLAP().ReadWorkflowRun(
ctx.Request().Context(),
sqlchelpers.UUIDFromStr(resp.ExternalId),
)
if err != nil && !errors.Is(err, pgx.ErrNoRows) {
return nil, err
}
if err != nil && errors.Is(err, pgx.ErrNoRows) {
retries++
time.Sleep(1 * time.Second)
continue
}
break
}
if rawWorkflowRun == nil || rawWorkflowRun.WorkflowRun == nil {
return nil, fmt.Errorf("rawWorkflowRun not populated, we are likely seeing high latency in creating tasks")
}
if sqlchelpers.UUIDToStr(rawWorkflowRun.WorkflowRun.TenantID) != tenantId {
return nil, fmt.Errorf("tenantId mismatch in the triggered workflow run")
}
details, err := t.getWorkflowRunDetails(
ctx.Request().Context(),
tenantId,
rawWorkflowRun,
)
if err != nil {
return nil, err
}
// Search for api errors to see how we handle errors in other cases
return gen.V1WorkflowRunCreate200JSONResponse(
*details,
), nil
}

View File

@@ -10,11 +10,13 @@ import (
"github.com/hatchet-dev/hatchet/api/v1/server/oas/transformers"
"github.com/hatchet-dev/hatchet/pkg/random"
"github.com/hatchet-dev/hatchet/pkg/repository"
"github.com/hatchet-dev/hatchet/pkg/repository/prisma/db"
"github.com/hatchet-dev/hatchet/pkg/repository/postgres/dbsqlc"
"github.com/hatchet-dev/hatchet/pkg/repository/postgres/sqlchelpers"
)
func (i *WebhookWorkersService) WebhookCreate(ctx echo.Context, request gen.WebhookCreateRequestObject) (gen.WebhookCreateResponseObject, error) {
tenant := ctx.Get("tenant").(*db.TenantModel)
tenant := ctx.Get("tenant").(*dbsqlc.Tenant)
tenantId := sqlchelpers.UUIDToStr(tenant.ID)
var secret string
if request.Body.Secret == nil {
@@ -27,13 +29,13 @@ func (i *WebhookWorkersService) WebhookCreate(ctx echo.Context, request gen.Webh
secret = *request.Body.Secret
}
encSecret, err := i.config.Encryption.EncryptString(secret, tenant.ID)
encSecret, err := i.config.Encryption.EncryptString(secret, tenantId)
if err != nil {
return nil, err
}
ww, err := i.config.EngineRepository.WebhookWorker().CreateWebhookWorker(ctx.Request().Context(), &repository.CreateWebhookWorkerOpts{
TenantId: tenant.ID,
TenantId: tenantId,
Name: request.Body.Name,
URL: request.Body.Url,
Secret: encSecret,

View File

@@ -4,14 +4,16 @@ import (
"github.com/labstack/echo/v4"
"github.com/hatchet-dev/hatchet/api/v1/server/oas/gen"
"github.com/hatchet-dev/hatchet/pkg/repository/prisma/db"
"github.com/hatchet-dev/hatchet/pkg/repository/postgres/dbsqlc"
"github.com/hatchet-dev/hatchet/pkg/repository/postgres/sqlchelpers"
)
func (i *WebhookWorkersService) WebhookDelete(ctx echo.Context, request gen.WebhookDeleteRequestObject) (gen.WebhookDeleteResponseObject, error) {
tenant := ctx.Get("tenant").(*db.TenantModel)
webhook := ctx.Get("webhook").(*db.WebhookWorkerModel)
tenant := ctx.Get("tenant").(*dbsqlc.Tenant)
tenantId := sqlchelpers.UUIDToStr(tenant.ID)
webhook := ctx.Get("webhook").(*dbsqlc.WebhookWorker)
err := i.config.EngineRepository.WebhookWorker().SoftDeleteWebhookWorker(ctx.Request().Context(), webhook.ID, tenant.ID)
err := i.config.EngineRepository.WebhookWorker().SoftDeleteWebhookWorker(ctx.Request().Context(), sqlchelpers.UUIDToStr(webhook.ID), tenantId)
if err != nil {
return nil, err
}

View File

@@ -7,13 +7,15 @@ import (
"github.com/hatchet-dev/hatchet/api/v1/server/oas/gen"
"github.com/hatchet-dev/hatchet/api/v1/server/oas/transformers"
"github.com/hatchet-dev/hatchet/pkg/repository/prisma/db"
"github.com/hatchet-dev/hatchet/pkg/repository/postgres/dbsqlc"
"github.com/hatchet-dev/hatchet/pkg/repository/postgres/sqlchelpers"
)
func (i *WebhookWorkersService) WebhookList(ctx echo.Context, request gen.WebhookListRequestObject) (gen.WebhookListResponseObject, error) {
tenant := ctx.Get("tenant").(*db.TenantModel)
tenant := ctx.Get("tenant").(*dbsqlc.Tenant)
tenantId := sqlchelpers.UUIDToStr(tenant.ID)
webhooks, err := i.config.EngineRepository.WebhookWorker().ListActiveWebhookWorkers(context.Background(), tenant.ID)
webhooks, err := i.config.EngineRepository.WebhookWorker().ListActiveWebhookWorkers(context.Background(), tenantId)
if err != nil {
return nil, err

View File

@@ -1,15 +1,31 @@
package workers
import (
"fmt"
"github.com/labstack/echo/v4"
"github.com/hatchet-dev/hatchet/api/v1/server/oas/gen"
"github.com/hatchet-dev/hatchet/api/v1/server/oas/transformers"
"github.com/hatchet-dev/hatchet/pkg/repository/prisma/dbsqlc"
"github.com/hatchet-dev/hatchet/pkg/repository/prisma/sqlchelpers"
transformersv1 "github.com/hatchet-dev/hatchet/api/v1/server/oas/transformers/v1"
"github.com/hatchet-dev/hatchet/pkg/repository/postgres/dbsqlc"
"github.com/hatchet-dev/hatchet/pkg/repository/postgres/sqlchelpers"
)
func (t *WorkerService) WorkerGet(ctx echo.Context, request gen.WorkerGetRequestObject) (gen.WorkerGetResponseObject, error) {
tenant := ctx.Get("tenant").(*dbsqlc.Tenant)
switch tenant.Version {
case dbsqlc.TenantMajorEngineVersionV0:
return t.workerGetV0(ctx, tenant, request)
case dbsqlc.TenantMajorEngineVersionV1:
return t.workerGetV1(ctx, tenant, request)
default:
return nil, fmt.Errorf("unsupported tenant version: %s", string(tenant.Version))
}
}
func (t *WorkerService) workerGetV0(ctx echo.Context, tenant *dbsqlc.Tenant, request gen.WorkerGetRequestObject) (gen.WorkerGetResponseObject, error) {
worker := ctx.Get("worker").(*dbsqlc.GetWorkerByIdRow)
slotState, recent, err := t.config.APIRepository.Worker().ListWorkerState(
@@ -63,3 +79,64 @@ func (t *WorkerService) WorkerGet(ctx echo.Context, request gen.WorkerGetRequest
return gen.WorkerGet200JSONResponse(workerResp), nil
}
func (t *WorkerService) workerGetV1(ctx echo.Context, tenant *dbsqlc.Tenant, request gen.WorkerGetRequestObject) (gen.WorkerGetResponseObject, error) {
workerV0 := ctx.Get("worker").(*dbsqlc.GetWorkerByIdRow)
worker, err := t.config.V1.Workers().GetWorkerById(sqlchelpers.UUIDToStr(workerV0.Worker.ID))
if err != nil {
return nil, err
}
slotState, recent, err := t.config.V1.Workers().ListWorkerState(
sqlchelpers.UUIDToStr(worker.Worker.TenantId),
sqlchelpers.UUIDToStr(worker.Worker.ID),
int(worker.Worker.MaxRuns),
)
if err != nil {
return nil, err
}
actions, err := t.config.APIRepository.Worker().GetWorkerActionsByWorkerId(
sqlchelpers.UUIDToStr(worker.Worker.TenantId),
sqlchelpers.UUIDToStr(worker.Worker.ID),
)
if err != nil {
return nil, err
}
respStepRuns := make([]gen.RecentStepRuns, len(recent))
for i := range recent {
genStepRun, err := transformers.ToRecentStepRun(recent[i])
if err != nil {
return nil, err
}
respStepRuns[i] = *genStepRun
}
slots := int(worker.RemainingSlots)
workerResp := *transformersv1.ToWorkerSqlc(&worker.Worker, &slots, &worker.WebhookUrl.String, actions)
workerResp.RecentStepRuns = &respStepRuns
workerResp.Slots = transformersv1.ToSlotState(slotState, slots)
affinity, err := t.config.APIRepository.Worker().ListWorkerLabels(
sqlchelpers.UUIDToStr(worker.Worker.TenantId),
sqlchelpers.UUIDToStr(worker.Worker.ID),
)
if err != nil {
return nil, err
}
workerResp.Labels = transformers.ToWorkerLabels(affinity)
return gen.WorkerGet200JSONResponse(workerResp), nil
}

View File

@@ -1,22 +1,38 @@
package workers
import (
"fmt"
"time"
"github.com/labstack/echo/v4"
"github.com/hatchet-dev/hatchet/api/v1/server/oas/gen"
"github.com/hatchet-dev/hatchet/api/v1/server/oas/transformers"
transformersv1 "github.com/hatchet-dev/hatchet/api/v1/server/oas/transformers/v1"
"github.com/hatchet-dev/hatchet/pkg/repository"
"github.com/hatchet-dev/hatchet/pkg/repository/prisma/db"
"github.com/hatchet-dev/hatchet/pkg/repository/postgres/dbsqlc"
"github.com/hatchet-dev/hatchet/pkg/repository/postgres/sqlchelpers"
)
func (t *WorkerService) WorkerList(ctx echo.Context, request gen.WorkerListRequestObject) (gen.WorkerListResponseObject, error) {
tenant := ctx.Get("tenant").(*db.TenantModel)
tenant := ctx.Get("tenant").(*dbsqlc.Tenant)
switch tenant.Version {
case dbsqlc.TenantMajorEngineVersionV0:
return t.workerListV0(ctx, tenant, request)
case dbsqlc.TenantMajorEngineVersionV1:
return t.workerListV1(ctx, tenant, request)
default:
return nil, fmt.Errorf("unsupported tenant version: %s", string(tenant.Version))
}
}
func (t *WorkerService) workerListV0(ctx echo.Context, tenant *dbsqlc.Tenant, request gen.WorkerListRequestObject) (gen.WorkerListResponseObject, error) {
tenantId := sqlchelpers.UUIDToStr(tenant.ID)
sixSecAgo := time.Now().Add(-24 * time.Hour)
workers, err := t.config.APIRepository.Worker().ListWorkers(tenant.ID, &repository.ListWorkersOpts{
workers, err := t.config.APIRepository.Worker().ListWorkers(tenantId, &repository.ListWorkersOpts{
LastHeartbeatAfter: &sixSecAgo,
})
@@ -39,3 +55,32 @@ func (t *WorkerService) WorkerList(ctx echo.Context, request gen.WorkerListReque
},
), nil
}
func (t *WorkerService) workerListV1(ctx echo.Context, tenant *dbsqlc.Tenant, request gen.WorkerListRequestObject) (gen.WorkerListResponseObject, error) {
tenantId := sqlchelpers.UUIDToStr(tenant.ID)
sixSecAgo := time.Now().Add(-24 * time.Hour)
workers, err := t.config.V1.Workers().ListWorkers(tenantId, &repository.ListWorkersOpts{
LastHeartbeatAfter: &sixSecAgo,
})
if err != nil {
return nil, err
}
rows := make([]gen.Worker, len(workers))
for i, worker := range workers {
workerCp := worker
slots := int(worker.RemainingSlots)
rows[i] = *transformersv1.ToWorkerSqlc(&workerCp.Worker, &slots, &workerCp.WebhookUrl.String, nil)
}
return gen.WorkerList200JSONResponse(
gen.WorkerList{
Rows: &rows,
},
), nil
}

View File

@@ -6,8 +6,8 @@ import (
"github.com/hatchet-dev/hatchet/api/v1/server/oas/gen"
"github.com/hatchet-dev/hatchet/api/v1/server/oas/transformers"
"github.com/hatchet-dev/hatchet/pkg/repository"
"github.com/hatchet-dev/hatchet/pkg/repository/prisma/dbsqlc"
"github.com/hatchet-dev/hatchet/pkg/repository/prisma/sqlchelpers"
"github.com/hatchet-dev/hatchet/pkg/repository/postgres/dbsqlc"
"github.com/hatchet-dev/hatchet/pkg/repository/postgres/sqlchelpers"
)
func (t *WorkerService) WorkerUpdate(ctx echo.Context, request gen.WorkerUpdateRequestObject) (gen.WorkerUpdateResponseObject, error) {

View File

@@ -12,12 +12,13 @@ import (
"github.com/hatchet-dev/hatchet/internal/msgqueue"
"github.com/hatchet-dev/hatchet/internal/services/shared/tasktypes"
"github.com/hatchet-dev/hatchet/pkg/repository"
"github.com/hatchet-dev/hatchet/pkg/repository/prisma/db"
"github.com/hatchet-dev/hatchet/pkg/repository/prisma/sqlchelpers"
"github.com/hatchet-dev/hatchet/pkg/repository/postgres/dbsqlc"
"github.com/hatchet-dev/hatchet/pkg/repository/postgres/sqlchelpers"
)
func (t *WorkflowRunsService) WorkflowRunUpdateReplay(ctx echo.Context, request gen.WorkflowRunUpdateReplayRequestObject) (gen.WorkflowRunUpdateReplayResponseObject, error) {
tenant := ctx.Get("tenant").(*db.TenantModel)
tenant := ctx.Get("tenant").(*dbsqlc.Tenant)
tenantId := sqlchelpers.UUIDToStr(tenant.ID)
workflowRunIds := make([]string, len(request.Body.WorkflowRunIds))
@@ -28,7 +29,7 @@ func (t *WorkflowRunsService) WorkflowRunUpdateReplay(ctx echo.Context, request
limit := 500
// make sure all workflow runs belong to the tenant
filteredWorkflowRuns, err := t.config.EngineRepository.WorkflowRun().ListWorkflowRuns(ctx.Request().Context(), tenant.ID, &repository.ListWorkflowRunsOpts{
filteredWorkflowRuns, err := t.config.EngineRepository.WorkflowRun().ListWorkflowRuns(ctx.Request().Context(), tenantId, &repository.ListWorkflowRunsOpts{
Ids: workflowRunIds,
Limit: &limit,
})
@@ -44,7 +45,7 @@ func (t *WorkflowRunsService) WorkflowRunUpdateReplay(ctx echo.Context, request
err = t.config.MessageQueue.AddMessage(
ctx.Request().Context(),
msgqueue.WORKFLOW_PROCESSING_QUEUE,
tasktypes.WorkflowRunReplayToTask(tenant.ID, sqlchelpers.UUIDToStr(filteredWorkflowRuns.Rows[i].WorkflowRun.ID)),
tasktypes.WorkflowRunReplayToTask(tenantId, sqlchelpers.UUIDToStr(filteredWorkflowRuns.Rows[i].WorkflowRun.ID)),
)
if err != nil {
@@ -59,7 +60,7 @@ func (t *WorkflowRunsService) WorkflowRunUpdateReplay(ctx echo.Context, request
dbCtx, cancel := context.WithTimeout(ctx.Request().Context(), 60*time.Second)
defer cancel()
newWorkflowRuns, err := t.config.APIRepository.WorkflowRun().ListWorkflowRuns(dbCtx, tenant.ID, &repository.ListWorkflowRunsOpts{
newWorkflowRuns, err := t.config.APIRepository.WorkflowRun().ListWorkflowRuns(dbCtx, tenantId, &repository.ListWorkflowRunsOpts{
Ids: workflowRunIds,
Limit: &limit,
})

Some files were not shown because too many files have changed in this diff Show More