Skip to content
Closed
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
30 changes: 15 additions & 15 deletions lefthook.yml
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
# see https://github.com/evilmartians/lefthook for references
pre-push:
follow: true
piped: true # Stop if one of the steps fail
commands:
1_generate:
run: make generate
2_lint:
run: make lint
3_format:
run: make format
4_check_mod_change:
run: go mod tidy
5_check_local_changes:
run: make no-local-changes
## see https://github.com/evilmartians/lefthook for references
#pre-push:
# follow: true
# piped: true # Stop if one of the steps fail
# commands:
# 1_generate:
# run: make generate
# 2_lint:
# run: make lint
# 3_format:
# run: make format
# 4_check_mod_change:
# run: go mod tidy
# 5_check_local_changes:
# run: make no-local-changes
123 changes: 120 additions & 3 deletions pkg/nginxprocess/process.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,26 @@
package nginxprocess

import (
"bufio"
"context"
"fmt"
"github.com/nginx/agent/v3/internal/datasource/host/exec"

Check failure on line 13 in pkg/nginxprocess/process.go

View workflow job for this annotation

GitHub Actions / Lint

File is not properly formatted (gofumpt)
"log/slog"
"os"
"strconv"
"strings"
"time"

"github.com/shirou/gopsutil/v4/process"
)

const (
keyValueLen = 2
flagLen = 1
workerString = "nginx: worker %s"
masterString = "nginx: master %s"
)

// Process contains a snapshot of read-only data about an OS-level NGINX process. Create using [List] or [Find].
type Process struct {
// Created is when this process was created, precision varies by platform and is at best to the millisecond. On
Expand All @@ -25,6 +38,8 @@
Status string // process status, only present if this process was created using [WithStatus]
PID int32
PPID int32 // parent PID
// TODO: after this is out of spike I will be using this for returning a map

Check failure on line 41 in pkg/nginxprocess/process.go

View workflow job for this annotation

GitHub Actions / Lint

Line contains TODO/BUG/FIXME/HACK: "TODO: after this is out of spike I will ..." (godox)
Master bool
}

// IsWorker returns true if the process is a NGINX worker process.
Expand Down Expand Up @@ -65,7 +80,7 @@
}

func convert(ctx context.Context, p *process.Process, o options) (*Process, error) {
if err := ctx.Err(); err != nil { // fail fast if we've canceled

Check failure on line 83 in pkg/nginxprocess/process.go

View workflow job for this annotation

GitHub Actions / Lint

cyclomatic: function convert has cyclomatic complexity 17 (> max enabled 12) (revive)
return nil, err
}

Expand All @@ -81,7 +96,19 @@
return nil, errNotAnNginxProcess
}

