mirror of
https://gitee.com/rainbond/Rainbond.git
synced 2024-11-30 02:38:17 +08:00
[REV] optimize,merge new code
This commit is contained in:
commit
c2269ac74d
@ -161,6 +161,8 @@ class AppImage():
|
||||
pass
|
||||
|
||||
self.log.info("云帮应用发布完毕", step="last", status="success")
|
||||
else:
|
||||
self.log.info("镜像不存在,发布失败", step="callback", status="failure")
|
||||
elif dest == "ys":
|
||||
# 当前有镜像并且云市的image数据中心开启
|
||||
if self.region_registry.exist_image(image) and self.is_oss_image:
|
||||
@ -229,7 +231,9 @@ class AppImage():
|
||||
"云市应用发布失败 {}".format(e.message),
|
||||
step="callback",
|
||||
status="failure")
|
||||
|
||||
else:
|
||||
self.log.info("镜像不存在,发布失败", step="callback", status="failure")
|
||||
|
||||
def download_and_deploy(self):
|
||||
image = self.task['image']
|
||||
namespace = self.task['namespace']
|
||||
|
@ -343,7 +343,10 @@ class RepoBuilder():
|
||||
"path": build_image_name,
|
||||
"event_id": self.event_id
|
||||
}
|
||||
self.region_client.update_version_region(json.dumps(version_body))
|
||||
try:
|
||||
self.region_client.update_version_region(json.dumps(version_body))
|
||||
except Exception as e:
|
||||
pass
|
||||
return True
|
||||
|
||||
def build_code(self):
|
||||
@ -417,7 +420,10 @@ class RepoBuilder():
|
||||
"path": package_name,
|
||||
"event_id": self.event_id
|
||||
}
|
||||
#self.region_client.update_version_region(json.dumps(version_body))
|
||||
try:
|
||||
self.region_client.update_version_region(json.dumps(version_body))
|
||||
except Exception as e:
|
||||
pass
|
||||
return True
|
||||
|
||||
def feedback(self):
|
||||
@ -474,7 +480,7 @@ class RepoBuilder():
|
||||
self.log.error(
|
||||
"升级部署应用错误", step="callback", status="failure")
|
||||
else:
|
||||
self.log.info("构建失败。", step="callback", status="failure")
|
||||
self.log.info("构建失败,请查看Debug构建日志", step="callback", status="failure")
|
||||
else:
|
||||
self.log.error("代码拉取失败。", step="callback", status="failure")
|
||||
except Exception as e:
|
||||
|
@ -35,8 +35,8 @@ class UserConsoleAPI(BaseHttpClient):
|
||||
return res, body
|
||||
|
||||
def service_publish_success(self, body):
|
||||
# pass
|
||||
url = self.base_url + '/api/tenants/services/publish'
|
||||
pass
|
||||
#url = self.base_url + '/api/tenants/services/publish'
|
||||
# url = 'http://127.0.0.1:3228/api/publish'
|
||||
res, body = self._post(url, self.default_headers, body)
|
||||
return res, body
|
||||
#res, body = self._post(url, self.default_headers, body)
|
||||
#return res, body
|
||||
|
@ -139,12 +139,11 @@ class CodeCheck():
|
||||
self.region_client.code_check_region(json.dumps(body))
|
||||
|
||||
|
||||
|
||||
def main():
|
||||
body = ""
|
||||
for line in fileinput.input(): # read task from stdin
|
||||
body = line
|
||||
|
||||
|
||||
code_check = CodeCheck(job=Job(body=body), config=load_dict, base_dir=sys.path[0])
|
||||
code_check.do_work()
|
||||
|
||||
|
@ -29,6 +29,9 @@ type TenantInterface interface {
|
||||
TenantResources(w http.ResponseWriter, r *http.Request)
|
||||
Tenant(w http.ResponseWriter, r *http.Request)
|
||||
ServicesInfo(w http.ResponseWriter, r *http.Request)
|
||||
TenantsWithResource(w http.ResponseWriter, r *http.Request)
|
||||
TenantsQuery(w http.ResponseWriter, r *http.Request)
|
||||
TenantsGetByName(w http.ResponseWriter, r *http.Request)
|
||||
SumTenants(w http.ResponseWriter, r *http.Request)
|
||||
SingleTenantResources(w http.ResponseWriter, r *http.Request)
|
||||
}
|
||||
|
@ -185,6 +185,11 @@ func (v2 *V2) resourcesRouter() chi.Router {
|
||||
r := chi.NewRouter()
|
||||
r.Post("/tenants", controller.GetManager().TenantResources)
|
||||
r.Get("/tenants/sum", controller.GetManager().SumTenants)
|
||||
//tenants's resource
|
||||
r.Get("/tenants/res", controller.GetManager().TenantsWithResource)
|
||||
r.Get("/tenants/res/page/{curPage}/size/{pageLen}", controller.GetManager().TenantsWithResource)
|
||||
r.Get("/tenants/query/{tenant_name}", controller.GetManager().TenantsQuery)
|
||||
r.Get("/tenants/{tenant_name}/res", controller.GetManager().TenantsGetByName)
|
||||
return r
|
||||
}
|
||||
|
||||
|
@ -40,6 +40,8 @@ import (
|
||||
httputil "github.com/goodrain/rainbond/pkg/util/http"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"sort"
|
||||
"github.com/renstorm/fuzzysearch/fuzzy"
|
||||
)
|
||||
|
||||
//V2Routes v2Routes
|
||||
@ -132,6 +134,201 @@ func (t *TenantStruct) TenantResources(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
|
||||
//TenantsQuery TenantsQuery
|
||||
func (t *TenantStruct) TenantsQuery(w http.ResponseWriter, r *http.Request) {
|
||||
// swagger:operation GET /v2/tenants/query/{tenant_name} v2 tenants
|
||||
//
|
||||
// 租户带资源列表
|
||||
//
|
||||
// get tenant resources
|
||||
//
|
||||
// ---
|
||||
// produces:
|
||||
// - application/json
|
||||
// - application/xml
|
||||
//
|
||||
// parameters:
|
||||
// - name: tenant_name
|
||||
// in: path
|
||||
// description: '123'
|
||||
// required: true
|
||||
// type: string
|
||||
// format: string
|
||||
//
|
||||
// responses:
|
||||
// default:
|
||||
// schema:
|
||||
// "$ref": "#/responses/commandResponse"
|
||||
// description: 统一返回格式
|
||||
|
||||
|
||||
tenantName := strings.TrimSpace(chi.URLParam(r, "tenant_name"))
|
||||
|
||||
|
||||
rep, err := handler.GetTenantManager().GetTenantsName()
|
||||
if err != nil {
|
||||
httputil.ReturnError(r, w, 500, fmt.Sprintf("get tenants names error, %v", err))
|
||||
return
|
||||
}
|
||||
|
||||
result:=fuzzy.Find(tenantName, rep) // [cartwheel wheel]
|
||||
httputil.ReturnSuccess(r, w, result)
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
//TenantsGetByName TenantsGetByName
|
||||
func (t *TenantStruct) TenantsGetByName(w http.ResponseWriter, r *http.Request) {
|
||||
// swagger:operation GET /v2/tenants/{tenant_name}/res v2 tenants
|
||||
//
|
||||
// 租户带资源单个
|
||||
//
|
||||
// get tenant resources
|
||||
//
|
||||
// ---
|
||||
// produces:
|
||||
// - application/json
|
||||
// - application/xml
|
||||
//
|
||||
// parameters:
|
||||
// - name: tenant_name
|
||||
// in: path
|
||||
// description: '123'
|
||||
// required: true
|
||||
// type: string
|
||||
// format: string
|
||||
//
|
||||
// responses:
|
||||
// default:
|
||||
// schema:
|
||||
// "$ref": "#/responses/commandResponse"
|
||||
// description: 统一返回格式
|
||||
|
||||
|
||||
|
||||
|
||||
tenantName := strings.TrimSpace(chi.URLParam(r, "tenant_name"))
|
||||
|
||||
v, err := handler.GetTenantManager().GetTenantsByName(tenantName)
|
||||
if err != nil {
|
||||
httputil.ReturnError(r, w, 500, fmt.Sprintf("get tenants names error, %v", err))
|
||||
return
|
||||
}
|
||||
logrus.Infof("query tenant from db by name %s ,got %v",tenantName,v)
|
||||
var res =&api_model.TenantResource{}
|
||||
services, err := handler.GetServiceManager().GetService(v.UUID)
|
||||
if err != nil {
|
||||
httputil.ReturnError(r, w, 500, fmt.Sprintf("get services by tenantID %s error, %v",v.UUID, err))
|
||||
return
|
||||
}
|
||||
totalResInfo, _ := handler.GetTenantManager().TotalMemCPU(services)
|
||||
usedResInfo, _ := handler.GetTenantManager().StatsMemCPU(services)
|
||||
|
||||
res.UUID=v.UUID
|
||||
res.Name=v.Name
|
||||
res.EID=v.EID
|
||||
res.AllocatedCPU=totalResInfo.CPU
|
||||
res.AllocatedMEM=totalResInfo.MEM
|
||||
res.UsedCPU=usedResInfo.CPU
|
||||
res.UsedMEM=usedResInfo.MEM
|
||||
|
||||
httputil.ReturnSuccess(r, w, res)
|
||||
return
|
||||
}
|
||||
|
||||
//TenantsWithResource TenantsWithResource
|
||||
func (t *TenantStruct) TenantsWithResource(w http.ResponseWriter, r *http.Request) {
|
||||
// swagger:operation GET /v2/resources/tenants/res/page/{curPage}/size/{pageLen} v2 PagedTenantResList
|
||||
//
|
||||
// 租户带资源列表
|
||||
//
|
||||
// get paged tenant resources
|
||||
//
|
||||
// ---
|
||||
// produces:
|
||||
// - application/json
|
||||
// - application/xml
|
||||
//
|
||||
// parameters:
|
||||
// - name: curPage
|
||||
// in: path
|
||||
// description: '123'
|
||||
// required: true
|
||||
// type: string
|
||||
// format: string
|
||||
// - name: pageLen
|
||||
// in: path
|
||||
// description: '25'
|
||||
// required: true
|
||||
// type: string
|
||||
// format: string
|
||||
//
|
||||
// responses:
|
||||
// default:
|
||||
// schema:
|
||||
// "$ref": "#/responses/commandResponse"
|
||||
// description: 统一返回格式
|
||||
|
||||
|
||||
|
||||
pageLenStr := strings.TrimSpace(chi.URLParam(r, "pageLen"))
|
||||
curPageStr := strings.TrimSpace(chi.URLParam(r, "curPage"))
|
||||
|
||||
|
||||
|
||||
pageLen,err:=strconv.Atoi(pageLenStr)
|
||||
if err != nil {
|
||||
httputil.ReturnError(r, w, 400, fmt.Sprintf("bad request, %v", err))
|
||||
return
|
||||
}
|
||||
curPage,err:=strconv.Atoi(curPageStr)
|
||||
if err != nil {
|
||||
httputil.ReturnError(r, w, 400, fmt.Sprintf("bad request, %v", err))
|
||||
return
|
||||
}
|
||||
rep, err := handler.GetTenantManager().GetTenants()
|
||||
if err != nil {
|
||||
httputil.ReturnError(r, w, 500, fmt.Sprintf("get tenants error, %v", err))
|
||||
return
|
||||
}
|
||||
var result []*api_model.TenantResource
|
||||
for _,v:=range rep{
|
||||
services, err := handler.GetServiceManager().GetService(v.UUID)
|
||||
if err != nil {
|
||||
httputil.ReturnError(r, w, 500, fmt.Sprintf("get services by tenantID %s error, %v",v.UUID, err))
|
||||
return
|
||||
}
|
||||
totalResInfo, _ := handler.GetTenantManager().TotalMemCPU(services)
|
||||
usedResInfo, _ := handler.GetTenantManager().StatsMemCPU(services)
|
||||
var res api_model.TenantResource
|
||||
res.UUID=v.UUID
|
||||
res.Name=v.Name
|
||||
res.EID=v.EID
|
||||
res.AllocatedCPU=totalResInfo.CPU
|
||||
res.AllocatedMEM=totalResInfo.MEM
|
||||
res.UsedCPU=usedResInfo.CPU
|
||||
res.UsedMEM=usedResInfo.MEM
|
||||
result=append(result,&res)
|
||||
}
|
||||
pList := api_model.TenantResList(result)
|
||||
sort.Sort(pList)
|
||||
var resultList []*api_model.TenantResource
|
||||
if curPage*pageLen<len(rep) {
|
||||
resultList=pList[(curPage-1)*pageLen:curPage*pageLen]
|
||||
}else{
|
||||
resultList=pList[(curPage-1)*pageLen:len(rep)]
|
||||
}
|
||||
|
||||
var ret api_model.PagedTenantResList
|
||||
ret.List=resultList
|
||||
ret.Length=len(resultList)
|
||||
httputil.ReturnSuccess(r, w, ret)
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
//SumTenants 统计租户数量
|
||||
func (t *TenantStruct) SumTenants(w http.ResponseWriter, r *http.Request) {
|
||||
// swagger:operation GET /v2/resources/tenants/sum v2 sumTenants
|
||||
|
@ -503,30 +503,14 @@ func (t *TenantStruct) BuildService(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
sEvent, status, err := createEvent(build.Body.EventID, serviceID, "build", tenantID, build.Body.DeployVersion)
|
||||
handleStatus(status, err, w, r)
|
||||
//{\"tenant_name\":\"\",\"service_alias\":\"\",\"Body\":{\"event_id\":\"c19aa41c357a4d9e9ca38ab7f2a44961\",\"envs\":{},\"kind\":\"source\",\"action\":\"deploy\",\"image_url\":\"\",\"deploy_version\":\"20171122154417\",\"repo_url\":\"--branch master --depth 1 https://github.com/bay1ts/zk_cluster_mini.git\",\"operator\":\"bay1ts\",\"tenant_name\":\"bay1ts-test\",\"service_alias\":\"gr21ea6b\"}}
|
||||
////createBuildInfo
|
||||
|
||||
version := dbmodel.VersionInfo{}
|
||||
version.EventID = sEvent.EventID
|
||||
version.ServiceID = serviceID
|
||||
version.RepoURL = build.Body.RepoURL
|
||||
version.Kind = build.Body.Kind
|
||||
version.BuildVersion = build.Body.DeployVersion
|
||||
db.GetManager().VersionInfoDao().AddModel(&version)
|
||||
//save
|
||||
//version.DeliveredPath
|
||||
//version.FinalStatus
|
||||
//need update
|
||||
|
||||
//EventID string `json:"event_id" validate:"event_id|required"`
|
||||
//ENVS map[string]string `json:"envs" validate:"envs"`
|
||||
//Kind string `json:"kind" validate:"kind|required"`
|
||||
//Action string `json:"action" validate:"action"`
|
||||
//ImageURL string `json:"image_url" validate:"image_url"`
|
||||
//DeployVersion string `json:"deploy_version" validate:"deploy_version|required"`
|
||||
//RepoURL string `json:"repo_url" validate:"repo_url"`
|
||||
//Operator string `json:"operator" validate:"operator"`
|
||||
//TenantName string `json:"tenant_name"`
|
||||
//ServiceAlias string `json:"service_alias"`
|
||||
|
||||
build.Body.EventID = sEvent.EventID
|
||||
if err := handler.GetServiceManager().ServiceBuild(tenantID, serviceID, &build); err != nil {
|
||||
@ -535,6 +519,12 @@ func (t *TenantStruct) BuildService(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
logrus.Debugf("equeue mq build task success")
|
||||
|
||||
err=db.GetManager().VersionInfoDao().AddModel(&version)
|
||||
|
||||
if err != nil {
|
||||
logrus.Infof("error add version %v ,details %s",version,err.Error())
|
||||
}
|
||||
httputil.ReturnSuccess(r, w, sEvent)
|
||||
//w.WriteHeader(200)
|
||||
}
|
||||
|
@ -1,19 +1,19 @@
|
||||
|
||||
// RAINBOND, Application Management Platform
|
||||
// Copyright (C) 2014-2017 Goodrain Co., Ltd.
|
||||
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version. For any non-GPL usage of Rainbond,
|
||||
// one or multiple Commercial Licenses authorized by Goodrain Co., Ltd.
|
||||
// must be obtained first.
|
||||
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
@ -28,7 +28,10 @@ import (
|
||||
//TenantHandler tenant handler
|
||||
type TenantHandler interface {
|
||||
GetTenants() ([]*dbmodel.Tenants, error)
|
||||
GetTenantsByName(name string) (*dbmodel.Tenants, error)
|
||||
GetTenantsName() ([]string, error)
|
||||
StatsMemCPU(services []*dbmodel.TenantServices) (*api_model.StatsInfo, error)
|
||||
TotalMemCPU(services []*dbmodel.TenantServices) (*api_model.StatsInfo, error)
|
||||
//QueryTsdb(md *api_model.MontiorData) (*tsdbClient.QueryResponse, error)
|
||||
HTTPTsdb(md *api_model.MontiorData) ([]byte, error)
|
||||
GetTenantsResources(tr *api_model.TenantResources) ([]*map[string]interface{}, error)
|
||||
|
@ -34,6 +34,7 @@ import (
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
"strings"
|
||||
)
|
||||
|
||||
//TenantAction tenant act
|
||||
@ -91,6 +92,49 @@ func (t *TenantAction) GetTenants() ([]*dbmodel.Tenants, error) {
|
||||
return tenants, err
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//StatsMemCPU StatsMemCPU
|
||||
func (t *TenantAction) TotalMemCPU(services []*dbmodel.TenantServices) (*api_model.StatsInfo, error){
|
||||
cpus := 0
|
||||
mem := 0
|
||||
for _, service := range services {
|
||||
|
||||
logrus.Debugf("service is %s, cpus is %v, mem is %v", service.ID, service.ContainerCPU, service.ContainerMemory)
|
||||
cpus += service.ContainerCPU
|
||||
mem += service.ContainerMemory
|
||||
}
|
||||
si := &api_model.StatsInfo{
|
||||
CPU: cpus,
|
||||
MEM: mem,
|
||||
}
|
||||
return si, nil
|
||||
}
|
||||
|
||||
//GetTenantsName get tenants name
|
||||
func (t *TenantAction) GetTenantsName() ([]string, error) {
|
||||
tenants, err := db.GetManager().TenantDao().GetALLTenants()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var result []string
|
||||
for _,v:=range tenants{
|
||||
result=append(result,strings.ToLower(v.Name))
|
||||
}
|
||||
return result, err
|
||||
}
|
||||
|
||||
//GetTenants get tenants
|
||||
func (t *TenantAction) GetTenantsByName(name string) (*dbmodel.Tenants, error) {
|
||||
tenant, err := db.GetManager().TenantDao().GetTenantIDByName(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return tenant, err
|
||||
}
|
||||
|
||||
//StatsMemCPU StatsMemCPU
|
||||
func (t *TenantAction) StatsMemCPU(services []*dbmodel.TenantServices) (*api_model.StatsInfo, error) {
|
||||
cpus := 0
|
||||
|
@ -25,6 +25,8 @@ import (
|
||||
dbmodel "github.com/goodrain/rainbond/pkg/db/model"
|
||||
)
|
||||
|
||||
|
||||
|
||||
//ServiceGetCommon path参数
|
||||
//swagger:parameters getVolumes getDepVolumes
|
||||
type ServiceGetCommon struct {
|
||||
|
58
pkg/api/model/tenantResourceModel.go
Normal file
58
pkg/api/model/tenantResourceModel.go
Normal file
@ -0,0 +1,58 @@
|
||||
// RAINBOND, Application Management Platform
|
||||
// Copyright (C) 2014-2017 Goodrain Co., Ltd.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version. For any non-GPL usage of Rainbond,
|
||||
// one or multiple Commercial Licenses authorized by Goodrain Co., Ltd.
|
||||
// must be obtained first.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package model
|
||||
|
||||
|
||||
type TenantResList []*TenantResource
|
||||
|
||||
type PagedTenantResList struct {
|
||||
List []*TenantResource `json:"list"`
|
||||
Length int `json:"length"`
|
||||
}
|
||||
//TenantResource path参数
|
||||
//swagger:parameters getVolumes getDepVolumes
|
||||
type TenantResource struct {
|
||||
AllocatedCPU int `json:"alloc_cpu"`
|
||||
AllocatedMEM int `json:"alloc_memory"`
|
||||
|
||||
UsedCPU int `json:"used_cpu"`
|
||||
UsedMEM int `json:"used_memory"`
|
||||
Name string `json:"name"`
|
||||
UUID string `json:"uuid"`
|
||||
EID string `json:"eid"`
|
||||
}
|
||||
func (list TenantResList) Len() int {
|
||||
return len(list)
|
||||
}
|
||||
|
||||
func (list TenantResList) Less(i, j int) bool {
|
||||
if list[i].UsedMEM > list[j].UsedMEM {
|
||||
return true
|
||||
} else if list[i].UsedMEM < list[j].UsedMEM {
|
||||
return false
|
||||
} else {
|
||||
return list[i].UsedCPU > list[j].UsedCPU
|
||||
}
|
||||
}
|
||||
|
||||
func (list TenantResList) Swap(i, j int) {
|
||||
var temp *TenantResource = list[i]
|
||||
list[i] = list[j]
|
||||
list[j] = temp
|
||||
}
|
@ -62,6 +62,8 @@ type NodeInterface interface {
|
||||
Label(label map[string]string)
|
||||
}
|
||||
|
||||
|
||||
|
||||
func (t *Node)Label(label map[string]string) {
|
||||
body,_:=json.Marshal(label)
|
||||
_,_,err:=nodeServer.Request("/nodes/"+t.Id+"/labels","PUT",body)
|
||||
|
@ -37,6 +37,7 @@ type TenantDao interface {
|
||||
GetTenantByUUID(uuid string) (*model.Tenants, error)
|
||||
GetTenantIDByName(tenantName string) (*model.Tenants, error)
|
||||
GetALLTenants() ([]*model.Tenants, error)
|
||||
//GetTenantsOrderByUsedMemPaged(page,pagesize int) ([]*model.Tenants, error)
|
||||
}
|
||||
|
||||
//LicenseDao LicenseDao
|
||||
|
@ -77,6 +77,15 @@ func (t *TenantDaoImpl) GetTenantIDByName(name string) (*model.Tenants, error) {
|
||||
return &tenant, nil
|
||||
}
|
||||
|
||||
//GetTenantsOrderByUsedMemPaged 获取租户分页
|
||||
//func (t *TenantDaoImpl) GetTenantsOrderByUsedMemPaged(page,pagesize int) ([]*model.Tenants, error) {
|
||||
// var tenant []*model.Tenants
|
||||
// if err := t.DB.Select("sum(container_cpu), sum(container_memory)").Where("cur_status = ?", "running").Group("tenant_id").Find(&tenant).Error; err != nil {
|
||||
// return nil, err
|
||||
// }
|
||||
// return tenant, nil
|
||||
//}
|
||||
|
||||
//GetALLTenants GetALLTenants
|
||||
func (t *TenantDaoImpl) GetALLTenants() ([]*model.Tenants, error) {
|
||||
var tenants []*model.Tenants
|
||||
|
@ -312,8 +312,12 @@ func (h *handleMessageStore) handleBarrelEvent() {
|
||||
event.EventID = eventID
|
||||
event.CodeVersion = codeVersion
|
||||
cdb.GetManager().ServiceEventDao().UpdateModel(&event)
|
||||
version,_:=cdb.GetManager().VersionInfoDao().GetVersionByEventID(eventID)
|
||||
version,err:=cdb.GetManager().VersionInfoDao().GetVersionByEventID(eventID)
|
||||
//infos:=strings.Split(codeVersion,":")
|
||||
if err!=nil {
|
||||
logrus.Errorf("error get version by eventID %s",eventID)
|
||||
continue
|
||||
}
|
||||
version.CodeVersion=codeVersion
|
||||
//for k,v:=range infos{
|
||||
// i:=strings.Split(v," ")
|
||||
|
@ -40,6 +40,7 @@ func GetCmds() []cli.Command {
|
||||
cmds = append(cmds, NewCmdEvent())
|
||||
cmds = append(cmds, NewCmdGet())
|
||||
cmds = append(cmds, NewCmdInit())
|
||||
cmds = append(cmds, NewCmdShow())
|
||||
//cmds = append(cmds, NewCmdAddNode())
|
||||
|
||||
//cmds = append(cmds, NewCmdComputeGroup())
|
||||
|
@ -89,7 +89,6 @@ func NewCmdInstallStatus() cli.Command {
|
||||
Status(v.ID)
|
||||
return nil
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}else {
|
||||
|
@ -35,7 +35,23 @@ import (
|
||||
"bytes"
|
||||
)
|
||||
|
||||
|
||||
func NewCmdShow() cli.Command {
|
||||
c:=cli.Command{
|
||||
Name:"show",
|
||||
Usage:"显示region安装完成后访问地址",
|
||||
Action: func(c *cli.Context) error {
|
||||
var urls []string
|
||||
manageHosts:=clients.NodeClient.Nodes().Rule("manage")
|
||||
for _,v:=range manageHosts{
|
||||
url:=v.ExternalIP+":7070"
|
||||
urls=append(urls,url)
|
||||
}
|
||||
fmt.Println(urls)
|
||||
return nil
|
||||
},
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
func NewCmdNode() cli.Command {
|
||||
c:=cli.Command{
|
||||
@ -77,35 +93,35 @@ func NewCmdNode() cli.Command {
|
||||
Name: "list",
|
||||
Usage: "list",
|
||||
Action: func(c *cli.Context) error {
|
||||
list:=clients.NodeClient.Nodes().List()
|
||||
list := clients.NodeClient.Nodes().List()
|
||||
serviceTable := termtables.CreateTable()
|
||||
serviceTable.AddHeaders("uid", "IP", "HostName","role","alived","unschedulable","ready")
|
||||
serviceTable.AddHeaders("uid", "IP", "HostName", "role", "alived", "unschedulable", "ready")
|
||||
var rest []*model.HostNode
|
||||
for _,v:=range list{
|
||||
var ready bool=false
|
||||
for _,c:=range v.Conditions {
|
||||
if string(c.Type)=="Ready"&&string(c.Status)=="True"{
|
||||
ready=true
|
||||
for _, v := range list {
|
||||
var ready bool = false
|
||||
for _, c := range v.Conditions {
|
||||
if string(c.Type) == "Ready" && string(c.Status) == "True" {
|
||||
ready = true
|
||||
}
|
||||
}
|
||||
if v.Role.HasRule("manage") {
|
||||
serviceTable.AddRow(v.ID, v.InternalIP,v.HostName, v.Role.String(),v.Alived,"N/A",ready)
|
||||
serviceTable.AddRow(v.ID, v.InternalIP, v.HostName, v.Role.String(), v.Alived, "N/A", ready)
|
||||
|
||||
}else{
|
||||
rest=append(rest,v)
|
||||
} else {
|
||||
rest = append(rest, v)
|
||||
}
|
||||
}
|
||||
if len(rest)>0 {
|
||||
if len(rest) > 0 {
|
||||
serviceTable.AddSeparator()
|
||||
}
|
||||
for _,v:=range rest{
|
||||
var ready bool=false
|
||||
for _,c:=range v.Conditions {
|
||||
if string(c.Type)=="Ready"&&string(c.Status)=="True"{
|
||||
ready=true
|
||||
for _, v := range rest {
|
||||
var ready bool = false
|
||||
for _, c := range v.Conditions {
|
||||
if string(c.Type) == "Ready" && string(c.Status) == "True" {
|
||||
ready = true
|
||||
}
|
||||
}
|
||||
serviceTable.AddRow(v.ID, v.InternalIP,v.HostName, v.Role.String(),v.Alived,v.Unschedulable,ready)
|
||||
serviceTable.AddRow(v.ID, v.InternalIP, v.HostName, v.Role.String(), v.Alived, v.Unschedulable, ready)
|
||||
}
|
||||
fmt.Println(serviceTable.Render())
|
||||
return nil
|
||||
|
@ -23,7 +23,7 @@ import (
|
||||
"github.com/goodrain/rainbond/pkg/node/core/job"
|
||||
"github.com/goodrain/rainbond/pkg/node/core/k8s"
|
||||
"github.com/goodrain/rainbond/pkg/node/core/store"
|
||||
|
||||
//httputil "github.com/goodrain/rainbond/pkg/util/http"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
@ -543,7 +543,81 @@ func Resources(w http.ResponseWriter, r *http.Request) {
|
||||
logrus.Infof("get cpu %v and mem %v", cpuR, memR)
|
||||
api.ReturnSuccess(r, w, result)
|
||||
}
|
||||
func CapRes(w http.ResponseWriter, r *http.Request) {
|
||||
nodes, err := nodeService.GetAllNode()
|
||||
if err != nil {
|
||||
err.Handle(r, w)
|
||||
return
|
||||
}
|
||||
var capCpu int64
|
||||
var capMem int64
|
||||
for _,v:=range nodes{
|
||||
if v.NodeStatus != nil {
|
||||
capCpu+=v.NodeStatus.Capacity.Cpu().Value()
|
||||
capMem+=v.NodeStatus.Capacity.Memory().Value()
|
||||
}
|
||||
}
|
||||
|
||||
result := new(model.Resource)
|
||||
result.CpuR=int(capCpu)
|
||||
result.MemR=int(capMem)
|
||||
logrus.Infof("get cpu %v and mem %v", capCpu, capMem)
|
||||
api.ReturnSuccess(r, w, result)
|
||||
}
|
||||
|
||||
func RegionRes(w http.ResponseWriter, r *http.Request) {
|
||||
nodes, err := nodeService.GetAllNode()
|
||||
if err != nil {
|
||||
err.Handle(r, w)
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
var capCpu int64
|
||||
var capMem int64
|
||||
for _,v:=range nodes{
|
||||
if v.NodeStatus != nil {
|
||||
capCpu+=v.NodeStatus.Capacity.Cpu().Value()
|
||||
capMem+=v.NodeStatus.Capacity.Memory().Value()
|
||||
}
|
||||
}
|
||||
//
|
||||
//tenants, error := db.GetManager().TenantDao().GetALLTenants()
|
||||
//if error != nil {
|
||||
// logrus.Errorf("error get tenants ,details %s",error.Error())
|
||||
//}
|
||||
//s:=len(tenants)
|
||||
nodeList, error := k8s.K8S.Core().Nodes().List(metav1.ListOptions{})
|
||||
if error != nil {
|
||||
logrus.Errorf("error get nodes from k8s ,details %s", error.Error())
|
||||
api.ReturnError(r, w, 500, "failed,details "+error.Error())
|
||||
return
|
||||
}
|
||||
|
||||
cpuR := 0
|
||||
memR := 0
|
||||
for _, v := range nodeList.Items {
|
||||
|
||||
ps, _ := k8s.GetPodsByNodeName(v.Name)
|
||||
for _, pv := range ps {
|
||||
rc := pv.Spec.Containers[0].Resources.Requests.Cpu().String()
|
||||
rm := pv.Spec.Containers[0].Resources.Requests.Memory().String()
|
||||
cpuR += getCpuInt(rc)
|
||||
memR += convertMemoryToMBInt(rm, true)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
result := new(model.ClusterResource)
|
||||
result.CapCpu=int(capCpu)
|
||||
result.CapMem=int(capMem)/1024/1024
|
||||
result.ReqCpu = float32(cpuR)/1000
|
||||
result.ReqMem = memR
|
||||
result.Node=len(nodes)
|
||||
result.Tenant=0
|
||||
logrus.Infof("get cpu %v and mem %v", capCpu, capMem)
|
||||
api.ReturnSuccess(r, w, result)
|
||||
}
|
||||
func UpdateNode(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
nodeUID := strings.TrimSpace(chi.URLParam(r, "node"))
|
||||
|
@ -76,6 +76,15 @@ func GetNodes(w http.ResponseWriter, r *http.Request) {
|
||||
err.Handle(r, w)
|
||||
return
|
||||
}
|
||||
for _,v:=range nodes {
|
||||
if v.NodeStatus!=nil{
|
||||
for _,condiction:=range v.Conditions{
|
||||
if condiction.Type=="Ready"&&condiction.Status=="True" {
|
||||
v.Status="running"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
httputil.ReturnSuccess(r, w, nodes)
|
||||
}
|
||||
|
||||
|
@ -78,11 +78,21 @@ func ExecTask(w http.ResponseWriter, r *http.Request) {
|
||||
if ok := httputil.ValidatorRequestStructAndErrorResponse(r, w, &nodes, nil); !ok {
|
||||
return
|
||||
}
|
||||
|
||||
err := taskService.ExecTask(taskID, nodes.Nodes)
|
||||
if err != nil {
|
||||
err.Handle(r, w)
|
||||
return
|
||||
}
|
||||
for _,v:=range nodes.Nodes {
|
||||
node, err := nodeService.GetNode(v)
|
||||
if err != nil {
|
||||
err.Handle(r, w)
|
||||
return
|
||||
}
|
||||
node.Status="install"
|
||||
}
|
||||
|
||||
httputil.ReturnSuccess(r, w, nil)
|
||||
}
|
||||
|
||||
|
@ -31,6 +31,16 @@ type Resource struct {
|
||||
MemR int `json:"mem"`
|
||||
}
|
||||
|
||||
//Resource 资源
|
||||
type ClusterResource struct {
|
||||
Node int `json:"node"`
|
||||
Tenant int `json:"tenant"`
|
||||
CapCpu int `json:"cap_cpu"`
|
||||
CapMem int `json:"cap_mem"`
|
||||
ReqCpu float32 `json:"req_cpu"`
|
||||
ReqMem int `json:"req_mem"`
|
||||
}
|
||||
|
||||
type FirstConfig struct {
|
||||
StorageMode string `json:"storage_mode"`
|
||||
StorageHost string `json:"storage_host,omitempty"`
|
||||
|
@ -53,8 +53,11 @@ func Routers(mode string) *chi.Mux {
|
||||
r.Get("/datacenter", controller.GetDatacenterConfig)
|
||||
r.Put("/datacenter", controller.PutDatacenterConfig)
|
||||
})
|
||||
|
||||
r.Route("/nodes", func(r chi.Router) {
|
||||
r.Get("/fullres",controller.RegionRes)
|
||||
r.Get("/resources", controller.Resources)
|
||||
r.Get("/capres", controller.CapRes)
|
||||
r.Get("/", controller.GetNodes)
|
||||
r.Get("/{rule}", controller.GetRuleNodes)
|
||||
r.Post("/", controller.NewNode) //增加一个节点
|
||||
|
@ -62,7 +62,10 @@ func (n *NodeService) AddNode(node *model.APIHostNode) *utils.APIHandleError {
|
||||
}
|
||||
}
|
||||
rbnode := node.Clone()
|
||||
rbnode.Status="init"
|
||||
rbnode.CreateTime = time.Now()
|
||||
rbnode.Status="create"
|
||||
|
||||
rbnode.Conditions = make([]model.NodeCondition, 0)
|
||||
if _, err := rbnode.Update(); err != nil {
|
||||
return utils.CreateAPIHandleErrorFromDBError("save node", err)
|
||||
@ -120,9 +123,6 @@ func (n *NodeService) CordonNode(nodeID string, unschedulable bool) *utils.APIHa
|
||||
}
|
||||
//更新节点状态
|
||||
hostNode.Unschedulable = unschedulable
|
||||
if unschedulable {
|
||||
hostNode.Status = "unschedulable"
|
||||
}
|
||||
//k8s节点存在
|
||||
if hostNode.NodeStatus != nil {
|
||||
//true表示drain,不可调度
|
||||
@ -163,6 +163,7 @@ func (n *NodeService) DownNode(nodeID string) (*model.HostNode, *utils.APIHandle
|
||||
if !hostNode.Role.HasRule(model.ComputeNode) || hostNode.NodeStatus == nil {
|
||||
return nil, utils.CreateAPIHandleError(400, fmt.Errorf("node is not k8s node or it not up"))
|
||||
}
|
||||
hostNode.Status="down"
|
||||
err := k8s.DeleteNode(hostNode.ID)
|
||||
if err != nil {
|
||||
return nil, utils.CreateAPIHandleError(500, fmt.Errorf("k8s node down error,%s", err.Error()))
|
||||
|
@ -294,6 +294,7 @@ func (n *NodeCluster) checkNodeInstall(node *model.HostNode) {
|
||||
node.UpdataCondition(initCondition)
|
||||
n.UpdateNode(node)
|
||||
}()
|
||||
node.Status="init"
|
||||
errorCondition := func(reason string, err error) {
|
||||
initCondition.Status = model.ConditionFalse
|
||||
initCondition.LastTransitionTime = time.Now()
|
||||
|
10
vendor/github.com/renstorm/fuzzysearch/.travis.yml
generated
vendored
Normal file
10
vendor/github.com/renstorm/fuzzysearch/.travis.yml
generated
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
language: go
|
||||
|
||||
go:
|
||||
- 1.4
|
||||
- 1.5
|
||||
|
||||
script:
|
||||
make test
|
||||
|
||||
sudo: false
|
21
vendor/github.com/renstorm/fuzzysearch/LICENSE
generated
vendored
Normal file
21
vendor/github.com/renstorm/fuzzysearch/LICENSE
generated
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015 Peter Renström
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
10
vendor/github.com/renstorm/fuzzysearch/Makefile
generated
vendored
Normal file
10
vendor/github.com/renstorm/fuzzysearch/Makefile
generated
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
default: build
|
||||
|
||||
build:
|
||||
go build
|
||||
|
||||
test:
|
||||
go test -v ./...
|
||||
|
||||
benchmark:
|
||||
go test -benchmem -bench=. ./...
|
43
vendor/github.com/renstorm/fuzzysearch/README.md
generated
vendored
Normal file
43
vendor/github.com/renstorm/fuzzysearch/README.md
generated
vendored
Normal file
@ -0,0 +1,43 @@
|
||||
# Fuzzy Search
|
||||
|
||||
[![Build Status](https://img.shields.io/travis/renstrom/fuzzysearch.svg?style=flat-square)](https://travis-ci.org/renstrom/fuzzysearch)
|
||||
[![Godoc](https://img.shields.io/badge/godoc-reference-blue.svg?style=flat-square)](https://godoc.org/github.com/renstrom/fuzzysearch/fuzzy)
|
||||
|
||||
Inspired by _[bevacqua/fuzzysearch][1]_, a fuzzy matching library written in JavaScript. But contains some extras like ranking using _[Levenshtein distance][2]_ (see [`RankMatch()`](https://godoc.org/github.com/renstrom/fuzzysearch/fuzzy#RankMatch)) and finding matches in a list of words (see [`Find()`](https://godoc.org/github.com/renstrom/fuzzysearch/fuzzy#Find)).
|
||||
|
||||
Fuzzy searching allows for flexibly matching a string with partial input, useful for filtering data very quickly based on lightweight user input.
|
||||
|
||||
The current implementation uses the algorithm suggested by Mr. Aleph, a russian compiler engineer working at V8.
|
||||
|
||||
## Usage
|
||||
|
||||
```go
|
||||
fuzzy.Match("twl", "cartwheel") // true
|
||||
fuzzy.Match("cart", "cartwheel") // true
|
||||
fuzzy.Match("cw", "cartwheel") // true
|
||||
fuzzy.Match("ee", "cartwheel") // true
|
||||
fuzzy.Match("art", "cartwheel") // true
|
||||
fuzzy.Match("eeel", "cartwheel") // false
|
||||
fuzzy.Match("dog", "cartwheel") // false
|
||||
|
||||
fuzzy.RankMatch("kitten", "sitting") // 3
|
||||
|
||||
words := []string{"cartwheel", "foobar", "wheel", "baz"}
|
||||
fuzzy.Find("whl", words) // [cartwheel wheel]
|
||||
|
||||
fuzzy.RankFind("whl", words) // [{whl cartwheel 6} {whl wheel 2}]
|
||||
```
|
||||
|
||||
You can sort the result of a `fuzzy.RankFind()` call using the [`sort`](https://golang.org/pkg/sort/) package in the standard library:
|
||||
|
||||
```go
|
||||
matches := fuzzy.RankFind("whl", words) // [{whl cartwheel 6} {whl wheel 2}]
|
||||
sort.Sort(matches) // [{whl wheel 2} {whl cartwheel 6}]
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
MIT
|
||||
|
||||
[1]: https://github.com/bevacqua/fuzzysearch
|
||||
[2]: http://en.wikipedia.org/wiki/Levenshtein_distance
|
167
vendor/github.com/renstorm/fuzzysearch/fuzzy/fuzzy.go
generated
vendored
Normal file
167
vendor/github.com/renstorm/fuzzysearch/fuzzy/fuzzy.go
generated
vendored
Normal file
@ -0,0 +1,167 @@
|
||||
// Fuzzy searching allows for flexibly matching a string with partial input,
|
||||
// useful for filtering data very quickly based on lightweight user input.
|
||||
package fuzzy
|
||||
|
||||
import (
|
||||
"unicode"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
var noop = func(r rune) rune { return r }
|
||||
|
||||
// Match returns true if source matches target using a fuzzy-searching
|
||||
// algorithm. Note that it doesn't implement Levenshtein distance (see
|
||||
// RankMatch instead), but rather a simplified version where there's no
|
||||
// approximation. The method will return true only if each character in the
|
||||
// source can be found in the target and occurs after the preceding matches.
|
||||
func Match(source, target string) bool {
|
||||
return match(source, target, noop)
|
||||
}
|
||||
|
||||
// MatchFold is a case-insensitive version of Match.
|
||||
func MatchFold(source, target string) bool {
|
||||
return match(source, target, unicode.ToLower)
|
||||
}
|
||||
|
||||
func match(source, target string, fn func(rune) rune) bool {
|
||||
lenDiff := len(target) - len(source)
|
||||
|
||||
if lenDiff < 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
if lenDiff == 0 && source == target {
|
||||
return true
|
||||
}
|
||||
|
||||
Outer:
|
||||
for _, r1 := range source {
|
||||
for i, r2 := range target {
|
||||
if fn(r1) == fn(r2) {
|
||||
target = target[i+utf8.RuneLen(r2):]
|
||||
continue Outer
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// Find will return a list of strings in targets that fuzzy matches source.
|
||||
func Find(source string, targets []string) []string {
|
||||
return find(source, targets, noop)
|
||||
}
|
||||
|
||||
// FindFold is a case-insensitive version of Find.
|
||||
func FindFold(source string, targets []string) []string {
|
||||
return find(source, targets, unicode.ToLower)
|
||||
}
|
||||
|
||||
func find(source string, targets []string, fn func(rune) rune) []string {
|
||||
var matches []string
|
||||
|
||||
for _, target := range targets {
|
||||
if match(source, target, fn) {
|
||||
matches = append(matches, target)
|
||||
}
|
||||
}
|
||||
|
||||
return matches
|
||||
}
|
||||
|
||||
// RankMatch is similar to Match except it will measure the Levenshtein
|
||||
// distance between the source and the target and return its result. If there
|
||||
// was no match, it will return -1.
|
||||
// Given the requirements of match, RankMatch only needs to perform a subset of
|
||||
// the Levenshtein calculation, only deletions need be considered, required
|
||||
// additions and substitutions would fail the match test.
|
||||
func RankMatch(source, target string) int {
|
||||
return rank(source, target, noop)
|
||||
}
|
||||
|
||||
// RankMatchFold is a case-insensitive version of RankMatch.
|
||||
func RankMatchFold(source, target string) int {
|
||||
return rank(source, target, unicode.ToLower)
|
||||
}
|
||||
|
||||
func rank(source, target string, fn func(rune) rune) int {
|
||||
lenDiff := len(target) - len(source)
|
||||
|
||||
if lenDiff < 0 {
|
||||
return -1
|
||||
}
|
||||
|
||||
if lenDiff == 0 && source == target {
|
||||
return 0
|
||||
}
|
||||
|
||||
runeDiff := 0
|
||||
|
||||
Outer:
|
||||
for _, r1 := range source {
|
||||
for i, r2 := range target {
|
||||
if fn(r1) == fn(r2) {
|
||||
target = target[i+utf8.RuneLen(r2):]
|
||||
continue Outer
|
||||
} else {
|
||||
runeDiff++
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
// Count up remaining char
|
||||
for len(target) > 0 {
|
||||
target = target[utf8.RuneLen(rune(target[0])):]
|
||||
runeDiff++
|
||||
}
|
||||
|
||||
return runeDiff
|
||||
}
|
||||
|
||||
// RankFind is similar to Find, except it will also rank all matches using
|
||||
// Levenshtein distance.
|
||||
func RankFind(source string, targets []string) Ranks {
|
||||
var r Ranks
|
||||
for _, target := range find(source, targets, noop) {
|
||||
distance := LevenshteinDistance(source, target)
|
||||
r = append(r, Rank{source, target, distance})
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
// RankFindFold is a case-insensitive version of RankFind.
|
||||
func RankFindFold(source string, targets []string) Ranks {
|
||||
var r Ranks
|
||||
for _, target := range find(source, targets, unicode.ToLower) {
|
||||
distance := LevenshteinDistance(source, target)
|
||||
r = append(r, Rank{source, target, distance})
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
type Rank struct {
|
||||
// Source is used as the source for matching.
|
||||
Source string
|
||||
|
||||
// Target is the word matched against.
|
||||
Target string
|
||||
|
||||
// Distance is the Levenshtein distance between Source and Target.
|
||||
Distance int
|
||||
}
|
||||
|
||||
type Ranks []Rank
|
||||
|
||||
func (r Ranks) Len() int {
|
||||
return len(r)
|
||||
}
|
||||
|
||||
func (r Ranks) Swap(i, j int) {
|
||||
r[i], r[j] = r[j], r[i]
|
||||
}
|
||||
|
||||
func (r Ranks) Less(i, j int) bool {
|
||||
return r[i].Distance < r[j].Distance
|
||||
}
|
210
vendor/github.com/renstorm/fuzzysearch/fuzzy/fuzzy_test.go
generated
vendored
Normal file
210
vendor/github.com/renstorm/fuzzysearch/fuzzy/fuzzy_test.go
generated
vendored
Normal file
@ -0,0 +1,210 @@
|
||||
package fuzzy
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
const deBelloGallico = `All Gaul is divided into three parts, one of which the Belgae inhabit,
|
||||
the Aquitani another, those who in their own language are called Celts, in our Gauls, the third.
|
||||
All these differ from each other in language, customs and laws. The river Garonne separates the
|
||||
Gauls from the Aquitani; the Marne and the Seine separate them from the Belgae. Of all these,
|
||||
the Belgae are the bravest, because they are furthest from the civilization and refinement of
|
||||
[our] Province, and merchants least frequently resort to them, and import those things which tend
|
||||
to effeminate the mind; and they are the nearest to the Germans, who dwell beyond the Rhine,
|
||||
with whom they are continually waging war; for which reason the Helvetii also surpass the rest
|
||||
of the Gauls in valor, as they contend with the Germans in almost daily battles, when they either
|
||||
repel them from their own territories, or themselves wage war on their frontiers. One part of
|
||||
these, which it has been said that the Gauls occupy, takes its beginning at the river Rhone;
|
||||
it is bounded by the river Garonne, the ocean, and the territories of the Belgae; it borders,
|
||||
too, on the side of the Sequani and the Helvetii, upon the river Rhine, and stretches toward the
|
||||
north. The Belgae rises from the extreme frontier of Gaul, extend to the lower part of the river
|
||||
Rhine; and look toward the north and the rising sun. Aquitania extends from the river Garonne to
|
||||
the Pyrenaean mountains and to that part of the ocean which is near Spain: it looks between the
|
||||
setting of the sun, and the north star.`
|
||||
|
||||
var fuzzyTests = []struct {
|
||||
source string
|
||||
target string
|
||||
wanted bool
|
||||
rank int
|
||||
}{
|
||||
{"zazz", deBelloGallico + " zazz", true, 1544},
|
||||
{"zazz", "zazz " + deBelloGallico, true, 1544},
|
||||
{"twl", "cartwheel", true, 6},
|
||||
{"cart", "cartwheel", true, 5},
|
||||
{"cw", "cartwheel", true, 7},
|
||||
{"ee", "cartwheel", true, 7},
|
||||
{"art", "cartwheel", true, 6},
|
||||
{"eeel", "cartwheel", false, -1},
|
||||
{"dog", "cartwheel", false, -1},
|
||||
{"ёлка", "ёлочка", true, 2},
|
||||
{"ветер", "ёлочка", false, -1},
|
||||
{"中国", "中华人民共和国", true, 5},
|
||||
{"日本", "中华人民共和国", false, -1},
|
||||
}
|
||||
|
||||
func TestFuzzyMatch(t *testing.T) {
|
||||
for _, val := range fuzzyTests {
|
||||
match := Match(val.source, val.target)
|
||||
if match != val.wanted {
|
||||
t.Errorf("%s in %s expected match to be %t, got %t",
|
||||
val.source, val.target, val.wanted, match)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestFuzzyMatchFold(t *testing.T) {
|
||||
for _, val := range fuzzyTests {
|
||||
match := MatchFold(val.source, strings.ToUpper(val.target))
|
||||
if match != val.wanted {
|
||||
t.Errorf("%s in %s expected match to be %t, got %t",
|
||||
val.source, strings.ToUpper(val.target), val.wanted, match)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestFuzzyFind(t *testing.T) {
|
||||
target := []string{"cartwheel", "foobar", "wheel", "baz"}
|
||||
wanted := []string{"cartwheel", "wheel"}
|
||||
|
||||
matches := Find("whl", target)
|
||||
|
||||
if len(matches) != len(wanted) {
|
||||
t.Errorf("expected %s, got %s", wanted, matches)
|
||||
}
|
||||
|
||||
for i := range wanted {
|
||||
if wanted[i] != matches[i] {
|
||||
t.Errorf("expected %s, got %s", wanted, matches)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestRankMatch(t *testing.T) {
|
||||
for _, val := range fuzzyTests {
|
||||
rank := RankMatch(val.source, val.target)
|
||||
if rank != val.rank {
|
||||
t.Errorf("expected ranking %d, got %d for %s in %s",
|
||||
val.rank, rank, val.source, val.target)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestRankFind(t *testing.T) {
|
||||
target := []string{"cartwheel", "foobar", "wheel", "baz"}
|
||||
wanted := []Rank{
|
||||
{"whl", "cartwheel", 6},
|
||||
{"whl", "wheel", 2},
|
||||
}
|
||||
|
||||
ranks := RankFind("whl", target)
|
||||
|
||||
if len(ranks) != len(wanted) {
|
||||
t.Errorf("expected %+v, got %+v", wanted, ranks)
|
||||
}
|
||||
|
||||
for i := range wanted {
|
||||
if wanted[i] != ranks[i] {
|
||||
t.Errorf("expected %+v, got %+v", wanted, ranks)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSortingRanks(t *testing.T) {
|
||||
rs := Ranks{{"a", "b", 1}, {"a", "cc", 2}, {"a", "a", 0}}
|
||||
wanted := Ranks{rs[2], rs[0], rs[1]}
|
||||
|
||||
sort.Sort(rs)
|
||||
|
||||
for i := range wanted {
|
||||
if wanted[i] != rs[i] {
|
||||
t.Errorf("expected %+v, got %+v", wanted, rs)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkMatch(b *testing.B) {
|
||||
ft := fuzzyTests[2]
|
||||
for i := 0; i < b.N; i++ {
|
||||
Match(ft.source, ft.target)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkMatchBigLate(b *testing.B) {
|
||||
ft := fuzzyTests[0]
|
||||
for i := 0; i < b.N; i++ {
|
||||
Match(ft.source, ft.target)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkMatchBigEarly(b *testing.B) {
|
||||
ft := fuzzyTests[1]
|
||||
for i := 0; i < b.N; i++ {
|
||||
Match(ft.source, ft.target)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkMatchFold(b *testing.B) {
|
||||
ft := fuzzyTests[2]
|
||||
for i := 0; i < b.N; i++ {
|
||||
MatchFold(ft.source, ft.target)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkMatchFoldBigLate(b *testing.B) {
|
||||
ft := fuzzyTests[0]
|
||||
for i := 0; i < b.N; i++ {
|
||||
MatchFold(ft.source, ft.target)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkMatchFoldBigEarly(b *testing.B) {
|
||||
ft := fuzzyTests[1]
|
||||
for i := 0; i < b.N; i++ {
|
||||
MatchFold(ft.source, ft.target)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkRankMatch(b *testing.B) {
|
||||
ft := fuzzyTests[2]
|
||||
for i := 0; i < b.N; i++ {
|
||||
RankMatch(ft.source, ft.target)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkRankMatchBigLate(b *testing.B) {
|
||||
ft := fuzzyTests[0]
|
||||
for i := 0; i < b.N; i++ {
|
||||
RankMatch(ft.source, ft.target)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkRankMatchBigEarly(b *testing.B) {
|
||||
ft := fuzzyTests[1]
|
||||
for i := 0; i < b.N; i++ {
|
||||
RankMatch(ft.source, ft.target)
|
||||
}
|
||||
}
|
||||
|
||||
func ExampleMatch() {
|
||||
fmt.Print(Match("twl", "cartwheel"))
|
||||
// Output: true
|
||||
}
|
||||
|
||||
func ExampleFind() {
|
||||
fmt.Print(Find("whl", []string{"cartwheel", "foobar", "wheel", "baz"}))
|
||||
// Output: [cartwheel wheel]
|
||||
}
|
||||
|
||||
func ExampleRankMatch() {
|
||||
fmt.Print(RankMatch("twl", "cartwheel"))
|
||||
// Output: 6
|
||||
}
|
||||
|
||||
func ExampleRankFind() {
|
||||
fmt.Printf("%+v", RankFind("whl", []string{"cartwheel", "foobar", "wheel", "baz"}))
|
||||
// Output: [{Source:whl Target:cartwheel Distance:6} {Source:whl Target:wheel Distance:2}]
|
||||
}
|
43
vendor/github.com/renstorm/fuzzysearch/fuzzy/levenshtein.go
generated
vendored
Normal file
43
vendor/github.com/renstorm/fuzzysearch/fuzzy/levenshtein.go
generated
vendored
Normal file
@ -0,0 +1,43 @@
|
||||
package fuzzy
|
||||
|
||||
// LevenshteinDistance measures the difference between two strings.
|
||||
// The Levenshtein distance between two words is the minimum number of
|
||||
// single-character edits (i.e. insertions, deletions or substitutions)
|
||||
// required to change one word into the other.
|
||||
//
|
||||
// This implemention is optimized to use O(min(m,n)) space and is based on the
|
||||
// optimized C version found here:
|
||||
// http://en.wikibooks.org/wiki/Algorithm_implementation/Strings/Levenshtein_distance#C
|
||||
func LevenshteinDistance(s, t string) int {
|
||||
r1, r2 := []rune(s), []rune(t)
|
||||
column := make([]int, len(r1)+1)
|
||||
|
||||
for y := 1; y <= len(r1); y++ {
|
||||
column[y] = y
|
||||
}
|
||||
|
||||
for x := 1; x <= len(r2); x++ {
|
||||
column[0] = x
|
||||
|
||||
for y, lastDiag := 1, x-1; y <= len(r1); y++ {
|
||||
oldDiag := column[y]
|
||||
cost := 0
|
||||
if r1[y-1] != r2[x-1] {
|
||||
cost = 1
|
||||
}
|
||||
column[y] = min(column[y]+1, column[y-1]+1, lastDiag+cost)
|
||||
lastDiag = oldDiag
|
||||
}
|
||||
}
|
||||
|
||||
return column[len(r1)]
|
||||
}
|
||||
|
||||
func min(a, b, c int) int {
|
||||
if a < b && a < c {
|
||||
return a
|
||||
} else if b < c {
|
||||
return b
|
||||
}
|
||||
return c
|
||||
}
|
55
vendor/github.com/renstorm/fuzzysearch/fuzzy/levenshtein_test.go
generated
vendored
Normal file
55
vendor/github.com/renstorm/fuzzysearch/fuzzy/levenshtein_test.go
generated
vendored
Normal file
@ -0,0 +1,55 @@
|
||||
package fuzzy
|
||||
|
||||
import "testing"
|
||||
|
||||
var levenshteinDistanceTests = []struct {
|
||||
s, t string
|
||||
wanted int
|
||||
}{
|
||||
{"zazz", deBelloGallico + " zazz", 1544},
|
||||
{"zazz", "zazz " + deBelloGallico, 1544},
|
||||
{"a", "a", 0},
|
||||
{"ab", "ab", 0},
|
||||
{"ab", "aa", 1},
|
||||
{"ab", "aa", 1},
|
||||
{"ab", "aaa", 2},
|
||||
{"bbb", "a", 3},
|
||||
{"kitten", "sitting", 3},
|
||||
{"ёлка", "ёлочка", 2},
|
||||
{"ветер", "ёлочка", 6},
|
||||
{"中国", "中华人民共和国", 5},
|
||||
{"日本", "中华人民共和国", 7},
|
||||
}
|
||||
|
||||
func TestLevenshtein(t *testing.T) {
|
||||
for _, test := range levenshteinDistanceTests {
|
||||
distance := LevenshteinDistance(test.s, test.t)
|
||||
if distance != test.wanted {
|
||||
t.Errorf("got distance %d, expected %d for %s in %s",
|
||||
distance, test.wanted, test.s, test.t)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkLevenshteinDistance(b *testing.B) {
|
||||
ldt := levenshteinDistanceTests[2]
|
||||
ldt2 := levenshteinDistanceTests[5]
|
||||
for i := 0; i < b.N; i++ {
|
||||
LevenshteinDistance(ldt.s, ldt.t)
|
||||
LevenshteinDistance(ldt2.s, ldt2.t)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkLevenshteinDistanceBigLate(b *testing.B) {
|
||||
ldt := levenshteinDistanceTests[0]
|
||||
for i := 0; i < b.N; i++ {
|
||||
LevenshteinDistance(ldt.s, ldt.t)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkLevenshteinDistanceBigEarly(b *testing.B) {
|
||||
ldt := levenshteinDistanceTests[1]
|
||||
for i := 0; i < b.N; i++ {
|
||||
LevenshteinDistance(ldt.s, ldt.t)
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user