Added kubeadm init
This commit is contained in:
@@ -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()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user