agent/taskengine/sendfile.go (230 lines of code) (raw):

package taskengine import ( "encoding/base64" "fmt" "io/ioutil" "os" "os/user" "path" "runtime" "strconv" "strings" "github.com/aliyun/aliyun_assist_client/agent/log" "github.com/aliyun/aliyun_assist_client/agent/metrics" "github.com/aliyun/aliyun_assist_client/agent/taskengine/models" "github.com/aliyun/aliyun_assist_client/agent/util" "github.com/aliyun/aliyun_assist_client/common/pathutil" ) const ( ESuccess = 0 EFileCreateFail = 1 EChownError = 2 EChmodError = 3 ECreateDirFailed = 4 EInvalidFilePath = 10 EFileAlreadyExist = 11 EEmptyContent = 12 EInvalidContent = 13 EInvalidContentType = 14 EInvalidFileType = 15 EInvalidSignature = 16 EInalidFileMode = 17 EInalidGID = 18 EInalidUID = 19 ) var G_IsWindows bool = false var G_IsFreebsd bool = false var G_IsLinux bool = false func init() { if runtime.GOOS == "windows" { G_IsWindows = true } else if runtime.GOOS == "linux" { G_IsLinux = true } else if runtime.GOOS == "freebsd" { G_IsFreebsd = true } else { } } func SendFiles(sendFileTasks []models.SendFileTaskInfo) { for _, s := range sendFileTasks { doSendFile(s) } } func SendFileFinished(sendFile models.SendFileTaskInfo, status int) { url := util.GetFinishOutputService() reportStatus := "Success" if status != ESuccess { reportStatus = "Failed" } param := fmt.Sprintf("?taskId=%s&status=%s&taskType=%s&errorcode=%d", sendFile.TaskID, reportStatus, "sendfile", status) url += param log.GetLogger().Printf("post = %s", url) if status != ESuccess { metrics.GetTaskFailedEvent( "taskid", sendFile.TaskID, "errormsg", param, ).ReportEvent() } _, err := util.HttpPost(url, "", "text") if err != nil { log.GetLogger().Printf("HttpPost url %s error:%s ", url, err.Error()) } } func SendFileInvalid(sendFile models.SendFileTaskInfo, status int) { url := util.GetInvalidTaskService() key := "" value := "" if status == EInvalidFilePath { key = "FileNameInvalid" value = sendFile.Name } else if status == EFileAlreadyExist { key = "FileExist" value = sendFile.Name } else if status == EEmptyContent { key = "EmptyFile" } else if status == EInvalidContent { key = "InvalidFileContent" } else if status == EInvalidSignature { key = "InvalidSignature" value = sendFile.Signature } else if status == EInalidFileMode { key = "InvalidFileMode" value = sendFile.Mode } else if status == EInalidGID { key = "FileGroupNotExist" value = sendFile.Group } else if status == EInalidUID { key = "FileOwnerNotExist" value = sendFile.Owner } metrics.GetTaskFailedEvent( "taskid", sendFile.TaskID, "errormsg", fmt.Sprintf("%s : %s", key, value), ).ReportEvent() url = url + "?" + "taskId=" + sendFile.TaskID + "&taskType=sendfile&param=" + key + "&value=" + value log.GetLogger().Printf("post = %s", url) _, err := util.HttpPost(url, "", "text") if err != nil { log.GetLogger().Printf("HttpPost url %s error:%s ", url, err.Error()) } } func doSendFile(task models.SendFileTaskInfo) { ret := sendFile(task) log.GetLogger().Println("sendFile ret: ", ret) if ret <= ECreateDirFailed { SendFileFinished(task, ret) } else { SendFileInvalid(task, ret) } } func sendFile(sendFile models.SendFileTaskInfo) int { if sendFile.Name == "" { return EInvalidFilePath } if sendFile.Content == "" { return EEmptyContent } fileDir := "" if sendFile.Destination == "" { if G_IsWindows { fileDir, _ = pathutil.GetExecutableDir() } else { fileDir = "/root" } } else { fileDir = sendFile.Destination } if sendFile.Destination != "" { err := os.MkdirAll(sendFile.Destination, os.ModePerm) if err != nil { log.GetLogger().Errorln("MkdirAll error: ", err) return ECreateDirFailed } } if G_IsLinux || G_IsFreebsd { //文件下发时,如果root目录有一个test的文件,又创建了一个/root/test下的文件,则会报错。报错应通过invalid接口上报 if util.IsFile(sendFile.Destination) { return EInvalidFilePath } } file_path := path.Join(fileDir, sendFile.Name) fileContent, err := base64.StdEncoding.DecodeString(sendFile.Content) if err != nil { log.GetLogger().Errorln("base64 decode error: ", err) return EInvalidContent } contentMd5 := util.ComputeStrMd5(sendFile.Content) if strings.ToLower(contentMd5) != strings.ToLower(sendFile.Signature) { return EInvalidSignature } fileMode := sendFile.Mode if len(fileMode) != 3 && len(fileMode) != 4 && len(fileMode) != 0 { return EInalidFileMode } if len(fileMode) == 0 { fileMode = "0644" } fMode, err := strconv.ParseInt(fileMode, 8, 32) if err != nil { return EInalidFileMode } ret := writeFile(file_path, fileContent, sendFile.Overwrite, os.FileMode(fMode)) if ret != ESuccess { return ret } return changeFileOwner(file_path, sendFile.Owner, sendFile.Group) } func changeFileOwner(filePath string, User string, Group string) int { if G_IsWindows { return ESuccess } if User == "" && Group == "" { return ESuccess } if User == "root" && Group == "root" { return ESuccess } if User == "" { User = "root" } lu, err := user.Lookup(User) if err != nil { log.GetLogger().Printf("Lookup uid %s error:%s ", User, err.Error()) return EInalidUID } uid, _ := strconv.Atoi(lu.Uid) if Group == "" { Group = "root" } lg, err := user.LookupGroup(Group) if err != nil { log.GetLogger().Printf("Lookup gid %s error:%s ", Group, err.Error()) return EInalidGID } gid, _ := strconv.Atoi(lg.Gid) err = os.Chown(filePath, uid, gid) if err != nil { log.GetLogger().Printf("Chown file %s error:%s ", filePath, err.Error()) return EChownError } return ESuccess } func writeFile(filePath string, data []byte, overWrite bool, fileMode os.FileMode) int { fileExist := util.FileExist(filePath) if fileExist && !overWrite { return EFileAlreadyExist } err := ioutil.WriteFile(filePath, data, 0644) if err != nil { log.GetLogger().Errorln("WriteFile: ", err) return EFileCreateFail } if G_IsLinux { err = os.Chmod(filePath, fileMode) if err != nil { log.GetLogger().Errorln(" Chmod faild", err) return EChmodError } } return ESuccess }