-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
6bb0156
commit d24f21f
Showing
8 changed files
with
458 additions
and
25 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
package runner | ||
|
||
import ( | ||
"context" | ||
) | ||
|
||
type TasksDefinition struct { | ||
Tasks []Task | ||
} | ||
|
||
type Task struct { | ||
Name string | ||
Image string | ||
Command []string | ||
Cleanup bool | ||
Resources Resources | ||
WaitToComplete bool | ||
} | ||
|
||
type Resources struct { | ||
Limits ResourceLimits | ||
Reservations ResourceReservations | ||
} | ||
|
||
type ResourceLimits struct { | ||
CPUs string | ||
Memory string | ||
} | ||
|
||
type ResourceReservations struct { | ||
CPUs string | ||
Memory string | ||
} | ||
|
||
type Runner interface { | ||
Run(ctx context.Context, isDone chan<- bool) | ||
} | ||
|
||
type ContainerManager interface { | ||
CreateContainer(ctx context.Context, task Task) (string, error) | ||
StartContainer(ctx context.Context, id string) error | ||
WaitForContainer(ctx context.Context, id string) (bool, error) | ||
RemoveContainer(ctx context.Context, id string) error | ||
} | ||
|
||
type ImageManager interface { | ||
PullImage(ctx context.Context, image string) error | ||
} |
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,12 @@ | ||
package docker | ||
|
||
import "github.com/docker/docker/client" | ||
|
||
func NewClient() (*client.Client, error) { | ||
cli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation()) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
return cli, 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,71 @@ | ||
package container | ||
|
||
import ( | ||
"context" | ||
|
||
"github.com/docker/docker/api/types/container" | ||
"github.com/docker/docker/client" | ||
"github.com/khanzadimahdi/testproject/domain/runner" | ||
) | ||
|
||
type manager struct { | ||
cli *client.Client | ||
} | ||
|
||
var _ runner.ContainerManager = &manager{} | ||
|
||
func NewManager(cli *client.Client) *manager { | ||
return &manager{ | ||
cli: cli, | ||
} | ||
} | ||
|
||
// CreateContainer creates a new container and returns it ID. | ||
func (m *manager) CreateContainer(ctx context.Context, task runner.Task) (string, error) { | ||
config := &container.Config{ | ||
Image: task.Image, | ||
Cmd: task.Command, | ||
} | ||
|
||
res, err := m.cli.ContainerCreate(ctx, config, &container.HostConfig{}, nil, nil, task.Name) | ||
if err != nil { | ||
return "", err | ||
} | ||
|
||
return res.ID, nil | ||
} | ||
|
||
// StartContainer starts the container created with given ID. | ||
func (m *manager) StartContainer(ctx context.Context, id string) error { | ||
return m.cli.ContainerStart(ctx, id, container.StartOptions{}) | ||
} | ||
|
||
// WaitForContainer waits for the running container to finish. | ||
func (m *manager) WaitForContainer(ctx context.Context, id string) (bool, error) { | ||
// check if the container is in running state | ||
if _, err := m.cli.ContainerInspect(ctx, id); err != nil { | ||
return true, nil | ||
} | ||
|
||
// send API call to wait for the container completion | ||
wait, errC := m.cli.ContainerWait(ctx, id, container.WaitConditionNotRunning) | ||
|
||
// check if container exit code is 0, and return accordingly | ||
select { | ||
case status := <-wait: | ||
if status.StatusCode == 0 { | ||
return true, nil | ||
} | ||
|
||
return false, nil | ||
case err := <-errC: | ||
return false, err | ||
case <-ctx.Done(): | ||
return false, ctx.Err() | ||
} | ||
} | ||
|
||
// RemoveContainer removes the given container id | ||
func (m *manager) RemoveContainer(ctx context.Context, id string) error { | ||
return m.cli.ContainerRemove(ctx, id, container.RemoveOptions{}) | ||
} |
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,70 @@ | ||
package image | ||
|
||
import ( | ||
"context" | ||
"encoding/json" | ||
"fmt" | ||
"io" | ||
|
||
"github.com/docker/docker/api/types/image" | ||
"github.com/docker/docker/client" | ||
"github.com/khanzadimahdi/testproject/domain/runner" | ||
"github.com/pkg/errors" | ||
) | ||
|
||
type ImagePullStatus struct { | ||
Status string `json:"status"` | ||
Error string `json:"error"` | ||
Progress string `json:"progress"` | ||
ProgressDetail struct { | ||
Current int `json:"current"` | ||
Total int `json:"total"` | ||
} `json:"progressDetail"` | ||
} | ||
|
||
type manager struct { | ||
cli *client.Client | ||
} | ||
|
||
var _ runner.ImageManager = &manager{} | ||
|
||
func NewManager(cli *client.Client) *manager { | ||
return &manager{ | ||
cli: cli, | ||
} | ||
} | ||
|
||
// PullImage outputs to stdout the contents of the runner image. | ||
func (m *manager) PullImage(ctx context.Context, imageName string) error { | ||
out, err := m.cli.ImagePull(ctx, imageName, image.PullOptions{}) | ||
if err != nil { | ||
return errors.New("DOCKER PULL") | ||
} | ||
|
||
defer func() { | ||
if err := out.Close(); err != nil { | ||
fmt.Println(err) | ||
} | ||
}() | ||
|
||
fd := json.NewDecoder(out) | ||
var status *ImagePullStatus | ||
for { | ||
if err := fd.Decode(&status); err != nil { | ||
if errors.Is(err, io.EOF) { | ||
break | ||
} | ||
|
||
return errors.Wrap(err, "DOCKER PULL") | ||
} | ||
|
||
if status.Error != "" { | ||
return errors.Wrap(errors.New(status.Error), "DOCKER PULL") | ||
} | ||
|
||
// uncomment to log image pull status | ||
// fmt.Println(status) | ||
} | ||
|
||
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,29 @@ | ||
package models | ||
|
||
type TasksDefinition struct { | ||
Tasks []Task `json:"tasks,omitempty"` | ||
} | ||
|
||
type Task struct { | ||
Name string `json:"name,omitempty"` | ||
Image string `json:"runner,omitempty"` | ||
Command []string `json:"command,omitempty"` | ||
Cleanup bool `json:"cleanup,omitempty"` | ||
Resources Resources `json:"resources,omitempty"` | ||
WaitToComplete bool `json:"wait_to_complete,omitempty"` | ||
} | ||
|
||
type Resources struct { | ||
Limits ResourceLimits `json:"limits,omitempty"` | ||
Reservations ResourceReservations `json:"reservations,omitempty"` | ||
} | ||
|
||
type ResourceLimits struct { | ||
CPUs string `json:"cpus,omitempty"` | ||
Memory string `json:"memory,omitempty"` | ||
} | ||
|
||
type ResourceReservations struct { | ||
CPUs string `json:"cpus,omitempty"` | ||
Memory string `json:"memory,omitempty"` | ||
} |
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,71 @@ | ||
package runner | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
|
||
runnerDomain "github.com/khanzadimahdi/testproject/domain/runner" | ||
) | ||
|
||
type runner struct { | ||
containerManager runnerDomain.ContainerManager | ||
imageManager runnerDomain.ImageManager | ||
} | ||
|
||
var _ runnerDomain.Runner = &runner{} | ||
Check failure on line 15 in infrastructure/runner/runner.go GitHub Actions / ci
Check failure on line 15 in infrastructure/runner/runner.go GitHub Actions / ci
|
||
|
||
func NewRunner( | ||
containerManager runnerDomain.ContainerManager, | ||
imageManager runnerDomain.ImageManager, | ||
) *runner { | ||
return &runner{ | ||
containerManager: containerManager, | ||
imageManager: imageManager, | ||
} | ||
} | ||
|
||
func (r *runner) Run(ctx context.Context, tasksDefinition runnerDomain.TasksDefinition) error { | ||
for _, task := range tasksDefinition.Tasks { | ||
if err != r.run(ctx, task); err != nil { | ||
Check failure on line 29 in infrastructure/runner/runner.go GitHub Actions / ci
|
||
return err | ||
Check failure on line 30 in infrastructure/runner/runner.go GitHub Actions / ci
|
||
} | ||
} | ||
} | ||
Check failure on line 33 in infrastructure/runner/runner.go GitHub Actions / ci
|
||
|
||
func (r *runner) run(ctx context.Context, task runnerDomain.Task) error { | ||
fmt.Println("preparing task - ", task.Name) | ||
if err := r.imageManager.PullImage(ctx, task.Image); err != nil { | ||
return err | ||
} | ||
|
||
id, err := r.containerManager.CreateContainer(ctx, task) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
fmt.Println("starting task - ", task.Name) | ||
err = r.containerManager.StartContainer(ctx, id) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
statusSuccess, err := r.containerManager.WaitForContainer(ctx, id) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
if statusSuccess { | ||
fmt.Println("completed task - ", task.Name) | ||
|
||
// cleanup by removing the task container | ||
if task.Cleanup { | ||
fmt.Println("cleanup task - ", task.Name) | ||
err = r.containerManager.RemoveContainer(ctx, id) | ||
if err != nil { | ||
fmt.Println(err) | ||
} | ||
} | ||
} else { | ||
fmt.Println("failed task - ", task.Name) | ||
} | ||
} | ||
Check failure on line 71 in infrastructure/runner/runner.go GitHub Actions / ci
|