From 929f9adcf15f4552496fc1b3fbae58ba330a2b63 Mon Sep 17 00:00:00 2001 From: LittleTransparent Date: Thu, 21 Jan 2021 17:08:00 +0800 Subject: [PATCH 1/5] =?UTF-8?q?meta=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- controllers/meta.go | 26 ++++++ models/meta.go | 193 ++++++++++++++++++++++++++++++++++++++++++++ routers/router.go | 2 + 3 files changed, 221 insertions(+) create mode 100644 controllers/meta.go create mode 100644 models/meta.go diff --git a/controllers/meta.go b/controllers/meta.go new file mode 100644 index 0000000..950098a --- /dev/null +++ b/controllers/meta.go @@ -0,0 +1,26 @@ +package controllers + +import ( + "github.com/beego/beego/v2/server/web" +) + +type MetaController struct { + web.Controller +} + +func (mc *MetaController) Get() { + mc.Data["json"] = models.getResourceMetas() + mc.ServeJSON() +} + +type MetasController struct { + web.Controller +} + +func (mc *MetasController) Get() { + rscClass := mc.Ctx.Input.Param(":rsc_class") + rscType := mc.Ctx.Input.Param(":rsc_type") + rscProvider := mc.Ctx.Input.Param(":rsc_provider") + mc.Data["json"] = models.getAllResourceMetas(rscClass, rscType, rscProvider) + mc.ServeJSON() +} diff --git a/models/meta.go b/models/meta.go new file mode 100644 index 0000000..98c70e8 --- /dev/null +++ b/models/meta.go @@ -0,0 +1,193 @@ +package models + +import ( + "regexp" + "strings" + + "github.com/beevik/etree" + "openkylin.com/ha-api/utils" +) + +func GetAllResourceMetas() map[string]interface{} { + var result map[string]interface{} + + out, err := utils.RunCommand("crm_resource --list-standards") + if err != nil { + result["action"] = false + result["error"] = out + return result + } + standards := strings.Split(string(out), "\n") + data := make(map[string]interface{}) + res := make(map[string][]string) + + for _, st := range standards { + if st == "ocf" { + out, err := utils.RunCommand("crm_resource --list-ocf-providers") + if err != nil { + result["action"] = false + result["error"] = out + return result + } + pvds := strings.Split(string(out), "\n") + for _, p := range pvds { + out, err := utils.RunCommand("crm_resource --list-agents ocf:" + p) + if err != nil { + result["action"] = false + result["error"] = out + return result + } + ag := strings.Split(string(out), "\n") + // Eliminate Duplicates + agMap := map[string]bool{} + for _, agStr := range ag { + agMap[agStr] = true + } + ag = []string{} + for k, _ := range agMap { + ag = append(ag, k) + } // Eliminate Duplicates Over + res[p] = ag + } + data["ocf"] = res + } else if st == "lsb" { + continue + } else { + out, err := utils.RunCommand("crm_resource --list-agents " + st) + if err != nil { + result["action"] = false + result["error"] = out + return result + } + la := strings.Split(string(out), "\n") + // Eliminate Duplicates + laMap := map[string]bool{} + for _, laStr := range la { + laMap[laStr] = true + } + la = []string{} + for k, _ := range laMap { + la = append(la, k) + } // Eliminate Duplicates Over + laLen := len(la) + for i := laLen - 1; i >= 0; i-- { + if strings.HasSuffix(la[i], "@") { + la = append(la[:i], la[(i+1):]...) + } + } + for i, subla := range la { + if ok, _ := regexp.MatchString(`.*\@`, subla); ok { + la = append(la[:i], la[(i+1):]...) + } + } + data[st] = la + } + } + result["action"] = true + result["data"] = data + return result +} + +func GetResourceMetas(rscClass, rscType, rscProvider string) map[string]interface{} { + data := make(map[string]interface{}) + prop := []map[string]interface{}{} + actions := []map[string]string{} + + cmd := "" + resourceType := "crm_resource --show-metadata " + if rscProvider == "None" { + cmd = resourceType + rscClass + ":" + rscType + } else { + cmd = resourceType + rscClass + ":" + rscProvider + ":" + rscType + } + out, err := utils.RunCommand(cmd) + if err != nil { + return map[string]interface{}{"action": false, "data": data} + } + doc := etree.NewDocument() + if err = doc.ReadFromBytes(out); err != nil { + return map[string]interface{}{"action": false, "data": data} + } + eRoot := doc.Root() + data["name"] = eRoot.SelectAttrValue("name", "") + parameter := eRoot.FindElements("./parameters/parameter") + for _, i := range parameter { + var parameters map[string]interface{} + parameters["name"] = i.SelectAttrValue("name", "") + parameters["required"] = i.SelectAttrValue("required", "") + parameters["unique"] = i.SelectAttrValue("unique", "") + content := i.FindElement("content") + var cnt map[string]string + cnt["default"] = content.SelectAttrValue("default", "") + cnt["type"] = content.SelectAttrValue("type", "") + parameters["content"] = cnt + if i.FindElement("shortdesc") != nil { + text := i.FindElement("shortdesc").Text() + count := strings.Count(text, "\n") + parameters["shortdesc"] = strings.Replace(text, "\n", " ", count) + } else { + parameters["shortdesc"] = "" + } + if i.FindElement("longdesc") != nil { + text := i.FindElement("longdesc").Text() + count := strings.Count(text, "\n") + parameters["longdesc"] = strings.Replace(text, "\n", " ", count) + } else { + parameters["longdesc"] = "" + } + prop = append(prop, parameters) + if rscClass == "stonith" { + var pcmkHostList map[string]interface{} + content := map[string]string{"default": "", "type": "string"} + pcmkHostList["content"] = content + pcmkHostList["longdesc"] = "A list of machines controlled by this device." + pcmkHostList["name"] = "pcmk_host_list" + pcmkHostList["required"] = "1" + pcmkHostList["shortdesc"] = "" + pcmkHostList["unique"] = "" + pcmkHostList["value"] = "" + prop = append(prop, pcmkHostList) + } + } + actionElems := eRoot.FindElements("./actions/action") + for _, actionElem := range actionElems { + var act map[string]string + for _, attr := range actionElem.Attr { + act[attr.Key] = attr.Value + } + actions = append(actions, act) + } + if version := eRoot.FindElement("version"); version != nil { + data["version"] = version.Text() + } else { + data["version"] = "" + } + if longdesc := eRoot.FindElement("longdesc"); longdesc != nil { + text := longdesc.Text() + count := strings.Count(text, "\n") + data["longdesc"] = strings.Replace(text, "\n", " ", count) + } else { + data["longdesc"] = "" + } + if shortdesc := eRoot.FindElement("shortdesc"); shortdesc != nil { + text := shortdesc.Text() + count := strings.Count(text, "\n") + data["shortdesc"] = strings.Replace(text, "\n", " ", count) + } else { + data["shortdesc"] = "" + } + data["parameters"] = prop + data["actions"] = actions + + if rscType == "fence_sbd" { + w := data["parameters"].([]map[string]interface{}) + for i, v := range w { + ret := v["name"] + if ret == "plug" { + w = append(w[:i], w[(i+1):]...) + } + } + } + /* By the end of "pcs resource describe " */ + return map[string]interface{}{"action": true, "data": data} +} diff --git a/routers/router.go b/routers/router.go index bb45bf4..f17ebc4 100644 --- a/routers/router.go +++ b/routers/router.go @@ -23,6 +23,8 @@ func init() { web.NSRouter("/haclusters/1/resources", &controllers.ResourceController{}), web.NSRouter("/haclusters/1/resources/:rscID/:action", &controllers.ResourceController{}), + web.NSRouter("/haclusters/1/metas", &controllers.MetasController{}), + web.NSRouter("/haclusters/1/metas/:rsc_class/:rsc_type/:rsc_provider", &controllers.MetaController{}), web.NSRouter("/haclusters/1/configs", &controllers.HeartBeatController{}), -- Gitee From a7fc0c87da7abf7af35acb5b6f581598abcd338c Mon Sep 17 00:00:00 2001 From: LittleTransparent Date: Thu, 21 Jan 2021 19:08:29 +0800 Subject: [PATCH 2/5] resource partially committed --- models/resource.go | 242 +++++++++++++++++++++++++++++++++++++++++-- utils/score_level.go | 6 ++ 2 files changed, 240 insertions(+), 8 deletions(-) create mode 100644 utils/score_level.go diff --git a/models/resource.go b/models/resource.go index eab4083..fbd24fb 100644 --- a/models/resource.go +++ b/models/resource.go @@ -18,11 +18,11 @@ func GerResourceInfo() map[string]interface{} { clusterStatus := GetClusterStatus() if clusterStatus != 0 { result["action"] = true - result["action"] = []string{} + result["data"] = []string{} return result } - constraints := GetAllConstraints() + constraints := GetAllConstraints() ///////////////// if _, ok := constraints["action"]; !ok { return constraints } @@ -39,7 +39,7 @@ func GerResourceInfo() map[string]interface{} { } t := GetResourceType(rscId) - subRscs := GetSubResources(rscId) + subRscs := GetSubResources(rscId) /////////////////// if t == "group" || t == "clone" { constraint["subrscs"] = subRscs["subrscs"] } else { @@ -73,7 +73,32 @@ func GetResourceConstraints() { } -func GetResourceFailedMessage() {} +func GetResourceFailedMessage() map[string]map[string]string { + out, err := utils.RunCommand("crm_mon -1 --as-xml") + failInfo := map[string]map[string]string{} + if err != nil { + return failInfo + } + doc := etree.NewDocument() + if err = doc.ReadFromBytes(out); err != nil { + return failInfo + } + failures := doc.SelectElements("crm_mon/failures/failure") + if len(failures) == 0 { + return failInfo + } else { + for _, failure := range failures { + infoFail := map[string]string{} + rscIdf := strings.Split(failure.SelectAttr("op_key").Value, "_stop_")[0] + rscIdm := strings.Split(rscIdf, "_start_")[0] + rscId := strings.Split(rscIdm, "_start_")[0] + node := failure.SelectAttr("node") + exitreason := failure.SelectAttr("exitreason") + + } + } + return failInfo +} func GetResourceMetaAttributes() {} @@ -82,12 +107,170 @@ func GetResourceByConstraintAndId() { } func CreateResource(data []byte) map[string]interface{} { - // TODO: return nil } func GetAllConstraints() map[string]interface{} { - return nil + rscStatus := GetAllResourceStatus() /////////////// + var data map[string](map[string]interface{}) + + topRsc := GetTopResource() + for _, rscId := range topRsc { + rsc := strings.Split(rscId, ":")[0] + data[rsc] = map[string]interface{}{} + if _, ok := rscStatus[rsc]; !ok { + data[rsc]["status"] = "Running" + data[rsc]["status_message"] = "" + data[rsc]["running_node"] = []string{} + } else { + data[rsc]["status"] = "Running" + data[rsc]["status_message"] = "" + data[rsc]["running_node"] = rscStatus[rsc]["running_node"] + } + data[rsc]["before_rscs"] = []map[string]string{} + data[rsc]["after_rscs"] = []map[string]string{} + data[rsc]["same_node"] = []map[string]string{} + data[rsc]["diff_node"] = []map[string]string{} + data[rsc]["location"] = []map[string]string{} + } + + out, err := utils.RunCommand("cibadmin -Q") + if err != nil { + var result map[string]interface{} + result["action"] = false + result["data"] = data + return result + } + doc := etree.NewDocument() + if err = doc.ReadFromBytes(out); err != nil { + var result map[string]interface{} + result["action"] = false + result["data"] = data + return result + } + constraints := doc.FindElement("constraints") + + //location + for _, location := range constraints.FindElements("rsc_location") { + if strings.HasPrefix(location.SelectAttr("id").Value, "cli-prefer-") { + continue + } + node := location.SelectAttr("node").Value + rscId := location.SelectAttr("rsc").Value + score := location.SelectAttr("score").Value + locationSingle := make(map[string]string) + locationSingle["node"] = node + locationSingle["level"] = utils.ScoreToLevel(score) ////////// + locationArr := []map[string]string{} + for key := range data { + if rscId == key { + locationArr = append(locationArr, locationSingle) + } + } + data[rscId]["location"] = locationArr + } + + //order + for _, order := range constraints.FindElements("rsc_order") { + first := order.SelectAttr("first").Value + then := order.SelectAttr("then").Value + + //try except + score := order.SelectAttr("score").Value + if score == "" || len(score) == 0 { + score = "infinity" + } + if score != "INFINITY" && score != "+INFINITY" && score != "infinity" && score != "+infinity" { + continue + } + + afterRscsArr := []map[string]string{} + if _, ok := data[first]; !ok { + afterRscsArr = append(afterRscsArr, map[string]string{"id": then}) + } + data[first]["after_rscs"] = afterRscsArr + beforeRscsArr := []map[string]string{} + if _, ok := data[then]; !ok { + beforeRscsArr = append(beforeRscsArr, map[string]string{"id": then}) + } + data[then]["before_rscs"] = beforeRscsArr + } + + //colocation + for _, colocation := range constraints.FindElements("rsc_colocation") { + first := colocation.SelectAttr("rsc").Value + with := colocation.SelectAttr("with-rsc").Value + + //try except + score := colocation.SelectAttr("score").Value + if score == "INFINITY" || score == "+INFINITY" || score == "infinity" || score == "+infinity" { + rsc := map[string]string{} + rsc["rsc"] = first + rsc["with_rsc"] = with + data[first]["same_node"] = rsc + data[with]["same_node"] = rsc + } else if score == "-INFINITY" || score == "-infinity" { + rsc := map[string]string{} + rsc["rsc"] = first + rsc["with_rsc"] = with + data[first]["diff_node"] = rsc + data[with]["diff_node"] = rsc + } + } + + failureInfo := GetResourceFailedMessage() /////////////// + + constraintMaps := []map[string]interface{}{} + for rscId := range data { + var constraint map[string]interface{} + constraint["id"] = rscId + rscIDFirst := strings.Split(rscId, ":")[0] + if _, ok := rscStatus[rscId]; !ok { + if _, ok := failureInfo[rscIDFirst]; !ok { + constraint["status"] = "Stopped" + constraint["status_message"] = "" + constraint["running_node"] = []string{} + } + } else if strings.HasSuffix(rscId, "-clone") { + constraint["status"] = "Failed" + //////////////////// + constraint["status_message"] = failureInfo[rscIDFirst]["exitreason"] + " on " + failureInfo[rscIDFirst]["node"] + constraint["running_node"] = []string{} + } else { + rscInfo := rscStatus[rscId] + constraint["status"] = rscInfo["status"] + constraint["status_message"] = "" + constraint["running_node"] = rscInfo["running_node"] + } + + colocation := map[string]interface{}{} + colocation["same_node"] = data[rscId]["same_node"] + colocation["diff_node"] = data[rscId]["diff_node"] + if tempArray, ok := colocation["same_node"].([]map[string]string); ok { + colocation["same_node_num"] = len(tempArray) + } + if tempArray, ok := colocation["diff_node"].([]map[string]string); ok { + colocation["diff_node_num"] = len(tempArray) + } + order := map[string]interface{}{} + order["before_rscs"] = data[rscId]["before_rscs"] + order["after_rscs"] = data[rscId]["after_rscs"] + if tempArray, ok := colocation["before_rscs"].([]map[string]string); ok { + colocation["before_rscs_num"] = len(tempArray) + } + if tempArray, ok := colocation["after_rscs"].([]map[string]string); ok { + colocation["after_rscs_num"] = len(tempArray) + } + constraint["location"] = data[rscId]["location"] + constraint["colocation"] = colocation + constraint["order"] = order + constraintMaps = append(constraintMaps, constraint) + } + + var result map[string]interface{} + result["action"] = true + result["data"] = constraints + return result } func GetAllMigrateResources() []string { @@ -134,11 +317,54 @@ func GetAllMigrateResources() []string { } } - return result + return rscList +} + +func GetAllResourceStatus() map[string]map[string]string { + // rscInfo:= + out, err := utils.RunCommand("crm_mon -1 --as-xml") + if err != nil { + return map[string]map[string]string{} + } + doc := etree.NewDocument() + if err = doc.ReadFromBytes(out); err != nil { + return map[string]map[string]string{} + } + + if len(doc.SelectElements("crm_mon/resources")) == 0 { + return map[string]map[string]string{} + } + // allRscRun:=[]string{} // doesn't used + rscClone := doc.SelectElements("crm_mon/resources/clone") + rscGroup := doc.SelectElements("crm_mon/resources/group") + rscResource := doc.SelectElements("crm_mon/resources/resource") + + if len(rscClone) != 0 { + if len(rscClone) != 1 { + for _, rsc := range rscClone { + subRscs := rsc.FindElement("resource") + index := 0 + + for _, subRsc := range subRscs { + + } + } + } + } + if len(rscGroup) != 0 { + + } + if len(rscResource) != 0 { + + } + + return map[string]map[string]string{} } func GetSubResources(rscId string) map[string]interface{} { - // TODO: + rscStatus := GetAllResourceStatus() + failInfo := GetResourceFailedMessage() + return nil } diff --git a/utils/score_level.go b/utils/score_level.go new file mode 100644 index 0000000..2af8a96 --- /dev/null +++ b/utils/score_level.go @@ -0,0 +1,6 @@ +package utils + +func ScoreToLevel(score string) string { + + return "" +} -- Gitee From 0afe5c59ef0cc1936cb5f25933ce5b2bea4fbde3 Mon Sep 17 00:00:00 2001 From: LittleTransparent Date: Fri, 22 Jan 2021 19:41:59 +0800 Subject: [PATCH 3/5] part of resource --- models/resource.go | 401 ++++++++++++++++++++++++++++++++++++++++--- utils/score_level.go | 6 - utils/utils.go | 13 ++ 3 files changed, 386 insertions(+), 34 deletions(-) delete mode 100644 utils/score_level.go diff --git a/models/resource.go b/models/resource.go index dc9737c..a3504f6 100644 --- a/models/resource.go +++ b/models/resource.go @@ -22,7 +22,7 @@ func GetResourceInfo() map[string]interface{} { return result } - constraints := GetAllConstraints() ///////////////// + constraints := GetAllConstraints() if _, ok := constraints["action"]; !ok { return constraints } @@ -39,7 +39,7 @@ func GetResourceInfo() map[string]interface{} { } t := GetResourceType(rscId) - subRscs := GetSubResources(rscId) /////////////////// + subRscs := GetSubResources(rscId) if t == "group" || t == "clone" { constraint["subrscs"] = subRscs["subrscs"] } else { @@ -194,9 +194,11 @@ func GetResourceFailedMessage() map[string]map[string]string { rscIdf := strings.Split(failure.SelectAttr("op_key").Value, "_stop_")[0] rscIdm := strings.Split(rscIdf, "_start_")[0] rscId := strings.Split(rscIdm, "_start_")[0] - node := failure.SelectAttr("node") - exitreason := failure.SelectAttr("exitreason") - + node := failure.SelectAttr("node").Value + exitreason := failure.SelectAttr("exitreason").Value + infoFail["node"] = node + infoFail["exitreason"] = exitreason + failInfo[rscId] = infoFail } } return failInfo @@ -318,11 +320,12 @@ func GetResourceByConstraintAndId() { } func CreateResource(data []byte) map[string]interface{} { + // TODO: return nil } func GetAllConstraints() map[string]interface{} { - rscStatus := GetAllResourceStatus() /////////////// + rscStatus := GetAllResourceStatus() var data map[string](map[string]interface{}) topRsc := GetTopResource() @@ -336,7 +339,7 @@ func GetAllConstraints() map[string]interface{} { } else { data[rsc]["status"] = "Running" data[rsc]["status_message"] = "" - data[rsc]["running_node"] = rscStatus[rsc]["running_node"] + data[rsc]["running_node"] = rscStatus["running_node"] } data[rsc]["before_rscs"] = []map[string]string{} data[rsc]["after_rscs"] = []map[string]string{} @@ -371,7 +374,7 @@ func GetAllConstraints() map[string]interface{} { score := location.SelectAttr("score").Value locationSingle := make(map[string]string) locationSingle["node"] = node - locationSingle["level"] = utils.ScoreToLevel(score) ////////// + locationSingle["level"] = ScoreToLevel(score) locationArr := []map[string]string{} for key := range data { if rscId == key { @@ -429,7 +432,7 @@ func GetAllConstraints() map[string]interface{} { } } - failureInfo := GetResourceFailedMessage() /////////////// + failureInfo := GetResourceFailedMessage() constraintMaps := []map[string]interface{}{} for rscId := range data { @@ -441,16 +444,15 @@ func GetAllConstraints() map[string]interface{} { constraint["status"] = "Stopped" constraint["status_message"] = "" constraint["running_node"] = []string{} + } else if strings.HasSuffix(rscId, "-clone") { + constraint["status"] = "Failed" + constraint["status_message"] = failureInfo[rscIDFirst]["exitreason"] + " on " + failureInfo[rscIDFirst]["node"] + constraint["running_node"] = []string{} } - } else if strings.HasSuffix(rscId, "-clone") { - constraint["status"] = "Failed" - //////////////////// - constraint["status_message"] = failureInfo[rscIDFirst]["exitreason"] + " on " + failureInfo[rscIDFirst]["node"] - constraint["running_node"] = []string{} } else { rscInfo := rscStatus[rscId] - constraint["status"] = rscInfo["status"] constraint["status_message"] = "" + constraint["status"] = rscInfo["status"] constraint["running_node"] = rscInfo["running_node"] } @@ -531,19 +533,33 @@ func GetAllMigrateResources() []string { return rscList } -func GetAllResourceStatus() map[string]map[string]string { - // rscInfo:= +func GetAllResourceStatus() map[string]map[string]interface{} { + /* + infos = { + 0:_('Running'), + 1:_('Not Running'), + 2:_('Unmanaged'), + 3:_('Failed'), + 4:_('Stop Failed'), + 5:_('running (Master)'), + 6:_('running (Slave)')} + rsc_info = { + "hj1": {"status": 0 , "status_message": "test", running_node: []} + "hj2": {"status": 0 , "status_message": "test", running_node: []} + } + */ + rscInfo := map[string]map[string]interface{}{} out, err := utils.RunCommand("crm_mon -1 --as-xml") if err != nil { - return map[string]map[string]string{} + return map[string]map[string]interface{}{} } doc := etree.NewDocument() if err = doc.ReadFromBytes(out); err != nil { - return map[string]map[string]string{} + return map[string]map[string]interface{}{} } if len(doc.SelectElements("crm_mon/resources")) == 0 { - return map[string]map[string]string{} + return map[string]map[string]interface{}{} } // allRscRun:=[]string{} // doesn't used rscClone := doc.SelectElements("crm_mon/resources/clone") @@ -551,30 +567,319 @@ func GetAllResourceStatus() map[string]map[string]string { rscResource := doc.SelectElements("crm_mon/resources/resource") if len(rscClone) != 0 { + // several clone if len(rscClone) != 1 { for _, rsc := range rscClone { - subRscs := rsc.FindElement("resource") + // subResources is common resources + if subRscs := rsc.SelectElements("resource"); len(subRscs) != 0 { + index := 0 + cloneRunNodes := []string{} + cloneInfo := map[string]interface{}{} + for _, subRsc := range subRscs { + info := map[string]interface{}{} + info["status"] = GetResourceStatus(subRsc) + info["status_message"] = "" + nodename := "" + if node := subRsc.FindElement("node"); node != nil { + nodename = node.SelectAttr("name").Value + } + id := subRsc.SelectAttr("id").Value + ":" + string(index) + index++ + info["running_node"] = []string{nodename} + rscInfo[id] = info + cloneRunNodes = append(cloneRunNodes, nodename) + } + cloneInfo["status"] = GetResourceStatus(rsc) + cloneInfo["status_message"] = "" + cloneInfo["running_node"] = cloneRunNodes + cloneId := rsc.SelectAttr("id").Value + rscInfo[cloneId] = cloneInfo + } + // subResources is gourp resources + if subRscs := rsc.SelectElements("group"); len(subRscs) != 0 { + cloneRunNodes := []string{} + cloneInfo := map[string]interface{}{} + for _, subRsc := range subRscs { + subRscId := subRsc.SelectAttr("id").Value + groupInfo := map[string]interface{}{} + groupRunNodes := []string{} + if innerRscs := subRsc.SelectElements("resource"); len(innerRscs) != 0 { + groupInfo["status"] = "Not Running" + if len(innerRscs) == 1 { + innerRsc := innerRscs[0] + innerRscId := innerRsc.SelectAttr("id").Value + info := map[string]interface{}{} + info["status"] = GetResourceStatus(subRsc) + info["status_message"] = "" + if node := innerRsc.FindElement("node"); node != nil { + nodename := "" + if node := subRsc.FindElement("node"); node != nil { + nodename = node.SelectAttr("name").Value + } + info["running_node"] = []string{nodename} + groupRunNodes = append(groupRunNodes, nodename) + cloneRunNodes = append(cloneRunNodes, nodename) + groupInfo["status"] = "Running" + } + fatherId := strings.Split(subRscId, ":")[1] + id := innerRscId + ":" + fatherId + rscInfo[id] = info + } else { + for _, innerRsc := range innerRscs { + innerRscId := innerRsc.SelectAttr("id").Value + info := map[string]interface{}{} + groupInfo["status"] = "Stopped" + info["status"] = GetResourceStatus(subRsc) + if info["status"] == "Running" { + groupInfo["status"] = "Running" + } + info["status_message"] = "" + if node := innerRsc.FindElement("node"); node != nil { + nodename := node.SelectAttr("name").Value + info["running_node"] = []string{nodename} + cloneRunNodes = append(cloneRunNodes, nodename) + groupRunNodes = append(groupRunNodes, nodename) + } + fatherId := strings.Split(subRscId, ":")[1] + id := innerRscId + ":" + fatherId + rscInfo[id] = info + } + } + } + groupInfo["running_node"] = utils.RemoveDupl(groupRunNodes) + groupInfo["status_message"] = "" + groupId := subRscId + rscInfo[groupId] = groupInfo + } + cloneInfo["status"] = GetResourceStatus(rsc) + cloneInfo["status_message"] = "" + cloneInfo["running_node"] = utils.RemoveDupl(cloneRunNodes) + cloneId := rsc.SelectAttr("id").Value + rscInfo[cloneId] = cloneInfo + } + } + } else { // single clone + // clone is group resource + if rscCloneGroups := rscClone[0].SelectElements("group"); len(rscCloneGroups) != 0 { + cloneRunNodes := []string{} + cloneInfo := map[string]interface{}{} + cloneInfo["status"] = "Not Running" + for _, rscCloneGroup := range rscCloneGroups { + cloneGroupRunNodes := []string{} + cloneGroupInfo := map[string]interface{}{} + subGroupId := rscCloneGroup.SelectAttr("id").Value + index := strings.Split(subGroupId, ":")[1] + if subRscs := rscCloneGroup.SelectElements("resource"); len(subRscs) != 0 { + cloneGroupInfo["status"] = "Not Running" + + for _, subRsc := range subRscs { + info := map[string]interface{}{} + info["status"] = GetResourceStatus(subRsc) + info["status_message"] = "" + id := subRsc.SelectAttr("id").Value + ":" + index + if node := subRsc.FindElement("node"); node != nil { + nodename := node.SelectAttr("name").Value + info["running_node"] = []string{nodename} + cloneGroupInfo["status"] = "Running" + cloneInfo["status"] = "Running" + cloneGroupRunNodes = append(cloneGroupRunNodes, nodename) + cloneRunNodes = append(cloneRunNodes, nodename) + } + rscInfo[id] = info + } + } + cloneGroupInfo["running_node"] = utils.RemoveDupl(cloneGroupRunNodes) + cloneGroupInfo["status_message"] = "" + rscInfo[subGroupId] = cloneGroupInfo + } + cloneInfo["status_message"] = "" + cloneInfo["running_node"] = utils.RemoveDupl(cloneRunNodes) + id := rscClone[0].SelectAttr("id").Value + rscInfo[id] = cloneInfo + } + // clone is common resource + if subRscs := rscClone[0].SelectElements("resource"); len(subRscs) != 0 { index := 0 - + cloneRunNodes := []string{} + cloneInfo := map[string]interface{}{} for _, subRsc := range subRscs { - + info := map[string]interface{}{} + info["status"] = GetResourceStatus(subRsc) + info["status_message"] = "" + nodename := subRsc.FindElement("node").SelectAttr("name").Value + id := string(subRsc.SelectAttr("id").Value) + ":" + string(index) + index++ + info["running_node"] = []string{nodename} + rscInfo[id] = info + cloneRunNodes = append(cloneRunNodes, nodename) } + cloneInfo["status"] = GetResourceStatus(rscClone[0]) + cloneInfo["status_message"] = "" + cloneInfo["running_node"] = cloneRunNodes + id := rscClone[0].SelectAttr("id").Value + rscInfo[id] = cloneInfo } } } if len(rscGroup) != 0 { - + // several group + if len(rscGroup) != 1 { + for _, rsc := range rscGroup { + subRscs := rsc.SelectElements("resource") + // several resources in each group + if len(subRscs) > 1 { + groupRunNodes := []string{} + groupInfo := map[string]interface{}{} + groupInfo["status"] = "Not Running" + for _, subRsc := range subRscs { + info := map[string]interface{}{} + info["status"] = GetResourceStatus(subRsc) + info["status_message"] = "" + nodename := "" + if node := subRsc.FindElement("node"); node != nil { + nodename = node.SelectAttr("name").Value + info["running_node"] = []string{nodename} + groupRunNodes = append(groupRunNodes, nodename) + groupInfo["status"] = "Running" + } + id := subRsc.SelectAttr("id").Value + rscInfo[id] = info + } + groupInfo["status_message"] = "" + groupInfo["running_node"] = groupRunNodes + id := rsc.SelectAttr("id").Value + rscInfo[id] = groupInfo + } else { + subRsc := subRscs[0] + groupRunNodes := []string{} + groupInfo := map[string]interface{}{} + groupInfo["status"] = "Not Running" + info := map[string]interface{}{} + info["status"] = GetResourceStatus(subRsc) + info["status_message"] = "" + nodename := "" + if node := subRsc.FindElement("node"); node != nil { + nodename = node.SelectAttr("name").Value + info["running_node"] = []string{nodename} + groupRunNodes = append(groupRunNodes, nodename) + groupInfo["status"] = "Running" + } + id := subRsc.SelectAttr("id").Value + rscInfo[id] = info + groupInfo["status_message"] = "" + groupInfo["running_node"] = utils.RemoveDupl(groupRunNodes) + gid := rsc.SelectAttr("id").Value + rscInfo[gid] = groupInfo + } + } + } else { // single group + rscGroupSin := rscGroup[0] + subRscs := rscGroupSin.SelectElements("resource") + groupInfo := map[string]interface{}{} + flag := 0 + if len(subRscs) > 1 { + groupInfo["status"] = "Not Running" + for _, subRsc := range subRscs { + info := map[string]interface{}{} + info["status"] = GetResourceStatus(subRsc) + info["status_message"] = "" + id := subRsc.SelectAttr("id").Value + if nodes := subRsc.SelectElements("node"); len(nodes) != 0 { + infoRunNode := []string{} + groupRunNodes := []string{} + for _, node := range nodes { + nodename := node.SelectAttr("name").Value + infoRunNode = append(infoRunNode, nodename) + groupRunNodes = append(groupRunNodes, nodename) + groupInfo["status"] = "Running" + } + info["running_node"] = utils.RemoveDupl(infoRunNode) + groupInfo["running_node"] = utils.RemoveDupl(groupRunNodes) + } + rscInfo[id] = info + } + groupInfo["status_message"] = "" + groupId := rscGroupSin.SelectAttr("id").Value + rscInfo[groupId] = groupInfo + } else { + subRsc := subRscs[0] + info := map[string]interface{}{} + info["status"] = GetResourceStatus(subRsc) + info["status_message"] = "" + nodename := "" + if node := subRsc.FindElement("node"); node != nil { + nodename = node.SelectAttr("name").Value + } else { + flag = 1 + } + id := subRsc.SelectAttr("id").Value + info["running_node"] = []string{nodename} + rscInfo[id] = info + groupInfo["status_message"] = "" + groupInfo["running_node"] = []string{} + if flag == 1 { + groupInfo["status"] = "Not Running" + } else { + groupInfo["status"] = "Running" + groupInfo["running_node"] = []string{nodename} + } + groupId := rscGroupSin.SelectAttr("id").Value + rscInfo[groupId] = groupInfo + } + } } if len(rscResource) != 0 { + // several common resource + if len(rscGroup) != 1 { + for _, rsc := range rscResource { + resourceInfo := map[string]interface{}{} + resourceInfo["status"] = GetResourceStatus(rsc) + runningNode := []string{} + if nodes := rsc.SelectElements("node"); len(nodes) != 0 { + for _, node := range nodes { + runningNode = append(runningNode, node.SelectAttr("name").Value) + } + } + resourceInfo["running_node"] = runningNode + resourceInfo["status_message"] = "" + id := rsc.SelectAttr("id").Value + rscInfo[id] = resourceInfo + } + } + } + + return rscInfo +} +func GetResourceStatus(rscInfo *etree.Element) string { + rscId := rscInfo.SelectAttr("id").Value + failInfo := GetResourceFailedMessage() + if _, ok := failInfo[rscId]; ok { + return "Failed" } - return map[string]map[string]string{} + if rscInfo.SelectAttr("managed").Value == "false" { + return "Unmanaged" + } + if rscInfo.SelectAttr("failed").Value == "true" { + return "Failed" + } + if role := rscInfo.SelectAttr("role"); role != nil { + if role.Value == "Started" { + return "Running" + } + if role.Value == "Stopped" { + return "Not Running" + } + + } + return "Running" } func GetSubResources(rscId string) map[string]interface{} { - rscStatus := GetAllResourceStatus() - failInfo := GetResourceFailedMessage() + // TODO: + // rscStatus := GetAllResourceStatus() + // failInfo := GetResourceFailedMessage() // failure run information return nil } @@ -604,7 +909,6 @@ func GetTopResource() []string { return result } - // TODO: check logic doc := etree.NewDocument() if err = doc.ReadFromBytes(out); err != nil { return result @@ -906,3 +1210,44 @@ func getResourceInfoFromXml(cl string, et *etree.Element) (map[string]interface{ return prop, nil } + +func levelInit() []string { + nodeinfo, _ := GetNodesInfo() + nodeNum := len(nodeinfo) + max := nodeNum - 1 + levelScoreArr := make([]string, max) + for i := 0; i < max; i++ { + levelScoreArr[i] = strconv.Itoa(16000 - 1000*i) + } + return levelScoreArr +} + +func ScoreToLevel(score string) string { + levelScoreArr := levelInit() + if score == "20000" { + return "Master Node" + } + if score == "-INFINITY" || score == "-infinity" { + return "No Run Node" + } + + isIn := false + for _, v := range levelScoreArr { + if score == v { + isIn = true + break + } + } + if isIn == false { + return score + } + + level := 1 + for _, s := range levelScoreArr { + if s == score { + return "Slave " + strconv.Itoa(level) + } + level = level + 1 + } + return "" +} diff --git a/utils/score_level.go b/utils/score_level.go deleted file mode 100644 index 2af8a96..0000000 --- a/utils/score_level.go +++ /dev/null @@ -1,6 +0,0 @@ -package utils - -func ScoreToLevel(score string) string { - - return "" -} diff --git a/utils/utils.go b/utils/utils.go index 56f43a8..2816d7c 100644 --- a/utils/utils.go +++ b/utils/utils.go @@ -10,3 +10,16 @@ func IsInSlice(str string, sli []string) bool { } return false } + +// RemoveDupl remove duplicates in string array +func RemoveDupl(strs []string) []string { + strSet := map[string]bool{} + for _, v := range strs { + strSet[v] = true + } + strsDupl := []string{} + for k := range strSet { + strsDupl = append(strsDupl, k) + } + return strsDupl +} -- Gitee From 3b5a390625ac12dc0fe09e83386c95e36cf61753 Mon Sep 17 00:00:00 2001 From: LittleTransparent Date: Mon, 25 Jan 2021 11:28:32 +0800 Subject: [PATCH 4/5] GetSubResources --- models/resource.go | 180 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 176 insertions(+), 4 deletions(-) diff --git a/models/resource.go b/models/resource.go index a3504f6..7917f40 100644 --- a/models/resource.go +++ b/models/resource.go @@ -321,6 +321,42 @@ func GetResourceByConstraintAndId() { func CreateResource(data []byte) map[string]interface{} { // TODO: + // if data == nil || len(data) == 0 { + // return map[string]interface{}{"action": false, "error": "No input data"} + // } + // // rscId := str(data["id"]) + // // cate := str(data["category"]) + // if cate == "primitive" { + // rscIdStr := " id=\"" + rscId + "\"" + // // rscClass:= " class=\"" + str(data["class"]) + "\"" + // // rscType = " type=\"" + str(data["type"]) + "\"" + // cmd := "cibadmin --create -o resources --xml-text '<" + // role := "pcs resource disable " + // out, err := utils.RunCommand("cibadmin -Q") + // if err != nil { + // // TODO: error statements + // return map[string]interface{}{"action": false, "error": "error"} + // } + // doc := etree.NewDocument() + // if err = doc.ReadFromBytes(out); err != nil { + // // TODO: error statements + // return map[string]interface{}{"action": false, "error": "error"} + // } + // primitives := doc.FindElements("primitive") + // for _, primitive := range primitives { + // id := primitive.SelectAttr("id").Value + // resourceId := map[string]string{"id": id} + // if rscId == resourceId["id"] { + // return map[string]interface{}{"action": false, "error": rscId + " is exist"} + // } + // } + + // } else if cate == "group" { + + // } else if cate == "clone" { + + // } + // return map[string]interface{}{"action": true, "info": "Add " + cate + " resource success"} return nil } @@ -562,10 +598,10 @@ func GetAllResourceStatus() map[string]map[string]interface{} { return map[string]map[string]interface{}{} } // allRscRun:=[]string{} // doesn't used + rscClone := doc.SelectElements("crm_mon/resources/clone") rscGroup := doc.SelectElements("crm_mon/resources/group") rscResource := doc.SelectElements("crm_mon/resources/resource") - if len(rscClone) != 0 { // several clone if len(rscClone) != 1 { @@ -878,10 +914,146 @@ func GetResourceStatus(rscInfo *etree.Element) string { func GetSubResources(rscId string) map[string]interface{} { // TODO: - // rscStatus := GetAllResourceStatus() - // failInfo := GetResourceFailedMessage() // failure run information + //map[string]map[string]interface{} + rscStatus := GetAllResourceStatus() + //map[string]map[string]string + failInfo := GetResourceFailedMessage() // failure run information + var rscInfo map[string]interface{} - return nil + out, err := utils.RunCommand("cibadmin --query --scope resources") + if err != nil { + return rscInfo + } + doc := etree.NewDocument() + if err = doc.ReadFromBytes(out); err != nil { + return rscInfo + } + resJson := doc.FindElement("resources") + rscType := GetResourceType(rscId) + rscInfo["id"] = rscId + subRscs := []map[string]interface{}{} + + if rscType == "clone" { + nodeInfo, _ := GetNodesInfo() + nodeNum := len(nodeInfo) + clone := resJson.FindElements("clone") + var cloneAim *etree.Element + // find the clone resource's location + if len(clone) < 2 { + if clone[0].SelectAttr("id").Value == rscId { + cloneAim = clone[0] + } + } else { + for _, subClone := range clone { + if subClone.SelectAttr("id").Value == rscId { + cloneAim = subClone + } + } + } + // clone resource objects is group or primitive + // Parse the types of resources and assemble them into strings + if cloneGroup := cloneAim.FindElement("group"); cloneGroup != nil { + subRscId := cloneGroup.SelectAttr("id").Value + if rscPrimitive := cloneGroup.FindElements("primitive"); len(rscPrimitive) != 0 { + for i := 0; i < nodeNum; i++ { + var subRsc map[string]interface{} + subRsc["status"] = "Not Running" + subRsc["running_node"] = []string{} + subRsc["status_message"] = "" + subId := subRscId + ":" + strconv.Itoa(i) + subRsc["id"] = subId + if _, ok := rscStatus[subId]; ok { + subRsc["status"] = rscStatus[subId]["status"] + subRsc["running_node"] = rscStatus[subId]["running_node"] + } + subRsc["type"] = "group" + subSubRsc := []map[string]interface{}{} + for _, primitive := range rscPrimitive { + pid := primitive.SelectAttr("id").Value + ":" + strconv.Itoa(i) + primitiveInfo := map[string]interface{}{} + primitiveInfo["id"] = pid + primitiveInfo["status"] = "Not Running" + primitiveInfo["status_message"] = "" + primitiveInfo["running_node"] = []string{} + if _, ok := rscStatus[pid]; ok { + primitiveInfo["status"] = rscStatus[pid]["status"] + primitiveInfo["running_node"] = rscStatus[pid]["running_node"] + } + primitiveInfo["svc"] = primitive.SelectAttr("type").Value + primitiveInfo["type"] = "primitive" + subSubRsc = append(subSubRsc, primitiveInfo) + } + subRsc["subrscs"] = subSubRsc + subRscs = append(subRscs, subRsc) + } + } + } + + if clonePrimitive := cloneAim.FindElement("primitive"); clonePrimitive != nil { + subRscId := clonePrimitive.SelectAttr("id").Value + for i := 0; i < nodeNum; i++ { + var subRsc map[string]interface{} + subRsc["status"] = "Not Running" + subRsc["status_message"] = "" + subId := subRscId + ":" + strconv.Itoa(i) + subRsc["id"] = subId + if _, ok := rscStatus[subId]; ok { + subRsc["status"] = rscStatus[subId]["status"] + subRsc["running_node"] = rscStatus[subId]["running_node"] + } + // judgment failure message + if subFailInfo, ok := failInfo[subRscId]; ok { + subRsc["status_message"] = subFailInfo["exitreason"] + " on " + subFailInfo["node"] + subRsc["status"] = "Failed" + if subRscStatus, ok := rscStatus[subRscId]; ok { + subRsc["running_node"] = subRscStatus["running_node"] + } else { + subRsc["running_node"] = []string{} + } + } + subRsc["type"] = "primitive" + subRsc["svc"] = clonePrimitive.SelectAttr("type").Value + subRscs = append(subRscs, subRsc) + } + } + } + + if rscType == "group" { + groups := resJson.FindElements("group") + for _, group := range groups { + if rscId == group.SelectAttr("id").Value { + rscPrimitive := group.FindElements("primitive") + for _, primitive := range rscPrimitive { + primitiveInfo := map[string]interface{}{} + primitiveInfo["status_message"] = "" + primitiveId := primitive.SelectAttr("id").Value + primitiveInfo["id"] = primitiveId + if priRscStatus, ok := rscStatus[primitiveId]; ok { + primitiveInfo["status"] = priRscStatus["status"] + primitiveInfo["running_node"] = priRscStatus["running_node"] + } else { + primitiveInfo["status"] = "" + primitiveInfo["running_node"] = []string{} + } + // judgment failure message + if priFail, ok := failInfo[primitiveId]; ok { + primitiveInfo["status_message"] = priFail["exitreason"] + " on " + priFail["node"] + primitiveInfo["status"] = "Failed" + if priRscStatus, ok := rscStatus[primitiveId]; ok { + primitiveInfo["running_node"] = priRscStatus["running_node"] + } else { + primitiveInfo["running_node"] = []string{} + } + } + primitiveInfo["type"] = "primitive" + primitiveInfo["svc"] = primitive.SelectAttr("type").Value + subRscs = append(subRscs, primitiveInfo) + } + } + } + } + rscInfo["subrscs"] = subRscs + return rscInfo } func GetResourceSvc(rscId string) string { -- Gitee From d2d5a1124121f9ce0bde344625201cecd99e612d Mon Sep 17 00:00:00 2001 From: LittleTransparent Date: Tue, 26 Jan 2021 11:21:27 +0800 Subject: [PATCH 5/5] finish get, part of post --- models/resource.go | 367 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 353 insertions(+), 14 deletions(-) diff --git a/models/resource.go b/models/resource.go index cc756b2..1db5250 100644 --- a/models/resource.go +++ b/models/resource.go @@ -320,27 +320,36 @@ func GetResourceByConstraintAndId() { } func CreateResource(data []byte) map[string]interface{} { - // TODO: if data == nil || len(data) == 0 { return map[string]interface{}{"action": false, "error": "No input data"} } - // rscId := str(data["id"]) - // cate := str(data["category"]) + var jsonData interface{} + err := json.Unmarshal(data, jsonData) + if err != nil { + return map[string]interface{}{"action": false, "error": "Cannot convert data to json map"} + } + jsonMap := jsonData.(map[string]interface{}) + + var rscId string + if v, ok := jsonMap["id"].(string); ok { + rscId = v + } else if v, ok := jsonMap["id"].(int); ok { + rscId = strconv.Itoa(v) + } + cate := jsonMap["category"].(string) if cate == "primitive" { rscIdStr := " id=\"" + rscId + "\"" - // rscClass:= " class=\"" + str(data["class"]) + "\"" - // rscType = " type=\"" + str(data["type"]) + "\"" + rscClass := " class=\"" + jsonMap["class"].(string) + "\"" + rscType := " type=\"" + jsonMap["type"].(string) + "\"" cmd := "cibadmin --create -o resources --xml-text '<" role := "pcs resource disable " out, err := utils.RunCommand("cibadmin -Q") if err != nil { - // TODO: error statements - return map[string]interface{}{"action": false, "error": "error"} + return map[string]interface{}{"action": false, "error": out} } doc := etree.NewDocument() if err = doc.ReadFromBytes(out); err != nil { - // TODO: error statements - return map[string]interface{}{"action": false, "error": "error"} + return map[string]interface{}{"action": false, "error": "xml parse failed"} } primitives := doc.FindElements("primitive") for _, primitive := range primitives { @@ -350,7 +359,36 @@ func CreateResource(data []byte) map[string]interface{} { return map[string]interface{}{"action": false, "error": rscId + " is exist"} } } + groups := doc.FindElements("group") + for _, group := range groups { + id := group.SelectAttr("id").Value + resourceId := map[string]string{"id": id} + if rscId == resourceId["id"] { + return map[string]interface{}{"action": false, "error": rscId + " is exist"} + } + } + clones := doc.FindElements("clone") + for _, clone := range clones { + id := clone.SelectAttr("id").Value + resourceId := map[string]string{"id": id} + if rscId == resourceId["id"] { + return map[string]interface{}{"action": false, "error": rscId + " is exist"} + } + } + if _, ok := jsonMap["provider"]; ok { + provider := " provider=\"" + jsonMap["provider"].(string) + "\"" + cmdStr := cmd + cate + rscIdStr + rscClass + rscType + provider + ">'" + out, err := utils.RunCommand(cmdStr) + if err != nil { + return map[string]interface{}{"action": false, "error": out} + } + flag := 0 + UpdateResourcAttributes(rscId, jsonMap) + attrib := GetMetaAndInst(rscId) + for _, v := range attrib { + } + } } else if cate == "group" { } else if cate == "clone" { @@ -360,6 +398,259 @@ func CreateResource(data []byte) map[string]interface{} { } +// UpdateResourcAttributes updates meta_attributes and instance_attributes +func UpdateResourcAttributes(rscId string, data map[string]interface{}) map[string]interface{} { + /* + Example data: + { + "category": "primitive", + "actions":[ + { + "interval":"100", + "name":"start" + } + ], + "meta_attributes":{ + "resource-stickiness":"104", + "is-managed":"true", + "target-role":"Started" + }, + "type":"Filesystem", + "id":"iscisi", + "provider":"heartbeat", + "instance_attributes":{ + "device":"/dev/sda1", + "directory":"/var/lib/mysql", + "fstype":"ext4" + }, + "class":"ocf" + } + */ + if data == nil || len(data) == 0 { + return map[string]interface{}{"action": false, "error": "No input data"} + } + // delete all the attribute + attrib := GetMetaAndInst(rscId) + if _, ok := attrib["meta_attributes"]; ok { + metaAttri := attrib["meta_attributes"].([]string) + for _, v := range metaAttri { + cmd := "crm_resource -r " + rscId + " -m --delete-parameter " + v + out, err := utils.RunCommand(cmd) + if err != nil { + return map[string]interface{}{"action": false, "error": out} + } + } + } + if _, ok := attrib["instance_attributes"]; ok { + metaAttri := attrib["instance_attributes"].([]string) + for _, v := range metaAttri { + cmd := "crm_resource -r " + rscId + " -m --delete-parameter " + v + out, err := utils.RunCommand(cmd) + if err != nil { + return map[string]interface{}{"action": false, "error": out} + } + } + } + if data["category"] == "group" { + if _, ok := data["meta_attributes"]; ok { + metaAttri := data["meta_attributes"].(map[string]string) + for k, v := range metaAttri { + cmd := "pcs resource meta " + rscId + " " + k + "=" + v + out, err := utils.RunCommand(cmd) + if err != nil { + return map[string]interface{}{"action": false, "error": out} + } + } + } + } else { + if _, ok := data["meta_attributes"]; ok { + metaAttri := data["meta_attributes"].(map[string]string) + for k, v := range metaAttri { + cmd := "pcs resource update " + rscId + " meta " + k + "=" + v + " --force" + out, err := utils.RunCommand(cmd) + if err != nil { + return map[string]interface{}{"action": false, "error": out} + } + } + } + } + + out, err := utils.RunCommand("sleep 1") + if err != nil { + return map[string]interface{}{"action": false, "error": out} + } + + instStr := "" + if _, ok := data["instance_attributes"]; ok { + instAttri := data["instance_attributes"].(map[string]string) + for k, v := range instAttri { + instStr = instStr + k + "=" + v + " " + } + } + out, err = utils.RunCommand("pcs resource update " + rscId + " " + instStr + " --force") + if err != nil { + return map[string]interface{}{"action": false, "error": out} + } + + // change operation + if _, ok := data["actions"]; ok { + // delete all the attribute + opList := GetAllOps(rscId) + if len(opList) != 0 { + cmdDelHead := "pcs resource op delete " + rscId + for _, op := range opList { + cmdDel := cmdDelHead + " " + op + out, err = utils.RunCommand(cmdDel) + if err != nil { + return map[string]interface{}{"action": false, "error": out} + } + } + } + action := data["actions"].([]map[string]string) + // overwrite + cmdIn := "pcs resource update " + rscId + " op" + for _, ops := range action { + name := ops["name"] + cmdIn = cmdIn + " " + name + if v, ok := ops["interval"]; ok { + cmdIn = cmdIn + " " + "interval=" + v + } + if v, ok := ops["start-delay"]; ok { + cmdIn = cmdIn + " " + "start-delay=" + v + } + if v, ok := ops["timeout"]; ok { + cmdIn = cmdIn + " " + "timeout=" + v + } + if v, ok := ops["role"]; ok { + cmdIn = cmdIn + " " + "role=" + v + } + if v, ok := ops["requires"]; ok { + cmdIn = cmdIn + " " + "requires=" + v + } + if v, ok := ops["on-fail"]; ok { + cmdIn = cmdIn + " " + "on-fail=" + v + } + } + out, err = utils.RunCommand(cmdIn) + if err != nil { + return map[string]interface{}{"action": false, "error": out} + } + } + + // add group resource + if data["category"] == "group" { + /* + { + "id":"group1", + "category":"group", + "rscs":["iscisi", "test1" ], + "meta_attributes":{ + "target-role":"Started" + } + } + */ + } + return map[string]interface{}{"action": true, "info": "Update resource attributes Success"} +} + +func GetAllOps(rscId string) []string { + opList := []string{} + cmd := "crm_resource --resource " + rscId + " --query-xml" + out, err := utils.RunCommand(cmd) + if err != nil { + return opList + } + xml := strings.Split(string(out), ":\n")[1] + doc := etree.NewDocument() + if err := doc.ReadFromString(xml); err != nil { + return opList + } + e := doc.FindElement("operations") + if e != nil { + op := e.SelectElements("./op") + for _, item := range op { + opList = append(opList, item.SelectAttrValue("name", "")) + } + } + return opList +} + +func DeletePriAttrib(rscId string) error { + // delete attribute + attrib := GetMetaAndInst(rscId) + if metaAttri, ok := attrib["meta_attributes"]; ok { + metaArr := metaAttri.([]string) + for _, v := range metaArr { + cmd := "crm_resource -r " + rscId + " -m --delete-parameter " + if v == "is-managed" || v == "priority" || v == "target-role" { + cmd += v + _, err := utils.RunCommand(cmd) + if err != nil { + return err + } + } + } + } + // delete constraint + // colocation + targetId := getResourceConstraintIDs(rscId, "colocation") + err := DeleteColocationByIdAndAction(rscId, targetId) + if err != nil { + return err + } + // location + ids := getResourceConstraintIDs(rscId, "location") + for _, item := range ids { + cmd := "pcs constraint location delete " + item + _, err := utils.RunCommand(cmd) + if err != nil { + return err + } + } + // order + if findOrder(rscId) { + cmd := "pcs constraint order delete " + rscId + _, err := utils.RunCommand(cmd) + if err != nil { + return err + } + } + return nil +} + +func GetMetaAndInst(rscId string) map[string]interface{} { + cmdStr := "crm_resource --resource " + rscId + " --query-xml" + out, err := utils.RunCommand(cmdStr) + if err != nil { + return map[string]interface{}{"action": false, "error": out} + } + xml := strings.Split(string(out), ":\n")[1] + doc := etree.NewDocument() + if err = doc.ReadFromString(xml); err != nil { + return map[string]interface{}{"action": false, "error": err} + } + data := map[string]interface{}{} + eMeta := doc.FindElement("meta_attributes") + if eMeta != nil { + prop := []string{} + items := eMeta.SelectElements("./nvpair") + for _, item := range items { + prop = append(prop, item.SelectAttr("name").Value) + } + data["meta_attributes"] = prop + } + eInst := doc.FindElement("instance_attributes") + if eInst != nil { + prop := []string{} + items := eInst.SelectElements("./nvpair") + for _, item := range items { + prop = append(prop, item.SelectAttr("name").Value) + } + data["instance_attributes"] = prop + } + return data +} + func GetAllConstraints() map[string]interface{} { rscStatus := GetAllResourceStatus() var data map[string](map[string]interface{}) @@ -913,10 +1204,7 @@ func GetResourceStatus(rscInfo *etree.Element) string { } func GetSubResources(rscId string) map[string]interface{} { - // TODO: - //map[string]map[string]interface{} rscStatus := GetAllResourceStatus() - //map[string]map[string]string failInfo := GetResourceFailedMessage() // failure run information var rscInfo map[string]interface{} @@ -1259,7 +1547,43 @@ func ResourceAction(rscID, action string, data []byte) error { } func getResourceConstraintIDs(rscID, action string) []string { - return nil + ids := []string{} + out, err := utils.RunCommand("cibadmin --query --scope constraints") + if err != nil { + return ids + } + doc := etree.NewDocument() + if err = doc.ReadFromBytes(out); err != nil { + return ids + } + + if action == "colocation" { + et := doc.SelectElements("./rsc_colocation") + for _, item := range et { + rsc := item.SelectAttrValue("rsc", "") + rscWith := item.SelectAttrValue("with-rsc", "") + if rsc == rscID { + ids = append(ids, rscWith) + } + if rscWith == rscID { + ids = append(ids, rsc) + } + return ids + } + } else if action == "location" { + et := doc.SelectElements("./rsc_location") + for _, item := range et { + rsc := item.SelectAttrValue("rsc", "") + if rsc == rscID { + if item.SelectAttr("score") != nil && item.SelectAttrValue("score", "") == "-INFINITY" { + continue + } + ids = append(ids, item.SelectAttrValue("id", "")) + } + return ids + } + } + return ids } func DeleteColocationByIdAndAction(rscID string, targetIds []string) error { @@ -1273,7 +1597,22 @@ func DeleteColocationByIdAndAction(rscID string, targetIds []string) error { } func findOrder(rscID string) bool { - // TODO: + out, err := utils.RunCommand("cibadmin --query --scope constraints") + if err != nil { + return false + } + doc := etree.NewDocument() + if err = doc.ReadFromBytes(out); err != nil { + return false + } + et := doc.SelectElements("./rsc_order") + for _, item := range et { + first := item.SelectAttrValue("first", "") + then := item.SelectAttrValue("then", "") + if first == rscID || then == rscID { + return true + } + } return false } -- Gitee