mirror of
https://github.com/blacktop/ipsw.git
synced 2026-06-07 12:27:36 +00:00
139 lines
3.4 KiB
Go
139 lines
3.4 KiB
Go
package docker
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
"slices"
|
|
|
|
"github.com/docker/docker/api/types/container"
|
|
"github.com/docker/docker/api/types/image"
|
|
"github.com/docker/docker/api/types/mount"
|
|
"github.com/docker/docker/api/types/network"
|
|
"github.com/docker/docker/client"
|
|
"github.com/docker/docker/pkg/stdcopy"
|
|
"github.com/google/uuid"
|
|
specs "github.com/opencontainers/image-spec/specs-go/v1"
|
|
)
|
|
|
|
type Client struct {
|
|
ID string `yaml:"id,omitempty" json:"id,omitempty"`
|
|
Image string `yaml:"image,omitempty" json:"image,omitempty"`
|
|
Entrypoint []string `yaml:"entrypoint,omitempty" json:"entrypoint,omitempty"`
|
|
Cmd []string `yaml:"cmd,omitempty" json:"cmd,omitempty"`
|
|
Env []string `yaml:"env,omitempty" json:"env,omitempty"`
|
|
Mounts []HostMounts `yaml:"mounts,omitempty" json:"mounts,omitempty"`
|
|
}
|
|
|
|
type HostMounts struct {
|
|
Source string
|
|
Target string
|
|
ReadOnly bool
|
|
}
|
|
|
|
func NewClient(id, image string, entry []string, cmd []string, env []string, mounts []HostMounts) *Client {
|
|
return &Client{
|
|
ID: id,
|
|
Image: image,
|
|
Entrypoint: entry,
|
|
Cmd: cmd,
|
|
Env: env,
|
|
Mounts: mounts,
|
|
}
|
|
}
|
|
|
|
func (c *Client) Run(ctx context.Context) error {
|
|
cli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation())
|
|
if err != nil {
|
|
return fmt.Errorf("failed to create docker client: %w", err)
|
|
}
|
|
|
|
images, err := cli.ImageList(ctx, image.ListOptions{})
|
|
if err != nil {
|
|
return fmt.Errorf("failed to list images: %w", err)
|
|
}
|
|
found := false
|
|
for _, image := range images {
|
|
if slices.Contains(image.RepoTags, c.Image) {
|
|
found = true
|
|
break
|
|
}
|
|
}
|
|
if !found {
|
|
reader, err := cli.ImagePull(ctx, c.Image, image.PullOptions{
|
|
// Platform: "linux/amd64",
|
|
})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer reader.Close()
|
|
|
|
io.Copy(os.Stdout, reader)
|
|
}
|
|
|
|
var mounts []mount.Mount
|
|
for _, m := range c.Mounts {
|
|
mounts = append(mounts, mount.Mount{
|
|
Type: mount.TypeBind,
|
|
Source: m.Source,
|
|
Target: m.Target,
|
|
ReadOnly: m.ReadOnly,
|
|
BindOptions: &mount.BindOptions{
|
|
CreateMountpoint: true,
|
|
},
|
|
})
|
|
}
|
|
|
|
resp, err := cli.ContainerCreate(ctx,
|
|
&container.Config{
|
|
Image: c.Image,
|
|
Entrypoint: c.Entrypoint,
|
|
Cmd: c.Cmd,
|
|
Env: c.Env,
|
|
Tty: true,
|
|
AttachStdout: true,
|
|
AttachStderr: true,
|
|
NetworkDisabled: true,
|
|
}, &container.HostConfig{
|
|
AutoRemove: true,
|
|
// Resources: container.Resources{Memory: 1 << 30, MemorySwap: 1 << 30},
|
|
Mounts: mounts,
|
|
}, &network.NetworkingConfig{}, &specs.Platform{
|
|
OS: "linux",
|
|
Architecture: "amd64",
|
|
}, "ipsw-idapro-"+uuid.New().String())
|
|
if err != nil {
|
|
return fmt.Errorf("failed to create container: %w", err)
|
|
}
|
|
|
|
if err := cli.ContainerStart(ctx, resp.ID, container.StartOptions{}); err != nil {
|
|
return fmt.Errorf("failed to start container: %w", err)
|
|
}
|
|
|
|
go func() {
|
|
out, err := cli.ContainerLogs(ctx, resp.ID, container.LogsOptions{
|
|
ShowStdout: true,
|
|
ShowStderr: true,
|
|
Follow: true,
|
|
Timestamps: false,
|
|
})
|
|
if err != nil {
|
|
panic(fmt.Errorf("failed to get container logs: %w", err))
|
|
}
|
|
|
|
stdcopy.StdCopy(os.Stdout, os.Stderr, out)
|
|
}()
|
|
|
|
statusCh, errCh := cli.ContainerWait(ctx, resp.ID, container.WaitConditionNotRunning)
|
|
select {
|
|
case err := <-errCh:
|
|
if err != nil {
|
|
return fmt.Errorf("error waiting for container: %w", err)
|
|
}
|
|
case <-statusCh:
|
|
}
|
|
|
|
return nil
|
|
}
|