package base
import (
"encoding/json"
"fleetmanager/api/common/query"
"fleetmanager/api/errors"
"fleetmanager/api/model/fleet"
"fleetmanager/api/params"
"fleetmanager/api/service/constants"
"fleetmanager/client"
"fleetmanager/db/dao"
"fleetmanager/logger"
"fmt"
"net/http"
"strconv"
"strings"
"github.com/beego/beego/v2/client/orm"
"github.com/beego/beego/v2/server/web/context"
)
type FleetService struct {
Ctx *context.Context
Logger *logger.FMLogger
Fleet *dao.Fleet
}
func (s *FleetService) SetFleet() *errors.CodedError {
fleetId := s.Ctx.Input.Param(params.FleetId)
if fleetId == "" {
return errors.NewError(errors.MissingFleetId)
}
filter := dao.Filters{
"Id": fleetId,
"ProjectId": s.Ctx.Input.Param(params.ProjectId),
"Terminated": false,
}
f, err := dao.GetFleetStorage().Get(filter)
if err != nil {
if err == orm.ErrNoRows {
return errors.NewError(errors.FleetNotFound)
}
s.Logger.Error("get fleet info db error: %v", err)
return errors.NewError(errors.DBError)
}
s.Fleet = f
return nil
}
func (s *FleetService) SetFleetById(fleetId string) *errors.CodedError {
if fleetId == "" {
return errors.NewError(errors.MissingFleetId)
}
filter := dao.Filters{
"Id": fleetId,
"ProjectId": s.Ctx.Input.Param(params.ProjectId),
"Terminated": false,
}
f, err := dao.GetFleetStorage().Get(filter)
if err != nil {
if err == orm.ErrNoRows {
return errors.NewError(errors.FleetNotFound)
}
s.Logger.Error("get fleet info db error: %v", err)
return errors.NewError(errors.DBError)
}
s.Fleet = f
return nil
}
func (s *FleetService) SetFleetByServerSessionId(fssId string) *errors.CodedError {
if fssId == "" {
return errors.NewError(errors.MissingServerSessionId)
}
filter := dao.Filters{"ServerSessionId": fssId}
fss, err := dao.GetFleetServerSessionStorage().GetOne(filter)
if err != nil {
if err == orm.ErrNoRows {
return errors.NewError(errors.ServerSessionNotFound)
}
s.Logger.Error("get fleet info db error: %v", err)
return errors.NewError(errors.DBError)
}
if err := s.SetFleetById(fss.FleetId); err != nil {
return err
}
return nil
}
func (s *FleetService) SetFleetByQuery() *errors.CodedError {
fleetId := s.Ctx.Input.Query(params.QueryFleetId)
filter := dao.Filters{"Id": fleetId}
f, err := dao.GetFleetStorage().Get(filter)
if err != nil {
if err == orm.ErrNoRows {
return errors.NewError(errors.FleetNotFound)
}
s.Logger.Error("get fleet info db error: %v", err)
return errors.NewError(errors.DBError)
}
s.Fleet = f
return nil
}
func (s *FleetService) ForwardRspCheck(code int, rsp []byte, err error) (int, []byte, *errors.CodedError) {
if code < http.StatusOK || code >= http.StatusBadRequest {
if err != nil {
return 0, nil, errors.NewError(errors.ServerInternalError)
}
return code, rsp, nil
}
return code, rsp, nil
}
func GetFleetQueryField() []string {
var query_fileds []string
query_fileds = append(query_fileds, params.QueryFleetId)
return query_fileds
}
func GetInstancesQueryField() []string {
var query_fileds []string
query_fileds = append(query_fileds, params.QueryFleetId, params.Limit, params.ParamOffset,
params.InstanceId, params.HealthState, params.LifeCycleState,
params.DurationStart, params.DurationEnd)
return query_fileds
}
func GetAppProcessesQueryField() []string {
var query_fileds []string
query_fileds = append(query_fileds, params.QueryFleetId, params.InstanceId, params.ProcessId,
params.State, params.IpAddress, params.DurationStart, params.DurationEnd,
params.ParamOffset, params.ParamLimit)
return query_fileds
}
func GetServerSessionsQueryFiled() []string {
var query_fileds []string
query_fileds = append(query_fileds, params.QueryFleetId, params.InstanceId, params.ProcessId,
params.QueryServerSessionId, params.State, params.IpAddress, params.StartTime, params.EndTime,
params.ParamOffset, params.ParamLimit)
return query_fileds
}
func GetQueryParams(c *context.Context, query_fileds []string) map[string]string {
query_params := make(map[string]string)
for _, filed := range query_fileds {
param := c.Input.Query(filed)
if param == "" {
param = c.Input.Param(":" + filed)
}
query_params[filed] = param
}
return query_params
}
func ForwardToAppgw(c *context.Context, region string, url string, params map[string]string) (
code int, rsp []byte, err error) {
url = client.GetServiceEndpoint(client.ServiceNameAPPGW, region) + url
req := client.NewRequest(client.ServiceNameAPPGW, url, http.MethodGet, nil)
for key, value := range params {
req.SetQuery(key, value)
}
req.SetHeader(map[string]string{
logger.RequestId: fmt.Sprintf("%s", c.Input.GetData(logger.RequestId)),
})
return req.DoRequest()
}
func ForwardToAASS(c *context.Context, region string, url string, params map[string]string) (
code int, rsp []byte, err error) {
url = client.GetServiceEndpoint(client.ServiceNameAASS, region) + url
req := client.NewRequest(client.ServiceNameAASS, url, http.MethodGet, nil)
for key, value := range params {
req.SetQuery(key, value)
}
req.SetHeader(map[string]string{
logger.RequestId: fmt.Sprintf("%s", c.Input.GetData(logger.RequestId)),
})
return req.DoRequest()
}
func RequestForward(c *context.Context, serviceName string,
region string, url string) (code int, rsp []byte, err error) {
url = client.GetServiceEndpoint(serviceName, region) + url
req := client.NewRequest(serviceName, url, c.Request.Method, c.Input.RequestBody)
if c.Input.IsGet() {
params := c.Request.URL.Query()
for key, values := range params {
req.SetQuery(key, strings.Join(values, "-"))
}
}
reqHeaders := c.Request.Header
header := make(map[string]string)
for key, values := range reqHeaders {
header[key] = strings.Join(values, "-")
}
header[logger.RequestId] = fmt.Sprintf("%s", c.Input.GetData(logger.RequestId))
req.SetHeader(header)
return req.DoRequest()
}
func AcceptResp(logger *logger.FMLogger, m interface{},
code int, rsp []byte, err error) *errors.CodedError {
if code < http.StatusOK || code >= http.StatusBadRequest {
errCode := &errors.CodedError{}
if newErr := json.Unmarshal(rsp, &errCode); newErr != nil {
logger.Error("unmarshal rep: %s to %+v error: %v", rsp, errCode, newErr)
return errors.NewError(errors.ServerInternalError)
}
return errCode
}
if newErr := json.Unmarshal(rsp, &m); newErr != nil {
logger.Error("unmarshal rep: %s to %+v error: %v", rsp, m, newErr)
return errors.NewError(errors.ServerInternalError)
}
return nil
}
func GetDuration(CtxParams map[string]string, tLogger *logger.FMLogger) (int, int, error) {
var start, end = 0, query.MaxServerSessionNum
var err error
if CtxParams[params.DurationStart] == "" {
tLogger.Info("[query checker] duration start is not valid, not set")
} else {
start, err = strconv.Atoi(CtxParams[params.DurationStart])
if err != nil {
return start, end, fmt.Errorf("invalid duration start, please check")
}
}
if CtxParams[params.DurationEnd] == "" {
tLogger.Info("[query checker] duration end is not valid, not set")
} else {
end, err = strconv.Atoi(CtxParams[params.DurationEnd])
if err != nil {
return start, end, fmt.Errorf("invalid duration end, please check")
}
}
if start < 0 || end < 0 || start > query.MaxServerSessionNum || end > query.MaxServerSessionNum {
return start, end, fmt.Errorf("duration strat and end should be in [0, %d], please check", query.MaxServerSessionNum)
}
if start > end {
return start, end, fmt.Errorf("duration start larger duration end, please check")
}
return start, end, nil
}
func GenerateInstances(CtxParams map[string]string, resp_aass *fleet.ListInstanceResonseFromAASS,
appg_instance map[string]map[string]int, ips map[string]string, tLogger *logger.FMLogger) (
*fleet.ListMonitorInstancesResponce, *errors.CodedError) {
resp := fleet.ListMonitorInstancesResponce{
TotalCount: resp_aass.TotalNumber,
Instances: []fleet.MonitorInstanceResponce{},
}
duration_start, duration_end, err := GetDuration(CtxParams, tLogger)
if err != nil {
return nil, errors.NewErrorF(errors.InvalidParameterValue, err.Error())
}
instance_id := CtxParams[params.InstanceId]
for _, ins := range resp_aass.Instances {
if duration_start >= 0 && appg_instance[ins.InstanceId]["server_session_count"] < duration_start {
continue
}
if duration_end >= 0 && appg_instance[ins.InstanceId]["server_session_count"] > duration_end {
continue
}
if instance_id == "" || instance_id == ins.InstanceId {
resp.Instances = append(resp.Instances,
*GenerateInstancesResponce(appg_instance[ins.InstanceId], ips[ins.InstanceId], &ins))
resp.Count += 1
if instance_id != "" {
break
}
}
}
return &resp, nil
}
func GenerateInstancesResponce(appw map[string]int, ip string,
aass *fleet.InstanceResponseFromAASS) *fleet.MonitorInstanceResponce {
var process_count int
var server_session_count int
var max_server_session_num int
if appw == nil {
process_count = 0
server_session_count = 0
max_server_session_num = 0
} else {
process_count = appw["process_count"]
server_session_count = appw["server_session_count"]
max_server_session_num = appw["max_server_session_num"]
}
return &fleet.MonitorInstanceResponce{
InstanceId: aass.InstanceId,
InstanceName: aass.InstanceName,
HealthStatus: aass.HealthStatus,
CreatedAt: aass.CreatedAt.Format(constants.TimeFormatLayout),
ActiveAt: aass.ActiveAt,
ProcessCount: process_count,
IpAddress: ip,
ServerSessionCount: server_session_count,
MaxServerSessionNum: max_server_session_num,
}
}