[Agent][Deploy] - add zjyd

This commit is contained in:
zeaslity
2024-08-20 09:35:32 +08:00
parent 1828116d8a
commit 40b540f082
252 changed files with 21873 additions and 25482 deletions

View File

@@ -0,0 +1,512 @@
package main
import (
"errors"
"os"
"slices"
"strings"
image2 "wdd.io/agent-common/image"
"wdd.io/agent-common/utils"
"wdd.io/agent-deploy/d_app"
"wdd.io/agent-operator/image"
)
const OfflineDeployHarborHost = "harbor.wdd.io"
const PublicDeployHarborHost = "42.192.52.227"
const DirectPushDeployHarborHost = "chongqingcis-9b4a3da9.ecis.chongqing-1.cmecloud.cn"
type ImageSyncEntity struct {
ProjectName string // 优先级3 优先级最低 从DEMO拉取镜像
ProjectVersion string // 优先级2 高于ProjectName 优先拉取特定版本的镜像
CmiiNameTagList []string // 优先级1 appName:tag 会被转换为FullNameImageList
FullNameImageList []string // 优先级1 优先下载此类型
ShouldDownloadImage bool // 下载镜像 DCU中的D
ShouldCompressImageToGzip bool // 压缩镜像 DCU中的C
ShouldUploadToDemoMinio bool // 上传镜像 DCU中的U
ShouldDownloadFromOss bool // 下载镜像 DLTU中的D
ShouldUpdateImageTag bool // 更新镜像 DLTU中的U
ShouldDirectPushToHarbor bool // 直接推送到对方的主机 || 离线部署机
DirectHarborHost string // IP:Port or 域名:PORT 不带http前缀
}
type ImageSyncResult struct {
ErrorPullImageList []string
ErrorGzipImageList []string
ErrorPushImageNameList []string
RealImageNameList []string
RealGzipFileNameList []string
AllCmiiImageNameList []string
}
// PullFromEntityAndSyncConditionally 根据ImageSyncEntity拉取特定的镜像然后上传到特定的目标机器(或者上传的minio中)
func (sync ImageSyncEntity) PullFromEntityAndSyncConditionally() (imageSyncResult ImageSyncResult) {
var realCmiiImageList []string
var allCmiiImageNameList []string
var errorPullImageList []string
var allGzipFileNameList []string
var errorGzipImageList []string
var errorPushImageNameList []string
var gzipFolderFullPath string
if (sync.CmiiNameTagList == nil && sync.FullNameImageList == nil) || (len(sync.CmiiNameTagList) == 0 && len(sync.FullNameImageList) == 0) {
// 没有指定特定的镜像,那么根据 ProjectVersion 或者从DEMO拉取镜像
// pull images
// compress
if sync.ProjectVersion != "" {
// 获取特定版本的镜像
errorPullImageList, errorGzipImageList, allCmiiImageNameList, allGzipFileNameList = C_DownloadCompressUploadFromVersion(sync.ProjectVersion, sync.ShouldCompressImageToGzip, sync.ShouldUploadToDemoMinio)
gzipFolderFullPath = image.OfflineImageGzipFolderPrefix + sync.ProjectVersion
} else {
// 获取DEMO的镜像
errorPullImageList, errorGzipImageList, allCmiiImageNameList, allGzipFileNameList = C_DownloadCompressUploadFromDemo(sync.ProjectName, sync.ShouldCompressImageToGzip, sync.ShouldUploadToDemoMinio)
gzipFolderFullPath = image.OfflineImageGzipFolderPrefix + sync.ProjectName
}
} else {
// 拉取特定的镜像
gzipFolderFullPath = image.OfflineImageGzipFolderPrefix + "tmp"
// 组装镜像名称
allCmiiImageNameList = concatAndUniformCmiiImage(sync.FullNameImageList, sync.CmiiNameTagList)
// DCU
errorPullImageList, errorGzipImageList, realCmiiImageList, allGzipFileNameList = A_DownloadCompressUpload(true, allCmiiImageNameList, sync.ShouldCompressImageToGzip, gzipFolderFullPath, sync.ShouldUploadToDemoMinio)
}
// 直接传输到目标Harbor仓库
if sync.ShouldDirectPushToHarbor {
if sync.DirectHarborHost == "" {
log.ErrorF("DirectHarborHost is null ! can't push to target harbor !")
}
// push to
errorPushImageNameList = image.TagFromListAndPushToCHarbor(allCmiiImageNameList, sync.DirectHarborHost)
}
// build result
imageSyncResult.AllCmiiImageNameList = allCmiiImageNameList
imageSyncResult.RealImageNameList = realCmiiImageList
imageSyncResult.ErrorPullImageList = errorPullImageList
imageSyncResult.RealGzipFileNameList = allGzipFileNameList
imageSyncResult.ErrorGzipImageList = errorGzipImageList
imageSyncResult.ErrorPushImageNameList = errorPushImageNameList
return imageSyncResult
}
func concatAndUniformCmiiImage(fullImageList []string, cmiiImageList []string) []string {
if cmiiImageList != nil || len(cmiiImageList) > 0 {
// cmiiImageList has content
if fullImageList == nil {
fullImageList = []string{}
}
for _, cmiiImage := range cmiiImageList {
fullImageList = append(fullImageList, image2.CmiiHarborPrefix+cmiiImage)
}
}
return fullImageList
}
// A_DownloadCompressUpload DCU 镜像同步的前半部分通常在35.71 LapPro执行无需Bastion Mode
func A_DownloadCompressUpload(downloadImage bool, fullNameList []string, shouldGzip bool, gzipFolderFullPath string, shouldOss bool) (errorPullImageList, errorGzipImageList, realCmiiImageName, allGzipFileFullNameList []string) {
// write to file
localGzipFileListTxt := gzipFolderFullPath + "all-gzip-image-file-name.txt"
// Download
log.Info("DOWNLOAD START !")
if downloadImage {
if fullNameList == nil || len(fullNameList) == 0 {
log.InfoF("no image name list !")
} else {
errorPullImageList = image.PullFromFullNameList(fullNameList)
}
}
// remove failed
fullNameList = slices.DeleteFunc(fullNameList, func(imageName string) bool {
return slices.Contains(errorPullImageList, imageName)
})
// Compress
if shouldGzip {
// remove file
_ = os.Remove(localGzipFileListTxt)
gzipFileAlready := make(map[string]bool)
if utils.FileOrFolderExists(gzipFolderFullPath) {
dir, _ := os.ReadDir(gzipFolderFullPath)
for _, entry := range dir {
if entry.IsDir() {
continue
}
gzipFileAlready[strings.TrimPrefix(entry.Name(), gzipFolderFullPath)] = true
}
}
// mkdir folder
err := os.MkdirAll(gzipFolderFullPath, os.ModeDir)
if err != nil {
if !errors.Is(err, os.ErrExist) {
log.ErrorF("create folder error of %s", gzipFolderFullPath)
panic(err)
}
}
// 循环遍历压缩
log.Info("COMPRESS START")
for _, imageFullName := range fullNameList {
// gzip image file already exists
gzipFileName := image2.ImageFullNameToGzipFileName(imageFullName)
gzipImageFileFullPath := gzipFolderFullPath + gzipFileName
_, ok := gzipFileAlready[gzipFileName]
if len(gzipFileAlready) > 0 && ok {
log.DebugF("gzip file %s already exists !", gzipFileName)
} else {
ok, gzipImageFileFullPath = image.SaveToGzipFile(imageFullName, gzipFolderFullPath)
if !ok {
errorGzipImageList = append(errorGzipImageList, imageFullName)
continue
}
}
// 压缩成功
allGzipFileFullNameList = append(allGzipFileFullNameList, gzipImageFileFullPath)
}
// remove failed
fullNameList = slices.DeleteFunc(fullNameList, func(imageName string) bool {
return slices.Contains(errorGzipImageList, imageName)
})
for _, gzipFileFullName := range allGzipFileFullNameList {
utils.AppendContentToFile(
strings.TrimPrefix(gzipFileFullName, gzipFolderFullPath)+"\n",
localGzipFileListTxt,
)
}
log.InfoF("all gzip file name list is %s", localGzipFileListTxt)
}
// Upload
if shouldOss {
//uploadGzipFileToDemoMinio()
// get gzip file name list
log.Info("UPLOAD OSS START !")
// start to upload
// extract demo oss location suffix from gzipFolderFullPath
trimPrefix := strings.TrimPrefix(gzipFolderFullPath, image.OfflineImageGzipFolderPrefix)
bucketNameWithPrefix := "cmlc-installation/" + trimPrefix
log.InfoF("gzip file location in demo oss is %s", DefaultDemoEndpoint+"/"+bucketNameWithPrefix)
// upload gzip file list txt to demo
if !DefaultCmiiMinioOperator.UploadToDemo(bucketNameWithPrefix, gzipFolderFullPath, strings.TrimPrefix(localGzipFileListTxt, gzipFolderFullPath)) {
log.ErrorF("upload of %s to demo oss error !", localGzipFileListTxt)
}
log.InfoF("upload all gzip file to demo oss !")
for _, gzipFileFullName := range allGzipFileFullNameList {
// SaveToGzipFile 返回的是全路径 归一化处理 gzip file name
gzipFileFullName = strings.TrimPrefix(gzipFileFullName, gzipFolderFullPath)
if !DefaultCmiiMinioOperator.UploadToDemo(bucketNameWithPrefix, gzipFolderFullPath, gzipFileFullName) {
log.ErrorF("upload of %s to demo oss error !", gzipFileFullName)
}
}
}
return errorPullImageList, errorGzipImageList, fullNameList, allGzipFileFullNameList
}
// A_DownloadLoadTagUpload DLTU procedure ImageSync的另外一般流程需要支持 堡垒机(纯离线)的模式
// 2. Gzip文件目录RKE MIDDLE CMII三个文件目录 - 约定目录
// 约定目录 /root/wdd/image/rke/ /root/wdd/image/middle/ /root/wdd/image/cmii/
// 3. 读取本机的IP地址 - 参数传递
// 4. OSS地址 - ossUrlPrefix传空 则使用默认值
// 5. ossFileName - 如果结尾为txt则为文件的形式如果为tar.gz则为gzip文件夹的形式
func A_DownloadLoadTagUpload(downloadFromOss bool, ossUrlPrefix, ossFileNameOrGzipFileListTxt, localGzipFolderOrGzipFile string, targetHarborFullName string) (targetImageFullNameList []string) {
// 支持单文件的形式
if !utils.IsDirOrFile(localGzipFolderOrGzipFile) {
// 单个压缩文件 肯定是离线的形式
if !strings.HasSuffix(localGzipFolderOrGzipFile, ".tar.gz") {
log.ErrorF("local gzip file %s is not a .tar.gz file !", localGzipFolderOrGzipFile)
return nil
}
// load
image.LoadFromGzipFilePath(localGzipFolderOrGzipFile)
} else {
separator := os.PathSeparator
if !strings.HasSuffix(localGzipFolderOrGzipFile, string(separator)) {
localGzipFolderOrGzipFile += string(separator)
}
// download
if downloadFromOss {
if !parseAndDownloadFromOss(ossUrlPrefix, ossFileNameOrGzipFileListTxt, localGzipFolderOrGzipFile) {
log.ErrorF("download from oss error !")
return nil
}
}
// load
loadAllGzipImageFromLocalFolder(localGzipFolderOrGzipFile)
}
// tag
// push
allFileInFolder, err := utils.ListAllFileInFolder(localGzipFolderOrGzipFile)
if err != nil {
return nil
}
for _, gzipFileName := range allFileInFolder {
// 过滤非.tar.gz结尾的文件
if !strings.HasSuffix(gzipFileName, ".tar.gz") {
continue
}
log.DebugF("gzip file name is %s", gzipFileName)
// gzip to image full name 拿到镜像的原始名称
imageFullName := image2.GzipFileNameToImageFullName(gzipFileName)
if imageFullName == "" {
log.ErrorF("gzip file %s to image full name error !", gzipFileName)
continue
}
// tag 拿到目标名称 然后重新Tag
targetImageFullName := image2.ImageNameToTargetImageFullName(imageFullName, targetHarborFullName)
image.TagFromSourceToTarget(imageFullName, targetImageFullName)
// uploadToHarbor 上传到目标Harbor
if image.UploadToHarbor(targetImageFullName) {
targetImageFullNameList = append(targetImageFullNameList, targetImageFullName)
} else {
log.ErrorF("upload to harbor error of %s", targetImageFullName)
}
}
return targetImageFullNameList
}
func loadAllGzipImageFromLocalFolder(localGzipFolder string) {
image.LoadFromFolderPath(localGzipFolder)
}
func parseAndDownloadFromOss(ossUrlPrefix, ossFileName, localGzipFolder string) bool {
if ossUrlPrefix == "" {
ossUrlPrefix = DefaultOssUrlPrefix
}
if !strings.HasSuffix(ossUrlPrefix, "/") {
ossUrlPrefix += "/"
}
log.InfoF("prepare to download from %s%s", ossUrlPrefix, ossFileName)
if !DefaultCmiiMinioOperator.DemoMinioOperator.DownloadFileFromOssFullUrl(ossUrlPrefix+ossFileName, localGzipFolder) {
log.ErrorF("download %s from oss error !", ossUrlPrefix+ossFileName)
return false
}
if strings.HasSuffix(ossFileName, ".txt") {
// download from gzip file list txt
// download all files in the txt file
result := utils.ReadAllContentFromFile(localGzipFolder + ossFileName)
for _, gzipFileName := range result {
DefaultCmiiMinioOperator.DemoMinioOperator.DownloadFileFromOssFullUrl(ossUrlPrefix+gzipFileName, localGzipFolder)
}
}
// 解析
return true
}
// C_DownloadCompressUploadFromDemo 获取DEMO环境的全部镜像
func C_DownloadCompressUploadFromDemo(projectName string, shouldGzip, shouldOss bool) (errorPullImageList, errorGzipImageList, realCmiiImageName, allGzipFileNameList []string) {
// generate a project folder
err := os.MkdirAll(image.OfflineImageGzipFolderPrefix+projectName, os.ModeDir)
if err != nil {
if !errors.Is(err, os.ErrExist) {
log.ErrorF("[Download_Compress_Upload_From_Demo] - create folder of %s error %s", image.OfflineImageGzipFolderPrefix+projectName, err.Error())
return errorPullImageList, errorGzipImageList, realCmiiImageName, allGzipFileNameList
}
}
// get demo image version map
allCmiiImageNameListFromDemo := buildAllCmiiImageNameListFromDemo(projectName)
// do work
// DCU
return A_DownloadCompressUpload(true, allCmiiImageNameListFromDemo, shouldGzip, image.OfflineImageGzipFolderPrefix+projectName, shouldOss)
}
func buildAllCmiiImageNameListFromDemo(projectName string) []string {
var realCmiiImageName []string
backendMap, frontendMap, srsMap := BackupAllCmiiDeploymentToMap(demo)
// save map to file
backendMapFile := image.OfflineImageGzipFolderPrefix + projectName + "-backend-app.json"
frontendMapFile := image.OfflineImageGzipFolderPrefix + projectName + "-frontend-app.json"
srsMapFile := image.OfflineImageGzipFolderPrefix + projectName + "-srs-app.json"
_ = os.Remove(backendMapFile)
_ = os.Remove(frontendMapFile)
_ = os.Remove(srsMapFile)
//utils.AppendContentToFile(
// utils.BeautifulPrintToString(backendMap),
// backendMapFile,
//)
//utils.AppendContentToFile(
// utils.BeautifulPrintToString(frontendMap),
// frontendMapFile,
//)
//utils.AppendContentToFile(
// utils.BeautifulPrintToString(srsMapFile),
// srsMapFile,
//)
realCmiiImageName = append(realCmiiImageName, image.CmiiImageMapToFullNameList(backendMap)...)
realCmiiImageName = append(realCmiiImageName, image.CmiiImageMapToFullNameList(frontendMap)...)
realCmiiImageName = append(realCmiiImageName, image.CmiiImageMapToFullNameList(srsMap)...)
utils.BeautifulPrintListWithTitle(realCmiiImageName, "Cmii Project Image => "+projectName)
return realCmiiImageName
}
// C_DownloadCompressUploadFromVersion 根据版本下载全部的CMII镜像
func C_DownloadCompressUploadFromVersion(cmiiVersion string, shouldGzip bool, shouldOss bool) (errorPullImageList, errorGzipImageList, realCmiiImageName, allGzipFileNameList []string) {
// generate a project folder
err := os.MkdirAll(image.OfflineImageGzipFolderPrefix+cmiiVersion, os.ModeDir)
if err != nil {
if !errors.Is(err, os.ErrExist) {
log.ErrorF("[Download_Compress_Upload_From_Demo] - create folder of %s error %s", image.OfflineImageGzipFolderPrefix+cmiiVersion, err.Error())
return errorPullImageList, errorGzipImageList, realCmiiImageName, allGzipFileNameList
}
}
// build all cmii image name list
realCmiiImageName = buildAllCmiiImageNameListFromVersion(cmiiVersion)
// do work
// DCU procedure
return A_DownloadCompressUpload(true, realCmiiImageName, shouldGzip, image.OfflineImageGzipFolderPrefix+cmiiVersion, shouldOss)
}
func buildAllCmiiImageNameListFromVersion(cmiiVersion string) []string {
var realCmiiImageName []string
backendMap := d_app.CmiiBackendAppMap
frontendMap := d_app.CmiiFrontendAppMap
for app := range backendMap {
backendMap[app] = cmiiVersion
}
for app := range frontendMap {
frontendMap[app] = cmiiVersion
}
realCmiiImageName = append(realCmiiImageName, image.CmiiImageMapToFullNameList(backendMap)...)
realCmiiImageName = append(realCmiiImageName, image.CmiiImageMapToFullNameList(frontendMap)...)
for key, value := range d_app.CmiiSrsAppMap {
var app *CmiiDeploymentInterface
if strings.Contains(value, "deployment") {
app = DefaultCmiiOperator.DeploymentOneInterface(demo, key)
if app != nil {
realCmiiImageName = append(realCmiiImageName, app.Image)
}
} else if strings.Contains(value, "state") {
app = DefaultCmiiOperator.StatefulSetOneInterface(demo, key)
if app != nil {
for _, imageName := range app.ContainerImageMap {
realCmiiImageName = append(realCmiiImageName, imageName)
}
}
}
}
utils.BeautifulPrintListWithTitle(realCmiiImageName, "Cmii Version Image => "+cmiiVersion)
return realCmiiImageName
}
// C_DownloadCompressUploadDependency DCU所有的依赖镜像
func C_DownloadCompressUploadDependency(shouldGzip bool, shouldOss bool, shouldDownload bool, isRKE bool) (errorPullImageList, errorGzipImageList, realCmiiImageName, allGzipFileNameList []string) {
log.Info("DCU for middle and rke!")
err := os.MkdirAll(image.OfflineImageGzipFolderPrefix, os.ModeDir)
if err != nil {
if !errors.Is(err, os.ErrExist) {
log.ErrorF("[FetchDependencyRepos] - create folder of %s error %s", image.OfflineImageGzipFolderPrefix, err.Error())
}
}
var fulleImageNameList []string
var gzipFolderPrefix string
if isRKE {
log.Info("DCU for rke!")
fulleImageNameList = d_app.Rancher1204Amd64
gzipFolderPrefix = image.OfflineImageGzipFolderPrefix + "rke/"
} else {
log.Info("DCU for middle!")
fulleImageNameList = d_app.MiddlewareAmd64
gzipFolderPrefix = image.OfflineImageGzipFolderPrefix + "middle/"
}
return A_DownloadCompressUpload(shouldDownload, fulleImageNameList, shouldGzip, gzipFolderPrefix, shouldOss)
}
func LoadSplitCmiiGzipImageToTargetHarbor(projectName, targetHarborHost string) (errorLoadImageNameList, errorPushImageNameList []string) {
// list folder
projectGzipFolder := image.OfflineImageGzipFolderPrefix + projectName
errorLoadImageNameList = append(errorLoadImageNameList, image.LoadFromFolderPath(projectGzipFolder)...)
// read from json
errorPushImageNameList = append(errorPushImageNameList, image.TagFromListAndPushToCHarbor(d_app.Cmii520DemoImageList, targetHarborHost)...)
// re-tag
// push
// todo clean host and harbor
// check harbor exits
return errorLoadImageNameList, errorPushImageNameList
}
func LoadSplitDepGzipImageToTargetHarbor(targetHarborHost string) (errorLoadImageNameList []string, errorPushImageNameList []string) {
errorPushImageNameList = append(errorPushImageNameList, image.TagFromListAndPushToCHarbor(d_app.MiddlewareAmd64, targetHarborHost)...)
//errorPushImageNameList = append(errorPushImageNameList, image.TagFromListAndPushToCHarbor(d_app.Rancher1204Amd64, targetHarborHost)...)
return errorLoadImageNameList, errorPushImageNameList
}