Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/docs.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,22 +8,22 @@

jobs:
deploy:
runs-on: ubuntu-20.04
runs-on: ubuntu-24.04
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
steps:
- uses: actions/checkout@v4

- name: Setup mdBook
uses: peaceiris/actions-mdbook@v2
with:
mdbook-version: '0.4.10'

- run: mdbook build docs

- name: Deploy
uses: peaceiris/actions-gh-pages@v4
if: ${{ github.ref == 'refs/heads/main' }}
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./docs/book

Check warning

Code scanning / CodeQL

Workflow does not contain permissions Medium

Actions job or workflow does not limit the permissions of the GITHUB_TOKEN. Consider setting an explicit permissions block, using the following as a minimal starting point: {contents: read}
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
.idea
*.iml
*.proj
.vscode

# C Dependency
libjq
32 changes: 16 additions & 16 deletions cmd/shell-operator/start.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,27 +25,27 @@ const (
)

func start(logger *log.Logger) func(_ *kingpin.ParseContext) error {
app.AppStartMessage = fmt.Sprintf("%s %s", app.AppName, app.Version)
ctx := context.Background()
telemetryShutdown := registerTelemetry(ctx)
// Init logging and initialize a ShellOperator instance.
operator, err := shell_operator.Init(logger.Named("shell-operator"))
if err != nil {
return func(_ *kingpin.ParseContext) error {
return func(_ *kingpin.ParseContext) error {
app.AppStartMessage = fmt.Sprintf("%s %s", app.AppName, app.Version)
ctx := context.Background()
telemetryShutdown := registerTelemetry(ctx)
// Init logging and initialize a ShellOperator instance.
operator, err := shell_operator.Init(logger.Named("shell-operator"))
if err != nil {
return fmt.Errorf("init failed: %w", err)
}
}

operator.Start()
operator.Start()

// Block action by waiting signals from OS.
utils_signal.WaitForProcessInterruption(func() {
operator.Shutdown()
_ = telemetryShutdown(ctx)
os.Exit(1)
})
// Block action by waiting signals from OS.
utils_signal.WaitForProcessInterruption(func() {
operator.Shutdown()
_ = telemetryShutdown(ctx)
os.Exit(1)
})

return nil
return nil
}
}

func registerTelemetry(ctx context.Context) func(ctx context.Context) error {
Expand Down
34 changes: 30 additions & 4 deletions pkg/debug/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import (
"net/http"
"os"
"path"
"path/filepath"
"strings"

"github.com/deckhouse/deckhouse/pkg/log"
"github.com/go-chi/chi/v5"
Expand Down Expand Up @@ -117,20 +119,32 @@ func (s *Server) RegisterHandler(method, pattern string, handler func(request *h
func handleFormattedOutput(writer http.ResponseWriter, request *http.Request, handler func(request *http.Request) (interface{}, error)) {
out, err := handler(request)
if err != nil {
if _, ok := err.(*BadRequestError); ok {
switch err.(type) {
case *BadRequestError:
http.Error(writer, err.Error(), http.StatusBadRequest)
return
case *NotFoundError:
http.Error(writer, err.Error(), http.StatusNotFound)
default:
http.Error(writer, err.Error(), http.StatusInternalServerError)
}

http.Error(writer, err.Error(), http.StatusInternalServerError)
return
}
if out == nil {
writer.WriteHeader(http.StatusOK)
return
}

format := FormatFromRequest(request)
// Trying to get format from chi
format := chi.URLParam(request, "format")
if format == "" { // If failed, trying to parse uri
uri := request.URL.Path
uriFragments := strings.Split(uri, "/")
uriLastFragment := uriFragments[len(uriFragments)-1] // string after last "/" to ignore garbage
format = filepath.Ext(uriLastFragment) // Extracts extension of path (like .yaml), may return empty string
format = strings.TrimPrefix(format, ".")
}

structuredLogger.GetLogEntry(request).Debug("used format", slog.String("format", format))

switch format {
Expand All @@ -140,6 +154,10 @@ func handleFormattedOutput(writer http.ResponseWriter, request *http.Request, ha
writer.Header().Set("Content-Type", "application/json")
case "yaml":
writer.Header().Set("Content-Type", "application/yaml")
// support for old behavior. If the extension is not indicated, we use text by default
case "":
format = "text"
writer.Header().Set("Content-Type", "text/plain; charset=utf-8")
}
writer.WriteHeader(http.StatusOK)

Expand Down Expand Up @@ -196,3 +214,11 @@ type BadRequestError struct {
func (be *BadRequestError) Error() string {
return be.Msg
}

type NotFoundError struct {
Msg string
}

func (nf *NotFoundError) Error() string {
return nf.Msg
}
57 changes: 57 additions & 0 deletions pkg/filter/jq/apply_benchmark_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package jq

import (
"os"
"testing"

"gopkg.in/yaml.v3"
)

func setupNodeList(count int) []map[string]any {
var node map[string]any
content, _ := os.ReadFile("testdata/test.yaml")
yaml.Unmarshal(content, &node)

Check failure on line 13 in pkg/filter/jq/apply_benchmark_test.go

View workflow job for this annotation

GitHub Actions / Run linter

Error return value of `yaml.Unmarshal` is not checked (errcheck)

nodeslice := make([]map[string]any, 0, count)

for range count {
nodeslice = append(nodeslice, node)
}

return nodeslice
}

func benchmarkApplyFilter(b *testing.B, filter string, objs []map[string]any) {
f := NewFilter()
b.ResetTimer()

for i := 0; i < b.N; i++ {
for _, obj := range objs {
// res, _ := f.ApplyFilter(filter, obj)
// fmt.Println(string(res))
f.ApplyFilter(filter, obj)

Check failure on line 32 in pkg/filter/jq/apply_benchmark_test.go

View workflow job for this annotation

GitHub Actions / Run linter

Error return value of `f.ApplyFilter` is not checked (errcheck)
}
}
}

func BenchmarkApplyFilter_dot_10(b *testing.B) {
benchmarkApplyFilter(b, ".", setupNodeList(10))
}

Check failure on line 39 in pkg/filter/jq/apply_benchmark_test.go

View workflow job for this annotation

GitHub Actions / Run linter

File is not properly formatted (gofumpt)
func BenchmarkApplyFilter_dot_100(b *testing.B) {
benchmarkApplyFilter(b, ".", setupNodeList(100))
}
func BenchmarkApplyFilter_dot_1000(b *testing.B) {
benchmarkApplyFilter(b, ".", setupNodeList(1000))
}

func BenchmarkApplyFilter_easy_10(b *testing.B) {
benchmarkApplyFilter(b, ".metadata.name", setupNodeList(10))
}

func BenchmarkApplyFilter_easy_100(b *testing.B) {
benchmarkApplyFilter(b, ".metadata.name", setupNodeList(100))
}

func BenchmarkApplyFilter_easy_1000(b *testing.B) {
benchmarkApplyFilter(b, ".metadata.name", setupNodeList(1000))
}
30 changes: 27 additions & 3 deletions pkg/shell-operator/debug_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,20 @@ package shell_operator
import (
"fmt"
"net/http"
"regexp"
"strconv"
"time"

"github.com/deckhouse/deckhouse/pkg/log"
"github.com/go-chi/chi/v5"

"github.com/flant/shell-operator/pkg/config"
"github.com/flant/shell-operator/pkg/debug"
"github.com/flant/shell-operator/pkg/task/dump"
)

// hook path may be nested like: /hook/myfolder/myhook.sh/snapshots
var snapshotRe = regexp.MustCompile(`/hook/(.*)/snapshots.*`)

// RunDefaultDebugServer initialized and run default debug server on unix and http sockets
// This method is also used in addon-operator
func RunDefaultDebugServer(unixSocket, httpServerAddress string, logger *log.Logger) (*debug.Server, error) {
Expand Down Expand Up @@ -53,9 +56,30 @@ func (op *ShellOperator) RegisterDebugHookRoutes(dbgSrv *debug.Server) {
return op.HookManager.GetHookNames(), nil
})

dbgSrv.RegisterHandler(http.MethodGet, "/hook/{name}/snapshots.{format:(json|yaml|text)}", func(r *http.Request) (interface{}, error) {
hookName := chi.URLParam(r, "name")
// handler for dump hook snapshots
// Example path: /hook/100-test.sh/snapshots.text
dbgSrv.RegisterHandler(http.MethodGet, "/hook/*", func(r *http.Request) (interface{}, error) {
// check regex match
isMatched := snapshotRe.MatchString(r.RequestURI)
if !isMatched {
return nil, &debug.NotFoundError{Msg: "404 page not found"}
}

// Extracting hook name from URI
matched := snapshotRe.FindStringSubmatch(r.RequestURI) // expression returns slice of: matched substring, matched group hookName
var hookName string
if len(matched) >= 2 { // expected presence of second element (hookName)
hookName = matched[1]
}
if hookName == "" {
return nil, &debug.BadRequestError{Msg: "'hook' parameter is required"}
}

// Return hook snapshot dump
h := op.HookManager.GetHook(hookName)
if h == nil {
return nil, &debug.BadRequestError{Msg: fmt.Sprintf("hook '%s' is not exist", hookName)}
}
return h.HookController.SnapshotsDump(), nil
})
}
Expand Down
4 changes: 4 additions & 0 deletions pkg/shell-operator/operator.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,11 +96,14 @@ func NewShellOperator(ctx context.Context, opts ...Option) *ShellOperator {
func (op *ShellOperator) Start() {
log.Info("start shell-operator")

op.logger.Debug("start APIServer")
op.APIServer.Start(op.ctx)

// Create 'main' queue and add onStartup tasks and enable bindings tasks.
op.logger.Debug("start bootstrapMainQueue")
op.bootstrapMainQueue(op.TaskQueues)
// Start main task queue handler
op.logger.Debug("start TaskQueues StartMain")
op.TaskQueues.StartMain(op.ctx)
op.initAndStartHookQueues()

Expand Down Expand Up @@ -275,6 +278,7 @@ func (op *ShellOperator) initValidatingWebhookManager() error {
return admissionResponse, nil
})

op.logger.Debug("debug ValidatingWebhookManager ValidatingResources", slog.Any("ValidatingResources", op.AdmissionWebhookManager.ValidatingResources))
if err := op.AdmissionWebhookManager.Start(); err != nil {
return fmt.Errorf("ValidatingWebhookManager start: %w", err)
}
Expand Down
5 changes: 5 additions & 0 deletions pkg/webhook/admission/resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package admission

import (
"context"
"fmt"
"log/slog"
"strings"

Expand Down Expand Up @@ -63,9 +64,13 @@ func (w *ValidatingWebhookResource) Register() error {
slog.String("path", *webhook.ClientConfig.Service.Path),
slog.String("configurationName", w.opts.ConfigurationName))

log.Debug("debug w.opts.ServiceName", slog.String("w.opts.ServiceName", w.opts.ServiceName))
log.Debug("debug ValidatingWebhook client", slog.String("webhook.ValidatingWebhook.ClientConfig.Service.Name", webhook.ValidatingWebhook.ClientConfig.Service.Name))

configuration.Webhooks = append(configuration.Webhooks, *webhook.ValidatingWebhook)
}

fmt.Println(configuration.Webhooks)
return w.submit(configuration)
}

Expand Down
Loading