Skip to content

Commit

Permalink
Merge pull request #13 from YaKun9/dev
Browse files Browse the repository at this point in the history
merge
  • Loading branch information
YaKun9 authored Oct 10, 2024
2 parents bee71a2 + c7e576c commit 5c3e72f
Show file tree
Hide file tree
Showing 42 changed files with 455 additions and 353 deletions.
22 changes: 22 additions & 0 deletions backend/app/api/v1/snapshot.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,28 @@ func (b *BaseApi) SearchSnapshot(c *gin.Context) {
})
}

// @Tags System Setting
// @Summary Load system snapshot size
// @Description 获取系统快照大小
// @Accept json
// @Param request body dto.PageSnapshot true "request"
// @Success 200
// @Security ApiKeyAuth
// @Router /settings/snapshot/size [post]
func (b *BaseApi) LoadSnapshotSize(c *gin.Context) {
var req dto.PageSnapshot
if err := helper.CheckBindAndValidate(&req, c); err != nil {
return
}

data, err := snapshotService.LoadSize(req)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, data)
}

// @Tags System Setting
// @Summary Recover system backup
// @Description 从系统快照恢复
Expand Down
3 changes: 2 additions & 1 deletion backend/app/dto/container.go
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,7 @@ type ComposeInfo struct {
Workdir string `json:"workdir"`
Path string `json:"path"`
Containers []ComposeContainer `json:"containers"`
Env []string `json:"env"`
}
type ComposeContainer struct {
ContainerID string `json:"containerID"`
Expand All @@ -218,7 +219,7 @@ type ComposeCreate struct {
type ComposeOperation struct {
Name string `json:"name" validate:"required"`
Path string `json:"path" validate:"required"`
Operation string `json:"operation" validate:"required,oneof=up start stop down"`
Operation string `json:"operation" validate:"required,oneof=up start stop down delete"`
WithFile bool `json:"withFile"`
}
type ComposeUpdate struct {
Expand Down
31 changes: 16 additions & 15 deletions backend/app/dto/request/website.go
Original file line number Diff line number Diff line change
Expand Up @@ -175,21 +175,22 @@ type WebsiteUpdateDirPermission struct {
}

type WebsiteProxyConfig struct {
ID uint `json:"id" validate:"required"`
Operate string `json:"operate" validate:"required"`
Enable bool `json:"enable" `
Cache bool `json:"cache" `
CacheTime int `json:"cacheTime" `
CacheUnit string `json:"cacheUnit"`
Name string `json:"name" validate:"required"`
Modifier string `json:"modifier"`
Match string `json:"match" validate:"required"`
ProxyPass string `json:"proxyPass" validate:"required"`
ProxyHost string `json:"proxyHost" validate:"required"`
Content string `json:"content"`
FilePath string `json:"filePath"`
Replaces map[string]string `json:"replaces"`
SNI bool `json:"sni"`
ID uint `json:"id" validate:"required"`
Operate string `json:"operate" validate:"required"`
Enable bool `json:"enable" `
Cache bool `json:"cache" `
CacheTime int `json:"cacheTime" `
CacheUnit string `json:"cacheUnit"`
Name string `json:"name" validate:"required"`
Modifier string `json:"modifier"`
Match string `json:"match" validate:"required"`
ProxyPass string `json:"proxyPass" validate:"required"`
ProxyHost string `json:"proxyHost" validate:"required"`
Content string `json:"content"`
FilePath string `json:"filePath"`
Replaces map[string]string `json:"replaces"`
SNI bool `json:"sni"`
ProxySSLName string `json:"proxySSLName"`
}

type WebsiteProxyReq struct {
Expand Down
7 changes: 6 additions & 1 deletion backend/app/dto/setting.go
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,6 @@ type SnapshotInfo struct {
Message string `json:"message"`
CreatedAt time.Time `json:"createdAt"`
Version string `json:"version"`
Size int64 `json:"size"`

InterruptStep string `json:"interruptStep"`
RecoverStatus string `json:"recoverStatus"`
Expand All @@ -160,6 +159,12 @@ type SnapshotInfo struct {
LastRollbackedAt string `json:"lastRollbackedAt"`
}

type SnapshotFile struct {
ID uint `json:"id"`
Name string `json:"name"`
Size int64 `json:"size"`
}

type UpgradeInfo struct {
TestVersion string `json:"testVersion"`
NewVersion string `json:"newVersion"`
Expand Down
215 changes: 72 additions & 143 deletions backend/app/service/container_compose.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,11 @@ import (
"bufio"
"errors"
"fmt"
"gopkg.in/yaml.v3"
"io"
"io/ioutil"
"os"
"os/exec"
"path"
"path/filepath"
"sort"
"strings"
"time"
Expand Down Expand Up @@ -161,7 +160,26 @@ func (u *ContainerService) PageCompose(req dto.SearchWithPage) (int64, interface
}
BackDatas = records[start:end]
}
return int64(total), BackDatas, nil
listItem := loadEnv(BackDatas)
return int64(total), listItem, nil
}

func loadEnv(list []dto.ComposeInfo) []dto.ComposeInfo {
for i := 0; i < len(list); i++ {
envFilePath := filepath.Join(path.Dir(list[i].Path), "1panel.env")
file, err := os.ReadFile(envFilePath)
if err != nil {
continue
}
lines := strings.Split(string(file), "\n")
for _, line := range lines {
lineItem := strings.TrimSpace(line)
if len(lineItem) != 0 && !strings.HasPrefix(lineItem, "#") {
list[i].Env = append(list[i].Env, lineItem)
}
}
}
return list
}

func (u *ContainerService) TestCompose(req dto.ComposeCreate) (bool, error) {
Expand All @@ -175,6 +193,9 @@ func (u *ContainerService) TestCompose(req dto.ComposeCreate) (bool, error) {
if err := u.loadPath(&req); err != nil {
return false, err
}
if err := newComposeEnv(req.Path, req.Env); err != nil {
return false, err
}
cmd := exec.Command("docker-compose", "-f", req.Path, "config")
stdout, err := cmd.CombinedOutput()
if err != nil {
Expand All @@ -183,59 +204,6 @@ func (u *ContainerService) TestCompose(req dto.ComposeCreate) (bool, error) {
return true, nil
}

func formatYAML(data []byte) []byte {
return []byte(strings.ReplaceAll(string(data), "\t", " "))
}

func updateDockerComposeWithEnv(req dto.ComposeCreate) error {
data, err := ioutil.ReadFile(req.Path)
if err != nil {
return fmt.Errorf("failed to read docker-compose.yml: %v", err)
}
var composeItem DockerCompose
if err := yaml.Unmarshal(data, &composeItem); err != nil {
return fmt.Errorf("failed to parse docker-compose.yml: %v", err)
}
for serviceName, service := range composeItem.Services {
envMap := make(map[string]string)
if existingEnv, exists := service["environment"].([]interface{}); exists {
for _, env := range existingEnv {
envStr := env.(string)
parts := strings.SplitN(envStr, "=", 2)
if len(parts) == 2 {
envMap[parts[0]] = parts[1]
}
}
}
for _, env := range req.Env {
parts := strings.SplitN(env, "=", 2)
if len(parts) == 2 {
envMap[parts[0]] = parts[1]
}
}
envVars := []string{}
for key, value := range envMap {
envVars = append(envVars, key+"="+value)
}
service["environment"] = envVars
composeItem.Services[serviceName] = service
}
if composeItem.Networks != nil {
for key := range composeItem.Networks {
composeItem.Networks[key] = map[string]interface{}{}
}
}
newData, err := yaml.Marshal(&composeItem)
if err != nil {
return fmt.Errorf("failed to marshal docker-compose.yml: %v", err)
}
formattedData := formatYAML(newData)
if err := ioutil.WriteFile(req.Path, formattedData, 0644); err != nil {
return fmt.Errorf("failed to write docker-compose.yml: %v", err)
}
return nil
}

func (u *ContainerService) CreateCompose(req dto.ComposeCreate) (string, error) {
if cmd.CheckIllegal(req.Name, req.Path) {
return "", buserr.New(constant.ErrCmdIllegal)
Expand All @@ -260,11 +228,8 @@ func (u *ContainerService) CreateCompose(req dto.ComposeCreate) (string, error)
if err != nil {
return "", err
}
if len(req.Env) > 0 {
if err := updateDockerComposeWithEnv(req); err != nil {
fmt.Printf("failed to update docker-compose.yml with env: %v\n", err)
return "", err
}
if err := newComposeEnv(req.Path, req.Env); err != nil {
return "", err
}
go func() {
defer file.Close()
Expand Down Expand Up @@ -293,6 +258,16 @@ func (u *ContainerService) ComposeOperation(req dto.ComposeOperation) error {
if _, err := os.Stat(req.Path); err != nil {
return fmt.Errorf("load file with path %s failed, %v", req.Path, err)
}
if req.Operation == "delete" {
if stdout, err := compose.Operate(req.Path, "down"); err != nil {
return errors.New(string(stdout))
}
if req.WithFile {
_ = os.RemoveAll(path.Dir(req.Path))
}
_ = composeRepo.DeleteRecord(commonRepo.WithByName(req.Name))
return nil
}
if req.Operation == "up" {
if stdout, err := compose.Up(req.Path); err != nil {
return errors.New(string(stdout))
Expand All @@ -303,74 +278,6 @@ func (u *ContainerService) ComposeOperation(req dto.ComposeOperation) error {
}
}
global.LOG.Infof("docker-compose %s %s successful", req.Operation, req.Name)
if req.Operation == "down" {
if req.WithFile {
_ = composeRepo.DeleteRecord(commonRepo.WithByName(req.Name))
_ = os.RemoveAll(path.Dir(req.Path))
} else {
composeItem, _ := composeRepo.GetRecord(commonRepo.WithByName(req.Name))
if composeItem.Path == "" {
upMap := make(map[string]interface{})
upMap["path"] = req.Path
_ = composeRepo.UpdateRecord(req.Name, upMap)
}
}
}

return nil
}

func updateComposeWithEnv(req dto.ComposeUpdate) error {
var composeItem DockerCompose
if err := yaml.Unmarshal([]byte(req.Content), &composeItem); err != nil {
return fmt.Errorf("failed to parse docker-compose content: %v", err)
}
for serviceName, service := range composeItem.Services {
envMap := make(map[string]string)
for _, env := range req.Env {
parts := strings.SplitN(env, "=", 2)
if len(parts) == 2 {
envMap[parts[0]] = parts[1]
}
}
newEnvVars := []string{}
if existingEnv, exists := service["environment"].([]interface{}); exists {
for _, env := range existingEnv {
envStr := env.(string)
parts := strings.SplitN(envStr, "=", 2)
if len(parts) == 2 {
key := parts[0]
if value, found := envMap[key]; found {
newEnvVars = append(newEnvVars, key+"="+value)
delete(envMap, key)
} else {
newEnvVars = append(newEnvVars, envStr)
}
}
}
}
for key, value := range envMap {
newEnvVars = append(newEnvVars, key+"="+value)
}
if len(newEnvVars) > 0 {
service["environment"] = newEnvVars
} else {
delete(service, "environment")
}
composeItem.Services[serviceName] = service
}
if composeItem.Networks != nil {
for key := range composeItem.Networks {
composeItem.Networks[key] = map[string]interface{}{}
}
}
newData, err := yaml.Marshal(&composeItem)
if err != nil {
return fmt.Errorf("failed to marshal docker-compose.yml: %v", err)
}
if err := ioutil.WriteFile(req.Path, newData, 0644); err != nil {
return fmt.Errorf("failed to write docker-compose.yml to path: %v", err)
}
return nil
}

Expand All @@ -382,21 +289,20 @@ func (u *ContainerService) ComposeUpdate(req dto.ComposeUpdate) error {
if err != nil {
return fmt.Errorf("load file with path %s failed, %v", req.Path, err)
}
if len(req.Env) > 0 {
if err := updateComposeWithEnv(req); err != nil {
return fmt.Errorf("failed to update docker-compose with env: %v", err)
}
} else {
file, err := os.OpenFile(req.Path, os.O_WRONLY|os.O_TRUNC, 0640)
if err != nil {
return err
}
defer file.Close()
write := bufio.NewWriter(file)
_, _ = write.WriteString(req.Content)
write.Flush()
global.LOG.Infof("docker-compose.yml %s has been replaced", req.Path)
file, err := os.OpenFile(req.Path, os.O_WRONLY|os.O_TRUNC, 0640)
if err != nil {
return err
}
defer file.Close()
write := bufio.NewWriter(file)
_, _ = write.WriteString(req.Content)
write.Flush()

global.LOG.Infof("docker-compose.yml %s has been replaced, now start to docker-compose restart", req.Path)
if err := newComposeEnv(req.Path, req.Env); err != nil {
return err
}

if stdout, err := compose.Up(req.Path); err != nil {
if err := recreateCompose(string(oldFile), req.Path); err != nil {
return fmt.Errorf("update failed when handle compose up, err: %s, recreate failed: %v", string(stdout), err)
Expand Down Expand Up @@ -445,3 +351,26 @@ func recreateCompose(content, path string) error {
}
return nil
}

func newComposeEnv(pathItem string, env []string) error {
if len(env) == 0 {
return nil
}
envFilePath := path.Join(path.Dir(pathItem), "1panel.env")

file, err := os.OpenFile(envFilePath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
if err != nil {
global.LOG.Errorf("failed to create env file: %v", err)
return err
}
defer file.Close()
for _, env := range env {
envItem := strings.TrimSpace(env)
if _, err := file.WriteString(fmt.Sprintf("%s\n", envItem)); err != nil {
global.LOG.Errorf("failed to write env to file: %v", err)
return err
}
}
global.LOG.Infof("1panel.env file successfully created or updated with env variables in %s", envFilePath)
return nil
}
Loading

0 comments on commit 5c3e72f

Please sign in to comment.