* Copyright (c) 2019 Huawei Technologies Co., Ltd.
* A-Tune is licensed under the Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
* 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 v2 for more details.
* Create: 2019-10-29
*/
package schedule
import (
"encoding/json"
"fmt"
"io/ioutil"
"io"
"os"
"strings"
"github.com/go-ini/ini"
PB "gitee.com/openeuler/A-Tune/api/profile"
"gitee.com/openeuler/A-Tune/common/config"
"gitee.com/openeuler/A-Tune/common/http"
"gitee.com/openeuler/A-Tune/common/log"
"gitee.com/openeuler/A-Tune/common/models"
"gitee.com/openeuler/A-Tune/common/registry"
"gitee.com/openeuler/A-Tune/common/sqlstore"
"gitee.com/openeuler/A-Tune/common/utils"
)
func sendChanToAdm(ch chan *PB.AckCheck, item string, status string, description string) {
if ch == nil {
return
}
ch <- &PB.AckCheck{Name: item, Status: status, Description: description}
}
type ConfigPutBody struct {
Section string `json:"section"`
Key string `json:"key"`
Value string `json:"value"`
}
type RespPut struct {
Status string `json:"status"`
Value string `json:"value"`
}
func (c *ConfigPutBody) Put() (*RespPut, error) {
url := config.GetURL(config.ConfiguratorURI)
res, err := http.Put(url, c)
if err != nil {
return nil, err
}
defer res.Body.Close()
if res.StatusCode != 200 {
return nil, fmt.Errorf("connect to configurator service failed")
}
resBody, err := ioutil.ReadAll(res.Body)
if err != nil {
return nil, err
}
respPutIns := new(RespPut)
err = json.Unmarshal(resBody, respPutIns)
if err != nil {
return nil, err
}
return respPutIns, nil
}
func (c *ConfigPutBody) Get() (*RespPut, error) {
url := config.GetURL(config.ConfiguratorURI)
res, err := http.Get(url, c)
if err != nil {
return nil, err
}
defer res.Body.Close()
if res.StatusCode != 200 {
return nil, fmt.Errorf("connect to configurator service failed")
}
resBody, err := ioutil.ReadAll(res.Body)
if err != nil {
return nil, err
}
respPutIns := new(RespPut)
err = json.Unmarshal(resBody, respPutIns)
if err != nil {
return nil, err
}
return respPutIns, nil
}
type Scheduler struct {
schedule []*sqlstore.Schedule
id int
}
var instance *Scheduler = nil
func (s *Scheduler) Init() error {
s.schedule = sqlstore.GetSchedule()
return nil
}
func (s *Scheduler) SetScheduleId(scheduleId int) {
s.id = scheduleId
}
func (s *Scheduler) Schedule(pids string, strategy string, save bool, ch chan *PB.AckCheck) error {
schedManager, err := GetScheduleManager()
if err != nil {
return err
}
scheduler, err := schedManager.New(strategy,
pids,
WithChannel(ch),
)
if err != nil {
return err
}
schedManager.Submit(scheduler)
schedManager.Start()
return nil
}
func (s *Scheduler) Active(ch chan *PB.AckCheck, itemKeys []string, items map[string]*ini.File) error {
logStr := ""
for _, item := range itemKeys {
value := items[item]
if value == nil {
continue
}
for _, section := range value.Sections() {
if section.Name() == "main" {
continue
}
if section.Name() == "DEFAULT" {
continue
}
if section.Name() == "tip" {
for _, key := range section.Keys() {
description := key.Name()
sendChanToAdm(ch, key.Value(), utils.SUGGEST, description)
log.Infof("tip key name: %s, key value: %s", key.Name(), key.Value())
currLog := section.Name() + "|" + key.Name() + "|" + key.Value() + "|"
logStr += currLog + "\n"
_, err := models.InitTransfer("log", "running", currLog, "", s.id)
if err != nil {
log.Errorf("log info write error: transfer data %v", err)
}
}
continue
}
if section.Name() == "schedule" {
for _, key := range section.Keys() {
_ = s.Schedule(key.Name(), key.Value(), false, ch)
currLog := section.Name() + "|" + key.Name() + "|" + key.Value() + "|"
logStr += currLog + "\n"
_, err := models.InitTransfer("log", "running", currLog, "", s.id)
if err != nil {
log.Errorf("log info write error: transfer data %v", err)
}
}
continue
}
if section.Name() == "check" {
if !section.HasKey("check_environment") {
continue
}
if section.Key("check_environment").Value() != "on" {
continue
}
services := registry.GetCheckerServices()
for _, service := range services {
log.Infof("initializing checker service: %s", service.Name)
if err := service.Instance.Init(); err != nil {
return fmt.Errorf("service init failed: %v", err)
}
}
for _, srv := range services {
service := srv
checkerService, ok := service.Instance.(registry.CheckService)
if !ok {
continue
}
if !registry.IsCheckDisabled(service.Instance) {
continue
}
err := checkerService.Check(ch)
if err != nil {
log.Errorf("service %s running failed, reason: %v", service.Name, err)
continue
}
}
continue
}
var statusStr string = "OK"
message := make([]string, 0)
for _, key := range section.Keys() {
scriptKey := key.Name()
value := key.Value()
body := &ConfigPutBody{
Section: section.Name(),
Key: scriptKey,
Value: value,
}
respPutIns, err := body.Put()
if err != nil {
statusStr = err.Error()
continue
}
log.Infof("active parameter, key: %s, value: %s, status:%s", scriptKey, value, respPutIns.Status)
if respPutIns.Status == "OK" {
message = append(message, scriptKey)
} else {
if statusStr != utils.ERROR {
statusStr = respPutIns.Status
}
message = append(message, respPutIns.Value)
}
currLog := section.Name() + "|" + statusStr + "|" + key.Name() + "|" + key.Value() + "|"
if statusStr != "OK" {
currLog += respPutIns.Value
}
logStr += currLog + "\n"
_, err = models.InitTransfer("log", "running", currLog, "", s.id)
if err != nil {
log.Errorf("log info write error: transfer data %v", err)
}
}
message = utils.RemoveDuplicateElement(message)
status := strings.ToUpper(statusStr)
if status == "OK" {
sendChanToAdm(ch, item, utils.SUCCESS, strings.Join(message, ","))
} else if status == utils.WARNING {
sendChanToAdm(ch, item, utils.SUGGEST, strings.Join(message, ","))
} else {
sendChanToAdm(ch, item, utils.FAILD, strings.Join(message, ","))
}
}
}
logFile, err := utils.GetLogFilePath(config.DefaultTempPath)
if err != nil {
log.Infof("get log file path failed: %v", err)
} else {
file, err := os.OpenFile(logFile, os.O_APPEND|os.O_WRONLY, 0640)
if err != nil {
return fmt.Errorf("open file failed: %v", err)
}
defer file.Close()
_, err = io.WriteString(file, logStr)
if err != nil {
log.Errorf("write to log failed: %v", err)
}
}
_, err = models.InitTransfer("log", "finished", "", "", s.id)
if err != nil {
log.Errorf("log info write error: transfer data %v", err)
}
return nil
}
func GetScheduler() *Scheduler {
if instance == nil {
instance = new(Scheduler)
_ = instance.Init()
}
return instance
}