diff --git a/pkg/apis/v1alpha/resources/resources.go b/pkg/apis/v1alpha/resources/resources.go index 240bdebef..1e554815d 100644 --- a/pkg/apis/v1alpha/resources/resources.go +++ b/pkg/apis/v1alpha/resources/resources.go @@ -34,12 +34,16 @@ func Register(ws *restful.WebService, subPath string) { tags := []string{"resources"} - 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{})) + 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 isInvalid(str string) bool { diff --git a/pkg/models/controllers/configmaps.go b/pkg/models/controllers/configmaps.go new file mode 100644 index 000000000..396cd457a --- /dev/null +++ b/pkg/models/controllers/configmaps.go @@ -0,0 +1,162 @@ +/* +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 ( + "strings" + "time" + + "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" +) + +func (ctl *ConfigMapCtl) generateObject(item v1.ConfigMap) *ConfigMap { + var displayName string + if item.Annotations != nil && len(item.Annotations[DisplayName]) > 0 { + displayName = item.Annotations[DisplayName] + } + + createTime := item.CreationTimestamp.Time + if createTime.IsZero() { + createTime = time.Now() + } + + var entries []string + + for entry := range item.Data { + entries = append(entries, entry) + } + + object := &ConfigMap{ + Name: item.Name, + Namespace: item.Namespace, + CreateTime: createTime, + Annotation: MapString{item.Annotations}, + DisplayName: displayName, + Entries: strings.Join(entries, ","), + } + + return object +} + +func (ctl *ConfigMapCtl) Name() string { + return ctl.CommonAttribute.Name +} + +func (ctl *ConfigMapCtl) sync(stopChan chan struct{}) { + db := ctl.DB + + if db.HasTable(&ConfigMap{}) { + db.DropTable(&ConfigMap{}) + } + + db = db.CreateTable(&ConfigMap{}) + + ctl.initListerAndInformer() + + list, err := ctl.lister.List(labels.Everything()) + if err != nil { + glog.Error(err) + return + } + + for _, item := range list { + obj := ctl.generateObject(*item) + if obj != nil { + db.Create(obj) + } + } + + ctl.informer.Run(stopChan) +} + +func (ctl *ConfigMapCtl) 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 *ConfigMapCtl) initListerAndInformer() { + db := ctl.DB + + informerFactory := informers.NewSharedInformerFactory(ctl.K8sClient, time.Second*resyncCircle) + ctl.lister = informerFactory.Core().V1().ConfigMaps().Lister() + + informer := informerFactory.Core().V1().ConfigMaps().Informer() + informer.AddEventHandler(cache.ResourceEventHandlerFuncs{ + AddFunc: func(obj interface{}) { + + object := obj.(*v1.ConfigMap) + mysqlObject := ctl.generateObject(*object) + if mysqlObject != nil { + db.Create(mysqlObject) + } + }, + UpdateFunc: func(old, new interface{}) { + object := new.(*v1.ConfigMap) + mysqlObject := ctl.generateObject(*object) + if mysqlObject != nil { + db.Save(mysqlObject) + } + }, + DeleteFunc: func(obj interface{}) { + var item ConfigMap + object := obj.(*v1.ConfigMap) + db.Where("name=?", object.Name).Find(&item) + db.Delete(item) + + }, + }) + ctl.informer = informer +} + +func (ctl *ConfigMapCtl) CountWithConditions(conditions string) int { + var object ConfigMap + + if strings.Contains(conditions, "namespace") { + conditions = "" + } + return countWithConditions(ctl.DB, conditions, &object) +} + +func (ctl *ConfigMapCtl) ListWithConditions(conditions string, paging *Paging, order string) (int, interface{}, error) { + var object ConfigMap + var list []ConfigMap + var total int + + if len(order) == 0 { + order = "createTime desc" + } + + db := ctl.DB + + listWithConditions(db, &total, &object, &list, conditions, paging, order) + + return total, list, nil +} + +func (ctl *ConfigMapCtl) Lister() interface{} { + + return ctl.lister +} diff --git a/pkg/models/controllers/run.go b/pkg/models/controllers/run.go index c9ba0322f..9659d65af 100644 --- a/pkg/models/controllers/run.go +++ b/pkg/models/controllers/run.go @@ -74,6 +74,10 @@ func (rec *resourceControllers) runContoller(name string, stopChan chan struct{} ctl = &ReplicaSetCtl{CommonAttribute: attr} case ControllerRevisions: ctl = &ControllerRevisionCtl{CommonAttribute: attr} + case ConfigMaps: + ctl = &ConfigMapCtl{CommonAttribute: attr} + case Secrets: + ctl = &SecretCtl{CommonAttribute: attr} default: return } @@ -112,7 +116,8 @@ func Run(stopChan chan struct{}, wg *sync.WaitGroup) { ResourceControllers = resourceControllers{k8sClient: k8sClient, Controllers: make(map[string]Controller)} for _, item := range []string{Deployments, Statefulsets, Daemonsets, PersistentVolumeClaim, Pods, Services, - Ingresses, Roles, ClusterRoles, Namespaces, StorageClasses, Jobs, Cronjobs, Nodes, Replicasets, ControllerRevisions} { + Ingresses, Roles, ClusterRoles, Namespaces, StorageClasses, Jobs, Cronjobs, Nodes, Replicasets, + ControllerRevisions, ConfigMaps, Secrets} { ResourceControllers.runContoller(item, stopChan, wg) } @@ -129,7 +134,7 @@ func Run(stopChan chan struct{}, wg *sync.WaitGroup) { ResourceControllers.runContoller(ctlName, stopChan, wg) } default: - time.Sleep(5 * time.Second) + time.Sleep(3 * time.Second) } } } diff --git a/pkg/models/controllers/secrets.go b/pkg/models/controllers/secrets.go new file mode 100644 index 000000000..808dfc8ca --- /dev/null +++ b/pkg/models/controllers/secrets.go @@ -0,0 +1,157 @@ +/* +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 ( + "strings" + "time" + + "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" +) + +func (ctl *SecretCtl) generateObject(item v1.Secret) *Secret { + var displayName string + if item.Annotations != nil && len(item.Annotations[DisplayName]) > 0 { + displayName = item.Annotations[DisplayName] + } + + createTime := item.CreationTimestamp.Time + if createTime.IsZero() { + createTime = time.Now() + } + + object := &Secret{ + Name: item.Name, + Namespace: item.Namespace, + CreateTime: createTime, + Annotation: MapString{item.Annotations}, + DisplayName: displayName, + Entries: len(item.Data), + Type: string(item.Type), + } + + return object +} + +func (ctl *SecretCtl) Name() string { + return ctl.CommonAttribute.Name +} + +func (ctl *SecretCtl) sync(stopChan chan struct{}) { + db := ctl.DB + + if db.HasTable(&Secret{}) { + db.DropTable(&Secret{}) + } + + db = db.CreateTable(&Secret{}) + + ctl.initListerAndInformer() + + list, err := ctl.lister.List(labels.Everything()) + if err != nil { + glog.Error(err) + return + } + + for _, item := range list { + obj := ctl.generateObject(*item) + if obj != nil { + db.Create(obj) + } + } + + ctl.informer.Run(stopChan) +} + +func (ctl *SecretCtl) 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 *SecretCtl) initListerAndInformer() { + db := ctl.DB + + informerFactory := informers.NewSharedInformerFactory(ctl.K8sClient, time.Second*resyncCircle) + ctl.lister = informerFactory.Core().V1().Secrets().Lister() + + informer := informerFactory.Core().V1().Secrets().Informer() + informer.AddEventHandler(cache.ResourceEventHandlerFuncs{ + AddFunc: func(obj interface{}) { + + object := obj.(*v1.Secret) + mysqlObject := ctl.generateObject(*object) + if mysqlObject != nil { + db.Create(mysqlObject) + } + }, + UpdateFunc: func(old, new interface{}) { + object := new.(*v1.Secret) + mysqlObject := ctl.generateObject(*object) + if mysqlObject != nil { + db.Save(mysqlObject) + } + }, + DeleteFunc: func(obj interface{}) { + var item Secret + object := obj.(*v1.Secret) + db.Where("name=?", object.Name).Find(&item) + db.Delete(item) + + }, + }) + ctl.informer = informer +} + +func (ctl *SecretCtl) CountWithConditions(conditions string) int { + var object Secret + + if strings.Contains(conditions, "namespace") { + conditions = "" + } + return countWithConditions(ctl.DB, conditions, &object) +} + +func (ctl *SecretCtl) ListWithConditions(conditions string, paging *Paging, order string) (int, interface{}, error) { + var object Secret + var list []Secret + var total int + + if len(order) == 0 { + order = "createTime desc" + } + + db := ctl.DB + + listWithConditions(db, &total, &object, &list, conditions, paging, order) + + return total, list, nil +} + +func (ctl *SecretCtl) Lister() interface{} { + + return ctl.lister +} diff --git a/pkg/models/controllers/types.go b/pkg/models/controllers/types.go index 548a86b2d..35ef692a2 100644 --- a/pkg/models/controllers/types.go +++ b/pkg/models/controllers/types.go @@ -67,6 +67,8 @@ const ( Nodes = "nodes" Replicasets = "replicasets" ControllerRevisions = "controllerrevisions" + ConfigMaps = "configmaps" + Secrets = "secrets" ) type MapString struct { @@ -334,6 +336,26 @@ type Node struct { Role string `json:"role"` CreateTime time.Time `gorm:"column:createTime" json:"createTime,omitempty"` } + +type ConfigMap struct { + Name string `gorm:"primary_key" json:"name"` + Namespace string `gorm:"primary_key" json:"namespace"` + DisplayName string `json:"displayName,omitempty" gorm:"column:displayName"` + CreateTime time.Time `gorm:"column:createTime" json:"createTime,omitempty"` + Annotation MapString `json:"annotations"` + Entries string `gorm:"type:text" json:"entries"` +} + +type Secret struct { + Name string `gorm:"primary_key" json:"name"` + Namespace string `gorm:"primary_key" json:"namespace"` + DisplayName string `json:"displayName,omitempty" gorm:"column:displayName"` + CreateTime time.Time `gorm:"column:createTime" json:"createTime,omitempty"` + Annotation MapString `json:"annotations"` + Entries int `json:"entries"` + Type string `json:"type"` +} + type Paging struct { Limit, Offset, Page int } @@ -469,3 +491,15 @@ type ControllerRevisionCtl struct { informer cache.SharedIndexInformer CommonAttribute } + +type ConfigMapCtl struct { + lister coreV1.ConfigMapLister + informer cache.SharedIndexInformer + CommonAttribute +} + +type SecretCtl struct { + lister coreV1.SecretLister + informer cache.SharedIndexInformer + CommonAttribute +} diff --git a/pkg/models/resources.go b/pkg/models/resources.go index b281bc907..ed9e1377c 100644 --- a/pkg/models/resources.go +++ b/pkg/models/resources.go @@ -52,7 +52,7 @@ func getController(resource string) (controllers.Controller, error) { case controllers.Deployments, controllers.Statefulsets, controllers.Daemonsets, controllers.Ingresses, controllers.PersistentVolumeClaim, controllers.Roles, controllers.ClusterRoles, controllers.Services, controllers.Pods, controllers.Namespaces, controllers.StorageClasses, controllers.Jobs, controllers.Cronjobs, - controllers.Nodes: + controllers.Nodes, controllers.Secrets, controllers.ConfigMaps: return controllers.ResourceControllers.Controllers[resource], nil default: