/* * Copyright (c) 2019 Huawei Technologies Co., Ltd. * A-Tune is licensed under the Mulan PSL v1. * You can use this software according to the terms and conditions of the Mulan PSL v1. * You may obtain a copy of Mulan PSL v1 at: * http://license.coscl.org.cn/MulanPSL * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR * PURPOSE. * See the Mulan PSL v1 for more details. * Create: 2019-10-29 */ package main import ( PB "atune/api/profile" "atune/common/checker" "atune/common/config" "atune/common/http" "atune/common/log" "atune/common/models" "atune/common/profile" "atune/common/project" "atune/common/schedule" SVC "atune/common/service" "atune/common/sqlstore" "atune/common/tuning" "atune/common/utils" "bufio" "context" "encoding/json" "fmt" "io/ioutil" "os" "os/exec" "path" "regexp" "sort" "strconv" "strings" "syscall" "time" "github.com/go-ini/ini" "github.com/urfave/cli" "google.golang.org/grpc" yaml "gopkg.in/yaml.v2" ) // Monitor : the body send to monitor service type Monitor struct { Module string `json:"module"` Purpose string `json:"purpose"` Field string `json:"field"` } // CollectorPost : the body send to collection service type CollectorPost struct { Monitors []Monitor `json:"monitors"` SampleNum int `json:"sample_num"` Pipe string `json:"pipe"` } // RespCollectorPost : the response of collection servie type RespCollectorPost struct { Path string `json:"path"` } // ClassifyPostBody : the body send to classify service type ClassifyPostBody struct { Data string `json:"data"` ModelPath string `json:"modelpath,omitempty"` Model string `json:"model,omitempty"` } // RespClassify : the response of classify model type RespClassify struct { ResourceLimit string `json:"resource_limit"` WorkloadType string `json:"workload_type"` Percentage float32 `json:"percentage"` } // ProfileServer : the type impletent the grpc server type ProfileServer struct { utils.MutexLock ConfPath string ScriptPath string Raw *ini.File } func init() { svc := SVC.ProfileService{ Name: "opt.profile", Desc: "opt profile module", NewInst: NewProfileServer, } if err := SVC.AddService(&svc); err != nil { fmt.Printf("Failed to load service project : %s\n", err) return } log.Info("load profile service successfully\n") } // NewProfileServer method new a instance of the grpc server func NewProfileServer(ctx *cli.Context, opts ...interface{}) (interface{}, error) { defaultConfigFile := path.Join(config.DefaultConfPath, "atuned.cnf") exist, err := utils.PathExist(defaultConfigFile) if err != nil { return nil, err } if !exist { return nil, fmt.Errorf("Could not find default config file") } cfg, err := ini.Load(defaultConfigFile) if err != nil { return nil, fmt.Errorf("Faild to parse %s, %v", defaultConfigFile, err) } return &ProfileServer{ Raw: cfg, }, nil } // RegisterServer method register the grpc service func (s *ProfileServer) RegisterServer(server *grpc.Server) error { PB.RegisterProfileMgrServer(server, s) return nil } // Healthy method, implement SvrService interface func (s *ProfileServer) Healthy(opts ...interface{}) error { return nil } // Post method send POST to start analysis the workload type func (p *ClassifyPostBody) Post() (*RespClassify, error) { url := config.GetUrl(config.ClassificationURI) response, err := http.Post(url, p) if err != nil { return nil, err } defer response.Body.Close() if response.StatusCode != 200 { return nil, fmt.Errorf("online learning faild") } resBody, err := ioutil.ReadAll(response.Body) resPostIns := new(RespClassify) err = json.Unmarshal(resBody, resPostIns) if err != nil { return nil, err } return resPostIns, nil } // Post method send POST to start collection data func (c *CollectorPost) Post() (*RespCollectorPost, error) { url := config.GetUrl(config.CollectorURI) response, err := http.Post(url, c) if err != nil { return nil, err } defer response.Body.Close() if response.StatusCode != 200 { return nil, fmt.Errorf("collect data faild") } resBody, err := ioutil.ReadAll(response.Body) resPostIns := new(RespCollectorPost) err = json.Unmarshal(resBody, resPostIns) if err != nil { return nil, err } return resPostIns, nil } // Profile method set the workload type to effective manual func (s *ProfileServer) Profile(profileInfo *PB.ProfileInfo, stream PB.ProfileMgr_ProfileServer) error { profileNames := profileInfo.GetName() profile, ok := profile.LoadFromWorkloadType(profileNames) if !ok { fmt.Println("Failure Load ", profileInfo.GetName()) return fmt.Errorf("Load profile %s Faild", profileInfo.GetName()) } ch := make(chan *PB.AckCheck) ctx, cancel := context.WithCancel(context.Background()) defer close(ch) defer cancel() go func(ctx context.Context) error { for { select { case value := <-ch: stream.Send(value) case <-ctx.Done(): return nil } } return nil }(ctx) if err := profile.RollbackActive(ch); err != nil { return err } return nil } // ListWorkload method list support workload func (s *ProfileServer) ListWorkload(profileInfo *PB.ProfileInfo, stream PB.ProfileMgr_ListWorkloadServer) error { log.Debug("Begin to inquire all workloads\n") workloads := &sqlstore.GetClass{} err := sqlstore.GetClasses(workloads) if err != nil { return err } for _, classProfile := range workloads.Result { stream.Send(&PB.ListMessage{WorkloadType: classProfile.Class, ProfileNames: classProfile.ProfileType, Active: strconv.FormatBool(classProfile.Active)}) } return nil } // CheckInitProfile method check the system init information // like BIOS version, memory balanced... func (s *ProfileServer) CheckInitProfile(profileInfo *PB.ProfileInfo, stream PB.ProfileMgr_CheckInitProfileServer) error { elf := profileInfo.GetName() rd, err := ioutil.ReadDir(config.DefaultCheckerPath) if err != nil { return err } ch := make(chan *PB.AckCheck, 0) defer close(ch) go func() error { for { select { case value, ok := <-ch: if ok { stream.Send(value) continue } break } } return nil }() elf = strings.Trim(elf, "") if elf != "" { if exist, _ := utils.PathExist(elf); exist { program := checker.ELF{FileName: elf} program.Check(ch) } } for _, dir := range rd { if dir.IsDir() { continue } if !strings.HasSuffix(dir.Name(), ".xml") { continue } filename := strings.TrimSuffix(dir.Name(), ".xml") switch filename { case "mem_topo": memTopo := checker.MemTopo{Path: path.Join(config.DefaultCheckerPath, dir.Name())} memTopo.Check(ch) } } time.Sleep(time.Duration(2) * time.Second) stream.Send(&PB.AckCheck{Name: "check system finished"}) return nil } // Analysis method analysis the system traffic load func (s *ProfileServer) Analysis(message *PB.AnalysisMessage, stream PB.ProfileMgr_AnalysisServer) error { if !s.TryLock() { return fmt.Errorf("analysis has been in running") } defer s.Unlock() stream.Send(&PB.AckCheck{Name: "1. Analysis system runtime information: CPU Memory IO and Network..."}) npipe, err := utils.CreateNamedPipe() if err != nil { return fmt.Errorf("create named pipe faild") } defer os.Remove(npipe) go func() { file, _ := os.OpenFile(npipe, os.O_RDONLY, os.ModeNamedPipe) reader := bufio.NewReader(file) scanner := bufio.NewScanner(reader) for scanner.Scan() { line := scanner.Text() stream.Send(&PB.AckCheck{Name: line, Status: utils.INFO}) } }() //1. get the dimension structure of the system data to be collected collections, err := sqlstore.GetCollections() if err != nil { log.Errorf("inquery collection tables error: %v", err) return err } // 1.1 send the collect data command to the monitor service monitors := make([]Monitor, 0) for _, collection := range collections { re := regexp.MustCompile(`\{([^}]+)\}`) matches := re.FindAllStringSubmatch(collection.Metrics, -1) if len(matches) > 0 { for _, match := range matches { if !s.Raw.Section("system").Haskey(match[1]) { return fmt.Errorf("%s is not exist in the system section", match[1]) } value := s.Raw.Section("system").Key(match[1]).Value() collection.Metrics = re.ReplaceAllString(collection.Metrics, value) } } monitor := Monitor{Module: collection.Module, Purpose: collection.Purpose, Field: collection.Metrics} monitors = append(monitors, monitor) } sampleNum := s.Raw.Section("server").Key("sample_num").MustInt(20) collectorBody := new(CollectorPost) collectorBody.SampleNum = sampleNum collectorBody.Monitors = monitors collectorBody.Pipe = npipe respCollectPost, err := collectorBody.Post() if err != nil { stream.Send(&PB.AckCheck{Name: err.Error()}) return err } //2. send the collected data to the model for completion type identification body := new(ClassifyPostBody) body.Data = respCollectPost.Path body.ModelPath = path.Join(config.DefaultAnalysisPath, "models") if message.GetModel() != "" { body.Model = message.GetModel() } respPostIns, err := body.Post() if err != nil { stream.Send(&PB.AckCheck{Name: err.Error()}) return err } workloadType := respPostIns.WorkloadType stream.Send(&PB.AckCheck{Name: fmt.Sprintf("\n 2. Current System Workload Characterization is %s", workloadType)}) //3. judge the workload type is exist in the database classProfile := &sqlstore.GetClass{Class: workloadType} if err := sqlstore.GetClasses(classProfile); err != nil { log.Errorf("inquery workload type table faild %v", err) return fmt.Errorf("inquery workload type table faild %v", err) } if len(classProfile.Result) == 0 { log.Errorf("%s is not exist in the table", workloadType) return fmt.Errorf("%s is not exist in the table", workloadType) } // the workload type is already actived if classProfile.Result[0].Active { log.Infof("analysis result %s is the same with current active workload type", workloadType) return nil } //4. inquery the support app of the workload type classApps := &sqlstore.GetClassApp{Class: workloadType} err = sqlstore.GetClassApps(classApps) if err != nil { log.Errorf("inquery support app depend on class error: %v", err) return err } if len(classApps.Result) == 0 { return fmt.Errorf("class %s is not exist in the tables", workloadType) } apps := classApps.Result[0].Apps log.Infof("workload %s support app: %s", workloadType, apps) log.Infof("workload %s resource limit: %s, cluster result resource limit: %s", workloadType, apps, respPostIns.ResourceLimit) stream.Send(&PB.AckCheck{Name: "\n 3. Build the best resource model..."}) //5. get the profile type depend on the workload type profileType := classProfile.Result[0].ProfileType profileNames := strings.Split(profileType, ",") if len(profileNames) == 0 { log.Errorf("No profile or invaild profiles were specified.") return fmt.Errorf("No profile or invaild profiles were specified") } //6. get the profile info depend on the profile type log.Infof("the resource model of the profile type is %s", profileType) stream.Send(&PB.AckCheck{Name: fmt.Sprintf("\n 4. Match profile: %s", profileType)}) pro, _ := profile.Load(profileNames) pro.SetWorkloadType(workloadType) stream.Send(&PB.AckCheck{Name: fmt.Sprintf("\n 5. bengin to set static profile")}) log.Infof("bengin to set static profile") //static profile setting ch := make(chan *PB.AckCheck, 0) go func() error { for { select { case value, ok := <-ch: if ok { stream.Send(value) continue } break } } return nil }() pro.RollbackActive(ch) rules := &sqlstore.GetRuleTuned{Class: workloadType} if err := sqlstore.GetRuleTuneds(rules); err != nil { return err } if len(rules.Result) < 1 { stream.Send(&PB.AckCheck{Name: fmt.Sprintf("Completed optimization, please restart application!")}) log.Info("no rules to tuned") return nil } log.Info("begin to dynamic tunning depending on rules") stream.Send(&PB.AckCheck{Name: fmt.Sprintf("\n 6. bengin to set dynamic profile")}) if err := tuning.RuleTuned(workloadType); err != nil { return err } stream.Send(&PB.AckCheck{Name: fmt.Sprintf("Completed optimization, please restart application!")}) return nil } // Tuning method calling the bayes search method to tuned parameters func (s *ProfileServer) Tuning(profileInfo *PB.ProfileInfo, stream PB.ProfileMgr_TuningServer) error { //dynamic profle setting data := profileInfo.GetName() fmt.Println(data) var byteData []byte = []byte(data) project := project.YamlPrj{} if err := yaml.Unmarshal(byteData, &project); err != nil { return err } log.Info("begin to dynamic optimizer search") stream.Send(&PB.AckCheck{Name: fmt.Sprintf("bengin to dynamic optimizer search")}) ch := make(chan *PB.AckCheck, 0) go func() error { for { select { case value, ok := <-ch: if ok { stream.Send(value) continue } break } } return nil }() optimizer := tuning.Optimizer{Prj: &project} err := optimizer.DynamicTuned(ch) if err != nil { return err } return nil } /* UpgradeProfile method update the db file */ func (s *ProfileServer) UpgradeProfile(profileInfo *PB.ProfileInfo, stream PB.ProfileMgr_UpgradeProfileServer) error { log.Debug("Begin to upgrade profiles\n") currenDbPath := path.Join(config.DatabasePath, config.DatabaseName) newDbPath := profileInfo.GetName() exist, err := utils.PathExist(config.DefaultTempPath) if err != nil { return err } if !exist { os.MkdirAll(config.DefaultTempPath, os.ModePerm) } timeUnix := strconv.FormatInt(time.Now().Unix(), 10) + ".db" tempFile := path.Join(config.DefaultTempPath, timeUnix) if err := utils.CopyFile(tempFile, currenDbPath); err != nil { stream.Send(&PB.AckCheck{Name: err.Error(), Status: utils.FAILD}) return nil } if err := utils.CopyFile(currenDbPath, newDbPath); err != nil { stream.Send(&PB.AckCheck{Name: err.Error(), Status: utils.FAILD}) return nil } if err := sqlstore.Reload(currenDbPath); err != nil { stream.Send(&PB.AckCheck{Name: err.Error(), Status: utils.FAILD}) return nil } stream.Send(&PB.AckCheck{Name: fmt.Sprintf("upgrade success"), Status: utils.SUCCESS}) return nil } /* InfoProfile method display the content of the specified workload type */ func (s *ProfileServer) InfoProfile(profileInfo *PB.ProfileInfo, stream PB.ProfileMgr_InfoProfileServer) error { workloadType := profileInfo.GetName() classProfile := &sqlstore.GetClass{Class: workloadType} err := sqlstore.GetClasses(classProfile) if err != nil { log.Errorf("inquery class_profile table faild") return fmt.Errorf("inquery class_profile table faild") } if len(classProfile.Result) == 0 { log.Errorf("%s is not exist in the class_profile table", workloadType) return fmt.Errorf("%s is not exist in the class_profile table", workloadType) } profileType := classProfile.Result[0].ProfileType profileNames := strings.Split(profileType, ",") for _, name := range profileNames { name = strings.Trim(name, " ") context, _ := sqlstore.GetContext(name) context = "\n*** " + name + ":\n" + context stream.Send(&PB.ProfileInfo{Name: context}) } return nil } /* CheckActiveProfile method check current active profile is effective */ func (s *ProfileServer) CheckActiveProfile(profileInfo *PB.ProfileInfo, stream PB.ProfileMgr_CheckActiveProfileServer) error { log.Debug("Begin to check active profiles\n") profiles := &sqlstore.GetClass{Active: true} err := sqlstore.GetClasses(profiles) if err != nil { return err } if len(profiles.Result) != 1 { return fmt.Errorf("No active profile or more than 1 active profile") } workloadType := profiles.Result[0].Class profile, ok := profile.LoadFromWorkloadType(workloadType) if !ok { log.WithField("profile", workloadType).Errorf("Load profile %s Faild", workloadType) return fmt.Errorf("Load workload type %s Faild", workloadType) } ch := make(chan *PB.AckCheck, 0) defer close(ch) go func() error { for { select { case value, ok := <-ch: if ok { stream.Send(value) continue } break } return nil } return nil }() if err := profile.Check(ch); err != nil { return err } return nil } // ProfileRollback method rollback the profile to init state func (s *ProfileServer) ProfileRollback(profileInfo *PB.ProfileInfo, stream PB.ProfileMgr_ProfileRollbackServer) error { profileLogs, err := sqlstore.GetProfileLogs() if err != nil { return err } if len(profileLogs) < 1 { stream.Send(&PB.AckCheck{Name: "no profile need to rollback"}) return nil } sort.Slice(profileLogs, func(i, j int) bool { return profileLogs[i].ID > profileLogs[j].ID }) //static profile setting ch := make(chan *PB.AckCheck, 0) go func() error { for { select { case value, ok := <-ch: if ok { stream.Send(value) continue } break } return nil } return nil }() for _, pro := range profileLogs { log.Infof("begin to restore profile id: %s", pro.ID) profileInfo := profile.HistoryProfile{} profileInfo.Load(pro.Context) profileInfo.Resume(ch) // delete profile log after restored if err := sqlstore.DelProfileLogByID(pro.ID); err != nil { return err } //delete backup dir if err := os.RemoveAll(pro.BackupPath); err != nil { return err } // update active profile after restored if err := sqlstore.ActiveProfile(pro.ProfileID); err != nil { return nil } } if err := sqlstore.InActiveProfile(); err != nil { return nil } return nil } /* Collection method call collection script to collect system data. */ func (s *ProfileServer) Collection(message *PB.CollectFlag, stream PB.ProfileMgr_CollectionServer) error { classApps := &sqlstore.GetClassApp{Class: message.GetType()} err := sqlstore.GetClassApps(classApps) if err != nil { return err } if len(classApps.Result) == 0 { return fmt.Errorf("workload type %s is not exist, please use define command first", message.GetType()) } exist, err := utils.PathExist(message.GetOutputPath()) if err != nil { return err } if !exist { return fmt.Errorf("output_path %s is not exist", message.GetOutputPath()) } if err := utils.InterfaceByName(message.GetNetwork()); err != nil { return err } if err := utils.DiskByName(message.GetBlock()); err != nil { return err } collector := path.Join(config.DefaultCollectorPath, "collect_training_data.sh") script := make([]string, 0) script = append(script, collector) script = append(script, message.GetWorkload()) script = append(script, strconv.FormatInt(message.GetDuration(), 10)) script = append(script, strconv.FormatInt(message.GetInterval(), 10)) script = append(script, message.GetOutputPath()) script = append(script, message.GetBlock()) script = append(script, message.GetNetwork()) script = append(script, message.GetType()) newScript := strings.Join(script, " ") cmd := exec.Command("sudo", "sh", "-c", newScript) cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true} stdout, err := cmd.StdoutPipe() stderr, err := cmd.StderrPipe() ctx := stream.Context() go func() { for { select { case <-ctx.Done(): syscall.Kill(-cmd.Process.Pid, syscall.SIGKILL) return } } }() go func() { scanner := bufio.NewScanner(stdout) for scanner.Scan() { line := scanner.Text() stream.Send(&PB.AckCheck{Name: line}) } }() go func() { scanner := bufio.NewScanner(stderr) for scanner.Scan() { line := scanner.Text() stream.Send(&PB.AckCheck{Name: line}) } }() err = cmd.Start() if err != nil { log.Error(err) return err } err = cmd.Wait() if err != nil { log.Error(err) return err } return nil } /* Training method train the collected data to generate the model */ func (s *ProfileServer) Training(message *PB.TrainMessage, stream PB.ProfileMgr_TrainingServer) error { DataPath := message.GetDataPath() OutputPath := message.GetOutputPath() trainBody := new(models.Training) trainBody.DataPath = DataPath trainBody.OutputPath = OutputPath trainBody.ModelPath = path.Join(config.DefaultAnalysisPath, "models") success, err := trainBody.Post() if err != nil { return err } if success { stream.Send(&PB.AckCheck{Name: "training the self collect data success"}) return nil } stream.Send(&PB.AckCheck{Name: "training the self collect data faild"}) return nil } // Charaterization method will be deprecate in the future func (s *ProfileServer) Charaterization(profileInfo *PB.ProfileInfo, stream PB.ProfileMgr_CharaterizationServer) error { stream.Send(&PB.AckCheck{Name: "1. Analysis system runtime information: CPU Memory IO and Network..."}) npipe, err := utils.CreateNamedPipe() if err != nil { return fmt.Errorf("create named pipe faild") } defer os.Remove(npipe) go func() { file, _ := os.OpenFile(npipe, os.O_RDONLY, os.ModeNamedPipe) reader := bufio.NewReader(file) scanner := bufio.NewScanner(reader) for scanner.Scan() { line := scanner.Text() stream.Send(&PB.AckCheck{Name: line, Status: utils.INFO}) } }() //1. get the dimension structure of the system data to be collected collections, err := sqlstore.GetCollections() if err != nil { log.Errorf("inquery collection tables error: %v", err) return err } // 1.1 send the collect data command to the monitor service monitors := make([]Monitor, 0) for _, collection := range collections { re := regexp.MustCompile(`\{([^}]+)\}`) matches := re.FindAllStringSubmatch(collection.Metrics, -1) if len(matches) > 0 { for _, match := range matches { if !s.Raw.Section("system").Haskey(match[1]) { return fmt.Errorf("%s is not exist in the system section", match[1]) } value := s.Raw.Section("system").Key(match[1]).Value() collection.Metrics = re.ReplaceAllString(collection.Metrics, value) } } monitor := Monitor{Module: collection.Module, Purpose: collection.Purpose, Field: collection.Metrics} monitors = append(monitors, monitor) } collectorBody := new(CollectorPost) collectorBody.SampleNum = 5 collectorBody.Monitors = monitors collectorBody.Pipe = npipe respCollectPost, err := collectorBody.Post() if err != nil { stream.Send(&PB.AckCheck{Name: err.Error()}) return err } //2. send the collected data to the model for completion type identification body := new(ClassifyPostBody) body.Data = respCollectPost.Path body.ModelPath = path.Join(config.DefaultAnalysisPath, "models") respPostIns, err := body.Post() if err != nil { stream.Send(&PB.AckCheck{Name: err.Error()}) return err } workloadType := respPostIns.WorkloadType stream.Send(&PB.AckCheck{Name: fmt.Sprintf("\n 2. Current System Workload Characterization is %s", workloadType)}) return nil } // Define method user define workload type and profile func (s *ProfileServer) Define(ctx context.Context, message *PB.DefineMessage) (*PB.Ack, error) { workloadType := message.GetWorkloadType() profileName := message.GetProfileName() content := string(message.GetContent()) workloadTypeExist, err := sqlstore.ExistWorkloadType(workloadType) if err != nil { return &PB.Ack{}, err } if workloadTypeExist { return &PB.Ack{Status: fmt.Sprintf("%s is already exist", workloadType)}, nil } profileExist, err := sqlstore.ExistProfile(profileName) if err != nil { return &PB.Ack{}, err } if profileExist { return &PB.Ack{Status: fmt.Sprintf("%s is already exist", profileName)}, nil } if err := sqlstore.InsertClassApps(&sqlstore.ClassApps{Class: workloadType, Deletable: true}); err != nil { return &PB.Ack{}, err } if err := sqlstore.InsertClassProfile(&sqlstore.ClassProfile{Class: workloadType, ProfileType: profileName, Active: false}); err != nil { return &PB.Ack{}, err } if err := sqlstore.InsertProfile(&sqlstore.Profile{ProfileType: profileName, ProfileInformation: content}); err != nil { return &PB.Ack{}, err } return &PB.Ack{Status: "OK"}, nil } // Delete method delete the self define workload type from database func (s *ProfileServer) Delete(ctx context.Context, message *PB.DefineMessage) (*PB.Ack, error) { workloadType := message.GetWorkloadType() classApps := &sqlstore.GetClassApp{Class: workloadType} err := sqlstore.GetClassApps(classApps) if err != nil { return &PB.Ack{}, err } log.Infof("the result length: %d, query the classapp table of workload: %s", len(classApps.Result), workloadType) if len(classApps.Result) != 1 { return &PB.Ack{Status: fmt.Sprintf("workload type %s may be not exist in the table", workloadType)}, nil } classApp := classApps.Result[0] if classApp.Deletable != true { return &PB.Ack{Status: "only self defined workload type can be deleted"}, nil } if err := sqlstore.DeleteClassApps(workloadType); err != nil { return &PB.Ack{}, err } // get the profile type from the classprofile table classProfile := &sqlstore.GetClass{Class: workloadType} if err := sqlstore.GetClasses(classProfile); err != nil { log.Errorf("inquery workload type table faild %v", err) return &PB.Ack{}, fmt.Errorf("inquery workload type table faild %v", err) } if len(classProfile.Result) == 0 { log.Errorf("%s is not exist in the table", workloadType) return &PB.Ack{}, fmt.Errorf("%s is not exist in the table", workloadType) } profileType := classProfile.Result[0].ProfileType profileNames := strings.Split(profileType, ",") if len(profileNames) == 0 { log.Errorf("No profile or invaild profiles were specified.") return &PB.Ack{}, fmt.Errorf("No profile or invaild profiles were specified") } // delete profile depend the profiletype for _, profileName := range profileNames { if err := sqlstore.DeleteProfile(profileName); err != nil { log.Errorf("delete item from profile table faild %v ", err) } } // delete classprofile depend the workloadType if err := sqlstore.DeleteClassProfile(workloadType); err != nil { log.Errorf("delete item from classprofile tabble faild.") return &PB.Ack{}, err } return &PB.Ack{Status: "OK"}, nil } // Update method update the content of the specified workload type from database func (s *ProfileServer) Update(ctx context.Context, message *PB.DefineMessage) (*PB.Ack, error) { workloadType := message.GetWorkloadType() profileName := message.GetProfileName() content := string(message.GetContent()) workloadTypeExist, err := sqlstore.ExistWorkloadType(workloadType) if err != nil { return &PB.Ack{}, err } if !workloadTypeExist { return &PB.Ack{Status: fmt.Sprintf("workload type %s is not exist in the table", workloadType)}, nil } // get the profile type from the classprofile table classProfile := &sqlstore.GetClass{Class: workloadType} if err := sqlstore.GetClasses(classProfile); err != nil { log.Errorf("inquery workload type table faild %v", err) return &PB.Ack{}, fmt.Errorf("inquery workload type table faild %v", err) } if len(classProfile.Result) == 0 { log.Errorf("%s is not exist in the table", workloadType) return &PB.Ack{}, fmt.Errorf("%s is not exist in the table", workloadType) } profileType := classProfile.Result[0].ProfileType profileNames := strings.Split(profileType, ",") if len(profileNames) == 0 { log.Errorf("No profile or invaild profiles were specified.") return &PB.Ack{}, fmt.Errorf("no profile exist corresponding to workload type") } exist := false for _, profile := range profileNames { if profileName == strings.TrimSpace(profile) { exist = true break } } if !exist { return &PB.Ack{}, fmt.Errorf("profile name %s is exist corresponding to workload type %s", profileName, workloadType) } if err := sqlstore.UpdateProfile(&sqlstore.Profile{ProfileType: profileName, ProfileInformation: content}); err != nil { return &PB.Ack{}, err } return &PB.Ack{Status: "OK"}, nil } /* * schedule cpu/irq/numa ... */ func (s *ProfileServer) Schedule(message *PB.ScheduleMessage, stream PB.ProfileMgr_ScheduleServer) error { _ = message.GetApp() Type := message.GetType() Strategy := message.GetStrategy() scheduler := schedule.GetScheduler() scheduler.Schedule(Type, Strategy, true) return nil }