Merge pull request #7296 from dokku/k3s-nginx-show-config
Implement nginx:show-config for k3s plugin
This commit is contained in:
@@ -528,13 +528,17 @@ This plugin implements various functionality through `plugn` triggers to integra
|
|||||||
- `enter`
|
- `enter`
|
||||||
- `deploy`
|
- `deploy`
|
||||||
- healthchecks
|
- healthchecks
|
||||||
- Due to Kubernetes limitations, only a single healthcheck is supported for each of the `liveness`, `readiness`, and `startup` healthchecks
|
- Due to Kubernetes limitations, only a single healthcheck is supported for each of the `liveness`, `readiness`, and `startup` healthchecks
|
||||||
- Due to Kubernetes limitations, content checks are not supported
|
- Due to Kubernetes limitations, content checks are not supported
|
||||||
- Ports specified in the `app.json` are ignored in favor of the container port on the port mapping detected
|
- Ports specified in the `app.json` are ignored in favor of the container port on the port mapping detected
|
||||||
- `logs`
|
- `logs`
|
||||||
|
- `nginx`
|
||||||
|
- Properties set by the `nginx` plugin will be respected, either by turning them into annotations or creating a custom server/location snippet that the `ingress-nginx` project can use.
|
||||||
|
- The `nginx:access-logs` and `nginx:error-logs` commands will fetch logs from one running `ingress-nginx` pod.
|
||||||
|
- The `nginx:show-config` command will retrieve any `server` blocks associated with a domain attached to the app from one running `ingress-nginx` pod.
|
||||||
- `ps:stop`
|
- `ps:stop`
|
||||||
- `run`
|
- `run`
|
||||||
- The `scheduler-post-run` trigger is not always triggered
|
- The `scheduler-post-run` trigger is not always triggered
|
||||||
- `run:detached`
|
- `run:detached`
|
||||||
- `run:list`
|
- `run:list`
|
||||||
|
|
||||||
|
|||||||
@@ -158,8 +158,21 @@ cmd-nginx-show-config() {
|
|||||||
declare cmd="nginx:show-config"
|
declare cmd="nginx:show-config"
|
||||||
[[ "$1" == "$cmd" ]] && shift 1
|
[[ "$1" == "$cmd" ]] && shift 1
|
||||||
declare APP="$1"
|
declare APP="$1"
|
||||||
|
local proxy_type
|
||||||
|
|
||||||
verify_app_name "$APP"
|
verify_app_name "$APP"
|
||||||
|
proxy_type="$(plugn trigger proxy-type "$APP")"
|
||||||
|
|
||||||
|
local DOKKU_SCHEDULER=$(get_app_scheduler "$APP")
|
||||||
|
if [[ "$DOKKU_SCHEDULER" != "docker-local" ]]; then
|
||||||
|
plugn trigger scheduler-proxy-config "$DOKKU_SCHEDULER" "$APP" "$proxy_type"
|
||||||
|
return $?
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "$proxy_type" != "nginx" ]]; then
|
||||||
|
dokku_log_fail "This command is only available for apps with the nginx proxy type"
|
||||||
|
fi
|
||||||
|
|
||||||
if [[ ! -f "$DOKKU_ROOT/$APP/nginx.conf" ]]; then
|
if [[ ! -f "$DOKKU_ROOT/$APP/nginx.conf" ]]; then
|
||||||
dokku_log_fail "No nginx.conf exists for $APP"
|
dokku_log_fail "No nginx.conf exists for $APP"
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -66,6 +66,7 @@ restart_nginx() {
|
|||||||
nginx_logs() {
|
nginx_logs() {
|
||||||
declare desc="display app nginx logs"
|
declare desc="display app nginx logs"
|
||||||
declare NGINX_LOGS_TYPE="${1#nginx:}" APP="$2"
|
declare NGINX_LOGS_TYPE="${1#nginx:}" APP="$2"
|
||||||
|
local proxy_type
|
||||||
|
|
||||||
local NGINX_LOGS_TYPE=${NGINX_LOGS_TYPE%-logs}
|
local NGINX_LOGS_TYPE=${NGINX_LOGS_TYPE%-logs}
|
||||||
local NGINX_LOGS_PATH="$("fn-nginx-computed-${NGINX_LOGS_TYPE}-log-path" "$APP")"
|
local NGINX_LOGS_PATH="$("fn-nginx-computed-${NGINX_LOGS_TYPE}-log-path" "$APP")"
|
||||||
@@ -74,6 +75,8 @@ nginx_logs() {
|
|||||||
dokku_log_fail "$NGINX_LOGS_TYPE logs are disabled for this app"
|
dokku_log_fail "$NGINX_LOGS_TYPE logs are disabled for this app"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
proxy_type="$(plugn trigger proxy-type "$APP")"
|
||||||
|
|
||||||
local tail=false
|
local tail=false
|
||||||
local num=0
|
local num=0
|
||||||
if [[ $3 == "-t" ]]; then
|
if [[ $3 == "-t" ]]; then
|
||||||
@@ -84,7 +87,7 @@ nginx_logs() {
|
|||||||
|
|
||||||
local DOKKU_SCHEDULER=$(get_app_scheduler "$APP")
|
local DOKKU_SCHEDULER=$(get_app_scheduler "$APP")
|
||||||
if [[ "$DOKKU_SCHEDULER" != "docker-local" ]]; then
|
if [[ "$DOKKU_SCHEDULER" != "docker-local" ]]; then
|
||||||
plugn trigger scheduler-proxy-logs "$DOKKU_SCHEDULER" "$APP" "nginx" "$NGINX_LOGS_TYPE" "$tail" "$num"
|
plugn trigger scheduler-proxy-logs "$DOKKU_SCHEDULER" "$APP" "$proxy_type" "$NGINX_LOGS_TYPE" "$tail" "$num"
|
||||||
return $?
|
return $?
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
SUBCOMMANDS = subcommands/annotations:set subcommands/autoscaling-auth:set subcommands/autoscaling-auth:report subcommands/cluster-add subcommands/cluster-list subcommands/cluster-remove subcommands/initialize subcommands/labels:set subcommands/report subcommands/set subcommands/show-kubeconfig subcommands/uninstall
|
SUBCOMMANDS = subcommands/annotations:set subcommands/autoscaling-auth:set subcommands/autoscaling-auth:report subcommands/cluster-add subcommands/cluster-list subcommands/cluster-remove subcommands/initialize subcommands/labels:set subcommands/report subcommands/set subcommands/show-kubeconfig subcommands/uninstall
|
||||||
TRIGGERS = triggers/install triggers/post-app-clone-setup triggers/post-app-rename-setup triggers/post-delete triggers/report triggers/scheduler-app-status triggers/scheduler-deploy triggers/scheduler-enter triggers/scheduler-logs triggers/scheduler-proxy-logs triggers/scheduler-post-delete triggers/scheduler-run triggers/scheduler-run-list triggers/scheduler-stop
|
TRIGGERS = triggers/install triggers/post-app-clone-setup triggers/post-app-rename-setup triggers/post-delete triggers/report triggers/scheduler-app-status triggers/scheduler-deploy triggers/scheduler-enter triggers/scheduler-logs triggers/scheduler-proxy-config triggers/scheduler-proxy-logs triggers/scheduler-post-delete triggers/scheduler-run triggers/scheduler-run-list triggers/scheduler-stop
|
||||||
BUILD = commands subcommands triggers
|
BUILD = commands subcommands triggers
|
||||||
PLUGIN_NAME = scheduler-k3s
|
PLUGIN_NAME = scheduler-k3s
|
||||||
|
|
||||||
|
|||||||
@@ -312,6 +312,12 @@ type ExecCommandInput struct {
|
|||||||
|
|
||||||
// Namespace is the Kubernetes namespace
|
// Namespace is the Kubernetes namespace
|
||||||
Namespace string
|
Namespace string
|
||||||
|
|
||||||
|
// Stderr is the error writer
|
||||||
|
Stderr io.Writer
|
||||||
|
|
||||||
|
// Stdout is the output writer
|
||||||
|
Stdout io.Writer
|
||||||
}
|
}
|
||||||
|
|
||||||
// ExecCommand executes a command in a Kubernetes pod
|
// ExecCommand executes a command in a Kubernetes pod
|
||||||
@@ -340,11 +346,26 @@ func (k KubernetesClient) ExecCommand(ctx context.Context, input ExecCommandInpu
|
|||||||
req.Param("command", cmd)
|
req.Param("command", cmd)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var stdout io.Writer
|
||||||
|
if input.Stdout == nil {
|
||||||
|
stdout = os.Stdout
|
||||||
|
} else {
|
||||||
|
stdout = input.Stdout
|
||||||
|
}
|
||||||
|
|
||||||
|
var stderr io.Writer
|
||||||
|
if input.Stderr == nil {
|
||||||
|
stderr = os.Stderr
|
||||||
|
} else {
|
||||||
|
stderr = input.Stderr
|
||||||
|
}
|
||||||
|
|
||||||
t := term.TTY{
|
t := term.TTY{
|
||||||
In: os.Stdin,
|
In: os.Stdin,
|
||||||
Out: os.Stdout,
|
Out: stdout,
|
||||||
Raw: true,
|
Raw: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
size := t.GetSize()
|
size := t.GetSize()
|
||||||
sizeQueue := t.MonitorSize(size)
|
sizeQueue := t.MonitorSize(size)
|
||||||
|
|
||||||
@@ -356,8 +377,8 @@ func (k KubernetesClient) ExecCommand(ctx context.Context, input ExecCommandInpu
|
|||||||
|
|
||||||
return exec.StreamWithContext(ctx, remotecommand.StreamOptions{
|
return exec.StreamWithContext(ctx, remotecommand.StreamOptions{
|
||||||
Stdin: os.Stdin,
|
Stdin: os.Stdin,
|
||||||
Stdout: os.Stdout,
|
Stdout: stdout,
|
||||||
Stderr: os.Stderr,
|
Stderr: stderr,
|
||||||
Tty: true,
|
Tty: true,
|
||||||
TerminalSizeQueue: sizeQueue,
|
TerminalSizeQueue: sizeQueue,
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -84,6 +84,11 @@ func main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
err = scheduler_k3s.TriggerSchedulerLogs(scheduler, appName, processType, tail, quiet, numLines)
|
err = scheduler_k3s.TriggerSchedulerLogs(scheduler, appName, processType, tail, quiet, numLines)
|
||||||
|
case "scheduler-proxy-config":
|
||||||
|
scheduler := flag.Arg(0)
|
||||||
|
appName := flag.Arg(1)
|
||||||
|
proxyType := flag.Arg(2)
|
||||||
|
err = scheduler_k3s.TriggerSchedulerProxyConfig(scheduler, appName, proxyType)
|
||||||
case "scheduler-proxy-logs":
|
case "scheduler-proxy-logs":
|
||||||
var tail bool
|
var tail bool
|
||||||
var numLines int64
|
var numLines int64
|
||||||
|
|||||||
@@ -1,12 +1,14 @@
|
|||||||
package scheduler_k3s
|
package scheduler_k3s
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
@@ -841,9 +843,102 @@ func TriggerSchedulerLogs(scheduler string, appName string, processType string,
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TriggerSchedulerProxyConfig displays nginx config for a given application
|
||||||
|
func TriggerSchedulerProxyConfig(scheduler string, appName string, proxyType string) error {
|
||||||
|
if scheduler != "k3s" || proxyType != "k3s" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
clientset, err := NewKubernetesClient()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error creating kubernetes client: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
pods, err := clientset.ListPods(context.Background(), ListPodsInput{
|
||||||
|
Namespace: "ingress-nginx",
|
||||||
|
LabelSelector: "app.kubernetes.io/name=ingress-nginx",
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error listing pods: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(pods) == 0 {
|
||||||
|
return errors.New("No pods found for ingress-nginx")
|
||||||
|
}
|
||||||
|
|
||||||
|
var buf bytes.Buffer
|
||||||
|
w := io.MultiWriter(&buf)
|
||||||
|
|
||||||
|
command := []string{"cat", "/etc/nginx/nginx.conf"}
|
||||||
|
err = clientset.ExecCommand(context.Background(), ExecCommandInput{
|
||||||
|
Command: command,
|
||||||
|
ContainerName: "controller",
|
||||||
|
Name: pods[0].Name,
|
||||||
|
Namespace: "ingress-nginx",
|
||||||
|
Stdout: w,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error reading nginx config: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// split buffer string into lines
|
||||||
|
lines := strings.Split(buf.String(), "\n")
|
||||||
|
|
||||||
|
// get every domain block from the nginx config
|
||||||
|
// domain blocks begin with "## start server DOMAIN_NAME" and end with "## end server DOMAIN_NAME"
|
||||||
|
// each line also may have space characters at the beginning
|
||||||
|
domainBlocks := map[string][]string{}
|
||||||
|
for i, line := range lines {
|
||||||
|
strippedLine := strings.TrimSpace(line)
|
||||||
|
if strings.HasPrefix(strippedLine, "## start server ") {
|
||||||
|
domainName := strings.TrimPrefix(strippedLine, "## start server ")
|
||||||
|
domainBlocks[domainName] = []string{}
|
||||||
|
for _, nextLine := range lines[i+1:] {
|
||||||
|
nextStrippedLine := strings.TrimSpace(nextLine)
|
||||||
|
if strings.HasPrefix(nextStrippedLine, "## end server "+domainName) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
domainBlocks[domainName] = append(domainBlocks[domainName], nextLine)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// get all domains for this app
|
||||||
|
domains := []string{}
|
||||||
|
_, err = common.CallPlugnTrigger(common.PlugnTriggerInput{
|
||||||
|
Trigger: "domains-vhost-enabled",
|
||||||
|
Args: []string{appName},
|
||||||
|
StreamStdio: true,
|
||||||
|
})
|
||||||
|
if err == nil {
|
||||||
|
results, err := common.CallPlugnTrigger(common.PlugnTriggerInput{
|
||||||
|
Trigger: "domains-list",
|
||||||
|
Args: []string{appName},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error getting domains for deployment: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, domain := range strings.Split(results.StdoutContents(), "\n") {
|
||||||
|
domain = strings.TrimSpace(domain)
|
||||||
|
if domain != "" {
|
||||||
|
domains = append(domains, domain)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, domain := range domains {
|
||||||
|
if domainBlock, ok := domainBlocks[domain]; ok {
|
||||||
|
fmt.Println(strings.Join(domainBlock, "\n"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
// TriggerSchedulerProxyLogs displays nginx logs for a given application
|
// TriggerSchedulerProxyLogs displays nginx logs for a given application
|
||||||
func TriggerSchedulerProxyLogs(scheduler string, appName string, proxyType string, logType string, tail bool, numLines int64) error {
|
func TriggerSchedulerProxyLogs(scheduler string, appName string, proxyType string, logType string, tail bool, numLines int64) error {
|
||||||
if scheduler != "k3s" || proxyType != "nginx" {
|
if scheduler != "k3s" || proxyType != "k3s" {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user