From f5ca7f5de76480accd399223e0a9dfe9947d04aa Mon Sep 17 00:00:00 2001 From: niqdev Date: Mon, 11 Sep 2023 22:28:56 +0100 Subject: [PATCH] update task model --- internal/command/box/flag/tunnel.go | 2 +- internal/command/task/task.go | 7 ++++--- pkg/box/kubernetes/kubernetes.go | 5 ++--- pkg/box/model/box.go | 2 +- pkg/box/model/labels.go | 4 ++-- pkg/client/common/util.go | 8 -------- pkg/client/common/util_test.go | 4 ---- pkg/client/kubernetes/builder.go | 6 +++--- pkg/common/model/options.go | 2 +- pkg/task/client.go | 2 +- pkg/task/docker/client.go | 2 +- pkg/task/docker/docker.go | 22 ++++++++-------------- pkg/task/model/options.go | 3 ++- pkg/task/model/task.go | 11 +++++++++++ pkg/task/model/task_test.go | 17 +++++++++++++++++ pkg/util/{helper.go => string.go} | 10 +++++++++- pkg/util/string_test.go | 11 +++++++++++ 17 files changed, 74 insertions(+), 44 deletions(-) create mode 100644 pkg/task/model/task_test.go rename pkg/util/{helper.go => string.go} (73%) create mode 100644 pkg/util/string_test.go diff --git a/internal/command/box/flag/tunnel.go b/internal/command/box/flag/tunnel.go index e3f0920d..c08e34e6 100644 --- a/internal/command/box/flag/tunnel.go +++ b/internal/command/box/flag/tunnel.go @@ -21,7 +21,7 @@ type TunnelFlag struct { func (f *TunnelFlag) ToConnectOptions(template *boxModel.BoxV1, name string, temporary bool) *boxModel.ConnectOptions { return &boxModel.ConnectOptions{ Template: template, - StreamOpts: commonModel.NewStreamOpts(true), + StreamOpts: commonModel.NewStdStreamOpts(true), Name: name, DisableExec: f.NoExec, DisableTunnel: f.NoTunnel, diff --git a/internal/command/task/task.go b/internal/command/task/task.go index 04135340..3b47a536 100644 --- a/internal/command/task/task.go +++ b/internal/command/task/task.go @@ -105,13 +105,14 @@ func runTask(sourceLoader template.SourceLoader[taskModel.TaskV1], provider task return err } - createOpts := &taskModel.CreateOptions{ + runOpts := &taskModel.RunOptions{ Template: &info.Value.Data, - Parameters: commonModel.Parameters{}, // TODO common model + Parameters: commonModel.Parameters{}, // TODO []string rename commands Labels: commonCmd.AddTemplateLabels[taskModel.TaskV1](info, labels), + StreamOpts: commonModel.NewStdStreamOpts(false), } - return taskClient.Run(createOpts) + return taskClient.Run(runOpts) } func newDefaultTaskClient(provider taskModel.TaskProvider, configRef *config.ConfigRef, loader *commonCmd.Loader) (task.TaskClient, error) { diff --git a/pkg/box/kubernetes/kubernetes.go b/pkg/box/kubernetes/kubernetes.go index 42ff6001..84ce562a 100644 --- a/pkg/box/kubernetes/kubernetes.go +++ b/pkg/box/kubernetes/kubernetes.go @@ -7,7 +7,6 @@ import ( "golang.org/x/exp/slices" boxModel "github.com/hckops/hckctl/pkg/box/model" - "github.com/hckops/hckctl/pkg/client/common" "github.com/hckops/hckctl/pkg/client/kubernetes" commonModel "github.com/hckops/hckctl/pkg/common/model" "github.com/hckops/hckctl/pkg/schema" @@ -100,7 +99,7 @@ func newResources(namespace string, name string, opts *boxModel.CreateOptions) * Name: name, Annotations: opts.Labels, Labels: kubernetes.BuildLabels(name, opts.Template.Image.Repository, opts.Template.Image.ResolveVersion(), - map[string]string{commonModel.LabelSchemaKind: common.ToKebabCase(schema.KindBoxV1.String())}), + map[string]string{commonModel.LabelSchemaKind: util.ToLowerKebabCase(schema.KindBoxV1.String())}), Ports: ports, PodInfo: &kubernetes.PodInfo{ Namespace: namespace, @@ -178,7 +177,7 @@ func (box *KubeBoxClient) execBox(template *boxModel.BoxV1, info *boxModel.BoxIn // exec opts := &kubernetes.PodExecOpts{ Namespace: box.clientOpts.Namespace, - PodName: common.ToKebabCase(template.Image.Repository), // pod.Spec.Containers[0].Name + PodName: util.ToLowerKebabCase(template.Image.Repository), // pod.Spec.Containers[0].Name PodId: info.Id, Shell: template.Shell, InStream: streamOpts.In, diff --git a/pkg/box/model/box.go b/pkg/box/model/box.go index b9971f48..d16cba8e 100644 --- a/pkg/box/model/box.go +++ b/pkg/box/model/box.go @@ -61,7 +61,7 @@ func SortEnv(env []BoxEnv) []BoxEnv { } func (box *BoxV1) GenerateName() string { - return fmt.Sprintf("%s%s-%s", BoxPrefixName, box.Name, util.RandomAlphanumeric(5)) + return fmt.Sprintf("%s%s-%s", BoxPrefixName, util.ToLowerKebabCase(box.Name), util.RandomAlphanumeric(5)) } // ToBoxTemplateName returns the strictly validated template name, or the original trimmed name diff --git a/pkg/box/model/labels.go b/pkg/box/model/labels.go index 8b24e8eb..75538dbe 100644 --- a/pkg/box/model/labels.go +++ b/pkg/box/model/labels.go @@ -4,9 +4,9 @@ import ( "fmt" "strings" - "github.com/hckops/hckctl/pkg/client/common" commonModel "github.com/hckops/hckctl/pkg/common/model" "github.com/hckops/hckctl/pkg/schema" + "github.com/hckops/hckctl/pkg/util" ) const ( @@ -33,5 +33,5 @@ func ToBoxSize(labels commonModel.Labels) (ResourceSize, error) { func BoxLabelSelector() string { // value must be sanitized - return fmt.Sprintf("%s=%s", commonModel.LabelSchemaKind, common.ToKebabCase(schema.KindBoxV1.String())) + return fmt.Sprintf("%s=%s", commonModel.LabelSchemaKind, util.ToLowerKebabCase(schema.KindBoxV1.String())) } diff --git a/pkg/client/common/util.go b/pkg/client/common/util.go index 1a30db61..53e8410c 100644 --- a/pkg/client/common/util.go +++ b/pkg/client/common/util.go @@ -1,7 +1,6 @@ package common import ( - "regexp" "strings" ) @@ -12,10 +11,3 @@ func DefaultShell(command string) string { return "/bin/bash" } } - -// matches anything other than a letter, digit or underscore, equivalent to "[^a-zA-Z0-9_]" -var anyNonWordCharacterRegex = regexp.MustCompile(`\W+`) - -func ToKebabCase(value string) string { - return anyNonWordCharacterRegex.ReplaceAllString(value, "-") -} diff --git a/pkg/client/common/util_test.go b/pkg/client/common/util_test.go index b943b92a..cd8d6669 100644 --- a/pkg/client/common/util_test.go +++ b/pkg/client/common/util_test.go @@ -13,7 +13,3 @@ func TestDefaultShell(t *testing.T) { assert.Equal(t, "foo", DefaultShell("foo")) } - -func TestToKebabCase(t *testing.T) { - assert.Equal(t, "hckops-my-test_value-example", ToKebabCase("hckops/my-test_value$example")) -} diff --git a/pkg/client/kubernetes/builder.go b/pkg/client/kubernetes/builder.go index 4269c8be..eebbdb73 100644 --- a/pkg/client/kubernetes/builder.go +++ b/pkg/client/kubernetes/builder.go @@ -12,7 +12,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/intstr" - "github.com/hckops/hckctl/pkg/client/common" + "github.com/hckops/hckctl/pkg/util" ) func BuildResources(opts *ResourcesOpts) (*appsv1.Deployment, *corev1.Service, error) { @@ -42,7 +42,7 @@ func BuildLabels(name, instance, version string, extra map[string]string) map[st // default labels := map[string]string{ LabelKubeName: name, - LabelKubeInstance: common.ToKebabCase(instance), + LabelKubeInstance: util.ToLowerKebabCase(instance), LabelKubeVersion: version, LabelKubeManagedBy: "hckops", // TODO common? } @@ -62,7 +62,7 @@ func buildPod(objectMeta metav1.ObjectMeta, podInfo *PodInfo, ports []KubePort) Spec: corev1.PodSpec{ Containers: []corev1.Container{ { - Name: common.ToKebabCase(podInfo.ContainerName), + Name: util.ToLowerKebabCase(podInfo.ContainerName), Image: podInfo.ImageName, ImagePullPolicy: corev1.PullIfNotPresent, TTY: true, diff --git a/pkg/common/model/options.go b/pkg/common/model/options.go index a3817734..8618229f 100644 --- a/pkg/common/model/options.go +++ b/pkg/common/model/options.go @@ -30,7 +30,7 @@ type StreamOptions struct { IsTty bool // tty is false for ssh tunnel or logs } -func NewStreamOpts(tty bool) *StreamOptions { +func NewStdStreamOpts(tty bool) *StreamOptions { return &StreamOptions{ In: os.Stdin, Out: os.Stdout, diff --git a/pkg/task/client.go b/pkg/task/client.go index 7535097b..70b63053 100644 --- a/pkg/task/client.go +++ b/pkg/task/client.go @@ -11,7 +11,7 @@ import ( type TaskClient interface { Provider() model.TaskProvider Events() *event.EventBus - Run(opts *model.CreateOptions) error + Run(opts *model.RunOptions) error } func NewTaskClient(opts *model.TaskClientOptions) (TaskClient, error) { diff --git a/pkg/task/docker/client.go b/pkg/task/docker/client.go index 0691ed78..fb7e55c5 100644 --- a/pkg/task/docker/client.go +++ b/pkg/task/docker/client.go @@ -25,6 +25,6 @@ func (task *DockerTaskClient) Events() *event.EventBus { return task.eventBus } -func (task *DockerTaskClient) Run(opts *taskModel.CreateOptions) error { +func (task *DockerTaskClient) Run(opts *taskModel.RunOptions) error { return task.runTask(opts) } diff --git a/pkg/task/docker/docker.go b/pkg/task/docker/docker.go index d1553a4e..e59c4749 100644 --- a/pkg/task/docker/docker.go +++ b/pkg/task/docker/docker.go @@ -29,7 +29,7 @@ func (task *DockerTaskClient) close() error { return task.client.Close() } -func (task *DockerTaskClient) runTask(opts *taskModel.CreateOptions) error { +func (task *DockerTaskClient) runTask(opts *taskModel.RunOptions) error { imageName := opts.Template.Image.Name() imagePullOpts := &docker.ImagePullOpts{ @@ -64,18 +64,16 @@ func (task *DockerTaskClient) runTask(opts *taskModel.CreateOptions) error { } // taskName - // TODO containerName := opts.Template.GenerateName() - containerName := "task-whalesay-12345" + containerName := opts.Template.GenerateName() - // TODO tty false? containerConfig, err := docker.BuildContainerConfig(&docker.ContainerConfigOpts{ ImageName: imageName, ContainerName: containerName, - //Env: containerEnv, - //Ports: containerPorts, - Labels: opts.Labels, - Tty: false, - Cmd: []string{"cowsay", "hello world"}, + Env: []docker.ContainerEnv{}, + Ports: []docker.ContainerPort{}, + Labels: opts.Labels, + Tty: opts.StreamOpts.IsTty, + Cmd: []string{"cowsay", "hello world"}, // TODO parameters vs command }) if err != nil { return err @@ -87,8 +85,7 @@ func (task *DockerTaskClient) runTask(opts *taskModel.CreateOptions) error { return err } - // TODO networkName := box.clientOpts.NetworkName - networkName := "hckops" // TODO unique network? + networkName := task.clientOpts.NetworkName networkId, err := task.client.NetworkUpsert(networkName) if err != nil { return err @@ -118,9 +115,6 @@ func (task *DockerTaskClient) runTask(opts *taskModel.CreateOptions) error { } // TODO box.eventBus.Publish(newContainerCreateDockerEvent(opts.Template.Name, containerName, containerId)) - // TODO background task - //return &boxModel.BoxInfo{Id: containerId, Name: containerName, Healthy: true}, nil - if err := task.client.ContainerLogsStd(containerId); err != nil { return err } diff --git a/pkg/task/model/options.go b/pkg/task/model/options.go index 4fb22849..b7b64544 100644 --- a/pkg/task/model/options.go +++ b/pkg/task/model/options.go @@ -20,8 +20,9 @@ func NewCommonTaskOpts() *CommonTaskOptions { } } -type CreateOptions struct { +type RunOptions struct { Template *TaskV1 Parameters map[string]string Labels commonModel.Labels + StreamOpts *commonModel.StreamOptions } diff --git a/pkg/task/model/task.go b/pkg/task/model/task.go index 0fce990e..3b4db2c7 100644 --- a/pkg/task/model/task.go +++ b/pkg/task/model/task.go @@ -1,7 +1,14 @@ package model import ( + "fmt" + commonModel "github.com/hckops/hckctl/pkg/common/model" + "github.com/hckops/hckctl/pkg/util" +) + +const ( + TagPrefixName = "task-" ) type TaskV1 struct { @@ -10,3 +17,7 @@ type TaskV1 struct { Tags []string Image commonModel.Image } + +func (task *TaskV1) GenerateName() string { + return fmt.Sprintf("%s%s-%s", TagPrefixName, util.ToLowerKebabCase(task.Name), util.RandomAlphanumeric(5)) +} diff --git a/pkg/task/model/task_test.go b/pkg/task/model/task_test.go new file mode 100644 index 00000000..2b496450 --- /dev/null +++ b/pkg/task/model/task_test.go @@ -0,0 +1,17 @@ +package model + +import ( + "strings" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestGenerateName(t *testing.T) { + task := &TaskV1{ + Name: "my-name", + } + taskId := task.GenerateName() + assert.True(t, strings.HasPrefix(taskId, "task-my-name-")) + assert.Equal(t, 18, len(taskId)) +} diff --git a/pkg/util/helper.go b/pkg/util/string.go similarity index 73% rename from pkg/util/helper.go rename to pkg/util/string.go index 6115a860..f9185809 100644 --- a/pkg/util/helper.go +++ b/pkg/util/string.go @@ -2,10 +2,11 @@ package util import ( "fmt" - "github.com/pkg/errors" + "regexp" "strings" "github.com/dchest/uniuri" + "github.com/pkg/errors" ) func IotaToValues[T comparable](kv map[T]string) []string { @@ -41,3 +42,10 @@ func SplitKeyValue(kv string) (string, string, error) { } return "", "", errors.New("invalid key-value pair") } + +// matches anything other than a letter, digit or underscore, equivalent to "[^a-zA-Z0-9_]" +var anyNonWordCharacterRegex = regexp.MustCompile(`\W+`) + +func ToLowerKebabCase(value string) string { + return anyNonWordCharacterRegex.ReplaceAllString(strings.ToLower(strings.TrimSpace(value)), "-") +} diff --git a/pkg/util/string_test.go b/pkg/util/string_test.go new file mode 100644 index 00000000..8f7054a9 --- /dev/null +++ b/pkg/util/string_test.go @@ -0,0 +1,11 @@ +package util + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestToLowerKebabCase(t *testing.T) { + assert.Equal(t, "hckops-my-test_value-example", ToLowerKebabCase(" hCKops/my-tEst_value$ExamplE\t")) +}