1024 lines
28 KiB
Go
Raw Normal View History

/*
* 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
}