Skip to content
This repository has been archived by the owner on Mar 24, 2023. It is now read-only.

Commit

Permalink
Merge pull request #793 from dexhorthy/built-kube
Browse files Browse the repository at this point in the history
Add logging and better templating to kubectl step
  • Loading branch information
dexhorthy authored Jan 10, 2019
2 parents 9f9fe11 + ac56c7a commit 6296283
Showing 1 changed file with 47 additions and 19 deletions.
66 changes: 47 additions & 19 deletions pkg/lifecycle/kubectl/daemonless.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,54 +14,44 @@ import (
"github.com/replicatedhq/ship/pkg/api"
"github.com/replicatedhq/ship/pkg/lifecycle"
"github.com/replicatedhq/ship/pkg/lifecycle/daemon/daemontypes"
"github.com/replicatedhq/ship/pkg/state"
"github.com/replicatedhq/ship/pkg/templates"
)

type DaemonlessKubectl struct {
Logger log.Logger
Status daemontypes.StatusReceiver
StateManager state.Manager
BuilderBuilder *templates.BuilderBuilder
}

func NewDaemonlessKubectl(
logger log.Logger,
builderBuilder *templates.BuilderBuilder,
statemanager state.Manager,
) lifecycle.KubectlApply {
return &DaemonlessKubectl{
Logger: logger,
BuilderBuilder: builderBuilder,
StateManager: statemanager,
}
}

func (d *DaemonlessKubectl) WithStatusReceiver(statusReceiver daemontypes.StatusReceiver) lifecycle.KubectlApply {
return &DaemonlessKubectl{
Logger: d.Logger,
BuilderBuilder: d.BuilderBuilder,
StateManager: d.StateManager,
Status: statusReceiver,
}
}

// TODO I need tests
func (d *DaemonlessKubectl) Execute(ctx context.Context, release api.Release, step api.KubectlApply, confirmedChan chan bool) error {
builder, err := d.BuilderBuilder.BaseBuilder(release.Metadata)
if err != nil {
return errors.Wrap(err, "get builder")
}

builtPath, _ := builder.String(step.Path)
builtKubePath, _ := builder.String(step.Kubeconfig)

debug := level.Debug(log.With(d.Logger, "step.type", "kubectl"))

if builtPath == "" {
return errors.New("A path to apply is required")
}

cmd := exec.Command("kubectl")
cmd.Dir = release.FindRenderRoot()
cmd.Args = append(cmd.Args, "apply", "-f", step.Path)
if step.Kubeconfig != "" {
cmd.Args = append(cmd.Args, "--kubeconfig", builtKubePath)
}
cmd, err := d.prepareCmd(release, step)
debug.Log("event", "kubectl.execute", "args", fmt.Sprintf("%+v", cmd.Args))

var stderr bytes.Buffer
cmd.Stderr = &stderr
Expand All @@ -72,6 +62,7 @@ func (d *DaemonlessKubectl) Execute(ctx context.Context, release api.Release, st
doneCh := make(chan struct{})
messageCh := make(chan daemontypes.Message)
go d.Status.PushStreamStep(ctx, messageCh)
debug.Log("event", "kubectl.streamStep.pushed")

stderrString := ""
stdoutString := ""
Expand All @@ -93,8 +84,10 @@ func (d *DaemonlessKubectl) Execute(ctx context.Context, release api.Release, st
Contents: ansiToHTML(stdoutString, stderrString),
TrustedHTML: true,
}
debug.Log("event", "kubectl.message.pushed")
}
case <-doneCh:
debug.Log("event", "kubectl.doneCh")
stderrString = stderr.String()
stdoutString = stdout.String()
close(messageCh)
Expand All @@ -113,8 +106,9 @@ func (d *DaemonlessKubectl) Execute(ctx context.Context, release api.Release, st
debug.Log("stderr", stderrString)

if err != nil {
debug.Log("event", "kubectl.run.error", "err", err)
stderrString = fmt.Sprintf(`Error: %s
stderr: %s`, err.Error(), stderrString)
stderr: %s`, err.Error(), stderrString)
}

d.Status.PushMessageStep(
Expand All @@ -125,10 +119,44 @@ stderr: %s`, err.Error(), stderrString)
},
confirmActions(),
)
debug.Log("event", "kubectl.outputs.pushed", "next", "confirmed.await")

return d.awaitMessageConfirmed(ctx, confirmedChan)
}

func (d *DaemonlessKubectl) prepareCmd(release api.Release, step api.KubectlApply) (*exec.Cmd, error) {
currState, err := d.StateManager.TryLoad()
if err != nil {
return nil, errors.Wrap(err, "load state")
}

builder, err := d.BuilderBuilder.FullBuilder(release.Metadata, release.Spec.Config.V1, currState.CurrentConfig())
if err != nil {
return nil, errors.Wrap(err, "get builder")
}

builtPath, err := builder.String(step.Path)
if err != nil {
return nil, errors.Wrapf(err, "build apply path %s", step.Path)
}
builtKubePath, err := builder.String(step.Kubeconfig)
if err != nil {
return nil, errors.Wrapf(err, "build kubeconfig path %s", step.Kubeconfig)
}

if builtPath == "" {
return nil, errors.New("A path to apply is required")
}

cmd := exec.Command("kubectl")
cmd.Dir = release.FindRenderRoot()
cmd.Args = append(cmd.Args, "apply", "-f", builtPath)
if step.Kubeconfig != "" {
cmd.Args = append(cmd.Args, "--kubeconfig", builtKubePath)
}
return cmd, nil
}

func (d *DaemonlessKubectl) awaitMessageConfirmed(ctx context.Context, confirmedChan chan bool) error {
debug := level.Debug(log.With(d.Logger, "struct", "daemonlesskubectl", "method", "awaitMessageConfirmed"))
for {
Expand Down

0 comments on commit 6296283

Please sign in to comment.