659 lines
19 KiB
Go
659 lines
19 KiB
Go
package devcontainer
|
||
|
||
import (
|
||
"archive/tar"
|
||
"bufio"
|
||
"bytes"
|
||
"context"
|
||
"fmt"
|
||
"os/exec"
|
||
"regexp"
|
||
"strconv"
|
||
"strings"
|
||
|
||
"code.gitea.io/gitea/models/db"
|
||
devcontainer_model "code.gitea.io/gitea/models/devcontainer"
|
||
devcontainer_models "code.gitea.io/gitea/models/devcontainer"
|
||
docker_module "code.gitea.io/gitea/modules/docker"
|
||
"code.gitea.io/gitea/modules/log"
|
||
gitea_web_context "code.gitea.io/gitea/services/context"
|
||
"github.com/docker/docker/api/types"
|
||
"github.com/docker/docker/api/types/container"
|
||
"github.com/docker/docker/client"
|
||
"github.com/docker/go-connections/nat"
|
||
)
|
||
|
||
func CreateDevcontainer(ctx *context.Context, newDevContainer *CreateDevcontainerDTO, devContainerJSON *DevStarJSON, initializeScript string, restartScript string) error {
|
||
|
||
log.Info("开始创建容器.....")
|
||
|
||
// 1. 创建docker client
|
||
cli, err := docker_module.CreateDockerClient(ctx)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
defer cli.Close()
|
||
|
||
// 加入22 7681集合
|
||
natPort22 := nat.Port("22/tcp")
|
||
natPort7681 := nat.Port("7681/tcp")
|
||
devContainerJSON.ForwardPorts[natPort22] = struct{}{}
|
||
devContainerJSON.ForwardPorts[natPort7681] = struct{}{}
|
||
// 2. 创建容器
|
||
opts := &docker_module.CreateDevcontainerOptions{
|
||
DockerfileContent: newDevContainer.DockerfileContent,
|
||
Name: newDevContainer.Name,
|
||
Image: newDevContainer.Image,
|
||
CommandList: []string{
|
||
"sh",
|
||
"-c",
|
||
strings.Join(devContainerJSON.InitializeCommand, "") + "tail -f /dev/null;",
|
||
},
|
||
RepoId: newDevContainer.RepoId,
|
||
UserId: newDevContainer.UserId,
|
||
SSHPublicKeyList: newDevContainer.SSHPublicKeyList,
|
||
GitRepositoryURL: newDevContainer.GitRepositoryURL,
|
||
ContainerEnv: devContainerJSON.ContainerEnv,
|
||
PostCreateCommand: append([]string{"/home/devcontainer_init.sh"}, devContainerJSON.PostCreateCommand...),
|
||
ForwardPorts: devContainerJSON.ForwardPorts,
|
||
InitializeCommand: initializeScript,
|
||
RestartCommand: restartScript,
|
||
}
|
||
var flag string
|
||
for _, content := range devContainerJSON.RunArgs {
|
||
if flag == "-p" {
|
||
if opts.PortBindings == nil {
|
||
opts.PortBindings = nat.PortMap{}
|
||
}
|
||
// Split the string by ':'
|
||
parts := strings.Split(content, ":")
|
||
if len(parts) != 2 {
|
||
continue
|
||
}
|
||
|
||
hostPort := strings.TrimSpace(parts[0])
|
||
containerPortWithProtocol := strings.TrimSpace(parts[1])
|
||
|
||
// Split the container port and protocol
|
||
containerParts := strings.Split(containerPortWithProtocol, "/")
|
||
var containerProtocol = "tcp"
|
||
if len(containerParts) == 2 {
|
||
containerProtocol = containerParts[1]
|
||
}
|
||
containerPort := containerParts[0]
|
||
|
||
// Create nat.Port and nat.PortBinding
|
||
port := nat.Port(fmt.Sprintf("%s/%s", containerPort, containerProtocol))
|
||
portBinding := nat.PortBinding{
|
||
HostIP: "0.0.0.0",
|
||
HostPort: hostPort,
|
||
}
|
||
// Add to the port map
|
||
opts.PortBindings[port] = []nat.PortBinding{portBinding}
|
||
|
||
}
|
||
flag = strings.TrimSpace(content)
|
||
}
|
||
dockerHost, err := docker_module.GetDockerSocketPath()
|
||
if err != nil {
|
||
return fmt.Errorf("获取docker socket路径失败:%v", err)
|
||
}
|
||
// 拉取镜像
|
||
err = PullImageAsyncAndStartContainer(ctx, cli, dockerHost, opts)
|
||
if err != nil {
|
||
return fmt.Errorf("创建容器失败:%v", err)
|
||
}
|
||
return nil
|
||
}
|
||
|
||
func DeleteDevcontainer(ctx *context.Context, devcontainersList *[]devcontainer_model.Devcontainer) error {
|
||
log.Info("开始删除容器...")
|
||
// 创建docker client
|
||
cli, err := docker_module.CreateDockerClient(ctx)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
defer cli.Close()
|
||
// 获取容器 ID
|
||
var containerIDList []string
|
||
for _, devcontainer := range *devcontainersList {
|
||
v, err := docker_module.GetContainerID(cli, devcontainer.Name)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
containerIDList = append(containerIDList, v)
|
||
}
|
||
// 删除容器
|
||
for _, id := range containerIDList {
|
||
if err := docker_module.DeleteContainer(cli, id); err != nil {
|
||
return err
|
||
}
|
||
}
|
||
return nil
|
||
}
|
||
|
||
func GetDevcontainer(ctx *context.Context, opts *OpenDevcontainerAppDispatcherOptions) (uint16, error) {
|
||
// 创建docker client
|
||
cli, err := docker_module.CreateDockerClient(ctx)
|
||
if err != nil {
|
||
return 0, err
|
||
}
|
||
if cli != nil {
|
||
defer cli.Close()
|
||
}
|
||
|
||
// 获取容器ID
|
||
containerID, err := docker_module.GetContainerID(cli, opts.Name)
|
||
if err != nil {
|
||
return 0, err
|
||
}
|
||
port, err := docker_module.GetMappedPort(cli, containerID, "22")
|
||
if err != nil {
|
||
return 0, err
|
||
}
|
||
// 添加公钥
|
||
_, err = docker_module.ExecCommandInContainer(ctx, cli, containerID, fmt.Sprintf("echo '%s' >> ~/.ssh/authorized_keys", opts.UserPublicKey))
|
||
if err != nil {
|
||
return 0, err
|
||
}
|
||
v, err := strconv.ParseUint(port, 10, 16)
|
||
if err != nil {
|
||
return 0, err
|
||
}
|
||
return uint16(v), nil
|
||
|
||
}
|
||
|
||
func SaveDevcontainer(ctx *gitea_web_context.Context, opts *UpdateDevcontainerOptions) error {
|
||
// 创建docker client
|
||
reqctx := ctx.Req.Context()
|
||
cli, err := docker_module.CreateDockerClient(&reqctx)
|
||
imageRef := opts.RepositoryAddress + "/" + opts.RepositoryUsername + "/" + opts.ImageName
|
||
if err != nil {
|
||
return fmt.Errorf("创建docker client失败 %v", err)
|
||
}
|
||
defer cli.Close()
|
||
dbEngine := db.GetEngine(*ctx)
|
||
_, err = dbEngine.Table("devcontainer").
|
||
Where("user_id = ? AND repo_id = ? ", opts.Actor.ID, opts.Repository.ID).
|
||
Update(&devcontainer_model.Devcontainer{DevcontainerStatus: 6})
|
||
if err != nil {
|
||
log.Info("err %v", err)
|
||
}
|
||
if opts.SaveMethod == "on" {
|
||
// 创建构建上下文(包含Dockerfile的tar包)
|
||
var buf bytes.Buffer
|
||
tw := tar.NewWriter(&buf)
|
||
defer tw.Close()
|
||
// 添加Dockerfile到tar包
|
||
dockerfile := "Dockerfile"
|
||
dockerfileContent, err := GetDockerfileContent(ctx, opts.Repository)
|
||
content := []byte(dockerfileContent)
|
||
header := &tar.Header{
|
||
Name: dockerfile,
|
||
Size: int64(len(content)),
|
||
Mode: 0644,
|
||
}
|
||
if err := tw.WriteHeader(header); err != nil {
|
||
panic(err)
|
||
}
|
||
if _, err := tw.Write(content); err != nil {
|
||
panic(err)
|
||
}
|
||
|
||
buildOptions := types.ImageBuildOptions{
|
||
Tags: []string{imageRef}, // 镜像标签
|
||
}
|
||
|
||
_, err = cli.ImageBuild(
|
||
context.Background(),
|
||
&buf,
|
||
buildOptions,
|
||
)
|
||
if err != nil {
|
||
log.Info(err.Error())
|
||
return err
|
||
}
|
||
|
||
} else {
|
||
// 获取容器ID
|
||
containerID, err := docker_module.GetContainerID(cli, opts.DevContainerName)
|
||
if err != nil {
|
||
return fmt.Errorf("获取容器ID失败 %v", err)
|
||
}
|
||
// 提交容器
|
||
_, err = cli.ContainerCommit(ctx, containerID, types.ContainerCommitOptions{Reference: imageRef})
|
||
if err != nil {
|
||
return fmt.Errorf("提交容器失败 %v", err)
|
||
}
|
||
}
|
||
|
||
// 推送到仓库
|
||
dockerHost, err := docker_module.GetDockerSocketPath()
|
||
if err != nil {
|
||
return fmt.Errorf("推送到仓库失败 %v", err)
|
||
}
|
||
docker_module.PushImage(dockerHost, opts.RepositoryUsername, opts.PassWord, opts.RepositoryAddress, imageRef)
|
||
devcontainerJson, err := GetDevcontainerJsonString(ctx, opts.Repository)
|
||
// 定义正则表达式来匹配 image 字段
|
||
re := regexp.MustCompile(`"image"\s*:\s*"([^"]+)"`)
|
||
// 使用正则表达式查找并替换 image 字段的值
|
||
newJSONStr := re.ReplaceAllString(devcontainerJson, `"image": "`+imageRef+`"`)
|
||
|
||
_, err = dbEngine.Table("devcontainer").
|
||
Where("user_id = ? AND repo_id = ? ", opts.Actor.ID, opts.Repository.ID).
|
||
Update(&devcontainer_model.Devcontainer{DevcontainerStatus: 4})
|
||
if err != nil {
|
||
log.Info("err %v", err)
|
||
}
|
||
return UpdateDevcontainerJSON(ctx, newJSONStr)
|
||
}
|
||
|
||
func PullImageAsyncAndStartContainer(ctx *context.Context, cli *client.Client, dockerHost string, opts *docker_module.CreateDevcontainerOptions) error {
|
||
var stdoutScanner, stderrScanner *bufio.Scanner
|
||
// 创建扫描器来读取输出
|
||
dbEngine := db.GetEngine(*ctx)
|
||
|
||
_, err := dbEngine.Table("devcontainer").
|
||
Where("user_id = ? AND repo_id = ? ", opts.UserId, opts.RepoId).
|
||
Update(&devcontainer_model.Devcontainer{DevcontainerStatus: 1})
|
||
if err != nil {
|
||
log.Info("err %v", err)
|
||
}
|
||
if opts.DockerfileContent != "" {
|
||
|
||
// 创建构建上下文(包含Dockerfile的tar包)
|
||
var buf bytes.Buffer
|
||
tw := tar.NewWriter(&buf)
|
||
defer tw.Close()
|
||
// 添加Dockerfile到tar包
|
||
dockerfile := "Dockerfile"
|
||
content := []byte(opts.DockerfileContent)
|
||
header := &tar.Header{
|
||
Name: dockerfile,
|
||
Size: int64(len(content)),
|
||
Mode: 0644,
|
||
}
|
||
if err := tw.WriteHeader(header); err != nil {
|
||
panic(err)
|
||
}
|
||
if _, err := tw.Write(content); err != nil {
|
||
panic(err)
|
||
}
|
||
// 执行镜像构建
|
||
opts.Image = fmt.Sprintf("%d", opts.UserId) + "-" + fmt.Sprintf("%d", opts.RepoId) + "-dockerfileimage"
|
||
buildOptions := types.ImageBuildOptions{
|
||
Tags: []string{opts.Image}, // 镜像标签
|
||
}
|
||
|
||
buildResponse, err := cli.ImageBuild(
|
||
context.Background(),
|
||
&buf,
|
||
buildOptions,
|
||
)
|
||
if err != nil {
|
||
log.Info(err.Error())
|
||
return err
|
||
}
|
||
stdoutScanner = bufio.NewScanner(buildResponse.Body)
|
||
} else {
|
||
script := "docker " + "-H " + dockerHost + " pull " + opts.Image
|
||
cmd := exec.Command("sh", "-c", script)
|
||
// 获取标准输出和标准错误输出的管道
|
||
stdout, err := cmd.StdoutPipe()
|
||
if err != nil {
|
||
return err
|
||
}
|
||
stderr, err := cmd.StderrPipe()
|
||
if err != nil {
|
||
return err
|
||
}
|
||
err = cmd.Start()
|
||
if err != nil {
|
||
return err
|
||
}
|
||
stdoutScanner = bufio.NewScanner(stdout)
|
||
stderrScanner = bufio.NewScanner(stderr)
|
||
}
|
||
|
||
var pullImageOutput = devcontainer_models.DevcontainerOutput{
|
||
Output: "",
|
||
ListId: 0,
|
||
Status: "running",
|
||
UserId: opts.UserId,
|
||
RepoId: opts.RepoId,
|
||
Command: "Pull Image",
|
||
}
|
||
if _, err := dbEngine.Table("devcontainer_output").Insert(&pullImageOutput); err != nil {
|
||
log.Info("Failed to insert record: %v", err)
|
||
return err
|
||
}
|
||
|
||
_, err = dbEngine.Table("devcontainer_output").
|
||
Where("user_id = ? AND repo_id = ? ", opts.UserId, opts.RepoId).
|
||
Get(&pullImageOutput)
|
||
if err != nil {
|
||
log.Info("err %v", err)
|
||
return err
|
||
}
|
||
if _, err := dbEngine.Table("devcontainer_output").Insert(&devcontainer_models.DevcontainerOutput{
|
||
Output: "",
|
||
Status: "running",
|
||
UserId: opts.UserId,
|
||
RepoId: opts.RepoId,
|
||
Command: "Initialize Workspace",
|
||
ListId: 1,
|
||
}); err != nil {
|
||
log.Info("Failed to insert record: %v", err)
|
||
return err
|
||
}
|
||
_, err = dbEngine.Table("devcontainer_output").Insert(&devcontainer_models.DevcontainerOutput{
|
||
Output: "",
|
||
Status: "running",
|
||
UserId: opts.UserId,
|
||
RepoId: opts.RepoId,
|
||
Command: "Initialize DevStar",
|
||
ListId: 2,
|
||
})
|
||
if err != nil {
|
||
log.Info("Failed to insert record: %v", err)
|
||
return err
|
||
}
|
||
|
||
if len(opts.PostCreateCommand) > 1 {
|
||
_, err := dbEngine.Table("devcontainer_output").Insert(&devcontainer_models.DevcontainerOutput{
|
||
Output: "",
|
||
Status: "running",
|
||
UserId: opts.UserId,
|
||
RepoId: opts.RepoId,
|
||
Command: "Run postCreateCommand",
|
||
ListId: 3,
|
||
})
|
||
if err != nil {
|
||
log.Info("Failed to insert record: %v", err)
|
||
return err
|
||
}
|
||
}
|
||
|
||
// 使用 goroutine 来读取标准输出
|
||
go func() {
|
||
var output string
|
||
var cur int = 0
|
||
for stdoutScanner.Scan() {
|
||
output += "\n" + stdoutScanner.Text()
|
||
cur++
|
||
if cur%10 == 0 {
|
||
_, err = dbEngine.Table("devcontainer_output").
|
||
Where("id = ?", pullImageOutput.Id).
|
||
Update(&devcontainer_models.DevcontainerOutput{
|
||
Output: output})
|
||
if err != nil {
|
||
log.Info("err %v", err)
|
||
|
||
}
|
||
}
|
||
}
|
||
if stderrScanner != nil {
|
||
for stderrScanner.Scan() {
|
||
output += "\n" + stderrScanner.Text()
|
||
cur++
|
||
if cur%10 == 0 {
|
||
_, err = dbEngine.Table("devcontainer_output").
|
||
Where("id = ?", pullImageOutput.Id).
|
||
Update(&devcontainer_models.DevcontainerOutput{
|
||
Output: output})
|
||
if err != nil {
|
||
log.Info("err %v", err)
|
||
|
||
}
|
||
}
|
||
}
|
||
}
|
||
_, err = dbEngine.Table("devcontainer_output").
|
||
Where("id = ?", pullImageOutput.Id).
|
||
Update(&devcontainer_models.DevcontainerOutput{
|
||
Output: output})
|
||
if err != nil {
|
||
log.Info("err %v", err)
|
||
|
||
}
|
||
dbEngine.Table("devcontainer_output").
|
||
Where("id = ?", pullImageOutput.Id).
|
||
Update(&devcontainer_models.DevcontainerOutput{Status: "success"})
|
||
|
||
// 创建并启动容器
|
||
_, err := dbEngine.Table("devcontainer").
|
||
Where("user_id = ? AND repo_id = ? ", opts.UserId, opts.RepoId).
|
||
Update(&devcontainer_model.Devcontainer{DevcontainerStatus: 2})
|
||
if err != nil {
|
||
log.Info("err %v", err)
|
||
}
|
||
output, err = docker_module.CreateAndStartContainer(cli, opts)
|
||
if err != nil {
|
||
log.Info("创建或启动容器失败: %v", err)
|
||
}
|
||
containerID, err := docker_module.GetContainerID(cli, opts.Name)
|
||
if err != nil {
|
||
log.Info("获取容器ID:%v", err)
|
||
}
|
||
portInfo, err := docker_module.GetAllMappedPort(cli, containerID)
|
||
if err != nil {
|
||
log.Info("创建或启动容器失败:%v", err)
|
||
}
|
||
// 存储到数据库
|
||
if _, err := dbEngine.Table("devcontainer_output").
|
||
Where("user_id = ? AND repo_id = ? AND list_id = ?", opts.UserId, opts.RepoId, 1).
|
||
Update(&devcontainer_models.DevcontainerOutput{
|
||
Output: output + portInfo,
|
||
Status: "success",
|
||
}); err != nil {
|
||
log.Info("Error storing output for command %v: %v\n", opts.CommandList[2], err)
|
||
}
|
||
// 创建 exec 实例
|
||
_, err = dbEngine.Table("devcontainer").
|
||
Where("user_id = ? AND repo_id = ? ", opts.UserId, opts.RepoId).
|
||
Update(&devcontainer_model.Devcontainer{DevcontainerStatus: 3})
|
||
if err != nil {
|
||
log.Info("err %v", err)
|
||
}
|
||
var buffer string = ""
|
||
var state int = 2
|
||
for index, cmd := range opts.PostCreateCommand {
|
||
|
||
if index == 1 {
|
||
_, err = dbEngine.Table("devcontainer_output").
|
||
Where("user_id = ? AND repo_id = ? AND list_id = ?", opts.UserId, opts.RepoId, state).
|
||
Update(&devcontainer_models.DevcontainerOutput{
|
||
Status: "success",
|
||
})
|
||
if err != nil {
|
||
log.Info("Error storing output for command %v: %v\n", cmd, err)
|
||
}
|
||
buffer = ""
|
||
state = 3
|
||
continue
|
||
}
|
||
|
||
output, err = docker_module.ExecCommandInContainer(ctx, cli, containerID, cmd)
|
||
buffer += output
|
||
if err != nil {
|
||
log.Info("执行命令失败:%v", err)
|
||
}
|
||
|
||
_, err := dbEngine.Table("devcontainer_output").
|
||
Where("user_id = ? AND repo_id = ? AND list_id = ?", opts.UserId, opts.RepoId, state).
|
||
Update(&devcontainer_models.DevcontainerOutput{
|
||
Output: buffer,
|
||
})
|
||
if err != nil {
|
||
log.Info("Error storing output for command %v: %v\n", cmd, err)
|
||
}
|
||
}
|
||
_, err = dbEngine.Table("devcontainer_output").
|
||
Where("user_id = ? AND repo_id = ? AND list_id = ?", opts.UserId, opts.RepoId, state).
|
||
Update(&devcontainer_models.DevcontainerOutput{
|
||
Status: "success",
|
||
})
|
||
if err != nil {
|
||
log.Info("Error storing output for command pull image: %v\n", err)
|
||
}
|
||
_, err = dbEngine.Table("devcontainer").
|
||
Where("user_id = ? AND repo_id = ? ", opts.UserId, opts.RepoId).
|
||
Update(&devcontainer_model.Devcontainer{DevcontainerStatus: 4})
|
||
if err != nil {
|
||
log.Info("err %v", err)
|
||
}
|
||
}()
|
||
|
||
return nil
|
||
}
|
||
func DockerRestartContainer(gitea_ctx *gitea_web_context.Context, opts *RepoDevContainer) error {
|
||
// 创建docker client
|
||
ctx := context.Background()
|
||
cli, err := docker_module.CreateDockerClient(&ctx)
|
||
if err != nil {
|
||
return fmt.Errorf("创建docker client失败 %v", err)
|
||
}
|
||
defer cli.Close()
|
||
// 获取容器ID
|
||
containerID, err := docker_module.GetContainerID(cli, opts.DevContainerName)
|
||
if err != nil {
|
||
return fmt.Errorf("获取容器ID失败 %v", err)
|
||
}
|
||
dbEngine := db.GetEngine(ctx)
|
||
_, err = dbEngine.Table("devcontainer").
|
||
Where("user_id = ? AND repo_id = ? ", opts.UserId, opts.RepoId).
|
||
Update(&devcontainer_model.Devcontainer{DevcontainerStatus: 5})
|
||
if err != nil {
|
||
log.Info("err %v", err)
|
||
}
|
||
timeout := 10 // 超时时间(秒)
|
||
err = cli.ContainerRestart(context.Background(), containerID, container.StopOptions{
|
||
Timeout: &timeout,
|
||
})
|
||
if err != nil {
|
||
return fmt.Errorf("重启容器失败: %s\n", err)
|
||
} else {
|
||
log.Info("容器已重启")
|
||
}
|
||
|
||
devContainerJson, err := GetDevcontainerJsonModel(*gitea_ctx, gitea_ctx.Repo.Repository)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
cmd := []string{"/home/devcontainer_restart.sh"}
|
||
postCreateCommand := append(cmd, devContainerJson.PostCreateCommand...)
|
||
// 创建 exec 实例
|
||
|
||
var buffer string = ""
|
||
var state int = 2
|
||
_, err = dbEngine.Table("devcontainer_output").
|
||
Where("user_id = ? AND repo_id = ? AND list_id = ?", opts.UserId, opts.RepoId, state).
|
||
Update(&devcontainer_models.DevcontainerOutput{
|
||
Status: "running",
|
||
})
|
||
if err != nil {
|
||
return err
|
||
}
|
||
if len(devContainerJson.PostCreateCommand) > 1 {
|
||
_, err = dbEngine.Table("devcontainer_output").
|
||
Where("user_id = ? AND repo_id = ? AND list_id = ?", opts.UserId, opts.RepoId, state+1).
|
||
Update(&devcontainer_models.DevcontainerOutput{
|
||
Status: "running",
|
||
})
|
||
if err != nil {
|
||
return err
|
||
}
|
||
}
|
||
|
||
for index, cmd := range postCreateCommand {
|
||
|
||
if index == 1 {
|
||
_, err = dbEngine.Table("devcontainer_output").
|
||
Where("user_id = ? AND repo_id = ? AND list_id = ?", opts.UserId, opts.RepoId, state).
|
||
Update(&devcontainer_models.DevcontainerOutput{
|
||
Status: "success",
|
||
})
|
||
if err != nil {
|
||
log.Info("Error storing output for command %v: %v\n", cmd, err)
|
||
}
|
||
buffer = ""
|
||
state = 3
|
||
continue
|
||
}
|
||
|
||
output, err := docker_module.ExecCommandInContainer(&ctx, cli, containerID, cmd)
|
||
buffer += output
|
||
if err != nil {
|
||
log.Info("执行命令失败:%v", err)
|
||
}
|
||
|
||
_, err = dbEngine.Table("devcontainer_output").
|
||
Where("user_id = ? AND repo_id = ? AND list_id = ?", opts.UserId, opts.RepoId, state).
|
||
Update(&devcontainer_models.DevcontainerOutput{
|
||
Output: buffer,
|
||
})
|
||
if err != nil {
|
||
log.Info("Error storing output for command %v: %v\n", cmd, err)
|
||
return err
|
||
}
|
||
}
|
||
_, err = dbEngine.Table("devcontainer_output").
|
||
Where("user_id = ? AND repo_id = ? AND list_id = ?", opts.UserId, opts.RepoId, 2).
|
||
Update(&devcontainer_models.DevcontainerOutput{
|
||
Status: "success",
|
||
})
|
||
if err != nil {
|
||
return err
|
||
}
|
||
if len(devContainerJson.PostCreateCommand) > 1 {
|
||
_, err = dbEngine.Table("devcontainer_output").
|
||
Where("user_id = ? AND repo_id = ? AND list_id = ?", opts.UserId, opts.RepoId, 3).
|
||
Update(&devcontainer_models.DevcontainerOutput{
|
||
Status: "success",
|
||
})
|
||
if err != nil {
|
||
log.Info("Error storing output for command %v: %v\n", cmd, err)
|
||
return err
|
||
}
|
||
}
|
||
_, err = dbEngine.Table("devcontainer").
|
||
Where("user_id = ? AND repo_id = ? ", opts.UserId, opts.RepoId).
|
||
Update(&devcontainer_model.Devcontainer{DevcontainerStatus: 4})
|
||
log.Info("DockerRestartContainerDockerRestartContainerDockerRestartContainer")
|
||
if err != nil {
|
||
log.Info("err %v", err)
|
||
}
|
||
return nil
|
||
}
|
||
func DockerStopContainer(ctx *context.Context, opts *RepoDevContainer) error {
|
||
// 创建docker client
|
||
cli, err := docker_module.CreateDockerClient(ctx)
|
||
if err != nil {
|
||
return fmt.Errorf("创建docker client失败 %v", err)
|
||
}
|
||
defer cli.Close()
|
||
// 获取容器ID
|
||
containerID, err := docker_module.GetContainerID(cli, opts.DevContainerName)
|
||
if err != nil {
|
||
return fmt.Errorf("获取容器ID失败 %v", err)
|
||
}
|
||
dbEngine := db.GetEngine(*ctx)
|
||
_, err = dbEngine.Table("devcontainer").
|
||
Where("user_id = ? AND repo_id = ? ", opts.UserId, opts.RepoId).
|
||
Update(&devcontainer_model.Devcontainer{DevcontainerStatus: 6})
|
||
if err != nil {
|
||
log.Info("err %v", err)
|
||
}
|
||
timeout := 10 // 超时时间(秒)
|
||
err = cli.ContainerStop(context.Background(), containerID, container.StopOptions{
|
||
Timeout: &timeout,
|
||
})
|
||
if err != nil {
|
||
return fmt.Errorf("停止容器失败: %s\n", err)
|
||
} else {
|
||
log.Info("容器已停止")
|
||
return nil
|
||
}
|
||
}
|