| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469 |
- package tools
- import (
- "context"
- "io"
- "net/netip"
- "strings"
- "time"
- "github.com/moby/go-archive"
- "github.com/moby/moby/api/pkg/stdcopy"
- "github.com/moby/moby/api/types/container"
- "github.com/moby/moby/api/types/network"
- "github.com/moby/term"
- "github.com/moby/moby/client"
- "github.com/moby/moby/client/pkg/jsonmessage"
- v1 "github.com/opencontainers/image-spec/specs-go/v1"
- )
- func Docker() *docker {
- ctx := context.Background()
- return &docker{
- ctx: ctx,
- }
- }
- type (
- docker struct {
- ctx context.Context
- }
- dockerImage struct {
- docker *docker
- auth string
- }
- dockerContainer struct {
- docker *docker
- id string
- name string
- config *container.Config
- hostconfig *container.HostConfig
- network *network.NetworkingConfig
- }
- )
- func (t *docker) client() (*client.Client, error) {
- cli, err := client.New(client.FromEnv)
- if err != nil {
- return nil, err
- }
- return cli, nil
- }
- func (t *docker) ContainerList() ([]*dockerContainer, error) {
- cli, err := t.client()
- if err != nil {
- return nil, err
- }
- defer cli.Close()
- containers, err := cli.ContainerList(context.Background(), client.ContainerListOptions{All: true})
- if err != nil {
- return nil, err
- }
- res := []*dockerContainer{}
- for _, ctr := range containers.Items {
- c, err := t.ContainerGetByID(ctr.ID)
- if err != nil {
- return nil, err
- }
- res = append(res, c)
- }
- return res, nil
- }
- func (t *docker) ContainerGetByID(id string) (*dockerContainer, error) {
- cli, err := t.client()
- if err != nil {
- return nil, err
- }
- defer cli.Close()
- c, err := cli.ContainerInspect(context.Background(), id, client.ContainerInspectOptions{})
- if err != nil {
- return nil, err
- }
- return &dockerContainer{
- docker: t,
- id: id,
- name: strings.TrimPrefix(c.Container.Name, "/"),
- config: c.Container.Config,
- hostconfig: c.Container.HostConfig,
- network: &network.NetworkingConfig{
- EndpointsConfig: map[string]*network.EndpointSettings{},
- },
- }, nil
- }
- func (t *docker) ContainerGetByName(name string) (*dockerContainer, error) {
- cli, err := t.client()
- if err != nil {
- return nil, err
- }
- defer cli.Close()
- filters := client.Filters{}
- filters.Add("name", name)
- containers, err := cli.ContainerList(context.Background(),
- client.ContainerListOptions{
- Filters: filters,
- })
- if err != nil {
- return nil, err
- }
- var id string
- for _, ctr := range containers.Items {
- for _, n := range ctr.Names {
- if strings.TrimPrefix(n, "/") == name {
- id = ctr.ID
- }
- }
- }
- return t.ContainerGetByID(id)
- }
- func (t *docker) ContainerNew(name string) *dockerContainer {
- return &dockerContainer{
- name: name,
- docker: t,
- config: &container.Config{
- ExposedPorts: network.PortSet{},
- },
- hostconfig: &container.HostConfig{
- AutoRemove: false,
- },
- network: &network.NetworkingConfig{
- EndpointsConfig: map[string]*network.EndpointSettings{},
- },
- }
- }
- func (t *dockerContainer) ID() string { return t.id }
- func (t *dockerContainer) Name() string { return t.name }
- func (t *dockerContainer) Config() *container.Config { return t.config }
- func (t *dockerContainer) HostConfig() *container.HostConfig { return t.hostconfig }
- func (t *dockerContainer) NetworkConfig() *network.NetworkingConfig { return t.network }
- func (t *dockerContainer) Exec() {}
- func (t *dockerContainer) Run(destOut io.Writer, destErr io.Writer, timeout time.Duration) (int64, error) {
- err := t.Create()
- if err != nil {
- return -1, err
- }
- err = t.Start()
- if err != nil {
- return -1, err
- }
- res, err := t.Wait(timeout)
- errs := t.Stop()
- if errs != nil {
- destErr.Write([]byte(errs.Error()))
- }
- errs = t.Logs(destOut, destErr)
- if errs != nil {
- destErr.Write([]byte(errs.Error()))
- }
- errs = t.Remove()
- if errs != nil {
- destErr.Write([]byte(errs.Error()))
- }
- return res, err
- }
- func (t *dockerContainer) Logs(destOut io.Writer, destErr io.Writer) error {
- cli, err := t.docker.client()
- if err != nil {
- return err
- }
- defer cli.Close()
- res, err := cli.ContainerLogs(t.docker.ctx, t.id, client.ContainerLogsOptions{
- ShowStdout: true,
- ShowStderr: true,
- // Details: true,
- })
- if err != nil {
- return err
- }
- defer res.Close()
- _, err = stdcopy.StdCopy(destOut, destErr, res)
- if err != nil {
- return err
- }
- return nil
- }
- func (t *dockerContainer) AddPort(containerPort, address, hostPort string) error {
- cp, err := network.ParsePort(containerPort)
- if err != nil {
- return err
- }
- addr, err := netip.ParseAddr(address)
- if err != nil {
- return err
- }
- if t.hostconfig.PortBindings == nil {
- t.hostconfig.PortBindings = network.PortMap{}
- }
- t.hostconfig.PortBindings[cp] = []network.PortBinding{
- {
- HostPort: hostPort,
- HostIP: addr,
- },
- }
- return nil
- }
- func (t *dockerContainer) State() (container.ContainerState, error) {
- cli, err := t.docker.client()
- if err != nil {
- return "", err
- }
- c, err := cli.ContainerInspect(context.Background(), t.id, client.ContainerInspectOptions{})
- if err != nil {
- return "", err
- }
- return c.Container.State.Status, nil
- }
- func (t *dockerContainer) Wait(timeout time.Duration) (int64, error) {
- cli, err := t.docker.client()
- if err != nil {
- return -1, err
- }
- defer cli.Close()
- ctx, _ := context.WithTimeout(t.docker.ctx, timeout)
- wait := cli.ContainerWait(ctx, t.id, client.ContainerWaitOptions{})
- select {
- case err := <-wait.Error:
- if err != nil {
- return -1, err
- }
- case res := <-wait.Result:
- return res.StatusCode, nil
- }
- return -1, nil
- }
- func (t *dockerContainer) Create() error {
- cli, err := t.docker.client()
- if err != nil {
- return err
- }
- defer cli.Close()
- create, err := cli.ContainerCreate(context.Background(), client.ContainerCreateOptions{
- Name: t.name,
- Config: t.config,
- HostConfig: t.hostconfig,
- NetworkingConfig: t.network,
- Platform: &v1.Platform{},
- })
- if err != nil {
- return err
- }
- t.id = create.ID
- return nil
- }
- func (t *dockerContainer) Start() error {
- cli, err := t.docker.client()
- if err != nil {
- return err
- }
- defer cli.Close()
- _, err = cli.ContainerStart(t.docker.ctx, t.id, client.ContainerStartOptions{})
- if err != nil {
- return err
- }
- return nil
- }
- func (t *dockerContainer) Stop() error {
- cli, err := t.docker.client()
- if err != nil {
- return err
- }
- defer cli.Close()
- _, err = cli.ContainerStop(t.docker.ctx, t.id, client.ContainerStopOptions{})
- if err != nil {
- return err
- }
- return nil
- }
- func (t *dockerContainer) Remove() error {
- cli, err := t.docker.client()
- if err != nil {
- return err
- }
- defer cli.Close()
- _, err = cli.ContainerRemove(t.docker.ctx, t.id,
- client.ContainerRemoveOptions{
- // RemoveLinks: true,
- RemoveVolumes: true,
- Force: true,
- })
- if err != nil {
- return err
- }
- t.id = ""
- return nil
- }
- func (t *docker) Image() *dockerImage {
- return &dockerImage{
- docker: t,
- }
- }
- // RegistryAuth is the base64 encoded credentials for the registry
- func (t *dockerImage) Auth(RegistryAuth string) { t.auth = RegistryAuth }
- func (t *dockerImage) Build(tag, path, dockerfile string) error {
- cli, err := t.docker.client()
- if err != nil {
- return err
- }
- defer cli.Close()
- tar, err := archive.TarWithOptions(path, &archive.TarOptions{})
- if err != nil {
- return err
- }
- opts := client.ImageBuildOptions{
- Dockerfile: dockerfile,
- Tags: []string{tag},
- Remove: true,
- }
- buildResponse, err := cli.ImageBuild(t.docker.ctx, tar, opts)
- if err != nil {
- return err
- }
- defer buildResponse.Body.Close()
- if log != nil {
- fd, isTerminal := term.GetFdInfo(log)
- return jsonmessage.DisplayJSONMessagesStream(buildResponse.Body, log, fd, isTerminal, nil)
- }
- return nil
- }
- func (t *dockerImage) Tag(source, target string) error {
- cli, err := t.docker.client()
- if err != nil {
- return err
- }
- defer cli.Close()
- _, err = cli.ImageTag(t.docker.ctx, client.ImageTagOptions{
- Source: source,
- Target: target,
- })
- if err != nil {
- return err
- }
- return nil
- }
- func (t *dockerImage) Push(image string) error {
- cli, err := t.docker.client()
- if err != nil {
- return err
- }
- defer cli.Close()
- res, err := cli.ImagePush(t.docker.ctx, image, client.ImagePushOptions{
- RegistryAuth: t.auth,
- })
- if err != nil {
- return err
- }
- defer res.Close()
- if log != nil {
- fd, isTerminal := term.GetFdInfo(log)
- return jsonmessage.DisplayJSONMessagesStream(res, log, fd, isTerminal, nil)
- }
- return nil
- }
- func (t *dockerImage) Remove(image string) error {
- cli, err := t.docker.client()
- if err != nil {
- return err
- }
- defer cli.Close()
- _, err = cli.ImageRemove(t.docker.ctx, image, client.ImageRemoveOptions{})
- if err != nil {
- return err
- }
- return nil
- }
- func (t *dockerImage) Pull(image string, timeout time.Duration) error {
- cli, err := t.docker.client()
- if err != nil {
- return err
- }
- defer cli.Close()
- ctx, _ := context.WithTimeout(t.docker.ctx, timeout)
- res, err := cli.ImagePull(ctx, image, client.ImagePullOptions{
- RegistryAuth: t.auth,
- })
- if err != nil {
- return err
- }
- defer res.Close()
- if log != nil {
- fd, isTerminal := term.GetFdInfo(log)
- return jsonmessage.DisplayJSONMessagesStream(res, log, fd, isTerminal, nil)
- } else {
- err = res.Wait(ctx)
- if err != nil {
- return err
- }
- }
- return nil
- }
|