Skip to content

Commit

Permalink
update docker task
Browse files Browse the repository at this point in the history
  • Loading branch information
niqdev committed Sep 19, 2023
1 parent 5193f9f commit 2d2086c
Show file tree
Hide file tree
Showing 11 changed files with 171 additions and 65 deletions.
6 changes: 2 additions & 4 deletions internal/command/task/task.go
Original file line number Diff line number Diff line change
Expand Up @@ -113,19 +113,17 @@ func (opts *taskCmdOptions) runTask(sourceLoader template.SourceLoader[taskModel
loader.Start("loading template %s", info.Value.Data.Name) // TODO review template name e.g task/name (lowercase)
defer loader.Stop()

log.Info().Msgf("loading template: provider=%s name=%s\n%s", opts.provider, info.Value.Data.Name, info.Value.Data.Pretty())

taskClient, err := newDefaultTaskClient(opts.provider, opts.configRef, loader)
if err != nil {
return err
}

// TODO --command and --input
// TODO opts.networkVpnFlag

var arguments []string
if opts.commandFlag.Inline {
arguments = inlineArguments
} else {
// TODO expand/merge values
arguments = info.Value.Data.DefaultCommandArguments()
}

Expand Down
20 changes: 12 additions & 8 deletions pkg/box/docker/docker.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,13 +83,13 @@ func (box *DockerBoxClient) createBox(opts *boxModel.CreateOptions) (*boxModel.B
}

containerConfig, err := docker.BuildContainerConfig(&docker.ContainerConfigOpts{
ImageName: imageName,
ContainerName: containerName,
Env: containerEnv,
Ports: containerPorts,
Labels: opts.Labels,
Tty: true, // always
Cmd: []string{},
ImageName: imageName,
Hostname: containerName,
Env: containerEnv,
Ports: containerPorts,
Labels: opts.Labels,
Tty: true, // always
Cmd: []string{},
})
if err != nil {
return nil, err
Expand All @@ -98,7 +98,11 @@ func (box *DockerBoxClient) createBox(opts *boxModel.CreateOptions) (*boxModel.B
onPortBindCallback := func(port docker.ContainerPort) {
box.publishPortInfo(networkMap, containerName, port)
}
hostConfig, err := docker.BuildHostConfig(containerPorts, onPortBindCallback)
hostConfig, err := docker.BuildHostConfig(&docker.ContainerHostConfigOpts{
NetworkMode: docker.DefaultNetworkMode(),
Ports: containerPorts,
OnPortBindCallback: onPortBindCallback,
})
if err != nil {
return nil, err
}
Expand Down
8 changes: 4 additions & 4 deletions pkg/box/docker/events.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,14 +76,14 @@ func newContainerCreateEnvDockerConsoleEvent(containerName string, env model.Box
return &dockerBoxEvent{kind: event.PrintConsole, value: fmt.Sprintf("[%s] %s=%s", containerName, env.Key, env.Value)}
}

func newContainerCreateDockerEvent(templateName string, containerName string, containerId string) *dockerBoxEvent {
return &dockerBoxEvent{kind: event.LogInfo, value: fmt.Sprintf("container create: templateName=%s containerName=%s containerId=%s", templateName, containerName, containerId)}
}

func newContainerCreateStatusDockerEvent(status string) *dockerBoxEvent {
return &dockerBoxEvent{kind: event.LogDebug, value: status}
}

func newContainerCreateDockerEvent(templateName string, containerName string, containerId string) *dockerBoxEvent {
return &dockerBoxEvent{kind: event.LogInfo, value: fmt.Sprintf("container create: templateName=%s containerName=%s containerId=%s", templateName, containerName, containerId)}
}

func newContainerRestartDockerEvent(containerId string, status string) *dockerBoxEvent {
return &dockerBoxEvent{kind: event.LogInfo, value: fmt.Sprintf("container restart: containerId=%s status=%s", containerId, status)}
}
Expand Down
7 changes: 3 additions & 4 deletions pkg/box/model/box_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,15 @@ import (
"testing"

"github.com/stretchr/testify/assert"

commonModel "github.com/hckops/hckctl/pkg/common/model"
)

var testBox = &BoxV1{
Kind: "box/v1",
Name: "my-name",
Tags: []string{"my-tag"},
Image: struct {
Repository string
Version string
}{
Image: commonModel.Image{
Repository: "hckops/my-image",
},
Shell: "/bin/bash",
Expand Down
19 changes: 14 additions & 5 deletions pkg/client/docker/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package docker

import (
"fmt"
"strings"

"github.com/pkg/errors"

Expand All @@ -28,7 +29,7 @@ func BuildContainerConfig(opts *ContainerConfigOpts) (*container.Config, error)
}

return &container.Config{
Hostname: opts.ContainerName, // TODO vpn conflict with NetworkMode
Hostname: opts.Hostname,
Image: opts.ImageName,
AttachStdin: true,
AttachStdout: true,
Expand All @@ -43,10 +44,10 @@ func BuildContainerConfig(opts *ContainerConfigOpts) (*container.Config, error)
}, nil
}

func BuildHostConfig(ports []ContainerPort, onPortBindCallback func(port ContainerPort)) (*container.HostConfig, error) {
func BuildHostConfig(opts *ContainerHostConfigOpts) (*container.HostConfig, error) {

portBindings := make(nat.PortMap)
for _, port := range ports {
for _, port := range opts.Ports {

localPort, err := util.FindOpenPort(port.Local)
if err != nil {
Expand All @@ -59,7 +60,7 @@ func BuildHostConfig(ports []ContainerPort, onPortBindCallback func(port Contain
}

// actual bound port
onPortBindCallback(ContainerPort{
opts.OnPortBindCallback(ContainerPort{
Local: localPort,
Remote: port.Remote,
})
Expand All @@ -71,11 +72,19 @@ func BuildHostConfig(ports []ContainerPort, onPortBindCallback func(port Contain
}

return &container.HostConfig{
NetworkMode: container.NetworkMode(opts.NetworkMode),
PortBindings: portBindings,
//NetworkMode: "container:alpine-openvpn-???", // TODO vpn
}, nil
}

func DefaultNetworkMode() string {
return string(container.IsolationDefault)
}

func ContainerNetworkMode(idOrName string) string {
return strings.Join([]string{"container", idOrName}, ":")
}

func BuildNetworkingConfig(networkName, networkId string) *network.NetworkingConfig {
return &network.NetworkingConfig{EndpointsConfig: map[string]*network.EndpointSettings{networkName: {NetworkID: networkId}}}
}
28 changes: 21 additions & 7 deletions pkg/client/docker/builder_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,12 @@ func TestBuildContainerConfig(t *testing.T) {
},
}
opts := &ContainerConfigOpts{
ImageName: "myImageName",
ContainerName: "myContainerName",
Env: envs,
Ports: ports,
Tty: true,
Cmd: []string{},
ImageName: "myImageName",
Hostname: "myContainerName",
Env: envs,
Ports: ports,
Tty: true,
Cmd: []string{},
Labels: map[string]string{
"a.b.c": "hello",
"x.y.z": "world",
Expand All @@ -66,16 +66,30 @@ func TestBuildHostConfig(t *testing.T) {
{Local: "1024", Remote: "1024"},
}
expected := &container.HostConfig{
NetworkMode: "myNetworkMode",
PortBindings: nat.PortMap{
"1024/tcp": []nat.PortBinding{{HostIP: "0.0.0.0", HostPort: "1024"}},
},
}
opts := &ContainerHostConfigOpts{
NetworkMode: "myNetworkMode",
Ports: ports,
OnPortBindCallback: func(port ContainerPort) {},
}

result, err := BuildHostConfig(ports, func(port ContainerPort) {})
result, err := BuildHostConfig(opts)
assert.NoError(t, err)
assert.Equal(t, expected, result)
}

func TestDefaultNetworkMode(t *testing.T) {
assert.Equal(t, "default", DefaultNetworkMode())
}

func TestContainerNetworkMode(t *testing.T) {
assert.Equal(t, "container:myIdOrName", ContainerNetworkMode("myIdOrName"))
}

func TestBuildNetworkingConfig(t *testing.T) {
expected := &network.NetworkingConfig{EndpointsConfig: map[string]*network.EndpointSettings{"myNetwork": {NetworkID: "123"}}}

Expand Down
20 changes: 13 additions & 7 deletions pkg/client/docker/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,19 @@ import (
)

type ContainerConfigOpts struct {
ImageName string
ContainerName string
Env []ContainerEnv
Ports []ContainerPort
Tty bool
Cmd []string
Labels map[string]string
ImageName string
Hostname string
Env []ContainerEnv
Ports []ContainerPort
Tty bool
Cmd []string
Labels map[string]string
}

type ContainerHostConfigOpts struct {
NetworkMode string
Ports []ContainerPort
OnPortBindCallback func(port ContainerPort)
}

type ImagePullOpts struct {
Expand Down
49 changes: 23 additions & 26 deletions pkg/task/docker/docker.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,14 +37,14 @@ func (task *DockerTaskClient) runTask(opts *taskModel.RunOptions) error {
imagePullOpts := &docker.ImagePullOpts{
ImageName: imageName,
OnImagePullCallback: func() {
// TODO box.eventBus.Publish(newImagePullDockerLoaderEvent(imageName))
task.eventBus.Publish(newImagePullDockerLoaderEvent(imageName))
},
}
// TODO box.eventBus.Publish(newImagePullDockerEvent(imageName))
task.eventBus.Publish(newImagePullDockerEvent(imageName))
if err := task.client.ImagePull(imagePullOpts); err != nil {
// try to use an existing image if exists
if task.clientOpts.IgnoreImagePullError {
// TODO box.eventBus.Publish(newImagePullIgnoreDockerEvent(imageName))
task.eventBus.Publish(newImagePullIgnoreDockerEvent(imageName))
} else {
// do not allow offline
return err
Expand All @@ -54,11 +54,11 @@ func (task *DockerTaskClient) runTask(opts *taskModel.RunOptions) error {
// cleanup obsolete nightly images
imageRemoveOpts := &docker.ImageRemoveOpts{
OnImageRemoveCallback: func(imageId string) {
// TODO box.eventBus.Publish(newImageRemoveDockerEvent(imageId))
task.eventBus.Publish(newImageRemoveDockerEvent(imageId))
},
OnImageRemoveErrorCallback: func(imageId string, err error) {
// ignore error: keep images used by existing containers
// TODO box.eventBus.Publish(newImageRemoveIgnoreDockerEvent(imageId, err))
task.eventBus.Publish(newImageRemoveIgnoreDockerEvent(imageId, err))
},
}
if err := task.client.ImageRemoveDangling(imageRemoveOpts); err != nil {
Expand All @@ -69,20 +69,23 @@ func (task *DockerTaskClient) runTask(opts *taskModel.RunOptions) error {
containerName := opts.Template.GenerateName()

containerConfig, err := docker.BuildContainerConfig(&docker.ContainerConfigOpts{
ImageName: imageName,
ContainerName: containerName,
Env: []docker.ContainerEnv{},
Ports: []docker.ContainerPort{},
Labels: opts.Labels,
Tty: opts.StreamOpts.IsTty,
Cmd: opts.Arguments,
ImageName: imageName,
Hostname: "", // TODO vpn NetworkMode conflicts with Hostname containerName
Env: []docker.ContainerEnv{},
Ports: []docker.ContainerPort{},
Labels: opts.Labels,
Tty: opts.StreamOpts.IsTty,
Cmd: opts.Arguments,
})
if err != nil {
return err
}

onPortBindCallback := func(port docker.ContainerPort) {}
hostConfig, err := docker.BuildHostConfig([]docker.ContainerPort{}, onPortBindCallback)
hostConfig, err := docker.BuildHostConfig(&docker.ContainerHostConfigOpts{
NetworkMode: docker.DefaultNetworkMode(), // TODO vpn
Ports: []docker.ContainerPort{},
OnPortBindCallback: func(docker.ContainerPort) {},
})
if err != nil {
return err
}
Expand All @@ -92,32 +95,26 @@ func (task *DockerTaskClient) runTask(opts *taskModel.RunOptions) error {
if err != nil {
return err
}
// TODO box.eventBus.Publish(newNetworkUpsertDockerEvent(networkName, networkId))
task.eventBus.Publish(newNetworkUpsertDockerEvent(networkName, networkId))

containerOpts := &docker.ContainerCreateOpts{
ContainerName: containerName,
ContainerConfig: containerConfig,
HostConfig: hostConfig,
NetworkingConfig: docker.BuildNetworkingConfig(networkName, networkId), // all on the same network
WaitStatus: true,
OnContainerStatusCallback: func(s string) {
//box.eventBus.Publish(newContainerCreateStatusDockerEvent(status))
},
OnContainerStartCallback: func() {
//for _, e := range opts.Template.EnvironmentVariables() {
// box.eventBus.Publish(newContainerCreateEnvDockerEvent(containerName, e))
// box.eventBus.Publish(newContainerCreateEnvDockerConsoleEvent(containerName, e))
//}
OnContainerStatusCallback: func(status string) {
task.eventBus.Publish(newContainerCreateStatusDockerEvent(status))
},
OnContainerStartCallback: func() {},
}
// taskId
containerId, err := task.client.ContainerCreate(containerOpts)
if err != nil {
return err
}
// TODO box.eventBus.Publish(newContainerCreateDockerEvent(opts.Template.Name, containerName, containerId))

// TODO stop loader
task.eventBus.Publish(newContainerCreateDockerEvent(opts.Template.Name, containerName, containerId))
task.eventBus.Publish(newContainerCreateDockerLoaderEvent())

if err := task.client.ContainerLogsStd(containerId); err != nil {
return err
Expand Down
38 changes: 38 additions & 0 deletions pkg/task/docker/events.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package docker

import (
"fmt"

"github.com/hckops/hckctl/pkg/event"
"github.com/hckops/hckctl/pkg/task/model"
)
Expand Down Expand Up @@ -29,3 +31,39 @@ func newInitDockerClientEvent() *dockerTaskEvent {
func newCloseDockerClientEvent() *dockerTaskEvent {
return &dockerTaskEvent{kind: event.LogDebug, value: "close docker client"}
}

func newImagePullDockerEvent(imageName string) *dockerTaskEvent {
return &dockerTaskEvent{kind: event.LogInfo, value: fmt.Sprintf("image pull: imageName=%s", imageName)}
}

func newImagePullDockerLoaderEvent(imageName string) *dockerTaskEvent {
return &dockerTaskEvent{kind: event.LoaderUpdate, value: fmt.Sprintf("pulling image %s", imageName)}
}

func newImagePullIgnoreDockerEvent(imageName string) *dockerTaskEvent {
return &dockerTaskEvent{kind: event.LogWarning, value: fmt.Sprintf("image pull ignored: imageName=%s", imageName)}
}

func newImageRemoveDockerEvent(imageId string) *dockerTaskEvent {
return &dockerTaskEvent{kind: event.LogInfo, value: fmt.Sprintf("image remove: imageId=%s", imageId)}
}

func newImageRemoveIgnoreDockerEvent(imageId string, err error) *dockerTaskEvent {
return &dockerTaskEvent{kind: event.LogWarning, value: fmt.Sprintf("image remove ignored: imageId=%s error=%v", imageId, err)}
}

func newNetworkUpsertDockerEvent(networkName string, networkId string) *dockerTaskEvent {
return &dockerTaskEvent{kind: event.LogInfo, value: fmt.Sprintf("network upsert: networkName=%s networkId=%s", networkName, networkId)}
}

func newContainerCreateStatusDockerEvent(status string) *dockerTaskEvent {
return &dockerTaskEvent{kind: event.LogDebug, value: status}
}

func newContainerCreateDockerEvent(templateName string, containerName string, containerId string) *dockerTaskEvent {
return &dockerTaskEvent{kind: event.LogInfo, value: fmt.Sprintf("container create: templateName=%s containerName=%s containerId=%s", templateName, containerName, containerId)}
}

func newContainerCreateDockerLoaderEvent() *dockerTaskEvent {
return &dockerTaskEvent{kind: event.LoaderStop, value: "waiting"}
}
5 changes: 5 additions & 0 deletions pkg/task/model/task.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,8 @@ func (task *TaskV1) DefaultCommandArguments() []string {
}
return []string{}
}

func (task *TaskV1) Pretty() string {
value, _ := util.EncodeJsonIndent(task)
return value
}
Loading

0 comments on commit 2d2086c

Please sign in to comment.