if strings.HasPrefix(cmdLine, "nginx:") || strings.HasPrefix(cmdLine, "{nginx-debug} nginx:") {
var sbin string
var pidPath string
configArgs := nginxArgs(ctx)
if configArgs["sbin-path"] != nil {
sbin = configArgs["sbin-path"].(string)
}

Check failure on line 104 in pkg/nginxprocess/process.go

View workflow job for this annotation

GitHub Actions / Lint

type assertion must be checked (forcetypeassert)

if configArgs["pid-path"] != nil {
pidPath = configArgs["pid-path"].(string)
}

Check failure on line 108 in pkg/nginxprocess/process.go

View workflow job for this annotation

GitHub Actions / Lint

type assertion must be checked (forcetypeassert)

if strings.HasPrefix(cmdLine, "nginx:") || strings.HasPrefix(cmdLine, "{nginx-debug} nginx:") ||
strings.HasPrefix(cmdLine, "/run/rosetta/rosetta") {

Check failure on line 111 in pkg/nginxprocess/process.go

View workflow job for this annotation

GitHub Actions / Lint

`if strings.HasPrefix(cmdLine, "nginx:") || strings.HasPrefix(cmdLine, "{nginx-debug} nginx:") ||
var status string
if o.loadStatus {
flags, _ := p.StatusWithContext(ctx) // slow: shells out to ps
Expand All @@ -96,20 +123,110 @@
ppid, _ := p.PpidWithContext(ctx)
exe, _ := p.ExeWithContext(ctx)

return &Process{
nginxProcess := &Process{
PID: p.Pid,
PPID: ppid,
Name: name,
Cmd: cmdLine,
Created: created,
Status: status,
Exe: exe,
}, ctx.Err()
}

// Check if process is master process
if strings.HasPrefix(cmdLine, "nginx: master") ||
strings.HasPrefix(cmdLine, "{nginx-debug} nginx: master") {
slog.InfoContext(ctx, "Nginx master process - cmd", "pid", nginxProcess)
nginxProcess.Master = true
// Check if process is worker process
} else if strings.HasPrefix(cmdLine, "nginx: worker") {
nginxProcess.Master = false
slog.InfoContext(ctx, "Nginx worker process - cmd", "pid", nginxProcess)
// if process is not either could be running on rosetta check nginx pid file
// Check if process is master by checking pid matches nginx pid file
} else if p.Pid == nginxPID(ctx, pidPath) {
nginxProcess.Master = true
nginxProcess.Cmd = fmt.Sprintf(masterString, sbin)
nginxProcess.Exe = sbin
slog.InfoContext(ctx, "Nginx master process - file", "pid", nginxProcess)
// Check if process is worker by checking ppid matches nginx pid file
} else if ppid == nginxPID(ctx, pidPath) {
slog.InfoContext(ctx, "Nginx worker process - file", "pid", nginxProcess)
nginxProcess.Master = false
nginxProcess.Cmd = fmt.Sprintf(workerString, sbin)
}

return nginxProcess, ctx.Err()
}

return nil, errNotAnNginxProcess
}

func nginxArgs(ctx context.Context) map[string]interface{} {
configArgs := make(map[string]interface{})
executer := &exec.Exec{}
outputBuffer, err := executer.RunCmd(ctx, "nginx", "-V")
if err != nil {
return nil
}

scanner := bufio.NewScanner(outputBuffer)
for scanner.Scan() {
line := strings.TrimSpace(scanner.Text())
switch {
case strings.HasPrefix(line, "configure arguments"):

Check failure on line 177 in pkg/nginxprocess/process.go

View workflow job for this annotation

GitHub Actions / Lint

unnecessary-stmt: switch with only one case can be replaced by an if-then (revive)
configArgs = parseConfigureArguments(line)
}
}

return configArgs
}

func nginxPID(ctx context.Context, pidPath string) int32 {
if _, err := os.Stat(pidPath); os.IsNotExist(err) {

Check failure on line 186 in pkg/nginxprocess/process.go

View workflow job for this annotation

GitHub Actions / Lint

nginxPID - ctx is unused (unparam)
return 0
}
pidBytes, err := os.ReadFile(pidPath)
if err != nil {
return 0
}

pidString := string(pidBytes)
pidString = strings.TrimSpace(pidString)
pid, err := strconv.ParseInt(pidString, 10, 32)

if err != nil {
return 0
}

return int32(pid)
}

func parseConfigureArguments(line string) map[string]interface{} {
// need to check for empty strings
flags := strings.Split(line[len("configure arguments:"):], " --")
result := make(map[string]interface{})

for _, flag := range flags {
vals := strings.Split(flag, "=")
if isFlag(vals) {
result[vals[0]] = true
} else if isKeyValueFlag(vals) {
result[vals[0]] = vals[1]
}
}

return result
}

func isFlag(vals []string) bool {
return len(vals) == flagLen && vals[0] != ""
}

func isKeyValueFlag(vals []string) bool {
return len(vals) == keyValueLen
}

// List returns a slice of all NGINX processes. Returns a zero-length slice if no NGINX processes are found.
func List(ctx context.Context, opts ...Option) (ret []*Process, err error) {
processes, err := process.ProcessesWithContext(ctx)
Expand Down
18 changes: 4 additions & 14 deletions test/docker/nginx-plus-and-nap/deb/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ RUN --mount=type=secret,id=nginx-crt,dst=nginx-repo.crt \
&& apt-get update --allow-releaseinfo-change \
&& apt-get install --no-install-recommends --no-install-suggests -y \
ca-certificates \
gnupg1 \
gpg \
lsb-release \
apt-transport-https \
git \
Expand All @@ -32,18 +32,6 @@ RUN --mount=type=secret,id=nginx-crt,dst=nginx-repo.crt \
ubuntu-keyring \
&& wget -qO - https://cs.nginx.com/static/keys/app-protect-security-updates.key | gpg --dearmor | tee /usr/share/keyrings/app-protect-security-updates.gpg >/dev/null \
&& wget -qO - https://cs.nginx.com/static/keys/nginx_signing.key | gpg --dearmor | tee /usr/share/keyrings/nginx-archive-keyring.gpg >/dev/null \
&& \
NGINX_GPGKEY=573BFD6B3D8FBC641079A6ABABF5BD827BD9BF62; \
found=''; \
for server in \
hkp://keyserver.ubuntu.com:80 \
pgp.mit.edu \
; do \
echo "Fetching GPG key $NGINX_GPGKEY from $server"; \
apt-key adv --keyserver "$server" --keyserver-options timeout=10 --recv-keys "$NGINX_GPGKEY" && found=yes && break; \
done; \
test -z "$found" && echo >&2 "error: failed to fetch GPG key $NGINX_GPGKEY" && exit 1; \
apt-get remove --purge --auto-remove -y gnupg1 && rm -rf /var/lib/apt/lists/* \
# Install the latest release of NGINX Plus and/or NGINX Plus modules
# Uncomment individual modules if necessary
# Use versioned packages over defaults to specify a release
Expand All @@ -54,7 +42,8 @@ RUN --mount=type=secret,id=nginx-crt,dst=nginx-repo.crt \
&& echo "Acquire::https::pkgs.nginx.com::Verify-Host \"true\";" >> /etc/apt/apt.conf.d/90nginx \
&& echo "Acquire::https::pkgs.nginx.com::SslCert \"/etc/ssl/nginx/nginx-repo.crt\";" >> /etc/apt/apt.conf.d/90nginx \
&& echo "Acquire::https::pkgs.nginx.com::SslKey \"/etc/ssl/nginx/nginx-repo.key\";" >> /etc/apt/apt.conf.d/90nginx \
&& printf "deb https://pkgs.nginx.com/plus/${PLUS_VERSION}/ubuntu/ `lsb_release -cs` nginx-plus\n" > /etc/apt/sources.list.d/nginx-plus.list \
&& printf "deb [signed-by=/usr/share/keyrings/nginx-archive-keyring.gpg] https://pkgs.nginx.com/plus/${PLUS_VERSION}/ubuntu/ `lsb_release -cs` nginx-plus\n" > /etc/apt/sources.list.d/nginx-plus.list \
&& wget -qO - https://cs.nginx.com/static/keys/nginx_signing.key | gpg --dearmor | tee /usr/share/keyrings/nginx-archive-keyring.gpg >/dev/null \
&& printf "deb [signed-by=/usr/share/keyrings/nginx-archive-keyring.gpg] https://pkgs.nginx.com/app-protect/${PLUS_VERSION}/ubuntu `lsb_release -cs` nginx-plus\n" | tee /etc/apt/sources.list.d/nginx-app-protect.list \
&& printf "deb [signed-by=/usr/share/keyrings/app-protect-security-updates.gpg] https://pkgs.nginx.com/app-protect-security-updates/ubuntu `lsb_release -cs` nginx-plus\n" | tee -a /etc/apt/sources.list.d/nginx-app-protect.list \
&& mkdir -p /etc/ssl/nginx \
Expand All @@ -66,6 +55,7 @@ RUN --mount=type=secret,id=nginx-crt,dst=nginx-repo.crt \
curl \
gettext-base \
jq \
gnupg2 \
&& apt-get remove --purge -y lsb-release \
&& apt-get remove --purge --auto-remove -y && rm -rf /var/lib/apt/lists/* /etc/apt/sources.list.d/nginx-plus.list /etc/apt/sources.list.d/nginx-app-protect.list \
&& rm -rf /etc/apt/apt.conf.d/90nginx /etc/ssl/nginx
Expand Down
Loading