refactor the code of resource list function

This commit is contained in:
richardxz
2018-09-17 10:24:01 +08:00
parent f7e607a14c
commit 4bd18b072c
25 changed files with 1564 additions and 306 deletions

2
Gopkg.lock generated
View File

@@ -650,6 +650,6 @@
[solve-meta] [solve-meta]
analyzer-name = "dep" analyzer-name = "dep"
analyzer-version = 1 analyzer-version = 1
inputs-digest = "9f1ac4fe878dadee802b8971f67ba69171326c81e2c379247015003f2e0ba134" inputs-digest = "d92e4ea931c670e5ebb04661788db5386ee647b8b6bac4ec6b519a1544b2c400"
solver-name = "gps-cdcl" solver-name = "gps-cdcl"
solver-version = 1 solver-version = 1

View File

@@ -23,6 +23,9 @@ import (
"github.com/emicklei/go-restful-openapi" "github.com/emicklei/go-restful-openapi"
"fmt"
"strings"
"kubesphere.io/kubesphere/pkg/constants" "kubesphere.io/kubesphere/pkg/constants"
"kubesphere.io/kubesphere/pkg/models" "kubesphere.io/kubesphere/pkg/models"
) )
@@ -31,15 +34,33 @@ func Register(ws *restful.WebService, subPath string) {
tags := []string{"resources"} tags := []string{"resources"}
ws.Route(ws.GET(subPath+"/{resource}").To(handleResource).Produces(restful.MIME_JSON).Metadata(restfulspec.KeyOpenAPITags, tags).Doc("Get resource" + ws.Route(ws.GET(subPath+"/{resource}").To(listResource).Produces(restful.MIME_JSON).Metadata(restfulspec.KeyOpenAPITags, tags).Doc("Get resource" +
" list").Param(ws.PathParameter("resource", "resource name").DataType( " list").Param(ws.PathParameter("resource", "resource name").DataType("string")).Param(ws.QueryParameter("conditions",
"string")).Param(ws.QueryParameter("conditions", "search "+ "search conditions").DataType("string")).Param(ws.QueryParameter("reverse",
"conditions").DataType("string")).Param(ws.QueryParameter("paging", "support reverse ordering").DataType("bool").DefaultValue("false")).Param(ws.QueryParameter("order",
"the field for sorting").DataType("string")).Param(ws.QueryParameter("paging",
"support paging function").DataType("string")).Writes(models.ResourceList{})) "support paging function").DataType("string")).Writes(models.ResourceList{}))
} }
func handleResource(req *restful.Request, resp *restful.Response) { func isInvalid(str string) bool {
invalidList := []string{"exec", "insert", "select", "delete", "update", "count", "*", "%", "truncate", "drop"}
str = strings.Replace(str, "=", " ", -1)
str = strings.Replace(str, ",", " ", -1)
str = strings.Replace(str, "~", " ", -1)
items := strings.Split(str, " ")
for _, invalid := range invalidList {
for _, item := range items {
if item == invalid || strings.ToLower(item) == invalid {
return true
}
}
}
return false
}
func listResource(req *restful.Request, resp *restful.Response) {
resource := req.PathParameter("resource") resource := req.PathParameter("resource")
if resource == "applications" { if resource == "applications" {
@@ -48,7 +69,23 @@ func handleResource(req *restful.Request, resp *restful.Response) {
} }
conditions := req.QueryParameter("conditions") conditions := req.QueryParameter("conditions")
paging := req.QueryParameter("paging") paging := req.QueryParameter("paging")
res, err := models.ListResource(resource, conditions, paging) orderField := req.QueryParameter("order")
reverse := req.QueryParameter("reverse")
if len(orderField) > 0 {
if reverse == "true" {
orderField = fmt.Sprintf("%s %s", orderField, "desc")
} else {
orderField = fmt.Sprintf("%s %s", orderField, "asc")
}
}
if isInvalid(conditions) || isInvalid(paging) || isInvalid(orderField) {
resp.WriteHeaderAndEntity(http.StatusBadRequest, constants.MessageResponse{Message: "invalid input"})
return
}
res, err := models.ListResource(resource, conditions, paging, orderField)
if err != nil { if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()}) resp.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()})
return return
@@ -58,7 +95,6 @@ func handleResource(req *restful.Request, resp *restful.Response) {
} }
func handleApplication(req *restful.Request, resp *restful.Response) { func handleApplication(req *restful.Request, resp *restful.Response) {
//searchWord := req.QueryParameter("search-word")
paging := req.QueryParameter("paging") paging := req.QueryParameter("paging")
clusterId := req.QueryParameter("cluster_id") clusterId := req.QueryParameter("cluster_id")
runtimeId := req.QueryParameter("runtime_id") runtimeId := req.QueryParameter("runtime_id")

View File

@@ -240,7 +240,7 @@ func (ctl *ApplicationCtl) GetWorkLoads(namespace string, clusterRoles []cluster
if strings.HasSuffix(workLoadName, deploySurffix) { if strings.HasSuffix(workLoadName, deploySurffix) {
name := strings.Split(workLoadName, deploySurffix)[0] name := strings.Split(workLoadName, deploySurffix)[0]
ctl := ResourceControllers.Controllers[Deployments] ctl := ResourceControllers.Controllers[Deployments]
_, items, _ := ctl.ListWithConditions(fmt.Sprintf("namespace='%s' and name = '%s'", namespace, name), nil) _, items, _ := ctl.ListWithConditions(fmt.Sprintf("namespace='%s' and name = '%s'", namespace, name), nil, "")
works.Deployments = append(works.Deployments, items.([]Deployment)...) works.Deployments = append(works.Deployments, items.([]Deployment)...)
continue continue
} }
@@ -248,7 +248,7 @@ func (ctl *ApplicationCtl) GetWorkLoads(namespace string, clusterRoles []cluster
if strings.HasSuffix(workLoadName, daemonSurffix) { if strings.HasSuffix(workLoadName, daemonSurffix) {
name := strings.Split(workLoadName, daemonSurffix)[0] name := strings.Split(workLoadName, daemonSurffix)[0]
ctl := ResourceControllers.Controllers[Daemonsets] ctl := ResourceControllers.Controllers[Daemonsets]
_, items, _ := ctl.ListWithConditions(fmt.Sprintf("namespace='%s' and name = '%s'", namespace, name), nil) _, items, _ := ctl.ListWithConditions(fmt.Sprintf("namespace='%s' and name = '%s'", namespace, name), nil, "")
works.Daemonsets = append(works.Daemonsets, items.([]Daemonset)...) works.Daemonsets = append(works.Daemonsets, items.([]Daemonset)...)
continue continue
} }
@@ -256,7 +256,7 @@ func (ctl *ApplicationCtl) GetWorkLoads(namespace string, clusterRoles []cluster
if strings.HasSuffix(workLoadName, stateSurffix) { if strings.HasSuffix(workLoadName, stateSurffix) {
name := strings.Split(workLoadName, stateSurffix)[0] name := strings.Split(workLoadName, stateSurffix)[0]
ctl := ResourceControllers.Controllers[Statefulsets] ctl := ResourceControllers.Controllers[Statefulsets]
_, items, _ := ctl.ListWithConditions(fmt.Sprintf("namespace='%s' and name = '%s'", namespace, name), nil) _, items, _ := ctl.ListWithConditions(fmt.Sprintf("namespace='%s' and name = '%s'", namespace, name), nil, "")
works.Statefulsets = append(works.Statefulsets, items.([]Statefulset)...) works.Statefulsets = append(works.Statefulsets, items.([]Statefulset)...)
continue continue
} }
@@ -265,16 +265,6 @@ func (ctl *ApplicationCtl) GetWorkLoads(namespace string, clusterRoles []cluster
return &works return &works
} }
//
//func (ctl *ApplicationCtl) getCreator(desc string) string {
// var dc description
// err := json.Unmarshal([]byte(desc), &dc)
// if err != nil {
// return unknown
// }
// return dc.Creator
//}
func (ctl *ApplicationCtl) getLabels(namespace string, workloads *workLoads) *[]map[string]string { func (ctl *ApplicationCtl) getLabels(namespace string, workloads *workLoads) *[]map[string]string {
k8sClient := client.NewK8sClient() k8sClient := client.NewK8sClient()
@@ -349,7 +339,7 @@ func (ctl *ApplicationCtl) getIng(namespace string, services *[]Service) *[]ing
ingCtl := ResourceControllers.Controllers[Ingresses] ingCtl := ResourceControllers.Controllers[Ingresses]
var ings []ing var ings []ing
for _, svc := range *services { for _, svc := range *services {
_, items, err := ingCtl.ListWithConditions(fmt.Sprintf("namespace = '%s' and rules like '%%%s%%' ", namespace, svc.Name), nil) _, items, err := ingCtl.ListWithConditions(fmt.Sprintf("namespace = '%s' and rules like '%%%s%%' ", namespace, svc.Name), nil, "")
if err != nil { if err != nil {
glog.Error(err) glog.Error(err)
return nil return nil

View File

@@ -30,6 +30,11 @@ import (
const systemPrefix = "system:" const systemPrefix = "system:"
func (ctl *ClusterRoleCtl) generateObject(item v1.ClusterRole) *ClusterRole { func (ctl *ClusterRoleCtl) generateObject(item v1.ClusterRole) *ClusterRole {
var displayName string
if item.Annotations != nil && len(item.Annotations[DisplayName]) > 0 {
displayName = item.Annotations[DisplayName]
}
name := item.Name name := item.Name
if strings.HasPrefix(name, systemPrefix) { if strings.HasPrefix(name, systemPrefix) {
return nil return nil
@@ -40,7 +45,7 @@ func (ctl *ClusterRoleCtl) generateObject(item v1.ClusterRole) *ClusterRole {
createTime = time.Now() createTime = time.Now()
} }
object := &ClusterRole{Name: name, CreateTime: createTime, Annotation: Annotation{item.Annotations}} object := &ClusterRole{Name: name, CreateTime: createTime, Annotation: MapString{item.Annotations}, DisplayName: displayName}
return object return object
} }
@@ -136,15 +141,23 @@ func (ctl *ClusterRoleCtl) CountWithConditions(conditions string) int {
return countWithConditions(ctl.DB, conditions, &object) return countWithConditions(ctl.DB, conditions, &object)
} }
func (ctl *ClusterRoleCtl) ListWithConditions(conditions string, paging *Paging) (int, interface{}, error) { func (ctl *ClusterRoleCtl) ListWithConditions(conditions string, paging *Paging, order string) (int, interface{}, error) {
var object ClusterRole var object ClusterRole
var list []ClusterRole var list []ClusterRole
var total int var total int
order := "createTime desc" if len(order) == 0 {
order = "createTime desc"
}
db := ctl.DB db := ctl.DB
listWithConditions(db, &total, &object, &list, conditions, paging, order) listWithConditions(db, &total, &object, &list, conditions, paging, order)
return total, list, nil return total, list, nil
} }
func (ctl *ClusterRoleCtl) Lister() interface{} {
return ctl.lister
}

View File

@@ -133,7 +133,7 @@ func checkAndResync(ctl Controller, stopChan chan struct{}) {
func listAndWatch(ctl Controller) { func listAndWatch(ctl Controller) {
defer handleCrash(ctl) defer handleCrash(ctl)
defer ctl.CloseDB()
stopChan := make(chan struct{}) stopChan := make(chan struct{})
go ctl.sync(stopChan) go ctl.sync(stopChan)

View File

@@ -0,0 +1,64 @@
/*
Copyright 2018 The KubeSphere Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package controllers
import (
"time"
"k8s.io/client-go/informers"
)
func (ctl *ControllerRevisionCtl) Name() string {
return ctl.CommonAttribute.Name
}
func (ctl *ControllerRevisionCtl) sync(stopChan chan struct{}) {
ctl.initListerAndInformer()
ctl.informer.Run(stopChan)
}
func (ctl *ControllerRevisionCtl) total() int {
return 0
}
func (ctl *ControllerRevisionCtl) initListerAndInformer() {
informerFactory := informers.NewSharedInformerFactory(ctl.K8sClient, time.Second*resyncCircle)
ctl.lister = informerFactory.Apps().V1().ControllerRevisions().Lister()
informer := informerFactory.Apps().V1().ControllerRevisions().Informer()
ctl.informer = informer
}
func (ctl *ControllerRevisionCtl) CountWithConditions(conditions string) int {
return 0
}
func (ctl *ControllerRevisionCtl) ListWithConditions(conditions string, paging *Paging, order string) (int, interface{}, error) {
return 0, nil, nil
}
func (ctl *ControllerRevisionCtl) Lister() interface{} {
return ctl.lister
}

View File

@@ -0,0 +1,158 @@
/*
Copyright 2018 The KubeSphere Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package controllers
import (
"time"
"github.com/golang/glog"
"k8s.io/api/batch/v1beta1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/client-go/informers"
"k8s.io/client-go/tools/cache"
)
func (ctl *CronJobCtl) generateObject(item v1beta1.CronJob) *CronJob {
var status, displayName string
var lastScheduleTime *time.Time
if item.Annotations != nil && len(item.Annotations[DisplayName]) > 0 {
displayName = item.Annotations[DisplayName]
}
name := item.Name
namespace := item.Namespace
status = Running
if *item.Spec.Suspend {
status = Pause
}
schedule := item.Spec.Schedule
if item.Status.LastScheduleTime != nil {
lastScheduleTime = &item.Status.LastScheduleTime.Time
}
active := len(item.Status.Active)
object := &CronJob{
Namespace: namespace,
Name: name,
DisplayName: displayName,
LastScheduleTime: lastScheduleTime,
Active: active,
Schedule: schedule,
Status: status,
Annotation: MapString{item.Annotations},
Labels: MapString{item.ObjectMeta.Labels},
}
return object
}
func (ctl *CronJobCtl) Name() string {
return ctl.CommonAttribute.Name
}
func (ctl *CronJobCtl) sync(stopChan chan struct{}) {
db := ctl.DB
if db.HasTable(&CronJob{}) {
db.DropTable(&CronJob{})
}
db = db.CreateTable(&CronJob{})
ctl.initListerAndInformer()
list, err := ctl.lister.List(labels.Everything())
if err != nil {
glog.Error(err)
return
}
for _, item := range list {
obj := ctl.generateObject(*item)
db.Create(obj)
}
ctl.informer.Run(stopChan)
}
func (ctl *CronJobCtl) total() int {
list, err := ctl.lister.List(labels.Everything())
if err != nil {
glog.Errorf("count %s falied, reason:%s", err, ctl.Name())
return 0
}
return len(list)
}
func (ctl *CronJobCtl) initListerAndInformer() {
db := ctl.DB
informerFactory := informers.NewSharedInformerFactory(ctl.K8sClient, time.Second*resyncCircle)
ctl.lister = informerFactory.Batch().V1beta1().CronJobs().Lister()
informer := informerFactory.Batch().V1beta1().CronJobs().Informer()
informer.AddEventHandler(cache.ResourceEventHandlerFuncs{
AddFunc: func(obj interface{}) {
object := obj.(*v1beta1.CronJob)
mysqlObject := ctl.generateObject(*object)
db.Create(mysqlObject)
},
UpdateFunc: func(old, new interface{}) {
object := new.(*v1beta1.CronJob)
mysqlObject := ctl.generateObject(*object)
db.Save(mysqlObject)
},
DeleteFunc: func(obj interface{}) {
var item CronJob
object := obj.(*v1beta1.CronJob)
db.Where("name=? And namespace=?", object.Name, object.Namespace).Find(&item)
db.Delete(item)
},
})
ctl.informer = informer
}
func (ctl *CronJobCtl) CountWithConditions(conditions string) int {
var object CronJob
return countWithConditions(ctl.DB, conditions, &object)
}
func (ctl *CronJobCtl) ListWithConditions(conditions string, paging *Paging, order string) (int, interface{}, error) {
var list []CronJob
var object CronJob
var total int
if len(order) == 0 {
order = "lastScheduleTime desc"
}
listWithConditions(ctl.DB, &total, &object, &list, conditions, paging, order)
return total, list, nil
}
func (ctl *CronJobCtl) Lister() interface{} {
return ctl.lister
}

View File

@@ -28,8 +28,11 @@ import (
) )
func (ctl *DaemonsetCtl) generateObject(item v1.DaemonSet) *Daemonset { func (ctl *DaemonsetCtl) generateObject(item v1.DaemonSet) *Daemonset {
var app string var app, status, displayName string
var status string
if item.Annotations != nil && len(item.Annotations[DisplayName]) > 0 {
displayName = item.Annotations[DisplayName]
}
name := item.Name name := item.Name
namespace := item.Namespace namespace := item.Namespace
availablePodNum := item.Status.NumberAvailable availablePodNum := item.Status.NumberAvailable
@@ -55,8 +58,19 @@ func (ctl *DaemonsetCtl) generateObject(item v1.DaemonSet) *Daemonset {
status = Updating status = Updating
} }
object := &Daemonset{Namespace: namespace, Name: name, Available: availablePodNum, Desire: desirePodNum, object := &Daemonset{
App: app, CreateTime: createTime, Status: status, NodeSelector: string(nodeSelectorStr), Annotation: Annotation{item.Annotations}} Namespace: namespace,
Name: name,
DisplayName: displayName,
Available: availablePodNum,
Desire: desirePodNum,
App: app,
CreateTime: createTime,
Status: status,
NodeSelector: string(nodeSelectorStr),
Annotation: MapString{item.Annotations},
Labels: MapString{item.Spec.Selector.MatchLabels},
}
return object return object
} }
@@ -135,25 +149,21 @@ func (ctl *DaemonsetCtl) CountWithConditions(conditions string) int {
return countWithConditions(ctl.DB, conditions, &object) return countWithConditions(ctl.DB, conditions, &object)
} }
func (ctl *DaemonsetCtl) ListWithConditions(conditions string, paging *Paging) (int, interface{}, error) { func (ctl *DaemonsetCtl) ListWithConditions(conditions string, paging *Paging, order string) (int, interface{}, error) {
var list []Daemonset var list []Daemonset
var object Daemonset var object Daemonset
var total int var total int
order := "createTime desc" if len(order) == 0 {
order = "createTime desc"
}
listWithConditions(ctl.DB, &total, &object, &list, conditions, paging, order) listWithConditions(ctl.DB, &total, &object, &list, conditions, paging, order)
return total, list, nil return total, list, nil
} }
//func (ctl *DaemonsetCtl) Count(namespace string) int { func (ctl *DaemonsetCtl) Lister() interface{} {
// var count int
// db := ctl.DB return ctl.lister
// if len(namespace) == 0 { }
// db.Model(&Daemonset{}).Count(&count)
// } else {
// db.Model(&Daemonset{}).Where("namespace = ?", namespace).Count(&count)
// }
// return count
//}

View File

@@ -27,9 +27,13 @@ import (
) )
func (ctl *DeploymentCtl) generateObject(item v1.Deployment) *Deployment { func (ctl *DeploymentCtl) generateObject(item v1.Deployment) *Deployment {
var app string var app, status, displayName string
var status string
var updateTime time.Time var updateTime time.Time
if item.Annotations != nil && len(item.Annotations[DisplayName]) > 0 {
displayName = item.Annotations[DisplayName]
}
name := item.Name name := item.Name
namespace := item.Namespace namespace := item.Namespace
availablePodNum := item.Status.AvailableReplicas availablePodNum := item.Status.AvailableReplicas
@@ -41,9 +45,13 @@ func (ctl *DeploymentCtl) generateObject(item v1.Deployment) *Deployment {
app = release + "/" + chart app = release + "/" + chart
} }
for _, conditon := range item.Status.Conditions { for _, condition := range item.Status.Conditions {
if conditon.Type == "Available" { if updateTime.IsZero() {
updateTime = conditon.LastUpdateTime.Time updateTime = condition.LastUpdateTime.Time
} else {
if updateTime.Before(condition.LastUpdateTime.Time) {
updateTime = condition.LastUpdateTime.Time
}
} }
} }
if updateTime.IsZero() { if updateTime.IsZero() {
@@ -60,8 +68,18 @@ func (ctl *DeploymentCtl) generateObject(item v1.Deployment) *Deployment {
} }
} }
return &Deployment{Namespace: namespace, Name: name, Available: availablePodNum, Desire: desirePodNum, return &Deployment{
App: app, UpdateTime: updateTime, Status: status, Annotation: Annotation{item.Annotations}} Namespace: namespace,
Name: name,
Available: availablePodNum,
Desire: desirePodNum,
App: app,
UpdateTime: updateTime,
Status: status,
Annotation: MapString{item.Annotations},
Labels: MapString{item.Spec.Selector.MatchLabels},
DisplayName: displayName,
}
} }
func (ctl *DeploymentCtl) Name() string { func (ctl *DeploymentCtl) Name() string {
@@ -138,14 +156,21 @@ func (ctl *DeploymentCtl) CountWithConditions(conditions string) int {
return countWithConditions(ctl.DB, conditions, &object) return countWithConditions(ctl.DB, conditions, &object)
} }
func (ctl *DeploymentCtl) ListWithConditions(conditions string, paging *Paging) (int, interface{}, error) { func (ctl *DeploymentCtl) ListWithConditions(conditions string, paging *Paging, order string) (int, interface{}, error) {
var list []Deployment var list []Deployment
var object Deployment var object Deployment
var total int var total int
order := "updateTime desc" if len(order) == 0 {
order = "updateTime desc"
}
listWithConditions(ctl.DB, &total, &object, &list, conditions, paging, order) listWithConditions(ctl.DB, &total, &object, &list, conditions, paging, order)
return total, list, nil return total, list, nil
} }
func (ctl *DeploymentCtl) Lister() interface{} {
return ctl.lister
}

View File

@@ -30,9 +30,16 @@ import (
) )
func (ctl *IngressCtl) generateObject(item v1beta1.Ingress) *Ingress { func (ctl *IngressCtl) generateObject(item v1beta1.Ingress) *Ingress {
var ip, tls, displayName string
name := item.Name name := item.Name
namespace := item.Namespace namespace := item.Namespace
var ip, tls string
if item.Annotations != nil && len(item.Annotations[DisplayName]) > 0 {
displayName = item.Annotations[DisplayName]
}
createTime := item.CreationTimestamp.Time createTime := item.CreationTimestamp.Time
if createTime.IsZero() { if createTime.IsZero() {
createTime = time.Now() createTime = time.Now()
@@ -63,7 +70,17 @@ func (ctl *IngressCtl) generateObject(item v1beta1.Ingress) *Ingress {
ruleStr, _ := json.Marshal(ingRules) ruleStr, _ := json.Marshal(ingRules)
object := &Ingress{Namespace: namespace, Name: name, TlsTermination: tls, Ip: ip, CreateTime: createTime, Annotation: Annotation{item.Annotations}, Rules: string(ruleStr)} object := &Ingress{
Namespace: namespace,
Name: name,
DisplayName: displayName,
TlsTermination: tls,
Ip: ip,
CreateTime: createTime,
Annotation: MapString{item.Annotations},
Rules: string(ruleStr),
Labels: MapString{item.Labels},
}
return object return object
} }
@@ -143,25 +160,21 @@ func (ctl *IngressCtl) CountWithConditions(conditions string) int {
return countWithConditions(ctl.DB, conditions, &object) return countWithConditions(ctl.DB, conditions, &object)
} }
func (ctl *IngressCtl) ListWithConditions(conditions string, paging *Paging) (int, interface{}, error) { func (ctl *IngressCtl) ListWithConditions(conditions string, paging *Paging, order string) (int, interface{}, error) {
var list []Ingress var list []Ingress
var object Ingress var object Ingress
var total int var total int
order := "createTime desc" if len(order) == 0 {
order = "createTime desc"
}
listWithConditions(ctl.DB, &total, &object, &list, conditions, paging, order) listWithConditions(ctl.DB, &total, &object, &list, conditions, paging, order)
return total, list, nil return total, list, nil
} }
//func (ctl *IngressCtl) Count(namespace string) int { func (ctl *IngressCtl) Lister() interface{} {
// var count int
// db := ctl.DB return ctl.lister
// if len(namespace) == 0 { }
// db.Model(&Ingress{}).Count(&count)
// } else {
// db.Model(&Ingress{}).Where("namespace = ?", namespace).Count(&count)
// }
// return count
//}

View File

@@ -0,0 +1,276 @@
/*
Copyright 2018 The KubeSphere Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package controllers
import (
"encoding/json"
"fmt"
"time"
"github.com/golang/glog"
"k8s.io/api/batch/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/client-go/informers"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/tools/cache"
"kubesphere.io/kubesphere/pkg/client"
)
var k8sClient *kubernetes.Clientset
func (ctl *JobCtl) generateObject(item v1.Job) *Job {
var status, displayName string
if item.Annotations != nil && len(item.Annotations[DisplayName]) > 0 {
displayName = item.Annotations[DisplayName]
}
name := item.Name
namespace := item.Namespace
succeedPodNum := item.Status.Succeeded
desirePodNum := *item.Spec.Completions
createTime := item.CreationTimestamp.Time
updteTime := createTime
for _, condition := range item.Status.Conditions {
if condition.Type == "Failed" && condition.Status == "True" {
status = Failed
}
if condition.Type == "Complete" && condition.Status == "True" {
status = Completed
}
if updteTime.Before(condition.LastProbeTime.Time) {
updteTime = condition.LastProbeTime.Time
}
if updteTime.Before(condition.LastTransitionTime.Time) {
updteTime = condition.LastTransitionTime.Time
}
}
if desirePodNum > succeedPodNum && len(status) == 0 {
status = Running
}
object := &Job{
Namespace: namespace,
Name: name,
DisplayName: displayName,
Desire: desirePodNum,
Completed: succeedPodNum,
UpdateTime: updteTime,
CreateTime: createTime,
Status: status,
Annotation: MapString{item.Annotations},
Labels: MapString{item.Labels},
}
return object
}
func (ctl *JobCtl) Name() string {
return ctl.CommonAttribute.Name
}
func (ctl *JobCtl) sync(stopChan chan struct{}) {
db := ctl.DB
if db.HasTable(&Job{}) {
db.DropTable(&Job{})
}
db = db.CreateTable(&Job{})
ctl.initListerAndInformer()
list, err := ctl.lister.List(labels.Everything())
if err != nil {
glog.Error(err)
return
}
for _, item := range list {
obj := ctl.generateObject(*item)
db.Create(obj)
}
ctl.informer.Run(stopChan)
}
func (ctl *JobCtl) total() int {
list, err := ctl.lister.List(labels.Everything())
if err != nil {
glog.Errorf("count %s falied, reason:%s", err, ctl.Name())
return 0
}
return len(list)
}
func (ctl *JobCtl) initListerAndInformer() {
db := ctl.DB
informerFactory := informers.NewSharedInformerFactory(ctl.K8sClient, time.Second*resyncCircle)
ctl.lister = informerFactory.Batch().V1().Jobs().Lister()
informer := informerFactory.Batch().V1().Jobs().Informer()
informer.AddEventHandler(cache.ResourceEventHandlerFuncs{
AddFunc: func(obj interface{}) {
object := obj.(*v1.Job)
mysqlObject := ctl.generateObject(*object)
db.Create(mysqlObject)
},
UpdateFunc: func(old, new interface{}) {
object := new.(*v1.Job)
mysqlObject := ctl.generateObject(*object)
db.Save(mysqlObject)
},
DeleteFunc: func(obj interface{}) {
var item Job
object := obj.(*v1.Job)
db.Where("name=? And namespace=?", object.Name, object.Namespace).Find(&item)
db.Delete(item)
},
})
ctl.informer = informer
}
func (ctl *JobCtl) CountWithConditions(conditions string) int {
var object Job
return countWithConditions(ctl.DB, conditions, &object)
}
func (ctl *JobCtl) ListWithConditions(conditions string, paging *Paging, order string) (int, interface{}, error) {
var list []Job
var object Job
var total int
if len(order) == 0 {
order = "updateTime desc"
}
listWithConditions(ctl.DB, &total, &object, &list, conditions, paging, order)
return total, list, nil
}
func (ctl *JobCtl) Lister() interface{} {
return ctl.lister
}
func getRevisions(job v1.Job) (JobRevisions, error) {
revisions := make(JobRevisions)
if _, exist := job.Annotations["revisions"]; exist {
revisionsStr := job.Annotations["revisions"]
err := json.Unmarshal([]byte(revisionsStr), &revisions)
if err != nil {
glog.Errorf("failed to rerun job %s, reason: %s", err, err)
return nil, fmt.Errorf("failed to rerun job %s", job.Name)
}
}
return revisions, nil
}
func getStatus(item *v1.Job) JobStatus {
var status JobStatus
for _, condition := range item.Status.Conditions {
if condition.Type == "Failed" && condition.Status == "True" {
status.Status = Failed
status.Reasons = append(status.Reasons, condition.Reason)
status.Messages = append(status.Messages, condition.Message)
}
if condition.Type == "Complete" && condition.Status == "True" {
status.Status = Completed
}
}
if len(status.Status) == 0 {
status.Status = Unfinished
}
status.DesirePodNum = *item.Spec.Completions
status.Succeed = item.Status.Succeeded
status.Failed = item.Status.Failed
status.StartTime = item.Status.StartTime.Time
if item.Status.CompletionTime != nil {
status.CompletionTime = item.Status.CompletionTime.Time
}
return status
}
func deleteJob(namespace, job string) error {
deletePolicy := metav1.DeletePropagationBackground
err := k8sClient.BatchV1().Jobs(namespace).Delete(job, &metav1.DeleteOptions{PropagationPolicy: &deletePolicy})
return err
}
func JobReRun(namespace, jobName string) (string, error) {
k8sClient = client.NewK8sClient()
job, err := k8sClient.BatchV1().Jobs(namespace).Get(jobName, metav1.GetOptions{})
if err != nil {
return "", err
}
newJob := *job
newJob.ResourceVersion = ""
newJob.Status = v1.JobStatus{}
newJob.ObjectMeta.UID = ""
delete(newJob.Spec.Selector.MatchLabels, "controller-uid")
delete(newJob.Spec.Template.ObjectMeta.Labels, "controller-uid")
revisions, err := getRevisions(*job)
if err != nil {
return "", err
}
index := len(revisions) + 1
value := getStatus(job)
revisions[index] = value
revisionsByte, err := json.Marshal(revisions)
if err != nil {
glog.Errorf("failed to rerun job %s, reason: %s", err, err)
return "", fmt.Errorf("failed to rerun job %s", jobName)
}
newJob.Annotations["revisions"] = string(revisionsByte)
err = deleteJob(job.Namespace, job.Name)
if err != nil {
glog.Errorf("failed to rerun job %s, reason: %s", err, err)
return "", fmt.Errorf("failed to rerun job %s", jobName)
}
_, err = k8sClient.BatchV1().Jobs(namespace).Create(&newJob)
if err != nil {
glog.Errorf("failed to rerun job %s, reason: %s", err, err)
return "", fmt.Errorf("failed to rerun job %s", jobName)
}
return "succeed", nil
}

View File

@@ -227,6 +227,11 @@ func (ctl *NamespaceCtl) createRoleAndRuntime(item v1.Namespace) {
} }
func (ctl *NamespaceCtl) generateObject(item v1.Namespace) *Namespace { func (ctl *NamespaceCtl) generateObject(item v1.Namespace) *Namespace {
var displayName string
if item.Annotations != nil && len(item.Annotations[DisplayName]) > 0 {
displayName = item.Annotations[DisplayName]
}
name := item.Name name := item.Name
createTime := item.CreationTimestamp.Time createTime := item.CreationTimestamp.Time
@@ -236,7 +241,13 @@ func (ctl *NamespaceCtl) generateObject(item v1.Namespace) *Namespace {
createTime = time.Now() createTime = time.Now()
} }
object := &Namespace{Name: name, CreateTime: createTime, Status: status, Annotation: Annotation{item.Annotations}} object := &Namespace{
Name: name,
DisplayName: displayName,
CreateTime: createTime,
Status: status,
Annotation: MapString{item.Annotations},
}
return object return object
} }
@@ -320,12 +331,14 @@ func (ctl *NamespaceCtl) CountWithConditions(conditions string) int {
return countWithConditions(ctl.DB, conditions, &object) return countWithConditions(ctl.DB, conditions, &object)
} }
func (ctl *NamespaceCtl) ListWithConditions(conditions string, paging *Paging) (int, interface{}, error) { func (ctl *NamespaceCtl) ListWithConditions(conditions string, paging *Paging, order string) (int, interface{}, error) {
var list []Namespace var list []Namespace
var object Namespace var object Namespace
var total int var total int
order := "createTime desc" if len(order) == 0 {
order = "createTime desc"
}
listWithConditions(ctl.DB, &total, &object, &list, conditions, paging, order) listWithConditions(ctl.DB, &total, &object, &list, conditions, paging, order)
@@ -333,7 +346,7 @@ func (ctl *NamespaceCtl) ListWithConditions(conditions string, paging *Paging) (
for index := range list { for index := range list {
usage, err := ctl.GetNamespaceQuota(list[index].Name) usage, err := ctl.GetNamespaceQuota(list[index].Name)
if err == nil { if err == nil {
list[index].Usaeg = usage list[index].Usage = usage
} }
} }
} }
@@ -350,7 +363,7 @@ func (ctl *NamespaceCtl) GetNamespaceQuota(namespace string) (v1.ResourceList, e
usage := make(v1.ResourceList) usage := make(v1.ResourceList)
resourceList := []string{Daemonsets, Deployments, Ingresses, Roles, Services, Statefulsets, PersistentVolumeClaim, Pods} resourceList := []string{Daemonsets, Deployments, Ingresses, Roles, Services, Statefulsets, PersistentVolumeClaim, Pods, Jobs, Cronjobs}
for _, resourceName := range resourceList { for _, resourceName := range resourceList {
used := getUsage(namespace, resourceName) used := getUsage(namespace, resourceName)
var quantity resource.Quantity var quantity resource.Quantity
@@ -365,3 +378,8 @@ func (ctl *NamespaceCtl) GetNamespaceQuota(namespace string) (v1.ResourceList, e
usage["runningPods"] = quantity usage["runningPods"] = quantity
return usage, nil return usage, nil
} }
func (ctl *NamespaceCtl) Lister() interface{} {
return ctl.lister
}

View File

@@ -0,0 +1,183 @@
/*
Copyright 2018 The KubeSphere Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package controllers
import (
"time"
"strings"
"github.com/golang/glog"
"k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/client-go/informers"
"k8s.io/client-go/tools/cache"
)
const nodeRole = "role"
func (ctl *NodeCtl) generateObject(item v1.Node) *Node {
var status, ip, role, displayName, msgStr string
var msg []string
if item.Annotations != nil && len(item.Annotations[DisplayName]) > 0 {
displayName = item.Annotations[DisplayName]
}
name := item.Name
createTime := item.ObjectMeta.CreationTimestamp.Time
annotation := item.Annotations
if _, exist := item.Labels[nodeRole]; exist {
role = item.Labels[nodeRole]
}
for _, condition := range item.Status.Conditions {
if condition.Type == "Ready" {
if condition.Status == "True" {
status = Running
} else {
status = Error
}
} else {
if condition.Status == "True" {
msg = append(msg, condition.Reason)
}
}
}
if len(msg) > 0 {
msgStr = strings.Join(msg, ",")
if status == Running {
status = Warning
}
}
for _, address := range item.Status.Addresses {
if address.Type == "InternalIP" {
ip = address.Address
}
}
object := &Node{
Name: name,
DisplayName: displayName,
Ip: ip,
Status: status,
CreateTime: createTime,
Annotation: MapString{annotation},
Taints: Taints{item.Spec.Taints},
Msg: msgStr,
Role: role,
Labels: MapString{item.Labels}}
return object
}
func (ctl *NodeCtl) Name() string {
return ctl.CommonAttribute.Name
}
func (ctl *NodeCtl) sync(stopChan chan struct{}) {
db := ctl.DB
if db.HasTable(&Node{}) {
db.DropTable(&Node{})
}
db = db.CreateTable(&Node{})
ctl.initListerAndInformer()
list, err := ctl.lister.List(labels.Everything())
if err != nil {
glog.Error(err)
return
}
for _, item := range list {
obj := ctl.generateObject(*item)
db.Create(obj)
}
ctl.informer.Run(stopChan)
}
func (ctl *NodeCtl) total() int {
list, err := ctl.lister.List(labels.Everything())
if err != nil {
glog.Errorf("count %s falied, reason:%s", err, ctl.Name())
return 0
}
return len(list)
}
func (ctl *NodeCtl) initListerAndInformer() {
db := ctl.DB
informerFactory := informers.NewSharedInformerFactory(ctl.K8sClient, time.Second*resyncCircle)
ctl.lister = informerFactory.Core().V1().Nodes().Lister()
informer := informerFactory.Core().V1().Nodes().Informer()
informer.AddEventHandler(cache.ResourceEventHandlerFuncs{
AddFunc: func(obj interface{}) {
object := obj.(*v1.Node)
mysqlObject := ctl.generateObject(*object)
db.Create(mysqlObject)
},
UpdateFunc: func(old, new interface{}) {
object := new.(*v1.Node)
mysqlObject := ctl.generateObject(*object)
db.Save(mysqlObject)
},
DeleteFunc: func(obj interface{}) {
var item Node
object := obj.(*v1.Node)
db.Where("name=? ", object.Name, object.Namespace).Find(&item)
db.Delete(item)
},
})
ctl.informer = informer
}
func (ctl *NodeCtl) CountWithConditions(conditions string) int {
var object Node
return countWithConditions(ctl.DB, conditions, &object)
}
func (ctl *NodeCtl) ListWithConditions(conditions string, paging *Paging, order string) (int, interface{}, error) {
var list []Node
var object Node
var total int
if len(order) == 0 {
order = "createTime desc"
}
listWithConditions(ctl.DB, &total, &object, &list, conditions, paging, order)
return total, list, nil
}
func (ctl *NodeCtl) Lister() interface{} {
return ctl.lister
}

View File

@@ -193,8 +193,19 @@ func (ctl *PodCtl) generateObject(item v1.Pod) *Pod {
containers = append(containers, container) containers = append(containers, container)
} }
object := &Pod{Namespace: namespace, Name: name, Node: nodeName, PodIp: podIp, Status: status, NodeIp: nodeIp, object := &Pod{
CreateTime: createTime, Annotation: Annotation{item.Annotations}, Containers: containers, RestartCount: restartCount} Namespace: namespace,
Name: name,
Node: nodeName,
PodIp: podIp,
Status: status,
NodeIp: nodeIp,
CreateTime: createTime,
Annotation: MapString{item.Annotations},
Containers: containers,
RestartCount: restartCount,
Labels: MapString{item.Labels},
}
return object return object
} }
@@ -277,25 +288,21 @@ func (ctl *PodCtl) CountWithConditions(conditions string) int {
return countWithConditions(ctl.DB, conditions, &object) return countWithConditions(ctl.DB, conditions, &object)
} }
func (ctl *PodCtl) ListWithConditions(conditions string, paging *Paging) (int, interface{}, error) { func (ctl *PodCtl) ListWithConditions(conditions string, paging *Paging, order string) (int, interface{}, error) {
var list []Pod var list []Pod
var object Pod var object Pod
var total int var total int
order := "createTime desc" if len(order) == 0 {
order = "createTime desc"
}
listWithConditions(ctl.DB, &total, &object, &list, conditions, paging, order) listWithConditions(ctl.DB, &total, &object, &list, conditions, paging, order)
return total, list, nil return total, list, nil
} }
//func (ctl *PodCtl) Count(namespace string) int { func (ctl *PodCtl) Lister() interface{} {
// var count int
// db := ctl.DB return ctl.lister
// if len(namespace) == 0 { }
// db.Model(&Pod{}).Count(&count)
// } else {
// db.Model(&Pod{}).Where("namespace = ?", namespace).Count(&count)
// }
// return count
//}

View File

@@ -30,6 +30,12 @@ import (
) )
func (ctl *PvcCtl) generateObject(item *v1.PersistentVolumeClaim) *Pvc { func (ctl *PvcCtl) generateObject(item *v1.PersistentVolumeClaim) *Pvc {
var displayName string
if item.Annotations != nil && len(item.Annotations[DisplayName]) > 0 {
displayName = item.Annotations[DisplayName]
}
name := item.Name name := item.Name
namespace := item.Namespace namespace := item.Namespace
status := fmt.Sprintf("%s", item.Status.Phase) status := fmt.Sprintf("%s", item.Status.Phase)
@@ -58,8 +64,18 @@ func (ctl *PvcCtl) generateObject(item *v1.PersistentVolumeClaim) *Pvc {
accessModeStr = strings.Join(accessModeList, ",") accessModeStr = strings.Join(accessModeList, ",")
object := &Pvc{Namespace: namespace, Name: name, Status: status, Capacity: capacity, object := &Pvc{
AccessMode: accessModeStr, StorageClassName: storageClass, CreateTime: createTime, Annotation: Annotation{item.Annotations}} Namespace: namespace,
Name: name,
DisplayName: displayName,
Status: status,
Capacity: capacity,
AccessMode: accessModeStr,
StorageClassName: storageClass,
CreateTime: createTime,
Annotation: MapString{item.Annotations},
Labels: MapString{item.Labels},
}
return object return object
} }
@@ -138,12 +154,14 @@ func (ctl *PvcCtl) CountWithConditions(conditions string) int {
return countWithConditions(ctl.DB, conditions, &object) return countWithConditions(ctl.DB, conditions, &object)
} }
func (ctl *PvcCtl) ListWithConditions(conditions string, paging *Paging) (int, interface{}, error) { func (ctl *PvcCtl) ListWithConditions(conditions string, paging *Paging, order string) (int, interface{}, error) {
var list []Pvc var list []Pvc
var object Pvc var object Pvc
var total int var total int
order := "createTime desc" if len(order) == 0 {
order = "createTime desc"
}
listWithConditions(ctl.DB, &total, &object, &list, conditions, paging, order) listWithConditions(ctl.DB, &total, &object, &list, conditions, paging, order)
@@ -163,13 +181,7 @@ func (ctl *PvcCtl) ListWithConditions(conditions string, paging *Paging) (int, i
return total, list, nil return total, list, nil
} }
//func (ctl *PvcCtl) Count(namespace string) int { func (ctl *PvcCtl) Lister() interface{} {
// var count int
// db := ctl.DB return ctl.lister
// if len(namespace) == 0 { }
// db.Model(&Pvc{}).Count(&count)
// } else {
// db.Model(&Pvc{}).Where("namespace = ?", namespace).Count(&count)
// }
// return count
//}

View File

@@ -0,0 +1,64 @@
/*
Copyright 2018 The KubeSphere Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package controllers
import (
"time"
"k8s.io/client-go/informers"
)
func (ctl *ReplicaSetCtl) Name() string {
return ctl.CommonAttribute.Name
}
func (ctl *ReplicaSetCtl) sync(stopChan chan struct{}) {
ctl.initListerAndInformer()
ctl.informer.Run(stopChan)
}
func (ctl *ReplicaSetCtl) total() int {
return 0
}
func (ctl *ReplicaSetCtl) initListerAndInformer() {
informerFactory := informers.NewSharedInformerFactory(ctl.K8sClient, time.Second*resyncCircle)
ctl.lister = informerFactory.Apps().V1().ReplicaSets().Lister()
informer := informerFactory.Apps().V1().ReplicaSets().Informer()
ctl.informer = informer
}
func (ctl *ReplicaSetCtl) CountWithConditions(conditions string) int {
return 0
}
func (ctl *ReplicaSetCtl) ListWithConditions(conditions string, paging *Paging, order string) (int, interface{}, error) {
return 0, nil, nil
}
func (ctl *ReplicaSetCtl) Lister() interface{} {
return ctl.lister
}

View File

@@ -28,6 +28,12 @@ import (
) )
func (ctl *RoleCtl) generateObject(item v1.Role) *Role { func (ctl *RoleCtl) generateObject(item v1.Role) *Role {
var displayName string
if item.Annotations != nil && len(item.Annotations[DisplayName]) > 0 {
displayName = item.Annotations[DisplayName]
}
name := item.Name name := item.Name
if strings.HasPrefix(name, systemPrefix) { if strings.HasPrefix(name, systemPrefix) {
return nil return nil
@@ -38,7 +44,13 @@ func (ctl *RoleCtl) generateObject(item v1.Role) *Role {
createTime = time.Now() createTime = time.Now()
} }
object := &Role{Namespace: namespace, Name: name, CreateTime: createTime, Annotation: Annotation{item.Annotations}} object := &Role{
Namespace: namespace,
Name: name,
DisplayName: displayName,
CreateTime: createTime,
Annotation: MapString{item.Annotations},
}
return object return object
} }
@@ -132,21 +144,21 @@ func (ctl *RoleCtl) CountWithConditions(conditions string) int {
return countWithConditions(ctl.DB, conditions, &object) return countWithConditions(ctl.DB, conditions, &object)
} }
func (ctl *RoleCtl) ListWithConditions(conditions string, paging *Paging) (int, interface{}, error) { func (ctl *RoleCtl) ListWithConditions(conditions string, paging *Paging, order string) (int, interface{}, error) {
var list []Role var list []Role
var object Role var object Role
var total int var total int
order := "createTime desc" if len(order) == 0 {
order = "createTime desc"
}
listWithConditions(ctl.DB, &total, &object, &list, conditions, paging, order) listWithConditions(ctl.DB, &total, &object, &list, conditions, paging, order)
return total, list, nil return total, list, nil
} }
//func (ctl *RoleCtl) Count(namespace string) int { func (ctl *RoleCtl) Lister() interface{} {
// var count int
// db := ctl.DB return ctl.lister
// db.Model(&Role{}).Where("namespace = ?", namespace).Count(&count) }
// return count
//}

View File

@@ -31,10 +31,9 @@ type resourceControllers struct {
k8sClient *kubernetes.Clientset k8sClient *kubernetes.Clientset
} }
var stopChan chan struct{}
var ResourceControllers resourceControllers var ResourceControllers resourceControllers
func (rec *resourceControllers) runContoller(name string) { func (rec *resourceControllers) runContoller(name string, stopChan chan struct{}) {
var ctl Controller var ctl Controller
attr := CommonAttribute{DB: client.NewDBClient(), K8sClient: rec.k8sClient, stopChan: stopChan, attr := CommonAttribute{DB: client.NewDBClient(), K8sClient: rec.k8sClient, stopChan: stopChan,
aliveChan: make(chan struct{}), Name: name} aliveChan: make(chan struct{}), Name: name}
@@ -61,6 +60,16 @@ func (rec *resourceControllers) runContoller(name string) {
ctl = &NamespaceCtl{CommonAttribute: attr} ctl = &NamespaceCtl{CommonAttribute: attr}
case StorageClasses: case StorageClasses:
ctl = &StorageClassCtl{CommonAttribute: attr} ctl = &StorageClassCtl{CommonAttribute: attr}
case Jobs:
ctl = &JobCtl{CommonAttribute: attr}
case Cronjobs:
ctl = &CronJobCtl{CommonAttribute: attr}
case Nodes:
ctl = &NodeCtl{CommonAttribute: attr}
case Replicasets:
ctl = &ReplicaSetCtl{CommonAttribute: attr}
case ControllerRevisions:
ctl = &ControllerRevisionCtl{CommonAttribute: attr}
default: default:
return return
} }
@@ -71,6 +80,8 @@ func (rec *resourceControllers) runContoller(name string) {
} }
func dbHealthCheck(db *gorm.DB) { func dbHealthCheck(db *gorm.DB) {
defer db.Close()
for { for {
count := 0 count := 0
var err error var err error
@@ -79,7 +90,7 @@ func dbHealthCheck(db *gorm.DB) {
if err != nil { if err != nil {
count++ count++
} }
time.Sleep(1 * time.Second) time.Sleep(5 * time.Second)
} }
if count > 3 { if count > 3 {
@@ -98,8 +109,8 @@ func Run() {
ResourceControllers = resourceControllers{k8sClient: k8sClient, Controllers: make(map[string]Controller)} ResourceControllers = resourceControllers{k8sClient: k8sClient, Controllers: make(map[string]Controller)}
for _, item := range []string{Deployments, Statefulsets, Daemonsets, PersistentVolumeClaim, Pods, Services, for _, item := range []string{Deployments, Statefulsets, Daemonsets, PersistentVolumeClaim, Pods, Services,
Ingresses, Roles, ClusterRoles, Namespaces, StorageClasses} { Ingresses, Roles, ClusterRoles, Namespaces, StorageClasses, Jobs, Cronjobs, Nodes, Replicasets, ControllerRevisions} {
ResourceControllers.runContoller(item) ResourceControllers.runContoller(item, stopChan)
} }
go dbHealthCheck(client.NewDBClient()) go dbHealthCheck(client.NewDBClient())
@@ -110,7 +121,7 @@ func Run() {
case _, isClose := <-controller.chanAlive(): case _, isClose := <-controller.chanAlive():
if !isClose { if !isClose {
glog.Errorf("controller %s have stopped, restart it", ctlName) glog.Errorf("controller %s have stopped, restart it", ctlName)
ResourceControllers.runContoller(ctlName) ResourceControllers.runContoller(ctlName, stopChan)
} }
default: default:
time.Sleep(5 * time.Second) time.Sleep(5 * time.Second)

View File

@@ -69,12 +69,25 @@ func getExternalIp(item v1.Service) string {
} }
func generateSvcObject(item v1.Service) *Service { func generateSvcObject(item v1.Service) *Service {
var app string
var displayName string
if item.Annotations != nil && len(item.Annotations[DisplayName]) > 0 {
displayName = item.Annotations[DisplayName]
}
name := item.Name name := item.Name
namespace := item.Namespace namespace := item.Namespace
createTime := item.CreationTimestamp.Time createTime := item.CreationTimestamp.Time
externalIp := getExternalIp(item) externalIp := getExternalIp(item)
serviceType := item.Spec.Type serviceType := item.Spec.Type
vip := item.Spec.ClusterIP vip := item.Spec.ClusterIP
release := item.ObjectMeta.Labels["release"]
chart := item.ObjectMeta.Labels["chart"]
if len(release) > 0 && len(chart) > 0 {
app = release + "/" + chart
}
ports := "" ports := ""
var nodePorts []string var nodePorts []string
@@ -118,13 +131,16 @@ func generateSvcObject(item v1.Service) *Service {
object := &Service{ object := &Service{
Namespace: namespace, Namespace: namespace,
Name: name, Name: name,
DisplayName: displayName,
ServiceType: string(serviceType), ServiceType: string(serviceType),
ExternalIp: externalIp, ExternalIp: externalIp,
VirtualIp: vip, VirtualIp: vip,
CreateTime: createTime, CreateTime: createTime,
Ports: ports, Ports: ports,
NodePorts: strings.Join(nodePorts, ","), NodePorts: strings.Join(nodePorts, ","),
Annotation: Annotation{item.Annotations}, Annotation: MapString{item.Annotations},
Labels: MapString{item.Labels},
App: app,
} }
return object return object
@@ -209,14 +225,21 @@ func (ctl *ServiceCtl) CountWithConditions(conditions string) int {
return countWithConditions(ctl.DB, conditions, &object) return countWithConditions(ctl.DB, conditions, &object)
} }
func (ctl *ServiceCtl) ListWithConditions(conditions string, paging *Paging) (int, interface{}, error) { func (ctl *ServiceCtl) ListWithConditions(conditions string, paging *Paging, order string) (int, interface{}, error) {
var list []Service var list []Service
var object Service var object Service
var total int var total int
order := "createTime desc" if len(order) == 0 {
order = "createTime desc"
}
listWithConditions(ctl.DB, &total, &object, &list, conditions, paging, order) listWithConditions(ctl.DB, &total, &object, &list, conditions, paging, order)
return total, list, nil return total, list, nil
} }
func (ctl *ServiceCtl) Lister() interface{} {
return ctl.lister
}

View File

@@ -30,6 +30,11 @@ import (
func (ctl *StatefulsetCtl) generateObject(item v1.StatefulSet) *Statefulset { func (ctl *StatefulsetCtl) generateObject(item v1.StatefulSet) *Statefulset {
var app string var app string
var status string var status string
var displayName string
if item.Annotations != nil && len(item.Annotations[DisplayName]) > 0 {
displayName = item.Annotations[DisplayName]
}
name := item.Name name := item.Name
namespace := item.Namespace namespace := item.Namespace
availablePodNum := item.Status.ReadyReplicas availablePodNum := item.Status.ReadyReplicas
@@ -56,8 +61,18 @@ func (ctl *StatefulsetCtl) generateObject(item v1.StatefulSet) *Statefulset {
} }
} }
statefulSetObject := &Statefulset{Namespace: namespace, Name: name, Available: availablePodNum, Desire: desirePodNum, statefulSetObject := &Statefulset{
App: app, CreateTime: createTime, Status: status, Annotation: Annotation{item.Annotations}} Namespace: namespace,
Name: name,
DisplayName: displayName,
Available: availablePodNum,
Desire: desirePodNum,
App: app,
CreateTime: createTime,
Status: status,
Annotation: MapString{item.Annotations},
Labels: MapString{item.Spec.Selector.MatchLabels},
}
return statefulSetObject return statefulSetObject
} }
@@ -137,14 +152,21 @@ func (ctl *StatefulsetCtl) CountWithConditions(conditions string) int {
return countWithConditions(ctl.DB, conditions, &object) return countWithConditions(ctl.DB, conditions, &object)
} }
func (ctl *StatefulsetCtl) ListWithConditions(conditions string, paging *Paging) (int, interface{}, error) { func (ctl *StatefulsetCtl) ListWithConditions(conditions string, paging *Paging, order string) (int, interface{}, error) {
var list []Statefulset var list []Statefulset
var object Statefulset var object Statefulset
var total int var total int
order := "createTime desc" if len(order) == 0 {
order = "createTime desc"
}
listWithConditions(ctl.DB, &total, &object, &list, conditions, paging, order) listWithConditions(ctl.DB, &total, &object, &list, conditions, paging, order)
return total, list, nil return total, list, nil
} }
func (ctl *StatefulsetCtl) Lister() interface{} {
return ctl.lister
}

View File

@@ -30,6 +30,12 @@ import (
func (ctl *StorageClassCtl) generateObject(item v1.StorageClass) *StorageClass { func (ctl *StorageClassCtl) generateObject(item v1.StorageClass) *StorageClass {
var displayName string
if item.Annotations != nil && len(item.Annotations[DisplayName]) > 0 {
displayName = item.Annotations[DisplayName]
}
name := item.Name name := item.Name
createTime := item.CreationTimestamp.Time createTime := item.CreationTimestamp.Time
isDefault := false isDefault := false
@@ -41,7 +47,13 @@ func (ctl *StorageClassCtl) generateObject(item v1.StorageClass) *StorageClass {
createTime = time.Now() createTime = time.Now()
} }
object := &StorageClass{Name: name, CreateTime: createTime, IsDefault: isDefault, Annotation: Annotation{item.Annotations}} object := &StorageClass{
Name: name,
DisplayName: displayName,
CreateTime: createTime,
IsDefault: isDefault,
Annotation: MapString{item.Annotations},
}
return object return object
} }
@@ -120,12 +132,14 @@ func (ctl *StorageClassCtl) CountWithConditions(conditions string) int {
return countWithConditions(ctl.DB, conditions, &object) return countWithConditions(ctl.DB, conditions, &object)
} }
func (ctl *StorageClassCtl) ListWithConditions(conditions string, paging *Paging) (int, interface{}, error) { func (ctl *StorageClassCtl) ListWithConditions(conditions string, paging *Paging, order string) (int, interface{}, error) {
var list []StorageClass var list []StorageClass
var object StorageClass var object StorageClass
var total int var total int
order := "createTime desc" if len(order) == 0 {
order = "createTime desc"
}
listWithConditions(ctl.DB, &total, &object, &list, conditions, paging, order) listWithConditions(ctl.DB, &total, &object, &list, conditions, paging, order)
@@ -138,3 +152,8 @@ func (ctl *StorageClassCtl) ListWithConditions(conditions string, paging *Paging
return total, list, nil return total, list, nil
} }
func (ctl *StorageClassCtl) Lister() interface{} {
return ctl.lister
}

View File

@@ -27,6 +27,8 @@ import (
"k8s.io/api/core/v1" "k8s.io/api/core/v1"
"k8s.io/client-go/kubernetes" "k8s.io/client-go/kubernetes"
appV1 "k8s.io/client-go/listers/apps/v1" appV1 "k8s.io/client-go/listers/apps/v1"
batchv1 "k8s.io/client-go/listers/batch/v1"
batchv1beta1 "k8s.io/client-go/listers/batch/v1beta1"
coreV1 "k8s.io/client-go/listers/core/v1" coreV1 "k8s.io/client-go/listers/core/v1"
"k8s.io/client-go/listers/extensions/v1beta1" "k8s.io/client-go/listers/extensions/v1beta1"
rbacV1 "k8s.io/client-go/listers/rbac/v1" rbacV1 "k8s.io/client-go/listers/rbac/v1"
@@ -35,22 +37,18 @@ import (
) )
const ( const (
resyncCircle = 600 resyncCircle = 600
Stopped = "stopped" Stopped = "stopped"
PvcPending = "Pending" PvcPending = "pending"
Running = "running" Running = "running"
Updating = "updating" Updating = "updating"
tablePods = "pods" Failed = "failed"
tableDeployments = "deployments" Unfinished = "unfinished"
tableDaemonsets = "daemonsets" Completed = "completed"
tableStatefulsets = "statefulsets" Pause = "pause"
tableNamespaces = "namespaces" Warning = "warning"
tableIngresses = "ingresses" Error = "error"
tablePersistentVolumeClaim = "pvcs" DisplayName = "displayName"
tableRoles = "roles"
tableClusterRoles = "cluster_roles"
tableServices = "services"
tableStorageClasses = "storage_classes"
Pods = "pods" Pods = "pods"
Deployments = "deployments" Deployments = "deployments"
@@ -64,13 +62,18 @@ const (
Services = "services" Services = "services"
StorageClasses = "storage-classes" StorageClasses = "storage-classes"
Applications = "applications" Applications = "applications"
Jobs = "jobs"
Cronjobs = "cronjobs"
Nodes = "nodes"
Replicasets = "replicasets"
ControllerRevisions = "controllerrevisions"
) )
type Annotation struct { type MapString struct {
Values map[string]string `gorm:"type:TEXT"` Values map[string]string `json:"values" gorm:"type:TEXT"`
} }
func (annotation *Annotation) Scan(val interface{}) error { func (annotation *MapString) Scan(val interface{}) error {
switch val := val.(type) { switch val := val.(type) {
case string: case string:
return json.Unmarshal([]byte(val), annotation) return json.Unmarshal([]byte(val), annotation)
@@ -82,92 +85,104 @@ func (annotation *Annotation) Scan(val interface{}) error {
return nil return nil
} }
func (annotation Annotation) Value() (driver.Value, error) { func (annotation MapString) Value() (driver.Value, error) {
bytes, err := json.Marshal(annotation) bytes, err := json.Marshal(annotation)
return string(bytes), err return string(bytes), err
} }
type Deployment struct { type Taints struct {
Name string `gorm:"primary_key" json:"name"` Values []v1.Taint `json:"values" gorm:"type:TEXT"`
Namespace string `gorm:"primary_key" json:"namespace"`
App string `json:"app,omitempty"`
Available int32 `json:"available"`
Desire int32 `json:"desire"`
Status string `json:"status"`
Annotation Annotation `json:"annotations"`
UpdateTime time.Time `gorm:"column:updateTime" json:"updateTime,omitempty"`
} }
func (Deployment) TableName() string { func (taints *Taints) Scan(val interface{}) error {
return tableDeployments switch val := val.(type) {
case string:
return json.Unmarshal([]byte(val), taints)
case []byte:
return json.Unmarshal(val, taints)
default:
return errors.New("not support")
}
return nil
}
func (taints Taints) Value() (driver.Value, error) {
bytes, err := json.Marshal(taints)
return string(bytes), err
}
type Deployment struct {
Name string `gorm:"primary_key" json:"name"`
DisplayName string `json:"displayName,omitempty" gorm:"column:displayName"`
Namespace string `gorm:"primary_key" json:"namespace"`
App string `json:"app,omitempty"`
Available int32 `json:"available"`
Desire int32 `json:"desire"`
Status string `json:"status"`
Labels MapString `json:"labels"`
Annotation MapString `json:"annotations"`
UpdateTime time.Time `gorm:"column:updateTime" json:"updateTime,omitempty"`
} }
type Statefulset struct { type Statefulset struct {
Name string `gorm:"primary_key" json:"name,omitempty"` Name string `gorm:"primary_key" json:"name,omitempty"`
Namespace string `gorm:"primary_key" json:"namespace,omitempty"` DisplayName string `json:"displayName,omitempty" gorm:"column:displayName"`
App string `json:"app,omitempty"` Namespace string `gorm:"primary_key" json:"namespace,omitempty"`
App string `json:"app,omitempty"`
Available int32 `json:"available"` Available int32 `json:"available"`
Desire int32 `json:"desire"` Desire int32 `json:"desire"`
Status string `json:"status"` Status string `json:"status"`
Annotation Annotation `json:"annotations"` Annotation MapString `json:"annotations"`
CreateTime time.Time `gorm:"column:createTime" json:"createTime,omitempty"` Labels MapString `json:"labels"`
} CreateTime time.Time `gorm:"column:createTime" json:"createTime,omitempty"`
func (Statefulset) TableName() string {
return tableStatefulsets
} }
type Daemonset struct { type Daemonset struct {
Name string `gorm:"primary_key" json:"name,omitempty"` Name string `gorm:"primary_key" json:"name,omitempty"`
Namespace string `gorm:"primary_key" json:"namespace,omitempty"` DisplayName string `json:"displayName,omitempty" gorm:"column:displayName"`
App string `json:"app,omitempty"` Namespace string `gorm:"primary_key" json:"namespace,omitempty"`
App string `json:"app,omitempty"`
Available int32 `json:"available"` Available int32 `json:"available"`
Desire int32 `json:"desire"` Desire int32 `json:"desire"`
Status string `json:"status"` Status string `json:"status"`
NodeSelector string `json:"nodeSelector, omitempty"` NodeSelector string `json:"nodeSelector, omitempty"`
Annotation Annotation `json:"annotations"` Annotation MapString `json:"annotations"`
CreateTime time.Time `gorm:"column:createTime" json:"createTime,omitempty"` Labels MapString `json:"labels"`
} CreateTime time.Time `gorm:"column:createTime" json:"createTime,omitempty"`
func (Daemonset) TableName() string {
return tableDaemonsets
} }
type Service struct { type Service struct {
Name string `gorm:"primary_key" json:"name"` Name string `gorm:"primary_key" json:"name"`
DisplayName string `json:"displayName,omitempty" gorm:"column:displayName"`
Namespace string `gorm:"primary_key" json:"namespace"` Namespace string `gorm:"primary_key" json:"namespace"`
ServiceType string `json:"type,omitempty"` ServiceType string `gorm:"column:type" json:"type,omitempty"`
VirtualIp string `json:"virtualIp,omitempty"` App string `json:"app,omitempty"`
ExternalIp string `json:"externalIp,omitempty"` VirtualIp string `gorm:"column:virtualIp" json:"virtualIp,omitempty"`
ExternalIp string `gorm:"column:externalIp" json:"externalIp,omitempty"`
Ports string `json:"ports,omitempty"` Ports string `json:"ports,omitempty"`
NodePorts string `json:"nodePorts,omitempty"` NodePorts string `gorm:"column:nodePorts" json:"nodePorts,omitempty"`
Annotation Annotation `json:"annotations"` Annotation MapString `json:"annotations"`
CreateTime time.Time `gorm:"column:createTime" json:"createTime,omitempty"` Labels MapString `json:"labels"`
} CreateTime time.Time `gorm:"column:createTime" json:"createTime,omitempty"`
func (Service) TableName() string {
return tableServices
} }
type Pvc struct { type Pvc struct {
Name string `gorm:"primary_key" json:"name"` Name string `gorm:"primary_key" json:"name"`
Namespace string `gorm:"primary_key" json:"namespace"` DisplayName string `json:"displayName,omitempty" gorm:"column:displayName"`
Status string `json:"status,omitempty"` Namespace string `gorm:"primary_key" json:"namespace"`
Capacity string `json:"capacity,omitempty"` Status string `json:"status,omitempty"`
AccessMode string `json:"accessMode,omitempty"` Capacity string `json:"capacity,omitempty"`
Annotation Annotation `json:"annotations"` AccessMode string `gorm:"column:accessMode" json:"accessMode,omitempty"`
CreateTime time.Time `gorm:"column:createTime" json:"createTime,omitempty"` Annotation MapString `json:"annotations"`
StorageClassName string `gorm:"column:storage_class" json:"storage_class,omitempty"` Labels MapString `json:"labels"`
InUse bool `gorm:"-" json:"inUse"` CreateTime time.Time `gorm:"column:createTime" json:"createTime,omitempty"`
} StorageClassName string `gorm:"column:storage_class" json:"storage_class,omitempty"`
InUse bool `gorm:"column:inUse" json:"inUse"`
func (Pvc) TableName() string {
return tablePersistentVolumeClaim
} }
type ingressRule struct { type ingressRule struct {
@@ -178,17 +193,15 @@ type ingressRule struct {
} }
type Ingress struct { type Ingress struct {
Name string `gorm:"primary_key" json:"name"` Name string `gorm:"primary_key" json:"name"`
Namespace string `gorm:"primary_key" json:"namespace"` DisplayName string `json:"displayName,omitempty" gorm:"column:displayName"`
Ip string `json:"ip,omitempty"` Namespace string `gorm:"primary_key" json:"namespace"`
Rules string `gorm:"type:text" json:"rules, omitempty"` Ip string `json:"ip,omitempty"`
TlsTermination string `json:"tlsTermination,omitempty"` Rules string `gorm:"type:text" json:"rules, omitempty"`
Annotation Annotation `json:"annotations"` TlsTermination string `gorm:"column:tlsTermination" json:"tlsTermination,omitempty"`
CreateTime time.Time `gorm:"column:createTime" json:"createTime,omitempty"` Annotation MapString `json:"annotations"`
} Labels MapString `json:"labels"`
CreateTime time.Time `gorm:"column:createTime" json:"createTime,omitempty"`
func (Ingress) TableName() string {
return tableIngresses
} }
type Pod struct { type Pod struct {
@@ -196,10 +209,11 @@ type Pod struct {
Namespace string `gorm:"primary_key" json:"namespace"` Namespace string `gorm:"primary_key" json:"namespace"`
Status string `json:"status,omitempty"` Status string `json:"status,omitempty"`
Node string `json:"node,omitempty"` Node string `json:"node,omitempty"`
NodeIp string `json:"nodeIp,omitempty"` NodeIp string `gorm:"column:nodeIp" json:"nodeIp,omitempty"`
PodIp string `json:"podIp,omitempty"` PodIp string `gorm:"column:podIp" json:"podIp,omitempty"`
Containers Containers `gorm:"type:text" json:"containers,omitempty"` Containers Containers `gorm:"type:text" json:"containers,omitempty"`
Annotation Annotation `json:"annotations"` Annotation MapString `json:"annotations"`
Labels MapString `json:"labels"`
RestartCount int `json:"restartCount"` RestartCount int `json:"restartCount"`
CreateTime time.Time `gorm:"column:createTime" json:"createTime,omitempty"` CreateTime time.Time `gorm:"column:createTime" json:"createTime,omitempty"`
} }
@@ -230,61 +244,97 @@ func (containers Containers) Value() (driver.Value, error) {
return string(bytes), err return string(bytes), err
} }
func (Pod) TableName() string {
return tablePods
}
type Role struct { type Role struct {
Name string `gorm:"primary_key" json:"name"` Name string `gorm:"primary_key" json:"name"`
Namespace string `gorm:"primary_key" json:"namespace"` DisplayName string `json:"displayName,omitempty" gorm:"column:displayName"`
Annotation Annotation `json:"annotations"` Namespace string `gorm:"primary_key" json:"namespace"`
CreateTime time.Time `gorm:"column:createTime" json:"createTime,omitempty"` Annotation MapString `json:"annotations"`
} CreateTime time.Time `gorm:"column:createTime" json:"createTime,omitempty"`
func (Role) TableName() string {
return tableRoles
} }
type ClusterRole struct { type ClusterRole struct {
Name string `gorm:"primary_key" json:"name"` Name string `gorm:"primary_key" json:"name"`
Annotation Annotation `json:"annotations"` DisplayName string `json:"displayName,omitempty" gorm:"column:displayName"`
CreateTime time.Time `gorm:"column:createTime" json:"createTime,omitempty"` Annotation MapString `json:"annotations"`
} CreateTime time.Time `gorm:"column:createTime" json:"createTime,omitempty"`
func (ClusterRole) TableName() string {
return tableClusterRoles
} }
type Namespace struct { type Namespace struct {
Name string `gorm:"primary_key" json:"name"` Name string `gorm:"primary_key" json:"name"`
Creator string `json:"creator,omitempty"` DisplayName string `json:"displayName,omitempty" gorm:"column:displayName"`
Status string `json:"status"` Creator string `json:"creator,omitempty"`
Status string `json:"status"`
Descrition string `json:"description,omitempty"` Descrition string `json:"description,omitempty"`
Annotation Annotation `json:"annotations"` Annotation MapString `json:"annotations"`
CreateTime time.Time `gorm:"column:createTime" json:"createTime,omitempty"` CreateTime time.Time `gorm:"column:createTime" json:"createTime,omitempty"`
Usaeg v1.ResourceList `gorm:"-" json:"usage,omitempty"` Usage v1.ResourceList `gorm:"-" json:"usage,omitempty"`
}
func (Namespace) TableName() string {
return tableNamespaces
} }
type StorageClass struct { type StorageClass struct {
Name string `gorm:"primary_key" json:"name"` Name string `gorm:"primary_key" json:"name"`
Creator string `json:"creator,omitempty"` DisplayName string `json:"displayName,omitempty" gorm:"column:displayName"`
Annotation Annotation `json:"annotations"` Creator string `json:"creator,omitempty"`
CreateTime time.Time `gorm:"column:createTime" json:"createTime,omitempty"` Annotation MapString `json:"annotations"`
IsDefault bool `json:"default"` CreateTime time.Time `gorm:"column:createTime" json:"createTime,omitempty"`
Count int `json:"count"` IsDefault bool `json:"default"`
Count int `json:"count"`
} }
func (StorageClass) TableName() string { type JobRevisions map[int]JobStatus
return tableStorageClasses
type JobStatus struct {
Status string `json:"status"`
Reasons []string `json:"reasons"`
Messages []string `json:"messages"`
Succeed int32 `json:"succeed"`
DesirePodNum int32 `json:"desire"`
Failed int32 `json:"failed"`
StartTime time.Time `json:"start-time"`
CompletionTime time.Time `json:"completion-time"`
} }
type Job struct {
Name string `gorm:"primary_key" json:"name,omitempty"`
DisplayName string `json:"displayName,omitempty" gorm:"column:displayName"`
Namespace string `gorm:"primary_key" json:"namespace,omitempty"`
Completed int32 `json:"completed"`
Desire int32 `json:"desire"`
Status string `json:"status"`
Annotation MapString `json:"annotations"`
Labels MapString `json:"labels"`
CreateTime time.Time `gorm:"column:createTime" json:"createTime,omitempty"`
UpdateTime time.Time `gorm:"column:updateTime" json:"updateTime,omitempty"`
}
type CronJob struct {
Name string `gorm:"primary_key" json:"name,omitempty"`
DisplayName string `json:"displayName,omitempty" gorm:"column:displayName"`
Namespace string `gorm:"primary_key" json:"namespace,omitempty"`
Active int `json:"active"`
Schedule string `json:"schedule"`
Status string `json:"status"`
Annotation MapString `json:"annotations"`
Labels MapString `json:"labels"`
LastScheduleTime *time.Time `gorm:"column:lastScheduleTime" json:"lastScheduleTime,omitempty"`
}
type Node struct {
Name string `gorm:"primary_key" json:"name,omitempty"`
DisplayName string `json:"displayName,omitempty" gorm:"column:displayName"`
Ip string `json:"ip"`
Status string `json:"status"`
Annotation MapString `json:"annotations"`
Labels MapString `json:"labels"`
Taints Taints `json:"taints"`
Msg string `json:"msg"`
Role string `json:"role"`
CreateTime time.Time `gorm:"column:createTime" json:"createTime,omitempty"`
}
type Paging struct { type Paging struct {
Limit, Offset int Limit, Offset, Page int
} }
type Controller interface { type Controller interface {
@@ -295,7 +345,9 @@ type Controller interface {
initListerAndInformer() initListerAndInformer()
sync(stopChan chan struct{}) sync(stopChan chan struct{})
Name() string Name() string
ListWithConditions(condition string, paging *Paging) (int, interface{}, error) CloseDB()
Lister() interface{}
ListWithConditions(condition string, paging *Paging, order string) (int, interface{}, error)
} }
type CommonAttribute struct { type CommonAttribute struct {
@@ -316,6 +368,11 @@ func (ca *CommonAttribute) chanAlive() chan struct{} {
return ca.aliveChan return ca.aliveChan
} }
func (ca *CommonAttribute) CloseDB() {
ca.DB.Close()
}
type DeploymentCtl struct { type DeploymentCtl struct {
CommonAttribute CommonAttribute
lister appV1.DeploymentLister lister appV1.DeploymentLister
@@ -381,3 +438,33 @@ type ClusterRoleCtl struct {
informer cache.SharedIndexInformer informer cache.SharedIndexInformer
CommonAttribute CommonAttribute
} }
type JobCtl struct {
lister batchv1.JobLister
informer cache.SharedIndexInformer
CommonAttribute
}
type CronJobCtl struct {
lister batchv1beta1.CronJobLister
informer cache.SharedIndexInformer
CommonAttribute
}
type NodeCtl struct {
lister coreV1.NodeLister
informer cache.SharedIndexInformer
CommonAttribute
}
type ReplicaSetCtl struct {
lister appV1.ReplicaSetLister
informer cache.SharedIndexInformer
CommonAttribute
}
type ControllerRevisionCtl struct {
lister appV1.ControllerRevisionLister
informer cache.SharedIndexInformer
CommonAttribute
}

View File

@@ -40,12 +40,15 @@ const (
persistentvolumeclaimsKey = "persistentvolumeclaims" persistentvolumeclaimsKey = "persistentvolumeclaims"
storageClassesKey = "count/storageClass" storageClassesKey = "count/storageClass"
namespaceKey = "count/namespace" namespaceKey = "count/namespace"
jobsKey = "count/jobs.batch"
cronJobsKey = "count/cronjobs.batch"
) )
var resourceMap = map[string]string{daemonsetsKey: controllers.Daemonsets, deploymentsKey: controllers.Deployments, var resourceMap = map[string]string{daemonsetsKey: controllers.Daemonsets, deploymentsKey: controllers.Deployments,
ingressKey: controllers.Ingresses, rolesKey: controllers.Roles, servicesKey: controllers.Services, ingressKey: controllers.Ingresses, rolesKey: controllers.Roles, servicesKey: controllers.Services,
statefulsetsKey: controllers.Statefulsets, persistentvolumeclaimsKey: controllers.PersistentVolumeClaim, podsKey: controllers.Pods, statefulsetsKey: controllers.Statefulsets, persistentvolumeclaimsKey: controllers.PersistentVolumeClaim, podsKey: controllers.Pods,
namespaceKey: controllers.Namespaces, storageClassesKey: controllers.StorageClasses, clusterRolesKey: controllers.ClusterRoles} namespaceKey: controllers.Namespaces, storageClassesKey: controllers.StorageClasses, clusterRolesKey: controllers.ClusterRoles,
jobsKey: controllers.Jobs, cronJobsKey: controllers.Cronjobs}
type ResourceQuota struct { type ResourceQuota struct {
NameSpace string `json:"namespace"` NameSpace string `json:"namespace"`

View File

@@ -1,3 +1,19 @@
/*
Copyright 2018 The KubeSphere Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package models package models
import ( import (
@@ -24,11 +40,19 @@ type ResourceList struct {
Items interface{} `json:"items,omitempty"` Items interface{} `json:"items,omitempty"`
} }
type searchConditions struct {
match map[string]string
fuzzy map[string]string
matchOr map[string]string
fuzzyOr map[string]string
}
func getController(resource string) (controllers.Controller, error) { func getController(resource string) (controllers.Controller, error) {
switch resource { switch resource {
case controllers.Deployments, controllers.Statefulsets, controllers.Daemonsets, controllers.Ingresses, case controllers.Deployments, controllers.Statefulsets, controllers.Daemonsets, controllers.Ingresses,
controllers.PersistentVolumeClaim, controllers.Roles, controllers.ClusterRoles, controllers.Services, controllers.PersistentVolumeClaim, controllers.Roles, controllers.ClusterRoles, controllers.Services,
controllers.Pods, controllers.Namespaces, controllers.StorageClasses: controllers.Pods, controllers.Namespaces, controllers.StorageClasses, controllers.Jobs, controllers.Cronjobs,
controllers.Nodes:
return controllers.ResourceControllers.Controllers[resource], nil return controllers.ResourceControllers.Controllers[resource], nil
default: default:
@@ -38,20 +62,21 @@ func getController(resource string) (controllers.Controller, error) {
} }
func getConditions(str string) (map[string]string, map[string]string, error) { func getConditions(str string) (*searchConditions, map[string]string, error) {
match := make(map[string]string) match := make(map[string]string)
fuzzy := make(map[string]string) fuzzy := make(map[string]string)
matchOr := make(map[string]string)
fuzzyOr := make(map[string]string)
orderField := make(map[string]string)
if len(str) == 0 { if len(str) == 0 {
return nil, nil, nil return nil, nil, nil
} }
list := strings.Split(str, ",")
for _, item := range list {
if strings.Count(item, "=") >= 2 {
return nil, nil, errors.New("invalid condition input, invalid character \"=\"")
}
if strings.Count(item, "~") >= 2 { conditions := strings.Split(str, ",")
return nil, nil, errors.New("invalid condition input, invalid character \"~\"") for _, item := range conditions {
if strings.Count(item, "=") >= 2 || strings.Count(item, "~") >= 2 {
return nil, nil, errors.New("invalid condition input")
} }
if strings.Count(item, "=") == 1 { if strings.Count(item, "=") == 1 {
@@ -59,7 +84,17 @@ func getConditions(str string) (map[string]string, map[string]string, error) {
if len(kvs) < 2 || len(kvs[1]) == 0 { if len(kvs) < 2 || len(kvs[1]) == 0 {
return nil, nil, errors.New("invalid condition input") return nil, nil, errors.New("invalid condition input")
} }
match[kvs[0]] = kvs[1]
if !strings.Contains(kvs[0], "|") {
match[kvs[0]] = kvs[1]
} else {
multiFields := strings.Split(kvs[0], "|")
for _, filed := range multiFields {
if len(filed) > 0 {
matchOr[filed] = kvs[1]
}
}
}
continue continue
} }
@@ -68,86 +103,130 @@ func getConditions(str string) (map[string]string, map[string]string, error) {
if len(kvs) < 2 || len(kvs[1]) == 0 { if len(kvs) < 2 || len(kvs[1]) == 0 {
return nil, nil, errors.New("invalid condition input") return nil, nil, errors.New("invalid condition input")
} }
fuzzy[kvs[0]] = kvs[1] if !strings.Contains(kvs[0], "|") {
fuzzy[kvs[0]] = kvs[1]
} else {
multiFields := strings.Split(kvs[0], "|")
if len(multiFields) > 1 && len(multiFields[1]) > 0 {
orderField[multiFields[0]] = kvs[1]
}
for _, filed := range multiFields {
if len(filed) > 0 {
fuzzyOr[filed] = kvs[1]
}
}
}
continue continue
} }
return nil, nil, errors.New("invalid condition input") return nil, nil, errors.New("invalid condition input")
} }
return match, fuzzy, nil
return &searchConditions{match: match, fuzzyOr: fuzzyOr, matchOr: matchOr, fuzzy: fuzzy}, orderField, nil
} }
func getPaging(resourceName, pagingStr string) (*controllers.Paging, map[string]int, error) { func getPaging(resourceName, pagingStr string) (*controllers.Paging, error) {
defaultPaging := &controllers.Paging{Limit: 10, Offset: 0} defaultPaging := &controllers.Paging{Limit: 10, Offset: 0, Page: 1}
defautlPagingMap := map[string]int{"page": 1, "limit": 10} paging := controllers.Paging{}
if resourceName == controllers.Namespaces { if resourceName == controllers.Namespaces {
defaultPaging = nil defaultPaging = nil
defautlPagingMap = map[string]int{"page": 0, "limit": 0}
} }
pagingMap := make(map[string]int)
if len(pagingStr) == 0 { if len(pagingStr) == 0 {
return defaultPaging, defautlPagingMap, nil return defaultPaging, nil
} }
list := strings.Split(pagingStr, ",") list := strings.Split(pagingStr, ",")
for _, item := range list { for _, item := range list {
kvs := strings.Split(item, "=") kvs := strings.Split(item, "=")
if len(kvs) < 2 { if len(kvs) < 2 {
return nil, nil, errors.New("invalid Paging input") return nil, errors.New("invalid Paging input")
} }
value, err := strconv.Atoi(kvs[1]) value, err := strconv.Atoi(kvs[1])
if err != nil { if err != nil || value <= 0 {
return nil, nil, errors.New("invalid Paging input") return nil, errors.New("invalid Paging input")
} }
pagingMap[kvs[0]] = value if kvs[0] == limit {
paging.Limit = value
}
if kvs[0] == page {
paging.Page = value
}
} }
if pagingMap[limit] <= 0 || pagingMap[page] <= 0 { if paging.Limit > 0 && paging.Page > 0 {
return nil, nil, errors.New("invalid Paging input") paging.Offset = (paging.Page - 1) * paging.Limit
return &paging, nil
} }
if pagingMap[limit] > 0 && pagingMap[page] > 0 { return defaultPaging, nil
offset := (pagingMap[page] - 1) * pagingMap[limit]
return &controllers.Paging{Limit: pagingMap[limit], Offset: offset}, pagingMap, nil
}
return defaultPaging, defautlPagingMap, nil
} }
func ListResource(resourceName, conditonSrt, pagingStr string) (*ResourceList, error) { func generateOrder(orderField map[string]string, order string) string {
match, fuzzy, err := getConditions(conditonSrt) if len(orderField) == 0 {
return order
}
var str string
for k, v := range orderField {
if len(str) > 0 {
str = fmt.Sprintf("%s, (%s like '%%%s%%')", str, k, v)
} else {
str = fmt.Sprintf("(%s like '%%%s%%')", k, v)
}
}
if len(order) == 0 {
return fmt.Sprintf("%s desc", str)
} else {
return fmt.Sprintf("%s, %s", str, order)
}
}
func ListResource(resourceName, conditonSrt, pagingStr, order string) (*ResourceList, error) {
conditions, OrderFields, err := getConditions(conditonSrt)
if err != nil { if err != nil {
return nil, err return nil, err
} }
paging, pagingMap, err := getPaging(resourceName, pagingStr) order = generateOrder(OrderFields, order)
conditionStr := generateConditionStr(conditions)
paging, err := getPaging(resourceName, pagingStr)
if err != nil { if err != nil {
return nil, err return nil, err
} }
conditionStr := generateConditionStr(match, fuzzy)
ctl, err := getController(resourceName) ctl, err := getController(resourceName)
if err != nil { if err != nil {
return nil, err return nil, err
} }
total, items, err := ctl.ListWithConditions(conditionStr, paging) total, items, err := ctl.ListWithConditions(conditionStr, paging, order)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &ResourceList{Total: total, Items: items, Page: pagingMap[page], Limit: pagingMap[limit]}, nil if paging != nil {
return &ResourceList{Total: total, Items: items, Page: paging.Page, Limit: paging.Limit}, nil
} else {
return &ResourceList{Total: total, Items: items}, nil
}
} }
func generateConditionStr(match map[string]string, fuzzy map[string]string) string { func generateConditionStr(conditions *searchConditions) string {
conditionStr := "" conditionStr := ""
for k, v := range match { if conditions == nil {
return conditionStr
}
for k, v := range conditions.match {
if len(conditionStr) == 0 { if len(conditionStr) == 0 {
conditionStr = fmt.Sprintf("%s = \"%s\" ", k, v) conditionStr = fmt.Sprintf("%s = \"%s\" ", k, v)
} else { } else {
@@ -155,7 +234,7 @@ func generateConditionStr(match map[string]string, fuzzy map[string]string) stri
} }
} }
for k, v := range fuzzy { for k, v := range conditions.fuzzy {
if len(conditionStr) == 0 { if len(conditionStr) == 0 {
conditionStr = fmt.Sprintf("%s like '%%%s%%' ", k, v) conditionStr = fmt.Sprintf("%s like '%%%s%%' ", k, v)
} else { } else {
@@ -163,6 +242,22 @@ func generateConditionStr(match map[string]string, fuzzy map[string]string) stri
} }
} }
for k, v := range conditions.matchOr {
if len(conditionStr) == 0 {
conditionStr = fmt.Sprintf("%s = \"%s\" ", k, v)
} else {
conditionStr = fmt.Sprintf("%s OR %s = \"%s\" ", conditionStr, k, v)
}
}
for k, v := range conditions.fuzzyOr {
if len(conditionStr) == 0 {
conditionStr = fmt.Sprintf("%s like '%%%s%%' ", k, v)
} else {
conditionStr = fmt.Sprintf("%s OR %s like '%%%s%%' ", conditionStr, k, v)
}
}
return conditionStr return conditionStr
} }
@@ -182,9 +277,9 @@ func GetNamespacesResourceStatus(namespace string) (*workLoadStatus, error) {
notReadyStatus = controllers.PvcPending notReadyStatus = controllers.PvcPending
} }
if len(namespace) > 0 { if len(namespace) > 0 {
status, err = ListResource(resource, fmt.Sprintf("status=%s,namespace=%s", notReadyStatus, namespace), "") status, err = ListResource(resource, fmt.Sprintf("status=%s,namespace=%s", notReadyStatus, namespace), "", "")
} else { } else {
status, err = ListResource(resource, fmt.Sprintf("status=%s", notReadyStatus), "") status, err = ListResource(resource, fmt.Sprintf("status=%s", notReadyStatus), "", "")
} }
if err != nil { if err != nil {
@@ -208,25 +303,30 @@ func GetApplication(clusterId string) (interface{}, error) {
return ctl.GetApp(clusterId) return ctl.GetApp(clusterId)
} }
func ListApplication(runtimeId, conditions, pagingStr string) (*ResourceList, error) { func ListApplication(runtimeId, conditionStr, pagingStr string) (*ResourceList, error) {
paging, pagingMap, err := getPaging(controllers.Applications, pagingStr) paging, err := getPaging(controllers.Applications, pagingStr)
if err != nil { if err != nil {
return nil, err return nil, err
} }
match, fuzzy, err := getConditions(conditions) conditions, _, err := getConditions(conditionStr)
if err != nil { if err != nil {
glog.Error(err) glog.Error(err)
return nil, err return nil, err
} }
if conditions == nil {
conditions = &searchConditions{}
}
ctl := &controllers.ApplicationCtl{OpenpitrixAddr: options.ServerOptions.GetOpAddress()} ctl := &controllers.ApplicationCtl{OpenpitrixAddr: options.ServerOptions.GetOpAddress()}
total, items, err := ctl.ListApplication(runtimeId, match, fuzzy, paging)
total, items, err := ctl.ListApplication(runtimeId, conditions.match, conditions.fuzzy, paging)
if err != nil { if err != nil {
glog.Errorf("get application list failed, reason: %s", err) glog.Errorf("get application list failed, reason: %s", err)
return nil, err return nil, err
} }
return &ResourceList{Total: total, Items: items, Page: pagingMap[page], Limit: pagingMap[limit]}, nil return &ResourceList{Total: total, Items: items, Page: paging.Page, Limit: paging.Limit}, nil
} }

112
pkg/models/revisions.go Normal file
View File

@@ -0,0 +1,112 @@
/*
Copyright 2018 The KubeSphere Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package models
import (
"fmt"
"strconv"
"github.com/golang/glog"
"k8s.io/api/apps/v1"
"k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/labels"
appsV1 "k8s.io/client-go/listers/apps/v1"
"kubesphere.io/kubesphere/pkg/models/controllers"
)
func GetDeployRevision(namespace, name, revision string) (*v1.ReplicaSet, error) {
deployLister := controllers.ResourceControllers.Controllers[controllers.Deployments].Lister().(appsV1.DeploymentLister)
deploy, err := deployLister.Deployments(namespace).Get(name)
if err != nil {
glog.Errorf("get deployment %s failed, reason: %s", name, err)
return nil, err
}
labelMap := deploy.Spec.Template.Labels
labelSelector := labels.Set(labelMap).AsSelector()
rsLister := controllers.ResourceControllers.Controllers[controllers.Replicasets].Lister().(appsV1.ReplicaSetLister)
rsList, err := rsLister.ReplicaSets(namespace).List(labelSelector)
if err != nil {
return nil, err
}
for _, rs := range rsList {
if rs.Annotations["deployment.kubernetes.io/revision"] == revision {
return rs, nil
}
}
return nil, errors.NewNotFound(v1.Resource("deployment revision"), fmt.Sprintf("%s#%s", name, revision))
}
func GetDaemonSetRevision(namespace, name, revision string) (*v1.ControllerRevision, error) {
revisionInt, err := strconv.Atoi(revision)
if err != nil {
return nil, err
}
dsLister := controllers.ResourceControllers.Controllers[controllers.Daemonsets].Lister().(appsV1.DaemonSetLister)
ds, err := dsLister.DaemonSets(namespace).Get(name)
if err != nil {
glog.Errorf("get Daemonset %s failed, reason: %s", name, err)
return nil, err
}
labels := ds.Spec.Template.Labels
return getControllerRevision(namespace, name, labels, revisionInt)
}
func GetStatefulSetRevision(namespace, name, revision string) (*v1.ControllerRevision, error) {
revisionInt, err := strconv.Atoi(revision)
if err != nil {
return nil, err
}
stLister := controllers.ResourceControllers.Controllers[controllers.Statefulsets].Lister().(appsV1.StatefulSetLister)
st, err := stLister.StatefulSets(namespace).Get(name)
if err != nil {
glog.Errorf("get Daemonset %s failed, reason: %s", name, err)
return nil, err
}
labels := st.Spec.Template.Labels
return getControllerRevision(namespace, name, labels, revisionInt)
}
func getControllerRevision(namespace, name string, labelMap map[string]string, revision int) (*v1.ControllerRevision, error) {
labelSelector := labels.Set(labelMap).AsSelector()
revisionLister := controllers.ResourceControllers.Controllers[controllers.ControllerRevisions].Lister().(appsV1.ControllerRevisionLister)
revisions, err := revisionLister.ControllerRevisions(namespace).List(labelSelector)
if err != nil {
return nil, err
}
for _, controllerRevision := range revisions {
if controllerRevision.Revision == int64(revision) {
return controllerRevision, nil
}
}
return nil, errors.NewNotFound(v1.Resource("revision"), fmt.Sprintf("%s#%s", name, revision))
}