-
Notifications
You must be signed in to change notification settings - Fork 250
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
6571bcf
commit 8b0e922
Showing
21 changed files
with
7,781 additions
and
5,345 deletions.
There are no files selected for viewing
206 changes: 206 additions & 0 deletions
206
bcs-services/bcs-bscp/cmd/api-server/service/config_import.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,206 @@ | ||
/* | ||
* Tencent is pleased to support the open source community by making Blueking Container Service available. | ||
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. | ||
* Licensed under the MIT License (the "License"); you may not use this file except | ||
* in compliance with the License. You may obtain a copy of the License at | ||
* http://opensource.org/licenses/MIT | ||
* Unless required by applicable law or agreed to in writing, software distributed under | ||
* the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, | ||
* either express or implied. See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
package service | ||
|
||
import ( | ||
"bytes" | ||
"crypto/sha256" | ||
"encoding/hex" | ||
"errors" | ||
"fmt" | ||
"io" | ||
"io/fs" | ||
"net/http" | ||
"os" | ||
"path/filepath" | ||
"strings" | ||
"unicode/utf8" | ||
|
||
"github.com/go-chi/render" | ||
|
||
"bscp.io/pkg/cc" | ||
"bscp.io/pkg/criteria/constant" | ||
"bscp.io/pkg/dal/repository" | ||
"bscp.io/pkg/iam/auth" | ||
"bscp.io/pkg/kit" | ||
pbcs "bscp.io/pkg/protocol/config-server" | ||
"bscp.io/pkg/rest" | ||
"bscp.io/pkg/runtime/archive" | ||
"bscp.io/pkg/types" | ||
) | ||
|
||
type configImport struct { | ||
authorizer auth.Authorizer | ||
provider repository.Provider | ||
cfgClient pbcs.ConfigClient | ||
} | ||
|
||
// FileImport Import config file | ||
func (c *configImport) FileImport(w http.ResponseWriter, r *http.Request) { | ||
kt := kit.MustGetKit(r.Context()) | ||
|
||
// Validation size | ||
|
||
if r.ContentLength > constant.ContentLength { | ||
_ = render.Render(w, r, rest.BadRequest(errors.New("request body size exceeds 100MB"))) | ||
return | ||
} | ||
|
||
// Unzip file | ||
unpackTempDir, err := archive.Unpack(r.Body) | ||
if err != nil { | ||
_ = render.Render(w, r, rest.BadRequest(err)) | ||
return | ||
} | ||
// 删除临时文件夹 | ||
defer func() { _ = os.RemoveAll(unpackTempDir) }() | ||
|
||
folder, err := c.scanFolder(kt, unpackTempDir, unpackTempDir) | ||
if err != nil { | ||
_ = render.Render(w, r, rest.BadRequest(err)) | ||
return | ||
} | ||
exist := make([]*types.TemplateItem, 0) | ||
|
||
nonExist := make([]*types.TemplateItem, 0) | ||
for _, item := range folder { | ||
// 验证模板配置文件是否存在 | ||
template, _ := c.cfgClient.GetTemplateDetailByUniqueKey(kt.RpcCtx(), &pbcs.GetTemplateDetailByUniqueKeyReq{ | ||
TemplateSpaceId: kt.TmplSpaceID, | ||
BizId: kt.BizID, | ||
Name: item.Name, | ||
Path: item.Path, | ||
}) | ||
if template.GetTemplate().GetId() != 0 { | ||
exist = append(exist, &types.TemplateItem{ | ||
Id: template.GetTemplate().GetId(), | ||
Name: item.Name, | ||
Path: item.Path, | ||
FileType: item.FileType, | ||
FileMode: template.GetTemplateRevision().GetFileMode(), | ||
Memo: template.GetTemplate().GetSpec().GetMemo(), | ||
Privilege: template.GetTemplateRevision().GetPermission().GetPrivilege(), | ||
User: template.GetTemplateRevision().GetPermission().GetUser(), | ||
UserGroup: template.GetTemplateRevision().GetPermission().GetUserGroup(), | ||
Sign: item.Sign, | ||
ByteSize: item.ByteSize, | ||
}) | ||
} else { | ||
nonExist = append(nonExist, &types.TemplateItem{ | ||
Name: item.Name, | ||
Path: item.Path, | ||
FileType: item.FileType, | ||
FileMode: constant.FileMode, | ||
Sign: item.Sign, | ||
ByteSize: item.ByteSize, | ||
}) | ||
} | ||
} | ||
_ = render.Render(w, r, rest.OKRender(&types.TemplatesImportResp{ | ||
Exist: exist, | ||
NonExist: nonExist, | ||
})) | ||
} | ||
|
||
// 扫描文件夹 | ||
// fileDir 文件目录 | ||
// rootDir 根目录 | ||
func (c *configImport) scanFolder(kt *kit.Kit, fileDir, rootDir string) ([]*types.FileInfo, error) { | ||
fileData := make([]*types.FileInfo, 0) | ||
err := filepath.WalkDir(fileDir, func(path string, d fs.DirEntry, err error) error { | ||
if !d.IsDir() { | ||
info, err := c.uploadFile(kt, path, rootDir) | ||
if err != nil { | ||
return err | ||
} | ||
fileData = append(fileData, info) | ||
} | ||
return nil | ||
}) | ||
if err != nil { | ||
return nil, err | ||
} | ||
return fileData, nil | ||
} | ||
|
||
// 上传文件 | ||
func (c *configImport) uploadFile(kt *kit.Kit, filePath, rootDir string) (*types.FileInfo, error) { | ||
var ( | ||
content bytes.Buffer | ||
fileType = "text" | ||
fileDir = "" | ||
) | ||
fileContent, err := os.Open(filePath) | ||
if err != nil { | ||
return nil, fmt.Errorf("open file fail %s: %v\n", filePath, err) | ||
} | ||
|
||
defer func(fileContent *os.File) { | ||
_ = fileContent.Close() | ||
}(fileContent) | ||
|
||
_, err = io.Copy(&content, fileContent) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
// 计算文件的SHA-256散列值 | ||
hash := sha256.New() | ||
hash.Write(content.Bytes()) | ||
hashInBytes := hash.Sum(nil) | ||
hashString := hex.EncodeToString(hashInBytes) | ||
// 处理路径、名称、文件类型 | ||
fileInfo, err := fileContent.Stat() | ||
if err != nil { | ||
return nil, err | ||
} | ||
// Check if the file size is greater than 5MB (5 * 1024 * 1024 bytes) | ||
if fileInfo.Size() > constant.MaxFileSize { | ||
fileType = "binary" | ||
} else { | ||
if !utf8.Valid(content.Bytes()) { | ||
fileType = "binary" | ||
} | ||
} | ||
fileDir = strings.Replace(filePath, rootDir, "", 1) | ||
fileDir = strings.Replace(fileDir, "\\", "/", -1) | ||
lastSlashIndex := strings.LastIndex(fileDir, "/") | ||
if lastSlashIndex >= 0 { | ||
fileDir = fileDir[:lastSlashIndex] | ||
} | ||
|
||
upload, err := c.provider.Upload(kt, hashString, &content) | ||
if err != nil { | ||
return nil, fmt.Errorf("file upload fail %s: %v\n", filePath, err) | ||
} | ||
return &types.FileInfo{ | ||
Name: fileInfo.Name(), | ||
Path: fileDir, | ||
FileType: fileType, | ||
Sign: upload.Sha256, | ||
ByteSize: uint64(upload.ByteSize), | ||
}, nil | ||
} | ||
|
||
func newConfigImportService(settings cc.Repository, authorizer auth.Authorizer, cfgClient pbcs.ConfigClient) (*configImport, error) { | ||
provider, err := repository.NewProvider(settings) | ||
if err != nil { | ||
return nil, err | ||
} | ||
config := &configImport{ | ||
authorizer: authorizer, | ||
provider: provider, | ||
cfgClient: cfgClient, | ||
} | ||
return config, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.