From 6d9b7476d33f3b7db3cb60745613c159156bb500 Mon Sep 17 00:00:00 2001 From: Yousong Zhou Date: Mon, 11 Nov 2019 11:31:37 +0000 Subject: [PATCH 1/4] =?UTF-8?q?influxdb:=20=E8=AE=B0=E5=BD=95=E7=BB=93?= =?UTF-8?q?=E6=9E=9C=E4=B8=AD=E7=9A=84tags?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pkg/util/influxdb/influxdb.go | 1 + 1 file changed, 1 insertion(+) diff --git a/pkg/util/influxdb/influxdb.go b/pkg/util/influxdb/influxdb.go index 91ca6a1c2e..1e5e5847fc 100644 --- a/pkg/util/influxdb/influxdb.go +++ b/pkg/util/influxdb/influxdb.go @@ -53,6 +53,7 @@ func NewInfluxdbWithDebug(accessUrl string, debug bool) *SInfluxdb { type dbResult struct { Name string + Tags *jsonutils.JSONDict Columns []string Values [][]jsonutils.JSONObject } From 653616015793041be0f88bd161ffed72cfc0edf9 Mon Sep 17 00:00:00 2001 From: Yousong Zhou Date: Tue, 12 Nov 2019 02:26:16 +0000 Subject: [PATCH 2/4] =?UTF-8?q?lbbackends:=20=E4=BD=BF=E7=94=A8yunion.io/p?= =?UTF-8?q?kg/errors?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pkg/compute/models/loadbalancerbackends.go | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/pkg/compute/models/loadbalancerbackends.go b/pkg/compute/models/loadbalancerbackends.go index e8fd750ba8..f040fdcba9 100644 --- a/pkg/compute/models/loadbalancerbackends.go +++ b/pkg/compute/models/loadbalancerbackends.go @@ -19,10 +19,9 @@ import ( "database/sql" "fmt" - "github.com/pkg/errors" - "yunion.io/x/jsonutils" "yunion.io/x/log" + "yunion.io/x/pkg/errors" "yunion.io/x/pkg/util/compare" "yunion.io/x/pkg/utils" "yunion.io/x/sqlchemy" @@ -292,12 +291,12 @@ func (lbb *SLoadbalancerBackend) getVpc(ctx context.Context) (*SVpc, error) { theLbbJanitor.Signal() return nil, nil } - return nil, errors.WithMessagef(err, "find guest %s", lbb.BackendId) + return nil, errors.Wrapf(err, "find guest %s", lbb.BackendId) } guest := guestM.(*SGuest) vpc, err := guest.GetVpc() if err != nil { - return nil, errors.WithMessagef(err, "find guest %s(%s) vpc", guest.Name, guest.Id) + return nil, errors.Wrapf(err, "find guest %s(%s) vpc", guest.Name, guest.Id) } return vpc, nil } From 018d8276ba54ee948988b08761219c3c95a06f2d Mon Sep 17 00:00:00 2001 From: Yousong Zhou Date: Mon, 11 Nov 2019 10:33:00 +0000 Subject: [PATCH 3/4] =?UTF-8?q?lblis,=20lbr:=20=E5=A2=9E=E5=8A=A0=E6=9F=A5?= =?UTF-8?q?=E8=AF=A2=E5=90=8E=E7=AB=AF=E7=8A=B6=E6=80=81=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../models/loadbalancer_backendstatus.go | 180 ++++++++++++++++++ pkg/compute/models/loadbalanceragents.go | 9 + pkg/compute/models/loadbalancers.go | 12 ++ 3 files changed, 201 insertions(+) create mode 100644 pkg/compute/models/loadbalancer_backendstatus.go diff --git a/pkg/compute/models/loadbalancer_backendstatus.go b/pkg/compute/models/loadbalancer_backendstatus.go new file mode 100644 index 0000000000..05ef4e191b --- /dev/null +++ b/pkg/compute/models/loadbalancer_backendstatus.go @@ -0,0 +1,180 @@ +// Copyright 2019 Yunion +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package models + +import ( + "context" + "fmt" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/utils" + + api "yunion.io/x/onecloud/pkg/apis/compute" + "yunion.io/x/onecloud/pkg/cloudcommon/db" + "yunion.io/x/onecloud/pkg/httperrors" + "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/onecloud/pkg/util/influxdb" +) + +func (lblis *SLoadbalancerListener) AllowGetDetailsBackendStatus(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) bool { + return db.IsProjectAllowGetSpec(userCred, lblis, "backend-status") +} + +func (lblis *SLoadbalancerListener) GetDetailsBackendStatus(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) (jsonutils.JSONObject, error) { + if lblis.ManagerId != "" { + return jsonutils.NewArray(), nil + } + if lblis.BackendGroupId == "" { + return jsonutils.NewArray(), nil + } + var pxname string + switch lblis.ListenerType { + case api.LB_LISTENER_TYPE_TCP: + pxname = fmt.Sprintf("backends_listener-%s", lblis.Id) + case api.LB_LISTENER_TYPE_HTTP, api.LB_LISTENER_TYPE_HTTPS: + pxname = fmt.Sprintf("backends_listener_default-%s", lblis.Id) + } + return lbGetBackendGroupCheckStatus(ctx, userCred, lblis.LoadbalancerId, pxname, lblis.BackendGroupId) +} + +func (lbr *SLoadbalancerListenerRule) AllowGetDetailsBackendStatus(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) bool { + return db.IsProjectAllowGetSpec(userCred, lbr, "backend-status") +} + +func (lbr *SLoadbalancerListenerRule) GetDetailsBackendStatus(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) (jsonutils.JSONObject, error) { + if lbr.ManagerId != "" { + return jsonutils.NewArray(), nil + } + lblis := lbr.GetLoadbalancerListener() + if lblis == nil { + return nil, httperrors.NewNotFoundError("find listener of listener rule %s(%s)", lbr.Name, lbr.Id) + } + pxname := fmt.Sprintf("backends_rule-%s", lbr.Id) + return lbGetBackendGroupCheckStatus(ctx, userCred, lblis.LoadbalancerId, pxname, lbr.BackendGroupId) +} + +func lbGetInfluxdbByLbId(lbId string) (*influxdb.SInfluxdb, string, error) { + lb, err := LoadbalancerManager.getLoadbalancer(lbId) + if err != nil { + return nil, "", err + } + lbagents, err := LoadbalancerAgentManager.getByClusterId(lb.ClusterId) + if err != nil { + return nil, "", err + } + var ( + dbUrl string + dbName string + ) + for i := range lbagents { + lbagent := &lbagents[i] + params := lbagent.Params + if params == nil { + continue + } + paramsTelegraf := params.Telegraf + if paramsTelegraf.InfluxDbOutputUrl != "" && paramsTelegraf.InfluxDbOutputName != "" { + dbUrl = paramsTelegraf.InfluxDbOutputUrl + dbName = paramsTelegraf.InfluxDbOutputName + if lbagent.HaState == api.LB_HA_STATE_MASTER { + // prefer the one on master + break + } + } + } + if dbUrl == "" || dbName == "" { + return nil, "", fmt.Errorf("no influxdb url or db name") + } + dbinst := influxdb.NewInfluxdb(dbUrl) + return dbinst, dbName, nil +} + +func lbGetBackendGroupCheckStatus(ctx context.Context, userCred mcclient.TokenCredential, lbId string, pxname string, groupId string) (*jsonutils.JSONArray, error) { + var ( + backendJsons []jsonutils.JSONObject + backendIds []string + ) + { + var err error + q := LoadbalancerBackendManager.Query().Equals("backend_group_id", groupId).IsFalse("pending_deleted") + backendJsons, err = db.Query2List(LoadbalancerBackendManager, ctx, userCred, q, jsonutils.NewDict(), false) + if err != nil { + return nil, errors.Wrapf(err, "query backends of backend group %s", groupId) + } + if len(backendJsons) == 0 { + return jsonutils.NewArray(), nil + } + for _, backendJson := range backendJsons { + id, err := backendJson.GetString("id") + if err != nil { + return nil, errors.Wrap(err, "get backend id from json") + } + if id == "" { + return nil, errors.Wrap(err, "get backend id from json: id empty") + } + backendIds = append(backendIds, id) + } + } + + dbinst, dbName, err := lbGetInfluxdbByLbId(lbId) + if err != nil { + return nil, errors.Wrapf(err, "find influxdb for loadbalancer %s", lbId) + } + + queryFmt := "select check_status, check_code from %s..haproxy where pxname = '%s' and svname =~ /........-....-....-....-............/ group by pxname, svname order by time desc limit 1" + querySql := fmt.Sprintf(queryFmt, dbName, pxname) + queryRes, err := dbinst.Query(querySql) + if err != nil { + return nil, errors.Wrap(err, "query influxdb") + } + if len(queryRes) != 1 { + return nil, fmt.Errorf("query influxdb: expecting 1 set of results, got %d", len(queryRes)) + } + type Tags struct { + PxName string `json:"pxname"` + SvName string `json:"svname"` + } + for _, resSeries := range queryRes[0] { + if len(resSeries.Values) == 0 { + continue + } + resColumns := resSeries.Values[0] + if len(resColumns) != 3 { + continue + } + tags := Tags{} + if err := resSeries.Tags.Unmarshal(&tags); err != nil { + return nil, errors.Wrap(err, "unmarshal tags in influxdb query result") + } + ok, i := utils.InStringArray(tags.SvName, backendIds) + if !ok { + continue + } + fmt.Printf("idx: %d\n", i) + backendJson := backendJsons[i].(*jsonutils.JSONDict) + for j, colName := range resSeries.Columns { + colVal := resColumns[j] + if colVal == nil { + colVal = jsonutils.JSONNull + } + if colName == "time" { + colName = "check_time" + } + backendJson.Set(colName, colVal) + } + } + return jsonutils.NewArray(backendJsons...), nil +} diff --git a/pkg/compute/models/loadbalanceragents.go b/pkg/compute/models/loadbalanceragents.go index b1d23b25bd..a44b8ffc4e 100644 --- a/pkg/compute/models/loadbalanceragents.go +++ b/pkg/compute/models/loadbalanceragents.go @@ -566,6 +566,15 @@ func (manager *SLoadbalancerAgentManager) QueryDistinctExtraField(q *sqlchemy.SQ return q, nil } +func (man *SLoadbalancerAgentManager) getByClusterId(clusterId string) ([]SLoadbalancerAgent, error) { + r := []SLoadbalancerAgent{} + q := man.Query().Equals("cluster_id", clusterId) + if err := db.FetchModelObjects(man, q, &r); err != nil { + return nil, err + } + return r, nil +} + func (lbagent *SLoadbalancerAgent) AllowPerformHb(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data *jsonutils.JSONDict) bool { return db.IsAdminAllowPerform(userCred, lbagent, "hb") } diff --git a/pkg/compute/models/loadbalancers.go b/pkg/compute/models/loadbalancers.go index 2049381434..ffd3beff70 100644 --- a/pkg/compute/models/loadbalancers.go +++ b/pkg/compute/models/loadbalancers.go @@ -849,3 +849,15 @@ func (manager *SLoadbalancerManager) GetLbDefaultBackendGroupIds() ([]string, er return ret, nil } + +func (man *SLoadbalancerManager) getLoadbalancer(lbId string) (*SLoadbalancer, error) { + obj, err := man.FetchById(lbId) + if err != nil { + return nil, errors.Wrapf(err, "get loadbalancer %s", lbId) + } + lb := obj.(*SLoadbalancer) + if lb.PendingDeleted { + return nil, errors.Wrap(errors.ErrNotFound, "pending deleted") + } + return lb, nil +} From 10e575f62ba79334f67f091c95c4c22bd82edcec Mon Sep 17 00:00:00 2001 From: Yousong Zhou Date: Tue, 12 Nov 2019 03:35:22 +0000 Subject: [PATCH 4/4] =?UTF-8?q?climc:=20=E6=B7=BB=E5=8A=A0lblistener{,rule?= =?UTF-8?q?}-backend-status=E5=91=BD=E4=BB=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cmd/climc/shell/loadbalancerlistenerrules.go | 7 ++++ cmd/climc/shell/loadbalancerlisteners.go | 38 +++++++++++++++++++ .../options/loadbalancerlistenerrules.go | 4 ++ pkg/mcclient/options/loadbalancerlisteners.go | 4 ++ 4 files changed, 53 insertions(+) diff --git a/cmd/climc/shell/loadbalancerlistenerrules.go b/cmd/climc/shell/loadbalancerlistenerrules.go index 1d82eaa5f8..ac0832d50e 100644 --- a/cmd/climc/shell/loadbalancerlistenerrules.go +++ b/cmd/climc/shell/loadbalancerlistenerrules.go @@ -89,4 +89,11 @@ func init() { printObject(lblistenerrule) return nil }) + R(&options.LoadbalancerListenerRuleGetBackendStatusOptions{}, "lblistenerrule-backend-status", "Get lblistenerrule backend status", func(s *mcclient.ClientSession, opts *options.LoadbalancerListenerRuleGetBackendStatusOptions) error { + backendStatus, err := modules.LoadbalancerListenerRules.GetSpecific(s, opts.ID, "backend-status", nil) + if err != nil { + return err + } + return printLbBackendStatus(backendStatus) + }) } diff --git a/cmd/climc/shell/loadbalancerlisteners.go b/cmd/climc/shell/loadbalancerlisteners.go index 7b54c3b94c..7e9eedfa99 100644 --- a/cmd/climc/shell/loadbalancerlisteners.go +++ b/cmd/climc/shell/loadbalancerlisteners.go @@ -15,13 +15,44 @@ package shell import ( + "fmt" + "yunion.io/x/jsonutils" "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/onecloud/pkg/mcclient/modulebase" "yunion.io/x/onecloud/pkg/mcclient/modules" "yunion.io/x/onecloud/pkg/mcclient/options" ) +func printLbBackendStatus(backendStatus jsonutils.JSONObject) error { + arr, ok := backendStatus.(*jsonutils.JSONArray) + if !ok { + return fmt.Errorf("want json array, got %s", backendStatus.String()) + } + objList, err := arr.GetArray() + if err != nil { + return err + } + listResult := &modulebase.ListResult{ + Data: objList, + } + columns := []string{ + "id", + "name", + "backend_type", + "backend_id", + "address", + "port", + "weight", + "check_time", + "check_status", + "check_code", + } + printList(listResult, columns) + return nil +} + func init() { R(&options.LoadbalancerListenerCreateOptions{}, "lblistener-create", "Create lblistener", func(s *mcclient.ClientSession, opts *options.LoadbalancerListenerCreateOptions) error { @@ -99,4 +130,11 @@ func init() { printObject(lblistener) return nil }) + R(&options.LoadbalancerListenerGetBackendStatusOptions{}, "lblistener-backend-status", "Get lblistene backend status", func(s *mcclient.ClientSession, opts *options.LoadbalancerListenerGetBackendStatusOptions) error { + backendStatus, err := modules.LoadbalancerListeners.GetSpecific(s, opts.ID, "backend-status", nil) + if err != nil { + return err + } + return printLbBackendStatus(backendStatus) + }) } diff --git a/pkg/mcclient/options/loadbalancerlistenerrules.go b/pkg/mcclient/options/loadbalancerlistenerrules.go index c5f41c51d0..10975f428f 100644 --- a/pkg/mcclient/options/loadbalancerlistenerrules.go +++ b/pkg/mcclient/options/loadbalancerlistenerrules.go @@ -46,6 +46,10 @@ type LoadbalancerListenerRuleDeleteOptions struct { ID string `json:"-"` } +type LoadbalancerListenerRuleGetBackendStatusOptions struct { + ID string `json:"-"` +} + type LoadbalancerListenerRuleActionStatusOptions struct { ID string `json:"-"` Status string `choices:"enabled|disabled"` diff --git a/pkg/mcclient/options/loadbalancerlisteners.go b/pkg/mcclient/options/loadbalancerlisteners.go index 93ce2322a5..850ffb7964 100644 --- a/pkg/mcclient/options/loadbalancerlisteners.go +++ b/pkg/mcclient/options/loadbalancerlisteners.go @@ -184,6 +184,10 @@ type LoadbalancerListenerActionStatusOptions struct { Status string `choices:"enabled|disabled"` } +type LoadbalancerListenerGetBackendStatusOptions struct { + ID string `json:"-"` +} + type LoadbalancerListenerActionSyncStatusOptions struct { ID string `json:"-"` }