Added kubeadm init

This commit is contained in:
2026-03-30 01:31:38 +08:00
parent 5fbc2846a1
commit 210fabdcc6
7 changed files with 419 additions and 102 deletions

View File

@@ -1,6 +1,7 @@
package system
import (
"bufio"
"bytes"
"context"
"errors"
@@ -54,6 +55,10 @@ type RunOptions struct {
Stderr io.Writer
Quiet bool
RedactEnv []string
// Optional line hooks. Called for each complete line seen on stdout/stderr.
OnStdoutLine func(line string)
OnStderrLine func(line string)
}
type RetryOptions struct {
@@ -86,23 +91,30 @@ func (r *Runner) RunWithOptions(ctx context.Context, name string, args []string,
var stdoutBuf bytes.Buffer
var stderrBuf bytes.Buffer
stdoutW := io.Writer(&stdoutBuf)
stderrW := io.Writer(&stderrBuf)
stdoutDst := io.Writer(&stdoutBuf)
stderrDst := io.Writer(&stderrBuf)
if opt.Stdout != nil {
stdoutW = io.MultiWriter(stdoutW, opt.Stdout)
stdoutDst = io.MultiWriter(stdoutDst, opt.Stdout)
} else if r.cfg.StreamOutput && !opt.Quiet {
stdoutW = io.MultiWriter(stdoutW, os.Stdout)
stdoutDst = io.MultiWriter(stdoutDst, os.Stdout)
}
if opt.Stderr != nil {
stderrW = io.MultiWriter(stderrW, opt.Stderr)
stderrDst = io.MultiWriter(stderrDst, opt.Stderr)
} else if r.cfg.StreamOutput && !opt.Quiet {
stderrW = io.MultiWriter(stderrW, os.Stderr)
stderrDst = io.MultiWriter(stderrDst, os.Stderr)
}
cmd.Stdout = stdoutW
cmd.Stderr = stderrW
if opt.OnStdoutLine != nil {
stdoutDst = newLineHookWriter(stdoutDst, opt.OnStdoutLine)
}
if opt.OnStderrLine != nil {
stderrDst = newLineHookWriter(stderrDst, opt.OnStderrLine)
}
cmd.Stdout = stdoutDst
cmd.Stderr = stderrDst
start := time.Now()
if r.cfg.Logger != nil {
@@ -110,6 +122,13 @@ func (r *Runner) RunWithOptions(ctx context.Context, name string, args []string,
}
err := cmd.Run()
if hw, ok := stdoutDst.(interface{ Flush() }); ok {
hw.Flush()
}
if hw, ok := stderrDst.(interface{ Flush() }); ok {
hw.Flush()
}
end := time.Now()
res := &Result{
@@ -344,3 +363,61 @@ func (l *StdLogger) Printf(format string, args ...any) {
defer l.mu.Unlock()
fmt.Fprintf(os.Stderr, format+"\n", args...)
}
type lineHookWriter struct {
dst io.Writer
fn func(string)
mu sync.Mutex
buf bytes.Buffer
}
func newLineHookWriter(dst io.Writer, fn func(string)) *lineHookWriter {
return &lineHookWriter{
dst: dst,
fn: fn,
}
}
func (w *lineHookWriter) Write(p []byte) (int, error) {
w.mu.Lock()
defer w.mu.Unlock()
n, err := w.dst.Write(p)
// Keep line processing separate from dst write result.
w.buf.Write(p)
w.flushCompleteLinesLocked()
return n, err
}
func (w *lineHookWriter) flushCompleteLinesLocked() {
r := bufio.NewReader(&w.buf)
var pending bytes.Buffer
for {
line, err := r.ReadString('\n')
if err == io.EOF {
pending.WriteString(line)
break
}
line = strings.TrimRight(line, "\r\n")
w.fn(line)
}
w.buf.Reset()
_, _ = w.buf.Write(pending.Bytes())
}
// Flush emits the final unterminated line, if any.
// Not strictly required for kubeadm, but useful and correct.
func (w *lineHookWriter) Flush() {
w.mu.Lock()
defer w.mu.Unlock()
if w.buf.Len() == 0 {
return
}
w.fn(strings.TrimRight(w.buf.String(), "\r\n"))
w.buf.Reset()
}