Merge pull request #132177 from pgimalac/apiserver-avoid-template-for-dce

Remove use of html/template in apiserver to avoid disabling dead code elimination
This commit is contained in:
Kubernetes Prow Robot
2025-06-13 09:00:57 -07:00
committed by GitHub
6 changed files with 50 additions and 67 deletions

View File

@@ -19,7 +19,7 @@ package util
import (
"bytes"
"crypto/x509"
"html/template"
"html/template" //nolint:depguard
"strings"
"k8s.io/client-go/tools/clientcmd"

View File

@@ -254,6 +254,8 @@ linters:
deny:
- pkg: "github.com/google/go-cmp/cmp"
desc: "cmp is allowed only in test files"
- pkg: "html/template"
desc: "template is allowed only in test files as it disables dead code elimination"
forbidigo:
analyze-types: true
forbid:

View File

@@ -268,6 +268,8 @@ linters:
deny:
- pkg: "github.com/google/go-cmp/cmp"
desc: "cmp is allowed only in test files"
- pkg: "html/template"
desc: "template is allowed only in test files as it disables dead code elimination"
forbidigo:
analyze-types: true
forbid:

View File

@@ -198,6 +198,8 @@ linters:
deny:
- pkg: "github.com/google/go-cmp/cmp"
desc: "cmp is allowed only in test files"
- pkg: "html/template"
desc: "template is allowed only in test files as it disables dead code elimination"
forbidigo:
analyze-types: true
forbid:

View File

@@ -18,7 +18,7 @@ package routes
import (
"fmt"
"html/template"
"html/template" //nolint:depguard
"io"
"net/http"
"path"
@@ -56,12 +56,15 @@ func (f DebugFlags) Install(c *mux.PathRecorderMux, flag string, handler func(ht
func (f DebugFlags) Index(w http.ResponseWriter, r *http.Request) {
lock.RLock()
defer lock.RUnlock()
if err := indexTmpl.Execute(w, registeredFlags); err != nil {
if err := indexTmpl(w, registeredFlags); err != nil {
klog.Error(err)
}
}
var indexTmpl = template.Must(template.New("index").Parse(`<html>
func indexTmpl(w io.Writer, flags map[string]debugFlag) error {
// avoid using a template to avoid disabling dead code elimination
// https://github.com/golang/go/issues/72895
_, err := w.Write([]byte(`<html>
<head>
<title>/debug/flags/</title>
</head>
@@ -70,15 +73,27 @@ var indexTmpl = template.Must(template.New("index").Parse(`<html>
<br>
flags:<br>
<table>
{{range .}}
<tr>{{.Flag}}<br>
{{end}}
</table>
`))
if err != nil {
return err
}
for _, flag := range flags {
_, err := fmt.Fprintf(w, `<tr>%s<br>
`, template.HTMLEscapeString(flag.Flag))
if err != nil {
return err
}
}
_, err = w.Write([]byte(`</table>
<br>
full flags configurable<br>
</body>
</html>
`))
return err
}
type debugFlag struct {
Flag string

View File

@@ -17,9 +17,8 @@ limitations under the License.
package statusz
import (
"bytes"
"fmt"
"html/template"
"html"
"math/rand"
"net/http"
"time"
@@ -35,30 +34,11 @@ var (
const DefaultStatuszPath = "/statusz"
const (
headerFmt = `
const headerFmt = `
%s statusz
Warning: This endpoint is not meant to be machine parseable, has no formatting compatibility guarantees and is for debugging purposes only.
`
dataTemplate = `
Started{{.Delim}} {{.StartTime}}
Up{{.Delim}} {{.Uptime}}
Go version{{.Delim}} {{.GoVersion}}
Binary version{{.Delim}} {{.BinaryVersion}}
{{if .EmulationVersion}}Emulation version{{.Delim}} {{.EmulationVersion}}{{end}}
`
)
type contentFields struct {
Delim string
StartTime string
Uptime string
GoVersion string
BinaryVersion string
EmulationVersion string
}
type mux interface {
Handle(path string, handler http.Handler)
}
@@ -68,25 +48,10 @@ func NewRegistry(effectiveVersion compatibility.EffectiveVersion) statuszRegistr
}
func Install(m mux, componentName string, reg statuszRegistry) {
dataTmpl, err := initializeTemplates()
if err != nil {
klog.Errorf("error while parsing gotemplates: %v", err)
return
}
m.Handle(DefaultStatuszPath, handleStatusz(componentName, dataTmpl, reg))
m.Handle(DefaultStatuszPath, handleStatusz(componentName, reg))
}
func initializeTemplates() (*template.Template, error) {
d := template.New("data")
dataTmpl, err := d.Parse(dataTemplate)
if err != nil {
return nil, err
}
return dataTmpl, nil
}
func handleStatusz(componentName string, dataTmpl *template.Template, reg statuszRegistry) http.HandlerFunc {
func handleStatusz(componentName string, reg statuszRegistry) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
if !httputil.AcceptableMediaType(r) {
http.Error(w, httputil.ErrUnsupportedMediaType.Error(), http.StatusNotAcceptable)
@@ -94,7 +59,7 @@ func handleStatusz(componentName string, dataTmpl *template.Template, reg status
}
fmt.Fprintf(w, headerFmt, componentName)
data, err := populateStatuszData(dataTmpl, reg)
data, err := populateStatuszData(reg)
if err != nil {
klog.Errorf("error while populating statusz data: %v", err)
http.Error(w, "error while populating statusz data", http.StatusInternalServerError)
@@ -106,31 +71,28 @@ func handleStatusz(componentName string, dataTmpl *template.Template, reg status
}
}
func populateStatuszData(tmpl *template.Template, reg statuszRegistry) (string, error) {
if tmpl == nil {
return "", fmt.Errorf("received nil template")
}
func populateStatuszData(reg statuszRegistry) (string, error) {
randomIndex := rand.Intn(len(delimiters))
data := contentFields{
Delim: delimiters[randomIndex],
StartTime: reg.processStartTime().Format(time.UnixDate),
Uptime: uptime(reg.processStartTime()),
GoVersion: reg.goVersion(),
BinaryVersion: reg.binaryVersion().String(),
}
delim := html.EscapeString(delimiters[randomIndex])
startTime := html.EscapeString(reg.processStartTime().Format(time.UnixDate))
uptime := html.EscapeString(uptime(reg.processStartTime()))
goVersion := html.EscapeString(reg.goVersion())
binaryVersion := html.EscapeString(reg.binaryVersion().String())
var emulationVersion string
if reg.emulationVersion() != nil {
data.EmulationVersion = reg.emulationVersion().String()
emulationVersion = fmt.Sprintf(`Emulation version%s %s`, delim, html.EscapeString(reg.emulationVersion().String()))
}
var tpl bytes.Buffer
err := tmpl.Execute(&tpl, data)
if err != nil {
return "", fmt.Errorf("error executing statusz template: %w", err)
}
status := fmt.Sprintf(`
Started%[1]s %[2]s
Up%[1]s %[3]s
Go version%[1]s %[4]s
Binary version%[1]s %[5]s
%[6]s
`, delim, startTime, uptime, goVersion, binaryVersion, emulationVersion)
return tpl.String(), nil
return status, nil
}
func uptime(t time.Time) string {