package cmii_operator import ( "bufio" "context" "encoding/json" "errors" "fmt" "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/filters" "github.com/docker/docker/client" "github.com/klauspost/pgzip" "io" "io/fs" "os" "strconv" "strings" ) var apiClient = newClient() const CmiiHarborPrefix = "harbor.cdcyy.com.cn/cmii/" func newClient() *client.Client { apiClient, err := client.NewClientWithOpts(client.FromEnv) if err != nil { log.ErrorF("[newClient] - new client failed ! => %s", err.Error()) panic(err) } defer apiClient.Close() return apiClient } func GetRunningContainer() []types.Container { return getContainerList(false) } func GetAllContainer() []types.Container { return getContainerList(true) } func getContainerList(all bool) []types.Container { containers, err := apiClient.ContainerList(context.Background(), types.ContainerListOptions{ Quiet: false, Size: false, All: all, Latest: false, Limit: 0, Filters: filters.Args{}, }) if err != nil { log.ErrorF("[getContainerList] - error => %s", err.Error()) } return containers } func ImageGetAll() []types.ImageSummary { list, err := apiClient.ImageList(context.TODO(), types.ImageListOptions{ All: true, Filters: filters.Args{}, }) if err != nil { log.ErrorF("[ImageGetAll] --error => %s", err.Error()) } return list } func ImageGetByName(imageName string) *types.ImageSummary { imageGetAll := ImageGetAll() for _, imageSummary := range imageGetAll { for _, tag := range imageSummary.RepoTags { if strings.Contains(tag, imageName) { return &imageSummary } } } return nil } func ImageDelete(imageName string) []types.ImageDeleteResponseItem { imageGetByName := ImageGetByName(imageName) if imageGetByName == nil { log.ErrorF("[ImageDelete] -- image not exists ! %s", imageGetByName.RepoTags) return nil } remove, err := apiClient.ImageRemove(context.TODO(), imageGetByName.ID, types.ImageRemoveOptions{ Force: true, PruneChildren: false, }) if err != nil { log.ErrorF("[ImageDelete] -- ImageRemove error ! %s", err.Error()) return nil } return remove } func ImagePruneAllCmiiImages() (errorRemoveImageNameList []string) { imageGetAll := ImageGetAll() for _, imageSummary := range imageGetAll { if strings.Contains(imageSummary.RepoTags[0], CmiiHarborPrefix) { _, err := apiClient.ImageRemove(context.TODO(), imageSummary.ID, types.ImageRemoveOptions{ Force: true, PruneChildren: false, }) if err != nil { log.ErrorF("[ImageDelete] -- ImageRemove error ! %s", err.Error()) errorRemoveImageNameList = append(errorRemoveImageNameList, imageSummary.RepoTags[0]) } log.InfoF("[ImageDelete] - image remove of [%s] success!", imageSummary.RepoTags[0]) } } return errorRemoveImageNameList } func ImageTagFromSourceToTarget(sourceImageName, targetImageName string) bool { getByName := ImageGetByName(sourceImageName) if getByName == nil { log.ErrorF("[ImageTagFromSourceToTarget] - %s not exits !", sourceImageName) return false } err := apiClient.ImageTag(context.TODO(), sourceImageName, targetImageName) if err != nil { log.ErrorF("[ImageTagFromSourceToTarget] - from %s to %s error %s", sourceImageName, targetImageName, err.Error()) } log.InfoF("[ImageTagFromSourceToTarget] - from %s to %s success!", sourceImageName, targetImageName) return true } func ImagePushToOctopusKindHarbor(targetImageName string) (pushResult io.ReadCloser) { if ImageGetByName(targetImageName) == nil { log.ErrorF("[ImagePushToOctopusKindHarbor] - %s not exits !", targetImageName) return pushResult } pushResult, err := apiClient.ImagePush(context.TODO(), targetImageName, types.ImagePushOptions{ All: false, RegistryAuth: "eyAidXNlcm5hbWUiOiAiYWRtaW4iLCAicGFzc3dvcmQiOiAiVjJyeVN0ckBuZ1BzcyIsICJlbWFpbCI6ICJpY2VAcXEuY29tIiB9Cg==", PrivilegeFunc: nil, Platform: "amd64", }) if err != nil { log.ErrorF("[ImagePushToOctopusKindHarbor] - push %s error %s", targetImageName, err.Error()) return nil } return pushResult } func ImageTagFromListAndPushToCHarbor(referenceImageList []string, targetHarborHost string) (errorPushImageNameList []string) { for _, imageName := range referenceImageList { // check image cmiiImageFullName := imageName if strings.HasPrefix(imageName, "cmii") { cmiiImageFullName = CmiiHarborPrefix + imageName } targetProject := "cmii" if strings.HasPrefix(imageName, "rancher") { targetProject = "rancher" } if strings.Contains(imageName, "/") { imageName = strings.Split(imageName, "/")[1] } targetImageName := targetHarborHost + ":8033/" + targetProject + "/" + imageName if ImageTagFromSourceToTarget(cmiiImageFullName, targetImageName) { pushResult := ImagePushToOctopusKindHarbor(targetImageName) if pushResult == nil { errorPushImageNameList = append(errorPushImageNameList, cmiiImageFullName) continue } scanner := bufio.NewScanner(pushResult) for scanner.Scan() { } log.InfoF("[ImageTagFromListAndPushToCHarbor] - push of %s success!", targetImageName) } else { errorPushImageNameList = append(errorPushImageNameList, cmiiImageFullName) } } return errorPushImageNameList } func ImagePullFromCmiiHarbor(imageName string) (pullResult io.ReadCloser) { pullResult, err := apiClient.ImagePull(context.TODO(), imageName, types.ImagePullOptions{ All: false, RegistryAuth: "eyAidXNlcm5hbWUiOiAicmFkMDJfZHJvbmUiLCAicGFzc3dvcmQiOiAiRHJvbmVAMTIzNCIsICJlbWFpbCI6ICJpY2VAcXEuY29tIiB9Cg==", PrivilegeFunc: func() (string, error) { return "authorization: Basic cmFkMDJfZHJvbmU6RHJvbmVAMTIzNA==", nil }, Platform: "amd64", }) if err != nil { log.ErrorF("[ImagePullFromCmiiHarbor]- image pull of %s ,error => %s", imageName, err.Error()) return nil } return pullResult } func ImagePullFromCmiiHarborByMap(imageVersionMap map[string]string, silentMode bool) (errorPullImageList []string) { fullImageNameList := convertCMiiImageMapToList(imageVersionMap) return ImagePullFromFullNameList(fullImageNameList) } func ImagePullCMiiFromFileJson(filePathName string) { readFile, err := os.ReadFile(filePathName) if err != nil { log.ErrorF("[ImagePullCMiiFromFileJson] - file %s read error ! %s", filePathName, err.Error()) return } var resultMap map[string]string err = json.Unmarshal(readFile, &readFile) if err != nil { log.ErrorF("[ImagePullCMiiFromFileJson] - file %s un marshal error ! %s", filePathName, err.Error()) return } for image, tag := range resultMap { pullResult := ImagePullFromCmiiHarbor(image + ":" + tag) if pullResult == nil { continue } scanner := bufio.NewScanner(pullResult) for scanner.Scan() { line := scanner.Text() if strings.Contains(line, "\"status\":\"Pulling from") { fmt.Println(line) } if strings.Contains(line, "Status: Image is up to date for") { fmt.Println(line) } } fmt.Println() } } func ImagePullFromFullNameList(fullImageNameList []string) (errorPullImageList []string) { for _, dep := range fullImageNameList { pullResult := ImagePullFromCmiiHarbor(dep) if pullResult == nil { errorPullImageList = append(errorPullImageList, dep) continue } scanner := bufio.NewScanner(pullResult) for scanner.Scan() { line := scanner.Text() if strings.Contains(line, "\"status\":\"Pulling from") { fmt.Println(line) } if strings.Contains(line, "Status: Image is up to date for") { fmt.Println(line) } } fmt.Println() } return errorPullImageList } func ImagePullFromListAndCompressSplit(fullImageNameList []string, gzipFolder string) (errorPullImageList, errorGzipImageList []string) { errorPullImageList = ImagePullFromFullNameList(fullImageNameList) // generate a project folder err := os.MkdirAll(gzipFolder, os.ModeDir) if err != nil { if !errors.Is(err, os.ErrExist) { log.ErrorF("[ImagePullFromListAndCompressSplit] - create folder of %s error %s", gzipFolder, err.Error()) } } for _, image := range fullImageNameList { if !ImageSaveToTarGZ(image, gzipFolder) { errorGzipImageList = append(errorGzipImageList, image) } } return errorPullImageList, errorGzipImageList } func ImageLoadFromFile(gzipFullPath string) bool { openFile, err := os.OpenFile(gzipFullPath, 0, fs.ModePerm) if err != nil { log.ErrorF("[ImageLoadFromFile] - failed to open file %s, error is %s", gzipFullPath, err.Error()) return false } loadResponse, err := apiClient.ImageLoad(context.TODO(), openFile, true) if err != nil { log.ErrorF("[ImageLoadFromFile] - load error %s, error is %s", gzipFullPath, err.Error()) return false } log.InfoF("[ImageLoadFromFile] - load of %s, result is %s", gzipFullPath, strconv.FormatBool(loadResponse.JSON)) scanner := bufio.NewScanner(loadResponse.Body) for scanner.Scan() { line := scanner.Text() fmt.Println(line) } return true } func ImageLoadFromFolderPath(folderPath string) (errorLoadImageNameList []string) { if !strings.HasSuffix(folderPath, "/") { folderPath += "/" } dirEntries, err := os.ReadDir(folderPath) if err != nil { log.ErrorF("[ImageLoadFromFolderPath] - error read folder %s error is %s", folderPath, err.Error()) return } // load gzip file for _, dirEntry := range dirEntries { if strings.HasSuffix(dirEntry.Name(), ".tar.gz") { if !ImageLoadFromFile(folderPath + dirEntry.Name()) { errorLoadImageNameList = append(errorLoadImageNameList, folderPath+dirEntry.Name()) } } } return errorLoadImageNameList } func ImageSaveToTarGZ(targetImageName, folderPathPrefix string) bool { imageGetByName := ImageGetByName(targetImageName) if imageGetByName == nil { log.ErrorF("[ImageSaveToTarGZ] - %s not exits", targetImageName) return false } imageSaveTarStream, err := apiClient.ImageSave(context.TODO(), imageGetByName.RepoTags) if err != nil { log.ErrorF("[ImageSaveToTarGZ] - image save error %s", err.Error()) return false } gzipImageFile := convertImageGzipFileName(imageGetByName.RepoTags[0]) if !strings.HasSuffix(folderPathPrefix, "/") { folderPathPrefix += "/" } gzipImageFile = folderPathPrefix + gzipImageFile log.InfoF("[ImageSaveToTarGZ] - start to save [%s] to [%s]", imageGetByName.RepoTags[0], gzipImageFile) _ = os.Remove(gzipImageFile) tarFile, err := os.Create(gzipImageFile) if err != nil { log.ErrorF("[ImageSaveToTarGZ] - error create gzip %s file ! => %s ", gzipImageFile, err.Error()) return false } defer tarFile.Close() // 创建pgzip writer gw, err := pgzip.NewWriterLevel(tarFile, pgzip.DefaultCompression) // 你可以调整压缩级别 if err != nil { log.ErrorF("[ImageSaveToTarGZ] - pgzip create writer error: %s", err.Error()) } defer gw.Close() // Copy the tar archive to the gzip writer. if _, err := io.Copy(gw, imageSaveTarStream); err != nil { log.ErrorF("[ImageSaveToTarGZ] - failed to copy tar archive to gzip writer: %s", err.Error()) return false } return true } func convertImageGzipFileName(imageRepoTag string) (gzipFileName string) { split := strings.Split(imageRepoTag, ":") //log.DebugF(" %s to %s", imageRepoTag, split) if len(split) == 1 { return "docker=" + imageRepoTag + "=latest.tar.gz" } first := strings.Split(split[0], "/") //log.DebugF(" split[0] %s to %s", split[0], first) if len(first) == 3 { if strings.Contains(first[0], "cdcyy") { gzipFileName += "cmlc=" } else { gzipFileName += "docker=" } gzipFileName += first[1] gzipFileName += "=" gzipFileName += first[2] gzipFileName += "=" } else if len(first) == 2 { // gzipFileName += "docker=" gzipFileName += first[0] gzipFileName += "=" gzipFileName += first[1] gzipFileName += "=" } else if len(first) == 1 { // return "docker=" + split[0] + "=" + split[1] + ".tar.gz" } gzipFileName += split[1] gzipFileName += ".tar.gz" return gzipFileName } func convertCMiiImageMapToList(cmiiImageVersionMap map[string]string) (fullImageNameList []string) { for image, tag := range cmiiImageVersionMap { s := CmiiHarborPrefix + image + ":" + tag fullImageNameList = append(fullImageNameList, s) } return fullImageNameList } func loginToDockerHub(HarborFullHost string) { if HarborFullHost == "" { HarborFullHost = "https://registry-1.docker.io" } login, err := apiClient.RegistryLogin(context.TODO(), types.AuthConfig{ Username: "icederce", Password: "loveff.cxc.23", Auth: "aWNlZGVyY2U6bG92ZWZmLmN4Yy4yMw==", ServerAddress: HarborFullHost, }) if err != nil { log.ErrorF("[loginToDockerHub] - login to %s failed !", HarborFullHost) } log.DebugF("[loginToDockerHub] - login is %s", login.Status) }