mirror of
https://github.com/mentos1386/zdravko.git
synced 2024-11-21 23:33:34 +00:00
Compare commits
5 commits
e317112a34
...
bf384166ad
Author | SHA1 | Date | |
---|---|---|---|
bf384166ad | |||
813c76fc3e | |||
315b7c1381 | |||
034f530923 | |||
b8c37cfd3c |
25 changed files with 298 additions and 141 deletions
|
@ -17,9 +17,9 @@ primary_region = 'waw'
|
|||
ROOT_URL = 'https://zdravko.mnts.dev'
|
||||
TEMPORAL_SERVER_HOST = 'server.process.zdravko.internal:7233'
|
||||
|
||||
TEMPORAL_DATABASE_PATH = '/data/temporal-10.db'
|
||||
SQLITE_DATABASE_PATH = '/data/zdravko-10.db'
|
||||
KEYVALUE_DATABASE_PATH = '/data/zdravko_kv-10.db'
|
||||
TEMPORAL_DATABASE_PATH = '/data/temporal-11.db'
|
||||
SQLITE_DATABASE_PATH = '/data/zdravko-11.db'
|
||||
KEYVALUE_DATABASE_PATH = '/data/zdravko_kv-11.db'
|
||||
|
||||
[processes]
|
||||
server = '--temporal --server'
|
||||
|
|
28
internal/server/activities/add_target_history.go
Normal file
28
internal/server/activities/add_target_history.go
Normal file
|
@ -0,0 +1,28 @@
|
|||
package activities
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/mentos1386/zdravko/database/models"
|
||||
"github.com/mentos1386/zdravko/internal/server/services"
|
||||
"github.com/mentos1386/zdravko/internal/temporal"
|
||||
)
|
||||
|
||||
func (a *Activities) AddTargetHistory(ctx context.Context, param temporal.ActivityAddTargetHistoryParam) (*temporal.ActivityAddTargetHistoryResult, error) {
|
||||
|
||||
status := models.TargetStatusUnknown
|
||||
if param.Status == temporal.AddTargetHistoryStatusSuccess {
|
||||
status = models.TargetStatusSuccess
|
||||
}
|
||||
if param.Status == temporal.AddTargetHistoryStatusFailure {
|
||||
status = models.TargetStatusFailure
|
||||
}
|
||||
|
||||
err := services.AddHistoryForTarget(ctx, a.db, &models.TargetHistory{
|
||||
TargetId: param.Target.Id,
|
||||
Status: status,
|
||||
Note: param.Note,
|
||||
})
|
||||
|
||||
return &temporal.ActivityAddTargetHistoryResult{}, err
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
package activities
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/mentos1386/zdravko/internal/temporal"
|
||||
)
|
||||
|
||||
func (a *Activities) ProcessCheckOutcome(ctx context.Context, param temporal.ActivityProcessCheckOutcomeParam) (*temporal.ActivityProcessCheckOutcomeResult, error) {
|
||||
return nil, nil
|
||||
}
|
|
@ -4,10 +4,10 @@ import (
|
|||
"context"
|
||||
|
||||
"github.com/dop251/goja"
|
||||
"github.com/mentos1386/zdravko/database/models"
|
||||
"github.com/mentos1386/zdravko/internal/server/services"
|
||||
"github.com/mentos1386/zdravko/internal/temporal"
|
||||
"github.com/mentos1386/zdravko/pkg/script"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
func (a *Activities) TargetsFilter(ctx context.Context, param temporal.ActivityTargetsFilterParam) (*temporal.ActivityTargetsFilterResult, error) {
|
||||
|
@ -17,22 +17,53 @@ func (a *Activities) TargetsFilter(ctx context.Context, param temporal.ActivityT
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
filteredTargets := make([]*models.Target, 0)
|
||||
filteredTargets := make([]*temporal.Target, 0)
|
||||
|
||||
program, err := goja.Compile("filter", script.UnescapeString(param.Filter), false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, target := range allTargets {
|
||||
vm := goja.New()
|
||||
vm.SetFieldNameMapper(goja.UncapFieldNameMapper())
|
||||
|
||||
err = vm.Set("target", target)
|
||||
var metadata map[string]interface{}
|
||||
err := yaml.Unmarshal([]byte(target.Metadata), &metadata)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
value, err := vm.RunString(script.UnescapeString(param.Filter))
|
||||
a.logger.Info("TargetsFilter", "target", target)
|
||||
|
||||
targetWithMedatada := &struct {
|
||||
Id string
|
||||
Name string
|
||||
Group string
|
||||
Metadata map[string]interface{}
|
||||
}{
|
||||
Id: target.Id,
|
||||
Name: target.Name,
|
||||
Group: target.Group,
|
||||
Metadata: metadata,
|
||||
}
|
||||
|
||||
err = vm.Set("target", targetWithMedatada)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
value, err := vm.RunProgram(program)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if value.Export().(bool) {
|
||||
filteredTargets = append(filteredTargets, target)
|
||||
filteredTargets = append(filteredTargets, &temporal.Target{
|
||||
Id: target.Id,
|
||||
Name: target.Name,
|
||||
Group: target.Group,
|
||||
Metadata: target.Metadata,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ import (
|
|||
jwtInternal "github.com/mentos1386/zdravko/pkg/jwt"
|
||||
)
|
||||
|
||||
const sessionName = "zdravko-hey"
|
||||
const authenticationSessionName = "zdravko-hey"
|
||||
|
||||
type AuthenticatedPrincipal struct {
|
||||
User *AuthenticatedUser
|
||||
|
@ -48,7 +48,7 @@ func GetUser(ctx context.Context) *AuthenticatedUser {
|
|||
}
|
||||
|
||||
func (h *BaseHandler) AuthenticateRequestWithCookies(r *http.Request) (*AuthenticatedUser, error) {
|
||||
session, err := h.store.Get(r, sessionName)
|
||||
session, err := h.store.Get(r, authenticationSessionName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -114,7 +114,7 @@ func (h *BaseHandler) AuthenticateRequestWithToken(r *http.Request) (*Authentica
|
|||
}
|
||||
|
||||
func (h *BaseHandler) SetAuthenticatedUserForRequest(w http.ResponseWriter, r *http.Request, user *AuthenticatedUser) error {
|
||||
session, err := h.store.Get(r, sessionName)
|
||||
session, err := h.store.Get(r, authenticationSessionName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -124,24 +124,16 @@ func (h *BaseHandler) SetAuthenticatedUserForRequest(w http.ResponseWriter, r *h
|
|||
session.Values["oauth2_refresh_token"] = user.OAuth2RefreshToken
|
||||
session.Values["oauth2_token_type"] = user.OAuth2TokenType
|
||||
session.Values["oauth2_expiry"] = user.OAuth2Expiry.Format(time.RFC3339)
|
||||
err = h.store.Save(r, w, session)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
return h.store.Save(r, w, session)
|
||||
}
|
||||
|
||||
func (h *BaseHandler) ClearAuthenticatedUserForRequest(w http.ResponseWriter, r *http.Request) error {
|
||||
session, err := h.store.Get(r, sessionName)
|
||||
session, err := h.store.Get(r, authenticationSessionName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
session.Options.MaxAge = -1
|
||||
err = h.store.Save(r, w, session)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
return h.store.Save(r, w, session)
|
||||
}
|
||||
|
||||
type AuthenticatedHandler func(http.ResponseWriter, *http.Request, *AuthenticatedPrincipal)
|
||||
|
@ -159,7 +151,7 @@ func (h *BaseHandler) Authenticated(next echo.HandlerFunc) echo.HandlerFunc {
|
|||
if user.OAuth2Expiry.Before(time.Now()) {
|
||||
user, err = h.RefreshToken(c.Response(), c.Request(), user)
|
||||
if err != nil {
|
||||
return c.Redirect(http.StatusTemporaryRedirect, "/oauth2/login")
|
||||
return c.Redirect(http.StatusTemporaryRedirect, "/oauth2/login?redirect="+c.Request().URL.Path)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -173,6 +165,6 @@ func (h *BaseHandler) Authenticated(next echo.HandlerFunc) echo.HandlerFunc {
|
|||
return next(cc)
|
||||
}
|
||||
|
||||
return c.Redirect(http.StatusTemporaryRedirect, "/oauth2/login")
|
||||
return c.Redirect(http.StatusTemporaryRedirect, "/oauth2/login?redirect="+c.Request().URL.Path)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -85,7 +85,7 @@ filter: |
|
|||
|
||||
target: |
|
||||
kind: Http
|
||||
tags:
|
||||
labels:
|
||||
production: "true"
|
||||
spec:
|
||||
url: "https://test.k6.io"
|
||||
|
|
|
@ -19,6 +19,45 @@ import (
|
|||
"golang.org/x/oauth2"
|
||||
)
|
||||
|
||||
const oauth2RedirectSessionName = "zdravko-hey-oauth2"
|
||||
|
||||
func (h *BaseHandler) setOAuth2Redirect(c echo.Context, redirect string) error {
|
||||
w := c.Response()
|
||||
r := c.Request()
|
||||
|
||||
session, err := h.store.Get(r, oauth2RedirectSessionName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
session.Values["redirect"] = redirect
|
||||
return h.store.Save(r, w, session)
|
||||
}
|
||||
|
||||
func (h *BaseHandler) getOAuth2Redirect(c echo.Context) (string, error) {
|
||||
r := c.Request()
|
||||
|
||||
session, err := h.store.Get(r, oauth2RedirectSessionName)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if session.IsNew {
|
||||
return "", nil
|
||||
}
|
||||
return session.Values["redirect"].(string), nil
|
||||
}
|
||||
|
||||
func (h *BaseHandler) clearOAuth2Redirect(c echo.Context) error {
|
||||
w := c.Response()
|
||||
r := c.Request()
|
||||
|
||||
session, err := h.store.Get(r, oauth2RedirectSessionName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
session.Options.MaxAge = -1
|
||||
return h.store.Save(r, w, session)
|
||||
}
|
||||
|
||||
type UserInfo struct {
|
||||
Id int `json:"id"` // FIXME: This might not always be int?
|
||||
Sub string `json:"sub"`
|
||||
|
@ -97,6 +136,14 @@ func (h *BaseHandler) OAuth2LoginGET(c echo.Context) error {
|
|||
|
||||
url := conf.AuthCodeURL(state, oauth2.AccessTypeOffline)
|
||||
|
||||
redirect := c.QueryParam("redirect")
|
||||
h.logger.Info("OAuth2LoginGET", "redirect", redirect)
|
||||
|
||||
err = h.setOAuth2Redirect(c, redirect)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return c.Redirect(http.StatusTemporaryRedirect, url)
|
||||
}
|
||||
|
||||
|
@ -156,7 +203,21 @@ func (h *BaseHandler) OAuth2CallbackGET(c echo.Context) error {
|
|||
return err
|
||||
}
|
||||
|
||||
return c.Redirect(http.StatusTemporaryRedirect, "/settings")
|
||||
redirect, err := h.getOAuth2Redirect(c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
h.logger.Info("OAuth2CallbackGET", "redirect", redirect)
|
||||
if redirect == "" {
|
||||
redirect = "/settings"
|
||||
}
|
||||
|
||||
err = h.clearOAuth2Redirect(c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return c.Redirect(http.StatusTemporaryRedirect, redirect)
|
||||
}
|
||||
|
||||
func (h *BaseHandler) OAuth2LogoutGET(c echo.Context) error {
|
||||
|
|
|
@ -6,53 +6,71 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/mentos1386/zdravko/internal/temporal"
|
||||
"github.com/mentos1386/zdravko/pkg/api"
|
||||
"go.temporal.io/sdk/workflow"
|
||||
)
|
||||
|
||||
func (w *Workflows) CheckWorkflowDefinition(ctx workflow.Context, param temporal.WorkflowCheckParam) (api.CheckStatus, error) {
|
||||
func (w *Workflows) CheckWorkflowDefinition(ctx workflow.Context, param temporal.WorkflowCheckParam) error {
|
||||
workerGroupIds := param.WorkerGroupIds
|
||||
sort.Strings(workerGroupIds)
|
||||
|
||||
ctx = workflow.WithActivityOptions(ctx, workflow.ActivityOptions{
|
||||
StartToCloseTimeout: 60 * time.Second,
|
||||
TaskQueue: temporal.TEMPORAL_SERVER_QUEUE,
|
||||
})
|
||||
targetsFilterParam := temporal.ActivityTargetsFilterParam{
|
||||
Filter: param.Filter,
|
||||
}
|
||||
targetsFilterResult := temporal.ActivityTargetsFilterResult{}
|
||||
err := workflow.ExecuteActivity(ctx, temporal.ActivityTargetsFilterName, targetsFilterParam).Get(ctx, &targetsFilterResult)
|
||||
err := workflow.ExecuteActivity(
|
||||
workflow.WithActivityOptions(ctx, workflow.ActivityOptions{
|
||||
StartToCloseTimeout: 60 * time.Second,
|
||||
TaskQueue: temporal.TEMPORAL_SERVER_QUEUE,
|
||||
}),
|
||||
temporal.ActivityTargetsFilterName,
|
||||
temporal.ActivityTargetsFilterParam{
|
||||
Filter: param.Filter,
|
||||
},
|
||||
).Get(ctx, &targetsFilterResult)
|
||||
if err != nil {
|
||||
return api.CheckStatusUnknown, err
|
||||
return err
|
||||
}
|
||||
|
||||
for _, target := range targetsFilterResult.Targets {
|
||||
for _, workerGroupId := range workerGroupIds {
|
||||
ctx = workflow.WithActivityOptions(ctx, workflow.ActivityOptions{
|
||||
StartToCloseTimeout: 60 * time.Second,
|
||||
TaskQueue: workerGroupId,
|
||||
})
|
||||
|
||||
heatlcheckParam := temporal.ActivityCheckParam{
|
||||
Script: param.Script,
|
||||
Target: target,
|
||||
}
|
||||
|
||||
var checkResult *temporal.ActivityCheckResult
|
||||
err := workflow.ExecuteActivity(ctx, temporal.ActivityCheckName, heatlcheckParam).Get(ctx, &checkResult)
|
||||
err := workflow.ExecuteActivity(
|
||||
workflow.WithActivityOptions(ctx, workflow.ActivityOptions{
|
||||
StartToCloseTimeout: 60 * time.Second,
|
||||
TaskQueue: workerGroupId,
|
||||
}),
|
||||
temporal.ActivityCheckName,
|
||||
temporal.ActivityCheckParam{
|
||||
Script: param.Script,
|
||||
Target: target,
|
||||
},
|
||||
).Get(ctx, &checkResult)
|
||||
if err != nil {
|
||||
return api.CheckStatusUnknown, err
|
||||
return err
|
||||
}
|
||||
|
||||
status := api.CheckStatusFailure
|
||||
status := temporal.AddTargetHistoryStatusFailure
|
||||
if checkResult.Success {
|
||||
status = api.CheckStatusSuccess
|
||||
status = temporal.AddTargetHistoryStatusSuccess
|
||||
}
|
||||
|
||||
var addTargetHistoryResult *temporal.ActivityAddTargetHistoryResult
|
||||
err = workflow.ExecuteActivity(
|
||||
workflow.WithActivityOptions(ctx, workflow.ActivityOptions{
|
||||
StartToCloseTimeout: 60 * time.Second,
|
||||
TaskQueue: temporal.TEMPORAL_SERVER_QUEUE,
|
||||
}),
|
||||
temporal.ActivityAddTargetHistoryName,
|
||||
&temporal.ActivityAddTargetHistoryParam{
|
||||
Target: target,
|
||||
Status: status,
|
||||
Note: checkResult.Note,
|
||||
},
|
||||
).Get(ctx, &addTargetHistoryResult)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
slog.Info("Check %s status: %s", param.CheckId, status)
|
||||
}
|
||||
}
|
||||
|
||||
return api.CheckStatusSuccess, nil
|
||||
return nil
|
||||
}
|
||||
|
|
20
internal/temporal/activity_add_target_history.go
Normal file
20
internal/temporal/activity_add_target_history.go
Normal file
|
@ -0,0 +1,20 @@
|
|||
package temporal
|
||||
|
||||
type AddTargetHistoryStatus string
|
||||
|
||||
const (
|
||||
AddTargetHistoryStatusSuccess AddTargetHistoryStatus = "SUCCESS"
|
||||
AddTargetHistoryStatusFailure AddTargetHistoryStatus = "FAILURE"
|
||||
AddTargetHistoryStatusUnknown AddTargetHistoryStatus = "UNKNOWN"
|
||||
)
|
||||
|
||||
type ActivityAddTargetHistoryParam struct {
|
||||
Target *Target
|
||||
Status AddTargetHistoryStatus
|
||||
Note string
|
||||
}
|
||||
|
||||
type ActivityAddTargetHistoryResult struct {
|
||||
}
|
||||
|
||||
const ActivityAddTargetHistoryName = "ADD_TARGET_HISTORY"
|
|
@ -1,10 +1,8 @@
|
|||
package temporal
|
||||
|
||||
import "github.com/mentos1386/zdravko/database/models"
|
||||
|
||||
type ActivityCheckParam struct {
|
||||
Script string
|
||||
Target *models.Target
|
||||
Target *Target
|
||||
}
|
||||
|
||||
type ActivityCheckResult struct {
|
||||
|
|
|
@ -1,10 +0,0 @@
|
|||
package temporal
|
||||
|
||||
type ActivityProcessCheckOutcomeParam struct {
|
||||
Outcome string
|
||||
}
|
||||
|
||||
type ActivityProcessCheckOutcomeResult struct {
|
||||
}
|
||||
|
||||
const ActivityProcessCheckOutcomeName = "PROCESS_CHECK_OUTCOME"
|
|
@ -1,15 +1,11 @@
|
|||
package temporal
|
||||
|
||||
import (
|
||||
"github.com/mentos1386/zdravko/database/models"
|
||||
)
|
||||
|
||||
type ActivityTargetsFilterParam struct {
|
||||
Filter string
|
||||
}
|
||||
|
||||
type ActivityTargetsFilterResult struct {
|
||||
Targets []*models.Target
|
||||
Targets []*Target
|
||||
}
|
||||
|
||||
const ActivityTargetsFilterName = "TARGETS_FILTER"
|
||||
|
|
|
@ -12,6 +12,13 @@ import (
|
|||
"go.temporal.io/sdk/client"
|
||||
)
|
||||
|
||||
type Target struct {
|
||||
Id string
|
||||
Name string
|
||||
Group string
|
||||
Metadata string
|
||||
}
|
||||
|
||||
// Must be default, as we are also processing
|
||||
// some temporal things.
|
||||
const TEMPORAL_SERVER_QUEUE = "default"
|
||||
|
|
|
@ -8,16 +8,23 @@ import (
|
|||
"github.com/mentos1386/zdravko/pkg/k6"
|
||||
"github.com/mentos1386/zdravko/pkg/k6/zdravko"
|
||||
"github.com/mentos1386/zdravko/pkg/script"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
func (a *Activities) Check(ctx context.Context, param temporal.ActivityCheckParam) (*temporal.ActivityCheckResult, error) {
|
||||
execution := k6.NewExecution(slog.Default(), script.UnescapeString(param.Script))
|
||||
|
||||
var metadata map[string]interface{}
|
||||
err := yaml.Unmarshal([]byte(param.Target.Metadata), &metadata)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ctx = zdravko.WithZdravkoContext(ctx, zdravko.Context{
|
||||
Target: zdravko.Target{
|
||||
Name: param.Target.Name,
|
||||
Group: param.Target.Group,
|
||||
//Metadata: param.Target.Metadata,
|
||||
Name: param.Target.Name,
|
||||
Group: param.Target.Group,
|
||||
Metadata: metadata,
|
||||
},
|
||||
})
|
||||
|
||||
|
|
|
@ -1,15 +1 @@
|
|||
package api
|
||||
|
||||
type CheckStatus string
|
||||
|
||||
const (
|
||||
CheckStatusSuccess CheckStatus = "SUCCESS"
|
||||
CheckStatusFailure CheckStatus = "FAILURE"
|
||||
CheckStatusUnknown CheckStatus = "UNKNOWN"
|
||||
)
|
||||
|
||||
type ApiV1ChecksHistoryPOSTBody struct {
|
||||
Status CheckStatus `json:"status"`
|
||||
Note string `json:"note"`
|
||||
WorkerGroupId string `json:"worker_group"`
|
||||
}
|
||||
|
|
|
@ -4,12 +4,6 @@ import "context"
|
|||
|
||||
type zdravkoContextKey string
|
||||
|
||||
type Target struct {
|
||||
Name string
|
||||
Group string
|
||||
Metadata map[string]interface{}
|
||||
}
|
||||
|
||||
type Context struct {
|
||||
Target Target
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package zdravko
|
||||
|
||||
import (
|
||||
"github.com/dop251/goja"
|
||||
"go.k6.io/k6/js/modules"
|
||||
)
|
||||
|
||||
|
@ -41,14 +42,20 @@ func (*RootModule) NewModuleInstance(vu modules.VU) modules.Instance {
|
|||
}
|
||||
}
|
||||
|
||||
type Zdravko struct {
|
||||
vu modules.VU
|
||||
Targets []string
|
||||
type Target struct {
|
||||
Name string
|
||||
Group string
|
||||
Metadata map[string]interface{}
|
||||
}
|
||||
|
||||
func (z *Zdravko) GetTarget() Target {
|
||||
type Zdravko struct {
|
||||
vu modules.VU
|
||||
Targets []Target
|
||||
}
|
||||
|
||||
func (z *Zdravko) GetTarget() goja.Value {
|
||||
zdravkoContext := GetZdravkoContext(z.vu.Context())
|
||||
return zdravkoContext.Target
|
||||
return z.vu.Runtime().ToValue(zdravkoContext.Target)
|
||||
}
|
||||
|
||||
// Exports implements the modules.Instance interface and returns the exported types for the JS module.
|
||||
|
|
|
@ -31,7 +31,7 @@ func NewWorker(temporalClient client.Client, cfg *config.ServerConfig, logger *s
|
|||
|
||||
// Register Activities
|
||||
worker.RegisterActivityWithOptions(a.TargetsFilter, activity.RegisterOptions{Name: temporal.ActivityTargetsFilterName})
|
||||
worker.RegisterActivityWithOptions(a.ProcessCheckOutcome, activity.RegisterOptions{Name: temporal.ActivityProcessCheckOutcomeName})
|
||||
worker.RegisterActivityWithOptions(a.AddTargetHistory, activity.RegisterOptions{Name: temporal.ActivityAddTargetHistoryName})
|
||||
|
||||
return &Worker{
|
||||
worker: worker,
|
||||
|
|
|
@ -1798,6 +1798,10 @@ code {
|
|||
}
|
||||
|
||||
@media (min-width: 640px) {
|
||||
.sm\:col-span-2 {
|
||||
grid-column: span 2 / span 2;
|
||||
}
|
||||
|
||||
.sm\:w-auto {
|
||||
width: auto;
|
||||
}
|
||||
|
|
|
@ -35,26 +35,26 @@
|
|||
<code>@yearly</code>.
|
||||
</p>
|
||||
<label for="filter">Filter</label>
|
||||
<textarea required id="filter" name="filter" class="h-12">
|
||||
<textarea required id="filter" name="filter" class="sm:col-span-2 h-12">
|
||||
{{ ScriptUnescapeString .ExampleFilter }}</textarea
|
||||
>
|
||||
<div
|
||||
id="editor-filter"
|
||||
class="hidden block w-full h-12 rounded-lg border border-gray-300 overflow-hidden"
|
||||
class="hidden sm:col-span-2 block w-full h-12 rounded-lg border border-gray-300 overflow-hidden"
|
||||
></div>
|
||||
<p>
|
||||
<p class="sm:col-span-2">
|
||||
With filter we specify what targets the check will run on. The must be a
|
||||
javascript expression that returns a boolean.
|
||||
</p>
|
||||
<label for="script">Script</label>
|
||||
<textarea required id="script" name="script" class="h-96">
|
||||
<textarea required id="script" name="script" class="sm:col-span-2 h-96">
|
||||
{{ ScriptUnescapeString .ExampleScript }}</textarea
|
||||
>
|
||||
<div
|
||||
id="editor-script"
|
||||
class="hidden block w-full h-96 rounded-lg border border-gray-300 overflow-hidden"
|
||||
class="hidden sm:col-span-2 block w-full h-96 rounded-lg border border-gray-300 overflow-hidden"
|
||||
></div>
|
||||
<p>
|
||||
<p class="sm:col-span-2">
|
||||
Script is what determines the status of a service. You can read more
|
||||
about it on
|
||||
<a target="_blank" href="https://k6.io/docs/using-k6/http-requests/"
|
||||
|
@ -68,7 +68,13 @@
|
|||
<script src="/static/monaco/vs/loader.js"></script>
|
||||
<script>
|
||||
const items = [
|
||||
{ name: "filter", language: "javascript" },
|
||||
{
|
||||
name: "filter",
|
||||
language: "javascript",
|
||||
options: {
|
||||
quickSuggestions: false,
|
||||
},
|
||||
},
|
||||
{ name: "script", language: "javascript" },
|
||||
];
|
||||
|
||||
|
@ -80,7 +86,7 @@
|
|||
}
|
||||
|
||||
window.editors = {};
|
||||
for (const { name, language } of items) {
|
||||
for (const { name, language, options = {} } of items) {
|
||||
const textarea = document.getElementById(name);
|
||||
const editor = document.getElementById("editor-" + name);
|
||||
|
||||
|
@ -96,6 +102,8 @@
|
|||
codeLens: false,
|
||||
contextmenu: false,
|
||||
scrollBeyondLastLine: false,
|
||||
wordWrap: "on",
|
||||
...options,
|
||||
});
|
||||
|
||||
const resizeObserver = new ResizeObserver((entries) => {
|
||||
|
|
|
@ -29,26 +29,26 @@
|
|||
<code>@yearly</code>.
|
||||
</p>
|
||||
<label for="filter">Filter</label>
|
||||
<textarea required id="filter" name="filter" class="h-12">
|
||||
<textarea required id="filter" name="filter" class="sm:col-span-2 h-12">
|
||||
{{ ScriptUnescapeString .Check.Filter }}</textarea
|
||||
>
|
||||
<div
|
||||
id="editor-filter"
|
||||
class="hidden block w-full h-12 rounded-lg border border-gray-300 overflow-hidden"
|
||||
class="hidden sm:col-span-2 block w-full h-12 rounded-lg border border-gray-300 overflow-hidden"
|
||||
></div>
|
||||
<p>
|
||||
<p class="sm:col-span-2">
|
||||
With filter we specify what targets the check will run on. The must be a
|
||||
javascript expression that returns a boolean.
|
||||
</p>
|
||||
<label for="script">Script</label>
|
||||
<textarea required id="script" name="script" class="h-96">
|
||||
<textarea required id="script" name="script" class="sm:col-span-2 h-96">
|
||||
{{ ScriptUnescapeString .Check.Script }}</textarea
|
||||
>
|
||||
<div
|
||||
id="editor-script"
|
||||
class="block w-full h-96 rounded-lg border border-gray-300 overflow-hidden hidden"
|
||||
class="hidden sm:col-span-2 block w-full h-96 rounded-lg border border-gray-300 overflow-hidden"
|
||||
></div>
|
||||
<p>
|
||||
<p class="sm:col-span-2">
|
||||
Script is what determines the status of a service. You can read more
|
||||
about it on
|
||||
<a target="_blank" href="https://k6.io/docs/using-k6/http-requests/"
|
||||
|
@ -184,7 +184,13 @@
|
|||
<script src="/static/monaco/vs/loader.js"></script>
|
||||
<script>
|
||||
const items = [
|
||||
{ name: "filter", language: "javascript" },
|
||||
{
|
||||
name: "filter",
|
||||
language: "javascript",
|
||||
options: {
|
||||
quickSuggestions: false,
|
||||
},
|
||||
},
|
||||
{ name: "script", language: "javascript" },
|
||||
];
|
||||
|
||||
|
@ -196,7 +202,7 @@
|
|||
}
|
||||
|
||||
window.editors = {};
|
||||
for (const { name, language } of items) {
|
||||
for (const { name, language, options = {} } of items) {
|
||||
const textarea = document.getElementById(name);
|
||||
const editor = document.getElementById("editor-" + name);
|
||||
|
||||
|
@ -212,6 +218,8 @@
|
|||
codeLens: false,
|
||||
contextmenu: false,
|
||||
scrollBeyondLastLine: false,
|
||||
wordWrap: "on",
|
||||
...options,
|
||||
});
|
||||
|
||||
const resizeObserver = new ResizeObserver((entries) => {
|
||||
|
|
|
@ -28,14 +28,19 @@
|
|||
homepage.
|
||||
</p>
|
||||
<label for="metadata">Metadata</label>
|
||||
<textarea required id="metadata" name="metadata" class="h-96">
|
||||
<textarea
|
||||
required
|
||||
id="metadata"
|
||||
name="metadata"
|
||||
class="sm:col-span-2 h-96"
|
||||
>
|
||||
{{ ScriptUnescapeString .Example }}</textarea
|
||||
>
|
||||
<div
|
||||
id="editor-metadata"
|
||||
class="hidden block w-full h-96 rounded-lg border border-gray-300 overflow-hidden"
|
||||
class="hidden sm:col-span-2 block w-full h-96 rounded-lg border border-gray-300 overflow-hidden"
|
||||
></div>
|
||||
<p>
|
||||
<p class="sm:col-span-2">
|
||||
Metadata is a YAML object that contains the configuration for the
|
||||
target. This configuration can be then used for <code>Checks</code> to
|
||||
filter the targets to act on as well as by using
|
||||
|
@ -58,7 +63,7 @@
|
|||
}
|
||||
|
||||
window.editors = {};
|
||||
for (const { name, language } of items) {
|
||||
for (const { name, language, options = {} } of items) {
|
||||
const textarea = document.getElementById(name);
|
||||
const editor = document.getElementById("editor-" + name);
|
||||
|
||||
|
@ -74,6 +79,7 @@
|
|||
codeLens: false,
|
||||
contextmenu: false,
|
||||
scrollBeyondLastLine: false,
|
||||
...options,
|
||||
});
|
||||
|
||||
const resizeObserver = new ResizeObserver((entries) => {
|
||||
|
|
|
@ -35,14 +35,19 @@
|
|||
homepage.
|
||||
</p>
|
||||
<label for="metadata">Metadata</label>
|
||||
<textarea required id="metadata" name="metadata" class="h-96">
|
||||
<textarea
|
||||
required
|
||||
id="metadata"
|
||||
name="metadata"
|
||||
class="sm:col-span-2 h-96"
|
||||
>
|
||||
{{ ScriptUnescapeString .Target.Metadata }}</textarea
|
||||
>
|
||||
<div
|
||||
id="editor-metadata"
|
||||
class="hidden block w-full h-96 rounded-lg border border-gray-300 overflow-hidden"
|
||||
class="hidden sm:col-span-2 block w-full h-96 rounded-lg border border-gray-300 overflow-hidden"
|
||||
></div>
|
||||
<p>
|
||||
<p class="sm:col-span-2">
|
||||
Metadata is a YAML object that contains the configuration for the
|
||||
target. This configuration can be then used for <code>Targets</code> to
|
||||
filter the targets to act on as well as by using
|
||||
|
|
|
@ -10,14 +10,14 @@
|
|||
/>
|
||||
<p>Name of the trigger can be anything.</p>
|
||||
<label for="script">Script</label>
|
||||
<textarea required id="script" name="script" class="h-96">
|
||||
<textarea required id="script" name="script" class="sm:col-span-2 h-96">
|
||||
{{ ScriptUnescapeString .Example }}</textarea
|
||||
>
|
||||
<div
|
||||
id="editor-script"
|
||||
class="hidden block w-full h-96 rounded-lg border border-gray-300 overflow-hidden"
|
||||
class="hidden sm:col-span-2 block w-full h-96 rounded-lg border border-gray-300 overflow-hidden"
|
||||
></div>
|
||||
<p>
|
||||
<p class="sm:col-span-2">
|
||||
The trigger script executes for every matching <code>target</code>'s
|
||||
execution of <code>trigger</code>. The outcome of that
|
||||
<code>trigger</code> is passed to the script as a
|
||||
|
@ -40,7 +40,7 @@
|
|||
}
|
||||
|
||||
window.editors = {};
|
||||
for (const { name, language } of items) {
|
||||
for (const { name, language, options = {} } of items) {
|
||||
const textarea = document.getElementById(name);
|
||||
const editor = document.getElementById("editor-" + name);
|
||||
|
||||
|
@ -56,6 +56,7 @@
|
|||
codeLens: false,
|
||||
contextmenu: false,
|
||||
scrollBeyondLastLine: false,
|
||||
...options,
|
||||
});
|
||||
|
||||
const resizeObserver = new ResizeObserver((entries) => {
|
||||
|
|
|
@ -3,14 +3,14 @@
|
|||
<form action="/settings/triggers/{{ .Trigger.Id }}" method="post">
|
||||
<h2>Configuration</h2>
|
||||
<label for="script">Script</label>
|
||||
<textarea required id="script" name="script" class="h-96">
|
||||
<textarea required id="script" name="script" class="sm:col-span-2 h-96">
|
||||
{{ ScriptUnescapeString .Trigger.Script }}</textarea
|
||||
>
|
||||
<div
|
||||
id="editor-script"
|
||||
class="block w-full h-96 rounded-lg border border-gray-300 overflow-hidden hidden"
|
||||
class="hidden sm:col-span-2 block w-full h-96 rounded-lg border border-gray-300 overflow-hidden"
|
||||
></div>
|
||||
<p>
|
||||
<p class="sm:col-span-2">
|
||||
The trigger script executes for every matching <code>target</code>'s
|
||||
execution of <code>trigger</code>. The outcome of that
|
||||
<code>trigger</code> is passed to the script as a
|
||||
|
@ -122,7 +122,7 @@
|
|||
}
|
||||
|
||||
window.editors = {};
|
||||
for (const { name, language } of items) {
|
||||
for (const { name, language, options = {} } of items) {
|
||||
const textarea = document.getElementById(name);
|
||||
const editor = document.getElementById("editor-" + name);
|
||||
|
||||
|
@ -138,6 +138,7 @@
|
|||
codeLens: false,
|
||||
contextmenu: false,
|
||||
scrollBeyondLastLine: false,
|
||||
...options,
|
||||
});
|
||||
|
||||
const resizeObserver = new ResizeObserver((entries) => {
|
||||
|
|
Loading…
Reference in a new issue