-
Notifications
You must be signed in to change notification settings - Fork 138
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add virtual tink worker command ## Description * Add a no-op tinkerbell worker ## Why is this needed This worker is helpful if you want to test Tinkerbell API changes while not actually executing a worker that executes docker containers. Fixes: # ## How Has This Been Tested? Tested locally against the Tinkerbell API. I'll have an E2E test in a future PR that uses the no-op logger and container manager. ## How are existing users impacted? What migration steps/scripts do we need? No impact to existing users. ## Checklist: I have: - [ ] updated the documentation and/or roadmap (if required) - [ ] added unit or e2e tests - [ ] provided instructions on how to upgrade
- Loading branch information
Showing
9 changed files
with
269 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
virtual-worker | ||
virtual-worker-* |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
FROM alpine:3.15 | ||
ENTRYPOINT [ "/usr/bin/virtual-worker" ] | ||
|
||
ARG TARGETARCH | ||
ARG TARGETVARIANT | ||
|
||
RUN apk add --no-cache --update --upgrade ca-certificates | ||
COPY virtual-worker-linux-${TARGETARCH:-amd64}${TARGETVARIANT} /usr/bin/virtual-worker |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
package cmd | ||
|
||
import ( | ||
"strings" | ||
"time" | ||
|
||
"github.com/packethost/pkg/log" | ||
"github.com/pkg/errors" | ||
"github.com/spf13/cobra" | ||
"github.com/spf13/pflag" | ||
"github.com/spf13/viper" | ||
"github.com/tinkerbell/tink/client" | ||
tinkWorker "github.com/tinkerbell/tink/cmd/tink-worker/worker" | ||
"github.com/tinkerbell/tink/cmd/virtual-worker/worker" | ||
"github.com/tinkerbell/tink/protos/workflow" | ||
) | ||
|
||
const ( | ||
defaultRetryIntervalSeconds = 3 | ||
defaultRetryCount = 3 | ||
defaultMaxFileSize = 10 * 1024 * 1024 // 10MB | ||
) | ||
|
||
// NewRootCommand creates a new Virtual Worker Cobra root command. | ||
func NewRootCommand(version string, logger log.Logger) *cobra.Command { | ||
rootCmd := &cobra.Command{ | ||
Use: "virtual-worker", | ||
Short: "Virtual Tink Worker", | ||
PreRunE: func(cmd *cobra.Command, args []string) error { | ||
return createViper(logger, cmd) | ||
}, | ||
RunE: func(cmd *cobra.Command, args []string) error { | ||
retryInterval := viper.GetDuration("retry-interval") | ||
retries := viper.GetInt("max-retry") | ||
workerID := viper.GetString("id") | ||
maxFileSize := viper.GetInt64("max-file-size") | ||
captureActionLogs := viper.GetBool("capture-action-logs") | ||
sleepMin := viper.GetDuration("sleep-min") | ||
sleepJitter := viper.GetDuration("sleep-jitter") | ||
|
||
logger.With("version", version).Info("starting") | ||
|
||
conn, err := client.NewClientConn( | ||
viper.GetString("tinkerbell-grpc-authority"), | ||
viper.GetBool("tinkerbell-tls"), | ||
) | ||
if err != nil { | ||
return err | ||
} | ||
workflowClient := workflow.NewWorkflowServiceClient(conn) | ||
|
||
containerManager := worker.NewFakeContainerManager(logger, sleepMin, sleepJitter) | ||
logCapturer := worker.NewEmptyLogCapturer() | ||
|
||
w := tinkWorker.NewWorker( | ||
workerID, | ||
workflowClient, | ||
containerManager, | ||
logCapturer, | ||
logger, | ||
tinkWorker.WithMaxFileSize(maxFileSize), | ||
tinkWorker.WithRetries(retryInterval, retries), | ||
tinkWorker.WithLogCapture(captureActionLogs)) | ||
|
||
err = w.ProcessWorkflowActions(cmd.Context()) | ||
if err != nil { | ||
return errors.Wrap(err, "worker Finished with error") | ||
} | ||
return nil | ||
}, | ||
} | ||
|
||
rootCmd.Flags().Duration("retry-interval", defaultRetryIntervalSeconds*time.Second, "Retry interval in seconds (RETRY_INTERVAL)") | ||
rootCmd.Flags().Int("max-retry", defaultRetryCount, "Maximum number of retries to attempt (MAX_RETRY)") | ||
rootCmd.Flags().Int64("max-file-size", defaultMaxFileSize, "Maximum file size in bytes (MAX_FILE_SIZE)") | ||
rootCmd.Flags().Bool("capture-action-logs", true, "Capture action container output as part of worker logs") | ||
rootCmd.Flags().Duration("sleep-min", time.Second*4, "The minimum amount of time to sleep during faked docker operations") | ||
rootCmd.Flags().Duration("sleep-jitter", time.Second*2, "The amount of jitter to add during faked docker operations") | ||
|
||
must := func(err error) { | ||
if err != nil { | ||
logger.Fatal(err) | ||
} | ||
} | ||
|
||
rootCmd.Flags().StringP("id", "i", "", "Sets the worker id (ID)") | ||
must(rootCmd.MarkFlagRequired("id")) | ||
|
||
_ = viper.BindPFlags(rootCmd.Flags()) | ||
|
||
return rootCmd | ||
} | ||
|
||
// createViper creates a Viper object configured to read in configuration files | ||
// (from various paths with content type specific filename extensions) and loads | ||
// environment variables. | ||
func createViper(logger log.Logger, cmd *cobra.Command) error { | ||
viper.AutomaticEnv() | ||
viper.SetConfigName("virtual-worker") | ||
viper.AddConfigPath("/etc/tinkerbell") | ||
viper.AddConfigPath(".") | ||
viper.SetEnvKeyReplacer(strings.NewReplacer("-", "_")) | ||
|
||
// If a config file is found, read it in. | ||
if err := viper.ReadInConfig(); err != nil { | ||
if _, ok := err.(viper.ConfigFileNotFoundError); !ok { | ||
logger.With("configFile", viper.ConfigFileUsed()).Error(err, "could not load config file") | ||
return err | ||
} | ||
logger.Info("no config file found") | ||
} else { | ||
logger.With("configFile", viper.ConfigFileUsed()).Info("loaded config file") | ||
} | ||
|
||
cmd.Flags().VisitAll(func(f *pflag.Flag) { | ||
if viper.IsSet(f.Name) { | ||
_ = cmd.Flags().SetAnnotation(f.Name, cobra.BashCompOneRequiredFlag, []string{"false"}) | ||
} | ||
}) | ||
|
||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
package main | ||
|
||
import ( | ||
"os" | ||
|
||
"github.com/packethost/pkg/log" | ||
"github.com/tinkerbell/tink/cmd/virtual-worker/cmd" | ||
) | ||
|
||
const ( | ||
serviceKey = "github.com/tinkerbell/tink" | ||
) | ||
|
||
// version is set at build time. | ||
var version = "devel" | ||
|
||
func main() { | ||
logger, err := log.Init(serviceKey) | ||
if err != nil { | ||
panic(err) | ||
} | ||
rootCmd := cmd.NewRootCommand(version, logger) | ||
if err := rootCmd.Execute(); err != nil { | ||
os.Exit(1) | ||
} | ||
logger.Close() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
package worker | ||
|
||
import ( | ||
"context" | ||
"math/rand" | ||
"time" | ||
|
||
"github.com/packethost/pkg/log" | ||
"github.com/tinkerbell/tink/cmd/tink-worker/worker" | ||
pb "github.com/tinkerbell/tink/protos/workflow" | ||
) | ||
|
||
func getRandHexStr(r *rand.Rand, length int) string { | ||
alphabet := []byte("1234567890abcdef") | ||
resp := []byte{} | ||
for i := 0; i < length; i++ { | ||
resp = append(resp, alphabet[r.Intn(len(alphabet))]) | ||
} | ||
return string(resp) | ||
} | ||
|
||
type fakeManager struct { | ||
// minimum milliseconds to sleep for faked Docker API calls | ||
sleepMinimum time.Duration | ||
// additional jitter milliseconds to sleep for faked Docker API calls | ||
sleepJitter time.Duration | ||
|
||
r *rand.Rand | ||
logger log.Logger | ||
} | ||
|
||
func (m *fakeManager) sleep() { | ||
jitter := time.Duration(m.r.Int31n(int32(m.sleepJitter.Milliseconds()))) * time.Millisecond | ||
time.Sleep(jitter + m.sleepMinimum) | ||
} | ||
|
||
// NewFakeContainerManager returns a fake worker.ContainerManager that will sleep for Docker API calls. | ||
func NewFakeContainerManager(l log.Logger, sleepMinimum, sleepJitter time.Duration) worker.ContainerManager { | ||
return &fakeManager{ | ||
sleepMinimum: sleepMinimum, | ||
sleepJitter: sleepJitter, | ||
logger: l, | ||
// intentionally weak RNG. This is only for fake output | ||
r: rand.New(rand.NewSource(time.Now().UnixNano())), | ||
} | ||
} | ||
|
||
func (m *fakeManager) CreateContainer(_ context.Context, cmd []string, _ string, _ *pb.WorkflowAction, _, _ bool) (string, error) { | ||
m.logger.With("command", cmd).Info("creating container") | ||
return getRandHexStr(m.r, 64), nil | ||
} | ||
|
||
func (m *fakeManager) StartContainer(_ context.Context, id string) error { | ||
m.logger.With("containerID", id).Debug("starting container") | ||
return nil | ||
} | ||
|
||
func (m *fakeManager) WaitForContainer(_ context.Context, id string) (pb.State, error) { | ||
m.logger.With("containerID", id).Info("waiting for container") | ||
m.sleep() | ||
|
||
return pb.State_STATE_SUCCESS, nil | ||
} | ||
|
||
func (m *fakeManager) WaitForFailedContainer(_ context.Context, id string, failedActionStatus chan pb.State) { | ||
m.logger.With("containerID", id).Info("waiting for container") | ||
m.sleep() | ||
failedActionStatus <- pb.State_STATE_SUCCESS | ||
} | ||
|
||
func (m *fakeManager) RemoveContainer(_ context.Context, id string) error { | ||
m.logger.With("containerID", id).Info("removing container") | ||
return nil | ||
} | ||
|
||
func (m *fakeManager) PullImage(_ context.Context, image string) error { | ||
m.logger.With("image", image).Info("pulling image") | ||
m.sleep() | ||
|
||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
package worker | ||
|
||
import ( | ||
"context" | ||
|
||
"github.com/tinkerbell/tink/cmd/tink-worker/worker" | ||
) | ||
|
||
type emptyLogger struct{} | ||
|
||
func (l *emptyLogger) CaptureLogs(context.Context, string) {} | ||
|
||
// NewEmptyLogCapturer returns an no-op log capturer. | ||
func NewEmptyLogCapturer() worker.LogCapturer { | ||
return &emptyLogger{} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters