mirror of
https://github.com/dokku/dokku.git
synced 2026-08-29 10:08:53 +02:00
The dynamic `dns-provider-*` properties were reported as `--traefik-dns-provider-<env_var>`, outside the `global`/`computed` namespace every other traefik property uses, so a consumer reading the json report could not tell which of the two a key represented. They are now reported as `--traefik-global-dns-provider-<env_var>`. The `basic-auth-password` property is a credential as well and is now masked in the default report output on the same terms as the dns provider values, meaning the raw value is returned only for `--format json` or when the flag is queried by name.
305 lines
9.4 KiB
Go
305 lines
9.4 KiB
Go
package traefikvhosts
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
|
|
"github.com/dokku/dokku/plugins/common"
|
|
)
|
|
|
|
// valueMask is shown in place of credential values in the default stdout report
|
|
const valueMask = "*******"
|
|
|
|
// ReportSingleApp is an internal function that displays the traefik report for one or more apps
|
|
func ReportSingleApp(appName string, format string, infoFlag string) error {
|
|
if appName != "--global" {
|
|
if err := common.VerifyAppName(appName); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
flags := map[string]common.ReportFunc{
|
|
"--traefik-computed-api-enabled": reportComputedAPIEnabled,
|
|
"--traefik-computed-api-entry-point": reportComputedAPIEntryPoint,
|
|
"--traefik-computed-api-entry-point-address": reportComputedAPIEntryPointAddress,
|
|
"--traefik-computed-api-vhost": reportComputedAPIVhost,
|
|
"--traefik-computed-basic-auth-password": reportComputedBasicAuthPassword,
|
|
"--traefik-computed-basic-auth-username": reportComputedBasicAuthUsername,
|
|
"--traefik-computed-challenge-mode": reportComputedChallengeMode,
|
|
"--traefik-computed-dashboard-enabled": reportComputedDashboardEnabled,
|
|
"--traefik-computed-dns-provider": reportComputedDNSProvider,
|
|
"--traefik-computed-http-entry-point": reportComputedHTTPEntryPoint,
|
|
"--traefik-computed-https-entry-point": reportComputedHTTPSEntryPoint,
|
|
"--traefik-computed-image": reportComputedImage,
|
|
"--traefik-computed-letsencrypt-email": reportComputedLetsencryptEmail,
|
|
"--traefik-computed-letsencrypt-server": reportComputedLetsencryptServer,
|
|
"--traefik-computed-log-level": reportComputedLogLevel,
|
|
"--traefik-global-api-enabled": reportGlobalAPIEnabled,
|
|
"--traefik-global-api-entry-point": reportGlobalAPIEntryPoint,
|
|
"--traefik-global-api-entry-point-address": reportGlobalAPIEntryPointAddress,
|
|
"--traefik-global-api-vhost": reportGlobalAPIVhost,
|
|
"--traefik-global-basic-auth-password": reportGlobalBasicAuthPassword,
|
|
"--traefik-global-basic-auth-username": reportGlobalBasicAuthUsername,
|
|
"--traefik-global-challenge-mode": reportGlobalChallengeMode,
|
|
"--traefik-global-dashboard-enabled": reportGlobalDashboardEnabled,
|
|
"--traefik-global-dns-provider": reportGlobalDNSProvider,
|
|
"--traefik-global-http-entry-point": reportGlobalHTTPEntryPoint,
|
|
"--traefik-global-https-entry-point": reportGlobalHTTPSEntryPoint,
|
|
"--traefik-global-image": reportGlobalImage,
|
|
"--traefik-global-letsencrypt-email": reportGlobalLetsencryptEmail,
|
|
"--traefik-global-letsencrypt-server": reportGlobalLetsencryptServer,
|
|
"--traefik-global-log-level": reportGlobalLogLevel,
|
|
}
|
|
|
|
for _, flagName := range []string{"--traefik-computed-basic-auth-password", "--traefik-global-basic-auth-password"} {
|
|
flags[flagName] = maskedReportFunc(flags[flagName], flagName, format, infoFlag)
|
|
}
|
|
|
|
dnsProviderFlags, err := dnsProviderReportFlags(format, infoFlag)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
for flagName, reportFunc := range dnsProviderFlags {
|
|
flags[flagName] = reportFunc
|
|
}
|
|
|
|
flagKeys := []string{}
|
|
for flagKey := range flags {
|
|
flagKeys = append(flagKeys, flagKey)
|
|
}
|
|
|
|
infoFlags := common.CollectReport(appName, infoFlag, flags)
|
|
return common.ReportSingleApp(common.ReportSingleAppInput{
|
|
ReportType: "traefik",
|
|
AppName: appName,
|
|
InfoFlag: infoFlag,
|
|
InfoFlags: infoFlags,
|
|
InfoFlagKeys: flagKeys,
|
|
Format: format,
|
|
TrimPrefix: true,
|
|
UppercaseFirstCharacter: true,
|
|
EmitLegacyPrefix: false,
|
|
})
|
|
}
|
|
|
|
// maskedReportFunc hides a credential value behind valueMask so the default stdout
|
|
// report - and thus the aggregate `dokku report` - never prints it. The raw value is
|
|
// returned for machine-readable output or when the flag is requested by name.
|
|
func maskedReportFunc(fn common.ReportFunc, flagName string, format string, infoFlag string) common.ReportFunc {
|
|
if format == "json" || infoFlag == flagName {
|
|
return fn
|
|
}
|
|
|
|
return func(appName string) string {
|
|
if fn(appName) == "" {
|
|
return ""
|
|
}
|
|
|
|
return valueMask
|
|
}
|
|
}
|
|
|
|
// dnsProviderReportFlags returns report functions for the dynamic dns-provider-*
|
|
// properties, keyed by their global report flag
|
|
func dnsProviderReportFlags(format string, infoFlag string) (map[string]common.ReportFunc, error) {
|
|
flags := map[string]common.ReportFunc{}
|
|
properties, err := common.PropertyGetAllByPrefix("traefik", "--global", "dns-provider-")
|
|
if err != nil {
|
|
return flags, err
|
|
}
|
|
|
|
for property, value := range properties {
|
|
flagName := "--traefik-global-" + property
|
|
flags[flagName] = maskedReportFunc(func(string) string { return value }, flagName, format, infoFlag)
|
|
}
|
|
|
|
return flags, nil
|
|
}
|
|
|
|
func reportGlobalAPIEnabled(appName string) string {
|
|
return common.PropertyGet("traefik", "--global", "api-enabled")
|
|
}
|
|
|
|
func reportComputedAPIEnabled(appName string) string {
|
|
value := reportGlobalAPIEnabled(appName)
|
|
if value == "" {
|
|
value = "false"
|
|
}
|
|
|
|
return value
|
|
}
|
|
|
|
func reportGlobalAPIEntryPoint(appName string) string {
|
|
return common.PropertyGet("traefik", "--global", "api-entry-point")
|
|
}
|
|
|
|
func reportComputedAPIEntryPoint(appName string) string {
|
|
return reportGlobalAPIEntryPoint(appName)
|
|
}
|
|
|
|
func reportGlobalAPIEntryPointAddress(appName string) string {
|
|
return common.PropertyGet("traefik", "--global", "api-entry-point-address")
|
|
}
|
|
|
|
func reportComputedAPIEntryPointAddress(appName string) string {
|
|
return reportGlobalAPIEntryPointAddress(appName)
|
|
}
|
|
|
|
func reportGlobalAPIVhost(appName string) string {
|
|
return common.PropertyGet("traefik", "--global", "api-vhost")
|
|
}
|
|
|
|
func reportComputedAPIVhost(appName string) string {
|
|
value := reportGlobalAPIVhost(appName)
|
|
if value == "" {
|
|
value = "traefik.dokku.me"
|
|
}
|
|
|
|
return value
|
|
}
|
|
|
|
func reportGlobalBasicAuthPassword(appName string) string {
|
|
return common.PropertyGet("traefik", "--global", "basic-auth-password")
|
|
}
|
|
|
|
func reportComputedBasicAuthPassword(appName string) string {
|
|
return reportGlobalBasicAuthPassword(appName)
|
|
}
|
|
|
|
func reportGlobalBasicAuthUsername(appName string) string {
|
|
return common.PropertyGet("traefik", "--global", "basic-auth-username")
|
|
}
|
|
|
|
func reportComputedBasicAuthUsername(appName string) string {
|
|
return reportGlobalBasicAuthUsername(appName)
|
|
}
|
|
|
|
func reportGlobalChallengeMode(appName string) string {
|
|
return common.PropertyGet("traefik", "--global", "challenge-mode")
|
|
}
|
|
|
|
func reportComputedChallengeMode(appName string) string {
|
|
value := reportGlobalChallengeMode(appName)
|
|
if value == "" {
|
|
value = "tls"
|
|
}
|
|
|
|
return value
|
|
}
|
|
|
|
func reportGlobalDashboardEnabled(appName string) string {
|
|
return common.PropertyGet("traefik", "--global", "dashboard-enabled")
|
|
}
|
|
|
|
func reportComputedDashboardEnabled(appName string) string {
|
|
value := reportGlobalDashboardEnabled(appName)
|
|
if value == "" {
|
|
value = "false"
|
|
}
|
|
|
|
return value
|
|
}
|
|
|
|
func reportGlobalDNSProvider(appName string) string {
|
|
return common.PropertyGet("traefik", "--global", "dns-provider")
|
|
}
|
|
|
|
func reportComputedDNSProvider(appName string) string {
|
|
return reportGlobalDNSProvider(appName)
|
|
}
|
|
|
|
func reportGlobalHTTPEntryPoint(appName string) string {
|
|
return common.PropertyGet("traefik", "--global", "http-entry-point")
|
|
}
|
|
|
|
func reportComputedHTTPEntryPoint(appName string) string {
|
|
value := reportGlobalHTTPEntryPoint(appName)
|
|
if value == "" {
|
|
value = "http"
|
|
}
|
|
|
|
return value
|
|
}
|
|
|
|
func reportGlobalHTTPSEntryPoint(appName string) string {
|
|
return common.PropertyGet("traefik", "--global", "https-entry-point")
|
|
}
|
|
|
|
func reportComputedHTTPSEntryPoint(appName string) string {
|
|
value := reportGlobalHTTPSEntryPoint(appName)
|
|
if value == "" {
|
|
value = "https"
|
|
}
|
|
|
|
return value
|
|
}
|
|
|
|
func reportGlobalImage(appName string) string {
|
|
return common.PropertyGet("traefik", "--global", "image")
|
|
}
|
|
|
|
func reportComputedImage(appName string) string {
|
|
value := reportGlobalImage(appName)
|
|
if value == "" {
|
|
value = dockerfileFromImage("traefik-vhosts")
|
|
}
|
|
|
|
return value
|
|
}
|
|
|
|
func reportGlobalLetsencryptEmail(appName string) string {
|
|
return common.PropertyGet("traefik", "--global", "letsencrypt-email")
|
|
}
|
|
|
|
func reportComputedLetsencryptEmail(appName string) string {
|
|
return reportGlobalLetsencryptEmail(appName)
|
|
}
|
|
|
|
func reportGlobalLetsencryptServer(appName string) string {
|
|
return common.PropertyGet("traefik", "--global", "letsencrypt-server")
|
|
}
|
|
|
|
func reportComputedLetsencryptServer(appName string) string {
|
|
value := reportGlobalLetsencryptServer(appName)
|
|
if value == "" {
|
|
value = "https://acme-v02.api.letsencrypt.org/directory"
|
|
}
|
|
|
|
return value
|
|
}
|
|
|
|
func reportGlobalLogLevel(appName string) string {
|
|
return common.PropertyGet("traefik", "--global", "log-level")
|
|
}
|
|
|
|
func reportComputedLogLevel(appName string) string {
|
|
value := reportGlobalLogLevel(appName)
|
|
if value == "" {
|
|
value = "ERROR"
|
|
}
|
|
|
|
return strings.ToUpper(value)
|
|
}
|
|
|
|
// dockerfileFromImage returns the image referenced by the FROM line of the named
|
|
// plugin's Dockerfile, or an empty string when it cannot be read
|
|
func dockerfileFromImage(pluginName string) string {
|
|
pluginPath := os.Getenv("PLUGIN_AVAILABLE_PATH")
|
|
data, err := os.ReadFile(filepath.Join(pluginPath, pluginName, "Dockerfile"))
|
|
if err != nil {
|
|
return ""
|
|
}
|
|
|
|
for _, line := range strings.Split(string(data), "\n") {
|
|
if strings.Contains(line, "FROM") {
|
|
fields := strings.Fields(line)
|
|
if len(fields) >= 2 {
|
|
return fields[1]
|
|
}
|
|
}
|
|
}
|
|
|
|
return ""
|
|
}
|