Merge pull request #160 from richardxz/master

refactor the code of resource list function
This commit is contained in:
zryfish
2018-09-17 11:02:02 +08:00
committed by GitHub
25 changed files with 1564 additions and 306 deletions

2
Gopkg.lock generated
View File

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

View File

@@ -23,6 +23,9 @@ import (
"github.com/emicklei/go-restful-openapi"
"fmt"
"strings"
"kubesphere.io/kubesphere/pkg/constants"
"kubesphere.io/kubesphere/pkg/models"
)
@@ -31,15 +34,33 @@ func Register(ws *restful.WebService, subPath string) {
tags := []string{"resources"}
ws.Route(ws.GET(subPath+"/{resource}").To(handleResource).Produces(restful.MIME_JSON).Metadata(restfulspec.KeyOpenAPITags, tags).Doc("Get resource" +
" list").Param(ws.PathParameter("resource", "resource name").DataType(
"string")).Param(ws.QueryParameter("conditions", "search "+
"conditions").DataType("string")).Param(ws.QueryParameter("paging",
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("string")).Param(ws.QueryParameter("conditions",
"search conditions").DataType("string")).Param(ws.QueryParameter("reverse",
"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{}))
}
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")
if resource == "applications" {
@@ -48,7 +69,23 @@ func handleResource(req *restful.Request, resp *restful.Response) {
}
conditions := req.QueryParameter("conditions")
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 {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()})
return
@@ -58,7 +95,6 @@ func handleResource(req *restful.Request, resp *restful.Response) {
}
func handleApplication(req *restful.Request, resp *restful.Response) {
//searchWord := req.QueryParameter("search-word")
paging := req.QueryParameter("paging")
clusterId := req.QueryParameter("cluster_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) {
name := strings.Split(workLoadName, deploySurffix)[0]
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)...)
continue
}
@@ -248,7 +248,7 @@ func (ctl *ApplicationCtl) GetWorkLoads(namespace string, clusterRoles []cluster
if strings.HasSuffix(workLoadName, daemonSurffix) {
name := strings.Split(workLoadName, daemonSurffix)[0]
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)...)
continue
}
@@ -256,7 +256,7 @@ func (ctl *ApplicationCtl) GetWorkLoads(namespace string, clusterRoles []cluster
if strings.HasSuffix(workLoadName, stateSurffix) {
name := strings.Split(workLoadName, stateSurffix)[0]
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)...)
continue
}
@@ -265,16 +265,6 @@ func (ctl *ApplicationCtl) GetWorkLoads(namespace string, clusterRoles []cluster
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 {
k8sClient := client.NewK8sClient()
@@ -349,7 +339,7 @@ func (ctl *ApplicationCtl) getIng(namespace string, services *[]Service) *[]ing
ingCtl := ResourceControllers.Controllers[Ingresses]
var ings []ing
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 {
glog.Error(err)
return nil

View File

@@ -30,6 +30,11 @@ import (
const systemPrefix = "system:"
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
if strings.HasPrefix(name, systemPrefix) {
return nil
@@ -40,7 +45,7 @@ func (ctl *ClusterRoleCtl) generateObject(item v1.ClusterRole) *ClusterRole {
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
}
@@ -136,15 +141,23 @@ func (ctl *ClusterRoleCtl) CountWithConditions(conditions string) int {
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 list []ClusterRole
var total int
order := "createTime desc"
if len(order) == 0 {
order = "createTime desc"
}
db := ctl.DB
listWithConditions(db, &total, &object, &list, conditions, paging, order)
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) {
defer handleCrash(ctl)
defer ctl.CloseDB()
stopChan := make(chan struct{})
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 {
var app string
var status string
var app, status, displayName string
if item.Annotations != nil && len(item.Annotations[DisplayName]) > 0 {
displayName = item.Annotations[DisplayName]
}
name := item.Name
namespace := item.Namespace
availablePodNum := item.Status.NumberAvailable
@@ -55,8 +58,19 @@ func (ctl *DaemonsetCtl) generateObject(item v1.DaemonSet) *Daemonset {
status = Updating
}
object := &Daemonset{Namespace: namespace, Name: name, Available: availablePodNum, Desire: desirePodNum,
App: app, CreateTime: createTime, Status: status, NodeSelector: string(nodeSelectorStr), Annotation: Annotation{item.Annotations}}
object := &Daemonset{
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
}
@@ -135,25 +149,21 @@ func (ctl *DaemonsetCtl) CountWithConditions(conditions string) int {
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 object Daemonset
var total int
order := "createTime desc"
if len(order) == 0 {
order = "createTime desc"
}
listWithConditions(ctl.DB, &total, &object, &list, conditions, paging, order)
return total, list, nil
}
//func (ctl *DaemonsetCtl) Count(namespace string) int {
// var count int
// db := ctl.DB
// if len(namespace) == 0 {
// db.Model(&Daemonset{}).Count(&count)
// } else {
// db.Model(&Daemonset{}).Where("namespace = ?", namespace).Count(&count)
// }
// return count
//}
func (ctl *DaemonsetCtl) Lister() interface{} {
return ctl.lister
}

View File

@@ -27,9 +27,13 @@ import (
)
func (ctl *DeploymentCtl) generateObject(item v1.Deployment) *Deployment {
var app string
var status string
var app, status, displayName string
var updateTime time.Time
if item.Annotations != nil && len(item.Annotations[DisplayName]) > 0 {
displayName = item.Annotations[DisplayName]
}
name := item.Name
namespace := item.Namespace
availablePodNum := item.Status.AvailableReplicas
@@ -41,9 +45,13 @@ func (ctl *DeploymentCtl) generateObject(item v1.Deployment) *Deployment {
app = release + "/" + chart
}
for _, conditon := range item.Status.Conditions {
if conditon.Type == "Available" {
updateTime = conditon.LastUpdateTime.Time
for _, condition := range item.Status.Conditions {
if updateTime.IsZero() {
updateTime = condition.LastUpdateTime.Time
} else {
if updateTime.Before(condition.LastUpdateTime.Time) {
updateTime = condition.LastUpdateTime.Time
}
}
}
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,
App: app, UpdateTime: updateTime, Status: status, Annotation: Annotation{item.Annotations}}
return &Deployment{
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 {
@@ -138,14 +156,21 @@ func (ctl *DeploymentCtl) CountWithConditions(conditions string) int {
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 object Deployment
var total int
order := "updateTime desc"
if len(order) == 0 {
order = "updateTime desc"
}
listWithConditions(ctl.DB, &total, &object, &list, conditions, paging, order)
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 {
var ip, tls, displayName string
name := item.Name
namespace := item.Namespace
var ip, tls string
if item.Annotations != nil && len(item.Annotations[DisplayName]) > 0 {
displayName = item.Annotations[DisplayName]
}
createTime := item.CreationTimestamp.Time
if createTime.IsZero() {
createTime = time.Now()
@@ -63,7 +70,17 @@ func (ctl *IngressCtl) generateObject(item v1beta1.Ingress) *Ingress {
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
}
@@ -143,25 +160,21 @@ func (ctl *IngressCtl) CountWithConditions(conditions string) int {
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 object Ingress
var total int
order := "createTime desc"
if len(order) == 0 {
order = "createTime desc"
}
listWithConditions(ctl.DB, &total, &object, &list, conditions, paging, order)
return total, list, nil
}
//func (ctl *IngressCtl) Count(namespace string) int {
// var count int
// db := ctl.DB
// if len(namespace) == 0 {
// db.Model(&Ingress{}).Count(&count)
// } else {
// db.Model(&Ingress{}).Where("namespace = ?", namespace).Count(&count)
// }
// return count
//}
func (ctl *IngressCtl) Lister() interface{} {
return ctl.lister
}

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 {
var displayName string
if item.Annotations != nil && len(item.Annotations[DisplayName]) > 0 {
displayName = item.Annotations[DisplayName]
}
name := item.Name
createTime := item.CreationTimestamp.Time
@@ -236,7 +241,13 @@ func (ctl *NamespaceCtl) generateObject(item v1.Namespace) *Namespace {
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
}
@@ -320,12 +331,14 @@ func (ctl *NamespaceCtl) CountWithConditions(conditions string) int {
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 object Namespace
var total int
order := "createTime desc"
if len(order) == 0 {
order = "createTime desc"
}
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 {
usage, err := ctl.GetNamespaceQuota(list[index].Name)
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)
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 {
used := getUsage(namespace, resourceName)
var quantity resource.Quantity
@@ -365,3 +378,8 @@ func (ctl *NamespaceCtl) GetNamespaceQuota(namespace string) (v1.ResourceList, e
usage["runningPods"] = quantity
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)
}
object := &Pod{Namespace: namespace, Name: name, Node: nodeName, PodIp: podIp, Status: status, NodeIp: nodeIp,
CreateTime: createTime, Annotation: Annotation{item.Annotations}, Containers: containers, RestartCount: restartCount}
object := &Pod{
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
}
@@ -277,25 +288,21 @@ func (ctl *PodCtl) CountWithConditions(conditions string) int {
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 object Pod
var total int
order := "createTime desc"
if len(order) == 0 {
order = "createTime desc"
}
listWithConditions(ctl.DB, &total, &object, &list, conditions, paging, order)
return total, list, nil
}
//func (ctl *PodCtl) Count(namespace string) int {
// var count int
// db := ctl.DB
// if len(namespace) == 0 {
// db.Model(&Pod{}).Count(&count)
// } else {
// db.Model(&Pod{}).Where("namespace = ?", namespace).Count(&count)
// }
// return count
//}
func (ctl *PodCtl) Lister() interface{} {
return ctl.lister
}

View File

@@ -30,6 +30,12 @@ import (
)
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
namespace := item.Namespace
status := fmt.Sprintf("%s", item.Status.Phase)
@@ -58,8 +64,18 @@ func (ctl *PvcCtl) generateObject(item *v1.PersistentVolumeClaim) *Pvc {
accessModeStr = strings.Join(accessModeList, ",")
object := &Pvc{Namespace: namespace, Name: name, Status: status, Capacity: capacity,
AccessMode: accessModeStr, StorageClassName: storageClass, CreateTime: createTime, Annotation: Annotation{item.Annotations}}
object := &Pvc{
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
}
@@ -138,12 +154,14 @@ func (ctl *PvcCtl) CountWithConditions(conditions string) int {
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 object Pvc
var total int
order := "createTime desc"
if len(order) == 0 {
order = "createTime desc"
}
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
}
//func (ctl *PvcCtl) Count(namespace string) int {
// var count int
// db := ctl.DB
// if len(namespace) == 0 {
// db.Model(&Pvc{}).Count(&count)
// } else {
// db.Model(&Pvc{}).Where("namespace = ?", namespace).Count(&count)
// }
// return count
//}
func (ctl *PvcCtl) Lister() interface{} {
return ctl.lister
}

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 {
var displayName string
if item.Annotations != nil && len(item.Annotations[DisplayName]) > 0 {
displayName = item.Annotations[DisplayName]
}
name := item.Name
if strings.HasPrefix(name, systemPrefix) {
return nil
@@ -38,7 +44,13 @@ func (ctl *RoleCtl) generateObject(item v1.Role) *Role {
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
}
@@ -132,21 +144,21 @@ func (ctl *RoleCtl) CountWithConditions(conditions string) int {
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 object Role
var total int
order := "createTime desc"
if len(order) == 0 {
order = "createTime desc"
}
listWithConditions(ctl.DB, &total, &object, &list, conditions, paging, order)
return total, list, nil
}
//func (ctl *RoleCtl) Count(namespace string) int {
// var count int
// db := ctl.DB
// db.Model(&Role{}).Where("namespace = ?", namespace).Count(&count)
// return count
//}
func (ctl *RoleCtl) Lister() interface{} {
return ctl.lister
}

View File

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

View File

@@ -69,12 +69,25 @@ func getExternalIp(item v1.Service) string {
}
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
namespace := item.Namespace
createTime := item.CreationTimestamp.Time
externalIp := getExternalIp(item)
serviceType := item.Spec.Type
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 := ""
var nodePorts []string
@@ -118,13 +131,16 @@ func generateSvcObject(item v1.Service) *Service {
object := &Service{
Namespace: namespace,
Name: name,
DisplayName: displayName,
ServiceType: string(serviceType),
ExternalIp: externalIp,
VirtualIp: vip,
CreateTime: createTime,
Ports: ports,
NodePorts: strings.Join(nodePorts, ","),
Annotation: Annotation{item.Annotations},
Annotation: MapString{item.Annotations},
Labels: MapString{item.Labels},
App: app,
}
return object
@@ -209,14 +225,21 @@ func (ctl *ServiceCtl) CountWithConditions(conditions string) int {
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 object Service
var total int
order := "createTime desc"
if len(order) == 0 {
order = "createTime desc"
}
listWithConditions(ctl.DB, &total, &object, &list, conditions, paging, order)
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 {
var app string
var status string
var displayName string
if item.Annotations != nil && len(item.Annotations[DisplayName]) > 0 {
displayName = item.Annotations[DisplayName]
}
name := item.Name
namespace := item.Namespace
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,
App: app, CreateTime: createTime, Status: status, Annotation: Annotation{item.Annotations}}
statefulSetObject := &Statefulset{
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
}
@@ -137,14 +152,21 @@ func (ctl *StatefulsetCtl) CountWithConditions(conditions string) int {
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 object Statefulset
var total int
order := "createTime desc"
if len(order) == 0 {
order = "createTime desc"
}
listWithConditions(ctl.DB, &total, &object, &list, conditions, paging, order)
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 {
var displayName string
if item.Annotations != nil && len(item.Annotations[DisplayName]) > 0 {
displayName = item.Annotations[DisplayName]
}
name := item.Name
createTime := item.CreationTimestamp.Time
isDefault := false
@@ -41,7 +47,13 @@ func (ctl *StorageClassCtl) generateObject(item v1.StorageClass) *StorageClass {
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
}
@@ -120,12 +132,14 @@ func (ctl *StorageClassCtl) CountWithConditions(conditions string) int {
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 object StorageClass
var total int
order := "createTime desc"
if len(order) == 0 {
order = "createTime desc"
}
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
}
func (ctl *StorageClassCtl) Lister() interface{} {
return ctl.lister
}

View File

@@ -27,6 +27,8 @@ import (
"k8s.io/api/core/v1"
"k8s.io/client-go/kubernetes"
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"
"k8s.io/client-go/listers/extensions/v1beta1"
rbacV1 "k8s.io/client-go/listers/rbac/v1"
@@ -35,22 +37,18 @@ import (
)
const (
resyncCircle = 600
Stopped = "stopped"
PvcPending = "Pending"
Running = "running"
Updating = "updating"
tablePods = "pods"
tableDeployments = "deployments"
tableDaemonsets = "daemonsets"
tableStatefulsets = "statefulsets"
tableNamespaces = "namespaces"
tableIngresses = "ingresses"
tablePersistentVolumeClaim = "pvcs"
tableRoles = "roles"
tableClusterRoles = "cluster_roles"
tableServices = "services"
tableStorageClasses = "storage_classes"
resyncCircle = 600
Stopped = "stopped"
PvcPending = "pending"
Running = "running"
Updating = "updating"
Failed = "failed"
Unfinished = "unfinished"
Completed = "completed"
Pause = "pause"
Warning = "warning"
Error = "error"
DisplayName = "displayName"
Pods = "pods"
Deployments = "deployments"
@@ -64,13 +62,18 @@ const (
Services = "services"
StorageClasses = "storage-classes"
Applications = "applications"
Jobs = "jobs"
Cronjobs = "cronjobs"
Nodes = "nodes"
Replicasets = "replicasets"
ControllerRevisions = "controllerrevisions"
)
type Annotation struct {
Values map[string]string `gorm:"type:TEXT"`
type MapString struct {
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) {
case string:
return json.Unmarshal([]byte(val), annotation)
@@ -82,92 +85,104 @@ func (annotation *Annotation) Scan(val interface{}) error {
return nil
}
func (annotation Annotation) Value() (driver.Value, error) {
func (annotation MapString) Value() (driver.Value, error) {
bytes, err := json.Marshal(annotation)
return string(bytes), err
}
type Deployment struct {
Name string `gorm:"primary_key" json:"name"`
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"`
type Taints struct {
Values []v1.Taint `json:"values" gorm:"type:TEXT"`
}
func (Deployment) TableName() string {
return tableDeployments
func (taints *Taints) Scan(val interface{}) error {
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 {
Name string `gorm:"primary_key" json:"name,omitempty"`
Namespace string `gorm:"primary_key" json:"namespace,omitempty"`
App string `json:"app,omitempty"`
Name string `gorm:"primary_key" json:"name,omitempty"`
DisplayName string `json:"displayName,omitempty" gorm:"column:displayName"`
Namespace string `gorm:"primary_key" json:"namespace,omitempty"`
App string `json:"app,omitempty"`
Available int32 `json:"available"`
Desire int32 `json:"desire"`
Status string `json:"status"`
Annotation Annotation `json:"annotations"`
CreateTime time.Time `gorm:"column:createTime" json:"createTime,omitempty"`
}
func (Statefulset) TableName() string {
return tableStatefulsets
Available int32 `json:"available"`
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"`
}
type Daemonset struct {
Name string `gorm:"primary_key" json:"name,omitempty"`
Namespace string `gorm:"primary_key" json:"namespace,omitempty"`
App string `json:"app,omitempty"`
Name string `gorm:"primary_key" json:"name,omitempty"`
DisplayName string `json:"displayName,omitempty" gorm:"column:displayName"`
Namespace string `gorm:"primary_key" json:"namespace,omitempty"`
App string `json:"app,omitempty"`
Available int32 `json:"available"`
Desire int32 `json:"desire"`
Status string `json:"status"`
NodeSelector string `json:"nodeSelector, omitempty"`
Annotation Annotation `json:"annotations"`
CreateTime time.Time `gorm:"column:createTime" json:"createTime,omitempty"`
}
func (Daemonset) TableName() string {
return tableDaemonsets
Available int32 `json:"available"`
Desire int32 `json:"desire"`
Status string `json:"status"`
NodeSelector string `json:"nodeSelector, omitempty"`
Annotation MapString `json:"annotations"`
Labels MapString `json:"labels"`
CreateTime time.Time `gorm:"column:createTime" json:"createTime,omitempty"`
}
type Service struct {
Name string `gorm:"primary_key" json:"name"`
DisplayName string `json:"displayName,omitempty" gorm:"column:displayName"`
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"`
ExternalIp string `json:"externalIp,omitempty"`
App string `json:"app,omitempty"`
VirtualIp string `gorm:"column:virtualIp" json:"virtualIp,omitempty"`
ExternalIp string `gorm:"column:externalIp" json:"externalIp,omitempty"`
Ports string `json:"ports,omitempty"`
NodePorts string `json:"nodePorts,omitempty"`
Annotation Annotation `json:"annotations"`
CreateTime time.Time `gorm:"column:createTime" json:"createTime,omitempty"`
}
func (Service) TableName() string {
return tableServices
Ports string `json:"ports,omitempty"`
NodePorts string `gorm:"column:nodePorts" json:"nodePorts,omitempty"`
Annotation MapString `json:"annotations"`
Labels MapString `json:"labels"`
CreateTime time.Time `gorm:"column:createTime" json:"createTime,omitempty"`
}
type Pvc struct {
Name string `gorm:"primary_key" json:"name"`
Namespace string `gorm:"primary_key" json:"namespace"`
Status string `json:"status,omitempty"`
Capacity string `json:"capacity,omitempty"`
AccessMode string `json:"accessMode,omitempty"`
Annotation Annotation `json:"annotations"`
CreateTime time.Time `gorm:"column:createTime" json:"createTime,omitempty"`
StorageClassName string `gorm:"column:storage_class" json:"storage_class,omitempty"`
InUse bool `gorm:"-" json:"inUse"`
}
func (Pvc) TableName() string {
return tablePersistentVolumeClaim
Name string `gorm:"primary_key" json:"name"`
DisplayName string `json:"displayName,omitempty" gorm:"column:displayName"`
Namespace string `gorm:"primary_key" json:"namespace"`
Status string `json:"status,omitempty"`
Capacity string `json:"capacity,omitempty"`
AccessMode string `gorm:"column:accessMode" json:"accessMode,omitempty"`
Annotation MapString `json:"annotations"`
Labels MapString `json:"labels"`
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"`
}
type ingressRule struct {
@@ -178,17 +193,15 @@ type ingressRule struct {
}
type Ingress struct {
Name string `gorm:"primary_key" json:"name"`
Namespace string `gorm:"primary_key" json:"namespace"`
Ip string `json:"ip,omitempty"`
Rules string `gorm:"type:text" json:"rules, omitempty"`
TlsTermination string `json:"tlsTermination,omitempty"`
Annotation Annotation `json:"annotations"`
CreateTime time.Time `gorm:"column:createTime" json:"createTime,omitempty"`
}
func (Ingress) TableName() string {
return tableIngresses
Name string `gorm:"primary_key" json:"name"`
DisplayName string `json:"displayName,omitempty" gorm:"column:displayName"`
Namespace string `gorm:"primary_key" json:"namespace"`
Ip string `json:"ip,omitempty"`
Rules string `gorm:"type:text" json:"rules, omitempty"`
TlsTermination string `gorm:"column:tlsTermination" json:"tlsTermination,omitempty"`
Annotation MapString `json:"annotations"`
Labels MapString `json:"labels"`
CreateTime time.Time `gorm:"column:createTime" json:"createTime,omitempty"`
}
type Pod struct {
@@ -196,10 +209,11 @@ type Pod struct {
Namespace string `gorm:"primary_key" json:"namespace"`
Status string `json:"status,omitempty"`
Node string `json:"node,omitempty"`
NodeIp string `json:"nodeIp,omitempty"`
PodIp string `json:"podIp,omitempty"`
NodeIp string `gorm:"column:nodeIp" json:"nodeIp,omitempty"`
PodIp string `gorm:"column:podIp" json:"podIp,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"`
CreateTime time.Time `gorm:"column:createTime" json:"createTime,omitempty"`
}
@@ -230,61 +244,97 @@ func (containers Containers) Value() (driver.Value, error) {
return string(bytes), err
}
func (Pod) TableName() string {
return tablePods
}
type Role struct {
Name string `gorm:"primary_key" json:"name"`
Namespace string `gorm:"primary_key" json:"namespace"`
Annotation Annotation `json:"annotations"`
CreateTime time.Time `gorm:"column:createTime" json:"createTime,omitempty"`
}
func (Role) TableName() string {
return tableRoles
Name string `gorm:"primary_key" json:"name"`
DisplayName string `json:"displayName,omitempty" gorm:"column:displayName"`
Namespace string `gorm:"primary_key" json:"namespace"`
Annotation MapString `json:"annotations"`
CreateTime time.Time `gorm:"column:createTime" json:"createTime,omitempty"`
}
type ClusterRole struct {
Name string `gorm:"primary_key" json:"name"`
Annotation Annotation `json:"annotations"`
CreateTime time.Time `gorm:"column:createTime" json:"createTime,omitempty"`
}
func (ClusterRole) TableName() string {
return tableClusterRoles
Name string `gorm:"primary_key" json:"name"`
DisplayName string `json:"displayName,omitempty" gorm:"column:displayName"`
Annotation MapString `json:"annotations"`
CreateTime time.Time `gorm:"column:createTime" json:"createTime,omitempty"`
}
type Namespace struct {
Name string `gorm:"primary_key" json:"name"`
Creator string `json:"creator,omitempty"`
Status string `json:"status"`
Name string `gorm:"primary_key" json:"name"`
DisplayName string `json:"displayName,omitempty" gorm:"column:displayName"`
Creator string `json:"creator,omitempty"`
Status string `json:"status"`
Descrition string `json:"description,omitempty"`
Annotation Annotation `json:"annotations"`
Annotation MapString `json:"annotations"`
CreateTime time.Time `gorm:"column:createTime" json:"createTime,omitempty"`
Usaeg v1.ResourceList `gorm:"-" json:"usage,omitempty"`
}
func (Namespace) TableName() string {
return tableNamespaces
Usage v1.ResourceList `gorm:"-" json:"usage,omitempty"`
}
type StorageClass struct {
Name string `gorm:"primary_key" json:"name"`
Creator string `json:"creator,omitempty"`
Annotation Annotation `json:"annotations"`
CreateTime time.Time `gorm:"column:createTime" json:"createTime,omitempty"`
IsDefault bool `json:"default"`
Count int `json:"count"`
Name string `gorm:"primary_key" json:"name"`
DisplayName string `json:"displayName,omitempty" gorm:"column:displayName"`
Creator string `json:"creator,omitempty"`
Annotation MapString `json:"annotations"`
CreateTime time.Time `gorm:"column:createTime" json:"createTime,omitempty"`
IsDefault bool `json:"default"`
Count int `json:"count"`
}
func (StorageClass) TableName() string {
return tableStorageClasses
type JobRevisions map[int]JobStatus
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 {
Limit, Offset int
Limit, Offset, Page int
}
type Controller interface {
@@ -295,7 +345,9 @@ type Controller interface {
initListerAndInformer()
sync(stopChan chan struct{})
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 {
@@ -316,6 +368,11 @@ func (ca *CommonAttribute) chanAlive() chan struct{} {
return ca.aliveChan
}
func (ca *CommonAttribute) CloseDB() {
ca.DB.Close()
}
type DeploymentCtl struct {
CommonAttribute
lister appV1.DeploymentLister
@@ -381,3 +438,33 @@ type ClusterRoleCtl struct {
informer cache.SharedIndexInformer
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"
storageClassesKey = "count/storageClass"
namespaceKey = "count/namespace"
jobsKey = "count/jobs.batch"
cronJobsKey = "count/cronjobs.batch"
)
var resourceMap = map[string]string{daemonsetsKey: controllers.Daemonsets, deploymentsKey: controllers.Deployments,
ingressKey: controllers.Ingresses, rolesKey: controllers.Roles, servicesKey: controllers.Services,
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 {
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
import (
@@ -24,11 +40,19 @@ type ResourceList struct {
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) {
switch resource {
case controllers.Deployments, controllers.Statefulsets, controllers.Daemonsets, controllers.Ingresses,
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
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)
fuzzy := make(map[string]string)
matchOr := make(map[string]string)
fuzzyOr := make(map[string]string)
orderField := make(map[string]string)
if len(str) == 0 {
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 {
return nil, nil, errors.New("invalid condition input, invalid character \"~\"")
conditions := strings.Split(str, ",")
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 {
@@ -59,7 +84,17 @@ func getConditions(str string) (map[string]string, map[string]string, error) {
if len(kvs) < 2 || len(kvs[1]) == 0 {
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
}
@@ -68,86 +103,130 @@ func getConditions(str string) (map[string]string, map[string]string, error) {
if len(kvs) < 2 || len(kvs[1]) == 0 {
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
}
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) {
defaultPaging := &controllers.Paging{Limit: 10, Offset: 0}
defautlPagingMap := map[string]int{"page": 1, "limit": 10}
func getPaging(resourceName, pagingStr string) (*controllers.Paging, error) {
defaultPaging := &controllers.Paging{Limit: 10, Offset: 0, Page: 1}
paging := controllers.Paging{}
if resourceName == controllers.Namespaces {
defaultPaging = nil
defautlPagingMap = map[string]int{"page": 0, "limit": 0}
}
pagingMap := make(map[string]int)
if len(pagingStr) == 0 {
return defaultPaging, defautlPagingMap, nil
return defaultPaging, nil
}
list := strings.Split(pagingStr, ",")
for _, item := range list {
kvs := strings.Split(item, "=")
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])
if err != nil {
return nil, nil, errors.New("invalid Paging input")
if err != nil || value <= 0 {
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 {
return nil, nil, errors.New("invalid Paging input")
if paging.Limit > 0 && paging.Page > 0 {
paging.Offset = (paging.Page - 1) * paging.Limit
return &paging, nil
}
if pagingMap[limit] > 0 && pagingMap[page] > 0 {
offset := (pagingMap[page] - 1) * pagingMap[limit]
return &controllers.Paging{Limit: pagingMap[limit], Offset: offset}, pagingMap, nil
}
return defaultPaging, defautlPagingMap, nil
return defaultPaging, nil
}
func ListResource(resourceName, conditonSrt, pagingStr string) (*ResourceList, error) {
match, fuzzy, err := getConditions(conditonSrt)
func generateOrder(orderField map[string]string, order string) string {
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 {
return nil, err
}
paging, pagingMap, err := getPaging(resourceName, pagingStr)
order = generateOrder(OrderFields, order)
conditionStr := generateConditionStr(conditions)
paging, err := getPaging(resourceName, pagingStr)
if err != nil {
return nil, err
}
conditionStr := generateConditionStr(match, fuzzy)
ctl, err := getController(resourceName)
if err != nil {
return nil, err
}
total, items, err := ctl.ListWithConditions(conditionStr, paging)
total, items, err := ctl.ListWithConditions(conditionStr, paging, order)
if err != nil {
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 := ""
for k, v := range match {
if conditions == nil {
return conditionStr
}
for k, v := range conditions.match {
if len(conditionStr) == 0 {
conditionStr = fmt.Sprintf("%s = \"%s\" ", k, v)
} 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 {
conditionStr = fmt.Sprintf("%s like '%%%s%%' ", k, v)
} 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
}
@@ -182,9 +277,9 @@ func GetNamespacesResourceStatus(namespace string) (*workLoadStatus, error) {
notReadyStatus = controllers.PvcPending
}
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 {
status, err = ListResource(resource, fmt.Sprintf("status=%s", notReadyStatus), "")
status, err = ListResource(resource, fmt.Sprintf("status=%s", notReadyStatus), "", "")
}
if err != nil {
@@ -208,25 +303,30 @@ func GetApplication(clusterId string) (interface{}, error) {
return ctl.GetApp(clusterId)
}
func ListApplication(runtimeId, conditions, pagingStr string) (*ResourceList, error) {
paging, pagingMap, err := getPaging(controllers.Applications, pagingStr)
func ListApplication(runtimeId, conditionStr, pagingStr string) (*ResourceList, error) {
paging, err := getPaging(controllers.Applications, pagingStr)
if err != nil {
return nil, err
}
match, fuzzy, err := getConditions(conditions)
conditions, _, err := getConditions(conditionStr)
if err != nil {
glog.Error(err)
return nil, err
}
if conditions == nil {
conditions = &searchConditions{}
}
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 {
glog.Errorf("get application list failed, reason: %s", 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))
}