mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2024-09-20 15:45:57 +08:00
fix: 解决同名网站备份恢复异常 (#3370)
Refs https://github.com/1Panel-dev/1Panel/issues/3355
This commit is contained in:
parent
9aaa387b23
commit
78f2b6f72d
|
@ -19,6 +19,7 @@ type IBackupRepo interface {
|
||||||
Update(id uint, vars map[string]interface{}) error
|
Update(id uint, vars map[string]interface{}) error
|
||||||
Delete(opts ...DBOption) error
|
Delete(opts ...DBOption) error
|
||||||
DeleteRecord(ctx context.Context, opts ...DBOption) error
|
DeleteRecord(ctx context.Context, opts ...DBOption) error
|
||||||
|
UpdateRecord(record *model.BackupRecord) error
|
||||||
WithByDetailName(detailName string) DBOption
|
WithByDetailName(detailName string) DBOption
|
||||||
WithByFileName(fileName string) DBOption
|
WithByFileName(fileName string) DBOption
|
||||||
WithByType(backupType string) DBOption
|
WithByType(backupType string) DBOption
|
||||||
|
@ -105,6 +106,10 @@ func (u *BackupRepo) CreateRecord(record *model.BackupRecord) error {
|
||||||
return global.DB.Create(record).Error
|
return global.DB.Create(record).Error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (u *BackupRepo) UpdateRecord(record *model.BackupRecord) error {
|
||||||
|
return global.DB.Save(record).Error
|
||||||
|
}
|
||||||
|
|
||||||
func (u *BackupRepo) Update(id uint, vars map[string]interface{}) error {
|
func (u *BackupRepo) Update(id uint, vars map[string]interface{}) error {
|
||||||
return global.DB.Model(&model.BackupAccount{}).Where("id = ?", id).Updates(vars).Error
|
return global.DB.Model(&model.BackupAccount{}).Where("id = ?", id).Updates(vars).Error
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,7 +25,7 @@ func (u *BackupService) WebsiteBackup(req dto.CommonBackup) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
website, err := websiteRepo.GetFirst(websiteRepo.WithDomain(req.Name))
|
website, err := websiteRepo.GetFirst(websiteRepo.WithAlias(req.DetailName))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -40,7 +40,7 @@ func (u *BackupService) WebsiteBackup(req dto.CommonBackup) error {
|
||||||
record := &model.BackupRecord{
|
record := &model.BackupRecord{
|
||||||
Type: "website",
|
Type: "website",
|
||||||
Name: website.PrimaryDomain,
|
Name: website.PrimaryDomain,
|
||||||
DetailName: "",
|
DetailName: req.DetailName,
|
||||||
Source: "LOCAL",
|
Source: "LOCAL",
|
||||||
BackupType: "LOCAL",
|
BackupType: "LOCAL",
|
||||||
FileDir: backupDir,
|
FileDir: backupDir,
|
||||||
|
@ -54,14 +54,14 @@ func (u *BackupService) WebsiteBackup(req dto.CommonBackup) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *BackupService) WebsiteRecover(req dto.CommonRecover) error {
|
func (u *BackupService) WebsiteRecover(req dto.CommonRecover) error {
|
||||||
website, err := websiteRepo.GetFirst(websiteRepo.WithDomain(req.Name))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
fileOp := files.NewFileOp()
|
fileOp := files.NewFileOp()
|
||||||
if !fileOp.Stat(req.File) {
|
if !fileOp.Stat(req.File) {
|
||||||
return errors.New(fmt.Sprintf("%s file is not exist", req.File))
|
return errors.New(fmt.Sprintf("%s file is not exist", req.File))
|
||||||
}
|
}
|
||||||
|
website, err := websiteRepo.GetFirst(websiteRepo.WithAlias(req.DetailName))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
global.LOG.Infof("recover website %s from backup file %s", req.Name, req.File)
|
global.LOG.Infof("recover website %s from backup file %s", req.Name, req.File)
|
||||||
if err := handleWebsiteRecover(&website, req.File, false); err != nil {
|
if err := handleWebsiteRecover(&website, req.File, false); err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -79,15 +79,6 @@ func handleWebsiteRecover(website *model.Website, recoverFile string, isRollback
|
||||||
_ = os.RemoveAll(tmpPath)
|
_ = os.RemoveAll(tmpPath)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
temPathWithName := tmpPath + "/" + website.Alias
|
|
||||||
if !fileOp.Stat(tmpPath+"/website.json") || !fileOp.Stat(temPathWithName+".conf") || !fileOp.Stat(temPathWithName+".web.tar.gz") {
|
|
||||||
return buserr.WithDetail(constant.ErrBackupExist, ".conf or .web.tar.gz", nil)
|
|
||||||
}
|
|
||||||
if website.Type == constant.Deployment {
|
|
||||||
if !fileOp.Stat(temPathWithName + ".app.tar.gz") {
|
|
||||||
return buserr.WithDetail(constant.ErrBackupExist, ".app.tar.gz", nil)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var oldWebsite model.Website
|
var oldWebsite model.Website
|
||||||
websiteJson, err := os.ReadFile(tmpPath + "/website.json")
|
websiteJson, err := os.ReadFile(tmpPath + "/website.json")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -101,6 +92,16 @@ func handleWebsiteRecover(website *model.Website, recoverFile string, isRollback
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
temPathWithName := tmpPath + "/" + website.Alias
|
||||||
|
if !fileOp.Stat(tmpPath+"/website.json") || !fileOp.Stat(temPathWithName+".conf") || !fileOp.Stat(temPathWithName+".web.tar.gz") {
|
||||||
|
return buserr.WithDetail(constant.ErrBackupExist, ".conf or .web.tar.gz", nil)
|
||||||
|
}
|
||||||
|
if website.Type == constant.Deployment {
|
||||||
|
if !fileOp.Stat(temPathWithName + ".app.tar.gz") {
|
||||||
|
return buserr.WithDetail(constant.ErrBackupExist, ".app.tar.gz", nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
isOk := false
|
isOk := false
|
||||||
if !isRollback {
|
if !isRollback {
|
||||||
rollbackFile := path.Join(global.CONF.System.TmpDir, fmt.Sprintf("website/%s_%s.tar.gz", website.Alias, time.Now().Format("20060102150405")))
|
rollbackFile := path.Join(global.CONF.System.TmpDir, fmt.Sprintf("website/%s_%s.tar.gz", website.Alias, time.Now().Format("20060102150405")))
|
||||||
|
|
|
@ -582,24 +582,6 @@ func (u *FirewallService) addAddressRecord(req dto.AddrRuleOperate) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func listIpRules(strategy string) ([]string, error) {
|
|
||||||
client, err := firewall.NewFirewallClient()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
addrs, err := client.ListAddress()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
var rules []string
|
|
||||||
for _, addr := range addrs {
|
|
||||||
if addr.Strategy == strategy {
|
|
||||||
rules = append(rules, addr.Address)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return rules, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func checkPortUsed(ports, proto string, apps []portOfApp) string {
|
func checkPortUsed(ports, proto string, apps []portOfApp) string {
|
||||||
var portList []int
|
var portList []int
|
||||||
if strings.Contains(ports, "-") || strings.Contains(ports, ",") {
|
if strings.Contains(ports, "-") || strings.Contains(ports, ",") {
|
||||||
|
|
|
@ -104,6 +104,9 @@ func (w WebsiteCAService) Create(create request.WebsiteCACreate) (*request.Websi
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
rootCert, err := x509.ParseCertificate(rootDer)
|
rootCert, err := x509.ParseCertificate(rootDer)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
certBlock := &pem.Block{
|
certBlock := &pem.Block{
|
||||||
Type: "CERTIFICATE",
|
Type: "CERTIFICATE",
|
||||||
Bytes: rootCert.Raw,
|
Bytes: rootCert.Raw,
|
||||||
|
|
|
@ -60,6 +60,7 @@ func Init() {
|
||||||
migrations.AddDatabaseSSL,
|
migrations.AddDatabaseSSL,
|
||||||
migrations.AddDefaultCA,
|
migrations.AddDefaultCA,
|
||||||
migrations.AddSettingRecycleBin,
|
migrations.AddSettingRecycleBin,
|
||||||
|
migrations.UpdateWebsiteBackupRecord,
|
||||||
})
|
})
|
||||||
if err := m.Migrate(); err != nil {
|
if err := m.Migrate(); err != nil {
|
||||||
global.LOG.Error(err)
|
global.LOG.Error(err)
|
||||||
|
|
|
@ -3,6 +3,7 @@ package migrations
|
||||||
import (
|
import (
|
||||||
"github.com/1Panel-dev/1Panel/backend/app/dto/request"
|
"github.com/1Panel-dev/1Panel/backend/app/dto/request"
|
||||||
"github.com/1Panel-dev/1Panel/backend/app/model"
|
"github.com/1Panel-dev/1Panel/backend/app/model"
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/app/repo"
|
||||||
"github.com/1Panel-dev/1Panel/backend/app/service"
|
"github.com/1Panel-dev/1Panel/backend/app/service"
|
||||||
"github.com/go-gormigrate/gormigrate/v2"
|
"github.com/go-gormigrate/gormigrate/v2"
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
|
@ -87,3 +88,18 @@ var AddSettingRecycleBin = &gormigrate.Migration{
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var UpdateWebsiteBackupRecord = &gormigrate.Migration{
|
||||||
|
ID: "20231218-update-backup-record-for-website",
|
||||||
|
Migrate: func(tx *gorm.DB) error {
|
||||||
|
backupRepo := repo.NewIBackupRepo()
|
||||||
|
websitesBackups, _ := backupRepo.ListRecord(repo.NewCommonRepo().WithByType("website"))
|
||||||
|
if len(websitesBackups) > 0 {
|
||||||
|
for _, backup := range websitesBackups {
|
||||||
|
backup.DetailName = backup.Name
|
||||||
|
_ = backupRepo.UpdateRecord(&backup)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
|
@ -88,13 +88,6 @@ func IsCrossVersion(version1, version2 string) bool {
|
||||||
return v2num > v1num
|
return v2num > v1num
|
||||||
}
|
}
|
||||||
|
|
||||||
func min(a, b int) int {
|
|
||||||
if a < b {
|
|
||||||
return a
|
|
||||||
}
|
|
||||||
return b
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetUuid() string {
|
func GetUuid() string {
|
||||||
b := make([]byte, 16)
|
b := make([]byte, 16)
|
||||||
_, _ = io.ReadFull(rand.Reader, b)
|
_, _ = io.ReadFull(rand.Reader, b)
|
||||||
|
|
|
@ -142,6 +142,9 @@ const acceptParams = async (params: DialogProps): Promise<void> => {
|
||||||
} else {
|
} else {
|
||||||
baseDir.value = `${pathRes.data}/uploads/${dir}/${name.value}/`;
|
baseDir.value = `${pathRes.data}/uploads/${dir}/${name.value}/`;
|
||||||
}
|
}
|
||||||
|
if (type.value === 'website') {
|
||||||
|
baseDir.value = `${pathRes.data}/uploads/database/${type.value}/${detailName.value}/`;
|
||||||
|
}
|
||||||
upVisible.value = true;
|
upVisible.value = true;
|
||||||
search();
|
search();
|
||||||
};
|
};
|
||||||
|
|
|
@ -5,6 +5,9 @@
|
||||||
<el-form-item :label="$t('website.primaryDomain')" prop="primaryDomain">
|
<el-form-item :label="$t('website.primaryDomain')" prop="primaryDomain">
|
||||||
<el-input v-model="form.primaryDomain"></el-input>
|
<el-input v-model="form.primaryDomain"></el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
<el-form-item :label="$t('website.alias')" prop="primaryDomain">
|
||||||
|
<el-input v-model="form.alias" disabled></el-input>
|
||||||
|
</el-form-item>
|
||||||
<el-form-item :label="$t('website.group')" prop="webSiteGroupID">
|
<el-form-item :label="$t('website.group')" prop="webSiteGroupID">
|
||||||
<el-select v-model="form.webSiteGroupId">
|
<el-select v-model="form.webSiteGroupId">
|
||||||
<el-option
|
<el-option
|
||||||
|
@ -21,6 +24,7 @@
|
||||||
<el-form-item prop="IPV6">
|
<el-form-item prop="IPV6">
|
||||||
<el-checkbox v-model="form.IPV6" :label="$t('website.ipv6')" size="large" />
|
<el-checkbox v-model="form.IPV6" :label="$t('website.ipv6')" size="large" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-form-item>
|
<el-form-item>
|
||||||
<el-button type="primary" @click="submit(websiteForm)" :disabled="loading">
|
<el-button type="primary" @click="submit(websiteForm)" :disabled="loading">
|
||||||
{{ $t('commons.button.save') }}
|
{{ $t('commons.button.save') }}
|
||||||
|
@ -58,6 +62,7 @@ const form = reactive({
|
||||||
remark: '',
|
remark: '',
|
||||||
webSiteGroupId: 0,
|
webSiteGroupId: 0,
|
||||||
IPV6: false,
|
IPV6: false,
|
||||||
|
alias: '',
|
||||||
});
|
});
|
||||||
const rules = ref({
|
const rules = ref({
|
||||||
primaryDomain: [Rules.requiredInput],
|
primaryDomain: [Rules.requiredInput],
|
||||||
|
@ -91,6 +96,7 @@ const search = async () => {
|
||||||
form.remark = res.data.remark;
|
form.remark = res.data.remark;
|
||||||
form.webSiteGroupId = res.data.webSiteGroupId;
|
form.webSiteGroupId = res.data.webSiteGroupId;
|
||||||
form.IPV6 = res.data.IPV6;
|
form.IPV6 = res.data.IPV6;
|
||||||
|
form.alias = res.data.alias;
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -379,7 +379,7 @@ const buttons = [
|
||||||
let params = {
|
let params = {
|
||||||
type: 'website',
|
type: 'website',
|
||||||
name: row.primaryDomain,
|
name: row.primaryDomain,
|
||||||
detailName: '',
|
detailName: row.alias,
|
||||||
};
|
};
|
||||||
dialogBackupRef.value!.acceptParams(params);
|
dialogBackupRef.value!.acceptParams(params);
|
||||||
},
|
},
|
||||||
|
@ -390,7 +390,7 @@ const buttons = [
|
||||||
let params = {
|
let params = {
|
||||||
type: 'website',
|
type: 'website',
|
||||||
name: row.primaryDomain,
|
name: row.primaryDomain,
|
||||||
detailName: '',
|
detailName: row.alias,
|
||||||
};
|
};
|
||||||
uploadRef.value!.acceptParams(params);
|
uploadRef.value!.acceptParams(params);
|
||||||
},
|
},
|
||||||
|
|
Loading…
Reference in a new issue